Don't emit shadow copies for anonymous variables.

Switch statements generate at least one anonymous match variable per
case, which consumes both a lot of stack space and an explosion of
range extension depencies due to the way case statements are scoped.

rdar://problem/34326355
This commit is contained in:
Adrian Prantl
2017-11-16 10:41:40 -08:00
parent 5015ee1107
commit e574aa765f
4 changed files with 55 additions and 58 deletions

View File

@@ -1994,19 +1994,7 @@ void IRGenDebugInfoImpl::emitDbgIntrinsic(
return;
}
// If the storage is an instruction, insert the dbg.value directly after it.
if (auto *I = dyn_cast<llvm::Instruction>(Storage)) {
auto InsPt = std::next(I->getIterator());
auto E = I->getParent()->end();
while (InsPt != E && isa<llvm::PHINode>(&*InsPt))
++InsPt;
if (InsPt != E) {
DBuilder.insertDbgValueIntrinsic(Storage, Var, Expr, DL, &*InsPt);
return;
}
}
// Otherwise just insert it at the current insertion point.
// Insert a dbg.value at the current insertion point.
DBuilder.insertDbgValueIntrinsic(Storage, Var, Expr, DL, BB);
}

View File

@@ -578,13 +578,15 @@ public:
}
template <class DebugVarCarryingInst>
StringRef getVarName(DebugVarCarryingInst *i) {
StringRef getVarName(DebugVarCarryingInst *i, bool &IsAnonymous) {
StringRef Name = i->getVarInfo().Name;
// The $match variables generated by the type checker are not
// guaranteed to be unique within their scope, but they have
// unique VarDecls.
if ((Name.empty() || Name == "$match") && i->getDecl())
if ((Name.empty() || Name == "$match") && i->getDecl()) {
IsAnonymous = true;
return getOrCreateAnonymousVarName(i->getDecl());
}
return Name;
}
@@ -665,15 +667,13 @@ public:
/// 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,
llvm::Value *emitShadowCopy(llvm::Value *Storage, const SILDebugScope *Scope,
StringRef Name, unsigned ArgNo, bool IsAnonymous,
Alignment Align = Alignment(0)) {
auto Ty = Storage->getType();
// Never emit shadow copies when optimizing, or if already on the stack.
if (IGM.IRGen.Opts.shouldOptimize() ||
isa<llvm::AllocaInst>(Storage) ||
isa<llvm::UndefValue>(Storage) ||
if (IGM.IRGen.Opts.shouldOptimize() || IsAnonymous ||
isa<llvm::AllocaInst>(Storage) || isa<llvm::UndefValue>(Storage) ||
Ty == IGM.RefCountedPtrTy) // No debug info is emitted for refcounts.
return Storage;
@@ -701,16 +701,17 @@ public:
}
llvm::Value *emitShadowCopy(Address Storage, const SILDebugScope *Scope,
StringRef Name, unsigned ArgNo) {
return emitShadowCopy(Storage.getAddress(), Scope, Name, ArgNo,
StringRef Name, unsigned ArgNo,
bool IsAnonymous) {
return emitShadowCopy(Storage.getAddress(), Scope, Name, ArgNo, IsAnonymous,
Storage.getAlignment());
}
void emitShadowCopy(ArrayRef<llvm::Value *> vals, const SILDebugScope *Scope,
StringRef Name, unsigned ArgNo,
StringRef Name, unsigned ArgNo, bool IsAnonymous,
llvm::SmallVectorImpl<llvm::Value *> &copy) {
// Only do this at -O0.
if (IGM.IRGen.Opts.shouldOptimize()) {
if (IGM.IRGen.Opts.shouldOptimize() || IsAnonymous) {
copy.append(vals.begin(), vals.end());
return;
}
@@ -718,7 +719,7 @@ public:
// Single or empty values.
if (vals.size() <= 1) {
for (auto val : vals)
copy.push_back(emitShadowCopy(val, Scope, Name, ArgNo));
copy.push_back(emitShadowCopy(val, Scope, Name, ArgNo, IsAnonymous));
return;
}
@@ -3435,7 +3436,7 @@ void IRGenSILFunction::emitErrorResultVar(SILResultInfo ErrorInfo,
auto ErrorResultSlot = getErrorResultSlot(IGM.silConv.getSILType(ErrorInfo));
SILDebugVariable Var = DbgValue->getVarInfo();
auto Storage = emitShadowCopy(ErrorResultSlot.getAddress(), getDebugScope(),
Var.Name, Var.ArgNo);
Var.Name, Var.ArgNo, false);
DebugTypeInfo DTI(nullptr, nullptr, ErrorInfo.getType(),
ErrorResultSlot->getType(), IGM.getPointerSize(),
IGM.getPointerAlignment(), true);
@@ -3460,7 +3461,8 @@ void IRGenSILFunction::visitDebugValueInst(DebugValueInst *i) {
return;
}
StringRef Name = getVarName(i);
bool IsAnonymous = false;
StringRef Name = getVarName(i, IsAnonymous);
DebugTypeInfo DbgTy;
SILType SILTy = SILVal->getType();
auto RealTy = SILVal->getType().getSwiftRValueType();
@@ -3481,7 +3483,8 @@ void IRGenSILFunction::visitDebugValueInst(DebugValueInst *i) {
llvm::SmallVector<llvm::Value *, 8> Copy;
Explosion e = getLoweredExplosion(SILVal);
unsigned ArgNo = i->getVarInfo().ArgNo;
emitShadowCopy(e.claimAll(), i->getDebugScope(), Name, ArgNo, Copy);
emitShadowCopy(e.claimAll(), i->getDebugScope(), Name, ArgNo, IsAnonymous,
Copy);
emitDebugVariableDeclaration(Copy, DbgTy, SILTy, i->getDebugScope(),
i->getDecl(), Name, ArgNo);
}
@@ -3497,7 +3500,8 @@ void IRGenSILFunction::visitDebugValueAddrInst(DebugValueAddrInst *i) {
if (isa<SILUndef>(SILVal))
return;
StringRef Name = getVarName(i);
bool IsAnonymous = false;
StringRef Name = getVarName(i, IsAnonymous);
auto Addr = getLoweredAddress(SILVal).getAddress();
SILType SILTy = SILVal->getType();
auto RealType = SILTy.getSwiftRValueType();
@@ -3519,7 +3523,7 @@ void IRGenSILFunction::visitDebugValueAddrInst(DebugValueAddrInst *i) {
// intrinsic.
unsigned ArgNo = i->getVarInfo().ArgNo;
emitDebugVariableDeclaration(
emitShadowCopy(Addr, i->getDebugScope(), Name, ArgNo), DbgTy,
emitShadowCopy(Addr, i->getDebugScope(), Name, ArgNo, IsAnonymous), DbgTy,
SILType(), i->getDebugScope(), Decl, Name, ArgNo,
DbgTy.isImplicitlyIndirect() ? DirectValue : IndirectValue);
}
@@ -3736,7 +3740,8 @@ void IRGenSILFunction::emitDebugInfoForAllocStack(AllocStackInst *i,
auto DbgTy = DebugTypeInfo::getLocalVariable(
CurSILFn->getDeclContext(), CurSILFn->getGenericEnvironment(), Decl,
RealType, type, false);
StringRef Name = getVarName(i);
bool IsAnonymous = false;
StringRef Name = getVarName(i, IsAnonymous);
if (auto DS = i->getDebugScope())
emitDebugVariableDeclaration(addr, DbgTy, SILTy, DS, Decl, Name,
i->getVarInfo().ArgNo);
@@ -3751,7 +3756,8 @@ void IRGenSILFunction::visitAllocStackInst(swift::AllocStackInst *i) {
StringRef dbgname;
# ifndef NDEBUG
// If this is a DEBUG build, use pretty names for the LLVM IR.
dbgname = getVarName(i);
bool IsAnonymous = false;
dbgname = getVarName(i, IsAnonymous);
# endif
(void) Decl;
@@ -3888,8 +3894,9 @@ void IRGenSILFunction::visitAllocBoxInst(swift::AllocBoxInst *i) {
->getFieldType(IGM.getSILModule(), 0));
// Derive name from SIL location.
bool IsAnonymous = false;
VarDecl *Decl = i->getDecl();
StringRef Name = getVarName(i);
StringRef Name = getVarName(i, IsAnonymous);
StringRef DbgName =
# ifndef NDEBUG
// If this is a DEBUG build, use pretty names for the LLVM IR.
@@ -3928,7 +3935,8 @@ void IRGenSILFunction::visitAllocBoxInst(swift::AllocBoxInst *i) {
IGM.DebugInfo->emitVariableDeclaration(
Builder,
emitShadowCopy(boxWithAddr.getAddress(), i->getDebugScope(), Name, 0),
emitShadowCopy(boxWithAddr.getAddress(), i->getDebugScope(), Name, 0,
IsAnonymous),
DbgTy, i->getDebugScope(), Decl, Name, 0,
DbgTy.isImplicitlyIndirect() ? DirectValue : IndirectValue);
}

View File

@@ -1,9 +1,9 @@
// RUN: %target-swift-frontend -primary-file %s -emit-ir -g -o - | %FileCheck %s
// CHECK: !DILocalVariable(name: "x4", arg: 4
// CHECK: !DILocalVariable(name: "_0", arg: 1
// CHECK: !DILocalVariable(name: "_1", arg: 2
// CHECK: !DILocalVariable(name: "_2", arg: 3
// CHECK: !DILocalVariable(name: "x4", arg: 4
public func fourth<T>(_: T, _: T, _: T, x4 : T) -> T {
return x4

View File

@@ -31,27 +31,28 @@ public func mangle(s: [UnicodeScalar]) -> [UnicodeScalar] {
// The patterns in the first case statement each define an anonymous variable,
// which shares the storage with the expression in the switch statement. Make
// sure we only emit live range extensions for the storage once per basic block.
// sure we emit a dbg.value once per basic block.
// CHECK: define {{.*}}@_T011patternvars6mangleSayAA13UnicodeScalarVGAE1s_tFA2DcfU_
// CHECK: call void asm sideeffect "", "r"
// CHECK-NOT: call void asm sideeffect "", "r"
// CHECK: br {{.*}}label
// CHECK: call void asm sideeffect "", "r"
// CHECK-NOT: call void asm sideeffect "", "r"
// CHECK: br {{.*}}label
// CHECK: call void asm sideeffect "", "r"
// CHECK-NOT: call void asm sideeffect "", "r"
// CHECK: br {{.*}}label
// CHECK: call void asm sideeffect "", "r"
// CHECK-NOT: call void asm sideeffect "", "r"
// CHECK: br {{.*}}label
// CHECK: call void asm sideeffect "", "r"
// CHECK-NOT: call void asm sideeffect "", "r"
// CHECK: br {{.*}}label
// CHECK: call void asm sideeffect "", "r"
// CHECK-NOT: call void asm sideeffect "", "r"
// CHECK: br {{.*}}label
// CHECK: call void asm sideeffect "", "r"
// CHECK-NOT: call void asm sideeffect "", "r"
// CHECK: br {{.*}}label
// CHECK: %[[VAL:[0-9]+]] = call swiftcc i32 @_T011patternvars13UnicodeScalarV5values6UInt32Vvg(i32 %0)
// CHECK-NEXT: call void @llvm.dbg.value(metadata i32 %[[VAL]]
// CHECK: ; <label>
// CHECK: call void @llvm.dbg.value(metadata i32 %[[VAL]]
// CHECK-NOT: call void @llvm.dbg.value
// CHECK-NOT: call void asm sideeffect "", "r"
// CHECK: ; <label>
// CHECK: call void @llvm.dbg.value(metadata i32 %[[VAL]]
// CHECK-NOT: call void @llvm.dbg.value
// CHECK-NOT: call void asm sideeffect "", "r"
// CHECK: ; <label>
// CHECK: call void @llvm.dbg.value(metadata i32 %[[VAL]]
// CHECK-NOT: call void @llvm.dbg.value
// CHECK-NOT: call void asm sideeffect "", "r"
// CHECK: ; <label>
// CHECK: call void @llvm.dbg.value(metadata i32 %[[VAL]]
// CHECK-NOT: call void @llvm.dbg.value
// CHECK-NOT: call void asm sideeffect "", "r"