mirror of
https://github.com/irmen/prog8.git
synced 2024-11-27 03:50:27 +00:00
expression splitter integrated into expression simplifier
This commit is contained in:
parent
3994de77d0
commit
5fb714fcb2
@ -190,10 +190,9 @@ private fun optimizeAst(programAst: Program, errors: ErrorReporter) {
|
|||||||
// keep optimizing expressions and statements until no more steps remain
|
// keep optimizing expressions and statements until no more steps remain
|
||||||
val optsDone1 = programAst.simplifyExpressions()
|
val optsDone1 = programAst.simplifyExpressions()
|
||||||
val optsDone2 = programAst.optimizeStatements(errors)
|
val optsDone2 = programAst.optimizeStatements(errors)
|
||||||
val optsDone3 = programAst.splitExpressions()
|
|
||||||
programAst.constantFold(errors) // because simplified statements and expressions can result in more constants that can be folded away
|
programAst.constantFold(errors) // because simplified statements and expressions can result in more constants that can be folded away
|
||||||
errors.handle()
|
errors.handle()
|
||||||
if (optsDone1 + optsDone2 + optsDone3 == 0)
|
if (optsDone1 + optsDone2 == 0)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,7 +219,7 @@ private fun writeAssembly(programAst: Program, errors: ErrorReporter, outputDir:
|
|||||||
programAst.processAstBeforeAsmGeneration(errors)
|
programAst.processAstBeforeAsmGeneration(errors)
|
||||||
errors.handle()
|
errors.handle()
|
||||||
|
|
||||||
printAst(programAst) // TODO
|
// printAst(programAst)
|
||||||
|
|
||||||
CompilationTarget.instance.machine.initializeZeropage(compilerOptions)
|
CompilationTarget.instance.machine.initializeZeropage(compilerOptions)
|
||||||
val assembly = CompilationTarget.instance.asmGenerator(
|
val assembly = CompilationTarget.instance.asmGenerator(
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
package prog8.optimizer
|
package prog8.optimizer
|
||||||
|
|
||||||
|
import prog8.ast.INameScope
|
||||||
import prog8.ast.Node
|
import prog8.ast.Node
|
||||||
import prog8.ast.Program
|
import prog8.ast.Program
|
||||||
import prog8.ast.base.*
|
import prog8.ast.base.*
|
||||||
import prog8.ast.expressions.*
|
import prog8.ast.expressions.*
|
||||||
import prog8.ast.processing.AstWalker
|
import prog8.ast.processing.AstWalker
|
||||||
import prog8.ast.processing.IAstModification
|
import prog8.ast.processing.IAstModification
|
||||||
|
import prog8.ast.statements.AssignTarget
|
||||||
|
import prog8.ast.statements.Assignment
|
||||||
|
import prog8.ast.statements.VarDecl
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
import kotlin.math.log2
|
import kotlin.math.log2
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
@ -275,6 +279,81 @@ internal class ExpressionSimplifier(private val program: Program) : AstWalker()
|
|||||||
return noModifications
|
return noModifications
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
|
||||||
|
// TODO somehow if we do this, the resulting code for some programs (cube3d.p8) gets hundreds of bytes larger...:
|
||||||
|
// if(decl.type==VarDeclType.VAR ) {
|
||||||
|
// val binExpr = decl.value as? BinaryExpression
|
||||||
|
// if (binExpr != null && binExpr.operator in augmentAssignmentOperators) {
|
||||||
|
// // split into a vardecl with just the left expression, and an aug. assignment with the right expression.
|
||||||
|
// val augExpr = BinaryExpression(IdentifierReference(listOf(decl.name), decl.position), binExpr.operator, binExpr.right, binExpr.position)
|
||||||
|
// val target = AssignTarget(IdentifierReference(listOf(decl.name), decl.position), null, null, decl.position)
|
||||||
|
// val assign = Assignment(target, augExpr, binExpr.position)
|
||||||
|
// println("SPLIT VARDECL $decl")
|
||||||
|
// return listOf(
|
||||||
|
// IAstModification.SetExpression({ decl.value = it }, binExpr.left, decl),
|
||||||
|
// IAstModification.InsertAfter(decl, assign, parent)
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return noModifications
|
||||||
|
// }
|
||||||
|
|
||||||
|
override fun after(assignment: Assignment, parent: Node): Iterable<IAstModification> {
|
||||||
|
|
||||||
|
val binExpr = assignment.value as? BinaryExpression
|
||||||
|
if (binExpr != 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 = BinExpr X = LeftExpr
|
||||||
|
<operator> followed by
|
||||||
|
/ \ IF 'X' not used X = BinExpr
|
||||||
|
/ \ IN LEFTEXPR ==> <operator>
|
||||||
|
/ \ / \
|
||||||
|
LeftExpr. RightExpr. / \
|
||||||
|
/ \ / \ X RightExpr.
|
||||||
|
.. .. .. ..
|
||||||
|
|
||||||
|
*/
|
||||||
|
if(binExpr.operator in augmentAssignmentOperators && isSimpleTarget(assignment.target, program.namespace)) {
|
||||||
|
if (!assignment.isAugmentable) {
|
||||||
|
val firstAssign = Assignment(assignment.target, binExpr.left, binExpr.left.position)
|
||||||
|
val targetExpr = assignment.target.toExpression()
|
||||||
|
val augExpr = BinaryExpression(targetExpr, binExpr.operator, binExpr.right, binExpr.right.position)
|
||||||
|
println("SPLIT $assignment")
|
||||||
|
return listOf(
|
||||||
|
IAstModification.InsertBefore(assignment, firstAssign, parent),
|
||||||
|
IAstModification.ReplaceNode(assignment.value, augExpr, assignment))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO further unraveling of binary expression trees into flat statements.
|
||||||
|
// however this should probably be done in a more generic way to also service
|
||||||
|
// the expressiontrees that are not used in an assignment statement...
|
||||||
|
}
|
||||||
|
|
||||||
|
return noModifications
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
target.isInRegularRAM(namespace)
|
||||||
|
else
|
||||||
|
false
|
||||||
|
}
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun after(functionCall: FunctionCall, parent: Node): Iterable<IAstModification> {
|
override fun after(functionCall: FunctionCall, parent: Node): Iterable<IAstModification> {
|
||||||
if(functionCall.target.nameInSource == listOf("lsb")) {
|
if(functionCall.target.nameInSource == listOf("lsb")) {
|
||||||
val arg = functionCall.args[0]
|
val arg = functionCall.args[0]
|
||||||
|
@ -1,91 +0,0 @@
|
|||||||
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
|
|
||||||
import prog8.ast.statements.VarDecl
|
|
||||||
|
|
||||||
class ExpressionSplitter(private val program: Program) : AstWalker() {
|
|
||||||
|
|
||||||
// TODO once this works, integrate it back into expressionsimplifier
|
|
||||||
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
|
|
||||||
|
|
||||||
// TODO somehow if we do this, the resulting code for some programs (cube3d.p8) gets hundreds of bytes larger...:
|
|
||||||
// if(decl.type==VarDeclType.VAR ) {
|
|
||||||
// val binExpr = decl.value as? BinaryExpression
|
|
||||||
// if (binExpr != null && binExpr.operator in augmentAssignmentOperators) {
|
|
||||||
// // split into a vardecl with just the left expression, and an aug. assignment with the right expression.
|
|
||||||
// val augExpr = BinaryExpression(IdentifierReference(listOf(decl.name), decl.position), binExpr.operator, binExpr.right, binExpr.position)
|
|
||||||
// val target = AssignTarget(IdentifierReference(listOf(decl.name), decl.position), null, null, decl.position)
|
|
||||||
// val assign = Assignment(target, augExpr, binExpr.position)
|
|
||||||
// println("SPLIT VARDECL $decl")
|
|
||||||
// return listOf(
|
|
||||||
// IAstModification.SetExpression({ decl.value = it }, binExpr.left, decl),
|
|
||||||
// IAstModification.InsertAfter(decl, assign, parent)
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
return emptyList()
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO once this works, integrate it back into expressionsimplifier
|
|
||||||
override fun after(assignment: Assignment, parent: Node): Iterable<IAstModification> {
|
|
||||||
|
|
||||||
val binExpr = assignment.value as? BinaryExpression
|
|
||||||
if (binExpr != 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 = BinExpr X = LeftExpr
|
|
||||||
<operator> followed by
|
|
||||||
/ \ IF 'X' not used X = BinExpr
|
|
||||||
/ \ IN LEFTEXPR ==> <operator>
|
|
||||||
/ \ / \
|
|
||||||
LeftExpr. RightExpr. / \
|
|
||||||
/ \ / \ X RightExpr.
|
|
||||||
.. .. .. ..
|
|
||||||
|
|
||||||
*/
|
|
||||||
if(binExpr.operator in augmentAssignmentOperators && isSimpleTarget(assignment.target, program.namespace)) {
|
|
||||||
if (!assignment.isAugmentable) {
|
|
||||||
val firstAssign = Assignment(assignment.target, binExpr.left, binExpr.left.position)
|
|
||||||
val targetExpr = assignment.target.toExpression()
|
|
||||||
val augExpr = BinaryExpression(targetExpr, binExpr.operator, binExpr.right, binExpr.right.position)
|
|
||||||
return listOf(
|
|
||||||
IAstModification.InsertBefore(assignment, firstAssign, parent),
|
|
||||||
IAstModification.ReplaceNode(assignment.value, augExpr, assignment))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO further unraveling of binary expression trees into flat statements.
|
|
||||||
// however this should probably be done in a more generic way to also service
|
|
||||||
// the expressiontrees that are not used in an assignment statement...
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
target.isInRegularRAM(namespace)
|
|
||||||
else
|
|
||||||
false
|
|
||||||
}
|
|
||||||
else -> false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -53,10 +53,3 @@ internal fun Program.simplifyExpressions() : Int {
|
|||||||
opti.visit(this)
|
opti.visit(this)
|
||||||
return opti.applyModifications()
|
return opti.applyModifications()
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun Program.splitExpressions() : Int {
|
|
||||||
val splitter = ExpressionSplitter(this)
|
|
||||||
splitter.visit(this)
|
|
||||||
return splitter.applyModifications()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user