Index: llvm/trunk/lib/Target/ARM/ARMISelLowering.h =================================================================== --- llvm/trunk/lib/Target/ARM/ARMISelLowering.h +++ llvm/trunk/lib/Target/ARM/ARMISelLowering.h @@ -393,6 +393,7 @@ Type *Ty, CallingConv::ID CallConv, bool isVarArg) const override; bool hasLoadLinkedStoreConditional() const override; + Instruction *makeDMB(IRBuilder<> &Builder, ARM_MB::MemBOpt Domain) const; Value *emitLoadLinked(IRBuilder<> &Builder, Value *Addr, AtomicOrdering Ord) const override; Value *emitStoreConditional(IRBuilder<> &Builder, Value *Val, Index: llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp =================================================================== --- llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp +++ llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp @@ -10984,11 +10984,33 @@ bool ARMTargetLowering::hasLoadLinkedStoreConditional() const { return true; } -static void makeDMB(IRBuilder<> &Builder, ARM_MB::MemBOpt Domain) { +Instruction* ARMTargetLowering::makeDMB(IRBuilder<> &Builder, + ARM_MB::MemBOpt Domain) const { Module *M = Builder.GetInsertBlock()->getParent()->getParent(); - Function *DMB = llvm::Intrinsic::getDeclaration(M, Intrinsic::arm_dmb); - Constant *CDomain = Builder.getInt32(Domain); - Builder.CreateCall(DMB, CDomain); + + // First, if the target has no DMB, see what fallback we can use. + if (!Subtarget->hasDataBarrier()) { + // Some ARMv6 cpus can support data barriers with an mcr instruction. + // Thumb1 and pre-v6 ARM mode use a libcall instead and should never get + // here. + if (Subtarget->hasV6Ops() && !Subtarget->isThumb()) { + Function *MCR = llvm::Intrinsic::getDeclaration(M, Intrinsic::arm_mcr); + Value* args[6] = {Builder.getInt32(15), Builder.getInt32(0), + Builder.getInt32(0), Builder.getInt32(7), + Builder.getInt32(10), Builder.getInt32(5)}; + return Builder.CreateCall(MCR, args); + } else { + // Instead of using barriers, atomic accesses on these subtargets use + // libcalls. + llvm_unreachable("makeDMB on a target so old that it has no barriers"); + } + } else { + Function *DMB = llvm::Intrinsic::getDeclaration(M, Intrinsic::arm_dmb); + // Only a full system barrier exists in the M-class architectures. + Domain = Subtarget->isMClass() ? ARM_MB::SY : Domain; + Constant *CDomain = Builder.getInt32(Domain); + return Builder.CreateCall(DMB, CDomain); + } } // Based on http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html Index: llvm/trunk/test/CodeGen/ARM/atomic-load-store.ll =================================================================== --- llvm/trunk/test/CodeGen/ARM/atomic-load-store.ll +++ llvm/trunk/test/CodeGen/ARM/atomic-load-store.ll @@ -3,6 +3,8 @@ ; RUN: llc < %s -mtriple=thumbv7-apple-ios -verify-machineinstrs | FileCheck %s -check-prefix=THUMBTWO ; RUN: llc < %s -mtriple=thumbv6-apple-ios | FileCheck %s -check-prefix=THUMBONE ; RUN: llc < %s -mtriple=armv4-apple-ios | FileCheck %s -check-prefix=ARMV4 +; RUN: llc < %s -mtriple=armv6-apple-ios | FileCheck %s -check-prefix=ARMV6 +; RUN: llc < %s -mtriple=thumbv7m-apple-ios | FileCheck %s -check-prefix=THUMBM define void @test1(i32* %ptr, i32 %val1) { ; ARM-LABEL: test1 @@ -15,6 +17,14 @@ ; THUMBTWO: dmb {{ish$}} ; THUMBTWO-NEXT: str ; THUMBTWO-NEXT: dmb {{ish$}} +; ARMV6-LABEL: test1 +; ARMV6: mcr p15, #0, {{r[0-9]*}}, c7, c10, #5 +; ARMV6: str +; ARMV6: mcr p15, #0, {{r[0-9]*}}, c7, c10, #5 +; THUMBM-LABEL: test1 +; THUMBM: dmb sy +; THUMBM: str +; THUMBM: dmb sy store atomic i32 %val1, i32* %ptr seq_cst, align 4 ret void } @@ -28,6 +38,12 @@ ; THUMBTWO-LABEL: test2 ; THUMBTWO: ldr ; THUMBTWO-NEXT: dmb {{ish$}} +; ARMV6-LABEL: test2 +; ARMV6: ldr +; ARMV6: mcr p15, #0, {{r[0-9]*}}, c7, c10, #5 +; THUMBM-LABEL: test2 +; THUMBM: ldr +; THUMBM: dmb sy %val = load atomic i32* %ptr seq_cst, align 4 ret i32 %val } @@ -55,6 +71,11 @@ ; THUMBONE-NOT: dmb ; THUMBONE: strb ; THUMBONE-NOT: dmb + +; ARMV6-LABEL: test3 +; ARMV6-NOT: mcr +; THUMBM-LABEL: test3 +; THUMBM-NOT: dmb sy %val = load atomic i8* %ptr1 unordered, align 1 store atomic i8 %val, i8* %ptr2 unordered, align 1 ret void @@ -64,6 +85,8 @@ ; THUMBONE-LABEL: test4 ; THUMBONE: ___sync_val_compare_and_swap_1 ; THUMBONE: ___sync_lock_test_and_set_1 +; ARMV6-LABEL: test4 +; THUMBM-LABEL: test4 %val = load atomic i8* %ptr1 seq_cst, align 1 store atomic i8 %val, i8* %ptr2 seq_cst, align 1 ret void