Index: include/llvm/IR/IntrinsicsARM.td =================================================================== --- include/llvm/IR/IntrinsicsARM.td +++ include/llvm/IR/IntrinsicsARM.td @@ -45,6 +45,11 @@ def int_arm_ldrexd : Intrinsic<[llvm_i32_ty, llvm_i32_ty], [llvm_ptr_ty]>; //===----------------------------------------------------------------------===// +// Data barrier instructions +def int_arm_dmb : Intrinsic<[], [llvm_i32_ty]>; +def int_arm_dsb : Intrinsic<[], [llvm_i32_ty]>; + +//===----------------------------------------------------------------------===// // VFP def int_arm_get_fpscr : GCCBuiltin<"__builtin_arm_get_fpscr">, Index: lib/Target/ARM/ARMISelLowering.h =================================================================== --- lib/Target/ARM/ARMISelLowering.h +++ lib/Target/ARM/ARMISelLowering.h @@ -94,7 +94,6 @@ DYN_ALLOC, // Dynamic allocation on the stack. - MEMBARRIER, // Memory barrier (DMB) MEMBARRIER_MCR, // Memory barrier (MCR) PRELOAD, // Preload Index: lib/Target/ARM/ARMISelLowering.cpp =================================================================== --- lib/Target/ARM/ARMISelLowering.cpp +++ lib/Target/ARM/ARMISelLowering.cpp @@ -1010,7 +1010,6 @@ case ARMISD::DYN_ALLOC: return "ARMISD::DYN_ALLOC"; - case ARMISD::MEMBARRIER: return "ARMISD::MEMBARRIER"; case ARMISD::MEMBARRIER_MCR: return "ARMISD::MEMBARRIER_MCR"; case ARMISD::PRELOAD: return "ARMISD::PRELOAD"; @@ -2610,7 +2609,8 @@ Domain = ARM_MB::ISHST; } - return DAG.getNode(ARMISD::MEMBARRIER, dl, MVT::Other, Op.getOperand(0), + return DAG.getNode(ISD::INTRINSIC_VOID, dl, MVT::Other, Op.getOperand(0), + DAG.getConstant(Intrinsic::arm_dmb, MVT::i32), DAG.getConstant(Domain, MVT::i32)); } Index: lib/Target/ARM/ARMInstrInfo.td =================================================================== --- lib/Target/ARM/ARMInstrInfo.td +++ lib/Target/ARM/ARMInstrInfo.td @@ -165,8 +165,6 @@ SDT_ARMEH_SJLJ_Longjmp, [SDNPHasChain, SDNPSideEffect]>; -def ARMMemBarrier : SDNode<"ARMISD::MEMBARRIER", SDT_ARMMEMBARRIER, - [SDNPHasChain, SDNPSideEffect]>; def ARMMemBarrierMCR : SDNode<"ARMISD::MEMBARRIER_MCR", SDT_ARMMEMBARRIER, [SDNPHasChain, SDNPSideEffect]>; def ARMPreload : SDNode<"ARMISD::PRELOAD", SDT_ARMPREFETCH, @@ -4255,7 +4253,7 @@ // memory barriers protect the atomic sequences let hasSideEffects = 1 in { def DMB : AInoP<(outs), (ins memb_opt:$opt), MiscFrm, NoItinerary, - "dmb", "\t$opt", [(ARMMemBarrier (i32 imm:$opt))]>, + "dmb", "\t$opt", [(int_arm_dmb (i32 imm0_15:$opt))]>, Requires<[IsARM, HasDB]> { bits<4> opt; let Inst{31-4} = 0xf57ff05; @@ -4264,7 +4262,7 @@ } def DSB : AInoP<(outs), (ins memb_opt:$opt), MiscFrm, NoItinerary, - "dsb", "\t$opt", []>, + "dsb", "\t$opt", [(int_arm_dsb (i32 imm0_15:$opt))]>, Requires<[IsARM, HasDB]> { bits<4> opt; let Inst{31-4} = 0xf57ff04; Index: lib/Target/ARM/ARMInstrThumb2.td =================================================================== --- lib/Target/ARM/ARMInstrThumb2.td +++ lib/Target/ARM/ARMInstrThumb2.td @@ -3155,7 +3155,7 @@ // memory barriers protect the atomic sequences let hasSideEffects = 1 in { def t2DMB : T2I<(outs), (ins memb_opt:$opt), NoItinerary, - "dmb", "\t$opt", [(ARMMemBarrier (i32 imm:$opt))]>, + "dmb", "\t$opt", [(int_arm_dmb (i32 imm:$opt))]>, Requires<[HasDB]> { bits<4> opt; let Inst{31-4} = 0xf3bf8f5; @@ -3164,7 +3164,8 @@ } def t2DSB : T2I<(outs), (ins memb_opt:$opt), NoItinerary, - "dsb", "\t$opt", []>, Requires<[HasDB]> { + "dsb", "\t$opt", [(int_arm_dsb (i32 imm:$opt)]>, + Requires<[HasDB]> { bits<4> opt; let Inst{31-4} = 0xf3bf8f4; let Inst{3-0} = opt; Index: lib/Target/ARM/AsmParser/ARMAsmParser.cpp =================================================================== --- lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -339,6 +339,7 @@ struct MBOptOp { ARM_MB::MemBOpt Val; + bool HasV8; }; struct ISBOptOp { @@ -2452,9 +2453,11 @@ return Op; } - static ARMOperand *CreateMemBarrierOpt(ARM_MB::MemBOpt Opt, SMLoc S) { + static ARMOperand *CreateMemBarrierOpt(ARM_MB::MemBOpt Opt, SMLoc S, + bool HasV8) { ARMOperand *Op = new ARMOperand(k_MemBarrierOpt); Op->MBOpt.Val = Opt; + Op->MBOpt.HasV8 = HasV8; Op->StartLoc = S; Op->EndLoc = S; return Op; @@ -2521,7 +2524,8 @@ getImm()->print(OS); break; case k_MemBarrierOpt: - OS << ""; + OS << ""; break; case k_InstSyncBarrierOpt: OS << ""; @@ -3466,18 +3470,27 @@ Opt = StringSwitch(OptStr.slice(0, OptStr.size()).lower()) .Case("sy", ARM_MB::SY) .Case("st", ARM_MB::ST) + .Case("ld", ARM_MB::LD) .Case("sh", ARM_MB::ISH) .Case("ish", ARM_MB::ISH) .Case("shst", ARM_MB::ISHST) .Case("ishst", ARM_MB::ISHST) + .Case("ishld", ARM_MB::ISHLD) .Case("nsh", ARM_MB::NSH) .Case("un", ARM_MB::NSH) .Case("nshst", ARM_MB::NSHST) + .Case("nshld", ARM_MB::NSHLD) .Case("unst", ARM_MB::NSHST) .Case("osh", ARM_MB::OSH) .Case("oshst", ARM_MB::OSHST) + .Case("oshld", ARM_MB::OSHLD) .Default(~0U); + // ishld, oshld, nshld and ld are only available from ARMv8. + if (!hasV8Ops() && (Opt == ARM_MB::ISHLD || Opt == ARM_MB::OSHLD || + Opt == ARM_MB::NSHLD || Opt == ARM_MB::LD)) + Opt = ~0U; + if (Opt == ~0U) return MatchOperand_NoMatch; @@ -3511,7 +3524,8 @@ } else return MatchOperand_ParseFail; - Operands.push_back(ARMOperand::CreateMemBarrierOpt((ARM_MB::MemBOpt)Opt, S)); + Operands.push_back( + ARMOperand::CreateMemBarrierOpt((ARM_MB::MemBOpt)Opt, S, hasV8Ops())); return MatchOperand_Success; } Index: lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp =================================================================== --- lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp +++ lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp @@ -677,7 +677,7 @@ void ARMInstPrinter::printMemBOption(const MCInst *MI, unsigned OpNum, raw_ostream &O) { unsigned val = MI->getOperand(OpNum).getImm(); - O << ARM_MB::MemBOptToString(val); + O << ARM_MB::MemBOptToString(val, (getAvailableFeatures() & ARM::HasV8Ops)); } void ARMInstPrinter::printInstSyncBOption(const MCInst *MI, unsigned OpNum, Index: lib/Target/ARM/MCTargetDesc/ARMBaseInfo.h =================================================================== --- lib/Target/ARM/MCTargetDesc/ARMBaseInfo.h +++ lib/Target/ARM/MCTargetDesc/ARMBaseInfo.h @@ -121,41 +121,41 @@ // the option field for memory barrier operations. enum MemBOpt { RESERVED_0 = 0, - RESERVED_1 = 1, + OSHLD = 1, OSHST = 2, OSH = 3, RESERVED_4 = 4, - RESERVED_5 = 5, + NSHLD = 5, NSHST = 6, NSH = 7, RESERVED_8 = 8, - RESERVED_9 = 9, + ISHLD = 9, ISHST = 10, ISH = 11, RESERVED_12 = 12, - RESERVED_13 = 13, + LD = 13, ST = 14, SY = 15 }; - inline static const char *MemBOptToString(unsigned val) { + inline static const char *MemBOptToString(unsigned val, bool HasV8) { switch (val) { default: llvm_unreachable("Unknown memory operation"); case SY: return "sy"; case ST: return "st"; - case RESERVED_13: return "#0xd"; + case LD: return HasV8 ? "ld" : "#0xd"; case RESERVED_12: return "#0xc"; case ISH: return "ish"; case ISHST: return "ishst"; - case RESERVED_9: return "#0x9"; + case ISHLD: return HasV8 ? "ishld" : "#0x9"; case RESERVED_8: return "#0x8"; case NSH: return "nsh"; case NSHST: return "nshst"; - case RESERVED_5: return "#0x5"; + case NSHLD: return HasV8 ? "nshld" : "#0x5"; case RESERVED_4: return "#0x4"; case OSH: return "osh"; case OSHST: return "oshst"; - case RESERVED_1: return "#0x1"; + case OSHLD: return HasV8 ? "oshld" : "#0x1"; case RESERVED_0: return "#0x0"; } } Index: test/CodeGen/ARM/intrinsics-v8.ll =================================================================== --- /dev/null +++ test/CodeGen/ARM/intrinsics-v8.ll @@ -0,0 +1,16 @@ +; RUN: llc < %s -mtriple=armv8 -mattr=+db | FileCheck %s + +define void @test() { + ; CHECK: dmb sy + call void @llvm.arm.dmb(i32 15) + ; CHECK: dmb osh + call void @llvm.arm.dmb(i32 3) + ; CHECK: dsb sy + call void @llvm.arm.dsb(i32 15) + ; CHECK: dsb ishld + call void @llvm.arm.dsb(i32 9) + ret void +} + +declare void @llvm.arm.dmb(i32) +declare void @llvm.arm.dsb(i32) Index: test/MC/ARM/basic-arm-instructions-v8.s =================================================================== --- /dev/null +++ test/MC/ARM/basic-arm-instructions-v8.s @@ -0,0 +1,38 @@ +@ RUN: not llvm-mc -triple=armv8 -mattr=+db -show-encoding < %s | FileCheck %s +@ RUN: not llvm-mc -triple=armv7 -mattr=+db -show-encoding < %s 2>&1 | FileCheck %s --check-prefix=CHECK-V7 + +@------------------------------------------------------------------------------ +@ DMB (v8 barriers) +@------------------------------------------------------------------------------ + dmb ishld + dmb oshld + dmb nshld + dmb ld + dmb #20 + +@ CHECK: dmb ishld @ encoding: [0x59,0xf0,0x7f,0xf5] +@ CHECK: dmb oshld @ encoding: [0x51,0xf0,0x7f,0xf5] +@ CHECK: dmb nshld @ encoding: [0x55,0xf0,0x7f,0xf5] +@ CHECK: dmb ld @ encoding: [0x5d,0xf0,0x7f,0xf5] +@ CHECK-V7: error: invalid operand for instruction +@ CHECK-V7: error: invalid operand for instruction +@ CHECK-V7: error: invalid operand for instruction +@ CHECK-V7: error: invalid operand for instruction +@ CHECK-V7: error: immediate value out of range + +@------------------------------------------------------------------------------ +@ DSB (v8 barriers) +@------------------------------------------------------------------------------ + dsb ishld + dsb oshld + dsb nshld + dsb ld + +@ CHECK: dsb ishld @ encoding: [0x49,0xf0,0x7f,0xf5] +@ CHECK: dsb oshld @ encoding: [0x41,0xf0,0x7f,0xf5] +@ CHECK: dsb nshld @ encoding: [0x45,0xf0,0x7f,0xf5] +@ CHECK: dsb ld @ encoding: [0x4d,0xf0,0x7f,0xf5] +@ CHECK-V7: error: invalid operand for instruction +@ CHECK-V7: error: invalid operand for instruction +@ CHECK-V7: error: invalid operand for instruction +@ CHECK-V7: error: invalid operand for instruction