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).
151 lines
5.7 KiB
C++
151 lines
5.7 KiB
C++
//===- PseudoProbeInserter.cpp - Insert annotation for callsite profiling -===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements PseudoProbeInserter pass, which inserts pseudo probe
|
|
// annotations for call instructions with a pseudo-probe-specific dwarf
|
|
// discriminator. such discriminator indicates that the call instruction comes
|
|
// with a pseudo probe, and the discriminator value holds information to
|
|
// identify the corresponding counter.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/CodeGen/MachineBasicBlock.h"
|
|
#include "llvm/CodeGen/MachineFunctionPass.h"
|
|
#include "llvm/CodeGen/MachineInstr.h"
|
|
#include "llvm/CodeGen/TargetInstrInfo.h"
|
|
#include "llvm/IR/DebugInfoMetadata.h"
|
|
#include "llvm/IR/Module.h"
|
|
#include "llvm/IR/PseudoProbe.h"
|
|
#include "llvm/InitializePasses.h"
|
|
|
|
#define DEBUG_TYPE "pseudo-probe-inserter"
|
|
|
|
using namespace llvm;
|
|
|
|
namespace {
|
|
class PseudoProbeInserter : public MachineFunctionPass {
|
|
public:
|
|
static char ID;
|
|
|
|
PseudoProbeInserter() : MachineFunctionPass(ID) {
|
|
initializePseudoProbeInserterPass(*PassRegistry::getPassRegistry());
|
|
}
|
|
|
|
StringRef getPassName() const override { return "Pseudo Probe Inserter"; }
|
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
|
AU.setPreservesAll();
|
|
MachineFunctionPass::getAnalysisUsage(AU);
|
|
}
|
|
|
|
bool doInitialization(Module &M) override {
|
|
ShouldRun = M.getNamedMetadata(PseudoProbeDescMetadataName);
|
|
return false;
|
|
}
|
|
|
|
bool runOnMachineFunction(MachineFunction &MF) override {
|
|
if (!ShouldRun)
|
|
return false;
|
|
const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
|
|
bool Changed = false;
|
|
for (MachineBasicBlock &MBB : MF) {
|
|
MachineInstr *FirstInstr = nullptr;
|
|
for (MachineInstr &MI : MBB) {
|
|
if (!MI.isPseudo())
|
|
FirstInstr = &MI;
|
|
if (MI.isCall()) {
|
|
if (DILocation *DL = MI.getDebugLoc()) {
|
|
auto Value = DL->getDiscriminator();
|
|
if (DILocation::isPseudoProbeDiscriminator(Value)) {
|
|
BuildMI(MBB, MI, DL, TII->get(TargetOpcode::PSEUDO_PROBE))
|
|
.addImm(getFuncGUID(MF.getFunction().getParent(), DL))
|
|
.addImm(
|
|
PseudoProbeDwarfDiscriminator::extractProbeIndex(Value))
|
|
.addImm(
|
|
PseudoProbeDwarfDiscriminator::extractProbeType(Value))
|
|
.addImm(PseudoProbeDwarfDiscriminator::extractProbeAttributes(
|
|
Value));
|
|
Changed = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Walk the block backwards, move PSEUDO_PROBE before the first real
|
|
// instruction to fix out-of-order probes. There is a problem with probes
|
|
// as the terminator of the block. During the offline counts processing,
|
|
// the samples collected on the first physical instruction following a
|
|
// probe will be counted towards the probe. This logically equals to
|
|
// treating the instruction next to a probe as if it is from the same
|
|
// block of the probe. This is accurate most of the time unless the
|
|
// instruction can be reached from multiple flows, which means it actually
|
|
// starts a new block. Samples collected on such probes may cause
|
|
// imprecision with the counts inference algorithm. Fortunately, if
|
|
// there are still other native instructions preceding the probe we can
|
|
// use them as a place holder to collect samples for the probe.
|
|
if (FirstInstr) {
|
|
auto MII = MBB.rbegin();
|
|
while (MII != MBB.rend()) {
|
|
// Skip all pseudo probes followed by a real instruction since they
|
|
// are not dangling.
|
|
if (!MII->isPseudo())
|
|
break;
|
|
auto Cur = MII++;
|
|
if (Cur->getOpcode() != TargetOpcode::PSEUDO_PROBE)
|
|
continue;
|
|
// Move the dangling probe before FirstInstr.
|
|
auto *ProbeInstr = &*Cur;
|
|
MBB.remove(ProbeInstr);
|
|
MBB.insert(FirstInstr, ProbeInstr);
|
|
Changed = true;
|
|
}
|
|
} else {
|
|
// Probes not surrounded by any real instructions in the same block are
|
|
// called dangling probes. Since there's no good way to pick up a sample
|
|
// collection point for dangling probes at compile time, they are being
|
|
// removed so that the profile correlation tool will not report any
|
|
// samples collected for them and it's up to the counts inference tool
|
|
// to get them a reasonable count.
|
|
SmallVector<MachineInstr *, 4> ToBeRemoved;
|
|
for (MachineInstr &MI : MBB) {
|
|
if (MI.isPseudoProbe())
|
|
ToBeRemoved.push_back(&MI);
|
|
}
|
|
|
|
for (auto *MI : ToBeRemoved)
|
|
MI->eraseFromParent();
|
|
|
|
Changed |= !ToBeRemoved.empty();
|
|
}
|
|
}
|
|
|
|
return Changed;
|
|
}
|
|
|
|
private:
|
|
uint64_t getFuncGUID(Module *M, DILocation *DL) {
|
|
auto Name = DL->getSubprogramLinkageName();
|
|
return Function::getGUIDAssumingExternalLinkage(Name);
|
|
}
|
|
|
|
bool ShouldRun = false;
|
|
};
|
|
} // namespace
|
|
|
|
char PseudoProbeInserter::ID = 0;
|
|
INITIALIZE_PASS_BEGIN(PseudoProbeInserter, DEBUG_TYPE,
|
|
"Insert pseudo probe annotations for value profiling",
|
|
false, false)
|
|
INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
|
|
INITIALIZE_PASS_END(PseudoProbeInserter, DEBUG_TYPE,
|
|
"Insert pseudo probe annotations for value profiling",
|
|
false, false)
|
|
|
|
FunctionPass *llvm::createPseudoProbeInserter() {
|
|
return new PseudoProbeInserter();
|
|
}
|