clang 24.0.0git
RecordTypeConverter.cpp
Go to the documentation of this file.
1//===- RecordTypeConverter.cpp - Record-rebuilding type converter ---------===//
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
10
11#include "llvm/ADT/STLExtras.h"
12#include "llvm/ADT/ScopeExit.h"
13#include "llvm/Support/Threading.h"
14
15#include <mutex>
16#include <shared_mutex>
17
18using namespace cir;
19
21 mlir::MLIRContext &context)
22 : context(context) {
23 addConversion([&](mlir::Type type) -> mlir::Type { return type; });
24 // This is necessary in order to convert CIR pointer types that are pointing
25 // to CIR types that are being converted.
26 addConversion([&](cir::PointerType type) -> mlir::Type {
27 mlir::Type loweredPointeeType = convertType(type.getPointee());
28 if (!loweredPointeeType)
29 return {};
30 return cir::PointerType::get(type.getContext(), loweredPointeeType,
31 type.getAddrSpace());
32 });
33 addConversion([&](cir::ArrayType type) -> mlir::Type {
34 mlir::Type loweredElementType = convertType(type.getElementType());
35 if (!loweredElementType)
36 return {};
37 return cir::ArrayType::get(loweredElementType, type.getSize());
38 });
39 // This is necessary in order to convert CIR function types that have
40 // argument or return types that use CIR types that are being converted.
41 addConversion([&](cir::FuncType type) -> mlir::Type {
42 llvm::SmallVector<mlir::Type> loweredInputTypes;
43 loweredInputTypes.reserve(type.getNumInputs());
44 if (mlir::failed(convertTypes(type.getInputs(), loweredInputTypes)))
45 return {};
46
47 mlir::Type loweredReturnType = convertType(type.getReturnType());
48 if (!loweredReturnType)
49 return {};
50
51 return cir::FuncType::get(loweredInputTypes, loweredReturnType,
52 /*isVarArg=*/type.getVarArg());
53 });
54 addConversion([&](cir::StructType type) -> mlir::Type {
55 return convertRecordType(type);
56 });
57 addConversion([&](cir::UnionType type) -> mlir::Type {
58 return convertRecordType(type);
59 });
60}
61
63 std::unique_lock<decltype(recordTypeMutex)> lock(recordTypeMutex);
64
65 for (auto rt : convertedRecordTypes)
66 rt.removeABIConversionNamePrefix();
67}
68
69// This provides a stack for the RecordTypes being processed on the current
70// thread, which lets us solve recursive conversions. This implementation is
71// cribbed from the LLVMTypeConverter which solves a similar but not identical
72// problem.
74RecordRewritingTypeConverter::getCurrentThreadRecursiveStack() {
75 {
76 // Most of the time, the entry already exists in the map.
77 std::shared_lock<decltype(callStackMutex)> lock(callStackMutex,
78 std::defer_lock);
79 if (context.isMultithreadingEnabled())
80 lock.lock();
81 auto recursiveStack = conversionCallStack.find(llvm::get_threadid());
82 if (recursiveStack != conversionCallStack.end())
83 return *recursiveStack->second;
84 }
85
86 // First time this thread gets here, we have to get an exclusive access to
87 // insert in the map
88 std::unique_lock<decltype(callStackMutex)> lock(callStackMutex);
89 auto recursiveStackInserted = conversionCallStack.insert(
90 std::make_pair(llvm::get_threadid(),
91 std::make_unique<llvm::SmallVector<cir::RecordType>>()));
92 return *recursiveStackInserted.first->second;
93}
94
95void RecordRewritingTypeConverter::addConvertedRecordType(cir::RecordType rt) {
96 std::unique_lock<decltype(recordTypeMutex)> lock(recordTypeMutex);
97 convertedRecordTypes.push_back(rt);
98}
99
100llvm::SmallVector<mlir::Type>
101RecordRewritingTypeConverter::convertRecordMemberTypes(cir::RecordType type) {
102 llvm::SmallVector<mlir::Type> loweredMemberTypes;
103 loweredMemberTypes.reserve(type.getNumElements());
104
105 if (mlir::failed(convertTypes(type.getMembers(), loweredMemberTypes)))
106 return {};
107
108 return loweredMemberTypes;
109}
110
111cir::RecordType
112RecordRewritingTypeConverter::convertRecordType(cir::RecordType type) {
113 // Unnamed record types can't be referred to recursively, so we can just
114 // convert this one. It also doesn't have uniqueness problems, so we can
115 // just do a conversion on it.
116 if (!type.getName()) {
117 llvm::SmallVector<mlir::Type> converted = convertRecordMemberTypes(type);
118 assert(converted.size() == type.getNumElements() &&
119 "member conversion must be one type in, one type out for the "
120 "kinds to carry over by index");
121 if (auto u = mlir::dyn_cast<cir::UnionType>(type)) {
122 mlir::Type loweredPadding;
123 if (mlir::Type pad = u.getPadding())
124 loweredPadding = convertType(pad);
125 return cir::UnionType::get(type.getContext(), converted, type.getPacked(),
126 loweredPadding, u.getMemberKinds());
127 }
128 auto s = mlir::cast<cir::StructType>(type);
129 return cir::StructType::get(type.getContext(), converted, type.getPacked(),
130 s.getIsClass(), s.getMemberKinds());
131 }
132
133 assert(!type.isIncomplete() || type.getMembers().empty());
134
135 // If the type has already been converted, we can just return, since there
136 // is nothing to do. Also, if it is incomplete, it can't have invalid
137 // members! So we can skip transforming it.
138 if (type.isIncomplete() || type.isABIConvertedRecord())
139 return type;
140
141 llvm::SmallVectorImpl<cir::RecordType> &recursiveStack =
142 getCurrentThreadRecursiveStack();
143
144 cir::RecordType convertedType;
145 if (mlir::isa<cir::UnionType>(type))
146 convertedType =
147 cir::UnionType::get(type.getContext(), type.getABIConvertedName());
148 else
149 convertedType =
150 cir::StructType::get(type.getContext(), type.getABIConvertedName(),
151 mlir::cast<cir::StructType>(type).getIsClass());
152
153 // This type has already been converted, just return it.
154 if (convertedType.isComplete())
155 return convertedType;
156
157 // We put the existing 'type' into the vector if we're in the process of
158 // converting it (and pop it when we're done). To prevent recursion,
159 // just return the 'incomplete' version, and the 'top level' version of this
160 // call will call 'complete' on it.
161 if (llvm::is_contained(recursiveStack, type))
162 return convertedType;
163
164 recursiveStack.push_back(type);
165 llvm::scope_exit popConvertingType(
166 [&recursiveStack]() { recursiveStack.pop_back(); });
167
168 llvm::SmallVector<mlir::Type> convertedMembers =
169 convertRecordMemberTypes(type);
170 assert(convertedMembers.size() == type.getNumElements() &&
171 "member conversion must be one type in, one type out for the kinds "
172 "to carry over by index");
173
174 mlir::Type loweredPadding;
175 if (auto u = mlir::dyn_cast<cir::UnionType>(type))
176 if (mlir::Type pad = u.getPadding())
177 loweredPadding = convertType(pad);
178 convertedType.complete(convertedMembers, type.getPacked(), loweredPadding,
179 type.getMemberKinds());
180 addConvertedRecordType(convertedType);
181 return convertedType;
182}
void restoreRecordTypeNames()
Remove the temporary name of every record rebuilt by this converter.
RecordRewritingTypeConverter(mlir::MLIRContext &context)
bool isComplete() const
Definition CIRTypes.h:168
void complete(llvm::ArrayRef< mlir::Type > members, bool packed, mlir::Type padding, llvm::ArrayRef< RecordMemberKind > memberKinds)
padding is union-only.
Definition CIRTypes.cpp:657
const internal::VariadicAllOfMatcher< Type > type
Matches Types in the clang AST.