@@ -401,6 +401,10 @@ class IRGenSILFunction :
401
401
llvm::SmallDenseMap<StackSlotKey, Address, 8 > ShadowStackSlots;
402
402
llvm::SmallDenseMap<llvm::Value *, Address, 8 > TaskAllocStackSlots;
403
403
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;
404
408
unsigned NumAnonVars = 0 ;
405
409
406
410
// / Accumulative amount of allocated bytes on the stack. Used to limit the
@@ -691,6 +695,83 @@ class IRGenSILFunction :
691
695
Size, llvm::MaybeAlign (AI->getAlignment ()));
692
696
}
693
697
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
+
694
775
// / Account for bugs in LLVM.
695
776
// /
696
777
// / - When a variable is spilled into a stack slot, LiveDebugValues fails to
@@ -872,6 +953,14 @@ class IRGenSILFunction :
872
953
// turned off for async functions, because they make it impossible to track
873
954
// debug info during coroutine splitting. Instead we are relying on LLVM's
874
955
// 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 ()});
875
964
if (IGM.IRGen .Opts .DisableDebuggerShadowCopies ||
876
965
IGM.IRGen .Opts .shouldOptimize () || IsAnonymous ||
877
966
(CurSILFn->isAsync () && VarInfo.ArgNo ) ||
@@ -905,6 +994,15 @@ class IRGenSILFunction :
905
994
(CurSILFn->isAsync () && VarInfo.ArgNo )) {
906
995
auto vals = e.claimAll ();
907
996
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 ()});
908
1006
return ;
909
1007
}
910
1008
@@ -2271,6 +2369,8 @@ void IRGenSILFunction::visitSILBasicBlock(SILBasicBlock *BB) {
2271
2369
IGM.DebugInfo ->setCurrentLoc (
2272
2370
Builder, DS, RegularLocation::getAutoGeneratedLocation ());
2273
2371
}
2372
+ if (isa<TermInst>(&I))
2373
+ emitDebugVariableRangeExtension (BB);
2274
2374
}
2275
2375
visit (&I);
2276
2376
}
@@ -4867,7 +4967,6 @@ void IRGenSILFunction::emitDebugInfoForAllocStack(AllocStackInst *i,
4867
4967
4868
4968
void IRGenSILFunction::visitAllocStackInst (swift::AllocStackInst *i) {
4869
4969
const TypeInfo &type = getTypeInfo (i->getElementType ());
4870
-
4871
4970
// Derive name from SIL location.
4872
4971
StringRef dbgname;
4873
4972
VarDecl *Decl = i->getDecl ();
0 commit comments