Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support capability atomics in hybrid mode #473

Closed
wants to merge 44 commits into from

Conversation

arichardson
Copy link
Member

@arichardson arichardson commented Sep 8, 2020

This cleans up various atomic code generation bugs and adds support for atomic RMW operations in hybrid mode for both RISC-V and MIPS.

@arichardson arichardson marked this pull request as draft September 8, 2020 17:26
@arichardson
Copy link
Member Author

ping? (I'll fix the amdgpu test if this change looks ok)

@arichardson arichardson marked this pull request as ready for review September 23, 2020 14:13
@arichardson
Copy link
Member Author

I've pushed fixup commits to make it easier to see the difference to the last version. Will squash them into the appropriate commit before merging if this looks good now.

@arichardson
Copy link
Member Author

Last commit was submitted upstream as https://reviews.llvm.org/D88800

@arichardson
Copy link
Member Author

ping?

Copy link
Member

@jrtc27 jrtc27 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still don't like the fact that we're using cmpxchg for other AMOs unlike integer-in-normal/hybrid and capability-in-purecap atomics.

llvm/lib/CodeGen/AtomicExpandPass.cpp Outdated Show resolved Hide resolved
clang/test/CodeGen/cheri/c11-atomic-caps.c Outdated Show resolved Hide resolved
clang/lib/CodeGen/TargetInfo.cpp Show resolved Hide resolved
clang/lib/CodeGen/CGAtomic.cpp Show resolved Hide resolved
clang/lib/CodeGen/CGAtomic.cpp Outdated Show resolved Hide resolved
clang/lib/CodeGen/CGAtomic.cpp Outdated Show resolved Hide resolved
llvm/lib/Target/RISCV/RISCVExpandAtomicPseudoInsts.cpp Outdated Show resolved Hide resolved
llvm/lib/Target/RISCV/RISCVInstrInfoXCheri.td Outdated Show resolved Hide resolved
llvm/lib/CodeGen/AtomicExpandPass.cpp Outdated Show resolved Hide resolved
The code was full of bugs that for some reason happened to generate
working
(or at least non-asserting) code in the majority of cases. However, when
falling back to library calls for unsupported atomics arguments were not
being passed correctly. As we don't implement those library calls this
should not matter, but I was getting an assertion failure while
compiling
the atomics code from the latest QtBase dev branch. Now we call a
non-existent libbcall instead of crashing which is a lot easier to
debug.

This also improves the -Watomic-alignment check to report unsupported
rather than misaligned for operations such as xor/and/etc.
This fixes an assertion and incorrect generation of i128 IR instead of
i8 addrspace(200)* when generating hybrid MIPS C11 atomics. It turns out
that we are using libcalls even for load/store/xchg for MIPS which will
be fixed in a follow-up commit.
This matches RISC-V and allows reuse of the c11-atomic-caps.c checks for
CHERI-RISC-V.
This fixes the atomicexpandpass to always emit pointer type cmpxchg
instructions and adds missing some instruction selection patterns that
are required now that MIPS no longer uses libcalls for some atomics.

Note: RISC-V falls back to atomic libcalls but selects the generic
overload which cannot handle capabilities correctly.
We need to call a specialized libcall for capability arguments since the
generic one will not handle capability tag bits.

Note: we don't have an implementation of those spciailized functions but a
linker error is much better than silent run-time tag corruption.
Also add a test that all RMW operations generate sensible code in both
purecap and hybrid mode when passed a capability pointer (and a
non-capability argument).

This test shows that the same IR will result in an assertion for RISC-V
which was already reported as
CTSRD-CHERI#470
I don't think this can currently be triggered, but I found it while testing
some changes to the CHERI-RISC-V instruction definitions.
Previously we would assert when attempting to perform an atomic RMW
operation using a capability pointer operand. This change implements
atomic RMW operations using an integer argument by expanding them to a
cmpxchg sequence (which results in a lr.<size>.cap+sc.<size>.cap loop).
The generated code could be made more efficient by implementing the
necessary hooks for AtomicExpansionKind::LLSC, but that can be done later.

Fixes CTSRD-CHERI#470
@arichardson
Copy link
Member Author

You can ignore all commits other than the last two that don't start with fixup: since they are the same as the last version.

In preparation for the next commit. No functional change but makes bugs
easier to spot.
This change adds new intrinsics that are custom-lowered to the explicit
mode intrinsics since writing tablegen patterns for all the variations
would be extremely tedious (and also result in difficult-to-debug failure
modes).
@arichardson
Copy link
Member Author

Updated to use LR/SC now.

This makes it more awkward to use for out CHERI-RISC-V atomics with
explicit addressing mode since the RISC-V backend only treats XLen-sized
integers as legal. Since this value is only used in an icmp, any integer
type should be fine and it allows us to return an i64 for RV64 instead.
This should generate the same code as i8 addrspace(200)*.
llvm/lib/Target/RISCV/RISCVExpandAtomicPseudoInsts.cpp Outdated Show resolved Hide resolved
Comment on lines +3390 to +3393
// The atomic RMW instructions are only available in capmode, so for the
// hybrid ABI we have expand these operations using a LR/SC sequence.
if (needsExplicitAddressingModeAtomics(AI, Subtarget))
return AtomicExpansionKind::LLSC;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still is differing. It should be doing things exactly the same as the non-explicit versions, just with different expansions in ExpandAtomicPseudoInsts. No new intrinsics should be needed, just a bunch of SelectionDAG pseudos and patterns mirroring what's already there.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like quite a lot of effort. Maybe I'll get to it next year

Copy link
Member

@jrtc27 jrtc27 Nov 9, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW AtomicExpansionKind::LLSC is particularly broken, as it's done far too early in CodeGen so spills and reloads can sneak in between the two, which is highly problematic on architectures that permit very simple implementations with a single link/reserved bit. RISC-V's forward-progress guarantee requires the code to not use any memory instructions in between the LR and the SC, among other things. This is why the pseudos exist and are expanded so late, otherwise RISC-V would just use the existing expansion code and save a lot of effort. CmpXChg does work but is of course much less efficient when your primitive is LR/SC.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good to know, I assumed it would work considering that ARM/AArch64 uses it.

Copy link
Member

@jrtc27 jrtc27 Nov 9, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Arm ARM probably mandates a less-stupid implementation, although maybe technically if you put an atomic on the stack you can get issues there, but why on earth would you do that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(See https://bugs.llvm.org/show_bug.cgi?id=32020 for a real-world case of this mattering)

llvm/lib/Target/RISCV/RISCVISelLowering.cpp Outdated Show resolved Hide resolved
@@ -3440,14 +3531,6 @@ Value *RISCVTargetLowering::emitMaskedAtomicCmpXchgIntrinsic(
return Result;
}

bool RISCVTargetLowering::canLowerPointerTypeCmpXchg(
const llvm::DataLayout &DL, llvm::AtomicCmpXchgInst *AI) const {
if (Subtarget.hasStdExtA() && Subtarget.hasCheri() &&
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does deleting the A check not break non-A codegen?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As you can see in llvm/test/CodeGen/CHERI-Generic/RISCV64/cmpxchg-cap-ptr.ll, removing a results in libcalls, so it does not seem to be required.
If I recall correctly, this function is only used to determine whether the IR can contain cmpxchg instructions with pointer types instead of just integers (since non-RISC-V/non-MIPS backends expect integer operands).

llvm/test/CodeGen/RISCV/cheri/fp32-load-store-hybrid.ll Outdated Show resolved Hide resolved
llvm/test/CodeGen/RISCV/cheri/fp32-load-store-hybrid.ll Outdated Show resolved Hide resolved
llvm/test/CodeGen/RISCV/cheri/fp64-load-store-hybrid.ll Outdated Show resolved Hide resolved
@@ -1770,7 +1800,7 @@ bool AtomicExpand::expandAtomicOpToLibcall(
auto PtrTypeAS = PointerOperand->getType()->getPointerAddressSpace();
Value *PtrVal = Builder.CreateBitCast(PointerOperand,
Type::getInt8PtrTy(Ctx, PtrTypeAS));
unsigned PtrValAS = DL.getAllocaAddrSpace();
auto PtrValAS = PointerOperandIsCap ? PtrTypeAS : DL.getAllocaAddrSpace();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When would this ever not be just PtrTypeAS?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this could happen for other architectures, where you can only pass one type of pointer to libfuncs. We can pass both AS0 and AS200, but that might not always be possible.

@arichardson arichardson marked this pull request as draft November 9, 2020 13:36
@jrtc27
Copy link
Member

jrtc27 commented Nov 9, 2020

Can we split out frontend, target-independent and MIPS bits though, so it's just a case of someone bothering to do the RISC-V backend grunt work?

This current results in a selection failure for RISCV when used on i8/i16
since it's trying to use the masked intrinsics.
… mode

This was previously asserting since the backend tried to use the masked
instrinsics (which cannot be used with capabilities and also should not be
used since we need to remain in-bounds).
Also drop the unnncessary fadd. I think I originally added this to double-
check that it was really generating soft-float code, but this can also be
seen by the lack of fmv.x.w instructions.
@arichardson
Copy link
Member Author

Will split this up into smaller parts.

@arichardson
Copy link
Member Author

Abadoning this PR in favour of smaller ones.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants