diff options
Diffstat (limited to 'clang/lib/CodeGen/CGBuiltin.cpp')
| -rw-r--r-- | clang/lib/CodeGen/CGBuiltin.cpp | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 1a9ff26d83d..2c8a6e0737e 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -7287,8 +7287,125 @@ static Value *EmitX86SExtMask(CodeGenFunction &CGF, Value *Op, return CGF.Builder.CreateSExt(Mask, DstTy, "vpmovm2"); } +static Value *EmitX86CpuIs(CodeGenFunction &CGF, const CallExpr *E) { + const Expr *CPUExpr = E->getArg(0)->IgnoreParenCasts(); + StringRef CPUStr = cast<clang::StringLiteral>(CPUExpr)->getString(); + + // This enum contains the vendor, type, and subtype enums from the + // runtime library concatenated together. The _START labels mark + // the start and are used to adjust the value into the correct + // encoding space. + enum X86CPUs { + INTEL = 1, + AMD, + CPU_TYPE_START, + INTEL_BONNELL, + INTEL_CORE2, + INTEL_COREI7, + AMDFAM10H, + AMDFAM15H, + INTEL_SILVERMONT, + INTEL_KNL, + AMD_BTVER1, + AMD_BTVER2, + CPU_SUBTYPE_START, + INTEL_COREI7_NEHALEM, + INTEL_COREI7_WESTMERE, + INTEL_COREI7_SANDYBRIDGE, + AMDFAM10H_BARCELONA, + AMDFAM10H_SHANGHAI, + AMDFAM10H_ISTANBUL, + AMDFAM15H_BDVER1, + AMDFAM15H_BDVER2, + AMDFAM15H_BDVER3, + AMDFAM15H_BDVER4, + AMDFAM17H_ZNVER1, + INTEL_COREI7_IVYBRIDGE, + INTEL_COREI7_HASWELL, + INTEL_COREI7_BROADWELL, + INTEL_COREI7_SKYLAKE, + INTEL_COREI7_SKYLAKE_AVX512, + }; + + X86CPUs CPU = + StringSwitch<X86CPUs>(CPUStr) + .Case("amd", AMD) + .Case("amdfam10h", AMDFAM10H) + .Case("amdfam15h", AMDFAM15H) + .Case("atom", INTEL_BONNELL) + .Case("barcelona", AMDFAM10H_BARCELONA) + .Case("bdver1", AMDFAM15H_BDVER1) + .Case("bdver2", AMDFAM15H_BDVER2) + .Case("bdver3", AMDFAM15H_BDVER3) + .Case("bdver4", AMDFAM15H_BDVER4) + .Case("bonnell", INTEL_BONNELL) + .Case("broadwell", INTEL_COREI7_BROADWELL) + .Case("btver1", AMD_BTVER1) + .Case("btver2", AMD_BTVER2) + .Case("core2", INTEL_CORE2) + .Case("corei7", INTEL_COREI7) + .Case("haswell", INTEL_COREI7_HASWELL) + .Case("intel", INTEL) + .Case("istanbul", AMDFAM10H_ISTANBUL) + .Case("ivybridge", INTEL_COREI7_IVYBRIDGE) + .Case("knl", INTEL_KNL) + .Case("nehalem", INTEL_COREI7_NEHALEM) + .Case("sandybridge", INTEL_COREI7_SANDYBRIDGE) + .Case("shanghai", AMDFAM10H_SHANGHAI) + .Case("silvermont", INTEL_SILVERMONT) + .Case("skylake", INTEL_COREI7_SKYLAKE) + .Case("skylake-avx512", INTEL_COREI7_SKYLAKE_AVX512) + .Case("slm", INTEL_SILVERMONT) + .Case("westmere", INTEL_COREI7_WESTMERE) + .Case("znver1", AMDFAM17H_ZNVER1); + + llvm::Type *Int32Ty = CGF.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 = CGF.CGM.CreateRuntimeVariable(STy, "__cpu_model"); + + // Calculate the index needed to access the correct field based on the + // range. Also adjust the expected value. + unsigned Index; + unsigned Value; + if (CPU > CPU_SUBTYPE_START) { + Index = 2; + Value = CPU - CPU_SUBTYPE_START; + } else if (CPU > CPU_TYPE_START) { + Index = 1; + Value = CPU - CPU_TYPE_START; + } else { + Index = 0; + Value = CPU; + } + + // Grab the appropriate field from __cpu_model. + llvm::Value *Idxs[] = { + 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)); + + // Check the value of the field against the requested value. + return CGF.Builder.CreateICmpEQ(CpuValue, + llvm::ConstantInt::get(Int32Ty, Value)); +} + Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, const CallExpr *E) { + if (BuiltinID == X86::BI__builtin_cpu_is) + return EmitX86CpuIs(*this, E); + SmallVector<Value*, 4> Ops; // Find out if any arguments are required to be integer constant expressions. |

