Comments 171
Так сколько же?
Но причём здесь AMD и конкуренция? Intel ведь не упомянут в статье.
А то количество инструкций и загуглить можно, но в чем польза то? Все равно, что написать «в стране X население Y», ок, рад что получил эту бесполезную информацию, которая находится в интернете за 1 секунду…
Есть неплохая книга "Modern X86 Assembly Language Programming: 32-bit, 64-bit, SSE, and AVX".
Я бы ещё порекомендовал бы Agner fog. Там всё детально разбирается. Ну и официальные гайды, конечно же.
2014 года — не устарела ли?
Просто дизассемблер x86 я делал когда AVX и AVX2 уже были, а AVX512 ещё не было. Заняло пару недель, сравнение с XEDом и Objdump'ом показало, что текстовый выхлоп совпадает на всех инструкциях.
А вот если вы хотите сделать что-то, что работает и с x86 и с ARM и со всем существующим зоопарком… вот тут да — задачка будет посложнее.
Две недели — это, на мой взгляд, быстро. Много кофе выпили?
В моём случае поддержка x86 была необязательной опцией и сводилась по большей части к дизассемблеру длин.
Поделка анализировала предельную глубину используемого стека в программах под ARM (если встречала alloca, либо рекурсию — ругалась). Начиная с точки входа потока выводилось дерево вызовов со счётчиком накопленного стекового расхода в каждом узле. Незаменимый инструмент в ряде случаев.
Две недели — это, на мой взгляд, быстро. Много кофе выпили?Там не нужно «много кофе», на самом деле. Нужно примерно день на чтение мануала и медитацию.
В x86 есть примерно дюжина «странных» инструкций из «ранней истрии вопроса» (вот всякие эти BOUND/ENTER/MOVS/...).
Но подавляющее большинство инструкций следуют строгому шаблону (описан тут, а тут есть прямо даже красивая картинка). Пара дней уходит на декодер «абстрактной x86-инструкции», неделька на то, чтобы перенести все эти тысячи инструкций в тот формат описания, что вы себе придумали (может быть это можно как-то ускорить и вытащить данные из PDF… я не стал заморачиваться), ну и ешё день-два — на борьбу вот с теми «извращениями», которые из раннего х86 пришли к нам (все современные инструкции начиная с MMX и новее имеют регулярную форму, только EXTRQ из SSE4A выделяется).
Мне тоже не нужен был «полноценный декодер», но зато была очень важна его скорость.
На самом деле самое «весёлое» это не вот все эти тысячи инструкций, но подобного рода косячки.
Иструкции из тех, чтоб были уже в самом-самом первом 8086, но по разному декодирующиеся в AMD64 и Intel 64… это ж просто праздник какой-то!
Спасибо за полезную информацию. Вы вселили в меня осторожный оптимизм касательно дизассемблирования x86.
Применяется простой приём: есть куча (16 обычно) «простых» декодеров (которые могут узнать только длину инстукции) и ещё 3-4 «сложных» — которые уже могут декодировать инстукции до конца.
Потому декодирование стремятся сделать как можно более простым. Транзисторный бюжет ведь ограничен! Потому, в частности, AMD «выкинула на помойку» 3DNow! и SSE4a в 2012м (в «серии тяжёлая техника» — где появилась как раз поддержка AVX) и TBM и XOP в 2017м (Ryzen). Не потому что их сложно реализовать. А потому что их сложно декодировать!
Так что… с течением времени, как ни странно, декодирование сильно сложнее не становится — инструкции всё более регулярные, наоборот. А вот «унаследованные инструкции»… вот там да — содом и гоморра.
Потому, в частности, AMD «выкинула на помойку» 3DNow! и SSE4a в 2012м (в «серии тяжёлая техника» — где появилась как раз поддержка AVX) и TBM и XOP в 2017м (Ryzen). Не потому что их сложно реализовать. А потому что их сложно декодировать!
а как же обратная совместимость?
Кое-где потрачена, видимо, решив, что не сильно нужно. Например, я столкнулся с багами рендера в игре Mass Effect на AMD FX.
Они дают ошибку не более описанной, да, но вот побитовые значения — разные.
А если игра на это заложилась…
Самая большая беда — для многопользовательских игр: там не так важно, какой именно результат получается — важно, чтобы у всех игроков один и тот же. А тут, вдруг, такой «подарочек»…
Ну, в этом смысле амд действительно правы — зачем вам 3Dnow!, если есть AVX. Пользуйтесь лучшими технологиями ))) К тому же 3Dnow! был разный — это не одно расширение, а чуть ли не три или четыре. С разными дополнительными наборами команд
К тому же 3Dnow! был разный — это не одно расширение, а чуть ли не три или четыре.Два с половиной. 3DNow!, Extended 3DNow! и ещё пара специнструкций у Geode.
Последнее связано с тем, что Geode — это вообще разработка другой фирмы (Cyrix, который National Semiconductor купила, а потом перепродала AMD).
Если программа не проверяет CPUID — то ССЗБ, это бага, чинить нужно.
В итоге Capstone-то использовали?
Интересно, что последняя версия вышла в начале этого месяца, а баг с декодированием mulsd в ней тоже присутствует. Но разработчик написал, что в пятой версии уже исправлено. Вот насколько x86 сложна, бедные разработчики Capstone...
Спасибо. Классный график :) Однако есть ещё некоторое количество "безымянных" опкодов. Ну то есть команда есть, а названия у неё нет. И документации как правило тоже нет. Но если знаешь — можно emitами в код вставлять. Но в целом я думаю они не более 1% инструкций
Несколько сотен недокументированных опкодов среди нескольких тысяч документированных — это, похоже, намного больше 1%.
Для каждого года отмечен только один процессор.
www.cpu-world.com/CPUs/Pentium/Intel-Mobile%20Pentium%20MMX%20166%20-%20TT80503166%20(TT166).html
У Вас ус отклеился, простите, ссылка сломалась… :-((((( хабрапарсер чертов
В 1992 ведь ещё и Pentium не было, не то что MMX.
Раз уж вы свели табличку, может и в текстовом виде её вставите?
en.wikipedia.org/wiki/Weitek
Не говоря о том, что сопроцессор для 8086 не обязан был быть арифметическим, т.е. опкоды сопроцессора не обязаны были соответствовать операциям с плавающей точкой.
С учетом того, что даже 8086 всегда так или иначе обрабатывал (передавал сопру или эмулировал с помощью исключений) команды FPUНе подскажите как выглядел ультра-супер-мега-модуль, позволявший процессору в 1978м общаться с кристаллом, расположенным в 1980м? Это ж просто мегатехнология какая-то!
То, что 8086 был выпущен с рассчётом на то, что в будущем, к нему будут выпущены сопроцессоры (не обязательно математические, был ещё и 8089… который, кстати, вышел раньше 8087, в 1979м) — не обозначает что все инструкции всех этих сопроцессоров нужно в список вносить…
P.S. 80387й тоже через два года после 80386го появился, кстати.
The 8087 was initially conceived by Bill Pohlman, the engineering manager at Intel who oversaw the development of the 8086 chip. Bill took steps to be sure that the 8086 chip could support a yet-to-be-developed math chip.en.wikipedia.org/wiki/Intel_8087#Design_and_development
In 1977 Pohlman got the go ahead to design the 8087 math chip. Bruce Ravenel was assigned as architect, and John Palmer was hired to be co-architect and mathematician for the project.
Наличие/отсутствие позволяли обрабатывать исключения —
#NM—Device Not Available (No Math Coprocessor)
#MF—Floating-Point Error (Math Fault)
… опкоды сопроцессора не обязаны были соответствовать операциям с плавающей точкой.Так и да, но… Но с идентичной структурой данных, адресацией и т.п. Поскольку основной процессор так же декодировал эти команды и управлял обращениями к ОЗУ.
Поскольку основной процессор так же декодировал эти команды и управлял обращениями к ОЗУ.Не. Он тупо читал два байта. И выкидывал их. И всё.
Всё остальное делал сопроцессор. Он мог, в принципе, вообще что угодно делать — но любая инструкция была длиной в 11 бит…
fld tbyte ptr [si+12]
fstp qword ptr [bp]
fild dword ptr [di+bx]
fabs
С «fabs», как бы, может быть по разному (ЕМНИП почти внутреннее дело сопроцессора), а с остальными? Кто регистры складывает для вычисления адреса, кто с длинной операнда в памяти разбирается, кто адрес(а) на шину выставляет, кто что декодирует?
Процессор декодирует команду (считая что первый байт — это опкод, второй — ModRM) и читает два байта, которые потом тупо выкидывает.
Сопроцессор за этим делом «шпионит» и, при желании, может использовать адрес и сами эти самые байты (они на одной шине сидят, всё что видит процесор видит и сопроцессор).
Всё остальное он делает независимо.
А так, там же и написано ж, что:
- Не «любая инструкция была длиной в 11 бит», а совместимая с декодированием modR/M, т.е. из этих 11 бит, совсем уж «любыми» могут только 3 бита;
- Не «при желании», а система команд сопроцессора должна иметь и имеет такую структуру, что бы при mod != 11b обмен был необходим (даже если предположить некий гипотетический «кривой» сопроцессор, то обращения в память должны быть всё равно успешными);
- Не просто «шпионит», а с учётом modR/M, т.е. с «пропуском» возможного цикла обмена с памятью для загрузки смещения.
Всё это вместе и можно назвать: процессор и сопроцессор совместно декодируют инструкции и процессор управляет обращением в ОЗУ (первым обращением). ;)
обращения в память должны быть всё равно успешными
Как обращения 8086 в память могут быть неуспешными?
Ну а к процессорам/сопроцессорам 80286/80287, 80386/80387, надеюсь, вопросов нет ;)
Ну а к процессорам/сопроцессорам 80286/80287, 80386/80387, надеюсь, вопросов нет ;)К этим нет — там и протокол и вообще всё параллельно разрабатывалось. В случае с 80286/80287 — вообще всё одновременно, у них даже мануал один на двоих, а 80387й — да, появился позже, но там просто ускорили разрабтку 80386го в какой-то момент.
Конечно, мой вопрос был почти риторическим, но я никак не мог вспомнить команду, которая работала немного по другому: «FSTSW AX».Вот только 8087 этой инструкцией не обладал. Она в 80287м появилась… и даже понятно почему.
Всё это вместе и можно назвать: процессор и сопроцессор совместно декодируют инструкции и процессор управляет обращением в ОЗУ (первым обращением). ;)Ну можно и так, наверное. Но факт в том, что 8087й появился только через два года, после выпуска 8086го. То есть какой-то задел, под него, конечно, сделали, но окончательного понимания как всё будет работать ещё не было.
Так. У меня вопрос. TL;DR. Прошу прощения, если что
Так вот. Считалось количество реально разных инструкций (т.е., например, все вариации MOV за одну команду) или количество разных вариаций оп-кодов (т.е., например, все вариации одной команды с разными опкодами — разные). И как считались префиксы (repne всякие)?
Вот зачем была нужна вторая «фича» — до сих пор никто не знает, технически ничто не мешало сделать эти инструкции преемниками друг друга, просто с разным количеством аргументов.
P.S. Кстати использование AVX512 тоже просаживает проиводительность AVX2-кода, но при этом имена похожие… в общем какие-то потуги маркетологов…
Что было и логично, так как работать с «полными» 256-битными регистрами более-менее беспроблемно можно только в AVX2, в первой версии AVX много ограничений. Программа, использующая AVX, могла об желании работать в таком режиме «явно сообщить» процессору, вызвав VZEROUPPER. А программа, использующая SSE — про AVX ничего не знает и нужен был другой способ.
Ну вот… нахимичили… теперь расхлёбываем.
- инструкция №1 заполняет R целиком;
- инструкция №2 читает R;
- инструкция №3 заполняет половинку R и оставляет вторую половинку нетронутой.
В этом раскладе невозможно запустить на выполнение №3 параллельно с №1, даже если нетронутая половинка R в дальнейшем использоваться не будет.
Именно поэтому в x64 прописали, что 32-битные операции обнуляют старшую половинку регистра. (Для сравнения, во время работы над 80386 о возможности OoO не подумали, и поэтому 16-битные операции оставляют старшую половинку 32-битного регистра нетронутой.)
Для 8 битных регистров это делали с Pentium II (скорее всего и сейчас ещё делают).
Помните байку про то, что Pentium Pro плохо работает на 16-битных программах, но отлично на 32-битных? Вот это вот оно.
Там речь не про 16-битные программы, а про программы, использующие %al/%ah и вот это вот всё.
Но для «упрощения» шла речь о 16-битных программах (MS-DOS и Windows 95).
В результате SSE2 инструкции (с учётом переименования регистров) оказываются сложнее, чем AVX, но главное — возникают «паразитные связи» между инструкциями. Потому что если у вас в один и тот же регистр AVX инструкция чего-то пишет, а потом с ним работает SSE инструкция… то, внезапно, результат работы SSE инструкции оказывается зависимым от результата работы AVX-инструкции и впараллель их исполнять нельзя.
Прелестно, да? Что мешало сделать SSE-иструкции просто копией AVX-инструкций с двумя операндами?
внезапно, результат работы SSE инструкции оказывается зависимым от результата работы AVX-инструкции и впараллель их исполнять нельзя.
А зачем
Также имеется VZEROUPPER чтобы сбросить зависимость.
Что мешало сделать SSE-иструкции просто копией AVX-инструкций с двумя операндами?
Простите что? SSE появился в 1999г, AVX в 2011.
software.intel.com/content/www/us/en/develop/articles/intel-avx-state-transitions-migrating-sse-code-to-avx.html
To бишь, согласно иллюстрации в документе Intel, мы переходим из состояния B в состояние C.
Operating in State C is undesirable.
Что же касается компиляции легаси кода, то SSE интринсики автоматически преобразуются в AVX компилятором.
zig.godbolt.org/z/BkFrTE
Ассемблерные вставки — зло. Используйте интринсики, либо пишите нормальный асм код.
Если ваш кодер плюёт на рекомендации Интел и
Ещё раз напомню, что эта «страшная» проблема лечится одной инструкцией. Написав этот коммент, вы приложили на порядок больше усилий чем требует решение проблемы.
Ещё раз напомню, что эта «страшная» проблема лечится одной инструкцией.Какая интсрукция?
MAGICBEERUSER2
? Или как?Как вы собираетесь AVX-код на процессорах без AVX запускать?
У нас, к примеру требование: программа должна поддерживать все процессоры с поддержкой SSE2 и более новые.
Куда и какую команду вставить чтобы реализация инструкций на SSE (а не весь код требует 256 битных регистров, там есть даже и скалярные вычисления, представьте), вдруг, внезапно, стала нормально работать везде?
Если в вашем коде нет AVX-инструкций, а есть только SSE, то нет никаких проблем — проблемы появляются только от их смешения.
Если ваша прогремма должна, внезапно, поставляться заказчику (да и даже выполняться на кластере, где есть компьютеры с
AVX
и без) — то логично тот код, которому AVX не нужен писать на SSE и не умножать сущности без необходимости.Но тогда вам придётся на каждом переходе требовать, чтобы использовался
VZEROUPPER
. И в результате, так как компиилятор понятия не имеет — использует ваша программа SSE-код или нет, он эту инструкцию пихает во все места. И он будет это делать даже без вашего желания. Да, можно его стукнуть по башке… но вы реально верите что вот все-все должны это делать и делают? Я даже не знаю как в MSVC это сделать в принципе (поиск показывать только кучу несчастных, безуспешно пытающихся его научить так делать).Прелестно, не так ли? Вы и после вот всего этого будете утвеждать, что разработчики AVX вовсе-то и не обосрались?
Если ваша прогремма должна, внезапно, поставляться заказчику (да и даже выполняться на кластере, где есть компьютеры с AVX и без)
Если у вашей минимальной целевой платформы нет AVX, значит используются чипы 9-летней давности и производительность никого не интересует.
Это решить проще всего — используйте только SSE2.
Если конечно маркетинг не продаёт AVX код как фичу.
Но тогда вам придётся на каждом переходе требовать, чтобы использовался VZEROUPPER
На каком переходе? Она нужна в конце вычислений с использованием 256-битного AVX.
Если вы используете 128-битный AVX (который переводится из SSE компилятором), скорее всего уже
проц находится в состоянии A (в вышеупомянутой таблице).
он эту инструкцию пихает во все места.
Вот видите, компилятор сам заботится о вас, чтобы у вас не тормозил код.
В чём, собственно, проблема?
Несмотря на то что в Skylake убрали столл при переключении состояния, если вы не сделаете vzeroupper, будет другая «беда».
For what it's worth, the vzero family is still very much needed on Skylake. The big one-time state transition penalty has disappeared, but was replaced with the ongoing penalty of blending the high half of the register for all all the non-VEX encoded instructions.
That penalty if often huge, perhaps a 2x to 6x slowdown, and it never ends while you run non-VEX code. So you very much need to do the zeroing on Skylake — not for «consistency» but for performance. This has been biting people repeatedly in weird and wonderful ways — the old one-time penalty probably occurred here too, but as a small one-time it would have never been noticed.
Вы и после вот всего этого будете утвеждать, что разработчики AVX вовсе-то и не обосрались?
А, ну всё понятно. Вас интересует поиск виноватых…
Если у вашей минимальной целевой платформы нет AVX, значит используются чипы 9-летней давности и производительность никого не интересует.Если у вас нет мозгов — то ваше мнение никого не волнует.
Представьте себе — не все программы в мире это игры, где CPU должно хватать для рассчёта картинки за 1/60 секунды.
Какой-нибудь Floyd–Steinberg вполне может быть достаточно медленным даже на процессоре с AVX2, однако если ваш графический редактор не будет работать на компьютерах без оного — то вас, извините, не поймут-с.
Photoshop до сих пор требует только SSE2 — и ничего более.
На каком переходе?При мереходе из функции в функцию, однако.
Вот видите, компилятор сам заботится о вас, чтобы у вас не тормозил код.Проблема в том, что цена
В чём, собственно, проблема?
VZEROUPPER
— нифига не нулевая. И наличие его там, где оно не нужно (также, как и его отсутствие там, где нужно) — приводит к замедлению.Несмотря на то что в Skylake убрали столл при переключении состояния, если вы не сделаете vzeroupper, будет другая «беда».А вы не заметили, что мы, как бы, ровно эту вашу «беду» тут и обсуждаем? То, что было в Sandy bridge — это, конечно, вообще ни в какие ворота не лезет, но вот это вот идиотское отличие SSE от AVX — по прежнему является проблемой, как вы сами-таки и откопали…
For what it's worth, the vzero family is still very much needed on Skylake. The big one-time state transition penalty has disappeared, but was replaced with the ongoing penalty of blending the high half of the register for all all the non-VEX encoded instructions.
That penalty if often huge, perhaps a 2x to 6x slowdown, and it never ends while you run non-VEX code. So you very much need to do the zeroing on Skylake — not for «consistency» but for performance. This has been biting people repeatedly in weird and wonderful ways — the old one-time penalty probably occurred here too, but as a small one-time it would have never been noticed.
Photoshop до сих пор требует только SSE2 — и ничего более.
Как видите, они следуют моему совету. Отнюдь не потому что у них «нет мозгов» :)
При мереходе из функции в функцию, однако.
У вас весь код состоит из перемешанных SSE и AVX функций?
Проблема в том, что цена VZEROUPPER — нифига не нулевая.
А какая? Должна быть в районе нескольких тактов.
А вы не заметили, что мы, как бы, ровно эту вашу «беду» тут и обсуждаем?
Это ваша беда — у меня нет таких проблем.
Обсуждаем мы «легаси код 2002г» и смешивание инструкций разных наборов, что крайне не рекомендуется делать разработчиком архитектуры.
Даже один такт может вполне ощутимо просаживать производительность. Современные процессоры мало того, что могут исполнять 3-4 инструкции за такт, так они ещё и спекулятивно могут исполнять код в других функциях (для этого есть специальные оптимизации).Проблема в том, что цена VZEROUPPER — нифига не нулевая.
А какая? Должна быть в районе нескольких тактов.
Обсуждаем мы «легаси код 2002г»Серьёзно? То есть вы можете убедить вышеупомянутом примере MSVC не геренить лишний
VZEROUPPER
? Расскажите как — после этого можно будет что-то обсуждать. Там, как бы компилятор от декабря 2019го… свеженький такой.и смешивание инструкций разных наборов, что крайне не рекомендуется делать разработчиком архитектуры.Угу. И мы даже выясниль — костылём к какому именно костылю этот идиотизм был порождён… Вот только платите вы за всё это даже на самых соврменных процессорах и даже там, где никакого SSE нет и не будет (нет, clang/gcc позволяют от костылей отказаться… MSVC, похоже, нет).
Даже один такт может вполне ощутимо просаживать производительность.
Смешно.
После условных 10000 тактов на выполнение цикла, этот 1 такт прямо так ощутимо будет просаживать производительность вашей программы :)
Согласно таблицам Фога, на процессорах Intel vzeroupper и занимает 1 такт. Не думаю, что вы считаете количество обращений к памяти. Это подотчётная операция у вас? Ибо, с такой заботой об каждом такте, она должна быть таковой.
Современные процессоры мало того, что могут исполнять 3-4 инструкции за такт
А вы измеряли сколько в реальности выполняется?
sophisticated CPU cores actually sustain an average of slightly more than one instruction per cycle when executing many programs.
Или вот отрывок из документации по vtune:
Modern superscalar processors issue up to four instructions per cycle, suggesting a theoretical best IPC of 4. But various effects (long-latency memory, floating-point, or SIMD operations; non-retired instructions due to branch mispredictions; instruction starvation in the front-end) tend to pull the observed IPC down. A IPC of 1 is generally considered acceptable for HPC applications but different application domains will have very different expected values.
То есть вы можете убедить MSVC не геренить лишний VZEROUPPER?
А смысл? Его нужно генерить в вашем случае.
Это рекомендация Интел.
Его не нужно было бы генерить, если бы вы использовали AVX-128. Моя целевая платформа (кстати с довольно дорогим vzeroupper) предполагает наличие AVX, соответственно вашей проблемы у меня нет, как я уже говорил.
И мы даже выясниль — костылём к какому именно костылю этот идиотизм был порождён
Операции над AX точно так же не очищают EAX. Искать виноватых — последнее дело.
MSVC, похоже, нет
С выходом 10-го clang, пользоваться MSVC по большому счёту и не нужно.
Операции над AX точно так же не очищают EAX. Искать виноватых — последнее дело.
Зато очищают верхнюю половинку RAX :-P
#include <stdio.h>
#include <stdint.h>
int main() {
uint64_t a = 0x123456789abcdef0;
asm(
"mov $3, %%bl\n\t"
"mov %%bl, %%al"
: "=a" (a) : "0" (a) : "rbx");
printf("%lx\n", a);
}
Запускаю:
123456789abcde03
И это по-своему логично, потому что если операции над AL, AX обязаны сохранять старшие биты EAX (8-31 и 16-31 соответственно), и (false) dependency всё равно присутствует — то зачем их ломать ради очистки RAX?
А вот 32-битные операции — да, очищают — там эту зависимость можно развязать, чем и воспользовались.
Обратите внимание, что компиляторы для переноса 8- и 16-битных значений в регистр жёстко предпочитают использовать не простой mov, а movsbl, movzbl, movswl, movzwl и т.п. (в обозначениях AT&T) — именно для исключения этих зависимостей самым дешёвым доступным способом…
Обратите внимание, что компиляторы для переноса 8- и 16-битных значений в регистр жёстко предпочитают использовать не простой mov, а movsbl, movzbl, movswl, movzwl и т.п. (в обозначениях AT&T) — именно для исключения этих зависимостей самым дешёвым доступным способом…Только 16 бит. Из-за MS-DOS и Windows 95 в Pentium II сделали AL и 3/4 AX отдельными регистрами, а дальше — на это компиляторы заложились, потому это теперь не убрать.
Про clang & icc принято, но всё равно странновато и никто не мешает тут не делать потенциальные диверсии.
А что такое «3/4 AX»?
Биты 8-31 от EAX?
А что такое «3/4 AX»?Угу. У них была проблема в том, что в MS-DOS активно используется API, где AL/AH, BL/BH, CL/CH и DL/DH рассматриваются как независимые регистры. Из-за этого архитектурно более совершенный Pentium Pro оказывался по скорости едва-едва быстрее Pentium. При цене чуть не на порядок большей.
Биты 8-31 от EAX?
В Pentium II эти регистры начали рассматривать как независимые.
Про clang & icc принято, но всё равно странновато и никто не мешает тут не делать потенциальные диверсии.Если учесть, что ICC — это прямо «компилятор от производителя CPU», то, наверное, так и надо…
А вообще — у них заметно разные «подходы». Вот тут можно увидеть. Clang пытается за счёт использования дополнительных регистров код сделать проще, icc довольно быстро отказывается от 8-битных регистров и пытается за счёт битовых оптимизаций что-то сделать… gcc тупо «сливает».
P.S. В 64-битном режиме это меньше заметно, там же 16 8-битовых регистров (правда включая SPL). В 32-битном режиме — это беда…
Это подотчётная операция у вас? Ибо, с такой заботой об каждом такте, она должна быть таковой.Знаете, если у вас весь код пишется с одинаковым подотчётным тщанием — то мне вас просто жаль.
Потому что у нормальных людей, у которых в голове мозги, а не пиво, в одной и той же программе может быть код на Python (какая там производительность — знаете без меня) и код, в котором не то, что каждый такт учтён, но даже проверена раскладка по испоняющих устройствам для разных CPU.
Всё зависит от того, что это за код и где он используется.
Ах, ну да. Как же я мог забыть. Нужно просто соблюдать рекомендации — и всё будет чики-пуки. А если ништяки с неба не сыплются, то нужно просто рекомендации тщательнее исполнять.То есть вы можете убедить MSVC не геренить лишний VZEROUPPER?
А смысл? Его нужно генерить в вашем случае.
Это рекомендация Интел.
Его не нужно было бы генерить, если бы вы использовали AVX-128.А кто тут у нас писал Что же касается компиляции легаси кода, то SSE интринсики автоматически преобразуются в AVX компилятором? Быстро же у вас сменилась «линия партии».
Операции над AX точно так же не очищают EAX и вызывают partial register stall.А вот операции с EAX, внезапно, так не делают. Старшая половина RAX всегда либо обнуляется.
Искать виноватых — последнее дело.Наоборот. Когда кто-то где-то вырезает «гланды автогеном через задницу» — это первое, что нужно сделать. И понять почему. А потом уже можно решить — что с этим делать. Может уже пора и перестать, а может нужно и, наоборот, продолжить это делать — если тому есть веская причина.
С выходом 10-го clang, пользоваться MSVC по большому счёту и не нужно.По-моему это рекорд: тут у вас «линия партии» сменилась посередине одного сообщения.
И вот поиском на такую тему нахожу:
The history is this: The extension of vector registers from 128 to 256 bits caused a problem when legacy Windows device drivers saved only the lower 128 bits of the new 256-bit registers. This problem was solved in a rather complex way.и дальше описание того, что уже знаем.
«Семь бед — один ответ! Костыль и велосипед!» (tm)
Объясните, а то что-то не сходится.
Поэтому ABI собирались обновить обратно-совместимым образом: вызываемая сторона либо сохраняет верхние половинки, либо не трогает их, и тогда они остаются без изменения. Хотя судя по тому, что я вижу в MSDN прямо сейчас, такого обновления ABI так и не произошло.
Это неизбежно. И тут Intel мог бы помочь, например, прямым доступом к верхним половинам… хотя смысла всё равно нет с текущим стилем железа — для такой задачи, где нужен AVX256, сохранить на 16 байт больше из одного регистра — копейки.
> такого обновления ABI так и не произошло.
Они и не могли сделать такое обновление. Костыль принципиально уже не мог сработать и не сработал.
Дальше по ссылке пояснение, что виноваты не «legacy drivers», а Win64 ABI, предписывающее сохранять XMM-регистры.Нет.
Во время создания этого ABI ещё не предполагалось, что у XMM-регистров появится «верхняя половина», которую уже скомпилированный код сохранять не сможет.То, что он эти части YMM-регистров не может сохранить или восстановить — это полбеды. В конце-концов если они потеряны никакой
VZEROUPPER
не поможет.Нет, обсуждаемая по той ссылки проблема была рождена как раз чьим-то идиотским решением не обнулять старшие половинка 256-битных регистров при использовании SSE инструкций.
Именно это создаёт «паразитную связь» между AVX-кодом, работающим в одной процедуре, через SSE-код, который сохраняет младшие половинки и только их и восстанавливает и AVX-кодом уже в другой процедуре.
Если бы SSE-код эти страршие половинки бы обнулял — весь этот «танец с бубнами» был бы не нужен.
К сожалению иначе как вредитеством я это решения назвать не могу. Ну потому что это ж было через много лет после фиско Pentium Pro — та история должна была бы остаться у кого-то в мозгах!
А
VZEROUPPER
— это уже попытка частично это вредительство смягчить…Подумайте для начала — почему, вдруг, процессор оказался в таком состоянии, что
VZEROUPPER
может чему-то помочь?Ответ: потому что кто-то сохранил значение 128 бит в стеке, а потом восстановил (как вы прочитали в той статье) с помощью SSE инструкций!
А что было бы, если бы, вместо этого, использовались бы AVX128 инструкции (или если бы SSE инструкции вели себя так же, как AVX128 инструкций). Ой, глядика-ты: проблема бы рассосалась и исчезла!
Паразитных зависимостей не было бы изначально, никакой
VZEROUPPER
был бы не нужен.и дальше описание того, что уже знаем.Ага. Только вот этот «костыль и велосипед» — это уже как раз следствие того, что SSE ведёт себя не как AVX128.
«Семь бед — один ответ! Костыль и велосипед!» (tm)
А вот какую проблему это «расчщепление сущностей» помогло-таки решить?
Вам незачем мне тут возражать — я точно так же говорю, что проблема возникла, когда решили, что SSE на расширенных регистрах должно не трогать старшие 128 бит, при том, что это была вторая половина 2000-х и последствия уже все знали.
А вот была ли у них хотя бы в пределах года-двух разумная причина — это как раз то, что я не могу найти, и при чём тут ссылка на драйвера — мне непонятно. Тут какая-то очень частная маргинальная ситуация.
> Проблема в том, что вы нашли кой-чего-совсем-не-то.
А что именно «то»?
Ваши же слова рядом:
Нет, обсуждаемая по той ссылки проблема была рождена как раз чьим-то идиотским решением не обнулять старшие половинка 256-битных регистров при использовании SSE инструкций.
так вот — Intel, возможно, и идиоты, но не кретины, в медицинском смысле. Что именно было тут причиной? Я перебрал возможные ситуации со своей точки зрения, и единственное предположение тут следующее: если драйвера (это слово там прозвучало не зря?) используют SSE, и умеют при этом сохранять модифицированные ими регистры, но только командами SSE (а не каким-нибудь XSAVE), и нет горизонтального переключения между соседними процессами (это важно — иначе не поможет), или же это горизонтальное переключение сделано системным кодом, который уже YMM-aware, а драйвера — ещё нет — то вариант «делаем, чтобы никакое SSE не трогало верхние половинки» тут поможет. Пенальти на переключение между State B и State C на входе/выходе сисколла или прерывания — не так уж и страшно, с их точки зрения.
Многовато натяжек (всё равно непонятно, почему нельзя было на границе сисколла/прерывания явно отработать проблему), но «если отбросить всё невозможное — остаётся реальное». Или у вас есть другие идеи?
Многовато натяжек, но «если отбросить всё невозможное — остаётся реальное». Или у вас есть другие идеи?Похоже они не нужны. Да, там по ссылки есть сообщение от чувака из
Intel
, который ровно про это и говорит: да, у нас есть драйвера, которые трогают SSE (руки бы оторвать таким драйверописателям) и нам придётся «устроить всем кузькину мать».Которую мы теперь будем разсхлёбывать вечно. Ну или пока от испоьзования SSE не откажемся совсем, по крайней мере.
Класс.
Ну спасибо хоть объясниснили в чём беда, а то я уж совсем испугался за разум товаристчей из Intel: Theoretically a new OS could take care of this for the ISR, but we didnt want to penalize users of the legacy architecture and could not mandate a major OS re-write.
Жуть. Хоть бы флаг в процессоре сделали бы, чесслово. Собственно два флага: один для привелегированного кода, другой для непривелигированного. И всё. И нет проблем.
Никто бы про эту разницу между SSE и AVX (кроме драйверописателей) даже не задумывался бы…
Тогда хотя бы те, кого это не касается (все пользователи Линукс, собственно), жили бы спокойно…
Не сохраняли верхнюю половину регистров, которой ещё не существовало?
На вопрос типа «ты перестал пить коньяк по утрам?» сложно ответить конструктивно. А ваш вопрос именно такого типа. При чём тут авторы драйверов, когда проблема создана на уровне процессора?
Решить её можно было несколькими методами, но почему-то выбран оказался «лучший из худших».
А зато если SSE регистры не используются, то их не нужно и сохранять.
Если же ну вот очень-очень-очень надо, прям край как надо, ускорение ожидается космическое… можно использовать инструкцию, которая, внезапно, как раз для этого и предназначена (и появилась в Pentium II, ещё когда SSE первой версии в проекте был… так что не надо про то, что «мы ж не знали» — знали, просто не думали).
Подобные дискуссии среди разработчиков Linux — ни разу не редкость и, в результате, в Linux в драйверах ни SSE, ни AVX не используются (за исключением драйвера RAID).
При чём тут авторы драйверов, когда проблема создана на уровне процессора?Проблема не создана на уровне процессора. Она создана на уровне драйверов. Сохраниение контекста (включая SSE регистры!) процессором осуществляется с помощью команды FXSAVE, которая, внезапно, появлась аж в Pentium II (то есть до изобретения SSE даже).
Однако некоторые ушлые драйверописатели обнаружили, что это ж долго — все рагистры-то сохранять! А давайте мы парочку регистриков тихо-и-незаметно куда-нибудь сохраним, а потом восстановим… никто ж ничего не заметит, ведь правда?
Ну а потом, как мы выяснили, и родилось вот это вот идиотское решение с явным разнесенеием SSE и AVX инструкций и «штрафом» за их перемешивание…
Если нет разницы, зачем платить больше?
Хм, но ведь и FXSAVE не сохраняет верхние половинки?Так она их не сохраняет потому что драйвера эту инструкцию не используют!
Научить сохранять YMM'ы в 32-битном режиме (где самое лютейшее легаси и обитает) — вообще без проблем, в 64-битном — можно было бы прописать в какой-нибудь MSR адрес процедуры, которая бы YMM регистры куда-нибудь записывала бы.
Главное — сохранение и восстановление состояния выполнялись бы настолько медленно (62+68 тактов = 130 тактов на Pentium II), что вся эта конструкция «яйца бы выеденного не стоила». Применялась бы в трёх всем известных драйверах, как в Linux, и всё.
Вообще вся эта попытка выиграть что-то под Windows и MacOS — это какой-то вечный забег по граблям. В духе «а давайте мы для экономии памяти научим ядро часть своего кода выгружать… а лет через 10 обнаружим, что у нас и невыгружаемая часть теперь больше, чем вообще всё ядро в Linux».
Про большую коллекцию граблей, которую собрала MacOS из-за попытки вписаться в 128K в 1984м году есть даже отдельная статья в Wikipedia.
Но, как известно уроки истории заключаются в том, что люди ничего не извлекают из уроков истории — тут мы это видим в очередной раз.
Развитие идёт по спирали, как известно… и каждое следующее поколение, получил от граблей фингал под глазом и обматерив предшественников всеми нехорошими словами, какие удалось вспомнить, тут же разворачивается и аккуратно покрывает оставшуюся за ними дорожку всё теми же самыми граблями.
А то, вдруг, следующее поколение без фингалов под глазами окажется… непорядок.
Это, кстати, для общих затрат даже на вертикальное переключение — не очень много — всё равно все регистры сохранять-восстанавливать, а если делать это одной порцией в память, то самые серьёзные затраты с торможением по памяти будут обойдены. Не восстанавливать все пользовательские регистры опасно утечкой данных, потому что в стандартном соглашении вызова те регистры, что args + result + scratch, никто не чистит, а в callee-saved, наоборот, может что-то лишнее притечь ядру… опасно.
Спрашивается, что мешало AMD и Intel при реализации x64 сделать так же? Вопрос обратной совместимости тогда не стоял, а стольких проблем удалось бы избежать.
ARM при вертикальных переключениях сам заменяет все регистры.Это кто ж вас так жестоко обманул? На картинку, хотя бы, гляньте. В большинстве режимов он меняет буквально пару регистров и только в FIQ — половину (и то не все).
Все регистры менял 8080… уже даже Z80 не мог себе этого позволить.
Спрашивается, что мешало AMD и Intel при реализации x64 сделать так же?Дык никто не мешал. Кроме здравого смысла. Прерывание — оно, знаете ли… прерывает. И потому должно работать быстро. Соответственно обычные регистры x64 сохраняет, а x87 и SSE — нет. Ну просто никому и в страшном сне не могло присниться, что при обработке прерываний кто-то решит, внезапно, использовать SSE.
Но… нет такого идиотизма, который не могут совершить разработчики в погоне за требованиями маркетологов! Если у вас есть кто-то вроде Линуса, кто посылает маркетологов «в пешее эротическое» — всё будет в порядке. Если нет — ну вот и получим то, что получили…
Дык никто не мешал. Кроме здравого смысла. Прерывание — оно, знаете ли… прерывает. И потому должно работать быстро.
Время, занимаемое переключением регистров, не зависит от числа переключаемых регистров, потому что меняется только маппинг, самое содержимое регистров никуда не перекачивается.
Но… нет такого идиотизма, который не могут совершить разработчики в погоне за требованиями маркетологов! Если у вас есть кто-то вроде Линуса, кто посылает маркетологов «в пешее эротическое» — всё будет в порядке. Если нет — ну вот и получим то, что получили…
Драйвера под Windows проверяются в WHQL, и Windows не загружает их без подписи, удостоверяющей, что драйвер проверен.
Время, занимаемое переключением регистров, не зависит от числа переключаемых регистров, потому что меняется только маппинг, самое содержимое регистров никуда не перекачивается.
В смысле? Т.е. Вы хотите сказать, что при переключении контекста НИКОГДА не сохраняется содержимое регистров в ОЗУ? Или про то, что прерывания != переключение контекста? Или про то, что в процессоре есть дофигища регистров, скрытых от пользователя (программиста), на которые можно что-то там намаппить?
Вы хотите сказать, что при переключении контекста НИКОГДА не сохраняется содержимое регистров в ОЗУ?
Если процессор не сохраняет регистры сам, то их приходится сохранять программисту в ОЗУ.
Или про то, что в процессоре есть дофигища регистров, скрытых от пользователя (программиста), на которые можно что-то там намаппить?
Конечно есть.
Конечно есть.
Я, наверное, не совсем правильно выразился. Т.е. существование их мне известно и я могу его… как бы… обосновать технически. Вопрос в том ДЕЙСТВИТЕЛЬНО ли они участвуют в означенных процессах ("сохранение регистров при прерывании" и "сохранение контекста при переключении процесса") или это побочный эффект.
И это мы не затрагиваем еще режимы работы вроде SMM.....
Вопрос в том ДЕЙСТВИТЕЛЬНО ли они участвуют в означенных процессах («сохранение регистров при прерывании» и «сохранение контекста при переключении процесса») или это побочный эффект.Это — не побочный эффект, но сознательное архитектурное решение. От которого, внезапно, все отказались в современных архитектурах. Так как это — существенное усложнение всей конструкции без каких-либо плюсов. В оригинальной, 32-битной, архитектуре ARM IRQ сохранял 3 регистра, FIQ сохранял 8, на Arrch64 — в обоих случаях сохраняется парочка, остальным занимается OS.
И это мы не затрагиваем еще режимы работы вроде SMM.....С SMM всё, как раз, гораздо проще: он под конкретный процессор затачивается, в случае существенного архитектурного обновления — может потребоваться обновления firmware всё равно.
Время, занимаемое переключением регистров, не зависит от числа переключаемых регистров, потому что меняется только маппинг, самое содержимое регистров никуда не перекачивается.В физическом мире ничего не бывает «бесплатно». Если вы добавляете в процессор систему маппинга регистров, то у вас усложнается стадия декодирования и, что ещё хуже, она начинает зависеть от режима, в котором находится процессор… в общем всё это далеко небесплатно. Вспомните как и почему sysenter появился.
Драйвера под Windows проверяются в WHQL, и Windows не загружает их без подписи, удостоверяющей, что драйвер проверен.А толку? WHQL — это просто некоторый набор тестов. Вы не поверите на что свособно воображение драйверописателей, у которых с одной стороны есть одна задача (пройти тексты), с другой другая (удовлетворить хотелки маркетинга).
Если вы добавляете в процессор систему маппинга регистров, то у вас усложнается стадия декодирования и, что ещё хуже, она начинает зависеть от режима, в котором находится процессор… в общем всё это далеко небесплатно.
Я про то, что если это уже сделано для половины регистров, то можно без дополнительных затрат расширить эту систему на все регистры.
А толку? WHQL — это просто некоторый набор тестов.
Они в том числе проверяют драйвера на использование «запрещённых приёмов».
Вы не поверите на что свособно воображение драйверописателей, у которых с одной стороны есть одна задача (пройти тексты), с другой другая (удовлетворить хотелки маркетинга).
devblogs.microsoft.com/oldnewthing/20040305-00/?p=40373
Я про то, что если это уже сделано для половины регистров, то можно без дополнительных затрат расширить эту систему на все регистры.А… вы про это. Ну так её довольно давно Intel выпилил. Ещё при переходе с 8080 на 8086 в 1978м году. Про ARM не знаю — вроде документация от 1987го года (тут можно найти) говорит о том, что там действительно маппинг регистров имеется, но я не уверен, что в современных суперскалярах это всё ещё поддерживается…
Я про то, что если это уже сделано для половины регистров, то можно без дополнительных затрат расширить эту систему на все регистры.
У ARMv8 маппинг РОН убрали. Для поддержки AArch32 он всё ещё есть, аппаратно, но все теневые регистры отображены на 31 РОН. Некоторые современные ARM процессоры больше не поддерживают 32-битный режим.
Это будет означать, что количество архитектурных регистров будет умножено на количество уровней привилегий. Пусть их 4, как в типовых современных архитектурах — значит, ко всем номерам регистров добавится по 2 бита. Соответственно утолщение блока переименований… увеличение объёма пула реальных регистров на весь этот балласт… зачем?
Я боюсь, вы допускаете тут ошибку, полагая, что если говорят, что, например, SP каждый на свой уровень, то он реально хранится раздельно и подключается именно конкретный в каждый момент. Для более чем одного регистра это невыгодно, лучше копировать в момент переключения, а адресовать уже один регистр всегда.
И даже для комплекта для FIQ это скорее всего на момент перекидки использование прямой связи между тремя версиями одного регистра.
Я боюсь, вы допускаете тут ошибку, полагая, что если говорят, что, например, SP каждый на свой уровень, то он реально хранится раздельно и подключается именно конкретный в каждый момент.В ранних процессорах так и было. Именно за счёт этого EXX, «меняющая» местами 4 регистровых пары в 8080 отрабатывает всего за 4 такта (вот тут есть немного на эту тему).
И даже для комплекта для FIQ это скорее всего на момент перекидки использование прямой связи между тремя версиями одного регистра.В ARM2 точно не так. Они там за задержки очень переживали. Аж даже ради этого сотворили архитектуру где FIQ не берёт адрес инструкции откуда-то, а может прямо код иметь расположенный по адресу
1C
: The FIQ routine might reside at 0000001CH onwards, and therebay void the need for (and execution time of) a branch instruction.Но мне кажется из всех суперскаляров все эти извращения выпилили.
Именно за счёт этого EXX, «меняющая» местами 4 регистровых пары в 8080 отрабатывает всего за 4 такта
Z80.
Аж даже ради этого сотворили архитектуру где FIQ не берёт адрес инструкции откуда-то, а может прямо код иметь расположенный по адресу 1C:
Таблица векторов прерываний содержит не адрес, а инструкции, что часто использовалось в те времена (в вами же упомянутом 8080), плюс упрощало создание процессора.
Такая простая мелочь позволяла вдвое(?) сократить время реакции на прерывание.
Такая простая мелочь позволяла вдвое(?) сократить время реакции на прерывание.Только в случае пустого обработчика. Что в реальном мире несколько… эээ… бессмысленно. Очередная победа маркетологов над здравым смыслом.
Очередная победа маркетологов
Тогда и слов-то таких не знали.
Думаю вам стоит вернуться в прошлое [шутка] и убедить Sophie Wilson потратить ещё немного транзисторов чтобы сделать как вам нравится.
Время реакции не зависит от размера обработчика.То есть, я извиняюсь, как? Процессор у вас без исполнения какого-то кода что-то, внезапно, начинает делать?
Зависит, конечно.
Правда в этой истории есть и «условно счастливый» конец: вдрызг проиграв «гонку мегагерц» (во многом как раз из-за «клёвых находок» типа 26-битной адресации и FIQ) процессоры ARM оказались востребованы в бытовой электронике. И да — вот как раз там все эти штучки оказались «к месту».
Думаю вам стоит вернуться в прошлое [шутка] и убедить Sophie Wilson потратить ещё немного транзисторов чтобы сделать как вам нравится.Даже если вы вернётесь в прошлое вы там никакой «Sophie Wilson» не найдёте. Вот с Роджером можно бы и поговорить — впрочем не слишком ясно о чём: ресурсов на то, чтобы создать что-то конкурентоспособное в сравнении хотя бы с 80486м у Acorn не было, а уж про Pentium (который появится через несколько лет) — тягаться и совсем бессмысленно.
Так что как раз FIQ можно и оставить (хотя на десктопе он не нужен), а вот как раз если что-то и столо бы предвидеть — так это то, что 64MiB окажется «небольшим объёмом» куда быстрее, чем казалось в 1985м…
Тогда и слов-то таких не знали.Знали, конечно. И FIQ как раз под то, чтобы можно было заявить о том, как всё круто в пресс-релизах делался. А что он, потом, реально пригодился — но только уже после того, как Acorn обанкротился… это скорее счастливая случайность…
То есть, я извиняюсь, как?
Я подразумевал время до выполнения первой инструкции ISR.
вдрызг проиграв «гонку мегагерц» (во многом как раз из-за «клёвых находок» типа 26-битной адресации и FIQ)
Казалось бы, причём тут 26-битная адресация и мегагерцы. Интел выиграл гонку мегагерц за счёт своего производства. Acorn же не имел таких возможностей.
а вот как раз если что-то и столо бы предвидеть — так это то, что 64MiB окажется «небольшим объёмом» куда быстрее
ARM был сделан чтобы решать проблемы «здесь и сейчас» а не когда-то в будущем.
Вы бы просто физически не могли подключить столько памяти к ARM2/3 и т.д.
68000 выдавал 24 бита адреса на шину по тем же причинам — экономия транзисторов.
Если соблюдать элементарную гигиену, программам решительно пофиг, сколько там бит выведено на шину адреса. Мои программы под 68к работают на любом другом.
Давайте лучше вспомним «640КБ хватит всем». A20 gate и прочие красоты х86.
Знали, конечно. И FIQ как раз под то, чтобы можно было заявить о том, как всё круто в пресс-релизах делался.Пресс-релиз в студию! Иначе это враньё.
Продавался компьютер целиком, а не контроллер прерываний.
ISA спроектирована (тогда ещё Роджером) в одиночку для решения необходимого круга задач, а вовсе не для удовлетворения маркетологов. Цель была получить RISC-овый 32-битный «6502» с быстрой подсистемой памяти. Там всё продиктовано тем, чтобы максимально эффективно работать с памятью.
В итоге получился супероптимизированный процессор, легко опережающий 386, который имел в 10 раз больше транзисторов.
Блестящая инженерная работа!
Казалось бы, причём тут 26-битная адресация и мегагерцы. Интел выиграл гонку мегагерц за счёт своего производства. Acorn же не имел таких возможностей.Acorn не имел таких возможностей, но партнёры ARM (DEC, Samsung и даже, внезапно, Intel) — несомненно имели.
Однако их процессоры, внезапно, не имели совместимости с 26-битным режимом, под который были заточены как RiscOS, так и куча софта.
Вы бы просто физически не могли подключить столько памяти к ARM2/3 и т.д.Речь идёт не о подключении такого количетва памяти, а возможности написания софта, способного столько памяти использовать.
В ранние модели на 80386 тоже больше 16MiB не впихнуть, но Windows 3.1 может использова 512MiB… а программы для Windows 3.1 работают и в Windows 10, которая может и больше.
68000 выдавал 24 бита адреса на шину по тем же причинам — экономия транзисторов.Однако же 68000 не пытался в те же 32 бита запихнуть ещё и статусные биты и потому апгрейд тех же Маков до 68020 прошёл без титанических усилий, требовавших переписать вообще всё.
Если соблюдать элементарную гигиену, программам решительно пофиг, сколько там бит выведено на шину адреса.Как вы собрались «соблюдать элементарную гигиену», если на ARM2 флаги процессора засунуты в
R15
, слиты в единое целое с адресом инструкции и сохраняются просто командой STR
как единое целое?Давайте лучше вспомним «640КБ хватит всем». A20 gate и прочие красоты х86.Ну там как раз всё понятно: чего вы вообще хотите от «заглушки для сокета»? 8086, как известно, был создан только для того, чтобы ну хоть что-то противопоставить Z80 и прочим всяким 68000, пока настоящий ответ готовился.
Что, собственно, и позволило Apple выжить и лет 10 просуществовать в статусе «премиальной платформы» — аж до 1995го года.
В итоге получился супероптимизированный процессор, легко опережающий 386, который имел в 10 раз больше транзисторов.Работа-то, может, и блестящая, но не без косяков. В частности FIQ (вот именно дизайн с размещением кода прямо по адресу
Блестящая инженерная работа!
1C
) и 26-битный режим — очевидные ошибки.Хотя в целом — да, куда более качественная разработка, чем, скажем, 8086…
Прерывание — оно, знаете ли… прерывает. И потому должно работать быстро. Соответственно обычные регистры x64 сохраняетА точно сохраняет? Вроде же выпилили на х64 аппаратное переключение задач, точно должно сохраняться CS,RIP,RFLAGS, а дальше ручками наверно (даже
pushad
выпилили).Но с практической точки зрения — это без разницы: важно что их кто-то да сохраняет. А вот x87/SSE регистры — не сохраняет никто… но это не значит, что в них нужно, тайком от мамы, залезать «через задний проход»… нет — это значит, что в них не нужно лазить. Совсем.
не сохраняет никто…Хм…
Сохраняемые регистры вызываемого и вызывающего объектовdocs.microsoft.com/ru-ru/cpp/build/x64-calling-convention?view=vs-2019
Регистры RAX, RCX, RDX, R8, R9, R10, R11, XMM0-5 и верхние части YMM0-15 и ZMM0-15 рассматриваются как изменяемые и должны считаться уничтоженными при вызовах функций (если иное не обеспечивается защитой при анализе, например при оптимизации всей программы). В AVX512VL регистры ZMM, YMM и XMM 16-31 являются изменяемыми.
Регистры RBX, RBP, RDI, RSI, RSP, R12, R13, R14, R15 и XMM6-15 считаются неизменяемыми и должны быть сохранены и восстановлены с помощью функции, которая их использует.
Не восстанавливать все пользовательские регистры опасно утечкой данных, потому что в стандартном соглашении вызова те регистры, что args + result + scratch, никто не чистит, а в callee-saved, наоборот, может что-то лишнее притечь ядру… опасно.Абсолютно безопасно. Задаёте опцию -mno-sse — и нет проблем, никаких утечек.
Общие регистры вы принципиально игнорируете? В них обычно сильно более интересные данные, чем в SSE :)
В текущем коде их, насколько вижу, восстанавливают равным значениям на входе.
В текущем коде их, насколько вижу, восстанавливают равным значениям на входе.Совершенно верно — а поскольку их восстанавливают, то утечек быть не должно (если забыть про Spectre).
А вот x87 и SSE регистры обработчики прерываний просто не должны трогать — и всё.
Даже пресловутый драйвер RAID в Linux не использует SSE регистры внутри обработчика прерываний.
Ага, вот где меня заглючило — решил по кривым описаниям, что она появилась позже SSE. Спасибо, тогда полностью согласен.
Простите. Голова. Мозги. Думать.Что мешало сделать SSE-иструкции просто копией AVX-инструкций с двумя операндами?Простите что? SSE появился в 1999г, AVX в 2011.
На процессоре с 256-битными регистрами, внезапно, AVX есть всегда есть. По определению. И если бы SSE инструкции были бы переопределены внутри процессора как 128-битные инструкции с двумя операндами — совместимость не пострадала бы ни на йоту.
Вместо этого… имеем вот весь этот геморой.
А зачемНу, например, чтобы не тащить с собой две копии всех функций: для «старых» процессоров и для «новых».бить себя лопатой по головеиспользовать AVX и SSE одновременно?
Простите. Голова. Мозги. Думать.
Какой вы нервный, однако.
Я не счёл нужным ставить табличку [сарказм]. Похоже что зря.
И если бы SSE инструкции были бы переопределены внутри процессора как 128-битные инструкции с двумя операндами — совместимость не пострадала бы ни на йоту.
AVX-128 и SSE это разные наборы команд. Да, SSE могли бы чистить старшую половину (например, в зависимости от режима работы процессора), но так не сделали, и с этим нужно жить.
например, чтобы не тащить с собой две копии всех функций: для «старых» процессоров и для «новых».
И ничего бы не изменилось — AVX-128 более совершенный набор чем SSE.
Грубо говоря, ничто не мешает конкуренту Intel сделать чип с поддержкой SSE и продавать его под названием «SSE-256», даже если Intel под «SSE-256» понимает нечто совсем иное.
Поэтому Pentium вместо i586, поэтому AArch64 вместо ARM-64, и т.д.
Теперь хорошо бы сие изображение в ту же википедию запостить.
Computer Architecture: A Quantitative Approach
www.amazon.com/Computer-Architecture-Quantitative-John-Hennessy/dp/012383872X
Сколько инструкций в x86?