Assembleur 8086. - la mise en Œuvre de toute multiplication et la division sans MUL et DIV instruction
Je voudrais savoir si il existe un moyen pour effectuer toute multiplication ou de la division, sans l'utilisation de MUL ou DIV instruction, car ils nécessitent beaucoup de cycles de CPU. Puis-je exploiter SHL ou SHR instructions pour cette cible? Comment puis-je mettre en œuvre le code assembleur?
Bien sûr, vous pouvez le faire, mais sauf si vous êtes à multiplier/diviser par une classe spéciale de valeurs ou d'une constante de votre code sera probablement au moins un ordre de grandeur inférieur.
Avez-vous besoin pour être en mesure de plusieurs/diviser par des nombres arbitraires ou par une valeur prédéfinie(s)?
Si vous êtes intéressé par ce sujet, vous pouvez prendre un coup d'oeil à la "série multiplicateur" et "parallèle multiplicateur". De cette façon, vous obtenez une meilleure compréhension de la façon dont les multiplications sont effectués et quels sont les inconvénients et les avantages de ces deux types
Ce n'est pas la première question à ce sujet. Avez-vous fait une recherche avant?
Êtes-vous vraiment cibler réelle 8086 d'Intel de puces de 1980-es, ou des incarnations modernes de la même architecture? Il fait beaucoup de différence.
Avez-vous besoin pour être en mesure de plusieurs/diviser par des nombres arbitraires ou par une valeur prédéfinie(s)?
Si vous êtes intéressé par ce sujet, vous pouvez prendre un coup d'oeil à la "série multiplicateur" et "parallèle multiplicateur". De cette façon, vous obtenez une meilleure compréhension de la façon dont les multiplications sont effectués et quels sont les inconvénients et les avantages de ces deux types
Ce n'est pas la première question à ce sujet. Avez-vous fait une recherche avant?
Êtes-vous vraiment cibler réelle 8086 d'Intel de puces de 1980-es, ou des incarnations modernes de la même architecture? Il fait beaucoup de différence.
OriginalL'auteur Anth | 2015-01-13
Vous devez vous connecter pour publier un commentaire.
Comme tout le reste dans l'assemblée il y a beaucoup de façons de faire la multiplication et la division.
lea
(multiplication).Mythe de contournement
MUL
etIMUL
sont hyper rapide moderne de la CPU, voir: http://www.agner.org/optimize/instruction_tables.pdfDIV
etIDIV
sont et ont toujours été extrêmement lente.Un exemple pour Intel Skylake (page 217):
Noter que c'est la maximum latence de multiplier deux 64 ! la valeur des bits.
Le CPU peut remplir l'une de ces multiplications chaque cycle du PROCESSEUR si ca fais des multiplications.
Si vous considérez que l'exemple ci-dessus à l'aide de changements et ajoute à multiplier par 7 a un temps de latence de 4 cycles (3 à l'aide de léa). Il n'y a pas de véritable moyen de battre une plaine de se multiplier sur un PROCESSEUR récent.
Multiplication par l'inverse
Selon Agner le Brouillard de l'asm lib instructions page 12:
Multipliant par l'inverse fonctionne bien lorsque vous avez besoin de diviser par une constante ou si vous divisez par la même variable plusieurs fois dans une rangée.
Vous pouvez trouver vraiment cool assemblée de code illustrant le concept de Agner le Brouillard de la bibliothèque de l'assemblée.
Changements et ajoute/subs
Un décalage à droite est une division par deux
shr
- (Rréduire).Un virage à gauche est une multiplication par deux
shl
- (Larger).Vous pouvez ajouter et soustraire à corriger les non-puissances de deux le long du chemin.
Autre section que par des puissances de 2, à l'aide de cette méthode devient rapidement complexes.
Vous pouvez vous demander pourquoi je suis en train de faire les opérations dans une étrange commande, mais je vais essayer de faire le la chaîne de dépendances aussi court que possible afin de maximiser le nombre d'instructions qui peuvent être exécutées en parallèle.
À l'aide de
Lea
Lea est une instruction pour calculer l'adresse de décalages.
Il est possible de calculer des multiples de 2,3,4,5,8, et 9 en une seule instruction.
Comme:
Note cependant que
lea
avec un multiplicateur (facteur d'échelle) est considéré comme un "complexe" instruction sur les Processeurs AMD de K10 Zen et a un temps de latence de 2 cycles de PROCESSEUR. Sur les anciens Processeurs AMD (k8),lea
a toujours 2-cycle de latence, même avec un simple[reg+reg]
ou[reg+disp8]
mode d'adressage.AMD
Agner le Brouillard de l'instruction tables sont mauvais pour les processeurs AMD Zen: 3-composant ou à l'échelle de l'index LEA est encore 2 cycles sur le Zen (avec seulement 2% de l'horloge de débit au lieu de 4) selon InstLatx64 (http://instlatx64.atw.hu/). Aussi, comme précédemment Processeurs, en mode 64 bits
lea r32, [r64 + whatever]
a 2 cycle de latence. Donc, il est effectivement plus rapide à utiliserlea rdx, [rax+rax]
au lieu delea edx, [rax+rax]
sur les Processeurs AMD, contrairement à Intel, où le fait de tronquer le résultat de 32 bits est gratuit.L' *4 et *8 peut être fait plus rapidement en utilisant
shl
parce que d'un simple changement ne prend qu'un seul cycle.Sur le côté de plus,
lea
ne modifie pas les drapeaux et il permet un gratuit passer à un autre registre de destination.Parce que
lea
ne peut décale à gauche par des 0, 1, 2, ou 3 bits (aka multiplier par 1, 2, 4 ou 8) ce sont les seules pauses que vous obtenez.Intel
Sur les Processeurs Intel (Sandybridge-famille), 2-composant LEA (un seul
+
) a un seul cycle de latence. Donclea edx, [rax + rax*4]
a un seul cycle de latence, maislea edx, [rax + rax + 12]
a 3 cycle de latence (et le pire de débit). Un exemple de ce dilemme est discuté en détail dans Le code C++ pour tester la conjecture de Collatz plus rapide que la main de l'assemblée - pourquoi?.lea eax, [eax*4]
serait plus efficace queshl eax,2
, car une échelle d'indice avec pas d'adresse de base n'est disponible qu'en[disp32 + idx*scale]
(donc il faut un 4 octets constante de zéro). Mais si il vous permet d'économisermov
instruction de copie avant de passer, puis utilisezlea
. (Même pour remplacer le premier cas avecadd eax,eax
.)tout à fait vrai, je voulais juste démontrer que vous pouvez utiliser
shr/shl
Donc, si je remplacerlea
ce genre de défaites le point.Je parlais du dernier bloc, où vous utilisez LEA exclusivement. Que
lea eax,[eax*4]
n'est bon que si vous avez réellement copier-shift avec un autre registre de destination. Il est utile de différentes manières, mais tout regrouper de manière optimale l'enseignement de chaque chose serait de bon.Je suis toujours étonné de voir à vos détaillé et très instructif connaissance de l'UC micro-architecture. Merci!
OriginalL'auteur Johan
Des choses comme SHL/SHR, SAL/SAR, ADD/SUB sont plus rapides que les MUL et DIV, mais MUL et DIV fonctionne mieux pour les numéros dynamiques. Par exemple, si vous savez que vous avez juste besoin de diviser par deux, alors c'est un simple décalage de bits à droite. Mais si vous ne savez pas à l'avance le nombre, alors vous pourriez être tenté à plusieurs reprises SOUS les valeurs. Par exemple, pour déterminer AX divisé par BX, vous pouvez simplement constamment soustraire BX de AX jusqu'à ce que BX est > AX, suivre le dépouillement. Mais si vous étiez en divisant par 200, par 1, ce qui signifierait 200 boucles et SOUS-opérations.
MUL et DIV fonctionnera mieux dans la plupart des cas, lorsque les chiffres ne sont pas codées en dur et connu à l'avance. Les seules exceptions que je pense, c'est quand vous savez que c'est quelque chose comme un de plusieurs/diviser par 2, 4, 8, etc. où les opérateurs de Décalage sera beau travail.
OriginalL'auteur SomeNYCGuy
Voici un exemple:
OriginalL'auteur user719596
La mise en œuvre de la multiplication est plus facile, si vous vous souvenez, un shl opération effectue la même opération que la multiplication de la opérande spécifié par deux. Déplacement à gauche de deux positions de bits multiplie les opérande par quatre. Décalage vers la gauche des trois positions de bits multiplie les opérande par huit. En général, le déplacement d'un opérande à gauche de n bits multiplie par 2n. Toute valeur peut être multipliée par une constante à l'aide d'une série de changements et d'ajouter ou de quarts de travail et les soustractions. Par exemple, pour multiplier le registre ax par dix, il vous suffit de le multiplier par huit, puis ajouter en deux fois la valeur d'origine. C'est, 10*ax = 8*ax + 2*ax. Le code d'accomplir ceci est
Le registre ax (ou de n'importe quel registre, d'ailleurs) peut être multiplié par plus constante des valeurs beaucoup plus rapide à l'aide de shl que par l'utilisation de l'instruction mul. Cela peut sembler difficile à croire, car il ne prend que deux instructions pour le calcul de ce produit:
Cependant, si vous regardez le calendrier, la maj et ajout de l'exemple ci-dessus nécessite moins de cycles d'horloge sur la plupart des processeurs de la famille 80x86 que l'instruction mul. Bien sûr, le code est un peu plus grande (quelques octets), mais l'amélioration de la performance est généralement la peine. Bien sûr, sur le tard processeurs 80x86, la mul instruction est un peu plus rapide que le plus tôt les processeurs, mais les maj et ajouter régime est généralement plus rapide sur ces processeurs.
Vous pouvez également utiliser la soustraction avec les changements à effectuer une opération de multiplication. Considérons la suite de la multiplication par sept:
Cela résulte directement du fait que ax*7 = (ax*8)-ax.
Une erreur commune faite par le début de l'assemblée des étudiants de langues est la soustraction ou addition d'une ou deux plutôt que ax*1 ou ax*2. Ne pas calculer ax*7:
Il calcule (8*ax)-1, quelque chose de totalement différent (à moins, bien sûr, ax = 1). Méfiez-vous de ce piège lors de l'utilisation de changements, additions et soustractions pour effectuer les opérations de multiplication.
Division est un peu plus difficile, besoin de réfléchir...
J'ai trouvé ce avec une brève recherche. Ce n'est pas 8086, mais la technique est la même: what-when-how.com/microcontrollers/...
Merci pour vos réponses! Pour la division des choses est plus difficile. Mais je n'ai pas idée de comment cela peut-il être mis en œuvre :(. Pour moi, c'est bon aussi le cas où je connais le résultat
désolé, je suis occupé avec quelques autres trucs, va chercher une solution pour la division et de l'ajouter à modifier dès que possible
Cette info est tout à fait obsolète. Sur un nouveau PROCESSEUR d'un
mul reg,reg
est presque toujours plus rapide que les quarts de et ajoute. Esp. parce que les changements et ajoute allonger la chaîne de dépendances. Aussi x86 a un canon de levier de vitesses.shr eax,3
qui se passe en un seul cycle et peut être couplé avec 3 autres instructions pour un 1/4 d'un coût de cycle. Il n'est pas nécessaire de créer un long depency-chaîne pour les quarts de travail par un seul bits. Enfin vous avez oubliélea
, mais c'est un problème mineur.OriginalL'auteur RicoRicochet