diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt index 0e40931d5..94f9931c9 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt @@ -1092,7 +1092,30 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { internal fun operatorLogicalAndInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): Result { if(array!=null) { - TODO("and") + val result = mutableListOf() + val constIndex = array.index.asConstInteger() + val constValue = operand.asConstInteger() + val eltSize = codeGen.program.memsizer.memorySize(array.type) + if(constIndex!=null && constValue!=null) { + if(array.splitWords) { + val valueRegLsb = codeGen.registers.nextFree() + val valueRegMsb = codeGen.registers.nextFree() + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOAD, vmDt, reg1=valueRegLsb, immediate=constValue and 255) + it += IRInstruction(Opcode.LOAD, vmDt, reg1=valueRegMsb, immediate=constValue shr 8) + it += IRInstruction(Opcode.ANDM, vmDt, reg1=valueRegLsb, labelSymbol = array.variable.name+"_lsb", symbolOffset = constIndex) + it += IRInstruction(Opcode.ANDM, vmDt, reg1=valueRegMsb, labelSymbol = array.variable.name+"_msb", symbolOffset = constIndex) + } + } else { + val valueReg = codeGen.registers.nextFree() + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOAD, vmDt, reg1=valueReg, immediate=constValue) + it += IRInstruction(Opcode.ANDM, vmDt, reg1=valueReg, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize) + } + } + return Ok(result) + } + return Err(NotImplementedError("inplace word array and")) // TODO? } if(constAddress==null && memory!=null) return Err(NotImplementedError("optimized memory in-place and")) // TODO @@ -1169,7 +1192,30 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { internal fun operatorLogicalOrInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): Result { if(array!=null) { - TODO("or") + val result = mutableListOf() + val constIndex = array.index.asConstInteger() + val constValue = operand.asConstInteger() + val eltSize = codeGen.program.memsizer.memorySize(array.type) + if(constIndex!=null && constValue!=null) { + if(array.splitWords) { + val valueRegLsb = codeGen.registers.nextFree() + val valueRegMsb = codeGen.registers.nextFree() + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOAD, vmDt, reg1=valueRegLsb, immediate=constValue and 255) + it += IRInstruction(Opcode.LOAD, vmDt, reg1=valueRegMsb, immediate=constValue shr 8) + it += IRInstruction(Opcode.ORM, vmDt, reg1=valueRegLsb, labelSymbol = array.variable.name+"_lsb", symbolOffset = constIndex) + it += IRInstruction(Opcode.ORM, vmDt, reg1=valueRegMsb, labelSymbol = array.variable.name+"_msb", symbolOffset = constIndex) + } + } else { + val valueReg = codeGen.registers.nextFree() + result += IRCodeChunk(null, null).also { + it += IRInstruction(Opcode.LOAD, vmDt, reg1=valueReg, immediate=constValue) + it += IRInstruction(Opcode.ORM, vmDt, reg1=valueReg, labelSymbol = array.variable.name, symbolOffset = constIndex*eltSize) + } + } + return Ok(result) + } + return Err(NotImplementedError("inplace word array or")) // TODO? } if(constAddress==null && memory!=null) return Err(NotImplementedError("optimized memory in-place or")) // TODO @@ -1206,7 +1252,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { internal fun operatorDivideInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression, signed: Boolean): Result { if(array!=null) { - TODO("/") + TODO("/ in array") } if(constAddress==null && memory!=null) return Err(NotImplementedError("optimized memory in-place /")) // TODO @@ -1261,7 +1307,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { internal fun operatorMultiplyInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): Result { if(array!=null) { - TODO("*") + TODO("* in array") } if(constAddress==null && memory!=null) return Err(NotImplementedError("optimized memory in-place *")) // TODO @@ -1475,7 +1521,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { internal fun operatorShiftRightInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression, signed: Boolean): Result { if(array!=null) { - TODO(">>") + TODO(">> in array") } if(constAddress==null && memory!=null) return Err(NotImplementedError("optimized memory in-place >>")) // TODO @@ -1503,7 +1549,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { internal fun operatorShiftLeftInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): Result { if(array!=null) { - TODO("<<") + TODO("<< in array") } if(constAddress==null && memory!=null) return Err(NotImplementedError("optimized memory in-place <<")) // TODO @@ -1552,7 +1598,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { } return Ok(result) } - return Err(NotImplementedError("inplace word array ^")) // TODO? + return Err(NotImplementedError("inplace word array xor")) // TODO? } if(constAddress==null && memory!=null) return Err(NotImplementedError("optimized memory in-place xor")) // TODO @@ -1570,7 +1616,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { internal fun operatorModuloInplace(symbol: String?, array: PtArrayIndexer?, constAddress: Int?, memory: PtMemoryByte?, vmDt: IRDataType, operand: PtExpression): Result { if(array!=null) { - TODO("%") + TODO("% in array") } if(constAddress==null && memory!=null) return Err(NotImplementedError("optimized memory in-place %")) // TODO diff --git a/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt b/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt index 29c9878cb..eb774940f 100644 --- a/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt +++ b/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt @@ -128,7 +128,6 @@ if not CONDITION if(!whileLoop.condition.inferType(program).isBool) errors.err("condition should be a boolean", whileLoop.condition.position) - /* while true -> repeat while false -> discard diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 0ab5a9ef0..717508563 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -13,30 +13,27 @@ ConstantFoldingOptimizer (after merging master): ===== ====== ======= VM 6502 what ===== ====== ======= -ok ok boolean const -ok ok boolean variables value -ok ok static bool var (block scope) with initializer value (staticVariable2asm) -ok ok boolean arrays value, list and single value -ok ok type error for bool[3] derp = 99 and also for init value [1,0,1] and also for [true, false, 1, 0, 222] -ok ok return boolean value from sub -ok . make sure that and,or,xor,not aren't getting replaced by the bitwise versions -ok . and, or, xor, not work in expressions: print_ub((bb and true) as ubyte) -ok . logical not works, also inplace -ok . logical xor works, also inplace -- . efficient code for manipulating bools in an array (normal and agumented assigns) -ok ok bitwise logical ops on bools give type error, including invert -ok ok arithmetic ops on bools give type error -ok ok boolean values in ubyte array should give type error -ok ok while booleanvar==42 should give type error -ok ok do..until booleanvar==42 should give type error -ok ok while not should give type error -FAIL . while not should give type error +ok . boolean const +ok . boolean variables value, boolean subroutine param +ok . static bool var (block scope) with initializer value (staticVariable2asm) +ok . boolean arrays value, list and single value +ok . return boolean value from sub +ok . logical not, and, or, xor work correctly, also inplace +ok . make sure that and,or,xor,not aren't getting replaced by the bitwise versions in the Ast +ok . and, or, xor, not should work in expressions: print_ub((bb and true) as ubyte) +ok . bitwise logical ops on bools give type error, including invert +ok . arithmetic ops on bools give type error +ok . logical ops on ints give type error +ok . boolean values in ubyte array should give type error +ok . type error for bool[3] derp = 99 and also for init value [1,0,1] and also for [true, false, 1, 0, 222] +ok . while booleanvar==42 and do..until booleanvar==42 should give type error +ok . while not should give type error +ok . while not should give type error ok . while boolean should produce identical code as while integer!=0 -ok . while not guessed -> can we get rid of the cmp? +ok . while not boolvar -> can we get rid of the cmp? (6502 only?) ok . if someint==0 / ==1 should stil produce good asm same as what it used to be with if not someint/if someint -ok . if not X -> test all variations with and without else -yes . is this De Morgan's optimization still useful in this branch? : not a1 or not a2 -> not(a1 and a2) likewise for and. -yes . is it beneficial to somehow have DeMorgan's law also work on integer types if b1==0 and b2==0 -> if (b1 & b2)==0 +ok . efficient code for manipulating bools in an array (normal and agumented assigns) +ok . testmonogfx works ok . check program sizes vs. master branch ===== ====== ======= diff --git a/examples/test.p8 b/examples/test.p8 index 8a12745ff..342e97e42 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -3,22 +3,267 @@ %option no_sysinit main { + bool @shared staticbool1 = true + bool @shared staticbool2 + sub start() { - bool[3] barr + boolean_const_and_var(true) + staticbool1 = boolean_arrays_and_return() + txt.print_ub(staticbool1 as ubyte) + txt.nl() + and_or_xor_not() +; bitwise_on_bools_errors() +; arith_on_bools_errors() +; logical_on_ints_errors() +; bools_in_intarray_errors() +; ints_in_boolarray_errors() +; while_until_int_errors() + while_equiv() + bools_in_array_assigns() + bools_in_array_assigns_inplace() + if_code() + +; bool[3] barr +; bool @shared bb +; +; barr[1] = barr[0] and barr[2] +; barr[1] = barr[0] or barr[2] +; barr[1] = barr[0] xor barr[2] +; barr[1] = not barr[0] +; barr[1] = not barr[1] +; barr[1] = barr[1] and bb +; barr[1] = barr[1] or bb +; barr[1] = barr[1] xor bb +; +; bb = bb and barr[1] +; bb = bb or barr[1] +; bb = bb xor barr[1] +; bb = not bb + } + + sub boolean_const_and_var(bool barg) { + const bool bconst1 = true + const bool bconst2 = false + bool @shared bvar1 = bconst1 or bconst2 + bool @shared bvar2 + bool @shared bvar3 = true + ; should print: 101101 + txt.print_ub(staticbool1 as ubyte) + txt.print_ub(staticbool2 as ubyte) + txt.print_ub(barg as ubyte) + txt.print_ub(bvar1 as ubyte) + txt.print_ub(bvar2 as ubyte) + txt.print_ub(bvar3 as ubyte) + txt.nl() + } + + sub boolean_arrays_and_return() -> bool { + bool[] barr1 = [ true, false, true ] + bool[3] barr2 = true + bool zz + ; should print: 101, 111 + for zz in barr1 + txt.print_ub(zz as ubyte) + txt.nl() + for zz in barr2 + txt.print_ub(zz as ubyte) + txt.nl() + return false + } + + sub and_or_xor_not() { + bool @shared btrue1 = true + bool @shared bfalse1 = false + bool @shared btrue2 = true + bool @shared bfalse2 = false + bool @shared bb + staticbool2 = staticbool1 and bb + staticbool1 = staticbool2 or bb + staticbool2 = staticbool1 xor bb + staticbool1 = staticbool1 and bb + staticbool2 = staticbool2 or bb + staticbool1 = staticbool1 xor bb + txt.print_ub((bb and true) as ubyte) + txt.print_ub((bb or true) as ubyte) + txt.print_ub((bb xor true) as ubyte) + txt.nl() + if not(btrue1 and btrue2) + txt.print("fail1\n") + if btrue1 and bfalse2 + txt.print("fail2\n") + if bfalse1 or bfalse2 + txt.print("fail3\n") + if not(btrue1 or btrue2) + txt.print("fail4\n") + if btrue1 xor btrue2 + txt.print("fail5\n") + if not(bfalse1 xor btrue1) + txt.print("fail6\n") + + bb = false + bb = bb or btrue1 + if not bb + txt.print("fail7\n") + bb = bb and bfalse1 + if bb + txt.print("fail8\n") + bb = bb xor btrue1 + if not bb + txt.print("fail9\n") + } + +; sub bitwise_on_bools_errors() { +; bool bb1 +; bool bb2 +; bb2 = bb1 | staticbool1 +; bb1 = bb2 & staticbool1 +; bb2 = bb1 ^ staticbool1 +; bb1 = bb1 | staticbool1 +; bb2 = bb2 & staticbool1 +; bb1 = bb1 ^ staticbool1 +; bb2 = ~ staticbool1 +; voidfuncub(bb1 | staticbool1) +; } +; +; sub arith_on_bools_errors() { +; bool @shared bb1 +; bool @shared bb2 +; bb2 = bb1 + staticbool1 +; bb1 = bb2 * staticbool1 +; bb2 = staticbool1 * staticbool1 +; voidfuncub(bb1 + staticbool1) +; } +; +; sub logical_on_ints_errors() { +; ubyte @shared ub1 +; ubyte @shared ub2 +; staticbool1 = ub1 and ub2 +; voidfuncub(ub1 xor ub2) +; } +; +; sub bools_in_intarray_errors() { +; ubyte[3] arr1 = true +; ubyte[3] arr2 = [1, true, 2] +; } +; +; sub ints_in_boolarray_errors() { +; ;; bool[3] arr1 = 42 +; bool[3] arr2 = [1, true, 2] +; } +; +; sub while_until_int_errors() { +;; while staticbool1==42 { +;; cx16.r0++ +;; } +;; +;; do { +;; cx16.r0++ +;; } until staticbool1==42 +; +; ubyte @shared ub1 +; +; while not ub1 { +; cx16.r0++ +; } +; +; while intfunc() { +; cx16.r0++ +; } +; +; while not intfunc() { +; cx16.r0++ +; } +; +;; while not cx16.mouse_pos() { +;; cx16.r0++ +;; } +; } + + sub while_equiv() { + ubyte @shared ub bool @shared bb - barr[1] = barr[0] and barr[2] - barr[1] = barr[0] or barr[2] - barr[1] = barr[0] xor barr[2] - barr[1] = not barr[0] - barr[1] = not barr[1] - barr[1] = barr[1] and bb - barr[1] = barr[1] or bb - barr[1] = barr[1] xor bb + while bb { + cx16.r0++ + } + while ub!=0 { + cx16.r0++ + } + while not bb { + cx16.r0++ + } + while ub==0 { + cx16.r0++ + } + } - bb = bb and barr[1] - bb = bb or barr[1] - bb = bb xor barr[1] - bb = not bb + sub bools_in_array_assigns() { + bool[] ba = [true, false, true] + ba[1] = ba[0] xor staticbool2 + ba[2] = staticbool2 xor ba[0] + ba[1] = ba[0] and staticbool2 + ba[2] = staticbool2 and ba[0] + ba[1] = ba[0] or staticbool2 + ba[2] = staticbool2 or ba[0] + ba[1] = not staticbool2 + + ba[1] = ba[0] xor ba[2] + ba[2] = ba[0] and ba[1] + ba[1] = ba[0] or ba[2] + ba[1] = not ba[2] + } + + sub bools_in_array_assigns_inplace() { + bool[] ba = [true, false, true] + cx16.r0++ + ba[1] = ba[1] xor staticbool2 + ba[2] = staticbool2 xor ba[2] + ba[1] = ba[1] and staticbool2 + ba[2] = staticbool2 and ba[2] + ba[1] = ba[1] or staticbool2 + ba[2] = staticbool2 or ba[2] + + ba[2] = ba[2] xor ba[1] + ba[1] = ba[1] and ba[2] + ba[2] = ba[2] or ba[1] + ba[2] = not ba[2] + } + + sub if_code() { + ubyte @shared ub + bool @shared bb + if ub==0 + cx16.r0++ + if ub!=0 + cx16.r0++ + if bb + cx16.r0++ + if not bb + cx16.r0++ + + if ub==0 + cx16.r0++ + else + cx16.r0-- + if ub!=0 + cx16.r0++ + else + cx16.r0-- + if bb + cx16.r0++ + else + cx16.r0-- + if not bb + cx16.r0++ + else + cx16.r0-- + } + + sub intfunc() -> ubyte { + return cx16.r0L + } + + sub voidfuncub(ubyte arg) { + cx16.r0++ } }