Page 1 sur 1

Convention d'appel de fonction PB_ (PB 4.40 x64)

Publié : lun. 04/janv./2010 6:45
par ker2x
la doc indique :
General notes:

- Only the registers 'eax', 'edx' and 'ecx' can be destroyed, all other must be preserved.
- A PureFunction name declaration begin always by 'PB_' (ex: PB_Right, PB_Left...)
- The first parameter is passed via the 'eax' register all other are on the stack.
- If Float is used on the first paramater, it's not passed on 'eax' but on 'ST0'
(first FPU register).
- Float or Double result must be put on ST0.
- Quad result has to be put in 'eax' (low word) and 'edx' (high word)
Le code asm generé pour appeler une fonction est :

Code : Tout sélectionner

 
; Plot(i,j,iter) 
  PUSH   qword [v_iter]
  MOVZX  rax,word [v_j]
  MOV    rax,rax
  PUSH   rax
  MOVZX  rax,word [v_i]
  MOV    rax,rax
  PUSH   rax
  POP    rcx
  POP    rdx
  POP    r8
  CALL   PB_Plot2
Je comprend pas du tout pourquoi il fait tous ces push et pop... sans parler du "MOV rax, rax" ...

Alors au final, c'est quoi la convention d'appel de fonction PB_ ?
Et quel sont les registres preservés au final ? (en particulier les xmm ? )

merci.

Re: Convention d'appel de fonction PB_ (PB 4.40 x64)

Publié : lun. 04/janv./2010 7:21
par ker2x
J'ai changé le code en :

Code : Tout sélectionner

 
  ; Plot(i,j,iter)
  MOVZX  rcx,r13w  ; arg i
  MOVZX  rdx, r14w ; arg j
  MOV    r8, qword [v_iter]
  CALL   PB_Plot2
Sachant que j'avais optimisé plus haut pout que r13w et et r14w contiennent i et j :)

C'est quand meme plus propre, et ca marche :)
Mais ca ne m'aide pas pour connaitre exactement les conventions d'appels.

Re: Convention d'appel de fonction PB_ (PB 4.40 x64)

Publié : lun. 04/janv./2010 7:45
par ker2x
Visiblement ca serait : rcx (1er arg), rdx (2eme arg), r8 (3eme arg), r9 (4eme arg), et le reste dans la stack.
et la valeur de retour dans rax.

Re: Convention d'appel de fonction PB_ (PB 4.40 x64)

Publié : lun. 04/janv./2010 8:14
par Anonyme2
Il me semble avoir lu sur le forum anglais, une explication de Fred sur la convention d'appel en 64 bits, mais je ne retrouve pas le lien et la recherche avec les nouveaux forums fonctionne très mal, on ne retrouve presque rien.

Re: Convention d'appel de fonction PB_ (PB 4.40 x64)

Publié : lun. 04/janv./2010 9:43
par Fred
Plus d'infos ici: http://blogs.msdn.com/freik/archive/200 ... 98200.aspx. Et il faut à tout prix reserver 32 bytes sous Windows quand tu mets un argument sur la pile. Les MOV rax,rax sont comment dire.. superflux :). Je vais regarder ca. utilise des variables de type ".i" ca evitera la convertion en 64 bits. Il est pas conseiller de typer les variables en pur, sauf quand c'est pour des raisons bien precises.

Re: Convention d'appel de fonction PB_ (PB 4.40 x64)

Publié : lun. 04/janv./2010 10:25
par ker2x
Merci pour l'info, je vais lire ca.

Je force justement le 64bits car derriere je patche le code FASM (j'ai arreté l'inline ASM, pas assez souple) et utilise des instructions SSE,2,3 x64.
La portabilité c'est pas mon soucis :)

Au passage, il est tres facile d'optimiser du code FASM genere par PureBasic.
D'une part grace au code commenté, d'autre part parce PureBasic ne genere pas toujours du code optimal :)

Re: Convention d'appel de fonction PB_ (PB 4.40 x64)

Publié : lun. 04/janv./2010 10:26
par Fred
Qu'est ce qu'il manque à l'inline asm pour que ce soit plus souple ?

