https://github.com/rturrado updated https://github.com/llvm/llvm-project/pull/173197
>From bab70fe98ebcbaa0d4a9ff13e46c22f5c7cd886c Mon Sep 17 00:00:00 2001 From: rturrado <[email protected]> Date: Fri, 19 Dec 2025 21:02:27 +0100 Subject: [PATCH 1/6] [CIR][X86] Add support for cpuid/cpuidex --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 27 +++++++ clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp | 12 +++- .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 70 +++++++++++++++++++ 3 files changed, 108 insertions(+), 1 deletion(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 50798be64551a..4998f307ee8e7 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -5896,4 +5896,31 @@ def CIR_BlockAddressOp : CIR_Op<"block_address", [Pure]> { }]; } +//===----------------------------------------------------------------------===// +// CpuIdOp +//===----------------------------------------------------------------------===// + +def CIR_CpuIdOp : CIR_Op<"cpuid"> { + let summary = "Get information about the CPU"; + let description = [{ + The `cir.cpuid` operation takes a base pointer to an array of 4 integers, a + function ID and a sub-function ID. The array of 4 integers is filled with + different information about the processor. + + Example: + + ```mlir + cir.cpuid %basePtr, %funcId, %subFuncId + : (!cir.ptr<!cir.array<4 x !s32i>>, !s32i, !s32i) + ``` + }]; + + let arguments = + (ins Arg<CIR_PtrToArray, "array address", [MemWrite]>:$basePtr, + CIR_SInt32:$funcId, CIR_SInt32:$subFuncId); + // TODO: remove once we can return an optional mlir::Value from + // emitX86BuiltinExpr + let results = (outs CIR_VectorType:$result); +} + #endif // CLANG_CIR_DIALECT_IR_CIROPS_TD diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp index 8bf3e63ad9179..00b50a3c74d6b 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp @@ -25,6 +25,7 @@ #include "clang/CIR/Dialect/IR/CIRTypes.h" #include "clang/CIR/MissingFeatures.h" #include "llvm/ADT/Sequence.h" +#include "llvm/IR/InlineAsm.h" #include "llvm/Support/ErrorHandling.h" #include <string> @@ -1949,7 +1950,16 @@ CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID, const CallExpr *expr) { return emitX86Select(builder, loc, ops[2], res, ops[1]); } case X86::BI__cpuid: - case X86::BI__cpuidex: + case X86::BI__cpuidex: { + mlir::Location loc = getLoc(expr->getExprLoc()); + mlir::Type i32Ty = builder.getSInt32Ty(); + mlir::Value subFuncId = builtinID == X86::BI__cpuidex + ? ops[2] + : builder.getConstInt(loc, sInt32Ty, 0); + cir::CpuIdOp::create(builder, loc, i32Ty, /*basePtr=*/ops[0], + /*funcId=*/ops[1], /*subFuncId=*/subFuncId); + return mlir::Value{}; + } case X86::BI__emul: case X86::BI__emulu: case X86::BI__mulh: diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 914233d8f6b8f..9d1e1e9fd2398 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -4282,6 +4282,76 @@ mlir::LogicalResult CIRToLLVMAwaitOpLowering::matchAndRewrite( return mlir::failure(); } +mlir::LogicalResult CIRToLLVMCpuIdOpLowering::matchAndRewrite( + cir::CpuIdOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + mlir::Type i32Ty = rewriter.getI32Type(); + mlir::Type i64Ty = rewriter.getI64Type(); + mlir::Type i32PtrTy = mlir::LLVM::LLVMPointerType::get(i32Ty.getContext(), 0); + + mlir::Type cpuidRetTy = mlir::LLVM::LLVMStructType::getLiteral( + rewriter.getContext(), {i32Ty, i32Ty, i32Ty, i32Ty}); + + mlir::Value funcId = adaptor.getFuncId(); + mlir::Value subFuncId = adaptor.getSubFuncId(); + mlir::StringAttr opNameAttr = op->getAttrOfType<mlir::StringAttr>("name"); + if (!opNameAttr) + return mlir::failure(); + if (opNameAttr.getValue() == "cpuid") + subFuncId = mlir::LLVM::ConstantOp::create(rewriter, op.getLoc(), i32Ty, 0); + std::vector operands{funcId, subFuncId}; + + StringRef asmString, constraints; + mlir::ModuleOp moduleOp = op->getParentOfType<mlir::ModuleOp>(); + mlir::StringAttr tripleAttr = + moduleOp->getAttrOfType<mlir::StringAttr>("llvm.target_triple"); + if (!tripleAttr) + return mlir::failure(); + llvm::Triple triple(tripleAttr.getValue().str()); + if (triple.getArch() == llvm::Triple::x86) { + asmString = "cpuid"; + constraints = "={ax},={bx},={cx},={dx},{ax},{cx}"; + } else { + // x86-64 uses %rbx as the base register, so preserve it. + asmString = "xchgq %rbx, ${1:q}\n" + "cpuid\n" + "xchgq %rbx, ${1:q}"; + constraints = "={ax},=r,={cx},={dx},0,2"; + } + + mlir::Value inlineAsm = + mlir::LLVM::InlineAsmOp::create( + rewriter, op.getLoc(), cpuidRetTy, mlir::ValueRange(operands), + rewriter.getStringAttr(asmString), + rewriter.getStringAttr(constraints), + /*has_side_effects=*/mlir::UnitAttr{}, + /*is_align_stack=*/mlir::UnitAttr{}, + /*tail_call_kind=*/mlir::LLVM::TailCallKindAttr{}, + /*asm_dialect=*/mlir::LLVM::AsmDialectAttr{}, + /*operand_attrs=*/mlir::ArrayAttr{}) + .getResult(0); + + mlir::Value basePtr = adaptor.getBasePtr(); + + mlir::DataLayout layout(op->getParentOfType<mlir::ModuleOp>()); + unsigned alignment = layout.getTypeABIAlignment(i32Ty); + for (unsigned i = 0; i < 4; i++) { + mlir::Value extracted = + mlir::LLVM::ExtractValueOp::create(rewriter, op.getLoc(), inlineAsm, i) + .getResult(); + mlir::Value index = mlir::LLVM::ConstantOp::create( + rewriter, op.getLoc(), i64Ty, rewriter.getI64IntegerAttr(i)); + llvm::SmallVector<mlir::Value, 1> gepIndices = {index}; + mlir::Value storePtr = mlir::LLVM::GEPOp::create( + rewriter, op.getLoc(), i32PtrTy, i32Ty, basePtr, + gepIndices, mlir::LLVM::GEPNoWrapFlags::none) + .getResult(); + mlir::LLVM::StoreOp::create(rewriter, op.getLoc(), extracted, storePtr, + alignment); + } + return mlir::success(); +} + std::unique_ptr<mlir::Pass> createConvertCIRToLLVMPass() { return std::make_unique<ConvertCIRToLLVMPass>(); } >From 6979f456a475bfe92bbc7a286a51c56ffba26afd Mon Sep 17 00:00:00 2001 From: rturrado <[email protected]> Date: Thu, 25 Dec 2025 19:32:54 +0100 Subject: [PATCH 2/6] Address review comments from Lancern --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 18 ++++++++++----- clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp | 1 - clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 22 +++++++++++++++++++ .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 19 +++++----------- 4 files changed, 40 insertions(+), 20 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 4998f307ee8e7..3a4fe958e1804 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -5903,9 +5903,16 @@ def CIR_BlockAddressOp : CIR_Op<"block_address", [Pure]> { def CIR_CpuIdOp : CIR_Op<"cpuid"> { let summary = "Get information about the CPU"; let description = [{ - The `cir.cpuid` operation takes a base pointer to an array of 4 integers, a - function ID and a sub-function ID. The array of 4 integers is filled with - different information about the processor. + The `cir.cpuid` operation retrieves different types of CPU information and + stores it in an array of 4 integers. + + This operation takes 3 arguments: `basePtr`, a pointer to an array of 4 + integers; `funcID`, an integer determining what type of information to be + retrieved (for instance, basic information, processor information and + features, or cache/TLB information); and `subFuncId`, an integer that adds + more detail about what information is requested. + + As a result, the array of 4 integers is filled with the requested information. Example: @@ -5918,9 +5925,8 @@ def CIR_CpuIdOp : CIR_Op<"cpuid"> { let arguments = (ins Arg<CIR_PtrToArray, "array address", [MemWrite]>:$basePtr, CIR_SInt32:$funcId, CIR_SInt32:$subFuncId); - // TODO: remove once we can return an optional mlir::Value from - // emitX86BuiltinExpr - let results = (outs CIR_VectorType:$result); + + let hasVerifier = 1; } #endif // CLANG_CIR_DIALECT_IR_CIROPS_TD diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp index 00b50a3c74d6b..16d8b36853a93 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp @@ -25,7 +25,6 @@ #include "clang/CIR/Dialect/IR/CIRTypes.h" #include "clang/CIR/MissingFeatures.h" #include "llvm/ADT/Sequence.h" -#include "llvm/IR/InlineAsm.h" #include "llvm/Support/ErrorHandling.h" #include <string> diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 063896b00a5a5..6945176537c89 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -3565,6 +3565,28 @@ cir::EhTypeIdOp::verifySymbolUses(SymbolTableCollection &symbolTable) { return success(); } +//===----------------------------------------------------------------------===// +// CpuIdOp +//===----------------------------------------------------------------------===// + +LogicalResult cir::CpuIdOp::verify() { + auto basePtrTy = mlir::dyn_cast<cir::PointerType>(getBasePtr().getType()); + if (!basePtrTy) + return mlir::failure(); + + auto arrayTy = mlir::dyn_cast<cir::ArrayType>(basePtrTy.getPointee()); + if (!arrayTy) + return mlir::failure(); + if (arrayTy.getSize() != 4) + return emitOpError() << "base pointer must point to an array of size 4"; + + auto intTy = mlir::dyn_cast<cir::IntType>(arrayTy.getElementType()); + if (!intTy || !intTy.isSigned() || intTy.getWidth() != 32) + return emitOpError() << "base pointer must point to an array of !s32i"; + + return mlir::success(); +} + //===----------------------------------------------------------------------===// // TableGen'd op method definitions //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 9d1e1e9fd2398..c647ceb2a4577 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -12,6 +12,7 @@ #include "LowerToLLVM.h" +#include <array> #include <deque> #include <optional> @@ -4294,21 +4295,11 @@ mlir::LogicalResult CIRToLLVMCpuIdOpLowering::matchAndRewrite( mlir::Value funcId = adaptor.getFuncId(); mlir::Value subFuncId = adaptor.getSubFuncId(); - mlir::StringAttr opNameAttr = op->getAttrOfType<mlir::StringAttr>("name"); - if (!opNameAttr) - return mlir::failure(); - if (opNameAttr.getValue() == "cpuid") - subFuncId = mlir::LLVM::ConstantOp::create(rewriter, op.getLoc(), i32Ty, 0); - std::vector operands{funcId, subFuncId}; + std::array<mlir::Value, 2> operands{funcId, subFuncId}; StringRef asmString, constraints; - mlir::ModuleOp moduleOp = op->getParentOfType<mlir::ModuleOp>(); - mlir::StringAttr tripleAttr = - moduleOp->getAttrOfType<mlir::StringAttr>("llvm.target_triple"); - if (!tripleAttr) - return mlir::failure(); - llvm::Triple triple(tripleAttr.getValue().str()); - if (triple.getArch() == llvm::Triple::x86) { + if (const llvm::Triple &triple = lowerMod->getTarget().getTriple(); + triple.getArch() == llvm::Triple::x86) { asmString = "cpuid"; constraints = "={ax},={bx},={cx},={dx},{ax},{cx}"; } else { @@ -4349,6 +4340,8 @@ mlir::LogicalResult CIRToLLVMCpuIdOpLowering::matchAndRewrite( mlir::LLVM::StoreOp::create(rewriter, op.getLoc(), extracted, storePtr, alignment); } + + rewriter.eraseOp(op); return mlir::success(); } >From a9f1a2a7a68f7a49c83fb4c00fa67db64358f713 Mon Sep 17 00:00:00 2001 From: rturrado <[email protected]> Date: Wed, 7 Jan 2026 23:08:06 +0100 Subject: [PATCH 3/6] Fix cpuid/cpuidex builtin implementation These builtins do not return anything, so the first parameter is the first operand. --- clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp index 16d8b36853a93..77454552df64d 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp @@ -1951,11 +1951,10 @@ CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID, const CallExpr *expr) { case X86::BI__cpuid: case X86::BI__cpuidex: { mlir::Location loc = getLoc(expr->getExprLoc()); - mlir::Type i32Ty = builder.getSInt32Ty(); mlir::Value subFuncId = builtinID == X86::BI__cpuidex ? ops[2] : builder.getConstInt(loc, sInt32Ty, 0); - cir::CpuIdOp::create(builder, loc, i32Ty, /*basePtr=*/ops[0], + cir::CpuIdOp::create(builder, loc, /*basePtr=*/ops[0], /*funcId=*/ops[1], /*subFuncId=*/subFuncId); return mlir::Value{}; } >From f30a508f6ad6e2130f326831a9a571b4dd96bb63 Mon Sep 17 00:00:00 2001 From: rturrado <[email protected]> Date: Wed, 7 Jan 2026 23:16:09 +0100 Subject: [PATCH 4/6] Change CIR_CpuIdOp to accept a pointer as first operand Arrays are usually decayed to pointers. By not restricting basePtr to be exactly a pointer to an array of 4 signed integers, we allow passing a pointer to signed integer. Extra verifications are already done at the verifier. --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 8 +++++--- clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 14 ++++++++------ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 3a4fe958e1804..75b4870819d6d 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -5914,16 +5914,18 @@ def CIR_CpuIdOp : CIR_Op<"cpuid"> { As a result, the array of 4 integers is filled with the requested information. + Note that, since arrays usually decay to pointers, `basePtr` is expected to be + just a pointer to integer. Extra verifications are done at the verifier. + Example: ```mlir - cir.cpuid %basePtr, %funcId, %subFuncId - : (!cir.ptr<!cir.array<4 x !s32i>>, !s32i, !s32i) + cir.cpuid %basePtr, %funcId, %subFuncId : (!cir.ptr<!s32i>, !s32i, !s32i) ``` }]; let arguments = - (ins Arg<CIR_PtrToArray, "array address", [MemWrite]>:$basePtr, + (ins Arg<CIR_PointerType, "array address", [MemWrite]>:$basePtr, CIR_SInt32:$funcId, CIR_SInt32:$subFuncId); let hasVerifier = 1; diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 6945176537c89..ccc43bd27a6bb 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -3574,13 +3574,15 @@ LogicalResult cir::CpuIdOp::verify() { if (!basePtrTy) return mlir::failure(); - auto arrayTy = mlir::dyn_cast<cir::ArrayType>(basePtrTy.getPointee()); - if (!arrayTy) - return mlir::failure(); - if (arrayTy.getSize() != 4) - return emitOpError() << "base pointer must point to an array of size 4"; + mlir::Type type = basePtrTy.getPointee(); + + // basePtr points to an array of size at least 4 + auto arrayTy = mlir::dyn_cast<cir::ArrayType>(type); + if (arrayTy && (arrayTy.getSize() < 4)) + return emitOpError() << "base pointer must point to an array of size at least 4"; - auto intTy = mlir::dyn_cast<cir::IntType>(arrayTy.getElementType()); + // Array decay: basePtr points to !s32i + auto intTy = mlir::dyn_cast<cir::IntType>(type); if (!intTy || !intTy.isSigned() || intTy.getWidth() != 32) return emitOpError() << "base pointer must point to an array of !s32i"; >From 62f2420501ce9999bd68d56c90446f1dd72adc0e Mon Sep 17 00:00:00 2001 From: rturrado <[email protected]> Date: Wed, 7 Jan 2026 23:30:24 +0100 Subject: [PATCH 5/6] Add cpuid-builtins.c test --- clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 3 +- .../CIR/CodeGenBuiltins/X86/cpuid-builtins.c | 31 +++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 clang/test/CIR/CodeGenBuiltins/X86/cpuid-builtins.c diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index ccc43bd27a6bb..7a514a4f18cd7 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -3579,7 +3579,8 @@ LogicalResult cir::CpuIdOp::verify() { // basePtr points to an array of size at least 4 auto arrayTy = mlir::dyn_cast<cir::ArrayType>(type); if (arrayTy && (arrayTy.getSize() < 4)) - return emitOpError() << "base pointer must point to an array of size at least 4"; + return emitOpError() + << "base pointer must point to an array of size at least 4"; // Array decay: basePtr points to !s32i auto intTy = mlir::dyn_cast<cir::IntType>(type); diff --git a/clang/test/CIR/CodeGenBuiltins/X86/cpuid-builtins.c b/clang/test/CIR/CodeGenBuiltins/X86/cpuid-builtins.c new file mode 100644 index 0000000000000..5012fe2331baa --- /dev/null +++ b/clang/test/CIR/CodeGenBuiltins/X86/cpuid-builtins.c @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux -fms-extensions -Wno-implicit-function-declaration -fclangir -emit-cir -o %t.cir -Wall -Werror %s +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s + +#pragma intrinsic(__cpuid) + +void test__cpuid_with_array_decayed_to_pointer(int cpuInfo[4], int function_id) { + __cpuid(cpuInfo, function_id); +} +// CIR-LABEL: __cpuid_with_array_decayed_to_pointer +// CIR: %[[CPUINFO_PTR:.*]] = cir.alloca !cir.ptr<!s32i> +// CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i +// CIR: {{.*}}cir.cpuid{{.*}}(%{{.*}}, %{{.*}}, %[[ZERO]]) : (!cir.ptr<!s32i>, !s32i, !s32i) + +void test__cpuid_with_array(int function_id) { + int cpuInfo[4]; + __cpuid(cpuInfo, function_id); +} +// CIR-LABEL: __cpuid_with_array +// CIR: %[[CPUINFO_PTR:.*]] = cir.alloca !cir.array<!s32i x 4> +// CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i +// CIR: {{.*}}cir.cpuid{{.*}}(%{{.*}}, %{{.*}}, %[[ZERO]]) : (!cir.ptr<!s32i>, !s32i, !s32i) + +#pragma intrinsic(__cpuidex) + +void test__cpuidex(int cpuInfo[4], int function_id, int subfunction_id) { + __cpuidex(cpuInfo, function_id, subfunction_id); +} +// CIR-LABEL: __cpuidex +// CIR: %[[SUBFUNCTION_ID_PTR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["subfunction_id" +// CIR: %[[SUBFUNCTION_ID:.*]] = cir.load {{.*}} %[[SUBFUNCTION_ID_PTR]] +// CIR: {{.*}}cir.cpuid{{.*}}(%{{.*}}, %{{.*}}, %[[SUBFUNCTION_ID]]) : (!cir.ptr<!s32i>, !s32i, !s32i) >From e9d570e948bf13aac494842cd6dded529ee732c1 Mon Sep 17 00:00:00 2001 From: rturrado <[email protected]> Date: Thu, 8 Jan 2026 19:48:26 +0100 Subject: [PATCH 6/6] Add LLVM and OGCG checks to cpuid-builtins.c test --- .../CIR/CodeGenBuiltins/X86/cpuid-builtins.c | 131 +++++++++++++++++- 1 file changed, 124 insertions(+), 7 deletions(-) diff --git a/clang/test/CIR/CodeGenBuiltins/X86/cpuid-builtins.c b/clang/test/CIR/CodeGenBuiltins/X86/cpuid-builtins.c index 5012fe2331baa..cb2fdb8a8c7b8 100644 --- a/clang/test/CIR/CodeGenBuiltins/X86/cpuid-builtins.c +++ b/clang/test/CIR/CodeGenBuiltins/X86/cpuid-builtins.c @@ -1,31 +1,148 @@ // RUN: %clang_cc1 -triple x86_64-unknown-linux -fms-extensions -Wno-implicit-function-declaration -fclangir -emit-cir -o %t.cir -Wall -Werror %s // RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux -fms-extensions -Wno-implicit-function-declaration -fclangir -emit-llvm -o %t-cir.ll -Wall -Werror %s +// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s + +// RUN: %clang_cc1 -triple x86_64-unknown-linux -fms-extensions -Wno-implicit-function-declaration -emit-llvm -o %t.ll -Wall -Werror %s +// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s + #pragma intrinsic(__cpuid) -void test__cpuid_with_array_decayed_to_pointer(int cpuInfo[4], int function_id) { - __cpuid(cpuInfo, function_id); +void test__cpuid_with_array_decayed_to_pointer(int cpuInfo[4], int functionId) { + __cpuid(cpuInfo, functionId); } // CIR-LABEL: __cpuid_with_array_decayed_to_pointer // CIR: %[[CPUINFO_PTR:.*]] = cir.alloca !cir.ptr<!s32i> // CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i // CIR: {{.*}}cir.cpuid{{.*}}(%{{.*}}, %{{.*}}, %[[ZERO]]) : (!cir.ptr<!s32i>, !s32i, !s32i) -void test__cpuid_with_array(int function_id) { +// LLVM-LABEL: __cpuid_with_array_decayed_to_pointer +// LLVM-DAG: [[STACK_PTR_TO_CPU_INFO_PTR:%.*]] = alloca ptr +// LLVM-DAG: [[STACK_PTR_TO_FUNCTION_ID:%.*]] = alloca i32 +// LLVM-DAG: [[CPU_INFO_PTR:%.*]] = load ptr, ptr [[STACK_PTR_TO_CPU_INFO_PTR]] +// LLVM-DAG: [[FUNCTION_ID:%.*]] = load i32, ptr [[STACK_PTR_TO_FUNCTION_ID]] +// LLVM-DAG: [[ASMRESULTS:%.*]] = call { i32, i32, i32, i32 } asm "{{.*}}cpuid{{.*}}", "={ax},=r,={cx},={dx},0,2"(i32 [[FUNCTION_ID]], i32 0) +// LLVM-DAG: [[RESULT0:%.*]] = extractvalue { i32, i32, i32, i32 } [[ASMRESULTS]], 0 +// LLVM-DAG: [[RESULT1:%.*]] = extractvalue { i32, i32, i32, i32 } [[ASMRESULTS]], 1 +// LLVM-DAG: [[RESULT2:%.*]] = extractvalue { i32, i32, i32, i32 } [[ASMRESULTS]], 2 +// LLVM-DAG: [[RESULT3:%.*]] = extractvalue { i32, i32, i32, i32 } [[ASMRESULTS]], 3 +// LLVM-DAG: [[ADDRPTR0:%.*]] = getelementptr i32, ptr [[CPU_INFO_PTR]], i64 0 +// LLVM-DAG: [[ADDRPTR1:%.*]] = getelementptr i32, ptr [[CPU_INFO_PTR]], i64 1 +// LLVM-DAG: [[ADDRPTR2:%.*]] = getelementptr i32, ptr [[CPU_INFO_PTR]], i64 2 +// LLVM-DAG: [[ADDRPTR3:%.*]] = getelementptr i32, ptr [[CPU_INFO_PTR]], i64 3 +// LLVM-DAG: store i32 [[RESULT0]], ptr [[ADDRPTR0]], align 4 +// LLVM-DAG: store i32 [[RESULT1]], ptr [[ADDRPTR1]], align 4 +// LLVM-DAG: store i32 [[RESULT2]], ptr [[ADDRPTR2]], align 4 +// LLVM-DAG: store i32 [[RESULT3]], ptr [[ADDRPTR3]], align 4 + +// OGCG-LABEL: __cpuid_with_array_decayed_to_pointer +// OGCG-DAG: [[STACK_PTR_TO_CPU_INFO_PTR:%.*]] = alloca ptr +// OGCG-DAG: [[STACK_PTR_TO_FUNCTION_ID:%.*]] = alloca i32 +// OGCG-DAG: [[ASMRESULTS:%.*]] = call { i32, i32, i32, i32 } asm "{{.*}}cpuid{{.*}}", "={ax},=r,={cx},={dx},0,2"(i32 %{{.*}}, i32 0) +// OGCG-DAG: [[RESULT0:%.*]] = extractvalue { i32, i32, i32, i32 } %{{.*}}, 0 +// OGCG-DAG: [[RESULT1:%.*]] = extractvalue { i32, i32, i32, i32 } %{{.*}}, 1 +// OGCG-DAG: [[RESULT2:%.*]] = extractvalue { i32, i32, i32, i32 } %{{.*}}, 2 +// OGCG-DAG: [[RESULT3:%.*]] = extractvalue { i32, i32, i32, i32 } %{{.*}}, 3 +// OGCG-DAG: [[ADDRPTR0:%.*]] = getelementptr inbounds i32, ptr %{{.*}}, i32 0 +// OGCG-DAG: [[ADDRPTR1:%.*]] = getelementptr inbounds i32, ptr %{{.*}}, i32 1 +// OGCG-DAG: [[ADDRPTR2:%.*]] = getelementptr inbounds i32, ptr %{{.*}}, i32 2 +// OGCG-DAG: [[ADDRPTR3:%.*]] = getelementptr inbounds i32, ptr %{{.*}}, i32 3 +// OGCG-DAG: store i32 [[RESULT0]], ptr [[ADDRPTR0]], align 4 +// OGCG-DAG: store i32 [[RESULT1]], ptr [[ADDRPTR1]], align 4 +// OGCG-DAG: store i32 [[RESULT2]], ptr [[ADDRPTR2]], align 4 +// OGCG-DAG: store i32 [[RESULT3]], ptr [[ADDRPTR3]], align 4 + +void test__cpuid_with_array(int functionId) { int cpuInfo[4]; - __cpuid(cpuInfo, function_id); + __cpuid(cpuInfo, functionId); } // CIR-LABEL: __cpuid_with_array // CIR: %[[CPUINFO_PTR:.*]] = cir.alloca !cir.array<!s32i x 4> // CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i // CIR: {{.*}}cir.cpuid{{.*}}(%{{.*}}, %{{.*}}, %[[ZERO]]) : (!cir.ptr<!s32i>, !s32i, !s32i) +// LLVM-LABEL: __cpuid_with_array +// LLVM-DAG: [[STACK_PTR_TO_CPU_INFO_PTR:%.*]] = alloca [4 x i32] +// LLVM-DAG: [[STACK_PTR_TO_FUNCTION_ID:%.*]] = alloca i32 +// LLVM-DAG: [[CPU_INFO_PTR:%.*]] = getelementptr i32, ptr [[STACK_PTR_TO_CPU_INFO_PTR]] +// LLVM-DAG: [[FUNCTION_ID:%.*]] = load i32, ptr [[STACK_PTR_TO_FUNCTION_ID]] +// LLVM-DAG: [[ASMRESULTS:%.*]] = call { i32, i32, i32, i32 } asm "{{.*}}cpuid{{.*}}", "={ax},=r,={cx},={dx},0,2"(i32 [[FUNCTION_ID]], i32 0) +// LLVM-DAG: [[RESULT0:%.*]] = extractvalue { i32, i32, i32, i32 } [[ASMRESULTS]], 0 +// LLVM-DAG: [[RESULT1:%.*]] = extractvalue { i32, i32, i32, i32 } [[ASMRESULTS]], 1 +// LLVM-DAG: [[RESULT2:%.*]] = extractvalue { i32, i32, i32, i32 } [[ASMRESULTS]], 2 +// LLVM-DAG: [[RESULT3:%.*]] = extractvalue { i32, i32, i32, i32 } [[ASMRESULTS]], 3 +// LLVM-DAG: [[ADDRPTR0:%.*]] = getelementptr i32, ptr [[CPU_INFO_PTR]], i64 0 +// LLVM-DAG: [[ADDRPTR1:%.*]] = getelementptr i32, ptr [[CPU_INFO_PTR]], i64 1 +// LLVM-DAG: [[ADDRPTR2:%.*]] = getelementptr i32, ptr [[CPU_INFO_PTR]], i64 2 +// LLVM-DAG: [[ADDRPTR3:%.*]] = getelementptr i32, ptr [[CPU_INFO_PTR]], i64 3 +// LLVM-DAG: store i32 [[RESULT0]], ptr [[ADDRPTR0]], align 4 +// LLVM-DAG: store i32 [[RESULT1]], ptr [[ADDRPTR1]], align 4 +// LLVM-DAG: store i32 [[RESULT2]], ptr [[ADDRPTR2]], align 4 +// LLVM-DAG: store i32 [[RESULT3]], ptr [[ADDRPTR3]], align 4 + +// OGCG-LABEL: __cpuid_with_array +// OGCG-DAG: [[STACK_PTR_TO_CPU_INFO_PTR:%.*]] = alloca [4 x i32] +// OGCG-DAG: [[STACK_PTR_TO_FUNCTION_ID:%.*]] = alloca i32 +// OGCG-DAG: [[ASMRESULTS:%.*]] = call { i32, i32, i32, i32 } asm "{{.*}}cpuid{{.*}}", "={ax},=r,={cx},={dx},0,2"(i32 %{{.*}}, i32 0) +// OGCG-DAG: [[RESULT0:%.*]] = extractvalue { i32, i32, i32, i32 } %{{.*}}, 0 +// OGCG-DAG: [[RESULT1:%.*]] = extractvalue { i32, i32, i32, i32 } %{{.*}}, 1 +// OGCG-DAG: [[RESULT2:%.*]] = extractvalue { i32, i32, i32, i32 } %{{.*}}, 2 +// OGCG-DAG: [[RESULT3:%.*]] = extractvalue { i32, i32, i32, i32 } %{{.*}}, 3 +// OGCG-DAG: [[ADDRPTR0:%.*]] = getelementptr inbounds i32, ptr %{{.*}}, i32 0 +// OGCG-DAG: [[ADDRPTR1:%.*]] = getelementptr inbounds i32, ptr %{{.*}}, i32 1 +// OGCG-DAG: [[ADDRPTR2:%.*]] = getelementptr inbounds i32, ptr %{{.*}}, i32 2 +// OGCG-DAG: [[ADDRPTR3:%.*]] = getelementptr inbounds i32, ptr %{{.*}}, i32 3 +// OGCG-DAG: store i32 [[RESULT0]], ptr [[ADDRPTR0]], align 4 +// OGCG-DAG: store i32 [[RESULT1]], ptr [[ADDRPTR1]], align 4 +// OGCG-DAG: store i32 [[RESULT2]], ptr [[ADDRPTR2]], align 4 +// OGCG-DAG: store i32 [[RESULT3]], ptr [[ADDRPTR3]], align 4 + #pragma intrinsic(__cpuidex) -void test__cpuidex(int cpuInfo[4], int function_id, int subfunction_id) { - __cpuidex(cpuInfo, function_id, subfunction_id); +void test__cpuidex(int cpuInfo[4], int functionId, int subfunctionId) { + __cpuidex(cpuInfo, functionId, subfunctionId); } // CIR-LABEL: __cpuidex -// CIR: %[[SUBFUNCTION_ID_PTR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["subfunction_id" +// CIR: %[[SUBFUNCTION_ID_PTR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["subfunctionId" // CIR: %[[SUBFUNCTION_ID:.*]] = cir.load {{.*}} %[[SUBFUNCTION_ID_PTR]] // CIR: {{.*}}cir.cpuid{{.*}}(%{{.*}}, %{{.*}}, %[[SUBFUNCTION_ID]]) : (!cir.ptr<!s32i>, !s32i, !s32i) + +// LLVM-LABEL: __cpuidex +// LLVM-DAG: [[STACK_PTR_TO_CPU_INFO_PTR:%.*]] = alloca ptr +// LLVM-DAG: [[STACK_PTR_TO_FUNCTION_ID:%.*]] = alloca i32 +// LLVM-DAG: [[STACK_PTR_TO_SUBFUNCTION_ID:%.*]] = alloca i32 +// LLVM-DAG: [[CPU_INFO_PTR:%.*]] = load ptr, ptr [[STACK_PTR_TO_CPU_INFO_PTR]] +// LLVM-DAG: [[FUNCTION_ID:%.*]] = load i32, ptr [[STACK_PTR_TO_FUNCTION_ID]] +// LLVM-DAG: [[SUBFUNCTION_ID:%.*]] = load i32, ptr [[STACK_PTR_TO_SUBFUNCTION_ID]] +// LLVM-DAG: [[ASMRESULTS:%.*]] = call { i32, i32, i32, i32 } asm "{{.*}}cpuid{{.*}}", "={ax},=r,={cx},={dx},0,2"(i32 [[FUNCTION_ID]], i32 [[SUBFUNCTION_ID]]) +// LLVM-DAG: [[RESULT0:%.*]] = extractvalue { i32, i32, i32, i32 } [[ASMRESULTS]], 0 +// LLVM-DAG: [[RESULT1:%.*]] = extractvalue { i32, i32, i32, i32 } [[ASMRESULTS]], 1 +// LLVM-DAG: [[RESULT2:%.*]] = extractvalue { i32, i32, i32, i32 } [[ASMRESULTS]], 2 +// LLVM-DAG: [[RESULT3:%.*]] = extractvalue { i32, i32, i32, i32 } [[ASMRESULTS]], 3 +// LLVM-DAG: [[ADDRPTR0:%.*]] = getelementptr i32, ptr [[CPU_INFO_PTR]], i64 0 +// LLVM-DAG: [[ADDRPTR1:%.*]] = getelementptr i32, ptr [[CPU_INFO_PTR]], i64 1 +// LLVM-DAG: [[ADDRPTR2:%.*]] = getelementptr i32, ptr [[CPU_INFO_PTR]], i64 2 +// LLVM-DAG: [[ADDRPTR3:%.*]] = getelementptr i32, ptr [[CPU_INFO_PTR]], i64 3 +// LLVM-DAG: store i32 [[RESULT0]], ptr [[ADDRPTR0]], align 4 +// LLVM-DAG: store i32 [[RESULT1]], ptr [[ADDRPTR1]], align 4 +// LLVM-DAG: store i32 [[RESULT2]], ptr [[ADDRPTR2]], align 4 +// LLVM-DAG: store i32 [[RESULT3]], ptr [[ADDRPTR3]], align 4 + +// OGCG-LABEL: __cpuidex +// OGCG-DAG: [[STACK_PTR_TO_CPU_INFO_PTR:%.*]] = alloca ptr +// OGCG-DAG: [[STACK_PTR_TO_FUNCTION_ID:%.*]] = alloca i32 +// OGCG-DAG: [[STACK_PTR_TO_SUBFUNCTION_ID:%.*]] = alloca i32 +// OGCG-DAG: [[ASMRESULTS:%.*]] = call { i32, i32, i32, i32 } asm "{{.*}}cpuid{{.*}}", "={ax},=r,={cx},={dx},0,2"(i32 %{{.*}}, i32 %{{.*}}) +// OGCG-DAG: [[RESULT0:%.*]] = extractvalue { i32, i32, i32, i32 } %{{.*}}, 0 +// OGCG-DAG: [[RESULT1:%.*]] = extractvalue { i32, i32, i32, i32 } %{{.*}}, 1 +// OGCG-DAG: [[RESULT2:%.*]] = extractvalue { i32, i32, i32, i32 } %{{.*}}, 2 +// OGCG-DAG: [[RESULT3:%.*]] = extractvalue { i32, i32, i32, i32 } %{{.*}}, 3 +// OGCG-DAG: [[ADDRPTR0:%.*]] = getelementptr inbounds i32, ptr %{{.*}}, i32 0 +// OGCG-DAG: [[ADDRPTR1:%.*]] = getelementptr inbounds i32, ptr %{{.*}}, i32 1 +// OGCG-DAG: [[ADDRPTR2:%.*]] = getelementptr inbounds i32, ptr %{{.*}}, i32 2 +// OGCG-DAG: [[ADDRPTR3:%.*]] = getelementptr inbounds i32, ptr %{{.*}}, i32 3 +// OGCG-DAG: store i32 [[RESULT0]], ptr [[ADDRPTR0]], align 4 +// OGCG-DAG: store i32 [[RESULT1]], ptr [[ADDRPTR1]], align 4 +// OGCG-DAG: store i32 [[RESULT2]], ptr [[ADDRPTR2]], align 4 +// OGCG-DAG: store i32 [[RESULT3]], ptr [[ADDRPTR3]], align 4 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
