mirror of
https://github.com/irmen/prog8.git
synced 2024-10-25 00:24:16 +00:00
more rpn optimization
This commit is contained in:
parent
7b802bfd3d
commit
84b31e65e1
@ -247,26 +247,35 @@ 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) {
|
||||||
return translateComparisonWithZero(left, leftDt, oper.operator)
|
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
|
// 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)
|
||||||
@ -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) {
|
||||||
|
Loading…
Reference in New Issue
Block a user