From 090a8f45f20688a03f5fe9c797a64a22ec004adc Mon Sep 17 00:00:00 2001 From: Yi Kong Date: Thu, 3 Jul 2014 16:00:41 +0000 Subject: [PATCH] [ARM] Implement ISB memory barrier intrinsic Adds support for __builtin_arm_isb. Also corrects DSB and ISB instructions modelling by adding has-side-effects property. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@212276 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/IR/IntrinsicsARM.td | 1 + lib/Target/ARM/ARMInstrInfo.td | 6 +- lib/Target/ARM/ARMInstrThumb2.td | 9 +-- test/CodeGen/ARM/intrinsics-memory-barrier.ll | 55 +++++++++++++++++++ 4 files changed, 64 insertions(+), 7 deletions(-) create mode 100644 test/CodeGen/ARM/intrinsics-memory-barrier.ll diff --git a/include/llvm/IR/IntrinsicsARM.td b/include/llvm/IR/IntrinsicsARM.td index 145eeedc22b..16ac857045e 100644 --- a/include/llvm/IR/IntrinsicsARM.td +++ b/include/llvm/IR/IntrinsicsARM.td @@ -56,6 +56,7 @@ def int_arm_ldaexd : Intrinsic<[llvm_i32_ty, llvm_i32_ty], [llvm_ptr_ty]>; // Data barrier instructions def int_arm_dmb : GCCBuiltin<"__builtin_arm_dmb">, Intrinsic<[], [llvm_i32_ty]>; def int_arm_dsb : GCCBuiltin<"__builtin_arm_dsb">, Intrinsic<[], [llvm_i32_ty]>; +def int_arm_isb : GCCBuiltin<"__builtin_arm_isb">, Intrinsic<[], [llvm_i32_ty]>; //===----------------------------------------------------------------------===// // VFP diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td index af946a90b19..15e4483a77b 100644 --- a/lib/Target/ARM/ARMInstrInfo.td +++ b/lib/Target/ARM/ARMInstrInfo.td @@ -4443,7 +4443,7 @@ def instsyncb_opt : Operand { let DecoderMethod = "DecodeInstSyncBarrierOption"; } -// memory barriers protect the atomic sequences +// Memory barriers protect the atomic sequences let hasSideEffects = 1 in { def DMB : AInoP<(outs), (ins memb_opt:$opt), MiscFrm, NoItinerary, "dmb", "\t$opt", [(int_arm_dmb (i32 imm0_15:$opt))]>, @@ -4452,7 +4452,6 @@ def DMB : AInoP<(outs), (ins memb_opt:$opt), MiscFrm, NoItinerary, let Inst{31-4} = 0xf57ff05; let Inst{3-0} = opt; } -} def DSB : AInoP<(outs), (ins memb_opt:$opt), MiscFrm, NoItinerary, "dsb", "\t$opt", [(int_arm_dsb (i32 imm0_15:$opt))]>, @@ -4464,12 +4463,13 @@ def DSB : AInoP<(outs), (ins memb_opt:$opt), MiscFrm, NoItinerary, // ISB has only full system option def ISB : AInoP<(outs), (ins instsyncb_opt:$opt), MiscFrm, NoItinerary, - "isb", "\t$opt", []>, + "isb", "\t$opt", [(int_arm_isb (i32 imm0_15:$opt))]>, Requires<[IsARM, HasDB]> { bits<4> opt; let Inst{31-4} = 0xf57ff06; let Inst{3-0} = opt; } +} let usesCustomInserter = 1, Defs = [CPSR] in { diff --git a/lib/Target/ARM/ARMInstrThumb2.td b/lib/Target/ARM/ARMInstrThumb2.td index c30d6abbb29..85e93516807 100644 --- a/lib/Target/ARM/ARMInstrThumb2.td +++ b/lib/Target/ARM/ARMInstrThumb2.td @@ -3209,27 +3209,28 @@ def t2MOVCCi32imm let hasSideEffects = 1 in { def t2DMB : T2I<(outs), (ins memb_opt:$opt), NoItinerary, "dmb", "\t$opt", [(int_arm_dmb (i32 imm0_15:$opt))]>, - Requires<[HasDB]> { + Requires<[IsThumb, HasDB]> { bits<4> opt; let Inst{31-4} = 0xf3bf8f5; let Inst{3-0} = opt; } -} def t2DSB : T2I<(outs), (ins memb_opt:$opt), NoItinerary, "dsb", "\t$opt", [(int_arm_dsb (i32 imm0_15:$opt))]>, - Requires<[HasDB]> { + Requires<[IsThumb, HasDB]> { bits<4> opt; let Inst{31-4} = 0xf3bf8f4; let Inst{3-0} = opt; } def t2ISB : T2I<(outs), (ins instsyncb_opt:$opt), NoItinerary, - "isb", "\t$opt", []>, Requires<[HasDB]> { + "isb", "\t$opt", [(int_arm_isb (i32 imm0_15:$opt))]>, + Requires<[IsThumb, HasDB]> { bits<4> opt; let Inst{31-4} = 0xf3bf8f6; let Inst{3-0} = opt; } +} class T2I_ldrex opcod, dag oops, dag iops, AddrMode am, int sz, InstrItinClass itin, string opc, string asm, string cstr, diff --git a/test/CodeGen/ARM/intrinsics-memory-barrier.ll b/test/CodeGen/ARM/intrinsics-memory-barrier.ll new file mode 100644 index 00000000000..5ee0b3e5990 --- /dev/null +++ b/test/CodeGen/ARM/intrinsics-memory-barrier.ll @@ -0,0 +1,55 @@ +; RUN: llc < %s -mtriple=armv7 -mattr=+db | FileCheck %s +; RUN: llc < %s -mtriple=thumbv7 -mattr=+db | FileCheck %s + +; CHECK-LABEL: test +define void @test() { + call void @llvm.arm.dmb(i32 3) ; CHECK: dmb osh + call void @llvm.arm.dsb(i32 7) ; CHECK: dsb nsh + call void @llvm.arm.isb(i32 15) ; CHECK: isb sy + ret void +} + +; Important point is that the compiler should not reorder memory access +; instructions around DMB. +; Failure to do so, two STRs will collapse into one STRD. +; CHECK-LABEL: test_dmb_reordering +define void @test_dmb_reordering(i32 %a, i32 %b, i32* %d) { + store i32 %a, i32* %d ; CHECK: str {{r[0-9]+}}, [{{r[0-9]+}}] + + call void @llvm.arm.dmb(i32 15) ; CHECK: dmb sy + + %d1 = getelementptr i32* %d, i32 1 + store i32 %b, i32* %d1 ; CHECK: str {{r[0-9]+}}, [{{r[0-9]+}}, #4] + + ret void +} + +; Similarly for DSB. +; CHECK-LABEL: test_dsb_reordering +define void @test_dsb_reordering(i32 %a, i32 %b, i32* %d) { + store i32 %a, i32* %d ; CHECK: str {{r[0-9]+}}, [{{r[0-9]+}}] + + call void @llvm.arm.dsb(i32 15) ; CHECK: dsb sy + + %d1 = getelementptr i32* %d, i32 1 + store i32 %b, i32* %d1 ; CHECK: str {{r[0-9]+}}, [{{r[0-9]+}}, #4] + + ret void +} + +; And ISB. +; CHECK-LABEL: test_isb_reordering +define void @test_isb_reordering(i32 %a, i32 %b, i32* %d) { + store i32 %a, i32* %d ; CHECK: str {{r[0-9]+}}, [{{r[0-9]+}}] + + call void @llvm.arm.isb(i32 15) ; CHECK: isb sy + + %d1 = getelementptr i32* %d, i32 1 + store i32 %b, i32* %d1 ; CHECK: str {{r[0-9]+}}, [{{r[0-9]+}}, #4] + + ret void +} + +declare void @llvm.arm.dmb(i32) +declare void @llvm.arm.dsb(i32) +declare void @llvm.arm.isb(i32) -- 2.34.1