multi assign

This commit is contained in:
Irmen de Jong 2024-03-22 21:45:58 +01:00
parent edc83305a4
commit 03e486c082
4 changed files with 108 additions and 32 deletions

View File

@ -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()

View File

@ -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<IRCodeChunkBase>()
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<IRCodeChunk>().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)

View File

@ -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<Int> = emptyList(), val multipleResultFpRegs: List<Int> = emptyList()
) {
constructor(chunk: IRCodeChunk, dt: IRDataType, resultReg: Int, resultFpReg: Int, multipleResultRegs: List<Int> = emptyList(), multipleResultFpRegs: List<Int> = 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,

View File

@ -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
}}
}