Podobné věci jsem viděl naposledy dost dávno, a tehdy se - aspoň u těch char* nulování - řešilo speciálně "dozarovnání" na kulaté adresy, aby ty vícebajtové instrukce pracovali na "přirozeném" bloku. Proč to už není potřeba? Už to je procesoru jedno, nebo už jsou zarovnané i char*? Nebo to zarovnávání vždycky byl jen cargo kult?
Ona instrukce MOVUPS má +- třikrát větší latenci než MOVAPS, takže ty výsledné programy nejsou úplně dobré. Ale tady překladač zjistil, že než si nějakými bitovými operacemi řešit zarovnání začátku a konce třeba 32bajtového pole, tak bude lepší tam vrazit dvě MOVUPS. Cargo kult to není - vždycky se narazí na šířku datové sběrnice.
Mezi MOVAPS a MOVUPS už dlouho není rozdíl, pokud cílová adresa je zarovnaná, takže safe je použít unaligned instrukce, protože když adresa je aligned, tak k žádné penalizaci nedojde. Naopak MOVAPS je dobré použít tam, kde je opravdu očekáváné, že adresa je zarovnaná, protože CPU se postará o SIGBUS v případě, že tomu tak není.
Pokud je ale nějaký cyklus dlouhý a pracuje s jedním polem, je lepší pointer zarovnat manuálně, protože pak CPU nemusí kombinovat více cache lines dohromady (tady klesá IPC) - nejhorší je ale page split - pokud chci unaligned read/write, který je někde mezi 2 pages, tak tam je penalizace o řády větší než pár cyklů (nemluvím o případném page fault).
Obecně říct, že latence unaligned vs aligned je 3x horší ale dnes nejde, pokud člověk nezmíní konkrétní mikroarchitekturu. Třeba když CPU podporuje 2x512-bit fetch, tak buď to budou 2x512-bit aligned a nebo 1x512-bit unaligned (kde se fetch udělá 2x). Takže latence pořád může být 1 cyklus, ale už není možné udělat další paralelní fetch.