100 | 100 |
self._touched = set()
|
101 | 101 |
self._range = dict()
|
102 | 102 |
self._writeable = set()
|
|
103 |
self._has_encountered_goto = False
|
103 | 104 |
|
104 | 105 |
for ref in inputs:
|
105 | 106 |
if ref.is_constant():
|
|
242 | 243 |
for ref in refs:
|
243 | 244 |
self._writeable.remove(ref)
|
244 | 245 |
|
|
246 |
def set_encountered_goto(self):
|
|
247 |
self._has_encountered_goto = True
|
|
248 |
|
|
249 |
def has_encountered_goto(self):
|
|
250 |
return self._has_encountered_goto
|
|
251 |
|
245 | 252 |
|
246 | 253 |
class Analyzer(object):
|
247 | 254 |
|
248 | 255 |
def __init__(self, debug=False):
|
249 | 256 |
self.current_routine = None
|
250 | |
self.has_encountered_goto = False
|
251 | 257 |
self.routines = {}
|
252 | 258 |
self.debug = debug
|
253 | 259 |
|
|
280 | 286 |
def analyze_routine(self, routine):
|
281 | 287 |
assert isinstance(routine, Routine)
|
282 | 288 |
self.current_routine = routine
|
283 | |
self.has_encountered_goto = False
|
284 | 289 |
if routine.block is None:
|
285 | 290 |
# it's an extern, that's fine
|
286 | 291 |
return
|
|
311 | 316 |
if ref in type_.outputs:
|
312 | 317 |
raise UnmeaningfulOutputError(routine, ref.name)
|
313 | 318 |
|
314 | |
if not self.has_encountered_goto:
|
|
319 |
if not context.has_encountered_goto():
|
315 | 320 |
for ref in type_.outputs:
|
316 | 321 |
context.assert_meaningful(ref, exception_class=UnmeaningfulOutputError)
|
317 | 322 |
for ref in context.each_touched():
|
|
322 | 327 |
def analyze_block(self, block, context):
|
323 | 328 |
assert isinstance(block, Block)
|
324 | 329 |
for i in block.instrs:
|
325 | |
if self.has_encountered_goto:
|
326 | |
raise IllegalJumpError(i, i)
|
327 | 330 |
self.analyze_instr(i, context)
|
328 | 331 |
|
329 | 332 |
def analyze_instr(self, instr, context):
|
|
345 | 348 |
opcode = instr.opcode
|
346 | 349 |
dest = instr.dest
|
347 | 350 |
src = instr.src
|
348 | |
|
|
351 |
|
|
352 |
if context.has_encountered_goto():
|
|
353 |
raise IllegalJumpError(instr, instr)
|
|
354 |
|
349 | 355 |
if opcode == 'ld':
|
350 | 356 |
if isinstance(src, IndexedRef):
|
351 | 357 |
if TableType.is_a_table_type(src.ref.type, TYPE_BYTE) and dest.type == TYPE_BYTE:
|
|
559 | 565 |
self.assert_affected_within('outputs', type_, current_type)
|
560 | 566 |
self.assert_affected_within('trashes', type_, current_type)
|
561 | 567 |
|
562 | |
self.has_encountered_goto = True
|
|
568 |
context.set_encountered_goto()
|
563 | 569 |
elif opcode == 'trash':
|
564 | 570 |
context.set_touched(instr.dest)
|
565 | 571 |
context.set_unmeaningful(instr.dest)
|
|
600 | 606 |
context._touched = set(context1._touched) | set(context2._touched)
|
601 | 607 |
context.set_meaningful(*list(outgoing_meaningful))
|
602 | 608 |
context._writeable = set(context1._writeable) | set(context2._writeable)
|
|
609 |
if context1.has_encountered_goto() or context2.has_encountered_goto():
|
|
610 |
context.set_encountered_goto()
|
603 | 611 |
|
604 | 612 |
for ref in outgoing_trashes:
|
605 | 613 |
context.set_touched(ref)
|