-2
votes

Comment convertir ce code d'assemblage en code intrinsèque?

ci-dessous cela semble être intrinsèque, cependant, je ne connais pas les fonctions intrinsèques. Aidez-moi s'il vous plaît à convertir le code réel. Surtout, Testfunc () est plus ambigu pour moi. Je suppose que c'est aussi pour le produit DOT de deux vecteurs de flotteurs, mais les étiquettes Lrep et Lexit me font confondre. S'il vous plaît, déterminez clairement pour moi. Et les intrinsions sont disponibles pour le processeur mobile?

pA = A;
for (k = 0; k < K; k++) {
    pC = C;
    for (i = 0; i < M; i++) {
        pA = A + i * K + k;
        pB = B + k * N;
        for (j = N / 32; j > 0; j--) {
            _asm {
                mov             eax, pC;
                mov             ebx, pA;
                mov             ecx, pB;
                vmovups         ymm0, ymmword ptr[eax];
                vmovss          xmm1, dword ptr[ebx];
                vbroadcastss    ymm4, xmm1;
                vmovups         ymm2, ymmword ptr[ecx];
                vfmadd231ps     ymm0, ymm4, ymm2;
                vmovups         ymmword ptr[eax], ymm0;
            }
            pC += 8; pB += 8;
            _asm {
                mov             eax, pC;
                mov             ebx, pA;
                mov             ecx, pB;
                vmovups         ymm0, ymmword ptr[eax];
                vmovss          xmm1, dword ptr[ebx];
                vbroadcastss    ymm4, xmm1;
                vmovups         ymm2, ymmword ptr[ecx];
                vfmadd231ps     ymm0, ymm4, ymm2;
                vmovups         ymmword ptr[eax], ymm0;
            }
            pC += 8; pB += 8;
            _asm {
                mov             eax, pC;
                mov             ebx, pA;
                mov             ecx, pB;
                vmovups         ymm0, ymmword ptr[eax];
                vmovss          xmm1, dword ptr[ebx];
                vbroadcastss    ymm4, xmm1;
                vmovups         ymm2, ymmword ptr[ecx];
                vfmadd231ps     ymm0, ymm4, ymm2;
                vmovups         ymmword ptr[eax], ymm0;
            }
            pC += 8; pB += 8;
            _asm {
                mov             eax, pC;
                mov             ebx, pA;
                mov             ecx, pB;
                vmovups         ymm0, ymmword ptr[eax];
                vmovss          xmm1, dword ptr[ebx];
                vbroadcastss    ymm4, xmm1;
                vmovups         ymm2, ymmword ptr[ecx];
                vfmadd231ps     ymm0, ymm4, ymm2;
                vmovups         ymmword ptr[eax], ymm0;
            }
            pC += 8; pB += 8;
        }
        for (j = N / 32 * 32; j < N; j++) {
            *pC += *pA * *pB;
            pC += 1; pB += 1;
        }
    }
}


2 commentaires

Vous pouvez directement copier le code de montage dans un bloc __ asm . Cependant, votre architecture de projet devrait être X86, car X64 n'est pas prise en charge.


Salut, seccpur. Merci pour votre réponse. J'ai déjà copié le code de montage dans mon code. Mes problèmes ne consistent pas à ne pas travailler le code de montage mais ne peuvent pas déboguer correctement ce code de montage en ligne. VS 2015 Le débogueur saute ces lignes ASM, il fait donc une ligne incorrecte.


3 Réponses :


0
votes

Je ferai les premières lignes pour vous aider à démarrer, mais vraiment, si vous ne pouvez pas lire l'assemblage, vous devez vous référer au manuel de la CPU Intel pour pouvoir le déchiffrer.

mov             esi, K8;
sub             esi, 8;
shl             esi, 2;
xor             edi, edi;
mov             edx, a;
mov             ebx, bb;
mov             esi, K8


2 commentaires

Merci pour votre bonne réponse. Ensuite, qu'en est-il de "VXorps YMM3, YMM3, YMM3;"? Que devrais-je en apprendre davantage à ce sujet?


Même si je n'ai pas rencontré l'instruction VXorps avant que la recherche de Google rapide soit tout ce que je devais trouver la définition. Je suis aussi nouveau à ce jour, mais je suis presque sûr que l'idée n'est pas pour moi juste de tout répondre pour vous, mais plutôt de vous pousser dans la bonne direction. Corrige moi si je me trompe.



2
votes

2 charges de vecteur (de la même position dans 2 tableaux) alimentant une FMA dans un accumulateur de vecteur sent un produit de point à moi.