Re: Convention d'appel de fonction PB_ (PB 4.40 x64)

Publié : lun. 04/janv./2010 13:02
par ker2x
Il manque aucune feature.
Mais comme l'optimisation consiste a modifier le code fasm generé par purebasic pour qu'il soit plus rapide, c'est plus simple de bosser directement sur le fichier FASM que de remplacer les fonctions purebasic par de l'InlineASM.

Bon par contre ca veut dire qu'on ne peut plus recompiler le fichier .pb sous peine d'ecraser toutes les optimisations.

Les 2 methodes ont leurs avantages et inconveniants :)


Mais de cette maniere j'ai triplé la vitesse de mon appli :
1) FPU -> SSE
2) deplacer des "MOV" hors des boucles critiques et utilisation des registres xmm0..15, puis reécriture des registres en memoire en sortie de boucle. plutot que de faire des lectures ecritures multiples en memoire a l'interieur des boucles.
3) utilisation des "packed" instructions (mmx, sse, ...)

Re: Convention d'appel de fonction PB_ (PB 4.40 x64)

Publié : lun. 04/janv./2010 13:13
par ker2x
Ha bein j'avais bien trouvé, une partie du moins :)

The x87 register stack is unused. It may be used, but must be considered volatile across function calls. All floating point operations are done using the 16 XMM registers.
The arguments are passed in registers RCX, RDX, R8, and R9.
If the arguments are float/double, they are passed in XMM0L, XMM1L, XMM2L, and XMM3L.
In addition to these registers, RAX, R10, R11, XMM4, and XMM5 are volatile.
Par contre je ne comprend toujours pas :
- The caller is responsible for allocating space for parameters to the callee, and must always allocate sufficient space for the 4 register parameters, even if the callee doesn’t have that many parameters.
- il faut à tout prix reserver 32 bytes sous Windows quand tu mets un argument sur la pile.

reserver ? ou ? quoi ? comment ?

Re: Convention d'appel de fonction PB_ (PB 4.40 x64)

Publié : lun. 04/janv./2010 14:49
par Fred
Par example la fonction "Truc(a,b,c,d,e)". L'appel sera le suivant:

Code : Tout sélectionner

 PUSH qword [e]
  MOV r9,d
  MOV r8,c
  MOV rdx,b
  MOV rcx,a
  SUB rsp,32 ; Reserve 32 bytes (4 * 8) qui sera utilisé par la fonction pour mettre rcx->r9 sur la stack (si besoin est)
  CALL Truc
  ADD rsp,32

Re: Convention d'appel de fonction PB_ (PB 4.40 x64)

Publié : lun. 04/janv./2010 16:33
par ker2x
Je viens de trouver ca sur un site :
Bien que la pile utilise des quadruples mots (8 octets soit 64 bits), le pointeur de pile (RSP) doit toujours être aligné sur un multiple de 16 avant d'appeler une API.

Ref. : AMD64 ABI Ref. : http://msdn2.microsoft.com/en-us/librar ... S.80).aspx

Pour se prémunir de ce problème, on peut utiliser un code comme celui-ci :

Code : Tout sélectionner

PUSH RSP             ; sauvegarde la position courante de RSP sur la pile
PUSH [RSP]           ; garde une autre copie sur la pile
AND SPL,0F0h         ; ajuste RSP pour aligner la pile au cas où elle ne le serait pas.
                     ;
                     ;  paramètre(s) de l'API s'il y a lieu.
                     ;
SUB RSP, 32d         ; ajuste RSP pour la sauvegarde des paramètres (32d = 0x20)
CALL API
ADD RSP, xx          ; nettoie la pile (avec xx = 32d + (nombre de paramètre poussés * 8))
POP RSP              ; restaure RSP à sa valeur originale.
N.B : Certaines APIs supportent une pile mal alignée sans déclencher d'exception. Certaines déclenchent une exception en interne et rétablissent (toujours en interne) une pile alignée. D'autres encore ne supportent aucunement une pile mal alignée. Dans le doute : alignez la pile avant l'appel.
Merci pour ton aide.