mirror of
https://github.com/irmen/prog8.git
synced 2025-01-12 19:29:50 +00:00
only save A's value if needed for a return value
This commit is contained in:
parent
5f15794c3b
commit
96c700ee46
@ -758,6 +758,16 @@ class Subroutine(override val name: String,
|
||||
fun regXasResult() = asmReturnvaluesRegisters.any { it.registerOrPair in setOf(RegisterOrPair.X, RegisterOrPair.AX, RegisterOrPair.XY) }
|
||||
fun regXasParam() = asmParameterRegisters.any { it.registerOrPair in setOf(RegisterOrPair.X, RegisterOrPair.AX, RegisterOrPair.XY) }
|
||||
fun shouldSaveX() = CpuRegister.X in asmClobbers || regXasResult() || regXasParam()
|
||||
fun shouldKeepA(): Pair<Boolean, Boolean> {
|
||||
// determine if A's value should be kept when preparing for calling the subroutine, and when returning from it
|
||||
if(!isAsmSubroutine)
|
||||
return Pair(false, false)
|
||||
|
||||
// it seems that we never have to save A when calling? will be loaded correctly after setup.
|
||||
// but on return it depends on wether the routine returns something in A.
|
||||
val saveAonReturn = asmReturnvaluesRegisters.any { it.registerOrPair==RegisterOrPair.A || it.registerOrPair==RegisterOrPair.AY || it.registerOrPair==RegisterOrPair.AX }
|
||||
return Pair(false, saveAonReturn)
|
||||
}
|
||||
|
||||
fun amountOfRtsInAsm(): Int = statements
|
||||
.asSequence()
|
||||
|
@ -547,59 +547,82 @@ internal class AsmGen(private val program: Program,
|
||||
|
||||
private fun fixNameSymbols(name: String) = name.replace("<", "prog8_").replace(">", "") // take care of the autogenerated invalid (anon) label names
|
||||
|
||||
internal fun saveRegister(register: CpuRegister, scope: Subroutine, useStack: Boolean) {
|
||||
if(useStack) {
|
||||
when (register) {
|
||||
CpuRegister.A -> out(" pha")
|
||||
CpuRegister.X -> {
|
||||
if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) out(" phx")
|
||||
else out(" sta P8ZP_SCRATCH_REG | txa | pha | lda P8ZP_SCRATCH_REG")
|
||||
}
|
||||
CpuRegister.Y -> {
|
||||
if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) out(" phy")
|
||||
else out(" sta P8ZP_SCRATCH_REG | tya | pha | lda P8ZP_SCRATCH_REG")
|
||||
internal fun saveRegisterLocal(register: CpuRegister, scope: Subroutine) {
|
||||
when (register) {
|
||||
CpuRegister.A -> {
|
||||
out(" sta _prog8_regsaveA")
|
||||
scope.asmGenInfo.usedRegsaveA = true
|
||||
}
|
||||
CpuRegister.X -> {
|
||||
out(" stx _prog8_regsaveX")
|
||||
scope.asmGenInfo.usedRegsaveX = true
|
||||
}
|
||||
CpuRegister.Y -> {
|
||||
out(" sty _prog8_regsaveY")
|
||||
scope.asmGenInfo.usedRegsaveY = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun saveRegisterStack(register: CpuRegister, keepA: Boolean) {
|
||||
when (register) {
|
||||
CpuRegister.A -> out(" pha")
|
||||
CpuRegister.X -> {
|
||||
if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) out(" phx")
|
||||
else {
|
||||
if(keepA)
|
||||
out(" sta P8ZP_SCRATCH_REG | txa | pha | lda P8ZP_SCRATCH_REG")
|
||||
else
|
||||
out(" txa | pha")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
when (register) {
|
||||
CpuRegister.A -> {
|
||||
out(" sta _prog8_regsaveA")
|
||||
scope.asmGenInfo.usedRegsaveA = true
|
||||
}
|
||||
CpuRegister.X -> {
|
||||
out(" stx _prog8_regsaveX")
|
||||
scope.asmGenInfo.usedRegsaveX = true
|
||||
}
|
||||
CpuRegister.Y -> {
|
||||
out(" sty _prog8_regsaveY")
|
||||
scope.asmGenInfo.usedRegsaveY = true
|
||||
CpuRegister.Y -> {
|
||||
if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) out(" phy")
|
||||
else {
|
||||
if(keepA)
|
||||
out(" sta P8ZP_SCRATCH_REG | tya | pha | lda P8ZP_SCRATCH_REG")
|
||||
else
|
||||
out(" tya | pha")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun restoreRegister(register: CpuRegister, useStack: Boolean) {
|
||||
if(useStack) {
|
||||
when (register) {
|
||||
CpuRegister.A -> out(" pla")
|
||||
CpuRegister.X -> {
|
||||
if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) out(" plx")
|
||||
else out(" sta P8ZP_SCRATCH_REG | pla | tax | lda P8ZP_SCRATCH_REG")
|
||||
}
|
||||
CpuRegister.Y -> {
|
||||
if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) out(" ply")
|
||||
else out(" sta P8ZP_SCRATCH_REG | pla | tay | lda P8ZP_SCRATCH_REG")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
when (register) {
|
||||
CpuRegister.A -> out(" lda _prog8_regsaveA")
|
||||
CpuRegister.X -> out(" ldx _prog8_regsaveX")
|
||||
CpuRegister.Y -> out(" ldy _prog8_regsaveY")
|
||||
}
|
||||
internal fun restoreRegisterLocal(register: CpuRegister) {
|
||||
when (register) {
|
||||
CpuRegister.A -> out(" lda _prog8_regsaveA")
|
||||
CpuRegister.X -> out(" ldx _prog8_regsaveX")
|
||||
CpuRegister.Y -> out(" ldy _prog8_regsaveY")
|
||||
}
|
||||
}
|
||||
|
||||
internal fun restoreRegisterStack(register: CpuRegister, keepA: Boolean) {
|
||||
when (register) {
|
||||
CpuRegister.A -> {
|
||||
if(keepA)
|
||||
throw AssemblyError("can't set keepA if A is restored")
|
||||
out(" pla")
|
||||
}
|
||||
CpuRegister.X -> {
|
||||
if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) out(" plx")
|
||||
else {
|
||||
if(keepA)
|
||||
out(" sta P8ZP_SCRATCH_REG | pla | tax | lda P8ZP_SCRATCH_REG")
|
||||
else
|
||||
out(" pla | tax")
|
||||
}
|
||||
}
|
||||
CpuRegister.Y -> {
|
||||
if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) out(" ply")
|
||||
else {
|
||||
if(keepA)
|
||||
out(" sta P8ZP_SCRATCH_REG | pla | tay | lda P8ZP_SCRATCH_REG")
|
||||
else
|
||||
out(" pla | tay")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun translate(stmt: Statement) {
|
||||
outputSourceLine(stmt)
|
||||
|
@ -120,9 +120,9 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
||||
asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.R0)
|
||||
asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.R1)
|
||||
asmgen.assignExpressionToRegister(fcall.args[2], RegisterOrPair.A)
|
||||
asmgen.saveRegister(CpuRegister.X, scope, false)
|
||||
asmgen.saveRegisterLocal(CpuRegister.X, scope)
|
||||
asmgen.out(" jsr cx16.memory_fill")
|
||||
asmgen.restoreRegister(CpuRegister.X, false)
|
||||
asmgen.restoreRegisterLocal(CpuRegister.X)
|
||||
}
|
||||
"memcopy" -> {
|
||||
val count = fcall.args[2].constValue(program)?.number?.toInt()
|
||||
@ -138,9 +138,9 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
||||
asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.R0)
|
||||
asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.R1)
|
||||
asmgen.assignExpressionToRegister(fcall.args[2], RegisterOrPair.R2)
|
||||
asmgen.saveRegister(CpuRegister.X, scope, false)
|
||||
asmgen.saveRegisterLocal(CpuRegister.X, scope)
|
||||
asmgen.out(" jsr cx16.memory_copy")
|
||||
asmgen.restoreRegister(CpuRegister.X, false)
|
||||
asmgen.restoreRegisterLocal(CpuRegister.X)
|
||||
}
|
||||
"memsetw" -> {
|
||||
translateArguments(fcall.args, func, scope)
|
||||
|
@ -26,8 +26,13 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
|
||||
val sub = stmt.target.targetSubroutine(program.namespace) ?: throw AssemblyError("undefined subroutine ${stmt.target}")
|
||||
val saveX = sub.shouldSaveX()
|
||||
val regSaveOnStack = sub.asmAddress==null // rom-routines don't require registers to be saved on stack, normal subroutines do because they can contain nested calls
|
||||
if(saveX)
|
||||
asmgen.saveRegister(CpuRegister.X, (stmt as Node).definingSubroutine()!!, regSaveOnStack)
|
||||
val (keepAonEntry: Boolean, keepAonReturn: Boolean) = sub.shouldKeepA()
|
||||
if(saveX) {
|
||||
if(regSaveOnStack)
|
||||
asmgen.saveRegisterStack(CpuRegister.X, keepAonEntry)
|
||||
else
|
||||
asmgen.saveRegisterLocal(CpuRegister.X, (stmt as Node).definingSubroutine()!!)
|
||||
}
|
||||
|
||||
val subName = asmgen.asmSymbolName(stmt.target)
|
||||
if(stmt.args.isNotEmpty()) {
|
||||
@ -64,8 +69,12 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
|
||||
}
|
||||
}
|
||||
asmgen.out(" jsr $subName")
|
||||
if(saveX)
|
||||
asmgen.restoreRegister(CpuRegister.X, regSaveOnStack)
|
||||
if(saveX) {
|
||||
if(regSaveOnStack)
|
||||
asmgen.restoreRegisterStack(CpuRegister.X, keepAonReturn)
|
||||
else
|
||||
asmgen.restoreRegisterLocal(CpuRegister.X)
|
||||
}
|
||||
}
|
||||
|
||||
private fun registerArgsViaStackEvaluation(stmt: IFunctionCall, sub: Subroutine) {
|
||||
|
@ -91,7 +91,7 @@ internal class PostIncrDecrAsmGen(private val program: Program, private val asmg
|
||||
else
|
||||
{
|
||||
asmgen.loadScaledArrayIndexIntoRegister(targetArrayIdx, elementDt, CpuRegister.A)
|
||||
asmgen.saveRegister(CpuRegister.X, scope!!, false)
|
||||
asmgen.saveRegisterLocal(CpuRegister.X, scope!!)
|
||||
asmgen.out(" tax")
|
||||
when(elementDt) {
|
||||
in ByteDatatypes -> {
|
||||
@ -119,7 +119,7 @@ internal class PostIncrDecrAsmGen(private val program: Program, private val asmg
|
||||
}
|
||||
else -> throw AssemblyError("weird array elt dt")
|
||||
}
|
||||
asmgen.restoreRegister(CpuRegister.X, false)
|
||||
asmgen.restoreRegisterLocal(CpuRegister.X)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2000,9 +2000,9 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
|
||||
asmgen.storeByteIntoPointer(addressExpr, null)
|
||||
}
|
||||
else -> {
|
||||
asmgen.saveRegister(register, memoryAddress.definingSubroutine()!!, true)
|
||||
asmgen.saveRegisterStack(register, false)
|
||||
assignExpressionToVariable(addressExpr, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null)
|
||||
asmgen.restoreRegister(CpuRegister.A, true)
|
||||
asmgen.restoreRegisterStack(CpuRegister.A, false)
|
||||
asmgen.out(" ldy #0 | sta (P8ZP_SCRATCH_W2),y")
|
||||
}
|
||||
}
|
||||
|
@ -1417,7 +1417,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
|
||||
private fun inplaceModification_float_value_to_variable(name: String, operator: String, value: Expression, scope: Subroutine) {
|
||||
asmgen.assignExpressionToRegister(value, RegisterOrPair.FAC1)
|
||||
asmgen.saveRegister(CpuRegister.X, scope, false)
|
||||
asmgen.saveRegisterLocal(CpuRegister.X, scope)
|
||||
when (operator) {
|
||||
"**" -> {
|
||||
asmgen.out("""
|
||||
@ -1463,7 +1463,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
ldy #>$name
|
||||
jsr floats.MOVMF
|
||||
""")
|
||||
asmgen.restoreRegister(CpuRegister.X, false)
|
||||
asmgen.restoreRegisterLocal(CpuRegister.X)
|
||||
}
|
||||
|
||||
private fun inplaceModification_float_variable_to_variable(name: String, operator: String, ident: IdentifierReference, scope: Subroutine) {
|
||||
@ -1472,7 +1472,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
throw AssemblyError("float variable expected")
|
||||
|
||||
val otherName = asmgen.asmVariableName(ident)
|
||||
asmgen.saveRegister(CpuRegister.X, scope, false)
|
||||
asmgen.saveRegisterLocal(CpuRegister.X, scope)
|
||||
when (operator) {
|
||||
"**" -> {
|
||||
if(CompilationTarget.instance is Cx16Target) {
|
||||
@ -1545,12 +1545,12 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
ldy #>$name
|
||||
jsr floats.MOVMF
|
||||
""")
|
||||
asmgen.restoreRegister(CpuRegister.X, false)
|
||||
asmgen.restoreRegisterLocal(CpuRegister.X)
|
||||
}
|
||||
|
||||
private fun inplaceModification_float_litval_to_variable(name: String, operator: String, value: Double, scope: Subroutine) {
|
||||
val constValueName = asmgen.getFloatAsmConst(value)
|
||||
asmgen.saveRegister(CpuRegister.X, scope, false)
|
||||
asmgen.saveRegisterLocal(CpuRegister.X, scope)
|
||||
when (operator) {
|
||||
"**" -> {
|
||||
if(CompilationTarget.instance is Cx16Target) {
|
||||
@ -1630,7 +1630,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
|
||||
ldy #>$name
|
||||
jsr floats.MOVMF
|
||||
""")
|
||||
asmgen.restoreRegister(CpuRegister.X, false)
|
||||
asmgen.restoreRegisterLocal(CpuRegister.X)
|
||||
}
|
||||
|
||||
private fun inplaceCast(target: AsmAssignTarget, cast: TypecastExpression, position: Position) {
|
||||
|
@ -69,14 +69,22 @@ _y .byte 0
|
||||
}}
|
||||
}
|
||||
|
||||
sub start () {
|
||||
asmsub withasm(uword foo @R0, ubyte arg1 @A, ubyte arg2 @Y) clobbers(X) -> ubyte @A {
|
||||
%asm {{
|
||||
sty P8ZP_SCRATCH_REG
|
||||
clc
|
||||
adc P8ZP_SCRATCH_REG
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
||||
txt.print("status 8: ")
|
||||
uword ss = diskio.status(8)
|
||||
txt.print(ss)
|
||||
txt.print("\nstatus 9: ")
|
||||
ss = diskio.status(9)
|
||||
txt.print(ss)
|
||||
sub derp(uword aa)-> uword {
|
||||
return 9999+aa
|
||||
}
|
||||
|
||||
sub start () {
|
||||
ubyte ss = withasm(derp(1), 33,66)
|
||||
txt.print_ub(ss)
|
||||
txt.chrout('\n')
|
||||
|
||||
; cx16.r0 = 65535
|
||||
|
@ -4,7 +4,6 @@
|
||||
%import test_stack
|
||||
%zeropage floatsafe
|
||||
|
||||
; TODO WHY is this a couple of 100 bytes larger than a few hours ago?
|
||||
|
||||
main {
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user