Skip to content

Commit 3a58271

Browse files
committed
[LLVMABI] QualType Mapper Implementation
1 parent 114cab7 commit 3a58271

File tree

8 files changed

+298
-86
lines changed

8 files changed

+298
-86
lines changed
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#ifndef LLVM_ABI_QUALTYPE_MAPPER_H
2+
#define LLVM_ABI_QUALTYPE_MAPPER_H
3+
4+
#include "llvm/IR/DerivedTypes.h"
5+
#include "llvm/Support/Allocator.h"
6+
#include <clang/AST/ASTContext.h>
7+
#include <clang/AST/Decl.h>
8+
#include <clang/AST/Type.h>
9+
#include <llvm/ABI/Types.h>
10+
#include <llvm/ADT/DenseMap.h>
11+
12+
// Specialization for QualType
13+
template <> struct llvm::DenseMapInfo<clang::QualType> {
14+
static inline clang::QualType getEmptyKey() {
15+
return clang::QualType::getFromOpaquePtr(
16+
reinterpret_cast<clang::Type *>(-1));
17+
}
18+
19+
static inline clang::QualType getTombstoneKey() {
20+
return clang::QualType::getFromOpaquePtr(
21+
reinterpret_cast<clang::Type *>(-2));
22+
}
23+
24+
static unsigned getHashValue(const clang::QualType &Val) {
25+
return (unsigned)((uintptr_t)Val.getAsOpaquePtr()) ^
26+
((unsigned)((uintptr_t)Val.getAsOpaquePtr() >> 9));
27+
}
28+
29+
static bool isEqual(const clang::QualType &LHS, const clang::QualType &RHS) {
30+
return LHS == RHS;
31+
}
32+
};
33+
34+
namespace clang {
35+
namespace mapper {
36+
37+
class QualTypeMapper {
38+
private:
39+
clang::ASTContext &ASTCtx;
40+
llvm::abi::TypeBuilder Builder;
41+
42+
llvm::DenseMap<clang::QualType, const llvm::abi::Type *> TypeCache;
43+
44+
const llvm::abi::Type *convertBuiltinType(const clang::BuiltinType *BT);
45+
const llvm::abi::Type *convertPointerType(const clang::PointerType *PT);
46+
const llvm::abi::Type *convertArrayType(const clang::ArrayType *AT);
47+
const llvm::abi::Type *convertVectorType(const clang::VectorType *VT);
48+
const llvm::abi::Type *convertRecordType(const clang::RecordType *RT);
49+
const llvm::abi::Type *convertEnumType(const clang::EnumType *ET);
50+
51+
const llvm::abi::StructType *convertStructType(const clang::RecordDecl *RD);
52+
const llvm::abi::UnionType *convertUnionType(const clang::RecordDecl *RD);
53+
const llvm::abi::Type *createPointerTypeForPointee(QualType PointeeType);
54+
55+
void computeFieldInfo(const clang::RecordDecl *RD,
56+
SmallVectorImpl<llvm::abi::FieldInfo> &Fields,
57+
const clang::ASTRecordLayout &Layout);
58+
59+
llvm::TypeSize getTypeSize(clang::QualType QT) const;
60+
llvm::Align getTypeAlign(clang::QualType QT) const;
61+
uint64_t getPointerSize() const;
62+
uint64_t getPointerAlign() const;
63+
64+
public:
65+
explicit QualTypeMapper(clang::ASTContext &Ctx, llvm::BumpPtrAllocator &Alloc)
66+
: ASTCtx(Ctx), Builder(Alloc) {}
67+
68+
const llvm::abi::Type *convertType(clang::QualType QT);
69+
70+
void clearCache() { TypeCache.clear(); }
71+
72+
llvm::abi::TypeBuilder getTypeBuilder() { return Builder; }
73+
};
74+
75+
} // namespace mapper
76+
} // namespace clang
77+
78+
#endif // !LLVM_ABI_QUALTYPE_MAPPER_H

clang/lib/ABI/CMakeLists.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
add_clang_library(clangABI
2+
QualTypeMapper.cpp
3+
4+
LINK_LIBS
5+
clangAST
6+
clangBasic
7+
LLVMABI
8+
LLVMSupport
9+
)

