mirror of
https://github.com/irmen/prog8.git
synced 2025-08-14 22:27:48 +00:00
preparing optimization plan for if statements
This commit is contained in:
@@ -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
|
||||||
|
@@ -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)
|
||||||
|
@@ -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
|
||||||
|
@@ -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
|
||||||
|
@@ -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)
|
||||||
|
@@ -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++
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user