#include "X86.h"
#include "X86InstrBuilder.h"
#include "X86InstrInfo.h"
#include "X86MachineFunctionInfo.h"
#include "X86Subtarget.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/ProfileData/SampleProf.h"
#include "llvm/ProfileData/SampleProfReader.h"
#include "llvm/Support/Debug.h"
#include "llvm/Transforms/IPO/SampleProfile.h"
using namespace llvm;
#define DEBUG_TYPE "x86-discriminate-memops"
static cl::opt<bool> EnableDiscriminateMemops(
DEBUG_TYPE, cl::init(false),
cl::desc("Generate unique debug info for each instruction with a memory "
"operand. Should be enabled for profile-driven cache prefetching, "
"both in the build of the binary being profiled, as well as in "
"the build of the binary consuming the profile."),
cl::Hidden);
static cl::opt<bool> BypassPrefetchInstructions(
"x86-bypass-prefetch-instructions", cl::init(true),
cl::desc("When discriminating instructions with memory operands, ignore "
"prefetch instructions. This ensures the other memory operand "
"instructions have the same identifiers after inserting "
"prefetches, allowing for successive insertions."),
cl::Hidden);
namespace {
using Location = std::pair<StringRef, unsigned>;
Location diToLocation(const DILocation *Loc) {
return std::make_pair(Loc->getFilename(), Loc->getLine());
}
void updateDebugInfo(MachineInstr *MI, const DILocation *Loc) {
DebugLoc DL(Loc);
MI->setDebugLoc(DL);
}
class X86DiscriminateMemOps : public MachineFunctionPass {
bool runOnMachineFunction(MachineFunction &MF) override;
StringRef getPassName() const override {
return "X86 Discriminate Memory Operands";
}
public:
static char ID;
X86DiscriminateMemOps();
};
bool IsPrefetchOpcode(unsigned Opcode) {
return Opcode == X86::PREFETCHNTA || Opcode == X86::PREFETCHT0 ||
Opcode == X86::PREFETCHT1 || Opcode == X86::PREFETCHT2;
}
}
char X86DiscriminateMemOps::ID = 0;
X86DiscriminateMemOps::X86DiscriminateMemOps() : MachineFunctionPass(ID) {}
bool X86DiscriminateMemOps::runOnMachineFunction(MachineFunction &MF) {
if (!EnableDiscriminateMemops)
return false;
DISubprogram *FDI = MF.getFunction().getSubprogram();
if (!FDI || !FDI->getUnit()->getDebugInfoForProfiling())
return false;
const DILocation *ReferenceDI =
DILocation::get(FDI->getContext(), FDI->getLine(), 0, FDI);
assert(ReferenceDI && "ReferenceDI should not be nullptr");
DenseMap<Location, unsigned> MemOpDiscriminators;
MemOpDiscriminators[diToLocation(ReferenceDI)] = 0;
for (auto &MBB : MF) {
for (auto &MI : MBB) {
const auto &DI = MI.getDebugLoc();
if (!DI)
continue;
if (BypassPrefetchInstructions && IsPrefetchOpcode(MI.getDesc().Opcode))
continue;
Location Loc = diToLocation(DI);
MemOpDiscriminators[Loc] =
std::max(MemOpDiscriminators[Loc], DI->getBaseDiscriminator());
}
}
DenseMap<Location, DenseSet<unsigned>> Seen;
bool Changed = false;
for (auto &MBB : MF) {
for (auto &MI : MBB) {
if (X86II::getMemoryOperandNo(MI.getDesc().TSFlags) < 0)
continue;
if (BypassPrefetchInstructions && IsPrefetchOpcode(MI.getDesc().Opcode))
continue;
const DILocation *DI = MI.getDebugLoc();
bool HasDebug = DI;
if (!HasDebug) {
DI = ReferenceDI;
}
Location L = diToLocation(DI);
DenseSet<unsigned> &Set = Seen[L];
const std::pair<DenseSet<unsigned>::iterator, bool> TryInsert =
Set.insert(DI->getBaseDiscriminator());
if (!TryInsert.second || !HasDebug) {
unsigned BF, DF, CI = 0;
DILocation::decodeDiscriminator(DI->getDiscriminator(), BF, DF, CI);
Optional<unsigned> EncodedDiscriminator = DILocation::encodeDiscriminator(
MemOpDiscriminators[L] + 1, DF, CI);
if (!EncodedDiscriminator) {
LLVM_DEBUG(dbgs() << "Unable to create a unique discriminator "
"for instruction with memory operand in: "
<< DI->getFilename() << " Line: " << DI->getLine()
<< " Column: " << DI->getColumn()
<< ". This is likely due to a large macro expansion. \n");
continue;
}
++MemOpDiscriminators[L];
DI = DI->cloneWithDiscriminator(*EncodedDiscriminator);
assert(DI && "DI should not be nullptr");
updateDebugInfo(&MI, DI);
Changed = true;
std::pair<DenseSet<unsigned>::iterator, bool> MustInsert =
Set.insert(DI->getBaseDiscriminator());
(void)MustInsert; assert(MustInsert.second && "New discriminator shouldn't be present in set");
}
ReferenceDI = DI;
}
}
return Changed;
}
FunctionPass *llvm::createX86DiscriminateMemOpsPass() {
return new X86DiscriminateMemOps();
}