1
0
mirror of https://github.com/catseye/SixtyPical.git synced 2024-06-07 22:29:27 +00:00

Better generation of code at tail of routines.

This commit is contained in:
Chris Pressey 2019-10-22 11:37:00 +01:00
parent b9df1482c6
commit 44d97c33a2
5 changed files with 45 additions and 30 deletions

View File

@ -14,6 +14,9 @@ History of SixtyPical
* Added `--prune-unreachable-routines` option, which causes * Added `--prune-unreachable-routines` option, which causes
the compiler to in fact omit routines determined to be the compiler to in fact omit routines determined to be
unreachable as described above. unreachable as described above.
* Code generation now performs modest peephole optimization,
generating better code for `goto`s and `if` blocks at the
end of a routine.
* The `dcc6502-adapter` test adapter was updated to conform * The `dcc6502-adapter` test adapter was updated to conform
to the output of the latest version of `dcc6502`. to the output of the latest version of `dcc6502`.

View File

@ -90,11 +90,6 @@ if the block is in tail position. The constraints should iron out the same both
As long as the routine has consistent type context every place it exits, that should be fine. As long as the routine has consistent type context every place it exits, that should be fine.
### Branch optimization in `if`
Currently the `if` generator is not smart enough to avoid generating silly
jump instructions. (See the Fallthru tests.) Improve it.
Implementation Implementation
-------------- --------------

View File

@ -9,7 +9,7 @@ from sixtypical.model import (
TableType, PointerType, RoutineType, VectorType, TableType, PointerType, RoutineType, VectorType,
REG_A, REG_X, REG_Y, FLAG_C REG_A, REG_X, REG_Y, FLAG_C
) )
from sixtypical.emitter import Byte, Word, Table, Label, Offset, LowAddressByte, HighAddressByte from sixtypical.emitter import Byte, Word, Table, Label, Offset, LowAddressByte, HighAddressByte, Emitter
from sixtypical.gen6502 import ( from sixtypical.gen6502 import (
Immediate, Absolute, AbsoluteX, AbsoluteY, ZeroPage, Indirect, IndirectY, Relative, Immediate, Absolute, AbsoluteX, AbsoluteY, ZeroPage, Indirect, IndirectY, Relative,
LDA, LDX, LDY, STA, STX, STY, LDA, LDX, LDY, STA, STX, STY,
@ -157,17 +157,31 @@ class Compiler(object):
self.emitter.resolve_bss_label(label) self.emitter.resolve_bss_label(label)
def compile_routine(self, routine, next_routine=None): def compile_routine(self, routine, next_routine=None):
self.current_routine = routine
self.skip_final_goto = (next_routine is not None)
self.final_goto_seen = False
assert isinstance(routine, Routine) assert isinstance(routine, Routine)
self.current_routine = routine
saved_emitter = self.emitter
self.emitter = Emitter(saved_emitter.addr)
if routine.block: if routine.block:
self.emitter.resolve_label(self.get_label(routine.name)) self.emitter.resolve_label(self.get_label(routine.name))
self.compile_block(routine.block) self.compile_block(routine.block)
if not self.final_goto_seen:
needs_rts = True
if self.emitter.accum:
last_op = self.emitter.accum[-1]
if isinstance(last_op, JMP):
needs_rts = False
if isinstance(last_op.operand, Absolute):
if isinstance(last_op.operand.value, Label):
if next_routine and last_op.operand.value.name == next_routine.name:
self.emitter.retract()
if needs_rts:
self.emitter.emit(RTS()) self.emitter.emit(RTS())
saved_emitter.emit(*self.emitter.accum)
self.emitter = saved_emitter
self.current_routine = None self.current_routine = None
self.skip_final_goto = False
def compile_block(self, block): def compile_block(self, block):
assert isinstance(block, Block) assert isinstance(block, Block)
@ -441,19 +455,15 @@ class Compiler(object):
raise NotImplementedError(location_type) raise NotImplementedError(location_type)
def compile_goto(self, instr): def compile_goto(self, instr):
self.final_goto_seen = True location = instr.location
if self.skip_final_goto: label = self.get_label(instr.location.name)
pass location_type = self.get_type(location)
if isinstance(location_type, RoutineType):
self.emitter.emit(JMP(Absolute(label)))
elif isinstance(location_type, VectorType):
self.emitter.emit(JMP(Indirect(label)))
else: else:
location = instr.location raise NotImplementedError(location_type)
label = self.get_label(instr.location.name)
location_type = self.get_type(location)
if isinstance(location_type, RoutineType):
self.emitter.emit(JMP(Absolute(label)))
elif isinstance(location_type, VectorType):
self.emitter.emit(JMP(Indirect(label)))
else:
raise NotImplementedError(location_type)
def compile_cmp(self, instr, src, dest): def compile_cmp(self, instr, src, dest):
"""`instr` is only for reporting purposes""" """`instr` is only for reporting purposes"""
@ -666,12 +676,17 @@ class Compiler(object):
else_label = Label('else_label') else_label = Label('else_label')
self.emitter.emit(cls(Relative(else_label))) self.emitter.emit(cls(Relative(else_label)))
self.compile_block(instr.block1) self.compile_block(instr.block1)
if instr.block2 is not None: if instr.block2 is not None:
end_label = Label('end_label') if instr.block1.shallow_contains_goto:
self.emitter.emit(JMP(Absolute(end_label))) self.emitter.resolve_label(else_label)
self.emitter.resolve_label(else_label) self.compile_block(instr.block2)
self.compile_block(instr.block2) else:
self.emitter.resolve_label(end_label) end_label = Label('end_label')
self.emitter.emit(JMP(Absolute(end_label)))
self.emitter.resolve_label(else_label)
self.compile_block(instr.block2)
self.emitter.resolve_label(end_label)
else: else:
self.emitter.resolve_label(else_label) self.emitter.resolve_label(else_label)

View File

@ -171,6 +171,10 @@ class Emitter(object):
self.accum.append(thing) self.accum.append(thing)
self.addr += thing.size() self.addr += thing.size()
def retract(self):
thing = self.accum.pop()
self.addr -= thing.size()
def serialize_to(self, stream): def serialize_to(self, stream):
"""`stream` should be a file opened in binary mode.""" """`stream` should be a file opened in binary mode."""
addr = self.start_addr addr = self.start_addr

View File

@ -610,7 +610,6 @@ Compiling `repeat forever`.
= $080D LDY #$41 = $080D LDY #$41
= $080F INY = $080F INY
= $0810 JMP $080F = $0810 JMP $080F
= $0813 RTS
The body of `repeat forever` can be empty. The body of `repeat forever` can be empty.
@ -620,7 +619,6 @@ The body of `repeat forever` can be empty.
| } forever | } forever
| } | }
= $080D JMP $080D = $080D JMP $080D
= $0810 RTS
Compiling `for ... up to`. Compiling `for ... up to`.