Matroids Matheplanet Forum Index
Moderiert von matroid
Informatik » Programmieren » superschnelle Multiplikation für 1024 Bit (309stellige Zahl)
Autor
Universität/Hochschule superschnelle Multiplikation für 1024 Bit (309stellige Zahl)
hyperG
Senior Letzter Besuch: in der letzten Woche
Dabei seit: 03.02.2017
Mitteilungen: 2106
  Themenstart: 2023-09-17 13:10

Hallo zusammen, im Internet fand ich einen interessanten Artikel: Big Integer Arithmetic Using Intel IFMA mit schönen Balken, die eine enorme Steigerung gegenüber GMP zeigen: https://matheplanet.com/matheplanet/nuke/html/uploads/c/47407_Mul1024_GMP_AVX512_Balken.PNG Erst viel zu spät bemerkte ich, dass ich zwar eine CPU mit AVX512 Befehlen habe, ABER es im Artikel bei der "schnellsten Variante" um Untergruppen IFMA & VBMI geht, was nur sehr wenige CPUs unterstützen. Aber so schnell gebe ich nicht auf. Hürde 1: IFMA-Befehl _mm512_madd52hi_epu64 durch ASM emuliert -> erledigt! Hürde 2: VBMI _mm512_maskz_permutex2var_epi8 Emulation -> hier könnte ich Hilfe gebrauchen: Dieser Befehl (CPUID Flags: AVX512_VBMI) macht folgendes: \sourceon BASIC //AVX512_VBMI Befehl nur: Sapphire Rapids oder Icelake Xeon __m512i _mm512_maskz_permutex2var_epi8 (__mmask64 k, __m512i a, __m512i idx, __m512i b) FOR j := 0 to 63 i := j*8 IF k[j] off := 8*idx[i+5:i] dst[i+7:i] := idx[i+6] ? b[off+7:off] : a[off+7:off] ELSE dst[i+7:i] := 0 FI ENDFOR \sourceoff Statt total umständlich diese For-Schleife nachzubasteln, würde ich gern mit dem funktionierenden Befehl ("einfaches AVX512") \sourceon BASIC // AVX512BW, den mehrere neue CPUs unterstützen __m512i _mm512_maskz_permutex2var_epi16 (__mmask32 k, __m512i a, __m512i idx, __m512i b) FOR j := 0 to 31 i := j*16 IF k[j] off := 16*idx[i+4:i] dst[i+15:i] := idx[i+5] ? b[off+15:off] : a[off+15:off] ELSE dst[i+15:i] := 0 FI ENDFOR \sourceoff emulieren. Geht das? Anderer Weg: Compiler finden, der diesen SONDER-Befehl nicht 1:1 umsetzt wie https://matheplanet.com/matheplanet/nuke/html/uploads/c/47407_permutex2var_epi8_ASM.png sondern den ASM-Befehl vpermt2b ersetzt durch vpermt2w oder andere... Aber natürlich stellt sich die berechtigte Frage, ob die Emulation von den wichtigsten Befehlen nicht die komplette Laufzeit wieder explodieren lässt... Deshalb betrachte ich auch den vorletzten Balken mit "einfachen AVX512". Zwar gibt es hier eine Seite mit ASM-Code (avx512_mul1024.s), aber dieser ist für die LINUX-Welt mit 2 Fakten, die ich in der Windows-Welt nicht gebrauchen kann: a) LINUX (System V amd64 ABI) Aufruf-Syntax, d.h. bei Funktionen werden andere Register übergeben b) "NICHT-Intel-Syntax": statt \sourceon Win-ASM mit INTEL-Syntax mov ecx, 63 \sourceoff steht dort \sourceon LINUX-ASM mit NICHT-Intel-Syntax mov $0x3f, %ecx \sourceoff Gibt es da "Konverter" oder gcc für Windows, wo man die avx512_mul1024.s nutzen kann? Weg 1: MinGW die s in eine o (obj) Datei wandeln, und dann für den Copmiler einbinden. Aus der exe kann ich mir dann den ASM selbst herausziehen... Weg 2: Internetseiten, zu online-Wandlung...? Grüße


   Profil
Yggdrasil
Senior Letzter Besuch: in der letzten Woche
Dabei seit: 01.07.2004
Mitteilungen: 863
Wohnort: Berlin
  Beitrag No.1, eingetragen 2023-09-18 11:26

