tweak & fix if expression with word condition

This commit is contained in:
Irmen de Jong 2024-11-02 18:40:10 +01:00
parent 3b798097b9
commit 7cfb33a448
7 changed files with 258 additions and 113 deletions

View File

@ -43,12 +43,16 @@ internal class IfElseAsmGen(private val program: PtProgram,
val prefixCond = stmt.condition as? PtPrefix
if(prefixCond?.operator=="not") {
checkNotRomsubReturnsStatusReg(prefixCond.value)
assignConditionValueToRegisterAndTest(prefixCond.value)
return if(jumpAfterIf!=null)
translateJumpElseBodies("beq", "bne", jumpAfterIf, stmt.elseScope)
else
translateIfElseBodies("bne", stmt)
if(stmt.hasElse())
throw AssemblyError("not prefix in ifelse should have been replaced by swapped if-else blocks")
else {
checkNotRomsubReturnsStatusReg(prefixCond.value)
assignConditionValueToRegisterAndTest(prefixCond.value)
return if (jumpAfterIf != null)
translateJumpElseBodies("beq", "bne", jumpAfterIf, stmt.elseScope)
else
translateIfElseBodies("bne", stmt)
}
}
throw AssemblyError("weird non-boolean condition node type ${stmt.condition} at ${stmt.condition.position}")
@ -99,8 +103,7 @@ internal class IfElseAsmGen(private val program: PtProgram,
}
}
else if(condition is PtPrefix && condition.operator=="not") {
assignConditionValueToRegisterAndTest(condition.value)
asmgen.out(" bne $falseLabel")
throw AssemblyError("not prefix in ifexpression should have been replaced by swapped values")
} else {
// 'simple' condition, check if it is a byte bittest
val bittest = condition as? PtBuiltinFunctionCall
@ -396,51 +399,27 @@ internal class IfElseAsmGen(private val program: PtProgram,
}
private fun translateIfWordConditionBranch(condition: PtBinaryExpression, falseLabel: String) {
val signed = condition.left.type in SignedDatatypes
// TODO can we reuse this whole thing from IfElse ?
val constValue = condition.right.asConstInteger()
if(constValue==0) {
// TODO reuse more code from regular if statements. Need a shared routine like isWordExprZero() ?
when(condition.operator) {
"==" -> {
// if w==0
asmgen.assignExpressionToRegister(condition.left, RegisterOrPair.AY, signed)
asmgen.out(" sty P8ZP_SCRATCH_REG | ora P8ZP_SCRATCH_REG | bne $falseLabel")
return
if(constValue!=null) {
if (constValue == 0) {
when (condition.operator) {
"==" -> return translateWordExprIsZero(condition.left, falseLabel)
"!=" -> return translateWordExprIsNotZero(condition.left, falseLabel)
}
"!=" -> {
// if w!=0
asmgen.assignExpressionToRegister(condition.left, RegisterOrPair.AY, signed)
asmgen.out(" sty P8ZP_SCRATCH_REG | ora P8ZP_SCRATCH_REG | beq $falseLabel")
return
}
if (constValue != 0) {
when (condition.operator) {
"==" -> return translateWordExprEqualsNumber(condition.left, constValue, falseLabel)
"!=" -> return translateWordExprNotEqualsNumber(condition.left, constValue, falseLabel)
}
}
}
if(constValue!=0) {
// TODO reuse more code from regular if statements. Need a shared routine like isWordExprEqualNumber() ?
when(condition.operator) {
"==" -> {
// if w==number
asmgen.assignExpressionToRegister(condition.left, RegisterOrPair.AY, signed)
asmgen.out("""
cmp #<$constValue
bne $falseLabel
cpy #>$constValue
bne $falseLabel""")
return
}
"!=" -> {
// if w!=number
asmgen.assignExpressionToRegister(condition.left, RegisterOrPair.AY, signed)
asmgen.out("""
cmp #<$constValue
bne +
cpy #>$constValue
beq $falseLabel
+""")
return
}
val variable = condition.right as? PtIdentifier
if(variable!=null) {
when (condition.operator) {
"==" -> return translateWordExprEqualsVariable(condition.left, variable, falseLabel)
"!=" -> return translateWordExprNotEqualsVariable(condition.left, variable, falseLabel)
}
}
@ -449,6 +428,130 @@ internal class IfElseAsmGen(private val program: PtProgram,
asmgen.out(" beq $falseLabel")
}
private fun translateWordExprNotEqualsVariable(expr: PtExpression, variable: PtIdentifier, falseLabel: String) {
// if w!=variable
// TODO reuse code from ifElse?
val varRight = asmgen.asmVariableName(variable)
if(expr is PtIdentifier) {
val varLeft = asmgen.asmVariableName(expr)
asmgen.out("""
lda $varLeft
cmp $varRight
bne +
lda $varLeft+1
cmp $varRight+1
beq $falseLabel
+""")
} else {
asmgen.assignExpressionToRegister(expr, RegisterOrPair.AY, false)
asmgen.out("""
cmp $varRight
bne +
cpy $varRight+1
beq $falseLabel
+""")
}
}
private fun translateWordExprEqualsVariable(expr: PtExpression, variable: PtIdentifier, falseLabel: String) {
// if w==variable
// TODO reuse code from ifElse?
val varRight = asmgen.asmVariableName(variable)
if(expr is PtIdentifier) {
val varLeft = asmgen.asmVariableName(expr)
asmgen.out("""
lda $varLeft
cmp $varRight
bne $falseLabel
lda $varLeft+1
cmp $varRight+1
bne $falseLabel""")
} else {
asmgen.assignExpressionToRegister(expr, RegisterOrPair.AY, false)
asmgen.out("""
cmp $varRight
bne $falseLabel
cpy $varRight+1
bne $falseLabel""")
}
}
private fun translateWordExprNotEqualsNumber(expr: PtExpression, number: Int, falseLabel: String) {
// if w!=number
// TODO reuse code from ifElse?
if(expr is PtIdentifier) {
val varname = asmgen.asmVariableName(expr)
asmgen.out("""
lda $varname
cmp #<$number
bne +
lda $varname+1
cmp #>$number
beq $falseLabel
+""")
} else {
asmgen.assignExpressionToRegister(expr, RegisterOrPair.AY, false)
asmgen.out("""
cmp #<$number
bne +
cpy #>$number
beq $falseLabel
+""")
}
}
private fun translateWordExprEqualsNumber(expr: PtExpression, number: Int, falseLabel: String) {
// if w==number
// TODO reuse code from ifElse?
if(expr is PtIdentifier) {
val varname = asmgen.asmVariableName(expr)
asmgen.out("""
lda $varname
cmp #<$number
bne $falseLabel
lda $varname+1
cmp #>$number
bne $falseLabel""")
} else {
asmgen.assignExpressionToRegister(expr, RegisterOrPair.AY, false)
asmgen.out( """
cmp #<$number
bne $falseLabel
cpy #>$number
bne $falseLabel""")
}
}
private fun translateWordExprIsNotZero(expr: PtExpression, falseLabel: String) {
// if w!=0
// TODO reuse code from ifElse?
if(expr is PtIdentifier) {
val varname = asmgen.asmVariableName(expr)
asmgen.out("""
lda $varname
ora $varname+1
beq $falseLabel""")
} else {
asmgen.assignExpressionToRegister(expr, RegisterOrPair.AY, false)
asmgen.out(" sty P8ZP_SCRATCH_REG | ora P8ZP_SCRATCH_REG | beq $falseLabel")
}
}
private fun translateWordExprIsZero(expr: PtExpression, falseLabel: String) {
// if w==0
// TODO reuse code from ifElse?
if(expr is PtIdentifier) {
val varname = asmgen.asmVariableName(expr)
asmgen.out("""
lda $varname
ora $varname+1
bne $falseLabel""")
} else {
asmgen.assignExpressionToRegister(expr, RegisterOrPair.AY, false)
asmgen.out(" sty P8ZP_SCRATCH_REG | ora P8ZP_SCRATCH_REG | bne $falseLabel")
}
}
private fun translateIfCompareWithZeroByteBranch(condition: PtBinaryExpression, signed: Boolean, falseLabel: String) {
// optimized code for byte comparisons with 0
assignConditionValueToRegisterAndTest(condition.left)

View File

@ -91,6 +91,10 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
}
private fun translate(ifExpr: PtIfExpression): ExpressionCodeResult {
if((ifExpr.condition as? PtPrefix)?.operator=="not")
throw AssemblyError("not prefix in ifexpression should have been replaced by swapped values")
// TODO don't store condition as expression result but just use the flags, like a normal PtIfElse translation does
val condTr = translateExpression(ifExpr.condition)
val trueTr = translateExpression(ifExpr.truevalue)

View File

@ -1330,6 +1330,9 @@ class IRCodeGen(
}
private fun translateIfElse(ifElse: PtIfElse): IRCodeChunks {
if((ifElse.condition as? PtPrefix)?.operator=="not")
throw AssemblyError("not prefix in ifelse should have been replaced by swapped if-else blocks")
val condition = ifElse.condition as? PtBinaryExpression
if(condition==null || condition.left.type != DataType.FLOAT) {
return ifWithElse_IntegerCond(ifElse)

View File

@ -238,11 +238,8 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr
if(expr.operator=="==") {
if(rightDt==DataType.BOOL && leftDt==DataType.BOOL) {
val rightConstBool = rightVal?.asBooleanValue
if(rightConstBool!=null) {
return if(rightConstBool)
listOf(IAstModification.ReplaceNode(expr, expr.left, parent))
else
listOf(IAstModification.ReplaceNode(expr, PrefixExpression("not", expr.left, expr.position), parent))
if(rightConstBool==true) {
return listOf(IAstModification.ReplaceNode(expr, expr.left, parent))
}
}
if (rightVal?.number == 1.0) {
@ -261,11 +258,8 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr
if (expr.operator=="!=") {
if(rightDt==DataType.BOOL && leftDt==DataType.BOOL) {
val rightConstBool = rightVal?.asBooleanValue
if(rightConstBool!=null) {
return if (rightConstBool)
listOf(IAstModification.ReplaceNode(expr, PrefixExpression("not", expr.left, expr.position), parent))
else
listOf(IAstModification.ReplaceNode(expr, expr.left, parent))
if(rightConstBool==false) {
listOf(IAstModification.ReplaceNode(expr, expr.left, parent))
}
}
if (rightVal?.number == 1.0) {
@ -416,21 +410,6 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr
return noModifications
}
override fun after(expr: PrefixExpression, parent: Node): Iterable<IAstModification> {
if(expr.operator=="not") {
// not X <compare> Y -> X <invertedcompare> Y
val binExpr = expr.expression as? BinaryExpression
if(binExpr!=null) {
val invertedOperator = invertedComparisonOperator(binExpr.operator)
if(invertedOperator!=null) {
val inverted = BinaryExpression(binExpr.left, invertedOperator, binExpr.right, binExpr.position)
return listOf(IAstModification.ReplaceNode(expr, inverted, parent))
}
}
}
return noModifications
}
private fun applyAbsorptionLaws(expr: BinaryExpression): Expression? {
// NOTE: only when the terms are not function calls!!!
if(expr.left is IFunctionCall || expr.right is IFunctionCall)

View File

@ -127,19 +127,6 @@ class StatementOptimizer(private val program: Program,
)
}
}
// switch if/else around if the condition is a not
val prefixCond = ifElse.condition as? PrefixExpression
if(prefixCond?.operator=="not") {
errors.info("invert conditon and swap if/else blocks", ifElse.condition.position)
val newTruePart = AnonymousScope(ifElse.elsepart.statements, ifElse.elsepart.position)
val newElsePart = AnonymousScope(ifElse.truepart.statements, ifElse.truepart.position)
return listOf(
IAstModification.ReplaceNode(ifElse.elsepart, newElsePart, ifElse),
IAstModification.ReplaceNode(ifElse.truepart, newTruePart, ifElse),
IAstModification.ReplaceNode(ifElse.condition, prefixCond.expression, ifElse)
)
}
}
return noModifications

View File

@ -3,10 +3,8 @@ package prog8.compiler.astprocessing
import prog8.ast.Node
import prog8.ast.Program
import prog8.ast.base.FatalAstException
import prog8.ast.expressions.BinaryExpression
import prog8.ast.expressions.NumericLiteral
import prog8.ast.expressions.PrefixExpression
import prog8.ast.expressions.invertCondition
import prog8.ast.expressions.*
import prog8.ast.statements.IfElse
import prog8.ast.walk.AstWalker
import prog8.ast.walk.IAstModification
import prog8.code.core.*
@ -97,7 +95,6 @@ internal class NotExpressionAndIfComparisonExprChanger(val program: Program, val
override fun after(expr: PrefixExpression, parent: Node): Iterable<IAstModification> {
if(expr.operator == "not") {
// first check if we're already part of a "boolean" expression (i.e. comparing against 0 or 1)
// if so, simplify THAT whole expression rather than making it more complicated
if (parent is BinaryExpression) {
@ -155,22 +152,49 @@ internal class NotExpressionAndIfComparisonExprChanger(val program: Program, val
val notZero = BinaryExpression(x, "!=", NumericLiteral(dt, 0.0, expr.position), expr.position)
return listOf(IAstModification.ReplaceNode(expr, notZero, parent))
}
// not X <compare> Y -> X <invertedcompare> Y
val subBinExpr = expr.expression as? BinaryExpression
if(subBinExpr?.operator=="==") {
if(subBinExpr.right.constValue(program)?.number==0.0) {
// not(x==0) -> x!=0
subBinExpr.operator = "!="
return listOf(IAstModification.ReplaceNode(expr, subBinExpr, parent))
}
} else if(subBinExpr?.operator=="!=") {
if(subBinExpr.right.constValue(program)?.number==0.0) {
// not(x!=0) -> x==0
subBinExpr.operator = "=="
return listOf(IAstModification.ReplaceNode(expr, subBinExpr, parent))
if(subBinExpr!=null) {
val invertedOperator = invertedComparisonOperator(subBinExpr.operator)
if(invertedOperator!=null) {
val inverted = BinaryExpression(subBinExpr.left, invertedOperator, subBinExpr.right, subBinExpr.position)
return listOf(IAstModification.ReplaceNode(expr, inverted, parent))
}
}
}
return noModifications
}
override fun before(ifElse: IfElse, parent: Node): Iterable<IAstModification> {
if(ifElse.elsepart.isNotEmpty()) {
val prefix = ifElse.condition as? PrefixExpression
if(prefix?.operator=="not") {
// if not x a else b -> if x b else a
errors.info("invert condition and swap if/else blocks", ifElse.condition.position)
ifElse.condition = prefix.expression
ifElse.condition.parent = ifElse
val elsepart = ifElse.elsepart
ifElse.elsepart = ifElse.truepart
ifElse.truepart = elsepart
}
}
return noModifications
}
override fun before(ifExpr: IfExpression, parent: Node): Iterable<IAstModification> {
val prefix = ifExpr.condition as? PrefixExpression
if(prefix?.operator=="not") {
// if not x a else b -> if x b else a
errors.info("invert condition and swap values", ifExpr.condition.position)
ifExpr.condition = prefix.expression
ifExpr.condition.parent = ifExpr
val falsevalue = ifExpr.falsevalue
ifExpr.falsevalue = ifExpr.truevalue
ifExpr.truevalue = falsevalue
}
return noModifications
}
}

View File

@ -1,21 +1,66 @@
%import textio
%option no_sysinit
%zeropage basicsafe
%memtop $0840
main {
sub start() {
cx16.r0L=0
if cx16.r0L==0 {
uword[] addresses = [scores2, start]
uword[] @split scores1 = [10, 25, 50, 100] ; can never clear more than 4 lines at once
uword[] @split scores2 = [10, 25, 50, 100] ; can never clear more than 4 lines at once
cx16.r0=0
cx16.r0 = &scores1
cx16.r1 = &scores2
cx16.r2 = &addresses
}
if cx16.r0==0
cx16.r1L=42
else
cx16.r1L=99
cx16.r2L = if cx16.r0==0 42 else 99
if cx16.r0==33
cx16.r1L=42
else
cx16.r1L=99
cx16.r2L = if cx16.r0==33 42 else 99
if cx16.r0!=3333
cx16.r1L=42
else
cx16.r1L=99
cx16.r2L = if cx16.r0!=3333 42 else 99
if cx16.r0!=0
cx16.r1L=42
else
cx16.r1L=99
cx16.r2L = if cx16.r0!=0 42 else 99
if cx16.r0!=33
cx16.r1L=42
else
cx16.r1L=99
cx16.r2L = if cx16.r0!=0 42 else 99
if cx16.r0==cx16.r9
cx16.r1L=42
else
cx16.r1L=99
cx16.r2L = if cx16.r0==cx16.r9 42 else 99
if cx16.r0!=cx16.r9
cx16.r1L=42
else
cx16.r1L=99
cx16.r2L = if cx16.r0!=cx16.r9 42 else 99
if cx16.r0>cx16.r1
cx16.r1L=42
else
cx16.r1L=99
cx16.r2L = if cx16.r0>cx16.r1 42 else 99
}
}