• # Du haut niveau pour gérer correctement du bas niveau

    Posté par (site web personnel) . En réponse au journal Un décalage de 64 bits, ça vous inspire comment ?. Évalué à 10.

    Ce journal montre que beaucoup de langages au dessus de l'assembleur se contentent de répliquer ce que fait le jeu d'instructions du processeur (et donc font que a >> b est indéfini dès que la valeur de b dépasse la taille machine de a en supposant que le développeur a lu la doc dans les moindres détails. Certes on est tous censés lire la doc, mais malgré tout, on augmente le risque de bugs en laissant ce genre de situations indéfinies).

    Certains langages donnent un sens à "a>>b" cohérent avec les mathématiques quelque soient les valeurs de b.

    J'ai cru comprendre que pour certains "décaler les bits, c'est du bas niveau, donc c'est normal qu'on ne fasse pas davantage que le jeu d'instructions du processeur". D'autres ont plutôt dit que "si on programme au dessus de l'assembleur, on perd du temps alors qu'un shr sert en général à optimiser à fond à bas niveau".

    Je mettrais un bémol. Je pense qu'un langage de haut niveau peut permettre de régler les deux problèmes précédents.

    Exemple en Ada:

    with interfaces;use interfaces;
    [...]
     subtype amount is natural range 0..2**6 - 1;
     function my_clean_shr (u : unsigned_64; a : amount ) return unsigned_64 is (Shift_Right (u,a));
     function my_shr (u : unsigned_64; a : natural) return unsigned_64 is (Shift_Right (u,a));

    Ce bout de code crée un sous-type du type natural contraint aux valeurs de 0 à 63 puis définit deux fonctions de décalage.
    La première exige que "amount" soit compris entre 0 et 63.
    La seconde n'exige rien.

    Lorsque l'on génère l'assembleur (avec l'option -O1) on obtient pour la première fonction

    leaq 32(%rsp), %rsi
    movl $.LC0, %edx
    shrq %cl, %rax

    et pour la deuxième

    movl $0, %edi
    leaq 32(%rsp), %rsi
    shrq %cl, %rax
    cmpl $63, %r12d
    movl $.LC0, %edx

    Le compilateur a donc généré un code plus efficace (et minimal) pour my_clean_shr (car on lui dit que l'argument "amount" est contraint entre 0 et 63 ; information dont il ne dispose pas pour my_shr).

    Au final, comme je le disais un peu plus haut, on gagne sur tous les plans:
    Le relecteur est au courant du problème de limitation de l'argument de droite de shr (car c'est dans la signature de la fonction).
    Le code généré est aussi efficace que si on l'avait fait bêtement en C (l'assembleur est le même si on code my_shr à la mode C) avec toutes les petites surprises que ça peut laisser ces bouts de code potentiellement non définis.

    (en espérant avoir été clair en cette heure tardive)