IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

Manipulation de bits : C vs ASM


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 461
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 461
    Par défaut Manipulation de bits : C vs ASM
    UPDATE : Fil déplacé (la discussion originale avait commencé ici : http://www.developpez.net/forums/d60...ilier-sprintf/ )

    Citation Envoyé par Jean-Marc.Bourguet Voir le message
    Mince alors... je l'ai fait sans assembleur. Pire, je ne vois pas en quoi l'assembleur aide beaucoup -- enfin, un peu les perfs du calcul entier multiprécision qui est nécessaire, mais les drapeaux de controles de la FPU n'aident pas beaucoup pour cela.
    Alors, d'un point de vue complètement parallèle à cette discussion, je peux témoigner qu'il est beaucoup plus confortable de coder en assembleur les routines de calcul arithmétique et logique, notamment grâce aux facilités de manipulation de bits. L'exemple le plus direct est la rotation des bits d'un entier de longueur arbitraire. Quand on fait un décalage d'un bit, on peut utiliser directement la retenue du processeur et faire des ROL en cascade. Sur Intel, il existe même des instruction de manipulation de chaîne, comme LODS, STOS, MOVS et le préfixe répétiteur REP. Bref, tout ce qu'il faut pour faire de la manipulation de données, principale tâche du CPU.

    En C, il n'y a - à ma connaissance (quiquonque peut élargir le cercle de mes connaissances étant le bienvenu) - pas de manière facile d'extraire un bit sortant. Le plus rapide que j'ai trouvé pour récupérer la valeur du bit de poids fort d'un entier quelquonque et le ramener en première position en évitant les sauts conditionnels est :

    Ça a l'avantage d'utiliser des instructions fondamentales et implicites (potentiellement sans accès au bus) du microprocesseur. Par contre, ça s'éloigne beaucoup, dans la syntaxe, de l'algo initial et le compilateur aura bien du mal à faire les optimisations nécessaires.

    Un autre exemple : les trois instructions de mon post #9 dans cette discussion : http://www.developpez.net/forums/d58...r/#post3552842

    Difficile d'expliquer çà au C, même si celui-ci y met la meilleure volonté du monde.

  2. #2
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Citation Envoyé par Obsidian Voir le message
    En C, il n'y a - à ma connaissance (quiquonque peut élargir le cercle de mes connaissances étant le bienvenu) - pas de manière facile d'extraire un bit sortant. Le plus rapide que j'ai trouvé pour récupérer la valeur du bit de poids fort d'un entier quelquonque et le ramener en première position en évitant les sauts conditionnels est :

    J'ai du mal à comprendre ce code. 0 est une typo pour 0U (sinon ~0 est signé et le déclage a un comportement indéfini, souvent ça conserve le signe et donc le décalage n'est pas très utile) mais 4 parenthèses qui se ferment, 3 qui s'ouvrent et je n'arrive pas à placer la parenthèse ouvrante manquante de manière à avoir le résultat demandé.

    Si x est signé, l'expression évidente est
    Si x est non signé,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    x >> 31
    x >= 0x80000000
    (x & 0x80000000) != 0
    font l'affaire. 0x800000 peut être remplacé par ~(~0U >> 1)) de manière à être indépendant de la taille des entiers, mais je ne connais rien d'aussi simple pour remplacer le 31(CHAR_BIT*sizeof int -1 est le plus simple mais foire dans le cas conforme mais peu courant de présence de bits ne participant pas à la valeur dans l'int).

    Dans chaque cas, gcc me génère le même code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    	testl	%edx, %edx
    	js	.L15
    ou
    suivant le contexte (demandant un saut ou assignation). Ca qui me semble assez bon (mais cela fait 10 ans que je n'ai plus fait d'assembleur, je manque peut-être l'évident).

  3. #3
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 461
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 461
    Par défaut
    Citation Envoyé par Jean-Marc.Bourguet Voir le message
    mais 4 parenthèses qui se ferment, 3 qui s'ouvrent et je n'arrive pas à placer la parenthèse ouvrante manquante de manière à avoir le résultat demandé.
    Faute de frappe de ma part, désolé !

    peut être remplacé par ~(~0U >> 1)) de manière à être indépendant de la taille des entiers, mais je ne connais rien d'aussi simple pour remplacer le 31(CHAR_BIT*sizeof int -1 est le plus simple mais foire dans le cas conforme mais peu courant de présence de bits ne participant pas à la valeur dans l'int).
    C'était l'idée, effectivement.

    Dans chaque cas, gcc me génère le même code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    	testl	%edx, %edx
    	js	.L15
    ou
    suivant le contexte (demandant un saut ou assignation). Ca qui me semble assez bon (mais cela fait 10 ans que je n'ai plus fait d'assembleur, je manque peut-être l'évident).
    Imparable pour GCC, mais l'essentiel demeure : il reste difficile de faire proprement une transmission de bits d'un champs à l'autre et surtout, il n'y a pas moyen de l'exprimer proprement en C (ni dans d'autres langages). Ici, on s'est démerdé pour que le résultat final extraie un bit et GCC a été suffisamment performant pour le comprendre et appliquer la bonne technique, mais il n'est pas du tout certain qu'il soit capable de s'y retrouver dans une équation un peu plus compliquée.

    Sémantiquement, c'est génant : dire que l'on fait un calcul qui se traduit dans les faits par un décalage de bits ne permet pas du tout d'affirmer clairement que c'est cela qu'on cherche à faire au final.

    Et puis SHRL $31, c'est ce que je cherche à éviter : ça tient en une instruction mais le nombre de cycles est probablement élevé, et ça ne marche pas sur tous les CPU : bon nombre d'entre eux ne proposent qu'un décalage au niveau du bit et il faut alors 31 opcodes pour arriver à ses fins.

  4. #4
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Citation Envoyé par Obsidian Voir le message
    Imparable pour GCC, mais l'essentiel demeure : il reste difficile de faire proprement une transmission de bits d'un champs à l'autre et surtout, il n'y a pas moyen de l'exprimer proprement en C (ni dans d'autres langages).
    En C
    En Ada
    Et même si on n'utilise pas les champs comme ça,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    x = (x & NOT_X_MASK) | ((y & Y_MASK) >> XY_OFFSET);
    est très proche de ce que j'écrirais en assembleur.

    Une chose qui est plus compliquée, ce sont les rotations (bien que compilateurs les détectent généralement quand elles sont constantes).

    Une autre c'est l'utilisation de résultats annexes des opérations qui ont généralement plusieurs résultats en assembleur (carry, partie haute d'une multiplication, reste d'une division, ...).

    Ici, on s'est démerdé pour que le résultat final extraie un bit et GCC a été suffisamment performant pour le comprendre et appliquer la bonne technique, mais il n'est pas du tout certain qu'il soit capable de s'y retrouver dans une équation un peu plus compliquée.

    Sémantiquement, c'est génant : dire que l'on fait un calcul qui se traduit dans les faits par un décalage de bits ne permet pas du tout d'affirmer clairement que c'est cela qu'on cherche à faire au final.
    Bizarre, j'ai quatres expressions qui la traduction directe en C des quatres sémantiques que je vois à la chose de plus bas niveau.

    Et puis SHRL $31, c'est ce que je cherche à éviter : ça tient en une instruction mais le nombre de cycles est probablement élevé, et ça ne marche pas sur tous les CPU : bon nombre d'entre eux ne proposent qu'un décalage au niveau du bit et il faut alors 31 opcodes pour arriver à ses fins.
    L'optimiseur fait son boulot: tu écris x < 0, il génère un décalage parce que sur cette cible c'est le plus efficace et tu n'es pas content parce que sur une autre cible ça pourrait ne pas convenir?

Discussions similaires

  1. manipulation de bits d'un byte
    Par orelero dans le forum Langage
    Réponses: 6
    Dernier message: 22/08/2008, 10h41
  2. word_t et Manipulation de bits
    Par fmichael dans le forum C#
    Réponses: 2
    Dernier message: 19/03/2007, 09h33
  3. [VS 2005] Manipuler des bits
    Par b_lob dans le forum C#
    Réponses: 5
    Dernier message: 05/02/2007, 09h51
  4. [Ada] Manipulation de "Bits"
    Par BoBy9 dans le forum Ada
    Réponses: 2
    Dernier message: 14/06/2006, 11h57
  5. Manipulation de bits
    Par Tsly dans le forum C++
    Réponses: 2
    Dernier message: 28/09/2005, 12h41

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo