Index: include/llvm/IR/IntrinsicsX86.td =================================================================== --- include/llvm/IR/IntrinsicsX86.td +++ include/llvm/IR/IntrinsicsX86.td @@ -4237,6 +4237,10 @@ Intrinsic<[], [llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty], []>; def int_x86_xsaves64 : Intrinsic<[], [llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty], []>; + def int_x86_xgetbv : + Intrinsic<[llvm_i64_ty], [llvm_i32_ty], []>; + def int_x86_xsetbv : + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], []>; } //===----------------------------------------------------------------------===// Index: lib/Target/X86/X86ISelLowering.h =================================================================== --- lib/Target/X86/X86ISelLowering.h +++ lib/Target/X86/X86ISelLowering.h @@ -539,6 +539,8 @@ // ERI instructions. RSQRT28, RCP28, EXP2, + XGETBV_DAG, + // Compare and swap. LCMPXCHG_DAG = ISD::FIRST_TARGET_MEMORY_OPCODE, LCMPXCHG8_DAG, Index: lib/Target/X86/X86ISelLowering.cpp =================================================================== --- lib/Target/X86/X86ISelLowering.cpp +++ lib/Target/X86/X86ISelLowering.cpp @@ -18123,6 +18123,51 @@ return SDValue(Res, 0); } +/// Handles the lowering of builtin intrinsic that return the value +/// of the extended control register. +static void getExtendedControlRegister(SDNode *N, const SDLoc &DL, + SelectionDAG &DAG, + const X86Subtarget &Subtarget, + SmallVectorImpl &Results) { + assert(N->getNumOperands() == 3 && "Unexpected number of operands!"); + SDVTList Tys = DAG.getVTList(MVT::Other, MVT::Glue); + SDValue LO, HI; + + // The ECX register is used to select the index of the XCR register to + // return. + SDValue Chain = DAG.getCopyToReg(N->getOperand(0), DL, X86::ECX, + N->getOperand(2)); + SDValue rd = DAG.getNode(X86ISD::XGETBV_DAG, DL, Tys, Chain); + + // Reads the content of XCR and returns it in registers EDX:EAX. + if (Subtarget.is64Bit()) { + LO = DAG.getCopyFromReg(rd, DL, X86::RAX, MVT::i64, rd.getValue(1)); + HI = DAG.getCopyFromReg(LO.getValue(1), DL, X86::RDX, MVT::i64, + LO.getValue(2)); + } + else { + LO = DAG.getCopyFromReg(rd, DL, X86::EAX, MVT::i32, rd.getValue(1)); + HI = DAG.getCopyFromReg(LO.getValue(1), DL, X86::EDX, MVT::i32, + LO.getValue(2)); + } + Chain = HI.getValue(1); + + if (Subtarget.is64Bit()) { + // Merge the two 32-bit values into a 64-bit one.. + SDValue Tmp = DAG.getNode(ISD::SHL, DL, MVT::i64, HI, + DAG.getConstant(32, DL, MVT::i8)); + Results.push_back(DAG.getNode(ISD::OR, DL, MVT::i64, LO, Tmp)); + Results.push_back(Chain); + return; + } + + // Use a buildpair to merge the two 32-bit values into a 64-bit one. + SDValue Ops[] = { LO, HI }; + SDValue Pair = DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i64, Ops); + Results.push_back(Pair); + Results.push_back(Chain); +} + /// Handles the lowering of builtin intrinsics that read performance monitor /// counters (x86_rdpmc). static void getReadPerformanceCounter(SDNode *N, const SDLoc &DL, @@ -18365,6 +18410,11 @@ getReadPerformanceCounter(Op.getNode(), dl, DAG, Subtarget, Results); return DAG.getMergeValues(Results, dl); } + case XGETBV: { + SmallVector Results; + getExtendedControlRegister(Op.getNode(), dl, DAG, Subtarget, Results); + return DAG.getMergeValues(Results, dl); + } // XTEST intrinsics. case XTEST: { SDVTList VTs = DAG.getVTList(Op->getValueType(0), MVT::Other); @@ -21837,6 +21887,9 @@ Results); case Intrinsic::x86_rdpmc: return getReadPerformanceCounter(N, dl, DAG, Subtarget, Results); + + case Intrinsic::x86_xgetbv: + return getExtendedControlRegister(N, dl, DAG, Subtarget, Results); } } case ISD::INTRINSIC_WO_CHAIN: { @@ -22003,6 +22056,7 @@ case X86ISD::RDTSC_DAG: return "X86ISD::RDTSC_DAG"; case X86ISD::RDTSCP_DAG: return "X86ISD::RDTSCP_DAG"; case X86ISD::RDPMC_DAG: return "X86ISD::RDPMC_DAG"; + case X86ISD::XGETBV_DAG: return "X86ISD::XGETBV_DAG"; case X86ISD::BT: return "X86ISD::BT"; case X86ISD::CMP: return "X86ISD::CMP"; case X86ISD::COMI: return "X86ISD::COMI"; Index: lib/Target/X86/X86InstrInfo.td =================================================================== --- lib/Target/X86/X86InstrInfo.td +++ lib/Target/X86/X86InstrInfo.td @@ -283,6 +283,9 @@ def X86TLSCall : SDNode<"X86ISD::TLSCALL", SDT_X86TLSCALL, [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>; +def X86xgetbv : SDNode<"X86ISD::XGETBV_DAG", SDTX86Void, + [SDNPHasChain, SDNPOutGlue, SDNPSideEffect]>; + //===----------------------------------------------------------------------===// // X86 Operand Definitions. // Index: lib/Target/X86/X86InstrSystem.td =================================================================== --- lib/Target/X86/X86InstrSystem.td +++ lib/Target/X86/X86InstrSystem.td @@ -478,11 +478,14 @@ let SchedRW = [WriteSystem] in { let Predicates = [HasXSAVE] in { let Defs = [EDX, EAX], Uses = [ECX] in - def XGETBV : I<0x01, MRM_D0, (outs), (ins), "xgetbv", []>, TB; + def XGETBV : I<0x01, MRM_D0, (outs), (ins), "xgetbv", [(X86xgetbv)]>, TB; let Uses = [EDX, EAX, ECX] in - def XSETBV : I<0x01, MRM_D1, (outs), (ins), "xsetbv", []>, TB; -} + def XSETBV : I<0x01, MRM_D1, (outs), (ins), + "xsetbv", + [(int_x86_xsetbv ECX, EDX, EAX)]>, TB; + +} // HasXSAVE let Uses = [EDX, EAX] in { let Predicates = [HasXSAVE] in { Index: lib/Target/X86/X86IntrinsicsInfo.h =================================================================== --- lib/Target/X86/X86IntrinsicsInfo.h +++ lib/Target/X86/X86IntrinsicsInfo.h @@ -21,7 +21,7 @@ enum IntrinsicType : uint16_t { INTR_NO_TYPE, - GATHER, SCATTER, PREFETCH, RDSEED, RDRAND, RDPMC, RDTSC, XTEST, ADX, FPCLASS, FPCLASSS, + GATHER, SCATTER, PREFETCH, RDSEED, RDRAND, RDPMC, RDTSC, XGETBV, XTEST, ADX, FPCLASS, FPCLASSS, INTR_TYPE_1OP, INTR_TYPE_2OP, INTR_TYPE_2OP_IMM8, INTR_TYPE_3OP, INTR_TYPE_4OP, CMP_MASK, CMP_MASK_CC,CMP_MASK_SCALAR_CC, VSHIFT, VSHIFT_MASK, COMI, COMI_RM, INTR_TYPE_1OP_MASK, INTR_TYPE_1OP_MASK_RM, @@ -231,6 +231,7 @@ X86_INTRINSIC_DATA(subborrow_u32, ADX, X86ISD::SBB, 0), X86_INTRINSIC_DATA(subborrow_u64, ADX, X86ISD::SBB, 0), + X86_INTRINSIC_DATA(xgetbv, XGETBV, X86ISD::XGETBV_DAG, 0), X86_INTRINSIC_DATA(xtest, XTEST, X86ISD::XTEST, 0), }; Index: test/CodeGen/X86/system-intrinsics-xgetbv.ll =================================================================== --- test/CodeGen/X86/system-intrinsics-xgetbv.ll +++ test/CodeGen/X86/system-intrinsics-xgetbv.ll @@ -0,0 +1,21 @@ +; RUN: llc < %s -mtriple=i686-unknown-unknown -mattr=+xsave | FileCheck %s +; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+xsave | FileCheck %s --check-prefix=CHECK64 + +define i64 @test_xgetbv(i32 %in) { +; CHECK-LABEL: test_xgetbv +; CHECK: movl 4(%esp), %ecx +; CHECK: xgetbv +; CHECK: ret + +; CHECK64-LABEL: test_xgetbv64 +; CHECK64: movl %edi, %ecx +; CHECK64: xgetbv +; CHECK64: shlq $32, %rdx +; CHECK64: orq %rdx, %rax +; CHECK64: ret + + %1 = call i64 @llvm.x86.xgetbv(i32 %in) + ret i64 %1; +} + +declare i64 @llvm.x86.xgetbv(i32) \ No newline at end of file Index: test/CodeGen/X86/system-intrinsics-xsetbv.ll =================================================================== --- test/CodeGen/X86/system-intrinsics-xsetbv.ll +++ test/CodeGen/X86/system-intrinsics-xsetbv.ll @@ -0,0 +1,23 @@ +; RUN: llc < %s -mtriple=i686-unknown-unknown -mattr=+xsave | FileCheck %s +; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+xsave | FileCheck %s --check-prefix=CHECK64 + +define void @test_xsetbv(i32 %in, i32 %high, i32 %low) { +; CHECK-LABEL: test_xsetbv +; CHECK: movl 4(%esp), %ecx +; CHECK: movl 8(%esp), %edx +; CHECK: movl 12(%esp), %eax +; CHECK: xsetbv +; CHECK: ret + +; CHECK64-LABEL: test_xsetbv +; CHECK64: movl %edx, %eax +; CHECK64: movl %edi, %ecx +; CHECK64: movl %esi, %edx +; CHECK64: xsetbv +; CHECK64: ret + + call void @llvm.x86.xsetbv(i32 %in, i32 %high, i32 %low) + ret void; +} +declare void @llvm.x86.xsetbv(i32, i32, i32) +