From 03e486c08232ef7ba90b7393a560f9e30fc476a1 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Fri, 22 Mar 2024 21:45:58 +0100 Subject: [PATCH] multi assign --- codeCore/src/prog8/code/ast/AstPrinter.kt | 2 +- .../codegen/intermediate/AssignmentGen.kt | 63 ++++++++++++++++--- .../codegen/intermediate/ExpressionGen.kt | 58 +++++++++++------ examples/test.p8 | 17 ++++- 4 files changed, 108 insertions(+), 32 deletions(-) diff --git a/codeCore/src/prog8/code/ast/AstPrinter.kt b/codeCore/src/prog8/code/ast/AstPrinter.kt index cfc4d8d58..c9294928c 100644 --- a/codeCore/src/prog8/code/ast/AstPrinter.kt +++ b/codeCore/src/prog8/code/ast/AstPrinter.kt @@ -34,7 +34,7 @@ fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Uni str + node.name + "()" } is PtIdentifier -> "${node.name} ${type(node.type)}" - is PtIrRegister -> "VMREG#${node.register} ${type(node.type)}" + is PtIrRegister -> "IRREG#${node.register} ${type(node.type)}" is PtMemoryByte -> "@()" is PtNumber -> { val numstr = if(node.type == DataType.FLOAT) node.number.toString() else node.number.toHex() diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt index 521e2746b..55d19dcb3 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt @@ -1,6 +1,7 @@ package prog8.codegen.intermediate import prog8.code.StRomSub +import prog8.code.StRomSubParameter import prog8.code.ast.* import prog8.code.core.* import prog8.intermediate.* @@ -17,14 +18,18 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express ?: throw AssemblyError("only asmsubs can return multiple values") val result = mutableListOf() - sub.returns.zip(assignment.children).forEach { (returns, target) -> - val singleAssign = PtAssignment(assignment.position) - singleAssign.children.add(target) - TODO("IR cannot store machine register results yet ${assignment.position}") - // singleAssign.children.add(PtMachineRegister(4242, returns.type, assignment.position)) - // result += translateRegularAssign(singleAssign) - } - return result + val funcCall = this.expressionEval.translate(values) + require(funcCall.multipleResultRegs.size + funcCall.multipleResultFpRegs.size >= 2) + if(funcCall.multipleResultFpRegs.isNotEmpty()) + TODO("deal with (multiple?) FP return registers") + + TODO("add to result multi return regs from expression") +// addToResult(result, funcCall, funcCall.resultReg, funcCall.resultFpReg) +// sub.returns.zip(assignment.children).forEach { (returns, target) -> +// result += assignCpuRegister(returns, funcCall, target as PtAssignTarget) +// } +// result.filterIsInstance().firstOrNull()?.appendSrcPosition(assignment.position) +// return result } else { if (assignment.target.children.single() is PtIrRegister) throw AssemblyError("assigning to a register should be done by just evaluating the expression into resultregister") @@ -35,6 +40,48 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express } } + private fun assignCpuRegister(returns: StRomSubParameter, target: PtAssignTarget): IRCodeChunk { + val targetIdentifier = target.identifier + val chunk = IRCodeChunk(null, null) + if(targetIdentifier!=null) { + TODO() + val regNum = 4242 // TODO?? + when(returns.register.registerOrPair) { + RegisterOrPair.A -> chunk += IRInstruction(Opcode.LOADHA, IRDataType.BYTE, reg1=regNum) + RegisterOrPair.X -> chunk += IRInstruction(Opcode.LOADHX, IRDataType.BYTE, reg1=regNum) + RegisterOrPair.Y -> chunk += IRInstruction(Opcode.LOADHY, IRDataType.BYTE, reg1=regNum) + RegisterOrPair.AX -> chunk += IRInstruction(Opcode.LOADHAX, IRDataType.WORD, reg1=regNum) + RegisterOrPair.AY -> chunk += IRInstruction(Opcode.LOADHAY, IRDataType.WORD, reg1=regNum) + RegisterOrPair.XY -> chunk += IRInstruction(Opcode.LOADHXY, IRDataType.WORD, reg1=regNum) + null -> { + when(returns.register.statusflag) { + Statusflag.Pc -> chunk += IRInstruction(Opcode.LOADHA, IRDataType.BYTE, reg1=regNum) + else -> throw AssemblyError("weird statusflag as returnvalue") + } + } + else -> throw AssemblyError("cannot load register") + } + chunk += IRInstruction(Opcode.STOREM, irType(target.type), reg1=regNum, labelSymbol = targetIdentifier.name) + return chunk + } + val targetMem = target.memory + if(targetMem!=null) { + TODO("assign $returns to $targetMem") + return chunk + } + val targetArray = target.array + if(targetArray!=null) { + TODO("assign $returns to $targetArray") + return chunk + } + throw AssemblyError("weird target") +// val singleAssign = PtAssignment(target.position) +// singleAssign.children.add(target) +// TODO("use the new IR instructions to store machine regs STOREHxx ${target.position}") + // singleAssign.children.add(PtMachineRegister(4242, returns.type, assignment.position)) + // result += translateRegularAssign(singleAssign) + } + internal fun translate(augAssign: PtAugmentedAssign): IRCodeChunks { // augmented assignment always has just a single target if(augAssign.target.children.single() is PtIrRegister) diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt index dc0140da8..1102e918b 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt @@ -7,8 +7,11 @@ import prog8.code.core.* import prog8.intermediate.* -internal class ExpressionCodeResult(val chunks: IRCodeChunks, val dt: IRDataType, val resultReg: Int, val resultFpReg: Int) { - constructor(chunks: IRCodeChunk, dt: IRDataType, resultReg: Int, resultFpReg: Int) : this(listOf(chunks), dt, resultReg, resultFpReg) +internal class ExpressionCodeResult(val chunks: IRCodeChunks, val dt: IRDataType, val resultReg: Int, val resultFpReg: Int, + val multipleResultRegs: List = emptyList(), val multipleResultFpRegs: List = emptyList() +) { + constructor(chunk: IRCodeChunk, dt: IRDataType, resultReg: Int, resultFpReg: Int, multipleResultRegs: List = emptyList(), multipleResultFpRegs: List = emptyList()) + : this(listOf(chunk), dt, resultReg, resultFpReg, multipleResultRegs, multipleResultFpRegs) companion object { val EMPTY: ExpressionCodeResult = ExpressionCodeResult(emptyList(), IRDataType.BYTE, -1, -1) @@ -493,29 +496,40 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { else argRegisters.add(FunctionCallArgs.ArgumentSpec("", null, FunctionCallArgs.RegSpec(paramDt, tr.resultReg, parameter.register))) result += tr.chunks + when(parameter.register.registerOrPair) { + RegisterOrPair.A -> addInstr(result, IRInstruction(Opcode.STOREHA, IRDataType.BYTE, reg1=tr.resultReg), null) + RegisterOrPair.X -> addInstr(result, IRInstruction(Opcode.STOREHX, IRDataType.BYTE, reg1=tr.resultReg), null) + RegisterOrPair.Y -> addInstr(result, IRInstruction(Opcode.STOREHY, IRDataType.BYTE, reg1=tr.resultReg), null) + RegisterOrPair.AX -> addInstr(result, IRInstruction(Opcode.STOREHAX, IRDataType.WORD, reg1=tr.resultReg), null) + RegisterOrPair.AY -> addInstr(result, IRInstruction(Opcode.STOREHAY, IRDataType.WORD, reg1=tr.resultReg), null) + RegisterOrPair.XY -> addInstr(result, IRInstruction(Opcode.STOREHXY, IRDataType.WORD, reg1=tr.resultReg), null) + in Cx16VirtualRegisters -> { + addInstr(result, IRInstruction(Opcode.STOREM, paramDt, reg1=tr.resultReg, labelSymbol = "cx16.${parameter.register.registerOrPair.toString().lowercase()}"), null) + } + null -> when(parameter.register.statusflag) { + // TODO: do the statusflag argument as last + Statusflag.Pc -> addInstr(result, IRInstruction(Opcode.LSR, paramDt, reg1=tr.resultReg), null) + else -> throw AssemblyError("weird statusflag as param") + } + else -> throw AssemblyError("unsupported register arg") + } } - // return value + + if(callTarget.returns.size>1) + return callWithMultipleReturnValues() + + // return a single value var statusFlagResult: Statusflag? = null val returnRegSpec = if(fcall.void) null else { if(callTarget.returns.isEmpty()) null - else if(callTarget.returns.size==1) { - val returns = callTarget.returns[0] - val returnIrType = irType(returns.type) - if(returnIrType==IRDataType.FLOAT) - FunctionCallArgs.RegSpec(returnIrType, codeGen.registers.nextFreeFloat(), returns.register) - else { - val returnRegister = codeGen.registers.nextFree() - FunctionCallArgs.RegSpec(returnIrType, returnRegister, returns.register) - } - } else { - // multiple return values: take the first *register* (not status flag) return value and ignore the rest. - val returns = callTarget.returns.first { it.register.registerOrPair!=null } - val returnIrType = irType(returns.type) - if(returnIrType==IRDataType.FLOAT) - FunctionCallArgs.RegSpec(returnIrType, codeGen.registers.nextFreeFloat(), returns.register) - else - FunctionCallArgs.RegSpec(returnIrType, codeGen.registers.nextFree(), returns.register) + val returns = callTarget.returns[0] + val returnIrType = irType(returns.type) + if(returnIrType==IRDataType.FLOAT) + FunctionCallArgs.RegSpec(returnIrType, codeGen.registers.nextFreeFloat(), returns.register) + else { + val returnRegister = codeGen.registers.nextFree() + FunctionCallArgs.RegSpec(returnIrType, returnRegister, returns.register) } } // create the call @@ -572,6 +586,10 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { } } + private fun callWithMultipleReturnValues(): ExpressionCodeResult { + TODO("call with multiple return values") + } + private fun operatorGreaterThan( binExpr: PtBinaryExpression, vmDt: IRDataType, diff --git a/examples/test.p8 b/examples/test.p8 index 916a98edf..5db5a26d5 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,4 +1,3 @@ -%import diskio %zeropage basicsafe %option no_sysinit @@ -6,13 +5,25 @@ main { sub start() { bool @shared flag - cx16.r0L = test(12345, flag, -42) + cx16.r1=9999 + ; flag = test(42) + cx16.r0L, flag = test2(12345, 5566, flag, -42) } - asmsub test(uword arg @AY, bool flag @Pc, byte value @X) -> ubyte @A, bool @Pc { + asmsub test(ubyte arg @A) -> bool @Pc { + %asm {{ + sec + rts + }} + } + + ; TODO cx16.r1 as return reg + + asmsub test2(uword arg @AY, uword arg2 @R1, bool flag @Pc, byte value @X) -> ubyte @A, bool @Pc { %asm {{ txa + sec rts }} }