X86DiscriminateMemOps.cpp 7.1 KB

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