diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/IfElseAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/IfElseAsmGen.kt index 78e4d9f82..44fc9ca6a 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/IfElseAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/IfElseAsmGen.kt @@ -43,12 +43,16 @@ internal class IfElseAsmGen(private val program: PtProgram, val prefixCond = stmt.condition as? PtPrefix if(prefixCond?.operator=="not") { - checkNotRomsubReturnsStatusReg(prefixCond.value) - assignConditionValueToRegisterAndTest(prefixCond.value) - return if(jumpAfterIf!=null) - translateJumpElseBodies("beq", "bne", jumpAfterIf, stmt.elseScope) - else - translateIfElseBodies("bne", stmt) + if(stmt.hasElse()) + throw AssemblyError("not prefix in ifelse should have been replaced by swapped if-else blocks") + else { + checkNotRomsubReturnsStatusReg(prefixCond.value) + assignConditionValueToRegisterAndTest(prefixCond.value) + return if (jumpAfterIf != null) + translateJumpElseBodies("beq", "bne", jumpAfterIf, stmt.elseScope) + else + translateIfElseBodies("bne", stmt) + } } throw AssemblyError("weird non-boolean condition node type ${stmt.condition} at ${stmt.condition.position}") @@ -99,8 +103,7 @@ internal class IfElseAsmGen(private val program: PtProgram, } } else if(condition is PtPrefix && condition.operator=="not") { - assignConditionValueToRegisterAndTest(condition.value) - asmgen.out(" bne $falseLabel") + throw AssemblyError("not prefix in ifexpression should have been replaced by swapped values") } else { // 'simple' condition, check if it is a byte bittest val bittest = condition as? PtBuiltinFunctionCall @@ -396,51 +399,27 @@ internal class IfElseAsmGen(private val program: PtProgram, } private fun translateIfWordConditionBranch(condition: PtBinaryExpression, falseLabel: String) { - val signed = condition.left.type in SignedDatatypes + // TODO can we reuse this whole thing from IfElse ? val constValue = condition.right.asConstInteger() - if(constValue==0) { - - // TODO reuse more code from regular if statements. Need a shared routine like isWordExprZero() ? - when(condition.operator) { - "==" -> { - // if w==0 - asmgen.assignExpressionToRegister(condition.left, RegisterOrPair.AY, signed) - asmgen.out(" sty P8ZP_SCRATCH_REG | ora P8ZP_SCRATCH_REG | bne $falseLabel") - return + if(constValue!=null) { + if (constValue == 0) { + when (condition.operator) { + "==" -> return translateWordExprIsZero(condition.left, falseLabel) + "!=" -> return translateWordExprIsNotZero(condition.left, falseLabel) } - "!=" -> { - // if w!=0 - asmgen.assignExpressionToRegister(condition.left, RegisterOrPair.AY, signed) - asmgen.out(" sty P8ZP_SCRATCH_REG | ora P8ZP_SCRATCH_REG | beq $falseLabel") - return + } + if (constValue != 0) { + when (condition.operator) { + "==" -> return translateWordExprEqualsNumber(condition.left, constValue, falseLabel) + "!=" -> return translateWordExprNotEqualsNumber(condition.left, constValue, falseLabel) } } } - - if(constValue!=0) { - // TODO reuse more code from regular if statements. Need a shared routine like isWordExprEqualNumber() ? - when(condition.operator) { - "==" -> { - // if w==number - asmgen.assignExpressionToRegister(condition.left, RegisterOrPair.AY, signed) - asmgen.out(""" - cmp #<$constValue - bne $falseLabel - cpy #>$constValue - bne $falseLabel""") - return - } - "!=" -> { - // if w!=number - asmgen.assignExpressionToRegister(condition.left, RegisterOrPair.AY, signed) - asmgen.out(""" - cmp #<$constValue - bne + - cpy #>$constValue - beq $falseLabel -+""") - return - } + val variable = condition.right as? PtIdentifier + if(variable!=null) { + when (condition.operator) { + "==" -> return translateWordExprEqualsVariable(condition.left, variable, falseLabel) + "!=" -> return translateWordExprNotEqualsVariable(condition.left, variable, falseLabel) } } @@ -449,6 +428,130 @@ internal class IfElseAsmGen(private val program: PtProgram, asmgen.out(" beq $falseLabel") } + private fun translateWordExprNotEqualsVariable(expr: PtExpression, variable: PtIdentifier, falseLabel: String) { + // if w!=variable + // TODO reuse code from ifElse? + val varRight = asmgen.asmVariableName(variable) + if(expr is PtIdentifier) { + val varLeft = asmgen.asmVariableName(expr) + asmgen.out(""" + lda $varLeft + cmp $varRight + bne + + lda $varLeft+1 + cmp $varRight+1 + beq $falseLabel ++""") + } else { + asmgen.assignExpressionToRegister(expr, RegisterOrPair.AY, false) + asmgen.out(""" + cmp $varRight + bne + + cpy $varRight+1 + beq $falseLabel ++""") + } + } + + private fun translateWordExprEqualsVariable(expr: PtExpression, variable: PtIdentifier, falseLabel: String) { + // if w==variable + // TODO reuse code from ifElse? + val varRight = asmgen.asmVariableName(variable) + if(expr is PtIdentifier) { + val varLeft = asmgen.asmVariableName(expr) + asmgen.out(""" + lda $varLeft + cmp $varRight + bne $falseLabel + lda $varLeft+1 + cmp $varRight+1 + bne $falseLabel""") + } else { + asmgen.assignExpressionToRegister(expr, RegisterOrPair.AY, false) + asmgen.out(""" + cmp $varRight + bne $falseLabel + cpy $varRight+1 + bne $falseLabel""") + } + } + + private fun translateWordExprNotEqualsNumber(expr: PtExpression, number: Int, falseLabel: String) { + // if w!=number + // TODO reuse code from ifElse? + if(expr is PtIdentifier) { + val varname = asmgen.asmVariableName(expr) + asmgen.out(""" + lda $varname + cmp #<$number + bne + + lda $varname+1 + cmp #>$number + beq $falseLabel ++""") + } else { + asmgen.assignExpressionToRegister(expr, RegisterOrPair.AY, false) + asmgen.out(""" + cmp #<$number + bne + + cpy #>$number + beq $falseLabel ++""") + } + } + + private fun translateWordExprEqualsNumber(expr: PtExpression, number: Int, falseLabel: String) { + // if w==number + // TODO reuse code from ifElse? + if(expr is PtIdentifier) { + val varname = asmgen.asmVariableName(expr) + asmgen.out(""" + lda $varname + cmp #<$number + bne $falseLabel + lda $varname+1 + cmp #>$number + bne $falseLabel""") + } else { + asmgen.assignExpressionToRegister(expr, RegisterOrPair.AY, false) + asmgen.out( """ + cmp #<$number + bne $falseLabel + cpy #>$number + bne $falseLabel""") + } + } + + private fun translateWordExprIsNotZero(expr: PtExpression, falseLabel: String) { + // if w!=0 + // TODO reuse code from ifElse? + if(expr is PtIdentifier) { + val varname = asmgen.asmVariableName(expr) + asmgen.out(""" + lda $varname + ora $varname+1 + beq $falseLabel""") + } else { + asmgen.assignExpressionToRegister(expr, RegisterOrPair.AY, false) + asmgen.out(" sty P8ZP_SCRATCH_REG | ora P8ZP_SCRATCH_REG | beq $falseLabel") + } + } + + private fun translateWordExprIsZero(expr: PtExpression, falseLabel: String) { + // if w==0 + // TODO reuse code from ifElse? + if(expr is PtIdentifier) { + val varname = asmgen.asmVariableName(expr) + asmgen.out(""" + lda $varname + ora $varname+1 + bne $falseLabel""") + } else { + asmgen.assignExpressionToRegister(expr, RegisterOrPair.AY, false) + asmgen.out(" sty P8ZP_SCRATCH_REG | ora P8ZP_SCRATCH_REG | bne $falseLabel") + } + } + private fun translateIfCompareWithZeroByteBranch(condition: PtBinaryExpression, signed: Boolean, falseLabel: String) { // optimized code for byte comparisons with 0 assignConditionValueToRegisterAndTest(condition.left) diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt index 3fdc2fd0e..dea0b732b 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt @@ -91,6 +91,10 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { } private fun translate(ifExpr: PtIfExpression): ExpressionCodeResult { + + if((ifExpr.condition as? PtPrefix)?.operator=="not") + throw AssemblyError("not prefix in ifexpression should have been replaced by swapped values") + // TODO don't store condition as expression result but just use the flags, like a normal PtIfElse translation does val condTr = translateExpression(ifExpr.condition) val trueTr = translateExpression(ifExpr.truevalue) diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt index c67353e4f..17e20014e 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt @@ -1330,6 +1330,9 @@ class IRCodeGen( } private fun translateIfElse(ifElse: PtIfElse): IRCodeChunks { + if((ifElse.condition as? PtPrefix)?.operator=="not") + throw AssemblyError("not prefix in ifelse should have been replaced by swapped if-else blocks") + val condition = ifElse.condition as? PtBinaryExpression if(condition==null || condition.left.type != DataType.FLOAT) { return ifWithElse_IntegerCond(ifElse) diff --git a/codeOptimizers/src/prog8/optimizer/ExpressionSimplifier.kt b/codeOptimizers/src/prog8/optimizer/ExpressionSimplifier.kt index d800eeb82..92a758510 100644 --- a/codeOptimizers/src/prog8/optimizer/ExpressionSimplifier.kt +++ b/codeOptimizers/src/prog8/optimizer/ExpressionSimplifier.kt @@ -238,11 +238,8 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr if(expr.operator=="==") { if(rightDt==DataType.BOOL && leftDt==DataType.BOOL) { val rightConstBool = rightVal?.asBooleanValue - if(rightConstBool!=null) { - return if(rightConstBool) - listOf(IAstModification.ReplaceNode(expr, expr.left, parent)) - else - listOf(IAstModification.ReplaceNode(expr, PrefixExpression("not", expr.left, expr.position), parent)) + if(rightConstBool==true) { + return listOf(IAstModification.ReplaceNode(expr, expr.left, parent)) } } if (rightVal?.number == 1.0) { @@ -261,11 +258,8 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr if (expr.operator=="!=") { if(rightDt==DataType.BOOL && leftDt==DataType.BOOL) { val rightConstBool = rightVal?.asBooleanValue - if(rightConstBool!=null) { - return if (rightConstBool) - listOf(IAstModification.ReplaceNode(expr, PrefixExpression("not", expr.left, expr.position), parent)) - else - listOf(IAstModification.ReplaceNode(expr, expr.left, parent)) + if(rightConstBool==false) { + listOf(IAstModification.ReplaceNode(expr, expr.left, parent)) } } if (rightVal?.number == 1.0) { @@ -416,21 +410,6 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr return noModifications } - override fun after(expr: PrefixExpression, parent: Node): Iterable { - if(expr.operator=="not") { - // not X Y -> X Y - val binExpr = expr.expression as? BinaryExpression - if(binExpr!=null) { - val invertedOperator = invertedComparisonOperator(binExpr.operator) - if(invertedOperator!=null) { - val inverted = BinaryExpression(binExpr.left, invertedOperator, binExpr.right, binExpr.position) - return listOf(IAstModification.ReplaceNode(expr, inverted, parent)) - } - } - } - return noModifications - } - private fun applyAbsorptionLaws(expr: BinaryExpression): Expression? { // NOTE: only when the terms are not function calls!!! if(expr.left is IFunctionCall || expr.right is IFunctionCall) diff --git a/codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt b/codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt index 7a0080bea..04a312f6f 100644 --- a/codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt +++ b/codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt @@ -127,19 +127,6 @@ class StatementOptimizer(private val program: Program, ) } } - - // switch if/else around if the condition is a not - val prefixCond = ifElse.condition as? PrefixExpression - if(prefixCond?.operator=="not") { - errors.info("invert conditon and swap if/else blocks", ifElse.condition.position) - val newTruePart = AnonymousScope(ifElse.elsepart.statements, ifElse.elsepart.position) - val newElsePart = AnonymousScope(ifElse.truepart.statements, ifElse.truepart.position) - return listOf( - IAstModification.ReplaceNode(ifElse.elsepart, newElsePart, ifElse), - IAstModification.ReplaceNode(ifElse.truepart, newTruePart, ifElse), - IAstModification.ReplaceNode(ifElse.condition, prefixCond.expression, ifElse) - ) - } } return noModifications diff --git a/compiler/src/prog8/compiler/astprocessing/NotExpressionAndIfComparisonExprChanger.kt b/compiler/src/prog8/compiler/astprocessing/NotExpressionAndIfComparisonExprChanger.kt index 0c65c3504..d1d77073c 100644 --- a/compiler/src/prog8/compiler/astprocessing/NotExpressionAndIfComparisonExprChanger.kt +++ b/compiler/src/prog8/compiler/astprocessing/NotExpressionAndIfComparisonExprChanger.kt @@ -3,10 +3,8 @@ package prog8.compiler.astprocessing import prog8.ast.Node import prog8.ast.Program import prog8.ast.base.FatalAstException -import prog8.ast.expressions.BinaryExpression -import prog8.ast.expressions.NumericLiteral -import prog8.ast.expressions.PrefixExpression -import prog8.ast.expressions.invertCondition +import prog8.ast.expressions.* +import prog8.ast.statements.IfElse import prog8.ast.walk.AstWalker import prog8.ast.walk.IAstModification import prog8.code.core.* @@ -97,7 +95,6 @@ internal class NotExpressionAndIfComparisonExprChanger(val program: Program, val override fun after(expr: PrefixExpression, parent: Node): Iterable { if(expr.operator == "not") { - // first check if we're already part of a "boolean" expression (i.e. comparing against 0 or 1) // if so, simplify THAT whole expression rather than making it more complicated if (parent is BinaryExpression) { @@ -155,22 +152,49 @@ internal class NotExpressionAndIfComparisonExprChanger(val program: Program, val val notZero = BinaryExpression(x, "!=", NumericLiteral(dt, 0.0, expr.position), expr.position) return listOf(IAstModification.ReplaceNode(expr, notZero, parent)) } + + // not X Y -> X Y val subBinExpr = expr.expression as? BinaryExpression - if(subBinExpr?.operator=="==") { - if(subBinExpr.right.constValue(program)?.number==0.0) { - // not(x==0) -> x!=0 - subBinExpr.operator = "!=" - return listOf(IAstModification.ReplaceNode(expr, subBinExpr, parent)) - } - } else if(subBinExpr?.operator=="!=") { - if(subBinExpr.right.constValue(program)?.number==0.0) { - // not(x!=0) -> x==0 - subBinExpr.operator = "==" - return listOf(IAstModification.ReplaceNode(expr, subBinExpr, parent)) + if(subBinExpr!=null) { + val invertedOperator = invertedComparisonOperator(subBinExpr.operator) + if(invertedOperator!=null) { + val inverted = BinaryExpression(subBinExpr.left, invertedOperator, subBinExpr.right, subBinExpr.position) + return listOf(IAstModification.ReplaceNode(expr, inverted, parent)) } } } return noModifications } + + override fun before(ifElse: IfElse, parent: Node): Iterable { + if(ifElse.elsepart.isNotEmpty()) { + val prefix = ifElse.condition as? PrefixExpression + if(prefix?.operator=="not") { + // if not x a else b -> if x b else a + errors.info("invert condition and swap if/else blocks", ifElse.condition.position) + ifElse.condition = prefix.expression + ifElse.condition.parent = ifElse + val elsepart = ifElse.elsepart + ifElse.elsepart = ifElse.truepart + ifElse.truepart = elsepart + } + } + return noModifications + } + + override fun before(ifExpr: IfExpression, parent: Node): Iterable { + val prefix = ifExpr.condition as? PrefixExpression + if(prefix?.operator=="not") { + // if not x a else b -> if x b else a + errors.info("invert condition and swap values", ifExpr.condition.position) + ifExpr.condition = prefix.expression + ifExpr.condition.parent = ifExpr + val falsevalue = ifExpr.falsevalue + ifExpr.falsevalue = ifExpr.truevalue + ifExpr.truevalue = falsevalue + } + + return noModifications + } } diff --git a/examples/test.p8 b/examples/test.p8 index cb7daaed6..e8a25229d 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,21 +1,66 @@ %import textio %option no_sysinit %zeropage basicsafe -%memtop $0840 main { sub start() { - cx16.r0L=0 - if cx16.r0L==0 { - uword[] addresses = [scores2, start] - uword[] @split scores1 = [10, 25, 50, 100] ; can never clear more than 4 lines at once - uword[] @split scores2 = [10, 25, 50, 100] ; can never clear more than 4 lines at once + cx16.r0=0 - cx16.r0 = &scores1 - cx16.r1 = &scores2 - cx16.r2 = &addresses - } + if cx16.r0==0 + cx16.r1L=42 + else + cx16.r1L=99 + + cx16.r2L = if cx16.r0==0 42 else 99 + + if cx16.r0==33 + cx16.r1L=42 + else + cx16.r1L=99 + + cx16.r2L = if cx16.r0==33 42 else 99 + + if cx16.r0!=3333 + cx16.r1L=42 + else + cx16.r1L=99 + + cx16.r2L = if cx16.r0!=3333 42 else 99 + + if cx16.r0!=0 + cx16.r1L=42 + else + cx16.r1L=99 + + cx16.r2L = if cx16.r0!=0 42 else 99 + + if cx16.r0!=33 + cx16.r1L=42 + else + cx16.r1L=99 + + cx16.r2L = if cx16.r0!=0 42 else 99 + + if cx16.r0==cx16.r9 + cx16.r1L=42 + else + cx16.r1L=99 + + cx16.r2L = if cx16.r0==cx16.r9 42 else 99 + + if cx16.r0!=cx16.r9 + cx16.r1L=42 + else + cx16.r1L=99 + + cx16.r2L = if cx16.r0!=cx16.r9 42 else 99 + + if cx16.r0>cx16.r1 + cx16.r1L=42 + else + cx16.r1L=99 + + cx16.r2L = if cx16.r0>cx16.r1 42 else 99 } - }