diff options
author | Tim Northover <tnorthover@apple.com> | 2014-06-16 18:49:36 +0000 |
---|---|---|
committer | Tim Northover <tnorthover@apple.com> | 2014-06-16 18:49:36 +0000 |
commit | b45c3b74b4641a129a9d4e8c6b1e1d6b38a1b4a5 (patch) | |
tree | 94027718dc54d87fc17fc588ae95f45a151a5f44 /llvm | |
parent | 4c2a0425b8b9703a0d113c2ba66b394027d72f20 (diff) | |
download | bcm5719-llvm-b45c3b74b4641a129a9d4e8c6b1e1d6b38a1b4a5.tar.gz bcm5719-llvm-b45c3b74b4641a129a9d4e8c6b1e1d6b38a1b4a5.zip |
ARM: implement correct atomic operations on v7M
ARM v7M has ldrex/strex but not ldrexd/strexd. This means 32-bit
operations should work as normal, but 64-bit ones are almost certainly
doomed.
Patch by Phoebe Buckheister.
llvm-svn: 211042
Diffstat (limited to 'llvm')
-rw-r--r-- | llvm/lib/Target/ARM/ARMISelLowering.cpp | 22 | ||||
-rw-r--r-- | llvm/test/CodeGen/ARM/ldstrex-m.ll | 59 |
2 files changed, 73 insertions, 8 deletions
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp index 3350601aadc..f9fc641b12d 100644 --- a/llvm/lib/Target/ARM/ARMISelLowering.cpp +++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp @@ -10744,14 +10744,20 @@ bool ARMTargetLowering::shouldConvertConstantLoadToIntImm(const APInt &Imm, 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 - // things go wrong: - if (StoreInst *SI = dyn_cast<StoreInst>(Inst)) - return SI->getValueOperand()->getType()->getPrimitiveSizeInBits() == 64; - else if (LoadInst *LI = dyn_cast<LoadInst>(Inst)) - return LI->getType()->getPrimitiveSizeInBits() == 64; - - // For the real atomic operations, we have ldrex/strex up to 64 bits. - return Inst->getType()->getPrimitiveSizeInBits() <= 64; + // things go wrong. Cortex M doesn't have ldrexd/strexd though, so don't emit + // anything for those. + bool IsMClass = Subtarget->isMClass(); + if (StoreInst *SI = dyn_cast<StoreInst>(Inst)) { + unsigned Size = SI->getValueOperand()->getType()->getPrimitiveSizeInBits(); + return Size == 64 && !IsMClass; + } else if (LoadInst *LI = dyn_cast<LoadInst>(Inst)) { + return LI->getType()->getPrimitiveSizeInBits() == 64 && !IsMClass; + } + + // For the real atomic operations, we have ldrex/strex up to 32 bits, + // and up to 64 bits on the non-M profiles + unsigned AtomicLimit = IsMClass ? 32 : 64; + return Inst->getType()->getPrimitiveSizeInBits() <= AtomicLimit; } Value *ARMTargetLowering::emitLoadLinked(IRBuilder<> &Builder, Value *Addr, diff --git a/llvm/test/CodeGen/ARM/ldstrex-m.ll b/llvm/test/CodeGen/ARM/ldstrex-m.ll new file mode 100644 index 00000000000..b50699f4cde --- /dev/null +++ b/llvm/test/CodeGen/ARM/ldstrex-m.ll @@ -0,0 +1,59 @@ +; RUN: llc < %s -mtriple=thumbv7m-none-eabi -mcpu=cortex-m4 | FileCheck %s + +; CHECK-LABEL: f0: +; CHECK-NOT: ldrexd +define i64 @f0(i64* %p) nounwind readonly { +entry: + %0 = load atomic i64* %p seq_cst, align 8 + ret i64 %0 +} + +; CHECK-LABEL: f1: +; CHECK-NOT: strexd +define void @f1(i64* %p) nounwind readonly { +entry: + store atomic i64 0, i64* %p seq_cst, align 8 + ret void +} + +; CHECK-LABEL: f2: +; CHECK-NOT: ldrexd +; CHECK-NOT: strexd +define i64 @f2(i64* %p) nounwind readonly { +entry: + %0 = atomicrmw add i64* %p, i64 1 seq_cst + ret i64 %0 +} + +; CHECK-LABEL: f3: +; CHECK: ldr +define i32 @f3(i32* %p) nounwind readonly { +entry: + %0 = load atomic i32* %p seq_cst, align 4 + ret i32 %0 +} + +; CHECK-LABEL: f4: +; CHECK: ldrb +define i8 @f4(i8* %p) nounwind readonly { +entry: + %0 = load atomic i8* %p seq_cst, align 4 + ret i8 %0 +} + +; CHECK-LABEL: f5: +; CHECK: str +define void @f5(i32* %p) nounwind readonly { +entry: + store atomic i32 0, i32* %p seq_cst, align 4 + ret void +} + +; CHECK-LABEL: f6: +; CHECK: ldrex +; CHECK: strex +define i32 @f6(i32* %p) nounwind readonly { +entry: + %0 = atomicrmw add i32* %p, i32 1 seq_cst + ret i32 %0 +} |