@@ -401,6 +401,10 @@ class IRGenSILFunction :
401401 llvm::SmallDenseMap<StackSlotKey, Address, 8 > ShadowStackSlots;
402402 llvm::SmallDenseMap<llvm::Value *, Address, 8 > TaskAllocStackSlots;
403403 llvm::SmallDenseMap<Decl *, SmallString<4 >, 8 > AnonymousVariables;
404+ // / To avoid inserting elements into ValueDomPoints twice.
405+ llvm::SmallDenseSet<llvm::Instruction *, 8 > ValueVariables;
406+ // / Holds the DominancePoint of values that are storage for a source variable.
407+ SmallVector<std::pair<llvm::Instruction *, DominancePoint>, 8 > ValueDomPoints;
404408 unsigned NumAnonVars = 0 ;
405409
406410 // / Accumulative amount of allocated bytes on the stack. Used to limit the
@@ -691,6 +695,83 @@ class IRGenSILFunction :
691695 Size, llvm::MaybeAlign (AI->getAlignment ()));
692696 }
693697
698+ // / Try to emit an inline assembly gadget which extends the lifetime of
699+ // / \p Var. Returns whether or not this was successful.
700+ bool emitLifetimeExtendingUse (llvm::Value *Var) {
701+ llvm::Type *ArgTys;
702+ auto *Ty = Var->getType ();
703+ // Vectors, Pointers and Floats are expected to fit into a register.
704+ if (Ty->isPointerTy () || Ty->isFloatingPointTy () || Ty->isVectorTy ())
705+ ArgTys = {Ty};
706+ else {
707+ // If this is not a scalar or vector type, we can't handle it.
708+ if (isa<llvm::StructType>(Ty))
709+ return false ;
710+ // The storage is guaranteed to be no larger than the register width.
711+ // Extend the storage so it would fit into a register.
712+ llvm::Type *IntTy;
713+ switch (IGM.getClangASTContext ().getTargetInfo ().getRegisterWidth ()) {
714+ case 64 :
715+ IntTy = IGM.Int64Ty ;
716+ break ;
717+ case 32 :
718+ IntTy = IGM.Int32Ty ;
719+ break ;
720+ default :
721+ llvm_unreachable (" unsupported register width" );
722+ }
723+ ArgTys = {IntTy};
724+ Var = Var->getType ()->getIntegerBitWidth () < IntTy->getIntegerBitWidth ()
725+ ? Builder.CreateZExtOrBitCast (Var, IntTy)
726+ : Builder.CreateTruncOrBitCast (Var, IntTy);
727+ }
728+ // Emit an empty inline assembler expression depending on the register.
729+ auto *AsmFnTy = llvm::FunctionType::get (IGM.VoidTy , ArgTys, false );
730+ auto *InlineAsm = llvm::InlineAsm::get (AsmFnTy, " " , " r" , true );
731+ Builder.CreateAsmCall (InlineAsm, Var);
732+ return true ;
733+ }
734+
735+ // / At -Onone, forcibly keep all LLVM values that are tracked by
736+ // / debug variables alive by inserting an empty inline assembler
737+ // / expression depending on the value in the blocks dominated by the
738+ // / value.
739+ // /
740+ // / This is used only in async functions.
741+ void emitDebugVariableRangeExtension (const SILBasicBlock *CurBB) {
742+ if (IGM.IRGen .Opts .shouldOptimize ())
743+ return ;
744+ for (auto &Variable : ValueDomPoints) {
745+ llvm::Instruction *Var = Variable.first ;
746+ DominancePoint VarDominancePoint = Variable.second ;
747+ if (getActiveDominancePoint () == VarDominancePoint ||
748+ isActiveDominancePointDominatedBy (VarDominancePoint)) {
749+ bool ExtendedLifetime = emitLifetimeExtendingUse (Var);
750+ if (!ExtendedLifetime)
751+ continue ;
752+
753+ // Propagate dbg.values for Var into the current basic block. Note
754+ // that this shouldn't be necessary. LiveDebugValues should be doing
755+ // this but can't in general because it currently only tracks register
756+ // locations.
757+ llvm::BasicBlock *BB = Var->getParent ();
758+ llvm::BasicBlock *CurBB = Builder.GetInsertBlock ();
759+ if (BB == CurBB)
760+ // The current basic block must be a successor of the dbg.value().
761+ continue ;
762+
763+ llvm::SmallVector<llvm::DbgValueInst *, 4 > DbgValues;
764+ llvm::findDbgValues (DbgValues, Var);
765+ for (auto *DVI : DbgValues)
766+ if (DVI->getParent () == BB)
767+ IGM.DebugInfo ->getBuilder ().insertDbgValueIntrinsic (
768+ DVI->getValue (), DVI->getVariable (), DVI->getExpression (),
769+ DVI->getDebugLoc (), &*CurBB->getFirstInsertionPt ());
770+ }
771+ }
772+ }
773+
774+
694775 // / Account for bugs in LLVM.
695776 // /
696777 // / - When a variable is spilled into a stack slot, LiveDebugValues fails to
@@ -872,6 +953,14 @@ class IRGenSILFunction :
872953 // turned off for async functions, because they make it impossible to track
873954 // debug info during coroutine splitting. Instead we are relying on LLVM's
874955 // CoroSplit.cpp to emit shadow copies.
956+
957+ // Mark variables in async functions for lifetime extension, so they get
958+ // spilled into the async context.
959+ if (!IGM.IRGen .Opts .shouldOptimize () && CurSILFn->isAsync ())
960+ if (auto *Value = dyn_cast<llvm::Instruction>(Storage))
961+ if (emitLifetimeExtendingUse (Value))
962+ if (ValueVariables.insert (Value).second )
963+ ValueDomPoints.push_back ({Value, getActiveDominancePoint ()});
875964 if (IGM.IRGen .Opts .DisableDebuggerShadowCopies ||
876965 IGM.IRGen .Opts .shouldOptimize () || IsAnonymous ||
877966 (CurSILFn->isAsync () && VarInfo.ArgNo ) ||
@@ -905,6 +994,15 @@ class IRGenSILFunction :
905994 (CurSILFn->isAsync () && VarInfo.ArgNo )) {
906995 auto vals = e.claimAll ();
907996 copy.append (vals.begin (), vals.end ());
997+
998+ // Mark variables in async functions for lifetime extension, so they get
999+ // spilled into the async context.
1000+ if (!IGM.IRGen .Opts .shouldOptimize () && CurSILFn->isAsync ())
1001+ if (vals.begin () != vals.end ())
1002+ if (auto *Value = dyn_cast<llvm::Instruction>(vals.front ()))
1003+ if (emitLifetimeExtendingUse (Value))
1004+ if (ValueVariables.insert (Value).second )
1005+ ValueDomPoints.push_back ({Value, getActiveDominancePoint ()});
9081006 return ;
9091007 }
9101008
@@ -2271,6 +2369,8 @@ void IRGenSILFunction::visitSILBasicBlock(SILBasicBlock *BB) {
22712369 IGM.DebugInfo ->setCurrentLoc (
22722370 Builder, DS, RegularLocation::getAutoGeneratedLocation ());
22732371 }
2372+ if (isa<TermInst>(&I))
2373+ emitDebugVariableRangeExtension (BB);
22742374 }
22752375 visit (&I);
22762376 }
@@ -4867,7 +4967,6 @@ void IRGenSILFunction::emitDebugInfoForAllocStack(AllocStackInst *i,
48674967
48684968void IRGenSILFunction::visitAllocStackInst (swift::AllocStackInst *i) {
48694969 const TypeInfo &type = getTypeInfo (i->getElementType ());
4870-
48714970 // Derive name from SIL location.
48724971 StringRef dbgname;
48734972 VarDecl *Decl = i->getDecl ();
0 commit comments