Index: include/llvm/IR/IntrinsicsX86.td =================================================================== --- include/llvm/IR/IntrinsicsX86.td +++ include/llvm/IR/IntrinsicsX86.td @@ -3553,6 +3553,35 @@ } //===----------------------------------------------------------------------===// +// XSAVE +let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". + def int_x86_xsave : + Intrinsic<[], [llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty], []>; + def int_x86_xsave64 : + Intrinsic<[], [llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty], []>; + def int_x86_xrstor : + Intrinsic<[], [llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty], []>; + def int_x86_xrstor64 : + Intrinsic<[], [llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty], []>; + def int_x86_xsaveopt : + Intrinsic<[], [llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty], []>; + def int_x86_xsaveopt64 : + Intrinsic<[], [llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty], []>; + def int_x86_xrstors : + Intrinsic<[], [llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty], []>; + def int_x86_xrstors64 : + Intrinsic<[], [llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty], []>; + def int_x86_xsavec : + Intrinsic<[], [llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty], []>; + def int_x86_xsavec64 : + Intrinsic<[], [llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty], []>; + def int_x86_xsaves : + Intrinsic<[], [llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty], []>; + def int_x86_xsaves64 : + Intrinsic<[], [llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty], []>; +} + +//===----------------------------------------------------------------------===// // Half float conversion let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". Index: lib/Support/Host.cpp =================================================================== --- lib/Support/Host.cpp +++ lib/Support/Host.cpp @@ -769,6 +769,7 @@ Features["movbe"] = (ECX >> 22) & 1; Features["popcnt"] = (ECX >> 23) & 1; Features["aes"] = (ECX >> 25) & 1; + Features["xsave"] = (ECX >> 26) & 1; Features["rdrnd"] = (ECX >> 30) & 1; // If CPUID indicates support for XSAVE, XRESTORE and AVX, and XGETBV @@ -819,6 +820,14 @@ Features["avx512bw"] = HasLeaf7 && ((EBX >> 30) & 1) && HasAVX512Save; Features["avx512vl"] = HasLeaf7 && ((EBX >> 31) & 1) && HasAVX512Save; + + bool HasLeafD = MaxLevel >= 0xd && + !GetX86CpuIDAndInfoEx(0xd, 0x1, &EAX, &EBX, &ECX, &EDX); + + Features["xsaveopt"] = Features["xsave"] && HasLeafD && ((EAX >> 0) & 1); + Features["xsavec"] = Features["xsave"] && HasLeafD && ((EAX >> 1) & 1); + Features["xsaves"] = Features["xsave"] && HasLeafD && ((EAX >> 3) & 1); + return true; } #elif defined(__linux__) && (defined(__arm__) || defined(__aarch64__)) Index: lib/Target/X86/X86.td =================================================================== --- lib/Target/X86/X86.td +++ lib/Target/X86/X86.td @@ -37,6 +37,17 @@ def FeaturePOPCNT : SubtargetFeature<"popcnt", "HasPOPCNT", "true", "Support POPCNT instruction">; +def FeatureXSAVE : SubtargetFeature<"xsave", "HasXSAVE", "true", + "Support xsave instructions">; + +def FeatureXSAVEOPT: SubtargetFeature<"xsaveopt", "HasXSAVEOPT", "true", + "Support xsaveopt instructions">; + +def FeatureXSAVEC : SubtargetFeature<"xsavec", "HasXSAVEC", "true", + "Support xsavec instructions">; + +def FeatureXSAVES : SubtargetFeature<"xsaves", "HasXSAVES", "true", + "Support xsaves instructions">; def FeatureMMX : SubtargetFeature<"mmx","X86SSELevel", "MMX", "Enable MMX instructions">; Index: lib/Target/X86/X86InstrInfo.td =================================================================== --- lib/Target/X86/X86InstrInfo.td +++ lib/Target/X86/X86InstrInfo.td @@ -772,6 +772,10 @@ def HasPOPCNT : Predicate<"Subtarget->hasPOPCNT()">; def HasAES : Predicate<"Subtarget->hasAES()">; +def HasXSAVE : Predicate<"Subtarget->hasXSAVE()">; +def HasXSAVEOPT : Predicate<"Subtarget->hasXSAVEOPT()">; +def HasXSAVEC : Predicate<"Subtarget->hasXSAVEC()">; +def HasXSAVES : Predicate<"Subtarget->hasXSAVES()">; def HasPCLMUL : Predicate<"Subtarget->hasPCLMUL()">; def HasFMA : Predicate<"Subtarget->hasFMA()">; def UseFMAOnAVX : Predicate<"Subtarget->hasFMA() && !Subtarget->hasAVX512()">; @@ -2634,7 +2638,9 @@ def : MnemonicAlias<"xsaveq", "xsave64", "att">; def : MnemonicAlias<"xrstorq", "xrstor64", "att">; def : MnemonicAlias<"xsaveoptq", "xsaveopt64", "att">; - +def : MnemonicAlias<"xrstorsq", "xrstors64", "att">; +def : MnemonicAlias<"xsavecq", "xsavec64", "att">; +def : MnemonicAlias<"xsavesq", "xsaves64", "att">; class CondCodeAlias Index: lib/Target/X86/X86InstrSystem.td =================================================================== --- lib/Target/X86/X86InstrSystem.td +++ lib/Target/X86/X86InstrSystem.td @@ -478,39 +478,60 @@ //===----------------------------------------------------------------------===// // XSAVE instructions let SchedRW = [WriteSystem] in { +let Predicates = [HasXSAVE] in { let Defs = [EDX, EAX], Uses = [ECX] in def XGETBV : I<0x01, MRM_D0, (outs), (ins), "xgetbv", []>, TB; let Uses = [EDX, EAX, ECX] in def XSETBV : I<0x01, MRM_D1, (outs), (ins), "xsetbv", []>, TB; +} -let Uses = [RDX, RAX] in { - def XSAVE : I<0xAE, MRM4m, (outs opaque512mem:$dst), (ins), - "xsave\t$dst", []>, TB; - def XSAVE64 : RI<0xAE, MRM4m, (outs opaque512mem:$dst), (ins), - "xsave64\t$dst", []>, TB, Requires<[In64BitMode]>; +let Uses = [EDX, EAX] in { +let Predicates = [HasXSAVE] in { + def XSAVE : I<0xAE, MRM4m, (outs), (ins opaque512mem:$dst), + "xsave\t$dst", + [(int_x86_xsave addr:$dst, EDX, EAX)]>, TB; + def XSAVE64 : RI<0xAE, MRM4m, (outs), (ins opaque512mem:$dst), + "xsave64\t$dst", + [(int_x86_xsave64 addr:$dst, EDX, EAX)]>, TB, Requires<[In64BitMode]>; def XRSTOR : I<0xAE, MRM5m, (outs), (ins opaque512mem:$dst), - "xrstor\t$dst", []>, TB; + "xrstor\t$dst", + [(int_x86_xrstor addr:$dst, EDX, EAX)]>, TB; def XRSTOR64 : RI<0xAE, MRM5m, (outs), (ins opaque512mem:$dst), - "xrstor64\t$dst", []>, TB, Requires<[In64BitMode]>; - def XSAVEOPT : I<0xAE, MRM6m, (outs opaque512mem:$dst), (ins), - "xsaveopt\t$dst", []>, PS; - def XSAVEOPT64 : RI<0xAE, MRM6m, (outs opaque512mem:$dst), (ins), - "xsaveopt64\t$dst", []>, PS, Requires<[In64BitMode]>; - + "xrstor64\t$dst", + [(int_x86_xrstor64 addr:$dst, EDX, EAX)]>, TB, Requires<[In64BitMode]>; +} +let Predicates = [HasXSAVEOPT] in { + def XSAVEOPT : I<0xAE, MRM6m, (outs), (ins opaque512mem:$dst), + "xsaveopt\t$dst", + [(int_x86_xsaveopt addr:$dst, EDX, EAX)]>, TB; + def XSAVEOPT64 : RI<0xAE, MRM6m, (outs), (ins opaque512mem:$dst), + "xsaveopt64\t$dst", + [(int_x86_xsaveopt64 addr:$dst, EDX, EAX)]>, TB, Requires<[In64BitMode]>; +} +let Predicates = [HasXSAVEC] in { + def XSAVEC : I<0xC7, MRM4m, (outs), (ins opaque512mem:$dst), + "xsavec\t$dst", + [(int_x86_xsavec addr:$dst, EDX, EAX)]>, TB; + def XSAVEC64 : RI<0xC7, MRM4m, (outs), (ins opaque512mem:$dst), + "xsavec64\t$dst", + [(int_x86_xsavec64 addr:$dst, EDX, EAX)]>, TB, Requires<[In64BitMode]>; +} +let Predicates = [HasXSAVES] in { + def XSAVES : I<0xC7, MRM5m, (outs), (ins opaque512mem:$dst), + "xsaves\t$dst", + [(int_x86_xsaves addr:$dst, EDX, EAX)]>, TB; + def XSAVES64 : RI<0xC7, MRM5m, (outs), (ins opaque512mem:$dst), + "xsaves64\t$dst", + [(int_x86_xsaves64 addr:$dst, EDX, EAX)]>, TB, Requires<[In64BitMode]>; def XRSTORS : I<0xC7, MRM3m, (outs), (ins opaque512mem:$dst), - "xrstors\t$dst", []>, TB; + "xrstors\t$dst", + [(int_x86_xrstors addr:$dst, EDX, EAX)]>, TB; def XRSTORS64 : RI<0xC7, MRM3m, (outs), (ins opaque512mem:$dst), - "xrstors64\t$dst", []>, TB, Requires<[In64BitMode]>; - def XSAVEC : I<0xC7, MRM4m, (outs opaque512mem:$dst), (ins), - "xsavec\t$dst", []>, TB; - def XSAVEC64 : RI<0xC7, MRM4m, (outs opaque512mem:$dst), (ins), - "xsavec64\t$dst", []>, TB, Requires<[In64BitMode]>; - def XSAVES : I<0xC7, MRM5m, (outs opaque512mem:$dst), (ins), - "xsaves\t$dst", []>, TB; - def XSAVES64 : RI<0xC7, MRM5m, (outs opaque512mem:$dst), (ins), - "xsaves64\t$dst", []>, TB, Requires<[In64BitMode]>; + "xrstors64\t$dst", + [(int_x86_xrstors64 addr:$dst, EDX, EAX)]>, TB, Requires<[In64BitMode]>; } +} // Uses } // SchedRW //===----------------------------------------------------------------------===// Index: lib/Target/X86/X86Subtarget.h =================================================================== --- lib/Target/X86/X86Subtarget.h +++ lib/Target/X86/X86Subtarget.h @@ -86,6 +86,15 @@ /// Target has AES instructions bool HasAES; + /// Target has XSAVE instructions + bool HasXSAVE; + /// Target has XSAVEOPT instructions + bool HasXSAVEOPT; + /// Target has XSAVEC instructions + bool HasXSAVEC; + /// Target has XSAVES instructions + bool HasXSAVES; + /// Target has carry-less multiplication bool HasPCLMUL; @@ -336,6 +345,10 @@ bool has3DNowA() const { return X863DNowLevel >= ThreeDNowA; } bool hasPOPCNT() const { return HasPOPCNT; } bool hasAES() const { return HasAES; } + bool hasXSAVE() const { return HasXSAVE; } + bool hasXSAVEOPT() const { return HasXSAVEOPT; } + bool hasXSAVEC() const { return HasXSAVEC; } + bool hasXSAVES() const { return HasXSAVES; } bool hasPCLMUL() const { return HasPCLMUL; } bool hasFMA() const { return HasFMA; } // FIXME: Favor FMA when both are enabled. Is this the right thing to do? Index: test/CodeGen/X86/system-intrinsics-64-xsave.ll =================================================================== --- test/CodeGen/X86/system-intrinsics-64-xsave.ll +++ test/CodeGen/X86/system-intrinsics-64-xsave.ll @@ -0,0 +1,41 @@ +; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+xsave | FileCheck %s + +define void @test_xsave(i8* %ptr, i32 %hi, i32 %lo) { +; CHECK-LABEL: test_xsave +; CHECK: movl %edx, %eax +; CHECK: movl %esi, %edx +; CHECK: xsave (%rdi) + call void @llvm.x86.xsave(i8* %ptr, i32 %hi, i32 %lo) + ret void; +} +declare void @llvm.x86.xsave(i8*, i32, i32) + +define void @test_xsave64(i8* %ptr, i32 %hi, i32 %lo) { +; CHECK-LABEL: test_xsave64 +; CHECK: movl %edx, %eax +; CHECK: movl %esi, %edx +; CHECK: xsave64 (%rdi) + call void @llvm.x86.xsave64(i8* %ptr, i32 %hi, i32 %lo) + ret void; +} +declare void @llvm.x86.xsave64(i8*, i32, i32) + +define void @test_xrstor(i8* %ptr, i32 %hi, i32 %lo) { +; CHECK-LABEL: test_xrstor +; CHECK: movl %edx, %eax +; CHECK: movl %esi, %edx +; CHECK: xrstor (%rdi) + call void @llvm.x86.xrstor(i8* %ptr, i32 %hi, i32 %lo) + ret void; +} +declare void @llvm.x86.xrstor(i8*, i32, i32) + +define void @test_xrstor64(i8* %ptr, i32 %hi, i32 %lo) { +; CHECK-LABEL: test_xrstor64 +; CHECK: movl %edx, %eax +; CHECK: movl %esi, %edx +; CHECK: xrstor64 (%rdi) + call void @llvm.x86.xrstor64(i8* %ptr, i32 %hi, i32 %lo) + ret void; +} +declare void @llvm.x86.xrstor64(i8*, i32, i32) Index: test/CodeGen/X86/system-intrinsics-64-xsavec.ll =================================================================== --- test/CodeGen/X86/system-intrinsics-64-xsavec.ll +++ test/CodeGen/X86/system-intrinsics-64-xsavec.ll @@ -0,0 +1,21 @@ +; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+xsave,+xsavec | FileCheck %s + +define void @test_xsavec(i8* %ptr, i32 %hi, i32 %lo) { +; CHECK-LABEL: test_xsavec +; CHECK: movl %edx, %eax +; CHECK: movl %esi, %edx +; CHECK: xsavec (%rdi) + call void @llvm.x86.xsavec(i8* %ptr, i32 %hi, i32 %lo) + ret void; +} +declare void @llvm.x86.xsavec(i8*, i32, i32) + +define void @test_xsavec64(i8* %ptr, i32 %hi, i32 %lo) { +; CHECK-LABEL: test_xsavec64 +; CHECK: movl %edx, %eax +; CHECK: movl %esi, %edx +; CHECK: xsavec64 (%rdi) + call void @llvm.x86.xsavec64(i8* %ptr, i32 %hi, i32 %lo) + ret void; +} +declare void @llvm.x86.xsavec64(i8*, i32, i32) Index: test/CodeGen/X86/system-intrinsics-64-xsaveopt.ll =================================================================== --- test/CodeGen/X86/system-intrinsics-64-xsaveopt.ll +++ test/CodeGen/X86/system-intrinsics-64-xsaveopt.ll @@ -0,0 +1,21 @@ +; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+xsaveopt | FileCheck %s + +define void @test_xsaveopt(i8* %ptr, i32 %hi, i32 %lo) { +; CHECK-LABEL: test_xsaveopt +; CHECK: movl %edx, %eax +; CHECK: movl %esi, %edx +; CHECK: xsaveopt (%rdi) + call void @llvm.x86.xsaveopt(i8* %ptr, i32 %hi, i32 %lo) + ret void; +} +declare void @llvm.x86.xsaveopt(i8*, i32, i32) + +define void @test_xsaveopt64(i8* %ptr, i32 %hi, i32 %lo) { +; CHECK-LABEL: test_xsaveopt64 +; CHECK: movl %edx, %eax +; CHECK: movl %esi, %edx +; CHECK: xsaveopt64 (%rdi) + call void @llvm.x86.xsaveopt64(i8* %ptr, i32 %hi, i32 %lo) + ret void; +} +declare void @llvm.x86.xsaveopt64(i8*, i32, i32) Index: test/CodeGen/X86/system-intrinsics-64-xsaves.ll =================================================================== --- test/CodeGen/X86/system-intrinsics-64-xsaves.ll +++ test/CodeGen/X86/system-intrinsics-64-xsaves.ll @@ -0,0 +1,41 @@ +; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+xsave,+xsaves | FileCheck %s + +define void @test_xsaves(i8* %ptr, i32 %hi, i32 %lo) { +; CHECK-LABEL: test_xsaves +; CHECK: movl %edx, %eax +; CHECK: movl %esi, %edx +; CHECK: xsaves (%rdi) + call void @llvm.x86.xsaves(i8* %ptr, i32 %hi, i32 %lo) + ret void; +} +declare void @llvm.x86.xsaves(i8*, i32, i32) + +define void @test_xsaves64(i8* %ptr, i32 %hi, i32 %lo) { +; CHECK-LABEL: test_xsaves64 +; CHECK: movl %edx, %eax +; CHECK: movl %esi, %edx +; CHECK: xsaves64 (%rdi) + call void @llvm.x86.xsaves64(i8* %ptr, i32 %hi, i32 %lo) + ret void; +} +declare void @llvm.x86.xsaves64(i8*, i32, i32) + +define void @test_xrstors(i8* %ptr, i32 %hi, i32 %lo) { +; CHECK-LABEL: test_xrstors +; CHECK: movl %edx, %eax +; CHECK: movl %esi, %edx +; CHECK: xrstors (%rdi) + call void @llvm.x86.xrstors(i8* %ptr, i32 %hi, i32 %lo) + ret void; +} +declare void @llvm.x86.xrstors(i8*, i32, i32) + +define void @test_xrstors64(i8* %ptr, i32 %hi, i32 %lo) { +; CHECK-LABEL: test_xrstors64 +; CHECK: movl %edx, %eax +; CHECK: movl %esi, %edx +; CHECK: xrstors64 (%rdi) + call void @llvm.x86.xrstors64(i8* %ptr, i32 %hi, i32 %lo) + ret void; +} +declare void @llvm.x86.xrstors64(i8*, i32, i32) Index: test/CodeGen/X86/system-intrinsics-xsave.ll =================================================================== --- test/CodeGen/X86/system-intrinsics-xsave.ll +++ test/CodeGen/X86/system-intrinsics-xsave.ll @@ -0,0 +1,23 @@ +; RUN: llc < %s -mtriple=i686-unknown-unknown -mattr=+xsave | FileCheck %s + +define void @test_xsave(i8* %ptr, i32 %hi, i32 %lo) { +; CHECK-LABEL: test_xsave +; CHECK: movl 8(%esp), %edx +; CHECK: movl 12(%esp), %eax +; CHECK: movl 4(%esp), %ecx +; CHECK: xsave (%ecx) + call void @llvm.x86.xsave(i8* %ptr, i32 %hi, i32 %lo) + ret void; +} +declare void @llvm.x86.xsave(i8*, i32, i32) + +define void @test_xrstor(i8* %ptr, i32 %hi, i32 %lo) { +; CHECK-LABEL: test_xrstor +; CHECK: movl 8(%esp), %edx +; CHECK: movl 12(%esp), %eax +; CHECK: movl 4(%esp), %ecx +; CHECK: xrstor (%ecx) + call void @llvm.x86.xrstor(i8* %ptr, i32 %hi, i32 %lo) + ret void; +} +declare void @llvm.x86.xrstor(i8*, i32, i32) Index: test/CodeGen/X86/system-intrinsics-xsavec.ll =================================================================== --- test/CodeGen/X86/system-intrinsics-xsavec.ll +++ test/CodeGen/X86/system-intrinsics-xsavec.ll @@ -0,0 +1,12 @@ +; RUN: llc < %s -mtriple=i686-unknown-unknown -mattr=+xsave,+xsavec | FileCheck %s + +define void @test_xsavec(i8* %ptr, i32 %hi, i32 %lo) { +; CHECK-LABEL: test_xsavec +; CHECK: movl 8(%esp), %edx +; CHECK: movl 12(%esp), %eax +; CHECK: movl 4(%esp), %ecx +; CHECK: xsavec (%ecx) + call void @llvm.x86.xsavec(i8* %ptr, i32 %hi, i32 %lo) + ret void; +} +declare void @llvm.x86.xsavec(i8*, i32, i32) Index: test/CodeGen/X86/system-intrinsics-xsaveopt.ll =================================================================== --- test/CodeGen/X86/system-intrinsics-xsaveopt.ll +++ test/CodeGen/X86/system-intrinsics-xsaveopt.ll @@ -0,0 +1,12 @@ +; RUN: llc < %s -mtriple=i686-unknown-unknown -mattr=+xsave,+xsaveopt | FileCheck %s + +define void @test_xsaveopt(i8* %ptr, i32 %hi, i32 %lo) { +; CHECK-LABEL: test_xsaveopt +; CHECK: movl 8(%esp), %edx +; CHECK: movl 12(%esp), %eax +; CHECK: movl 4(%esp), %ecx +; CHECK: xsaveopt (%ecx) + call void @llvm.x86.xsaveopt(i8* %ptr, i32 %hi, i32 %lo) + ret void; +} +declare void @llvm.x86.xsaveopt(i8*, i32, i32) Index: test/CodeGen/X86/system-intrinsics-xsaves.ll =================================================================== --- test/CodeGen/X86/system-intrinsics-xsaves.ll +++ test/CodeGen/X86/system-intrinsics-xsaves.ll @@ -0,0 +1,23 @@ +; RUN: llc < %s -mtriple=i686-unknown-unknown -mattr=+xsave,+xsaves | FileCheck %s + +define void @test_xsaves(i8* %ptr, i32 %hi, i32 %lo) { +; CHECK-LABEL: test_xsaves +; CHECK: movl 8(%esp), %edx +; CHECK: movl 12(%esp), %eax +; CHECK: movl 4(%esp), %ecx +; CHECK: xsaves (%ecx) + call void @llvm.x86.xsaves(i8* %ptr, i32 %hi, i32 %lo) + ret void; +} +declare void @llvm.x86.xsaves(i8*, i32, i32) + +define void @test_xrstors(i8* %ptr, i32 %hi, i32 %lo) { +; CHECK-LABEL: test_xrstors +; CHECK: movl 8(%esp), %edx +; CHECK: movl 12(%esp), %eax +; CHECK: movl 4(%esp), %ecx +; CHECK: xrstors (%ecx) + call void @llvm.x86.xrstors(i8* %ptr, i32 %hi, i32 %lo) + ret void; +} +declare void @llvm.x86.xrstors(i8*, i32, i32)