otázka zní, kdo a do jaké míry SSE a třeba i AVX využije. Třeba Gočko vůbec SIMD neumí, i když Go používá skalární SSE instrukce. Dtto většina interpetrů. A céčko snad jen přes intrinsiky. (Rust netuším, ale tam věřím, že nějak SIMD dokážou utilizovat)
Takže co nám zbývá? Asi Fortran, možná Julia? Nebo specializované knihovny jako Numpy.
FYI rychlý test:
typedef struct vector4d { float v[4]; } vector4d;
void vectorAdd(vector4d *out, vector4d *s1, vector4d *s2)
{
for (int i = 0; i < 4; ++i) {
out->v[i] = s1->v[i] + s2->v[i];
}
}
x86_64:
vectorAdd(vector4d*, vector4d*, vector4d*):
movups xmm0, XMMWORD PTR [rsi]
movups xmm1, XMMWORD PTR [rdx]
addps xmm0, xmm1
movups XMMWORD PTR [rdi], xmm0
ret
aarch64:
vectorAdd(vector4d*, vector4d*, vector4d*):
ldr q31, [x1]
ldr q30, [x2]
fadd v30.4s, v31.4s, v30.4s
str q30, [x0]
ret
A moderní (už dlouho) kompilátory zvládají i maticové násobení docela slušně.
Protože Intel a CISC :-), RISCy měly ty desítky registrů (typicky 32, ale AMD 29K mělo 128 a Itanium tuším taky 128 v registrových oknech). Ale popravdě, ono to natahuje i instrukční slova a navíc každé přerušení nebo context switch může znamenat nutnost to celé někam odložit (takové ty snahy o PUSHA a POPA) nebo mít možnost odložit registry podle bitového pole (původní ARMy).
U některých RISCů se to snažili vyřešit "oknem" registrů; to se mi osobně dost líbilo, ale nějak to umřelo s tím, jak to všechno válcoval Intel. Ale jak píšeš, dneska už máme registrů spíš víc než míň (jak běžných skalárních, tak i pro AVX).
Tak, ono by to tudíž nesměly být jednotlivé univerzální registry. Nevím, co bylo to "okno" zmiňované panem Tišnovským, ale možná podobné mému nápadu: část registrů přístupná jenom nějak podobně jako zásobník plus instrukce "načti celý zásobník naráz z RAM". Pak by to šlo použít podobně jako program v PostScriptu, tj. spustí se výpočet mnoha kroků s minimální režií a bere se až sada výsledků na konci. Navíc, krom už tak výrazně snížené režie, celou dobu toho výpočtu je všechen ostatní HW volný a může jet paralelně, např. chystat v RAM data pro další kolo výpočtu: sběrnice na RAM, CPU... - protože SIMD je celou dobu výpočtu soběstačný (má kód, data i úložný prostor pro výsledky).
Ono je to trošku podobné. Popsáno je to ve třetí kapitole v https://www.root.cz/clanky/procesory-risc-v-pracovnich-stanicich-a-serverech-architektura-sparc-v8-a-v9/#k03 (doskoky na kapitoly u starších článků přestaly fungovat, tak je nutné doskrolovat).
Dostupných je například 32 registrů z 256 (to je +- to samé, co máme dneska k dispozici). Při volání subrutiny se okno nad všemi registry posune, řekněme tak, že 8 registrů už nebude dostupných (tam si původní kód nechává hodnoty, které chceme zachovat) a dalších 16 registrů bude vidět i subrutina (s jinými indexy). Tak je možné předávat argumenty a návratové hodnoty. A posledních 8 registrů je zcela "nových", tam si subrutina dává lokální proměnné. A při RETURN se to okno zase vrátí zpátky.
program přeložený s podporou SSE nebude na procesoru bez této technologie pracovat korektně, i když by pravděpodobně bylo možné SSE emulovat s využitím podprogramů spouštěných při zavolání neplatného operačního kódu (tj. operačního kódu SSE instrukce, která je samozřejmě pro ne-SSE procesor neznámým kódem).
Když jsem se snažil (úspěšně) rozběhat Furmark na 486, tak jsem narazil na informaci, že některé generace CPU některé neznámé SSE instrukce ignorují.