cb424d7448
verify-patch-sanity.py validates every active recipe .patch has internally- consistent hunk line counts — catching the 'malformed patch at line N' failure at commit/CI/preflight time instead of hours into a cook. This cycle hit that class three times (qtwaylandscanner, sddm, xwayland), each only discovered when cookbook tried to apply the patch. Running it across the repo found 29 latent malformed patches (validated against GNU patch: e.g. relibc/P3-sysv-ipc reproduces 'malformed patch at line 22'). They were harmless only because they sit in vendored recipes (baked, not re- applied) — but would fail on any version-bump re-derivation. --fix recounts the hunk headers (body untouched) and repaired all 29. Wired into build-preflight.sh (Phase 1.0D) and redbear-ci.yml, with a unit test (test-patch-sanity.sh). Skips archived/legacy trees and unvalidatable formats (empty placeholders, bare-@@ git hunks).
247 lines
8.1 KiB
C++
247 lines
8.1 KiB
C++
//===- RemoveRedundantDebugValues.cpp - Remove Redundant Debug Value MIs --===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/CodeGen/RemoveRedundantDebugValues.h"
|
|
#include "llvm/ADT/DenseMap.h"
|
|
#include "llvm/ADT/DenseSet.h"
|
|
#include "llvm/ADT/SmallVector.h"
|
|
#include "llvm/ADT/Statistic.h"
|
|
#include "llvm/CodeGen/MachineBasicBlock.h"
|
|
#include "llvm/CodeGen/MachineFunctionPass.h"
|
|
#include "llvm/CodeGen/TargetSubtargetInfo.h"
|
|
#include "llvm/IR/DebugInfoMetadata.h"
|
|
#include "llvm/IR/Function.h"
|
|
#include "llvm/InitializePasses.h"
|
|
#include "llvm/Pass.h"
|
|
#include "llvm/PassRegistry.h"
|
|
|
|
/// \file RemoveRedundantDebugValues.cpp
|
|
///
|
|
/// The RemoveRedundantDebugValues pass removes redundant DBG_VALUEs that
|
|
/// appear in MIR after the register allocator.
|
|
|
|
#define DEBUG_TYPE "removeredundantdebugvalues"
|
|
|
|
using namespace llvm;
|
|
|
|
STATISTIC(NumRemovedBackward, "Number of DBG_VALUEs removed (backward scan)");
|
|
STATISTIC(NumRemovedForward, "Number of DBG_VALUEs removed (forward scan)");
|
|
|
|
namespace {
|
|
|
|
struct RemoveRedundantDebugValuesImpl {
|
|
bool reduceDbgValues(MachineFunction &MF);
|
|
};
|
|
|
|
class RemoveRedundantDebugValuesLegacy : public MachineFunctionPass {
|
|
public:
|
|
static char ID;
|
|
|
|
RemoveRedundantDebugValuesLegacy();
|
|
/// Remove redundant debug value MIs for the given machine function.
|
|
bool runOnMachineFunction(MachineFunction &MF) override;
|
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
|
AU.setPreservesCFG();
|
|
MachineFunctionPass::getAnalysisUsage(AU);
|
|
}
|
|
};
|
|
|
|
} // namespace
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Implementation
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
char RemoveRedundantDebugValuesLegacy::ID = 0;
|
|
|
|
char &llvm::RemoveRedundantDebugValuesID = RemoveRedundantDebugValuesLegacy::ID;
|
|
|
|
INITIALIZE_PASS(RemoveRedundantDebugValuesLegacy, DEBUG_TYPE,
|
|
"Remove Redundant DEBUG_VALUE analysis", false, false)
|
|
|
|
/// Default construct and initialize the pass.
|
|
RemoveRedundantDebugValuesLegacy::RemoveRedundantDebugValuesLegacy()
|
|
: MachineFunctionPass(ID) {
|
|
initializeRemoveRedundantDebugValuesLegacyPass(
|
|
*PassRegistry::getPassRegistry());
|
|
}
|
|
|
|
// This analysis aims to remove redundant DBG_VALUEs by going forward
|
|
// in the basic block by considering the first DBG_VALUE as a valid
|
|
// until its first (location) operand is not clobbered/modified.
|
|
// For example:
|
|
// (1) DBG_VALUE $edi, !"var1", ...
|
|
// (2) <block of code that does affect $edi>
|
|
// (3) DBG_VALUE $edi, !"var1", ...
|
|
// ...
|
|
// in this case, we can remove (3).
|
|
// TODO: Support DBG_VALUE_LIST and other debug instructions.
|
|
static bool reduceDbgValsForwardScan(MachineBasicBlock &MBB) {
|
|
LLVM_DEBUG(dbgs() << "\n == Forward Scan == \n");
|
|
|
|
SmallVector<MachineInstr *, 8> DbgValsToBeRemoved;
|
|
DenseMap<DebugVariable, std::pair<MachineOperand *, const DIExpression *>>
|
|
VariableMap;
|
|
const auto *TRI = MBB.getParent()->getSubtarget().getRegisterInfo();
|
|
|
|
for (auto &MI : MBB) {
|
|
if (MI.isDebugValue()) {
|
|
DebugVariable Var(MI.getDebugVariable(), std::nullopt,
|
|
MI.getDebugLoc()->getInlinedAt());
|
|
auto VMI = VariableMap.find(Var);
|
|
// Just stop tracking this variable, until we cover DBG_VALUE_LIST.
|
|
// 1 DBG_VALUE $rax, "x", DIExpression()
|
|
// ...
|
|
// 2 DBG_VALUE_LIST "x", DIExpression(...), $rax, $rbx
|
|
// ...
|
|
// 3 DBG_VALUE $rax, "x", DIExpression()
|
|
if (MI.isDebugValueList() && VMI != VariableMap.end()) {
|
|
VariableMap.erase(VMI);
|
|
continue;
|
|
}
|
|
|
|
MachineOperand &Loc = MI.getDebugOperand(0);
|
|
if (!Loc.isReg()) {
|
|
// If it's not a register, just stop tracking such variable.
|
|
if (VMI != VariableMap.end())
|
|
VariableMap.erase(VMI);
|
|
continue;
|
|
}
|
|
|
|
// We have found a new value for a variable.
|
|
if (VMI == VariableMap.end() ||
|
|
VMI->second.first->getReg() != Loc.getReg() ||
|
|
VMI->second.second != MI.getDebugExpression()) {
|
|
VariableMap[Var] = {&Loc, MI.getDebugExpression()};
|
|
continue;
|
|
}
|
|
|
|
// Found an identical DBG_VALUE, so it can be considered
|
|
// for later removal.
|
|
DbgValsToBeRemoved.push_back(&MI);
|
|
}
|
|
|
|
if (MI.isMetaInstruction())
|
|
continue;
|
|
|
|
// Stop tracking any location that is clobbered by this instruction.
|
|
for (auto &Var : VariableMap) {
|
|
auto &LocOp = Var.second.first;
|
|
if (MI.modifiesRegister(LocOp->getReg(), TRI))
|
|
VariableMap.erase(Var.first);
|
|
}
|
|
}
|
|
|
|
for (auto &Instr : DbgValsToBeRemoved) {
|
|
LLVM_DEBUG(dbgs() << "removing "; Instr->dump());
|
|
Instr->eraseFromParent();
|
|
++NumRemovedForward;
|
|
}
|
|
|
|
return !DbgValsToBeRemoved.empty();
|
|
}
|
|
|
|
// This analysis aims to remove redundant DBG_VALUEs by going backward
|
|
// in the basic block and removing all but the last DBG_VALUE for any
|
|
// given variable in a set of consecutive DBG_VALUE instructions.
|
|
// For example:
|
|
// (1) DBG_VALUE $edi, !"var1", ...
|
|
// (2) DBG_VALUE $esi, !"var2", ...
|
|
// (3) DBG_VALUE $edi, !"var1", ...
|
|
// ...
|
|
// in this case, we can remove (1).
|
|
static bool reduceDbgValsBackwardScan(MachineBasicBlock &MBB) {
|
|
LLVM_DEBUG(dbgs() << "\n == Backward Scan == \n");
|
|
SmallVector<MachineInstr *, 8> DbgValsToBeRemoved;
|
|
SmallDenseSet<DebugVariable> VariableSet;
|
|
|
|
for (MachineInstr &MI : llvm::reverse(MBB)) {
|
|
if (MI.isDebugValue()) {
|
|
DebugVariable Var(MI.getDebugVariable(), MI.getDebugExpression(),
|
|
MI.getDebugLoc()->getInlinedAt());
|
|
auto R = VariableSet.insert(Var);
|
|
// If it is a DBG_VALUE describing a constant as:
|
|
// DBG_VALUE 0, ...
|
|
// we just don't consider such instructions as candidates
|
|
// for redundant removal.
|
|
if (MI.isNonListDebugValue()) {
|
|
MachineOperand &Loc = MI.getDebugOperand(0);
|
|
if (!Loc.isReg()) {
|
|
// If we have already encountered this variable, just stop
|
|
// tracking it.
|
|
if (!R.second)
|
|
VariableSet.erase(Var);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// We have already encountered the value for this variable,
|
|
// so this one can be deleted.
|
|
if (!R.second)
|
|
DbgValsToBeRemoved.push_back(&MI);
|
|
continue;
|
|
}
|
|
|
|
// If we encountered a non-DBG_VALUE, try to find the next
|
|
// sequence with consecutive DBG_VALUE instructions.
|
|
VariableSet.clear();
|
|
}
|
|
|
|
for (auto &Instr : DbgValsToBeRemoved) {
|
|
LLVM_DEBUG(dbgs() << "removing "; Instr->dump());
|
|
Instr->eraseFromParent();
|
|
++NumRemovedBackward;
|
|
}
|
|
|
|
return !DbgValsToBeRemoved.empty();
|
|
}
|
|
|
|
bool RemoveRedundantDebugValuesImpl::reduceDbgValues(MachineFunction &MF) {
|
|
LLVM_DEBUG(dbgs() << "\nDebug Value Reduction\n");
|
|
|
|
bool Changed = false;
|
|
|
|
for (auto &MBB : MF) {
|
|
Changed |= reduceDbgValsBackwardScan(MBB);
|
|
Changed |= reduceDbgValsForwardScan(MBB);
|
|
}
|
|
|
|
return Changed;
|
|
}
|
|
|
|
bool RemoveRedundantDebugValuesLegacy::runOnMachineFunction(
|
|
MachineFunction &MF) {
|
|
// Skip functions without debugging information or functions from NoDebug
|
|
// compilation units.
|
|
if (!MF.getFunction().getSubprogram() ||
|
|
(MF.getFunction().getSubprogram()->getUnit()->getEmissionKind() ==
|
|
DICompileUnit::NoDebug))
|
|
return false;
|
|
|
|
return RemoveRedundantDebugValuesImpl().reduceDbgValues(MF);
|
|
}
|
|
|
|
PreservedAnalyses
|
|
RemoveRedundantDebugValuesPass::run(MachineFunction &MF,
|
|
MachineFunctionAnalysisManager &MFAM) {
|
|
// Skip functions without debugging information or functions from NoDebug
|
|
// compilation units.
|
|
if (!MF.getFunction().getSubprogram() ||
|
|
(MF.getFunction().getSubprogram()->getUnit()->getEmissionKind() ==
|
|
DICompileUnit::NoDebug))
|
|
return PreservedAnalyses::all();
|
|
|
|
if (!RemoveRedundantDebugValuesImpl().reduceDbgValues(MF))
|
|
return PreservedAnalyses::all();
|
|
|
|
auto PA = getMachineFunctionPassPreservedAnalyses();
|
|
PA.preserveSet<CFGAnalyses>();
|
|
return PA;
|
|
}
|