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