diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -52,6 +52,7 @@ #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/X86TargetParser.h" +#include "llvm/Transforms/Utils/X86EmitMultiVersionResolver.h" #include using namespace clang; @@ -12300,7 +12301,7 @@ Value *CodeGenFunction::EmitX86CpuIs(const CallExpr *E) { const Expr *CPUExpr = E->getArg(0)->IgnoreParenCasts(); StringRef CPUStr = cast(CPUExpr)->getString(); - return EmitX86CpuIs(CPUStr); + return llvm::X86::emitCpuIs(Builder, CPUStr); } // Convert F16 halfs to floats. @@ -12352,124 +12353,10 @@ return BitCast; } -Value *CodeGenFunction::EmitX86CpuIs(StringRef CPUStr) { - - llvm::Type *Int32Ty = Builder.getInt32Ty(); - - // Matching the struct layout from the compiler-rt/libgcc structure that is - // filled in: - // unsigned int __cpu_vendor; - // unsigned int __cpu_type; - // unsigned int __cpu_subtype; - // unsigned int __cpu_features[1]; - llvm::Type *STy = llvm::StructType::get(Int32Ty, Int32Ty, Int32Ty, - llvm::ArrayType::get(Int32Ty, 1)); - - // Grab the global __cpu_model. - llvm::Constant *CpuModel = CGM.CreateRuntimeVariable(STy, "__cpu_model"); - cast(CpuModel)->setDSOLocal(true); - - // Calculate the index needed to access the correct field based on the - // range. Also adjust the expected value. - unsigned Index; - unsigned Value; - std::tie(Index, Value) = StringSwitch>(CPUStr) -#define X86_VENDOR(ENUM, STRING) \ - .Case(STRING, {0u, static_cast(llvm::X86::ENUM)}) -#define X86_CPU_TYPE_ALIAS(ENUM, ALIAS) \ - .Case(ALIAS, {1u, static_cast(llvm::X86::ENUM)}) -#define X86_CPU_TYPE(ENUM, STR) \ - .Case(STR, {1u, static_cast(llvm::X86::ENUM)}) -#define X86_CPU_SUBTYPE(ENUM, STR) \ - .Case(STR, {2u, static_cast(llvm::X86::ENUM)}) -#include "llvm/Support/X86TargetParser.def" - .Default({0, 0}); - assert(Value != 0 && "Invalid CPUStr passed to CpuIs"); - - // Grab the appropriate field from __cpu_model. - llvm::Value *Idxs[] = {ConstantInt::get(Int32Ty, 0), - ConstantInt::get(Int32Ty, Index)}; - llvm::Value *CpuValue = Builder.CreateGEP(STy, CpuModel, Idxs); - CpuValue = Builder.CreateAlignedLoad(Int32Ty, CpuValue, - CharUnits::fromQuantity(4)); - - // Check the value of the field against the requested value. - return Builder.CreateICmpEQ(CpuValue, - llvm::ConstantInt::get(Int32Ty, Value)); -} - Value *CodeGenFunction::EmitX86CpuSupports(const CallExpr *E) { const Expr *FeatureExpr = E->getArg(0)->IgnoreParenCasts(); StringRef FeatureStr = cast(FeatureExpr)->getString(); - return EmitX86CpuSupports(FeatureStr); -} - -Value *CodeGenFunction::EmitX86CpuSupports(ArrayRef FeatureStrs) { - return EmitX86CpuSupports(llvm::X86::getCpuSupportsMask(FeatureStrs)); -} - -llvm::Value *CodeGenFunction::EmitX86CpuSupports(uint64_t FeaturesMask) { - uint32_t Features1 = Lo_32(FeaturesMask); - uint32_t Features2 = Hi_32(FeaturesMask); - - Value *Result = Builder.getTrue(); - - if (Features1 != 0) { - // Matching the struct layout from the compiler-rt/libgcc structure that is - // filled in: - // unsigned int __cpu_vendor; - // unsigned int __cpu_type; - // unsigned int __cpu_subtype; - // unsigned int __cpu_features[1]; - llvm::Type *STy = llvm::StructType::get(Int32Ty, Int32Ty, Int32Ty, - llvm::ArrayType::get(Int32Ty, 1)); - - // Grab the global __cpu_model. - llvm::Constant *CpuModel = CGM.CreateRuntimeVariable(STy, "__cpu_model"); - cast(CpuModel)->setDSOLocal(true); - - // Grab the first (0th) element from the field __cpu_features off of the - // global in the struct STy. - Value *Idxs[] = {Builder.getInt32(0), Builder.getInt32(3), - Builder.getInt32(0)}; - Value *CpuFeatures = Builder.CreateGEP(STy, CpuModel, Idxs); - Value *Features = Builder.CreateAlignedLoad(Int32Ty, CpuFeatures, - CharUnits::fromQuantity(4)); - - // Check the value of the bit corresponding to the feature requested. - Value *Mask = Builder.getInt32(Features1); - Value *Bitset = Builder.CreateAnd(Features, Mask); - Value *Cmp = Builder.CreateICmpEQ(Bitset, Mask); - Result = Builder.CreateAnd(Result, Cmp); - } - - if (Features2 != 0) { - llvm::Constant *CpuFeatures2 = CGM.CreateRuntimeVariable(Int32Ty, - "__cpu_features2"); - cast(CpuFeatures2)->setDSOLocal(true); - - Value *Features = Builder.CreateAlignedLoad(Int32Ty, CpuFeatures2, - CharUnits::fromQuantity(4)); - - // Check the value of the bit corresponding to the feature requested. - Value *Mask = Builder.getInt32(Features2); - Value *Bitset = Builder.CreateAnd(Features, Mask); - Value *Cmp = Builder.CreateICmpEQ(Bitset, Mask); - Result = Builder.CreateAnd(Result, Cmp); - } - - return Result; -} - -Value *CodeGenFunction::EmitX86CpuInit() { - llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, - /*Variadic*/ false); - llvm::FunctionCallee Func = - CGM.CreateRuntimeFunction(FTy, "__cpu_indicator_init"); - cast(Func.getCallee())->setDSOLocal(true); - cast(Func.getCallee()) - ->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass); - return Builder.CreateCall(Func); + return llvm::X86::emitCpuSupports(Builder, FeatureStr); } Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, @@ -12479,7 +12366,7 @@ if (BuiltinID == X86::BI__builtin_cpu_supports) return EmitX86CpuSupports(E); if (BuiltinID == X86::BI__builtin_cpu_init) - return EmitX86CpuInit(); + return llvm::X86::emitCPUInit(Builder); // Handle MSVC intrinsics before argument evaluation to prevent double // evaluation. diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -4707,27 +4707,6 @@ void EmitSanitizerStatReport(llvm::SanitizerStatKind SSK); - struct MultiVersionResolverOption { - llvm::Function *Function; - struct Conds { - StringRef Architecture; - llvm::SmallVector Features; - - Conds(StringRef Arch, ArrayRef Feats) - : Architecture(Arch), Features(Feats.begin(), Feats.end()) {} - } Conditions; - - MultiVersionResolverOption(llvm::Function *F, StringRef Arch, - ArrayRef Feats) - : Function(F), Conditions(Arch, Feats) {} - }; - - // Emits the body of a multiversion function's resolver. Assumes that the - // options are already sorted in the proper order, with the 'default' option - // last (if it exists). - void EmitMultiVersionResolver(llvm::Function *Resolver, - ArrayRef Options); - private: QualType getVarArgType(const Expr *Arg); @@ -4740,12 +4719,7 @@ llvm::Value *GetValueForARMHint(unsigned BuiltinID); llvm::Value *EmitX86CpuIs(const CallExpr *E); - llvm::Value *EmitX86CpuIs(StringRef CPUStr); llvm::Value *EmitX86CpuSupports(const CallExpr *E); - llvm::Value *EmitX86CpuSupports(ArrayRef FeatureStrs); - llvm::Value *EmitX86CpuSupports(uint64_t Mask); - llvm::Value *EmitX86CpuInit(); - llvm::Value *FormResolverCondition(const MultiVersionResolverOption &RO); }; /// TargetFeatures - This class is used to check whether the builtin function diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -45,6 +45,7 @@ #include "llvm/Support/CRC.h" #include "llvm/Transforms/Scalar/LowerExpectIntrinsic.h" #include "llvm/Transforms/Utils/PromoteMemToReg.h" +#include "llvm/Transforms/Utils/X86EmitMultiVersionResolver.h" using namespace clang; using namespace CodeGen; @@ -2533,86 +2534,6 @@ CGM.getSanStats().create(IRB, SSK); } -llvm::Value * -CodeGenFunction::FormResolverCondition(const MultiVersionResolverOption &RO) { - llvm::Value *Condition = nullptr; - - if (!RO.Conditions.Architecture.empty()) - Condition = EmitX86CpuIs(RO.Conditions.Architecture); - - if (!RO.Conditions.Features.empty()) { - llvm::Value *FeatureCond = EmitX86CpuSupports(RO.Conditions.Features); - Condition = - Condition ? Builder.CreateAnd(Condition, FeatureCond) : FeatureCond; - } - return Condition; -} - -static void CreateMultiVersionResolverReturn(CodeGenModule &CGM, - llvm::Function *Resolver, - CGBuilderTy &Builder, - llvm::Function *FuncToReturn, - bool SupportsIFunc) { - if (SupportsIFunc) { - Builder.CreateRet(FuncToReturn); - return; - } - - llvm::SmallVector Args; - llvm::for_each(Resolver->args(), - [&](llvm::Argument &Arg) { Args.push_back(&Arg); }); - - llvm::CallInst *Result = Builder.CreateCall(FuncToReturn, Args); - Result->setTailCallKind(llvm::CallInst::TCK_MustTail); - - if (Resolver->getReturnType()->isVoidTy()) - Builder.CreateRetVoid(); - else - Builder.CreateRet(Result); -} - -void CodeGenFunction::EmitMultiVersionResolver( - llvm::Function *Resolver, ArrayRef Options) { - assert(getContext().getTargetInfo().getTriple().isX86() && - "Only implemented for x86 targets"); - - bool SupportsIFunc = getContext().getTargetInfo().supportsIFunc(); - - // Main function's basic block. - llvm::BasicBlock *CurBlock = createBasicBlock("resolver_entry", Resolver); - Builder.SetInsertPoint(CurBlock); - EmitX86CpuInit(); - - for (const MultiVersionResolverOption &RO : Options) { - Builder.SetInsertPoint(CurBlock); - llvm::Value *Condition = FormResolverCondition(RO); - - // The 'default' or 'generic' case. - if (!Condition) { - assert(&RO == Options.end() - 1 && - "Default or Generic case must be last"); - CreateMultiVersionResolverReturn(CGM, Resolver, Builder, RO.Function, - SupportsIFunc); - return; - } - - llvm::BasicBlock *RetBlock = createBasicBlock("resolver_return", Resolver); - CGBuilderTy RetBuilder(*this, RetBlock); - CreateMultiVersionResolverReturn(CGM, Resolver, RetBuilder, RO.Function, - SupportsIFunc); - CurBlock = createBasicBlock("resolver_else", Resolver); - Builder.CreateCondBr(Condition, RetBlock, CurBlock); - } - - // If no generic/default, emit an unreachable. - Builder.SetInsertPoint(CurBlock); - llvm::CallInst *TrapCall = EmitTrapCall(llvm::Intrinsic::trap); - TrapCall->setDoesNotReturn(); - TrapCall->setDoesNotThrow(); - Builder.CreateUnreachable(); - Builder.ClearInsertionPoint(); -} - // Loc - where the diagnostic will point, where in the source code this // alignment has failed. // SecondaryLoc - if present (will be present if sufficiently different from diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -64,6 +64,7 @@ #include "llvm/Support/MD5.h" #include "llvm/Support/TimeProfiler.h" #include "llvm/Support/X86TargetParser.h" +#include "llvm/Transforms/Utils/X86EmitMultiVersionResolver.h" using namespace clang; using namespace CodeGen; @@ -3245,9 +3246,8 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old, llvm::Function *NewFn); -static unsigned -TargetMVPriority(const TargetInfo &TI, - const CodeGenFunction::MultiVersionResolverOption &RO) { +static unsigned TargetMVPriority(const TargetInfo &TI, + const llvm::MultiVersionResolverOption &RO) { unsigned Priority = 0; for (StringRef Feat : RO.Conditions.Features) Priority = std::max(Priority, TI.multiVersionSortPriority(Feat)); @@ -3262,7 +3262,7 @@ std::vector MVFuncsToEmit; MultiVersionFuncs.swap(MVFuncsToEmit); for (GlobalDecl GD : MVFuncsToEmit) { - SmallVector Options; + SmallVector Options; const FunctionDecl *FD = cast(GD.getDecl()); getContext().forEachMultiversionedFunctionVersion( FD, [this, &GD, &Options](const FunctionDecl *CurFD) { @@ -3308,12 +3308,12 @@ getModule().getOrInsertComdat(ResolverFunc->getName())); llvm::stable_sort( - Options, [&TI](const CodeGenFunction::MultiVersionResolverOption &LHS, - const CodeGenFunction::MultiVersionResolverOption &RHS) { + Options, [&TI](const llvm::MultiVersionResolverOption &LHS, + const llvm::MultiVersionResolverOption &RHS) { return TargetMVPriority(TI, LHS) > TargetMVPriority(TI, RHS); }); - CodeGenFunction CGF(*this); - CGF.EmitMultiVersionResolver(ResolverFunc, Options); + llvm::emitMultiVersionResolver( + ResolverFunc, Options, getContext().getTargetInfo().supportsIFunc()); } // Ensure that any additions to the deferred decls list caused by emitting a @@ -3361,7 +3361,7 @@ ResolverFunc->setComdat( getModule().getOrInsertComdat(ResolverFunc->getName())); - SmallVector Options; + SmallVector Options; const TargetInfo &Target = getTarget(); unsigned Index = 0; for (const IdentifierInfo *II : DD->cpus()) { @@ -3400,12 +3400,11 @@ ++Index; } - llvm::stable_sort( - Options, [](const CodeGenFunction::MultiVersionResolverOption &LHS, - const CodeGenFunction::MultiVersionResolverOption &RHS) { - return llvm::X86::getCpuSupportsMask(LHS.Conditions.Features) > - llvm::X86::getCpuSupportsMask(RHS.Conditions.Features); - }); + llvm::stable_sort(Options, [](const llvm::MultiVersionResolverOption &LHS, + const llvm::MultiVersionResolverOption &RHS) { + return llvm::X86::getCpuSupportsMask(LHS.Conditions.Features) > + llvm::X86::getCpuSupportsMask(RHS.Conditions.Features); + }); // If the list contains multiple 'default' versions, such as when it contains // 'pentium' and 'generic', don't emit the call to the generic one (since we @@ -3414,16 +3413,16 @@ while (Options.size() > 1 && llvm::X86::getCpuSupportsMask( (Options.end() - 2)->Conditions.Features) == 0) { - StringRef LHSName = (Options.end() - 2)->Function->getName(); - StringRef RHSName = (Options.end() - 1)->Function->getName(); + StringRef LHSName = (Options.end() - 2)->Fn->getName(); + StringRef RHSName = (Options.end() - 1)->Fn->getName(); if (LHSName.compare(RHSName) < 0) Options.erase(Options.end() - 2); else Options.erase(Options.end() - 1); } - CodeGenFunction CGF(*this); - CGF.EmitMultiVersionResolver(ResolverFunc, Options); + llvm::emitMultiVersionResolver(ResolverFunc, Options, + getContext().getTargetInfo().supportsIFunc()); if (getTarget().supportsIFunc()) { std::string AliasName = getMangledNameImpl( diff --git a/llvm/include/llvm/Transforms/Utils/X86EmitMultiVersionResolver.h b/llvm/include/llvm/Transforms/Utils/X86EmitMultiVersionResolver.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/Transforms/Utils/X86EmitMultiVersionResolver.h @@ -0,0 +1,55 @@ +//===-- X86EmitMultiVersionResolver -----------------------------*- C++ -*-===// +// +// 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 utitlities to generate code used for CPU dispatch code. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_UTILS_X86EMITMULTIVERSIONRESOLVER_H +#define LLVM_TRANSFORMS_UTILS_X86EMITMULTIVERSIONRESOLVER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" + +namespace llvm { +class Value; +class Function; +class IRBuilderBase; + +struct MultiVersionResolverOption { + Function *Fn; + struct Conds { + StringRef Architecture; + llvm::SmallVector Features; + + Conds(StringRef Arch, ArrayRef Feats) + : Architecture(Arch), Features(Feats.begin(), Feats.end()) {} + } Conditions; + + MultiVersionResolverOption(Function *Fn, StringRef Arch, + ArrayRef Feats) + : Fn(Fn), Conditions(Arch, Feats) {} +}; + +// Emits the body of a multiversion function's resolver. Assumes that the +// options are already sorted in the proper order, with the 'default' option +// last (if it exists). +void emitMultiVersionResolver(Function *Resolver, + ArrayRef Options, + bool UseIFunc); +Value *formResolverCondition(IRBuilderBase &Builder, + const MultiVersionResolverOption &RO); +namespace X86 { +Value *emitCPUInit(IRBuilderBase &Builder); +Value *emitCpuIs(IRBuilderBase &Builder, StringRef CPUStr); +Value *emitCpuSupports(IRBuilderBase &Builder, uint64_t FeaturesMask); +Value *emitCpuSupports(IRBuilderBase &Builder, ArrayRef FeatureStrs); +} // namespace X86 +} // namespace llvm + +#endif diff --git a/llvm/lib/Transforms/Utils/CMakeLists.txt b/llvm/lib/Transforms/Utils/CMakeLists.txt --- a/llvm/lib/Transforms/Utils/CMakeLists.txt +++ b/llvm/lib/Transforms/Utils/CMakeLists.txt @@ -74,6 +74,7 @@ Utils.cpp ValueMapper.cpp VNCoercion.cpp + X86EmitMultiVersionResolver.cpp ADDITIONAL_HEADER_DIRS ${LLVM_MAIN_INCLUDE_DIR}/llvm/Transforms diff --git a/llvm/lib/Transforms/Utils/X86EmitMultiVersionResolver.cpp b/llvm/lib/Transforms/Utils/X86EmitMultiVersionResolver.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Transforms/Utils/X86EmitMultiVersionResolver.cpp @@ -0,0 +1,227 @@ +//===-- X86EmitMultiVersionResolver -----------------------------*- C++ -*-===// +// +// 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 utitlities to generate code used for CPU dispatch code. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/Utils/X86EmitMultiVersionResolver.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Type.h" +#include "llvm/Support/X86TargetParser.h" + +using namespace llvm; +using namespace llvm::X86; + +Value *llvm::formResolverCondition(IRBuilderBase &Builder, + const MultiVersionResolverOption &RO) { + llvm::Value *Condition = nullptr; + + if (!RO.Conditions.Architecture.empty()) + Condition = llvm::X86::emitCpuIs(Builder, RO.Conditions.Architecture); + if (!RO.Conditions.Features.empty()) { + llvm::Value *FeatureCond = + llvm::X86::emitCpuSupports(Builder, RO.Conditions.Features); + Condition = + Condition ? Builder.CreateAnd(Condition, FeatureCond) : FeatureCond; + } + return Condition; +} + +static void CreateMultiVersionResolverReturn(Function *Resolver, + IRBuilderBase &Builder, + Function *FuncToReturn, + bool UseIFunc) { + if (UseIFunc) { + Builder.CreateRet(FuncToReturn); + return; + } + + SmallVector Args; + for_each(Resolver->args(), [&](Argument &Arg) { Args.push_back(&Arg); }); + + CallInst *Result = Builder.CreateCall(FuncToReturn, Args); + Result->setTailCallKind(CallInst::TCK_MustTail); + + if (Resolver->getReturnType()->isVoidTy()) + Builder.CreateRetVoid(); + else + Builder.CreateRet(Result); +} + +void llvm::emitMultiVersionResolver( + Function *Resolver, ArrayRef Options, + bool UseIFunc) { + assert(Triple(Resolver->getParent()->getTargetTriple()).isX86() && + "Only implemented for x86 targets"); + + auto &Ctx = Resolver->getContext(); + // Main function's basic block. + BasicBlock *CurBlock = BasicBlock::Create(Ctx, "resolver_entry", Resolver); + + IRBuilder<> Builder(CurBlock, CurBlock->begin()); + llvm::X86::emitCPUInit(Builder); + + for (const MultiVersionResolverOption &RO : Options) { + Builder.SetInsertPoint(CurBlock); + llvm::Value *Condition = formResolverCondition(Builder, RO); + + // The 'default' or 'generic' case. + if (!Condition) { + assert(&RO == Options.end() - 1 && + "Default or Generic case must be last"); + CreateMultiVersionResolverReturn(Resolver, Builder, RO.Fn, UseIFunc); + return; + } + + llvm::BasicBlock *RetBlock = + BasicBlock::Create(Ctx, "resolver_return", Resolver); + { + IRBuilderBase::InsertPointGuard Guard(Builder); + Builder.SetInsertPoint(RetBlock); + CreateMultiVersionResolverReturn(Resolver, Builder, RO.Fn, UseIFunc); + } + CurBlock = BasicBlock::Create(Ctx, "resolver_else", Resolver); + Builder.CreateCondBr(Condition, RetBlock, CurBlock); + } + + // If no generic/default, emit an unreachable. + Builder.SetInsertPoint(CurBlock); + CallInst *TrapCall = Builder.CreateIntrinsic(Intrinsic::trap, {}, {}); + TrapCall->setDoesNotReturn(); + TrapCall->setDoesNotThrow(); + Builder.CreateUnreachable(); +} + +static Type *getCpuModelType(IRBuilderBase &Builder) { + Type *Int32Ty = Builder.getInt32Ty(); + + // Matching the struct layout from the compiler-rt/libgcc structure that is + // filled in: + // unsigned int __cpu_vendor; + // unsigned int __cpu_type; + // unsigned int __cpu_subtype; + // unsigned int __cpu_features[1]; + Type *STy = + StructType::get(Int32Ty, Int32Ty, Int32Ty, ArrayType::get(Int32Ty, 1)); + return STy; +} + +static Value *getOrCreateGlobal(IRBuilderBase &Builder, StringRef Name, + Type *Ty) { + Module *M = Builder.GetInsertBlock()->getParent()->getParent(); + if (GlobalValue *Val = M->getNamedValue(Name)) { + return Val; + } + + auto *New = new GlobalVariable( + *M, Ty, false, GlobalValue::ExternalLinkage, nullptr, Name, nullptr, + GlobalVariable::NotThreadLocal, 0 /* AddressSpace */); + New->setDSOLocal(true); + return New; +} + +Value *llvm::X86::emitCPUInit(IRBuilderBase &Builder) { + FunctionType *FTy = FunctionType::get(Builder.getVoidTy(), + /*Variadic*/ false); + Module *M = Builder.GetInsertBlock()->getParent()->getParent(); + GlobalValue *Entry = M->getNamedValue("__cpu_indicator_init"); + if (Entry) { + // TODO: asserts and possibly return nullptr if something bad. + return Builder.CreateCall(cast(Entry)); + } + + Function *F = Function::Create(FTy, Function::ExternalLinkage, + "__cpu_indicator_init", M); + + F->setDSOLocal(true); + F->setDLLStorageClass(GlobalValue::DefaultStorageClass); + return Builder.CreateCall(F); +} + +Value *llvm::X86::emitCpuIs(IRBuilderBase &Builder, StringRef CPUStr) { + // Calculate the index needed to access the correct field based on the + // range. Also adjust the expected value. + unsigned Index; + unsigned Val; + std::tie(Index, Val) = StringSwitch>(CPUStr) +#define X86_VENDOR(ENUM, STRING) \ + .Case(STRING, {0u, static_cast(llvm::X86::ENUM)}) +#define X86_CPU_TYPE_ALIAS(ENUM, ALIAS) \ + .Case(ALIAS, {1u, static_cast(llvm::X86::ENUM)}) +#define X86_CPU_TYPE(ENUM, STR) \ + .Case(STR, {1u, static_cast(llvm::X86::ENUM)}) +#define X86_CPU_SUBTYPE(ENUM, STR) \ + .Case(STR, {2u, static_cast(llvm::X86::ENUM)}) +#include "llvm/Support/X86TargetParser.def" + .Default({0, 0}); + assert(Val != 0 && "Invalid CPUStr passed to CpuIs"); + + // Grab the appropriate field from __cpu_model. + Value *Idxs[] = {Builder.getInt32(0), Builder.getInt32(Index)}; + Type *CpuModelType = getCpuModelType(Builder); + Value *CpuValue = Builder.CreateGEP( + CpuModelType, getOrCreateGlobal(Builder, "__cpu_model", CpuModelType), + Idxs); + CpuValue = + Builder.CreateAlignedLoad(Builder.getInt32Ty(), CpuValue, MaybeAlign(4)); + + // Check the value of the field against the requested value. + return Builder.CreateICmpEQ(CpuValue, Builder.getInt32(Val)); +} + +Value *llvm::X86::emitCpuSupports(IRBuilderBase &Builder, + uint64_t FeaturesMask) { + uint32_t Features1 = Lo_32(FeaturesMask); + uint32_t Features2 = Hi_32(FeaturesMask); + + Value *Result = Builder.getTrue(); + Type *Int32Ty = Builder.getInt32Ty(); + Type *CpuModelType = getCpuModelType(Builder); + + if (Features1 != 0) { + Value *CpuModel = getOrCreateGlobal(Builder, "__cpu_model", CpuModelType); + + // Grab the first (0th) element from the field __cpu_features off of the + // global in the struct STy. + Value *Idxs[] = {Builder.getInt32(0), Builder.getInt32(3), + Builder.getInt32(0)}; + Value *CpuFeatures = Builder.CreateGEP(CpuModelType, CpuModel, Idxs); + Value *Features = + Builder.CreateAlignedLoad(Int32Ty, CpuFeatures, MaybeAlign(4)); + + // Check the value of the bit corresponding to the feature requested. + Value *Mask = Builder.getInt32(Features1); + Value *Bitset = Builder.CreateAnd(Features, Mask); + Value *Cmp = Builder.CreateICmpEQ(Bitset, Mask); + Result = Builder.CreateAnd(Result, Cmp); + } + + if (Features2 != 0) { + Value *CpuFeatures2 = + getOrCreateGlobal(Builder, "__cpu_features2", Int32Ty); + + Value *Features = + Builder.CreateAlignedLoad(Int32Ty, CpuFeatures2, Align(4)); + + // Check the value of the bit corresponding to the feature requested. + Value *Mask = Builder.getInt32(Features2); + Value *Bitset = Builder.CreateAnd(Features, Mask); + Value *Cmp = Builder.CreateICmpEQ(Bitset, Mask); + Result = Builder.CreateAnd(Result, Cmp); + } + + return Result; +} + +Value *llvm::X86::emitCpuSupports(IRBuilderBase &Builder, + ArrayRef FeatureStrs) { + return emitCpuSupports(Builder, getCpuSupportsMask(FeatureStrs)); +}