ětšina zpomalení je způsobena patrně zvětšením binárek a agresivním vkládání funkcí (function inline), což zvětšuje tlak na registry a vyrovnávací paměť.
A jak si autor představuje, že by "tlak na registry" mohl mít vliv na zpomalení programu? I když bude program menší, tak "tlak na registry" bude pořád stejný. Každá dnešní moderní architektura používá register renaming, takže "tlakem" to asi nebude...
Vysvětlení je přitom mnohem prostší - co způsobuje tak masivní zvětšení binárky? Je to inlining funkcí, jak je psané v článku, a nebo spíš loop unrolling? Ono totiž když compiler unrolluje všechny loopy v programu, které třeba běžně mají jen pár iterací, tak tam je právě problém - kód bude celkově větší (unrolling znamená extra prolog/epilog - "tlak" právě na instruction cache) a aby ten unrolling dával smysl, tak se musí amortizovat počtem iterací. Takže pokud compiler běžně unrollne loopy, kde je počet iterací minimální, tak to stojí jak strojový čas tak i extra instruction cache.
To ale musí všechno spočítat překladač. Pokud loop potřebuje 8 proměnných a existuje jen 16 registrů, tak moc nemá cenu pokoušet se o unrolling, pokud se nejedná o nějakou autovektorizaci třeba, kde se použijou jiné registry (SIMD).
Ale překladače v tomto opravdu chybují, a problém je, že loop unrolling se dělá mnohem dřív než alokace registrů, takže se stává, že před transformací je program "perfektní", ale po transformaci už chybí registry. Každý unroll stojí i nějaké GP registry, protože prolog/epilog (popř. lead/tail loop) potřebuje většinou vlastní counter, popř. pokud se dělá alignment tak jsou potřeba nějaké dočasné registry, které nemusí být k dispozici a nebo sice jsou k dispozici, ale funkce bude potřebovat větší prolog/epilog (pro save/restore non-clobbered registrů).
Já bych osobně doporučil nastudovat si direktivy (#pragma), napsat si makro (#define NO_UNROLL ...) a přidat to k cyklům, které nikdy nechci unrollovat. Clang tomu rozumí, GCC někdy jo a někdo ne... MSVC nevim.
BTW: Dnešní kompilery umí i "rematerializaci" - to je obejítí znovunačtení tím, že se obsah registru znovu vypočítá (třeba pokud C = A + B, ztratím C, tak si ho můžu znovu vypočítat a vyhnout se uložení a načtení do/z paměti).