Skip to content

Commit 050851b

Browse files
authored
Merge pull request swiftlang#36140 from adrian-prantl/let-await
2 parents 16d3f78 + c2dc87c commit 050851b

File tree

4 files changed

+151
-66
lines changed

4 files changed

+151
-66
lines changed

lib/IRGen/IRGenDebugInfo.cpp

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2413,6 +2413,20 @@ void IRGenDebugInfoImpl::emitVariableDeclaration(
24132413
DBuilder.createExpression(), Line, Loc.column, Scope, DS);
24142414
}
24152415

2416+
static bool pointsIntoAlloca(llvm::Value *Storage) {
2417+
while (Storage) {
2418+
if (auto *LdInst = dyn_cast<llvm::LoadInst>(Storage))
2419+
Storage = LdInst->getOperand(0);
2420+
else if (auto *GEPInst = dyn_cast<llvm::GetElementPtrInst>(Storage))
2421+
Storage = GEPInst->getOperand(0);
2422+
else if (auto *BCInst = dyn_cast<llvm::BitCastInst>(Storage))
2423+
Storage = BCInst->getOperand(0);
2424+
else
2425+
return isa<llvm::AllocaInst>(Storage);
2426+
}
2427+
return false;
2428+
}
2429+
24162430
void IRGenDebugInfoImpl::emitDbgIntrinsic(
24172431
IRBuilder &Builder, llvm::Value *Storage, llvm::DILocalVariable *Var,
24182432
llvm::DIExpression *Expr, unsigned Line, unsigned Col,
@@ -2454,8 +2468,11 @@ void IRGenDebugInfoImpl::emitDbgIntrinsic(
24542468
else
24552469
DBuilder.insertDeclare(Storage, Var, Expr, DL, &EntryBlock);
24562470
} else {
2457-
// Insert a dbg.value at the current insertion point.
2458-
DBuilder.insertDbgValueIntrinsic(Storage, Var, Expr, DL, BB);
2471+
if (pointsIntoAlloca(Storage))
2472+
DBuilder.insertDeclare(Storage, Var, Expr, DL, BB);
2473+
else
2474+
// Insert a dbg.value at the current insertion point.
2475+
DBuilder.insertDbgValueIntrinsic(Storage, Var, Expr, DL, BB);
24592476
}
24602477
}
24612478

lib/IRGen/IRGenSIL.cpp

Lines changed: 113 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,7 @@ class IRGenSILFunction :
399399
std::pair<unsigned, std::pair<const SILDebugScope *, StringRef>>;
400400
/// Keeps track of the mapping of source variables to -O0 shadow copy allocas.
401401
llvm::SmallDenseMap<StackSlotKey, Address, 8> ShadowStackSlots;
402+
llvm::SmallDenseMap<llvm::Value *, Address, 8> TaskAllocStackSlots;
402403
llvm::SmallDenseMap<Decl *, SmallString<4>, 8> AnonymousVariables;
403404
unsigned NumAnonVars = 0;
404405

@@ -732,10 +733,118 @@ class IRGenSILFunction :
732733
}
733734
#endif
734735

