diff --git a/compiler/examples/cube3d.p8 b/compiler/examples/cube3d.p8 index 02a1b3352..a1cde3590 100644 --- a/compiler/examples/cube3d.p8 +++ b/compiler/examples/cube3d.p8 @@ -39,7 +39,7 @@ _vm_gfx_text(14, 5, 5, "Spin to Win !!!") for i in 0 to width//10 { - _vm_gfx_line(i*2+width//2-width//10, 130, i*10, 199, 6) + _vm_gfx_line(i*2+width//2-width//10, 130, i*10.w, 199, 6) } rotate_vertices(flt(irq.global_time) / 30.0) diff --git a/compiler/examples/swirl.p8 b/compiler/examples/swirl.p8 index c90c86f85..3052a7510 100644 --- a/compiler/examples/swirl.p8 +++ b/compiler/examples/swirl.p8 @@ -25,9 +25,9 @@ } sub screenx(x: float) -> word { - return floor(x * flt(width)/4.1) + width // 2 ; @todo const-fold x*y/z + return floor(x * flt(width)/4.1) + width // 2 } sub screeny(y: float) -> word { - return floor(y * flt(height)/4.1) + height // 2 ; @todo const-fold x*y/z + return floor(y * flt(height)/4.1) + height // 2 } } diff --git a/compiler/examples/test.p8 b/compiler/examples/test.p8 index ca523732e..47c9e03ba 100644 --- a/compiler/examples/test.p8 +++ b/compiler/examples/test.p8 @@ -6,16 +6,18 @@ sub start() { - const byte b1 = 20//7 - const word w1 = 20//7 - const float f1 = 20/7 + const float c1 = 11.11 + const float c2 = 22.22 + float v + float r + byte x + word w + + r=flt(x) + w=wrd(x) + w=wrdhi(x) + - _vm_write_num(b1) - _vm_write_char('\n') - _vm_write_num(w1) - _vm_write_char('\n') - _vm_write_num(f1) - _vm_write_char('\n') return } diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index da8480e2f..b539037e9 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -826,6 +826,8 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, } "msb" -> stackvmProg.instr(Opcode.MSB) "lsb" -> stackvmProg.instr(Opcode.LSB) + "wrd" -> stackvmProg.instr(Opcode.B2WORD) + "wrdhi" -> stackvmProg.instr(Opcode.MSB2WORD) "lsl" -> { val arg = args.single() when (arg.resultingDatatype(namespace, heap)) { diff --git a/compiler/src/prog8/functions/BuiltinFunctions.kt b/compiler/src/prog8/functions/BuiltinFunctions.kt index fdbd14325..59276f8e2 100644 --- a/compiler/src/prog8/functions/BuiltinFunctions.kt +++ b/compiler/src/prog8/functions/BuiltinFunctions.kt @@ -47,6 +47,8 @@ val BuiltinFunctions = mapOf( "lsb" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.WORD))), DataType.BYTE) { a, p, n, h -> oneIntArgOutputInt(a, p, n, h) { x: Int -> x and 255 }}, "msb" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.WORD))), DataType.BYTE) { a, p, n, h -> oneIntArgOutputInt(a, p, n, h) { x: Int -> x ushr 8 and 255}}, "flt" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.BYTE, DataType.WORD))), DataType.FLOAT, ::builtinFlt), + "wrd" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.BYTE))), DataType.WORD, ::builtinWrd), + "wrdhi" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.BYTE))), DataType.WORD, ::builtinWrdHi), "rnd" to FunctionSignature(true, emptyList(), DataType.BYTE), "rndw" to FunctionSignature(true, emptyList(), DataType.WORD), "rndf" to FunctionSignature(true, emptyList(), DataType.FLOAT), @@ -266,6 +268,28 @@ private fun builtinFlt(args: List, position: Position, namespace:IN return LiteralValue(DataType.FLOAT, floatvalue = number.toDouble(), position = position) } +private fun builtinWrd(args: List, position: Position, namespace:INameScope, heap: HeapValues): LiteralValue { + // 1 byte arg, convert to word + if(args.size!=1) + throw SyntaxError("wrd requires one numeric argument", position) + + val constval = args[0].constValue(namespace, heap) ?: throw NotConstArgumentException() + if(constval.type!=DataType.BYTE) + throw SyntaxError("wrd requires one byte argument", position) + return LiteralValue(DataType.WORD, wordvalue = constval.bytevalue!!.toInt(), position = position) +} + +private fun builtinWrdHi(args: List, position: Position, namespace:INameScope, heap: HeapValues): LiteralValue { + // 1 byte arg, convert to word (in hi byte) + if(args.size!=1) + throw SyntaxError("wrdhi requires one numeric argument", position) + + val constval = args[0].constValue(namespace, heap) ?: throw NotConstArgumentException() + if(constval.type!=DataType.BYTE) + throw SyntaxError("wrdhi requires one byte argument", position) + return LiteralValue(DataType.WORD, wordvalue = constval.bytevalue!!.toInt() shl 8, position = position) +} + private fun builtinAbs(args: List, position: Position, namespace:INameScope, heap: HeapValues): LiteralValue { // 1 arg, type = float or int, result type= same as argument type if(args.size!=1) diff --git a/compiler/src/prog8/optimizing/ConstantFolding.kt b/compiler/src/prog8/optimizing/ConstantFolding.kt index ff8412a3f..89f382e6d 100644 --- a/compiler/src/prog8/optimizing/ConstantFolding.kt +++ b/compiler/src/prog8/optimizing/ConstantFolding.kt @@ -278,11 +278,134 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV } return expr } - - // todo: other cases where both operators are identical return expr + } else { - // todo: other combinations of operators and constants (with different operator in subexpr) + + if(expr.operator=="/" && subExpr.operator=="*") { + optimizationsDone++ + if(leftIsConst) { + return if(subleftIsConst) { + // C1/(C2*V) -> (C1/C2)/V + BinaryExpression( + BinaryExpression(expr.left, "/", subExpr.left, subExpr.position), + "/", + subExpr.right, expr.position) + } else { + // C1/(V*C2) -> (C1/C2)/V + BinaryExpression( + BinaryExpression(expr.left, "/", subExpr.right, subExpr.position), + "/", + subExpr.left, expr.position) + } + } else { + return if(subleftIsConst) { + // (C1*V)/C2 -> (C1/C2)*V + BinaryExpression( + BinaryExpression(subExpr.left, "/", expr.right, subExpr.position), + "*", + subExpr.right, expr.position) + } else { + // (V*C1)/C2 -> (C1/C2)*V + BinaryExpression( + BinaryExpression(subExpr.right, "/", expr.right, subExpr.position), + "*", + subExpr.left, expr.position) + } + } + } else if(expr.operator=="*" && subExpr.operator=="/") { + optimizationsDone++ + if(leftIsConst) { + return if(subleftIsConst) { + // C1*(C2/V) -> (C1*C2)/V + BinaryExpression( + BinaryExpression(expr.left, "*", subExpr.left, subExpr.position), + "/", + subExpr.right, expr.position) + } else { + // C1*(V/C2) -> (C1/C2)*V + BinaryExpression( + BinaryExpression(expr.left, "/", subExpr.right, subExpr.position), + "*", + subExpr.left, expr.position) + } + } else { + return if(subleftIsConst) { + // (C1/V)*C2 -> (C1*C2)/V + BinaryExpression( + BinaryExpression(subExpr.left, "*", expr.right, subExpr.position), + "/", + subExpr.right, expr.position) + } else { + // (V/C1)*C2 -> (C2/C1)*V + BinaryExpression( + BinaryExpression(subExpr.right, "/", expr.right, subExpr.position), + "*", + subExpr.left, expr.position) + } + } + } else if(expr.operator=="+" && subExpr.operator=="-") { + if(leftIsConst){ + return if(subleftIsConst){ + // c1+(c2-v) -> (c1+c2)-v + BinaryExpression( + BinaryExpression(expr.left, "+", subExpr.left, subExpr.position), + "-", + subExpr.right, expr.position) + } else { + // c1+(v-c2) -> v+(c1-c2) + BinaryExpression( + BinaryExpression(expr.left, "-", subExpr.right, subExpr.position), + "+", + subExpr.left, expr.position) + } + } else { + return if(subleftIsConst) { + // (c1-v)+c2 -> (c1+c2)-v + BinaryExpression( + BinaryExpression(subExpr.left, "+", expr.right, subExpr.position), + "-", + subExpr.right, expr.position) + } else { + // (v-c1)+c2 -> v+(c2-c1) + BinaryExpression( + BinaryExpression(expr.right, "-", subExpr.right, subExpr.position), + "+", + subExpr.left, expr.position) + } + } + } else if(expr.operator=="-" && subExpr.operator=="+") { + if(leftIsConst) { + return if(subleftIsConst) { + // c1-(c2+v) -> (c1-c2)-v + BinaryExpression( + BinaryExpression(expr.left, "-", subExpr.left, subExpr.position), + "-", + subExpr.right, expr.position) + } else { + // c1-(v+c2) -> (c1-c2)-v + BinaryExpression( + BinaryExpression(expr.left, "-", subExpr.right, subExpr.position), + "-", + subExpr.left, expr.position) + } + } else { + return if(subleftIsConst) { + // (c1+v)-c2 -> v+(c1-c2) + BinaryExpression( + BinaryExpression(subExpr.left, "-", expr.right, subExpr.position), + "+", + subExpr.right, expr.position) + } else { + // (v+c1)-c2 -> v+(c1-c2) + BinaryExpression( + BinaryExpression(subExpr.right, "-", expr.right, subExpr.position), + "+", + subExpr.left, expr.position) + } + } + } + return expr } } diff --git a/docs/source/programming.rst b/docs/source/programming.rst index d542117a4..2027e6339 100644 --- a/docs/source/programming.rst +++ b/docs/source/programming.rst @@ -561,6 +561,14 @@ flt(x) Explicitly convert the number x to a floating point number. This is required if you want calculations to have floating point precision when the values aren't float already. +wrd(x) + Explicitly convert the byte x to a word. + This is required if you want calculations to have word precision when the values are bytes. + +wrdhi(x) + Explicitly convert the byte x to a word, where x will be the high byte (msb) in the word. + This can be useful in calculations with word precision when the values are bytes. + any(x) 1 ('true') if any of the values in the non-scalar (array or matrix) value x is 'true' (not zero), else 0 ('false')