loop_dependence.cpp 64 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674
  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. #include "source/opt/loop_dependence.h"
  15. #include <functional>
  16. #include <numeric>
  17. #include <string>
  18. #include <utility>
  19. #include <vector>
  20. #include "source/opt/instruction.h"
  21. #include "source/opt/scalar_analysis_nodes.h"
  22. namespace spvtools {
  23. namespace opt {
  24. using SubscriptPair = std::pair<SENode*, SENode*>;
  25. namespace {
  26. // Calculate the greatest common divisor of a & b using Stein's algorithm.
  27. // https://en.wikipedia.org/wiki/Binary_GCD_algorithm
  28. int64_t GreatestCommonDivisor(int64_t a, int64_t b) {
  29. // Simple cases
  30. if (a == b) {
  31. return a;
  32. } else if (a == 0) {
  33. return b;
  34. } else if (b == 0) {
  35. return a;
  36. }
  37. // Both even
  38. if (a % 2 == 0 && b % 2 == 0) {
  39. return 2 * GreatestCommonDivisor(a / 2, b / 2);
  40. }
  41. // Even a, odd b
  42. if (a % 2 == 0 && b % 2 == 1) {
  43. return GreatestCommonDivisor(a / 2, b);
  44. }
  45. // Odd a, even b
  46. if (a % 2 == 1 && b % 2 == 0) {
  47. return GreatestCommonDivisor(a, b / 2);
  48. }
  49. // Both odd, reduce the larger argument
  50. if (a > b) {
  51. return GreatestCommonDivisor((a - b) / 2, b);
  52. } else {
  53. return GreatestCommonDivisor((b - a) / 2, a);
  54. }
  55. }
  56. // Check if node is affine, ie in the form: a0*i0 + a1*i1 + ... an*in + c
  57. // and contains only the following types of nodes: SERecurrentNode, SEAddNode
  58. // and SEConstantNode
  59. bool IsInCorrectFormForGCDTest(SENode* node) {
  60. bool children_ok = true;
  61. if (auto add_node = node->AsSEAddNode()) {
  62. for (auto child : add_node->GetChildren()) {
  63. children_ok &= IsInCorrectFormForGCDTest(child);
  64. }
  65. }
  66. bool this_ok = node->AsSERecurrentNode() || node->AsSEAddNode() ||
  67. node->AsSEConstantNode();
  68. return children_ok && this_ok;
  69. }
  70. // If |node| is an SERecurrentNode then returns |node| or if |node| is an
  71. // SEAddNode returns a vector of SERecurrentNode that are its children.
  72. std::vector<SERecurrentNode*> GetAllTopLevelRecurrences(SENode* node) {
  73. auto nodes = std::vector<SERecurrentNode*>{};
  74. if (auto recurrent_node = node->AsSERecurrentNode()) {
  75. nodes.push_back(recurrent_node);
  76. }
  77. if (auto add_node = node->AsSEAddNode()) {
  78. for (auto child : add_node->GetChildren()) {
  79. auto child_nodes = GetAllTopLevelRecurrences(child);
  80. nodes.insert(nodes.end(), child_nodes.begin(), child_nodes.end());
  81. }
  82. }
  83. return nodes;
  84. }
  85. // If |node| is an SEConstantNode then returns |node| or if |node| is an
  86. // SEAddNode returns a vector of SEConstantNode that are its children.
  87. std::vector<SEConstantNode*> GetAllTopLevelConstants(SENode* node) {
  88. auto nodes = std::vector<SEConstantNode*>{};
  89. if (auto recurrent_node = node->AsSEConstantNode()) {
  90. nodes.push_back(recurrent_node);
  91. }
  92. if (auto add_node = node->AsSEAddNode()) {
  93. for (auto child : add_node->GetChildren()) {
  94. auto child_nodes = GetAllTopLevelConstants(child);
  95. nodes.insert(nodes.end(), child_nodes.begin(), child_nodes.end());
  96. }
  97. }
  98. return nodes;
  99. }
  100. bool AreOffsetsAndCoefficientsConstant(
  101. const std::vector<SERecurrentNode*>& nodes) {
  102. for (auto node : nodes) {
  103. if (!node->GetOffset()->AsSEConstantNode() ||
  104. !node->GetOffset()->AsSEConstantNode()) {
  105. return false;
  106. }
  107. }
  108. return true;
  109. }
  110. // Fold all SEConstantNode that appear in |recurrences| and |constants| into a
  111. // single integer value.
  112. int64_t CalculateConstantTerm(const std::vector<SERecurrentNode*>& recurrences,
  113. const std::vector<SEConstantNode*>& constants) {
  114. int64_t constant_term = 0;
  115. for (auto recurrence : recurrences) {
  116. constant_term +=
  117. recurrence->GetOffset()->AsSEConstantNode()->FoldToSingleValue();
  118. }
  119. for (auto constant : constants) {
  120. constant_term += constant->FoldToSingleValue();
  121. }
  122. return constant_term;
  123. }
  124. int64_t CalculateGCDFromCoefficients(
  125. const std::vector<SERecurrentNode*>& recurrences, int64_t running_gcd) {
  126. for (SERecurrentNode* recurrence : recurrences) {
  127. auto coefficient = recurrence->GetCoefficient()->AsSEConstantNode();
  128. running_gcd = GreatestCommonDivisor(
  129. running_gcd, std::abs(coefficient->FoldToSingleValue()));
  130. }
  131. return running_gcd;
  132. }
  133. // Compare 2 fractions while first normalizing them, e.g. 2/4 and 4/8 will both
  134. // be simplified to 1/2 and then determined to be equal.
  135. bool NormalizeAndCompareFractions(int64_t numerator_0, int64_t denominator_0,
  136. int64_t numerator_1, int64_t denominator_1) {
  137. auto gcd_0 =
  138. GreatestCommonDivisor(std::abs(numerator_0), std::abs(denominator_0));
  139. auto gcd_1 =
  140. GreatestCommonDivisor(std::abs(numerator_1), std::abs(denominator_1));
  141. auto normalized_numerator_0 = numerator_0 / gcd_0;
  142. auto normalized_denominator_0 = denominator_0 / gcd_0;
  143. auto normalized_numerator_1 = numerator_1 / gcd_1;
  144. auto normalized_denominator_1 = denominator_1 / gcd_1;
  145. return normalized_numerator_0 == normalized_numerator_1 &&
  146. normalized_denominator_0 == normalized_denominator_1;
  147. }
  148. } // namespace
  149. bool LoopDependenceAnalysis::GetDependence(const Instruction* source,
  150. const Instruction* destination,
  151. DistanceVector* distance_vector) {
  152. // Start off by finding and marking all the loops in |loops_| that are
  153. // irrelevant to the dependence analysis.
  154. MarkUnsusedDistanceEntriesAsIrrelevant(source, destination, distance_vector);
  155. Instruction* source_access_chain = GetOperandDefinition(source, 0);
  156. Instruction* destination_access_chain = GetOperandDefinition(destination, 0);
  157. auto num_access_chains =
  158. (source_access_chain->opcode() == spv::Op::OpAccessChain) +
  159. (destination_access_chain->opcode() == spv::Op::OpAccessChain);
  160. // If neither is an access chain, then they are load/store to a variable.
  161. if (num_access_chains == 0) {
  162. if (source_access_chain != destination_access_chain) {
  163. // Not the same location, report independence
  164. return true;
  165. } else {
  166. // Accessing the same variable
  167. for (auto& entry : distance_vector->GetEntries()) {
  168. entry = DistanceEntry();
  169. }
  170. return false;
  171. }
  172. }
  173. // If only one is an access chain, it could be accessing a part of a struct
  174. if (num_access_chains == 1) {
  175. auto source_is_chain =
  176. source_access_chain->opcode() == spv::Op::OpAccessChain;
  177. auto access_chain =
  178. source_is_chain ? source_access_chain : destination_access_chain;
  179. auto variable =
  180. source_is_chain ? destination_access_chain : source_access_chain;
  181. auto location_in_chain = GetOperandDefinition(access_chain, 0);
  182. if (variable != location_in_chain) {
  183. // Not the same location, report independence
  184. return true;
  185. } else {
  186. // Accessing the same variable
  187. for (auto& entry : distance_vector->GetEntries()) {
  188. entry = DistanceEntry();
  189. }
  190. return false;
  191. }
  192. }
  193. // If the access chains aren't collecting from the same structure there is no
  194. // dependence.
  195. Instruction* source_array = GetOperandDefinition(source_access_chain, 0);
  196. Instruction* destination_array =
  197. GetOperandDefinition(destination_access_chain, 0);
  198. // Nested access chains are not supported yet, bail out.
  199. if (source_array->opcode() == spv::Op::OpAccessChain ||
  200. destination_array->opcode() == spv::Op::OpAccessChain) {
  201. for (auto& entry : distance_vector->GetEntries()) {
  202. entry = DistanceEntry();
  203. }
  204. return false;
  205. }
  206. if (source_array != destination_array) {
  207. PrintDebug("Proved independence through different arrays.");
  208. return true;
  209. }
  210. // To handle multiple subscripts we must get every operand in the access
  211. // chains past the first.
  212. std::vector<Instruction*> source_subscripts = GetSubscripts(source);
  213. std::vector<Instruction*> destination_subscripts = GetSubscripts(destination);
  214. auto sets_of_subscripts =
  215. PartitionSubscripts(source_subscripts, destination_subscripts);
  216. auto first_coupled = std::partition(
  217. std::begin(sets_of_subscripts), std::end(sets_of_subscripts),
  218. [](const std::set<std::pair<Instruction*, Instruction*>>& set) {
  219. return set.size() == 1;
  220. });
  221. // Go through each subscript testing for independence.
  222. // If any subscript results in independence, we prove independence between the
  223. // load and store.
  224. // If we can't prove independence we store what information we can gather in
  225. // a DistanceVector.
  226. for (auto it = std::begin(sets_of_subscripts); it < first_coupled; ++it) {
  227. auto source_subscript = std::get<0>(*(*it).begin());
  228. auto destination_subscript = std::get<1>(*(*it).begin());
  229. SENode* source_node = scalar_evolution_.SimplifyExpression(
  230. scalar_evolution_.AnalyzeInstruction(source_subscript));
  231. SENode* destination_node = scalar_evolution_.SimplifyExpression(
  232. scalar_evolution_.AnalyzeInstruction(destination_subscript));
  233. // Check the loops are in a form we support.
  234. auto subscript_pair = std::make_pair(source_node, destination_node);
  235. const Loop* loop = GetLoopForSubscriptPair(subscript_pair);
  236. if (loop) {
  237. if (!IsSupportedLoop(loop)) {
  238. PrintDebug(
  239. "GetDependence found an unsupported loop form. Assuming <=> for "
  240. "loop.");
  241. DistanceEntry* distance_entry =
  242. GetDistanceEntryForSubscriptPair(subscript_pair, distance_vector);
  243. if (distance_entry) {
  244. distance_entry->direction = DistanceEntry::Directions::ALL;
  245. }
  246. continue;
  247. }
  248. }
  249. // If either node is simplified to a CanNotCompute we can't perform any
  250. // analysis so must assume <=> dependence and return.
  251. if (source_node->GetType() == SENode::CanNotCompute ||
  252. destination_node->GetType() == SENode::CanNotCompute) {
  253. // Record the <=> dependence if we can get a DistanceEntry
  254. PrintDebug(
  255. "GetDependence found source_node || destination_node as "
  256. "CanNotCompute. Abandoning evaluation for this subscript.");
  257. DistanceEntry* distance_entry =
  258. GetDistanceEntryForSubscriptPair(subscript_pair, distance_vector);
  259. if (distance_entry) {
  260. distance_entry->direction = DistanceEntry::Directions::ALL;
  261. }
  262. continue;
  263. }
  264. // We have no induction variables so can apply a ZIV test.
  265. if (IsZIV(subscript_pair)) {
  266. PrintDebug("Found a ZIV subscript pair");
  267. if (ZIVTest(subscript_pair)) {
  268. PrintDebug("Proved independence with ZIVTest.");
  269. return true;
  270. }
  271. }
  272. // We have only one induction variable so should attempt an SIV test.
  273. if (IsSIV(subscript_pair)) {
  274. PrintDebug("Found a SIV subscript pair.");
  275. if (SIVTest(subscript_pair, distance_vector)) {
  276. PrintDebug("Proved independence with SIVTest.");
  277. return true;
  278. }
  279. }
  280. // We have multiple induction variables so should attempt an MIV test.
  281. if (IsMIV(subscript_pair)) {
  282. PrintDebug("Found a MIV subscript pair.");
  283. if (GCDMIVTest(subscript_pair)) {
  284. PrintDebug("Proved independence with the GCD test.");
  285. auto current_loops = CollectLoops(source_node, destination_node);
  286. for (auto current_loop : current_loops) {
  287. auto distance_entry =
  288. GetDistanceEntryForLoop(current_loop, distance_vector);
  289. distance_entry->direction = DistanceEntry::Directions::NONE;
  290. }
  291. return true;
  292. }
  293. }
  294. }
  295. for (auto it = first_coupled; it < std::end(sets_of_subscripts); ++it) {
  296. auto coupled_instructions = *it;
  297. std::vector<SubscriptPair> coupled_subscripts{};
  298. for (const auto& elem : coupled_instructions) {
  299. auto source_subscript = std::get<0>(elem);
  300. auto destination_subscript = std::get<1>(elem);
  301. SENode* source_node = scalar_evolution_.SimplifyExpression(
  302. scalar_evolution_.AnalyzeInstruction(source_subscript));
  303. SENode* destination_node = scalar_evolution_.SimplifyExpression(
  304. scalar_evolution_.AnalyzeInstruction(destination_subscript));
  305. coupled_subscripts.push_back({source_node, destination_node});
  306. }
  307. auto supported = true;
  308. for (const auto& subscript : coupled_subscripts) {
  309. auto loops = CollectLoops(std::get<0>(subscript), std::get<1>(subscript));
  310. auto is_subscript_supported =
  311. std::all_of(std::begin(loops), std::end(loops),
  312. [this](const Loop* l) { return IsSupportedLoop(l); });
  313. supported = supported && is_subscript_supported;
  314. }
  315. if (DeltaTest(coupled_subscripts, distance_vector)) {
  316. return true;
  317. }
  318. }
  319. // We were unable to prove independence so must gather all of the direction
  320. // information we found.
  321. PrintDebug(
  322. "Couldn't prove independence.\n"
  323. "All possible direction information has been collected in the input "
  324. "DistanceVector.");
  325. return false;
  326. }
  327. bool LoopDependenceAnalysis::ZIVTest(
  328. const std::pair<SENode*, SENode*>& subscript_pair) {
  329. auto source = std::get<0>(subscript_pair);
  330. auto destination = std::get<1>(subscript_pair);
  331. PrintDebug("Performing ZIVTest");
  332. // If source == destination, dependence with direction = and distance 0.
  333. if (source == destination) {
  334. PrintDebug("ZIVTest found EQ dependence.");
  335. return false;
  336. } else {
  337. PrintDebug("ZIVTest found independence.");
  338. // Otherwise we prove independence.
  339. return true;
  340. }
  341. }
  342. bool LoopDependenceAnalysis::SIVTest(
  343. const std::pair<SENode*, SENode*>& subscript_pair,
  344. DistanceVector* distance_vector) {
  345. DistanceEntry* distance_entry =
  346. GetDistanceEntryForSubscriptPair(subscript_pair, distance_vector);
  347. if (!distance_entry) {
  348. PrintDebug(
  349. "SIVTest could not find a DistanceEntry for subscript_pair. Exiting");
  350. }
  351. SENode* source_node = std::get<0>(subscript_pair);
  352. SENode* destination_node = std::get<1>(subscript_pair);
  353. int64_t source_induction_count = CountInductionVariables(source_node);
  354. int64_t destination_induction_count =
  355. CountInductionVariables(destination_node);
  356. // If the source node has no induction variables we can apply a
  357. // WeakZeroSrcTest.
  358. if (source_induction_count == 0) {
  359. PrintDebug("Found source has no induction variable.");
  360. if (WeakZeroSourceSIVTest(
  361. source_node, destination_node->AsSERecurrentNode(),
  362. destination_node->AsSERecurrentNode()->GetCoefficient(),
  363. distance_entry)) {
  364. PrintDebug("Proved independence with WeakZeroSourceSIVTest.");
  365. distance_entry->dependence_information =
  366. DistanceEntry::DependenceInformation::DIRECTION;
  367. distance_entry->direction = DistanceEntry::Directions::NONE;
  368. return true;
  369. }
  370. }
  371. // If the destination has no induction variables we can apply a
  372. // WeakZeroDestTest.
  373. if (destination_induction_count == 0) {
  374. PrintDebug("Found destination has no induction variable.");
  375. if (WeakZeroDestinationSIVTest(
  376. source_node->AsSERecurrentNode(), destination_node,
  377. source_node->AsSERecurrentNode()->GetCoefficient(),
  378. distance_entry)) {
  379. PrintDebug("Proved independence with WeakZeroDestinationSIVTest.");
  380. distance_entry->dependence_information =
  381. DistanceEntry::DependenceInformation::DIRECTION;
  382. distance_entry->direction = DistanceEntry::Directions::NONE;
  383. return true;
  384. }
  385. }
  386. // We now need to collect the SERecurrentExpr nodes from source and
  387. // destination. We do not handle cases where source or destination have
  388. // multiple SERecurrentExpr nodes.
  389. std::vector<SERecurrentNode*> source_recurrent_nodes =
  390. source_node->CollectRecurrentNodes();
  391. std::vector<SERecurrentNode*> destination_recurrent_nodes =
  392. destination_node->CollectRecurrentNodes();
  393. if (source_recurrent_nodes.size() == 1 &&
  394. destination_recurrent_nodes.size() == 1) {
  395. PrintDebug("Found source and destination have 1 induction variable.");
  396. SERecurrentNode* source_recurrent_expr = *source_recurrent_nodes.begin();
  397. SERecurrentNode* destination_recurrent_expr =
  398. *destination_recurrent_nodes.begin();
  399. // If the coefficients are identical we can apply a StrongSIVTest.
  400. if (source_recurrent_expr->GetCoefficient() ==
  401. destination_recurrent_expr->GetCoefficient()) {
  402. PrintDebug("Found source and destination share coefficient.");
  403. if (StrongSIVTest(source_node, destination_node,
  404. source_recurrent_expr->GetCoefficient(),
  405. distance_entry)) {
  406. PrintDebug("Proved independence with StrongSIVTest");
  407. distance_entry->dependence_information =
  408. DistanceEntry::DependenceInformation::DIRECTION;
  409. distance_entry->direction = DistanceEntry::Directions::NONE;
  410. return true;
  411. }
  412. }
  413. // If the coefficients are of equal magnitude and opposite sign we can
  414. // apply a WeakCrossingSIVTest.
  415. if (source_recurrent_expr->GetCoefficient() ==
  416. scalar_evolution_.CreateNegation(
  417. destination_recurrent_expr->GetCoefficient())) {
  418. PrintDebug("Found source coefficient = -destination coefficient.");
  419. if (WeakCrossingSIVTest(source_node, destination_node,
  420. source_recurrent_expr->GetCoefficient(),
  421. distance_entry)) {
  422. PrintDebug("Proved independence with WeakCrossingSIVTest");
  423. distance_entry->dependence_information =
  424. DistanceEntry::DependenceInformation::DIRECTION;
  425. distance_entry->direction = DistanceEntry::Directions::NONE;
  426. return true;
  427. }
  428. }
  429. }
  430. return false;
  431. }
  432. bool LoopDependenceAnalysis::StrongSIVTest(SENode* source, SENode* destination,
  433. SENode* coefficient,
  434. DistanceEntry* distance_entry) {
  435. PrintDebug("Performing StrongSIVTest.");
  436. // If both source and destination are SERecurrentNodes we can perform tests
  437. // based on distance.
  438. // If either source or destination contain value unknown nodes or if one or
  439. // both are not SERecurrentNodes we must attempt a symbolic test.
  440. std::vector<SEValueUnknown*> source_value_unknown_nodes =
  441. source->CollectValueUnknownNodes();
  442. std::vector<SEValueUnknown*> destination_value_unknown_nodes =
  443. destination->CollectValueUnknownNodes();
  444. if (source_value_unknown_nodes.size() > 0 ||
  445. destination_value_unknown_nodes.size() > 0) {
  446. PrintDebug(
  447. "StrongSIVTest found symbolics. Will attempt SymbolicStrongSIVTest.");
  448. return SymbolicStrongSIVTest(source, destination, coefficient,
  449. distance_entry);
  450. }
  451. if (!source->AsSERecurrentNode() || !destination->AsSERecurrentNode()) {
  452. PrintDebug(
  453. "StrongSIVTest could not simplify source and destination to "
  454. "SERecurrentNodes so will exit.");
  455. distance_entry->direction = DistanceEntry::Directions::ALL;
  456. return false;
  457. }
  458. // Build an SENode for distance.
  459. std::pair<SENode*, SENode*> subscript_pair =
  460. std::make_pair(source, destination);
  461. const Loop* subscript_loop = GetLoopForSubscriptPair(subscript_pair);
  462. SENode* source_constant_term =
  463. GetConstantTerm(subscript_loop, source->AsSERecurrentNode());
  464. SENode* destination_constant_term =
  465. GetConstantTerm(subscript_loop, destination->AsSERecurrentNode());
  466. if (!source_constant_term || !destination_constant_term) {
  467. PrintDebug(
  468. "StrongSIVTest could not collect the constant terms of either source "
  469. "or destination so will exit.");
  470. return false;
  471. }
  472. SENode* constant_term_delta =
  473. scalar_evolution_.SimplifyExpression(scalar_evolution_.CreateSubtraction(
  474. destination_constant_term, source_constant_term));
  475. // Scalar evolution doesn't perform division, so we must fold to constants and
  476. // do it manually.
  477. // We must check the offset delta and coefficient are constants.
  478. int64_t distance = 0;
  479. SEConstantNode* delta_constant = constant_term_delta->AsSEConstantNode();
  480. SEConstantNode* coefficient_constant = coefficient->AsSEConstantNode();
  481. if (delta_constant && coefficient_constant) {
  482. int64_t delta_value = delta_constant->FoldToSingleValue();
  483. int64_t coefficient_value = coefficient_constant->FoldToSingleValue();
  484. PrintDebug(
  485. "StrongSIVTest found delta value and coefficient value as constants "
  486. "with values:\n"
  487. "\tdelta value: " +
  488. ToString(delta_value) +
  489. "\n\tcoefficient value: " + ToString(coefficient_value) + "\n");
  490. // Check if the distance is not integral to try to prove independence.
  491. if (delta_value % coefficient_value != 0) {
  492. PrintDebug(
  493. "StrongSIVTest proved independence through distance not being an "
  494. "integer.");
  495. distance_entry->dependence_information =
  496. DistanceEntry::DependenceInformation::DIRECTION;
  497. distance_entry->direction = DistanceEntry::Directions::NONE;
  498. return true;
  499. } else {
  500. distance = delta_value / coefficient_value;
  501. PrintDebug("StrongSIV test found distance as " + ToString(distance));
  502. }
  503. } else {
  504. // If we can't fold delta and coefficient to single values we can't produce
  505. // distance.
  506. // As a result we can't perform the rest of the pass and must assume
  507. // dependence in all directions.
  508. PrintDebug("StrongSIVTest could not produce a distance. Must exit.");
  509. distance_entry->distance = DistanceEntry::Directions::ALL;
  510. return false;
  511. }
  512. // Next we gather the upper and lower bounds as constants if possible. If
  513. // distance > upper_bound - lower_bound we prove independence.
  514. SENode* lower_bound = GetLowerBound(subscript_loop);
  515. SENode* upper_bound = GetUpperBound(subscript_loop);
  516. if (lower_bound && upper_bound) {
  517. PrintDebug("StrongSIVTest found bounds.");
  518. SENode* bounds = scalar_evolution_.SimplifyExpression(
  519. scalar_evolution_.CreateSubtraction(upper_bound, lower_bound));
  520. if (bounds->GetType() == SENode::SENodeType::Constant) {
  521. int64_t bounds_value = bounds->AsSEConstantNode()->FoldToSingleValue();
  522. PrintDebug(
  523. "StrongSIVTest found upper_bound - lower_bound as a constant with "
  524. "value " +
  525. ToString(bounds_value));
  526. // If the absolute value of the distance is > upper bound - lower bound
  527. // then we prove independence.
  528. if (llabs(distance) > llabs(bounds_value)) {
  529. PrintDebug(
  530. "StrongSIVTest proved independence through distance escaping the "
  531. "loop bounds.");
  532. distance_entry->dependence_information =
  533. DistanceEntry::DependenceInformation::DISTANCE;
  534. distance_entry->direction = DistanceEntry::Directions::NONE;
  535. distance_entry->distance = distance;
  536. return true;
  537. }
  538. }
  539. } else {
  540. PrintDebug("StrongSIVTest was unable to gather lower and upper bounds.");
  541. }
  542. // Otherwise we can get a direction as follows
  543. // { < if distance > 0
  544. // direction = { = if distance == 0
  545. // { > if distance < 0
  546. PrintDebug(
  547. "StrongSIVTest could not prove independence. Gathering direction "
  548. "information.");
  549. if (distance > 0) {
  550. distance_entry->dependence_information =
  551. DistanceEntry::DependenceInformation::DISTANCE;
  552. distance_entry->direction = DistanceEntry::Directions::LT;
  553. distance_entry->distance = distance;
  554. return false;
  555. }
  556. if (distance == 0) {
  557. distance_entry->dependence_information =
  558. DistanceEntry::DependenceInformation::DISTANCE;
  559. distance_entry->direction = DistanceEntry::Directions::EQ;
  560. distance_entry->distance = 0;
  561. return false;
  562. }
  563. if (distance < 0) {
  564. distance_entry->dependence_information =
  565. DistanceEntry::DependenceInformation::DISTANCE;
  566. distance_entry->direction = DistanceEntry::Directions::GT;
  567. distance_entry->distance = distance;
  568. return false;
  569. }
  570. // We were unable to prove independence or discern any additional information
  571. // Must assume <=> direction.
  572. PrintDebug(
  573. "StrongSIVTest was unable to determine any dependence information.");
  574. distance_entry->direction = DistanceEntry::Directions::ALL;
  575. return false;
  576. }
  577. bool LoopDependenceAnalysis::SymbolicStrongSIVTest(
  578. SENode* source, SENode* destination, SENode* coefficient,
  579. DistanceEntry* distance_entry) {
  580. PrintDebug("Performing SymbolicStrongSIVTest.");
  581. SENode* source_destination_delta = scalar_evolution_.SimplifyExpression(
  582. scalar_evolution_.CreateSubtraction(source, destination));
  583. // By cancelling out the induction variables by subtracting the source and
  584. // destination we can produce an expression of symbolics and constants. This
  585. // expression can be compared to the loop bounds to find if the offset is
  586. // outwith the bounds.
  587. std::pair<SENode*, SENode*> subscript_pair =
  588. std::make_pair(source, destination);
  589. const Loop* subscript_loop = GetLoopForSubscriptPair(subscript_pair);
  590. if (IsProvablyOutsideOfLoopBounds(subscript_loop, source_destination_delta,
  591. coefficient)) {
  592. PrintDebug(
  593. "SymbolicStrongSIVTest proved independence through loop bounds.");
  594. distance_entry->dependence_information =
  595. DistanceEntry::DependenceInformation::DIRECTION;
  596. distance_entry->direction = DistanceEntry::Directions::NONE;
  597. return true;
  598. }
  599. // We were unable to prove independence or discern any additional information.
  600. // Must assume <=> direction.
  601. PrintDebug(
  602. "SymbolicStrongSIVTest was unable to determine any dependence "
  603. "information.");
  604. distance_entry->direction = DistanceEntry::Directions::ALL;
  605. return false;
  606. }
  607. bool LoopDependenceAnalysis::WeakZeroSourceSIVTest(
  608. SENode* source, SERecurrentNode* destination, SENode* coefficient,
  609. DistanceEntry* distance_entry) {
  610. PrintDebug("Performing WeakZeroSourceSIVTest.");
  611. std::pair<SENode*, SENode*> subscript_pair =
  612. std::make_pair(source, destination);
  613. const Loop* subscript_loop = GetLoopForSubscriptPair(subscript_pair);
  614. // Build an SENode for distance.
  615. SENode* destination_constant_term =
  616. GetConstantTerm(subscript_loop, destination);
  617. SENode* delta = scalar_evolution_.SimplifyExpression(
  618. scalar_evolution_.CreateSubtraction(source, destination_constant_term));
  619. // Scalar evolution doesn't perform division, so we must fold to constants and
  620. // do it manually.
  621. int64_t distance = 0;
  622. SEConstantNode* delta_constant = delta->AsSEConstantNode();
  623. SEConstantNode* coefficient_constant = coefficient->AsSEConstantNode();
  624. if (delta_constant && coefficient_constant) {
  625. PrintDebug(
  626. "WeakZeroSourceSIVTest folding delta and coefficient to constants.");
  627. int64_t delta_value = delta_constant->FoldToSingleValue();
  628. int64_t coefficient_value = coefficient_constant->FoldToSingleValue();
  629. // Check if the distance is not integral.
  630. if (delta_value % coefficient_value != 0) {
  631. PrintDebug(
  632. "WeakZeroSourceSIVTest proved independence through distance not "
  633. "being an integer.");
  634. distance_entry->dependence_information =
  635. DistanceEntry::DependenceInformation::DIRECTION;
  636. distance_entry->direction = DistanceEntry::Directions::NONE;
  637. return true;
  638. } else {
  639. distance = delta_value / coefficient_value;
  640. PrintDebug(
  641. "WeakZeroSourceSIVTest calculated distance with the following "
  642. "values\n"
  643. "\tdelta value: " +
  644. ToString(delta_value) +
  645. "\n\tcoefficient value: " + ToString(coefficient_value) +
  646. "\n\tdistance: " + ToString(distance) + "\n");
  647. }
  648. } else {
  649. PrintDebug(
  650. "WeakZeroSourceSIVTest was unable to fold delta and coefficient to "
  651. "constants.");
  652. }
  653. // If we can prove the distance is outside the bounds we prove independence.
  654. SEConstantNode* lower_bound =
  655. GetLowerBound(subscript_loop)->AsSEConstantNode();
  656. SEConstantNode* upper_bound =
  657. GetUpperBound(subscript_loop)->AsSEConstantNode();
  658. if (lower_bound && upper_bound) {
  659. PrintDebug("WeakZeroSourceSIVTest found bounds as SEConstantNodes.");
  660. int64_t lower_bound_value = lower_bound->FoldToSingleValue();
  661. int64_t upper_bound_value = upper_bound->FoldToSingleValue();
  662. if (!IsWithinBounds(llabs(distance), lower_bound_value,
  663. upper_bound_value)) {
  664. PrintDebug(
  665. "WeakZeroSourceSIVTest proved independence through distance escaping "
  666. "the loop bounds.");
  667. PrintDebug(
  668. "Bound values were as follow\n"
  669. "\tlower bound value: " +
  670. ToString(lower_bound_value) +
  671. "\n\tupper bound value: " + ToString(upper_bound_value) +
  672. "\n\tdistance value: " + ToString(distance) + "\n");
  673. distance_entry->dependence_information =
  674. DistanceEntry::DependenceInformation::DISTANCE;
  675. distance_entry->direction = DistanceEntry::Directions::NONE;
  676. distance_entry->distance = distance;
  677. return true;
  678. }
  679. } else {
  680. PrintDebug(
  681. "WeakZeroSourceSIVTest was unable to find lower and upper bound as "
  682. "SEConstantNodes.");
  683. }
  684. // Now we want to see if we can detect to peel the first or last iterations.
  685. // We get the FirstTripValue as GetFirstTripInductionNode() +
  686. // GetConstantTerm(destination)
  687. SENode* first_trip_SENode =
  688. scalar_evolution_.SimplifyExpression(scalar_evolution_.CreateAddNode(
  689. GetFirstTripInductionNode(subscript_loop),
  690. GetConstantTerm(subscript_loop, destination)));
  691. // If source == FirstTripValue, peel_first.
  692. if (first_trip_SENode) {
  693. PrintDebug("WeakZeroSourceSIVTest built first_trip_SENode.");
  694. if (first_trip_SENode->AsSEConstantNode()) {
  695. PrintDebug(
  696. "WeakZeroSourceSIVTest has found first_trip_SENode as an "
  697. "SEConstantNode with value: " +
  698. ToString(first_trip_SENode->AsSEConstantNode()->FoldToSingleValue()) +
  699. "\n");
  700. }
  701. if (source == first_trip_SENode) {
  702. // We have found that peeling the first iteration will break dependency.
  703. PrintDebug(
  704. "WeakZeroSourceSIVTest has found peeling first iteration will break "
  705. "dependency");
  706. distance_entry->dependence_information =
  707. DistanceEntry::DependenceInformation::PEEL;
  708. distance_entry->peel_first = true;
  709. return false;
  710. }
  711. } else {
  712. PrintDebug("WeakZeroSourceSIVTest was unable to build first_trip_SENode");
  713. }
  714. // We get the LastTripValue as GetFinalTripInductionNode(coefficient) +
  715. // GetConstantTerm(destination)
  716. SENode* final_trip_SENode =
  717. scalar_evolution_.SimplifyExpression(scalar_evolution_.CreateAddNode(
  718. GetFinalTripInductionNode(subscript_loop, coefficient),
  719. GetConstantTerm(subscript_loop, destination)));
  720. // If source == LastTripValue, peel_last.
  721. if (final_trip_SENode) {
  722. PrintDebug("WeakZeroSourceSIVTest built final_trip_SENode.");
  723. if (first_trip_SENode->AsSEConstantNode()) {
  724. PrintDebug(
  725. "WeakZeroSourceSIVTest has found final_trip_SENode as an "
  726. "SEConstantNode with value: " +
  727. ToString(final_trip_SENode->AsSEConstantNode()->FoldToSingleValue()) +
  728. "\n");
  729. }
  730. if (source == final_trip_SENode) {
  731. // We have found that peeling the last iteration will break dependency.
  732. PrintDebug(
  733. "WeakZeroSourceSIVTest has found peeling final iteration will break "
  734. "dependency");
  735. distance_entry->dependence_information =
  736. DistanceEntry::DependenceInformation::PEEL;
  737. distance_entry->peel_last = true;
  738. return false;
  739. }
  740. } else {
  741. PrintDebug("WeakZeroSourceSIVTest was unable to build final_trip_SENode");
  742. }
  743. // We were unable to prove independence or discern any additional information.
  744. // Must assume <=> direction.
  745. PrintDebug(
  746. "WeakZeroSourceSIVTest was unable to determine any dependence "
  747. "information.");
  748. distance_entry->direction = DistanceEntry::Directions::ALL;
  749. return false;
  750. }
  751. bool LoopDependenceAnalysis::WeakZeroDestinationSIVTest(
  752. SERecurrentNode* source, SENode* destination, SENode* coefficient,
  753. DistanceEntry* distance_entry) {
  754. PrintDebug("Performing WeakZeroDestinationSIVTest.");
  755. // Build an SENode for distance.
  756. std::pair<SENode*, SENode*> subscript_pair =
  757. std::make_pair(source, destination);
  758. const Loop* subscript_loop = GetLoopForSubscriptPair(subscript_pair);
  759. SENode* source_constant_term = GetConstantTerm(subscript_loop, source);
  760. SENode* delta = scalar_evolution_.SimplifyExpression(
  761. scalar_evolution_.CreateSubtraction(destination, source_constant_term));
  762. // Scalar evolution doesn't perform division, so we must fold to constants and
  763. // do it manually.
  764. int64_t distance = 0;
  765. SEConstantNode* delta_constant = delta->AsSEConstantNode();
  766. SEConstantNode* coefficient_constant = coefficient->AsSEConstantNode();
  767. if (delta_constant && coefficient_constant) {
  768. PrintDebug(
  769. "WeakZeroDestinationSIVTest folding delta and coefficient to "
  770. "constants.");
  771. int64_t delta_value = delta_constant->FoldToSingleValue();
  772. int64_t coefficient_value = coefficient_constant->FoldToSingleValue();
  773. // Check if the distance is not integral.
  774. if (delta_value % coefficient_value != 0) {
  775. PrintDebug(
  776. "WeakZeroDestinationSIVTest proved independence through distance not "
  777. "being an integer.");
  778. distance_entry->dependence_information =
  779. DistanceEntry::DependenceInformation::DIRECTION;
  780. distance_entry->direction = DistanceEntry::Directions::NONE;
  781. return true;
  782. } else {
  783. distance = delta_value / coefficient_value;
  784. PrintDebug(
  785. "WeakZeroDestinationSIVTest calculated distance with the following "
  786. "values\n"
  787. "\tdelta value: " +
  788. ToString(delta_value) +
  789. "\n\tcoefficient value: " + ToString(coefficient_value) +
  790. "\n\tdistance: " + ToString(distance) + "\n");
  791. }
  792. } else {
  793. PrintDebug(
  794. "WeakZeroDestinationSIVTest was unable to fold delta and coefficient "
  795. "to constants.");
  796. }
  797. // If we can prove the distance is outside the bounds we prove independence.
  798. SEConstantNode* lower_bound =
  799. GetLowerBound(subscript_loop)->AsSEConstantNode();
  800. SEConstantNode* upper_bound =
  801. GetUpperBound(subscript_loop)->AsSEConstantNode();
  802. if (lower_bound && upper_bound) {
  803. PrintDebug("WeakZeroDestinationSIVTest found bounds as SEConstantNodes.");
  804. int64_t lower_bound_value = lower_bound->FoldToSingleValue();
  805. int64_t upper_bound_value = upper_bound->FoldToSingleValue();
  806. if (!IsWithinBounds(llabs(distance), lower_bound_value,
  807. upper_bound_value)) {
  808. PrintDebug(
  809. "WeakZeroDestinationSIVTest proved independence through distance "
  810. "escaping the loop bounds.");
  811. PrintDebug(
  812. "Bound values were as follows\n"
  813. "\tlower bound value: " +
  814. ToString(lower_bound_value) +
  815. "\n\tupper bound value: " + ToString(upper_bound_value) +
  816. "\n\tdistance value: " + ToString(distance));
  817. distance_entry->dependence_information =
  818. DistanceEntry::DependenceInformation::DISTANCE;
  819. distance_entry->direction = DistanceEntry::Directions::NONE;
  820. distance_entry->distance = distance;
  821. return true;
  822. }
  823. } else {
  824. PrintDebug(
  825. "WeakZeroDestinationSIVTest was unable to find lower and upper bound "
  826. "as SEConstantNodes.");
  827. }
  828. // Now we want to see if we can detect to peel the first or last iterations.
  829. // We get the FirstTripValue as GetFirstTripInductionNode() +
  830. // GetConstantTerm(source)
  831. SENode* first_trip_SENode = scalar_evolution_.SimplifyExpression(
  832. scalar_evolution_.CreateAddNode(GetFirstTripInductionNode(subscript_loop),
  833. GetConstantTerm(subscript_loop, source)));
  834. // If destination == FirstTripValue, peel_first.
  835. if (first_trip_SENode) {
  836. PrintDebug("WeakZeroDestinationSIVTest built first_trip_SENode.");
  837. if (first_trip_SENode->AsSEConstantNode()) {
  838. PrintDebug(
  839. "WeakZeroDestinationSIVTest has found first_trip_SENode as an "
  840. "SEConstantNode with value: " +
  841. ToString(first_trip_SENode->AsSEConstantNode()->FoldToSingleValue()) +
  842. "\n");
  843. }
  844. if (destination == first_trip_SENode) {
  845. // We have found that peeling the first iteration will break dependency.
  846. PrintDebug(
  847. "WeakZeroDestinationSIVTest has found peeling first iteration will "
  848. "break dependency");
  849. distance_entry->dependence_information =
  850. DistanceEntry::DependenceInformation::PEEL;
  851. distance_entry->peel_first = true;
  852. return false;
  853. }
  854. } else {
  855. PrintDebug(
  856. "WeakZeroDestinationSIVTest was unable to build first_trip_SENode");
  857. }
  858. // We get the LastTripValue as GetFinalTripInductionNode(coefficient) +
  859. // GetConstantTerm(source)
  860. SENode* final_trip_SENode =
  861. scalar_evolution_.SimplifyExpression(scalar_evolution_.CreateAddNode(
  862. GetFinalTripInductionNode(subscript_loop, coefficient),
  863. GetConstantTerm(subscript_loop, source)));
  864. // If destination == LastTripValue, peel_last.
  865. if (final_trip_SENode) {
  866. PrintDebug("WeakZeroDestinationSIVTest built final_trip_SENode.");
  867. if (final_trip_SENode->AsSEConstantNode()) {
  868. PrintDebug(
  869. "WeakZeroDestinationSIVTest has found final_trip_SENode as an "
  870. "SEConstantNode with value: " +
  871. ToString(final_trip_SENode->AsSEConstantNode()->FoldToSingleValue()) +
  872. "\n");
  873. }
  874. if (destination == final_trip_SENode) {
  875. // We have found that peeling the last iteration will break dependency.
  876. PrintDebug(
  877. "WeakZeroDestinationSIVTest has found peeling final iteration will "
  878. "break dependency");
  879. distance_entry->dependence_information =
  880. DistanceEntry::DependenceInformation::PEEL;
  881. distance_entry->peel_last = true;
  882. return false;
  883. }
  884. } else {
  885. PrintDebug(
  886. "WeakZeroDestinationSIVTest was unable to build final_trip_SENode");
  887. }
  888. // We were unable to prove independence or discern any additional information.
  889. // Must assume <=> direction.
  890. PrintDebug(
  891. "WeakZeroDestinationSIVTest was unable to determine any dependence "
  892. "information.");
  893. distance_entry->direction = DistanceEntry::Directions::ALL;
  894. return false;
  895. }
  896. bool LoopDependenceAnalysis::WeakCrossingSIVTest(
  897. SENode* source, SENode* destination, SENode* coefficient,
  898. DistanceEntry* distance_entry) {
  899. PrintDebug("Performing WeakCrossingSIVTest.");
  900. // We currently can't handle symbolic WeakCrossingSIVTests. If either source
  901. // or destination are not SERecurrentNodes we must exit.
  902. if (!source->AsSERecurrentNode() || !destination->AsSERecurrentNode()) {
  903. PrintDebug(
  904. "WeakCrossingSIVTest found source or destination != SERecurrentNode. "
  905. "Exiting");
  906. distance_entry->direction = DistanceEntry::Directions::ALL;
  907. return false;
  908. }
  909. // Build an SENode for distance.
  910. SENode* offset_delta =
  911. scalar_evolution_.SimplifyExpression(scalar_evolution_.CreateSubtraction(
  912. destination->AsSERecurrentNode()->GetOffset(),
  913. source->AsSERecurrentNode()->GetOffset()));
  914. // Scalar evolution doesn't perform division, so we must fold to constants and
  915. // do it manually.
  916. int64_t distance = 0;
  917. SEConstantNode* delta_constant = offset_delta->AsSEConstantNode();
  918. SEConstantNode* coefficient_constant = coefficient->AsSEConstantNode();
  919. if (delta_constant && coefficient_constant) {
  920. PrintDebug(
  921. "WeakCrossingSIVTest folding offset_delta and coefficient to "
  922. "constants.");
  923. int64_t delta_value = delta_constant->FoldToSingleValue();
  924. int64_t coefficient_value = coefficient_constant->FoldToSingleValue();
  925. // Check if the distance is not integral or if it has a non-integral part
  926. // equal to 1/2.
  927. if (delta_value % (2 * coefficient_value) != 0 &&
  928. static_cast<float>(delta_value % (2 * coefficient_value)) /
  929. static_cast<float>(2 * coefficient_value) !=
  930. 0.5) {
  931. PrintDebug(
  932. "WeakCrossingSIVTest proved independence through distance escaping "
  933. "the loop bounds.");
  934. distance_entry->dependence_information =
  935. DistanceEntry::DependenceInformation::DIRECTION;
  936. distance_entry->direction = DistanceEntry::Directions::NONE;
  937. return true;
  938. } else {
  939. distance = delta_value / (2 * coefficient_value);
  940. }
  941. if (distance == 0) {
  942. PrintDebug("WeakCrossingSIVTest found EQ dependence.");
  943. distance_entry->dependence_information =
  944. DistanceEntry::DependenceInformation::DISTANCE;
  945. distance_entry->direction = DistanceEntry::Directions::EQ;
  946. distance_entry->distance = 0;
  947. return false;
  948. }
  949. } else {
  950. PrintDebug(
  951. "WeakCrossingSIVTest was unable to fold offset_delta and coefficient "
  952. "to constants.");
  953. }
  954. // We were unable to prove independence or discern any additional information.
  955. // Must assume <=> direction.
  956. PrintDebug(
  957. "WeakCrossingSIVTest was unable to determine any dependence "
  958. "information.");
  959. distance_entry->direction = DistanceEntry::Directions::ALL;
  960. return false;
  961. }
  962. // Perform the GCD test if both, the source and the destination nodes, are in
  963. // the form a0*i0 + a1*i1 + ... an*in + c.
  964. bool LoopDependenceAnalysis::GCDMIVTest(
  965. const std::pair<SENode*, SENode*>& subscript_pair) {
  966. auto source = std::get<0>(subscript_pair);
  967. auto destination = std::get<1>(subscript_pair);
  968. // Bail out if source/destination is in an unexpected form.
  969. if (!IsInCorrectFormForGCDTest(source) ||
  970. !IsInCorrectFormForGCDTest(destination)) {
  971. return false;
  972. }
  973. auto source_recurrences = GetAllTopLevelRecurrences(source);
  974. auto dest_recurrences = GetAllTopLevelRecurrences(destination);
  975. // Bail out if all offsets and coefficients aren't constant.
  976. if (!AreOffsetsAndCoefficientsConstant(source_recurrences) ||
  977. !AreOffsetsAndCoefficientsConstant(dest_recurrences)) {
  978. return false;
  979. }
  980. // Calculate the GCD of all coefficients.
  981. auto source_constants = GetAllTopLevelConstants(source);
  982. int64_t source_constant =
  983. CalculateConstantTerm(source_recurrences, source_constants);
  984. auto dest_constants = GetAllTopLevelConstants(destination);
  985. int64_t destination_constant =
  986. CalculateConstantTerm(dest_recurrences, dest_constants);
  987. int64_t delta = std::abs(source_constant - destination_constant);
  988. int64_t running_gcd = 0;
  989. running_gcd = CalculateGCDFromCoefficients(source_recurrences, running_gcd);
  990. running_gcd = CalculateGCDFromCoefficients(dest_recurrences, running_gcd);
  991. return delta % running_gcd != 0;
  992. }
  993. using PartitionedSubscripts =
  994. std::vector<std::set<std::pair<Instruction*, Instruction*>>>;
  995. PartitionedSubscripts LoopDependenceAnalysis::PartitionSubscripts(
  996. const std::vector<Instruction*>& source_subscripts,
  997. const std::vector<Instruction*>& destination_subscripts) {
  998. PartitionedSubscripts partitions{};
  999. auto num_subscripts = source_subscripts.size();
  1000. // Create initial partitions with one subscript pair per partition.
  1001. for (size_t i = 0; i < num_subscripts; ++i) {
  1002. partitions.push_back({{source_subscripts[i], destination_subscripts[i]}});
  1003. }
  1004. // Iterate over the loops to create all partitions
  1005. for (auto loop : loops_) {
  1006. int64_t k = -1;
  1007. for (size_t j = 0; j < partitions.size(); ++j) {
  1008. auto& current_partition = partitions[j];
  1009. // Does |loop| appear in |current_partition|
  1010. auto it = std::find_if(
  1011. current_partition.begin(), current_partition.end(),
  1012. [loop,
  1013. this](const std::pair<Instruction*, Instruction*>& elem) -> bool {
  1014. auto source_recurrences =
  1015. scalar_evolution_.AnalyzeInstruction(std::get<0>(elem))
  1016. ->CollectRecurrentNodes();
  1017. auto destination_recurrences =
  1018. scalar_evolution_.AnalyzeInstruction(std::get<1>(elem))
  1019. ->CollectRecurrentNodes();
  1020. source_recurrences.insert(source_recurrences.end(),
  1021. destination_recurrences.begin(),
  1022. destination_recurrences.end());
  1023. auto loops_in_pair = CollectLoops(source_recurrences);
  1024. auto end_it = loops_in_pair.end();
  1025. return std::find(loops_in_pair.begin(), end_it, loop) != end_it;
  1026. });
  1027. auto has_loop = it != current_partition.end();
  1028. if (has_loop) {
  1029. if (k == -1) {
  1030. k = j;
  1031. } else {
  1032. // Add |partitions[j]| to |partitions[k]| and discard |partitions[j]|
  1033. partitions[static_cast<size_t>(k)].insert(current_partition.begin(),
  1034. current_partition.end());
  1035. current_partition.clear();
  1036. }
  1037. }
  1038. }
  1039. }
  1040. // Remove empty (discarded) partitions
  1041. partitions.erase(
  1042. std::remove_if(
  1043. partitions.begin(), partitions.end(),
  1044. [](const std::set<std::pair<Instruction*, Instruction*>>& partition) {
  1045. return partition.empty();
  1046. }),
  1047. partitions.end());
  1048. return partitions;
  1049. }
  1050. Constraint* LoopDependenceAnalysis::IntersectConstraints(
  1051. Constraint* constraint_0, Constraint* constraint_1,
  1052. const SENode* lower_bound, const SENode* upper_bound) {
  1053. if (constraint_0->AsDependenceNone()) {
  1054. return constraint_1;
  1055. } else if (constraint_1->AsDependenceNone()) {
  1056. return constraint_0;
  1057. }
  1058. // Both constraints are distances. Either the same distance or independent.
  1059. if (constraint_0->AsDependenceDistance() &&
  1060. constraint_1->AsDependenceDistance()) {
  1061. auto dist_0 = constraint_0->AsDependenceDistance();
  1062. auto dist_1 = constraint_1->AsDependenceDistance();
  1063. if (*dist_0->GetDistance() == *dist_1->GetDistance()) {
  1064. return constraint_0;
  1065. } else {
  1066. return make_constraint<DependenceEmpty>();
  1067. }
  1068. }
  1069. // Both constraints are points. Either the same point or independent.
  1070. if (constraint_0->AsDependencePoint() && constraint_1->AsDependencePoint()) {
  1071. auto point_0 = constraint_0->AsDependencePoint();
  1072. auto point_1 = constraint_1->AsDependencePoint();
  1073. if (*point_0->GetSource() == *point_1->GetSource() &&
  1074. *point_0->GetDestination() == *point_1->GetDestination()) {
  1075. return constraint_0;
  1076. } else {
  1077. return make_constraint<DependenceEmpty>();
  1078. }
  1079. }
  1080. // Both constraints are lines/distances.
  1081. if ((constraint_0->AsDependenceDistance() ||
  1082. constraint_0->AsDependenceLine()) &&
  1083. (constraint_1->AsDependenceDistance() ||
  1084. constraint_1->AsDependenceLine())) {
  1085. auto is_distance_0 = constraint_0->AsDependenceDistance() != nullptr;
  1086. auto is_distance_1 = constraint_1->AsDependenceDistance() != nullptr;
  1087. auto a0 = is_distance_0 ? scalar_evolution_.CreateConstant(1)
  1088. : constraint_0->AsDependenceLine()->GetA();
  1089. auto b0 = is_distance_0 ? scalar_evolution_.CreateConstant(-1)
  1090. : constraint_0->AsDependenceLine()->GetB();
  1091. auto c0 =
  1092. is_distance_0
  1093. ? scalar_evolution_.SimplifyExpression(
  1094. scalar_evolution_.CreateNegation(
  1095. constraint_0->AsDependenceDistance()->GetDistance()))
  1096. : constraint_0->AsDependenceLine()->GetC();
  1097. auto a1 = is_distance_1 ? scalar_evolution_.CreateConstant(1)
  1098. : constraint_1->AsDependenceLine()->GetA();
  1099. auto b1 = is_distance_1 ? scalar_evolution_.CreateConstant(-1)
  1100. : constraint_1->AsDependenceLine()->GetB();
  1101. auto c1 =
  1102. is_distance_1
  1103. ? scalar_evolution_.SimplifyExpression(
  1104. scalar_evolution_.CreateNegation(
  1105. constraint_1->AsDependenceDistance()->GetDistance()))
  1106. : constraint_1->AsDependenceLine()->GetC();
  1107. if (a0->AsSEConstantNode() && b0->AsSEConstantNode() &&
  1108. c0->AsSEConstantNode() && a1->AsSEConstantNode() &&
  1109. b1->AsSEConstantNode() && c1->AsSEConstantNode()) {
  1110. auto constant_a0 = a0->AsSEConstantNode()->FoldToSingleValue();
  1111. auto constant_b0 = b0->AsSEConstantNode()->FoldToSingleValue();
  1112. auto constant_c0 = c0->AsSEConstantNode()->FoldToSingleValue();
  1113. auto constant_a1 = a1->AsSEConstantNode()->FoldToSingleValue();
  1114. auto constant_b1 = b1->AsSEConstantNode()->FoldToSingleValue();
  1115. auto constant_c1 = c1->AsSEConstantNode()->FoldToSingleValue();
  1116. // a & b can't both be zero, otherwise it wouldn't be line.
  1117. if (NormalizeAndCompareFractions(constant_a0, constant_b0, constant_a1,
  1118. constant_b1)) {
  1119. // Slopes are equal, either parallel lines or the same line.
  1120. if (constant_b0 == 0 && constant_b1 == 0) {
  1121. if (NormalizeAndCompareFractions(constant_c0, constant_a0,
  1122. constant_c1, constant_a1)) {
  1123. return constraint_0;
  1124. }
  1125. return make_constraint<DependenceEmpty>();
  1126. } else if (NormalizeAndCompareFractions(constant_c0, constant_b0,
  1127. constant_c1, constant_b1)) {
  1128. // Same line.
  1129. return constraint_0;
  1130. } else {
  1131. // Parallel lines can't intersect, report independence.
  1132. return make_constraint<DependenceEmpty>();
  1133. }
  1134. } else {
  1135. // Lines are not parallel, therefore, they must intersect.
  1136. // Calculate intersection.
  1137. if (upper_bound->AsSEConstantNode() &&
  1138. lower_bound->AsSEConstantNode()) {
  1139. auto constant_lower_bound =
  1140. lower_bound->AsSEConstantNode()->FoldToSingleValue();
  1141. auto constant_upper_bound =
  1142. upper_bound->AsSEConstantNode()->FoldToSingleValue();
  1143. auto up = constant_b1 * constant_c0 - constant_b0 * constant_c1;
  1144. // Both b or both a can't be 0, so down is never 0
  1145. // otherwise would have entered the parallel line section.
  1146. auto down = constant_b1 * constant_a0 - constant_b0 * constant_a1;
  1147. auto x_coord = up / down;
  1148. int64_t y_coord = 0;
  1149. int64_t arg1 = 0;
  1150. int64_t const_b_to_use = 0;
  1151. if (constant_b1 != 0) {
  1152. arg1 = constant_c1 - constant_a1 * x_coord;
  1153. y_coord = arg1 / constant_b1;
  1154. const_b_to_use = constant_b1;
  1155. } else if (constant_b0 != 0) {
  1156. arg1 = constant_c0 - constant_a0 * x_coord;
  1157. y_coord = arg1 / constant_b0;
  1158. const_b_to_use = constant_b0;
  1159. }
  1160. if (up % down == 0 &&
  1161. arg1 % const_b_to_use == 0 && // Coordinates are integers.
  1162. constant_lower_bound <=
  1163. x_coord && // x_coord is within loop bounds.
  1164. x_coord <= constant_upper_bound &&
  1165. constant_lower_bound <=
  1166. y_coord && // y_coord is within loop bounds.
  1167. y_coord <= constant_upper_bound) {
  1168. // Lines intersect at integer coordinates.
  1169. return make_constraint<DependencePoint>(
  1170. scalar_evolution_.CreateConstant(x_coord),
  1171. scalar_evolution_.CreateConstant(y_coord),
  1172. constraint_0->GetLoop());
  1173. } else {
  1174. return make_constraint<DependenceEmpty>();
  1175. }
  1176. } else {
  1177. // Not constants, bail out.
  1178. return make_constraint<DependenceNone>();
  1179. }
  1180. }
  1181. } else {
  1182. // Not constants, bail out.
  1183. return make_constraint<DependenceNone>();
  1184. }
  1185. }
  1186. // One constraint is a line/distance and the other is a point.
  1187. if ((constraint_0->AsDependencePoint() &&
  1188. (constraint_1->AsDependenceLine() ||
  1189. constraint_1->AsDependenceDistance())) ||
  1190. (constraint_1->AsDependencePoint() &&
  1191. (constraint_0->AsDependenceLine() ||
  1192. constraint_0->AsDependenceDistance()))) {
  1193. auto point_0 = constraint_0->AsDependencePoint() != nullptr;
  1194. auto point = point_0 ? constraint_0->AsDependencePoint()
  1195. : constraint_1->AsDependencePoint();
  1196. auto line_or_distance = point_0 ? constraint_1 : constraint_0;
  1197. auto is_distance = line_or_distance->AsDependenceDistance() != nullptr;
  1198. auto a = is_distance ? scalar_evolution_.CreateConstant(1)
  1199. : line_or_distance->AsDependenceLine()->GetA();
  1200. auto b = is_distance ? scalar_evolution_.CreateConstant(-1)
  1201. : line_or_distance->AsDependenceLine()->GetB();
  1202. auto c =
  1203. is_distance
  1204. ? scalar_evolution_.SimplifyExpression(
  1205. scalar_evolution_.CreateNegation(
  1206. line_or_distance->AsDependenceDistance()->GetDistance()))
  1207. : line_or_distance->AsDependenceLine()->GetC();
  1208. auto x = point->GetSource();
  1209. auto y = point->GetDestination();
  1210. if (a->AsSEConstantNode() && b->AsSEConstantNode() &&
  1211. c->AsSEConstantNode() && x->AsSEConstantNode() &&
  1212. y->AsSEConstantNode()) {
  1213. auto constant_a = a->AsSEConstantNode()->FoldToSingleValue();
  1214. auto constant_b = b->AsSEConstantNode()->FoldToSingleValue();
  1215. auto constant_c = c->AsSEConstantNode()->FoldToSingleValue();
  1216. auto constant_x = x->AsSEConstantNode()->FoldToSingleValue();
  1217. auto constant_y = y->AsSEConstantNode()->FoldToSingleValue();
  1218. auto left_hand_side = constant_a * constant_x + constant_b * constant_y;
  1219. if (left_hand_side == constant_c) {
  1220. // Point is on line, return point
  1221. return point_0 ? constraint_0 : constraint_1;
  1222. } else {
  1223. // Point not on line, report independence (empty constraint).
  1224. return make_constraint<DependenceEmpty>();
  1225. }
  1226. } else {
  1227. // Not constants, bail out.
  1228. return make_constraint<DependenceNone>();
  1229. }
  1230. }
  1231. return nullptr;
  1232. }
  1233. // Propagate constraints function as described in section 5 of Practical
  1234. // Dependence Testing, Goff, Kennedy, Tseng, 1991.
  1235. SubscriptPair LoopDependenceAnalysis::PropagateConstraints(
  1236. const SubscriptPair& subscript_pair,
  1237. const std::vector<Constraint*>& constraints) {
  1238. SENode* new_first = subscript_pair.first;
  1239. SENode* new_second = subscript_pair.second;
  1240. for (auto& constraint : constraints) {
  1241. // In the paper this is a[k]. We're extracting the coefficient ('a') of a
  1242. // recurrent expression with respect to the loop 'k'.
  1243. SENode* coefficient_of_recurrent =
  1244. scalar_evolution_.GetCoefficientFromRecurrentTerm(
  1245. new_first, constraint->GetLoop());
  1246. // In the paper this is a'[k].
  1247. SENode* coefficient_of_recurrent_prime =
  1248. scalar_evolution_.GetCoefficientFromRecurrentTerm(
  1249. new_second, constraint->GetLoop());
  1250. if (constraint->GetType() == Constraint::Distance) {
  1251. DependenceDistance* as_distance = constraint->AsDependenceDistance();
  1252. // In the paper this is a[k]*d
  1253. SENode* rhs = scalar_evolution_.CreateMultiplyNode(
  1254. coefficient_of_recurrent, as_distance->GetDistance());
  1255. // In the paper this is a[k] <- 0
  1256. SENode* zeroed_coefficient =
  1257. scalar_evolution_.BuildGraphWithoutRecurrentTerm(
  1258. new_first, constraint->GetLoop());
  1259. // In the paper this is e <- e - a[k]*d.
  1260. new_first = scalar_evolution_.CreateSubtraction(zeroed_coefficient, rhs);
  1261. new_first = scalar_evolution_.SimplifyExpression(new_first);
  1262. // In the paper this is a'[k] - a[k].
  1263. SENode* new_child = scalar_evolution_.SimplifyExpression(
  1264. scalar_evolution_.CreateSubtraction(coefficient_of_recurrent_prime,
  1265. coefficient_of_recurrent));
  1266. // In the paper this is a'[k]'i[k].
  1267. SERecurrentNode* prime_recurrent =
  1268. scalar_evolution_.GetRecurrentTerm(new_second, constraint->GetLoop());
  1269. if (!prime_recurrent) continue;
  1270. // As we hash the nodes we need to create a new node when we update a
  1271. // child.
  1272. SENode* new_recurrent = scalar_evolution_.CreateRecurrentExpression(
  1273. constraint->GetLoop(), prime_recurrent->GetOffset(), new_child);
  1274. // In the paper this is a'[k] <- a'[k] - a[k].
  1275. new_second = scalar_evolution_.UpdateChildNode(
  1276. new_second, prime_recurrent, new_recurrent);
  1277. }
  1278. }
  1279. new_second = scalar_evolution_.SimplifyExpression(new_second);
  1280. return std::make_pair(new_first, new_second);
  1281. }
  1282. bool LoopDependenceAnalysis::DeltaTest(
  1283. const std::vector<SubscriptPair>& coupled_subscripts,
  1284. DistanceVector* dv_entry) {
  1285. std::vector<Constraint*> constraints(loops_.size());
  1286. std::vector<bool> loop_appeared(loops_.size());
  1287. std::generate(std::begin(constraints), std::end(constraints),
  1288. [this]() { return make_constraint<DependenceNone>(); });
  1289. // Separate SIV and MIV subscripts
  1290. std::vector<SubscriptPair> siv_subscripts{};
  1291. std::vector<SubscriptPair> miv_subscripts{};
  1292. for (const auto& subscript_pair : coupled_subscripts) {
  1293. if (IsSIV(subscript_pair)) {
  1294. siv_subscripts.push_back(subscript_pair);
  1295. } else {
  1296. miv_subscripts.push_back(subscript_pair);
  1297. }
  1298. }
  1299. // Delta Test
  1300. while (!siv_subscripts.empty()) {
  1301. std::vector<bool> results(siv_subscripts.size());
  1302. std::vector<DistanceVector> current_distances(
  1303. siv_subscripts.size(), DistanceVector(loops_.size()));
  1304. // Apply SIV test to all SIV subscripts, report independence if any of them
  1305. // is independent
  1306. std::transform(
  1307. std::begin(siv_subscripts), std::end(siv_subscripts),
  1308. std::begin(current_distances), std::begin(results),
  1309. [this](SubscriptPair& p, DistanceVector& d) { return SIVTest(p, &d); });
  1310. if (std::accumulate(std::begin(results), std::end(results), false,
  1311. std::logical_or<bool>{})) {
  1312. return true;
  1313. }
  1314. // Derive new constraint vector.
  1315. std::vector<std::pair<Constraint*, size_t>> all_new_constrants{};
  1316. for (size_t i = 0; i < siv_subscripts.size(); ++i) {
  1317. auto loop = GetLoopForSubscriptPair(siv_subscripts[i]);
  1318. auto loop_id =
  1319. std::distance(std::begin(loops_),
  1320. std::find(std::begin(loops_), std::end(loops_), loop));
  1321. loop_appeared[loop_id] = true;
  1322. auto distance_entry = current_distances[i].GetEntries()[loop_id];
  1323. if (distance_entry.dependence_information ==
  1324. DistanceEntry::DependenceInformation::DISTANCE) {
  1325. // Construct a DependenceDistance.
  1326. auto node = scalar_evolution_.CreateConstant(distance_entry.distance);
  1327. all_new_constrants.push_back(
  1328. {make_constraint<DependenceDistance>(node, loop), loop_id});
  1329. } else {
  1330. // Construct a DependenceLine.
  1331. const auto& subscript_pair = siv_subscripts[i];
  1332. SENode* source_node = std::get<0>(subscript_pair);
  1333. SENode* destination_node = std::get<1>(subscript_pair);
  1334. int64_t source_induction_count = CountInductionVariables(source_node);
  1335. int64_t destination_induction_count =
  1336. CountInductionVariables(destination_node);
  1337. SENode* a = nullptr;
  1338. SENode* b = nullptr;
  1339. SENode* c = nullptr;
  1340. if (destination_induction_count != 0) {
  1341. a = destination_node->AsSERecurrentNode()->GetCoefficient();
  1342. c = scalar_evolution_.CreateNegation(
  1343. destination_node->AsSERecurrentNode()->GetOffset());
  1344. } else {
  1345. a = scalar_evolution_.CreateConstant(0);
  1346. c = scalar_evolution_.CreateNegation(destination_node);
  1347. }
  1348. if (source_induction_count != 0) {
  1349. b = scalar_evolution_.CreateNegation(
  1350. source_node->AsSERecurrentNode()->GetCoefficient());
  1351. c = scalar_evolution_.CreateAddNode(
  1352. c, source_node->AsSERecurrentNode()->GetOffset());
  1353. } else {
  1354. b = scalar_evolution_.CreateConstant(0);
  1355. c = scalar_evolution_.CreateAddNode(c, source_node);
  1356. }
  1357. a = scalar_evolution_.SimplifyExpression(a);
  1358. b = scalar_evolution_.SimplifyExpression(b);
  1359. c = scalar_evolution_.SimplifyExpression(c);
  1360. all_new_constrants.push_back(
  1361. {make_constraint<DependenceLine>(a, b, c, loop), loop_id});
  1362. }
  1363. }
  1364. // Calculate the intersection between the new and existing constraints.
  1365. std::vector<Constraint*> intersection = constraints;
  1366. for (const auto& constraint_to_intersect : all_new_constrants) {
  1367. auto loop_id = std::get<1>(constraint_to_intersect);
  1368. auto loop = loops_[loop_id];
  1369. intersection[loop_id] = IntersectConstraints(
  1370. intersection[loop_id], std::get<0>(constraint_to_intersect),
  1371. GetLowerBound(loop), GetUpperBound(loop));
  1372. }
  1373. // Report independence if an empty constraint (DependenceEmpty) is found.
  1374. auto first_empty =
  1375. std::find_if(std::begin(intersection), std::end(intersection),
  1376. [](Constraint* constraint) {
  1377. return constraint->AsDependenceEmpty() != nullptr;
  1378. });
  1379. if (first_empty != std::end(intersection)) {
  1380. return true;
  1381. }
  1382. std::vector<SubscriptPair> new_siv_subscripts{};
  1383. std::vector<SubscriptPair> new_miv_subscripts{};
  1384. auto equal =
  1385. std::equal(std::begin(constraints), std::end(constraints),
  1386. std::begin(intersection),
  1387. [](Constraint* a, Constraint* b) { return *a == *b; });
  1388. // If any constraints have changed, propagate them into the rest of the
  1389. // subscripts possibly creating new ZIV/SIV subscripts.
  1390. if (!equal) {
  1391. std::vector<SubscriptPair> new_subscripts(miv_subscripts.size());
  1392. // Propagate constraints into MIV subscripts
  1393. std::transform(std::begin(miv_subscripts), std::end(miv_subscripts),
  1394. std::begin(new_subscripts),
  1395. [this, &intersection](SubscriptPair& subscript_pair) {
  1396. return PropagateConstraints(subscript_pair,
  1397. intersection);
  1398. });
  1399. // If a ZIV subscript is returned, apply test, otherwise, update untested
  1400. // subscripts.
  1401. for (auto& subscript : new_subscripts) {
  1402. if (IsZIV(subscript) && ZIVTest(subscript)) {
  1403. return true;
  1404. } else if (IsSIV(subscript)) {
  1405. new_siv_subscripts.push_back(subscript);
  1406. } else {
  1407. new_miv_subscripts.push_back(subscript);
  1408. }
  1409. }
  1410. }
  1411. // Set new constraints and subscripts to test.
  1412. std::swap(siv_subscripts, new_siv_subscripts);
  1413. std::swap(miv_subscripts, new_miv_subscripts);
  1414. std::swap(constraints, intersection);
  1415. }
  1416. // Create the dependence vector from the constraints.
  1417. for (size_t i = 0; i < loops_.size(); ++i) {
  1418. // Don't touch entries for loops that weren't tested.
  1419. if (loop_appeared[i]) {
  1420. auto current_constraint = constraints[i];
  1421. auto& current_distance_entry = (*dv_entry).GetEntries()[i];
  1422. if (auto dependence_distance =
  1423. current_constraint->AsDependenceDistance()) {
  1424. if (auto constant_node =
  1425. dependence_distance->GetDistance()->AsSEConstantNode()) {
  1426. current_distance_entry.dependence_information =
  1427. DistanceEntry::DependenceInformation::DISTANCE;
  1428. current_distance_entry.distance = constant_node->FoldToSingleValue();
  1429. if (current_distance_entry.distance == 0) {
  1430. current_distance_entry.direction = DistanceEntry::Directions::EQ;
  1431. } else if (current_distance_entry.distance < 0) {
  1432. current_distance_entry.direction = DistanceEntry::Directions::GT;
  1433. } else {
  1434. current_distance_entry.direction = DistanceEntry::Directions::LT;
  1435. }
  1436. }
  1437. } else if (auto dependence_point =
  1438. current_constraint->AsDependencePoint()) {
  1439. auto source = dependence_point->GetSource();
  1440. auto destination = dependence_point->GetDestination();
  1441. if (source->AsSEConstantNode() && destination->AsSEConstantNode()) {
  1442. current_distance_entry = DistanceEntry(
  1443. source->AsSEConstantNode()->FoldToSingleValue(),
  1444. destination->AsSEConstantNode()->FoldToSingleValue());
  1445. }
  1446. }
  1447. }
  1448. }
  1449. // Test any remaining MIV subscripts and report independence if found.
  1450. std::vector<bool> results(miv_subscripts.size());
  1451. std::transform(std::begin(miv_subscripts), std::end(miv_subscripts),
  1452. std::begin(results),
  1453. [this](const SubscriptPair& p) { return GCDMIVTest(p); });
  1454. return std::accumulate(std::begin(results), std::end(results), false,
  1455. std::logical_or<bool>{});
  1456. }
  1457. } // namespace opt
  1458. } // namespace spvtools