From 694d0881608ecd2f20ee0040c84d48690696c690 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Thu, 9 Feb 2023 03:13:52 +0100 Subject: [PATCH] some cleanups about asmsub return registers and types --- codeCore/src/prog8/code/SymbolTable.kt | 2 +- codeCore/src/prog8/code/SymbolTableMaker.kt | 9 +++++---- codeCore/src/prog8/code/ast/AstPrinter.kt | 2 +- codeCore/src/prog8/code/ast/AstStatements.kt | 5 ++--- .../src/prog8/codegen/cpu6502/AsmGen.kt | 6 +++--- .../src/prog8/codegen/cpu6502/AsmsubHelpers.kt | 16 ++++++++-------- .../prog8/codegen/cpu6502/ExpressionsAsmGen.kt | 4 ++-- .../src/prog8/codegen/cpu6502/Extensions.kt | 12 ++++++------ .../prog8/codegen/cpu6502/FunctionCallAsmGen.kt | 10 +++++----- .../codegen/cpu6502/assignment/AsmAssignment.kt | 4 ++-- .../cpu6502/assignment/AssignmentAsmGen.kt | 8 ++++---- .../prog8/codegen/intermediate/ExpressionGen.kt | 10 +++++----- .../src/prog8/codegen/intermediate/IRCodeGen.kt | 4 ++-- .../astprocessing/IntermediateAstMaker.kt | 9 +++------ 14 files changed, 49 insertions(+), 52 deletions(-) diff --git a/codeCore/src/prog8/code/SymbolTable.kt b/codeCore/src/prog8/code/SymbolTable.kt index 02ff6cfcd..20a5948c2 100644 --- a/codeCore/src/prog8/code/SymbolTable.kt +++ b/codeCore/src/prog8/code/SymbolTable.kt @@ -215,7 +215,7 @@ class StSub(name: String, val parameters: List, val retur class StRomSub(name: String, val address: UInt, val parameters: List, - val returns: List, + val returns: List, astNode: PtNode, position: Position) : StNode(name, StNodeType.ROMSUB, position, astNode) diff --git a/codeCore/src/prog8/code/SymbolTableMaker.kt b/codeCore/src/prog8/code/SymbolTableMaker.kt index 598ff749f..233b6ee52 100644 --- a/codeCore/src/prog8/code/SymbolTableMaker.kt +++ b/codeCore/src/prog8/code/SymbolTableMaker.kt @@ -40,11 +40,12 @@ class SymbolTableMaker(private val program: PtProgram, private val options: Comp val stNode = when(node) { is PtAsmSub -> { if(node.address==null) { - val params = node.parameters.map { StSubroutineParameter(it.first.name, it.first.type) } - StSub(node.name, params, node.returnTypes.singleOrNull(), node, node.position) + val params = node.parameters.map { StSubroutineParameter(it.second.name, it.second.type) } + StSub(node.name, params, node.returns.singleOrNull()?.second, node, node.position) } else { - val parameters = node.parameters.map { StRomSubParameter(it.second, it.first.type) } - StRomSub(node.name, node.address, parameters, node.retvalRegisters, node, node.position) + val parameters = node.parameters.map { StRomSubParameter(it.first, it.second.type) } + val returns = node.returns.map { StRomSubParameter(it.first, it.second) } + StRomSub(node.name, node.address, parameters, returns, node, node.position) } } is PtBlock -> { diff --git a/codeCore/src/prog8/code/ast/AstPrinter.kt b/codeCore/src/prog8/code/ast/AstPrinter.kt index 223cab1fa..cbaee7a0f 100644 --- a/codeCore/src/prog8/code/ast/AstPrinter.kt +++ b/codeCore/src/prog8/code/ast/AstPrinter.kt @@ -57,7 +57,7 @@ fun printAst(root: PtNode, output: (text: String) -> Unit) { is PtAsmSub -> { val params = if (node.parameters.isEmpty()) "" else "...TODO ${node.parameters.size} PARAMS..." val clobbers = if (node.clobbers.isEmpty()) "" else "clobbers ${node.clobbers}" - val returns = if (node.returnTypes.isEmpty()) "" else (if (node.returnTypes.size == 1) "-> ${node.returnTypes[0].name.lowercase()}" else "-> ${node.returnTypes.map { it.name.lowercase() }}") + val returns = if (node.returns.isEmpty()) "" else (if (node.returns.size == 1) "-> ${node.returns[0].second.name.lowercase()}" else "-> ${node.returns.map { it.second.name.lowercase() }}") val str = if (node.inline) "inline " else "" if(node.address==null) { str + "asmsub ${node.name}($params) $clobbers $returns" diff --git a/codeCore/src/prog8/code/ast/AstStatements.kt b/codeCore/src/prog8/code/ast/AstStatements.kt index 7f2caa30b..eaedfbb62 100644 --- a/codeCore/src/prog8/code/ast/AstStatements.kt +++ b/codeCore/src/prog8/code/ast/AstStatements.kt @@ -11,9 +11,8 @@ class PtAsmSub( name: String, val address: UInt?, val clobbers: Set, - val parameters: List>, - val returnTypes: List, // TODO join with registers below, as Pairs ? - val retvalRegisters: List, + val parameters: List>, + val returns: List>, val inline: Boolean, position: Position ) : PtNamedNode(name, position), IPtSubroutine { diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt index aede26605..5a88a64f4 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt @@ -2886,7 +2886,7 @@ $repeatLabel lda $counterVar } internal fun popCpuStack(asmsub: PtAsmSub, parameter: PtSubroutineParameter, reg: RegisterOrStatusflag) { - val shouldKeepA = asmsub.parameters.any { it.second.registerOrPair==RegisterOrPair.AX || it.second.registerOrPair==RegisterOrPair.AY} + val shouldKeepA = asmsub.parameters.any { it.first.registerOrPair==RegisterOrPair.AX || it.first.registerOrPair==RegisterOrPair.AY} if(reg.statusflag!=null) { if(shouldKeepA) out(" sta P8ZP_SCRATCH_REG") @@ -2961,8 +2961,8 @@ $repeatLabel lda $counterVar // note: because A is pushed first so popped last, saving A is often not required here. val targetAsmSub = (target as PtNode).definingAsmSub() if(targetAsmSub != null) { - val parameter = targetAsmSub.parameters.first { it.first.name==target.name } - popCpuStack(targetAsmSub, parameter.first, parameter.second) + val parameter = targetAsmSub.parameters.first { it.second.name==target.name } + popCpuStack(targetAsmSub, parameter.second, parameter.first) return } val scopedName = when(target) { diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmsubHelpers.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmsubHelpers.kt index 8b8e1f7e0..d6475cb7a 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmsubHelpers.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmsubHelpers.kt @@ -15,19 +15,19 @@ fun asmsub6502ArgsEvalOrder(sub: PtAsmSub): List { // 4) CPU Carry status flag // 5) the A register itself last (so everything before it can use the accumulator without having to save its value) val args = sub.parameters.withIndex() - val (cx16regs, args2) = args.partition { it.value.second.registerOrPair in Cx16VirtualRegisters } + val (cx16regs, args2) = args.partition { it.value.first.registerOrPair in Cx16VirtualRegisters } val pairedRegisters = arrayOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY) - val (pairedRegs , args3) = args2.partition { it.value.second.registerOrPair in pairedRegisters } - val (regsWithoutA, args4) = args3.partition { it.value.second.registerOrPair != RegisterOrPair.A } - val (regA, rest) = args4.partition { it.value.second.registerOrPair != null } + val (pairedRegs , args3) = args2.partition { it.value.first.registerOrPair in pairedRegisters } + val (regsWithoutA, args4) = args3.partition { it.value.first.registerOrPair != RegisterOrPair.A } + val (regA, rest) = args4.partition { it.value.first.registerOrPair != null } cx16regs.forEach { order += it.index } pairedRegs.forEach { order += it.index } regsWithoutA.forEach { - if(it.value.second.registerOrPair != RegisterOrPair.X) + if(it.value.first.registerOrPair != RegisterOrPair.X) order += it.index } - regsWithoutA.firstOrNull { it.value.second.registerOrPair==RegisterOrPair.X } ?.let { order += it.index} + regsWithoutA.firstOrNull { it.value.first.registerOrPair==RegisterOrPair.X } ?.let { order += it.index} rest.forEach { order += it.index } regA.forEach { order += it.index } require(order.size==sub.parameters.size) @@ -36,13 +36,13 @@ fun asmsub6502ArgsEvalOrder(sub: PtAsmSub): List { fun asmsub6502ArgsHaveRegisterClobberRisk( args: List, - params: List> + params: List> ): Boolean { fun isClobberRisk(expr: PtExpression): Boolean { when (expr) { is PtArrayIndexer -> { return params.any { - it.second.registerOrPair in listOf(RegisterOrPair.Y, RegisterOrPair.AY, RegisterOrPair.XY) + it.first.registerOrPair in listOf(RegisterOrPair.Y, RegisterOrPair.AY, RegisterOrPair.XY) } } is PtBuiltinFunctionCall -> { diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/ExpressionsAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/ExpressionsAsmGen.kt index 75298b6d4..8c6438787 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/ExpressionsAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/ExpressionsAsmGen.kt @@ -54,8 +54,8 @@ internal class ExpressionsAsmGen(private val program: PtProgram, } asmgen.restoreXafterCall(call) - val returns: List> = sub.returnsWhatWhere() - for ((_, reg) in returns) { + val returns: List> = sub.returnsWhatWhere() + for ((reg, _) in returns) { // result value is in cpu or status registers, put it on the stack instead (as we're evaluating an expression tree) if (reg.registerOrPair != null) { when (reg.registerOrPair!!) { diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/Extensions.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/Extensions.kt index e9a710505..cda0c0942 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/Extensions.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/Extensions.kt @@ -59,13 +59,13 @@ fun PtExpression.isSimple(): Boolean { } internal fun IPtSubroutine.regXasResult(): Boolean = - (this is PtAsmSub) && this.retvalRegisters.any { it.registerOrPair in arrayOf(RegisterOrPair.X, RegisterOrPair.AX, RegisterOrPair.XY) } + (this is PtAsmSub) && this.returns.any { it.first.registerOrPair in arrayOf(RegisterOrPair.X, RegisterOrPair.AX, RegisterOrPair.XY) } internal fun IPtSubroutine.shouldSaveX(): Boolean = this.regXasResult() || (this is PtAsmSub && (CpuRegister.X in this.clobbers || regXasParam())) internal fun PtAsmSub.regXasParam(): Boolean = - parameters.any { it.second.registerOrPair in arrayOf(RegisterOrPair.X, RegisterOrPair.AX, RegisterOrPair.XY) } + parameters.any { it.first.registerOrPair in arrayOf(RegisterOrPair.X, RegisterOrPair.AX, RegisterOrPair.XY) } internal class KeepAresult(val saveOnEntry: Boolean, val saveOnReturn: Boolean) @@ -74,14 +74,14 @@ internal fun PtAsmSub.shouldKeepA(): KeepAresult { // it seems that we never have to save A when calling? will be loaded correctly after setup. // but on return it depends on wether the routine returns something in A. - val saveAonReturn = retvalRegisters.any { it.registerOrPair==RegisterOrPair.A || it.registerOrPair==RegisterOrPair.AY || it.registerOrPair==RegisterOrPair.AX } + val saveAonReturn = returns.any { it.first.registerOrPair==RegisterOrPair.A || it.first.registerOrPair==RegisterOrPair.AY || it.first.registerOrPair==RegisterOrPair.AX } return KeepAresult(false, saveAonReturn) } -internal fun IPtSubroutine.returnsWhatWhere(): List> { +internal fun IPtSubroutine.returnsWhatWhere(): List> { when(this) { is PtAsmSub -> { - return returnTypes.zip(this.retvalRegisters) + return returns } is PtSub -> { // for non-asm subroutines, determine the return registers based on the type of the return value @@ -94,7 +94,7 @@ internal fun IPtSubroutine.returnsWhatWhere(): List RegisterOrStatusflag(RegisterOrPair.FAC1, null) else -> RegisterOrStatusflag(RegisterOrPair.AY, null) } - listOf(Pair(returntype!!, register)) + listOf(Pair(register, returntype!!)) } } } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt index 385242b12..6555673ef 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt @@ -106,7 +106,7 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as private fun argumentsViaRegisters(sub: PtAsmSub, call: PtFunctionCall) { if(sub.parameters.size==1) { - argumentViaRegister(sub, IndexedValue(0, sub.parameters.single().first), call.args[0]) + argumentViaRegister(sub, IndexedValue(0, sub.parameters.single().second), call.args[0]) } else { if(asmsub6502ArgsHaveRegisterClobberRisk(call.args, sub.parameters)) { registerArgsViaCpuStackEvaluation(call, sub) @@ -114,7 +114,7 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as asmsub6502ArgsEvalOrder(sub).forEach { val param = sub.parameters[it] val arg = call.args[it] - argumentViaRegister(sub, IndexedValue(it, param.first), arg) + argumentViaRegister(sub, IndexedValue(it, param.second), arg) } } } @@ -130,11 +130,11 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as // use the cpu hardware stack as intermediate storage for the arguments. val argOrder = asmsub6502ArgsEvalOrder(callee) argOrder.reversed().forEach { - asmgen.pushCpuStack(callee.parameters[it].first.type, call.args[it]) + asmgen.pushCpuStack(callee.parameters[it].second.type, call.args[it]) } argOrder.forEach { val param = callee.parameters[it] - asmgen.popCpuStack(callee, param.first, param.second) + asmgen.popCpuStack(callee, param.second, param.first) } } @@ -153,7 +153,7 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as throw AssemblyError("argument type incompatible") val paramRegister: RegisterOrStatusflag = when(sub) { - is PtAsmSub -> if(registerOverride==null) sub.parameters[parameter.index].second else RegisterOrStatusflag(registerOverride, null) + is PtAsmSub -> if(registerOverride==null) sub.parameters[parameter.index].first else RegisterOrStatusflag(registerOverride, null) is PtSub -> RegisterOrStatusflag(registerOverride!!, null) } val statusflag = paramRegister.statusflag diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AsmAssignment.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AsmAssignment.kt index 1ca125fc3..4ff83ae7e 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AsmAssignment.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AsmAssignment.kt @@ -60,7 +60,7 @@ internal class AsmAssignTarget(val kind: TargetStorageKind, if (parameter!=null) { val sub = parameter.definingAsmSub() if (sub!=null) { - val reg = sub.parameters.single { it.first===parameter }.second + val reg = sub.parameters.single { it.second===parameter }.first if(reg.statusflag!=null) throw AssemblyError("can't assign value to processor statusflag directly") else @@ -160,7 +160,7 @@ internal class AsmAssignSource(val kind: SourceStorageKind, is PtFunctionCall -> { val symbol = asmgen.symbolTable.lookup(value.name) val sub = symbol!!.astNode as IPtSubroutine - val returnType = sub.returnsWhatWhere().firstOrNull { rr -> rr.second.registerOrPair != null || rr.second.statusflag!=null }?.first + val returnType = sub.returnsWhatWhere().firstOrNull { rr -> rr.first.registerOrPair != null || rr.first.statusflag!=null }?.second ?: throw AssemblyError("can't translate zero return values in assignment") AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, returnType, expression = value) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index 6377798cb..14c328e97 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -181,8 +181,8 @@ internal class AssignmentAsmGen(private val program: PtProgram, val sub = symbol!!.astNode as IPtSubroutine asmgen.saveXbeforeCall(value) asmgen.translateFunctionCall(value) - val returnValue = sub.returnsWhatWhere().singleOrNull() { it.second.registerOrPair!=null } ?: sub.returnsWhatWhere().single() { it.second.statusflag!=null } - when (returnValue.first) { + val returnValue = sub.returnsWhatWhere().singleOrNull { it.first.registerOrPair!=null } ?: sub.returnsWhatWhere().single { it.first.statusflag!=null } + when (returnValue.second) { DataType.STR -> { asmgen.restoreXafterCall(value) when(assign.target.datatype) { @@ -203,7 +203,7 @@ internal class AssignmentAsmGen(private val program: PtProgram, } else -> { // do NOT restore X register before assigning the result values first - when (returnValue.second.registerOrPair) { + when (returnValue.first.registerOrPair) { RegisterOrPair.A -> assignRegisterByte(assign.target, CpuRegister.A) RegisterOrPair.X -> assignRegisterByte(assign.target, CpuRegister.X) RegisterOrPair.Y -> assignRegisterByte(assign.target, CpuRegister.Y) @@ -227,7 +227,7 @@ internal class AssignmentAsmGen(private val program: PtProgram, RegisterOrPair.R14 -> assignVirtualRegister(assign.target, RegisterOrPair.R14) RegisterOrPair.R15 -> assignVirtualRegister(assign.target, RegisterOrPair.R15) else -> { - val sflag = returnValue.second.statusflag + val sflag = returnValue.first.statusflag if(sflag!=null) assignStatusFlagByte(assign.target, sflag) else diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt index a93a39b5e..05fe03c67 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt @@ -988,20 +988,20 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { if(fcall.type==DataType.FLOAT) throw AssemblyError("doesn't support float register result in asm romsub") val returns = callTarget.returns.single() - val regStr = if(returns.registerOrPair!=null) returns.registerOrPair.toString() else returns.statusflag.toString() + val regStr = if(returns.register.registerOrPair!=null) returns.register.registerOrPair.toString() else returns.register.statusflag.toString() addInstr(result, IRInstruction(Opcode.LOADCPU, codeGen.irType(fcall.type), reg1=resultRegister, labelSymbol = regStr), null) } else -> { - val returnRegister = callTarget.returns.singleOrNull{ it.registerOrPair!=null } + val returnRegister = callTarget.returns.singleOrNull{ it.register.registerOrPair!=null } if(returnRegister!=null) { // we skip the other values returned in the status flags. - val regStr = returnRegister.registerOrPair.toString() + val regStr = returnRegister.register.registerOrPair.toString() addInstr(result, IRInstruction(Opcode.LOADCPU, codeGen.irType(fcall.type), reg1=resultRegister, labelSymbol = regStr), null) } else { - val firstReturnRegister = callTarget.returns.firstOrNull{ it.registerOrPair!=null } + val firstReturnRegister = callTarget.returns.firstOrNull{ it.register.registerOrPair!=null } if(firstReturnRegister!=null) { // we just take the first register return value and ignore the rest. - val regStr = firstReturnRegister.registerOrPair.toString() + val regStr = firstReturnRegister.register.registerOrPair.toString() addInstr(result, IRInstruction(Opcode.LOADCPU, codeGen.irType(fcall.type), reg1=resultRegister, labelSymbol = regStr), null) } else { throw AssemblyError("invalid number of return values from call") diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt index 2af57ae31..31a0bed03 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt @@ -1203,8 +1203,8 @@ class IRCodeGen( child.name, child.address, child.clobbers, - child.parameters.map { IRAsmSubroutine.IRAsmParam(it.second, it.first.type) }, // note: the name of the asmsub param is not used anymore. - child.returnTypes.zip(child.retvalRegisters).map { IRAsmSubroutine.IRAsmParam(it.second, it.first) }, + child.parameters.map { IRAsmSubroutine.IRAsmParam(it.first, it.second.type) }, // note: the name of the asmsub param is not used here anymore + child.returns.map { IRAsmSubroutine.IRAsmParam(it.first, it.second)}, asmChunk, child.position ) diff --git a/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt b/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt index f4cce7c4e..b4c0b7f3c 100644 --- a/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt +++ b/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt @@ -285,18 +285,15 @@ class IntermediateAstMaker(private val program: Program, private val options: Co } private fun transformAsmSub(srcSub: Subroutine): PtAsmSub { - val params = srcSub.parameters - .map { PtSubroutineParameter(it.name, it.type, it.position) } - .zip(srcSub.asmParameterRegisters) + val params = srcSub.asmParameterRegisters.zip(srcSub.parameters.map { PtSubroutineParameter(it.name, it.type, it.position) }) val sub = PtAsmSub(srcSub.name, srcSub.asmAddress, srcSub.asmClobbers, params, - srcSub.returntypes, - srcSub.asmReturnvaluesRegisters, + srcSub.asmReturnvaluesRegisters.zip(srcSub.returntypes), srcSub.inline, srcSub.position) - sub.parameters.forEach { it.first.parent=sub } + sub.parameters.forEach { it.second.parent=sub } if(srcSub.asmAddress==null) { var combinedTrueAsm = ""