From df2d7d47341321eaebb09f3a0c6b9106bd2f5944 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sun, 19 Mar 2023 13:10:41 +0100 Subject: [PATCH] fix RPN comparison exprs --- codeCore/src/prog8/code/ast/AstPrinter.kt | 16 ++++-- .../src/prog8/codegen/cpu6502/AsmGen.kt | 2 + .../cpu6502/assignment/AsmAssignment.kt | 22 ++++++++ .../cpu6502/assignment/AssignmentAsmGen.kt | 54 ++++++++++++++----- compiler/src/prog8/compiler/Compiler.kt | 2 +- compiler/test/ast/TestIntermediateAst.kt | 2 +- docs/source/todo.rst | 1 - examples/balls.p8 | 4 +- examples/test.p8 | 19 +++---- 9 files changed, 89 insertions(+), 33 deletions(-) diff --git a/codeCore/src/prog8/code/ast/AstPrinter.kt b/codeCore/src/prog8/code/ast/AstPrinter.kt index ca1aad133..8da3affba 100644 --- a/codeCore/src/prog8/code/ast/AstPrinter.kt +++ b/codeCore/src/prog8/code/ast/AstPrinter.kt @@ -6,7 +6,7 @@ import prog8.code.core.* * Produces readable text from a [PtNode] (AST node, usually starting with PtProgram as root), * passing it as a String to the specified receiver function. */ -fun printAst(root: PtNode, output: (text: String) -> Unit) { +fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Unit) { fun type(dt: DataType) = "!${dt.name.lowercase()}!" fun txt(node: PtNode): String { return when(node) { @@ -136,16 +136,22 @@ fun printAst(root: PtNode, output: (text: String) -> Unit) { root.children.forEach { walkAst(it) { node, depth -> val txt = txt(node) - if(txt.isNotEmpty()) - output(" ".repeat(depth) + txt(node)) + val library = if(node is PtBlock) node.library else node.definingBlock()?.library==true + if(!library || !skipLibraries) { + if (txt.isNotEmpty()) + output(" ".repeat(depth) + txt(node)) + } } } println() } else { walkAst(root) { node, depth -> val txt = txt(node) - if(txt.isNotEmpty()) - output(" ".repeat(depth) + txt(node)) + val library = if(node is PtBlock) node.library else node.definingBlock()?.library==true + if(!library || !skipLibraries) { + if (txt.isNotEmpty()) + output(" ".repeat(depth) + txt(node)) + } } } } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt index 1ae9d4e42..69015a532 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt @@ -26,6 +26,8 @@ class AsmGen6502: ICodeGeneratorBackend { errors.warn("EXPERIMENTAL RPN EXPRESSION NODES ARE USED. CODE SIZE+SPEED WILL SUFFER.", Position.DUMMY) } + // printAst(program, true) { println(it) } + val asmgen = AsmGen6502Internal(program, symbolTable, options, errors) return asmgen.compileToAssembly() } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AsmAssignment.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AsmAssignment.kt index ef14e3e49..9f7b9cc9b 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AsmAssignment.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AsmAssignment.kt @@ -102,6 +102,28 @@ internal class AsmAssignTarget(val kind: TargetStorageKind, RegisterOrPair.R15 -> AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, if(signed) DataType.WORD else DataType.UWORD, scope, pos, register = registers) } } + + fun isSameAs(left: PtExpression): Boolean = + when(kind) { + TargetStorageKind.VARIABLE -> { + val scopedName: String = if('.' in asmVarname) + asmVarname + else { + val scopeName = (scope as? PtNamedNode)?.scopedName + if (scopeName == null) asmVarname else "$scopeName.$asmVarname" + } + left is PtIdentifier && left.name==scopedName + } + TargetStorageKind.ARRAY -> { + left is PtArrayIndexer && left isSameAs array!! + } + TargetStorageKind.MEMORY -> { + left isSameAs memory!! + } + TargetStorageKind.REGISTER, TargetStorageKind.STACK -> { + false + } + } } internal class AsmAssignSource(val kind: SourceStorageKind, diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index 6f0b9d21f..7453c62df 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -366,7 +366,7 @@ internal class AssignmentAsmGen(private val program: PtProgram, val value = assign.source.expression as PtRpn val (left, oper, right) = value.finalOperation() - // TODO RPN the fallthrough if size>3 seems to generate not 100% correct code... (balls example fills the screen weird) + // TODO RPN the fallthrough if size>3 seems to generate very inefficient code... if(value.children.size==3 && oper.operator in ComparisonOperators) { assignRPNComparison(assign, value) return true @@ -564,20 +564,46 @@ internal class AssignmentAsmGen(private val program: PtProgram, val rightNum = right as? PtNumber val jumpIfFalseLabel = asmgen.makeLabel("cmp") - when(assign.target.datatype) { - in ByteDatatypes -> assignConstantByte(assign.target, 0) - in WordDatatypes -> assignConstantWord(assign.target, 0) - DataType.FLOAT -> assignConstantFloat(assign.target, 0.0) - else -> throw AssemblyError("invalid dt") + if(assign.target.isSameAs(left)) { + // In-place comparison Target = Target Right + // NOTE : this generates pretty inefficient code.... TODO RPN optimize? + val targetDt = assign.target.datatype + val tempVar = asmgen.getTempVarName(assign.target.datatype) + val tempTarget = AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, targetDt, comparison.definingISub(), comparison.position, variableAsmName = tempVar) + when (assign.target.datatype) { + in ByteDatatypes -> assignConstantByte(tempTarget, 0) + in WordDatatypes -> assignConstantWord(tempTarget, 0) + DataType.FLOAT -> assignConstantFloat(tempTarget, 0.0) + else -> throw AssemblyError("invalid dt") + } + asmgen.testNonzeroComparisonAndJump(left, oper.operator, right, jumpIfFalseLabel, leftNum, rightNum) + when (assign.target.datatype) { + in ByteDatatypes -> assignConstantByte(tempTarget, 1) + in WordDatatypes -> assignConstantWord(tempTarget, 1) + DataType.FLOAT -> assignConstantFloat(tempTarget, 1.0) + else -> throw AssemblyError("invalid dt") + } + asmgen.out(jumpIfFalseLabel) + val tempLeft = PtIdentifier(tempVar, targetDt, comparison.position) + tempLeft.parent=comparison + asmgen.assignExpressionTo(tempLeft, assign.target) + } else { + // Normal comparison Target = Left Right + when (assign.target.datatype) { + in ByteDatatypes -> assignConstantByte(assign.target, 0) + in WordDatatypes -> assignConstantWord(assign.target, 0) + DataType.FLOAT -> assignConstantFloat(assign.target, 0.0) + else -> throw AssemblyError("invalid dt") + } + asmgen.testNonzeroComparisonAndJump(left, oper.operator, right, jumpIfFalseLabel, leftNum, rightNum) + when (assign.target.datatype) { + in ByteDatatypes -> assignConstantByte(assign.target, 1) + in WordDatatypes -> assignConstantWord(assign.target, 1) + DataType.FLOAT -> assignConstantFloat(assign.target, 1.0) + else -> throw AssemblyError("invalid dt") + } + asmgen.out(jumpIfFalseLabel) } - asmgen.testNonzeroComparisonAndJump(left, oper.operator, right, jumpIfFalseLabel, leftNum, rightNum) - when(assign.target.datatype) { - in ByteDatatypes -> assignConstantByte(assign.target, 1) - in WordDatatypes -> assignConstantWord(assign.target, 1) - DataType.FLOAT -> assignConstantFloat(assign.target, 1.0) - else -> throw AssemblyError("invalid dt") - } - asmgen.out(jumpIfFalseLabel) } private fun attemptAssignOptimizedBinexpr(expr: PtBinaryExpression, assign: AsmAssignment): Boolean { diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 79db69c5f..bdb4bc897 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -120,7 +120,7 @@ fun compileProgram(args: CompilerArguments): CompilationResult? { // println("*********** COMPILER AST RIGHT BEFORE ASM GENERATION *************") // printProgram(program) // println("*********** AST RIGHT BEFORE ASM GENERATION *************") -// printAst(intermediateAst, ::println) +// printAst(intermediateAst, true, ::println) if(!createAssemblyAndAssemble(intermediateAst, args.errors, compilationOptions)) { System.err.println("Error in codegeneration or assembler") diff --git a/compiler/test/ast/TestIntermediateAst.kt b/compiler/test/ast/TestIntermediateAst.kt index 8d944c80a..13bb420fb 100644 --- a/compiler/test/ast/TestIntermediateAst.kt +++ b/compiler/test/ast/TestIntermediateAst.kt @@ -66,7 +66,7 @@ class TestIntermediateAst: FunSpec({ val fcall = (entry.children[4] as PtAssignment).value as PtFunctionCall fcall.void shouldBe false fcall.type shouldBe DataType.UBYTE - printAst(ast, ::println) + printAst(ast, false, ::println) } }) \ No newline at end of file diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 43caa9ad1..314f3e904 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -1,7 +1,6 @@ TODO ==== -BRANCH: balls.p8 directions are wrong since the comparison operator fallthrough in attemptAssignOptimizedExprRPN BRANCH: Fix the TODO RPN routines to be optimized assembly in RpnExpressionAsmGen.kt BRANCH: check BinExprSplitter disablement any effect for RPN? BRANCH: Implement RPN codegen for IR. diff --git a/examples/balls.p8 b/examples/balls.p8 index 14081c0af..883dddb7c 100644 --- a/examples/balls.p8 +++ b/examples/balls.p8 @@ -43,7 +43,7 @@ main { DX[lp] = true else BX[lp]=BX[lp]-1 - } else if DX[lp] { + } else { if (BX[lp] == txt.DEFAULT_WIDTH-1) { BX[lp] = txt.DEFAULT_WIDTH-2 DX[lp] = false @@ -56,7 +56,7 @@ main { DY[lp] = true else BY[lp]=BY[lp]-1 - } else if DY[lp] == 1 { + } else { if (BY[lp] == txt.DEFAULT_HEIGHT-1) { BY[lp] = txt.DEFAULT_HEIGHT-2 DY[lp] = false diff --git a/examples/test.p8 b/examples/test.p8 index 06f840700..23e7dc5ec 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,4 +1,5 @@ %import math +%import textio %zeropage basicsafe ; Note: this program is compatible with C64 and CX16. @@ -6,15 +7,15 @@ main { sub start() { -; ubyte[255] BC -; bool[255] DX - - if math.rnd() & 22 { - cx16.r0L++ + bool x + ubyte y + repeat 20 { + x = math.rnd() & 1 + y = ((math.rnd()&1)!=0) + txt.print_ub(x) + txt.spc() + txt.print_ub(y) + txt.nl() } -; BC[2] = math.rnd() & 15 -; BC[3] = math.rnd() & 15 -; BC[4] = math.rnd() & 15 - ;DX[2] = math.rnd() & 1 } }