-
Notifications
You must be signed in to change notification settings - Fork 36
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
Conversation
a39a0c4
to
b524fc8
Compare
ping? (I'll fix the amdgpu test if this change looks ok) |
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. |
Last commit was submitted upstream as https://reviews.llvm.org/D88800 |
ping? |
There was a problem hiding this 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.
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.
f44ba4e
to
8951c74
Compare
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
8951c74
to
f14898b
Compare
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).
Updated to use LR/SC now. |
15a36f9
to
8806d23
Compare
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)*.
8806d23
to
38f7b1c
Compare
llvm/test/CodeGen/CHERI-Generic/Inputs/atomic-rmw-cap-ptr-cap-arg.ll
Outdated
Show resolved
Hide resolved
// 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; |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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)
@@ -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() && |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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/CHERI-Generic/Inputs/atomic-rmw-cap-ptr-cap-arg.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(); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
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.
Will split this up into smaller parts. |
38f7b1c
to
e60382c
Compare
Abadoning this PR in favour of smaller ones. |
This cleans up various atomic code generation bugs and adds support for atomic RMW operations in hybrid mode for both RISC-V and MIPS.