ifelse more

This commit is contained in:
Irmen de Jong 2024-02-16 22:35:09 +01:00
parent c77cd0da39
commit e1a133c2c0
4 changed files with 647 additions and 70 deletions

View File

@ -156,26 +156,8 @@ internal class IfElseAsmGen(private val program: PtProgram,
translateIfElseBodies("bcs", stmt)
}
}
"<=" -> {
fallbackTranslate(stmt, true)
// asmgen.assignExpressionToRegister(condition.left, RegisterOrPair.A, signed)
// cmpAwithByteValue(condition.right)
// if(signed) {
// TODO("byte if <=")
// } else {
// TODO("ubyte if <=")
// }
}
">" -> {
fallbackTranslate(stmt, true)
// asmgen.assignExpressionToRegister(condition.left, RegisterOrPair.A, signed)
// cmpAwithByteValue(condition.right)
// return if(signed) {
// TODO("byte if >")
// } else {
// TODO("ubyte if >")
// }
}
"<=" -> translateByteLessEqual(stmt, signed, jumpAfterIf)
">" -> translateByteGreater(stmt, signed, jumpAfterIf)
">=" -> {
asmgen.assignExpressionToRegister(condition.left, RegisterOrPair.A, signed)
cmpAwithByteValue(condition.right)
@ -240,66 +222,544 @@ internal class IfElseAsmGen(private val program: PtProgram,
}
}
private fun translateByteLessEqual(stmt: PtIfElse, signed: Boolean, jumpAfterIf: PtJump?) {
fun bodies(greaterBranches: Pair<String, String>, stmt: PtIfElse) {
// comparison value is already in A
val afterIfLabel = asmgen.makeLabel("afterif")
if(stmt.hasElse()) {
// if and else blocks
val elseLabel = asmgen.makeLabel("else")
asmgen.out("""
${greaterBranches.first} +
${greaterBranches.second} $elseLabel
+""")
asmgen.translate(stmt.ifScope)
asmgen.jmp(afterIfLabel, false)
asmgen.out(elseLabel)
asmgen.translate(stmt.elseScope)
} else {
// no else block
asmgen.out("""
${greaterBranches.first} +
${greaterBranches.second} $afterIfLabel
+""")
asmgen.translate(stmt.ifScope)
}
asmgen.out(afterIfLabel)
}
fun bodies(
branches: Pair<String, String>,
greaterBranches: Pair<String, String>,
jump: PtJump,
elseBlock: PtNodeGroup
) {
// comparison value is already in A
val (asmLabel, indirect) = asmgen.getJumpTarget(jump)
if(indirect) {
asmgen.out("""
${greaterBranches.first} +
${greaterBranches.second} ++
+ jmp ($asmLabel)
+""")
} else {
asmgen.out(" ${branches.first} $asmLabel | ${branches.second} $asmLabel")
}
asmgen.translate(elseBlock)
}
val condition = stmt.condition as PtBinaryExpression
asmgen.assignExpressionToRegister(condition.left, RegisterOrPair.A, signed)
cmpAwithByteValue(condition.right)
if(signed) {
if(jumpAfterIf!=null) {
bodies("bmi" to "beq", "beq" to "bpl", jumpAfterIf, stmt.elseScope)
} else {
bodies("beq" to "bpl", stmt)
}
} else {
if(jumpAfterIf!=null) {
bodies("bcc" to "beq", "beq" to "bcs", jumpAfterIf, stmt.elseScope)
} else {
bodies("beq" to "bcs", stmt)
}
}
}
private fun translateByteGreater(stmt: PtIfElse, signed: Boolean, jumpAfterIf: PtJump?) {
fun bodies(lessEqBranches: Pair<String, String>, stmt: PtIfElse) {
// comparison value is already in A
val afterIfLabel = asmgen.makeLabel("afterif")
if(stmt.hasElse()) {
// if and else blocks
val elseLabel = asmgen.makeLabel("else")
asmgen.out(" ${lessEqBranches.first} $elseLabel | ${lessEqBranches.second} $elseLabel")
asmgen.translate(stmt.ifScope)
asmgen.jmp(afterIfLabel, false)
asmgen.out(elseLabel)
asmgen.translate(stmt.elseScope)
} else {
// no else block
asmgen.out(" ${lessEqBranches.first} $afterIfLabel | ${lessEqBranches.second} $afterIfLabel")
asmgen.translate(stmt.ifScope)
}
asmgen.out(afterIfLabel)
}
fun bodies(
branches: Pair<String, String>,
lessEqBranches: Pair<String, String>,
jump: PtJump,
elseBlock: PtNodeGroup
) {
// comparison value is already in A
val (asmLabel, indirect) = asmgen.getJumpTarget(jump)
if(indirect) {
asmgen.out("""
${lessEqBranches.first} +
${lessEqBranches.second} +
jmp ($asmLabel)
+""")
} else {
asmgen.out("""
${branches.first} +
${branches.second} $asmLabel
+""")
}
asmgen.translate(elseBlock)
}
val condition = stmt.condition as PtBinaryExpression
asmgen.assignExpressionToRegister(condition.left, RegisterOrPair.A, signed)
cmpAwithByteValue(condition.right)
if(signed) {
if(jumpAfterIf!=null) {
bodies("beq" to "bpl", "bmi" to "beq", jumpAfterIf, stmt.elseScope)
} else {
bodies("bmi" to "beq", stmt)
}
} else {
if(jumpAfterIf!=null) {
bodies("beq" to "bcs", "bcc" to "beq", jumpAfterIf, stmt.elseScope)
} else {
bodies("bcc" to "beq", stmt)
}
}
}
private fun translateIfWord(stmt: PtIfElse, condition: PtBinaryExpression, jumpAfterIf: PtJump?) {
val signed = condition.left.type in SignedDatatypes
val constValue = condition.right.asConstInteger()
if(constValue==0) {
if(condition.operator=="==") {
// if X==0
// TODO even more optimized code by comparing lsb and msb separately
asmgen.assignExpressionToRegister(condition.left, RegisterOrPair.AY, signed)
asmgen.out(" sty P8ZP_SCRATCH_REG | ora P8ZP_SCRATCH_REG")
return if(jumpAfterIf!=null)
translateJumpElseBodies("beq", "bne", jumpAfterIf, stmt.elseScope)
else
translateIfElseBodies("bne", stmt)
} else if(condition.operator=="!=") {
// if X!=0
// TODO even more optimized code by comparing lsb and msb separately
asmgen.assignExpressionToRegister(condition.left, RegisterOrPair.AY, signed)
asmgen.out(" sty P8ZP_SCRATCH_REG | ora P8ZP_SCRATCH_REG")
return if(jumpAfterIf!=null)
translateJumpElseBodies("bne", "beq", jumpAfterIf, stmt.elseScope)
else
translateIfElseBodies("beq", stmt)
// optimized comparisons with zero
when (condition.operator) {
"==" -> return wordEqualsZero(condition.left, false, signed, jumpAfterIf, stmt)
"!=" -> return wordEqualsZero(condition.left, true, signed, jumpAfterIf, stmt)
"<" -> return wordLessZero(condition.left, signed, jumpAfterIf, stmt)
"<=" -> return wordLessEqualsZero(condition.left, signed, jumpAfterIf, stmt)
">" -> return wordGreaterZero(condition.left, signed, jumpAfterIf, stmt)
">=" -> return wordGreaterEqualsZero(condition.left, signed, jumpAfterIf, stmt)
}
}
// non-zero comparisons
when(condition.operator) {
"==" -> {
// TODO
println("word if ==")
fallbackTranslate(stmt)
}
"!=" -> {
// TODO
println("word if !=")
fallbackTranslate(stmt)
}
"<" -> {
// TODO()
println("word if <")
fallbackTranslate(stmt)
}
"<=" -> {
// TODO()
println("word if <=")
fallbackTranslate(stmt)
}
">" -> {
// TODO()
println("word if >")
fallbackTranslate(stmt)
}
">=" -> {
// TODO()
println("word if >=")
fallbackTranslate(stmt)
}
"==" -> 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)
">=" -> wordGreaterEqualsValue(condition.left, condition.right, signed, jumpAfterIf, stmt)
else -> fallbackTranslate(stmt, false)
}
}
private fun wordGreaterEqualsZero(value: PtExpression, signed: Boolean, jump: PtJump?, stmt: PtIfElse) {
// special case for word>=0
if(signed) {
loadAndCmp0MSB(value)
if (jump != null)
translateJumpElseBodies("bpl", "bmi", jump, stmt.elseScope)
else
translateIfElseBodies("bmi", stmt)
} else {
asmgen.translate(stmt.ifScope)
}
}
private fun wordLessZero(value: PtExpression, signed: Boolean, jump: PtJump?, stmt: PtIfElse) {
if(signed) {
loadAndCmp0MSB(value)
if (jump != null)
translateJumpElseBodies("bmi", "bpl", jump, stmt.elseScope)
else
translateIfElseBodies("bpl", stmt)
} else {
asmgen.translate(stmt.elseScope)
}
}
private fun wordLessValue(left: PtExpression, right: PtExpression, signed: Boolean, jump: PtJump?, stmt: PtIfElse) {
println("word if <") // TODO
fallbackTranslate(stmt)
}
private fun wordGreaterValue(left: PtExpression, right: PtExpression, signed: Boolean, jump: PtJump?, stmt: PtIfElse) {
println("word if >") // TODO
fallbackTranslate(stmt)
}
private fun wordLessEqualsValue(left: PtExpression, right: PtExpression, signed: Boolean, jump: PtJump?, stmt: PtIfElse) {
println("word if <=") // TODO
fallbackTranslate(stmt)
}
private fun wordGreaterEqualsValue(left: PtExpression, right: PtExpression, signed: Boolean, jump: PtJump?, stmt: PtIfElse) {
println("word if >=") // TODO
fallbackTranslate(stmt)
}
private fun loadAndCmp0MSB(value: PtExpression) {
when(value) {
is PtArrayIndexer -> {
val varname = asmgen.asmVariableName(value.variable)
asmgen.loadScaledArrayIndexIntoRegister(value, CpuRegister.Y)
asmgen.out(" lda $varname+1,y")
}
is PtIdentifier -> {
val varname = asmgen.asmVariableName(value)
asmgen.out(" lda $varname+1")
}
else -> {
asmgen.assignExpressionToRegister(value, RegisterOrPair.AY, true)
asmgen.out(" cmp #0")
}
}
}
private fun wordLessEqualsZero(value: PtExpression, signed: Boolean, jump: PtJump?, stmt: PtIfElse) {
return if(signed) {
asmgen.assignExpressionToRegister(value, RegisterOrPair.AY, true) // TODO optimize this even further by doing MSB/LSB separately
if(jump!=null) {
val (asmLabel, indirect) = asmgen.getJumpTarget(jump)
if(indirect) {
asmgen.out("""
cpy #0
bmi +
bne ++
cmp #0
bne ++
+ jmp ($asmLabel)
+""")
} else {
asmgen.out("""
cpy #0
bmi $asmLabel
bne +
cmp #0
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("""
cpy #0
bmi +
bne $elseLabel
cmp #0
bne $elseLabel
+""")
asmgen.translate(stmt.ifScope)
asmgen.jmp(afterIfLabel, false)
asmgen.out(elseLabel)
asmgen.translate(stmt.elseScope)
} else {
// no else block
asmgen.out("""
cpy #0
bmi +
bne $afterIfLabel
cmp #0
bne $afterIfLabel
+""")
asmgen.translate(stmt.ifScope)
}
asmgen.out(afterIfLabel)
}
} else {
wordEqualsZero(value, true, false, jump, stmt)
}
}
private fun wordGreaterZero(value: PtExpression, signed: Boolean, jump: PtJump?, stmt: PtIfElse) {
if(signed) {
asmgen.assignExpressionToRegister(value, RegisterOrPair.AY, true) // TODO optimize this even further by doing MSB/LSB separately
if(jump!=null) {
val (asmLabel, indirect) = asmgen.getJumpTarget(jump)
if(indirect) {
asmgen.out("""
cpy #0
bmi ++
bne +
cmp #0
beq ++
+ jmp ($asmLabel)
+""")
} else {
asmgen.out("""
cpy #0
bmi +
bne $asmLabel
cmp #0
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("""
cpy #0
bmi $elseLabel
bne +
cmp #0
beq $elseLabel
+""")
asmgen.translate(stmt.ifScope)
asmgen.jmp(afterIfLabel, false)
asmgen.out(elseLabel)
asmgen.translate(stmt.elseScope)
} else {
// no else block
asmgen.out("""
cpy #0
bmi $afterIfLabel
bne +
cmp #0
beq $afterIfLabel
+""")
asmgen.translate(stmt.ifScope)
}
asmgen.out(afterIfLabel)
}
} else {
wordEqualsZero(value, true, false, jump, stmt)
}
}
private fun wordEqualsZero(value: PtExpression, notEquals: Boolean, signed: Boolean, jump: PtJump?, stmt: PtIfElse) {
fun viaScratchReg(branchInstr: String, falseBranch: String) {
asmgen.assignExpressionToRegister(value, RegisterOrPair.AY, signed)
asmgen.out(" sty P8ZP_SCRATCH_REG | ora P8ZP_SCRATCH_REG")
if(jump!=null)
translateJumpElseBodies(branchInstr, falseBranch, jump, stmt.elseScope)
else
translateIfElseBodies(falseBranch, stmt)
}
fun translateLoadFromVar(variable: String, branch: String, falseBranch: String) {
asmgen.out(" lda $variable | ora $variable+1")
return if(jump!=null)
translateJumpElseBodies(branch, falseBranch, jump, stmt.elseScope)
else
translateIfElseBodies(falseBranch, stmt)
}
if(notEquals) {
when(value) {
is PtArrayIndexer -> {
val constIndex = value.index.asConstInteger()
if(constIndex!=null) {
val offset = constIndex * program.memsizer.memorySize(value.type)
if(offset<256) {
val varName = asmgen.asmVariableName(value.variable)
return translateLoadFromVar("$varName+$offset", "bne", "beq")
}
}
viaScratchReg("bne", "beq")
}
is PtIdentifier -> {
return translateLoadFromVar(asmgen.asmVariableName(value), "bne", "beq")
}
else -> viaScratchReg("bne", "beq")
}
} else {
when (value) {
is PtArrayIndexer -> {
val constIndex = value.index.asConstInteger()
if(constIndex!=null) {
val offset = constIndex * program.memsizer.memorySize(value.type)
if(offset<256) {
val varName = asmgen.asmVariableName(value.variable)
return translateLoadFromVar("$varName+$offset", "beq", "bne")
}
}
viaScratchReg("beq", "bne")
}
is PtIdentifier -> {
return translateLoadFromVar(asmgen.asmVariableName(value), "beq", "bne")
}
else -> viaScratchReg("beq", "bne")
}
}
}
private fun wordEqualsValue(
left: PtExpression,
right: PtExpression,
notEquals: Boolean,
signed: Boolean,
jump: PtJump?,
stmt: PtIfElse
) {
fun translateLoadFromVarNotEquals(varname: String) {
if(jump!=null) {
val (asmLabel, indirect) = asmgen.getJumpTarget(jump)
if(indirect) {
asmgen.out("""
cmp $varname
bne +
cpy $varname+1
beq ++
+ jmp ($asmLabel)
+""")
} else {
asmgen.out("""
cmp $varname
bne $asmLabel
cpy $varname+1
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("""
cmp $varname
bne +
cpy $varname+1
beq $elseLabel
+""")
asmgen.translate(stmt.ifScope)
asmgen.jmp(afterIfLabel, false)
asmgen.out(elseLabel)
asmgen.translate(stmt.elseScope)
} else {
// no else block
asmgen.out("""
cmp $varname
bne +
cpy $varname+1
beq $afterIfLabel
+""")
asmgen.translate(stmt.ifScope)
}
asmgen.out(afterIfLabel)
}
}
fun translateLoadFromVarEquals(varname: String) {
return if(jump!=null) {
val (asmLabel, indirect) = asmgen.getJumpTarget(jump)
if(indirect) {
asmgen.out("""
cmp $varname
bne +
cpy $varname+1
bne +
jmp ($asmLabel)
+""")
} else {
asmgen.out("""
cmp $varname
bne +
cpy $varname+1
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("""
cmp $varname
bne $elseLabel
cpy $varname+1
bne $elseLabel""")
asmgen.translate(stmt.ifScope)
asmgen.jmp(afterIfLabel, false)
asmgen.out(elseLabel)
asmgen.translate(stmt.elseScope)
} else {
// no else block
asmgen.out("""
cmp $varname
bne $afterIfLabel
cpy $varname+1
bne $afterIfLabel""")
asmgen.translate(stmt.ifScope)
}
asmgen.out(afterIfLabel)
}
}
if(notEquals) {
when(left) {
is PtArrayIndexer -> {
asmgen.assignExpressionToRegister(right, RegisterOrPair.AY, signed)
val constIndex = left.index.asConstInteger()
if(constIndex!=null) {
val offset = constIndex * program.memsizer.memorySize(left.type)
if(offset<256) {
val varName = asmgen.asmVariableName(left.variable)
return translateLoadFromVarNotEquals("$varName+$offset")
}
}
fallbackTranslate(stmt, false)
}
is PtIdentifier -> {
asmgen.assignExpressionToRegister(right, RegisterOrPair.AY, signed)
return translateLoadFromVarNotEquals(asmgen.asmVariableName(left))
}
else -> fallbackTranslate(stmt, false)
}
} else {
when(left) {
is PtArrayIndexer -> {
asmgen.assignExpressionToRegister(right, RegisterOrPair.AY, signed)
val constIndex = left.index.asConstInteger()
if(constIndex!=null) {
val offset = constIndex * program.memsizer.memorySize(left.type)
if(offset<256) {
val varName = asmgen.asmVariableName(left.variable)
return translateLoadFromVarEquals("$varName+$offset")
}
}
fallbackTranslate(stmt, false)
}
is PtIdentifier -> {
asmgen.assignExpressionToRegister(right, RegisterOrPair.AY, signed)
return translateLoadFromVarEquals(asmgen.asmVariableName(left))
}
else -> fallbackTranslate(stmt, false)
}
}
}
private fun translateIfFloat(stmt: PtIfElse, condition: PtBinaryExpression, jumpAfterIf: PtJump?) {
val constValue = (condition.right as? PtNumber)?.number
if(constValue==0.0) {

View File

@ -2091,7 +2091,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
throw AssemblyError("can't store word into memory byte")
}
TargetStorageKind.ARRAY -> {
asmgen.out(" lda #<$sourceName | ldy #>$sourceName")
asmgen.out(" lda #<$sourceName | ldy #>$sourceName")
assignRegisterpairWord(target, RegisterOrPair.AY)
}
TargetStorageKind.REGISTER -> {

View File

@ -1,6 +1,12 @@
TODO
====
examples/primes is larger than on 10.1
examples/maze is larger than on 10.1
examples/textelite is larger than on 10.1
===== ====== =======
VM 6502 what
===== ====== =======
@ -44,6 +50,9 @@ ok . check program sizes vs. master branch
===== ====== =======
retest all comparisons in if statements (byte, word, signed and unsigned) + all comparison assignments. Against 0 and something else as 0.
with jump, indirect jump, no else block, and both if+else blocks.
check that the flood fill routine in gfx2 and paint still works.
re-allow typecast of const true/false back to ubytes 1 and 0.
re-allow typecast of const ubyte 0/1 to false/true boolean.

View File

@ -6,8 +6,98 @@
main {
bool @shared staticbool1 = true
bool @shared staticbool2
word[4] words
byte @shared sbb
sub start() {
while cx16.r0s < 1234
cx16.r0L++
loop:
if cx16.r0s >= 1234
goto skip
cx16.r0L++
goto loop
skip:
; TODO all this for uwords
; if sbb<0
; cx16.r0L++
; if sbb>0
; cx16.r0L++
; if sbb<=0
; cx16.r0L++
; if sbb>=0
; cx16.r0L++
; if cx16.r0s<0
; cx16.r0L++
; if cx16.r0s>0
; cx16.r0L++
; if cx16.r0s>0
; goto start
; if cx16.r0s>0
; goto cx16.r0
; if cx16.r0s<=0
; cx16.r0L++
; else
; cx16.r0L++
; if cx16.r0s>=0
; cx16.r0L++
; if words[2]<0
; cx16.r0L++
; if words[2]>0
; cx16.r0L++
; if words[2]<=0
; cx16.r0L++
; if words[2]>=0
; cx16.r0L++
; if words[cx16.r0L]<0
; cx16.r0L++
; if words[cx16.r0L]>0
; cx16.r0L++
; if words[cx16.r0L]<=0
; cx16.r0L++
; if words[cx16.r0L]>=0
; cx16.r0L++
; staticbool2 = sbb < 0
; staticbool2 = sbb > 0
; staticbool1 = sbb <= 0
; staticbool1 = sbb >= 0
; staticbool2 = cx16.r0s <0
; staticbool2 = cx16.r0s >0
; staticbool1 = cx16.r0s <=0
; staticbool1 = cx16.r0s >=0
; staticbool2 = words[2]<0
; staticbool2 = words[2]>0
; staticbool1 = words[2]<=0
; staticbool1 = words[2]>=0
; staticbool2 = words[cx16.r0L]<0
; staticbool2 = words[cx16.r0L]>0
; staticbool1 = words[cx16.r0L]<=0
; staticbool1 = words[cx16.r0L]>=0
; if cx16.r0 > 1234
; cx16.r0L++
; if cx16.r0s > 1234
; cx16.r0L++
; if cx16.r0 < 1234
; cx16.r0L++
; if cx16.r0s < 1234
; cx16.r0L++
; if cx16.r0 >= 1234
; cx16.r0L++
; if cx16.r0s >= 1234
; cx16.r0L++
; if cx16.r0 <= 1234
; cx16.r0L++
; if cx16.r0s <= 1234
; cx16.r0L++
; boolean_const_and_var(true)
; staticbool1 = boolean_arrays_and_return()
; txt.print_ub(staticbool1 as ubyte)
@ -27,7 +117,7 @@ main {
; efficient_compare_99()
; efficient_compare_var()
; efficient_assign_cmp_0()
efficient_assign_cmp_99()
; efficient_assign_cmp_99()
; efficient_assign_cmp_var()
; if_gotos()
; if_code()
@ -472,6 +562,7 @@ main {
sub if_code() {
ubyte @shared ub
byte @shared sb
bool @shared bb
if ub==0
cx16.r0L++
@ -498,6 +589,23 @@ main {
cx16.r0L++
else
cx16.r0--
if ub>10
cx16.r0++
if ub>=10
cx16.r0++
if ub<10
cx16.r0++
if ub<=10
cx16.r0++
if sb>10
cx16.r0++
if sb>=10
cx16.r0++
if sb<10
cx16.r0++
if sb<=10
cx16.r0++
}
sub intfunc() -> ubyte {