Index: include/llvm/IR/IntrinsicsX86.td =================================================================== --- include/llvm/IR/IntrinsicsX86.td +++ include/llvm/IR/IntrinsicsX86.td @@ -6293,3 +6293,37 @@ def int_x86_tpause : GCCBuiltin<"__builtin_ia32_tpause">, Intrinsic<[llvm_i8_ty], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], []>; } + +//===----------------------------------------------------------------------===// +// Platform Configuration +let TargetPrefix = "x86" in { + def int_x86_pconfig_32 : + Intrinsic<[llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], + [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], []>; + def int_x86_pconfig_64 : + Intrinsic<[llvm_i32_ty, llvm_i64_ty, llvm_i64_ty, llvm_i64_ty], + [llvm_i32_ty, llvm_i64_ty, llvm_i64_ty, llvm_i64_ty], []>; +} + +//===----------------------------------------------------------------------===// +// SGX Intrinsics +let TargetPrefix = "x86" in { + def int_x86_encls_32 : + Intrinsic<[llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], + [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], []>; + def int_x86_encls_64 : + Intrinsic<[llvm_i32_ty, llvm_i64_ty, llvm_i64_ty, llvm_i64_ty], + [llvm_i32_ty, llvm_i64_ty, llvm_i64_ty, llvm_i64_ty], []>; + def int_x86_enclu_32 : + Intrinsic<[llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], + [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], []>; + def int_x86_enclu_64 : + Intrinsic<[llvm_i32_ty, llvm_i64_ty, llvm_i64_ty, llvm_i64_ty], + [llvm_i32_ty, llvm_i64_ty, llvm_i64_ty, llvm_i64_ty], []>; + def int_x86_enclv_32 : + Intrinsic<[llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], + [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], []>; + def int_x86_enclv_64 : + Intrinsic<[llvm_i32_ty, llvm_i64_ty, llvm_i64_ty, llvm_i64_ty], + [llvm_i32_ty, llvm_i64_ty, llvm_i64_ty, llvm_i64_ty], []>; +} Index: lib/Support/Host.cpp =================================================================== --- lib/Support/Host.cpp +++ lib/Support/Host.cpp @@ -1264,6 +1264,18 @@ Features["ibt"] = HasLeaf7 && ((EDX >> 20) & 1); + // There are two CPUID leafs which information associated with the pconfig + // instruction: + // EAX=0x7, ECX=0x0 indicates the availability of the instruction (via the 18th + // bit of EDX), while the EAX=0x1b leaf returns information on the + // availability of specific pconfig leafs. + // The target feature here only refers to the the first of these two. + // Users might need to check for the availability of specific pconfig + // leaves using cpuid, since that information is ignored while + // detecting features using the "-march=native" flag. + // For more info, see X86 ISA docs. + Features["pconfig"] = HasLeaf7 && ((EDX >> 18) & 1); + bool HasLeafD = MaxLevel >= 0xd && !getX86CpuIDAndInfoEx(0xd, 0x1, &EAX, &EBX, &ECX, &EDX); Index: lib/Target/X86/X86.td =================================================================== --- lib/Target/X86/X86.td +++ lib/Target/X86/X86.td @@ -280,6 +280,8 @@ def FeatureLZCNTFalseDeps : SubtargetFeature<"false-deps-lzcnt-tzcnt", "HasLZCNTFalseDeps", "true", "LZCNT/TZCNT have a false dependency on dest register">; +def FeaturePCONFIG : SubtargetFeature<"pconfig", "HasPCONFIG", "true", + "platform configuration instruction">; // On recent X86 (port bound) processors, its preferable to combine to a single shuffle // using a variable mask over multiple fixed shuffles. def FeatureFastVariableShuffle @@ -860,6 +862,7 @@ class IcelakeServerProc : ProcModel; Index: lib/Target/X86/X86ISelLowering.cpp =================================================================== --- lib/Target/X86/X86ISelLowering.cpp +++ lib/Target/X86/X86ISelLowering.cpp @@ -21153,6 +21153,32 @@ return SDValue(Res, 0); } +static SDValue getInstrWFourImplicitOps(SDValue Op, SelectionDAG &DAG, + const X86Subtarget &Subtarget, + unsigned Opcode) { + SDLoc DL(Op); + SDVTList Tys = DAG.getVTList(MVT::Other, MVT::Glue); + SDValue Chain = Op.getOperand(0); + unsigned ArgReg1 = Subtarget.is64Bit() ? X86::RBX : X86::EBX; + unsigned ArgReg2 = Subtarget.is64Bit() ? X86::RCX : X86::ECX; + unsigned ArgReg3 = Subtarget.is64Bit() ? X86::RDX : X86::EDX; + auto ArgVT = Subtarget.is64Bit() ? MVT::i64 : MVT::i32; + + Chain = DAG.getCopyToReg(Chain, DL, X86::EAX, Op->getOperand(2)); + Chain = DAG.getCopyToReg(Chain, DL, ArgReg1, Op->getOperand(3)); + Chain = DAG.getCopyToReg(Chain, DL, ArgReg2, Op->getOperand(4)); + Chain = DAG.getCopyToReg(Chain, DL, ArgReg3, Op->getOperand(5)); + + SDNode *Res = DAG.getMachineNode(Opcode, DL, Tys, Chain); + + SDValue A = DAG.getCopyFromReg(SDValue(Res, 0), DL, X86::EAX, MVT::i32, SDValue(Res, 1)); + SDValue B = DAG.getCopyFromReg(A.getValue(1), DL, ArgReg1, ArgVT, A.getValue(2)); + SDValue C = DAG.getCopyFromReg(B.getValue(1), DL, ArgReg2, ArgVT, B.getValue(2)); + SDValue D = DAG.getCopyFromReg(C.getValue(1), DL, ArgReg3, ArgVT, C.getValue(2)); + + return DAG.getMergeValues({A, B, C, D, SDValue(Res, 0)}, DL); +} + /// Handles the lowering of builtin intrinsic that return the value /// of the extended control register. static void getExtendedControlRegister(SDNode *N, const SDLoc &DL, @@ -21425,6 +21451,18 @@ return DAG.getNode(ISD::MERGE_VALUES, dl, Op->getVTList(), Result, Operation.getValue(1)); } + case Intrinsic::x86_pconfig_32: + case Intrinsic::x86_pconfig_64: + return getInstrWFourImplicitOps(Op, DAG, Subtarget, X86::PCONFIG); + case Intrinsic::x86_encls_32: + case Intrinsic::x86_encls_64: + return getInstrWFourImplicitOps(Op, DAG, Subtarget, X86::ENCLS); + case Intrinsic::x86_enclu_32: + case Intrinsic::x86_enclu_64: + return getInstrWFourImplicitOps(Op, DAG, Subtarget, X86::ENCLU); + case Intrinsic::x86_enclv_32: + case Intrinsic::x86_enclv_64: + return getInstrWFourImplicitOps(Op, DAG, Subtarget, X86::ENCLV); } return SDValue(); } Index: lib/Target/X86/X86InstrInfo.td =================================================================== --- lib/Target/X86/X86InstrInfo.td +++ lib/Target/X86/X86InstrInfo.td @@ -882,6 +882,7 @@ def HasRTM : Predicate<"Subtarget->hasRTM()">; def HasADX : Predicate<"Subtarget->hasADX()">; def HasSHA : Predicate<"Subtarget->hasSHA()">; +def HasSGX : Predicate<"Subtarget->hasSGX()">; def HasPRFCHW : Predicate<"Subtarget->hasPRFCHW()">; def HasRDSEED : Predicate<"Subtarget->hasRDSEED()">; def HasSSEPrefetch : Predicate<"Subtarget->hasSSEPrefetch()">; @@ -903,6 +904,7 @@ def HasRDPID : Predicate<"Subtarget->hasRDPID()">; def HasWAITPKG : Predicate<"Subtarget->hasWAITPKG()">; def HasCmpxchg16b: Predicate<"Subtarget->hasCmpxchg16b()">; +def HasPCONFIG : Predicate<"Subtarget->hasPCONFIG()">; def Not64BitMode : Predicate<"!Subtarget->is64Bit()">, AssemblerPredicate<"!Mode64Bit", "Not 64-bit mode">; def In64BitMode : Predicate<"Subtarget->is64Bit()">, Index: lib/Target/X86/X86InstrSGX.td =================================================================== --- lib/Target/X86/X86InstrSGX.td +++ lib/Target/X86/X86InstrSGX.td @@ -15,7 +15,7 @@ //===----------------------------------------------------------------------===// // SGX instructions -let SchedRW = [WriteSystem] in { +let SchedRW = [WriteSystem], Predicates = [HasSGX] in { // ENCLS - Execute an Enclave System Function of Specified Leaf Number def ENCLS : I<0x01, MRM_CF, (outs), (ins), "encls", []>, TB; @@ -23,4 +23,8 @@ // ENCLU - Execute an Enclave User Function of Specified Leaf Number def ENCLU : I<0x01, MRM_D7, (outs), (ins), "enclu", []>, TB; + +// ENCLV - Execute an Enclave VMM Function of Specified Leaf Number +def ENCLV : I<0x01, MRM_C0, (outs), (ins), + "enclv", []>, TB; } // SchedRW Index: lib/Target/X86/X86InstrSystem.td =================================================================== --- lib/Target/X86/X86InstrSystem.td +++ lib/Target/X86/X86InstrSystem.td @@ -704,3 +704,20 @@ def PTWRITE64r : RI<0xAE, MRM4r, (outs), (ins GR64:$dst), "ptwrite{q}\t$dst", []>, XS, Requires<[In64BitMode]>; } // SchedRW + +//===----------------------------------------------------------------------===// +// Platform Configuration instruction + +// From ISA docs: +// "This instruction is used to execute functions for configuring platform +// features. +// EAX: Leaf function to be invoked. +// RBX/RCX/RDX: Leaf-specific purpose." +// "Successful execution of the leaf clears RAX (set to zero) and ZF, CF, PF, +// AF, OF, and SF are cleared. In case of failure, the failure reason is +// indicated in RAX with ZF set to 1 and CF, PF, AF, OF, and SF are cleared." +// Thus all these mentioned registers are considered clobbered. + +let Uses = [RAX, RBX, RCX, RDX], Defs = [RAX, RBX, RCX, RDX, EFLAGS] in + def PCONFIG : I<0x01, MRM_C5, (outs), (ins), "pconfig", []>, TB, + Requires<[HasPCONFIG]>; Index: lib/Target/X86/X86Subtarget.h =================================================================== --- lib/Target/X86/X86Subtarget.h +++ lib/Target/X86/X86Subtarget.h @@ -373,6 +373,9 @@ /// Processor supports WaitPKG instructions bool HasWAITPKG; + /// Processor supports PCONFIG instruction + bool HasPCONFIG; + /// Use a retpoline thunk rather than indirect calls to block speculative /// execution. bool UseRetpoline; @@ -632,6 +635,8 @@ bool hasWBNOINVD() const { return HasWBNOINVD; } bool hasRDPID() const { return HasRDPID; } bool hasWAITPKG() const { return HasWAITPKG; } + bool hasPCONFIG() const { return HasPCONFIG; } + bool hasSGX() const { return HasSGX; } bool useRetpoline() const { return UseRetpoline; } bool useRetpolineExternalThunk() const { return UseRetpolineExternalThunk; } Index: lib/Target/X86/X86Subtarget.cpp =================================================================== --- lib/Target/X86/X86Subtarget.cpp +++ lib/Target/X86/X86Subtarget.cpp @@ -321,6 +321,7 @@ HasSHSTK = false; HasIBT = false; HasSGX = false; + HasPCONFIG = false; HasCLFLUSHOPT = false; HasCLWB = false; HasWBNOINVD = false; Index: test/CodeGen/X86/SGX32-intrinsics.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/SGX32-intrinsics.ll @@ -0,0 +1,131 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple=i686-unknown-unknown -mattr=+sgx | FileCheck %s + +; Function Attrs: nounwind +define i32 @test_encls(i32 %leaf, i32* nocapture %d) local_unnamed_addr #0 { +; CHECK-LABEL: test_encls: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: pushl %ebx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: pushl %esi +; CHECK-NEXT: .cfi_def_cfa_offset 12 +; CHECK-NEXT: .cfi_offset %esi, -12 +; CHECK-NEXT: .cfi_offset %ebx, -8 +; CHECK-NEXT: movl {{[0-9]+}}(%esp), %eax +; CHECK-NEXT: movl {{[0-9]+}}(%esp), %esi +; CHECK-NEXT: movl (%esi), %ebx +; CHECK-NEXT: movl 4(%esi), %ecx +; CHECK-NEXT: movl 8(%esi), %edx +; CHECK-NEXT: encls +; CHECK-NEXT: movl %ebx, (%esi) +; CHECK-NEXT: movl %ecx, 4(%esi) +; CHECK-NEXT: movl %edx, 8(%esi) +; CHECK-NEXT: popl %esi +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: popl %ebx +; CHECK-NEXT: .cfi_def_cfa_offset 4 +; CHECK-NEXT: retl +entry: + %add.ptr.i = getelementptr inbounds i32, i32* %d, i32 1 + %add.ptr1.i = getelementptr inbounds i32, i32* %d, i32 2 + %0 = load i32, i32* %d, align 4 + %1 = load i32, i32* %add.ptr.i, align 4 + %2 = load i32, i32* %add.ptr1.i, align 4 + %3 = tail call { i32, i32, i32, i32 } @llvm.x86.encls.32(i32 %leaf, i32 %0, i32 %1, i32 %2) #1 + %4 = extractvalue { i32, i32, i32, i32 } %3, 1 + store i32 %4, i32* %d, align 4 + %5 = extractvalue { i32, i32, i32, i32 } %3, 2 + store i32 %5, i32* %add.ptr.i, align 4 + %6 = extractvalue { i32, i32, i32, i32 } %3, 3 + store i32 %6, i32* %add.ptr1.i, align 4 + %7 = extractvalue { i32, i32, i32, i32 } %3, 0 + ret i32 %7 +} + +declare { i32, i32, i32, i32 } @llvm.x86.encls.32(i32, i32, i32, i32) #1 + +; Function Attrs: nounwind +define i32 @test_enclu(i32 %leaf, i32* nocapture %d) local_unnamed_addr #0 { +; CHECK-LABEL: test_enclu: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: pushl %ebx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: pushl %esi +; CHECK-NEXT: .cfi_def_cfa_offset 12 +; CHECK-NEXT: .cfi_offset %esi, -12 +; CHECK-NEXT: .cfi_offset %ebx, -8 +; CHECK-NEXT: movl {{[0-9]+}}(%esp), %eax +; CHECK-NEXT: movl {{[0-9]+}}(%esp), %esi +; CHECK-NEXT: movl (%esi), %ebx +; CHECK-NEXT: movl 4(%esi), %ecx +; CHECK-NEXT: movl 8(%esi), %edx +; CHECK-NEXT: enclu +; CHECK-NEXT: movl %ebx, (%esi) +; CHECK-NEXT: movl %ecx, 4(%esi) +; CHECK-NEXT: movl %edx, 8(%esi) +; CHECK-NEXT: popl %esi +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: popl %ebx +; CHECK-NEXT: .cfi_def_cfa_offset 4 +; CHECK-NEXT: retl +entry: + %add.ptr.i = getelementptr inbounds i32, i32* %d, i32 1 + %add.ptr1.i = getelementptr inbounds i32, i32* %d, i32 2 + %0 = load i32, i32* %d, align 4 + %1 = load i32, i32* %add.ptr.i, align 4 + %2 = load i32, i32* %add.ptr1.i, align 4 + %3 = tail call { i32, i32, i32, i32 } @llvm.x86.enclu.32(i32 %leaf, i32 %0, i32 %1, i32 %2) #1 + %4 = extractvalue { i32, i32, i32, i32 } %3, 1 + store i32 %4, i32* %d, align 4 + %5 = extractvalue { i32, i32, i32, i32 } %3, 2 + store i32 %5, i32* %add.ptr.i, align 4 + %6 = extractvalue { i32, i32, i32, i32 } %3, 3 + store i32 %6, i32* %add.ptr1.i, align 4 + %7 = extractvalue { i32, i32, i32, i32 } %3, 0 + ret i32 %7 +} + +declare { i32, i32, i32, i32 } @llvm.x86.enclu.32(i32, i32, i32, i32) #1 + +; Function Attrs: nounwind +define i32 @test_enclv(i32 %leaf, i32* nocapture %d) local_unnamed_addr #0 { +; CHECK-LABEL: test_enclv: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: pushl %ebx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: pushl %esi +; CHECK-NEXT: .cfi_def_cfa_offset 12 +; CHECK-NEXT: .cfi_offset %esi, -12 +; CHECK-NEXT: .cfi_offset %ebx, -8 +; CHECK-NEXT: movl {{[0-9]+}}(%esp), %eax +; CHECK-NEXT: movl {{[0-9]+}}(%esp), %esi +; CHECK-NEXT: movl (%esi), %ebx +; CHECK-NEXT: movl 4(%esi), %ecx +; CHECK-NEXT: movl 8(%esi), %edx +; CHECK-NEXT: enclv +; CHECK-NEXT: movl %ebx, (%esi) +; CHECK-NEXT: movl %ecx, 4(%esi) +; CHECK-NEXT: movl %edx, 8(%esi) +; CHECK-NEXT: popl %esi +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: popl %ebx +; CHECK-NEXT: .cfi_def_cfa_offset 4 +; CHECK-NEXT: retl +entry: + %add.ptr.i = getelementptr inbounds i32, i32* %d, i32 1 + %add.ptr1.i = getelementptr inbounds i32, i32* %d, i32 2 + %0 = load i32, i32* %d, align 4 + %1 = load i32, i32* %add.ptr.i, align 4 + %2 = load i32, i32* %add.ptr1.i, align 4 + %3 = tail call { i32, i32, i32, i32 } @llvm.x86.enclv.32(i32 %leaf, i32 %0, i32 %1, i32 %2) #1 + %4 = extractvalue { i32, i32, i32, i32 } %3, 1 + store i32 %4, i32* %d, align 4 + %5 = extractvalue { i32, i32, i32, i32 } %3, 2 + store i32 %5, i32* %add.ptr.i, align 4 + %6 = extractvalue { i32, i32, i32, i32 } %3, 3 + store i32 %6, i32* %add.ptr1.i, align 4 + %7 = extractvalue { i32, i32, i32, i32 } %3, 0 + ret i32 %7 +} + +declare { i32, i32, i32, i32 } @llvm.x86.enclv.32(i32, i32, i32, i32) #1 Index: test/CodeGen/X86/SGX64-intrinsics.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/SGX64-intrinsics.ll @@ -0,0 +1,109 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+sgx | FileCheck %s + +define i32 @test_encls(i32 %leaf, i64* nocapture %arguments) local_unnamed_addr #0 { +; CHECK-LABEL: test_encls: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: pushq %rbx +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset %rbx, -16 +; CHECK-NEXT: movq (%rsi), %rbx +; CHECK-NEXT: movq 8(%rsi), %rcx +; CHECK-NEXT: movq 16(%rsi), %rdx +; CHECK-NEXT: encls +; CHECK-NEXT: movq %rbx, (%rsi) +; CHECK-NEXT: movq %rcx, 8(%rsi) +; CHECK-NEXT: movq %rdx, 16(%rsi) +; CHECK-NEXT: movl %edi, %eax +; CHECK-NEXT: popq %rbx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq +entry: + %add.ptr.i = getelementptr inbounds i64, i64* %arguments, i64 1 + %add.ptr1.i = getelementptr inbounds i64, i64* %arguments, i64 2 + %0 = load i64, i64* %arguments, align 8 + %1 = load i64, i64* %add.ptr.i, align 8 + %2 = load i64, i64* %add.ptr1.i, align 8 + %3 = tail call { i32, i64, i64, i64 } @llvm.x86.encls.64(i32 %leaf, i64 %0, i64 %1, i64 %2) #1 + %4 = extractvalue { i32, i64, i64, i64 } %3, 1 + store i64 %4, i64* %arguments, align 8 + %5 = extractvalue { i32, i64, i64, i64 } %3, 2 + store i64 %5, i64* %add.ptr.i, align 8 + %6 = extractvalue { i32, i64, i64, i64 } %3, 3 + store i64 %6, i64* %add.ptr1.i, align 8 + %7 = extractvalue { i32, i64, i64, i64 } %3, 0 + ret i32 %7 +} + +; Function Attrs: nounwind +define i32 @test_enclu(i32 %leaf, i64* nocapture %arguments) local_unnamed_addr #0 { +; CHECK-LABEL: test_enclu: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: pushq %rbx +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset %rbx, -16 +; CHECK-NEXT: movq (%rsi), %rbx +; CHECK-NEXT: movq 8(%rsi), %rcx +; CHECK-NEXT: movq 16(%rsi), %rdx +; CHECK-NEXT: enclu +; CHECK-NEXT: movq %rbx, (%rsi) +; CHECK-NEXT: movq %rcx, 8(%rsi) +; CHECK-NEXT: movq %rdx, 16(%rsi) +; CHECK-NEXT: movl %edi, %eax +; CHECK-NEXT: popq %rbx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq +entry: + %add.ptr.i = getelementptr inbounds i64, i64* %arguments, i64 1 + %add.ptr1.i = getelementptr inbounds i64, i64* %arguments, i64 2 + %0 = load i64, i64* %arguments, align 8 + %1 = load i64, i64* %add.ptr.i, align 8 + %2 = load i64, i64* %add.ptr1.i, align 8 + %3 = tail call { i32, i64, i64, i64 } @llvm.x86.enclu.64(i32 %leaf, i64 %0, i64 %1, i64 %2) #1 + %4 = extractvalue { i32, i64, i64, i64 } %3, 1 + store i64 %4, i64* %arguments, align 8 + %5 = extractvalue { i32, i64, i64, i64 } %3, 2 + store i64 %5, i64* %add.ptr.i, align 8 + %6 = extractvalue { i32, i64, i64, i64 } %3, 3 + store i64 %6, i64* %add.ptr1.i, align 8 + %7 = extractvalue { i32, i64, i64, i64 } %3, 0 + ret i32 %7 +} + +define i32 @test_enclv(i32 %leaf, i64* nocapture %arguments) local_unnamed_addr #0 { +; CHECK-LABEL: test_enclv: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: pushq %rbx +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset %rbx, -16 +; CHECK-NEXT: movq (%rsi), %rbx +; CHECK-NEXT: movq 8(%rsi), %rcx +; CHECK-NEXT: movq 16(%rsi), %rdx +; CHECK-NEXT: enclv +; CHECK-NEXT: movq %rbx, (%rsi) +; CHECK-NEXT: movq %rcx, 8(%rsi) +; CHECK-NEXT: movq %rdx, 16(%rsi) +; CHECK-NEXT: movl %edi, %eax +; CHECK-NEXT: popq %rbx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq +entry: + %add.ptr.i = getelementptr inbounds i64, i64* %arguments, i64 1 + %add.ptr1.i = getelementptr inbounds i64, i64* %arguments, i64 2 + %0 = load i64, i64* %arguments, align 8 + %1 = load i64, i64* %add.ptr.i, align 8 + %2 = load i64, i64* %add.ptr1.i, align 8 + %3 = tail call { i32, i64, i64, i64 } @llvm.x86.enclv.64(i32 %leaf, i64 %0, i64 %1, i64 %2) #1 + %4 = extractvalue { i32, i64, i64, i64 } %3, 1 + store i64 %4, i64* %arguments, align 8 + %5 = extractvalue { i32, i64, i64, i64 } %3, 2 + store i64 %5, i64* %add.ptr.i, align 8 + %6 = extractvalue { i32, i64, i64, i64 } %3, 3 + store i64 %6, i64* %add.ptr1.i, align 8 + %7 = extractvalue { i32, i64, i64, i64 } %3, 0 + ret i32 %7 +} + +declare { i32, i64, i64, i64 } @llvm.x86.encls.64(i32, i64, i64, i64) #1 +declare { i32, i64, i64, i64 } @llvm.x86.enclu.64(i32, i64, i64, i64) #1 +declare { i32, i64, i64, i64 } @llvm.x86.enclv.64(i32, i64, i64, i64) #1 Index: test/CodeGen/X86/pconfig32-intrinsic.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/pconfig32-intrinsic.ll @@ -0,0 +1,50 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple=i686-unknown-unknown -mattr=+pconfig | FileCheck %s + +; Function Attrs: nounwind +define i32 @test_pconfig(i32 %leaf, i32* nocapture %d) local_unnamed_addr #0 { +; CHECK-LABEL: test_pconfig: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: pushl %ebx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: pushl %esi +; CHECK-NEXT: .cfi_def_cfa_offset 12 +; CHECK-NEXT: .cfi_offset %esi, -12 +; CHECK-NEXT: .cfi_offset %ebx, -8 +; CHECK-NEXT: movl {{[0-9]+}}(%esp), %eax +; CHECK-NEXT: movl {{[0-9]+}}(%esp), %esi +; CHECK-NEXT: movl (%esi), %ebx +; CHECK-NEXT: movl 4(%esi), %ecx +; CHECK-NEXT: movl 8(%esi), %edx +; CHECK-NEXT: # kill: def $eax killed $eax def $rax +; CHECK-NEXT: # kill: def $ebx killed $ebx def $rbx +; CHECK-NEXT: # kill: def $ecx killed $ecx def $rcx +; CHECK-NEXT: # kill: def $edx killed $edx def $rdx +; CHECK-NEXT: pconfig +; CHECK-NEXT: movl %ebx, (%esi) +; CHECK-NEXT: movl %ecx, 4(%esi) +; CHECK-NEXT: movl %edx, 8(%esi) +; CHECK-NEXT: popl %esi +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: popl %ebx +; CHECK-NEXT: .cfi_def_cfa_offset 4 +; CHECK-NEXT: retl +entry: + %add.ptr.i = getelementptr inbounds i32, i32* %d, i32 1 + %add.ptr1.i = getelementptr inbounds i32, i32* %d, i32 2 + %0 = load i32, i32* %d, align 4 + %1 = load i32, i32* %add.ptr.i, align 4 + %2 = load i32, i32* %add.ptr1.i, align 4 + %3 = tail call { i32, i32, i32, i32 } @llvm.x86.pconfig.32(i32 %leaf, i32 %0, i32 %1, i32 %2) #1 + %4 = extractvalue { i32, i32, i32, i32 } %3, 1 + store i32 %4, i32* %d, align 4 + %5 = extractvalue { i32, i32, i32, i32 } %3, 2 + store i32 %5, i32* %add.ptr.i, align 4 + %6 = extractvalue { i32, i32, i32, i32 } %3, 3 + store i32 %6, i32* %add.ptr1.i, align 4 + %7 = extractvalue { i32, i32, i32, i32 } %3, 0 + ret i32 %7 +} + +; Function Attrs: nounwind +declare { i32, i32, i32, i32 } @llvm.x86.pconfig.32(i32, i32, i32, i32) #1 Index: test/CodeGen/X86/pconfig64-intrinsic.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/pconfig64-intrinsic.ll @@ -0,0 +1,40 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+pconfig | FileCheck %s + +; Function Attrs: nounwind +define i32 @test_pconfig(i32 %leaf, i64* nocapture %d) local_unnamed_addr #0 { +; CHECK-LABEL: test_pconfig: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: pushq %rbx +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset %rbx, -16 +; CHECK-NEXT: movq (%rsi), %rbx +; CHECK-NEXT: movq 8(%rsi), %rcx +; CHECK-NEXT: movq 16(%rsi), %rdx +; CHECK-NEXT: movl %edi, %eax +; CHECK-NEXT: pconfig +; CHECK-NEXT: movq %rbx, (%rsi) +; CHECK-NEXT: movq %rcx, 8(%rsi) +; CHECK-NEXT: movq %rdx, 16(%rsi) +; CHECK-NEXT: popq %rbx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq +entry: + %add.ptr.i = getelementptr inbounds i64, i64* %d, i64 1 + %add.ptr1.i = getelementptr inbounds i64, i64* %d, i64 2 + %0 = load i64, i64* %d, align 8 + %1 = load i64, i64* %add.ptr.i, align 8 + %2 = load i64, i64* %add.ptr1.i, align 8 + %3 = tail call { i32, i64, i64, i64 } @llvm.x86.pconfig.64(i32 %leaf, i64 %0, i64 %1, i64 %2) #1 + %4 = extractvalue { i32, i64, i64, i64 } %3, 1 + store i64 %4, i64* %d, align 8 + %5 = extractvalue { i32, i64, i64, i64 } %3, 2 + store i64 %5, i64* %add.ptr.i, align 8 + %6 = extractvalue { i32, i64, i64, i64 } %3, 3 + store i64 %6, i64* %add.ptr1.i, align 8 + %7 = extractvalue { i32, i64, i64, i64 } %3, 0 + ret i32 %7 +} + +; Function Attrs: nounwind +declare { i32, i64, i64, i64 } @llvm.x86.pconfig.64(i32, i64, i64, i64) #1 Index: test/MC/X86/sgx-encoding.s =================================================================== --- test/MC/X86/sgx-encoding.s +++ test/MC/X86/sgx-encoding.s @@ -7,3 +7,7 @@ // CHECK: enclu // CHECK: encoding: [0x0f,0x01,0xd7] enclu + +// CHECK: enclv +// CHECK: encoding: [0x0f,0x01,0xc0] + enclv Index: test/MC/X86/x86-32-coverage.s =================================================================== --- test/MC/X86/x86-32-coverage.s +++ test/MC/X86/x86-32-coverage.s @@ -10768,3 +10768,7 @@ // CHECK: tpause %eax // CHECK: encoding: [0x66,0x0f,0xae,0xf0] tpause %eax + +// CHECK: pconfig +// CHECK: encoding: [0x0f,0x01,0xc5] + pconfig Index: test/MC/X86/x86-64.s =================================================================== --- test/MC/X86/x86-64.s +++ test/MC/X86/x86-64.s @@ -1599,6 +1599,10 @@ // CHECK: encoding: [0x66,0x0f,0xae,0xf3] tpause %ebx +// CHECK: pconfig +// CHECK: encoding: [0x0f,0x01,0xc5] +pconfig + // __asm __volatile( // "pushf \n\t" // "popf \n\t"