loop_dependence_helpers.cpp 18 KB

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