Index: include/llvm/IR/IntrinsicsX86.td =================================================================== --- include/llvm/IR/IntrinsicsX86.td +++ include/llvm/IR/IntrinsicsX86.td @@ -8709,3 +8709,14 @@ def int_x86_sha256msg2 : GCCBuiltin<"__builtin_ia32_sha256msg2">, Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_v4i32_ty], [IntrNoMem]>; } + +//===----------------------------------------------------------------------===// +// Thread synchronization ops with timer. +let TargetPrefix = "x86" in { + def int_x86_monitorx + : GCCBuiltin<"__builtin_ia32_monitorx">, + Intrinsic<[], [ llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty ], []>; + def int_x86_mwaitx + : GCCBuiltin<"__builtin_ia32_mwaitx">, + Intrinsic<[], [ llvm_i32_ty, llvm_i32_ty, llvm_i32_ty ], []>; +} Index: lib/Support/Host.cpp =================================================================== --- lib/Support/Host.cpp +++ lib/Support/Host.cpp @@ -252,6 +252,7 @@ GetX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX); bool Em64T = (EDX >> 29) & 0x1; bool HasTBM = (ECX >> 21) & 0x1; + bool HasMWAITX = (ECX >> 29) & 0x1; if (memcmp(text.c, "GenuineIntel", 12) == 0) { switch (Family) { @@ -802,6 +803,7 @@ Features["xop"] = HasExtLeaf1 && ((ECX >> 11) & 1) && HasAVXSave; Features["fma4"] = HasExtLeaf1 && ((ECX >> 16) & 1) && HasAVXSave; Features["tbm"] = HasExtLeaf1 && ((ECX >> 21) & 1); + Features["mwaitx"] = HasExtLeaf1 && ((ECX >> 29) & 1); bool HasLeaf7 = MaxLevel >= 7 && !GetX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX); Index: lib/Target/X86/X86.td =================================================================== --- lib/Target/X86/X86.td +++ lib/Target/X86/X86.td @@ -198,6 +198,8 @@ "Support RDSEED instruction">; def FeatureLAHFSAHF : SubtargetFeature<"sahf", "HasLAHFSAHF", "true", "Support LAHF and SAHF instructions">; +def FeatureMWAITX : SubtargetFeature<"mwaitx", "HasMWAITX", "true", + "Enable MONITORX/MWAITX timer functionality">; def FeatureMPX : SubtargetFeature<"mpx", "HasMPX", "true", "Support MPX instructions">; def FeatureLEAForSP : SubtargetFeature<"lea-sp", "UseLeaForSP", "true", @@ -728,7 +730,8 @@ FeatureFMA, FeatureXSAVEOPT, FeatureFSGSBase, - FeatureLAHFSAHF + FeatureLAHFSAHF, + FeatureMWAITX ]>; def : Proc<"geode", [FeatureX87, FeatureSlowUAMem16, Feature3DNowA]>; Index: lib/Target/X86/X86ISelLowering.cpp =================================================================== --- lib/Target/X86/X86ISelLowering.cpp +++ lib/Target/X86/X86ISelLowering.cpp @@ -22221,7 +22221,8 @@ } static MachineBasicBlock *emitMonitor(MachineInstr *MI, MachineBasicBlock *BB, - const X86Subtarget &Subtarget) { + const X86Subtarget &Subtarget, + unsigned Opc) { DebugLoc dl = MI->getDebugLoc(); const TargetInstrInfo *TII = Subtarget.getInstrInfo(); // Address into RAX/EAX, other two args into ECX, EDX. @@ -22238,7 +22239,7 @@ .addReg(MI->getOperand(ValOps+1).getReg()); // The instruction doesn't actually take any operands though. - BuildMI(*BB, MI, dl, TII->get(X86::MONITORrrr)); + BuildMI(*BB, MI, dl, TII->get(Opc)); MI->eraseFromParent(); // The pseudo is gone now. return BB; @@ -23739,7 +23740,9 @@ // Thread synchronization. case X86::MONITOR: - return emitMonitor(MI, BB, Subtarget); + return emitMonitor(MI, BB, Subtarget, X86::MONITORrrr); + case X86::MONITORX: + return emitMonitor(MI, BB, Subtarget, X86::MONITORXrrr); // PKU feature case X86::WRPKRU: return emitWRPKRU(MI, BB, Subtarget); Index: lib/Target/X86/X86InstrInfo.td =================================================================== --- lib/Target/X86/X86InstrInfo.td +++ lib/Target/X86/X86InstrInfo.td @@ -847,6 +847,7 @@ def HasRDSEED : Predicate<"Subtarget->hasRDSEED()">; def HasPrefetchW : Predicate<"Subtarget->hasPRFCHW()">; def HasLAHFSAHF : Predicate<"Subtarget->hasLAHFSAHF()">; +def HasMWAITX : Predicate<"Subtarget->hasMWAITX()">; def FPStackf32 : Predicate<"!Subtarget->hasSSE1()">; def FPStackf64 : Predicate<"!Subtarget->hasSSE2()">; def HasMPX : Predicate<"Subtarget->hasMPX()">; @@ -2401,22 +2402,34 @@ //===----------------------------------------------------------------------===// // MONITORX/MWAITX Instructions // -let SchedRW = [WriteSystem] in { -let Uses = [EAX, ECX, EDX] in -def MONITORXrrr : I<0x01, MRM_FA, (outs), (ins), "monitorx", [], - IIC_SSE_MONITOR>, TB; -let Uses = [ECX, EAX, EBX] in -def MWAITXrr : I<0x01, MRM_FB, (outs), (ins), "mwaitx", [], IIC_SSE_MWAIT>, - TB; +let SchedRW = [ WriteSystem ] in { + let usesCustomInserter = 1 in { + def MONITORX : PseudoI<(outs), (ins i32mem:$src1, GR32:$src2, GR32:$src3), + [(int_x86_monitorx addr:$src1, GR32:$src2, GR32:$src3)]>, + Requires<[ HasMWAITX ]>; + } + + let Uses = [ EAX, ECX, EDX ] in { + def MONITORXrrr : I<0x01, MRM_FA, (outs), (ins), "monitorx", [], IIC_SSE_MONITORX>, + TB, Requires<[ HasMWAITX ]>; + } + + let Uses = [ ECX, EAX, EBX ] in { + def MWAITXrrr : I<0x01, MRM_FB, (outs), (ins), "mwaitx", + [(int_x86_mwaitx ECX, EAX, EBX)], IIC_SSE_MWAITX>, + TB, Requires<[ HasMWAITX ]>; + } } // SchedRW -def : InstAlias<"mwaitx\t{%eax, %ecx, %ebx|ebx, ecx, eax}", (MWAITXrr)>, Requires<[Not64BitMode]>; -def : InstAlias<"mwaitx\t{%rax, %rcx, %rbx|rbx, rcx, rax}", (MWAITXrr)>, Requires<[In64BitMode]>; +def : InstAlias<"mwaitx\t{%eax, %ecx, %ebx|ebx, ecx, eax}", (MWAITXrrr)>, + Requires<[ Not64BitMode ]>; +def : InstAlias<"mwaitx\t{%rax, %rcx, %rbx|rbx, rcx, rax}", (MWAITXrrr)>, + Requires<[ In64BitMode ]>; def : InstAlias<"monitorx\t{%eax, %ecx, %edx|edx, ecx, eax}", (MONITORXrrr)>, - Requires<[Not64BitMode]>; + Requires<[ Not64BitMode ]>; def : InstAlias<"monitorx\t{%rax, %rcx, %rdx|rdx, rcx, rax}", (MONITORXrrr)>, - Requires<[In64BitMode]>; + Requires<[ In64BitMode ]>; //===----------------------------------------------------------------------===// // CLZERO Instruction Index: lib/Target/X86/X86InstrSSE.td =================================================================== --- lib/Target/X86/X86InstrSSE.td +++ lib/Target/X86/X86InstrSSE.td @@ -5849,6 +5849,7 @@ let Uses = [EAX, ECX, EDX] in def MONITORrrr : I<0x01, MRM_C8, (outs), (ins), "monitor", [], IIC_SSE_MONITOR>, TB, Requires<[HasSSE3]>; + let Uses = [ECX, EAX] in def MWAITrr : I<0x01, MRM_C9, (outs), (ins), "mwait", [(int_x86_sse3_mwait ECX, EAX)], IIC_SSE_MWAIT>, Index: lib/Target/X86/X86Schedule.td =================================================================== --- lib/Target/X86/X86Schedule.td +++ lib/Target/X86/X86Schedule.td @@ -364,6 +364,8 @@ def IIC_SSE_PALIGNRM : InstrItinClass; def IIC_SSE_MWAIT : InstrItinClass; def IIC_SSE_MONITOR : InstrItinClass; +def IIC_SSE_MWAITX : InstrItinClass; +def IIC_SSE_MONITORX : InstrItinClass; def IIC_SSE_PREFETCH : InstrItinClass; def IIC_SSE_PAUSE : InstrItinClass; Index: lib/Target/X86/X86Subtarget.h =================================================================== --- lib/Target/X86/X86Subtarget.h +++ lib/Target/X86/X86Subtarget.h @@ -164,6 +164,9 @@ /// Processor has LAHF/SAHF instructions. bool HasLAHFSAHF; + /// Processor has MONITORX/MWAITX instructions. + bool HasMWAITX; + /// Processor has Prefetch with intent to Write instruction bool HasPFPREFETCHWT1; @@ -421,6 +424,7 @@ bool hasPRFCHW() const { return HasPRFCHW; } bool hasRDSEED() const { return HasRDSEED; } bool hasLAHFSAHF() const { return HasLAHFSAHF; } + bool hasMWAITX() const { return HasMWAITX; } bool isBTMemSlow() const { return IsBTMemSlow; } bool isSHLDSlow() const { return IsSHLDSlow; } bool isUnalignedMem16Slow() const { return IsUAMem16Slow; } Index: lib/Target/X86/X86Subtarget.cpp =================================================================== --- lib/Target/X86/X86Subtarget.cpp +++ lib/Target/X86/X86Subtarget.cpp @@ -314,6 +314,7 @@ HasPRFCHW = false; HasRDSEED = false; HasLAHFSAHF = false; + HasMWAITX = false; HasMPX = false; IsBTMemSlow = false; IsSHLDSlow = false; Index: test/CodeGen/X86/mwaitx.ll =================================================================== --- test/CodeGen/X86/mwaitx.ll +++ test/CodeGen/X86/mwaitx.ll @@ -0,0 +1,36 @@ +; RUN: llc < %s -mtriple=x86_64-linux -mattr=+mwaitx | FileCheck %s +; RUN: llc < %s -mtriple=x86_64-win32 -mattr=+mwaitx | FileCheck %s -check-prefix=WIN64 + +; CHECK-LABEL: foo: +; CHECK: leaq (%rdi), %rax +; CHECK-NEXT: movl %esi, %ecx +; CHECK-NEXT: monitorx +; WIN64-LABEL: foo: +; WIN64: leaq (%rcx), %rax +; WIN64-NEXT: movl %edx, %ecx +; WIN64-NEXT: movl %r8d, %edx +; WIN64-NEXT: monitorx +define void @foo(i8* %P, i32 %E, i32 %H) nounwind { +entry: + tail call void @llvm.x86.monitorx(i8* %P, i32 %E, i32 %H) + ret void +} + +declare void @llvm.x86.monitorx(i8*, i32, i32) nounwind + +; CHECK-LABEL: bar: +; CHECK: movl %edi, %ecx +; CHECK-NEXT: movl %esi, %eax +; CHECK-NEXT: movl %edx, %ebx +; CHECK-NEXT: mwaitx +; WIN64-LABEL: bar: +; WIN64: movl %edx, %eax +; WIN64: movl %r8d, %ebx +; WIN64-NEXT: mwaitx +define void @bar(i32 %E, i32 %H, i32 %C) nounwind { +entry: + tail call void @llvm.x86.mwaitx(i32 %E, i32 %H, i32 %C) + ret void +} + +declare void @llvm.x86.mwaitx(i32, i32, i32) nounwind Index: test/MC/Disassembler/X86/simple-tests.txt =================================================================== --- test/MC/Disassembler/X86/simple-tests.txt +++ test/MC/Disassembler/X86/simple-tests.txt @@ -51,6 +51,12 @@ # CHECK: rdtscp 0x0f 0x01 0xf9 +# CHECK: monitorx +0x0f 0x01 0xfa + +# CHECK: mwaitx +0x0f 0x01 0xfb + # CHECK: vmxon 0xf3 0x0f 0xc7 0x30 Index: test/MC/Disassembler/X86/x86-32.txt =================================================================== --- test/MC/Disassembler/X86/x86-32.txt +++ test/MC/Disassembler/X86/x86-32.txt @@ -90,6 +90,12 @@ # CHECK: rdtscp 0x0f 0x01 0xf9 +# CHECK: monitorx +0x0f 0x01 0xfa + +# CHECK: mwaitx +0x0f 0x01 0xfb + # CHECK: vmxon 0xf3 0x0f 0xc7 0x30