clang 23.0.0git
CXXABILowering.cpp
Go to the documentation of this file.
1//==- CXXABILowering.cpp - lower C++ operations to target-specific ABI form -=//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include <deque>
10
11#include "PassDetail.h"
13
14#include "mlir/IR/PatternMatch.h"
15#include "mlir/Interfaces/DataLayoutInterfaces.h"
16#include "mlir/Pass/Pass.h"
17#include "mlir/Transforms/DialectConversion.h"
25
26using namespace mlir;
27using namespace cir;
28
29namespace mlir {
30#define GEN_PASS_DEF_CXXABILOWERING
31#include "clang/CIR/Dialect/Passes.h.inc"
32} // namespace mlir
33
34namespace {
35
36#define GET_ABI_LOWERING_PATTERNS
37#include "clang/CIR/Dialect/IR/CIRLowering.inc"
38#undef GET_ABI_LOWERING_PATTERNS
39
40struct CXXABILoweringPass
41 : public impl::CXXABILoweringBase<CXXABILoweringPass> {
42 CXXABILoweringPass() = default;
43 void runOnOperation() override;
44};
45
46/// A generic ABI lowering rewrite pattern. This conversion pattern matches any
47/// CIR dialect operations with at least one operand or result of an
48/// ABI-dependent type. This conversion pattern rewrites the matched operation
49/// by replacing all its ABI-dependent operands and results with their
50/// lowered counterparts.
51class CIRGenericCXXABILoweringPattern : public mlir::ConversionPattern {
52public:
53 CIRGenericCXXABILoweringPattern(mlir::MLIRContext *context,
54 const mlir::TypeConverter &typeConverter)
55 : mlir::ConversionPattern(typeConverter, MatchAnyOpTypeTag(),
56 /*benefit=*/1, context) {}
57
58 mlir::LogicalResult
59 matchAndRewrite(mlir::Operation *op, llvm::ArrayRef<mlir::Value> operands,
60 mlir::ConversionPatternRewriter &rewriter) const override {
61 // Do not match on operations that have dedicated ABI lowering rewrite rules
62 if (llvm::isa<cir::AllocaOp, cir::BaseDataMemberOp, cir::BaseMethodOp,
63 cir::CastOp, cir::CmpOp, cir::ConstantOp, cir::DeleteArrayOp,
64 cir::DerivedDataMemberOp, cir::DerivedMethodOp, cir::FuncOp,
65 cir::GetMethodOp, cir::GetRuntimeMemberOp, cir::GlobalOp>(op))
66 return mlir::failure();
67
68 const mlir::TypeConverter *typeConverter = getTypeConverter();
69 assert(typeConverter &&
70 "CIRGenericCXXABILoweringPattern requires a type converter");
71 bool operandsAndResultsLegal = typeConverter->isLegal(op);
72 bool regionsLegal =
73 std::all_of(op->getRegions().begin(), op->getRegions().end(),
74 [typeConverter](mlir::Region &region) {
75 return typeConverter->isLegal(&region);
76 });
77 if (operandsAndResultsLegal && regionsLegal) {
78 // The operation does not have any CXXABI-dependent operands or results,
79 // the match fails.
80 return mlir::failure();
81 }
82
83 assert(op->getNumRegions() == 0 && "CIRGenericCXXABILoweringPattern cannot "
84 "deal with operations with regions");
85
86 mlir::OperationState loweredOpState(op->getLoc(), op->getName());
87 loweredOpState.addOperands(operands);
88 loweredOpState.addAttributes(op->getAttrs());
89 loweredOpState.addSuccessors(op->getSuccessors());
90
91 // Lower all result types
92 llvm::SmallVector<mlir::Type> loweredResultTypes;
93 loweredResultTypes.reserve(op->getNumResults());
94 for (mlir::Type result : op->getResultTypes())
95 loweredResultTypes.push_back(typeConverter->convertType(result));
96 loweredOpState.addTypes(loweredResultTypes);
97
98 // Lower all regions
99 for (mlir::Region &region : op->getRegions()) {
100 mlir::Region *loweredRegion = loweredOpState.addRegion();
101 rewriter.inlineRegionBefore(region, *loweredRegion, loweredRegion->end());
102 if (mlir::failed(
103 rewriter.convertRegionTypes(loweredRegion, *getTypeConverter())))
104 return mlir::failure();
105 }
106
107 // Clone the operation with lowered operand types and result types
108 mlir::Operation *loweredOp = rewriter.create(loweredOpState);
109
110 rewriter.replaceOp(op, loweredOp);
111 return mlir::success();
112 }
113};
114
115} // namespace
116
117mlir::LogicalResult CIRAllocaOpABILowering::matchAndRewrite(
118 cir::AllocaOp op, OpAdaptor adaptor,
119 mlir::ConversionPatternRewriter &rewriter) const {
120 mlir::Type allocaPtrTy = op.getType();
121 mlir::Type allocaTy = op.getAllocaType();
122 mlir::Type loweredAllocaPtrTy = getTypeConverter()->convertType(allocaPtrTy);
123 mlir::Type loweredAllocaTy = getTypeConverter()->convertType(allocaTy);
124
125 cir::AllocaOp loweredOp = cir::AllocaOp::create(
126 rewriter, op.getLoc(), loweredAllocaPtrTy, loweredAllocaTy, op.getName(),
127 op.getAlignmentAttr(), /*dynAllocSize=*/adaptor.getDynAllocSize());
128 loweredOp.setInit(op.getInit());
129 loweredOp.setConstant(op.getConstant());
130 loweredOp.setAnnotationsAttr(op.getAnnotationsAttr());
131
132 rewriter.replaceOp(op, loweredOp);
133 return mlir::success();
134}
135
136mlir::LogicalResult CIRCastOpABILowering::matchAndRewrite(
137 cir::CastOp op, OpAdaptor adaptor,
138 mlir::ConversionPatternRewriter &rewriter) const {
139 mlir::Type srcTy = op.getSrc().getType();
140 assert((mlir::isa<cir::DataMemberType, cir::MethodType>(srcTy)) &&
141 "input to bitcast in ABI lowering must be a data member or method");
142
143 switch (op.getKind()) {
144 case cir::CastKind::bitcast: {
145 mlir::Type destTy = getTypeConverter()->convertType(op.getType());
146 mlir::Value loweredResult;
147 if (mlir::isa<cir::DataMemberType>(srcTy))
148 loweredResult = lowerModule->getCXXABI().lowerDataMemberBitcast(
149 op, destTy, adaptor.getSrc(), rewriter);
150 else
151 loweredResult = lowerModule->getCXXABI().lowerMethodBitcast(
152 op, destTy, adaptor.getSrc(), rewriter);
153 rewriter.replaceOp(op, loweredResult);
154 return mlir::success();
155 }
156 case cir::CastKind::member_ptr_to_bool: {
157 mlir::Value loweredResult;
158 if (mlir::isa<cir::MethodType>(srcTy))
159 loweredResult = lowerModule->getCXXABI().lowerMethodToBoolCast(
160 op, adaptor.getSrc(), rewriter);
161 else
162 loweredResult = lowerModule->getCXXABI().lowerDataMemberToBoolCast(
163 op, adaptor.getSrc(), rewriter);
164 rewriter.replaceOp(op, loweredResult);
165 return mlir::success();
166 }
167 default:
168 break;
169 }
170
171 return mlir::failure();
172}
173// Helper function to lower a value for things like an initializer.
174static mlir::TypedAttr lowerInitialValue(const LowerModule *lowerModule,
175 const mlir::DataLayout &layout,
176 const mlir::TypeConverter &tc,
177 mlir::Type ty,
178 mlir::Attribute initVal) {
179 if (mlir::isa<cir::DataMemberType>(ty)) {
180 auto dataMemberVal = mlir::cast_if_present<cir::DataMemberAttr>(initVal);
181 return lowerModule->getCXXABI().lowerDataMemberConstant(dataMemberVal,
182 layout, tc);
183 }
184 if (mlir::isa<cir::MethodType>(ty)) {
185 auto methodVal = mlir::cast_if_present<cir::MethodAttr>(initVal);
186 return lowerModule->getCXXABI().lowerMethodConstant(methodVal, layout, tc);
187 }
188
189 if (auto arrTy = mlir::dyn_cast<cir::ArrayType>(ty)) {
190 auto loweredArrTy = mlir::cast<cir::ArrayType>(tc.convertType(arrTy));
191 // TODO(cir): there are other types that can appear here inside of record
192 // members that we should handle. Those will come in a follow-up patch to
193 // minimize changes here.
194 if (!initVal)
195 return {};
196 auto arrayVal = mlir::cast<cir::ConstArrayAttr>(initVal);
197 auto arrayElts = mlir::cast<ArrayAttr>(arrayVal.getElts());
198 SmallVector<mlir::Attribute> loweredElements;
199 loweredElements.reserve(arrTy.getSize());
200 for (const mlir::Attribute &attr : arrayElts) {
201 auto typedAttr = cast<mlir::TypedAttr>(attr);
202 loweredElements.push_back(lowerInitialValue(
203 lowerModule, layout, tc, typedAttr.getType(), typedAttr));
204 }
205
206 return cir::ConstArrayAttr::get(
207 loweredArrTy, mlir::ArrayAttr::get(ty.getContext(), loweredElements),
208 arrayVal.getTrailingZerosNum());
209 }
210
211 llvm_unreachable("inputs to cir.global/constant in ABI lowering must be data "
212 "member or method");
213}
214
215mlir::LogicalResult CIRConstantOpABILowering::matchAndRewrite(
216 cir::ConstantOp op, OpAdaptor adaptor,
217 mlir::ConversionPatternRewriter &rewriter) const {
218
219 mlir::DataLayout layout(op->getParentOfType<mlir::ModuleOp>());
220 mlir::TypedAttr newValue = lowerInitialValue(
221 lowerModule, layout, *getTypeConverter(), op.getType(), op.getValue());
222 rewriter.replaceOpWithNewOp<ConstantOp>(op, newValue);
223 return mlir::success();
224}
225
226mlir::LogicalResult CIRCmpOpABILowering::matchAndRewrite(
227 cir::CmpOp op, OpAdaptor adaptor,
228 mlir::ConversionPatternRewriter &rewriter) const {
229 mlir::Type type = op.getLhs().getType();
230 assert((mlir::isa<cir::DataMemberType, cir::MethodType>(type)) &&
231 "input to cmp in ABI lowering must be a data member or method");
232
233 mlir::Value loweredResult;
234 if (mlir::isa<cir::DataMemberType>(type))
235 loweredResult = lowerModule->getCXXABI().lowerDataMemberCmp(
236 op, adaptor.getLhs(), adaptor.getRhs(), rewriter);
237 else
238 loweredResult = lowerModule->getCXXABI().lowerMethodCmp(
239 op, adaptor.getLhs(), adaptor.getRhs(), rewriter);
240
241 rewriter.replaceOp(op, loweredResult);
242 return mlir::success();
243}
244
245mlir::LogicalResult CIRFuncOpABILowering::matchAndRewrite(
246 cir::FuncOp op, OpAdaptor adaptor,
247 mlir::ConversionPatternRewriter &rewriter) const {
248 cir::FuncType opFuncType = op.getFunctionType();
249 mlir::TypeConverter::SignatureConversion signatureConversion(
250 opFuncType.getNumInputs());
251
252 for (const auto &[i, argType] : llvm::enumerate(opFuncType.getInputs())) {
253 mlir::Type loweredArgType = getTypeConverter()->convertType(argType);
254 if (!loweredArgType)
255 return mlir::failure();
256 signatureConversion.addInputs(i, loweredArgType);
257 }
258
259 mlir::Type loweredResultType =
260 getTypeConverter()->convertType(opFuncType.getReturnType());
261 if (!loweredResultType)
262 return mlir::failure();
263
264 auto loweredFuncType =
265 cir::FuncType::get(signatureConversion.getConvertedTypes(),
266 loweredResultType, /*isVarArg=*/opFuncType.isVarArg());
267
268 // Create a new cir.func operation for the CXXABI-lowered function.
269 cir::FuncOp loweredFuncOp = rewriter.cloneWithoutRegions(op);
270 loweredFuncOp.setFunctionType(loweredFuncType);
271 rewriter.inlineRegionBefore(op.getBody(), loweredFuncOp.getBody(),
272 loweredFuncOp.end());
273 if (mlir::failed(rewriter.convertRegionTypes(
274 &loweredFuncOp.getBody(), *getTypeConverter(), &signatureConversion)))
275 return mlir::failure();
276
277 rewriter.eraseOp(op);
278 return mlir::success();
279}
280
281mlir::LogicalResult CIRGlobalOpABILowering::matchAndRewrite(
282 cir::GlobalOp op, OpAdaptor adaptor,
283 mlir::ConversionPatternRewriter &rewriter) const {
284 mlir::Type ty = op.getSymType();
285 mlir::Type loweredTy = getTypeConverter()->convertType(ty);
286 if (!loweredTy)
287 return mlir::failure();
288
289 mlir::DataLayout layout(op->getParentOfType<mlir::ModuleOp>());
290
291 mlir::Attribute loweredInit = lowerInitialValue(
292 lowerModule, layout, *getTypeConverter(), ty, op.getInitialValueAttr());
293
294 auto newOp = mlir::cast<cir::GlobalOp>(rewriter.clone(*op.getOperation()));
295 newOp.setInitialValueAttr(loweredInit);
296 newOp.setSymType(loweredTy);
297 rewriter.replaceOp(op, newOp);
298 return mlir::success();
299}
300
301mlir::LogicalResult CIRBaseDataMemberOpABILowering::matchAndRewrite(
302 cir::BaseDataMemberOp op, OpAdaptor adaptor,
303 mlir::ConversionPatternRewriter &rewriter) const {
304 mlir::Value loweredResult = lowerModule->getCXXABI().lowerBaseDataMember(
305 op, adaptor.getSrc(), rewriter);
306 rewriter.replaceOp(op, loweredResult);
307 return mlir::success();
308}
309
310mlir::LogicalResult CIRBaseMethodOpABILowering::matchAndRewrite(
311 cir::BaseMethodOp op, OpAdaptor adaptor,
312 mlir::ConversionPatternRewriter &rewriter) const {
313 mlir::Value loweredResult =
314 lowerModule->getCXXABI().lowerBaseMethod(op, adaptor.getSrc(), rewriter);
315 rewriter.replaceOp(op, loweredResult);
316 return mlir::success();
317}
318
319mlir::LogicalResult CIRDeleteArrayOpABILowering::matchAndRewrite(
320 cir::DeleteArrayOp op, OpAdaptor adaptor,
321 mlir::ConversionPatternRewriter &rewriter) const {
322 mlir::FlatSymbolRefAttr deleteFn = op.getDeleteFnAttr();
323 mlir::Location loc = op->getLoc();
324 mlir::Value loweredAddress = adaptor.getAddress();
325
326 cir::UsualDeleteParamsAttr deleteParams = op.getDeleteParams();
327 bool cookieRequired = deleteParams.getSize();
328 assert((deleteParams.getSize() || !op.getElementDtorAttr()) &&
329 "Expected size parameter when dtor fn is provided!");
330
331 if (deleteParams.getTypeAwareDelete() || deleteParams.getDestroyingDelete() ||
332 deleteParams.getAlignment())
333 return rewriter.notifyMatchFailure(
334 op, "type-aware, destroying, or aligned delete not yet supported");
335
336 const CIRCXXABI &cxxABI = lowerModule->getCXXABI();
337 CIRBaseBuilderTy cirBuilder(rewriter);
338 mlir::Value deletePtr;
340
341 if (cookieRequired) {
342 mlir::Value numElements;
343 clang::CharUnits cookieSize;
344 auto ptrTy = mlir::cast<cir::PointerType>(loweredAddress.getType());
345 mlir::DataLayout dl(op->getParentOfType<mlir::ModuleOp>());
346
347 cxxABI.readArrayCookie(loc, loweredAddress, dl, cirBuilder, numElements,
348 deletePtr, cookieSize);
349
350 // If a dtor function is provided, create an array dtor operation.
351 // This will get expanded during LoweringPrepare.
352 mlir::FlatSymbolRefAttr dtorFn = op.getElementDtorAttr();
353 if (dtorFn) {
354 auto eltPtrTy = cir::PointerType::get(ptrTy.getPointee());
355 cir::ArrayDtor::create(
356 rewriter, loc, loweredAddress, numElements,
357 [&](mlir::OpBuilder &b, mlir::Location l) {
358 auto arg = b.getInsertionBlock()->addArgument(eltPtrTy, l);
359 cir::CallOp::create(b, l, dtorFn, cir::VoidType(),
360 mlir::ValueRange{arg});
361 cir::YieldOp::create(b, l);
362 });
363 }
364
365 // Compute the total allocation size and add it to the call arguments.
366 callArgs.push_back(deletePtr);
367 uint64_t eltSizeBytes = dl.getTypeSizeInBits(ptrTy.getPointee()) / 8;
368 unsigned ptrWidth =
369 lowerModule->getTarget().getPointerWidth(clang::LangAS::Default);
370 cir::IntType sizeTy = cirBuilder.getUIntNTy(ptrWidth);
371
372 mlir::Value eltSizeVal = cir::ConstantOp::create(
373 rewriter, loc, cir::IntAttr::get(sizeTy, eltSizeBytes));
374 mlir::Value allocSize =
375 cir::MulOp::create(rewriter, loc, sizeTy, eltSizeVal, numElements);
376 mlir::Value cookieSizeVal = cir::ConstantOp::create(
377 rewriter, loc, cir::IntAttr::get(sizeTy, cookieSize.getQuantity()));
378 allocSize =
379 cir::AddOp::create(rewriter, loc, sizeTy, allocSize, cookieSizeVal);
380 callArgs.push_back(allocSize);
381 } else {
382 deletePtr = cir::CastOp::create(rewriter, loc, cirBuilder.getVoidPtrTy(),
383 cir::CastKind::bitcast, loweredAddress);
384 callArgs.push_back(deletePtr);
385 }
386
387 cir::CallOp::create(rewriter, loc, deleteFn, cir::VoidType(), callArgs);
388 rewriter.eraseOp(op);
389 return mlir::success();
390}
391
392mlir::LogicalResult CIRDerivedDataMemberOpABILowering::matchAndRewrite(
393 cir::DerivedDataMemberOp op, OpAdaptor adaptor,
394 mlir::ConversionPatternRewriter &rewriter) const {
395 mlir::Value loweredResult = lowerModule->getCXXABI().lowerDerivedDataMember(
396 op, adaptor.getSrc(), rewriter);
397 rewriter.replaceOp(op, loweredResult);
398 return mlir::success();
399}
400
401mlir::LogicalResult CIRDerivedMethodOpABILowering::matchAndRewrite(
402 cir::DerivedMethodOp op, OpAdaptor adaptor,
403 mlir::ConversionPatternRewriter &rewriter) const {
404 mlir::Value loweredResult = lowerModule->getCXXABI().lowerDerivedMethod(
405 op, adaptor.getSrc(), rewriter);
406 rewriter.replaceOp(op, loweredResult);
407 return mlir::success();
408}
409
410mlir::LogicalResult CIRDynamicCastOpABILowering::matchAndRewrite(
411 cir::DynamicCastOp op, OpAdaptor adaptor,
412 mlir::ConversionPatternRewriter &rewriter) const {
413 mlir::Value loweredResult =
414 lowerModule->getCXXABI().lowerDynamicCast(op, rewriter);
415 rewriter.replaceOp(op, loweredResult);
416 return mlir::success();
417}
418
419mlir::LogicalResult CIRGetMethodOpABILowering::matchAndRewrite(
420 cir::GetMethodOp op, OpAdaptor adaptor,
421 mlir::ConversionPatternRewriter &rewriter) const {
422 mlir::Value callee;
423 mlir::Value thisArg;
424 lowerModule->getCXXABI().lowerGetMethod(
425 op, callee, thisArg, adaptor.getMethod(), adaptor.getObject(), rewriter);
426 rewriter.replaceOp(op, {callee, thisArg});
427 return mlir::success();
428}
429
430mlir::LogicalResult CIRGetRuntimeMemberOpABILowering::matchAndRewrite(
431 cir::GetRuntimeMemberOp op, OpAdaptor adaptor,
432 mlir::ConversionPatternRewriter &rewriter) const {
433 mlir::Type resTy = getTypeConverter()->convertType(op.getType());
434 mlir::Operation *newOp = lowerModule->getCXXABI().lowerGetRuntimeMember(
435 op, resTy, adaptor.getAddr(), adaptor.getMember(), rewriter);
436 rewriter.replaceOp(op, newOp);
437 return mlir::success();
438}
439
440mlir::LogicalResult CIRVTableGetTypeInfoOpABILowering::matchAndRewrite(
441 cir::VTableGetTypeInfoOp op, OpAdaptor adaptor,
442 mlir::ConversionPatternRewriter &rewriter) const {
443 mlir::Value loweredResult =
444 lowerModule->getCXXABI().lowerVTableGetTypeInfo(op, rewriter);
445 rewriter.replaceOp(op, loweredResult);
446 return mlir::success();
447}
448
449// A type to handle type conversion for the CXXABILowering pass.
450class CIRABITypeConverter : public mlir::TypeConverter {
451public:
452 CIRABITypeConverter(mlir::DataLayout &dataLayout,
453 cir::LowerModule &lowerModule) {
454 addConversion([&](mlir::Type type) -> mlir::Type { return type; });
455 // This is necessary in order to convert CIR pointer types that are
456 // pointing to CIR types that we are lowering in this pass.
457 addConversion([&](cir::PointerType type) -> mlir::Type {
458 mlir::Type loweredPointeeType = convertType(type.getPointee());
459 if (!loweredPointeeType)
460 return {};
461 return cir::PointerType::get(type.getContext(), loweredPointeeType,
462 type.getAddrSpace());
463 });
464 addConversion([&](cir::ArrayType type) -> mlir::Type {
465 mlir::Type loweredElementType = convertType(type.getElementType());
466 if (!loweredElementType)
467 return {};
468 return cir::ArrayType::get(loweredElementType, type.getSize());
469 });
470
471 addConversion([&](cir::DataMemberType type) -> mlir::Type {
472 mlir::Type abiType =
473 lowerModule.getCXXABI().lowerDataMemberType(type, *this);
474 return convertType(abiType);
475 });
476 addConversion([&](cir::MethodType type) -> mlir::Type {
477 mlir::Type abiType = lowerModule.getCXXABI().lowerMethodType(type, *this);
478 return convertType(abiType);
479 });
480 // This is necessary in order to convert CIR function types that have
481 // argument or return types that use CIR types that we are lowering in
482 // this pass.
483 addConversion([&](cir::FuncType type) -> mlir::Type {
484 llvm::SmallVector<mlir::Type> loweredInputTypes;
485 loweredInputTypes.reserve(type.getNumInputs());
486 if (mlir::failed(convertTypes(type.getInputs(), loweredInputTypes)))
487 return {};
488
489 mlir::Type loweredReturnType = convertType(type.getReturnType());
490 if (!loweredReturnType)
491 return {};
492
493 return cir::FuncType::get(loweredInputTypes, loweredReturnType,
494 /*isVarArg=*/type.getVarArg());
495 });
496 }
497};
498
499static void
500populateCXXABIConversionTarget(mlir::ConversionTarget &target,
501 const mlir::TypeConverter &typeConverter) {
502 target.addLegalOp<mlir::ModuleOp>();
503
504 // The ABI lowering pass is interested in CIR operations with operands or
505 // results of CXXABI-dependent types, or CIR operations with regions whose
506 // block arguments are of CXXABI-dependent types.
507 target.addDynamicallyLegalDialect<cir::CIRDialect>(
508 [&typeConverter](mlir::Operation *op) {
509 if (!typeConverter.isLegal(op))
510 return false;
511 return std::all_of(op->getRegions().begin(), op->getRegions().end(),
512 [&typeConverter](mlir::Region &region) {
513 return typeConverter.isLegal(&region);
514 });
515 });
516
517 // Some CIR ops needs special checking for legality
518 target.addDynamicallyLegalOp<cir::FuncOp>([&typeConverter](cir::FuncOp op) {
519 return typeConverter.isLegal(op.getFunctionType());
520 });
521 target.addDynamicallyLegalOp<cir::GlobalOp>(
522 [&typeConverter](cir::GlobalOp op) {
523 return typeConverter.isLegal(op.getSymType());
524 });
525 // Operations that do not use any special types must be explicitly marked as
526 // illegal to trigger processing here.
527 target.addIllegalOp<cir::DeleteArrayOp>();
528 target.addIllegalOp<cir::DynamicCastOp>();
529 target.addIllegalOp<cir::VTableGetTypeInfoOp>();
530}
531
532//===----------------------------------------------------------------------===//
533// The Pass
534//===----------------------------------------------------------------------===//
535
536// The applyPartialConversion function traverses blocks in the dominance order,
537// so it does not lower and operations that are not reachachable from the
538// operations passed in as arguments. Since we do need to lower such code in
539// order to avoid verification errors occur, we cannot just pass the module op
540// to applyPartialConversion. We must build a set of unreachable ops and
541// explicitly add them, along with the module, to the vector we pass to
542// applyPartialConversion.
543//
544// For instance, this CIR code:
545//
546// cir.func @foo(%arg0: !s32i) -> !s32i {
547// %4 = cir.cast int_to_bool %arg0 : !s32i -> !cir.bool
548// cir.if %4 {
549// %5 = cir.const #cir.int<1> : !s32i
550// cir.return %5 : !s32i
551// } else {
552// %5 = cir.const #cir.int<0> : !s32i
553// cir.return %5 : !s32i
554// }
555// cir.return %arg0 : !s32i
556// }
557//
558// contains an unreachable return operation (the last one). After the CXXABI
559// pass it will be placed into the unreachable block. This will error because
560// it will have not converted the types in the block, making the legalizer fail.
561//
562// In the future we may want to get rid of this function and use a DCE pass or
563// something similar. But for now we need to guarantee the absence of the
564// dialect verification errors. Note: We do the same in LowerToLLVM as well,
565// this is a striaght copy/paste including most of the comment. We might wi sh
566// to combine these if we don't want to do a DCE pass/etc.
567static void collectUnreachable(mlir::Operation *parent,
569
570 llvm::SmallVector<mlir::Block *> unreachableBlocks;
571 parent->walk([&](mlir::Block *blk) { // check
572 if (blk->hasNoPredecessors() && !blk->isEntryBlock())
573 unreachableBlocks.push_back(blk);
574 });
575
576 std::set<mlir::Block *> visited;
577 for (mlir::Block *root : unreachableBlocks) {
578 // We create a work list for each unreachable block.
579 // Thus we traverse operations in some order.
580 std::deque<mlir::Block *> workList;
581 workList.push_back(root);
582
583 while (!workList.empty()) {
584 mlir::Block *blk = workList.back();
585 workList.pop_back();
586 if (visited.count(blk))
587 continue;
588 visited.emplace(blk);
589
590 for (mlir::Operation &op : *blk)
591 ops.push_back(&op);
592
593 for (mlir::Block *succ : blk->getSuccessors())
594 workList.push_back(succ);
595 }
596 }
597}
598
599void CXXABILoweringPass::runOnOperation() {
600 auto mod = mlir::cast<mlir::ModuleOp>(getOperation());
601 mlir::MLIRContext *ctx = mod.getContext();
602
603 std::unique_ptr<cir::LowerModule> lowerModule = cir::createLowerModule(mod);
604 // If lower module is not available, skip the ABI lowering pass.
605 if (!lowerModule) {
606 mod.emitWarning("Cannot create a CIR lower module, skipping the ")
607 << getName() << " pass";
608 return;
609 }
610
611 mlir::DataLayout dataLayout(mod);
612 CIRABITypeConverter typeConverter(dataLayout, *lowerModule);
613
614 mlir::RewritePatternSet patterns(ctx);
615 patterns.add<CIRGenericCXXABILoweringPattern>(patterns.getContext(),
616 typeConverter);
617 patterns.add<
618#define GET_ABI_LOWERING_PATTERNS_LIST
619#include "clang/CIR/Dialect/IR/CIRLowering.inc"
620#undef GET_ABI_LOWERING_PATTERNS_LIST
621 >(patterns.getContext(), typeConverter, dataLayout, *lowerModule);
622
623 mlir::ConversionTarget target(*ctx);
624 populateCXXABIConversionTarget(target, typeConverter);
625
626 llvm::SmallVector<mlir::Operation *> ops;
627 ops.push_back(mod);
628 collectUnreachable(mod, ops);
629
630 if (failed(mlir::applyPartialConversion(ops, target, std::move(patterns))))
631 signalPassFailure();
632}
633
634std::unique_ptr<Pass> mlir::createCXXABILoweringPass() {
635 return std::make_unique<CXXABILoweringPass>();
636}
static void collectUnreachable(mlir::Operation *parent, llvm::SmallVector< mlir::Operation * > &ops)
static void populateCXXABIConversionTarget(mlir::ConversionTarget &target, const mlir::TypeConverter &typeConverter)
static mlir::TypedAttr lowerInitialValue(const LowerModule *lowerModule, const mlir::DataLayout &layout, const mlir::TypeConverter &tc, mlir::Type ty, mlir::Attribute initVal)
__device__ __2f16 b
CIRABITypeConverter(mlir::DataLayout &dataLayout, cir::LowerModule &lowerModule)
virtual mlir::Type lowerMethodType(cir::MethodType type, const mlir::TypeConverter &typeConverter) const =0
Lower the given member function pointer type to its ABI type.
void readArrayCookie(mlir::Location loc, mlir::Value elementPtr, const mlir::DataLayout &dataLayout, CIRBaseBuilderTy &builder, mlir::Value &numElements, mlir::Value &allocPtr, clang::CharUnits &cookieSize) const
Read the array cookie for a dynamically-allocated array whose first element is at elementPtr.
Definition CIRCXXABI.cpp:25
virtual mlir::TypedAttr lowerDataMemberConstant(cir::DataMemberAttr attr, const mlir::DataLayout &layout, const mlir::TypeConverter &typeConverter) const =0
Lower the given data member pointer constant to a constant of the ABI type.
virtual mlir::TypedAttr lowerMethodConstant(cir::MethodAttr attr, const mlir::DataLayout &layout, const mlir::TypeConverter &typeConverter) const =0
Lower the given member function pointer constant to a constant of the ABI type.
virtual mlir::Type lowerDataMemberType(cir::DataMemberType type, const mlir::TypeConverter &typeConverter) const =0
Lower the given data member pointer type to its ABI type.
CIRCXXABI & getCXXABI() const
Definition LowerModule.h:46
CharUnits - This is an opaque type for sizes expressed in character units.
Definition CharUnits.h:38
QuantityType getQuantity() const
getQuantity - Get the raw integer representation of this quantity.
Definition CharUnits.h:185
std::unique_ptr< LowerModule > createLowerModule(mlir::ModuleOp module)
StringRef getName(const HeaderType T)
Definition HeaderFile.h:38
RangeSelector callArgs(std::string ID)
std::unique_ptr< Pass > createCXXABILoweringPass()
__DEVICE__ _Tp arg(const std::complex< _Tp > &__c)