1.1 --- a/micropython/ast.py Fri Aug 01 01:44:02 2008 +0200
1.2 +++ b/micropython/ast.py Sat Aug 02 00:32:48 2008 +0200
1.3 @@ -31,7 +31,9 @@
1.4
1.5 "A translated module."
1.6
1.7 - supported_optimisations = ["constant_storage", "known_target", "self_access", "temp_storage", "load_operations", "unused_results"]
1.8 + supported_optimisations = [
1.9 + "constant_storage", "known_target", "self_access", "temp_storage", "load_operations", "no_operations", "unused_results"
1.10 + ]
1.11
1.12 attribute_load_instructions = (LoadAddress, LoadAddressContext, LoadAttr, LoadAttrIndex)
1.13 attribute_store_instructions = (None, None, StoreAttr, StoreAttrIndex)
1.14 @@ -242,6 +244,8 @@
1.15 # Optimise load operations employed by this instruction.
1.16
1.17 self._optimise_load_operations(op)
1.18 + if self._optimise_away_no_operations(op):
1.19 + return
1.20
1.21 self.code.append(op)
1.22 self.active = op
1.23 @@ -286,6 +290,9 @@
1.24 def _should_optimise_load_operations(self):
1.25 return "load_operations" in self.optimisations
1.26
1.27 + def _should_optimise_away_no_operations(self):
1.28 + return "no_operations" in self.optimisations
1.29 +
1.30 def _should_optimise_unused_results(self):
1.31 return "unused_results" in self.optimisations
1.32
1.33 @@ -321,6 +328,19 @@
1.34 StoreAttr, StoreAttrIndex, StoreCallable # as the object being referenced
1.35 ))
1.36
1.37 + def _is_resultant_no_operation(self, instruction):
1.38 +
1.39 + """
1.40 + Return whether 'instruction' merely stores its input where the input
1.41 + originally came from.
1.42 + """
1.43 +
1.44 + return (
1.45 + isinstance(instruction.input, LoadTemp) and isinstance(instruction, StoreTemp) and
1.46 + instruction.input.attr == instruction.attr) or (
1.47 + isinstance(instruction.input, LoadResult) and isinstance(instruction, StoreResult)
1.48 + )
1.49 +
1.50 def _is_input(self, instruction):
1.51
1.52 "Return whether 'instruction' provides an input."
1.53 @@ -376,7 +396,10 @@
1.54 to a temporary variable retaining the result of the last instruction.
1.55 """
1.56
1.57 - return isinstance(self.active, (LoadName, LoadTemp, LoadAddress, LoadConst, LoadResult))
1.58 + # LoadResult cannot be relied upon, since in general the result register
1.59 + # could be updated since first being referenced.
1.60 +
1.61 + return isinstance(self.active, (LoadName, LoadTemp, LoadAddress, LoadConst))
1.62
1.63 # Optimisation methods. See the supported_optimisations class attribute.
1.64
1.65 @@ -504,6 +527,20 @@
1.66 self.remove_op()
1.67 instruction.input = last
1.68
1.69 + def _optimise_away_no_operations(self, instruction):
1.70 +
1.71 + """
1.72 + Optimise away operations which just store their inputs in the place
1.73 + the inputs originally came from.
1.74 + """
1.75 +
1.76 + if self._should_optimise_away_no_operations() and \
1.77 + self._is_resultant_no_operation(instruction):
1.78 +
1.79 + return 1
1.80 + else:
1.81 + return 0
1.82 +
1.83 def _optimise_unused_results(self):
1.84
1.85 "Discard results which will not be used."
1.86 @@ -886,12 +923,13 @@
1.87 self.new_op(instruction)
1.88 self.new_op(JumpWithFrame())
1.89
1.90 - def _endCallFunc(self, instruction=None):
1.91 + def _endCallFunc(self, instruction=None, load_result=1):
1.92
1.93 "Finish the invocation and tidy up afterwards."
1.94
1.95 self.new_op(DropFrame())
1.96 - self.new_op(LoadResult())
1.97 + if load_result:
1.98 + self.new_op(LoadResult())
1.99
1.100 # Discard any temporary storage instructions.
1.101
1.102 @@ -1019,6 +1057,7 @@
1.103 # NOTE: No support for defaults.
1.104
1.105 self.new_op(temp) # Explicit context as first argument.
1.106 + self.new_op(StoreFrame(0))
1.107 self._doCallFunc(temp_method)
1.108 self._endCallFunc(temp_method)
1.109 self.new_op(Jump(end_label))
1.110 @@ -1068,14 +1107,18 @@
1.111 self.dispatch(node.right)
1.112 temp2 = self._optimise_temp_storage()
1.113
1.114 - self._generateBinary(temp1, temp2, left_method, right_method)
1.115 + self._generateBinary(node, temp1, temp2, left_method, right_method)
1.116 +
1.117 + # Yield the result.
1.118 +
1.119 + self.new_op(LoadResult())
1.120
1.121 # Compilation duties...
1.122
1.123 self.discard_temp(temp1)
1.124 self.discard_temp(temp2)
1.125
1.126 - def _generateBinary(self, temp1, temp2, left_method, right_method):
1.127 + def _generateBinary(self, node, temp1, temp2, left_method, right_method):
1.128
1.129 right_label = self.new_label()
1.130 type_error_label = self.new_label()
1.131 @@ -1083,12 +1126,12 @@
1.132
1.133 # Left method.
1.134
1.135 - self._generateOpMethod(temp1, temp2, left_method, right_label, end_label)
1.136 + self._generateOpMethod(node, temp1, temp2, left_method, right_label, end_label)
1.137
1.138 # Right method.
1.139
1.140 self.set_label(right_label)
1.141 - self._generateOpMethod(temp2, temp1, right_method, type_error_label, end_label)
1.142 + self._generateOpMethod(node, temp2, temp1, right_method, type_error_label, end_label)
1.143
1.144 # Raise a TypeError.
1.145
1.146 @@ -1099,7 +1142,7 @@
1.147
1.148 self.set_label(end_label)
1.149
1.150 - def _generateOpMethod(self, temp1, temp2, method_name, next_method_label, end_label):
1.151 + def _generateOpMethod(self, node, temp1, temp2, method_name, next_method_label, end_label):
1.152
1.153 end_attempt_label = self.new_label()
1.154
1.155 @@ -1124,7 +1167,9 @@
1.156 # NOTE: No support for defaults.
1.157
1.158 self.new_op(temp1) # Explicit context as first argument.
1.159 + self.new_op(StoreFrame(0))
1.160 self.new_op(temp2)
1.161 + self.new_op(StoreFrame(1))
1.162 self._doCallFunc(temp_method)
1.163 self._endCallFunc(temp_method)
1.164
1.165 @@ -1138,7 +1183,7 @@
1.166 # End method attempt.
1.167
1.168 self.set_label(end_attempt_label)
1.169 - self._endCallFunc() # From the left method call.
1.170 + self._endCallFunc(load_result=0) # From the method call.
1.171
1.172 def _visitSequence(self, sequence_type, node):
1.173 self.new_op(MakeObject((sequence_type, len(node.nodes))))
1.174 @@ -1260,24 +1305,29 @@
1.175 self.dispatch(node.expr)
1.176 temp2 = self._optimise_temp_storage()
1.177
1.178 - for op_name, next_node in compare.ops:
1.179 - left_method, right_method = self.comparison_methods[op_name]
1.180 + last_op = node.ops[-1]
1.181 +
1.182 + for op in node.ops:
1.183 + op_name, next_node = op
1.184 + methods = self.comparison_methods[op_name]
1.185
1.186 temp1 = temp2
1.187 self.dispatch(next_node)
1.188 temp2 = self._optimise_temp_storage()
1.189
1.190 if methods is not None:
1.191 + left_method, right_method = methods
1.192
1.193 # Generate method call using evaluated argument and next node.
1.194
1.195 - self._generateBinary(temp1, temp2, left_method, right_method)
1.196 + self._generateBinary(node, temp1, temp2, left_method, right_method)
1.197
1.198 # Test the result and jump to the end label if false.
1.199
1.200 - self.new_op(LoadResult())
1.201 - self.new_op(TestBoolean())
1.202 - self.new_op(JumpIfFalse(end_label))
1.203 + if op is not last_op:
1.204 + self.new_op(LoadResult())
1.205 + self.new_op(TestBoolean())
1.206 + self.new_op(JumpIfFalse(end_label))
1.207
1.208 else:
1.209 # NOTE: Deal with the special operators.
1.210 @@ -1291,6 +1341,8 @@
1.211 self.discard_temp(temp2)
1.212 self.set_label(end_label)
1.213
1.214 + self.new_op(LoadResult())
1.215 +
1.216 def visitConst(self, node):
1.217 const = self.module.constant_values[node.value]
1.218 self.new_op(LoadConst(const))