[DebugInfo] Convert intrinsic llvm.dbg.label to MachineInstr.
In order to convert LLVM IR to MachineInstr, we need a new TargetOpcode, DBG_LABEL, to ‘lower’ intrinsic llvm.dbg.label. The patch creates this new TargetOpcode and convert intrinsic llvm.dbg.label to MachineInstr through SelectionDAG. In SelectionDAG, debug information is stored in SDDbgInfo. We create a new data member of SDDbgInfo for labels and use the new data member, SDDbgLabel, to create DBG_LABEL MachineInstr. The new DBG_LABEL MachineInstr uses label metadata from LLVM IR as its parameter. So, the backend could get metadata information of labels from DBG_LABEL MachineInstr. Differential Revision: https://reviews.llvm.org/D45341 Patch by Hsiangkai Wang. llvm-svn: 331842
This commit is contained in:
parent
2c864551df
commit
cd070cdc94
|
@ -292,6 +292,10 @@ public:
|
|||
/// this DBG_VALUE instruction.
|
||||
const DIExpression *getDebugExpression() const;
|
||||
|
||||
/// Return the debug label referenced by
|
||||
/// this DBG_LABEL instruction.
|
||||
const DILabel *getDebugLabel() const;
|
||||
|
||||
/// Emit an error referring to the source location of this instruction.
|
||||
/// This should only be used for inline assembly that is somehow
|
||||
/// impossible to compile. Other errors should have been handled much
|
||||
|
@ -831,6 +835,8 @@ public:
|
|||
bool isPosition() const { return isLabel() || isCFIInstruction(); }
|
||||
|
||||
bool isDebugValue() const { return getOpcode() == TargetOpcode::DBG_VALUE; }
|
||||
bool isDebugLabel() const { return getOpcode() == TargetOpcode::DBG_LABEL; }
|
||||
bool isDebugInstr() const { return isDebugValue() || isDebugLabel(); }
|
||||
|
||||
/// A DBG_VALUE is indirect iff the first operand is a register and
|
||||
/// the second operand is an immediate.
|
||||
|
@ -907,6 +913,7 @@ public:
|
|||
case TargetOpcode::EH_LABEL:
|
||||
case TargetOpcode::GC_LABEL:
|
||||
case TargetOpcode::DBG_VALUE:
|
||||
case TargetOpcode::DBG_LABEL:
|
||||
case TargetOpcode::LIFETIME_START:
|
||||
case TargetOpcode::LIFETIME_END:
|
||||
return true;
|
||||
|
|
|
@ -73,6 +73,7 @@ class MachineConstantPoolValue;
|
|||
class MCSymbol;
|
||||
class OptimizationRemarkEmitter;
|
||||
class SDDbgValue;
|
||||
class SDDbgLabel;
|
||||
class SelectionDAG;
|
||||
class SelectionDAGTargetInfo;
|
||||
class TargetLibraryInfo;
|
||||
|
@ -148,6 +149,7 @@ class SDDbgInfo {
|
|||
BumpPtrAllocator Alloc;
|
||||
SmallVector<SDDbgValue*, 32> DbgValues;
|
||||
SmallVector<SDDbgValue*, 32> ByvalParmDbgValues;
|
||||
SmallVector<SDDbgLabel*, 4> DbgLabels;
|
||||
using DbgValMapType = DenseMap<const SDNode *, SmallVector<SDDbgValue *, 2>>;
|
||||
DbgValMapType DbgValMap;
|
||||
|
||||
|
@ -164,6 +166,10 @@ public:
|
|||
DbgValMap[Node].push_back(V);
|
||||
}
|
||||
|
||||
void add(SDDbgLabel *L) {
|
||||
DbgLabels.push_back(L);
|
||||
}
|
||||
|
||||
/// Invalidate all DbgValues attached to the node and remove
|
||||
/// it from the Node-to-DbgValues map.
|
||||
void erase(const SDNode *Node);
|
||||
|
@ -172,13 +178,14 @@ public:
|
|||
DbgValMap.clear();
|
||||
DbgValues.clear();
|
||||
ByvalParmDbgValues.clear();
|
||||
DbgLabels.clear();
|
||||
Alloc.Reset();
|
||||
}
|
||||
|
||||
BumpPtrAllocator &getAlloc() { return Alloc; }
|
||||
|
||||
bool empty() const {
|
||||
return DbgValues.empty() && ByvalParmDbgValues.empty();
|
||||
return DbgValues.empty() && ByvalParmDbgValues.empty() && DbgLabels.empty();
|
||||
}
|
||||
|
||||
ArrayRef<SDDbgValue*> getSDDbgValues(const SDNode *Node) {
|
||||
|
@ -189,11 +196,14 @@ public:
|
|||
}
|
||||
|
||||
using DbgIterator = SmallVectorImpl<SDDbgValue*>::iterator;
|
||||
using DbgLabelIterator = SmallVectorImpl<SDDbgLabel*>::iterator;
|
||||
|
||||
DbgIterator DbgBegin() { return DbgValues.begin(); }
|
||||
DbgIterator DbgEnd() { return DbgValues.end(); }
|
||||
DbgIterator ByvalParmDbgBegin() { return ByvalParmDbgValues.begin(); }
|
||||
DbgIterator ByvalParmDbgEnd() { return ByvalParmDbgValues.end(); }
|
||||
DbgLabelIterator DbgLabelBegin() { return DbgLabels.begin(); }
|
||||
DbgLabelIterator DbgLabelEnd() { return DbgLabels.end(); }
|
||||
};
|
||||
|
||||
void checkForCycles(const SelectionDAG *DAG, bool force = false);
|
||||
|
@ -255,7 +265,7 @@ class SelectionDAG {
|
|||
/// Pool allocation for misc. objects that are created once per SelectionDAG.
|
||||
BumpPtrAllocator Allocator;
|
||||
|
||||
/// Tracks dbg_value information through SDISel.
|
||||
/// Tracks dbg_value and dbg_label information through SDISel.
|
||||
SDDbgInfo *DbgInfo;
|
||||
|
||||
uint16_t NextPersistentId = 0;
|
||||
|
@ -1247,6 +1257,9 @@ public:
|
|||
unsigned VReg, bool IsIndirect,
|
||||
const DebugLoc &DL, unsigned O);
|
||||
|
||||
/// Creates a SDDbgLabel node.
|
||||
SDDbgLabel *getDbgLabel(DILabel *Label, const DebugLoc &DL, unsigned O);
|
||||
|
||||
/// Transfer debug values from one node to another, while optionally
|
||||
/// generating fragment expressions for split-up values. If \p InvalidateDbg
|
||||
/// is set, debug values are invalidated after they are transferred.
|
||||
|
@ -1328,6 +1341,9 @@ public:
|
|||
/// value is produced by SD.
|
||||
void AddDbgValue(SDDbgValue *DB, SDNode *SD, bool isParameter);
|
||||
|
||||
/// Add a dbg_label SDNode.
|
||||
void AddDbgLabel(SDDbgLabel *DB);
|
||||
|
||||
/// Get the debug values which reference the given SDNode.
|
||||
ArrayRef<SDDbgValue*> GetDbgValues(const SDNode* SD) {
|
||||
return DbgInfo->getSDDbgValues(SD);
|
||||
|
@ -1349,6 +1365,13 @@ public:
|
|||
return DbgInfo->ByvalParmDbgEnd();
|
||||
}
|
||||
|
||||
SDDbgInfo::DbgLabelIterator DbgLabelBegin() {
|
||||
return DbgInfo->DbgLabelBegin();
|
||||
}
|
||||
SDDbgInfo::DbgLabelIterator DbgLabelEnd() {
|
||||
return DbgInfo->DbgLabelEnd();
|
||||
}
|
||||
|
||||
/// To be invoked on an SDNode that is slated to be erased. This
|
||||
/// function mirrors \c llvm::salvageDebugInfo.
|
||||
void salvageDebugInfo(SDNode &N);
|
||||
|
|
|
@ -77,6 +77,9 @@ HANDLE_TARGET_OPCODE(SUBREG_TO_REG)
|
|||
/// DBG_VALUE - a mapping of the llvm.dbg.value intrinsic
|
||||
HANDLE_TARGET_OPCODE(DBG_VALUE)
|
||||
|
||||
/// DBG_LABEL - a mapping of the llvm.dbg.label intrinsic
|
||||
HANDLE_TARGET_OPCODE(DBG_LABEL)
|
||||
|
||||
/// REG_SEQUENCE - This variadic instruction is used to form a register that
|
||||
/// represents a consecutive sequence of sub-registers. It's used as a
|
||||
/// register coalescing / allocation aid and must be eliminated before code
|
||||
|
|
|
@ -997,6 +997,12 @@ def DBG_VALUE : StandardPseudoInstruction {
|
|||
let AsmString = "DBG_VALUE";
|
||||
let hasSideEffects = 0;
|
||||
}
|
||||
def DBG_LABEL : StandardPseudoInstruction {
|
||||
let OutOperandList = (outs);
|
||||
let InOperandList = (ins unknown:$label);
|
||||
let AsmString = "DBG_LABEL";
|
||||
let hasSideEffects = 0;
|
||||
}
|
||||
def REG_SEQUENCE : StandardPseudoInstruction {
|
||||
let OutOperandList = (outs unknown:$dst);
|
||||
let InOperandList = (ins unknown:$supersrc, variable_ops);
|
||||
|
|
|
@ -911,6 +911,30 @@ static bool emitDebugValueComment(const MachineInstr *MI, AsmPrinter &AP) {
|
|||
return true;
|
||||
}
|
||||
|
||||
/// This method handles the target-independent form of DBG_LABEL, returning
|
||||
/// true if it was able to do so. A false return means the target will need
|
||||
/// to handle MI in EmitInstruction.
|
||||
static bool emitDebugLabelComment(const MachineInstr *MI, AsmPrinter &AP) {
|
||||
if (MI->getNumOperands() != 1)
|
||||
return false;
|
||||
|
||||
SmallString<128> Str;
|
||||
raw_svector_ostream OS(Str);
|
||||
OS << "DEBUG_LABEL: ";
|
||||
|
||||
const DILabel *V = MI->getDebugLabel();
|
||||
if (auto *SP = dyn_cast<DISubprogram>(V->getScope())) {
|
||||
StringRef Name = SP->getName();
|
||||
if (!Name.empty())
|
||||
OS << Name << ":";
|
||||
}
|
||||
OS << V->getName();
|
||||
|
||||
// NOTE: Want this comment at start of line, don't emit with AddComment.
|
||||
AP.OutStreamer->emitRawComment(OS.str());
|
||||
return true;
|
||||
}
|
||||
|
||||
AsmPrinter::CFIMoveType AsmPrinter::needsCFIMoves() const {
|
||||
if (MAI->getExceptionHandlingType() == ExceptionHandling::DwarfCFI &&
|
||||
MF->getFunction().needsUnwindTableEntry())
|
||||
|
@ -1074,6 +1098,12 @@ void AsmPrinter::EmitFunctionBody() {
|
|||
EmitInstruction(&MI);
|
||||
}
|
||||
break;
|
||||
case TargetOpcode::DBG_LABEL:
|
||||
if (isVerbose()) {
|
||||
if (!emitDebugLabelComment(&MI, *this))
|
||||
EmitInstruction(&MI);
|
||||
}
|
||||
break;
|
||||
case TargetOpcode::IMPLICIT_DEF:
|
||||
if (isVerbose()) emitImplicitDef(&MI);
|
||||
break;
|
||||
|
|
|
@ -613,6 +613,11 @@ int MachineInstr::findInlineAsmFlagIdx(unsigned OpIdx,
|
|||
return -1;
|
||||
}
|
||||
|
||||
const DILabel *MachineInstr::getDebugLabel() const {
|
||||
assert(isDebugLabel() && "not a DBG_LABEL");
|
||||
return cast<DILabel>(getOperand(0).getMetadata());
|
||||
}
|
||||
|
||||
const DILocalVariable *MachineInstr::getDebugVariable() const {
|
||||
assert(isDebugValue() && "not a DBG_VALUE");
|
||||
return cast<DILocalVariable>(getOperand(2).getMetadata());
|
||||
|
@ -1383,6 +1388,17 @@ void MachineInstr::print(raw_ostream &OS, ModuleSlotTracker &MST,
|
|||
MO.print(OS, MST, TypeToPrint, /*PrintDef=*/true, IsStandalone,
|
||||
ShouldPrintRegisterTies, TiedOperandIdx, TRI, IntrinsicInfo);
|
||||
}
|
||||
} else if (isDebugLabel() && MO.isMetadata()) {
|
||||
// Pretty print DBG_LABEL instructions.
|
||||
auto *DIL = dyn_cast<DILabel>(MO.getMetadata());
|
||||
if (DIL && !DIL->getName().empty())
|
||||
OS << "\"" << DIL->getName() << '\"';
|
||||
else {
|
||||
LLT TypeToPrint = MRI ? getTypeToPrint(i, PrintedTypes, *MRI) : LLT{};
|
||||
unsigned TiedOperandIdx = getTiedOperandIdx(i);
|
||||
MO.print(OS, MST, TypeToPrint, /*PrintDef=*/true, IsStandalone,
|
||||
ShouldPrintRegisterTies, TiedOperandIdx, TRI, IntrinsicInfo);
|
||||
}
|
||||
} else if (i == AsmDescOp && MO.isImm()) {
|
||||
// Pretty print the inline asm operand descriptor.
|
||||
OS << '$' << AsmOpCount++;
|
||||
|
|
|
@ -49,6 +49,7 @@ static bool doesNotGeneratecode(const MachineInstr &MI) {
|
|||
case TargetOpcode::EH_LABEL:
|
||||
case TargetOpcode::GC_LABEL:
|
||||
case TargetOpcode::DBG_VALUE:
|
||||
case TargetOpcode::DBG_LABEL:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -753,6 +753,20 @@ InstrEmitter::EmitDbgValue(SDDbgValue *SD,
|
|||
return &*MIB;
|
||||
}
|
||||
|
||||
MachineInstr *
|
||||
InstrEmitter::EmitDbgLabel(SDDbgLabel *SD) {
|
||||
MDNode *Label = SD->getLabel();
|
||||
DebugLoc DL = SD->getDebugLoc();
|
||||
assert(cast<DILabel>(Label)->isValidLocationForIntrinsic(DL) &&
|
||||
"Expected inlined-at fields to agree");
|
||||
|
||||
const MCInstrDesc &II = TII->get(TargetOpcode::DBG_LABEL);
|
||||
MachineInstrBuilder MIB = BuildMI(*MF, DL, II);
|
||||
MIB.addMetadata(Label);
|
||||
|
||||
return &*MIB;
|
||||
}
|
||||
|
||||
/// EmitMachineNode - Generate machine code for a target-specific node and
|
||||
/// needed dependencies.
|
||||
///
|
||||
|
|
|
@ -113,6 +113,9 @@ public:
|
|||
MachineInstr *EmitDbgValue(SDDbgValue *SD,
|
||||
DenseMap<SDValue, unsigned> &VRBaseMap);
|
||||
|
||||
/// Generate machine instruction for a dbg_label node.
|
||||
MachineInstr *EmitDbgLabel(SDDbgLabel *SD);
|
||||
|
||||
/// EmitNode - Generate machine code for a node and needed dependencies.
|
||||
///
|
||||
void EmitNode(SDNode *Node, bool IsClone, bool IsCloned,
|
||||
|
|
|
@ -128,6 +128,28 @@ public:
|
|||
bool isInvalidated() const { return Invalid; }
|
||||
};
|
||||
|
||||
/// Holds the information from a dbg_label node through SDISel.
|
||||
/// We do not use SDValue here to avoid including its header.
|
||||
class SDDbgLabel {
|
||||
MDNode *Label;
|
||||
DebugLoc DL;
|
||||
unsigned Order;
|
||||
|
||||
public:
|
||||
SDDbgLabel(MDNode *Label, DebugLoc dl, unsigned O)
|
||||
: Label(Label), DL(std::move(dl)), Order(O) {}
|
||||
|
||||
/// Returns the MDNode pointer for the label.
|
||||
MDNode *getLabel() const { return Label; }
|
||||
|
||||
/// Returns the DebugLoc.
|
||||
DebugLoc getDebugLoc() const { return DL; }
|
||||
|
||||
/// Returns the SDNodeOrder. This is the order of the preceding node in the
|
||||
/// input.
|
||||
unsigned getOrder() const { return Order; }
|
||||
};
|
||||
|
||||
} // end llvm namespace
|
||||
|
||||
#endif
|
||||
|
|
|
@ -911,6 +911,39 @@ EmitSchedule(MachineBasicBlock::iterator &InsertPos) {
|
|||
MachineBasicBlock *InsertBB = Emitter.getBlock();
|
||||
MachineBasicBlock::iterator Pos = InsertBB->getFirstTerminator();
|
||||
InsertBB->insert(Pos, DbgMIs.begin(), DbgMIs.end());
|
||||
|
||||
SDDbgInfo::DbgLabelIterator DLI = DAG->DbgLabelBegin();
|
||||
SDDbgInfo::DbgLabelIterator DLE = DAG->DbgLabelEnd();
|
||||
// Now emit the rest according to source order.
|
||||
LastOrder = 0;
|
||||
for (const auto &InstrOrder : Orders) {
|
||||
unsigned Order = InstrOrder.first;
|
||||
MachineInstr *MI = InstrOrder.second;
|
||||
if (!MI)
|
||||
continue;
|
||||
|
||||
// Insert all SDDbgLabel's whose order(s) are before "Order".
|
||||
for (; DLI != DLE &&
|
||||
(*DLI)->getOrder() >= LastOrder && (*DLI)->getOrder() < Order;
|
||||
++DLI) {
|
||||
MachineInstr *DbgMI = Emitter.EmitDbgLabel(*DLI);
|
||||
if (DbgMI) {
|
||||
if (!LastOrder)
|
||||
// Insert to start of the BB (after PHIs).
|
||||
BB->insert(BBBegin, DbgMI);
|
||||
else {
|
||||
// Insert at the instruction, which may be in a different
|
||||
// block, if the block was split by a custom inserter.
|
||||
MachineBasicBlock::iterator Pos = MI;
|
||||
MI->getParent()->insert(Pos, DbgMI);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (DLI == DLE)
|
||||
break;
|
||||
|
||||
LastOrder = Order;
|
||||
}
|
||||
}
|
||||
|
||||
InsertPos = Emitter.getInsertPos();
|
||||
|
|
|
@ -7420,6 +7420,14 @@ void SelectionDAG::salvageDebugInfo(SDNode &N) {
|
|||
AddDbgValue(Dbg, Dbg->getSDNode(), false);
|
||||
}
|
||||
|
||||
/// Creates a SDDbgLabel node.
|
||||
SDDbgLabel *SelectionDAG::getDbgLabel(DILabel *Label,
|
||||
const DebugLoc &DL, unsigned O) {
|
||||
assert(cast<DILabel>(Label)->isValidLocationForIntrinsic(DL) &&
|
||||
"Expected inlined-at fields to agree");
|
||||
return new (DbgInfo->getAlloc()) SDDbgLabel(Label, DL, O);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
/// RAUWUpdateListener - Helper for ReplaceAllUsesWith - When the node
|
||||
|
@ -7905,6 +7913,10 @@ void SelectionDAG::AddDbgValue(SDDbgValue *DB, SDNode *SD, bool isParameter) {
|
|||
DbgInfo->add(DB, SD, isParameter);
|
||||
}
|
||||
|
||||
void SelectionDAG::AddDbgLabel(SDDbgLabel *DB) {
|
||||
DbgInfo->add(DB);
|
||||
}
|
||||
|
||||
SDValue SelectionDAG::makeEquivalentMemoryOrdering(LoadSDNode *OldLoad,
|
||||
SDValue NewMemOp) {
|
||||
assert(isa<MemSDNode>(NewMemOp.getNode()) && "Expected a memop node");
|
||||
|
|
|
@ -5230,6 +5230,16 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) {
|
|||
}
|
||||
return nullptr;
|
||||
}
|
||||
case Intrinsic::dbg_label: {
|
||||
const DbgLabelInst &DI = cast<DbgLabelInst>(I);
|
||||
DILabel *Label = DI.getLabel();
|
||||
assert(Label && "Missing label");
|
||||
|
||||
SDDbgLabel *SDV;
|
||||
SDV = DAG.getDbgLabel(Label, dl, SDNodeOrder);
|
||||
DAG.AddDbgLabel(SDV);
|
||||
return nullptr;
|
||||
}
|
||||
case Intrinsic::dbg_value: {
|
||||
const DbgValueInst &DI = cast<DbgValueInst>(I);
|
||||
assert(DI.getVariable() && "Missing variable");
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
; Test DBG_LABEL MachineInstr for label debugging.
|
||||
; RUN: llc -fast-isel=false -debug-only=isel %s -o /dev/null 2> %t.debug
|
||||
; RUN: cat %t.debug | FileCheck %s --check-prefix=CHECKMI
|
||||
;
|
||||
; CHECKMI: DBG_LABEL "top", debug-location !9
|
||||
; CHECKMI: DBG_LABEL "done", debug-location !11
|
||||
;
|
||||
; RUN: llc -fast-isel=false %s -o - | FileCheck %s --check-prefix=CHECKASM
|
||||
;
|
||||
; CHECKASM: #DEBUG_LABEL: foo:top
|
||||
; CHECKASM: #DEBUG_LABEL: foo:done
|
||||
|
||||
source_filename = "debug-label-mi.c"
|
||||
|
||||
; Function Attrs: noinline nounwind optnone
|
||||
define i32 @foo(i32 signext %a, i32 signext %b) #0 !dbg !4 {
|
||||
entry:
|
||||
%a.addr = alloca i32, align 4
|
||||
%b.addr = alloca i32, align 4
|
||||
%sum = alloca i32, align 4
|
||||
store i32 %a, i32* %a.addr, align 4
|
||||
store i32 %b, i32* %b.addr, align 4
|
||||
br label %top
|
||||
|
||||
top: ; preds = %entry
|
||||
call void @llvm.dbg.label(metadata !8), !dbg !9
|
||||
%0 = load i32, i32* %a.addr, align 4
|
||||
%1 = load i32, i32* %b.addr, align 4
|
||||
%add = add nsw i32 %0, %1
|
||||
store i32 %add, i32* %sum, align 4
|
||||
br label %done
|
||||
|
||||
done: ; preds = %top
|
||||
call void @llvm.dbg.label(metadata !10), !dbg !11
|
||||
%2 = load i32, i32* %sum, align 4
|
||||
ret i32 %2
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind readnone speculatable
|
||||
declare void @llvm.dbg.label(metadata)
|
||||
|
||||
attributes #0 = { noinline nounwind optnone uwtable }
|
||||
|
||||
!llvm.dbg.cu = !{!0}
|
||||
!llvm.module.flags = !{!3}
|
||||
|
||||
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, isOptimized: false, emissionKind: FullDebug, enums: !2)
|
||||
!1 = !DIFile(filename: "debug-label-mi.c", directory: "./")
|
||||
!2 = !{}
|
||||
!3 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
!4 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !5, isLocal: false, isDefinition: true, scopeLine: 2, isOptimized: false, unit: !0, retainedNodes: !2)
|
||||
!5 = !DISubroutineType(types: !6)
|
||||
!6 = !{!7, !7, !7}
|
||||
!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
|
||||
!8 = !DILabel(scope: !4, name: "top", file: !1, line: 4)
|
||||
!9 = !DILocation(line: 4, column: 1, scope: !4)
|
||||
!10 = !DILabel(scope: !4, name: "done", file: !1, line: 7)
|
||||
!11 = !DILocation(line: 7, column: 1, scope: !4)
|
|
@ -0,0 +1,73 @@
|
|||
; Test DBG_LABEL MachineInstr under optimization.
|
||||
; The test case is generated by clang with -O2 is on.
|
||||
; RUN: llc -fast-isel=false -debug-only=isel %s -o /dev/null 2> %t.debug
|
||||
; RUN: cat %t.debug | FileCheck %s --check-prefix=CHECKMI
|
||||
;
|
||||
; CHECKMI: DBG_LABEL "end_sum", debug-location !18
|
||||
; CHECKMI: DBG_LABEL "end", debug-location !20
|
||||
source_filename = "debug-label-opt.c"
|
||||
|
||||
define i32 @foo(i32* nocapture readonly %a, i32 %n) local_unnamed_addr !dbg !7 {
|
||||
entry:
|
||||
call void @llvm.dbg.value(metadata i32* %a, metadata !13, metadata !DIExpression()), !dbg !6
|
||||
call void @llvm.dbg.value(metadata i32 %n, metadata !14, metadata !DIExpression()), !dbg !6
|
||||
call void @llvm.dbg.value(metadata i32 0, metadata !15, metadata !DIExpression()), !dbg !6
|
||||
switch i32 %n, label %end_sum [
|
||||
i32 2, label %end_sum.sink.split
|
||||
i32 3, label %if.then3
|
||||
], !dbg !6
|
||||
|
||||
if.then3: ; preds = %entry
|
||||
%arrayidx4 = getelementptr inbounds i32, i32* %a, i64 1, !dbg !6
|
||||
br label %end_sum.sink.split, !dbg !6
|
||||
|
||||
end_sum.sink.split: ; preds = %entry, %if.then3
|
||||
%a.sink = phi i32* [ %arrayidx4, %if.then3 ], [ %a, %entry ]
|
||||
%.sink = phi i64 [ 2, %if.then3 ], [ 1, %entry ]
|
||||
%0 = load i32, i32* %a.sink, align 4
|
||||
%arrayidx1 = getelementptr inbounds i32, i32* %a, i64 %.sink
|
||||
%1 = load i32, i32* %arrayidx1, align 4
|
||||
%add = add nsw i32 %1, %0
|
||||
br label %end_sum, !dbg !6
|
||||
|
||||
end_sum: ; preds = %end_sum.sink.split, %entry
|
||||
%sum.0 = phi i32 [ 0, %entry ], [ %add, %end_sum.sink.split ]
|
||||
call void @llvm.dbg.value(metadata i32 %sum.0, metadata !15, metadata !DIExpression()), !dbg !6
|
||||
call void @llvm.dbg.label(metadata !16), !dbg !18
|
||||
%2 = load i32, i32* %a, align 4, !dbg !6
|
||||
%mul = mul nsw i32 %2, %sum.0, !dbg !19
|
||||
call void @llvm.dbg.value(metadata i32 %mul, metadata !15, metadata !DIExpression()), !dbg !6
|
||||
call void @llvm.dbg.label(metadata !17), !dbg !20
|
||||
ret i32 %mul, !dbg !6
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind readnone speculatable
|
||||
declare void @llvm.dbg.label(metadata)
|
||||
|
||||
; Function Attrs: nounwind readnone speculatable
|
||||
declare void @llvm.dbg.value(metadata, metadata, metadata)
|
||||
|
||||
!llvm.dbg.cu = !{!0}
|
||||
!llvm.module.flags = !{!3, !4, !5}
|
||||
|
||||
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
|
||||
!1 = !DIFile(filename: "debug-label-opt.c", directory: "./")
|
||||
!2 = !{}
|
||||
!3 = !{i32 2, !"Dwarf Version", i32 4}
|
||||
!4 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
!5 = !{i32 1, !"wchar_size", i32 4}
|
||||
!6 = !DILocation(line: 1, column: 14, scope: !7)
|
||||
!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !8, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !12)
|
||||
!8 = !DISubroutineType(types: !9)
|
||||
!9 = !{!10, !11, !10}
|
||||
!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
|
||||
!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !10, size: 64)
|
||||
!12 = !{!13, !14, !15, !16, !17}
|
||||
!13 = !DILocalVariable(name: "a", arg: 1, scope: !7, file: !1, line: 1, type: !11)
|
||||
!14 = !DILocalVariable(name: "n", arg: 2, scope: !7, file: !1, line: 1, type: !10)
|
||||
!15 = !DILocalVariable(name: "sum", scope: !7, file: !1, line: 3, type: !10)
|
||||
!16 = !DILabel(scope: !7, name: "end_sum", file: !1, line: 10)
|
||||
!17 = !DILabel(scope: !7, name: "end", file: !1, line: 13)
|
||||
!18 = !DILocation(line: 10, column: 1, scope: !7)
|
||||
!19 = !DILocation(line: 11, column: 7, scope: !7)
|
||||
!20 = !DILocation(line: 13, column: 1, scope: !7)
|
Loading…
Reference in New Issue