Debug Info: Retreive the layout information of exploded values from the

explosion schema rather than from the debug type information and retire
a bunch of heuristics that are no longer necessary.

To enable this, this commit also includes a bugfix to debug info for
opaque data structures with the correct size and alignment information.

<rdar://problem/21470869+22707597>
This commit is contained in:
Adrian Prantl
2016-03-09 13:29:27 -08:00
parent ad4f065ad6
commit 7e489db91b
3 changed files with 102 additions and 125 deletions

View File

@@ -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;
@@ -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)
@@ -1030,32 +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);
assert((Dim.SizeInBits != 0 || StorageSize != 0) &&
"zero-sized variable with nonzero storage size");
// 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;
// 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;
// Sanity checks.
assert(SizeInBits && "zero-sized piece");
assert(SizeInBits < VarSizeInBits && "piece covers entire var");
assert(OffsetInBits+SizeInBits <= VarSizeInBits && "pars > totum");
assert(Dim.SizeInBits < VarSizeInBits
&& "piece covers entire var");
assert(OffsetInBits+Dim.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);
@@ -1334,14 +1259,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.
@@ -1497,6 +1454,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);
@@ -1508,9 +1466,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: {
@@ -1520,15 +1478,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);
@@ -1538,9 +1497,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: {
@@ -1549,6 +1508,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);
@@ -1640,18 +1600,17 @@ 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.
@@ -1659,20 +1618,31 @@ llvm::DIType *IRGenDebugInfo::createType(DebugTypeInfo DbgTy,
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;
}

View File

@@ -264,6 +264,13 @@ private:
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();
};

View File

@@ -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]+]])
@@ -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:.*]])
@@ -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:.*]])