diff --git a/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt b/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt index 3d9c37e4e..cf525a36c 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt @@ -115,15 +115,9 @@ class AstPreprocessor(val program: Program, val errors: IErrorReporter, val comp override fun before(expr: PrefixExpression, parent: Node): Iterable { if(expr.operator == "not") { - // To enable simple bitwise and/or/xor/not instructions in the codegen for the logical and/or/xor/not, - // we wrap the operands in a call to boolean() if required so that they are 0 or 1 as needed. - // Making the codegen more generic to do this by itself all the time will generate much larger - // code because it is hard to decide there if the value conversion to 0 or 1 is needed or not, - // so a lot of useless checks and conversions are added. Here we can be smarter so the codegen - // can just rely on the correct value of the operands (0 or 1) if they're boolean, and just use bitwise instructions. - - // not(x) --> boolean(x)==0 - val replacement = BinaryExpression(wrapWithBooleanConversion(expr.expression), "==", NumericLiteral.optimalInteger(0, expr.position), expr.position) + // not(x) --> x==0 + val dt = expr.expression.inferType(program).getOr(DataType.UNDEFINED) + val replacement = BinaryExpression(expr.expression, "==", NumericLiteral(dt,0.0, expr.position), expr.position) return listOf(IAstModification.ReplaceNodeSafe(expr, replacement, parent)) } return noModifications diff --git a/compiler/test/TestOptimization.kt b/compiler/test/TestOptimization.kt index b7b2b872b..19d173126 100644 --- a/compiler/test/TestOptimization.kt +++ b/compiler/test/TestOptimization.kt @@ -462,8 +462,7 @@ class TestOptimization: FunSpec({ ubyte z2 z2 = 255 ubyte z3 - z3 = 0 - z3 = (boolean(z3)==0) + z3 = 1 uword z4 z4 = 0 ubyte z5 @@ -474,30 +473,28 @@ class TestOptimization: FunSpec({ z6 -= 5 */ val statements = result.program.entrypoint.statements - statements.size shouldBe 15 + statements.size shouldBe 14 val z1decl = statements[0] as VarDecl val z1init = statements[1] as Assignment val z2decl = statements[2] as VarDecl val z2init = statements[3] as Assignment val z3decl = statements[4] as VarDecl val z3init = statements[5] as Assignment - val z3not = statements[6] as Assignment - val z4decl = statements[7] as VarDecl - val z4init = statements[8] as Assignment - val z5decl = statements[9] as VarDecl - val z5init = statements[10] as Assignment - val z5plus = statements[11] as Assignment - val z6decl = statements[12] as VarDecl - val z6init = statements[13] as Assignment - val z6plus = statements[14] as Assignment + val z4decl = statements[6] as VarDecl + val z4init = statements[7] as Assignment + val z5decl = statements[8] as VarDecl + val z5init = statements[9] as Assignment + val z5plus = statements[10] as Assignment + val z6decl = statements[11] as VarDecl + val z6init = statements[12] as Assignment + val z6plus = statements[13] as Assignment z1decl.name shouldBe "z1" z1init.value shouldBe NumericLiteral(DataType.UBYTE, 10.0, Position.DUMMY) z2decl.name shouldBe "z2" z2init.value shouldBe NumericLiteral(DataType.UBYTE, 255.0, Position.DUMMY) z3decl.name shouldBe "z3" - z3init.value shouldBe NumericLiteral(DataType.UBYTE, 0.0, Position.DUMMY) - z3not.value shouldBe instanceOf() + z3init.value shouldBe NumericLiteral(DataType.UBYTE, 1.0, Position.DUMMY) z4decl.name shouldBe "z4" z4init.value shouldBe NumericLiteral(DataType.UBYTE, 0.0, Position.DUMMY) z5decl.name shouldBe "z5" diff --git a/compiler/test/arithmetic/logical.p8 b/compiler/test/arithmetic/logical.p8 index e7bd69f3c..7b8abbab9 100644 --- a/compiler/test/arithmetic/logical.p8 +++ b/compiler/test/arithmetic/logical.p8 @@ -20,155 +20,181 @@ main { ubyte ub4 = 0 ubyte bvalue - txt.print("bitwise or 14: ") - txt.print_ub(ub1 | ub2 | ub3 | ub4) + txt.print("const not 126: ") + txt.print_ub(not 129) txt.nl() - txt.print("bitwise or 142: ") - txt.print_ub(ub1 | ub2 | ub3 | ub4 | 128) + txt.print("const not 255: ") + txt.print_ub(not 0) txt.nl() - txt.print("bitwise and 0: ") - txt.print_ub(ub1 & ub2 & ub3 & ub4) - txt.nl() - txt.print("bitwise and 8: ") - txt.print_ub(ub3 & ub3 & 127) - txt.nl() - txt.print("bitwise xor 14: ") - txt.print_ub(ub1 ^ ub2 ^ ub3 ^ ub4) - txt.nl() - txt.print("bitwise xor 6: ") - txt.print_ub(ub1 ^ ub2 ^ ub3 ^ 8) - txt.nl() - txt.print("bitwise not 247: ") - txt.print_ub(~ub3) + bvalue = 129 + txt.print("bitwise not 126: ") + bvalue = not bvalue + txt.print_ub(bvalue) txt.nl() + bvalue = 0 txt.print("bitwise not 255: ") - txt.print_ub(~ub4) + bvalue = not bvalue + txt.print_ub(bvalue) txt.nl() - txt.print("not 0: ") - bvalue = not ub3 - txt.print_ub(bvalue) - if not ub1 - txt.print(" / fail") - else - txt.print(" / ok") - txt.nl() - - txt.print("not 1: ") - bvalue = not ub4 - txt.print_ub(bvalue) - if not ub4 - txt.print(" / ok") - else - txt.print(" / fail") - txt.nl() - - bvalue = bvalue and 128 - txt.print("bvl 1: ") - txt.print_ub(bvalue) - if bvalue and 128 - txt.print(" / ok") - else - txt.print(" / fail") - txt.nl() - - txt.print("and 1: ") - bvalue = ub1 and ub2 and ub3 - txt.print_ub(bvalue) - if ub1 and ub2 and ub3 - txt.print(" / ok") - else - txt.print(" / fail") - txt.nl() - txt.print("and 1: ") - bvalue = ub1 and ub2 and ub3 and 64 - txt.print_ub(bvalue) - if ub1 and ub2 and ub3 and 64 - txt.print(" / ok") - else - txt.print(" / fail") - txt.nl() - txt.print("and 1: ") - bvalue = ub1 and ub2 and ub3 and ftrue(99) - txt.print_ub(bvalue) - if ub1 and ub2 and ub3 and ftrue(99) - txt.print(" / ok") - else - txt.print(" / fail") - txt.nl() - txt.print("and 0: ") - bvalue = ub1 and ub2 and ub3 and ub4 - txt.print_ub(bvalue) - if ub1 and ub2 and ub3 and ub4 - txt.print(" / fail") - else - txt.print(" / ok") - txt.nl() - txt.print("and 0: ") - bvalue = ub1 and ub2 and ub3 and ffalse(99) - txt.print_ub(bvalue) - if ub1 and ub2 and ub3 and ffalse(99) - txt.print(" / fail") - else - txt.print(" / ok") - txt.nl() - - txt.print(" or 1: ") - bvalue = ub1 or ub2 or ub3 or ub4 - txt.print_ub(bvalue) - if ub1 or ub2 or ub3 or ub4 - txt.print(" / ok") - else - txt.print(" / fail") - txt.nl() - txt.print(" or 1: ") - bvalue = ub4 or ub4 or ub1 - txt.print_ub(bvalue) - if ub4 or ub4 or ub1 - txt.print(" / ok") - else - txt.print(" / fail") - txt.nl() - txt.print(" or 1: ") - bvalue = ub1 or ub2 or ub3 or ftrue(99) - txt.print_ub(bvalue) - if ub1 or ub2 or ub3 or ftrue(99) - txt.print(" / ok") - else - txt.print(" / fail") - txt.nl() - - txt.print("xor 1: ") - bvalue = ub1 xor ub2 xor ub3 xor ub4 - txt.print_ub(bvalue) - if ub1 xor ub2 xor ub3 xor ub4 - txt.print(" / ok") - else - txt.print(" / fail") - txt.nl() - txt.print("xor 1: ") - bvalue = ub1 xor ub2 xor ub3 xor ffalse(99) - txt.print_ub(bvalue) - if ub1 xor ub2 xor ub3 xor ffalse(99) - txt.print(" / ok") - else - txt.print(" / fail") - txt.nl() - - txt.print("xor 0: ") - bvalue = ub1 xor ub2 xor ub3 xor ub4 xor true - txt.print_ub(bvalue) - if ub1 xor ub2 xor ub3 xor ub4 xor true - txt.print(" / fail") - else - txt.print(" / ok") - txt.nl() - txt.print("xor 0: ") - bvalue = ub1 xor ub2 xor ub3 xor ftrue(99) - txt.print_ub(bvalue) - if ub1 xor ub2 xor ub3 xor ftrue(99) - txt.print(" / fail") - else - txt.print(" / ok") +; txt.print("bitwise or 14: ") +; txt.print_ub(ub1 | ub2 | ub3 | ub4) +; txt.nl() +; txt.print("bitwise or 142: ") +; txt.print_ub(ub1 | ub2 | ub3 | ub4 | 128) +; txt.nl() +; txt.print("bitwise and 0: ") +; txt.print_ub(ub1 & ub2 & ub3 & ub4) +; txt.nl() +; txt.print("bitwise and 8: ") +; txt.print_ub(ub3 & ub3 & 127) +; txt.nl() +; txt.print("bitwise xor 14: ") +; txt.print_ub(ub1 ^ ub2 ^ ub3 ^ ub4) +; txt.nl() +; txt.print("bitwise xor 6: ") +; txt.print_ub(ub1 ^ ub2 ^ ub3 ^ 8) +; txt.nl() +; txt.print("bitwise not 247: ") +; txt.print_ub(~ub3) +; txt.nl() +; txt.print("bitwise not 255: ") +; txt.print_ub(~ub4) +; txt.nl() +; +; txt.print("not 0: ") +; bvalue = 3 * (ub4 | not (ub3 | ub3 | ub3)) +; txt.print_ub(bvalue) +; if 3*(ub4 | not (ub1 | ub1 | ub1)) +; txt.print(" / fail") +; else +; txt.print(" / ok") +; txt.nl() +; +; txt.print("not 0: ") +; bvalue = not ub3 +; txt.print_ub(bvalue) +; if not ub1 +; txt.print(" / fail") +; else +; txt.print(" / ok") +; txt.nl() +; +; txt.print("not 1: ") +; bvalue = not ub4 +; txt.print_ub(bvalue) +; if not ub4 +; txt.print(" / ok") +; else +; txt.print(" / fail") +; txt.nl() +; +; bvalue = bvalue and 128 +; txt.print("bvl 1: ") +; txt.print_ub(bvalue) +; if bvalue and 128 +; txt.print(" / ok") +; else +; txt.print(" / fail") +; txt.nl() +; +; txt.print("and 1: ") +; bvalue = ub1 and ub2 and ub3 +; txt.print_ub(bvalue) +; if ub1 and ub2 and ub3 +; txt.print(" / ok") +; else +; txt.print(" / fail") +; txt.nl() +; txt.print("and 1: ") +; bvalue = ub1 and ub2 and ub3 and 64 +; txt.print_ub(bvalue) +; if ub1 and ub2 and ub3 and 64 +; txt.print(" / ok") +; else +; txt.print(" / fail") +; txt.nl() +; txt.print("and 1: ") +; bvalue = ub1 and ub2 and ub3 and ftrue(99) +; txt.print_ub(bvalue) +; if ub1 and ub2 and ub3 and ftrue(99) +; txt.print(" / ok") +; else +; txt.print(" / fail") +; txt.nl() +; txt.print("and 0: ") +; bvalue = ub1 and ub2 and ub3 and ub4 +; txt.print_ub(bvalue) +; if ub1 and ub2 and ub3 and ub4 +; txt.print(" / fail") +; else +; txt.print(" / ok") +; txt.nl() +; txt.print("and 0: ") +; bvalue = ub1 and ub2 and ub3 and ffalse(99) +; txt.print_ub(bvalue) +; if ub1 and ub2 and ub3 and ffalse(99) +; txt.print(" / fail") +; else +; txt.print(" / ok") +; txt.nl() +; +; txt.print(" or 1: ") +; bvalue = ub1 or ub2 or ub3 or ub4 +; txt.print_ub(bvalue) +; if ub1 or ub2 or ub3 or ub4 +; txt.print(" / ok") +; else +; txt.print(" / fail") +; txt.nl() +; txt.print(" or 1: ") +; bvalue = ub4 or ub4 or ub1 +; txt.print_ub(bvalue) +; if ub4 or ub4 or ub1 +; txt.print(" / ok") +; else +; txt.print(" / fail") +; txt.nl() +; txt.print(" or 1: ") +; bvalue = ub1 or ub2 or ub3 or ftrue(99) +; txt.print_ub(bvalue) +; if ub1 or ub2 or ub3 or ftrue(99) +; txt.print(" / ok") +; else +; txt.print(" / fail") +; txt.nl() +; +; txt.print("xor 1: ") +; bvalue = ub1 xor ub2 xor ub3 xor ub4 +; txt.print_ub(bvalue) +; if ub1 xor ub2 xor ub3 xor ub4 +; txt.print(" / ok") +; else +; txt.print(" / fail") +; txt.nl() +; txt.print("xor 1: ") +; bvalue = ub1 xor ub2 xor ub3 xor ffalse(99) +; txt.print_ub(bvalue) +; if ub1 xor ub2 xor ub3 xor ffalse(99) +; txt.print(" / ok") +; else +; txt.print(" / fail") +; txt.nl() +; +; txt.print("xor 0: ") +; bvalue = ub1 xor ub2 xor ub3 xor ub4 xor true +; txt.print_ub(bvalue) +; if ub1 xor ub2 xor ub3 xor ub4 xor true +; txt.print(" / fail") +; else +; txt.print(" / ok") +; txt.nl() +; txt.print("xor 0: ") +; bvalue = ub1 xor ub2 xor ub3 xor ftrue(99) +; txt.print_ub(bvalue) +; if ub1 xor ub2 xor ub3 xor ftrue(99) +; txt.print(" / fail") +; else +; txt.print(" / ok") } } diff --git a/docs/source/syntaxreference.rst b/docs/source/syntaxreference.rst index 4280bd01a..fac90d00c 100644 --- a/docs/source/syntaxreference.rst +++ b/docs/source/syntaxreference.rst @@ -486,6 +486,7 @@ logical: ``not`` ``and`` ``or`` ``xor`` These operators are the usual logical operations that are part of a logical expression to reason about truths (boolean values). The result of such an expression is a 'boolean' value 'true' or 'false' (which in reality is just a byte value of 1 or 0). + Notice that the expression ``not x`` is equivalent to ``x==0``, and the compiler will treat it as such. .. note:: Unlike most other programming languages, there is no short-cirquit or McCarthy-evaluation