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]>;
+
}
//===----------------------------------------------------------------------===//
let ParserMatchClass = Imm0_7Operand;
}
+// imm32_0_15 predicate - True if the 32-bit immediate is in the range [0,15]
+def imm32_0_15 : Operand<i32>, ImmLeaf<i32, [{
+ return ((uint32_t)Imm) < 16;
+}]>;
+
// An arithmetic shifter operand:
// {7-6} - shift type: 00 = lsl, 01 = lsr, 10 = asr
// {5-0} - imm6
let PrintMethod = "printBarrierOption";
let ParserMatchClass = BarrierAsmOperand;
}
-class CRmSystemI<Operand crmtype, bits<3> opc, string asm>
- : SimpleSystemI<0, (ins crmtype:$CRm), asm, "\t$CRm">,
+class CRmSystemI<Operand crmtype, bits<3> opc, string asm,
+ list<dag> pattern = []>
+ : SimpleSystemI<0, (ins crmtype:$CRm), asm, "\t$CRm", pattern>,
Sched<[WriteBarrier]> {
bits<4> CRm;
let Inst{20-12} = 0b000110011;
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<imm0_15, 0b010, "clrex">;
-def DMB : CRmSystemI<barrier_op, 0b101, "dmb">;
-def DSB : CRmSystemI<barrier_op, 0b100, "dsb">;
-def ISB : CRmSystemI<barrier_op, 0b110, "isb">;
+// 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<barrier_op, 0b101, "dmb",
+ [(int_aarch64_dmb (i32 imm32_0_15:$CRm))]>;
+
+def DSB : CRmSystemI<barrier_op, 0b100, "dsb",
+ [(int_aarch64_dsb (i32 imm32_0_15:$CRm))]>;
+
+def ISB : CRmSystemI<barrier_op, 0b110, "isb",
+ [(int_aarch64_isb (i32 imm32_0_15:$CRm))]>;
+}
+
def : InstAlias<"clrex", (CLREX 0xf)>;
def : InstAlias<"isb", (ISB 0xf)>;
--- /dev/null
+; 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)