better codegen for call() function

This commit is contained in:
Irmen de Jong 2024-09-29 23:18:51 +02:00
parent df35aa7942
commit a064ade1e0
5 changed files with 57 additions and 111 deletions

View File

@ -266,23 +266,40 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
} }
private fun funcCall(fcall: PtBuiltinFunctionCall) { private fun funcCall(fcall: PtBuiltinFunctionCall) {
// note: the routine can return a word value (in AY)
val constAddr = fcall.args[0].asConstInteger() val constAddr = fcall.args[0].asConstInteger()
if(constAddr!=null) { if(constAddr!=null) {
asmgen.out(" jsr ${constAddr.toHex()}") asmgen.out(" jsr ${constAddr.toHex()}")
} else { return
asmgen.assignExpressionToRegister(fcall.args[0], RegisterOrPair.AY) // jump address
asmgen.out("""
sta (+)+1
sty (+)+2
+ jsr 0 ; modified""")
// TODO: avoid using modifying code here by pushing return address on the stack manually and use JMP (INDIRECT) ? And if it's just a variable, simply JMP (variable) !
// TODO: also do this for CallFar below!
} }
// note: the routine can return a word value (in AY) val identifier = fcall.args[0] as? PtIdentifier
if(identifier!=null) {
asmgen.out("""
; push a return address so the jmp becomes indirect jsr
lda #>((+)-1)
pha
lda #<((+)-1)
pha
jmp (${asmgen.asmSymbolName(identifier)})
+""")
return
}
asmgen.assignExpressionToVariable(fcall.args[0], asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD) // jump address
asmgen.out("""
; push a return address so the jmp becomes indirect jsr
lda #>((+)-1)
pha
lda #<((+)-1)
pha
jmp (P8ZP_SCRATCH_W2)
+""")
} }
private fun funcCallFar(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?) { private fun funcCallFar(fcall: PtBuiltinFunctionCall, resultRegister: RegisterOrPair?) {
// TODO apply same optimizations here as used on call() codegen above
if(asmgen.options.compTarget.name != "cx16") if(asmgen.options.compTarget.name != "cx16")
throw AssemblyError("callfar only works on cx16 target at this time") throw AssemblyError("callfar only works on cx16 target at this time")

View File

@ -1346,7 +1346,7 @@ internal class AstChecker(private val program: Program,
if(target.name=="call") { if(target.name=="call") {
if(args[0] is AddressOf) if(args[0] is AddressOf)
errors.err("can't call this indirectly, just use normal function call syntax", args[0].position) errors.err("can't call this indirectly, just use normal function call syntax", args[0].position)
if(args[0] is IdentifierReference) { else if(args[0] is IdentifierReference) {
val callTarget = (args[0] as IdentifierReference).targetStatement(program) val callTarget = (args[0] as IdentifierReference).targetStatement(program)
if(callTarget !is VarDecl) if(callTarget !is VarDecl)
errors.err("can't call this indirectly, just use normal function call syntax", args[0].position) errors.err("can't call this indirectly, just use normal function call syntax", args[0].position)

View File

@ -92,8 +92,11 @@ main {
main { main {
sub start() { sub start() {
uword func = 12345 uword func = 12345
uword[] pointers = [1234,6789]
void call(func) ; ok void call(func) ; ok
void call(12345) ; ok void call(12345) ; ok
void call(pointers[1]) ; ok
void call(cx16.r0+10) ; ok
cx16.r0 = call(func) ; ok cx16.r0 = call(func) ; ok
void call(&start) ; error void call(&start) ; error
void call(start) ; error void call(start) ; error

View File

@ -5,9 +5,8 @@ Regenerate skeleton doc files.
"invalid number of arguments" -> print the list of missing arguments "invalid number of arguments" -> print the list of missing arguments
call() asm gen in funcCall() could be improved by not using modifying code , see the TODO. callfar() should allow setting an argument in the X register as well? + similar optimizations that call() got.
callfar() should allow setting an argument in the X register as well?
Add a new SublimeText syntax file for prog8, and also install this for bat: https://github.com/sharkdp/bat?tab=readme-ov-file#adding-new-syntaxes--language-definitions Add a new SublimeText syntax file for prog8, and also install this for bat: https://github.com/sharkdp/bat?tab=readme-ov-file#adding-new-syntaxes--language-definitions
@ -21,6 +20,7 @@ Future Things and Ideas
^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^
Compiler: Compiler:
- AST weirdness: why is call(...) a normal FunctionCallStatement and not a BuiltinFunctionCall? What does ror() produce for instance?
- Can we support signed % (remainder) somehow? - Can we support signed % (remainder) somehow?
- Don't add "random" rts to %asm blocks but instead give a warning about it? (but this breaks existing behavior that others already depend on... command line switch? block directive?) - Don't add "random" rts to %asm blocks but instead give a warning about it? (but this breaks existing behavior that others already depend on... command line switch? block directive?)
- IR: implement missing operators in AssignmentGen (array shifts etc) - IR: implement missing operators in AssignmentGen (array shifts etc)

View File

@ -1,116 +1,42 @@
%import textio %import textio
%import string %import string
%import compression %import compression
%import test_stack
%zeropage basicsafe %zeropage basicsafe
%option no_sysinit %option no_sysinit
main { main {
sub start() { sub start() {
ubyte[] rle = [ test_stack.test()
5, '1', '2', '3', '4', '5', '6', example(function1, 42)
3, 'a', 'b', 'c', 'd', example(function1, 99)
0, 'z', example(function2, 42)
3, '1', '2', '3','4', example(function2, 99)
-5, '=', test_stack.test()
-127, '+', cx16.r0++
4, '!', '@', '#', '$', '%',
128]
str @shared result = "\x00"*200 sub function1(ubyte arg) {
txt.print("function 1 arg=")
uword ptr = &rle txt.print_ub(arg)
txt.print_uw(compression.decode_rle_srcfunc(callback, result, len(result)))
txt.nl()
txt.print_uw(compression.decode_rle(rle, result, len(result)))
txt.nl()
txt.print_uw(string.length(result))
txt.nl()
txt.print(result)
txt.nl()
txt.print_uwhex(&result, true)
txt.nl()
sub callback() -> ubyte {
ubyte x = @(ptr)
ptr++
return x
}
ubyte[256] buffer
ubyte[256] buffer2
uword bufptr = &buffer
uword outputsize=0
sub outputter(ubyte value) {
@(bufptr) = value
bufptr++
outputsize++
}
str input = iso:"123456aaaaabcdzzz1234======++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++!@#$%"
ubyte[31] expected_rle = [$5, $31, $32, $33, $34, $35, $36, $fc, $61, $2, $62, $63, $64, $fe, $7a, $3, $31, $32, $33, $34, $fb, $3d, $81, $2b, $4, $21, $40, $23, $24, $25, $80]
txt.print(input)
txt.nl()
compression.encode_rle_outfunc(input, len(input), outputter, true)
txt.print_uw(outputsize)
txt.nl()
if outputsize!=len(expected_rle)
txt.print("wrong rle size!\n")
txt.print("\ncompare rle (encode using callback):\n")
for cx16.r9L in 0 to len(expected_rle)-1 {
; txt.print_ub0(cx16.r9L)
; txt.spc()
; txt.print_ubhex(expected_rle[cx16.r9L], false)
; txt.spc()
; txt.print_ubhex(buffer[cx16.r9L], false)
if buffer[cx16.r9L] != expected_rle[cx16.r9L]
txt.print(" wrong rle data!")
; txt.nl()
}
txt.nl()
cx16.r0 = compression.decode_rle(buffer, buffer2, len(buffer2))
if cx16.r0 != len(input)
txt.print("wrong decompress result!\n")
else {
txt.print("good result: ")
txt.print(buffer2)
txt.nl() txt.nl()
} }
sub function2(ubyte arg) {
buffer[0] = buffer[1] = buffer[2] = 128 txt.print("function 2 arg=")
outputsize = compression.encode_rle(input, len(input), buffer, true) txt.print_ub(arg)
txt.print_uw(outputsize)
txt.nl()
if outputsize!=len(expected_rle)
txt.print("wrong rle size!\n")
txt.print("\ncompare rle (encode into buffer):\n")
for cx16.r9L in 0 to len(expected_rle)-1 {
; txt.print_ub0(cx16.r9L)
; txt.spc()
; txt.print_ubhex(expected_rle[cx16.r9L], false)
; txt.spc()
; txt.print_ubhex(buffer[cx16.r9L], false)
if buffer[cx16.r9L] != expected_rle[cx16.r9L]
txt.print(" wrong rle data!")
; txt.nl()
}
txt.nl()
cx16.r0 = compression.decode_rle(buffer, buffer2, len(buffer2))
if cx16.r0 != len(input)
txt.print("wrong decompress result!\n")
else {
txt.print("good result: ")
txt.print(buffer2)
txt.nl() txt.nl()
} }
sub example(uword function, ubyte value) {
%asm {{
lda p8v_value
}}
call(function)
cx16.r1 = function+10
call(cx16.r1-10)
}
} }
} }