Skip to content

When generating debug info for AllocStackInst, make sure to describe #14573

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 15, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 79 additions & 37 deletions lib/IRGen/IRGenSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -715,18 +715,35 @@ class IRGenSILFunction :
isa<llvm::PHINode>(Storage);
}

/// Unconditionally emit a stack shadow copy of an \c llvm::Value.
llvm::Value *emitShadowCopy(llvm::Value *Storage, const SILDebugScope *Scope,
StringRef Name, unsigned ArgNo, Alignment Align) {
if (Align.isZero())
Align = IGM.getPointerAlignment();

auto &Alloca = ShadowStackSlots[{ArgNo, {Scope, Name}}];
if (!Alloca.isValid())
Alloca = createAlloca(Storage->getType(), Align, Name+".addr");

ArtificialLocation AutoRestore(Scope, IGM.DebugInfo, Builder);
Builder.CreateStore(Storage, Alloca.getAddress(), Align);
return Alloca.getAddress();
}

/// At -Onone, emit a shadow copy of an Address in an alloca, so the
/// register allocator doesn't elide the dbg.value intrinsic when
/// register pressure is high. There is a trade-off to this: With
/// shadow copies, we lose the precise lifetime.
llvm::Value *emitShadowCopy(llvm::Value *Storage, const SILDebugScope *Scope,
StringRef Name, unsigned ArgNo, bool IsAnonymous,
Alignment Align = Alignment(0)) {
auto Ty = Storage->getType();
llvm::Value *emitShadowCopyIfNeeded(llvm::Value *Storage,
const SILDebugScope *Scope,
StringRef Name, unsigned ArgNo,
bool IsAnonymous,
Alignment Align = Alignment(0)) {
// Never emit shadow copies when optimizing, or if already on the stack.
// No debug info is emitted for refcounts either.
if (IGM.IRGen.Opts.shouldOptimize() || IsAnonymous ||
isa<llvm::AllocaInst>(Storage) || isa<llvm::UndefValue>(Storage) ||
Ty == IGM.RefCountedPtrTy) // No debug info is emitted for refcounts.
Storage->getType() == IGM.RefCountedPtrTy)
return Storage;

// Always emit shadow copies for function arguments.
Expand All @@ -739,29 +756,23 @@ class IRGenSILFunction :
ValueDomPoints.push_back({Value, getActiveDominancePoint()});
return Storage;
}

if (Align.isZero())
Align = IGM.getPointerAlignment();

auto &Alloca = ShadowStackSlots[{ArgNo, {Scope, Name}}];
if (!Alloca.isValid())
Alloca = createAlloca(Ty, Align, Name+".addr");

ArtificialLocation AutoRestore(Scope, IGM.DebugInfo, Builder);
Builder.CreateStore(Storage, Alloca.getAddress(), Align);
return Alloca.getAddress();
return emitShadowCopy(Storage, Scope, Name, ArgNo, Align);
}

