fix call parameters to be inside reg preserve logic

This commit is contained in:
Irmen de Jong 2017-12-25 02:07:17 +01:00
parent 4025d44b74
commit d0f5a9789b
4 changed files with 62 additions and 20 deletions

View File

@ -6,6 +6,7 @@ Written by Irmen de Jong (irmen@razorvine.net)
License: GNU GPL 3.0, see LICENSE License: GNU GPL 3.0, see LICENSE
""" """
import sys
import io import io
import math import math
import datetime import datetime
@ -435,7 +436,9 @@ class CodeGenerator:
raise NotImplementedError("decr by > 1") # XXX raise NotImplementedError("decr by > 1") # XXX
def generate_call(self, stmt: ParseResult.CallStmt) -> None: def generate_call(self, stmt: ParseResult.CallStmt) -> None:
# the argument assignments have already been generated via separate assignment statements. def generate_param_assignments():
for assign_stmt in stmt.desugared_call_arguments:
self.generate_assignment(assign_stmt)
if stmt.target.name: if stmt.target.name:
symblock, targetdef = self.cur_block.lookup(stmt.target.name) symblock, targetdef = self.cur_block.lookup(stmt.target.name)
else: else:
@ -451,9 +454,10 @@ class CodeGenerator:
return return
clobbered = set() # type: Set[str] clobbered = set() # type: Set[str]
if targetdef.clobbered_registers: if targetdef.clobbered_registers:
if stmt.preserve_regs: # @todo make this work with the separate assignment statements for the parameters.. :( if stmt.preserve_regs:
clobbered = targetdef.clobbered_registers clobbered = targetdef.clobbered_registers
with self.preserving_registers(clobbered): with self.preserving_registers(clobbered):
generate_param_assignments()
self.p("\t\tjsr " + targetstr) self.p("\t\tjsr " + targetstr)
return return
if isinstance(stmt.target, ParseResult.IndirectValue): if isinstance(stmt.target, ParseResult.IndirectValue):
@ -471,6 +475,7 @@ class CodeGenerator:
raise CodeError("missing name", stmt.target.value) raise CodeError("missing name", stmt.target.value)
if stmt.is_goto: if stmt.is_goto:
# no need to preserve registers for a goto # no need to preserve registers for a goto
generate_param_assignments()
if targetstr in REGISTER_WORDS: if targetstr in REGISTER_WORDS:
self.p("\t\tst{:s} {:s}".format(targetstr[0].lower(), Parser.to_hex(Zeropage.SCRATCH_B1))) self.p("\t\tst{:s} {:s}".format(targetstr[0].lower(), Parser.to_hex(Zeropage.SCRATCH_B1)))
self.p("\t\tst{:s} {:s}".format(targetstr[1].lower(), Parser.to_hex(Zeropage.SCRATCH_B2))) self.p("\t\tst{:s} {:s}".format(targetstr[1].lower(), Parser.to_hex(Zeropage.SCRATCH_B2)))
@ -480,6 +485,7 @@ class CodeGenerator:
else: else:
preserve_regs = {'A', 'X', 'Y'} if stmt.preserve_regs else set() preserve_regs = {'A', 'X', 'Y'} if stmt.preserve_regs else set()
with self.preserving_registers(preserve_regs): with self.preserving_registers(preserve_regs):
generate_param_assignments()
if targetstr in REGISTER_WORDS: if targetstr in REGISTER_WORDS:
if stmt.preserve_regs: if stmt.preserve_regs:
# cannot use zp scratch. This is very inefficient code! # cannot use zp scratch. This is very inefficient code!
@ -515,10 +521,13 @@ class CodeGenerator:
else: else:
raise CodeError("missing name", stmt.target) raise CodeError("missing name", stmt.target)
if stmt.is_goto: if stmt.is_goto:
# no need to preserve registers for a goto
generate_param_assignments()
self.p("\t\tjmp " + targetstr) self.p("\t\tjmp " + targetstr)
else: else:
preserve_regs = {'A', 'X', 'Y'} if stmt.preserve_regs else set() preserve_regs = {'A', 'X', 'Y'} if stmt.preserve_regs else set()
with self.preserving_registers(preserve_regs): with self.preserving_registers(preserve_regs):
generate_param_assignments()
self.p("\t\tjsr " + targetstr) self.p("\t\tjsr " + targetstr)
def generate_assignment(self, stmt: ParseResult.AssignmentStmt) -> None: def generate_assignment(self, stmt: ParseResult.AssignmentStmt) -> None:
@ -949,6 +958,9 @@ class Assembler64Tass:
print("\ncreating C-64 .prg") print("\ncreating C-64 .prg")
elif self.format == ProgramFormat.RAW: elif self.format == ProgramFormat.RAW:
print("\ncreating raw binary") print("\ncreating raw binary")
try:
subprocess.check_call(args) subprocess.check_call(args)
except FileNotFoundError as x:
raise SystemExit("ERROR: cannot run assembler program: "+str(x))
except subprocess.CalledProcessError as x: except subprocess.CalledProcessError as x:
print("assembler failed with returncode", x.returncode) print("assembler failed with returncode", x.returncode)

