From 53df0eb70763a794886bd5276951e1d07c7cc1b4 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Wed, 10 Apr 2024 22:04:03 +0200 Subject: [PATCH] cleanups --- codeCore/src/prog8/code/ast/AstExpressions.kt | 6 +- .../src/prog8/codegen/cpu6502/AsmOptimizer.kt | 2 - .../src/prog8/codegen/cpu6502/IfElseAsmGen.kt | 2 +- .../codegen/cpu6502/ProgramAndVarsGen.kt | 3 +- .../cpu6502/assignment/AnyExprAsmGen.kt | 70 ++++--------------- .../intermediate/IRPeepholeOptimizer.kt | 16 ++--- .../optimizer/ConstantFoldingOptimizer.kt | 1 - .../prog8/optimizer/ExpressionSimplifier.kt | 4 +- .../compiler/astprocessing/VariousCleanups.kt | 22 ------ .../src/prog8/ast/antlr/Antlr2Kotlin.kt | 2 +- .../src/prog8/ast/statements/AstStatements.kt | 3 +- examples/test.p8 | 51 +++++++++++--- .../src/prog8/intermediate/IRFileReader.kt | 2 +- .../src/prog8/intermediate/IRSymbolTable.kt | 1 - 14 files changed, 66 insertions(+), 119 deletions(-) diff --git a/codeCore/src/prog8/code/ast/AstExpressions.kt b/codeCore/src/prog8/code/ast/AstExpressions.kt index 9bebd8abb..9fa7c81c9 100644 --- a/codeCore/src/prog8/code/ast/AstExpressions.kt +++ b/codeCore/src/prog8/code/ast/AstExpressions.kt @@ -139,13 +139,9 @@ class PtAddressOf(position: Position) : PtExpression(DataType.UWORD, position) { class PtArrayIndexer(elementType: DataType, position: Position): PtExpression(elementType, position) { val variable: PtIdentifier - get() { - require((children[0] as? PtIdentifier)?.type in ArrayDatatypes+DataType.STR) // TODO remove - return children[0] as PtIdentifier - } + get() = children[0] as PtIdentifier val index: PtExpression get() = children[1] as PtExpression - val splitWords: Boolean get() = variable.type in SplitWordArrayTypes diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmOptimizer.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmOptimizer.kt index 8fbfa512c..f499f8dea 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmOptimizer.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmOptimizer.kt @@ -65,8 +65,6 @@ internal fun optimizeAssembly(lines: MutableList, machine: IMachineDefin numberOfOptimizations++ } - // TODO more assembly peephole optimizations - return numberOfOptimizations } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/IfElseAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/IfElseAsmGen.kt index fdfa3e21e..d1084f9ea 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/IfElseAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/IfElseAsmGen.kt @@ -193,7 +193,7 @@ internal class IfElseAsmGen(private val program: PtProgram, else translateIfElseBodies("beq", stmt) } else { - errors.warn("SLOW FALLBACK FOR 'IF' CODEGEN - ask for support", stmt.position) // TODO should have no more of these at all + errors.warn("SLOW FALLBACK FOR 'IF' CODEGEN - ask for support", stmt.position) // should not occur ;-) assignConditionValueToRegisterAndTest(stmt.condition) if(jumpAfterIf!=null) translateJumpElseBodies("bne", "beq", jumpAfterIf, stmt.elseScope) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt index 1a61f1750..55a17ffd4 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt @@ -635,8 +635,7 @@ internal class ProgramAndVarsGen( } else 0 when (variable.dt) { - DataType.BOOL -> TODO("bool var to asm") - DataType.UBYTE -> asmgen.out("${variable.name}\t.byte ${initialValue.toHex()}") + DataType.BOOL, DataType.UBYTE -> asmgen.out("${variable.name}\t.byte ${initialValue.toHex()}") DataType.BYTE -> asmgen.out("${variable.name}\t.char $initialValue") DataType.UWORD -> asmgen.out("${variable.name}\t.word ${initialValue.toHex()}") DataType.WORD -> asmgen.out("${variable.name}\t.sint $initialValue") diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AnyExprAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AnyExprAsmGen.kt index caf6a5247..1b3c0521f 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AnyExprAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AnyExprAsmGen.kt @@ -35,7 +35,7 @@ internal class AnyExprAsmGen( require(expr.left.type in WordDatatypes && expr.right.type in WordDatatypes) { "both operands must be words" } - return assignWordBinExpr(expr) + throw AssemblyError("expression should have been handled otherwise: word ${expr.operator} at ${expr.position}") } DataType.FLOAT -> { require(expr.left.type==DataType.FLOAT && expr.right.type==DataType.FLOAT) { @@ -47,30 +47,6 @@ internal class AnyExprAsmGen( } } - private fun assignWordBinExpr(expr: PtBinaryExpression): Boolean { - when(expr.operator) { - "+" -> TODO("word + at ${expr.position}") - "-" -> TODO("word - at ${expr.position}") - "*" -> TODO("word * at ${expr.position}") - "/" -> TODO("word / at ${expr.position}") - "<<" -> TODO("word << at ${expr.position}") - ">>" -> TODO("word >> at ${expr.position}") - "%" -> TODO("word % at ${expr.position}") - "and" -> TODO("word logical and (with optional shortcircuit) ${expr.position}") - "or" -> TODO("word logical or (with optional shortcircuit) ${expr.position}") - "&" -> TODO("word and at ${expr.position}") - "|" -> TODO("word or at ${expr.position}") - "^", "xor" -> TODO("word xor at ${expr.position}") - "==" -> TODO("word == at ${expr.position}") - "!=" -> TODO("word != at ${expr.position}") - "<" -> TODO("word < at ${expr.position}") - "<=" -> TODO("word <= at ${expr.position}") - ">" -> TODO("word > at ${expr.position}") - ">=" -> TODO("word >= at ${expr.position}") - else -> return false - } - } - private fun assignByteBinExpr(expr: PtBinaryExpression, assign: AsmAssignment): Boolean { when(expr.operator) { "+" -> { @@ -89,21 +65,11 @@ internal class AnyExprAsmGen( asmgen.assignRegister(RegisterOrPair.A, assign.target) return true } - "*" -> { - TODO("byte * at ${expr.position}") - } - "/" -> { - TODO("byte / at ${expr.position}") - } - "<<" -> { - TODO("byte << at ${expr.position}") - } - ">>" -> { - TODO("byte >> at ${expr.position}") - } - "%" -> { - TODO("byte % at ${expr.position}") - } + "*" -> TODO("byte * at ${expr.position}") + "/" -> TODO("byte / at ${expr.position}") + "<<" -> TODO("byte << at ${expr.position}") + ">>" -> TODO("byte >> at ${expr.position}") + "%" -> TODO("byte % at ${expr.position}") "and" -> TODO("logical and (with optional shortcircuit) ${expr.position}") "or" -> TODO("logical or (with optional shortcircuit) ${expr.position}") "&" -> { @@ -130,24 +96,12 @@ internal class AnyExprAsmGen( asmgen.assignRegister(RegisterOrPair.A, assign.target) return true } - "==" -> { - TODO("byte == at ${expr.position}") - } - "!=" -> { - TODO("byte != at ${expr.position}") - } - "<" -> { - TODO("byte < at ${expr.position}") - } - "<=" -> { - TODO("byte <= at ${expr.position}") - } - ">" -> { - TODO("byte > at ${expr.position}") - } - ">=" -> { - TODO("byte >= at ${expr.position}") - } + "==" -> TODO("byte == at ${expr.position}") + "!=" -> TODO("byte != at ${expr.position}") + "<" -> TODO("byte < at ${expr.position}") + "<=" -> TODO("byte <= at ${expr.position}") + ">" -> TODO("byte > at ${expr.position}") + ">=" -> TODO("byte >= at ${expr.position}") else -> return false } } diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/IRPeepholeOptimizer.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/IRPeepholeOptimizer.kt index 3f50971a0..52d9e8a18 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/IRPeepholeOptimizer.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/IRPeepholeOptimizer.kt @@ -52,15 +52,12 @@ class IRPeepholeOptimizer(private val irprog: IRProgram) { || removeWeirdBranches(chunk1, chunk2, indexedInstructions) || removeDoubleSecClc(chunk1, indexedInstructions) || cleanupPushPop(chunk1, indexedInstructions) - // TODO other optimizations } while (changed) } } removeEmptyChunks(sub) } - // TODO also do register optimization step here at the end? - irprog.linkChunks() // re-link } @@ -451,12 +448,13 @@ class IRPeepholeOptimizer(private val irprog: IRProgram) { } /* - // TODO: detect multiple loads to the same target registers, only keep first (if source is not I/O memory) - // TODO: detect multiple stores to the same target, only keep first (if target is not I/O memory) - // TODO: detect multiple float ffrom/fto to the same target, only keep first - // TODO: detect subsequent same xors/nots/negs, remove the pairs completely as they cancel out - // TODO: detect multiple same ands, ors; only keep first - // TODO: (hard) detect multiple registers being assigned the same value (and not changed) - use only 1 of them + Possible other optimizations: + // detect multiple loads to the same target registers, only keep first (if source is not I/O memory) + // detect multiple stores to the same target, only keep first (if target is not I/O memory) + // detect multiple float ffrom/fto to the same target, only keep first + // detect subsequent same xors/nots/negs, remove the pairs completely as they cancel out + // detect multiple same ands, ors; only keep first + // detect multiple registers being assigned the same value (and not changed) - use only 1 of them (hard!) // ... */ } diff --git a/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt b/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt index fa3311ec7..d0db88efb 100644 --- a/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt +++ b/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt @@ -435,7 +435,6 @@ class ConstantFoldingOptimizer(private val program: Program, private val errors: subrightIsConst: Boolean): IAstModification? { // NOTE: THESE REORDERINGS ARE ONLY VALID FOR FLOATING POINT CONSTANTS - // TODO: this implements only a small set of possible reorderings at this time, we could perhaps add more if(expr.operator==subExpr.operator) { // both operators are the same. diff --git a/codeOptimizers/src/prog8/optimizer/ExpressionSimplifier.kt b/codeOptimizers/src/prog8/optimizer/ExpressionSimplifier.kt index 2a691fe1c..8e649a516 100644 --- a/codeOptimizers/src/prog8/optimizer/ExpressionSimplifier.kt +++ b/codeOptimizers/src/prog8/optimizer/ExpressionSimplifier.kt @@ -13,8 +13,6 @@ import kotlin.math.abs import kotlin.math.log2 import kotlin.math.pow -// TODO add more peephole expression optimizations? Investigate what optimizations binaryen has? - class ExpressionSimplifier(private val program: Program, private val options: CompilationOptions, private val errors: IErrorReporter) : AstWalker() { private val powersOfTwo = (1..16).map { (2.0).pow(it) }.toSet() private val negativePowersOfTwo = powersOfTwo.map { -it }.toSet() @@ -740,7 +738,7 @@ class ExpressionSimplifier(private val program: Program, private val options: Co in powersOfTwo -> { if (leftDt==DataType.UBYTE || leftDt==DataType.UWORD) { // Unsigned number divided by a power of two => shift right - // Signed number can't simply be bitshifted in this case (due to rounding issues for negative values), TODO is this correct??? + // Signed number can't simply be bitshifted in this case (due to rounding issues for negative values), // so we leave that as is and let the code generator deal with it. val numshifts = log2(cv).toInt() return BinaryExpression(expr.left, ">>", NumericLiteral.optimalInteger(numshifts, expr.position), expr.position) diff --git a/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt b/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt index bfaa113dc..72ff7440e 100644 --- a/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt +++ b/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt @@ -156,28 +156,6 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter, } } -/* TODO: is this really no longer needed in boolean branch? - if(expr.operator in LogicalOperators) { - // remove redundant !=0 comparisons from logical expressions such as: a!=0 xor b --> a xor b (only for byte operands!) - val leftExpr = expr.left as? BinaryExpression - if(leftExpr != null && - leftExpr.operator == "!=" && - !leftExpr.left.isSimple && - leftExpr.left.inferType(program).isBytes && - leftExpr.right.constValue(program)?.number == 0.0) { - return listOf(IAstModification.ReplaceNode(leftExpr, leftExpr.left, expr)) - } - val rightExpr = expr.right as? BinaryExpression - if(rightExpr != null && - rightExpr.operator == "!=" && - !rightExpr.left.isSimple && - rightExpr.left.inferType(program).isBytes && - rightExpr.right.constValue(program)?.number == 0.0) { - return listOf(IAstModification.ReplaceNode(rightExpr, rightExpr.left, expr)) - } - } -*/ - return noModifications } diff --git a/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt b/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt index 0764e2d75..6a6fad4b9 100644 --- a/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt +++ b/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt @@ -97,7 +97,7 @@ private fun StatementContext.toAst() : Statement { val operator = it.operator.text val pos = it.toPosition() // print("\u001b[92mINFO\u001B[0m ") // bright green -// println("${pos}: ++ and -- will be removed in a future version, please use +=1 or -=1 instead.") // TODO +// println("${pos}: ++ and -- will be removed in a future version, please use +=1 or -=1 instead.") // .... if we decode to remove them one day val addSubOne = BinaryExpression(tgt.toExpression(), if(operator=="++") "+" else "-", NumericLiteral.optimalInteger(1, pos), pos, false) return Assignment(tgt, addSubOne, AssignmentOrigin.USERCODE, pos) } diff --git a/compilerAst/src/prog8/ast/statements/AstStatements.kt b/compilerAst/src/prog8/ast/statements/AstStatements.kt index d6f12fc13..770589de6 100644 --- a/compilerAst/src/prog8/ast/statements/AstStatements.kt +++ b/compilerAst/src/prog8/ast/statements/AstStatements.kt @@ -538,8 +538,7 @@ data class AssignTarget(var identifier: IdentifierReference?, if (memoryAddress != null) return InferredTypes.knownFor(DataType.UBYTE) - // a multi-assign has no 1 type... TODO although it could perhaps be the type of the first target? - + // a multi-target has no 1 particular type return InferredTypes.unknown() } diff --git a/examples/test.p8 b/examples/test.p8 index c3e6af8d2..4a23d8142 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -3,18 +3,47 @@ %option no_sysinit main { - sub start() { - sys.clear_carry() - cx16.r0s=-42 + ubyte[255] array1 + ubyte[255] array2 + uword block1 = memory("b1", 6000 ,0) + uword block2 = memory("b2", 6000 ,0) - if_z - txt.print("zero") - else if_cs - txt.print("carry") - else if_neg - txt.print("negative") - else - txt.print("nothing") + sub start() { + cbm.SETTIM(0,0,0) + + repeat 2000 { + sys.memcopy(array1, array2, sizeof(array1)) + } + + txt.print_uw(cbm.RDTIM16()) + txt.nl() + + cbm.SETTIM(0,0,0) + + repeat 2000 { + cx16.memory_copy(array1, array2, sizeof(array1)) + } + + txt.print_uw(cbm.RDTIM16()) + txt.nl() + + cbm.SETTIM(0,0,0) + + repeat 100 { + sys.memcopy(block1, block2, 6000) + } + + txt.print_uw(cbm.RDTIM16()) + txt.nl() + + cbm.SETTIM(0,0,0) + + repeat 100 { + cx16.memory_copy(block1, block2, 6000) + } + + txt.print_uw(cbm.RDTIM16()) + txt.nl() } } diff --git a/intermediate/src/prog8/intermediate/IRFileReader.kt b/intermediate/src/prog8/intermediate/IRFileReader.kt index 888f77518..ff628afab 100644 --- a/intermediate/src/prog8/intermediate/IRFileReader.kt +++ b/intermediate/src/prog8/intermediate/IRFileReader.kt @@ -202,7 +202,7 @@ class IRFileReader { var initNumeric: Double? = null var initArray: StArray? = null when(dt) { - DataType.BOOL -> TODO("parse boolean $value") + DataType.BOOL -> initNumeric = if(value.lowercase()=="false") 0.0 else 1.0 in NumericDatatypes -> initNumeric = parseIRValue(value) in ArrayDatatypes -> { initArray = value.split(',').map { diff --git a/intermediate/src/prog8/intermediate/IRSymbolTable.kt b/intermediate/src/prog8/intermediate/IRSymbolTable.kt index 598bc63f8..7c04148b8 100644 --- a/intermediate/src/prog8/intermediate/IRSymbolTable.kt +++ b/intermediate/src/prog8/intermediate/IRSymbolTable.kt @@ -235,7 +235,6 @@ class IRStArrayElement(val number: Double?, val addressOfSymbol: String?) { } init { - // TODO TEMPORARY require(number!=null || addressOfSymbol!=null) } }