mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-24 19:52:54 +01:00
[Debugify] Support checking Machine IR debug info
Add mir-check-debug pass to check MIR-level debug info. For IR-level, currently, LLVM have debugify + check-debugify to generate and check debug IR. Much like the IR-level pass debugify, mir-debugify inserts sequentially increasing line locations to each MachineInstr in a Module, But there is no equivalent MIR-level check-debugify pass, So now we support it at "mir-check-debug". Reviewed By: djtodoro Differential Revision: https://reviews.llvm.org/D91595
This commit is contained in:
parent
f195aa7b4b
commit
7ce08bafea
@ -342,8 +342,8 @@ A variant of the ``debugify`` utility described in
|
||||
:ref:`Mutation testing for IR-level transformations<IRDebugify>` can be used
|
||||
for MIR-level transformations as well: much like the IR-level pass,
|
||||
``mir-debugify`` inserts sequentially increasing line locations to each
|
||||
``MachineInstr`` in a ``Module`` (although there is no equivalent MIR-level
|
||||
``check-debugify`` pass).
|
||||
``MachineInstr`` in a ``Module``. And the MIR-level ``mir-check-debugify`` is
|
||||
similar to IR-level ``check-debugify`` pass.
|
||||
|
||||
For example, here is a snippet before:
|
||||
|
||||
@ -403,16 +403,32 @@ and ``-start-after``. For example:
|
||||
$ llc -debugify-and-strip-all-safe -run-pass=... <other llc args>
|
||||
$ llc -debugify-and-strip-all-safe -O1 <other llc args>
|
||||
|
||||
If you want to check it after each pass in a pipeline, use
|
||||
``-debugify-check-and-strip-all-safe``. This can also be combined with
|
||||
``-start-before`` and ``-start-after``. For example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ llc -debugify-check-and-strip-all-safe -run-pass=... <other llc args>
|
||||
$ llc -debugify-check-and-strip-all-safe -O1 <other llc args>
|
||||
|
||||
To check all debug info from a test, use ``mir-check-debugify``, like:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ llc -run-pass=mir-debugify,other-pass,mir-check-debugify
|
||||
|
||||
To strip out all debug info from a test, use ``mir-strip-debug``, like:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ llc -run-pass=mir-debugify,other-pass,mir-strip-debug
|
||||
|
||||
It can be useful to combine ``mir-debugify`` and ``mir-strip-debug`` to
|
||||
identify backend transformations which break in the presence of debug info.
|
||||
For example, to run the AArch64 backend tests with all normal passes
|
||||
"sandwiched" in between MIRDebugify and MIRStripDebugify mutation passes, run:
|
||||
It can be useful to combine ``mir-debugify``, ``mir-check-debugify`` and/or
|
||||
``mir-strip-debug`` to identify backend transformations which break in
|
||||
the presence of debug info. For example, to run the AArch64 backend tests
|
||||
with all normal passes "sandwiched" in between MIRDebugify and
|
||||
MIRStripDebugify mutation passes, run:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
|
@ -482,6 +482,9 @@ namespace llvm {
|
||||
/// info was generated by another source such as clang.
|
||||
ModulePass *createStripDebugMachineModulePass(bool OnlyDebugified);
|
||||
|
||||
/// Creates MIR Check Debug pass. \see MachineCheckDebugify.cpp
|
||||
ModulePass *createCheckDebugMachineModulePass();
|
||||
|
||||
/// The pass fixups statepoint machine instruction to replace usage of
|
||||
/// caller saved registers with stack slots.
|
||||
extern char &FixupStatepointCallerSavedID;
|
||||
|
@ -313,6 +313,9 @@ public:
|
||||
/// Add a pass to remove debug info from the MIR.
|
||||
void addStripDebugPass();
|
||||
|
||||
/// Add a pass to check synthesized debug info for MIR.
|
||||
void addCheckDebugPass();
|
||||
|
||||
/// Add standard passes before a pass that's about to be added. For example,
|
||||
/// the DebugifyMachineModulePass if it is enabled.
|
||||
void addMachinePrePasses(bool AllowDebugify = true);
|
||||
|
@ -112,6 +112,7 @@ void initializeCallGraphViewerPass(PassRegistry&);
|
||||
void initializeCallGraphWrapperPassPass(PassRegistry&);
|
||||
void initializeCallSiteSplittingLegacyPassPass(PassRegistry&);
|
||||
void initializeCalledValuePropagationLegacyPassPass(PassRegistry &);
|
||||
void initializeCheckDebugMachineModulePass(PassRegistry &);
|
||||
void initializeCodeGenPreparePass(PassRegistry&);
|
||||
void initializeConstantHoistingLegacyPassPass(PassRegistry&);
|
||||
void initializeConstantMergeLegacyPassPass(PassRegistry&);
|
||||
|
@ -74,6 +74,7 @@ add_llvm_component_library(LLVMCodeGen
|
||||
MachineCombiner.cpp
|
||||
MachineCopyPropagation.cpp
|
||||
MachineCSE.cpp
|
||||
MachineCheckDebugify.cpp
|
||||
MachineDebugify.cpp
|
||||
MachineDominanceFrontier.cpp
|
||||
MachineDominators.cpp
|
||||
|
@ -25,6 +25,7 @@ void llvm::initializeCodeGen(PassRegistry &Registry) {
|
||||
initializeBranchRelaxationPass(Registry);
|
||||
initializeCFGuardLongjmpPass(Registry);
|
||||
initializeCFIInstrInserterPass(Registry);
|
||||
initializeCheckDebugMachineModulePass(Registry);
|
||||
initializeCodeGenPreparePass(Registry);
|
||||
initializeDeadMachineInstructionElimPass(Registry);
|
||||
initializeDebugifyMachineModulePass(Registry);
|
||||
|
126
lib/CodeGen/MachineCheckDebugify.cpp
Normal file
126
lib/CodeGen/MachineCheckDebugify.cpp
Normal file
@ -0,0 +1,126 @@
|
||||
//===- MachineCheckDebugify.cpp - Check debug info ------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file This checks debug info after mir-debugify (+ pass-to-test). Currently
|
||||
/// it simply checks the integrity of line info in DILocation and
|
||||
/// DILocalVariable which mir-debugifiy generated before.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/MachineModuleInfo.h"
|
||||
#include "llvm/CodeGen/Passes.h"
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
#include "llvm/InitializePasses.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Transforms/Utils/Debugify.h"
|
||||
|
||||
#define DEBUG_TYPE "mir-check-debugify"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
struct CheckDebugMachineModule : public ModulePass {
|
||||
bool runOnModule(Module &M) override {
|
||||
MachineModuleInfo &MMI =
|
||||
getAnalysis<MachineModuleInfoWrapperPass>().getMMI();
|
||||
|
||||
NamedMDNode *NMD = M.getNamedMetadata("llvm.mir.debugify");
|
||||
if (!NMD) {
|
||||
errs() << "WARNING: Please run mir-debugify to generate "
|
||||
"llvm.mir.debugify metadata first.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto getDebugifyOperand = [&](unsigned Idx) -> unsigned {
|
||||
return mdconst::extract<ConstantInt>(NMD->getOperand(Idx)->getOperand(0))
|
||||
->getZExtValue();
|
||||
};
|
||||
assert(NMD->getNumOperands() == 2 &&
|
||||
"llvm.mir.debugify should have exactly 2 operands!");
|
||||
unsigned NumLines = getDebugifyOperand(0);
|
||||
unsigned NumVars = getDebugifyOperand(1);
|
||||
BitVector MissingLines{NumLines, true};
|
||||
BitVector MissingVars{NumVars, true};
|
||||
|
||||
for (Function &F : M.functions()) {
|
||||
MachineFunction *MF = MMI.getMachineFunction(F);
|
||||
if (!MF)
|
||||
continue;
|
||||
for (MachineBasicBlock &MBB : *MF) {
|
||||
// Find missing lines.
|
||||
// TODO: Avoid meta instructions other than dbg_val.
|
||||
for (MachineInstr &MI : MBB) {
|
||||
if (MI.isDebugValue())
|
||||
continue;
|
||||
const DebugLoc DL = MI.getDebugLoc();
|
||||
if (DL && DL.getLine() != 0) {
|
||||
MissingLines.reset(DL.getLine() - 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!DL) {
|
||||
errs() << "WARNING: Instruction with empty DebugLoc in function ";
|
||||
errs() << F.getName() << " --";
|
||||
MI.print(errs());
|
||||
}
|
||||
}
|
||||
|
||||
// Find missing variables.
|
||||
// TODO: Handle DBG_INSTR_REF which is under an experimental option now.
|
||||
for (MachineInstr &MI : MBB) {
|
||||
if (!MI.isDebugValue())
|
||||
continue;
|
||||
const DILocalVariable *LocalVar = MI.getDebugVariable();
|
||||
unsigned Var = ~0U;
|
||||
|
||||
(void)to_integer(LocalVar->getName(), Var, 10);
|
||||
assert(Var <= NumVars && "Unexpected name for DILocalVariable");
|
||||
MissingVars.reset(Var - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Fail = false;
|
||||
for (unsigned Idx : MissingLines.set_bits()) {
|
||||
errs() << "WARNING: Missing line " << Idx + 1 << "\n";
|
||||
Fail = true;
|
||||
}
|
||||
|
||||
for (unsigned Idx : MissingVars.set_bits()) {
|
||||
errs() << "WARNING: Missing variable " << Idx + 1 << "\n";
|
||||
Fail = true;
|
||||
}
|
||||
errs() << "Machine IR debug info check: ";
|
||||
errs() << (Fail ? "FAIL" : "PASS") << "\n";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
CheckDebugMachineModule() : ModulePass(ID) {}
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||
AU.addRequired<MachineModuleInfoWrapperPass>();
|
||||
AU.addPreserved<MachineModuleInfoWrapperPass>();
|
||||
AU.setPreservesCFG();
|
||||
}
|
||||
|
||||
static char ID; // Pass identification.
|
||||
};
|
||||
char CheckDebugMachineModule::ID = 0;
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
INITIALIZE_PASS_BEGIN(CheckDebugMachineModule, DEBUG_TYPE,
|
||||
"Machine Check Debug Module", false, false)
|
||||
INITIALIZE_PASS_END(CheckDebugMachineModule, DEBUG_TYPE,
|
||||
"Machine Check Debug Module", false, false)
|
||||
|
||||
ModulePass *llvm::createCheckDebugMachineModulePass() {
|
||||
return new CheckDebugMachineModule();
|
||||
}
|
@ -14,6 +14,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
@ -89,10 +90,11 @@ bool applyDebugifyMetadataToMachineFunction(MachineModuleInfo &MMI,
|
||||
// Do this by introducing debug uses of each register definition. If that is
|
||||
// not possible (e.g. we have a phi or a meta instruction), emit a constant.
|
||||
uint64_t NextImm = 0;
|
||||
SmallSet<DILocalVariable *, 16> VarSet;
|
||||
const MCInstrDesc &DbgValDesc = TII.get(TargetOpcode::DBG_VALUE);
|
||||
for (MachineBasicBlock &MBB : MF) {
|
||||
MachineBasicBlock::iterator FirstNonPHIIt = MBB.getFirstNonPHI();
|
||||
for (auto I = MBB.begin(), E = MBB.end(); I != E; ) {
|
||||
for (auto I = MBB.begin(), E = MBB.end(); I != E;) {
|
||||
MachineInstr &MI = *I;
|
||||
++I;
|
||||
|
||||
@ -113,6 +115,7 @@ bool applyDebugifyMetadataToMachineFunction(MachineModuleInfo &MMI,
|
||||
Line = EarliestDVI->getDebugLoc().getLine();
|
||||
DILocalVariable *LocalVar = Line2Var[Line];
|
||||
assert(LocalVar && "No variable for current line?");
|
||||
VarSet.insert(LocalVar);
|
||||
|
||||
// Emit DBG_VALUEs for register definitions.
|
||||
SmallVector<MachineOperand *, 4> RegDefs;
|
||||
@ -132,6 +135,33 @@ bool applyDebugifyMetadataToMachineFunction(MachineModuleInfo &MMI,
|
||||
}
|
||||
}
|
||||
|
||||
// Here we save the number of lines and variables into "llvm.mir.debugify".
|
||||
// It is useful for mir-check-debugify.
|
||||
NamedMDNode *NMD = M.getNamedMetadata("llvm.mir.debugify");
|
||||
IntegerType *Int32Ty = Type::getInt32Ty(Ctx);
|
||||
if (!NMD) {
|
||||
NMD = M.getOrInsertNamedMetadata("llvm.mir.debugify");
|
||||
auto addDebugifyOperand = [&](unsigned N) {
|
||||
NMD->addOperand(MDNode::get(
|
||||
Ctx, ValueAsMetadata::getConstant(ConstantInt::get(Int32Ty, N))));
|
||||
};
|
||||
// Add number of lines.
|
||||
addDebugifyOperand(NextLine - 1);
|
||||
// Add number of variables.
|
||||
addDebugifyOperand(VarSet.size());
|
||||
} else {
|
||||
assert(NMD->getNumOperands() == 2 &&
|
||||
"llvm.mir.debugify should have exactly 2 operands!");
|
||||
auto setDebugifyOperand = [&](unsigned Idx, unsigned N) {
|
||||
NMD->setOperand(Idx, MDNode::get(Ctx, ValueAsMetadata::getConstant(
|
||||
ConstantInt::get(Int32Ty, N))));
|
||||
};
|
||||
// Set number of lines.
|
||||
setDebugifyOperand(0, NextLine - 1);
|
||||
// Set number of variables.
|
||||
setDebugifyOperand(1, VarSet.size());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -120,6 +120,12 @@ static cl::opt<cl::boolOrDefault> DebugifyAndStripAll(
|
||||
"Debugify MIR before and Strip debug after "
|
||||
"each pass except those known to be unsafe when debug info is present"),
|
||||
cl::ZeroOrMore);
|
||||
static cl::opt<cl::boolOrDefault> DebugifyCheckAndStripAll(
|
||||
"debugify-check-and-strip-all-safe", cl::Hidden,
|
||||
cl::desc(
|
||||
"Debugify MIR before, by checking and stripping the debug info after, "
|
||||
"each pass except those known to be unsafe when debug info is present"),
|
||||
cl::ZeroOrMore);
|
||||
enum RunOutliner { AlwaysOutline, NeverOutline, TargetDefault };
|
||||
// Enable or disable the MachineOutliner.
|
||||
static cl::opt<RunOutliner> EnableMachineOutliner(
|
||||
@ -625,15 +631,26 @@ void TargetPassConfig::addStripDebugPass() {
|
||||
PM->add(createStripDebugMachineModulePass(/*OnlyDebugified=*/true));
|
||||
}
|
||||
|
||||
void TargetPassConfig::addCheckDebugPass() {
|
||||
PM->add(createCheckDebugMachineModulePass());
|
||||
}
|
||||
|
||||
void TargetPassConfig::addMachinePrePasses(bool AllowDebugify) {
|
||||
if (AllowDebugify && DebugifyAndStripAll == cl::BOU_TRUE && DebugifyIsSafe)
|
||||
if (AllowDebugify && DebugifyIsSafe &&
|
||||
(DebugifyAndStripAll == cl::BOU_TRUE ||
|
||||
DebugifyCheckAndStripAll == cl::BOU_TRUE))
|
||||
addDebugifyPass();
|
||||
}
|
||||
|
||||
void TargetPassConfig::addMachinePostPasses(const std::string &Banner,
|
||||
bool AllowVerify, bool AllowStrip) {
|
||||
if (DebugifyAndStripAll == cl::BOU_TRUE && DebugifyIsSafe)
|
||||
addStripDebugPass();
|
||||
if (DebugifyIsSafe) {
|
||||
if (DebugifyCheckAndStripAll == cl::BOU_TRUE) {
|
||||
addCheckDebugPass();
|
||||
addStripDebugPass();
|
||||
} else if (DebugifyAndStripAll == cl::BOU_TRUE)
|
||||
addStripDebugPass();
|
||||
}
|
||||
if (AllowVerify)
|
||||
addVerifyPass(Banner);
|
||||
}
|
||||
|
@ -13,17 +13,17 @@ body: |
|
||||
liveins: $x0
|
||||
; CHECK-LABEL: name: fconstant_to_constant_s32
|
||||
; CHECK: liveins: $x0
|
||||
; CHECK: [[COPY:%[0-9]+]]:_(p0) = COPY $x0, debug-location !10
|
||||
; CHECK: DBG_VALUE [[COPY]](p0), $noreg, !8, !DIExpression(), debug-location !10
|
||||
; CHECK: [[C:%[0-9]+]]:_(s32) = G_FCONSTANT float 0x3FA99999A0000000, debug-location !DILocation(line: 2, column: 1, scope: !5)
|
||||
; CHECK: DBG_VALUE [[C]](s32), $noreg, !8, !DIExpression(), debug-location !DILocation(line: 2, column: 1, scope: !5)
|
||||
; CHECK: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 524, debug-location !DILocation(line: 3, column: 1, scope: !5)
|
||||
; CHECK: DBG_VALUE [[C1]](s64), $noreg, !8, !DIExpression(), debug-location !DILocation(line: 3, column: 1, scope: !5)
|
||||
; CHECK: [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY]], [[C1]](s64), debug-location !DILocation(line: 4, column: 1, scope: !5)
|
||||
; CHECK: DBG_VALUE [[PTR_ADD]](p0), $noreg, !8, !DIExpression(), debug-location !DILocation(line: 4, column: 1, scope: !5)
|
||||
; CHECK: G_STORE [[C]](s32), [[PTR_ADD]](p0), debug-location !DILocation(line: 5, column: 1, scope: !5) :: (store 4)
|
||||
; CHECK: DBG_VALUE 0, $noreg, !8, !DIExpression(), debug-location !DILocation(line: 5, column: 1, scope: !5)
|
||||
; CHECK: RET_ReallyLR debug-location !DILocation(line: 6, column: 1, scope: !5)
|
||||
; CHECK: [[COPY:%[0-9]+]]:_(p0) = COPY $x0, debug-location !11
|
||||
; CHECK: DBG_VALUE [[COPY]](p0), $noreg, !9, !DIExpression(), debug-location !11
|
||||
; CHECK: [[C:%[0-9]+]]:_(s32) = G_FCONSTANT float 0x3FA99999A0000000, debug-location !DILocation(line: 2, column: 1, scope: !6)
|
||||
; CHECK: DBG_VALUE [[C]](s32), $noreg, !9, !DIExpression(), debug-location !DILocation(line: 2, column: 1, scope: !6)
|
||||
; CHECK: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 524, debug-location !DILocation(line: 3, column: 1, scope: !6)
|
||||
; CHECK: DBG_VALUE [[C1]](s64), $noreg, !9, !DIExpression(), debug-location !DILocation(line: 3, column: 1, scope: !6)
|
||||
; CHECK: [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY]], [[C1]](s64), debug-location !DILocation(line: 4, column: 1, scope: !6)
|
||||
; CHECK: DBG_VALUE [[PTR_ADD]](p0), $noreg, !9, !DIExpression(), debug-location !DILocation(line: 4, column: 1, scope: !6)
|
||||
; CHECK: G_STORE [[C]](s32), [[PTR_ADD]](p0), debug-location !DILocation(line: 5, column: 1, scope: !6) :: (store 4)
|
||||
; CHECK: DBG_VALUE 0, $noreg, !9, !DIExpression(), debug-location !DILocation(line: 5, column: 1, scope: !6)
|
||||
; CHECK: RET_ReallyLR debug-location !DILocation(line: 6, column: 1, scope: !6)
|
||||
%0:_(p0) = COPY $x0
|
||||
%3:_(s32) = G_FCONSTANT float 0x3FA99999A0000000
|
||||
%1:_(s64) = G_CONSTANT i64 524
|
||||
|
@ -36,41 +36,41 @@ body: |
|
||||
; CHECK: bb.0:
|
||||
; CHECK: successors: %bb.1(0x40000000), %bb.2(0x40000000)
|
||||
; CHECK: liveins: $w0
|
||||
; CHECK: [[COPY:%[0-9]+]]:_(s32) = COPY $w0, debug-location !10
|
||||
; CHECK: DBG_VALUE [[COPY]](s32), $noreg, !8, !DIExpression(), debug-location !10
|
||||
; CHECK: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0, debug-location !DILocation(line: 2, column: 1, scope: !5)
|
||||
; CHECK: DBG_VALUE [[C]](s32), $noreg, !8, !DIExpression(), debug-location !DILocation(line: 2, column: 1, scope: !5)
|
||||
; CHECK: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 1, debug-location !DILocation(line: 3, column: 1, scope: !5)
|
||||
; CHECK: DBG_VALUE [[C1]](s32), $noreg, !8, !DIExpression(), debug-location !DILocation(line: 3, column: 1, scope: !5)
|
||||
; CHECK: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 2, debug-location !DILocation(line: 4, column: 1, scope: !5)
|
||||
; CHECK: DBG_VALUE [[C2]](s32), $noreg, !8, !DIExpression(), debug-location !DILocation(line: 4, column: 1, scope: !5)
|
||||
; CHECK: [[ICMP:%[0-9]+]]:_(s1) = G_ICMP intpred(ugt), [[COPY]](s32), [[C]], debug-location !DILocation(line: 5, column: 1, scope: !5)
|
||||
; CHECK: DBG_VALUE [[ICMP]](s1), $noreg, !8, !DIExpression(), debug-location !DILocation(line: 5, column: 1, scope: !5)
|
||||
; CHECK: G_BRCOND [[ICMP]](s1), %bb.1, debug-location !DILocation(line: 6, column: 1, scope: !5)
|
||||
; CHECK: G_BR %bb.2, debug-location !DILocation(line: 7, column: 1, scope: !5)
|
||||
; CHECK: [[COPY:%[0-9]+]]:_(s32) = COPY $w0, debug-location !11
|
||||
; CHECK: DBG_VALUE [[COPY]](s32), $noreg, !9, !DIExpression(), debug-location !11
|
||||
; CHECK: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0, debug-location !DILocation(line: 2, column: 1, scope: !6)
|
||||
; CHECK: DBG_VALUE [[C]](s32), $noreg, !9, !DIExpression(), debug-location !DILocation(line: 2, column: 1, scope: !6)
|
||||
; CHECK: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 1, debug-location !DILocation(line: 3, column: 1, scope: !6)
|
||||
; CHECK: DBG_VALUE [[C1]](s32), $noreg, !9, !DIExpression(), debug-location !DILocation(line: 3, column: 1, scope: !6)
|
||||
; CHECK: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 2, debug-location !DILocation(line: 4, column: 1, scope: !6)
|
||||
; CHECK: DBG_VALUE [[C2]](s32), $noreg, !9, !DIExpression(), debug-location !DILocation(line: 4, column: 1, scope: !6)
|
||||
; CHECK: [[ICMP:%[0-9]+]]:_(s1) = G_ICMP intpred(ugt), [[COPY]](s32), [[C]], debug-location !DILocation(line: 5, column: 1, scope: !6)
|
||||
; CHECK: DBG_VALUE [[ICMP]](s1), $noreg, !9, !DIExpression(), debug-location !DILocation(line: 5, column: 1, scope: !6)
|
||||
; CHECK: G_BRCOND [[ICMP]](s1), %bb.1, debug-location !DILocation(line: 6, column: 1, scope: !6)
|
||||
; CHECK: G_BR %bb.2, debug-location !DILocation(line: 7, column: 1, scope: !6)
|
||||
; CHECK: bb.1:
|
||||
; CHECK: successors: %bb.3(0x80000000)
|
||||
; CHECK: [[ADD:%[0-9]+]]:_(s32) = G_ADD [[COPY]], [[C1]], debug-location !DILocation(line: 8, column: 1, scope: !5)
|
||||
; CHECK: DBG_VALUE [[ADD]](s32), $noreg, !8, !DIExpression(), debug-location !DILocation(line: 8, column: 1, scope: !5)
|
||||
; CHECK: [[TRUNC:%[0-9]+]]:_(s1) = G_TRUNC [[ADD]](s32), debug-location !DILocation(line: 9, column: 1, scope: !5)
|
||||
; CHECK: DBG_VALUE [[TRUNC]](s1), $noreg, !8, !DIExpression(), debug-location !DILocation(line: 9, column: 1, scope: !5)
|
||||
; CHECK: G_BR %bb.3, debug-location !DILocation(line: 10, column: 1, scope: !5)
|
||||
; CHECK: [[ADD:%[0-9]+]]:_(s32) = G_ADD [[COPY]], [[C1]], debug-location !DILocation(line: 8, column: 1, scope: !6)
|
||||
; CHECK: DBG_VALUE [[ADD]](s32), $noreg, !9, !DIExpression(), debug-location !DILocation(line: 8, column: 1, scope: !6)
|
||||
; CHECK: [[TRUNC:%[0-9]+]]:_(s1) = G_TRUNC [[ADD]](s32), debug-location !DILocation(line: 9, column: 1, scope: !6)
|
||||
; CHECK: DBG_VALUE [[TRUNC]](s1), $noreg, !9, !DIExpression(), debug-location !DILocation(line: 9, column: 1, scope: !6)
|
||||
; CHECK: G_BR %bb.3, debug-location !DILocation(line: 10, column: 1, scope: !6)
|
||||
; CHECK: bb.2:
|
||||
; CHECK: successors: %bb.3(0x80000000)
|
||||
; CHECK: [[ADD1:%[0-9]+]]:_(s32) = G_ADD [[COPY]], [[C2]], debug-location !DILocation(line: 11, column: 1, scope: !5)
|
||||
; CHECK: DBG_VALUE [[ADD1]](s32), $noreg, !8, !DIExpression(), debug-location !DILocation(line: 11, column: 1, scope: !5)
|
||||
; CHECK: [[TRUNC1:%[0-9]+]]:_(s1) = G_TRUNC [[ADD1]](s32), debug-location !DILocation(line: 12, column: 1, scope: !5)
|
||||
; CHECK: DBG_VALUE [[TRUNC1]](s1), $noreg, !8, !DIExpression(), debug-location !DILocation(line: 12, column: 1, scope: !5)
|
||||
; CHECK: [[ADD1:%[0-9]+]]:_(s32) = G_ADD [[COPY]], [[C2]], debug-location !DILocation(line: 11, column: 1, scope: !6)
|
||||
; CHECK: DBG_VALUE [[ADD1]](s32), $noreg, !9, !DIExpression(), debug-location !DILocation(line: 11, column: 1, scope: !6)
|
||||
; CHECK: [[TRUNC1:%[0-9]+]]:_(s1) = G_TRUNC [[ADD1]](s32), debug-location !DILocation(line: 12, column: 1, scope: !6)
|
||||
; CHECK: DBG_VALUE [[TRUNC1]](s1), $noreg, !9, !DIExpression(), debug-location !DILocation(line: 12, column: 1, scope: !6)
|
||||
; CHECK: bb.3:
|
||||
; CHECK: [[PHI:%[0-9]+]]:_(s1) = G_PHI [[TRUNC]](s1), %bb.1, [[TRUNC1]](s1), %bb.2, debug-location !DILocation(line: 13, column: 1, scope: !5)
|
||||
; CHECK: [[PHI1:%[0-9]+]]:_(s1) = G_PHI [[TRUNC]](s1), %bb.1, [[TRUNC1]](s1), %bb.2, debug-location !DILocation(line: 14, column: 1, scope: !5)
|
||||
; CHECK: DBG_VALUE [[PHI]](s1), $noreg, !8, !DIExpression(), debug-location !DILocation(line: 13, column: 1, scope: !5)
|
||||
; CHECK: DBG_VALUE [[PHI1]](s1), $noreg, !8, !DIExpression(), debug-location !DILocation(line: 14, column: 1, scope: !5)
|
||||
; CHECK: [[ZEXT:%[0-9]+]]:_(s32) = G_ZEXT [[PHI]](s1), debug-location !DILocation(line: 15, column: 1, scope: !5)
|
||||
; CHECK: DBG_VALUE [[ZEXT]](s32), $noreg, !8, !DIExpression(), debug-location !DILocation(line: 15, column: 1, scope: !5)
|
||||
; CHECK: $w0 = COPY [[ZEXT]](s32), debug-location !DILocation(line: 16, column: 1, scope: !5)
|
||||
; CHECK: DBG_VALUE $w0, $noreg, !8, !DIExpression(), debug-location !DILocation(line: 16, column: 1, scope: !5)
|
||||
; CHECK: RET_ReallyLR implicit $w0, debug-location !DILocation(line: 17, column: 1, scope: !5)
|
||||
; CHECK: [[PHI:%[0-9]+]]:_(s1) = G_PHI [[TRUNC]](s1), %bb.1, [[TRUNC1]](s1), %bb.2, debug-location !DILocation(line: 13, column: 1, scope: !6)
|
||||
; CHECK: [[PHI1:%[0-9]+]]:_(s1) = G_PHI [[TRUNC]](s1), %bb.1, [[TRUNC1]](s1), %bb.2, debug-location !DILocation(line: 14, column: 1, scope: !6)
|
||||
; CHECK: DBG_VALUE [[PHI]](s1), $noreg, !9, !DIExpression(), debug-location !DILocation(line: 13, column: 1, scope: !6)
|
||||
; CHECK: DBG_VALUE [[PHI1]](s1), $noreg, !9, !DIExpression(), debug-location !DILocation(line: 14, column: 1, scope: !6)
|
||||
; CHECK: [[ZEXT:%[0-9]+]]:_(s32) = G_ZEXT [[PHI]](s1), debug-location !DILocation(line: 15, column: 1, scope: !6)
|
||||
; CHECK: DBG_VALUE [[ZEXT]](s32), $noreg, !9, !DIExpression(), debug-location !DILocation(line: 15, column: 1, scope: !6)
|
||||
; CHECK: $w0 = COPY [[ZEXT]](s32), debug-location !DILocation(line: 16, column: 1, scope: !6)
|
||||
; CHECK: DBG_VALUE $w0, $noreg, !9, !DIExpression(), debug-location !DILocation(line: 16, column: 1, scope: !6)
|
||||
; CHECK: RET_ReallyLR implicit $w0, debug-location !DILocation(line: 17, column: 1, scope: !6)
|
||||
bb.0:
|
||||
successors: %bb.1(0x40000000), %bb.2(0x40000000)
|
||||
liveins: $w0
|
||||
|
@ -0,0 +1,80 @@
|
||||
# REQUIRES: x86-registered-target
|
||||
# RUN: llc -mtriple=x86_64-unknown-linux-gnu -run-pass=mir-check-debugify -o - %s 2>&1 | FileCheck %s
|
||||
--- |
|
||||
; ModuleID = 'check-line-and-variables.mir'
|
||||
source_filename = "check-line-and-variables.c"
|
||||
|
||||
@ga = dso_local local_unnamed_addr global i32 2, align 4
|
||||
|
||||
; Function Attrs: nofree norecurse nounwind uwtable writeonly
|
||||
define dso_local i32 @foo(i32 %a, i32 %b) local_unnamed_addr #0 !dbg !9 {
|
||||
entry:
|
||||
%add = add nsw i32 %b, %a, !dbg !15
|
||||
call void @llvm.dbg.value(metadata i32 %add, metadata !12, metadata !DIExpression()), !dbg !15
|
||||
%mul = shl nsw i32 %add, 1, !dbg !16
|
||||
call void @llvm.dbg.value(metadata i32 %mul, metadata !14, metadata !DIExpression()), !dbg !16
|
||||
store i32 %mul, i32* @ga, align 4, !dbg !17
|
||||
ret i32 %add, !dbg !18
|
||||
}
|
||||
|
||||
declare void @llvm.dbg.value(metadata, metadata, metadata) #1
|
||||
|
||||
!llvm.module.flags = !{!0, !1}
|
||||
!llvm.ident = !{!2}
|
||||
!llvm.dbg.cu = !{!3}
|
||||
!llvm.mir.debugify = !{!6, !7}
|
||||
!llvm.debugify = !{!8, !7}
|
||||
|
||||
!0 = !{i32 1, !"wchar_size", i32 4}
|
||||
!1 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
!2 = !{!"clang version 12.0.0 (https://github.com/llvm/llvm-project.git c0a922b3db2d39f36c0c01776cce90cc160a7d62)"}
|
||||
!3 = distinct !DICompileUnit(language: DW_LANG_C, file: !4, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !5)
|
||||
!4 = !DIFile(filename: "main.mir", directory: "/")
|
||||
!5 = !{}
|
||||
!6 = !{i32 6}
|
||||
!7 = !{i32 2}
|
||||
!8 = !{i32 4}
|
||||
!9 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !4, line: 1, type: !10, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !3, retainedNodes: !11)
|
||||
!10 = !DISubroutineType(types: !5)
|
||||
!11 = !{!12, !14}
|
||||
!12 = !DILocalVariable(name: "1", scope: !9, file: !4, line: 1, type: !13)
|
||||
!13 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_unsigned)
|
||||
!14 = !DILocalVariable(name: "2", scope: !9, file: !4, line: 2, type: !13)
|
||||
!15 = !DILocation(line: 1, column: 1, scope: !9)
|
||||
!16 = !DILocation(line: 2, column: 1, scope: !9)
|
||||
!17 = !DILocation(line: 3, column: 1, scope: !9)
|
||||
!18 = !DILocation(line: 4, column: 1, scope: !9)
|
||||
|
||||
...
|
||||
---
|
||||
name: foo
|
||||
body: |
|
||||
bb.0.entry:
|
||||
liveins: $edi, $esi
|
||||
|
||||
%1:gr32 = COPY $esi, debug-location !15
|
||||
DBG_VALUE %1, $noreg, !12, !DIExpression(), debug-location !15
|
||||
; Let it missing !14 and debug-location !16
|
||||
; %0:gr32 = COPY $edi, debug-location !16
|
||||
; DBG_VALUE %0, $noreg, !14, !DIExpression(), debug-location !16
|
||||
%0:gr32 = COPY $edi
|
||||
%2:gr32 = nsw ADD32rr %1, %0, implicit-def dead $eflags, debug-location !17
|
||||
DBG_VALUE %2, $noreg, !12, !DIExpression(), debug-location !17
|
||||
DBG_VALUE $eflags, $noreg, !12, !DIExpression(), debug-location !17
|
||||
%3:gr32 = nsw ADD32rr %2, %2, implicit-def dead $eflags, debug-location !18
|
||||
DBG_VALUE %3, $noreg, !12, !DIExpression(), debug-location !18
|
||||
DBG_VALUE $eflags, $noreg, !12, !DIExpression(), debug-location !18
|
||||
MOV32mr $rip, 1, $noreg, @ga, $noreg, killed %3, debug-location !DILocation(line: 5, column: 1, scope: !9) :: (store 4 into @ga, !tbaa !18)
|
||||
DBG_VALUE 0, $noreg, !12, !DIExpression(), debug-location !DILocation(line: 5, column: 1, scope: !9)
|
||||
; Let it miss Line 6: Change "!DILocation(line: 6, ..." to "!DILocation(line: 5, ..."
|
||||
$eax = COPY %2, debug-location !DILocation(line: 5, column: 1, scope: !9)
|
||||
DBG_VALUE $eax, $noreg, !12, !DIExpression(), debug-location !DILocation(line: 6, column: 1, scope: !9)
|
||||
RET 0, $eax, debug-location !DILocation(line: 7, column: 1, scope: !9)
|
||||
|
||||
;CHECK: WARNING: Instruction with empty DebugLoc in function foo --%1:gr32 = COPY $edi
|
||||
;CHECK-NEXT: WARNING: Missing line 2
|
||||
;CHECK-NEXT: WARNING: Missing line 6
|
||||
;CHECK-NEXT: WARNING: Missing variable 2
|
||||
;CHECK-NEXT: Machine IR debug info check: FAIL
|
||||
|
||||
...
|
29
test/CodeGen/Generic/MIRDebugify/check-line-and-variables.ll
Normal file
29
test/CodeGen/Generic/MIRDebugify/check-line-and-variables.ll
Normal file
@ -0,0 +1,29 @@
|
||||
; RUN: llc -debugify-check-and-strip-all-safe -o - %s 2>&1 | FileCheck %s
|
||||
|
||||
; ModuleID = 'main.c'
|
||||
source_filename = "main.c"
|
||||
|
||||
@ga = dso_local global i32 2, align 4
|
||||
|
||||
define dso_local i32 @foo(i32 %a, i32 %b) {
|
||||
entry:
|
||||
%a.addr = alloca i32, align 4
|
||||
%b.addr = alloca i32, align 4
|
||||
%c = alloca i32, align 4
|
||||
store i32 %a, i32* %a.addr, align 4
|
||||
store i32 %b, i32* %b.addr, align 4
|
||||
%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* %c, align 4
|
||||
%2 = load i32, i32* %c, align 4
|
||||
%mul = mul nsw i32 %2, 2
|
||||
store i32 %mul, i32* @ga, align 4
|
||||
%3 = load i32, i32* %c, align 4
|
||||
ret i32 %3
|
||||
}
|
||||
|
||||
; Different Back-Ends may have different number of passes, here we only
|
||||
; check two of them to make sure -debugify-check-and-strip-all-safe works.
|
||||
;CHECK: Machine IR debug info check: PASS
|
||||
;CHECK: Machine IR debug info check: PASS
|
@ -0,0 +1,70 @@
|
||||
# REQUIRES: x86-registered-target
|
||||
# RUN: llc -mtriple=x86_64-unknown-linux-gnu -run-pass=mir-debugify,dead-mi-elimination,mir-check-debugify -o - %s 2>&1 | FileCheck %s
|
||||
# RUN: llc -mtriple=x86_64-unknown-linux-gnu -run-pass=mir-debugify,mir-check-debugify -o - %s 2>&1 | FileCheck %s --check-prefix=CHECK-PASS
|
||||
--- |
|
||||
; ModuleID = 'check-line-and-variables.mir'
|
||||
source_filename = "check-line-and-variables.ll"
|
||||
|
||||
@ga = dso_local global i32 2, align 4
|
||||
|
||||
; Function Attrs: noinline nounwind optnone uwtable
|
||||
define dso_local i32 @foo(i32 %a, i32 %b) {
|
||||
entry:
|
||||
%a.addr = alloca i32, align 4
|
||||
%b.addr = alloca i32, align 4
|
||||
%c = alloca i32, align 4
|
||||
store i32 %a, i32* %a.addr, align 4
|
||||
store i32 %b, i32* %b.addr, align 4
|
||||
%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* %c, align 4
|
||||
%2 = load i32, i32* %c, align 4
|
||||
%mul = mul nsw i32 %2, 2
|
||||
store i32 %mul, i32* @ga, align 4
|
||||
%3 = load i32, i32* %c, align 4
|
||||
; dead-mi-elimination will remove %4 = ...
|
||||
%4 = load i32, i32* %a.addr, align 4
|
||||
ret i32 %3
|
||||
}
|
||||
|
||||
...
|
||||
---
|
||||
name: foo
|
||||
alignment: 16
|
||||
stack:
|
||||
- { id: 0, name: a.addr, type: default, offset: 0, size: 4, alignment: 4,
|
||||
stack-id: default, callee-saved-register: '', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 1, name: b.addr, type: default, offset: 0, size: 4, alignment: 4,
|
||||
stack-id: default, callee-saved-register: '', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 2, name: c, type: default, offset: 0, size: 4, alignment: 4,
|
||||
stack-id: default, callee-saved-register: '', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
body: |
|
||||
bb.0.entry:
|
||||
liveins: $edi, $esi
|
||||
|
||||
%2:gr32 = COPY $esi
|
||||
%0:gr32 = COPY $edi
|
||||
%1:gr32 = COPY killed %0
|
||||
%3:gr32 = COPY killed %2
|
||||
MOV32mr %stack.0.a.addr, 1, $noreg, 0, $noreg, %1 :: (store 4 into %ir.a.addr)
|
||||
MOV32mr %stack.1.b.addr, 1, $noreg, 0, $noreg, %3 :: (store 4 into %ir.b.addr)
|
||||
%14:gr32 = MOV32rm %stack.0.a.addr, 1, $noreg, 0, $noreg :: (load 4 from %ir.a.addr)
|
||||
%13:gr32 = ADD32rm killed %14, %stack.1.b.addr, 1, $noreg, 0, $noreg, implicit-def $eflags :: (load 4 from %ir.b.addr)
|
||||
; dead-mi-elimination will remove %15:gr32 = ...
|
||||
%15:gr32 = MOV32rm %stack.0.a.addr, 1, $noreg, 0, $noreg :: (load 4 from %ir.a.addr)
|
||||
MOV32mr %stack.2.c, 1, $noreg, 0, $noreg, killed %13 :: (store 4 into %ir.c)
|
||||
%9:gr32 = MOV32rm %stack.2.c, 1, $noreg, 0, $noreg :: (load 4 from %ir.c)
|
||||
%8:gr32 = SHL32ri killed %9, 1, implicit-def $eflags
|
||||
MOV32mr $noreg, 1, $noreg, @ga, $noreg, killed %8 :: (store 4 into @ga)
|
||||
%5:gr32 = MOV32rm %stack.2.c, 1, $noreg, 0, $noreg :: (load 4 from %ir.c)
|
||||
$eax = COPY %5
|
||||
RETQ implicit $eax
|
||||
|
||||
;CHECK: WARNING: Missing line 9
|
||||
;CHECK-NEXT: Machine IR debug info check: FAIL
|
||||
;CHECK-PASS: Machine IR debug info check: PASS
|
||||
...
|
@ -17,10 +17,10 @@
|
||||
ret i32 %sub
|
||||
}
|
||||
|
||||
; ALL: !llvm.dbg.cu = !{!0}
|
||||
; ALL: !llvm.dbg.cu = !{![[CU:[0-9]+]]}
|
||||
; ALL: !llvm.debugify =
|
||||
; ALL: !llvm.module.flags = !{![[VERSION:[0-9]+]]}
|
||||
; ALL: !0 = distinct !DICompileUnit(
|
||||
; ALL: ![[CU]] = distinct !DICompileUnit(
|
||||
; ALL: ![[VERSION]] = !{i32 2, !"Debug Info Version", i32 3}
|
||||
; VALUE: [[VAR1:![0-9]+]] = !DILocalVariable(name: "1"
|
||||
; VALUE: [[VAR2:![0-9]+]] = !DILocalVariable(name: "2"
|
||||
@ -44,8 +44,8 @@ body: |
|
||||
; VALUE: DBG_VALUE %1(s32), $noreg, [[VAR2]], !DIExpression(), debug-location [[L2]]
|
||||
; ALL: %2:_(s32) = G_CONSTANT i32 2, debug-location [[L3]]
|
||||
; VALUE: DBG_VALUE %2(s32), $noreg, [[VAR1]], !DIExpression(), debug-location [[L3]]
|
||||
; ALL: %3:_(s32) = G_ADD %0, %2, debug-location !DILocation(line: 4, column: 1, scope: !6)
|
||||
; ALL: %3:_(s32) = G_ADD %0, %2, debug-location !DILocation(line: 4, column: 1, scope: [[SP:![0-9]+]])
|
||||
; VALUE: DBG_VALUE %3(s32), $noreg, [[VAR1]], !DIExpression(), debug-location !DILocation(line: 4
|
||||
; ALL: %4:_(s32) = G_SUB %3, %1, debug-location !DILocation(line: 5, column: 1, scope: !6)
|
||||
; ALL: %4:_(s32) = G_SUB %3, %1, debug-location !DILocation(line: 5, column: 1, scope: [[SP]])
|
||||
; VALUE: DBG_VALUE %4(s32), $noreg, [[VAR1]], !DIExpression(), debug-location !DILocation(line: 5
|
||||
...
|
||||
|
@ -99,6 +99,7 @@ static_library("CodeGen") {
|
||||
"MachineBlockPlacement.cpp",
|
||||
"MachineBranchProbabilityInfo.cpp",
|
||||
"MachineCSE.cpp",
|
||||
"MachineCheckDebugify.cpp",
|
||||
"MachineCombiner.cpp",
|
||||
"MachineCopyPropagation.cpp",
|
||||
"MachineDebugify.cpp",
|
||||
|
Loading…
Reference in New Issue
Block a user