added some more constant foldings

This commit is contained in:
Irmen de Jong 2018-09-27 01:35:35 +02:00
parent 6681787288
commit 5e729e21ff
6 changed files with 124 additions and 20 deletions

View File

@ -14,8 +14,8 @@
float yy float yy
float x float x
float y float y
float xsq float xsquared
float ysq float ysquared
byte iter byte iter
word plotx word plotx
byte ploty byte ploty
@ -24,21 +24,21 @@
_vm_gfx_text(5, 5, 7, "Calculating Mandelbrot Fractal...") _vm_gfx_text(5, 5, 7, "Calculating Mandelbrot Fractal...")
for pixely in yoffset to yoffset+height-1 { for pixely in yoffset to yoffset+height-1 {
yy = flt((pixely-yoffset))/height/3.6+0.4 ; @todo why is /height/3.6 not const-folded??? yy = flt((pixely-yoffset))/height/3.6+0.4
for pixelx in xoffset to xoffset+width-1 { for pixelx in xoffset to xoffset+width-1 {
xx = flt((pixelx-xoffset))/width/3+0.2 ; @todo why is /width/3 not const-folded??? xx = flt((pixelx-xoffset))/width/3+0.2
x = 0.0 x = 0.0
y = 0.0 y = 0.0
xsq = 0 xsquared = 0
ysq = 0 ysquared = 0
iter = 0 iter = 0
while (iter<32 and xsq+ysq<4) { while (iter<32 and xsquared+ysquared<4) {
y = x*y*2 + yy y = x*y*2 + yy
x = xsq - ysq + xx x = xsquared - ysquared + xx
xsq = x*x xsquared = x*x
ysq = y*y ysquared = y*y
iter++ iter++
} }

View File

@ -4,15 +4,21 @@
sub start() -> () { sub start() -> () {
const word yoffset=100
const float height=20.2
word pixely word pixely
float yy
float v
pixely = A % 0 ; @todo divide 0 yy = 11.0-(v-22.0)
pixely = A / 0 ; @todo divide 0 yy = 11.0-(22.0-v)
pixely = A // 0 ; @todo divide 0 yy = (v-22.0)-11.0
yy = (22.0-v)-11.0
pixely |= 1 ; pixely = pixely | 1 yy = 11.0/(v/22.0)
pixely &= 1 ; pixely = pixely & 1 yy = 11.0/(22.0/v)
pixely ^= 1 ; pixely = pixely ^ 1 yy = (v/22.0)/11.0
yy = (22.0/v)/11.0
} }
} }

View File

@ -709,7 +709,7 @@ class PrefixExpression(val operator: String, var expression: IExpression, overri
} }
class BinaryExpression(var left: IExpression, val operator: String, var right: IExpression, override val position: Position) : IExpression { class BinaryExpression(var left: IExpression, var operator: String, var right: IExpression, override val position: Position) : IExpression {
override lateinit var parent: Node override lateinit var parent: Node
override fun linkParents(parent: Node) { override fun linkParents(parent: Node) {

View File

@ -3,6 +3,10 @@ package prog8.optimizing
import prog8.ast.* import prog8.ast.*
import kotlin.math.pow import kotlin.math.pow
val associativeOperators = setOf("+", "*", "&", "|", "^", "or", "and", "xor", "==", "!=")
class ConstExprEvaluator { class ConstExprEvaluator {
fun evaluate(left: LiteralValue, operator: String, right: LiteralValue): IExpression { fun evaluate(left: LiteralValue, operator: String, right: LiteralValue): IExpression {

View File

@ -171,14 +171,49 @@ class ConstantFolding(private val namespace: INameScope) : IAstProcessor {
* Try to process a binary expression. * Try to process a binary expression.
* Compile-time constant sub expressions will be evaluated on the spot. * Compile-time constant sub expressions will be evaluated on the spot.
* For instance, "9 * (4 + 2)" will be optimized into the integer literal 54. * For instance, "9 * (4 + 2)" will be optimized into the integer literal 54.
*
* More complex: dealing with associative operators:
* if our operator is +,-,*,/ THEN:
* if one of our operands is a const, THEN:
* if the other operand is also a binary expression THEN:
* if its operator is in the same group as our operator (+ and -, * and /) THEN:
* if one of its operands is a const THEN:
* reorder the expression by lifting out the calculation on the 2 consts. (so that it can be const-folded later)
*/ */
override fun process(expr: BinaryExpression): IExpression { override fun process(expr: BinaryExpression): IExpression {
return try { return try {
super.process(expr) super.process(expr)
val evaluator = ConstExprEvaluator()
val leftconst = expr.left.constValue(namespace) val leftconst = expr.left.constValue(namespace)
val rightconst = expr.right.constValue(namespace) val rightconst = expr.right.constValue(namespace)
// check associative operators and const operands
if(setOf("+", "-", "*", "/").contains(expr.operator)) {
val subExpr: BinaryExpression? = when {
leftconst!=null -> expr.right as? BinaryExpression
rightconst!=null -> expr.left as? BinaryExpression
else -> null
}
if(subExpr!=null) {
val sameGroupOperator =
when (expr.operator) {
"+", "-" -> subExpr.operator == "+" || subExpr.operator == "-"
"*", "/" -> subExpr.operator == "*" || subExpr.operator == "/"
else -> false
}
if (sameGroupOperator) {
val subleftconst = subExpr.left.constValue(namespace)
val subrightconst = subExpr.right.constValue(namespace)
if (subleftconst != null || subrightconst != null) {
// reorder!
return reorderAssociativeConst(expr, subExpr, leftconst!=null, rightconst!=null, subleftconst!=null, subrightconst!=null)
}
}
}
}
// const fold when both operands are a const
val evaluator = ConstExprEvaluator()
return when { return when {
leftconst != null && rightconst != null -> { leftconst != null && rightconst != null -> {
optimizationsDone++ optimizationsDone++
@ -192,6 +227,66 @@ class ConstantFolding(private val namespace: INameScope) : IAstProcessor {
} }
} }
private fun reorderAssociativeConst(expr: BinaryExpression,
subExpr: BinaryExpression,
leftIsConst: Boolean,
rightIsConst: Boolean,
subleftIsConst: Boolean,
subrightIsConst: Boolean): IExpression {
if(expr.operator==subExpr.operator) {
// both operators are the same.
// If + or *, we can simply swap the const of expr and Var in subexpr.
if(expr.operator=="+" || expr.operator=="*") {
if(leftIsConst) {
if(subleftIsConst)
expr.left = subExpr.right.also { subExpr.right = expr.left }
else
expr.left = subExpr.left.also { subExpr.left = expr.left }
} else {
if(subleftIsConst)
expr.right = subExpr.right.also {subExpr.right = expr.right }
else
expr.right = subExpr.left.also { subExpr.left = expr.right }
}
optimizationsDone++
return expr
}
// If - or /, we simetimes must reorder more, and flip operators (- -> +, / -> *)
if(expr.operator=="-" || expr.operator=="/") {
optimizationsDone++
if(leftIsConst) {
if(subleftIsConst) {
val tmp = subExpr.right
subExpr.right = subExpr.left
subExpr.left = expr.left
expr.left = tmp
expr.operator = if(expr.operator=="-") "+" else "*"
} else
return BinaryExpression(
BinaryExpression(expr.left, if(expr.operator=="-") "+" else "*", subExpr.right, subExpr.position),
expr.operator, subExpr.left, expr.position)
} else {
if(subleftIsConst)
expr.right = subExpr.right.also {subExpr.right = expr.right}
else
return BinaryExpression(
subExpr.left, expr.operator,
BinaryExpression(expr.right, if(expr.operator=="-") "+" else "*", subExpr.right, subExpr.position),
expr.position)
}
return expr
}
// todo: other combinations of operators and constants
return expr
} else {
return expr // TODO reorder when operators are not identical
}
}
override fun process(range: RangeExpr): IExpression { override fun process(range: RangeExpr): IExpression {
range.from = range.from.process(this) range.from = range.from.process(this)
range.to = range.to.process(this) range.to = range.to.process(this)

View File

@ -115,7 +115,6 @@ class SimplifyExpressions(private val namespace: INameScope) : IAstProcessor {
private data class ReorderedAssociativeBinaryExpr(val expr: BinaryExpression, val leftVal: LiteralValue?, val rightVal: LiteralValue?) private data class ReorderedAssociativeBinaryExpr(val expr: BinaryExpression, val leftVal: LiteralValue?, val rightVal: LiteralValue?)
private fun reorderAssociative(expr: BinaryExpression, leftVal: LiteralValue?): ReorderedAssociativeBinaryExpr { private fun reorderAssociative(expr: BinaryExpression, leftVal: LiteralValue?): ReorderedAssociativeBinaryExpr {
val associativeOperators = setOf("+", "*", "&", "|", "^", "or", "and", "xor", "==", "!=")
if(associativeOperators.contains(expr.operator) && leftVal!=null) { if(associativeOperators.contains(expr.operator) && leftVal!=null) {
// swap left and right so that right is always the constant // swap left and right so that right is always the constant
val tmp = expr.left val tmp = expr.left