improve register arg passing again

This commit is contained in:
Irmen de Jong 2020-09-07 02:29:03 +02:00
parent 90c4a26d52
commit 137d506e42
2 changed files with 68 additions and 35 deletions

View File

@ -65,44 +65,77 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
// this is called when one or more of the arguments are 'complex' and
// cannot be assigned to a register easily or risk clobbering other registers.
// make sure the X register is loaded last so we can "safely" destroy the estack pointer
val argsOrig = stmt.args.zip(sub.asmParameterRegisters)
val args = mutableListOf<Pair<Expression, RegisterOrStatusflag>>()
for(argOrig in argsOrig) {
if(argOrig.second.registerOrPair in setOf(RegisterOrPair.X, RegisterOrPair.AX, RegisterOrPair.XY))
args.add(argOrig)
else
args.add(0, argOrig)
}
if(sub.parameters.isEmpty())
return
for (arg in args.reversed())
asmgen.translateExpression(arg.first)
for (arg in args) {
val regparam = arg.second
// 1. load all arguments reversed onto the stack: first arg goes last (is on top).
for (arg in stmt.args.reversed())
asmgen.translateExpression(arg)
var argForCarry: IndexedValue<Pair<Expression, RegisterOrStatusflag>>? = null
var argForXregister: IndexedValue<Pair<Expression, RegisterOrStatusflag>>? = null
var argForAregister: IndexedValue<Pair<Expression, RegisterOrStatusflag>>? = null
asmgen.out(" inx") // align estack pointer
for(argi in stmt.args.zip(sub.asmParameterRegisters).withIndex()) {
when {
regparam.statusflag==Statusflag.Pc -> {
asmgen.out("""
inx
pha
lda P8ESTACK_LO,x
beq +
sec
bcs ++
+ clc
+ pla""")
argi.value.second.stack -> TODO("asmsub @stack parameter")
argi.value.second.statusflag == Statusflag.Pc -> {
require(argForCarry == null)
argForCarry = argi
}
regparam.statusflag!=null -> {
throw AssemblyError("can only use Carry as status flag parameter")
argi.value.second.statusflag != null -> throw AssemblyError("can only use Carry as status flag parameter")
argi.value.second.registerOrPair in setOf(RegisterOrPair.X, RegisterOrPair.AX, RegisterOrPair.XY) -> {
require(argForXregister==null)
argForXregister = argi
}
regparam.registerOrPair!=null -> {
val tgt = AsmAssignTarget.fromRegisters(regparam.registerOrPair, program, asmgen)
val source = AsmAssignSource(SourceStorageKind.STACK, program, tgt.datatype)
val asgn = AsmAssignment(source, tgt, false, Position.DUMMY)
asmgen.translateNormalAssignment(asgn)
argi.value.second.registerOrPair in setOf(RegisterOrPair.A, RegisterOrPair.AY) -> {
require(argForAregister == null)
argForAregister = argi
}
else -> {}
argi.value.second.registerOrPair == RegisterOrPair.Y -> {
asmgen.out(" ldy P8ESTACK_LO+${argi.index},x")
}
else -> throw AssemblyError("weird argument")
}
}
if(argForCarry!=null) {
asmgen.out("""
lda P8ESTACK_LO+${argForCarry.index},x
beq +
sec
bcs ++
+ clc
+ php""") // push the status flags
}
if(argForAregister!=null) {
when(argForAregister.value.second.registerOrPair) {
RegisterOrPair.A -> asmgen.out(" lda P8ESTACK_LO+${argForAregister.index},x")
RegisterOrPair.AY -> asmgen.out(" lda P8ESTACK_LO+${argForAregister.index},x | ldy P8ESTACK_HI+${argForAregister.index},x")
else -> throw AssemblyError("weird arg")
}
}
if(argForXregister!=null) {
if(argForAregister!=null)
asmgen.out(" pha")
when(argForXregister.value.second.registerOrPair) {
RegisterOrPair.X -> asmgen.out(" lda P8ESTACK_LO+${argForXregister.index},x | tax")
RegisterOrPair.AX -> asmgen.out(" ldy P8ESTACK_LO+${argForXregister.index},x | lda P8ESTACK_HI+${argForXregister.index},x | tax | tya")
RegisterOrPair.XY -> asmgen.out(" ldy P8ESTACK_HI+${argForXregister.index},x | lda P8ESTACK_LO+${argForXregister.index},x | tax")
else -> throw AssemblyError("weird arg")
}
if(argForAregister!=null)
asmgen.out(" pla")
} else {
repeat(sub.parameters.size - 1) { asmgen.out(" inx") } // unwind stack
}
if(argForCarry!=null)
asmgen.out(" plp") // set the carry flag back to correct value
}
private fun argumentViaVariable(sub: Subroutine, parameter: IndexedValue<SubroutineParameter>, value: Expression) {

View File

@ -260,16 +260,16 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
DataType.UBYTE, DataType.BYTE -> {
when(target.register!!) {
RegisterOrPair.A -> asmgen.out(" inx | lda P8ESTACK_LO,x")
RegisterOrPair.X -> asmgen.out(" inx | lda P8ESTACK_LO,x | tax")
RegisterOrPair.X -> throw AssemblyError("can't load X from stack here - use intermediary var? ${target.origAstTarget?.position}")
RegisterOrPair.Y -> asmgen.out(" inx | ldy P8ESTACK_LO,x")
else -> throw AssemblyError("can't assign byte to register pair word")
}
}
DataType.UWORD, DataType.WORD, in PassByReferenceDatatypes -> {
when(target.register!!) {
RegisterOrPair.AX -> asmgen.out(" inx | lda P8ESTACK_LO,x | pha | lda P8ESTACK_HI,x | tax | pla")
RegisterOrPair.AX -> throw AssemblyError("can't load X from stack here - use intermediary var? ${target.origAstTarget?.position}")
RegisterOrPair.AY-> asmgen.out(" inx | lda P8ESTACK_LO,x | ldy P8ESTACK_HI,x")
RegisterOrPair.XY-> asmgen.out(" inx | lda P8ESTACK_LO,x | ldy P8ESTACK_HI,x | tax")
RegisterOrPair.XY-> throw AssemblyError("can't load X from stack here - use intermediary var? ${target.origAstTarget?.position}")
else -> throw AssemblyError("can't assign word to single byte register")
}
}
@ -590,7 +590,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
TargetStorageKind.STACK -> {
when(register) {
CpuRegister.A -> asmgen.out(" sta P8ESTACK_LO,x | dex")
CpuRegister.X -> throw AssemblyError("can't store X itself on eval stack")
CpuRegister.X -> throw AssemblyError("can't use X here")
CpuRegister.Y -> asmgen.out(" tya | sta P8ESTACK_LO,x | dex")
}
}