diff --git a/codeOptimizers/src/prog8/optimizer/ConstExprEvaluator.kt b/codeOptimizers/src/prog8/optimizer/ConstExprEvaluator.kt index 6c1311cbe..560396989 100644 --- a/codeOptimizers/src/prog8/optimizer/ConstExprEvaluator.kt +++ b/codeOptimizers/src/prog8/optimizer/ConstExprEvaluator.kt @@ -66,7 +66,7 @@ class ConstExprEvaluator { // DataType.WORD -> result = result.toShort().toInt() // else -> { /* keep as it is */ } // } - return NumericLiteral.optimalNumeric(result.toDouble(), left.position) + return NumericLiteral.optimalNumeric(left.type, null, result.toDouble(), left.position) } private fun bitwiseXor(left: NumericLiteral, right: NumericLiteral): NumericLiteral { @@ -133,7 +133,7 @@ class ConstExprEvaluator { val error = "cannot add $left and $right" return when (left.type) { in IntegerDatatypes -> when (right.type) { - in IntegerDatatypes -> NumericLiteral.optimalInteger(left.number.toInt() + right.number.toInt(), left.position) + in IntegerDatatypes -> NumericLiteral.optimalInteger(left.type, right.type, left.number.toInt() + right.number.toInt(), left.position) DataType.FLOAT -> NumericLiteral(DataType.FLOAT, left.number.toInt() + right.number, left.position) else -> throw ExpressionError(error, left.position) } @@ -150,7 +150,7 @@ class ConstExprEvaluator { val error = "cannot subtract $left and $right" return when (left.type) { in IntegerDatatypes -> when (right.type) { - in IntegerDatatypes -> NumericLiteral.optimalInteger(left.number.toInt() - right.number.toInt(), left.position) + in IntegerDatatypes -> NumericLiteral.optimalInteger(left.type, right.type, left.number.toInt() - right.number.toInt(), left.position) DataType.FLOAT -> NumericLiteral(DataType.FLOAT, left.number.toInt() - right.number, left.position) else -> throw ExpressionError(error, left.position) } @@ -167,7 +167,7 @@ class ConstExprEvaluator { val error = "cannot multiply ${left.type} and ${right.type}" return when (left.type) { in IntegerDatatypes -> when (right.type) { - in IntegerDatatypes -> NumericLiteral.optimalInteger(left.number.toInt() * right.number.toInt(), left.position) + in IntegerDatatypes -> NumericLiteral.optimalInteger(left.type, right.type, left.number.toInt() * right.number.toInt(), left.position) DataType.FLOAT -> NumericLiteral(DataType.FLOAT, left.number.toInt() * right.number, left.position) else -> throw ExpressionError(error, left.position) } @@ -190,7 +190,7 @@ class ConstExprEvaluator { in IntegerDatatypes -> { if(right.number.toInt()==0) divideByZeroError(right.position) val result: Int = left.number.toInt() / right.number.toInt() - NumericLiteral.optimalInteger(result, left.position) + NumericLiteral.optimalInteger(left.type, right.type, result, left.position) } DataType.FLOAT -> { if(right.number==0.0) divideByZeroError(right.position) @@ -219,7 +219,7 @@ class ConstExprEvaluator { in IntegerDatatypes -> when (right.type) { in IntegerDatatypes -> { if(right.number.toInt()==0) divideByZeroError(right.position) - NumericLiteral.optimalNumeric(left.number.toInt().toDouble() % right.number.toInt().toDouble(), left.position) + NumericLiteral.optimalNumeric(left.type, right.type, left.number.toInt().toDouble() % right.number.toInt().toDouble(), left.position) } DataType.FLOAT -> { if(right.number ==0.0) divideByZeroError(right.position) diff --git a/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt b/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt index 589e21b21..c3136b941 100644 --- a/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt +++ b/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt @@ -33,6 +33,14 @@ class ConstantFoldingOptimizer(private val program: Program, private val errors: } override fun after(numLiteral: NumericLiteral, parent: Node): Iterable { + + if(numLiteral.type==DataType.LONG) { + // see if LONG values may be reduced to something smaller + val smaller = NumericLiteral.optimalInteger(numLiteral.number.toInt(), numLiteral.position) + if(smaller.type!=DataType.LONG) + return listOf(IAstModification.ReplaceNode(numLiteral, smaller, parent)) + } + if(parent is Assignment) { val iDt = parent.target.inferType(program) if(iDt.isKnown && !iDt.isBool && !iDt.istype(numLiteral.type)) { @@ -164,13 +172,13 @@ class ConstantFoldingOptimizer(private val program: Program, private val errors: if(leftconst==null && rightconst!=null && rightconst.number<0.0) { if (expr.operator == "-") { // X - -1 ---> X + 1 - val posNumber = NumericLiteral.optimalNumeric(-rightconst.number, rightconst.position) + val posNumber = NumericLiteral.optimalNumeric(rightconst.type, null, -rightconst.number, rightconst.position) val plusExpr = BinaryExpression(expr.left, "+", posNumber, expr.position) return listOf(IAstModification.ReplaceNode(expr, plusExpr, parent)) } else if (expr.operator == "+") { // X + -1 ---> X - 1 - val posNumber = NumericLiteral.optimalNumeric(-rightconst.number, rightconst.position) + val posNumber = NumericLiteral.optimalNumeric(rightconst.type, null, -rightconst.number, rightconst.position) val plusExpr = BinaryExpression(expr.left, "-", posNumber, expr.position) return listOf(IAstModification.ReplaceNode(expr, plusExpr, parent)) } @@ -384,12 +392,13 @@ class ConstantFoldingOptimizer(private val program: Program, private val errors: val numval = decl.value as? NumericLiteral if(decl.type== VarDeclType.CONST && numval!=null) { val valueDt = numval.inferType(program) + if(valueDt istype DataType.LONG) { + return noModifications // this is handled in the numericalvalue case + } if(valueDt isnot decl.datatype) { - if(decl.datatype!=DataType.BOOL || valueDt.isnot(DataType.UBYTE)) { - val cast = numval.cast(decl.datatype, true) - if (cast.isValid) - return listOf(IAstModification.ReplaceNode(numval, cast.valueOrZero(), decl)) - } + val cast = numval.cast(decl.datatype, true) + if (cast.isValid) + return listOf(IAstModification.ReplaceNode(numval, cast.valueOrZero(), decl)) } } return noModifications diff --git a/compiler/res/prog8lib/cx16/gfx2.p8 b/compiler/res/prog8lib/cx16/gfx2.p8 index 61ad49863..448d5624a 100644 --- a/compiler/res/prog8lib/cx16/gfx2.p8 +++ b/compiler/res/prog8lib/cx16/gfx2.p8 @@ -15,6 +15,9 @@ ; ; NOTE: the bitmap screen data is positioned in vram at $0:0000 ; +; NOTE: In the future, these routines might be split out to separate modules, 1 for each screen mode, +; so they can be optimized a lot better. There's already a "gfx_lores" module with a few routines for lores 256C mode. +; ; SCREEN MODE LIST: ; mode 0 = reset back to default text mode ; mode 1 = bitmap 320 x 240 x 256c (8 bpp) diff --git a/compiler/res/prog8lib/virtual/math.p8 b/compiler/res/prog8lib/virtual/math.p8 index ba7cd9c9f..85aa296be 100644 --- a/compiler/res/prog8lib/virtual/math.p8 +++ b/compiler/res/prog8lib/virtual/math.p8 @@ -233,7 +233,7 @@ math { sub direction(ubyte x1, ubyte y1, ubyte x2, ubyte y2) -> ubyte { ; From a pair of positive coordinates, calculate discrete direction between 0 and 23 into A. ; This adjusts the atan() result so that the direction N is centered on the angle=N instead of having it as a boundary - ubyte angle = atan2(x1, y1, x2, y2) - 256/48 + ubyte angle = atan2(x1, y1, x2, y2) - (256/48 as ubyte) return 23-lsb(mkword(angle,0) / 2730) } diff --git a/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt b/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt index 1ded64449..7c129e417 100644 --- a/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt +++ b/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt @@ -190,21 +190,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val } val cvalue = assignment.value.constValue(program) if(cvalue!=null) { - val number = cvalue.number - // more complex comparisons if the type is different, but the constant value is compatible - if (valuetype == DataType.BYTE && targettype == DataType.UBYTE) { - if(number>0) - return castLiteral(cvalue) - } else if (valuetype == DataType.WORD && targettype == DataType.UWORD) { - if(number>0) - return castLiteral(cvalue) - } else if (valuetype == DataType.UBYTE && targettype == DataType.BYTE) { - if(number<0x80) - return castLiteral(cvalue) - } else if (valuetype == DataType.UWORD && targettype == DataType.WORD) { - if(number<0x8000) - return castLiteral(cvalue) - } + return castLiteral(cvalue) } } } @@ -357,15 +343,72 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val } override fun after(range: RangeExpression, parent: Node): Iterable { + val fromConst = range.from.constValue(program) + val toConst = range.to.constValue(program) + + if(fromConst!=null) { + val smaller = NumericLiteral.optimalInteger(fromConst.number.toInt(), fromConst.position) + if(fromConst.type.largerThan(smaller.type)) { + val toType = range.to.inferType(program) + if(toType isnot smaller.type) { + if(toConst!=null) { + // can we make the to value into the same smaller type? + val smallerTo = NumericLiteral.optimalInteger(toConst.number.toInt(), toConst.position) + if(smaller.type==smallerTo.type) { + val newRange = RangeExpression(smaller, smallerTo, range.step, range.position) + return listOf(IAstModification.ReplaceNode(range, newRange, parent)) + } + } + } else { + val newRange = RangeExpression(smaller, range.to, range.step, range.position) + return listOf(IAstModification.ReplaceNode(range, newRange, parent)) + } + } + } + if(toConst!=null) { + val smaller = NumericLiteral.optimalInteger(toConst.number.toInt(), toConst.position) + if(toConst.type.largerThan(smaller.type)) { + val fromType = range.from.inferType(program) + if(fromType isnot smaller.type) { + if(fromConst!=null) { + // can we make the from value into the same smaller type? + val smallerFrom = NumericLiteral.optimalInteger(fromConst.number.toInt(), fromConst.position) + if(smaller.type==smallerFrom.type) { + val newRange = RangeExpression(smallerFrom, smaller, range.step, range.position) + return listOf(IAstModification.ReplaceNode(range, newRange, parent)) + } + } + } else { + val newRange = RangeExpression(range.from, smaller, range.step, range.position) + return listOf(IAstModification.ReplaceNode(range, newRange, parent)) + } + } + } + + val modifications = mutableListOf() val fromDt = range.from.inferType(program).getOr(DataType.UNDEFINED) val toDt = range.to.inferType(program).getOr(DataType.UNDEFINED) - val modifications = mutableListOf() val (commonDt, toChange) = BinaryExpression.commonDatatype(fromDt, toDt, range.from, range.to) if(toChange!=null) addTypecastOrCastedValueModification(modifications, toChange, commonDt, range) + return modifications } + override fun after(arrayIndexedExpression: ArrayIndexedExpression, parent: Node): Iterable { + val constIdx = arrayIndexedExpression.indexer.constIndex() + if(constIdx!=null) { + val smaller = NumericLiteral.optimalInteger(constIdx, arrayIndexedExpression.indexer.position) + val idxDt = arrayIndexedExpression.indexer.indexExpr.inferType(program).getOr(DataType.UNDEFINED) + if(idxDt.largerThan(smaller.type)) { + val newIdx = ArrayIndex(smaller, smaller.position) + val newIndexer = ArrayIndexedExpression(arrayIndexedExpression.arrayvar, newIdx, arrayIndexedExpression.position) + return listOf(IAstModification.ReplaceNode(arrayIndexedExpression, newIndexer, parent)) + } + } + return noModifications + } + private fun addTypecastOrCastedValueModification( modifications: MutableList, expressionToCast: Expression, diff --git a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt index abdd2edeb..379a4835d 100644 --- a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt +++ b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt @@ -498,6 +498,24 @@ class NumericLiteral(val type: DataType, // only numerical types allowed fun fromBoolean(bool: Boolean, position: Position) = NumericLiteral(DataType.BOOL, if(bool) 1.0 else 0.0, position) + fun optimalNumeric(origType1: DataType, origType2: DataType?, value: Number, position: Position) : NumericLiteral { + val optimal = optimalNumeric(value, position) + val largestOrig = if(origType2==null) origType1 else if(origType1.largerThan(origType2)) origType1 else origType2 + if(largestOrig.largerThan(optimal.type)) + return NumericLiteral(largestOrig, optimal.number, position) + else + return optimal + } + + fun optimalInteger(origType1: DataType, origType2: DataType?, value: Int, position: Position): NumericLiteral { + val optimal = optimalInteger(value, position) + val largestOrig = if(origType2==null) origType1 else if(origType1.largerThan(origType2)) origType1 else origType2 + if(largestOrig.largerThan(optimal.type)) + return NumericLiteral(largestOrig, optimal.number, position) + else + return optimal + } + fun optimalNumeric(value: Number, position: Position): NumericLiteral { val digits = floor(value.toDouble()) - value.toDouble() return if(value is Double && digits!=0.0) { @@ -1090,7 +1108,16 @@ data class IdentifierReference(val nameInSource: List, override val posi } else if(vardecl.type!= VarDeclType.CONST) { return null } - return vardecl.value?.constValue(program) + + // the value of a variable can (temporarily) be a different type as the vardecl itself. + // don't return the value if the types don't match yet! + val value = vardecl.value?.constValue(program) + if(value==null || value.type==vardecl.datatype) + return value + val optimal = NumericLiteral.optimalNumeric(value.number, value.position) + if(optimal.type==vardecl.datatype) + return optimal + return null } override fun toString(): String { diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 8584a14e8..3fae30806 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -1,8 +1,10 @@ TODO ==== -wrong answer if cast as uword is not done in: - const uword W=320; uword x1 = ((WIDTH-256)/2 as uword) + math.sin8u(i) +Should give type error, but seems to make num a word !?: + const uword screenwidth = txt.DEFAULT_WIDTH + const ubyte num = (screenwidth-1) / 2 + callgraph issue? : if a sub contains another sub and it calls that, the outer sub is never removed even if it doesn't get called? diff --git a/examples/cx16/diskspeed.p8 b/examples/cx16/diskspeed.p8 index af51e716b..e09faa5cb 100644 --- a/examples/cx16/diskspeed.p8 +++ b/examples/cx16/diskspeed.p8 @@ -33,9 +33,9 @@ main { } if fastserial - diskio.fastmode(3) + void diskio.fastmode(3) else - diskio.fastmode(0) + void diskio.fastmode(0) test_save() test_save_blocks() diff --git a/examples/cx16/mandelbrot.p8 b/examples/cx16/mandelbrot.p8 index d9ab62780..57536bf1b 100644 --- a/examples/cx16/mandelbrot.p8 +++ b/examples/cx16/mandelbrot.p8 @@ -3,8 +3,8 @@ %zeropage basicsafe main { - const uword width = 60 - const uword height = 50 + const ubyte width = 60 + const ubyte height = 50 const ubyte max_iter = 16 sub start() { diff --git a/examples/mandelbrot.p8 b/examples/mandelbrot.p8 index 7e005f08f..3009b9c8d 100644 --- a/examples/mandelbrot.p8 +++ b/examples/mandelbrot.p8 @@ -6,8 +6,8 @@ ; Note: this program can be compiled for multiple target systems. main { - const uword width = 30 - const uword height = 20 + const ubyte width = 30 + const ubyte height = 20 const ubyte max_iter = 16 sub start() { diff --git a/examples/test.p8 b/examples/test.p8 index 2ca98d4de..41efef18b 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,61 +1,16 @@ %import textio -%import gfx_lores -%import emudbg %zeropage basicsafe %option no_sysinit main { - const uword WIDTH = 320 - const ubyte HEIGHT = 240 - sub start() { - uword clo, chi - - void cx16.set_screen_mode(128) - - word x1, y1, x2, y2 - ubyte i - ubyte color = 2 - - sys.set_irqd() - emudbg.reset_cpu_cycles() - for i in 0 to 254 step 4 { - x1 = ((WIDTH-256)/2 as word) + math.sin8u(i) as word - y1 = (HEIGHT-128)/2 + math.cos8u(i)/2 - x2 = ((WIDTH-64)/2 as word) + math.sin8u(i)/4 as word - y2 = (HEIGHT-64)/2 + math.cos8u(i)/4 - cx16.GRAPH_set_colors(color, 0, 1) - cx16.GRAPH_draw_line(x1 as uword, y1 as uword, x2 as uword, y2 as uword) - } - clo, chi = emudbg.cpu_cycles() - sys.clear_irqd() - - txt.print_uwhex(chi, true) - txt.print_uwhex(clo, false) + uword @shared large = (320*240/8/8) + const uword WIDTH=320 + uword x1 = ((WIDTH-256)/2 as uword) + 200 + txt.print_uw(x1) txt.nl() - - sys.wait(50) - cx16.GRAPH_clear() - sys.wait(50) - - sys.set_irqd() - emudbg.reset_cpu_cycles() - color = 5 - for i in 0 to 254 step 4 { - x1 = ((WIDTH-256)/2 as word) + math.sin8u(i) as word - y1 = (HEIGHT-128)/2 + math.cos8u(i)/2 - x2 = ((WIDTH-64)/2 as word) + math.sin8u(i)/4 as word - y2 = (HEIGHT-64)/2 + math.cos8u(i)/4 - gfx_lores.line(x1 as uword, y1 as ubyte, x2 as uword, y2 as ubyte, color) - } - clo, chi = emudbg.cpu_cycles() - sys.clear_irqd() - - txt.print_uwhex(chi, true) - txt.print_uwhex(clo, false) - txt.nl() - - + x1 = ((WIDTH-256)/2) + 200 + txt.print_uw(x1) } }