loop_dependence_helpers.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541
  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 <ostream>
  16. #include <set>
  17. #include <string>
  18. #include <unordered_set>
  19. #include <utility>
  20. #include <vector>
  21. #include "source/opt/basic_block.h"
  22. #include "source/opt/instruction.h"
  23. #include "source/opt/scalar_analysis.h"
  24. #include "source/opt/scalar_analysis_nodes.h"
  25. namespace spvtools {
  26. namespace opt {
  27. bool LoopDependenceAnalysis::IsZIV(
  28. const std::pair<SENode*, SENode*>& subscript_pair) {
  29. return CountInductionVariables(subscript_pair.first, subscript_pair.second) ==
  30. 0;
  31. }
  32. bool LoopDependenceAnalysis::IsSIV(
  33. const std::pair<SENode*, SENode*>& subscript_pair) {
  34. return CountInductionVariables(subscript_pair.first, subscript_pair.second) ==
  35. 1;
  36. }
  37. bool LoopDependenceAnalysis::IsMIV(
  38. const std::pair<SENode*, SENode*>& subscript_pair) {
  39. return CountInductionVariables(subscript_pair.first, subscript_pair.second) >
  40. 1;
  41. }
  42. SENode* LoopDependenceAnalysis::GetLowerBound(const Loop* loop) {
  43. Instruction* cond_inst = loop->GetConditionInst();
  44. if (!cond_inst) {
  45. return nullptr;
  46. }
  47. Instruction* lower_inst = GetOperandDefinition(cond_inst, 0);
  48. switch (cond_inst->opcode()) {
  49. case SpvOpULessThan:
  50. case SpvOpSLessThan:
  51. case SpvOpULessThanEqual:
  52. case SpvOpSLessThanEqual:
  53. case SpvOpUGreaterThan:
  54. case SpvOpSGreaterThan:
  55. case SpvOpUGreaterThanEqual:
  56. case SpvOpSGreaterThanEqual: {
  57. // If we have a phi we are looking at the induction variable. We look
  58. // through the phi to the initial value of the phi upon entering the loop.
  59. if (lower_inst->opcode() == SpvOpPhi) {
  60. lower_inst = GetOperandDefinition(lower_inst, 0);
  61. // We don't handle looking through multiple phis.
  62. if (lower_inst->opcode() == SpvOpPhi) {
  63. return nullptr;
  64. }
  65. }
  66. return scalar_evolution_.SimplifyExpression(
  67. scalar_evolution_.AnalyzeInstruction(lower_inst));
  68. }
  69. default:
  70. return nullptr;
  71. }
  72. }
  73. SENode* LoopDependenceAnalysis::GetUpperBound(const Loop* loop) {
  74. Instruction* cond_inst = loop->GetConditionInst();
  75. if (!cond_inst) {
  76. return nullptr;
  77. }
  78. Instruction* upper_inst = GetOperandDefinition(cond_inst, 1);
  79. switch (cond_inst->opcode()) {
  80. case SpvOpULessThan:
  81. case SpvOpSLessThan: {
  82. // When we have a < condition we must subtract 1 from the analyzed upper
  83. // instruction.
  84. SENode* upper_bound = scalar_evolution_.SimplifyExpression(
  85. scalar_evolution_.CreateSubtraction(
  86. scalar_evolution_.AnalyzeInstruction(upper_inst),
  87. scalar_evolution_.CreateConstant(1)));
  88. return upper_bound;
  89. }
  90. case SpvOpUGreaterThan:
  91. case SpvOpSGreaterThan: {
  92. // When we have a > condition we must add 1 to the analyzed upper
  93. // instruction.
  94. SENode* upper_bound =
  95. scalar_evolution_.SimplifyExpression(scalar_evolution_.CreateAddNode(
  96. scalar_evolution_.AnalyzeInstruction(upper_inst),
  97. scalar_evolution_.CreateConstant(1)));
  98. return upper_bound;
  99. }
  100. case SpvOpULessThanEqual:
  101. case SpvOpSLessThanEqual:
  102. case SpvOpUGreaterThanEqual:
  103. case SpvOpSGreaterThanEqual: {
  104. // We don't need to modify the results of analyzing when we have <= or >=.
  105. SENode* upper_bound = scalar_evolution_.SimplifyExpression(
  106. scalar_evolution_.AnalyzeInstruction(upper_inst));
  107. return upper_bound;
  108. }
  109. default:
  110. return nullptr;
  111. }
  112. }
  113. bool LoopDependenceAnalysis::IsWithinBounds(int64_t value, int64_t bound_one,
  114. int64_t bound_two) {
  115. if (bound_one < bound_two) {
  116. // If |bound_one| is the lower bound.
  117. return (value >= bound_one && value <= bound_two);
  118. } else if (bound_one > bound_two) {
  119. // If |bound_two| is the lower bound.
  120. return (value >= bound_two && value <= bound_one);
  121. } else {
  122. // Both bounds have the same value.
  123. return value == bound_one;
  124. }
  125. }
  126. bool LoopDependenceAnalysis::IsProvablyOutsideOfLoopBounds(
  127. const Loop* loop, SENode* distance, SENode* coefficient) {
  128. // We test to see if we can reduce the coefficient to an integral constant.
  129. SEConstantNode* coefficient_constant = coefficient->AsSEConstantNode();
  130. if (!coefficient_constant) {
  131. PrintDebug(
  132. "IsProvablyOutsideOfLoopBounds could not reduce coefficient to a "
  133. "SEConstantNode so must exit.");
  134. return false;
  135. }
  136. SENode* lower_bound = GetLowerBound(loop);
  137. SENode* upper_bound = GetUpperBound(loop);
  138. if (!lower_bound || !upper_bound) {
  139. PrintDebug(
  140. "IsProvablyOutsideOfLoopBounds could not get both the lower and upper "
  141. "bounds so must exit.");
  142. return false;
  143. }
  144. // If the coefficient is positive we calculate bounds as upper - lower
  145. // If the coefficient is negative we calculate bounds as lower - upper
  146. SENode* bounds = nullptr;
  147. if (coefficient_constant->FoldToSingleValue() >= 0) {
  148. PrintDebug(
  149. "IsProvablyOutsideOfLoopBounds found coefficient >= 0.\n"
  150. "Using bounds as upper - lower.");
  151. bounds = scalar_evolution_.SimplifyExpression(
  152. scalar_evolution_.CreateSubtraction(upper_bound, lower_bound));
  153. } else {
  154. PrintDebug(
  155. "IsProvablyOutsideOfLoopBounds found coefficient < 0.\n"
  156. "Using bounds as lower - upper.");
  157. bounds = scalar_evolution_.SimplifyExpression(
  158. scalar_evolution_.CreateSubtraction(lower_bound, upper_bound));
  159. }
  160. // We can attempt to deal with symbolic cases by subtracting |distance| and
  161. // the bound nodes. If we can subtract, simplify and produce a SEConstantNode
  162. // we can produce some information.
  163. SEConstantNode* distance_minus_bounds =
  164. scalar_evolution_
  165. .SimplifyExpression(
  166. scalar_evolution_.CreateSubtraction(distance, bounds))
  167. ->AsSEConstantNode();
  168. if (distance_minus_bounds) {
  169. PrintDebug(
  170. "IsProvablyOutsideOfLoopBounds found distance - bounds as a "
  171. "SEConstantNode with value " +
  172. ToString(distance_minus_bounds->FoldToSingleValue()));
  173. // If distance - bounds > 0 we prove the distance is outwith the loop
  174. // bounds.
  175. if (distance_minus_bounds->FoldToSingleValue() > 0) {
  176. PrintDebug(
  177. "IsProvablyOutsideOfLoopBounds found distance escaped the loop "
  178. "bounds.");
  179. return true;
  180. }
  181. }
  182. return false;
  183. }
  184. const Loop* LoopDependenceAnalysis::GetLoopForSubscriptPair(
  185. const std::pair<SENode*, SENode*>& subscript_pair) {
  186. // Collect all the SERecurrentNodes.
  187. std::vector<SERecurrentNode*> source_nodes =
  188. std::get<0>(subscript_pair)->CollectRecurrentNodes();
  189. std::vector<SERecurrentNode*> destination_nodes =
  190. std::get<1>(subscript_pair)->CollectRecurrentNodes();
  191. // Collect all the loops stored by the SERecurrentNodes.
  192. std::unordered_set<const Loop*> loops{};
  193. for (auto source_nodes_it = source_nodes.begin();
  194. source_nodes_it != source_nodes.end(); ++source_nodes_it) {
  195. loops.insert((*source_nodes_it)->GetLoop());
  196. }
  197. for (auto destination_nodes_it = destination_nodes.begin();
  198. destination_nodes_it != destination_nodes.end();
  199. ++destination_nodes_it) {
  200. loops.insert((*destination_nodes_it)->GetLoop());
  201. }
  202. // If we didn't find 1 loop |subscript_pair| is a subscript over multiple or 0
  203. // loops. We don't handle this so return nullptr.
  204. if (loops.size() != 1) {
  205. PrintDebug("GetLoopForSubscriptPair found loops.size() != 1.");
  206. return nullptr;
  207. }
  208. return *loops.begin();
  209. }
  210. DistanceEntry* LoopDependenceAnalysis::GetDistanceEntryForLoop(
  211. const Loop* loop, DistanceVector* distance_vector) {
  212. if (!loop) {
  213. return nullptr;
  214. }
  215. DistanceEntry* distance_entry = nullptr;
  216. for (size_t loop_index = 0; loop_index < loops_.size(); ++loop_index) {
  217. if (loop == loops_[loop_index]) {
  218. distance_entry = &(distance_vector->GetEntries()[loop_index]);
  219. break;
  220. }
  221. }
  222. return distance_entry;
  223. }
  224. DistanceEntry* LoopDependenceAnalysis::GetDistanceEntryForSubscriptPair(
  225. const std::pair<SENode*, SENode*>& subscript_pair,
  226. DistanceVector* distance_vector) {
  227. const Loop* loop = GetLoopForSubscriptPair(subscript_pair);
  228. return GetDistanceEntryForLoop(loop, distance_vector);
  229. }
  230. SENode* LoopDependenceAnalysis::GetTripCount(const Loop* loop) {
  231. BasicBlock* condition_block = loop->FindConditionBlock();
  232. if (!condition_block) {
  233. return nullptr;
  234. }
  235. Instruction* induction_instr = loop->FindConditionVariable(condition_block);
  236. if (!induction_instr) {
  237. return nullptr;
  238. }
  239. Instruction* cond_instr = loop->GetConditionInst();
  240. if (!cond_instr) {
  241. return nullptr;
  242. }
  243. size_t iteration_count = 0;
  244. // We have to check the instruction type here. If the condition instruction
  245. // isn't a supported type we can't calculate the trip count.
  246. if (loop->IsSupportedCondition(cond_instr->opcode())) {
  247. if (loop->FindNumberOfIterations(induction_instr, &*condition_block->tail(),
  248. &iteration_count)) {
  249. return scalar_evolution_.CreateConstant(
  250. static_cast<int64_t>(iteration_count));
  251. }
  252. }
  253. return nullptr;
  254. }
  255. SENode* LoopDependenceAnalysis::GetFirstTripInductionNode(const Loop* loop) {
  256. BasicBlock* condition_block = loop->FindConditionBlock();
  257. if (!condition_block) {
  258. return nullptr;
  259. }
  260. Instruction* induction_instr = loop->FindConditionVariable(condition_block);
  261. if (!induction_instr) {
  262. return nullptr;
  263. }
  264. int64_t induction_initial_value = 0;
  265. if (!loop->GetInductionInitValue(induction_instr, &induction_initial_value)) {
  266. return nullptr;
  267. }
  268. SENode* induction_init_SENode = scalar_evolution_.SimplifyExpression(
  269. scalar_evolution_.CreateConstant(induction_initial_value));
  270. return induction_init_SENode;
  271. }
  272. SENode* LoopDependenceAnalysis::GetFinalTripInductionNode(
  273. const Loop* loop, SENode* induction_coefficient) {
  274. SENode* first_trip_induction_node = GetFirstTripInductionNode(loop);
  275. if (!first_trip_induction_node) {
  276. return nullptr;
  277. }
  278. // Get trip_count as GetTripCount - 1
  279. // This is because the induction variable is not stepped on the first
  280. // iteration of the loop
  281. SENode* trip_count =
  282. scalar_evolution_.SimplifyExpression(scalar_evolution_.CreateSubtraction(
  283. GetTripCount(loop), scalar_evolution_.CreateConstant(1)));
  284. // Return first_trip_induction_node + trip_count * induction_coefficient
  285. return scalar_evolution_.SimplifyExpression(scalar_evolution_.CreateAddNode(
  286. first_trip_induction_node,
  287. scalar_evolution_.CreateMultiplyNode(trip_count, induction_coefficient)));
  288. }
  289. std::set<const Loop*> LoopDependenceAnalysis::CollectLoops(
  290. const std::vector<SERecurrentNode*>& recurrent_nodes) {
  291. // We don't handle loops with more than one induction variable. Therefore we
  292. // can identify the number of induction variables by collecting all of the
  293. // loops the collected recurrent nodes belong to.
  294. std::set<const Loop*> loops{};
  295. for (auto recurrent_nodes_it = recurrent_nodes.begin();
  296. recurrent_nodes_it != recurrent_nodes.end(); ++recurrent_nodes_it) {
  297. loops.insert((*recurrent_nodes_it)->GetLoop());
  298. }
  299. return loops;
  300. }
  301. int64_t LoopDependenceAnalysis::CountInductionVariables(SENode* node) {
  302. if (!node) {
  303. return -1;
  304. }
  305. std::vector<SERecurrentNode*> recurrent_nodes = node->CollectRecurrentNodes();
  306. // We don't handle loops with more than one induction variable. Therefore we
  307. // can identify the number of induction variables by collecting all of the
  308. // loops the collected recurrent nodes belong to.
  309. std::set<const Loop*> loops = CollectLoops(recurrent_nodes);
  310. return static_cast<int64_t>(loops.size());
  311. }
  312. std::set<const Loop*> LoopDependenceAnalysis::CollectLoops(
  313. SENode* source, SENode* destination) {
  314. if (!source || !destination) {
  315. return std::set<const Loop*>{};
  316. }
  317. std::vector<SERecurrentNode*> source_nodes = source->CollectRecurrentNodes();
  318. std::vector<SERecurrentNode*> destination_nodes =
  319. destination->CollectRecurrentNodes();
  320. std::set<const Loop*> loops = CollectLoops(source_nodes);
  321. std::set<const Loop*> destination_loops = CollectLoops(destination_nodes);
  322. loops.insert(std::begin(destination_loops), std::end(destination_loops));
  323. return loops;
  324. }
  325. int64_t LoopDependenceAnalysis::CountInductionVariables(SENode* source,
  326. SENode* destination) {
  327. if (!source || !destination) {
  328. return -1;
  329. }
  330. std::set<const Loop*> loops = CollectLoops(source, destination);
  331. return static_cast<int64_t>(loops.size());
  332. }
  333. Instruction* LoopDependenceAnalysis::GetOperandDefinition(
  334. const Instruction* instruction, int id) {
  335. return context_->get_def_use_mgr()->GetDef(
  336. instruction->GetSingleWordInOperand(id));
  337. }
  338. std::vector<Instruction*> LoopDependenceAnalysis::GetSubscripts(
  339. const Instruction* instruction) {
  340. Instruction* access_chain = GetOperandDefinition(instruction, 0);
  341. std::vector<Instruction*> subscripts;
  342. for (auto i = 1u; i < access_chain->NumInOperandWords(); ++i) {
  343. subscripts.push_back(GetOperandDefinition(access_chain, i));
  344. }
  345. return subscripts;
  346. }
  347. SENode* LoopDependenceAnalysis::GetConstantTerm(const Loop* loop,
  348. SERecurrentNode* induction) {
  349. SENode* offset = induction->GetOffset();
  350. SENode* lower_bound = GetLowerBound(loop);
  351. if (!offset || !lower_bound) {
  352. return nullptr;
  353. }
  354. SENode* constant_term = scalar_evolution_.SimplifyExpression(
  355. scalar_evolution_.CreateSubtraction(offset, lower_bound));
  356. return constant_term;
  357. }
  358. bool LoopDependenceAnalysis::CheckSupportedLoops(
  359. std::vector<const Loop*> loops) {
  360. for (auto loop : loops) {
  361. if (!IsSupportedLoop(loop)) {
  362. return false;
  363. }
  364. }
  365. return true;
  366. }
  367. void LoopDependenceAnalysis::MarkUnsusedDistanceEntriesAsIrrelevant(
  368. const Instruction* source, const Instruction* destination,
  369. DistanceVector* distance_vector) {
  370. std::vector<Instruction*> source_subscripts = GetSubscripts(source);
  371. std::vector<Instruction*> destination_subscripts = GetSubscripts(destination);
  372. std::set<const Loop*> used_loops{};
  373. for (Instruction* source_inst : source_subscripts) {
  374. SENode* source_node = scalar_evolution_.SimplifyExpression(
  375. scalar_evolution_.AnalyzeInstruction(source_inst));
  376. std::vector<SERecurrentNode*> recurrent_nodes =
  377. source_node->CollectRecurrentNodes();
  378. for (SERecurrentNode* recurrent_node : recurrent_nodes) {
  379. used_loops.insert(recurrent_node->GetLoop());
  380. }
  381. }
  382. for (Instruction* destination_inst : destination_subscripts) {
  383. SENode* destination_node = scalar_evolution_.SimplifyExpression(
  384. scalar_evolution_.AnalyzeInstruction(destination_inst));
  385. std::vector<SERecurrentNode*> recurrent_nodes =
  386. destination_node->CollectRecurrentNodes();
  387. for (SERecurrentNode* recurrent_node : recurrent_nodes) {
  388. used_loops.insert(recurrent_node->GetLoop());
  389. }
  390. }
  391. for (size_t i = 0; i < loops_.size(); ++i) {
  392. if (used_loops.find(loops_[i]) == used_loops.end()) {
  393. distance_vector->GetEntries()[i].dependence_information =
  394. DistanceEntry::DependenceInformation::IRRELEVANT;
  395. }
  396. }
  397. }
  398. bool LoopDependenceAnalysis::IsSupportedLoop(const Loop* loop) {
  399. std::vector<Instruction*> inductions{};
  400. loop->GetInductionVariables(inductions);
  401. if (inductions.size() != 1) {
  402. return false;
  403. }
  404. Instruction* induction = inductions[0];
  405. SENode* induction_node = scalar_evolution_.SimplifyExpression(
  406. scalar_evolution_.AnalyzeInstruction(induction));
  407. if (!induction_node->AsSERecurrentNode()) {
  408. return false;
  409. }
  410. SENode* induction_step =
  411. induction_node->AsSERecurrentNode()->GetCoefficient();
  412. if (!induction_step->AsSEConstantNode()) {
  413. return false;
  414. }
  415. if (!(induction_step->AsSEConstantNode()->FoldToSingleValue() == 1 ||
  416. induction_step->AsSEConstantNode()->FoldToSingleValue() == -1)) {
  417. return false;
  418. }
  419. return true;
  420. }
  421. void LoopDependenceAnalysis::PrintDebug(std::string debug_msg) {
  422. if (debug_stream_) {
  423. (*debug_stream_) << debug_msg << "\n";
  424. }
  425. }
  426. bool Constraint::operator==(const Constraint& other) const {
  427. // A distance of |d| is equivalent to a line |x - y = -d|
  428. if ((GetType() == ConstraintType::Distance &&
  429. other.GetType() == ConstraintType::Line) ||
  430. (GetType() == ConstraintType::Line &&
  431. other.GetType() == ConstraintType::Distance)) {
  432. auto is_distance = AsDependenceLine() != nullptr;
  433. auto as_distance =
  434. is_distance ? AsDependenceDistance() : other.AsDependenceDistance();
  435. auto distance = as_distance->GetDistance();
  436. auto line = other.AsDependenceLine();
  437. auto scalar_evolution = distance->GetParentAnalysis();
  438. auto neg_distance = scalar_evolution->SimplifyExpression(
  439. scalar_evolution->CreateNegation(distance));
  440. return *scalar_evolution->CreateConstant(1) == *line->GetA() &&
  441. *scalar_evolution->CreateConstant(-1) == *line->GetB() &&
  442. *neg_distance == *line->GetC();
  443. }
  444. if (GetType() != other.GetType()) {
  445. return false;
  446. }
  447. if (AsDependenceDistance()) {
  448. return *AsDependenceDistance()->GetDistance() ==
  449. *other.AsDependenceDistance()->GetDistance();
  450. }
  451. if (AsDependenceLine()) {
  452. auto this_line = AsDependenceLine();
  453. auto other_line = other.AsDependenceLine();
  454. return *this_line->GetA() == *other_line->GetA() &&
  455. *this_line->GetB() == *other_line->GetB() &&
  456. *this_line->GetC() == *other_line->GetC();
  457. }
  458. if (AsDependencePoint()) {
  459. auto this_point = AsDependencePoint();
  460. auto other_point = other.AsDependencePoint();
  461. return *this_point->GetSource() == *other_point->GetSource() &&
  462. *this_point->GetDestination() == *other_point->GetDestination();
  463. }
  464. return true;
  465. }
  466. bool Constraint::operator!=(const Constraint& other) const {
  467. return !(*this == other);
  468. }
  469. } // namespace opt
  470. } // namespace spvtools