llvm-project/llvm/lib/CodeGen/MIRFSDiscriminator.cpp
Hongtao Yu d4d6b9a142 [FS-AFDO] Clean up non-zero discriminator for pseudo probes at the first FS discriminator pass.
The dwarf discriminator field for pseudo probes is not supposed to be used until the first FS discriminator pass. Unfortunately there are always corner cases that accidientally set this field. For example, the inliner could set this field for an inlined instruction if the instruction does not come with any debug information. While fixing all such spots is possible, but for future-proff I'd like to enforce a general cleanup before assigning probes any FS discriminator.

Reviewed By: wenlei

Differential Revision: https://reviews.llvm.org/D150741
2023-05-16 21:35:17 -07:00

203 lines
7.7 KiB
C++

//===-------- MIRFSDiscriminator.cpp: Flow Sensitive Discriminator --------===//
//
// 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 provides the implementation of a machine pass that adds the flow
// sensitive discriminator to the instruction debug information.
//
//===----------------------------------------------------------------------===//
#include "llvm/CodeGen/MIRFSDiscriminator.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/Analysis/BlockFrequencyInfoImpl.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/PseudoProbe.h"
#include "llvm/InitializePasses.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/xxhash.h"
#include "llvm/Transforms/Utils/SampleProfileLoaderBaseUtil.h"
using namespace llvm;
using namespace sampleprof;
using namespace sampleprofutil;
#define DEBUG_TYPE "mirfs-discriminators"
// TODO(xur): Remove this option and related code once we make true as the
// default.
cl::opt<bool> ImprovedFSDiscriminator(
"improved-fs-discriminator", cl::Hidden, cl::init(false),
cl::desc("New FS discriminators encoding (incompatible with the original "
"encoding)"));
char MIRAddFSDiscriminators::ID = 0;
INITIALIZE_PASS(MIRAddFSDiscriminators, DEBUG_TYPE,
"Add MIR Flow Sensitive Discriminators",
/* cfg = */ false, /* is_analysis = */ false)
char &llvm::MIRAddFSDiscriminatorsID = MIRAddFSDiscriminators::ID;
FunctionPass *llvm::createMIRAddFSDiscriminatorsPass(FSDiscriminatorPass P) {
return new MIRAddFSDiscriminators(P);
}
// TODO(xur): Remove this once we switch to ImprovedFSDiscriminator.
// Compute a hash value using debug line number, and the line numbers from the
// inline stack.
static uint64_t getCallStackHashV0(const MachineBasicBlock &BB,
const MachineInstr &MI,
const DILocation *DIL) {
auto updateHash = [](const StringRef &Str) -> uint64_t {
if (Str.empty())
return 0;
return MD5Hash(Str);
};
uint64_t Ret = updateHash(std::to_string(DIL->getLine()));
Ret ^= updateHash(BB.getName());
Ret ^= updateHash(DIL->getScope()->getSubprogram()->getLinkageName());
for (DIL = DIL->getInlinedAt(); DIL; DIL = DIL->getInlinedAt()) {
Ret ^= updateHash(std::to_string(DIL->getLine()));
Ret ^= updateHash(DIL->getScope()->getSubprogram()->getLinkageName());
}
return Ret;
}
static uint64_t getCallStackHash(const DILocation *DIL) {
auto hashCombine = [](const uint64_t Seed, const uint64_t Val) {
std::hash<uint64_t> Hasher;
return Seed ^ (Hasher(Val) + 0x9e3779b9 + (Seed << 6) + (Seed >> 2));
};
uint64_t Ret = 0;
for (DIL = DIL->getInlinedAt(); DIL; DIL = DIL->getInlinedAt()) {
Ret = hashCombine(Ret, xxHash64(ArrayRef<uint8_t>(DIL->getLine())));
Ret = hashCombine(Ret, xxHash64(DIL->getSubprogramLinkageName()));
}
return Ret;
}
// Traverse the CFG and assign FD discriminators. If two instructions
// have the same lineno and discriminator, but residing in different BBs,
// the latter instruction will get a new discriminator value. The new
// discriminator keeps the existing discriminator value but sets new bits
// b/w LowBit and HighBit.
bool MIRAddFSDiscriminators::runOnMachineFunction(MachineFunction &MF) {
if (!EnableFSDiscriminator)
return false;
bool HasPseudoProbe = MF.getFunction().getParent()->getNamedMetadata(
PseudoProbeDescMetadataName);
if (!HasPseudoProbe && !MF.getFunction().shouldEmitDebugInfoForProfiling())
return false;
bool Changed = false;
using LocationDiscriminator =
std::tuple<StringRef, unsigned, unsigned, uint64_t>;
using BBSet = DenseSet<const MachineBasicBlock *>;
using LocationDiscriminatorBBMap = DenseMap<LocationDiscriminator, BBSet>;
using LocationDiscriminatorCurrPassMap =
DenseMap<LocationDiscriminator, unsigned>;
LocationDiscriminatorBBMap LDBM;
LocationDiscriminatorCurrPassMap LDCM;
// Mask of discriminators before this pass.
// TODO(xur): simplify this once we switch to ImprovedFSDiscriminator.
unsigned LowBitTemp = LowBit;
assert(LowBit > 0 && "LowBit in FSDiscriminator cannot be 0");
if (ImprovedFSDiscriminator)
LowBitTemp -= 1;
unsigned BitMaskBefore = getN1Bits(LowBitTemp);
// Mask of discriminators including this pass.
unsigned BitMaskNow = getN1Bits(HighBit);
// Mask of discriminators for bits specific to this pass.
unsigned BitMaskThisPass = BitMaskNow ^ BitMaskBefore;
unsigned NumNewD = 0;
LLVM_DEBUG(dbgs() << "MIRAddFSDiscriminators working on Func: "
<< MF.getFunction().getName() << " Highbit=" << HighBit
<< "\n");
for (MachineBasicBlock &BB : MF) {
for (MachineInstr &I : BB) {
if (HasPseudoProbe) {
// Only assign discriminators to pseudo probe instructions. Call
// instructions are excluded since their dwarf discriminators are used
// for other purposes, i.e, storing probe ids.
if (!I.isPseudoProbe())
continue;
} else if (ImprovedFSDiscriminator && I.isMetaInstruction()) {
continue;
}
const DILocation *DIL = I.getDebugLoc().get();
if (!DIL)
continue;
// Use the id of pseudo probe to compute the discriminator.
unsigned LineNo =
I.isPseudoProbe() ? I.getOperand(1).getImm() : DIL->getLine();
if (LineNo == 0)
continue;
unsigned Discriminator = DIL->getDiscriminator();
// Clean up discriminators for pseudo probes at the first FS discriminator
// pass as their discriminators should not ever be used.
if ((Pass == FSDiscriminatorPass::Pass1) && I.isPseudoProbe()) {
Discriminator = 0;
I.setDebugLoc(DIL->cloneWithDiscriminator(0));
}
uint64_t CallStackHashVal = 0;
if (ImprovedFSDiscriminator)
CallStackHashVal = getCallStackHash(DIL);
LocationDiscriminator LD{DIL->getFilename(), LineNo, Discriminator,
CallStackHashVal};
auto &BBMap = LDBM[LD];
auto R = BBMap.insert(&BB);
if (BBMap.size() == 1)
continue;
unsigned DiscriminatorCurrPass;
DiscriminatorCurrPass = R.second ? ++LDCM[LD] : LDCM[LD];
DiscriminatorCurrPass = DiscriminatorCurrPass << LowBit;
if (!ImprovedFSDiscriminator)
DiscriminatorCurrPass += getCallStackHashV0(BB, I, DIL);
DiscriminatorCurrPass &= BitMaskThisPass;
unsigned NewD = Discriminator | DiscriminatorCurrPass;
const auto *const NewDIL = DIL->cloneWithDiscriminator(NewD);
if (!NewDIL) {
LLVM_DEBUG(dbgs() << "Could not encode discriminator: "
<< DIL->getFilename() << ":" << DIL->getLine() << ":"
<< DIL->getColumn() << ":" << Discriminator << " "
<< I << "\n");
continue;
}
I.setDebugLoc(NewDIL);
NumNewD++;
LLVM_DEBUG(dbgs() << DIL->getFilename() << ":" << DIL->getLine() << ":"
<< DIL->getColumn() << ": add FS discriminator, from "
<< Discriminator << " -> " << NewD << "\n");
Changed = true;
}
}
if (Changed) {
createFSDiscriminatorVariable(MF.getFunction().getParent());
LLVM_DEBUG(dbgs() << "Num of FS Discriminators: " << NumNewD << "\n");
(void) NumNewD;
}
return Changed;
}