Path: blob/main/contrib/llvm-project/llvm/lib/Target/X86/X86DiscriminateMemOps.cpp
35266 views
//===- X86DiscriminateMemOps.cpp - Unique IDs for Mem Ops -----------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7///8/// This pass aids profile-driven cache prefetch insertion by ensuring all9/// instructions that have a memory operand are distinguishible from each other.10///11//===----------------------------------------------------------------------===//1213#include "X86.h"14#include "X86InstrBuilder.h"15#include "X86InstrInfo.h"16#include "X86MachineFunctionInfo.h"17#include "X86Subtarget.h"18#include "llvm/CodeGen/MachineFunctionPass.h"19#include "llvm/CodeGen/MachineModuleInfo.h"20#include "llvm/IR/DebugInfoMetadata.h"21#include "llvm/ProfileData/SampleProf.h"22#include "llvm/ProfileData/SampleProfReader.h"23#include "llvm/Support/Debug.h"24#include "llvm/Transforms/IPO/SampleProfile.h"25#include <optional>26using namespace llvm;2728#define DEBUG_TYPE "x86-discriminate-memops"2930static cl::opt<bool> EnableDiscriminateMemops(31DEBUG_TYPE, cl::init(false),32cl::desc("Generate unique debug info for each instruction with a memory "33"operand. Should be enabled for profile-driven cache prefetching, "34"both in the build of the binary being profiled, as well as in "35"the build of the binary consuming the profile."),36cl::Hidden);3738static cl::opt<bool> BypassPrefetchInstructions(39"x86-bypass-prefetch-instructions", cl::init(true),40cl::desc("When discriminating instructions with memory operands, ignore "41"prefetch instructions. This ensures the other memory operand "42"instructions have the same identifiers after inserting "43"prefetches, allowing for successive insertions."),44cl::Hidden);4546namespace {4748using Location = std::pair<StringRef, unsigned>;4950Location diToLocation(const DILocation *Loc) {51return std::make_pair(Loc->getFilename(), Loc->getLine());52}5354/// Ensure each instruction having a memory operand has a distinct <LineNumber,55/// Discriminator> pair.56void updateDebugInfo(MachineInstr *MI, const DILocation *Loc) {57DebugLoc DL(Loc);58MI->setDebugLoc(DL);59}6061class X86DiscriminateMemOps : public MachineFunctionPass {62bool runOnMachineFunction(MachineFunction &MF) override;63StringRef getPassName() const override {64return "X86 Discriminate Memory Operands";65}6667public:68static char ID;6970/// Default construct and initialize the pass.71X86DiscriminateMemOps();72};7374bool IsPrefetchOpcode(unsigned Opcode) {75return Opcode == X86::PREFETCHNTA || Opcode == X86::PREFETCHT0 ||76Opcode == X86::PREFETCHT1 || Opcode == X86::PREFETCHT2 ||77Opcode == X86::PREFETCHIT0 || Opcode == X86::PREFETCHIT1;78}79} // end anonymous namespace8081//===----------------------------------------------------------------------===//82// Implementation83//===----------------------------------------------------------------------===//8485char X86DiscriminateMemOps::ID = 0;8687/// Default construct and initialize the pass.88X86DiscriminateMemOps::X86DiscriminateMemOps() : MachineFunctionPass(ID) {}8990bool X86DiscriminateMemOps::runOnMachineFunction(MachineFunction &MF) {91if (!EnableDiscriminateMemops)92return false;9394DISubprogram *FDI = MF.getFunction().getSubprogram();95if (!FDI || !FDI->getUnit()->getDebugInfoForProfiling())96return false;9798// Have a default DILocation, if we find instructions with memops that don't99// have any debug info.100const DILocation *ReferenceDI =101DILocation::get(FDI->getContext(), FDI->getLine(), 0, FDI);102assert(ReferenceDI && "ReferenceDI should not be nullptr");103DenseMap<Location, unsigned> MemOpDiscriminators;104MemOpDiscriminators[diToLocation(ReferenceDI)] = 0;105106// Figure out the largest discriminator issued for each Location. When we107// issue new discriminators, we can thus avoid issuing discriminators108// belonging to instructions that don't have memops. This isn't a requirement109// for the goals of this pass, however, it avoids unnecessary ambiguity.110for (auto &MBB : MF) {111for (auto &MI : MBB) {112const auto &DI = MI.getDebugLoc();113if (!DI)114continue;115if (BypassPrefetchInstructions && IsPrefetchOpcode(MI.getDesc().Opcode))116continue;117Location Loc = diToLocation(DI);118MemOpDiscriminators[Loc] =119std::max(MemOpDiscriminators[Loc], DI->getBaseDiscriminator());120}121}122123// Keep track of the discriminators seen at each Location. If an instruction's124// DebugInfo has a Location and discriminator we've already seen, replace its125// discriminator with a new one, to guarantee uniqueness.126DenseMap<Location, DenseSet<unsigned>> Seen;127128bool Changed = false;129for (auto &MBB : MF) {130for (auto &MI : MBB) {131if (X86II::getMemoryOperandNo(MI.getDesc().TSFlags) < 0)132continue;133if (BypassPrefetchInstructions && IsPrefetchOpcode(MI.getDesc().Opcode))134continue;135const DILocation *DI = MI.getDebugLoc();136bool HasDebug = DI;137if (!HasDebug) {138DI = ReferenceDI;139}140Location L = diToLocation(DI);141DenseSet<unsigned> &Set = Seen[L];142const std::pair<DenseSet<unsigned>::iterator, bool> TryInsert =143Set.insert(DI->getBaseDiscriminator());144if (!TryInsert.second || !HasDebug) {145unsigned BF, DF, CI = 0;146DILocation::decodeDiscriminator(DI->getDiscriminator(), BF, DF, CI);147std::optional<unsigned> EncodedDiscriminator =148DILocation::encodeDiscriminator(MemOpDiscriminators[L] + 1, DF, CI);149150if (!EncodedDiscriminator) {151// FIXME(mtrofin): The assumption is that this scenario is infrequent/OK152// not to support. If evidence points otherwise, we can explore synthesizeing153// unique DIs by adding fake line numbers, or by constructing 64 bit154// discriminators.155LLVM_DEBUG(dbgs() << "Unable to create a unique discriminator "156"for instruction with memory operand in: "157<< DI->getFilename() << " Line: " << DI->getLine()158<< " Column: " << DI->getColumn()159<< ". This is likely due to a large macro expansion. \n");160continue;161}162// Since we were able to encode, bump the MemOpDiscriminators.163++MemOpDiscriminators[L];164DI = DI->cloneWithDiscriminator(*EncodedDiscriminator);165assert(DI && "DI should not be nullptr");166updateDebugInfo(&MI, DI);167Changed = true;168std::pair<DenseSet<unsigned>::iterator, bool> MustInsert =169Set.insert(DI->getBaseDiscriminator());170(void)MustInsert; // Silence warning in release build.171assert(MustInsert.second && "New discriminator shouldn't be present in set");172}173174// Bump the reference DI to avoid cramming discriminators on line 0.175// FIXME(mtrofin): pin ReferenceDI on blocks or first instruction with DI176// in a block. It's more consistent than just relying on the last memop177// instruction we happened to see.178ReferenceDI = DI;179}180}181return Changed;182}183184FunctionPass *llvm::createX86DiscriminateMemOpsPass() {185return new X86DiscriminateMemOps();186}187188189