1e5dd7070Spatrick //===-- CGCleanup.h - Classes for cleanups IR generation --------*- C++ -*-===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // These classes support the generation of LLVM IR for cleanups.
10e5dd7070Spatrick //
11e5dd7070Spatrick //===----------------------------------------------------------------------===//
12e5dd7070Spatrick
13e5dd7070Spatrick #ifndef LLVM_CLANG_LIB_CODEGEN_CGCLEANUP_H
14e5dd7070Spatrick #define LLVM_CLANG_LIB_CODEGEN_CGCLEANUP_H
15e5dd7070Spatrick
16e5dd7070Spatrick #include "EHScopeStack.h"
17e5dd7070Spatrick
18e5dd7070Spatrick #include "Address.h"
19e5dd7070Spatrick #include "llvm/ADT/SmallPtrSet.h"
20e5dd7070Spatrick #include "llvm/ADT/SmallVector.h"
21e5dd7070Spatrick
22e5dd7070Spatrick namespace llvm {
23e5dd7070Spatrick class BasicBlock;
24e5dd7070Spatrick class Value;
25e5dd7070Spatrick class ConstantInt;
26e5dd7070Spatrick }
27e5dd7070Spatrick
28e5dd7070Spatrick namespace clang {
29e5dd7070Spatrick class FunctionDecl;
30e5dd7070Spatrick namespace CodeGen {
31e5dd7070Spatrick class CodeGenModule;
32e5dd7070Spatrick class CodeGenFunction;
33e5dd7070Spatrick
34e5dd7070Spatrick /// The MS C++ ABI needs a pointer to RTTI data plus some flags to describe the
35e5dd7070Spatrick /// type of a catch handler, so we use this wrapper.
36e5dd7070Spatrick struct CatchTypeInfo {
37e5dd7070Spatrick llvm::Constant *RTTI;
38e5dd7070Spatrick unsigned Flags;
39e5dd7070Spatrick };
40e5dd7070Spatrick
41e5dd7070Spatrick /// A protected scope for zero-cost EH handling.
42e5dd7070Spatrick class EHScope {
43e5dd7070Spatrick llvm::BasicBlock *CachedLandingPad;
44e5dd7070Spatrick llvm::BasicBlock *CachedEHDispatchBlock;
45e5dd7070Spatrick
46e5dd7070Spatrick EHScopeStack::stable_iterator EnclosingEHScope;
47e5dd7070Spatrick
48e5dd7070Spatrick class CommonBitFields {
49e5dd7070Spatrick friend class EHScope;
50e5dd7070Spatrick unsigned Kind : 3;
51e5dd7070Spatrick };
52e5dd7070Spatrick enum { NumCommonBits = 3 };
53e5dd7070Spatrick
54e5dd7070Spatrick protected:
55e5dd7070Spatrick class CatchBitFields {
56e5dd7070Spatrick friend class EHCatchScope;
57e5dd7070Spatrick unsigned : NumCommonBits;
58e5dd7070Spatrick
59e5dd7070Spatrick unsigned NumHandlers : 32 - NumCommonBits;
60e5dd7070Spatrick };
61e5dd7070Spatrick
62e5dd7070Spatrick class CleanupBitFields {
63e5dd7070Spatrick friend class EHCleanupScope;
64e5dd7070Spatrick unsigned : NumCommonBits;
65e5dd7070Spatrick
66e5dd7070Spatrick /// Whether this cleanup needs to be run along normal edges.
67e5dd7070Spatrick unsigned IsNormalCleanup : 1;
68e5dd7070Spatrick
69e5dd7070Spatrick /// Whether this cleanup needs to be run along exception edges.
70e5dd7070Spatrick unsigned IsEHCleanup : 1;
71e5dd7070Spatrick
72e5dd7070Spatrick /// Whether this cleanup is currently active.
73e5dd7070Spatrick unsigned IsActive : 1;
74e5dd7070Spatrick
75e5dd7070Spatrick /// Whether this cleanup is a lifetime marker
76e5dd7070Spatrick unsigned IsLifetimeMarker : 1;
77e5dd7070Spatrick
78e5dd7070Spatrick /// Whether the normal cleanup should test the activation flag.
79e5dd7070Spatrick unsigned TestFlagInNormalCleanup : 1;
80e5dd7070Spatrick
81e5dd7070Spatrick /// Whether the EH cleanup should test the activation flag.
82e5dd7070Spatrick unsigned TestFlagInEHCleanup : 1;
83e5dd7070Spatrick
84e5dd7070Spatrick /// The amount of extra storage needed by the Cleanup.
85e5dd7070Spatrick /// Always a multiple of the scope-stack alignment.
86e5dd7070Spatrick unsigned CleanupSize : 12;
87e5dd7070Spatrick };
88e5dd7070Spatrick
89e5dd7070Spatrick class FilterBitFields {
90e5dd7070Spatrick friend class EHFilterScope;
91e5dd7070Spatrick unsigned : NumCommonBits;
92e5dd7070Spatrick
93e5dd7070Spatrick unsigned NumFilters : 32 - NumCommonBits;
94e5dd7070Spatrick };
95e5dd7070Spatrick
96e5dd7070Spatrick union {
97e5dd7070Spatrick CommonBitFields CommonBits;
98e5dd7070Spatrick CatchBitFields CatchBits;
99e5dd7070Spatrick CleanupBitFields CleanupBits;
100e5dd7070Spatrick FilterBitFields FilterBits;
101e5dd7070Spatrick };
102e5dd7070Spatrick
103e5dd7070Spatrick public:
104ec727ea7Spatrick enum Kind { Cleanup, Catch, Terminate, Filter };
105e5dd7070Spatrick
EHScope(Kind kind,EHScopeStack::stable_iterator enclosingEHScope)106e5dd7070Spatrick EHScope(Kind kind, EHScopeStack::stable_iterator enclosingEHScope)
107e5dd7070Spatrick : CachedLandingPad(nullptr), CachedEHDispatchBlock(nullptr),
108e5dd7070Spatrick EnclosingEHScope(enclosingEHScope) {
109e5dd7070Spatrick CommonBits.Kind = kind;
110e5dd7070Spatrick }
111e5dd7070Spatrick
getKind()112e5dd7070Spatrick Kind getKind() const { return static_cast<Kind>(CommonBits.Kind); }
113e5dd7070Spatrick
getCachedLandingPad()114e5dd7070Spatrick llvm::BasicBlock *getCachedLandingPad() const {
115e5dd7070Spatrick return CachedLandingPad;
116e5dd7070Spatrick }
117e5dd7070Spatrick
setCachedLandingPad(llvm::BasicBlock * block)118e5dd7070Spatrick void setCachedLandingPad(llvm::BasicBlock *block) {
119e5dd7070Spatrick CachedLandingPad = block;
120e5dd7070Spatrick }
121e5dd7070Spatrick
getCachedEHDispatchBlock()122e5dd7070Spatrick llvm::BasicBlock *getCachedEHDispatchBlock() const {
123e5dd7070Spatrick return CachedEHDispatchBlock;
124e5dd7070Spatrick }
125e5dd7070Spatrick
setCachedEHDispatchBlock(llvm::BasicBlock * block)126e5dd7070Spatrick void setCachedEHDispatchBlock(llvm::BasicBlock *block) {
127e5dd7070Spatrick CachedEHDispatchBlock = block;
128e5dd7070Spatrick }
129e5dd7070Spatrick
hasEHBranches()130e5dd7070Spatrick bool hasEHBranches() const {
131e5dd7070Spatrick if (llvm::BasicBlock *block = getCachedEHDispatchBlock())
132e5dd7070Spatrick return !block->use_empty();
133e5dd7070Spatrick return false;
134e5dd7070Spatrick }
135e5dd7070Spatrick
getEnclosingEHScope()136e5dd7070Spatrick EHScopeStack::stable_iterator getEnclosingEHScope() const {
137e5dd7070Spatrick return EnclosingEHScope;
138e5dd7070Spatrick }
139e5dd7070Spatrick };
140e5dd7070Spatrick
141e5dd7070Spatrick /// A scope which attempts to handle some, possibly all, types of
142e5dd7070Spatrick /// exceptions.
143e5dd7070Spatrick ///
144e5dd7070Spatrick /// Objective C \@finally blocks are represented using a cleanup scope
145e5dd7070Spatrick /// after the catch scope.
146e5dd7070Spatrick class EHCatchScope : public EHScope {
147e5dd7070Spatrick // In effect, we have a flexible array member
148e5dd7070Spatrick // Handler Handlers[0];
149e5dd7070Spatrick // But that's only standard in C99, not C++, so we have to do
150e5dd7070Spatrick // annoying pointer arithmetic instead.
151e5dd7070Spatrick
152e5dd7070Spatrick public:
153e5dd7070Spatrick struct Handler {
154e5dd7070Spatrick /// A type info value, or null (C++ null, not an LLVM null pointer)
155e5dd7070Spatrick /// for a catch-all.
156e5dd7070Spatrick CatchTypeInfo Type;
157e5dd7070Spatrick
158e5dd7070Spatrick /// The catch handler for this type.
159e5dd7070Spatrick llvm::BasicBlock *Block;
160e5dd7070Spatrick
isCatchAllHandler161e5dd7070Spatrick bool isCatchAll() const { return Type.RTTI == nullptr; }
162e5dd7070Spatrick };
163e5dd7070Spatrick
164e5dd7070Spatrick private:
165e5dd7070Spatrick friend class EHScopeStack;
166e5dd7070Spatrick
getHandlers()167e5dd7070Spatrick Handler *getHandlers() {
168e5dd7070Spatrick return reinterpret_cast<Handler*>(this+1);
169e5dd7070Spatrick }
170e5dd7070Spatrick
getHandlers()171e5dd7070Spatrick const Handler *getHandlers() const {
172e5dd7070Spatrick return reinterpret_cast<const Handler*>(this+1);
173e5dd7070Spatrick }
174e5dd7070Spatrick
175e5dd7070Spatrick public:
getSizeForNumHandlers(unsigned N)176e5dd7070Spatrick static size_t getSizeForNumHandlers(unsigned N) {
177e5dd7070Spatrick return sizeof(EHCatchScope) + N * sizeof(Handler);
178e5dd7070Spatrick }
179e5dd7070Spatrick
EHCatchScope(unsigned numHandlers,EHScopeStack::stable_iterator enclosingEHScope)180e5dd7070Spatrick EHCatchScope(unsigned numHandlers,
181e5dd7070Spatrick EHScopeStack::stable_iterator enclosingEHScope)
182e5dd7070Spatrick : EHScope(Catch, enclosingEHScope) {
183e5dd7070Spatrick CatchBits.NumHandlers = numHandlers;
184e5dd7070Spatrick assert(CatchBits.NumHandlers == numHandlers && "NumHandlers overflow?");
185e5dd7070Spatrick }
186e5dd7070Spatrick
getNumHandlers()187e5dd7070Spatrick unsigned getNumHandlers() const {
188e5dd7070Spatrick return CatchBits.NumHandlers;
189e5dd7070Spatrick }
190e5dd7070Spatrick
setCatchAllHandler(unsigned I,llvm::BasicBlock * Block)191e5dd7070Spatrick void setCatchAllHandler(unsigned I, llvm::BasicBlock *Block) {
192e5dd7070Spatrick setHandler(I, CatchTypeInfo{nullptr, 0}, Block);
193e5dd7070Spatrick }
194e5dd7070Spatrick
setHandler(unsigned I,llvm::Constant * Type,llvm::BasicBlock * Block)195e5dd7070Spatrick void setHandler(unsigned I, llvm::Constant *Type, llvm::BasicBlock *Block) {
196e5dd7070Spatrick assert(I < getNumHandlers());
197e5dd7070Spatrick getHandlers()[I].Type = CatchTypeInfo{Type, 0};
198e5dd7070Spatrick getHandlers()[I].Block = Block;
199e5dd7070Spatrick }
200e5dd7070Spatrick
setHandler(unsigned I,CatchTypeInfo Type,llvm::BasicBlock * Block)201e5dd7070Spatrick void setHandler(unsigned I, CatchTypeInfo Type, llvm::BasicBlock *Block) {
202e5dd7070Spatrick assert(I < getNumHandlers());
203e5dd7070Spatrick getHandlers()[I].Type = Type;
204e5dd7070Spatrick getHandlers()[I].Block = Block;
205e5dd7070Spatrick }
206e5dd7070Spatrick
getHandler(unsigned I)207e5dd7070Spatrick const Handler &getHandler(unsigned I) const {
208e5dd7070Spatrick assert(I < getNumHandlers());
209e5dd7070Spatrick return getHandlers()[I];
210e5dd7070Spatrick }
211e5dd7070Spatrick
212e5dd7070Spatrick // Clear all handler blocks.
213e5dd7070Spatrick // FIXME: it's better to always call clearHandlerBlocks in DTOR and have a
214e5dd7070Spatrick // 'takeHandler' or some such function which removes ownership from the
215e5dd7070Spatrick // EHCatchScope object if the handlers should live longer than EHCatchScope.
clearHandlerBlocks()216e5dd7070Spatrick void clearHandlerBlocks() {
217e5dd7070Spatrick for (unsigned I = 0, N = getNumHandlers(); I != N; ++I)
218e5dd7070Spatrick delete getHandler(I).Block;
219e5dd7070Spatrick }
220e5dd7070Spatrick
221e5dd7070Spatrick typedef const Handler *iterator;
begin()222e5dd7070Spatrick iterator begin() const { return getHandlers(); }
end()223e5dd7070Spatrick iterator end() const { return getHandlers() + getNumHandlers(); }
224e5dd7070Spatrick
classof(const EHScope * Scope)225e5dd7070Spatrick static bool classof(const EHScope *Scope) {
226e5dd7070Spatrick return Scope->getKind() == Catch;
227e5dd7070Spatrick }
228e5dd7070Spatrick };
229e5dd7070Spatrick
230e5dd7070Spatrick /// A cleanup scope which generates the cleanup blocks lazily.
231e5dd7070Spatrick class alignas(8) EHCleanupScope : public EHScope {
232e5dd7070Spatrick /// The nearest normal cleanup scope enclosing this one.
233e5dd7070Spatrick EHScopeStack::stable_iterator EnclosingNormal;
234e5dd7070Spatrick
235e5dd7070Spatrick /// The nearest EH scope enclosing this one.
236e5dd7070Spatrick EHScopeStack::stable_iterator EnclosingEH;
237e5dd7070Spatrick
238e5dd7070Spatrick /// The dual entry/exit block along the normal edge. This is lazily
239e5dd7070Spatrick /// created if needed before the cleanup is popped.
240e5dd7070Spatrick llvm::BasicBlock *NormalBlock;
241e5dd7070Spatrick
242e5dd7070Spatrick /// An optional i1 variable indicating whether this cleanup has been
243e5dd7070Spatrick /// activated yet.
244*12c85518Srobert Address ActiveFlag;
245e5dd7070Spatrick
246e5dd7070Spatrick /// Extra information required for cleanups that have resolved
247e5dd7070Spatrick /// branches through them. This has to be allocated on the side
248e5dd7070Spatrick /// because everything on the cleanup stack has be trivially
249e5dd7070Spatrick /// movable.
250e5dd7070Spatrick struct ExtInfo {
251e5dd7070Spatrick /// The destinations of normal branch-afters and branch-throughs.
252e5dd7070Spatrick llvm::SmallPtrSet<llvm::BasicBlock*, 4> Branches;
253e5dd7070Spatrick
254e5dd7070Spatrick /// Normal branch-afters.
255e5dd7070Spatrick SmallVector<std::pair<llvm::BasicBlock*,llvm::ConstantInt*>, 4>
256e5dd7070Spatrick BranchAfters;
257e5dd7070Spatrick };
258e5dd7070Spatrick mutable struct ExtInfo *ExtInfo;
259e5dd7070Spatrick
260e5dd7070Spatrick /// The number of fixups required by enclosing scopes (not including
261e5dd7070Spatrick /// this one). If this is the top cleanup scope, all the fixups
262e5dd7070Spatrick /// from this index onwards belong to this scope.
263e5dd7070Spatrick unsigned FixupDepth;
264e5dd7070Spatrick
getExtInfo()265e5dd7070Spatrick struct ExtInfo &getExtInfo() {
266e5dd7070Spatrick if (!ExtInfo) ExtInfo = new struct ExtInfo();
267e5dd7070Spatrick return *ExtInfo;
268e5dd7070Spatrick }
269e5dd7070Spatrick
getExtInfo()270e5dd7070Spatrick const struct ExtInfo &getExtInfo() const {
271e5dd7070Spatrick if (!ExtInfo) ExtInfo = new struct ExtInfo();
272e5dd7070Spatrick return *ExtInfo;
273e5dd7070Spatrick }
274e5dd7070Spatrick
275e5dd7070Spatrick public:
276e5dd7070Spatrick /// Gets the size required for a lazy cleanup scope with the given
277e5dd7070Spatrick /// cleanup-data requirements.
getSizeForCleanupSize(size_t Size)278e5dd7070Spatrick static size_t getSizeForCleanupSize(size_t Size) {
279e5dd7070Spatrick return sizeof(EHCleanupScope) + Size;
280e5dd7070Spatrick }
281e5dd7070Spatrick
getAllocatedSize()282e5dd7070Spatrick size_t getAllocatedSize() const {
283e5dd7070Spatrick return sizeof(EHCleanupScope) + CleanupBits.CleanupSize;
284e5dd7070Spatrick }
285e5dd7070Spatrick
EHCleanupScope(bool isNormal,bool isEH,unsigned cleanupSize,unsigned fixupDepth,EHScopeStack::stable_iterator enclosingNormal,EHScopeStack::stable_iterator enclosingEH)286ec727ea7Spatrick EHCleanupScope(bool isNormal, bool isEH, unsigned cleanupSize,
287ec727ea7Spatrick unsigned fixupDepth,
288e5dd7070Spatrick EHScopeStack::stable_iterator enclosingNormal,
289e5dd7070Spatrick EHScopeStack::stable_iterator enclosingEH)
290e5dd7070Spatrick : EHScope(EHScope::Cleanup, enclosingEH),
291e5dd7070Spatrick EnclosingNormal(enclosingNormal), NormalBlock(nullptr),
292*12c85518Srobert ActiveFlag(Address::invalid()), ExtInfo(nullptr),
293*12c85518Srobert FixupDepth(fixupDepth) {
294e5dd7070Spatrick CleanupBits.IsNormalCleanup = isNormal;
295e5dd7070Spatrick CleanupBits.IsEHCleanup = isEH;
296ec727ea7Spatrick CleanupBits.IsActive = true;
297e5dd7070Spatrick CleanupBits.IsLifetimeMarker = false;
298e5dd7070Spatrick CleanupBits.TestFlagInNormalCleanup = false;
299e5dd7070Spatrick CleanupBits.TestFlagInEHCleanup = false;
300e5dd7070Spatrick CleanupBits.CleanupSize = cleanupSize;
301e5dd7070Spatrick
302e5dd7070Spatrick assert(CleanupBits.CleanupSize == cleanupSize && "cleanup size overflow");
303e5dd7070Spatrick }
304e5dd7070Spatrick
Destroy()305e5dd7070Spatrick void Destroy() {
306e5dd7070Spatrick delete ExtInfo;
307e5dd7070Spatrick }
308e5dd7070Spatrick // Objects of EHCleanupScope are not destructed. Use Destroy().
309e5dd7070Spatrick ~EHCleanupScope() = delete;
310e5dd7070Spatrick
isNormalCleanup()311e5dd7070Spatrick bool isNormalCleanup() const { return CleanupBits.IsNormalCleanup; }
getNormalBlock()312e5dd7070Spatrick llvm::BasicBlock *getNormalBlock() const { return NormalBlock; }
setNormalBlock(llvm::BasicBlock * BB)313e5dd7070Spatrick void setNormalBlock(llvm::BasicBlock *BB) { NormalBlock = BB; }
314e5dd7070Spatrick
isEHCleanup()315e5dd7070Spatrick bool isEHCleanup() const { return CleanupBits.IsEHCleanup; }
316e5dd7070Spatrick
isActive()317e5dd7070Spatrick bool isActive() const { return CleanupBits.IsActive; }
setActive(bool A)318e5dd7070Spatrick void setActive(bool A) { CleanupBits.IsActive = A; }
319e5dd7070Spatrick
isLifetimeMarker()320e5dd7070Spatrick bool isLifetimeMarker() const { return CleanupBits.IsLifetimeMarker; }
setLifetimeMarker()321e5dd7070Spatrick void setLifetimeMarker() { CleanupBits.IsLifetimeMarker = true; }
322e5dd7070Spatrick
hasActiveFlag()323*12c85518Srobert bool hasActiveFlag() const { return ActiveFlag.isValid(); }
getActiveFlag()324e5dd7070Spatrick Address getActiveFlag() const {
325*12c85518Srobert return ActiveFlag;
326e5dd7070Spatrick }
setActiveFlag(Address Var)327e5dd7070Spatrick void setActiveFlag(Address Var) {
328e5dd7070Spatrick assert(Var.getAlignment().isOne());
329*12c85518Srobert ActiveFlag = Var;
330e5dd7070Spatrick }
331e5dd7070Spatrick
setTestFlagInNormalCleanup()332e5dd7070Spatrick void setTestFlagInNormalCleanup() {
333e5dd7070Spatrick CleanupBits.TestFlagInNormalCleanup = true;
334e5dd7070Spatrick }
shouldTestFlagInNormalCleanup()335e5dd7070Spatrick bool shouldTestFlagInNormalCleanup() const {
336e5dd7070Spatrick return CleanupBits.TestFlagInNormalCleanup;
337e5dd7070Spatrick }
338e5dd7070Spatrick
setTestFlagInEHCleanup()339e5dd7070Spatrick void setTestFlagInEHCleanup() {
340e5dd7070Spatrick CleanupBits.TestFlagInEHCleanup = true;
341e5dd7070Spatrick }
shouldTestFlagInEHCleanup()342e5dd7070Spatrick bool shouldTestFlagInEHCleanup() const {
343e5dd7070Spatrick return CleanupBits.TestFlagInEHCleanup;
344e5dd7070Spatrick }
345e5dd7070Spatrick
getFixupDepth()346e5dd7070Spatrick unsigned getFixupDepth() const { return FixupDepth; }
getEnclosingNormalCleanup()347e5dd7070Spatrick EHScopeStack::stable_iterator getEnclosingNormalCleanup() const {
348e5dd7070Spatrick return EnclosingNormal;
349e5dd7070Spatrick }
350e5dd7070Spatrick
getCleanupSize()351e5dd7070Spatrick size_t getCleanupSize() const { return CleanupBits.CleanupSize; }
getCleanupBuffer()352e5dd7070Spatrick void *getCleanupBuffer() { return this + 1; }
353e5dd7070Spatrick
getCleanup()354e5dd7070Spatrick EHScopeStack::Cleanup *getCleanup() {
355e5dd7070Spatrick return reinterpret_cast<EHScopeStack::Cleanup*>(getCleanupBuffer());
356e5dd7070Spatrick }
357e5dd7070Spatrick
358e5dd7070Spatrick /// True if this cleanup scope has any branch-afters or branch-throughs.
hasBranches()359e5dd7070Spatrick bool hasBranches() const { return ExtInfo && !ExtInfo->Branches.empty(); }
360e5dd7070Spatrick
361e5dd7070Spatrick /// Add a branch-after to this cleanup scope. A branch-after is a
362e5dd7070Spatrick /// branch from a point protected by this (normal) cleanup to a
363e5dd7070Spatrick /// point in the normal cleanup scope immediately containing it.
364e5dd7070Spatrick /// For example,
365e5dd7070Spatrick /// for (;;) { A a; break; }
366e5dd7070Spatrick /// contains a branch-after.
367e5dd7070Spatrick ///
368e5dd7070Spatrick /// Branch-afters each have their own destination out of the
369e5dd7070Spatrick /// cleanup, guaranteed distinct from anything else threaded through
370e5dd7070Spatrick /// it. Therefore branch-afters usually force a switch after the
371e5dd7070Spatrick /// cleanup.
addBranchAfter(llvm::ConstantInt * Index,llvm::BasicBlock * Block)372e5dd7070Spatrick void addBranchAfter(llvm::ConstantInt *Index,
373e5dd7070Spatrick llvm::BasicBlock *Block) {
374e5dd7070Spatrick struct ExtInfo &ExtInfo = getExtInfo();
375e5dd7070Spatrick if (ExtInfo.Branches.insert(Block).second)
376e5dd7070Spatrick ExtInfo.BranchAfters.push_back(std::make_pair(Block, Index));
377e5dd7070Spatrick }
378e5dd7070Spatrick
379e5dd7070Spatrick /// Return the number of unique branch-afters on this scope.
getNumBranchAfters()380e5dd7070Spatrick unsigned getNumBranchAfters() const {
381e5dd7070Spatrick return ExtInfo ? ExtInfo->BranchAfters.size() : 0;
382e5dd7070Spatrick }
383e5dd7070Spatrick
getBranchAfterBlock(unsigned I)384e5dd7070Spatrick llvm::BasicBlock *getBranchAfterBlock(unsigned I) const {
385e5dd7070Spatrick assert(I < getNumBranchAfters());
386e5dd7070Spatrick return ExtInfo->BranchAfters[I].first;
387e5dd7070Spatrick }
388e5dd7070Spatrick
getBranchAfterIndex(unsigned I)389e5dd7070Spatrick llvm::ConstantInt *getBranchAfterIndex(unsigned I) const {
390e5dd7070Spatrick assert(I < getNumBranchAfters());
391e5dd7070Spatrick return ExtInfo->BranchAfters[I].second;
392e5dd7070Spatrick }
393e5dd7070Spatrick
394e5dd7070Spatrick /// Add a branch-through to this cleanup scope. A branch-through is
395e5dd7070Spatrick /// a branch from a scope protected by this (normal) cleanup to an
396e5dd7070Spatrick /// enclosing scope other than the immediately-enclosing normal
397e5dd7070Spatrick /// cleanup scope.
398e5dd7070Spatrick ///
399e5dd7070Spatrick /// In the following example, the branch through B's scope is a
400e5dd7070Spatrick /// branch-through, while the branch through A's scope is a
401e5dd7070Spatrick /// branch-after:
402e5dd7070Spatrick /// for (;;) { A a; B b; break; }
403e5dd7070Spatrick ///
404e5dd7070Spatrick /// All branch-throughs have a common destination out of the
405e5dd7070Spatrick /// cleanup, one possibly shared with the fall-through. Therefore
406e5dd7070Spatrick /// branch-throughs usually don't force a switch after the cleanup.
407e5dd7070Spatrick ///
408e5dd7070Spatrick /// \return true if the branch-through was new to this scope
addBranchThrough(llvm::BasicBlock * Block)409e5dd7070Spatrick bool addBranchThrough(llvm::BasicBlock *Block) {
410e5dd7070Spatrick return getExtInfo().Branches.insert(Block).second;
411e5dd7070Spatrick }
412e5dd7070Spatrick
413e5dd7070Spatrick /// Determines if this cleanup scope has any branch throughs.
hasBranchThroughs()414e5dd7070Spatrick bool hasBranchThroughs() const {
415e5dd7070Spatrick if (!ExtInfo) return false;
416e5dd7070Spatrick return (ExtInfo->BranchAfters.size() != ExtInfo->Branches.size());
417e5dd7070Spatrick }
418e5dd7070Spatrick
classof(const EHScope * Scope)419e5dd7070Spatrick static bool classof(const EHScope *Scope) {
420e5dd7070Spatrick return (Scope->getKind() == Cleanup);
421e5dd7070Spatrick }
422e5dd7070Spatrick };
423e5dd7070Spatrick // NOTE: there's a bunch of different data classes tacked on after an
424e5dd7070Spatrick // EHCleanupScope. It is asserted (in EHScopeStack::pushCleanup*) that
425e5dd7070Spatrick // they don't require greater alignment than ScopeStackAlignment. So,
426e5dd7070Spatrick // EHCleanupScope ought to have alignment equal to that -- not more
427e5dd7070Spatrick // (would be misaligned by the stack allocator), and not less (would
428e5dd7070Spatrick // break the appended classes).
429e5dd7070Spatrick static_assert(alignof(EHCleanupScope) == EHScopeStack::ScopeStackAlignment,
430e5dd7070Spatrick "EHCleanupScope expected alignment");
431e5dd7070Spatrick
432e5dd7070Spatrick /// An exceptions scope which filters exceptions thrown through it.
433e5dd7070Spatrick /// Only exceptions matching the filter types will be permitted to be
434e5dd7070Spatrick /// thrown.
435e5dd7070Spatrick ///
436e5dd7070Spatrick /// This is used to implement C++ exception specifications.
437e5dd7070Spatrick class EHFilterScope : public EHScope {
438e5dd7070Spatrick // Essentially ends in a flexible array member:
439e5dd7070Spatrick // llvm::Value *FilterTypes[0];
440e5dd7070Spatrick
getFilters()441e5dd7070Spatrick llvm::Value **getFilters() {
442e5dd7070Spatrick return reinterpret_cast<llvm::Value**>(this+1);
443e5dd7070Spatrick }
444e5dd7070Spatrick
getFilters()445e5dd7070Spatrick llvm::Value * const *getFilters() const {
446e5dd7070Spatrick return reinterpret_cast<llvm::Value* const *>(this+1);
447e5dd7070Spatrick }
448e5dd7070Spatrick
449e5dd7070Spatrick public:
EHFilterScope(unsigned numFilters)450e5dd7070Spatrick EHFilterScope(unsigned numFilters)
451e5dd7070Spatrick : EHScope(Filter, EHScopeStack::stable_end()) {
452e5dd7070Spatrick FilterBits.NumFilters = numFilters;
453e5dd7070Spatrick assert(FilterBits.NumFilters == numFilters && "NumFilters overflow");
454e5dd7070Spatrick }
455e5dd7070Spatrick
getSizeForNumFilters(unsigned numFilters)456e5dd7070Spatrick static size_t getSizeForNumFilters(unsigned numFilters) {
457e5dd7070Spatrick return sizeof(EHFilterScope) + numFilters * sizeof(llvm::Value*);
458e5dd7070Spatrick }
459e5dd7070Spatrick
getNumFilters()460e5dd7070Spatrick unsigned getNumFilters() const { return FilterBits.NumFilters; }
461e5dd7070Spatrick
setFilter(unsigned i,llvm::Value * filterValue)462e5dd7070Spatrick void setFilter(unsigned i, llvm::Value *filterValue) {
463e5dd7070Spatrick assert(i < getNumFilters());
464e5dd7070Spatrick getFilters()[i] = filterValue;
465e5dd7070Spatrick }
466e5dd7070Spatrick
getFilter(unsigned i)467e5dd7070Spatrick llvm::Value *getFilter(unsigned i) const {
468e5dd7070Spatrick assert(i < getNumFilters());
469e5dd7070Spatrick return getFilters()[i];
470e5dd7070Spatrick }
471e5dd7070Spatrick
classof(const EHScope * scope)472e5dd7070Spatrick static bool classof(const EHScope *scope) {
473e5dd7070Spatrick return scope->getKind() == Filter;
474e5dd7070Spatrick }
475e5dd7070Spatrick };
476e5dd7070Spatrick
477e5dd7070Spatrick /// An exceptions scope which calls std::terminate if any exception
478e5dd7070Spatrick /// reaches it.
479e5dd7070Spatrick class EHTerminateScope : public EHScope {
480e5dd7070Spatrick public:
EHTerminateScope(EHScopeStack::stable_iterator enclosingEHScope)481e5dd7070Spatrick EHTerminateScope(EHScopeStack::stable_iterator enclosingEHScope)
482e5dd7070Spatrick : EHScope(Terminate, enclosingEHScope) {}
getSize()483e5dd7070Spatrick static size_t getSize() { return sizeof(EHTerminateScope); }
484e5dd7070Spatrick
classof(const EHScope * scope)485e5dd7070Spatrick static bool classof(const EHScope *scope) {
486e5dd7070Spatrick return scope->getKind() == Terminate;
487e5dd7070Spatrick }
488e5dd7070Spatrick };
489e5dd7070Spatrick
490e5dd7070Spatrick /// A non-stable pointer into the scope stack.
491e5dd7070Spatrick class EHScopeStack::iterator {
492e5dd7070Spatrick char *Ptr;
493e5dd7070Spatrick
494e5dd7070Spatrick friend class EHScopeStack;
iterator(char * Ptr)495e5dd7070Spatrick explicit iterator(char *Ptr) : Ptr(Ptr) {}
496e5dd7070Spatrick
497e5dd7070Spatrick public:
iterator()498e5dd7070Spatrick iterator() : Ptr(nullptr) {}
499e5dd7070Spatrick
get()500e5dd7070Spatrick EHScope *get() const {
501e5dd7070Spatrick return reinterpret_cast<EHScope*>(Ptr);
502e5dd7070Spatrick }
503e5dd7070Spatrick
504e5dd7070Spatrick EHScope *operator->() const { return get(); }
505e5dd7070Spatrick EHScope &operator*() const { return *get(); }
506e5dd7070Spatrick
507e5dd7070Spatrick iterator &operator++() {
508e5dd7070Spatrick size_t Size;
509e5dd7070Spatrick switch (get()->getKind()) {
510e5dd7070Spatrick case EHScope::Catch:
511e5dd7070Spatrick Size = EHCatchScope::getSizeForNumHandlers(
512e5dd7070Spatrick static_cast<const EHCatchScope *>(get())->getNumHandlers());
513e5dd7070Spatrick break;
514e5dd7070Spatrick
515e5dd7070Spatrick case EHScope::Filter:
516e5dd7070Spatrick Size = EHFilterScope::getSizeForNumFilters(
517e5dd7070Spatrick static_cast<const EHFilterScope *>(get())->getNumFilters());
518e5dd7070Spatrick break;
519e5dd7070Spatrick
520e5dd7070Spatrick case EHScope::Cleanup:
521e5dd7070Spatrick Size = static_cast<const EHCleanupScope *>(get())->getAllocatedSize();
522e5dd7070Spatrick break;
523e5dd7070Spatrick
524e5dd7070Spatrick case EHScope::Terminate:
525e5dd7070Spatrick Size = EHTerminateScope::getSize();
526e5dd7070Spatrick break;
527e5dd7070Spatrick }
528e5dd7070Spatrick Ptr += llvm::alignTo(Size, ScopeStackAlignment);
529e5dd7070Spatrick return *this;
530e5dd7070Spatrick }
531e5dd7070Spatrick
next()532e5dd7070Spatrick iterator next() {
533e5dd7070Spatrick iterator copy = *this;
534e5dd7070Spatrick ++copy;
535e5dd7070Spatrick return copy;
536e5dd7070Spatrick }
537e5dd7070Spatrick
538e5dd7070Spatrick iterator operator++(int) {
539e5dd7070Spatrick iterator copy = *this;
540e5dd7070Spatrick operator++();
541e5dd7070Spatrick return copy;
542e5dd7070Spatrick }
543e5dd7070Spatrick
encloses(iterator other)544e5dd7070Spatrick bool encloses(iterator other) const { return Ptr >= other.Ptr; }
strictlyEncloses(iterator other)545e5dd7070Spatrick bool strictlyEncloses(iterator other) const { return Ptr > other.Ptr; }
546e5dd7070Spatrick
547e5dd7070Spatrick bool operator==(iterator other) const { return Ptr == other.Ptr; }
548e5dd7070Spatrick bool operator!=(iterator other) const { return Ptr != other.Ptr; }
549e5dd7070Spatrick };
550e5dd7070Spatrick
begin()551e5dd7070Spatrick inline EHScopeStack::iterator EHScopeStack::begin() const {
552e5dd7070Spatrick return iterator(StartOfData);
553e5dd7070Spatrick }
554e5dd7070Spatrick
end()555e5dd7070Spatrick inline EHScopeStack::iterator EHScopeStack::end() const {
556e5dd7070Spatrick return iterator(EndOfBuffer);
557e5dd7070Spatrick }
558e5dd7070Spatrick
popCatch()559e5dd7070Spatrick inline void EHScopeStack::popCatch() {
560e5dd7070Spatrick assert(!empty() && "popping exception stack when not empty");
561e5dd7070Spatrick
562e5dd7070Spatrick EHCatchScope &scope = cast<EHCatchScope>(*begin());
563e5dd7070Spatrick InnermostEHScope = scope.getEnclosingEHScope();
564e5dd7070Spatrick deallocate(EHCatchScope::getSizeForNumHandlers(scope.getNumHandlers()));
565e5dd7070Spatrick }
566e5dd7070Spatrick
popTerminate()567e5dd7070Spatrick inline void EHScopeStack::popTerminate() {
568e5dd7070Spatrick assert(!empty() && "popping exception stack when not empty");
569e5dd7070Spatrick
570e5dd7070Spatrick EHTerminateScope &scope = cast<EHTerminateScope>(*begin());
571e5dd7070Spatrick InnermostEHScope = scope.getEnclosingEHScope();
572e5dd7070Spatrick deallocate(EHTerminateScope::getSize());
573e5dd7070Spatrick }
574e5dd7070Spatrick
find(stable_iterator sp)575e5dd7070Spatrick inline EHScopeStack::iterator EHScopeStack::find(stable_iterator sp) const {
576e5dd7070Spatrick assert(sp.isValid() && "finding invalid savepoint");
577e5dd7070Spatrick assert(sp.Size <= stable_begin().Size && "finding savepoint after pop");
578e5dd7070Spatrick return iterator(EndOfBuffer - sp.Size);
579e5dd7070Spatrick }
580e5dd7070Spatrick
581e5dd7070Spatrick inline EHScopeStack::stable_iterator
stabilize(iterator ir)582e5dd7070Spatrick EHScopeStack::stabilize(iterator ir) const {
583e5dd7070Spatrick assert(StartOfData <= ir.Ptr && ir.Ptr <= EndOfBuffer);
584e5dd7070Spatrick return stable_iterator(EndOfBuffer - ir.Ptr);
585e5dd7070Spatrick }
586e5dd7070Spatrick
587e5dd7070Spatrick /// The exceptions personality for a function.
588e5dd7070Spatrick struct EHPersonality {
589e5dd7070Spatrick const char *PersonalityFn;
590e5dd7070Spatrick
591e5dd7070Spatrick // If this is non-null, this personality requires a non-standard
592e5dd7070Spatrick // function for rethrowing an exception after a catchall cleanup.
593e5dd7070Spatrick // This function must have prototype void(void*).
594e5dd7070Spatrick const char *CatchallRethrowFn;
595e5dd7070Spatrick
596e5dd7070Spatrick static const EHPersonality &get(CodeGenModule &CGM, const FunctionDecl *FD);
597e5dd7070Spatrick static const EHPersonality &get(CodeGenFunction &CGF);
598e5dd7070Spatrick
599e5dd7070Spatrick static const EHPersonality GNU_C;
600e5dd7070Spatrick static const EHPersonality GNU_C_SJLJ;
601e5dd7070Spatrick static const EHPersonality GNU_C_SEH;
602e5dd7070Spatrick static const EHPersonality GNU_ObjC;
603e5dd7070Spatrick static const EHPersonality GNU_ObjC_SJLJ;
604e5dd7070Spatrick static const EHPersonality GNU_ObjC_SEH;
605e5dd7070Spatrick static const EHPersonality GNUstep_ObjC;
606e5dd7070Spatrick static const EHPersonality GNU_ObjCXX;
607e5dd7070Spatrick static const EHPersonality NeXT_ObjC;
608e5dd7070Spatrick static const EHPersonality GNU_CPlusPlus;
609e5dd7070Spatrick static const EHPersonality GNU_CPlusPlus_SJLJ;
610e5dd7070Spatrick static const EHPersonality GNU_CPlusPlus_SEH;
611e5dd7070Spatrick static const EHPersonality MSVC_except_handler;
612e5dd7070Spatrick static const EHPersonality MSVC_C_specific_handler;
613e5dd7070Spatrick static const EHPersonality MSVC_CxxFrameHandler3;
614e5dd7070Spatrick static const EHPersonality GNU_Wasm_CPlusPlus;
615a9ac8606Spatrick static const EHPersonality XL_CPlusPlus;
616e5dd7070Spatrick
617e5dd7070Spatrick /// Does this personality use landingpads or the family of pad instructions
618e5dd7070Spatrick /// designed to form funclets?
usesFuncletPadsEHPersonality619e5dd7070Spatrick bool usesFuncletPads() const {
620e5dd7070Spatrick return isMSVCPersonality() || isWasmPersonality();
621e5dd7070Spatrick }
622e5dd7070Spatrick
isMSVCPersonalityEHPersonality623e5dd7070Spatrick bool isMSVCPersonality() const {
624e5dd7070Spatrick return this == &MSVC_except_handler || this == &MSVC_C_specific_handler ||
625e5dd7070Spatrick this == &MSVC_CxxFrameHandler3;
626e5dd7070Spatrick }
627e5dd7070Spatrick
isWasmPersonalityEHPersonality628e5dd7070Spatrick bool isWasmPersonality() const { return this == &GNU_Wasm_CPlusPlus; }
629e5dd7070Spatrick
isMSVCXXPersonalityEHPersonality630e5dd7070Spatrick bool isMSVCXXPersonality() const { return this == &MSVC_CxxFrameHandler3; }
631e5dd7070Spatrick };
632e5dd7070Spatrick }
633e5dd7070Spatrick }
634e5dd7070Spatrick
635e5dd7070Spatrick #endif
636