View File

@ -8,6 +8,7 @@ Written by Irmen de Jong (irmen@razorvine.net)
License: GNU GPL 3.0, see LICENSE License: GNU GPL 3.0, see LICENSE
""" """
import time
import os import os
import argparse import argparse
from .parse import Parser, Optimizer from .parse import Parser, Optimizer
@ -31,6 +32,7 @@ def main() -> None:
print("\n" + description) print("\n" + description)
start = time.perf_counter()
pp = PreprocessingParser(args.sourcefile) pp = PreprocessingParser(args.sourcefile)
sourcelines, symbols = pp.preprocess() sourcelines, symbols = pp.preprocess()
symbols.print_table(True) symbols.print_table(True)
@ -50,5 +52,7 @@ def main() -> None:
cg.write_assembly(out) cg.write_assembly(out)
assembler = Assembler64Tass(parsed.format) assembler = Assembler64Tass(parsed.format)
assembler.assemble(assembly_filename, program_filename) assembler.assemble(assembly_filename, program_filename)
duration_total = time.perf_counter() - start
print("Compile duration: {:.2f} seconds".format(duration_total))
print("Output file: ", program_filename) print("Output file: ", program_filename)
print() print()

View File

@ -406,18 +406,16 @@ class ParseResult:
self.arguments = arguments self.arguments = arguments
self.is_goto = is_goto self.is_goto = is_goto
self.preserve_regs = preserve_regs self.preserve_regs = preserve_regs
self.desugared_call_arguments = [] # type: List[ParseResult.AssignmentStmt]
def desugar_call_arguments(self, parser: 'Parser') -> List['ParseResult._AstNode']: def desugar_call_arguments(self, parser: 'Parser') -> None:
if not self.arguments: if self.arguments:
return [self] self.desugared_call_arguments.clear()
statements = [] # type: List[ParseResult._AstNode]
for name, value in self.arguments: for name, value in self.arguments:
assert name is not None, "all call arguments should have a name or be matched on a named parameter" assert name is not None, "all call arguments should have a name or be matched on a named parameter"
assignment = parser.parse_assignment("{:s}={:s}".format(name, value)) assignment = parser.parse_assignment("{:s}={:s}".format(name, value))
assignment.lineno = self.lineno assignment.lineno = self.lineno
statements.append(assignment) self.desugared_call_arguments.append(assignment)
statements.append(self)
return statements
class InlineAsm(_AstNode): class InlineAsm(_AstNode):
def __init__(self, lineno: int, asmlines: List[str]) -> None: def __init__(self, lineno: int, asmlines: List[str]) -> None:
@ -571,11 +569,7 @@ class Parser:
if isinstance(stmt, ParseResult.CallStmt): if isinstance(stmt, ParseResult.CallStmt):
self.sourceref.line = stmt.lineno self.sourceref.line = stmt.lineno
self.sourceref.column = 0 self.sourceref.column = 0
statements = stmt.desugar_call_arguments(self) stmt.desugar_call_arguments(self)
if len(statements) == 1:
block.statements[index] = statements[0]
else:
block.statements[index] = statements # type: ignore
block.flatten_statement_list() block.flatten_statement_list()
# desugar immediate string value assignments # desugar immediate string value assignments
for index, stmt in enumerate(list(block.statements)): for index, stmt in enumerate(list(block.statements)):
@ -1034,7 +1028,10 @@ class Parser:
and not isinstance(target.value, (ParseResult.IntegerValue, ParseResult.RegisterValue, ParseResult.MemMappedValue)): and not isinstance(target.value, (ParseResult.IntegerValue, ParseResult.RegisterValue, ParseResult.MemMappedValue)):
raise self.PError("cannot call that type of indirect symbol") raise self.PError("cannot call that type of indirect symbol")
address = target.address if isinstance(target, ParseResult.MemMappedValue) else None address = target.address if isinstance(target, ParseResult.MemMappedValue) else None
try:
_, symbol = self.lookup(targetstr) _, symbol = self.lookup(targetstr)
except ParseError:
symbol = None # it's probably a number or a register then
if isinstance(symbol, SubroutineDef): if isinstance(symbol, SubroutineDef):
# verify subroutine arguments # verify subroutine arguments
if len(arguments or []) != len(symbol.parameters): if len(arguments or []) != len(symbol.parameters):

View File

@ -135,5 +135,34 @@ start
c64.MOVFM!(#c64.FL_FR4) c64.MOVFM!(#c64.FL_FR4)
c64.FPRINTLN!() c64.FPRINTLN!()
reg_to_float
c64.CHROUT!(13)
A=34
X=99
Y=121
my_float = A
c64.MOVFM(#my_float)
c64.FPRINTLN()
my_float = X
c64.MOVFM(#my_float)
c64.FPRINTLN()
my_float = Y
c64.MOVFM(#my_float)
c64.FPRINTLN()
XY = 56789
;my_float = XY ; @todo support
c64.MOVFM(#my_float)
c64.FPRINTLN()
AX = 33221
;my_float = AX ; @todo support
c64.MOVFM(#my_float)
c64.FPRINTLN()
return return
} }