From f33a30cdd02460a469e3bd93f424a2dc602d2ca4 Mon Sep 17 00:00:00 2001 From: Yi Kong Date: Thu, 17 Jul 2014 10:50:20 +0000 Subject: [PATCH] Port memory barriers intrinsics to AArch64 Memory barrier __builtin_arm_[dmb, dsb, isb] intrinsics are required to implement their corresponding ACLE and MSVC intrinsics. This patch ports ARM dmb, dsb, isb intrinsic to AArch64. Differential Revision: http://reviews.llvm.org/D4520 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@213247 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/IR/IntrinsicsAArch64.td | 7 +++ lib/Target/AArch64/AArch64InstrFormats.td | 10 +++- lib/Target/AArch64/AArch64InstrInfo.td | 18 ++++-- .../AArch64/intrinsics-memory-barrier.ll | 57 +++++++++++++++++++ 4 files changed, 86 insertions(+), 6 deletions(-) create mode 100644 test/CodeGen/AArch64/intrinsics-memory-barrier.ll diff --git a/include/llvm/IR/IntrinsicsAArch64.td b/include/llvm/IR/IntrinsicsAArch64.td index 050762b6114..7d69ed52171 100644 --- a/include/llvm/IR/IntrinsicsAArch64.td +++ b/include/llvm/IR/IntrinsicsAArch64.td @@ -43,6 +43,13 @@ def int_aarch64_hint : Intrinsic<[], [llvm_i32_ty]>; def int_aarch64_rbit : Intrinsic<[llvm_anyint_ty], [LLVMMatchType<0>], [IntrNoMem]>; +//===----------------------------------------------------------------------===// +// Data Barrier Instructions + +def int_aarch64_dmb : GCCBuiltin<"__builtin_arm_dmb">, Intrinsic<[], [llvm_i32_ty]>; +def int_aarch64_dsb : GCCBuiltin<"__builtin_arm_dsb">, Intrinsic<[], [llvm_i32_ty]>; +def int_aarch64_isb : GCCBuiltin<"__builtin_arm_isb">, Intrinsic<[], [llvm_i32_ty]>; + } //===----------------------------------------------------------------------===// diff --git a/lib/Target/AArch64/AArch64InstrFormats.td b/lib/Target/AArch64/AArch64InstrFormats.td index 0c9687eca56..e88c0c038c3 100644 --- a/lib/Target/AArch64/AArch64InstrFormats.td +++ b/lib/Target/AArch64/AArch64InstrFormats.td @@ -539,6 +539,11 @@ def imm0_7 : Operand, ImmLeaf, ImmLeaf; + // An arithmetic shifter operand: // {7-6} - shift type: 00 = lsl, 01 = lsr, 10 = asr // {5-0} - imm6 @@ -821,8 +826,9 @@ def barrier_op : Operand { let PrintMethod = "printBarrierOption"; let ParserMatchClass = BarrierAsmOperand; } -class CRmSystemI opc, string asm> - : SimpleSystemI<0, (ins crmtype:$CRm), asm, "\t$CRm">, +class CRmSystemI opc, string asm, + list pattern = []> + : SimpleSystemI<0, (ins crmtype:$CRm), asm, "\t$CRm", pattern>, Sched<[WriteBarrier]> { bits<4> CRm; let Inst{20-12} = 0b000110011; diff --git a/lib/Target/AArch64/AArch64InstrInfo.td b/lib/Target/AArch64/AArch64InstrInfo.td index 3ec0212b416..0fae8021950 100644 --- a/lib/Target/AArch64/AArch64InstrInfo.td +++ b/lib/Target/AArch64/AArch64InstrInfo.td @@ -331,13 +331,23 @@ def : InstAlias<"wfi", (HINT 0b011)>; def : InstAlias<"sev", (HINT 0b100)>; def : InstAlias<"sevl", (HINT 0b101)>; - // As far as LLVM is concerned this writes to the system's exclusive monitors. +// As far as LLVM is concerned this writes to the system's exclusive monitors. let mayLoad = 1, mayStore = 1 in def CLREX : CRmSystemI; -def DMB : CRmSystemI; -def DSB : CRmSystemI; -def ISB : CRmSystemI; +// NOTE: ideally, this would have mayStore = 0, mayLoad = 0, but we cannot +// model patterns with sufficiently fine granularity. +let mayLoad = ?, mayStore = ? in { +def DMB : CRmSystemI; + +def DSB : CRmSystemI; + +def ISB : CRmSystemI; +} + def : InstAlias<"clrex", (CLREX 0xf)>; def : InstAlias<"isb", (ISB 0xf)>; diff --git a/test/CodeGen/AArch64/intrinsics-memory-barrier.ll b/test/CodeGen/AArch64/intrinsics-memory-barrier.ll new file mode 100644 index 00000000000..09e34ae2d2e --- /dev/null +++ b/test/CodeGen/AArch64/intrinsics-memory-barrier.ll @@ -0,0 +1,57 @@ +; RUN: llc < %s -mtriple=aarch64-eabi -O=3 | FileCheck %s + +define void @test() { + ; CHECK: dmb sy + call void @llvm.aarch64.dmb(i32 15) + ; CHECK: dmb osh + call void @llvm.aarch64.dmb(i32 3) + ; CHECK: dsb sy + call void @llvm.aarch64.dsb(i32 15) + ; CHECK: dsb ishld + call void @llvm.aarch64.dsb(i32 9) + ; CHECK: isb + call void @llvm.aarch64.isb(i32 15) + 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 STP. +define void @test_dmb_reordering(i32 %a, i32 %b, i32* %d) { + store i32 %a, i32* %d ; CHECK: str {{w[0-9]+}}, [{{x[0-9]+}}] + + call void @llvm.aarch64.dmb(i32 15); CHECK: dmb sy + + %d1 = getelementptr i32* %d, i64 1 + store i32 %b, i32* %d1 ; CHECK: str {{w[0-9]+}}, [{{x[0-9]+}}, #4] + + ret void +} + +; Similarly for DSB. +define void @test_dsb_reordering(i32 %a, i32 %b, i32* %d) { + store i32 %a, i32* %d ; CHECK: str {{w[0-9]+}}, [{{x[0-9]+}}] + + call void @llvm.aarch64.dsb(i32 15); CHECK: dsb sy + + %d1 = getelementptr i32* %d, i64 1 + store i32 %b, i32* %d1 ; CHECK: str {{w[0-9]+}}, [{{x[0-9]+}}, #4] + + ret void +} + +; And ISB. +define void @test_isb_reordering(i32 %a, i32 %b, i32* %d) { + store i32 %a, i32* %d ; CHECK: str {{w[0-9]+}}, [{{x[0-9]+}}] + + call void @llvm.aarch64.isb(i32 15); CHECK: isb + + %d1 = getelementptr i32* %d, i64 1 + store i32 %b, i32* %d1 ; CHECK: str {{w[0-9]+}}, [{{x[0-9]+}}, #4] + + ret void +} + +declare void @llvm.aarch64.dmb(i32) +declare void @llvm.aarch64.dsb(i32) +declare void @llvm.aarch64.isb(i32)