[clang] [clang][clangIR]: Implement builtin x86 arch cpu detection. (PR #212143)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Jul 26 11:56:41 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Lucas Ribeiro (lucaslive974)
<details>
<summary>Changes</summary>
This PR implements x86 CPU feature detection builtins for ClangIR.
Adresses #<!-- -->167765
---
Patch is 217.22 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/212143.diff
6 Files Affected:
- (modified) clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp (+162-12)
- (added) clang/test/CIR/CodeGenBuiltins/X86/builtin-cpu-is-cputype.c (+440)
- (added) clang/test/CIR/CodeGenBuiltins/X86/builtin-cpu-is-subtype.c (+792)
- (added) clang/test/CIR/CodeGenBuiltins/X86/builtin-cpu-is-vendor.c (+71)
- (added) clang/test/CIR/CodeGenBuiltins/X86/builtin-cpu-supports-all.c (+2193)
- (added) clang/test/CIR/CodeGenBuiltins/X86/builtin-cpu-supports.c (+222)
``````````diff
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp
index 2369c654833cf..9f7307f3cb1e5 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,21 +909,170 @@ static mlir::Value emitX86PackedByteShift(CIRGenBuilderTy &builder,
return shuffleResult;
}
-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{};
+static mlir::Value emitX86CpuInit(CIRGenModule &module,
+ CIRGenBuilderTy &builder,
+ mlir::Location loc) {
+ cir::VoidType voidTy = builder.getVoidTy();
+ cir::FuncType fnTy = builder.getFuncType({}, voidTy);
+
+ cir::FuncOp fn = module.createRuntimeFunction(fnTy, "__cpu_indicator_init");
+ fn.setDsoLocal(true);
+ fn.setBuiltin(true);
+
+ return builder.createCallOp(loc, fn, mlir::ValueRange{}).getResult();
+}
+
+// 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];
+static cir::GetGlobalOp getX86CpuModelGlobalRecord(CIRGenModule &module,
+ CIRGenBuilderTy &builder,
+ mlir::Location loc) {
+ auto u32iTy = builder.getUInt32Ty();
+ auto arrTy = cir::ArrayType::get(u32iTy, /**size=*/1);
+ cir::StructType sTy =
+ builder.getAnonRecordTy({u32iTy, u32iTy, u32iTy, arrTy});
+
+ cir::GlobalOp cpuModel;
+ if (auto it = module.symbolLookupCache.find("__cpu_model");
+ it == module.symbolLookupCache.end()) {
+ cpuModel = module.createGlobalOp(loc, "__cpu_model", sTy);
+ cpuModel.setDSOLocal(true);
+ } else
+ cpuModel = cast<cir::GlobalOp>(it->second);
+
+ return builder.createGetGlobal(cpuModel);
+}
+
+static mlir::Value emitX86CpuIs(CIRGenModule &module, CIRGenBuilderTy &builder,
+ mlir::Location loc, llvm::StringRef cpuStr) {
+ // Calculate the index needed to access the correct field based on the
+ // range. ABI_VALUE matches with compiler-rt/libgcc values.
+ auto [index, abiValue, member] =
+ mlir::StringSwitch<std::tuple<unsigned, unsigned, llvm::StringRef>>(
+ cpuStr)
+#define X86_VENDOR(ENUM, STR, ABI_VALUE) \
+ .Case(STR, {0u, ABI_VALUE, "__cpu_vendor"})
+#define X86_CPU_TYPE(ENUM, STR, ABI_VALUE) \
+ .Case(STR, {1u, ABI_VALUE, "__cpu_type"})
+#define X86_CPU_SUBTYPE(ENUM, STR, ABI_VALUE) \
+ .Case(STR, {2u, ABI_VALUE, "__cpu_subtype"})
+#include "llvm/TargetParser/X86TargetParser.def"
+ .Default({0, 0, ""});
+ assert(abiValue != 0 && "Invalid CPUStr passed to CpuIs");
+
+ auto u32iTy = builder.getUInt32Ty();
+
+ cir::GetGlobalOp cpuModel = getX86CpuModelGlobalRecord(module, builder, loc);
+ cir::GetMemberOp cpuValue = builder.createGetMember(
+ loc, builder.getPointerTo(u32iTy), cpuModel, member, index);
+ mlir::Value value = builder.createAlignedLoad(loc, u32iTy, cpuValue,
+ CharUnits::fromQuantity(4));
+
+ return builder.createCompare(loc, cir::CmpOpKind::eq, value,
+ /**rhs=*/builder.getUInt32(abiValue, loc));
+}
+
+// Matching the struct layout from the compiler-rt/libgcc structure that is
+// filled in:
+// unsigned int __features2[3];
+static cir::GetGlobalOp getX86CpuFeature2GlobalRecord(CIRGenModule &module,
+ CIRGenBuilderTy &builder,
+ mlir::Location loc) {
+ auto u32iTy = builder.getUInt32Ty();
+ auto arrTy = cir::ArrayType::get(u32iTy, /**size=*/3);
+
+ cir::GlobalOp cpuFeatures;
+ if (auto it = module.symbolLookupCache.find("__cpu_features2");
+ it == module.symbolLookupCache.end()) {
+ cpuFeatures = module.createGlobalOp(loc, "__cpu_features2", arrTy);
+ cpuFeatures.setDSOLocal(true);
+ } else
+ cpuFeatures = cast<cir::GlobalOp>(it->second);
+
+ return builder.createGetGlobal(cpuFeatures);
+}
+
+static mlir::Value emitX86CpuSupports(CIRGenModule &module,
+ CIRGenBuilderTy &builder,
+ mlir::Location loc,
+ llvm::StringRef featureStr) {
+ if (!module.getASTContext().getTargetInfo().validateCpuSupports(featureStr))
+ return builder.getFalse(loc);
+
+ std::array<uint32_t, 4> cpuSupportMask =
+ llvm::X86::getCpuSupportsMask(featureStr);
+
+ auto u32iTy = builder.getUInt32Ty();
+ auto arrTy = cir::ArrayType::get(u32iTy, 1);
+ auto aligmentUnit = CharUnits::fromQuantity(4);
+
+ mlir::Value result = builder.getTrue(loc);
+ if (cpuSupportMask[0] != 0) {
+ cir::GetGlobalOp cpuModel =
+ getX86CpuModelGlobalRecord(module, builder, loc);
+ cir::GetMemberOp cpuFeatureArr = builder.createGetMember(
+ loc, builder.getPointerTo(arrTy), cpuModel, "__cpu_feature", 3);
+
+ mlir::Value feature0Ptr =
+ builder.getArrayElement(loc, loc, cpuFeatureArr, u32iTy,
+ /**idx=*/builder.getUInt32(0, loc),
+ /**shouldDecay=*/false);
+ cir::LoadOp feature0 =
+ builder.createAlignedLoad(loc, u32iTy, feature0Ptr, aligmentUnit);
+
+ cir::ConstantOp mask = builder.getUInt32(cpuSupportMask[0], loc);
+ mlir::Value bitset = builder.createAnd(loc, feature0, mask);
+ mlir::Value cmp =
+ builder.createCompare(loc, cir::CmpOpKind::eq, bitset, mask);
+
+ result = builder.createAnd(loc, result, cmp);
}
- if (builtinID == Builtin::BI__builtin_cpu_init) {
- cgm.errorNYI(expr->getSourceRange(), "__builtin_cpu_init");
- return mlir::Value{};
+
+ cir::GetGlobalOp cpuFeature2Arr =
+ getX86CpuFeature2GlobalRecord(module, builder, loc);
+ for (unsigned idx : llvm::seq(1, 4)) {
+ const uint32_t featureMask = cpuSupportMask[idx];
+ if (!featureMask)
+ continue;
+
+ auto featurePtr =
+ builder.getArrayElement(loc, loc, cpuFeature2Arr, u32iTy,
+ /**idx=*/builder.getUInt32(idx - 1, loc),
+ /**shouldDecay=*/true);
+ mlir::Value feature =
+ builder.createAlignedLoad(loc, u32iTy, featurePtr, aligmentUnit);
+
+ cir::ConstantOp mask = builder.getUInt32(featureMask, loc);
+ mlir::Value bitset = builder.createAnd(loc, feature, mask);
+ mlir::Value cmp =
+ builder.createCompare(loc, cir::CmpOpKind::eq, bitset, mask);
+
+ result = builder.createAnd(loc, result, cmp);
}
+ return result;
+}
+
+static llvm::StringRef getX86CpuString(const CallExpr *expr) {
+ const Expr *cpuExpr = expr->getArg(0)->IgnoreParenCasts();
+ return cast<clang::StringLiteral>(cpuExpr)->getString();
+}
+
+std::optional<mlir::Value>
+CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID, const CallExpr *expr) {
+ if (builtinID == Builtin::BI__builtin_cpu_is)
+ return emitX86CpuIs(cgm, builder, getLoc(expr->getExprLoc()),
+ getX86CpuString(expr));
+ if (builtinID == Builtin::BI__builtin_cpu_supports)
+ return emitX86CpuSupports(cgm, builder, getLoc(expr->getExprLoc()),
+ getX86CpuString(expr));
+ if (builtinID == Builtin::BI__builtin_cpu_init)
+ return emitX86CpuInit(cgm, builder, getLoc(expr->getExprLoc()));
+
// Handle MSVC intrinsics before argument evaluation to prevent double
// evaluation.
assert(!cir::MissingFeatures::msvcBuiltins());
diff --git a/clang/test/CIR/CodeGenBuiltins/X86/builtin-cpu-is-cputype.c b/clang/test/CIR/CodeGenBuiltins/X86/builtin-cpu-is-cputype.c
new file mode 100644
index 0000000000000..2920120f0e521
--- /dev/null
+++ b/clang/test/CIR/CodeGenBuiltins/X86/builtin-cpu-is-cputype.c
@@ -0,0 +1,440 @@
+// RUN: %clang_cc1 -x c -ffreestanding -triple x86_64-unknown-linux -Wno-implicit-function-declaration -fclangir -emit-cir -o %t.cir %s
+// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
+
+// RUN: %clang_cc1 -x c -ffreestanding -triple x86_64-unknown-linux -Wno-implicit-function-declaration -fclangir -emit-llvm -o %t.ll %s
+// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s
+
+// RUN: %clang_cc1 -ffreestanding -triple=x86_64-pc-linux-gnu -emit-llvm -Wall -Werror %s -o - | FileCheck %s -check-prefix=OGCG
+
+// 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: !rec_anon_struct = !cir.struct<{!u32i, !u32i, !u32i, !cir.array<!u32i x 1>}>
+// CIR: cir.global "private" external dso_local @__cpu_model : !rec_anon_struct
+// LLVM: @__cpu_model = external dso_local global { i32, i32, i32, [1 x i32] }
+// OGCG: @__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 no_inline dso_local @test_bonnell(
+// CIR: [[GLOBAL:%.]] = cir.get_global @__cpu_model : !cir.ptr<!rec_anon_struct>
+// CIR-NEXT: [[CPUTYPE:%.]] = cir.get_member [[GLOBAL]][1] {name = "__cpu_type"} : !cir.ptr<!rec_anon_struct> -> !cir.ptr<!u32i>
+// CIR-NEXT: [[VALUE:%.]] = cir.load align(4) [[CPUTYPE]] : !cir.ptr<!u32i>, !u32i
+// CIR-NEXT: [[MASK:%.]] = cir.const #cir.int<1> : !u32i
+// CIR-NEXT: {{.*}} = cir.cmp eq [[VALUE]], [[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
+
+// OGCG-LABEL: define{{.*}} void @test_bonnell(
+// OGCG: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 4)
+// OGCG: = icmp eq i32 [[LOAD]], 1
+TEST_CPU_IS(bonnell, "bonnell")
+
+// CIR-LABEL: cir.func no_inline dso_local @test_core2(
+// CIR: [[GLOBAL:%.]] = cir.get_global @__cpu_model : !cir.ptr<!rec_anon_struct>
+// CIR-NEXT: [[CPUTYPE:%.]] = cir.get_member [[GLOBAL]][1] {name = "__cpu_type"} : !cir.ptr<!rec_anon_struct> -> !cir.ptr<!u32i>
+// CIR-NEXT: [[VALUE:%.]] = cir.load align(4) [[CPUTYPE]] : !cir.ptr<!u32i>, !u32i
+// CIR-NEXT: [[MASK:%.]] = cir.const #cir.int<2> : !u32i
+// CIR-NEXT: {{.*}} = cir.cmp eq [[VALUE]], [[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
+
+// OGCG-LABEL: define{{.*}} void @test_core2(
+// OGCG: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 4)
+// OGCG: = icmp eq i32 [[LOAD]], 2
+TEST_CPU_IS(core2, "core2")
+
+// CIR-LABEL: cir.func no_inline dso_local @test_corei7(
+// CIR: [[GLOBAL:%.]] = cir.get_global @__cpu_model : !cir.ptr<!rec_anon_struct>
+// CIR-NEXT: [[CPUTYPE:%.]] = cir.get_member [[GLOBAL]][1] {name = "__cpu_type"} : !cir.ptr<!rec_anon_struct> -> !cir.ptr<!u32i>
+// CIR-NEXT: [[VALUE:%.]] = cir.load align(4) [[CPUTYPE]] : !cir.ptr<!u32i>, !u32i
+// CIR-NEXT: [[MASK:%.]] = cir.const #cir.int<3> : !u32i
+// CIR-NEXT: {{.*}} = cir.cmp eq [[VALUE]], [[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
+
+// OGCG-LABEL: define{{.*}} void @test_corei7(
+// OGCG: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 4)
+// OGCG: = icmp eq i32 [[LOAD]], 3
+TEST_CPU_IS(corei7, "corei7")
+
+// CIR-LABEL: cir.func no_inline dso_local @test_amdfam10h(
+// CIR: [[GLOBAL:%.]] = cir.get_global @__cpu_model : !cir.ptr<!rec_anon_struct>
+// CIR-NEXT: [[CPUTYPE:%.]] = cir.get_member [[GLOBAL]][1] {name = "__cpu_type"} : !cir.ptr<!rec_anon_struct> -> !cir.ptr<!u32i>
+// CIR-NEXT: [[VALUE:%.]] = cir.load align(4) [[CPUTYPE]] : !cir.ptr<!u32i>, !u32i
+// CIR-NEXT: [[MASK:%.]] = cir.const #cir.int<4> : !u32i
+// CIR-NEXT: {{.*}} = cir.cmp eq [[VALUE]], [[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
+
+// OGCG-LABEL: define{{.*}} void @test_amdfam10h(
+// OGCG: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 4)
+// OGCG: = icmp eq i32 [[LOAD]], 4
+TEST_CPU_IS(amdfam10h, "amdfam10h")
+
+// CIR-LABEL: cir.func no_inline dso_local @test_amdfam15h(
+// CIR: [[GLOBAL:%.]] = cir.get_global @__cpu_model : !cir.ptr<!rec_anon_struct>
+// CIR-NEXT: [[CPUTYPE:%.]] = cir.get_member [[GLOBAL]][1] {name = "__cpu_type"} : !cir.ptr<!rec_anon_struct> -> !cir.ptr<!u32i>
+// CIR-NEXT: [[VALUE:%.]] = cir.load align(4) [[CPUTYPE]] : !cir.ptr<!u32i>, !u32i
+// CIR-NEXT: [[MASK:%.]] = cir.const #cir.int<5> : !u32i
+// CIR-NEXT: {{.*}} = cir.cmp eq [[VALUE]], [[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
+
+// OGCG-LABEL: define{{.*}} void @test_amdfam15h(
+// OGCG: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 4)
+// OGCG: = icmp eq i32 [[LOAD]], 5
+TEST_CPU_IS(amdfam15h, "amdfam15h")
+
+// CIR-LABEL: cir.func no_inline dso_local @test_silvermont(
+// CIR: [[GLOBAL:%.]] = cir.get_global @__cpu_model : !cir.ptr<!rec_anon_struct>
+// CIR-NEXT: [[CPUTYPE:%.]] = cir.get_member [[GLOBAL]][1] {name = "__cpu_type"} : !cir.ptr<!rec_anon_struct> -> !cir.ptr<!u32i>
+// CIR-NEXT: [[VALUE:%.]] = cir.load align(4) [[CPUTYPE]] : !cir.ptr<!u32i>, !u32i
+// CIR-NEXT: [[MASK:%.]] = cir.const #cir.int<6> : !u32i
+// CIR-NEXT: {{.*}} = cir.cmp eq [[VALUE]], [[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
+
+// OGCG-LABEL: define{{.*}} void @test_silvermont(
+// OGCG: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 4)
+// OGCG: = icmp eq i32 [[LOAD]], 6
+TEST_CPU_IS(silvermont, "silvermont")
+
+// CIR-LABEL: cir.func no_inline dso_local @test_knl(
+// CIR: [[GLOBAL:%.]] = cir.get_global @__cpu_model : !cir.ptr<!rec_anon_struct>
+// CIR-NEXT: [[CPUTYPE:%.]] = cir.get_member [[GLOBAL]][1] {name = "__cpu_type"} : !cir.ptr<!rec_anon_struct> -> !cir.ptr<!u32i>
+// CIR-NEXT: [[VALUE:%.]] = cir.load align(4) [[CPUTYPE]] : !cir.ptr<!u32i>, !u32i
+// CIR-NEXT: [[MASK:%.]] = cir.const #cir.int<7> : !u32i
+// CIR-NEXT: {{.*}} = cir.cmp eq [[VALUE]], [[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
+
+// OGCG-LABEL: define{{.*}} void @test_knl(
+// OGCG: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 4)
+// OGCG: = icmp eq i32 [[LOAD]], 7
+TEST_CPU_IS(knl, "knl")
+
+// CIR-LABEL: cir.func no_inline dso_local @test_btver1(
+// CIR: [[GLOBAL:%.]] = cir.get_global @__cpu_model : !cir.ptr<!rec_anon_struct>
+// CIR-NEXT: [[CPUTYPE:%.]] = cir.get_member [[GLOBAL]][1] {name = "__cpu_type"} : !cir.ptr<!rec_anon_struct> -> !cir.ptr<!u32i>
+// CIR-NEXT: [[VALUE:%.]] = cir.load align(4) [[CPUTYPE]] : !cir.ptr<!u32i>, !u32i
+// CIR-NEXT: [[MASK:%.]] = cir.const #cir.int<8> : !u32i
+// CIR-NEXT: {{.*}} = cir.cmp eq [[VALUE]], [[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
+
+// OGCG-LABEL: define{{.*}} void @test_btver1(
+// OGCG: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 4)
+// OGCG: = icmp eq i32 [[LOAD]], 8
+TEST_CPU_IS(btver1, "btver1")
+
+// CIR-LABEL: cir.func no_inline dso_local @test_btver2(
+// CIR: [[GLOBAL:%.]] = cir.get_global @__cpu_model : !cir.ptr<!rec_anon_struct>
+// CIR-NEXT: [[CPUTYPE:%.]] = cir.get_member [[GLOBAL]][1] {name = "__cpu_type"} : !cir.ptr<!rec_anon_struct> -> !cir.ptr<!u32i>
+// CIR-NEXT: [[VALUE:%.]] = cir.load align(4) [[CPUTYPE]] : !cir.ptr<!u32i>, !u32i
+// CIR-NEXT: [[MASK:%.]] = cir.const #cir.int<9> : !u32i
+// CIR-NEXT: {{.*}} = cir.cmp eq [[VALUE]], [[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
+
+// OGCG-LABEL: define{{.*}} void @test_btver2(
+// OGCG: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 4)
+// OGCG: = icmp eq i32 [[LOAD]], 9
+TEST_CPU_IS(btver2, "btver2")
+
+// CIR-LABEL: cir.func no_inline dso_local @test_amdfam17h(
+// CIR: [[GLOBAL:%.]] = cir.get_global @__cpu_model : !cir.ptr<!rec_anon_struct>
+// CIR-NEXT: [[CPUTYPE:%.]] = cir.get_member [[GLOBAL]][1] {name = "__cpu_type"} : !cir.ptr<!rec_anon_struct> -> !cir.ptr<!u32i>
+// CIR-NEXT: [[VALUE:%.]] = cir.load align(4) [[CPUTYPE]] : !cir.ptr<!u32i>, !u32i
+// CIR-NEXT: [[MASK:%.]] = cir.const #cir.int<10> : !u32i
+// CIR-NEXT: {{.*}} = cir.cmp eq [[VALUE]], [[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
+
+// OGCG-LABEL: define{{.*}} void @test_amdfam17h(
+// OGCG: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 4)
+// OGCG: = icmp eq i32 [[LOAD]], 10
+TEST_CPU_IS(amdfam17h, "amdfam17h")
+
+// CIR-LABEL: cir.func no_inline dso_local @test_knm(
+// CIR: [[GLOBAL:%.]] = cir.get_global @__cpu_model : !cir.ptr<!rec_anon_struct>
+// CIR-NEXT: [[CPUTYPE:%.]] = cir.get_member [[GLOBAL]][1] {name = "__cpu_type"} : !cir.ptr<!rec_anon_struct> -> !cir.ptr<!u32i>
+// CIR-NEXT: [[VALUE:%.]] = cir.load align(4) [[CPUTYPE]] : !cir.ptr<!u32i>, !u32i
+// CIR-NEXT: [[MASK:%.]] = cir.const #cir.int<11> : !u32i
+// CIR-NEXT: {{.*}} = cir.cmp eq [[VALUE]], [[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
+
+// OGCG-LABEL: define{{.*}} void @test_knm(
+// OGCG: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 4)
+// OGCG: = icmp eq i32 [[LOAD]], 11
+TEST_CPU_IS(knm, "knm")
+
+// CIR-LABEL: cir.func no_inline dso_local @test_goldmont(
+// CIR: [[GLOBAL:%.]] = cir.get_global @__cpu_model : !cir.ptr<!rec_anon_struct>
+// CIR-NEXT: [[CPUTYPE:%.]] = cir.get_member [[GLOBAL]][1] {name = "__cpu_type"} : !cir.ptr<!rec_anon_struct> -> !cir.ptr<!u32i>
+// CIR-NEXT: [[VALUE:%.]] = cir.load align(4) [[CPUTYPE]] : !cir.ptr<!u32i>, !u32i
+// CIR-NEXT: [[MASK:%.]] = cir.const #cir.int<12> : !u32i
+// CIR-NEXT: {{.*}} = cir.cmp eq [[VALUE]], [[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
+
+// OGCG-LABEL: define{{.*}} void @test_goldmont(
+// OGCG: [[LOAD:%[^ ]+]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @__cpu_model, i64 4)
+// OGCG: = icmp eq i32 [[LOAD]], 12
+TEST_CPU_IS(goldmon...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/212143
More information about the cfe-commits
mailing list