clang 22.0.0git
CIRGenCleanup.cpp
Go to the documentation of this file.
1//===--- CIRGenCleanup.cpp - Bookkeeping and code emission for cleanups ---===//
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// This file contains code dealing with the IR generation for cleanups
10// and related information.
11//
12// A "cleanup" is a piece of code which needs to be executed whenever
13// control transfers out of a particular scope. This can be
14// conditionalized to occur only on exceptional control flow, only on
15// normal control flow, or both.
16//
17//===----------------------------------------------------------------------===//
18
19#include "CIRGenCleanup.h"
20#include "CIRGenFunction.h"
21
23
24using namespace clang;
25using namespace clang::CIRGen;
26
27//===----------------------------------------------------------------------===//
28// CIRGenFunction cleanup related
29//===----------------------------------------------------------------------===//
30
31//===----------------------------------------------------------------------===//
32// EHScopeStack
33//===----------------------------------------------------------------------===//
34
35void EHScopeStack::Cleanup::anchor() {}
36
37/// Push an entry of the given size onto this protected-scope stack.
38char *EHScopeStack::allocate(size_t size) {
39 size = llvm::alignTo(size, ScopeStackAlignment);
40 if (!startOfBuffer) {
41 unsigned capacity = llvm::PowerOf2Ceil(std::max(size, 1024ul));
42 startOfBuffer = std::make_unique<char[]>(capacity);
43 startOfData = endOfBuffer = startOfBuffer.get() + capacity;
44 } else if (static_cast<size_t>(startOfData - startOfBuffer.get()) < size) {
45 unsigned currentCapacity = endOfBuffer - startOfBuffer.get();
46 unsigned usedCapacity =
47 currentCapacity - (startOfData - startOfBuffer.get());
48 unsigned requiredCapacity = usedCapacity + size;
49 // We know from the 'else if' condition that requiredCapacity is greater
50 // than currentCapacity.
51 unsigned newCapacity = llvm::PowerOf2Ceil(requiredCapacity);
52
53 std::unique_ptr<char[]> newStartOfBuffer =
54 std::make_unique<char[]>(newCapacity);
55 char *newEndOfBuffer = newStartOfBuffer.get() + newCapacity;
56 char *newStartOfData = newEndOfBuffer - usedCapacity;
57 memcpy(newStartOfData, startOfData, usedCapacity);
58 startOfBuffer.swap(newStartOfBuffer);
59 endOfBuffer = newEndOfBuffer;
60 startOfData = newStartOfData;
61 }
62
63 assert(startOfBuffer.get() + size <= startOfData);
64 startOfData -= size;
65 return startOfData;
66}
67
68void EHScopeStack::deallocate(size_t size) {
69 startOfData += llvm::alignTo(size, ScopeStackAlignment);
70}
71
72void *EHScopeStack::pushCleanup(CleanupKind kind, size_t size) {
73 char *buffer = allocate(EHCleanupScope::getSizeForCleanupSize(size));
74 bool isEHCleanup = kind & EHCleanup;
75 bool isLifetimeMarker = kind & LifetimeMarker;
76
78
79 EHCleanupScope *scope = new (buffer) EHCleanupScope(size);
80
81 if (isLifetimeMarker)
82 cgf->cgm.errorNYI("push lifetime marker cleanup");
83
84 // With Windows -EHa, Invoke llvm.seh.scope.begin() for EHCleanup
85 if (cgf->getLangOpts().EHAsynch && isEHCleanup && !isLifetimeMarker &&
87 cgf->cgm.errorNYI("push seh cleanup");
88
89 return scope->getCleanupBuffer();
90}
91
93 assert(!empty() && "popping exception stack when not empty");
94
95 assert(isa<EHCleanupScope>(*begin()));
96 EHCleanupScope &cleanup = cast<EHCleanupScope>(*begin());
97 deallocate(cleanup.getAllocatedSize());
98
99 // Destroy the cleanup.
100 cleanup.destroy();
101
103}
104
106 // Ask the cleanup to emit itself.
107 assert(cgf.haveInsertPoint() && "expected insertion point");
109 cleanup->emit(cgf);
110 assert(cgf.haveInsertPoint() && "cleanup ended with no insertion point?");
111}
112
113/// Pops a cleanup block. If the block includes a normal cleanup, the
114/// current insertion point is threaded through the cleanup, as are
115/// any branch fixups on the cleanup.
117 assert(!ehStack.empty() && "cleanup stack is empty!");
118 assert(isa<EHCleanupScope>(*ehStack.begin()) && "top not a cleanup!");
119 EHCleanupScope &scope = cast<EHCleanupScope>(*ehStack.begin());
120
121 // Remember activation information.
122 bool isActive = scope.isActive();
123
125
126 // - whether there's a fallthrough
127 mlir::Block *fallthroughSource = builder.getInsertionBlock();
128 bool hasFallthrough = fallthroughSource != nullptr && isActive;
129
130 bool requiresNormalCleanup = scope.isNormalCleanup() && hasFallthrough;
131
132 // If we don't need the cleanup at all, we're done.
134 if (!requiresNormalCleanup) {
135 ehStack.popCleanup();
136 return;
137 }
138
139 // Copy the cleanup emission data out. This uses either a stack
140 // array or malloc'd memory, depending on the size, which is
141 // behavior that SmallVector would provide, if we could use it
142 // here. Unfortunately, if you ask for a SmallVector<char>, the
143 // alignment isn't sufficient.
144 auto *cleanupSource = reinterpret_cast<char *>(scope.getCleanupBuffer());
146 cleanupBufferStack[8 * sizeof(void *)];
147 std::unique_ptr<char[]> cleanupBufferHeap;
148 size_t cleanupSize = scope.getCleanupSize();
149 EHScopeStack::Cleanup *cleanup;
150
151 // This is necessary because we are going to deallocate the cleanup
152 // (in popCleanup) before we emit it.
153 if (cleanupSize <= sizeof(cleanupBufferStack)) {
154 memcpy(cleanupBufferStack, cleanupSource, cleanupSize);
155 cleanup = reinterpret_cast<EHScopeStack::Cleanup *>(cleanupBufferStack);
156 } else {
157 cleanupBufferHeap.reset(new char[cleanupSize]);
158 memcpy(cleanupBufferHeap.get(), cleanupSource, cleanupSize);
159 cleanup =
160 reinterpret_cast<EHScopeStack::Cleanup *>(cleanupBufferHeap.get());
161 }
162
164
165 ehStack.popCleanup();
166 scope.markEmitted();
167 emitCleanup(*this, cleanup);
168}
169
170/// Pops cleanup blocks until the given savepoint is reached.
172 EHScopeStack::stable_iterator oldCleanupStackDepth) {
174
175 // Pop cleanup blocks until we reach the base stack depth for the
176 // current scope.
177 while (ehStack.stable_begin() != oldCleanupStackDepth) {
178 popCleanupBlock();
179 }
180}
static void emitCleanup(CIRGenFunction &cgf, EHScopeStack::Cleanup *cleanup)
__DEVICE__ void * memcpy(void *__a, const void *__b, size_t __c)
const clang::LangOptions & getLangOpts() const
const TargetInfo & getTarget() const
bool haveInsertPoint() const
True if an insertion point is defined.
void popCleanupBlocks(EHScopeStack::stable_iterator oldCleanupStackDepth)
Takes the old cleanup stack size and emits the cleanup blocks that have been added.
void popCleanupBlock()
Pops a cleanup block.
DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef)
Helpers to emit "not yet implemented" error diagnostics.
A cleanup scope which generates the cleanup blocks lazily.
Definition: CIRGenCleanup.h:74
static size_t getSizeForCleanupSize(size_t size)
Gets the size required for a lazy cleanup scope with the given cleanup-data requirements.
Definition: CIRGenCleanup.h:78
Information for lazily generating a cleanup.
Definition: EHScopeStack.h:93
A saved depth on the scope stack.
Definition: EHScopeStack.h:53
void popCleanup()
Pops a cleanup scope off the stack. This is private to CIRGenCleanup.cpp.
bool empty() const
Determines whether the exception-scopes stack is empty.
Definition: EHScopeStack.h:162
iterator begin() const
Returns an iterator pointing to the innermost EH scope.
bool isMicrosoft() const
Is this ABI an MSVC-compatible ABI?
Definition: TargetCXXABI.h:136
TargetCXXABI getCXXABI() const
Get the C++ ABI currently in use.
Definition: TargetInfo.h:1360
@ EHCleanup
Denotes a cleanup that should run when a scope is exited using exceptional control flow (a throw stat...
Definition: EHScopeStack.h:30
unsigned kind
All of the diagnostics that can be emitted by the frontend.
Definition: DiagnosticIDs.h:76
The JSON file list parser is used to communicate input to InstallAPI.
static bool ehCleanupFlags()
static bool ehCleanupScopeRequiresEHCleanup()
static bool ehstackBranches()
static bool innermostEHScope()
static bool ehCleanupBranchFixups()