65 | 65 |
"""
|
66 | 66 |
A location is touched if it was changed (or even potentially
|
67 | 67 |
changed) during this routine, or some routine called by this routine.
|
68 | |
|
|
68 |
|
69 | 69 |
A location is meaningful if it was an input to this routine,
|
70 | 70 |
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 |
|
73 | 79 |
A location is writeable if it was listed in the outputs and trashes
|
74 | 80 |
lists of this routine.
|
75 | 81 |
"""
|
|
77 | 83 |
self.routines = routines # Location -> AST node
|
78 | 84 |
self.routine = routine
|
79 | 85 |
self._touched = set()
|
80 | |
self._meaningful = set()
|
|
86 |
self._range = dict()
|
81 | 87 |
self._writeable = set()
|
82 | 88 |
|
83 | 89 |
for ref in inputs:
|
84 | 90 |
if ref.is_constant():
|
85 | 91 |
raise ConstantConstraintError('%s in %s' % (ref.name, routine.name))
|
86 | |
self._meaningful.add(ref)
|
|
92 |
self._range[ref] = ref.max_range()
|
87 | 93 |
output_names = set()
|
88 | 94 |
for ref in outputs:
|
89 | 95 |
if ref.is_constant():
|
|
98 | 104 |
self._writeable.add(ref)
|
99 | 105 |
|
100 | 106 |
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)
|
103 | 109 |
)
|
104 | 110 |
|
105 | 111 |
def clone(self):
|
106 | 112 |
c = Context(self.routines, self.routine, [], [], [])
|
107 | 113 |
c._touched = set(self._touched)
|
108 | |
c._meaningful = set(self._meaningful)
|
|
114 |
c._range = dict(self._range)
|
109 | 115 |
c._writeable = set(self._writeable)
|
110 | 116 |
return c
|
111 | 117 |
|
112 | 118 |
def each_meaningful(self):
|
113 | |
for ref in self._meaningful:
|
|
119 |
for ref in self._range.keys():
|
114 | 120 |
yield ref
|
115 | 121 |
|
116 | 122 |
def each_touched(self):
|
|
126 | 132 |
if ref.is_constant() or ref in self.routines:
|
127 | 133 |
pass
|
128 | 134 |
elif isinstance(ref, LocationRef):
|
129 | |
if ref not in self._meaningful:
|
|
135 |
if ref not in self._range:
|
130 | 136 |
message = '%s in %s' % (ref.name, self.routine.name)
|
131 | 137 |
if kwargs.get('message'):
|
132 | 138 |
message += ' (%s)' % kwargs['message']
|
|
155 | 161 |
|
156 | 162 |
def set_meaningful(self, *refs):
|
157 | 163 |
for ref in refs:
|
158 | |
self._meaningful.add(ref)
|
|
164 |
self._range[ref] = ref.max_range()
|
159 | 165 |
|
160 | 166 |
def set_unmeaningful(self, *refs):
|
161 | 167 |
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]
|
164 | 170 |
|
165 | 171 |
def set_written(self, *refs):
|
166 | 172 |
"""A "helper" method which does the following common sequence for
|
|
222 | 228 |
print context
|
223 | 229 |
|
224 | 230 |
self.analyze_block(routine.block, context)
|
225 | |
trashed = set(context.each_touched()) - context._meaningful
|
|
231 |
trashed = set(context.each_touched()) - set(context.each_meaningful())
|
226 | 232 |
|
227 | 233 |
if self.debug:
|
228 | 234 |
print "at end of routine `{}`:".format(routine.name)
|
|
396 | 402 |
|
397 | 403 |
# merge the contexts. this used to be a method called `set_from`
|
398 | 404 |
context._touched = set(context1._touched) | set(context2._touched)
|
399 | |
context._meaningful = outgoing_meaningful
|
|
405 |
context.set_meaningful(*list(outgoing_meaningful))
|
400 | 406 |
context._writeable = set(context1._writeable) | set(context2._writeable)
|
401 | 407 |
|
402 | 408 |
for ref in outgoing_trashes:
|