cfg_optimization.py 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. """Optimizes and analyzes CFG-IR."""
  2. import modelverse_jit.cfg_ir as cfg_ir
  3. def get_directly_reachable_blocks(block):
  4. """Gets the set of all blocks that can be reached by taking a single branch from the
  5. given block."""
  6. return [branch.block for branch in block.flow.branches()]
  7. def get_reachable_blocks(entry_point):
  8. """Constructs the set of all reachable vertices from the given block."""
  9. # This is a simple O(n^2) algorithm. Maybe a faster algorithm is more appropriate here.
  10. def __add_block_children(block, results):
  11. for child in get_directly_reachable_blocks(block):
  12. if child not in results:
  13. results.add(child)
  14. __add_block_children(child, results)
  15. return results
  16. return __add_block_children(entry_point, set())
  17. def get_all_reachable_blocks(entry_point):
  18. """Constructs the set of all reachable vertices, for every block that is
  19. reachable from the given entry point."""
  20. # This is a simple O(n^3) algorithm. Maybe a faster algorithm is more appropriate here.
  21. results = {}
  22. all_blocks = get_reachable_blocks(entry_point)
  23. results[entry_point] = all_blocks
  24. for block in all_blocks:
  25. if block not in results:
  26. results[block] = get_reachable_blocks(block)
  27. return results
  28. def is_empty_block(block):
  29. """Tests if the given block contains no parameters or definitions."""
  30. return len(block.parameters) == 0 and len(block.definitions) == 0
  31. def optimize_flow(block):
  32. """Optimizes the given block's flow instruction."""
  33. changed = True
  34. while changed:
  35. changed = False
  36. # Select flow with a literal condition can be optimized to a direct jump.
  37. if (isinstance(block.flow, cfg_ir.SelectFlow)
  38. and cfg_ir.is_literal_def(block.flow.condition)):
  39. literal = cfg_ir.get_literal_def_value(block.flow.condition)
  40. block.flow = cfg_ir.JumpFlow(
  41. block.flow.if_branch if literal else block.flow.else_branch)
  42. changed = True
  43. # Jumps to blocks which contain no parameters or definitions can be replaced
  44. # by the target block's flow.
  45. if (isinstance(block.flow, cfg_ir.JumpFlow)
  46. and is_empty_block(block.flow.branch.block)
  47. and block.flow.branch.block is not block):
  48. block.flow = block.flow.branch.block.flow
  49. changed = True
  50. def optimize_graph_flow(entry_point):
  51. """Optimizes all flow instructions in the graph defined by the given entry point."""
  52. all_blocks = set(get_reachable_blocks(entry_point))
  53. all_blocks.add(entry_point)
  54. for block in all_blocks:
  55. optimize_flow(block)
  56. def optimize(entry_point):
  57. """Optimizes the control-flow graph defined by the given entry point."""
  58. optimize_graph_flow(entry_point)