diff --git a/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp b/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp index 4e0a305a502c..40fc101d4c23 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp @@ -42,8 +42,36 @@ cir::BrOp CIRGenFunction::emitBranchThroughCleanup(mlir::Location Loc, // Insert a branch: to the cleanup block (unsolved) or to the already // materialized label. Keep track of unsolved goto's. - return builder.create(Loc, Dest.isValid() ? Dest.getBlock() - : ReturnBlock().getBlock()); + auto brOp = builder.create( + Loc, Dest.isValid() ? Dest.getBlock() : ReturnBlock().getBlock()); + + // Calculate the innermost active normal cleanup. + EHScopeStack::stable_iterator TopCleanup = + EHStack.getInnermostActiveNormalCleanup(); + + // If we're not in an active normal cleanup scope, or if the + // destination scope is within the innermost active normal cleanup + // scope, we don't need to worry about fixups. + if (TopCleanup == EHStack.stable_end() || + TopCleanup.encloses(Dest.getScopeDepth())) { // works for invalid + // FIXME(cir): should we clear insertion point here? + return brOp; + } + + // If we can't resolve the destination cleanup scope, just add this + // to the current cleanup scope as a branch fixup. + if (!Dest.getScopeDepth().isValid()) { + BranchFixup &Fixup = EHStack.addBranchFixup(); + Fixup.destination = Dest.getBlock(); + Fixup.destinationIndex = Dest.getDestIndex(); + Fixup.initialBranch = brOp; + Fixup.optimisticBranchBlock = nullptr; + // FIXME(cir): should we clear insertion point here? + return brOp; + } + + // FIXME(cir): otherwise, thread through all the normal cleanups in scope. + return brOp; } /// Emits all the code to cause the given temporary to be cleaned up. @@ -574,6 +602,18 @@ void CIRGenFunction::PopCleanupBlocks( void EHScopeStack::Cleanup::anchor() {} +EHScopeStack::stable_iterator +EHScopeStack::getInnermostActiveNormalCleanup() const { + for (stable_iterator si = getInnermostNormalCleanup(), se = stable_end(); + si != se;) { + EHCleanupScope &cleanup = cast(*find(si)); + if (cleanup.isActive()) + return si; + si = cleanup.getEnclosingNormalCleanup(); + } + return stable_end(); +} + /// Push an entry of the given size onto this protected-scope stack. char *EHScopeStack::allocate(size_t Size) { Size = llvm::alignTo(Size, ScopeStackAlignment); diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp index 1c84cb3ca71b..fa46b0bd2cef 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp @@ -537,8 +537,8 @@ void CIRGenFunction::finishFunction(SourceLocation EndLoc) { // the ret after it's been at EndLoc. if (auto *DI = getDebugInfo()) assert(!cir::MissingFeatures::generateDebugInfo() && "NYI"); - // FIXME(cir): vla.c test currently crashes here. - // PopCleanupBlocks(PrologueCleanupDepth); + builder.clearInsertionPoint(); + PopCleanupBlocks(PrologueCleanupDepth); } // Emit function epilog (to return). @@ -561,8 +561,7 @@ void CIRGenFunction::finishFunction(SourceLocation EndLoc) { assert(!cir::MissingFeatures::emitFunctionEpilog() && "NYI"); assert(!cir::MissingFeatures::emitEndEHSpec() && "NYI"); - // FIXME(cir): vla.c test currently crashes here. - // assert(EHStack.empty() && "did not remove all scopes from cleanup stack!"); + assert(EHStack.empty() && "did not remove all scopes from cleanup stack!"); // If someone did an indirect goto, emit the indirect goto block at the end of // the function. @@ -1203,8 +1202,7 @@ void CIRGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, } assert(!cir::MissingFeatures::emitStartEHSpec() && "NYI"); - // FIXME(cir): vla.c test currently crashes here. - // PrologueCleanupDepth = EHStack.stable_begin(); + PrologueCleanupDepth = EHStack.stable_begin(); // Emit OpenMP specific initialization of the device functions. if (getLangOpts().OpenMP && CurCodeDecl) diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index e5db0a01e429..4172ac1e208d 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -76,11 +76,24 @@ class CIRGenFunction : public CIRGenTypeCache { /// require a jump out through normal cleanups. struct JumpDest { JumpDest() = default; - JumpDest(mlir::Block *Block) : Block(Block) {} + JumpDest(mlir::Block *block, EHScopeStack::stable_iterator depth = {}, + unsigned index = 0) + : block(block) {} + + bool isValid() const { return block != nullptr; } + mlir::Block *getBlock() const { return block; } + EHScopeStack::stable_iterator getScopeDepth() const { return scopeDepth; } + unsigned getDestIndex() const { return index; } + + // This should be used cautiously. + void setScopeDepth(EHScopeStack::stable_iterator depth) { + scopeDepth = depth; + } - bool isValid() const { return Block != nullptr; } - mlir::Block *getBlock() const { return Block; } - mlir::Block *Block = nullptr; + private: + mlir::Block *block = nullptr; + EHScopeStack::stable_iterator scopeDepth; + unsigned index; }; /// Track mlir Blocks for each C/C++ label. diff --git a/clang/lib/CIR/CodeGen/EHScopeStack.h b/clang/lib/CIR/CodeGen/EHScopeStack.h index e235c9ec3685..a35ca2140856 100644 --- a/clang/lib/CIR/CodeGen/EHScopeStack.h +++ b/clang/lib/CIR/CodeGen/EHScopeStack.h @@ -34,22 +34,22 @@ class CIRGenFunction; /// the innermost cleanup. When a (normal) cleanup is popped, any /// unresolved fixups in that scope are threaded through the cleanup. struct BranchFixup { - // /// The block containing the terminator which needs to be modified - // /// into a switch if this fixup is resolved into the current scope. - // /// If null, LatestBranch points directly to the destination. - // llvm::BasicBlock *OptimisticBranchBlock; - - // /// The ultimate destination of the branch. - // /// - // /// This can be set to null to indicate that this fixup was - // /// successfully resolved. - // llvm::BasicBlock *Destination; - - // /// The destination index value. - // unsigned DestinationIndex; - - // /// The initial branch of the fixup. - // llvm::BranchInst *InitialBranch; + /// The block containing the terminator which needs to be modified + /// into a switch if this fixup is resolved into the current scope. + /// If null, LatestBranch points directly to the destination. + mlir::Block *optimisticBranchBlock = nullptr; + + /// The ultimate destination of the branch. + /// + /// This can be set to null to indicate that this fixup was + /// successfully resolved. + mlir::Block *destination = nullptr; + + /// The destination index value. + unsigned destinationIndex = 0; + + /// The initial branch of the fixup. + cir::BrOp initialBranch = {}; }; template struct InvariantValue {