Skip to content

Support additional salvage debug info opportunities #39341

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 11 commits into from
Sep 20, 2021
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
2 changes: 2 additions & 0 deletions include/swift/AST/DiagnosticsParse.def
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,8 @@ ERROR(sil_invalid_column_in_sil_location,none,
"column number must be a positive integer", ())
ERROR(sil_invalid_scope_slot,none,
"scope number must be a positive integer ", ())
ERROR(sil_invalid_constant,none,
"constant operand must be an integer literal ", ())
ERROR(sil_scope_undeclared,none,
"scope number %0 needs to be declared before first use", (unsigned))
ERROR(sil_scope_redefined,none,
Expand Down
49 changes: 45 additions & 4 deletions include/swift/SIL/SILDebugInfoExpression.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#ifndef SWIFT_SIL_DEBUGINFOEXPRESSION_H
#define SWIFT_SIL_DEBUGINFOEXPRESSION_H
#include "swift/AST/Decl.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/iterator_range.h"
Expand All @@ -36,17 +37,30 @@ enum class SILDIExprOperator : unsigned {
/// VarDecl operand pointing to the field declaration.
/// Note that this directive can only appear at the end of an
/// expression.
Fragment
Fragment,
/// Perform arithmetic addition on the top two elements of the
/// expression stack and push the result back to the stack.
Plus,
/// Subtract the top element in expression stack by the second
/// element. Then push the result back to the stack.
Minus,
/// Push an unsigned integer constant onto the stack.
ConstUInt,
/// Push a signed integer constant onto the stack.
ConstSInt
};

/// Represents a single component in a debug info expression.
/// Including operator and operand.
struct SILDIExprElement {
enum Kind {
/// A di-expression operator
/// A di-expression operator.
OperatorKind,
/// An operand that has declaration type
DeclKind
/// An operand that has declaration type.
DeclKind,
/// An integer constant value. Note that
/// we don't specify its signedness here.
ConstIntKind
};

private:
Expand All @@ -55,6 +69,7 @@ struct SILDIExprElement {
union {
SILDIExprOperator Operator;
Decl *Declaration;
uint64_t ConstantInt;
};

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

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

Optional<uint64_t> getAsConstInt() const {
if (OpKind == ConstIntKind)
return ConstantInt;
else
return {};
}

static SILDIExprElement createOperator(SILDIExprOperator Op) {
SILDIExprElement DIOp(OperatorKind);
DIOp.Operator = Op;
Expand All @@ -79,6 +101,12 @@ struct SILDIExprElement {
DIOp.Declaration = D;
return DIOp;
}

static SILDIExprElement createConstInt(uint64_t V) {
SILDIExprElement DIOp(ConstIntKind);
DIOp.ConstantInt = V;
return DIOp;
}
};

/// For a given SILDIExprOperator, provides information
Expand Down Expand Up @@ -231,6 +259,19 @@ class SILDebugInfoExpression {

/// Create a op_fragment expression
static SILDebugInfoExpression createFragment(VarDecl *Field);

/// Return true if this DIExpression starts with op_deref
bool startsWithDeref() const {
return Elements.size() &&
Elements[0].getAsOperator() == SILDIExprOperator::Dereference;
}

/// Return true if this DIExpression has op_fragment (at the end)
bool hasFragment() const {
return Elements.size() >= 2 &&
Elements[Elements.size() - 2].getAsOperator() ==
SILDIExprOperator::Fragment;
}
};
} // end namespace swift
#endif
5 changes: 4 additions & 1 deletion include/swift/SIL/SILInstructionWorklist.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "swift/SIL/SILInstruction.h"
#include "swift/SIL/InstructionUtils.h"
#include "swift/SIL/SILValue.h"
#include "swift/SILOptimizer/Utils/DebugOptUtils.h"
#include "swift/SILOptimizer/Utils/InstOptUtils.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
Expand Down Expand Up @@ -309,7 +310,9 @@ class SILInstructionWorklist : SILInstructionWorklistBase {
void eraseInstFromFunction(SILInstruction &instruction,
SILBasicBlock::iterator &iterator,
bool addOperandsToWorklist = true) {
// Delete any debug users first.
// Try to salvage debug info first.
swift::salvageDebugInfo(&instruction);
// Then delete old debug users.
for (auto result : instruction.getResults()) {
while (!result->use_empty()) {
auto *user = result->use_begin()->getUser();
Expand Down
59 changes: 33 additions & 26 deletions lib/IRGen/DebugTypeInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@
using namespace swift;
using namespace irgen;

DebugTypeInfo::DebugTypeInfo(swift::Type Ty, llvm::Type *StorageTy,
DebugTypeInfo::DebugTypeInfo(swift::Type Ty, llvm::Type *FragmentStorageTy,
Optional<Size> size, Alignment align,
bool HasDefaultAlignment, bool IsMetadata)
: Type(Ty.getPointer()), StorageType(StorageTy), size(size), align(align),
DefaultAlignment(HasDefaultAlignment), IsMetadataType(IsMetadata) {
bool HasDefaultAlignment, bool IsMetadata,
bool SizeIsFragmentSize)
: Type(Ty.getPointer()), FragmentStorageType(FragmentStorageTy), size(size),
align(align), DefaultAlignment(HasDefaultAlignment),
IsMetadataType(IsMetadata), SizeIsFragmentSize(SizeIsFragmentSize) {
assert(align.getValue() != 0);
}

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

DebugTypeInfo DebugTypeInfo::getFromTypeInfo(swift::Type Ty,
const TypeInfo &Info) {
const TypeInfo &Info,
bool IsFragmentTypeInfo) {
Optional<Size> size;
if (Info.isFixedSize()) {
const FixedTypeInfo &FixTy = *cast<const FixedTypeInfo>(&Info);
Expand All @@ -51,11 +54,12 @@ DebugTypeInfo DebugTypeInfo::getFromTypeInfo(swift::Type Ty,
assert(Info.getStorageType() && "StorageType is a nullptr");
return DebugTypeInfo(Ty.getPointer(), Info.getStorageType(), size,
Info.getBestKnownAlignment(), ::hasDefaultAlignment(Ty),
false);
false, IsFragmentTypeInfo);
}

DebugTypeInfo DebugTypeInfo::getLocalVariable(VarDecl *Decl, swift::Type Ty,
const TypeInfo &Info) {
const TypeInfo &Info,
bool IsFragmentTypeInfo) {

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

DebugTypeInfo DebugTypeInfo::getMetadata(swift::Type Ty, llvm::Type *StorageTy,
Size size, Alignment align) {
DebugTypeInfo DbgTy(Ty.getPointer(), StorageTy, size,
align, true, false);
align, true, false, false);
assert(StorageTy && "StorageType is a nullptr");
assert(!DbgTy.isContextArchetype() && "type metadata cannot contain an archetype");
assert(!DbgTy.isContextArchetype() &&
"type metadata cannot contain an archetype");
return DbgTy;
}

DebugTypeInfo DebugTypeInfo::getArchetype(swift::Type Ty, llvm::Type *StorageTy,
Size size, Alignment align) {
DebugTypeInfo DbgTy(Ty.getPointer(), StorageTy, size,
align, true, true);
align, true, true, false);
assert(StorageTy && "StorageType is a nullptr");
assert(!DbgTy.isContextArchetype() && "type metadata cannot contain an archetype");
assert(!DbgTy.isContextArchetype() &&
"type metadata cannot contain an archetype");
return DbgTy;
}

DebugTypeInfo DebugTypeInfo::getForwardDecl(swift::Type Ty) {
DebugTypeInfo DbgTy(Ty.getPointer(), nullptr, {}, Alignment(1), true,
false);
false, false);
return DbgTy;
}

Expand All @@ -109,29 +115,30 @@ DebugTypeInfo DebugTypeInfo::getGlobal(SILGlobalVariable *GV,
Type = DeclType.getPointer();
}
DebugTypeInfo DbgTy(Type, StorageTy, size, align, ::hasDefaultAlignment(Type),
false);
assert(StorageTy && "StorageType is a nullptr");
false, false);
assert(StorageTy && "FragmentStorageType is a nullptr");
assert(!DbgTy.isContextArchetype() &&
"type of global variable cannot be an archetype");
assert(align.getValue() != 0);
return DbgTy;
}

DebugTypeInfo DebugTypeInfo::getObjCClass(ClassDecl *theClass,
llvm::Type *StorageType, Size size,
Alignment align) {
DebugTypeInfo DbgTy(theClass->getInterfaceType().getPointer(), StorageType,
size, align, true, false);
assert(StorageType && "StorageType is a nullptr");
assert(!DbgTy.isContextArchetype() && "type of objc class cannot be an archetype");
llvm::Type *FragmentStorageType,
Size size, Alignment align) {
DebugTypeInfo DbgTy(theClass->getInterfaceType().getPointer(),
FragmentStorageType, size, align, true, false, false);
assert(FragmentStorageType && "FragmentStorageType is a nullptr");
assert(!DbgTy.isContextArchetype() &&
"type of objc class cannot be an archetype");
return DbgTy;
}

DebugTypeInfo DebugTypeInfo::getErrorResult(swift::Type Ty,
llvm::Type *StorageType, Size size,
Alignment align) {
assert(StorageType && "StorageType is a nullptr");
return {Ty, StorageType, size, align, true, false};
assert(StorageType && "FragmentStorageType is a nullptr");
return {Ty, StorageType, size, align, true, false, false};
}

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

if (StorageType) {
llvm::errs() << "StorageType=";
StorageType->dump();
if (FragmentStorageType) {
llvm::errs() << "FragmentStorageType=";
FragmentStorageType->dump();
} else
llvm::errs() << "forward-declared\n";
}
Expand Down
43 changes: 27 additions & 16 deletions lib/IRGen/DebugTypeInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,21 +42,24 @@ class DebugTypeInfo {
TypeBase *Type = nullptr;
/// Needed to determine the size of basic types and to determine
/// the storage type for undefined variables.
llvm::Type *StorageType = nullptr;
llvm::Type *FragmentStorageType = nullptr;
Optional<Size> size;
Alignment align;
bool DefaultAlignment = true;
bool IsMetadataType = false;
bool SizeIsFragmentSize;

public:
DebugTypeInfo() = default;
DebugTypeInfo(swift::Type Ty, llvm::Type *StorageTy,
Optional<Size> SizeInBytes, Alignment AlignInBytes,
bool HasDefaultAlignment, bool IsMetadataType);
bool HasDefaultAlignment, bool IsMetadataType,
bool IsFragmentTypeInfo);

/// Create type for a local variable.
static DebugTypeInfo getLocalVariable(VarDecl *Decl,
swift::Type Ty, const TypeInfo &Info);
static DebugTypeInfo getLocalVariable(VarDecl *Decl, swift::Type Ty,
const TypeInfo &Info,
bool IsFragmentTypeInfo);
/// Create type for global type metadata.
static DebugTypeInfo getMetadata(swift::Type Ty, llvm::Type *StorageTy,
Size size, Alignment align);
Expand All @@ -68,10 +71,12 @@ class DebugTypeInfo {
static DebugTypeInfo getForwardDecl(swift::Type Ty);

/// Create a standalone type from a TypeInfo object.
static DebugTypeInfo getFromTypeInfo(swift::Type Ty, const TypeInfo &Info);
static DebugTypeInfo getFromTypeInfo(swift::Type Ty, const TypeInfo &Info,
bool IsFragmentTypeInfo);
/// Global variables.
static DebugTypeInfo getGlobal(SILGlobalVariable *GV, llvm::Type *StorageType,
Size size, Alignment align);
static DebugTypeInfo getGlobal(SILGlobalVariable *GV,
llvm::Type *StorageType, Size size,
Alignment align);
/// ObjC classes.
static DebugTypeInfo getObjCClass(ClassDecl *theClass,
llvm::Type *StorageType, Size size,
Expand All @@ -86,24 +91,29 @@ class DebugTypeInfo {

// Determine whether this type is an Archetype dependent on a generic context.
bool isContextArchetype() const {
if (auto archetype = Type->getWithoutSpecifierType()->getAs<ArchetypeType>()) {
if (auto archetype =
Type->getWithoutSpecifierType()->getAs<ArchetypeType>()) {
return !isa<OpaqueTypeArchetypeType>(archetype->getRoot());
}
return false;
}

llvm::Type *getStorageType() const {
llvm::Type *getFragmentStorageType() const {
if (size && size->isZero())
assert(StorageType && "only defined types may have a size");
return StorageType;
assert(FragmentStorageType && "only defined types may have a size");
return FragmentStorageType;
}
Optional<Size> getSize() const { return size; }
Optional<Size> getTypeSize() const {
return SizeIsFragmentSize ? llvm::None : size;
}
Optional<Size> getRawSize() const { return size; }
void setSize(Size NewSize) { size = NewSize; }
Alignment getAlignment() const { return align; }
bool isNull() const { return Type == nullptr; }
bool isForwardDecl() const { return StorageType == nullptr; }
bool isForwardDecl() const { return FragmentStorageType == nullptr; }
bool isMetadataType() const { return IsMetadataType; }
bool hasDefaultAlignment() const { return DefaultAlignment; }
bool isSizeFragmentSize() const { return SizeIsFragmentSize; }

bool operator==(DebugTypeInfo T) const;
bool operator!=(DebugTypeInfo T) const;
Expand All @@ -115,17 +125,18 @@ class DebugTypeInfo {
/// A DebugTypeInfo with a defined size (that may be 0).
class CompletedDebugTypeInfo : public DebugTypeInfo {
CompletedDebugTypeInfo(DebugTypeInfo DbgTy) : DebugTypeInfo(DbgTy) {}

public:
static Optional<CompletedDebugTypeInfo> get(DebugTypeInfo DbgTy) {
if (!DbgTy.getSize())
if (!DbgTy.getRawSize() || DbgTy.isSizeFragmentSize())
return {};
return CompletedDebugTypeInfo(DbgTy);
}

static Optional<CompletedDebugTypeInfo>
getFromTypeInfo(swift::Type Ty, const TypeInfo &Info) {
return CompletedDebugTypeInfo::get(
DebugTypeInfo::getFromTypeInfo(Ty, Info));
DebugTypeInfo::getFromTypeInfo(Ty, Info, /*IsFragment*/ false));
}

Size::int_type getSizeValue() const { return size->getValue(); }
Expand All @@ -144,7 +155,7 @@ template <> struct DenseMapInfo<swift::irgen::DebugTypeInfo> {
static swift::irgen::DebugTypeInfo getTombstoneKey() {
return swift::irgen::DebugTypeInfo(
llvm::DenseMapInfo<swift::TypeBase *>::getTombstoneKey(), nullptr,
swift::irgen::Size(0), swift::irgen::Alignment(), false, false);
swift::irgen::Size(0), swift::irgen::Alignment(), false, false, false);
}
static unsigned getHashValue(swift::irgen::DebugTypeInfo Val) {
return DenseMapInfo<swift::CanType>::getHashValue(Val.getType());
Expand Down
Loading