some optimizations

This commit is contained in:
Irmen de Jong 2024-01-06 00:04:15 +01:00
parent 334e6dca28
commit 8e6b91cb9e
6 changed files with 78 additions and 72 deletions

View File

@ -486,13 +486,24 @@ internal class AssignmentAsmGen(private val program: PtProgram,
return false return false
} }
private fun directIntoY(expr: PtExpression): Boolean {
return when(expr) {
is PtIdentifier -> true
is PtMachineRegister -> true
is PtNumber -> true
is PtBuiltinFunctionCall -> expr.name in arrayOf("lsb", "msb")
else -> false
}
}
private fun optimizedRemainderExpr(expr: PtBinaryExpression, target: AsmAssignTarget): Boolean { private fun optimizedRemainderExpr(expr: PtBinaryExpression, target: AsmAssignTarget): Boolean {
when(expr.type) { when(expr.type) {
DataType.UBYTE -> { DataType.UBYTE -> {
assignExpressionToRegister(expr.left, RegisterOrPair.A, false) assignExpressionToRegister(expr.left, RegisterOrPair.A, false)
asmgen.out(" pha") if(!directIntoY(expr.right)) asmgen.out(" pha")
assignExpressionToRegister(expr.right, RegisterOrPair.Y, false) assignExpressionToRegister(expr.right, RegisterOrPair.Y, false)
asmgen.out(" pla | jsr math.divmod_ub_asm") if(!directIntoY(expr.right)) asmgen.out(" pla")
asmgen.out(" jsr math.divmod_ub_asm")
if(target.register==RegisterOrPair.A) if(target.register==RegisterOrPair.A)
asmgen.out(" cmp #0") // fix the status register asmgen.out(" cmp #0") // fix the status register
else else
@ -513,17 +524,19 @@ internal class AssignmentAsmGen(private val program: PtProgram,
when(expr.type) { when(expr.type) {
DataType.UBYTE -> { DataType.UBYTE -> {
assignExpressionToRegister(expr.left, RegisterOrPair.A, false) assignExpressionToRegister(expr.left, RegisterOrPair.A, false)
asmgen.out(" pha") if(!directIntoY(expr.right)) asmgen.out(" pha")
assignExpressionToRegister(expr.right, RegisterOrPair.Y, false) assignExpressionToRegister(expr.right, RegisterOrPair.Y, false)
asmgen.out(" pla | jsr math.divmod_ub_asm") if(!directIntoY(expr.right)) asmgen.out(" pla")
asmgen.out(" jsr math.divmod_ub_asm")
assignRegisterByte(target, CpuRegister.Y, false, true) assignRegisterByte(target, CpuRegister.Y, false, true)
return true return true
} }
DataType.BYTE -> { DataType.BYTE -> {
assignExpressionToRegister(expr.left, RegisterOrPair.A, true) assignExpressionToRegister(expr.left, RegisterOrPair.A, true)
asmgen.out(" pha") if(!directIntoY(expr.right)) asmgen.out(" pha")
assignExpressionToRegister(expr.right, RegisterOrPair.Y, true) assignExpressionToRegister(expr.right, RegisterOrPair.Y, true)
asmgen.out(" pla | jsr math.divmod_b_asm") if(!directIntoY(expr.right)) asmgen.out(" pla")
asmgen.out(" jsr math.divmod_b_asm")
assignRegisterByte(target, CpuRegister.Y, true, true) assignRegisterByte(target, CpuRegister.Y, true, true)
return true return true
} }
@ -549,9 +562,10 @@ internal class AssignmentAsmGen(private val program: PtProgram,
when(expr.type) { when(expr.type) {
in ByteDatatypes -> { in ByteDatatypes -> {
assignExpressionToRegister(expr.left, RegisterOrPair.A, expr.type in SignedDatatypes) assignExpressionToRegister(expr.left, RegisterOrPair.A, expr.type in SignedDatatypes)
asmgen.out(" pha") if(!directIntoY(expr.right)) asmgen.out(" pha")
assignExpressionToRegister(expr.right, RegisterOrPair.Y, expr.type in SignedDatatypes) assignExpressionToRegister(expr.right, RegisterOrPair.Y, expr.type in SignedDatatypes)
asmgen.out(" pla | jsr math.multiply_bytes") if(!directIntoY(expr.right)) asmgen.out(" pla")
asmgen.out(" jsr math.multiply_bytes")
assignRegisterByte(target, CpuRegister.A, false, true) assignRegisterByte(target, CpuRegister.A, false, true)
return true return true
} }
@ -814,9 +828,14 @@ internal class AssignmentAsmGen(private val program: PtProgram,
assignRegisterByte(target, CpuRegister.A, dt in SignedDatatypes, true) assignRegisterByte(target, CpuRegister.A, dt in SignedDatatypes, true)
} else { } else {
assignExpressionToRegister(left, RegisterOrPair.A, left.type==DataType.BYTE) assignExpressionToRegister(left, RegisterOrPair.A, left.type==DataType.BYTE)
asmgen.out(" pha") if(directIntoY(right)) {
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", right.type) assignExpressionToRegister(right, RegisterOrPair.Y, left.type==DataType.BYTE)
asmgen.out(" pla") asmgen.out(" sty P8ZP_SCRATCH_B1")
} else {
asmgen.out(" pha")
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", right.type)
asmgen.out(" pla")
}
if (expr.operator == "+") if (expr.operator == "+")
asmgen.out(" clc | adc P8ZP_SCRATCH_B1") asmgen.out(" clc | adc P8ZP_SCRATCH_B1")
else else
@ -1005,9 +1024,14 @@ internal class AssignmentAsmGen(private val program: PtProgram,
} }
assignExpressionToRegister(expr.left, RegisterOrPair.A, false) assignExpressionToRegister(expr.left, RegisterOrPair.A, false)
asmgen.out(" pha") if(directIntoY(expr.right)) {
assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE) assignExpressionToRegister(expr.right, RegisterOrPair.Y, false)
asmgen.out(" pla") asmgen.out(" sty P8ZP_SCRATCH_B1")
} else {
asmgen.out(" pha")
assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE)
asmgen.out(" pla")
}
when (expr.operator) { when (expr.operator) {
"&" -> asmgen.out(" and P8ZP_SCRATCH_B1") "&" -> asmgen.out(" and P8ZP_SCRATCH_B1")
"|" -> asmgen.out(" ora P8ZP_SCRATCH_B1") "|" -> asmgen.out(" ora P8ZP_SCRATCH_B1")
@ -1075,9 +1099,14 @@ internal class AssignmentAsmGen(private val program: PtProgram,
} else { } else {
// normal evaluation into A // normal evaluation into A
assignExpressionToRegister(expr.left, RegisterOrPair.A, false) assignExpressionToRegister(expr.left, RegisterOrPair.A, false)
asmgen.out(" pha") if(directIntoY(expr.right)) {
assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE) assignExpressionToRegister(expr.right, RegisterOrPair.Y, false)
asmgen.out(" pla") asmgen.out(" sty P8ZP_SCRATCH_B1")
} else {
asmgen.out(" pha")
assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE)
asmgen.out(" pla")
}
when (expr.operator) { when (expr.operator) {
"and" -> asmgen.out(" and P8ZP_SCRATCH_B1") "and" -> asmgen.out(" and P8ZP_SCRATCH_B1")
"or" -> asmgen.out(" ora P8ZP_SCRATCH_B1") "or" -> asmgen.out(" ora P8ZP_SCRATCH_B1")
@ -1783,9 +1812,14 @@ internal class AssignmentAsmGen(private val program: PtProgram,
private fun assignLogicalAndOrWithSimpleRightOperandByte(target: AsmAssignTarget, left: PtExpression, operator: String, right: PtExpression) { private fun assignLogicalAndOrWithSimpleRightOperandByte(target: AsmAssignTarget, left: PtExpression, operator: String, right: PtExpression) {
// normal evaluation, not worth to shortcircuit the simple right operand // normal evaluation, not worth to shortcircuit the simple right operand
assignExpressionToRegister(left, RegisterOrPair.A, false) assignExpressionToRegister(left, RegisterOrPair.A, false)
asmgen.out(" pha") if(directIntoY(right)) {
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE) assignExpressionToRegister(right, RegisterOrPair.Y, false)
asmgen.out(" pla") asmgen.out(" sty P8ZP_SCRATCH_B1")
} else {
asmgen.out(" pha")
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE)
asmgen.out(" pla")
}
when (operator) { when (operator) {
"and" -> asmgen.out(" and P8ZP_SCRATCH_B1") "and" -> asmgen.out(" and P8ZP_SCRATCH_B1")
"or" -> asmgen.out(" ora P8ZP_SCRATCH_B1") "or" -> asmgen.out(" ora P8ZP_SCRATCH_B1")

View File

@ -445,6 +445,14 @@ class ExpressionSimplifier(private val program: Program,
return listOf(IAstModification.ReplaceNode(functionCallExpr, cast, parent)) return listOf(IAstModification.ReplaceNode(functionCallExpr, cast, parent))
} }
} }
else if(functionCallExpr.target.nameInSource == listOf("string", "contains")) {
val target = (functionCallExpr.args[0] as? IdentifierReference)?.targetVarDecl(program)
if(target?.value is StringLiteral) {
errors.info("for actual strings, use a regular containment check instead: 'char in string'", functionCallExpr.position)
val contains = ContainmentCheck(functionCallExpr.args[1], functionCallExpr.args[0], functionCallExpr.position)
return listOf(IAstModification.ReplaceNode(functionCallExpr as Node, contains, parent))
}
}
return noModifications return noModifications
} }

View File

@ -27,7 +27,7 @@ romsub $fe00 = AYINT() clobbers(A,X,Y) ; fac1-> signed word in 100-101
romsub $fe03 = GIVAYF(ubyte lo @ Y, ubyte hi @ A) clobbers(A,X,Y) romsub $fe03 = GIVAYF(ubyte lo @ Y, ubyte hi @ A) clobbers(A,X,Y)
romsub $fe06 = FOUT() clobbers(X) -> uword @ AY ; fac1 -> string, address returned in AY romsub $fe06 = FOUT() clobbers(X) -> uword @ AY ; fac1 -> string, address returned in AY
romsub $fe09 = VAL_1(uword string @XY, ubyte length @A) clobbers(A,X,Y) -> float @FAC1 ; convert ASCII string in XY and length in A, to floating point in FAC1. WARNING: not implemented in the ROM yet! romsub $fe09 = VAL_1(uword string @XY, ubyte length @A) clobbers(A,X,Y) -> float @FAC1 ; convert ASCII string in XY and length in A, to floating point in FAC1. WARNING: only implemented in ROM 47+. Safer to use floats.parse() instead.
; GETADR: fac1 -> unsigned word in Y/A (might throw ILLEGAL QUANTITY) (result also in $14/15) ; GETADR: fac1 -> unsigned word in Y/A (might throw ILLEGAL QUANTITY) (result also in $14/15)
; (tip: use GETADRAY to get A/Y output; lo/hi switched to normal little endian order) ; (tip: use GETADRAY to get A/Y output; lo/hi switched to normal little endian order)
@ -139,7 +139,7 @@ asmsub parse(str value @AY) -> float @FAC1 {
; -- parse a string value of a number to float in FAC1 ; -- parse a string value of a number to float in FAC1
; warning: on older <R47 kernals it uses an internal BASIC routine that is ROM version dependent, ; warning: on older <R47 kernals it uses an internal BASIC routine that is ROM version dependent,
; ($deb6 is inside the routine for VAL at $deb3) See basic.sym from x16-rom ; ($deb6 is inside the routine for VAL at $deb3) See basic.sym from x16-rom
; TODO once VAL_1 is merged into the kernal properly, remove all the workarounds here ; TODO once ROM v47 is released, all the workarounds here can be removed. But probably keep the kernal VAL_1 existance check
%asm {{ %asm {{
ldx VAL_1 ldx VAL_1
cpx #$4c ; is there an implementation in VAL_1? (test for JMP) cpx #$4c ; is there an implementation in VAL_1? (test for JMP)

View File

@ -43,7 +43,7 @@ Compiler:
Libraries: Libraries:
- once a VAL_1 implementation is merged into the X16 kernal properly, remove all the workarounds in cx16 floats.parse_f() . Prototype parse routine in examples/cx16/floatparse.p8 - once kernal rom v47 is released, remove most of the workarounds in cx16 floats.parse_f() . Prototype parse routine in examples/cx16/floatparse.p8
- fix the problems in atari target, and flesh out its libraries. - fix the problems in atari target, and flesh out its libraries.
- c128 target: make syslib more complete (missing kernal routines)? - c128 target: make syslib more complete (missing kernal routines)?
- pet32 target: make syslib more complete (missing kernal routines)? - pet32 target: make syslib more complete (missing kernal routines)?
@ -51,7 +51,6 @@ Libraries:
Optimizations: Optimizations:
- the many pha/pla's in AssignmentAsmGen added to the code size. Can they be tweaked better? Maybe they are not always required, how to detect that/use another register/tempvar/etc?
- VariableAllocator: can we think of a smarter strategy for allocating variables into zeropage, rather than first-come-first-served? - VariableAllocator: can we think of a smarter strategy for allocating variables into zeropage, rather than first-come-first-served?
for instance, vars used inside loops first, then loopvars, then uwords used as pointers, then the rest for instance, vars used inside loops first, then loopvars, then uwords used as pointers, then the rest
- various optimizers skip stuff if compTarget.name==VMTarget.NAME. Once 6502-codegen is done from IR code, - various optimizers skip stuff if compTarget.name==VMTarget.NAME. Once 6502-codegen is done from IR code,

View File

@ -5,7 +5,7 @@
main { main {
; float parsing prototype (remember, there's no official kernal VAL_1 routine to do this yet...) ; float parsing prototype
sub start() { sub start() {
f("") f("")

View File

@ -5,56 +5,21 @@
main { main {
sub start() { sub start() {
str s = "?" str s = "the quick brown fox jumps over the lazy dog."
s[0] = 's' uword sp = &s
txt.print(s)
cbm.SETTIM(0,0,0)
repeat 5000 {
cx16.r0L = 'v' in s
}
txt.print_uw(cbm.RDTIM16())
txt.nl() txt.nl()
if 's' in s { cbm.SETTIM(0,0,0)
txt.print("ok1\n") repeat 5000 {
} else { cx16.r0L = string.contains(s, 'v')
txt.print("fail1\n")
} }
txt.print_uw(cbm.RDTIM16())
void string.find(s, 's')
if_cs {
txt.print("ok2\n")
} else {
txt.print("fail2\n")
}
if string.contains(s, 's') {
txt.print("ok3\n")
} else {
txt.print("fail3\n")
}
if 'q' in s {
txt.print("ok1\n")
} else {
txt.print("fail1\n")
}
void string.find(s, 'q')
if_cs {
txt.print("ok2\n")
} else {
txt.print("fail2\n")
}
if string.contains(s, 'q') {
txt.print("ok3\n")
} else {
txt.print("fail3\n")
}
str buffer="?" * 20
str name = "irmen de jong"
string.left(name, 5, buffer)
txt.print(buffer)
txt.nl()
string.right(name, 4, buffer)
txt.print(buffer)
txt.nl() txt.nl()
} }