Skip to content
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
221 changes: 94 additions & 127 deletions lib/IRGen/IRGenDebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -885,74 +885,6 @@ llvm::DIFile *IRGenDebugInfo::getFile(llvm::DIScope *Scope) {
return cast<llvm::DIFile>(Scope);
}

/// Return the storage size of an explosion value.
static uint64_t getSizeFromExplosionValue(const clang::TargetInfo &TI,
llvm::Value *V) {
llvm::Type *Ty = V->getType();
if (unsigned PrimitiveSize = Ty->getPrimitiveSizeInBits())
return PrimitiveSize;
else if (Ty->isPointerTy())
return TI.getPointerWidth(0);
else
llvm_unreachable("unhandled type of explosion value");
}

/// A generator that recursively returns the size of each element of a
/// composite type.
class ElementSizes {
const TrackingDIRefMap &DIRefMap;
llvm::SmallPtrSetImpl<const llvm::DIType *> &IndirectEnums;
llvm::SmallVector<const llvm::DIType *, 12> Stack;
public:
ElementSizes(const llvm::DIType *DITy, const TrackingDIRefMap &DIRefMap,
llvm::SmallPtrSetImpl<const llvm::DIType *> &IndirectEnums)
: DIRefMap(DIRefMap), IndirectEnums(IndirectEnums), Stack(1, DITy) {}

struct SizeAlign {
uint64_t SizeInBits, AlignInBits;
};

struct SizeAlign getNext() {
if (Stack.empty())
return {0, 0};

auto *Cur = Stack.pop_back_val();
if (isa<llvm::DICompositeType>(Cur) &&
Cur->getTag() != llvm::dwarf::DW_TAG_subroutine_type) {
auto *CTy = cast<llvm::DICompositeType>(Cur);
auto Elts = CTy->getElements();
unsigned N = Cur->getTag() == llvm::dwarf::DW_TAG_union_type
? std::min(1U, Elts.size()) // For unions, pick any one.
: Elts.size();

if (N) {
// Push all elements in reverse order.
// FIXME: With a little more state we don't need to actually
// store them on the Stack.
for (unsigned I = N; I > 0; --I)
Stack.push_back(cast<llvm::DIType>(Elts[I - 1]));
return getNext();
}
}
switch (Cur->getTag()) {
case llvm::dwarf::DW_TAG_member:
// FIXME: Correctly handle the explosion value for enum types
// with indirect members.
if (IndirectEnums.count(Cur))
return {0, 0};
[[clang::fallthrough]];
case llvm::dwarf::DW_TAG_typedef: {
// Replace top of stack.
auto *DTy = cast<llvm::DIDerivedType>(Cur);
Stack.push_back(DTy->getBaseType().resolve(DIRefMap));
return getNext();
}
default:
return {Cur->getSizeInBits(), Cur->getAlignInBits()};
}
}
};

