# HG changeset patch # User Paul Boddie # Date 1313963992 -7200 # Node ID eb806eaca9d5dd27957eb607950340777c1be0f1 # Parent e6bd9da8269264481d10d5f3108e746a715ab0ac Attempted to add support for setting the target of instructions so that the result register can be directly populated. Fixed lambda initialisation by duplicating the temporary instruction yielding the lambda. diff -r e6bd9da82692 -r eb806eaca9d5 micropython/ast.py --- a/micropython/ast.py Sun Aug 21 21:38:56 2011 +0200 +++ b/micropython/ast.py Sun Aug 21 23:59:52 2011 +0200 @@ -824,11 +824,7 @@ else: self.dispatch(compiler.ast.Name("None")) - # NOTE: Cannot guarantee that all active instructions can be set. - #self.set_target("result") - - self.new_op(Transfer(source="working", target="result")) - self.new_op(Transfer(source="working_context", target="result_context")) + self.set_target("result") if self.in_exception_handler: self.new_op(ClearException(target="exception")) diff -r e6bd9da82692 -r eb806eaca9d5 micropython/code.py --- a/micropython/code.py Sun Aug 21 21:38:56 2011 +0200 +++ b/micropython/code.py Sun Aug 21 23:59:52 2011 +0200 @@ -80,11 +80,20 @@ return Block() - def set_block(self, block): + def get_block(self): + + "Return the current block." + + return self.blocks[-1] - "Add the given 'block' to the unit's list of blocks." + def set_block(self, block, preceding=None): - self.optimiser.reset() + """ + Add the given 'block' to the unit's list of blocks, noting any active + value information from 'preceding' blocks on the new block. + """ + + self.optimiser.reset(block, preceding) self.blocks.append(block) def get_loop_blocks(self): diff -r e6bd9da82692 -r eb806eaca9d5 micropython/opt.py --- a/micropython/opt.py Sun Aug 21 21:38:56 2011 +0200 +++ b/micropython/opt.py Sun Aug 21 23:59:52 2011 +0200 @@ -53,9 +53,9 @@ self.active = None - # The instruction providing the active value. + # Instructions providing the active value. - self.active_value = None + self.active_values = set() def get_attribute_store_instructions(self): @@ -75,12 +75,30 @@ None ) - def reset(self): + def reset(self, block=None, blocks=None): + + """ + Reset the optimiser for the given 'block' (or the current block), + clearing the active value instructions if no 'blocks' are given, or + collecting the active instructions from each of the blocks otherwise. + """ + + self.clear_active() + + # Make a new collection of instructions for a new block. - "Reset the optimiser, clearing the active instructions." + if block: + self.active_values = set() + block.set_active_values(self.active_values) + + # Otherwise, clear the collection for an existing block. - self.clear_active_value() - self.clear_active() + else: + self.active_values.clear() + + if blocks: + for b in blocks: + self.active_values.update(b.get_active_values()) def set_new(self, op): @@ -94,13 +112,17 @@ "Set the value-providing active instruction." if isinstance(op, current_value_instructions) and op.target == "working": - self.active_value = op + self.active_values.clear() + self.active_values.add(op) - def clear_active_value(self): + def get_active_value(self): - "Clear the value-providing active instruction." + "Get any single active value or None if none or more than one exist." - self.active_value = None + if len(self.active_values) == 1: + return list(self.active_values)[0] + else: + return None def remove_active_value(self): @@ -109,7 +131,7 @@ if appropriate, but keep a record of the active instruction itself. """ - if self.active_value is self.active: + if self.active in self.active_values: removed = self.active self.translation.remove_op() return removed @@ -120,8 +142,8 @@ "Set the target of the active instruction to 'target'." - if self.active is not None: - self.active.target = target + for expr in self.active_values: + expr.target = target def set_active(self, op): @@ -227,15 +249,13 @@ "Return whether the active instruction provides a constant input." - return self.is_constant_input(self.active_value) - - have_known_target = have_constant_input + return self.get_active_value() and self.is_constant_input(self.get_active_value()) def have_simple_input(self): "Return whether the active instruction provides a simple input." - return self.is_simple_input(self.active_value) + return self.get_active_value() and self.is_simple_input(self.get_active_value()) def have_self_input(self, unit): @@ -244,18 +264,16 @@ given 'unit'. """ - return isinstance(unit, Function) and \ - unit.is_method() and isinstance(self.active_value, LoadName) and \ - self.active_value.attr.name == "self" - - def have_temp_compatible_access(self): + if not (isinstance(unit, Function) and unit.is_method()): + return 0 - """ - Indicate whether the active instruction can be used in place of access - to a temporary variable retaining the result of the last instruction. - """ + expr = self.get_active_value() + return expr and isinstance(expr, LoadName) and expr.attr.name == "self" - return isinstance(self.active_value, (LoadName, LoadTemp, LoadAddress, LoadConst, LoadClass, LoadFunction)) + # Indicate whether the active instruction can be used in place of access + # to a temporary variable retaining the result of the last instruction. + + have_temp_compatible_access = have_simple_input def have_correct_self_for_target(self, context, unit): @@ -299,7 +317,7 @@ """ if self.should_optimise_constant_accessor() and self.have_constant_input(): - value = self.active_value + value = self.get_active_value() # Get the details of the access. @@ -328,8 +346,8 @@ appropriate, get information about the specific initialiser. """ - if self.should_optimise_known_target() and self.have_known_target(): - value = self.active_value + if self.should_optimise_known_target() and self.have_constant_input(): + value = self.get_active_value() target = value.attr.get_value() context = value.attr.get_context() diff -r e6bd9da82692 -r eb806eaca9d5 micropython/program.py --- a/micropython/program.py Sun Aug 21 21:38:56 2011 +0200 +++ b/micropython/program.py Sun Aug 21 23:59:52 2011 +0200 @@ -3,7 +3,7 @@ """ Program code and data representations. -Copyright (C) 2009 Paul Boddie +Copyright (C) 2009, 2011 Paul Boddie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -26,10 +26,17 @@ def __init__(self): self.code = [] self.location = None + self.active_values = set() def __repr__(self): return "Block(%r, location=%r)" % (id(self), self.location) + def set_active_values(self, values): + self.active_values = values + + def get_active_values(self): + return self.active_values + class DataValue: "A representation of a raw program value." diff -r e6bd9da82692 -r eb806eaca9d5 micropython/trans.py --- a/micropython/trans.py Sun Aug 21 21:38:56 2011 +0200 +++ b/micropython/trans.py Sun Aug 21 23:59:52 2011 +0200 @@ -856,7 +856,9 @@ self.new_op(temp) self.new_op(StoreCallable(source="source")) - self.new_op(temp) + # Prevent the above instruction from being modified. + + self.new_op(temp.copy()) #self.discard_temp(temp) else: self.new_op(LoadFunction(fn)) @@ -931,12 +933,7 @@ if not fn.is_lambda(): self.dispatch(compiler.ast.Name("None")) - # NOTE: Cannot guarantee that all active instructions can be set. - #self.set_target("result") - - self.new_op(Transfer(source="working", target="result")) - self.new_op(Transfer(source="working_context", target="result_context")) - + self.set_target("result") self.new_op(Return()) # Make sure that enough frame space is reserved from the start. @@ -1301,6 +1298,7 @@ boolean status. """ + false_block = self.get_block() true_block = self.new_block() end_block = self.new_block() @@ -1311,7 +1309,7 @@ self.set_block(true_block) self.new_op(LoadConst(self.importer.get_predefined_constant("True"))) - self.set_block(end_block) + self.set_block(end_block, [false_block, true_block]) def _visitPrint(self, node, function_name): self._startCallFunc()