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 &&
86 cgf->getTarget().getCXXABI().isMicrosoft())
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
105static void emitCleanup(CIRGenFunction &cgf, EHScopeStack::Cleanup *cleanup) {
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!");
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();
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) {
179 }
180}
static void emitCleanup(CIRGenFunction &cgf, EHScopeStack::Cleanup *cleanup)
tooling::Replacements cleanup(const FormatStyle &Style, StringRef Code, ArrayRef< tooling::Range > Ranges, StringRef FileName="<stdin>")
Clean up any erroneous/redundant code in the given Ranges in Code.
__DEVICE__ void * memcpy(void *__a, const void *__b, size_t __c)
EHScopeStack ehStack
Tracks function scope overall cleanup handling.
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.
A cleanup scope which generates the cleanup blocks lazily.
static size_t getSizeForCleanupSize(size_t size)
Gets the size required for a lazy cleanup scope with the given cleanup-data requirements.
Information for lazily generating a cleanup.
A saved depth on the scope stack.
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.
iterator begin() const
Returns an iterator pointing to the innermost EH scope.
@ EHCleanup
Denotes a cleanup that should run when a scope is exited using exceptional control flow (a throw stat...
unsigned kind
All of the diagnostics that can be emitted by the frontend.
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Definition Address.h:330
U cast(CodeGen::Address addr)
Definition Address.h:327
static bool ehCleanupFlags()
static bool ehCleanupScopeRequiresEHCleanup()
static bool ehstackBranches()
static bool innermostEHScope()
static bool ehCleanupBranchFixups()