diff options
| author | Craig Topper <craig.topper@intel.com> | 2017-08-10 20:28:30 +0000 |
|---|---|---|
| committer | Craig Topper <craig.topper@intel.com> | 2017-08-10 20:28:30 +0000 |
| commit | 699ae0c173bd9f9a38523a7de354f5e9cc602ecc (patch) | |
| tree | ef9abdeee56670c011dd15c7696f954d59bc1f00 /clang/lib | |
| parent | 4d28c0ff4f1790edf49b41ebc368de95223ea259 (diff) | |
| download | bcm5719-llvm-699ae0c173bd9f9a38523a7de354f5e9cc602ecc.tar.gz bcm5719-llvm-699ae0c173bd9f9a38523a7de354f5e9cc602ecc.zip | |
[X86] Implement __builtin_cpu_is
This patch adds support for __builtin_cpu_is. I've tried to match the strings supported to the latest version of gcc.
Differential Revision: https://reviews.llvm.org/D35449
llvm-svn: 310657
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/Basic/Targets/X86.cpp | 38 | ||||
| -rw-r--r-- | clang/lib/Basic/Targets/X86.h | 2 | ||||
| -rw-r--r-- | clang/lib/CodeGen/CGBuiltin.cpp | 117 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 23 |
4 files changed, 180 insertions, 0 deletions
diff --git a/clang/lib/Basic/Targets/X86.cpp b/clang/lib/Basic/Targets/X86.cpp index 5c48850cb41..fc0c9c85efe 100644 --- a/clang/lib/Basic/Targets/X86.cpp +++ b/clang/lib/Basic/Targets/X86.cpp @@ -1307,6 +1307,44 @@ bool X86TargetInfo::validateCpuSupports(StringRef FeatureStr) const { .Default(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<bool>(FeatureStr) + .Case("amd", true) + .Case("amdfam10h", true) + .Case("amdfam15h", true) + .Case("atom", true) + .Case("barcelona", true) + .Case("bdver1", true) + .Case("bdver2", true) + .Case("bdver3", true) + .Case("bdver4", true) + .Case("bonnell", true) + .Case("broadwell", true) + .Case("btver1", true) + .Case("btver2", true) + .Case("core2", true) + .Case("corei7", true) + .Case("haswell", true) + .Case("intel", true) + .Case("istanbul", true) + .Case("ivybridge", true) + .Case("knl", true) + .Case("nehalem", true) + .Case("sandybridge", true) + .Case("shanghai", true) + .Case("silvermont", true) + .Case("skylake", true) + .Case("skylake-avx512", true) + .Case("slm", true) + .Case("westmere", true) + .Case("znver1", true) + .Default(false); +} + bool X86TargetInfo::validateAsmConstraint( const char *&Name, TargetInfo::ConstraintInfo &Info) const { switch (*Name) { diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h index 671b8c9c170..34c7bdfbe3d 100644 --- a/clang/lib/Basic/Targets/X86.h +++ b/clang/lib/Basic/Targets/X86.h @@ -382,6 +382,8 @@ public: bool validateCpuSupports(StringRef Name) const override; + bool validateCpuIs(StringRef Name) const override; + bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &info) const override; 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. diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 0112bffa29b..e75c15a37cd 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -1841,6 +1841,26 @@ static bool SemaBuiltinCpuSupports(Sema &S, CallExpr *TheCall) { return false; } +/// SemaBuiltinCpuIs - Handle __builtin_cpu_is(char *). +/// This checks that the target supports __builtin_cpu_is and +/// that the string argument is constant and valid. +static bool SemaBuiltinCpuIs(Sema &S, CallExpr *TheCall) { + Expr *Arg = TheCall->getArg(0); + + // Check if the argument is a string literal. + if (!isa<StringLiteral>(Arg->IgnoreParenImpCasts())) + return S.Diag(TheCall->getLocStart(), diag::err_expr_not_string_literal) + << Arg->getSourceRange(); + + // Check the contents of the string. + StringRef Feature = + cast<StringLiteral>(Arg->IgnoreParenImpCasts())->getString(); + if (!S.Context.getTargetInfo().validateCpuIs(Feature)) + return S.Diag(TheCall->getLocStart(), diag::err_invalid_cpu_is) + << Arg->getSourceRange(); + return false; +} + // Check if the rounding mode is legal. bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) { // Indicates if this instruction has rounding control or just SAE. @@ -2154,6 +2174,9 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { if (BuiltinID == X86::BI__builtin_cpu_supports) return SemaBuiltinCpuSupports(*this, TheCall); + if (BuiltinID == X86::BI__builtin_cpu_is) + return SemaBuiltinCpuIs(*this, TheCall); + // If the intrinsic has rounding or SAE make sure its valid. if (CheckX86BuiltinRoundingOrSAE(BuiltinID, TheCall)) return true; |

