6502 codegen for multi-assigns

This commit is contained in:
Irmen de Jong 2024-03-25 22:15:41 +01:00
parent 2e37f5dee3
commit 9a27505315
5 changed files with 90 additions and 9 deletions

View File

@ -587,7 +587,10 @@ class AsmGen6502Internal (
is PtInlineAssembly -> translate(stmt)
is PtBuiltinFunctionCall -> builtinFunctionsAsmGen.translateFunctioncallStatement(stmt)
is PtFunctionCall -> functioncallAsmGen.translateFunctionCallStatement(stmt)
is PtAssignment -> assignmentAsmGen.translate(stmt)
is PtAssignment -> {
if(stmt.multiTarget) assignmentAsmGen.translateMultiAssign(stmt)
else assignmentAsmGen.translate(stmt)
}
is PtAugmentedAssign -> assignmentAsmGen.translate(stmt)
is PtJump -> {
val (asmLabel, indirect) = getJumpTarget(stmt)

View File

@ -1,6 +1,8 @@
package prog8.codegen.cpu6502.assignment
import prog8.code.StMemVar
import prog8.code.StRomSub
import prog8.code.StRomSubParameter
import prog8.code.StStaticVariable
import prog8.code.ast.*
import prog8.code.core.*
@ -32,6 +34,77 @@ internal class AssignmentAsmGen(private val program: PtProgram,
augmentableAsmGen.translate(assign, augmentedAssign.definingISub())
}
fun translateMultiAssign(assignment: PtAssignment) {
// TODO("translate multi-value assignment ${assignment.position}")
val values = assignment.value as? PtFunctionCall
?: throw AssemblyError("only function calls can return multiple values in a multi-assign")
val sub = asmgen.symbolTable.lookup(values.name) as? StRomSub
?: throw AssemblyError("only asmsubs can return multiple values")
require(sub.returns.size>=2)
if(sub.returns.any { it.type==DataType.FLOAT })
TODO("deal with (multiple?) FP return registers")
asmgen.translate(values)
fun needsToSaveA(registersResults: List<Pair<StRomSubParameter, PtNode>>): Boolean =
if(registersResults.isEmpty())
false
else if(registersResults.all { (it.second as PtAssignTarget).identifier!=null})
false
else
true
fun assignCarryResult(target: PtAssignTarget, saveA: Boolean) {
if(saveA) asmgen.out(" pha")
asmgen.out(" lda #0 | rol a")
val tgt = AsmAssignTarget.fromAstAssignment(target, target.definingISub(), asmgen)
assignRegisterByte(tgt, CpuRegister.A, false, false)
if(saveA) asmgen.out(" pla")
}
fun assignRegisterResults(registersResults: List<Pair<StRomSubParameter, PtNode>>) {
registersResults.forEach { (returns, target) ->
val targetIdent = (target as PtAssignTarget).identifier
val targetMem = target.memory
if(targetIdent!=null || targetMem!=null) {
val tgt = AsmAssignTarget.fromAstAssignment(target, target.definingISub(), asmgen)
when(returns.type) {
in ByteDatatypesWithBoolean -> {
assignRegisterByte(tgt, returns.register.registerOrPair!!.asCpuRegister(), false, false)
}
in WordDatatypes -> {
assignRegisterpairWord(tgt, returns.register.registerOrPair!!)
}
else -> throw AssemblyError("weird dt")
}
}
else TODO("array target for multi-value assignment") // Not done yet due to result register clobbering complexity
}
}
// because we can only handle integer results right now we can just zip() it all up
val (statusFlagResult, registersResults) = sub.returns.zip(assignment.children).partition { it.first.register.statusflag!=null }
if(statusFlagResult.isNotEmpty()) {
val (returns, target) = statusFlagResult.single()
if(returns.register.statusflag!=Statusflag.Pc)
TODO("other status flag for return value")
target as PtAssignTarget
if(registersResults.all { (it.second as PtAssignTarget).identifier!=null}) {
// all other results are just stored into identifiers directly so first handle those
// (simple store instructions that don't modify the carry flag)
assignRegisterResults(registersResults)
assignCarryResult(target, false)
return
}
assignCarryResult(target, needsToSaveA(registersResults))
}
assignRegisterResults(registersResults)
}
fun translateNormalAssignment(assign: AsmAssignment, scope: IPtSubroutine?) {
when(assign.source.kind) {
SourceStorageKind.LITERALBOOLEAN -> {

View File

@ -31,15 +31,12 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
val target = it.first.second as PtAssignTarget
result += assignCpuRegister(returns, regNumber, target)
}
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")
val chunks = translateRegularAssign(assignment)
chunks.filterIsInstance<IRCodeChunk>().firstOrNull()?.appendSrcPosition(assignment.position)
return chunks
return translateRegularAssign(assignment)
}
}

View File

@ -1,8 +1,8 @@
TODO
====
6502 codegen: make multi return value asmsub calls work.
add unit tests for vm and 6502 multi-assigns.
add docs for multi-assigns.
...

View File

@ -6,9 +6,9 @@ main {
bool @shared flag
cx16.r1=9999
; flag = test(42)
flag = test(42)
cx16.r0L, flag = test2(12345, 5566, flag, -42)
cx16.r0, flag = test3()
}
asmsub test(ubyte arg @A) -> bool @Pc {
@ -27,4 +27,12 @@ main {
rts
}}
}
asmsub test3() -> uword @AY, bool @Pc {
%asm {{
lda #0
ldy #0
rts
}}
}
}