optimize word >, word <=

This commit is contained in:
Irmen de Jong 2024-02-27 21:34:58 +01:00
parent bed629998a
commit dba0846866
5 changed files with 183 additions and 376 deletions

View File

@ -435,8 +435,8 @@ internal class IfElseAsmGen(private val program: PtProgram,
"==" -> wordEqualsValue(condition.left, condition.right, false, signed, jumpAfterIf, stmt)
"!=" -> wordEqualsValue(condition.left, condition.right, true, signed, jumpAfterIf, stmt)
"<" -> wordLessValue(condition.left, condition.right, signed, jumpAfterIf, stmt)
"<=" -> wordLessEqualsValue(condition.left, condition.right, signed, jumpAfterIf, stmt)
">" -> wordGreaterValue(condition.left, condition.right, signed, jumpAfterIf, stmt)
"<=" -> throw AssemblyError("X<=Y should have been replaced by Y>=X")
">" -> throw AssemblyError("X>Y should have been replaced by Y<X")
">=" -> wordGreaterEqualsValue(condition.left, condition.right, signed, jumpAfterIf, stmt)
else -> fallbackTranslate(stmt, false)
}
@ -591,301 +591,6 @@ _jump jmp ($asmLabel)
code("P8ZP_SCRATCH_W2", "P8ZP_SCRATCH_W2+1")
}
private fun wordGreaterValue(left: PtExpression, right: PtExpression, signed: Boolean, jump: PtJump?, stmt: PtIfElse) {
fun code(valueLsb: String, valueMsb: String) {
if(signed) {
// word > X
if(jump!=null) {
val (asmLabel, indirect) = asmgen.getJumpTarget(jump)
if(indirect) {
asmgen.out("""
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
ldy $valueLsb
lda $valueMsb
cpy P8ZP_SCRATCH_W1
sbc P8ZP_SCRATCH_W1+1
bvc +
eor #128
+ bpl +
jmp ($asmLabel)
+""")
} else {
asmgen.out("""
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
ldy $valueLsb
lda $valueMsb
cpy P8ZP_SCRATCH_W1
sbc P8ZP_SCRATCH_W1+1
bvc +
eor #128
+ bmi $asmLabel""")
}
} else {
val afterIfLabel = asmgen.makeLabel("afterif")
if(stmt.hasElse()) {
// if and else blocks
val elseLabel = asmgen.makeLabel("else")
asmgen.out("""
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
ldy $valueLsb
lda $valueMsb
cpy P8ZP_SCRATCH_W1
sbc P8ZP_SCRATCH_W1+1
bvc +
eor #128
+ bpl $elseLabel""")
asmgen.translate(stmt.ifScope)
asmgen.jmp(afterIfLabel, false)
asmgen.out(elseLabel)
asmgen.translate(stmt.elseScope)
} else {
// no else block
asmgen.out("""
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
ldy $valueLsb
lda $valueMsb
cpy P8ZP_SCRATCH_W1
sbc P8ZP_SCRATCH_W1+1
bvc +
eor #128
+ bpl $afterIfLabel""")
asmgen.translate(stmt.ifScope)
}
asmgen.out(afterIfLabel)
}
} else {
// uword > X
if(jump!=null) {
val (asmLabel, indirect) = asmgen.getJumpTarget(jump)
if(indirect) {
asmgen.out("""
cpy $valueMsb
beq +
bcc ++
jmp ($asmLabel)
+ cmp $valueLsb
bcc +
beq +
jmp ($asmLabel)
+""")
} else {
asmgen.out("""
cpy $valueMsb
beq +
bcc ++
bcs $asmLabel
+ cmp $valueLsb
bcc +
beq +
bne $asmLabel
+""")
}
} else {
val afterIfLabel = asmgen.makeLabel("afterif")
if(stmt.hasElse()) {
val elseLabel = asmgen.makeLabel("else")
asmgen.out("""
cpy $valueMsb
bcc $elseLabel
bne +
cmp $valueLsb
bcc $elseLabel
beq $elseLabel
+""")
asmgen.translate(stmt.ifScope)
asmgen.jmp(afterIfLabel, false)
asmgen.out(elseLabel)
asmgen.translate(stmt.elseScope)
} else {
// no else block
asmgen.out("""
cpy $valueMsb
bcc $afterIfLabel
bne +
cmp $valueLsb
bcc $afterIfLabel
beq $afterIfLabel
+""")
asmgen.translate(stmt.ifScope)
}
asmgen.out(afterIfLabel)
}
}
}
if(right is PtNumber) {
asmgen.assignExpressionToRegister(left, RegisterOrPair.AY, signed)
val number = right.number.toHex()
return code("#<$number", "#>$number")
}
if(right is PtIdentifier) {
asmgen.assignExpressionToRegister(left, RegisterOrPair.AY, signed)
val variable = asmgen.asmVariableName(right)
return code(variable, variable+"+1")
}
// TODO optimize for simple array value
// generic case via scratch register
asmgen.assignWordOperandsToAYAndVar(left, right, "P8ZP_SCRATCH_W2")
code("P8ZP_SCRATCH_W2", "P8ZP_SCRATCH_W2+1")
}
private fun wordLessEqualsValue(left: PtExpression, right: PtExpression, signed: Boolean, jump: PtJump?, stmt: PtIfElse) {
fun code(valueLsb: String, valueMsb: String) {
if(signed) {
// word <= X
if(jump!=null) {
val (asmLabel, indirect) = asmgen.getJumpTarget(jump)
if(indirect) {
asmgen.out("""
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
ldy $valueLsb
lda $valueMsb
cpy P8ZP_SCRATCH_W1
sbc P8ZP_SCRATCH_W1+1
bvc +
eor #128
+ bmi +
jmp ($asmLabel)
+""")
} else {
asmgen.out("""
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
ldy $valueLsb
lda $valueMsb
cpy P8ZP_SCRATCH_W1
sbc P8ZP_SCRATCH_W1+1
bvc +
eor #128
+ bpl $asmLabel""")
}
} else {
val afterIfLabel = asmgen.makeLabel("afterif")
if(stmt.hasElse()) {
// if and else blocks
val elseLabel = asmgen.makeLabel("else")
asmgen.out("""
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
ldy $valueLsb
lda $valueMsb
cpy P8ZP_SCRATCH_W1
sbc P8ZP_SCRATCH_W1+1
bvc +
eor #128
+ bmi $elseLabel""")
asmgen.translate(stmt.ifScope)
asmgen.jmp(afterIfLabel, false)
asmgen.out(elseLabel)
asmgen.translate(stmt.elseScope)
} else {
// no else block
asmgen.out("""
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
ldy $valueLsb
lda $valueMsb
cpy P8ZP_SCRATCH_W1
sbc P8ZP_SCRATCH_W1+1
bvc +
eor #128
+ bmi $afterIfLabel""")
asmgen.translate(stmt.ifScope)
}
asmgen.out(afterIfLabel)
}
} else {
// uword <= X
if(jump!=null) {
val (asmLabel, indirect) = asmgen.getJumpTarget(jump)
if(indirect) {
asmgen.out("""
sec
sbc $valueLsb
sta P8ZP_SCRATCH_REG
tya
sbc $valueMsb
ora P8ZP_SCRATCH_REG
beq +
bcs ++
+ jmp ($asmLabel)
+""")
} else {
asmgen.out("""
sec
sbc $valueLsb
sta P8ZP_SCRATCH_REG
tya
sbc $valueMsb
ora P8ZP_SCRATCH_REG
beq $asmLabel
bcc $asmLabel""")
}
} else {
val afterIfLabel = asmgen.makeLabel("afterif")
if(stmt.hasElse()) {
// if and else blocks
val elseLabel = asmgen.makeLabel("else")
asmgen.out("""
sec
sbc $valueLsb
sta P8ZP_SCRATCH_REG
tya
sbc $valueMsb
ora P8ZP_SCRATCH_REG
beq +
bcs $elseLabel
+""")
asmgen.translate(stmt.ifScope)
asmgen.jmp(afterIfLabel, false)
asmgen.out(elseLabel)
asmgen.translate(stmt.elseScope)
} else {
// no else block
asmgen.out("""
sec
sbc $valueLsb
sta P8ZP_SCRATCH_REG
tya
sbc $valueMsb
ora P8ZP_SCRATCH_REG
beq +
bcs $afterIfLabel
+""")
asmgen.translate(stmt.ifScope)
}
asmgen.out(afterIfLabel)
}
}
}
if(right is PtNumber) {
asmgen.assignExpressionToRegister(left, RegisterOrPair.AY, signed)
val number = right.number.toHex()
return code("#<$number", "#>$number")
}
if(right is PtIdentifier) {
asmgen.assignExpressionToRegister(left, RegisterOrPair.AY, signed)
val variable = asmgen.asmVariableName(right)
return code(variable, variable+"+1")
}
// TODO optimize for simple array value
// generic case via scratch register
asmgen.assignWordOperandsToAYAndVar(left, right, "P8ZP_SCRATCH_W2")
code("P8ZP_SCRATCH_W2", "P8ZP_SCRATCH_W2+1")
}
private fun wordGreaterEqualsValue(left: PtExpression, right: PtExpression, signed: Boolean, jump: PtJump?, stmt: PtIfElse) {
fun code(valueLsb: String, valueMsb: String) {
@ -1037,7 +742,64 @@ _jump jmp ($asmLabel)
private fun wordLessEqualsZero(value: PtExpression, signed: Boolean, jump: PtJump?, stmt: PtIfElse) {
return if(signed) {
// word <= 0
asmgen.assignExpressionToRegister(value, RegisterOrPair.AY, true) // TODO optimize this even further by doing MSB/LSB separately
if(value is PtIdentifier) {
// special optimization to compare msb/lsb separately
// TODO also do this for array?
if(jump!=null) {
val (asmLabel, indirect) = asmgen.getJumpTarget(jump)
if(indirect) {
asmgen.out("""
lda ${value.name}+1
bmi +
bne ++
lda ${value.name}
bne ++
+ jmp ($asmLabel)
+""")
} else {
asmgen.out("""
lda ${value.name}+1
bmi $asmLabel
bne +
lda ${value.name}
beq $asmLabel
+""")
}
asmgen.translate(stmt.elseScope)
} else {
val afterIfLabel = asmgen.makeLabel("afterif")
if(stmt.hasElse()) {
// if and else blocks
val elseLabel = asmgen.makeLabel("else")
asmgen.out("""
lda ${value.name}+1
bmi +
bne $elseLabel
lda ${value.name}
bne $elseLabel
+""")
asmgen.translate(stmt.ifScope)
asmgen.jmp(afterIfLabel, false)
asmgen.out(elseLabel)
asmgen.translate(stmt.elseScope)
} else {
// no else block
asmgen.out("""
lda ${value.name}+1
bmi +
bne $afterIfLabel
lda ${value.name}
bne $afterIfLabel
+""")
asmgen.translate(stmt.ifScope)
}
asmgen.out(afterIfLabel)
}
return
}
asmgen.assignExpressionToRegister(value, RegisterOrPair.AY, true)
if(jump!=null) {
val (asmLabel, indirect) = asmgen.getJumpTarget(jump)
if(indirect) {
@ -1097,7 +859,63 @@ _jump jmp ($asmLabel)
private fun wordGreaterZero(value: PtExpression, signed: Boolean, jump: PtJump?, stmt: PtIfElse) {
if(signed) {
// word > 0
asmgen.assignExpressionToRegister(value, RegisterOrPair.AY, true) // TODO optimize this even further by doing MSB/LSB separately
if(value is PtIdentifier) {
// special optimization to compare msb/lsb separately
// TODO also do this for array?
if(jump!=null) {
val (asmLabel, indirect) = asmgen.getJumpTarget(jump)
if(indirect) {
asmgen.out("""
lda ${value.name}+1
bmi ++
bne +
lda ${value.name}
beq ++
+ jmp ($asmLabel)
+""")
} else {
asmgen.out("""
lda ${value.name}+1
bmi +
bne $asmLabel
lda ${value.name}
bne $asmLabel
+""")
}
asmgen.translate(stmt.elseScope)
} else {
val afterIfLabel = asmgen.makeLabel("afterif")
if(stmt.hasElse()) {
// if and else blocks
val elseLabel = asmgen.makeLabel("else")
asmgen.out("""
lda ${value.name}+1
bmi $elseLabel
bne +
lda ${value.name}
beq $elseLabel
+""")
asmgen.translate(stmt.ifScope)
asmgen.jmp(afterIfLabel, false)
asmgen.out(elseLabel)
asmgen.translate(stmt.elseScope)
} else {
// no else block
asmgen.out("""
lda ${value.name}+1
bmi $afterIfLabel
bne +
lda ${value.name}
beq $afterIfLabel
+""")
asmgen.translate(stmt.ifScope)
}
asmgen.out(afterIfLabel)
}
return
}
asmgen.assignExpressionToRegister(value, RegisterOrPair.AY, true)
if(jump!=null) {
val (asmLabel, indirect) = asmgen.getJumpTarget(jump)
if(indirect) {

View File

@ -103,8 +103,7 @@ internal class BeforeAsmAstChanger(val program: Program, private val options: Co
}
override fun after(ifElse: IfElse, parent: Node): Iterable<IAstModification> {
val binExpr = ifElse.condition as? BinaryExpression
if(binExpr!=null) {
val binExpr = ifElse.condition as? BinaryExpression ?: return noModifications
if(binExpr.operator !in ComparisonOperators) {
val constRight = binExpr.right.constValue(program)
if(constRight!=null) {
@ -123,40 +122,61 @@ internal class BeforeAsmAstChanger(val program: Program, private val options: Co
}
}
if((binExpr.left as? NumericLiteral)?.number==0.0 &&
if(binExpr.operator=="==" &&
(binExpr.left as? NumericLiteral)?.number==0.0 &&
(binExpr.right as? NumericLiteral)?.number!=0.0)
throw InternalCompilerException("0==X should be just X")
}
throw InternalCompilerException("0==X should be just X ${binExpr.position}")
return noModifications
}
override fun after(expr: BinaryExpression, parent: Node): Iterable<IAstModification> {
if(options.compTarget.name!=VMTarget.NAME) {
val rightNum = expr.right.constValue(program)
if(rightNum!=null && rightNum.type in IntegerDatatypes) {
//val signed = expr.left.inferType(program).getOr(DataType.UNDEFINED) in SignedDatatypes
when(expr.operator) {
">" -> {
// X>N -> X>=N+1, easier to do in 6502
// TODO check if useful for words as well
val maximum = if(rightNum.type in ByteDatatypes) 255 else 65535
if(rightNum.number<maximum) {
val numPlusOne = rightNum.number.toInt()+1
val newExpr = BinaryExpression(expr.left, ">=", NumericLiteral(rightNum.type, numPlusOne.toDouble(), rightNum.position), expr.position)
return listOf(IAstModification.ReplaceNode(expr, newExpr, parent))
}
if (options.compTarget.name == VMTarget.NAME)
return noModifications
val rightDt = expr.right.inferType(program)
val rightNum = expr.right.constValue(program)
if(rightDt.isWords && (rightNum==null || rightNum.number!=0.0)) {
when (expr.operator) {
">" -> {
// X>Y -> Y<X , easier to do in 6502
expr.operator = "<"
val left = expr.left
expr.left = expr.right
expr.right = left
return noModifications
}
"<=" -> {
// X<=Y -> Y>=X , easier to do in 6502
expr.operator = ">="
val left = expr.left
expr.left = expr.right
expr.right = left
return noModifications
}
}
}
if(rightNum!=null && rightNum.type in IntegerDatatypes && rightNum.number!=0.0) {
when(expr.operator) {
">" -> {
// X>N -> X>=N+1, easier to do in 6502
val maximum = if(rightNum.type in ByteDatatypes) 255 else 65535
if(rightNum.number<maximum) {
val numPlusOne = rightNum.number.toInt()+1
val newExpr = BinaryExpression(expr.left, ">=", NumericLiteral(rightNum.type, numPlusOne.toDouble(), rightNum.position), expr.position)
return listOf(IAstModification.ReplaceNode(expr, newExpr, parent))
}
"<=" -> {
// X<=N -> X<N+1, easier to do in 6502
// TODO check if useful for words as well
val maximum = if(rightNum.type in ByteDatatypes) 255 else 65535
if(rightNum.number<maximum) {
val numPlusOne = rightNum.number.toInt()+1
val newExpr = BinaryExpression(expr.left, "<", NumericLiteral(rightNum.type, numPlusOne.toDouble(), rightNum.position), expr.position)
return listOf(IAstModification.ReplaceNode(expr, newExpr, parent))
}
}
"<=" -> {
// X<=N -> X<N+1, easier to do in 6502
val maximum = if(rightNum.type in ByteDatatypes) 255 else 65535
if(rightNum.number<maximum) {
val numPlusOne = rightNum.number.toInt()+1
val newExpr = BinaryExpression(expr.left, "<", NumericLiteral(rightNum.type, numPlusOne.toDouble(), rightNum.position), expr.position)
return listOf(IAstModification.ReplaceNode(expr, newExpr, parent))
}
}
}

View File

@ -367,8 +367,8 @@ main {
main {
sub start() {
byte bb = -10
word ww = -1000
byte @shared bb = -10
word @shared ww = -1000
if bb>0 {
bb++
@ -413,11 +413,11 @@ main {
val text = """
main {
sub start() {
byte bb
word ww
byte @shared bb
word @shared ww
bool iteration_in_progress
uword num_bytes
bool @shared iteration_in_progress
uword @shared num_bytes
if not iteration_in_progress or num_bytes==0 {
num_bytes++
@ -455,10 +455,10 @@ main {
val text = """
main {
sub start() {
byte ub1 = -50
byte ub2 = -51
byte ub3 = -52
byte ub4 = 100
byte @shared ub1 = -50
byte @shared ub2 = -51
byte @shared ub3 = -52
byte @shared ub4 = 100
word @shared ww = func(ub1, ub2, ub3, ub4)
ww = func(ub4, ub2, ub3, ub1)
ww=afunc(ub1, ub2, ub3, ub4)

View File

@ -1,33 +1,16 @@
TODO
====
optimize signed word wordGreaterValue, wordLessEqualsValue (can it be without scratch vars?)
optimize signed word wordGreaterZero, wordLessEqualsZero (by comparing msb/lsb separately?)
floatparse is a lot larger
snow is a lot larger
neofetch is larger
chess is larger
verify ifelse codegens to be shortest code: (some are using too many scratch vars?)
uword >=
uword >
uword <=
uword <
word >=
word >
word <=
word <
explore possible optimizations for words when comparing to a constant number (BeforeAsmAstChanger)
floatparse is a bit larger
testgfx2 is a quite a bit larger
amiga is a bit larger
halloween is 1 byte larger
rockrunner is bigger than on 10.1
paint is slightly bigger than on 10.1
chess is bigger than on 10.1
imageviewer is a lot bigger
shell is a couple of bytes bigger
add tests for comparison that do an assignment rather than an if
assign to variable, and barray[indexvar], test if they're both correct
(bb = value > -100 --> contains a beq +++ that shouldn't be there??)

View File

@ -5,24 +5,10 @@
main {
sub start() {
if cx16.r0sL > 10
if cx16.r0s > 0
cx16.r1L++
if cx16.r0sL >= 10
if cx16.r0s <= 0
cx16.r1L++
if cx16.r0sL < 10
cx16.r1L++
if cx16.r0sL <= 10
cx16.r1L++
}
sub ub() -> ubyte {
cx16.r0++
return cx16.r0L
}
sub sb() -> byte {
cx16.r0++
return cx16.r0sL
}
}