preparing optimization plan for if statements

This commit is contained in:
Irmen de Jong
2021-04-12 02:10:54 +02:00
parent ae1b62e147
commit 0a03c46351
6 changed files with 46 additions and 25 deletions

View File

@@ -65,7 +65,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
if(rightConstVal?.number?.toDouble() == 0.0) { if(rightConstVal?.number?.toDouble() == 0.0) {
if(dt in ByteDatatypes) { if(dt in ByteDatatypes) {
asmgen.assignExpressionToRegister(left, RegisterOrPair.A) asmgen.assignExpressionToRegister(left, RegisterOrPair.A)
if(left is FunctionCall) if(left is FunctionCall && !left.isSimple)
asmgen.out(" cmp #0") asmgen.out(" cmp #0")
asmgen.out(" bne $jumpIfFalseLabel") asmgen.out(" bne $jumpIfFalseLabel")
return return
@@ -94,7 +94,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
if(rightConstVal?.number?.toDouble() == 0.0) { if(rightConstVal?.number?.toDouble() == 0.0) {
if(dt in ByteDatatypes) { if(dt in ByteDatatypes) {
asmgen.assignExpressionToRegister(left, RegisterOrPair.A) asmgen.assignExpressionToRegister(left, RegisterOrPair.A)
if(left is FunctionCall) if(left is FunctionCall && !left.isSimple)
asmgen.out(" cmp #0") asmgen.out(" cmp #0")
asmgen.out(" beq $jumpIfFalseLabel") asmgen.out(" beq $jumpIfFalseLabel")
return return

View File

@@ -57,7 +57,7 @@ X = BinExpr X = LeftExpr
if(assignment.target isSameAs binExpr.left || assignment.target isSameAs binExpr.right) if(assignment.target isSameAs binExpr.left || assignment.target isSameAs binExpr.right)
return noModifications return noModifications
if(isSimpleExpression(binExpr.right) && !assignment.isAugmentable) { if(binExpr.right.isSimple && !assignment.isAugmentable) {
val firstAssign = Assignment(assignment.target.copy(), binExpr.left, binExpr.left.position) val firstAssign = Assignment(assignment.target.copy(), binExpr.left, binExpr.left.position)
val targetExpr = assignment.target.toExpression() val targetExpr = assignment.target.toExpression()
val augExpr = BinaryExpression(targetExpr, binExpr.operator, binExpr.right, binExpr.right.position) val augExpr = BinaryExpression(targetExpr, binExpr.operator, binExpr.right, binExpr.right.position)
@@ -76,9 +76,6 @@ X = BinExpr X = LeftExpr
return noModifications return noModifications
} }
private fun isSimpleExpression(expr: Expression) =
expr is IdentifierReference || expr is NumericLiteralValue || expr is AddressOf || expr is DirectMemoryRead || expr is StringLiteralValue || expr is ArrayLiteralValue || expr is RangeExpr
private fun isSimpleTarget(target: AssignTarget, program: Program) = private fun isSimpleTarget(target: AssignTarget, program: Program) =
if (target.identifier!=null || target.memoryAddress!=null) if (target.identifier!=null || target.memoryAddress!=null)
compTarget.isInRegularRAM(target, program) compTarget.isInRegularRAM(target, program)

View File

@@ -22,6 +22,7 @@ sealed class Expression: Node {
abstract fun accept(visitor: AstWalker, parent: Node) abstract fun accept(visitor: AstWalker, parent: Node)
abstract fun referencesIdentifier(vararg scopedName: String): Boolean abstract fun referencesIdentifier(vararg scopedName: String): Boolean
abstract fun inferType(program: Program): InferredTypes.InferredType abstract fun inferType(program: Program): InferredTypes.InferredType
abstract val isSimple: Boolean
infix fun isSameAs(assigntarget: AssignTarget) = assigntarget.isSameAs(this) infix fun isSameAs(assigntarget: AssignTarget) = assigntarget.isSameAs(this)
@@ -105,6 +106,8 @@ class PrefixExpression(val operator: String, var expression: Expression, overrid
} }
} }
override val isSimple = false
override fun toString(): String { override fun toString(): String {
return "Prefix($operator $expression)" return "Prefix($operator $expression)"
} }
@@ -133,6 +136,8 @@ class BinaryExpression(var left: Expression, var operator: String, var right: Ex
return "[$left $operator $right]" return "[$left $operator $right]"
} }
override val isSimple = false
// binary expression should actually have been optimized away into a single value, before const value was requested... // binary expression should actually have been optimized away into a single value, before const value was requested...
override fun constValue(program: Program): NumericLiteralValue? = null override fun constValue(program: Program): NumericLiteralValue? = null
@@ -242,6 +247,8 @@ class ArrayIndexedExpression(var arrayvar: IdentifierReference,
indexer.linkParents(this) indexer.linkParents(this)
} }
override val isSimple = false
override fun replaceChildNode(node: Node, replacement: Node) { override fun replaceChildNode(node: Node, replacement: Node) {
when { when {
node===arrayvar -> arrayvar = replacement as IdentifierReference node===arrayvar -> arrayvar = replacement as IdentifierReference
@@ -283,6 +290,8 @@ class TypecastExpression(var expression: Expression, var type: DataType, val imp
expression.linkParents(this) expression.linkParents(this)
} }
override val isSimple = false
override fun replaceChildNode(node: Node, replacement: Node) { override fun replaceChildNode(node: Node, replacement: Node) {
require(replacement is Expression && node===expression) require(replacement is Expression && node===expression)
expression = replacement expression = replacement
@@ -316,6 +325,8 @@ data class AddressOf(var identifier: IdentifierReference, override val position:
identifier.parent=this identifier.parent=this
} }
override val isSimple = true
override fun replaceChildNode(node: Node, replacement: Node) { override fun replaceChildNode(node: Node, replacement: Node) {
require(replacement is IdentifierReference && node===identifier) require(replacement is IdentifierReference && node===identifier)
identifier = replacement identifier = replacement
@@ -337,6 +348,8 @@ class DirectMemoryRead(var addressExpression: Expression, override val position:
this.addressExpression.linkParents(this) this.addressExpression.linkParents(this)
} }
override val isSimple = true
override fun replaceChildNode(node: Node, replacement: Node) { override fun replaceChildNode(node: Node, replacement: Node) {
require(replacement is Expression && node===addressExpression) require(replacement is Expression && node===addressExpression)
addressExpression = replacement addressExpression = replacement
@@ -362,6 +375,8 @@ class NumericLiteralValue(val type: DataType, // only numerical types allowed
override val position: Position) : Expression() { override val position: Position) : Expression() {
override lateinit var parent: Node override lateinit var parent: Node
override val isSimple = true
companion object { companion object {
fun fromBoolean(bool: Boolean, position: Position) = fun fromBoolean(bool: Boolean, position: Position) =
NumericLiteralValue(DataType.UBYTE, if (bool) 1 else 0, position) NumericLiteralValue(DataType.UBYTE, if (bool) 1 else 0, position)
@@ -493,6 +508,8 @@ class StringLiteralValue(val value: String,
this.parent = parent this.parent = parent
} }
override val isSimple = true
override fun replaceChildNode(node: Node, replacement: Node) { override fun replaceChildNode(node: Node, replacement: Node) {
throw FatalAstException("can't replace here") throw FatalAstException("can't replace here")
} }
@@ -523,6 +540,8 @@ class ArrayLiteralValue(val type: InferredTypes.InferredType, // inferred be
value.forEach {it.linkParents(this)} value.forEach {it.linkParents(this)}
} }
override val isSimple = true
override fun replaceChildNode(node: Node, replacement: Node) { override fun replaceChildNode(node: Node, replacement: Node) {
require(replacement is Expression) require(replacement is Expression)
val idx = value.indexOfFirst { it===node } val idx = value.indexOfFirst { it===node }
@@ -629,6 +648,8 @@ class RangeExpr(var from: Expression,
step.linkParents(this) step.linkParents(this)
} }
override val isSimple = true
override fun replaceChildNode(node: Node, replacement: Node) { override fun replaceChildNode(node: Node, replacement: Node) {
require(replacement is Expression) require(replacement is Expression)
when { when {
@@ -718,6 +739,8 @@ internal fun makeRange(fromVal: Int, toVal: Int, stepVal: Int): IntProgression {
data class IdentifierReference(val nameInSource: List<String>, override val position: Position) : Expression(), IAssignable { data class IdentifierReference(val nameInSource: List<String>, override val position: Position) : Expression(), IAssignable {
override lateinit var parent: Node override lateinit var parent: Node
override val isSimple = true
fun targetStatement(program: Program) = fun targetStatement(program: Program) =
if(nameInSource.size==1 && nameInSource[0] in program.builtinFunctions.names) if(nameInSource.size==1 && nameInSource[0] in program.builtinFunctions.names)
BuiltinFunctionStatementPlaceholder(nameInSource[0], position, parent) BuiltinFunctionStatementPlaceholder(nameInSource[0], position, parent)
@@ -797,6 +820,8 @@ class FunctionCall(override var target: IdentifierReference,
args.forEach { it.linkParents(this) } args.forEach { it.linkParents(this) }
} }
override val isSimple = target.nameInSource.size==1 && (target.nameInSource[0] in setOf("msb", "lsb", "peek", "peekw"))
override fun replaceChildNode(node: Node, replacement: Node) { override fun replaceChildNode(node: Node, replacement: Node) {
if(node===target) if(node===target)
target=replacement as IdentifierReference target=replacement as IdentifierReference

View File

@@ -662,7 +662,6 @@ class Subroutine(override val name: String,
override lateinit var parent: Node override lateinit var parent: Node
val asmGenInfo = AsmGenInfo() val asmGenInfo = AsmGenInfo()
val scopedname: String by lazy { makeScopedName(name) } val scopedname: String by lazy { makeScopedName(name) }
var inlineAnnotated: Boolean = false
override fun linkParents(parent: Node) { override fun linkParents(parent: Node) {
this.parent = parent this.parent = parent

View File

@@ -1,6 +1,13 @@
==== ====
TODO TODO
==== ====
- make sure that in if statements, the left and right operand of the comparison is never a complex expression
anymore (only number, variable, addressof or memread) by rewriting if <left> <op> <right> {..} into:
if_eval_left = left
if_eval_right = right
if if_eval_left <op> if_eval_right { ... } (only rewrite operand if x.isSimple() !!)
and then simplify all the codegeneration for if statements.
the variables are allocated in subroutine scope (otherwise irq handler could clobber them)
- optimize several inner loops in gfx2 - optimize several inner loops in gfx2
- hoist all variable declarations up to the subroutine scope *before* even the constant folding takes place (to avoid undefined symbol errors when referring to a variable from another nested scope in the subroutine) - hoist all variable declarations up to the subroutine scope *before* even the constant folding takes place (to avoid undefined symbol errors when referring to a variable from another nested scope in the subroutine)

View File

@@ -7,22 +7,6 @@ main {
ubyte yy ubyte yy
ubyte joy=1 ubyte joy=1
ubyte zz ubyte zz
str foobar="foobar"
uword joyw=1
if joyw + 1000 > 1000
txt.print(">1000")
if joyw + 1000 > 1011
txt.print(">1011")
if joyw + 1000 > & foobar
txt.print(">&foobar")
if joyw + 1000 > joyw
txt.print(">&foobar")
if joy + 10 > 10
txt.print(">10")
if joy + 10 >11
txt.print(">11")
joy >>= 1 joy >>= 1
if_cs if_cs
@@ -33,9 +17,18 @@ main {
yy++ yy++
; TODO the shifting checks above result in way smaller code than this: ; TODO the shifting checks above result in way smaller code than this:
if joy & %00000001 if joy+44 > 33 {
yy++ yy++
if joy & %00000010 }
yy=joy+44>33
if yy {
yy++
}
if joy & %00000001
yy++
if joy & %00000010
yy++ yy++
} }