Skip to content

Commit

Permalink
[DebugInfo] Convert intrinsic llvm.dbg.label to MachineInstr.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
ShivaChen committed May 9, 2018
1 parent 2c86455 commit cd070cd
Show file tree
Hide file tree
Showing 15 changed files with 313 additions and 2 deletions.
7 changes: 7 additions & 0 deletions llvm/include/llvm/CodeGen/MachineInstr.h
Expand Up @@ -292,6 +292,10 @@ class MachineInstr
/// 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
Expand Down Expand Up @@ -831,6 +835,8 @@ class MachineInstr
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.
Expand Down Expand Up @@ -907,6 +913,7 @@ class MachineInstr
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;
Expand Down
27 changes: 25 additions & 2 deletions llvm/include/llvm/CodeGen/SelectionDAG.h
Expand Up @@ -73,6 +73,7 @@ class MachineConstantPoolValue;
class MCSymbol;
class OptimizationRemarkEmitter;
class SDDbgValue;
class SDDbgLabel;
class SelectionDAG;
class SelectionDAGTargetInfo;
class TargetLibraryInfo;
Expand Down Expand Up @@ -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;

Expand All @@ -164,6 +166,10 @@ class SDDbgInfo {
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);
Expand All @@ -172,13 +178,14 @@ class SDDbgInfo {
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) {
Expand All @@ -189,11 +196,14 @@ class SDDbgInfo {
}

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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -1247,6 +1257,9 @@ class SelectionDAG {
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.
Expand Down Expand Up @@ -1328,6 +1341,9 @@ class SelectionDAG {
/// 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);
Expand All @@ -1349,6 +1365,13 @@ class SelectionDAG {
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);
Expand Down
3 changes: 3 additions & 0 deletions llvm/include/llvm/Support/TargetOpcodes.def
Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions llvm/include/llvm/Target/Target.td
Expand Up @@ -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);
Expand Down
30 changes: 30 additions & 0 deletions llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
Expand Up @@ -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())
Expand Down Expand Up @@ -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;
Expand Down
16 changes: 16 additions & 0 deletions llvm/lib/CodeGen/MachineInstr.cpp
Expand Up @@ -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());
Expand Down Expand Up @@ -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++;
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/CodeGen/PatchableFunction.cpp
Expand Up @@ -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;
}
}
Expand Down
14 changes: 14 additions & 0 deletions llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp
Expand Up @@ -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.
///
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/CodeGen/SelectionDAG/InstrEmitter.h
Expand Up @@ -113,6 +113,9 @@ class LLVM_LIBRARY_VISIBILITY InstrEmitter {
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,
Expand Down
22 changes: 22 additions & 0 deletions llvm/lib/CodeGen/SelectionDAG/SDNodeDbgValue.h
Expand Up @@ -128,6 +128,28 @@ class SDDbgValue {
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
33 changes: 33 additions & 0 deletions llvm/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp
Expand Up @@ -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();
Expand Down
12 changes: 12 additions & 0 deletions llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
Expand Up @@ -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
Expand Down Expand Up @@ -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");
Expand Down
10 changes: 10 additions & 0 deletions llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
Expand Up @@ -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");
Expand Down

0 comments on commit cd070cd

Please sign in to comment.