24
24
#include " mlir/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.h"
25
25
#include " mlir/Target/LLVMIR/Export.h"
26
26
#include " mlir/Transforms/DialectConversion.h"
27
+ #include " clang/CIR/Dialect/IR/CIRAttrVisitor.h"
27
28
#include " clang/CIR/Dialect/IR/CIRDialect.h"
28
29
#include " clang/CIR/MissingFeatures.h"
29
30
#include " llvm/IR/Module.h"
@@ -35,6 +36,71 @@ using namespace llvm;
35
36
namespace cir {
36
37
namespace direct {
37
38
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
+
38
104
// This pass requires the CIR to be in a "flat" state. All blocks in each
39
105
// function must belong to the parent region. Once scopes and control flow
40
106
// are implemented in CIR, a pass will be run before this one to flatten
@@ -55,14 +121,81 @@ struct ConvertCIRToLLVMPass
55
121
StringRef getArgument () const override { return " cir-flat-to-llvm" ; }
56
122
};
57
123
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
+
58
182
mlir::LogicalResult CIRToLLVMGlobalOpLowering::matchAndRewrite (
59
183
cir::GlobalOp op, OpAdaptor adaptor,
60
184
mlir::ConversionPatternRewriter &rewriter) const {
61
185
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
+
62
194
// Fetch required values to create LLVM op.
63
195
const mlir::Type cirSymType = op.getSymType ();
64
196
65
197
// This is the LLVM dialect type.
198
+ assert (!cir::MissingFeatures::convertTypeForMemory ());
66
199
const mlir::Type llvmType = getTypeConverter ()->convertType (cirSymType);
67
200
// FIXME: These default values are placeholders until the the equivalent
68
201
// attributes are available on cir.global ops.
@@ -79,20 +212,15 @@ mlir::LogicalResult CIRToLLVMGlobalOpLowering::matchAndRewrite(
79
212
assert (!cir::MissingFeatures::opGlobalLinkage ());
80
213
const mlir::LLVM::Linkage linkage = mlir::LLVM::Linkage::External;
81
214
const StringRef symbol = op.getSymName ();
82
- std::optional<mlir::Attribute> init = op.getInitialValue ();
83
-
84
215
SmallVector<mlir::NamedAttribute> attributes;
85
216
86
217
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 ()) {
96
224
op.emitError () << " unsupported initializer '" << init.value () << " '" ;
97
225
return mlir::failure ();
98
226
}
@@ -109,6 +237,13 @@ mlir::LogicalResult CIRToLLVMGlobalOpLowering::matchAndRewrite(
109
237
110
238
static void prepareTypeConverter (mlir::LLVMTypeConverter &converter,
111
239
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
+ });
112
247
converter.addConversion ([&](cir::IntType type) -> mlir::Type {
113
248
// LLVM doesn't work with signed types, so we drop the CIR signs here.
114
249
return mlir::IntegerType::get (type.getContext (), type.getWidth ());
0 commit comments