Skip to content

Commit 3c96333

Browse files
committed
Emit debug info shadow copies of the addresses of dynamic allocas.
Whan an alloca is dynamic, all FastISel can do is describe the register in which the address of of the dynamic alloca is kept, and if the value isn't used it will get kicked out by regalloc. rdar://problem/36663932
1 parent 56d8a8d commit 3c96333

File tree

4 files changed

+95
-51
lines changed

4 files changed

+95
-51
lines changed

lib/IRGen/IRGenSIL.cpp

Lines changed: 79 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -715,18 +715,35 @@ class IRGenSILFunction :
715715
isa<llvm::PHINode>(Storage);
716716
}
717717

718+
/// Unconditionally emit a stack shadow copy of an \c llvm::Value.
719+
llvm::Value *emitShadowCopy(llvm::Value *Storage, const SILDebugScope *Scope,
720+
StringRef Name, unsigned ArgNo, Alignment Align) {
721+
if (Align.isZero())
722+
Align = IGM.getPointerAlignment();
723+
724+
auto &Alloca = ShadowStackSlots[{ArgNo, {Scope, Name}}];
725+
if (!Alloca.isValid())
726+
Alloca = createAlloca(Storage->getType(), Align, Name+".addr");
727+
728+
ArtificialLocation AutoRestore(Scope, IGM.DebugInfo, Builder);
729+
Builder.CreateStore(Storage, Alloca.getAddress(), Align);
730+
return Alloca.getAddress();
731+
}
732+
718733
/// At -Onone, emit a shadow copy of an Address in an alloca, so the
719734
/// register allocator doesn't elide the dbg.value intrinsic when
720735
/// register pressure is high. There is a trade-off to this: With
721736
/// shadow copies, we lose the precise lifetime.
722-
llvm::Value *emitShadowCopy(llvm::Value *Storage, const SILDebugScope *Scope,
723-
StringRef Name, unsigned ArgNo, bool IsAnonymous,
724-
Alignment Align = Alignment(0)) {
725-
auto Ty = Storage->getType();
737+
llvm::Value *emitShadowCopyIfNeeded(llvm::Value *Storage,
738+
const SILDebugScope *Scope,
739+
StringRef Name, unsigned ArgNo,
740+
bool IsAnonymous,
741+
Alignment Align = Alignment(0)) {
726742
// Never emit shadow copies when optimizing, or if already on the stack.
743+
// No debug info is emitted for refcounts either.
727744
if (IGM.IRGen.Opts.shouldOptimize() || IsAnonymous ||
728745
isa<llvm::AllocaInst>(Storage) || isa<llvm::UndefValue>(Storage) ||
729-
Ty == IGM.RefCountedPtrTy) // No debug info is emitted for refcounts.
746+
Storage->getType() == IGM.RefCountedPtrTy)
730747
return Storage;
731748

732749
// Always emit shadow copies for function arguments.
@@ -739,29 +756,23 @@ class IRGenSILFunction :
739756
ValueDomPoints.push_back({Value, getActiveDominancePoint()});
740757
return Storage;
741758
}
742-
743-
if (Align.isZero())
744-
Align = IGM.getPointerAlignment();
745-
746-
auto &Alloca = ShadowStackSlots[{ArgNo, {Scope, Name}}];
747-
if (!Alloca.isValid())
748-
Alloca = createAlloca(Ty, Align, Name+".addr");
749-
750-
ArtificialLocation AutoRestore(Scope, IGM.DebugInfo, Builder);
751-
Builder.CreateStore(Storage, Alloca.getAddress(), Align);
752-
return Alloca.getAddress();
759+
return emitShadowCopy(Storage, Scope, Name, ArgNo, Align);
753760
}
754761

