clang 24.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 "PassDetail.h"
11
12#include "mlir/Dialect/OpenACC/OpenACCOpsDialect.h.inc"
13#include "mlir/Dialect/OpenMP/OpenMPOpsDialect.h.inc"
14#include "mlir/IR/PatternMatch.h"
15#include "mlir/Interfaces/DataLayoutInterfaces.h"
16#include "mlir/Pass/Pass.h"
17#include "mlir/Transforms/DialectConversion.h"
26
27#include "llvm/ADT/ScopeExit.h"
28#include "llvm/ADT/TypeSwitch.h"
29
30using namespace mlir;
31using namespace cir;
32
33namespace mlir {
34#define GEN_PASS_DEF_CXXABILOWERING
35#include "clang/CIR/Dialect/Passes.h.inc"
36} // namespace mlir
37
38namespace {
39// Check an attribute for legality. An attribute is only currently potentially
40// illegal if it contains a type, member pointers are our source of illegality
41// in regards to attributes.
42bool isCXXABIAttributeLegal(const mlir::TypeConverter &tc,
43 mlir::Attribute attr) {
44 // If we don't have an attribute, it can't have a type!
45 if (!attr)
46 return true;
47
48 // None of the OpenACC/OMP attributes contain a type of concern, so we can
49 // just treat them as legal.
50 if (isa<mlir::acc::OpenACCDialect, mlir::omp::OpenMPDialect>(
51 attr.getDialect()))
52 return true;
53
54 // These attributes either don't contain a type, or don't contain a type that
55 // can have a data member/method.
56 if (isa<mlir::DenseArrayAttr, mlir::FloatAttr, mlir::UnitAttr,
57 mlir::StringAttr, mlir::IntegerAttr, mlir::SymbolRefAttr,
58 cir::AnnotationAttr>(attr))
59 return true;
60
61 // Tablegen'ed always-legal attributes:
62 if (isa<
64#include "clang/CIR/Dialect/IR/CIRLowering.inc"
66 >(attr))
67 return true;
68
69 // Data Member and method are ALWAYS illegal.
70 if (isa<cir::DataMemberAttr, cir::DataMemberOffsetAttr, cir::MethodAttr>(
71 attr))
72 return false;
73
74 return llvm::TypeSwitch<mlir::Attribute, bool>(attr)
75 // These attributes just have a type, so they are legal if their type is.
76 .Case<cir::ZeroAttr>(
77 [&tc](cir::ZeroAttr za) { return tc.isLegal(za.getType()); })
78 .Case<cir::PoisonAttr>(
79 [&tc](cir::PoisonAttr pa) { return tc.isLegal(pa.getType()); })
80 .Case<cir::UndefAttr>(
81 [&tc](cir::UndefAttr uda) { return tc.isLegal(uda.getType()); })
82 .Case<mlir::TypeAttr>(
83 [&tc](mlir::TypeAttr ta) { return tc.isLegal(ta.getValue()); })
84 .Case<cir::ConstPtrAttr>(
85 [&tc](cir::ConstPtrAttr cpa) { return tc.isLegal(cpa.getType()); })
86 .Case<cir::CXXCtorAttr>(
87 [&tc](cir::CXXCtorAttr ca) { return tc.isLegal(ca.getType()); })
88 .Case<cir::CXXDtorAttr>(
89 [&tc](cir::CXXDtorAttr da) { return tc.isLegal(da.getType()); })
90 .Case<cir::CXXAssignAttr>(
91 [&tc](cir::CXXAssignAttr aa) { return tc.isLegal(aa.getType()); })
92
93 // Collection attributes are legal if ALL of the attributes in them are
94 // also legal.
95 .Case<mlir::ArrayAttr>([&tc](mlir::ArrayAttr array) {
96 return llvm::all_of(array.getValue(), [&tc](mlir::Attribute attr) {
97 return isCXXABIAttributeLegal(tc, attr);
98 });
99 })
100 .Case<mlir::DictionaryAttr>([&tc](mlir::DictionaryAttr dict) {
101 return llvm::all_of(dict.getValue(), [&tc](mlir::NamedAttribute na) {
102 return isCXXABIAttributeLegal(tc, na.getValue());
103 });
104 })
105 // These attributes have sub-attributes that we should check for legality.
106 .Case<cir::ConstArrayAttr>([&tc](cir::ConstArrayAttr array) {
107 return tc.isLegal(array.getType()) &&
108 isCXXABIAttributeLegal(tc, array.getElts());
109 })
110 .Case<cir::GlobalViewAttr>([&tc](cir::GlobalViewAttr gva) {
111 return tc.isLegal(gva.getType()) &&
112 isCXXABIAttributeLegal(tc, gva.getIndices());
113 })
114 .Case<cir::GlobalOffsetAttr>([&tc](cir::GlobalOffsetAttr goa) {
115 return tc.isLegal(goa.getType());
116 })
117 .Case<cir::VTableAttr>([&tc](cir::VTableAttr vta) {
118 return tc.isLegal(vta.getType()) &&
119 isCXXABIAttributeLegal(tc, vta.getData());
120 })
121 .Case<cir::TypeInfoAttr>([&tc](cir::TypeInfoAttr tia) {
122 return tc.isLegal(tia.getType()) &&
123 isCXXABIAttributeLegal(tc, tia.getData());
124 })
125 .Case<cir::DynamicCastInfoAttr>([&tc](cir::DynamicCastInfoAttr dcia) {
126 return isCXXABIAttributeLegal(tc, dcia.getSrcRtti()) &&
127 isCXXABIAttributeLegal(tc, dcia.getDestRtti()) &&
128 isCXXABIAttributeLegal(tc, dcia.getRuntimeFunc()) &&
129 isCXXABIAttributeLegal(tc, dcia.getBadCastFunc());
130 })
131 .Case<cir::ConstRecordAttr>([&tc](cir::ConstRecordAttr cra) {
132 return tc.isLegal(cra.getType()) &&
133 isCXXABIAttributeLegal(tc, cra.getMembers());
134 })
135 // We did an audit of all of our attributes (both in OpenACC and CIR), so
136 // it shouldn't be dangerous to consider everything we haven't considered
137 // 'illegal'. Any 'new' attributes will end up asserting in
138 // 'rewriteAttribute' to make sure we consider them here. Otherwise, we
139 // wouldn't discover a problematic new attribute until it contains a
140 // member/method.
141 .Default(false);
142}
143
144mlir::Attribute rewriteAttribute(const mlir::TypeConverter &tc,
145 mlir::MLIRContext *ctx, mlir::Attribute attr) {
146 // If the attribute is legal, there is no reason to rewrite it. This also
147 // filters out 'null' attributes.
148 if (isCXXABIAttributeLegal(tc, attr))
149 return attr;
150
151 // This switch needs to be kept in sync with the potentially-legal type switch
152 // from isCXXABIAttributeLegal. IF we miss any, this will end up causing
153 // verification/transformation issues later, often in the form of
154 // unrealized-conversion-casts.
155
156 return llvm::TypeSwitch<mlir::Attribute, mlir::Attribute>(attr)
157 // These attributes just have a type, so convert just the type.
158 .Case<cir::ZeroAttr>([&tc](cir::ZeroAttr za) {
159 return cir::ZeroAttr::get(tc.convertType(za.getType()));
160 })
161 .Case<cir::PoisonAttr>([&tc](cir::PoisonAttr pa) {
162 return cir::PoisonAttr::get(tc.convertType(pa.getType()));
163 })
164 .Case<cir::UndefAttr>([&tc](cir::UndefAttr uda) {
165 return cir::UndefAttr::get(tc.convertType(uda.getType()));
166 })
167 .Case<mlir::TypeAttr>([&tc](mlir::TypeAttr ta) {
168 return mlir::TypeAttr::get(tc.convertType(ta.getValue()));
169 })
170 .Case<cir::ConstPtrAttr>([&tc](cir::ConstPtrAttr cpa) {
171 return cir::ConstPtrAttr::get(tc.convertType(cpa.getType()),
172 cpa.getValue());
173 })
174 .Case<cir::CXXCtorAttr>([&tc](cir::CXXCtorAttr ca) {
175 return cir::CXXCtorAttr::get(tc.convertType(ca.getType()),
176 ca.getCtorKind(), ca.getIsTrivial());
177 })
178 .Case<cir::CXXDtorAttr>([&tc](cir::CXXDtorAttr da) {
179 return cir::CXXDtorAttr::get(tc.convertType(da.getType()),
180 da.getIsTrivial());
181 })
182 .Case<cir::CXXAssignAttr>([&tc](cir::CXXAssignAttr aa) {
183 return cir::CXXAssignAttr::get(tc.convertType(aa.getType()),
184 aa.getAssignKind(), aa.getIsTrivial());
185 })
186 // Collection attributes need to transform all of the attributes inside of
187 // them.
188 .Case<mlir::ArrayAttr>([&tc, ctx](mlir::ArrayAttr array) {
190 for (mlir::Attribute a : array.getValue())
191 elts.push_back(rewriteAttribute(tc, ctx, a));
192 return mlir::ArrayAttr::get(ctx, elts);
193 })
194 .Case<mlir::DictionaryAttr>([&tc, ctx](mlir::DictionaryAttr dict) {
196 for (mlir::NamedAttribute na : dict.getValue())
197 elts.emplace_back(na.getName(),
198 rewriteAttribute(tc, ctx, na.getValue()));
199
200 return mlir::DictionaryAttr::get(ctx, elts);
201 })
202 // These attributes have sub-attributes that need converting too.
203 .Case<cir::ConstArrayAttr>([&tc, ctx](cir::ConstArrayAttr array) {
204 return cir::ConstArrayAttr::get(
205 ctx, tc.convertType(array.getType()),
206 rewriteAttribute(tc, ctx, array.getElts()),
207 array.getTrailingZerosNum());
208 })
209 .Case<cir::GlobalViewAttr>([&tc, ctx](cir::GlobalViewAttr gva) {
210 return cir::GlobalViewAttr::get(
211 tc.convertType(gva.getType()), gva.getSymbol(),
212 mlir::cast<mlir::ArrayAttr>(
213 rewriteAttribute(tc, ctx, gva.getIndices())));
214 })
215 .Case<cir::GlobalOffsetAttr>([&tc](cir::GlobalOffsetAttr goa) {
216 return cir::GlobalOffsetAttr::get(tc.convertType(goa.getType()),
217 goa.getSymbol(), goa.getOffset());
218 })
219 .Case<cir::VTableAttr>([&tc, ctx](cir::VTableAttr vta) {
220 return cir::VTableAttr::get(
221 tc.convertType(vta.getType()),
222 mlir::cast<mlir::ArrayAttr>(
223 rewriteAttribute(tc, ctx, vta.getData())));
224 })
225 .Case<cir::TypeInfoAttr>([&tc, ctx](cir::TypeInfoAttr tia) {
226 return cir::TypeInfoAttr::get(
227 tc.convertType(tia.getType()),
228 mlir::cast<mlir::ArrayAttr>(
229 rewriteAttribute(tc, ctx, tia.getData())));
230 })
231 .Case<cir::DynamicCastInfoAttr>([&tc,
232 ctx](cir::DynamicCastInfoAttr dcia) {
233 return cir::DynamicCastInfoAttr::get(
234 mlir::cast<cir::GlobalViewAttr>(
235 rewriteAttribute(tc, ctx, dcia.getSrcRtti())),
236 mlir::cast<cir::GlobalViewAttr>(
237 rewriteAttribute(tc, ctx, dcia.getDestRtti())),
238 dcia.getRuntimeFunc(), dcia.getBadCastFunc(), dcia.getOffsetHint());
239 })
240 .Case<cir::ConstRecordAttr>([&tc, ctx](cir::ConstRecordAttr cra) {
241 return cir::ConstRecordAttr::get(
242 ctx, tc.convertType(cra.getType()),
243 mlir::cast<mlir::ArrayAttr>(
244 rewriteAttribute(tc, ctx, cra.getMembers())));
245 })
246 .DefaultUnreachable("unrewritten illegal attribute kind");
247}
248
249bool areCXXABIInherentAttrsLegal(mlir::Operation *op,
250 const mlir::TypeConverter &typeConverter) {
251 bool legal = true;
252 op->getName().walkInherentAttrs(
253 op, [&](llvm::StringRef, mlir::Attribute &attr) {
254 legal &= isCXXABIAttributeLegal(typeConverter, attr);
255 });
256 return legal;
257}
258
259#define GET_ABI_LOWERING_PATTERNS
260#include "clang/CIR/Dialect/IR/CIRLowering.inc"
261#undef GET_ABI_LOWERING_PATTERNS
262
263struct CXXABILoweringPass
264 : public impl::CXXABILoweringBase<CXXABILoweringPass> {
265 CXXABILoweringPass() = default;
266 void runOnOperation() override;
267};
268
269/// A generic ABI lowering rewrite pattern. This conversion pattern matches any
270/// CIR dialect operations with at least one operand or result of an
271/// ABI-dependent type. This conversion pattern rewrites the matched operation
272/// by replacing all its ABI-dependent operands and results with their
273/// lowered counterparts.
274class CIRGenericCXXABILoweringPattern : public mlir::ConversionPattern {
275public:
276 CIRGenericCXXABILoweringPattern(mlir::MLIRContext *context,
277 const mlir::TypeConverter &typeConverter)
278 : mlir::ConversionPattern(typeConverter, MatchAnyOpTypeTag(),
279 /*benefit=*/1, context) {}
280
281 mlir::LogicalResult
282 matchAndRewrite(mlir::Operation *op, llvm::ArrayRef<mlir::Value> operands,
283 mlir::ConversionPatternRewriter &rewriter) const override {
284 // Do not match on operations that have dedicated ABI lowering rewrite rules
285 if (llvm::isa<cir::AllocaOp, cir::BaseDataMemberOp, cir::BaseMethodOp,
286 cir::CastOp, cir::CmpOp, cir::ConstantOp, cir::DeleteArrayOp,
287 cir::DerivedDataMemberOp, cir::DerivedMethodOp, cir::FuncOp,
288 cir::GetMethodOp, cir::GetRuntimeMemberOp, cir::GlobalOp>(op))
289 return mlir::failure();
290
291 const mlir::TypeConverter *typeConverter = getTypeConverter();
292 assert(typeConverter &&
293 "CIRGenericCXXABILoweringPattern requires a type converter");
294 bool operandsAndResultsLegal = typeConverter->isLegal(op);
295 bool regionsLegal =
296 std::all_of(op->getRegions().begin(), op->getRegions().end(),
297 [typeConverter](mlir::Region &region) {
298 return typeConverter->isLegal(&region);
299 });
300 bool attrsLegal = areCXXABIInherentAttrsLegal(op, *typeConverter);
301
302 if (operandsAndResultsLegal && regionsLegal && attrsLegal) {
303 // The operation does not have any CXXABI-dependent operands or results,
304 // the match fails.
305 return mlir::failure();
306 }
307
308 mlir::OperationState loweredOpState(op->getLoc(), op->getName());
309 loweredOpState.addOperands(operands);
310 loweredOpState.addSuccessors(op->getSuccessors());
311
312 // Lower inherent attributes while preserving auxiliary metadata verbatim.
313 loweredOpState.propertiesAttr = op->getPropertiesAsAttribute();
314 loweredOpState.addAttributes(op->getDiscardableAttrDictionary().getValue());
315
316 // Lower all result types
317 llvm::SmallVector<mlir::Type> loweredResultTypes;
318 loweredResultTypes.reserve(op->getNumResults());
319 for (mlir::Type result : op->getResultTypes())
320 loweredResultTypes.push_back(typeConverter->convertType(result));
321 loweredOpState.addTypes(loweredResultTypes);
322
323 // Lower all regions
324 for (mlir::Region &region : op->getRegions()) {
325 mlir::Region *loweredRegion = loweredOpState.addRegion();
326 rewriter.inlineRegionBefore(region, *loweredRegion, loweredRegion->end());
327 if (mlir::failed(
328 rewriter.convertRegionTypes(loweredRegion, *getTypeConverter())))
329 return mlir::failure();
330 }
331
332 // Clone the operation with lowered operand types and result types
333 mlir::Operation *loweredOp = rewriter.create(loweredOpState);
334 loweredOp->getName().walkInherentAttrs(
335 loweredOp, [&](llvm::StringRef, mlir::Attribute &attr) {
336 attr = rewriteAttribute(*typeConverter, op->getContext(), attr);
337 });
338
339 rewriter.replaceOp(op, loweredOp);
340 return mlir::success();
341 }
342};
343
344} // namespace
345
346mlir::LogicalResult CIRAllocaOpABILowering::matchAndRewrite(
347 cir::AllocaOp op, OpAdaptor adaptor,
348 mlir::ConversionPatternRewriter &rewriter) const {
349 mlir::Type allocaPtrTy = op.getType();
350 mlir::Type loweredAllocaPtrTy = getTypeConverter()->convertType(allocaPtrTy);
351
352 cir::AllocaOp loweredOp = cir::AllocaOp::create(
353 rewriter, op.getLoc(), loweredAllocaPtrTy, op.getName(),
354 op.getAlignmentAttr(), /*dynAllocSize=*/adaptor.getDynAllocSize());
355 loweredOp.setInit(op.getInit());
356 loweredOp.setConstant(op.getConstant());
357 loweredOp.setAnnotationsAttr(op.getAnnotationsAttr());
358
359 rewriter.replaceOp(op, loweredOp);
360 return mlir::success();
361}
362
363mlir::LogicalResult CIRCastOpABILowering::matchAndRewrite(
364 cir::CastOp op, OpAdaptor adaptor,
365 mlir::ConversionPatternRewriter &rewriter) const {
366 mlir::Type srcTy = op.getSrc().getType();
367
368 if (mlir::isa<cir::DataMemberType, cir::MethodType>(srcTy)) {
369 switch (op.getKind()) {
370 case cir::CastKind::bitcast: {
371 mlir::Type destTy = getTypeConverter()->convertType(op.getType());
372 mlir::Value loweredResult;
373 if (mlir::isa<cir::DataMemberType>(srcTy))
374 loweredResult = lowerModule->getCXXABI().lowerDataMemberBitcast(
375 op, destTy, adaptor.getSrc(), rewriter);
376 else
377 loweredResult = lowerModule->getCXXABI().lowerMethodBitcast(
378 op, destTy, adaptor.getSrc(), rewriter);
379 rewriter.replaceOp(op, loweredResult);
380 return mlir::success();
381 }
382 case cir::CastKind::member_ptr_to_bool: {
383 mlir::Value loweredResult;
384 if (mlir::isa<cir::DataMemberType>(srcTy))
385 loweredResult = lowerModule->getCXXABI().lowerDataMemberToBoolCast(
386 op, adaptor.getSrc(), rewriter);
387 else
388 loweredResult = lowerModule->getCXXABI().lowerMethodToBoolCast(
389 op, adaptor.getSrc(), rewriter);
390 rewriter.replaceOp(op, loweredResult);
391 return mlir::success();
392 }
393 default:
394 break;
395 }
396 }
397
398 mlir::Value loweredResult = cir::CastOp::create(
399 rewriter, op.getLoc(), getTypeConverter()->convertType(op.getType()),
400 adaptor.getKind(), adaptor.getSrc());
401 rewriter.replaceOp(op, loweredResult);
402 return mlir::success();
403}
404
405// Helper function to lower a value for things like an initializer.
406static mlir::TypedAttr lowerInitialValue(const LowerModule *lowerModule,
407 const mlir::DataLayout &layout,
408 const mlir::TypeConverter &tc,
409 mlir::Type ty,
410 mlir::Attribute initVal) {
411 if (mlir::isa<cir::DataMemberType>(ty)) {
412 // Members without a CIR field index (e.g. no_unique_address empty fields)
413 // are represented by an explicit byte offset instead of a field path.
414 if (auto offsetVal =
415 mlir::dyn_cast_if_present<cir::DataMemberOffsetAttr>(initVal))
416 return lowerModule->getCXXABI().lowerDataMemberOffsetConstant(offsetVal,
417 layout, tc);
418 auto dataMemberVal = mlir::cast_if_present<cir::DataMemberAttr>(initVal);
419 return lowerModule->getCXXABI().lowerDataMemberConstant(dataMemberVal,
420 layout, tc);
421 }
422 if (mlir::isa<cir::MethodType>(ty)) {
423 auto methodVal = mlir::cast_if_present<cir::MethodAttr>(initVal);
424 return lowerModule->getCXXABI().lowerMethodConstant(methodVal, layout, tc);
425 }
426
427 if (auto arrTy = mlir::dyn_cast<cir::ArrayType>(ty)) {
428 auto loweredArrTy = mlir::cast<cir::ArrayType>(tc.convertType(arrTy));
429
430 if (!initVal)
431 return {};
432
433 if (auto zeroVal = mlir::dyn_cast_if_present<cir::ZeroAttr>(initVal))
434 return cir::ZeroAttr::get(loweredArrTy);
435
436 auto arrayVal = mlir::cast<cir::ConstArrayAttr>(initVal);
437
438 // String-literal arrays store their bytes as a StringAttr in `elts`. The
439 // backing i8 element type is never rewritten by the CXX ABI type
440 // converter, so the attribute is already legal and can be passed through
441 // unchanged.
442 if (mlir::isa<mlir::StringAttr>(arrayVal.getElts())) {
443 assert(loweredArrTy == arrTy &&
444 "string-literal array type should not change under CXX ABI");
445 return arrayVal;
446 }
447
448 auto arrayElts = mlir::cast<ArrayAttr>(arrayVal.getElts());
449 SmallVector<mlir::Attribute> loweredElements;
450 loweredElements.reserve(arrTy.getSize());
451 for (const mlir::Attribute &attr : arrayElts) {
452 auto typedAttr = cast<mlir::TypedAttr>(attr);
453 loweredElements.push_back(lowerInitialValue(
454 lowerModule, layout, tc, typedAttr.getType(), typedAttr));
455 }
456
457 return cir::ConstArrayAttr::get(
458 loweredArrTy, mlir::ArrayAttr::get(ty.getContext(), loweredElements),
459 arrayVal.getTrailingZerosNum());
460 }
461
462 if (auto recordTy = mlir::dyn_cast<cir::RecordType>(ty)) {
463 auto convertedTy =
464 mlir::dyn_cast<cir::RecordType>(tc.convertType(recordTy));
465 if (!convertedTy)
466 return {};
467
468 if (auto recVal = mlir::dyn_cast_if_present<cir::ZeroAttr>(initVal))
469 return cir::ZeroAttr::get(convertedTy);
470
471 if (auto undefVal = mlir::dyn_cast_if_present<cir::UndefAttr>(initVal))
472 return cir::UndefAttr::get(convertedTy);
473
474 // This might not be possible from Clang directly, but we can get here with
475 // hand-written IR.
476 if (auto poisonVal = mlir::dyn_cast_if_present<cir::PoisonAttr>(initVal))
477 return cir::PoisonAttr::get(convertedTy);
478
479 if (auto recVal =
480 mlir::dyn_cast_if_present<cir::ConstRecordAttr>(initVal)) {
481 auto recordMembers = mlir::cast<ArrayAttr>(recVal.getMembers());
482
483 SmallVector<mlir::Attribute> loweredMembers;
484 loweredMembers.reserve(recordMembers.size());
485
486 for (const mlir::Attribute &attr : recordMembers) {
487 auto typedAttr = cast<mlir::TypedAttr>(attr);
488 loweredMembers.push_back(lowerInitialValue(
489 lowerModule, layout, tc, typedAttr.getType(), typedAttr));
490 }
491
492 return cir::ConstRecordAttr::get(
493 convertedTy, mlir::ArrayAttr::get(ty.getContext(), loweredMembers));
494 }
495
496 assert(!initVal && "Record init val type not handled");
497 return {};
498 }
499
500 // Pointers can contain record types, which can change.
501 if (auto ptrTy = mlir::dyn_cast<cir::PointerType>(ty)) {
502 auto convertedTy = mlir::cast<cir::PointerType>(tc.convertType(ptrTy));
503 // pointers don't change other than their types.
504
505 if (auto gva = mlir::dyn_cast_if_present<cir::GlobalViewAttr>(initVal))
506 return cir::GlobalViewAttr::get(convertedTy, gva.getSymbol(),
507 gva.getIndices());
508
509 if (auto goa = mlir::dyn_cast_if_present<cir::GlobalOffsetAttr>(initVal))
510 return cir::GlobalOffsetAttr::get(convertedTy, goa.getSymbol(),
511 goa.getOffset());
512
513 if (auto blockAddr =
514 mlir::dyn_cast_if_present<cir::BlockAddrInfoAttr>(initVal)) {
515 assert(convertedTy == ptrTy && "BlockAddrInfo type should not change");
516 return blockAddr;
517 }
518
519 auto constPtr = mlir::cast_if_present<cir::ConstPtrAttr>(initVal);
520 if (!constPtr)
521 return {};
522 return cir::ConstPtrAttr::get(convertedTy, constPtr.getValue());
523 }
524
525 assert(ty == tc.convertType(ty) &&
526 "cir.global or constant operand is not an CXXABI-dependent type");
527
528 // Every other type can be left alone.
529 return cast<mlir::TypedAttr>(initVal);
530}
531
532mlir::LogicalResult CIRConstantOpABILowering::matchAndRewrite(
533 cir::ConstantOp op, OpAdaptor adaptor,
534 mlir::ConversionPatternRewriter &rewriter) const {
535
536 mlir::DataLayout layout(op->getParentOfType<mlir::ModuleOp>());
537 mlir::TypedAttr newValue = lowerInitialValue(
538 lowerModule, layout, *getTypeConverter(), op.getType(), op.getValue());
539 rewriter.replaceOpWithNewOp<ConstantOp>(op, newValue);
540 return mlir::success();
541}
542
543mlir::LogicalResult CIRCmpOpABILowering::matchAndRewrite(
544 cir::CmpOp op, OpAdaptor adaptor,
545 mlir::ConversionPatternRewriter &rewriter) const {
546 mlir::Type type = op.getLhs().getType();
547
548 mlir::Value loweredResult;
549 if (mlir::isa<cir::DataMemberType>(type))
550 loweredResult = lowerModule->getCXXABI().lowerDataMemberCmp(
551 op, adaptor.getLhs(), adaptor.getRhs(), rewriter);
552 else if (mlir::isa<cir::MethodType>(type))
553 loweredResult = lowerModule->getCXXABI().lowerMethodCmp(
554 op, adaptor.getLhs(), adaptor.getRhs(), rewriter);
555 else
556 loweredResult = cir::CmpOp::create(
557 rewriter, op.getLoc(), getTypeConverter()->convertType(op.getType()),
558 adaptor.getKind(), adaptor.getLhs(), adaptor.getRhs());
559
560 rewriter.replaceOp(op, loweredResult);
561 return mlir::success();
562}
563
564mlir::LogicalResult CIRFuncOpABILowering::matchAndRewrite(
565 cir::FuncOp op, OpAdaptor adaptor,
566 mlir::ConversionPatternRewriter &rewriter) const {
567 cir::FuncType opFuncType = op.getFunctionType();
568 mlir::TypeConverter::SignatureConversion signatureConversion(
569 opFuncType.getNumInputs());
570
571 for (const auto &[i, argType] : llvm::enumerate(opFuncType.getInputs())) {
572 mlir::Type loweredArgType = getTypeConverter()->convertType(argType);
573 if (!loweredArgType)
574 return mlir::failure();
575 signatureConversion.addInputs(i, loweredArgType);
576 }
577
578 mlir::Type loweredResultType =
579 getTypeConverter()->convertType(opFuncType.getReturnType());
580 if (!loweredResultType)
581 return mlir::failure();
582
583 auto loweredFuncType =
584 cir::FuncType::get(signatureConversion.getConvertedTypes(),
585 loweredResultType, /*isVarArg=*/opFuncType.isVarArg());
586
587 // Create a new cir.func operation for the CXXABI-lowered function.
588 cir::FuncOp loweredFuncOp = rewriter.cloneWithoutRegions(op);
589 loweredFuncOp.setFunctionType(loweredFuncType);
590
591 loweredFuncOp->getName().walkInherentAttrs(
592 loweredFuncOp, [&](llvm::StringRef, mlir::Attribute &attr) {
593 attr = rewriteAttribute(*getTypeConverter(), op->getContext(), attr);
594 });
595 rewriter.inlineRegionBefore(op.getBody(), loweredFuncOp.getBody(),
596 loweredFuncOp.end());
597 if (mlir::failed(rewriter.convertRegionTypes(
598 &loweredFuncOp.getBody(), *getTypeConverter(), &signatureConversion)))
599 return mlir::failure();
600
601 rewriter.eraseOp(op);
602 return mlir::success();
603}
604
605mlir::LogicalResult CIRGlobalOpABILowering::matchAndRewrite(
606 cir::GlobalOp op, OpAdaptor adaptor,
607 mlir::ConversionPatternRewriter &rewriter) const {
608 mlir::Type ty = op.getSymType();
609 mlir::Type loweredTy = getTypeConverter()->convertType(ty);
610 if (!loweredTy)
611 return mlir::failure();
612
613 mlir::DataLayout layout(op->getParentOfType<mlir::ModuleOp>());
614
615 mlir::Attribute loweredInit = lowerInitialValue(
616 lowerModule, layout, *getTypeConverter(), ty, op.getInitialValueAttr());
617
618 auto newOp = mlir::cast<cir::GlobalOp>(rewriter.clone(*op.getOperation()));
619 newOp.setInitialValueAttr(loweredInit);
620 newOp.setSymType(loweredTy);
621 rewriter.replaceOp(op, newOp);
622 return mlir::success();
623}
624
625mlir::LogicalResult CIRBaseDataMemberOpABILowering::matchAndRewrite(
626 cir::BaseDataMemberOp op, OpAdaptor adaptor,
627 mlir::ConversionPatternRewriter &rewriter) const {
628 mlir::Value loweredResult = lowerModule->getCXXABI().lowerBaseDataMember(
629 op, adaptor.getSrc(), rewriter);
630 rewriter.replaceOp(op, loweredResult);
631 return mlir::success();
632}
633
634mlir::LogicalResult CIRBaseMethodOpABILowering::matchAndRewrite(
635 cir::BaseMethodOp op, OpAdaptor adaptor,
636 mlir::ConversionPatternRewriter &rewriter) const {
637 mlir::Value loweredResult =
638 lowerModule->getCXXABI().lowerBaseMethod(op, adaptor.getSrc(), rewriter);
639 rewriter.replaceOp(op, loweredResult);
640 return mlir::success();
641}
642
643mlir::LogicalResult CIRDeleteArrayOpABILowering::matchAndRewrite(
644 cir::DeleteArrayOp op, OpAdaptor adaptor,
645 mlir::ConversionPatternRewriter &rewriter) const {
646 mlir::FlatSymbolRefAttr deleteFn = op.getDeleteFnAttr();
647 mlir::Location loc = op->getLoc();
648 mlir::Value loweredAddress = adaptor.getAddress();
649
650 cir::UsualDeleteParamsAttr deleteParams = op.getDeleteParamsAttr();
651 if (!deleteParams)
652 deleteParams = cir::UsualDeleteParamsAttr::get(op.getContext(), false,
653 std::nullopt, false, false);
654 bool cookieRequired = deleteParams.getSize() || op.getElementDtorAttr();
655
656 assert(!deleteParams.getDestroyingDelete() &&
657 "destroying delete not legal on arrays");
658 assert(!deleteParams.getTypeAwareDelete() &&
659 "type-aware delete not legal on arrays");
660
661 const CIRCXXABI &cxxABI = lowerModule->getCXXABI();
662 CIRBaseBuilderTy cirBuilder(rewriter);
663
664 // Read the array cookie (or compute the void* pointer for the
665 // non-cookie case) before creating the cleanup scope. The cookie read
666 // produces values that are needed by both the destruction loop in the
667 // body region (numElements for the array.dtor) and the operator
668 // delete[] call in the cleanup region (deletePtr / numElements for the
669 // total-size computation), so it must dominate both regions.
670 mlir::Value deletePtr;
671 mlir::Value numElements;
672 cir::PointerType ptrTy;
673 clang::CharUnits cookieSize;
674 mlir::DataLayout dl(op->getParentOfType<mlir::ModuleOp>());
675 unsigned ptrWidth =
676 lowerModule->getTarget().getPointerWidth(clang::LangAS::Default);
677 cir::IntType sizeTy = cirBuilder.getUIntNTy(ptrWidth);
678
679 if (cookieRequired) {
680 ptrTy = mlir::cast<cir::PointerType>(loweredAddress.getType());
681 clang::CharUnits elementAlign =
682 clang::CharUnits::fromQuantity(op.getElementAlign());
683 cxxABI.readArrayCookie(loc, loweredAddress, elementAlign, dl, cirBuilder,
684 numElements, deletePtr, cookieSize);
685 } else {
686 deletePtr = cir::CastOp::create(rewriter, loc, cirBuilder.getVoidPtrTy(),
687 cir::CastKind::bitcast, loweredAddress);
688 }
689
690 // Create a cleanup scope to wrap the ArrayDtor operation (if needed) and
691 // call the array delete operator from the cleanup region. If no exceptions
692 // are thrown during the array dtor, the normal control flow will call the
693 // delete operator. The ArrayDtor operation will get its own cleanup region
694 // when it is expanded during LoweringPrepare. If an exception is thrown, the
695 // exception handling flow will be connected to the cleanup region here to
696 // call the delete operator on the exception path.
697 mlir::FlatSymbolRefAttr dtorFn = op.getElementDtorAttr();
698 cir::CleanupKind cleanupKind =
699 op.getDtorMayThrow() ? cir::CleanupKind::All : cir::CleanupKind::Normal;
700 cir::CleanupScopeOp::create(
701 rewriter, loc, cleanupKind,
702 /*bodyBuilder=*/
703 [&](mlir::OpBuilder &b, mlir::Location l) {
704 if (dtorFn) {
705 auto eltPtrTy = cir::PointerType::get(ptrTy.getPointee());
706 auto arrayDtor = cir::ArrayDtor::create(
707 b, l, loweredAddress, numElements,
708 [&](mlir::OpBuilder &bb, mlir::Location ll) {
709 mlir::Value arg =
710 bb.getInsertionBlock()->addArgument(eltPtrTy, ll);
711 auto dtorCall = cir::CallOp::create(
712 bb, ll, dtorFn, cir::VoidType(), mlir::ValueRange{arg});
713 if (!op.getDtorMayThrow())
714 dtorCall.setNothrowAttr(bb.getUnitAttr());
715 cir::YieldOp::create(bb, ll);
716 });
717 if (op.getDtorMayThrow())
718 arrayDtor.setDtorMayThrow(true);
719 }
720 cir::YieldOp::create(b, l);
721 },
722 /*cleanupBuilder=*/
723 [&](mlir::OpBuilder &b, mlir::Location l) {
725 callArgs.push_back(deletePtr);
726 if (deleteParams.getSize()) {
727 uint64_t eltSizeBytes = dl.getTypeSizeInBits(ptrTy.getPointee()) / 8;
728 auto eltSizeVal = cir::ConstantOp::create(
729 b, l, cir::IntAttr::get(sizeTy, eltSizeBytes));
730 mlir::Value allocSize =
731 cir::MulOp::create(b, l, sizeTy, eltSizeVal, numElements);
732 auto cookieSizeVal = cir::ConstantOp::create(
733 b, l, cir::IntAttr::get(sizeTy, cookieSize.getQuantity()));
734 allocSize =
735 cir::AddOp::create(b, l, sizeTy, allocSize, cookieSizeVal);
736 callArgs.push_back(allocSize);
737 }
738 if (deleteParams.getAlignment()) {
739 auto alignVal = cir::ConstantOp::create(
740 b, l, cir::IntAttr::get(sizeTy, *deleteParams.getAlignment()));
741 callArgs.push_back(alignVal);
742 }
743
744 auto deleteCall =
745 cir::CallOp::create(b, l, deleteFn, cir::VoidType(), callArgs);
746 // operator delete[] is implicitly nothrow per [basic.stc.dynamic],
747 // matching classic CodeGen's `nounwind` attribute on the call.
748 deleteCall.setNothrowAttr(b.getUnitAttr());
749 cir::YieldOp::create(b, l);
750 });
751
752 rewriter.eraseOp(op);
753 return mlir::success();
754}
755
756mlir::LogicalResult CIRDerivedDataMemberOpABILowering::matchAndRewrite(
757 cir::DerivedDataMemberOp op, OpAdaptor adaptor,
758 mlir::ConversionPatternRewriter &rewriter) const {
759 mlir::Value loweredResult = lowerModule->getCXXABI().lowerDerivedDataMember(
760 op, adaptor.getSrc(), rewriter);
761 rewriter.replaceOp(op, loweredResult);
762 return mlir::success();
763}
764
765mlir::LogicalResult CIRDerivedMethodOpABILowering::matchAndRewrite(
766 cir::DerivedMethodOp op, OpAdaptor adaptor,
767 mlir::ConversionPatternRewriter &rewriter) const {
768 mlir::Value loweredResult = lowerModule->getCXXABI().lowerDerivedMethod(
769 op, adaptor.getSrc(), rewriter);
770 rewriter.replaceOp(op, loweredResult);
771 return mlir::success();
772}
773
774mlir::LogicalResult CIRDynamicCastOpABILowering::matchAndRewrite(
775 cir::DynamicCastOp op, OpAdaptor adaptor,
776 mlir::ConversionPatternRewriter &rewriter) const {
777 mlir::Value loweredResult =
778 lowerModule->getCXXABI().lowerDynamicCast(op, rewriter);
779 rewriter.replaceOp(op, loweredResult);
780 return mlir::success();
781}
782
783mlir::LogicalResult CIRGetMethodOpABILowering::matchAndRewrite(
784 cir::GetMethodOp op, OpAdaptor adaptor,
785 mlir::ConversionPatternRewriter &rewriter) const {
786 mlir::Value callee;
787 mlir::Value thisArg;
788 lowerModule->getCXXABI().lowerGetMethod(
789 op, callee, thisArg, adaptor.getMethod(), adaptor.getObject(), rewriter);
790 rewriter.replaceOp(op, {callee, thisArg});
791 return mlir::success();
792}
793
794mlir::LogicalResult CIRGetRuntimeMemberOpABILowering::matchAndRewrite(
795 cir::GetRuntimeMemberOp op, OpAdaptor adaptor,
796 mlir::ConversionPatternRewriter &rewriter) const {
797 mlir::Type resTy = getTypeConverter()->convertType(op.getType());
798 mlir::Operation *newOp = lowerModule->getCXXABI().lowerGetRuntimeMember(
799 op, resTy, adaptor.getAddr(), adaptor.getMember(), rewriter);
800 rewriter.replaceOp(op, newOp);
801 return mlir::success();
802}
803
804mlir::LogicalResult CIRVTableGetTypeInfoOpABILowering::matchAndRewrite(
805 cir::VTableGetTypeInfoOp op, OpAdaptor adaptor,
806 mlir::ConversionPatternRewriter &rewriter) const {
807 mlir::Value loweredResult =
808 lowerModule->getCXXABI().lowerVTableGetTypeInfo(op, rewriter);
809 rewriter.replaceOp(op, loweredResult);
810 return mlir::success();
811}
812
813namespace {
814// A small type to handle type conversion for the the CXXABILoweringPass.
815// Even though this is a CIR-to-CIR pass, we are eliminating some CIR types.
816// Most importantly, this pass solves recursive type conversion problems by
817// keeping a call stack.
818class CIRABITypeConverter : public mlir::TypeConverter {
819
820 mlir::MLIRContext &context;
821
822 // Recursive structure detection.
823 // We store one entry per thread here, and rely on locking. This works the
824 // same way as the LLVM-IR lowering does it, which has a similar problem.
825 DenseMap<uint64_t, std::unique_ptr<SmallVector<cir::RecordType>>>
826 conversionCallStack;
827 llvm::sys::SmartRWMutex<true> callStackMutex;
828
829 // In order to let us 'change the names' back after the fact, we collect them
830 // along the way. They should only be added/accessed via the thread-safe
831 // functions below.
832 llvm::SmallVector<cir::RecordType> convertedRecordTypes;
833 llvm::sys::SmartRWMutex<true> recordTypeMutex;
834
835 // This provides a stack for the RecordTypes being processed on the current
836 // thread, which lets us solve recursive conversions. This implementation is
837 // cribbed from the LLVMTypeConverter which solves a similar but not identical
838 // problem.
839 SmallVector<cir::RecordType> &getCurrentThreadRecursiveStack() {
840 {
841 // Most of the time, the entry already exists in the map.
842 std::shared_lock<decltype(callStackMutex)> lock(callStackMutex,
843 std::defer_lock);
844 if (context.isMultithreadingEnabled())
845 lock.lock();
846 auto recursiveStack = conversionCallStack.find(llvm::get_threadid());
847 if (recursiveStack != conversionCallStack.end())
848 return *recursiveStack->second;
849 }
850
851 // First time this thread gets here, we have to get an exclusive access to
852 // insert in the map
853 std::unique_lock<decltype(callStackMutex)> lock(callStackMutex);
854 auto recursiveStackInserted = conversionCallStack.insert(
855 std::make_pair(llvm::get_threadid(),
856 std::make_unique<SmallVector<cir::RecordType>>()));
857 return *recursiveStackInserted.first->second;
858 }
859
860 void addConvertedRecordType(cir::RecordType rt) {
861 std::unique_lock<decltype(recordTypeMutex)> lock(recordTypeMutex);
862 convertedRecordTypes.push_back(rt);
863 }
864
865 llvm::SmallVector<mlir::Type> convertRecordMemberTypes(cir::RecordType type) {
866 llvm::SmallVector<mlir::Type> loweredMemberTypes;
867 loweredMemberTypes.reserve(type.getNumElements());
868
869 if (mlir::failed(convertTypes(type.getMembers(), loweredMemberTypes)))
870 return {};
871
872 return loweredMemberTypes;
873 }
874
875 cir::RecordType convertRecordType(cir::RecordType type) {
876 // Unnamed record types can't be referred to recursively, so we can just
877 // convert this one. It also doesn't have uniqueness problems, so we can
878 // just do a conversion on it.
879 if (!type.getName()) {
880 llvm::SmallVector<mlir::Type> converted = convertRecordMemberTypes(type);
881 assert(converted.size() == type.getNumElements() &&
882 "member conversion must be one type in, one type out for the "
883 "kinds to carry over by index");
884 if (auto u = mlir::dyn_cast<cir::UnionType>(type)) {
885 mlir::Type loweredPadding;
886 if (mlir::Type pad = u.getPadding())
887 loweredPadding = convertType(pad);
888 return cir::UnionType::get(type.getContext(), converted,
889 type.getPacked(), loweredPadding,
890 u.getMemberKinds());
891 }
892 auto s = mlir::cast<cir::StructType>(type);
893 return cir::StructType::get(type.getContext(), converted,
894 type.getPacked(), s.getIsClass(),
895 s.getMemberKinds());
896 }
897
898 assert(!type.isIncomplete() || type.getMembers().empty());
899
900 // If the type has already been converted, we can just return, since there
901 // is nothing to do. Also, if it is incomplete, it can't have invalid
902 // members! So we can skip transforming it.
903 if (type.isIncomplete() || type.isABIConvertedRecord())
904 return type;
905
906 SmallVectorImpl<cir::RecordType> &recursiveStack =
907 getCurrentThreadRecursiveStack();
908
909 cir::RecordType convertedType;
910 if (mlir::isa<cir::UnionType>(type))
911 convertedType =
912 cir::UnionType::get(type.getContext(), type.getABIConvertedName());
913 else
914 convertedType =
915 cir::StructType::get(type.getContext(), type.getABIConvertedName(),
916 mlir::cast<cir::StructType>(type).getIsClass());
917
918 // This type has already been converted, just return it.
919 if (convertedType.isComplete())
920 return convertedType;
921
922 // We put the existing 'type' into the vector if we're in the process of
923 // converting it (and pop it when we're done). To prevent recursion,
924 // just return the 'incomplete' version, and the 'top level' version of this
925 // call will call 'complete' on it.
926 if (llvm::is_contained(recursiveStack, type))
927 return convertedType;
928
929 recursiveStack.push_back(type);
930 llvm::scope_exit popConvertingType(
931 [&recursiveStack]() { recursiveStack.pop_back(); });
932
933 SmallVector<mlir::Type> convertedMembers = convertRecordMemberTypes(type);
934 assert(convertedMembers.size() == type.getNumElements() &&
935 "member conversion must be one type in, one type out for the kinds "
936 "to carry over by index");
937
938 mlir::Type loweredPadding;
939 if (auto u = mlir::dyn_cast<cir::UnionType>(type))
940 if (mlir::Type pad = u.getPadding())
941 loweredPadding = convertType(pad);
942 convertedType.complete(convertedMembers, type.getPacked(), loweredPadding,
943 type.getMemberKinds());
944 addConvertedRecordType(convertedType);
945 return convertedType;
946 }
947
948public:
949 CIRABITypeConverter(mlir::MLIRContext &ctx, mlir::DataLayout &dataLayout,
950 cir::LowerModule &lowerModule)
951 : context(ctx) {
952 addConversion([&](mlir::Type type) -> mlir::Type { return type; });
953 // This is necessary in order to convert CIR pointer types that are
954 // pointing to CIR types that we are lowering in this pass.
955 addConversion([&](cir::PointerType type) -> mlir::Type {
956 mlir::Type loweredPointeeType = convertType(type.getPointee());
957 if (!loweredPointeeType)
958 return {};
959 return cir::PointerType::get(type.getContext(), loweredPointeeType,
960 type.getAddrSpace());
961 });
962 addConversion([&](cir::ArrayType type) -> mlir::Type {
963 mlir::Type loweredElementType = convertType(type.getElementType());
964 if (!loweredElementType)
965 return {};
966 return cir::ArrayType::get(loweredElementType, type.getSize());
967 });
968
969 addConversion([&](cir::DataMemberType type) -> mlir::Type {
970 mlir::Type abiType =
971 lowerModule.getCXXABI().lowerDataMemberType(type, *this);
972 return convertType(abiType);
973 });
974 addConversion([&](cir::MethodType type) -> mlir::Type {
975 mlir::Type abiType = lowerModule.getCXXABI().lowerMethodType(type, *this);
976 return convertType(abiType);
977 });
978 // This is necessary in order to convert CIR function types that have
979 // argument or return types that use CIR types that we are lowering in
980 // this pass.
981 addConversion([&](cir::FuncType type) -> mlir::Type {
982 llvm::SmallVector<mlir::Type> loweredInputTypes;
983 loweredInputTypes.reserve(type.getNumInputs());
984 if (mlir::failed(convertTypes(type.getInputs(), loweredInputTypes)))
985 return {};
986
987 mlir::Type loweredReturnType = convertType(type.getReturnType());
988 if (!loweredReturnType)
989 return {};
990
991 return cir::FuncType::get(loweredInputTypes, loweredReturnType,
992 /*isVarArg=*/type.getVarArg());
993 });
994 addConversion([&](cir::StructType type) -> mlir::Type {
995 return convertRecordType(type);
996 });
997 addConversion([&](cir::UnionType type) -> mlir::Type {
998 return convertRecordType(type);
999 });
1000 }
1001
1002 void restoreRecordTypeNames() {
1003 std::unique_lock<decltype(recordTypeMutex)> lock(recordTypeMutex);
1004
1005 for (auto rt : convertedRecordTypes)
1007 }
1008};
1009} // namespace
1010
1011static void
1012populateCXXABIConversionTarget(mlir::ConversionTarget &target,
1013 const mlir::TypeConverter &typeConverter) {
1014 target.addLegalOp<mlir::ModuleOp>();
1015
1016 // The ABI lowering pass is interested in CIR operations with operands or
1017 // results of CXXABI-dependent types, or CIR operations with regions whose
1018 // block arguments are of CXXABI-dependent types.
1019 target.addDynamicallyLegalDialect<cir::CIRDialect>(
1020 [&typeConverter](mlir::Operation *op) {
1021 if (!typeConverter.isLegal(op))
1022 return false;
1023
1024 bool attrs = areCXXABIInherentAttrsLegal(op, typeConverter);
1025
1026 return attrs &&
1027 std::all_of(op->getRegions().begin(), op->getRegions().end(),
1028 [&typeConverter](mlir::Region &region) {
1029 return typeConverter.isLegal(&region);
1030 });
1031 });
1032
1033 target.addDynamicallyLegalDialect<mlir::acc::OpenACCDialect>(
1034 [&typeConverter](mlir::Operation *op) {
1035 if (!typeConverter.isLegal(op))
1036 return false;
1037
1038 bool attrs = areCXXABIInherentAttrsLegal(op, typeConverter);
1039
1040 return attrs &&
1041 std::all_of(op->getRegions().begin(), op->getRegions().end(),
1042 [&typeConverter](mlir::Region &region) {
1043 return typeConverter.isLegal(&region);
1044 });
1045 });
1046
1047 // Some CIR ops needs special checking for legality
1048 target.addDynamicallyLegalOp<cir::FuncOp>([&typeConverter](cir::FuncOp op) {
1049 bool attrs = areCXXABIInherentAttrsLegal(op, typeConverter);
1050
1051 return attrs && typeConverter.isLegal(op.getFunctionType());
1052 });
1053 target.addDynamicallyLegalOp<cir::GlobalOp>(
1054 [&typeConverter](cir::GlobalOp op) {
1055 return typeConverter.isLegal(op.getSymType());
1056 });
1057 // Operations that do not use any special types must be explicitly marked as
1058 // illegal to trigger processing here.
1059 target.addIllegalOp<cir::DeleteArrayOp>();
1060 target.addIllegalOp<cir::DynamicCastOp>();
1061 target.addIllegalOp<cir::VTableGetTypeInfoOp>();
1062}
1063
1064//===----------------------------------------------------------------------===//
1065// The Pass
1066//===----------------------------------------------------------------------===//
1067
1068void CXXABILoweringPass::runOnOperation() {
1069 auto mod = mlir::cast<mlir::ModuleOp>(getOperation());
1070 mlir::MLIRContext *ctx = mod.getContext();
1071
1072 std::unique_ptr<cir::LowerModule> lowerModule = cir::createLowerModule(mod);
1073 // If lower module is not available, skip the ABI lowering pass.
1074 if (!lowerModule) {
1075 mod.emitWarning("Cannot create a CIR lower module, skipping the ")
1076 << getName() << " pass";
1077 return;
1078 }
1079
1080 mlir::DataLayout dataLayout(mod);
1081 CIRABITypeConverter typeConverter(*ctx, dataLayout, *lowerModule);
1082
1083 mlir::RewritePatternSet patterns(ctx);
1084 patterns.add<CIRGenericCXXABILoweringPattern>(patterns.getContext(),
1085 typeConverter);
1086 patterns.add<
1087#define GET_ABI_LOWERING_PATTERNS_LIST
1088#include "clang/CIR/Dialect/IR/CIRLowering.inc"
1089#undef GET_ABI_LOWERING_PATTERNS_LIST
1090 >(patterns.getContext(), typeConverter, dataLayout, *lowerModule);
1091
1092 mlir::ConversionTarget target(*ctx);
1093 populateCXXABIConversionTarget(target, typeConverter);
1094
1095 llvm::SmallVector<mlir::Operation *> ops;
1096 ops.push_back(mod);
1097 cir::collectUnreachable(mod, ops);
1098
1099 if (failed(mlir::applyPartialConversion(ops, target, std::move(patterns))))
1100 signalPassFailure();
1101
1102 typeConverter.restoreRecordTypeNames();
1103}
1104
1105std::unique_ptr<Pass> mlir::createCXXABILoweringPass() {
1106 return std::make_unique<CXXABILoweringPass>();
1107}
#define CXX_ABI_ALWAYS_LEGAL_ATTRS
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)
virtual mlir::Type lowerMethodType(cir::MethodType type, const mlir::TypeConverter &typeConverter) const =0
Lower the given member function pointer type to its ABI type.
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 lowerDataMemberOffsetConstant(cir::DataMemberOffsetAttr attr, const mlir::DataLayout &layout, const mlir::TypeConverter &typeConverter) const =0
Lower the given by-offset data member pointer constant (used for members with no CIR field index,...
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.
void readArrayCookie(mlir::Location loc, mlir::Value elementPtr, clang::CharUnits elementAlign, 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
CIRCXXABI & getCXXABI() const
Definition LowerModule.h:53
bool isComplete() const
Definition CIRTypes.h:168
void removeABIConversionNamePrefix()
Definition CIRTypes.cpp:696
void complete(llvm::ArrayRef< mlir::Type > members, bool packed, mlir::Type padding, llvm::ArrayRef< RecordMemberKind > memberKinds)
padding is union-only.
Definition CIRTypes.cpp:657
This is an opaque type for sizes expressed in character units.
Definition CharUnits.h:38
QuantityType getQuantity() const
Get the raw integer representation of this quantity.
Definition CharUnits.h:153
static CharUnits fromQuantity(QuantityType Quantity)
Construct a CharUnits quantity from a raw integer type.
Definition CharUnits.h:58
void collectUnreachable(mlir::Operation *parent, llvm::SmallVectorImpl< mlir::Operation * > &ops)
Collect ops in blocks that are unreachable from their region's entry, appending them to ops.
std::unique_ptr< LowerModule > createLowerModule(mlir::ModuleOp module)
const internal::VariadicAllOfMatcher< Attr > attr
const internal::VariadicAllOfMatcher< Type > type
Matches Types in the clang AST.
StringRef getName(const HeaderType T)
Definition HeaderFile.h:38
RangeSelector callArgs(std::string ID)
bool isa(CodeGen::Address addr)
Definition Address.h:330
@ Default
Set to the current date and time.
std::unique_ptr< Pass > createCXXABILoweringPass()
__DEVICE__ _Tp arg(const std::complex< _Tp > &__c)