|
Autor |
superschnelle Multiplikation für 1024 Bit (309stellige Zahl) |
|
hyperG
Senior  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  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  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  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  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  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  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  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  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  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. |
|