[X86] Add support for more than 32 features for __builtin_cpu_is
libgcc supports more than 32 features by adding a new 32-bit variable __cpu_features2. This adds the clang support for checking these feature bits. Patches for compiler-rt and llvm to support this are coming as well. Probably still need an additional patch for target multiversioning in clang. Differential Revision: https://reviews.llvm.org/D53458 llvm-svn: 344832
This commit is contained in:
parent
0aca35df77
commit
4d8ced1807
|
@ -9088,17 +9088,17 @@ Value *CodeGenFunction::EmitX86CpuSupports(const CallExpr *E) {
|
|||
return EmitX86CpuSupports(FeatureStr);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
uint64_t
|
||||
CodeGenFunction::GetX86CpuSupportsMask(ArrayRef<StringRef> FeatureStrs) {
|
||||
// Processor features and mapping to processor feature value.
|
||||
uint32_t FeaturesMask = 0;
|
||||
uint64_t FeaturesMask = 0;
|
||||
for (const StringRef &FeatureStr : FeatureStrs) {
|
||||
unsigned Feature =
|
||||
StringSwitch<unsigned>(FeatureStr)
|
||||
#define X86_FEATURE_COMPAT(VAL, ENUM, STR) .Case(STR, VAL)
|
||||
#include "llvm/Support/X86TargetParser.def"
|
||||
;
|
||||
FeaturesMask |= (1U << Feature);
|
||||
FeaturesMask |= (1ULL << Feature);
|
||||
}
|
||||
return FeaturesMask;
|
||||
}
|
||||
|
@ -9107,31 +9107,54 @@ Value *CodeGenFunction::EmitX86CpuSupports(ArrayRef<StringRef> FeatureStrs) {
|
|||
return EmitX86CpuSupports(GetX86CpuSupportsMask(FeatureStrs));
|
||||
}
|
||||
|
||||
llvm::Value *CodeGenFunction::EmitX86CpuSupports(uint32_t FeaturesMask) {
|
||||
// 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));
|
||||
llvm::Value *CodeGenFunction::EmitX86CpuSupports(uint64_t FeaturesMask) {
|
||||
uint32_t Features1 = Lo_32(FeaturesMask);
|
||||
uint32_t Features2 = Hi_32(FeaturesMask);
|
||||
|
||||
// Grab the global __cpu_model.
|
||||
llvm::Constant *CpuModel = CGM.CreateRuntimeVariable(STy, "__cpu_model");
|
||||
Value *Result = Builder.getTrue();
|
||||
|
||||
// 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));
|
||||
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));
|
||||
|
||||
// Check the value of the bit corresponding to the feature requested.
|
||||
Value *Mask = Builder.getInt32(FeaturesMask);
|
||||
Value *Bitset = Builder.CreateAnd(Features, Mask);
|
||||
return Builder.CreateICmpEQ(Bitset, Mask);
|
||||
// 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[] = {Builder.getInt32(0), Builder.getInt32(3),
|
||||
Builder.getInt32(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 *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");
|
||||
Value *Features =
|
||||
Builder.CreateAlignedLoad(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() {
|
||||
|
|
|
@ -4308,7 +4308,7 @@ public:
|
|||
void EmitCPUDispatchMultiVersionResolver(
|
||||
llvm::Function *Resolver,
|
||||
ArrayRef<CPUDispatchMultiVersionResolverOption> Options);
|
||||
static uint32_t GetX86CpuSupportsMask(ArrayRef<StringRef> FeatureStrs);
|
||||
static uint64_t GetX86CpuSupportsMask(ArrayRef<StringRef> FeatureStrs);
|
||||
|
||||
private:
|
||||
QualType getVarArgType(const Expr *Arg);
|
||||
|
@ -4325,7 +4325,7 @@ private:
|
|||
llvm::Value *EmitX86CpuIs(StringRef CPUStr);
|
||||
llvm::Value *EmitX86CpuSupports(const CallExpr *E);
|
||||
llvm::Value *EmitX86CpuSupports(ArrayRef<StringRef> FeatureStrs);
|
||||
llvm::Value *EmitX86CpuSupports(uint32_t Mask);
|
||||
llvm::Value *EmitX86CpuSupports(uint64_t Mask);
|
||||
llvm::Value *EmitX86CpuInit();
|
||||
llvm::Value *FormResolverCondition(const MultiVersionResolverOption &RO);
|
||||
};
|
||||
|
|
|
@ -16,5 +16,12 @@ int main() {
|
|||
// CHECK: [[AND:%[^ ]+]] = and i32 [[LOAD]], 256
|
||||
// CHECK: = icmp eq i32 [[AND]], 256
|
||||
|
||||
if (__builtin_cpu_supports("gfni"))
|
||||
a("gfni");
|
||||
|
||||
// CHECK: [[LOAD:%[^ ]+]] = load i32, i32* @__cpu_features2
|
||||
// CHECK: [[AND:%[^ ]+]] = and i32 [[LOAD]], 1
|
||||
// CHECK: = icmp eq i32 [[AND]], 1
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -75,6 +75,11 @@ void verifyfeaturestrings() {
|
|||
(void)__builtin_cpu_supports("avx5124vnniw");
|
||||
(void)__builtin_cpu_supports("avx5124fmaps");
|
||||
(void)__builtin_cpu_supports("avx512vpopcntdq");
|
||||
(void)__builtin_cpu_supports("avx512vbmi2");
|
||||
(void)__builtin_cpu_supports("gfni");
|
||||
(void)__builtin_cpu_supports("vpclmulqdq");
|
||||
(void)__builtin_cpu_supports("avx512vnni");
|
||||
(void)__builtin_cpu_supports("avx512bitalg");
|
||||
}
|
||||
|
||||
void verifycpustrings() {
|
||||
|
@ -95,7 +100,11 @@ void verifycpustrings() {
|
|||
(void)__builtin_cpu_is("cannonlake");
|
||||
(void)__builtin_cpu_is("core2");
|
||||
(void)__builtin_cpu_is("corei7");
|
||||
(void)__builtin_cpu_is("goldmont");
|
||||
(void)__builtin_cpu_is("goldmont-plus");
|
||||
(void)__builtin_cpu_is("haswell");
|
||||
(void)__builtin_cpu_is("icelake-client");
|
||||
(void)__builtin_cpu_is("icelake-server");
|
||||
(void)__builtin_cpu_is("intel");
|
||||
(void)__builtin_cpu_is("istanbul");
|
||||
(void)__builtin_cpu_is("ivybridge");
|
||||
|
@ -108,6 +117,7 @@ void verifycpustrings() {
|
|||
(void)__builtin_cpu_is("skylake");
|
||||
(void)__builtin_cpu_is("skylake-avx512");
|
||||
(void)__builtin_cpu_is("slm");
|
||||
(void)__builtin_cpu_is("tremont");
|
||||
(void)__builtin_cpu_is("westmere");
|
||||
(void)__builtin_cpu_is("znver1");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue