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