ReduceOperandsSkip.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. //===----------------------------------------------------------------------===//
  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 "ReduceOperandsSkip.h"
  9. #include "llvm/ADT/Sequence.h"
  10. #include "llvm/ADT/SetVector.h"
  11. #include "llvm/IR/Constants.h"
  12. #include "llvm/IR/Dominators.h"
  13. #include "llvm/IR/InstIterator.h"
  14. #include "llvm/IR/Instructions.h"
  15. #include "llvm/IR/Operator.h"
  16. using namespace llvm;
  17. /// Collect all values that are directly or indirectly referenced by @p Root,
  18. /// including Root itself. This is a BF search such that the more steps needed
  19. /// to get to the reference, the more behind it is found in @p Collection. Each
  20. /// step could be its own reduction, therefore we consider later values "more
  21. /// reduced".
  22. static SetVector<Value *> collectReferencedValues(Value *Root) {
  23. SetVector<Value *> Refs;
  24. std::deque<Value *> Worklist;
  25. Worklist.push_back(Root);
  26. while (!Worklist.empty()) {
  27. Value *Val = Worklist.front();
  28. Worklist.pop_front();
  29. if (!Refs.insert(Val))
  30. continue;
  31. if (auto *O = dyn_cast<Operator>(Val)) {
  32. for (Use &Op : O->operands())
  33. Worklist.push_back(Op.get());
  34. }
  35. }
  36. return Refs;
  37. }
  38. static bool shouldReduceOperand(Use &Op) {
  39. Type *Ty = Op->getType();
  40. if (Ty->isLabelTy() || Ty->isMetadataTy())
  41. return false;
  42. // TODO: be more precise about which GEP operands we can reduce (e.g. array
  43. // indexes)
  44. if (isa<GEPOperator>(Op.getUser()))
  45. return false;
  46. if (auto *CB = dyn_cast<CallBase>(Op.getUser())) {
  47. if (&CB->getCalledOperandUse() == &Op)
  48. return false;
  49. }
  50. return true;
  51. }
  52. /// Return a reduction priority for @p V. A higher values means "more reduced".
  53. static int classifyReductivePower(Value *V) {
  54. if (auto *C = dyn_cast<ConstantData>(V)) {
  55. if (isa<UndefValue>(V))
  56. return 4;
  57. if (C->isNullValue())
  58. return 7;
  59. if (C->isOneValue())
  60. return 6;
  61. return 5;
  62. }
  63. if (isa<Argument>(V))
  64. return 3;
  65. if (isa<GlobalValue>(V))
  66. return 2;
  67. if (isa<Constant>(V))
  68. return 1;
  69. if (isa<Instruction>(V))
  70. return -1;
  71. return 0;
  72. }
  73. /// Calls @p Callback for every reduction opportunity in @p F. Used by
  74. /// countOperands() and extractOperandsFromModule() to ensure consistency
  75. /// between the two.
  76. static void
  77. opportunities(Function &F,
  78. function_ref<void(Use &, ArrayRef<Value *>)> Callback) {
  79. if (F.isDeclaration())
  80. return;
  81. // Need DominatorTree to find out whether an SSA value can be referenced.
  82. DominatorTree DT(F);
  83. // Return whether @p LHS is "more reduced" that @p RHS. That is, whether
  84. // @p RHS should be preferred over @p LHS in a reduced output. This is a
  85. // partial order, a Value may not be preferable over another.
  86. auto IsMoreReduced = [&DT](Value *LHS, Value *RHS) -> bool {
  87. // A value is not more reduced than itself.
  88. if (LHS == RHS)
  89. return false;
  90. int ReductivePowerDiff =
  91. classifyReductivePower(RHS) - classifyReductivePower(LHS);
  92. if (ReductivePowerDiff != 0)
  93. return ReductivePowerDiff < 0;
  94. // LHS is more reduced if it is defined further up the dominance tree. In a
  95. // chain of definitions,
  96. //
  97. // %a = ..
  98. // %b = op %a
  99. // %c = op %b
  100. //
  101. // every use of %b can be replaced by %a, but not by a use of %c. That is, a
  102. // use %c can be replaced in steps first by %b, then by %a, making %a the
  103. // "more reduced" choice that skips over more instructions.
  104. auto *LHSInst = dyn_cast<Instruction>(LHS);
  105. auto *RHSInst = dyn_cast<Instruction>(RHS);
  106. if (LHSInst && RHSInst) {
  107. if (DT.dominates(LHSInst, RHSInst))
  108. return true;
  109. }
  110. // Compress the number of used arguments by prefering the first ones. Unused
  111. // trailing argument can be removed by the arguments pass.
  112. auto *LHSArg = dyn_cast<Argument>(LHS);
  113. auto *RHSArg = dyn_cast<Argument>(RHS);
  114. if (LHSArg && RHSArg) {
  115. if (LHSArg->getArgNo() < RHSArg->getArgNo())
  116. return true;
  117. }
  118. return false;
  119. };
  120. for (Instruction &I : instructions(&F)) {
  121. for (Use &Op : I.operands()) {
  122. if (!shouldReduceOperand(Op))
  123. continue;
  124. Value *OpVal = Op.get();
  125. // Collect refenced values as potential replacement candidates.
  126. SetVector<Value *> ReferencedVals = collectReferencedValues(OpVal);
  127. // Regardless whether referenced, add the function arguments as
  128. // replacement possibility with the goal of reducing the number of (used)
  129. // function arguments, possibly created by the the operands-to-args.
  130. for (Argument &Arg : F.args())
  131. ReferencedVals.insert(&Arg);
  132. // After all candidates have been added, it doesn't need to be a set
  133. // anymore.
  134. std::vector<Value *> Candidates = ReferencedVals.takeVector();
  135. // Remove ineligible candidates.
  136. llvm::erase_if(Candidates, [&, OpVal](Value *V) {
  137. // Candidate value must have the same type.
  138. if (OpVal->getType() != V->getType())
  139. return true;
  140. // Only consider candidates that are "more reduced" than the original
  141. // value. This explicitly also rules out candidates with the same
  142. // reduction power. This is to ensure that repeated invocations of this
  143. // pass eventually reach a fixpoint without switch back and forth
  144. // between two opportunities with the same reductive power.
  145. return !IsMoreReduced(V, OpVal);
  146. });
  147. if (Candidates.empty())
  148. continue;
  149. // collectReferencedValues pushed the more reductive values to the end of
  150. // the collection, but we need them at the front.
  151. std::reverse(Candidates.begin(), Candidates.end());
  152. // Independency of collectReferencedValues's idea of reductive power,
  153. // ensure the the partial order of IsMoreReduced is enforced.
  154. llvm::stable_sort(Candidates, IsMoreReduced);
  155. Callback(Op, Candidates);
  156. }
  157. }
  158. }
  159. static void extractOperandsFromModule(Oracle &O, Module &Program) {
  160. for (Function &F : Program.functions()) {
  161. SmallVector<std::pair<Use *, Value *>> Replacements;
  162. opportunities(F, [&](Use &Op, ArrayRef<Value *> Candidates) {
  163. // Only apply the candidate the Oracle selected to keep that is the most
  164. // reduced. Candidates with less reductive power can be interpreted as an
  165. // intermediate step that is immediately replaced with the more reduced
  166. // one. The number of shouldKeep() calls must be independent of the result
  167. // of previous shouldKeep() calls to keep the total number of calls
  168. // in-sync with what countOperands() has computed.
  169. bool AlreadyReplaced = false;
  170. for (Value *C : Candidates) {
  171. bool Keep = O.shouldKeep();
  172. if (AlreadyReplaced || Keep)
  173. continue;
  174. // Replacing the operand value immediately would influence the candidate
  175. // set for the following operands. Delay it until after all candidates
  176. // have been determined.
  177. Replacements.push_back({&Op, C});
  178. AlreadyReplaced = true;
  179. }
  180. });
  181. for (std::pair<Use *, Value *> P : Replacements)
  182. P.first->set(P.second);
  183. }
  184. }
  185. void llvm::reduceOperandsSkipDeltaPass(TestRunner &Test) {
  186. errs() << "*** Reducing operands by skipping over instructions ...\n";
  187. runDeltaPass(Test, extractOperandsFromModule);
  188. }