more optimal if expression code

This commit is contained in:
Irmen de Jong 2024-10-22 22:58:32 +02:00
parent 326eab3dd1
commit c14f6cfc2b
6 changed files with 23 additions and 56 deletions

View File

@ -66,6 +66,7 @@ What does Prog8 provide?
- conditional branches that map 1:1 to cpu status flags
- ``when`` statement to provide a concise jump table alternative to if/elseif chains
- ``in`` expression for concise and efficient multi-value/containment check
- ``defer`` statement to help write concise and robust subroutine cleanup logic
- several specialized built-in functions such as ``lsb``, ``msb``, ``min``, ``max``, ``rol``, ``ror``
- various powerful built-in libraries to do I/O, number conversions, graphics and more
- inline assembly allows you to have full control when every cycle or byte matters

View File

@ -645,7 +645,7 @@ internal class AssignmentAsmGen(
}
private fun assignIfExpression(target: AsmAssignTarget, expr: PtIfExpression) {
// TODO dont store condition as expression result but just use the flags, like a normal PtIfElse translation does
// TODO don't store condition as expression result but just use the flags, like a normal PtIfElse translation does
require(target.datatype==expr.type)
val falseLabel = asmgen.makeLabel("ifexpr_false")
val endLabel = asmgen.makeLabel("ifexpr_end")
@ -654,32 +654,27 @@ internal class AssignmentAsmGen(
when(expr.type) {
in ByteDatatypesWithBoolean -> {
assignExpressionToRegister(expr.truevalue, RegisterOrPair.A, false)
assignRegisterByte(target, CpuRegister.A, false, false)
asmgen.jmp(endLabel)
asmgen.out(falseLabel)
assignExpressionToRegister(expr.falsevalue, RegisterOrPair.A, false)
assignRegisterByte(target, CpuRegister.A, false, false)
asmgen.out(endLabel)
assignRegisterByte(target, CpuRegister.A, false, false)
}
in WordDatatypes -> {
assignExpressionToRegister(expr.truevalue, RegisterOrPair.AY, false)
assignRegisterpairWord(target, RegisterOrPair.AY)
asmgen.jmp(endLabel)
asmgen.out(falseLabel)
assignExpressionToRegister(expr.falsevalue, RegisterOrPair.AY, false)
assignRegisterpairWord(target, RegisterOrPair.AY)
asmgen.out(endLabel)
assignRegisterpairWord(target, RegisterOrPair.AY)
}
DataType.FLOAT -> {
val trueSrc = AsmAssignSource.fromAstSource(expr.truevalue, program, asmgen)
val assignTrue = AsmAssignment(trueSrc, target, program.memsizer, expr.position)
translateNormalAssignment(assignTrue, expr.definingISub())
assignExpressionToRegister(expr.truevalue, RegisterOrPair.FAC1, true)
asmgen.jmp(endLabel)
asmgen.out(falseLabel)
val falseSrc = AsmAssignSource.fromAstSource(expr.falsevalue, program, asmgen)
val assignFalse = AsmAssignment(falseSrc, target, program.memsizer, expr.position)
translateNormalAssignment(assignFalse, expr.definingISub())
assignExpressionToRegister(expr.falsevalue, RegisterOrPair.FAC1, true)
asmgen.out(endLabel)
asmgen.assignRegister(RegisterOrPair.FAC1, target)
}
else -> throw AssemblyError("weird dt")
}

View File

@ -91,7 +91,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
}
private fun translate(ifExpr: PtIfExpression): ExpressionCodeResult {
// TODO dont store condition as expression result but just use the flags, like a normal PtIfElse translation does
// 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)
val falseTr = translateExpression(ifExpr.falsevalue)

View File

@ -93,11 +93,12 @@ Features
still able to directly use memory addresses and ROM subroutines,
and inline assembly to have full control when every register, cycle or byte matters
- Variables are all allocated statically, no memory allocation overhead
- Variable data types include signed and unsigned bytes and words, arrays, strings.
- Conditional branches for status flags that map 1:1 to processor branch instructions for optimal efficiency
- ``when`` statement to avoid if-else chains
- ``in`` expression for concise and efficient multi-value/containment test
- ``defer`` statement to help write concise and robust subroutine cleanup logic
- Several specialized built-in functions, such as ``lsb``, ``msb``, ``min``, ``max``, ``rol``, ``ror``
- Variable data types include signed and unsigned bytes and words, arrays, strings.
- Various powerful built-in libraries to do I/O, number conversions, graphics and more
- Floating point math is supported on certain compiler targets.
- Easy and highly efficient integration with external subroutines and ROM routines on the target systems.

View File

@ -1,7 +1,7 @@
TODO
====
- Optimize the IfExpression code generation to be more like regular if-else code. (both 6502 and IR)
- Optimize the IfExpression code generation to be more like regular if-else code. (both 6502 and IR) (assignIfExpression / translate(ifExpr: PtIfExpression))
Improve register load order in subroutine call args assignments:

View File

@ -1,54 +1,24 @@
%import textio
%import floats
%import textio
%option no_sysinit
%zeropage basicsafe
main {
sub start() {
uword res1 = allocate(111)
defer deallocate(res1)
uword res2 = allocate(222)
if res2==0
return
defer deallocate(res2)
ubyte[4] values
uword[4] wvalues
float[4] fvalues
cx16.r0L = 0
cx16.r1L = 3
values[cx16.r0L+2] = if cx16.r1L>2 99 else 111
wvalues[cx16.r0L+2] = if cx16.r1L>2 9999 else 1111
fvalues[cx16.r0L+2] = if cx16.r1L>2 9.99 else 1.111
if not process1(res1, res2)
return
if not process2(res1, res2)
return
}
sub allocate(uword arg) -> uword {
; if arg==222
; return 0
txt.print("allocate ")
txt.print_uw(4000+arg)
txt.print_ub(values[2])
txt.nl()
return 4000+arg
}
sub deallocate(uword arg) {
txt.print("dealloc ")
txt.print_uw(arg)
txt.print_uw(wvalues[2])
txt.nl()
}
sub process1(uword arg1, uword arg2) -> bool {
txt.print("process1 ")
txt.print_uw(arg1)
txt.spc()
txt.print_uw(arg2)
txt.nl()
return true
}
sub process2(uword arg1, uword arg2) -> bool {
txt.print("process2 ")
txt.print_uw(arg1)
txt.spc()
txt.print_uw(arg2)
txt.nl()
return true
floats.print(fvalues[2])
}
}