Hallo HyperG, ich habe etwas herumprobiert um den Assembler-Code in die Intel-Syntax zu konvertieren und bin am Ende bei dieser Variante gelandet. Vermutlich kann man es noch eleganter lösen, aber zumindest funktionierte das schon mal. 1. Ich habe die Routine als Inline-Assembler eingefügt: \sourceon C int main() { asm( ".align 64\n\t" "# Masks to convert 2^64->2^29\n\t" "permMask:\n\t" ".short 0, 1, 0, 0, 1, 2, 3, 0, 3, 4, 5, 0, 5, 6, 7, 0\n\t" ".short 7, 8, 9, 0, 9,10, 0, 0, 10,11,12, 0, 12,13,14, 0\n\t" […] \sourceoff Und es dann mit clang übersetzt: \sourceon Sh clang -S -mllvm --x86-asm-syntax=intel test.c \sourceoff Der Abschnitt mit der Funktion lautet dann: \sourceon Assembler mul1024_avx512: mov ecx, 63 kmovd k1, ecx vpxorq zmm20, zmm20, zmm20 vpxorq zmm21, zmm21, zmm21 # First we need to convert the input from radix 2^64 to redundant 2^29 vmovdqa64 zmm24, zmmword ptr [rip + permMask] vmovdqa64 zmm25, zmmword ptr [rip + shiftMask] vpbroadcastq zmm23, qword ptr [rip + andMask] vpbroadcastq zmm22, qword ptr [rip + one] # Load values with 29-byte intervals and shuffle + shift accordingly # First A vpermw zmm9, zmm24, zmmword ptr [rsi] vpermw zmm10, zmm24, zmmword ptr [rsi + 29] vpermw zmm11, zmm24, zmmword ptr [rsi + 58] vpermw zmm12, zmm24, zmmword ptr [rsi + 87] vmovdqu16 zmm13 {k1} {z}, zmmword ptr [rsi + 116] vpermw zmm13, zmm24, zmm13 vpsrlvq zmm9, zmm9, zmm25 vpsrlvq zmm10, zmm10, zmm25 vpsrlvq zmm11, zmm11, zmm25 vpsrlvq zmm12, zmm12, zmm25 vpsrlvq zmm13, zmm13, zmm25 vpandq zmm9, zmm9, zmm23 vpandq zmm10, zmm10, zmm23 vpandq zmm11, zmm11, zmm23 vpandq zmm12, zmm12, zmm23 vpandq zmm13, zmm13, zmm23 vpxorq zmm14, zmm14, zmm14 # Then B vpermw zmm15, zmm24, zmmword ptr [rdx] vpermw zmm16, zmm24, zmmword ptr [rdx + 29] vpermw zmm17, zmm24, zmmword ptr [rdx + 58] vpermw zmm18, zmm24, zmmword ptr [rdx + 87] vmovdqu16 zmm19 {k1} {z}, zmmword ptr [rdx + 116] vpermw zmm19, zmm24, zmm19 vpsrlvq zmm15, zmm15, zmm25 vpsrlvq zmm16, zmm16, zmm25 vpsrlvq zmm17, zmm17, zmm25 vpsrlvq zmm18, zmm18, zmm25 vpsrlvq zmm19, zmm19, zmm25 vpandq zmm15, zmm15, zmm23 vpandq zmm16, zmm16, zmm23 vpandq zmm17, zmm17, zmm23 vpandq zmm18, zmm18, zmm23 vpandq zmm19, zmm19, zmm23 # Zero the accumulators vpxorq zmm0, zmm0, zmm0 vpxorq zmm1, zmm1, zmm1 vpxorq zmm2, zmm2, zmm2 vpxorq zmm3, zmm3, zmm3 vpxorq zmm4, zmm4, zmm4 vpxorq zmm5, zmm5, zmm5 vpxorq zmm6, zmm6, zmm6 vpxorq zmm7, zmm7, zmm7 vpxorq zmm8, zmm8, zmm8 # The classic approach is to multiply by a single digit of B # each iteration, however we prefer to multiply by all digits # with 8-digit interval, while the registers are aligned, and then # shift. We have a total of 36 digits, therefore we multipy A in 8 # iterations by the following digits: # itr 0: 0,8,16,24,32 # itr 1: 1,9,17,25,33 # itr 2: 2,10,18,26,34 # itr 3: 3,11,19,27,35 # itr 4: 4,12,20,28 # itr 5: 5,13,21,29 # itr 6: 6,14,22,30 # itr 7: 7,15,23,31 # IDX holds the index of the currently required value mov rax, 5 mov rcx, 4 .Ltmp0: # Get the correct digits into T0, T1 and T2 vpermq zmm24, zmm21, zmm15 vpermq zmm25, zmm21, zmm16 vpermq zmm26, zmm21, zmm17 vpermq zmm27, zmm21, zmm18 vpermq zmm28, zmm21, zmm19 vpaddq zmm21, zmm21, zmm22 # Multiply the correctly aligned values vpmuludq zmm29, zmm24, zmm9 vpaddq zmm0, zmm0, zmm29 vpmuludq zmm29, zmm24, zmm10 vpaddq zmm1, zmm1, zmm29 vpmuludq zmm29, zmm24, zmm11 vpaddq zmm2, zmm2, zmm29 vpmuludq zmm29, zmm24, zmm12 vpaddq zmm3, zmm3, zmm29 vpmuludq zmm29, zmm24, zmm13 vpaddq zmm4, zmm4, zmm29 vpmuludq zmm29, zmm25, zmm9 vpaddq zmm1, zmm1, zmm29 vpmuludq zmm29, zmm25, zmm10 vpaddq zmm2, zmm2, zmm29 vpmuludq zmm29, zmm25, zmm11 vpaddq zmm3, zmm3, zmm29 vpmuludq zmm29, zmm25, zmm12 vpaddq zmm4, zmm4, zmm29 vpmuludq zmm29, zmm25, zmm13 vpaddq zmm5, zmm5, zmm29 vpmuludq zmm29, zmm26, zmm9 vpaddq zmm2, zmm2, zmm29 vpmuludq zmm29, zmm26, zmm10 vpaddq zmm3, zmm3, zmm29 vpmuludq zmm29, zmm26, zmm11 vpaddq zmm4, zmm4, zmm29 vpmuludq zmm29, zmm26, zmm12 vpaddq zmm5, zmm5, zmm29 vpmuludq zmm29, zmm26, zmm13 vpaddq zmm6, zmm6, zmm29 vpmuludq zmm29, zmm27, zmm9 vpaddq zmm3, zmm3, zmm29 vpmuludq zmm29, zmm27, zmm10 vpaddq zmm4, zmm4, zmm29 vpmuludq zmm29, zmm27, zmm11 vpaddq zmm5, zmm5, zmm29 vpmuludq zmm29, zmm27, zmm12 vpaddq zmm6, zmm6, zmm29 vpmuludq zmm29, zmm27, zmm13 vpaddq zmm7, zmm7, zmm29 vpmuludq zmm29, zmm28, zmm9 vpaddq zmm4, zmm4, zmm29 vpmuludq zmm29, zmm28, zmm10 vpaddq zmm5, zmm5, zmm29 vpmuludq zmm29, zmm28, zmm11 vpaddq zmm6, zmm6, zmm29 vpmuludq zmm29, zmm28, zmm12 vpaddq zmm7, zmm7, zmm29 vpmuludq zmm29, zmm28, zmm13 vpaddq zmm8, zmm8, zmm29 dec rax je .Ltmp1 # We need to align the accumulator, but that will create dependency # on the output of the previous operation. # Instead we align A (which also has fewer digits). # However A will overflow after 4 such iterations, # this is when we switch to a slightly different loop valignq zmm13, zmm13, zmm12, 7 # zmm13 = zmm12[7],zmm13[0,1,2,3,4,5,6] valignq zmm12, zmm12, zmm11, 7 # zmm12 = zmm11[7],zmm12[0,1,2,3,4,5,6] valignq zmm11, zmm11, zmm10, 7 # zmm11 = zmm10[7],zmm11[0,1,2,3,4,5,6] valignq zmm10, zmm10, zmm9, 7 # zmm10 = zmm9[7],zmm10[0,1,2,3,4,5,6] valignq zmm9, zmm9, zmm20, 7 # zmm9 = zmm20[7],zmm9[0,1,2,3,4,5,6] jmp .Ltmp0 .Ltmp2: # Get the correct digits into T0 and T1 # We finished all the digits in B4 vpermq zmm24, zmm21, zmm15 vpermq zmm25, zmm21, zmm16 vpermq zmm26, zmm21, zmm17 vpermq zmm27, zmm21, zmm18 vpaddq zmm21, zmm21, zmm22 # Multiply the correctly aligned values, since A overflowed we now # have more multiplications vpmuludq zmm29, zmm24, zmm9 vpaddq zmm0, zmm0, zmm29 vpmuludq zmm29, zmm24, zmm10 vpaddq zmm1, zmm1, zmm29 vpmuludq zmm29, zmm24, zmm11 vpaddq zmm2, zmm2, zmm29 vpmuludq zmm29, zmm24, zmm12 vpaddq zmm3, zmm3, zmm29 vpmuludq zmm29, zmm24, zmm13 vpaddq zmm4, zmm4, zmm29 vpmuludq zmm29, zmm24, zmm14 vpaddq zmm5, zmm5, zmm29 vpmuludq zmm29, zmm25, zmm9 vpaddq zmm1, zmm1, zmm29 vpmuludq zmm29, zmm25, zmm10 vpaddq zmm2, zmm2, zmm29 vpmuludq zmm29, zmm25, zmm11 vpaddq zmm3, zmm3, zmm29 vpmuludq zmm29, zmm25, zmm12 vpaddq zmm4, zmm4, zmm29 vpmuludq zmm29, zmm25, zmm13 vpaddq zmm5, zmm5, zmm29 vpmuludq zmm29, zmm25, zmm14 vpaddq zmm6, zmm6, zmm29 vpmuludq zmm29, zmm26, zmm9 vpaddq zmm2, zmm2, zmm29 vpmuludq zmm29, zmm26, zmm10 vpaddq zmm3, zmm3, zmm29 vpmuludq zmm29, zmm26, zmm11 vpaddq zmm4, zmm4, zmm29 vpmuludq zmm29, zmm26, zmm12 vpaddq zmm5, zmm5, zmm29 vpmuludq zmm29, zmm26, zmm13 vpaddq zmm6, zmm6, zmm29 vpmuludq zmm29, zmm26, zmm14 vpaddq zmm7, zmm7, zmm29 vpmuludq zmm29, zmm27, zmm9 vpaddq zmm3, zmm3, zmm29 vpmuludq zmm29, zmm27, zmm10 vpaddq zmm4, zmm4, zmm29 vpmuludq zmm29, zmm27, zmm11 vpaddq zmm5, zmm5, zmm29 vpmuludq zmm29, zmm27, zmm12 vpaddq zmm6, zmm6, zmm29 vpmuludq zmm29, zmm27, zmm13 vpaddq zmm7, zmm7, zmm29 vpmuludq zmm29, zmm27, zmm14 vpaddq zmm8, zmm8, zmm29 # This is the entry point for the second loop .Ltmp1: valignq zmm14, zmm14, zmm13, 7 # zmm14 = zmm13[7],zmm14[0,1,2,3,4,5,6] valignq zmm13, zmm13, zmm12, 7 # zmm13 = zmm12[7],zmm13[0,1,2,3,4,5,6] valignq zmm12, zmm12, zmm11, 7 # zmm12 = zmm11[7],zmm12[0,1,2,3,4,5,6] valignq zmm11, zmm11, zmm10, 7 # zmm11 = zmm10[7],zmm11[0,1,2,3,4,5,6] valignq zmm10, zmm10, zmm9, 7 # zmm10 = zmm9[7],zmm10[0,1,2,3,4,5,6] valignq zmm9, zmm9, zmm20, 7 # zmm9 = zmm20[7],zmm9[0,1,2,3,4,5,6] dec rcx jne .Ltmp2 # Perform two folds of the top bits, for # easier recombination. vpsrlq zmm24, zmm0, 29 vpsrlq zmm25, zmm1, 29 vpsrlq zmm26, zmm2, 29 vpsrlq zmm27, zmm3, 29 vpsrlq zmm28, zmm4, 29 vpsrlq zmm9, zmm5, 29 vpsrlq zmm10, zmm6, 29 vpsrlq zmm11, zmm7, 29 vpsrlq zmm12, zmm8, 29 vpsrlq zmm29, zmm0, 58 vpsrlq zmm13, zmm1, 58 vpsrlq zmm14, zmm2, 58 vpsrlq zmm15, zmm3, 58 vpsrlq zmm16, zmm4, 58 vpsrlq zmm17, zmm5, 58 vpsrlq zmm18, zmm6, 58 vpsrlq zmm19, zmm7, 58 vpsrlq zmm30, zmm8, 58 vpandq zmm0, zmm0, zmm23 vpandq zmm1, zmm1, zmm23 vpandq zmm2, zmm2, zmm23 vpandq zmm3, zmm3, zmm23 vpandq zmm4, zmm4, zmm23 vpandq zmm5, zmm5, zmm23 vpandq zmm6, zmm6, zmm23 vpandq zmm7, zmm7, zmm23 vpandq zmm8, zmm8, zmm23 vpandq zmm24, zmm24, zmm23 vpandq zmm25, zmm25, zmm23 vpandq zmm26, zmm26, zmm23 vpandq zmm27, zmm27, zmm23 vpandq zmm28, zmm28, zmm23 vpandq zmm9, zmm9, zmm23 vpandq zmm10, zmm10, zmm23 vpandq zmm11, zmm11, zmm23 vpandq zmm12, zmm12, zmm23 valignq zmm12, zmm12, zmm11, 7 # zmm12 = zmm11[7],zmm12[0,1,2,3,4,5,6] valignq zmm11, zmm11, zmm10, 7 # zmm11 = zmm10[7],zmm11[0,1,2,3,4,5,6] valignq zmm10, zmm10, zmm9, 7 # zmm10 = zmm9[7],zmm10[0,1,2,3,4,5,6] valignq zmm9, zmm9, zmm28, 7 # zmm9 = zmm28[7],zmm9[0,1,2,3,4,5,6] valignq zmm28, zmm28, zmm27, 7 # zmm28 = zmm27[7],zmm28[0,1,2,3,4,5,6] valignq zmm27, zmm27, zmm26, 7 # zmm27 = zmm26[7],zmm27[0,1,2,3,4,5,6] valignq zmm26, zmm26, zmm25, 7 # zmm26 = zmm25[7],zmm26[0,1,2,3,4,5,6] valignq zmm25, zmm25, zmm24, 7 # zmm25 = zmm24[7],zmm25[0,1,2,3,4,5,6] valignq zmm24, zmm24, zmm20, 7 # zmm24 = zmm20[7],zmm24[0,1,2,3,4,5,6] valignq zmm30, zmm30, zmm19, 6 # zmm30 = zmm19[6,7],zmm30[0,1,2,3,4,5] valignq zmm19, zmm19, zmm18, 6 # zmm19 = zmm18[6,7],zmm19[0,1,2,3,4,5] valignq zmm18, zmm18, zmm17, 6 # zmm18 = zmm17[6,7],zmm18[0,1,2,3,4,5] valignq zmm17, zmm17, zmm16, 6 # zmm17 = zmm16[6,7],zmm17[0,1,2,3,4,5] valignq zmm16, zmm16, zmm15, 6 # zmm16 = zmm15[6,7],zmm16[0,1,2,3,4,5] valignq zmm15, zmm15, zmm14, 6 # zmm15 = zmm14[6,7],zmm15[0,1,2,3,4,5] valignq zmm14, zmm14, zmm13, 6 # zmm14 = zmm13[6,7],zmm14[0,1,2,3,4,5] valignq zmm13, zmm13, zmm29, 6 # zmm13 = zmm29[6,7],zmm13[0,1,2,3,4,5] valignq zmm29, zmm29, zmm20, 6 # zmm29 = zmm20[6,7],zmm29[0,1,2,3,4,5] vpaddq zmm0, zmm0, zmm24 vpaddq zmm1, zmm1, zmm25 vpaddq zmm2, zmm2, zmm26 vpaddq zmm3, zmm3, zmm27 vpaddq zmm4, zmm4, zmm28 vpaddq zmm5, zmm5, zmm9 vpaddq zmm6, zmm6, zmm10 vpaddq zmm7, zmm7, zmm11 vpaddq zmm8, zmm8, zmm12 vpaddq zmm0, zmm0, zmm29 vpaddq zmm1, zmm1, zmm13 vpaddq zmm2, zmm2, zmm14 vpaddq zmm3, zmm3, zmm15 vpaddq zmm4, zmm4, zmm16 vpaddq zmm5, zmm5, zmm17 vpaddq zmm6, zmm6, zmm18 vpaddq zmm7, zmm7, zmm19 vpaddq zmm8, zmm8, zmm30 # At this stage the redundant values occupy at most 30bit containers ################# # Recombine bits 0:511 vmovdqa64 zmm24, zmmword ptr [rip + fixMask0] vmovdqa64 zmm25, zmmword ptr [rip + fixMask1] vmovdqa64 zmm26, zmmword ptr [rip + fixMask2] # Combine ACC2 and ACC1 so we can address more words in the permute vpsllq zmm28, zmm2, 32 vpxorq zmm28, zmm28, zmm1 vpermi2d zmm24, zmm0, zmm28 vpermi2w zmm25, zmm0, zmm28 vpermi2d zmm26, zmm0, zmm28 vpsrlvq zmm24, zmm24, zmmword ptr [rip + fixShift0] vpsllvq zmm25, zmm25, zmmword ptr [rip + fixShift1] vpsllvq zmm29, zmm26, zmmword ptr [rip + fixShift2] mov eax, 524288 kmovd k1, eax vpsllw zmm25 {k1}, zmm25, 10 # We can sum T0 + T1 with no carry # Carry can occur when we add T2 vpaddq zmm0, zmm25, zmm24 ################# # Recombine bits 512:1023 vmovdqa64 zmm24, zmmword ptr [rip + fixMask3] vmovdqa64 zmm25, zmmword ptr [rip + fixMask4] vmovdqa64 zmm26, zmmword ptr [rip + fixMask5] vpsllq zmm28, zmm4, 32 vpxorq zmm28, zmm28, zmm3 vpermi2d zmm24, zmm2, zmm28 vpermi2w zmm25, zmm2, zmm28 vpermi2d zmm26, zmm2, zmm28 vpsrlvq zmm24, zmm24, zmmword ptr [rip + fixShift3] vpsllvq zmm25, zmm25, zmmword ptr [rip + fixShift4] vpsllvq zmm13, zmm26, zmmword ptr [rip + fixShift5] mov eax, 134217856 kmovd k1, eax vpsllw zmm25 {k1}, zmm25, 10 # We can sum T0 + T1 with no carry # Carry can occur when we add T2 vpaddq zmm1, zmm25, zmm24 ################# # Recombine bits 1024:1535 vmovdqa64 zmm24, zmmword ptr [rip + fixMask6] vmovdqa64 zmm25, zmmword ptr [rip + fixMask7] vmovdqa64 zmm26, zmmword ptr [rip + fixMask8] vpsllq zmm28, zmm6, 32 vpxorq zmm28, zmm28, zmm5 vpermi2d zmm24, zmm4, zmm28 vpermi2w zmm25, zmm4, zmm28 vpermi2d zmm26, zmm4, zmm28 vpsrlvq zmm24, zmm24, zmmword ptr [rip + fixShift6] vpsllvq zmm25, zmm25, zmmword ptr [rip + fixShift7] vpsllvq zmm14, zmm26, zmmword ptr [rip + fixShift8] mov eax, 32768 kmovd k1, eax vpsllw zmm25 {k1}, zmm25, 10 # We can sum T0 + T1 with no carry # Carry can occur when we add T2 vpaddq zmm2, zmm25, zmm24 ################# # Recombine bits 1536:2047 vmovdqa64 zmm24, zmmword ptr [rip + fixMask9] vmovdqa64 zmm25, zmmword ptr [rip + fixMask10] vmovdqa64 zmm26, zmmword ptr [rip + fixMask11] vpsllq zmm28, zmm8, 32 vpxorq zmm28, zmm28, zmm7 vpermi2d zmm24, zmm6, zmm28 vpermi2w zmm25, zmm6, zmm28 vpermi2d zmm26, zmm6, zmm28 vpsrlvq zmm24, zmm24, zmmword ptr [rip + fixShift9] vpsllvq zmm25, zmm25, zmmword ptr [rip + fixShift10] vpsllvq zmm15, zmm26, zmmword ptr [rip + fixShift11] mov eax, 8388616 kmovd k1, eax vpsllw zmm25 {k1}, zmm25, 10 # We can sum T0 + T1 with no carry # Carry can occur when we add T2 vpaddq zmm3, zmm25, zmm24 ################# # Add and propagate carry vpaddq zmm0, zmm0, zmm29 vpaddq zmm1, zmm1, zmm13 vpaddq zmm2, zmm2, zmm14 vpaddq zmm3, zmm3, zmm15 vpsubq zmm23, zmm20, zmm22 vpcmpltuq k1, zmm0, zmm29 vpcmpltuq k2, zmm1, zmm13 vpcmpltuq k3, zmm2, zmm14 vpcmpltuq k4, zmm3, zmm15 kmovb eax, k1 kmovb ecx, k2 kmovb edx, k3 kmovb esi, k4 add al, al adc cl, cl adc dl, dl adc sil, sil vpcmpequq k1, zmm0, zmm23 vpcmpequq k2, zmm1, zmm23 vpcmpequq k3, zmm2, zmm23 vpcmpequq k4, zmm3, zmm23 kmovb r8d, k1 kmovb r9d, k2 kmovb r10d, k3 kmovb r11d, k4 add al, r8b adc cl, r9b adc dl, r10b adc sil, r11b xor al, r8b xor cl, r9b xor dl, r10b xor sil, r11b kmovb k1, eax kmovb k2, ecx kmovb k3, edx kmovb k4, esi vpsubq zmm0 {k1}, zmm0, zmm23 vpsubq zmm1 {k2}, zmm1, zmm23 vpsubq zmm2 {k3}, zmm2, zmm23 vpsubq zmm3 {k4}, zmm3, zmm23 vmovdqu64 zmmword ptr [rdi], zmm0 vmovdqu64 zmmword ptr [rdi + 64], zmm1 vmovdqu64 zmmword ptr [rdi + 128], zmm2 vmovdqu64 zmmword ptr [rdi + 192], zmm3 ret \sourceoff Davor steht dann noch die Definition der Konstanten, was ich ausgelassen habe. Da wäre es nat. schön, wenn man sie einfach übernehmen kann, aber ich weiß nicht ob die Definition der Konstanten in beiden Assembler-Dialekten (AT&T / Intel) gleich ist. Was bei der Konvertierung leider auch verloren ging sind die 'Platzhalter'-Namen wie z.B. '.set A0, %zmm9'. Aber die kann man wahrscheinlich einfach wieder einfügen. Gruß Yggdrasil


   Profil
Yggdrasil
Senior Letzter Besuch: in der letzten Woche
Dabei seit: 01.07.2004
Mitteilungen: 863
Wohnort: Berlin
  Beitrag No.2, eingetragen 2023-09-18 12:36

Meine Komplettübertragung der Assembler-Funktion in die Intel-Syntax lautet folgendermaßen. Da meine CPU das nicht unterstützt, kann ich es nicht testen, aber binär kommt kompiliert das identische Resultat heraus im Vergleich zur Originalversion. \sourceon Assembler /* * Multiply two 1024-bit numbers using AVX512F instructions * * Copyright (C) 2015 Vlad Krasnov * Copyright (C) 2015 Shay Gueron * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ .intel_syntax noprefix .p2align 6, 0x90 # Masks to convert 2^64->2^29 permMask: .short 0 .short 1 .short 0 .short 0 .short 1 .short 2 .short 3 .short 0 .short 3 .short 4 .short 5 .short 0 .short 5 .short 6 .short 7 .short 0 .short 7 .short 8 .short 9 .short 0 .short 9 .short 10 .short 0 .short 0 .short 10 .short 11 .short 12 .short 0 .short 12 .short 13 .short 14 .short 0 shiftMask: .quad 0 .quad 13 .quad 10 .quad 7 .quad 4 .quad 1 .quad 14 .quad 11 # Masks to convert 2^29->2^64 .p2align 6, 0x90 fixMask0: .long 0 .long 1 .long 4 .long 1 .long 8 .long 1 .long 12 .long 1 .long 16 .long 1 .long 22 .long 1 .long 26 .long 1 .long 30 .long 1 fixMask1: .short 4 .short 5 .short 3 .short 3 .short 12 .short 13 .short 3 .short 3 .short 20 .short 21 .short 3 .short 3 .short 28 .short 29 .short 3 .short 3 .short 36 .short 37 .short 3 .short 44 .short 48 .short 49 .short 3 .short 3 .short 56 .short 57 .short 3 .short 3 .short 34 .short 35 .short 3 .short 3 fixMask2: .long 4 .long 1 .long 8 .long 1 .long 12 .long 1 .long 16 .long 1 .long 20 .long 1 .long 26 .long 1 .long 30 .long 1 .long 19 .long 1 fixShift0: .quad 0 .quad 6 .quad 12 .quad 18 .quad 24 .quad 1 .quad 7 .quad 13 fixShift1: .quad 29 .quad 23 .quad 17 .quad 11 .quad 5 .quad 28 .quad 22 .quad 16 fixShift2: .quad 58 .quad 52 .quad 46 .quad 40 .quad 34 .quad 57 .quad 51 .quad 45 fixMask3: .long 2 .long 1 .long 6 .long 1 .long 12 .long 1 .long 16 .long 1 .long 20 .long 1 .long 24 .long 1 .long 28 .long 1 .long 19 .long 1 fixMask4: .short 8 .short 9 .short 3 .short 3 .short 16 .short 17 .short 3 .short 24 .short 28 .short 29 .short 3 .short 3 .short 36 .short 37 .short 3 .short 3 .short 44 .short 45 .short 3 .short 3 .short 52 .short 53 .short 3 .short 3 .short 60 .short 61 .short 3 .short 38 .short 42 .short 43 .short 3 .short 3 fixMask5: .long 6 .long 1 .long 10 .long 1 .long 16 .long 1 .long 20 .long 1 .long 24 .long 1 .long 28 .long 1 .long 17 .long 1 .long 23 .long 1 fixShift3: .quad 19 .quad 25 .quad 2 .quad 8 .quad 14 .quad 20 .quad 26 .quad 3 fixShift4: .quad 10 .quad 4 .quad 27 .quad 21 .quad 15 .quad 9 .quad 3 .quad 26 fixShift5: .quad 39 .quad 33 .quad 56 .quad 50 .quad 44 .quad 38 .quad 32 .quad 55 fixMask6: .long 6 .long 1 .long 10 .long 1 .long 14 .long 1 .long 18 .long 1 .long 24 .long 1 .long 28 .long 1 .long 17 .long 1 .long 21 .long 1 fixMask7: .short 16 .short 17 .short 3 .short 3 .short 24 .short 25 .short 3 .short 3 .short 32 .short 33 .short 3 .short 3 .short 40 .short 41 .short 3 .short 48 .short 52 .short 53 .short 3 .short 3 .short 60 .short 61 .short 3 .short 3 .short 38 .short 39 .short 3 .short 3 .short 46 .short 47 .short 3 .short 3 fixMask8: .long 10 .long 1 .long 14 .long 1 .long 18 .long 1 .long 22 .long 1 .long 28 .long 1 .long 17 .long 1 .long 21 .long 1 .long 25 .long 1 fixShift6: .quad 9 .quad 15 .quad 21 .quad 27 .quad 4 .quad 10 .quad 16 .quad 22 fixShift7: .quad 20 .quad 14 .quad 8 .quad 2 .quad 25 .quad 19 .quad 13 .quad 7 fixShift8: .quad 49 .quad 43 .quad 37 .quad 31 .quad 54 .quad 48 .quad 42 .quad 36 fixMask9: .long 8 .long 1 .long 14 .long 1 .long 18 .long 1 .long 22 .long 1 .long 26 .long 1 .long 30 .long 1 .long 21 .long 1 .long 25 .long 1 fixMask10: .short 20 .short 21 .short 3 .short 28 .short 32 .short 33 .short 3 .short 3 .short 40 .short 41 .short 3 .short 3 .short 48 .short 49 .short 3 .short 3 .short 56 .short 57 .short 3 .short 3 .short 34 .short 35 .short 3 .short 42 .short 46 .short 47 .short 3 .short 3 .short 54 .short 55 .short 3 .short 3 fixMask11: .long 12 .long 1 .long 18 .long 1 .long 22 .long 1 .long 26 .long 1 .long 30 .long 1 .long 19 .long 1 .long 25 .long 1 .long 29 .long 1 fixShift9: .quad 28 .quad 5 .quad 11 .quad 17 .quad 23 .quad 29 .quad 6 .quad 12 fixShift10: .quad 1 .quad 24 .quad 18 .quad 12 .quad 6 .quad 0 .quad 23 .quad 17 fixShift11: .quad 30 .quad 53 .quad 47 .quad 41 .quad 35 .quad 29 .quad 52 .quad 46 # Mask for the bottom 29 bits andMask: .quad 0x1FFFFFFF # The constant 1 one: .quad 1 # The result is 2048 bit. ceil(2048/29) = 71. ceil(40/8) = 9. # Therefore 9 registers for the result. .set ACC0, %zmm0 .set ACC1, %zmm1 .set ACC2, %zmm2 .set ACC3, %zmm3 .set ACC4, %zmm4 .set ACC5, %zmm5 .set ACC6, %zmm6 .set ACC7, %zmm7 .set ACC8, %zmm8 # The inputs are 1024 bit. ceil(1024/29) = 36. ceil(36/8) = 5. .set A0, %zmm9 .set A1, %zmm10 .set A2, %zmm11 .set A3, %zmm12 .set A4, %zmm13 .set A5, %zmm14 .set B0, %zmm15 .set B1, %zmm16 .set B2, %zmm17 .set B3, %zmm18 .set B4, %zmm19 # Helper registers .set ZERO, %zmm20 # always zero .set IDX, %zmm21 # current index for the permutation .set ONE, %zmm22 # (uint64_t)1, broadcasted .set AND_MASK, %zmm23 # for masking the 29 bits of each qword .set T0, %zmm24 .set T1, %zmm25 .set T2, %zmm26 .set T3, %zmm27 .set T4, %zmm28 .set H0, %zmm29 # To be used only after we are done with A and B .set T5, A0 .set T6, A1 .set T7, A2 .set T8, A3 .set H1, A4 .set H2, A5 .set H3, B0 .set H4, B1 .set H5, B2 .set H6, B3 .set H7, B4 .set H8, %zmm30 # ABI registers .set res, %rdi .set a, %rsi .set b, %rdx # Iterators .set itr1, %rax .set itr2, %rcx # void mul1024_avx512(uint64_t res[32], uint64_t a[16], uint64_t b[16]); .globl mul1024_avx512 .type mul1024_avx512,@function mul1024_avx512: mov ecx, 63 kmovd k1, ecx vpxorq ZERO, ZERO, ZERO vpxorq IDX, IDX, IDX # First we need to convert the input from radix 2^64 to redundant 2^29 vmovdqa64 T0, zmmword ptr [rip + permMask] vmovdqa64 T1, zmmword ptr [rip + shiftMask] vpbroadcastq AND_MASK, qword ptr [rip + andMask] vpbroadcastq ONE, qword ptr [rip + one] # Load values with 29-byte intervals and shuffle + shift accordingly # First A vpermw A0, T0, zmmword ptr [rsi] vpermw A1, T0, zmmword ptr [rsi + 29] vpermw A2, T0, zmmword ptr [rsi + 58] vpermw A3, T0, zmmword ptr [rsi + 87] vmovdqu16 A4 {k1} {z}, zmmword ptr [rsi + 116] vpermw A4, T0, A4 vpsrlvq A0, A0, T1 vpsrlvq A1, A1, T1 vpsrlvq A2, A2, T1 vpsrlvq A3, A3, T1 vpsrlvq A4, A4, T1 vpandq A0, A0, AND_MASK vpandq A1, A1, AND_MASK vpandq A2, A2, AND_MASK vpandq A3, A3, AND_MASK vpandq A4, A4, AND_MASK vpxorq A5, A5, A5 # Then B vpermw B0, T0, zmmword ptr [rdx] vpermw B1, T0, zmmword ptr [rdx + 29] vpermw B2, T0, zmmword ptr [rdx + 58] vpermw B3, T0, zmmword ptr [rdx + 87] vmovdqu16 B4 {k1} {z}, zmmword ptr [rdx + 116] vpermw B4, T0, B4 vpsrlvq B0, B0, T1 vpsrlvq B1, B1, T1 vpsrlvq B2, B2, T1 vpsrlvq B3, B3, T1 vpsrlvq B4, B4, T1 vpandq B0, B0, AND_MASK vpandq B1, B1, AND_MASK vpandq B2, B2, AND_MASK vpandq B3, B3, AND_MASK vpandq B4, B4, AND_MASK # Zero the accumulators vpxorq ACC0, ACC0, ACC0 vpxorq ACC1, ACC1, ACC1 vpxorq ACC2, ACC2, ACC2 vpxorq ACC3, ACC3, ACC3 vpxorq ACC4, ACC4, ACC4 vpxorq ACC5, ACC5, ACC5 vpxorq ACC6, ACC6, ACC6 vpxorq ACC7, ACC7, ACC7 vpxorq ACC8, ACC8, ACC8 # The classic approach is to multiply by a single digit of B # each iteration, however we prefer to multiply by all digits # with 8-digit interval, while the registers are aligned, and then # shift. We have a total of 36 digits, therefore we multipy A in 8 # iterations by the following digits: # itr 0: 0,8,16,24,32 # itr 1: 1,9,17,25,33 # itr 2: 2,10,18,26,34 # itr 3: 3,11,19,27,35 # itr 4: 4,12,20,28 # itr 5: 5,13,21,29 # itr 6: 6,14,22,30 # itr 7: 7,15,23,31 # IDX holds the index of the currently required value mov itr1, 5 mov itr2, 4 1: # Get the correct digits into T0, T1 and T2 vpermq T0, IDX, B0 vpermq T1, IDX, B1 vpermq T2, IDX, B2 vpermq T3, IDX, B3 vpermq T4, IDX, B4 vpaddq IDX, IDX, ONE # Multiply the correctly aligned values vpmuludq H0, T0, A0 vpaddq ACC0, ACC0, H0 vpmuludq H0, T0, A1 vpaddq ACC1, ACC1, H0 vpmuludq H0, T0, A2 vpaddq ACC2, ACC2, H0 vpmuludq H0, T0, A3 vpaddq ACC3, ACC3, H0 vpmuludq H0, T0, A4 vpaddq ACC4, ACC4, H0 vpmuludq H0, T1, A0 vpaddq ACC1, ACC1, H0 vpmuludq H0, T1, A1 vpaddq ACC2, ACC2, H0 vpmuludq H0, T1, A2 vpaddq ACC3, ACC3, H0 vpmuludq H0, T1, A3 vpaddq ACC4, ACC4, H0 vpmuludq H0, T1, A4 vpaddq ACC5, ACC5, H0 vpmuludq H0, T2, A0 vpaddq ACC2, ACC2, H0 vpmuludq H0, T2, A1 vpaddq ACC3, ACC3, H0 vpmuludq H0, T2, A2 vpaddq ACC4, ACC4, H0 vpmuludq H0, T2, A3 vpaddq ACC5, ACC5, H0 vpmuludq H0, T2, A4 vpaddq ACC6, ACC6, H0 vpmuludq H0, T3, A0 vpaddq ACC3, ACC3, H0 vpmuludq H0, T3, A1 vpaddq ACC4, ACC4, H0 vpmuludq H0, T3, A2 vpaddq ACC5, ACC5, H0 vpmuludq H0, T3, A3 vpaddq ACC6, ACC6, H0 vpmuludq H0, T3, A4 vpaddq ACC7, ACC7, H0 vpmuludq H0, T4, A0 vpaddq ACC4, ACC4, H0 vpmuludq H0, T4, A1 vpaddq ACC5, ACC5, H0 vpmuludq H0, T4, A2 vpaddq ACC6, ACC6, H0 vpmuludq H0, T4, A3 vpaddq ACC7, ACC7, H0 vpmuludq H0, T4, A4 vpaddq ACC8, ACC8, H0 dec itr1 je 3f # We need to align the accumulator, but that will create dependency # on the output of the previous operation. # Instead we align A (which also has fewer digits). # However A will overflow after 4 such iterations, # this is when we switch to a slightly different loop valignq A4, A4, A3, 7 # A4 = A3[7],A4[0,1,2,3,4,5,6] valignq A3, A3, A2, 7 # A3 = A2[7],A3[0,1,2,3,4,5,6] valignq A2, A2, A1, 7 # A2 = A1[7],A2[0,1,2,3,4,5,6] valignq A1, A1, A0, 7 # A1 = A0[7],A1[0,1,2,3,4,5,6] valignq A0, A0, ZERO, 7 # A0 = ZERO[7],A0[0,1,2,3,4,5,6] jmp 1b 2: # Get the correct digits into T0 and T1 # We finished all the digits in B4 vpermq T0, IDX, B0 vpermq T1, IDX, B1 vpermq T2, IDX, B2 vpermq T3, IDX, B3 vpaddq IDX, IDX, ONE # Multiply the correctly aligned values, since A overflowed we now # have more multiplications vpmuludq H0, T0, A0 vpaddq ACC0, ACC0, H0 vpmuludq H0, T0, A1 vpaddq ACC1, ACC1, H0 vpmuludq H0, T0, A2 vpaddq ACC2, ACC2, H0 vpmuludq H0, T0, A3 vpaddq ACC3, ACC3, H0 vpmuludq H0, T0, A4 vpaddq ACC4, ACC4, H0 vpmuludq H0, T0, A5 vpaddq ACC5, ACC5, H0 vpmuludq H0, T1, A0 vpaddq ACC1, ACC1, H0 vpmuludq H0, T1, A1 vpaddq ACC2, ACC2, H0 vpmuludq H0, T1, A2 vpaddq ACC3, ACC3, H0 vpmuludq H0, T1, A3 vpaddq ACC4, ACC4, H0 vpmuludq H0, T1, A4 vpaddq ACC5, ACC5, H0 vpmuludq H0, T1, A5 vpaddq ACC6, ACC6, H0 vpmuludq H0, T2, A0 vpaddq ACC2, ACC2, H0 vpmuludq H0, T2, A1 vpaddq ACC3, ACC3, H0 vpmuludq H0, T2, A2 vpaddq ACC4, ACC4, H0 vpmuludq H0, T2, A3 vpaddq ACC5, ACC5, H0 vpmuludq H0, T2, A4 vpaddq ACC6, ACC6, H0 vpmuludq H0, T2, A5 vpaddq ACC7, ACC7, H0 vpmuludq H0, T3, A0 vpaddq ACC3, ACC3, H0 vpmuludq H0, T3, A1 vpaddq ACC4, ACC4, H0 vpmuludq H0, T3, A2 vpaddq ACC5, ACC5, H0 vpmuludq H0, T3, A3 vpaddq ACC6, ACC6, H0 vpmuludq H0, T3, A4 vpaddq ACC7, ACC7, H0 vpmuludq H0, T3, A5 vpaddq ACC8, ACC8, H0 # This is the entry point for the second loop 3: valignq A5, A5, A4, 7 # A5 = A4[7],A5[0,1,2,3,4,5,6] valignq A4, A4, A3, 7 # A4 = A3[7],A4[0,1,2,3,4,5,6] valignq A3, A3, A2, 7 # A3 = A2[7],A3[0,1,2,3,4,5,6] valignq A2, A2, A1, 7 # A2 = A1[7],A2[0,1,2,3,4,5,6] valignq A1, A1, A0, 7 # A1 = A0[7],A1[0,1,2,3,4,5,6] valignq A0, A0, ZERO, 7 # A0 = ZERO[7],A0[0,1,2,3,4,5,6] dec itr2 jne 2b # Perform two folds of the top bits, for # easier recombination. vpsrlq T0, ACC0, 29 vpsrlq T1, ACC1, 29 vpsrlq T2, ACC2, 29 vpsrlq T3, ACC3, 29 vpsrlq T4, ACC4, 29 vpsrlq A0, ACC5, 29 vpsrlq A1, ACC6, 29 vpsrlq A2, ACC7, 29 vpsrlq A3, ACC8, 29 vpsrlq H0, ACC0, 58 vpsrlq A4, ACC1, 58 vpsrlq A5, ACC2, 58 vpsrlq B0, ACC3, 58 vpsrlq B1, ACC4, 58 vpsrlq B2, ACC5, 58 vpsrlq B3, ACC6, 58 vpsrlq B4, ACC7, 58 vpsrlq H8, ACC8, 58 vpandq ACC0, ACC0, AND_MASK vpandq ACC1, ACC1, AND_MASK vpandq ACC2, ACC2, AND_MASK vpandq ACC3, ACC3, AND_MASK vpandq ACC4, ACC4, AND_MASK vpandq ACC5, ACC5, AND_MASK vpandq ACC6, ACC6, AND_MASK vpandq ACC7, ACC7, AND_MASK vpandq ACC8, ACC8, AND_MASK vpandq T0, T0, AND_MASK vpandq T1, T1, AND_MASK vpandq T2, T2, AND_MASK vpandq T3, T3, AND_MASK vpandq T4, T4, AND_MASK vpandq A0, A0, AND_MASK vpandq A1, A1, AND_MASK vpandq A2, A2, AND_MASK vpandq A3, A3, AND_MASK valignq A3, A3, A2, 7 # A3 = A2[7],A3[0,1,2,3,4,5,6] valignq A2, A2, A1, 7 # A2 = A1[7],A2[0,1,2,3,4,5,6] valignq A1, A1, A0, 7 # A1 = A0[7],A1[0,1,2,3,4,5,6] valignq A0, A0, T4, 7 # A0 = T4[7],A0[0,1,2,3,4,5,6] valignq T4, T4, T3, 7 # T4 = T3[7],T4[0,1,2,3,4,5,6] valignq T3, T3, T2, 7 # T3 = T2[7],T3[0,1,2,3,4,5,6] valignq T2, T2, T1, 7 # T2 = T1[7],T2[0,1,2,3,4,5,6] valignq T1, T1, T0, 7 # T1 = T0[7],T1[0,1,2,3,4,5,6] valignq T0, T0, ZERO, 7 # T0 = ZERO[7],T0[0,1,2,3,4,5,6] valignq H8, H8, B4, 6 # H8 = B4[6,7],H8[0,1,2,3,4,5] valignq B4, B4, B3, 6 # B4 = B3[6,7],B4[0,1,2,3,4,5] valignq B3, B3, B2, 6 # B3 = B2[6,7],B3[0,1,2,3,4,5] valignq B2, B2, B1, 6 # B2 = B1[6,7],B2[0,1,2,3,4,5] valignq B1, B1, B0, 6 # B1 = B0[6,7],B1[0,1,2,3,4,5] valignq B0, B0, A5, 6 # B0 = A5[6,7],B0[0,1,2,3,4,5] valignq A5, A5, A4, 6 # A5 = A4[6,7],A5[0,1,2,3,4,5] valignq A4, A4, H0, 6 # A4 = H0[6,7],A4[0,1,2,3,4,5] valignq H0, H0, ZERO, 6 # H0 = ZERO[6,7],H0[0,1,2,3,4,5] vpaddq ACC0, ACC0, T0 vpaddq ACC1, ACC1, T1 vpaddq ACC2, ACC2, T2 vpaddq ACC3, ACC3, T3 vpaddq ACC4, ACC4, T4 vpaddq ACC5, ACC5, A0 vpaddq ACC6, ACC6, A1 vpaddq ACC7, ACC7, A2 vpaddq ACC8, ACC8, A3 vpaddq ACC0, ACC0, H0 vpaddq ACC1, ACC1, A4 vpaddq ACC2, ACC2, A5 vpaddq ACC3, ACC3, B0 vpaddq ACC4, ACC4, B1 vpaddq ACC5, ACC5, B2 vpaddq ACC6, ACC6, B3 vpaddq ACC7, ACC7, B4 vpaddq ACC8, ACC8, H8 # At this stage the redundant values occupy at most 30bit containers ################# # Recombine bits 0:511 vmovdqa64 T0, zmmword ptr [rip + fixMask0] vmovdqa64 T1, zmmword ptr [rip + fixMask1] vmovdqa64 T2, zmmword ptr [rip + fixMask2] # Combine ACC2 and ACC1 so we can address more words in the permute vpsllq T4, ACC2, 32 vpxorq T4, T4, ACC1 vpermi2d T0, ACC0, T4 vpermi2w T1, ACC0, T4 vpermi2d T2, ACC0, T4 vpsrlvq T0, T0, zmmword ptr [rip + fixShift0] vpsllvq T1, T1, zmmword ptr [rip + fixShift1] vpsllvq H0, T2, zmmword ptr [rip + fixShift2] mov eax, 0x80000 kmovd k1, eax vpsllw T1 {k1}, T1, 10 # We can sum T0 + T1 with no carry # Carry can occur when we add T2 vpaddq ACC0, T1, T0 ################# # Recombine bits 512:1023 vmovdqa64 T0, zmmword ptr [rip + fixMask3] vmovdqa64 T1, zmmword ptr [rip + fixMask4] vmovdqa64 T2, zmmword ptr [rip + fixMask5] vpsllq T4, ACC4, 32 vpxorq T4, T4, ACC3 vpermi2d T0, ACC2, T4 vpermi2w T1, ACC2, T4 vpermi2d T2, ACC2, T4 vpsrlvq T0, T0, zmmword ptr [rip + fixShift3] vpsllvq T1, T1, zmmword ptr [rip + fixShift4] vpsllvq A4, T2, zmmword ptr [rip + fixShift5] mov eax, 0x8000080 kmovd k1, eax vpsllw T1 {k1}, T1, 10 # We can sum T0 + T1 with no carry # Carry can occur when we add T2 vpaddq ACC1, T1, T0 ################# # Recombine bits 1024:1535 vmovdqa64 T0, zmmword ptr [rip + fixMask6] vmovdqa64 T1, zmmword ptr [rip + fixMask7] vmovdqa64 T2, zmmword ptr [rip + fixMask8] vpsllq T4, ACC6, 32 vpxorq T4, T4, ACC5 vpermi2d T0, ACC4, T4 vpermi2w T1, ACC4, T4 vpermi2d T2, ACC4, T4 vpsrlvq T0, T0, zmmword ptr [rip + fixShift6] vpsllvq T1, T1, zmmword ptr [rip + fixShift7] vpsllvq A5, T2, zmmword ptr [rip + fixShift8] mov eax, 0x8000 kmovd k1, eax vpsllw T1 {k1}, T1, 10 # We can sum T0 + T1 with no carry # Carry can occur when we add T2 vpaddq ACC2, T1, T0 ################# # Recombine bits 1536:2047 vmovdqa64 T0, zmmword ptr [rip + fixMask9] vmovdqa64 T1, zmmword ptr [rip + fixMask10] vmovdqa64 T2, zmmword ptr [rip + fixMask11] vpsllq T4, ACC8, 32 vpxorq T4, T4, ACC7 vpermi2d T0, ACC6, T4 vpermi2w T1, ACC6, T4 vpermi2d T2, ACC6, T4 vpsrlvq T0, T0, zmmword ptr [rip + fixShift9] vpsllvq T1, T1, zmmword ptr [rip + fixShift10] vpsllvq B0, T2, zmmword ptr [rip + fixShift11] mov eax, 0x800008 kmovd k1, eax vpsllw T1 {k1}, T1, 10 # We can sum T0 + T1 with no carry # Carry can occur when we add T2 vpaddq ACC3, T1, T0 ################# # Add and propagate carry vpaddq ACC0, ACC0, H0 vpaddq ACC1, ACC1, A4 vpaddq ACC2, ACC2, A5 vpaddq ACC3, ACC3, B0 vpsubq AND_MASK, ZERO, ONE vpcmpltuq k1, ACC0, H0 vpcmpltuq k2, ACC1, A4 vpcmpltuq k3, ACC2, A5 vpcmpltuq k4, ACC3, B0 kmovb eax, k1 kmovb ecx, k2 kmovb edx, k3 kmovb esi, k4 add al, al adc cl, cl adc dl, dl adc sil, sil vpcmpequq k1, ACC0, AND_MASK vpcmpequq k2, ACC1, AND_MASK vpcmpequq k3, ACC2, AND_MASK vpcmpequq k4, ACC3, AND_MASK kmovb r8d, k1 kmovb r9d, k2 kmovb r10d, k3 kmovb r11d, k4 add al, r8b adc cl, r9b adc dl, r10b adc sil, r11b xor al, r8b xor cl, r9b xor dl, r10b xor sil, r11b kmovb k1, eax kmovb k2, ecx kmovb k3, edx kmovb k4, esi vpsubq ACC0 {k1}, ACC0, AND_MASK vpsubq ACC1 {k2}, ACC1, AND_MASK vpsubq ACC2 {k3}, ACC2, AND_MASK vpsubq ACC3 {k4}, ACC3, AND_MASK vmovdqu64 zmmword ptr [rdi], ACC0 vmovdqu64 zmmword ptr [rdi + 64], ACC1 vmovdqu64 zmmword ptr [rdi + 128], ACC2 vmovdqu64 zmmword ptr [rdi + 192], ACC3 ret .size mul1024_avx512, .-mul1024_avx512 \sourceoff


   Profil
hyperG
Senior Letzter Besuch: in der letzten Woche
Dabei seit: 03.02.2017
Mitteilungen: 2106
  Beitrag No.3, vom Themenstarter, eingetragen 2023-09-18 16:55

Super Yggdrasil! Damit wäre Punkt b) Syntaxwandlung ja schon erledigt. Variante 1 gefällt mir sogar besser, da direkter, kürzer & kompatibler. Um Konstanten, PUSH, POP und Prozedurnamen kümmere ich mich dann schon. Wichtig ist jedoch a) die Vertauschung der ABI-Register von LINUX nach Windows: \sourceon ABI-Register-Vertauschung LINUX | Windows -------+--------- 4 Proc-Übergabeparameter rdi | rcx rsi | rdx rdx | r8 rcx | r9 ; 4. Übergabeparameter zur Reserve --------------- Restliche Register anpassen, da vordere sich nicht ändern dürfen rax | rax bleibt gleich r8 | rdx r9 | rcx r10 | r10 r11 | r11 \sourceoff Oben gibt es ja bereits eine universelle "ABI-Stelle" zum Tausch: Kannst Du bitte vor der Konvertierung diese Stelle ändern von \sourceon LINUX # ABI registers .set res, %rdi .set a, %rsi .set b, %rdx # Iterators .set itr1, %rax .set itr2, %rcx \sourceoff nach: \sourceon windows # ABI registers .set res, %rcx .set a, %rdx .set b, %r8 # Iterators .set itr1, %rax .set itr2, %r9 \sourceoff um alle Stellen Win-kompatibel nach Syntax Beitrag 1 zu bekommen? Das Kommentarzeichen # tausche ich dann noch nach ; oder Proc-Name ... passe ich dann noch an. Um die restliche Vertauschungen ab kmovb ecx, k2 ; Unterregister ecx gehört zu rcx ; getauscht mit r9 kümmere ich mich dann "per Hand", da sie fest vorgegeben waren (statt dynamisch wie weiter vorn -> mischmasch ist nie gut!). Grüße Gerd Konisch ist noch, dass Masken mal mit rip: vmovdqa64 T0, zmmword ptr [rip + permMask] und mal ohne rip geladen werden...


   Profil
hyperG
Senior Letzter Besuch: in der letzten Woche
Dabei seit: 03.02.2017
Mitteilungen: 2106
  Beitrag No.4, vom Themenstarter, eingetragen 2023-09-18 23:07

Nach zig Anpassungen {vpcmpuq k1, zmm0, zmm29,1 ;statt vpcmpequq ...} konnte nun dieser ASM-Code in eine OBJ gewandelt werden: \showon \sourceon asm .data ;SEGMENT 64 ;align 64 ; asm( ".align 64\n\t" LINUX Register: http://6.s081.scripts.mit.edu/sp18/x86-64-architecture-guide.html ; "# Masks to convert 2^64->2^29\n\t" ; clang -S -mllvm --x86-asm-syntax=intel test.c ;LINUX | Windows ;-------+--------- 4 Proc-Übergabeparameter ;rdi | rcx ;rsi | rdx ;rdx | r8 ;rcx | r9 ; 4. Übergabeparameter zur Reserve) ;--------------- Restliche Register anpassen, da vordere sich nicht ändern dürfen ;rax | rax bleibt gleich ; rcx | r12 statt r9!! ;ecx | r12d ; cl | r12b ;edx | r8d ;esi | edx ; dl | r8b ;sil | dl ;r8 | rbx ;nicht rdx ;r8d | ebx ;r8b | bl ;r9 | r9 bleibt ;nicht rcx, da 1. In Ptr ! ;r9d | r9d nicht ecx ;r9b | r9b nicht cl ;r10 | r10 ;r11 | r11 ; Masks to convert 2^64->2^29 | short=DB = 1byte=8bit | DW word=2 bytes |long DD 4 Byte|quad=DQ permMask: DB 0 DB 1 DB 0 DB 0 DB 1 DB 2 DB 3 DB 0 DB 3 DB 4 DB 5 DB 0 DB 5 DB 6 DB 7 DB 0 DB 7 DB 8 DB 9 DB 0 DB 9 DB 10 DB 0 DB 0 DB 10 DB 11 DB 12 DB 0 DB 12 DB 13 DB 14 DB 0 shiftMask: DQ 0 DQ 13 DQ 10 DQ 7 DQ 4 DQ 1 DQ 14 DQ 11 ; Masks to convert 2^29->2^64 ;align 64 fixMask0: DD 0, 1, 4, 1, 8, 1,12, 1,16, 1,22, 1,26, 1,30, 1 fixMask1: DB 4, 5, 3, 3 DB 12,13, 3, 3 DB 20,21, 3, 3 DB 28,29, 3, 3 DB 36,37, 3,44 DB 48,49, 3, 3 DB 56,57, 3, 3 DB 34,35, 3, 3 fixMask2: DD 4, 1, 8, 1,12, 1,16, 1,20, 1,26, 1,30, 1,19, 1 fixShift0: DQ 0, 6,12,18,24, 1, 7,13 fixShift1: DQ 29,23,17,11, 5,28,22,16 fixShift2: DQ 58,52,46,40,34,57,51,45 fixMask3: DD 2, 1, 6, 1,12, 1,16, 1,20, 1,24, 1,28, 1,19, 1 fixMask4: DB 8, 9, 3, 3 DB 16,17, 3,24 DB 28,29, 3, 3 DB 36,37, 3, 3 DB 44,45, 3, 3 DB 52,53, 3, 3 DB 60,61, 3,38 DB 42,43, 3, 3 fixMask5: DD 6, 1,10, 1,16, 1,20, 1,24, 1,28, 1,17, 1,23, 1 fixShift3: DQ 19,25, 2, 8,14,20,26, 3 fixShift4: DQ 10, 4,27,21,15, 9, 3,26 fixShift5: DQ 39,33,56,50,44,38,32,55 fixMask6: DD 6, 1,10, 1,14, 1,18, 1,24, 1,28, 1,17, 1,21, 1 fixMask7: DB 16,17, 3, 3 DB 24,25, 3, 3 DB 32,33, 3, 3 DB 40,41, 3,48 DB 52,53, 3, 3 DB 60,61, 3, 3 DB 38,39, 3, 3 DB 46,47, 3, 3 fixMask8: DD 10, 1,14, 1,18, 1,22, 1,28, 1,17, 1,21, 1,25, 1 fixShift6: DQ 9,15,21,27, 4,10,16,22 fixShift7: DQ 20,14, 8, 2,25,19,13, 7 fixShift8: DQ 49,43,37,31,54,48,42,36 fixMask9: DD 8, 1,14, 1,18, 1,22, 1,26, 1,30, 1,21, 1,25, 1 fixMask10: DB 20,21, 3,28 DB 32,33, 3, 3 DB 40,41, 3, 3 DB 48,49, 3, 3 DB 56,57, 3, 3 DB 34,35, 3,42 DB 46,47, 3, 3 DB 54,55, 3, 3 fixMask11: DD 12, 1,18, 1,22, 1,26, 1,30, 1,19, 1,25, 1,29, 1 fixShift9: DQ 28, 5,11,17,23,29, 6,12 fixShift10: DQ 1,24,18,12, 6, 0,23,17 fixShift11: DQ 30,53,47,41,35,29,52,46 ; Mask for the bottom 29 bits andMask: DQ 536870911 ;0x1FFFFFFF ; The constant 1 one: DQ 1 .code avx512_mul1024 proc push r12 push r11 push r10 push r9 push rbx mov r12d, 63 kmovd k1, r12d vpxorq zmm20, zmm20, zmm20 vpxorq zmm21, zmm21, zmm21 ; First we need to convert the input from radix 2^64 to redundant 2^29 vmovdqa64 zmm24, zmmword ptr [ permMask] ;rip + vmovdqa64 zmm25, zmmword ptr [shiftMask] ;rip + vpbroadcastq zmm23, qword ptr [ andMask] vpbroadcastq zmm22, qword ptr [ one] ; Load values with 29-byte intervals and shuffle + shift accordingly ; First A vpermw zmm9, zmm24, zmmword ptr [rdx] vpermw zmm10, zmm24, zmmword ptr [rdx + 29] vpermw zmm11, zmm24, zmmword ptr [rdx + 58] vpermw zmm12, zmm24, zmmword ptr [rdx + 87] vmovdqu16 zmm13 {k1} {z}, zmmword ptr [rdx + 116] vpermw zmm13, zmm24, zmm13 vpsrlvq zmm9, zmm9, zmm25 vpsrlvq zmm10, zmm10, zmm25 vpsrlvq zmm11, zmm11, zmm25 vpsrlvq zmm12, zmm12, zmm25 vpsrlvq zmm13, zmm13, zmm25 vpandq zmm9, zmm9, zmm23 vpandq zmm10, zmm10, zmm23 vpandq zmm11, zmm11, zmm23 vpandq zmm12, zmm12, zmm23 vpandq zmm13, zmm13, zmm23 vpxorq zmm14, zmm14, zmm14 ; Then B vpermw zmm15, zmm24, zmmword ptr [r8] vpermw zmm16, zmm24, zmmword ptr [r8 + 29] vpermw zmm17, zmm24, zmmword ptr [r8 + 58] vpermw zmm18, zmm24, zmmword ptr [r8 + 87] vmovdqu16 zmm19 {k1} {z}, zmmword ptr [r8 + 116] vpermw zmm19, zmm24, zmm19 vpsrlvq zmm15, zmm15, zmm25 vpsrlvq zmm16, zmm16, zmm25 vpsrlvq zmm17, zmm17, zmm25 vpsrlvq zmm18, zmm18, zmm25 vpsrlvq zmm19, zmm19, zmm25 vpandq zmm15, zmm15, zmm23 vpandq zmm16, zmm16, zmm23 vpandq zmm17, zmm17, zmm23 vpandq zmm18, zmm18, zmm23 vpandq zmm19, zmm19, zmm23 ; Zero the accumulators vpxorq zmm0, zmm0, zmm0 vpxorq zmm1, zmm1, zmm1 vpxorq zmm2, zmm2, zmm2 vpxorq zmm3, zmm3, zmm3 vpxorq zmm4, zmm4, zmm4 vpxorq zmm5, zmm5, zmm5 vpxorq zmm6, zmm6, zmm6 vpxorq zmm7, zmm7, zmm7 vpxorq zmm8, zmm8, zmm8 ; The classic approach is to multiply by a single digit of B ; each iteration, however we prefer to multiply by all digits ; with 8-digit interval, while the registers are aligned, and then ; shift. We have a total of 36 digits, therefore we multipy A in 8 ; iterations by the following digits: ; itr 0: 0,8,16,24,32 ; itr 1: 1,9,17,25,33 ; itr 2: 2,10,18,26,34 ; itr 3: 3,11,19,27,35 ; itr 4: 4,12,20,28 ; itr 5: 5,13,21,29 ; itr 6: 6,14,22,30 ; itr 7: 7,15,23,31 ; IDX holds the index of the currently required value mov rax, 5 mov r12, 4 ;rcx -> r12 !! Ltmp0: ; Get the correct digits into T0, T1 and T2 vpermq zmm24, zmm21, zmm15 vpermq zmm25, zmm21, zmm16 vpermq zmm26, zmm21, zmm17 vpermq zmm27, zmm21, zmm18 vpermq zmm28, zmm21, zmm19 vpaddq zmm21, zmm21, zmm22 ; Multiply the correctly aligned values vpmuludq zmm29, zmm24, zmm9 vpaddq zmm0, zmm0, zmm29 vpmuludq zmm29, zmm24, zmm10 vpaddq zmm1, zmm1, zmm29 vpmuludq zmm29, zmm24, zmm11 vpaddq zmm2, zmm2, zmm29 vpmuludq zmm29, zmm24, zmm12 vpaddq zmm3, zmm3, zmm29 vpmuludq zmm29, zmm24, zmm13 vpaddq zmm4, zmm4, zmm29 vpmuludq zmm29, zmm25, zmm9 vpaddq zmm1, zmm1, zmm29 vpmuludq zmm29, zmm25, zmm10 vpaddq zmm2, zmm2, zmm29 vpmuludq zmm29, zmm25, zmm11 vpaddq zmm3, zmm3, zmm29 vpmuludq zmm29, zmm25, zmm12 vpaddq zmm4, zmm4, zmm29 vpmuludq zmm29, zmm25, zmm13 vpaddq zmm5, zmm5, zmm29 vpmuludq zmm29, zmm26, zmm9 vpaddq zmm2, zmm2, zmm29 vpmuludq zmm29, zmm26, zmm10 vpaddq zmm3, zmm3, zmm29 vpmuludq zmm29, zmm26, zmm11 vpaddq zmm4, zmm4, zmm29 vpmuludq zmm29, zmm26, zmm12 vpaddq zmm5, zmm5, zmm29 vpmuludq zmm29, zmm26, zmm13 vpaddq zmm6, zmm6, zmm29 vpmuludq zmm29, zmm27, zmm9 vpaddq zmm3, zmm3, zmm29 vpmuludq zmm29, zmm27, zmm10 vpaddq zmm4, zmm4, zmm29 vpmuludq zmm29, zmm27, zmm11 vpaddq zmm5, zmm5, zmm29 vpmuludq zmm29, zmm27, zmm12 vpaddq zmm6, zmm6, zmm29 vpmuludq zmm29, zmm27, zmm13 vpaddq zmm7, zmm7, zmm29 vpmuludq zmm29, zmm28, zmm9 vpaddq zmm4, zmm4, zmm29 vpmuludq zmm29, zmm28, zmm10 vpaddq zmm5, zmm5, zmm29 vpmuludq zmm29, zmm28, zmm11 vpaddq zmm6, zmm6, zmm29 vpmuludq zmm29, zmm28, zmm12 vpaddq zmm7, zmm7, zmm29 vpmuludq zmm29, zmm28, zmm13 vpaddq zmm8, zmm8, zmm29 dec rax je Ltmp1 ; We need to align the accumulator, but that will create dependency ; on the output of the previous operation. ; Instead we align A (which also has fewer digits). ; However A will overflow after 4 such iterations, ; this is when we switch to a slightly different loop valignq zmm13, zmm13, zmm12, 7 ; zmm13 = zmm12[7],zmm13[0,1,2,3,4,5,6] valignq zmm12, zmm12, zmm11, 7 ; zmm12 = zmm11[7],zmm12[0,1,2,3,4,5,6] valignq zmm11, zmm11, zmm10, 7 ; zmm11 = zmm10[7],zmm11[0,1,2,3,4,5,6] valignq zmm10, zmm10, zmm9, 7 ; zmm10 = zmm9[7],zmm10[0,1,2,3,4,5,6] valignq zmm9, zmm9, zmm20, 7 ; zmm9 = zmm20[7],zmm9[0,1,2,3,4,5,6] jmp Ltmp0 Ltmp2: ; Get the correct digits into T0 and T1 ; We finished all the digits in B4 vpermq zmm24, zmm21, zmm15 vpermq zmm25, zmm21, zmm16 vpermq zmm26, zmm21, zmm17 vpermq zmm27, zmm21, zmm18 vpaddq zmm21, zmm21, zmm22 ; Multiply the correctly aligned values, since A overflowed we now ; have more multiplications vpmuludq zmm29, zmm24, zmm9 vpaddq zmm0, zmm0, zmm29 vpmuludq zmm29, zmm24, zmm10 vpaddq zmm1, zmm1, zmm29 vpmuludq zmm29, zmm24, zmm11 vpaddq zmm2, zmm2, zmm29 vpmuludq zmm29, zmm24, zmm12 vpaddq zmm3, zmm3, zmm29 vpmuludq zmm29, zmm24, zmm13 vpaddq zmm4, zmm4, zmm29 vpmuludq zmm29, zmm24, zmm14 vpaddq zmm5, zmm5, zmm29 vpmuludq zmm29, zmm25, zmm9 vpaddq zmm1, zmm1, zmm29 vpmuludq zmm29, zmm25, zmm10 vpaddq zmm2, zmm2, zmm29 vpmuludq zmm29, zmm25, zmm11 vpaddq zmm3, zmm3, zmm29 vpmuludq zmm29, zmm25, zmm12 vpaddq zmm4, zmm4, zmm29 vpmuludq zmm29, zmm25, zmm13 vpaddq zmm5, zmm5, zmm29 vpmuludq zmm29, zmm25, zmm14 vpaddq zmm6, zmm6, zmm29 vpmuludq zmm29, zmm26, zmm9 vpaddq zmm2, zmm2, zmm29 vpmuludq zmm29, zmm26, zmm10 vpaddq zmm3, zmm3, zmm29 vpmuludq zmm29, zmm26, zmm11 vpaddq zmm4, zmm4, zmm29 vpmuludq zmm29, zmm26, zmm12 vpaddq zmm5, zmm5, zmm29 vpmuludq zmm29, zmm26, zmm13 vpaddq zmm6, zmm6, zmm29 vpmuludq zmm29, zmm26, zmm14 vpaddq zmm7, zmm7, zmm29 vpmuludq zmm29, zmm27, zmm9 vpaddq zmm3, zmm3, zmm29 vpmuludq zmm29, zmm27, zmm10 vpaddq zmm4, zmm4, zmm29 vpmuludq zmm29, zmm27, zmm11 vpaddq zmm5, zmm5, zmm29 vpmuludq zmm29, zmm27, zmm12 vpaddq zmm6, zmm6, zmm29 vpmuludq zmm29, zmm27, zmm13 vpaddq zmm7, zmm7, zmm29 vpmuludq zmm29, zmm27, zmm14 vpaddq zmm8, zmm8, zmm29 ; This is the entry point for the second loop Ltmp1: valignq zmm14, zmm14, zmm13, 7 ; zmm14 = zmm13[7],zmm14[0,1,2,3,4,5,6] valignq zmm13, zmm13, zmm12, 7 ; zmm13 = zmm12[7],zmm13[0,1,2,3,4,5,6] valignq zmm12, zmm12, zmm11, 7 ; zmm12 = zmm11[7],zmm12[0,1,2,3,4,5,6] valignq zmm11, zmm11, zmm10, 7 ; zmm11 = zmm10[7],zmm11[0,1,2,3,4,5,6] valignq zmm10, zmm10, zmm9, 7 ; zmm10 = zmm9[7],zmm10[0,1,2,3,4,5,6] valignq zmm9, zmm9, zmm20, 7 ; zmm9 = zmm20[7],zmm9[0,1,2,3,4,5,6] dec r12 jne Ltmp2 ; Perform two folds of the top bits, for ; easier recombination. vpsrlq zmm24, zmm0, 29 vpsrlq zmm25, zmm1, 29 vpsrlq zmm26, zmm2, 29 vpsrlq zmm27, zmm3, 29 vpsrlq zmm28, zmm4, 29 vpsrlq zmm9, zmm5, 29 vpsrlq zmm10, zmm6, 29 vpsrlq zmm11, zmm7, 29 vpsrlq zmm12, zmm8, 29 vpsrlq zmm29, zmm0, 58 vpsrlq zmm13, zmm1, 58 vpsrlq zmm14, zmm2, 58 vpsrlq zmm15, zmm3, 58 vpsrlq zmm16, zmm4, 58 vpsrlq zmm17, zmm5, 58 vpsrlq zmm18, zmm6, 58 vpsrlq zmm19, zmm7, 58 vpsrlq zmm30, zmm8, 58 vpandq zmm0, zmm0, zmm23 vpandq zmm1, zmm1, zmm23 vpandq zmm2, zmm2, zmm23 vpandq zmm3, zmm3, zmm23 vpandq zmm4, zmm4, zmm23 vpandq zmm5, zmm5, zmm23 vpandq zmm6, zmm6, zmm23 vpandq zmm7, zmm7, zmm23 vpandq zmm8, zmm8, zmm23 vpandq zmm24, zmm24, zmm23 vpandq zmm25, zmm25, zmm23 vpandq zmm26, zmm26, zmm23 vpandq zmm27, zmm27, zmm23 vpandq zmm28, zmm28, zmm23 vpandq zmm9, zmm9, zmm23 vpandq zmm10, zmm10, zmm23 vpandq zmm11, zmm11, zmm23 vpandq zmm12, zmm12, zmm23 valignq zmm12, zmm12, zmm11, 7 ; zmm12 = zmm11[7],zmm12[0,1,2,3,4,5,6] valignq zmm11, zmm11, zmm10, 7 ; zmm11 = zmm10[7],zmm11[0,1,2,3,4,5,6] valignq zmm10, zmm10, zmm9, 7 ; zmm10 = zmm9[7],zmm10[0,1,2,3,4,5,6] valignq zmm9, zmm9, zmm28, 7 ; zmm9 = zmm28[7],zmm9[0,1,2,3,4,5,6] valignq zmm28, zmm28, zmm27, 7 ; zmm28 = zmm27[7],zmm28[0,1,2,3,4,5,6] valignq zmm27, zmm27, zmm26, 7 ; zmm27 = zmm26[7],zmm27[0,1,2,3,4,5,6] valignq zmm26, zmm26, zmm25, 7 ; zmm26 = zmm25[7],zmm26[0,1,2,3,4,5,6] valignq zmm25, zmm25, zmm24, 7 ; zmm25 = zmm24[7],zmm25[0,1,2,3,4,5,6] valignq zmm24, zmm24, zmm20, 7 ; zmm24 = zmm20[7],zmm24[0,1,2,3,4,5,6] valignq zmm30, zmm30, zmm19, 6 ; zmm30 = zmm19[6,7],zmm30[0,1,2,3,4,5] valignq zmm19, zmm19, zmm18, 6 ; zmm19 = zmm18[6,7],zmm19[0,1,2,3,4,5] valignq zmm18, zmm18, zmm17, 6 ; zmm18 = zmm17[6,7],zmm18[0,1,2,3,4,5] valignq zmm17, zmm17, zmm16, 6 ; zmm17 = zmm16[6,7],zmm17[0,1,2,3,4,5] valignq zmm16, zmm16, zmm15, 6 ; zmm16 = zmm15[6,7],zmm16[0,1,2,3,4,5] valignq zmm15, zmm15, zmm14, 6 ; zmm15 = zmm14[6,7],zmm15[0,1,2,3,4,5] valignq zmm14, zmm14, zmm13, 6 ; zmm14 = zmm13[6,7],zmm14[0,1,2,3,4,5] valignq zmm13, zmm13, zmm29, 6 ; zmm13 = zmm29[6,7],zmm13[0,1,2,3,4,5] valignq zmm29, zmm29, zmm20, 6 ; zmm29 = zmm20[6,7],zmm29[0,1,2,3,4,5] vpaddq zmm0, zmm0, zmm24 vpaddq zmm1, zmm1, zmm25 vpaddq zmm2, zmm2, zmm26 vpaddq zmm3, zmm3, zmm27 vpaddq zmm4, zmm4, zmm28 vpaddq zmm5, zmm5, zmm9 vpaddq zmm6, zmm6, zmm10 vpaddq zmm7, zmm7, zmm11 vpaddq zmm8, zmm8, zmm12 vpaddq zmm0, zmm0, zmm29 vpaddq zmm1, zmm1, zmm13 vpaddq zmm2, zmm2, zmm14 vpaddq zmm3, zmm3, zmm15 vpaddq zmm4, zmm4, zmm16 vpaddq zmm5, zmm5, zmm17 vpaddq zmm6, zmm6, zmm18 vpaddq zmm7, zmm7, zmm19 vpaddq zmm8, zmm8, zmm30 ; At this stage the redundant values occupy at most 30bit containers ; Recombine bits 0:511 vmovdqa64 zmm24, zmmword ptr [ fixMask0] ;rip + vmovdqa64 zmm25, zmmword ptr [fixMask1] vmovdqa64 zmm26, zmmword ptr [fixMask2] ; Combine ACC2 and ACC1 so we can address more words in the permute vpsllq zmm28, zmm2, 32 vpxorq zmm28, zmm28, zmm1 vpermi2d zmm24, zmm0, zmm28 vpermi2w zmm25, zmm0, zmm28 vpermi2d zmm26, zmm0, zmm28 vpsrlvq zmm24, zmm24, zmmword ptr [fixShift0] vpsllvq zmm25, zmm25, zmmword ptr [ fixShift1] vpsllvq zmm29, zmm26, zmmword ptr [ fixShift2] mov eax, 524288 kmovd k1, eax vpsllw zmm25 {k1}, zmm25, 10 ; We can sum T0 + T1 with no carry ; Carry can occur when we add T2 vpaddq zmm0, zmm25, zmm24 ; Recombine bits 512:1023 vmovdqa64 zmm24, zmmword ptr [ fixMask3] vmovdqa64 zmm25, zmmword ptr [ fixMask4] vmovdqa64 zmm26, zmmword ptr [ fixMask5] vpsllq zmm28, zmm4, 32 vpxorq zmm28, zmm28, zmm3 vpermi2d zmm24, zmm2, zmm28 vpermi2w zmm25, zmm2, zmm28 vpermi2d zmm26, zmm2, zmm28 vpsrlvq zmm24, zmm24, zmmword ptr [ fixShift3] vpsllvq zmm25, zmm25, zmmword ptr [ fixShift4] vpsllvq zmm13, zmm26, zmmword ptr [fixShift5] mov eax, 134217856 kmovd k1, eax vpsllw zmm25 {k1}, zmm25, 10 ; We can sum T0 + T1 with no carry ; Carry can occur when we add T2 vpaddq zmm1, zmm25, zmm24 ; Recombine bits 1024:1535 vmovdqa64 zmm24, zmmword ptr [ fixMask6] vmovdqa64 zmm25, zmmword ptr [ fixMask7] vmovdqa64 zmm26, zmmword ptr [ fixMask8] vpsllq zmm28, zmm6, 32 vpxorq zmm28, zmm28, zmm5 vpermi2d zmm24, zmm4, zmm28 vpermi2w zmm25, zmm4, zmm28 vpermi2d zmm26, zmm4, zmm28 vpsrlvq zmm24, zmm24, zmmword ptr [ fixShift6] vpsllvq zmm25, zmm25, zmmword ptr [ fixShift7] vpsllvq zmm14, zmm26, zmmword ptr [fixShift8] mov eax, 32768 kmovd k1, eax vpsllw zmm25 {k1}, zmm25, 10 ; We can sum T0 + T1 with no carry ; Carry can occur when we add T2 vpaddq zmm2, zmm25, zmm24 ; Recombine bits 1536:2047 vmovdqa64 zmm24, zmmword ptr [ fixMask9] vmovdqa64 zmm25, zmmword ptr [fixMask10] vmovdqa64 zmm26, zmmword ptr [ fixMask11] vpsllq zmm28, zmm8, 32 vpxorq zmm28, zmm28, zmm7 vpermi2d zmm24, zmm6, zmm28 vpermi2w zmm25, zmm6, zmm28 vpermi2d zmm26, zmm6, zmm28 vpsrlvq zmm24, zmm24, zmmword ptr [ fixShift9] vpsllvq zmm25, zmm25, zmmword ptr [ fixShift10] vpsllvq zmm15, zmm26, zmmword ptr [ fixShift11] mov eax, 8388616 kmovd k1, eax vpsllw zmm25 {k1}, zmm25, 10 ; We can sum T0 + T1 with no carry ; Carry can occur when we add T2 vpaddq zmm3, zmm25, zmm24 ; Add and propagate carry vpaddq zmm0, zmm0, zmm29 vpaddq zmm1, zmm1, zmm13 vpaddq zmm2, zmm2, zmm14 vpaddq zmm3, zmm3, zmm15 vpsubq zmm23, zmm20, zmm22 vpcmpuq k1, zmm0, zmm29,1 ;statt vpcmpequq vpcmpuq k2, zmm1, zmm13,1 vpcmpuq k3, zmm2, zmm14,1 vpcmpuq k4, zmm3, zmm15,1 kmovb eax, k1 kmovb r12d, k2 ;ecx -> r12d kmovb ebx, k3 kmovb edx, k4 add al, al adc r12b, r12b ; cl->r12b adc r8b, r8b ; dl->r8b adc dl, dl ;sil->dl vpcmpuq k1, zmm0, zmm23,0 ;statt vpcmpequq vpcmpuq k2, zmm1, zmm23,0 vpcmpuq k3, zmm2, zmm23,0 vpcmpuq k4, zmm3, zmm23,0 kmovb ebx, k1 ;r8d -> ebx nicht bl, k1!! kmovb r9d, k2 ;r9d bleibt! kmovb r10d, k3 kmovb r11d, k4 add al, bl adc r12b,r9b ; <->cl -> r12b adc r8b, r10b adc dl, r11b xor al, bl xor r12b, r9b xor r8b, r10b xor dl, r11b kmovb k1, eax kmovb k2, r12d ;ecx->r12d kmovb k3, r8d kmovb k4, edx vpsubq zmm0 {k1}, zmm0, zmm23 vpsubq zmm1 {k2}, zmm1, zmm23 vpsubq zmm2 {k3}, zmm2, zmm23 vpsubq zmm3 {k4}, zmm3, zmm23 vmovdqu64 zmmword ptr [rcx], zmm0 vmovdqu64 zmmword ptr [rcx + 64], zmm1 vmovdqu64 zmmword ptr [rcx + 128], zmm2 vmovdqu64 zmmword ptr [rcx + 192], zmm3 pop rbx pop r9 pop r10 pop r11 pop r12 ret avx512_mul1024 endp end \sourceoff \showoff - Gerade bei den Ersetzungen muss man sehr aufpassen! - Hoffentlich fehlen keine PUSH & POP zum Sichern der Register... - rip gibt es nicht - align 64 musste ich im Projekt global einstellen Genau genommen musste JEDE ASM-Zeile zum Original geändert werden! Bin gespannt, was da noch alles kommt...


   Profil
hyperG
Senior Letzter Besuch: in der letzten Woche
Dabei seit: 03.02.2017
Mitteilungen: 2106
  Beitrag No.5, vom Themenstarter, eingetragen 2023-09-20 00:19

Korrektur: die Konstanten werden so gewandelt: \sourceon nameDerSprache Linux | VC .Byte | DB = 1byte=8bit .short | DW word=2 bytes .long | DD 4 Byte .quad | DQ 8Byte=64 Bit \sourceoff Danach hatte ich tatsächlich erste Erfolge: bis Ergebnisse 256Bit stimmte alles, da unter hier ja schon fertige Wandlungs- & Vergleichsfunktionen vorhanden waren. Nun muss ich noch Funktionen schreiben: String -> 1024 Bit 2048 Bit -> String Also genau genommen ist es sogar eine 2048 Bit Multiplikation! Nochmals vielen Dank Yggdrasil! Die Starthilfe für diesen Weg konnte ich gut gebrauchen! Grüße Gerd


   Profil
hyperG
Senior Letzter Besuch: in der letzten Woche
Dabei seit: 03.02.2017
Mitteilungen: 2106
  Beitrag No.6, vom Themenstarter, eingetragen 2023-09-20 21:05

So, universelle Konvertierungsfunktionen zur Ein- & Ausgabe beliebig langer Byte-Arrays konnte ich jetzt mit Hilfe der GMP-Funktionen realisieren, die ja bereits Hex & Dec ineinander wandeln können (gmp_sprintf , mpz_init...). Problem beim 2048-Bit-Ergebnis (32 * uint64, denn 32*64=2048 Bit): uint64[24] und uint64[23] steht statt einer 0 eine 1 bei "kleinen Ergebnissen" \sourceon falsches Ergebnis [31] [24|23| | | | 0|0|0|0|0|0|0|1|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|4611686018427387904|1|18446744073709551615|18446744073709550891 <- [0] Lo \sourceoff Nun beginnt die Suche in den Tiefen... (ob Offset konst 1 zu groß... ob Maske falsch... ) Aber 2^(64*23)= 443stellige Zahl ist ja schon mal was...


   Profil
hyperG
Senior Letzter Besuch: in der letzten Woche
Dabei seit: 03.02.2017
Mitteilungen: 2106
  Beitrag No.7, vom Themenstarter, eingetragen 2023-09-21 00:56

Heureka, ich hab's: Fehler gefunden: \sourceon asm kmovb eax, k1 kmovb r12d, k2 ;ecx -> r12d kmovb r8d, k3 ; edx -> r8d Fehler1 beseitigt kmovb edx, k4 ; esi -> edx \sourceoff \sourceon 2048 Bit Ergebnis 103832233355830988297895908956136602173863539970952653580954499891375611125393213484084471166283701188362712938867662993037283291730596745157449847336586375021636252655128655534478803968892260269455034976230594660447794341159067395872743763847536808569825767394501962775830297963263350044527386261397969715379 * 141511208013288993905548618523568379159209531313198643566041603705174941650952171106949545429764487011873161761006897833151168886907482683529271679375037466087638727219273947489257466532681524585138503805211545426332063140368813261776869550667538989576919880253875506574449377084344185486022194731700128764265 = 14693424772901362914134253920904258052812646793743227572983015842454323733676444516131683269022093887760213311612979967280053075165601618366184815438733279717430218670877851003842880213962966419317109253923179206308452782253223519471281041281187898785314291615627868361110932512714612344268396959956511853154438423982297014957289252215680369946779123645160650482603180742766886904901482885972178817876277492574591211034291840672348175861033574093653686180518327250755537270685023120621101501315531965078189839511707312598379261937912040739625495304575377759805525422610258535215747214380918080115882276257193036131435 \sourceoff Gute Nacht https://matheplanet.com/matheplanet/nuke/html/images/forum/subject/shocked.gif


   Profil
Yggdrasil
Senior Letzter Besuch: in der letzten Woche
Dabei seit: 01.07.2004
Mitteilungen: 863
Wohnort: Berlin
  Beitrag No.8, eingetragen 2023-09-21 21:46

Oh, schön zu sehen, dass dich mein kleiner Beitrag so weit gebracht hat :) Vielleicht kannst du den Assembler-Code ja dem Ausgangs-Githubprojekt beisteuern, auch wenn das schon 8 Jahre alt ist.


   Profil
hyperG
Senior Letzter Besuch: in der letzten Woche
Dabei seit: 03.02.2017
Mitteilungen: 2106
  Beitrag No.9, vom Themenstarter, eingetragen 2023-09-22 00:36

Noch bin ich mitten drin... Erste Zeitmessungen mit iterativer Fehlerfortpflanzung (falls auch nur 1 Zwischenergebnis abweicht): \sourceon Zeit in s und Ergebnis nach 16542597 Iterationen GMP in 3.184 s 11441142058490848130924300253181211127949211463480142137614309575188932920928673343613018353628070473450675402420311258052169655757531919541438402749131040823840135899395670005296908063510256863274911541718451203606535110873975960297629606543772451063340179605805082380480340287564704949249205448572051977196442582415067978896647356625487636239445594949075896823526638429090685901317330012984635186543068607930493714542866630683413275636022630440625335172173455891545364830344931635268966083628459801587891733370001226484777465976001638936545602037057952481733830031275152098760143251759786320656928862144021378629632 AVX512 in 2.000 s 11441142058490848130924300253181211127949211463480142137614309575188932920928673343613018353628070473450675402420311258052169655757531919541438402749131040823840135899395670005296908063510256863274911541718451203606535110873975960297629606543772451063340179605805082380480340287564704949249205448572051977196442582415067978896647356625487636239445594949075896823526638429090685901317330012984635186543068607930493714542866630683413275636022630440625335172173455891545364830344931635268966083628459801587891733370001226484777465976001638936545602037057952481733830031275152098760143251759786320656928862144021378629632 \sourceoff also etwa 1,592 mal schneller. https://matheplanet.com/matheplanet/nuke/html/uploads/c/47407_Balken_GMP_AVX512.PNG Zwar habe ich das "Drumherum" versucht zu minimieren, aber es ist noch nicht optimal. YMP kommt noch... Gute Nacht


   Profil
hyperG hat die Antworten auf ihre/seine Frage gesehen.

Wechsel in ein anderes Forum:
 Suchen    
 
All logos and trademarks in this site are property of their respective owner. The comments are property of their posters, all the rest © 2001-2023 by Matroids Matheplanet
This web site was originally made with PHP-Nuke, a former web portal system written in PHP that seems no longer to be maintained nor supported. PHP-Nuke is Free Software released under the GNU/GPL license.
Ich distanziere mich von rechtswidrigen oder anstößigen Inhalten, die sich trotz aufmerksamer Prüfung hinter hier verwendeten Links verbergen mögen.
Lesen Sie die Nutzungsbedingungen, die Distanzierung, die Datenschutzerklärung und das Impressum.
[Seitenanfang]