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::Integer: {
34 const auto *IT = cast<abi::IntegerType>(Val: ABIType);
35 Result =
36 llvm::IntegerType::get(C&: Context, NumBits: IT->getSizeInBits().getFixedValue());
37 break;
38 }
39 case abi::TypeKind::Float: {
40 const llvm::fltSemantics *Semantics =
41 cast<abi::FloatType>(Val: ABIType)->getSemantics();
42 Result = llvm::Type::getFloatingPointTy(C&: Context, S: *Semantics);
43 break;
44 }
45 case abi::TypeKind::Pointer:
46 Result = llvm::PointerType::get(
47 C&: Context, AddressSpace: cast<abi::PointerType>(Val: ABIType)->getAddrSpace());
48 break;
49 case abi::TypeKind::Array:
50 Result = convertArrayType(AT: cast<abi::ArrayType>(Val: ABIType));
51 break;
52 case abi::TypeKind::Vector:
53 Result = convertVectorType(VT: cast<abi::VectorType>(Val: ABIType));
54 break;
55 case abi::TypeKind::Record:
56 Result = convertRecordType(RT: cast<abi::RecordType>(Val: ABIType));
57 break;
58 case abi::TypeKind::Complex:
59 Result = convertComplexType(CT: cast<abi::ComplexType>(Val: ABIType));
60 break;
61 case abi::TypeKind::MemberPointer:
62 Result = convertMemberPointerType(MPT: cast<abi::MemberPointerType>(Val: ABIType));
63 break;
64 }
65
66 TypeCache[ABIType] = Result;
67 return Result;
68}
69
70llvm::Type *IRTypeMapper::convertArrayType(const abi::ArrayType *AT) {
71 llvm::Type *ElementType = convertType(ABIType: AT->getElementType());
72 uint64_t NumElements = AT->getNumElements();
73 if (AT->isMatrixType())
74 return llvm::VectorType::get(ElementType,
75 EC: ElementCount::getFixed(MinVal: NumElements));
76 return llvm::ArrayType::get(ElementType, NumElements);
77}
78
79llvm::Type *IRTypeMapper::convertVectorType(const abi::VectorType *VT) {
80 llvm::Type *ElementType = convertType(ABIType: VT->getElementType());
81 return llvm::VectorType::get(ElementType, EC: VT->getNumElements());
82}
83
84llvm::Type *IRTypeMapper::convertRecordType(const abi::RecordType *RT) {
85 return createStructFromFields(Fields: RT->getFields(), Size: RT->getSizeInBits(),
86 Alignment: RT->getAlignment(), IsUnion: RT->isUnion());
87}
88
89llvm::Type *IRTypeMapper::convertComplexType(const abi::ComplexType *CT) {
90 llvm::Type *ElementType = convertType(ABIType: CT->getElementType());
91 llvm::Type *Fields[] = {ElementType, ElementType};
92 return llvm::StructType::get(Context, Elements: Fields, /*isPacked=*/false);
93}
94
95llvm::Type *
96IRTypeMapper::convertMemberPointerType(const abi::MemberPointerType *MPT) {
97 llvm::Type *IntPtrTy = DL.getIntPtrType(C&: Context);
98 if (MPT->isFunctionPointer()) {
99 llvm::Type *Fields[] = {IntPtrTy, IntPtrTy};
100 return llvm::StructType::get(Context, Elements: Fields, /*isPacked=*/false);
101 }
102 return IntPtrTy;
103}
104
105llvm::Type *IRTypeMapper::createPaddingType(uint64_t PaddingBits) {
106 if (PaddingBits == 0)
107 return nullptr;
108 assert(PaddingBits % 8 == 0 &&
109 "sub-byte padding cannot be expressed as an llvm::Type");
110 return llvm::ArrayType::get(ElementType: llvm::IntegerType::get(C&: Context, NumBits: 8),
111 NumElements: PaddingBits / 8);
112}
113
114llvm::StructType *
115IRTypeMapper::createStructFromFields(ArrayRef<abi::FieldInfo> Fields,
116 TypeSize Size, Align Alignment,
117 bool IsUnion) {
118 SmallVector<llvm::Type *, 16> FieldTypes;
119
120 if (IsUnion) {
121 llvm::Type *LargestFieldType = nullptr;
122 uint64_t LargestFieldSize = 0;
123 for (const auto &Field : Fields) {
124 llvm::Type *FieldType = convertType(ABIType: Field.FieldType);
125 uint64_t FieldSize = Field.FieldType->getSizeInBits().getFixedValue();
126 if (FieldSize > LargestFieldSize) {
127 LargestFieldSize = FieldSize;
128 LargestFieldType = FieldType;
129 }
130 }
131 if (LargestFieldType) {
132 FieldTypes.push_back(Elt: LargestFieldType);
133 uint64_t UnionSizeBits = Size.getFixedValue();
134 if (LargestFieldSize < UnionSizeBits) {
135 if (llvm::Type *PaddingType =
136 createPaddingType(PaddingBits: UnionSizeBits - LargestFieldSize))
137 FieldTypes.push_back(Elt: PaddingType);
138 }
139 }
140 } else {
141 uint64_t CurrentOffset = 0;
142 for (const auto &Field : Fields) {
143 assert(!Field.IsBitField && "bitfields should not reach IR type mapping");
144 llvm::Type *FieldType = convertType(ABIType: Field.FieldType);
145 if (Field.OffsetInBits > CurrentOffset) {
146 uint64_t AlignBits = DL.getABITypeAlign(Ty: FieldType).value() * 8;
147 uint64_t NaturalNextOffset =
148 AlignBits ? alignTo(Value: CurrentOffset, Align: AlignBits) : CurrentOffset;
149 if (NaturalNextOffset != Field.OffsetInBits) {
150 if (llvm::Type *PaddingType =
151 createPaddingType(PaddingBits: Field.OffsetInBits - CurrentOffset))
152 FieldTypes.push_back(Elt: PaddingType);
153 }
154 CurrentOffset = Field.OffsetInBits;
155 }
156 FieldTypes.push_back(Elt: FieldType);
157 CurrentOffset += Field.FieldType->getSizeInBits().getFixedValue();
158 }
159 uint64_t TotalSizeBits = Size.getFixedValue();
160 if (CurrentOffset < TotalSizeBits) {
161 if (llvm::Type *PaddingType =
162 createPaddingType(PaddingBits: TotalSizeBits - CurrentOffset))
163 FieldTypes.push_back(Elt: PaddingType);
164 }
165 }
166
167 return StructType::get(Context, Elements: FieldTypes, /*isPacked=*/false);
168}
169