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
}
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 {
when(expr.type) {
DataType.UBYTE -> {
assignExpressionToRegister(expr.left, RegisterOrPair.A, false)
asmgen.out(" pha")
if(!directIntoY(expr.right)) asmgen.out(" pha")
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)
asmgen.out(" cmp #0") // fix the status register
else
@ -513,17 +524,19 @@ internal class AssignmentAsmGen(private val program: PtProgram,
when(expr.type) {
DataType.UBYTE -> {
assignExpressionToRegister(expr.left, RegisterOrPair.A, false)
asmgen.out(" pha")
if(!directIntoY(expr.right)) asmgen.out(" pha")
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)
return true
}
DataType.BYTE -> {
assignExpressionToRegister(expr.left, RegisterOrPair.A, true)
asmgen.out(" pha")
if(!directIntoY(expr.right)) asmgen.out(" pha")
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)
return true
}
@ -549,9 +562,10 @@ internal class AssignmentAsmGen(private val program: PtProgram,
when(expr.type) {
in ByteDatatypes -> {
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)
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)
return true
}
@ -814,9 +828,14 @@ internal class AssignmentAsmGen(private val program: PtProgram,
assignRegisterByte(target, CpuRegister.A, dt in SignedDatatypes, true)
} else {
assignExpressionToRegister(left, RegisterOrPair.A, left.type==DataType.BYTE)
asmgen.out(" pha")
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", right.type)
asmgen.out(" pla")
if(directIntoY(right)) {
assignExpressionToRegister(right, RegisterOrPair.Y, left.type==DataType.BYTE)
asmgen.out(" sty P8ZP_SCRATCH_B1")
} else {
asmgen.out(" pha")
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", right.type)
asmgen.out(" pla")
}
if (expr.operator == "+")
asmgen.out(" clc | adc P8ZP_SCRATCH_B1")
else
@ -1005,9 +1024,14 @@ internal class AssignmentAsmGen(private val program: PtProgram,
}
assignExpressionToRegister(expr.left, RegisterOrPair.A, false)
asmgen.out(" pha")
assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE)
asmgen.out(" pla")
if(directIntoY(expr.right)) {
assignExpressionToRegister(expr.right, RegisterOrPair.Y, false)
asmgen.out(" sty P8ZP_SCRATCH_B1")
} else {
asmgen.out(" pha")
assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE)
asmgen.out(" pla")
}
when (expr.operator) {
"&" -> asmgen.out(" and P8ZP_SCRATCH_B1")
"|" -> asmgen.out(" ora P8ZP_SCRATCH_B1")
@ -1075,9 +1099,14 @@ internal class AssignmentAsmGen(private val program: PtProgram,
} else {
// normal evaluation into A
assignExpressionToRegister(expr.left, RegisterOrPair.A, false)
asmgen.out(" pha")
assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE)
asmgen.out(" pla")
if(directIntoY(expr.right)) {
assignExpressionToRegister(expr.right, RegisterOrPair.Y, false)
asmgen.out(" sty P8ZP_SCRATCH_B1")
} else {
asmgen.out(" pha")
assignExpressionToVariable(expr.right, "P8ZP_SCRATCH_B1", DataType.UBYTE)
asmgen.out(" pla")
}
when (expr.operator) {
"and" -> asmgen.out(" and 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) {
// normal evaluation, not worth to shortcircuit the simple right operand
assignExpressionToRegister(left, RegisterOrPair.A, false)
asmgen.out(" pha")
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE)
asmgen.out(" pla")
if(directIntoY(right)) {
assignExpressionToRegister(right, RegisterOrPair.Y, false)
asmgen.out(" sty P8ZP_SCRATCH_B1")
} else {
asmgen.out(" pha")
assignExpressionToVariable(right, "P8ZP_SCRATCH_B1", DataType.UBYTE)
asmgen.out(" pla")
}
when (operator) {
"and" -> asmgen.out(" and 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))
}
}
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
}

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 $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)
; (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
; 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
; 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 {{
ldx VAL_1
cpx #$4c ; is there an implementation in VAL_1? (test for JMP)

View File

@ -43,7 +43,7 @@ Compiler:
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.
- c128 target: make syslib more complete (missing kernal routines)?
- pet32 target: make syslib more complete (missing kernal routines)?
@ -51,7 +51,6 @@ Libraries:
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?
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,

View File

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

View File

@ -5,56 +5,21 @@
main {
sub start() {
str s = "?"
s[0] = 's'
txt.print(s)
str s = "the quick brown fox jumps over the lazy dog."
uword sp = &s
cbm.SETTIM(0,0,0)
repeat 5000 {
cx16.r0L = 'v' in s
}
txt.print_uw(cbm.RDTIM16())
txt.nl()
if 's' in s {
txt.print("ok1\n")
} else {
txt.print("fail1\n")
cbm.SETTIM(0,0,0)
repeat 5000 {
cx16.r0L = string.contains(s, 'v')
}
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.print_uw(cbm.RDTIM16())
txt.nl()
}