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