1 //===- X86DiscriminateMemOps.cpp - Unique IDs for Mem Ops -----------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 ///
10 /// This pass aids profile-driven cache prefetch insertion by ensuring all
11 /// instructions that have a memory operand are distinguishible from each other.
12 ///
13 //===----------------------------------------------------------------------===//
14 
15 #include "X86.h"
16 #include "X86InstrBuilder.h"
17 #include "X86InstrInfo.h"
18 #include "X86MachineFunctionInfo.h"
19 #include "X86Subtarget.h"
20 #include "llvm/CodeGen/MachineModuleInfo.h"
21 #include "llvm/IR/DebugInfoMetadata.h"
22 #include "llvm/ProfileData/SampleProf.h"
23 #include "llvm/ProfileData/SampleProfReader.h"
24 #include "llvm/Transforms/IPO/SampleProfile.h"
25 using namespace llvm;
26 
27 namespace {
28 
29 using Location = std::pair<StringRef, unsigned>;
30 
31 Location diToLocation(const DILocation *Loc) {
32   return std::make_pair(Loc->getFilename(), Loc->getLine());
33 }
34 
35 /// Ensure each instruction having a memory operand has a distinct <LineNumber,
36 /// Discriminator> pair.
37 void updateDebugInfo(MachineInstr *MI, const DILocation *Loc) {
38   DebugLoc DL(Loc);
39   MI->setDebugLoc(DL);
40 }
41 
42 class X86DiscriminateMemOps : public MachineFunctionPass {
43   bool runOnMachineFunction(MachineFunction &MF) override;
44   StringRef getPassName() const override {
45     return "X86 Discriminate Memory Operands";
46   }
47 
48 public:
49   static char ID;
50 
51   /// Default construct and initialize the pass.
52   X86DiscriminateMemOps();
53 };
54 
55 } // end anonymous namespace
56 
57 //===----------------------------------------------------------------------===//
58 //            Implementation
59 //===----------------------------------------------------------------------===//
60 
61 char X86DiscriminateMemOps::ID = 0;
62 
63 /// Default construct and initialize the pass.
64 X86DiscriminateMemOps::X86DiscriminateMemOps() : MachineFunctionPass(ID) {}
65 
66 bool X86DiscriminateMemOps::runOnMachineFunction(MachineFunction &MF) {
67   DISubprogram *FDI = MF.getFunction().getSubprogram();
68   if (!FDI || !FDI->getUnit()->getDebugInfoForProfiling())
69     return false;
70 
71   // Have a default DILocation, if we find instructions with memops that don't
72   // have any debug info.
73   const DILocation *ReferenceDI =
74       DILocation::get(FDI->getContext(), FDI->getLine(), 0, FDI);
75 
76   DenseMap<Location, unsigned> MemOpDiscriminators;
77   MemOpDiscriminators[diToLocation(ReferenceDI)] = 0;
78 
79   // Figure out the largest discriminator issued for each Location. When we
80   // issue new discriminators, we can thus avoid issuing discriminators
81   // belonging to instructions that don't have memops. This isn't a requirement
82   // for the goals of this pass, however, it avoids unnecessary ambiguity.
83   for (auto &MBB : MF) {
84     for (auto &MI : MBB) {
85       const auto &DI = MI.getDebugLoc();
86       if (!DI)
87         continue;
88       Location Loc = diToLocation(DI);
89       MemOpDiscriminators[Loc] =
90           std::max(MemOpDiscriminators[Loc], DI->getBaseDiscriminator());
91     }
92   }
93 
94   // Keep track of the discriminators seen at each Location. If an instruction's
95   // DebugInfo has a Location and discriminator we've already seen, replace its
96   // discriminator with a new one, to guarantee uniqueness.
97   DenseMap<Location, DenseSet<unsigned>> Seen;
98 
99   bool Changed = false;
100   for (auto &MBB : MF) {
101     for (auto &MI : MBB) {
102       if (X86II::getMemoryOperandNo(MI.getDesc().TSFlags) < 0)
103         continue;
104       const DILocation *DI = MI.getDebugLoc();
105       if (!DI) {
106         DI = ReferenceDI;
107       }
108       DenseSet<unsigned> &Set = Seen[diToLocation(DI)];
109       const std::pair<DenseSet<unsigned>::iterator, bool> TryInsert =
110           Set.insert(DI->getBaseDiscriminator());
111       if (!TryInsert.second) {
112         DI = DI->setBaseDiscriminator(++MemOpDiscriminators[diToLocation(DI)]);
113         updateDebugInfo(&MI, DI);
114         Changed = true;
115         const std::pair<DenseSet<unsigned>::iterator, bool> MustInsert =
116             Set.insert(DI->getBaseDiscriminator());
117         (void)MustInsert; // silence warning.
118         assert(MustInsert.second &&
119                "New discriminator shouldn't be present in set");
120       }
121 
122       // Bump the reference DI to avoid cramming discriminators on line 0.
123       // FIXME(mtrofin): pin ReferenceDI on blocks or first instruction with DI
124       // in a block. It's more consistent than just relying on the last memop
125       // instruction we happened to see.
126       ReferenceDI = DI;
127     }
128   }
129   return Changed;
130 }
131 
132 FunctionPass *llvm::createX86DiscriminateMemOpsPass() {
133   return new X86DiscriminateMemOps();
134 }
135