msvc 2017 x64 запазване на регистъра

Според https://docs.microsoft.com/ru-ru/cpp/build/x64-software-conventions?view=vs-2017 - xmm6:xmm15 са енергонезависими. Но програмата ми не се срива, ако не запазя xmm6, xmm7. Не извиквам ОС от сборка. Трябва ли да запазя регистрите в този случай? Работя под Windows 7.


person Andrey    schedule 18.11.2019    source източник
comment
Вашата програма не се срива днес, но няма гаранции за утре. (Може също така да се държи неправилно по начин, който не се срива.)   -  person Raymond Chen    schedule 18.11.2019
comment
Ако никога не се върнете от функция, тогава тази функция не трябва да запазва никакви регистри, защото никога не е необходимо да ги възстановявате. В противен случай, ако се върнете и енергонезависимите регистри са се променили, значи сте нарушили обещание, което сте дали на повикващия и всичко може да се случи.   -  person Ross Ridge    schedule 18.11.2019
comment
Разбирам, но програмата ми е достатъчно голяма. Изглежда странно, че няма сривове - изглежда, че компилаторът не използва xmm6-xmm7. Би било чудесно да избягвате запазването на тези регистри, защото това влияе на производителността (не много, но все пак).   -  person Andrey    schedule 18.11.2019
comment
Компилаторът не дава обещания да не използва XMM6 или XMM7 и ще използва тези регистри винаги, когато намери за полезно да го направи. Поради автоматичното векторизиране и други оптимизации те могат да бъдат използвани във функции, където бихте помислили, че компилаторът няма да има извикване да ги използвате. Също така не забравяйте, че компилаторът, който използвате днес, може да не е същият компилатор, който ще използвате утре. И накрая, сривът не е единственият възможен лош резултат, по-вероятно е програмата ви да не се срива, а както каза Реймънд Чен, да се държи неправилно. Това може да бъде много трудна грешка за проследяване, ако не знаете причината.   -  person Ross Ridge    schedule 18.11.2019
comment
ОС, която извиква вашата функция, очаква регистрите да бъдат запазени. Ако се върнете с различни стойности в тези регистри, тогава операционната система може да се държи хаотично по начини, които не могат да бъдат предвидени (и които могат да се променят при всяка актуализация на защитата).   -  person Raymond Chen    schedule 18.11.2019
comment
Моята функция е приложение за Windows. Мога ли просто да запазя тези регистри в началото на приложението си и да ги възстановя накрая?   -  person Andrey    schedule 18.11.2019
comment
Само ако цялото ви Windows приложение е написано в асемблиране, тогава можете да следвате каквато и да е конвенция за извикване, която искате, когато извиквате собствените си асемблиращи функции от вашите собствени асемблиращи функции. В противен случай, ако извиквате своя собствена асемблираща функция от C++ функция, тогава трябва да следвате стандартната конвенция за извикване, в противен случай нарушавате обещание към компилатора и всичко може да се случи като резултат.   -  person Ross Ridge    schedule 18.11.2019


Отговори (1)


Нарушаването на ABI не гарантира грешка, точно както UB в C може да работи. напр. може би повикващият записва/възстановява (при влизане/излизане) XMM reg, който унищожавате, но не се интересува от техните стойности в извикването на вашата функция. напр. може би е искал да запази FP стойност в регистър през printf повикване, а не през извикването на вашата функция.

Или може би нищо не ги използва и main и кодът за стартиране на CRT не се интересуват.


Начинът, по който ABI гарантира работа, е, че ако ги следвате, гарантирате без проблеми, а не обратното.

IDK, ако има функция за обвивка „проверка“ на конвенцията за извикване, която проверява дали всички запазени за повиквания правила са запазени правилно и че не сте стъпили на пространство на стека извън пространството на сянката и (ако има такива) на вашите аргументи на стека. Сигурно някой е написал нещо подобно. напр. Писане на thunk за проверка на съответствието на SysV ABI


Би било чудесно да избягвате запазването на тези регистри, защото това влияе на производителността (не много, но все пак).

Ако компилирате вашия C с GCC или clang, можете да декларирате прототипа на вашата asm функция като използващ x86-64 System V ABI, където всички xmm0..15 са извиквани (и предаването на аргументи използва различни регистри), използвайки атрибут на GCC функция

__attribute__((sysv_abi))
extern "C" int myfunc(void);

Тогава повикващият ще трябва да запази/възстанови всички от xmm6..15, защото трябва да приеме, че извикваният ги е унищожил.

Така че направете това за функция, която е достатъчно високо в дървото на повикванията, така че тези режийни разходи да се амортизират при много извиквания на функции.

(Или по-добре, използвайте вътрешни елементи, така че използването на XMM regs да може да се вгради и да оптимизирате режийните разходи за повикване/повтаряне, както и режийните разходи за записване/възстановяване на XMM рег. Ако запазването/възстановяването или режийните разходи за повикване са от значение, решението е по-вградено, така че функциите не са толкова малки.)

Вижте Заобикаляне на Windows calling convention preserving xmm registers? за това . Внимавайте, че ICC е с грешки и не успява да запази/възстанови XMM6..15 около извикване на System V ABI функция и GCC не поддържа правилно AVX в Windows (проблеми с подравняването на стека).

person Peter Cordes    schedule 18.11.2019