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/// Emits all the code to cause the given temporary to be cleaned up.
33 QualType tempType, Address ptr) {
35}
36
37//===----------------------------------------------------------------------===//
38// EHScopeStack
39//===----------------------------------------------------------------------===//
40
41void EHScopeStack::Cleanup::anchor() {}
42
43/// Push an entry of the given size onto this protected-scope stack.
44char *EHScopeStack::allocate(size_t size) {
45 size = llvm::alignTo(size, ScopeStackAlignment);
46 if (!startOfBuffer) {
47 unsigned capacity = llvm::PowerOf2Ceil(std::max(size, 1024ul));
48 startOfBuffer = std::make_unique<char[]>(capacity);
49 startOfData = endOfBuffer = startOfBuffer.get() + capacity;
50 } else if (static_cast<size_t>(startOfData - startOfBuffer.get()) < size) {
51 unsigned currentCapacity = endOfBuffer - startOfBuffer.get();
52 unsigned usedCapacity =
53 currentCapacity - (startOfData - startOfBuffer.get());
54 unsigned requiredCapacity = usedCapacity + size;
55 // We know from the 'else if' condition that requiredCapacity is greater
56 // than currentCapacity.
57 unsigned newCapacity = llvm::PowerOf2Ceil(requiredCapacity);
58
59 std::unique_ptr<char[]> newStartOfBuffer =
60 std::make_unique<char[]>(newCapacity);
61 char *newEndOfBuffer = newStartOfBuffer.get() + newCapacity;
62 char *newStartOfData = newEndOfBuffer - usedCapacity;
63 memcpy(newStartOfData, startOfData, usedCapacity);
64 startOfBuffer.swap(newStartOfBuffer);
65 endOfBuffer = newEndOfBuffer;
66 startOfData = newStartOfData;
67 }
68
69 assert(startOfBuffer.get() + size <= startOfData);
70 startOfData -= size;
71 return startOfData;
72}
73
74void EHScopeStack::deallocate(size_t size) {
75 startOfData += llvm::alignTo(size, ScopeStackAlignment);
76}
77
78void *EHScopeStack::pushCleanup(CleanupKind kind, size_t size) {
79 char *buffer = allocate(EHCleanupScope::getSizeForCleanupSize(size));
80 bool isEHCleanup = kind & EHCleanup;
81 bool isLifetimeMarker = kind & LifetimeMarker;
82
84
85 EHCleanupScope *scope = new (buffer) EHCleanupScope(size);
86
87 if (isLifetimeMarker)
88 cgf->cgm.errorNYI("push lifetime marker cleanup");
89
90 // With Windows -EHa, Invoke llvm.seh.scope.begin() for EHCleanup
91 if (cgf->getLangOpts().EHAsynch && isEHCleanup && !isLifetimeMarker &&
92 cgf->getTarget().getCXXABI().isMicrosoft())
93 cgf->cgm.errorNYI("push seh cleanup");
94
95 return scope->getCleanupBuffer();
96}
97
99 assert(!empty() && "popping exception stack when not empty");
100
101 assert(isa<EHCleanupScope>(*begin()));
102 EHCleanupScope &cleanup = cast<EHCleanupScope>(*begin());
103 deallocate(cleanup.getAllocatedSize());
104
105 // Destroy the cleanup.
106 cleanup.destroy();
107
109}
110
111static void emitCleanup(CIRGenFunction &cgf, EHScopeStack::Cleanup *cleanup) {
112 // Ask the cleanup to emit itself.
113 assert(cgf.haveInsertPoint() && "expected insertion point");
115 cleanup->emit(cgf);
116 assert(cgf.haveInsertPoint() && "cleanup ended with no insertion point?");
117}
118
119/// Pops a cleanup block. If the block includes a normal cleanup, the
120/// current insertion point is threaded through the cleanup, as are
121/// any branch fixups on the cleanup.
123 assert(!ehStack.empty() && "cleanup stack is empty!");
124 assert(isa<EHCleanupScope>(*ehStack.begin()) && "top not a cleanup!");
126
127 // Remember activation information.
128 bool isActive = scope.isActive();
129
131
132 // - whether there's a fallthrough
133 mlir::Block *fallthroughSource = builder.getInsertionBlock();
134 bool hasFallthrough = fallthroughSource != nullptr && isActive;
135
136 bool requiresNormalCleanup = scope.isNormalCleanup() && hasFallthrough;
137
138 // If we don't need the cleanup at all, we're done.
140 if (!requiresNormalCleanup) {
141 ehStack.popCleanup();
142 return;
143 }
144
145 // Copy the cleanup emission data out. This uses either a stack
146 // array or malloc'd memory, depending on the size, which is
147 // behavior that SmallVector would provide, if we could use it
148 // here. Unfortunately, if you ask for a SmallVector<char>, the
149 // alignment isn't sufficient.
150 auto *cleanupSource = reinterpret_cast<char *>(scope.getCleanupBuffer());
152 cleanupBufferStack[8 * sizeof(void *)];
153 std::unique_ptr<char[]> cleanupBufferHeap;
154 size_t cleanupSize = scope.getCleanupSize();
156
157 // This is necessary because we are going to deallocate the cleanup
158 // (in popCleanup) before we emit it.
159 if (cleanupSize <= sizeof(cleanupBufferStack)) {
160 memcpy(cleanupBufferStack, cleanupSource, cleanupSize);
161 cleanup = reinterpret_cast<EHScopeStack::Cleanup *>(cleanupBufferStack);
162 } else {
163 cleanupBufferHeap.reset(new char[cleanupSize]);
164 memcpy(cleanupBufferHeap.get(), cleanupSource, cleanupSize);
165 cleanup =
166 reinterpret_cast<EHScopeStack::Cleanup *>(cleanupBufferHeap.get());
167 }
168
170
171 ehStack.popCleanup();
172 scope.markEmitted();
173 emitCleanup(*this, cleanup);
174}
175
176/// Pops cleanup blocks until the given savepoint is reached.
178 EHScopeStack::stable_iterator oldCleanupStackDepth) {
180
181 // Pop cleanup blocks until we reach the base stack depth for the
182 // current scope.
183 while (ehStack.stable_begin() != oldCleanupStackDepth) {
185 }
186}
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 emitCXXTemporary(const CXXTemporary *temporary, QualType tempType, Address ptr)
Emits all the code to cause the given temporary to be cleaned up.
void pushDestroy(CleanupKind kind, Address addr, QualType type, Destroyer *destroyer)
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.
Represents a C++ temporary.
Definition ExprCXX.h:1460
A (possibly-)qualified type.
Definition TypeBase.h:937
@ 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()