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/Support/Debug.h"
25 #include "llvm/Transforms/IPO/SampleProfile.h"
26 using namespace llvm;
27 
28 #define DEBUG_TYPE "x86-discriminate-memops"
29 
30 static cl::opt<bool> EnableDiscriminateMemops(
31     DEBUG_TYPE, cl::init(false),
32     cl::desc("Generate unique debug info for each instruction with a memory "
33              "operand. Should be enabled for profile-drived 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."),
36     cl::Hidden);
37 
38 namespace {
39 
40 using Location = std::pair<StringRef, unsigned>;
41 
diToLocation(const DILocation * Loc)42 Location diToLocation(const DILocation *Loc) {
43   return std::make_pair(Loc->getFilename(), Loc->getLine());
44 }
45 
46 /// Ensure each instruction having a memory operand has a distinct <LineNumber,
47 /// Discriminator> pair.
updateDebugInfo(MachineInstr * MI,const DILocation * Loc)48 void updateDebugInfo(MachineInstr *MI, const DILocation *Loc) {
49   DebugLoc DL(Loc);
50   MI->setDebugLoc(DL);
51 }
52 
53 class X86DiscriminateMemOps : public MachineFunctionPass {
54   bool runOnMachineFunction(MachineFunction &MF) override;
getPassName() const55   StringRef getPassName() const override {
56     return "X86 Discriminate Memory Operands";
57   }
58 
59 public:
60   static char ID;
61 
62   /// Default construct and initialize the pass.
63   X86DiscriminateMemOps();
64 };
65 
66 } // end anonymous namespace
67 
68 //===----------------------------------------------------------------------===//
69 //            Implementation
70 //===----------------------------------------------------------------------===//
71 
72 char X86DiscriminateMemOps::ID = 0;
73 
74 /// Default construct and initialize the pass.
X86DiscriminateMemOps()75 X86DiscriminateMemOps::X86DiscriminateMemOps() : MachineFunctionPass(ID) {}
76 
runOnMachineFunction(MachineFunction & MF)77 bool X86DiscriminateMemOps::runOnMachineFunction(MachineFunction &MF) {
78   if (!EnableDiscriminateMemops)
79     return false;
80 
81   DISubprogram *FDI = MF.getFunction().getSubprogram();
82   if (!FDI || !FDI->getUnit()->getDebugInfoForProfiling())
83     return false;
84 
85   // Have a default DILocation, if we find instructions with memops that don't
86   // have any debug info.
87   const DILocation *ReferenceDI =
88       DILocation::get(FDI->getContext(), FDI->getLine(), 0, FDI);
89 
90   DenseMap<Location, unsigned> MemOpDiscriminators;
91   MemOpDiscriminators[diToLocation(ReferenceDI)] = 0;
92 
93   // Figure out the largest discriminator issued for each Location. When we
94   // issue new discriminators, we can thus avoid issuing discriminators
95   // belonging to instructions that don't have memops. This isn't a requirement
96   // for the goals of this pass, however, it avoids unnecessary ambiguity.
97   for (auto &MBB : MF) {
98     for (auto &MI : MBB) {
99       const auto &DI = MI.getDebugLoc();
100       if (!DI)
101         continue;
102       Location Loc = diToLocation(DI);
103       MemOpDiscriminators[Loc] =
104           std::max(MemOpDiscriminators[Loc], DI->getBaseDiscriminator());
105     }
106   }
107 
108   // Keep track of the discriminators seen at each Location. If an instruction's
109   // DebugInfo has a Location and discriminator we've already seen, replace its
110   // discriminator with a new one, to guarantee uniqueness.
111   DenseMap<Location, DenseSet<unsigned>> Seen;
112 
113   bool Changed = false;
114   for (auto &MBB : MF) {
115     for (auto &MI : MBB) {
116       if (X86II::getMemoryOperandNo(MI.getDesc().TSFlags) < 0)
117         continue;
118       const DILocation *DI = MI.getDebugLoc();
119       if (!DI) {
120         DI = ReferenceDI;
121       }
122       Location L = diToLocation(DI);
123       DenseSet<unsigned> &Set = Seen[L];
124       const std::pair<DenseSet<unsigned>::iterator, bool> TryInsert =
125           Set.insert(DI->getBaseDiscriminator());
126       if (!TryInsert.second) {
127         unsigned BF, DF, CI = 0;
128         DILocation::decodeDiscriminator(DI->getDiscriminator(), BF, DF, CI);
129         Optional<unsigned> EncodedDiscriminator = DILocation::encodeDiscriminator(
130             MemOpDiscriminators[L] + 1, DF, CI);
131 
132         if (!EncodedDiscriminator) {
133           // FIXME(mtrofin): The assumption is that this scenario is infrequent/OK
134           // not to support. If evidence points otherwise, we can explore synthesizeing
135           // unique DIs by adding fake line numbers, or by constructing 64 bit
136           // discriminators.
137           LLVM_DEBUG(dbgs() << "Unable to create a unique discriminator "
138                      "for instruction with memory operand in: "
139                      << DI->getFilename() << " Line: " << DI->getLine()
140                      << " Column: " << DI->getColumn()
141                      << ". This is likely due to a large macro expansion. \n");
142           continue;
143         }
144         // Since we were able to encode, bump the MemOpDiscriminators.
145         ++MemOpDiscriminators[L];
146         DI = DI->cloneWithDiscriminator(EncodedDiscriminator.getValue());
147         updateDebugInfo(&MI, DI);
148         Changed = true;
149         std::pair<DenseSet<unsigned>::iterator, bool> MustInsert =
150             Set.insert(DI->getBaseDiscriminator());
151         (void)MustInsert; // Silence warning in release build.
152         assert(MustInsert.second && "New discriminator shouldn't be present in set");
153       }
154 
155       // Bump the reference DI to avoid cramming discriminators on line 0.
156       // FIXME(mtrofin): pin ReferenceDI on blocks or first instruction with DI
157       // in a block. It's more consistent than just relying on the last memop
158       // instruction we happened to see.
159       ReferenceDI = DI;
160     }
161   }
162   return Changed;
163 }
164 
createX86DiscriminateMemOpsPass()165 FunctionPass *llvm::createX86DiscriminateMemOpsPass() {
166   return new X86DiscriminateMemOps();
167 }
168