- Notifications
You must be signed in to change notification settings - Fork 15.6k
[CIR][X86] Add support for cpuid/cpuidex #173197
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
| @llvm/pr-subscribers-clang Author: Roberto Turrado Camblor (rturrado) ChangesAdds support for the Part of 167765. Full diff: https://github.com/llvm/llvm-project/pull/173197.diff 3 Files Affected:
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 7e7424fd71878..c1292ac6ce241 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -5762,4 +5762,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 1c87e945de846..c58391ecc5b42 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> @@ -1835,7 +1836,15 @@ CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID, const CallExpr *expr) { case X86::BI__builtin_ia32_cvtneps2bf16_256_mask: case X86::BI__builtin_ia32_cvtneps2bf16_512_mask: case X86::BI__cpuid: - case X86::BI__cpuidex: + case X86::BI__cpuidex: { + 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 eb0a219f18618..24924085ea9ea 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -4193,6 +4193,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>(); } |
| @llvm/pr-subscribers-clangir Author: Roberto Turrado Camblor (rturrado) ChangesAdds support for the Part of 167765. Full diff: https://github.com/llvm/llvm-project/pull/173197.diff 3 Files Affected:
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 7e7424fd71878..c1292ac6ce241 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -5762,4 +5762,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 1c87e945de846..c58391ecc5b42 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> @@ -1835,7 +1836,15 @@ CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID, const CallExpr *expr) { case X86::BI__builtin_ia32_cvtneps2bf16_256_mask: case X86::BI__builtin_ia32_cvtneps2bf16_512_mask: case X86::BI__cpuid: - case X86::BI__cpuidex: + case X86::BI__cpuidex: { + 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 eb0a219f18618..24924085ea9ea 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -4193,6 +4193,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>(); } |
| I haven't added any tests yet. I have seen there are currently 2 types of tests for
Thanks! |
1bd67a4 to 111be7a Compare 🐧 Linux x64 Test Results
✅ The build succeeded and all tests passed. |
980272e to ebcbcc3 Compare ebcbcc3 to 412f88f Compare
Adds support for the
__builtin_ia32_cpuidand__builtin_ia32_cpuidexX86 builtins.Part of 167765.