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 /// Cleanup scope op that represent the current scope in CIR
112 cir::CleanupScopeOp cleanupScopeOp;
113
114public:
115 /// Gets the size required for a lazy cleanup scope with the given
116 /// cleanup-data requirements.
117 static size_t getSizeForCleanupSize(size_t size) {
118 return sizeof(EHCleanupScope) + size;
119 }
120
121 size_t getAllocatedSize() const {
122 return sizeof(EHCleanupScope) + cleanupBits.cleanupSize;
123 }
124
125 EHCleanupScope(bool isNormal, bool isEH, unsigned cleanupSize,
126 cir::CleanupScopeOp cleanupScopeOp,
127 EHScopeStack::stable_iterator enclosingNormal,
129 : EHScope(EHScope::Cleanup, enclosingEH),
130 enclosingNormal(enclosingNormal), cleanupScopeOp(cleanupScopeOp) {
131 cleanupBits.isNormalCleanup = isNormal;
132 cleanupBits.isEHCleanup = isEH;
133 cleanupBits.isActive = true;
134 cleanupBits.isLifetimeMarker = false;
135 cleanupBits.testFlagInNormalCleanup = false;
136 cleanupBits.testFlagInEHCleanup = false;
137 cleanupBits.cleanupSize = cleanupSize;
138
139 assert(cleanupBits.cleanupSize == cleanupSize && "cleanup size overflow");
140 }
141
142 void destroy() {}
143 // Objects of EHCleanupScope are not destructed. Use destroy().
144 ~EHCleanupScope() = delete;
145
146 mlir::Block *getNormalBlock() const { return normalBlock; }
147 void setNormalBlock(mlir::Block *bb) { normalBlock = bb; }
148
149 bool isNormalCleanup() const { return cleanupBits.isNormalCleanup; }
150 bool isEHCleanup() const { return cleanupBits.isEHCleanup; }
151
152 bool isActive() const { return cleanupBits.isActive; }
153 void setActive(bool isActive) { cleanupBits.isActive = isActive; }
154
155 bool isLifetimeMarker() const { return cleanupBits.isLifetimeMarker; }
156
158 return enclosingNormal;
159 }
160
161 size_t getCleanupSize() const { return cleanupBits.cleanupSize; }
162 void *getCleanupBuffer() { return this + 1; }
163
165 return reinterpret_cast<EHScopeStack::Cleanup *>(getCleanupBuffer());
166 }
167
168 cir::CleanupScopeOp getCleanupScopeOp() { return cleanupScopeOp; }
169
170 static bool classof(const EHScope *scope) {
171 return (scope->getKind() == Cleanup);
172 }
173
174 void markEmitted() {}
175};
176
177/// A non-stable pointer into the scope stack.
179 char *ptr = nullptr;
180
181 friend class EHScopeStack;
182 explicit iterator(char *ptr) : ptr(ptr) {}
183
184public:
185 iterator() = default;
186
187 EHScope *get() const { return reinterpret_cast<EHScope *>(ptr); }
188
189 EHScope *operator->() const { return get(); }
190 EHScope &operator*() const { return *get(); }
191
192 iterator &operator++() {
193 size_t size;
194 switch (get()->getKind()) {
195 case EHScope::Filter:
196 llvm_unreachable("EHScopeStack::iterator Filter");
197 break;
198
199 case EHScope::Cleanup:
200 size = static_cast<const EHCleanupScope *>(get())->getAllocatedSize();
201 break;
202
204 llvm_unreachable("EHScopeStack::iterator Terminate");
205 break;
206 }
207 ptr += llvm::alignTo(size, ScopeStackAlignment);
208 return *this;
209 }
210
211 bool operator==(iterator other) const { return ptr == other.ptr; }
212 bool operator!=(iterator other) const { return ptr != other.ptr; }
213};
214
216 return iterator(startOfData);
217}
218
220 return iterator(endOfBuffer);
221}
222
225 assert(savePoint.isValid() && "finding invalid savepoint");
226 assert(savePoint.size <= stable_begin().size &&
227 "finding savepoint after pop");
228 return iterator(endOfBuffer - savePoint.size);
229}
230
231/// The exceptions personality for a function.
233 const char *personalityFn = nullptr;
234
235 // If this is non-null, this personality requires a non-standard
236 // function for rethrowing an exception after a catchall cleanup.
237 // This function must have prototype void(void*).
238 const char *catchallRethrowFn = nullptr;
239
240 static const EHPersonality &get(CIRGenModule &cgm,
241 const clang::FunctionDecl *fd);
242 static const EHPersonality &get(CIRGenFunction &cgf);
243
244 static const EHPersonality GNU_C;
262
263 /// Does this personality use landingpads or the family of pad instructions
264 /// designed to form funclets?
265 bool usesFuncletPads() const {
267 }
268
269 bool isMSVCPersonality() const {
270 return this == &MSVC_except_handler || this == &MSVC_C_specific_handler ||
271 this == &MSVC_CxxFrameHandler3;
272 }
273
274 bool isWasmPersonality() const { return this == &GNU_Wasm_CPlusPlus; }
275
276 bool isMSVCXXPersonality() const { return this == &MSVC_CxxFrameHandler3; }
277};
278
279} // namespace clang::CIRGen
280#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
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.
EHScopeStack::stable_iterator getEnclosingNormalCleanup() 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:2000
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