X86DiscriminateMemOps.cpp 7.2 KB

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