mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-10-20 19:42:54 +02:00
[codeview] support more DW_OPs for more complete debug info
Summary: Some variables show up in Visual Studio as "optimized out" even in -O0 -Od builds. This change fixes two issues that would cause this to happen. The first issue is that not all DIExpressions we generate were recognized by the CodeView writer. This has been addressed by adding support for DW_OP_constu, DW_OP_minus, and DW_OP_plus. The second issue is that we had no way to encode DW_OP_deref in CodeView. We get around that by changinge the type we encode in the debug info to be a reference to the type in the source code. This fixes PR34261. Reviewers: aprantl, rnk, zturner Reviewed By: rnk Subscribers: mgorny, llvm-commits, aprantl, hiraditya Differential Revision: https://reviews.llvm.org/D36907 llvm-svn: 311957
This commit is contained in:
parent
b2df2ba5d2
commit
8243c03db7
@ -949,13 +949,103 @@ void CodeViewDebug::collectVariableInfoFromMFTable(
|
||||
}
|
||||
}
|
||||
|
||||
void CodeViewDebug::calculateRanges(
|
||||
LocalVariable &Var, const DbgValueHistoryMap::InstrRanges &Ranges) {
|
||||
const TargetRegisterInfo *TRI = Asm->MF->getSubtarget().getRegisterInfo();
|
||||
|
||||
// calculate the definition ranges.
|
||||
for (auto I = Ranges.begin(), E = Ranges.end(); I != E; ++I) {
|
||||
const InsnRange &Range = *I;
|
||||
const MachineInstr *DVInst = Range.first;
|
||||
assert(DVInst->isDebugValue() && "Invalid History entry");
|
||||
// FIXME: Find a way to represent constant variables, since they are
|
||||
// relatively common.
|
||||
DbgVariableLocation Location;
|
||||
bool Supported =
|
||||
DbgVariableLocation::extractFromMachineInstruction(Location, *DVInst);
|
||||
|
||||
// Because we cannot express DW_OP_deref in CodeView directly,
|
||||
// we use a trick: we encode the type as a reference to the
|
||||
// real type.
|
||||
if (Var.Deref) {
|
||||
// When we're encoding the type as a reference to the original type,
|
||||
// we need to remove a level of indirection from incoming locations.
|
||||
// E.g. [RSP+8] with DW_OP_deref becomes [RSP+8],
|
||||
// and [RCX+0] without DW_OP_deref becomes RCX.
|
||||
if (!Location.Deref) {
|
||||
if (Location.InMemory)
|
||||
Location.InMemory = false;
|
||||
else
|
||||
Supported = false;
|
||||
}
|
||||
} else if (Location.Deref) {
|
||||
// We've encountered a Deref range when we had not applied the
|
||||
// reference encoding. Start over using reference encoding.
|
||||
Var.Deref = true;
|
||||
Var.DefRanges.clear();
|
||||
calculateRanges(Var, Ranges);
|
||||
return;
|
||||
}
|
||||
|
||||
// If we don't know how to handle this range, skip past it.
|
||||
if (!Supported || (Location.Offset && !Location.InMemory))
|
||||
continue;
|
||||
|
||||
// Handle the two cases we can handle: indirect in memory and in register.
|
||||
{
|
||||
LocalVarDefRange DR;
|
||||
DR.CVRegister = TRI->getCodeViewRegNum(Location.Register);
|
||||
DR.InMemory = Location.InMemory;
|
||||
DR.DataOffset = Location.Offset;
|
||||
if (Location.FragmentInfo) {
|
||||
DR.IsSubfield = true;
|
||||
DR.StructOffset = Location.FragmentInfo->OffsetInBits / 8;
|
||||
} else {
|
||||
DR.IsSubfield = false;
|
||||
DR.StructOffset = 0;
|
||||
}
|
||||
|
||||
if (Var.DefRanges.empty() ||
|
||||
Var.DefRanges.back().isDifferentLocation(DR)) {
|
||||
Var.DefRanges.emplace_back(std::move(DR));
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the label range.
|
||||
const MCSymbol *Begin = getLabelBeforeInsn(Range.first);
|
||||
const MCSymbol *End = getLabelAfterInsn(Range.second);
|
||||
if (!End) {
|
||||
// This range is valid until the next overlapping bitpiece. In the
|
||||
// common case, ranges will not be bitpieces, so they will overlap.
|
||||
auto J = std::next(I);
|
||||
const DIExpression *DIExpr = DVInst->getDebugExpression();
|
||||
while (J != E &&
|
||||
!fragmentsOverlap(DIExpr, J->first->getDebugExpression()))
|
||||
++J;
|
||||
if (J != E)
|
||||
End = getLabelBeforeInsn(J->first);
|
||||
else
|
||||
End = Asm->getFunctionEnd();
|
||||
}
|
||||
|
||||
// If the last range end is our begin, just extend the last range.
|
||||
// Otherwise make a new range.
|
||||
SmallVectorImpl<std::pair<const MCSymbol *, const MCSymbol *>> &R =
|
||||
Var.DefRanges.back().Ranges;
|
||||
if (!R.empty() && R.back().second == Begin)
|
||||
R.back().second = End;
|
||||
else
|
||||
R.emplace_back(Begin, End);
|
||||
|
||||
// FIXME: Do more range combining.
|
||||
}
|
||||
}
|
||||
|
||||
void CodeViewDebug::collectVariableInfo(const DISubprogram *SP) {
|
||||
DenseSet<InlinedVariable> Processed;
|
||||
// Grab the variable info that was squirreled away in the MMI side-table.
|
||||
collectVariableInfoFromMFTable(Processed);
|
||||
|
||||
const TargetRegisterInfo *TRI = Asm->MF->getSubtarget().getRegisterInfo();
|
||||
|
||||
for (const auto &I : DbgValues) {
|
||||
InlinedVariable IV = I.first;
|
||||
if (Processed.count(IV))
|
||||
@ -978,89 +1068,7 @@ void CodeViewDebug::collectVariableInfo(const DISubprogram *SP) {
|
||||
LocalVariable Var;
|
||||
Var.DIVar = DIVar;
|
||||
|
||||
// Calculate the definition ranges.
|
||||
for (auto I = Ranges.begin(), E = Ranges.end(); I != E; ++I) {
|
||||
const InsnRange &Range = *I;
|
||||
const MachineInstr *DVInst = Range.first;
|
||||
assert(DVInst->isDebugValue() && "Invalid History entry");
|
||||
const DIExpression *DIExpr = DVInst->getDebugExpression();
|
||||
bool InMemory = DVInst->getOperand(1).isImm();
|
||||
bool IsSubfield = false;
|
||||
unsigned StructOffset = 0;
|
||||
// Recognize a +Offset expression.
|
||||
int Offset = 0;
|
||||
DIExpressionCursor Ops(DIExpr);
|
||||
auto Op = Ops.peek();
|
||||
if (Op && Op->getOp() == dwarf::DW_OP_plus_uconst) {
|
||||
Offset = Op->getArg(0);
|
||||
Ops.take();
|
||||
}
|
||||
|
||||
// Handle fragments.
|
||||
auto Fragment = Ops.getFragmentInfo();
|
||||
if (Fragment) {
|
||||
IsSubfield = true;
|
||||
StructOffset = Fragment->OffsetInBits / 8;
|
||||
}
|
||||
// Ignore unrecognized exprs.
|
||||
if (Ops.peek() && Ops.peek()->getOp() != dwarf::DW_OP_LLVM_fragment)
|
||||
continue;
|
||||
if (!InMemory && Offset)
|
||||
continue;
|
||||
|
||||
// Bail if operand 0 is not a valid register. This means the variable is a
|
||||
// simple constant, or is described by a complex expression.
|
||||
// FIXME: Find a way to represent constant variables, since they are
|
||||
// relatively common.
|
||||
unsigned Reg =
|
||||
DVInst->getOperand(0).isReg() ? DVInst->getOperand(0).getReg() : 0;
|
||||
if (Reg == 0)
|
||||
continue;
|
||||
|
||||
// Handle the two cases we can handle: indirect in memory and in register.
|
||||
unsigned CVReg = TRI->getCodeViewRegNum(Reg);
|
||||
{
|
||||
LocalVarDefRange DR;
|
||||
DR.CVRegister = CVReg;
|
||||
DR.InMemory = InMemory;
|
||||
DR.DataOffset = Offset;
|
||||
DR.IsSubfield = IsSubfield;
|
||||
DR.StructOffset = StructOffset;
|
||||
|
||||
if (Var.DefRanges.empty() ||
|
||||
Var.DefRanges.back().isDifferentLocation(DR)) {
|
||||
Var.DefRanges.emplace_back(std::move(DR));
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the label range.
|
||||
const MCSymbol *Begin = getLabelBeforeInsn(Range.first);
|
||||
const MCSymbol *End = getLabelAfterInsn(Range.second);
|
||||
if (!End) {
|
||||
// This range is valid until the next overlapping bitpiece. In the
|
||||
// common case, ranges will not be bitpieces, so they will overlap.
|
||||
auto J = std::next(I);
|
||||
while (J != E &&
|
||||
!fragmentsOverlap(DIExpr, J->first->getDebugExpression()))
|
||||
++J;
|
||||
if (J != E)
|
||||
End = getLabelBeforeInsn(J->first);
|
||||
else
|
||||
End = Asm->getFunctionEnd();
|
||||
}
|
||||
|
||||
// If the last range end is our begin, just extend the last range.
|
||||
// Otherwise make a new range.
|
||||
SmallVectorImpl<std::pair<const MCSymbol *, const MCSymbol *>> &Ranges =
|
||||
Var.DefRanges.back().Ranges;
|
||||
if (!Ranges.empty() && Ranges.back().second == Begin)
|
||||
Ranges.back().second = End;
|
||||
else
|
||||
Ranges.emplace_back(Begin, End);
|
||||
|
||||
// FIXME: Do more range combining.
|
||||
}
|
||||
|
||||
calculateRanges(Var, Ranges);
|
||||
recordLocalVariable(std::move(Var), InlinedAt);
|
||||
}
|
||||
}
|
||||
@ -1987,6 +1995,16 @@ TypeIndex CodeViewDebug::getTypeIndex(DITypeRef TypeRef, DITypeRef ClassTyRef) {
|
||||
return recordTypeIndexForDINode(Ty, TI, ClassTy);
|
||||
}
|
||||
|
||||
TypeIndex CodeViewDebug::getTypeIndexForReferenceTo(DITypeRef TypeRef) {
|
||||
DIType *Ty = TypeRef.resolve();
|
||||
PointerRecord PR(getTypeIndex(Ty),
|
||||
getPointerSizeInBytes() == 8 ? PointerKind::Near64
|
||||
: PointerKind::Near32,
|
||||
PointerMode::LValueReference, PointerOptions::None,
|
||||
Ty->getSizeInBits() / 8);
|
||||
return TypeTable.writeKnownType(PR);
|
||||
}
|
||||
|
||||
TypeIndex CodeViewDebug::getCompleteTypeIndex(DITypeRef TypeRef) {
|
||||
const DIType *Ty = TypeRef.resolve();
|
||||
|
||||
@ -2094,7 +2112,8 @@ void CodeViewDebug::emitLocalVariable(const LocalVariable &Var) {
|
||||
Flags |= LocalSymFlags::IsOptimizedOut;
|
||||
|
||||
OS.AddComment("TypeIndex");
|
||||
TypeIndex TI = getCompleteTypeIndex(Var.DIVar->getType());
|
||||
TypeIndex TI = Var.Deref ? getTypeIndexForReferenceTo(Var.DIVar->getType())
|
||||
: getCompleteTypeIndex(Var.DIVar->getType());
|
||||
OS.EmitIntValue(TI.getIndex(), 4);
|
||||
OS.AddComment("Flags");
|
||||
OS.EmitIntValue(static_cast<uint16_t>(Flags), 2);
|
||||
|
@ -94,6 +94,7 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase {
|
||||
struct LocalVariable {
|
||||
const DILocalVariable *DIVar = nullptr;
|
||||
SmallVector<LocalVarDefRange, 1> DefRanges;
|
||||
bool Deref = false;
|
||||
};
|
||||
|
||||
struct InlineSite {
|
||||
@ -147,6 +148,9 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase {
|
||||
|
||||
codeview::TypeIndex getFuncIdForSubprogram(const DISubprogram *SP);
|
||||
|
||||
void calculateRanges(LocalVariable &Var,
|
||||
const DbgValueHistoryMap::InstrRanges &Ranges);
|
||||
|
||||
static void collectInlineSiteChildren(SmallVectorImpl<unsigned> &Children,
|
||||
const FunctionInfo &FI,
|
||||
const InlineSite &Site);
|
||||
@ -259,6 +263,8 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase {
|
||||
codeview::TypeIndex getTypeIndex(DITypeRef TypeRef,
|
||||
DITypeRef ClassTyRef = DITypeRef());
|
||||
|
||||
codeview::TypeIndex getTypeIndexForReferenceTo(DITypeRef TypeRef);
|
||||
|
||||
codeview::TypeIndex getMemberFunctionType(const DISubprogram *SP,
|
||||
const DICompositeType *Class);
|
||||
|
||||
|
@ -23,6 +23,57 @@
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
bool DbgVariableLocation::extractFromMachineInstruction(
|
||||
DbgVariableLocation &Location, const MachineInstr &Instruction) {
|
||||
if (!Instruction.isDebugValue())
|
||||
return false;
|
||||
if (!Instruction.getOperand(0).isReg())
|
||||
return false;
|
||||
Location.Register = Instruction.getOperand(0).getReg();
|
||||
Location.InMemory = Instruction.getOperand(1).isImm();
|
||||
Location.Deref = false;
|
||||
Location.FragmentInfo.reset();
|
||||
// We only handle expressions generated by DIExpression::appendOffset,
|
||||
// which doesn't require a full stack machine.
|
||||
int64_t Offset = 0;
|
||||
const DIExpression *DIExpr = Instruction.getDebugExpression();
|
||||
auto Op = DIExpr->expr_op_begin();
|
||||
while (Op != DIExpr->expr_op_end()) {
|
||||
switch (Op->getOp()) {
|
||||
case dwarf::DW_OP_constu: {
|
||||
int Value = Op->getArg(0);
|
||||
++Op;
|
||||
if (Op != DIExpr->expr_op_end()) {
|
||||
switch (Op->getOp()) {
|
||||
case dwarf::DW_OP_minus:
|
||||
Offset -= Value;
|
||||
break;
|
||||
case dwarf::DW_OP_plus:
|
||||
Offset += Value;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case dwarf::DW_OP_plus_uconst:
|
||||
Offset += Op->getArg(0);
|
||||
break;
|
||||
case dwarf::DW_OP_LLVM_fragment:
|
||||
Location.FragmentInfo = {Op->getArg(1), Op->getArg(0)};
|
||||
break;
|
||||
case dwarf::DW_OP_deref:
|
||||
Location.Deref = true;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
++Op;
|
||||
}
|
||||
|
||||
Location.Offset = Offset;
|
||||
return true;
|
||||
}
|
||||
|
||||
DebugHandlerBase::DebugHandlerBase(AsmPrinter *A) : Asm(A), MMI(Asm->MMI) {}
|
||||
|
||||
// Each LexicalScope has first instruction and last instruction to mark
|
||||
|
@ -17,14 +17,44 @@
|
||||
|
||||
#include "AsmPrinterHandler.h"
|
||||
#include "DbgValueHistoryCalculator.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/CodeGen/LexicalScopes.h"
|
||||
#include "llvm/CodeGen/MachineInstr.h"
|
||||
#include "llvm/IR/DebugInfoMetadata.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class AsmPrinter;
|
||||
class MachineInstr;
|
||||
class MachineModuleInfo;
|
||||
|
||||
/// Represents the location at which a variable is stored.
|
||||
struct DbgVariableLocation {
|
||||
/// Offset relative to base register.
|
||||
int64_t Offset;
|
||||
|
||||
/// Base register.
|
||||
unsigned Register;
|
||||
|
||||
/// If false, Register is the location. If true,
|
||||
/// Register+Offset point at the location.
|
||||
unsigned InMemory : 1;
|
||||
|
||||
/// If false, the location holds the variable's value.
|
||||
/// If true, the location holds the variable's address.
|
||||
unsigned Deref : 1;
|
||||
|
||||
/// Present if the location is part of a larger variable.
|
||||
llvm::Optional<llvm::DIExpression::FragmentInfo> FragmentInfo;
|
||||
|
||||
/// Extract a VariableLocation from a MachineInstr. The struct passed in as
|
||||
/// Location is populated. The MachineInstr must be a debug value
|
||||
/// instruction.
|
||||
/// @return true if successful and false if not.
|
||||
static bool extractFromMachineInstruction(DbgVariableLocation &Location,
|
||||
const MachineInstr &Instruction);
|
||||
};
|
||||
|
||||
/// Base class for debug information backends. Common functionality related to
|
||||
/// tracking which variables and scopes are alive at a given PC live here.
|
||||
class DebugHandlerBase : public AsmPrinterHandler {
|
||||
|
253
test/CodeGen/MIR/X86/diexpr-win32.mir
Normal file
253
test/CodeGen/MIR/X86/diexpr-win32.mir
Normal file
@ -0,0 +1,253 @@
|
||||
# RUN: llc -filetype=obj -O0 %s -o - | llvm-readobj -codeview | FileCheck %s
|
||||
#
|
||||
# (DW_OP_plus_uconst 12)
|
||||
# CHECK: LocalSym {
|
||||
# CHECK-NEXT: Kind: S_LOCAL (0x113E)
|
||||
# CHECK-NEXT: Type: string* (0x
|
||||
# CHECK-NEXT: Flags [ (0x0)
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: VarName: Str
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: DefRangeRegisterRelSym {
|
||||
# CHECK-NEXT: Kind: S_DEFRANGE_REGISTER_REL (0x1145)
|
||||
# CHECK-NEXT: BaseRegister:
|
||||
# CHECK-NEXT: HasSpilledUDTMember: No
|
||||
# CHECK-NEXT: OffsetInParent: 0
|
||||
# CHECK-NEXT: BasePointerOffset: 12
|
||||
# CHECK-NEXT: LocalVariableAddrRange {
|
||||
# CHECK-NEXT: OffsetStart:
|
||||
# CHECK-NEXT: ISectStart:
|
||||
# CHECK-NEXT: Range:
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: }
|
||||
# (DW_OP_plus_uconst, 8, DW_OP_deref)
|
||||
# CHECK: LocalSym {
|
||||
# CHECK-NEXT: Kind: S_LOCAL (0x113E)
|
||||
# CHECK-NEXT: Type: string& (0x
|
||||
# CHECK-NEXT: Flags [ (0x0)
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: VarName: Result
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: DefRangeRegisterRelSym {
|
||||
# CHECK-NEXT: Kind: S_DEFRANGE_REGISTER_REL (0x1145)
|
||||
# CHECK-NEXT: BaseRegister:
|
||||
# CHECK-NEXT: HasSpilledUDTMember: No
|
||||
# CHECK-NEXT: OffsetInParent: 0
|
||||
# CHECK-NEXT: BasePointerOffset: 8
|
||||
# CHECK-NEXT: LocalVariableAddrRange {
|
||||
# CHECK-NEXT: OffsetStart:
|
||||
# CHECK-NEXT: ISectStart:
|
||||
# CHECK-NEXT: Range:
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: }
|
||||
# (DW_OP_constu, 4, DW_OP_minus)
|
||||
# CHECK: LocalSym {
|
||||
# CHECK-NEXT: Kind: S_LOCAL (0x113E)
|
||||
# CHECK-NEXT: Type: long (0x12)
|
||||
# CHECK-NEXT: Flags [ (0x0)
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: VarName: Bytes
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: DefRangeRegisterRelSym {
|
||||
# CHECK-NEXT: Kind: S_DEFRANGE_REGISTER_REL (0x1145)
|
||||
# CHECK-NEXT: BaseRegister:
|
||||
# CHECK-NEXT: HasSpilledUDTMember: No
|
||||
# CHECK-NEXT: OffsetInParent: 0
|
||||
# CHECK-NEXT: BasePointerOffset: -4
|
||||
# CHECK-NEXT: LocalVariableAddrRange {
|
||||
# CHECK-NEXT: OffsetStart:
|
||||
# CHECK-NEXT: ISectStart:
|
||||
# CHECK-NEXT: Range:
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: }
|
||||
--- |
|
||||
; ModuleID = '<stdin>'
|
||||
source_filename = "<stdin>"
|
||||
target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
|
||||
target triple = "i386-pc-windows-msvc19.0.24215"
|
||||
|
||||
%struct.string = type { i32, i32, i8* }
|
||||
|
||||
define void @fun(%struct.string* noalias sret %agg.result, %struct.string* noalias %str) !dbg !12 {
|
||||
entry:
|
||||
call void @llvm.dbg.value(metadata %struct.string* %agg.result, metadata !23, metadata !24), !dbg !25
|
||||
call void @llvm.dbg.value(metadata %struct.string* %str, metadata !26, metadata !28), !dbg !25
|
||||
%call = call dereferenceable(12) %struct.string* @getString(), !dbg !29
|
||||
%0 = bitcast %struct.string* %agg.result to i8*, !dbg !29
|
||||
%1 = bitcast %struct.string* %call to i8*, !dbg !29
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* %0, i8* %1, i32 12, i32 4, i1 false), !dbg !29
|
||||
ret void, !dbg !30
|
||||
}
|
||||
|
||||
define i32 @len(%struct.string* %s, i32 %acc) !dbg !31 {
|
||||
entry:
|
||||
%0 = bitcast %struct.string* %s to i32*
|
||||
%bytes = load i32, i32* %0, !dbg !34
|
||||
call void @llvm.dbg.declare(metadata i32 %bytes, metadata !35, metadata !28), !dbg !34
|
||||
%1 = add i32 %bytes, %acc, !dbg !36
|
||||
ret i32 %1, !dbg !36
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind readnone speculatable
|
||||
declare void @llvm.dbg.declare(metadata, metadata, metadata) #0
|
||||
|
||||
; Function Attrs: nounwind readnone speculatable
|
||||
declare void @llvm.dbg.value(metadata, metadata, metadata) #0
|
||||
|
||||
declare dereferenceable(12) %struct.string* @getString()
|
||||
|
||||
; Function Attrs: argmemonly nounwind
|
||||
declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture writeonly, i8* nocapture readonly, i32, i32, i1) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare void @llvm.stackprotector(i8*, i8**) #2
|
||||
|
||||
attributes #0 = { nounwind readnone speculatable }
|
||||
attributes #1 = { argmemonly nounwind }
|
||||
attributes #2 = { nounwind }
|
||||
|
||||
!llvm.dbg.cu = !{!0}
|
||||
!llvm.linker.options = !{!3, !4}
|
||||
!llvm.module.flags = !{!5, !6, !7, !8}
|
||||
!llvm.ident = !{!9}
|
||||
|
||||
!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 6.0.0 ", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
|
||||
!1 = !DIFile(filename: "diexpr.ll", directory: "C:\5Csrc", checksumkind: CSK_MD5, checksum: "c547c362c610fa79e7abaddc76e1efe7")
|
||||
!2 = !{}
|
||||
!3 = !{!"/DEFAULTLIB:libcmt.lib"}
|
||||
!4 = !{!"/DEFAULTLIB:oldnames.lib"}
|
||||
!5 = !{i32 1, !"NumRegisterParameters", i32 0}
|
||||
!6 = !{i32 2, !"CodeView", i32 1}
|
||||
!7 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
!8 = !{i32 1, !"wchar_size", i32 2}
|
||||
!9 = !{!"clang version 6.0.0 "}
|
||||
!10 = !DIExpression(DW_OP_plus_uconst, 12)
|
||||
!11 = !DIExpression(DW_OP_plus_uconst, 8, DW_OP_deref)
|
||||
!12 = distinct !DISubprogram(name: "fun", linkageName: "fun", scope: !1, file: !1, line: 9, type: !13, isLocal: false, isDefinition: true, scopeLine: 9, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
|
||||
!13 = !DISubroutineType(types: !14)
|
||||
!14 = !{!15}
|
||||
!15 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "string", file: !1, line: 1, size: 96, elements: !16, identifier: ".?AUstring@@")
|
||||
!16 = !{!17, !19, !20}
|
||||
!17 = !DIDerivedType(tag: DW_TAG_member, name: "length", scope: !15, file: !1, line: 2, baseType: !18, size: 32)
|
||||
!18 = !DIBasicType(name: "long int", size: 32, encoding: DW_ATE_signed)
|
||||
!19 = !DIDerivedType(tag: DW_TAG_member, name: "size", scope: !15, file: !1, line: 3, baseType: !18, size: 32, offset: 32)
|
||||
!20 = !DIDerivedType(tag: DW_TAG_member, name: "data", scope: !15, file: !1, line: 4, baseType: !21, size: 32, offset: 64)
|
||||
!21 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !22, size: 32)
|
||||
!22 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
|
||||
!23 = !DILocalVariable(name: "Result", scope: !12, file: !1, line: 10, type: !15)
|
||||
!24 = !DIExpression(DW_OP_deref)
|
||||
!25 = !DILocation(line: 10, scope: !12)
|
||||
!26 = !DILocalVariable(name: "Str", scope: !12, file: !1, line: 10, type: !27)
|
||||
!27 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !15, size: 32)
|
||||
!28 = !DIExpression(DW_OP_constu, 4, DW_OP_minus)
|
||||
!29 = !DILocation(line: 11, scope: !12)
|
||||
!30 = !DILocation(line: 12, scope: !12)
|
||||
!31 = distinct !DISubprogram(name: "len", linkageName: "len", scope: !1, file: !1, line: 14, type: !32, isLocal: false, isDefinition: true, scopeLine: 14, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
|
||||
!32 = !DISubroutineType(types: !33)
|
||||
!33 = !{!18}
|
||||
!34 = !DILocation(line: 15, scope: !31)
|
||||
!35 = !DILocalVariable(name: "Bytes", scope: !31, file: !1, line: 15, type: !18)
|
||||
!36 = !DILocation(line: 16, scope: !31)
|
||||
|
||||
...
|
||||
---
|
||||
name: fun
|
||||
alignment: 4
|
||||
exposesReturnsTwice: false
|
||||
legalized: false
|
||||
regBankSelected: false
|
||||
selected: false
|
||||
tracksRegLiveness: true
|
||||
registers:
|
||||
liveins:
|
||||
frameInfo:
|
||||
isFrameAddressTaken: false
|
||||
isReturnAddressTaken: false
|
||||
hasStackMap: false
|
||||
hasPatchPoint: false
|
||||
stackSize: 4
|
||||
offsetAdjustment: 0
|
||||
maxAlignment: 4
|
||||
adjustsStack: true
|
||||
hasCalls: true
|
||||
stackProtector: ''
|
||||
maxCallFrameSize: 0
|
||||
hasOpaqueSPAdjustment: false
|
||||
hasVAStart: false
|
||||
hasMustTailInVarArgFunc: false
|
||||
savePoint: ''
|
||||
restorePoint: ''
|
||||
fixedStack:
|
||||
- { id: 0, type: spill-slot, offset: -8, size: 4, alignment: 4, stack-id: 0,
|
||||
callee-saved-register: '%esi' }
|
||||
- { id: 1, type: default, offset: 4, size: 4, alignment: 4, stack-id: 0,
|
||||
isImmutable: true, isAliased: false, callee-saved-register: '' }
|
||||
- { id: 2, type: default, offset: 0, size: 4, alignment: 4, stack-id: 0,
|
||||
isImmutable: true, isAliased: false, callee-saved-register: '' }
|
||||
stack:
|
||||
constants:
|
||||
body: |
|
||||
bb.0.entry:
|
||||
liveins: %esi
|
||||
|
||||
frame-setup PUSH32r killed %esi, implicit-def %esp, implicit %esp
|
||||
CFI_INSTRUCTION def_cfa_offset 8
|
||||
CFI_INSTRUCTION offset %esi, -8
|
||||
%esi = MOV32rm %esp, 1, _, 8, _ :: (load 4 from %fixed-stack.2)
|
||||
DBG_VALUE %esp, 0, !26, !10, debug-location !25
|
||||
DBG_VALUE %esp, 0, !23, !11, debug-location !25
|
||||
CALLpcrel32 @getString, csr_32, implicit %esp, implicit-def %esp, implicit-def %eax, debug-location !29
|
||||
%ecx = MOV32rm %eax, 1, _, 0, _, debug-location !29 :: (dereferenceable load 4 from %ir.1)
|
||||
%edx = MOV32rm %eax, 1, _, 4, _, debug-location !29 :: (dereferenceable load 4 from %ir.1 + 4)
|
||||
MOV32mr %esi, 1, _, 0, _, killed %ecx, debug-location !29 :: (store 4 into %ir.0)
|
||||
MOV32mr %esi, 1, _, 4, _, killed %edx, debug-location !29 :: (store 4 into %ir.0 + 4)
|
||||
%eax = MOV32rm killed %eax, 1, _, 8, _, debug-location !29 :: (dereferenceable load 4 from %ir.1 + 8)
|
||||
MOV32mr %esi, 1, _, 8, _, killed %eax, debug-location !29 :: (store 4 into %ir.0 + 8)
|
||||
%eax = COPY killed %esi, debug-location !30
|
||||
%esi = POP32r implicit-def %esp, implicit %esp, debug-location !30
|
||||
RET 0, %eax, debug-location !30
|
||||
|
||||
...
|
||||
---
|
||||
name: len
|
||||
alignment: 4
|
||||
exposesReturnsTwice: false
|
||||
legalized: false
|
||||
regBankSelected: false
|
||||
selected: false
|
||||
tracksRegLiveness: true
|
||||
registers:
|
||||
liveins:
|
||||
frameInfo:
|
||||
isFrameAddressTaken: false
|
||||
isReturnAddressTaken: false
|
||||
hasStackMap: false
|
||||
hasPatchPoint: false
|
||||
stackSize: 0
|
||||
offsetAdjustment: 0
|
||||
maxAlignment: 4
|
||||
adjustsStack: false
|
||||
hasCalls: false
|
||||
stackProtector: ''
|
||||
maxCallFrameSize: 0
|
||||
hasOpaqueSPAdjustment: false
|
||||
hasVAStart: false
|
||||
hasMustTailInVarArgFunc: false
|
||||
savePoint: ''
|
||||
restorePoint: ''
|
||||
fixedStack:
|
||||
- { id: 0, type: default, offset: 4, size: 4, alignment: 4, stack-id: 0,
|
||||
isImmutable: true, isAliased: false, callee-saved-register: '' }
|
||||
- { id: 1, type: default, offset: 0, size: 4, alignment: 4, stack-id: 0,
|
||||
isImmutable: true, isAliased: false, callee-saved-register: '' }
|
||||
stack:
|
||||
constants:
|
||||
body: |
|
||||
bb.0.entry:
|
||||
%eax = MOV32rm %esp, 1, _, 4, _ :: (load 4 from %fixed-stack.1)
|
||||
%eax = MOV32rm killed %eax, 1, _, 0, _, debug-location !34 :: (load 4 from %ir.0)
|
||||
DBG_VALUE debug-use %eax, 0, !35, !28, debug-location !34
|
||||
%eax = ADD32rm killed %eax, %esp, 1, _, 8, _, implicit-def dead %eflags, debug-location !36 :: (load 4 from %fixed-stack.0)
|
||||
RET 0, %eax, debug-location !36
|
||||
|
||||
...
|
@ -179,8 +179,7 @@
|
||||
; ASM: .asciz "nested" # Function name
|
||||
; ASM: .short 4414 # Record kind: S_LOCAL
|
||||
; ASM: .asciz "o"
|
||||
; FIXME: We should have a .cv_def_range for 'o', but we don't yet.
|
||||
; ASM-NOT: .cv_def_range
|
||||
; ASM: .cv_def_range .Lfunc_begin3 .Lfunc_end3, "E\021J\001\000\000\000\000\000\000"
|
||||
; ASM: .short 4414 # Record kind: S_LOCAL
|
||||
; ASM: .asciz "p"
|
||||
; ASM: .cv_def_range [[p_start]] .Lfunc_end3, "C\021\021\000\000\000\004\000\000\000"
|
||||
@ -190,8 +189,17 @@
|
||||
; OBJ: DisplayName: nested
|
||||
; OBJ: }
|
||||
; OBJ: LocalSym {
|
||||
; OBJ: Type: Nested&
|
||||
; OBJ: VarName: o
|
||||
; OBJ: }
|
||||
; OBJ: DefRangeRegisterRelSym {
|
||||
; OBJ: BaseRegister: 330
|
||||
; OBJ: HasSpilledUDTMember: No
|
||||
; OBJ: OffsetInParent: 0
|
||||
; OBJ: BasePointerOffset: 0
|
||||
; OBJ: LocalVariableAddrRange {
|
||||
; OBJ: }
|
||||
; OBJ: }
|
||||
; OBJ: LocalSym {
|
||||
; OBJ: VarName: p
|
||||
; OBJ: }
|
||||
|
@ -50,28 +50,40 @@
|
||||
; CHECK: SizeOf: 4
|
||||
; CHECK: Name:
|
||||
; CHECK: }
|
||||
; CHECK: Array (0x1004) {
|
||||
; CHECK: Pointer (0x1004) {
|
||||
; CHECK: TypeLeafKind: LF_POINTER (0x1002)
|
||||
; CHECK: PointeeType: 0x1003
|
||||
; CHECK: PointerAttributes: 0x2A
|
||||
; CHECK: PtrType: Near32 (0xA)
|
||||
; CHECK: PtrMode: LValueReference (0x1)
|
||||
; CHECK: IsFlat: 0
|
||||
; CHECK: IsConst: 0
|
||||
; CHECK: IsVolatile: 0
|
||||
; CHECK: IsUnaligned: 0
|
||||
; CHECK: SizeOf: 0
|
||||
; CHECK: }
|
||||
; CHECK: Array (0x1005) {
|
||||
; CHECK: TypeLeafKind: LF_ARRAY (0x1503)
|
||||
; CHECK: ElementType: char (0x70)
|
||||
; CHECK: IndexType: unsigned long (0x22)
|
||||
; CHECK: SizeOf: 7
|
||||
; CHECK: Name:
|
||||
; CHECK: }
|
||||
; CHECK: Array (0x1005) {
|
||||
; CHECK: TypeLeafKind: LF_ARRAY (0x1503)
|
||||
; CHECK: ElementType: 0x1004
|
||||
; CHECK: IndexType: unsigned long (0x22)
|
||||
; CHECK: SizeOf: 35
|
||||
; CHECK: Name:
|
||||
; CHECK: }
|
||||
; CHECK: Array (0x1006) {
|
||||
; CHECK: TypeLeafKind: LF_ARRAY (0x1503)
|
||||
; CHECK: ElementType: 0x1005
|
||||
; CHECK: IndexType: unsigned long (0x22)
|
||||
; CHECK: SizeOf: 35
|
||||
; CHECK: Name:
|
||||
; CHECK: }
|
||||
; CHECK: Array (0x1007) {
|
||||
; CHECK: TypeLeafKind: LF_ARRAY (0x1503)
|
||||
; CHECK: ElementType: 0x1006
|
||||
; CHECK: IndexType: unsigned long (0x22)
|
||||
; CHECK: SizeOf: 70
|
||||
; CHECK: Name:
|
||||
; CHECK: }
|
||||
; CHECK: Struct (0x1007) {
|
||||
; CHECK: Struct (0x1008) {
|
||||
; CHECK: TypeLeafKind: LF_STRUCTURE (0x1505)
|
||||
; CHECK: MemberCount: 0
|
||||
; CHECK: Properties [ (0x280)
|
||||
@ -85,16 +97,16 @@
|
||||
; CHECK: Name: incomplete_struct
|
||||
; CHECK: LinkageName: .?AUincomplete_struct@@
|
||||
; CHECK: }
|
||||
; CHECK: Array (0x1008) {
|
||||
; CHECK: Array (0x1009) {
|
||||
; CHECK: TypeLeafKind: LF_ARRAY (0x1503)
|
||||
; CHECK: ElementType: incomplete_struct (0x1007)
|
||||
; CHECK: ElementType: incomplete_struct (0x1008)
|
||||
; CHECK: IndexType: unsigned long (0x22)
|
||||
; CHECK: SizeOf: 12
|
||||
; CHECK: Name:
|
||||
; CHECK: }
|
||||
; CHECK: Pointer (0x1009) {
|
||||
; CHECK: Pointer (0x100A) {
|
||||
; CHECK: TypeLeafKind: LF_POINTER (0x1002)
|
||||
; CHECK: PointeeType: 0x1008
|
||||
; CHECK: PointeeType: 0x1009
|
||||
; CHECK: PointerAttributes: 0x800A
|
||||
; CHECK: PtrType: Near32 (0xA)
|
||||
; CHECK: PtrMode: Pointer (0x0)
|
||||
@ -104,8 +116,41 @@
|
||||
; CHECK: IsUnaligned: 0
|
||||
; CHECK: SizeOf: 4
|
||||
; CHECK: }
|
||||
;
|
||||
; CHECK: Modifier (0x100E) {
|
||||
; CHECK: FieldList (0x100B) {
|
||||
; CHECK: TypeLeafKind: LF_FIELDLIST (0x1203)
|
||||
; CHECK: DataMember {
|
||||
; CHECK: TypeLeafKind: LF_MEMBER (0x150D)
|
||||
; CHECK: AccessSpecifier: Public (0x3)
|
||||
; CHECK: Type: int (0x74)
|
||||
; CHECK: FieldOffset: 0x0
|
||||
; CHECK: Name: s1
|
||||
; CHECK: }
|
||||
; CHECK: }
|
||||
; CHECK: Struct (0x100C) {
|
||||
; CHECK: TypeLeafKind: LF_STRUCTURE (0x1505)
|
||||
; CHECK: MemberCount: 1
|
||||
; CHECK: Properties [ (0x200)
|
||||
; CHECK: HasUniqueName (0x200)
|
||||
; CHECK: ]
|
||||
; CHECK: FieldList: <field list> (0x100B)
|
||||
; CHECK: DerivedFrom: 0x0
|
||||
; CHECK: VShape: 0x0
|
||||
; CHECK: SizeOf: 4
|
||||
; CHECK: Name: incomplete_struct
|
||||
; CHECK: LinkageName: .?AUincomplete_struct@@
|
||||
; CHECK: }
|
||||
; CHECK: StringId (0x100D) {
|
||||
; CHECK: TypeLeafKind: LF_STRING_ID (0x1605)
|
||||
; CHECK: Id: 0x0
|
||||
; CHECK: StringData: \t.cpp
|
||||
; CHECK: }
|
||||
; CHECK: UdtSourceLine (0x100E) {
|
||||
; CHECK: TypeLeafKind: LF_UDT_SRC_LINE (0x1606)
|
||||
; CHECK: UDT: incomplete_struct (0x100C)
|
||||
; CHECK: SourceFile: \t.cpp (0x100D)
|
||||
; CHECK: LineNumber: 4
|
||||
; CHECK: }
|
||||
; CHECK: Modifier (0x100F) {
|
||||
; CHECK: TypeLeafKind: LF_MODIFIER (0x1001)
|
||||
; CHECK: ModifiedType: int (0x74)
|
||||
; CHECK: Modifiers [ (0x3)
|
||||
@ -113,12 +158,12 @@
|
||||
; CHECK: Volatile (0x2)
|
||||
; CHECK: ]
|
||||
; CHECK: }
|
||||
; CHECK: Array (0x100F) {
|
||||
; CHECK: Array (0x1010) {
|
||||
; CHECK: TypeLeafKind: LF_ARRAY (0x1503)
|
||||
; CHECK: ElementType: const volatile int (0x100E)
|
||||
; CHECK: ElementType: const volatile int (0x100F)
|
||||
; CHECK: IndexType: unsigned long (0x22)
|
||||
; CHECK: SizeOf: 16
|
||||
; CHECK: Name:
|
||||
; CHECK: Name:
|
||||
; CHECK: }
|
||||
; CHECK: ]
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user