mirror of
https://github.com/catseye/SixtyPical.git
synced 2024-11-22 01:32:13 +00:00
Confirm that AND clips the range and INC/DEC invalidate it.
This commit is contained in:
parent
1eaec602e3
commit
bda0202dee
@ -31,7 +31,6 @@ Documentation
|
||||
* [SixtyPical specification](doc/SixtyPical.md)
|
||||
* [SixtyPical revision history](HISTORY.md)
|
||||
* [Literate test suite for SixtyPical syntax](tests/SixtyPical%20Syntax.md)
|
||||
* [Literate test suite for SixtyPical execution](tests/SixtyPical%20Execution.md)
|
||||
* [Literate test suite for SixtyPical analysis](tests/SixtyPical%20Analysis.md)
|
||||
* [Literate test suite for SixtyPical compilation](tests/SixtyPical%20Compilation.md)
|
||||
* [6502 Opcodes used/not used in SixtyPical](doc/6502%20Opcodes.md)
|
||||
@ -78,11 +77,14 @@ are trashed inside the block.
|
||||
### Re-order routines and optimize tail-calls to fallthroughs
|
||||
|
||||
Not because it saves 3 bytes, but because it's a neat trick. Doing it optimally
|
||||
is probably NP-complete. But doing it adeuqately is probably not that hard.
|
||||
is probably NP-complete. But doing it adequately is probably not that hard.
|
||||
|
||||
### Different preludes for different architectures
|
||||
|
||||
`--prelude=c64-basic`
|
||||
|
||||
### And at some point...
|
||||
|
||||
* Confirm that `and` can be used to restrict the range of table reads/writes.
|
||||
* `low` and `high` address operators - to turn `word` type into `byte`.
|
||||
* `const`s that can be used in defining the size of tables, etc.
|
||||
* Tests, and implementation, ensuring a routine can be assigned to a vector of "wider" type
|
||||
|
@ -194,6 +194,7 @@ class Context(object):
|
||||
def set_touched(self, *refs):
|
||||
for ref in refs:
|
||||
self._touched.add(ref)
|
||||
# TODO: it might be possible to invalidate the range here
|
||||
|
||||
def set_meaningful(self, *refs):
|
||||
for ref in refs:
|
||||
@ -220,6 +221,10 @@ class Context(object):
|
||||
src_range = src.max_range()
|
||||
self._range[dest] = src_range
|
||||
|
||||
def invalidate_range(self, ref):
|
||||
self.assert_meaningful(ref)
|
||||
self._range[ref] = ref.max_range()
|
||||
|
||||
def set_unmeaningful(self, *refs):
|
||||
for ref in refs:
|
||||
if ref in self._range:
|
||||
@ -377,6 +382,7 @@ class Analyzer(object):
|
||||
raise TypeMismatchError(instr, '{} and {}'.format(src, name))
|
||||
else:
|
||||
context.set_written(dest)
|
||||
# FIXME: context.copy_range(src, dest) ?
|
||||
context.assert_meaningful(src)
|
||||
elif opcode == 'add':
|
||||
context.assert_meaningful(src, dest, FLAG_C)
|
||||
@ -395,6 +401,7 @@ class Analyzer(object):
|
||||
context.set_unmeaningful(REG_A)
|
||||
else:
|
||||
self.assert_type(TYPE_WORD, dest)
|
||||
context.invalidate_range(dest)
|
||||
elif opcode == 'sub':
|
||||
context.assert_meaningful(src, dest, FLAG_C)
|
||||
if src.type == TYPE_BYTE:
|
||||
@ -405,10 +412,12 @@ class Analyzer(object):
|
||||
context.set_written(dest, FLAG_Z, FLAG_N, FLAG_C, FLAG_V)
|
||||
context.set_touched(REG_A)
|
||||
context.set_unmeaningful(REG_A)
|
||||
context.invalidate_range(dest)
|
||||
elif opcode in ('inc', 'dec'):
|
||||
self.assert_type(TYPE_BYTE, dest)
|
||||
context.assert_meaningful(dest)
|
||||
context.set_written(dest, FLAG_Z, FLAG_N)
|
||||
context.invalidate_range(dest)
|
||||
elif opcode == 'cmp':
|
||||
self.assert_type(TYPE_BYTE, src, dest)
|
||||
context.assert_meaningful(src, dest)
|
||||
@ -425,10 +434,12 @@ class Analyzer(object):
|
||||
self.assert_type(TYPE_BYTE, src, dest)
|
||||
context.assert_meaningful(src, dest)
|
||||
context.set_written(dest, FLAG_Z, FLAG_N)
|
||||
context.invalidate_range(dest)
|
||||
elif opcode in ('shl', 'shr'):
|
||||
self.assert_type(TYPE_BYTE, dest)
|
||||
context.assert_meaningful(dest, FLAG_C)
|
||||
context.set_written(dest, FLAG_Z, FLAG_N, FLAG_C)
|
||||
context.invalidate_range(dest)
|
||||
elif opcode == 'call':
|
||||
type = instr.location.type
|
||||
if isinstance(type, VectorType):
|
||||
|
@ -623,6 +623,62 @@ This applies to `copy` as well.
|
||||
| }
|
||||
? RangeExceededError
|
||||
|
||||
`AND`'ing a register with a value ensures the range of the
|
||||
register will not exceed the range of the value. This can
|
||||
be used to "clip" the range of an index so that it fits in
|
||||
a table.
|
||||
|
||||
| word one: 77
|
||||
| word table[32] many
|
||||
|
|
||||
| routine main
|
||||
| inputs a, many, one
|
||||
| outputs many, one
|
||||
| trashes a, x, n, z
|
||||
| {
|
||||
| and a, 31
|
||||
| ld x, a
|
||||
| copy one, many + x
|
||||
| copy many + x, one
|
||||
| }
|
||||
= ok
|
||||
|
||||
Test for "clipping", but not enough.
|
||||
|
||||
| word one: 77
|
||||
| word table[32] many
|
||||
|
|
||||
| routine main
|
||||
| inputs a, many, one
|
||||
| outputs many, one
|
||||
| trashes a, x, n, z
|
||||
| {
|
||||
| and a, 63
|
||||
| ld x, a
|
||||
| copy one, many + x
|
||||
| copy many + x, one
|
||||
| }
|
||||
? RangeExceededError
|
||||
|
||||
If you alter the value after "clipping" it, the range can
|
||||
no longer be guaranteed.
|
||||
|
||||
| word one: 77
|
||||
| word table[32] many
|
||||
|
|
||||
| routine main
|
||||
| inputs a, many, one
|
||||
| outputs many, one
|
||||
| trashes a, x, n, z
|
||||
| {
|
||||
| and a, 31
|
||||
| ld x, a
|
||||
| inc x
|
||||
| copy one, many + x
|
||||
| copy many + x, one
|
||||
| }
|
||||
? RangeExceededError
|
||||
|
||||
### add ###
|
||||
|
||||
Can't `add` from or to a memory location that isn't initialized.
|
||||
|
Loading…
Reference in New Issue
Block a user