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