clang 24.0.0git
CIRABIClassifier.cpp
Go to the documentation of this file.
1//===- CIRABIClassifier.cpp - ABI classification for CIR ------------------===//
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// This file implements the classification shared by the targets that classify
10// through the LLVM ABI Lowering Library, and the two test drivers that stand
11// in for a target.
12//
13//===----------------------------------------------------------------------===//
14
15#include "CIRABIClassifier.h"
17
18#include "mlir/ABI/Targets/Test/TestTarget.h"
21#include "llvm/ABI/Types.h"
22#include "llvm/ADT/TypeSwitch.h"
23#include "llvm/Support/MathExtras.h"
24
25using namespace mlir;
26using namespace mlir::abi;
27using namespace cir;
28
29//===----------------------------------------------------------------------===//
30// LLVM ABI Lowering Library classifier bridge
31//
32// Maps CIR types to llvm::abi::Type, runs the target's classifier from the
33// LLVM ABI Lowering Library, and converts the result back into the
34// dialect-agnostic mlir::abi::FunctionClassification that CIRABIRewriteContext
35// consumes.
36//
37// isSupportedType says which CIR types the bridge handles, and a signature
38// naming any other fails the pass instead of being misclassified.
39//===----------------------------------------------------------------------===//
40
41/// Whether a struct's declared argument-passing kind (from the module's
42/// record-layout metadata) allows it to be passed in registers. A record with
43/// no layout entry (e.g. an anonymous struct) has no C++ non-trivial reason to
44/// be forced to memory, so it defaults to can-pass-in-registers.
45static bool recordCanPassInRegs(ModuleOp modOp, cir::RecordType recTy) {
46 auto layout = cir::tryGetRecordLayout(modOp, recTy.getName());
47 if (!layout)
48 return true;
49 return layout.getArgPassingKind() == cir::ArgPassingKind::CanPassInRegs;
50}
51
52static bool recordIsTransparentUnion(ModuleOp modOp, cir::RecordType recTy) {
53 auto layout = cir::tryGetRecordLayout(modOp, recTy.getName());
54 return layout && layout.getTransparentUnion();
55}
56
57/// Whether the classifier could give this type the SSEUP class, looking
58/// through arrays and records at the types they hold.
59static bool mayReachSseUp(mlir::Type ty, const DataLayout &dl) {
60 // The classifier sizes a vector with its width rounded up to a power of two.
61 if (isa<cir::VectorType>(ty))
62 return llvm::PowerOf2Ceil(dl.getTypeSizeInBits(ty).getFixedValue()) >= 128;
63 if (auto fpTy = dyn_cast<cir::FPTypeInterface>(ty))
64 return &fpTy.getFloatSemantics() == &llvm::APFloat::IEEEquad();
65 if (auto arrTy = dyn_cast<cir::ArrayType>(ty))
66 return mayReachSseUp(arrTy.getElementType(), dl);
67 if (auto recTy = dyn_cast<cir::RecordType>(ty))
68 return recTy.isComplete() &&
69 llvm::any_of(recTy.getMembers(),
70 [&](mlir::Type m) { return mayReachSseUp(m, dl); });
71 // The rest classify integer, SSE or memory. A complex is SSE at float and
72 // double width and memory above that, so it needs no walk of its own.
73 assert((isa<cir::IntType, cir::BoolType, cir::PointerType, cir::VPtrType,
74 cir::VoidType, cir::ComplexType, cir::BitFieldType>(ty)) &&
75 "unhandled type in the SSEUP walk");
76 return false;
77}
78
79/// Whether the record's size has no SSEUP coerce. That coerce is a vector as
80/// wide as the record, so only 128, 256 and 512 bits have one. A record past
81/// 512 bits classifies memory before any coerce is asked for.
82static bool sseUpCoerceSizeUnsupported(uint64_t recordBits,
84 const DataLayout &dl) {
85 if (recordBits == 128 || recordBits == 256 || recordBits == 512)
86 return false;
87 if (recordBits < 128 || recordBits > 512)
88 return false;
89 return llvm::any_of(members,
90 [&](mlir::Type m) { return mayReachSseUp(m, dl); });
91}
92
93/// Whether a member is an empty record, looking through arrays, since an array
94/// of empty records supplies no bytes either.
95static bool memberIsEmptyRecord(mlir::Type ty) {
96 while (auto arrTy = dyn_cast<cir::ArrayType>(ty))
97 ty = arrTy.getElementType();
98 auto recTy = dyn_cast<cir::RecordType>(ty);
99 return recTy && recTy.isEmptyForABI();
100}
101
102/// A record's declared alignment, which the ABI uses for the byval and sret
103/// alignment of an indirect argument. DataLayout derives alignment from the
104/// members, so it cannot see `__attribute__((aligned(N)))`. The declared value
105/// comes from the module's record-layout metadata instead. CIRGen emits an
106/// entry for every record it names, so the computed fallback only serves
107/// hand-written CIR.
108static llvm::Align recordDeclaredAlign(ModuleOp modOp, cir::RecordType recTy,
109 const DataLayout &dl) {
110 auto layout = cir::tryGetRecordLayout(modOp, recTy.getName());
111 if (!layout)
112 return llvm::Align(dl.getTypeABIAlignment(recTy));
113 return llvm::Align(layout.getRecordAlign());
114}
115
116/// A record's unadjusted alignment, the alignment its members give it before
117/// an alignment attribute on the record raises it. Like the declared
118/// alignment, it comes from the module's record-layout metadata, and the
119/// computed fallback only serves hand-written CIR.
120static llvm::Align recordUnadjustedAlign(ModuleOp modOp, cir::RecordType recTy,
121 const DataLayout &dl) {
122 auto layout = cir::tryGetRecordLayout(modOp, recTy.getName());
123 if (!layout)
124 return llvm::Align(dl.getTypeABIAlignment(recTy));
125 return llvm::Align(layout.getUnadjustedAlign());
126}
127
128/// The CIR types the bridge handles. Scalars: an integer up to 128
129/// bits (including `__int128`), a `_BitInt` of any width, pointer, vtable
130/// pointer, bool, void, or any floating-point type. Aggregates: a complete
131/// struct or union whose members are all themselves supported, or an array
132/// of a supported element type. Also a `_Complex`, or a fixed-width vector,
133/// of a supported element type. Everything else is reported NYI at the
134/// reject() choke point in classifySignature.
135static bool isSupportedType(mlir::Type ty, const DataLayout &dl) {
136 // A pointer is only handled in the default address space (null) or an
137 // already-lowered target address space. A LangAddressSpaceAttr must be
138 // lowered before this pass, so reject it rather than silently dropping it.
139 if (auto ptrTy = dyn_cast<cir::PointerType>(ty))
140 return !ptrTy.getAddrSpace() ||
141 mlir::isa<cir::TargetAddressSpaceAttr>(ptrTy.getAddrSpace());
142 // cir::VPtrType carries no address-space parameter yet, so its target
143 // address space cannot be checked here even though it is not always the
144 // default one.
145 if (isa<cir::VPtrType>(ty)) {
147 return true;
148 }
149 if (isa<cir::VoidType, cir::BoolType>(ty))
150 return true;
151 // Every CIR floating-point type carries the semantics the classifier
152 // switches on, so all of them are handled.
153 if (isa<cir::FPTypeInterface>(ty))
154 return true;
155 if (auto intTy = dyn_cast<cir::IntType>(ty)) {
156 // Integers up to 64 bits, __int128, and _BitInt of any width are
157 // handled: the classifier extends a width below 32, widens 33 through 63
158 // to i64, coerces 65 through 127 to a {i64, i64} pair, and passes 32, 64,
159 // and 128 in the natural type. A _BitInt wider than 128 bits classifies
160 // Indirect, the same path an oversized aggregate already takes.
161 // Non-_BitInt intermediate widths (65..127) do not arise from C and stay
162 // rejected.
163 if (intTy.getIsBitInt())
164 return true;
165 return intTy.getWidth() <= 64 || intTy.getWidth() == 128;
166 }
167 if (auto complexTy = dyn_cast<cir::ComplexType>(ty))
168 return isSupportedType(complexTy.getElementType(), dl);
169 if (auto vecTy = dyn_cast<cir::VectorType>(ty)) {
170 // A scalable vector has no fixed size, and no target that classifies
171 // through the bridge passes one yet.
172 if (vecTy.isScalable())
173 return false;
174 // mapCIRType maps a bool as a one-bit integer, so a bool vector is sized
175 // one bit per element, as clang packs it. Vectors of a _BitInt whose
176 // width is not a whole number of bytes are not handled yet.
177 mlir::Type elemTy = vecTy.getElementType();
178 if (auto elemInt = dyn_cast<cir::IntType>(elemTy)) {
179 if (elemInt.getWidth() % 8)
180 return false;
181 } else if (!isa<cir::FPTypeInterface, cir::BoolType>(elemTy)) {
182 return false;
183 }
184 return isSupportedType(elemTy, dl);
185 }
186 if (auto arrTy = dyn_cast<cir::ArrayType>(ty))
187 return isSupportedType(arrTy.getElementType(), dl);
188 // A bit-field is classified from the type it was declared with and the bits
189 // it holds, and is loaded through its access unit, so both types have to be
190 // ones the bridge handles. A zero-width bit-field has no unit of its own.
191 if (auto bfTy = dyn_cast<cir::BitFieldType>(ty)) {
192 if (mlir::Type storageTy = bfTy.getStorageType())
193 if (!isSupportedType(storageTy, dl))
194 return false;
195 return llvm::all_of(bfTy.getFields(), [&](cir::BitFieldDeclAttr decl) {
196 return isSupportedType(decl.getDeclaredType(), dl);
197 });
198 }
199 if (auto recTy = dyn_cast<cir::RecordType>(ty)) {
200 // An incomplete record has no layout to classify.
201 if (!recTy.isComplete())
202 return false;
203 // The members are checked first so that everything below reasons only
204 // about types the bridge handles.
205 if (!llvm::all_of(recTy.getMembers(),
206 [&](mlir::Type m) { return isSupportedType(m, dl); }))
207 return false;
208 if (recTy.isUnion()) {
209 llvm::ArrayRef<mlir::Type> members = recTy.getMembers();
210 uint64_t recordBits = dl.getTypeSizeInBits(recTy).getFixedValue();
211 // Refuse a union that could reach SSEUP at a size no coerce exists for.
212 // The classifier asserts on those rather than returning a coerce.
213 if (sseUpCoerceSizeUnsupported(recordBits, members, dl))
214 return false;
215 // A member-less union is all padding, which classifies Ignore up to two
216 // eightbytes. Past that SysV says MEMORY regardless of content, and
217 // there is no member here to build the Indirect coercion from.
218 if (members.empty() && recordBits > 128)
219 return false;
220 // A `_BitInt` access unit past an eightbyte has byte-array storage in
221 // CIR and integer storage in classic CodeGen, so the narrowing walk
222 // finds an i8 in the second eightbyte where classic keeps an i64.
223 if (llvm::any_of(members, [&](mlir::Type m) {
224 auto bfTy = dyn_cast<cir::BitFieldType>(m);
225 if (!bfTy || dl.getTypeSizeInBits(bfTy).getFixedValue() <= 64)
226 return false;
227 return llvm::any_of(bfTy.getFields(), [](cir::BitFieldDeclAttr d) {
228 auto intTy = dyn_cast<cir::IntType>(d.getDeclaredType());
229 return intTy && intTy.getIsBitInt();
230 });
231 }))
232 return false;
233 } else {
234 // A struct's `empty` member that occupies bytes is later read as an
235 // unnamed bit-field. An empty-for-ABI record occupies its own padding,
236 // and reading that as a unit would hand the classifier storage classic
237 // CodeGen ignores. A zero-sized one is dropped before classification,
238 // so a misaligned one never reaches the rule that sends its record to
239 // memory. A union needs neither rule: mapCIRType skips such a variant
240 // instead of reading it as a unit, and every variant sits at offset
241 // zero.
242 for (auto [idx, memberTy, kind] :
243 llvm::enumerate(recTy.getMembers(), recTy.getMemberKinds())) {
244 if (kind != cir::RecordMemberKind::Empty)
245 continue;
246 if (dl.getTypeSizeInBits(memberTy).getFixedValue()) {
247 if (memberIsEmptyRecord(memberTy))
248 return false;
249 } else if (recTy.getElementOffset(dl, idx) %
250 dl.getTypeABIAlignment(memberTy)) {
251 return false;
252 }
253 }
254 }
255 return true;
256 }
257 return false;
258}
259
260/// Convert an llvm::abi::Type coercion type back to a CIR type.
261static mlir::Type abiTypeToCIR(const llvm::abi::Type *ty, MLIRContext *ctx) {
262 if (!ty)
263 return nullptr;
264 return llvm::TypeSwitch<const llvm::abi::Type *, mlir::Type>(ty)
265 .Case(
266 [&](const llvm::abi::VoidType *) { return cir::VoidType::get(ctx); })
267 .Case([&](const llvm::abi::IntegerType *intTy) -> mlir::Type {
268 // mapCIRType maps a bool as a one-bit integer.
269 if (intTy->isBool())
270 return cir::BoolType::get(ctx);
271 return cir::IntType::get(ctx, intTy->getSizeInBits().getFixedValue(),
272 intTy->isSigned(), intTy->isBitInt());
273 })
274 .Case([&](const llvm::abi::FloatType *fltTy) {
275 return cir::getFloatingPointType(*fltTy->getSemantics(), ctx);
276 })
277 .Case([&](const llvm::abi::PointerType *ptrTy) {
278 auto voidTy = cir::VoidType::get(ctx);
279 if (unsigned as = ptrTy->getAddrSpace())
280 return cir::PointerType::get(
281 voidTy, cir::TargetAddressSpaceAttr::get(ctx, as));
282 return cir::PointerType::get(voidTy);
283 })
284 .Case([&](const llvm::abi::VectorType *vecTy) -> mlir::Type {
285 mlir::Type elemCIR = abiTypeToCIR(vecTy->getElementType(), ctx);
286 if (!elemCIR)
287 return nullptr;
288 return cir::VectorType::getFixed(
289 elemCIR, vecTy->getNumElements().getFixedValue());
290 })
291 .Case([&](const llvm::abi::ArrayType *arrTy) -> mlir::Type {
292 mlir::Type elemCIR = abiTypeToCIR(arrTy->getElementType(), ctx);
293 if (!elemCIR)
294 return nullptr;
295 return cir::ArrayType::get(elemCIR, arrTy->getNumElements());
296 })
297 .Case([&](const llvm::abi::RecordType *recTy) -> mlir::Type {
298 SmallVector<mlir::Type> fieldTypes;
299 fieldTypes.reserve(recTy->getFields().size());
300 for (const auto &field : recTy->getFields()) {
301 mlir::Type fieldCIR = abiTypeToCIR(field.FieldType, ctx);
302 if (!fieldCIR)
303 return nullptr;
304 fieldTypes.push_back(fieldCIR);
305 }
306 // Coercion types are plain register tuples, not the source record.
307 return cir::StructType::get(
308 ctx, fieldTypes, /*packed=*/false,
309 /*is_class=*/false, cir::RecordType::getAllDataKinds(fieldTypes));
310 })
311 .Default([](const llvm::abi::Type *) -> mlir::Type { return nullptr; });
312}
313
314/// Returns \p ty with a LongDoubleType vector element replaced by its
315/// underlying format, which is the element abiTypeToCIR builds for the same
316/// float.
317static mlir::Type unwrapLongDoubleVectorElement(mlir::Type ty) {
318 if (auto vecTy = dyn_cast<cir::VectorType>(ty)) {
319 if (auto longDoubleTy =
320 dyn_cast<cir::LongDoubleType>(vecTy.getElementType()))
321 return cir::VectorType::get(longDoubleTy.getUnderlying(),
322 vecTy.getSize());
323 }
324 return ty;
325}
326
327/// Map a CIR type to an llvm::abi::Type. classifySignature pre-filters
328/// the signature, so only the scalar and struct/array types handled here can
329/// reach this function.
330static const llvm::abi::Type *mapCIRType(mlir::Type type,
331 mlir::abi::ABITypeMapper &typeMapper,
332 const DataLayout &dl, ModuleOp modOp) {
333 llvm::abi::TypeBuilder &tb = typeMapper.getTypeBuilder();
334 return llvm::TypeSwitch<mlir::Type, const llvm::abi::Type *>(type)
335 .Case([&](cir::IntType intTy) {
336 return tb.getIntegerType(intTy.getWidth(),
337 llvm::Align(dl.getTypeABIAlignment(type)),
338 intTy.isSigned(), intTy.getIsBitInt());
339 })
340 .Case([&](cir::PointerType ptrTy) {
341 unsigned addrSpace = 0;
342 if (auto targetAsAttr =
343 dyn_cast_if_present<cir::TargetAddressSpaceAttr>(
344 ptrTy.getAddrSpace()))
345 addrSpace = targetAsAttr.getValue();
346 // Any address-space attribute is a qualifier.
347 bool hasAddressSpaceQualifier = ptrTy.getAddrSpace() != nullptr;
348 return tb.getPointerType(dl.getTypeSizeInBits(type),
349 llvm::Align(dl.getTypeABIAlignment(type)),
350 addrSpace, hasAddressSpaceQualifier);
351 })
352 .Case([&](cir::VPtrType) {
353 // cir::VPtrType carries no address-space parameter yet, so this
354 // always maps into the default one until that gap closes.
356 return tb.getPointerType(dl.getTypeSizeInBits(type),
357 llvm::Align(dl.getTypeABIAlignment(type)));
358 })
359 .Case([&](cir::BoolType) {
360 // A bool is a one-bit integer to the classifier, as QualTypeMapper
361 // maps it, so a bool vector is sized one bit per element.
362 return tb.getIntegerType(1, llvm::Align(dl.getTypeABIAlignment(type)),
363 /*Signed=*/false);
364 })
365 .Case([&](cir::VoidType) { return tb.getVoidType(); })
366 .Case([&](cir::FPTypeInterface fpTy) {
367 // LongDoubleType reports its underlying format's semantics, so the
368 // classifier sees x87 or IEEE quad rather than the wrapper.
369 return tb.getFloatType(fpTy.getFloatSemantics(),
370 llvm::Align(dl.getTypeABIAlignment(type)));
371 })
372 .Case([&](cir::ComplexType complexTy) {
373 return tb.getComplexType(
374 mapCIRType(complexTy.getElementType(), typeMapper, dl, modOp),
375 llvm::Align(dl.getTypeABIAlignment(type)));
376 })
377 .Case([&](cir::VectorType vecTy) {
378 // isSupportedType rejects a scalable vector, so the element count is
379 // always fixed here.
380 return tb.getVectorType(
381 mapCIRType(vecTy.getElementType(), typeMapper, dl, modOp),
382 vecTy.getSize(), llvm::Align(dl.getTypeABIAlignment(type)));
383 })
384 .Case([&](cir::ArrayType arrTy) {
385 const llvm::abi::Type *elemAbi =
386 mapCIRType(arrTy.getElementType(), typeMapper, dl, modOp);
387 return tb.getArrayType(elemAbi, arrTy.getSize(),
388 dl.getTypeSizeInBits(type).getFixedValue());
389 })
390 .Case([&](cir::RecordType recTy) -> const llvm::abi::Type * {
391 llvm::abi::RecordFlags flags = llvm::abi::RecordFlags::None;
392 if (recordCanPassInRegs(modOp, recTy))
393 flags = flags | llvm::abi::RecordFlags::CanPassInRegisters;
394 if (recordIsTransparentUnion(modOp, recTy))
395 flags = flags | llvm::abi::RecordFlags::IsTransparent;
396 llvm::TypeSize sizeBits = llvm::TypeSize::getFixed(
397 dl.getTypeSizeInBits(type).getFixedValue());
398 llvm::Align align = recordDeclaredAlign(modOp, recTy, dl);
399 llvm::Align unadjustedAlign = recordUnadjustedAlign(modOp, recTy, dl);
400
401 // Mapped with no fields, an empty record reaches Ignore on its own.
402 // The size still matters, since a target may pass a large empty
403 // record in memory whatever its content.
404 if (recTy.isEmptyForABI())
405 return tb.getRecordType(
406 /*Fields=*/{}, sizeBits, align, unadjustedAlign,
407 llvm::abi::StructPacking::Default,
408 /*BaseClasses=*/{}, /*VirtualBaseClasses=*/{}, flags);
409
411 fields.reserve(recTy.getMembers().size());
412
413 // The classifier reads one entry per source bit-field, so a unit is
414 // spread back out into the fields it holds. The targets classified
415 // here are little-endian, so the unit's first byte holds the first of
416 // them, and the rest follow at the widths ahead of them.
417 //
418 // A coercion for a register is built from the type at the first byte
419 // the register holds, where the unit's first field sits, so that
420 // field's entry carries the unit rather than its own declared type.
421 // The bits holding user data are a separate question, and the answer
422 // is the extent of the type each field was declared with, which the
423 // classifier reads through to decide whether a narrower coercion
424 // would drop something. One entry cannot answer both, so a unit
425 // narrower than its first field's declaration takes an extra entry for
426 // that declaration, holding no bits of its own. A zero-width
427 // bit-field has no unit and so contributes only the declaration.
428 //
429 // A width of zero is how the classifier recognizes the entries that
430 // take no part in assigning register classes, so the width goes
431 // through as declared.
432 auto addAccessUnit = [&](cir::BitFieldType bfTy,
433 uint64_t unitOffsetBits) {
434 mlir::Type unitTy = bfTy.getStorageType();
435 uint64_t unitBits =
436 unitTy ? dl.getTypeSizeInBits(unitTy).getFixedValue() : 0;
437 for (auto [idx, decl] : llvm::enumerate(bfTy.getFields())) {
438 const uint64_t offsetBits =
439 unitOffsetBits + bfTy.getFieldBitOffset(idx);
440 const bool holdsUnit = idx == 0 && unitTy;
441 if (holdsUnit)
442 fields.push_back(llvm::abi::FieldInfo(
443 mapCIRType(unitTy, typeMapper, dl, modOp), offsetBits,
444 /*IsBitField=*/true, decl.getWidth(),
445 /*IsUnnamedBitField=*/decl.getIsUnnamed()));
446 mlir::Type declaredTy = decl.getDeclaredType();
447 if (!holdsUnit ||
448 dl.getTypeSizeInBits(declaredTy).getFixedValue() > unitBits)
449 fields.push_back(llvm::abi::FieldInfo(
450 mapCIRType(declaredTy, typeMapper, dl, modOp), offsetBits,
451 /*IsBitField=*/true, holdsUnit ? 0 : decl.getWidth(),
452 /*IsUnnamedBitField=*/holdsUnit || decl.getIsUnnamed()));
453 }
454 };
455
456 // The size passed here spans the tail padding, so the classifier
457 // covers the whole union rather than just the member it reduces the
458 // union to.
459 if (recTy.isUnion()) {
460 // Classify only the variants that supply data, judged by each
461 // variant's own storage rather than by its mark. One supplying
462 // none is skipped so it does not appear as a spurious argument.
463 // Whether the record is empty at all is settled from the marks
464 // before this. Every variant starts at offset zero, so a
465 // bit-field variant needs no offset of its own.
466 assert(!llvm::is_contained(recTy.getMemberKinds(),
467 cir::RecordMemberKind::Pad) &&
468 "a union member cannot be marked pad");
469 for (mlir::Type variantTy : recTy.getMembers()) {
470 if (auto bfTy = dyn_cast<cir::BitFieldType>(variantTy)) {
471 // A variant that is an unnamed bit-field holds data all the
472 // same, so it is flagged rather than skipped, as in the struct
473 // path below.
474 addAccessUnit(bfTy, /*unitOffsetBits=*/0);
475 continue;
476 }
477 if (dl.getTypeSizeInBits(variantTy).getFixedValue() == 0 ||
478 memberIsEmptyRecord(variantTy))
479 continue;
480 fields.push_back(llvm::abi::FieldInfo(
481 mapCIRType(variantTy, typeMapper, dl, modOp)));
482 }
483 return tb.getUnionType(fields, sizeBits, align, unadjustedAlign,
484 llvm::abi::StructPacking::Default, flags);
485 }
486
487 // Padding is dropped, so the classifier sees its bytes as holding
488 // nothing, while the record's full size set above still spans them. An
489 // unnamed bit-field is flagged rather than dropped, since classic
490 // CodeGen ignores it when assigning register classes but counts it
491 // when choosing the coerce type, and a member's presence alone cannot
492 // say both.
493 for (auto [idx, fieldTy, kind] :
494 llvm::enumerate(recTy.getMembers(), recTy.getMemberKinds())) {
495 if (kind == cir::RecordMemberKind::Pad)
496 continue;
497 if (auto bfTy = dyn_cast<cir::BitFieldType>(fieldTy)) {
498 addAccessUnit(bfTy, recTy.getElementOffset(dl, idx) * 8);
499 continue;
500 }
501 // An `empty` member that is not a bit-field still stands for bytes
502 // no field of the source reads, so it is flagged the same way.
503 bool isUnnamed = kind == cir::RecordMemberKind::Empty;
504 uint64_t widthBits = dl.getTypeSizeInBits(fieldTy).getFixedValue();
505 if (isUnnamed && widthBits == 0)
506 continue;
507 assert((!isUnnamed || !memberIsEmptyRecord(fieldTy)) &&
508 "an empty-for-ABI member must not reach the classifier as an "
509 "unnamed bit-field");
510 fields.push_back(llvm::abi::FieldInfo(
511 mapCIRType(fieldTy, typeMapper, dl, modOp),
512 recTy.getElementOffset(dl, idx) * 8,
513 /*IsBitField=*/isUnnamed, isUnnamed ? widthBits : 0,
514 /*IsUnnamedBitField=*/isUnnamed));
515 }
516
517 return tb.getRecordType(fields, sizeBits, align, unadjustedAlign,
518 llvm::abi::StructPacking::Default,
519 /*BaseClasses=*/{}, /*VirtualBaseClasses=*/{},
520 flags);
521 })
522 .Default([](mlir::Type) -> const llvm::abi::Type * {
523 llvm_unreachable(
524 "mapCIRType: type not pre-filtered by classifySignature");
525 });
526}
527
528#ifndef NDEBUG
529/// Whether \p coercedAbiTy holds the same value as the scalar \p origTy: an
530/// integer of the same width, a float with the same semantics, or a pointer.
531/// Used only in an assert in convertDirectArgInfo.
532static bool coerceKeepsScalarValue(mlir::Type origTy,
533 const llvm::abi::Type *coercedAbiTy) {
534 if (auto intTy = dyn_cast<cir::IntType>(origTy)) {
535 const auto *abiInt = dyn_cast<llvm::abi::IntegerType>(coercedAbiTy);
536 return abiInt &&
537 abiInt->getSizeInBits().getFixedValue() == intTy.getWidth();
538 }
539 if (isa<cir::BoolType>(origTy))
540 return isa<llvm::abi::IntegerType>(coercedAbiTy);
541 if (auto fpTy = dyn_cast<cir::FPTypeInterface>(origTy)) {
542 const auto *abiFloat = dyn_cast<llvm::abi::FloatType>(coercedAbiTy);
543 return abiFloat && abiFloat->getSemantics() == &fpTy.getFloatSemantics();
544 }
545 if (isa<cir::PointerType, cir::VPtrType>(origTy))
546 return isa<llvm::abi::PointerType>(coercedAbiTy);
547 return false;
548}
549#endif
550
551/// Convert a Direct llvm::abi::ArgInfo. A null coercedType in the result
552/// means the value is passed unchanged in its own type. Otherwise the
553/// rewriter converts the value to coercedType, and when that is a struct and
554/// canFlatten is set, passes each field of the struct as a separate argument.
555static mlir::FailureOr<ArgClassification>
556convertDirectArgInfo(const llvm::abi::ArgInfo &info, MLIRContext *ctx,
557 mlir::Type origTy) {
558 assert(origTy && "a Direct value must have a type");
559 unsigned offset = info.getDirectOffset();
560 llvm::MaybeAlign align = info.getDirectAlign();
561 auto passUnchanged = [&] {
562 return ArgClassification::getDirect(/*coerced=*/nullptr, /*offset=*/0,
563 align);
564 };
565 auto passCoerced = [&](mlir::Type coerced, unsigned coercedOffset) {
566 ArgClassification classified =
567 ArgClassification::getDirect(coerced, coercedOffset, align);
568 classified.canFlatten = info.getCanBeFlattened();
569 return classified;
570 };
571
572 const llvm::abi::Type *coercedAbiTy = info.getCoerceToType();
573 if (!coercedAbiTy) {
574 // A struct the classifier allows to be flattened is coerced to its own
575 // type, so that its fields are passed as separate arguments.
576 auto recTy = dyn_cast<cir::RecordType>(origTy);
577 if (recTy && recTy.isStruct() && info.getCanBeFlattened())
578 return passCoerced(recTy, /*offset=*/0);
579 return passUnchanged();
580 }
581
582 // A nonzero offset means the value's data starts that many bytes into its
583 // storage. The rewriter has no implementation of an offset for a coerced
584 // struct, either when it passes the struct's fields as separate arguments
585 // or when it fetches the struct in va_arg, so this is reported as NYI.
586 bool coercedIsStruct = isa<llvm::abi::RecordType>(coercedAbiTy);
587 if (offset && coercedIsStruct)
588 return mlir::failure();
589
590 // A scalar at byte 0 that is not split into a struct is coerced when the
591 // classifier names a wider integer or a pointer in another address space.
592 // Otherwise the classifier names a type of the same kind and width, and the
593 // scalar passes unchanged. The coerce type is not compared with the
594 // scalar's own in CIR, since converting it to CIR loses a long double's
595 // wrapper and a pointer's pointee.
596 bool isScalar =
597 !isa<cir::VectorType, cir::RecordType, cir::ArrayType, cir::ComplexType>(
598 origTy);
599 if (isScalar && !offset && !coercedIsStruct) {
600 auto origPtr = dyn_cast<cir::PointerType>(origTy);
601 const auto *coercedAbiPtr = dyn_cast<llvm::abi::PointerType>(coercedAbiTy);
602 if (origPtr && coercedAbiPtr) {
603 // Compare numbers, since an explicit address_space(0) keeps a
604 // target_address_space(0) attribute that a plain pointer lacks.
605 auto origAS = dyn_cast_if_present<cir::TargetAddressSpaceAttr>(
606 origPtr.getAddrSpace());
607 if (coercedAbiPtr->getAddrSpace() == (origAS ? origAS.getValue() : 0))
608 return passUnchanged();
609 auto coercedPtr = cast<cir::PointerType>(abiTypeToCIR(coercedAbiTy, ctx));
610 return passCoerced(cir::PointerType::get(origPtr.getPointee(),
611 coercedPtr.getAddrSpace()),
612 /*offset=*/0);
613 }
614 auto origInt = dyn_cast<cir::IntType>(origTy);
615 const auto *coercedAbiInt = dyn_cast<llvm::abi::IntegerType>(coercedAbiTy);
616 bool widensInt =
617 origInt && coercedAbiInt &&
618 coercedAbiInt->getSizeInBits().getFixedValue() > origInt.getWidth();
619 if (!widensInt) {
620 // FIXME: A coerce type that changes the scalar's kind or width should
621 // be handled like a wider integer. The scalar is coerced to
622 // abiTypeToCIR(coercedAbiTy), which the rewriter emits as a store of
623 // the scalar and a load of the coerce type from the same memory.
624 assert(coerceKeepsScalarValue(origTy, coercedAbiTy) &&
625 "the classifier changed a scalar's kind or width");
626 return passUnchanged();
627 }
628 }
629
630 mlir::Type coerced = abiTypeToCIR(coercedAbiTy, ctx);
631 if (!coerced)
632 return mlir::failure();
633 if (coerced == unwrapLongDoubleVectorElement(origTy)) {
634 // ArgClassification has no way to represent a coercion to the value's own
635 // type at an offset, since a coerced type equal to the value's own type
636 // is treated as no coercion. This is reported as NYI.
637 if (offset)
638 return mlir::failure();
639 // A vector the classifier passes as itself needs no rewrite.
640 if (isa<cir::VectorType>(origTy))
641 return passUnchanged();
642 }
643 // An aggregate or _Complex is unpacked into the registers the coerced type
644 // describes. A vector or scalar is reinterpreted as the coerced type.
645 return passCoerced(coerced, offset);
646}
647
648/// Convert an llvm::abi::ArgInfo into the ArgClassification consumed by
649/// CIRABIRewriteContext. Returns failure when the classifier picks a
650/// coercion this bridge cannot represent, which the caller reports as NYI.
651static mlir::FailureOr<ArgClassification>
652convertABIArgInfo(const llvm::abi::ArgInfo &info, MLIRContext *ctx,
653 mlir::Type origTy) {
654 if (info.isDirect())
655 return convertDirectArgInfo(info, ctx, origTy);
656 // An extended value is always read from byte 0 of its own storage, so
657 // there is no offset to honor here.
658 if (info.isExtend()) {
659 assert(origTy && "an extended value must have a type");
660 if (isa<cir::BoolType>(origTy))
661 return ArgClassification::getExtend(nullptr, info.isSignExt());
662 assert((isa<cir::IntType, cir::RecordType>(origTy)) &&
663 "Extend is only expected for integers, bool, and transparent "
664 "unions");
665 mlir::Type extendedTy = abiTypeToCIR(info.getCoerceToType(), ctx);
666 return ArgClassification::getExtend(extendedTy, info.isSignExt());
667 }
668 if (info.isIndirect())
669 return ArgClassification::getIndirect(info.getIndirectAlign(),
670 info.getIndirectByVal(),
671 info.getIndirectAddrSpace());
672 if (info.isIndirectAliased())
673 return ArgClassification::getIndirectAliased(info.getIndirectAlign(),
674 info.getIndirectAddrSpace());
675 // AArch64 pure scalable aggregates use CoerceAndExpand, but they aren't
676 // supported yet.
677 assert(!info.isCoerceAndExpand() && "CoerceAndExpand is not handled yet");
678 assert(info.isIgnore() && "Unexpected classification");
679 return ArgClassification::getIgnore();
680}
681
682/// Where \p fnTy's declared parameters end and its ellipsis arguments begin.
683static llvm::abi::RequiredArgs requiredArgs(cir::FuncType fnTy) {
684 if (!fnTy.isVarArg())
685 return llvm::abi::RequiredArgs::All;
686 return llvm::abi::RequiredArgs(fnTy.getNumInputs());
687}
688
689/// Classify a signature (return type + argument types) using the LLVM ABI
690/// library. Shared by the cir.func path, the variadic-call path and the
691/// indirect-call path (the latter classifies from the callee function
692/// pointer's pointee FuncType). \p required marks where the declared
693/// parameters in \p inputs end. The classifier treats every argument past that
694/// point as passed through an ellipsis. \p callConv is the calling convention
695/// the signature is classified under. Returns failure and emits an NYI
696/// error via \p emitError if the signature uses a type the bridge does not
697/// handle yet.
698mlir::FailureOr<FunctionClassification>
699CIRABIClassifierCommon::classifySignature(
700 mlir::Type retCIR, mlir::TypeRange inputs, llvm::abi::RequiredArgs required,
701 const llvm::abi::TargetInfo &targetInfo, llvm::CallingConv::ID callConv,
702 llvm::function_ref<mlir::InFlightDiagnostic()> emitError) {
703 assert(retCIR && "signature return type must be non-null");
704 assert((!required.allowsOptionalArgs() ||
705 required.getNumRequiredArgs() <= inputs.size()) &&
706 "declared parameters cannot outnumber the classified arguments");
707 MLIRContext *ctx = modOp->getContext();
708 bool voidRet = isa<cir::VoidType>(retCIR);
709
710 auto reject = [&](mlir::Type t) -> bool {
711 if (isSupportedType(t, dl))
712 return false;
713 emitError() << "calling-convention lowering not yet implemented for type "
714 << t;
715 return true;
716 };
717 if (!voidRet && reject(retCIR))
718 return mlir::failure();
719 for (mlir::Type a : inputs)
720 if (reject(a))
721 return mlir::failure();
722
723 const llvm::abi::Type *retAbi =
724 voidRet ? typeMapper.getTypeBuilder().getVoidType()
725 : mapCIRType(retCIR, typeMapper, dl, modOp);
726 SmallVector<const llvm::abi::Type *> argAbi;
727 for (mlir::Type a : inputs)
728 argAbi.push_back(mapCIRType(a, typeMapper, dl, modOp));
729
730 std::unique_ptr<llvm::abi::FunctionInfo> fi =
731 llvm::abi::FunctionInfo::create(callConv, retAbi, argAbi, required);
732 targetInfo.computeInfo(*fi);
733
734 // convertABIArgInfo returns failure when the classifier picks a coercion this
735 // bridge cannot represent.
736 auto nyiCoercion = [&](mlir::Type t) {
737 emitError() << "calling-convention lowering not yet "
738 "implemented for the ABI coercion of type "
739 << t;
740 };
741
742 FunctionClassification fc;
743 fc.returnsVoid = voidRet;
744 mlir::Type origRet = voidRet ? mlir::Type() : retCIR;
745 mlir::FailureOr<ArgClassification> retAc =
746 convertABIArgInfo(fi->getReturnInfo(), ctx, origRet);
747 if (failed(retAc)) {
748 nyiCoercion(retCIR);
749 return mlir::failure();
750 }
751 fc.returnInfo = *retAc;
752 for (unsigned i = 0, e = fi->arg_size(); i < e; ++i) {
753 mlir::Type origArg = inputs[i];
754 const llvm::abi::ArgInfo &argInfo = fi->getArgInfo(i).Info;
755 mlir::FailureOr<ArgClassification> ac =
756 convertABIArgInfo(argInfo, ctx, origArg);
757 if (failed(ac)) {
758 nyiCoercion(origArg);
759 return mlir::failure();
760 }
761 // The classifier passes a transparent union as its first member, and
762 // names no coerce type when it passes that member as its own type.
763 auto recTy = dyn_cast<cir::RecordType>(origArg);
764 if (ac->kind == ArgKind::Direct && !ac->coercedType && recTy &&
766 ac->coercedType = recTy.getMembers().front();
767 ac->neededIntRegs = argInfo.getNeededIntRegs();
768 ac->neededSseRegs = argInfo.getNeededSseRegs();
769 fc.argInfos.push_back(*ac);
770 }
771 return fc;
772}
773
774/// FIXME: Only the AMDGPU kernel convention is mapped. Every other convention
775/// is classified as C.
776llvm::CallingConv::ID cir::convertCallingConv(cir::CallingConv cc) {
777 if (cc == cir::CallingConv::AMDGPUKernel)
778 return llvm::CallingConv::AMDGPU_KERNEL;
779 return llvm::CallingConv::C;
780}
781
782/// Classify a cir.func using the LLVM ABI library. Returns failure and
783/// emits an NYI error if the signature uses a type the bridge does not handle
784/// yet.
785mlir::FailureOr<FunctionClassification>
787 cir::FuncType fnTy = func.getFunctionType();
788 return classifySignature(fnTy.getReturnType(), fnTy.getInputs(),
789 requiredArgs(fnTy), getTargetInfo(func),
790 convertCallingConv(func.getCallingConv()),
791 [&]() { return func.emitOpError(); });
792}
793
794/// Classify the single type fetched by a `cir.va_arg` as an unnamed argument
795/// (RequiredArgs(0)) with a full register budget. Returns failure and
796/// emits an NYI error if the type is not one this bridge handles.
797mlir::FailureOr<ArgClassification> CIRABIClassifierCommon::classifyVarArgType(
798 mlir::Type ty, const llvm::abi::TargetInfo &targetInfo,
799 llvm::function_ref<mlir::InFlightDiagnostic()> emitError) {
800 MLIRContext *ctx = modOp->getContext();
801 mlir::FailureOr<FunctionClassification> fc = classifySignature(
802 cir::VoidType::get(ctx), mlir::TypeRange(ty), llvm::abi::RequiredArgs(0),
803 targetInfo, llvm::CallingConv::C, emitError);
804 if (failed(fc))
805 return mlir::failure();
806 return fc->argInfos[0];
807}
808
809/// Classify a call that passes arguments through an ellipsis. The callee's
810/// own classification covers only its declared parameters, but an ellipsis
811/// argument competes for the same argument registers as a declared one, so
812/// what the ABI does with it depends on the whole argument list: the same
813/// small struct is passed in registers early in the list and in memory once
814/// the integer registers are gone. Classifying from the call's operands
815/// rather than the callee's signature is what makes that accounting right.
816mlir::FailureOr<FunctionClassification>
818 cir::CIRCallOpInterface call, cir::FuncType calleeTy,
819 const llvm::abi::TargetInfo &targetInfo, llvm::CallingConv::ID callConv) {
820 assert(calleeTy.isVarArg() &&
821 "only a variadic callee can take more operands than it declares");
822 Operation *op = call.getOperation();
823 return classifySignature(calleeTy.getReturnType(),
824 call.getArgOperands().getTypes(),
825 requiredArgs(calleeTy), targetInfo, callConv,
826 [&]() { return op->emitOpError(); });
827}
828
829mlir::FailureOr<FunctionClassification>
831 cir::FuncOp callee) {
832 return classifyVariadicCall(call, callee.getFunctionType(),
833 getTargetInfo(callee),
834 convertCallingConv(callee.getCallingConv()));
835}
836
837mlir::FailureOr<FunctionClassification>
838CIRABIClassifierCommon::classifyIndirectCall(cir::CIRCallOpInterface call) {
839 cir::FuncType funcTy = getIndirectCalleeType(call);
840 const llvm::abi::TargetInfo &targetInfo =
841 getTargetInfo(call->getParentOfType<cir::FuncOp>());
842 // An indirect callee is an ordinary function pointer, so it uses the C
843 // convention.
844 if (call.getNumArgOperands() > funcTy.getNumInputs())
845 return classifyVariadicCall(call, funcTy, targetInfo, llvm::CallingConv::C);
846 return classifySignature(
847 funcTy.getReturnType(), funcTy.getInputs(), requiredArgs(funcTy),
848 targetInfo, llvm::CallingConv::C, [&]() { return call->emitOpError(); });
849}
850
851/// Record on \p fc whether \p returnType is CIR's void. classifySignature
852/// answers this itself, but the other two drivers cannot: the test target is
853/// dialect-neutral and has no notion of CIR's void, and the
854/// classification-attr schema carries no return type at all. Both route
855/// through here so a classification always reaches needsRewrite paired with
856/// the return type it was built from.
857static mlir::FailureOr<FunctionClassification>
858withReturnVoidness(mlir::FailureOr<FunctionClassification> fc,
859 mlir::Type returnType) {
860 if (succeeded(fc))
861 fc->returnsVoid = mlir::isa<cir::VoidType>(returnType);
862 return fc;
863}
864
865/// Classify \p func using whichever driver mode is configured. Returns
866/// failure and emits an error on the function if classification fails
867/// (e.g. injection-driver mode but the function is missing the attribute,
868/// or the attribute is malformed).
869static mlir::FailureOr<FunctionClassification>
870classifyFunction(cir::FuncOp func, const DataLayout &dl,
871 cir::CallConvTarget target, StringRef classificationAttrName) {
872 ArrayRef<Type> argTypes = func.getFunctionType().getInputs();
873 Type returnType = func.getFunctionType().getReturnType();
874
875 if (!classificationAttrName.empty()) {
876 auto attr = func->getAttrOfType<DictionaryAttr>(classificationAttrName);
877 if (!attr) {
878 func.emitOpError()
879 << "missing classification attribute '" << classificationAttrName
880 << "' (CallConvLowering driver mode 'classification-attr')";
881 return mlir::failure();
882 }
883 return withReturnVoidness(mlir::abi::test::parseClassificationAttr(
884 attr, [&]() { return func.emitOpError(); }),
885 returnType);
886 }
887
888 // The x86_64 and AMDGPU targets classify through CIRABIClassifierCommon, so
889 // only the test target reaches here.
890 assert(target == cir::CallConvTarget::Test &&
891 "classifyFunction only handles the test target");
892 return withReturnVoidness(mlir::abi::test::classify(argTypes, returnType, dl),
893 returnType);
894}
895
896namespace {
897
898/// Classifies with the MLIR test ABI target: predictable rules that
899/// approximate x86_64 SysV, used by tests that need a target-independent
900/// driver.
901class TestTargetClassifier final : public CIRABIClassifier {
902public:
903 explicit TestTargetClassifier(const mlir::DataLayout &dl) : dl(dl) {}
904
905 mlir::FailureOr<FunctionClassification>
906 classifyFunction(cir::FuncOp func) final {
907 return ::classifyFunction(func, dl, cir::CallConvTarget::Test,
908 /*classificationAttrName=*/"");
909 }
910
911 /// The test target classifies only declared parameters.
912 mlir::FailureOr<FunctionClassification>
913 classifyVariadicCall(cir::CIRCallOpInterface call, cir::FuncOp) final {
914 call->emitOpError()
915 << "variadic arguments not yet implemented in CallConvLowering";
916 return mlir::failure();
917 }
918
919 mlir::FailureOr<FunctionClassification>
920 classifyIndirectCall(cir::CIRCallOpInterface call) final {
921 cir::FuncType funcTy = getIndirectCalleeType(call);
922 if (call.getNumArgOperands() > funcTy.getNumInputs()) {
923 call->emitOpError()
924 << "variadic arguments not yet implemented in CallConvLowering";
925 return mlir::failure();
926 }
927 return withReturnVoidness(mlir::abi::test::classify(funcTy.getInputs(),
928 funcTy.getReturnType(),
929 dl),
930 funcTy.getReturnType());
931 }
932
933 mlir::FailureOr<ArgClassification> classifyVAArg(cir::VAArgOp vaArg) final {
934 vaArg->emitOpError()
935 << "not yet implemented in CallConvLowering for the test target";
936 return mlir::failure();
937 }
938
939private:
940 const mlir::DataLayout &dl;
941};
942
943/// Reads a pre-built classification from a function attribute, so a test can
944/// inject any classification (including shapes no target produces) without
945/// depending on a real ABI target.
946class InjectedClassifier final : public CIRABIClassifier {
947public:
948 InjectedClassifier(const mlir::DataLayout &dl, llvm::StringRef attrName)
949 : dl(dl), attrName(attrName) {}
950
951 mlir::FailureOr<FunctionClassification>
952 classifyFunction(cir::FuncOp func) final {
953 return ::classifyFunction(func, dl, cir::CallConvTarget::None, attrName);
954 }
955
956 /// The injected classification covers a function's declared parameters, so
957 /// it cannot describe an operand passed through an ellipsis.
958 mlir::FailureOr<FunctionClassification>
959 classifyVariadicCall(cir::CIRCallOpInterface call, cir::FuncOp) final {
960 call->emitOpError()
961 << "variadic arguments not yet implemented in CallConvLowering";
962 return mlir::failure();
963 }
964
965 /// Nor can it describe a callee resolved at run time, which names no
966 /// function to read the attribute from.
967 mlir::FailureOr<FunctionClassification>
968 classifyIndirectCall(cir::CIRCallOpInterface call) final {
969 call->emitOpError() << "indirect call cannot be classified in the "
970 "'classification-attr' driver mode";
971 return mlir::failure();
972 }
973
974 mlir::FailureOr<ArgClassification> classifyVAArg(cir::VAArgOp vaArg) final {
975 vaArg->emitOpError() << "cannot be classified in the "
976 "'classification-attr' driver mode";
977 return mlir::failure();
978 }
979
980private:
981 const mlir::DataLayout &dl;
982 std::string attrName;
983};
984
985} // namespace
986
987std::unique_ptr<CIRABIClassifier>
988cir::createTestTargetABIClassifier(const mlir::DataLayout &dl) {
989 return std::make_unique<TestTargetClassifier>(dl);
990}
991
992std::unique_ptr<CIRABIClassifier>
993cir::createInjectedABIClassifier(const mlir::DataLayout &dl,
994 llvm::StringRef attrName) {
995 return std::make_unique<InjectedClassifier>(dl, attrName);
996}
static bool recordIsTransparentUnion(ModuleOp modOp, cir::RecordType recTy)
static bool memberIsEmptyRecord(mlir::Type ty)
Whether a member is an empty record, looking through arrays, since an array of empty records supplies...
static llvm::Align recordUnadjustedAlign(ModuleOp modOp, cir::RecordType recTy, const DataLayout &dl)
A record's unadjusted alignment, the alignment its members give it before an alignment attribute on t...
static llvm::Align recordDeclaredAlign(ModuleOp modOp, cir::RecordType recTy, const DataLayout &dl)
A record's declared alignment, which the ABI uses for the byval and sret alignment of an indirect arg...
static bool recordCanPassInRegs(ModuleOp modOp, cir::RecordType recTy)
Whether a struct's declared argument-passing kind (from the module's record-layout metadata) allows i...
static mlir::FailureOr< ArgClassification > convertABIArgInfo(const llvm::abi::ArgInfo &info, MLIRContext *ctx, mlir::Type origTy)
Convert an llvm::abi::ArgInfo into the ArgClassification consumed by CIRABIRewriteContext.
static mlir::FailureOr< FunctionClassification > withReturnVoidness(mlir::FailureOr< FunctionClassification > fc, mlir::Type returnType)
Record on fc whether returnType is CIR's void.
static const llvm::abi::Type * mapCIRType(mlir::Type type, mlir::abi::ABITypeMapper &typeMapper, const DataLayout &dl, ModuleOp modOp)
Map a CIR type to an llvm::abi::Type.
static mlir::Type unwrapLongDoubleVectorElement(mlir::Type ty)
Returns ty with a LongDoubleType vector element replaced by its underlying format,...
static bool mayReachSseUp(mlir::Type ty, const DataLayout &dl)
Whether the classifier could give this type the SSEUP class, looking through arrays and records at th...
static llvm::abi::RequiredArgs requiredArgs(cir::FuncType fnTy)
Where fnTy's declared parameters end and its ellipsis arguments begin.
static bool coerceKeepsScalarValue(mlir::Type origTy, const llvm::abi::Type *coercedAbiTy)
Whether coercedAbiTy holds the same value as the scalar origTy: an integer of the same width,...
static mlir::FailureOr< FunctionClassification > classifyFunction(cir::FuncOp func, const DataLayout &dl, cir::CallConvTarget target, StringRef classificationAttrName)
Classify func using whichever driver mode is configured.
static mlir::FailureOr< ArgClassification > convertDirectArgInfo(const llvm::abi::ArgInfo &info, MLIRContext *ctx, mlir::Type origTy)
Convert a Direct llvm::abi::ArgInfo.
static bool sseUpCoerceSizeUnsupported(uint64_t recordBits, llvm::ArrayRef< mlir::Type > members, const DataLayout &dl)
Whether the record's size has no SSEUP coerce.
static bool isSupportedType(mlir::Type ty, const DataLayout &dl)
The CIR types the bridge handles.
static mlir::Type abiTypeToCIR(const llvm::abi::Type *ty, MLIRContext *ctx)
Convert an llvm::abi::Type coercion type back to a CIR type.
*collection of selector each with an associated kind and an ordered *collection of selectors A selector has a kind
mlir::FailureOr< mlir::abi::FunctionClassification > classifyIndirectCall(cir::CIRCallOpInterface call) override
A callee resolved at run time carries no features of its own, so the call is classified at the featur...
mlir::FailureOr< mlir::abi::FunctionClassification > classifyFunction(cir::FuncOp func) override
Classify a cir.func using the LLVM ABI library.
const mlir::DataLayout & dl
mlir::FailureOr< mlir::abi::ArgClassification > classifyVarArgType(mlir::Type ty, const llvm::abi::TargetInfo &targetInfo, llvm::function_ref< mlir::InFlightDiagnostic()> emitError)
Classify ty, the type fetched by a cir.va_arg, as an unnamed argument with every argument register fr...
mlir::FailureOr< mlir::abi::FunctionClassification > classifyVariadicCall(cir::CIRCallOpInterface call, cir::FuncOp callee) override
The call is classified at the callee's features, not the caller's, because the pass rewrites the defi...
virtual const llvm::abi::TargetInfo & getTargetInfo(cir::FuncOp featureSource)=0
The library classifier for a function whose recorded target features may refine the ABI rules.
mlir::abi::ABITypeMapper typeMapper
Produces the classification CallConvLowering rewrites a signature from.
C++ view class that accepts both !cir.struct and !cir.union types.
Definition CIRTypes.h:150
bool isUnion() const
Definition CIRTypes.h:176
bool isEmptyForABI() const
Whether no member holds data.
Definition CIRTypes.cpp:741
llvm::ArrayRef< mlir::Type > getMembers() const
Definition CIRTypes.cpp:648
static llvm::SmallVector< RecordMemberKind > getAllDataKinds(llvm::ArrayRef< mlir::Type > members)
One Data kind per member.
Definition CIRTypes.cpp:151
mlir::StringAttr getName() const
Definition CIRTypes.cpp:653
llvm::ArrayRef< RecordMemberKind > getMemberKinds() const
Definition CIRTypes.cpp:673
uint64_t getElementOffset(const mlir::DataLayout &dataLayout, unsigned idx) const
Definition CIRTypes.cpp:706
RecordLayoutAttr tryGetRecordLayout(mlir::ModuleOp mod, mlir::StringAttr name)
Same lookup as getRecordLayout, but returns a null attribute instead of asserting when the record has...
llvm::CallingConv::ID convertCallingConv(cir::CallingConv cc)
Map a CIR calling convention to the llvm::CallingConv the ABI classifier uses.
cir::FPTypeInterface getFloatingPointType(const llvm::fltSemantics &sem, mlir::MLIRContext *ctx)
Returns the CIR floating-point type for the given semantics, or a null type if CIR has no type for it...
Definition CIRTypes.cpp:43
cir::FuncType getIndirectCalleeType(cir::CIRCallOpInterface call)
The signature the indirect call call reaches its callee through.
std::unique_ptr< CIRABIClassifier > createInjectedABIClassifier(const mlir::DataLayout &dl, llvm::StringRef attrName)
A classifier that reads each function's classification from the DictionaryAttr named attrName.
std::unique_ptr< CIRABIClassifier > createTestTargetABIClassifier(const mlir::DataLayout &dl)
The MLIR test ABI target's classifier, whose predictable rules approximate x86_64 SysV.
CallConvTarget
The ABI target whose calling-convention rules drive CallConvLowering.
Definition Passes.h:23
static bool addressSpace()