Add support of RDSEED defined in AVX2 extension
llvm-svn: 178314
This commit is contained in:
parent
3b602ce5a4
commit
a486a11dcf
|
@ -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], [], []>;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
//
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
Loading…
Reference in New Issue