mirror of
https://github.com/irmen/prog8.git
synced 2024-06-09 14:29:32 +00:00
multi assign
This commit is contained in:
parent
edc83305a4
commit
03e486c082
|
@ -34,7 +34,7 @@ fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Uni
|
||||||
str + node.name + "()"
|
str + node.name + "()"
|
||||||
}
|
}
|
||||||
is PtIdentifier -> "${node.name} ${type(node.type)}"
|
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 PtMemoryByte -> "@()"
|
||||||
is PtNumber -> {
|
is PtNumber -> {
|
||||||
val numstr = if(node.type == DataType.FLOAT) node.number.toString() else node.number.toHex()
|
val numstr = if(node.type == DataType.FLOAT) node.number.toString() else node.number.toHex()
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package prog8.codegen.intermediate
|
package prog8.codegen.intermediate
|
||||||
|
|
||||||
import prog8.code.StRomSub
|
import prog8.code.StRomSub
|
||||||
|
import prog8.code.StRomSubParameter
|
||||||
import prog8.code.ast.*
|
import prog8.code.ast.*
|
||||||
import prog8.code.core.*
|
import prog8.code.core.*
|
||||||
import prog8.intermediate.*
|
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")
|
?: throw AssemblyError("only asmsubs can return multiple values")
|
||||||
|
|
||||||
val result = mutableListOf<IRCodeChunkBase>()
|
val result = mutableListOf<IRCodeChunkBase>()
|
||||||
sub.returns.zip(assignment.children).forEach { (returns, target) ->
|
val funcCall = this.expressionEval.translate(values)
|
||||||
val singleAssign = PtAssignment(assignment.position)
|
require(funcCall.multipleResultRegs.size + funcCall.multipleResultFpRegs.size >= 2)
|
||||||
singleAssign.children.add(target)
|
if(funcCall.multipleResultFpRegs.isNotEmpty())
|
||||||
TODO("IR cannot store machine register results yet ${assignment.position}")
|
TODO("deal with (multiple?) FP return registers")
|
||||||
// singleAssign.children.add(PtMachineRegister(4242, returns.type, assignment.position))
|
|
||||||
// result += translateRegularAssign(singleAssign)
|
TODO("add to result multi return regs from expression")
|
||||||
}
|
// addToResult(result, funcCall, funcCall.resultReg, funcCall.resultFpReg)
|
||||||
return result
|
// 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 {
|
} else {
|
||||||
if (assignment.target.children.single() is PtIrRegister)
|
if (assignment.target.children.single() is PtIrRegister)
|
||||||
throw AssemblyError("assigning to a register should be done by just evaluating the expression into resultregister")
|
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 {
|
internal fun translate(augAssign: PtAugmentedAssign): IRCodeChunks {
|
||||||
// augmented assignment always has just a single target
|
// augmented assignment always has just a single target
|
||||||
if(augAssign.target.children.single() is PtIrRegister)
|
if(augAssign.target.children.single() is PtIrRegister)
|
||||||
|
|
|
@ -7,8 +7,11 @@ import prog8.code.core.*
|
||||||
import prog8.intermediate.*
|
import prog8.intermediate.*
|
||||||
|
|
||||||
|
|
||||||
internal class ExpressionCodeResult(val chunks: IRCodeChunks, val dt: IRDataType, val resultReg: Int, val resultFpReg: Int) {
|
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)
|
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 {
|
companion object {
|
||||||
val EMPTY: ExpressionCodeResult = ExpressionCodeResult(emptyList(), IRDataType.BYTE, -1, -1)
|
val EMPTY: ExpressionCodeResult = ExpressionCodeResult(emptyList(), IRDataType.BYTE, -1, -1)
|
||||||
|
@ -493,29 +496,40 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
||||||
else
|
else
|
||||||
argRegisters.add(FunctionCallArgs.ArgumentSpec("", null, FunctionCallArgs.RegSpec(paramDt, tr.resultReg, parameter.register)))
|
argRegisters.add(FunctionCallArgs.ArgumentSpec("", null, FunctionCallArgs.RegSpec(paramDt, tr.resultReg, parameter.register)))
|
||||||
result += tr.chunks
|
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
|
var statusFlagResult: Statusflag? = null
|
||||||
val returnRegSpec = if(fcall.void) null else {
|
val returnRegSpec = if(fcall.void) null else {
|
||||||
if(callTarget.returns.isEmpty())
|
if(callTarget.returns.isEmpty())
|
||||||
null
|
null
|
||||||
else if(callTarget.returns.size==1) {
|
val returns = callTarget.returns[0]
|
||||||
val returns = callTarget.returns[0]
|
val returnIrType = irType(returns.type)
|
||||||
val returnIrType = irType(returns.type)
|
if(returnIrType==IRDataType.FLOAT)
|
||||||
if(returnIrType==IRDataType.FLOAT)
|
FunctionCallArgs.RegSpec(returnIrType, codeGen.registers.nextFreeFloat(), returns.register)
|
||||||
FunctionCallArgs.RegSpec(returnIrType, codeGen.registers.nextFreeFloat(), returns.register)
|
else {
|
||||||
else {
|
val returnRegister = codeGen.registers.nextFree()
|
||||||
val returnRegister = codeGen.registers.nextFree()
|
FunctionCallArgs.RegSpec(returnIrType, returnRegister, returns.register)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// create the call
|
// 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(
|
private fun operatorGreaterThan(
|
||||||
binExpr: PtBinaryExpression,
|
binExpr: PtBinaryExpression,
|
||||||
vmDt: IRDataType,
|
vmDt: IRDataType,
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
%import diskio
|
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
%option no_sysinit
|
%option no_sysinit
|
||||||
|
|
||||||
|
@ -6,13 +5,25 @@ main {
|
||||||
sub start() {
|
sub start() {
|
||||||
bool @shared flag
|
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 {{
|
%asm {{
|
||||||
txa
|
txa
|
||||||
|
sec
|
||||||
rts
|
rts
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user