mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-14 11:32:34 +00:00
Add intrinsics for Ivy Bridge's rdrand instruction.
The rdrand/cmov sequence is the same that is emitted by both GCC and ICC. Fixes PR13284. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@160117 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
4e8982a34d
commit
b9bee04995
@ -2536,3 +2536,14 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.".
|
|||||||
Intrinsic<[llvm_v8i16_ty], [llvm_v8f32_ty, llvm_i32_ty],
|
Intrinsic<[llvm_v8i16_ty], [llvm_v8f32_ty, llvm_i32_ty],
|
||||||
[IntrNoMem]>;
|
[IntrNoMem]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// RDRAND intrinsics. Return a random value and whether it is valid.
|
||||||
|
|
||||||
|
let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.".
|
||||||
|
// These are declared side-effecting so they don't get eliminated by CSE or
|
||||||
|
// LICM.
|
||||||
|
def int_x86_rdrand_16 : Intrinsic<[llvm_i16_ty, llvm_i32_ty], [], []>;
|
||||||
|
def int_x86_rdrand_32 : Intrinsic<[llvm_i32_ty, llvm_i32_ty], [], []>;
|
||||||
|
def int_x86_rdrand_64 : Intrinsic<[llvm_i64_ty, llvm_i32_ty], [], []>;
|
||||||
|
}
|
||||||
|
@ -1176,6 +1176,7 @@ X86TargetLowering::X86TargetLowering(X86TargetMachine &TM)
|
|||||||
|
|
||||||
// We want to custom lower some of our intrinsics.
|
// We want to custom lower some of our intrinsics.
|
||||||
setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom);
|
setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom);
|
||||||
|
setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::Other, Custom);
|
||||||
|
|
||||||
|
|
||||||
// Only custom-lower 64-bit SADDO and friends on 64-bit because we don't
|
// Only custom-lower 64-bit SADDO and friends on 64-bit because we don't
|
||||||
@ -9810,6 +9811,38 @@ X86TargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SDValue
|
||||||
|
X86TargetLowering::LowerINTRINSIC_W_CHAIN(SDValue Op, SelectionDAG &DAG) const {
|
||||||
|
DebugLoc dl = Op.getDebugLoc();
|
||||||
|
unsigned IntNo = cast<ConstantSDNode>(Op.getOperand(1))->getZExtValue();
|
||||||
|
switch (IntNo) {
|
||||||
|
default: return SDValue(); // Don't custom lower most intrinsics.
|
||||||
|
|
||||||
|
// RDRAND intrinsics.
|
||||||
|
case Intrinsic::x86_rdrand_16:
|
||||||
|
case Intrinsic::x86_rdrand_32:
|
||||||
|
case Intrinsic::x86_rdrand_64: {
|
||||||
|
// Emit the node with the right value type.
|
||||||
|
SDValue Result = DAG.getNode(X86ISD::RDRAND, dl,
|
||||||
|
DAG.getVTList(Op->getValueType(0), MVT::Glue));
|
||||||
|
|
||||||
|
// If the value returned by RDRAND was valid (CF=1), return 1. Otherwise
|
||||||
|
// return the value from Rand, which is always 0, casted to i32.
|
||||||
|
SDValue Ops[] = { DAG.getZExtOrTrunc(Result, dl, Op->getValueType(1)),
|
||||||
|
DAG.getConstant(1, Op->getValueType(1)),
|
||||||
|
DAG.getConstant(X86::COND_B, MVT::i32),
|
||||||
|
SDValue(Result.getNode(), 1) };
|
||||||
|
SDValue isValid = DAG.getNode(X86ISD::CMOV, dl,
|
||||||
|
DAG.getVTList(Op->getValueType(1), MVT::Glue),
|
||||||
|
Ops, 4);
|
||||||
|
|
||||||
|
// Return { result, isValid, chain }.
|
||||||
|
return DAG.getNode(ISD::MERGE_VALUES, dl, Op->getVTList(), Result, isValid,
|
||||||
|
Op.getOperand(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SDValue X86TargetLowering::LowerRETURNADDR(SDValue Op,
|
SDValue X86TargetLowering::LowerRETURNADDR(SDValue Op,
|
||||||
SelectionDAG &DAG) const {
|
SelectionDAG &DAG) const {
|
||||||
MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
|
MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
|
||||||
@ -10894,6 +10927,7 @@ SDValue X86TargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
|
|||||||
case ISD::VAARG: return LowerVAARG(Op, DAG);
|
case ISD::VAARG: return LowerVAARG(Op, DAG);
|
||||||
case ISD::VACOPY: return LowerVACOPY(Op, DAG);
|
case ISD::VACOPY: return LowerVACOPY(Op, DAG);
|
||||||
case ISD::INTRINSIC_WO_CHAIN: return LowerINTRINSIC_WO_CHAIN(Op, DAG);
|
case ISD::INTRINSIC_WO_CHAIN: return LowerINTRINSIC_WO_CHAIN(Op, DAG);
|
||||||
|
case ISD::INTRINSIC_W_CHAIN: return LowerINTRINSIC_W_CHAIN(Op, DAG);
|
||||||
case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG);
|
case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG);
|
||||||
case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG);
|
case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG);
|
||||||
case ISD::FRAME_TO_ARGS_OFFSET:
|
case ISD::FRAME_TO_ARGS_OFFSET:
|
||||||
@ -11228,6 +11262,7 @@ const char *X86TargetLowering::getTargetNodeName(unsigned Opcode) const {
|
|||||||
case X86ISD::SEG_ALLOCA: return "X86ISD::SEG_ALLOCA";
|
case X86ISD::SEG_ALLOCA: return "X86ISD::SEG_ALLOCA";
|
||||||
case X86ISD::WIN_FTOL: return "X86ISD::WIN_FTOL";
|
case X86ISD::WIN_FTOL: return "X86ISD::WIN_FTOL";
|
||||||
case X86ISD::SAHF: return "X86ISD::SAHF";
|
case X86ISD::SAHF: return "X86ISD::SAHF";
|
||||||
|
case X86ISD::RDRAND: return "X86ISD::RDRAND";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,6 +322,9 @@ namespace llvm {
|
|||||||
// SAHF - Store contents of %ah into %eflags.
|
// SAHF - Store contents of %ah into %eflags.
|
||||||
SAHF,
|
SAHF,
|
||||||
|
|
||||||
|
// RDRAND - Get a random integer and indicate whether it is valid in CF.
|
||||||
|
RDRAND,
|
||||||
|
|
||||||
// ATOMADD64_DAG, ATOMSUB64_DAG, ATOMOR64_DAG, ATOMAND64_DAG,
|
// ATOMADD64_DAG, ATOMSUB64_DAG, ATOMOR64_DAG, ATOMAND64_DAG,
|
||||||
// ATOMXOR64_DAG, ATOMNAND64_DAG, ATOMSWAP64_DAG -
|
// ATOMXOR64_DAG, ATOMNAND64_DAG, ATOMSWAP64_DAG -
|
||||||
// Atomic 64-bit binary operations.
|
// Atomic 64-bit binary operations.
|
||||||
@ -768,6 +771,7 @@ namespace llvm {
|
|||||||
SDValue LowerVAARG(SDValue Op, SelectionDAG &DAG) const;
|
SDValue LowerVAARG(SDValue Op, SelectionDAG &DAG) const;
|
||||||
SDValue LowerVACOPY(SDValue Op, SelectionDAG &DAG) const;
|
SDValue LowerVACOPY(SDValue Op, SelectionDAG &DAG) const;
|
||||||
SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const;
|
SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const;
|
||||||
|
SDValue LowerINTRINSIC_W_CHAIN(SDValue Op, SelectionDAG &DAG) const;
|
||||||
SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const;
|
SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const;
|
||||||
SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const;
|
SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const;
|
||||||
SDValue LowerFRAME_TO_ARGS_OFFSET(SDValue Op, SelectionDAG &DAG) const;
|
SDValue LowerFRAME_TO_ARGS_OFFSET(SDValue Op, SelectionDAG &DAG) const;
|
||||||
|
@ -65,6 +65,8 @@ def SDTX86SetCC_C : SDTypeProfile<1, 2,
|
|||||||
|
|
||||||
def SDTX86sahf : SDTypeProfile<1, 1, [SDTCisVT<0, i32>, SDTCisVT<1, i8>]>;
|
def SDTX86sahf : SDTypeProfile<1, 1, [SDTCisVT<0, i32>, SDTCisVT<1, i8>]>;
|
||||||
|
|
||||||
|
def SDTX86rdrand : SDTypeProfile<2, 0, [SDTCisInt<0>, SDTCisVT<1, i32>]>;
|
||||||
|
|
||||||
def SDTX86cas : SDTypeProfile<0, 3, [SDTCisPtrTy<0>, SDTCisInt<1>,
|
def SDTX86cas : SDTypeProfile<0, 3, [SDTCisPtrTy<0>, SDTCisInt<1>,
|
||||||
SDTCisVT<2, i8>]>;
|
SDTCisVT<2, i8>]>;
|
||||||
def SDTX86caspair : SDTypeProfile<0, 1, [SDTCisPtrTy<0>]>;
|
def SDTX86caspair : SDTypeProfile<0, 1, [SDTCisPtrTy<0>]>;
|
||||||
@ -137,6 +139,8 @@ def X86setcc_c : SDNode<"X86ISD::SETCC_CARRY", SDTX86SetCC_C>;
|
|||||||
|
|
||||||
def X86sahf : SDNode<"X86ISD::SAHF", SDTX86sahf>;
|
def X86sahf : SDNode<"X86ISD::SAHF", SDTX86sahf>;
|
||||||
|
|
||||||
|
def X86rdrand : SDNode<"X86ISD::RDRAND", SDTX86rdrand>;
|
||||||
|
|
||||||
def X86cas : SDNode<"X86ISD::LCMPXCHG_DAG", SDTX86cas,
|
def X86cas : SDNode<"X86ISD::LCMPXCHG_DAG", SDTX86cas,
|
||||||
[SDNPHasChain, SDNPInGlue, SDNPOutGlue, SDNPMayStore,
|
[SDNPHasChain, SDNPInGlue, SDNPOutGlue, SDNPMayStore,
|
||||||
SDNPMayLoad, SDNPMemOperand]>;
|
SDNPMayLoad, SDNPMemOperand]>;
|
||||||
@ -1466,11 +1470,14 @@ let Predicates = [HasMOVBE] in {
|
|||||||
//
|
//
|
||||||
let Predicates = [HasRDRAND], Defs = [EFLAGS] in {
|
let Predicates = [HasRDRAND], Defs = [EFLAGS] in {
|
||||||
def RDRAND16r : I<0xC7, MRM6r, (outs GR16:$dst), (ins),
|
def RDRAND16r : I<0xC7, MRM6r, (outs GR16:$dst), (ins),
|
||||||
"rdrand{w}\t$dst", []>, OpSize, TB;
|
"rdrand{w}\t$dst",
|
||||||
|
[(set GR16:$dst, EFLAGS, (X86rdrand))]>, OpSize, TB;
|
||||||
def RDRAND32r : I<0xC7, MRM6r, (outs GR32:$dst), (ins),
|
def RDRAND32r : I<0xC7, MRM6r, (outs GR32:$dst), (ins),
|
||||||
"rdrand{l}\t$dst", []>, TB;
|
"rdrand{l}\t$dst",
|
||||||
|
[(set GR32:$dst, EFLAGS, (X86rdrand))]>, TB;
|
||||||
def RDRAND64r : RI<0xC7, MRM6r, (outs GR64:$dst), (ins),
|
def RDRAND64r : RI<0xC7, MRM6r, (outs GR64:$dst), (ins),
|
||||||
"rdrand{q}\t$dst", []>, TB;
|
"rdrand{q}\t$dst",
|
||||||
|
[(set GR64:$dst, EFLAGS, (X86rdrand))]>, TB;
|
||||||
}
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
47
test/CodeGen/X86/rdrand.ll
Normal file
47
test/CodeGen/X86/rdrand.ll
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
; RUN: llc < rdrand.ll -march=x86-64 -mattr=+rdrand | FileCheck %s
|
||||||
|
declare {i16, i32} @llvm.x86.rdrand.16()
|
||||||
|
declare {i32, i32} @llvm.x86.rdrand.32()
|
||||||
|
declare {i64, i32} @llvm.x86.rdrand.64()
|
||||||
|
|
||||||
|
define i32 @_rdrand16_step(i16* %random_val) {
|
||||||
|
%call = call {i16, i32} @llvm.x86.rdrand.16()
|
||||||
|
%randval = extractvalue {i16, i32} %call, 0
|
||||||
|
store i16 %randval, i16* %random_val
|
||||||
|
%isvalid = extractvalue {i16, i32} %call, 1
|
||||||
|
ret i32 %isvalid
|
||||||
|
; CHECK: _rdrand16_step:
|
||||||
|
; CHECK: rdrandw %ax
|
||||||
|
; CHECK: movw %ax, (%rdi)
|
||||||
|
; CHECK: movzwl %ax, %ecx
|
||||||
|
; CHECK: movl $1, %eax
|
||||||
|
; CHECK: cmovael %ecx, %eax
|
||||||
|
; CHECK: ret
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32 @_rdrand32_step(i32* %random_val) {
|
||||||
|
%call = call {i32, i32} @llvm.x86.rdrand.32()
|
||||||
|
%randval = extractvalue {i32, i32} %call, 0
|
||||||
|
store i32 %randval, i32* %random_val
|
||||||
|
%isvalid = extractvalue {i32, i32} %call, 1
|
||||||
|
ret i32 %isvalid
|
||||||
|
; CHECK: _rdrand32_step:
|
||||||
|
; CHECK: rdrandl %ecx
|
||||||
|
; CHECK: movl %ecx, (%rdi)
|
||||||
|
; CHECK: movl $1, %eax
|
||||||
|
; CHECK: cmovael %ecx, %eax
|
||||||
|
; CHECK: ret
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32 @_rdrand64_step(i64* %random_val) {
|
||||||
|
%call = call {i64, i32} @llvm.x86.rdrand.64()
|
||||||
|
%randval = extractvalue {i64, i32} %call, 0
|
||||||
|
store i64 %randval, i64* %random_val
|
||||||
|
%isvalid = extractvalue {i64, i32} %call, 1
|
||||||
|
ret i32 %isvalid
|
||||||
|
; CHECK: _rdrand64_step:
|
||||||
|
; CHECK: rdrandq %rcx
|
||||||
|
; CHECK: movq %rcx, (%rdi)
|
||||||
|
; CHECK: movl $1, %eax
|
||||||
|
; CHECK: cmovael %ecx, %eax
|
||||||
|
; CHECK: ret
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user