git @ Cat's Eye Technologies SixtyPical / ab33331
Associate a range with each meaningful storage location in context. Chris Pressey 7 years ago
2 changed file(s) with 35 addition(s) and 19 deletion(s). Raw diff Collapse all Expand all
6565 """
6666 A location is touched if it was changed (or even potentially
6767 changed) during this routine, or some routine called by this routine.
68
68
6969 A location is meaningful if it was an input to this routine,
7070 or if it was set to a meaningful value by some operation in this
71 routine (or some routine called by this routine.
72
71 routine (or some routine called by this routine).
72
73 If a location is meaningful, it has a range. This range represents
74 the lowest and highest values that it might possibly be (i.e. we know
75 it cannot possibly be below the lowest or above the highest.) In the
76 absence of any usage information, the range of a byte, is 0..255 and
77 the range of a word is 0..65535.
78
7379 A location is writeable if it was listed in the outputs and trashes
7480 lists of this routine.
7581 """
7783 self.routines = routines # Location -> AST node
7884 self.routine = routine
7985 self._touched = set()
80 self._meaningful = set()
86 self._range = dict()
8187 self._writeable = set()
8288
8389 for ref in inputs:
8490 if ref.is_constant():
8591 raise ConstantConstraintError('%s in %s' % (ref.name, routine.name))
86 self._meaningful.add(ref)
92 self._range[ref] = ref.max_range()
8793 output_names = set()
8894 for ref in outputs:
8995 if ref.is_constant():
98104 self._writeable.add(ref)
99105
100106 def __str__(self):
101 return "Context(\n _touched={},\n _meaningful={},\n _writeable={}\n)".format(
102 LocationRef.format_set(self._touched), LocationRef.format_set(self._meaningful), LocationRef.format_set(self._writeable)
107 return "Context(\n _touched={},\n _range={},\n _writeable={}\n)".format(
108 LocationRef.format_set(self._touched), LocationRef.format_set(self._range), LocationRef.format_set(self._writeable)
103109 )
104110
105111 def clone(self):
106112 c = Context(self.routines, self.routine, [], [], [])
107113 c._touched = set(self._touched)
108 c._meaningful = set(self._meaningful)
114 c._range = dict(self._range)
109115 c._writeable = set(self._writeable)
110116 return c
111117
112118 def each_meaningful(self):
113 for ref in self._meaningful:
119 for ref in self._range.keys():
114120 yield ref
115121
116122 def each_touched(self):
126132 if ref.is_constant() or ref in self.routines:
127133 pass
128134 elif isinstance(ref, LocationRef):
129 if ref not in self._meaningful:
135 if ref not in self._range:
130136 message = '%s in %s' % (ref.name, self.routine.name)
131137 if kwargs.get('message'):
132138 message += ' (%s)' % kwargs['message']
155161
156162 def set_meaningful(self, *refs):
157163 for ref in refs:
158 self._meaningful.add(ref)
164 self._range[ref] = ref.max_range()
159165
160166 def set_unmeaningful(self, *refs):
161167 for ref in refs:
162 if ref in self._meaningful:
163 self._meaningful.remove(ref)
168 if ref in self._range:
169 del self._range[ref]
164170
165171 def set_written(self, *refs):
166172 """A "helper" method which does the following common sequence for
222228 print context
223229
224230 self.analyze_block(routine.block, context)
225 trashed = set(context.each_touched()) - context._meaningful
231 trashed = set(context.each_touched()) - set(context.each_meaningful())
226232
227233 if self.debug:
228234 print "at end of routine `{}`:".format(routine.name)
396402
397403 # merge the contexts. this used to be a method called `set_from`
398404 context._touched = set(context1._touched) | set(context2._touched)
399 context._meaningful = outgoing_meaningful
405 context.set_meaningful(*list(outgoing_meaningful))
400406 context._writeable = set(context1._writeable) | set(context2._writeable)
401407
402408 for ref in outgoing_trashes:
11
22
33 class Type(object):
4 def __init__(self, name):
4 def __init__(self, name, max_range=None):
55 self.name = name
6 self.max_range = max_range
67
78 def __repr__(self):
89 return 'Type(%r)' % self.name
3132 self.trashes = set([resolve(w) for w in self.trashes])
3233
3334
34 TYPE_BIT = Type('bit')
35 TYPE_BYTE = Type('byte')
36 TYPE_WORD = Type('word')
35 TYPE_BIT = Type('bit', max_range=(0, 1))
36 TYPE_BYTE = Type('byte', max_range=(0, 255))
37 TYPE_WORD = Type('word', max_range=(0, 65535))
3738
3839
3940
131132 will not change during the lifetime of the program."""
132133 raise NotImplementedError
133134
135 def max_range(self):
136 raise NotImplementedError
137
134138
135139 class LocationRef(Ref):
136140 def __init__(self, type, name):
159163 def is_constant(self):
160164 return isinstance(self.type, RoutineType)
161165
166 def max_range(self):
167 try:
168 return self.type.max_range
169 except:
170 return (0, 0)
171
162172 @classmethod
163173 def format_set(cls, location_refs):
164174 return '{%s}' % ', '.join([str(loc) for loc in sorted(location_refs)])