program.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. from statement import Statement as S, Block
  2. from dataflow import find_basic_blocks, generate_flow_graph
  3. from optimize.redundancies import remove_redundant_jumps, remove_redundancies,\
  4. remove_redundant_branch_jumps
  5. from optimize.advanced import eliminate_common_subexpressions, \
  6. fold_constants, copy_propagation, eliminate_dead_code
  7. from writer import write_statements
  8. import liveness
  9. import reaching_definitions
  10. class Program(Block):
  11. def __len__(self):
  12. """Get the number of statements in the program."""
  13. return len(self.statements) if hasattr(self, 'statements') \
  14. else reduce(lambda a, b: len(a) + len(b), self.blocks, 0)
  15. def get_statements(self, add_block_comments=False):
  16. """Concatenate the statements of all blocks and return the resulting
  17. list."""
  18. if hasattr(self, 'statements'):
  19. return self.statements
  20. # Only add block start and end comments when in debug mode
  21. if add_block_comments and self.debug:
  22. get_id = lambda b: b.bid
  23. statements = []
  24. for b in self.blocks:
  25. message = ' Block %d (%d statements), edges from: %s' \
  26. % (b.bid, len(b), map(get_id, b.edges_from))
  27. if hasattr(b, 'live_in'):
  28. message += ', LIVE_in: %s' % list(b.live_in)
  29. if hasattr(b, 'reach_in'):
  30. message += ', REACH_in: %s' % list(b.reach_in)
  31. statements.append(S('comment', message, block=False))
  32. statements += b.statements
  33. message = ' End of block %d, edges to: %s' \
  34. % (b.bid, map(get_id, b.edges_to))
  35. if hasattr(b, 'live_out'):
  36. message += ', LIVE_out: %s' % list(b.live_out)
  37. if hasattr(b, 'reach_out'):
  38. message += ', REACH_out: %s' % list(b.reach_out)
  39. statements.append(S('comment', message, block=False))
  40. return statements
  41. return reduce(lambda a, b: a + b,
  42. [b.statements for b in self.blocks])
  43. def count_instructions(self):
  44. """Count the number of statements that are commands or labels."""
  45. return len(filter(lambda s: s.is_command() or s.is_label(),
  46. self.get_statements()))
  47. def optimize_global(self):
  48. """Optimize on a global level."""
  49. if not hasattr(self, 'statements'):
  50. self.statements = self.get_statements()
  51. return remove_redundant_jumps(self) \
  52. | remove_redundant_branch_jumps(self)
  53. def optimize_blocks(self):
  54. """Optimize on block level. Keep executing all optimizations until no
  55. more changes occur."""
  56. changed = False
  57. for block in self.blocks:
  58. print 'block iteration'
  59. if remove_redundancies(block) \
  60. | eliminate_common_subexpressions(block) \
  61. | fold_constants(block) \
  62. | copy_propagation(block) \
  63. | eliminate_dead_code(block):
  64. changed = True
  65. return changed
  66. def find_basic_blocks(self):
  67. """Divide the statement list into basic blocks."""
  68. self.blocks = find_basic_blocks(self.statements)
  69. for b in self.blocks:
  70. b.debug = self.debug
  71. # Remove the old statement list, since it will probably change
  72. del self.statements
  73. def perform_dataflow_analysis(self):
  74. """Perform dataflow analysis:
  75. - Divide the statement list into basic blocks
  76. - Generate flow graph
  77. - Create liveness sets: def, use, in, out
  78. - Create reaching definitions sets: gen, kill, in, out"""
  79. self.find_basic_blocks()
  80. generate_flow_graph(self.blocks)
  81. liveness.create_in_out(self.blocks)
  82. reaching_definitions.create_in_out(self.blocks)
  83. def save(self, filename):
  84. """Save the program in the specified file."""
  85. f = open(filename, 'w+')
  86. f.write(write_statements(self.get_statements(True)))
  87. f.close()