advanced.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. from src.statement import Statement as S
  2. def create_variable():
  3. return '$15'
  4. def eliminate_common_subexpressions(block):
  5. """
  6. Common subexpression elimination:
  7. - Traverse through the statements in reverse order.
  8. - If the statement can be possibly be eliminated, walk further collecting
  9. all other occurrences of the expression until one of the arguments is
  10. assigned in a statement, or the start of the block has been reached.
  11. - If one or more occurrences were found, insert the expression with a new
  12. destination address before the last found occurrence and change all
  13. occurrences to a move instruction from that address.
  14. """
  15. found = False
  16. block.reverse_statements()
  17. while not block.end():
  18. s = block.read()
  19. if s.is_arith():
  20. pointer = block.pointer
  21. last = False
  22. new_reg = False
  23. args = s[1:]
  24. # Collect similar statements
  25. while not block.end():
  26. s2 = block.read()
  27. # Stop if one of the arguments is assigned
  28. if len(s2) and s2[0] in args:
  29. break
  30. # Replace a similar expression by a move instruction
  31. if s2.name == s.name and s2[1:] == args:
  32. if not new_reg:
  33. new_reg = create_variable()
  34. block.replace(1, [S('command', 'move', s2[0], new_reg)])
  35. last = block.pointer
  36. # Insert an additional expression with a new destination address
  37. if last:
  38. block.insert(S('command', s.name, [new_reg] + args), last)
  39. found = True
  40. # Reset pointer to and continue from the original statement
  41. block.pointer = pointer
  42. block.reverse_statements()
  43. return found
  44. def to_hex(value):
  45. """Create the hexadecimal string of an integer."""
  46. return '0x%08x' % value
  47. def fold_constants(block):
  48. """
  49. Constant folding:
  50. - An immidiate load defines a register value:
  51. li $reg, XX -> register[$reg] = XX
  52. - Integer variable definition is of the following form:
  53. li $reg, XX -> constants[VAR] = XX
  54. sw $reg, VAR -> register[$reg] = XX
  55. - When a variable is used, the following happens:
  56. lw $reg, VAR -> register[$reg] = constants[VAR]
  57. """
  58. found = False
  59. # Variable values
  60. constants = {}
  61. # Current known values in register
  62. register = {}
  63. while not block.end():
  64. s = block.read()
  65. if not s.is_command():
  66. continue
  67. if s.name == 'li':
  68. # Save value in register
  69. register[s[0]] = int(s[1], 16)
  70. elif s.name == 'move' and s[0] in register:
  71. reg_to, reg_from = s
  72. if reg_from in register:
  73. # Other value is also known, copy its value
  74. register[reg_to] = register[reg_to]
  75. else:
  76. # Other value is unknown, delete the value
  77. del register[reg_to]
  78. elif s.name == 'sw' and s[0] in register:
  79. # Constant variable definition, e.g. 'int a = 1;'
  80. constants[s[1]] = register[s[0]]
  81. elif s.name == 'lw' and s[1] in constants:
  82. # Usage of variable with constant value
  83. register[s[0]] = constants[s[1]]
  84. elif s.name in ['addu', 'subu', 'mult', 'div']:
  85. # Calculation with constants
  86. rd, rs, rt = s
  87. rs_known = rs in register
  88. rt_known = rt in register
  89. if rs_known and rt_known:
  90. # a = 5 -> b = 15
  91. # c = 10
  92. # b = a + c
  93. rs_val = register[rs]
  94. rt_val = register[rt]
  95. if s.name == 'addu':
  96. result = to_hex(rs_val + rt_val)
  97. if s.name == 'subu':
  98. result = to_hex(rs_val - rt_val)
  99. if s.name == 'mult':
  100. result = to_hex(rs_val * rt_val)
  101. if s.name == 'div':
  102. result = to_hex(rs_val / rt_val)
  103. block.replace(1, [S('command', 'li', result)])
  104. register[rd] = result
  105. found = True
  106. elif rt_known:
  107. # c = 10 -> b = a + 10
  108. # b = c + a
  109. s[2] = register[rt]
  110. found = True
  111. elif rs_known and s.name in ['addu', 'mult']:
  112. # a = 10 -> b = c + 10
  113. # b = c + a
  114. s[1] = rt
  115. s[2] = register[rs]
  116. found = True
  117. elif len(s) and s[0] in register:
  118. # Known register is overwritten, remove its value
  119. del register[s[0]]
  120. return found
  121. def copy_propagation(block):
  122. """
  123. Rename values that were copied to there original, so the copy statement
  124. might be useless, allowing it to be removed by dead code elimination.
  125. """
  126. moves_from = []
  127. moves_to = []
  128. while not block.end():
  129. s = block.read()
  130. if len(s) == 3:
  131. print "s[0] = ", s[0]
  132. print "s[1] = ", s[1]
  133. print "s[2] = ", s[2]
  134. if moves_from:
  135. print "fr: ", moves_from
  136. print "to: ", moves_to
  137. if s.is_command('move') and s[0] not in moves_to:
  138. moves_from.append(s[1])
  139. moves_to.append(s[0])
  140. print "Added move to list."
  141. elif s.is_command('move'):
  142. for i in xrange(len(moves_to)):
  143. if moves_to[i] == s[0]:
  144. moves_from[i] = s[1]
  145. elif len(s) == 3 and s[0] in moves_to:
  146. print len(s)
  147. print len(moves_to)
  148. for i in xrange(len(moves_to)):
  149. if moves_to[i] == s[0]:
  150. del moves_to[i]
  151. del moves_from[i]
  152. "Removed move from list."
  153. elif len(s) == 3 and (s[1] in moves_to or s[2] in moves_to):
  154. print "Have to propagate."
  155. for i in xrange(len(moves_to)):
  156. if s[1] == moves_to[i]:
  157. s[1] = moves_from[i]
  158. print "Propagated"
  159. if s[2] == moves_to[i]:
  160. s[2] = moves_from[i]
  161. print "Propagated"
  162. print ""
  163. return False