Página 1 de 1

Z88DK: Ayuda con fastcall y callee, int, char...

Publicado: Lun, 25 Nov 2013, 15:18
por D_Skywalk
Estaba leyendo este documento:
http://www.z88dk.org/wiki/doku.php?id=optimization

Y sigo sin entender muy bien como funcionan fastcall y demás...

En C:
$this->bbcode_second_pass_code('', 'int suma(int a)
{
a += 2;
}


main()
{
suma(a);
b++;
}')

En ASM:
$this->bbcode_second_pass_code('', '._suma
pop bc
pop hl
push hl
push bc
inc hl
inc hl
pop de
pop bc
push hl
push de
ret



._main
ld hl,(_a)
push hl
call _suma
pop bc
ld hl,(_b)
inc hl
ld (_b),hl
dec hl
ret')

ASM + llamando a suma con FASTCALL:
$this->bbcode_second_pass_code('', '._suma
pop bc
pop hl
push hl
push bc
inc hl
inc hl
pop de
pop bc
push hl
push de
ret



._main
ld hl,(_a)
call _suma
ld hl,(_b)
inc hl
ld (_b),hl
dec hl
ret')

Veo que me estoy ahorrando en la llamada el PUSH HL, supongo que por que sólo va a usar un valor... pero se puede hacer lo mismo si usas dos chars como parámetros?
¿para que vale CALLEE? ¿QUE HACEN LOS POPs y PUSH iniciales intercambiar variable?
¿porque no puede hacer directamente inc hl inc hl, si ya está en HL el valor?

Luego he visto que cuando usas un char, tiene que usar mascaras para hacer las operaciones ... no le vendría bien a la churrera pasar algunas variables globales a int?
Y ya cuando usas una variable signed, se lía un pifostio XD

Si estas preguntas quedan fuera del foro, o preferís que se hagan en Speccy ... avisadme :)

Un saludo compas!

Re: Z88DK: Ayuda con fastcall y callee, int, char...

Publicado: Lun, 25 Nov 2013, 15:49
por antoniovillena
A ver, los parámetros normalmente se pasan por pila, ten en cuenta que lo último que se mete en la pila es la dirección de retorno, la última instrucción que se ejecuta antes de entrar en la función es un call, y este call es el que mete (actúa como un push) la dirección de retorno en pila.

Como lo que has puesto es código en C, el compilador en teoría puede hacer lo que le de la gana. En principio hay 2 formas de acceder a los parámetros de la pila: o popeas los valores (luego lo pusheas para equilibrar la pila) directamente en registros, o usas el puntero HL y aplicas aritmética de punteros. El ejemplo que has puesto el compilador hace lo primero. De la otra forma sería:

$this->bbcode_second_pass_code('', '
ld hl, 2
add hl, sp
ld e, (hl)
inc hl
ld d, (hl)
inc de
inc de
ld (hl), d
dec hl
ld (hl), e
ret
')

Después tenemos el FASTCALL, que sólo se aplica sólo si la función tiene un parámetro (menor de 16 bits), y lo que se hace es emplear el registro HL en lugar de la pila, tanto para el parámetro de entrada como para el parámetro de salida. Esto se traduce en código más eficiente, el ejemplo de arriba sería:

$this->bbcode_second_pass_code('', '
inc hl
inc hl
ret
')

Por último tenemos los CALLEE, mediante el cual le indicamos a la función que el equilibrado de pila lo haremos dentro de la función (normalmente se hace fuera, después del call). A nivel de eficiencia es lo mismo, y no es recomendable porque el código en ensamblador de la función en más difícil de entender. La única ventaja que tiene es que si hay muchas llamadas a esa función, el tamaño del binario se reduce, puesto que en el caso de no usar CALLEE el código que equilibra la pila aparece N veces, mientras que si usamos CALLEE sólo aparece una vez (al final de la función).

Re: Z88DK: Ayuda con fastcall y callee, int, char...

Publicado: Lun, 25 Nov 2013, 15:54
por antoniovillena
Ten en cuenta que el compilador siempre es tonto, empleando el primer método (popeado de valores) sería más sencillo hacer ésto:

$this->bbcode_second_pass_code('', '
pop bc
pop hl
inc hl
inc hl
push hl
push bc
ret
')

Re: Z88DK: Ayuda con fastcall y callee, int, char...

Publicado: Lun, 25 Nov 2013, 16:23
por antoniovillena
$this->bbcode_second_pass_quote('', '
')¿para que vale CALLEE? ¿QUE HACEN LOS POPs y PUSH iniciales intercambiar variable?
¿porque no puede hacer directamente inc hl inc hl, si ya está en HL el valor?


La función que has puesto como ejemplo es un poco inútil, porque incrementa una variable local que no se retorna, si quieres prueba con esta:

$this->bbcode_second_pass_code('', '
int suma(int a)
{
retun a + 2;
}

main()
{
a= 3;
b= suma(a);
printf("%d", b);
}
')

Re: Z88DK: Ayuda con fastcall y callee, int, char...

Publicado: Lun, 25 Nov 2013, 18:46
por D_Skywalk
Bueno, en realidad estoy modificando una variable global, así que sí tiene sentido, no?
Vale, que no la imprimo pero es por simplificar el tocho asm que me suelta el Z88DK :lol:

Esto es lo que yo decía, si lo mete en hl, por que no hacía algo así y ya está...
$this->bbcode_second_pass_code('', '
inc hl
inc hl
ret')

La idea de todas estas preguntas es simplemente aprender a programar mejor y si puede ser generar un código más óptimo con Z88DK :)

Entonces, la función CALLEE en C, no entiendo para que me puede servir, por que su control sería más para mezclar con ASM, no para usarlo con C...

Por cierto, otras pruebas:


incrementos:
a += 1;
$this->bbcode_second_pass_code('', '
pop bc
pop hl
push hl
push bc
inc hl
pop de
pop bc
push hl
push de')

a++;
$this->bbcode_second_pass_code('', '
pop de
pop hl
inc hl
push hl
push de
dec hl')

++a;
$this->bbcode_second_pass_code('', '
pop de
pop hl
inc hl
push hl
push de')

Un Saludo! :corchoneta:

Re: Z88DK: Ayuda con fastcall y callee, int, char...

Publicado: Lun, 25 Nov 2013, 19:18
por antoniovillena
$this->bbcode_second_pass_quote('D_Skywalk', 'B')ueno, en realidad estoy modificando una variable global, así que sí tiene sentido, no?
Vale, que no la imprimo pero es por simplificar el tocho asm que me suelta el Z88DK :lol:


Si tienes una variable global y otra local con el mismo nombre el compilador la que "ve" es la local.

$this->bbcode_second_pass_quote('D_Skywalk', '
')Esto es lo que yo decía, si lo mete en hl, por que no hacía algo así y ya está...
$this->bbcode_second_pass_code('', '
inc hl
inc hl
ret')

La idea de todas estas preguntas es simplemente aprender a programar mejor y si puede ser generar un código más óptimo con Z88DK :)

Entonces, la función CALLEE en C, no entiendo para que me puede servir, por que su control sería más para mezclar con ASM, no para usarlo con C...

Por cierto, otras pruebas:


incrementos:
a += 1;
$this->bbcode_second_pass_code('', '
pop bc
pop hl
push hl
push bc
inc hl
pop de
pop bc
push hl
push de')

a++;
$this->bbcode_second_pass_code('', '
pop de
pop hl
inc hl
push hl
push de
dec hl')

++a;
$this->bbcode_second_pass_code('', '
pop de
pop hl
inc hl
push hl
push de')

Un Saludo! :corchoneta:


La función CALLEE es lo que te he dicho antes, tiene sentido si haces muchas llamadas a la función, pero vamos que mi experiencia con z80dk es lo que he visto desde que integramos el código del descompresor. Prueba a llamar a una función de tipo CALLEE (escrita en C nativo) varias veces, comprueba el tamaño del binario, luego le quitas el CALLEE y vuelves a compilar y si el tamaño aumenta es lo que yo decía.

Re: Z88DK: Ayuda con fastcall y callee, int, char...

Publicado: Lun, 25 Nov 2013, 20:17
por D_Skywalk
Llevas razón XD
Vale mañana hago pruebas también con punteros, así modifico la variable global :)

En realidad lo que estoy mirando no es el tamaño del binario, si no el resultado del código generado directamente en ASM, para ver que sucede cuando lo compila el z88dk :loco:

Un Saludo! :porro:
Pd: tengo que actualizar la versión de z88dk, por si acaso la cosa cambia :?

Re: Z88DK: Ayuda con fastcall y callee, int, char...

Publicado: Lun, 25 Nov 2013, 21:36
por antoniovillena
Eso que haces es muy instructivo, yo lo hice hace tiempo con el ensamblador del 8086 (modo real MS-DOS) y la verdad es que aprendes un montón. Aprendes ensamblador, el cómo funciona el compilador y cómo se optimizan los recursos (por ejemplo las variables locales están en la pila, por lo que no hay que reservar espacio explícitamente).

No creo que cambie mucho la cosa si actualizas, los compiladores por lo general cambian poco a nivel estructural, lo que sí puede hacer que el código compilado varíe notablemente es el optimizador (última fase del compilador), pero en una arquitectura con tan pocos registros como el Z80 no hay mucho que optimizar, no merece la pena estar cambiando el optimizador cada dos por tres.