clang/lib/ABI/QualTypeMapper.cpp

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
#include "clang/AST/RecordLayout.h"
2+
#include "clang/AST/Type.h"
3+
#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
4+
#include "clang/Basic/LLVM.h"
5+
#include "clang/Basic/TargetInfo.h"
6+
#include "llvm/ABI/Types.h"
7+
#include "llvm/Support/Alignment.h"
8+
#include "llvm/Support/Casting.h"
9+
#include <clang/ABI/QualTypeMapper.h>
10+
11+
namespace clang {
12+
namespace mapper {
13+
14+
const llvm::abi::Type *QualTypeMapper::convertType(QualType QT) {
15+
QT = QT.getCanonicalType().getUnqualifiedType();
16+
17+
auto It = TypeCache.find(QT);
18+
if (It != TypeCache.end())
19+
return It->second;
20+
21+
const llvm::abi::Type *Result = nullptr;
22+
if (const auto *BT = dyn_cast<BuiltinType>(QT.getTypePtr())) {
23+
Result = convertBuiltinType(BT);
24+
} else if (const auto *PT = dyn_cast<PointerType>(QT.getTypePtr())) {
25+
Result = convertPointerType(PT);
26+
} else if (const auto *AT = dyn_cast<ArrayType>(QT.getTypePtr())) {
27+
Result = convertArrayType(AT);
28+
} else if (const auto *VT = dyn_cast<VectorType>(QT.getTypePtr())) {
29+
Result = convertVectorType(VT);
30+
} else if (const auto *RT = dyn_cast<RecordType>(QT.getTypePtr())) {
31+
Result = convertRecordType(RT);
32+
} else if (const auto *ET = dyn_cast<EnumType>(QT.getTypePtr())) {
33+
Result = convertEnumType(ET);
34+
} else {
35+
// TODO: Write Fallback logic for unsupported types.
36+
}
37+
TypeCache[QT] = Result;
38+
return Result;
39+
}
40+
41+
const llvm::abi::Type *
42+
QualTypeMapper::convertBuiltinType(const BuiltinType *BT) {
43+
switch (BT->getKind()) {
44+
case BuiltinType::Void:
45+
return Builder.getVoidType();
46+
47+
case BuiltinType::Bool:
48+
case BuiltinType::UChar:
49+
case BuiltinType::Char_U:
50+
case BuiltinType::UShort:
51+
return Builder.getIntegerType(ASTCtx.getTypeSize(QualType(BT, 0)),
52+
getTypeAlign(QualType(BT, 0)), false);
53+
54+
case BuiltinType::Char_S:
55+
case BuiltinType::SChar:
56+
case BuiltinType::Short:
57+
return Builder.getIntegerType(ASTCtx.getCharWidth(),
58+
getTypeAlign(QualType(BT, 0)), true);
59+
60+
case BuiltinType::WChar_U:
61+
return Builder.getIntegerType(ASTCtx.getCharWidth(),
62+
getTypeAlign(QualType(BT, 0)), false);
63+
64+
case BuiltinType::WChar_S:
65+
return Builder.getIntegerType(ASTCtx.getCharWidth(),
66+
getTypeAlign(QualType(BT, 0)), true);
67+
68+
case BuiltinType::Char8:
69+
return Builder.getIntegerType(8, getTypeAlign(QualType(BT, 0)), false);
70+
71+
case BuiltinType::Char16:
72+
return Builder.getIntegerType(16, getTypeAlign(QualType(BT, 0)), false);
73+
74+
case BuiltinType::Char32:
75+
return Builder.getIntegerType(32, getTypeAlign(QualType(BT, 0)), false);
76+
77+
case BuiltinType::Int:
78+
case BuiltinType::UInt:
79+
return Builder.getIntegerType(ASTCtx.getIntWidth(QualType(BT, 0)),
80+
getTypeAlign(QualType(BT, 0)),
81+
BT->getKind() == BuiltinType::Int);
82+
83+
case BuiltinType::Long:
84+
case BuiltinType::ULong:
85+
return Builder.getIntegerType(ASTCtx.getTypeSize(QualType(BT, 0)),
86+
getTypeAlign(QualType(BT, 0)),
87+
BT->getKind() == BuiltinType::Long);
88+
89+
case BuiltinType::LongLong:
90+
case BuiltinType::ULongLong:
91+
return Builder.getIntegerType(ASTCtx.getTypeSize(QualType(BT, 0)),
92+
getTypeAlign(QualType(BT, 0)),
93+
BT->getKind() == BuiltinType::LongLong);
94+
95+
case BuiltinType::Int128:
96+
case BuiltinType::UInt128:
97+
return Builder.getIntegerType(128, getTypeAlign(QualType(BT, 0)),
98+
BT->getKind() == BuiltinType::Int128);
99+
100+
case BuiltinType::Half:
101+
case BuiltinType::Float16:
102+
return Builder.getFloatType(llvm::APFloat::IEEEhalf(),
103+
getTypeAlign(QualType(BT, 0)));
104+
105+
case BuiltinType::Float:
106+
return Builder.getFloatType(llvm::APFloat::IEEEsingle(),
107+
getTypeAlign(QualType(BT, 0)));
108+
109+
case BuiltinType::Double:
110+
return Builder.getFloatType(llvm::APFloat::IEEEdouble(),
111+
getTypeAlign(QualType(BT, 0)));
112+
113+
case BuiltinType::LongDouble:
114+
return Builder.getFloatType(ASTCtx.getFloatTypeSemantics(QualType(BT, 0)),
115+
getTypeAlign(QualType(BT, 0)));
116+
117+
case BuiltinType::BFloat16:
118+
return Builder.getFloatType(llvm::APFloat::BFloat(),
119+
getTypeAlign(QualType(BT, 0)));
120+
121+
case BuiltinType::Float128:
122+
return Builder.getFloatType(llvm::APFloat::IEEEquad(),
123+
getTypeAlign(QualType(BT, 0)));
124+
125+
default:
126+
return Builder.getIntegerType(ASTCtx.getTypeSize(QualType(BT, 0)),
127+
getTypeAlign(QualType(BT, 0)), false);
128+
}
129+
}
130+
131+
const llvm::abi::Type *
132+
QualTypeMapper::convertArrayType(const clang::ArrayType *AT) {
133+
const llvm::abi::Type *ElementType = convertType(AT->getElementType());
134+
135+
if (const auto *CAT = dyn_cast<ConstantArrayType>(AT)) {
136+
auto NumElements = CAT->getZExtSize();
137+
return Builder.getArrayType(ElementType, NumElements);
138+
}
139+
if (const auto *IAT = dyn_cast<IncompleteArrayType>(AT))
140+
return Builder.getArrayType(ElementType, 0);
141+
if (const auto *VAT = dyn_cast<VariableArrayType>(AT))
142+
return createPointerTypeForPointee(VAT->getPointeeType());
143+
// TODO: This of a better fallback.
144+
return Builder.getArrayType(ElementType, 1);
145+
}
146+
147+
const llvm::abi::Type *QualTypeMapper::convertVectorType(const VectorType *VT) {
148+
const llvm::abi::Type *ElementType = convertType(VT->getElementType());
149+
uint64_t NumElements = VT->getNumElements();
150+
151+
llvm::Align VectorAlign = getTypeAlign(QualType(VT, 0));
152+
153+
return Builder.getVectorType(ElementType, NumElements, VectorAlign);
154+
}
155+
156+
const llvm::abi::Type *QualTypeMapper::convertRecordType(const RecordType *RT) {
157+
const RecordDecl *RD = RT->getDecl()->getDefinition();
158+
if (!RD) {
159+
SmallVector<llvm::abi::FieldInfo, 0> Fields;
160+
return Builder.getStructType(Fields, llvm::TypeSize::getFixed(0),
161+
llvm::Align(1));
162+
}
163+
164+
if (RD->isUnion())
165+
return convertUnionType(RD);
166+
return convertStructType(RD);
167+
}
168+
169+
const llvm::abi::Type *
170+
QualTypeMapper::convertPointerType(const clang::PointerType *PT) {
171+
return createPointerTypeForPointee(PT->getPointeeType());
172+
}
173+
174+
llvm::Align QualTypeMapper::getTypeAlign(QualType QT) const {
175+
return llvm::Align(ASTCtx.getTypeAlign(QT));
176+
}
177+
178+
const llvm::abi::Type *
179+
QualTypeMapper::createPointerTypeForPointee(QualType PointeeType) {
180+
auto AddrSpace = PointeeType.getAddressSpace();
181+
auto PointerSize = ASTCtx.getTargetInfo().getPointerWidth(AddrSpace);
182+
llvm::Align Alignment =
183+
llvm::Align(ASTCtx.getTargetInfo().getPointerAlign(AddrSpace));
184+
return Builder.getPointerType(PointerSize, Alignment);
185+
}
186+
187+
void QualTypeMapper::computeFieldInfo(
188+
const RecordDecl *RD, SmallVectorImpl<llvm::abi::FieldInfo> &Fields,
189+
const ASTRecordLayout &Layout) {
190+
unsigned FieldIndex = 0;
191+
192+
for (const auto *FD : RD->fields()) {
193+
const llvm::abi::Type *FieldType = convertType(FD->getType());
194+
uint64_t OffsetInBits = Layout.getFieldOffset(FieldIndex);
195+
196+
bool IsBitField = FD->isBitField();
197+
uint64_t BitFieldWidth = 0;
198+
199+
if (IsBitField) {
200+
BitFieldWidth = FD->getBitWidthValue();
201+
}
202+
203+
Fields.emplace_back(FieldType, OffsetInBits, IsBitField, BitFieldWidth);
204+
++FieldIndex;
205+
}
206+
}
207+
208+
} // namespace mapper
209+
} // namespace clang

clang/lib/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
add_subdirectory(ABI)
12
add_subdirectory(Headers)
23
add_subdirectory(Basic)
34
add_subdirectory(APINotes)

llvm/include/llvm/ABI/QualTypeMapper.h

Lines changed: 0 additions & 52 deletions
This file was deleted.

llvm/lib/ABI/CMakeLists.txt

Lines changed: 0 additions & 17 deletions
This file was deleted.

llvm/lib/ABI/QualTypeMapper.cpp

Lines changed: 0 additions & 16 deletions
This file was deleted.

0 commit comments

Comments
 (0)