Je n'ai pas vérifié le manuel de référence de l'ASM pour voir que l'opérande de destination était la somme plutôt que 1 des multiplicands, mais c'est comme ça qui a du sens.

La boucle triple imbriquée ressemble à une multiplication de matrice. Il diffuse 1 entrée tout en faisant une charge de vecteur de l'autre pour nourrir une FMA, il est donc probablement probablement générant un vecteur de résultats de SIMD pour une ligne de sortie.

Utilisation de la syntaxe ASM en ligne MSVC pour cela est plutôt mauvaise; Il ne peut accepter que des entrées via des opérandes de mémoire afin qu'il force une recharge + stocke entre chaque bloc d'ASM. Si vous allez dérouler, utilisez une grande instruction ASM et utilisez des déplacements dans les modes d'adressage.


idk pourquoi la boucle de produit de points est écrite inefficace (avec une branche conditionnelle et inconditionnelle à l'intérieur de la boucle), et non déroulée avec plusieurs accumulateurs. Vaincre à peu près le but de codage de la main dans l'ASM. Voir Pourquoi les mults ne prend que 3 cycles sur HASWELL, différents des tableaux d'instructions d'Agner? pour utiliser plusieurs accumulateurs pour masquer la latence FMA. Ou laissez CLang le faire pour vous quand vous déroulera + vectorisant une boucle C pure C.

Je ne sais pas non plus pourquoi il ne suit pas le résultat horizontal, mais il suffit plutôt de le stocker à la mémoire avec vmovups [c], ymm3 . Semble inutile. Je suppose que l'appelant doit recroouger à partir de la mémoire et de la somme, ou vous pouvez déclarer la fonction comme retournant un __ m256 vecteur et ignorez le magasin.


Quoi qu'il en soit, vous pouvez évidemment écrire un produit de point dans le code scalaire C, peut-être utiliser FMA (A [i], B [i], somme) de Math.h pour reproduire le comportement de l'ASM de ne pas arrondir le résultat temporaire.

ou copiez la vectorisation manuelle avec intrinsique comme somme = _mm256_fmadd_ps (_mm256_loadu_ps (a [i]), _mm256_loadu_ps (b [i]), somme); ou quelque chose. (Voir Guide intrinsique d'Intel ).


0 commentaires

1
votes

dans intrinsique, c'est ce code répété 4 fois.

{
// vmovups         ymm0, ymmword ptr[eax];
__m256 tempC = _mm256_loadu_ps((float*)pC);

// vmovss          xmm1, dword ptr[ebx];
// vbroadcastss    ymm4, xmm1;
__m256 tempA = _mm256_set1_ps(*pA);

// vmovups         ymm2, ymmword ptr[ecx];
__m256 tempB = _mm256_loadu_ps((float*)pB);

// vfmadd231ps     ymm0, ymm4, ymm2;
__m256 result = _mm256_fmadd_ps(tempA, tempB, tempC);

// vmovups         ymmword ptr[eax], ymm0;
_mm256_storeu_ps(pC, result);
}

pC += 8; pB += 8;


4 commentaires

Merci pour votre bonne réponse. Pourriez-vous recommander des documents pour apprendre des intrinsions?


@Seyon pas vraiment. C'est le genre de chose où les ressources deviennent rapidement obsolètes. Je viens d'utiliser le guide Intel intrinsics: logiciel.intel.com/sites/landingpage/intrinsicsguide/... et gueule (avec les drapeaux -mavx2-----mfma -O2 et -ffast-maths).


@robthebloke et futurs lecteurs: préférez -march = haswell ou -march = znver1 sur -mavx2 -mfma . Surtout avec GCC, réglage -MTUNE = à un processeur Intel avec AVX2 + FMA Règles SÉDUCTION LOADU / Stoin dans plusieurs instructions ASM. Pourquoi GCC ne résolve pas _mm256_loadu_pd comme un seul vmovupd? si vos données sont réellement alignées au moment de l'exécution, c'est un inconvénient éventuellement.


Un avantage d'utiliser intrinsique au lieu de l'ASM est que le compilateur peut hisser la diffusion de la boucle. (Au moins si vous utilisez float * restreindre PC ou pa de sorte que le compilateur sait que les stocks via pc n'affectent pas les valeurs lues de PA .) Et oui, je pensais que quelque chose semblait étrange de ce matmul ASM quand j'écrivais ma réponse, mais je ne pouvais pas mettre mon doigt dessus. Les charges redondantes expliquent pourquoi une écluse rapide ne l'a pas empêchée de savoir s'il s'agissait d'une colonne ou d'une rangée. Bien repéré.