diff options
author | Robin Morisset <morisset@google.com> | 2014-09-03 21:01:03 +0000 |
---|---|---|
committer | Robin Morisset <morisset@google.com> | 2014-09-03 21:01:03 +0000 |
commit | a47cb411dc977a03cba06046677f23a15b41c461 (patch) | |
tree | 7a8e8ffd5228d8466b22aab9f4170ec712cc8838 /llvm/lib/Target/ARM/ARMISelLowering.cpp | |
parent | 88e32517c4b190df960a9f281f5c958c4143df15 (diff) | |
download | bcm5719-llvm-a47cb411dc977a03cba06046677f23a15b41c461.tar.gz bcm5719-llvm-a47cb411dc977a03cba06046677f23a15b41c461.zip |
Use target-dependent emitLeading/TrailingFence instead of the target-independent insertLeading/TrailingFence (in AtomicExpandPass)
Fixes two latent bugs:
- There was no fence inserted before expanded seq_cst load (unsound on Power)
- There was only a fence release before seq_cst stores (again unsound, in particular on Power)
It is not even clear if this is correct on ARM swift processors (where release fences are
DMB ishst instead of DMB ish). This behaviour is currently preserved on ARM Swift
as it is not clear whether it is incorrect. I would love to get documentation stating
whether it is correct or not.
These two bugs were not triggered because Power is not (yet) using this pass, and these
behaviours happen to be (mostly?) working on ARM
(although they completely butchered the semantics of the llvm IR).
See:
http://lists.cs.uiuc.edu/pipermail/llvmdev/2014-August/075821.html
for an example of the problems that can be caused by the second of these bugs.
I couldn't see a way of fixing these in a completely target-independent way without
adding lots of unnecessary fences on ARM, hence the target-dependent parts of this
patch.
This patch implements the new target-dependent parts only for ARM (the default
of not doing anything is enough for AArch64), other architectures will use this
infrastructure in later patches.
llvm-svn: 217076
Diffstat (limited to 'llvm/lib/Target/ARM/ARMISelLowering.cpp')
-rw-r--r-- | llvm/lib/Target/ARM/ARMISelLowering.cpp | 59 |
1 files changed, 58 insertions, 1 deletions
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp index 0e78204bbf8..aeed2b2dede 100644 --- a/llvm/lib/Target/ARM/ARMISelLowering.cpp +++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp @@ -2723,7 +2723,7 @@ static SDValue LowerATOMIC_FENCE(SDValue Op, SelectionDAG &DAG, ConstantSDNode *OrdN = cast<ConstantSDNode>(Op.getOperand(1)); AtomicOrdering Ord = static_cast<AtomicOrdering>(OrdN->getZExtValue()); - unsigned Domain = ARM_MB::ISH; + ARM_MB::MemBOpt Domain = ARM_MB::ISH; if (Subtarget->isMClass()) { // Only a full system barrier exists in the M-class architectures. Domain = ARM_MB::SY; @@ -10982,6 +10982,63 @@ bool ARMTargetLowering::shouldConvertConstantLoadToIntImm(const APInt &Imm, return true; } +static void makeDMB(IRBuilder<> &Builder, ARM_MB::MemBOpt Domain) { + Module *M = Builder.GetInsertBlock()->getParent()->getParent(); + Function *DMB = llvm::Intrinsic::getDeclaration(M, Intrinsic::arm_dmb); + Constant *CDomain = Builder.getInt32(Domain); + Builder.CreateCall(DMB, CDomain); +} + +// Based on http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html +void ARMTargetLowering::emitLeadingFence(IRBuilder<> &Builder, + AtomicOrdering Ord, bool IsStore, + bool IsLoad) const { + if (!getInsertFencesForAtomic()) + return; + + switch (Ord) { + case NotAtomic: + case Unordered: + llvm_unreachable("Invalid fence: unordered/non-atomic"); + case Monotonic: + case Acquire: + return; // Nothing to do + case SequentiallyConsistent: + if (!IsStore) + return; // Nothing to do + /*FALLTHROUGH*/ + case Release: + case AcquireRelease: + if (Subtarget->isSwift()) + makeDMB(Builder, ARM_MB::ISHST); + // FIXME: add a comment with a link to documentation justifying this. + else + makeDMB(Builder, ARM_MB::ISH); + return; + } +} + +void ARMTargetLowering::emitTrailingFence(IRBuilder<> &Builder, + AtomicOrdering Ord, bool IsStore, + bool IsLoad) const { + if (!getInsertFencesForAtomic()) + return; + + switch (Ord) { + case NotAtomic: + case Unordered: + llvm_unreachable("Invalid fence: unordered/not-atomic"); + case Monotonic: + case Release: + return; // Nothing to do + case Acquire: + case AcquireRelease: + case SequentiallyConsistent: + makeDMB(Builder, ARM_MB::ISH); + return; + } +} + bool ARMTargetLowering::shouldExpandAtomicInIR(Instruction *Inst) const { // Loads and stores less than 64-bits are already atomic; ones above that // are doomed anyway, so defer to the default libcall and blame the OS when |