diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/ExpressionsAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/ExpressionsAsmGen.kt index c2c02265d..9122b52ad 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/ExpressionsAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/ExpressionsAsmGen.kt @@ -247,30 +247,39 @@ internal class ExpressionsAsmGen(private val program: PtProgram, private fun translateRpnExpression(expr: PtRpn) { // Uses evalstack to evaluate the given expression. THIS IS SLOW AND SHOULD BE AVOIDED! - val oper = expr.finalOperator() - val left = expr.finalLeftOperand() as? PtExpression + val (left, oper, right) = expr.finalOperation() + if(left is PtExpression && right is PtExpression && translateSomewhatOptimized(left, oper.operator, right)) + return + val leftDt = oper.leftType val rightDt = oper.rightType - // comparison against zero - if(left != null && oper.operator in ComparisonOperators) { - if(leftDt in NumericDatatypes && rightDt in NumericDatatypes) { - val rightVal = (expr.finalRightOperand() as PtExpression).asConstInteger() - if(rightVal==0) - return translateComparisonWithZero(left, leftDt, oper.operator) + // comparison with zero + if(oper.operator in ComparisonOperators && leftDt in NumericDatatypes && rightDt in NumericDatatypes) { + val rightVal = (expr.finalRightOperand() as PtExpression).asConstInteger() + if (rightVal == 0) { + when (left) { + is PtExpression -> { + translateComparisonWithZero(left, leftDt, oper.operator) + } + is PtRpnOperator -> { + expr.children.removeLast() + expr.children.removeLast() + translateComparisonWithZero(expr, leftDt, oper.operator) + } + else -> throw AssemblyError("weird rpn node") + } + return } } // string compare - if(left!=null && leftDt==DataType.STR && rightDt==DataType.STR && oper.operator in ComparisonOperators) { + if(left is PtExpression && leftDt==DataType.STR && rightDt==DataType.STR && oper.operator in ComparisonOperators) return translateCompareStrings(left, oper.operator, expr.finalRightOperand() as PtExpression) - } - - // TODO: RPN: add the other optimizations that BinaryExpression has, to avoid eval stack usage // any other expression if((leftDt in ByteDatatypes && rightDt !in ByteDatatypes) - || (leftDt in WordDatatypes && rightDt !in WordDatatypes)) + || (leftDt in WordDatatypes && rightDt !in WordDatatypes)) throw AssemblyError("operator ${oper.operator} left/right dt not identical: $leftDt $rightDt right=${expr.finalRightOperand()}") var depth=0 @@ -294,16 +303,50 @@ internal class ExpressionsAsmGen(private val program: PtProgram, private fun translateExpression(expr: PtBinaryExpression) { // Uses evalstack to evaluate the given expression. THIS IS SLOW AND SHOULD BE AVOIDED! require(!program.binaryExpressionsAreRPN) + if(translateSomewhatOptimized(expr.left, expr.operator, expr.right)) + return + val leftDt = expr.left.type val rightDt = expr.right.type - // see if we can apply some optimized routines still - when(expr.operator) { + + // compare with zero + if(expr.operator in ComparisonOperators) { + if(leftDt in NumericDatatypes && rightDt in NumericDatatypes) { + val rightVal = expr.right.asConstInteger() + if(rightVal==0) + return translateComparisonWithZero(expr.left, leftDt, expr.operator) + } + } + + if(leftDt==DataType.STR && rightDt==DataType.STR && expr.operator in ComparisonOperators) + return translateCompareStrings(expr.left, expr.operator, expr.right) + + if((leftDt in ByteDatatypes && rightDt !in ByteDatatypes) + || (leftDt in WordDatatypes && rightDt !in WordDatatypes)) + throw AssemblyError("binary operator ${expr.operator} left/right dt not identical") + + // the general, non-optimized cases + // TODO optimize more cases.... (or one day just don't use the evalstack at all anymore) + translateExpressionInternal(expr.left) + translateExpressionInternal(expr.right) + when (leftDt) { + in ByteDatatypes -> translateBinaryOperatorBytes(expr.operator, leftDt) + in WordDatatypes -> translateBinaryOperatorWords(expr.operator, leftDt) + DataType.FLOAT -> translateBinaryOperatorFloats(expr.operator) + else -> throw AssemblyError("non-numerical datatype") + } + } + + private fun translateSomewhatOptimized(left: PtExpression, operator: String, right: PtExpression): Boolean { + val leftDt = left.type + val rightDt = right.type + when(operator) { "+" -> { if(leftDt in IntegerDatatypes && rightDt in IntegerDatatypes) { - val leftVal = expr.left.asConstInteger() - val rightVal = expr.right.asConstInteger() + val leftVal = left.asConstInteger() + val rightVal = right.asConstInteger() if (leftVal!=null && leftVal in -4..4) { - translateExpressionInternal(expr.right) + translateExpressionInternal(right) if(rightDt in ByteDatatypes) { val incdec = if(leftVal<0) "dec" else "inc" repeat(leftVal.absoluteValue) { @@ -329,11 +372,11 @@ internal class ExpressionsAsmGen(private val program: PtProgram, } } } - return + return true } else if (rightVal!=null && rightVal in -4..4) { - translateExpressionInternal(expr.left) + translateExpressionInternal(left) if(leftDt in ByteDatatypes) { val incdec = if(rightVal<0) "dec" else "inc" repeat(rightVal.absoluteValue) { @@ -359,16 +402,16 @@ internal class ExpressionsAsmGen(private val program: PtProgram, } } } - return + return true } } } "-" -> { if(leftDt in IntegerDatatypes && rightDt in IntegerDatatypes) { - val rightVal = expr.right.asConstInteger() + val rightVal = right.asConstInteger() if (rightVal!=null && rightVal in -4..4) { - translateExpressionInternal(expr.left) + translateExpressionInternal(left) if(leftDt in ByteDatatypes) { val incdec = if(rightVal<0) "inc" else "dec" repeat(rightVal.absoluteValue) { @@ -394,14 +437,14 @@ internal class ExpressionsAsmGen(private val program: PtProgram, } } } - return + return true } } } ">>" -> { - val amount = expr.right.asConstInteger() + val amount = right.asConstInteger() if(amount!=null) { - translateExpressionInternal(expr.left) + translateExpressionInternal(left) when (leftDt) { DataType.UBYTE -> { if (amount <= 2) @@ -427,7 +470,7 @@ internal class ExpressionsAsmGen(private val program: PtProgram, asmgen.out(" stz P8ESTACK_LO+1,x | stz P8ESTACK_HI+1,x") else asmgen.out(" lda #0 | sta P8ESTACK_LO+1,x | sta P8ESTACK_HI+1,x") - return + return true } var left = amount while (left >= 7) { @@ -452,7 +495,7 @@ internal class ExpressionsAsmGen(private val program: PtProgram, sta P8ESTACK_LO+1,x sta P8ESTACK_HI+1,x +""") - return + return true } var left = amount while (left >= 7) { @@ -466,13 +509,13 @@ internal class ExpressionsAsmGen(private val program: PtProgram, } else -> throw AssemblyError("weird type") } - return + return true } } "<<" -> { - val amount = expr.right.asConstInteger() + val amount = right.asConstInteger() if(amount!=null) { - translateExpressionInternal(expr.left) + translateExpressionInternal(left) if (leftDt in ByteDatatypes) { if (amount <= 2) repeat(amount) { asmgen.out(" asl P8ESTACK_LO+1,x") } @@ -492,68 +535,70 @@ internal class ExpressionsAsmGen(private val program: PtProgram, else asmgen.out(" jsr math.shift_left_w_$left") } - return + return true } } "*" -> { if(leftDt in IntegerDatatypes && rightDt in IntegerDatatypes) { - val leftVar = expr.left as? PtIdentifier - val rightVar = expr.right as? PtIdentifier - if(leftVar!=null && rightVar!=null && leftVar==rightVar) - return translateSquared(leftVar, leftDt) + val leftVar = left as? PtIdentifier + val rightVar = right as? PtIdentifier + if(leftVar!=null && rightVar!=null && leftVar==rightVar) { + translateSquared(leftVar, leftDt) + return true + } } - val value = expr.right as? PtNumber + val value = right as? PtNumber if(value!=null) { if(rightDt in IntegerDatatypes) { val amount = value.number.toInt() if(amount==2) { // optimize x*2 common case - translateExpressionInternal(expr.left) + translateExpressionInternal(left) if(leftDt in ByteDatatypes) { asmgen.out(" asl P8ESTACK_LO+1,x") } else { asmgen.out(" asl P8ESTACK_LO+1,x | rol P8ESTACK_HI+1,x") } - return + return true } when(rightDt) { DataType.UBYTE -> { if(amount in asmgen.optimizedByteMultiplications) { - translateExpressionInternal(expr.left) + translateExpressionInternal(left) asmgen.out(" jsr math.stack_mul_byte_$amount") - return + return true } } DataType.BYTE -> { if(amount in asmgen.optimizedByteMultiplications) { - translateExpressionInternal(expr.left) + translateExpressionInternal(left) asmgen.out(" jsr math.stack_mul_byte_$amount") - return + return true } if(amount.absoluteValue in asmgen.optimizedByteMultiplications) { - translateExpressionInternal(expr.left) + translateExpressionInternal(left) asmgen.out(" jsr prog8_lib.neg_b | jsr math.stack_mul_byte_${amount.absoluteValue}") - return + return true } } DataType.UWORD -> { if(amount in asmgen.optimizedWordMultiplications) { - translateExpressionInternal(expr.left) + translateExpressionInternal(left) asmgen.out(" jsr math.stack_mul_word_$amount") - return + return true } } DataType.WORD -> { if(amount in asmgen.optimizedWordMultiplications) { - translateExpressionInternal(expr.left) + translateExpressionInternal(left) asmgen.out(" jsr math.stack_mul_word_$amount") - return + return true } if(amount.absoluteValue in asmgen.optimizedWordMultiplications) { - translateExpressionInternal(expr.left) + translateExpressionInternal(left) asmgen.out(" jsr prog8_lib.neg_w | jsr math.stack_mul_word_${amount.absoluteValue}") - return + return true } } else -> {} @@ -563,9 +608,9 @@ internal class ExpressionsAsmGen(private val program: PtProgram, } "/" -> { if(leftDt in IntegerDatatypes && rightDt in IntegerDatatypes) { - val rightVal = expr.right.asConstInteger() + val rightVal = right.asConstInteger() if(rightVal!=null && rightVal==2) { - translateExpressionInternal(expr.left) + translateExpressionInternal(left) when (leftDt) { DataType.UBYTE -> { asmgen.out(" lsr P8ESTACK_LO+1,x") @@ -598,38 +643,13 @@ internal class ExpressionsAsmGen(private val program: PtProgram, } else -> throw AssemblyError("weird dt") } - return + return true } } } - in ComparisonOperators -> { - if(leftDt in NumericDatatypes && rightDt in NumericDatatypes) { - val rightVal = expr.right.asConstInteger() - if(rightVal==0) - return translateComparisonWithZero(expr.left, leftDt, expr.operator) - } - } } - if((leftDt in ByteDatatypes && rightDt !in ByteDatatypes) - || (leftDt in WordDatatypes && rightDt !in WordDatatypes)) - throw AssemblyError("binary operator ${expr.operator} left/right dt not identical") - - if(leftDt==DataType.STR && rightDt==DataType.STR && expr.operator in ComparisonOperators) { - translateCompareStrings(expr.left, expr.operator, expr.right) - } - else { - // the general, non-optimized cases - // TODO optimize more cases.... (or one day just don't use the evalstack at all anymore) - translateExpressionInternal(expr.left) - translateExpressionInternal(expr.right) - when (leftDt) { - in ByteDatatypes -> translateBinaryOperatorBytes(expr.operator, leftDt) - in WordDatatypes -> translateBinaryOperatorWords(expr.operator, leftDt) - DataType.FLOAT -> translateBinaryOperatorFloats(expr.operator) - else -> throw AssemblyError("non-numerical datatype") - } - } + return false } private fun translateComparisonWithZero(expr: PtExpression, dt: DataType, operator: String) {