git @ Cat's Eye Technologies SixtyPical / d13c6a9
Drop the check for "consistent initialization" inside `if` blocks. Chris Pressey 2 years ago
5 changed file(s) with 46 addition(s) and 51 deletion(s). Raw diff Collapse all Expand all
33 0.18
44 ----
55
6 * The "consistent initialization" check inside `if` blocks has
7 been dropped. If a location is initialized inside one block
8 but not the other, it is treated as uninitialized afterwards.
69 * Syntactically, `goto` may only appear at the end of a block.
710 It need no longer be the final instruction in a routine,
811 as long as the type context is consistent at every exit.
4343 An alternative would be `static` pointers, which are currently not possible because
4444 pointers must be zero-page, thus `@`, thus uninitialized.
4545
46 ### Question "consistent initialization"
47
48 Question the value of the "consistent initialization" principle for `if` statement analysis.
49
50 Part of this is the trashes at the end; I think what it should be is that the trashes
51 after the `if` is the union of the trashes in each of the branches; this would obviate the
52 need to `trash` values explicitly, but if you tried to access them afterwards, it would still
53 error.
54
5546 ### Tail-call optimization
5647
5748 If a block ends in a `call` can that be converted to end in a `goto`? Why not? I think it can,
310310 ld a, 1
311311 st a, player_died
312312 }
313
314 // FIXME these trashes, strictly speaking, probably shouldn't be needed,
315 // but currently the compiler cares a little too much about values that are
316 // initialized in one branch of an `if`, but not the other, but are trashed
317 // at the end of the routine anyway.
318 trash ptr
319 trash y
320 trash v
321313 }
322314 }
323315
354346 add ptr, pos
355347 copy 82, [ptr] + y
356348 }
357
358 // FIXME these trashes, strictly speaking, probably shouldn't be needed,
359 // but currently the compiler cares too much about values that are
360 // initialized in one branch of an `if`, but not the other, but trashed
361 // at the end of the routine anyway.
362 trash ptr
363 trash y
364349 } else {
365350 copy delta, compare_target
366351 st on, c
413413 if self.debug:
414414 print("at end of routine `{}`:".format(routine.name))
415415 print(context)
416 print("trashed: ", LocationRef.format_set(trashed))
416 #print("trashed: ", LocationRef.format_set(trashed))
417417 print("outputs: ", LocationRef.format_set(type_.outputs))
418 trashed_outputs = type_.outputs & trashed
419 if trashed_outputs:
420 print("TRASHED OUTPUTS: ", LocationRef.format_set(trashed_outputs))
418 #trashed_outputs = type_.outputs & trashed
419 #if trashed_outputs:
420 # print("TRASHED OUTPUTS: ", LocationRef.format_set(trashed_outputs))
421421 print('')
422422 print('-' * 79)
423423 print('')
800800 outgoing_meaningful = set(context1.each_meaningful()) & set(context2.each_meaningful())
801801 outgoing_trashes = incoming_meaningful - outgoing_meaningful
802802
803 # TODO may we need to deal with touched separately here too?
804 # probably not; if it wasn't meaningful in the first place, it
805 # doesn't really matter if you modified it or not, coming out.
806 for ref in context1.each_meaningful():
807 if ref in outgoing_trashes:
808 continue
809 context2.assert_meaningful(
810 ref, exception_class=InconsistentInitializationError,
811 message='initialized in block 1 but not in block 2 of `if {}`'.format(instr.src)
812 )
813 for ref in context2.each_meaningful():
814 if ref in outgoing_trashes:
815 continue
816 context1.assert_meaningful(
817 ref, exception_class=InconsistentInitializationError,
818 message='initialized in block 2 but not in block 1 of `if {}`'.format(instr.src)
819 )
820
821803 # merge the contexts.
822804
823805 # first, the easy case: if one of the contexts has terminated, just use the other one.
16061606 | }
16071607 = ok
16081608
1609 If a location is initialized in one block, is must be initialized in the other as well.
1609 If a location is initialized in one block, is must be initialized in the other as well
1610 in order to be considered to be initialized after the block. If it is not consistent,
1611 it will be considered uninitialized.
16101612
16111613 | define foo routine
16121614 | inputs a
16201622 | ld a, 23
16211623 | }
16221624 | }
1623 ? InconsistentInitializationError: x
1625 ? UnmeaningfulOutputError: x
16241626
16251627 | define foo routine
16261628 | inputs a
16341636 | ld x, 7
16351637 | }
16361638 | }
1637 ? InconsistentInitializationError: x
1639 ? UnmeaningfulOutputError: x
16381640
16391641 | define foo routine
16401642 | inputs a
16481650 | ld x, 7
16491651 | }
16501652 | }
1651 ? InconsistentInitializationError: x
1653 ? UnmeaningfulOutputError: x
1654
1655 If we don't care if it's uninitialized after the `if`, that's okay then.
1656
1657 | define foo routine
1658 | inputs a
1659 | trashes a, x, z, n, c
1660 | {
1661 | cmp a, 42
1662 | if not z {
1663 | ld a, 6
1664 | } else {
1665 | ld x, 7
1666 | }
1667 | }
1668 = ok
1669
1670 Or, if it does get initialized on both branches, that's okay then.
1671
1672 | define foo routine
1673 | inputs a
1674 | outputs x
1675 | trashes a, z, n, c
1676 | {
1677 | cmp a, 42
1678 | if not z {
1679 | ld x, 0
1680 | ld a, 6
1681 | } else {
1682 | ld x, 7
1683 | }
1684 | }
1685 = ok
16521686
16531687 However, this only pertains to initialization. If a value is already
16541688 initialized, either because it was set previous to the `if`, or is an
16971731 | ld x, 7
16981732 | }
16991733 | }
1700 ? InconsistentInitializationError: x
1734 ? UnmeaningfulOutputError: x
17011735
17021736 | define foo routine
17031737 | inputs a