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