# HG changeset patch # User Paul Boddie # Date 1217629968 -7200 # Node ID 1097b1921e565e6897d4916bef5956a314e9357b # Parent 76c0d6737c11a65a86df4c91b523f33df8a43f9f Removed LoadResult from the temporary storage compatible instructions. Added a no-operation optimisation where instructions which are the inverse or complement of their input are skipped. Fixed missing frame population instructions in the operators. Fixed operator invocation generation method signatures. Improved comparison support. diff -r 76c0d6737c11 -r 1097b1921e56 micropython/ast.py --- a/micropython/ast.py Fri Aug 01 01:44:02 2008 +0200 +++ b/micropython/ast.py Sat Aug 02 00:32:48 2008 +0200 @@ -31,7 +31,9 @@ "A translated module." - supported_optimisations = ["constant_storage", "known_target", "self_access", "temp_storage", "load_operations", "unused_results"] + supported_optimisations = [ + "constant_storage", "known_target", "self_access", "temp_storage", "load_operations", "no_operations", "unused_results" + ] attribute_load_instructions = (LoadAddress, LoadAddressContext, LoadAttr, LoadAttrIndex) attribute_store_instructions = (None, None, StoreAttr, StoreAttrIndex) @@ -242,6 +244,8 @@ # Optimise load operations employed by this instruction. self._optimise_load_operations(op) + if self._optimise_away_no_operations(op): + return self.code.append(op) self.active = op @@ -286,6 +290,9 @@ def _should_optimise_load_operations(self): return "load_operations" in self.optimisations + def _should_optimise_away_no_operations(self): + return "no_operations" in self.optimisations + def _should_optimise_unused_results(self): return "unused_results" in self.optimisations @@ -321,6 +328,19 @@ StoreAttr, StoreAttrIndex, StoreCallable # as the object being referenced )) + def _is_resultant_no_operation(self, instruction): + + """ + Return whether 'instruction' merely stores its input where the input + originally came from. + """ + + return ( + isinstance(instruction.input, LoadTemp) and isinstance(instruction, StoreTemp) and + instruction.input.attr == instruction.attr) or ( + isinstance(instruction.input, LoadResult) and isinstance(instruction, StoreResult) + ) + def _is_input(self, instruction): "Return whether 'instruction' provides an input." @@ -376,7 +396,10 @@ to a temporary variable retaining the result of the last instruction. """ - return isinstance(self.active, (LoadName, LoadTemp, LoadAddress, LoadConst, LoadResult)) + # LoadResult cannot be relied upon, since in general the result register + # could be updated since first being referenced. + + return isinstance(self.active, (LoadName, LoadTemp, LoadAddress, LoadConst)) # Optimisation methods. See the supported_optimisations class attribute. @@ -504,6 +527,20 @@ self.remove_op() instruction.input = last + def _optimise_away_no_operations(self, instruction): + + """ + Optimise away operations which just store their inputs in the place + the inputs originally came from. + """ + + if self._should_optimise_away_no_operations() and \ + self._is_resultant_no_operation(instruction): + + return 1 + else: + return 0 + def _optimise_unused_results(self): "Discard results which will not be used." @@ -886,12 +923,13 @@ self.new_op(instruction) self.new_op(JumpWithFrame()) - def _endCallFunc(self, instruction=None): + def _endCallFunc(self, instruction=None, load_result=1): "Finish the invocation and tidy up afterwards." self.new_op(DropFrame()) - self.new_op(LoadResult()) + if load_result: + self.new_op(LoadResult()) # Discard any temporary storage instructions. @@ -1019,6 +1057,7 @@ # NOTE: No support for defaults. self.new_op(temp) # Explicit context as first argument. + self.new_op(StoreFrame(0)) self._doCallFunc(temp_method) self._endCallFunc(temp_method) self.new_op(Jump(end_label)) @@ -1068,14 +1107,18 @@ self.dispatch(node.right) temp2 = self._optimise_temp_storage() - self._generateBinary(temp1, temp2, left_method, right_method) + self._generateBinary(node, temp1, temp2, left_method, right_method) + + # Yield the result. + + self.new_op(LoadResult()) # Compilation duties... self.discard_temp(temp1) self.discard_temp(temp2) - def _generateBinary(self, temp1, temp2, left_method, right_method): + def _generateBinary(self, node, temp1, temp2, left_method, right_method): right_label = self.new_label() type_error_label = self.new_label() @@ -1083,12 +1126,12 @@ # Left method. - self._generateOpMethod(temp1, temp2, left_method, right_label, end_label) + self._generateOpMethod(node, temp1, temp2, left_method, right_label, end_label) # Right method. self.set_label(right_label) - self._generateOpMethod(temp2, temp1, right_method, type_error_label, end_label) + self._generateOpMethod(node, temp2, temp1, right_method, type_error_label, end_label) # Raise a TypeError. @@ -1099,7 +1142,7 @@ self.set_label(end_label) - def _generateOpMethod(self, temp1, temp2, method_name, next_method_label, end_label): + def _generateOpMethod(self, node, temp1, temp2, method_name, next_method_label, end_label): end_attempt_label = self.new_label() @@ -1124,7 +1167,9 @@ # NOTE: No support for defaults. self.new_op(temp1) # Explicit context as first argument. + self.new_op(StoreFrame(0)) self.new_op(temp2) + self.new_op(StoreFrame(1)) self._doCallFunc(temp_method) self._endCallFunc(temp_method) @@ -1138,7 +1183,7 @@ # End method attempt. self.set_label(end_attempt_label) - self._endCallFunc() # From the left method call. + self._endCallFunc(load_result=0) # From the method call. def _visitSequence(self, sequence_type, node): self.new_op(MakeObject((sequence_type, len(node.nodes)))) @@ -1260,24 +1305,29 @@ self.dispatch(node.expr) temp2 = self._optimise_temp_storage() - for op_name, next_node in compare.ops: - left_method, right_method = self.comparison_methods[op_name] + last_op = node.ops[-1] + + for op in node.ops: + op_name, next_node = op + methods = self.comparison_methods[op_name] temp1 = temp2 self.dispatch(next_node) temp2 = self._optimise_temp_storage() if methods is not None: + left_method, right_method = methods # Generate method call using evaluated argument and next node. - self._generateBinary(temp1, temp2, left_method, right_method) + self._generateBinary(node, temp1, temp2, left_method, right_method) # Test the result and jump to the end label if false. - self.new_op(LoadResult()) - self.new_op(TestBoolean()) - self.new_op(JumpIfFalse(end_label)) + if op is not last_op: + self.new_op(LoadResult()) + self.new_op(TestBoolean()) + self.new_op(JumpIfFalse(end_label)) else: # NOTE: Deal with the special operators. @@ -1291,6 +1341,8 @@ self.discard_temp(temp2) self.set_label(end_label) + self.new_op(LoadResult()) + def visitConst(self, node): const = self.module.constant_values[node.value] self.new_op(LoadConst(const))