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 - conditional branches that map 1:1 to cpu status flags
- ``when`` statement to provide a concise jump table alternative to if/elseif chains - ``when`` statement to provide a concise jump table alternative to if/elseif chains
- ``in`` expression for concise and efficient multi-value/containment check - ``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`` - 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 - 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 - 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) { 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) require(target.datatype==expr.type)
val falseLabel = asmgen.makeLabel("ifexpr_false") val falseLabel = asmgen.makeLabel("ifexpr_false")
val endLabel = asmgen.makeLabel("ifexpr_end") val endLabel = asmgen.makeLabel("ifexpr_end")
@@ -654,32 +654,27 @@ internal class AssignmentAsmGen(
when(expr.type) { when(expr.type) {
in ByteDatatypesWithBoolean -> { in ByteDatatypesWithBoolean -> {
assignExpressionToRegister(expr.truevalue, RegisterOrPair.A, false) assignExpressionToRegister(expr.truevalue, RegisterOrPair.A, false)
assignRegisterByte(target, CpuRegister.A, false, false)
asmgen.jmp(endLabel) asmgen.jmp(endLabel)
asmgen.out(falseLabel) asmgen.out(falseLabel)
assignExpressionToRegister(expr.falsevalue, RegisterOrPair.A, false) assignExpressionToRegister(expr.falsevalue, RegisterOrPair.A, false)
assignRegisterByte(target, CpuRegister.A, false, false)
asmgen.out(endLabel) asmgen.out(endLabel)
assignRegisterByte(target, CpuRegister.A, false, false)
} }
in WordDatatypes -> { in WordDatatypes -> {
assignExpressionToRegister(expr.truevalue, RegisterOrPair.AY, false) assignExpressionToRegister(expr.truevalue, RegisterOrPair.AY, false)
assignRegisterpairWord(target, RegisterOrPair.AY)
asmgen.jmp(endLabel) asmgen.jmp(endLabel)
asmgen.out(falseLabel) asmgen.out(falseLabel)
assignExpressionToRegister(expr.falsevalue, RegisterOrPair.AY, false) assignExpressionToRegister(expr.falsevalue, RegisterOrPair.AY, false)
assignRegisterpairWord(target, RegisterOrPair.AY)
asmgen.out(endLabel) asmgen.out(endLabel)
assignRegisterpairWord(target, RegisterOrPair.AY)
} }
DataType.FLOAT -> { DataType.FLOAT -> {
val trueSrc = AsmAssignSource.fromAstSource(expr.truevalue, program, asmgen) assignExpressionToRegister(expr.truevalue, RegisterOrPair.FAC1, true)
val assignTrue = AsmAssignment(trueSrc, target, program.memsizer, expr.position)
translateNormalAssignment(assignTrue, expr.definingISub())
asmgen.jmp(endLabel) asmgen.jmp(endLabel)
asmgen.out(falseLabel) asmgen.out(falseLabel)
val falseSrc = AsmAssignSource.fromAstSource(expr.falsevalue, program, asmgen) assignExpressionToRegister(expr.falsevalue, RegisterOrPair.FAC1, true)
val assignFalse = AsmAssignment(falseSrc, target, program.memsizer, expr.position)
translateNormalAssignment(assignFalse, expr.definingISub())
asmgen.out(endLabel) asmgen.out(endLabel)
asmgen.assignRegister(RegisterOrPair.FAC1, target)
} }
else -> throw AssemblyError("weird dt") else -> throw AssemblyError("weird dt")
} }

View File

@@ -91,7 +91,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
} }
private fun translate(ifExpr: PtIfExpression): ExpressionCodeResult { 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 condTr = translateExpression(ifExpr.condition)
val trueTr = translateExpression(ifExpr.truevalue) val trueTr = translateExpression(ifExpr.truevalue)
val falseTr = translateExpression(ifExpr.falsevalue) val falseTr = translateExpression(ifExpr.falsevalue)

View File

@@ -93,11 +93,12 @@ Features
still able to directly use memory addresses and ROM subroutines, still able to directly use memory addresses and ROM subroutines,
and inline assembly to have full control when every register, cycle or byte matters and inline assembly to have full control when every register, cycle or byte matters
- Variables are all allocated statically, no memory allocation overhead - 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 - Conditional branches for status flags that map 1:1 to processor branch instructions for optimal efficiency
- ``when`` statement to avoid if-else chains - ``when`` statement to avoid if-else chains
- ``in`` expression for concise and efficient multi-value/containment test - ``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`` - 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 - Various powerful built-in libraries to do I/O, number conversions, graphics and more
- Floating point math is supported on certain compiler targets. - Floating point math is supported on certain compiler targets.
- Easy and highly efficient integration with external subroutines and ROM routines on the target systems. - Easy and highly efficient integration with external subroutines and ROM routines on the target systems.

View File

@@ -1,7 +1,7 @@
TODO 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: Improve register load order in subroutine call args assignments:

View File

@@ -1,54 +1,24 @@
%import textio
%import floats %import floats
%import textio
%option no_sysinit %option no_sysinit
%zeropage basicsafe %zeropage basicsafe
main { main {
sub start() { sub start() {
uword res1 = allocate(111) ubyte[4] values
defer deallocate(res1) uword[4] wvalues
uword res2 = allocate(222) float[4] fvalues
if res2==0 cx16.r0L = 0
return cx16.r1L = 3
defer deallocate(res2) 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) txt.print_ub(values[2])
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.nl() txt.nl()
return 4000+arg txt.print_uw(wvalues[2])
}
sub deallocate(uword arg) {
txt.print("dealloc ")
txt.print_uw(arg)
txt.nl() txt.nl()
} floats.print(fvalues[2])
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
} }
} }