diff options
author | Benjamin Kramer <benny.kra@googlemail.com> | 2012-07-12 09:31:43 +0000 |
---|---|---|
committer | Benjamin Kramer <benny.kra@googlemail.com> | 2012-07-12 09:31:43 +0000 |
commit | b9bee0499553358e64c34cfcbd32380ac7fb452e (patch) | |
tree | a9168a3d1d6d1ffbafb4fcee06089d72972ed532 | |
parent | 4e8982a34da69effe23ce9c553680b19d7d57551 (diff) | |
download | external_llvm-b9bee0499553358e64c34cfcbd32380ac7fb452e.zip external_llvm-b9bee0499553358e64c34cfcbd32380ac7fb452e.tar.gz external_llvm-b9bee0499553358e64c34cfcbd32380ac7fb452e.tar.bz2 |
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
-rw-r--r-- | include/llvm/IntrinsicsX86.td | 11 | ||||
-rw-r--r-- | lib/Target/X86/X86ISelLowering.cpp | 35 | ||||
-rw-r--r-- | lib/Target/X86/X86ISelLowering.h | 4 | ||||
-rw-r--r-- | lib/Target/X86/X86InstrInfo.td | 13 | ||||
-rw-r--r-- | test/CodeGen/X86/rdrand.ll | 47 |
5 files changed, 107 insertions, 3 deletions
diff --git a/include/llvm/IntrinsicsX86.td b/include/llvm/IntrinsicsX86.td index 14fd76d..e8039f2 100644 --- a/include/llvm/IntrinsicsX86.td +++ b/include/llvm/IntrinsicsX86.td @@ -2536,3 +2536,14 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". Intrinsic<[llvm_v8i16_ty], [llvm_v8f32_ty, llvm_i32_ty], [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], [], []>; +} diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp index 4dccd40..c242aaa 100644 --- a/lib/Target/X86/X86ISelLowering.cpp +++ b/lib/Target/X86/X86ISelLowering.cpp @@ -1176,6 +1176,7 @@ X86TargetLowering::X86TargetLowering(X86TargetMachine &TM) // We want to custom lower some of our intrinsics. 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 @@ -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, SelectionDAG &DAG) const { 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::VACOPY: return LowerVACOPY(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::FRAMEADDR: return LowerFRAMEADDR(Op, DAG); 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::WIN_FTOL: return "X86ISD::WIN_FTOL"; case X86ISD::SAHF: return "X86ISD::SAHF"; + case X86ISD::RDRAND: return "X86ISD::RDRAND"; } } diff --git a/lib/Target/X86/X86ISelLowering.h b/lib/Target/X86/X86ISelLowering.h index 2f561a0..41bdd06 100644 --- a/lib/Target/X86/X86ISelLowering.h +++ b/lib/Target/X86/X86ISelLowering.h @@ -322,6 +322,9 @@ namespace llvm { // SAHF - Store contents of %ah into %eflags. SAHF, + // RDRAND - Get a random integer and indicate whether it is valid in CF. + RDRAND, + // ATOMADD64_DAG, ATOMSUB64_DAG, ATOMOR64_DAG, ATOMAND64_DAG, // ATOMXOR64_DAG, ATOMNAND64_DAG, ATOMSWAP64_DAG - // Atomic 64-bit binary operations. @@ -768,6 +771,7 @@ namespace llvm { SDValue LowerVAARG(SDValue Op, SelectionDAG &DAG) const; SDValue LowerVACOPY(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 LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const; SDValue LowerFRAME_TO_ARGS_OFFSET(SDValue Op, SelectionDAG &DAG) const; diff --git a/lib/Target/X86/X86InstrInfo.td b/lib/Target/X86/X86InstrInfo.td index 0f7b787..dc26d4c 100644 --- a/lib/Target/X86/X86InstrInfo.td +++ b/lib/Target/X86/X86InstrInfo.td @@ -65,6 +65,8 @@ def SDTX86SetCC_C : SDTypeProfile<1, 2, 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>, SDTCisVT<2, i8>]>; 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 X86rdrand : SDNode<"X86ISD::RDRAND", SDTX86rdrand>; + def X86cas : SDNode<"X86ISD::LCMPXCHG_DAG", SDTX86cas, [SDNPHasChain, SDNPInGlue, SDNPOutGlue, SDNPMayStore, SDNPMayLoad, SDNPMemOperand]>; @@ -1466,11 +1470,14 @@ let Predicates = [HasMOVBE] in { // let Predicates = [HasRDRAND], Defs = [EFLAGS] in { 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), - "rdrand{l}\t$dst", []>, TB; + "rdrand{l}\t$dst", + [(set GR32:$dst, EFLAGS, (X86rdrand))]>, TB; def RDRAND64r : RI<0xC7, MRM6r, (outs GR64:$dst), (ins), - "rdrand{q}\t$dst", []>, TB; + "rdrand{q}\t$dst", + [(set GR64:$dst, EFLAGS, (X86rdrand))]>, TB; } //===----------------------------------------------------------------------===// diff --git a/test/CodeGen/X86/rdrand.ll b/test/CodeGen/X86/rdrand.ll new file mode 100644 index 0000000..7bb25b3 --- /dev/null +++ b/test/CodeGen/X86/rdrand.ll @@ -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 +} |