1//===---- IRTypeMapper.cpp - Maps LLVM ABI Types to LLVM IR 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#include "llvm/ABI/IRTypeMapper.h"
10#include "llvm/ABI/Types.h"
11#include "llvm/ADT/APFloat.h"
12#include "llvm/ADT/SmallVector.h"
13#include "llvm/IR/DataLayout.h"
14#include "llvm/IR/DerivedTypes.h"
15#include "llvm/IR/Type.h"
16#include "llvm/Support/MathExtras.h"
17
18using namespace llvm::abi;
19
20llvm::Type *IRTypeMapper::convertType(const abi::Type *ABIType) {
21 assert(ABIType && "convertType requires a non-null ABI type");
22
23 auto It = TypeCache.find(Val: ABIType);
24 if (It != TypeCache.end())
25 return It->second;
26
27 llvm::Type *Result = nullptr;
28
29 switch (ABIType->getKind()) {
30 case abi::TypeKind::Void:
31 Result = llvm::Type::getVoidTy(C&: Context);
32 break;
33 case abi::TypeKind::Atomic:
34 Result = convertAtomicType(AT: cast<abi::AtomicType>(Val: ABIType));
35 break;
36 case abi::TypeKind::Integer: {
37 const auto *IT = cast<abi::IntegerType>(Val: ABIType);
38 Result =
39 llvm::IntegerType::get(C&: Context, NumBits: IT->getSizeInBits().getFixedValue());
40 break;
41 }
42 case abi::TypeKind::Float: {
43 const llvm::fltSemantics *Semantics =
44 cast<abi::FloatType>(Val: ABIType)->getSemantics();
45 Result = llvm::Type::getFloatingPointTy(C&: Context, S: *Semantics);
46 break;
47 }
48 case abi::TypeKind::Pointer:
49 Result = llvm::PointerType::get(
50 C&: Context, AddressSpace: cast<abi::PointerType>(Val: ABIType)->getAddrSpace());
51 break;
52 case abi::TypeKind::Array:
53 Result = convertArrayType(AT: cast<abi::ArrayType>(Val: ABIType));
54 break;
55 case abi::TypeKind::Vector:
56 Result = convertVectorType(VT: cast<abi::VectorType>(Val: ABIType));
57 break;
58 case abi::TypeKind::Tuple:
59 Result = convertTupleType(TT: cast<abi::TupleType>(Val: ABIType));
60 break;
61 case abi::TypeKind::Record:
62 Result = convertRecordType(RT: cast<abi::RecordType>(Val: ABIType));
63 break;
64 case abi::TypeKind::Complex:
65 Result = convertComplexType(CT: cast<abi::ComplexType>(Val: ABIType));
66 break;
67 case abi::TypeKind::MemberPointer:
68 Result = convertMemberPointerType(MPT: cast<abi::MemberPointerType>(Val: ABIType));
69 break;
70 }
71
72 TypeCache[ABIType] = Result;
73 return Result;
74}
75
76llvm::Type *IRTypeMapper::convertAtomicType(const abi::AtomicType *AT) {
77 llvm::Type *ValueType = convertType(ABIType: AT->getValueType());
78 uint64_t ValueSize = AT->getValueType()->getSizeInBits().getFixedValue();
79 uint64_t AtomicSize = AT->getSizeInBits().getFixedValue();
80 if (ValueSize == AtomicSize)
81 return ValueType;
82
83 assert(ValueSize < AtomicSize && "atomic type cannot shrink its value type");
84 llvm::Type *Fields[] = {ValueType,
85 llvm::ArrayType::get(ElementType: llvm::Type::getInt8Ty(C&: Context),
86 NumElements: (AtomicSize - ValueSize) / 8)};
87 return llvm::StructType::get(Context, Elements: Fields, /*isPacked=*/false);
88}
89
90llvm::Type *IRTypeMapper::convertArrayType(const abi::ArrayType *AT) {
91 llvm::Type *ElementType = convertType(ABIType: AT->getElementType());
92 uint64_t NumElements = AT->getNumElements();
93 if (AT->isMatrixType())
94 return llvm::VectorType::get(ElementType,
95 EC: ElementCount::getFixed(MinVal: NumElements));
96 return llvm::ArrayType::get(ElementType, NumElements);
97}
98
99llvm::Type *IRTypeMapper::convertVectorType(const abi::VectorType *VT) {
100 if (VT->isSVECount())
101 return llvm::TargetExtType::get(Context, Name: "aarch64.svcount");
102
103 llvm::Type *ElementType = convertType(ABIType: VT->getElementType());
104 return llvm::VectorType::get(ElementType, EC: VT->getNumElements());
105}
106
107llvm::Type *IRTypeMapper::convertTupleType(const abi::TupleType *TT) {
108 llvm::Type *VecTy = convertType(ABIType: TT->getVectorType());
109 SmallVector<llvm::Type *, 4> Elements(TT->getNumVectors(), VecTy);
110 return llvm::StructType::get(Context, Elements);
111}
112
113llvm::Type *IRTypeMapper::convertRecordType(const abi::RecordType *RT) {
114 // A packed record is a sequence of fields with no alignment padding. Pure
115 // scalable aggregates use one as the unpadded coerce-and-expand type, and
116 // its fields may be scalable vectors.
117 if (RT->getPacking() == StructPacking::Packed) {
118 SmallVector<llvm::Type *, 8> FieldTypes;
119 for (const FieldInfo &Field : RT->getFields())
120 FieldTypes.push_back(Elt: convertType(ABIType: Field.FieldType));
121 return llvm::StructType::get(Context, Elements: FieldTypes, /*isPacked=*/true);
122 }
123 return createStructFromFields(Fields: RT->getFields(), Size: RT->getSizeInBits(),
124 Alignment: RT->getAlignment(), IsUnion: RT->isUnion());
125}
126
127llvm::Type *IRTypeMapper::convertComplexType(const abi::ComplexType *CT) {
128 llvm::Type *ElementType = convertType(ABIType: CT->getElementType());
129 llvm::Type *Fields[] = {ElementType, ElementType};
130 return llvm::StructType::get(Context, Elements: Fields, /*isPacked=*/false);
131}
132
133llvm::Type *
134IRTypeMapper::convertMemberPointerType(const abi::MemberPointerType *MPT) {
135 llvm::Type *IntPtrTy = DL.getIntPtrType(C&: Context);
136 if (MPT->isFunctionPointer()) {
137 llvm::Type *Fields[] = {IntPtrTy, IntPtrTy};
138 return llvm::StructType::get(Context, Elements: Fields, /*isPacked=*/false);
139 }
140 return IntPtrTy;
141}
142
143llvm::Type *IRTypeMapper::createPaddingType(uint64_t PaddingBits) {
144 if (PaddingBits == 0)
145 return nullptr;
146 assert(PaddingBits % 8 == 0 &&
147 "sub-byte padding cannot be expressed as an llvm::Type");
148 return llvm::ArrayType::get(ElementType: llvm::IntegerType::get(C&: Context, NumBits: 8),
149 NumElements: PaddingBits / 8);
150}
151
152llvm::StructType *
153IRTypeMapper::createStructFromFields(ArrayRef<abi::FieldInfo> Fields,
154 TypeSize Size, Align Alignment,
155 bool IsUnion) {
156 SmallVector<llvm::Type *, 16> FieldTypes;
157
158 if (IsUnion) {
159 llvm::Type *LargestFieldType = nullptr;
160 uint64_t LargestFieldSize = 0;
161 for (const auto &Field : Fields) {
162 llvm::Type *FieldType = convertType(ABIType: Field.FieldType);
163 uint64_t FieldSize = Field.FieldType->getSizeInBits().getFixedValue();
164 if (FieldSize > LargestFieldSize) {
165 LargestFieldSize = FieldSize;
166 LargestFieldType = FieldType;
167 }
168 }
169 if (LargestFieldType) {
170 FieldTypes.push_back(Elt: LargestFieldType);
171 uint64_t UnionSizeBits = Size.getFixedValue();
172 if (LargestFieldSize < UnionSizeBits) {
173 if (llvm::Type *PaddingType =
174 createPaddingType(PaddingBits: UnionSizeBits - LargestFieldSize))
175 FieldTypes.push_back(Elt: PaddingType);
176 }
177 }
178 } else {
179 uint64_t CurrentOffset = 0;
180 for (const auto &Field : Fields) {
181 assert(!Field.IsBitField && "bitfields should not reach IR type mapping");
182 llvm::Type *FieldType = convertType(ABIType: Field.FieldType);
183 if (Field.OffsetInBits > CurrentOffset) {
184 uint64_t AlignBits = DL.getABITypeAlign(Ty: FieldType).value() * 8;
185 uint64_t NaturalNextOffset =
186 AlignBits ? alignTo(Value: CurrentOffset, Align: AlignBits) : CurrentOffset;
187 if (NaturalNextOffset != Field.OffsetInBits) {
188 if (llvm::Type *PaddingType =
189 createPaddingType(PaddingBits: Field.OffsetInBits - CurrentOffset))
190 FieldTypes.push_back(Elt: PaddingType);
191 }
192 CurrentOffset = Field.OffsetInBits;
193 }
194 FieldTypes.push_back(Elt: FieldType);
195 CurrentOffset += Field.FieldType->getSizeInBits().getFixedValue();
196 }
197 uint64_t TotalSizeBits = Size.getFixedValue();
198 if (CurrentOffset < TotalSizeBits) {
199 if (llvm::Type *PaddingType =
200 createPaddingType(PaddingBits: TotalSizeBits - CurrentOffset))
201 FieldTypes.push_back(Elt: PaddingType);
202 }
203 }
204
205 return StructType::get(Context, Elements: FieldTypes, /*isPacked=*/false);
206}
207