0 | 0 |
# encoding: UTF-8
|
1 | 1 |
|
2 | |
import sys
|
3 | |
|
4 | |
from sixtypical.ast import Program, Defn, Routine, Block, Instr
|
5 | |
from sixtypical.model import ConstantRef, LocationRef
|
|
2 |
from sixtypical.ast import Program, Routine, Block, Instr
|
|
3 |
from sixtypical.model import (
|
|
4 |
ConstantRef, LocationRef, FLAG_Z, FLAG_N, FLAG_V, FLAG_C
|
|
5 |
)
|
6 | 6 |
|
7 | 7 |
|
8 | 8 |
UNINITIALIZED = 'UNINITIALIZED'
|
|
53 | 53 |
c._writeables = set(self._writeables)
|
54 | 54 |
return c
|
55 | 55 |
|
56 | |
def assertInitialized(self, *refs, **kwargs):
|
|
56 |
def set_from(self, c):
|
|
57 |
self._store = dict(c._store)
|
|
58 |
self._writeables = set(c._writeables)
|
|
59 |
|
|
60 |
def each_initialized(self):
|
|
61 |
for key, value in self._store.iteritems():
|
|
62 |
if value == INITIALIZED:
|
|
63 |
yield LocationRef(key)
|
|
64 |
|
|
65 |
def assert_initialized(self, *refs, **kwargs):
|
57 | 66 |
exception_class = kwargs.get('exception_class', UninitializedAccessError)
|
58 | 67 |
for ref in refs:
|
59 | 68 |
if isinstance(ref, ConstantRef):
|
|
64 | 73 |
else:
|
65 | 74 |
raise ValueError(ref)
|
66 | 75 |
|
67 | |
def assertWriteable(self, *refs):
|
|
76 |
def assert_writeable(self, *refs):
|
68 | 77 |
for ref in refs:
|
69 | 78 |
if ref.name not in self._writeables:
|
70 | 79 |
raise IllegalWriteError(ref.name)
|
71 | 80 |
|
72 | |
def setInitialized(self, *refs):
|
|
81 |
def set_initialized(self, *refs):
|
73 | 82 |
for ref in refs:
|
74 | 83 |
self.set(ref, INITIALIZED)
|
75 | 84 |
|
76 | |
def setUninitialized(self, *refs):
|
|
85 |
def set_uninitialized(self, *refs):
|
77 | 86 |
for ref in refs:
|
78 | 87 |
self.set(ref, UNINITIALIZED)
|
79 | 88 |
|
|
104 | 113 |
context = Context(routine.inputs, routine.outputs, routine.trashes)
|
105 | 114 |
analyze_block(routine.block, context, routines)
|
106 | 115 |
for ref in routine.outputs:
|
107 | |
context.assertInitialized(ref, exception_class=UninitializedOutputError)
|
|
116 |
context.assert_initialized(ref, exception_class=UninitializedOutputError)
|
108 | 117 |
|
109 | 118 |
|
110 | 119 |
def analyze_block(block, context, routines):
|
|
120 | 129 |
src = instr.src
|
121 | 130 |
|
122 | 131 |
if opcode == 'ld':
|
123 | |
context.assertInitialized(src)
|
124 | |
context.assertWriteable(dest, LocationRef('z'), LocationRef('n'))
|
125 | |
context.setInitialized(dest, LocationRef('z'), LocationRef('n'))
|
|
132 |
context.assert_initialized(src)
|
|
133 |
context.assert_writeable(dest, FLAG_Z, FLAG_N)
|
|
134 |
context.set_initialized(dest, FLAG_Z, FLAG_N)
|
126 | 135 |
elif opcode == 'st':
|
127 | |
context.assertInitialized(src)
|
128 | |
context.assertWriteable(dest)
|
129 | |
context.setInitialized(dest)
|
|
136 |
context.assert_initialized(src)
|
|
137 |
context.assert_writeable(dest)
|
|
138 |
context.set_initialized(dest)
|
130 | 139 |
elif opcode in ('add', 'sub'):
|
131 | |
context.assertInitialized(src, dest, LocationRef('c'))
|
132 | |
context.assertWriteable(dest,
|
133 | |
LocationRef('z'), LocationRef('n'),
|
134 | |
LocationRef('c'), LocationRef('v'),
|
135 | |
)
|
136 | |
context.setInitialized(dest,
|
137 | |
LocationRef('z'), LocationRef('n'),
|
138 | |
LocationRef('c'), LocationRef('v'),
|
139 | |
)
|
|
140 |
context.assert_initialized(src, dest, FLAG_C)
|
|
141 |
context.assert_writeable(dest, FLAG_Z, FLAG_N, FLAG_C, FLAG_V)
|
|
142 |
context.set_initialized(dest, FLAG_Z, FLAG_N, FLAG_C, FLAG_V)
|
140 | 143 |
elif opcode in ('inc', 'dec'):
|
141 | |
context.assertInitialized(dest)
|
142 | |
context.assertWriteable(dest, LocationRef('z'), LocationRef('n'))
|
143 | |
context.setInitialized(dest, LocationRef('z'), LocationRef('n'))
|
|
144 |
context.assert_initialized(dest)
|
|
145 |
context.assert_writeable(dest, FLAG_Z, FLAG_N)
|
|
146 |
context.set_initialized(dest, FLAG_Z, FLAG_N)
|
144 | 147 |
elif opcode == 'cmp':
|
145 | |
context.assertInitialized(src, dest)
|
146 | |
context.assertWriteable(LocationRef('z'), LocationRef('n'), LocationRef('c'))
|
147 | |
context.setInitialized(LocationRef('z'), LocationRef('n'), LocationRef('c'))
|
|
148 |
context.assert_initialized(src, dest)
|
|
149 |
context.assert_writeable(FLAG_Z, FLAG_N, FLAG_C)
|
|
150 |
context.set_initialized(FLAG_Z, FLAG_N, FLAG_C)
|
148 | 151 |
elif opcode in ('and', 'or', 'xor'):
|
149 | |
context.assertInitialized(sec, dest)
|
150 | |
context.assertWriteable(dest, LocationRef('z'), LocationRef('n'))
|
151 | |
context.setInitialized(dest, LocationRef('z'), LocationRef('n'))
|
|
152 |
context.assert_initialized(src, dest)
|
|
153 |
context.assert_writeable(dest, FLAG_Z, FLAG_N)
|
|
154 |
context.set_initialized(dest, FLAG_Z, FLAG_N)
|
152 | 155 |
elif opcode in ('shl', 'shr'):
|
153 | |
context.assertInitialized(dest)
|
154 | |
context.assertWriteable(dest, LocationRef('z'), LocationRef('n'), LocationRef('c'))
|
155 | |
context.setInitialized(dest, LocationRef('z'), LocationRef('n'), LocationRef('c'))
|
|
156 |
context.assert_initialized(dest)
|
|
157 |
context.assert_writeable(dest, FLAG_Z, FLAG_N, FLAG_C)
|
|
158 |
context.set_initialized(dest, FLAG_Z, FLAG_N, FLAG_C)
|
156 | 159 |
elif opcode == 'call':
|
157 | 160 |
routine = routines[instr.name]
|
158 | 161 |
for ref in routine.inputs:
|
159 | |
context.assertInitialized(ref)
|
|
162 |
context.assert_initialized(ref)
|
160 | 163 |
for ref in routine.outputs:
|
161 | |
context.assertWriteable(ref)
|
162 | |
context.setInitialized(ref)
|
|
164 |
context.assert_writeable(ref)
|
|
165 |
context.set_initialized(ref)
|
163 | 166 |
for ref in routine.trashes:
|
164 | |
context.assertWriteable(ref)
|
165 | |
context.setUninitialized(ref)
|
|
167 |
context.assert_writeable(ref)
|
|
168 |
context.set_uninitialized(ref)
|
166 | 169 |
elif opcode == 'if':
|
167 | 170 |
context1 = context.clone()
|
168 | 171 |
context2 = context.clone()
|
169 | 172 |
analyze_block(instr.block1, context1, routines)
|
170 | 173 |
analyze_block(instr.block2, context2, routines)
|
171 | |
reconcile_contexts(context1, context2, output=context)
|
|
174 |
for ref in context1.each_initialized():
|
|
175 |
context2.assert_initialized(ref)
|
|
176 |
for ref in context2.each_initialized():
|
|
177 |
context1.assert_initialized(ref)
|
|
178 |
context.set_from(context1)
|
172 | 179 |
else:
|
173 | |
raise NotImplementedError
|
|
180 |
raise NotImplementedError(opcode)
|