llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Andy Kaylor (andykaylor) <details> <summary>Changes</summary> Add support for lowering global variables of any pointer type to LLVM IR. --- Full diff: https://github.com/llvm/llvm-project/pull/125619.diff 4 Files Affected: - (added) clang/include/clang/CIR/Dialect/IR/CIRAttrVisitor.h (+51) - (modified) clang/include/clang/CIR/MissingFeatures.h (+3) - (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+84) - (modified) clang/test/CIR/Lowering/global-var-simple.cpp (+21) ``````````diff diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrVisitor.h b/clang/include/clang/CIR/Dialect/IR/CIRAttrVisitor.h new file mode 100644 index 000000000000000..4babccc48038e61 --- /dev/null +++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrVisitor.h @@ -0,0 +1,51 @@ +#ifndef LLVM_CLANG_CIR_DIALECT_IR_CIRATTRVISITOR_H +#define LLVM_CLANG_CIR_DIALECT_IR_CIRATTRVISITOR_H + +#include "clang/CIR/Dialect/IR/CIRAttrs.h" + +namespace cir { + +template <typename ImplClass, typename RetTy> class CirAttrVisitor { +public: + // FIXME: Create a TableGen list to automatically handle new attributes + template <typename... Args> + RetTy visit(mlir::Attribute attr, Args &&...args) { + if (const auto intAttr = mlir::dyn_cast<cir::IntAttr>(attr)) + return static_cast<ImplClass *>(this)->visitCirIntAttr( + intAttr, std::forward<Args>(args)...); + if (const auto fltAttr = mlir::dyn_cast<cir::FPAttr>(attr)) + return static_cast<ImplClass *>(this)->visitCirFPAttr( + fltAttr, std::forward<Args>(args)...); + if (const auto ptrAttr = mlir::dyn_cast<cir::ConstPtrAttr>(attr)) + return static_cast<ImplClass *>(this)->visitCirConstPtrAttr( + ptrAttr, std::forward<Args>(args)...); + llvm_unreachable("unhandled attribute type"); + } + + // If the implementation chooses not to implement a certain visit + // method, fall back to the parent. + template <typename... Args> + RetTy visitCirIntAttr(cir::IntAttr attr, Args &&...args) { + return static_cast<ImplClass *>(this)->visitCirAttr( + attr, std::forward<Args>(args)...); + } + template <typename... Args> + RetTy visitCirFPAttr(cir::FPAttr attr, Args &&...args) { + return static_cast<ImplClass *>(this)->visitCirAttr( + attr, std::forward<Args>(args)...); + } + template <typename... Args> + RetTy visitCirConstPtrAttr(cir::ConstPtrAttr attr, Args &&...args) { + return static_cast<ImplClass *>(this)->visitCirAttr( + attr, std::forward<Args>(args)...); + } + + template <typename... Args> + RetTy visitCirAttr(mlir::Attribute attr, Args &&...args) { + return RetTy(); + } +}; + +} // namespace cir + +#endif // LLVM_CLANG_CIR_DIALECT_IR_CIRATTRVISITOR_H diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index 3c018aeea650142..d4fcd52e7e6e3bc 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -27,6 +27,9 @@ struct MissingFeatures { // Address space related static bool addressSpace() { return false; } + // This isn't needed until we add support for bools. + static bool convertTypeForMemory() { return false; } + // Unhandled global/linkage information. static bool opGlobalDSOLocal() { return false; } static bool opGlobalThreadLocal() { return false; } diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index af8ca7d0b89e681..66f6ee328e55e5d 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -24,6 +24,7 @@ #include "mlir/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.h" #include "mlir/Target/LLVMIR/Export.h" #include "mlir/Transforms/DialectConversion.h" +#include "clang/CIR/Dialect/IR/CIRAttrVisitor.h" #include "clang/CIR/Dialect/IR/CIRDialect.h" #include "clang/CIR/MissingFeatures.h" #include "llvm/IR/Module.h" @@ -35,6 +36,54 @@ using namespace llvm; namespace cir { namespace direct { +class CIRAttrToValue : public CirAttrVisitor<CIRAttrToValue, mlir::Value> { +public: + mlir::Value lowerCirAttrAsValue(mlir::Operation *parentOp, + mlir::Attribute attr, + mlir::ConversionPatternRewriter &rewriter, + const mlir::TypeConverter *converter, + mlir::DataLayout const &dataLayout) { + return visit(attr, parentOp, rewriter, converter, dataLayout); + } + + mlir::Value visitCirIntAttr(cir::IntAttr intAttr, mlir::Operation *parentOp, + mlir::ConversionPatternRewriter &rewriter, + const mlir::TypeConverter *converter, + mlir::DataLayout const &dataLayout) { + auto loc = parentOp->getLoc(); + return rewriter.create<mlir::LLVM::ConstantOp>( + loc, converter->convertType(intAttr.getType()), intAttr.getValue()); + } + + mlir::Value visitCirFPAttr(cir::FPAttr fltAttr, mlir::Operation *parentOp, + mlir::ConversionPatternRewriter &rewriter, + const mlir::TypeConverter *converter, + mlir::DataLayout const &dataLayout) { + auto loc = parentOp->getLoc(); + return rewriter.create<mlir::LLVM::ConstantOp>( + loc, converter->convertType(fltAttr.getType()), fltAttr.getValue()); + } + + mlir::Value visitCirConstPtrAttr(cir::ConstPtrAttr ptrAttr, + mlir::Operation *parentOp, + mlir::ConversionPatternRewriter &rewriter, + const mlir::TypeConverter *converter, + mlir::DataLayout const &dataLayout) { + auto loc = parentOp->getLoc(); + if (ptrAttr.isNullValue()) { + return rewriter.create<mlir::LLVM::ZeroOp>( + loc, converter->convertType(ptrAttr.getType())); + } + mlir::DataLayout layout(parentOp->getParentOfType<mlir::ModuleOp>()); + mlir::Value ptrVal = rewriter.create<mlir::LLVM::ConstantOp>( + loc, + rewriter.getIntegerType(layout.getTypeSizeInBits(ptrAttr.getType())), + ptrAttr.getValue().getInt()); + return rewriter.create<mlir::LLVM::IntToPtrOp>( + loc, converter->convertType(ptrAttr.getType()), ptrVal); + } +}; + // This pass requires the CIR to be in a "flat" state. All blocks in each // function must belong to the parent region. Once scopes and control flow // are implemented in CIR, a pass will be run before this one to flatten @@ -55,14 +104,19 @@ struct ConvertCIRToLLVMPass StringRef getArgument() const override { return "cir-flat-to-llvm"; } }; +/// Replace CIR global with a region initialized LLVM global and update +/// insertion point to the end of the initializer block. + 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(); + const auto loc = op.getLoc(); // This is the LLVM dialect type. + assert(!cir::MissingFeatures::convertTypeForMemory()); const mlir::Type llvmType = getTypeConverter()->convertType(cirSymType); // FIXME: These default values are placeholders until the the equivalent // attributes are available on cir.global ops. @@ -84,6 +138,19 @@ mlir::LogicalResult CIRToLLVMGlobalOpLowering::matchAndRewrite( SmallVector<mlir::NamedAttribute> attributes; if (init.has_value()) { + auto setupRegionInitializedLLVMGlobalOp = [&]() { + assert(!cir::MissingFeatures::convertTypeForMemory()); + const mlir::Type llvmType = + getTypeConverter()->convertType(op.getSymType()); + SmallVector<mlir::NamedAttribute> attributes; + auto newGlobalOp = rewriter.replaceOpWithNewOp<mlir::LLVM::GlobalOp>( + op, llvmType, isConst, linkage, op.getSymName(), nullptr, alignment, + addrSpace, isDsoLocal, isThreadLocal, + /*comdat=*/mlir::SymbolRefAttr(), attributes); + newGlobalOp.getRegion().push_back(new mlir::Block()); + rewriter.setInsertionPointToEnd(newGlobalOp.getInitializerBlock()); + }; + if (const auto fltAttr = mlir::dyn_cast<cir::FPAttr>(init.value())) { // Initializer is a constant floating-point number: convert to MLIR // builtin constant. @@ -92,6 +159,16 @@ mlir::LogicalResult CIRToLLVMGlobalOpLowering::matchAndRewrite( mlir::dyn_cast<cir::IntAttr>(init.value())) { // Initializer is a constant array: convert it to a compatible llvm init. init = rewriter.getIntegerAttr(llvmType, intAttr.getValue()); + } else if (isa<cir::ConstPtrAttr>(init.value())) { + // TODO(cir): once LLVM's dialect has proper equivalent attributes this + // should be updated. For now, we use a custom op to initialize globals + // to the appropriate value. + setupRegionInitializedLLVMGlobalOp(); + CIRAttrToValue attrVisitor; + mlir::Value value = attrVisitor.lowerCirAttrAsValue( + op, init.value(), rewriter, typeConverter, dataLayout); + rewriter.create<mlir::LLVM::ReturnOp>(loc, value); + return mlir::success(); } else { op.emitError() << "unsupported initializer '" << init.value() << "'"; return mlir::failure(); @@ -109,6 +186,13 @@ mlir::LogicalResult CIRToLLVMGlobalOpLowering::matchAndRewrite( static void prepareTypeConverter(mlir::LLVMTypeConverter &converter, mlir::DataLayout &dataLayout) { + converter.addConversion([&](cir::PointerType type) -> mlir::Type { + // Drop pointee type since LLVM dialect only allows opaque pointers. + assert(!cir::MissingFeatures::addressSpace()); + unsigned targetAS = 0; + + return mlir::LLVM::LLVMPointerType::get(type.getContext(), targetAS); + }); 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()); diff --git a/clang/test/CIR/Lowering/global-var-simple.cpp b/clang/test/CIR/Lowering/global-var-simple.cpp index 06050e409d54401..a5adb4011931afe 100644 --- a/clang/test/CIR/Lowering/global-var-simple.cpp +++ b/clang/test/CIR/Lowering/global-var-simple.cpp @@ -79,3 +79,24 @@ long double ld; __float128 f128; // CHECK: @f128 = external dso_local global fp128 + +void *vp; +// CHECK: @vp = external dso_local global ptr{{$}} + +int *ip = 0; +// CHECK: @ip = dso_local global ptr null + +double *dp; +// CHECK: @dp = external dso_local global ptr{{$}} + +char **cpp; +// CHECK: @cpp = external dso_local global ptr{{$}} + +void (*fp)(); +// CHECK: @fp = external dso_local global ptr{{$}} + +int (*fpii)(int) = 0; +// CHECK: @fpii = dso_local global ptr null + +void (*fpvar)(int, ...); +// CHECK: @fpvar = external dso_local global ptr{{$}} `````````` </details> https://github.com/llvm/llvm-project/pull/125619 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits