more rpn optimization

This commit is contained in:
Irmen de Jong 2023-03-18 14:23:17 +01:00
parent 7b802bfd3d
commit 84b31e65e1

View File

@ -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) {