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
43*601d7eabSKarthika Devi C #include "polly/Support/PollyDebug.h"
4436550bacSMichael Kruse #define DEBUG_TYPE "polly-optree"
45a6b2de3bSMichael Kruse
46a6b2de3bSMichael Kruse using namespace llvm;
479248fde5SEugene Zelenko using namespace polly;
48a6b2de3bSMichael Kruse
4970af4f57SMichael Kruse static cl::opt<bool>
5070af4f57SMichael Kruse AnalyzeKnown("polly-optree-analyze-known",
5170af4f57SMichael Kruse cl::desc("Analyze array contents for load forwarding"),
5270af4f57SMichael Kruse cl::cat(PollyCategory), cl::init(true), cl::Hidden);
5370af4f57SMichael Kruse
5468821a8bSMichael Kruse static cl::opt<bool>
5568821a8bSMichael Kruse NormalizePHIs("polly-optree-normalize-phi",
5668821a8bSMichael Kruse cl::desc("Replace PHIs by their incoming values"),
5768821a8bSMichael Kruse cl::cat(PollyCategory), cl::init(false), cl::Hidden);
5868821a8bSMichael Kruse
59ef8325baSMichael Kruse static cl::opt<unsigned>
6070af4f57SMichael Kruse MaxOps("polly-optree-max-ops",
6170af4f57SMichael Kruse cl::desc("Maximum number of ISL operations to invest for known "
6270af4f57SMichael Kruse "analysis; 0=no limit"),
6370af4f57SMichael Kruse cl::init(1000000), cl::cat(PollyCategory), cl::Hidden);
6470af4f57SMichael Kruse
6570af4f57SMichael Kruse STATISTIC(KnownAnalyzed, "Number of successfully analyzed SCoPs");
6670af4f57SMichael Kruse STATISTIC(KnownOutOfQuota,
6770af4f57SMichael Kruse "Analyses aborted because max_operations was reached");
6870af4f57SMichael Kruse
69a6b2de3bSMichael Kruse STATISTIC(TotalInstructionsCopied, "Number of copied instructions");
7070af4f57SMichael Kruse STATISTIC(TotalKnownLoadsForwarded,
7170af4f57SMichael Kruse "Number of forwarded loads because their value was known");
72822dfe27SMichael Kruse STATISTIC(TotalReloads, "Number of reloaded values");
7307e8c36dSMichael Kruse STATISTIC(TotalReadOnlyCopied, "Number of copied read-only accesses");
74a6b2de3bSMichael Kruse STATISTIC(TotalForwardedTrees, "Number of forwarded operand trees");
75a6b2de3bSMichael Kruse STATISTIC(TotalModifiedStmts,
76a6b2de3bSMichael Kruse "Number of statements with at least one forwarded tree");
77a6b2de3bSMichael Kruse
78a6b2de3bSMichael Kruse STATISTIC(ScopsModified, "Number of SCoPs with at least one forwarded tree");
79a6b2de3bSMichael Kruse
8006ed5292SMichael Kruse STATISTIC(NumValueWrites, "Number of scalar value writes after OpTree");
8106ed5292SMichael Kruse STATISTIC(NumValueWritesInLoops,
8206ed5292SMichael Kruse "Number of scalar value writes nested in affine loops after OpTree");
8306ed5292SMichael Kruse STATISTIC(NumPHIWrites, "Number of scalar phi writes after OpTree");
8406ed5292SMichael Kruse STATISTIC(NumPHIWritesInLoops,
8506ed5292SMichael Kruse "Number of scalar phi writes nested in affine loops after OpTree");
8606ed5292SMichael Kruse STATISTIC(NumSingletonWrites, "Number of singleton writes after OpTree");
8706ed5292SMichael Kruse STATISTIC(NumSingletonWritesInLoops,
8806ed5292SMichael Kruse "Number of singleton writes nested in affine loops after OpTree");
8906ed5292SMichael Kruse
90a6b2de3bSMichael Kruse namespace {
91a6b2de3bSMichael Kruse
92a6b2de3bSMichael Kruse /// The state of whether an operand tree was/can be forwarded.
93d85e345cSMichael Kruse ///
94d85e345cSMichael Kruse /// The items apply to an instructions and its operand tree with the instruction
95d85e345cSMichael Kruse /// as the root element. If the value in question is not an instruction in the
96d85e345cSMichael Kruse /// SCoP, it can be a leaf of an instruction's operand tree.
97a6b2de3bSMichael Kruse enum ForwardingDecision {
987175cffbSMichael Kruse /// An uninitialized value.
997175cffbSMichael Kruse FD_Unknown,
1007175cffbSMichael Kruse
101d85e345cSMichael Kruse /// The root instruction or value cannot be forwarded at all.
102a6b2de3bSMichael Kruse FD_CannotForward,
103d85e345cSMichael Kruse
104d85e345cSMichael Kruse /// The root instruction or value can be forwarded as a leaf of a larger
105d85e345cSMichael Kruse /// operand tree.
106d85e345cSMichael Kruse /// It does not make sense to move the value itself, it would just replace it
107d85e345cSMichael Kruse /// by a use of itself. For instance, a constant "5" used in a statement can
108d85e345cSMichael Kruse /// be forwarded, but it would just replace it by the same constant "5".
109d85e345cSMichael Kruse /// However, it makes sense to move as an operand of
110d85e345cSMichael Kruse ///
111d85e345cSMichael Kruse /// %add = add 5, 5
112d85e345cSMichael Kruse ///
113d85e345cSMichael Kruse /// where "5" is moved as part of a larger operand tree. "5" would be placed
114d85e345cSMichael Kruse /// (disregarding for a moment that literal constants don't have a location
115d85e345cSMichael Kruse /// and can be used anywhere) into the same statement as %add would.
11667752076SMichael Kruse FD_CanForwardLeaf,
117d85e345cSMichael Kruse
118822dfe27SMichael Kruse /// The root instruction can be forwarded and doing so avoids a scalar
119822dfe27SMichael Kruse /// dependency.
120822dfe27SMichael Kruse ///
121822dfe27SMichael Kruse /// This can be either because the operand tree can be moved to the target
122822dfe27SMichael Kruse /// statement, or a memory access is redirected to read from a different
123822dfe27SMichael Kruse /// location.
124822dfe27SMichael Kruse FD_CanForwardProfitably,
125d85e345cSMichael Kruse
126a9a70863SMichael Kruse /// A forwarding method cannot be applied to the operand tree.
127a9a70863SMichael Kruse /// The difference to FD_CannotForward is that there might be other methods
128a9a70863SMichael Kruse /// that can handle it.
129a9a70863SMichael Kruse FD_NotApplicable
130a6b2de3bSMichael Kruse };
131a6b2de3bSMichael Kruse
1327175cffbSMichael Kruse /// Represents the evaluation of and action to taken when forwarding a value
1337175cffbSMichael Kruse /// from an operand tree.
1347175cffbSMichael Kruse struct ForwardingAction {
1357175cffbSMichael Kruse using KeyTy = std::pair<Value *, ScopStmt *>;
1367175cffbSMichael Kruse
1377175cffbSMichael Kruse /// Evaluation of forwarding a value.
1387175cffbSMichael Kruse ForwardingDecision Decision = FD_Unknown;
1397175cffbSMichael Kruse
1407175cffbSMichael Kruse /// Callback to execute the forwarding.
1417175cffbSMichael Kruse /// Returning true allows deleting the polly::MemoryAccess if the value is the
1427175cffbSMichael Kruse /// root of the operand tree (and its elimination the reason why the
1437175cffbSMichael Kruse /// forwarding is done). Return false if the MemoryAccess is reused or there
1447175cffbSMichael Kruse /// might be other users of the read accesses. In the letter case the
1457175cffbSMichael Kruse /// polly::SimplifyPass can remove dead MemoryAccesses.
__anon8f337d270202__anon8f337d270111::ForwardingAction1467175cffbSMichael Kruse std::function<bool()> Execute = []() -> bool {
1477175cffbSMichael Kruse llvm_unreachable("unspecified how to forward");
1487175cffbSMichael Kruse };
1497175cffbSMichael Kruse
1507175cffbSMichael Kruse /// Other values that need to be forwarded if this action is executed. Their
1517175cffbSMichael Kruse /// actions are executed after this one.
1527175cffbSMichael Kruse SmallVector<KeyTy, 4> Depends;
1537175cffbSMichael Kruse
1547175cffbSMichael Kruse /// Named ctor: The method creating this object does not apply to the kind of
1557175cffbSMichael Kruse /// value, but other methods may.
notApplicable__anon8f337d270111::ForwardingAction1567175cffbSMichael Kruse static ForwardingAction notApplicable() {
1577175cffbSMichael Kruse ForwardingAction Result;
1587175cffbSMichael Kruse Result.Decision = FD_NotApplicable;
1597175cffbSMichael Kruse return Result;
1607175cffbSMichael Kruse }
1617175cffbSMichael Kruse
1627175cffbSMichael Kruse /// Named ctor: The value cannot be forwarded.
cannotForward__anon8f337d270111::ForwardingAction1637175cffbSMichael Kruse static ForwardingAction cannotForward() {
1647175cffbSMichael Kruse ForwardingAction Result;
1657175cffbSMichael Kruse Result.Decision = FD_CannotForward;
1667175cffbSMichael Kruse return Result;
1677175cffbSMichael Kruse }
1687175cffbSMichael Kruse
1697175cffbSMichael Kruse /// Named ctor: The value can just be used without any preparation.
triviallyForwardable__anon8f337d270111::ForwardingAction170c1cf51e7SMichael Kruse static ForwardingAction triviallyForwardable(bool IsProfitable, Value *Val) {
1717175cffbSMichael Kruse ForwardingAction Result;
1727175cffbSMichael Kruse Result.Decision =
1737175cffbSMichael Kruse IsProfitable ? FD_CanForwardProfitably : FD_CanForwardLeaf;
174c1cf51e7SMichael Kruse Result.Execute = [=]() {
175*601d7eabSKarthika Devi C POLLY_DEBUG(dbgs() << " trivially forwarded: " << *Val << "\n");
176c1cf51e7SMichael Kruse return true;
177c1cf51e7SMichael Kruse };
1787175cffbSMichael Kruse return Result;
1797175cffbSMichael Kruse }
1807175cffbSMichael Kruse
1817175cffbSMichael Kruse /// Name ctor: The value can be forwarded by executing an action.
canForward__anon8f337d270111::ForwardingAction1827175cffbSMichael Kruse static ForwardingAction canForward(std::function<bool()> Execute,
1837175cffbSMichael Kruse ArrayRef<KeyTy> Depends,
1847175cffbSMichael Kruse bool IsProfitable) {
1857175cffbSMichael Kruse ForwardingAction Result;
1867175cffbSMichael Kruse Result.Decision =
1877175cffbSMichael Kruse IsProfitable ? FD_CanForwardProfitably : FD_CanForwardLeaf;
1887175cffbSMichael Kruse Result.Execute = std::move(Execute);
1897175cffbSMichael Kruse Result.Depends.append(Depends.begin(), Depends.end());
1907175cffbSMichael Kruse return Result;
1917175cffbSMichael Kruse }
1927175cffbSMichael Kruse };
1937175cffbSMichael Kruse
194a6b2de3bSMichael Kruse /// Implementation of operand tree forwarding for a specific SCoP.
195a6b2de3bSMichael Kruse ///
196a6b2de3bSMichael Kruse /// For a statement that requires a scalar value (through a value read
197a6b2de3bSMichael Kruse /// MemoryAccess), see if its operand can be moved into the statement. If so,
198a6b2de3bSMichael Kruse /// the MemoryAccess is removed and the all the operand tree instructions are
199a6b2de3bSMichael Kruse /// moved into the statement. All original instructions are left in the source
200a6b2de3bSMichael Kruse /// statements. The simplification pass can clean these up.
201bd93df93SMichael Kruse class ForwardOpTreeImpl final : ZoneAlgorithm {
202a6b2de3bSMichael Kruse private:
2037175cffbSMichael Kruse using MemoizationTy = DenseMap<ForwardingAction::KeyTy, ForwardingAction>;
2047175cffbSMichael Kruse
20589972e21SMichael Kruse /// Scope guard to limit the number of isl operations for this pass.
20689972e21SMichael Kruse IslMaxOperationsGuard &MaxOpGuard;
20789972e21SMichael Kruse
208a6b2de3bSMichael Kruse /// How many instructions have been copied to other statements.
209a6b2de3bSMichael Kruse int NumInstructionsCopied = 0;
210a6b2de3bSMichael Kruse
21170af4f57SMichael Kruse /// Number of loads forwarded because their value was known.
21270af4f57SMichael Kruse int NumKnownLoadsForwarded = 0;
21370af4f57SMichael Kruse
214822dfe27SMichael Kruse /// Number of values reloaded from known array elements.
215822dfe27SMichael Kruse int NumReloads = 0;
216822dfe27SMichael Kruse
21707e8c36dSMichael Kruse /// How many read-only accesses have been copied.
21807e8c36dSMichael Kruse int NumReadOnlyCopied = 0;
21907e8c36dSMichael Kruse
220a6b2de3bSMichael Kruse /// How many operand trees have been forwarded.
221a6b2de3bSMichael Kruse int NumForwardedTrees = 0;
222a6b2de3bSMichael Kruse
223a6b2de3bSMichael Kruse /// Number of statements with at least one forwarded operand tree.
224a6b2de3bSMichael Kruse int NumModifiedStmts = 0;
225a6b2de3bSMichael Kruse
226a6b2de3bSMichael Kruse /// Whether we carried out at least one change to the SCoP.
227a6b2de3bSMichael Kruse bool Modified = false;
228a6b2de3bSMichael Kruse
2297175cffbSMichael Kruse /// Cache of how to forward values.
2307175cffbSMichael Kruse /// The key of this map is the llvm::Value to be forwarded and the
2317175cffbSMichael Kruse /// polly::ScopStmt it is forwarded from. This is because the same llvm::Value
2327175cffbSMichael Kruse /// can evaluate differently depending on where it is evaluate. For instance,
2337175cffbSMichael Kruse /// a synthesizable Scev represents a recurrence with an loop but the loop's
2347175cffbSMichael Kruse /// exit value if evaluated after the loop.
2357175cffbSMichael Kruse /// The cached results are only valid for the current TargetStmt.
2367175cffbSMichael Kruse /// CHECKME: ScalarEvolution::getScevAtScope should take care for getting the
2377175cffbSMichael Kruse /// exit value when instantiated outside of the loop. The primary concern is
2387175cffbSMichael Kruse /// ambiguity when crossing PHI nodes, which currently is not supported.
2397175cffbSMichael Kruse MemoizationTy ForwardingActions;
2407175cffbSMichael Kruse
24170af4f57SMichael Kruse /// Contains the zones where array elements are known to contain a specific
24270af4f57SMichael Kruse /// value.
24370af4f57SMichael Kruse /// { [Element[] -> Zone[]] -> ValInst[] }
24470af4f57SMichael Kruse /// @see computeKnown()
24570af4f57SMichael Kruse isl::union_map Known;
24670af4f57SMichael Kruse
24770af4f57SMichael Kruse /// Translator for newly introduced ValInsts to already existing ValInsts such
24870af4f57SMichael Kruse /// that new introduced load instructions can reuse the Known analysis of its
24970af4f57SMichael Kruse /// original load. { ValInst[] -> ValInst[] }
25070af4f57SMichael Kruse isl::union_map Translator;
25170af4f57SMichael Kruse
25270af4f57SMichael Kruse /// Get list of array elements that do contain the same ValInst[] at Domain[].
25370af4f57SMichael Kruse ///
25470af4f57SMichael Kruse /// @param ValInst { Domain[] -> ValInst[] }
25570af4f57SMichael Kruse /// The values for which we search for alternative locations,
25670af4f57SMichael Kruse /// per statement instance.
25770af4f57SMichael Kruse ///
25870af4f57SMichael Kruse /// @return { Domain[] -> Element[] }
25970af4f57SMichael Kruse /// For each statement instance, the array elements that contain the
26070af4f57SMichael Kruse /// same ValInst.
findSameContentElements(isl::union_map ValInst)26170af4f57SMichael Kruse isl::union_map findSameContentElements(isl::union_map ValInst) {
262e276e9f3SMichael Kruse assert(!ValInst.is_single_valued().is_false());
26370af4f57SMichael Kruse
26470af4f57SMichael Kruse // { Domain[] }
26570af4f57SMichael Kruse isl::union_set Domain = ValInst.domain();
26670af4f57SMichael Kruse
26770af4f57SMichael Kruse // { Domain[] -> Scatter[] }
26870af4f57SMichael Kruse isl::union_map Schedule = getScatterFor(Domain);
26970af4f57SMichael Kruse
27070af4f57SMichael Kruse // { Element[] -> [Scatter[] -> ValInst[]] }
27170af4f57SMichael Kruse isl::union_map MustKnownCurried =
27270af4f57SMichael Kruse convertZoneToTimepoints(Known, isl::dim::in, false, true).curry();
27370af4f57SMichael Kruse
27470af4f57SMichael Kruse // { [Domain[] -> ValInst[]] -> Scatter[] }
27570af4f57SMichael Kruse isl::union_map DomValSched = ValInst.domain_map().apply_range(Schedule);
27670af4f57SMichael Kruse
27770af4f57SMichael Kruse // { [Scatter[] -> ValInst[]] -> [Domain[] -> ValInst[]] }
27870af4f57SMichael Kruse isl::union_map SchedValDomVal =
27970af4f57SMichael Kruse DomValSched.range_product(ValInst.range_map()).reverse();
28070af4f57SMichael Kruse
28170af4f57SMichael Kruse // { Element[] -> [Domain[] -> ValInst[]] }
28270af4f57SMichael Kruse isl::union_map MustKnownInst = MustKnownCurried.apply_range(SchedValDomVal);
28370af4f57SMichael Kruse
28470af4f57SMichael Kruse // { Domain[] -> Element[] }
28570af4f57SMichael Kruse isl::union_map MustKnownMap =
28670af4f57SMichael Kruse MustKnownInst.uncurry().domain().unwrap().reverse();
28770af4f57SMichael Kruse simplify(MustKnownMap);
28870af4f57SMichael Kruse
28970af4f57SMichael Kruse return MustKnownMap;
29070af4f57SMichael Kruse }
29170af4f57SMichael Kruse
29270af4f57SMichael Kruse /// Find a single array element for each statement instance, within a single
29370af4f57SMichael Kruse /// array.
29470af4f57SMichael Kruse ///
29570af4f57SMichael Kruse /// @param MustKnown { Domain[] -> Element[] }
29670af4f57SMichael Kruse /// Set of candidate array elements.
29770af4f57SMichael Kruse /// @param Domain { Domain[] }
29870af4f57SMichael Kruse /// The statement instance for which we need elements for.
29970af4f57SMichael Kruse ///
30070af4f57SMichael Kruse /// @return { Domain[] -> Element[] }
30170af4f57SMichael Kruse /// For each statement instance, an array element out of @p MustKnown.
30270af4f57SMichael Kruse /// All array elements must be in the same array (Polly does not yet
30370af4f57SMichael Kruse /// support reading from different accesses using the same
30470af4f57SMichael Kruse /// MemoryAccess). If no mapping for all of @p Domain exists, returns
30570af4f57SMichael Kruse /// null.
singleLocation(isl::union_map MustKnown,isl::set Domain)30670af4f57SMichael Kruse isl::map singleLocation(isl::union_map MustKnown, isl::set Domain) {
30770af4f57SMichael Kruse // { Domain[] -> Element[] }
30870af4f57SMichael Kruse isl::map Result;
30970af4f57SMichael Kruse
3103b9677e1SMichael Kruse // Make irrelevant elements not interfere.
3113b9677e1SMichael Kruse Domain = Domain.intersect_params(S->getContext());
3123b9677e1SMichael Kruse
31370af4f57SMichael Kruse // MemoryAccesses can read only elements from a single array
31470af4f57SMichael Kruse // (i.e. not: { Dom[0] -> A[0]; Dom[1] -> B[1] }).
31570af4f57SMichael Kruse // Look through all spaces until we find one that contains at least the
31670af4f57SMichael Kruse // wanted statement instance.s
31791f851b1STobias Grosser for (isl::map Map : MustKnown.get_map_list()) {
31870af4f57SMichael Kruse // Get the array this is accessing.
31970af4f57SMichael Kruse isl::id ArrayId = Map.get_tuple_id(isl::dim::out);
32070af4f57SMichael Kruse ScopArrayInfo *SAI = static_cast<ScopArrayInfo *>(ArrayId.get_user());
32170af4f57SMichael Kruse
32270af4f57SMichael Kruse // No support for generation of indirect array accesses.
32370af4f57SMichael Kruse if (SAI->getBasePtrOriginSAI())
32491f851b1STobias Grosser continue;
32570af4f57SMichael Kruse
32670af4f57SMichael Kruse // Determine whether this map contains all wanted values.
32770af4f57SMichael Kruse isl::set MapDom = Map.domain();
32870af4f57SMichael Kruse if (!Domain.is_subset(MapDom).is_true())
32991f851b1STobias Grosser continue;
33070af4f57SMichael Kruse
33170af4f57SMichael Kruse // There might be multiple array elements that contain the same value, but
33270af4f57SMichael Kruse // choose only one of them. lexmin is used because it returns a one-value
33370af4f57SMichael Kruse // mapping, we do not care about which one.
33470af4f57SMichael Kruse // TODO: Get the simplest access function.
33570af4f57SMichael Kruse Result = Map.lexmin();
33691f851b1STobias Grosser break;
33791f851b1STobias Grosser }
33870af4f57SMichael Kruse
33970af4f57SMichael Kruse return Result;
34070af4f57SMichael Kruse }
34170af4f57SMichael Kruse
34270af4f57SMichael Kruse public:
ForwardOpTreeImpl(Scop * S,LoopInfo * LI,IslMaxOperationsGuard & MaxOpGuard)34389972e21SMichael Kruse ForwardOpTreeImpl(Scop *S, LoopInfo *LI, IslMaxOperationsGuard &MaxOpGuard)
34489972e21SMichael Kruse : ZoneAlgorithm("polly-optree", S, LI), MaxOpGuard(MaxOpGuard) {}
3459248fde5SEugene Zelenko
34670af4f57SMichael Kruse /// Compute the zones of known array element contents.
34770af4f57SMichael Kruse ///
34870af4f57SMichael Kruse /// @return True if the computed #Known is usable.
computeKnownValues()34970af4f57SMichael Kruse bool computeKnownValues() {
35070af4f57SMichael Kruse isl::union_map MustKnown, KnownFromLoad, KnownFromInit;
35170af4f57SMichael Kruse
35270af4f57SMichael Kruse // Check that nothing strange occurs.
35347281843SMichael Kruse collectCompatibleElts();
35470af4f57SMichael Kruse
35570af4f57SMichael Kruse {
35689972e21SMichael Kruse IslQuotaScope QuotaScope = MaxOpGuard.enter();
35770af4f57SMichael Kruse
35870af4f57SMichael Kruse computeCommon();
35968821a8bSMichael Kruse if (NormalizePHIs)
36068821a8bSMichael Kruse computeNormalizedPHIs();
36170af4f57SMichael Kruse Known = computeKnown(true, true);
36270af4f57SMichael Kruse
36370af4f57SMichael Kruse // Preexisting ValInsts use the known content analysis of themselves.
36470af4f57SMichael Kruse Translator = makeIdentityMap(Known.range(), false);
36570af4f57SMichael Kruse }
36670af4f57SMichael Kruse
3677c7978a1Spatacca if (Known.is_null() || Translator.is_null() || NormalizeMap.is_null()) {
36870af4f57SMichael Kruse assert(isl_ctx_last_error(IslCtx.get()) == isl_error_quota);
3699b41d095Spatacca Known = {};
3709b41d095Spatacca Translator = {};
3719b41d095Spatacca NormalizeMap = {};
372*601d7eabSKarthika Devi C POLLY_DEBUG(dbgs() << "Known analysis exceeded max_operations\n");
37370af4f57SMichael Kruse return false;
37470af4f57SMichael Kruse }
37570af4f57SMichael Kruse
37670af4f57SMichael Kruse KnownAnalyzed++;
377*601d7eabSKarthika Devi C POLLY_DEBUG(dbgs() << "All known: " << Known << "\n");
37870af4f57SMichael Kruse
37970af4f57SMichael Kruse return true;
38070af4f57SMichael Kruse }
38170af4f57SMichael Kruse
printStatistics(raw_ostream & OS,int Indent=0)382a6b2de3bSMichael Kruse void printStatistics(raw_ostream &OS, int Indent = 0) {
383a6b2de3bSMichael Kruse OS.indent(Indent) << "Statistics {\n";
384a6b2de3bSMichael Kruse OS.indent(Indent + 4) << "Instructions copied: " << NumInstructionsCopied
385a6b2de3bSMichael Kruse << '\n';
38670af4f57SMichael Kruse OS.indent(Indent + 4) << "Known loads forwarded: " << NumKnownLoadsForwarded
38770af4f57SMichael Kruse << '\n';
388822dfe27SMichael Kruse OS.indent(Indent + 4) << "Reloads: " << NumReloads << '\n';
38907e8c36dSMichael Kruse OS.indent(Indent + 4) << "Read-only accesses copied: " << NumReadOnlyCopied
39007e8c36dSMichael Kruse << '\n';
391a6b2de3bSMichael Kruse OS.indent(Indent + 4) << "Operand trees forwarded: " << NumForwardedTrees
392a6b2de3bSMichael Kruse << '\n';
393a6b2de3bSMichael Kruse OS.indent(Indent + 4) << "Statements with forwarded operand trees: "
394a6b2de3bSMichael Kruse << NumModifiedStmts << '\n';
395a6b2de3bSMichael Kruse OS.indent(Indent) << "}\n";
396a6b2de3bSMichael Kruse }
397a6b2de3bSMichael Kruse
printStatements(raw_ostream & OS,int Indent=0) const3989248fde5SEugene Zelenko void printStatements(raw_ostream &OS, int Indent = 0) const {
399a6b2de3bSMichael Kruse OS.indent(Indent) << "After statements {\n";
400a6b2de3bSMichael Kruse for (auto &Stmt : *S) {
401a6b2de3bSMichael Kruse OS.indent(Indent + 4) << Stmt.getBaseName() << "\n";
402a6b2de3bSMichael Kruse for (auto *MA : Stmt)
403a6b2de3bSMichael Kruse MA->print(OS);
404a6b2de3bSMichael Kruse
405a6b2de3bSMichael Kruse OS.indent(Indent + 12);
406a6b2de3bSMichael Kruse Stmt.printInstructions(OS);
407a6b2de3bSMichael Kruse }
408a6b2de3bSMichael Kruse OS.indent(Indent) << "}\n";
409a6b2de3bSMichael Kruse }
410a6b2de3bSMichael Kruse
41170af4f57SMichael Kruse /// Create a new MemoryAccess of type read and MemoryKind::Array.
41270af4f57SMichael Kruse ///
41370af4f57SMichael Kruse /// @param Stmt The statement in which the access occurs.
41470af4f57SMichael Kruse /// @param LI The instruction that does the access.
41570af4f57SMichael Kruse /// @param AccessRelation The array element that each statement instance
41670af4f57SMichael Kruse /// accesses.
41770af4f57SMichael Kruse ///
41870af4f57SMichael Kruse /// @param The newly created access.
makeReadArrayAccess(ScopStmt * Stmt,LoadInst * LI,isl::map AccessRelation)41970af4f57SMichael Kruse MemoryAccess *makeReadArrayAccess(ScopStmt *Stmt, LoadInst *LI,
42070af4f57SMichael Kruse isl::map AccessRelation) {
42170af4f57SMichael Kruse isl::id ArrayId = AccessRelation.get_tuple_id(isl::dim::out);
42270af4f57SMichael Kruse ScopArrayInfo *SAI = reinterpret_cast<ScopArrayInfo *>(ArrayId.get_user());
42370af4f57SMichael Kruse
42470af4f57SMichael Kruse // Create a dummy SCEV access, to be replaced anyway.
42570af4f57SMichael Kruse SmallVector<const SCEV *, 4> Sizes;
42670af4f57SMichael Kruse Sizes.reserve(SAI->getNumberOfDimensions());
42770af4f57SMichael Kruse SmallVector<const SCEV *, 4> Subscripts;
42870af4f57SMichael Kruse Subscripts.reserve(SAI->getNumberOfDimensions());
42970af4f57SMichael Kruse for (unsigned i = 0; i < SAI->getNumberOfDimensions(); i += 1) {
43070af4f57SMichael Kruse Sizes.push_back(SAI->getDimensionSize(i));
43170af4f57SMichael Kruse Subscripts.push_back(nullptr);
43270af4f57SMichael Kruse }
43370af4f57SMichael Kruse
43470af4f57SMichael Kruse MemoryAccess *Access =
43570af4f57SMichael Kruse new MemoryAccess(Stmt, LI, MemoryAccess::READ, SAI->getBasePtr(),
43670af4f57SMichael Kruse LI->getType(), true, {}, Sizes, LI, MemoryKind::Array);
43770af4f57SMichael Kruse S->addAccessFunction(Access);
43870af4f57SMichael Kruse Stmt->addAccess(Access, true);
43970af4f57SMichael Kruse
44070af4f57SMichael Kruse Access->setNewAccessRelation(AccessRelation);
44170af4f57SMichael Kruse
44270af4f57SMichael Kruse return Access;
44370af4f57SMichael Kruse }
44470af4f57SMichael Kruse
44570af4f57SMichael Kruse /// Forward a load by reading from an array element that contains the same
44670af4f57SMichael Kruse /// value. Typically the location it was loaded from.
44770af4f57SMichael Kruse ///
44870af4f57SMichael Kruse /// @param TargetStmt The statement the operand tree will be copied to.
44970af4f57SMichael Kruse /// @param Inst The (possibly speculatable) instruction to forward.
45070af4f57SMichael Kruse /// @param UseStmt The statement that uses @p Inst.
45170af4f57SMichael Kruse /// @param UseLoop The loop @p Inst is used in.
45270af4f57SMichael Kruse /// @param DefStmt The statement @p Inst is defined in.
45370af4f57SMichael Kruse /// @param DefLoop The loop which contains @p Inst.
45470af4f57SMichael Kruse ///
4557175cffbSMichael Kruse /// @return A ForwardingAction object describing the feasibility and
4567175cffbSMichael Kruse /// profitability evaluation and the callback carrying-out the value
4577175cffbSMichael Kruse /// forwarding.
forwardKnownLoad(ScopStmt * TargetStmt,Instruction * Inst,ScopStmt * UseStmt,Loop * UseLoop,ScopStmt * DefStmt,Loop * DefLoop)4587175cffbSMichael Kruse ForwardingAction forwardKnownLoad(ScopStmt *TargetStmt, Instruction *Inst,
45970af4f57SMichael Kruse ScopStmt *UseStmt, Loop *UseLoop,
4607175cffbSMichael Kruse ScopStmt *DefStmt, Loop *DefLoop) {
46170af4f57SMichael Kruse // Cannot do anything without successful known analysis.
462d3ce899dSMichael Kruse if (Known.is_null() || Translator.is_null() ||
463d3ce899dSMichael Kruse MaxOpGuard.hasQuotaExceeded())
4647175cffbSMichael Kruse return ForwardingAction::notApplicable();
46570af4f57SMichael Kruse
46670af4f57SMichael Kruse LoadInst *LI = dyn_cast<LoadInst>(Inst);
46770af4f57SMichael Kruse if (!LI)
4687175cffbSMichael Kruse return ForwardingAction::notApplicable();
46970af4f57SMichael Kruse
4707175cffbSMichael Kruse ForwardingDecision OpDecision =
4717175cffbSMichael Kruse forwardTree(TargetStmt, LI->getPointerOperand(), DefStmt, DefLoop);
47270af4f57SMichael Kruse switch (OpDecision) {
473822dfe27SMichael Kruse case FD_CanForwardProfitably:
4747175cffbSMichael Kruse case FD_CanForwardLeaf:
47570af4f57SMichael Kruse break;
4767175cffbSMichael Kruse case FD_CannotForward:
4777175cffbSMichael Kruse return ForwardingAction::cannotForward();
47870af4f57SMichael Kruse default:
47970af4f57SMichael Kruse llvm_unreachable("Shouldn't return this");
48070af4f57SMichael Kruse }
48170af4f57SMichael Kruse
4827175cffbSMichael Kruse MemoryAccess *Access = TargetStmt->getArrayAccessOrNULLFor(LI);
4837175cffbSMichael Kruse if (Access) {
4847175cffbSMichael Kruse // If the load is already in the statement, no forwarding is necessary.
4857175cffbSMichael Kruse // However, it might happen that the LoadInst is already present in the
4867175cffbSMichael Kruse // statement's instruction list. In that case we do as follows:
4877175cffbSMichael Kruse // - For the evaluation, we can trivially forward it as it is
4887175cffbSMichael Kruse // benefit of forwarding an already present instruction.
4897175cffbSMichael Kruse // - For the execution, prepend the instruction (to make it
4907175cffbSMichael Kruse // available to all instructions following in the instruction list), but
4917175cffbSMichael Kruse // do not add another MemoryAccess.
4927175cffbSMichael Kruse auto ExecAction = [this, TargetStmt, LI, Access]() -> bool {
4937175cffbSMichael Kruse TargetStmt->prependInstruction(LI);
494*601d7eabSKarthika Devi C POLLY_DEBUG(
4957175cffbSMichael Kruse dbgs() << " forwarded known load with preexisting MemoryAccess"
4967175cffbSMichael Kruse << Access << "\n");
49798031b66SFangrui Song (void)Access;
4987175cffbSMichael Kruse
4997175cffbSMichael Kruse NumKnownLoadsForwarded++;
5007175cffbSMichael Kruse TotalKnownLoadsForwarded++;
5017175cffbSMichael Kruse return true;
5027175cffbSMichael Kruse };
5037175cffbSMichael Kruse return ForwardingAction::canForward(
5047175cffbSMichael Kruse ExecAction, {{LI->getPointerOperand(), DefStmt}}, true);
5057175cffbSMichael Kruse }
5067175cffbSMichael Kruse
5077175cffbSMichael Kruse // Allow the following Isl calculations (until we return the
5087175cffbSMichael Kruse // ForwardingAction, excluding the code inside the lambda that will be
5097175cffbSMichael Kruse // executed later) to fail.
5107175cffbSMichael Kruse IslQuotaScope QuotaScope = MaxOpGuard.enter();
51189972e21SMichael Kruse
51270af4f57SMichael Kruse // { DomainDef[] -> ValInst[] }
51370af4f57SMichael Kruse isl::map ExpectedVal = makeValInst(Inst, UseStmt, UseLoop);
514d51fbfcaSMichael Kruse assert(!isNormalized(ExpectedVal).is_false() &&
515d51fbfcaSMichael Kruse "LoadInsts are always normalized");
51670af4f57SMichael Kruse
517d3ce899dSMichael Kruse // { DomainUse[] -> DomainTarget[] }
518d3ce899dSMichael Kruse isl::map UseToTarget = getDefToTarget(UseStmt, TargetStmt);
519d3ce899dSMichael Kruse
52070af4f57SMichael Kruse // { DomainTarget[] -> ValInst[] }
52170af4f57SMichael Kruse isl::map TargetExpectedVal = ExpectedVal.apply_domain(UseToTarget);
52270af4f57SMichael Kruse isl::union_map TranslatedExpectedVal =
52370af4f57SMichael Kruse isl::union_map(TargetExpectedVal).apply_range(Translator);
52470af4f57SMichael Kruse
52570af4f57SMichael Kruse // { DomainTarget[] -> Element[] }
52670af4f57SMichael Kruse isl::union_map Candidates = findSameContentElements(TranslatedExpectedVal);
52770af4f57SMichael Kruse
52870af4f57SMichael Kruse isl::map SameVal = singleLocation(Candidates, getDomainFor(TargetStmt));
5297c7978a1Spatacca if (SameVal.is_null())
5307175cffbSMichael Kruse return ForwardingAction::notApplicable();
531822dfe27SMichael Kruse
532*601d7eabSKarthika Devi C POLLY_DEBUG(dbgs() << " expected values where " << TargetExpectedVal
5337175cffbSMichael Kruse << "\n");
534*601d7eabSKarthika Devi C POLLY_DEBUG(dbgs() << " candidate elements where " << Candidates
5357175cffbSMichael Kruse << "\n");
53670af4f57SMichael Kruse
53770af4f57SMichael Kruse // { ValInst[] }
53870af4f57SMichael Kruse isl::space ValInstSpace = ExpectedVal.get_space().range();
53970af4f57SMichael Kruse
54070af4f57SMichael Kruse // After adding a new load to the SCoP, also update the Known content
54170af4f57SMichael Kruse // about it. The new load will have a known ValInst of
54270af4f57SMichael Kruse // { [DomainTarget[] -> Value[]] }
54370af4f57SMichael Kruse // but which -- because it is a copy of it -- has same value as the
54470af4f57SMichael Kruse // { [DomainDef[] -> Value[]] }
54570af4f57SMichael Kruse // that it replicates. Instead of cloning the known content of
54670af4f57SMichael Kruse // [DomainDef[] -> Value[]]
54770af4f57SMichael Kruse // for DomainTarget[], we add a 'translator' that maps
54870af4f57SMichael Kruse // [DomainTarget[] -> Value[]] to [DomainDef[] -> Value[]]
54970af4f57SMichael Kruse // before comparing to the known content.
55070af4f57SMichael Kruse // TODO: 'Translator' could also be used to map PHINodes to their incoming
55170af4f57SMichael Kruse // ValInsts.
5527175cffbSMichael Kruse isl::map LocalTranslator;
5537175cffbSMichael Kruse if (!ValInstSpace.is_wrapping().is_false()) {
55470af4f57SMichael Kruse // { DefDomain[] -> Value[] }
55570af4f57SMichael Kruse isl::map ValInsts = ExpectedVal.range().unwrap();
55670af4f57SMichael Kruse
55770af4f57SMichael Kruse // { DefDomain[] }
55870af4f57SMichael Kruse isl::set DefDomain = ValInsts.domain();
55970af4f57SMichael Kruse
56070af4f57SMichael Kruse // { Value[] }
56170af4f57SMichael Kruse isl::space ValSpace = ValInstSpace.unwrap().range();
56270af4f57SMichael Kruse
56370af4f57SMichael Kruse // { Value[] -> Value[] }
56470af4f57SMichael Kruse isl::map ValToVal =
56570af4f57SMichael Kruse isl::map::identity(ValSpace.map_from_domain_and_range(ValSpace));
56670af4f57SMichael Kruse
567d3ce899dSMichael Kruse // { DomainDef[] -> DomainTarget[] }
568d3ce899dSMichael Kruse isl::map DefToTarget = getDefToTarget(DefStmt, TargetStmt);
569d3ce899dSMichael Kruse
57070af4f57SMichael Kruse // { [TargetDomain[] -> Value[]] -> [DefDomain[] -> Value] }
5717175cffbSMichael Kruse LocalTranslator = DefToTarget.reverse().product(ValToVal);
572*601d7eabSKarthika Devi C POLLY_DEBUG(dbgs() << " local translator is " << LocalTranslator
57370af4f57SMichael Kruse << "\n");
5747175cffbSMichael Kruse
5757c7978a1Spatacca if (LocalTranslator.is_null())
5767175cffbSMichael Kruse return ForwardingAction::notApplicable();
57770af4f57SMichael Kruse }
5787175cffbSMichael Kruse
5797175cffbSMichael Kruse auto ExecAction = [this, TargetStmt, LI, SameVal,
5807175cffbSMichael Kruse LocalTranslator]() -> bool {
5817175cffbSMichael Kruse TargetStmt->prependInstruction(LI);
5827175cffbSMichael Kruse MemoryAccess *Access = makeReadArrayAccess(TargetStmt, LI, SameVal);
583*601d7eabSKarthika Devi C POLLY_DEBUG(dbgs() << " forwarded known load with new MemoryAccess"
5847175cffbSMichael Kruse << Access << "\n");
58598031b66SFangrui Song (void)Access;
5867175cffbSMichael Kruse
5877c7978a1Spatacca if (!LocalTranslator.is_null())
588d5ee355fSRiccardo Mori Translator = Translator.unite(LocalTranslator);
58970af4f57SMichael Kruse
59070af4f57SMichael Kruse NumKnownLoadsForwarded++;
59170af4f57SMichael Kruse TotalKnownLoadsForwarded++;
5927175cffbSMichael Kruse return true;
5937175cffbSMichael Kruse };
5947175cffbSMichael Kruse return ForwardingAction::canForward(
5957175cffbSMichael Kruse ExecAction, {{LI->getPointerOperand(), DefStmt}}, true);
596822dfe27SMichael Kruse }
597822dfe27SMichael Kruse
598822dfe27SMichael Kruse /// Forward a scalar by redirecting the access to an array element that stores
599822dfe27SMichael Kruse /// the same value.
600822dfe27SMichael Kruse ///
601822dfe27SMichael Kruse /// @param TargetStmt The statement the operand tree will be copied to.
602822dfe27SMichael Kruse /// @param Inst The scalar to forward.
603822dfe27SMichael Kruse /// @param UseStmt The statement that uses @p Inst.
604822dfe27SMichael Kruse /// @param UseLoop The loop @p Inst is used in.
605822dfe27SMichael Kruse /// @param DefStmt The statement @p Inst is defined in.
606822dfe27SMichael Kruse /// @param DefLoop The loop which contains @p Inst.
607822dfe27SMichael Kruse ///
6087175cffbSMichael Kruse /// @return A ForwardingAction object describing the feasibility and
6097175cffbSMichael Kruse /// profitability evaluation and the callback carrying-out the value
6107175cffbSMichael Kruse /// forwarding.
reloadKnownContent(ScopStmt * TargetStmt,Instruction * Inst,ScopStmt * UseStmt,Loop * UseLoop,ScopStmt * DefStmt,Loop * DefLoop)6117175cffbSMichael Kruse ForwardingAction reloadKnownContent(ScopStmt *TargetStmt, Instruction *Inst,
612822dfe27SMichael Kruse ScopStmt *UseStmt, Loop *UseLoop,
6137175cffbSMichael Kruse ScopStmt *DefStmt, Loop *DefLoop) {
614822dfe27SMichael Kruse // Cannot do anything without successful known analysis.
615d3ce899dSMichael Kruse if (Known.is_null() || Translator.is_null() ||
616d3ce899dSMichael Kruse MaxOpGuard.hasQuotaExceeded())
6177175cffbSMichael Kruse return ForwardingAction::notApplicable();
618822dfe27SMichael Kruse
6197175cffbSMichael Kruse // Don't spend too much time analyzing whether it can be reloaded.
6207175cffbSMichael Kruse IslQuotaScope QuotaScope = MaxOpGuard.enter();
6214d3f3c72SMichael Kruse
622822dfe27SMichael Kruse // { DomainDef[] -> ValInst[] }
62368821a8bSMichael Kruse isl::union_map ExpectedVal = makeNormalizedValInst(Inst, UseStmt, UseLoop);
624822dfe27SMichael Kruse
625d3ce899dSMichael Kruse // { DomainUse[] -> DomainTarget[] }
626d3ce899dSMichael Kruse isl::map UseToTarget = getDefToTarget(UseStmt, TargetStmt);
627d3ce899dSMichael Kruse
628822dfe27SMichael Kruse // { DomainTarget[] -> ValInst[] }
629822dfe27SMichael Kruse isl::union_map TargetExpectedVal = ExpectedVal.apply_domain(UseToTarget);
630822dfe27SMichael Kruse isl::union_map TranslatedExpectedVal =
631822dfe27SMichael Kruse TargetExpectedVal.apply_range(Translator);
632822dfe27SMichael Kruse
633822dfe27SMichael Kruse // { DomainTarget[] -> Element[] }
634822dfe27SMichael Kruse isl::union_map Candidates = findSameContentElements(TranslatedExpectedVal);
635822dfe27SMichael Kruse
636822dfe27SMichael Kruse isl::map SameVal = singleLocation(Candidates, getDomainFor(TargetStmt));
6377175cffbSMichael Kruse simplify(SameVal);
6387c7978a1Spatacca if (SameVal.is_null())
6397175cffbSMichael Kruse return ForwardingAction::notApplicable();
640822dfe27SMichael Kruse
6417175cffbSMichael Kruse auto ExecAction = [this, TargetStmt, Inst, SameVal]() {
6427175cffbSMichael Kruse MemoryAccess *Access = TargetStmt->lookupInputAccessOf(Inst);
643822dfe27SMichael Kruse if (!Access)
644822dfe27SMichael Kruse Access = TargetStmt->ensureValueRead(Inst);
645822dfe27SMichael Kruse Access->setNewAccessRelation(SameVal);
646822dfe27SMichael Kruse
647*601d7eabSKarthika Devi C POLLY_DEBUG(dbgs() << " forwarded known content of " << *Inst
648c1cf51e7SMichael Kruse << " which is " << SameVal << "\n");
649822dfe27SMichael Kruse TotalReloads++;
650822dfe27SMichael Kruse NumReloads++;
6517175cffbSMichael Kruse return false;
6527175cffbSMichael Kruse };
6537175cffbSMichael Kruse
6547175cffbSMichael Kruse return ForwardingAction::canForward(ExecAction, {}, true);
65570af4f57SMichael Kruse }
65670af4f57SMichael Kruse
657a9a70863SMichael Kruse /// Forwards a speculatively executable instruction.
658a9a70863SMichael Kruse ///
65970af4f57SMichael Kruse /// @param TargetStmt The statement the operand tree will be copied to.
66070af4f57SMichael Kruse /// @param UseInst The (possibly speculatable) instruction to forward.
66170af4f57SMichael Kruse /// @param DefStmt The statement @p UseInst is defined in.
66270af4f57SMichael Kruse /// @param DefLoop The loop which contains @p UseInst.
663a9a70863SMichael Kruse ///
6647175cffbSMichael Kruse /// @return A ForwardingAction object describing the feasibility and
6657175cffbSMichael Kruse /// profitability evaluation and the callback carrying-out the value
6667175cffbSMichael Kruse /// forwarding.
forwardSpeculatable(ScopStmt * TargetStmt,Instruction * UseInst,ScopStmt * DefStmt,Loop * DefLoop)6677175cffbSMichael Kruse ForwardingAction forwardSpeculatable(ScopStmt *TargetStmt,
6687175cffbSMichael Kruse Instruction *UseInst, ScopStmt *DefStmt,
6697175cffbSMichael Kruse Loop *DefLoop) {
670a9a70863SMichael Kruse // PHIs, unless synthesizable, are not yet supported.
671a9a70863SMichael Kruse if (isa<PHINode>(UseInst))
6727175cffbSMichael Kruse return ForwardingAction::notApplicable();
673a9a70863SMichael Kruse
674a9a70863SMichael Kruse // Compatible instructions must satisfy the following conditions:
675a9a70863SMichael Kruse // 1. Idempotent (instruction will be copied, not moved; although its
676a9a70863SMichael Kruse // original instance might be removed by simplification)
677a9a70863SMichael Kruse // 2. Not access memory (There might be memory writes between)
678a9a70863SMichael Kruse // 3. Not cause undefined behaviour (we might copy to a location when the
679a9a70863SMichael Kruse // original instruction was no executed; this is currently not possible
680a9a70863SMichael Kruse // because we do not forward PHINodes)
681a9a70863SMichael Kruse // 4. Not leak memory if executed multiple times (i.e. malloc)
682a9a70863SMichael Kruse //
683a9a70863SMichael Kruse // Instruction::mayHaveSideEffects is not sufficient because it considers
684a9a70863SMichael Kruse // malloc to not have side-effects. llvm::isSafeToSpeculativelyExecute is
685a9a70863SMichael Kruse // not sufficient because it allows memory accesses.
68693102505SPhilip Reames if (mayHaveNonDefUseDependency(*UseInst))
6877175cffbSMichael Kruse return ForwardingAction::notApplicable();
688a9a70863SMichael Kruse
6897175cffbSMichael Kruse SmallVector<ForwardingAction::KeyTy, 4> Depends;
6907175cffbSMichael Kruse Depends.reserve(UseInst->getNumOperands());
691a9a70863SMichael Kruse for (Value *OpVal : UseInst->operand_values()) {
692a9a70863SMichael Kruse ForwardingDecision OpDecision =
6937175cffbSMichael Kruse forwardTree(TargetStmt, OpVal, DefStmt, DefLoop);
694a9a70863SMichael Kruse switch (OpDecision) {
695a9a70863SMichael Kruse case FD_CannotForward:
6967175cffbSMichael Kruse return ForwardingAction::cannotForward();
697a9a70863SMichael Kruse
698a9a70863SMichael Kruse case FD_CanForwardLeaf:
699822dfe27SMichael Kruse case FD_CanForwardProfitably:
7007175cffbSMichael Kruse Depends.emplace_back(OpVal, DefStmt);
701a9a70863SMichael Kruse break;
702a9a70863SMichael Kruse
703a9a70863SMichael Kruse case FD_NotApplicable:
7047175cffbSMichael Kruse case FD_Unknown:
7057175cffbSMichael Kruse llvm_unreachable(
7067175cffbSMichael Kruse "forwardTree should never return FD_NotApplicable/FD_Unknown");
707a9a70863SMichael Kruse }
708a9a70863SMichael Kruse }
709a9a70863SMichael Kruse
7102213a354SFangrui Song auto ExecAction = [this, TargetStmt, UseInst]() {
7117175cffbSMichael Kruse // To ensure the right order, prepend this instruction before its
7127175cffbSMichael Kruse // operands. This ensures that its operands are inserted before the
7137175cffbSMichael Kruse // instruction using them.
7147175cffbSMichael Kruse TargetStmt->prependInstruction(UseInst);
715c1cf51e7SMichael Kruse
716*601d7eabSKarthika Devi C POLLY_DEBUG(dbgs() << " forwarded speculable instruction: " << *UseInst
717c1cf51e7SMichael Kruse << "\n");
7187175cffbSMichael Kruse NumInstructionsCopied++;
7197175cffbSMichael Kruse TotalInstructionsCopied++;
7207175cffbSMichael Kruse return true;
7217175cffbSMichael Kruse };
7227175cffbSMichael Kruse return ForwardingAction::canForward(ExecAction, Depends, true);
723a9a70863SMichael Kruse }
724a9a70863SMichael Kruse
7257175cffbSMichael Kruse /// Determines whether an operand tree can be forwarded and returns
7267175cffbSMichael Kruse /// instructions how to do so in the form of a ForwardingAction object.
727a6b2de3bSMichael Kruse ///
728a6b2de3bSMichael Kruse /// @param TargetStmt The statement the operand tree will be copied to.
729a6b2de3bSMichael Kruse /// @param UseVal The value (usually an instruction) which is root of an
730a6b2de3bSMichael Kruse /// operand tree.
731a6b2de3bSMichael Kruse /// @param UseStmt The statement that uses @p UseVal.
732a6b2de3bSMichael Kruse /// @param UseLoop The loop @p UseVal is used in.
733a6b2de3bSMichael Kruse ///
7347175cffbSMichael Kruse /// @return A ForwardingAction object describing the feasibility and
7357175cffbSMichael Kruse /// profitability evaluation and the callback carrying-out the value
7367175cffbSMichael Kruse /// forwarding.
forwardTreeImpl(ScopStmt * TargetStmt,Value * UseVal,ScopStmt * UseStmt,Loop * UseLoop)7377175cffbSMichael Kruse ForwardingAction forwardTreeImpl(ScopStmt *TargetStmt, Value *UseVal,
7387175cffbSMichael Kruse ScopStmt *UseStmt, Loop *UseLoop) {
73970af4f57SMichael Kruse ScopStmt *DefStmt = nullptr;
74070af4f57SMichael Kruse Loop *DefLoop = nullptr;
74170af4f57SMichael Kruse
74270af4f57SMichael Kruse // { DefDomain[] -> TargetDomain[] }
74370af4f57SMichael Kruse isl::map DefToTarget;
74470af4f57SMichael Kruse
745a6b2de3bSMichael Kruse VirtualUse VUse = VirtualUse::create(UseStmt, UseLoop, UseVal, true);
746a6b2de3bSMichael Kruse switch (VUse.getKind()) {
747a6b2de3bSMichael Kruse case VirtualUse::Constant:
748a6b2de3bSMichael Kruse case VirtualUse::Block:
749e5f4706aSMichael Kruse case VirtualUse::Hoisted:
750a6b2de3bSMichael Kruse // These can be used anywhere without special considerations.
751c1cf51e7SMichael Kruse return ForwardingAction::triviallyForwardable(false, UseVal);
752a6b2de3bSMichael Kruse
7539f6e41cdSMichael Kruse case VirtualUse::Synthesizable: {
7549f6e41cdSMichael Kruse // Check if the value is synthesizable at the new location as well. This
7559f6e41cdSMichael Kruse // might be possible when leaving a loop for which ScalarEvolution is
7569f6e41cdSMichael Kruse // unable to derive the exit value for.
7579f6e41cdSMichael Kruse // TODO: If there is a LCSSA PHI at the loop exit, use that one.
7589f6e41cdSMichael Kruse // If the SCEV contains a SCEVAddRecExpr, we currently depend on that we
7599f6e41cdSMichael Kruse // do not forward past its loop header. This would require us to use a
7609f6e41cdSMichael Kruse // previous loop induction variable instead the current one. We currently
7619f6e41cdSMichael Kruse // do not allow forwarding PHI nodes, thus this should never occur (the
7629f6e41cdSMichael Kruse // only exception where no phi is necessary being an unreachable loop
7639f6e41cdSMichael Kruse // without edge from the outside).
7649f6e41cdSMichael Kruse VirtualUse TargetUse = VirtualUse::create(
7659f6e41cdSMichael Kruse S, TargetStmt, TargetStmt->getSurroundingLoop(), UseVal, true);
7669f6e41cdSMichael Kruse if (TargetUse.getKind() == VirtualUse::Synthesizable)
767c1cf51e7SMichael Kruse return ForwardingAction::triviallyForwardable(false, UseVal);
7689f6e41cdSMichael Kruse
769*601d7eabSKarthika Devi C POLLY_DEBUG(
770349506a9SNicola Zaghen dbgs() << " Synthesizable would not be synthesizable anymore: "
7719f6e41cdSMichael Kruse << *UseVal << "\n");
7727175cffbSMichael Kruse return ForwardingAction::cannotForward();
7739f6e41cdSMichael Kruse }
774a6b2de3bSMichael Kruse
7757175cffbSMichael Kruse case VirtualUse::ReadOnly: {
776c1cf51e7SMichael Kruse if (!ModelReadOnlyScalars)
777c1cf51e7SMichael Kruse return ForwardingAction::triviallyForwardable(false, UseVal);
778c1cf51e7SMichael Kruse
77907e8c36dSMichael Kruse // If we model read-only scalars, we need to create a MemoryAccess for it.
7807175cffbSMichael Kruse auto ExecAction = [this, TargetStmt, UseVal]() {
78107e8c36dSMichael Kruse TargetStmt->ensureValueRead(UseVal);
78207e8c36dSMichael Kruse
783*601d7eabSKarthika Devi C POLLY_DEBUG(dbgs() << " forwarded read-only value " << *UseVal
784c1cf51e7SMichael Kruse << "\n");
78507e8c36dSMichael Kruse NumReadOnlyCopied++;
78607e8c36dSMichael Kruse TotalReadOnlyCopied++;
7877175cffbSMichael Kruse
7887175cffbSMichael Kruse // Note that we cannot return true here. With a operand tree
7897175cffbSMichael Kruse // depth of 0, UseVal is the use in TargetStmt that we try to replace.
7907175cffbSMichael Kruse // With -polly-analyze-read-only-scalars=true we would ensure the
7917175cffbSMichael Kruse // existence of a MemoryAccess (which already exists for a leaf) and be
7927175cffbSMichael Kruse // removed again by tryForwardTree because it's goal is to remove this
7937175cffbSMichael Kruse // scalar MemoryAccess. It interprets FD_CanForwardTree as the
7947175cffbSMichael Kruse // permission to do so.
7957175cffbSMichael Kruse return false;
7967175cffbSMichael Kruse };
7977175cffbSMichael Kruse return ForwardingAction::canForward(ExecAction, {}, false);
7987175cffbSMichael Kruse }
799a6b2de3bSMichael Kruse
800a6b2de3bSMichael Kruse case VirtualUse::Intra:
80170af4f57SMichael Kruse // Knowing that UseStmt and DefStmt are the same statement instance, just
80270af4f57SMichael Kruse // reuse the information about UseStmt for DefStmt
80370af4f57SMichael Kruse DefStmt = UseStmt;
804a6b2de3bSMichael Kruse
8050972a390SFangrui Song [[fallthrough]];
80670af4f57SMichael Kruse case VirtualUse::Inter:
80770af4f57SMichael Kruse Instruction *Inst = cast<Instruction>(UseVal);
80870af4f57SMichael Kruse
809cd3b9fedSMichael Kruse if (!DefStmt) {
81070af4f57SMichael Kruse DefStmt = S->getStmtFor(Inst);
811cd3b9fedSMichael Kruse if (!DefStmt)
8127175cffbSMichael Kruse return ForwardingAction::cannotForward();
813cd3b9fedSMichael Kruse }
814cd3b9fedSMichael Kruse
81570af4f57SMichael Kruse DefLoop = LI->getLoopFor(Inst->getParent());
81670af4f57SMichael Kruse
8177175cffbSMichael Kruse ForwardingAction SpeculativeResult =
8187175cffbSMichael Kruse forwardSpeculatable(TargetStmt, Inst, DefStmt, DefLoop);
8197175cffbSMichael Kruse if (SpeculativeResult.Decision != FD_NotApplicable)
820a9a70863SMichael Kruse return SpeculativeResult;
821a9a70863SMichael Kruse
8227175cffbSMichael Kruse ForwardingAction KnownResult = forwardKnownLoad(
8237175cffbSMichael Kruse TargetStmt, Inst, UseStmt, UseLoop, DefStmt, DefLoop);
8247175cffbSMichael Kruse if (KnownResult.Decision != FD_NotApplicable)
82570af4f57SMichael Kruse return KnownResult;
82670af4f57SMichael Kruse
8277175cffbSMichael Kruse ForwardingAction ReloadResult = reloadKnownContent(
8287175cffbSMichael Kruse TargetStmt, Inst, UseStmt, UseLoop, DefStmt, DefLoop);
8297175cffbSMichael Kruse if (ReloadResult.Decision != FD_NotApplicable)
830822dfe27SMichael Kruse return ReloadResult;
831822dfe27SMichael Kruse
832a9a70863SMichael Kruse // When no method is found to forward the operand tree, we effectively
833a9a70863SMichael Kruse // cannot handle it.
834*601d7eabSKarthika Devi C POLLY_DEBUG(dbgs() << " Cannot forward instruction: " << *Inst
835*601d7eabSKarthika Devi C << "\n");
8367175cffbSMichael Kruse return ForwardingAction::cannotForward();
8379f6e41cdSMichael Kruse }
8389f6e41cdSMichael Kruse
839a6b2de3bSMichael Kruse llvm_unreachable("Case unhandled");
840a6b2de3bSMichael Kruse }
841a6b2de3bSMichael Kruse
8427175cffbSMichael Kruse /// Determines whether an operand tree can be forwarded. Previous evaluations
8437175cffbSMichael Kruse /// are cached.
8447175cffbSMichael Kruse ///
8457175cffbSMichael Kruse /// @param TargetStmt The statement the operand tree will be copied to.
8467175cffbSMichael Kruse /// @param UseVal The value (usually an instruction) which is root of an
8477175cffbSMichael Kruse /// operand tree.
8487175cffbSMichael Kruse /// @param UseStmt The statement that uses @p UseVal.
8497175cffbSMichael Kruse /// @param UseLoop The loop @p UseVal is used in.
8507175cffbSMichael Kruse ///
8517175cffbSMichael Kruse /// @return FD_CannotForward if @p UseVal cannot be forwarded.
8527175cffbSMichael Kruse /// FD_CanForwardLeaf if @p UseVal is forwardable, but not
8537175cffbSMichael Kruse /// profitable.
8547175cffbSMichael Kruse /// FD_CanForwardProfitably if @p UseVal is forwardable and useful to
8557175cffbSMichael Kruse /// do.
forwardTree(ScopStmt * TargetStmt,Value * UseVal,ScopStmt * UseStmt,Loop * UseLoop)8567175cffbSMichael Kruse ForwardingDecision forwardTree(ScopStmt *TargetStmt, Value *UseVal,
8577175cffbSMichael Kruse ScopStmt *UseStmt, Loop *UseLoop) {
8587175cffbSMichael Kruse // Lookup any cached evaluation.
8597175cffbSMichael Kruse auto It = ForwardingActions.find({UseVal, UseStmt});
8607175cffbSMichael Kruse if (It != ForwardingActions.end())
8617175cffbSMichael Kruse return It->second.Decision;
8627175cffbSMichael Kruse
8637175cffbSMichael Kruse // Make a new evaluation.
8647175cffbSMichael Kruse ForwardingAction Action =
8657175cffbSMichael Kruse forwardTreeImpl(TargetStmt, UseVal, UseStmt, UseLoop);
8667175cffbSMichael Kruse ForwardingDecision Result = Action.Decision;
8677175cffbSMichael Kruse
8687175cffbSMichael Kruse // Remember for the next time.
8697175cffbSMichael Kruse assert(!ForwardingActions.count({UseVal, UseStmt}) &&
8707175cffbSMichael Kruse "circular dependency?");
8717175cffbSMichael Kruse ForwardingActions.insert({{UseVal, UseStmt}, std::move(Action)});
8727175cffbSMichael Kruse
8737175cffbSMichael Kruse return Result;
8747175cffbSMichael Kruse }
8757175cffbSMichael Kruse
8767175cffbSMichael Kruse /// Forward an operand tree using cached actions.
8777175cffbSMichael Kruse ///
8787175cffbSMichael Kruse /// @param Stmt Statement the operand tree is moved into.
8797175cffbSMichael Kruse /// @param UseVal Root of the operand tree within @p Stmt.
8807175cffbSMichael Kruse /// @param RA The MemoryAccess for @p UseVal that the forwarding intends
8817175cffbSMichael Kruse /// to remove.
applyForwardingActions(ScopStmt * Stmt,Value * UseVal,MemoryAccess * RA)8827175cffbSMichael Kruse void applyForwardingActions(ScopStmt *Stmt, Value *UseVal, MemoryAccess *RA) {
8837175cffbSMichael Kruse using ChildItTy =
8847175cffbSMichael Kruse decltype(std::declval<ForwardingAction>().Depends.begin());
8857175cffbSMichael Kruse using EdgeTy = std::pair<ForwardingAction *, ChildItTy>;
8867175cffbSMichael Kruse
8877175cffbSMichael Kruse DenseSet<ForwardingAction::KeyTy> Visited;
8887175cffbSMichael Kruse SmallVector<EdgeTy, 32> Stack;
8897175cffbSMichael Kruse SmallVector<ForwardingAction *, 32> Ordered;
8907175cffbSMichael Kruse
8917175cffbSMichael Kruse // Seed the tree search using the root value.
8927175cffbSMichael Kruse assert(ForwardingActions.count({UseVal, Stmt}));
8937175cffbSMichael Kruse ForwardingAction *RootAction = &ForwardingActions[{UseVal, Stmt}];
8947175cffbSMichael Kruse Stack.emplace_back(RootAction, RootAction->Depends.begin());
8957175cffbSMichael Kruse
8967175cffbSMichael Kruse // Compute the postorder of the operand tree: all operands of an instruction
8977175cffbSMichael Kruse // must be visited before the instruction itself. As an additional
8987175cffbSMichael Kruse // requirement, the topological ordering must be 'compact': Any subtree node
8997175cffbSMichael Kruse // must not be interleaved with nodes from a non-shared subtree. This is
9007175cffbSMichael Kruse // because the same llvm::Instruction can be materialized multiple times as
9017175cffbSMichael Kruse // used at different ScopStmts which might be different values. Intersecting
9027175cffbSMichael Kruse // these lifetimes may result in miscompilations.
9037175cffbSMichael Kruse // FIXME: Intersecting lifetimes might still be possible for the roots
9047175cffbSMichael Kruse // themselves, since instructions are just prepended to a ScopStmt's
9057175cffbSMichael Kruse // instruction list.
9067175cffbSMichael Kruse while (!Stack.empty()) {
9077175cffbSMichael Kruse EdgeTy &Top = Stack.back();
9087175cffbSMichael Kruse ForwardingAction *TopAction = Top.first;
9097175cffbSMichael Kruse ChildItTy &TopEdge = Top.second;
9107175cffbSMichael Kruse
9117175cffbSMichael Kruse if (TopEdge == TopAction->Depends.end()) {
9127175cffbSMichael Kruse // Postorder sorting
9137175cffbSMichael Kruse Ordered.push_back(TopAction);
9147175cffbSMichael Kruse Stack.pop_back();
9157175cffbSMichael Kruse continue;
9167175cffbSMichael Kruse }
9177175cffbSMichael Kruse ForwardingAction::KeyTy Key = *TopEdge;
9187175cffbSMichael Kruse
9197175cffbSMichael Kruse // Next edge for this level
9207175cffbSMichael Kruse ++TopEdge;
9217175cffbSMichael Kruse
9227175cffbSMichael Kruse auto VisitIt = Visited.insert(Key);
9237175cffbSMichael Kruse if (!VisitIt.second)
9247175cffbSMichael Kruse continue;
9257175cffbSMichael Kruse
9267175cffbSMichael Kruse assert(ForwardingActions.count(Key) &&
9277175cffbSMichael Kruse "Must not insert new actions during execution phase");
9287175cffbSMichael Kruse ForwardingAction *ChildAction = &ForwardingActions[Key];
9297175cffbSMichael Kruse Stack.emplace_back(ChildAction, ChildAction->Depends.begin());
9307175cffbSMichael Kruse }
9317175cffbSMichael Kruse
9327175cffbSMichael Kruse // Actually, we need the reverse postorder because actions prepend new
9337175cffbSMichael Kruse // instructions. Therefore, the first one will always be the action for the
9347175cffbSMichael Kruse // operand tree's root.
9357175cffbSMichael Kruse assert(Ordered.back() == RootAction);
9367175cffbSMichael Kruse if (RootAction->Execute())
9377175cffbSMichael Kruse Stmt->removeSingleMemoryAccess(RA);
9387175cffbSMichael Kruse Ordered.pop_back();
9397175cffbSMichael Kruse for (auto DepAction : reverse(Ordered)) {
9407175cffbSMichael Kruse assert(DepAction->Decision != FD_Unknown &&
9417175cffbSMichael Kruse DepAction->Decision != FD_CannotForward);
9427175cffbSMichael Kruse assert(DepAction != RootAction);
9437175cffbSMichael Kruse DepAction->Execute();
9447175cffbSMichael Kruse }
9457175cffbSMichael Kruse }
9467175cffbSMichael Kruse
947a6b2de3bSMichael Kruse /// Try to forward an operand tree rooted in @p RA.
tryForwardTree(MemoryAccess * RA)948a6b2de3bSMichael Kruse bool tryForwardTree(MemoryAccess *RA) {
949a6b2de3bSMichael Kruse assert(RA->isLatestScalarKind());
950*601d7eabSKarthika Devi C POLLY_DEBUG(dbgs() << "Trying to forward operand tree " << RA << "...\n");
951a6b2de3bSMichael Kruse
952a6b2de3bSMichael Kruse ScopStmt *Stmt = RA->getStatement();
953a6b2de3bSMichael Kruse Loop *InLoop = Stmt->getSurroundingLoop();
954a6b2de3bSMichael Kruse
95570af4f57SMichael Kruse isl::map TargetToUse;
95670af4f57SMichael Kruse if (!Known.is_null()) {
95770af4f57SMichael Kruse isl::space DomSpace = Stmt->getDomainSpace();
95870af4f57SMichael Kruse TargetToUse =
95970af4f57SMichael Kruse isl::map::identity(DomSpace.map_from_domain_and_range(DomSpace));
96070af4f57SMichael Kruse }
96170af4f57SMichael Kruse
962d3ce899dSMichael Kruse ForwardingDecision Assessment =
9637175cffbSMichael Kruse forwardTree(Stmt, RA->getAccessValue(), Stmt, InLoop);
964a6b2de3bSMichael Kruse
9657175cffbSMichael Kruse // If considered feasible and profitable, forward it.
9667175cffbSMichael Kruse bool Changed = false;
9677175cffbSMichael Kruse if (Assessment == FD_CanForwardProfitably) {
9687175cffbSMichael Kruse applyForwardingActions(Stmt, RA->getAccessValue(), RA);
9697175cffbSMichael Kruse Changed = true;
9707175cffbSMichael Kruse }
971a6b2de3bSMichael Kruse
9727175cffbSMichael Kruse ForwardingActions.clear();
9737175cffbSMichael Kruse return Changed;
974a6b2de3bSMichael Kruse }
975a6b2de3bSMichael Kruse
976a6b2de3bSMichael Kruse /// Return which SCoP this instance is processing.
getScop() const977a6b2de3bSMichael Kruse Scop *getScop() const { return S; }
978a6b2de3bSMichael Kruse
979a6b2de3bSMichael Kruse /// Run the algorithm: Use value read accesses as operand tree roots and try
980a6b2de3bSMichael Kruse /// to forward them into the statement.
forwardOperandTrees()981a6b2de3bSMichael Kruse bool forwardOperandTrees() {
982a6b2de3bSMichael Kruse for (ScopStmt &Stmt : *S) {
983a6b2de3bSMichael Kruse bool StmtModified = false;
984a6b2de3bSMichael Kruse
985a6b2de3bSMichael Kruse // Because we are modifying the MemoryAccess list, collect them first to
986a6b2de3bSMichael Kruse // avoid iterator invalidation.
987c8a0e27cSMichael Kruse SmallVector<MemoryAccess *, 16> Accs(Stmt.begin(), Stmt.end());
988c8a0e27cSMichael Kruse
989c8a0e27cSMichael Kruse for (MemoryAccess *RA : Accs) {
990a6b2de3bSMichael Kruse if (!RA->isRead())
991a6b2de3bSMichael Kruse continue;
992a6b2de3bSMichael Kruse if (!RA->isLatestScalarKind())
993a6b2de3bSMichael Kruse continue;
994a6b2de3bSMichael Kruse
995a6b2de3bSMichael Kruse if (tryForwardTree(RA)) {
996a6b2de3bSMichael Kruse Modified = true;
997a6b2de3bSMichael Kruse StmtModified = true;
998a6b2de3bSMichael Kruse NumForwardedTrees++;
999a6b2de3bSMichael Kruse TotalForwardedTrees++;
1000a6b2de3bSMichael Kruse }
1001a6b2de3bSMichael Kruse }
1002a6b2de3bSMichael Kruse
1003a6b2de3bSMichael Kruse if (StmtModified) {
1004a6b2de3bSMichael Kruse NumModifiedStmts++;
1005a6b2de3bSMichael Kruse TotalModifiedStmts++;
1006a6b2de3bSMichael Kruse }
1007a6b2de3bSMichael Kruse }
1008a6b2de3bSMichael Kruse
1009e8227804SMichael Kruse if (Modified) {
1010a6b2de3bSMichael Kruse ScopsModified++;
1011e8227804SMichael Kruse S->realignParams();
1012e8227804SMichael Kruse }
1013a6b2de3bSMichael Kruse return Modified;
1014a6b2de3bSMichael Kruse }
1015a6b2de3bSMichael Kruse
1016a6b2de3bSMichael Kruse /// Print the pass result, performed transformations and the SCoP after the
1017a6b2de3bSMichael Kruse /// transformation.
print(raw_ostream & OS,int Indent=0)10189248fde5SEugene Zelenko void print(raw_ostream &OS, int Indent = 0) {
1019a6b2de3bSMichael Kruse printStatistics(OS, Indent);
1020a6b2de3bSMichael Kruse
1021a6b2de3bSMichael Kruse if (!Modified) {
1022a6b2de3bSMichael Kruse // This line can easily be checked in regression tests.
1023a6b2de3bSMichael Kruse OS << "ForwardOpTree executed, but did not modify anything\n";
1024a6b2de3bSMichael Kruse return;
1025a6b2de3bSMichael Kruse }
1026a6b2de3bSMichael Kruse
1027a6b2de3bSMichael Kruse printStatements(OS, Indent);
1028a6b2de3bSMichael Kruse }
10294c64d8eeSMichael Kruse
isModified() const10304c64d8eeSMichael Kruse bool isModified() const { return Modified; }
1031a6b2de3bSMichael Kruse };
1032a6b2de3bSMichael Kruse
runForwardOpTree(Scop & S,LoopInfo & LI)10334c64d8eeSMichael Kruse static std::unique_ptr<ForwardOpTreeImpl> runForwardOpTree(Scop &S,
10344c64d8eeSMichael Kruse LoopInfo &LI) {
1035a6b2de3bSMichael Kruse std::unique_ptr<ForwardOpTreeImpl> Impl;
103689972e21SMichael Kruse {
103700fd43b3SPhilip Pfaffe IslMaxOperationsGuard MaxOpGuard(S.getIslCtx().get(), MaxOps, false);
1038736259e3SJonas Devlieghere Impl = std::make_unique<ForwardOpTreeImpl>(&S, &LI, MaxOpGuard);
1039a6b2de3bSMichael Kruse
104070af4f57SMichael Kruse if (AnalyzeKnown) {
1041*601d7eabSKarthika Devi C POLLY_DEBUG(dbgs() << "Prepare forwarders...\n");
104270af4f57SMichael Kruse Impl->computeKnownValues();
104370af4f57SMichael Kruse }
104470af4f57SMichael Kruse
1045*601d7eabSKarthika Devi C POLLY_DEBUG(dbgs() << "Forwarding operand trees...\n");
1046a6b2de3bSMichael Kruse Impl->forwardOperandTrees();
1047a6b2de3bSMichael Kruse
104889972e21SMichael Kruse if (MaxOpGuard.hasQuotaExceeded()) {
1049*601d7eabSKarthika Devi C POLLY_DEBUG(dbgs() << "Not all operations completed because of "
105089972e21SMichael Kruse "max_operations exceeded\n");
105189972e21SMichael Kruse KnownOutOfQuota++;
105289972e21SMichael Kruse }
105389972e21SMichael Kruse }
105489972e21SMichael Kruse
1055*601d7eabSKarthika Devi C POLLY_DEBUG(dbgs() << "\nFinal Scop:\n");
1056*601d7eabSKarthika Devi C POLLY_DEBUG(dbgs() << S);
1057a6b2de3bSMichael Kruse
105806ed5292SMichael Kruse // Update statistics
10594c64d8eeSMichael Kruse Scop::ScopStatistics ScopStats = S.getStatistics();
106006ed5292SMichael Kruse NumValueWrites += ScopStats.NumValueWrites;
106106ed5292SMichael Kruse NumValueWritesInLoops += ScopStats.NumValueWritesInLoops;
106206ed5292SMichael Kruse NumPHIWrites += ScopStats.NumPHIWrites;
106306ed5292SMichael Kruse NumPHIWritesInLoops += ScopStats.NumPHIWritesInLoops;
106406ed5292SMichael Kruse NumSingletonWrites += ScopStats.NumSingletonWrites;
106506ed5292SMichael Kruse NumSingletonWritesInLoops += ScopStats.NumSingletonWritesInLoops;
106606ed5292SMichael Kruse
10674c64d8eeSMichael Kruse return Impl;
10684c64d8eeSMichael Kruse }
10694c64d8eeSMichael Kruse
10704c64d8eeSMichael Kruse static PreservedAnalyses
runForwardOpTreeUsingNPM(Scop & S,ScopAnalysisManager & SAM,ScopStandardAnalysisResults & SAR,SPMUpdater & U,raw_ostream * OS)10714c64d8eeSMichael Kruse runForwardOpTreeUsingNPM(Scop &S, ScopAnalysisManager &SAM,
10724c64d8eeSMichael Kruse ScopStandardAnalysisResults &SAR, SPMUpdater &U,
10734c64d8eeSMichael Kruse raw_ostream *OS) {
10744c64d8eeSMichael Kruse LoopInfo &LI = SAR.LI;
10754c64d8eeSMichael Kruse
10764c64d8eeSMichael Kruse std::unique_ptr<ForwardOpTreeImpl> Impl = runForwardOpTree(S, LI);
10774c64d8eeSMichael Kruse if (OS) {
10784c64d8eeSMichael Kruse *OS << "Printing analysis 'Polly - Forward operand tree' for region: '"
10794c64d8eeSMichael Kruse << S.getName() << "' in function '" << S.getFunction().getName()
10804c64d8eeSMichael Kruse << "':\n";
10814c64d8eeSMichael Kruse if (Impl) {
10824c64d8eeSMichael Kruse assert(Impl->getScop() == &S);
10834c64d8eeSMichael Kruse
10844c64d8eeSMichael Kruse Impl->print(*OS);
10854c64d8eeSMichael Kruse }
10864c64d8eeSMichael Kruse }
10874c64d8eeSMichael Kruse
10884c64d8eeSMichael Kruse if (!Impl->isModified())
10894c64d8eeSMichael Kruse return PreservedAnalyses::all();
10904c64d8eeSMichael Kruse
10914c64d8eeSMichael Kruse PreservedAnalyses PA;
10924c64d8eeSMichael Kruse PA.preserveSet<AllAnalysesOn<Module>>();
10934c64d8eeSMichael Kruse PA.preserveSet<AllAnalysesOn<Function>>();
10944c64d8eeSMichael Kruse PA.preserveSet<AllAnalysesOn<Loop>>();
10954c64d8eeSMichael Kruse return PA;
10964c64d8eeSMichael Kruse }
10974c64d8eeSMichael Kruse
10984c64d8eeSMichael Kruse /// Pass that redirects scalar reads to array elements that are known to contain
10994c64d8eeSMichael Kruse /// the same value.
11004c64d8eeSMichael Kruse ///
11014c64d8eeSMichael Kruse /// This reduces the number of scalar accesses and therefore potentially
11024c64d8eeSMichael Kruse /// increases the freedom of the scheduler. In the ideal case, all reads of a
11034c64d8eeSMichael Kruse /// scalar definition are redirected (We currently do not care about removing
11044c64d8eeSMichael Kruse /// the write in this case). This is also useful for the main DeLICM pass as
11054c64d8eeSMichael Kruse /// there are less scalars to be mapped.
1106bd93df93SMichael Kruse class ForwardOpTreeWrapperPass final : public ScopPass {
11074c64d8eeSMichael Kruse private:
11084c64d8eeSMichael Kruse /// The pass implementation, also holding per-scop data.
11094c64d8eeSMichael Kruse std::unique_ptr<ForwardOpTreeImpl> Impl;
11104c64d8eeSMichael Kruse
11114c64d8eeSMichael Kruse public:
11124c64d8eeSMichael Kruse static char ID;
11134c64d8eeSMichael Kruse
ForwardOpTreeWrapperPass()11144c64d8eeSMichael Kruse explicit ForwardOpTreeWrapperPass() : ScopPass(ID) {}
11154c64d8eeSMichael Kruse ForwardOpTreeWrapperPass(const ForwardOpTreeWrapperPass &) = delete;
11164c64d8eeSMichael Kruse ForwardOpTreeWrapperPass &
11174c64d8eeSMichael Kruse operator=(const ForwardOpTreeWrapperPass &) = delete;
11184c64d8eeSMichael Kruse
getAnalysisUsage(AnalysisUsage & AU) const11194c64d8eeSMichael Kruse void getAnalysisUsage(AnalysisUsage &AU) const override {
11204c64d8eeSMichael Kruse AU.addRequiredTransitive<ScopInfoRegionPass>();
11214c64d8eeSMichael Kruse AU.addRequired<LoopInfoWrapperPass>();
11224c64d8eeSMichael Kruse AU.setPreservesAll();
11234c64d8eeSMichael Kruse }
11244c64d8eeSMichael Kruse
runOnScop(Scop & S)11254c64d8eeSMichael Kruse bool runOnScop(Scop &S) override {
11264c64d8eeSMichael Kruse // Free resources for previous SCoP's computation, if not yet done.
11274c64d8eeSMichael Kruse releaseMemory();
11284c64d8eeSMichael Kruse
11294c64d8eeSMichael Kruse LoopInfo &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
11304c64d8eeSMichael Kruse
11314c64d8eeSMichael Kruse Impl = runForwardOpTree(S, LI);
11324c64d8eeSMichael Kruse
1133a6b2de3bSMichael Kruse return false;
1134a6b2de3bSMichael Kruse }
1135a6b2de3bSMichael Kruse
printScop(raw_ostream & OS,Scop & S) const11369248fde5SEugene Zelenko void printScop(raw_ostream &OS, Scop &S) const override {
1137a6b2de3bSMichael Kruse if (!Impl)
1138a6b2de3bSMichael Kruse return;
1139a6b2de3bSMichael Kruse
1140a6b2de3bSMichael Kruse assert(Impl->getScop() == &S);
1141a6b2de3bSMichael Kruse Impl->print(OS);
1142a6b2de3bSMichael Kruse }
1143a6b2de3bSMichael Kruse
releaseMemory()11449248fde5SEugene Zelenko void releaseMemory() override { Impl.reset(); }
1145a6b2de3bSMichael Kruse }; // class ForwardOpTree
1146a6b2de3bSMichael Kruse
11474c64d8eeSMichael Kruse char ForwardOpTreeWrapperPass::ID;
11485c028081SMichael Kruse
11495c028081SMichael Kruse /// Print result from ForwardOpTreeWrapperPass.
1150bd93df93SMichael Kruse class ForwardOpTreePrinterLegacyPass final : public ScopPass {
11515c028081SMichael Kruse public:
11525c028081SMichael Kruse static char ID;
11535c028081SMichael Kruse
ForwardOpTreePrinterLegacyPass()11548de23009SOwen Pan ForwardOpTreePrinterLegacyPass() : ForwardOpTreePrinterLegacyPass(outs()) {}
ForwardOpTreePrinterLegacyPass(llvm::raw_ostream & OS)11555c028081SMichael Kruse explicit ForwardOpTreePrinterLegacyPass(llvm::raw_ostream &OS)
11565c028081SMichael Kruse : ScopPass(ID), OS(OS) {}
11575c028081SMichael Kruse
runOnScop(Scop & S)11585c028081SMichael Kruse bool runOnScop(Scop &S) override {
11595c028081SMichael Kruse ForwardOpTreeWrapperPass &P = getAnalysis<ForwardOpTreeWrapperPass>();
11605c028081SMichael Kruse
11615c028081SMichael Kruse OS << "Printing analysis '" << P.getPassName() << "' for region: '"
11625c028081SMichael Kruse << S.getRegion().getNameStr() << "' in function '"
11635c028081SMichael Kruse << S.getFunction().getName() << "':\n";
11645c028081SMichael Kruse P.printScop(OS, S);
11655c028081SMichael Kruse
11665c028081SMichael Kruse return false;
11675c028081SMichael Kruse }
11685c028081SMichael Kruse
getAnalysisUsage(AnalysisUsage & AU) const11695c028081SMichael Kruse void getAnalysisUsage(AnalysisUsage &AU) const override {
11705c028081SMichael Kruse ScopPass::getAnalysisUsage(AU);
11715c028081SMichael Kruse AU.addRequired<ForwardOpTreeWrapperPass>();
11725c028081SMichael Kruse AU.setPreservesAll();
11735c028081SMichael Kruse }
11745c028081SMichael Kruse
11755c028081SMichael Kruse private:
11765c028081SMichael Kruse llvm::raw_ostream &OS;
11775c028081SMichael Kruse };
11785c028081SMichael Kruse
11795c028081SMichael Kruse char ForwardOpTreePrinterLegacyPass::ID = 0;
11809248fde5SEugene Zelenko } // namespace
1181a6b2de3bSMichael Kruse
createForwardOpTreeWrapperPass()11824c64d8eeSMichael Kruse Pass *polly::createForwardOpTreeWrapperPass() {
11834c64d8eeSMichael Kruse return new ForwardOpTreeWrapperPass();
11844c64d8eeSMichael Kruse }
1185a6b2de3bSMichael Kruse
createForwardOpTreePrinterLegacyPass(llvm::raw_ostream & OS)11865c028081SMichael Kruse Pass *polly::createForwardOpTreePrinterLegacyPass(llvm::raw_ostream &OS) {
11875c028081SMichael Kruse return new ForwardOpTreePrinterLegacyPass(OS);
11885c028081SMichael Kruse }
11895c028081SMichael Kruse
run(Scop & S,ScopAnalysisManager & SAM,ScopStandardAnalysisResults & SAR,SPMUpdater & U)11904c64d8eeSMichael Kruse llvm::PreservedAnalyses ForwardOpTreePass::run(Scop &S,
11914c64d8eeSMichael Kruse ScopAnalysisManager &SAM,
11924c64d8eeSMichael Kruse ScopStandardAnalysisResults &SAR,
11934c64d8eeSMichael Kruse SPMUpdater &U) {
11944c64d8eeSMichael Kruse return runForwardOpTreeUsingNPM(S, SAM, SAR, U, nullptr);
11954c64d8eeSMichael Kruse }
11964c64d8eeSMichael Kruse
11974c64d8eeSMichael Kruse llvm::PreservedAnalyses
run(Scop & S,ScopAnalysisManager & SAM,ScopStandardAnalysisResults & SAR,SPMUpdater & U)11984c64d8eeSMichael Kruse ForwardOpTreePrinterPass::run(Scop &S, ScopAnalysisManager &SAM,
11994c64d8eeSMichael Kruse ScopStandardAnalysisResults &SAR, SPMUpdater &U) {
12004c64d8eeSMichael Kruse return runForwardOpTreeUsingNPM(S, SAM, SAR, U, &OS);
12014c64d8eeSMichael Kruse }
1202ad84c6f6SMichael Kruse
1203ad84c6f6SMichael Kruse INITIALIZE_PASS_BEGIN(ForwardOpTreeWrapperPass, "polly-optree",
1204ad84c6f6SMichael Kruse "Polly - Forward operand tree", false, false)
1205ad84c6f6SMichael Kruse INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
1206ad84c6f6SMichael Kruse INITIALIZE_PASS_END(ForwardOpTreeWrapperPass, "polly-optree",
1207ad84c6f6SMichael Kruse "Polly - Forward operand tree", false, false)
12085c028081SMichael Kruse
12095c028081SMichael Kruse INITIALIZE_PASS_BEGIN(ForwardOpTreePrinterLegacyPass, "polly-print-optree",
12105c028081SMichael Kruse "Polly - Print forward operand tree result", false, false)
12115c028081SMichael Kruse INITIALIZE_PASS_DEPENDENCY(ForwardOpTreeWrapperPass)
12125c028081SMichael Kruse INITIALIZE_PASS_END(ForwardOpTreePrinterLegacyPass, "polly-print-optree",
12135c028081SMichael Kruse "Polly - Print forward operand tree result", false, false)
1214