11#include "llvm/ADT/STLExtras.h"
12#include "llvm/ADT/ScopeExit.h"
13#include "llvm/Support/Threading.h"
16#include <shared_mutex>
21 mlir::MLIRContext &context)
23 addConversion([&](mlir::Type type) -> mlir::Type {
return type; });
26 addConversion([&](cir::PointerType type) -> mlir::Type {
27 mlir::Type loweredPointeeType = convertType(type.getPointee());
28 if (!loweredPointeeType)
30 return cir::PointerType::get(type.getContext(), loweredPointeeType,
33 addConversion([&](cir::ArrayType type) -> mlir::Type {
34 mlir::Type loweredElementType = convertType(type.getElementType());
35 if (!loweredElementType)
37 return cir::ArrayType::get(loweredElementType, type.getSize());
41 addConversion([&](cir::FuncType type) -> mlir::Type {
43 loweredInputTypes.reserve(type.getNumInputs());
44 if (mlir::failed(convertTypes(type.getInputs(), loweredInputTypes)))
47 mlir::Type loweredReturnType = convertType(type.getReturnType());
48 if (!loweredReturnType)
51 return cir::FuncType::get(loweredInputTypes, loweredReturnType,
54 addConversion([&](cir::StructType type) -> mlir::Type {
55 return convertRecordType(type);
57 addConversion([&](cir::UnionType type) -> mlir::Type {
58 return convertRecordType(type);
63 std::unique_lock<
decltype(recordTypeMutex)> lock(recordTypeMutex);
65 for (
auto rt : convertedRecordTypes)
66 rt.removeABIConversionNamePrefix();
74RecordRewritingTypeConverter::getCurrentThreadRecursiveStack() {
77 std::shared_lock<
decltype(callStackMutex)> lock(callStackMutex,
79 if (context.isMultithreadingEnabled())
81 auto recursiveStack = conversionCallStack.find(llvm::get_threadid());
82 if (recursiveStack != conversionCallStack.end())
83 return *recursiveStack->second;
88 std::unique_lock<
decltype(callStackMutex)> lock(callStackMutex);
89 auto recursiveStackInserted = conversionCallStack.insert(
90 std::make_pair(llvm::get_threadid(),
92 return *recursiveStackInserted.first->second;
95void RecordRewritingTypeConverter::addConvertedRecordType(cir::RecordType rt) {
96 std::unique_lock<
decltype(recordTypeMutex)> lock(recordTypeMutex);
97 convertedRecordTypes.push_back(rt);
100llvm::SmallVector<mlir::Type>
101RecordRewritingTypeConverter::convertRecordMemberTypes(cir::RecordType type) {
102 llvm::SmallVector<mlir::Type> loweredMemberTypes;
103 loweredMemberTypes.reserve(
type.getNumElements());
105 if (mlir::failed(convertTypes(
type.getMembers(), loweredMemberTypes)))
108 return loweredMemberTypes;
111bool RecordRewritingTypeConverter::reachesChangingType(
112 mlir::Type type, llvm::SmallPtrSetImpl<mlir::Type> &visiting)
const {
117 if (
auto rt = mlir::dyn_cast<cir::RecordType>(type)) {
118 if (!visiting.insert(type).second)
121 if (reachesChangingType(member, visiting))
123 if (
auto u = mlir::dyn_cast<cir::UnionType>(type))
124 if (mlir::Type pad = u.getPadding())
125 return reachesChangingType(pad, visiting);
130 type.walkImmediateSubElements([](mlir::Attribute) {},
131 [&](mlir::Type sub) {
133 reachesChangingType(sub, visiting);
138bool RecordRewritingTypeConverter::recordNeedsConversion(cir::RecordType type) {
140 std::shared_lock<
decltype(recordNeedsConversionMutex)> lock(
141 recordNeedsConversionMutex);
142 auto it = recordNeedsConversionCache.find(type);
143 if (it != recordNeedsConversionCache.end())
148 llvm::SmallPtrSet<mlir::Type, 8> visiting;
149 bool result = reachesChangingType(type, visiting);
151 std::unique_lock<
decltype(recordNeedsConversionMutex)> lock(
152 recordNeedsConversionMutex);
153 recordNeedsConversionCache[
type] = result;
158RecordRewritingTypeConverter::convertRecordType(cir::RecordType type) {
160 if (!recordNeedsConversion(type))
166 if (!
type.getName()) {
167 llvm::SmallVector<mlir::Type> converted = convertRecordMemberTypes(type);
168 assert(converted.size() ==
type.getNumElements() &&
169 "member conversion must be one type in, one type out for the "
170 "kinds to carry over by index");
171 if (
auto u = mlir::dyn_cast<cir::UnionType>(type)) {
172 mlir::Type loweredPadding;
173 if (mlir::Type pad = u.getPadding())
174 loweredPadding = convertType(pad);
175 return cir::UnionType::get(
type.getContext(), converted,
type.getPacked(),
176 loweredPadding, u.getMemberKinds());
178 auto s = mlir::cast<cir::StructType>(type);
179 return cir::StructType::get(
type.getContext(), converted,
type.getPacked(),
180 s.getIsClass(), s.getMemberKinds());
183 assert(!
type.isIncomplete() ||
type.getMembers().empty());
188 if (
type.isIncomplete() ||
type.isABIConvertedRecord())
191 llvm::SmallVectorImpl<cir::RecordType> &recursiveStack =
192 getCurrentThreadRecursiveStack();
194 cir::RecordType convertedType;
195 if (mlir::isa<cir::UnionType>(type))
197 cir::UnionType::get(
type.getContext(),
type.getABIConvertedName());
200 cir::StructType::get(
type.getContext(),
type.getABIConvertedName(),
201 mlir::cast<cir::StructType>(type).getIsClass());
205 return convertedType;
211 if (llvm::is_contained(recursiveStack, type))
212 return convertedType;
214 recursiveStack.push_back(type);
215 llvm::scope_exit popConvertingType(
216 [&recursiveStack]() { recursiveStack.pop_back(); });
218 llvm::SmallVector<mlir::Type> convertedMembers =
219 convertRecordMemberTypes(type);
220 assert(convertedMembers.size() ==
type.getNumElements() &&
221 "member conversion must be one type in, one type out for the kinds "
222 "to carry over by index");
224 mlir::Type loweredPadding;
225 if (
auto u = mlir::dyn_cast<cir::UnionType>(type))
226 if (mlir::Type pad = u.getPadding())
227 loweredPadding = convertType(pad);
228 convertedType.
complete(convertedMembers,
type.getPacked(), loweredPadding,
229 type.getMemberKinds());
230 addConvertedRecordType(convertedType);
231 return convertedType;
void restoreRecordTypeNames()
Remove the temporary name of every record rebuilt by this converter.
virtual bool typeMayChange(mlir::Type type) const
Whether type itself, ignoring nested types, may change.
RecordRewritingTypeConverter(mlir::MLIRContext &context)
llvm::ArrayRef< mlir::Type > getMembers() const
void complete(llvm::ArrayRef< mlir::Type > members, bool packed, mlir::Type padding, llvm::ArrayRef< RecordMemberKind > memberKinds)
padding is union-only.
const internal::VariadicAllOfMatcher< Type > type
Matches Types in the clang AST.