Author: Erich Keane Date: 2026-07-29T21:15:42-07:00 New Revision: f21b9cc9c6386cc1f4b057d8af6a3fdf617cddf9
URL: https://github.com/llvm/llvm-project/commit/f21b9cc9c6386cc1f4b057d8af6a3fdf617cddf9 DIFF: https://github.com/llvm/llvm-project/commit/f21b9cc9c6386cc1f4b057d8af6a3fdf617cddf9.diff LOG: [CIR] Implement __builtin_cpu_supports, _init, and _is (#212900) These are pretty trivial checks to a builtin variable, so this implements it for x86, as this shows up in self-build. The tests are pulled from classic-codegen and shows that we do the reasonable thing for each of them. Added: clang/test/CIR/CodeGen/builtin-cpu-is-cputype.c clang/test/CIR/CodeGen/builtin-cpu-is-subtype.c clang/test/CIR/CodeGen/builtin-cpu-is-vendor.c clang/test/CIR/CodeGen/builtin-cpu-supports.c Modified: clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp clang/lib/CIR/CodeGen/CIRGenFunction.h Removed: ################################################################################ diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp index 2369c654833cf..9c98f4bc55daa 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp @@ -26,6 +26,7 @@ #include "clang/CIR/MissingFeatures.h" #include "llvm/ADT/Sequence.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/TargetParser/X86TargetParser.h" #include <string> using namespace clang; @@ -908,20 +909,177 @@ static mlir::Value emitX86PackedByteShift(CIRGenBuilderTy &builder, return shuffleResult; } +mlir::Value CIRGenFunction::emitX86CpuIs(const CallExpr *expr) { + const Expr *cpuExpr = expr->getArg(0)->IgnoreParenCasts(); + StringRef cpuStr = cast<clang::StringLiteral>(cpuExpr)->getString(); + return emitX86CpuIs(getLoc(expr->getExprLoc()), cpuStr); +} + +cir::GetGlobalOp CIRGenFunction::createGetCpuModel(mlir::Location loc) { + mlir::Type u32 = builder.getUInt32Ty(); + auto cpuModel = + mlir::dyn_cast_or_null<cir::GlobalOp>(cgm.getGlobalValue("__cpu_model")); + + if (!cpuModel) { + // 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]; + mlir::Type tys[] = {u32, u32, u32, cir::ArrayType::get(u32, 1)}; + mlir::Type modelTy = builder.getAnonRecordTy(tys, /*incomplete=*/false); + cpuModel = + cgm.createGlobalOp(loc, "__cpu_model", modelTy, /*isConstant=*/false); + cpuModel.setDsoLocal(true); + } + + return cir::GetGlobalOp::create(builder, loc, + builder.getPointerTo(cpuModel.getSymType()), + cpuModel.getSymName()); +} + +cir::GetGlobalOp CIRGenFunction::createGetCpuFeatures2(mlir::Location loc) { + mlir::Type u32 = builder.getUInt32Ty(); + auto cpuFeatures2 = mlir::dyn_cast_or_null<cir::GlobalOp>( + cgm.getGlobalValue("__cpu_features2")); + + if (!cpuFeatures2) { + // This is just an array of 3 uint32s. + mlir::Type arrTy = cir::ArrayType::get(u32, 3); + cpuFeatures2 = + cgm.createGlobalOp(loc, "__cpu_features2", arrTy, /*isConstant=*/false); + cpuFeatures2.setDsoLocal(true); + } + + return cir::GetGlobalOp::create( + builder, loc, builder.getPointerTo(cpuFeatures2.getSymType()), + cpuFeatures2.getSymName()); +} + +mlir::Value CIRGenFunction::emitX86CpuIs(mlir::Location loc, StringRef cpuStr) { + mlir::Type u32 = builder.getUInt32Ty(); + // Calculate the index needed to access the correct field based on the + // range. ABI_VALUE matches with compiler-rt/libgcc values. + auto [fieldName, index, value] = + llvm::StringSwitch<std::tuple<llvm::StringLiteral, unsigned, unsigned>>( + cpuStr) +#define X86_VENDOR(ENUM, STRING, ABI_VALUE) \ + .Case(STRING, {"__cpu_vendor", 0u, ABI_VALUE}) +#define X86_CPU_TYPE(ENUM, STR, ABI_VALUE) \ + .Case(STR, {"__cpu_type", 1u, ABI_VALUE}) +#define X86_CPU_SUBTYPE(ENUM, STR, ABI_VALUE) \ + .Case(STR, {"__cpu_subtype", 2u, ABI_VALUE}) +#include "llvm/TargetParser/X86TargetParser.def" + .Default({"", 0, 0}); + assert(value != 0 && "Invalid CPUStr passed to CpuIs"); + + cir::GetGlobalOp getCpuModel = createGetCpuModel(loc); + + // Note: the StringSwitch above ONLY has the ability to get the first 3 + // fields, so we don't have to worry about it being the array field. So we + // can continue assuming everything is an int. + cir::GetMemberOp cpuValuePtr = builder.createGetMember( + loc, builder.getPointerTo(u32), getCpuModel, fieldName, index); + cir::LoadOp getVal = builder.createAlignedLoad(loc, u32, cpuValuePtr, + CharUnits::fromQuantity(4)); + + return cir::CmpOp::create(builder, loc, cir::CmpOpKind::eq, getVal, + builder.getUInt32(value, loc)); +} + +mlir::Value CIRGenFunction::emitX86CpuSupports(const CallExpr *expr) { + const Expr *featureExpr = expr->getArg(0)->IgnoreParenCasts(); + StringRef featureStr = cast<StringLiteral>(featureExpr)->getString(); + if (!getContext().getTargetInfo().validateCpuSupports(featureStr)) + return builder.getFalse(getLoc(expr->getExprLoc())); + return emitX86CpuSupports(getLoc(expr->getExprLoc()), featureStr); +} + +mlir::Value +CIRGenFunction::emitX86CpuSupports(mlir::Location loc, + ArrayRef<StringRef> featureStrs) { + return emitX86CpuSupports(loc, llvm::X86::getCpuSupportsMask(featureStrs)); +} + +mlir::Value +CIRGenFunction::emitX86CpuSupports(mlir::Location loc, + std::array<uint32_t, 4> featureMask) { + mlir::Type u32 = builder.getUInt32Ty(); + mlir::Value result; + + auto addCondition = [&](unsigned maskVal, mlir::Value features) { + cir::ConstantOp mask = builder.getUInt32(maskVal, loc); + mlir::Value bitset = builder.createAnd(loc, features, mask); + mlir::Value cmp = + cir::CmpOp::create(builder, loc, cir::CmpOpKind::eq, bitset, mask); + + if (result) + result = builder.createAnd(loc, result, cmp); + else + result = cmp; + }; + + // only check the '__cpu_features[0]' if we have a non-zero value. A zero + // here means to JUST check __cpu_features2. + if (featureMask[0] != 0) { + cir::GetGlobalOp getCpuModel = createGetCpuModel(loc); + mlir::Type u32 = builder.getUInt32Ty(); + auto arrTy = cir::ArrayType::get(u32, 1); + + // Pick out the __cpu_features field, the 4th field in the struct. + cir::GetMemberOp cpuFeatArrPtr = builder.createGetMember( + loc, builder.getPointerTo(arrTy), getCpuModel, "__cpu_features", 3); + + mlir::Value cpuFeatVal = builder.getArrayElement( + loc, loc, cpuFeatArrPtr, arrTy, + /*index=*/builder.getUInt32(0, loc), /*shouldDecay=*/true); + cir::LoadOp features = builder.createAlignedLoad( + loc, u32, cpuFeatVal, CharUnits::fromQuantity(4)); + + addCondition(featureMask[0], features); + } + + // the 0th index is looked up in the __cpu_model field, the rest come from an + // array. + cir::GetGlobalOp getCpuFeatures2; // = createGetCpuFeatures2(loc); + for (int i = 1; i != 4; ++i) { + const uint32_t val = featureMask[i]; + if (!val) + continue; + if (!getCpuFeatures2) + getCpuFeatures2 = createGetCpuFeatures2(loc); + mlir::Value getArrayElt = builder.getArrayElement( + loc, loc, getCpuFeatures2, + cast<cir::PointerType>(getCpuFeatures2.getType()).getPointee(), + builder.getUInt32(/*index=*/i - 1, loc), + /*shouldDecay=*/true); + cir::LoadOp features = builder.createAlignedLoad( + loc, u32, getArrayElt, CharUnits::fromQuantity(4)); + + addCondition(val, features); + } + + return result; +} + +mlir::Value CIRGenFunction::emitX86CpuInit(mlir::Location loc) { + cir::FuncOp initFunc = + cgm.createRuntimeFunction(builder.getVoidFnTy(), "__cpu_indicator_init"); + initFunc.setDsoLocal(true); + assert(!cir::MissingFeatures::setDLLStorageClass()); + + return builder.createCallOp(loc, initFunc, {}).getResult(); +} + std::optional<mlir::Value> CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID, const CallExpr *expr) { - if (builtinID == Builtin::BI__builtin_cpu_is) { - cgm.errorNYI(expr->getSourceRange(), "__builtin_cpu_is"); - return mlir::Value{}; - } - if (builtinID == Builtin::BI__builtin_cpu_supports) { - cgm.errorNYI(expr->getSourceRange(), "__builtin_cpu_supports"); - return mlir::Value{}; - } - if (builtinID == Builtin::BI__builtin_cpu_init) { - cgm.errorNYI(expr->getSourceRange(), "__builtin_cpu_init"); - return mlir::Value{}; - } + if (builtinID == Builtin::BI__builtin_cpu_is) + return emitX86CpuIs(expr); + if (builtinID == Builtin::BI__builtin_cpu_supports) + return emitX86CpuSupports(expr); + if (builtinID == Builtin::BI__builtin_cpu_init) + return emitX86CpuInit(getLoc(expr->getExprLoc())); // Handle MSVC intrinsics before argument evaluation to prevent double // evaluation. diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index eec20f595c5f2..ed53fc38f6930 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -2311,7 +2311,16 @@ class CIRGenFunction : public CIRGenTypeCache { std::optional<mlir::Value> emitRISCVBuiltinExpr(unsigned builtinID, const CallExpr *expr); - + cir::GetGlobalOp createGetCpuModel(mlir::Location loc); + cir::GetGlobalOp createGetCpuFeatures2(mlir::Location loc); + mlir::Value emitX86CpuIs(const CallExpr *expr); + mlir::Value emitX86CpuIs(mlir::Location loc, StringRef cpuStr); + mlir::Value emitX86CpuSupports(const CallExpr *expr); + mlir::Value emitX86CpuSupports(mlir::Location loc, + ArrayRef<StringRef> FeatureStrs); + mlir::Value emitX86CpuSupports(mlir::Location loc, + std::array<uint32_t, 4> FeatureMask); + mlir::Value emitX86CpuInit(mlir::Location loc); std::optional<mlir::Value> emitX86BuiltinExpr(unsigned builtinID, const CallExpr *expr); diff --git a/clang/test/CIR/CodeGen/builtin-cpu-is-cputype.c b/clang/test/CIR/CodeGen/builtin-cpu-is-cputype.c new file mode 100644 index 0000000000000..c020fc3b141bf --- /dev/null +++ b/clang/test/CIR/CodeGen/builtin-cpu-is-cputype.c @@ -0,0 +1,331 @@ +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fclangir -emit-cir %s -o - | FileCheck %s --check-prefix=CIR +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fclangir -emit-llvm %s -o - | FileCheck %s --check-prefix=LLVM +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix=LLVM + +// Test that __builtin_cpu_is emits the correct ABI value for every CPU type, +// in llvm/include/llvm/TargetParser/X86TargetParser.def. +extern void a(const char *); + +// CIR: ![[MODEL_TY:.*]] = !cir.struct<{!u32i, !u32i, !u32i, !cir.array<!u32i x 1>}> +// CIR: cir.global "private" external dso_local @__cpu_model : ![[MODEL_TY]] +// LLVM: @__cpu_model = external dso_local global { i32, i32, i32, [1 x i32] } + +#define TEST_CPU_IS(NAME, STR) \ + void test_##NAME(void) { \ + if (__builtin_cpu_is(STR)) \ + a(STR); \ + } + +// CIR-LABEL: cir.func{{.*}}@test_bonnell( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_MEM_PTR:.*]] = cir.get_member %[[GET_MODEL]][1] {name = "__cpu_type"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[LOAD_TYPE:.*]] = cir.load {{.*}}%[[GET_MEM_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<1> : !u32i +// CIR: cir.cmp eq %[[LOAD_TYPE]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_bonnell( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 4) +// LLVM: = icmp eq i32 [[LOAD]], 1 +TEST_CPU_IS(bonnell, "bonnell") + +// CIR-LABEL: cir.func{{.*}}@test_core2( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_MEM_PTR:.*]] = cir.get_member %[[GET_MODEL]][1] {name = "__cpu_type"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[LOAD_TYPE:.*]] = cir.load {{.*}}%[[GET_MEM_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<2> : !u32i +// CIR: cir.cmp eq %[[LOAD_TYPE]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_core2( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 4) +// LLVM: = icmp eq i32 [[LOAD]], 2 +TEST_CPU_IS(core2, "core2") + +// CIR-LABEL: cir.func{{.*}}@test_corei7( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_MEM_PTR:.*]] = cir.get_member %[[GET_MODEL]][1] {name = "__cpu_type"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[LOAD_TYPE:.*]] = cir.load {{.*}}%[[GET_MEM_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<3> : !u32i +// CIR: cir.cmp eq %[[LOAD_TYPE]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_corei7( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 4) +// LLVM: = icmp eq i32 [[LOAD]], 3 +TEST_CPU_IS(corei7, "corei7") + +// CIR-LABEL: cir.func{{.*}}@test_amdfam10h( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_MEM_PTR:.*]] = cir.get_member %[[GET_MODEL]][1] {name = "__cpu_type"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[LOAD_TYPE:.*]] = cir.load {{.*}}%[[GET_MEM_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<4> : !u32i +// CIR: cir.cmp eq %[[LOAD_TYPE]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_amdfam10h( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 4) +// LLVM: = icmp eq i32 [[LOAD]], 4 +TEST_CPU_IS(amdfam10h, "amdfam10h") + +// CIR-LABEL: cir.func{{.*}}@test_amdfam15h( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_MEM_PTR:.*]] = cir.get_member %[[GET_MODEL]][1] {name = "__cpu_type"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[LOAD_TYPE:.*]] = cir.load {{.*}}%[[GET_MEM_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<5> : !u32i +// CIR: cir.cmp eq %[[LOAD_TYPE]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_amdfam15h( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 4) +// LLVM: = icmp eq i32 [[LOAD]], 5 +TEST_CPU_IS(amdfam15h, "amdfam15h") + +// CIR-LABEL: cir.func{{.*}}@test_silvermont( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_MEM_PTR:.*]] = cir.get_member %[[GET_MODEL]][1] {name = "__cpu_type"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[LOAD_TYPE:.*]] = cir.load {{.*}}%[[GET_MEM_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<6> : !u32i +// CIR: cir.cmp eq %[[LOAD_TYPE]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_silvermont( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 4) +// LLVM: = icmp eq i32 [[LOAD]], 6 +TEST_CPU_IS(silvermont, "silvermont") + +// CIR-LABEL: cir.func{{.*}}@test_knl( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_MEM_PTR:.*]] = cir.get_member %[[GET_MODEL]][1] {name = "__cpu_type"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[LOAD_TYPE:.*]] = cir.load {{.*}}%[[GET_MEM_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<7> : !u32i +// CIR: cir.cmp eq %[[LOAD_TYPE]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_knl( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 4) +// LLVM: = icmp eq i32 [[LOAD]], 7 +TEST_CPU_IS(knl, "knl") + +// CIR-LABEL: cir.func{{.*}}@test_btver1( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_MEM_PTR:.*]] = cir.get_member %[[GET_MODEL]][1] {name = "__cpu_type"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[LOAD_TYPE:.*]] = cir.load {{.*}}%[[GET_MEM_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<8> : !u32i +// CIR: cir.cmp eq %[[LOAD_TYPE]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_btver1( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 4) +// LLVM: = icmp eq i32 [[LOAD]], 8 +TEST_CPU_IS(btver1, "btver1") + +// CIR-LABEL: cir.func{{.*}}@test_btver2( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_MEM_PTR:.*]] = cir.get_member %[[GET_MODEL]][1] {name = "__cpu_type"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[LOAD_TYPE:.*]] = cir.load {{.*}}%[[GET_MEM_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<9> : !u32i +// CIR: cir.cmp eq %[[LOAD_TYPE]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_btver2( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 4) +// LLVM: = icmp eq i32 [[LOAD]], 9 +TEST_CPU_IS(btver2, "btver2") + +// CIR-LABEL: cir.func{{.*}}@test_amdfam17h( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_MEM_PTR:.*]] = cir.get_member %[[GET_MODEL]][1] {name = "__cpu_type"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[LOAD_TYPE:.*]] = cir.load {{.*}}%[[GET_MEM_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<10> : !u32i +// CIR: cir.cmp eq %[[LOAD_TYPE]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_amdfam17h( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 4) +// LLVM: = icmp eq i32 [[LOAD]], 10 +TEST_CPU_IS(amdfam17h, "amdfam17h") + +// CIR-LABEL: cir.func{{.*}}@test_knm( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_MEM_PTR:.*]] = cir.get_member %[[GET_MODEL]][1] {name = "__cpu_type"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[LOAD_TYPE:.*]] = cir.load {{.*}}%[[GET_MEM_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<11> : !u32i +// CIR: cir.cmp eq %[[LOAD_TYPE]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_knm( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 4) +// LLVM: = icmp eq i32 [[LOAD]], 11 +TEST_CPU_IS(knm, "knm") + +// CIR-LABEL: cir.func{{.*}}@test_goldmont( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_MEM_PTR:.*]] = cir.get_member %[[GET_MODEL]][1] {name = "__cpu_type"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[LOAD_TYPE:.*]] = cir.load {{.*}}%[[GET_MEM_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<12> : !u32i +// CIR: cir.cmp eq %[[LOAD_TYPE]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_goldmont( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 4) +// LLVM: = icmp eq i32 [[LOAD]], 12 +TEST_CPU_IS(goldmont, "goldmont") + +// CIR-LABEL: cir.func{{.*}}@test_goldmont_plus( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_MEM_PTR:.*]] = cir.get_member %[[GET_MODEL]][1] {name = "__cpu_type"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[LOAD_TYPE:.*]] = cir.load {{.*}}%[[GET_MEM_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<13> : !u32i +// CIR: cir.cmp eq %[[LOAD_TYPE]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_goldmont_plus( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 4) +// LLVM: = icmp eq i32 [[LOAD]], 13 +TEST_CPU_IS(goldmont_plus, "goldmont-plus") + +// CIR-LABEL: cir.func{{.*}}@test_tremont( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_MEM_PTR:.*]] = cir.get_member %[[GET_MODEL]][1] {name = "__cpu_type"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[LOAD_TYPE:.*]] = cir.load {{.*}}%[[GET_MEM_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<14> : !u32i +// CIR: cir.cmp eq %[[LOAD_TYPE]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_tremont( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 4) +// LLVM: = icmp eq i32 [[LOAD]], 14 +TEST_CPU_IS(tremont, "tremont") + +// CIR-LABEL: cir.func{{.*}}@test_amdfam19h( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_MEM_PTR:.*]] = cir.get_member %[[GET_MODEL]][1] {name = "__cpu_type"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[LOAD_TYPE:.*]] = cir.load {{.*}}%[[GET_MEM_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<15> : !u32i +// CIR: cir.cmp eq %[[LOAD_TYPE]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_amdfam19h( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 4) +// LLVM: = icmp eq i32 [[LOAD]], 15 +TEST_CPU_IS(amdfam19h, "amdfam19h") + +// CIR-LABEL: cir.func{{.*}}@test_zhaoxin_fam7h( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_MEM_PTR:.*]] = cir.get_member %[[GET_MODEL]][1] {name = "__cpu_type"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[LOAD_TYPE:.*]] = cir.load {{.*}}%[[GET_MEM_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<16> : !u32i +// CIR: cir.cmp eq %[[LOAD_TYPE]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_zhaoxin_fam7h( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 4) +// LLVM: = icmp eq i32 [[LOAD]], 16 +TEST_CPU_IS(zhaoxin_fam7h, "zhaoxin_fam7h") + +// CIR-LABEL: cir.func{{.*}}@test_sierraforest( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_MEM_PTR:.*]] = cir.get_member %[[GET_MODEL]][1] {name = "__cpu_type"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[LOAD_TYPE:.*]] = cir.load {{.*}}%[[GET_MEM_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<17> : !u32i +// CIR: cir.cmp eq %[[LOAD_TYPE]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_sierraforest( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 4) +// LLVM: = icmp eq i32 [[LOAD]], 17 +TEST_CPU_IS(sierraforest, "sierraforest") + +// CIR-LABEL: cir.func{{.*}}@test_grandridge( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_MEM_PTR:.*]] = cir.get_member %[[GET_MODEL]][1] {name = "__cpu_type"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[LOAD_TYPE:.*]] = cir.load {{.*}}%[[GET_MEM_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<18> : !u32i +// CIR: cir.cmp eq %[[LOAD_TYPE]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_grandridge( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 4) +// LLVM: = icmp eq i32 [[LOAD]], 18 +TEST_CPU_IS(grandridge, "grandridge") + +// CIR-LABEL: cir.func{{.*}}@test_clearwaterforest( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_MEM_PTR:.*]] = cir.get_member %[[GET_MODEL]][1] {name = "__cpu_type"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[LOAD_TYPE:.*]] = cir.load {{.*}}%[[GET_MEM_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<19> : !u32i +// CIR: cir.cmp eq %[[LOAD_TYPE]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_clearwaterforest( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 4) +// LLVM: = icmp eq i32 [[LOAD]], 19 +TEST_CPU_IS(clearwaterforest, "clearwaterforest") + +// CIR-LABEL: cir.func{{.*}}@test_amdfam1ah( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_MEM_PTR:.*]] = cir.get_member %[[GET_MODEL]][1] {name = "__cpu_type"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[LOAD_TYPE:.*]] = cir.load {{.*}}%[[GET_MEM_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<20> : !u32i +// CIR: cir.cmp eq %[[LOAD_TYPE]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_amdfam1ah( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 4) +// LLVM: = icmp eq i32 [[LOAD]], 20 +TEST_CPU_IS(amdfam1ah, "amdfam1ah") + +// CIR-LABEL: cir.func{{.*}}@test_hygonfam18h( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_MEM_PTR:.*]] = cir.get_member %[[GET_MODEL]][1] {name = "__cpu_type"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[LOAD_TYPE:.*]] = cir.load {{.*}}%[[GET_MEM_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<21> : !u32i +// CIR: cir.cmp eq %[[LOAD_TYPE]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_hygonfam18h( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 4) +// LLVM: = icmp eq i32 [[LOAD]], 21 +TEST_CPU_IS(hygonfam18h, "hygonfam18h") + +// Aliases + +// CIR-LABEL: cir.func{{.*}}@test_atom( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_MEM_PTR:.*]] = cir.get_member %[[GET_MODEL]][1] {name = "__cpu_type"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[LOAD_TYPE:.*]] = cir.load {{.*}}%[[GET_MEM_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<1> : !u32i +// CIR: cir.cmp eq %[[LOAD_TYPE]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_atom( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 4) +// LLVM: = icmp eq i32 [[LOAD]], 1 +TEST_CPU_IS(atom, "atom") + +// CIR-LABEL: cir.func{{.*}}@test_amdfam10( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_MEM_PTR:.*]] = cir.get_member %[[GET_MODEL]][1] {name = "__cpu_type"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[LOAD_TYPE:.*]] = cir.load {{.*}}%[[GET_MEM_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<4> : !u32i +// CIR: cir.cmp eq %[[LOAD_TYPE]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_amdfam10( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 4) +// LLVM: = icmp eq i32 [[LOAD]], 4 +TEST_CPU_IS(amdfam10, "amdfam10") + +// CIR-LABEL: cir.func{{.*}}@test_amdfam15( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_MEM_PTR:.*]] = cir.get_member %[[GET_MODEL]][1] {name = "__cpu_type"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[LOAD_TYPE:.*]] = cir.load {{.*}}%[[GET_MEM_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<5> : !u32i +// CIR: cir.cmp eq %[[LOAD_TYPE]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_amdfam15( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 4) +// LLVM: = icmp eq i32 [[LOAD]], 5 +TEST_CPU_IS(amdfam15, "amdfam15") + +// CIR-LABEL: cir.func{{.*}}@test_slm( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_MEM_PTR:.*]] = cir.get_member %[[GET_MODEL]][1] {name = "__cpu_type"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[LOAD_TYPE:.*]] = cir.load {{.*}}%[[GET_MEM_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<6> : !u32i +// CIR: cir.cmp eq %[[LOAD_TYPE]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_slm( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 4) +// LLVM: = icmp eq i32 [[LOAD]], 6 +TEST_CPU_IS(slm, "slm") + +// CIR-LABEL: cir.func{{.*}}@test_amdfam1a( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_MEM_PTR:.*]] = cir.get_member %[[GET_MODEL]][1] {name = "__cpu_type"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[LOAD_TYPE:.*]] = cir.load {{.*}}%[[GET_MEM_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<20> : !u32i +// CIR: cir.cmp eq %[[LOAD_TYPE]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_amdfam1a( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 4) +// LLVM: = icmp eq i32 [[LOAD]], 20 +TEST_CPU_IS(amdfam1a, "amdfam1a") diff --git a/clang/test/CIR/CodeGen/builtin-cpu-is-subtype.c b/clang/test/CIR/CodeGen/builtin-cpu-is-subtype.c new file mode 100644 index 0000000000000..65be1e9ebac68 --- /dev/null +++ b/clang/test/CIR/CodeGen/builtin-cpu-is-subtype.c @@ -0,0 +1,596 @@ +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fclangir -emit-cir %s -o - | FileCheck %s --check-prefix=CIR +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fclangir -emit-llvm %s -o - | FileCheck %s --check-prefix=LLVM +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix=LLVM + + +// Test that __builtin_cpu_is emits the correct ABI value for every CPU +// subtype, llvm/include/llvm/TargetParser/X86TargetParser.def. +extern void a(const char *); + +// CIR: ![[MODEL_TY:.*]] = !cir.struct<{!u32i, !u32i, !u32i, !cir.array<!u32i x 1>}> +// CIR: cir.global "private" external dso_local @__cpu_model : ![[MODEL_TY]] +// LLVM: @__cpu_model = external dso_local global { i32, i32, i32, [1 x i32] } + +#define TEST_CPU_IS(NAME, STR) \ + void test_##NAME(void) { \ + if (__builtin_cpu_is(STR)) \ + a(STR); \ + } + +// CIR-LABEL: cir.func{{.*}} @test_nehalem( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<1> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_nehalem( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 1 +TEST_CPU_IS(nehalem, "nehalem") + +// CIR-LABEL: cir.func{{.*}} @test_westmere( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<2> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_westmere( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 2 +TEST_CPU_IS(westmere, "westmere") + +// CIR-LABEL: cir.func{{.*}} @test_sandybridge( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<3> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_sandybridge( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 3 +TEST_CPU_IS(sandybridge, "sandybridge") + +// CIR-LABEL: cir.func{{.*}} @test_barcelona( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<4> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_barcelona( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 4 +TEST_CPU_IS(barcelona, "barcelona") + +// CIR-LABEL: cir.func{{.*}} @test_shanghai( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<5> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_shanghai( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 5 +TEST_CPU_IS(shanghai, "shanghai") + +// CIR-LABEL: cir.func{{.*}} @test_istanbul( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<6> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_istanbul( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 6 +TEST_CPU_IS(istanbul, "istanbul") + +// CIR-LABEL: cir.func{{.*}} @test_bdver1( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<7> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_bdver1( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 7 +TEST_CPU_IS(bdver1, "bdver1") + +// CIR-LABEL: cir.func{{.*}} @test_bdver2( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<8> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_bdver2( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 8 +TEST_CPU_IS(bdver2, "bdver2") + +// CIR-LABEL: cir.func{{.*}} @test_bdver3( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<9> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_bdver3( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 9 +TEST_CPU_IS(bdver3, "bdver3") + +// CIR-LABEL: cir.func{{.*}} @test_bdver4( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<10> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_bdver4( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 10 +TEST_CPU_IS(bdver4, "bdver4") + +// CIR-LABEL: cir.func{{.*}} @test_znver1( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<11> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_znver1( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 11 +TEST_CPU_IS(znver1, "znver1") + +// CIR-LABEL: cir.func{{.*}} @test_ivybridge( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<12> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_ivybridge( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 12 +TEST_CPU_IS(ivybridge, "ivybridge") + +// CIR-LABEL: cir.func{{.*}} @test_haswell( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<13> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_haswell( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 13 +TEST_CPU_IS(haswell, "haswell") + +// CIR-LABEL: cir.func{{.*}} @test_broadwell( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<14> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_broadwell( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 14 +TEST_CPU_IS(broadwell, "broadwell") + +// CIR-LABEL: cir.func{{.*}} @test_skylake( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<15> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_skylake( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 15 +TEST_CPU_IS(skylake, "skylake") + +// CIR-LABEL: cir.func{{.*}} @test_skylake_avx512( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<16> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_skylake_avx512( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 16 +TEST_CPU_IS(skylake_avx512, "skylake-avx512") + +// CIR-LABEL: cir.func{{.*}} @test_cannonlake( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<17> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_cannonlake( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 17 +TEST_CPU_IS(cannonlake, "cannonlake") + +// CIR-LABEL: cir.func{{.*}} @test_icelake_client( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<18> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_icelake_client( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 18 +TEST_CPU_IS(icelake_client, "icelake-client") + +// CIR-LABEL: cir.func{{.*}} @test_icelake_server( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<19> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_icelake_server( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 19 +TEST_CPU_IS(icelake_server, "icelake-server") + +// CIR-LABEL: cir.func{{.*}} @test_znver2( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<20> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_znver2( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 20 +TEST_CPU_IS(znver2, "znver2") + +// CIR-LABEL: cir.func{{.*}} @test_cascadelake( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<21> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_cascadelake( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 21 +TEST_CPU_IS(cascadelake, "cascadelake") + +// CIR-LABEL: cir.func{{.*}} @test_tigerlake( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<22> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_tigerlake( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 22 +TEST_CPU_IS(tigerlake, "tigerlake") + +// CIR-LABEL: cir.func{{.*}} @test_cooperlake( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<23> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_cooperlake( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 23 +TEST_CPU_IS(cooperlake, "cooperlake") + +// CIR-LABEL: cir.func{{.*}} @test_sapphirerapids( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<24> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_sapphirerapids( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 24 +TEST_CPU_IS(sapphirerapids, "sapphirerapids") + +// CIR-LABEL: cir.func{{.*}} @test_alderlake( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<25> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_alderlake( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 25 +TEST_CPU_IS(alderlake, "alderlake") + +// CIR-LABEL: cir.func{{.*}} @test_znver3( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<26> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_znver3( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 26 +TEST_CPU_IS(znver3, "znver3") + +// CIR-LABEL: cir.func{{.*}} @test_rocketlake( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<27> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_rocketlake( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 27 +TEST_CPU_IS(rocketlake, "rocketlake") + +// CIR-LABEL: cir.func{{.*}} @test_zhaoxin_fam7h_lujiazui( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<28> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_zhaoxin_fam7h_lujiazui( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 28 +TEST_CPU_IS(zhaoxin_fam7h_lujiazui, "zhaoxin_fam7h_lujiazui") + +// CIR-LABEL: cir.func{{.*}} @test_znver4( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<29> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_znver4( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 29 +TEST_CPU_IS(znver4, "znver4") + +// CIR-LABEL: cir.func{{.*}} @test_graniterapids( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<30> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_graniterapids( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 30 +TEST_CPU_IS(graniterapids, "graniterapids") + +// CIR-LABEL: cir.func{{.*}} @test_graniterapids_d( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<31> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_graniterapids_d( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 31 +TEST_CPU_IS(graniterapids_d, "graniterapids-d") + +// CIR-LABEL: cir.func{{.*}} @test_arrowlake( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<32> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_arrowlake( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 32 +TEST_CPU_IS(arrowlake, "arrowlake") + +// CIR-LABEL: cir.func{{.*}} @test_arrowlake_s( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<33> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_arrowlake_s( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 33 +TEST_CPU_IS(arrowlake_s, "arrowlake-s") + +// CIR-LABEL: cir.func{{.*}} @test_pantherlake( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<34> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_pantherlake( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 34 +TEST_CPU_IS(pantherlake, "pantherlake") + +// CIR-LABEL: cir.func{{.*}} @test_znver5( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<36> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_znver5( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 36 +TEST_CPU_IS(znver5, "znver5") + +// CIR-LABEL: cir.func{{.*}} @test_diamondrapids( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<38> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_diamondrapids( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 38 +TEST_CPU_IS(diamondrapids, "diamondrapids") + +// CIR-LABEL: cir.func{{.*}} @test_novalake( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<39> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_novalake( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 39 +TEST_CPU_IS(novalake, "novalake") + +// CIR-LABEL: cir.func{{.*}} @test_znver6( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<40> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_znver6( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 40 +TEST_CPU_IS(znver6, "znver6") + +// CIR-LABEL: cir.func{{.*}} @test_c86_4g_m4( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<41> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_c86_4g_m4( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 41 +TEST_CPU_IS(c86_4g_m4, "c86-4g-m4") + +// CIR-LABEL: cir.func{{.*}} @test_c86_4g_m6( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<42> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_c86_4g_m6( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 42 +TEST_CPU_IS(c86_4g_m6, "c86-4g-m6") + +// CIR-LABEL: cir.func{{.*}} @test_c86_4g_m7( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<43> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_c86_4g_m7( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 43 +TEST_CPU_IS(c86_4g_m7, "c86-4g-m7") + +// CIR-LABEL: cir.func{{.*}} @test_c86_4g_m8( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<44> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_c86_4g_m8( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 44 +TEST_CPU_IS(c86_4g_m8, "c86-4g-m8") + +// Aliases + +// CIR-LABEL: cir.func{{.*}} @test_emeraldrapids( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<24> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_emeraldrapids( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 24 +TEST_CPU_IS(emeraldrapids, "emeraldrapids") + +// CIR-LABEL: cir.func{{.*}} @test_raptorlake( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<25> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_raptorlake( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 25 +TEST_CPU_IS(raptorlake, "raptorlake") + +// CIR-LABEL: cir.func{{.*}} @test_meteorlake( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<25> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_meteorlake( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 25 +TEST_CPU_IS(meteorlake, "meteorlake") + +// CIR-LABEL: cir.func{{.*}} @test_gracemont( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<25> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_gracemont( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 25 +TEST_CPU_IS(gracemont, "gracemont") + +// CIR-LABEL: cir.func{{.*}} @test_lunarlake( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<33> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_lunarlake( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 33 +TEST_CPU_IS(lunarlake, "lunarlake") + +// CIR-LABEL: cir.func{{.*}} @test_wildcatlake( +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_ST_PTR:.*]] = cir.get_member %[[GET_MODEL]][2] {name = "__cpu_subtype"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[ST:.*]] = cir.load {{.*}}%[[GET_ST_PTR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<34> : !u32i +// CIR: cir.cmp eq %[[ST]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_wildcatlake( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 8) +// LLVM: = icmp eq i32 [[LOAD]], 34 +TEST_CPU_IS(wildcatlake, "wildcatlake") diff --git a/clang/test/CIR/CodeGen/builtin-cpu-is-vendor.c b/clang/test/CIR/CodeGen/builtin-cpu-is-vendor.c new file mode 100644 index 0000000000000..b754f8dc6c1b1 --- /dev/null +++ b/clang/test/CIR/CodeGen/builtin-cpu-is-vendor.c @@ -0,0 +1,54 @@ +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fclangir -emit-cir %s -o - | FileCheck %s --check-prefix=CIR +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fclangir -emit-llvm %s -o - | FileCheck %s --check-prefix=LLVM +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix=LLVM + +// Test that __builtin_cpu_is emits the correct ABI value and field offset for +// every vendor (field offset 0) in llvm/include/llvm/TargetParser/ +// X86TargetParser.def. +extern void a(const char *); + +// CIR: ![[MODEL_TY:.*]] = !cir.struct<{!u32i, !u32i, !u32i, !cir.array<!u32i x 1>}> +// CIR: cir.global "private" external dso_local @__cpu_model : ![[MODEL_TY]] +// LLVM: @__cpu_model = external dso_local global { i32, i32, i32, [1 x i32] } + +#define TEST_CPU_IS(NAME, STR) \ + void test_##NAME(void) { \ + if (__builtin_cpu_is(STR)) \ + a(STR); \ + } + +// CIR-LABEL: cir.func {{.*}}@test_intel() +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_VENDOR:.*]] = cir.get_member %[[GET_MODEL]][0] {name = "__cpu_vendor"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[LOAD_VENDOR:.*]] = cir.load {{.*}}%[[GET_VENDOR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<1> : !u32i +// CIR: cir.cmp eq %[[LOAD_VENDOR]], %[[MASK]] : !u32i + +// LLVM-LABEL: define{{.*}} void @test_intel( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr @__cpu_model +// LLVM: = icmp eq i32 [[LOAD]], 1 +TEST_CPU_IS(intel, "intel") + +// CIR-LABEL: cir.func {{.*}}@test_amd() +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_VENDOR:.*]] = cir.get_member %[[GET_MODEL]][0] {name = "__cpu_vendor"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[LOAD_VENDOR:.*]] = cir.load {{.*}}%[[GET_VENDOR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<2> : !u32i +// CIR: cir.cmp eq %[[LOAD_VENDOR]], %[[MASK]] : !u32i +// +// LLVM-LABEL: define{{.*}} void @test_amd( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr @__cpu_model +// LLVM: = icmp eq i32 [[LOAD]], 2 +TEST_CPU_IS(amd, "amd") + +// CIR-LABEL: cir.func {{.*}}@test_other() +// CIR: %[[GET_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<![[MODEL_TY]]> +// CIR: %[[GET_VENDOR:.*]] = cir.get_member %[[GET_MODEL]][0] {name = "__cpu_vendor"} : !cir.ptr<![[MODEL_TY]]> -> !cir.ptr<!u32i> +// CIR: %[[LOAD_VENDOR:.*]] = cir.load {{.*}}%[[GET_VENDOR]] : !cir.ptr<!u32i>, !u32i +// CIR: %[[MASK:.*]] = cir.const #cir.int<5> : !u32i +// CIR: cir.cmp eq %[[LOAD_VENDOR]], %[[MASK]] : !u32i +// +// LLVM-LABEL: define{{.*}} void @test_other( +// LLVM: [[LOAD:%[^ ]+]] = load i32, ptr @__cpu_model +// LLVM: = icmp eq i32 [[LOAD]], 5 +TEST_CPU_IS(other, "other") diff --git a/clang/test/CIR/CodeGen/builtin-cpu-supports.c b/clang/test/CIR/CodeGen/builtin-cpu-supports.c new file mode 100644 index 0000000000000..eecde11ce26f3 --- /dev/null +++ b/clang/test/CIR/CodeGen/builtin-cpu-supports.c @@ -0,0 +1,229 @@ +// This is a clone of a file of the same name, but only the x86 parts, since +// that is all we support in CIR right now. +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fclangir -emit-cir %s -o - | FileCheck %s --check-prefix=CIR +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fclangir -emit-llvm %s -o - | FileCheck %s --check-prefix=LLVM,LLVMCIR +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix=LLVM,OGCG + +// Test that we have the structure definition, the gep offsets, the name of the +// global, the bit grab, and the icmp correct. +extern void a(const char *); + +// CIR-LABEL: cir.func{{.*}} @main() -> !s32i +// CIR-SAME: attributes {[[ATTRS:.*]]} { +// CIR: cir.call @__cpu_indicator_init() : () -> () +// CIR-NEXT: cir.scope { +// CIR-NEXT: %[[CPU_MODEL:.*]] = cir.get_global @__cpu_model : !cir.ptr<!rec_anon_struct> +// CIR-NEXT: %[[CPU_FEAT:.*]] = cir.get_member %[[CPU_MODEL]][3] {name = "__cpu_features"} : !cir.ptr<!rec_anon_struct> -> !cir.ptr<!cir.array<!u32i x 1>> +// CIR-NEXT: %[[ZERO:.*]] = cir.const #cir.int<0> : !u32i +// CIR-NEXT: %[[FEAT0:.*]] = cir.get_element %[[CPU_FEAT]][%[[ZERO]] : !u32i] : !cir.ptr<!cir.array<!u32i x 1>> -> !cir.ptr<!u32i> +// CIR-NEXT: %[[LOAD_FEAT0:.*]] = cir.load {{.*}} %[[FEAT0]] : !cir.ptr<!u32i>, !u32i +// CIR-NEXT: %[[MASK:.*]] = cir.const #cir.int<256> : !u32i +// CIR-NEXT: %[[AND:.*]] = cir.and %[[LOAD_FEAT0]], %[[MASK]] : !u32i +// CIR-NEXT: %[[RES:.*]] = cir.cmp eq %[[AND]], %[[MASK]] : !u32i +// CIR-NEXT: cir.if %[[RES]] { +// CIR-NEXT: %[[STR:.*]] = cir.get_global +// CIR-NEXT: %[[STR_DECAY:.*]] = cir.cast array_to_ptrdecay %[[STR]] : !cir.ptr<!cir.array<!s8i x 7>> -> !cir.ptr<!s8i> +// CIR-NEXT: cir.call @a(%[[STR_DECAY]]) : (!cir.ptr<!s8i> {llvm.noundef}) -> () +// CIR-NEXT: } +// CIR-NEXT: } +// CIR-NEXT: cir.scope { +// CIR-NEXT: %[[CPU_FEAT2:.*]] = cir.get_global @__cpu_features2 : !cir.ptr<!cir.array<!u32i x 3>> +// CIR-NEXT: %[[ZERO:.*]] = cir.const #cir.int<0> : !u32i +// CIR-NEXT: %[[FEAT2_0:.*]] = cir.get_element %[[CPU_FEAT2]][%[[ZERO]] : !u32i] : !cir.ptr<!cir.array<!u32i x 3>> -> !cir.ptr<!u32i> +// CIR-NEXT: %[[LOAD_FEAT2_0:.*]] = cir.load {{.*}} %[[FEAT2_0]] : !cir.ptr<!u32i>, !u32i +// CIR-NEXT: %[[MASK:.*]] = cir.const #cir.int<1> : !u32i +// CIR-NEXT: %[[AND:.*]] = cir.and %[[LOAD_FEAT2_0]], %[[MASK]] : !u32i +// CIR-NEXT: %[[RES:.*]] = cir.cmp eq %[[AND]], %[[MASK]] : !u32i +// CIR-NEXT: cir.if %[[RES]] { +// CIR-NEXT: %[[STR:.*]] = cir.get_global +// CIR-NEXT: %[[STR_DECAY:.*]] = cir.cast array_to_ptrdecay %[[STR]] : !cir.ptr<!cir.array<!s8i x 5>> -> !cir.ptr<!s8i> +// CIR-NEXT: cir.call @a(%[[STR_DECAY]]) : (!cir.ptr<!s8i> {llvm.noundef}) -> () +// CIR-NEXT: } +// CIR-NEXT: } + +// LLVM-LABEL: define dso_local i32 @main( +// LLVM-SAME: ) #[[ATTR0:[0-9]+]] { +// OGCG-NEXT: entry: +// LLVM-NEXT: [[RETVAL:%.*]] = alloca i32 +// LLVM-NEXT: store i32 0, ptr [[RETVAL]], align 4 +// LLVM-NEXT: call void @__cpu_indicator_init() +// +// CIR leaves an extra branch/newline/label here. +// LLVMCIR-NEXT: br label %[[BRANCH:.*]] +// LLVMCIR: [[BRANCH]]: +// +// LLVM-NEXT: [[TMP0:%.*]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 12), align 4 +// LLVM-NEXT: [[TMP1:%.*]] = and i32 [[TMP0]], 256 +// LLVM-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 256 +// +// OGCG-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] +// OGCG-NEXT: br i1 [[TMP3]], label %[[IF_THEN:.*]], label %[[IF_END:.*]] +// LLVMCIR-NEXT: br i1 [[TMP2]], label %[[IF_THEN:.*]], label %[[IF_END:.*]] +// +// LLVM: [[IF_THEN]]: +// LLVM-NEXT: call void @a(ptr noundef @.str) +// CIR has a meaningless set of empty blocks here. +// LLVM: br label %[[IF_END]] +// LLVM: [[IF_END]]: +// CIR has more meaningless empty blocks here. +// LLVM: [[TMP4:%.*]] = load i32, ptr @__cpu_features2, align 4 +// LLVM-NEXT: [[TMP5:%.*]] = and i32 [[TMP4]], 1 +// LLVM-NEXT: [[TMP6:%.*]] = icmp eq i32 [[TMP5]], 1 +// +// OGCG-NEXT: [[TMP7:%.*]] = and i1 true, [[TMP6]] +// OGCG-NEXT: br i1 [[TMP7]], label %[[IF_THEN1:.*]], label %[[IF_END1:.*]] +// LLVMCIR-NEXT: br i1 [[TMP6]], label %[[IF_THEN1:.*]], label %[[IF_END1:.*]] + +// +// LLVM: [[IF_THEN1]]: +// LLVM-NEXT: call void @a(ptr noundef @.str.1) + +int main(void) { + __builtin_cpu_init(); + + if (__builtin_cpu_supports("sse4.2")) + a("sse4.2"); + + + if (__builtin_cpu_supports("gfni")) + a("gfni"); + + + return 0; +} + + +// CIR-LABEL: cir.func{{.*}} @baseline() -> !s32i +// CIR-SAME: attributes {[[ATTRS]]} { +// CIR-NEXT: %[[RETVAL:.*]] = cir.alloca "__retval" {{.*}} : !cir.ptr<!s32i> +// CIR-NEXT: %[[CPU_FEAT2:.*]] = cir.get_global @__cpu_features2 : !cir.ptr<!cir.array<!u32i x 3>> +// CIR-NEXT: %[[ONE:.*]] = cir.const #cir.int<1> : !u32i +// CIR-NEXT: %[[FEAT2_ELT:.*]] = cir.get_element %[[CPU_FEAT2]][%[[ONE]] : !u32i] : !cir.ptr<!cir.array<!u32i x 3>> -> !cir.ptr<!u32i> +// CIR-NEXT: %[[FEAT2_ELT_LOAD:.*]] = cir.load {{.*}} %[[FEAT2_ELT]] : !cir.ptr<!u32i>, !u32i +// CIR-NEXT: %[[MASK:.*]] = cir.const #cir.int<2147483648> : !u32i +// CIR-NEXT: %[[AND:.*]] = cir.and %[[FEAT2_ELT_LOAD]], %[[MASK]] : !u32i +// CIR-NEXT: %[[RES:.*]] = cir.cmp eq %[[AND]], %[[MASK]] : !u32i +// CIR-NEXT: %[[CAST:.*]] = cir.cast bool_to_int %[[RES]] : !cir.bool -> !s32i +// CIR-NEXT: cir.store %[[CAST]], %[[RETVAL]] : !s32i, !cir.ptr<!s32i> +// CIR-NEXT: %[[LOAD_RET:.*]] = cir.load %[[RETVAL]] : !cir.ptr<!s32i>, !s32i +// CIR-NEXT: cir.return %[[LOAD_RET]] : !s32i + +// LLVM-LABEL: define dso_local i32 @baseline( +// LLVM-SAME: ) #[[ATTR0]] { +// OGCG-NEXT: entry: +// LLVMCIR-NEXT: [[RETVAL:%.*]] = alloca i32 +// LLVM-NEXT: [[TMP0:%.*]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_features2, i64 4), align 4 +// LLVM-NEXT: [[TMP1:%.*]] = and i32 [[TMP0]], -2147483648 +// LLVM-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], -2147483648 +// +// OGCG-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] +// OGCG-NEXT: [[CONV:%.*]] = zext i1 [[TMP3]] to i32 +// OGCG-NEXT: ret i32 [[CONV]] +// +// LLVMCIR-NEXT: [[EXT:%.*]] = zext i1 [[TMP2]] to i32 +// LLVMCIR-NEXT: store i32 [[EXT]], ptr [[RETVAL]] +// LLVMCIR-NEXT: [[LOAD_RET:%.*]] = load i32, ptr [[RETVAL]] +// LLVMCIR-NEXT: ret i32 [[LOAD_RET]] +// +int baseline() { return __builtin_cpu_supports("x86-64"); } + +// CIR-LABEL: cir.func{{.*}} @v2() -> !s32i +// CIR-SAME: attributes {[[ATTRS]]} { +// CIR-NEXT: %[[RETVAL:.*]] = cir.alloca "__retval" {{.*}} : !cir.ptr<!s32i> +// CIR-NEXT: %[[CPU_FEAT2:.*]] = cir.get_global @__cpu_features2 : !cir.ptr<!cir.array<!u32i x 3>> +// CIR-NEXT: %[[TWO:.*]] = cir.const #cir.int<2> : !u32i +// CIR-NEXT: %[[FEAT2_ELT:.*]] = cir.get_element %[[CPU_FEAT2]][%[[TWO]] : !u32i] : !cir.ptr<!cir.array<!u32i x 3>> -> !cir.ptr<!u32i> +// CIR-NEXT: %[[FEAT2_ELT_LOAD:.*]] = cir.load {{.*}} %[[FEAT2_ELT]] : !cir.ptr<!u32i>, !u32i +// CIR-NEXT: %[[MASK:.*]] = cir.const #cir.int<1> : !u32i +// CIR-NEXT: %[[AND:.*]] = cir.and %[[FEAT2_ELT_LOAD]], %[[MASK]] : !u32i +// CIR-NEXT: %[[RES:.*]] = cir.cmp eq %[[AND]], %[[MASK]] : !u32i +// CIR-NEXT: %[[CAST:.*]] = cir.cast bool_to_int %[[RES]] : !cir.bool -> !s32i +// CIR-NEXT: cir.store %[[CAST]], %[[RETVAL]] : !s32i, !cir.ptr<!s32i> +// CIR-NEXT: %[[LOAD_RET:.*]] = cir.load %[[RETVAL]] : !cir.ptr<!s32i>, !s32i +// CIR-NEXT: cir.return %[[LOAD_RET]] : !s32i + +// LLVM-LABEL: define dso_local i32 @v2( +// LLVM-SAME: ) #[[ATTR0]] { +// OGCG-NEXT: entry: +// LLVMCIR-NEXT: [[RETVAL:%.*]] = alloca i32 +// LLVM-NEXT: [[TMP0:%.*]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_features2, i64 8), align 4 +// LLVM-NEXT: [[TMP1:%.*]] = and i32 [[TMP0]], 1 +// LLVM-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 1 +// +// OGCG-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] +// OGCG-NEXT: [[CONV:%.*]] = zext i1 [[TMP3]] to i32 +// OGCG-NEXT: ret i32 [[CONV]] +// +// LLVMCIR-NEXT: [[EXT:%.*]] = zext i1 [[TMP2]] to i32 +// LLVMCIR-NEXT: store i32 [[EXT]], ptr [[RETVAL]] +// LLVMCIR-NEXT: [[LOAD_RET:%.*]] = load i32, ptr [[RETVAL]] +// LLVMCIR-NEXT: ret i32 [[LOAD_RET]] +// +int v2() { return __builtin_cpu_supports("x86-64-v2"); } + +// CIR-LABEL: cir.func{{.*}} @v3() -> !s32i +// CIR-SAME: attributes {[[ATTRS]]} { +// CIR-NEXT: %[[RETVAL:.*]] = cir.alloca "__retval" {{.*}} : !cir.ptr<!s32i> +// CIR-NEXT: %[[CPU_FEAT2:.*]] = cir.get_global @__cpu_features2 : !cir.ptr<!cir.array<!u32i x 3>> +// CIR-NEXT: %[[TWO:.*]] = cir.const #cir.int<2> : !u32i +// CIR-NEXT: %[[FEAT2_ELT:.*]] = cir.get_element %[[CPU_FEAT2]][%[[TWO]] : !u32i] : !cir.ptr<!cir.array<!u32i x 3>> -> !cir.ptr<!u32i> +// CIR-NEXT: %[[FEAT2_ELT_LOAD:.*]] = cir.load {{.*}} %[[FEAT2_ELT]] : !cir.ptr<!u32i>, !u32i +// CIR-NEXT: %[[MASK:.*]] = cir.const #cir.int<2> : !u32i +// CIR-NEXT: %[[AND:.*]] = cir.and %[[FEAT2_ELT_LOAD]], %[[MASK]] : !u32i +// CIR-NEXT: %[[RES:.*]] = cir.cmp eq %[[AND]], %[[MASK]] : !u32i +// CIR-NEXT: %[[CAST:.*]] = cir.cast bool_to_int %[[RES]] : !cir.bool -> !s32i +// CIR-NEXT: cir.store %[[CAST]], %[[RETVAL]] : !s32i, !cir.ptr<!s32i> +// CIR-NEXT: %[[LOAD_RET:.*]] = cir.load %[[RETVAL]] : !cir.ptr<!s32i>, !s32i +// CIR-NEXT: cir.return %[[LOAD_RET]] : !s32i + +// LLVM-LABEL: define dso_local i32 @v3( +// LLVM-SAME: ) #[[ATTR0]] { +// OGCG-NEXT: entry: +// LLVMCIR-NEXT: [[RETVAL:%.*]] = alloca i32 +// LLVM-NEXT: [[TMP0:%.*]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_features2, i64 8), align 4 +// LLVM-NEXT: [[TMP1:%.*]] = and i32 [[TMP0]], 2 +// LLVM-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 2 +// +// OGCG-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] +// OGCG-NEXT: [[CONV:%.*]] = zext i1 [[TMP3]] to i32 +// OGCG-NEXT: ret i32 [[CONV]] +// +// LLVMCIR-NEXT: [[EXT:%.*]] = zext i1 [[TMP2]] to i32 +// LLVMCIR-NEXT: store i32 [[EXT]], ptr [[RETVAL]] +// LLVMCIR-NEXT: [[LOAD_RET:%.*]] = load i32, ptr [[RETVAL]] +// LLVMCIR-NEXT: ret i32 [[LOAD_RET]] +// +int v3() { return __builtin_cpu_supports("x86-64-v3"); } + +// CIR-LABEL: cir.func{{.*}} @v4() -> !s32i +// CIR-SAME: attributes {[[ATTRS]]} { +// CIR-NEXT: %[[RETVAL:.*]] = cir.alloca "__retval" {{.*}} : !cir.ptr<!s32i> +// CIR-NEXT: %[[CPU_FEAT2:.*]] = cir.get_global @__cpu_features2 : !cir.ptr<!cir.array<!u32i x 3>> +// CIR-NEXT: %[[TWO:.*]] = cir.const #cir.int<2> : !u32i +// CIR-NEXT: %[[FEAT2_ELT:.*]] = cir.get_element %[[CPU_FEAT2]][%[[TWO]] : !u32i] : !cir.ptr<!cir.array<!u32i x 3>> -> !cir.ptr<!u32i> +// CIR-NEXT: %[[FEAT2_ELT_LOAD:.*]] = cir.load {{.*}} %[[FEAT2_ELT]] : !cir.ptr<!u32i>, !u32i +// CIR-NEXT: %[[MASK:.*]] = cir.const #cir.int<4> : !u32i +// CIR-NEXT: %[[AND:.*]] = cir.and %[[FEAT2_ELT_LOAD]], %[[MASK]] : !u32i +// CIR-NEXT: %[[RES:.*]] = cir.cmp eq %[[AND]], %[[MASK]] : !u32i +// CIR-NEXT: %[[CAST:.*]] = cir.cast bool_to_int %[[RES]] : !cir.bool -> !s32i +// CIR-NEXT: cir.store %[[CAST]], %[[RETVAL]] : !s32i, !cir.ptr<!s32i> +// CIR-NEXT: %[[LOAD_RET:.*]] = cir.load %[[RETVAL]] : !cir.ptr<!s32i>, !s32i +// CIR-NEXT: cir.return %[[LOAD_RET]] : !s32i + +// LLVM-LABEL: define dso_local i32 @v4( +// LLVM-SAME: ) #[[ATTR0]] { +// OGCG-NEXT: entry: +// LLVMCIR-NEXT: [[RETVAL:%.*]] = alloca i32 +// LLVM-NEXT: [[TMP0:%.*]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_features2, i64 8), align 4 +// LLVM-NEXT: [[TMP1:%.*]] = and i32 [[TMP0]], 4 +// LLVM-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 4 +// +// OGCG-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] +// OGCG-NEXT: [[CONV:%.*]] = zext i1 [[TMP3]] to i32 +// OGCG-NEXT: ret i32 [[CONV]] +// +// LLVMCIR-NEXT: [[EXT:%.*]] = zext i1 [[TMP2]] to i32 +// LLVMCIR-NEXT: store i32 [[EXT]], ptr [[RETVAL]] +// LLVMCIR-NEXT: [[LOAD_RET:%.*]] = load i32, ptr [[RETVAL]] +// LLVMCIR-NEXT: ret i32 [[LOAD_RET]] +int v4() { return __builtin_cpu_supports("x86-64-v4"); } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
