From e2bb0de24d1478e42b1eeaca5dae255041e72fd1 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sat, 15 Jul 2023 13:04:14 +0200 Subject: [PATCH] clean up X register save/store in compiler code, remove temp vars for register saving --- .../src/prog8/code/core/BuiltinFunctions.kt | 2 - .../src/prog8/codegen/cpu6502/AsmGen.kt | 53 -------- .../codegen/cpu6502/BuiltinFunctionsAsmGen.kt | 47 ++----- .../src/prog8/codegen/cpu6502/Extensions.kt | 9 -- .../codegen/cpu6502/FunctionCallAsmGen.kt | 32 ----- .../codegen/cpu6502/PostIncrDecrAsmGen.kt | 5 - .../codegen/cpu6502/ProgramAndVarsGen.kt | 6 - .../cpu6502/assignment/AssignmentAsmGen.kt | 23 +--- .../assignment/AugmentableAssignmentAsmGen.kt | 124 ++++++++++++++---- .../codegen/intermediate/BuiltinFuncGen.kt | 5 +- docs/source/programming.rst | 7 +- docs/source/technical.rst | 34 ----- docs/source/todo.rst | 4 +- 13 files changed, 114 insertions(+), 237 deletions(-) diff --git a/codeCore/src/prog8/code/core/BuiltinFunctions.kt b/codeCore/src/prog8/code/core/BuiltinFunctions.kt index e1fef8abd..5a69b8024 100644 --- a/codeCore/src/prog8/code/core/BuiltinFunctions.kt +++ b/codeCore/src/prog8/code/core/BuiltinFunctions.kt @@ -124,9 +124,7 @@ val BuiltinFunctions: Map = mapOf( "push" to FSignature(false, listOf(FParam("value", ByteDatatypes)), null), "pushw" to FSignature(false, listOf(FParam("value", WordDatatypes)), null), "rsave" to FSignature(false, emptyList(), null), - "rsavex" to FSignature(false, emptyList(), null), "rrestore" to FSignature(false, emptyList(), null), - "rrestorex" to FSignature(false, emptyList(), null), "memory" to FSignature(true, listOf(FParam("name", arrayOf(DataType.STR)), FParam("size", arrayOf(DataType.UWORD)), FParam("alignment", arrayOf(DataType.UWORD))), DataType.UWORD), "callfar" to FSignature(false, listOf(FParam("bank", arrayOf(DataType.UBYTE)), FParam("address", arrayOf(DataType.UWORD)), FParam("arg", arrayOf(DataType.UWORD))), DataType.UWORD), ) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt index 877e0d94f..b5dc42ac9 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt @@ -393,32 +393,6 @@ class AsmGen6502Internal ( return name2.replace("prog8_lib.P8ZP_SCRATCH_", "P8ZP_SCRATCH_") // take care of the 'hooks' to the temp vars -> reference zp symbols directly } - internal fun saveRegisterLocal(register: CpuRegister, scope: IPtSubroutine) { - if (isTargetCpu(CpuType.CPU65c02)) { - // just use the cpu's stack for all registers, shorter code - when (register) { - CpuRegister.A -> out(" pha") - CpuRegister.X -> out(" phx") - CpuRegister.Y -> out(" phy") - } - } else { - when (register) { - CpuRegister.A -> { - // just use the stack, only for A - out(" pha") - } - CpuRegister.X -> { - out(" stx prog8_regsaveX") - subroutineExtra(scope).usedRegsaveX = true - } - CpuRegister.Y -> { - out(" sty prog8_regsaveY") - subroutineExtra(scope).usedRegsaveY = true - } - } - } - } - internal fun saveRegisterStack(register: CpuRegister, keepA: Boolean) { when (register) { CpuRegister.A -> out(" pha") @@ -443,24 +417,6 @@ class AsmGen6502Internal ( } } - internal fun restoreRegisterLocal(register: CpuRegister) { - if (isTargetCpu(CpuType.CPU65c02)) { - when (register) { - // this just used the stack, for all registers. Shorter code. - CpuRegister.A -> out(" pla") - CpuRegister.X -> out(" plx") - CpuRegister.Y -> out(" ply") - } - - } else { - when (register) { - CpuRegister.A -> out(" pla") // this just used the stack but only for A - CpuRegister.X -> out(" ldx prog8_regsaveX") - CpuRegister.Y -> out(" ldy prog8_regsaveY") - } - } - } - internal fun restoreRegisterStack(register: CpuRegister, keepA: Boolean) { when (register) { CpuRegister.A -> { @@ -586,12 +542,6 @@ class AsmGen6502Internal ( internal fun translateFunctionCall(functionCallExpr: PtFunctionCall) = functioncallAsmGen.translateFunctionCall(functionCallExpr) - internal fun saveXbeforeCall(functionCall: PtFunctionCall) = - functioncallAsmGen.saveXbeforeCall(functionCall) - - internal fun restoreXafterCall(functionCall: PtFunctionCall) = - functioncallAsmGen.restoreXafterCall(functionCall) - internal fun translateNormalAssignment(assign: AsmAssignment, scope: IPtSubroutine?) = assignmentAsmGen.translateNormalAssignment(assign, scope) @@ -3095,9 +3045,6 @@ $repeatLabel""") * it's more consistent to only define these attributes on a Subroutine node. */ internal class SubroutineExtraAsmInfo { - var usedRegsaveA = false - var usedRegsaveX = false - var usedRegsaveY = false var usedFloatEvalResultVar1 = false var usedFloatEvalResultVar2 = false diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt index 625f3817d..f8e815743 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/BuiltinFunctionsAsmGen.kt @@ -68,9 +68,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, asmgen.popCpuStack(DataType.UWORD, target, fcall.definingISub()) } "rsave" -> funcRsave() - "rsavex" -> funcRsaveX() "rrestore" -> funcRrestore() - "rrestorex" -> funcRrestoreX() "cmp" -> funcCmp(fcall) "callfar" -> funcCallFar(fcall) "prog8_lib_stringcompare" -> funcStringCompare(fcall) @@ -137,13 +135,6 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, lda P8ZP_SCRATCH_REG""") } - private fun funcRsaveX() { - if (asmgen.isTargetCpu(CpuType.CPU65c02)) - asmgen.out(" phx") - else - asmgen.out(" txa | pha") - } - private fun funcRrestore() { if (asmgen.isTargetCpu(CpuType.CPU65c02)) asmgen.out(""" @@ -161,13 +152,6 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, plp""") } - private fun funcRrestoreX() { - if (asmgen.isTargetCpu(CpuType.CPU65c02)) - asmgen.out(" plx") - else - asmgen.out(" sta P8ZP_SCRATCH_B1 | pla | tax | lda P8ZP_SCRATCH_B1") - } - private fun funcCallFar(fcall: PtBuiltinFunctionCall) { if(asmgen.options.compTarget.name != "cx16") throw AssemblyError("callfar only works on cx16 target at this time") @@ -445,16 +429,13 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, } else { val ptrAndIndex = asmgen.pointerViaIndexRegisterPossible(what.address) if(ptrAndIndex!=null) { - asmgen.saveRegisterLocal(CpuRegister.X, fcall.definingISub()!!) - asmgen.assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.X) - asmgen.saveRegisterLocal(CpuRegister.X, fcall.definingISub()!!) + asmgen.assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.A) + asmgen.saveRegisterStack(CpuRegister.A, true) asmgen.assignExpressionToRegister(ptrAndIndex.first, RegisterOrPair.AY) - asmgen.restoreRegisterLocal(CpuRegister.X) + asmgen.out(" sta (+) + 1 | sty (+) + 2") + asmgen.restoreRegisterStack(CpuRegister.X, false) asmgen.out(""" - sta (+) + 1 - sty (+) + 2 + ror ${'$'}ffff,x ; modified""") - asmgen.restoreRegisterLocal(CpuRegister.X) } else { asmgen.assignExpressionToRegister(what.address, RegisterOrPair.AY) asmgen.out(""" @@ -550,16 +531,13 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, } else { val ptrAndIndex = asmgen.pointerViaIndexRegisterPossible(what.address) if(ptrAndIndex!=null) { - asmgen.saveRegisterLocal(CpuRegister.X, fcall.definingISub()!!) - asmgen.assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.X) - asmgen.saveRegisterLocal(CpuRegister.X, fcall.definingISub()!!) + asmgen.assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.A) + asmgen.saveRegisterStack(CpuRegister.A, true) asmgen.assignExpressionToRegister(ptrAndIndex.first, RegisterOrPair.AY) - asmgen.restoreRegisterLocal(CpuRegister.X) + asmgen.out(" sta (+) + 1 | sty (+) + 2") + asmgen.restoreRegisterStack(CpuRegister.X, false) asmgen.out(""" - sta (+) + 1 - sty (+) + 2 + rol ${'$'}ffff,x ; modified""") - asmgen.restoreRegisterLocal(CpuRegister.X) } else { asmgen.assignExpressionToRegister(what.address, RegisterOrPair.AY) asmgen.out(""" @@ -677,7 +655,6 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, val varname = asmgen.asmVariableName(addrExpr) if(asmgen.isZpVar(addrExpr)) { // pointervar is already in the zero page, no need to copy - asmgen.saveRegisterLocal(CpuRegister.X, fcall.definingISub()!!) asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.AX) if (asmgen.isTargetCpu(CpuType.CPU65c02)) { asmgen.out(""" @@ -693,7 +670,6 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, iny sta ($varname),y""") } - asmgen.restoreRegisterLocal(CpuRegister.X) return } } @@ -703,18 +679,15 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, if(result!=null && pointer!=null && asmgen.isZpVar(pointer)) { // can do ZP,Y indexing val varname = asmgen.asmVariableName(pointer) - val scope = fcall.definingISub()!! - asmgen.saveRegisterLocal(CpuRegister.X, scope) asmgen.assignExpressionToRegister(result.second, RegisterOrPair.Y) - asmgen.saveRegisterLocal(CpuRegister.Y, scope) + asmgen.saveRegisterStack(CpuRegister.Y, false) asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.AX) - asmgen.restoreRegisterLocal(CpuRegister.Y) + asmgen.restoreRegisterStack(CpuRegister.Y, true) asmgen.out(""" sta ($varname),y txa iny sta ($varname),y""") - asmgen.restoreRegisterLocal(CpuRegister.X) return } } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/Extensions.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/Extensions.kt index b1e7628ba..7f56fcbed 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/Extensions.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/Extensions.kt @@ -6,15 +6,6 @@ import prog8.code.ast.PtSub import prog8.code.core.* -internal fun IPtSubroutine.regXasResult(): Boolean = - (this is PtAsmSub) && this.returns.any { it.first.registerOrPair in arrayOf(RegisterOrPair.X, RegisterOrPair.AX, RegisterOrPair.XY) } - -internal fun IPtSubroutine.shouldSaveX(): Boolean = - this.regXasResult() || (this is PtAsmSub && (CpuRegister.X in this.clobbers || regXasParam())) - -internal fun PtAsmSub.regXasParam(): Boolean = - parameters.any { it.first.registerOrPair in arrayOf(RegisterOrPair.X, RegisterOrPair.AX, RegisterOrPair.XY) } - internal class KeepAresult(val saveOnEntry: Boolean, val saveOnReturn: Boolean) internal fun PtAsmSub.shouldKeepA(): KeepAresult { diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt index 39e0191b3..abc7ed411 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt @@ -11,42 +11,10 @@ import prog8.codegen.cpu6502.assignment.TargetStorageKind internal class FunctionCallAsmGen(private val program: PtProgram, private val asmgen: AsmGen6502Internal) { internal fun translateFunctionCallStatement(stmt: PtFunctionCall) { - saveXbeforeCall(stmt) translateFunctionCall(stmt) - restoreXafterCall(stmt) // just ignore any result values from the function call. } - internal fun saveXbeforeCall(stmt: PtFunctionCall) { - val symbol = asmgen.symbolTable.lookup(stmt.name) - val sub = symbol!!.astNode as IPtSubroutine - if(sub.shouldSaveX()) { - if(sub is PtAsmSub) { - val regSaveOnStack = sub.address == null // rom-routines don't require registers to be saved on stack, normal subroutines do because they can contain nested calls - if (regSaveOnStack) - asmgen.saveRegisterStack(CpuRegister.X, sub.shouldKeepA().saveOnEntry) - else - asmgen.saveRegisterLocal(CpuRegister.X, stmt.definingISub()!!) - } else - asmgen.saveRegisterLocal(CpuRegister.X, stmt.definingISub()!!) - } - } - - internal fun restoreXafterCall(stmt: PtFunctionCall) { - val symbol = asmgen.symbolTable.lookup(stmt.name) - val sub = symbol!!.astNode as IPtSubroutine - if(sub.shouldSaveX()) { - if(sub is PtAsmSub) { - val regSaveOnStack = sub.address == null // rom-routines don't require registers to be saved on stack, normal subroutines do because they can contain nested calls - if (regSaveOnStack) - asmgen.restoreRegisterStack(CpuRegister.X, sub.shouldKeepA().saveOnReturn) - else - asmgen.restoreRegisterLocal(CpuRegister.X) - } else - asmgen.restoreRegisterLocal(CpuRegister.X) - } - } - internal fun optimizeIntArgsViaRegisters(sub: PtSub) = (sub.parameters.size==1 && sub.parameters[0].type in IntegerDatatypes) || (sub.parameters.size==2 && sub.parameters[0].type in ByteDatatypes && sub.parameters[1].type in ByteDatatypes) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/PostIncrDecrAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/PostIncrDecrAsmGen.kt index c92b706ca..327cada54 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/PostIncrDecrAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/PostIncrDecrAsmGen.kt @@ -13,7 +13,6 @@ internal class PostIncrDecrAsmGen(private val program: PtProgram, private val as val targetIdent = stmt.target.identifier val targetMemory = stmt.target.memory val targetArrayIdx = stmt.target.array - val scope = stmt.definingISub() when { targetIdent!=null -> { val what = asmgen.asmVariableName(targetIdent) @@ -76,7 +75,6 @@ internal class PostIncrDecrAsmGen(private val program: PtProgram, private val as dec ${asmArrayvarname}_msb+$constIndex + dec ${asmArrayvarname}_lsb+$constIndex""") } else { - asmgen.saveRegisterLocal(CpuRegister.X, scope!!) asmgen.loadScaledArrayIndexIntoRegister(targetArrayIdx, elementDt, CpuRegister.X) if(incr) asmgen.out(" inc ${asmArrayvarname}_lsb,x | bne + | inc ${asmArrayvarname}_msb,x |+") @@ -86,7 +84,6 @@ internal class PostIncrDecrAsmGen(private val program: PtProgram, private val as bne + dec ${asmArrayvarname}_msb,x + dec ${asmArrayvarname}_lsb,x""") - asmgen.restoreRegisterLocal(CpuRegister.X) } return } @@ -113,7 +110,6 @@ internal class PostIncrDecrAsmGen(private val program: PtProgram, private val as } else { - asmgen.saveRegisterLocal(CpuRegister.X, scope!!) asmgen.loadScaledArrayIndexIntoRegister(targetArrayIdx, elementDt, CpuRegister.X) when(elementDt) { in ByteDatatypes -> { @@ -141,7 +137,6 @@ internal class PostIncrDecrAsmGen(private val program: PtProgram, private val as } else -> throw AssemblyError("weird array elt dt") } - asmgen.restoreRegisterLocal(CpuRegister.X) } } } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt index 7346f326b..b4fe380ca 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt @@ -371,12 +371,6 @@ internal class ProgramAndVarsGen( else -> throw AssemblyError("weird dt for extravar $dt") } } - if(asmGenInfo.usedRegsaveA) // will probably never occur - asmgen.out("prog8_regsaveA .byte ?") - if(asmGenInfo.usedRegsaveX) - asmgen.out("prog8_regsaveX .byte ?") - if(asmGenInfo.usedRegsaveY) - asmgen.out("prog8_regsaveY .byte ?") if(asmGenInfo.usedFloatEvalResultVar1) asmgen.out("$subroutineFloatEvalResultVar1 .fill ${options.compTarget.machine.FLOAT_MEM_SIZE}") if(asmGenInfo.usedFloatEvalResultVar2) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index b926f8464..cb7cb02b7 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -189,12 +189,10 @@ internal class AssignmentAsmGen(private val program: PtProgram, is PtFunctionCall -> { val symbol = asmgen.symbolTable.lookup(value.name) val sub = symbol!!.astNode as IPtSubroutine - asmgen.saveXbeforeCall(value) asmgen.translateFunctionCall(value) val returnValue = sub.returnsWhatWhere().singleOrNull { it.first.registerOrPair!=null } ?: sub.returnsWhatWhere().single { it.first.statusflag!=null } when (returnValue.second) { DataType.STR -> { - asmgen.restoreXafterCall(value) when(assign.target.datatype) { DataType.UWORD -> { // assign the address of the string result value @@ -208,7 +206,6 @@ internal class AssignmentAsmGen(private val program: PtProgram, } DataType.FLOAT -> { // float result from function sits in FAC1 - asmgen.restoreXafterCall(value) assignFAC1float(assign.target) } else -> { @@ -244,8 +241,6 @@ internal class AssignmentAsmGen(private val program: PtProgram, throw AssemblyError("should be just one register byte result value") } } - // we've processed the result value in the X register by now, so it's now finally safe to restore it - asmgen.restoreXafterCall(value) } } } @@ -1221,9 +1216,9 @@ internal class AssignmentAsmGen(private val program: PtProgram, DataType.STR -> { // use subroutine assignExpressionToRegister(containment.element, RegisterOrPair.A, elementDt == DataType.BYTE) - asmgen.saveRegisterLocal(CpuRegister.A, containment.definingISub()!!) + asmgen.saveRegisterStack(CpuRegister.A, true) assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingISub(), symbol.astNode.position,"P8ZP_SCRATCH_W1"), varname) - asmgen.restoreRegisterLocal(CpuRegister.A) + asmgen.restoreRegisterStack(CpuRegister.A, false) val stringVal = (variable as PtVariable).value as PtString asmgen.out(" ldy #${stringVal.value.length}") asmgen.out(" jsr prog8_lib.containment_bytearray") @@ -1234,9 +1229,9 @@ internal class AssignmentAsmGen(private val program: PtProgram, } DataType.ARRAY_B, DataType.ARRAY_UB -> { assignExpressionToRegister(containment.element, RegisterOrPair.A, elementDt == DataType.BYTE) - asmgen.saveRegisterLocal(CpuRegister.A, containment.definingISub()!!) + asmgen.saveRegisterStack(CpuRegister.A, true) assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingISub(), symbol.astNode.position, "P8ZP_SCRATCH_W1"), varname) - asmgen.restoreRegisterLocal(CpuRegister.A) + asmgen.restoreRegisterStack(CpuRegister.A, false) asmgen.out(" ldy #$numElements") asmgen.out(" jsr prog8_lib.containment_bytearray") return @@ -1458,27 +1453,19 @@ internal class AssignmentAsmGen(private val program: PtProgram, when(valueDt) { DataType.UBYTE -> { assignExpressionToRegister(value, RegisterOrPair.Y, false) - asmgen.saveRegisterLocal(CpuRegister.X, origTypeCastExpression.definingISub()!!) asmgen.out(" jsr floats.FREADUY") - asmgen.restoreRegisterLocal(CpuRegister.X) } DataType.BYTE -> { assignExpressionToRegister(value, RegisterOrPair.A, true) - asmgen.saveRegisterLocal(CpuRegister.X, origTypeCastExpression.definingISub()!!) asmgen.out(" jsr floats.FREADSA") - asmgen.restoreRegisterLocal(CpuRegister.X) } DataType.UWORD -> { assignExpressionToRegister(value, RegisterOrPair.AY, false) - asmgen.saveRegisterLocal(CpuRegister.X, origTypeCastExpression.definingISub()!!) asmgen.out(" jsr floats.GIVUAYFAY") - asmgen.restoreRegisterLocal(CpuRegister.X) } DataType.WORD -> { assignExpressionToRegister(value, RegisterOrPair.AY, true) - asmgen.saveRegisterLocal(CpuRegister.X, origTypeCastExpression.definingISub()!!) asmgen.out(" jsr floats.GIVAYFAY") - asmgen.restoreRegisterLocal(CpuRegister.X) } else -> throw AssemblyError("invalid dt") } @@ -2154,12 +2141,10 @@ internal class AssignmentAsmGen(private val program: PtProgram, asmgen.out(" sta ${wordtarget.asmVarname}+$scaledIdx | sty ${wordtarget.asmVarname}+$scaledIdx+1") } else { - asmgen.saveRegisterLocal(CpuRegister.X, wordtarget.scope!!) asmgen.loadScaledArrayIndexIntoRegister(wordtarget.array, wordtarget.datatype, CpuRegister.X) asmgen.out(" lda $sourceName") asmgen.signExtendAYlsb(DataType.BYTE) asmgen.out(" sta ${wordtarget.asmVarname},x | inx | tya | sta ${wordtarget.asmVarname},x") - asmgen.restoreRegisterLocal(CpuRegister.X) } } TargetStorageKind.REGISTER -> { diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt index cff5a434b..af413afbb 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt @@ -105,17 +105,41 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } DataType.FLOAT -> { when(value.kind) { - SourceStorageKind.LITERALNUMBER -> inplaceModification_float_litval_to_variable(target.asmVarname, operator, value.number!!.number, target.scope!!) - SourceStorageKind.VARIABLE -> inplaceModification_float_variable_to_variable(target.asmVarname, operator, value.asmVarname, target.scope!!) - SourceStorageKind.REGISTER -> inplaceModification_float_variable_to_variable(target.asmVarname, operator, regName(value), target.scope!!) + SourceStorageKind.LITERALNUMBER -> inplaceModification_float_litval_to_variable( + target.asmVarname, + operator, + value.number!!.number + ) + SourceStorageKind.VARIABLE -> inplaceModification_float_variable_to_variable( + target.asmVarname, + operator, + value.asmVarname + ) + SourceStorageKind.REGISTER -> inplaceModification_float_variable_to_variable( + target.asmVarname, + operator, + regName(value) + ) SourceStorageKind.MEMORY -> TODO("memread into float") - SourceStorageKind.ARRAY -> inplaceModification_float_value_to_variable(target.asmVarname, operator, value.array!!, target.scope!!) + SourceStorageKind.ARRAY -> inplaceModification_float_value_to_variable( + target.asmVarname, + operator, + value.array!! + ) SourceStorageKind.EXPRESSION -> { if(value.expression is PtTypeCast) { if (tryInplaceModifyWithRemovedRedundantCast(value.expression, target, operator)) return - inplaceModification_float_value_to_variable(target.asmVarname, operator, value.expression, target.scope!!) + inplaceModification_float_value_to_variable( + target.asmVarname, + operator, + value.expression + ) } else { - inplaceModification_float_value_to_variable(target.asmVarname, operator, value.expression!!, target.scope!!) + inplaceModification_float_value_to_variable( + target.asmVarname, + operator, + value.expression!! + ) } } else -> throw AssemblyError("weird source type ${value.kind}") @@ -236,17 +260,41 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } DataType.FLOAT -> { when(value.kind) { - SourceStorageKind.LITERALNUMBER -> inplaceModification_float_litval_to_variable(targetVarName, operator, value.number!!.number, target.scope!!) - SourceStorageKind.VARIABLE -> inplaceModification_float_variable_to_variable(targetVarName, operator, value.asmVarname, target.scope!!) - SourceStorageKind.REGISTER -> inplaceModification_float_variable_to_variable(targetVarName, operator, regName(value), target.scope!!) + SourceStorageKind.LITERALNUMBER -> inplaceModification_float_litval_to_variable( + targetVarName, + operator, + value.number!!.number + ) + SourceStorageKind.VARIABLE -> inplaceModification_float_variable_to_variable( + targetVarName, + operator, + value.asmVarname + ) + SourceStorageKind.REGISTER -> inplaceModification_float_variable_to_variable( + targetVarName, + operator, + regName(value) + ) SourceStorageKind.MEMORY -> TODO("memread into float array") - SourceStorageKind.ARRAY -> inplaceModification_float_value_to_variable(targetVarName, operator, value.array!!, target.scope!!) + SourceStorageKind.ARRAY -> inplaceModification_float_value_to_variable( + targetVarName, + operator, + value.array!! + ) SourceStorageKind.EXPRESSION -> { if(value.expression is PtTypeCast) { if (tryInplaceModifyWithRemovedRedundantCast(value.expression, target, operator)) return - inplaceModification_float_value_to_variable(targetVarName, operator, value.expression, target.scope!!) + inplaceModification_float_value_to_variable( + targetVarName, + operator, + value.expression + ) } else { - inplaceModification_float_value_to_variable(targetVarName, operator, value.expression!!, target.scope!!) + inplaceModification_float_value_to_variable( + targetVarName, + operator, + value.expression!! + ) } } else -> throw AssemblyError("weird source type ${value.kind}") @@ -264,7 +312,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, return asmgen.loadScaledArrayIndexIntoRegister(target.array, DataType.UBYTE, CpuRegister.Y) asmgen.out(" lda ${target.array.variable.name},y | sta P8ZP_SCRATCH_B1") - asmgen.saveRegisterLocal(CpuRegister.Y, target.scope!!) + asmgen.saveRegisterStack(CpuRegister.Y, false) when(value.kind) { SourceStorageKind.LITERALNUMBER -> inplaceModification_byte_litval_to_variable("P8ZP_SCRATCH_B1", target.datatype, operator, value.number!!.number.toInt()) SourceStorageKind.VARIABLE -> inplaceModification_byte_variable_to_variable("P8ZP_SCRATCH_B1", target.datatype, operator, value.asmVarname) @@ -280,7 +328,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } else -> throw AssemblyError("weird source type ${value.kind}") } - asmgen.restoreRegisterLocal(CpuRegister.Y) + asmgen.restoreRegisterStack(CpuRegister.Y, false) asmgen.out(" lda P8ZP_SCRATCH_B1 | sta ${target.array.variable.name},y") } in WordDatatypes -> { @@ -336,18 +384,42 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, ldy #>$tempvar jsr floats.copy_float""") // copy from array into float temp var, clobbers A,Y when(value.kind) { - SourceStorageKind.LITERALNUMBER -> inplaceModification_float_litval_to_variable(tempvar, operator, value.number!!.number, target.scope!!) - SourceStorageKind.VARIABLE -> inplaceModification_float_variable_to_variable(tempvar, operator, value.asmVarname, target.scope!!) - SourceStorageKind.REGISTER -> inplaceModification_float_variable_to_variable(tempvar, operator, regName(value), target.scope!!) + SourceStorageKind.LITERALNUMBER -> inplaceModification_float_litval_to_variable( + tempvar, + operator, + value.number!!.number + ) + SourceStorageKind.VARIABLE -> inplaceModification_float_variable_to_variable( + tempvar, + operator, + value.asmVarname + ) + SourceStorageKind.REGISTER -> inplaceModification_float_variable_to_variable( + tempvar, + operator, + regName(value) + ) SourceStorageKind.MEMORY -> TODO("memread into float") - SourceStorageKind.ARRAY -> inplaceModification_float_value_to_variable(tempvar, operator, value.array!!, target.scope!!) + SourceStorageKind.ARRAY -> inplaceModification_float_value_to_variable( + tempvar, + operator, + value.array!! + ) SourceStorageKind.EXPRESSION -> { if(value.expression is PtTypeCast) { if (tryInplaceModifyWithRemovedRedundantCast(value.expression, target, operator)) return - inplaceModification_float_value_to_variable(tempvar, operator, value.expression, target.scope!!) + inplaceModification_float_value_to_variable( + tempvar, + operator, + value.expression + ) } else { - inplaceModification_float_value_to_variable(tempvar, operator, value.expression!!, target.scope!!) + inplaceModification_float_value_to_variable( + tempvar, + operator, + value.expression!! + ) } } else -> throw AssemblyError("weird source type ${value.kind}") @@ -2283,9 +2355,8 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } } - private fun inplaceModification_float_value_to_variable(name: String, operator: String, value: PtExpression, scope: IPtSubroutine) { + private fun inplaceModification_float_value_to_variable(name: String, operator: String, value: PtExpression) { asmgen.assignExpressionToRegister(value, RegisterOrPair.FAC1) - asmgen.saveRegisterLocal(CpuRegister.X, scope) when (operator) { "+" -> { asmgen.out(""" @@ -2327,11 +2398,9 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, ldy #>$name jsr floats.MOVMF """) - asmgen.restoreRegisterLocal(CpuRegister.X) } - private fun inplaceModification_float_variable_to_variable(name: String, operator: String, otherName: String, scope: IPtSubroutine) { - asmgen.saveRegisterLocal(CpuRegister.X, scope) + private fun inplaceModification_float_variable_to_variable(name: String, operator: String, otherName: String) { when (operator) { "+" -> { asmgen.out(""" @@ -2443,12 +2512,10 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, ldy #>$name jsr floats.MOVMF """) - asmgen.restoreRegisterLocal(CpuRegister.X) } - private fun inplaceModification_float_litval_to_variable(name: String, operator: String, value: Double, scope: IPtSubroutine) { + private fun inplaceModification_float_litval_to_variable(name: String, operator: String, value: Double) { val constValueName = allocator.getFloatAsmConst(value) - asmgen.saveRegisterLocal(CpuRegister.X, scope) when (operator) { "+" -> { if (value == 0.0) @@ -2566,6 +2633,5 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, ldy #>$name jsr floats.MOVMF """) - asmgen.restoreRegisterLocal(CpuRegister.X) } } diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt index cd4f60d84..d9aa7f056 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/BuiltinFuncGen.kt @@ -24,10 +24,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe "popw" -> funcPopw(call) "push" -> funcPush(call) "pushw" -> funcPushw(call) - "rsave", - "rsavex", - "rrestore", - "rrestorex" -> ExpressionCodeResult.EMPTY // vm doesn't have registers to save/restore + "rsave", "rrestore" -> ExpressionCodeResult.EMPTY // vm doesn't have registers to save/restore "callfar" -> funcCallfar(call) "msb" -> funcMsb(call) "lsb" -> funcLsb(call) diff --git a/docs/source/programming.rst b/docs/source/programming.rst index 2aa2131f7..05aa391f2 100644 --- a/docs/source/programming.rst +++ b/docs/source/programming.rst @@ -944,15 +944,12 @@ syscall (callnr), syscall1 (callnr, arg), syscall2 (callnr, arg1, arg2), syscall specific memory locations. So these builtin function calls are not useful yet except for experimentation in new code generation targets. -rsave, rsavex +rsave Saves all registers including status (or only X) on the stack - It's not needed to rsave()/rsavex() before an asm subroutine that clobbers the X register - (which is used by prog8 as the internal evaluation stack pointer); - the compiler will take care of this situation automatically. Note: the 16 bit 'virtual' registers of the Commander X16 are *not* saved, but you can use ``cx16.save_virtual_registers()`` for that. -rrestore, rrestorex +rrestore Restore all registers including status (or only X) back from the cpu hardware stack Note: the 16 bit 'virtual' registers of the Commander X16 are *not* restored, but you can use ``cx16.restore_virtual_registers()`` for that. diff --git a/docs/source/technical.rst b/docs/source/technical.rst index 77373c483..d2e2ea554 100644 --- a/docs/source/technical.rst +++ b/docs/source/technical.rst @@ -118,40 +118,6 @@ doing something with that returnvalue. This can be on purpose if you're simply n Use the ``void`` keyword in front of the subroutine call to get rid of the warning in that case. -The 6502 CPU's X-register: off-limits -------------------------------------- - -Prog8 uses the cpu's X-register as a pointer in its internal expression evaluation stack. -When only writing code in Prog8, this is taken care of behind the scenes for you by the compiler. -However when you are including or linking with assembly routines or Kernal/ROM calls that *do* -use the X register (either clobbering it internally, or using it as a parameter, or return value register), -those calls will destroy Prog8's stack pointer and this will result in invalid calculations. - -You should avoid using the X register in your assembly code, or take preparations. -If you make sure that the value of the X register is preserved before calling a routine -that uses it, and restored when the routine is done, you'll be ok. - -Routines that return a value in the X register can be called from Prog8 but the return value is -inaccessible unless you write a short piece of inline assembly code to deal with it yourself, such as:: - - ubyte returnvalue - - %asm {{ - stx P8ZP_SCRATCH_REG ; use 'phx/plx' if using 65c02 cpu - ldx #10 - jsr routine_using_x - stx returnvalue - ldx P8ZP_SCRATCH_REG - }} - ; now use 'returnvalue' variable - -Prog8 also provides some help to deal with this: - -- you should use a ``clobbers(X)`` specification for asmsub routines that modify the X register; the compiler will preserve it for you automatically when such a routine is called -- the ``rsavex()`` and ``rrestorex()`` builtin functions can preserve and restore the X register -- the ``rsave()`` and ``rrestore()`` builtin functions can preserve and restore *all* registers (but this is very slow and overkill if you only need to save X) - - Compiler Internals ------------------ diff --git a/docs/source/todo.rst b/docs/source/todo.rst index c092b815f..65c4fd82e 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -1,11 +1,11 @@ TODO ==== -- (branch): clean up all X register special handling +- (branch): clean up all X register special handling in p8 code inline asm +- (branch): clean up docs about eval stack and X register - (branch): fix optimizeCmpSequence in AsmOptimizer - (branch): fix inplaceModification TODO in AugmentableAssignmentAsmGen - (branch): fix up cx16/keyboardhandler.p8 X register shenanigans -- (branch): clean up docs about eval stack and X register - IR: instructions that do type conversion (SZ etc, CONCAT, SGN) should put the result in a DIFFERENT register. - IR: reduce the number of branch instructions (gradually), replace with CMP(I) + status branch instruction