Je souhaite utiliser les instructions de montage BTS et BT X86 pour accélérer les opérations de bits sur mon code C ++ sur le Mac. Sous Windows, les intrinsèques _bittestandSet et _bittest fonctionnent bien et fournissent des gains de performance significatifs. Sur le Mac, le compilateur GCC ne semble pas supporter ceux-ci, alors j'essaie de le faire directement dans l'assembleur à la place.
Voici mon code C ++ (note que "bit" peut être> = 32): p> Le code d'assembleur suivant fonctionne, mais n'est pas optimal, car le compilateur ne peut pas optimiser l'allocation de registres: p> question : Comment puis-je obtenir le compilateur pour optimiser complètement autour de l'instruction BTS? Et comment puis-je remplacer Testbit par une instruction BT? P> p>
3 Réponses :
Une autre réponse légèrement indirecte, GCC expose Un certain nombre d'opérations atomiques commençant par la version 4.1. P>
inline void SetBit(*array, bit) { asm("bts %1,%0" : "+m" (*array) : "r" (bit)); }
Parfait merci. Cela m'a aidé à comprendre ma deuxième question: Inline Bool Testbit (Array Constworwords [], const int bit) {drapeau BOOL; ASM ("BT% 2,% 1; SETB% 0": "= q" (drapeau): "m" (* tableau), "r" (bit)); drapeau de retour; }
@Efement: Pouvez-vous ajouter des explications à votre réponse.
Si bit code> peut être en dehors de la plage 0..31, votre opérande de mémoire doit être l'ensemble de la matrice, pas seulement le premier élément de celui-ci. (N'oubliez pas la sémantique de string bit-string Crazy-Cisc de
BTS code>
avec Un opérande de mémoire.) De plus, vous devez laisser la source opérande être "ri" code>, car il fonctionne avec des opérandes immédiats (et est beaucoup moins lent de cette façon). Mais vous ne devriez vraiment pas l'utiliser du tout sur le X86 moderne.
BTS code> avec un opérande de mémoire est lent i> (voir ma réponse).
Cette instruction gère le drapeau C, mais l'assembly ne précise pas cela.
@MaximeGorushkin: Un clobber "CC" est implicite dans GNU C Inline ASM pour X86 et X86-64. Ce n'est pas un bug, bien que certaines personnes considèrent que c'est un bon style de la spécifier manuellement de toute façon.
ou peut-être changer un C'est en fait ce que GCC 5.2 génère de votre source C (Memory-Dest Notez également que Inline ASM ne peut pas renvoyer les indicateurs comme résultat (sauf avec un
8 commentaires
En fait, à partir de v6, gcc peut drapeaux de retour.
@Davidwohlferd: merci! C'est intéressant qu'ils ont finalement inclus cela.
@Petercordes Avez-vous déjà vu un compilateur générer
@Beeonrope: j'oublie. Ce que vous décrivez des sons familiers: en utilisant
Ouais, c'était exactement l'idome que j'ai testé dans le lien Godbolt. Je a fait i> trouver un moyen de générer
@Beeonrope: hein, cas d'utilisation intéressante. Je suppose que
@Beeonrope: Re: Manque de réponses récentes. Pas exactement, mais j'en ai marre de voir les mêmes questions débutantes tout le temps que j'ai pris une pause pendant un moment pour rattraper la télévision / les films / livres que je voulais regarder / lire.
@Petercordes, duh, bon point. J'avais seulement testé avec une telle constante en raison de la copie-colle d'un autre test: mais je n'avais pas explicitement destiné à utiliser 64 bits. Bien sûr, pour les constantes de 32 bits, BTS code> (et l'autre
bt * code> insns) avec une destination de mémoire sont lents. (> 10 UOPS sur Intel) . Vous aurez probablement un code plus rapide de faire l'adresse Math pour trouver le bon octet et le charger dans un registre. Ensuite, vous pouvez faire le
bt code> /
BTS code> avec une destination d'enregistrement et stockez le résultat.
1 code> à la bonne position et utilisez
ou code> avec une destination de mémoire pour setbit ou
et code> avec une source de mémoire pour
testbit code>. Bien sûr, si vous évitez l'ASM en ligne, le compilateur peut en ligne
testbit code> et utiliser
test code> au lieu de
et code>, qui est utile sur certains processeurs (puisque Il peut macro-fusible dans une branche de test sur plus de CPU que
et code>). p>
ou code> ou
test code>). On dirait optimal pour moi (moins d'UOPS qu'un Memory-Dest
BT code>). En fait, notez que votre code est cassé car il suppose
non signé long code> est de 32 bits, pas
char_bit * taille de (non signé_long) code>. Utilisation de
uint32_t code> ou
Char code> serait un plan bien meilleur. Notez l'extension de signe de
EAX code> dans
RAX code> avec l'instruction code> CQDE CODE>, en raison du C mal écrit qui utilise
1 Code> au lieu de
1UL code>. p>
BTS code>? Je pouvais effectivement obtenir au moins
clang code> et
icc code> pour générer
bt code> pour "bit de test" type fonctionne mais n'a eu aucune chance avec
BTS code> même s'il semblerait très utile pour la fonction de type" jeu de bit "par rapport à Les alternatives de l'utilisation de
shl code> ou
shlx code> et
ou code> et un couple ops supplémentaire pour charger la constante
1 code> etc.
BT code> pour tester les bits, mais omis d'utiliser
BTS code> pour le bit de jeu. Je suis sûr que c'est une victoire sur Intel CPus au moins, pour des trucs comme
foo | = 1 << n code>, où
n code> n'est pas une constante de compilation et foo est déjà dans un registre. Oui, juste testé, et pas de chance: godbolt.org/g/9s6i9d
BTS code> sur
icc code> uniquement, dans le cas spécifique d'un index de bit de compilation . Ni
GCC code> ni
clang code> Utiliser
BTS code> là et
ICC code> ne l'utilise pas si la position est variable (où Il est sans doute plus utile, car le code non-
BTS code> pour les changements variables est généralement encore plus lent que le boîtier constant, notamment pré-
shlx code>).
ou r64, IMM32 code> ne fonctionnerait pas là-bas, car la constante ne peut pas être représentée comme un signe étendu imm32. D'accord que l'utiliser pour les changements variables est une plus grande victoire.
ou code> est généralement meilleure en raison de plusieurs unités d'exécution et de la vitesse moyenne plus rapide sur de nombreuses architectures (
BTS code> n'a pas été 1 cycle pour toujours, AFAIK). En effet, tout le monde utilise
ou code> pour des constantes 32 bits ou moins (vous pouvez toujours faire un cas mineur pour
BTS code> car il est 5 octets vs
ou code> -with-32 bits-constants de 7 octets).
Pas une réponse directe, juste un lien vers GCC "rel =" Nofollow NOREFERRER "> cims.nyu.edu/cgi-systems/... Documentation ASM étendue .
bt * code> avec un opérande de mémoire est lent, à cause de la sémantique Crazy Cisc. En fait, il est plus rapide de laisser le compilateur émettre la séquence d'instructions de décalage / ou de test) que vous obtiendriez avec ce code. (Au moins, une version de BugFixed et 64 bits de ceci).