// The Memory Barrier Option constants map directly to the 4-bit encoding of
// the option field for memory barrier operations.
enum MemBOpt {
+ SY = 15,
ST = 14,
ISH = 11,
ISHST = 10,
inline static const char *MemBOptToString(unsigned val) {
switch (val) {
default: llvm_unreachable("Unknown memory operation");
+ case SY: return "sy";
case ST: return "st";
case ISH: return "ish";
case ISHST: return "ishst";
case ARMISD::DYN_ALLOC: return "ARMISD::DYN_ALLOC";
case ARMISD::MEMBARRIER: return "ARMISD::MEMBARRIER";
- case ARMISD::SYNCBARRIER: return "ARMISD::SYNCBARRIER";
+ case ARMISD::MEMBARRIER_MCR: return "ARMISD::MEMBARRIER_MCR";
case ARMISD::VCEQ: return "ARMISD::VCEQ";
case ARMISD::VCGE: return "ARMISD::VCGE";
static SDValue LowerMEMBARRIER(SDValue Op, SelectionDAG &DAG,
const ARMSubtarget *Subtarget) {
DebugLoc dl = Op.getDebugLoc();
- SDValue Op5 = Op.getOperand(5);
- unsigned isDeviceBarrier = cast<ConstantSDNode>(Op5)->getZExtValue();
- // Some subtargets which have dmb and dsb instructions can handle barriers
- // directly. Some ARMv6 cpus can support them with the help of mcr
- // instruction. Thumb1 and pre-v6 ARM mode use a libcall instead and should
- // never get here.
- unsigned Opc = isDeviceBarrier ? ARMISD::SYNCBARRIER : ARMISD::MEMBARRIER;
- if (Subtarget->hasDataBarrier())
- return DAG.getNode(Opc, dl, MVT::Other, Op.getOperand(0));
- else {
+ 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.
assert(Subtarget->hasV6Ops() && !Subtarget->isThumb1Only() &&
"Unexpected ISD::MEMBARRIER encountered. Should be libcall!");
- return DAG.getNode(Opc, dl, MVT::Other, Op.getOperand(0),
+ return DAG.getNode(ARMISD::MEMBARRIER_MCR, dl, MVT::Other, Op.getOperand(0),
DAG.getConstant(0, MVT::i32));
}
+
+ SDValue Op5 = Op.getOperand(5);
+ bool isDeviceBarrier = cast<ConstantSDNode>(Op5)->getZExtValue() != 0;
+ unsigned isLL = cast<ConstantSDNode>(Op.getOperand(1))->getZExtValue();
+ unsigned isLS = cast<ConstantSDNode>(Op.getOperand(2))->getZExtValue();
+ bool isOnlyStoreBarrier = (isLL == 0 && isLS == 0);
+
+ ARM_MB::MemBOpt DMBOpt;
+ if (isDeviceBarrier)
+ DMBOpt = isOnlyStoreBarrier ? ARM_MB::ST : ARM_MB::SY;
+ else
+ DMBOpt = isOnlyStoreBarrier ? ARM_MB::ISHST : ARM_MB::ISH;
+ return DAG.getNode(ARMISD::MEMBARRIER, dl, MVT::Other, Op.getOperand(0),
+ DAG.getConstant(DMBOpt, MVT::i32));
}
static SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) {
DYN_ALLOC, // Dynamic allocation on the stack.
- MEMBARRIER, // Memory barrier
- SYNCBARRIER, // Memory sync barrier
+ MEMBARRIER, // Memory barrier (DMB)
+ MEMBARRIER_MCR, // Memory barrier (MCR)
VCEQ, // Vector compare equal.
VCGE, // Vector compare greater than or equal.
def SDT_ARMEH_SJLJ_DispatchSetup: SDTypeProfile<0, 1, [SDTCisPtrTy<0>]>;
-def SDT_ARMMEMBARRIER : SDTypeProfile<0, 0, []>;
-def SDT_ARMSYNCBARRIER : SDTypeProfile<0, 0, []>;
-def SDT_ARMMEMBARRIERMCR : SDTypeProfile<0, 1, [SDTCisInt<0>]>;
-def SDT_ARMSYNCBARRIERMCR : SDTypeProfile<0, 1, [SDTCisInt<0>]>;
+def SDT_ARMMEMBARRIER : SDTypeProfile<0, 1, [SDTCisInt<0>]>;
def SDT_ARMTCRET : SDTypeProfile<0, 1, [SDTCisPtrTy<0>]>;
def ARMMemBarrier : SDNode<"ARMISD::MEMBARRIER", SDT_ARMMEMBARRIER,
[SDNPHasChain]>;
-def ARMSyncBarrier : SDNode<"ARMISD::SYNCBARRIER", SDT_ARMMEMBARRIER,
- [SDNPHasChain]>;
-def ARMMemBarrierMCR : SDNode<"ARMISD::MEMBARRIER", SDT_ARMMEMBARRIERMCR,
- [SDNPHasChain]>;
-def ARMSyncBarrierMCR : SDNode<"ARMISD::SYNCBARRIER", SDT_ARMMEMBARRIERMCR,
+def ARMMemBarrierMCR : SDNode<"ARMISD::MEMBARRIER_MCR", SDT_ARMMEMBARRIER,
[SDNPHasChain]>;
def ARMrbit : SDNode<"ARMISD::RBIT", SDTIntUnaryOp>;
// Atomic operations intrinsics
//
+def memb_opt : Operand<i32> {
+ let PrintMethod = "printMemBOption";
+}
+
// memory barriers protect the atomic sequences
let hasSideEffects = 1 in {
-def DMBsy : AInoP<(outs), (ins), MiscFrm, NoItinerary, "dmb", "",
- [(ARMMemBarrier)]>, Requires<[IsARM, HasDB]> {
+def DMB : AInoP<(outs), (ins memb_opt:$opt), MiscFrm, NoItinerary,
+ "dmb", "\t$opt", [(ARMMemBarrier (i32 imm:$opt))]>,
+ Requires<[IsARM, HasDB]> {
+ bits<4> opt;
let Inst{31-4} = 0xf57ff05;
- // FIXME: add support for options other than a full system DMB
- // See DMB disassembly-only variants below.
- let Inst{3-0} = 0b1111;
-}
-
-def DSBsy : AInoP<(outs), (ins), MiscFrm, NoItinerary, "dsb", "",
- [(ARMSyncBarrier)]>, Requires<[IsARM, HasDB]> {
- let Inst{31-4} = 0xf57ff04;
- // FIXME: add support for options other than a full system DSB
- // See DSB disassembly-only variants below.
- let Inst{3-0} = 0b1111;
+ let Inst{3-0} = opt;
}
def DMB_MCR : AInoP<(outs), (ins GPR:$zero), MiscFrm, NoItinerary,
"mcr", "\tp15, 0, $zero, c7, c10, 5",
[(ARMMemBarrierMCR GPR:$zero)]>,
Requires<[IsARM, HasV6]> {
- // FIXME: add support for options other than a full system DMB
// FIXME: add encoding
}
-
-def DSB_MCR : AInoP<(outs), (ins GPR:$zero), MiscFrm, NoItinerary,
- "mcr", "\tp15, 0, $zero, c7, c10, 4",
- [(ARMSyncBarrierMCR GPR:$zero)]>,
- Requires<[IsARM, HasV6]> {
- // FIXME: add support for options other than a full system DSB
- // FIXME: add encoding
-}
-}
-
-// Memory Barrier Operations Variants -- for disassembly only
-
-def memb_opt : Operand<i32> {
- let PrintMethod = "printMemBOption";
}
-class AMBI<bits<4> op7_4, string opc>
- : AInoP<(outs), (ins memb_opt:$opt), MiscFrm, NoItinerary, opc, "\t$opt",
- [/* For disassembly only; pattern left blank */]>,
- Requires<[IsARM, HasDB]> {
- let Inst{31-8} = 0xf57ff0;
- let Inst{7-4} = op7_4;
+def DSB : AInoP<(outs), (ins memb_opt:$opt), MiscFrm, NoItinerary,
+ "dsb", "\t$opt",
+ [/* For disassembly only; pattern left blank */]>,
+ Requires<[IsARM, HasDB]> {
+ bits<4> opt;
+ let Inst{31-4} = 0xf57ff04;
+ let Inst{3-0} = opt;
}
-// These DMB variants are for disassembly only.
-def DMBvar : AMBI<0b0101, "dmb">;
-
-// These DSB variants are for disassembly only.
-def DSBvar : AMBI<0b0100, "dsb">;
-
// ISB has only full system option -- for disassembly only
-def ISBsy : AInoP<(outs), (ins), MiscFrm, NoItinerary, "isb", "", []>,
- Requires<[IsARM, HasDB]> {
+def ISB : AInoP<(outs), (ins), MiscFrm, NoItinerary, "isb", "", []>,
+ Requires<[IsARM, HasDB]> {
let Inst{31-4} = 0xf57ff06;
let Inst{3-0} = 0b1111;
}
// memory barriers protect the atomic sequences
let hasSideEffects = 1 in {
-def t2DMBsy : AInoP<(outs), (ins), ThumbFrm, NoItinerary, "dmb", "",
- [(ARMMemBarrier)]>, Requires<[IsThumb, HasDB]> {
- let Inst{31-4} = 0xF3BF8F5;
- // FIXME: add support for options other than a full system DMB
- let Inst{3-0} = 0b1111;
-}
-
-def t2DSBsy : AInoP<(outs), (ins), ThumbFrm, NoItinerary, "dsb", "",
- [(ARMSyncBarrier)]>, Requires<[IsThumb, HasDB]> {
- let Inst{31-4} = 0xF3BF8F4;
- // FIXME: add support for options other than a full system DSB
- let Inst{3-0} = 0b1111;
+def t2DMB : AInoP<(outs), (ins memb_opt:$opt), ThumbFrm, NoItinerary,
+ "dmb", "\t$opt", [(ARMMemBarrier (i32 imm:$opt))]>,
+ Requires<[IsThumb, HasDB]> {
+ bits<4> opt;
+ let Inst{31-4} = 0xf3bf8f5;
+ let Inst{3-0} = opt;
}
}
-// Helper class for multiclass T2MemB -- for disassembly only
-class T2I_memb<string opc, string asm>
- : T2I<(outs), (ins), NoItinerary, opc, asm,
- [/* For disassembly only; pattern left blank */]>,
- Requires<[IsThumb2, HasV7]> {
- let Inst{31-20} = 0xf3b;
- let Inst{15-14} = 0b10;
- let Inst{12} = 0;
-}
-
-multiclass T2MemB<bits<4> op7_4, string opc> {
-
- def st : T2I_memb<opc, "\tst"> {
- let Inst{7-4} = op7_4;
- let Inst{3-0} = 0b1110;
- }
-
- def ish : T2I_memb<opc, "\tish"> {
- let Inst{7-4} = op7_4;
- let Inst{3-0} = 0b1011;
- }
-
- def ishst : T2I_memb<opc, "\tishst"> {
- let Inst{7-4} = op7_4;
- let Inst{3-0} = 0b1010;
- }
-
- def nsh : T2I_memb<opc, "\tnsh"> {
- let Inst{7-4} = op7_4;
- let Inst{3-0} = 0b0111;
- }
-
- def nshst : T2I_memb<opc, "\tnshst"> {
- let Inst{7-4} = op7_4;
- let Inst{3-0} = 0b0110;
- }
-
- def osh : T2I_memb<opc, "\tosh"> {
- let Inst{7-4} = op7_4;
- let Inst{3-0} = 0b0011;
- }
-
- def oshst : T2I_memb<opc, "\toshst"> {
- let Inst{7-4} = op7_4;
- let Inst{3-0} = 0b0010;
- }
+def t2DSB : AInoP<(outs), (ins memb_opt:$opt), ThumbFrm, NoItinerary,
+ "dsb", "\t$opt",
+ [/* For disassembly only; pattern left blank */]>,
+ Requires<[IsThumb, HasDB]> {
+ bits<4> opt;
+ let Inst{31-4} = 0xf3bf8f4;
+ let Inst{3-0} = opt;
}
-// These DMB variants are for disassembly only.
-defm t2DMB : T2MemB<0b0101, "dmb">;
-
-// These DSB variants are for disassembly only.
-defm t2DSB : T2MemB<0b0100, "dsb">;
-
// ISB has only full system option -- for disassembly only
-def t2ISBsy : T2I_memb<"isb", ""> {
- let Inst{7-4} = 0b0110;
+def t2ISB : T2I<(outs), (ins), NoItinerary, "isb", "",
+ [/* For disassembly only; pattern left blank */]>,
+ Requires<[IsThumb2, HasV7]> {
+ let Inst{31-4} = 0xf3bf8f6;
let Inst{3-0} = 0b1111;
}
; RUN: llc < %s -mtriple=thumbv6-apple-darwin | FileCheck %s -check-prefix=V6
; RUN: llc < %s -march=thumb -mattr=+v6m | FileCheck %s -check-prefix=V6M
-declare void @llvm.memory.barrier( i1 , i1 , i1 , i1 , i1 )
+declare void @llvm.memory.barrier(i1 , i1 , i1 , i1 , i1)
define void @t1() {
; V6: t1:
; V6: blx {{_*}}sync_synchronize
; V6M: t1:
-; V6M: dsb
- call void @llvm.memory.barrier( i1 false, i1 false, i1 false, i1 true, i1 true )
+; V6M: dmb st
+ call void @llvm.memory.barrier(i1 false, i1 false, i1 false, i1 true, i1 true)
ret void
}
; V6: blx {{_*}}sync_synchronize
; V6M: t2:
-; V6M: dmb
- call void @llvm.memory.barrier( i1 false, i1 false, i1 false, i1 true, i1 false )
+; V6M: dmb ish
+ call void @llvm.memory.barrier(i1 true, i1 false, i1 false, i1 true, i1 false)
ret void
}
; RUN: llc < %s -march=thumb -mcpu=cortex-a8 | FileCheck %s
-declare void @llvm.memory.barrier( i1 , i1 , i1 , i1 , i1 )
+declare void @llvm.memory.barrier(i1 , i1 , i1 , i1 , i1)
-define void @t1() {
-; CHECK: t1:
-; CHECK: dsb
- call void @llvm.memory.barrier( i1 false, i1 false, i1 false, i1 true, i1 true )
+define void @t_st() {
+; CHECK: t_st:
+; CHECK: dmb st
+ call void @llvm.memory.barrier(i1 false, i1 false, i1 false, i1 true, i1 true)
ret void
}
-define void @t2() {
-; CHECK: t2:
-; CHECK: dmb
- call void @llvm.memory.barrier( i1 false, i1 false, i1 false, i1 true, i1 false )
+define void @t_sy() {
+; CHECK: t_sy:
+; CHECK: dmb sy
+ call void @llvm.memory.barrier(i1 true, i1 false, i1 false, i1 true, i1 true)
+ ret void
+}
+
+define void @t_ishst() {
+; CHECK: t_ishst:
+; CHECK: dmb ishst
+ call void @llvm.memory.barrier(i1 false, i1 false, i1 false, i1 true, i1 false)
+ ret void
+}
+
+define void @t_ish() {
+; CHECK: t_ish:
+; CHECK: dmb ish
+ call void @llvm.memory.barrier(i1 true, i1 false, i1 false, i1 true, i1 false)
ret void
}