git @ Cat's Eye Technologies SixtyPical / 56f8407
Merge contexts from both branches of an `if`. Cat's Eye Technologies 8 years ago
3 changed file(s) with 107 addition(s) and 9 deletion(s). Raw diff Collapse all Expand all
8282 blocks. The `with` construct takes an instruction like `sei` and implicitly
8383 (and unavoidably) inserts the corresponding `cli` at the end of the block.
8484
85 Abstract interpretation extends to `if` blocks. The two incoming contexts are
86 merged, and any storage locations poisoned in either context are considered
87 poisoned in the result context.
88
89 (Same should apply for `repeat` and `with` and, really, many other cases
90 which there just aren't enough test cases for yet.)
91
8592 For More Information
8693 --------------------
8794
93100 -----
94101
95102 These aren't implemented yet:
96
97 * Abstract interpretation must extend to `if`, `repeat`, and `with`
98 blocks. The two incoming contexts must be merged, and any storage
99 locations updated differently or poisoned in either context, will be
100 considered poisoned in the result context.
101103
102104 * Inside a routine, an address may be declared with `temporary`. This is like
103105 `static` in C, except the value at that address is not guaranteed to be
126126 =
127127 = update_score ([A])
128128 = A: UpdatedWith (Immediate 8)
129
130 If a location is poisoned in either branch of an `if`, it is poisoned
131 after the `if`.
132
133 | reserve byte score
134 | routine update_score
135 | {
136 | if beq {
137 | lda #8
138 | } else {
139 | ldx #8
140 | }
141 | }
142 | routine main {
143 | lda #4
144 | jsr update_score
145 | sta score
146 | }
147 ? routine does not preserve 'A'
148
149 | reserve byte score
150 | routine update_score
151 | {
152 | if beq {
153 | ldx #8
154 | } else {
155 | lda #8
156 | }
157 | }
158 | routine main {
159 | lda #4
160 | jsr update_score
161 | sta score
162 | }
163 ? routine does not preserve 'A'
164
165 | reserve byte score
166 | routine update_score
167 | {
168 | lda #4
169 | sta score
170 | }
171 | routine main {
172 | lda #4
173 | if beq {
174 | jsr update_score
175 | } else {
176 | ldx #3
177 | }
178 | sta score
179 | }
180 ? routine does not preserve 'A'
181
182 | reserve byte score
183 | routine update_score
184 | {
185 | lda #4
186 | sta score
187 | }
188 | routine main {
189 | lda #4
190 | if beq {
191 | ldx #3
192 | } else {
193 | jsr update_score
194 | }
195 | sta score
196 | }
197 ? routine does not preserve 'A'
7272 -- TODO: mark Carry bit as "touched" here
7373 routCtx
7474 checkInstr (IF _ branch b1 b2) progCtx routCtx =
75 -- TODO: oooh, this one's gonna be fun
76 --checkBlock b1 progCtx routCtx
77 --checkBlock b2 progCtx routCtx
78 routCtx
75 let
76 routCtx1 = checkBlock b1 progCtx routCtx
77 routCtx2 = checkBlock b2 progCtx routCtx
78 in
79 mergeAlternateRoutCtxs routCtx1 routCtx2
7980 checkInstr (REPEAT _ branch blk) progCtx routCtx =
8081 -- TODO: oooh, this one's gonna be fun too
8182 --checkBlock blk progCtx routCtx
139140 NamedLocation Nothing name
140141 untypedLocation x = x
141142
143 --
144 -- Utility function:
145 -- Take 2 routine contexts -- one from each branch of an `if` -- and merge
146 -- them to create a new context for the remainder of the routine.
147 --
148 mergeAlternateRoutCtxs routCtx1 routCtx2 =
149 let
150 -- go through all the Usages in routCtx2
151 -- insert any that were updated, into routCtx1
152 poison location usage2 routCtxAccum =
153 case Map.lookup location routCtx1 of
154 Nothing ->
155 Map.insert location usage2 routCtxAccum
156 Just usage1 ->
157 -- it exists in both routCtxs.
158 -- if it is poisoned in either, it's poisoned here.
159 -- otherwise, it is OK to differ.
160 let
161 newUsage = case (usage1, usage2) of
162 (PoisonedWith _, _) -> usage1
163 (_, PoisonedWith _) -> usage2
164 _ -> usage1 -- or 2. doesn't matter.
165 in
166 Map.insert location newUsage routCtxAccum
167 in
168 Map.foldrWithKey (poison) routCtx1 routCtx2