1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-23 03:02:36 +01:00

[X86] Add xgetbv/xsetbv intrinsics to non-windows platforms

Differential Revision: https://reviews.llvm.org/D21958

llvm-svn: 278782
This commit is contained in:
Guy Blank 2016-08-16 06:41:00 +00:00
parent 4ca4b42bf0
commit 6b866e2b9c
6 changed files with 109 additions and 3 deletions

View File

@ -4130,6 +4130,10 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.".
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], []>;
}
//===----------------------------------------------------------------------===//

View File

@ -18480,6 +18480,51 @@ static SDValue getPrefetchNode(unsigned Opc, SDValue Op, SelectionDAG &DAG,
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<SDValue> &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));
SDNode *N1 = DAG.getMachineNode(X86::XGETBV, DL, Tys, Chain);
Chain = SDValue(N1, 0);
// Reads the content of XCR and returns it in registers EDX:EAX.
if (Subtarget.is64Bit()) {
LO = DAG.getCopyFromReg(Chain, DL, X86::RAX, MVT::i64, SDValue(N1, 1));
HI = DAG.getCopyFromReg(LO.getValue(1), DL, X86::RDX, MVT::i64,
LO.getValue(2));
} else {
LO = DAG.getCopyFromReg(Chain, DL, X86::EAX, MVT::i32, SDValue(N1, 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,
@ -18722,6 +18767,12 @@ static SDValue LowerINTRINSIC_W_CHAIN(SDValue Op, const X86Subtarget &Subtarget,
getReadPerformanceCounter(Op.getNode(), dl, DAG, Subtarget, Results);
return DAG.getMergeValues(Results, dl);
}
// Get Extended Control Register.
case XGETBV: {
SmallVector<SDValue, 2> 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);
@ -22176,6 +22227,9 @@ void X86TargetLowering::ReplaceNodeResults(SDNode *N,
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: {

View File

@ -481,8 +481,11 @@ let Defs = [EDX, EAX], Uses = [ECX] in
def XGETBV : I<0x01, MRM_D0, (outs), (ins), "xgetbv", []>, 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 {

View File

@ -21,7 +21,7 @@ namespace llvm {
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, XTEST, XGETBV, 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, COMI, COMI_RM,
INTR_TYPE_1OP_MASK, INTR_TYPE_1OP_MASK_RM,
@ -228,6 +228,7 @@ static const IntrinsicData IntrinsicsWithChain[] = {
X86_INTRINSIC_DATA(subborrow_u32, ADX, X86ISD::SBB, 0),
X86_INTRINSIC_DATA(subborrow_u64, ADX, X86ISD::SBB, 0),
X86_INTRINSIC_DATA(xgetbv, XGETBV, X86::XGETBV, 0),
X86_INTRINSIC_DATA(xtest, XTEST, X86ISD::XTEST, 0),
};

View File

@ -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_xgetbv
; 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)

View File

@ -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)