SerialSnippetGenerator.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. //===-- SerialSnippetGenerator.cpp ------------------------------*- C++ -*-===//
  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. #include "SerialSnippetGenerator.h"
  9. #include "CodeTemplate.h"
  10. #include "MCInstrDescView.h"
  11. #include "Target.h"
  12. #include <algorithm>
  13. #include <numeric>
  14. #include <vector>
  15. namespace llvm {
  16. namespace exegesis {
  17. struct ExecutionClass {
  18. ExecutionMode Mask;
  19. const char *Description;
  20. } static const kExecutionClasses[] = {
  21. {ExecutionMode::ALWAYS_SERIAL_IMPLICIT_REGS_ALIAS |
  22. ExecutionMode::ALWAYS_SERIAL_TIED_REGS_ALIAS,
  23. "Repeating a single implicitly serial instruction"},
  24. {ExecutionMode::SERIAL_VIA_EXPLICIT_REGS,
  25. "Repeating a single explicitly serial instruction"},
  26. {ExecutionMode::SERIAL_VIA_MEMORY_INSTR |
  27. ExecutionMode::SERIAL_VIA_NON_MEMORY_INSTR,
  28. "Repeating two instructions"},
  29. };
  30. static constexpr size_t kMaxAliasingInstructions = 10;
  31. static std::vector<const Instruction *>
  32. computeAliasingInstructions(const LLVMState &State, const Instruction *Instr,
  33. size_t MaxAliasingInstructions,
  34. const BitVector &ForbiddenRegisters) {
  35. // Randomly iterate the set of instructions.
  36. std::vector<unsigned> Opcodes;
  37. Opcodes.resize(State.getInstrInfo().getNumOpcodes());
  38. std::iota(Opcodes.begin(), Opcodes.end(), 0U);
  39. llvm::shuffle(Opcodes.begin(), Opcodes.end(), randomGenerator());
  40. std::vector<const Instruction *> AliasingInstructions;
  41. for (const unsigned OtherOpcode : Opcodes) {
  42. if (OtherOpcode == Instr->Description.getOpcode())
  43. continue;
  44. const Instruction &OtherInstr = State.getIC().getInstr(OtherOpcode);
  45. const MCInstrDesc &OtherInstrDesc = OtherInstr.Description;
  46. // Ignore instructions that we cannot run.
  47. if (OtherInstrDesc.isPseudo() || OtherInstrDesc.usesCustomInsertionHook() ||
  48. OtherInstrDesc.isBranch() || OtherInstrDesc.isIndirectBranch() ||
  49. OtherInstrDesc.isCall() || OtherInstrDesc.isReturn()) {
  50. continue;
  51. }
  52. if (OtherInstr.hasMemoryOperands())
  53. continue;
  54. if (!State.getExegesisTarget().allowAsBackToBack(OtherInstr))
  55. continue;
  56. if (Instr->hasAliasingRegistersThrough(OtherInstr, ForbiddenRegisters))
  57. AliasingInstructions.push_back(&OtherInstr);
  58. if (AliasingInstructions.size() >= MaxAliasingInstructions)
  59. break;
  60. }
  61. return AliasingInstructions;
  62. }
  63. static ExecutionMode getExecutionModes(const Instruction &Instr,
  64. const BitVector &ForbiddenRegisters) {
  65. ExecutionMode EM = ExecutionMode::UNKNOWN;
  66. if (Instr.hasAliasingImplicitRegisters())
  67. EM |= ExecutionMode::ALWAYS_SERIAL_IMPLICIT_REGS_ALIAS;
  68. if (Instr.hasTiedRegisters())
  69. EM |= ExecutionMode::ALWAYS_SERIAL_TIED_REGS_ALIAS;
  70. if (Instr.hasMemoryOperands())
  71. EM |= ExecutionMode::SERIAL_VIA_MEMORY_INSTR;
  72. else {
  73. if (Instr.hasAliasingRegisters(ForbiddenRegisters))
  74. EM |= ExecutionMode::SERIAL_VIA_EXPLICIT_REGS;
  75. if (Instr.hasOneUseOrOneDef())
  76. EM |= ExecutionMode::SERIAL_VIA_NON_MEMORY_INSTR;
  77. }
  78. return EM;
  79. }
  80. static void appendCodeTemplates(const LLVMState &State,
  81. InstructionTemplate Variant,
  82. const BitVector &ForbiddenRegisters,
  83. ExecutionMode ExecutionModeBit,
  84. StringRef ExecutionClassDescription,
  85. std::vector<CodeTemplate> &CodeTemplates) {
  86. assert(isEnumValue(ExecutionModeBit) && "Bit must be a power of two");
  87. switch (ExecutionModeBit) {
  88. case ExecutionMode::ALWAYS_SERIAL_IMPLICIT_REGS_ALIAS:
  89. // Nothing to do, the instruction is always serial.
  90. LLVM_FALLTHROUGH;
  91. case ExecutionMode::ALWAYS_SERIAL_TIED_REGS_ALIAS: {
  92. // Picking whatever value for the tied variable will make the instruction
  93. // serial.
  94. CodeTemplate CT;
  95. CT.Execution = ExecutionModeBit;
  96. CT.Info = std::string(ExecutionClassDescription);
  97. CT.Instructions.push_back(std::move(Variant));
  98. CodeTemplates.push_back(std::move(CT));
  99. return;
  100. }
  101. case ExecutionMode::SERIAL_VIA_MEMORY_INSTR: {
  102. // Select back-to-back memory instruction.
  103. // TODO: Implement me.
  104. return;
  105. }
  106. case ExecutionMode::SERIAL_VIA_EXPLICIT_REGS: {
  107. // Making the execution of this instruction serial by selecting one def
  108. // register to alias with one use register.
  109. const AliasingConfigurations SelfAliasing(Variant.getInstr(),
  110. Variant.getInstr());
  111. assert(!SelfAliasing.empty() && !SelfAliasing.hasImplicitAliasing() &&
  112. "Instr must alias itself explicitly");
  113. // This is a self aliasing instruction so defs and uses are from the same
  114. // instance, hence twice Variant in the following call.
  115. setRandomAliasing(SelfAliasing, Variant, Variant);
  116. CodeTemplate CT;
  117. CT.Execution = ExecutionModeBit;
  118. CT.Info = std::string(ExecutionClassDescription);
  119. CT.Instructions.push_back(std::move(Variant));
  120. CodeTemplates.push_back(std::move(CT));
  121. return;
  122. }
  123. case ExecutionMode::SERIAL_VIA_NON_MEMORY_INSTR: {
  124. const Instruction &Instr = Variant.getInstr();
  125. // Select back-to-back non-memory instruction.
  126. for (const auto *OtherInstr : computeAliasingInstructions(
  127. State, &Instr, kMaxAliasingInstructions, ForbiddenRegisters)) {
  128. const AliasingConfigurations Forward(Instr, *OtherInstr);
  129. const AliasingConfigurations Back(*OtherInstr, Instr);
  130. InstructionTemplate ThisIT(Variant);
  131. InstructionTemplate OtherIT(OtherInstr);
  132. if (!Forward.hasImplicitAliasing())
  133. setRandomAliasing(Forward, ThisIT, OtherIT);
  134. else if (!Back.hasImplicitAliasing())
  135. setRandomAliasing(Back, OtherIT, ThisIT);
  136. CodeTemplate CT;
  137. CT.Execution = ExecutionModeBit;
  138. CT.Info = std::string(ExecutionClassDescription);
  139. CT.Instructions.push_back(std::move(ThisIT));
  140. CT.Instructions.push_back(std::move(OtherIT));
  141. CodeTemplates.push_back(std::move(CT));
  142. }
  143. return;
  144. }
  145. default:
  146. llvm_unreachable("Unhandled enum value");
  147. }
  148. }
  149. SerialSnippetGenerator::~SerialSnippetGenerator() = default;
  150. Expected<std::vector<CodeTemplate>>
  151. SerialSnippetGenerator::generateCodeTemplates(
  152. InstructionTemplate Variant, const BitVector &ForbiddenRegisters) const {
  153. std::vector<CodeTemplate> Results;
  154. const ExecutionMode EM =
  155. getExecutionModes(Variant.getInstr(), ForbiddenRegisters);
  156. for (const auto EC : kExecutionClasses) {
  157. for (const auto ExecutionModeBit : getExecutionModeBits(EM & EC.Mask))
  158. appendCodeTemplates(State, Variant, ForbiddenRegisters, ExecutionModeBit,
  159. EC.Description, Results);
  160. if (!Results.empty())
  161. break;
  162. }
  163. if (Results.empty())
  164. return make_error<Failure>(
  165. "No strategy found to make the execution serial");
  166. return std::move(Results);
  167. }
  168. } // namespace exegesis
  169. } // namespace llvm