clang 24.0.0git
CIRGenCleanup.h
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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// These classes support the generation of CIR for cleanups, initially based
10// on LLVM IR cleanup handling, but ought to change as CIR evolves.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef CLANG_LIB_CIR_CODEGEN_CIRGENCLEANUP_H
15#define CLANG_LIB_CIR_CODEGEN_CIRGENCLEANUP_H
16
17#include "Address.h"
18#include "CIRGenModule.h"
19#include "EHScopeStack.h"
20#include "mlir/IR/Value.h"
21#include "clang/AST/StmtCXX.h"
22
23namespace clang::CIRGen {
24
25/// The MS C++ ABI needs a pointer to RTTI data plus some flags to describe the
26/// type of a catch handler, so we use this wrapper.
28 mlir::TypedAttr rtti;
29 unsigned flags;
30};
31
32/// A protected scope for zero-cost EH handling.
33class EHScope {
34 EHScopeStack::stable_iterator enclosingEHScope;
35
36 class CommonBitFields {
37 friend class EHScope;
38 unsigned kind : 3;
39 };
40 enum { NumCommonBits = 3 };
41
42 bool scopeMayThrow;
43
44protected:
46 friend class EHCleanupScope;
47 unsigned : NumCommonBits;
48
49 /// Whether this cleanup needs to be run along normal edges.
50 unsigned isNormalCleanup : 1;
51
52 /// Whether this cleanup needs to be run along exception edges.
53 unsigned isEHCleanup : 1;
54
55 /// Whether this cleanup is currently active.
56 unsigned isActive : 1;
57
58 /// Whether this cleanup is a lifetime marker
59 unsigned isLifetimeMarker : 1;
60
61 /// Whether the normal cleanup should test the activation flag.
62 unsigned testFlagInNormalCleanup : 1;
63
64 /// Whether the EH cleanup should test the activation flag.
65 unsigned testFlagInEHCleanup : 1;
66
67 /// The amount of extra storage needed by the Cleanup.
68 /// Always a multiple of the scope-stack alignment.
69 unsigned cleanupSize : 12;
70 };
71
72 union {
73 CommonBitFields commonBits;
75 };
76
77public:
79
81 : enclosingEHScope(enclosingEHScope) {
82 commonBits.kind = kind;
83 }
84
85 Kind getKind() const { return static_cast<Kind>(commonBits.kind); }
86
87 bool mayThrow() const {
88 // Traditional LLVM codegen also checks for `!block->use_empty()`, but
89 // in CIRGen the block content is not important, just used as a way to
90 // signal `hasEHBranches`.
91 return scopeMayThrow;
92 }
93
94 void setMayThrow(bool mayThrow) { scopeMayThrow = mayThrow; }
95
97 return enclosingEHScope;
98 }
99};
100
101/// A cleanup scope which generates the cleanup blocks lazily.
102class alignas(EHScopeStack::ScopeStackAlignment) EHCleanupScope
103 : public EHScope {
104 /// The nearest normal cleanup scope enclosing this one.
105 EHScopeStack::stable_iterator enclosingNormal;
106
107 /// The dual entry/exit block along the normal edge. This is lazily
108 /// created if needed before the cleanup is popped.
109 mlir::Block *normalBlock = nullptr;
110
111 /// An optional boolean variable indicating whether this cleanup has been
112 /// activated yet.
113 Address activeFlag = Address::invalid();
114
115 /// Cleanup scope op that represent the current scope in CIR
116 cir::CleanupScopeOp cleanupScopeOp;
117
118public:
119 /// Gets the size required for a lazy cleanup scope with the given
120 /// cleanup-data requirements.
121 static size_t getSizeForCleanupSize(size_t size) {
122 return sizeof(EHCleanupScope) + size;
123 }
124
125 size_t getAllocatedSize() const {
126 return sizeof(EHCleanupScope) + cleanupBits.cleanupSize;
127 }
128
129 EHCleanupScope(bool isNormal, bool isEH, unsigned cleanupSize,
130 cir::CleanupScopeOp cleanupScopeOp,
131 EHScopeStack::stable_iterator enclosingNormal,
133 : EHScope(EHScope::Cleanup, enclosingEH),
134 enclosingNormal(enclosingNormal), cleanupScopeOp(cleanupScopeOp) {
135 cleanupBits.isNormalCleanup = isNormal;
136 cleanupBits.isEHCleanup = isEH;
137 cleanupBits.isActive = true;
138 cleanupBits.isLifetimeMarker = false;
139 cleanupBits.testFlagInNormalCleanup = false;
140 cleanupBits.testFlagInEHCleanup = false;
141 cleanupBits.cleanupSize = cleanupSize;
142
143 assert(cleanupBits.cleanupSize == cleanupSize && "cleanup size overflow");
144 }
145
146 void destroy() {}
147 // Objects of EHCleanupScope are not destructed. Use destroy().
148 ~EHCleanupScope() = delete;
149
150 mlir::Block *getNormalBlock() const { return normalBlock; }
151 void setNormalBlock(mlir::Block *bb) { normalBlock = bb; }
152
153 bool isNormalCleanup() const { return cleanupBits.isNormalCleanup; }
154 bool isEHCleanup() const { return cleanupBits.isEHCleanup; }
155
156 bool isActive() const { return cleanupBits.isActive; }
157 void setActive(bool isActive) { cleanupBits.isActive = isActive; }
158
159 bool isLifetimeMarker() const { return cleanupBits.isLifetimeMarker; }
160 void setLifetimeMarker() { cleanupBits.isLifetimeMarker = true; }
161
162 bool hasActiveFlag() const { return activeFlag.isValid(); }
163 Address getActiveFlag() const { return activeFlag; }
164 void setActiveFlag(Address var) { activeFlag = var; }
165
166 void setTestFlagInNormalCleanup(bool value) {
167 cleanupBits.testFlagInNormalCleanup = value;
168 }
170 return cleanupBits.testFlagInNormalCleanup;
171 }
172
173 void setTestFlagInEHCleanup(bool value) {
174 cleanupBits.testFlagInEHCleanup = value;
175 }
177 return cleanupBits.testFlagInEHCleanup;
178 }
179
181 return enclosingNormal;
182 }
183
184 size_t getCleanupSize() const { return cleanupBits.cleanupSize; }
185 void *getCleanupBuffer() { return this + 1; }
186
188 return reinterpret_cast<EHScopeStack::Cleanup *>(getCleanupBuffer());
189 }
190
191 cir::CleanupScopeOp getCleanupScopeOp() { return cleanupScopeOp; }
192
193 static bool classof(const EHScope *scope) {
194 return (scope->getKind() == Cleanup);
195 }
196
197 void markEmitted() {}
198};
199
200/// A non-stable pointer into the scope stack.
202 char *ptr = nullptr;
203
204 friend class EHScopeStack;
205 explicit iterator(char *ptr) : ptr(ptr) {}
206
207public:
208 iterator() = default;
209
210 EHScope *get() const { return reinterpret_cast<EHScope *>(ptr); }
211
212 EHScope *operator->() const { return get(); }
213 EHScope &operator*() const { return *get(); }
214
215 iterator &operator++() {
216 size_t size;
217 switch (get()->getKind()) {
218 case EHScope::Filter:
219 llvm_unreachable("EHScopeStack::iterator Filter");
220 break;
221
222 case EHScope::Cleanup:
223 size = static_cast<const EHCleanupScope *>(get())->getAllocatedSize();
224 break;
225
227 llvm_unreachable("EHScopeStack::iterator Terminate");
228 break;
229 }
230 ptr += llvm::alignTo(size, ScopeStackAlignment);
231 return *this;
232 }
233
234 bool operator==(iterator other) const { return ptr == other.ptr; }
235 bool operator!=(iterator other) const { return ptr != other.ptr; }
236};
237
239 return iterator(startOfData);
240}
241
243 return iterator(endOfBuffer);
244}
245
248 assert(savePoint.isValid() && "finding invalid savepoint");
249 assert(savePoint.size <= stable_begin().size &&
250 "finding savepoint after pop");
251 return iterator(endOfBuffer - savePoint.size);
252}
253
254/// The exceptions personality for a function.
256 const char *personalityFn = nullptr;
257
258 // If this is non-null, this personality requires a non-standard
259 // function for rethrowing an exception after a catchall cleanup.
260 // This function must have prototype void(void*).
261 const char *catchallRethrowFn = nullptr;
262
263 static const EHPersonality &get(CIRGenModule &cgm,
264 const clang::FunctionDecl *fd);
265 static const EHPersonality &get(CIRGenFunction &cgf);
266
267 static const EHPersonality GNU_C;
285
286 /// Does this personality use landingpads or the family of pad instructions
287 /// designed to form funclets?
288 bool usesFuncletPads() const {
290 }
291
292 bool isMSVCPersonality() const {
293 return this == &MSVC_except_handler || this == &MSVC_C_specific_handler ||
294 this == &MSVC_CxxFrameHandler3;
295 }
296
297 bool isWasmPersonality() const { return this == &GNU_Wasm_CPlusPlus; }
298
299 bool isMSVCXXPersonality() const { return this == &MSVC_CxxFrameHandler3; }
300};
301
302} // namespace clang::CIRGen
303#endif // CLANG_LIB_CIR_CODEGEN_CIRGENCLEANUP_H
static Decl::Kind getKind(const Decl *D)
*collection of selector each with an associated kind and an ordered *collection of selectors A selector has a kind
static Address invalid()
Definition Address.h:76
This class organizes the cross-function state that is used while generating CIR code.
A cleanup scope which generates the cleanup blocks lazily.
mlir::Block * getNormalBlock() const
EHScopeStack::Cleanup * getCleanup()
EHCleanupScope(bool isNormal, bool isEH, unsigned cleanupSize, cir::CleanupScopeOp cleanupScopeOp, EHScopeStack::stable_iterator enclosingNormal, EHScopeStack::stable_iterator enclosingEH)
void setTestFlagInEHCleanup(bool value)
void setTestFlagInNormalCleanup(bool value)
cir::CleanupScopeOp getCleanupScopeOp()
static bool classof(const EHScope *scope)
static size_t getSizeForCleanupSize(size_t size)
Gets the size required for a lazy cleanup scope with the given cleanup-data requirements.
void setActiveFlag(Address var)
EHScopeStack::stable_iterator getEnclosingNormalCleanup() const
bool shouldTestFlagInNormalCleanup() const
void setNormalBlock(mlir::Block *bb)
void setActive(bool isActive)
Information for lazily generating a cleanup.
A non-stable pointer into the scope stack.
bool operator!=(iterator other) const
bool operator==(iterator other) const
A saved depth on the scope stack.
iterator find(stable_iterator savePoint) const
Turn a stable reference to a scope depth into a unstable pointer to the EH stack.
stable_iterator stable_begin() const
Create a stable reference to the top of the EH stack.
iterator end() const
Returns an iterator pointing to the outermost EH scope.
iterator begin() const
Returns an iterator pointing to the innermost EH scope.
A protected scope for zero-cost EH handling.
CleanupBitFields cleanupBits
void setMayThrow(bool mayThrow)
EHScopeStack::stable_iterator getEnclosingEHScope() const
CommonBitFields commonBits
EHScope(Kind kind, EHScopeStack::stable_iterator enclosingEHScope)
Represents a function declaration or definition.
Definition Decl.h:2059
The MS C++ ABI needs a pointer to RTTI data plus some flags to describe the type of a catch handler,...
The exceptions personality for a function.
bool usesFuncletPads() const
Does this personality use landingpads or the family of pad instructions designed to form funclets?
static const EHPersonality XL_CPlusPlus
static const EHPersonality GNU_ObjC_SJLJ
static const EHPersonality ZOS_CPlusPlus
static const EHPersonality GNUstep_ObjC
static const EHPersonality MSVC_CxxFrameHandler3
static const EHPersonality MSVC_C_specific_handler
static const EHPersonality GNU_CPlusPlus_SEH
static const EHPersonality GNU_ObjC
static const EHPersonality GNU_CPlusPlus_SJLJ
static const EHPersonality GNU_C_SJLJ
static const EHPersonality GNU_C
static const EHPersonality NeXT_ObjC
static const EHPersonality & get(CIRGenModule &cgm, const clang::FunctionDecl *fd)
static const EHPersonality GNU_CPlusPlus
static const EHPersonality GNU_ObjCXX
static const EHPersonality GNU_C_SEH
static const EHPersonality MSVC_except_handler
static const EHPersonality GNU_ObjC_SEH
static const EHPersonality GNU_Wasm_CPlusPlus