diff --git a/clang/docs/ClangCommandLineReference.rst b/clang/docs/ClangCommandLineReference.rst --- a/clang/docs/ClangCommandLineReference.rst +++ b/clang/docs/ClangCommandLineReference.rst @@ -3145,6 +3145,8 @@ .. option:: -msahf, -mno-sahf +.. option:: -mserialize, -mno-serialize + .. option:: -msgx, -mno-sgx .. option:: -msha, -mno-sha diff --git a/clang/include/clang/Basic/BuiltinsX86.def b/clang/include/clang/Basic/BuiltinsX86.def --- a/clang/include/clang/Basic/BuiltinsX86.def +++ b/clang/include/clang/Basic/BuiltinsX86.def @@ -1900,6 +1900,9 @@ TARGET_BUILTIN(__builtin_ia32_enqcmd, "Ucv*vC*", "n", "enqcmd") TARGET_BUILTIN(__builtin_ia32_enqcmds, "Ucv*vC*", "n", "enqcmd") +// SERIALIZE +TARGET_BUILTIN(__builtin_ia32_serialize, "v", "n", "serialize") + // MSVC TARGET_HEADER_BUILTIN(_BitScanForward, "UcUNi*UNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") TARGET_HEADER_BUILTIN(_BitScanReverse, "UcUNi*UNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -3218,6 +3218,8 @@ def mno_rdseed : Flag<["-"], "mno-rdseed">, Group; def msahf : Flag<["-"], "msahf">, Group; def mno_sahf : Flag<["-"], "mno-sahf">, Group; +def mserialize : Flag<["-"], "mserialize">, Group; +def mno_serialize : Flag<["-"], "mno-serialize">, Group; def msgx : Flag<["-"], "msgx">, Group; def mno_sgx : Flag<["-"], "mno-sgx">, Group; def msha : Flag<["-"], "msha">, Group; diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h --- a/clang/lib/Basic/Targets/X86.h +++ b/clang/lib/Basic/Targets/X86.h @@ -124,6 +124,7 @@ bool HasPTWRITE = false; bool HasINVPCID = false; bool HasENQCMD = false; + bool HasSERIALIZE = false; protected: /// Enumeration of all of the X86 CPUs supported by Clang. diff --git a/clang/lib/Basic/Targets/X86.cpp b/clang/lib/Basic/Targets/X86.cpp --- a/clang/lib/Basic/Targets/X86.cpp +++ b/clang/lib/Basic/Targets/X86.cpp @@ -857,6 +857,8 @@ HasINVPCID = true; } else if (Feature == "+enqcmd") { HasENQCMD = true; + } else if (Feature == "+serialize") { + HasSERIALIZE = true; } X86SSEEnum Level = llvm::StringSwitch(Feature) @@ -1247,6 +1249,8 @@ Builder.defineMacro("__INVPCID__"); if (HasENQCMD) Builder.defineMacro("__ENQCMD__"); + if (HasSERIALIZE) + Builder.defineMacro("__SERIALIZE__"); // Each case falls through to the previous one here. switch (SSELevel) { @@ -1390,6 +1394,7 @@ .Case("rdseed", true) .Case("rtm", true) .Case("sahf", true) + .Case("serialize", true) .Case("sgx", true) .Case("sha", true) .Case("shstk", true) @@ -1474,6 +1479,7 @@ .Case("retpoline-external-thunk", HasRetpolineExternalThunk) .Case("rtm", HasRTM) .Case("sahf", HasLAHFSAHF) + .Case("serialize", HasSERIALIZE) .Case("sgx", HasSGX) .Case("sha", HasSHA) .Case("shstk", HasSHSTK) diff --git a/clang/lib/Headers/CMakeLists.txt b/clang/lib/Headers/CMakeLists.txt --- a/clang/lib/Headers/CMakeLists.txt +++ b/clang/lib/Headers/CMakeLists.txt @@ -88,6 +88,7 @@ ptwriteintrin.h rdseedintrin.h rtmintrin.h + serializeintrin.h sgxintrin.h s390intrin.h shaintrin.h diff --git a/clang/lib/Headers/cpuid.h b/clang/lib/Headers/cpuid.h --- a/clang/lib/Headers/cpuid.h +++ b/clang/lib/Headers/cpuid.h @@ -182,6 +182,7 @@ /* Features in %edx for leaf 7 sub-leaf 0 */ #define bit_AVX5124VNNIW 0x00000004 #define bit_AVX5124FMAPS 0x00000008 +#define bit_SERIALIZE 0x00004000 #define bit_PCONFIG 0x00040000 #define bit_IBT 0x00100000 diff --git a/clang/lib/Headers/immintrin.h b/clang/lib/Headers/immintrin.h --- a/clang/lib/Headers/immintrin.h +++ b/clang/lib/Headers/immintrin.h @@ -434,6 +434,10 @@ #include #endif +#if !defined(_MSC_VER) || __has_feature(modules) || defined(__SERIALIZE__) +#include +#endif + #if defined(_MSC_VER) && __has_extension(gnu_asm) /* Define the default attributes for these intrinsics */ #define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__)) diff --git a/clang/lib/Headers/serializeintrin.h b/clang/lib/Headers/serializeintrin.h new file mode 100644 --- /dev/null +++ b/clang/lib/Headers/serializeintrin.h @@ -0,0 +1,30 @@ +/*===--------------- serializeintrin.h - serialize intrinsics --------------=== + * + * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. + * See https://llvm.org/LICENSE.txt for license information. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + * + *===-----------------------------------------------------------------------=== + */ + +#ifndef __IMMINTRIN_H +#error "Never use directly; include instead." +#endif + +#ifndef __SERIALIZEINTRIN_H +#define __SERIALIZEINTRIN_H + +/// Serialize instruction fetch and execution. +/// +/// \headerfile +/// +/// This intrinsic corresponds to the SERIALIZE instruction. +/// +static __inline__ void +__attribute__((__always_inline__, __nodebug__, __target__("serialize"))) +_serialize (void) +{ + __builtin_ia32_serialize (); +} + +#endif /* __SERIALIZEINTRIN_H */ diff --git a/clang/test/CodeGen/x86-serialize-intrin.c b/clang/test/CodeGen/x86-serialize-intrin.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/x86-serialize-intrin.c @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 %s -ffreestanding -triple x86_64-unknown-unknown -target-feature +serialize -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 %s -ffreestanding -triple i386-unknown-unknown -target-feature +serialize -emit-llvm -o - | FileCheck %s + +#include + +void test_serialize(void) +{ +// CHECK-LABEL: test_serialize +// CHECK: call void @llvm.x86.serialize() + _serialize(); +} diff --git a/clang/test/Driver/x86-target-features.c b/clang/test/Driver/x86-target-features.c --- a/clang/test/Driver/x86-target-features.c +++ b/clang/test/Driver/x86-target-features.c @@ -198,3 +198,8 @@ // RUN: %clang -target i386-unknown-linux-gnu -march=i386 -mno-vzeroupper %s -### -o %t.o 2>&1 | FileCheck --check-prefix=NO-VZEROUPPER %s // VZEROUPPER: "-target-feature" "+vzeroupper" // NO-VZEROUPPER: "-target-feature" "-vzeroupper" + +// RUN: %clang -target i386-unknown-linux-gnu -march=i386 -mserialize %s -### -o %t.o 2>&1 | FileCheck -check-prefix=SERIALIZE %s +// RUN: %clang -target i386-unknown-linux-gnu -march=i386 -mno-serialize %s -### -o %t.o 2>&1 | FileCheck -check-prefix=NO-SERIALIZE %s +// SERIALIZE: "-target-feature" "+serialize" +// NO-SERIALIZE: "-target-feature" "-serialize" diff --git a/clang/test/Preprocessor/x86_target_features.c b/clang/test/Preprocessor/x86_target_features.c --- a/clang/test/Preprocessor/x86_target_features.c +++ b/clang/test/Preprocessor/x86_target_features.c @@ -483,3 +483,11 @@ // RUN: %clang -target i386-unknown-unknown -march=atom -mno-enqcmd -x c -E -dM -o - %s | FileCheck -match-full-lines --check-prefix=NOENQCMD %s // NOENQCMD-NOT: #define __ENQCMD__ 1 + +// RUN: %clang -target i386-unknown-unknown -march=atom -mserialize -x c -E -dM -o - %s | FileCheck -match-full-lines --check-prefix=SERIALIZE %s + +// SERIALIZE: #define __SERIALIZE__ 1 + +// RUN: %clang -target i386-unknown-unknown -march=atom -mno-serialize -x c -E -dM -o - %s | FileCheck -match-full-lines --check-prefix=NOSERIALIZE %s + +// NOSERIALIZE-NOT: #define __SERIALIZE__ 1 diff --git a/llvm/include/llvm/IR/IntrinsicsX86.td b/llvm/include/llvm/IR/IntrinsicsX86.td --- a/llvm/include/llvm/IR/IntrinsicsX86.td +++ b/llvm/include/llvm/IR/IntrinsicsX86.td @@ -4930,3 +4930,11 @@ def int_x86_enqcmds : GCCBuiltin<"__builtin_ia32_enqcmds">, Intrinsic<[llvm_i8_ty], [llvm_ptr_ty, llvm_ptr_ty], []>; } + +//===----------------------------------------------------------------------===// +// SERIALIZE - Serialize instruction fetch and execution + +let TargetPrefix = "x86" in { + def int_x86_serialize : GCCBuiltin<"__builtin_ia32_serialize">, + Intrinsic<[], [], []>; +} diff --git a/llvm/lib/Support/Host.cpp b/llvm/lib/Support/Host.cpp --- a/llvm/lib/Support/Host.cpp +++ b/llvm/lib/Support/Host.cpp @@ -1477,6 +1477,7 @@ Features["movdir64b"] = HasLeaf7 && ((ECX >> 28) & 1); Features["enqcmd"] = HasLeaf7 && ((ECX >> 29) & 1); + Features["serialize"] = HasLeaf7 && ((EDX >> 14) & 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 diff --git a/llvm/lib/Target/X86/X86.td b/llvm/lib/Target/X86/X86.td --- a/llvm/lib/Target/X86/X86.td +++ b/llvm/lib/Target/X86/X86.td @@ -273,6 +273,8 @@ "Wait and pause enhancements">; def FeatureENQCMD : SubtargetFeature<"enqcmd", "HasENQCMD", "true", "Has ENQCMD instructions">; +def FeatureSERIALIZE : SubtargetFeature<"serialize", "HasSERIALIZE", "true", + "Has serialize instruction">; // On some processors, instructions that implicitly take two memory operands are // slow. In practice, this means that CALL, PUSH, and POP with memory operands // should be avoided in favor of a MOV + register CALL/PUSH/POP. diff --git a/llvm/lib/Target/X86/X86InstrInfo.td b/llvm/lib/Target/X86/X86InstrInfo.td --- a/llvm/lib/Target/X86/X86InstrInfo.td +++ b/llvm/lib/Target/X86/X86InstrInfo.td @@ -955,6 +955,7 @@ def HasCmpxchg16b: Predicate<"Subtarget->hasCmpxchg16b()">; def HasPCONFIG : Predicate<"Subtarget->hasPCONFIG()">; def HasENQCMD : Predicate<"Subtarget->hasENQCMD()">; +def HasSERIALIZE : Predicate<"Subtarget->hasSERIALIZE()">; def Not64BitMode : Predicate<"!Subtarget->is64Bit()">, AssemblerPredicate<(all_of (not Mode64Bit)), "Not 64-bit mode">; def In64BitMode : Predicate<"Subtarget->is64Bit()">, @@ -2862,6 +2863,13 @@ def : InstAlias<"clzero\t{%rax|rax}", (CLZERO64r)>, Requires<[In64BitMode]>; //===----------------------------------------------------------------------===// +// SERIALIZE Instruction +// +def SERIALIZE : I<0x01, MRM_E8, (outs), (ins), "serialize", + [(int_x86_serialize)]>, PS, + Requires<[HasSERIALIZE]>; + +//===----------------------------------------------------------------------===// // Pattern fragments to auto generate TBM instructions. //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/X86/X86Subtarget.h b/llvm/lib/Target/X86/X86Subtarget.h --- a/llvm/lib/Target/X86/X86Subtarget.h +++ b/llvm/lib/Target/X86/X86Subtarget.h @@ -397,6 +397,9 @@ /// Processor supports PCONFIG instruction bool HasPCONFIG = false; + /// Processor supports SERIALIZE instruction + bool HasSERIALIZE = false; + /// Processor has a single uop BEXTR implementation. bool HasFastBEXTR = false; @@ -706,6 +709,7 @@ bool threewayBranchProfitable() const { return ThreewayBranchProfitable; } bool hasINVPCID() const { return HasINVPCID; } bool hasENQCMD() const { return HasENQCMD; } + bool hasSERIALIZE() const { return HasSERIALIZE; } bool useRetpolineIndirectCalls() const { return UseRetpolineIndirectCalls; } bool useRetpolineIndirectBranches() const { return UseRetpolineIndirectBranches; diff --git a/llvm/test/CodeGen/X86/serialize-intrinsic.ll b/llvm/test/CodeGen/X86/serialize-intrinsic.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/X86/serialize-intrinsic.ll @@ -0,0 +1,26 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+serialize | FileCheck %s --check-prefix=X86_64 +; RUN: llc < %s -mtriple=i386-unknown-unknown -mattr=+serialize | FileCheck %s --check-prefix=X86 +; RUN: llc < %s -mtriple=x86_64-linux-gnux32 -mattr=+serialize | FileCheck %s --check-prefix=X32 + +define void @test_serialize() { +; X86_64-LABEL: test_serialize: +; X86_64: # %bb.0: # %entry +; X86_64-NEXT: serialize +; X86_64-NEXT: retq +; +; X86-LABEL: test_serialize: +; X86: # %bb.0: # %entry +; X86-NEXT: serialize +; X86-NEXT: retl +; +; X32-LABEL: test_serialize: +; X32: # %bb.0: # %entry +; X32-NEXT: serialize +; X32-NEXT: retq +entry: + call void @llvm.x86.serialize() + ret void +} + +declare void @llvm.x86.serialize() diff --git a/llvm/test/MC/Disassembler/X86/x86-16.txt b/llvm/test/MC/Disassembler/X86/x86-16.txt --- a/llvm/test/MC/Disassembler/X86/x86-16.txt +++ b/llvm/test/MC/Disassembler/X86/x86-16.txt @@ -836,3 +836,6 @@ # CHECK: enqcmds (%edi), %edi 0x67,0xf3,0x0f,0x38,0xf8,0x3f + +# CHECK: serialize +0x0f 0x01 0xe8 diff --git a/llvm/test/MC/Disassembler/X86/x86-32.txt b/llvm/test/MC/Disassembler/X86/x86-32.txt --- a/llvm/test/MC/Disassembler/X86/x86-32.txt +++ b/llvm/test/MC/Disassembler/X86/x86-32.txt @@ -943,3 +943,6 @@ # CHECK: enqcmds 8128(%bx,%di), %ax 0x67,0xf3,0x0f,0x38,0xf8,0x81,0xc0,0x1f + +# CHECK: serialize +0x0f 0x01 0xe8 diff --git a/llvm/test/MC/Disassembler/X86/x86-64.txt b/llvm/test/MC/Disassembler/X86/x86-64.txt --- a/llvm/test/MC/Disassembler/X86/x86-64.txt +++ b/llvm/test/MC/Disassembler/X86/x86-64.txt @@ -691,3 +691,6 @@ # CHECK: enqcmds 485498096, %rax 0xf3,0x0f,0x38,0xf8,0x04,0x25,0xf0,0x1c,0xf0,0x1c + +# CHECK: serialize +0x0f 0x01 0xe8 diff --git a/llvm/test/MC/X86/x86-16.s b/llvm/test/MC/X86/x86-16.s --- a/llvm/test/MC/X86/x86-16.s +++ b/llvm/test/MC/X86/x86-16.s @@ -1029,3 +1029,7 @@ // CHECK: enqcmds (%edi), %edi // CHECK: encoding: [0x67,0xf3,0x0f,0x38,0xf8,0x3f] enqcmds (%edi), %edi + +// CHECK: serialize +// CHECK: encoding: [0x0f,0x01,0xe8] +serialize diff --git a/llvm/test/MC/X86/x86-32-coverage.s b/llvm/test/MC/X86/x86-32-coverage.s --- a/llvm/test/MC/X86/x86-32-coverage.s +++ b/llvm/test/MC/X86/x86-32-coverage.s @@ -10876,3 +10876,7 @@ // CHECK: enqcmds 8128(%bx,%di), %ax // CHECK: encoding: [0x67,0xf3,0x0f,0x38,0xf8,0x81,0xc0,0x1f] enqcmds 8128(%bx,%di), %ax + +// CHECK: serialize +// CHECK: encoding: [0x0f,0x01,0xe8] +serialize diff --git a/llvm/test/MC/X86/x86-64.s b/llvm/test/MC/X86/x86-64.s --- a/llvm/test/MC/X86/x86-64.s +++ b/llvm/test/MC/X86/x86-64.s @@ -1877,3 +1877,7 @@ // CHECK: enqcmds 485498096, %rax // CHECK: encoding: [0xf3,0x0f,0x38,0xf8,0x04,0x25,0xf0,0x1c,0xf0,0x1c] enqcmds 485498096, %rax + +// CHECK: serialize +// CHECK: encoding: [0x0f,0x01,0xe8] +serialize