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) { private fun translateRpnExpression(expr: PtRpn) {
// Uses evalstack to evaluate the given expression. THIS IS SLOW AND SHOULD BE AVOIDED! // Uses evalstack to evaluate the given expression. THIS IS SLOW AND SHOULD BE AVOIDED!
val oper = expr.finalOperator() val (left, oper, right) = expr.finalOperation()
val left = expr.finalLeftOperand() as? PtExpression if(left is PtExpression && right is PtExpression && translateSomewhatOptimized(left, oper.operator, right))
return
val leftDt = oper.leftType val leftDt = oper.leftType
val rightDt = oper.rightType val rightDt = oper.rightType
// comparison against zero // comparison with zero
if(left != null && oper.operator in ComparisonOperators) { if(oper.operator in ComparisonOperators && leftDt in NumericDatatypes && rightDt in NumericDatatypes) {
if(leftDt in NumericDatatypes && rightDt in NumericDatatypes) { val rightVal = (expr.finalRightOperand() as PtExpression).asConstInteger()
val rightVal = (expr.finalRightOperand() as PtExpression).asConstInteger() if (rightVal == 0) {
if(rightVal==0) when (left) {
return translateComparisonWithZero(left, leftDt, oper.operator) 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 // 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) 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 // any other expression
if((leftDt in ByteDatatypes && rightDt !in ByteDatatypes) 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()}") throw AssemblyError("operator ${oper.operator} left/right dt not identical: $leftDt $rightDt right=${expr.finalRightOperand()}")
var depth=0 var depth=0
@ -294,16 +303,50 @@ internal class ExpressionsAsmGen(private val program: PtProgram,
private fun translateExpression(expr: PtBinaryExpression) { private fun translateExpression(expr: PtBinaryExpression) {
// Uses evalstack to evaluate the given expression. THIS IS SLOW AND SHOULD BE AVOIDED! // Uses evalstack to evaluate the given expression. THIS IS SLOW AND SHOULD BE AVOIDED!
require(!program.binaryExpressionsAreRPN) require(!program.binaryExpressionsAreRPN)
if(translateSomewhatOptimized(expr.left, expr.operator, expr.right))
return
val leftDt = expr.left.type val leftDt = expr.left.type
val rightDt = expr.right.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) { if(leftDt in IntegerDatatypes && rightDt in IntegerDatatypes) {
val leftVal = expr.left.asConstInteger() val leftVal = left.asConstInteger()
val rightVal = expr.right.asConstInteger() val rightVal = right.asConstInteger()
if (leftVal!=null && leftVal in -4..4) { if (leftVal!=null && leftVal in -4..4) {
translateExpressionInternal(expr.right) translateExpressionInternal(right)
if(rightDt in ByteDatatypes) { if(rightDt in ByteDatatypes) {
val incdec = if(leftVal<0) "dec" else "inc" val incdec = if(leftVal<0) "dec" else "inc"
repeat(leftVal.absoluteValue) { 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) else if (rightVal!=null && rightVal in -4..4)
{ {
translateExpressionInternal(expr.left) translateExpressionInternal(left)
if(leftDt in ByteDatatypes) { if(leftDt in ByteDatatypes) {
val incdec = if(rightVal<0) "dec" else "inc" val incdec = if(rightVal<0) "dec" else "inc"
repeat(rightVal.absoluteValue) { repeat(rightVal.absoluteValue) {
@ -359,16 +402,16 @@ internal class ExpressionsAsmGen(private val program: PtProgram,
} }
} }
} }
return return true
} }
} }
} }
"-" -> { "-" -> {
if(leftDt in IntegerDatatypes && rightDt in IntegerDatatypes) { if(leftDt in IntegerDatatypes && rightDt in IntegerDatatypes) {
val rightVal = expr.right.asConstInteger() val rightVal = right.asConstInteger()
if (rightVal!=null && rightVal in -4..4) if (rightVal!=null && rightVal in -4..4)
{ {
translateExpressionInternal(expr.left) translateExpressionInternal(left)
if(leftDt in ByteDatatypes) { if(leftDt in ByteDatatypes) {
val incdec = if(rightVal<0) "inc" else "dec" val incdec = if(rightVal<0) "inc" else "dec"
repeat(rightVal.absoluteValue) { 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) { if(amount!=null) {
translateExpressionInternal(expr.left) translateExpressionInternal(left)
when (leftDt) { when (leftDt) {
DataType.UBYTE -> { DataType.UBYTE -> {
if (amount <= 2) 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") asmgen.out(" stz P8ESTACK_LO+1,x | stz P8ESTACK_HI+1,x")
else else
asmgen.out(" lda #0 | sta P8ESTACK_LO+1,x | sta P8ESTACK_HI+1,x") asmgen.out(" lda #0 | sta P8ESTACK_LO+1,x | sta P8ESTACK_HI+1,x")
return return true
} }
var left = amount var left = amount
while (left >= 7) { while (left >= 7) {
@ -452,7 +495,7 @@ internal class ExpressionsAsmGen(private val program: PtProgram,
sta P8ESTACK_LO+1,x sta P8ESTACK_LO+1,x
sta P8ESTACK_HI+1,x sta P8ESTACK_HI+1,x
+""") +""")
return return true
} }
var left = amount var left = amount
while (left >= 7) { while (left >= 7) {
@ -466,13 +509,13 @@ internal class ExpressionsAsmGen(private val program: PtProgram,
} }
else -> throw AssemblyError("weird type") else -> throw AssemblyError("weird type")
} }
return return true
} }
} }
"<<" -> { "<<" -> {
val amount = expr.right.asConstInteger() val amount = right.asConstInteger()
if(amount!=null) { if(amount!=null) {
translateExpressionInternal(expr.left) translateExpressionInternal(left)
if (leftDt in ByteDatatypes) { if (leftDt in ByteDatatypes) {
if (amount <= 2) if (amount <= 2)
repeat(amount) { asmgen.out(" asl P8ESTACK_LO+1,x") } repeat(amount) { asmgen.out(" asl P8ESTACK_LO+1,x") }
@ -492,68 +535,70 @@ internal class ExpressionsAsmGen(private val program: PtProgram,
else else
asmgen.out(" jsr math.shift_left_w_$left") asmgen.out(" jsr math.shift_left_w_$left")
} }
return return true
} }
} }
"*" -> { "*" -> {
if(leftDt in IntegerDatatypes && rightDt in IntegerDatatypes) { if(leftDt in IntegerDatatypes && rightDt in IntegerDatatypes) {
val leftVar = expr.left as? PtIdentifier val leftVar = left as? PtIdentifier
val rightVar = expr.right as? PtIdentifier val rightVar = right as? PtIdentifier
if(leftVar!=null && rightVar!=null && leftVar==rightVar) if(leftVar!=null && rightVar!=null && leftVar==rightVar) {
return translateSquared(leftVar, leftDt) translateSquared(leftVar, leftDt)
return true
}
} }
val value = expr.right as? PtNumber val value = right as? PtNumber
if(value!=null) { if(value!=null) {
if(rightDt in IntegerDatatypes) { if(rightDt in IntegerDatatypes) {
val amount = value.number.toInt() val amount = value.number.toInt()
if(amount==2) { if(amount==2) {
// optimize x*2 common case // optimize x*2 common case
translateExpressionInternal(expr.left) translateExpressionInternal(left)
if(leftDt in ByteDatatypes) { if(leftDt in ByteDatatypes) {
asmgen.out(" asl P8ESTACK_LO+1,x") asmgen.out(" asl P8ESTACK_LO+1,x")
} else { } else {
asmgen.out(" asl P8ESTACK_LO+1,x | rol P8ESTACK_HI+1,x") asmgen.out(" asl P8ESTACK_LO+1,x | rol P8ESTACK_HI+1,x")
} }
return return true
} }
when(rightDt) { when(rightDt) {
DataType.UBYTE -> { DataType.UBYTE -> {
if(amount in asmgen.optimizedByteMultiplications) { if(amount in asmgen.optimizedByteMultiplications) {
translateExpressionInternal(expr.left) translateExpressionInternal(left)
asmgen.out(" jsr math.stack_mul_byte_$amount") asmgen.out(" jsr math.stack_mul_byte_$amount")
return return true
} }
} }
DataType.BYTE -> { DataType.BYTE -> {
if(amount in asmgen.optimizedByteMultiplications) { if(amount in asmgen.optimizedByteMultiplications) {
translateExpressionInternal(expr.left) translateExpressionInternal(left)
asmgen.out(" jsr math.stack_mul_byte_$amount") asmgen.out(" jsr math.stack_mul_byte_$amount")
return return true
} }
if(amount.absoluteValue in asmgen.optimizedByteMultiplications) { 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}") asmgen.out(" jsr prog8_lib.neg_b | jsr math.stack_mul_byte_${amount.absoluteValue}")
return return true
} }
} }
DataType.UWORD -> { DataType.UWORD -> {
if(amount in asmgen.optimizedWordMultiplications) { if(amount in asmgen.optimizedWordMultiplications) {
translateExpressionInternal(expr.left) translateExpressionInternal(left)
asmgen.out(" jsr math.stack_mul_word_$amount") asmgen.out(" jsr math.stack_mul_word_$amount")
return return true
} }
} }
DataType.WORD -> { DataType.WORD -> {
if(amount in asmgen.optimizedWordMultiplications) { if(amount in asmgen.optimizedWordMultiplications) {
translateExpressionInternal(expr.left) translateExpressionInternal(left)
asmgen.out(" jsr math.stack_mul_word_$amount") asmgen.out(" jsr math.stack_mul_word_$amount")
return return true
} }
if(amount.absoluteValue in asmgen.optimizedWordMultiplications) { 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}") asmgen.out(" jsr prog8_lib.neg_w | jsr math.stack_mul_word_${amount.absoluteValue}")
return return true
} }
} }
else -> {} else -> {}
@ -563,9 +608,9 @@ internal class ExpressionsAsmGen(private val program: PtProgram,
} }
"/" -> { "/" -> {
if(leftDt in IntegerDatatypes && rightDt in IntegerDatatypes) { if(leftDt in IntegerDatatypes && rightDt in IntegerDatatypes) {
val rightVal = expr.right.asConstInteger() val rightVal = right.asConstInteger()
if(rightVal!=null && rightVal==2) { if(rightVal!=null && rightVal==2) {
translateExpressionInternal(expr.left) translateExpressionInternal(left)
when (leftDt) { when (leftDt) {
DataType.UBYTE -> { DataType.UBYTE -> {
asmgen.out(" lsr P8ESTACK_LO+1,x") asmgen.out(" lsr P8ESTACK_LO+1,x")
@ -598,38 +643,13 @@ internal class ExpressionsAsmGen(private val program: PtProgram,
} }
else -> throw AssemblyError("weird dt") 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) return false
|| (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")
}
}
} }
private fun translateComparisonWithZero(expr: PtExpression, dt: DataType, operator: String) { private fun translateComparisonWithZero(expr: PtExpression, dt: DataType, operator: String) {