1.1 --- a/micropython/opt.py Mon Feb 06 19:06:46 2012 +0100
1.2 +++ b/micropython/opt.py Sun Feb 26 19:36:56 2012 +0100
1.3 @@ -52,13 +52,17 @@
1.4 # control-flow operations will flush the "active" instruction.
1.5
1.6 self.active = None
1.7 - self.saved_value_op = None
1.8 - self.saved_value_block = None
1.9 - self.saved_value_pos = None
1.10 +
1.11 + # Information about instructions providing the active values for
1.12 + # registers.
1.13
1.14 - # Instructions providing the active value.
1.15 + self.saved_value_op = {}
1.16 + self.saved_value_block = {}
1.17 + self.saved_value_pos = {}
1.18
1.19 - self.active_values = set()
1.20 + # Sets of instructions providing the active value for each register.
1.21 +
1.22 + self.active_values = {}
1.23
1.24 def get_attribute_store_instructions(self):
1.25
1.26 @@ -86,13 +90,13 @@
1.27 collecting the active instructions from each of the blocks otherwise.
1.28 """
1.29
1.30 - self.store_active_value()
1.31 + self.store_active_values()
1.32 self.clear_active()
1.33
1.34 # Make a new collection of instructions for a new block.
1.35
1.36 if block:
1.37 - self.active_values = set()
1.38 + self.active_values = {}
1.39 block.set_active_values(self.active_values)
1.40
1.41 # Otherwise, clear the collection for an existing block.
1.42 @@ -104,51 +108,77 @@
1.43 for b in blocks:
1.44 self.active_values.update(b.get_active_values())
1.45
1.46 - def set_new(self, op):
1.47 + def set_new(self, register, op):
1.48
1.49 - "Set the latest 'op' as the active instruction."
1.50 + "For 'register', set the latest 'op' as the active instruction."
1.51
1.52 self.set_active(op)
1.53 - self.set_active_value(op)
1.54 + self.set_active_value(register, op)
1.55 +
1.56 + def set_active_value(self, register, op):
1.57 +
1.58 + "For 'register', set 'op' as the value-providing active instruction."
1.59
1.60 - def set_active_value(self, op):
1.61 + # Since the current value provider may eventually be used, it needs to
1.62 + # store its output if appropriate.
1.63
1.64 - "Set the value-providing active instruction."
1.65 + self.store_active_value(register)
1.66 + self.active_values[register] = set([op])
1.67
1.68 - if affects_register(op, "working"):
1.69 - self.store_active_value()
1.70 - self.active_values.clear()
1.71 - self.active_values.add(op)
1.72 + def get_active_value(self, register):
1.73
1.74 - def get_active_value(self):
1.75 + """
1.76 + Get any single active value for the given 'register' or None if none or
1.77 + more than one exist.
1.78 + """
1.79
1.80 - "Get any single active value or None if none or more than one exist."
1.81 + if self.active_values.has_key(register) and \
1.82 + len(self.active_values[register]) == 1:
1.83
1.84 - if len(self.active_values) == 1:
1.85 - return list(self.active_values)[0]
1.86 + return list(self.active_values[register])[0]
1.87 +
1.88 else:
1.89 return None
1.90
1.91 - def remove_active_value(self):
1.92 + def remove_active_value(self, register):
1.93
1.94 """
1.95 - Remove the value-providing active instruction from the generated code,
1.96 - if appropriate, but keep a record of the active instruction itself.
1.97 + Remove the active instruction providing 'register' with its value from
1.98 + the generated code, if appropriate, and return the active instruction.
1.99 """
1.100
1.101 - if self.active in self.active_values:
1.102 + if self.active_values.has_key(register) and \
1.103 + self.active in self.active_values[register]:
1.104 +
1.105 removed = self.translation.remove_op()
1.106 - self.active_values.remove(removed)
1.107 + self.active_values[register].remove(removed)
1.108 return removed
1.109 +
1.110 else:
1.111 return None
1.112
1.113 - def set_target(self, target):
1.114 + def set_target(self, register, target):
1.115 +
1.116 + """
1.117 + Set the target of the active instruction involving 'register' to
1.118 + 'target'.
1.119 + """
1.120 +
1.121 + if self.active_values.has_key(register):
1.122 + for expr in self.active_values[register]:
1.123 + expr.target = target
1.124
1.125 - "Set the target of the active instruction to 'target'."
1.126 + # Transfer the active instructions to their new target.
1.127
1.128 - for expr in self.active_values:
1.129 - expr.target = target
1.130 + if not self.active_values.has_key(target):
1.131 + self.active_values[target] = self.active_values[register]
1.132 + else:
1.133 + self.active_values[target].update(self.active_values[register])
1.134 +
1.135 + # Remove the association between the instructions and the specified
1.136 + # register.
1.137 +
1.138 + del self.active_values[register]
1.139
1.140 def set_active(self, op):
1.141
1.142 @@ -164,33 +194,57 @@
1.143
1.144 # Permit the active value to be requested and restored.
1.145
1.146 - def request_active_value(self, temp, block, pos):
1.147 + def request_active_value(self, register, temp, block, pos):
1.148
1.149 """
1.150 - Request the current active value so that if the value is changed, a
1.151 - temporary storage element or equivalent will be allocated.
1.152 + Request the current active value for 'register' so that if the value is
1.153 + changed, a temporary storage element or equivalent will be allocated.
1.154 """
1.155
1.156 - self.store_active_value()
1.157 - self.saved_value_op = temp
1.158 - self.saved_value_block = block
1.159 - self.saved_value_pos = pos
1.160 + # Cause any previously active value for the register to be saved.
1.161 +
1.162 + self.store_active_value(register)
1.163 +
1.164 + # Redefine the active value for the register.
1.165 +
1.166 + self.saved_value_op[register] = temp
1.167 + self.saved_value_block[register] = block
1.168 + self.saved_value_pos[register] = pos
1.169
1.170 - def store_active_value(self):
1.171 + def store_active_values(self):
1.172 +
1.173 + "Store all active values."
1.174
1.175 - "Store the requested active value"
1.176 + for register in self.active_values.keys():
1.177 + self.store_active_value(register)
1.178 +
1.179 + def store_active_value(self, register):
1.180 +
1.181 + "Store the requested active value for 'register'."
1.182
1.183 - if self.saved_value_op is not None:
1.184 - self.translation.set_temp(self.saved_value_op, self.saved_value_block, self.saved_value_pos)
1.185 - self.ignore_active_value()
1.186 + if self.saved_value_op.has_key(register):
1.187 +
1.188 + # Cause an instruction to be inserted to store the active value for
1.189 + # the register, thus keeping it available for any subsequent usage.
1.190
1.191 - def ignore_active_value(self):
1.192 + self.translation.set_temp(
1.193 + self.saved_value_op[register], # cause the storage of the value
1.194 + self.saved_value_block[register], # in the appropriate block
1.195 + self.saved_value_pos[register] # at the appropriate location
1.196 + )
1.197
1.198 - "Ignore the active value."
1.199 + # Discard the existing active value information.
1.200 +
1.201 + self.ignore_active_value(register)
1.202 +
1.203 + def ignore_active_value(self, register):
1.204
1.205 - self.saved_value_op = None
1.206 - self.saved_value_block = None
1.207 - self.saved_value_pos = None
1.208 + "Ignore the active value in 'register'."
1.209 +
1.210 + if self.saved_value_op.has_key(register):
1.211 + del self.saved_value_op[register]
1.212 + del self.saved_value_block[register]
1.213 + del self.saved_value_pos[register]
1.214
1.215 # Optimisation tests.
1.216
1.217 @@ -290,13 +344,13 @@
1.218
1.219 "Return whether the active instruction provides a constant input."
1.220
1.221 - return self.get_active_value() and self.is_constant_input(self.get_active_value())
1.222 + return self.get_active_value("working") and self.is_constant_input(self.get_active_value("working"))
1.223
1.224 def have_simple_input(self):
1.225
1.226 "Return whether the active instruction provides a simple input."
1.227
1.228 - return self.get_active_value() and self.is_simple_input(self.get_active_value())
1.229 + return self.get_active_value("working") and self.is_simple_input(self.get_active_value("working"))
1.230
1.231 # Indicate whether the active instruction can be used in place of access
1.232 # to a temporary variable retaining the result of the last instruction.
1.233 @@ -313,7 +367,7 @@
1.234 if not (isinstance(unit, Function) and unit.is_method()):
1.235 return 0
1.236
1.237 - expr = self.get_active_value()
1.238 + expr = self.get_active_value("working")
1.239 return expr and isinstance(expr, LoadName) and expr.attr.name == "self"
1.240
1.241 def have_correct_self_for_target(self, context, unit):
1.242 @@ -358,7 +412,7 @@
1.243 """
1.244
1.245 if self.should_optimise_constant_accessor() and self.have_constant_input():
1.246 - value = self.get_active_value()
1.247 + value = self.get_active_value("working")
1.248
1.249 # Get the details of the access.
1.250
1.251 @@ -388,7 +442,7 @@
1.252 """
1.253
1.254 if self.should_optimise_known_target() and self.have_constant_input():
1.255 - value = self.get_active_value()
1.256 + value = self.get_active_value("working")
1.257 target = value.attr.get_value()
1.258 context = value.attr.get_context()
1.259
1.260 @@ -434,7 +488,7 @@
1.261
1.262 # Remove the active value contributor if possible.
1.263
1.264 - removed = self.remove_active_value()
1.265 + removed = self.remove_active_value("working")
1.266 if removed is not None:
1.267
1.268 # Extend the lifetime of any temporary storage location.
1.269 @@ -445,12 +499,12 @@
1.270 # Otherwise, just leave it in place, but return the instruction.
1.271
1.272 else:
1.273 - return self.get_active_value()
1.274 + return self.get_active_value("working")
1.275
1.276 # Or provisional temporary instructions.
1.277
1.278 - elif self.saved_value_op is not None:
1.279 - return self.saved_value_op
1.280 + elif self.saved_value_op.has_key("working"):
1.281 + return self.saved_value_op["working"]
1.282
1.283 return self.translation.get_temp()
1.284
1.285 @@ -469,7 +523,7 @@
1.286 "Discard results which will not be used."
1.287
1.288 if self.should_optimise_unused_results() and self.have_simple_input():
1.289 - self.remove_active_value()
1.290 + self.remove_active_value("working")
1.291
1.292 def optimise_unused_handlers(self, instruction):
1.293