# HG changeset patch # User Paul Boddie # Date 1209685639 -7200 # Node ID d06c78713711df12518645c47523f98dde4b3d93 # Parent 3ab797077458571207d5a5ba45d108eca3cacbfc Fixed the binary operator mechanism. Expanded the optimisations, incorporating LoadConst into temporary storage optimisations and adding the optimisation of TestIdentity instructions where one operand is a constant. diff -r 3ab797077458 -r d06c78713711 micropython/ast.py --- a/micropython/ast.py Mon Apr 28 21:19:42 2008 +0200 +++ b/micropython/ast.py Fri May 02 01:47:19 2008 +0200 @@ -48,7 +48,7 @@ "A translated module." - supported_optimisations = ["constant_storage", "known_target", "self_access", "temp_storage"] + supported_optimisations = ["constant_storage", "known_target", "self_access", "temp_storage", "constant_test"] def __init__(self, module, importer, optimisations=None): @@ -541,6 +541,9 @@ def _should_optimise_constant_storage(self): return "constant_storage" in self.optimisations + def _should_optimise_constant_test(self): + return "constant_test" in self.optimisations + def _should_optimise_known_target(self): return "known_target" in self.optimisations @@ -568,7 +571,7 @@ last = self.last_op() # NOTE: Should expand to cover LoadAttr and LoadAttrIndex, but this # NOTE: would require inspection of the stack operands. - return isinstance(last, (LoadName, LoadTemp, LoadAddress)) + return isinstance(last, (LoadName, LoadTemp, LoadAddress, LoadConst)) # Optimisation methods. See the supported_optimisations class attribute. @@ -607,6 +610,24 @@ else: return 0 + def _optimise_constant_test(self, instruction): + + """ + Where this operation tests the topmost stack value which happens to be + a constant against another stack value, merge the last instruction which + loaded the constant into the current 'instruction'. + """ + + if self._should_optimise_constant_test() and \ + instruction is TestIdentity and \ + self._have_constant_input(0): + + last = self.last_op() + self.replace_op(TestIdentityAddress(last.attr)) + return 1 + else: + return 0 + def _optimise_known_target(self): """ @@ -666,12 +687,21 @@ _t1 = node.left _t2 = node.right try: - _t1.__add__(_t2) + _result = _t1.__add__(_t2) + if _result is NotImplemented: + raise AttributeError except AttributeError: - _t2.__radd__(_t1) + try: + _result = _t2.__radd__(_t1) + if _result is NotImplemented: + raise AttributeError + except AttributeError: + raise TypeError """ + end_left_label = self.new_label() right_label = self.new_label() + type_error_label = self.new_label() end_label = self.new_label() # NOTE: Potentially remove the reservation if optimised storage is used. @@ -696,27 +726,73 @@ self._startCallFunc() self.new_op(temp1) + + # Get left method on temp1. + self._generateAttr(node, left_method, (LoadAddress, LoadAttr, LoadAttrIndex)) + self.dispatch(compiler.ast.Name("AttributeError")) + self.new_op(CheckException()) + self.new_op(JumpIfTrue(end_left_label)) + + # Add arguments. + self.new_op(temp1) # Explicit context as first argument. self.new_op(temp2) self._endCallFunc() - self.dispatch(compiler.ast.Name("AttributeError")) - self.new_op(CheckException()) - self.new_op(JumpIfFalse(end_label)) + # Test for NotImplemented. + # Don't actually raise an exception. + + self.dispatch(compiler.ast.Name("NotImplemented")) + if not self._optimise_constant_test(TestIdentity): + self.new_op(TestIdentity()) + self.new_op(JumpIfTrue(right_label)) + self.new_op(Jump(end_label)) + + # End left method attempt. + + self.set_label(end_left_label) + self.new_op(DropFrame()) # From the left method call. # Right method. self.set_label(right_label) self._startCallFunc() self.new_op(temp2) + + # Get right method on temp2. + self._generateAttr(node, right_method, (LoadAddress, LoadAttr, LoadAttrIndex)) + self.dispatch(compiler.ast.Name("AttributeError")) + self.new_op(CheckException()) + self.new_op(JumpIfTrue(type_error_label)) + + # Add arguments. + self.new_op(temp2) # Explicit context as first argument. self.new_op(temp1) self._endCallFunc() + # Test for NotImplemented. + # Don't actually raise an exception. + + self.dispatch(compiler.ast.Name("NotImplemented")) + if not self._optimise_constant_test(TestIdentity): + self.new_op(TestIdentity()) + self.new_op(JumpIfTrue(type_error_label)) + self.new_op(Jump(end_label)) + + # Raise a TypeError. + + self.set_label(type_error_label) + self.dispatch(compiler.ast.Name("TypeError")) + self.new_op(RaiseException()) + self.set_label(end_label) + # Compilation duties... + # NOTE: Potentially remove this when optimised away. + self.discard_temp(2) def visitAdd(self, node): diff -r 3ab797077458 -r d06c78713711 micropython/rsvp.py --- a/micropython/rsvp.py Mon Apr 28 21:19:42 2008 +0200 +++ b/micropython/rsvp.py Fri May 02 01:47:19 2008 +0200 @@ -157,4 +157,9 @@ class Return(Instruction): "Return a value from a subprogram." class CheckException(Instruction): "Check the raised exception against another." +# General instructions. + +class TestIdentity(Instruction): "Test whether the two topmost stack values are identical." +class TestIdentityAddress(Address): "Test whether the topmost stack value is identical to the given address." + # vim: tabstop=4 expandtab shiftwidth=4