From 5f2bf2b375a28c6fcc0af0d941dd2279f939e96d Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Wed, 16 Jan 2019 00:28:30 +0100 Subject: [PATCH] various regression fixes --- compiler/res/prog8lib/c64utils.p8 | 2 +- compiler/src/prog8/ast/StmtReorderer.kt | 6 ++ compiler/src/prog8/compiler/Compiler.kt | 19 ++---- .../intermediate/IntermediateProgram.kt | 10 ++- .../src/prog8/compiler/intermediate/Opcode.kt | 3 +- .../src/prog8/compiler/target/c64/AsmGen.kt | 7 +- compiler/src/prog8/stackvm/StackVm.kt | 3 +- examples/numbergame-lowlevel.p8 | 8 +-- examples/numbergame.p8 | 2 +- examples/test.p8 | 66 +++++++++++++------ 10 files changed, 71 insertions(+), 55 deletions(-) diff --git a/compiler/res/prog8lib/c64utils.p8 b/compiler/res/prog8lib/c64utils.p8 index b488057ce..0d28c53b9 100644 --- a/compiler/res/prog8lib/c64utils.p8 +++ b/compiler/res/prog8lib/c64utils.p8 @@ -259,7 +259,7 @@ _numlen - lda (c64.SCRATCH_ZPWORD1),y cmp #'0' bmi + - cmp #'9' + cmp #':' ; one after '9' bpl + iny bne - diff --git a/compiler/src/prog8/ast/StmtReorderer.kt b/compiler/src/prog8/ast/StmtReorderer.kt index 4c093e2ca..65830ab0c 100644 --- a/compiler/src/prog8/ast/StmtReorderer.kt +++ b/compiler/src/prog8/ast/StmtReorderer.kt @@ -14,6 +14,12 @@ class StatementReorderer(private val namespace: INameScope, private val heap: He // - the 'start' subroutine in the 'main' block will be moved to the top immediately following the directives. // - all other subroutines will be moved to the end of their block. + + // @todo sort the VariableInitializations and normal assignments: as long as the values are constants and they follow eachother without other stmts inbetween. something like this: + // // sort by datatype and value, so multiple initializations with the same value can be optimized (to load the value just once) + // val sortedInits = varinits.sortedWith(compareBy({it.value.resultingDatatype(namespace, heap)}, {it.value.constValue(namespace, heap)?.asNumericValue?.toDouble()})) + + private val directivesToMove = setOf("%output", "%launcher", "%zeropage", "%zpreserved", "%address", "%option") private val vardeclsToAdd = mutableMapOf>() diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 75f393dc8..e29f45b6f 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -183,10 +183,8 @@ private class StatementTranslator(private val prog: IntermediateProgram, prog.instr(Opcode.START_PROCDEF) prog.line(subroutine.position) // note: the caller has already written the arguments into the subroutine's parameter variables. - val (varinits, others) = subroutine.statements.partition { it is VariableInitializationAssignment } - val varInits: List = varinits as List - translateVarInits(varInits) - translate(others) + // note2: don't separate normal and VariableInitializationAssignment here, because the order strictly matters + translate(subroutine.statements) val r= super.process(subroutine) prog.instr(Opcode.END_PROCDEF) return r @@ -200,13 +198,6 @@ private class StatementTranslator(private val prog: IntermediateProgram, } } - private fun translateVarInits(varinits: List) { - // sort by datatype and value, so multiple initializations with the same value can be optimized (to load the value just once) - val sortedInits = varinits.sortedWith(compareBy({it.value.resultingDatatype(namespace, heap)}, {it.value.constValue(namespace, heap)?.asNumericValue?.toDouble()})) - for (vi in sortedInits) - translate(vi) - } - private fun translate(statements: List) { for (stmt: IStatement in statements) { generatedLabelSequenceNumber++ @@ -935,13 +926,13 @@ private class StatementTranslator(private val prog: IntermediateProgram, private fun translateSubroutineCall(subroutine: Subroutine, arguments: List, callPosition: Position) { // evaluate the arguments and assign them into the subroutine's argument variables. var restoreX = Register.X in subroutine.asmClobbers + if(restoreX) + prog.instr(Opcode.RSAVEX) + if(subroutine.isAsmSubroutine) { if(subroutine.parameters.size!=subroutine.asmParameterRegisters.size) throw CompilerException("no support for mix of register and non-register subroutine arguments") - if(restoreX) - prog.instr(Opcode.RSAVEX) - // only register arguments (or status-flag bits) var carryParam: Boolean? = null for(arg in arguments.zip(subroutine.asmParameterRegisters)) { diff --git a/compiler/src/prog8/compiler/intermediate/IntermediateProgram.kt b/compiler/src/prog8/compiler/intermediate/IntermediateProgram.kt index 13b7668da..3bb2e6b50 100644 --- a/compiler/src/prog8/compiler/intermediate/IntermediateProgram.kt +++ b/compiler/src/prog8/compiler/intermediate/IntermediateProgram.kt @@ -43,7 +43,7 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap optimizeVariableCopying() optimizeMultipleSequentialLineInstrs() optimizeCallReturnIntoJump() - optimizeRestoreXYSaveXYIntoRestoreXY() + optimizeRestoreXSaveXIntoRepopX() // todo: add more optimizations to stackvm code optimizeRemoveNops() // must be done as the last step @@ -57,16 +57,14 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap blk.instructions.removeIf { it.opcode== Opcode.NOP && it !is LabelInstr } } - private fun optimizeRestoreXYSaveXYIntoRestoreXY() { - // replace rrestorex/y+rsavex/y combo by only rrestorex/y + private fun optimizeRestoreXSaveXIntoRepopX() { + // replace rrestorex+rsavex combo by only repopX for(blk in blocks) { val instructionsToReplace = mutableMapOf() blk.instructions.asSequence().withIndex().filter {it.value.opcode!=Opcode.LINE}.windowed(2).toList().forEach { if(it[0].value.opcode==Opcode.RRESTOREX && it[1].value.opcode==Opcode.RSAVEX) { - instructionsToReplace[it[1].index] = Instruction(Opcode.NOP) - } - else if(it[0].value.opcode==Opcode.RRESTOREY && it[1].value.opcode==Opcode.RSAVEY) { + instructionsToReplace[it[0].index] = Instruction(Opcode.REPOPX) instructionsToReplace[it[1].index] = Instruction(Opcode.NOP) } } diff --git a/compiler/src/prog8/compiler/intermediate/Opcode.kt b/compiler/src/prog8/compiler/intermediate/Opcode.kt index a78f2e75c..fce9c1330 100644 --- a/compiler/src/prog8/compiler/intermediate/Opcode.kt +++ b/compiler/src/prog8/compiler/intermediate/Opcode.kt @@ -259,10 +259,9 @@ enum class Opcode { CLI, // clear irq-disable status flag RSAVE, // save all internal registers and status flags RSAVEX, // save just X (the evaluation stack pointer) - RSAVEY, // save just Y (used in for loops for instance) RRESTORE, // restore all internal registers and status flags RRESTOREX, // restore just X (the evaluation stack pointer) - RRESTOREY, // restore just Y (used in for loops for instance) + REPOPX, // restore just X (the evaluation stack pointer) but store it again too (essentially not erasing the value that's saved on the stack) NOP, // do nothing BREAKPOINT, // breakpoint diff --git a/compiler/src/prog8/compiler/target/c64/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/AsmGen.kt index 6997845ea..2a89f4fd8 100644 --- a/compiler/src/prog8/compiler/target/c64/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/AsmGen.kt @@ -479,10 +479,9 @@ class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, // restore all registers and cpu status flag " pla | tay | pla | tax | pla | plp" } - Opcode.RSAVEX -> " txa | pha" - Opcode.RRESTOREX -> " pla | tax" - Opcode.RSAVEY -> " tya | pha" - Opcode.RRESTOREY -> " pla | tay" + Opcode.RSAVEX -> " sta ${C64Zeropage.SCRATCH_REG} | txa | pha | lda ${C64Zeropage.SCRATCH_REG}" + Opcode.RRESTOREX -> " sta ${C64Zeropage.SCRATCH_REG} | pla | tax | lda ${C64Zeropage.SCRATCH_REG}" + Opcode.REPOPX -> " sta ${C64Zeropage.SCRATCH_REG} | pla | tax | pha | lda ${C64Zeropage.SCRATCH_REG}" Opcode.DISCARD_BYTE -> " inx" Opcode.DISCARD_WORD -> " inx" Opcode.DISCARD_FLOAT -> " inx | inx | inx" diff --git a/compiler/src/prog8/stackvm/StackVm.kt b/compiler/src/prog8/stackvm/StackVm.kt index 2c45c1ce5..cb8f6c105 100644 --- a/compiler/src/prog8/stackvm/StackVm.kt +++ b/compiler/src/prog8/stackvm/StackVm.kt @@ -1486,9 +1486,8 @@ class StackVm(private var traceOutputFile: String?) { P_irqd = evalstack.pop().asBooleanValue } Opcode.RSAVEX -> evalstack.push(variables["X"]) - Opcode.RSAVEY -> evalstack.push(variables["Y"]) Opcode.RRESTOREX -> variables["X"] = evalstack.pop() - Opcode.RRESTOREY -> variables["Y"] = evalstack.pop() + Opcode.REPOPX -> variables["X"] = evalstack.peek() Opcode.INLINE_ASSEMBLY -> throw VmExecutionException("stackVm doesn't support executing inline assembly code") Opcode.PUSH_ADDR_HEAPVAR -> { val heapId = variables[ins.callLabel]!!.heapId diff --git a/examples/numbergame-lowlevel.p8 b/examples/numbergame-lowlevel.p8 index ebf5d7061..5275ad462 100644 --- a/examples/numbergame-lowlevel.p8 +++ b/examples/numbergame-lowlevel.p8 @@ -8,11 +8,6 @@ ; It's less readable I think, but produces a smaller program. - -; @todo doesn't work correctly any longer and locks up at the end. Something seems broken in the if statements comparing the numbers. - - - ~ main { sub start() { str name = "????????????????????????????????????????" @@ -39,9 +34,10 @@ c64flt.FADDH() ; add 0.5.. c64flt.FADDH() ; and again, so +1 total A, Y = c64flt.GETADRAY() - secretnumber = A ; secret number = rnd()*100+1 + secretnumber = A ; secret number = rnd()*100+1 ask_guess: + c64.STROUT("\nYou have ") c64scr.print_ub(attempts_left) c64.STROUT(" guess") diff --git a/examples/numbergame.p8 b/examples/numbergame.p8 index 4c6ca7fbd..40dc05b26 100644 --- a/examples/numbergame.p8 +++ b/examples/numbergame.p8 @@ -33,7 +33,7 @@ return ending(true) } else { c64scr.print("\n\nThat is too ") - if guess