//===--- X86.cpp - Implement X86 target feature support -------------------===// // // 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 // //===----------------------------------------------------------------------===// // // This file implements X86 TargetInfo objects. // //===----------------------------------------------------------------------===// #include "X86.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/TargetBuiltins.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/TargetParser.h" namespace clang { namespace targets { const Builtin::Info BuiltinInfoX86[] = { #define BUILTIN(ID, TYPE, ATTRS) \ {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE}, #define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANGS, FEATURE) \ {#ID, TYPE, ATTRS, HEADER, LANGS, FEATURE}, #include "clang/Basic/BuiltinsX86.def" #define BUILTIN(ID, TYPE, ATTRS) \ {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE}, #define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANGS, FEATURE) \ {#ID, TYPE, ATTRS, HEADER, LANGS, FEATURE}, #include "clang/Basic/BuiltinsX86_64.def" }; static const char *const GCCRegNames[] = { "ax", "dx", "cx", "bx", "si", "di", "bp", "sp", "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)", "argp", "flags", "fpcr", "fpsr", "dirflag", "frame", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15", "ymm0", "ymm1", "ymm2", "ymm3", "ymm4", "ymm5", "ymm6", "ymm7", "ymm8", "ymm9", "ymm10", "ymm11", "ymm12", "ymm13", "ymm14", "ymm15", "xmm16", "xmm17", "xmm18", "xmm19", "xmm20", "xmm21", "xmm22", "xmm23", "xmm24", "xmm25", "xmm26", "xmm27", "xmm28", "xmm29", "xmm30", "xmm31", "ymm16", "ymm17", "ymm18", "ymm19", "ymm20", "ymm21", "ymm22", "ymm23", "ymm24", "ymm25", "ymm26", "ymm27", "ymm28", "ymm29", "ymm30", "ymm31", "zmm0", "zmm1", "zmm2", "zmm3", "zmm4", "zmm5", "zmm6", "zmm7", "zmm8", "zmm9", "zmm10", "zmm11", "zmm12", "zmm13", "zmm14", "zmm15", "zmm16", "zmm17", "zmm18", "zmm19", "zmm20", "zmm21", "zmm22", "zmm23", "zmm24", "zmm25", "zmm26", "zmm27", "zmm28", "zmm29", "zmm30", "zmm31", "k0", "k1", "k2", "k3", "k4", "k5", "k6", "k7", "cr0", "cr2", "cr3", "cr4", "cr8", "dr0", "dr1", "dr2", "dr3", "dr6", "dr7", "bnd0", "bnd1", "bnd2", "bnd3", }; const TargetInfo::AddlRegName AddlRegNames[] = { {{"al", "ah", "eax", "rax"}, 0}, {{"bl", "bh", "ebx", "rbx"}, 3}, {{"cl", "ch", "ecx", "rcx"}, 2}, {{"dl", "dh", "edx", "rdx"}, 1}, {{"esi", "rsi"}, 4}, {{"edi", "rdi"}, 5}, {{"esp", "rsp"}, 7}, {{"ebp", "rbp"}, 6}, {{"r8d", "r8w", "r8b"}, 38}, {{"r9d", "r9w", "r9b"}, 39}, {{"r10d", "r10w", "r10b"}, 40}, {{"r11d", "r11w", "r11b"}, 41}, {{"r12d", "r12w", "r12b"}, 42}, {{"r13d", "r13w", "r13b"}, 43}, {{"r14d", "r14w", "r14b"}, 44}, {{"r15d", "r15w", "r15b"}, 45}, }; } // namespace targets } // namespace clang using namespace clang; using namespace clang::targets; bool X86TargetInfo::setFPMath(StringRef Name) { if (Name == "387") { FPMath = FP_387; return true; } if (Name == "sse") { FPMath = FP_SSE; return true; } return false; } bool X86TargetInfo::initFeatureMap( llvm::StringMap &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector &FeaturesVec) const { // FIXME: This *really* should not be here. // X86_64 always has SSE2. if (getTriple().getArch() == llvm::Triple::x86_64) setFeatureEnabledImpl(Features, "sse2", true); const CPUKind Kind = getCPUKind(CPU); // Enable X87 for all X86 processors but Lakemont. if (Kind != CK_Lakemont) setFeatureEnabledImpl(Features, "x87", true); // Enable cmpxchg8 for i586 and greater CPUs. Include generic for backwards // compatibility. if (Kind >= CK_i586 || Kind == CK_Generic) setFeatureEnabledImpl(Features, "cx8", true); switch (Kind) { case CK_Generic: case CK_i386: case CK_i486: case CK_i586: case CK_Pentium: case CK_PentiumPro: case CK_i686: case CK_Lakemont: break; case CK_Cooperlake: // CPX inherits all CLX features plus AVX512BF16 setFeatureEnabledImpl(Features, "avx512bf16", true); LLVM_FALLTHROUGH; case CK_Cascadelake: // CLX inherits all SKX features plus AVX512VNNI setFeatureEnabledImpl(Features, "avx512vnni", true); LLVM_FALLTHROUGH; case CK_SkylakeServer: setFeatureEnabledImpl(Features, "avx512f", true); setFeatureEnabledImpl(Features, "avx512cd", true); setFeatureEnabledImpl(Features, "avx512dq", true); setFeatureEnabledImpl(Features, "avx512bw", true); setFeatureEnabledImpl(Features, "avx512vl", true); setFeatureEnabledImpl(Features, "clwb", true); setFeatureEnabledImpl(Features, "pku", true); // SkylakeServer cores inherits all SKL features, except SGX goto SkylakeCommon; case CK_Tigerlake: setFeatureEnabledImpl(Features, "avx512vp2intersect", true); setFeatureEnabledImpl(Features, "movdiri", true); setFeatureEnabledImpl(Features, "movdir64b", true); setFeatureEnabledImpl(Features, "shstk", true); // Tigerlake cores inherits IcelakeClient, except pconfig and wbnoinvd goto IcelakeCommon; case CK_IcelakeServer: setFeatureEnabledImpl(Features, "pconfig", true); setFeatureEnabledImpl(Features, "wbnoinvd", true); LLVM_FALLTHROUGH; case CK_IcelakeClient: IcelakeCommon: setFeatureEnabledImpl(Features, "vaes", true); setFeatureEnabledImpl(Features, "gfni", true); setFeatureEnabledImpl(Features, "vpclmulqdq", true); setFeatureEnabledImpl(Features, "avx512bitalg", true); setFeatureEnabledImpl(Features, "avx512vbmi2", true); setFeatureEnabledImpl(Features, "avx512vnni", true); setFeatureEnabledImpl(Features, "avx512vpopcntdq", true); setFeatureEnabledImpl(Features, "rdpid", true); setFeatureEnabledImpl(Features, "clwb", true); LLVM_FALLTHROUGH; case CK_Cannonlake: setFeatureEnabledImpl(Features, "avx512f", true); setFeatureEnabledImpl(Features, "avx512cd", true); setFeatureEnabledImpl(Features, "avx512dq", true); setFeatureEnabledImpl(Features, "avx512bw", true); setFeatureEnabledImpl(Features, "avx512vl", true); setFeatureEnabledImpl(Features, "avx512ifma", true); setFeatureEnabledImpl(Features, "avx512vbmi", true); setFeatureEnabledImpl(Features, "pku", true); setFeatureEnabledImpl(Features, "sha", true); LLVM_FALLTHROUGH; case CK_SkylakeClient: setFeatureEnabledImpl(Features, "sgx", true); // SkylakeServer cores inherits all SKL features, except SGX SkylakeCommon: setFeatureEnabledImpl(Features, "xsavec", true); setFeatureEnabledImpl(Features, "xsaves", true); setFeatureEnabledImpl(Features, "clflushopt", true); setFeatureEnabledImpl(Features, "aes", true); LLVM_FALLTHROUGH; case CK_Broadwell: setFeatureEnabledImpl(Features, "rdseed", true); setFeatureEnabledImpl(Features, "adx", true); setFeatureEnabledImpl(Features, "prfchw", true); LLVM_FALLTHROUGH; case CK_Haswell: setFeatureEnabledImpl(Features, "avx2", true); setFeatureEnabledImpl(Features, "lzcnt", true); setFeatureEnabledImpl(Features, "bmi", true); setFeatureEnabledImpl(Features, "bmi2", true); setFeatureEnabledImpl(Features, "fma", true); setFeatureEnabledImpl(Features, "invpcid", true); setFeatureEnabledImpl(Features, "movbe", true); LLVM_FALLTHROUGH; case CK_IvyBridge: setFeatureEnabledImpl(Features, "rdrnd", true); setFeatureEnabledImpl(Features, "f16c", true); setFeatureEnabledImpl(Features, "fsgsbase", true); LLVM_FALLTHROUGH; case CK_SandyBridge: setFeatureEnabledImpl(Features, "avx", true); setFeatureEnabledImpl(Features, "xsave", true); setFeatureEnabledImpl(Features, "xsaveopt", true); LLVM_FALLTHROUGH; case CK_Westmere: setFeatureEnabledImpl(Features, "pclmul", true); LLVM_FALLTHROUGH; case CK_Nehalem: setFeatureEnabledImpl(Features, "sse4.2", true); LLVM_FALLTHROUGH; case CK_Penryn: setFeatureEnabledImpl(Features, "sse4.1", true); LLVM_FALLTHROUGH; case CK_Core2: setFeatureEnabledImpl(Features, "ssse3", true); setFeatureEnabledImpl(Features, "sahf", true); LLVM_FALLTHROUGH; case CK_Nocona: setFeatureEnabledImpl(Features, "cx16", true); LLVM_FALLTHROUGH; case CK_Yonah: case CK_Prescott: setFeatureEnabledImpl(Features, "sse3", true); LLVM_FALLTHROUGH; case CK_PentiumM: case CK_Pentium4: case CK_x86_64: setFeatureEnabledImpl(Features, "sse2", true); LLVM_FALLTHROUGH; case CK_Pentium3: case CK_C3_2: setFeatureEnabledImpl(Features, "sse", true); LLVM_FALLTHROUGH; case CK_Pentium2: setFeatureEnabledImpl(Features, "fxsr", true); LLVM_FALLTHROUGH; case CK_PentiumMMX: case CK_K6: case CK_WinChipC6: setFeatureEnabledImpl(Features, "mmx", true); break; case CK_Tremont: setFeatureEnabledImpl(Features, "cldemote", true); setFeatureEnabledImpl(Features, "movdiri", true); setFeatureEnabledImpl(Features, "movdir64b", true); setFeatureEnabledImpl(Features, "gfni", true); setFeatureEnabledImpl(Features, "waitpkg", true); LLVM_FALLTHROUGH; case CK_GoldmontPlus: setFeatureEnabledImpl(Features, "ptwrite", true); setFeatureEnabledImpl(Features, "rdpid", true); setFeatureEnabledImpl(Features, "sgx", true); LLVM_FALLTHROUGH; case CK_Goldmont: setFeatureEnabledImpl(Features, "sha", true); setFeatureEnabledImpl(Features, "rdseed", true); setFeatureEnabledImpl(Features, "xsave", true); setFeatureEnabledImpl(Features, "xsaveopt", true); setFeatureEnabledImpl(Features, "xsavec", true); setFeatureEnabledImpl(Features, "xsaves", true); setFeatureEnabledImpl(Features, "clflushopt", true); setFeatureEnabledImpl(Features, "fsgsbase", true); setFeatureEnabledImpl(Features, "aes", true); LLVM_FALLTHROUGH; case CK_Silvermont: setFeatureEnabledImpl(Features, "rdrnd", true); setFeatureEnabledImpl(Features, "pclmul", true); setFeatureEnabledImpl(Features, "sse4.2", true); setFeatureEnabledImpl(Features, "prfchw", true); LLVM_FALLTHROUGH; case CK_Bonnell: setFeatureEnabledImpl(Features, "movbe", true); setFeatureEnabledImpl(Features, "ssse3", true); setFeatureEnabledImpl(Features, "fxsr", true); setFeatureEnabledImpl(Features, "cx16", true); setFeatureEnabledImpl(Features, "sahf", true); setFeatureEnabledImpl(Features, "mmx", true); break; case CK_KNM: // TODO: Add avx5124fmaps/avx5124vnniw. setFeatureEnabledImpl(Features, "avx512vpopcntdq", true); LLVM_FALLTHROUGH; case CK_KNL: setFeatureEnabledImpl(Features, "avx512f", true); setFeatureEnabledImpl(Features, "avx512cd", true); setFeatureEnabledImpl(Features, "avx512er", true); setFeatureEnabledImpl(Features, "avx512pf", true); setFeatureEnabledImpl(Features, "prfchw", true); setFeatureEnabledImpl(Features, "prefetchwt1", true); setFeatureEnabledImpl(Features, "fxsr", true); setFeatureEnabledImpl(Features, "rdseed", true); setFeatureEnabledImpl(Features, "adx", true); setFeatureEnabledImpl(Features, "lzcnt", true); setFeatureEnabledImpl(Features, "bmi", true); setFeatureEnabledImpl(Features, "bmi2", true); setFeatureEnabledImpl(Features, "fma", true); setFeatureEnabledImpl(Features, "rdrnd", true); setFeatureEnabledImpl(Features, "f16c", true); setFeatureEnabledImpl(Features, "fsgsbase", true); setFeatureEnabledImpl(Features, "aes", true); setFeatureEnabledImpl(Features, "pclmul", true); setFeatureEnabledImpl(Features, "cx16", true); setFeatureEnabledImpl(Features, "xsaveopt", true); setFeatureEnabledImpl(Features, "xsave", true); setFeatureEnabledImpl(Features, "movbe", true); setFeatureEnabledImpl(Features, "sahf", true); setFeatureEnabledImpl(Features, "mmx", true); break; case CK_K6_2: case CK_K6_3: case CK_WinChip2: case CK_C3: setFeatureEnabledImpl(Features, "3dnow", true); break; case CK_AMDFAM10: setFeatureEnabledImpl(Features, "sse4a", true); setFeatureEnabledImpl(Features, "lzcnt", true); setFeatureEnabledImpl(Features, "popcnt", true); setFeatureEnabledImpl(Features, "sahf", true); LLVM_FALLTHROUGH; case CK_K8SSE3: setFeatureEnabledImpl(Features, "sse3", true); LLVM_FALLTHROUGH; case CK_K8: setFeatureEnabledImpl(Features, "sse2", true); LLVM_FALLTHROUGH; case CK_AthlonXP: setFeatureEnabledImpl(Features, "sse", true); setFeatureEnabledImpl(Features, "fxsr", true); LLVM_FALLTHROUGH; case CK_Athlon: case CK_Geode: setFeatureEnabledImpl(Features, "3dnowa", true); break; case CK_BTVER2: setFeatureEnabledImpl(Features, "avx", true); setFeatureEnabledImpl(Features, "aes", true); setFeatureEnabledImpl(Features, "pclmul", true); setFeatureEnabledImpl(Features, "bmi", true); setFeatureEnabledImpl(Features, "f16c", true); setFeatureEnabledImpl(Features, "xsaveopt", true); setFeatureEnabledImpl(Features, "movbe", true); LLVM_FALLTHROUGH; case CK_BTVER1: setFeatureEnabledImpl(Features, "ssse3", true); setFeatureEnabledImpl(Features, "sse4a", true); setFeatureEnabledImpl(Features, "lzcnt", true); setFeatureEnabledImpl(Features, "popcnt", true); setFeatureEnabledImpl(Features, "prfchw", true); setFeatureEnabledImpl(Features, "cx16", true); setFeatureEnabledImpl(Features, "fxsr", true); setFeatureEnabledImpl(Features, "sahf", true); setFeatureEnabledImpl(Features, "mmx", true); break; case CK_ZNVER2: setFeatureEnabledImpl(Features, "clwb", true); setFeatureEnabledImpl(Features, "rdpid", true); setFeatureEnabledImpl(Features, "wbnoinvd", true); LLVM_FALLTHROUGH; case CK_ZNVER1: setFeatureEnabledImpl(Features, "adx", true); setFeatureEnabledImpl(Features, "aes", true); setFeatureEnabledImpl(Features, "avx2", true); setFeatureEnabledImpl(Features, "bmi", true); setFeatureEnabledImpl(Features, "bmi2", true); setFeatureEnabledImpl(Features, "clflushopt", true); setFeatureEnabledImpl(Features, "clzero", true); setFeatureEnabledImpl(Features, "cx16", true); setFeatureEnabledImpl(Features, "f16c", true); setFeatureEnabledImpl(Features, "fma", true); setFeatureEnabledImpl(Features, "fsgsbase", true); setFeatureEnabledImpl(Features, "fxsr", true); setFeatureEnabledImpl(Features, "lzcnt", true); setFeatureEnabledImpl(Features, "mmx", true); setFeatureEnabledImpl(Features, "mwaitx", true); setFeatureEnabledImpl(Features, "movbe", true); setFeatureEnabledImpl(Features, "pclmul", true); setFeatureEnabledImpl(Features, "popcnt", true); setFeatureEnabledImpl(Features, "prfchw", true); setFeatureEnabledImpl(Features, "rdrnd", true); setFeatureEnabledImpl(Features, "rdseed", true); setFeatureEnabledImpl(Features, "sahf", true); setFeatureEnabledImpl(Features, "sha", true); setFeatureEnabledImpl(Features, "sse4a", true); setFeatureEnabledImpl(Features, "xsave", true); setFeatureEnabledImpl(Features, "xsavec", true); setFeatureEnabledImpl(Features, "xsaveopt", true); setFeatureEnabledImpl(Features, "xsaves", true); break; case CK_BDVER4: setFeatureEnabledImpl(Features, "avx2", true); setFeatureEnabledImpl(Features, "bmi2", true); setFeatureEnabledImpl(Features, "mwaitx", true); LLVM_FALLTHROUGH; case CK_BDVER3: setFeatureEnabledImpl(Features, "fsgsbase", true); setFeatureEnabledImpl(Features, "xsaveopt", true); LLVM_FALLTHROUGH; case CK_BDVER2: setFeatureEnabledImpl(Features, "bmi", true); setFeatureEnabledImpl(Features, "fma", true); setFeatureEnabledImpl(Features, "f16c", true); setFeatureEnabledImpl(Features, "tbm", true); LLVM_FALLTHROUGH; case CK_BDVER1: // xop implies avx, sse4a and fma4. setFeatureEnabledImpl(Features, "xop", true); setFeatureEnabledImpl(Features, "lwp", true); setFeatureEnabledImpl(Features, "lzcnt", true); setFeatureEnabledImpl(Features, "aes", true); setFeatureEnabledImpl(Features, "pclmul", true); setFeatureEnabledImpl(Features, "prfchw", true); setFeatureEnabledImpl(Features, "cx16", true); setFeatureEnabledImpl(Features, "fxsr", true); setFeatureEnabledImpl(Features, "xsave", true); setFeatureEnabledImpl(Features, "sahf", true); setFeatureEnabledImpl(Features, "mmx", true); break; } if (!TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec)) return false; // Can't do this earlier because we need to be able to explicitly enable // or disable these features and the things that they depend upon. // Enable popcnt if sse4.2 is enabled and popcnt is not explicitly disabled. auto I = Features.find("sse4.2"); if (I != Features.end() && I->getValue() && llvm::find(FeaturesVec, "-popcnt") == FeaturesVec.end()) Features["popcnt"] = true; // Enable prfchw if 3DNow! is enabled and prfchw is not explicitly disabled. I = Features.find("3dnow"); if (I != Features.end() && I->getValue() && llvm::find(FeaturesVec, "-prfchw") == FeaturesVec.end()) Features["prfchw"] = true; // Additionally, if SSE is enabled and mmx is not explicitly disabled, // then enable MMX. I = Features.find("sse"); if (I != Features.end() && I->getValue() && llvm::find(FeaturesVec, "-mmx") == FeaturesVec.end()) Features["mmx"] = true; return true; } void X86TargetInfo::setSSELevel(llvm::StringMap &Features, X86SSEEnum Level, bool Enabled) { if (Enabled) { switch (Level) { case AVX512F: Features["avx512f"] = true; Features["fma"] = true; Features["f16c"] = true; LLVM_FALLTHROUGH; case AVX2: Features["avx2"] = true; LLVM_FALLTHROUGH; case AVX: Features["avx"] = true; Features["xsave"] = true; LLVM_FALLTHROUGH; case SSE42: Features["sse4.2"] = true; LLVM_FALLTHROUGH; case SSE41: Features["sse4.1"] = true; LLVM_FALLTHROUGH; case SSSE3: Features["ssse3"] = true; LLVM_FALLTHROUGH; case SSE3: Features["sse3"] = true; LLVM_FALLTHROUGH; case SSE2: Features["sse2"] = true; LLVM_FALLTHROUGH; case SSE1: Features["sse"] = true; LLVM_FALLTHROUGH; case NoSSE: break; } return; } switch (Level) { case NoSSE: case SSE1: Features["sse"] = false; LLVM_FALLTHROUGH; case SSE2: Features["sse2"] = Features["pclmul"] = Features["aes"] = false; Features["sha"] = Features["gfni"] = false; LLVM_FALLTHROUGH; case SSE3: Features["sse3"] = false; setXOPLevel(Features, NoXOP, false); LLVM_FALLTHROUGH; case SSSE3: Features["ssse3"] = false; LLVM_FALLTHROUGH; case SSE41: Features["sse4.1"] = false; LLVM_FALLTHROUGH; case SSE42: Features["sse4.2"] = false; LLVM_FALLTHROUGH; case AVX: Features["fma"] = Features["avx"] = Features["f16c"] = false; Features["xsave"] = Features["xsaveopt"] = Features["vaes"] = false; Features["vpclmulqdq"] = false; setXOPLevel(Features, FMA4, false); LLVM_FALLTHROUGH; case AVX2: Features["avx2"] = false; LLVM_FALLTHROUGH; case AVX512F: Features["avx512f"] = Features["avx512cd"] = Features["avx512er"] = false; Features["avx512pf"] = Features["avx512dq"] = Features["avx512bw"] = false; Features["avx512vl"] = Features["avx512vbmi"] = false; Features["avx512ifma"] = Features["avx512vpopcntdq"] = false; Features["avx512bitalg"] = Features["avx512vnni"] = false; Features["avx512vbmi2"] = Features["avx512bf16"] = false; Features["avx512vp2intersect"] = false; break; } } void X86TargetInfo::setMMXLevel(llvm::StringMap &Features, MMX3DNowEnum Level, bool Enabled) { if (Enabled) { switch (Level) { case AMD3DNowAthlon: Features["3dnowa"] = true; LLVM_FALLTHROUGH; case AMD3DNow: Features["3dnow"] = true; LLVM_FALLTHROUGH; case MMX: Features["mmx"] = true; LLVM_FALLTHROUGH; case NoMMX3DNow: break; } return; } switch (Level) { case NoMMX3DNow: case MMX: Features["mmx"] = false; LLVM_FALLTHROUGH; case AMD3DNow: Features["3dnow"] = false; LLVM_FALLTHROUGH; case AMD3DNowAthlon: Features["3dnowa"] = false; break; } } void X86TargetInfo::setXOPLevel(llvm::StringMap &Features, XOPEnum Level, bool Enabled) { if (Enabled) { switch (Level) { case XOP: Features["xop"] = true; LLVM_FALLTHROUGH; case FMA4: Features["fma4"] = true; setSSELevel(Features, AVX, true); LLVM_FALLTHROUGH; case SSE4A: Features["sse4a"] = true; setSSELevel(Features, SSE3, true); LLVM_FALLTHROUGH; case NoXOP: break; } return; } switch (Level) { case NoXOP: case SSE4A: Features["sse4a"] = false; LLVM_FALLTHROUGH; case FMA4: Features["fma4"] = false; LLVM_FALLTHROUGH; case XOP: Features["xop"] = false; break; } } void X86TargetInfo::setFeatureEnabledImpl(llvm::StringMap &Features, StringRef Name, bool Enabled) { // This is a bit of a hack to deal with the sse4 target feature when used // as part of the target attribute. We handle sse4 correctly everywhere // else. See below for more information on how we handle the sse4 options. if (Name != "sse4") Features[Name] = Enabled; if (Name == "mmx") { setMMXLevel(Features, MMX, Enabled); } else if (Name == "sse") { setSSELevel(Features, SSE1, Enabled); } else if (Name == "sse2") { setSSELevel(Features, SSE2, Enabled); } else if (Name == "sse3") { setSSELevel(Features, SSE3, Enabled); } else if (Name == "ssse3") { setSSELevel(Features, SSSE3, Enabled); } else if (Name == "sse4.2") { setSSELevel(Features, SSE42, Enabled); } else if (Name == "sse4.1") { setSSELevel(Features, SSE41, Enabled); } else if (Name == "3dnow") { setMMXLevel(Features, AMD3DNow, Enabled); } else if (Name == "3dnowa") { setMMXLevel(Features, AMD3DNowAthlon, Enabled); } else if (Name == "aes") { if (Enabled) setSSELevel(Features, SSE2, Enabled); else Features["vaes"] = false; } else if (Name == "vaes") { if (Enabled) { setSSELevel(Features, AVX, Enabled); Features["aes"] = true; } } else if (Name == "pclmul") { if (Enabled) setSSELevel(Features, SSE2, Enabled); else Features["vpclmulqdq"] = false; } else if (Name == "vpclmulqdq") { if (Enabled) { setSSELevel(Features, AVX, Enabled); Features["pclmul"] = true; } } else if (Name == "gfni") { if (Enabled) setSSELevel(Features, SSE2, Enabled); } else if (Name == "avx") { setSSELevel(Features, AVX, Enabled); } else if (Name == "avx2") { setSSELevel(Features, AVX2, Enabled); } else if (Name == "avx512f") { setSSELevel(Features, AVX512F, Enabled); } else if (Name.startswith("avx512")) { if (Enabled) setSSELevel(Features, AVX512F, Enabled); // Enable BWI instruction if certain features are being enabled. if ((Name == "avx512vbmi" || Name == "avx512vbmi2" || Name == "avx512bitalg" || Name == "avx512bf16") && Enabled) Features["avx512bw"] = true; // Also disable some features if BWI is being disabled. if (Name == "avx512bw" && !Enabled) { Features["avx512vbmi"] = false; Features["avx512vbmi2"] = false; Features["avx512bitalg"] = false; Features["avx512bf16"] = false; } } else if (Name == "fma") { if (Enabled) setSSELevel(Features, AVX, Enabled); else setSSELevel(Features, AVX512F, Enabled); } else if (Name == "fma4") { setXOPLevel(Features, FMA4, Enabled); } else if (Name == "xop") { setXOPLevel(Features, XOP, Enabled); } else if (Name == "sse4a") { setXOPLevel(Features, SSE4A, Enabled); } else if (Name == "f16c") { if (Enabled) setSSELevel(Features, AVX, Enabled); else setSSELevel(Features, AVX512F, Enabled); } else if (Name == "sha") { if (Enabled) setSSELevel(Features, SSE2, Enabled); } else if (Name == "sse4") { // We can get here via the __target__ attribute since that's not controlled // via the -msse4/-mno-sse4 command line alias. Handle this the same way // here - turn on the sse4.2 if enabled, turn off the sse4.1 level if // disabled. if (Enabled) setSSELevel(Features, SSE42, Enabled); else setSSELevel(Features, SSE41, Enabled); } else if (Name == "xsave") { if (!Enabled) Features["xsaveopt"] = false; } else if (Name == "xsaveopt" || Name == "xsavec" || Name == "xsaves") { if (Enabled) Features["xsave"] = true; } } /// handleTargetFeatures - Perform initialization based on the user /// configured set of features. bool X86TargetInfo::handleTargetFeatures(std::vector &Features, DiagnosticsEngine &Diags) { for (const auto &Feature : Features) { if (Feature[0] != '+') continue; if (Feature == "+aes") { HasAES = true; } else if (Feature == "+vaes") { HasVAES = true; } else if (Feature == "+pclmul") { HasPCLMUL = true; } else if (Feature == "+vpclmulqdq") { HasVPCLMULQDQ = true; } else if (Feature == "+lzcnt") { HasLZCNT = true; } else if (Feature == "+rdrnd") { HasRDRND = true; } else if (Feature == "+fsgsbase") { HasFSGSBASE = true; } else if (Feature == "+bmi") { HasBMI = true; } else if (Feature == "+bmi2") { HasBMI2 = true; } else if (Feature == "+popcnt") { HasPOPCNT = true; } else if (Feature == "+rtm") { HasRTM = true; } else if (Feature == "+prfchw") { HasPRFCHW = true; } else if (Feature == "+rdseed") { HasRDSEED = true; } else if (Feature == "+adx") { HasADX = true; } else if (Feature == "+tbm") { HasTBM = true; } else if (Feature == "+lwp") { HasLWP = true; } else if (Feature == "+fma") { HasFMA = true; } else if (Feature == "+f16c") { HasF16C = true; } else if (Feature == "+gfni") { HasGFNI = true; } else if (Feature == "+avx512cd") { HasAVX512CD = true; } else if (Feature == "+avx512vpopcntdq") { HasAVX512VPOPCNTDQ = true; } else if (Feature == "+avx512vnni") { HasAVX512VNNI = true; } else if (Feature == "+avx512bf16") { HasAVX512BF16 = true; } else if (Feature == "+avx512er") { HasAVX512ER = true; } else if (Feature == "+avx512pf") { HasAVX512PF = true; } else if (Feature == "+avx512dq") { HasAVX512DQ = true; } else if (Feature == "+avx512bitalg") { HasAVX512BITALG = true; } else if (Feature == "+avx512bw") { HasAVX512BW = true; } else if (Feature == "+avx512vl") { HasAVX512VL = true; } else if (Feature == "+avx512vbmi") { HasAVX512VBMI = true; } else if (Feature == "+avx512vbmi2") { HasAVX512VBMI2 = true; } else if (Feature == "+avx512ifma") { HasAVX512IFMA = true; } else if (Feature == "+avx512vp2intersect") { HasAVX512VP2INTERSECT = true; } else if (Feature == "+sha") { HasSHA = true; } else if (Feature == "+shstk") { HasSHSTK = true; } else if (Feature == "+movbe") { HasMOVBE = true; } else if (Feature == "+sgx") { HasSGX = true; } else if (Feature == "+cx8") { HasCX8 = true; } else if (Feature == "+cx16") { HasCX16 = true; } else if (Feature == "+fxsr") { HasFXSR = true; } else if (Feature == "+xsave") { HasXSAVE = true; } else if (Feature == "+xsaveopt") { HasXSAVEOPT = true; } else if (Feature == "+xsavec") { HasXSAVEC = true; } else if (Feature == "+xsaves") { HasXSAVES = true; } else if (Feature == "+mwaitx") { HasMWAITX = true; } else if (Feature == "+pku") { HasPKU = true; } else if (Feature == "+clflushopt") { HasCLFLUSHOPT = true; } else if (Feature == "+clwb") { HasCLWB = true; } else if (Feature == "+wbnoinvd") { HasWBNOINVD = true; } else if (Feature == "+prefetchwt1") { HasPREFETCHWT1 = true; } else if (Feature == "+clzero") { HasCLZERO = true; } else if (Feature == "+cldemote") { HasCLDEMOTE = true; } else if (Feature == "+rdpid") { HasRDPID = true; } else if (Feature == "+retpoline-external-thunk") { HasRetpolineExternalThunk = true; } else if (Feature == "+sahf") { HasLAHFSAHF = true; } else if (Feature == "+waitpkg") { HasWAITPKG = true; } else if (Feature == "+movdiri") { HasMOVDIRI = true; } else if (Feature == "+movdir64b") { HasMOVDIR64B = true; } else if (Feature == "+pconfig") { HasPCONFIG = true; } else if (Feature == "+ptwrite") { HasPTWRITE = true; } else if (Feature == "+invpcid") { HasINVPCID = true; } else if (Feature == "+enqcmd") { HasENQCMD = true; } X86SSEEnum Level = llvm::StringSwitch(Feature) .Case("+avx512f", AVX512F) .Case("+avx2", AVX2) .Case("+avx", AVX) .Case("+sse4.2", SSE42) .Case("+sse4.1", SSE41) .Case("+ssse3", SSSE3) .Case("+sse3", SSE3) .Case("+sse2", SSE2) .Case("+sse", SSE1) .Default(NoSSE); SSELevel = std::max(SSELevel, Level); MMX3DNowEnum ThreeDNowLevel = llvm::StringSwitch(Feature) .Case("+3dnowa", AMD3DNowAthlon) .Case("+3dnow", AMD3DNow) .Case("+mmx", MMX) .Default(NoMMX3DNow); MMX3DNowLevel = std::max(MMX3DNowLevel, ThreeDNowLevel); XOPEnum XLevel = llvm::StringSwitch(Feature) .Case("+xop", XOP) .Case("+fma4", FMA4) .Case("+sse4a", SSE4A) .Default(NoXOP); XOPLevel = std::max(XOPLevel, XLevel); } // LLVM doesn't have a separate switch for fpmath, so only accept it if it // matches the selected sse level. if ((FPMath == FP_SSE && SSELevel < SSE1) || (FPMath == FP_387 && SSELevel >= SSE1)) { Diags.Report(diag::err_target_unsupported_fpmath) << (FPMath == FP_SSE ? "sse" : "387"); return false; } SimdDefaultAlign = hasFeature("avx512f") ? 512 : hasFeature("avx") ? 256 : 128; return true; } /// X86TargetInfo::getTargetDefines - Return the set of the X86-specific macro /// definitions for this particular subtarget. void X86TargetInfo::getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { // Inline assembly supports X86 flag outputs. Builder.defineMacro("__GCC_ASM_FLAG_OUTPUTS__"); std::string CodeModel = getTargetOpts().CodeModel; if (CodeModel == "default") CodeModel = "small"; Builder.defineMacro("__code_model_" + CodeModel + "_"); // Target identification. if (getTriple().getArch() == llvm::Triple::x86_64) { Builder.defineMacro("__amd64__"); Builder.defineMacro("__amd64"); Builder.defineMacro("__x86_64"); Builder.defineMacro("__x86_64__"); if (getTriple().getArchName() == "x86_64h") { Builder.defineMacro("__x86_64h"); Builder.defineMacro("__x86_64h__"); } } else { DefineStd(Builder, "i386", Opts); } Builder.defineMacro("__SEG_GS"); Builder.defineMacro("__SEG_FS"); Builder.defineMacro("__seg_gs", "__attribute__((address_space(256)))"); Builder.defineMacro("__seg_fs", "__attribute__((address_space(257)))"); // Subtarget options. // FIXME: We are hard-coding the tune parameters based on the CPU, but they // truly should be based on -mtune options. switch (CPU) { case CK_Generic: break; case CK_i386: // The rest are coming from the i386 define above. Builder.defineMacro("__tune_i386__"); break; case CK_i486: case CK_WinChipC6: case CK_WinChip2: case CK_C3: defineCPUMacros(Builder, "i486"); break; case CK_PentiumMMX: Builder.defineMacro("__pentium_mmx__"); Builder.defineMacro("__tune_pentium_mmx__"); LLVM_FALLTHROUGH; case CK_i586: case CK_Pentium: defineCPUMacros(Builder, "i586"); defineCPUMacros(Builder, "pentium"); break; case CK_Pentium3: case CK_PentiumM: Builder.defineMacro("__tune_pentium3__"); LLVM_FALLTHROUGH; case CK_Pentium2: case CK_C3_2: Builder.defineMacro("__tune_pentium2__"); LLVM_FALLTHROUGH; case CK_PentiumPro: case CK_i686: defineCPUMacros(Builder, "i686"); defineCPUMacros(Builder, "pentiumpro"); break; case CK_Pentium4: defineCPUMacros(Builder, "pentium4"); break; case CK_Yonah: case CK_Prescott: case CK_Nocona: defineCPUMacros(Builder, "nocona"); break; case CK_Core2: case CK_Penryn: defineCPUMacros(Builder, "core2"); break; case CK_Bonnell: defineCPUMacros(Builder, "atom"); break; case CK_Silvermont: defineCPUMacros(Builder, "slm"); break; case CK_Goldmont: defineCPUMacros(Builder, "goldmont"); break; case CK_GoldmontPlus: defineCPUMacros(Builder, "goldmont_plus"); break; case CK_Tremont: defineCPUMacros(Builder, "tremont"); break; case CK_Nehalem: case CK_Westmere: case CK_SandyBridge: case CK_IvyBridge: case CK_Haswell: case CK_Broadwell: case CK_SkylakeClient: case CK_SkylakeServer: case CK_Cascadelake: case CK_Cooperlake: case CK_Cannonlake: case CK_IcelakeClient: case CK_IcelakeServer: case CK_Tigerlake: // FIXME: Historically, we defined this legacy name, it would be nice to // remove it at some point. We've never exposed fine-grained names for // recent primary x86 CPUs, and we should keep it that way. defineCPUMacros(Builder, "corei7"); break; case CK_KNL: defineCPUMacros(Builder, "knl"); break; case CK_KNM: break; case CK_Lakemont: defineCPUMacros(Builder, "i586", /*Tuning*/false); defineCPUMacros(Builder, "pentium", /*Tuning*/false); Builder.defineMacro("__tune_lakemont__"); break; case CK_K6_2: Builder.defineMacro("__k6_2__"); Builder.defineMacro("__tune_k6_2__"); LLVM_FALLTHROUGH; case CK_K6_3: if (CPU != CK_K6_2) { // In case of fallthrough // FIXME: GCC may be enabling these in cases where some other k6 // architecture is specified but -m3dnow is explicitly provided. The // exact semantics need to be determined and emulated here. Builder.defineMacro("__k6_3__"); Builder.defineMacro("__tune_k6_3__"); } LLVM_FALLTHROUGH; case CK_K6: defineCPUMacros(Builder, "k6"); break; case CK_Athlon: case CK_AthlonXP: defineCPUMacros(Builder, "athlon"); if (SSELevel != NoSSE) { Builder.defineMacro("__athlon_sse__"); Builder.defineMacro("__tune_athlon_sse__"); } break; case CK_K8: case CK_K8SSE3: case CK_x86_64: defineCPUMacros(Builder, "k8"); break; case CK_AMDFAM10: defineCPUMacros(Builder, "amdfam10"); break; case CK_BTVER1: defineCPUMacros(Builder, "btver1"); break; case CK_BTVER2: defineCPUMacros(Builder, "btver2"); break; case CK_BDVER1: defineCPUMacros(Builder, "bdver1"); break; case CK_BDVER2: defineCPUMacros(Builder, "bdver2"); break; case CK_BDVER3: defineCPUMacros(Builder, "bdver3"); break; case CK_BDVER4: defineCPUMacros(Builder, "bdver4"); break; case CK_ZNVER1: defineCPUMacros(Builder, "znver1"); break; case CK_ZNVER2: defineCPUMacros(Builder, "znver2"); break; case CK_Geode: defineCPUMacros(Builder, "geode"); break; } // Target properties. Builder.defineMacro("__REGISTER_PREFIX__", ""); // Define __NO_MATH_INLINES on linux/x86 so that we don't get inline // functions in glibc header files that use FP Stack inline asm which the // backend can't deal with (PR879). Builder.defineMacro("__NO_MATH_INLINES"); if (HasAES) Builder.defineMacro("__AES__"); if (HasVAES) Builder.defineMacro("__VAES__"); if (HasPCLMUL) Builder.defineMacro("__PCLMUL__"); if (HasVPCLMULQDQ) Builder.defineMacro("__VPCLMULQDQ__"); if (HasLZCNT) Builder.defineMacro("__LZCNT__"); if (HasRDRND) Builder.defineMacro("__RDRND__"); if (HasFSGSBASE) Builder.defineMacro("__FSGSBASE__"); if (HasBMI) Builder.defineMacro("__BMI__"); if (HasBMI2) Builder.defineMacro("__BMI2__"); if (HasPOPCNT) Builder.defineMacro("__POPCNT__"); if (HasRTM) Builder.defineMacro("__RTM__"); if (HasPRFCHW) Builder.defineMacro("__PRFCHW__"); if (HasRDSEED) Builder.defineMacro("__RDSEED__"); if (HasADX) Builder.defineMacro("__ADX__"); if (HasTBM) Builder.defineMacro("__TBM__"); if (HasLWP) Builder.defineMacro("__LWP__"); if (HasMWAITX) Builder.defineMacro("__MWAITX__"); if (HasMOVBE) Builder.defineMacro("__MOVBE__"); switch (XOPLevel) { case XOP: Builder.defineMacro("__XOP__"); LLVM_FALLTHROUGH; case FMA4: Builder.defineMacro("__FMA4__"); LLVM_FALLTHROUGH; case SSE4A: Builder.defineMacro("__SSE4A__"); LLVM_FALLTHROUGH; case NoXOP: break; } if (HasFMA) Builder.defineMacro("__FMA__"); if (HasF16C) Builder.defineMacro("__F16C__"); if (HasGFNI) Builder.defineMacro("__GFNI__"); if (HasAVX512CD) Builder.defineMacro("__AVX512CD__"); if (HasAVX512VPOPCNTDQ) Builder.defineMacro("__AVX512VPOPCNTDQ__"); if (HasAVX512VNNI) Builder.defineMacro("__AVX512VNNI__"); if (HasAVX512BF16) Builder.defineMacro("__AVX512BF16__"); if (HasAVX512ER) Builder.defineMacro("__AVX512ER__"); if (HasAVX512PF) Builder.defineMacro("__AVX512PF__"); if (HasAVX512DQ) Builder.defineMacro("__AVX512DQ__"); if (HasAVX512BITALG) Builder.defineMacro("__AVX512BITALG__"); if (HasAVX512BW) Builder.defineMacro("__AVX512BW__"); if (HasAVX512VL) Builder.defineMacro("__AVX512VL__"); if (HasAVX512VBMI) Builder.defineMacro("__AVX512VBMI__"); if (HasAVX512VBMI2) Builder.defineMacro("__AVX512VBMI2__"); if (HasAVX512IFMA) Builder.defineMacro("__AVX512IFMA__"); if (HasAVX512VP2INTERSECT) Builder.defineMacro("__AVX512VP2INTERSECT__"); if (HasSHA) Builder.defineMacro("__SHA__"); if (HasFXSR) Builder.defineMacro("__FXSR__"); if (HasXSAVE) Builder.defineMacro("__XSAVE__"); if (HasXSAVEOPT) Builder.defineMacro("__XSAVEOPT__"); if (HasXSAVEC) Builder.defineMacro("__XSAVEC__"); if (HasXSAVES) Builder.defineMacro("__XSAVES__"); if (HasPKU) Builder.defineMacro("__PKU__"); if (HasCLFLUSHOPT) Builder.defineMacro("__CLFLUSHOPT__"); if (HasCLWB) Builder.defineMacro("__CLWB__"); if (HasWBNOINVD) Builder.defineMacro("__WBNOINVD__"); if (HasSHSTK) Builder.defineMacro("__SHSTK__"); if (HasSGX) Builder.defineMacro("__SGX__"); if (HasPREFETCHWT1) Builder.defineMacro("__PREFETCHWT1__"); if (HasCLZERO) Builder.defineMacro("__CLZERO__"); if (HasRDPID) Builder.defineMacro("__RDPID__"); if (HasCLDEMOTE) Builder.defineMacro("__CLDEMOTE__"); if (HasWAITPKG) Builder.defineMacro("__WAITPKG__"); if (HasMOVDIRI) Builder.defineMacro("__MOVDIRI__"); if (HasMOVDIR64B) Builder.defineMacro("__MOVDIR64B__"); if (HasPCONFIG) Builder.defineMacro("__PCONFIG__"); if (HasPTWRITE) Builder.defineMacro("__PTWRITE__"); if (HasINVPCID) Builder.defineMacro("__INVPCID__"); if (HasENQCMD) Builder.defineMacro("__ENQCMD__"); // Each case falls through to the previous one here. switch (SSELevel) { case AVX512F: Builder.defineMacro("__AVX512F__"); LLVM_FALLTHROUGH; case AVX2: Builder.defineMacro("__AVX2__"); LLVM_FALLTHROUGH; case AVX: Builder.defineMacro("__AVX__"); LLVM_FALLTHROUGH; case SSE42: Builder.defineMacro("__SSE4_2__"); LLVM_FALLTHROUGH; case SSE41: Builder.defineMacro("__SSE4_1__"); LLVM_FALLTHROUGH; case SSSE3: Builder.defineMacro("__SSSE3__"); LLVM_FALLTHROUGH; case SSE3: Builder.defineMacro("__SSE3__"); LLVM_FALLTHROUGH; case SSE2: Builder.defineMacro("__SSE2__"); Builder.defineMacro("__SSE2_MATH__"); // -mfp-math=sse always implied. LLVM_FALLTHROUGH; case SSE1: Builder.defineMacro("__SSE__"); Builder.defineMacro("__SSE_MATH__"); // -mfp-math=sse always implied. LLVM_FALLTHROUGH; case NoSSE: break; } if (Opts.MicrosoftExt && getTriple().getArch() == llvm::Triple::x86) { switch (SSELevel) { case AVX512F: case AVX2: case AVX: case SSE42: case SSE41: case SSSE3: case SSE3: case SSE2: Builder.defineMacro("_M_IX86_FP", Twine(2)); break; case SSE1: Builder.defineMacro("_M_IX86_FP", Twine(1)); break; default: Builder.defineMacro("_M_IX86_FP", Twine(0)); break; } } // Each case falls through to the previous one here. switch (MMX3DNowLevel) { case AMD3DNowAthlon: Builder.defineMacro("__3dNOW_A__"); LLVM_FALLTHROUGH; case AMD3DNow: Builder.defineMacro("__3dNOW__"); LLVM_FALLTHROUGH; case MMX: Builder.defineMacro("__MMX__"); LLVM_FALLTHROUGH; case NoMMX3DNow: break; } if (CPU >= CK_i486 || CPU == CK_Generic) { Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); } if (HasCX8) Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); if (HasCX16 && getTriple().getArch() == llvm::Triple::x86_64) Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16"); if (HasFloat128) Builder.defineMacro("__SIZEOF_FLOAT128__", "16"); } bool X86TargetInfo::isValidFeatureName(StringRef Name) const { return llvm::StringSwitch(Name) .Case("3dnow", true) .Case("3dnowa", true) .Case("adx", true) .Case("aes", true) .Case("avx", true) .Case("avx2", true) .Case("avx512f", true) .Case("avx512cd", true) .Case("avx512vpopcntdq", true) .Case("avx512vnni", true) .Case("avx512bf16", true) .Case("avx512er", true) .Case("avx512pf", true) .Case("avx512dq", true) .Case("avx512bitalg", true) .Case("avx512bw", true) .Case("avx512vl", true) .Case("avx512vbmi", true) .Case("avx512vbmi2", true) .Case("avx512ifma", true) .Case("avx512vp2intersect", true) .Case("bmi", true) .Case("bmi2", true) .Case("cldemote", true) .Case("clflushopt", true) .Case("clwb", true) .Case("clzero", true) .Case("cx16", true) .Case("enqcmd", true) .Case("f16c", true) .Case("fma", true) .Case("fma4", true) .Case("fsgsbase", true) .Case("fxsr", true) .Case("gfni", true) .Case("invpcid", true) .Case("lwp", true) .Case("lzcnt", true) .Case("mmx", true) .Case("movbe", true) .Case("movdiri", true) .Case("movdir64b", true) .Case("mwaitx", true) .Case("pclmul", true) .Case("pconfig", true) .Case("pku", true) .Case("popcnt", true) .Case("prefetchwt1", true) .Case("prfchw", true) .Case("ptwrite", true) .Case("rdpid", true) .Case("rdrnd", true) .Case("rdseed", true) .Case("rtm", true) .Case("sahf", true) .Case("sgx", true) .Case("sha", true) .Case("shstk", true) .Case("sse", true) .Case("sse2", true) .Case("sse3", true) .Case("ssse3", true) .Case("sse4", true) .Case("sse4.1", true) .Case("sse4.2", true) .Case("sse4a", true) .Case("tbm", true) .Case("vaes", true) .Case("vpclmulqdq", true) .Case("wbnoinvd", true) .Case("waitpkg", true) .Case("x87", true) .Case("xop", true) .Case("xsave", true) .Case("xsavec", true) .Case("xsaves", true) .Case("xsaveopt", true) .Default(false); } bool X86TargetInfo::hasFeature(StringRef Feature) const { return llvm::StringSwitch(Feature) .Case("adx", HasADX) .Case("aes", HasAES) .Case("avx", SSELevel >= AVX) .Case("avx2", SSELevel >= AVX2) .Case("avx512f", SSELevel >= AVX512F) .Case("avx512cd", HasAVX512CD) .Case("avx512vpopcntdq", HasAVX512VPOPCNTDQ) .Case("avx512vnni", HasAVX512VNNI) .Case("avx512bf16", HasAVX512BF16) .Case("avx512er", HasAVX512ER) .Case("avx512pf", HasAVX512PF) .Case("avx512dq", HasAVX512DQ) .Case("avx512bitalg", HasAVX512BITALG) .Case("avx512bw", HasAVX512BW) .Case("avx512vl", HasAVX512VL) .Case("avx512vbmi", HasAVX512VBMI) .Case("avx512vbmi2", HasAVX512VBMI2) .Case("avx512ifma", HasAVX512IFMA) .Case("avx512vp2intersect", HasAVX512VP2INTERSECT) .Case("bmi", HasBMI) .Case("bmi2", HasBMI2) .Case("cldemote", HasCLDEMOTE) .Case("clflushopt", HasCLFLUSHOPT) .Case("clwb", HasCLWB) .Case("clzero", HasCLZERO) .Case("cx8", HasCX8) .Case("cx16", HasCX16) .Case("enqcmd", HasENQCMD) .Case("f16c", HasF16C) .Case("fma", HasFMA) .Case("fma4", XOPLevel >= FMA4) .Case("fsgsbase", HasFSGSBASE) .Case("fxsr", HasFXSR) .Case("gfni", HasGFNI) .Case("invpcid", HasINVPCID) .Case("lwp", HasLWP) .Case("lzcnt", HasLZCNT) .Case("mm3dnow", MMX3DNowLevel >= AMD3DNow) .Case("mm3dnowa", MMX3DNowLevel >= AMD3DNowAthlon) .Case("mmx", MMX3DNowLevel >= MMX) .Case("movbe", HasMOVBE) .Case("movdiri", HasMOVDIRI) .Case("movdir64b", HasMOVDIR64B) .Case("mwaitx", HasMWAITX) .Case("pclmul", HasPCLMUL) .Case("pconfig", HasPCONFIG) .Case("pku", HasPKU) .Case("popcnt", HasPOPCNT) .Case("prefetchwt1", HasPREFETCHWT1) .Case("prfchw", HasPRFCHW) .Case("ptwrite", HasPTWRITE) .Case("rdpid", HasRDPID) .Case("rdrnd", HasRDRND) .Case("rdseed", HasRDSEED) .Case("retpoline-external-thunk", HasRetpolineExternalThunk) .Case("rtm", HasRTM) .Case("sahf", HasLAHFSAHF) .Case("sgx", HasSGX) .Case("sha", HasSHA) .Case("shstk", HasSHSTK) .Case("sse", SSELevel >= SSE1) .Case("sse2", SSELevel >= SSE2) .Case("sse3", SSELevel >= SSE3) .Case("ssse3", SSELevel >= SSSE3) .Case("sse4.1", SSELevel >= SSE41) .Case("sse4.2", SSELevel >= SSE42) .Case("sse4a", XOPLevel >= SSE4A) .Case("tbm", HasTBM) .Case("vaes", HasVAES) .Case("vpclmulqdq", HasVPCLMULQDQ) .Case("wbnoinvd", HasWBNOINVD) .Case("waitpkg", HasWAITPKG) .Case("x86", true) .Case("x86_32", getTriple().getArch() == llvm::Triple::x86) .Case("x86_64", getTriple().getArch() == llvm::Triple::x86_64) .Case("xop", XOPLevel >= XOP) .Case("xsave", HasXSAVE) .Case("xsavec", HasXSAVEC) .Case("xsaves", HasXSAVES) .Case("xsaveopt", HasXSAVEOPT) .Default(false); } // We can't use a generic validation scheme for the features accepted here // versus subtarget features accepted in the target attribute because the // bitfield structure that's initialized in the runtime only supports the // below currently rather than the full range of subtarget features. (See // X86TargetInfo::hasFeature for a somewhat comprehensive list). bool X86TargetInfo::validateCpuSupports(StringRef FeatureStr) const { return llvm::StringSwitch(FeatureStr) #define X86_FEATURE_COMPAT(VAL, ENUM, STR) .Case(STR, true) #include "llvm/Support/X86TargetParser.def" .Default(false); } static llvm::X86::ProcessorFeatures getFeature(StringRef Name) { return llvm::StringSwitch(Name) #define X86_FEATURE_COMPAT(VAL, ENUM, STR) .Case(STR, llvm::X86::ENUM) #include "llvm/Support/X86TargetParser.def" ; // Note, this function should only be used after ensuring the value is // correct, so it asserts if the value is out of range. } static unsigned getFeaturePriority(llvm::X86::ProcessorFeatures Feat) { enum class FeatPriority { #define FEATURE(FEAT) FEAT, #include "clang/Basic/X86Target.def" }; switch (Feat) { #define FEATURE(FEAT) \ case llvm::X86::FEAT: \ return static_cast(FeatPriority::FEAT); #include "clang/Basic/X86Target.def" default: llvm_unreachable("No Feature Priority for non-CPUSupports Features"); } } unsigned X86TargetInfo::multiVersionSortPriority(StringRef Name) const { // Valid CPUs have a 'key feature' that compares just better than its key // feature. CPUKind Kind = getCPUKind(Name); if (Kind != CK_Generic) { switch (Kind) { default: llvm_unreachable( "CPU Type without a key feature used in 'target' attribute"); #define PROC_WITH_FEAT(ENUM, STR, IS64, KEY_FEAT) \ case CK_##ENUM: \ return (getFeaturePriority(llvm::X86::KEY_FEAT) << 1) + 1; #include "clang/Basic/X86Target.def" } } // Now we know we have a feature, so get its priority and shift it a few so // that we have sufficient room for the CPUs (above). return getFeaturePriority(getFeature(Name)) << 1; } bool X86TargetInfo::validateCPUSpecificCPUDispatch(StringRef Name) const { return llvm::StringSwitch(Name) #define CPU_SPECIFIC(NAME, MANGLING, FEATURES) .Case(NAME, true) #define CPU_SPECIFIC_ALIAS(NEW_NAME, NAME) .Case(NEW_NAME, true) #include "clang/Basic/X86Target.def" .Default(false); } static StringRef CPUSpecificCPUDispatchNameDealias(StringRef Name) { return llvm::StringSwitch(Name) #define CPU_SPECIFIC_ALIAS(NEW_NAME, NAME) .Case(NEW_NAME, NAME) #include "clang/Basic/X86Target.def" .Default(Name); } char X86TargetInfo::CPUSpecificManglingCharacter(StringRef Name) const { return llvm::StringSwitch(CPUSpecificCPUDispatchNameDealias(Name)) #define CPU_SPECIFIC(NAME, MANGLING, FEATURES) .Case(NAME, MANGLING) #include "clang/Basic/X86Target.def" .Default(0); } void X86TargetInfo::getCPUSpecificCPUDispatchFeatures( StringRef Name, llvm::SmallVectorImpl &Features) const { StringRef WholeList = llvm::StringSwitch(CPUSpecificCPUDispatchNameDealias(Name)) #define CPU_SPECIFIC(NAME, MANGLING, FEATURES) .Case(NAME, FEATURES) #include "clang/Basic/X86Target.def" .Default(""); WholeList.split(Features, ',', /*MaxSplit=*/-1, /*KeepEmpty=*/false); } // We can't use a generic validation scheme for the cpus accepted here // versus subtarget cpus accepted in the target attribute because the // variables intitialized by the runtime only support the below currently // rather than the full range of cpus. bool X86TargetInfo::validateCpuIs(StringRef FeatureStr) const { return llvm::StringSwitch(FeatureStr) #define X86_VENDOR(ENUM, STRING) .Case(STRING, true) #define X86_CPU_TYPE_COMPAT_WITH_ALIAS(ARCHNAME, ENUM, STR, ALIAS) \ .Cases(STR, ALIAS, true) #define X86_CPU_TYPE_COMPAT(ARCHNAME, ENUM, STR) .Case(STR, true) #define X86_CPU_SUBTYPE_COMPAT(ARCHNAME, ENUM, STR) .Case(STR, true) #include "llvm/Support/X86TargetParser.def" .Default(false); } static unsigned matchAsmCCConstraint(const char *&Name) { auto RV = llvm::StringSwitch(Name) .Case("@cca", 4) .Case("@ccae", 5) .Case("@ccb", 4) .Case("@ccbe", 5) .Case("@ccc", 4) .Case("@cce", 4) .Case("@ccz", 4) .Case("@ccg", 4) .Case("@ccge", 5) .Case("@ccl", 4) .Case("@ccle", 5) .Case("@ccna", 5) .Case("@ccnae", 6) .Case("@ccnb", 5) .Case("@ccnbe", 6) .Case("@ccnc", 5) .Case("@ccne", 5) .Case("@ccnz", 5) .Case("@ccng", 5) .Case("@ccnge", 6) .Case("@ccnl", 5) .Case("@ccnle", 6) .Case("@ccno", 5) .Case("@ccnp", 5) .Case("@ccns", 5) .Case("@cco", 4) .Case("@ccp", 4) .Case("@ccs", 4) .Default(0); return RV; } bool X86TargetInfo::validateAsmConstraint( const char *&Name, TargetInfo::ConstraintInfo &Info) const { switch (*Name) { default: return false; // Constant constraints. case 'e': // 32-bit signed integer constant for use with sign-extending x86_64 // instructions. case 'Z': // 32-bit unsigned integer constant for use with zero-extending // x86_64 instructions. case 's': Info.setRequiresImmediate(); return true; case 'I': Info.setRequiresImmediate(0, 31); return true; case 'J': Info.setRequiresImmediate(0, 63); return true; case 'K': Info.setRequiresImmediate(-128, 127); return true; case 'L': Info.setRequiresImmediate({int(0xff), int(0xffff), int(0xffffffff)}); return true; case 'M': Info.setRequiresImmediate(0, 3); return true; case 'N': Info.setRequiresImmediate(0, 255); return true; case 'O': Info.setRequiresImmediate(0, 127); return true; // Register constraints. case 'Y': // 'Y' is the first character for several 2-character constraints. // Shift the pointer to the second character of the constraint. Name++; switch (*Name) { default: return false; case 'z': case '0': // First SSE register. case '2': case 't': // Any SSE register, when SSE2 is enabled. case 'i': // Any SSE register, when SSE2 and inter-unit moves enabled. case 'm': // Any MMX register, when inter-unit moves enabled. case 'k': // AVX512 arch mask registers: k1-k7. Info.setAllowsRegister(); return true; } case 'f': // Any x87 floating point stack register. // Constraint 'f' cannot be used for output operands. if (Info.ConstraintStr[0] == '=') return false; Info.setAllowsRegister(); return true; case 'a': // eax. case 'b': // ebx. case 'c': // ecx. case 'd': // edx. case 'S': // esi. case 'D': // edi. case 'A': // edx:eax. case 't': // Top of floating point stack. case 'u': // Second from top of floating point stack. case 'q': // Any register accessible as [r]l: a, b, c, and d. case 'y': // Any MMX register. case 'v': // Any {X,Y,Z}MM register (Arch & context dependent) case 'x': // Any SSE register. case 'k': // Any AVX512 mask register (same as Yk, additionally allows k0 // for intermideate k reg operations). case 'Q': // Any register accessible as [r]h: a, b, c, and d. case 'R': // "Legacy" registers: ax, bx, cx, dx, di, si, sp, bp. case 'l': // "Index" registers: any general register that can be used as an // index in a base+index memory access. Info.setAllowsRegister(); return true; // Floating point constant constraints. case 'C': // SSE floating point constant. case 'G': // x87 floating point constant. return true; case '@': // CC condition changes. if (auto Len = matchAsmCCConstraint(Name)) { Name += Len - 1; Info.setAllowsRegister(); return true; } return false; } } bool X86TargetInfo::validateOutputSize(const llvm::StringMap &FeatureMap, StringRef Constraint, unsigned Size) const { // Strip off constraint modifiers. while (Constraint[0] == '=' || Constraint[0] == '+' || Constraint[0] == '&') Constraint = Constraint.substr(1); return validateOperandSize(FeatureMap, Constraint, Size); } bool X86TargetInfo::validateInputSize(const llvm::StringMap &FeatureMap, StringRef Constraint, unsigned Size) const { return validateOperandSize(FeatureMap, Constraint, Size); } bool X86TargetInfo::validateOperandSize(const llvm::StringMap &FeatureMap, StringRef Constraint, unsigned Size) const { switch (Constraint[0]) { default: break; case 'k': // Registers k0-k7 (AVX512) size limit is 64 bit. case 'y': return Size <= 64; case 'f': case 't': case 'u': return Size <= 128; case 'Y': // 'Y' is the first character for several 2-character constraints. switch (Constraint[1]) { default: return false; case 'm': // 'Ym' is synonymous with 'y'. case 'k': return Size <= 64; case 'z': case '0': // XMM0 if (FeatureMap.lookup("sse")) return Size <= 128U; return false; case 'i': case 't': case '2': // 'Yi','Yt','Y2' are synonymous with 'x' when SSE2 is enabled. if (SSELevel < SSE2) return false; break; } LLVM_FALLTHROUGH; case 'v': case 'x': if (FeatureMap.lookup("avx512f")) // 512-bit zmm registers can be used if target supports AVX512F. return Size <= 512U; else if (FeatureMap.lookup("avx")) // 256-bit ymm registers can be used if target supports AVX. return Size <= 256U; return Size <= 128U; } return true; } std::string X86TargetInfo::convertConstraint(const char *&Constraint) const { switch (*Constraint) { case '@': if (auto Len = matchAsmCCConstraint(Constraint)) { std::string Converted = "{" + std::string(Constraint, Len) + "}"; Constraint += Len - 1; return Converted; } return std::string(1, *Constraint); case 'a': return std::string("{ax}"); case 'b': return std::string("{bx}"); case 'c': return std::string("{cx}"); case 'd': return std::string("{dx}"); case 'S': return std::string("{si}"); case 'D': return std::string("{di}"); case 'p': // address return std::string("im"); case 't': // top of floating point stack. return std::string("{st}"); case 'u': // second from top of floating point stack. return std::string("{st(1)}"); // second from top of floating point stack. case 'Y': switch (Constraint[1]) { default: // Break from inner switch and fall through (copy single char), // continue parsing after copying the current constraint into // the return string. break; case 'k': case 'm': case 'i': case 't': case 'z': case '0': case '2': // "^" hints llvm that this is a 2 letter constraint. // "Constraint++" is used to promote the string iterator // to the next constraint. return std::string("^") + std::string(Constraint++, 2); } LLVM_FALLTHROUGH; default: return std::string(1, *Constraint); } } bool X86TargetInfo::checkCPUKind(CPUKind Kind) const { // Perform any per-CPU checks necessary to determine if this CPU is // acceptable. switch (Kind) { case CK_Generic: // No processor selected! return false; #define PROC(ENUM, STRING, IS64BIT) \ case CK_##ENUM: \ return IS64BIT || getTriple().getArch() == llvm::Triple::x86; #include "clang/Basic/X86Target.def" } llvm_unreachable("Unhandled CPU kind"); } void X86TargetInfo::fillValidCPUList(SmallVectorImpl &Values) const { #define PROC(ENUM, STRING, IS64BIT) \ if (IS64BIT || getTriple().getArch() == llvm::Triple::x86) \ Values.emplace_back(STRING); // For aliases we need to lookup the CPUKind to check get the 64-bit ness. #define PROC_ALIAS(ENUM, ALIAS) \ if (checkCPUKind(CK_##ENUM)) \ Values.emplace_back(ALIAS); #include "clang/Basic/X86Target.def" } X86TargetInfo::CPUKind X86TargetInfo::getCPUKind(StringRef CPU) const { return llvm::StringSwitch(CPU) #define PROC(ENUM, STRING, IS64BIT) .Case(STRING, CK_##ENUM) #define PROC_ALIAS(ENUM, ALIAS) .Case(ALIAS, CK_##ENUM) #include "clang/Basic/X86Target.def" .Default(CK_Generic); } ArrayRef X86TargetInfo::getGCCRegNames() const { return llvm::makeArrayRef(GCCRegNames); } ArrayRef X86TargetInfo::getGCCAddlRegNames() const { return llvm::makeArrayRef(AddlRegNames); } ArrayRef X86_32TargetInfo::getTargetBuiltins() const { return llvm::makeArrayRef(BuiltinInfoX86, clang::X86::LastX86CommonBuiltin - Builtin::FirstTSBuiltin + 1); } ArrayRef X86_64TargetInfo::getTargetBuiltins() const { return llvm::makeArrayRef(BuiltinInfoX86, X86::LastTSBuiltin - Builtin::FirstTSBuiltin); }