1.1 --- a/micropython/__init__.py Mon Jun 09 21:09:37 2008 +0200
1.2 +++ b/micropython/__init__.py Mon Jun 16 01:56:46 2008 +0200
1.3 @@ -77,6 +77,11 @@
1.4 self.constant_values = {}
1.5 self.constant_list = None # cache for constants
1.6
1.7 + # Main program information.
1.8 +
1.9 + self.code = None
1.10 + self.code_location = None
1.11 +
1.12 def constants(self):
1.13
1.14 "Return a list of constants."
1.15 @@ -210,6 +215,8 @@
1.16 image += code
1.17 pos += len(code)
1.18
1.19 + self.code = image
1.20 + self.code_location = self.modules["__main__"].code_location
1.21 return image
1.22
1.23 def get_object_table(self):
2.1 --- a/micropython/ast.py Mon Jun 09 21:09:37 2008 +0200
2.2 +++ b/micropython/ast.py Mon Jun 16 01:56:46 2008 +0200
2.3 @@ -31,7 +31,7 @@
2.4
2.5 "A translated module."
2.6
2.7 - supported_optimisations = ["constant_storage", "known_target", "self_access", "temp_storage", "constant_test"]
2.8 + supported_optimisations = ["constant_storage", "known_target", "self_access", "temp_storage", "constant_test", "stack_access"]
2.9
2.10 def __init__(self, module, importer, optimisations=None):
2.11
2.12 @@ -68,16 +68,25 @@
2.13 self.exception_labels = []
2.14
2.15 # The code itself. This is limited to the code for a particular block
2.16 - # being processed.
2.17 + # being processed. Also retained is information about temporary values
2.18 + # and the presumed state of the value stack.
2.19
2.20 self.code = None
2.21 self.temp_position = 0
2.22 + self.stack = []
2.23
2.24 def calculate_stack_usage(self):
2.25 max_stack_usage = 0
2.26 stack_usage = 0
2.27
2.28 for op in self.code:
2.29 +
2.30 + # Fix stack access operands.
2.31 +
2.32 + op.fix_stack(stack_usage)
2.33 +
2.34 + # Update the stack levels.
2.35 +
2.36 stack_usage += op.stack_usage
2.37 max_stack_usage = max(max_stack_usage, stack_usage)
2.38
2.39 @@ -90,6 +99,7 @@
2.40 self.unit = self.module
2.41 self.code = []
2.42 self.temp_position = self.unit.stack_local_usage
2.43 + self.stack = []
2.44
2.45 if self.module.module is not None:
2.46 self.dispatch(self.module.module)
2.47 @@ -104,6 +114,7 @@
2.48 self.unit = unit
2.49 self.code = []
2.50 self.temp_position = self.unit.stack_local_usage
2.51 + self.stack = []
2.52
2.53 if unit.astnode is not None:
2.54 self.dispatch(unit.astnode)
2.55 @@ -176,25 +187,69 @@
2.56
2.57 "Add 'op' to the generated code."
2.58
2.59 + position = len(self.code)
2.60 + self._optimise_stack_access(op)
2.61 +
2.62 + if isinstance(op, ResetStack):
2.63 + if not self.stack:
2.64 + return
2.65 + self.stack = []
2.66 +
2.67 self.code.append(op)
2.68
2.69 + if op.stack_usage == 1:
2.70 + self.stack.append((position, op))
2.71 + elif op.stack_usage == -1:
2.72 + for operand in op.operands:
2.73 + if isinstance(operand, StackLoad):
2.74 + self.stack.pop()
2.75 +
2.76 def new_ops(self, ops):
2.77
2.78 "Add 'ops' to the generated code."
2.79
2.80 - self.code += ops
2.81 + for op in ops:
2.82 + self.new_op(op)
2.83
2.84 def replace_op(self, op):
2.85
2.86 "Replace the last added instruction with 'op'."
2.87
2.88 - self.code[-1] = op
2.89 + self.remove_ops(1)
2.90 + self.new_op(op)
2.91 +
2.92 + def remove_op_using_stack(self):
2.93 +
2.94 + "Remove the instruction which created the top stack position."
2.95 +
2.96 + position, op = self.stack.pop()
2.97 +
2.98 + # NOTE: For now, just erase the instruction.
2.99 +
2.100 + self.code[position] = None
2.101 +
2.102 + op = self.code[-1]
2.103 + while op is None:
2.104 + del self.code[-1]
2.105 + if self.code:
2.106 + op = self.code[-1]
2.107 + else:
2.108 + break
2.109
2.110 def remove_ops(self, n):
2.111
2.112 "Remove the last 'n' instructions."
2.113
2.114 - del self.code[-n:]
2.115 + for i in range(0, n):
2.116 + op = self.code.pop()
2.117 + if op.stack_usage == 1:
2.118 + self.stack.pop()
2.119 + elif op.stack_usage < 0:
2.120 + for operand in op.operands:
2.121 + if isinstance(operand, StackLoad):
2.122 + raise ProcessingError, "Cannot remove instructions which reduce the stack."
2.123 + elif isinstance(op, ResetStack):
2.124 + raise ProcessingError, "Cannot remove instructions which reduce the stack."
2.125
2.126 def last_ops(self, n):
2.127
2.128 @@ -629,6 +684,9 @@
2.129 def _should_optimise_temp_storage(self):
2.130 return "temp_storage" in self.optimisations
2.131
2.132 + def _should_optimise_stack_access(self):
2.133 + return "stack_access" in self.optimisations
2.134 +
2.135 def _have_constant_input(self, n):
2.136 last = self.last_ops(n+1)
2.137 return len(last) > n and (isinstance(last[n], LoadAddress) and last[n].attr.assignments == 1 or
2.138 @@ -649,6 +707,15 @@
2.139 # NOTE: would require inspection of the stack operands.
2.140 return isinstance(last, (LoadName, LoadTemp, LoadAddress, LoadConst))
2.141
2.142 + def _have_fixed_sources(self, access):
2.143 + access_ops = []
2.144 + for i in xrange(0, access):
2.145 + position, op = self.stack[-1 - i]
2.146 + if not isinstance(op, (LoadName, LoadTemp, LoadAddress, LoadConst)):
2.147 + return 0
2.148 + access_ops.append(op)
2.149 + return access_ops
2.150 +
2.151 # Optimisation methods. See the supported_optimisations class attribute.
2.152
2.153 def _optimise_temp_storage(self):
2.154 @@ -768,6 +835,15 @@
2.155 else:
2.156 return 0
2.157
2.158 + def _optimise_stack_access(self, instruction):
2.159 + if self._should_optimise_stack_access():
2.160 + ops = self._have_fixed_sources(instruction.stack_access)
2.161 + if ops:
2.162 + #print "Optimised", instruction.operands, "->", ops
2.163 + for i in range(0, instruction.stack_access):
2.164 + self.remove_op_using_stack()
2.165 + instruction.operands = ops
2.166 +
2.167 # Visitor methods.
2.168
2.169 def default(self, node, *args):
2.170 @@ -1059,7 +1135,7 @@
2.171
2.172 def visitDiscard(self, node):
2.173 self.dispatch(node.expr)
2.174 - self.new_op(Pop())
2.175 + self.new_op(ResetStack())
2.176
2.177 def visitDiv(self, node):
2.178 self._visitBinary(node, "__div__", "__rdiv__")
2.179 @@ -1132,7 +1208,7 @@
2.180 # Pop the iterator.
2.181
2.182 self.set_label(exit_label)
2.183 - self.new_op(Pop())
2.184 + self.new_op(ResetStack())
2.185
2.186 def visitFrom(self, node): pass
2.187
3.1 --- a/micropython/rsvp.py Mon Jun 09 21:09:37 2008 +0200
3.2 +++ b/micropython/rsvp.py Mon Jun 16 01:56:46 2008 +0200
3.3 @@ -42,22 +42,31 @@
3.4 "A generic instruction."
3.5
3.6 stack_usage = 0
3.7 + stack_access = 0
3.8
3.9 def __init__(self, attr=None):
3.10 self.attr = attr
3.11 + self.operands = [StackLoad(-1 - n) for n in range(0, self.stack_access)]
3.12 +
3.13 + def fix_stack(self, level):
3.14 + for operand in self.operands:
3.15 + operand.fix_stack(level)
3.16 +
3.17 + def show_operands(self):
3.18 + return self.operands and (" %s" % self.operands) or ""
3.19
3.20 def __repr__(self):
3.21 if self.attr is not None:
3.22 - return "%s(%r)" % (self.__class__.__name__, self.attr)
3.23 + return "%s(%r)%s" % (self.__class__.__name__, self.attr, self.show_operands())
3.24 else:
3.25 - return "%s()" % self.__class__.__name__
3.26 + return "%s()%s" % (self.__class__.__name__, self.show_operands())
3.27
3.28 class StackRelativeInstruction(Instruction):
3.29
3.30 "An instruction operating on the local value stack."
3.31
3.32 def __repr__(self):
3.33 - return "%s(%r)" % (self.__class__.__name__, self.get_operand())
3.34 + return "%s(%r)%s" % (self.__class__.__name__, self.get_operand(), self.show_operands())
3.35
3.36 def get_operand(self):
3.37 return self.attr.position
3.38 @@ -71,9 +80,9 @@
3.39 def __repr__(self):
3.40 position = self.get_operand()
3.41 if position is not None:
3.42 - return "%s(%r) # %s" % (self.__class__.__name__, position, name(self.attr))
3.43 + return "%s(%r)%s # %s" % (self.__class__.__name__, position, self.show_operands(), name(self.attr))
3.44 else:
3.45 - return "%s(%r)" % (self.__class__.__name__, name(self.attr))
3.46 + return "%s(%r)%s" % (self.__class__.__name__, self.show_operands(), name(self.attr))
3.47
3.48 def get_operand(self):
3.49 return self.attr.position
3.50 @@ -87,11 +96,11 @@
3.51 def __repr__(self):
3.52 location, position, result = self.get_operands()
3.53 if location is not None:
3.54 - return "%s(%r) # %r, %r (%s)" % (self.__class__.__name__, result, location, position, name(self.attr))
3.55 + return "%s(%r)%s # %r, %r (%s)" % (self.__class__.__name__, result, self.show_operands(), location, position, name(self.attr))
3.56 elif result is not None:
3.57 - return "%s(%r) # %s" % (self.__class__.__name__, result, name(self.attr))
3.58 + return "%s(%r)%s # %s" % (self.__class__.__name__, result, self.show_operands(), name(self.attr))
3.59 else:
3.60 - return "%s(...) # %s" % (self.__class__.__name__, name(self.attr))
3.61 + return "%s(...)%s # %s" % (self.__class__.__name__, self.show_operands(), name(self.attr))
3.62
3.63 def get_operands(self):
3.64 if isinstance(self.attr, Attr):
3.65 @@ -122,7 +131,7 @@
3.66 "An instruction employing a constant."
3.67
3.68 def __repr__(self):
3.69 - return "%s(%r)" % (self.__class__.__name__, self.attr)
3.70 + return "%s(%r)%s" % (self.__class__.__name__, self.attr, self.show_operands())
3.71
3.72 def get_operand(self):
3.73 return self.attr
3.74 @@ -145,17 +154,19 @@
3.75 "Indicate that the stack must shrink as an effect of this instruction."
3.76
3.77 stack_usage = -1
3.78 + stack_access = 1
3.79
3.80 class StackRemove2:
3.81
3.82 "Indicate that the stack must shrink as an effect of this instruction."
3.83
3.84 stack_usage = -2
3.85 + stack_access = 2
3.86
3.87 # Instructions operating on the value stack.
3.88
3.89 class Duplicate(StackAdd, Instruction): "Duplicate the top of the stack."
3.90 -class Pop(StackRemove, Instruction): "Pop entries from the top of the stack."
3.91 +class ResetStack(Instruction): "Pop entries from the stack."
3.92
3.93 # Access to stored constant data.
3.94
3.95 @@ -166,7 +177,7 @@
3.96 class LoadName(StackAdd, SR): "Load the object from the given local attribute/variable."
3.97 class StoreName(StackRemove, SR): "Store the object in the given local attribute/variable."
3.98 class LoadTemp(Immediate): "Load the object from the given temporary location."
3.99 -class StoreTemp(Immediate): "Store the object in the given temporary location."
3.100 +class StoreTemp(StackRemove, Immediate): "Store the object in the given temporary location."
3.101
3.102 # Access to address-relative data.
3.103
3.104 @@ -207,4 +218,20 @@
3.105 class TestIdentity(Instruction): "Test whether the two topmost stack values are identical."
3.106 class TestIdentityAddress(Address): "Test whether the topmost stack value is identical to the given address."
3.107
3.108 +# Internal stack operations for instructions.
3.109 +
3.110 +class StackLoad:
3.111 +
3.112 + "Load a value from the stack."
3.113 +
3.114 + def __init__(self, n):
3.115 + self.n = n
3.116 + self.level = None
3.117 +
3.118 + def fix_stack(self, level):
3.119 + self.level = self.n + level
3.120 +
3.121 + def __repr__(self):
3.122 + return "%s(%r)" % (self.__class__.__name__, self.n)
3.123 +
3.124 # vim: tabstop=4 expandtab shiftwidth=4
4.1 --- a/test.py Mon Jun 09 21:09:37 2008 +0200
4.2 +++ b/test.py Mon Jun 16 01:56:46 2008 +0200
4.3 @@ -20,10 +20,10 @@
4.4 for i, x in enumerate(code):
4.5 print i, x
4.6
4.7 -def machine(code, code_location):
4.8 - rc = raw(code)
4.9 +def machine(importer):
4.10 + rc = raw(importer.code)
4.11 rm = rsvp.RSVPMachine(rc)
4.12 - rm.pc = code_location
4.13 + rm.pc = importer.code_location
4.14 return rm
4.15
4.16 def attrs(obj):
4.17 @@ -40,7 +40,8 @@
4.18 requested_optimisations = []
4.19 for arg in args:
4.20 if arg.startswith("-o"):
4.21 - requested_optimisations.append(arg[2:])
4.22 + for arg_part in arg[2:].split(","):
4.23 + requested_optimisations.append(arg_part)
4.24
4.25 try:
4.26 builtins = i.load_from_file("lib/builtins.py", "__builtins__")