optimized if-goto codegeneration

This commit is contained in:
Irmen de Jong 2021-12-27 20:46:10 +01:00
parent 97e84d0977
commit 1c7c4fc3b0
5 changed files with 52 additions and 44 deletions

View File

@ -1098,15 +1098,14 @@ class AsmGen(private val program: Program,
val booleanCondition = stmt.condition as BinaryExpression val booleanCondition = stmt.condition as BinaryExpression
if (stmt.elsepart.isEmpty()) { if (stmt.elsepart.isEmpty()) {
// TODO specialize this if(stmt.truepart.statements.singleOrNull() is Jump) {
// if(stmt.truepart.statements.singleOrNull() is Jump) { translateCompareAndJumpIfTrue(booleanCondition, stmt.truepart.statements[0] as Jump)
// translateCompareAndJumpIfTrue(booleanCondition, stmt.truepart.statements[0] as Jump) } else {
// } else {
val endLabel = makeLabel("if_end") val endLabel = makeLabel("if_end")
translateCompareAndJumpIfFalse(booleanCondition, endLabel) translateCompareAndJumpIfFalse(booleanCondition, endLabel)
translate(stmt.truepart) translate(stmt.truepart)
out(endLabel) out(endLabel)
// } }
} }
else { else {
// both true and else parts // both true and else parts
@ -1613,16 +1612,29 @@ $label nop""")
} }
private fun translateCompareAndJumpIfTrue(expr: BinaryExpression, jump: Jump) { private fun translateCompareAndJumpIfTrue(expr: BinaryExpression, jump: Jump) {
if(expr.operator !in ComparisonOperators)
throw AssemblyError("must be comparison expression")
// invert the comparison, so we can reuse the JumpIfFalse code generation routines
val invertedComparisonOperator = invertedComparisonOperator(expr.operator)
?: throw AssemblyError("can't invert comparison $expr")
val left = expr.left val left = expr.left
val right = expr.right val right = expr.right
val operator = expr.operator
val leftConstVal = left.constValue(program)
val rightConstVal = right.constValue(program) val rightConstVal = right.constValue(program)
val label = when {
jump.generatedLabel!=null -> jump.generatedLabel!!
jump.identifier!=null -> asmSymbolName(jump.identifier!!)
jump.address!=null -> jump.address!!.toHex()
else -> throw AssemblyError("weird jump")
}
if (rightConstVal!=null && rightConstVal.number == 0.0) if (rightConstVal!=null && rightConstVal.number == 0.0)
testZeroAndJump(left, operator, jump, null) testZeroAndJump(left, invertedComparisonOperator, label)
else else {
testNonzeroComparisonAndJump(left, operator, right, jump, null, leftConstVal, rightConstVal) val leftConstVal = left.constValue(program)
testNonzeroComparisonAndJump(left, invertedComparisonOperator, right, label, leftConstVal, rightConstVal)
}
} }
private fun translateCompareAndJumpIfFalse(expr: BinaryExpression, jumpIfFalseLabel: String) { private fun translateCompareAndJumpIfFalse(expr: BinaryExpression, jumpIfFalseLabel: String) {
@ -1633,18 +1645,16 @@ $label nop""")
val rightConstVal = right.constValue(program) val rightConstVal = right.constValue(program)
if (rightConstVal!=null && rightConstVal.number == 0.0) if (rightConstVal!=null && rightConstVal.number == 0.0)
testZeroAndJump(left, operator, null, jumpIfFalseLabel) testZeroAndJump(left, operator, jumpIfFalseLabel)
else else
testNonzeroComparisonAndJump(left, operator, right, null, jumpIfFalseLabel, leftConstVal, rightConstVal) testNonzeroComparisonAndJump(left, operator, right, jumpIfFalseLabel, leftConstVal, rightConstVal)
} }
private fun testZeroAndJump( private fun testZeroAndJump(
left: Expression, left: Expression,
operator: String, operator: String,
jumpIfTrue: Jump?, jumpIfFalseLabel: String
jumpIfFalseLabel: String?
) { ) {
require(jumpIfTrue!=null || jumpIfFalseLabel!=null)
when(val dt = left.inferType(program).getOr(DataType.UNDEFINED)) { when(val dt = left.inferType(program).getOr(DataType.UNDEFINED)) {
DataType.UBYTE, DataType.UWORD -> { DataType.UBYTE, DataType.UWORD -> {
if(operator=="<") { if(operator=="<") {
@ -1733,16 +1743,12 @@ $label nop""")
left: Expression, left: Expression,
operator: String, operator: String,
right: Expression, right: Expression,
jumpIfTrue: Jump?, jumpIfFalseLabel: String,
jumpIfFalseLabel: String?,
leftConstVal: NumericLiteralValue?, leftConstVal: NumericLiteralValue?,
rightConstVal: NumericLiteralValue? rightConstVal: NumericLiteralValue?
) { ) {
require(jumpIfTrue!=null || jumpIfFalseLabel!=null)
val dt = left.inferType(program).getOrElse { throw AssemblyError("unknown dt") } val dt = left.inferType(program).getOrElse { throw AssemblyError("unknown dt") }
jumpIfFalseLabel!! // TODO jump if true... or rewrite everything to use just jump-if-false
when (operator) { when (operator) {
"==" -> { "==" -> {
when (dt) { when (dt) {

View File

@ -724,25 +724,4 @@ class ExpressionSimplifier(private val program: Program) : AstWalker() {
private data class BinExprWithConstants(val expr: BinaryExpression, val leftVal: NumericLiteralValue?, val rightVal: NumericLiteralValue?) private data class BinExprWithConstants(val expr: BinaryExpression, val leftVal: NumericLiteralValue?, val rightVal: NumericLiteralValue?)
} }
fun invertCondition(cond: Expression): BinaryExpression? {
if(cond is BinaryExpression) {
val invertedOperator = invertedComparisonOperator(cond.operator)
if (invertedOperator != null)
return BinaryExpression(cond.left, invertedOperator, cond.right, cond.position)
}
return null
}
fun invertedComparisonOperator(operator: String) =
when (operator) {
"==" -> "!="
"!=" -> "=="
"<" -> ">="
">" -> "<="
"<=" -> ">"
">=" -> "<"
else -> null
}

View File

@ -9,7 +9,6 @@ import prog8.ast.statements.*
import prog8.ast.walk.AstWalker import prog8.ast.walk.AstWalker
import prog8.ast.walk.IAstModification import prog8.ast.walk.IAstModification
import prog8.compilerinterface.IErrorReporter import prog8.compilerinterface.IErrorReporter
import prog8.optimizer.invertedComparisonOperator
internal class VariousCleanups(val program: Program, val errors: IErrorReporter): AstWalker() { internal class VariousCleanups(val program: Program, val errors: IErrorReporter): AstWalker() {

View File

@ -15,6 +15,17 @@ val AugmentAssignmentOperators = setOf("+", "-", "/", "*", "**", "&", "|", "^",
val LogicalOperators = setOf("and", "or", "xor", "not") val LogicalOperators = setOf("and", "or", "xor", "not")
val BitwiseOperators = setOf("&", "|", "^") val BitwiseOperators = setOf("&", "|", "^")
fun invertedComparisonOperator(operator: String) =
when (operator) {
"==" -> "!="
"!=" -> "=="
"<" -> ">="
">" -> "<="
"<=" -> ">"
">=" -> "<"
else -> null
}
sealed class Expression: Node { sealed class Expression: Node {
abstract override fun copy(): Expression abstract override fun copy(): Expression
@ -938,3 +949,13 @@ class FunctionCall(override var target: IdentifierReference,
} }
} }
} }
fun invertCondition(cond: Expression): BinaryExpression? {
if(cond is BinaryExpression) {
val invertedOperator = invertedComparisonOperator(cond.operator)
if (invertedOperator != null)
return BinaryExpression(cond.left, invertedOperator, cond.right, cond.position)
}
return null
}

View File

@ -3,7 +3,10 @@ TODO
For next compiler release (7.6) For next compiler release (7.6)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
optimize ifs containing only a jump: reuse old code from AsmGen translateComparisonExpressionWithJumpIfFalse? fix imageviewer pcx decoding, broken since if/goto changes...
also wormfood: worm freezes when you press fire...
also petaxian: gameplay doesn't work at all anymore
also textelite: after showing map, it just exits
Blocked by an official Commander-x16 v39 release Blocked by an official Commander-x16 v39 release