Skip to content

Commit 7e7333e

Browse files
Merge pull request #39341 from adrian-prantl/min-salvage-pr
Support additional salvage debug info opportunities
2 parents 28d0de5 + 2edf098 commit 7e7333e

17 files changed

+453
-130
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,8 @@ ERROR(sil_invalid_column_in_sil_location,none,
522522
"column number must be a positive integer", ())
523523
ERROR(sil_invalid_scope_slot,none,
524524
"scope number must be a positive integer ", ())
525+
ERROR(sil_invalid_constant,none,
526+
"constant operand must be an integer literal ", ())
525527
ERROR(sil_scope_undeclared,none,
526528
"scope number %0 needs to be declared before first use", (unsigned))
527529
ERROR(sil_scope_redefined,none,

include/swift/SIL/SILDebugInfoExpression.h

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#ifndef SWIFT_SIL_DEBUGINFOEXPRESSION_H
1919
#define SWIFT_SIL_DEBUGINFOEXPRESSION_H
2020
#include "swift/AST/Decl.h"
21+
#include "llvm/ADT/APInt.h"
2122
#include "llvm/ADT/ArrayRef.h"
2223
#include "llvm/ADT/Optional.h"
2324
#include "llvm/ADT/iterator_range.h"
@@ -36,17 +37,30 @@ enum class SILDIExprOperator : unsigned {
3637
/// VarDecl operand pointing to the field declaration.
3738
/// Note that this directive can only appear at the end of an
3839
/// expression.
39-
Fragment
40+
Fragment,
41+
/// Perform arithmetic addition on the top two elements of the
42+
/// expression stack and push the result back to the stack.
43+
Plus,
44+
/// Subtract the top element in expression stack by the second
45+
/// element. Then push the result back to the stack.
46+
Minus,
47+
/// Push an unsigned integer constant onto the stack.
48+
ConstUInt,
49+
/// Push a signed integer constant onto the stack.
50+
ConstSInt
4051
};
4152

4253
/// Represents a single component in a debug info expression.
4354
/// Including operator and operand.
4455
struct SILDIExprElement {
4556
enum Kind {
46-
/// A di-expression operator
57+
/// A di-expression operator.
4758
OperatorKind,
48-
/// An operand that has declaration type
49-
DeclKind
59+
/// An operand that has declaration type.
60+
DeclKind,
61+
/// An integer constant value. Note that
62+
/// we don't specify its signedness here.
63+
ConstIntKind
5064
};
5165

5266
private:
@@ -55,6 +69,7 @@ struct SILDIExprElement {
5569
union {
5670
SILDIExprOperator Operator;
5771
Decl *Declaration;
72+
uint64_t ConstantInt;
5873
};
5974

6075
explicit SILDIExprElement(Kind OpK) : OpKind(OpK) {}
@@ -68,6 +83,13 @@ struct SILDIExprElement {
6883

6984
Decl *getAsDecl() const { return OpKind == DeclKind ? Declaration : nullptr; }
7085

86+
Optional<uint64_t> getAsConstInt() const {
87+
if (OpKind == ConstIntKind)
88+
return ConstantInt;
89+
else
90+
return {};
91+
}
92+
7193
static SILDIExprElement createOperator(SILDIExprOperator Op) {
7294
SILDIExprElement DIOp(OperatorKind);
7395
DIOp.Operator = Op;
@@ -79,6 +101,12 @@ struct SILDIExprElement {
79101
DIOp.Declaration = D;
80102
return DIOp;
81103
}
104+
105+
static SILDIExprElement createConstInt(uint64_t V) {
106+
SILDIExprElement DIOp(ConstIntKind);
107+
DIOp.ConstantInt = V;
108+
return DIOp;
109+
}
82110
};
83111

84112
/// For a given SILDIExprOperator, provides information
@@ -231,6 +259,19 @@ class SILDebugInfoExpression {
231259

232260
/// Create a op_fragment expression
233261
static SILDebugInfoExpression createFragment(VarDecl *Field);
262+
263+
/// Return true if this DIExpression starts with op_deref
264+
bool startsWithDeref() const {
265+
return Elements.size() &&
266+
Elements[0].getAsOperator() == SILDIExprOperator::Dereference;
267+
}
268+
269+
/// Return true if this DIExpression has op_fragment (at the end)
270+
bool hasFragment() const {
271+
return Elements.size() >= 2 &&
272+
Elements[Elements.size() - 2].getAsOperator() ==
273+
SILDIExprOperator::Fragment;
274+
}
234275
};
235276
} // end namespace swift
236277
#endif

include/swift/SIL/SILInstructionWorklist.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include "swift/SIL/SILInstruction.h"
3838
#include "swift/SIL/InstructionUtils.h"
3939
#include "swift/SIL/SILValue.h"
40+
#include "swift/SILOptimizer/Utils/DebugOptUtils.h"
4041
#include "swift/SILOptimizer/Utils/InstOptUtils.h"
4142
#include "llvm/ADT/DenseMap.h"
4243
#include "llvm/ADT/SmallVector.h"
@@ -309,7 +310,9 @@ class SILInstructionWorklist : SILInstructionWorklistBase {
309310
void eraseInstFromFunction(SILInstruction &instruction,
310311
SILBasicBlock::iterator &iterator,
311312
bool addOperandsToWorklist = true) {
312-
// Delete any debug users first.
313+
// Try to salvage debug info first.
314+
swift::salvageDebugInfo(&instruction);
315+
// Then delete old debug users.
313316
for (auto result : instruction.getResults()) {
314317
while (!result->use_empty()) {
315318
auto *user = result->use_begin()->getUser();

lib/IRGen/DebugTypeInfo.cpp

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,13 @@
2424
using namespace swift;
2525
using namespace irgen;
2626

27-
DebugTypeInfo::DebugTypeInfo(swift::Type Ty, llvm::Type *StorageTy,
27+
DebugTypeInfo::DebugTypeInfo(swift::Type Ty, llvm::Type *FragmentStorageTy,
2828
Optional<Size> size, Alignment align,
29-
bool HasDefaultAlignment, bool IsMetadata)
30-
: Type(Ty.getPointer()), StorageType(StorageTy), size(size), align(align),
31-
DefaultAlignment(HasDefaultAlignment), IsMetadataType(IsMetadata) {
29+
bool HasDefaultAlignment, bool IsMetadata,
30+
bool SizeIsFragmentSize)
31+
: Type(Ty.getPointer()), FragmentStorageType(FragmentStorageTy), size(size),
32+
align(align), DefaultAlignment(HasDefaultAlignment),
33+
IsMetadataType(IsMetadata), SizeIsFragmentSize(SizeIsFragmentSize) {
3234
assert(align.getValue() != 0);
3335
}
3436

@@ -42,7 +44,8 @@ static bool hasDefaultAlignment(swift::Type Ty) {
4244
}
4345

4446
DebugTypeInfo DebugTypeInfo::getFromTypeInfo(swift::Type Ty,
45-
const TypeInfo &Info) {
47+
const TypeInfo &Info,
48+
bool IsFragmentTypeInfo) {
4649
Optional<Size> size;
4750
if (Info.isFixedSize()) {
4851
const FixedTypeInfo &FixTy = *cast<const FixedTypeInfo>(&Info);
@@ -51,11 +54,12 @@ DebugTypeInfo DebugTypeInfo::getFromTypeInfo(swift::Type Ty,
5154
assert(Info.getStorageType() && "StorageType is a nullptr");
5255
return DebugTypeInfo(Ty.getPointer(), Info.getStorageType(), size,
5356
Info.getBestKnownAlignment(), ::hasDefaultAlignment(Ty),
54-
false);
57+
false, IsFragmentTypeInfo);
5558
}
5659

5760
DebugTypeInfo DebugTypeInfo::getLocalVariable(VarDecl *Decl, swift::Type Ty,
58-
const TypeInfo &Info) {
61+
const TypeInfo &Info,
62+
bool IsFragmentTypeInfo) {
5963

6064
auto DeclType = Decl->getInterfaceType();
6165
auto RealType = Ty;
@@ -69,30 +73,32 @@ DebugTypeInfo DebugTypeInfo::getLocalVariable(VarDecl *Decl, swift::Type Ty,
6973
// the type hasn't been mucked with by an optimization pass.
7074
auto *Type = Sugared->isEqual(RealType) ? DeclType.getPointer()
7175
: RealType.getPointer();
72-
return getFromTypeInfo(Type, Info);
76+
return getFromTypeInfo(Type, Info, IsFragmentTypeInfo);
7377
}
7478

7579
DebugTypeInfo DebugTypeInfo::getMetadata(swift::Type Ty, llvm::Type *StorageTy,
7680
Size size, Alignment align) {
7781
DebugTypeInfo DbgTy(Ty.getPointer(), StorageTy, size,
78-
align, true, false);
82+
align, true, false, false);
7983
assert(StorageTy && "StorageType is a nullptr");
80-
assert(!DbgTy.isContextArchetype() && "type metadata cannot contain an archetype");
84+
assert(!DbgTy.isContextArchetype() &&
85+
"type metadata cannot contain an archetype");
8186
return DbgTy;
8287
}
8388

8489
DebugTypeInfo DebugTypeInfo::getArchetype(swift::Type Ty, llvm::Type *StorageTy,
8590
Size size, Alignment align) {
8691
DebugTypeInfo DbgTy(Ty.getPointer(), StorageTy, size,
87-
align, true, true);
92+
align, true, true, false);
8893
assert(StorageTy && "StorageType is a nullptr");
89-
assert(!DbgTy.isContextArchetype() && "type metadata cannot contain an archetype");
94+
assert(!DbgTy.isContextArchetype() &&
95+
"type metadata cannot contain an archetype");
9096
return DbgTy;
9197
}
9298

9399
DebugTypeInfo DebugTypeInfo::getForwardDecl(swift::Type Ty) {
94100
DebugTypeInfo DbgTy(Ty.getPointer(), nullptr, {}, Alignment(1), true,
95-
false);
101+
false, false);
96102
return DbgTy;
97103
}
98104

@@ -109,29 +115,30 @@ DebugTypeInfo DebugTypeInfo::getGlobal(SILGlobalVariable *GV,
109115
Type = DeclType.getPointer();
110116
}
111117
DebugTypeInfo DbgTy(Type, StorageTy, size, align, ::hasDefaultAlignment(Type),
112-
false);
113-
assert(StorageTy && "StorageType is a nullptr");
118+
false, false);
119+
assert(StorageTy && "FragmentStorageType is a nullptr");
114120
assert(!DbgTy.isContextArchetype() &&
115121
"type of global variable cannot be an archetype");
116122
assert(align.getValue() != 0);
117123
return DbgTy;
118124
}
119125

120126
DebugTypeInfo DebugTypeInfo::getObjCClass(ClassDecl *theClass,
121-
llvm::Type *StorageType, Size size,
122-
Alignment align) {
123-
DebugTypeInfo DbgTy(theClass->getInterfaceType().getPointer(), StorageType,
124-
size, align, true, false);
125-
assert(StorageType && "StorageType is a nullptr");
126-
assert(!DbgTy.isContextArchetype() && "type of objc class cannot be an archetype");
127+
llvm::Type *FragmentStorageType,
128+
Size size, Alignment align) {
129+
DebugTypeInfo DbgTy(theClass->getInterfaceType().getPointer(),
130+
FragmentStorageType, size, align, true, false, false);
131+
assert(FragmentStorageType && "FragmentStorageType is a nullptr");
132+
assert(!DbgTy.isContextArchetype() &&
133+
"type of objc class cannot be an archetype");
127134
return DbgTy;
128135
}
129136

130137
DebugTypeInfo DebugTypeInfo::getErrorResult(swift::Type Ty,
131138
llvm::Type *StorageType, Size size,
132139
Alignment align) {
133-
assert(StorageType && "StorageType is a nullptr");
134-
return {Ty, StorageType, size, align, true, false};
140+
assert(StorageType && "FragmentStorageType is a nullptr");
141+
return {Ty, StorageType, size, align, true, false, false};
135142
}
136143

137144
bool DebugTypeInfo::operator==(DebugTypeInfo T) const {
@@ -162,9 +169,9 @@ LLVM_DUMP_METHOD void DebugTypeInfo::dump() const {
162169
llvm::errs() << "Alignment " << align.getValue() << "] ";
163170
getType()->dump(llvm::errs());
164171

165-
if (StorageType) {
166-
llvm::errs() << "StorageType=";
167-
StorageType->dump();
172+
if (FragmentStorageType) {
173+
llvm::errs() << "FragmentStorageType=";
174+
FragmentStorageType->dump();
168175
} else
169176
llvm::errs() << "forward-declared\n";
170177
}

lib/IRGen/DebugTypeInfo.h

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -42,21 +42,24 @@ class DebugTypeInfo {
4242
TypeBase *Type = nullptr;
4343
/// Needed to determine the size of basic types and to determine
4444
/// the storage type for undefined variables.
45-
llvm::Type *StorageType = nullptr;
45+
llvm::Type *FragmentStorageType = nullptr;
4646
Optional<Size> size;
4747
Alignment align;
4848
bool DefaultAlignment = true;
4949
bool IsMetadataType = false;
50+
bool SizeIsFragmentSize;
5051

5152
public:
5253
DebugTypeInfo() = default;
5354
DebugTypeInfo(swift::Type Ty, llvm::Type *StorageTy,
5455
Optional<Size> SizeInBytes, Alignment AlignInBytes,
55-
bool HasDefaultAlignment, bool IsMetadataType);
56+
bool HasDefaultAlignment, bool IsMetadataType,
57+
bool IsFragmentTypeInfo);
5658

5759
/// Create type for a local variable.
58-
static DebugTypeInfo getLocalVariable(VarDecl *Decl,
59-
swift::Type Ty, const TypeInfo &Info);
60+
static DebugTypeInfo getLocalVariable(VarDecl *Decl, swift::Type Ty,
61+
const TypeInfo &Info,
62+
bool IsFragmentTypeInfo);
6063
/// Create type for global type metadata.
6164
static DebugTypeInfo getMetadata(swift::Type Ty, llvm::Type *StorageTy,
6265
Size size, Alignment align);
@@ -68,10 +71,12 @@ class DebugTypeInfo {
6871
static DebugTypeInfo getForwardDecl(swift::Type Ty);
6972

7073
/// Create a standalone type from a TypeInfo object.
71-
static DebugTypeInfo getFromTypeInfo(swift::Type Ty, const TypeInfo &Info);
74+
static DebugTypeInfo getFromTypeInfo(swift::Type Ty, const TypeInfo &Info,
75+
bool IsFragmentTypeInfo);
7276
/// Global variables.
73-
static DebugTypeInfo getGlobal(SILGlobalVariable *GV, llvm::Type *StorageType,
74-
Size size, Alignment align);
77+
static DebugTypeInfo getGlobal(SILGlobalVariable *GV,
78+
llvm::Type *StorageType, Size size,
79+
Alignment align);
7580
/// ObjC classes.
7681
static DebugTypeInfo getObjCClass(ClassDecl *theClass,
7782
llvm::Type *StorageType, Size size,
@@ -86,24 +91,29 @@ class DebugTypeInfo {
8691

8792
// Determine whether this type is an Archetype dependent on a generic context.
8893
bool isContextArchetype() const {
89-
if (auto archetype = Type->getWithoutSpecifierType()->getAs<ArchetypeType>()) {
94+
if (auto archetype =
95+
Type->getWithoutSpecifierType()->getAs<ArchetypeType>()) {
9096
return !isa<OpaqueTypeArchetypeType>(archetype->getRoot());
9197
}
9298
return false;
9399
}
94100

95-
llvm::Type *getStorageType() const {
101+
llvm::Type *getFragmentStorageType() const {
96102
if (size && size->isZero())
97-
assert(StorageType && "only defined types may have a size");
98-
return StorageType;
103+
assert(FragmentStorageType && "only defined types may have a size");
104+
return FragmentStorageType;
99105
}
100-
Optional<Size> getSize() const { return size; }
106+
Optional<Size> getTypeSize() const {
107+
return SizeIsFragmentSize ? llvm::None : size;
108+
}
109+
Optional<Size> getRawSize() const { return size; }
101110
void setSize(Size NewSize) { size = NewSize; }
102111
Alignment getAlignment() const { return align; }
103112
bool isNull() const { return Type == nullptr; }
104-
bool isForwardDecl() const { return StorageType == nullptr; }
113+
bool isForwardDecl() const { return FragmentStorageType == nullptr; }
105114
bool isMetadataType() const { return IsMetadataType; }
106115
bool hasDefaultAlignment() const { return DefaultAlignment; }
116+
bool isSizeFragmentSize() const { return SizeIsFragmentSize; }
107117

108118
bool operator==(DebugTypeInfo T) const;
109119
bool operator!=(DebugTypeInfo T) const;
@@ -115,17 +125,18 @@ class DebugTypeInfo {
115125
/// A DebugTypeInfo with a defined size (that may be 0).
116126
class CompletedDebugTypeInfo : public DebugTypeInfo {
117127
CompletedDebugTypeInfo(DebugTypeInfo DbgTy) : DebugTypeInfo(DbgTy) {}
128+
118129
public:
119130
static Optional<CompletedDebugTypeInfo> get(DebugTypeInfo DbgTy) {
120-
if (!DbgTy.getSize())
131+
if (!DbgTy.getRawSize() || DbgTy.isSizeFragmentSize())
121132
return {};
122133
return CompletedDebugTypeInfo(DbgTy);
123134
}
124135

125136
static Optional<CompletedDebugTypeInfo>
126137
getFromTypeInfo(swift::Type Ty, const TypeInfo &Info) {
127138
return CompletedDebugTypeInfo::get(
128-
DebugTypeInfo::getFromTypeInfo(Ty, Info));
139+
DebugTypeInfo::getFromTypeInfo(Ty, Info, /*IsFragment*/ false));
129140
}
130141

131142
Size::int_type getSizeValue() const { return size->getValue(); }
@@ -144,7 +155,7 @@ template <> struct DenseMapInfo<swift::irgen::DebugTypeInfo> {
144155
static swift::irgen::DebugTypeInfo getTombstoneKey() {
145156
return swift::irgen::DebugTypeInfo(
146157
llvm::DenseMapInfo<swift::TypeBase *>::getTombstoneKey(), nullptr,
147-
swift::irgen::Size(0), swift::irgen::Alignment(), false, false);
158+
swift::irgen::Size(0), swift::irgen::Alignment(), false, false, false);
148159
}
149160
static unsigned getHashValue(swift::irgen::DebugTypeInfo Val) {
150161
return DenseMapInfo<swift::CanType>::getHashValue(Val.getType());

0 commit comments

Comments
 (0)