736+
static bool isCallToSwiftTaskAlloc(llvm::Value *val) {
737+
auto *call = dyn_cast<llvm::CallInst>(val);
738+
if (!call)
739+
return false;
740+
auto *callee = call->getCalledFunction();
741+
if (!callee)
742+
return false;
743+
auto isTaskAlloc = callee->getName().equals("swift_task_alloc");
744+
return isTaskAlloc;
745+
}
746+
747+
static bool isTaskAlloc(llvm::Value *Storage) {
748+
while (Storage) {
749+
if (auto *LdInst = dyn_cast<llvm::LoadInst>(Storage))
750+
Storage = LdInst->getOperand(0);
751+
else if (auto *GEPInst = dyn_cast<llvm::GetElementPtrInst>(Storage))
752+
Storage = GEPInst->getOperand(0);
753+
else if (auto *BCInst = dyn_cast<llvm::BitCastInst>(Storage))
754+
Storage = BCInst->getOperand(0);
755+
else if (auto *CallInst = dyn_cast<llvm::CallInst>(Storage))
756+
return isCallToSwiftTaskAlloc(CallInst);
757+
else
758+
break;
759+
}
760+
return false;
761+
}
762+
763+
/// Emit a direct path to an Argument.
764+
llvm::Value *getDirectCoroutineArgument(llvm::Value *Addr) {
765+
auto getDirect = [&](llvm::Instruction *Orig) {
766+
llvm::Value *Buffered = Orig->getOperand(0);
767+
llvm::Value *Direct = getDirectCoroutineArgument(Buffered);
768+
if (Buffered == Direct)
769+
return Orig;
770+
llvm::Instruction *Cloned = Orig->clone();
771+
Cloned->setOperand(0, Direct);
772+
Cloned->insertBefore(Orig);
773+
return Cloned;
774+
};
775+
if (auto *LdInst = dyn_cast<llvm::LoadInst>(Addr))
776+
return getDirect(LdInst);
777+
if (auto *GEPInst = dyn_cast<llvm::GetElementPtrInst>(Addr))
778+
return getDirect(GEPInst);
779+
if (auto *BCInst = dyn_cast<llvm::BitCastInst>(Addr))
780+
return getDirect(BCInst);
781+
if (auto *CallInst = dyn_cast<llvm::CallInst>(Addr)) {
782+
llvm::Value *Buffered = CallInst->getArgOperand(0);
783+
if (CallInst->getCalledFunction() != IGM.getProjectBoxFn()) {
784+
assert(false && "unhandled projection");
785+
return CallInst;
786+
}
787+
llvm::Value *Direct = getDirectCoroutineArgument(Buffered);
788+
if (Buffered == Direct)
789+
return CallInst;
790+
auto *Cloned = cast<llvm::CallInst>(CallInst->clone());
791+
Cloned->setArgOperand(0, Direct);
792+
Cloned->insertBefore(CallInst);
793+
return Cloned;
794+
}
795+
if (auto *AllocaInst = dyn_cast<llvm::AllocaInst>(Addr)) {
796+
llvm::Value *Direct = nullptr;
797+
unsigned NumStores = 0;
798+
for (auto &AIUse : AllocaInst->uses()) {
799+
llvm::User *U = AIUse.getUser();
800+
if (llvm::StoreInst *StInst = llvm::dyn_cast<llvm::StoreInst>(U)) {
801+
++NumStores;
802+
Direct = StInst->getOperand(0);
803+
}
804+
}
805+
if (NumStores == 1)
806+
return Direct;
807+
}
808+
return Addr;
809+
}
810+
811+
llvm::Value *emitTaskAllocShadowCopy(llvm::Value *Storage,
812+
const SILDebugScope *Scope) {
813+
auto getRec = [&](llvm::Instruction *Orig) {
814+
llvm::Instruction *Cloned = Orig->clone();
815+
Cloned->setOperand(0, emitTaskAllocShadowCopy(Orig->getOperand(0), Scope));
816+
Cloned->insertBefore(Orig);
817+
return Cloned;
818+
};
819+
if (auto *LdInst = dyn_cast<llvm::LoadInst>(Storage))
820+
return getRec(LdInst);
821+
if (auto *GEPInst = dyn_cast<llvm::GetElementPtrInst>(Storage))
822+
return getRec(GEPInst);
823+
if (auto *BCInst = dyn_cast<llvm::BitCastInst>(Storage))
824+
return getRec(BCInst);
825+
if (auto *CallInst = dyn_cast<llvm::CallInst>(Storage)) {
826+
assert(isTaskAlloc(CallInst));
827+
auto Align = IGM.getPointerAlignment();
828+
auto &Alloca = TaskAllocStackSlots[CallInst];
829+
if (!Alloca.isValid())
830+
Alloca = createAlloca(Storage->getType(), Align, "taskalloc.debug");
831+
zeroInit(cast<llvm::AllocaInst>(Alloca.getAddress()));
832+
ArtificialLocation AutoRestore(Scope, IGM.DebugInfo.get(), Builder);
833+
auto *Store =
834+
Builder.CreateStore(Storage, Alloca.getAddress(), Align);
835+
Store->moveAfter(CallInst);
836+
return Alloca.getAddress();
837+
}
838+
return Storage;
839+
}
840+
735841
/// Unconditionally emit a stack shadow copy of an \c llvm::Value.
736842
llvm::Value *emitShadowCopy(llvm::Value *Storage, const SILDebugScope *Scope,
737843
SILDebugVariable VarInfo,
738844
llvm::Optional<Alignment> _Align) {
845+
if (CurSILFn->isAsync())
846+
if (isTaskAlloc(Storage))
847+
return emitTaskAllocShadowCopy(Storage, Scope);
739848
auto Align = _Align.getValueOr(IGM.getPointerAlignment());
740849
unsigned ArgNo = VarInfo.ArgNo;
741850
auto &Alloca = ShadowStackSlots[{ArgNo, {Scope, VarInfo.Name}}];
@@ -764,7 +873,8 @@ class IRGenSILFunction :
764873
// debug info during coroutine splitting. Instead we are relying on LLVM's
765874
// CoroSplit.cpp to emit shadow copies.
766875
if (IGM.IRGen.Opts.DisableDebuggerShadowCopies ||
767-
IGM.IRGen.Opts.shouldOptimize() || IsAnonymous || CurSILFn->isAsync() ||
876+
IGM.IRGen.Opts.shouldOptimize() || IsAnonymous ||
877+
(CurSILFn->isAsync() && VarInfo.ArgNo) ||
768878
isa<llvm::AllocaInst>(Storage) || isa<llvm::UndefValue>(Storage) ||
769879
!needsShadowCopy(Storage))
770880
return Storage;
@@ -791,7 +901,8 @@ class IRGenSILFunction :
791901

792902
// Only do this at -O0.
793903
if (IGM.IRGen.Opts.DisableDebuggerShadowCopies ||
794-
IGM.IRGen.Opts.shouldOptimize() || IsAnonymous || CurSILFn->isAsync()) {
904+
IGM.IRGen.Opts.shouldOptimize() || IsAnonymous ||
905+
(CurSILFn->isAsync() && VarInfo.ArgNo)) {
795906
auto vals = e.claimAll();
796907
copy.append(vals.begin(), vals.end());
797908
return;
@@ -853,8 +964,6 @@ class IRGenSILFunction :
853964
IGM.DebugInfo->emitVariableDeclaration(Builder, Storage, Ty, DS, VarDecl,
854965
VarInfo, Indirection);
855966
}
856-
/// Emit a direct path to an Argument.
857-
llvm::Value *getDirectCoroutineArgument(llvm::Value *Addr);
858967

859968
void emitFailBB() {
860969
if (!FailBBs.empty()) {
@@ -4321,53 +4430,6 @@ void IRGenSILFunction::emitErrorResultVar(CanSILFunctionType FnTy,
43214430
IndirectValue, ArtificialValue);
43224431
}
43234432

4324-
llvm::Value *IRGenSILFunction::getDirectCoroutineArgument(llvm::Value *Addr) {
4325-
auto getDirect = [&](llvm::Instruction *Orig) {
4326-
llvm::Value *Buffered = Orig->getOperand(0);
4327-
llvm::Value *Direct = getDirectCoroutineArgument(Buffered);
4328-
if (Buffered == Direct)
4329-
return Orig;
4330-
llvm::Instruction *Cloned = Orig->clone();
4331-
Cloned->setOperand(0, Direct);
4332-
Cloned->insertBefore(Orig);
4333-
return Cloned;
4334-
};
4335-
if (auto *LdInst = dyn_cast<llvm::LoadInst>(Addr))
4336-
return getDirect(LdInst);
4337-
if (auto *GEPInst = dyn_cast<llvm::GetElementPtrInst>(Addr))
4338-
return getDirect(GEPInst);
4339-
if (auto *BCInst = dyn_cast<llvm::BitCastInst>(Addr))
4340-
return getDirect(BCInst);
4341-
if (auto *CallInst = dyn_cast<llvm::CallInst>(Addr)) {
4342-
llvm::Value *Buffered = CallInst->getArgOperand(0);
4343-
if (CallInst->getCalledFunction() != IGM.getProjectBoxFn()) {
4344-
assert(false && "unhandled projection");
4345-
return CallInst;
4346-
}
4347-
llvm::Value *Direct = getDirectCoroutineArgument(Buffered);
4348-
if (Buffered == Direct)
4349-
return CallInst;
4350-
auto *Cloned = cast<llvm::CallInst>(CallInst->clone());
4351-
Cloned->setArgOperand(0, Direct);
4352-
Cloned->insertBefore(CallInst);
4353-
return Cloned;
4354-
}
4355-
if (auto *AllocaInst = dyn_cast<llvm::AllocaInst>(Addr)) {
4356-
llvm::Value *Direct = nullptr;
4357-
unsigned NumStores = 0;
4358-
for (auto &AIUse : AllocaInst->uses()) {
4359-
llvm::User *U = AIUse.getUser();
4360-
if (llvm::StoreInst *StInst = llvm::dyn_cast<llvm::StoreInst>(U)) {
4361-
++NumStores;
4362-
Direct = StInst->getOperand(0);
4363-
}
4364-
}
4365-
if (NumStores == 1)
4366-
return Direct;
4367-
}
4368-
return Addr;
4369-
}
4370-
43714433
void IRGenSILFunction::visitDebugValueInst(DebugValueInst *i) {
43724434
if (i->getDebugScope()->getInlinedFunction()->isTransparent())
43734435
return;
@@ -4742,17 +4804,6 @@ void IRGenSILFunction::visitIsEscapingClosureInst(
47424804
setLoweredExplosion(i, out);
47434805
}
47444806

4745-
static bool isCallToSwiftTaskAlloc(llvm::Value *val) {
4746-
auto *call = dyn_cast<llvm::CallInst>(val);
4747-
if (!call)
4748-
return false;
4749-
auto *callee = call->getCalledFunction();
4750-
if (!callee)
4751-
return false;
4752-
auto isTaskAlloc = callee->getName().equals("swift_task_alloc");
4753-
return isTaskAlloc;
4754-
}
4755-
47564807
void IRGenSILFunction::emitDebugInfoForAllocStack(AllocStackInst *i,
47574808
const TypeInfo &type,
47584809
llvm::Value *addr) {

test/DebugInfo/async-let-await.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// RUN: %target-swift-frontend %s -emit-ir -g -o - \
2+
// RUN: -module-name M -enable-experimental-concurrency \
3+
// RUN: -parse-as-library | %FileCheck %s
4+
// REQUIRES: concurrency
5+
// UNSUPPORTED: CPU=arm64e
6+
7+
public func getVegetables() async -> [String] {
8+
return ["leek", "carrot"]
9+
}
10+
11+
// CHECK: define {{.*}} @"$s1M14chopVegetablesSaySSGyYKF.resume.0"
12+
public func chopVegetables() async throws -> [String] {
13+
let veggies = await getVegetables()
14+
// CHECK: call void @llvm.dbg.declare(metadata i8* %2, metadata ![[V:[0-9]+]]
15+
// CHECK: ![[V]] = !DILocalVariable(name: "veggies"
16+
return veggies.map { "chopped \($0)" }
17+
}

test/DebugInfo/inlined-generics-basic.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,8 @@ public class C<R> {
6868
// IR: call {{.*}}3use
6969
#sourceLocation(file: "f.swift", line: 3)
7070
g(r)
71-
// IR: dbg.value({{.*}}, metadata ![[GRS_T:[0-9]+]]
72-
// IR: dbg.value({{.*}}, metadata ![[GRS_U:[0-9]+]]
71+
// IR: dbg.declare({{.*}}, metadata ![[GRS_T:[0-9]+]]
72+
// IR: dbg.declare({{.*}}, metadata ![[GRS_U:[0-9]+]]
7373
// IR: call {{.*}}3use
7474
#sourceLocation(file: "f.swift", line: 4)
7575
g((r, s))

0 commit comments

Comments
 (0)