vendredi 25 avril 2014

Compilateur C/C++ [fr]

Certains d'entre vous se demandent certainement pourquoi désassembler les exécutables ?

Et bien, tout simplement parce que nos compilateurs C/C++ produisent du code lent.

J'ai désassemblé aujourd'hui StarShipW3D qui avait été compilé par Alain Thellier avec une vieille version de Gcc, la 2.90.27...

Et bien, le code généré ressemble comme deux gouttes d'eau avec celui de Warp3D. Je suis donc quasi-certain que toute la version 4.2 a été compilé à l'époque avec cette version-là de Gcc...

Regardez maintenant cet exemple édifiant dans la W3D_Permedia2.library. C'est la fonction Per2_SetState qui est concernée. Il faut bien comprendre que nos compilateurs sont "mécaniques", c'est à dire qu'ils convertissent le code C/C++ en assembleur sans réfléchir !

Per2_SetState pèse 134 octets :

En regardant de plus près et en comprenant la routine, il est clair que nous avons à faire à des tests de bits. En réfléchissant un peu, il est tout à fait possible de regrouper tous ces nombreux tests en un seul !

Puisqu'à chaque fois qu'un bit de d0 est à un, la routine conduit à un "moveq #0,d0". Pour mieux comprendre, il suffit de convertir déjà toutes les comparaisons en binaire :
  • $00002000 = %0000000000000000 0010000000000000 (W3D_BLENDING)
  • $00000400 = %0000000000000000 0000010000000000 (W3D_GOURAUD)
  • $00000100 = %0000000000000000 0000000100000000 (W3D_TEXMAPPING)
  • $00000010 = %0000000000000000 0000000000010000 (W3D_GLOBALTEXENV)
  • $00000200 = %0000000000000000 0000001000000000 (W3D_PERSPECTIVE)
  • $00000800 = %0000000000000000 0000100000000000 (W3D_ZBUFFER)
  • $00001000 = %0000000000000000 0001000000000000 (W3D_ZBUFFERUPDATE)
  • $02000000 = %0000001000000000 0000000000000000 (W3D_SCISSOR)
  • $00080000 = %0000000000001000 0000000000000000 (W3D_DITHERING)
  • $00004000 = %0000000000000000 0100000000000000 (W3D_FOGGING)
  • $00400000 = %0000000001000000 0000000000000000 (W3D_ALPHATEST)
  • $04000000 = %0000010000000000 0000000000000000 (W3D_CHROMATEST)
  • $08000000 = %0000100000000000 0000000000000000 (W3D_CULLFACE)

Ensuite, il suffit juste de concentrer tous les différents bit à tester en un seul chiffre, ce qui donne :
  • %0000111001001000 0111111100010000 = $E487F10

Afin de pouvoir ôter encore le "moveq #0,d0" final, il faut inverser ce chiffre avec un not.l :
  • not.l $E487F10 = $F1B780EF

Voilà donc la routine bien optimisée qui ne fait plus que 12 octets au lieu des 134 de départ :

Bon alors, c'est bien sûr un cas un peu particulier, mais qui donne toutefois une bonne idée sur les capacités humaines à améliorer ce que les robots compilateurs C/C++ pondent...

Un coder sur Amiga m'avait affirmé que le compilateur 68k CodeWarrior sur Macintosh produisait du code de qualité, ce que je n'ai pas encore pu vérifier... Peut-être faudrait-il l'adapter à nos Amiga ?

Alors, est-ce que Warp3D va finir par être globalement plus rapide ?

Faut y croire déjà, il y a encore beaucoup beaucoup de boulot en tout cas !!
 

Aucun commentaire:

Enregistrer un commentaire

Laissez vos commentaires ici :