loop_dependence.h 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. // Copyright (c) 2018 Google LLC.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #ifndef SOURCE_OPT_LOOP_DEPENDENCE_H_
  15. #define SOURCE_OPT_LOOP_DEPENDENCE_H_
  16. #include <algorithm>
  17. #include <cstdint>
  18. #include <list>
  19. #include <map>
  20. #include <memory>
  21. #include <ostream>
  22. #include <set>
  23. #include <string>
  24. #include <utility>
  25. #include <vector>
  26. #include "source/opt/instruction.h"
  27. #include "source/opt/ir_context.h"
  28. #include "source/opt/loop_descriptor.h"
  29. #include "source/opt/scalar_analysis.h"
  30. namespace spvtools {
  31. namespace opt {
  32. // Stores information about dependence between a load and a store wrt a single
  33. // loop in a loop nest.
  34. // DependenceInformation
  35. // * UNKNOWN if no dependence information can be gathered or is gathered
  36. // for it.
  37. // * DIRECTION if a dependence direction could be found, but not a
  38. // distance.
  39. // * DISTANCE if a dependence distance could be found.
  40. // * PEEL if peeling either the first or last iteration will break
  41. // dependence between the given load and store.
  42. // * IRRELEVANT if it has no effect on the dependence between the given
  43. // load and store.
  44. //
  45. // If peel_first == true, the analysis has found that peeling the first
  46. // iteration of this loop will break dependence.
  47. //
  48. // If peel_last == true, the analysis has found that peeling the last iteration
  49. // of this loop will break dependence.
  50. class DistanceEntry {
  51. public:
  52. enum DependenceInformation {
  53. UNKNOWN = 0,
  54. DIRECTION = 1,
  55. DISTANCE = 2,
  56. PEEL = 3,
  57. IRRELEVANT = 4,
  58. POINT = 5
  59. };
  60. enum Directions {
  61. NONE = 0,
  62. LT = 1,
  63. EQ = 2,
  64. LE = 3,
  65. GT = 4,
  66. NE = 5,
  67. GE = 6,
  68. ALL = 7
  69. };
  70. DependenceInformation dependence_information;
  71. Directions direction;
  72. int64_t distance;
  73. bool peel_first;
  74. bool peel_last;
  75. int64_t point_x;
  76. int64_t point_y;
  77. DistanceEntry()
  78. : dependence_information(DependenceInformation::UNKNOWN),
  79. direction(Directions::ALL),
  80. distance(0),
  81. peel_first(false),
  82. peel_last(false),
  83. point_x(0),
  84. point_y(0) {}
  85. explicit DistanceEntry(Directions direction_)
  86. : dependence_information(DependenceInformation::DIRECTION),
  87. direction(direction_),
  88. distance(0),
  89. peel_first(false),
  90. peel_last(false),
  91. point_x(0),
  92. point_y(0) {}
  93. DistanceEntry(Directions direction_, int64_t distance_)
  94. : dependence_information(DependenceInformation::DISTANCE),
  95. direction(direction_),
  96. distance(distance_),
  97. peel_first(false),
  98. peel_last(false),
  99. point_x(0),
  100. point_y(0) {}
  101. DistanceEntry(int64_t x, int64_t y)
  102. : dependence_information(DependenceInformation::POINT),
  103. direction(Directions::ALL),
  104. distance(0),
  105. peel_first(false),
  106. peel_last(false),
  107. point_x(x),
  108. point_y(y) {}
  109. bool operator==(const DistanceEntry& rhs) const {
  110. return direction == rhs.direction && peel_first == rhs.peel_first &&
  111. peel_last == rhs.peel_last && distance == rhs.distance &&
  112. point_x == rhs.point_x && point_y == rhs.point_y;
  113. }
  114. bool operator!=(const DistanceEntry& rhs) const { return !(*this == rhs); }
  115. };
  116. // Stores a vector of DistanceEntrys, one per loop in the analysis.
  117. // A DistanceVector holds all of the information gathered in a dependence
  118. // analysis wrt the loops stored in the LoopDependenceAnalysis performing the
  119. // analysis.
  120. class DistanceVector {
  121. public:
  122. explicit DistanceVector(size_t size) : entries(size, DistanceEntry{}) {}
  123. explicit DistanceVector(std::vector<DistanceEntry> entries_)
  124. : entries(entries_) {}
  125. DistanceEntry& GetEntry(size_t index) { return entries[index]; }
  126. const DistanceEntry& GetEntry(size_t index) const { return entries[index]; }
  127. std::vector<DistanceEntry>& GetEntries() { return entries; }
  128. const std::vector<DistanceEntry>& GetEntries() const { return entries; }
  129. bool operator==(const DistanceVector& rhs) const {
  130. if (entries.size() != rhs.entries.size()) {
  131. return false;
  132. }
  133. for (size_t i = 0; i < entries.size(); ++i) {
  134. if (entries[i] != rhs.entries[i]) {
  135. return false;
  136. }
  137. }
  138. return true;
  139. }
  140. bool operator!=(const DistanceVector& rhs) const { return !(*this == rhs); }
  141. private:
  142. std::vector<DistanceEntry> entries;
  143. };
  144. class DependenceLine;
  145. class DependenceDistance;
  146. class DependencePoint;
  147. class DependenceNone;
  148. class DependenceEmpty;
  149. class Constraint {
  150. public:
  151. explicit Constraint(const Loop* loop) : loop_(loop) {}
  152. enum ConstraintType { Line, Distance, Point, None, Empty };
  153. virtual ConstraintType GetType() const = 0;
  154. virtual ~Constraint() {}
  155. // Get the loop this constraint belongs to.
  156. const Loop* GetLoop() const { return loop_; }
  157. bool operator==(const Constraint& other) const;
  158. bool operator!=(const Constraint& other) const;
  159. // clang-format off
  160. #define DeclareCastMethod(target) \
  161. virtual target* As##target() { return nullptr; } \
  162. virtual const target* As##target() const { return nullptr; }
  163. DeclareCastMethod(DependenceLine)
  164. DeclareCastMethod(DependenceDistance)
  165. DeclareCastMethod(DependencePoint)
  166. DeclareCastMethod(DependenceNone)
  167. DeclareCastMethod(DependenceEmpty)
  168. #undef DeclareCastMethod
  169. protected:
  170. const Loop* loop_;
  171. };
  172. // clang-format on
  173. class DependenceLine : public Constraint {
  174. public:
  175. DependenceLine(SENode* a, SENode* b, SENode* c, const Loop* loop)
  176. : Constraint(loop), a_(a), b_(b), c_(c) {}
  177. ConstraintType GetType() const final { return Line; }
  178. DependenceLine* AsDependenceLine() final { return this; }
  179. const DependenceLine* AsDependenceLine() const final { return this; }
  180. SENode* GetA() const { return a_; }
  181. SENode* GetB() const { return b_; }
  182. SENode* GetC() const { return c_; }
  183. private:
  184. SENode* a_;
  185. SENode* b_;
  186. SENode* c_;
  187. };
  188. class DependenceDistance : public Constraint {
  189. public:
  190. DependenceDistance(SENode* distance, const Loop* loop)
  191. : Constraint(loop), distance_(distance) {}
  192. ConstraintType GetType() const final { return Distance; }
  193. DependenceDistance* AsDependenceDistance() final { return this; }
  194. const DependenceDistance* AsDependenceDistance() const final { return this; }
  195. SENode* GetDistance() const { return distance_; }
  196. private:
  197. SENode* distance_;
  198. };
  199. class DependencePoint : public Constraint {
  200. public:
  201. DependencePoint(SENode* source, SENode* destination, const Loop* loop)
  202. : Constraint(loop), source_(source), destination_(destination) {}
  203. ConstraintType GetType() const final { return Point; }
  204. DependencePoint* AsDependencePoint() final { return this; }
  205. const DependencePoint* AsDependencePoint() const final { return this; }
  206. SENode* GetSource() const { return source_; }
  207. SENode* GetDestination() const { return destination_; }
  208. private:
  209. SENode* source_;
  210. SENode* destination_;
  211. };
  212. class DependenceNone : public Constraint {
  213. public:
  214. DependenceNone() : Constraint(nullptr) {}
  215. ConstraintType GetType() const final { return None; }
  216. DependenceNone* AsDependenceNone() final { return this; }
  217. const DependenceNone* AsDependenceNone() const final { return this; }
  218. };
  219. class DependenceEmpty : public Constraint {
  220. public:
  221. DependenceEmpty() : Constraint(nullptr) {}
  222. ConstraintType GetType() const final { return Empty; }
  223. DependenceEmpty* AsDependenceEmpty() final { return this; }
  224. const DependenceEmpty* AsDependenceEmpty() const final { return this; }
  225. };
  226. // Provides dependence information between a store instruction and a load
  227. // instruction inside the same loop in a loop nest.
  228. //
  229. // The analysis can only check dependence between stores and loads with regard
  230. // to the loop nest it is created with.
  231. //
  232. // The analysis can output debugging information to a stream. The output
  233. // describes the control flow of the analysis and what information it can deduce
  234. // at each step.
  235. // SetDebugStream and ClearDebugStream are provided for this functionality.
  236. //
  237. // The dependency algorithm is based on the 1990 Paper
  238. // Practical Dependence Testing
  239. // Gina Goff, Ken Kennedy, Chau-Wen Tseng
  240. //
  241. // The algorithm first identifies subscript pairs between the load and store.
  242. // Each pair is tested until all have been tested or independence is found.
  243. // The number of induction variables in a pair determines which test to perform
  244. // on it;
  245. // Zero Index Variable (ZIV) is used when no induction variables are present
  246. // in the pair.
  247. // Single Index Variable (SIV) is used when only one induction variable is
  248. // present, but may occur multiple times in the pair.
  249. // Multiple Index Variable (MIV) is used when more than one induction variable
  250. // is present in the pair.
  251. class LoopDependenceAnalysis {
  252. public:
  253. LoopDependenceAnalysis(IRContext* context, std::vector<const Loop*> loops)
  254. : context_(context),
  255. loops_(loops),
  256. scalar_evolution_(context),
  257. debug_stream_(nullptr),
  258. constraints_{} {}
  259. // Finds the dependence between |source| and |destination|.
  260. // |source| should be an OpLoad.
  261. // |destination| should be an OpStore.
  262. // Any direction and distance information found will be stored in
  263. // |distance_vector|.
  264. // Returns true if independence is found, false otherwise.
  265. bool GetDependence(const Instruction* source, const Instruction* destination,
  266. DistanceVector* distance_vector);
  267. // Returns true if |subscript_pair| represents a Zero Index Variable pair
  268. // (ZIV)
  269. bool IsZIV(const std::pair<SENode*, SENode*>& subscript_pair);
  270. // Returns true if |subscript_pair| represents a Single Index Variable
  271. // (SIV) pair
  272. bool IsSIV(const std::pair<SENode*, SENode*>& subscript_pair);
  273. // Returns true if |subscript_pair| represents a Multiple Index Variable
  274. // (MIV) pair
  275. bool IsMIV(const std::pair<SENode*, SENode*>& subscript_pair);
  276. // Finds the lower bound of |loop| as an SENode* and returns the result.
  277. // The lower bound is the starting value of the loops induction variable
  278. SENode* GetLowerBound(const Loop* loop);
  279. // Finds the upper bound of |loop| as an SENode* and returns the result.
  280. // The upper bound is the last value before the loop exit condition is met.
  281. SENode* GetUpperBound(const Loop* loop);
  282. // Returns true if |value| is between |bound_one| and |bound_two| (inclusive).
  283. bool IsWithinBounds(int64_t value, int64_t bound_one, int64_t bound_two);
  284. // Finds the bounds of |loop| as upper_bound - lower_bound and returns the
  285. // resulting SENode.
  286. // If the operations can not be completed a nullptr is returned.
  287. SENode* GetTripCount(const Loop* loop);
  288. // Returns the SENode* produced by building an SENode from the result of
  289. // calling GetInductionInitValue on |loop|.
  290. // If the operation can not be completed a nullptr is returned.
  291. SENode* GetFirstTripInductionNode(const Loop* loop);
  292. // Returns the SENode* produced by building an SENode from the result of
  293. // GetFirstTripInductionNode + (GetTripCount - 1) * induction_coefficient.
  294. // If the operation can not be completed a nullptr is returned.
  295. SENode* GetFinalTripInductionNode(const Loop* loop,
  296. SENode* induction_coefficient);
  297. // Returns all the distinct loops that appear in |nodes|.
  298. std::set<const Loop*> CollectLoops(
  299. const std::vector<SERecurrentNode*>& nodes);
  300. // Returns all the distinct loops that appear in |source| and |destination|.
  301. std::set<const Loop*> CollectLoops(SENode* source, SENode* destination);
  302. // Returns true if |distance| is provably outside the loop bounds.
  303. // |coefficient| must be an SENode representing the coefficient of the
  304. // induction variable of |loop|.
  305. // This method is able to handle some symbolic cases which IsWithinBounds
  306. // can't handle.
  307. bool IsProvablyOutsideOfLoopBounds(const Loop* loop, SENode* distance,
  308. SENode* coefficient);
  309. // Sets the ostream for debug information for the analysis.
  310. void SetDebugStream(std::ostream& debug_stream) {
  311. debug_stream_ = &debug_stream;
  312. }
  313. // Clears the stored ostream to stop debug information printing.
  314. void ClearDebugStream() { debug_stream_ = nullptr; }
  315. // Returns the ScalarEvolutionAnalysis used by this analysis.
  316. ScalarEvolutionAnalysis* GetScalarEvolution() { return &scalar_evolution_; }
  317. // Creates a new constraint of type |T| and returns the pointer to it.
  318. template <typename T, typename... Args>
  319. Constraint* make_constraint(Args&&... args) {
  320. constraints_.push_back(
  321. std::unique_ptr<Constraint>(new T(std::forward<Args>(args)...)));
  322. return constraints_.back().get();
  323. }
  324. // Subscript partitioning as described in Figure 1 of 'Practical Dependence
  325. // Testing' by Gina Goff, Ken Kennedy, and Chau-Wen Tseng from PLDI '91.
  326. // Partitions the subscripts into independent subscripts and minimally coupled
  327. // sets of subscripts.
  328. // Returns the partitioning of subscript pairs. Sets of size 1 indicates an
  329. // independent subscript-pair and others indicate coupled sets.
  330. using PartitionedSubscripts =
  331. std::vector<std::set<std::pair<Instruction*, Instruction*>>>;
  332. PartitionedSubscripts PartitionSubscripts(
  333. const std::vector<Instruction*>& source_subscripts,
  334. const std::vector<Instruction*>& destination_subscripts);
  335. // Returns the Loop* matching the loop for |subscript_pair|.
  336. // |subscript_pair| must be an SIV pair.
  337. const Loop* GetLoopForSubscriptPair(
  338. const std::pair<SENode*, SENode*>& subscript_pair);
  339. // Returns the DistanceEntry matching the loop for |subscript_pair|.
  340. // |subscript_pair| must be an SIV pair.
  341. DistanceEntry* GetDistanceEntryForSubscriptPair(
  342. const std::pair<SENode*, SENode*>& subscript_pair,
  343. DistanceVector* distance_vector);
  344. // Returns the DistanceEntry matching |loop|.
  345. DistanceEntry* GetDistanceEntryForLoop(const Loop* loop,
  346. DistanceVector* distance_vector);
  347. // Returns a vector of Instruction* which form the subscripts of the array
  348. // access defined by the access chain |instruction|.
  349. std::vector<Instruction*> GetSubscripts(const Instruction* instruction);
  350. // Delta test as described in Figure 3 of 'Practical Dependence
  351. // Testing' by Gina Goff, Ken Kennedy, and Chau-Wen Tseng from PLDI '91.
  352. bool DeltaTest(
  353. const std::vector<std::pair<SENode*, SENode*>>& coupled_subscripts,
  354. DistanceVector* dv_entry);
  355. // Constraint propagation as described in Figure 5 of 'Practical Dependence
  356. // Testing' by Gina Goff, Ken Kennedy, and Chau-Wen Tseng from PLDI '91.
  357. std::pair<SENode*, SENode*> PropagateConstraints(
  358. const std::pair<SENode*, SENode*>& subscript_pair,
  359. const std::vector<Constraint*>& constraints);
  360. // Constraint intersection as described in Figure 4 of 'Practical Dependence
  361. // Testing' by Gina Goff, Ken Kennedy, and Chau-Wen Tseng from PLDI '91.
  362. Constraint* IntersectConstraints(Constraint* constraint_0,
  363. Constraint* constraint_1,
  364. const SENode* lower_bound,
  365. const SENode* upper_bound);
  366. // Returns true if each loop in |loops| is in a form supported by this
  367. // analysis.
  368. // A loop is supported if it has a single induction variable and that
  369. // induction variable has a step of +1 or -1 per loop iteration.
  370. bool CheckSupportedLoops(std::vector<const Loop*> loops);
  371. // Returns true if |loop| is in a form supported by this analysis.
  372. // A loop is supported if it has a single induction variable and that
  373. // induction variable has a step of +1 or -1 per loop iteration.
  374. bool IsSupportedLoop(const Loop* loop);
  375. private:
  376. IRContext* context_;
  377. // The loop nest we are analysing the dependence of.
  378. std::vector<const Loop*> loops_;
  379. // The ScalarEvolutionAnalysis used by this analysis to store and perform much
  380. // of its logic.
  381. ScalarEvolutionAnalysis scalar_evolution_;
  382. // The ostream debug information for the analysis to print to.
  383. std::ostream* debug_stream_;
  384. // Stores all the constraints created by the analysis.
  385. std::list<std::unique_ptr<Constraint>> constraints_;
  386. // Returns true if independence can be proven and false if it can't be proven.
  387. bool ZIVTest(const std::pair<SENode*, SENode*>& subscript_pair);
  388. // Analyzes the subscript pair to find an applicable SIV test.
  389. // Returns true if independence can be proven and false if it can't be proven.
  390. bool SIVTest(const std::pair<SENode*, SENode*>& subscript_pair,
  391. DistanceVector* distance_vector);
  392. // Takes the form a*i + c1, a*i + c2
  393. // When c1 and c2 are loop invariant and a is constant
  394. // distance = (c1 - c2)/a
  395. // < if distance > 0
  396. // direction = = if distance = 0
  397. // > if distance < 0
  398. // Returns true if independence is proven and false if it can't be proven.
  399. bool StrongSIVTest(SENode* source, SENode* destination, SENode* coeff,
  400. DistanceEntry* distance_entry);
  401. // Takes for form a*i + c1, a*i + c2
  402. // where c1 and c2 are loop invariant and a is constant.
  403. // c1 and/or c2 contain one or more SEValueUnknown nodes.
  404. bool SymbolicStrongSIVTest(SENode* source, SENode* destination,
  405. SENode* coefficient,
  406. DistanceEntry* distance_entry);
  407. // Takes the form a1*i + c1, a2*i + c2
  408. // where a1 = 0
  409. // distance = (c1 - c2) / a2
  410. // Returns true if independence is proven and false if it can't be proven.
  411. bool WeakZeroSourceSIVTest(SENode* source, SERecurrentNode* destination,
  412. SENode* coefficient,
  413. DistanceEntry* distance_entry);
  414. // Takes the form a1*i + c1, a2*i + c2
  415. // where a2 = 0
  416. // distance = (c2 - c1) / a1
  417. // Returns true if independence is proven and false if it can't be proven.
  418. bool WeakZeroDestinationSIVTest(SERecurrentNode* source, SENode* destination,
  419. SENode* coefficient,
  420. DistanceEntry* distance_entry);
  421. // Takes the form a1*i + c1, a2*i + c2
  422. // where a1 = -a2
  423. // distance = (c2 - c1) / 2*a1
  424. // Returns true if independence is proven and false if it can't be proven.
  425. bool WeakCrossingSIVTest(SENode* source, SENode* destination,
  426. SENode* coefficient, DistanceEntry* distance_entry);
  427. // Uses the def_use_mgr to get the instruction referenced by
  428. // SingleWordInOperand(|id|) when called on |instruction|.
  429. Instruction* GetOperandDefinition(const Instruction* instruction, int id);
  430. // Perform the GCD test if both, the source and the destination nodes, are in
  431. // the form a0*i0 + a1*i1 + ... an*in + c.
  432. bool GCDMIVTest(const std::pair<SENode*, SENode*>& subscript_pair);
  433. // Finds the number of induction variables in |node|.
  434. // Returns -1 on failure.
  435. int64_t CountInductionVariables(SENode* node);
  436. // Finds the number of induction variables shared between |source| and
  437. // |destination|.
  438. // Returns -1 on failure.
  439. int64_t CountInductionVariables(SENode* source, SENode* destination);
  440. // Takes the offset from the induction variable and subtracts the lower bound
  441. // from it to get the constant term added to the induction.
  442. // Returns the resuting constant term, or nullptr if it could not be produced.
  443. SENode* GetConstantTerm(const Loop* loop, SERecurrentNode* induction);
  444. // Marks all the distance entries in |distance_vector| that were relate to
  445. // loops in |loops_| but were not used in any subscripts as irrelevant to the
  446. // to the dependence test.
  447. void MarkUnsusedDistanceEntriesAsIrrelevant(const Instruction* source,
  448. const Instruction* destination,
  449. DistanceVector* distance_vector);
  450. // Converts |value| to a std::string and returns the result.
  451. // This is required because Android does not compile std::to_string.
  452. template <typename valueT>
  453. std::string ToString(valueT value) {
  454. std::ostringstream string_stream;
  455. string_stream << value;
  456. return string_stream.str();
  457. }
  458. // Prints |debug_msg| and "\n" to the ostream pointed to by |debug_stream_|.
  459. // Won't print anything if |debug_stream_| is nullptr.
  460. void PrintDebug(std::string debug_msg);
  461. };
  462. } // namespace opt
  463. } // namespace spvtools
  464. #endif // SOURCE_OPT_LOOP_DEPENDENCE_H_