Skip to content

[WIP] Encode WebAssembly specific locations in DBG_VALUEs and DW_AT_frame_base #2

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
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 llvm/include/llvm/BinaryFormat/Dwarf.def
Original file line number Diff line number Diff line change
@@ -627,6 +627,8 @@ HANDLE_DW_OP(0xa9, reinterpret, 5, DWARF)
// Vendor extensions:
// Extensions for GNU-style thread-local storage.
HANDLE_DW_OP(0xe0, GNU_push_tls_address, 0, GNU)
// Extensions for WebAssembly.
HANDLE_DW_OP(0xed, WASM_location, 0, WASM)
// Extensions for Fission proposal.
HANDLE_DW_OP(0xfb, GNU_addr_index, 0, GNU)
HANDLE_DW_OP(0xfc, GNU_const_index, 0, GNU)
3 changes: 2 additions & 1 deletion llvm/include/llvm/BinaryFormat/Dwarf.h
Original file line number Diff line number Diff line change
@@ -59,7 +59,8 @@ enum LLVMConstants : uint32_t {
DWARF_VENDOR_GNU = 3,
DWARF_VENDOR_GOOGLE = 4,
DWARF_VENDOR_LLVM = 5,
DWARF_VENDOR_MIPS = 6
DWARF_VENDOR_MIPS = 6,
DWARF_VENDOR_WASM = 7
};

/// Constants that define the DWARF format as 32 or 64 bit.
23 changes: 23 additions & 0 deletions llvm/include/llvm/CodeGen/TargetRegisterInfo.h
Original file line number Diff line number Diff line change
@@ -211,6 +211,22 @@ struct RegClassWeight {
unsigned WeightLimit;
};

struct FrameBaseLocation {
enum LocationKind {
Register,
CFA,
TargetIndex
} Kind;
struct TargetIndexInfo {
unsigned Index;
signed Offset;
};
union {
unsigned Reg;
TargetIndexInfo TI;
};
};

