From: Erich Keane Date: Fri, 1 Sep 2017 19:42:45 +0000 (+0000) Subject: [CodeGen]Refactor CpuSupports/CPUIs Builtin Code Gen to better work with X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=371351289d7eef8673fd1c579689b6057738cc21;p=clang [CodeGen]Refactor CpuSupports/CPUIs Builtin Code Gen to better work with "target" implementation A small set of refactors that'll make it easier for me to implement 'target' support. First, extract the CPUSupports functionality into its own function. THis has the advantage of not wasting time in this builtin to deal with arguments. Second, pulls both CPUSupports and CPUIs implementation into a member-function, so that it can be called from the resolver generation that I'm working on. Third, creates an overload that takes simply the feature/cpu name (rather than extracting it from a callexpr), since that info isn't available later. Note that despite how the 'diff' looks, the EmitX86CPUSupports function simply takes the implementation out of the 'switch'. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@312355 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index 9ced44b2e0..e6ae74a73c 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -7288,9 +7288,13 @@ static Value *EmitX86SExtMask(CodeGenFunction &CGF, Value *Op, return CGF.Builder.CreateSExt(Mask, DstTy, "vpmovm2"); } -static Value *EmitX86CpuIs(CodeGenFunction &CGF, const CallExpr *E) { +Value *CodeGenFunction::EmitX86CpuIs(const CallExpr *E) { const Expr *CPUExpr = E->getArg(0)->IgnoreParenCasts(); StringRef CPUStr = cast(CPUExpr)->getString(); + return EmitX86CpuIs(CPUStr); +} + +Value *CodeGenFunction::EmitX86CpuIs(StringRef CPUStr) { // This enum contains the vendor, type, and subtype enums from the // runtime library concatenated together. The _START labels mark @@ -7332,7 +7336,9 @@ static Value *EmitX86CpuIs(CodeGenFunction &CGF, const CallExpr *E) { StringSwitch(CPUStr) .Case("amd", AMD) .Case("amdfam10h", AMDFAM10H) + .Case("amdfam10", AMDFAM10H) .Case("amdfam15h", AMDFAM15H) + .Case("amdfam15", AMDFAM15H) .Case("atom", INTEL_BONNELL) .Case("barcelona", AMDFAM10H_BARCELONA) .Case("bdver1", AMDFAM15H_BDVER1) @@ -7360,7 +7366,7 @@ static Value *EmitX86CpuIs(CodeGenFunction &CGF, const CallExpr *E) { .Case("westmere", INTEL_COREI7_WESTMERE) .Case("znver1", AMDFAM17H_ZNVER1); - llvm::Type *Int32Ty = CGF.Builder.getInt32Ty(); + llvm::Type *Int32Ty = Builder.getInt32Ty(); // Matching the struct layout from the compiler-rt/libgcc structure that is // filled in: @@ -7372,7 +7378,7 @@ static Value *EmitX86CpuIs(CodeGenFunction &CGF, const CallExpr *E) { llvm::ArrayType::get(Int32Ty, 1)); // Grab the global __cpu_model. - llvm::Constant *CpuModel = CGF.CGM.CreateRuntimeVariable(STy, "__cpu_model"); + llvm::Constant *CpuModel = CGM.CreateRuntimeVariable(STy, "__cpu_model"); // Calculate the index needed to access the correct field based on the // range. Also adjust the expected value. @@ -7394,16 +7400,133 @@ static Value *EmitX86CpuIs(CodeGenFunction &CGF, const CallExpr *E) { ConstantInt::get(Int32Ty, 0), ConstantInt::get(Int32Ty, Index) }; - llvm::Value *CpuValue = CGF.Builder.CreateGEP(STy, CpuModel, Idxs); - CpuValue = CGF.Builder.CreateAlignedLoad(CpuValue, CharUnits::fromQuantity(4)); + llvm::Value *CpuValue = Builder.CreateGEP(STy, CpuModel, Idxs); + CpuValue = Builder.CreateAlignedLoad(CpuValue, CharUnits::fromQuantity(4)); // Check the value of the field against the requested value. - return CGF.Builder.CreateICmpEQ(CpuValue, + 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) { + // TODO: When/if this becomes more than x86 specific then use a TargetInfo + // based mapping. + // Processor features and mapping to processor feature value. + enum X86Features { + CMOV = 0, + MMX, + POPCNT, + SSE, + SSE2, + SSE3, + SSSE3, + SSE4_1, + SSE4_2, + AVX, + AVX2, + SSE4_A, + FMA4, + XOP, + FMA, + AVX512F, + BMI, + BMI2, + AES, + PCLMUL, + AVX512VL, + AVX512BW, + AVX512DQ, + AVX512CD, + AVX512ER, + AVX512PF, + AVX512VBMI, + AVX512IFMA, + AVX5124VNNIW, + AVX5124FMAPS, + AVX512VPOPCNTDQ, + MAX + }; + + uint32_t FeaturesMask = 0; + + for (const StringRef &FeatureStr : FeatureStrs) { + X86Features Feature = + StringSwitch(FeatureStr) + .Case("cmov", X86Features::CMOV) + .Case("mmx", X86Features::MMX) + .Case("popcnt", X86Features::POPCNT) + .Case("sse", X86Features::SSE) + .Case("sse2", X86Features::SSE2) + .Case("sse3", X86Features::SSE3) + .Case("ssse3", X86Features::SSSE3) + .Case("sse4.1", X86Features::SSE4_1) + .Case("sse4.2", X86Features::SSE4_2) + .Case("avx", X86Features::AVX) + .Case("avx2", X86Features::AVX2) + .Case("sse4a", X86Features::SSE4_A) + .Case("fma4", X86Features::FMA4) + .Case("xop", X86Features::XOP) + .Case("fma", X86Features::FMA) + .Case("avx512f", X86Features::AVX512F) + .Case("bmi", X86Features::BMI) + .Case("bmi2", X86Features::BMI2) + .Case("aes", X86Features::AES) + .Case("pclmul", X86Features::PCLMUL) + .Case("avx512vl", X86Features::AVX512VL) + .Case("avx512bw", X86Features::AVX512BW) + .Case("avx512dq", X86Features::AVX512DQ) + .Case("avx512cd", X86Features::AVX512CD) + .Case("avx512er", X86Features::AVX512ER) + .Case("avx512pf", X86Features::AVX512PF) + .Case("avx512vbmi", X86Features::AVX512VBMI) + .Case("avx512ifma", X86Features::AVX512IFMA) + .Case("avx5124vnniw", X86Features::AVX5124VNNIW) + .Case("avx5124fmaps", X86Features::AVX5124FMAPS) + .Case("avx512vpopcntdq", X86Features::AVX512VPOPCNTDQ) + .Default(X86Features::MAX); + assert(Feature != X86Features::MAX && "Invalid feature!"); + FeaturesMask |= (1U << Feature); + } + + // 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"); + + // Grab the first (0th) element from the field __cpu_features off of the + // global in the struct STy. + Value *Idxs[] = {ConstantInt::get(Int32Ty, 0), ConstantInt::get(Int32Ty, 3), + ConstantInt::get(Int32Ty, 0)}; + Value *CpuFeatures = Builder.CreateGEP(STy, CpuModel, Idxs); + Value *Features = + Builder.CreateAlignedLoad(CpuFeatures, CharUnits::fromQuantity(4)); + + // Check the value of the bit corresponding to the feature requested. + Value *Bitset = Builder.CreateAnd( + Features, llvm::ConstantInt::get(Int32Ty, FeaturesMask)); + return Builder.CreateICmpNE(Bitset, llvm::ConstantInt::get(Int32Ty, 0)); +} + Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, const CallExpr *E) { + if (BuiltinID == X86::BI__builtin_cpu_is) + return EmitX86CpuIs(E); + if (BuiltinID == X86::BI__builtin_cpu_supports) + return EmitX86CpuSupports(E); + SmallVector Ops; // Find out if any arguments are required to be integer constant expressions. @@ -7461,114 +7584,6 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, "__cpu_indicator_init"); return Builder.CreateCall(Func); } - case X86::BI__builtin_cpu_is: - return EmitX86CpuIs(*this, E); - case X86::BI__builtin_cpu_supports: { - const Expr *FeatureExpr = E->getArg(0)->IgnoreParenCasts(); - StringRef FeatureStr = cast(FeatureExpr)->getString(); - - // TODO: When/if this becomes more than x86 specific then use a TargetInfo - // based mapping. - // Processor features and mapping to processor feature value. - enum X86Features { - CMOV = 0, - MMX, - POPCNT, - SSE, - SSE2, - SSE3, - SSSE3, - SSE4_1, - SSE4_2, - AVX, - AVX2, - SSE4_A, - FMA4, - XOP, - FMA, - AVX512F, - BMI, - BMI2, - AES, - PCLMUL, - AVX512VL, - AVX512BW, - AVX512DQ, - AVX512CD, - AVX512ER, - AVX512PF, - AVX512VBMI, - AVX512IFMA, - AVX5124VNNIW, - AVX5124FMAPS, - AVX512VPOPCNTDQ, - MAX - }; - - X86Features Feature = - StringSwitch(FeatureStr) - .Case("cmov", X86Features::CMOV) - .Case("mmx", X86Features::MMX) - .Case("popcnt", X86Features::POPCNT) - .Case("sse", X86Features::SSE) - .Case("sse2", X86Features::SSE2) - .Case("sse3", X86Features::SSE3) - .Case("ssse3", X86Features::SSSE3) - .Case("sse4.1", X86Features::SSE4_1) - .Case("sse4.2", X86Features::SSE4_2) - .Case("avx", X86Features::AVX) - .Case("avx2", X86Features::AVX2) - .Case("sse4a", X86Features::SSE4_A) - .Case("fma4", X86Features::FMA4) - .Case("xop", X86Features::XOP) - .Case("fma", X86Features::FMA) - .Case("avx512f", X86Features::AVX512F) - .Case("bmi", X86Features::BMI) - .Case("bmi2", X86Features::BMI2) - .Case("aes", X86Features::AES) - .Case("pclmul", X86Features::PCLMUL) - .Case("avx512vl", X86Features::AVX512VL) - .Case("avx512bw", X86Features::AVX512BW) - .Case("avx512dq", X86Features::AVX512DQ) - .Case("avx512cd", X86Features::AVX512CD) - .Case("avx512er", X86Features::AVX512ER) - .Case("avx512pf", X86Features::AVX512PF) - .Case("avx512vbmi", X86Features::AVX512VBMI) - .Case("avx512ifma", X86Features::AVX512IFMA) - .Case("avx5124vnniw", X86Features::AVX5124VNNIW) - .Case("avx5124fmaps", X86Features::AVX5124FMAPS) - .Case("avx512vpopcntdq", X86Features::AVX512VPOPCNTDQ) - .Default(X86Features::MAX); - assert(Feature != X86Features::MAX && "Invalid feature!"); - - // 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"); - - // Grab the first (0th) element from the field __cpu_features off of the - // global in the struct STy. - Value *Idxs[] = { - ConstantInt::get(Int32Ty, 0), - ConstantInt::get(Int32Ty, 3), - ConstantInt::get(Int32Ty, 0) - }; - Value *CpuFeatures = Builder.CreateGEP(STy, CpuModel, Idxs); - Value *Features = Builder.CreateAlignedLoad(CpuFeatures, - CharUnits::fromQuantity(4)); - - // Check the value of the bit corresponding to the feature requested. - Value *Bitset = Builder.CreateAnd( - Features, llvm::ConstantInt::get(Int32Ty, 1ULL << Feature)); - return Builder.CreateICmpNE(Bitset, llvm::ConstantInt::get(Int32Ty, 0)); - } case X86::BI_mm_prefetch: { Value *Address = Ops[0]; Value *RW = ConstantInt::get(Int32Ty, 0); diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 28253ff985..da68074a70 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -3857,6 +3857,10 @@ private: void AddObjCARCExceptionMetadata(llvm::Instruction *Inst); 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); }; /// Helper class with most of the code for saving a value for a