spirv_cfg.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. /*
  2. * Copyright 2016-2021 Arm Limited
  3. * SPDX-License-Identifier: Apache-2.0 OR MIT
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. /*
  18. * At your option, you may choose to accept this material under either:
  19. * 1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
  20. * 2. The MIT License, found at <http://opensource.org/licenses/MIT>.
  21. */
  22. #include "spirv_cfg.hpp"
  23. #include "spirv_cross.hpp"
  24. #include <algorithm>
  25. #include <assert.h>
  26. using namespace std;
  27. namespace SPIRV_CROSS_NAMESPACE
  28. {
  29. CFG::CFG(Compiler &compiler_, const SPIRFunction &func_)
  30. : compiler(compiler_)
  31. , func(func_)
  32. {
  33. build_post_order_visit_order();
  34. build_immediate_dominators();
  35. }
  36. uint32_t CFG::find_common_dominator(uint32_t a, uint32_t b) const
  37. {
  38. while (a != b)
  39. {
  40. if (get_visit_order(a) < get_visit_order(b))
  41. a = get_immediate_dominator(a);
  42. else
  43. b = get_immediate_dominator(b);
  44. }
  45. return a;
  46. }
  47. void CFG::build_immediate_dominators()
  48. {
  49. // Traverse the post-order in reverse and build up the immediate dominator tree.
  50. immediate_dominators.clear();
  51. immediate_dominators[func.entry_block] = func.entry_block;
  52. for (auto i = post_order.size(); i; i--)
  53. {
  54. uint32_t block = post_order[i - 1];
  55. auto &pred = preceding_edges[block];
  56. if (pred.empty()) // This is for the entry block, but we've already set up the dominators.
  57. continue;
  58. for (auto &edge : pred)
  59. {
  60. if (immediate_dominators[block])
  61. {
  62. assert(immediate_dominators[edge]);
  63. immediate_dominators[block] = find_common_dominator(immediate_dominators[block], edge);
  64. }
  65. else
  66. immediate_dominators[block] = edge;
  67. }
  68. }
  69. }
  70. bool CFG::is_back_edge(uint32_t to) const
  71. {
  72. // We have a back edge if the visit order is set with the temporary magic value 0.
  73. // Crossing edges will have already been recorded with a visit order.
  74. auto itr = visit_order.find(to);
  75. return itr != end(visit_order) && itr->second.visited_branches && !itr->second.visited_resolve;
  76. }
  77. bool CFG::has_visited_branch(uint32_t to) const
  78. {
  79. auto itr = visit_order.find(to);
  80. return itr != end(visit_order) && itr->second.visited_branches;
  81. }
  82. void CFG::post_order_visit_entry(uint32_t block)
  83. {
  84. visit_stack.push_back(block);
  85. while (!visit_stack.empty())
  86. {
  87. bool keep_iterating;
  88. do
  89. {
  90. // Reverse the order to allow for stack-like behavior and preserves the visit order from recursive algorithm.
  91. // Traverse depth first.
  92. uint32_t to_visit = visit_stack.back();
  93. last_visited_size = visit_stack.size();
  94. post_order_visit_branches(to_visit);
  95. keep_iterating = last_visited_size != visit_stack.size();
  96. if (keep_iterating)
  97. std::reverse(visit_stack.begin() + last_visited_size, visit_stack.end());
  98. } while (keep_iterating);
  99. // We've reached the end of some tree leaf. Resolve the stack.
  100. // Any node which has been visited for real can be popped now.
  101. while (!visit_stack.empty() && visit_order[visit_stack.back()].visited_branches)
  102. {
  103. post_order_visit_resolve(visit_stack.back());
  104. visit_stack.pop_back();
  105. }
  106. }
  107. }
  108. void CFG::visit_branch(uint32_t block_id)
  109. {
  110. // Prune obvious duplicates.
  111. if (std::find(visit_stack.begin() + last_visited_size, visit_stack.end(), block_id) == visit_stack.end() &&
  112. !has_visited_branch(block_id))
  113. {
  114. visit_stack.push_back(block_id);
  115. }
  116. }
  117. void CFG::post_order_visit_branches(uint32_t block_id)
  118. {
  119. auto &block = compiler.get<SPIRBlock>(block_id);
  120. auto &visit = visit_order[block_id];
  121. if (visit.visited_branches)
  122. return;
  123. visit.visited_branches = true;
  124. if (block.merge == SPIRBlock::MergeLoop)
  125. visit_branch(block.merge_block);
  126. else if (block.merge == SPIRBlock::MergeSelection)
  127. visit_branch(block.next_block);
  128. // First visit our branch targets.
  129. switch (block.terminator)
  130. {
  131. case SPIRBlock::Direct:
  132. visit_branch(block.next_block);
  133. break;
  134. case SPIRBlock::Select:
  135. visit_branch(block.true_block);
  136. visit_branch(block.false_block);
  137. break;
  138. case SPIRBlock::MultiSelect:
  139. {
  140. const auto &cases = compiler.get_case_list(block);
  141. for (const auto &target : cases)
  142. visit_branch(target.block);
  143. if (block.default_block)
  144. visit_branch(block.default_block);
  145. break;
  146. }
  147. default:
  148. break;
  149. }
  150. }
  151. void CFG::post_order_visit_resolve(uint32_t block_id)
  152. {
  153. auto &block = compiler.get<SPIRBlock>(block_id);
  154. auto &visit_block = visit_order[block_id];
  155. assert(visit_block.visited_branches);
  156. auto &visited = visit_order[block_id].visited_resolve;
  157. if (visited)
  158. return;
  159. // If this is a loop header, add an implied branch to the merge target.
  160. // This is needed to avoid annoying cases with do { ... } while(false) loops often generated by inliners.
  161. // To the CFG, this is linear control flow, but we risk picking the do/while scope as our dominating block.
  162. // This makes sure that if we are accessing a variable outside the do/while, we choose the loop header as dominator.
  163. // We could use has_visited_forward_edge, but this break code-gen where the merge block is unreachable in the CFG.
  164. // Make a point out of visiting merge target first. This is to make sure that post visit order outside the loop
  165. // is lower than inside the loop, which is going to be key for some traversal algorithms like post-dominance analysis.
  166. // For selection constructs true/false blocks will end up visiting the merge block directly and it works out fine,
  167. // but for loops, only the header might end up actually branching to merge block.
  168. if (block.merge == SPIRBlock::MergeLoop && !is_back_edge(block.merge_block))
  169. add_branch(block_id, block.merge_block);
  170. // First visit our branch targets.
  171. switch (block.terminator)
  172. {
  173. case SPIRBlock::Direct:
  174. if (!is_back_edge(block.next_block))
  175. add_branch(block_id, block.next_block);
  176. break;
  177. case SPIRBlock::Select:
  178. if (!is_back_edge(block.true_block))
  179. add_branch(block_id, block.true_block);
  180. if (!is_back_edge(block.false_block))
  181. add_branch(block_id, block.false_block);
  182. break;
  183. case SPIRBlock::MultiSelect:
  184. {
  185. const auto &cases = compiler.get_case_list(block);
  186. for (const auto &target : cases)
  187. {
  188. if (!is_back_edge(target.block))
  189. add_branch(block_id, target.block);
  190. }
  191. if (block.default_block && !is_back_edge(block.default_block))
  192. add_branch(block_id, block.default_block);
  193. break;
  194. }
  195. default:
  196. break;
  197. }
  198. // If this is a selection merge, add an implied branch to the merge target.
  199. // This is needed to avoid cases where an inner branch dominates the outer branch.
  200. // This can happen if one of the branches exit early, e.g.:
  201. // if (cond) { ...; break; } else { var = 100 } use_var(var);
  202. // We can use the variable without a Phi since there is only one possible parent here.
  203. // However, in this case, we need to hoist out the inner variable to outside the branch.
  204. // Use same strategy as loops.
  205. if (block.merge == SPIRBlock::MergeSelection && !is_back_edge(block.next_block))
  206. {
  207. // If there is only one preceding edge to the merge block and it's not ourselves, we need a fixup.
  208. // Add a fake branch so any dominator in either the if (), or else () block, or a lone case statement
  209. // will be hoisted out to outside the selection merge.
  210. // If size > 1, the variable will be automatically hoisted, so we should not mess with it.
  211. // The exception here is switch blocks, where we can have multiple edges to merge block,
  212. // all coming from same scope, so be more conservative in this case.
  213. // Adding fake branches unconditionally breaks parameter preservation analysis,
  214. // which looks at how variables are accessed through the CFG.
  215. auto pred_itr = preceding_edges.find(block.next_block);
  216. if (pred_itr != end(preceding_edges))
  217. {
  218. auto &pred = pred_itr->second;
  219. auto succ_itr = succeeding_edges.find(block_id);
  220. size_t num_succeeding_edges = 0;
  221. if (succ_itr != end(succeeding_edges))
  222. num_succeeding_edges = succ_itr->second.size();
  223. if (block.terminator == SPIRBlock::MultiSelect && num_succeeding_edges == 1)
  224. {
  225. // Multiple branches can come from the same scope due to "break;", so we need to assume that all branches
  226. // come from same case scope in worst case, even if there are multiple preceding edges.
  227. // If we have more than one succeeding edge from the block header, it should be impossible
  228. // to have a dominator be inside the block.
  229. // Only case this can go wrong is if we have 2 or more edges from block header and
  230. // 2 or more edges to merge block, and still have dominator be inside a case label.
  231. if (!pred.empty())
  232. add_branch(block_id, block.next_block);
  233. }
  234. else
  235. {
  236. if (pred.size() == 1 && *pred.begin() != block_id)
  237. add_branch(block_id, block.next_block);
  238. }
  239. }
  240. else
  241. {
  242. // If the merge block does not have any preceding edges, i.e. unreachable, hallucinate it.
  243. // We're going to do code-gen for it, and domination analysis requires that we have at least one preceding edge.
  244. add_branch(block_id, block.next_block);
  245. }
  246. }
  247. visited = true;
  248. visit_block.order = ++visit_count;
  249. post_order.push_back(block_id);
  250. }
  251. void CFG::build_post_order_visit_order()
  252. {
  253. uint32_t block = func.entry_block;
  254. visit_count = 0;
  255. visit_order.clear();
  256. post_order.clear();
  257. post_order_visit_entry(block);
  258. }
  259. void CFG::add_branch(uint32_t from, uint32_t to)
  260. {
  261. assert(from && to);
  262. const auto add_unique = [](SmallVector<uint32_t> &l, uint32_t value) {
  263. auto itr = find(begin(l), end(l), value);
  264. if (itr == end(l))
  265. l.push_back(value);
  266. };
  267. add_unique(preceding_edges[to], from);
  268. add_unique(succeeding_edges[from], to);
  269. }
  270. uint32_t CFG::find_loop_dominator(uint32_t block_id) const
  271. {
  272. while (block_id != SPIRBlock::NoDominator)
  273. {
  274. auto itr = preceding_edges.find(block_id);
  275. if (itr == end(preceding_edges))
  276. return SPIRBlock::NoDominator;
  277. if (itr->second.empty())
  278. return SPIRBlock::NoDominator;
  279. uint32_t pred_block_id = SPIRBlock::NoDominator;
  280. bool ignore_loop_header = false;
  281. // If we are a merge block, go directly to the header block.
  282. // Only consider a loop dominator if we are branching from inside a block to a loop header.
  283. // NOTE: In the CFG we forced an edge from header to merge block always to support variable scopes properly.
  284. for (auto &pred : itr->second)
  285. {
  286. auto &pred_block = compiler.get<SPIRBlock>(pred);
  287. if (pred_block.merge == SPIRBlock::MergeLoop && pred_block.merge_block == ID(block_id))
  288. {
  289. pred_block_id = pred;
  290. ignore_loop_header = true;
  291. break;
  292. }
  293. else if (pred_block.merge == SPIRBlock::MergeSelection && pred_block.next_block == ID(block_id))
  294. {
  295. pred_block_id = pred;
  296. break;
  297. }
  298. }
  299. // No merge block means we can just pick any edge. Loop headers dominate the inner loop, so any path we
  300. // take will lead there.
  301. if (pred_block_id == SPIRBlock::NoDominator)
  302. pred_block_id = itr->second.front();
  303. block_id = pred_block_id;
  304. if (!ignore_loop_header && block_id)
  305. {
  306. auto &block = compiler.get<SPIRBlock>(block_id);
  307. if (block.merge == SPIRBlock::MergeLoop)
  308. return block_id;
  309. }
  310. }
  311. return block_id;
  312. }
  313. bool CFG::node_terminates_control_flow_in_sub_graph(BlockID from, BlockID to) const
  314. {
  315. // Walk backwards, starting from "to" block.
  316. // Only follow pred edges if they have a 1:1 relationship, or a merge relationship.
  317. // If we cannot find a path to "from", we must assume that to is inside control flow in some way.
  318. auto &from_block = compiler.get<SPIRBlock>(from);
  319. BlockID ignore_block_id = 0;
  320. if (from_block.merge == SPIRBlock::MergeLoop)
  321. ignore_block_id = from_block.merge_block;
  322. while (to != from)
  323. {
  324. auto pred_itr = preceding_edges.find(to);
  325. if (pred_itr == end(preceding_edges))
  326. return false;
  327. DominatorBuilder builder(*this);
  328. for (auto &edge : pred_itr->second)
  329. builder.add_block(edge);
  330. uint32_t dominator = builder.get_dominator();
  331. if (dominator == 0)
  332. return false;
  333. auto &dom = compiler.get<SPIRBlock>(dominator);
  334. bool true_path_ignore = false;
  335. bool false_path_ignore = false;
  336. bool merges_to_nothing = dom.merge == SPIRBlock::MergeNone ||
  337. (dom.merge == SPIRBlock::MergeSelection && dom.next_block &&
  338. compiler.get<SPIRBlock>(dom.next_block).terminator == SPIRBlock::Unreachable) ||
  339. (dom.merge == SPIRBlock::MergeLoop && dom.merge_block &&
  340. compiler.get<SPIRBlock>(dom.merge_block).terminator == SPIRBlock::Unreachable);
  341. if (dom.self == from || merges_to_nothing)
  342. {
  343. // We can only ignore inner branchy paths if there is no merge,
  344. // i.e. no code is generated afterwards. E.g. this allows us to elide continue:
  345. // for (;;) { if (cond) { continue; } else { break; } }.
  346. // Codegen here in SPIR-V will be something like either no merge if one path directly breaks, or
  347. // we merge to Unreachable.
  348. if (ignore_block_id && dom.terminator == SPIRBlock::Select)
  349. {
  350. auto &true_block = compiler.get<SPIRBlock>(dom.true_block);
  351. auto &false_block = compiler.get<SPIRBlock>(dom.false_block);
  352. auto &ignore_block = compiler.get<SPIRBlock>(ignore_block_id);
  353. true_path_ignore = compiler.execution_is_branchless(true_block, ignore_block);
  354. false_path_ignore = compiler.execution_is_branchless(false_block, ignore_block);
  355. }
  356. }
  357. // Cases where we allow traversal. This serves as a proxy for post-dominance in a loop body.
  358. // TODO: Might want to do full post-dominance analysis, but it's a lot of churn for something like this ...
  359. // - We're the merge block of a selection construct. Jump to header.
  360. // - We're the merge block of a loop. Jump to header.
  361. // - Direct branch. Trivial.
  362. // - Allow cases inside a branch if the header cannot merge execution before loop exit.
  363. if ((dom.merge == SPIRBlock::MergeSelection && dom.next_block == to) ||
  364. (dom.merge == SPIRBlock::MergeLoop && dom.merge_block == to) ||
  365. (dom.terminator == SPIRBlock::Direct && dom.next_block == to) ||
  366. (dom.terminator == SPIRBlock::Select && dom.true_block == to && false_path_ignore) ||
  367. (dom.terminator == SPIRBlock::Select && dom.false_block == to && true_path_ignore))
  368. {
  369. // Allow walking selection constructs if the other branch reaches out of a loop construct.
  370. // It cannot be in-scope anymore.
  371. to = dominator;
  372. }
  373. else
  374. return false;
  375. }
  376. return true;
  377. }
  378. DominatorBuilder::DominatorBuilder(const CFG &cfg_)
  379. : cfg(cfg_)
  380. {
  381. }
  382. void DominatorBuilder::add_block(uint32_t block)
  383. {
  384. if (!cfg.get_immediate_dominator(block))
  385. {
  386. // Unreachable block via the CFG, we will never emit this code anyways.
  387. return;
  388. }
  389. if (!dominator)
  390. {
  391. dominator = block;
  392. return;
  393. }
  394. if (block != dominator)
  395. dominator = cfg.find_common_dominator(block, dominator);
  396. }
  397. void DominatorBuilder::lift_continue_block_dominator()
  398. {
  399. // It is possible for a continue block to be the dominator of a variable is only accessed inside the while block of a do-while loop.
  400. // We cannot safely declare variables inside a continue block, so move any variable declared
  401. // in a continue block to the entry block to simplify.
  402. // It makes very little sense for a continue block to ever be a dominator, so fall back to the simplest
  403. // solution.
  404. if (!dominator)
  405. return;
  406. auto &block = cfg.get_compiler().get<SPIRBlock>(dominator);
  407. auto post_order = cfg.get_visit_order(dominator);
  408. // If we are branching to a block with a higher post-order traversal index (continue blocks), we have a problem
  409. // since we cannot create sensible GLSL code for this, fallback to entry block.
  410. bool back_edge_dominator = false;
  411. switch (block.terminator)
  412. {
  413. case SPIRBlock::Direct:
  414. if (cfg.get_visit_order(block.next_block) > post_order)
  415. back_edge_dominator = true;
  416. break;
  417. case SPIRBlock::Select:
  418. if (cfg.get_visit_order(block.true_block) > post_order)
  419. back_edge_dominator = true;
  420. if (cfg.get_visit_order(block.false_block) > post_order)
  421. back_edge_dominator = true;
  422. break;
  423. case SPIRBlock::MultiSelect:
  424. {
  425. auto &cases = cfg.get_compiler().get_case_list(block);
  426. for (auto &target : cases)
  427. {
  428. if (cfg.get_visit_order(target.block) > post_order)
  429. back_edge_dominator = true;
  430. }
  431. if (block.default_block && cfg.get_visit_order(block.default_block) > post_order)
  432. back_edge_dominator = true;
  433. break;
  434. }
  435. default:
  436. break;
  437. }
  438. if (back_edge_dominator)
  439. dominator = cfg.get_function().entry_block;
  440. }
  441. } // namespace SPIRV_CROSS_NAMESPACE