mirror of
https://github.com/irmen/prog8.git
synced 2024-12-23 09:32:43 +00:00
6502 codegen for multi-assigns
This commit is contained in:
parent
2e37f5dee3
commit
9a27505315
@ -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)
|
||||
|
@ -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 -> {
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
||||
...
|
||||
|
||||
|
@ -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
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user