llvm::Value *emitShadowCopy(Address Storage, const SILDebugScope *Scope,
StringRef Name, unsigned ArgNo,
bool IsAnonymous) {
return emitShadowCopy(Storage.getAddress(), Scope, Name, ArgNo, IsAnonymous,
Storage.getAlignment());
/// Like \c emitShadowCopyIfNeeded() but takes an \c Address instead of an
/// \c llvm::Value.
llvm::Value *emitShadowCopyIfNeeded(Address Storage,
const SILDebugScope *Scope,
StringRef Name, unsigned ArgNo,
bool IsAnonymous) {
return emitShadowCopyIfNeeded(Storage.getAddress(), Scope, Name, ArgNo,
IsAnonymous, Storage.getAlignment());
}

void emitShadowCopy(SILValue &SILVal, const SILDebugScope *Scope,
StringRef Name, unsigned ArgNo, bool IsAnonymous,
llvm::SmallVectorImpl<llvm::Value *> &copy) {
/// Like \c emitShadowCopyIfNeeded() but takes an exploded value.
void emitShadowCopyIfNeeded(SILValue &SILVal, const SILDebugScope *Scope,
StringRef Name, unsigned ArgNo, bool IsAnonymous,
llvm::SmallVectorImpl<llvm::Value *> &copy) {
Explosion e = getLoweredExplosion(SILVal);

// Only do this at -O0.
Expand All @@ -775,7 +786,8 @@ class IRGenSILFunction :
if (e.size() <= 1) {
auto vals = e.claimAll();
for (auto val : vals)
copy.push_back(emitShadowCopy(val, Scope, Name, ArgNo, IsAnonymous));
copy.push_back(
emitShadowCopyIfNeeded(val, Scope, Name, ArgNo, IsAnonymous));
return;
}

Expand Down Expand Up @@ -3578,8 +3590,9 @@ void IRGenSILFunction::emitErrorResultVar(SILResultInfo ErrorInfo,
return;
auto ErrorResultSlot = getErrorResultSlot(IGM.silConv.getSILType(ErrorInfo));
SILDebugVariable Var = DbgValue->getVarInfo();
auto Storage = emitShadowCopy(ErrorResultSlot.getAddress(), getDebugScope(),
Var.Name, Var.ArgNo, false);
auto Storage =
emitShadowCopyIfNeeded(ErrorResultSlot.getAddress(), getDebugScope(),
Var.Name, Var.ArgNo, false);
DebugTypeInfo DTI(nullptr, nullptr, ErrorInfo.getType(),
ErrorResultSlot->getType(), IGM.getPointerSize(),
IGM.getPointerAlignment(), true);
Expand Down Expand Up @@ -3625,7 +3638,8 @@ void IRGenSILFunction::visitDebugValueInst(DebugValueInst *i) {
// Put the value into a stack slot at -Onone.
llvm::SmallVector<llvm::Value *, 8> Copy;
unsigned ArgNo = i->getVarInfo().ArgNo;
emitShadowCopy(SILVal, i->getDebugScope(), Name, ArgNo, IsAnonymous, Copy);
emitShadowCopyIfNeeded(SILVal, i->getDebugScope(), Name, ArgNo, IsAnonymous,
Copy);
emitDebugVariableDeclaration(Copy, DbgTy, SILTy, i->getDebugScope(),
i->getDecl(), Name, ArgNo);
}
Expand Down Expand Up @@ -3665,8 +3679,9 @@ void IRGenSILFunction::visitDebugValueAddrInst(DebugValueAddrInst *i) {
// intrinsic.
unsigned ArgNo = i->getVarInfo().ArgNo;
emitDebugVariableDeclaration(
emitShadowCopy(Addr, i->getDebugScope(), Name, ArgNo, IsAnonymous), DbgTy,
SILType(), i->getDebugScope(), Decl, Name, ArgNo,
emitShadowCopyIfNeeded(Addr, i->getDebugScope(), Name, ArgNo,
IsAnonymous),
DbgTy, SILType(), i->getDebugScope(), Decl, Name, ArgNo,
(IsLoadablyByAddress || DbgTy.isImplicitlyIndirect()) ? DirectValue
: IndirectValue);
}
Expand Down Expand Up @@ -3871,6 +3886,31 @@ void IRGenSILFunction::emitDebugInfoForAllocStack(AllocStackInst *i,
const TypeInfo &type,
llvm::Value *addr) {
VarDecl *Decl = i->getDecl();
// Describe the underlying alloca. This way an llvm.dbg.declare instrinsic
// is used, which is valid for the entire lifetime of the alloca.
if (auto *BitCast = dyn_cast<llvm::BitCastInst>(addr))
if (auto *Alloca = dyn_cast<llvm::AllocaInst>(BitCast->getOperand(0)))
addr = Alloca;

auto DS = i->getDebugScope();
if (!DS)
return;

bool IsAnonymous = false;
unsigned ArgNo = i->getVarInfo().ArgNo;
StringRef Name = getVarName(i, IsAnonymous);

// At this point addr must be an alloca or an undef.
assert(isa<llvm::AllocaInst>(addr) || isa<llvm::UndefValue>(addr));
auto Indirection = DirectValue;
if (!IGM.IRGen.Opts.shouldOptimize())
if (auto *Alloca = dyn_cast<llvm::AllocaInst>(addr))
if (!Alloca->isStaticAlloca()) {
// Store the address of the dynamic alloca on the stack.
addr = emitShadowCopy(addr, DS, Name, ArgNo, IGM.getPointerAlignment());
Indirection = IndirectValue;
}

if (IGM.DebugInfo && Decl) {
// Ignore compiler-generated patterns but not optional bindings.
if (auto *Pattern = Decl->getParentPattern())
Expand All @@ -3883,11 +3923,13 @@ void IRGenSILFunction::emitDebugInfoForAllocStack(AllocStackInst *i,
auto DbgTy = DebugTypeInfo::getLocalVariable(
CurSILFn->getDeclContext(), CurSILFn->getGenericEnvironment(), Decl,
RealType, type, false);
bool IsAnonymous = false;
StringRef Name = getVarName(i, IsAnonymous);
if (auto DS = i->getDebugScope())
emitDebugVariableDeclaration(addr, DbgTy, SILTy, DS, Decl, Name,
i->getVarInfo().ArgNo);

// FIXME: This is working around the inverse special case in LLDB.
if (DbgTy.isImplicitlyIndirect())
Indirection = DirectValue;

emitDebugVariableDeclaration(addr, DbgTy, SILTy, DS, Decl, Name, ArgNo,
Indirection);
}
}

Expand Down Expand Up @@ -4095,8 +4137,8 @@ void IRGenSILFunction::visitAllocBoxInst(swift::AllocBoxInst *i) {

IGM.DebugInfo->emitVariableDeclaration(
Builder,
emitShadowCopy(boxWithAddr.getAddress(), i->getDebugScope(), Name, 0,
IsAnonymous),
emitShadowCopyIfNeeded(boxWithAddr.getAddress(), i->getDebugScope(),
Name, 0, IsAnonymous),
DbgTy, i->getDebugScope(), Decl, Name, 0,
DbgTy.isImplicitlyIndirect() ? DirectValue : IndirectValue);
}
Expand Down
16 changes: 10 additions & 6 deletions test/DebugInfo/generic_enum_closure.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,17 @@ struct CErrorOr<T>
// CHECK: define hidden {{.*}}void @"$S20generic_enum_closure8CErrorOrV1xACyxGAA14__CurrentErrnoV_tcfC"
// CHECK-NOT: define
// This is a SIL-level debug_value_addr instruction.
// CHECK: call void @llvm.dbg.value({{.*}}, metadata ![[SELF:.*]], metadata !DIExpression())
// CHECK: call void @llvm.dbg.declare
// Self is in a dynamic alloca, hence the shadow copy.
// CHECK: call void @llvm.dbg.declare(
// CHECK-SAME: metadata i8** %[[SHADOW:.*]], metadata ![[SELF:.*]], meta
// CHECK-SAME: !DIExpression(DW_OP_deref))
// CHECK: alloca
// CHECK: %[[DYN:.*]] = alloca i8, i{{32|64}} %
// CHECK: store i8* %[[DYN]], i8** %[[SHADOW]]
// CHECK: ![[T1:.*]] = !DICompositeType({{.*}}, identifier: "$S20generic_enum_closure8CErrorOrVyACQq_GD")
// CHECK: ![[SELF]] = !DILocalVariable(name: "self", scope: {{.*}}, type: ![[T1]])
// CHECK: ![[SELF]] = !DILocalVariable(name: "self", scope:
// CHECK-SAME: type: ![[T1]])
value = .none
}
func isError() -> Bool {
assert(value != nil, "the object should not contain an error")
return false
}
}
25 changes: 25 additions & 0 deletions test/DebugInfo/resilience.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend -g -emit-module -enable-resilience \
// RUN: -emit-module-path=%t/resilient_struct.swiftmodule \
// RUN: -module-name=resilient_struct %S/../Inputs/resilient_struct.swift
// RUN: %target-swift-frontend -g -I %t -emit-ir -enable-resilience %s \
// RUN: | %FileCheck %s
import resilient_struct

func use<T>(_ t: T) {}

public func f() {
let s1 = Size(w: 1, h: 2)
use(s1)
// CHECK: %[[ADDR:.*]] = alloca i8*
// CHECK: call void @llvm.dbg.declare(metadata i8** %[[ADDR]],
// CHECK-SAME: metadata ![[V1:[0-9]+]],
// CHECK-SAME: metadata !DIExpression(DW_OP_deref))
// CHECK: %[[USE_BUFFER:.*]] = alloca i8,
// CHECK: %[[S1:.*]] = alloca i8,
// CHECK: store i8* %[[S1]], i8** %[[ADDR]]
// CHECK: ![[V1]] = !DILocalVariable(name: "s1", {{.*}}type: ![[TY:[0-9]+]])
// CHECK: ![[TY]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Size",
// FIXME-NOT: size:
// CHECK: =
}
2 changes: 2 additions & 0 deletions test/IRGen/generic_tuples.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ func dup<T>(_ x: T) -> (T, T) { var x = x; return (x,x) }
// CHECK: [[SIZE:%.*]] = ptrtoint i8* [[SIZE_WITNESS]]
// CHECK: [[X_ALLOCA:%.*]] = alloca i8, {{.*}} [[SIZE]], align 16
// CHECK: [[X_TMP:%.*]] = bitcast i8* [[X_ALLOCA]] to %swift.opaque*
// Debug info shadow copy.
// CHECK-NEXT: store i8* [[X_ALLOCA]]
// CHECK-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 2
// CHECK-NEXT: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]], align 8
// CHECK-NEXT: [[INITIALIZE_WITH_COPY:%.*]] = bitcast i8* [[WITNESS]] to [[OPAQUE]]* ([[OPAQUE]]*, [[OPAQUE]]*, [[TYPE]]*)*
Expand Down