diff --git a/codeCore/src/prog8/code/core/Operators.kt b/codeCore/src/prog8/code/core/Operators.kt index ed9adb321..13ec2ac41 100644 --- a/codeCore/src/prog8/code/core/Operators.kt +++ b/codeCore/src/prog8/code/core/Operators.kt @@ -3,10 +3,8 @@ package prog8.code.core val AssociativeOperators = setOf("+", "*", "&", "|", "^", "==", "!=") val ComparisonOperators = setOf("==", "!=", "<", ">", "<=", ">=") val LogicalOperators = setOf("and", "or", "xor", "not") -val AugmentAssignmentOperators = setOf("+", "-", "/", "*", "&", "|", "^", "<<", ">>", "%", "and", "or", "xor") val BitwiseOperators = setOf("&", "|", "^", "~") val PrefixOperators = setOf("+", "-", "~", "not") -// val InvalidOperatorsForBoolean = setOf("+", "-", "*", "/", "%", "<<", ">>") + BitwiseOperators fun invertedComparisonOperator(operator: String) = when (operator) { diff --git a/codeOptimizers/src/prog8/optimizer/ConstExprEvaluator.kt b/codeOptimizers/src/prog8/optimizer/ConstExprEvaluator.kt index ea2004b51..c1efa7bd4 100644 --- a/codeOptimizers/src/prog8/optimizer/ConstExprEvaluator.kt +++ b/codeOptimizers/src/prog8/optimizer/ConstExprEvaluator.kt @@ -19,9 +19,9 @@ class ConstExprEvaluator { "*" -> multiply(left, right) "/" -> divide(left, right) "%" -> remainder(left, right) - "&" -> bitwiseand(left, right) - "|" -> bitwiseor(left, right) - "^" -> bitwisexor(left, right) + "&" -> bitwiseAnd(left, right) + "|" -> bitwiseOr(left, right) + "^" -> bitwiseXor(left, right) "<" -> NumericLiteral.fromBoolean(left < right, left.position) ">" -> NumericLiteral.fromBoolean(left > right, left.position) "<=" -> NumericLiteral.fromBoolean(left <= right, left.position) @@ -30,6 +30,9 @@ class ConstExprEvaluator { "!=" -> NumericLiteral.fromBoolean(left != right, left.position) "<<" -> shiftedleft(left, right) ">>" -> shiftedright(left, right) + "and" -> logicalAnd(left, right) + "or" -> logicalOr(left, right) + "xor" -> logicalXor(left, right) else -> throw FatalAstException("const evaluation for invalid operator $operator") } } catch (ax: FatalAstException) { @@ -55,7 +58,7 @@ class ConstExprEvaluator { return NumericLiteral(left.type, result.toDouble(), left.position) } - private fun bitwisexor(left: NumericLiteral, right: NumericLiteral): NumericLiteral { + private fun bitwiseXor(left: NumericLiteral, right: NumericLiteral): NumericLiteral { if(left.type== DataType.UBYTE) { if(right.type in IntegerDatatypes) { return NumericLiteral(DataType.UBYTE, (left.number.toInt() xor (right.number.toInt() and 255)).toDouble(), left.position) @@ -68,7 +71,7 @@ class ConstExprEvaluator { throw ExpressionError("cannot calculate $left ^ $right", left.position) } - private fun bitwiseor(left: NumericLiteral, right: NumericLiteral): NumericLiteral { + private fun bitwiseOr(left: NumericLiteral, right: NumericLiteral): NumericLiteral { if(left.type== DataType.UBYTE) { if(right.type in IntegerDatatypes) { return NumericLiteral(DataType.UBYTE, (left.number.toInt() or (right.number.toInt() and 255)).toDouble(), left.position) @@ -81,7 +84,7 @@ class ConstExprEvaluator { throw ExpressionError("cannot calculate $left | $right", left.position) } - private fun bitwiseand(left: NumericLiteral, right: NumericLiteral): NumericLiteral { + private fun bitwiseAnd(left: NumericLiteral, right: NumericLiteral): NumericLiteral { if(left.type== DataType.UBYTE) { if(right.type in IntegerDatatypes) { return NumericLiteral(DataType.UBYTE, (left.number.toInt() and (right.number.toInt() and 255)).toDouble(), left.position) @@ -94,6 +97,15 @@ class ConstExprEvaluator { throw ExpressionError("cannot calculate $left & $right", left.position) } + private fun logicalAnd(left: NumericLiteral, right: NumericLiteral): NumericLiteral = + NumericLiteral.fromBoolean(left.asBooleanValue and right.asBooleanValue, left.position) + + private fun logicalOr(left: NumericLiteral, right: NumericLiteral): NumericLiteral = + NumericLiteral.fromBoolean(left.asBooleanValue or right.asBooleanValue, left.position) + + private fun logicalXor(left: NumericLiteral, right: NumericLiteral): NumericLiteral = + NumericLiteral.fromBoolean(left.asBooleanValue xor right.asBooleanValue, left.position) + private fun plus(left: NumericLiteral, right: NumericLiteral): NumericLiteral { val error = "cannot add $left and $right" return when (left.type) { diff --git a/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt b/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt index f31ed8a07..e79fcb596 100644 --- a/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt +++ b/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt @@ -18,6 +18,8 @@ import kotlin.math.floor class ConstantFoldingOptimizer(private val program: Program, private val errors: IErrorReporter) : AstWalker() { + private val evaluator = ConstExprEvaluator() + override fun before(memread: DirectMemoryRead, parent: Node): Iterable { // @( &thing ) --> thing (but only if thing is a byte type!) val addrOf = memread.addressExpression as? AddressOf @@ -137,12 +139,13 @@ class ConstantFoldingOptimizer(private val program: Program, private val errors: } } - val evaluator = ConstExprEvaluator() - - // const fold when both operands are a const + // const fold when both operands are a const. + // if in a chained comparison, that one has to be desugared first though. if(leftconst != null && rightconst != null) { - val result = evaluator.evaluate(leftconst, expr.operator, rightconst) - modifications += IAstModification.ReplaceNode(expr, result, parent) + if((expr.parent as? BinaryExpression)?.isChainedComparison()!=true) { + val result = evaluator.evaluate(leftconst, expr.operator, rightconst) + modifications += IAstModification.ReplaceNode(expr, result, parent) + } } if(leftconst==null && rightconst!=null && rightconst.number<0.0) { diff --git a/codeOptimizers/src/prog8/optimizer/UnusedCodeRemover.kt b/codeOptimizers/src/prog8/optimizer/UnusedCodeRemover.kt index 18c1a88f3..b3efd8b0e 100644 --- a/codeOptimizers/src/prog8/optimizer/UnusedCodeRemover.kt +++ b/codeOptimizers/src/prog8/optimizer/UnusedCodeRemover.kt @@ -1,17 +1,11 @@ package prog8.optimizer import prog8.ast.* -import prog8.ast.expressions.BinaryExpression -import prog8.ast.expressions.NumericLiteral -import prog8.ast.expressions.PrefixExpression -import prog8.ast.expressions.TypecastExpression +import prog8.ast.expressions.* import prog8.ast.statements.* import prog8.ast.walk.AstWalker import prog8.ast.walk.IAstModification -import prog8.code.core.DataType -import prog8.code.core.ICompilationTarget -import prog8.code.core.IErrorReporter -import prog8.code.core.internedStringsModuleName +import prog8.code.core.* import prog8.compiler.CallGraph @@ -124,6 +118,36 @@ class UnusedCodeRemover(private val program: Program, return listOf(IAstModification.Remove(decl, parent as IStatementContainer)) } else { + val (writes, reads) = usages + .partition{ + it is InlineAssembly // can't really tell if it's written to or only read, assume the worst + || it.parent is AssignTarget + || it.parent is ForLoop + || it.parent is AddressOf + || (it.parent as? IFunctionCall)?.target?.nameInSource?.singleOrNull() in InplaceModifyingBuiltinFunctions + } + val singleAssignment = writes.singleOrNull()?.parent?.parent as? Assignment ?: writes.singleOrNull()?.parent as? Assignment + if (singleAssignment!=null && reads.isNotEmpty()) { + if (singleAssignment.origin == AssignmentOrigin.VARINIT && singleAssignment.value.constValue(program) != null) { + // variable only has a single write and it is the initialization value, so it can be replaced with a constant, IF the value is a constant + errors.warn("variable is never written to and was replaced by a constant", decl.position) + val const = VarDecl(VarDeclType.CONST, decl.origin, decl.datatype, decl.zeropage, decl.arraysize, decl.name, decl.names, singleAssignment.value, decl.sharedWithAsm, decl.splitArray, decl.position) + return listOf( + IAstModification.ReplaceNode(decl, const, parent), + IAstModification.Remove(singleAssignment, singleAssignment.parent as IStatementContainer) + ) + } + } + /* + TODO: need to check if there are no variable usages between the declaration and the assignment (because these rely on the original initialization value) + if(writes.size==2) { + val firstAssignment = writes[0].parent as? Assignment + val secondAssignment = writes[1].parent as? Assignment + if(firstAssignment?.origin==AssignmentOrigin.VARINIT && secondAssignment?.value?.constValue(program)!=null) { + errors.warn("variable is only assigned once here, consider using this as the initialization value in the declaration instead", secondAssignment.position) + } + } + */ if(usages.size==1) { val singleUse = usages[0].parent if(singleUse is AssignTarget) { diff --git a/compiler/res/prog8lib/cx16/bmx.p8 b/compiler/res/prog8lib/cx16/bmx.p8 index a7834dd78..87b06633a 100644 --- a/compiler/res/prog8lib/cx16/bmx.p8 +++ b/compiler/res/prog8lib/cx16/bmx.p8 @@ -3,6 +3,7 @@ ; BMX Specification: https://cx16forum.com/forum/viewtopic.php?t=6945 %import diskio +%option no_symbol_prefixing, ignore_unused bmx { @@ -17,7 +18,7 @@ bmx { uword palette_entries ; 1-256 ubyte palette_start ubyte compression - uword palette_buffer_ptr = 0 ; should you want to load or save the palette into main memory instead of directly into vram + uword @shared palette_buffer_ptr = 0 ; should you want to load or save the palette into main memory instead of directly into vram uword error_message ; pointer to error message, or 0 if all ok ubyte old_drivenumber diff --git a/compiler/res/prog8lib/cx16/diskio.p8 b/compiler/res/prog8lib/cx16/diskio.p8 index 66768b8e8..8d01af034 100644 --- a/compiler/res/prog8lib/cx16/diskio.p8 +++ b/compiler/res/prog8lib/cx16/diskio.p8 @@ -22,7 +22,7 @@ diskio { const ubyte READ_IO_CHANNEL=12 const ubyte WRITE_IO_CHANNEL=13 - ubyte drivenumber = 8 ; user programs can set this to the drive number they want to load/save to! + ubyte @shared drivenumber = 8 ; user programs can set this to the drive number they want to load/save to! sub reset_read_channel() { void cbm.CHKIN(READ_IO_CHANNEL) diff --git a/compiler/res/prog8lib/diskio.p8 b/compiler/res/prog8lib/diskio.p8 index 43e4e8085..76163a437 100644 --- a/compiler/res/prog8lib/diskio.p8 +++ b/compiler/res/prog8lib/diskio.p8 @@ -11,7 +11,7 @@ diskio { const ubyte READ_IO_CHANNEL=12 const ubyte WRITE_IO_CHANNEL=13 - ubyte drivenumber = 8 ; user programs can set this to the drive number they want to load/save to! + ubyte @shared drivenumber = 8 ; user programs can set this to the drive number they want to load/save to! sub reset_read_channel() { void cbm.CHKIN(READ_IO_CHANNEL) diff --git a/compiler/src/prog8/compiler/astprocessing/BeforeAsmTypecastCleaner.kt b/compiler/src/prog8/compiler/astprocessing/BeforeAsmTypecastCleaner.kt index aa33952cb..6fe2ab06a 100644 --- a/compiler/src/prog8/compiler/astprocessing/BeforeAsmTypecastCleaner.kt +++ b/compiler/src/prog8/compiler/astprocessing/BeforeAsmTypecastCleaner.kt @@ -81,8 +81,7 @@ internal class BeforeAsmTypecastCleaner(val program: Program, // also convert calls to builtin functions to BuiltinFunctionCall nodes to make things easier for codegen override fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable { - if(functionCallStatement.target.nameInSource.size==1 - && functionCallStatement.target.nameInSource[0] in program.builtinFunctions.names) { + if(functionCallStatement.target.nameInSource.singleOrNull() in program.builtinFunctions.names) { return listOf(IAstModification.ReplaceNode( functionCallStatement, BuiltinFunctionCallStatement(functionCallStatement.target, functionCallStatement.args, functionCallStatement.position), @@ -94,8 +93,7 @@ internal class BeforeAsmTypecastCleaner(val program: Program, } override fun before(functionCallExpr: FunctionCallExpression, parent: Node): Iterable { - if(functionCallExpr.target.nameInSource.size==1 - && functionCallExpr.target.nameInSource[0] in program.builtinFunctions.names) { + if(functionCallExpr.target.nameInSource.singleOrNull() in program.builtinFunctions.names) { return listOf(IAstModification.ReplaceNode( functionCallExpr, BuiltinFunctionCall(functionCallExpr.target, functionCallExpr.args, functionCallExpr.position), diff --git a/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt b/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt index 7503ca797..5096e95fc 100644 --- a/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt +++ b/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt @@ -262,10 +262,9 @@ _after: // desugar chained comparisons: i < x < j ---> i leave untouched - if(expr.operator in ComparisonOperators) { + if(expr.isChainedComparison()) { val leftBinExpr = expr.left as? BinaryExpression - val rightBinExpr = expr.right as? BinaryExpression - if(leftBinExpr!=null && !leftBinExpr.insideParentheses && leftBinExpr.operator in ComparisonOperators) { + if(leftBinExpr!=null) { if(!leftBinExpr.right.isSimple) { errors.warn("possible multiple evaluation of subexpression in chained comparison, consider using a temporary variable", leftBinExpr.right.position) } @@ -273,7 +272,8 @@ _after: val desugar = BinaryExpression(leftBinExpr, "and", right, expr.position) return listOf(IAstModification.ReplaceNode(expr, desugar, parent)) } - else if(rightBinExpr!=null && !rightBinExpr.insideParentheses && rightBinExpr.operator in ComparisonOperators) { + val rightBinExpr = expr.right as? BinaryExpression + if(rightBinExpr!=null) { if(!rightBinExpr.left.isSimple) { errors.warn("possible multiple evaluation of subexpression in chained comparison, consider using a temporary variable", rightBinExpr.left.position) } diff --git a/compiler/test/TestOptimization.kt b/compiler/test/TestOptimization.kt index a18568576..6939ac85e 100644 --- a/compiler/test/TestOptimization.kt +++ b/compiler/test/TestOptimization.kt @@ -106,8 +106,8 @@ class TestOptimization: FunSpec({ const ubyte boardOffsetC = 3 sub start() { - uword load_location = 12345 - word llw = 12345 + uword @shared load_location = 12345 + word @shared llw = 12345 cx16.r0 = load_location + 8000 + 1000 + 1000 cx16.r2 = 8000 + 1000 + 1000 + load_location cx16.r4 = load_location + boardOffsetC + boardHeightC - 1 @@ -156,8 +156,8 @@ class TestOptimization: FunSpec({ %option enable_floats main { sub start() { - float llw = 300.0 - float result + float @shared llw = 300.0 + float @shared result result = 9 * 2 * 10 * llw result++ result = llw * 9 * 2 * 10 @@ -214,7 +214,7 @@ class TestOptimization: FunSpec({ val source = """ main { sub start() { - word llw = 300 + word @shared llw = 300 cx16.r0s = 9 * 2 * 10 * llw cx16.r1s = llw * 9 * 2 * 10 cx16.r2s = llw / 30 / 3 @@ -483,8 +483,8 @@ class TestOptimization: FunSpec({ val src=""" main { sub start() { - uword aa - ubyte zz + uword @shared aa + ubyte @shared zz @(aa) = zz + 32 ; do not optimize this away! } } @@ -633,8 +633,8 @@ class TestOptimization: FunSpec({ val src=""" main { sub start() { - ubyte source=99 - ubyte thingy=42 + ubyte @shared source=99 + ubyte @shared thingy=42 if source==3 or source==4 or source==99 or source==1 thingy++ @@ -673,8 +673,8 @@ class TestOptimization: FunSpec({ val src=""" main { sub start() { - ubyte source=99 - ubyte thingy=42 + ubyte @shared source=99 + ubyte @shared thingy=42 if source==3 or source==4 or source!=99 or source==1 thingy++ @@ -691,8 +691,8 @@ class TestOptimization: FunSpec({ val src=""" main { sub start() { - ubyte source=99 - ubyte thingy=42 + ubyte @shared source=99 + ubyte @shared thingy=42 if source==3 or source==4 or thingy==99 or source==1 thingy++ @@ -709,8 +709,8 @@ class TestOptimization: FunSpec({ val src=""" main { sub start() { - ubyte source=99 - ubyte thingy=42 + ubyte @shared source=99 + ubyte @shared thingy=42 if source==3 or source==4 and source==99 or source==1 thingy++ @@ -727,7 +727,7 @@ class TestOptimization: FunSpec({ val src=""" main{ sub start () { - uword eRef + uword @shared eRef if eRef[3] and 10 { return } diff --git a/compiler/test/TestTypecasts.kt b/compiler/test/TestTypecasts.kt index d27cf54ed..fa3508beb 100644 --- a/compiler/test/TestTypecasts.kt +++ b/compiler/test/TestTypecasts.kt @@ -44,7 +44,7 @@ class TestTypecasts: FunSpec({ main { sub start() { - bool bb2=true + bool @shared bb2=true bool @shared bb = bb2 and true } }""" @@ -73,10 +73,9 @@ main { } sub start() { - bool ub1 = true - bool ub2 = true - bool ub3 = true - bool ub4 = 0 + bool @shared ub1 = true + bool @shared ub2 = true + bool @shared ub3 = true bool @shared bvalue bvalue = ub1 xor ub2 xor ub3 xor true diff --git a/compiler/test/codegeneration/TestVariousCodeGen.kt b/compiler/test/codegeneration/TestVariousCodeGen.kt index e5e055537..c82cc76b2 100644 --- a/compiler/test/codegeneration/TestVariousCodeGen.kt +++ b/compiler/test/codegeneration/TestVariousCodeGen.kt @@ -153,7 +153,7 @@ main { val text=""" main { sub start() { - ubyte c = 1 + ubyte @shared c = 1 @(15000 + c<<${'$'}0003) = 42 @(15000 + (c<<${'$'}0003)) = 42 @(15000 + c*${'$'}0008) = 42 ; *8 becomes a shift after opt @@ -247,7 +247,7 @@ main { sub start() { mylabel: - ubyte variable + ubyte @shared variable uword @shared pointer1 = &main.start uword @shared pointer2 = &start uword @shared pointer3 = &main.start.mylabel diff --git a/compiler/test/vm/TestCompilerVirtual.kt b/compiler/test/vm/TestCompilerVirtual.kt index edb76f47c..439e88407 100644 --- a/compiler/test/vm/TestCompilerVirtual.kt +++ b/compiler/test/vm/TestCompilerVirtual.kt @@ -152,9 +152,9 @@ mylabel_inside: val src = """ main { sub start() { - ubyte bytevar = 11 ; var at 0 - ubyte byteVAR = 22 ; var at 1 - ubyte ByteVar = 33 ; var at 2 + ubyte @shared bytevar = 11 ; var at 0 + ubyte @shared byteVAR = 22 ; var at 1 + ubyte @shared ByteVar = 33 ; var at 2 ubyte @shared total = bytevar+byteVAR+ByteVar ; var at 3 goto skipLABEL SkipLabel: diff --git a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt index d70ffe0fe..269bda815 100644 --- a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt +++ b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt @@ -153,7 +153,7 @@ class BinaryExpression( var operator: String, var right: Expression, override val position: Position, - val insideParentheses: Boolean = false // used in very few places to check priorities + private val insideParentheses: Boolean = false ) : Expression() { override lateinit var parent: Node @@ -178,6 +178,18 @@ class BinaryExpression( override val isSimple = false + fun isChainedComparison(): Boolean { + if(operator in ComparisonOperators) { + val leftBinExpr = left as? BinaryExpression + if (leftBinExpr != null && !leftBinExpr.insideParentheses && leftBinExpr.operator in ComparisonOperators) + return true + val rightBinExpr = right as? BinaryExpression + if (rightBinExpr != null && !rightBinExpr.insideParentheses && rightBinExpr.operator in ComparisonOperators) + return true + } + return false + } + // binary expression should actually have been optimized away into a single value, before const value was requested... override fun constValue(program: Program): NumericLiteral? = null @@ -980,7 +992,7 @@ data class IdentifierReference(val nameInSource: List, override val posi override val isSimple = true fun targetStatement(program: Program) = - if(nameInSource.size==1 && nameInSource[0] in program.builtinFunctions.names) + if(nameInSource.singleOrNull() in program.builtinFunctions.names) BuiltinFunctionPlaceholder(nameInSource[0], position, parent) else definingScope.lookup(nameInSource) diff --git a/compilerAst/src/prog8/compiler/CallGraph.kt b/compilerAst/src/prog8/compiler/CallGraph.kt index 41df866bf..34ac9f49c 100644 --- a/compilerAst/src/prog8/compiler/CallGraph.kt +++ b/compilerAst/src/prog8/compiler/CallGraph.kt @@ -141,30 +141,39 @@ class CallGraph(private val program: Program) : IAstVisitor { fun unused(module: Module) = module !in usedModules fun unused(sub: Subroutine): Boolean { - return sub !in usedSubroutines && !nameInAssemblyCode(sub.name) + return sub !in usedSubroutines && !nameInAssemblyCode(sub.name, listOf("p8s_", "")) } fun unused(block: Block): Boolean { - return block !in usedBlocks && !nameInAssemblyCode(block.name) + return block !in usedBlocks && !nameInAssemblyCode(block.name, listOf("p8b_", "")) } fun unused(decl: VarDecl): Boolean { - // Don't check assembly just for occurrences of variables, if they're not used in prog8 itself, just kill them + // Don't check assembly just for occurrences of variables, if they're not used in prog8 itself, just kill them. + // User should use @shared if they want to keep them. return usages(decl).isEmpty() } - fun usages(decl: VarDecl): List { + fun usages(decl: VarDecl): List { if(decl.type!=VarDeclType.VAR) return emptyList() if(decl.definingBlock !in usedBlocks) return emptyList() - return allIdentifiersAndTargets.filter { decl===it.value }.map{ it.key } + val assemblyBlocks = allAssemblyNodes.filter { + decl.name in it.names || "p8v_" + decl.name in it.names + } + return allIdentifiersAndTargets.filter { decl===it.value }.map{ it.key } + assemblyBlocks } private val prefixes = listOf("p8b_", "p8v_", "p8s_", "p8l_", "p8_", "") - private fun nameInAssemblyCode(name: String): Boolean { + private fun nameInAssemblyCode(name: String, knownAsmPrefixes: List = emptyList()): Boolean { + if(knownAsmPrefixes.isNotEmpty()) + return allAssemblyNodes.any { + knownAsmPrefixes.any { prefix -> prefix+name in it.names } + } + return allAssemblyNodes.any { prefixes.any { prefix -> prefix+name in it.names } } diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 5c0dd3e46..aadfb571f 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -2,6 +2,10 @@ TODO ==== +- make constants have p8c_ prefix instead of p8v_ +- add INFO error level and move some warnings to info +- add switch to enable INFO error messages (default is WARN and up) + - [on branch: shortcircuit] investigate McCarthy evaluation again? this may also reduce code size perhaps for things like if a>4 or a<2 .... ... @@ -56,8 +60,6 @@ Libraries: Optimizations: -- give a warning for variables that could be a const - or even make them a const (if not @shared)? -- treat every scalar variable decl with initialization value, as const by default, unless the variable gets assigned to somewhere (or has its address taken, or is @shared) - VariableAllocator: can we think of a smarter strategy for allocating variables into zeropage, rather than first-come-first-served? for instance, vars used inside loops first, then loopvars, then uwords used as pointers, then the rest - various optimizers skip stuff if compTarget.name==VMTarget.NAME. Once 6502-codegen is done from IR code, diff --git a/examples/cx16/chunkedfile/mcf.p8 b/examples/cx16/chunkedfile/mcf.p8 index 3ca0b40fe..c6188db83 100644 --- a/examples/cx16/chunkedfile/mcf.p8 +++ b/examples/cx16/chunkedfile/mcf.p8 @@ -17,6 +17,7 @@ mcf { ubyte file_channel sub open(str filename, ubyte drive, ubyte channel) -> bool { + file_channel = channel cbm.SETNAM(string.length(filename), filename) cbm.SETLFS(channel, drive, 2) void cbm.OPEN() diff --git a/examples/screencodes.p8 b/examples/screencodes.p8 index 0ce78e088..7e07f0e7d 100644 --- a/examples/screencodes.p8 +++ b/examples/screencodes.p8 @@ -24,8 +24,8 @@ main { for i in 0 to len(s2)-1 txt.setchr(i, 1, s2[i]) - ubyte c1 = 'z' - ubyte c2 = sc:'z' + const ubyte c1 = 'z' + const ubyte c2 = sc:'z' txt.print("\npetscii z=") txt.print_ub(c1) diff --git a/examples/test.p8 b/examples/test.p8 index df10d91b2..f73e53179 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -13,5 +13,7 @@ main { txt.nl() txt.print_ub(5<(x-y)<=9