1.1 --- a/micropython/ast.py Sat Sep 10 20:29:30 2011 +0200
1.2 +++ b/micropython/ast.py Sat Sep 10 20:33:52 2011 +0200
1.3 @@ -211,9 +211,6 @@
1.4
1.5 self.set_block(end_block)
1.6
1.7 - # Make a separate instruction to prevent previous temp accesses from
1.8 - # being altered by assign_value.
1.9 -
1.10 temp = LoadTemp(temp_pos)
1.11 self.new_op(temp)
1.12 self.discard_temp(temp)
1.13 @@ -245,9 +242,6 @@
1.14
1.15 self.set_block(end_block)
1.16
1.17 - # Make a separate instruction to prevent previous temp accesses from
1.18 - # being altered by assign_value.
1.19 -
1.20 temp = LoadTemp(temp_pos)
1.21 self.new_op(temp)
1.22 self.discard_temp(temp)
1.23 @@ -301,6 +295,7 @@
1.24 if op_name.startswith("is"):
1.25 self.new_op(temp1)
1.26 self.record_value()
1.27 + self.start_target()
1.28 self.new_op(temp2)
1.29 self.new_op(TestIdentity(target="status"))
1.30 self.assign_value()
1.31 @@ -454,6 +449,7 @@
1.32
1.33 "Assign the assignment expression to the recipient 'node'."
1.34
1.35 + self.start_target()
1.36 self._visitAttr(node, self.optimiser.get_attribute_store_instructions())
1.37 self.assign_value()
1.38
1.39 @@ -493,6 +489,7 @@
1.40 if hasattr(node, "flags") and node.flags == "OP_DELETE":
1.41 raise TranslationNotImplementedError("AssName(OP_DELETE)")
1.42
1.43 + self.start_target()
1.44 self._visitName(node, self.name_store_instructions)
1.45 self.assign_value()
1.46
1.47 @@ -531,6 +528,7 @@
1.48
1.49 self.new_op(LoadClass(node.unit))
1.50 self.record_value()
1.51 + self.start_target()
1.52 self._visitName(node, self.name_store_instructions)
1.53 self.assign_value()
1.54 self.discard_value()
1.55 @@ -559,6 +557,7 @@
1.56
1.57 self.record_value()
1.58
1.59 + self.start_target()
1.60 self._visitName(node, self.name_store_instructions) # AssName equivalent
1.61 self.assign_value()
1.62 self.discard_value()
2.1 --- a/micropython/code.py Sat Sep 10 20:29:30 2011 +0200
2.2 +++ b/micropython/code.py Sat Sep 10 20:33:52 2011 +0200
2.3 @@ -45,6 +45,10 @@
2.4
2.5 self.expr_temp = []
2.6
2.7 + # The start of the current assignment target instructions.
2.8 +
2.9 + self.target_start = None
2.10 +
2.11 # Wiring within the code.
2.12
2.13 self.labels = {}
2.14 @@ -144,50 +148,78 @@
2.15
2.16 self.discard_temp(self.expr_temp.pop())
2.17
2.18 + def start_target(self):
2.19 +
2.20 + """
2.21 + Start recording instructions used to define the target of an assignment.
2.22 + """
2.23 +
2.24 + self.target_start = len(self.blocks[-1])
2.25 +
2.26 + def remove_target_ops(self):
2.27 +
2.28 + "Remove the assignment target instructions."
2.29 +
2.30 + del self.blocks[-1].code[self.target_start:]
2.31 + self.target_start = None
2.32 + self.optimiser.clear_active()
2.33 +
2.34 + def get_target_ops(self):
2.35 +
2.36 + "Return the assignment target instructions."
2.37 +
2.38 + return self.blocks[-1].code[self.target_start:]
2.39 +
2.40 def assign_value(self, expr=None):
2.41
2.42 """
2.43 Set the source of an assignment using 'expr' or the current assignment
2.44 - value. This sets the source register of the current instruction.
2.45 + value. This may set the source register of the current instruction.
2.46 """
2.47
2.48 - if expr is None:
2.49 - expr = self.expr_temp[-1]
2.50 + expr = expr or self.expr_temp[-1]
2.51 +
2.52 + # Optimise away constant storage if appropriate.
2.53
2.54 - # Optimise away constant storage if appropriate.
2.55 -
2.56 - if self.optimiser.optimise_constant_storage(expr):
2.57 - self.remove_op()
2.58 - return
2.59 + if self.optimiser.optimise_constant_storage(expr):
2.60 + self.remove_target_ops()
2.61 + return
2.62
2.63 # Otherwise, insert the assignment source.
2.64
2.65 - if expr is not None:
2.66 - expr_copy = expr.copy()
2.67 - assign_op = self.last_op()
2.68 + expr_copy = expr.copy()
2.69 + assign_ops = self.get_target_ops()
2.70 +
2.71 + if not assign_ops:
2.72 + self.target_start = None
2.73 + return
2.74
2.75 - # Either insert the instruction yielding the value and adjust the
2.76 - # assignment source.
2.77 + assign_op = assign_ops[-1]
2.78
2.79 - expr_copy.target = "source"
2.80 + # Either insert the instruction yielding the value and adjust the
2.81 + # assignment source.
2.82
2.83 - if self.insert_op(-1, expr_copy):
2.84 - assign_op.source = "source"
2.85 - self.update_temp(expr, expr_copy)
2.86 + expr_copy.target = "source"
2.87
2.88 - # (Now, the instruction need not be inserted.)
2.89 + if self.insert_op(-1, expr_copy):
2.90 + assign_op.source = "source"
2.91 + self.update_temp(expr, expr_copy)
2.92
2.93 - # Or transfer the working value to the source register.
2.94 + # (Now, the instruction need not be inserted.)
2.95 +
2.96 + # Or transfer the working value to the source register.
2.97
2.98 - elif assign_op.working == "working":
2.99 - self.insert_op(-1, Transfer(source="working_context", target="source_context"))
2.100 - self.insert_op(-1, Transfer(source="working", target="source"))
2.101 - assign_op.source = "source"
2.102 + elif assign_op.working == "working":
2.103 + self.insert_op(-1, Transfer(source="working_context", target="source_context"))
2.104 + self.insert_op(-1, Transfer(source="working", target="source"))
2.105 + assign_op.source = "source"
2.106
2.107 - # Or let the assignment use the working register.
2.108 + # Or let the assignment use the working register.
2.109
2.110 - else:
2.111 - assign_op.source = "working"
2.112 + else:
2.113 + assign_op.source = "working"
2.114 +
2.115 + self.target_start = None
2.116
2.117 def set_target(self, target):
2.118
2.119 @@ -285,7 +317,11 @@
2.120 if isinstance(instruction, LoadTemp) and instruction.attr is not None:
2.121 temp_position = instruction.attr - self.unit.all_local_usage
2.122 self.free_temp(temp_position)
2.123 - self.optimiser.ignore_active_value()
2.124 +
2.125 + # Prevent any requested active value from generating instructions now
2.126 + # that our interest in it has passed.
2.127 +
2.128 + self.optimiser.ignore_active_value()
2.129
2.130 def free_temp(self, temp_position):
2.131
2.132 @@ -361,6 +397,7 @@
2.133
2.134 op = self.blocks[-1].code.pop()
2.135 self.optimiser.clear_active()
2.136 + return op
2.137
2.138 def replace_op(self, op):
2.139
2.140 @@ -375,8 +412,9 @@
2.141 Replace the value-providing active instruction with 'op' if appropriate.
2.142 """
2.143
2.144 - self.optimiser.remove_active_value()
2.145 + removed = self.optimiser.remove_active_value()
2.146 self.new_op(op)
2.147 + return removed
2.148
2.149 def last_op(self):
2.150
3.1 --- a/micropython/program.py Sat Sep 10 20:29:30 2011 +0200
3.2 +++ b/micropython/program.py Sat Sep 10 20:33:52 2011 +0200
3.3 @@ -43,6 +43,9 @@
3.4 def append(self, op):
3.5 self.code.append(op)
3.6
3.7 + def __len__(self):
3.8 + return len(self.code)
3.9 +
3.10 class DataValue:
3.11
3.12 "A representation of a raw program value."
4.1 --- a/micropython/trans.py Sat Sep 10 20:29:30 2011 +0200
4.2 +++ b/micropython/trans.py Sat Sep 10 20:33:52 2011 +0200
4.3 @@ -190,11 +190,8 @@
4.4 target_plus_name = self.optimiser.optimise_constant_accessor()
4.5
4.6 # Only try and discover the position if the target can be resolved.
4.7 - # Since instances cannot be constants, this involves classes and
4.8 - # modules.
4.9 - # It is acceptable to replace the instruction providing the constant
4.10 - # input because doing so does not lose any input information required by
4.11 - # the replacement instructions.
4.12 + # Since instances cannot be constants in general, this involves classes
4.13 + # and modules, but constants known at compile-time must also be handled.
4.14
4.15 if target_plus_name is not None:
4.16 target, target_name = target_plus_name
4.17 @@ -219,7 +216,20 @@
4.18 # Produce a suitable instruction.
4.19
4.20 if AddressInstruction is not None:
4.21 - self.replace_active_value(AddressInstruction(attr))
4.22 +
4.23 + # Where the target is a constant instance, the constant input
4.24 + # needs to be retained as the context of the resulting
4.25 + # attribute.
4.26 +
4.27 + if isinstance(target, Instance):
4.28 + self.new_op(AddressContextInstruction(attr))
4.29 +
4.30 + # It is acceptable to replace the instruction providing the
4.31 + # constant input because doing so does not lose any input
4.32 + # information required by the replacement instructions.
4.33 +
4.34 + else:
4.35 + self.replace_active_value(AddressInstruction(attr))
4.36 else:
4.37 raise TranslateError("Storing of class or module attribute %r via an object is not permitted." % attrname)
4.38
4.39 @@ -631,6 +641,7 @@
4.40
4.41 self.dispatch(arg.expr)
4.42 self.record_value()
4.43 + self.start_target()
4.44
4.45 # Store the source value using the callable's parameter
4.46 # table information.
4.47 @@ -979,6 +990,7 @@
4.48
4.49 else:
4.50 self.record_value()
4.51 + self.start_target()
4.52 self.new_op(StoreName(fn[parameter]))
4.53 self.assign_value()
4.54 self.discard_value()
4.55 @@ -1011,6 +1023,7 @@
4.56 self.dispatch(default)
4.57
4.58 self.record_value()
4.59 + self.start_target()
4.60 if dynamic:
4.61 self.new_op(temp)
4.62 self.new_op(StoreAttr(attr))
4.63 @@ -1239,6 +1252,8 @@
4.64
4.65 self.make_instance(self.get_builtin_class("list"), 1)
4.66 list_temp = self.get_temp()
4.67 +
4.68 + self.start_target()
4.69 self.new_op(list_temp)
4.70 self.new_op(StoreAttr(Attr(0, None, None))) # _elements is at position 0
4.71 self.assign_value()
4.72 @@ -1267,6 +1282,7 @@
4.73 position 'i' with the given starting 'offset'.
4.74 """
4.75
4.76 + self.start_target()
4.77 self.new_op(temp)
4.78 self.new_op(StoreAttr(Attr(i + offset, None, None)))
4.79 self.assign_value()