clang 23.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
161 bool hasActiveFlag() const { return activeFlag.isValid(); }
162 Address getActiveFlag() const { return activeFlag; }
163 void setActiveFlag(Address var) { activeFlag = var; }
164
166 cleanupBits.testFlagInNormalCleanup = true;
167 }
169 return cleanupBits.testFlagInNormalCleanup;
170 }
171
172 void setTestFlagInEHCleanup() { cleanupBits.testFlagInEHCleanup = true; }
174 return cleanupBits.testFlagInEHCleanup;
175 }
176
178 return enclosingNormal;
179 }
180
181 size_t getCleanupSize() const { return cleanupBits.cleanupSize; }
182 void *getCleanupBuffer() { return this + 1; }
183
185 return reinterpret_cast<EHScopeStack::Cleanup *>(getCleanupBuffer());
186 }
187
188 cir::CleanupScopeOp getCleanupScopeOp() { return cleanupScopeOp; }
189
190 static bool classof(const EHScope *scope) {
191 return (scope->getKind() == Cleanup);
192 }
193
194 void markEmitted() {}
195};
196
197/// A non-stable pointer into the scope stack.
199 char *ptr = nullptr;
200
201 friend class EHScopeStack;
202 explicit iterator(char *ptr) : ptr(ptr) {}
203
204public:
205 iterator() = default;
206
207 EHScope *get() const { return reinterpret_cast<EHScope *>(ptr); }
208
209 EHScope *operator->() const { return get(); }
210 EHScope &operator*() const { return *get(); }
211
212 iterator &operator++() {
213 size_t size;
214 switch (get()->getKind()) {
215 case EHScope::Filter:
216 llvm_unreachable("EHScopeStack::iterator Filter");
217 break;
218
219 case EHScope::Cleanup:
220 size = static_cast<const EHCleanupScope *>(get())->getAllocatedSize();
221 break;
222
224 llvm_unreachable("EHScopeStack::iterator Terminate");
225 break;
226 }
227 ptr += llvm::alignTo(size, ScopeStackAlignment);
228 return *this;
229 }
230
231 bool operator==(iterator other) const { return ptr == other.ptr; }
232 bool operator!=(iterator other) const { return ptr != other.ptr; }
233};
234
236 return iterator(startOfData);
237}
238
240 return iterator(endOfBuffer);
241}
242
245 assert(savePoint.isValid() && "finding invalid savepoint");
246 assert(savePoint.size <= stable_begin().size &&
247 "finding savepoint after pop");
248 return iterator(endOfBuffer - savePoint.size);
249}
250
251/// The exceptions personality for a function.
253 const char *personalityFn = nullptr;
254
255 // If this is non-null, this personality requires a non-standard
256 // function for rethrowing an exception after a catchall cleanup.
257 // This function must have prototype void(void*).
258 const char *catchallRethrowFn = nullptr;
259
260 static const EHPersonality &get(CIRGenModule &cgm,
261 const clang::FunctionDecl *fd);
262 static const EHPersonality &get(CIRGenFunction &cgf);
263
264 static const EHPersonality GNU_C;
282
283 /// Does this personality use landingpads or the family of pad instructions
284 /// designed to form funclets?
285 bool usesFuncletPads() const {
287 }
288
289 bool isMSVCPersonality() const {
290 return this == &MSVC_except_handler || this == &MSVC_C_specific_handler ||
291 this == &MSVC_CxxFrameHandler3;
292 }
293
294 bool isWasmPersonality() const { return this == &GNU_Wasm_CPlusPlus; }
295
296 bool isMSVCXXPersonality() const { return this == &MSVC_CxxFrameHandler3; }
297};
298
299} // namespace clang::CIRGen
300#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:74
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)
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:2015
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