[clang] [CIR] Lowering to LLVM for global pointers (PR #125619)
Andy Kaylor via cfe-commits
cfe-commits at lists.llvm.org
Tue Feb 4 17:21:11 PST 2025
https://github.com/andykaylor updated https://github.com/llvm/llvm-project/pull/125619
>From dc7f71d511d2e13e527e0c8cd242a3ece82bcdfd Mon Sep 17 00:00:00 2001
From: Andy Kaylor <akaylor at nvidia.com>
Date: Mon, 3 Feb 2025 13:20:51 -0800
Subject: [PATCH 1/2] [CIR] Lowering to LLVM for global pointers
Add support for lowering global variables of any pointer type to LLVM IR.
---
.../clang/CIR/Dialect/IR/CIRAttrVisitor.h | 51 +++++++++++
clang/include/clang/CIR/MissingFeatures.h | 3 +
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 84 +++++++++++++++++++
clang/test/CIR/Lowering/global-var-simple.cpp | 21 +++++
4 files changed, 159 insertions(+)
create mode 100644 clang/include/clang/CIR/Dialect/IR/CIRAttrVisitor.h
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 00000000000000..4babccc48038e6
--- /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 3c018aeea65014..d4fcd52e7e6e3b 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 af8ca7d0b89e68..66f6ee328e55e5 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 06050e409d5440..a5adb4011931af 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{{$}}
>From eee630f582711a38c96ec2d13a9bef426cb4aa88 Mon Sep 17 00:00:00 2001
From: Andy Kaylor <akaylor at nvidia.com>
Date: Tue, 4 Feb 2025 17:10:10 -0800
Subject: [PATCH 2/2] Refactoring based on review feedback
---
.../clang/CIR/Dialect/IR/CIRAttrVisitor.h | 37 ++--
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 167 ++++++++++++------
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.h | 10 ++
3 files changed, 132 insertions(+), 82 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrVisitor.h b/clang/include/clang/CIR/Dialect/IR/CIRAttrVisitor.h
index 4babccc48038e6..3f552c91742a04 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrVisitor.h
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrVisitor.h
@@ -8,42 +8,31 @@ 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) {
+ RetTy visit(mlir::Attribute attr) {
if (const auto intAttr = mlir::dyn_cast<cir::IntAttr>(attr))
- return static_cast<ImplClass *>(this)->visitCirIntAttr(
- intAttr, std::forward<Args>(args)...);
+ return getImpl().visitCirIntAttr(intAttr);
if (const auto fltAttr = mlir::dyn_cast<cir::FPAttr>(attr))
- return static_cast<ImplClass *>(this)->visitCirFPAttr(
- fltAttr, std::forward<Args>(args)...);
+ return getImpl().visitCirFPAttr(fltAttr);
if (const auto ptrAttr = mlir::dyn_cast<cir::ConstPtrAttr>(attr))
- return static_cast<ImplClass *>(this)->visitCirConstPtrAttr(
- ptrAttr, std::forward<Args>(args)...);
+ return getImpl().visitCirConstPtrAttr(ptrAttr);
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)...);
+ RetTy visitCirIntAttr(cir::IntAttr attr) {
+ return getImpl().visitCirAttr(attr);
}
- template <typename... Args>
- RetTy visitCirFPAttr(cir::FPAttr attr, Args &&...args) {
- return static_cast<ImplClass *>(this)->visitCirAttr(
- attr, std::forward<Args>(args)...);
+ RetTy visitCirFPAttr(cir::FPAttr attr) {
+ return getImpl().visitCirAttr(attr);
}
- template <typename... Args>
- RetTy visitCirConstPtrAttr(cir::ConstPtrAttr attr, Args &&...args) {
- return static_cast<ImplClass *>(this)->visitCirAttr(
- attr, std::forward<Args>(args)...);
+ RetTy visitCirConstPtrAttr(cir::ConstPtrAttr attr) {
+ return getImpl().visitCirAttr(attr);
}
- template <typename... Args>
- RetTy visitCirAttr(mlir::Attribute attr, Args &&...args) {
- return RetTy();
- }
+ RetTy visitCirAttr(mlir::Attribute attr) { return RetTy(); }
+
+ ImplClass &getImpl() { return *static_cast<ImplClass *>(this); }
};
} // namespace cir
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 66f6ee328e55e5..ed4501d1e5b1da 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -38,38 +38,27 @@ 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);
- }
+ CIRAttrToValue(mlir::Operation *parentOp,
+ mlir::ConversionPatternRewriter &rewriter,
+ const mlir::TypeConverter *converter)
+ : parentOp(parentOp), rewriter(rewriter), converter(converter) {}
+
+ mlir::Value lowerCirAttrAsValue(mlir::Attribute attr) { return visit(attr); }
- mlir::Value visitCirIntAttr(cir::IntAttr intAttr, mlir::Operation *parentOp,
- mlir::ConversionPatternRewriter &rewriter,
- const mlir::TypeConverter *converter,
- mlir::DataLayout const &dataLayout) {
- auto loc = parentOp->getLoc();
+ mlir::Value visitCirIntAttr(cir::IntAttr intAttr) {
+ mlir::Location 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();
+ mlir::Value visitCirFPAttr(cir::FPAttr fltAttr) {
+ mlir::Location 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();
+ mlir::Value visitCirConstPtrAttr(cir::ConstPtrAttr ptrAttr) {
+ mlir::Location loc = parentOp->getLoc();
if (ptrAttr.isNullValue()) {
return rewriter.create<mlir::LLVM::ZeroOp>(
loc, converter->convertType(ptrAttr.getType()));
@@ -82,6 +71,34 @@ class CIRAttrToValue : public CirAttrVisitor<CIRAttrToValue, mlir::Value> {
return rewriter.create<mlir::LLVM::IntToPtrOp>(
loc, converter->convertType(ptrAttr.getType()), ptrVal);
}
+
+private:
+ mlir::Operation *parentOp;
+ mlir::ConversionPatternRewriter &rewriter;
+ const mlir::TypeConverter *converter;
+};
+
+// This class handles rewriting initializer attributes for types that do not
+// require region initialization.
+class GlobalInitAttrRewriter
+ : public CirAttrVisitor<GlobalInitAttrRewriter, mlir::Attribute> {
+public:
+ GlobalInitAttrRewriter(mlir::Type type,
+ mlir::ConversionPatternRewriter &rewriter)
+ : llvmType(type), rewriter(rewriter) {}
+
+ mlir::Attribute rewriteInitAttr(mlir::Attribute attr) { return visit(attr); }
+
+ mlir::Attribute visitCirIntAttr(cir::IntAttr attr) {
+ return rewriter.getIntegerAttr(llvmType, attr.getValue());
+ }
+ mlir::Attribute visitCirFPAttr(cir::FPAttr attr) {
+ return rewriter.getFloatAttr(llvmType, attr.getValue());
+ }
+
+private:
+ mlir::Type llvmType;
+ mlir::ConversionPatternRewriter &rewriter;
};
// This pass requires the CIR to be in a "flat" state. All blocks in each
@@ -104,16 +121,78 @@ struct ConvertCIRToLLVMPass
StringRef getArgument() const override { return "cir-flat-to-llvm"; }
};
+bool CIRToLLVMGlobalOpLowering::attrRequiresRegionInitialization(
+ mlir::Attribute attr) const {
+ // There will be more case added later.
+ return isa<cir::ConstPtrAttr>(attr);
+}
+
/// Replace CIR global with a region initialized LLVM global and update
/// insertion point to the end of the initializer block.
+void CIRToLLVMGlobalOpLowering::setupRegionInitializedLLVMGlobalOp(
+ cir::GlobalOp op, mlir::ConversionPatternRewriter &rewriter) const {
+ assert(!cir::MissingFeatures::convertTypeForMemory());
+ const mlir::Type llvmType = getTypeConverter()->convertType(op.getSymType());
+
+ // FIXME: These default values are placeholders until the the equivalent
+ // attributes are available on cir.global ops. This duplicates code
+ // in CIRToLLVMGlobalOpLowering::matchAndRewrite() but that will go
+ // away when the placeholders are no longer needed.
+ assert(!cir::MissingFeatures::opGlobalConstant());
+ const bool isConst = false;
+ assert(!cir::MissingFeatures::addressSpace());
+ const unsigned addrSpace = 0;
+ assert(!cir::MissingFeatures::opGlobalDSOLocal());
+ const bool isDsoLocal = true;
+ assert(!cir::MissingFeatures::opGlobalThreadLocal());
+ const bool isThreadLocal = false;
+ assert(!cir::MissingFeatures::opGlobalAlignment());
+ const uint64_t alignment = 0;
+ assert(!cir::MissingFeatures::opGlobalLinkage());
+ const mlir::LLVM::Linkage linkage = mlir::LLVM::Linkage::External;
+ const StringRef symbol = op.getSymName();
+
+ SmallVector<mlir::NamedAttribute> attributes;
+ auto newGlobalOp = rewriter.replaceOpWithNewOp<mlir::LLVM::GlobalOp>(
+ op, llvmType, isConst, linkage, symbol, nullptr, alignment, addrSpace,
+ isDsoLocal, isThreadLocal,
+ /*comdat=*/mlir::SymbolRefAttr(), attributes);
+ newGlobalOp.getRegion().push_back(new mlir::Block());
+ rewriter.setInsertionPointToEnd(newGlobalOp.getInitializerBlock());
+};
+
+mlir::LogicalResult
+CIRToLLVMGlobalOpLowering::matchAndRewriteRegionInitializedGlobal(
+ cir::GlobalOp op, mlir::Attribute init,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ // TODO: Generalize this handling when more types are needed here.
+ assert(isa<cir::ConstPtrAttr>(init));
+
+ // 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.
+ const mlir::Location loc = op.getLoc();
+ setupRegionInitializedLLVMGlobalOp(op, rewriter);
+ CIRAttrToValue attrVisitor(op, rewriter, typeConverter);
+ mlir::Value value = attrVisitor.lowerCirAttrAsValue(init);
+ rewriter.create<mlir::LLVM::ReturnOp>(loc, value);
+ return mlir::success();
+}
mlir::LogicalResult CIRToLLVMGlobalOpLowering::matchAndRewrite(
cir::GlobalOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
+ std::optional<mlir::Attribute> init = op.getInitialValue();
+
+ // If we have an initializer and it requires region initialization, handle
+ // that separately
+ if (init.has_value() && attrRequiresRegionInitialization(init.value())) {
+ return matchAndRewriteRegionInitializedGlobal(op, init.value(), rewriter);
+ }
+
// 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());
@@ -133,43 +212,15 @@ mlir::LogicalResult CIRToLLVMGlobalOpLowering::matchAndRewrite(
assert(!cir::MissingFeatures::opGlobalLinkage());
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;
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.
- init = rewriter.getFloatAttr(llvmType, fltAttr.getValue());
- } else if (const auto intAttr =
- 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 {
+ GlobalInitAttrRewriter initRewriter(llvmType, rewriter);
+ init = initRewriter.rewriteInitAttr(init.value());
+ // If initRewriter returned a null attribute, init will have a value but
+ // the value will be null. If that happens, initRewriter didn't handle the
+ // attribute type. It probably needs to be added to GlobalInitAttrRewriter.
+ if (!init.value()) {
op.emitError() << "unsupported initializer '" << init.value() << "'";
return mlir::failure();
}
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
index 6167ff39b5ad6a..b3366c1fb93378 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
@@ -34,6 +34,16 @@ class CIRToLLVMGlobalOpLowering
mlir::LogicalResult
matchAndRewrite(cir::GlobalOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const override;
+
+private:
+ bool attrRequiresRegionInitialization(mlir::Attribute attr) const;
+
+ mlir::LogicalResult matchAndRewriteRegionInitializedGlobal(
+ cir::GlobalOp op, mlir::Attribute init,
+ mlir::ConversionPatternRewriter &rewriter) const;
+
+ void setupRegionInitializedLLVMGlobalOp(
+ cir::GlobalOp op, mlir::ConversionPatternRewriter &rewriter) const;
};
} // namespace direct
More information about the cfe-commits
mailing list