From 3fc49c001e68c7a6029c7b2dae60fcd8d02f61b5 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Tue, 2 May 2023 23:09:42 +0200 Subject: [PATCH 01/16] IR: fix for-loop codegen when step<0 --- .../prog8/codegen/intermediate/IRCodeGen.kt | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt index 529e8121d..408bcc544 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt @@ -520,16 +520,36 @@ class IRCodeGen( addToResult(result, fromTr, fromTr.resultReg, -1) val labelAfterFor = createLabelName() - val greaterOpcode = if(loopvarDt in SignedDatatypes) Opcode.BGTSR else Opcode.BGTR - addInstr(result, IRInstruction(greaterOpcode, loopvarDtIr, fromTr.resultReg, toTr.resultReg, labelSymbol=labelAfterFor), null) + val precheckInstruction = if(loopvarDt in SignedDatatypes) { + if(step>0) + IRInstruction(Opcode.BGTSR, loopvarDtIr, fromTr.resultReg, toTr.resultReg, labelSymbol=labelAfterFor) + else + IRInstruction(Opcode.BGTSR, loopvarDtIr, toTr.resultReg, fromTr.resultReg, labelSymbol=labelAfterFor) + } else { + if(step>0) + IRInstruction(Opcode.BGTR, loopvarDtIr, fromTr.resultReg, toTr.resultReg, labelSymbol=labelAfterFor) + else + IRInstruction(Opcode.BGTR, loopvarDtIr, toTr.resultReg, fromTr.resultReg, labelSymbol=labelAfterFor) + } + addInstr(result, precheckInstruction, null) addInstr(result, IRInstruction(Opcode.STOREM, loopvarDtIr, reg1=fromTr.resultReg, labelSymbol=loopvarSymbol), null) result += labelFirstChunk(translateNode(forLoop.statements), loopLabel) result += addConstMem(loopvarDtIr, null, loopvarSymbol, step) addInstr(result, IRInstruction(Opcode.LOADM, loopvarDtIr, reg1 = fromTr.resultReg, labelSymbol = loopvarSymbol), null) // if endvalue >= index, iterate loop - val branchOpcode = if(loopvarDt in SignedDatatypes) Opcode.BGESR else Opcode.BGER - addInstr(result, IRInstruction(branchOpcode, loopvarDtIr, reg1=toTr.resultReg, reg2=fromTr.resultReg, labelSymbol=loopLabel), null) + val branchInstr = if(loopvarDt in SignedDatatypes) { + if(step>0) + IRInstruction(Opcode.BGESR, loopvarDtIr, reg1=toTr.resultReg, reg2=fromTr.resultReg, labelSymbol=loopLabel) + else + IRInstruction(Opcode.BGESR, loopvarDtIr, reg1=fromTr.resultReg, reg2=toTr.resultReg, labelSymbol=loopLabel) + } else { + if(step>0) + IRInstruction(Opcode.BGER, loopvarDtIr, reg1=toTr.resultReg, reg2=fromTr.resultReg, labelSymbol=loopLabel) + else + IRInstruction(Opcode.BGER, loopvarDtIr, reg1=fromTr.resultReg, reg2=toTr.resultReg, labelSymbol=loopLabel) + } + addInstr(result, branchInstr, null) result += IRCodeChunk(labelAfterFor, null) return result From add8a777d84c19c099dadb1289017a76a485468e Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Wed, 3 May 2023 22:31:04 +0200 Subject: [PATCH 02/16] IR: binarydata fixes --- .../intermediate/IRPeepholeOptimizer.kt | 41 ++++++++++++++++--- .../src/prog8/intermediate/IRFileWriter.kt | 1 - .../src/prog8/intermediate/IRInstructions.kt | 14 ++----- virtualmachine/src/prog8/vm/VirtualMachine.kt | 1 - .../src/prog8/vm/VmProgramLoader.kt | 8 ++-- virtualmachine/test/TestVm.kt | 16 -------- 6 files changed, 42 insertions(+), 39 deletions(-) diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/IRPeepholeOptimizer.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/IRPeepholeOptimizer.kt index 6c88761e3..b81b34abb 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/IRPeepholeOptimizer.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/IRPeepholeOptimizer.kt @@ -24,6 +24,7 @@ class IRPeepholeOptimizer(private val irprog: IRProgram) { private fun optimizeOnlyJoinChunks() { irprog.blocks.asSequence().flatMap { it.children.filterIsInstance() }.forEach { sub -> + joinChunks(sub) removeEmptyChunks(sub) joinChunks(sub) } @@ -32,6 +33,7 @@ class IRPeepholeOptimizer(private val irprog: IRProgram) { private fun peepholeOptimize() { irprog.blocks.asSequence().flatMap { it.children.filterIsInstance() }.forEach { sub -> + joinChunks(sub) removeEmptyChunks(sub) joinChunks(sub) sub.chunks.withIndex().forEach { (index, chunk1) -> @@ -112,7 +114,7 @@ class IRPeepholeOptimizer(private val irprog: IRProgram) { if(sub.chunks.isEmpty()) return - fun mayJoin(previous: IRCodeChunkBase, chunk: IRCodeChunkBase): Boolean { + fun mayJoinCodeChunks(previous: IRCodeChunkBase, chunk: IRCodeChunkBase): Boolean { if(chunk.label!=null) return false if(previous is IRCodeChunk && chunk is IRCodeChunk) { @@ -129,12 +131,39 @@ class IRPeepholeOptimizer(private val irprog: IRProgram) { chunks += sub.chunks[0] for(ix in 1 until sub.chunks.size) { val lastChunk = chunks.last() - if(mayJoin(lastChunk, sub.chunks[ix])) { - lastChunk.instructions += sub.chunks[ix].instructions - lastChunk.next = sub.chunks[ix].next + val candidate = sub.chunks[ix] + when(candidate) { + is IRCodeChunk -> { + if(mayJoinCodeChunks(lastChunk, candidate)) { + lastChunk.instructions += candidate.instructions + lastChunk.next = candidate.next + } + else + chunks += candidate + } + is IRInlineAsmChunk -> { + if(candidate.label!=null) + chunks += candidate + else if(lastChunk.isEmpty()) { + val label = lastChunk.label + if(label!=null) + chunks += IRInlineAsmChunk(label, candidate.assembly, candidate.isIR, candidate.next) + else + chunks += candidate + } + } + is IRInlineBinaryChunk -> { + if(candidate.label!=null) + chunks += candidate + else if(lastChunk.isEmpty()) { + val label = lastChunk.label + if(label!=null) + chunks += IRInlineBinaryChunk(label, candidate.data, candidate.next) + else + chunks += candidate + } + } } - else - chunks += sub.chunks[ix] } sub.chunks.clear() sub.chunks += chunks diff --git a/intermediate/src/prog8/intermediate/IRFileWriter.kt b/intermediate/src/prog8/intermediate/IRFileWriter.kt index 5521f04bb..1cb02ad92 100644 --- a/intermediate/src/prog8/intermediate/IRFileWriter.kt +++ b/intermediate/src/prog8/intermediate/IRFileWriter.kt @@ -140,7 +140,6 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) { private fun writeInlineBytes(chunk: IRInlineBinaryChunk) { xml.writeStartElement("BYTES") chunk.label?.let { xml.writeAttribute("LABEL", chunk.label) } - xml.writeCharacters("\n") chunk.data.withIndex().forEach {(index, byte) -> xml.writeCharacters(byte.toString(16).padStart(2,'0')) if(index and 63 == 63 && index < chunk.data.size-1) diff --git a/intermediate/src/prog8/intermediate/IRInstructions.kt b/intermediate/src/prog8/intermediate/IRInstructions.kt index a2921842e..bd0f26195 100644 --- a/intermediate/src/prog8/intermediate/IRInstructions.kt +++ b/intermediate/src/prog8/intermediate/IRInstructions.kt @@ -213,7 +213,6 @@ msig [b, w] reg1, reg2 - reg1 becomes the most significant by concat [b, w] reg1, reg2 - reg1 = concatenated lsb/lsw of reg1 (as lsb) and lsb/lsw of reg2 (as msb) into word or int (int not yet implemented; requires 32bits regs) push [b, w, f] reg1 - push value in reg1 on the stack pop [b, w, f] reg1 - pop value from stack into reg1 -binarydata - 'instruction' to hold inlined binary data bytes */ enum class Opcode { @@ -371,8 +370,7 @@ enum class Opcode { POP, MSIG, CONCAT, - BREAKPOINT, - BINARYDATA + BREAKPOINT } val OpcodesThatJump = setOf( @@ -650,7 +648,6 @@ val instructionFormats = mutableMapOf( Opcode.CLC to InstructionFormat.from("N"), Opcode.SEC to InstructionFormat.from("N"), Opcode.BREAKPOINT to InstructionFormat.from("N"), - Opcode.BINARYDATA to InstructionFormat.from("N"), ) @@ -664,9 +661,8 @@ data class IRInstruction( val immediate: Int?=null, // 0-$ff or $ffff if word val immediateFp: Float?=null, val address: Int?=null, // 0-$ffff - val labelSymbol: String?=null, // symbolic label name as alternative to value (so only for Branch/jump/call Instructions!) - val binaryData: Collection?=null, - var branchTarget: IRCodeChunkBase? = null // will be linked after loading + val labelSymbol: String?=null, // symbolic label name as alternative to address (so only for Branch/jump/call Instructions!) + var branchTarget: IRCodeChunkBase? = null // Will be linked after loading in IRProgram.linkChunks()! This is the chunk that the branch labelSymbol points to. ) { // reg1 and fpreg1 can be IN/OUT/INOUT (all others are readonly INPUT) // This knowledge is useful in IL assembly optimizers to see how registers are used. @@ -683,10 +679,6 @@ data class IRInstruction( require(fpReg2==null || fpReg2 in 0..65536) {"fpReg2 out of bounds"} if(reg1!=null && reg2!=null) require(reg1!=reg2) {"reg1 must not be same as reg2"} // note: this is ok for fpRegs as these are always the same type - require((opcode==Opcode.BINARYDATA && binaryData!=null) || (opcode!=Opcode.BINARYDATA && binaryData==null)) { - "binarydata inconsistency" - } - val formats = instructionFormats.getValue(opcode) require (type != null || formats.containsKey(null)) { "missing type" } diff --git a/virtualmachine/src/prog8/vm/VirtualMachine.kt b/virtualmachine/src/prog8/vm/VirtualMachine.kt index ee4537f67..f90ad90f0 100644 --- a/virtualmachine/src/prog8/vm/VirtualMachine.kt +++ b/virtualmachine/src/prog8/vm/VirtualMachine.kt @@ -284,7 +284,6 @@ class VirtualMachine(irProgram: IRProgram) { Opcode.BREAKPOINT -> InsBREAKPOINT() Opcode.CLC -> { statusCarry = false; nextPc() } Opcode.SEC -> { statusCarry = true; nextPc() } - Opcode.BINARYDATA -> TODO("BINARYDATA not yet supported in VM") Opcode.LOADCPU -> InsLOADCPU(ins) Opcode.STORECPU -> InsSTORECPU(ins) Opcode.STOREZCPU -> InsSTOREZCPU(ins) diff --git a/virtualmachine/src/prog8/vm/VmProgramLoader.kt b/virtualmachine/src/prog8/vm/VmProgramLoader.kt index 14ac964e1..aa9546439 100644 --- a/virtualmachine/src/prog8/vm/VmProgramLoader.kt +++ b/virtualmachine/src/prog8/vm/VmProgramLoader.kt @@ -46,7 +46,7 @@ class VmProgramLoader { is IRCodeChunk -> programChunks += child is IRInlineAsmChunk -> { val replacement = addAssemblyToProgram(child, programChunks, variableAddresses) - chunkReplacements += replacement + chunkReplacements += Pair(child, replacement) } is IRInlineBinaryChunk -> throw IRParseException("inline binary data not yet supported in the VM") // TODO is IRSubroutine -> { @@ -55,7 +55,7 @@ class VmProgramLoader { when (chunk) { is IRInlineAsmChunk -> { val replacement = addAssemblyToProgram(chunk, programChunks, variableAddresses) - chunkReplacements += replacement + chunkReplacements += Pair(chunk, replacement) } is IRInlineBinaryChunk -> throw IRParseException("inline binary data not yet supported in the VM") // TODO is IRCodeChunk -> programChunks += chunk @@ -339,7 +339,7 @@ class VmProgramLoader { asmChunk: IRInlineAsmChunk, chunks: MutableList, symbolAddresses: MutableMap, - ): Pair { + ): IRCodeChunk { if(asmChunk.isIR) { val chunk = IRCodeChunk(asmChunk.label, asmChunk.next) asmChunk.assembly.lineSequence().forEach { @@ -350,7 +350,7 @@ class VmProgramLoader { ) } chunks += chunk - return Pair(asmChunk, chunk) + return chunk } else { throw IRParseException("vm currently does not support real inlined assembly (only IR): ${asmChunk.label}") } diff --git a/virtualmachine/test/TestVm.kt b/virtualmachine/test/TestVm.kt index 24ab28a57..ec8956d86 100644 --- a/virtualmachine/test/TestVm.kt +++ b/virtualmachine/test/TestVm.kt @@ -70,22 +70,6 @@ class TestVm: FunSpec( { vm.stepCount shouldBe code.instructions.size } - test("vm asmbinary not supported") { - val program = IRProgram("test", IRSymbolTable(null), getTestOptions(), VMTarget()) - val block = IRBlock("testmain", null, false, false, IRBlock.BlockAlignment.NONE, Position.DUMMY) - val startSub = IRSubroutine("testmain.testsub", emptyList(), null, Position.DUMMY) - val code = IRCodeChunk(startSub.label, null) - code += IRInstruction(Opcode.BINARYDATA, binaryData = listOf(1u,2u,3u)) - code += IRInstruction(Opcode.RETURN) - startSub += code - block += startSub - program.addBlock(block) - val vm = VirtualMachine(program) - shouldThrowWithMessage("An operation is not implemented: BINARYDATA not yet supported in VM") { - vm.run() - } - } - test("asmsub not supported in vm even with IR") { val program = IRProgram("test", IRSymbolTable(null), getTestOptions(), VMTarget()) val block = IRBlock("main", null, false, false, IRBlock.BlockAlignment.NONE, Position.DUMMY) From f9926beeefc94902043cd83cc12430490350d1ec Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Thu, 4 May 2023 00:16:24 +0200 Subject: [PATCH 03/16] fix cx16.psg irq issue --- compiler/res/prog8lib/cx16/psg.p8 | 21 +++++++++++++++------ compiler/res/prog8lib/cx16/syslib.p8 | 3 +-- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/compiler/res/prog8lib/cx16/psg.p8 b/compiler/res/prog8lib/cx16/psg.p8 index 27a55947f..0d5a0c850 100644 --- a/compiler/res/prog8lib/cx16/psg.p8 +++ b/compiler/res/prog8lib/cx16/psg.p8 @@ -22,7 +22,10 @@ psg { ; waveform = one of PULSE,SAWTOOTH,TRIANGLE,NOISE. ; pulsewidth = 0-63. Specifies the pulse width for waveform=PULSE. envelope_states[voice_num] = 255 - sys.set_irqd() + %asm {{ + php + sei + }} cx16.r0 = $f9c2 + voice_num * 4 cx16.VERA_CTRL = 0 cx16.VERA_ADDR_L = lsb(cx16.r0) @@ -33,7 +36,9 @@ psg { cx16.VERA_DATA0 = waveform | pulsewidth envelope_volumes[voice_num] = mkword(volume, 0) envelope_maxvolumes[voice_num] = volume - sys.clear_irqd() + %asm {{ + plp + }} } ; sub freq_hz(ubyte voice_num, float hertz) { @@ -48,7 +53,10 @@ psg { ; voice_num = 0-15, vera_freq = 0-65535 calculate this via the formula given in the Vera's PSG documentation. ; (https://github.com/x16community/x16-docs/blob/master/VERA%20Programmer's%20Reference.md) ; Write freq MSB first and then LSB to reduce the chance on clicks - sys.set_irqd() + %asm {{ + php + sei + }} cx16.r0 = $f9c1 + voice_num * 4 cx16.VERA_CTRL = 0 cx16.VERA_ADDR_L = lsb(cx16.r0) @@ -57,7 +65,9 @@ psg { cx16.VERA_DATA0 = msb(vera_freq) cx16.VERA_ADDR_L-- cx16.VERA_DATA0 = lsb(vera_freq) - sys.clear_irqd() + %asm {{ + plp + }} } sub volume(ubyte voice_num, ubyte vol) { @@ -106,12 +116,11 @@ psg { ; you have to call this routine every 1/60th second, for example from your vsync irq handler, ; or just install this routine as the only irq handler if you don't have to do other things there. ; Example: cx16.set_irq(&psg.envelopes_irq, true) - ; NOTE: this routine calls save/restore_vera_context() for you, don't nest this! + ; NOTE: this routine calls save/restore_vera_context() for you, don't nest this or call it yourself! ; cx16.r0 = the volume word (volume scaled by 256) ; cx16.r1L = the voice number ; cx16.r2L = attack value - pushw(cx16.r0) push(cx16.r1L) push(cx16.r2L) diff --git a/compiler/res/prog8lib/cx16/syslib.p8 b/compiler/res/prog8lib/cx16/syslib.p8 index 75bdce75b..04b17f75d 100644 --- a/compiler/res/prog8lib/cx16/syslib.p8 +++ b/compiler/res/prog8lib/cx16/syslib.p8 @@ -784,6 +784,7 @@ asmsub save_vera_context() clobbers(A) { lda cx16.VERA_CTRL sta _vera_storage+3 eor #1 + sta _vera_storage+7 sta cx16.VERA_CTRL lda cx16.VERA_ADDR_L sta _vera_storage+4 @@ -791,8 +792,6 @@ asmsub save_vera_context() clobbers(A) { sta _vera_storage+5 lda cx16.VERA_ADDR_H sta _vera_storage+6 - lda cx16.VERA_CTRL - sta _vera_storage+7 rts _vera_storage: .byte 0,0,0,0,0,0,0,0 }} From c65279b672afa60fb759908f3245d1da5147505d Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sun, 7 May 2023 13:29:45 +0200 Subject: [PATCH 04/16] optimized logical expressions more --- .../cpu6502/assignment/AssignmentAsmGen.kt | 76 +++++++++++-------- 1 file changed, 45 insertions(+), 31 deletions(-) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index c9cc9f0d0..402160d48 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -357,6 +357,15 @@ internal class AssignmentAsmGen(private val program: PtProgram, } } } + + if(expr.left.type in ByteDatatypes && expr.right.type in ByteDatatypes) { + if(assignOptimizedComparisonBytes(expr, assign)) + return true + } else if(expr.left.type in WordDatatypes && expr.right.type in WordDatatypes) { + if(assignOptimizedComparisonWords(expr, assign)) + return true + } + val origTarget = assign.target.origAstTarget if(origTarget!=null) { assignConstantByte(assign.target, 0) @@ -381,13 +390,19 @@ internal class AssignmentAsmGen(private val program: PtProgram, if(expr.type !in IntegerDatatypes) return false - fun simpleLogicalBytesExpr() { - // both left and right expression operands are simple. - if (expr.right is PtNumber || expr.right is PtIdentifier) - assignLogicalWithSimpleRightOperandByte(assign.target, expr.left, expr.operator, expr.right) - else if (expr.left is PtNumber || expr.left is PtIdentifier) - assignLogicalWithSimpleRightOperandByte(assign.target, expr.right, expr.operator, expr.left) - else { + if(expr.operator in setOf("&", "|", "^", "and", "or", "xor")) { + if (expr.left.type in ByteDatatypes && expr.right.type in ByteDatatypes) { + if (expr.right.isSimple()) { + if (expr.right is PtNumber || expr.right is PtIdentifier) { + assignLogicalWithSimpleRightOperandByte(assign.target, expr.left, expr.operator, expr.right) + return true + } + else if (expr.left is PtNumber || expr.left is PtIdentifier) { + assignLogicalWithSimpleRightOperandByte(assign.target, expr.right, expr.operator, expr.left) + return true + } + } + assignExpressionToRegister(expr.left, RegisterOrPair.A, false) asmgen.saveRegisterStack(CpuRegister.A, false) assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE) @@ -399,16 +414,19 @@ internal class AssignmentAsmGen(private val program: PtProgram, else -> throw AssemblyError("invalid operator") } assignRegisterByte(assign.target, CpuRegister.A, false) + return true } - } - - fun simpleLogicalWordsExpr() { - // both left and right expression operands are simple. - if (expr.right is PtNumber || expr.right is PtIdentifier) - assignLogicalWithSimpleRightOperandWord(assign.target, expr.left, expr.operator, expr.right) - else if (expr.left is PtNumber || expr.left is PtIdentifier) - assignLogicalWithSimpleRightOperandWord(assign.target, expr.right, expr.operator, expr.left) - else { + else if (expr.left.type in WordDatatypes && expr.right.type in WordDatatypes) { + if (expr.right.isSimple()) { + if (expr.right is PtNumber || expr.right is PtIdentifier) { + assignLogicalWithSimpleRightOperandWord(assign.target, expr.left, expr.operator, expr.right) + return true + } + else if (expr.left is PtNumber || expr.left is PtIdentifier) { + assignLogicalWithSimpleRightOperandWord(assign.target, expr.right, expr.operator, expr.left) + return true + } + } assignExpressionToRegister(expr.left, RegisterOrPair.AY, false) asmgen.saveRegisterStack(CpuRegister.A, false) asmgen.saveRegisterStack(CpuRegister.Y, false) @@ -420,21 +438,7 @@ internal class AssignmentAsmGen(private val program: PtProgram, else -> throw AssemblyError("invalid operator") } assignRegisterpairWord(assign.target, RegisterOrPair.AY) - } - } - - if(expr.operator in setOf("&", "|", "^", "and", "or", "xor")) { - if (expr.left.type in ByteDatatypes && expr.right.type in ByteDatatypes) { - if (expr.right.isSimple()) { - simpleLogicalBytesExpr() - return true - } - } - if (expr.left.type in WordDatatypes && expr.right.type in WordDatatypes) { - if (expr.right.isSimple()) { - simpleLogicalWordsExpr() - return true - } + return true } return false } @@ -685,6 +689,16 @@ internal class AssignmentAsmGen(private val program: PtProgram, return false } + private fun assignOptimizedComparisonBytes(expr: PtBinaryExpression, assign: AsmAssignment): Boolean { + // TODO("Not yet implemented") + return false + } + + private fun assignOptimizedComparisonWords(expr: PtBinaryExpression, assign: AsmAssignment): Boolean { + // TODO("Not yet implemented") + return false + } + private fun assignLogicalWithSimpleRightOperandByte(target: AsmAssignTarget, left: PtExpression, operator: String, right: PtExpression) { assignExpressionToRegister(left, RegisterOrPair.A, false) val operand = when(right) { From 533d825f1a06a93c2aed325c62344f035a9edc85 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sun, 7 May 2023 14:47:31 +0200 Subject: [PATCH 05/16] optimized ubyte comparison expressions --- .../cpu6502/assignment/AssignmentAsmGen.kt | 93 ++++++++++++++++++- docs/source/todo.rst | 3 + 2 files changed, 94 insertions(+), 2 deletions(-) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index 402160d48..6ba4e33a7 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -690,8 +690,97 @@ internal class AssignmentAsmGen(private val program: PtProgram, } private fun assignOptimizedComparisonBytes(expr: PtBinaryExpression, assign: AsmAssignment): Boolean { - // TODO("Not yet implemented") - return false + val signed = expr.left.type == DataType.BYTE || expr.right.type == DataType.BYTE + + fun assignExpressionOperandsLeftScratchRightA() { + if(expr.right.isSimple()) { + assignExpressionToVariable(expr.left, "P8ZP_SCRATCH_B1", DataType.UBYTE) + assignExpressionToRegister(expr.right, RegisterOrPair.A, signed) + } else { + assignExpressionToRegister(expr.right, RegisterOrPair.A, signed) + asmgen.saveRegisterStack(CpuRegister.A, false) + assignExpressionToVariable(expr.left, "P8ZP_SCRATCH_B1", DataType.UBYTE) + asmgen.restoreRegisterStack(CpuRegister.A, false) + } + } + + when(expr.operator) { + "==" -> { + assignExpressionOperandsLeftScratchRightA() + asmgen.out(""" + cmp P8ZP_SCRATCH_B1 + beq + + lda #0 + beq ++ ++ lda #1 ++""") + } + "!=" -> { + assignExpressionOperandsLeftScratchRightA() + asmgen.out(""" + cmp P8ZP_SCRATCH_B1 + bne + + lda #0 + beq ++ ++ lda #1 ++""") + } + "<" -> { + assignExpressionOperandsLeftScratchRightA() + if(signed) + return false // TODO("< signed") + else + asmgen.out(""" + cmp P8ZP_SCRATCH_B1 + beq + + bcs ++ ++ lda #0 + beq ++ ++ lda #1 ++""") + } + "<=" -> { + assignExpressionOperandsLeftScratchRightA() + if(signed) + return false // TODO("< signed") + else + asmgen.out(""" + cmp P8ZP_SCRATCH_B1 + lda #0 + rol a""") + } + ">" -> { + assignExpressionOperandsLeftScratchRightA() + if(signed) + return false // TODO("< signed") + else + asmgen.out(""" + cmp P8ZP_SCRATCH_B1 + bcc + + lda #0 + beq ++ ++ lda #1 ++""") + } + ">=" -> { + assignExpressionOperandsLeftScratchRightA() + if(signed) + return false // TODO(">= signed") + else + asmgen.out(""" + cmp P8ZP_SCRATCH_B1 + bcc + + beq + + lda #0 + beq ++ ++ lda #1 ++""") + } + else -> return false + } + + assignRegisterByte(assign.target, CpuRegister.A, signed) + return true } private fun assignOptimizedComparisonWords(expr: PtBinaryExpression, assign: AsmAssignment): Boolean { diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 874d4bab1..43bcda67a 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,6 +3,9 @@ TODO For next minor release ^^^^^^^^^^^^^^^^^^^^^^ +- assignOptimizedComparisonBytes() / assignOptimizedComparisonWords() +- find bcc/bcs branches that could be a rol? +- find adc #0 that could be a rol? - try to optimize newexpr a bit more ... From ffb54110e9765d90a5d290a0266b8d93521bf5c0 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sun, 7 May 2023 15:15:58 +0200 Subject: [PATCH 06/16] optimized byte comparison expressions --- .../cpu6502/assignment/AssignmentAsmGen.kt | 44 ++++++++++++-- examples/test.p8 | 58 ++++++++++++++++--- 2 files changed, 90 insertions(+), 12 deletions(-) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index 6ba4e33a7..865f51b0d 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -728,7 +728,16 @@ internal class AssignmentAsmGen(private val program: PtProgram, "<" -> { assignExpressionOperandsLeftScratchRightA() if(signed) - return false // TODO("< signed") + asmgen.out(""" + clc + sbc P8ZP_SCRATCH_B1 + bvc + + eor #$80 ++ bpl + + lda #0 + beq ++ ++ lda #1 ++""") else asmgen.out(""" cmp P8ZP_SCRATCH_B1 @@ -742,7 +751,16 @@ internal class AssignmentAsmGen(private val program: PtProgram, "<=" -> { assignExpressionOperandsLeftScratchRightA() if(signed) - return false // TODO("< signed") + asmgen.out(""" + sec + sbc P8ZP_SCRATCH_B1 + bvc + + eor #$80 ++ bpl + + lda #0 + beq ++ ++ lda #1 ++""") else asmgen.out(""" cmp P8ZP_SCRATCH_B1 @@ -752,7 +770,16 @@ internal class AssignmentAsmGen(private val program: PtProgram, ">" -> { assignExpressionOperandsLeftScratchRightA() if(signed) - return false // TODO("< signed") + asmgen.out(""" + sec + sbc P8ZP_SCRATCH_B1 + bvc + + eor #$80 ++ bmi + + lda #0 + beq ++ ++ lda #1 ++""") else asmgen.out(""" cmp P8ZP_SCRATCH_B1 @@ -765,7 +792,16 @@ internal class AssignmentAsmGen(private val program: PtProgram, ">=" -> { assignExpressionOperandsLeftScratchRightA() if(signed) - return false // TODO(">= signed") + asmgen.out(""" + clc + sbc P8ZP_SCRATCH_B1 + bvc + + eor #$80 ++ bmi + + lda #0 + beq ++ ++ lda #1 ++""") else asmgen.out(""" cmp P8ZP_SCRATCH_B1 diff --git a/examples/test.p8 b/examples/test.p8 index 6f54b5e35..72c98b993 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -4,16 +4,58 @@ main { sub start() { - txt.print("hello") - ; foobar() - } + ubyte[10] envelope_attacks = 99 - asmsub foobar() { - %asm {{ - nop - rts - }} + ; signed and unsigned word: + ; == + ; != + ; > + ; >= + ; < + ; <= + + + ; expect yep yep nope nope nope + cx16.r0sL = -10 + cx16.r2sL = -9 + if (cx16.r0sL <= cx16.r2sL) or (envelope_attacks[cx16.r1L]==0) { + txt.print("\nyep\n") + } else { + txt.print("\nnope\n") + } + + cx16.r0sL = -9 + cx16.r2sL = -9 + if (cx16.r0sL <= cx16.r2sL) or (envelope_attacks[cx16.r1L]==0) { + txt.print("\nyep\n") + } else { + txt.print("\nnope\n") + } + + cx16.r0sL = -8 + cx16.r2sL = -9 + if (cx16.r0sL <= cx16.r2sL) or (envelope_attacks[cx16.r1L]==0) { + txt.print("\nyep\n") + } else { + txt.print("\nnope\n") + } + + cx16.r0sL = 0 + cx16.r2sL = -9 + if (cx16.r0sL <= cx16.r2sL) or (envelope_attacks[cx16.r1L]==0) { + txt.print("\nyep\n") + } else { + txt.print("\nnope\n") + } + + cx16.r0sL = 10 + cx16.r2sL = 1 + if (cx16.r0sL <= cx16.r2sL) or (envelope_attacks[cx16.r1L]==0) { + txt.print("\nyep\n") + } else { + txt.print("\nnope\n") + } } } From 393e914a8624deacaf15af74d710880a9a0b5ddd Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sun, 7 May 2023 15:28:20 +0200 Subject: [PATCH 07/16] optimized word equality comparison expressions --- .../cpu6502/assignment/AssignmentAsmGen.kt | 90 ++++++++++++++++++- docs/source/todo.rst | 2 +- examples/test.p8 | 34 ++++--- 3 files changed, 103 insertions(+), 23 deletions(-) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index 865f51b0d..cb93c7a4a 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -694,12 +694,12 @@ internal class AssignmentAsmGen(private val program: PtProgram, fun assignExpressionOperandsLeftScratchRightA() { if(expr.right.isSimple()) { - assignExpressionToVariable(expr.left, "P8ZP_SCRATCH_B1", DataType.UBYTE) + assignExpressionToVariable(expr.left, "P8ZP_SCRATCH_B1", expr.left.type) assignExpressionToRegister(expr.right, RegisterOrPair.A, signed) } else { assignExpressionToRegister(expr.right, RegisterOrPair.A, signed) asmgen.saveRegisterStack(CpuRegister.A, false) - assignExpressionToVariable(expr.left, "P8ZP_SCRATCH_B1", DataType.UBYTE) + assignExpressionToVariable(expr.left, "P8ZP_SCRATCH_B1", expr.left.type) asmgen.restoreRegisterStack(CpuRegister.A, false) } } @@ -820,8 +820,90 @@ internal class AssignmentAsmGen(private val program: PtProgram, } private fun assignOptimizedComparisonWords(expr: PtBinaryExpression, assign: AsmAssignment): Boolean { - // TODO("Not yet implemented") - return false + val signed = expr.left.type == DataType.BYTE || expr.right.type == DataType.BYTE + fun assignExpressionOperandsLeftScratchRightAY() { + if(expr.right.isSimple()) { + assignExpressionToVariable(expr.left, "P8ZP_SCRATCH_W1", expr.left.type) + assignExpressionToRegister(expr.right, RegisterOrPair.AY, signed) + } else { + assignExpressionToRegister(expr.right, RegisterOrPair.AY, signed) + asmgen.saveRegisterStack(CpuRegister.A, false) + asmgen.saveRegisterStack(CpuRegister.Y, false) + assignExpressionToVariable(expr.left, "P8ZP_SCRATCH_W1", expr.left.type) + asmgen.restoreRegisterStack(CpuRegister.Y, false) + asmgen.restoreRegisterStack(CpuRegister.A, false) + } + } + when(expr.operator) { + "==" -> { + assignExpressionOperandsLeftScratchRightAY() + asmgen.out(""" + cmp P8ZP_SCRATCH_W1 + bne + + cpy P8ZP_SCRATCH_W1+1 + bne + + lda #1 + bne ++ ++ lda #0 ++""") + } + "!=" -> { + assignExpressionOperandsLeftScratchRightAY() + asmgen.out(""" + cmp P8ZP_SCRATCH_W1 + bne + + cpy P8ZP_SCRATCH_W1+1 + bne + + lda #0 + beq ++ ++ lda #1 ++""") + } + "<" -> { + if(signed) { + // TODO("word <") + return false + } + else { + // TODO("uword <") + return false + } + } + "<=" -> { + if(signed) { + // TODO("word <=") + return false + } + else { + // TODO("uword =<") + return false + } + } + ">" -> { + if(signed) { + // TODO("word >") + return false + } + else { + // TODO("uword >") + return false + } + } + ">=" -> { + if(signed) { + // TODO("word >=") + return false + } + else { + // TODO("uword >=") + return false + } + } + else -> return false + } + + assignRegisterByte(assign.target, CpuRegister.A, signed) + return true } private fun assignLogicalWithSimpleRightOperandByte(target: AsmAssignTarget, left: PtExpression, operator: String, right: PtExpression) { diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 43bcda67a..02c0bbbb5 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,7 +3,7 @@ TODO For next minor release ^^^^^^^^^^^^^^^^^^^^^^ -- assignOptimizedComparisonBytes() / assignOptimizedComparisonWords() +- finish assignOptimizedComparisonWords() - find bcc/bcs branches that could be a rol? - find adc #0 that could be a rol? - try to optimize newexpr a bit more diff --git a/examples/test.p8 b/examples/test.p8 index 72c98b993..8d78adc6a 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -8,50 +8,48 @@ main { ; signed and unsigned word: - ; == - ; != ; > ; >= ; < ; <= - ; expect yep yep nope nope nope - cx16.r0sL = -10 - cx16.r2sL = -9 - if (cx16.r0sL <= cx16.r2sL) or (envelope_attacks[cx16.r1L]==0) { + ; expect nope nope yep yep yep + cx16.r0 = $ea30 + cx16.r2 = $ea31 + if (cx16.r0 > cx16.r2) or (envelope_attacks[cx16.r1L]==0) { txt.print("\nyep\n") } else { txt.print("\nnope\n") } - cx16.r0sL = -9 - cx16.r2sL = -9 - if (cx16.r0sL <= cx16.r2sL) or (envelope_attacks[cx16.r1L]==0) { + cx16.r0 = $ea31 + cx16.r2 = $ea31 + if (cx16.r0 > cx16.r2) or (envelope_attacks[cx16.r1L]==0) { txt.print("\nyep\n") } else { txt.print("\nnope\n") } - cx16.r0sL = -8 - cx16.r2sL = -9 - if (cx16.r0sL <= cx16.r2sL) or (envelope_attacks[cx16.r1L]==0) { + cx16.r0 = $ea32 + cx16.r2 = $ea31 + if (cx16.r0 > cx16.r2) or (envelope_attacks[cx16.r1L]==0) { txt.print("\nyep\n") } else { txt.print("\nnope\n") } - cx16.r0sL = 0 - cx16.r2sL = -9 - if (cx16.r0sL <= cx16.r2sL) or (envelope_attacks[cx16.r1L]==0) { + cx16.r0 = $ee30 + cx16.r2 = $ea31 + if (cx16.r0 > cx16.r2) or (envelope_attacks[cx16.r1L]==0) { txt.print("\nyep\n") } else { txt.print("\nnope\n") } - cx16.r0sL = 10 - cx16.r2sL = 1 - if (cx16.r0sL <= cx16.r2sL) or (envelope_attacks[cx16.r1L]==0) { + cx16.r0 = $ffff + cx16.r2 = $ee31 + if (cx16.r0 > cx16.r2) or (envelope_attacks[cx16.r1L]==0) { txt.print("\nyep\n") } else { txt.print("\nnope\n") From 68336a76c5da5b0dfa346cc43b1903e7b3962e7d Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sun, 7 May 2023 19:55:06 +0200 Subject: [PATCH 08/16] optimized word comparison expressions --- .../cpu6502/assignment/AssignmentAsmGen.kt | 123 +++++++++++++++--- docs/source/todo.rst | 3 +- examples/test.p8 | 46 ++++--- 3 files changed, 132 insertions(+), 40 deletions(-) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index cb93c7a4a..4df9f6812 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -820,7 +820,7 @@ internal class AssignmentAsmGen(private val program: PtProgram, } private fun assignOptimizedComparisonWords(expr: PtBinaryExpression, assign: AsmAssignment): Boolean { - val signed = expr.left.type == DataType.BYTE || expr.right.type == DataType.BYTE + val signed = expr.left.type == DataType.WORD || expr.right.type == DataType.WORD fun assignExpressionOperandsLeftScratchRightAY() { if(expr.right.isSimple()) { assignExpressionToVariable(expr.left, "P8ZP_SCRATCH_W1", expr.left.type) @@ -834,6 +834,19 @@ internal class AssignmentAsmGen(private val program: PtProgram, asmgen.restoreRegisterStack(CpuRegister.A, false) } } + fun assignExpressionOperandsLeftAYRightScratch() { + if(expr.left.isSimple()) { + assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_W1", expr.left.type) + assignExpressionToRegister(expr.left, RegisterOrPair.AY, signed) + } else { + assignExpressionToRegister(expr.left, RegisterOrPair.AY, signed) + asmgen.saveRegisterStack(CpuRegister.A, false) + asmgen.saveRegisterStack(CpuRegister.Y, false) + assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_W1", expr.left.type) + asmgen.restoreRegisterStack(CpuRegister.Y, false) + asmgen.restoreRegisterStack(CpuRegister.A, false) + } + } when(expr.operator) { "==" -> { assignExpressionOperandsLeftScratchRightAY() @@ -861,42 +874,118 @@ internal class AssignmentAsmGen(private val program: PtProgram, } "<" -> { if(signed) { - // TODO("word <") - return false + assignExpressionOperandsLeftAYRightScratch() + asmgen.out(""" + cmp P8ZP_SCRATCH_W1 + tya + sbc P8ZP_SCRATCH_W1+1 + bvc + + eor #${'$'}80 ++ bpl ++ ++ lda #1 + bne ++ ++ lda #0 ++""") } else { - // TODO("uword <") - return false + assignExpressionOperandsLeftAYRightScratch() + asmgen.out(""" + cpy P8ZP_SCRATCH_W1+1 + bcc + + bne ++ + cmp P8ZP_SCRATCH_W1 + bcs ++ ++ lda #1 + bne ++ ++ lda #0 ++""") } } "<=" -> { if(signed) { - // TODO("word <=") - return false + assignExpressionOperandsLeftScratchRightAY() + asmgen.out(""" + cmp P8ZP_SCRATCH_W1 + tya + sbc P8ZP_SCRATCH_W1+1 + bvc + + eor #${'$'}80 ++ bmi + + lda #1 + bne ++ ++ lda #0 ++""") } else { - // TODO("uword =<") - return false + assignExpressionOperandsLeftScratchRightAY() + asmgen.out(""" + cpy P8ZP_SCRATCH_W1+1 + bcc ++ + bne + + cmp P8ZP_SCRATCH_W1 + bcc ++ ++ lda #1 + bne ++ ++ lda #0 ++""") } } ">" -> { if(signed) { - // TODO("word >") - return false + assignExpressionOperandsLeftScratchRightAY() + asmgen.out(""" + cmp P8ZP_SCRATCH_W1 + tya + sbc P8ZP_SCRATCH_W1+1 + bvc + + eor #${'$'}80 ++ bpl ++ ++ lda #1 + bne ++ ++ lda #0 ++""") } else { - // TODO("uword >") - return false + assignExpressionOperandsLeftScratchRightAY() + asmgen.out(""" + cpy P8ZP_SCRATCH_W1+1 + bcc + + bne ++ + cmp P8ZP_SCRATCH_W1 + bcs ++ ++ lda #1 + bne ++ ++ lda #0 ++""") } } ">=" -> { if(signed) { - // TODO("word >=") - return false + assignExpressionOperandsLeftAYRightScratch() + asmgen.out(""" + cmp P8ZP_SCRATCH_W1 + tya + sbc P8ZP_SCRATCH_W1+1 + bvc + + eor #${'$'}80 ++ bmi + + lda #1 + bne ++ ++ lda #0 ++""") } else { - // TODO("uword >=") - return false + assignExpressionOperandsLeftAYRightScratch() + asmgen.out(""" + cpy P8ZP_SCRATCH_W1+1 + bcc ++ + bne + + cmp P8ZP_SCRATCH_W1 + bcc ++ ++ lda #1 + bne ++ ++ lda #0 ++""") } } else -> return false diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 02c0bbbb5..2af475381 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,8 +3,7 @@ TODO For next minor release ^^^^^^^^^^^^^^^^^^^^^^ -- finish assignOptimizedComparisonWords() -- find bcc/bcs branches that could be a rol? +- find bcc/bcs + lda branches that could be a rol? - find adc #0 that could be a rol? - try to optimize newexpr a bit more diff --git a/examples/test.p8 b/examples/test.p8 index 8d78adc6a..bff14ebfd 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -6,50 +6,54 @@ main { sub start() { ubyte[10] envelope_attacks = 99 - - ; signed and unsigned word: + ; signed word: ; > - ; >= - ; < - ; <= - ; expect nope nope yep yep yep - cx16.r0 = $ea30 - cx16.r2 = $ea31 - if (cx16.r0 > cx16.r2) or (envelope_attacks[cx16.r1L]==0) { + ; expect yep nope nope nope yep nope + cx16.r0s = -1000 + cx16.r2s = -999 + if (cx16.r0s < cx16.r2s) or (envelope_attacks[cx16.r1L]==0) { txt.print("\nyep\n") } else { txt.print("\nnope\n") } - cx16.r0 = $ea31 - cx16.r2 = $ea31 - if (cx16.r0 > cx16.r2) or (envelope_attacks[cx16.r1L]==0) { + cx16.r0s = -999 + cx16.r2s = -999 + if (cx16.r0s < cx16.r2s) or (envelope_attacks[cx16.r1L]==0) { txt.print("\nyep\n") } else { txt.print("\nnope\n") } - cx16.r0 = $ea32 - cx16.r2 = $ea31 - if (cx16.r0 > cx16.r2) or (envelope_attacks[cx16.r1L]==0) { + cx16.r0s = -998 + cx16.r2s = -999 + if (cx16.r0s < cx16.r2s) or (envelope_attacks[cx16.r1L]==0) { txt.print("\nyep\n") } else { txt.print("\nnope\n") } - cx16.r0 = $ee30 - cx16.r2 = $ea31 - if (cx16.r0 > cx16.r2) or (envelope_attacks[cx16.r1L]==0) { + cx16.r0s = 0 + cx16.r2s = -999 + if (cx16.r0s < cx16.r2s) or (envelope_attacks[cx16.r1L]==0) { txt.print("\nyep\n") } else { txt.print("\nnope\n") } - cx16.r0 = $ffff - cx16.r2 = $ee31 - if (cx16.r0 > cx16.r2) or (envelope_attacks[cx16.r1L]==0) { + cx16.r0s = -999 + cx16.r2s = 0 + if (cx16.r0s < cx16.r2s) or (envelope_attacks[cx16.r1L]==0) { + txt.print("\nyep\n") + } else { + txt.print("\nnope\n") + } + + cx16.r0s = $7fff + cx16.r2s = $7eff + if (cx16.r0s < cx16.r2s) or (envelope_attacks[cx16.r1L]==0) { txt.print("\nyep\n") } else { txt.print("\nnope\n") From 8cbfe64f197270c102ef1cb30181cc77ffade4e1 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sun, 7 May 2023 21:03:14 +0200 Subject: [PATCH 09/16] optimize some carry flag assembly --- .../cpu6502/assignment/AssignmentAsmGen.kt | 19 ++++---- .../assignment/AugmentableAssignmentAsmGen.kt | 8 ++++ compiler/res/prog8lib/c128/syslib.p8 | 4 +- compiler/res/prog8lib/c64/syslib.p8 | 4 +- compiler/res/prog8lib/cx16/syslib.p8 | 2 +- compiler/res/prog8lib/string.p8 | 2 +- docs/source/todo.rst | 3 +- examples/test.p8 | 43 ++++++++----------- 8 files changed, 42 insertions(+), 43 deletions(-) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index 4df9f6812..a97817c8b 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -740,12 +740,11 @@ internal class AssignmentAsmGen(private val program: PtProgram, +""") else asmgen.out(""" - cmp P8ZP_SCRATCH_B1 + tay + lda #0 + cpy P8ZP_SCRATCH_B1 beq + - bcs ++ -+ lda #0 - beq ++ -+ lda #1 + rol a +""") } "<=" -> { @@ -783,11 +782,9 @@ internal class AssignmentAsmGen(private val program: PtProgram, else asmgen.out(""" cmp P8ZP_SCRATCH_B1 - bcc + lda #0 - beq ++ -+ lda #1 -+""") + rol a + eor #1""") } ">=" -> { assignExpressionOperandsLeftScratchRightA() @@ -803,10 +800,10 @@ internal class AssignmentAsmGen(private val program: PtProgram, + lda #1 +""") else - asmgen.out(""" + asmgen.out(""" cmp P8ZP_SCRATCH_B1 - bcc + beq + + bcc + lda #0 beq ++ + lda #1 diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt index e7284e706..ab1b61231 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt @@ -771,6 +771,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } "<" -> { if(dt==DataType.UBYTE) { + // TODO optimize Carry expr with rol? asmgen.out(""" lda $name cmp $otherName @@ -797,6 +798,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } "<=" -> { if(dt==DataType.UBYTE) { + // TODO optimize Carry expr with rol? asmgen.out(""" lda $otherName cmp $name @@ -822,6 +824,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } ">" -> { if(dt==DataType.UBYTE) { + // TODO optimize Carry expr with rol? asmgen.out(""" lda $name cmp $otherName @@ -848,6 +851,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } ">=" -> { if(dt==DataType.UBYTE) { + // TODO optimize Carry expr with rol? asmgen.out(""" lda $name cmp $otherName @@ -962,6 +966,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } "<" -> { if(dt==DataType.UBYTE) { + // TODO optimize Carry expr with rol? asmgen.out(""" lda $name cmp #$value @@ -988,6 +993,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } "<=" -> { if(dt==DataType.UBYTE) { + // TODO optimize Carry expr with rol? asmgen.out(""" lda #$value cmp $name @@ -1013,6 +1019,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } ">" -> { if(dt==DataType.UBYTE) { + // TODO optimize Carry expr with rol? asmgen.out(""" lda $name cmp #$value @@ -1039,6 +1046,7 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } ">=" -> { if(dt==DataType.UBYTE) { + // TODO optimize Carry expr with rol? asmgen.out(""" lda $name cmp #$value diff --git a/compiler/res/prog8lib/c128/syslib.p8 b/compiler/res/prog8lib/c128/syslib.p8 index 51f9b8b57..f87cf34e7 100644 --- a/compiler/res/prog8lib/c128/syslib.p8 +++ b/compiler/res/prog8lib/c128/syslib.p8 @@ -310,7 +310,7 @@ asmsub set_irq(uword handler @AY, ubyte useKernal @Pc) clobbers(A) { sta _modified+1 sty _modified+2 lda #0 - adc #0 + rol a sta _use_kernal sei lda #<_irq_handler @@ -404,7 +404,7 @@ asmsub set_rasterirq(uword handler @AY, uword rasterpos @R0, ubyte useKernal @P sta _modified+1 sty _modified+2 lda #0 - adc #0 + rol a sta set_irq._use_kernal lda cx16.r0 ldy cx16.r0+1 diff --git a/compiler/res/prog8lib/c64/syslib.p8 b/compiler/res/prog8lib/c64/syslib.p8 index d33634e18..e54291077 100644 --- a/compiler/res/prog8lib/c64/syslib.p8 +++ b/compiler/res/prog8lib/c64/syslib.p8 @@ -356,7 +356,7 @@ asmsub set_irq(uword handler @AY, ubyte useKernal @Pc) clobbers(A) { sta _modified+1 sty _modified+2 lda #0 - adc #0 + rol a sta _use_kernal sei lda #<_irq_handler @@ -450,7 +450,7 @@ asmsub set_rasterirq(uword handler @AY, uword rasterpos @R0, ubyte useKernal @P sta _modified+1 sty _modified+2 lda #0 - adc #0 + rol a sta set_irq._use_kernal lda cx16.r0 ldy cx16.r0+1 diff --git a/compiler/res/prog8lib/cx16/syslib.p8 b/compiler/res/prog8lib/cx16/syslib.p8 index 04b17f75d..85333f7aa 100644 --- a/compiler/res/prog8lib/cx16/syslib.p8 +++ b/compiler/res/prog8lib/cx16/syslib.p8 @@ -697,7 +697,7 @@ asmsub set_irq(uword handler @AY, ubyte useKernal @Pc) clobbers(A) { sta _modified+1 sty _modified+2 lda #0 - adc #0 + rol a sta _use_kernal sei lda #<_irq_handler diff --git a/compiler/res/prog8lib/string.p8 b/compiler/res/prog8lib/string.p8 index dcf5fc38f..5c43c05fa 100644 --- a/compiler/res/prog8lib/string.p8 +++ b/compiler/res/prog8lib/string.p8 @@ -292,7 +292,7 @@ str = P8ZP_SCRATCH_W1 sta modify_pattern2+2 jsr _match lda #0 - adc #0 + rol a ldx P8ZP_SCRATCH_REG rts diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 2af475381..5c44c4108 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,8 +3,7 @@ TODO For next minor release ^^^^^^^^^^^^^^^^^^^^^^ -- find bcc/bcs + lda branches that could be a rol? -- find adc #0 that could be a rol? +- find bcc/bcs + lda branches that could be a rol? (see "TODO optimize Carry expr with rol") - try to optimize newexpr a bit more ... diff --git a/examples/test.p8 b/examples/test.p8 index bff14ebfd..33da9ccdf 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,59 +1,54 @@ %import textio -%option no_sysinit %zeropage basicsafe main { sub start() { ubyte[10] envelope_attacks = 99 - ; signed word: - ; > - - - ; expect yep nope nope nope yep nope - cx16.r0s = -1000 - cx16.r2s = -999 - if (cx16.r0s < cx16.r2s) or (envelope_attacks[cx16.r1L]==0) { + ; expect nope yep yep nope yep yep + cx16.r0L = 8 + cx16.r2L = 9 + if (cx16.r0L >= cx16.r2L) or (envelope_attacks[cx16.r1L]==0) { txt.print("\nyep\n") } else { txt.print("\nnope\n") } - cx16.r0s = -999 - cx16.r2s = -999 - if (cx16.r0s < cx16.r2s) or (envelope_attacks[cx16.r1L]==0) { + cx16.r0L = 9 + cx16.r2L = 9 + if (cx16.r0L >= cx16.r2L) or (envelope_attacks[cx16.r1L]==0) { txt.print("\nyep\n") } else { txt.print("\nnope\n") } - cx16.r0s = -998 - cx16.r2s = -999 - if (cx16.r0s < cx16.r2s) or (envelope_attacks[cx16.r1L]==0) { + cx16.r0L = 10 + cx16.r2L = 9 + if (cx16.r0L >= cx16.r2L) or (envelope_attacks[cx16.r1L]==0) { txt.print("\nyep\n") } else { txt.print("\nnope\n") } - cx16.r0s = 0 - cx16.r2s = -999 - if (cx16.r0s < cx16.r2s) or (envelope_attacks[cx16.r1L]==0) { + cx16.r0L = 0 + cx16.r2L = 9 + if (cx16.r0L >= cx16.r2L) or (envelope_attacks[cx16.r1L]==0) { txt.print("\nyep\n") } else { txt.print("\nnope\n") } - cx16.r0s = -999 - cx16.r2s = 0 - if (cx16.r0s < cx16.r2s) or (envelope_attacks[cx16.r1L]==0) { + cx16.r0L = 9 + cx16.r2L = 0 + if (cx16.r0L >= cx16.r2L) or (envelope_attacks[cx16.r1L]==0) { txt.print("\nyep\n") } else { txt.print("\nnope\n") } - cx16.r0s = $7fff - cx16.r2s = $7eff - if (cx16.r0s < cx16.r2s) or (envelope_attacks[cx16.r1L]==0) { + cx16.r0L = 255 + cx16.r2L = 9 + if (cx16.r0L >= cx16.r2L) or (envelope_attacks[cx16.r1L]==0) { txt.print("\nyep\n") } else { txt.print("\nnope\n") From ab02e8a546eed2346504eae962ad2f3b9601cfd6 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sun, 7 May 2023 23:49:02 +0200 Subject: [PATCH 10/16] optimize more carry flag assembly --- .../assignment/AugmentableAssignmentAsmGen.kt | 90 +++++++------------ examples/test.p8 | 71 +++++---------- 2 files changed, 58 insertions(+), 103 deletions(-) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt index ab1b61231..006237f2c 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt @@ -771,15 +771,13 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } "<" -> { if(dt==DataType.UBYTE) { - // TODO optimize Carry expr with rol? asmgen.out(""" - lda $name - cmp $otherName - bcc + lda #0 - beq ++ -+ lda #1 -+ sta $name""") + ldy $name + cpy $otherName + rol a + eor #1 + sta $name""") } else { // see http://www.6502.org/tutorials/compare_beyond.html @@ -798,15 +796,12 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } "<=" -> { if(dt==DataType.UBYTE) { - // TODO optimize Carry expr with rol? asmgen.out(""" - lda $otherName - cmp $name - bcs + lda #0 - beq ++ -+ lda #1 -+ sta $name""") + ldy $otherName + cpy $name + rol a + sta $name""") } else { // see http://www.6502.org/tutorials/compare_beyond.html asmgen.out(""" @@ -824,15 +819,12 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } ">" -> { if(dt==DataType.UBYTE) { - // TODO optimize Carry expr with rol? asmgen.out(""" - lda $name - cmp $otherName + lda #0 + ldy $name + cpy $otherName beq + - bcs ++ -+ lda #0 - beq ++ -+ lda #1 + rol a + sta $name""") } else { // see http://www.6502.org/tutorials/compare_beyond.html @@ -851,15 +843,12 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } ">=" -> { if(dt==DataType.UBYTE) { - // TODO optimize Carry expr with rol? asmgen.out(""" - lda $name - cmp $otherName - bcs + lda #0 - beq ++ -+ lda #1 -+ sta $name""") + ldy $name + cpy $otherName + rol a + sta $name""") } else { // see http://www.6502.org/tutorials/compare_beyond.html asmgen.out(""" @@ -966,15 +955,13 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } "<" -> { if(dt==DataType.UBYTE) { - // TODO optimize Carry expr with rol? asmgen.out(""" - lda $name - cmp #$value - bcc + lda #0 - beq ++ -+ lda #1 -+ sta $name""") + ldy $name + cpy #$value + rol a + eor #1 + sta $name""") } else { // see http://www.6502.org/tutorials/compare_beyond.html @@ -993,15 +980,12 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } "<=" -> { if(dt==DataType.UBYTE) { - // TODO optimize Carry expr with rol? asmgen.out(""" - lda #$value - cmp $name - bcs + lda #0 - beq ++ -+ lda #1 -+ sta $name""") + ldy #$value + cpy $name + rol a + sta $name""") } else { // see http://www.6502.org/tutorials/compare_beyond.html asmgen.out(""" @@ -1019,15 +1003,12 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } ">" -> { if(dt==DataType.UBYTE) { - // TODO optimize Carry expr with rol? asmgen.out(""" - lda $name - cmp #$value + lda #0 + ldy $name + cpy #$value beq + - bcs ++ -+ lda #0 - beq ++ -+ lda #1 + rol a + sta $name""") } else { // see http://www.6502.org/tutorials/compare_beyond.html @@ -1046,15 +1027,12 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, } ">=" -> { if(dt==DataType.UBYTE) { - // TODO optimize Carry expr with rol? asmgen.out(""" - lda $name - cmp #$value - bcs + lda #0 - beq ++ -+ lda #1 -+ sta $name""") + ldy $name + cpy #$value + rol a + sta $name""") } else { // see http://www.6502.org/tutorials/compare_beyond.html asmgen.out(""" diff --git a/examples/test.p8 b/examples/test.p8 index 33da9ccdf..0fc6bdb3b 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -4,55 +4,32 @@ main { sub start() { ubyte[10] envelope_attacks = 99 + ubyte @shared xx = 4 + ubyte yy + ; 110 + xx = 4 + yy = 10 + xx = xx <= yy + if xx + txt.chrout('1') + else + txt.chrout('0') - ; expect nope yep yep nope yep yep - cx16.r0L = 8 - cx16.r2L = 9 - if (cx16.r0L >= cx16.r2L) or (envelope_attacks[cx16.r1L]==0) { - txt.print("\nyep\n") - } else { - txt.print("\nnope\n") - } + xx = 4 + yy = 4 + xx = xx <= yy + if xx + txt.chrout('1') + else + txt.chrout('0') - cx16.r0L = 9 - cx16.r2L = 9 - if (cx16.r0L >= cx16.r2L) or (envelope_attacks[cx16.r1L]==0) { - txt.print("\nyep\n") - } else { - txt.print("\nnope\n") - } - - cx16.r0L = 10 - cx16.r2L = 9 - if (cx16.r0L >= cx16.r2L) or (envelope_attacks[cx16.r1L]==0) { - txt.print("\nyep\n") - } else { - txt.print("\nnope\n") - } - - cx16.r0L = 0 - cx16.r2L = 9 - if (cx16.r0L >= cx16.r2L) or (envelope_attacks[cx16.r1L]==0) { - txt.print("\nyep\n") - } else { - txt.print("\nnope\n") - } - - cx16.r0L = 9 - cx16.r2L = 0 - if (cx16.r0L >= cx16.r2L) or (envelope_attacks[cx16.r1L]==0) { - txt.print("\nyep\n") - } else { - txt.print("\nnope\n") - } - - cx16.r0L = 255 - cx16.r2L = 9 - if (cx16.r0L >= cx16.r2L) or (envelope_attacks[cx16.r1L]==0) { - txt.print("\nyep\n") - } else { - txt.print("\nnope\n") - } + xx = 4 + yy = 2 + xx = xx <= yy + if xx + txt.chrout('1') + else + txt.chrout('0') } } From 6db715d879d2b93f2831b895466a5a16ceb58fd2 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Mon, 8 May 2023 01:03:54 +0200 Subject: [PATCH 11/16] optimize multiplication expr --- .../cpu6502/assignment/AssignmentAsmGen.kt | 114 ++++++++++++++++++ docs/source/todo.rst | 2 +- examples/test.p8 | 52 ++++---- 3 files changed, 140 insertions(+), 28 deletions(-) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index a97817c8b..9ce248775 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -686,6 +686,120 @@ internal class AssignmentAsmGen(private val program: PtProgram, } } } + else if(expr.operator=="*") { + val value = expr.right.asConstInteger() + if(value==null) { + when(expr.type) { + in ByteDatatypes -> { + assignExpressionToRegister(expr.left, RegisterOrPair.A, expr.type in SignedDatatypes) + asmgen.out(" pha") + assignExpressionToRegister(expr.right, RegisterOrPair.Y, expr.type in SignedDatatypes) + asmgen.out(" pla | jsr math.multiply_bytes") + assignRegisterByte(assign.target, CpuRegister.A, false) + return true + } + in WordDatatypes -> { + assignExpressionToVariable(expr.left, "P8ZP_SCRATCH_W1", expr.type) + assignExpressionToRegister(expr.right, RegisterOrPair.AY, expr.type in SignedDatatypes) + asmgen.out(""" + jsr math.multiply_words + lda math.multiply_words.result + ldy math.multiply_words.result+1""") + assignRegisterpairWord(assign.target, RegisterOrPair.AY) + return true + } + else -> return false + } + } else { + when (expr.type) { + in ByteDatatypes -> { + assignExpressionToRegister(expr.left, RegisterOrPair.A, expr.type in SignedDatatypes) + if (value in asmgen.optimizedByteMultiplications) + asmgen.out(" jsr math.mul_byte_${value}") + else + asmgen.out(" ldy #$value | jsr math.multiply_bytes") + assignRegisterByte(assign.target, CpuRegister.A, false) + return true + } + in WordDatatypes -> { + assignExpressionToRegister(expr.left, RegisterOrPair.AY, expr.type in SignedDatatypes) + if (value in asmgen.optimizedWordMultiplications) + asmgen.out(" jsr math.mul_word_${value}") + else + asmgen.out(""" + sta P8ZP_SCRATCH_W1 + sty P8ZP_SCRATCH_W1+1 + lda #<$value + ldy #>$value + jsr math.multiply_words + lda math.multiply_words.result + ldy math.multiply_words.result+1""") + assignRegisterpairWord(assign.target, RegisterOrPair.AY) + return true + } + else -> return false + } + } + } + else if(expr.operator=="/") { + when(expr.type) { + DataType.UBYTE -> { + assignExpressionToRegister(expr.left, RegisterOrPair.A, false) + asmgen.out(" pha") + assignExpressionToRegister(expr.right, RegisterOrPair.Y, false) + asmgen.out(" pla | jsr math.divmod_ub_asm") + assignRegisterByte(assign.target, CpuRegister.Y, false) + return true + } + DataType.BYTE -> { + assignExpressionToRegister(expr.left, RegisterOrPair.A, true) + asmgen.out(" pha") + assignExpressionToRegister(expr.right, RegisterOrPair.Y, true) + asmgen.out(" pla | jsr math.divmod_b_asm") + assignRegisterByte(assign.target, CpuRegister.Y, true) + return true + } + DataType.UWORD -> { + assignExpressionToVariable(expr.left, "P8ZP_SCRATCH_W1", DataType.UWORD) + assignExpressionToRegister(expr.right, RegisterOrPair.AY, false) + asmgen.out(" jsr math.divmod_uw_asm") + assignRegisterpairWord(assign.target, RegisterOrPair.AY) + return true + } + DataType.WORD -> { + assignExpressionToVariable(expr.left, "P8ZP_SCRATCH_W1", DataType.WORD) + assignExpressionToRegister(expr.right, RegisterOrPair.AY, true) + asmgen.out(" jsr math.divmod_w_asm") + assignRegisterpairWord(assign.target, RegisterOrPair.AY) + return true + } + else -> return false + } + } + else if(expr.operator=="%") { + when(expr.type) { + DataType.UBYTE -> { + assignExpressionToRegister(expr.left, RegisterOrPair.A, false) + asmgen.out(" pha") + assignExpressionToRegister(expr.right, RegisterOrPair.Y, false) + asmgen.out(" pla | jsr math.divmod_ub_asm") + if(assign.target.register==RegisterOrPair.A) + asmgen.out(" cmp #0") // fix the status register + else + assignRegisterByte(assign.target, CpuRegister.A, false) + return true + } + DataType.UWORD -> { + assignExpressionToVariable(expr.left, "P8ZP_SCRATCH_W1", DataType.UWORD) + assignExpressionToRegister(expr.right, RegisterOrPair.AY, false) + asmgen.out(" jsr math.divmod_uw_asm") + assignVariableWord(assign.target, "P8ZP_SCRATCH_W2") + return true + } + else -> return false + } + } + return false } diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 5c44c4108..116e24a7f 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,7 +3,7 @@ TODO For next minor release ^^^^^^^^^^^^^^^^^^^^^^ -- find bcc/bcs + lda branches that could be a rol? (see "TODO optimize Carry expr with rol") +- fix crash: uword remainder = seconds_uword % $0003 ==0 - try to optimize newexpr a bit more ... diff --git a/examples/test.p8 b/examples/test.p8 index 0fc6bdb3b..9b89dc426 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -2,34 +2,32 @@ %zeropage basicsafe main { + + uword vv = 60 + + sub print_time(uword seconds) { + ubyte remainder = seconds % $0003 ==0 + txt.print_uw(remainder) + txt.nl() + } + + sub print_time2(ubyte seconds) { + ubyte remainder = seconds % 3 ==0 + txt.print_uw(remainder) + txt.nl() + } + + sub start() { - ubyte[10] envelope_attacks = 99 - ubyte @shared xx = 4 - ubyte yy - ; 110 - xx = 4 - yy = 10 - xx = xx <= yy - if xx - txt.chrout('1') - else - txt.chrout('0') - - xx = 4 - yy = 4 - xx = xx <= yy - if xx - txt.chrout('1') - else - txt.chrout('0') - - xx = 4 - yy = 2 - xx = xx <= yy - if xx - txt.chrout('1') - else - txt.chrout('0') + print_time(9870) + print_time(9871) + print_time(9872) + print_time(9873) + txt.nl() + print_time2(50) + print_time2(51) + print_time2(52) + print_time2(53) } } From 6c233c6a0a28a89da2f68230ba3a6fb5dd1eaae9 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Mon, 8 May 2023 02:41:34 +0200 Subject: [PATCH 12/16] optimize add/sub expr --- .../cpu6502/assignment/AssignmentAsmGen.kt | 38 ++++++++++++++++++- examples/test.p8 | 28 +++----------- 2 files changed, 41 insertions(+), 25 deletions(-) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index 9ce248775..859d671b2 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -529,7 +529,18 @@ internal class AssignmentAsmGen(private val program: PtProgram, assignRegisterByte(assign.target, CpuRegister.A, dt in SignedDatatypes) return true } - else -> return false + else -> { + assignExpressionToRegister(left, RegisterOrPair.A, left.type==DataType.BYTE) + asmgen.out(" pha") + assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", right.type) + asmgen.out(" pla") + if(expr.operator=="+") + asmgen.out(" clc | adc P8ZP_SCRATCH_B1") + else + asmgen.out(" sec | sbc P8ZP_SCRATCH_B1") + assignRegisterByte(assign.target, CpuRegister.A, dt in SignedDatatypes) + return true + } } } else if(dt in WordDatatypes) { when (right) { @@ -630,7 +641,30 @@ internal class AssignmentAsmGen(private val program: PtProgram, } } } - else -> return false + else -> { + assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", right.type) + assignExpressionToRegister(left, RegisterOrPair.AY, left.type==DataType.WORD) + if(expr.operator=="+") + asmgen.out(""" + clc + adc P8ZP_SCRATCH_W2 + pha + tya + adc P8ZP_SCRATCH_W2+1 + tay + pla""") + else + asmgen.out(""" + sec + sbc P8ZP_SCRATCH_W2 + pha + tya + sbc P8ZP_SCRATCH_W2+1 + tay + pla""") + assignRegisterpairWord(assign.target, RegisterOrPair.AY) + return true + } } } } diff --git a/examples/test.p8 b/examples/test.p8 index 9b89dc426..53b2be513 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -3,31 +3,13 @@ main { - uword vv = 60 - - sub print_time(uword seconds) { - ubyte remainder = seconds % $0003 ==0 - txt.print_uw(remainder) - txt.nl() - } - - sub print_time2(ubyte seconds) { - ubyte remainder = seconds % 3 ==0 - txt.print_uw(remainder) - txt.nl() - } - + word[5] dx = [111,222,333,444,555] sub start() { - print_time(9870) - print_time(9871) - print_time(9872) - print_time(9873) - txt.nl() - print_time2(50) - print_time2(51) - print_time2(52) - print_time2(53) + uword hit_x = 999 + cx16.r0=2 + uword new_head_x = hit_x + dx[cx16.r0L] as uword + txt.print_uw(new_head_x) } } From d5d6dd361483063d9f3e5bb4e44a92a1077ea557 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Mon, 8 May 2023 03:30:14 +0200 Subject: [PATCH 13/16] optimize typecast expr --- .../cpu6502/assignment/AssignmentAsmGen.kt | 178 ++++++++++-------- docs/source/todo.rst | 2 + examples/test.p8 | 10 +- 3 files changed, 106 insertions(+), 84 deletions(-) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index 859d671b2..95078289b 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -427,6 +427,7 @@ internal class AssignmentAsmGen(private val program: PtProgram, return true } } + // TODO use utility function assignExpressionWordOperandsLeftAYRightScratchW1() etc. assignExpressionToRegister(expr.left, RegisterOrPair.AY, false) asmgen.saveRegisterStack(CpuRegister.A, false) asmgen.saveRegisterStack(CpuRegister.Y, false) @@ -472,6 +473,7 @@ internal class AssignmentAsmGen(private val program: PtProgram, return true } else if(expr.left.type in WordDatatypes && expr.right.type in WordDatatypes && expr.left.isSimple() && expr.right.isSimple()) { + // TODO use utility function assignExpressionWordOperandsLeftAYRightScratchW1() etc. assignExpressionToRegister(expr.left, RegisterOrPair.AY, false) asmgen.saveRegisterStack(CpuRegister.A, false) asmgen.saveRegisterStack(CpuRegister.Y, false) @@ -543,6 +545,36 @@ internal class AssignmentAsmGen(private val program: PtProgram, } } } else if(dt in WordDatatypes) { + + fun doAddOrSubWordExpr() { + // TODO use utility function assignExpressionWordOperandsLeftAYRightScratchW1() etc. + assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD) + asmgen.saveRegisterStack(CpuRegister.A, false) + asmgen.saveRegisterStack(CpuRegister.Y, false) + assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", dt) + asmgen.restoreRegisterStack(CpuRegister.Y, false) + asmgen.restoreRegisterStack(CpuRegister.A, false) + if(expr.operator=="+") + asmgen.out(""" + clc + adc P8ZP_SCRATCH_W2 + pha + tya + adc P8ZP_SCRATCH_W2+1 + tay + pla""") + else + asmgen.out(""" + sec + sbc P8ZP_SCRATCH_W2 + pha + tya + sbc P8ZP_SCRATCH_W2+1 + tay + pla""") + assignRegisterpairWord(assign.target, RegisterOrPair.AY) + } + when (right) { is PtAddressOf -> { assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD) @@ -618,51 +650,35 @@ internal class AssignmentAsmGen(private val program: PtProgram, } is PtTypeCast -> { val castedValue = right.value - if(right.type in WordDatatypes && castedValue.type in ByteDatatypes) { - if(castedValue is PtIdentifier) { - val castedSymname = asmgen.asmVariableName(castedValue) - assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD) - if(expr.operator=="+") - asmgen.out(""" - clc - adc $castedSymname - bcc + - iny - +""") - else - asmgen.out(""" - sec - sbc $castedSymname - bcs + - dey - +""") - assignRegisterpairWord(assign.target, RegisterOrPair.AY) - return true - } + if(right.type in WordDatatypes && castedValue.type in ByteDatatypes && castedValue is PtIdentifier) { + val castedSymname = asmgen.asmVariableName(castedValue) + assignExpressionToRegister(left, RegisterOrPair.AY, dt == DataType.WORD) + if (expr.operator == "+") + asmgen.out( + """ + clc + adc $castedSymname + bcc + + iny ++""" + ) + else + asmgen.out( + """ + sec + sbc $castedSymname + bcs + + dey ++""" + ) + assignRegisterpairWord(assign.target, RegisterOrPair.AY) + return true } + doAddOrSubWordExpr() + return true } else -> { - assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", right.type) - assignExpressionToRegister(left, RegisterOrPair.AY, left.type==DataType.WORD) - if(expr.operator=="+") - asmgen.out(""" - clc - adc P8ZP_SCRATCH_W2 - pha - tya - adc P8ZP_SCRATCH_W2+1 - tay - pla""") - else - asmgen.out(""" - sec - sbc P8ZP_SCRATCH_W2 - pha - tya - sbc P8ZP_SCRATCH_W2+1 - tay - pla""") - assignRegisterpairWord(assign.target, RegisterOrPair.AY) + doAddOrSubWordExpr() return true } } @@ -733,6 +749,7 @@ internal class AssignmentAsmGen(private val program: PtProgram, return true } in WordDatatypes -> { + // TODO use utility function assignExpressionWordOperandsLeftAYRightScratchW1() etc. assignExpressionToVariable(expr.left, "P8ZP_SCRATCH_W1", expr.type) assignExpressionToRegister(expr.right, RegisterOrPair.AY, expr.type in SignedDatatypes) asmgen.out(""" @@ -794,6 +811,7 @@ internal class AssignmentAsmGen(private val program: PtProgram, return true } DataType.UWORD -> { + // TODO use utility function assignExpressionWordOperandsLeftAYRightScratchW1() etc. assignExpressionToVariable(expr.left, "P8ZP_SCRATCH_W1", DataType.UWORD) assignExpressionToRegister(expr.right, RegisterOrPair.AY, false) asmgen.out(" jsr math.divmod_uw_asm") @@ -801,6 +819,7 @@ internal class AssignmentAsmGen(private val program: PtProgram, return true } DataType.WORD -> { + // TODO use utility function assignExpressionWordOperandsLeftAYRightScratchW1() etc. assignExpressionToVariable(expr.left, "P8ZP_SCRATCH_W1", DataType.WORD) assignExpressionToRegister(expr.right, RegisterOrPair.AY, true) asmgen.out(" jsr math.divmod_w_asm") @@ -824,6 +843,7 @@ internal class AssignmentAsmGen(private val program: PtProgram, return true } DataType.UWORD -> { + // TODO use utility function assignExpressionWordOperandsLeftAYRightScratchW1() etc. assignExpressionToVariable(expr.left, "P8ZP_SCRATCH_W1", DataType.UWORD) assignExpressionToRegister(expr.right, RegisterOrPair.AY, false) asmgen.out(" jsr math.divmod_uw_asm") @@ -966,35 +986,9 @@ internal class AssignmentAsmGen(private val program: PtProgram, private fun assignOptimizedComparisonWords(expr: PtBinaryExpression, assign: AsmAssignment): Boolean { val signed = expr.left.type == DataType.WORD || expr.right.type == DataType.WORD - fun assignExpressionOperandsLeftScratchRightAY() { - if(expr.right.isSimple()) { - assignExpressionToVariable(expr.left, "P8ZP_SCRATCH_W1", expr.left.type) - assignExpressionToRegister(expr.right, RegisterOrPair.AY, signed) - } else { - assignExpressionToRegister(expr.right, RegisterOrPair.AY, signed) - asmgen.saveRegisterStack(CpuRegister.A, false) - asmgen.saveRegisterStack(CpuRegister.Y, false) - assignExpressionToVariable(expr.left, "P8ZP_SCRATCH_W1", expr.left.type) - asmgen.restoreRegisterStack(CpuRegister.Y, false) - asmgen.restoreRegisterStack(CpuRegister.A, false) - } - } - fun assignExpressionOperandsLeftAYRightScratch() { - if(expr.left.isSimple()) { - assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_W1", expr.left.type) - assignExpressionToRegister(expr.left, RegisterOrPair.AY, signed) - } else { - assignExpressionToRegister(expr.left, RegisterOrPair.AY, signed) - asmgen.saveRegisterStack(CpuRegister.A, false) - asmgen.saveRegisterStack(CpuRegister.Y, false) - assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_W1", expr.left.type) - asmgen.restoreRegisterStack(CpuRegister.Y, false) - asmgen.restoreRegisterStack(CpuRegister.A, false) - } - } when(expr.operator) { "==" -> { - assignExpressionOperandsLeftScratchRightAY() + assignExpressionWordOperandsLeftScratchW1RightAY(expr) asmgen.out(""" cmp P8ZP_SCRATCH_W1 bne + @@ -1006,7 +1000,7 @@ internal class AssignmentAsmGen(private val program: PtProgram, +""") } "!=" -> { - assignExpressionOperandsLeftScratchRightAY() + assignExpressionWordOperandsLeftScratchW1RightAY(expr) asmgen.out(""" cmp P8ZP_SCRATCH_W1 bne + @@ -1019,7 +1013,7 @@ internal class AssignmentAsmGen(private val program: PtProgram, } "<" -> { if(signed) { - assignExpressionOperandsLeftAYRightScratch() + assignExpressionWordOperandsLeftAYRightScratchW1(expr) asmgen.out(""" cmp P8ZP_SCRATCH_W1 tya @@ -1033,7 +1027,7 @@ internal class AssignmentAsmGen(private val program: PtProgram, +""") } else { - assignExpressionOperandsLeftAYRightScratch() + assignExpressionWordOperandsLeftAYRightScratchW1(expr) asmgen.out(""" cpy P8ZP_SCRATCH_W1+1 bcc + @@ -1048,7 +1042,7 @@ internal class AssignmentAsmGen(private val program: PtProgram, } "<=" -> { if(signed) { - assignExpressionOperandsLeftScratchRightAY() + assignExpressionWordOperandsLeftScratchW1RightAY(expr) asmgen.out(""" cmp P8ZP_SCRATCH_W1 tya @@ -1062,7 +1056,7 @@ internal class AssignmentAsmGen(private val program: PtProgram, +""") } else { - assignExpressionOperandsLeftScratchRightAY() + assignExpressionWordOperandsLeftScratchW1RightAY(expr) asmgen.out(""" cpy P8ZP_SCRATCH_W1+1 bcc ++ @@ -1077,7 +1071,7 @@ internal class AssignmentAsmGen(private val program: PtProgram, } ">" -> { if(signed) { - assignExpressionOperandsLeftScratchRightAY() + assignExpressionWordOperandsLeftScratchW1RightAY(expr) asmgen.out(""" cmp P8ZP_SCRATCH_W1 tya @@ -1091,7 +1085,7 @@ internal class AssignmentAsmGen(private val program: PtProgram, +""") } else { - assignExpressionOperandsLeftScratchRightAY() + assignExpressionWordOperandsLeftScratchW1RightAY(expr) asmgen.out(""" cpy P8ZP_SCRATCH_W1+1 bcc + @@ -1106,7 +1100,7 @@ internal class AssignmentAsmGen(private val program: PtProgram, } ">=" -> { if(signed) { - assignExpressionOperandsLeftAYRightScratch() + assignExpressionWordOperandsLeftAYRightScratchW1(expr) asmgen.out(""" cmp P8ZP_SCRATCH_W1 tya @@ -1120,7 +1114,7 @@ internal class AssignmentAsmGen(private val program: PtProgram, +""") } else { - assignExpressionOperandsLeftAYRightScratch() + assignExpressionWordOperandsLeftAYRightScratchW1(expr) asmgen.out(""" cpy P8ZP_SCRATCH_W1+1 bcc ++ @@ -1308,6 +1302,34 @@ internal class AssignmentAsmGen(private val program: PtProgram, } } + private fun assignExpressionWordOperandsLeftScratchW1RightAY(expr: PtBinaryExpression) { + if(expr.right.isSimple()) { + assignExpressionToVariable(expr.left, "P8ZP_SCRATCH_W1", expr.left.type) + assignExpressionToRegister(expr.right, RegisterOrPair.AY, expr.right.type in SignedDatatypes) + } else { + assignExpressionToRegister(expr.right, RegisterOrPair.AY, expr.right.type in SignedDatatypes) + asmgen.saveRegisterStack(CpuRegister.A, false) + asmgen.saveRegisterStack(CpuRegister.Y, false) + assignExpressionToVariable(expr.left, "P8ZP_SCRATCH_W1", expr.left.type) + asmgen.restoreRegisterStack(CpuRegister.Y, false) + asmgen.restoreRegisterStack(CpuRegister.A, false) + } + } + + private fun assignExpressionWordOperandsLeftAYRightScratchW1(expr: PtBinaryExpression) { + if(expr.left.isSimple()) { + assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_W1", expr.left.type) + assignExpressionToRegister(expr.left, RegisterOrPair.AY, expr.left.type in SignedDatatypes) + } else { + assignExpressionToRegister(expr.left, RegisterOrPair.AY, expr.left.type in SignedDatatypes) + asmgen.saveRegisterStack(CpuRegister.A, false) + asmgen.saveRegisterStack(CpuRegister.Y, false) + assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_W1", expr.left.type) + asmgen.restoreRegisterStack(CpuRegister.Y, false) + asmgen.restoreRegisterStack(CpuRegister.A, false) + } + } + private fun assignStatusFlagByte(target: AsmAssignTarget, statusflag: Statusflag) { when(statusflag) { Statusflag.Pc -> { diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 116e24a7f..07833bc5c 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,7 +3,9 @@ TODO For next minor release ^^^^^^^^^^^^^^^^^^^^^^ +- AssignmentAsmGen: TODO use utility function <- do that - fix crash: uword remainder = seconds_uword % $0003 ==0 +- fix VM: void string.copy(".prg", &output_filename + string.length(output_filename)) - try to optimize newexpr a bit more ... diff --git a/examples/test.p8 b/examples/test.p8 index 53b2be513..3c2712b54 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,15 +1,13 @@ %import textio +%import string %zeropage basicsafe main { - word[5] dx = [111,222,333,444,555] - sub start() { - uword hit_x = 999 - cx16.r0=2 - uword new_head_x = hit_x + dx[cx16.r0L] as uword - txt.print_uw(new_head_x) + str output_filename = "?????????\x00????????????" + void string.copy(".prg", &output_filename + string.length(output_filename)) + txt.print(output_filename) } } From ef46fb2685e5dc103f604351357b1298d589679c Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Mon, 8 May 2023 21:51:55 +0200 Subject: [PATCH 14/16] refactor --- .../cpu6502/assignment/AssignmentAsmGen.kt | 52 +++++-------------- docs/source/todo.rst | 1 - 2 files changed, 14 insertions(+), 39 deletions(-) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index 95078289b..ed81924a4 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -427,15 +427,11 @@ internal class AssignmentAsmGen(private val program: PtProgram, return true } } - // TODO use utility function assignExpressionWordOperandsLeftAYRightScratchW1() etc. - assignExpressionToRegister(expr.left, RegisterOrPair.AY, false) - asmgen.saveRegisterStack(CpuRegister.A, false) - asmgen.saveRegisterStack(CpuRegister.Y, false) - assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_W1", DataType.UWORD) + assignExpressionWordOperandsLeftAYRightScratchW1(expr) when (expr.operator) { - "&", "and" -> asmgen.out(" pla | and P8ZP_SCRATCH_W1+1 | tay | pla | and P8ZP_SCRATCH_W1") - "|", "or" -> asmgen.out(" pla | ora P8ZP_SCRATCH_W1+1 | tay | pla | ora P8ZP_SCRATCH_W1") - "^", "xor" -> asmgen.out(" pla | eor P8ZP_SCRATCH_W1+1 | tay | pla | eor P8ZP_SCRATCH_W1") + "&", "and" -> asmgen.out(" and P8ZP_SCRATCH_W1 | pha | tya | and P8ZP_SCRATCH_W1+1 | tay | pla") + "|", "or" -> asmgen.out(" ora P8ZP_SCRATCH_W1 | pha | tya | ora P8ZP_SCRATCH_W1+1 | tay | pla") + "^", "xor" -> asmgen.out(" eor P8ZP_SCRATCH_W1 | pha | tya | eor P8ZP_SCRATCH_W1+1 | tay | pla") else -> throw AssemblyError("invalid operator") } assignRegisterpairWord(assign.target, RegisterOrPair.AY) @@ -473,13 +469,7 @@ internal class AssignmentAsmGen(private val program: PtProgram, return true } else if(expr.left.type in WordDatatypes && expr.right.type in WordDatatypes && expr.left.isSimple() && expr.right.isSimple()) { - // TODO use utility function assignExpressionWordOperandsLeftAYRightScratchW1() etc. - assignExpressionToRegister(expr.left, RegisterOrPair.AY, false) - asmgen.saveRegisterStack(CpuRegister.A, false) - asmgen.saveRegisterStack(CpuRegister.Y, false) - assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_W1", DataType.UWORD) - asmgen.restoreRegisterStack(CpuRegister.Y, false) - asmgen.restoreRegisterStack(CpuRegister.A, false) + assignExpressionWordOperandsLeftAYRightScratchW1(expr) if(expr.operator=="==") { asmgen.out(""" cmp P8ZP_SCRATCH_W1 @@ -547,29 +537,23 @@ internal class AssignmentAsmGen(private val program: PtProgram, } else if(dt in WordDatatypes) { fun doAddOrSubWordExpr() { - // TODO use utility function assignExpressionWordOperandsLeftAYRightScratchW1() etc. - assignExpressionToRegister(left, RegisterOrPair.AY, dt==DataType.WORD) - asmgen.saveRegisterStack(CpuRegister.A, false) - asmgen.saveRegisterStack(CpuRegister.Y, false) - assignExpressionToVariable(right, "P8ZP_SCRATCH_W2", dt) - asmgen.restoreRegisterStack(CpuRegister.Y, false) - asmgen.restoreRegisterStack(CpuRegister.A, false) + assignExpressionWordOperandsLeftAYRightScratchW1(expr) if(expr.operator=="+") asmgen.out(""" clc - adc P8ZP_SCRATCH_W2 + adc P8ZP_SCRATCH_W1 pha tya - adc P8ZP_SCRATCH_W2+1 + adc P8ZP_SCRATCH_W1+1 tay pla""") else asmgen.out(""" sec - sbc P8ZP_SCRATCH_W2 + sbc P8ZP_SCRATCH_W1 pha tya - sbc P8ZP_SCRATCH_W2+1 + sbc P8ZP_SCRATCH_W1+1 tay pla""") assignRegisterpairWord(assign.target, RegisterOrPair.AY) @@ -749,9 +733,7 @@ internal class AssignmentAsmGen(private val program: PtProgram, return true } in WordDatatypes -> { - // TODO use utility function assignExpressionWordOperandsLeftAYRightScratchW1() etc. - assignExpressionToVariable(expr.left, "P8ZP_SCRATCH_W1", expr.type) - assignExpressionToRegister(expr.right, RegisterOrPair.AY, expr.type in SignedDatatypes) + assignExpressionWordOperandsLeftScratchW1RightAY(expr) asmgen.out(""" jsr math.multiply_words lda math.multiply_words.result @@ -811,17 +793,13 @@ internal class AssignmentAsmGen(private val program: PtProgram, return true } DataType.UWORD -> { - // TODO use utility function assignExpressionWordOperandsLeftAYRightScratchW1() etc. - assignExpressionToVariable(expr.left, "P8ZP_SCRATCH_W1", DataType.UWORD) - assignExpressionToRegister(expr.right, RegisterOrPair.AY, false) + assignExpressionWordOperandsLeftScratchW1RightAY(expr) asmgen.out(" jsr math.divmod_uw_asm") assignRegisterpairWord(assign.target, RegisterOrPair.AY) return true } DataType.WORD -> { - // TODO use utility function assignExpressionWordOperandsLeftAYRightScratchW1() etc. - assignExpressionToVariable(expr.left, "P8ZP_SCRATCH_W1", DataType.WORD) - assignExpressionToRegister(expr.right, RegisterOrPair.AY, true) + assignExpressionWordOperandsLeftScratchW1RightAY(expr) asmgen.out(" jsr math.divmod_w_asm") assignRegisterpairWord(assign.target, RegisterOrPair.AY) return true @@ -843,9 +821,7 @@ internal class AssignmentAsmGen(private val program: PtProgram, return true } DataType.UWORD -> { - // TODO use utility function assignExpressionWordOperandsLeftAYRightScratchW1() etc. - assignExpressionToVariable(expr.left, "P8ZP_SCRATCH_W1", DataType.UWORD) - assignExpressionToRegister(expr.right, RegisterOrPair.AY, false) + assignExpressionWordOperandsLeftScratchW1RightAY(expr) asmgen.out(" jsr math.divmod_uw_asm") assignVariableWord(assign.target, "P8ZP_SCRATCH_W2") return true diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 07833bc5c..4d9a6ab7a 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,7 +3,6 @@ TODO For next minor release ^^^^^^^^^^^^^^^^^^^^^^ -- AssignmentAsmGen: TODO use utility function <- do that - fix crash: uword remainder = seconds_uword % $0003 ==0 - fix VM: void string.copy(".prg", &output_filename + string.length(output_filename)) - try to optimize newexpr a bit more From 97df33ab1adb9a97ba988e826ed6bb6074a62e13 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Mon, 8 May 2023 22:26:22 +0200 Subject: [PATCH 15/16] IR: fix byte to word assignment not doing value extension --- .../codegen/intermediate/AssignmentGen.kt | 55 ++++++++++++------- docs/source/todo.rst | 2 +- examples/test.p8 | 48 +++++++++++++++- .../src/prog8/intermediate/IRInstructions.kt | 26 ++++----- 4 files changed, 93 insertions(+), 38 deletions(-) diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt index 53b30902b..4b1be02c4 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt @@ -161,7 +161,8 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express val targetIdent = assignment.target.identifier val targetMemory = assignment.target.memory val targetArray = assignment.target.array - val vmDt = codeGen.irType(assignment.value.type) + val valueDt = codeGen.irType(assignment.value.type) + val targetDt = codeGen.irType(assignment.target.type) val result = mutableListOf() var valueRegister = -1 @@ -169,30 +170,42 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express val zero = codeGen.isZero(assignment.value) if(!zero) { // calculate the assignment value - if (vmDt == IRDataType.FLOAT) { + if (valueDt == IRDataType.FLOAT) { val tr = expressionEval.translateExpression(assignment.value) valueFpRegister = tr.resultFpReg addToResult(result, tr, -1, valueFpRegister) } else { + val extendByteToWord = if(targetDt != valueDt) { + // usually an error EXCEPT when a byte is assigned to a word. + if(targetDt==IRDataType.WORD && valueDt==IRDataType.BYTE) + true + else + throw AssemblyError("assignment value and target dt mismatch") + } else false if (assignment.value is PtMachineRegister) { valueRegister = (assignment.value as PtMachineRegister).register + if(extendByteToWord) + addInstr(result, IRInstruction(Opcode.EXT, IRDataType.BYTE, reg1=valueRegister), null) } else { val tr = expressionEval.translateExpression(assignment.value) valueRegister = tr.resultReg addToResult(result, tr, valueRegister, -1) + if(extendByteToWord) { + val opcode = if(assignment.value.type in SignedDatatypes) Opcode.EXTS else Opcode.EXT + addInstr(result, IRInstruction(opcode, IRDataType.BYTE, reg1 = valueRegister), null) + } } } } if(targetIdent!=null) { val instruction = if(zero) { - IRInstruction(Opcode.STOREZM, vmDt, labelSymbol = targetIdent.name) + IRInstruction(Opcode.STOREZM, targetDt, labelSymbol = targetIdent.name) } else { - if (vmDt == IRDataType.FLOAT) { - IRInstruction(Opcode.STOREM, vmDt, fpReg1 = valueFpRegister, labelSymbol = targetIdent.name) - } + if (targetDt == IRDataType.FLOAT) + IRInstruction(Opcode.STOREM, targetDt, fpReg1 = valueFpRegister, labelSymbol = targetIdent.name) else - IRInstruction(Opcode.STOREM, vmDt, reg1 = valueRegister, labelSymbol = targetIdent.name) + IRInstruction(Opcode.STOREM, targetDt, reg1 = valueRegister, labelSymbol = targetIdent.name) } result += IRCodeChunk(null, null).also { it += instruction } return result @@ -214,9 +227,9 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express if(zero) { // there's no STOREZIX instruction valueRegister = codeGen.registers.nextFree() - code += IRInstruction(Opcode.LOAD, vmDt, reg1=valueRegister, immediate = 0) + code += IRInstruction(Opcode.LOAD, targetDt, reg1=valueRegister, immediate = 0) } - code += IRInstruction(Opcode.STOREIX, vmDt, reg1=valueRegister, reg2=idxReg, labelSymbol = variable) + code += IRInstruction(Opcode.STOREIX, targetDt, reg1=valueRegister, reg2=idxReg, labelSymbol = variable) result += code return result } @@ -225,59 +238,59 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express if(zero) { if(fixedIndex!=null) { val offset = fixedIndex*itemsize - val chunk = IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREZM, vmDt, labelSymbol = "$variable+$offset") } + val chunk = IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREZM, targetDt, labelSymbol = "$variable+$offset") } result += chunk } else { val (code, indexReg) = loadIndexReg(targetArray, itemsize) result += code - result += IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREZX, vmDt, reg1=indexReg, labelSymbol = variable) } + result += IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREZX, targetDt, reg1=indexReg, labelSymbol = variable) } } } else { - if(vmDt== IRDataType.FLOAT) { + if(targetDt== IRDataType.FLOAT) { if(fixedIndex!=null) { val offset = fixedIndex*itemsize - val chunk = IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREM, vmDt, fpReg1 = valueFpRegister, labelSymbol = "$variable+$offset") } + val chunk = IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREM, targetDt, fpReg1 = valueFpRegister, labelSymbol = "$variable+$offset") } result += chunk } else { val (code, indexReg) = loadIndexReg(targetArray, itemsize) result += code - result += IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREX, vmDt, reg1 = indexReg, fpReg1 = valueFpRegister, labelSymbol = variable) } + result += IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREX, targetDt, reg1 = indexReg, fpReg1 = valueFpRegister, labelSymbol = variable) } } } else { if(fixedIndex!=null) { val offset = fixedIndex*itemsize - val chunk = IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREM, vmDt, reg1 = valueRegister, labelSymbol = "$variable+$offset") } + val chunk = IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREM, targetDt, reg1 = valueRegister, labelSymbol = "$variable+$offset") } result += chunk } else { val (code, indexReg) = loadIndexReg(targetArray, itemsize) result += code - result += IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREX, vmDt, reg1 = valueRegister, reg2=indexReg, labelSymbol = variable) } + result += IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREX, targetDt, reg1 = valueRegister, reg2=indexReg, labelSymbol = variable) } } } } return result } else if(targetMemory!=null) { - require(vmDt== IRDataType.BYTE) { "must be byte type ${targetMemory.position}"} + require(targetDt == IRDataType.BYTE) { "must be byte type ${targetMemory.position}"} if(zero) { if(targetMemory.address is PtNumber) { - val chunk = IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREZM, vmDt, address = (targetMemory.address as PtNumber).number.toInt()) } + val chunk = IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREZM, targetDt, address = (targetMemory.address as PtNumber).number.toInt()) } result += chunk } else { val tr = expressionEval.translateExpression(targetMemory.address) val addressReg = tr.resultReg addToResult(result, tr, tr.resultReg, -1) - result += IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREZI, vmDt, reg1=addressReg) } + result += IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREZI, targetDt, reg1=addressReg) } } } else { if(targetMemory.address is PtNumber) { - val chunk = IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREM, vmDt, reg1=valueRegister, address=(targetMemory.address as PtNumber).number.toInt()) } + val chunk = IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREM, targetDt, reg1=valueRegister, address=(targetMemory.address as PtNumber).number.toInt()) } result += chunk } else { val tr = expressionEval.translateExpression(targetMemory.address) val addressReg = tr.resultReg addToResult(result, tr, tr.resultReg, -1) - result += IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREI, vmDt, reg1=valueRegister, reg2=addressReg) } + result += IRCodeChunk(null, null).also { it += IRInstruction(Opcode.STOREI, targetDt, reg1=valueRegister, reg2=addressReg) } } } diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 4d9a6ab7a..81cedb0f5 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -4,7 +4,7 @@ TODO For next minor release ^^^^^^^^^^^^^^^^^^^^^^ - fix crash: uword remainder = seconds_uword % $0003 ==0 -- fix VM: void string.copy(".prg", &output_filename + string.length(output_filename)) +- fix VM problem with param passing: void string.copy(".prg", &output_filename + string.length(output_filename)) - try to optimize newexpr a bit more ... diff --git a/examples/test.p8 b/examples/test.p8 index 3c2712b54..e7b71fec9 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -5,9 +5,51 @@ main { sub start() { - str output_filename = "?????????\x00????????????" - void string.copy(".prg", &output_filename + string.length(output_filename)) - txt.print(output_filename) + str output_filename = "12345678\x00abcdefghij" + void myprint2("hallo", &output_filename+string.length(output_filename)) +; ubyte length = string.length(output_filename) +; txt.print_ub(length) +; txt.nl() +; txt.print_uw(&output_filename) +; txt.nl() +; output_filename[2]='!' +; txt.print(output_filename) +; txt.nl() +; +; void string_copy(".prg", &output_filename + string.length(output_filename)) +; txt.print(output_filename) + } + + sub myprint2(str source1, str source2) { + txt.print(source1) + txt.nl() + txt.print(source2) + txt.nl() + } + + sub string_copy(str source, str target) -> ubyte { + ; Copy a string to another, overwriting that one. + ; Returns the length of the string that was copied. + ; Often you don’t have to call this explicitly and can just write string1 = string2 + ; but this function is useful if you’re dealing with addresses for instance. + txt.print("src=") + txt.print(source) + txt.nl() + txt.print("target=") + txt.print(target) + txt.nl() + ubyte ix + repeat 5 { + ubyte qq=source[ix] + txt.print_ub(qq) + target[ix]=qq + txt.spc() + if qq==0 { + txt.nl() + return ix + } + ix++ + } } } diff --git a/intermediate/src/prog8/intermediate/IRInstructions.kt b/intermediate/src/prog8/intermediate/IRInstructions.kt index bd0f26195..115562d00 100644 --- a/intermediate/src/prog8/intermediate/IRInstructions.kt +++ b/intermediate/src/prog8/intermediate/IRInstructions.kt @@ -89,26 +89,26 @@ bgesr reg1, reg2, address - jump to location in program given by l ble reg1, value, address - jump to location in program given by location, if reg1 <= immediate value (unsigned) bles reg1, value, address - jump to location in program given by location, if reg1 <= immediate value (signed) ( NOTE: there are no bltr/bler instructions because these are equivalent to bgtr/bger with the register operands swapped around.) -sz reg1, reg2 - set reg1=1 if reg2==0, otherwise set reg1=0 -snz reg1, reg2 - set reg1=1 if reg2!=0, otherwise set reg1=0 -seq reg1, reg2 - set reg1=1 if reg1 == reg2, otherwise set reg1=0 -sne reg1, reg2 - set reg1=1 if reg1 != reg2, otherwise set reg1=0 -slt reg1, reg2 - set reg1=1 if reg1 < reg2 (unsigned), otherwise set reg1=0 -slts reg1, reg2 - set reg1=1 if reg1 < reg2 (signed), otherwise set reg1=0 -sle reg1, reg2 - set reg1=1 if reg1 <= reg2 (unsigned), otherwise set reg1=0 -sles reg1, reg2 - set reg1=1 if reg1 <= reg2 (signed), otherwise set reg1=0 -sgt reg1, reg2 - set reg1=1 if reg1 > reg2 (unsigned), otherwise set reg1=0 -sgts reg1, reg2 - set reg1=1 if reg1 > reg2 (signed), otherwise set reg1=0 -sge reg1, reg2 - set reg1=1 if reg1 >= reg2 (unsigned), otherwise set reg1=0 -sges reg1, reg2 - set reg1=1 if reg1 >= reg2 (signed), otherwise set reg1=0 +sz reg1, reg2 - set reg1=1.b if reg2==0, otherwise set reg1=0.b +snz reg1, reg2 - set reg1=1.b if reg2!=0, otherwise set reg1=0.b +seq reg1, reg2 - set reg1=1.b if reg1 == reg2, otherwise set reg1=0.b +sne reg1, reg2 - set reg1=1.b if reg1 != reg2, otherwise set reg1=0.b +slt reg1, reg2 - set reg1=1.b if reg1 < reg2 (unsigned), otherwise set reg1=0.b +slts reg1, reg2 - set reg1=1.b if reg1 < reg2 (signed), otherwise set reg1=0.b +sle reg1, reg2 - set reg1=1.b if reg1 <= reg2 (unsigned), otherwise set reg1=0.b +sles reg1, reg2 - set reg1=1.b if reg1 <= reg2 (signed), otherwise set reg1=0.b +sgt reg1, reg2 - set reg1=1.b if reg1 > reg2 (unsigned), otherwise set reg1=0.b +sgts reg1, reg2 - set reg1=1.b if reg1 > reg2 (signed), otherwise set reg1=0.b +sge reg1, reg2 - set reg1=1.b if reg1 >= reg2 (unsigned), otherwise set reg1=0.b +sges reg1, reg2 - set reg1=1.b if reg1 >= reg2 (signed), otherwise set reg1=0.b ARITHMETIC ---------- All have type b or w or f. Note: result types are the same as operand types! E.g. byte*byte->byte. -ext reg1 - reg1 = unsigned extension of reg1 (which in practice just means clearing the MSB / MSW) (ext.w not yet implemented as we don't have longs yet) exts reg1 - reg1 = signed extension of reg1 (byte to word, or word to long) (note: ext.w is not yet implemented as we don't have longs yet) +ext reg1 - reg1 = unsigned extension of reg1 (which in practice just means clearing the MSB / MSW) (ext.w not yet implemented as we don't have longs yet) inc reg1 - reg1 = reg1+1 incm address - memory at address += 1 dec reg1 - reg1 = reg1-1 From 4c8898a639b9f1e1c96f21deccbaf9b32a10c261 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Mon, 8 May 2023 23:02:48 +0200 Subject: [PATCH 16/16] fix typecheck crash on certain byte to word assignments --- .../cpu6502/assignment/AssignmentAsmGen.kt | 22 +++++++-- docs/source/todo.rst | 1 - examples/test.p8 | 48 ++----------------- 3 files changed, 21 insertions(+), 50 deletions(-) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index ed81924a4..aee9dc96a 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -2511,14 +2511,24 @@ internal class AssignmentAsmGen(private val program: PtProgram, } internal fun assignRegisterByte(target: AsmAssignTarget, register: CpuRegister, signed: Boolean) { - // we make an exception in the type check for assigning something to a register pair AX, AY or XY - // these will be correctly typecasted from a byte to a word value here - if(target.register !in setOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY)) - require(target.datatype in ByteDatatypes) { "assign target must be byte type ${target.position}"} + val assignAsWord = target.datatype in WordDatatypes when(target.kind) { TargetStorageKind.VARIABLE -> { asmgen.out(" st${register.name.lowercase()} ${target.asmVarname}") + if(assignAsWord) { + if(target.datatype in SignedDatatypes) { + if(register!=CpuRegister.A) + asmgen.out(" t${register.name.lowercase()}a") + asmgen.signExtendAYlsb(if(target.datatype in SignedDatatypes) DataType.BYTE else DataType.UBYTE) + asmgen.out(" sty ${target.asmVarname}+1") + } else { + if(asmgen.isTargetCpu(CpuType.CPU65c02)) + asmgen.out(" stz ${target.asmVarname}+1") + else + asmgen.out(" lda #0 | sta ${target.asmVarname}+1") + } + } } TargetStorageKind.MEMORY -> { when(register) { @@ -2529,6 +2539,8 @@ internal class AssignmentAsmGen(private val program: PtProgram, storeRegisterAInMemoryAddress(target.memory!!) } TargetStorageKind.ARRAY -> { + if(assignAsWord) + TODO("assign register as word into Array not yet supported") if (target.constArrayIndexValue!=null) { when (register) { CpuRegister.A -> asmgen.out(" sta ${target.asmVarname}+${target.constArrayIndexValue}") @@ -2690,6 +2702,8 @@ internal class AssignmentAsmGen(private val program: PtProgram, } } TargetStorageKind.STACK -> { + if(assignAsWord) + TODO("assign register as word onto Stack not yet supported") when(register) { CpuRegister.A -> asmgen.out(" sta P8ESTACK_LO,x | dex") CpuRegister.X -> throw AssemblyError("can't use X here") diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 81cedb0f5..13e79a6e1 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,7 +3,6 @@ TODO For next minor release ^^^^^^^^^^^^^^^^^^^^^^ -- fix crash: uword remainder = seconds_uword % $0003 ==0 - fix VM problem with param passing: void string.copy(".prg", &output_filename + string.length(output_filename)) - try to optimize newexpr a bit more diff --git a/examples/test.p8 b/examples/test.p8 index e7b71fec9..6375333dd 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -5,51 +5,9 @@ main { sub start() { - str output_filename = "12345678\x00abcdefghij" - void myprint2("hallo", &output_filename+string.length(output_filename)) -; ubyte length = string.length(output_filename) -; txt.print_ub(length) -; txt.nl() -; txt.print_uw(&output_filename) -; txt.nl() -; output_filename[2]='!' -; txt.print(output_filename) -; txt.nl() -; -; void string_copy(".prg", &output_filename + string.length(output_filename)) -; txt.print(output_filename) - } - - sub myprint2(str source1, str source2) { - txt.print(source1) - txt.nl() - txt.print(source2) - txt.nl() - } - - sub string_copy(str source, str target) -> ubyte { - ; Copy a string to another, overwriting that one. - ; Returns the length of the string that was copied. - ; Often you don’t have to call this explicitly and can just write string1 = string2 - ; but this function is useful if you’re dealing with addresses for instance. - txt.print("src=") - txt.print(source) - txt.nl() - txt.print("target=") - txt.print(target) - txt.nl() - ubyte ix - repeat 5 { - ubyte qq=source[ix] - txt.print_ub(qq) - target[ix]=qq - txt.spc() - if qq==0 { - txt.nl() - return ix - } - ix++ - } + uword seconds_uword = 1 + uword remainder = seconds_uword % $0003 ==0 + txt.print_uw(remainder) } }