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