1.1 --- a/micropython/ast.py Sat Jul 19 00:39:50 2008 +0200
1.2 +++ b/micropython/ast.py Sat Jul 19 21:26:47 2008 +0200
1.3 @@ -31,10 +31,10 @@
1.4
1.5 "A translated module."
1.6
1.7 - supported_optimisations = ["constant_storage", "known_target", "self_access", "temp_storage", "load_operations"]
1.8 + supported_optimisations = ["constant_storage", "known_target", "self_access", "temp_storage", "load_operations", "unused_results"]
1.9
1.10 attribute_load_instructions = (LoadAddress, LoadAddressContext, LoadAttr, LoadAttrIndex)
1.11 - attribute_store_instructions = (StoreAddress, StoreAddressContext, StoreAttr, StoreAttrIndex)
1.12 + attribute_store_instructions = (StoreAddress, None, StoreAttr, StoreAttrIndex)
1.13
1.14 def __init__(self, module, importer, optimisations=None):
1.15
1.16 @@ -188,6 +188,25 @@
1.17 def drop_exception_labels(self):
1.18 self.exception_labels.pop()
1.19
1.20 + # Assignment expression values.
1.21 +
1.22 + def record_value(self):
1.23 + self.expr_temp = self._optimise_temp_storage()
1.24 +
1.25 + def discard_value(self):
1.26 + self.discard_temp(self.expr_temp)
1.27 + self.expr_temp = None
1.28 +
1.29 + def set_source(self):
1.30 + if self.active is not None:
1.31 + self.active.source = self.expr_temp
1.32 +
1.33 + # Optimise away constant storage if appropriate.
1.34 +
1.35 + self._optimise_constant_storage()
1.36 +
1.37 + # Temporary storage administration.
1.38 +
1.39 def get_temp(self):
1.40
1.41 """
1.42 @@ -214,12 +233,6 @@
1.43
1.44 "Add 'op' to the generated code."
1.45
1.46 - # Optimise away constant storage if appropriate.
1.47 - # The target and value loading operations are also removed.
1.48 -
1.49 - if self._optimise_constant_storage(op):
1.50 - return
1.51 -
1.52 # Optimise load operations employed by this instruction.
1.53
1.54 self._optimise_load_operations(op)
1.55 @@ -267,6 +280,9 @@
1.56 def _should_optimise_load_operations(self):
1.57 return "load_operations" in self.optimisations
1.58
1.59 + def _should_optimise_unused_results(self):
1.60 + return "unused_results" in self.optimisations
1.61 +
1.62 # Simple tests.
1.63
1.64 def _is_constant_input(self, instruction):
1.65 @@ -287,14 +303,23 @@
1.66
1.67 "Return whether 'instruction' provides a simple input."
1.68
1.69 - return isinstance(instruction, (LoadName, LoadTemp, LoadResult, LoadAddress))
1.70 + return isinstance(instruction, (LoadConst, LoadName, LoadTemp, LoadResult, LoadAddress))
1.71
1.72 def _is_simple_input_user(self, instruction):
1.73
1.74 - "Return whether 'instruction' can use simple input."
1.75 + "Return whether 'instruction' can use simple input from the current value."
1.76
1.77 - return isinstance(instruction,
1.78 - (StoreName, StoreTemp, StoreFrame, StoreAddress, RaiseException) + self.attribute_store_instructions)
1.79 + return isinstance(instruction, (
1.80 + StoreTemp, StoreFrame, StoreResult, RaiseException, # as the value being stored
1.81 + LoadAddressContext, LoadAttr, LoadAttrIndex, # as the object being referenced
1.82 + StoreAttr, StoreAttrIndex # as the object being referenced
1.83 + ))
1.84 +
1.85 + def _is_input(self, instruction):
1.86 +
1.87 + "Return whether 'instruction' provides an input."
1.88 +
1.89 + return isinstance(instruction, (LoadConst, LoadName, LoadTemp, LoadResult) + self.attribute_load_instructions)
1.90
1.91 # Convenience tests.
1.92
1.93 @@ -306,12 +331,30 @@
1.94
1.95 _have_known_target = _have_constant_input
1.96
1.97 + def _have_constant_target(self):
1.98 +
1.99 + "Return whether the active instruction provides a constant target."
1.100 +
1.101 + return self._is_constant_target(self.active)
1.102 +
1.103 + def _have_constant_source(self):
1.104 +
1.105 + "Return whether the active instruction has a constant source."
1.106 +
1.107 + return self._is_constant_input(self.active.source)
1.108 +
1.109 def _have_simple_input(self):
1.110
1.111 - "Return whether the active instruction provides a local input."
1.112 + "Return whether the active instruction provides a simple input."
1.113
1.114 return self._is_simple_input(self.active)
1.115
1.116 + def _have_input(self):
1.117 +
1.118 + "Return whether the active instruction provides an input."
1.119 +
1.120 + return self._is_input(self.active)
1.121 +
1.122 def _have_self_input(self):
1.123
1.124 "Return whether the active instruction is a reference to self."
1.125 @@ -331,16 +374,16 @@
1.126
1.127 # Optimisation methods. See the supported_optimisations class attribute.
1.128
1.129 - def _optimise_constant_storage(self, instruction):
1.130 + def _optimise_constant_storage(self):
1.131
1.132 """
1.133 - Where this operation should store a constant into a target which is
1.134 - also constant, optimise away both operations.
1.135 + Where the last operation stores a constant into a target which is also
1.136 + constant, optimise away both operations.
1.137 """
1.138
1.139 if self._should_optimise_constant_storage() and \
1.140 - self._is_constant_target(instruction) and \
1.141 - self._have_constant_input():
1.142 + self._have_constant_target() and \
1.143 + self._have_constant_source():
1.144
1.145 self.remove_op()
1.146 return 1
1.147 @@ -373,7 +416,7 @@
1.148 else:
1.149 return None
1.150
1.151 - def _optimise_self_access(self, attrname, classes):
1.152 + def _optimise_self_access(self, attrname, classes, node):
1.153
1.154 """
1.155 Where the provided 'attrname' accesses an attribute which occupies the
1.156 @@ -398,7 +441,14 @@
1.157 except KeyError:
1.158 attr = self.unit.parent.all_attributes()[attrname]
1.159 new_attr = attr.via_instance()
1.160 - self.new_op(AddressContextInstruction(new_attr))
1.161 +
1.162 + # Only permit loading (not storing) of class attributes via self.
1.163 +
1.164 + if AddressContextInstruction is not None:
1.165 + self.new_op(AddressContextInstruction(new_attr))
1.166 + else:
1.167 + raise TranslateError(self.module.full_name(), node,
1.168 + "Storing of class attribute %r via self not permitted." % attrname)
1.169
1.170 return 1
1.171 else:
1.172 @@ -443,6 +493,13 @@
1.173 self.remove_op()
1.174 instruction.input = last
1.175
1.176 + def _optimise_unused_results(self):
1.177 +
1.178 + "Discard results which will not be used."
1.179 +
1.180 + if self._have_input():
1.181 + self.remove_op()
1.182 +
1.183 # Visitor methods.
1.184
1.185 def default(self, node, *args):
1.186 @@ -518,7 +575,7 @@
1.187 # see if the attribute is acceptably positioned and produce a direct
1.188 # access to the attribute.
1.189
1.190 - elif self._optimise_self_access(attrname, (AddressInstruction, AddressContextInstruction, AttrInstruction)):
1.191 + elif self._optimise_self_access(attrname, (AddressInstruction, AddressContextInstruction, AttrInstruction), node):
1.192 return
1.193
1.194 # Otherwise, perform a normal operation.
1.195 @@ -704,6 +761,7 @@
1.196 else:
1.197 self.dispatch(arg)
1.198 self.new_op(StoreFrame(frame_pos))
1.199 +
1.200 employed_positions.add(frame_pos)
1.201
1.202 # Check to see if the first argument is appropriate (compatible with
1.203 @@ -857,7 +915,7 @@
1.204
1.205 # Get the method on temp.
1.206
1.207 - self._generateAttr(node, method, self.attr_load_instructions)
1.208 + self._generateAttr(node, method, self.attribute_load_instructions)
1.209
1.210 # Add exception handling to the method acquisition instructions where
1.211 # the attribute access cannot be resolved at compile-time.
1.212 @@ -934,7 +992,7 @@
1.213
1.214 # Get left method on temp1.
1.215
1.216 - self._generateAttr(node, left_method, self.attr_load_instructions)
1.217 + self._generateAttr(node, left_method, self.attribute_load_instructions)
1.218
1.219 # Add exception handling to the method acquisition instructions where
1.220 # the attribute access cannot be resolved at compile-time.
1.221 @@ -974,7 +1032,7 @@
1.222
1.223 # Get right method on temp2.
1.224
1.225 - self._generateAttr(node, right_method, self.attr_load_instructions)
1.226 + self._generateAttr(node, right_method, self.attribute_load_instructions)
1.227
1.228 # Add exception handling to the method acquisition instructions where
1.229 # the attribute access cannot be resolved at compile-time.
1.230 @@ -1043,25 +1101,22 @@
1.231
1.232 def visitAssign(self, node):
1.233 self.dispatch(node.expr)
1.234 - self.expr_temp = self._optimise_temp_storage()
1.235 + self.record_value()
1.236
1.237 for n in node.nodes:
1.238 self.dispatch(n)
1.239
1.240 - self.discard_temp(self.expr_temp)
1.241 - self.expr_temp = None
1.242 + self.discard_value()
1.243
1.244 def visitAssAttr(self, node):
1.245 self._visitAttr(node, self.attribute_store_instructions)
1.246 - if self.active is not None:
1.247 - self.active.source = self.expr_temp
1.248 + self.set_source()
1.249
1.250 def visitAssList(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "AssList")
1.251
1.252 def visitAssName(self, node):
1.253 self._visitName(node, (StoreName, StoreAddress))
1.254 - if self.active is not None:
1.255 - self.active.source = self.expr_temp
1.256 + self.set_source()
1.257
1.258 visitAssTuple = visitAssList
1.259
1.260 @@ -1102,7 +1157,10 @@
1.261 # Store the name.
1.262
1.263 self.new_op(LoadConst(node.unit))
1.264 + self.record_value()
1.265 self._visitName(node, (StoreName, StoreAddress))
1.266 + self.set_source()
1.267 + self.discard_value()
1.268
1.269 # Visit the code.
1.270
1.271 @@ -1139,6 +1197,7 @@
1.272
1.273 def visitDiscard(self, node):
1.274 self.dispatch(node.expr)
1.275 + self._optimise_unused_results()
1.276
1.277 def visitDiv(self, node):
1.278 self._visitBinary(node, "__div__", "__rdiv__")
1.279 @@ -1161,7 +1220,7 @@
1.280
1.281 self._startCallFunc()
1.282 self.dispatch(node.list)
1.283 - self._generateAttr(node, "__iter__", self.attr_load_instructions)
1.284 + self._generateAttr(node, "__iter__", self.attribute_load_instructions)
1.285 temp = self._generateCallFunc([], node)
1.286 self._doCallFunc(temp)
1.287 self._endCallFunc(temp)
1.288 @@ -1176,7 +1235,7 @@
1.289
1.290 self._startCallFunc()
1.291 self.new_op(temp_iterator)
1.292 - self._generateAttr(node, "next", self.attr_load_instructions)
1.293 + self._generateAttr(node, "next", self.attribute_load_instructions)
1.294 temp = self._generateCallFunc([], node)
1.295 self._doCallFunc(temp)
1.296 self._endCallFunc(temp)
1.297 @@ -1226,13 +1285,21 @@
1.298
1.299 if self.unit is not node.unit:
1.300 self.new_op(LoadConst(node.unit))
1.301 +
1.302 + self.record_value()
1.303 self._visitName(node, (StoreName, StoreAddress))
1.304 + self.set_source()
1.305 + self.discard_value()
1.306
1.307 # Generate the default initialisation code.
1.308
1.309 for attr, default in zip(node.unit.default_attrs, node.unit.defaults):
1.310 self.dispatch(default)
1.311 +
1.312 + self.record_value()
1.313 self.new_op(StoreAddress(attr))
1.314 + self.set_source()
1.315 + self.discard_value()
1.316
1.317 # Visiting of the code occurs when get_code is invoked on this node.
1.318
1.319 @@ -1240,6 +1307,8 @@
1.320 self.dispatch(node.code)
1.321 if not isinstance(self.last_op(), Return):
1.322 self.dispatch(compiler.ast.Name("None"))
1.323 + self.new_op(StoreResult())
1.324 +
1.325 self.new_op(Return())
1.326
1.327 def visitGenExpr(self, node): raise TranslationNotImplementedError(self.module.full_name(), node, "GenExpr")
1.328 @@ -1377,6 +1446,8 @@
1.329 self.dispatch(node.value)
1.330 else:
1.331 self.dispatch(compiler.ast.Name("None"))
1.332 +
1.333 + self.new_op(StoreResult())
1.334 self.new_op(Return())
1.335
1.336 def visitRightShift(self, node):