diff --git a/codeGeneration/src/prog8/compiler/target/cpu6502/codegen/AsmGen.kt b/codeGeneration/src/prog8/compiler/target/cpu6502/codegen/AsmGen.kt index a108e1393..f780497e9 100644 --- a/codeGeneration/src/prog8/compiler/target/cpu6502/codegen/AsmGen.kt +++ b/codeGeneration/src/prog8/compiler/target/cpu6502/codegen/AsmGen.kt @@ -982,7 +982,7 @@ class AsmGen(private val program: Program, } private fun translate(stmt: IfStatement) { - checkBooleanExpression(stmt.condition) // we require the condition to be of the form 'x ' + requireComparisonExpression(stmt.condition) // IfStatement: condition must be of form 'x ' val booleanCondition = stmt.condition as BinaryExpression // DISABLED FOR NOW: @@ -1008,9 +1008,9 @@ class AsmGen(private val program: Program, } } - private fun checkBooleanExpression(condition: Expression) { + private fun requireComparisonExpression(condition: Expression) { if(condition !is BinaryExpression || condition.operator !in comparisonOperators) - throw AssemblyError("expected boolean expression $condition") + throw AssemblyError("expected boolean comparison expression $condition") } private fun translate(stmt: RepeatLoop) { @@ -1161,7 +1161,7 @@ $repeatLabel lda $counterVar } private fun translate(stmt: WhileLoop) { - checkBooleanExpression(stmt.condition) // we require the condition to be of the form 'x ' + requireComparisonExpression(stmt.condition) // WhileLoop: condition must be of form 'x ' val booleanCondition = stmt.condition as BinaryExpression val whileLabel = makeLabel("while") val endLabel = makeLabel("whileend") @@ -1175,7 +1175,7 @@ $repeatLabel lda $counterVar } private fun translate(stmt: UntilLoop) { - checkBooleanExpression(stmt.condition) // we require the condition to be of the form 'x ' + requireComparisonExpression(stmt.condition) // UntilLoop: condition must be of form 'x ' val booleanCondition = stmt.condition as BinaryExpression val repeatLabel = makeLabel("repeat") val endLabel = makeLabel("repeatend") diff --git a/codeGeneration/src/prog8/compiler/target/cpu6502/codegen/ExpressionsAsmGen.kt b/codeGeneration/src/prog8/compiler/target/cpu6502/codegen/ExpressionsAsmGen.kt index 13a444a6f..50355440e 100644 --- a/codeGeneration/src/prog8/compiler/target/cpu6502/codegen/ExpressionsAsmGen.kt +++ b/codeGeneration/src/prog8/compiler/target/cpu6502/codegen/ExpressionsAsmGen.kt @@ -33,13 +33,16 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge } internal fun translateComparisonExpressionWithJumpIfFalse(expr: BinaryExpression, jumpIfFalseLabel: String) { - // This is a helper routine called from while, do-util, and if expressions to generate optimized conditional branching code. + // This is a helper routine called from while, do-util, and if expressions to generate optimized conditional branching code. // First, if it is of the form: X , then flip the expression so the constant is always the right operand. + var left = expr.left var right = expr.right var operator = expr.operator var leftConstVal = left.constValue(program) var rightConstVal = right.constValue(program) + + // make sure the constant value is on the right of the comparison expression if(leftConstVal!=null) { val tmp = left left = right @@ -55,32 +58,90 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge } } - val idt = left.inferType(program) - if(!idt.isKnown) - throw AssemblyError("unknown dt") - val dt = idt.getOr(DataType.UNDEFINED) - when (operator) { - "==" -> { - // if the left operand is an expression, and the right is 0, we can just evaluate that expression, - // and use the result value directly to determine the boolean result. Shortcut only for integers. - if(rightConstVal?.number?.toDouble() == 0.0) { - if(dt in ByteDatatypes) { - asmgen.assignExpressionToRegister(left, RegisterOrPair.A) - if(left is FunctionCall && !left.isSimple) + if (rightConstVal!=null && rightConstVal.number.toDouble() == 0.0) + jumpIfZeroOrNot(left, operator, right, jumpIfFalseLabel, leftConstVal, rightConstVal) + else + jumpIfComparison(left, operator, right, jumpIfFalseLabel, leftConstVal, rightConstVal) + } + + private fun jumpIfZeroOrNot( + left: Expression, + operator: String, + right: Expression, + jumpIfFalseLabel: String, + leftConstVal: NumericLiteralValue?, + rightConstVal: NumericLiteralValue? + ) { + val dt = left.inferType(program).getOrElse { throw AssemblyError("unknown dt") } + when(dt) { + DataType.UBYTE, DataType.BYTE -> { + asmgen.assignExpressionToRegister(left, RegisterOrPair.A) + when (operator) { + "==", "!=" -> { + // simple zero (in)equality check + if (left is FunctionCall && !left.isSimple) asmgen.out(" cmp #0") - asmgen.out(" bne $jumpIfFalseLabel") - return + if (operator == "==") + asmgen.out(" bne $jumpIfFalseLabel") + else + asmgen.out(" beq $jumpIfFalseLabel") } - else if(dt in WordDatatypes) { - asmgen.assignExpressionToRegister(left, RegisterOrPair.AY) - asmgen.out(""" - sty P8ZP_SCRATCH_B1 - ora P8ZP_SCRATCH_B1 - bne $jumpIfFalseLabel""") - return + else -> { + // TODO optimize byte other operators + jumpIfComparison(left, operator, right, jumpIfFalseLabel, leftConstVal, rightConstVal) } } + } + DataType.UWORD, DataType.WORD -> { + asmgen.assignExpressionToRegister(left, RegisterOrPair.AY) + when (operator) { + "==" -> { + asmgen.out(" sty P8ZP_SCRATCH_B1 | ora P8ZP_SCRATCH_B1 | bne $jumpIfFalseLabel") + } + "!=" -> { + asmgen.out(" sty P8ZP_SCRATCH_B1 | ora P8ZP_SCRATCH_B1 | beq $jumpIfFalseLabel") + } + else -> { + // TODO optimize word other operators + jumpIfComparison(left, operator, right, jumpIfFalseLabel, leftConstVal, rightConstVal) + } + } + } + DataType.FLOAT -> { + asmgen.assignExpressionToRegister(left, RegisterOrPair.FAC1) + when (operator) { + "==" -> { + asmgen.out(" jsr floats.SIGN") // SIGN(fac1) to A, $ff, $0, $1 for negative, zero, positive + asmgen.out(" bne $jumpIfFalseLabel") + } + "!=" -> { + asmgen.out(" jsr floats.SIGN") // SIGN(fac1) to A, $ff, $0, $1 for negative, zero, positive + asmgen.out(" beq $jumpIfFalseLabel") + } + else -> { + // TODO optimize float other operators? + jumpIfComparison(left, operator, right, jumpIfFalseLabel, leftConstVal, rightConstVal) + } + } + } + else -> { + throw AssemblyError("invalid dt") + } + } + } + private fun jumpIfComparison( + left: Expression, + operator: String, + right: Expression, + jumpIfFalseLabel: String, + leftConstVal: NumericLiteralValue?, + rightConstVal: NumericLiteralValue? + ) { + val dt = left.inferType(program).getOrElse { throw AssemblyError("unknown dt") } + + when (operator) { + "==" -> { when (dt) { in ByteDatatypes -> translateByteEqualsJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel) in WordDatatypes -> translateWordEqualsJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel) @@ -90,26 +151,6 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge } } "!=" -> { - // if the left operand is an expression, and the right is 0, we can just evaluate that expression, - // and use the result value directly to determine the boolean result. Shortcut only for integers. - if(rightConstVal?.number?.toDouble() == 0.0) { - if(dt in ByteDatatypes) { - asmgen.assignExpressionToRegister(left, RegisterOrPair.A) - if(left is FunctionCall && !left.isSimple) - asmgen.out(" cmp #0") - asmgen.out(" beq $jumpIfFalseLabel") - return - } - else if(dt in WordDatatypes) { - asmgen.assignExpressionToRegister(left, RegisterOrPair.AY) - asmgen.out(""" - sty P8ZP_SCRATCH_B1 - ora P8ZP_SCRATCH_B1 - beq $jumpIfFalseLabel""") - return - } - } - when (dt) { in ByteDatatypes -> translateByteNotEqualsJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel) in WordDatatypes -> translateWordNotEqualsJump(left, right, leftConstVal, rightConstVal, jumpIfFalseLabel) diff --git a/examples/test.p8 b/examples/test.p8 index fbe3201a5..d6e49eff1 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,41 +1,55 @@ -%import string +%import floats %import textio %zeropage basicsafe main { + sub start() { - uword[] values = [1111,2222,3333,4444] + ubyte xx + float ff - @($2000) = 'a' - @($2001) = 'b' - @($2002) = 'c' - @($2003) = 0 + ff=0 - asmfunc([999,888,777]) - asmfunc(values) - asmfunc($2000) - txt.nl() - func([999,888,777]) - func(values) - func($2000) - } + if ff==0 { + txt.print("ff=0\n") + } + if ff!=0 { + txt.print("ff!=0 (error!)\n") + } + ff=-0.22 + if ff==0 { + txt.print("ff=0 (error!)\n") + } + if ff!=0 { + txt.print("ff!=0\n") + } - asmsub asmfunc(uword[] thing @AY) { - %asm {{ - sta func.thing - sty func.thing+1 - jmp func - }} - } - sub func(uword[] thing) { - uword t2 = thing as uword - ubyte length = string.length(thing) - txt.print_uwhex(thing, true) - txt.nl() - txt.print_ub(length) - txt.nl() - txt.print(thing) - txt.nl() + if xx { ; doesn't use stack... + xx++ + } + + xx = xx+1 ; doesn't use stack... + + if 8