static Size
getStorageSize(const llvm::DataLayout &DL, ArrayRef<llvm::Value *> Storage) {
unsigned size = 0;
Expand Down Expand Up @@ -1012,13 +944,16 @@ void IRGenDebugInfo::emitVariableDeclaration(
Optimized, Flags);

// Insert a debug intrinsic into the current block.
unsigned OffsetInBits = 0;
auto *BB = Builder.GetInsertBlock();
bool IsPiece = Storage.size() > 1;
uint64_t SizeOfByte = CI.getTargetInfo().getCharWidth();
unsigned VarSizeInBits = getSizeInBits(Var, DIRefMap);
ElementSizes EltSizes(DITy, DIRefMap, IndirectEnumCases);
auto Dim = EltSizes.getNext();

// Running variables for the current/previous piece.
unsigned SizeInBits = 0;
unsigned AlignInBits = SizeOfByte;
unsigned OffsetInBits = 0;

for (llvm::Value *Piece : Storage) {
SmallVector<uint64_t, 3> Operands;
if (Indirection)
Expand All @@ -1030,35 +965,22 @@ void IRGenDebugInfo::emitVariableDeclaration(
Piece = llvm::ConstantInt::get(llvm::Type::getInt64Ty(M.getContext()), 0);

if (IsPiece) {
// Try to get the size from the type if possible.
auto StorageSize = getSizeFromExplosionValue(CI.getTargetInfo(), Piece);
// FIXME: The TypeInfo for bound generic enum types reports a
// type <{}> (with size 0) but a concrete instance may still
// have storage allocated for it. rdar://problem/21470869
if (!Dim.SizeInBits || (StorageSize && Dim.SizeInBits > StorageSize))
Dim.SizeInBits = StorageSize;

// FIXME: Occasionally we miss out that the Storage is actually a
// refcount wrapper. Silently skip these for now.
if (OffsetInBits+Dim.SizeInBits > VarSizeInBits)
break;
if (OffsetInBits == 0 && Dim.SizeInBits == VarSizeInBits)
break;
if (Dim.SizeInBits == 0)
break;

assert(Dim.SizeInBits < VarSizeInBits
&& "piece covers entire var");
assert(OffsetInBits+Dim.SizeInBits <= VarSizeInBits && "pars > totum");
// Advance the offset and align it for the next piece.
OffsetInBits += llvm::alignTo(SizeInBits, AlignInBits);
SizeInBits = IGM.DataLayout.getTypeSizeInBits(Piece->getType());
AlignInBits = IGM.DataLayout.getABITypeAlignment(Piece->getType());
if (!AlignInBits)
AlignInBits = SizeOfByte;

// Sanity checks.
assert(SizeInBits && "zero-sized piece");
assert(SizeInBits < VarSizeInBits && "piece covers entire var");
assert(OffsetInBits+SizeInBits <= VarSizeInBits && "pars > totum");

// Add the piece DWARF expression.
Operands.push_back(llvm::dwarf::DW_OP_bit_piece);
Operands.push_back(OffsetInBits);
Operands.push_back(Dim.SizeInBits);

auto Size = Dim.SizeInBits;
Dim = EltSizes.getNext();
OffsetInBits +=
llvm::alignTo(Size, Dim.AlignInBits ? Dim.AlignInBits
: SizeOfByte);
Operands.push_back(SizeInBits);
}
emitDbgIntrinsic(BB, Piece, Var, DBuilder.createExpression(Operands), Line,
Loc.Column, Scope, DS);
Expand Down Expand Up @@ -1343,14 +1265,46 @@ llvm::DIType *IRGenDebugInfo::createPointerSizedStruct(
unsigned PtrAlign = CI.getTargetInfo().getPointerAlign(0);
auto PtrTy = DBuilder.createPointerType(PointeeTy, PtrSize, PtrAlign);
llvm::Metadata *Elements[] = {
DBuilder.createMemberType(Scope, "pointer", File, 0,
DBuilder.createMemberType(Scope, "ptr", File, 0,
PtrSize, PtrAlign, 0, Flags, PtrTy)
};
return DBuilder.createStructType(
Scope, Name, File, Line, PtrSize, PtrAlign, Flags,
nullptr, // DerivedFrom
DBuilder.getOrCreateArray(Elements), llvm::dwarf::DW_LANG_Swift,
nullptr, MangledName);
/* DerivedFrom */ nullptr, DBuilder.getOrCreateArray(Elements),
llvm::dwarf::DW_LANG_Swift, nullptr, MangledName);
}

/// Create a 2*pointer-sized struct with a mangled name and a single
/// member of PointeeTy.
llvm::DIType *IRGenDebugInfo::createDoublePointerSizedStruct(
llvm::DIScope *Scope, StringRef Name, llvm::DIType *PointeeTy,
llvm::DIFile *File, unsigned Line, unsigned Flags, StringRef MangledName) {
unsigned PtrSize = CI.getTargetInfo().getPointerWidth(0);
unsigned PtrAlign = CI.getTargetInfo().getPointerAlign(0);
llvm::Metadata *Elements[] = {
DBuilder.createMemberType(
Scope, "ptr", File, 0, PtrSize, PtrAlign, 0, Flags,
DBuilder.createPointerType(PointeeTy, PtrSize, PtrAlign)),
DBuilder.createMemberType(
Scope, "_", File, 0, PtrSize, PtrAlign, 0, Flags,
DBuilder.createPointerType(nullptr, PtrSize, PtrAlign))};
return DBuilder.createStructType(
Scope, Name, File, Line, 2*PtrSize, PtrAlign, Flags,
/* DerivedFrom */ nullptr, DBuilder.getOrCreateArray(Elements),
llvm::dwarf::DW_LANG_Swift, nullptr, MangledName);
}

/// Create an opaque struct with a mangled name.
llvm::DIType *
IRGenDebugInfo::createOpaqueStruct(llvm::DIScope *Scope, StringRef Name,
llvm::DIFile *File, unsigned Line,
unsigned SizeInBits, unsigned AlignInBits,
unsigned Flags, StringRef MangledName) {
return DBuilder.createStructType(
Scope, Name, File, Line, SizeInBits, AlignInBits, Flags,
/* DerivedFrom */ nullptr,
DBuilder.getOrCreateArray(ArrayRef<llvm::Metadata *>()),
llvm::dwarf::DW_LANG_Swift, nullptr, MangledName);
}

/// Construct a DIType from a DebugTypeInfo object.
Expand Down Expand Up @@ -1506,6 +1460,7 @@ llvm::DIType *IRGenDebugInfo::createType(DebugTypeInfo DbgTy,
}
Scope = getOrCreateModule(ModuleName, TheCU, ModuleName, ModulePath);
}
assert(SizeInBits == CI.getTargetInfo().getPointerWidth(0));
return createPointerSizedStruct(Scope, Decl->getNameStr(),
getOrCreateFile(L.Filename), L.Line, Flags,
MangledName);
Expand All @@ -1517,9 +1472,9 @@ llvm::DIType *IRGenDebugInfo::createType(DebugTypeInfo DbgTy,
// FIXME: (LLVM branch) This should probably be a DW_TAG_interface_type.
auto L = getDebugLoc(SM, Decl);
auto File = getOrCreateFile(L.Filename);
return createPointerSizedStruct(Scope,
Decl ? Decl->getNameStr() : MangledName,
File, L.Line, Flags, MangledName);
return createOpaqueStruct(Scope, Decl ? Decl->getNameStr() : MangledName,
File, L.Line, SizeInBits, AlignInBits, Flags,
MangledName);
}

case TypeKind::ProtocolComposition: {
Expand All @@ -1529,15 +1484,16 @@ llvm::DIType *IRGenDebugInfo::createType(DebugTypeInfo DbgTy,

// FIXME: emit types
// auto ProtocolCompositionTy = BaseTy->castTo<ProtocolCompositionType>();
return createPointerSizedStruct(Scope,
Decl ? Decl->getNameStr() : MangledName,
File, L.Line, Flags, MangledName);
return createOpaqueStruct(Scope, Decl ? Decl->getNameStr() : MangledName,
File, L.Line, SizeInBits, AlignInBits, Flags,
MangledName);
}

case TypeKind::UnboundGeneric: {
auto *UnboundTy = BaseTy->castTo<UnboundGenericType>();
auto *Decl = UnboundTy->getDecl();
auto L = getDebugLoc(SM, Decl);
assert(SizeInBits == CI.getTargetInfo().getPointerWidth(0));
return createPointerSizedStruct(Scope,
Decl ? Decl->getNameStr() : MangledName,
File, L.Line, Flags, MangledName);
Expand All @@ -1547,9 +1503,9 @@ llvm::DIType *IRGenDebugInfo::createType(DebugTypeInfo DbgTy,
auto *StructTy = BaseTy->castTo<BoundGenericStructType>();
auto *Decl = StructTy->getDecl();
auto L = getDebugLoc(SM, Decl);
return createPointerSizedStruct(Scope,
Decl ? Decl->getNameStr() : MangledName,
File, L.Line, Flags, MangledName);
return createOpaqueStruct(Scope, Decl ? Decl->getNameStr() : MangledName,
File, L.Line, SizeInBits, AlignInBits, Flags,
MangledName);
}

case TypeKind::BoundGenericClass: {
Expand All @@ -1558,6 +1514,7 @@ llvm::DIType *IRGenDebugInfo::createType(DebugTypeInfo DbgTy,
auto L = getDebugLoc(SM, Decl);
// TODO: We may want to peek at Decl->isObjC() and set this
// attribute accordingly.
assert(SizeInBits == CI.getTargetInfo().getPointerWidth(0));
return createPointerSizedStruct(Scope,
Decl ? Decl->getNameStr() : MangledName,
File, L.Line, Flags, MangledName);
Expand Down Expand Up @@ -1649,39 +1606,49 @@ llvm::DIType *IRGenDebugInfo::createType(DebugTypeInfo DbgTy,
case TypeKind::Function:
case TypeKind::PolymorphicFunction:
case TypeKind::GenericFunction: {
auto FwdDecl = llvm::TempDINode(
DBuilder.createReplaceableCompositeType(
auto FwdDecl = llvm::TempDINode(DBuilder.createReplaceableCompositeType(
llvm::dwarf::DW_TAG_subroutine_type, MangledName, Scope, File, 0,
llvm::dwarf::DW_LANG_Swift, SizeInBits, AlignInBits, Flags,
MangledName));
llvm::dwarf::DW_LANG_Swift, SizeInBits, AlignInBits, Flags,
MangledName));

auto TH = llvm::TrackingMDNodeRef(FwdDecl.get());
DITypeCache[DbgTy.getType()] = TH;

CanSILFunctionType FunctionTy;
CanSILFunctionType FunTy;
if (auto *SILFnTy = dyn_cast<SILFunctionType>(BaseTy))
FunctionTy = CanSILFunctionType(SILFnTy);
FunTy = CanSILFunctionType(SILFnTy);
// FIXME: Handling of generic parameters in SIL type lowering is in flux.
// DebugInfo doesn't appear to care about the generic context, so just
// throw it away before lowering.
else if (isa<GenericFunctionType>(BaseTy) ||
isa<PolymorphicFunctionType>(BaseTy)) {
auto *fTy = cast<AnyFunctionType>(BaseTy);
auto *nongenericTy = FunctionType::get(fTy->getInput(), fTy->getResult(),
fTy->getExtInfo());
fTy->getExtInfo());

FunctionTy = IGM.SILMod->Types.getLoweredType(nongenericTy)
.castTo<SILFunctionType>();
FunTy = IGM.SILMod->Types.getLoweredType(nongenericTy)
.castTo<SILFunctionType>();
} else
FunctionTy =
FunTy =
IGM.SILMod->Types.getLoweredType(BaseTy).castTo<SILFunctionType>();
auto Params = createParameterTypes(FunctionTy, DbgTy.getDeclContext());
auto Params = createParameterTypes(FunTy, DbgTy.getDeclContext());

// Functions are actually stored as a Pointer or a FunctionPairTy:
// { i8*, %swift.refcounted* }
auto FnTy = DBuilder.createSubroutineType(Params, Flags);
auto DITy = createPointerSizedStruct(Scope, MangledName, FnTy,
MainFile, 0, Flags, MangledName);
llvm::DIType *DITy;
if (FunTy->getRepresentation() == SILFunctionType::Representation::Thick) {
if (SizeInBits == 2 * CI.getTargetInfo().getPointerWidth(0))
// This is a FunctionPairTy: { i8*, %swift.refcounted* }.
DITy = createDoublePointerSizedStruct(Scope, MangledName, FnTy,
MainFile, 0, Flags, MangledName);
else
// This is a generic function as noted above.
DITy = createOpaqueStruct(Scope, MangledName, MainFile, 0, SizeInBits,
AlignInBits, Flags, MangledName);
} else {
assert(SizeInBits == CI.getTargetInfo().getPointerWidth(0));
DITy = createPointerSizedStruct(Scope, MangledName, FnTy, MainFile, 0,
Flags, MangledName);
}
DBuilder.replaceTemporary(std::move(FwdDecl), DITy);
return DITy;
}
Expand Down
7 changes: 7 additions & 0 deletions lib/IRGen/IRGenDebugInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,13 @@ class IRGenDebugInfo {
llvm::DIType *PointeeTy,
llvm::DIFile *File, unsigned Line,
unsigned Flags, StringRef MangledName);
llvm::DIType *createDoublePointerSizedStruct(
llvm::DIScope *Scope, StringRef Name, llvm::DIType *PointeeTy,
llvm::DIFile *File, unsigned Line, unsigned Flags, StringRef MangledName);
llvm::DIType *createOpaqueStruct(llvm::DIScope *Scope, StringRef Name,
llvm::DIFile *File, unsigned Line,
unsigned SizeInBits, unsigned AlignInBits,
unsigned Flags, StringRef MangledName);
uint64_t getSizeOfBasicType(DebugTypeInfo DbgTy);
TypeAliasDecl *getMetadataType();
};
Expand Down
6 changes: 3 additions & 3 deletions test/DebugInfo/fnptr.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ func main() -> Int64 {
// CHECK-DAG: !DILocalVariable(name: "bar_function_pointer",{{.*}} line: [[@LINE+1]],{{.*}} type: !"[[BARPT:[^,]+]]"
var bar_function_pointer = bar
// CHECK-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "[[BARPT]]",{{.*}} elements: ![[BARMEMBERS:[0-9]+]]
// CHECK-DAG: ![[BARMEMBERS]] = !{![[BARMEMBER:.*]]}
// CHECK-DAG: ![[BARMEMBERS]] = !{![[BARMEMBER:.*]], {{.*}}}
// CHECK-DAG: ![[BARMEMBER]] = !DIDerivedType(tag: DW_TAG_member,{{.*}} baseType: ![[BARPTR:[0-9]+]]
// CHECK-DAG: ![[BARPTR]] = !DIDerivedType(tag: DW_TAG_pointer_type,{{.*}} baseType: ![[BART:[0-9]+]]
// CHECK-DAG: ![[BART]] = !DISubroutineType(types: ![[BARARGS:[0-9]+]])
Expand All @@ -22,7 +22,7 @@ func main() -> Int64 {

// CHECK-DAG: !DILocalVariable(name: "baz_function_pointer",{{.*}} type: !"[[BAZPT:[^,]+]]"
// CHECK-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "[[BAZPT]]",{{.*}} elements: ![[BAZMEMBERS:[0-9]+]]
// CHECK-DAG: ![[BAZMEMBERS]] = !{![[BAZMEMBER:.*]]}
// CHECK-DAG: ![[BAZMEMBERS]] = !{![[BAZMEMBER:.*]], {{.*}}}
// CHECK-DAG: ![[BAZMEMBER]] = !DIDerivedType(tag: DW_TAG_member,{{.*}} baseType: ![[BAZPTR:[0-9]+]]
// CHECK-DAG: ![[BAZPTR]] = !DIDerivedType(tag: DW_TAG_pointer_type,{{.*}} baseType: ![[BAZT:[0-9]+]]
// CHECK-DAG: ![[BAZT]] = !DISubroutineType(types: ![[BAZARGS:.*]])
Expand All @@ -32,7 +32,7 @@ func main() -> Int64 {

// CHECK-DAG: !DILocalVariable(name: "barz_function_pointer",{{.*}} type: !"[[BARZPT:[^,]+]]"
// CHECK-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "[[BARZPT]]",{{.*}} elements: ![[BARZMEMBERS:[0-9]+]]
// CHECK-DAG: ![[BARZMEMBERS]] = !{![[BARZMEMBER:.*]]}
// CHECK-DAG: ![[BARZMEMBERS]] = !{![[BARZMEMBER:.*]], {{.*}}}
// CHECK-DAG: ![[BARZMEMBER]] = !DIDerivedType(tag: DW_TAG_member,{{.*}} baseType: ![[BARZPTR:[0-9]+]]
// CHECK-DAG: ![[BARZPTR]] = !DIDerivedType(tag: DW_TAG_pointer_type,{{.*}} baseType: ![[BARZT:[0-9]+]]
// CHECK-DAG: ![[BARZT]] = !DISubroutineType(types: ![[BARZARGS:.*]])
Expand Down