mirror of
https://github.com/irmen/prog8.git
synced 2025-02-07 09:30:54 +00:00
expression splitter moved to separate optimizer
This commit is contained in:
parent
95e9e1b550
commit
1464050bf5
@ -82,6 +82,7 @@ interface IAstModification {
|
||||
|
||||
class SwapOperands(val expr: BinaryExpression): IAstModification {
|
||||
override fun perform() {
|
||||
require(expr.operator in associativeOperators)
|
||||
val tmp = expr.left
|
||||
expr.left = expr.right
|
||||
expr.right = tmp
|
||||
@ -228,6 +229,7 @@ abstract class AstWalker {
|
||||
track(before(decl, parent), decl, parent)
|
||||
decl.value?.accept(this, decl)
|
||||
decl.arraysize?.accept(this, decl)
|
||||
decl.struct?.accept(this, decl)
|
||||
track(after(decl, parent), decl, parent)
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,7 @@ interface IAstVisitor {
|
||||
fun visit(decl: VarDecl) {
|
||||
decl.value?.accept(this)
|
||||
decl.arraysize?.accept(this)
|
||||
decl.struct?.accept(this)
|
||||
}
|
||||
|
||||
fun visit(subroutine: Subroutine) {
|
||||
|
@ -7,6 +7,7 @@ import prog8.ast.statements.Directive
|
||||
import prog8.compiler.target.C64Target
|
||||
import prog8.compiler.target.CompilationTarget
|
||||
import prog8.compiler.target.Cx16Target
|
||||
import prog8.optimizer.*
|
||||
import prog8.optimizer.UnusedCodeRemover
|
||||
import prog8.optimizer.constantFold
|
||||
import prog8.optimizer.optimizeStatements
|
||||
@ -189,9 +190,10 @@ private fun optimizeAst(programAst: Program, errors: ErrorReporter) {
|
||||
// keep optimizing expressions and statements until no more steps remain
|
||||
val optsDone1 = programAst.simplifyExpressions()
|
||||
val optsDone2 = programAst.optimizeStatements(errors)
|
||||
programAst.constantFold(errors) // because simplified statements and expressions could give rise to more constants that can be folded away
|
||||
val optsDone3 = programAst.splitExpressions()
|
||||
programAst.constantFold(errors) // because simplified statements and expressions can result in more constants that can be folded away
|
||||
errors.handle()
|
||||
if (optsDone1 + optsDone2 == 0)
|
||||
if (optsDone1 + optsDone2 + optsDone3 == 0)
|
||||
break
|
||||
}
|
||||
|
||||
|
65
compiler/src/prog8/optimizer/ExpressionSplitter.kt
Normal file
65
compiler/src/prog8/optimizer/ExpressionSplitter.kt
Normal file
@ -0,0 +1,65 @@
|
||||
package prog8.optimizer
|
||||
|
||||
import prog8.ast.INameScope
|
||||
import prog8.ast.Node
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.expressions.*
|
||||
import prog8.ast.processing.AstWalker
|
||||
import prog8.ast.processing.IAstModification
|
||||
import prog8.ast.statements.AssignTarget
|
||||
import prog8.ast.statements.Assignment
|
||||
|
||||
class ExpressionSplitter(private val program: Program) : AstWalker() {
|
||||
|
||||
// TODO once this works, integrate it back into expressionsimplifier
|
||||
override fun after(assignment: Assignment, parent: Node): Iterable<IAstModification> {
|
||||
|
||||
if(assignment!=null) {
|
||||
val expr = assignment.value as? BinaryExpression
|
||||
if (expr != null) {
|
||||
// reduce the complexity of a (binary) expression that has to be evaluated on the eval stack,
|
||||
// by attempting to splitting it up into individual simple steps:
|
||||
// X = <some-expression-not-X> <operator> <not-binary-expression>
|
||||
// or X = <not-binary-expression> <associativeoperator> <some-expression-not-X>
|
||||
// split that into X = <some-expression-not-X> ; X = X <operator> <not-binary-expression>
|
||||
|
||||
// TODO FIX THIS, IT SOMETIMES JUST LOOPS... (for example on plasma.p8)
|
||||
if (expr.operator !in comparisonOperators && !assignment.isAugmentable && isSimpleTarget(assignment.target, program.namespace)) {
|
||||
if (expr.right !is BinaryExpression) {
|
||||
println("SPLIT RIGHT BINEXPR $expr")
|
||||
val firstAssign = Assignment(assignment.target, expr.left, assignment.position)
|
||||
val augExpr = BinaryExpression(assignment.target.toExpression(), expr.operator, expr.right, expr.position)
|
||||
return listOf(
|
||||
IAstModification.InsertBefore(assignment, firstAssign, parent),
|
||||
IAstModification.ReplaceNode(assignment.value, augExpr, assignment)
|
||||
)
|
||||
} else if (expr.left !is BinaryExpression && expr.operator in associativeOperators) {
|
||||
println("SPLIT LEFT BINEXPR $expr")
|
||||
val firstAssign = Assignment(assignment.target, expr.right, assignment.position)
|
||||
val augExpr = BinaryExpression(assignment.target.toExpression(), expr.operator, expr.left, expr.position)
|
||||
return listOf(
|
||||
IAstModification.InsertBefore(assignment, firstAssign, parent),
|
||||
IAstModification.ReplaceNode(assignment.value, augExpr, assignment))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
private fun isSimpleTarget(target: AssignTarget, namespace: INameScope): Boolean {
|
||||
return when {
|
||||
target.identifier!=null -> target.isInRegularRAM(namespace)
|
||||
target.memoryAddress!=null -> target.isInRegularRAM(namespace)
|
||||
target.arrayindexed!=null -> {
|
||||
val index = target.arrayindexed!!.arrayspec.index
|
||||
if(index is NumericLiteralValue || index is IdentifierReference)
|
||||
target.isInRegularRAM(namespace)
|
||||
else
|
||||
false
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
@ -53,3 +53,10 @@ internal fun Program.simplifyExpressions() : Int {
|
||||
opti.visit(this)
|
||||
return opti.applyModifications()
|
||||
}
|
||||
|
||||
internal fun Program.splitExpressions() : Int {
|
||||
val opti = ExpressionSplitter(this)
|
||||
opti.visit(this)
|
||||
return opti.applyModifications()
|
||||
}
|
||||
|
||||
|
@ -436,43 +436,6 @@ internal class StatementOptimizer(private val program: Program,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun isSimpleTarget(target: AssignTarget, namespace: INameScope): Boolean {
|
||||
return when {
|
||||
target.identifier!=null -> target.isInRegularRAM(namespace)
|
||||
target.memoryAddress!=null -> target.isInRegularRAM(namespace)
|
||||
target.arrayindexed!=null -> {
|
||||
val index = target.arrayindexed!!.arrayspec.index
|
||||
if(index is NumericLiteralValue || index is IdentifierReference)
|
||||
target.isInRegularRAM(namespace)
|
||||
else
|
||||
false
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
// reduce the complexity of a (binary) expression that has to be evaluated on the eval stack,
|
||||
// by attempting to splitting it up into individual simple steps:
|
||||
// X = <some-expression-not-X> <operator> <not-binary-expression>
|
||||
// or X = <not-binary-expression> <associativeoperator> <some-expression-not-X>
|
||||
// split that into X = <some-expression-not-X> ; X = X <operator> <not-binary-expression>
|
||||
// TODO FIX THIS SPLITTING (IT ENDS UP IN A LOOP SOMETIMES)
|
||||
// if(bexpr.operator !in comparisonOperators && !assignment.isAugmentable && isSimpleTarget(assignment.target, program.namespace)) {
|
||||
// if (bexpr.right !is BinaryExpression) {
|
||||
// val firstAssign = Assignment(assignment.target, bexpr.left, assignment.position)
|
||||
// val augExpr = BinaryExpression(assignment.target.toExpression(), bexpr.operator, bexpr.right, bexpr.position)
|
||||
// return listOf(
|
||||
// IAstModification.InsertBefore(assignment, firstAssign, parent),
|
||||
// IAstModification.ReplaceNode(assignment.value, augExpr, assignment))
|
||||
// } else if (bexpr.left !is BinaryExpression && bexpr.operator in associativeOperators) {
|
||||
// val firstAssign = Assignment(assignment.target, bexpr.right, assignment.position)
|
||||
// val augExpr = BinaryExpression(assignment.target.toExpression(), bexpr.operator, bexpr.left, bexpr.position)
|
||||
// return listOf(
|
||||
// IAstModification.InsertBefore(assignment, firstAssign, parent),
|
||||
// IAstModification.ReplaceNode(assignment.value, augExpr, assignment))
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
return noModifications
|
||||
|
@ -4,14 +4,11 @@ import prog8.ast.INameScope
|
||||
import prog8.ast.Node
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.base.ErrorReporter
|
||||
import prog8.ast.expressions.NumericLiteralValue
|
||||
import prog8.ast.processing.AstWalker
|
||||
import prog8.ast.processing.IAstModification
|
||||
import prog8.ast.statements.*
|
||||
|
||||
|
||||
// TODO remove unneeded assignments such as: cc = 0 ; cc= xbuf ; ... the first can be removed (unless target is not RAM)
|
||||
|
||||
internal class UnusedCodeRemover(private val program: Program, private val errors: ErrorReporter): AstWalker() {
|
||||
|
||||
override fun before(program: Program, parent: Node): Iterable<IAstModification> {
|
||||
@ -86,15 +83,14 @@ internal class UnusedCodeRemover(private val program: Program, private val error
|
||||
return removeDoubleAssignments.map { IAstModification.Remove(it, subroutine) }
|
||||
}
|
||||
|
||||
// subroutine, anonscope,
|
||||
private fun deduplicateAssignments(statements: List<Statement>): List<Assignment> {
|
||||
// removes 'duplicate' assignments that assign the isSameAs target
|
||||
// removes 'duplicate' assignments that assign the same target directly after another
|
||||
val linesToRemove = mutableListOf<Assignment>()
|
||||
|
||||
for (stmtPairs in statements.windowed(2, step = 1)) {
|
||||
val assign1 = stmtPairs[0] as? Assignment
|
||||
val assign2 = stmtPairs[1] as? Assignment
|
||||
if (assign1 != null && assign2 != null) {
|
||||
if (assign1 != null && assign2 != null && !assign2.isAugmentable) {
|
||||
if (assign1.target.isSameAs(assign2.target, program) && assign1.target.isInRegularRAM(program.namespace))
|
||||
linesToRemove.add(assign1)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user