/// TargetRegisterInfo base class - We assume that the target defines a static
/// array of TargetRegisterDesc objects that represent all of the machine
/// registers that the target has. As such, we simply have to track a pointer
@@ -988,6 +1004,13 @@ class TargetRegisterInfo : public MCRegisterInfo {
/// for values allocated in the current stack frame.
virtual unsigned getFrameRegister(const MachineFunction &MF) const = 0;

virtual FrameBaseLocation getFrameBaseLocation(const MachineFunction &MF) const {
FrameBaseLocation Loc;
Loc.Kind = FrameBaseLocation::Register;
Loc.Reg = getFrameRegister(MF);
return Loc;
}

/// Mark a register and all its aliases as reserved in the given set.
void markSuperRegs(BitVector &RegisterSet, unsigned Reg) const;

4 changes: 4 additions & 0 deletions llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
Original file line number Diff line number Diff line change
@@ -895,6 +895,10 @@ static bool emitDebugValueComment(const MachineInstr *MI, AsmPrinter &AP) {
OS << MI->getOperand(0).getImm();
} else if (MI->getOperand(0).isCImm()) {
MI->getOperand(0).getCImm()->getValue().print(OS, false /*isSigned*/);
} else if (MI->getOperand(0).isTargetIndex()) {
auto Op = MI->getOperand(0);
OS << "!target-index(" << Op.getIndex() << "," << Op.getOffset() << ")";
return true;
} else {
unsigned Reg;
if (MI->getOperand(0).isReg()) {
37 changes: 34 additions & 3 deletions llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h
Original file line number Diff line number Diff line change
@@ -21,6 +21,19 @@
namespace llvm {
class AsmPrinter;

struct TargetIndexLocation {
int Index;
int Offset;

TargetIndexLocation() = default;
TargetIndexLocation(unsigned Idx, int64_t Offset)
: Index(Idx), Offset(Offset) {}

bool operator==(const TargetIndexLocation &Other) const {
return Index == Other.Index && Offset == Other.Offset;
}
};

/// This struct describes location entries emitted in the .debug_loc
/// section.
class DebugLocEntry {
@@ -47,12 +60,20 @@ class DebugLocEntry {
: Expression(Expr), EntryKind(E_Location), Loc(Loc) {
assert(cast<DIExpression>(Expr)->isValid());
}
Value(const DIExpression *Expr, TargetIndexLocation Loc)
: Expression(Expr), EntryKind(E_TargetIndexLocation), TIL(Loc) {}

/// Any complex address location expression for this Value.
const DIExpression *Expression;

/// Type of entry that this represents.
enum EntryType { E_Location, E_Integer, E_ConstantFP, E_ConstantInt };
enum EntryType {
E_Location,
E_Integer,
E_ConstantFP,
E_ConstantInt,
E_TargetIndexLocation
};
enum EntryType EntryKind;

/// Either a constant,
@@ -62,17 +83,25 @@ class DebugLocEntry {
const ConstantInt *CIP;
} Constant;

// Or a location in the machine frame.
MachineLocation Loc;
union {
// Or a location in the machine frame.
MachineLocation Loc;
// Or a location from target specific location.
TargetIndexLocation TIL;
};

bool isLocation() const { return EntryKind == E_Location; }
bool isTargetIndexLocation() const {
return EntryKind == E_TargetIndexLocation;
}
bool isInt() const { return EntryKind == E_Integer; }
bool isConstantFP() const { return EntryKind == E_ConstantFP; }
bool isConstantInt() const { return EntryKind == E_ConstantInt; }
int64_t getInt() const { return Constant.Int; }
const ConstantFP *getConstantFP() const { return Constant.CFP; }
const ConstantInt *getConstantInt() const { return Constant.CIP; }
MachineLocation getLoc() const { return Loc; }
TargetIndexLocation getTargetIndexLocation() const { return TIL; }
bool isFragment() const { return getExpression()->isFragment(); }
const DIExpression *getExpression() const { return Expression; }
friend bool operator==(const Value &, const Value &);
@@ -165,6 +194,8 @@ inline bool operator==(const DebugLocEntry::Value &A,
switch (A.EntryKind) {
case DebugLocEntry::Value::E_Location:
return A.Loc == B.Loc;
case DebugLocEntry::Value::E_TargetIndexLocation:
return A.TIL == B.TIL;
case DebugLocEntry::Value::E_Integer:
return A.Constant.Int == B.Constant.Int;
case DebugLocEntry::Value::E_ConstantFP:
17 changes: 14 additions & 3 deletions llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
Original file line number Diff line number Diff line change
@@ -340,13 +340,24 @@ DIE &DwarfCompileUnit::updateSubprogramScopeDIE(const DISubprogram *SP) {

// Only include DW_AT_frame_base in full debug info
if (!includeMinimalInlineScopes()) {
if (Asm->MF->getTarget().getTargetTriple().isNVPTX()) {
const TargetRegisterInfo *RI = Asm->MF->getSubtarget().getRegisterInfo();
auto FBL = RI->getFrameBaseLocation(*Asm->MF);
if (FBL.Kind == FrameBaseLocation::CFA) {
DIELoc *Loc = new (DIEValueAllocator) DIELoc;
addUInt(*Loc, dwarf::DW_FORM_data1, dwarf::DW_OP_call_frame_cfa);
addBlock(*SPDie, dwarf::DW_AT_frame_base, Loc);
} else if (FBL.Kind == FrameBaseLocation::TargetIndex) {
if (FBL.TI.Offset >= 0) {
DIELoc *Loc = new (DIEValueAllocator) DIELoc;
DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc);
DIExpressionCursor Cursor({});
DwarfExpr.addTargetIndexLocation(FBL.TI.Index, FBL.TI.Offset);
DwarfExpr.addExpression(std::move(Cursor));
addBlock(*SPDie, dwarf::DW_AT_frame_base, DwarfExpr.finalize());
}
} else {
const TargetRegisterInfo *RI = Asm->MF->getSubtarget().getRegisterInfo();
MachineLocation Location(RI->getFrameRegister(*Asm->MF));
assert(FBL.Kind == FrameBaseLocation::Register);
MachineLocation Location(FBL.Reg);
if (RI->isPhysicalRegister(Location.getReg()))
addAddress(*SPDie, dwarf::DW_AT_frame_base, Location);
}
8 changes: 8 additions & 0 deletions llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
Original file line number Diff line number Diff line change
@@ -1072,6 +1072,11 @@ static DebugLocEntry::Value getDebugLocValue(const MachineInstr *MI) {
MachineLocation MLoc(RegOp.getReg(), Op1.isImm());
return DebugLocEntry::Value(Expr, MLoc);
}
if (MI->getOperand(0).isTargetIndex()) {
auto Op = MI->getOperand(0);
return DebugLocEntry::Value(
Expr, TargetIndexLocation(Op.getIndex(), Op.getOffset()));
}
if (MI->getOperand(0).isImm())
return DebugLocEntry::Value(Expr, MI->getOperand(0).getImm());
if (MI->getOperand(0).isFPImm())
@@ -1920,6 +1925,9 @@ static void emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT,
if (!DwarfExpr.addMachineRegExpression(TRI, Cursor, Location.getReg()))
return;
return DwarfExpr.addExpression(std::move(Cursor));
} else if (Value.isTargetIndexLocation()) {
TargetIndexLocation Loc = Value.getTargetIndexLocation();
DwarfExpr.addTargetIndexLocation(Loc.Index, Loc.Offset);
} else if (Value.isConstantFP()) {
APInt RawBytes = Value.getConstantFP()->getValueAPF().bitcastToAPInt();
DwarfExpr.addUnsignedConstant(RawBytes);
8 changes: 8 additions & 0 deletions llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp
Original file line number Diff line number Diff line change
@@ -437,3 +437,11 @@ void DwarfExpression::addFragmentOffset(const DIExpression *Expr) {
addOpPiece(FragmentOffset - OffsetInBits);
OffsetInBits = FragmentOffset;
}

void DwarfExpression::addTargetIndexLocation(unsigned Index, int64_t Offset) {
assert(LocationKind == Implicit || LocationKind == Unknown);
LocationKind = Implicit;
emitOp(dwarf::DW_OP_WASM_location);
emitUnsigned(Index);
emitSigned(Offset);
}
4 changes: 4 additions & 0 deletions llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h
Original file line number Diff line number Diff line change
@@ -248,6 +248,10 @@ class DwarfExpression {
/// If applicable, emit an empty DW_OP_piece / DW_OP_bit_piece to advance to
/// the fragment described by \c Expr.
void addFragmentOffset(const DIExpression *Expr);

/// Emit location information expressed via target's index + offset
/// It is an extension for WebAssembly locals, globals and operand stack.
void addTargetIndexLocation(unsigned Index, int64_t Offset);
};

/// DwarfExpression implementation for .debug_loc entries.
2 changes: 2 additions & 0 deletions llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
Original file line number Diff line number Diff line change
@@ -93,6 +93,8 @@ static DescVector getDescriptions() {
Descriptions[DW_OP_implicit_value] =
Desc(Op::Dwarf3, Op::SizeLEB, Op::SizeBlock);
Descriptions[DW_OP_stack_value] = Desc(Op::Dwarf3);
Descriptions[DW_OP_WASM_location] =
Desc(Op::Dwarf4, Op::SizeLEB, Op::SignedSizeLEB);
Descriptions[DW_OP_GNU_push_tls_address] = Desc(Op::Dwarf3);
Descriptions[DW_OP_addrx] = Desc(Op::Dwarf4, Op::SizeLEB);
Descriptions[DW_OP_GNU_addr_index] = Desc(Op::Dwarf4, Op::SizeLEB);
6 changes: 6 additions & 0 deletions llvm/lib/Target/NVPTX/NVPTXRegisterInfo.h
Original file line number Diff line number Diff line change
@@ -45,6 +45,12 @@ class NVPTXRegisterInfo : public NVPTXGenRegisterInfo {

unsigned getFrameRegister(const MachineFunction &MF) const override;

FrameBaseLocation getFrameBaseLocation(const MachineFunction &MF) const override {
FrameBaseLocation Loc;
Loc.Kind = FrameBaseLocation::CFA;
return Loc;
}

ManagedStringPool *getStrPool() const {
return const_cast<ManagedStringPool *>(&ManagedStrPool);
}
4 changes: 4 additions & 0 deletions llvm/lib/Target/WebAssembly/WebAssembly.h
Original file line number Diff line number Diff line change
@@ -82,6 +82,10 @@ void initializeWebAssemblyRegNumberingPass(PassRegistry &);
void initializeWebAssemblyPeepholePass(PassRegistry &);
void initializeWebAssemblyCallIndirectFixupPass(PassRegistry &);

namespace WebAssembly {
enum TargetIndex { TI_LOCAL_START, TI_GLOBAL_START, TI_OPERAND_STACK_START };
} // end namespace WebAssembly

} // end namespace llvm

#endif
8 changes: 8 additions & 0 deletions llvm/lib/Target/WebAssembly/WebAssemblyDebugValueManager.cpp
Original file line number Diff line number Diff line change
@@ -12,6 +12,7 @@
///
//===----------------------------------------------------------------------===//

#include "WebAssembly.h"
#include "WebAssemblyDebugValueManager.h"
#include "WebAssemblyMachineFunctionInfo.h"
#include "llvm/CodeGen/MachineInstr.h"
@@ -44,3 +45,10 @@ void WebAssemblyDebugValueManager::clone(MachineInstr *Insert,
MBB->insert(Insert, Clone);
}
}

void WebAssemblyDebugValueManager::replaceWithLocal(unsigned LocalId) {
for (auto *DBI : DbgValues) {
MachineOperand &Op = DBI->getOperand(0);
Op.ChangeToTargetIndex(llvm::WebAssembly::TI_LOCAL_START, LocalId);
}
}
1 change: 1 addition & 0 deletions llvm/lib/Target/WebAssembly/WebAssemblyDebugValueManager.h
Original file line number Diff line number Diff line change
@@ -31,6 +31,7 @@ class WebAssemblyDebugValueManager {
void move(MachineInstr *Insert);
void updateReg(unsigned Reg);
void clone(MachineInstr *Insert, unsigned NewReg);
void replaceWithLocal(unsigned LocalId);
};

} // end namespace llvm
13 changes: 13 additions & 0 deletions llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp
Original file line number Diff line number Diff line change
@@ -18,6 +18,7 @@

#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
#include "WebAssembly.h"
#include "WebAssemblyDebugValueManager.h"
#include "WebAssemblyMachineFunctionInfo.h"
#include "WebAssemblySubtarget.h"
#include "WebAssemblyUtilities.h"
@@ -262,6 +263,8 @@ bool WebAssemblyExplicitLocals::runOnMachineFunction(MachineFunction &MF) {
.addImm(LocalId)
.addReg(MI.getOperand(2).getReg());

WebAssemblyDebugValueManager(&MI).replaceWithLocal(LocalId);

MI.eraseFromParent();
Changed = true;
continue;
@@ -291,6 +294,9 @@ bool WebAssemblyExplicitLocals::runOnMachineFunction(MachineFunction &MF) {
} else {
unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
unsigned Opc = getSetLocalOpcode(RC);

WebAssemblyDebugValueManager(&MI).replaceWithLocal(LocalId);

BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc))
.addImm(LocalId)
.addReg(NewReg);
@@ -380,6 +386,13 @@ bool WebAssemblyExplicitLocals::runOnMachineFunction(MachineFunction &MF) {
Changed = true;
}

{
auto RL = Reg2Local.find(MFI.SPVReg);
if (RL != Reg2Local.end()) {
MFI.SPLocal = RL->second;
}
}

#ifndef NDEBUG
// Assert that all registers have been stackified at this point.
for (const MachineBasicBlock &MBB : MF) {
10 changes: 10 additions & 0 deletions llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp
Original file line number Diff line number Diff line change
@@ -15,6 +15,7 @@

#include "WebAssemblyInstrInfo.h"
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
#include "WebAssembly.h"
#include "WebAssemblyMachineFunctionInfo.h"
#include "WebAssemblySubtarget.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
@@ -198,3 +199,12 @@ bool WebAssemblyInstrInfo::reverseBranchCondition(
Cond.front() = MachineOperand::CreateImm(!Cond.front().getImm());
return false;
}

ArrayRef<std::pair<int, const char *>>
WebAssemblyInstrInfo::getSerializableTargetIndices() const {
static const std::pair<int, const char *> TargetIndices[] = {
{WebAssembly::TI_LOCAL_START, "wasm-local-start"},
{WebAssembly::TI_GLOBAL_START, "wasm-global-start"},
{WebAssembly::TI_OPERAND_STACK_START, "wasm-operator-stack-start"}};
return makeArrayRef(TargetIndices);
}
4 changes: 4 additions & 0 deletions llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.h
Original file line number Diff line number Diff line change
@@ -17,6 +17,7 @@
#define LLVM_LIB_TARGET_WEBASSEMBLY_WEBASSEMBLYINSTRINFO_H

#include "WebAssemblyRegisterInfo.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/CodeGen/TargetInstrInfo.h"

#define GET_INSTRINFO_HEADER
@@ -56,6 +57,9 @@ class WebAssemblyInstrInfo final : public WebAssemblyGenInstrInfo {
int *BytesAdded = nullptr) const override;
bool
reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const override;

ArrayRef<std::pair<int, const char *>>
getSerializableTargetIndices() const override;
};

} // end namespace llvm
5 changes: 4 additions & 1 deletion llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h
Original file line number Diff line number Diff line change
@@ -53,7 +53,7 @@ class WebAssemblyFunctionInfo final : public MachineFunctionInfo {
unsigned BasePtrVreg = -1U;

public:
explicit WebAssemblyFunctionInfo(MachineFunction &MF) : MF(MF) {}
explicit WebAssemblyFunctionInfo(MachineFunction &MF) : MF(MF), SPVReg(WebAssembly::NoRegister) {}
~WebAssemblyFunctionInfo() override;

void addParam(MVT VT) { Params.push_back(VT); }
@@ -118,6 +118,9 @@ class WebAssemblyFunctionInfo final : public MachineFunctionInfo {
assert(Reg & INT32_MIN);
return Reg & INT32_MAX;
}

unsigned SPVReg;
unsigned SPLocal;
};

void ComputeLegalValueVTs(const Function &F, const TargetMachine &TM, Type *Ty,
10 changes: 10 additions & 0 deletions llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.cpp
Original file line number Diff line number Diff line change
@@ -138,6 +138,16 @@ WebAssemblyRegisterInfo::getFrameRegister(const MachineFunction &MF) const {
return Regs[TFI->hasFP(MF)][TT.isArch64Bit()];
}

FrameBaseLocation
WebAssemblyRegisterInfo::getFrameBaseLocation(const MachineFunction &MF) const {
const WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
FrameBaseLocation Loc;
Loc.Kind = FrameBaseLocation::TargetIndex;
signed Local = MFI.SPVReg != WebAssembly::NoRegister ? MFI.SPLocal : -1;
Loc.TI = {0, Local};
return Loc;
}

const TargetRegisterClass *
WebAssemblyRegisterInfo::getPointerRegClass(const MachineFunction &MF,
unsigned Kind) const {
2 changes: 2 additions & 0 deletions llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.h
Original file line number Diff line number Diff line change
@@ -42,6 +42,8 @@ class WebAssemblyRegisterInfo final : public WebAssemblyGenRegisterInfo {
// Debug information queries.
unsigned getFrameRegister(const MachineFunction &MF) const override;

FrameBaseLocation getFrameBaseLocation(const MachineFunction &MF) const override;

const TargetRegisterClass *
getPointerRegClass(const MachineFunction &MF,
unsigned Kind = 0) const override;
7 changes: 6 additions & 1 deletion llvm/lib/Target/WebAssembly/WebAssemblyReplacePhysRegs.cpp
Original file line number Diff line number Diff line change
@@ -89,8 +89,13 @@ bool WebAssemblyReplacePhysRegs::runOnMachineFunction(MachineFunction &MF) {
for (auto I = MRI.reg_begin(PReg), E = MRI.reg_end(); I != E;) {
MachineOperand &MO = *I++;
if (!MO.isImplicit()) {
if (VReg == WebAssembly::NoRegister)
if (VReg == WebAssembly::NoRegister) {
VReg = MRI.createVirtualRegister(RC);
if (PReg == WebAssembly::SP32) {
WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
MFI.SPVReg = VReg;
}
}
MO.setReg(VReg);
if (MO.getParent()->isDebugValue())
MO.setIsDebug();
74 changes: 74 additions & 0 deletions llvm/test/DebugInfo/WebAssembly/dbg-value-ti.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
; RUN: llc < %s -stop-after=wasm-explicit-locals | FileCheck %s

; Checks if DBG_VALUEs that correspond to new `local.{tee,set}` are
; using `target-index(wasm-local-start)` operands.

target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
target triple = "wasm32-unknown-unknown-wasm"

define hidden i32 @fib(i32 %n) local_unnamed_addr #0 !dbg !7 {
; CHECK: body:
entry:

; CHECK: %[[REG1:.*]]:i32 = CONST_I32 1,
; CHECK: LOCAL_SET_I32 [[LOOP_LOCAL:.*]], %[[REG1]],
; CHECK: DBG_VALUE 1, $noreg,
call void @llvm.dbg.value(metadata i32 1, metadata !16, metadata !DIExpression()), !dbg !19
%cmp8 = icmp sgt i32 %n, 0, !dbg !21
br i1 %cmp8, label %for.body, label %for.end, !dbg !24

for.body: ; preds = %entry, %for.body
%b.011 = phi i32 [ %add, %for.body ], [ 1, %entry ]
%a.010 = phi i32 [ %b.011, %for.body ], [ 0, %entry ]
%i.09 = phi i32 [ %inc, %for.body ], [ 0, %entry ]

; CHECK: %[[REG2:.*]]:i32 = LOCAL_GET_I32 [[LOOP_LOCAL]],
; CHECK: %[[REG3:.*]]:i32 = LOCAL_TEE_I32 [[TMP_LOCAL:.*]], %[[REG2]],
; CHECK: DBG_VALUE target-index(wasm-local-start) + [[TMP_LOCAL]], $noreg,
call void @llvm.dbg.value(metadata i32 %b.011, metadata !16, metadata !DIExpression()), !dbg !19

; CHECK: %[[REG4:.*]]:i32 = nsw ADD_I32
; CHECK: LOCAL_SET_I32 [[LOOP_LOCAL]], %[[REG4]],
; CHECK: DBG_VALUE target-index(wasm-local-start) + [[LOOP_LOCAL]], $noreg,
%add = add nsw i32 %b.011, %a.010, !dbg !26
%inc = add nuw nsw i32 %i.09, 1, !dbg !28
call void @llvm.dbg.value(metadata i32 %add, metadata !16, metadata !DIExpression()), !dbg !19
%exitcond = icmp eq i32 %inc, %n, !dbg !21
br i1 %exitcond, label %for.end, label %for.body, !dbg !24, !llvm.loop !29

for.end: ; preds = %for.body, %entry
%b.0.lcssa = phi i32 [ 1, %entry ], [ %add, %for.body ], !dbg !31
call void @llvm.dbg.value(metadata i32 %b.0.lcssa, metadata !16, metadata !DIExpression()), !dbg !19
ret i32 %b.0.lcssa, !dbg !32
}

declare void @llvm.dbg.value(metadata, metadata, metadata) #1

!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!4}
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 8.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
!1 = !DIFile(filename: "<unknown>", directory: "")
!2 = !{}
!4 = !{i32 2, !"Debug Info Version", i32 3}
!7 = distinct !DISubprogram(name: "fib", scope: !1, file: !1, line: 1, type: !8, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11)
!8 = !DISubroutineType(types: !9)
!9 = !{!10, !10}
!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!11 = !{!16}
!16 = !DILocalVariable(name: "b", scope: !7, file: !1, line: 2, type: !10)
!17 = !DILocation(line: 1, column: 13, scope: !7)
!18 = !DILocation(line: 2, column: 13, scope: !7)
!19 = !DILocation(line: 2, column: 20, scope: !7)
!20 = !DILocation(line: 2, column: 7, scope: !7)
!21 = !DILocation(line: 3, column: 17, scope: !22)
!22 = distinct !DILexicalBlock(scope: !23, file: !1, line: 3, column: 3)
!23 = distinct !DILexicalBlock(scope: !7, file: !1, line: 3, column: 3)
!24 = !DILocation(line: 3, column: 3, scope: !23)
!25 = !DILocation(line: 2, column: 10, scope: !7)
!26 = !DILocation(line: 6, column: 7, scope: !27)
!27 = distinct !DILexicalBlock(scope: !22, file: !1, line: 3, column: 27)
!28 = !DILocation(line: 3, column: 23, scope: !22)
!29 = distinct !{!29, !24, !30}
!30 = !DILocation(line: 7, column: 3, scope: !23)
!31 = !DILocation(line: 0, scope: !7)
!32 = !DILocation(line: 8, column: 3, scope: !7)