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