755-
llvm::Value *emitShadowCopy(Address Storage, const SILDebugScope *Scope,
756-
StringRef Name, unsigned ArgNo,
757-
bool IsAnonymous) {
758-
return emitShadowCopy(Storage.getAddress(), Scope, Name, ArgNo, IsAnonymous,
759-
Storage.getAlignment());
762+
/// Like \c emitShadowCopyIfNeeded() but takes an \c Address instead of an
763+
/// \c llvm::Value.
764+
llvm::Value *emitShadowCopyIfNeeded(Address Storage,
765+
const SILDebugScope *Scope,
766+
StringRef Name, unsigned ArgNo,
767+
bool IsAnonymous) {
768+
return emitShadowCopyIfNeeded(Storage.getAddress(), Scope, Name, ArgNo,
769+
IsAnonymous, Storage.getAlignment());
760770
}
761771

762-
void emitShadowCopy(SILValue &SILVal, const SILDebugScope *Scope,
763-
StringRef Name, unsigned ArgNo, bool IsAnonymous,
764-
llvm::SmallVectorImpl<llvm::Value *> &copy) {
772+
/// Like \c emitShadowCopyIfNeeded() but takes an exploded value.
773+
void emitShadowCopyIfNeeded(SILValue &SILVal, const SILDebugScope *Scope,
774+
StringRef Name, unsigned ArgNo, bool IsAnonymous,
775+
llvm::SmallVectorImpl<llvm::Value *> &copy) {
765776
Explosion e = getLoweredExplosion(SILVal);
766777

767778
// Only do this at -O0.
@@ -775,7 +786,8 @@ class IRGenSILFunction :
775786
if (e.size() <= 1) {
776787
auto vals = e.claimAll();
777788
for (auto val : vals)
778-
copy.push_back(emitShadowCopy(val, Scope, Name, ArgNo, IsAnonymous));
789+
copy.push_back(
790+
emitShadowCopyIfNeeded(val, Scope, Name, ArgNo, IsAnonymous));
779791
return;
780792
}
781793

@@ -3578,8 +3590,9 @@ void IRGenSILFunction::emitErrorResultVar(SILResultInfo ErrorInfo,
35783590
return;
35793591
auto ErrorResultSlot = getErrorResultSlot(IGM.silConv.getSILType(ErrorInfo));
35803592
SILDebugVariable Var = DbgValue->getVarInfo();
3581-
auto Storage = emitShadowCopy(ErrorResultSlot.getAddress(), getDebugScope(),
3582-
Var.Name, Var.ArgNo, false);
3593+
auto Storage =
3594+
emitShadowCopyIfNeeded(ErrorResultSlot.getAddress(), getDebugScope(),
3595+
Var.Name, Var.ArgNo, false);
35833596
DebugTypeInfo DTI(nullptr, nullptr, ErrorInfo.getType(),
35843597
ErrorResultSlot->getType(), IGM.getPointerSize(),
35853598
IGM.getPointerAlignment(), true);
@@ -3625,7 +3638,8 @@ void IRGenSILFunction::visitDebugValueInst(DebugValueInst *i) {
36253638
// Put the value into a stack slot at -Onone.
36263639
llvm::SmallVector<llvm::Value *, 8> Copy;
36273640
unsigned ArgNo = i->getVarInfo().ArgNo;
3628-
emitShadowCopy(SILVal, i->getDebugScope(), Name, ArgNo, IsAnonymous, Copy);
3641+
emitShadowCopyIfNeeded(SILVal, i->getDebugScope(), Name, ArgNo, IsAnonymous,
3642+
Copy);
36293643
emitDebugVariableDeclaration(Copy, DbgTy, SILTy, i->getDebugScope(),
36303644
i->getDecl(), Name, ArgNo);
36313645
}
@@ -3665,8 +3679,9 @@ void IRGenSILFunction::visitDebugValueAddrInst(DebugValueAddrInst *i) {
36653679
// intrinsic.
36663680
unsigned ArgNo = i->getVarInfo().ArgNo;
36673681
emitDebugVariableDeclaration(
3668-
emitShadowCopy(Addr, i->getDebugScope(), Name, ArgNo, IsAnonymous), DbgTy,
3669-
SILType(), i->getDebugScope(), Decl, Name, ArgNo,
3682+
emitShadowCopyIfNeeded(Addr, i->getDebugScope(), Name, ArgNo,
3683+
IsAnonymous),
3684+
DbgTy, SILType(), i->getDebugScope(), Decl, Name, ArgNo,
36703685
(IsLoadablyByAddress || DbgTy.isImplicitlyIndirect()) ? DirectValue
36713686
: IndirectValue);
36723687
}
@@ -3871,6 +3886,31 @@ void IRGenSILFunction::emitDebugInfoForAllocStack(AllocStackInst *i,
38713886
const TypeInfo &type,
38723887
llvm::Value *addr) {
38733888
VarDecl *Decl = i->getDecl();
3889+
// Describe the underlying alloca. This way an llvm.dbg.declare instrinsic
3890+
// is used, which is valid for the entire lifetime of the alloca.
3891+
if (auto *BitCast = dyn_cast<llvm::BitCastInst>(addr))
3892+
if (auto *Alloca = dyn_cast<llvm::AllocaInst>(BitCast->getOperand(0)))
3893+
addr = Alloca;
3894+
3895+
auto DS = i->getDebugScope();
3896+
if (!DS)
3897+
return;
3898+
3899+
bool IsAnonymous = false;
3900+
unsigned ArgNo = i->getVarInfo().ArgNo;
3901+
StringRef Name = getVarName(i, IsAnonymous);
3902+
3903+
// At this point addr must be an alloca or an undef.
3904+
assert(isa<llvm::AllocaInst>(addr) || isa<llvm::UndefValue>(addr));
3905+
auto Indirection = DirectValue;
3906+
if (!IGM.IRGen.Opts.shouldOptimize())
3907+
if (auto *Alloca = dyn_cast<llvm::AllocaInst>(addr))
3908+
if (!Alloca->isStaticAlloca()) {
3909+
// Store the address of the dynamic alloca on the stack.
3910+
addr = emitShadowCopy(addr, DS, Name, ArgNo, IGM.getPointerAlignment());
3911+
Indirection = IndirectValue;
3912+
}
3913+
38743914
if (IGM.DebugInfo && Decl) {
38753915
// Ignore compiler-generated patterns but not optional bindings.
38763916
if (auto *Pattern = Decl->getParentPattern())
@@ -3883,16 +3923,13 @@ void IRGenSILFunction::emitDebugInfoForAllocStack(AllocStackInst *i,
38833923
auto DbgTy = DebugTypeInfo::getLocalVariable(
38843924
CurSILFn->getDeclContext(), CurSILFn->getGenericEnvironment(), Decl,
38853925
RealType, type, false);
3886-
bool IsAnonymous = false;
3887-
StringRef Name = getVarName(i, IsAnonymous);
3888-
// Describe the underlying alloca. This way an llvm.dbg.declare instrinsic
3889-
// is used, which is valid for the entire lifetime of the alloca.
3890-
if (auto *BitCast = dyn_cast<llvm::BitCastInst>(addr))
3891-
if (auto *Alloca = dyn_cast<llvm::AllocaInst>(BitCast->getOperand(0)))
3892-
addr = Alloca;
3893-
if (auto DS = i->getDebugScope())
3894-
emitDebugVariableDeclaration(addr, DbgTy, SILTy, DS, Decl, Name,
3895-
i->getVarInfo().ArgNo);
3926+
3927+
// FIXME: This is working around the inverse special case in LLDB.
3928+
if (DbgTy.isImplicitlyIndirect())
3929+
Indirection = DirectValue;
3930+
3931+
emitDebugVariableDeclaration(addr, DbgTy, SILTy, DS, Decl, Name, ArgNo,
3932+
Indirection);
38963933
}
38973934
}
38983935

@@ -4100,8 +4137,8 @@ void IRGenSILFunction::visitAllocBoxInst(swift::AllocBoxInst *i) {
41004137

41014138
IGM.DebugInfo->emitVariableDeclaration(
41024139
Builder,
4103-
emitShadowCopy(boxWithAddr.getAddress(), i->getDebugScope(), Name, 0,
4104-
IsAnonymous),
4140+
emitShadowCopyIfNeeded(boxWithAddr.getAddress(), i->getDebugScope(),
4141+
Name, 0, IsAnonymous),
41054142
DbgTy, i->getDebugScope(), Decl, Name, 0,
41064143
DbgTy.isImplicitlyIndirect() ? DirectValue : IndirectValue);
41074144
}

test/DebugInfo/generic_enum_closure.swift

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,16 @@ struct CErrorOr<T>
99
// CHECK-NOT: define
1010
// This is a SIL-level debug_value_addr instruction.
1111
// CHECK: call void @llvm.dbg.declare
12-
// CHECK: call void @llvm.dbg.declare({{.*}}, metadata ![[SELF:.*]], metadata !DIExpression())
12+
// Self is in a dynamic alloca, hence the shadow copy.
13+
// CHECK: call void @llvm.dbg.declare(
14+
// CHECK-SAME: metadata i8** %[[SHADOW:.*]], metadata ![[SELF:.*]], meta
15+
// CHECK-SAME: !DIExpression(DW_OP_deref))
16+
// CHECK: alloca
17+
// CHECK: %[[DYN:.*]] = alloca i8, i{{32|64}} %
18+
// CHECK: store i8* %[[DYN]], i8** %[[SHADOW]]
1319
// CHECK: ![[T1:.*]] = !DICompositeType({{.*}}, identifier: "$S20generic_enum_closure8CErrorOrVyACQq_GD")
14-
// CHECK: ![[SELF]] = !DILocalVariable(name: "self", scope: {{.*}}, type: ![[T1]])
20+
// CHECK: ![[SELF]] = !DILocalVariable(name: "self", scope:
21+
// CHECK-SAME: type: ![[T1]])
1522
value = .none
1623
}
17-
func isError() -> Bool {
18-
assert(value != nil, "the object should not contain an error")
19-
return false
20-
}
2124
}

test/DebugInfo/resilience.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,13 @@ func use<T>(_ t: T) {}
1111
public func f() {
1212
let s1 = Size(w: 1, h: 2)
1313
use(s1)
14+
// CHECK: %[[ADDR:.*]] = alloca i8*
15+
// CHECK: call void @llvm.dbg.declare(metadata i8** %[[ADDR]],
16+
// CHECK-SAME: metadata ![[V1:[0-9]+]],
17+
// CHECK-SAME: metadata !DIExpression(DW_OP_deref))
1418
// CHECK: %[[USE_BUFFER:.*]] = alloca i8,
1519
// CHECK: %[[S1:.*]] = alloca i8,
16-
// CHECK: call void @llvm.dbg.declare(metadata i8* %[[S1]],
17-
// CHECK-SAME: metadata ![[V1:[0-9]+]],
18-
// CHECK-SAME: metadata !DIExpression())
20+
// CHECK: store i8* %[[S1]], i8** %[[ADDR]]
1921
// CHECK: ![[V1]] = !DILocalVariable(name: "s1", {{.*}}type: ![[TY:[0-9]+]])
2022
// CHECK: ![[TY]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Size",
2123
// FIXME-NOT: size:

test/IRGen/generic_tuples.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ func dup<T>(_ x: T) -> (T, T) { var x = x; return (x,x) }
2222
// CHECK: [[SIZE:%.*]] = ptrtoint i8* [[SIZE_WITNESS]]
2323
// CHECK: [[X_ALLOCA:%.*]] = alloca i8, {{.*}} [[SIZE]], align 16
2424
// CHECK: [[X_TMP:%.*]] = bitcast i8* [[X_ALLOCA]] to %swift.opaque*
25+
// Debug info shadow copy.
26+
// CHECK-NEXT: store i8* [[X_ALLOCA]]
2527
// CHECK-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 2
2628
// CHECK-NEXT: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]], align 8
2729
// CHECK-NEXT: [[INITIALIZE_WITH_COPY:%.*]] = bitcast i8* [[WITNESS]] to [[OPAQUE]]* ([[OPAQUE]]*, [[OPAQUE]]*, [[TYPE]]*)*

0 commit comments

Comments
 (0)