program.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  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, propagate_copies, eliminate_dead_code
  7. import liveness
  8. import reaching_definitions
  9. import copy_propagation
  10. from writer import write_statements
  11. class Program(Block):
  12. def __len__(self):
  13. """Get the number of statements in the program."""
  14. return len(self.statements) if hasattr(self, 'statements') \
  15. else reduce(lambda a, b: len(a) + len(b), self.blocks, 0)
  16. def get_statements(self, add_block_comments=False):
  17. """Concatenate the statements of all blocks and return the resulting
  18. list."""
  19. if hasattr(self, 'statements'):
  20. return self.statements
  21. # Only add block start and end comments when in verbose mode
  22. if add_block_comments and self.verbose:
  23. get_id = lambda b: b.bid
  24. statements = []
  25. for b in self.blocks:
  26. message = ' Block %d (%d statements), edges from: %s' \
  27. % (b.bid, len(b), map(get_id, b.edges_from))
  28. if hasattr(b, 'copy_in'):
  29. message += ', COPY_in: %s' % list(b.copy_in)
  30. if hasattr(b, 'live_in'):
  31. message += ', LIVE_in: %s' % list(b.live_in)
  32. if hasattr(b, 'reach_in'):
  33. message += ', REACH_in: %s' % list(b.reach_in)
  34. statements.append(S('comment', message, block=False))
  35. statements += b.statements
  36. message = ' End of block %d, edges to: %s' \
  37. % (b.bid, map(get_id, b.edges_to))
  38. if hasattr(b, 'copy_out'):
  39. message += ', COPY_out: %s' % list(b.copy_out)
  40. if hasattr(b, 'live_out'):
  41. message += ', LIVE_out: %s' % list(b.live_out)
  42. if hasattr(b, 'reach_out'):
  43. message += ', REACH_out: %s' % list(b.reach_out)
  44. statements.append(S('comment', message, block=False))
  45. return statements
  46. return reduce(lambda a, b: a + b,
  47. [b.statements for b in self.blocks])
  48. def count_instructions(self):
  49. """Count the number of statements that are commands or labels."""
  50. return len(filter(lambda s: s.is_command() or s.is_label(),
  51. self.get_statements()))
  52. def optimize_global(self):
  53. """Optimize on a global level."""
  54. changed = False
  55. if not hasattr(self, 'statements'):
  56. self.statements = self.get_statements()
  57. if remove_redundant_jumps(self):
  58. changed = True
  59. if remove_redundant_branch_jumps(self):
  60. changed = True
  61. return changed
  62. def optimize_blocks(self):
  63. """Optimize on block level. Keep executing all optimizations until no
  64. more changes occur."""
  65. changed = False
  66. for block in self.blocks:
  67. if remove_redundancies(block):
  68. changed = True
  69. if eliminate_common_subexpressions(block):
  70. changed = True
  71. if fold_constants(block):
  72. changed = True
  73. if propagate_copies(block):
  74. changed = True
  75. if eliminate_dead_code(block):
  76. changed = True
  77. return changed
  78. def find_basic_blocks(self):
  79. """Divide the statement list into basic blocks."""
  80. self.blocks = find_basic_blocks(self.statements)
  81. for b in self.blocks:
  82. b.verbose = self.verbose
  83. del self.statements
  84. def perform_dataflow_analysis(self):
  85. """Perform dataflow analysis:
  86. - Divide the statement list into basic blocks
  87. - Generate flow graph
  88. - Create liveness sets: def, use, in, out
  89. - Create reaching definitions sets: gen, kill, in, out"""
  90. self.find_basic_blocks()
  91. generate_flow_graph(self.blocks)
  92. liveness.create_in_out(self.blocks)
  93. reaching_definitions.create_in_out(self.blocks)
  94. copy_propagation.create_in_out(self.blocks)
  95. def save(self, filename):
  96. """Save the program in the specified file."""
  97. f = open(filename, 'w+')
  98. f.write(write_statements(self.get_statements(True),
  99. verbose=self.verbose))
  100. f.close()
  101. def optimize(self):
  102. """Optimization wrapper function, calls global and basic-block level
  103. optimization functions."""
  104. # Remember original number of statements
  105. o = self.count_instructions()
  106. changed = True
  107. iterations = 0
  108. while changed:
  109. iterations += 1
  110. if self.verbose > 1:
  111. print 'main iteration %d', iterations
  112. changed = False
  113. # Optimize on a global level
  114. if self.optimize_global():
  115. if self.verbose > 1:
  116. print 'changed on global level'
  117. changed = True
  118. # Perform dataflow analysis on new blocks
  119. self.perform_dataflow_analysis()
  120. # Optimize basic blocks
  121. if self.optimize_blocks():
  122. if self.verbose > 1:
  123. print 'changed on block level'
  124. changed = True
  125. # Count number of instructions after optimization
  126. b = self.count_instructions()
  127. # Print results
  128. if self.verbose:
  129. print 'Original statements: %d' % o
  130. print 'Statements removed: %d (%d%%)' \
  131. % (o - b, int((o - b) / float(b) * 100))