From c26392aa5d9c2dbca2909d6874d181455f8aeb8f Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Thu, 28 Mar 2013 23:41:26 +0000 Subject: [PATCH] Add support of RDSEED defined in AVX2 extension git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@178314 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/IR/IntrinsicsX86.td | 7 ++++- lib/Target/X86/X86.td | 2 ++ lib/Target/X86/X86ISelLowering.cpp | 24 +++++++++----- lib/Target/X86/X86ISelLowering.h | 4 +++ lib/Target/X86/X86InstrInfo.td | 19 ++++++++++++ lib/Target/X86/X86Subtarget.cpp | 5 +++ lib/Target/X86/X86Subtarget.h | 4 +++ test/CodeGen/X86/bool-simplify.ll | 50 +++++++++++++++++++++++++++++- test/CodeGen/X86/rdseed.ll | 48 ++++++++++++++++++++++++++++ test/MC/X86/x86_64-rand-encoding.s | 49 +++++++++++++++++++++++++++++ 10 files changed, 203 insertions(+), 9 deletions(-) create mode 100644 test/CodeGen/X86/rdseed.ll create mode 100644 test/MC/X86/x86_64-rand-encoding.s diff --git a/include/llvm/IR/IntrinsicsX86.td b/include/llvm/IR/IntrinsicsX86.td index 873c624bfef..69e0ab4fa2e 100644 --- a/include/llvm/IR/IntrinsicsX86.td +++ b/include/llvm/IR/IntrinsicsX86.td @@ -2550,7 +2550,9 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". } //===----------------------------------------------------------------------===// -// RDRAND intrinsics. Return a random value and whether it is valid. +// RDRAND intrinsics - Return a random value and whether it is valid. +// RDSEED intrinsics - Return a NIST SP800-90B & C compliant 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 @@ -2558,6 +2560,9 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". 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], [], []>; + def int_x86_rdseed_16 : Intrinsic<[llvm_i16_ty, llvm_i32_ty], [], []>; + def int_x86_rdseed_32 : Intrinsic<[llvm_i32_ty, llvm_i32_ty], [], []>; + def int_x86_rdseed_64 : Intrinsic<[llvm_i64_ty, llvm_i32_ty], [], []>; } //===----------------------------------------------------------------------===// diff --git a/lib/Target/X86/X86.td b/lib/Target/X86/X86.td index ec9a8230bd3..1dcc344e7f0 100644 --- a/lib/Target/X86/X86.td +++ b/lib/Target/X86/X86.td @@ -126,6 +126,8 @@ def FeatureADX : SubtargetFeature<"adx", "HasADX", "true", "Support ADX instructions">; def FeaturePRFCHW : SubtargetFeature<"prfchw", "HasPRFCHW", "true", "Support PRFCHW instructions">; +def FeatureRDSEED : SubtargetFeature<"rdseed", "HasRDSEED", "true", + "Support RDSEED instruction">; def FeatureLeaForSP : SubtargetFeature<"lea-sp", "UseLeaForSP", "true", "Use LEA for adjusting the stack pointer">; def FeatureSlowDivide : SubtargetFeature<"idiv-to-divb", diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp index e0f87c03b7c..b3127657cbd 100644 --- a/lib/Target/X86/X86ISelLowering.cpp +++ b/lib/Target/X86/X86ISelLowering.cpp @@ -10914,16 +10914,23 @@ static SDValue LowerINTRINSIC_W_CHAIN(SDValue Op, SelectionDAG &DAG) { switch (IntNo) { default: return SDValue(); // Don't custom lower most intrinsics. - // RDRAND intrinsics. + // RDRAND/RDSEED intrinsics. case Intrinsic::x86_rdrand_16: case Intrinsic::x86_rdrand_32: - case Intrinsic::x86_rdrand_64: { + case Intrinsic::x86_rdrand_64: + case Intrinsic::x86_rdseed_16: + case Intrinsic::x86_rdseed_32: + case Intrinsic::x86_rdseed_64: { + unsigned Opcode = (IntNo == Intrinsic::x86_rdseed_16 || + IntNo == Intrinsic::x86_rdseed_32 || + IntNo == Intrinsic::x86_rdseed_64) ? X86ISD::RDSEED : + X86ISD::RDRAND; // Emit the node with the right value type. SDVTList VTs = DAG.getVTList(Op->getValueType(0), MVT::Glue, MVT::Other); - SDValue Result = DAG.getNode(X86ISD::RDRAND, dl, VTs, Op.getOperand(0)); + SDValue Result = DAG.getNode(Opcode, dl, VTs, Op.getOperand(0)); - // 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. + // If the value returned by RDRAND/RDSEED 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), @@ -12781,6 +12788,7 @@ const char *X86TargetLowering::getTargetNodeName(unsigned Opcode) const { case X86ISD::WIN_FTOL: return "X86ISD::WIN_FTOL"; case X86ISD::SAHF: return "X86ISD::SAHF"; case X86ISD::RDRAND: return "X86ISD::RDRAND"; + case X86ISD::RDSEED: return "X86ISD::RDSEED"; case X86ISD::FMADD: return "X86ISD::FMADD"; case X86ISD::FMSUB: return "X86ISD::FMSUB"; case X86ISD::FNMADD: return "X86ISD::FNMADD"; @@ -15847,8 +15855,10 @@ static SDValue checkBoolTestSetCCCombine(SDValue Cmp, X86::CondCode &CC) { if (Op.getOpcode() == ISD::ZERO_EXTEND || Op.getOpcode() == ISD::TRUNCATE) Op = Op.getOperand(0); - // A special case for rdrand, where 0 is set if false cond is found. - if (Op.getOpcode() != X86ISD::RDRAND || Op.getResNo() != 0) + // A special case for rdrand/rdseed, where 0 is set if false cond is + // found. + if ((Op.getOpcode() != X86ISD::RDRAND && + Op.getOpcode() != X86ISD::RDSEED) || Op.getResNo() != 0) return SDValue(); } // Quit if false value is not the constant 0 or 1. diff --git a/lib/Target/X86/X86ISelLowering.h b/lib/Target/X86/X86ISelLowering.h index 5f141a49fa4..5725f7aea58 100644 --- a/lib/Target/X86/X86ISelLowering.h +++ b/lib/Target/X86/X86ISelLowering.h @@ -356,6 +356,10 @@ namespace llvm { // RDRAND - Get a random integer and indicate whether it is valid in CF. RDRAND, + // RDSEED - Get a NIST SP800-90B & C compliant random integer and + // indicate whether it is valid in CF. + RDSEED, + // PCMP*STRI PCMPISTRI, PCMPESTRI, diff --git a/lib/Target/X86/X86InstrInfo.td b/lib/Target/X86/X86InstrInfo.td index 93e8beb19be..ccc1aa2e35a 100644 --- a/lib/Target/X86/X86InstrInfo.td +++ b/lib/Target/X86/X86InstrInfo.td @@ -142,6 +142,9 @@ def X86sahf : SDNode<"X86ISD::SAHF", SDTX86sahf>; def X86rdrand : SDNode<"X86ISD::RDRAND", SDTX86rdrand, [SDNPHasChain, SDNPSideEffect]>; +def X86rdseed : SDNode<"X86ISD::RDSEED", SDTX86rdrand, + [SDNPHasChain, SDNPSideEffect]>; + def X86cas : SDNode<"X86ISD::LCMPXCHG_DAG", SDTX86cas, [SDNPHasChain, SDNPInGlue, SDNPOutGlue, SDNPMayStore, SDNPMayLoad, SDNPMemOperand]>; @@ -607,6 +610,7 @@ def HasHLE : Predicate<"Subtarget->hasHLE()">; def HasTSX : Predicate<"Subtarget->hasRTM() || Subtarget->hasHLE()">; def HasADX : Predicate<"Subtarget->hasADX()">; def HasPRFCHW : Predicate<"Subtarget->hasPRFCHW()">; +def HasRDSEED : Predicate<"Subtarget->hasRDSEED()">; def HasPrefetchW : Predicate<"Subtarget->has3DNow() || Subtarget->hasPRFCHW()">; def FPStackf32 : Predicate<"!Subtarget->hasSSE1()">; def FPStackf64 : Predicate<"!Subtarget->hasSSE2()">; @@ -1633,6 +1637,21 @@ let Predicates = [HasRDRAND], Defs = [EFLAGS] in { [(set GR64:$dst, EFLAGS, (X86rdrand))]>, TB; } +//===----------------------------------------------------------------------===// +// RDSEED Instruction +// +let Predicates = [HasRDSEED], Defs = [EFLAGS] in { + def RDSEED16r : I<0xC7, MRM7r, (outs GR16:$dst), (ins), + "rdseed{w}\t$dst", + [(set GR16:$dst, EFLAGS, (X86rdseed))]>, OpSize, TB; + def RDSEED32r : I<0xC7, MRM7r, (outs GR32:$dst), (ins), + "rdseed{l}\t$dst", + [(set GR32:$dst, EFLAGS, (X86rdseed))]>, TB; + def RDSEED64r : RI<0xC7, MRM7r, (outs GR64:$dst), (ins), + "rdseed{q}\t$dst", + [(set GR64:$dst, EFLAGS, (X86rdseed))]>, TB; +} + //===----------------------------------------------------------------------===// // LZCNT Instruction // diff --git a/lib/Target/X86/X86Subtarget.cpp b/lib/Target/X86/X86Subtarget.cpp index fa991298a6d..4132463ee8b 100644 --- a/lib/Target/X86/X86Subtarget.cpp +++ b/lib/Target/X86/X86Subtarget.cpp @@ -334,6 +334,10 @@ void X86Subtarget::AutoDetectSubtargetFeatures() { HasADX = true; ToggleFeature(X86::FeatureADX); } + if (IsIntel && ((EBX >> 18) & 0x1)) { + HasRDSEED = true; + ToggleFeature(X86::FeatureRDSEED); + } } } } @@ -454,6 +458,7 @@ void X86Subtarget::initializeEnvironment() { HasHLE = false; HasADX = false; HasPRFCHW = false; + HasRDSEED = false; IsBTMemSlow = false; IsUAMemFast = false; HasVectorUAMem = false; diff --git a/lib/Target/X86/X86Subtarget.h b/lib/Target/X86/X86Subtarget.h index cac3f579b00..6fbdb1d5f00 100644 --- a/lib/Target/X86/X86Subtarget.h +++ b/lib/Target/X86/X86Subtarget.h @@ -130,6 +130,9 @@ protected: /// HasPRFCHW - Processor has PRFCHW instructions. bool HasPRFCHW; + /// HasRDSEED - Processor has RDSEED instructions. + bool HasRDSEED; + /// IsBTMemSlow - True if BT (bit test) of memory instructions are slow. bool IsBTMemSlow; @@ -266,6 +269,7 @@ public: bool hasHLE() const { return HasHLE; } bool hasADX() const { return HasADX; } bool hasPRFCHW() const { return HasPRFCHW; } + bool hasRDSEED() const { return HasRDSEED; } bool isBTMemSlow() const { return IsBTMemSlow; } bool isUnalignedMemAccessFast() const { return IsUAMemFast; } bool hasVectorUAMem() const { return HasVectorUAMem; } diff --git a/test/CodeGen/X86/bool-simplify.ll b/test/CodeGen/X86/bool-simplify.ll index 6d8e7fbe45e..fa6f6e85e9b 100644 --- a/test/CodeGen/X86/bool-simplify.ll +++ b/test/CodeGen/X86/bool-simplify.ll @@ -1,4 +1,4 @@ -; RUN: llc < %s -march=x86-64 -mattr=+sse41,-avx,+rdrand | FileCheck %s +; RUN: llc < %s -march=x86-64 -mattr=+sse41,-avx,+rdrand,+rdseed | FileCheck %s define i32 @foo(<2 x i64> %c, i32 %a, i32 %b) { %t1 = call i32 @llvm.x86.sse41.ptestz(<2 x i64> %c, <2 x i64> %c) @@ -84,7 +84,55 @@ define i64 @rnd64(i64 %arg) nounwind uwtable { ; CHECK: ret } +define i16 @seed16(i16 %arg) nounwind uwtable { + %1 = tail call { i16, i32 } @llvm.x86.rdseed.16() nounwind + %2 = extractvalue { i16, i32 } %1, 0 + %3 = extractvalue { i16, i32 } %1, 1 + %4 = icmp eq i32 %3, 0 + %5 = select i1 %4, i16 0, i16 %arg + %6 = add i16 %5, %2 + ret i16 %6 +; CHECK: seed16 +; CHECK: rdseed +; CHECK: cmov +; CHECK-NOT: cmov +; CHECK: ret +} + +define i32 @seed32(i32 %arg) nounwind uwtable { + %1 = tail call { i32, i32 } @llvm.x86.rdseed.32() nounwind + %2 = extractvalue { i32, i32 } %1, 0 + %3 = extractvalue { i32, i32 } %1, 1 + %4 = icmp eq i32 %3, 0 + %5 = select i1 %4, i32 0, i32 %arg + %6 = add i32 %5, %2 + ret i32 %6 +; CHECK: seed32 +; CHECK: rdseed +; CHECK: cmov +; CHECK-NOT: cmov +; CHECK: ret +} + +define i64 @seed64(i64 %arg) nounwind uwtable { + %1 = tail call { i64, i32 } @llvm.x86.rdseed.64() nounwind + %2 = extractvalue { i64, i32 } %1, 0 + %3 = extractvalue { i64, i32 } %1, 1 + %4 = icmp eq i32 %3, 0 + %5 = select i1 %4, i64 0, i64 %arg + %6 = add i64 %5, %2 + ret i64 %6 +; CHECK: seed64 +; CHECK: rdseed +; CHECK: cmov +; CHECK-NOT: cmov +; CHECK: ret +} + declare i32 @llvm.x86.sse41.ptestz(<2 x i64>, <2 x i64>) nounwind readnone declare { i16, i32 } @llvm.x86.rdrand.16() nounwind declare { i32, i32 } @llvm.x86.rdrand.32() nounwind declare { i64, i32 } @llvm.x86.rdrand.64() nounwind +declare { i16, i32 } @llvm.x86.rdseed.16() nounwind +declare { i32, i32 } @llvm.x86.rdseed.32() nounwind +declare { i64, i32 } @llvm.x86.rdseed.64() nounwind diff --git a/test/CodeGen/X86/rdseed.ll b/test/CodeGen/X86/rdseed.ll new file mode 100644 index 00000000000..35de7ebf743 --- /dev/null +++ b/test/CodeGen/X86/rdseed.ll @@ -0,0 +1,48 @@ +; RUN: llc < %s -march=x86-64 -mcpu=core-avx-i -mattr=+rdseed | FileCheck %s + +declare {i16, i32} @llvm.x86.rdseed.16() +declare {i32, i32} @llvm.x86.rdseed.32() +declare {i64, i32} @llvm.x86.rdseed.64() + +define i32 @_rdseed16_step(i16* %random_val) { + %call = call {i16, i32} @llvm.x86.rdseed.16() + %randval = extractvalue {i16, i32} %call, 0 + store i16 %randval, i16* %random_val + %isvalid = extractvalue {i16, i32} %call, 1 + ret i32 %isvalid +; CHECK: _rdseed16_step: +; CHECK: rdseedw %ax +; CHECK: movw %ax, (%r[[A0:di|cx]]) +; CHECK: movzwl %ax, %ecx +; CHECK: movl $1, %eax +; CHECK: cmovael %ecx, %eax +; CHECK: ret +} + +define i32 @_rdseed32_step(i32* %random_val) { + %call = call {i32, i32} @llvm.x86.rdseed.32() + %randval = extractvalue {i32, i32} %call, 0 + store i32 %randval, i32* %random_val + %isvalid = extractvalue {i32, i32} %call, 1 + ret i32 %isvalid +; CHECK: _rdseed32_step: +; CHECK: rdseedl %e[[T0:[a-z]+]] +; CHECK: movl %e[[T0]], (%r[[A0]]) +; CHECK: movl $1, %eax +; CHECK: cmovael %e[[T0]], %eax +; CHECK: ret +} + +define i32 @_rdseed64_step(i64* %random_val) { + %call = call {i64, i32} @llvm.x86.rdseed.64() + %randval = extractvalue {i64, i32} %call, 0 + store i64 %randval, i64* %random_val + %isvalid = extractvalue {i64, i32} %call, 1 + ret i32 %isvalid +; CHECK: _rdseed64_step: +; CHECK: rdseedq %r[[T1:[a-z]+]] +; CHECK: movq %r[[T1]], (%r[[A0]]) +; CHECK: movl $1, %eax +; CHECK: cmovael %e[[T1]], %eax +; CHECK: ret +} diff --git a/test/MC/X86/x86_64-rand-encoding.s b/test/MC/X86/x86_64-rand-encoding.s new file mode 100644 index 00000000000..3a8cb817bc1 --- /dev/null +++ b/test/MC/X86/x86_64-rand-encoding.s @@ -0,0 +1,49 @@ +// RUN: llvm-mc -triple x86_64-unknown-unknown --show-encoding %s | FileCheck %s + +// CHECK: rdrandw %ax +// CHECK: encoding: [0x66,0x0f,0xc7,0xf0] + rdrand %ax + +// CHECK: rdrandl %eax +// CHECK: encoding: [0x0f,0xc7,0xf0] + rdrand %eax + +// CHECK: rdrandq %rax +// CHECK: encoding: [0x48,0x0f,0xc7,0xf0] + rdrand %rax + +// CHECK: rdrandw %r11w +// CHECK: encoding: [0x66,0x41,0x0f,0xc7,0xf3] + rdrand %r11w + +// CHECK: rdrandl %r11d +// CHECK: encoding: [0x41,0x0f,0xc7,0xf3] + rdrand %r11d + +// CHECK: rdrandq %r11 +// CHECK: encoding: [0x49,0x0f,0xc7,0xf3] + rdrand %r11 + +// CHECK: rdseedw %ax +// CHECK: encoding: [0x66,0x0f,0xc7,0xf8] + rdseed %ax + +// CHECK: rdseedl %eax +// CHECK: encoding: [0x0f,0xc7,0xf8] + rdseed %eax + +// CHECK: rdseedq %rax +// CHECK: encoding: [0x48,0x0f,0xc7,0xf8] + rdseed %rax + +// CHECK: rdseedw %r11w +// CHECK: encoding: [0x66,0x41,0x0f,0xc7,0xfb] + rdseed %r11w + +// CHECK: rdseedl %r11d +// CHECK: encoding: [0x41,0x0f,0xc7,0xfb] + rdseed %r11d + +// CHECK: rdseedq %r11 +// CHECK: encoding: [0x49,0x0f,0xc7,0xfb] + rdseed %r11 -- 2.34.1