llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Andy Kaylor (andykaylor) <details> <summary>Changes</summary> This change introduces lowering from CIR to LLVM IR of global integer variables, using defaults for attributes that aren't yet implemented. --- Full diff: https://github.com/llvm/llvm-project/pull/125260.diff 5 Files Affected: - (modified) clang/include/clang/CIR/LowerToLLVM.h (+21-1) - (modified) clang/lib/CIR/Lowering/DirectToLLVM/CMakeLists.txt (+7) - (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+128-2) - (added) clang/test/CIR/Lowering/global-var-simple.cpp (+63) - (modified) clang/test/CIR/Lowering/hello.c (+6-4) ``````````diff diff --git a/clang/include/clang/CIR/LowerToLLVM.h b/clang/include/clang/CIR/LowerToLLVM.h index afa1c1923ed516..1135dbcbe0354b 100644 --- a/clang/include/clang/CIR/LowerToLLVM.h +++ b/clang/include/clang/CIR/LowerToLLVM.h @@ -12,7 +12,9 @@ #ifndef CLANG_CIR_LOWERTOLLVM_H #define CLANG_CIR_LOWERTOLLVM_H -#include "mlir/Pass/Pass.h" +#include "mlir/Dialect/LLVMIR/LLVMDialect.h" +#include "mlir/Transforms/DialectConversion.h" +#include "clang/CIR/Dialect/IR/CIRDialect.h" #include <memory> @@ -31,6 +33,24 @@ namespace direct { std::unique_ptr<llvm::Module> lowerDirectlyFromCIRToLLVMIR(mlir::ModuleOp mlirModule, llvm::LLVMContext &llvmCtx); + +class CIRToLLVMGlobalOpLowering + : public mlir::OpConversionPattern<cir::GlobalOp> { + mlir::DataLayout const &dataLayout; + +public: + CIRToLLVMGlobalOpLowering(const mlir::TypeConverter &typeConverter, + mlir::MLIRContext *context, + mlir::DataLayout const &dataLayout) + : OpConversionPattern(typeConverter, context), dataLayout(dataLayout) { + setHasBoundedRewriteRecursion(); + } + + mlir::LogicalResult + matchAndRewrite(cir::GlobalOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const override; +}; + } // namespace direct } // namespace cir diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/CMakeLists.txt b/clang/lib/CIR/Lowering/DirectToLLVM/CMakeLists.txt index 0268234c3a2896..da802605676ac0 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/CMakeLists.txt +++ b/clang/lib/CIR/Lowering/DirectToLLVM/CMakeLists.txt @@ -3,6 +3,13 @@ set(LLVM_LINK_COMPONENTS Support ) +get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS) + add_clang_library(clangCIRLoweringDirectToLLVM LowerToLLVM.cpp + + LINK_LIBS + ${dialect_libs} + MLIRBuiltinToLLVMIRTranslation + MLIRLLVMToLLVMIRTranslation ) diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 63d2b51b428357..b24c41a93082d4 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -12,7 +12,19 @@ #include "clang/CIR/LowerToLLVM.h" +#include "mlir/Conversion/LLVMCommon/TypeConverter.h" +#include "mlir/Dialect/DLTI/DLTI.h" +#include "mlir/Dialect/Func/IR/FuncOps.h" +#include "mlir/Dialect/LLVMIR/LLVMDialect.h" +#include "mlir/IR/BuiltinDialect.h" #include "mlir/IR/BuiltinOps.h" +#include "mlir/Pass/Pass.h" +#include "mlir/Pass/PassManager.h" +#include "mlir/Target/LLVMIR/Dialect/Builtin/BuiltinToLLVMIRTranslation.h" +#include "mlir/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.h" +#include "mlir/Target/LLVMIR/Export.h" +#include "mlir/Transforms/DialectConversion.h" +#include "clang/CIR/Dialect/IR/CIRDialect.h" #include "llvm/IR/Module.h" #include "llvm/Support/TimeProfiler.h" @@ -22,13 +34,127 @@ using namespace llvm; namespace cir { namespace direct { +struct ConvertCIRToLLVMPass + : public mlir::PassWrapper<ConvertCIRToLLVMPass, + mlir::OperationPass<mlir::ModuleOp>> { + void getDependentDialects(mlir::DialectRegistry ®istry) const override { + registry.insert<mlir::BuiltinDialect, mlir::DLTIDialect, + mlir::LLVM::LLVMDialect, mlir::func::FuncDialect>(); + } + void runOnOperation() final; + + StringRef getDescription() const override { + return "Convert the prepared CIR dialect module to LLVM dialect"; + } + + StringRef getArgument() const override { return "cir-flat-to-llvm"; } +}; + +mlir::LogicalResult CIRToLLVMGlobalOpLowering::matchAndRewrite( + cir::GlobalOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + + // Fetch required values to create LLVM op. + const mlir::Type cirSymType = op.getSymType(); + + // This is the LLVM dialect type + const mlir::Type llvmType = getTypeConverter()->convertType(cirSymType); + // These defaults are just here until the equivalent attributes are + // available on cir.global ops. + const bool isConst = false; + const bool isDsoLocal = true; + const mlir::LLVM::Linkage linkage = mlir::LLVM::Linkage::External; + const StringRef symbol = op.getSymName(); + std::optional<mlir::Attribute> init = op.getInitialValue(); + + SmallVector<mlir::NamedAttribute> attributes; + + // Check for missing funcionalities. + if (!init.has_value()) { + rewriter.replaceOpWithNewOp<mlir::LLVM::GlobalOp>( + op, llvmType, isConst, linkage, symbol, mlir::Attribute(), + /*alignment*/ 0, /*addrSpace*/ 0, /*dsoLocal*/ isDsoLocal, + /*threadLocal*/ false, /*comdat*/ mlir::SymbolRefAttr(), attributes); + return mlir::success(); + } + + // Initializer is a constant array: convert it to a compatible llvm init. + if (auto intAttr = mlir::dyn_cast<cir::IntAttr>(init.value())) { + init = rewriter.getIntegerAttr(llvmType, intAttr.getValue()); + } else { + op.emitError() << "unsupported initializer '" << init.value() << "'"; + return mlir::failure(); + } + + // Rewrite op. + rewriter.replaceOpWithNewOp<mlir::LLVM::GlobalOp>( + op, llvmType, isConst, linkage, symbol, init.value(), /*alignment*/ 0, + /*addrSpace*/ 0, /*dsoLocal*/ isDsoLocal, /*threadLocal*/ false, + /*comdat*/ mlir::SymbolRefAttr(), attributes); + + return mlir::success(); +} + +static void prepareTypeConverter(mlir::LLVMTypeConverter &converter, + mlir::DataLayout &dataLayout) { + converter.addConversion([&](cir::IntType type) -> mlir::Type { + // LLVM doesn't work with signed types, so we drop the CIR signs here. + return mlir::IntegerType::get(type.getContext(), type.getWidth()); + }); +} + +void ConvertCIRToLLVMPass::runOnOperation() { + llvm::TimeTraceScope scope("Convert CIR to LLVM Pass"); + + mlir::ModuleOp module = getOperation(); + mlir::DataLayout dl(module); + mlir::LLVMTypeConverter converter(&getContext()); + prepareTypeConverter(converter, dl); // , lowerModule.get()); + + mlir::RewritePatternSet patterns(&getContext()); + + patterns.add<CIRToLLVMGlobalOpLowering>(converter, patterns.getContext(), dl); + + mlir::ConversionTarget target(getContext()); + target.addLegalOp<mlir::ModuleOp>(); + target.addLegalDialect<mlir::LLVM::LLVMDialect>(); + target.addIllegalDialect<mlir::BuiltinDialect, cir::CIRDialect, + mlir::func::FuncDialect>(); + + if (failed(applyPartialConversion(module, target, std::move(patterns)))) + signalPassFailure(); +} + +static std::unique_ptr<mlir::Pass> createConvertCIRToLLVMPass() { + return std::make_unique<ConvertCIRToLLVMPass>(); +} + +static void populateCIRToLLVMPasses(mlir::OpPassManager &pm) { + pm.addPass(createConvertCIRToLLVMPass()); +} + std::unique_ptr<llvm::Module> lowerDirectlyFromCIRToLLVMIR(mlir::ModuleOp mlirModule, LLVMContext &llvmCtx) { llvm::TimeTraceScope scope("lower from CIR to LLVM directly"); + mlir::MLIRContext *mlirCtx = mlirModule.getContext(); + + mlir::PassManager pm(mlirCtx); + populateCIRToLLVMPasses(pm); + + bool result = !mlir::failed(pm.run(mlirModule)); + if (!result) + report_fatal_error( + "The pass manager failed to lower CIR to LLVMIR dialect!"); + + mlir::registerBuiltinDialectTranslation(*mlirCtx); + mlir::registerLLVMDialectTranslation(*mlirCtx); + + llvm::TimeTraceScope translateScope("translateModuleToLLVMIR"); + std::optional<StringRef> moduleName = mlirModule.getName(); - auto llvmModule = std::make_unique<llvm::Module>( - moduleName ? *moduleName : "CIRToLLVMModule", llvmCtx); + std::unique_ptr<llvm::Module> llvmModule = mlir::translateModuleToLLVMIR( + mlirModule, llvmCtx, moduleName ? *moduleName : "CIRToLLVMModule"); if (!llvmModule) report_fatal_error("Lowering from LLVMIR dialect to llvm IR failed!"); diff --git a/clang/test/CIR/Lowering/global-var-simple.cpp b/clang/test/CIR/Lowering/global-var-simple.cpp new file mode 100644 index 00000000000000..e8d2138de3f58b --- /dev/null +++ b/clang/test/CIR/Lowering/global-var-simple.cpp @@ -0,0 +1,63 @@ +// Global variables of intergal types +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o - | FileCheck %s + +// Note: Currently unsupported features include default zero-initialization +// and alignment. The fact that "external" is only printed for globals +// without an initializer is a quirk of the LLVM AsmWriter. + +char c; +// CHECK: @c = external dso_local global i8 + +signed char sc; +// CHECK: @sc = external dso_local global i8 + +unsigned char uc; +// CHECK: @uc = external dso_local global i8 + +short ss; +// CHECK: @ss = external dso_local global i16 + +unsigned short us = 100; +// CHECK: @us = dso_local global i16 100 + +int si = 42; +// CHECK: @si = dso_local global i32 42 + +unsigned ui; +// CHECK: @ui = external dso_local global i32 + +long sl; +// CHECK: @sl = external dso_local global i64 + +unsigned long ul; +// CHECK: @ul = external dso_local global i64 + +long long sll; +// CHECK: @sll = external dso_local global i64 + +unsigned long long ull = 123456; +// CHECK: @ull = dso_local global i64 123456 + +__int128 s128; +// CHECK: @s128 = external dso_local global i128 + +unsigned __int128 u128; +// CHECK: @u128 = external dso_local global i128 + +wchar_t wc; +// CHECK: @wc = external dso_local global i32 + +char8_t c8; +// CHECK: @c8 = external dso_local global i8 + +char16_t c16; +// CHECK: @c16 = external dso_local global i16 + +char32_t c32; +// CHECK: @c32 = external dso_local global i32 + +_BitInt(20) sb20; +// CHECK: @sb20 = external dso_local global i20 + +unsigned _BitInt(48) ub48; +// CHECK: @ub48 = external dso_local global i48 diff --git a/clang/test/CIR/Lowering/hello.c b/clang/test/CIR/Lowering/hello.c index 320041f0ab7dc9..ff78b6e6f6a5e2 100644 --- a/clang/test/CIR/Lowering/hello.c +++ b/clang/test/CIR/Lowering/hello.c @@ -1,8 +1,10 @@ // Smoke test for ClangIR-to-LLVM IR code generation // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o - | FileCheck %s -// TODO: Add checks when proper lowering is implemented. -// For now, we're just creating an empty module. -// CHECK: ModuleID +int a; -void foo() {} +// CHECK: @a = external dso_local global i32 + +int b = 2; + +// CHECK: @b = dso_local global i32 2 `````````` </details> https://github.com/llvm/llvm-project/pull/125260 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits