}
}
+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))
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);
}
}
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();
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);
struct LocalVariable {
const DILocalVariable *DIVar = nullptr;
SmallVector<LocalVarDefRange, 1> DefRanges;
+ bool Deref = false;
};
struct InlineSite {
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);
codeview::TypeIndex getTypeIndex(DITypeRef TypeRef,
DITypeRef ClassTyRef = DITypeRef());
+ codeview::TypeIndex getTypeIndexForReferenceTo(DITypeRef TypeRef);
+
codeview::TypeIndex getMemberFunctionType(const DISubprogram *SP,
const DICompositeType *Class);
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
#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 {
--- /dev/null
+# 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
+
+...
; 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"
; 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: }
; 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: Array (0x1006) {
; CHECK: TypeLeafKind: LF_ARRAY (0x1503)
-; CHECK: ElementType: 0x1004
+; CHECK: ElementType: 0x1005
; CHECK: IndexType: unsigned long (0x22)
; CHECK: SizeOf: 35
; CHECK: Name:
; CHECK: }
-; CHECK: Array (0x1006) {
+; CHECK: Array (0x1007) {
; CHECK: TypeLeafKind: LF_ARRAY (0x1503)
-; CHECK: ElementType: 0x1005
+; 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)
; 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)
; 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)
; 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: ]