CFGBuildingPass.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. /*
  2. * Copyright (c) 2023, Dan Klishch <danilklishch@gmail.com>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include "Compiler/Passes/CFGBuildingPass.h"
  7. #include "AST/AST.h"
  8. #include "Function.h"
  9. namespace JSSpecCompiler {
  10. void CFGBuildingPass::process_function()
  11. {
  12. m_cfg = m_function->m_cfg = make_ref_counted<ControlFlowGraph>();
  13. m_current_block = m_cfg->start_block = create_empty_block();
  14. m_cfg->end_block = create_empty_block();
  15. m_cfg->end_block->m_continuation = make_ref_counted<ControlFlowFunctionReturn>(
  16. make_ref_counted<Variable>(m_function->m_return_value));
  17. m_is_expression_stack = { false };
  18. run_in_subtree(m_function->m_ast);
  19. // FIXME: What should we do if control flow reached the end of the function? Returning
  20. // error_tree will 100% confuse future passes.
  21. m_current_block->m_expressions.append(make_ref_counted<BinaryOperation>(
  22. BinaryOperator::Assignment,
  23. make_ref_counted<Variable>(m_function->m_return_value),
  24. error_tree));
  25. m_current_block->m_continuation = make_ref_counted<ControlFlowJump>(m_cfg->end_block);
  26. }
  27. RecursionDecision CFGBuildingPass::on_entry(Tree tree)
  28. {
  29. m_is_expression_stack.append(!as<Expression>(tree).is_null());
  30. if (auto if_else_if_chain = as<IfElseIfChain>(tree); if_else_if_chain) {
  31. auto* end_block = create_empty_block();
  32. for (size_t i = 0; i < if_else_if_chain->branches_count(); ++i) {
  33. auto current_condition = if_else_if_chain->m_conditions[i];
  34. run_in_subtree(current_condition);
  35. will_be_used_as_expression(current_condition);
  36. auto* condition_block = exchange_current_with_empty();
  37. auto* branch_entry = m_current_block;
  38. run_in_subtree(if_else_if_chain->m_branches[i]);
  39. auto* branch_return = exchange_current_with_empty();
  40. branch_return->m_continuation = make_ref_counted<ControlFlowJump>(end_block);
  41. condition_block->m_continuation = make_ref_counted<ControlFlowBranch>(current_condition, branch_entry, m_current_block);
  42. }
  43. if (if_else_if_chain->m_else_branch)
  44. run_in_const_subtree(if_else_if_chain->m_else_branch);
  45. m_current_block->m_continuation = make_ref_counted<ControlFlowJump>(end_block);
  46. m_current_block = end_block;
  47. return RecursionDecision::Continue;
  48. }
  49. if (auto return_node = as<ReturnNode>(tree); return_node) {
  50. Tree return_assignment = make_ref_counted<BinaryOperation>(
  51. BinaryOperator::Assignment,
  52. make_ref_counted<Variable>(m_function->m_return_value),
  53. return_node->m_return_value);
  54. run_in_subtree(return_assignment);
  55. auto* return_block = exchange_current_with_empty();
  56. return_block->m_continuation = make_ref_counted<ControlFlowJump>(m_cfg->end_block);
  57. return RecursionDecision::Continue;
  58. }
  59. return RecursionDecision::Recurse;
  60. }
  61. void CFGBuildingPass::on_leave(Tree tree)
  62. {
  63. (void)m_is_expression_stack.take_last();
  64. if (!m_is_expression_stack.last() && as<Expression>(tree))
  65. m_current_block->m_expressions.append(tree);
  66. }
  67. BasicBlockRef CFGBuildingPass::create_empty_block()
  68. {
  69. m_cfg->blocks.append(make_ref_counted<BasicBlock>(m_cfg->blocks_count(), invalid_continuation));
  70. return m_cfg->blocks.last();
  71. }
  72. BasicBlockRef CFGBuildingPass::exchange_current_with_empty()
  73. {
  74. auto* new_block = create_empty_block();
  75. swap(new_block, m_current_block);
  76. return new_block;
  77. }
  78. void CFGBuildingPass::will_be_used_as_expression(Tree const& tree)
  79. {
  80. if (m_current_block->m_expressions.is_empty())
  81. VERIFY(is<Statement>(tree.ptr()));
  82. else
  83. VERIFY(m_current_block->m_expressions.take_last() == tree);
  84. }
  85. }