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