1//==---- QualTypeMapper.cpp - Maps Clang QualType to LLVMABI Types ---------==//
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/// \file
10/// Maps Clang QualType instances to corresponding LLVM ABI type
11/// representations. This mapper translates high-level type information from the
12/// AST into low-level ABI-specific types that encode size, alignment, and
13/// layout details required for code generation and cross-language
14/// interoperability.
15///
16//===----------------------------------------------------------------------===//
17#include "QualTypeMapper.h"
18#include "clang/AST/ASTContext.h"
19#include "clang/AST/ASTFwd.h"
20#include "clang/AST/Attr.h"
21#include "clang/AST/Decl.h"
22#include "clang/AST/DeclCXX.h"
23#include "clang/AST/RecordLayout.h"
24#include "clang/AST/Type.h"
25#include "clang/Basic/AddressSpaces.h"
26#include "clang/Basic/LLVM.h"
27#include "clang/Basic/TargetInfo.h"
28#include "llvm/ABI/Types.h"
29#include "llvm/Support/Alignment.h"
30#include "llvm/Support/ErrorHandling.h"
31#include "llvm/Support/TypeSize.h"
32#include <cstdint>
33
34namespace clang {
35namespace CodeGen {
36
37/// Returns true if \p BT is one of the AArch64 SVE predicate types, i.e.
38/// svbool_t or one of its tuples.
39static bool isSVEPredicateBuiltinType(const BuiltinType *BT) {
40 switch (BT->getKind()) {
41#define SVE_PREDICATE_TYPE(Name, MangledName, Id, SingletonId) \
42 case BuiltinType::Id: \
43 return true;
44#include "clang/Basic/AArch64ACLETypes.def"
45 default:
46 return false;
47 }
48}
49
50/// Maps a Clang vector kind onto the ABI library's notion of a vector flavor.
51static llvm::abi::VectorKind getABIVectorKind(clang::VectorKind Kind) {
52 switch (Kind) {
53 case clang::VectorKind::SveFixedLengthData:
54 return llvm::abi::VectorKind::SVEData;
55 case clang::VectorKind::SveFixedLengthPredicate:
56 return llvm::abi::VectorKind::SVEPredicate;
57 default:
58 return llvm::abi::VectorKind::Generic;
59 }
60}
61
62/// Main entry point for converting Clang QualType to LLVM ABI Type.
63/// This method performs type canonicalization, caching, and dispatches
64/// to specialized conversion methods based on the type kind.
65///
66/// \param QT The Clang QualType to convert
67/// \return Corresponding LLVM ABI Type representation
68const llvm::abi::Type *QualTypeMapper::convertType(QualType QT) {
69 // Canonicalize type and strip qualifiers
70 // This ensures consistent type representation across different contexts
71 //
72 // TODO: AttributedType is NeverCanonical, so aligned typedef attributes
73 // for instance, __attribute__((aligned(N))) are lost here. Capture the
74 // effective alignment from the original QT and thread it through
75 // convertTypeImpl.
76 QT = QT.getCanonicalType().getUnqualifiedType();
77
78 // Results are cached since type conversion may be expensive.
79 auto It = TypeCache.find(Val: QT);
80 if (It != TypeCache.end())
81 return It->second;
82
83 const llvm::abi::Type *Result = convertTypeImpl(QT);
84 assert(Result && "convertTypeImpl returned nullptr");
85 TypeCache[QT] = Result;
86 return Result;
87}
88
89/// Dispatches to specialized conversion methods based on the type kind.
90const llvm::abi::Type *QualTypeMapper::convertTypeImpl(QualType QT) {
91 switch (QT->getTypeClass()) {
92 // Non-canonical and dependent types should have been stripped by
93 // getCanonicalType() above or cannot appear during code generation.
94#define TYPE(Class, Base)
95#define ABSTRACT_TYPE(Class, Base)
96#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
97#define DEPENDENT_TYPE(Class, Base) case Type::Class:
98#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class:
99#include "clang/AST/TypeNodes.inc"
100 llvm::reportFatalInternalError(
101 reason: "Non-canonical or dependent types should not reach ABI lowering");
102
103 case Type::Builtin:
104 return convertBuiltinType(BT: cast<BuiltinType>(Val&: QT));
105 case Type::Pointer:
106 return createPointerTypeForPointee(PointeeType: cast<PointerType>(Val&: QT)->getPointeeType());
107 case Type::LValueReference:
108 case Type::RValueReference:
109 return createPointerTypeForPointee(
110 PointeeType: cast<ReferenceType>(Val&: QT)->getPointeeType());
111 case Type::ConstantArray:
112 case Type::ArrayParameter:
113 case Type::IncompleteArray:
114 case Type::VariableArray:
115 return convertArrayType(AT: cast<ArrayType>(Val&: QT));
116 case Type::Vector:
117 case Type::ExtVector:
118 return convertVectorType(VT: cast<VectorType>(Val&: QT));
119 case Type::Record:
120 return convertRecordType(RT: cast<RecordType>(Val&: QT));
121 case Type::Enum:
122 return convertEnumType(ET: cast<EnumType>(Val&: QT));
123 case Type::Complex:
124 return convertComplexType(CT: cast<ComplexType>(Val&: QT));
125 case Type::Atomic: {
126 const auto *AT = cast<AtomicType>(Val&: QT);
127 return Builder.getAtomicType(ValueType: convertType(QT: AT->getValueType()),
128 SizeInBits: ASTCtx.getTypeSize(T: QT), Align: getTypeAlign(QT));
129 }
130 case Type::BlockPointer:
131 case Type::Pipe:
132 return createPointerTypeForPointee(PointeeType: ASTCtx.VoidPtrTy);
133 case Type::ConstantMatrix: {
134 const auto *MT = cast<ConstantMatrixType>(Val&: QT);
135 return Builder.getArrayType(ElementType: convertType(QT: MT->getElementType()),
136 NumElements: MT->getNumRows() * MT->getNumColumns(),
137 SizeInBits: ASTCtx.getTypeSize(T: QT), /*IsMatrixType=*/true);
138 }
139 case Type::MemberPointer:
140 return convertMemberPointerType(MPT: cast<MemberPointerType>(Val&: QT));
141 case Type::BitInt: {
142 const auto *BIT = cast<BitIntType>(Val&: QT);
143 return Builder.getIntegerType(BitWidth: BIT->getNumBits(), Align: getTypeAlign(QT),
144 /*Signed=*/BIT->isSigned(),
145 /*IsBitInt=*/true);
146 }
147 case Type::ObjCObject:
148 case Type::ObjCInterface:
149 case Type::ObjCObjectPointer:
150 // Objective-C objects are represented as pointers in the ABI.
151 return Builder.getPointerType(
152 Size: ASTCtx.getTargetInfo().getPointerWidth(AddrSpace: QT.getAddressSpace()),
153 Align: llvm::Align(
154 ASTCtx.getTargetInfo().getPointerAlign(AddrSpace: QT.getAddressSpace()) / 8),
155 Addrspace: ASTCtx.getTargetInfo().getTargetAddressSpace(AS: QT.getAddressSpace()));
156 case Type::OverflowBehavior:
157 return convertType(QT: cast<OverflowBehaviorType>(Val&: QT)->getUnderlyingType());
158 case Type::Auto:
159 case Type::DeducedTemplateSpecialization:
160 case Type::FunctionProto:
161 case Type::FunctionNoProto:
162 case Type::HLSLAttributedResource:
163 case Type::HLSLInlineSpirv:
164 llvm::reportFatalInternalError(reason: "Type not supported in ABI lowering");
165 }
166 llvm_unreachable("unhandled type class in convertTypeImpl");
167}
168
169/// Converts C/C++ builtin types to LLVM ABI types.
170/// This handles all fundamental scalar types including integers, floats,
171/// and special types like void and bool.
172const llvm::abi::Type *
173QualTypeMapper::convertBuiltinType(const BuiltinType *BT) {
174 QualType QT(BT, 0);
175
176 switch (BT->getKind()) {
177 case BuiltinType::Void:
178 return Builder.getVoidType();
179
180 case BuiltinType::NullPtr:
181 return createPointerTypeForPointee(PointeeType: QT);
182
183 case BuiltinType::Bool:
184 return Builder.getIntegerType(BitWidth: 1, Align: getTypeAlign(QT), /*Signed=*/false,
185 /*IsBitInt=*/false);
186
187 case BuiltinType::MetaInfo:
188 llvm::reportFatalInternalError(reason: "std::meta::info is consteval-only type");
189
190 case BuiltinType::Char_S:
191 case BuiltinType::Char_U:
192 case BuiltinType::SChar:
193 case BuiltinType::UChar:
194 case BuiltinType::WChar_S:
195 case BuiltinType::WChar_U:
196 case BuiltinType::Char8:
197 case BuiltinType::Char16:
198 case BuiltinType::Char32:
199 case BuiltinType::Short:
200 case BuiltinType::UShort:
201 case BuiltinType::Int:
202 case BuiltinType::UInt:
203 case BuiltinType::Long:
204 case BuiltinType::ULong:
205 case BuiltinType::LongLong:
206 case BuiltinType::ULongLong:
207 case BuiltinType::Int128:
208 case BuiltinType::UInt128:
209 return Builder.getIntegerType(BitWidth: ASTCtx.getTypeSize(T: QT), Align: getTypeAlign(QT),
210 /*Signed=*/BT->isSignedInteger(),
211 /*IsBitInt=*/false);
212
213 case BuiltinType::Half:
214 case BuiltinType::Float16:
215 case BuiltinType::BFloat16:
216 case BuiltinType::Float:
217 case BuiltinType::Double:
218 case BuiltinType::LongDouble:
219 case BuiltinType::Float128:
220 return Builder.getFloatType(Semantics: ASTCtx.getFloatTypeSemantics(T: QT),
221 Align: getTypeAlign(QT));
222
223 // TODO: IBM 128-bit extended double
224 case BuiltinType::Ibm128:
225 llvm::reportFatalInternalError(
226 reason: "IBM128 is not yet supported in the ABI lowering libary");
227
228 // TODO: Fixed-point types
229 case BuiltinType::ShortAccum:
230 case BuiltinType::Accum:
231 case BuiltinType::LongAccum:
232 case BuiltinType::UShortAccum:
233 case BuiltinType::UAccum:
234 case BuiltinType::ULongAccum:
235 case BuiltinType::ShortFract:
236 case BuiltinType::Fract:
237 case BuiltinType::LongFract:
238 case BuiltinType::UShortFract:
239 case BuiltinType::UFract:
240 case BuiltinType::ULongFract:
241 case BuiltinType::SatShortAccum:
242 case BuiltinType::SatAccum:
243 case BuiltinType::SatLongAccum:
244 case BuiltinType::SatUShortAccum:
245 case BuiltinType::SatUAccum:
246 case BuiltinType::SatULongAccum:
247 case BuiltinType::SatShortFract:
248 case BuiltinType::SatFract:
249 case BuiltinType::SatLongFract:
250 case BuiltinType::SatUShortFract:
251 case BuiltinType::SatUFract:
252 case BuiltinType::SatULongFract:
253 llvm::reportFatalInternalError(
254 reason: "Fixed Point types not yet implemented in the ABI lowering library");
255
256 // OpenCL image types are represented as opaque pointers.
257#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
258 case BuiltinType::Id:
259#include "clang/Basic/OpenCLImageTypes.def"
260 // OpenCL extension types are represented as opaque pointers.
261#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) case BuiltinType::Id:
262#include "clang/Basic/OpenCLExtensionTypes.def"
263 case BuiltinType::OCLSampler:
264 case BuiltinType::OCLEvent:
265 case BuiltinType::OCLClkEvent:
266 case BuiltinType::OCLQueue:
267 case BuiltinType::OCLReserveID:
268 return createPointerTypeForPointee(PointeeType: QT);
269
270 // Objective-C builtin types are represented as opaque pointers.
271 case BuiltinType::ObjCId:
272 case BuiltinType::ObjCClass:
273 case BuiltinType::ObjCSel:
274 return createPointerTypeForPointee(PointeeType: QT);
275
276 // AArch64 SVE data and predicate types, including the x2/x3/x4 tuples.
277#define SVE_VECTOR_TYPE(Name, MangledName, Id, SingletonId) \
278 case BuiltinType::Id:
279#define SVE_PREDICATE_TYPE(Name, MangledName, Id, SingletonId) \
280 case BuiltinType::Id:
281#include "clang/Basic/AArch64ACLETypes.def"
282 return convertSVEBuiltinType(BT);
283
284 case BuiltinType::SveCount:
285 return Builder.getScalablePredicateOrCountVectorType(
286 ABIAlign: getTypeAlign(QT), Kind: llvm::abi::VectorKind::SVECount);
287
288 // TODO: __mfp8 has no floating-point semantics of its own, so representing
289 // it needs a decision about how the ABI library should model opaque
290 // floating-point data. As an mfloat8 vector element it is treated as an
291 // 8-bit integer, but that is not right for the scalar type, which is passed
292 // in a floating-point register.
293 case BuiltinType::MFloat8:
294 llvm::reportFatalInternalError(
295 reason: "__mfp8 is not yet supported in the ABI lowering library");
296
297 // Target-specific vector/matrix types — not yet implemented.
298#define PPC_VECTOR_TYPE(Name, Id, Size) case BuiltinType::Id:
299#include "clang/Basic/PPCTypes.def"
300 llvm::reportFatalInternalError(
301 reason: "PPC MMA types not yet supported in ABI lowering library");
302#define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
303#include "clang/Basic/RISCVVTypes.def"
304 llvm::reportFatalInternalError(
305 reason: "RISC-V vector types not yet supported in ABI lowering library");
306#define WASM_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
307#include "clang/Basic/WebAssemblyReferenceTypes.def"
308 llvm::reportFatalInternalError(reason: "WebAssembly reference types not yet "
309 "supported in ABI lowering library");
310#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) case BuiltinType::Id:
311#include "clang/Basic/AMDGPUTypes.def"
312 llvm::reportFatalInternalError(
313 reason: "AMDGPU types not yet supported in ABI lowering library");
314#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
315#include "clang/Basic/HLSLIntangibleTypes.def"
316 llvm::reportFatalInternalError(
317 reason: "HLSL intangible types not yet Supported in ABI lowering library");
318#define HLSL_PACKED_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
319#include "clang/Basic/HLSLPackedTypes.def"
320 llvm::reportFatalInternalError(
321 reason: "HLSL packed types not yet Supported in ABI lowering library");
322#define SPIRV_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
323#include "clang/Basic/SPIRVTypes.def"
324 llvm::reportFatalInternalError(
325 reason: "SPIR-V types not yet supported in ABI lowering library");
326
327 // Placeholder types should never reach ABI lowering.
328#define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id:
329#define BUILTIN_TYPE(Id, SingletonId)
330#include "clang/AST/BuiltinTypes.def"
331 llvm::reportFatalInternalError(
332 reason: "Placeholder type should not reach ABI lowering");
333
334 case BuiltinType::Dependent:
335 llvm::reportFatalInternalError(
336 reason: "Dependent builtin type should not reach ABI lowering");
337 }
338 llvm_unreachable("unhandled builtin type kind in convertBuiltinType");
339}
340
341/// Converts array types to LLVM ABI array representations.
342/// Handles different array kinds: constant arrays, incomplete arrays,
343/// and variable-length arrays.
344///
345/// \param AT The ArrayType to convert
346/// \return LLVM ABI ArrayType or PointerType
347const llvm::abi::Type *
348QualTypeMapper::convertArrayType(const clang::ArrayType *AT) {
349 const llvm::abi::Type *ElementType = convertType(QT: AT->getElementType());
350 uint64_t Size = ASTCtx.getTypeSize(T: AT);
351
352 if (const auto *CAT = dyn_cast<ConstantArrayType>(Val: AT)) {
353 auto NumElements = CAT->getZExtSize();
354 return Builder.getArrayType(ElementType, NumElements, SizeInBits: Size);
355 }
356 if (isa<IncompleteArrayType>(Val: AT))
357 return Builder.getArrayType(ElementType, NumElements: 0, SizeInBits: 0);
358 if (const auto *VAT = dyn_cast<VariableArrayType>(Val: AT))
359 return createPointerTypeForPointee(PointeeType: VAT->getPointeeType());
360 llvm::reportFatalInternalError(
361 reason: "unexpected array type in ABI lowering (dependent array types should be "
362 "resolved before reaching this point)");
363}
364
365const llvm::abi::Type *QualTypeMapper::convertVectorType(const VectorType *VT) {
366 const llvm::abi::Type *ElementType = convertType(QT: VT->getElementType());
367 QualType VectorQualType(VT, 0);
368
369 unsigned NElems = VT->getNumElements();
370 llvm::ElementCount NumElements = llvm::ElementCount::getFixed(MinVal: NElems);
371 llvm::Align VectorAlign = getTypeAlign(QT: VectorQualType);
372
373 // SveFixedLengthPredicate is tagged SVEPredicate, like sizeless svbool_t.
374 // The element type is left as the AST unsigned char (i8). The builtin path
375 // below maps sizeless predicates to i1. Both match the Clang AST, but
376 // consumers that key only off VectorKind cannot assume a 1-bit element.
377 return Builder.getVectorType(ElementType, NumElements, Align: VectorAlign,
378 VecKind: getABIVectorKind(Kind: VT->getVectorKind()));
379}
380
381/// Converts the sizeless AArch64 SVE data and predicate builtin types.
382/// Single vectors become a scalable LLVM ABI VectorType. The x2/x3/x4
383/// forms become a TupleType of that vector.
384///
385/// \param BT The SVE BuiltinType to convert
386/// \return LLVM ABI VectorType or TupleType
387const llvm::abi::Type *
388QualTypeMapper::convertSVEBuiltinType(const BuiltinType *BT) {
389 ASTContext::BuiltinVectorTypeInfo Info = ASTCtx.getBuiltinVectorTypeInfo(VecTy: BT);
390 assert(Info.NumVectors > 0 && Info.NumVectors <= 4 &&
391 "Expected 1, 2, 3 or 4 vectors!");
392
393 // __mfp8 carries no floating-point semantics, so mfloat8 vectors use an
394 // 8-bit integer element type, which is also how they are represented in
395 // LLVM IR.
396 const llvm::abi::Type *ElementType =
397 Info.ElementType->isMFloat8Type()
398 ? Builder.getIntegerType(BitWidth: 8, Align: llvm::Align(1), /*Signed=*/false)
399 : convertType(QT: Info.ElementType);
400
401 llvm::abi::VectorKind VecKind = isSVEPredicateBuiltinType(BT)
402 ? llvm::abi::VectorKind::SVEPredicate
403 : llvm::abi::VectorKind::SVEData;
404
405 const llvm::abi::VectorType *VecTy = Builder.getVectorType(
406 ElementType, NumElements: Info.EC, Align: getTypeAlign(QT: QualType(BT, 0)), VecKind);
407 if (Info.NumVectors == 1)
408 return VecTy;
409 return Builder.getTupleType(Vec: VecTy, NumVectors: Info.NumVectors);
410}
411
412/// Converts complex types to LLVM ABI complex representations.
413/// Complex types consist of two components of the element type
414/// (real and imaginary parts).
415///
416/// \param CT The ComplexType to convert
417/// \return LLVM ABI ComplexType with element type and alignment
418const llvm::abi::Type *
419QualTypeMapper::convertComplexType(const ComplexType *CT) {
420 const llvm::abi::Type *ElementType = convertType(QT: CT->getElementType());
421 llvm::Align ComplexAlign = getTypeAlign(QT: QualType(CT, 0));
422
423 return Builder.getComplexType(ElementType, Align: ComplexAlign);
424}
425
426/// Converts member pointer types to LLVM ABI representations.
427/// Member pointers have different layouts depending on whether they
428/// point to functions or data members.
429///
430/// \param MPT The MemberPointerType to convert
431/// \return LLVM ABI MemberPointerType
432const llvm::abi::Type *
433QualTypeMapper::convertMemberPointerType(const clang::MemberPointerType *MPT) {
434 QualType QT(MPT, 0);
435 uint64_t Size = ASTCtx.getTypeSize(T: QT);
436 llvm::Align Align = getTypeAlign(QT);
437
438 bool IsFunctionPointer = MPT->isMemberFunctionPointerType();
439
440 return Builder.getMemberPointerType(IsFunctionPointer, SizeInBits: Size, Align);
441}
442
443/// Converts record types (struct/class/union) to LLVM ABI representations.
444/// This is the main dispatch method that handles different record kinds
445/// and delegates to specialized converters.
446///
447/// \param RT The RecordType to convert
448/// \return LLVM ABI RecordType
449const llvm::abi::Type *QualTypeMapper::convertRecordType(const RecordType *RT) {
450 const RecordDecl *RD = RT->getDecl()->getDefinition();
451 if (!RD)
452 return Builder.getRecordType(Fields: {}, Size: llvm::TypeSize::getFixed(ExactSize: 0),
453 ABIAlign: llvm::Align(1),
454 /*UnadjustedAlign=*/llvm::Align(1));
455
456 if (RD->isUnion())
457 return convertUnionType(RD);
458
459 // Handle C++ classes with base classes
460 auto *CXXRd = dyn_cast<CXXRecordDecl>(Val: RD);
461 if (CXXRd && (CXXRd->getNumBases() > 0 || CXXRd->getNumVBases() > 0))
462 return convertCXXRecordType(RD: CXXRd);
463 return convertStructType(RD);
464}
465
466/// Converts C++ classes with inheritance to LLVM ABI struct representations.
467/// This method handles the complex layout of C++ objects including:
468/// - Virtual table pointers for polymorphic classes
469/// - Base class subobjects (both direct and virtual bases)
470/// - Member field layout with proper offsets
471///
472/// \param RD The C++ record declaration
473/// \return LLVM ABI RecordType representing the complete object layout
474const llvm::abi::RecordType *
475QualTypeMapper::convertCXXRecordType(const CXXRecordDecl *RD) {
476 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(D: RD);
477 SmallVector<llvm::abi::FieldInfo, 16> Fields;
478 SmallVector<llvm::abi::FieldInfo, 8> BaseClasses;
479 SmallVector<llvm::abi::FieldInfo, 8> VirtualBaseClasses;
480
481 // Add vtable pointer for polymorphic classes
482 if (RD->isPolymorphic()) {
483 const llvm::abi::Type *VtablePointer =
484 createPointerTypeForPointee(PointeeType: ASTCtx.VoidPtrTy);
485 Fields.emplace_back(Args&: VtablePointer, Args: 0);
486 }
487
488 for (const auto &Base : RD->bases()) {
489 if (Base.isVirtual())
490 continue;
491
492 const RecordType *BaseRT = Base.getType()->castAs<RecordType>();
493 const llvm::abi::Type *BaseType = convertType(QT: Base.getType());
494 uint64_t BaseOffset =
495 Layout.getBaseClassOffset(Base: BaseRT->getAsCXXRecordDecl()).getQuantity() *
496 8;
497 BaseClasses.emplace_back(Args&: BaseType, Args&: BaseOffset);
498 }
499
500 for (const auto &VBase : RD->vbases()) {
501 const RecordType *VBaseRT = VBase.getType()->castAs<RecordType>();
502 const llvm::abi::Type *VBaseType = convertType(QT: VBase.getType());
503 uint64_t VBaseOffset =
504 Layout.getVBaseClassOffset(VBase: VBaseRT->getAsCXXRecordDecl())
505 .getQuantity() *
506 8;
507 VirtualBaseClasses.emplace_back(Args&: VBaseType, Args&: VBaseOffset);
508 }
509
510 computeFieldInfo(RD, Fields, Layout);
511
512 llvm::sort(C&: Fields,
513 Comp: [](const llvm::abi::FieldInfo &A, const llvm::abi::FieldInfo &B) {
514 return A.OffsetInBits < B.OffsetInBits;
515 });
516
517 llvm::TypeSize Size =
518 llvm::TypeSize::getFixed(ExactSize: Layout.getSize().getQuantity() * 8);
519 llvm::Align Alignment = llvm::Align(Layout.getAlignment().getQuantity());
520 llvm::Align UnadjustedAlign =
521 llvm::Align(Layout.getUnadjustedAlignment().getQuantity());
522
523 llvm::abi::RecordFlags RecFlags = llvm::abi::RecordFlags::IsCXXRecord;
524 if (RD->isPolymorphic())
525 RecFlags |= llvm::abi::RecordFlags::IsPolymorphic;
526 if (RD->canPassInRegisters())
527 RecFlags |= llvm::abi::RecordFlags::CanPassInRegisters;
528 if (RD->hasFlexibleArrayMember())
529 RecFlags |= llvm::abi::RecordFlags::HasFlexibleArrayMember;
530
531 return Builder.getRecordType(Fields, Size, ABIAlign: Alignment, UnadjustedAlign,
532 Pack: llvm::abi::StructPacking::Default, BaseClasses,
533 VirtualBaseClasses, RecFlags);
534}
535
536/// Converts enumeration types to their underlying integer representations.
537/// This method handles various enum states and falls back to safe defaults
538/// when enum information is incomplete or invalid.
539///
540/// \param ET The EnumType to convert
541/// \return LLVM ABI IntegerType representing the enum's underlying type
542const llvm::abi::Type *
543QualTypeMapper::convertEnumType(const clang::EnumType *ET) {
544 const EnumDecl *ED = ET->getDecl();
545 QualType UnderlyingType = ED->getIntegerType();
546
547 if (UnderlyingType.isNull())
548 UnderlyingType = ASTCtx.IntTy;
549
550 return convertType(QT: UnderlyingType);
551}
552
553/// Converts plain C structs and C++ classes without inheritance.
554/// This handles the simpler case where we only need to layout member fields
555/// without considering base classes or virtual functions.
556///
557/// \param RD The RecordDecl to convert
558/// \return LLVM ABI RecordType
559const llvm::abi::RecordType *
560QualTypeMapper::convertStructType(const clang::RecordDecl *RD) {
561 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(D: RD);
562
563 bool IsCXXRecord = isa<CXXRecordDecl>(Val: RD);
564 SmallVector<llvm::abi::FieldInfo, 16> Fields;
565 computeFieldInfo(RD, Fields, Layout);
566
567 llvm::TypeSize Size =
568 llvm::TypeSize::getFixed(ExactSize: Layout.getSize().getQuantity() * 8);
569 llvm::Align Alignment = llvm::Align(Layout.getAlignment().getQuantity());
570 llvm::Align UnadjustedAlign =
571 llvm::Align(Layout.getUnadjustedAlignment().getQuantity());
572
573 llvm::abi::RecordFlags RecFlags = llvm::abi::RecordFlags::None;
574 if (IsCXXRecord)
575 RecFlags |= llvm::abi::RecordFlags::IsCXXRecord;
576 if (RD->canPassInRegisters())
577 RecFlags |= llvm::abi::RecordFlags::CanPassInRegisters;
578 if (RD->hasFlexibleArrayMember())
579 RecFlags |= llvm::abi::RecordFlags::HasFlexibleArrayMember;
580
581 return Builder.getRecordType(Fields, Size, ABIAlign: Alignment, UnadjustedAlign,
582 Pack: llvm::abi::StructPacking::Default, BaseClasses: {}, VirtualBaseClasses: {},
583 RecFlags);
584}
585
586/// Converts C union types where all fields occupy the same memory location.
587/// The union size is determined by its largest member, and all fields
588/// start at offset 0.
589///
590/// \param RD The RecordDecl representing the union
591/// \return LLVM ABI UnionType
592const llvm::abi::RecordType *
593QualTypeMapper::convertUnionType(const clang::RecordDecl *RD) {
594 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(D: RD);
595
596 SmallVector<llvm::abi::FieldInfo, 16> AllFields;
597 computeFieldInfo(RD, Fields&: AllFields, Layout);
598
599 llvm::TypeSize Size =
600 llvm::TypeSize::getFixed(ExactSize: Layout.getSize().getQuantity() * 8);
601 llvm::Align Alignment = llvm::Align(Layout.getAlignment().getQuantity());
602 llvm::Align UnadjustedAlign =
603 llvm::Align(Layout.getUnadjustedAlignment().getQuantity());
604
605 llvm::abi::RecordFlags RecFlags = llvm::abi::RecordFlags::None;
606 if (RD->hasAttr<TransparentUnionAttr>())
607 RecFlags |= llvm::abi::RecordFlags::IsTransparent;
608 if (RD->canPassInRegisters())
609 RecFlags |= llvm::abi::RecordFlags::CanPassInRegisters;
610 if (isa<CXXRecordDecl>(Val: RD))
611 RecFlags |= llvm::abi::RecordFlags::IsCXXRecord;
612
613 return Builder.getUnionType(Fields: AllFields, Size, ABIAlign: Alignment, UnadjustedAlign,
614 Pack: llvm::abi::StructPacking::Default, RecFlags);
615}
616
617llvm::Align QualTypeMapper::getTypeAlign(QualType QT) const {
618
619 return llvm::Align(ASTCtx.getTypeAlignInChars(T: QT).getQuantity());
620}
621
622const llvm::abi::Type *
623QualTypeMapper::createPointerTypeForPointee(QualType PointeeType) {
624 auto AddrSpace = PointeeType.getAddressSpace();
625 auto PointerSize = ASTCtx.getTargetInfo().getPointerWidth(AddrSpace);
626 llvm::Align Alignment =
627 llvm::Align(ASTCtx.getTargetInfo().getPointerAlign(AddrSpace));
628 // Function types without an explicit address space qualifier use the program
629 // address space, which may differ from the default data address space on
630 // targets like AMDGPU.
631 unsigned TargetAddrSpace =
632 PointeeType->isFunctionType() && !PointeeType.hasAddressSpace()
633 ? DL.getProgramAddressSpace()
634 : ASTCtx.getTargetInfo().getTargetAddressSpace(AS: AddrSpace);
635 return Builder.getPointerType(Size: PointerSize, Align: llvm::Align(Alignment.value() / 8),
636 Addrspace: TargetAddrSpace);
637}
638
639/// Processes the fields of a record (struct/class/union) and populates
640/// the Fields vector with FieldInfo objects containing type, offset,
641/// and bitfield information.
642///
643/// \param RD The RecordDecl whose fields to process
644/// \param Fields Output vector to populate with field information
645/// \param Layout The AST record layout containing field offset information
646void QualTypeMapper::computeFieldInfo(
647 const RecordDecl *RD, SmallVectorImpl<llvm::abi::FieldInfo> &Fields,
648 const ASTRecordLayout &Layout) {
649 unsigned FieldIndex = 0;
650
651 for (const auto *FD : RD->fields()) {
652 const llvm::abi::Type *FieldType = convertType(QT: FD->getType());
653 uint64_t OffsetInBits = Layout.getFieldOffset(FieldNo: FieldIndex);
654
655 bool IsBitField = FD->isBitField();
656 uint64_t BitFieldWidth = 0;
657 bool IsUnnamedBitField = false;
658
659 if (IsBitField) {
660 BitFieldWidth = FD->getBitWidthValue();
661 IsUnnamedBitField = FD->isUnnamedBitField();
662 }
663
664 bool HasNoUniqueAddress = FD->hasAttr<NoUniqueAddressAttr>();
665 Fields.emplace_back(Args&: FieldType, Args&: OffsetInBits, Args&: IsBitField, Args&: BitFieldWidth,
666 Args&: IsUnnamedBitField, Args&: HasNoUniqueAddress);
667 ++FieldIndex;
668 }
669}
670
671} // namespace CodeGen
672} // namespace clang
673