Quelle est la différence entre 'asm', '__asm " et " __asm__'?
Aussi loin que je peux dire, la seule différence entre __asm { ... };
et __asm__("...");
est que le premier utilise mov eax, var
et la seconde utilise movl %0, %%eax
avec :"=r" (var)
à la fin. Quelles sont les autres différences sont là? Et qu'en est juste asm
?
- _asm est un synonyme __asm, selon ici: msdn.microsoft.com/en-us/library/45yd4tzz(v=vs. 120).aspx
- il est préférable de choisir la réponse de pierre, c'est de loin supérieure.
Vous devez vous connecter pour publier un commentaire.
Celui que vous utilisez dépend de votre compilateur. Ce n'est pas standard comme le langage C.
Il y a une énorme différence entre MSVC inline asm et C de GNU asm inline. GCC syntaxe est conçu pour un rendement optimal sans gaspillage d'instructions, pour envelopper une seule instruction ou de quelque chose. MSVC syntaxe est conçu pour être assez simple, mais AFAICT impossible de l'utiliser sans le temps de latence et les instructions supplémentaires d'un aller-retour à travers la mémoire pour vos entrées et vos sorties.
Si vous êtes en ligne de l'asm pour des raisons de performance, ce qui rend MSVC asm inline viable que si vous écrivez un ensemble de boucle entièrement en asm, pas pour l'emballage de courtes séquences dans une fonction inline. L'exemple ci-dessous (emballage
idiv
avec une fonction) est le genre de chose que MSVC est mauvaise: ~8 extra store/instructions de chargement.MSVC asm inline (utilisé par MSVC et probablement de la cpi, peut-être également disponibles dans certains compilateurs commerciaux):
mov ecx, shift_count
, par exemple. Donc à l'aide d'une seule instruction asm que le compilateur ne génère pas pour vous implique un aller-retour à travers la mémoire sur la manière et sur le moyen de sortir.GNU C asm inline n'est pas une bonne façon d'apprendre l'asm. Vous devez comprendre asm très bien de sorte que vous pouvez dire au compilateur sur votre code. Et vous devez comprendre ce que les compilateurs ont besoin de savoir. Cette réponse a également des liens vers d'autres inline-asm guides et Q&Comme. Le x86 la balise wiki a beaucoup de bonnes choses pour l'asm en général, mais seulement des liens vers que pour GNU asm inline. (Les trucs dans sa réponse, est applicable à GNU asm inline sur la non-plates-formes x86, trop.)
GNU C asm inline syntaxe est utilisée par gcc, clang, cpi, et peut-être que certains compilateurs commerciaux qui mettent en œuvre GNU C:
"c" (shift_count)
obtiendrez le compilateur de mettre lashift_count
variable enecx
avant votre inline asm s'exécute.supplémentaire maladroit pour de grands blocs de code, parce que l'asm doit être à l'intérieur d'une chaîne constante. Donc, vous devez généralement
très impitoyable /plus difficile, mais permet de réduire les frais généraux de l'esp. pour l'emballage de simples instructions. (emballage unique instructions a l'intention de conception d'origine, qui est pourquoi vous devez spécialement indiquent au compilateur début clobbers pour arrêter d'utiliser le même registre pour l'entrée et la sortie si c'est un problème).
Exemple: pleine largeur de la division entière (
div
)Sur 32 bits PROCESSEUR, la division d'un 64 bits entier 32 bits entier, ou de faire un plein de multiplication (32x32->64), peuvent bénéficier de l'asm inline. gcc et clang ne prennent pas avantage de
idiv
pour(int64_t)a /(int32_t)b
, probablement parce que l'instruction des défauts si le résultat ne rentre pas dans un registre 32 bits. Donc, contrairement à cette Q&Un sujet d'obtenir le quotient et le reste à partir d'undiv
, c'est un cas d'utilisation en ligne de l'asm. (Sauf si il y a un moyen d'informer le compilateur que le résultat de l'ajustement, de sorte idiv ne sera pas la faute.)Nous allons utiliser les conventions d'appel qui a mis certains des arguments dans les registres (avec
hi
même dans le droit registre), afin de montrer une situation qui est plus proche de ce que vous pouvez voir lorsque l'in-lining une petite fonction comme ceci.MSVC
Être prudent avec le registre-arg conventions d'appel lors de l'utilisation de inline-asm. Apparemment, le inline-asm soutien est tellement mal conçu ou mis en œuvre que le compilateur peut pas enregistrer/restaurer arg registres autour de l'asm inline, si ces arguments ne sont pas utilisés dans la ligne de l'asm. Merci @RossRidge pour le rappeler.
Mise à jour: apparemment, laissant une valeur dans
eax
ouedx:eax
et puis la chute, à la fin d'un non-void function (sansreturn
) est pris en charge, même lorsque l'in-lining. Je suppose que cela ne fonctionne que si il n'y a pas de code après laasm
déclaration. Cela évite le magasin/recharge pour la sortie (au moins pourquotient
), mais nous ne pouvons rien faire sur les entrées. Dans un non-fonction inline avec pile d'arguments, ils seront dans la mémoire déjà, mais dans ce cas, nous sommes en train d'écrire une petite fonction qui pourrait utilement dans la ligne.Compilé avec MSVC 19.00.23026
/O2
sur rextester (avec unmain()
qui trouve le répertoire de l'exe et vide le compilateur asm sortie sur stdout).Il y a une tonne supplémentaire instructions mov, et le compilateur ne vient même pas près d'optimiser tout de loin. J'ai pensé que peut-être il serait de voir et de comprendre le
mov tmp, edx
à l'intérieur de l'asm inline, et en faire un magasin pourpremainder
. Mais cela nécessiterait de chargementpremainder
de la pile dans un registre avant de l'asm inline block, je suppose.Cette fonction est en fait pire avec
_vectorcall
que la normale tout-sur-la-pile ABI. Avec deux entrées dans les registres, il les stocke dans la mémoire afin de l'asm inline pouvez les charger à partir de variables nommées. Si c'était inline, encore plus de paramètres pourraient être dans les regs, et il aurait pour stocker tous, de sorte que l'asm aurait mémoire opérandes! Donc, contrairement à gcc, nous ne sommes pas gagner beaucoup de inline cette.Faire
*premainder = tmp
à l'intérieur de l'asm bloc signifie plus de code écrit en asm, mais ne les éviter totalement braindead magasin/load/store chemin pour le reste. Cela réduit l'instruction de comptage par 2 total, en baisse de 11 (non compris leret
).Je vais essayer d'obtenir le meilleur code possible de MSVC, ne pas utiliser de mal" et de créer une paille-homme argument. Mais AFAICT c'est horrible pour l'emballage de très courtes séquences. Sans doute il y a une fonction intrinsèque pour 64/32 -> 32 division qui permet au compilateur de générer du code pour ce cas particulier, de sorte que l'ensemble de la prémisse de l'aide asm inline pour cela sur MSVC pourrait être une paille-homme argument. Mais il ne vous montrer que intrinsèques sont beaucoup mieux que dans la ligne de l'asm pour MSVC.
C GNU (gcc/clang/cpi)
Gcc fait encore mieux que le résultat indiqué ici quand inline div64, car il peut prendre des dispositions pour le code précédent pour générer le 64 bits entier dans edx:eax en premier lieu.
Je ne peux pas obtenir de gcc pour compiler pour le 32bit vectorcall ABI. Clang peut, mais il aspire à l'asm inline avec
"rm"
contraintes (essayez sur la godbolt lien: il rebondit fonction arg à travers la mémoire au lieu d'utiliser l'option inscrivez-vous à la contrainte). Le 64 bits MS convention d'appel est proche de la 32bit vectorcall, avec les deux premiers paramètres dans edx, ecx. La différence est que les 2 plus params aller dans regs avant d'utiliser la pile (et que le destinataire de l'appel ne se déclenche pas les arguments hors de la pile, qui est ce que laret 8
a été sur dans le MSVC de sortie.)compilé avec l'option
gcc-m64 -O3-mabi=ms-fverbose-asm
. Avec -m32, vous obtenez juste 3 des charges, idiv, et un magasin, comme vous pouvez le voir partir, changer des trucs dans ce godbolt lien.Pour les 32 bits vectorcall, gcc ferais quelque chose comme
MSVC utilise 13 instructions (pas y compris le ret), par rapport à gcc 4. Avec l'in-lining, comme je l'ai dit, il pourrait être compilé en un seul, tandis que MSVC serait toujours utiliser probablement 9. (Vous n'aurez pas besoin de réserver de l'espace de pile ou de la charge
premainder
; je suis en supposant qu'il a encore de la stocker sur 2 des 3 entrées. Puis il recharge à l'intérieur de l'asm, s'exécuteidiv
, de magasins, de deux sorties, et la recharge à l'extérieur de l'asm. Si c'est 4 charges/magasins pour l'entrée, et un autre 4 pour la sortie.)__stdcall
, mais__cdecl
fonctionne tout aussi bien. N'utilisez pas de__vectorcall
ou__fastcall
, ils ne pessimize asm inline. Notez que la sortie est à peu près identique à du CCG, à l'exception de la nécessité de charger explicitement les paramètres de la pile dans des registres. C'est dur de limitation de MSVC de l'asm inline, totalement inévitable et conduit inévitablement à la sous-optimale de code.Test
fonction n'utilise jamais d'elle. Mais je ne suis pas sûr que GCC ne ce soit.MulDiv
, mais c'est une API, pas une valeur intrinsèque, et aux prises avec certains anciens comportements pour les cas limites. MSVC prend en charge 64 bits de type int pour les versions 32 bits, et il fonctionne sensiblement pour certains..._allmul
,_alldiv
,_allrem
,_allshl
,_allshr
, et leur unsigned équivalents). De plus, ces fonctions CRT ne sont pas aussi efficaces que j'aimerais, même si elles sont mises en œuvre dans l'assemblée. Ils ne sont jamais intégrées en n'importe quoi (ce qui est apparemment assez commun; GCC et Clang ne font généralement pas de inline leur lib fonctions, soit), de sorte que vous ne peut pas faire pire en écrivant votre propre asm inline. Surtout parce qu'il évite un appel de fonction, et ici, peut-être beaucoup plus simple.Avec le compilateur gcc, ce n'est pas une grande différence.
asm
ou__asm
ou__asm__
sont les mêmes, ils ont juste l'utiliser pour éviter les conflits de noms but (il y a la fonction définie par l'utilisateur que le nom de l'asm, etc.)asm
vs__asm__
dans GCCasm
ne fonctionne pas avec-std=c99
, vous avez deux solutions:__asm__
-std=gnu99
Plus de détails: erreur: ‘asm’ non déclaré (première utilisation dans cette fonction)
__asm
vs__asm__
dans GCCJe ne pouvais pas trouver où
__asm
est documentée (notamment pas mentionné à https://gcc.gnu.org/onlinedocs/gcc-7.2.0/gcc/Alternate-Keywords.html#Alternate-Keywords ), mais à partir de la CCAG 8.1 source ils sont exactement les mêmes:donc, je voudrais juste utiliser
__asm__
qui est documenté.__asm { ... };
(avec des accolades, pas de parenthèses), donc ce n'est certainement pas GNU C asm inline. Clang et MSVC soutien MSVC style inline asm, mais gcc n'a pas.gcc
? Je ne sais pas de laquelle il s'est heureusement 🙂