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
"""
import sys
import io
import math
import datetime
@ -435,7 +436,9 @@ class CodeGenerator:
raise NotImplementedError("decr by > 1") # XXX
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:
symblock, targetdef = self.cur_block.lookup(stmt.target.name)
else:
@ -451,9 +454,10 @@ class CodeGenerator:
return
clobbered = set() # type: Set[str]
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
with self.preserving_registers(clobbered):
generate_param_assignments()
self.p("\t\tjsr " + targetstr)
return
if isinstance(stmt.target, ParseResult.IndirectValue):
@ -471,6 +475,7 @@ class CodeGenerator:
raise CodeError("missing name", stmt.target.value)
if stmt.is_goto:
# no need to preserve registers for a goto
generate_param_assignments()
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[1].lower(), Parser.to_hex(Zeropage.SCRATCH_B2)))
@ -480,6 +485,7 @@ class CodeGenerator:
else:
preserve_regs = {'A', 'X', 'Y'} if stmt.preserve_regs else set()
with self.preserving_registers(preserve_regs):
generate_param_assignments()
if targetstr in REGISTER_WORDS:
if stmt.preserve_regs:
# cannot use zp scratch. This is very inefficient code!
@ -515,10 +521,13 @@ class CodeGenerator:
else:
raise CodeError("missing name", stmt.target)
if stmt.is_goto:
# no need to preserve registers for a goto
generate_param_assignments()
self.p("\t\tjmp " + targetstr)
else:
preserve_regs = {'A', 'X', 'Y'} if stmt.preserve_regs else set()
with self.preserving_registers(preserve_regs):
generate_param_assignments()
self.p("\t\tjsr " + targetstr)
def generate_assignment(self, stmt: ParseResult.AssignmentStmt) -> None:
@ -949,6 +958,9 @@ class Assembler64Tass:
print("\ncreating C-64 .prg")
elif self.format == ProgramFormat.RAW:
print("\ncreating raw binary")
try:
subprocess.check_call(args)
except FileNotFoundError as x:
raise SystemExit("ERROR: cannot run assembler program: "+str(x))
except subprocess.CalledProcessError as x:
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
"""
import time
import os
import argparse
from .parse import Parser, Optimizer
@ -31,6 +32,7 @@ def main() -> None:
print("\n" + description)
start = time.perf_counter()
pp = PreprocessingParser(args.sourcefile)
sourcelines, symbols = pp.preprocess()
symbols.print_table(True)
@ -50,5 +52,7 @@ def main() -> None:
cg.write_assembly(out)
assembler = Assembler64Tass(parsed.format)
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()

View File

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

View File

@ -135,5 +135,34 @@ start
c64.MOVFM!(#c64.FL_FR4)
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
}