fix missing cmp #0 when asmsub call is part of a boolean expression

This commit is contained in:
Irmen de Jong
2025-06-02 19:22:00 +02:00
parent a228908c1a
commit 552e55c29f
2 changed files with 48 additions and 781 deletions

View File

@@ -1740,6 +1740,17 @@ internal class AssignmentAsmGen(
}
}
fun requiresCmp(expr: PtExpression) =
when (expr) {
is PtFunctionCall -> {
val function = asmgen.symbolTable.lookup(expr.name)
function is StExtSub // don't assume the extsub/asmsub has set the cpu flags correctly on exit, add an explicit cmp
}
is PtBuiltinFunctionCall -> true
is PtIfExpression -> true
else -> false
}
if(!expr.right.isSimple() && expr.operator!="xor") {
// shortcircuit evaluation into A
val shortcutLabel = asmgen.makeLabel("shortcut")
@@ -1747,15 +1758,23 @@ internal class AssignmentAsmGen(
"and" -> {
// short-circuit LEFT and RIGHT --> if LEFT then RIGHT else LEFT (== if !LEFT then LEFT else RIGHT)
assignExpressionToRegister(expr.left, RegisterOrPair.A, false)
if(requiresCmp(expr.left))
asmgen.out(" cmp #0")
asmgen.out(" beq $shortcutLabel")
assignExpressionToRegister(expr.right, RegisterOrPair.A, false)
if(requiresCmp(expr.right))
asmgen.out(" cmp #0")
asmgen.out(shortcutLabel)
}
"or" -> {
// short-circuit LEFT or RIGHT --> if LEFT then LEFT else RIGHT
assignExpressionToRegister(expr.left, RegisterOrPair.A, false)
if(requiresCmp(expr.left))
asmgen.out(" cmp #0")
asmgen.out(" bne $shortcutLabel")
assignExpressionToRegister(expr.right, RegisterOrPair.A, false)
if(requiresCmp(expr.right))
asmgen.out(" cmp #0")
asmgen.out(shortcutLabel)
}
else -> throw AssemblyError("invalid logical operator")

View File

@@ -3,798 +3,46 @@
main {
sub start() {
txt.plot(0, 49)
bytesoverflow()
bytesoverflow_jump()
bytesoverflow_jump_indirect()
bytessmall()
bytessmall_jump()
bytessmall_jump_indirect()
bytes99()
bytes100()
bytes101()
words()
zerobytes()
zerowords()
}
bool @shared bb, bb2
sub zerobytes() {
byte @shared sb = -100
byte @shared p = 0
const byte cb = -100
bb=true
bb2=false
txt.print("\nsigned bytes with 0\n")
txt.print("expected: ")
txt.print_b(cb)
txt.spc()
txt.print_bool(cb>0)
txt.spc()
txt.print_bool(cb>=0)
txt.spc()
txt.print_bool(cb<0)
txt.spc()
txt.print_bool(cb<=0)
txt.nl()
if bb and test() and testasm()
txt.print("yes1 ")
else
txt.print("error1 ")
txt.print(" calc'd: ")
txt.print_b(sb)
txt.spc()
txt.print_bool(sb>0)
txt.spc()
txt.print_bool(sb>=0)
txt.spc()
txt.print_bool(sb<0)
txt.spc()
txt.print_bool(sb<=0)
txt.nl()
txt.print("calc'd 2: ")
txt.print_b(sb)
txt.spc()
txt.print_bool(sb>p)
txt.spc()
txt.print_bool(sb>=p)
txt.spc()
txt.print_bool(sb<p)
txt.spc()
txt.print_bool(sb<=p)
txt.nl()
txt.print(" if stmt: ")
txt.print_b(sb)
txt.spc()
if sb>0 txt.print("true ") else txt.print("false ")
if sb>=0 txt.print("true ") else txt.print("false ")
if sb<0 txt.print("true ") else txt.print("false ")
if sb<=0 txt.print("true ") else txt.print("false ")
txt.nl()
txt.print(" ifstmt2: ")
txt.print_b(sb)
txt.spc()
if sb>p txt.print("true ") else txt.print("false ")
if sb>=p txt.print("true ") else txt.print("false ")
if sb<p txt.print("true ") else txt.print("false ")
if sb<=p txt.print("true ") else txt.print("false ")
if bb2 or test2() or testasm2()
txt.print("error2 ")
else
txt.print("yes2 ")
txt.nl()
}
sub zerowords() {
word @shared sbw = -30000
word @shared pw = 0
const word cbw = -30000
txt.print("\nsigned words\n")
txt.print("expected: ")
txt.print_w(cbw)
txt.spc()
txt.print_bool(cbw>0)
txt.spc()
txt.print_bool(cbw>=0)
txt.spc()
txt.print_bool(cbw<0)
txt.spc()
txt.print_bool(cbw<=0)
txt.nl()
txt.print(" calc'd: ")
txt.print_w(sbw)
txt.spc()
txt.print_bool(sbw>0)
txt.spc()
txt.print_bool(sbw>=0)
txt.spc()
txt.print_bool(sbw<0)
txt.spc()
txt.print_bool(sbw<=0)
txt.nl()
txt.print("calc'd 2: ")
txt.print_w(sbw)
txt.spc()
txt.print_bool(sbw>pw)
txt.spc()
txt.print_bool(sbw>=pw)
txt.spc()
txt.print_bool(sbw<pw)
txt.spc()
txt.print_bool(sbw<=pw)
txt.nl()
txt.print(" if stmt: ")
txt.print_w(sbw)
txt.spc()
if sbw>0 txt.print("true ") else txt.print("false ")
if sbw>=0 txt.print("true ") else txt.print("false ")
if sbw<0 txt.print("true ") else txt.print("false ")
if sbw<=0 txt.print("true ") else txt.print("false ")
txt.nl()
txt.print(" ifstmt2: ")
txt.print_w(sbw)
txt.spc()
if sbw>pw txt.print("true ") else txt.print("false ")
if sbw>=pw txt.print("true ") else txt.print("false ")
if sbw<pw txt.print("true ") else txt.print("false ")
if sbw<=pw txt.print("true ") else txt.print("false ")
txt.nl()
sub test() -> bool {
cx16.r0++
return true
}
sub bytes99() {
const byte cb = 99
byte @shared sb = 99
byte @shared p = 100
txt.print("\nsigned bytes, 99\n")
txt.print("expected: ")
txt.print_b(100)
txt.spc()
txt.print_bool(cb>100)
txt.spc()
txt.print_bool(cb>=100)
txt.spc()
txt.print_bool(cb<100)
txt.spc()
txt.print_bool(cb<=100)
txt.nl()
txt.print(" calc'd: ")
txt.print_b(100)
txt.spc()
txt.print_bool(sb>100)
txt.spc()
txt.print_bool(sb>=100)
txt.spc()
txt.print_bool(sb<100)
txt.spc()
txt.print_bool(sb<=100)
txt.nl()
txt.print("calc'd 2: ")
txt.print_b(p)
txt.spc()
txt.print_bool(sb>p)
txt.spc()
txt.print_bool(sb>=p)
txt.spc()
txt.print_bool(sb<p)
txt.spc()
txt.print_bool(sb<=p)
txt.nl()
txt.print(" if stmt: ")
txt.print_b(100)
txt.spc()
if sb>100 txt.print("true ") else txt.print("false ")
if sb>=100 txt.print("true ") else txt.print("false ")
if sb<100 txt.print("true ") else txt.print("false ")
if sb<=100 txt.print("true ") else txt.print("false ")
txt.nl()
txt.print(" ifstmt2: ")
txt.print_b(p)
txt.spc()
if sb>p txt.print("true ") else txt.print("false ")
if sb>=p txt.print("true ") else txt.print("false ")
if sb<p txt.print("true ") else txt.print("false ")
if sb<=p txt.print("true ") else txt.print("false ")
txt.nl()
sub test2() -> bool {
cx16.r0++
return false
}
sub bytes100() {
const byte cb = 100
byte @shared sb = 100
byte @shared p = 100
txt.print("\nsigned bytes, 100\n")
txt.print("expected: ")
txt.print_b(100)
txt.spc()
txt.print_bool(cb>100)
txt.spc()
txt.print_bool(cb>=100)
txt.spc()
txt.print_bool(cb<100)
txt.spc()
txt.print_bool(cb<=100)
txt.nl()
txt.print(" calc'd: ")
txt.print_b(100)
txt.spc()
txt.print_bool(sb>100)
txt.spc()
txt.print_bool(sb>=100)
txt.spc()
txt.print_bool(sb<100)
txt.spc()
txt.print_bool(sb<=100)
txt.nl()
txt.print("calc'd 2: ")
txt.print_b(p)
txt.spc()
txt.print_bool(sb>p)
txt.spc()
txt.print_bool(sb>=p)
txt.spc()
txt.print_bool(sb<p)
txt.spc()
txt.print_bool(sb<=p)
txt.nl()
txt.print(" if stmt: ")
txt.print_b(100)
txt.spc()
if sb>100 txt.print("true ") else txt.print("false ")
if sb>=100 txt.print("true ") else txt.print("false ")
if sb<100 txt.print("true ") else txt.print("false ")
if sb<=100 txt.print("true ") else txt.print("false ")
txt.nl()
txt.print(" ifstmt2: ")
txt.print_b(p)
txt.spc()
if sb>p txt.print("true ") else txt.print("false ")
if sb>=p txt.print("true ") else txt.print("false ")
if sb<p txt.print("true ") else txt.print("false ")
if sb<=p txt.print("true ") else txt.print("false ")
txt.nl()
asmsub testasm() -> bool @A {
%asm {{
lda #1
ldy #0
rts
}}
}
sub bytes101() {
const byte cb = 101
byte @shared sb = 101
byte @shared p = 100
txt.print("\nsigned bytes, 101\n")
txt.print("expected: ")
txt.print_b(100)
txt.spc()
txt.print_bool(cb>100)
txt.spc()
txt.print_bool(cb>=100)
txt.spc()
txt.print_bool(cb<100)
txt.spc()
txt.print_bool(cb<=100)
txt.nl()
txt.print(" calc'd: ")
txt.print_b(100)
txt.spc()
txt.print_bool(sb>100)
txt.spc()
txt.print_bool(sb>=100)
txt.spc()
txt.print_bool(sb<100)
txt.spc()
txt.print_bool(sb<=100)
txt.nl()
txt.print("calc'd 2: ")
txt.print_b(p)
txt.spc()
txt.print_bool(sb>p)
txt.spc()
txt.print_bool(sb>=p)
txt.spc()
txt.print_bool(sb<p)
txt.spc()
txt.print_bool(sb<=p)
txt.nl()
txt.print(" if stmt: ")
txt.print_b(100)
txt.spc()
if sb>100 txt.print("true ") else txt.print("false ")
if sb>=100 txt.print("true ") else txt.print("false ")
if sb<100 txt.print("true ") else txt.print("false ")
if sb<=100 txt.print("true ") else txt.print("false ")
txt.nl()
txt.print(" ifstmt2: ")
txt.print_b(p)
txt.spc()
if sb>p txt.print("true ") else txt.print("false ")
if sb>=p txt.print("true ") else txt.print("false ")
if sb<p txt.print("true ") else txt.print("false ")
if sb<=p txt.print("true ") else txt.print("false ")
txt.nl()
}
sub bytesoverflow() {
byte @shared sb = -100
byte @shared p = 100
const byte cb = -100
txt.print("\nsigned bytes, overflow\n")
txt.print("expected: ")
txt.print_b(100)
txt.spc()
txt.print_bool(cb>100)
txt.spc()
txt.print_bool(cb>=100)
txt.spc()
txt.print_bool(cb<100)
txt.spc()
txt.print_bool(cb<=100)
txt.nl()
txt.print(" calc'd: ")
txt.print_b(100)
txt.spc()
txt.print_bool(sb>100)
txt.spc()
txt.print_bool(sb>=100)
txt.spc()
txt.print_bool(sb<100)
txt.spc()
txt.print_bool(sb<=100)
txt.nl()
txt.print("calc'd 2: ")
txt.print_b(p)
txt.spc()
txt.print_bool(sb>p)
txt.spc()
txt.print_bool(sb>=p)
txt.spc()
txt.print_bool(sb<p)
txt.spc()
txt.print_bool(sb<=p)
txt.nl()
txt.print(" if stmt: ")
txt.print_b(100)
txt.spc()
if sb>100 txt.print("true ") else txt.print("false ")
if sb>=100 txt.print("true ") else txt.print("false ")
if sb<100 txt.print("true ") else txt.print("false ")
if sb<=100 txt.print("true ") else txt.print("false ")
txt.nl()
txt.print(" ifstmt2: ")
txt.print_b(p)
txt.spc()
if sb>p txt.print("true ") else txt.print("false ")
if sb>=p txt.print("true ") else txt.print("false ")
if sb<p txt.print("true ") else txt.print("false ")
if sb<=p txt.print("true ") else txt.print("false ")
txt.nl()
}
sub bytessmall() {
byte @shared sb = -10
byte @shared p = 10
const byte cb = -10
txt.print("\nsigned bytes, small value\n")
txt.print("expected: ")
txt.print_b(10)
txt.spc()
txt.print_bool(cb>10)
txt.spc()
txt.print_bool(cb>=10)
txt.spc()
txt.print_bool(cb<10)
txt.spc()
txt.print_bool(cb<=10)
txt.nl()
txt.print(" calc'd: ")
txt.print_b(10)
txt.spc()
txt.print_bool(sb>10)
txt.spc()
txt.print_bool(sb>=10)
txt.spc()
txt.print_bool(sb<10)
txt.spc()
txt.print_bool(sb<=10)
txt.nl()
txt.print("calc'd 2: ")
txt.print_b(p)
txt.spc()
txt.print_bool(sb>p)
txt.spc()
txt.print_bool(sb>=p)
txt.spc()
txt.print_bool(sb<p)
txt.spc()
txt.print_bool(sb<=p)
txt.nl()
txt.print(" if stmt: ")
txt.print_b(10)
txt.spc()
if sb>10 txt.print("true ") else txt.print("false ")
if sb>=10 txt.print("true ") else txt.print("false ")
if sb<10 txt.print("true ") else txt.print("false ")
if sb<=10 txt.print("true ") else txt.print("false ")
txt.nl()
txt.print(" ifstmt2: ")
txt.print_b(p)
txt.spc()
if sb>p txt.print("true ") else txt.print("false ")
if sb>=p txt.print("true ") else txt.print("false ")
if sb<p txt.print("true ") else txt.print("false ")
if sb<=p txt.print("true ") else txt.print("false ")
txt.nl()
}
sub bytesoverflow_jump() {
byte @shared sb = -100
byte @shared p = 100
const byte cb = -100
txt.print("\nsigned bytes, overflow, jmp after if\n")
txt.print("expected: ")
txt.print_b(100)
txt.spc()
txt.print_bool(cb>100)
txt.spc()
txt.print_bool(cb>=100)
txt.spc()
txt.print_bool(cb<100)
txt.spc()
txt.print_bool(cb<=100)
txt.nl()
txt.print(" calc'd: ")
txt.print_b(100)
txt.spc()
if sb>100 goto jump1
else { txt.print("false ") goto next1 }
jump1:
txt.print("true ")
next1:
if sb>=100 goto jump2
else { txt.print("false ") goto next2 }
jump2:
txt.print("true ")
next2:
if sb<100 goto jump3
else { txt.print("false ") goto next3 }
jump3:
txt.print("true ")
next3:
if sb<=100 goto jump4
else { txt.print("false ") goto next4 }
jump4:
txt.print("true ")
next4:
txt.nl()
txt.print("calc'd 2: ")
txt.print_b(p)
txt.spc()
if sb>p goto jump1b
else { txt.print("false ") goto next1b }
jump1b:
txt.print("true ")
next1b:
if sb>=p goto jump2b
else { txt.print("false ") goto next2b }
jump2b:
txt.print("true ")
next2b:
if sb<p goto jump3b
else { txt.print("false ") goto next3b }
jump3b:
txt.print("true ")
next3b:
if sb<=p goto jump4b
else { txt.print("false ") goto next4b }
jump4b:
txt.print("true ")
next4b:
txt.nl()
}
sub bytesoverflow_jump_indirect() {
byte @shared sb = -100
byte @shared p = 100
const byte cb = -100
txt.print("\nsigned bytes, overflow, jmp indirect after if\n")
txt.print("expected: ")
txt.print_b(100)
txt.spc()
txt.print_bool(cb>100)
txt.spc()
txt.print_bool(cb>=100)
txt.spc()
txt.print_bool(cb<100)
txt.spc()
txt.print_bool(cb<=100)
txt.nl()
txt.print(" calc'd: ")
txt.print_b(100)
txt.spc()
uword tgt = &jump1
if sb>100 goto tgt
else { txt.print("false ") goto next1 }
jump1:
txt.print("true ")
next1:
tgt = &jump2
if sb>=100 goto tgt
else { txt.print("false ") goto next2 }
jump2:
txt.print("true ")
next2:
tgt = &jump3
if sb<100 goto tgt
else { txt.print("false ") goto next3 }
jump3:
txt.print("true ")
next3:
tgt = &jump4
if sb<=100 goto tgt
else { txt.print("false ") goto next4 }
jump4:
txt.print("true ")
next4:
txt.nl()
txt.print("calc'd 2: ")
txt.print_b(p)
txt.spc()
tgt = &jump1b
if sb>p goto tgt
else { txt.print("false ") goto next1b }
jump1b:
txt.print("true ")
next1b:
tgt = &jump2b
if sb>=p goto tgt
else { txt.print("false ") goto next2b }
jump2b:
txt.print("true ")
next2b:
tgt = &jump3b
if sb<p goto tgt
else { txt.print("false ") goto next3b }
jump3b:
txt.print("true ")
next3b:
tgt = &jump4b
if sb<=p goto tgt
else { txt.print("false ") goto next4b }
jump4b:
txt.print("true ")
next4b:
txt.nl()
}
sub bytessmall_jump() {
byte @shared sb = -10
byte @shared p = 10
const byte cb = -10
txt.print("\nsigned bytes, small value, jmp after if\n")
txt.print("expected: ")
txt.print_b(10)
txt.spc()
txt.print_bool(cb>10)
txt.spc()
txt.print_bool(cb>=10)
txt.spc()
txt.print_bool(cb<10)
txt.spc()
txt.print_bool(cb<=10)
txt.nl()
txt.print(" calc'd: ")
txt.print_b(10)
txt.spc()
if sb>10 goto jump1
else { txt.print("false ") goto next1 }
jump1:
txt.print("true ")
next1:
if sb>=10 goto jump2
else { txt.print("false ") goto next2 }
jump2:
txt.print("true ")
next2:
if sb<10 goto jump3
else { txt.print("false ") goto next3 }
jump3:
txt.print("true ")
next3:
if sb<=10 goto jump4
else { txt.print("false ") goto next4 }
jump4:
txt.print("true ")
next4:
txt.nl()
txt.print("calc'd 2: ")
txt.print_b(p)
txt.spc()
if sb>p goto jump1b
else { txt.print("false ") goto next1b }
jump1b:
txt.print("true ")
next1b:
if sb>=p goto jump2b
else { txt.print("false ") goto next2b }
jump2b:
txt.print("true ")
next2b:
if sb<p goto jump3b
else { txt.print("false ") goto next3b }
jump3b:
txt.print("true ")
next3b:
if sb<=p goto jump4b
else { txt.print("false ") goto next4b }
jump4b:
txt.print("true ")
next4b:
txt.nl()
}
sub bytessmall_jump_indirect() {
byte @shared sb = -10
byte @shared p = 10
const byte cb = -10
txt.print("\nsigned bytes, small value, jmp indirect after if\n")
txt.print("expected: ")
txt.print_b(10)
txt.spc()
txt.print_bool(cb>10)
txt.spc()
txt.print_bool(cb>=10)
txt.spc()
txt.print_bool(cb<10)
txt.spc()
txt.print_bool(cb<=10)
txt.nl()
txt.print(" calc'd: ")
txt.print_b(10)
txt.spc()
uword tgt = &jump1
if sb>10 goto tgt
else { txt.print("false ") goto next1 }
jump1:
txt.print("true ")
next1:
tgt = &jump2
if sb>=10 goto tgt
else { txt.print("false ") goto next2 }
jump2:
txt.print("true ")
next2:
tgt = &jump3
if sb<10 goto tgt
else { txt.print("false ") goto next3 }
jump3:
txt.print("true ")
next3:
tgt = &jump4
if sb<=10 goto tgt
else { txt.print("false ") goto next4 }
jump4:
txt.print("true ")
next4:
txt.nl()
txt.print("calc'd 2: ")
txt.print_b(p)
txt.spc()
tgt = &jump1b
if sb>p goto tgt
else { txt.print("false ") goto next1b }
jump1b:
txt.print("true ")
next1b:
tgt = &jump2b
if sb>=p goto tgt
else { txt.print("false ") goto next2b }
jump2b:
txt.print("true ")
next2b:
tgt = &jump3b
if sb<p goto tgt
else { txt.print("false ") goto next3b }
jump3b:
txt.print("true ")
next3b:
tgt = &jump4b
if sb<=p goto tgt
else { txt.print("false ") goto next4b }
jump4b:
txt.print("true ")
next4b:
txt.nl()
}
sub words() {
word @shared sbw = -30000
word @shared pw = 30000
const word cbw = -30000
txt.print("\nsigned words\n")
txt.print("expected: ")
txt.print_w(cbw)
txt.spc()
txt.print_bool(cbw>30000)
txt.spc()
txt.print_bool(cbw>=30000)
txt.spc()
txt.print_bool(cbw<30000)
txt.spc()
txt.print_bool(cbw<=30000)
txt.nl()
txt.print(" calc'd: ")
txt.print_w(sbw)
txt.spc()
txt.print_bool(sbw>30000)
txt.spc()
txt.print_bool(sbw>=30000)
txt.spc()
txt.print_bool(sbw<30000)
txt.spc()
txt.print_bool(sbw<=30000)
txt.nl()
txt.print("calc'd 2: ")
txt.print_w(sbw)
txt.spc()
txt.print_bool(sbw>pw)
txt.spc()
txt.print_bool(sbw>=pw)
txt.spc()
txt.print_bool(sbw<pw)
txt.spc()
txt.print_bool(sbw<=pw)
txt.nl()
txt.print(" if stmt: ")
txt.print_w(sbw)
txt.spc()
if sbw>30000 txt.print("true ") else txt.print("false ")
if sbw>=30000 txt.print("true ") else txt.print("false ")
if sbw<30000 txt.print("true ") else txt.print("false ")
if sbw<=30000 txt.print("true ") else txt.print("false ")
txt.nl()
txt.print(" ifstmt2: ")
txt.print_w(sbw)
txt.spc()
if sbw>pw txt.print("true ") else txt.print("false ")
if sbw>=pw txt.print("true ") else txt.print("false ")
if sbw<pw txt.print("true ") else txt.print("false ")
if sbw<=pw txt.print("true ") else txt.print("false ")
txt.nl()
asmsub testasm2() -> bool @A {
%asm {{
lda #0
ldy #1
rts
}}
}
}