From 8c4b4a66a7a260afb41706f66f684695c844358d Mon Sep 17 00:00:00 2001 From: John McCall Date: Tue, 11 Nov 2025 16:10:13 -0500 Subject: [PATCH] WIP for [non_nested] support for alloc_stack --- include/swift/Runtime/RuntimeFunctions.def | 4 +- include/swift/SIL/SILCloner.h | 1 + include/swift/SIL/SILInstruction.h | 26 ++++++++++ include/swift/SIL/SILNode.h | 3 +- lib/IRGen/FixedTypeInfo.h | 8 +++- lib/IRGen/GenArray.cpp | 9 ++-- lib/IRGen/GenInit.cpp | 6 ++- lib/IRGen/GenOpaque.cpp | 21 +++++++++ lib/IRGen/GenType.cpp | 6 ++- lib/IRGen/IRGenFunction.h | 6 +++ lib/IRGen/IRGenSIL.cpp | 16 +++++-- lib/IRGen/NonFixedTypeInfo.h | 11 +++-- lib/IRGen/TypeInfo.h | 8 +++- lib/SIL/IR/SILInstruction.cpp | 19 ++++++++ lib/SIL/IR/SILInstructions.cpp | 1 + lib/SIL/IR/SILPrinter.cpp | 10 ++++ lib/SIL/Parser/ParseSIL.cpp | 17 ++++--- lib/SIL/Verifier/SILVerifier.cpp | 55 ++++++++++++++-------- lib/SILOptimizer/Utils/StackNesting.cpp | 8 +++- lib/Serialization/DeserializeSIL.cpp | 5 +- lib/Serialization/SerializeSIL.cpp | 1 + 21 files changed, 190 insertions(+), 51 deletions(-) diff --git a/include/swift/Runtime/RuntimeFunctions.def b/include/swift/Runtime/RuntimeFunctions.def index b802873309a9b..3f994d6321a4f 100644 --- a/include/swift/Runtime/RuntimeFunctions.def +++ b/include/swift/Runtime/RuntimeFunctions.def @@ -2570,7 +2570,7 @@ FUNCTION(AsyncLetBegin, ), ATTRS(NoUnwind), EFFECT(RuntimeEffect::Concurrency), - MEMEFFECTS(ArgMemOnly)) + UNKNOWN_MEMEFFECTS) /// void swift_asyncLet_finish( /// AsyncLet *alet, @@ -2592,7 +2592,7 @@ FUNCTION(AsyncLetFinish, ), ATTRS(NoUnwind), EFFECT(RuntimeEffect::Concurrency), - MEMEFFECTS(ArgMemOnly)) + UNKNOWN_MEMEFFECTS) /// void swift_task_run_inline( /// OpaqueValue *result, diff --git a/include/swift/SIL/SILCloner.h b/include/swift/SIL/SILCloner.h index 621ac4cdefff8..18f12575eb789 100644 --- a/include/swift/SIL/SILCloner.h +++ b/include/swift/SIL/SILCloner.h @@ -1062,6 +1062,7 @@ SILCloner::visitAllocStackInst(AllocStackInst *Inst) { true #endif ); + NewInst->setStackAllocationIsNested(Inst->isStackAllocationNested()); recordClonedInstruction(Inst, NewInst); } diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h index efad3428a1a6c..1299dab178e38 100644 --- a/include/swift/SIL/SILInstruction.h +++ b/include/swift/SIL/SILInstruction.h @@ -141,6 +141,15 @@ class SILPrintContext; template class SILClonerWithScopes; +enum StackAllocationIsNested_t : bool { + /// The instruction may not obey the ABBA rule of stack allocation. + StackAllocationIsNotNested = false, + + /// The instruction obeys the ABBA rule of stack allocation and can + /// allocate memory on the stack normally. + StackAllocationIsNested = true, +}; + enum class MemoryBehavior { None, /// The instruction may read memory. @@ -858,6 +867,15 @@ class SILInstruction : public llvm::ilist_node { /// The stack allocation produced by the instruction, if any. SILValue getStackAllocation() const; + /// Returns the kind of stack memory that should be allocated. There are + /// certain (unfortunate) situations in which "stack" allocations may become + /// unnested and must use alternative allocation strategies. Rather than + /// requiring all of these to explicitly use heap allocation, which may be + /// to be significantly less efficient (e.g. ) + StackAllocationIsNested_t isStackAllocationNested() const; + + void setStackAllocationIsNested(StackAllocationIsNested_t isNested); + /// Returns true if this is the deallocation of a stack allocating instruction. /// The first operand must be the allocating instruction. bool isDeallocatingStack() const; @@ -2055,6 +2073,14 @@ class AllocStackInst final } } + StackAllocationIsNested_t isStackAllocationNested() const { + return StackAllocationIsNested_t(!sharedUInt8().AllocStackInst.isNested); + } + + void setStackAllocationIsNested(StackAllocationIsNested_t isNested) { + sharedUInt8().AllocStackInst.isNested = bool(isNested); + } + void markUsesMoveableValueDebugInfo() { sharedUInt8().AllocStackInst.usesMoveableValueDebugInfo = (bool)UsesMoveableValueDebugInfo; diff --git a/include/swift/SIL/SILNode.h b/include/swift/SIL/SILNode.h index ca4220382463a..8cf66fbf9902c 100644 --- a/include/swift/SIL/SILNode.h +++ b/include/swift/SIL/SILNode.h @@ -229,7 +229,8 @@ class alignas(8) SILNode : lexical : 1, fromVarDecl : 1, usesMoveableValueDebugInfo : 1, - hasInvalidatedVarInfo : 1); + hasInvalidatedVarInfo : 1, + isNested : 1); SHARED_FIELD(AllocBoxInst, uint8_t dynamicLifetime : 1, diff --git a/lib/IRGen/FixedTypeInfo.h b/lib/IRGen/FixedTypeInfo.h index bad9f031b9f29..c888379b4354b 100644 --- a/lib/IRGen/FixedTypeInfo.h +++ b/lib/IRGen/FixedTypeInfo.h @@ -82,8 +82,12 @@ class FixedTypeInfo : public TypeInfo { } StackAddress allocateStack(IRGenFunction &IGF, SILType T, - const llvm::Twine &name) const override; - void deallocateStack(IRGenFunction &IGF, StackAddress addr, SILType T) const override; + const llvm::Twine &name, + StackAllocationIsNested_t isNested = + StackAllocationIsNested) const override; + void deallocateStack(IRGenFunction &IGF, StackAddress addr, SILType T, + StackAllocationIsNested_t isNested = + StackAllocationIsNested) const override; void destroyStack(IRGenFunction &IGF, StackAddress addr, SILType T, bool isOutlined) const override; diff --git a/lib/IRGen/GenArray.cpp b/lib/IRGen/GenArray.cpp index b95766f74e5e7..fbd176fb4bece 100644 --- a/lib/IRGen/GenArray.cpp +++ b/lib/IRGen/GenArray.cpp @@ -639,17 +639,18 @@ class NonFixedArrayTypeInfo final } StackAddress allocateStack(IRGenFunction &IGF, SILType T, - const llvm::Twine &name) const override { + const llvm::Twine &name, + StackAllocationIsNested_t isNested) const override { // Allocate memory on the stack. - auto alloca = IGF.emitDynamicAlloca(T, name); + auto alloca = IGF.emitDeallocStackDynamic(T, name, isNested); IGF.Builder.CreateLifetimeStart(alloca.getAddressPointer()); return alloca.withAddress(getAddressForPointer(alloca.getAddressPointer())); } void deallocateStack(IRGenFunction &IGF, StackAddress stackAddress, - SILType T) const override { + SILType T, StackAllocationIsNested_t isNested) const override { IGF.Builder.CreateLifetimeEnd(stackAddress.getAddress().getAddress()); - IGF.emitDeallocateDynamicAlloca(stackAddress); + IGF.emitDeallocStackDynamic(stackAddress, isNested); } void destroyStack(IRGenFunction &IGF, StackAddress stackAddress, SILType T, diff --git a/lib/IRGen/GenInit.cpp b/lib/IRGen/GenInit.cpp index 0e6756a3ea736..e2b5d29f6178c 100644 --- a/lib/IRGen/GenInit.cpp +++ b/lib/IRGen/GenInit.cpp @@ -60,7 +60,8 @@ void IRGenModule::emitSILGlobalVariable(SILGlobalVariable *var) { } StackAddress FixedTypeInfo::allocateStack(IRGenFunction &IGF, SILType T, - const Twine &name) const { + const Twine &name, + StackAllocationIsNested_t isNested) const { // If the type is known to be empty, don't actually allocate anything. if (isKnownEmpty(ResilienceExpansion::Maximal)) { auto addr = getUndefAddress(); @@ -81,7 +82,8 @@ void FixedTypeInfo::destroyStack(IRGenFunction &IGF, StackAddress addr, } void FixedTypeInfo::deallocateStack(IRGenFunction &IGF, StackAddress addr, - SILType T) const { + SILType T, + StackAllocationIsNested_t isNested) const { if (isKnownEmpty(ResilienceExpansion::Maximal)) return; IGF.Builder.CreateLifetimeEnd(addr.getAddress(), getFixedSize()); diff --git a/lib/IRGen/GenOpaque.cpp b/lib/IRGen/GenOpaque.cpp index 1ef51b261667c..eb40e5406c02d 100644 --- a/lib/IRGen/GenOpaque.cpp +++ b/lib/IRGen/GenOpaque.cpp @@ -553,6 +553,27 @@ irgen::emitInitializeBufferWithCopyOfBufferCall(IRGenFunction &IGF, return call; } +StackAddress +IRGenFunction::emitDynamicStackAllocation(SILType T, + StackAllocationIsNested_t isNested, + const llvm::Twine &name) { + if (isNested) { + return emitDynamicAlloca(T, name); + } + + FIXME: use malloc +} + +void +IRGenFunction::emitDynamicStackDeallocation(StackAddress address, + StackAllocationIsNested_t isNested) { + if (isNested) { + return emitDeallocateDynamicAlloca(address); + } + + FIXME: use malloc +} + /// Emit a dynamic alloca call to allocate enough memory to hold an object of /// type 'T' and an optional llvm.stackrestore point if 'isInEntryBlock' is /// false. diff --git a/lib/IRGen/GenType.cpp b/lib/IRGen/GenType.cpp index 51767c715660e..99ecc8dea98bc 100644 --- a/lib/IRGen/GenType.cpp +++ b/lib/IRGen/GenType.cpp @@ -1374,11 +1374,13 @@ namespace { return nullptr; } StackAddress allocateStack(IRGenFunction &IGF, SILType T, - const llvm::Twine &name) const override { + const llvm::Twine &name, + StackAllocationIsNested_t isNested) const override { llvm_unreachable("should not call on an immovable opaque type"); } void deallocateStack(IRGenFunction &IGF, StackAddress addr, - SILType T) const override { + SILType T, + StackAllocationIsNested_t isNested) const override { llvm_unreachable("should not call on an immovable opaque type"); } void destroyStack(IRGenFunction &IGF, StackAddress addr, SILType T, diff --git a/lib/IRGen/IRGenFunction.h b/lib/IRGen/IRGenFunction.h index f10cb8cb88feb..23795f389da5d 100644 --- a/lib/IRGen/IRGenFunction.h +++ b/lib/IRGen/IRGenFunction.h @@ -317,6 +317,12 @@ class IRGenFunction { bool useTaskDeallocThrough = false, bool forCalleeCoroutineFrame = false); + StackAddress emitAllocStackDynamic(SILType type, + StackAllocationIsNested_t isNested, + const llvm::Twine &name = ""); + void emitDeallocStackDynamic(StackAddress address, + StackAllocationIsNested_t isNested); + llvm::BasicBlock *createBasicBlock(const llvm::Twine &Name); const TypeInfo &getTypeInfoForUnlowered(Type subst); const TypeInfo &getTypeInfoForUnlowered(AbstractionPattern orig, Type subst); diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp index 783aa4688b979..9da1aee6f6a0f 100644 --- a/lib/IRGen/IRGenSIL.cpp +++ b/lib/IRGen/IRGenSIL.cpp @@ -6575,7 +6575,9 @@ void IRGenSILFunction::visitAllocStackInst(swift::AllocStackInst *i) { DebugTypeInfo DbgTy; emitDebugInfoBeforeAllocStack(i, type, DbgTy); - auto stackAddr = type.allocateStack(*this, i->getElementType(), dbgname); + auto stackAddr = type.allocateStack(*this, i->getElementType(), + i->isStackAllocationNested(), + dbgname); setLoweredStackAddress(i, stackAddr); Address addr = stackAddr.getAddress(); @@ -6668,23 +6670,27 @@ void IRGenSILFunction::visitDeallocStackInst(swift::DeallocStackInst *i) { if (auto *closure = dyn_cast(i->getOperand())) { assert(closure->isOnStack()); auto stackAddr = LoweredPartialApplyAllocations[i->getOperand()]; - emitDeallocateDynamicAlloca(stackAddr); + emitDeallocStackDynamic(stackAddr, closure->isStackAllocationNested()); return; } if (isaResultOf(i->getOperand())) { auto *mvi = getAsResultOf(i->getOperand()); auto *bai = cast(mvi->getParent()); + // FIXME: [non_nested] const auto &coroutine = getLoweredCoroutine(bai->getTokenResult()); emitDeallocYieldOnce2CoroutineFrame(*this, coroutine.getCalleeAllocatedFrame()); return; } - auto allocatedType = i->getOperand()->getType(); + auto *asi = cast(i->getOperand()); + + auto allocatedType = asi->getType(); const TypeInfo &allocatedTI = getTypeInfo(allocatedType); - StackAddress stackAddr = getLoweredStackAddress(i->getOperand()); + StackAddress stackAddr = getLoweredStackAddress(asi); + auto isNested = asi->isStackAllocationNested(); - allocatedTI.deallocateStack(*this, stackAddr, allocatedType); + allocatedTI.deallocateStack(*this, stackAddr, allocatedType, isNested); } void IRGenSILFunction::visitDeallocStackRefInst(DeallocStackRefInst *i) { diff --git a/lib/IRGen/NonFixedTypeInfo.h b/lib/IRGen/NonFixedTypeInfo.h index 50a00e5ccdf07..e52a7717a9a2c 100644 --- a/lib/IRGen/NonFixedTypeInfo.h +++ b/lib/IRGen/NonFixedTypeInfo.h @@ -63,18 +63,21 @@ class WitnessSizedTypeInfo : public IndirectTypeInfo { static bool isFixed() { return false; } StackAddress allocateStack(IRGenFunction &IGF, SILType T, - const llvm::Twine &name) const override { + const llvm::Twine &name, + StackAllocationIsNested_t isNested = + StackAllocationIsNested) const override { // Allocate memory on the stack. - auto alloca = IGF.emitDynamicAlloca(T, name); + auto alloca = IGF.emitDynamicStackAllocation(T, name, isNested); IGF.Builder.CreateLifetimeStart(alloca.getAddressPointer()); return alloca.withAddress( getAsBitCastAddress(IGF, alloca.getAddressPointer())); } void deallocateStack(IRGenFunction &IGF, StackAddress stackAddress, - SILType T) const override { + SILType T, StackAllocationIsNested_t isNested = + StackAllocationIsNested) const override { IGF.Builder.CreateLifetimeEnd(stackAddress.getAddress().getAddress()); - IGF.emitDeallocateDynamicAlloca(stackAddress); + IGF.emitDynamicStackDeallocation(stackAddress, isNested); } void destroyStack(IRGenFunction &IGF, StackAddress stackAddress, SILType T, diff --git a/lib/IRGen/TypeInfo.h b/lib/IRGen/TypeInfo.h index 91a7c7bdd3d1b..6c705e764c688 100644 --- a/lib/IRGen/TypeInfo.h +++ b/lib/IRGen/TypeInfo.h @@ -355,11 +355,15 @@ class TypeInfo { /// Allocate a variable of this type on the stack. virtual StackAddress allocateStack(IRGenFunction &IGF, SILType T, - const llvm::Twine &name) const = 0; + const llvm::Twine &name, + StackAllocationIsNested_t isNested = + StackAllocationIsNested) const = 0; /// Deallocate a variable of this type. virtual void deallocateStack(IRGenFunction &IGF, StackAddress addr, - SILType T) const = 0; + SILType T, + StackAllocationIsNested_t isNested = + StackAllocationIsNested) const = 0; /// Destroy the value of a variable of this type, then deallocate its /// memory. diff --git a/lib/SIL/IR/SILInstruction.cpp b/lib/SIL/IR/SILInstruction.cpp index 1708f92a56918..f23fa41312be5 100644 --- a/lib/SIL/IR/SILInstruction.cpp +++ b/lib/SIL/IR/SILInstruction.cpp @@ -1339,6 +1339,25 @@ SILValue SILInstruction::getStackAllocation() const { return cast(this); } +StackAllocationIsNested_t SILInstruction::isStackAllocationNested() const { + assert(isAllocatingStack()); + if (auto ASI = dyn_cast(this)) { + return ASI->isStackAllocationNested(); + } else { + // TODO: implement for all remaining allocations + return StackAllocationIsNested; + } +} + +void SILInstruction::setStackAllocationIsNested(StackAllocationIsNested_t nested) { + assert(isAllocatingStack()); + if (auto ASI = dyn_cast(this)) { + ASI->setStackAllocationIsNested(nested); + } else if (!nested) { + llvm_unreachable("unimplemented"); + } +} + bool SILInstruction::isDeallocatingStack() const { // NOTE: If you're adding a new kind of deallocating instruction, // there are several places scattered around the SIL optimizer which diff --git a/lib/SIL/IR/SILInstructions.cpp b/lib/SIL/IR/SILInstructions.cpp index 3c959a16d6d80..72951c3dd2b1c 100644 --- a/lib/SIL/IR/SILInstructions.cpp +++ b/lib/SIL/IR/SILInstructions.cpp @@ -231,6 +231,7 @@ AllocStackInst::AllocStackInst( sharedUInt8().AllocStackInst.fromVarDecl = (bool)isFromVarDecl; sharedUInt8().AllocStackInst.usesMoveableValueDebugInfo = (bool)usesMoveableValueDebugInfo || elementType.isMoveOnly(); + sharedUInt8().AllocStackInst.isNested = true; sharedUInt32().AllocStackInst.numOperands = TypeDependentOperands.size(); // VarInfo must be initialized after diff --git a/lib/SIL/IR/SILPrinter.cpp b/lib/SIL/IR/SILPrinter.cpp index 0d6b1f985b7a3..f4f244c4cd4c8 100644 --- a/lib/SIL/IR/SILPrinter.cpp +++ b/lib/SIL/IR/SILPrinter.cpp @@ -1568,7 +1568,17 @@ class SILPrinter : public SILInstructionVisitor { printDebugInfoExpression(Var->DIExpr); } + template + void printNonNested(T *inst) { + static_assert(&T::isStackAllocationNested != + &SILInstruction::isStackAllocationNested, + "Type doesn't override isStackAllocationNested"); + if (!inst->isStackAllocationNested()) + *this << "[non_nested] "; + } + void visitAllocStackInst(AllocStackInst *AVI) { + printNonNested(AVI); if (AVI->hasDynamicLifetime()) *this << "[dynamic_lifetime] "; if (AVI->isLexical()) diff --git a/lib/SIL/Parser/ParseSIL.cpp b/lib/SIL/Parser/ParseSIL.cpp index b699b15a333f0..390d0d4556dd7 100644 --- a/lib/SIL/Parser/ParseSIL.cpp +++ b/lib/SIL/Parser/ParseSIL.cpp @@ -4994,6 +4994,7 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B, auto isFromVarDecl = IsNotFromVarDecl; UsesMoveableValueDebugInfo_t usesMoveableValueDebugInfo = DoesNotUseMoveableValueDebugInfo; + auto isNested = StackAllocationIsNested; StringRef attributeName; SourceLoc attributeLoc; @@ -5006,6 +5007,8 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B, isFromVarDecl = IsFromVarDecl; else if (attributeName == "moveable_value_debuginfo") usesMoveableValueDebugInfo = UsesMoveableValueDebugInfo; + else if (attributeName == "non_nested") + isNested = StackAllocationIsNotNested; else { P.diagnose(attributeLoc, diag::sil_invalid_attribute_for_instruction, attributeName, "alloc_stack"); @@ -5025,14 +5028,16 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B, usesMoveableValueDebugInfo = UsesMoveableValueDebugInfo; // It doesn't make sense to attach a debug var info if the name is empty + AllocStackInst *ASI; if (VarInfo.Name.size()) - ResultVal = B.createAllocStack(InstLoc, Ty, VarInfo, hasDynamicLifetime, - isLexical, isFromVarDecl, - usesMoveableValueDebugInfo); + ASI = B.createAllocStack(InstLoc, Ty, VarInfo, hasDynamicLifetime, + isLexical, isFromVarDecl, + usesMoveableValueDebugInfo); else - ResultVal = - B.createAllocStack(InstLoc, Ty, {}, hasDynamicLifetime, isLexical, - isFromVarDecl, usesMoveableValueDebugInfo); + ASI = B.createAllocStack(InstLoc, Ty, {}, hasDynamicLifetime, isLexical, + isFromVarDecl, usesMoveableValueDebugInfo); + ASI->setStackAllocationIsNested(isNested); + ResultVal = ASI; break; } case SILInstructionKind::MetatypeInst: { diff --git a/lib/SIL/Verifier/SILVerifier.cpp b/lib/SIL/Verifier/SILVerifier.cpp index 9ea91953ef8e5..0aad0d517cf74 100644 --- a/lib/SIL/Verifier/SILVerifier.cpp +++ b/lib/SIL/Verifier/SILVerifier.cpp @@ -7005,6 +7005,22 @@ class SILVerifier : public SILVerifierBase { } } } + + void handleScopeInst(SILInstruction &i) { + if (!ActiveOps.insert(&i).second) { + verificationFailure("operation was not ended before re-beginning it", + &i, nullptr, nullptr); + } + } + + void handleScopeEndingInst(SILInstruction &i) { + if (auto beginOp = i.getOperand(0)->getDefiningInstruction()) { + if (!ActiveOps.erase(beginOp)) { + verificationFailure("operation has already been ended", + &i, nullptr, nullptr); + } + } + } }; struct DeadEndRegionState { @@ -7105,22 +7121,31 @@ class SILVerifier : public SILVerifierBase { } if (i.isAllocatingStack()) { - if (auto *BAI = dyn_cast(&i)) { - state.Stack.push_back(BAI->getCalleeAllocationResult()); + // Nested stack allocations are pushed on the stack. Non-nested stack + // allocations are treated as active ops so that we can at least verify + // their joint post-dominance. + if (i.isStackAllocationNested()) { + state.Stack.push_back(i.getStackAllocation()); + + // Also track begin_apply as a scope instruction. + if (isa(i)) + state.handleScopeInst(i); } else { - state.Stack.push_back(cast(&i)); + state.handleScopeInst(i); } - // Not "else if": begin_apply both allocates stack and begins an - // operation. - } - if (i.isDeallocatingStack()) { + } else if (i.isDeallocatingStack()) { SILValue op = i.getOperand(0); while (auto *mvi = dyn_cast(op)) { op = mvi->getOperand(); } - if (!state.Stack.empty() && op == state.Stack.back()) { + auto beginInst = op->getDefiningInstruction(); + if (beginInst && !beginInst->isStackAllocationNested()) { + state.handleScopeEndingInst(i); + } else if (!state.Stack.empty() && op == state.Stack.back()) { state.Stack.pop_back(); + if (beginInst && isa(beginInst)) + state.handleScopeEndingInst(i); } else { verificationFailure("deallocating allocation that is not the top of the stack", &i, nullptr, @@ -7131,20 +7156,12 @@ class SILVerifier : public SILVerifierBase { }); } } else if (isScopeInst(&i)) { - bool notAlreadyPresent = state.ActiveOps.insert(&i).second; - require(notAlreadyPresent, - "operation was not ended before re-beginning it"); + state.handleScopeInst(i); } else if (isScopeEndingInst(&i)) { - if (auto beginOp = i.getOperand(0)->getDefiningInstruction()) { - bool present = state.ActiveOps.erase(beginOp); - require(present, "operation has already been ended"); - } + state.handleScopeEndingInst(i); } else if (auto *endBorrow = dyn_cast(&i)) { if (isa(endBorrow->getOperand())) { - if (auto beginOp = i.getOperand(0)->getDefiningInstruction()) { - bool present = state.ActiveOps.erase(beginOp); - require(present, "operation has already been ended"); - } + state.handleScopeEndingInst(i); } } else if (auto gaci = dyn_cast(&i)) { require(!state.GotAsyncContinuation, diff --git a/lib/SILOptimizer/Utils/StackNesting.cpp b/lib/SILOptimizer/Utils/StackNesting.cpp index 050a5d61f8385..482cc196941e8 100644 --- a/lib/SILOptimizer/Utils/StackNesting.cpp +++ b/lib/SILOptimizer/Utils/StackNesting.cpp @@ -579,7 +579,9 @@ StackNesting::Changes StackNesting::fixNesting(SILFunction *F) { // In the formal presentation, the state change is // state = STATE_PUSH(state, alloc) if (I->isAllocatingStack()) { - state.allocations.push_back(I); + // Ignore non-nested allocations. + if (I->isStackAllocationNested()) + state.allocations.push_back(I); continue; } @@ -594,6 +596,10 @@ StackNesting::Changes StackNesting::fixNesting(SILFunction *F) { SILInstruction *dealloc = I; SILInstruction *alloc = getAllocForDealloc(dealloc); + // Ignore deallocations for non-nested allocations. + if (!alloc->isStackAllocationNested()) + continue; + #ifndef NDEBUG if (state.allocations.empty()) { state.abortForUnknownAllocation(alloc, dealloc); diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp index 430cdb0ff6c2a..b9e5ebc92b134 100644 --- a/lib/Serialization/DeserializeSIL.cpp +++ b/lib/Serialization/DeserializeSIL.cpp @@ -1818,9 +1818,12 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, auto isLexical = IsLexical_t((Attr >> 1) & 0x1); auto isFromVarDecl = IsFromVarDecl_t((Attr >> 2) & 0x1); auto wasMoved = UsesMoveableValueDebugInfo_t((Attr >> 3) & 0x1); - ResultInst = Builder.createAllocStack( + auto isNested = StackAllocationIsNested_t((Attr >> 4) & 0x1); + auto ASI = Builder.createAllocStack( Loc, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn), std::nullopt, hasDynamicLifetime, isLexical, isFromVarDecl, wasMoved); + ASI->setStackAllocationIsNested(isNested); + ResultInst = ASI; break; } case SILInstructionKind::AllocPackInst: { diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp index 2c8bda1286aa5..482ab3b964354 100644 --- a/lib/Serialization/SerializeSIL.cpp +++ b/lib/Serialization/SerializeSIL.cpp @@ -1341,6 +1341,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { attr |= unsigned(ASI->isLexical()) << 1; attr |= unsigned(ASI->isFromVarDecl()) << 2; attr |= unsigned(ASI->usesMoveableValueDebugInfo()) << 3; + attr |= unsigned(ASI->isStackAllocationNested()) << 4; writeOneTypeLayout(ASI->getKind(), attr, ASI->getElementType()); break; }