19248fde5SEugene Zelenko //===- ForwardOpTree.h ------------------------------------------*- C++ -*-===//
2a6b2de3bSMichael Kruse //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a6b2de3bSMichael Kruse //
7a6b2de3bSMichael Kruse //===----------------------------------------------------------------------===//
8a6b2de3bSMichael Kruse //
9a6b2de3bSMichael Kruse // Move instructions between statements.
10a6b2de3bSMichael Kruse //
11a6b2de3bSMichael Kruse //===----------------------------------------------------------------------===//
12a6b2de3bSMichael Kruse
13a6b2de3bSMichael Kruse #include "polly/ForwardOpTree.h"
1470af4f57SMichael Kruse #include "polly/Options.h"
1507e8c36dSMichael Kruse #include "polly/ScopBuilder.h"
16a6b2de3bSMichael Kruse #include "polly/ScopInfo.h"
17a6b2de3bSMichael Kruse #include "polly/ScopPass.h"
18a6b2de3bSMichael Kruse #include "polly/Support/GICHelper.h"
1970af4f57SMichael Kruse #include "polly/Support/ISLOStream.h"
2070af4f57SMichael Kruse #include "polly/Support/ISLTools.h"
21a6b2de3bSMichael Kruse #include "polly/Support/VirtualInstruction.h"
2270af4f57SMichael Kruse #include "polly/ZoneAlgo.h"
239248fde5SEugene Zelenko #include "llvm/ADT/STLExtras.h"
249248fde5SEugene Zelenko #include "llvm/ADT/SmallVector.h"
259248fde5SEugene Zelenko #include "llvm/ADT/Statistic.h"
269248fde5SEugene Zelenko #include "llvm/Analysis/LoopInfo.h"
27a6b2de3bSMichael Kruse #include "llvm/Analysis/ValueTracking.h"
289248fde5SEugene Zelenko #include "llvm/IR/Instruction.h"
299248fde5SEugene Zelenko #include "llvm/IR/Instructions.h"
309248fde5SEugene Zelenko #include "llvm/IR/Value.h"
3105da2fe5SReid Kleckner #include "llvm/InitializePasses.h"
329248fde5SEugene Zelenko #include "llvm/Support/Casting.h"
339248fde5SEugene Zelenko #include "llvm/Support/CommandLine.h"
349248fde5SEugene Zelenko #include "llvm/Support/Compiler.h"
359248fde5SEugene Zelenko #include "llvm/Support/Debug.h"
369248fde5SEugene Zelenko #include "llvm/Support/ErrorHandling.h"
379248fde5SEugene Zelenko #include "llvm/Support/raw_ostream.h"
389248fde5SEugene Zelenko #include "isl/ctx.h"
399248fde5SEugene Zelenko #include "isl/isl-noexceptions.h"
409248fde5SEugene Zelenko #include <cassert>
419248fde5SEugene Zelenko #include <memory>
42a6b2de3bSMichael Kruse
4336550bacSMichael Kruse #define DEBUG_TYPE "polly-optree"
44a6b2de3bSMichael Kruse
45a6b2de3bSMichael Kruse using namespace llvm;
469248fde5SEugene Zelenko using namespace polly;
47a6b2de3bSMichael Kruse
4870af4f57SMichael Kruse static cl::opt<bool>
4970af4f57SMichael Kruse AnalyzeKnown("polly-optree-analyze-known",
5070af4f57SMichael Kruse cl::desc("Analyze array contents for load forwarding"),
5170af4f57SMichael Kruse cl::cat(PollyCategory), cl::init(true), cl::Hidden);
5270af4f57SMichael Kruse
5368821a8bSMichael Kruse static cl::opt<bool>
5468821a8bSMichael Kruse NormalizePHIs("polly-optree-normalize-phi",
5568821a8bSMichael Kruse cl::desc("Replace PHIs by their incoming values"),
5668821a8bSMichael Kruse cl::cat(PollyCategory), cl::init(false), cl::Hidden);
5768821a8bSMichael Kruse
58ef8325baSMichael Kruse static cl::opt<unsigned>
5970af4f57SMichael Kruse MaxOps("polly-optree-max-ops",
6070af4f57SMichael Kruse cl::desc("Maximum number of ISL operations to invest for known "
6170af4f57SMichael Kruse "analysis; 0=no limit"),
6270af4f57SMichael Kruse cl::init(1000000), cl::cat(PollyCategory), cl::Hidden);
6370af4f57SMichael Kruse
6470af4f57SMichael Kruse STATISTIC(KnownAnalyzed, "Number of successfully analyzed SCoPs");
6570af4f57SMichael Kruse STATISTIC(KnownOutOfQuota,
6670af4f57SMichael Kruse "Analyses aborted because max_operations was reached");
6770af4f57SMichael Kruse
68a6b2de3bSMichael Kruse STATISTIC(TotalInstructionsCopied, "Number of copied instructions");
6970af4f57SMichael Kruse STATISTIC(TotalKnownLoadsForwarded,
7070af4f57SMichael Kruse "Number of forwarded loads because their value was known");
71822dfe27SMichael Kruse STATISTIC(TotalReloads, "Number of reloaded values");
7207e8c36dSMichael Kruse STATISTIC(TotalReadOnlyCopied, "Number of copied read-only accesses");
73a6b2de3bSMichael Kruse STATISTIC(TotalForwardedTrees, "Number of forwarded operand trees");
74a6b2de3bSMichael Kruse STATISTIC(TotalModifiedStmts,
75a6b2de3bSMichael Kruse "Number of statements with at least one forwarded tree");
76a6b2de3bSMichael Kruse
77a6b2de3bSMichael Kruse STATISTIC(ScopsModified, "Number of SCoPs with at least one forwarded tree");
78a6b2de3bSMichael Kruse
7906ed5292SMichael Kruse STATISTIC(NumValueWrites, "Number of scalar value writes after OpTree");
8006ed5292SMichael Kruse STATISTIC(NumValueWritesInLoops,
8106ed5292SMichael Kruse "Number of scalar value writes nested in affine loops after OpTree");
8206ed5292SMichael Kruse STATISTIC(NumPHIWrites, "Number of scalar phi writes after OpTree");
8306ed5292SMichael Kruse STATISTIC(NumPHIWritesInLoops,
8406ed5292SMichael Kruse "Number of scalar phi writes nested in affine loops after OpTree");
8506ed5292SMichael Kruse STATISTIC(NumSingletonWrites, "Number of singleton writes after OpTree");
8606ed5292SMichael Kruse STATISTIC(NumSingletonWritesInLoops,
8706ed5292SMichael Kruse "Number of singleton writes nested in affine loops after OpTree");
8806ed5292SMichael Kruse
89a6b2de3bSMichael Kruse namespace {
90a6b2de3bSMichael Kruse
91a6b2de3bSMichael Kruse /// The state of whether an operand tree was/can be forwarded.
92d85e345cSMichael Kruse ///
93d85e345cSMichael Kruse /// The items apply to an instructions and its operand tree with the instruction
94d85e345cSMichael Kruse /// as the root element. If the value in question is not an instruction in the
95d85e345cSMichael Kruse /// SCoP, it can be a leaf of an instruction's operand tree.
96a6b2de3bSMichael Kruse enum ForwardingDecision {
977175cffbSMichael Kruse /// An uninitialized value.
987175cffbSMichael Kruse FD_Unknown,
997175cffbSMichael Kruse
100d85e345cSMichael Kruse /// The root instruction or value cannot be forwarded at all.
101a6b2de3bSMichael Kruse FD_CannotForward,
102d85e345cSMichael Kruse
103d85e345cSMichael Kruse /// The root instruction or value can be forwarded as a leaf of a larger
104d85e345cSMichael Kruse /// operand tree.
105d85e345cSMichael Kruse /// It does not make sense to move the value itself, it would just replace it
106d85e345cSMichael Kruse /// by a use of itself. For instance, a constant "5" used in a statement can
107d85e345cSMichael Kruse /// be forwarded, but it would just replace it by the same constant "5".
108d85e345cSMichael Kruse /// However, it makes sense to move as an operand of
109d85e345cSMichael Kruse ///
110d85e345cSMichael Kruse /// %add = add 5, 5
111d85e345cSMichael Kruse ///
112d85e345cSMichael Kruse /// where "5" is moved as part of a larger operand tree. "5" would be placed
113d85e345cSMichael Kruse /// (disregarding for a moment that literal constants don't have a location
114d85e345cSMichael Kruse /// and can be used anywhere) into the same statement as %add would.
11567752076SMichael Kruse FD_CanForwardLeaf,
116d85e345cSMichael Kruse
117822dfe27SMichael Kruse /// The root instruction can be forwarded and doing so avoids a scalar
118822dfe27SMichael Kruse /// dependency.
119822dfe27SMichael Kruse ///
120822dfe27SMichael Kruse /// This can be either because the operand tree can be moved to the target
121822dfe27SMichael Kruse /// statement, or a memory access is redirected to read from a different
122822dfe27SMichael Kruse /// location.
123822dfe27SMichael Kruse FD_CanForwardProfitably,
124d85e345cSMichael Kruse
125a9a70863SMichael Kruse /// A forwarding method cannot be applied to the operand tree.
126a9a70863SMichael Kruse /// The difference to FD_CannotForward is that there might be other methods
127a9a70863SMichael Kruse /// that can handle it.
128a9a70863SMichael Kruse FD_NotApplicable
129a6b2de3bSMichael Kruse };
130a6b2de3bSMichael Kruse
1317175cffbSMichael Kruse /// Represents the evaluation of and action to taken when forwarding a value
1327175cffbSMichael Kruse /// from an operand tree.
1337175cffbSMichael Kruse struct ForwardingAction {
1347175cffbSMichael Kruse using KeyTy = std::pair<Value *, ScopStmt *>;
1357175cffbSMichael Kruse
1367175cffbSMichael Kruse /// Evaluation of forwarding a value.
1377175cffbSMichael Kruse ForwardingDecision Decision = FD_Unknown;
1387175cffbSMichael Kruse
1397175cffbSMichael Kruse /// Callback to execute the forwarding.
1407175cffbSMichael Kruse /// Returning true allows deleting the polly::MemoryAccess if the value is the
1417175cffbSMichael Kruse /// root of the operand tree (and its elimination the reason why the
1427175cffbSMichael Kruse /// forwarding is done). Return false if the MemoryAccess is reused or there
1437175cffbSMichael Kruse /// might be other users of the read accesses. In the letter case the
1447175cffbSMichael Kruse /// polly::SimplifyPass can remove dead MemoryAccesses.
__anon533823240202__anon533823240111::ForwardingAction1457175cffbSMichael Kruse std::function<bool()> Execute = []() -> bool {
1467175cffbSMichael Kruse llvm_unreachable("unspecified how to forward");
1477175cffbSMichael Kruse };
1487175cffbSMichael Kruse
1497175cffbSMichael Kruse /// Other values that need to be forwarded if this action is executed. Their
1507175cffbSMichael Kruse /// actions are executed after this one.
1517175cffbSMichael Kruse SmallVector<KeyTy, 4> Depends;
1527175cffbSMichael Kruse
1537175cffbSMichael Kruse /// Named ctor: The method creating this object does not apply to the kind of
1547175cffbSMichael Kruse /// value, but other methods may.
notApplicable__anon533823240111::ForwardingAction1557175cffbSMichael Kruse static ForwardingAction notApplicable() {
1567175cffbSMichael Kruse ForwardingAction Result;
1577175cffbSMichael Kruse Result.Decision = FD_NotApplicable;
1587175cffbSMichael Kruse return Result;
1597175cffbSMichael Kruse }
1607175cffbSMichael Kruse
1617175cffbSMichael Kruse /// Named ctor: The value cannot be forwarded.
cannotForward__anon533823240111::ForwardingAction1627175cffbSMichael Kruse static ForwardingAction cannotForward() {
1637175cffbSMichael Kruse ForwardingAction Result;
1647175cffbSMichael Kruse Result.Decision = FD_CannotForward;
1657175cffbSMichael Kruse return Result;
1667175cffbSMichael Kruse }
1677175cffbSMichael Kruse
1687175cffbSMichael Kruse /// Named ctor: The value can just be used without any preparation.
triviallyForwardable__anon533823240111::ForwardingAction169c1cf51e7SMichael Kruse static ForwardingAction triviallyForwardable(bool IsProfitable, Value *Val) {
1707175cffbSMichael Kruse ForwardingAction Result;
1717175cffbSMichael Kruse Result.Decision =
1727175cffbSMichael Kruse IsProfitable ? FD_CanForwardProfitably : FD_CanForwardLeaf;
173c1cf51e7SMichael Kruse Result.Execute = [=]() {
174c1cf51e7SMichael Kruse LLVM_DEBUG(dbgs() << " trivially forwarded: " << *Val << "\n");
175c1cf51e7SMichael Kruse return true;
176c1cf51e7SMichael Kruse };
1777175cffbSMichael Kruse return Result;
1787175cffbSMichael Kruse }
1797175cffbSMichael Kruse
1807175cffbSMichael Kruse /// Name ctor: The value can be forwarded by executing an action.
canForward__anon533823240111::ForwardingAction1817175cffbSMichael Kruse static ForwardingAction canForward(std::function<bool()> Execute,
1827175cffbSMichael Kruse ArrayRef<KeyTy> Depends,
1837175cffbSMichael Kruse bool IsProfitable) {
1847175cffbSMichael Kruse ForwardingAction Result;
1857175cffbSMichael Kruse Result.Decision =
1867175cffbSMichael Kruse IsProfitable ? FD_CanForwardProfitably : FD_CanForwardLeaf;
1877175cffbSMichael Kruse Result.Execute = std::move(Execute);
1887175cffbSMichael Kruse Result.Depends.append(Depends.begin(), Depends.end());
1897175cffbSMichael Kruse return Result;
1907175cffbSMichael Kruse }
1917175cffbSMichael Kruse };
1927175cffbSMichael Kruse
193a6b2de3bSMichael Kruse /// Implementation of operand tree forwarding for a specific SCoP.
194a6b2de3bSMichael Kruse ///
195a6b2de3bSMichael Kruse /// For a statement that requires a scalar value (through a value read
196a6b2de3bSMichael Kruse /// MemoryAccess), see if its operand can be moved into the statement. If so,
197a6b2de3bSMichael Kruse /// the MemoryAccess is removed and the all the operand tree instructions are
198a6b2de3bSMichael Kruse /// moved into the statement. All original instructions are left in the source
199a6b2de3bSMichael Kruse /// statements. The simplification pass can clean these up.
200*bd93df93SMichael Kruse class ForwardOpTreeImpl final : ZoneAlgorithm {
201a6b2de3bSMichael Kruse private:
2027175cffbSMichael Kruse using MemoizationTy = DenseMap<ForwardingAction::KeyTy, ForwardingAction>;
2037175cffbSMichael Kruse
20489972e21SMichael Kruse /// Scope guard to limit the number of isl operations for this pass.
20589972e21SMichael Kruse IslMaxOperationsGuard &MaxOpGuard;
20689972e21SMichael Kruse
207a6b2de3bSMichael Kruse /// How many instructions have been copied to other statements.
208a6b2de3bSMichael Kruse int NumInstructionsCopied = 0;
209a6b2de3bSMichael Kruse
21070af4f57SMichael Kruse /// Number of loads forwarded because their value was known.
21170af4f57SMichael Kruse int NumKnownLoadsForwarded = 0;
21270af4f57SMichael Kruse
213822dfe27SMichael Kruse /// Number of values reloaded from known array elements.
214822dfe27SMichael Kruse int NumReloads = 0;
215822dfe27SMichael Kruse
21607e8c36dSMichael Kruse /// How many read-only accesses have been copied.
21707e8c36dSMichael Kruse int NumReadOnlyCopied = 0;
21807e8c36dSMichael Kruse
219a6b2de3bSMichael Kruse /// How many operand trees have been forwarded.
220a6b2de3bSMichael Kruse int NumForwardedTrees = 0;
221a6b2de3bSMichael Kruse
222a6b2de3bSMichael Kruse /// Number of statements with at least one forwarded operand tree.
223a6b2de3bSMichael Kruse int NumModifiedStmts = 0;
224a6b2de3bSMichael Kruse
225a6b2de3bSMichael Kruse /// Whether we carried out at least one change to the SCoP.
226a6b2de3bSMichael Kruse bool Modified = false;
227a6b2de3bSMichael Kruse
2287175cffbSMichael Kruse /// Cache of how to forward values.
2297175cffbSMichael Kruse /// The key of this map is the llvm::Value to be forwarded and the
2307175cffbSMichael Kruse /// polly::ScopStmt it is forwarded from. This is because the same llvm::Value
2317175cffbSMichael Kruse /// can evaluate differently depending on where it is evaluate. For instance,
2327175cffbSMichael Kruse /// a synthesizable Scev represents a recurrence with an loop but the loop's
2337175cffbSMichael Kruse /// exit value if evaluated after the loop.
2347175cffbSMichael Kruse /// The cached results are only valid for the current TargetStmt.
2357175cffbSMichael Kruse /// CHECKME: ScalarEvolution::getScevAtScope should take care for getting the
2367175cffbSMichael Kruse /// exit value when instantiated outside of the loop. The primary concern is
2377175cffbSMichael Kruse /// ambiguity when crossing PHI nodes, which currently is not supported.
2387175cffbSMichael Kruse MemoizationTy ForwardingActions;
2397175cffbSMichael Kruse
24070af4f57SMichael Kruse /// Contains the zones where array elements are known to contain a specific
24170af4f57SMichael Kruse /// value.
24270af4f57SMichael Kruse /// { [Element[] -> Zone[]] -> ValInst[] }
24370af4f57SMichael Kruse /// @see computeKnown()
24470af4f57SMichael Kruse isl::union_map Known;
24570af4f57SMichael Kruse
24670af4f57SMichael Kruse /// Translator for newly introduced ValInsts to already existing ValInsts such
24770af4f57SMichael Kruse /// that new introduced load instructions can reuse the Known analysis of its
24870af4f57SMichael Kruse /// original load. { ValInst[] -> ValInst[] }
24970af4f57SMichael Kruse isl::union_map Translator;
25070af4f57SMichael Kruse
25170af4f57SMichael Kruse /// Get list of array elements that do contain the same ValInst[] at Domain[].
25270af4f57SMichael Kruse ///
25370af4f57SMichael Kruse /// @param ValInst { Domain[] -> ValInst[] }
25470af4f57SMichael Kruse /// The values for which we search for alternative locations,
25570af4f57SMichael Kruse /// per statement instance.
25670af4f57SMichael Kruse ///
25770af4f57SMichael Kruse /// @return { Domain[] -> Element[] }
25870af4f57SMichael Kruse /// For each statement instance, the array elements that contain the
25970af4f57SMichael Kruse /// same ValInst.
findSameContentElements(isl::union_map ValInst)26070af4f57SMichael Kruse isl::union_map findSameContentElements(isl::union_map ValInst) {
261e276e9f3SMichael Kruse assert(!ValInst.is_single_valued().is_false());
26270af4f57SMichael Kruse
26370af4f57SMichael Kruse // { Domain[] }
26470af4f57SMichael Kruse isl::union_set Domain = ValInst.domain();
26570af4f57SMichael Kruse
26670af4f57SMichael Kruse // { Domain[] -> Scatter[] }
26770af4f57SMichael Kruse isl::union_map Schedule = getScatterFor(Domain);
26870af4f57SMichael Kruse
26970af4f57SMichael Kruse // { Element[] -> [Scatter[] -> ValInst[]] }
27070af4f57SMichael Kruse isl::union_map MustKnownCurried =
27170af4f57SMichael Kruse convertZoneToTimepoints(Known, isl::dim::in, false, true).curry();
27270af4f57SMichael Kruse
27370af4f57SMichael Kruse // { [Domain[] -> ValInst[]] -> Scatter[] }
27470af4f57SMichael Kruse isl::union_map DomValSched = ValInst.domain_map().apply_range(Schedule);
27570af4f57SMichael Kruse
27670af4f57SMichael Kruse // { [Scatter[] -> ValInst[]] -> [Domain[] -> ValInst[]] }
27770af4f57SMichael Kruse isl::union_map SchedValDomVal =
27870af4f57SMichael Kruse DomValSched.range_product(ValInst.range_map()).reverse();
27970af4f57SMichael Kruse
28070af4f57SMichael Kruse // { Element[] -> [Domain[] -> ValInst[]] }
28170af4f57SMichael Kruse isl::union_map MustKnownInst = MustKnownCurried.apply_range(SchedValDomVal);
28270af4f57SMichael Kruse
28370af4f57SMichael Kruse // { Domain[] -> Element[] }
28470af4f57SMichael Kruse isl::union_map MustKnownMap =
28570af4f57SMichael Kruse MustKnownInst.uncurry().domain().unwrap().reverse();
28670af4f57SMichael Kruse simplify(MustKnownMap);
28770af4f57SMichael Kruse
28870af4f57SMichael Kruse return MustKnownMap;
28970af4f57SMichael Kruse }
29070af4f57SMichael Kruse
29170af4f57SMichael Kruse /// Find a single array element for each statement instance, within a single
29270af4f57SMichael Kruse /// array.
29370af4f57SMichael Kruse ///
29470af4f57SMichael Kruse /// @param MustKnown { Domain[] -> Element[] }
29570af4f57SMichael Kruse /// Set of candidate array elements.
29670af4f57SMichael Kruse /// @param Domain { Domain[] }
29770af4f57SMichael Kruse /// The statement instance for which we need elements for.
29870af4f57SMichael Kruse ///
29970af4f57SMichael Kruse /// @return { Domain[] -> Element[] }
30070af4f57SMichael Kruse /// For each statement instance, an array element out of @p MustKnown.
30170af4f57SMichael Kruse /// All array elements must be in the same array (Polly does not yet
30270af4f57SMichael Kruse /// support reading from different accesses using the same
30370af4f57SMichael Kruse /// MemoryAccess). If no mapping for all of @p Domain exists, returns
30470af4f57SMichael Kruse /// null.
singleLocation(isl::union_map MustKnown,isl::set Domain)30570af4f57SMichael Kruse isl::map singleLocation(isl::union_map MustKnown, isl::set Domain) {
30670af4f57SMichael Kruse // { Domain[] -> Element[] }
30770af4f57SMichael Kruse isl::map Result;
30870af4f57SMichael Kruse
3093b9677e1SMichael Kruse // Make irrelevant elements not interfere.
3103b9677e1SMichael Kruse Domain = Domain.intersect_params(S->getContext());
3113b9677e1SMichael Kruse
31270af4f57SMichael Kruse // MemoryAccesses can read only elements from a single array
31370af4f57SMichael Kruse // (i.e. not: { Dom[0] -> A[0]; Dom[1] -> B[1] }).
31470af4f57SMichael Kruse // Look through all spaces until we find one that contains at least the
31570af4f57SMichael Kruse // wanted statement instance.s
31691f851b1STobias Grosser for (isl::map Map : MustKnown.get_map_list()) {
31770af4f57SMichael Kruse // Get the array this is accessing.
31870af4f57SMichael Kruse isl::id ArrayId = Map.get_tuple_id(isl::dim::out);
31970af4f57SMichael Kruse ScopArrayInfo *SAI = static_cast<ScopArrayInfo *>(ArrayId.get_user());
32070af4f57SMichael Kruse
32170af4f57SMichael Kruse // No support for generation of indirect array accesses.
32270af4f57SMichael Kruse if (SAI->getBasePtrOriginSAI())
32391f851b1STobias Grosser continue;
32470af4f57SMichael Kruse
32570af4f57SMichael Kruse // Determine whether this map contains all wanted values.
32670af4f57SMichael Kruse isl::set MapDom = Map.domain();
32770af4f57SMichael Kruse if (!Domain.is_subset(MapDom).is_true())
32891f851b1STobias Grosser continue;
32970af4f57SMichael Kruse
33070af4f57SMichael Kruse // There might be multiple array elements that contain the same value, but
33170af4f57SMichael Kruse // choose only one of them. lexmin is used because it returns a one-value
33270af4f57SMichael Kruse // mapping, we do not care about which one.
33370af4f57SMichael Kruse // TODO: Get the simplest access function.
33470af4f57SMichael Kruse Result = Map.lexmin();
33591f851b1STobias Grosser break;
33691f851b1STobias Grosser }
33770af4f57SMichael Kruse
33870af4f57SMichael Kruse return Result;
33970af4f57SMichael Kruse }
34070af4f57SMichael Kruse
34170af4f57SMichael Kruse public:
ForwardOpTreeImpl(Scop * S,LoopInfo * LI,IslMaxOperationsGuard & MaxOpGuard)34289972e21SMichael Kruse ForwardOpTreeImpl(Scop *S, LoopInfo *LI, IslMaxOperationsGuard &MaxOpGuard)
34389972e21SMichael Kruse : ZoneAlgorithm("polly-optree", S, LI), MaxOpGuard(MaxOpGuard) {}
3449248fde5SEugene Zelenko
34570af4f57SMichael Kruse /// Compute the zones of known array element contents.
34670af4f57SMichael Kruse ///
34770af4f57SMichael Kruse /// @return True if the computed #Known is usable.
computeKnownValues()34870af4f57SMichael Kruse bool computeKnownValues() {
34970af4f57SMichael Kruse isl::union_map MustKnown, KnownFromLoad, KnownFromInit;
35070af4f57SMichael Kruse
35170af4f57SMichael Kruse // Check that nothing strange occurs.
35247281843SMichael Kruse collectCompatibleElts();
35370af4f57SMichael Kruse
35470af4f57SMichael Kruse {
35589972e21SMichael Kruse IslQuotaScope QuotaScope = MaxOpGuard.enter();
35670af4f57SMichael Kruse
35770af4f57SMichael Kruse computeCommon();
35868821a8bSMichael Kruse if (NormalizePHIs)
35968821a8bSMichael Kruse computeNormalizedPHIs();
36070af4f57SMichael Kruse Known = computeKnown(true, true);
36170af4f57SMichael Kruse
36270af4f57SMichael Kruse // Preexisting ValInsts use the known content analysis of themselves.
36370af4f57SMichael Kruse Translator = makeIdentityMap(Known.range(), false);
36470af4f57SMichael Kruse }
36570af4f57SMichael Kruse
3667c7978a1Spatacca if (Known.is_null() || Translator.is_null() || NormalizeMap.is_null()) {
36770af4f57SMichael Kruse assert(isl_ctx_last_error(IslCtx.get()) == isl_error_quota);
3689b41d095Spatacca Known = {};
3699b41d095Spatacca Translator = {};
3709b41d095Spatacca NormalizeMap = {};
371349506a9SNicola Zaghen LLVM_DEBUG(dbgs() << "Known analysis exceeded max_operations\n");
37270af4f57SMichael Kruse return false;
37370af4f57SMichael Kruse }
37470af4f57SMichael Kruse
37570af4f57SMichael Kruse KnownAnalyzed++;
376349506a9SNicola Zaghen LLVM_DEBUG(dbgs() << "All known: " << Known << "\n");
37770af4f57SMichael Kruse
37870af4f57SMichael Kruse return true;
37970af4f57SMichael Kruse }
38070af4f57SMichael Kruse
printStatistics(raw_ostream & OS,int Indent=0)381a6b2de3bSMichael Kruse void printStatistics(raw_ostream &OS, int Indent = 0) {
382a6b2de3bSMichael Kruse OS.indent(Indent) << "Statistics {\n";
383a6b2de3bSMichael Kruse OS.indent(Indent + 4) << "Instructions copied: " << NumInstructionsCopied
384a6b2de3bSMichael Kruse << '\n';
38570af4f57SMichael Kruse OS.indent(Indent + 4) << "Known loads forwarded: " << NumKnownLoadsForwarded
38670af4f57SMichael Kruse << '\n';
387822dfe27SMichael Kruse OS.indent(Indent + 4) << "Reloads: " << NumReloads << '\n';
38807e8c36dSMichael Kruse OS.indent(Indent + 4) << "Read-only accesses copied: " << NumReadOnlyCopied
38907e8c36dSMichael Kruse << '\n';
390a6b2de3bSMichael Kruse OS.indent(Indent + 4) << "Operand trees forwarded: " << NumForwardedTrees
391a6b2de3bSMichael Kruse << '\n';
392a6b2de3bSMichael Kruse OS.indent(Indent + 4) << "Statements with forwarded operand trees: "
393a6b2de3bSMichael Kruse << NumModifiedStmts << '\n';
394a6b2de3bSMichael Kruse OS.indent(Indent) << "}\n";
395a6b2de3bSMichael Kruse }
396a6b2de3bSMichael Kruse
printStatements(raw_ostream & OS,int Indent=0) const3979248fde5SEugene Zelenko void printStatements(raw_ostream &OS, int Indent = 0) const {
398a6b2de3bSMichael Kruse OS.indent(Indent) << "After statements {\n";
399a6b2de3bSMichael Kruse for (auto &Stmt : *S) {
400a6b2de3bSMichael Kruse OS.indent(Indent + 4) << Stmt.getBaseName() << "\n";
401a6b2de3bSMichael Kruse for (auto *MA : Stmt)
402a6b2de3bSMichael Kruse MA->print(OS);
403a6b2de3bSMichael Kruse
404a6b2de3bSMichael Kruse OS.indent(Indent + 12);
405a6b2de3bSMichael Kruse Stmt.printInstructions(OS);
406a6b2de3bSMichael Kruse }
407a6b2de3bSMichael Kruse OS.indent(Indent) << "}\n";
408a6b2de3bSMichael Kruse }
409a6b2de3bSMichael Kruse
41070af4f57SMichael Kruse /// Create a new MemoryAccess of type read and MemoryKind::Array.
41170af4f57SMichael Kruse ///
41270af4f57SMichael Kruse /// @param Stmt The statement in which the access occurs.
41370af4f57SMichael Kruse /// @param LI The instruction that does the access.
41470af4f57SMichael Kruse /// @param AccessRelation The array element that each statement instance
41570af4f57SMichael Kruse /// accesses.
41670af4f57SMichael Kruse ///
41770af4f57SMichael Kruse /// @param The newly created access.
makeReadArrayAccess(ScopStmt * Stmt,LoadInst * LI,isl::map AccessRelation)41870af4f57SMichael Kruse MemoryAccess *makeReadArrayAccess(ScopStmt *Stmt, LoadInst *LI,
41970af4f57SMichael Kruse isl::map AccessRelation) {
42070af4f57SMichael Kruse isl::id ArrayId = AccessRelation.get_tuple_id(isl::dim::out);
42170af4f57SMichael Kruse ScopArrayInfo *SAI = reinterpret_cast<ScopArrayInfo *>(ArrayId.get_user());
42270af4f57SMichael Kruse
42370af4f57SMichael Kruse // Create a dummy SCEV access, to be replaced anyway.
42470af4f57SMichael Kruse SmallVector<const SCEV *, 4> Sizes;
42570af4f57SMichael Kruse Sizes.reserve(SAI->getNumberOfDimensions());
42670af4f57SMichael Kruse SmallVector<const SCEV *, 4> Subscripts;
42770af4f57SMichael Kruse Subscripts.reserve(SAI->getNumberOfDimensions());
42870af4f57SMichael Kruse for (unsigned i = 0; i < SAI->getNumberOfDimensions(); i += 1) {
42970af4f57SMichael Kruse Sizes.push_back(SAI->getDimensionSize(i));
43070af4f57SMichael Kruse Subscripts.push_back(nullptr);
43170af4f57SMichael Kruse }
43270af4f57SMichael Kruse
43370af4f57SMichael Kruse MemoryAccess *Access =
43470af4f57SMichael Kruse new MemoryAccess(Stmt, LI, MemoryAccess::READ, SAI->getBasePtr(),
43570af4f57SMichael Kruse LI->getType(), true, {}, Sizes, LI, MemoryKind::Array);
43670af4f57SMichael Kruse S->addAccessFunction(Access);
43770af4f57SMichael Kruse Stmt->addAccess(Access, true);
43870af4f57SMichael Kruse
43970af4f57SMichael Kruse Access->setNewAccessRelation(AccessRelation);
44070af4f57SMichael Kruse
44170af4f57SMichael Kruse return Access;
44270af4f57SMichael Kruse }
44370af4f57SMichael Kruse
44470af4f57SMichael Kruse /// Forward a load by reading from an array element that contains the same
44570af4f57SMichael Kruse /// value. Typically the location it was loaded from.
44670af4f57SMichael Kruse ///
44770af4f57SMichael Kruse /// @param TargetStmt The statement the operand tree will be copied to.
44870af4f57SMichael Kruse /// @param Inst The (possibly speculatable) instruction to forward.
44970af4f57SMichael Kruse /// @param UseStmt The statement that uses @p Inst.
45070af4f57SMichael Kruse /// @param UseLoop The loop @p Inst is used in.
45170af4f57SMichael Kruse /// @param DefStmt The statement @p Inst is defined in.
45270af4f57SMichael Kruse /// @param DefLoop The loop which contains @p Inst.
45370af4f57SMichael Kruse ///
4547175cffbSMichael Kruse /// @return A ForwardingAction object describing the feasibility and
4557175cffbSMichael Kruse /// profitability evaluation and the callback carrying-out the value
4567175cffbSMichael Kruse /// forwarding.
forwardKnownLoad(ScopStmt * TargetStmt,Instruction * Inst,ScopStmt * UseStmt,Loop * UseLoop,ScopStmt * DefStmt,Loop * DefLoop)4577175cffbSMichael Kruse ForwardingAction forwardKnownLoad(ScopStmt *TargetStmt, Instruction *Inst,
45870af4f57SMichael Kruse ScopStmt *UseStmt, Loop *UseLoop,
4597175cffbSMichael Kruse ScopStmt *DefStmt, Loop *DefLoop) {
46070af4f57SMichael Kruse // Cannot do anything without successful known analysis.
461d3ce899dSMichael Kruse if (Known.is_null() || Translator.is_null() ||
462d3ce899dSMichael Kruse MaxOpGuard.hasQuotaExceeded())
4637175cffbSMichael Kruse return ForwardingAction::notApplicable();
46470af4f57SMichael Kruse
46570af4f57SMichael Kruse LoadInst *LI = dyn_cast<LoadInst>(Inst);
46670af4f57SMichael Kruse if (!LI)
4677175cffbSMichael Kruse return ForwardingAction::notApplicable();
46870af4f57SMichael Kruse
4697175cffbSMichael Kruse ForwardingDecision OpDecision =
4707175cffbSMichael Kruse forwardTree(TargetStmt, LI->getPointerOperand(), DefStmt, DefLoop);
47170af4f57SMichael Kruse switch (OpDecision) {
472822dfe27SMichael Kruse case FD_CanForwardProfitably:
4737175cffbSMichael Kruse case FD_CanForwardLeaf:
47470af4f57SMichael Kruse break;
4757175cffbSMichael Kruse case FD_CannotForward:
4767175cffbSMichael Kruse return ForwardingAction::cannotForward();
47770af4f57SMichael Kruse default:
47870af4f57SMichael Kruse llvm_unreachable("Shouldn't return this");
47970af4f57SMichael Kruse }
48070af4f57SMichael Kruse
4817175cffbSMichael Kruse MemoryAccess *Access = TargetStmt->getArrayAccessOrNULLFor(LI);
4827175cffbSMichael Kruse if (Access) {
4837175cffbSMichael Kruse // If the load is already in the statement, no forwarding is necessary.
4847175cffbSMichael Kruse // However, it might happen that the LoadInst is already present in the
4857175cffbSMichael Kruse // statement's instruction list. In that case we do as follows:
4867175cffbSMichael Kruse // - For the evaluation, we can trivially forward it as it is
4877175cffbSMichael Kruse // benefit of forwarding an already present instruction.
4887175cffbSMichael Kruse // - For the execution, prepend the instruction (to make it
4897175cffbSMichael Kruse // available to all instructions following in the instruction list), but
4907175cffbSMichael Kruse // do not add another MemoryAccess.
4917175cffbSMichael Kruse auto ExecAction = [this, TargetStmt, LI, Access]() -> bool {
4927175cffbSMichael Kruse TargetStmt->prependInstruction(LI);
4937175cffbSMichael Kruse LLVM_DEBUG(
4947175cffbSMichael Kruse dbgs() << " forwarded known load with preexisting MemoryAccess"
4957175cffbSMichael Kruse << Access << "\n");
49698031b66SFangrui Song (void)Access;
4977175cffbSMichael Kruse
4987175cffbSMichael Kruse NumKnownLoadsForwarded++;
4997175cffbSMichael Kruse TotalKnownLoadsForwarded++;
5007175cffbSMichael Kruse return true;
5017175cffbSMichael Kruse };
5027175cffbSMichael Kruse return ForwardingAction::canForward(
5037175cffbSMichael Kruse ExecAction, {{LI->getPointerOperand(), DefStmt}}, true);
5047175cffbSMichael Kruse }
5057175cffbSMichael Kruse
5067175cffbSMichael Kruse // Allow the following Isl calculations (until we return the
5077175cffbSMichael Kruse // ForwardingAction, excluding the code inside the lambda that will be
5087175cffbSMichael Kruse // executed later) to fail.
5097175cffbSMichael Kruse IslQuotaScope QuotaScope = MaxOpGuard.enter();
51089972e21SMichael Kruse
51170af4f57SMichael Kruse // { DomainDef[] -> ValInst[] }
51270af4f57SMichael Kruse isl::map ExpectedVal = makeValInst(Inst, UseStmt, UseLoop);
513d51fbfcaSMichael Kruse assert(!isNormalized(ExpectedVal).is_false() &&
514d51fbfcaSMichael Kruse "LoadInsts are always normalized");
51570af4f57SMichael Kruse
516d3ce899dSMichael Kruse // { DomainUse[] -> DomainTarget[] }
517d3ce899dSMichael Kruse isl::map UseToTarget = getDefToTarget(UseStmt, TargetStmt);
518d3ce899dSMichael Kruse
51970af4f57SMichael Kruse // { DomainTarget[] -> ValInst[] }
52070af4f57SMichael Kruse isl::map TargetExpectedVal = ExpectedVal.apply_domain(UseToTarget);
52170af4f57SMichael Kruse isl::union_map TranslatedExpectedVal =
52270af4f57SMichael Kruse isl::union_map(TargetExpectedVal).apply_range(Translator);
52370af4f57SMichael Kruse
52470af4f57SMichael Kruse // { DomainTarget[] -> Element[] }
52570af4f57SMichael Kruse isl::union_map Candidates = findSameContentElements(TranslatedExpectedVal);
52670af4f57SMichael Kruse
52770af4f57SMichael Kruse isl::map SameVal = singleLocation(Candidates, getDomainFor(TargetStmt));
5287c7978a1Spatacca if (SameVal.is_null())
5297175cffbSMichael Kruse return ForwardingAction::notApplicable();
530822dfe27SMichael Kruse
5317175cffbSMichael Kruse LLVM_DEBUG(dbgs() << " expected values where " << TargetExpectedVal
5327175cffbSMichael Kruse << "\n");
5337175cffbSMichael Kruse LLVM_DEBUG(dbgs() << " candidate elements where " << Candidates
5347175cffbSMichael Kruse << "\n");
53570af4f57SMichael Kruse
53670af4f57SMichael Kruse // { ValInst[] }
53770af4f57SMichael Kruse isl::space ValInstSpace = ExpectedVal.get_space().range();
53870af4f57SMichael Kruse
53970af4f57SMichael Kruse // After adding a new load to the SCoP, also update the Known content
54070af4f57SMichael Kruse // about it. The new load will have a known ValInst of
54170af4f57SMichael Kruse // { [DomainTarget[] -> Value[]] }
54270af4f57SMichael Kruse // but which -- because it is a copy of it -- has same value as the
54370af4f57SMichael Kruse // { [DomainDef[] -> Value[]] }
54470af4f57SMichael Kruse // that it replicates. Instead of cloning the known content of
54570af4f57SMichael Kruse // [DomainDef[] -> Value[]]
54670af4f57SMichael Kruse // for DomainTarget[], we add a 'translator' that maps
54770af4f57SMichael Kruse // [DomainTarget[] -> Value[]] to [DomainDef[] -> Value[]]
54870af4f57SMichael Kruse // before comparing to the known content.
54970af4f57SMichael Kruse // TODO: 'Translator' could also be used to map PHINodes to their incoming
55070af4f57SMichael Kruse // ValInsts.
5517175cffbSMichael Kruse isl::map LocalTranslator;
5527175cffbSMichael Kruse if (!ValInstSpace.is_wrapping().is_false()) {
55370af4f57SMichael Kruse // { DefDomain[] -> Value[] }
55470af4f57SMichael Kruse isl::map ValInsts = ExpectedVal.range().unwrap();
55570af4f57SMichael Kruse
55670af4f57SMichael Kruse // { DefDomain[] }
55770af4f57SMichael Kruse isl::set DefDomain = ValInsts.domain();
55870af4f57SMichael Kruse
55970af4f57SMichael Kruse // { Value[] }
56070af4f57SMichael Kruse isl::space ValSpace = ValInstSpace.unwrap().range();
56170af4f57SMichael Kruse
56270af4f57SMichael Kruse // { Value[] -> Value[] }
56370af4f57SMichael Kruse isl::map ValToVal =
56470af4f57SMichael Kruse isl::map::identity(ValSpace.map_from_domain_and_range(ValSpace));
56570af4f57SMichael Kruse
566d3ce899dSMichael Kruse // { DomainDef[] -> DomainTarget[] }
567d3ce899dSMichael Kruse isl::map DefToTarget = getDefToTarget(DefStmt, TargetStmt);
568d3ce899dSMichael Kruse
56970af4f57SMichael Kruse // { [TargetDomain[] -> Value[]] -> [DefDomain[] -> Value] }
5707175cffbSMichael Kruse LocalTranslator = DefToTarget.reverse().product(ValToVal);
571349506a9SNicola Zaghen LLVM_DEBUG(dbgs() << " local translator is " << LocalTranslator
57270af4f57SMichael Kruse << "\n");
5737175cffbSMichael Kruse
5747c7978a1Spatacca if (LocalTranslator.is_null())
5757175cffbSMichael Kruse return ForwardingAction::notApplicable();
57670af4f57SMichael Kruse }
5777175cffbSMichael Kruse
5787175cffbSMichael Kruse auto ExecAction = [this, TargetStmt, LI, SameVal,
5797175cffbSMichael Kruse LocalTranslator]() -> bool {
5807175cffbSMichael Kruse TargetStmt->prependInstruction(LI);
5817175cffbSMichael Kruse MemoryAccess *Access = makeReadArrayAccess(TargetStmt, LI, SameVal);
5827175cffbSMichael Kruse LLVM_DEBUG(dbgs() << " forwarded known load with new MemoryAccess"
5837175cffbSMichael Kruse << Access << "\n");
58498031b66SFangrui Song (void)Access;
5857175cffbSMichael Kruse
5867c7978a1Spatacca if (!LocalTranslator.is_null())
587d5ee355fSRiccardo Mori Translator = Translator.unite(LocalTranslator);
58870af4f57SMichael Kruse
58970af4f57SMichael Kruse NumKnownLoadsForwarded++;
59070af4f57SMichael Kruse TotalKnownLoadsForwarded++;
5917175cffbSMichael Kruse return true;
5927175cffbSMichael Kruse };
5937175cffbSMichael Kruse return ForwardingAction::canForward(
5947175cffbSMichael Kruse ExecAction, {{LI->getPointerOperand(), DefStmt}}, true);
595822dfe27SMichael Kruse }
596822dfe27SMichael Kruse
597822dfe27SMichael Kruse /// Forward a scalar by redirecting the access to an array element that stores
598822dfe27SMichael Kruse /// the same value.
599822dfe27SMichael Kruse ///
600822dfe27SMichael Kruse /// @param TargetStmt The statement the operand tree will be copied to.
601822dfe27SMichael Kruse /// @param Inst The scalar to forward.
602822dfe27SMichael Kruse /// @param UseStmt The statement that uses @p Inst.
603822dfe27SMichael Kruse /// @param UseLoop The loop @p Inst is used in.
604822dfe27SMichael Kruse /// @param DefStmt The statement @p Inst is defined in.
605822dfe27SMichael Kruse /// @param DefLoop The loop which contains @p Inst.
606822dfe27SMichael Kruse ///
6077175cffbSMichael Kruse /// @return A ForwardingAction object describing the feasibility and
6087175cffbSMichael Kruse /// profitability evaluation and the callback carrying-out the value
6097175cffbSMichael Kruse /// forwarding.
reloadKnownContent(ScopStmt * TargetStmt,Instruction * Inst,ScopStmt * UseStmt,Loop * UseLoop,ScopStmt * DefStmt,Loop * DefLoop)6107175cffbSMichael Kruse ForwardingAction reloadKnownContent(ScopStmt *TargetStmt, Instruction *Inst,
611822dfe27SMichael Kruse ScopStmt *UseStmt, Loop *UseLoop,
6127175cffbSMichael Kruse ScopStmt *DefStmt, Loop *DefLoop) {
613822dfe27SMichael Kruse // Cannot do anything without successful known analysis.
614d3ce899dSMichael Kruse if (Known.is_null() || Translator.is_null() ||
615d3ce899dSMichael Kruse MaxOpGuard.hasQuotaExceeded())
6167175cffbSMichael Kruse return ForwardingAction::notApplicable();
617822dfe27SMichael Kruse
6187175cffbSMichael Kruse // Don't spend too much time analyzing whether it can be reloaded.
6197175cffbSMichael Kruse IslQuotaScope QuotaScope = MaxOpGuard.enter();
6204d3f3c72SMichael Kruse
621822dfe27SMichael Kruse // { DomainDef[] -> ValInst[] }
62268821a8bSMichael Kruse isl::union_map ExpectedVal = makeNormalizedValInst(Inst, UseStmt, UseLoop);
623822dfe27SMichael Kruse
624d3ce899dSMichael Kruse // { DomainUse[] -> DomainTarget[] }
625d3ce899dSMichael Kruse isl::map UseToTarget = getDefToTarget(UseStmt, TargetStmt);
626d3ce899dSMichael Kruse
627822dfe27SMichael Kruse // { DomainTarget[] -> ValInst[] }
628822dfe27SMichael Kruse isl::union_map TargetExpectedVal = ExpectedVal.apply_domain(UseToTarget);
629822dfe27SMichael Kruse isl::union_map TranslatedExpectedVal =
630822dfe27SMichael Kruse TargetExpectedVal.apply_range(Translator);
631822dfe27SMichael Kruse
632822dfe27SMichael Kruse // { DomainTarget[] -> Element[] }
633822dfe27SMichael Kruse isl::union_map Candidates = findSameContentElements(TranslatedExpectedVal);
634822dfe27SMichael Kruse
635822dfe27SMichael Kruse isl::map SameVal = singleLocation(Candidates, getDomainFor(TargetStmt));
6367175cffbSMichael Kruse simplify(SameVal);
6377c7978a1Spatacca if (SameVal.is_null())
6387175cffbSMichael Kruse return ForwardingAction::notApplicable();
639822dfe27SMichael Kruse
6407175cffbSMichael Kruse auto ExecAction = [this, TargetStmt, Inst, SameVal]() {
6417175cffbSMichael Kruse MemoryAccess *Access = TargetStmt->lookupInputAccessOf(Inst);
642822dfe27SMichael Kruse if (!Access)
643822dfe27SMichael Kruse Access = TargetStmt->ensureValueRead(Inst);
644822dfe27SMichael Kruse Access->setNewAccessRelation(SameVal);
645822dfe27SMichael Kruse
646c1cf51e7SMichael Kruse LLVM_DEBUG(dbgs() << " forwarded known content of " << *Inst
647c1cf51e7SMichael Kruse << " which is " << SameVal << "\n");
648822dfe27SMichael Kruse TotalReloads++;
649822dfe27SMichael Kruse NumReloads++;
6507175cffbSMichael Kruse return false;
6517175cffbSMichael Kruse };
6527175cffbSMichael Kruse
6537175cffbSMichael Kruse return ForwardingAction::canForward(ExecAction, {}, true);
65470af4f57SMichael Kruse }
65570af4f57SMichael Kruse
656a9a70863SMichael Kruse /// Forwards a speculatively executable instruction.
657a9a70863SMichael Kruse ///
65870af4f57SMichael Kruse /// @param TargetStmt The statement the operand tree will be copied to.
65970af4f57SMichael Kruse /// @param UseInst The (possibly speculatable) instruction to forward.
66070af4f57SMichael Kruse /// @param DefStmt The statement @p UseInst is defined in.
66170af4f57SMichael Kruse /// @param DefLoop The loop which contains @p UseInst.
662a9a70863SMichael Kruse ///
6637175cffbSMichael Kruse /// @return A ForwardingAction object describing the feasibility and
6647175cffbSMichael Kruse /// profitability evaluation and the callback carrying-out the value
6657175cffbSMichael Kruse /// forwarding.
forwardSpeculatable(ScopStmt * TargetStmt,Instruction * UseInst,ScopStmt * DefStmt,Loop * DefLoop)6667175cffbSMichael Kruse ForwardingAction forwardSpeculatable(ScopStmt *TargetStmt,
6677175cffbSMichael Kruse Instruction *UseInst, ScopStmt *DefStmt,
6687175cffbSMichael Kruse Loop *DefLoop) {
669a9a70863SMichael Kruse // PHIs, unless synthesizable, are not yet supported.
670a9a70863SMichael Kruse if (isa<PHINode>(UseInst))
6717175cffbSMichael Kruse return ForwardingAction::notApplicable();
672a9a70863SMichael Kruse
673a9a70863SMichael Kruse // Compatible instructions must satisfy the following conditions:
674a9a70863SMichael Kruse // 1. Idempotent (instruction will be copied, not moved; although its
675a9a70863SMichael Kruse // original instance might be removed by simplification)
676a9a70863SMichael Kruse // 2. Not access memory (There might be memory writes between)
677a9a70863SMichael Kruse // 3. Not cause undefined behaviour (we might copy to a location when the
678a9a70863SMichael Kruse // original instruction was no executed; this is currently not possible
679a9a70863SMichael Kruse // because we do not forward PHINodes)
680a9a70863SMichael Kruse // 4. Not leak memory if executed multiple times (i.e. malloc)
681a9a70863SMichael Kruse //
682a9a70863SMichael Kruse // Instruction::mayHaveSideEffects is not sufficient because it considers
683a9a70863SMichael Kruse // malloc to not have side-effects. llvm::isSafeToSpeculativelyExecute is
684a9a70863SMichael Kruse // not sufficient because it allows memory accesses.
68593102505SPhilip Reames if (mayHaveNonDefUseDependency(*UseInst))
6867175cffbSMichael Kruse return ForwardingAction::notApplicable();
687a9a70863SMichael Kruse
6887175cffbSMichael Kruse SmallVector<ForwardingAction::KeyTy, 4> Depends;
6897175cffbSMichael Kruse Depends.reserve(UseInst->getNumOperands());
690a9a70863SMichael Kruse for (Value *OpVal : UseInst->operand_values()) {
691a9a70863SMichael Kruse ForwardingDecision OpDecision =
6927175cffbSMichael Kruse forwardTree(TargetStmt, OpVal, DefStmt, DefLoop);
693a9a70863SMichael Kruse switch (OpDecision) {
694a9a70863SMichael Kruse case FD_CannotForward:
6957175cffbSMichael Kruse return ForwardingAction::cannotForward();
696a9a70863SMichael Kruse
697a9a70863SMichael Kruse case FD_CanForwardLeaf:
698822dfe27SMichael Kruse case FD_CanForwardProfitably:
6997175cffbSMichael Kruse Depends.emplace_back(OpVal, DefStmt);
700a9a70863SMichael Kruse break;
701a9a70863SMichael Kruse
702a9a70863SMichael Kruse case FD_NotApplicable:
7037175cffbSMichael Kruse case FD_Unknown:
7047175cffbSMichael Kruse llvm_unreachable(
7057175cffbSMichael Kruse "forwardTree should never return FD_NotApplicable/FD_Unknown");
706a9a70863SMichael Kruse }
707a9a70863SMichael Kruse }
708a9a70863SMichael Kruse
7092213a354SFangrui Song auto ExecAction = [this, TargetStmt, UseInst]() {
7107175cffbSMichael Kruse // To ensure the right order, prepend this instruction before its
7117175cffbSMichael Kruse // operands. This ensures that its operands are inserted before the
7127175cffbSMichael Kruse // instruction using them.
7137175cffbSMichael Kruse TargetStmt->prependInstruction(UseInst);
714c1cf51e7SMichael Kruse
715c1cf51e7SMichael Kruse LLVM_DEBUG(dbgs() << " forwarded speculable instruction: " << *UseInst
716c1cf51e7SMichael Kruse << "\n");
7177175cffbSMichael Kruse NumInstructionsCopied++;
7187175cffbSMichael Kruse TotalInstructionsCopied++;
7197175cffbSMichael Kruse return true;
7207175cffbSMichael Kruse };
7217175cffbSMichael Kruse return ForwardingAction::canForward(ExecAction, Depends, true);
722a9a70863SMichael Kruse }
723a9a70863SMichael Kruse
7247175cffbSMichael Kruse /// Determines whether an operand tree can be forwarded and returns
7257175cffbSMichael Kruse /// instructions how to do so in the form of a ForwardingAction object.
726a6b2de3bSMichael Kruse ///
727a6b2de3bSMichael Kruse /// @param TargetStmt The statement the operand tree will be copied to.
728a6b2de3bSMichael Kruse /// @param UseVal The value (usually an instruction) which is root of an
729a6b2de3bSMichael Kruse /// operand tree.
730a6b2de3bSMichael Kruse /// @param UseStmt The statement that uses @p UseVal.
731a6b2de3bSMichael Kruse /// @param UseLoop The loop @p UseVal is used in.
732a6b2de3bSMichael Kruse ///
7337175cffbSMichael Kruse /// @return A ForwardingAction object describing the feasibility and
7347175cffbSMichael Kruse /// profitability evaluation and the callback carrying-out the value
7357175cffbSMichael Kruse /// forwarding.
forwardTreeImpl(ScopStmt * TargetStmt,Value * UseVal,ScopStmt * UseStmt,Loop * UseLoop)7367175cffbSMichael Kruse ForwardingAction forwardTreeImpl(ScopStmt *TargetStmt, Value *UseVal,
7377175cffbSMichael Kruse ScopStmt *UseStmt, Loop *UseLoop) {
73870af4f57SMichael Kruse ScopStmt *DefStmt = nullptr;
73970af4f57SMichael Kruse Loop *DefLoop = nullptr;
74070af4f57SMichael Kruse
74170af4f57SMichael Kruse // { DefDomain[] -> TargetDomain[] }
74270af4f57SMichael Kruse isl::map DefToTarget;
74370af4f57SMichael Kruse
744a6b2de3bSMichael Kruse VirtualUse VUse = VirtualUse::create(UseStmt, UseLoop, UseVal, true);
745a6b2de3bSMichael Kruse switch (VUse.getKind()) {
746a6b2de3bSMichael Kruse case VirtualUse::Constant:
747a6b2de3bSMichael Kruse case VirtualUse::Block:
748e5f4706aSMichael Kruse case VirtualUse::Hoisted:
749a6b2de3bSMichael Kruse // These can be used anywhere without special considerations.
750c1cf51e7SMichael Kruse return ForwardingAction::triviallyForwardable(false, UseVal);
751a6b2de3bSMichael Kruse
7529f6e41cdSMichael Kruse case VirtualUse::Synthesizable: {
7539f6e41cdSMichael Kruse // Check if the value is synthesizable at the new location as well. This
7549f6e41cdSMichael Kruse // might be possible when leaving a loop for which ScalarEvolution is
7559f6e41cdSMichael Kruse // unable to derive the exit value for.
7569f6e41cdSMichael Kruse // TODO: If there is a LCSSA PHI at the loop exit, use that one.
7579f6e41cdSMichael Kruse // If the SCEV contains a SCEVAddRecExpr, we currently depend on that we
7589f6e41cdSMichael Kruse // do not forward past its loop header. This would require us to use a
7599f6e41cdSMichael Kruse // previous loop induction variable instead the current one. We currently
7609f6e41cdSMichael Kruse // do not allow forwarding PHI nodes, thus this should never occur (the
7619f6e41cdSMichael Kruse // only exception where no phi is necessary being an unreachable loop
7629f6e41cdSMichael Kruse // without edge from the outside).
7639f6e41cdSMichael Kruse VirtualUse TargetUse = VirtualUse::create(
7649f6e41cdSMichael Kruse S, TargetStmt, TargetStmt->getSurroundingLoop(), UseVal, true);
7659f6e41cdSMichael Kruse if (TargetUse.getKind() == VirtualUse::Synthesizable)
766c1cf51e7SMichael Kruse return ForwardingAction::triviallyForwardable(false, UseVal);
7679f6e41cdSMichael Kruse
768349506a9SNicola Zaghen LLVM_DEBUG(
769349506a9SNicola Zaghen dbgs() << " Synthesizable would not be synthesizable anymore: "
7709f6e41cdSMichael Kruse << *UseVal << "\n");
7717175cffbSMichael Kruse return ForwardingAction::cannotForward();
7729f6e41cdSMichael Kruse }
773a6b2de3bSMichael Kruse
7747175cffbSMichael Kruse case VirtualUse::ReadOnly: {
775c1cf51e7SMichael Kruse if (!ModelReadOnlyScalars)
776c1cf51e7SMichael Kruse return ForwardingAction::triviallyForwardable(false, UseVal);
777c1cf51e7SMichael Kruse
77807e8c36dSMichael Kruse // If we model read-only scalars, we need to create a MemoryAccess for it.
7797175cffbSMichael Kruse auto ExecAction = [this, TargetStmt, UseVal]() {
78007e8c36dSMichael Kruse TargetStmt->ensureValueRead(UseVal);
78107e8c36dSMichael Kruse
782c1cf51e7SMichael Kruse LLVM_DEBUG(dbgs() << " forwarded read-only value " << *UseVal
783c1cf51e7SMichael Kruse << "\n");
78407e8c36dSMichael Kruse NumReadOnlyCopied++;
78507e8c36dSMichael Kruse TotalReadOnlyCopied++;
7867175cffbSMichael Kruse
7877175cffbSMichael Kruse // Note that we cannot return true here. With a operand tree
7887175cffbSMichael Kruse // depth of 0, UseVal is the use in TargetStmt that we try to replace.
7897175cffbSMichael Kruse // With -polly-analyze-read-only-scalars=true we would ensure the
7907175cffbSMichael Kruse // existence of a MemoryAccess (which already exists for a leaf) and be
7917175cffbSMichael Kruse // removed again by tryForwardTree because it's goal is to remove this
7927175cffbSMichael Kruse // scalar MemoryAccess. It interprets FD_CanForwardTree as the
7937175cffbSMichael Kruse // permission to do so.
7947175cffbSMichael Kruse return false;
7957175cffbSMichael Kruse };
7967175cffbSMichael Kruse return ForwardingAction::canForward(ExecAction, {}, false);
7977175cffbSMichael Kruse }
798a6b2de3bSMichael Kruse
799a6b2de3bSMichael Kruse case VirtualUse::Intra:
80070af4f57SMichael Kruse // Knowing that UseStmt and DefStmt are the same statement instance, just
80170af4f57SMichael Kruse // reuse the information about UseStmt for DefStmt
80270af4f57SMichael Kruse DefStmt = UseStmt;
803a6b2de3bSMichael Kruse
80470af4f57SMichael Kruse LLVM_FALLTHROUGH;
80570af4f57SMichael Kruse case VirtualUse::Inter:
80670af4f57SMichael Kruse Instruction *Inst = cast<Instruction>(UseVal);
80770af4f57SMichael Kruse
808cd3b9fedSMichael Kruse if (!DefStmt) {
80970af4f57SMichael Kruse DefStmt = S->getStmtFor(Inst);
810cd3b9fedSMichael Kruse if (!DefStmt)
8117175cffbSMichael Kruse return ForwardingAction::cannotForward();
812cd3b9fedSMichael Kruse }
813cd3b9fedSMichael Kruse
81470af4f57SMichael Kruse DefLoop = LI->getLoopFor(Inst->getParent());
81570af4f57SMichael Kruse
8167175cffbSMichael Kruse ForwardingAction SpeculativeResult =
8177175cffbSMichael Kruse forwardSpeculatable(TargetStmt, Inst, DefStmt, DefLoop);
8187175cffbSMichael Kruse if (SpeculativeResult.Decision != FD_NotApplicable)
819a9a70863SMichael Kruse return SpeculativeResult;
820a9a70863SMichael Kruse
8217175cffbSMichael Kruse ForwardingAction KnownResult = forwardKnownLoad(
8227175cffbSMichael Kruse TargetStmt, Inst, UseStmt, UseLoop, DefStmt, DefLoop);
8237175cffbSMichael Kruse if (KnownResult.Decision != FD_NotApplicable)
82470af4f57SMichael Kruse return KnownResult;
82570af4f57SMichael Kruse
8267175cffbSMichael Kruse ForwardingAction ReloadResult = reloadKnownContent(
8277175cffbSMichael Kruse TargetStmt, Inst, UseStmt, UseLoop, DefStmt, DefLoop);
8287175cffbSMichael Kruse if (ReloadResult.Decision != FD_NotApplicable)
829822dfe27SMichael Kruse return ReloadResult;
830822dfe27SMichael Kruse
831a9a70863SMichael Kruse // When no method is found to forward the operand tree, we effectively
832a9a70863SMichael Kruse // cannot handle it.
833349506a9SNicola Zaghen LLVM_DEBUG(dbgs() << " Cannot forward instruction: " << *Inst << "\n");
8347175cffbSMichael Kruse return ForwardingAction::cannotForward();
8359f6e41cdSMichael Kruse }
8369f6e41cdSMichael Kruse
837a6b2de3bSMichael Kruse llvm_unreachable("Case unhandled");
838a6b2de3bSMichael Kruse }
839a6b2de3bSMichael Kruse
8407175cffbSMichael Kruse /// Determines whether an operand tree can be forwarded. Previous evaluations
8417175cffbSMichael Kruse /// are cached.
8427175cffbSMichael Kruse ///
8437175cffbSMichael Kruse /// @param TargetStmt The statement the operand tree will be copied to.
8447175cffbSMichael Kruse /// @param UseVal The value (usually an instruction) which is root of an
8457175cffbSMichael Kruse /// operand tree.
8467175cffbSMichael Kruse /// @param UseStmt The statement that uses @p UseVal.
8477175cffbSMichael Kruse /// @param UseLoop The loop @p UseVal is used in.
8487175cffbSMichael Kruse ///
8497175cffbSMichael Kruse /// @return FD_CannotForward if @p UseVal cannot be forwarded.
8507175cffbSMichael Kruse /// FD_CanForwardLeaf if @p UseVal is forwardable, but not
8517175cffbSMichael Kruse /// profitable.
8527175cffbSMichael Kruse /// FD_CanForwardProfitably if @p UseVal is forwardable and useful to
8537175cffbSMichael Kruse /// do.
forwardTree(ScopStmt * TargetStmt,Value * UseVal,ScopStmt * UseStmt,Loop * UseLoop)8547175cffbSMichael Kruse ForwardingDecision forwardTree(ScopStmt *TargetStmt, Value *UseVal,
8557175cffbSMichael Kruse ScopStmt *UseStmt, Loop *UseLoop) {
8567175cffbSMichael Kruse // Lookup any cached evaluation.
8577175cffbSMichael Kruse auto It = ForwardingActions.find({UseVal, UseStmt});
8587175cffbSMichael Kruse if (It != ForwardingActions.end())
8597175cffbSMichael Kruse return It->second.Decision;
8607175cffbSMichael Kruse
8617175cffbSMichael Kruse // Make a new evaluation.
8627175cffbSMichael Kruse ForwardingAction Action =
8637175cffbSMichael Kruse forwardTreeImpl(TargetStmt, UseVal, UseStmt, UseLoop);
8647175cffbSMichael Kruse ForwardingDecision Result = Action.Decision;
8657175cffbSMichael Kruse
8667175cffbSMichael Kruse // Remember for the next time.
8677175cffbSMichael Kruse assert(!ForwardingActions.count({UseVal, UseStmt}) &&
8687175cffbSMichael Kruse "circular dependency?");
8697175cffbSMichael Kruse ForwardingActions.insert({{UseVal, UseStmt}, std::move(Action)});
8707175cffbSMichael Kruse
8717175cffbSMichael Kruse return Result;
8727175cffbSMichael Kruse }
8737175cffbSMichael Kruse
8747175cffbSMichael Kruse /// Forward an operand tree using cached actions.
8757175cffbSMichael Kruse ///
8767175cffbSMichael Kruse /// @param Stmt Statement the operand tree is moved into.
8777175cffbSMichael Kruse /// @param UseVal Root of the operand tree within @p Stmt.
8787175cffbSMichael Kruse /// @param RA The MemoryAccess for @p UseVal that the forwarding intends
8797175cffbSMichael Kruse /// to remove.
applyForwardingActions(ScopStmt * Stmt,Value * UseVal,MemoryAccess * RA)8807175cffbSMichael Kruse void applyForwardingActions(ScopStmt *Stmt, Value *UseVal, MemoryAccess *RA) {
8817175cffbSMichael Kruse using ChildItTy =
8827175cffbSMichael Kruse decltype(std::declval<ForwardingAction>().Depends.begin());
8837175cffbSMichael Kruse using EdgeTy = std::pair<ForwardingAction *, ChildItTy>;
8847175cffbSMichael Kruse
8857175cffbSMichael Kruse DenseSet<ForwardingAction::KeyTy> Visited;
8867175cffbSMichael Kruse SmallVector<EdgeTy, 32> Stack;
8877175cffbSMichael Kruse SmallVector<ForwardingAction *, 32> Ordered;
8887175cffbSMichael Kruse
8897175cffbSMichael Kruse // Seed the tree search using the root value.
8907175cffbSMichael Kruse assert(ForwardingActions.count({UseVal, Stmt}));
8917175cffbSMichael Kruse ForwardingAction *RootAction = &ForwardingActions[{UseVal, Stmt}];
8927175cffbSMichael Kruse Stack.emplace_back(RootAction, RootAction->Depends.begin());
8937175cffbSMichael Kruse
8947175cffbSMichael Kruse // Compute the postorder of the operand tree: all operands of an instruction
8957175cffbSMichael Kruse // must be visited before the instruction itself. As an additional
8967175cffbSMichael Kruse // requirement, the topological ordering must be 'compact': Any subtree node
8977175cffbSMichael Kruse // must not be interleaved with nodes from a non-shared subtree. This is
8987175cffbSMichael Kruse // because the same llvm::Instruction can be materialized multiple times as
8997175cffbSMichael Kruse // used at different ScopStmts which might be different values. Intersecting
9007175cffbSMichael Kruse // these lifetimes may result in miscompilations.
9017175cffbSMichael Kruse // FIXME: Intersecting lifetimes might still be possible for the roots
9027175cffbSMichael Kruse // themselves, since instructions are just prepended to a ScopStmt's
9037175cffbSMichael Kruse // instruction list.
9047175cffbSMichael Kruse while (!Stack.empty()) {
9057175cffbSMichael Kruse EdgeTy &Top = Stack.back();
9067175cffbSMichael Kruse ForwardingAction *TopAction = Top.first;
9077175cffbSMichael Kruse ChildItTy &TopEdge = Top.second;
9087175cffbSMichael Kruse
9097175cffbSMichael Kruse if (TopEdge == TopAction->Depends.end()) {
9107175cffbSMichael Kruse // Postorder sorting
9117175cffbSMichael Kruse Ordered.push_back(TopAction);
9127175cffbSMichael Kruse Stack.pop_back();
9137175cffbSMichael Kruse continue;
9147175cffbSMichael Kruse }
9157175cffbSMichael Kruse ForwardingAction::KeyTy Key = *TopEdge;
9167175cffbSMichael Kruse
9177175cffbSMichael Kruse // Next edge for this level
9187175cffbSMichael Kruse ++TopEdge;
9197175cffbSMichael Kruse
9207175cffbSMichael Kruse auto VisitIt = Visited.insert(Key);
9217175cffbSMichael Kruse if (!VisitIt.second)
9227175cffbSMichael Kruse continue;
9237175cffbSMichael Kruse
9247175cffbSMichael Kruse assert(ForwardingActions.count(Key) &&
9257175cffbSMichael Kruse "Must not insert new actions during execution phase");
9267175cffbSMichael Kruse ForwardingAction *ChildAction = &ForwardingActions[Key];
9277175cffbSMichael Kruse Stack.emplace_back(ChildAction, ChildAction->Depends.begin());
9287175cffbSMichael Kruse }
9297175cffbSMichael Kruse
9307175cffbSMichael Kruse // Actually, we need the reverse postorder because actions prepend new
9317175cffbSMichael Kruse // instructions. Therefore, the first one will always be the action for the
9327175cffbSMichael Kruse // operand tree's root.
9337175cffbSMichael Kruse assert(Ordered.back() == RootAction);
9347175cffbSMichael Kruse if (RootAction->Execute())
9357175cffbSMichael Kruse Stmt->removeSingleMemoryAccess(RA);
9367175cffbSMichael Kruse Ordered.pop_back();
9377175cffbSMichael Kruse for (auto DepAction : reverse(Ordered)) {
9387175cffbSMichael Kruse assert(DepAction->Decision != FD_Unknown &&
9397175cffbSMichael Kruse DepAction->Decision != FD_CannotForward);
9407175cffbSMichael Kruse assert(DepAction != RootAction);
9417175cffbSMichael Kruse DepAction->Execute();
9427175cffbSMichael Kruse }
9437175cffbSMichael Kruse }
9447175cffbSMichael Kruse
945a6b2de3bSMichael Kruse /// Try to forward an operand tree rooted in @p RA.
tryForwardTree(MemoryAccess * RA)946a6b2de3bSMichael Kruse bool tryForwardTree(MemoryAccess *RA) {
947a6b2de3bSMichael Kruse assert(RA->isLatestScalarKind());
948349506a9SNicola Zaghen LLVM_DEBUG(dbgs() << "Trying to forward operand tree " << RA << "...\n");
949a6b2de3bSMichael Kruse
950a6b2de3bSMichael Kruse ScopStmt *Stmt = RA->getStatement();
951a6b2de3bSMichael Kruse Loop *InLoop = Stmt->getSurroundingLoop();
952a6b2de3bSMichael Kruse
95370af4f57SMichael Kruse isl::map TargetToUse;
95470af4f57SMichael Kruse if (!Known.is_null()) {
95570af4f57SMichael Kruse isl::space DomSpace = Stmt->getDomainSpace();
95670af4f57SMichael Kruse TargetToUse =
95770af4f57SMichael Kruse isl::map::identity(DomSpace.map_from_domain_and_range(DomSpace));
95870af4f57SMichael Kruse }
95970af4f57SMichael Kruse
960d3ce899dSMichael Kruse ForwardingDecision Assessment =
9617175cffbSMichael Kruse forwardTree(Stmt, RA->getAccessValue(), Stmt, InLoop);
962a6b2de3bSMichael Kruse
9637175cffbSMichael Kruse // If considered feasible and profitable, forward it.
9647175cffbSMichael Kruse bool Changed = false;
9657175cffbSMichael Kruse if (Assessment == FD_CanForwardProfitably) {
9667175cffbSMichael Kruse applyForwardingActions(Stmt, RA->getAccessValue(), RA);
9677175cffbSMichael Kruse Changed = true;
9687175cffbSMichael Kruse }
969a6b2de3bSMichael Kruse
9707175cffbSMichael Kruse ForwardingActions.clear();
9717175cffbSMichael Kruse return Changed;
972a6b2de3bSMichael Kruse }
973a6b2de3bSMichael Kruse
974a6b2de3bSMichael Kruse /// Return which SCoP this instance is processing.
getScop() const975a6b2de3bSMichael Kruse Scop *getScop() const { return S; }
976a6b2de3bSMichael Kruse
977a6b2de3bSMichael Kruse /// Run the algorithm: Use value read accesses as operand tree roots and try
978a6b2de3bSMichael Kruse /// to forward them into the statement.
forwardOperandTrees()979a6b2de3bSMichael Kruse bool forwardOperandTrees() {
980a6b2de3bSMichael Kruse for (ScopStmt &Stmt : *S) {
981a6b2de3bSMichael Kruse bool StmtModified = false;
982a6b2de3bSMichael Kruse
983a6b2de3bSMichael Kruse // Because we are modifying the MemoryAccess list, collect them first to
984a6b2de3bSMichael Kruse // avoid iterator invalidation.
985c8a0e27cSMichael Kruse SmallVector<MemoryAccess *, 16> Accs(Stmt.begin(), Stmt.end());
986c8a0e27cSMichael Kruse
987c8a0e27cSMichael Kruse for (MemoryAccess *RA : Accs) {
988a6b2de3bSMichael Kruse if (!RA->isRead())
989a6b2de3bSMichael Kruse continue;
990a6b2de3bSMichael Kruse if (!RA->isLatestScalarKind())
991a6b2de3bSMichael Kruse continue;
992a6b2de3bSMichael Kruse
993a6b2de3bSMichael Kruse if (tryForwardTree(RA)) {
994a6b2de3bSMichael Kruse Modified = true;
995a6b2de3bSMichael Kruse StmtModified = true;
996a6b2de3bSMichael Kruse NumForwardedTrees++;
997a6b2de3bSMichael Kruse TotalForwardedTrees++;
998a6b2de3bSMichael Kruse }
999a6b2de3bSMichael Kruse }
1000a6b2de3bSMichael Kruse
1001a6b2de3bSMichael Kruse if (StmtModified) {
1002a6b2de3bSMichael Kruse NumModifiedStmts++;
1003a6b2de3bSMichael Kruse TotalModifiedStmts++;
1004a6b2de3bSMichael Kruse }
1005a6b2de3bSMichael Kruse }
1006a6b2de3bSMichael Kruse
1007e8227804SMichael Kruse if (Modified) {
1008a6b2de3bSMichael Kruse ScopsModified++;
1009e8227804SMichael Kruse S->realignParams();
1010e8227804SMichael Kruse }
1011a6b2de3bSMichael Kruse return Modified;
1012a6b2de3bSMichael Kruse }
1013a6b2de3bSMichael Kruse
1014a6b2de3bSMichael Kruse /// Print the pass result, performed transformations and the SCoP after the
1015a6b2de3bSMichael Kruse /// transformation.
print(raw_ostream & OS,int Indent=0)10169248fde5SEugene Zelenko void print(raw_ostream &OS, int Indent = 0) {
1017a6b2de3bSMichael Kruse printStatistics(OS, Indent);
1018a6b2de3bSMichael Kruse
1019a6b2de3bSMichael Kruse if (!Modified) {
1020a6b2de3bSMichael Kruse // This line can easily be checked in regression tests.
1021a6b2de3bSMichael Kruse OS << "ForwardOpTree executed, but did not modify anything\n";
1022a6b2de3bSMichael Kruse return;
1023a6b2de3bSMichael Kruse }
1024a6b2de3bSMichael Kruse
1025a6b2de3bSMichael Kruse printStatements(OS, Indent);
1026a6b2de3bSMichael Kruse }
10274c64d8eeSMichael Kruse
isModified() const10284c64d8eeSMichael Kruse bool isModified() const { return Modified; }
1029a6b2de3bSMichael Kruse };
1030a6b2de3bSMichael Kruse
runForwardOpTree(Scop & S,LoopInfo & LI)10314c64d8eeSMichael Kruse static std::unique_ptr<ForwardOpTreeImpl> runForwardOpTree(Scop &S,
10324c64d8eeSMichael Kruse LoopInfo &LI) {
1033a6b2de3bSMichael Kruse std::unique_ptr<ForwardOpTreeImpl> Impl;
103489972e21SMichael Kruse {
103500fd43b3SPhilip Pfaffe IslMaxOperationsGuard MaxOpGuard(S.getIslCtx().get(), MaxOps, false);
1036736259e3SJonas Devlieghere Impl = std::make_unique<ForwardOpTreeImpl>(&S, &LI, MaxOpGuard);
1037a6b2de3bSMichael Kruse
103870af4f57SMichael Kruse if (AnalyzeKnown) {
1039349506a9SNicola Zaghen LLVM_DEBUG(dbgs() << "Prepare forwarders...\n");
104070af4f57SMichael Kruse Impl->computeKnownValues();
104170af4f57SMichael Kruse }
104270af4f57SMichael Kruse
1043349506a9SNicola Zaghen LLVM_DEBUG(dbgs() << "Forwarding operand trees...\n");
1044a6b2de3bSMichael Kruse Impl->forwardOperandTrees();
1045a6b2de3bSMichael Kruse
104689972e21SMichael Kruse if (MaxOpGuard.hasQuotaExceeded()) {
1047349506a9SNicola Zaghen LLVM_DEBUG(dbgs() << "Not all operations completed because of "
104889972e21SMichael Kruse "max_operations exceeded\n");
104989972e21SMichael Kruse KnownOutOfQuota++;
105089972e21SMichael Kruse }
105189972e21SMichael Kruse }
105289972e21SMichael Kruse
1053349506a9SNicola Zaghen LLVM_DEBUG(dbgs() << "\nFinal Scop:\n");
1054349506a9SNicola Zaghen LLVM_DEBUG(dbgs() << S);
1055a6b2de3bSMichael Kruse
105606ed5292SMichael Kruse // Update statistics
10574c64d8eeSMichael Kruse Scop::ScopStatistics ScopStats = S.getStatistics();
105806ed5292SMichael Kruse NumValueWrites += ScopStats.NumValueWrites;
105906ed5292SMichael Kruse NumValueWritesInLoops += ScopStats.NumValueWritesInLoops;
106006ed5292SMichael Kruse NumPHIWrites += ScopStats.NumPHIWrites;
106106ed5292SMichael Kruse NumPHIWritesInLoops += ScopStats.NumPHIWritesInLoops;
106206ed5292SMichael Kruse NumSingletonWrites += ScopStats.NumSingletonWrites;
106306ed5292SMichael Kruse NumSingletonWritesInLoops += ScopStats.NumSingletonWritesInLoops;
106406ed5292SMichael Kruse
10654c64d8eeSMichael Kruse return Impl;
10664c64d8eeSMichael Kruse }
10674c64d8eeSMichael Kruse
10684c64d8eeSMichael Kruse static PreservedAnalyses
runForwardOpTreeUsingNPM(Scop & S,ScopAnalysisManager & SAM,ScopStandardAnalysisResults & SAR,SPMUpdater & U,raw_ostream * OS)10694c64d8eeSMichael Kruse runForwardOpTreeUsingNPM(Scop &S, ScopAnalysisManager &SAM,
10704c64d8eeSMichael Kruse ScopStandardAnalysisResults &SAR, SPMUpdater &U,
10714c64d8eeSMichael Kruse raw_ostream *OS) {
10724c64d8eeSMichael Kruse LoopInfo &LI = SAR.LI;
10734c64d8eeSMichael Kruse
10744c64d8eeSMichael Kruse std::unique_ptr<ForwardOpTreeImpl> Impl = runForwardOpTree(S, LI);
10754c64d8eeSMichael Kruse if (OS) {
10764c64d8eeSMichael Kruse *OS << "Printing analysis 'Polly - Forward operand tree' for region: '"
10774c64d8eeSMichael Kruse << S.getName() << "' in function '" << S.getFunction().getName()
10784c64d8eeSMichael Kruse << "':\n";
10794c64d8eeSMichael Kruse if (Impl) {
10804c64d8eeSMichael Kruse assert(Impl->getScop() == &S);
10814c64d8eeSMichael Kruse
10824c64d8eeSMichael Kruse Impl->print(*OS);
10834c64d8eeSMichael Kruse }
10844c64d8eeSMichael Kruse }
10854c64d8eeSMichael Kruse
10864c64d8eeSMichael Kruse if (!Impl->isModified())
10874c64d8eeSMichael Kruse return PreservedAnalyses::all();
10884c64d8eeSMichael Kruse
10894c64d8eeSMichael Kruse PreservedAnalyses PA;
10904c64d8eeSMichael Kruse PA.preserveSet<AllAnalysesOn<Module>>();
10914c64d8eeSMichael Kruse PA.preserveSet<AllAnalysesOn<Function>>();
10924c64d8eeSMichael Kruse PA.preserveSet<AllAnalysesOn<Loop>>();
10934c64d8eeSMichael Kruse return PA;
10944c64d8eeSMichael Kruse }
10954c64d8eeSMichael Kruse
10964c64d8eeSMichael Kruse /// Pass that redirects scalar reads to array elements that are known to contain
10974c64d8eeSMichael Kruse /// the same value.
10984c64d8eeSMichael Kruse ///
10994c64d8eeSMichael Kruse /// This reduces the number of scalar accesses and therefore potentially
11004c64d8eeSMichael Kruse /// increases the freedom of the scheduler. In the ideal case, all reads of a
11014c64d8eeSMichael Kruse /// scalar definition are redirected (We currently do not care about removing
11024c64d8eeSMichael Kruse /// the write in this case). This is also useful for the main DeLICM pass as
11034c64d8eeSMichael Kruse /// there are less scalars to be mapped.
1104*bd93df93SMichael Kruse class ForwardOpTreeWrapperPass final : public ScopPass {
11054c64d8eeSMichael Kruse private:
11064c64d8eeSMichael Kruse /// The pass implementation, also holding per-scop data.
11074c64d8eeSMichael Kruse std::unique_ptr<ForwardOpTreeImpl> Impl;
11084c64d8eeSMichael Kruse
11094c64d8eeSMichael Kruse public:
11104c64d8eeSMichael Kruse static char ID;
11114c64d8eeSMichael Kruse
ForwardOpTreeWrapperPass()11124c64d8eeSMichael Kruse explicit ForwardOpTreeWrapperPass() : ScopPass(ID) {}
11134c64d8eeSMichael Kruse ForwardOpTreeWrapperPass(const ForwardOpTreeWrapperPass &) = delete;
11144c64d8eeSMichael Kruse ForwardOpTreeWrapperPass &
11154c64d8eeSMichael Kruse operator=(const ForwardOpTreeWrapperPass &) = delete;
11164c64d8eeSMichael Kruse
getAnalysisUsage(AnalysisUsage & AU) const11174c64d8eeSMichael Kruse void getAnalysisUsage(AnalysisUsage &AU) const override {
11184c64d8eeSMichael Kruse AU.addRequiredTransitive<ScopInfoRegionPass>();
11194c64d8eeSMichael Kruse AU.addRequired<LoopInfoWrapperPass>();
11204c64d8eeSMichael Kruse AU.setPreservesAll();
11214c64d8eeSMichael Kruse }
11224c64d8eeSMichael Kruse
runOnScop(Scop & S)11234c64d8eeSMichael Kruse bool runOnScop(Scop &S) override {
11244c64d8eeSMichael Kruse // Free resources for previous SCoP's computation, if not yet done.
11254c64d8eeSMichael Kruse releaseMemory();
11264c64d8eeSMichael Kruse
11274c64d8eeSMichael Kruse LoopInfo &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
11284c64d8eeSMichael Kruse
11294c64d8eeSMichael Kruse Impl = runForwardOpTree(S, LI);
11304c64d8eeSMichael Kruse
1131a6b2de3bSMichael Kruse return false;
1132a6b2de3bSMichael Kruse }
1133a6b2de3bSMichael Kruse
printScop(raw_ostream & OS,Scop & S) const11349248fde5SEugene Zelenko void printScop(raw_ostream &OS, Scop &S) const override {
1135a6b2de3bSMichael Kruse if (!Impl)
1136a6b2de3bSMichael Kruse return;
1137a6b2de3bSMichael Kruse
1138a6b2de3bSMichael Kruse assert(Impl->getScop() == &S);
1139a6b2de3bSMichael Kruse Impl->print(OS);
1140a6b2de3bSMichael Kruse }
1141a6b2de3bSMichael Kruse
releaseMemory()11429248fde5SEugene Zelenko void releaseMemory() override { Impl.reset(); }
1143a6b2de3bSMichael Kruse }; // class ForwardOpTree
1144a6b2de3bSMichael Kruse
11454c64d8eeSMichael Kruse char ForwardOpTreeWrapperPass::ID;
11465c028081SMichael Kruse
11475c028081SMichael Kruse /// Print result from ForwardOpTreeWrapperPass.
1148*bd93df93SMichael Kruse class ForwardOpTreePrinterLegacyPass final : public ScopPass {
11495c028081SMichael Kruse public:
11505c028081SMichael Kruse static char ID;
11515c028081SMichael Kruse
ForwardOpTreePrinterLegacyPass()11525c028081SMichael Kruse ForwardOpTreePrinterLegacyPass() : ForwardOpTreePrinterLegacyPass(outs()){};
ForwardOpTreePrinterLegacyPass(llvm::raw_ostream & OS)11535c028081SMichael Kruse explicit ForwardOpTreePrinterLegacyPass(llvm::raw_ostream &OS)
11545c028081SMichael Kruse : ScopPass(ID), OS(OS) {}
11555c028081SMichael Kruse
runOnScop(Scop & S)11565c028081SMichael Kruse bool runOnScop(Scop &S) override {
11575c028081SMichael Kruse ForwardOpTreeWrapperPass &P = getAnalysis<ForwardOpTreeWrapperPass>();
11585c028081SMichael Kruse
11595c028081SMichael Kruse OS << "Printing analysis '" << P.getPassName() << "' for region: '"
11605c028081SMichael Kruse << S.getRegion().getNameStr() << "' in function '"
11615c028081SMichael Kruse << S.getFunction().getName() << "':\n";
11625c028081SMichael Kruse P.printScop(OS, S);
11635c028081SMichael Kruse
11645c028081SMichael Kruse return false;
11655c028081SMichael Kruse }
11665c028081SMichael Kruse
getAnalysisUsage(AnalysisUsage & AU) const11675c028081SMichael Kruse void getAnalysisUsage(AnalysisUsage &AU) const override {
11685c028081SMichael Kruse ScopPass::getAnalysisUsage(AU);
11695c028081SMichael Kruse AU.addRequired<ForwardOpTreeWrapperPass>();
11705c028081SMichael Kruse AU.setPreservesAll();
11715c028081SMichael Kruse }
11725c028081SMichael Kruse
11735c028081SMichael Kruse private:
11745c028081SMichael Kruse llvm::raw_ostream &OS;
11755c028081SMichael Kruse };
11765c028081SMichael Kruse
11775c028081SMichael Kruse char ForwardOpTreePrinterLegacyPass::ID = 0;
11789248fde5SEugene Zelenko } // namespace
1179a6b2de3bSMichael Kruse
createForwardOpTreeWrapperPass()11804c64d8eeSMichael Kruse Pass *polly::createForwardOpTreeWrapperPass() {
11814c64d8eeSMichael Kruse return new ForwardOpTreeWrapperPass();
11824c64d8eeSMichael Kruse }
1183a6b2de3bSMichael Kruse
createForwardOpTreePrinterLegacyPass(llvm::raw_ostream & OS)11845c028081SMichael Kruse Pass *polly::createForwardOpTreePrinterLegacyPass(llvm::raw_ostream &OS) {
11855c028081SMichael Kruse return new ForwardOpTreePrinterLegacyPass(OS);
11865c028081SMichael Kruse }
11875c028081SMichael Kruse
run(Scop & S,ScopAnalysisManager & SAM,ScopStandardAnalysisResults & SAR,SPMUpdater & U)11884c64d8eeSMichael Kruse llvm::PreservedAnalyses ForwardOpTreePass::run(Scop &S,
11894c64d8eeSMichael Kruse ScopAnalysisManager &SAM,
11904c64d8eeSMichael Kruse ScopStandardAnalysisResults &SAR,
11914c64d8eeSMichael Kruse SPMUpdater &U) {
11924c64d8eeSMichael Kruse return runForwardOpTreeUsingNPM(S, SAM, SAR, U, nullptr);
11934c64d8eeSMichael Kruse }
11944c64d8eeSMichael Kruse
11954c64d8eeSMichael Kruse llvm::PreservedAnalyses
run(Scop & S,ScopAnalysisManager & SAM,ScopStandardAnalysisResults & SAR,SPMUpdater & U)11964c64d8eeSMichael Kruse ForwardOpTreePrinterPass::run(Scop &S, ScopAnalysisManager &SAM,
11974c64d8eeSMichael Kruse ScopStandardAnalysisResults &SAR, SPMUpdater &U) {
11984c64d8eeSMichael Kruse return runForwardOpTreeUsingNPM(S, SAM, SAR, U, &OS);
11994c64d8eeSMichael Kruse }
1200ad84c6f6SMichael Kruse
1201ad84c6f6SMichael Kruse INITIALIZE_PASS_BEGIN(ForwardOpTreeWrapperPass, "polly-optree",
1202ad84c6f6SMichael Kruse "Polly - Forward operand tree", false, false)
1203ad84c6f6SMichael Kruse INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
1204ad84c6f6SMichael Kruse INITIALIZE_PASS_END(ForwardOpTreeWrapperPass, "polly-optree",
1205ad84c6f6SMichael Kruse "Polly - Forward operand tree", false, false)
12065c028081SMichael Kruse
12075c028081SMichael Kruse INITIALIZE_PASS_BEGIN(ForwardOpTreePrinterLegacyPass, "polly-print-optree",
12085c028081SMichael Kruse "Polly - Print forward operand tree result", false, false)
12095c028081SMichael Kruse INITIALIZE_PASS_DEPENDENCY(ForwardOpTreeWrapperPass)
12105c028081SMichael Kruse INITIALIZE_PASS_END(ForwardOpTreePrinterLegacyPass, "polly-print-optree",
12115c028081SMichael Kruse "Polly - Print forward operand tree result", false, false)
1212