23#include "llvm/Support/SaveAndRestore.h"
31class ConditionalEvaluationFinder
33 bool foundConditional =
false;
34 bool inResumeExpr =
false;
36 bool traverseSuspendExpr(CoroutineSuspendExpr *e) {
37 return TraverseStmt(e->
getCommonExpr()) && traverseResumeExpr(e);
42 bool traverseResumeExpr(CoroutineSuspendExpr *e) {
44 if (
auto *bind = dyn_cast_if_present<CXXBindTemporaryExpr>(resume))
45 resume = bind->getSubExpr();
46 llvm::SaveAndRestore inResume(inResumeExpr,
true);
47 return TraverseStmt(resume);
51 static bool needsCleanupScope(
const Stmt *s) {
52 ConditionalEvaluationFinder finder;
53 finder.TraverseStmt(
const_cast<Stmt *
>(s));
54 return finder.foundConditional;
57 static bool resumeExprDefersCleanups(
const CoroutineSuspendExpr &s) {
58 ConditionalEvaluationFinder finder;
59 finder.traverseResumeExpr(
const_cast<CoroutineSuspendExpr *
>(&s));
60 return finder.foundConditional;
65 bool shouldVisitImplicitCode()
const {
return true; }
67 bool VisitAbstractConditionalOperator(AbstractConditionalOperator *) {
68 foundConditional =
true;
72 bool VisitBinaryOperator(BinaryOperator *e) {
74 foundConditional =
true;
80 bool VisitCXXNewExpr(CXXNewExpr *e) {
85 foundConditional =
true;
95 if (init && !TraverseStmt(init))
99 bool TraverseBlockExpr(BlockExpr *) {
return true; }
100 bool TraverseStmtExpr(StmtExpr *) {
return true; }
102 bool TraverseGCCAsmStmt(GCCAsmStmt *s) {
104 if (!TraverseStmt(operand))
112 bool TraverseCoawaitExpr(CoawaitExpr *e) {
return traverseSuspendExpr(e); }
113 bool TraverseCoyieldExpr(CoyieldExpr *e) {
return traverseSuspendExpr(e); }
115 bool VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *) {
118 foundConditional =
true;
122 bool VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *e) {
125 foundConditional =
true;
136 return ConditionalEvaluationFinder::resumeExprDefersCleanups(s);
147 mlir::Location loc = builder.getUnknownLoc();
160 mlir::OpBuilder::InsertionGuard guard(builder);
163 builder.createFlagStore(loc,
false, active.
getPointer());
168 builder.createFlagStore(loc,
true, active.
getPointer());
179 assert(!cleanup.hasActiveFlag() &&
"cleanup already has active flag?");
180 cleanup.setActiveFlag(activeFlag);
182 cleanup.setTestFlagInNormalCleanup(cleanup.isNormalCleanup());
183 cleanup.setTestFlagInEHCleanup(cleanup.isEHCleanup());
188 : cgf(cgf), cleanups(cgf), scope(
nullptr),
195 assert(s &&
"expected an AST root for a cleanup boundary");
196 if (ConditionalEvaluationFinder::needsCleanupScope(s)) {
197 mlir::Location loc = cgf.builder.getUnknownLoc();
198 cir::CleanupKind cleanupKind = cgf.getLangOpts().Exceptions
199 ? cir::CleanupKind::All
200 : cir::CleanupKind::Normal;
201 scope = cir::CleanupScopeOp::create(
202 cgf.builder, loc, cleanupKind,
204 [&](mlir::OpBuilder &b, mlir::Location loc) {},
206 [&](mlir::OpBuilder &b, mlir::Location loc) {});
207 cgf.builder.setInsertionPointToEnd(&scope.getBodyRegion().front());
212 cgf.currentFullExprCleanupScope = scope;
217 if (cgf.outermostConditional)
218 cgf.hiddenOutermostConditional = cgf.outermostConditional;
219 cgf.outermostConditional =
nullptr;
226 cir::CleanupScopeOp scope) {
233 auto cur = alloca->getParentOfType<cir::CleanupScopeOp>();
234 while (cur && cur != scope)
235 cur = cur->getParentOfType<cir::CleanupScopeOp>();
242 mlir::Block *parentBlock = scope->getBlock();
243 mlir::OpBuilder::InsertPoint ip =
245 alloca->moveBefore(parentBlock, ip.getPoint());
254 for (mlir::Operation *cur = ptr.getDefiningOp(); cur && cur != alloca;) {
255 auto cast = mlir::dyn_cast<cir::CastOp>(cur);
258 casts.push_back(
cast);
259 cur =
cast.getSrc().getDefiningOp();
262 mlir::Operation *prev = alloca;
263 for (cir::CastOp
cast : llvm::reverse(casts)) {
264 cast->moveAfter(prev);
277 cir::CleanupScopeOp scope = condScope.
scope;
280 bool hasDeferredCleanups = stack.size() > base;
284 mlir::OpBuilder::InsertionGuard guard(builder);
285 mlir::Block &lastBodyBlock = scope.getBodyRegion().back();
286 builder.setInsertionPointToEnd(&lastBodyBlock);
287 if (lastBodyBlock.empty() ||
288 !lastBodyBlock.back().hasTrait<mlir::OpTrait::IsTerminator>())
296 if (hasDeferredCleanups) {
298 llvm::make_range(stack.begin() + base, stack.end()))
303 mlir::OpBuilder::InsertionGuard guard(builder);
304 mlir::Block &cleanupBlock = scope.getCleanupRegion().front();
305 builder.setInsertionPointToEnd(&cleanupBlock);
308 llvm::reverse(llvm::make_range(stack.begin() + base, stack.end()))) {
309 if (entry.activeFlag.isValid()) {
317 assert(entry.addr.getUnderlyingAllocaOp() &&
318 (entry.addr.getUnderlyingAllocaOp()->getBlock() ==
319 entry.addr.getPointer().getDefiningOp()->getBlock()) &&
320 "alloca and cast are in different blocks");
321 mlir::Value flag = builder.
createLoad(scope.getLoc(), entry.activeFlag);
322 cir::IfOp::create(builder, scope.getLoc(), flag,
324 [&](mlir::OpBuilder &b, mlir::Location loc) {
325 cgf.emitDestroy(entry.addr, entry.type,
327 builder.createYield(loc);
330 cgf.
emitDestroy(entry.addr, entry.type, entry.destroyer);
336 stack.truncate(base);
342 mlir::Block *insertBlock = builder.getInsertionBlock();
344 scope.getBodyRegion().findAncestorBlockInRegion(*insertBlock))
345 builder.setInsertionPointAfter(scope);
350 assert(!exited &&
"FullExprCleanupScope::exit called twice");
353 cgf.currentFullExprCleanupScope = oldFullExprCleanupScope;
354 cgf.outermostConditional = oldOutermostConditional;
355 cgf.hiddenOutermostConditional = oldHiddenOutermostConditional;
357 size_t oldSize = deferredCleanupStackSize;
360 assert(cgf.conditionalCleanupScopes.size() == conditionalScopeDepth &&
361 "conditional cleanup scope opened without one to close it");
362 cgf.deferredConditionalCleanupStack.truncate(oldSize);
363 cleanups.forceCleanup(valuesToReload);
369 for (mlir::Value *valPtr : valuesToReload) {
370 mlir::Value val = *valPtr;
375 Address temp = cgf.createDefaultAlignTempAlloca(val.getType(), val.getLoc(),
377 tempAllocas.push_back(temp);
378 cgf.builder.createStore(val.getLoc(), val, temp);
384 while (cgf.conditionalCleanupScopes.size() > conditionalScopeDepth)
386 cgf.conditionalCleanupScopes.pop_back_val());
391 cleanups.forceCleanupExceptLifetimeExtended();
395 mlir::OpBuilder::InsertionGuard guard(cgf.builder);
396 mlir::Block &lastBodyBlock = scope.getBodyRegion().back();
397 cgf.builder.setInsertionPointToEnd(&lastBodyBlock);
398 if (lastBodyBlock.empty() ||
399 !lastBodyBlock.back().hasTrait<mlir::OpTrait::IsTerminator>())
400 cgf.builder.createYield(scope.getLoc());
407 mlir::OpBuilder::InsertionGuard guard(cgf.builder);
408 mlir::Block &cleanupBlock = scope.getCleanupRegion().front();
409 cgf.builder.setInsertionPointToEnd(&cleanupBlock);
410 cgf.builder.createYield(scope.getLoc());
413 assert(cgf.deferredConditionalCleanupStack.size() == oldSize &&
414 "deferred cleanups were not consumed by a conditional scope");
415 cgf.builder.setInsertionPointAfter(scope);
421 cleanups.forceLifetimeExtendedCleanups();
424 for (
auto [addr, valPtr] : llvm::zip(tempAllocas, valuesToReload)) {
427 *valPtr = cgf.builder.createLoad(valPtr->getLoc(), addr);
435void EHScopeStack::Cleanup::anchor() {}
439 stable_iterator si = getInnermostNormalCleanup();
440 stable_iterator se = stable_end();
443 if (cleanup.isActive())
445 si = cleanup.getEnclosingNormalCleanup();
451char *EHScopeStack::allocate(
size_t size) {
452 size = llvm::alignTo(size, ScopeStackAlignment);
453 if (!startOfBuffer) {
454 unsigned capacity = llvm::PowerOf2Ceil(std::max<size_t>(size, 1024ul));
455 startOfBuffer = std::make_unique<char[]>(capacity);
456 startOfData = endOfBuffer = startOfBuffer.get() + capacity;
457 }
else if (
static_cast<size_t>(startOfData - startOfBuffer.get()) < size) {
458 unsigned currentCapacity = endOfBuffer - startOfBuffer.get();
459 unsigned usedCapacity =
460 currentCapacity - (startOfData - startOfBuffer.get());
461 unsigned requiredCapacity = usedCapacity + size;
464 unsigned newCapacity = llvm::PowerOf2Ceil(requiredCapacity);
466 std::unique_ptr<char[]> newStartOfBuffer =
467 std::make_unique<char[]>(newCapacity);
468 char *newEndOfBuffer = newStartOfBuffer.get() + newCapacity;
469 char *newStartOfData = newEndOfBuffer - usedCapacity;
470 memcpy(newStartOfData, startOfData, usedCapacity);
471 startOfBuffer.swap(newStartOfBuffer);
472 endOfBuffer = newEndOfBuffer;
473 startOfData = newStartOfData;
476 assert(startOfBuffer.get() + size <= startOfData);
481void EHScopeStack::deallocate(
size_t size) {
482 startOfData += llvm::alignTo(size, ScopeStackAlignment);
490 bool skipCleanupScope =
false;
492 cir::CleanupKind cleanupKind = cir::CleanupKind::All;
493 if (isEHCleanup && cgf->getLangOpts().Exceptions) {
495 isNormalCleanup ? cir::CleanupKind::All : cir::CleanupKind::EH;
501 cleanupKind = cir::CleanupKind::Normal;
503 skipCleanupScope =
true;
509 if (capturingCleanups)
510 skipCleanupScope =
true;
512 cir::CleanupScopeOp cleanupScope =
nullptr;
513 if (!skipCleanupScope) {
514 CIRGenBuilderTy &builder = cgf->getBuilder();
515 mlir::Location loc = builder.getUnknownLoc();
516 cleanupScope = cir::CleanupScopeOp::create(
517 builder, loc, cleanupKind,
519 [&](mlir::OpBuilder &b, mlir::Location loc) {
523 [&](mlir::OpBuilder &b, mlir::Location loc) {
527 builder.setInsertionPointToEnd(&cleanupScope.getBodyRegion().back());
534 if (innermostEHScope != stable_end() &&
538 EHCleanupScope *scope =
new (buffer)
539 EHCleanupScope(isNormalCleanup, isEHCleanup, size, cleanupScope,
540 innermostNormalCleanup, innermostEHScope);
543 innermostNormalCleanup = stable_begin();
546 innermostEHScope = stable_begin();
548 if (isLifetimeMarker)
552 if (cgf->getLangOpts().EHAsynch && isEHCleanup && !isLifetimeMarker &&
553 cgf->getTarget().getCXXABI().isMicrosoft())
554 cgf->cgm.errorNYI(
"push seh cleanup");
560 assert(!empty() &&
"popping exception stack when not empty");
564 innermostNormalCleanup =
cleanup.getEnclosingNormalCleanup();
565 innermostEHScope =
cleanup.getEnclosingEHScope();
566 deallocate(
cleanup.getAllocatedSize());
568 cir::CleanupScopeOp cleanupScope =
cleanup.getCleanupScopeOp();
570 auto *block = &cleanupScope.getBodyRegion().back();
571 if (!block->mightHaveTerminator()) {
572 mlir::OpBuilder::InsertionGuard guard(cgf->getBuilder());
573 cgf->getBuilder().setInsertionPointToEnd(block);
574 cir::YieldOp::create(cgf->getBuilder(),
575 cgf->getBuilder().getUnknownLoc());
579 mlir::Block *insertBlock = cgf->getBuilder().getInsertionBlock();
581 cleanupScope.getBodyRegion().findAncestorBlockInRegion(*insertBlock))
582 cgf->getBuilder().setInsertionPointAfter(cleanupScope);
590 for (stable_iterator si = getInnermostEHScope(); si != stable_end();) {
591 if (
auto *cleanup = dyn_cast<EHCleanupScope>(&*find(si))) {
592 if (
cleanup->isLifetimeMarker()) {
594 si =
cleanup->getEnclosingEHScope();
607 mlir::Operation *dominatingIP) {
626 if (!var.isValid()) {
627 mlir::Location loc = builder.getUnknownLoc();
630 loc,
"cleanup.isactive");
633 assert(dominatingIP &&
"no existing variable and no dominating IP!");
636 mlir::Value val = builder.
getBool(
true, loc);
639 mlir::OpBuilder::InsertionGuard guard(builder);
640 builder.setInsertionPoint(dominatingIP);
648 mlir::Location loc = builder.getUnknownLoc();
657 return op->isProperAncestor(condScope.scope);
663 mlir::Operation *dominatingIP) {
664 assert(c !=
ehStack.stable_end() &&
"deactivating bottom of stack?");
666 assert(scope.
isActive() &&
"double deactivation");
671 if (c ==
ehStack.stable_begin() &&
686 Address activeFlag, mlir::Location loc) {
694 cir::IfOp::create(builder, loc, isActive,
697 [&](mlir::OpBuilder &, mlir::Location) {
698 cleanup->emit(cgf, flags);
700 "cleanup ended with no insertion point?");
704 cleanup->emit(cgf, flags);
705 assert(cgf.
haveInsertPoint() &&
"cleanup ended with no insertion point?");
710 EHScopeStack::Cleanup *cleanup,
714 mlir::Block &block = cleanupScope.getCleanupRegion().back();
716 mlir::OpBuilder::InsertionGuard guard(builder);
717 builder.setInsertionPointToStart(&block);
719 emitCleanupBody(cgf, cleanup, flags, activeFlag, cleanupScope.getLoc());
721 mlir::Block &cleanupRegionLastBlock = cleanupScope.getCleanupRegion().back();
722 if (cleanupRegionLastBlock.empty() ||
723 !cleanupRegionLastBlock.back().hasTrait<mlir::OpTrait::IsTerminator>()) {
724 mlir::OpBuilder::InsertionGuard guardCase(builder);
725 builder.setInsertionPointToEnd(&cleanupRegionLastBlock);
736 .walk([&](mlir::Operation *op) {
738 return mlir::WalkResult::interrupt();
739 return mlir::WalkResult::advance();
749 assert(!
ehStack.empty() &&
"cleanup stack is empty!");
759 "missing cir.cleanup.scope for active cleanup");
781 if (forDeactivation && requiresNormalCleanup) {
788 mlir::Location loc = builder.getUnknownLoc();
795 mlir::OpBuilder::InsertionGuard guard(builder);
796 builder.setInsertionPoint(cleanupScope);
797 builder.createFlagStore(loc,
true, activeFlag.
getPointer());
801 assert(builder.getInsertionBlock() ==
802 &cleanupScope.getBodyRegion().back() &&
803 "expected insertion point in cleanup body");
804 builder.createFlagStore(loc,
false, activeFlag.
getPointer());
811 if (requiresEHCleanup)
812 cleanupScope.setCleanupKind(cir::CleanupKind::EH);
813 requiresNormalCleanup =
false;
825 if (!requiresNormalCleanup && !requiresEHCleanup) {
830 mlir::Block &cleanupBlock = cleanupScope.getCleanupRegion().back();
831 if (!cleanupBlock.mightHaveTerminator()) {
832 mlir::OpBuilder::InsertionGuard guard(builder);
833 builder.setInsertionPointToEnd(&cleanupBlock);
834 cir::YieldOp::create(builder, builder.getUnknownLoc());
847 cleanupBufferStack[8 *
sizeof(
void *)];
848 std::unique_ptr<char[]> cleanupBufferHeap;
854 if (cleanupSize <=
sizeof(cleanupBufferStack)) {
855 memcpy(cleanupBufferStack, cleanupSource, cleanupSize);
858 cleanupBufferHeap.reset(
new char[cleanupSize]);
859 memcpy(cleanupBufferHeap.get(), cleanupSource, cleanupSize);
871 Address cleanupActiveFlag = normalActiveFlag.
isValid() ? normalActiveFlag
872 : ehActiveFlag.
isValid() ? ehActiveFlag
880 emitCleanup(*
this, cleanupScope, cleanup, cleanupFlags, cleanupActiveFlag);
884 mlir::Location loc) {
889 while (
ehStack.stable_begin() != depth) {
893 "captured cleanup should not own a cleanup scope");
915 cleanupBufferStack[8 *
sizeof(
void *)];
916 std::unique_ptr<char[]> cleanupBufferHeap;
919 if (cleanupSize <=
sizeof(cleanupBufferStack)) {
920 memcpy(cleanupBufferStack, cleanupSource, cleanupSize);
923 cleanupBufferHeap.reset(
new char[cleanupSize]);
924 memcpy(cleanupBufferHeap.get(), cleanupSource, cleanupSize);
941 bool requiresCleanup =
false;
942 for (
auto it =
ehStack.begin(), ie =
ehStack.find(oldCleanupStackDepth);
945 requiresCleanup =
true;
954 if (requiresCleanup) {
955 for (mlir::Value *valPtr : valuesToReload) {
956 mlir::Value val = *valPtr;
964 tempAllocas.push_back(temp);
965 builder.createStore(val.getLoc(), val, temp);
971 while (
ehStack.stable_begin() != oldCleanupStackDepth)
975 if (requiresCleanup) {
976 for (
auto [addr, valPtr] : llvm::zip(tempAllocas, valuesToReload)) {
977 mlir::Location loc = valPtr->getLoc();
978 *valPtr = builder.createLoad(loc, addr);
static void setupCleanupBlockDeactivation(CIRGenFunction &cgf, EHScopeStack::stable_iterator c, mlir::Operation *dominatingIP)
The given cleanup block is being deactivated.
static bool bodyHasBranchThroughExits(mlir::Region &bodyRegion)
Check whether a cleanup scope body contains any non-yield exits that branch through the cleanup.
static void closeConditionalCleanupScope(CIRGenFunction &cgf, const CIRGenFunction::ConditionalCleanupScope &condScope)
Close a cleanup scope opened by a ConditionalEvaluation.
static bool enclosesOpenConditionalCleanupScope(CIRGenFunction &cgf, EHCleanupScope &scope)
static void hoistAllocaOutOfCleanupScope(CIRGenFunction &cgf, Address addr, cir::CleanupScopeOp scope)
If the alloca that backs addr is currently nested inside the body region of scope,...
static void emitCleanupBody(CIRGenFunction &cgf, EHScopeStack::Cleanup *cleanup, EHScopeStack::Cleanup::Flags flags, Address activeFlag, mlir::Location loc)
static void emitCleanup(CIRGenFunction &cgf, cir::CleanupScopeOp cleanupScope, EHScopeStack::Cleanup *cleanup, EHScopeStack::Cleanup::Flags flags, Address activeFlag)
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
__DEVICE__ void * memcpy(void *__a, const void *__b, size_t __c)
cir::ConstantOp getBool(bool state, mlir::Location loc)
cir::StoreOp createFlagStore(mlir::Location loc, bool val, mlir::Value dst)
static OpBuilder::InsertPoint getBestAllocaInsertPoint(mlir::Block *block)
cir::YieldOp createYield(mlir::Location loc, mlir::ValueRange value={})
Create a yield operation.
cir::LoadOp createFlagLoad(mlir::Location loc, mlir::Value addr)
Emit a load from an boolean flag variable.
cir::BoolType getBoolTy()
static bool isLogicalOp(Opcode Opc)
mlir::Value getPointer() const
cir::AllocaOp getUnderlyingAllocaOp() const
Return the underlying alloca for this address, if any.
cir::LoadOp createLoad(mlir::Location loc, Address addr, bool isVolatile=false, bool isNontemporal=false)
FullExprCleanupScope(CIRGenFunction &cgf, const Stmt *s)
s is the AST root for one cleanup boundary: a full-expression, an asm statement, or the construction ...
void exit(ArrayRef< mlir::Value * > valuesToReload={})
llvm::SmallVector< PendingCleanupEntry > lifetimeExtendedCleanupStack
ConditionalEvaluation * hiddenOutermostConditional
void initFullExprCleanup()
Set up the last cleanup that was pushed as a conditional full-expression cleanup.
void emitCapturedCleanups(EHScopeStack::stable_iterator depth, mlir::Location loc)
Emit the captured cleanups (those pushed above depth while EHScopeStack was capturing cleanups) at th...
mlir::Block * getCurFunctionEntryBlock()
bool isInConditionalBranch() const
void setBeforeOutermostConditional(mlir::Value value, Address addr)
ConditionalEvaluation * outermostConditional
static bool resumeExprDefersCleanups(const CoroutineSuspendExpr &s)
Whether the resume expression of s contains a construct that defers cleanups to the end of the enclos...
EHScopeStack ehStack
Tracks function scope overall cleanup handling.
llvm::SmallVector< PendingCleanupEntry > deferredConditionalCleanupStack
Cleanups for temporaries constructed inside a conditional.
llvm::SmallVector< ConditionalCleanupScope > conditionalCleanupScopes
void pushDestroy(QualType::DestructionKind dtorKind, Address addr, QualType type)
Push the standard destructor for the given type as at least a normal cleanup.
static Destroyer destroyCXXObject
void initFullExprCleanupWithFlag(Address activeFlag)
Address createCleanupActiveFlag()
Create an active flag variable for use with conditional cleanups.
void deactivateCleanupBlock(EHScopeStack::stable_iterator cleanup, mlir::Operation *dominatingIP)
Deactivates the given cleanup block.
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 popCleanupBlocks(EHScopeStack::stable_iterator oldCleanupStackDepth, ArrayRef< mlir::Value * > valuesToReload={})
Takes the old cleanup stack size and emits the cleanup blocks that have been added.
CIRGenBuilderTy & getBuilder()
void emitDestroy(Address addr, QualType type, Destroyer *destroyer)
Immediately perform the destruction of the given object.
void pushPendingCleanupToEHStack(const PendingCleanupEntry &entry)
Promote a single pending cleanup entry onto the EH scope stack.
void popCleanupBlock(bool forDeactivation=false)
Pop a cleanup block from the stack.
cir::CleanupScopeOp currentFullExprCleanupScope
The cir.cleanup.scope of the innermost FullExprCleanupScope that materialized one,...
EHScopeStack::stable_iterator currentCleanupStackDepth
CIRGenFunction(CIRGenModule &cgm, CIRGenBuilderTy &builder, bool suppressNewContext=false)
Address createTempAllocaWithoutCast(mlir::Type ty, CharUnits align, mlir::Location loc, const Twine &name="tmp", mlir::Value arraySize=nullptr, mlir::OpBuilder::InsertPoint ip={})
This creates a alloca and inserts it into the entry block of the current region.
Address createDefaultAlignTempAlloca(mlir::Type ty, mlir::Location loc, const Twine &name)
CreateDefaultAlignTempAlloca - This creates an alloca with the default alignment of the corresponding...
A cleanup scope which generates the cleanup blocks lazily.
void setTestFlagInEHCleanup(bool value)
void setTestFlagInNormalCleanup(bool value)
Address getActiveFlag() const
size_t getCleanupSize() const
cir::CleanupScopeOp getCleanupScopeOp()
bool shouldTestFlagInEHCleanup() const
static size_t getSizeForCleanupSize(size_t size)
Gets the size required for a lazy cleanup scope with the given cleanup-data requirements.
bool isNormalCleanup() const
void setActiveFlag(Address var)
void * getCleanupBuffer()
bool shouldTestFlagInNormalCleanup() const
void setActive(bool isActive)
void setIsEHCleanupKind()
void setIsNormalCleanupKind()
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.
iterator find(stable_iterator savePoint) const
Turn a stable reference to a scope depth into a unstable pointer to the EH stack.
bool requiresCatchOrCleanup() const
stable_iterator getInnermostActiveNormalCleanup() const
bool hasInitializer() const
Whether this new-expression has any initializer at all.
bool shouldNullCheckAllocation() const
True if the allocation result needs to be null-checked.
Represents a C++ temporary.
static CharUnits One()
Construct a CharUnits quantity of one.
Represents an expression that might suspend coroutine execution; either a co_await or co_yield expres...
Expr * getResumeExpr() const
Expr * getCommonExpr() const
llvm::iterator_range< capture_init_iterator > capture_inits()
Retrieve the initialization expressions for this lambda's captures.
A (possibly-)qualified type.
DestructionKind isDestructedType() const
Returns a nonzero value if objects of this type require non-trivial work to clean up after.
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
Stmt - This represents one statement.
@ EHCleanup
Denotes a cleanup that should run when a scope is exited using exceptional control flow (a throw stat...
@ NormalCleanup
Denotes a cleanup that should run when a scope is exited using normal control flow (falling off the e...
Top level wrappers for InstallAPI frontend operations.
bool isa(CodeGen::Address addr)
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
U cast(CodeGen::Address addr)
One record per cir.cleanup.scope opened by a ConditionalEvaluation, as described above.
size_t deferredCleanupStackSize
The size of deferredConditionalCleanupStack when this scope was opened.
cir::CleanupScopeOp scope
A cleanup whose destructor call is not emitted where the cleanup is registered.