2424#include " mlir/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.h"
2525#include " mlir/Target/LLVMIR/Export.h"
2626#include " mlir/Transforms/DialectConversion.h"
27+ #include " clang/CIR/Dialect/IR/CIRAttrVisitor.h"
2728#include " clang/CIR/Dialect/IR/CIRDialect.h"
2829#include " clang/CIR/MissingFeatures.h"
2930#include " llvm/IR/Module.h"
@@ -35,6 +36,71 @@ using namespace llvm;
3536namespace cir {
3637namespace direct {
3738
39+ class CIRAttrToValue : public CirAttrVisitor <CIRAttrToValue, mlir::Value> {
40+ public:
41+ CIRAttrToValue (mlir::Operation *parentOp,
42+ mlir::ConversionPatternRewriter &rewriter,
43+ const mlir::TypeConverter *converter)
44+ : parentOp(parentOp), rewriter(rewriter), converter(converter) {}
45+
46+ mlir::Value lowerCirAttrAsValue (mlir::Attribute attr) { return visit (attr); }
47+
48+ mlir::Value visitCirIntAttr (cir::IntAttr intAttr) {
49+ mlir::Location loc = parentOp->getLoc ();
50+ return rewriter.create <mlir::LLVM::ConstantOp>(
51+ loc, converter->convertType (intAttr.getType ()), intAttr.getValue ());
52+ }
53+
54+ mlir::Value visitCirFPAttr (cir::FPAttr fltAttr) {
55+ mlir::Location loc = parentOp->getLoc ();
56+ return rewriter.create <mlir::LLVM::ConstantOp>(
57+ loc, converter->convertType (fltAttr.getType ()), fltAttr.getValue ());
58+ }
59+
60+ mlir::Value visitCirConstPtrAttr (cir::ConstPtrAttr ptrAttr) {
61+ mlir::Location loc = parentOp->getLoc ();
62+ if (ptrAttr.isNullValue ()) {
63+ return rewriter.create <mlir::LLVM::ZeroOp>(
64+ loc, converter->convertType (ptrAttr.getType ()));
65+ }
66+ mlir::DataLayout layout (parentOp->getParentOfType <mlir::ModuleOp>());
67+ mlir::Value ptrVal = rewriter.create <mlir::LLVM::ConstantOp>(
68+ loc,
69+ rewriter.getIntegerType (layout.getTypeSizeInBits (ptrAttr.getType ())),
70+ ptrAttr.getValue ().getInt ());
71+ return rewriter.create <mlir::LLVM::IntToPtrOp>(
72+ loc, converter->convertType (ptrAttr.getType ()), ptrVal);
73+ }
74+
75+ private:
76+ mlir::Operation *parentOp;
77+ mlir::ConversionPatternRewriter &rewriter;
78+ const mlir::TypeConverter *converter;
79+ };
80+
81+ // This class handles rewriting initializer attributes for types that do not
82+ // require region initialization.
83+ class GlobalInitAttrRewriter
84+ : public CirAttrVisitor<GlobalInitAttrRewriter, mlir::Attribute> {
85+ public:
86+ GlobalInitAttrRewriter (mlir::Type type,
87+ mlir::ConversionPatternRewriter &rewriter)
88+ : llvmType(type), rewriter(rewriter) {}
89+
90+ mlir::Attribute rewriteInitAttr (mlir::Attribute attr) { return visit (attr); }
91+
92+ mlir::Attribute visitCirIntAttr (cir::IntAttr attr) {
93+ return rewriter.getIntegerAttr (llvmType, attr.getValue ());
94+ }
95+ mlir::Attribute visitCirFPAttr (cir::FPAttr attr) {
96+ return rewriter.getFloatAttr (llvmType, attr.getValue ());
97+ }
98+
99+ private:
100+ mlir::Type llvmType;
101+ mlir::ConversionPatternRewriter &rewriter;
102+ };
103+
38104// This pass requires the CIR to be in a "flat" state. All blocks in each
39105// function must belong to the parent region. Once scopes and control flow
40106// are implemented in CIR, a pass will be run before this one to flatten
@@ -55,14 +121,81 @@ struct ConvertCIRToLLVMPass
55121 StringRef getArgument () const override { return " cir-flat-to-llvm" ; }
56122};
57123
124+ bool CIRToLLVMGlobalOpLowering::attrRequiresRegionInitialization (
125+ mlir::Attribute attr) const {
126+ // There will be more cases added later.
127+ return isa<cir::ConstPtrAttr>(attr);
128+ }
129+
130+ // / Replace CIR global with a region initialized LLVM global and update
131+ // / insertion point to the end of the initializer block.
132+ void CIRToLLVMGlobalOpLowering::setupRegionInitializedLLVMGlobalOp (
133+ cir::GlobalOp op, mlir::ConversionPatternRewriter &rewriter) const {
134+ assert (!cir::MissingFeatures::convertTypeForMemory ());
135+ const mlir::Type llvmType = getTypeConverter ()->convertType (op.getSymType ());
136+
137+ // FIXME: These default values are placeholders until the the equivalent
138+ // attributes are available on cir.global ops. This duplicates code
139+ // in CIRToLLVMGlobalOpLowering::matchAndRewrite() but that will go
140+ // away when the placeholders are no longer needed.
141+ assert (!cir::MissingFeatures::opGlobalConstant ());
142+ const bool isConst = false ;
143+ assert (!cir::MissingFeatures::addressSpace ());
144+ const unsigned addrSpace = 0 ;
145+ assert (!cir::MissingFeatures::opGlobalDSOLocal ());
146+ const bool isDsoLocal = true ;
147+ assert (!cir::MissingFeatures::opGlobalThreadLocal ());
148+ const bool isThreadLocal = false ;
149+ assert (!cir::MissingFeatures::opGlobalAlignment ());
150+ const uint64_t alignment = 0 ;
151+ assert (!cir::MissingFeatures::opGlobalLinkage ());
152+ const mlir::LLVM::Linkage linkage = mlir::LLVM::Linkage::External;
153+ const StringRef symbol = op.getSymName ();
154+
155+ SmallVector<mlir::NamedAttribute> attributes;
156+ auto newGlobalOp = rewriter.replaceOpWithNewOp <mlir::LLVM::GlobalOp>(
157+ op, llvmType, isConst, linkage, symbol, nullptr , alignment, addrSpace,
158+ isDsoLocal, isThreadLocal,
159+ /* comdat=*/ mlir::SymbolRefAttr (), attributes);
160+ newGlobalOp.getRegion ().push_back (new mlir::Block ());
161+ rewriter.setInsertionPointToEnd (newGlobalOp.getInitializerBlock ());
162+ };
163+
164+ mlir::LogicalResult
165+ CIRToLLVMGlobalOpLowering::matchAndRewriteRegionInitializedGlobal (
166+ cir::GlobalOp op, mlir::Attribute init,
167+ mlir::ConversionPatternRewriter &rewriter) const {
168+ // TODO: Generalize this handling when more types are needed here.
169+ assert (isa<cir::ConstPtrAttr>(init));
170+
171+ // TODO(cir): once LLVM's dialect has proper equivalent attributes this
172+ // should be updated. For now, we use a custom op to initialize globals
173+ // to the appropriate value.
174+ const mlir::Location loc = op.getLoc ();
175+ setupRegionInitializedLLVMGlobalOp (op, rewriter);
176+ CIRAttrToValue attrVisitor (op, rewriter, typeConverter);
177+ mlir::Value value = attrVisitor.lowerCirAttrAsValue (init);
178+ rewriter.create <mlir::LLVM::ReturnOp>(loc, value);
179+ return mlir::success ();
180+ }
181+
58182mlir::LogicalResult CIRToLLVMGlobalOpLowering::matchAndRewrite (
59183 cir::GlobalOp op, OpAdaptor adaptor,
60184 mlir::ConversionPatternRewriter &rewriter) const {
61185
186+ std::optional<mlir::Attribute> init = op.getInitialValue ();
187+
188+ // If we have an initializer and it requires region initialization, handle
189+ // that separately
190+ if (init.has_value () && attrRequiresRegionInitialization (init.value ())) {
191+ return matchAndRewriteRegionInitializedGlobal (op, init.value (), rewriter);
192+ }
193+
62194 // Fetch required values to create LLVM op.
63195 const mlir::Type cirSymType = op.getSymType ();
64196
65197 // This is the LLVM dialect type.
198+ assert (!cir::MissingFeatures::convertTypeForMemory ());
66199 const mlir::Type llvmType = getTypeConverter ()->convertType (cirSymType);
67200 // FIXME: These default values are placeholders until the the equivalent
68201 // attributes are available on cir.global ops.
@@ -79,20 +212,15 @@ mlir::LogicalResult CIRToLLVMGlobalOpLowering::matchAndRewrite(
79212 assert (!cir::MissingFeatures::opGlobalLinkage ());
80213 const mlir::LLVM::Linkage linkage = mlir::LLVM::Linkage::External;
81214 const StringRef symbol = op.getSymName ();
82- std::optional<mlir::Attribute> init = op.getInitialValue ();
83-
84215 SmallVector<mlir::NamedAttribute> attributes;
85216
86217 if (init.has_value ()) {
87- if (const auto fltAttr = mlir::dyn_cast<cir::FPAttr>(init.value ())) {
88- // Initializer is a constant floating-point number: convert to MLIR
89- // builtin constant.
90- init = rewriter.getFloatAttr (llvmType, fltAttr.getValue ());
91- } else if (const auto intAttr =
92- mlir::dyn_cast<cir::IntAttr>(init.value ())) {
93- // Initializer is a constant array: convert it to a compatible llvm init.
94- init = rewriter.getIntegerAttr (llvmType, intAttr.getValue ());
95- } else {
218+ GlobalInitAttrRewriter initRewriter (llvmType, rewriter);
219+ init = initRewriter.rewriteInitAttr (init.value ());
220+ // If initRewriter returned a null attribute, init will have a value but
221+ // the value will be null. If that happens, initRewriter didn't handle the
222+ // attribute type. It probably needs to be added to GlobalInitAttrRewriter.
223+ if (!init.value ()) {
96224 op.emitError () << " unsupported initializer '" << init.value () << " '" ;
97225 return mlir::failure ();
98226 }
@@ -109,6 +237,13 @@ mlir::LogicalResult CIRToLLVMGlobalOpLowering::matchAndRewrite(
109237
110238static void prepareTypeConverter (mlir::LLVMTypeConverter &converter,
111239 mlir::DataLayout &dataLayout) {
240+ converter.addConversion ([&](cir::PointerType type) -> mlir::Type {
241+ // Drop pointee type since LLVM dialect only allows opaque pointers.
242+ assert (!cir::MissingFeatures::addressSpace ());
243+ unsigned targetAS = 0 ;
244+
245+ return mlir::LLVM::LLVMPointerType::get (type.getContext (), targetAS);
246+ });
112247 converter.addConversion ([&](cir::IntType type) -> mlir::Type {
113248 // LLVM doesn't work with signed types, so we drop the CIR signs here.
114249 return mlir::IntegerType::get (type.getContext (), type.getWidth ());
0 commit comments