Имеются ли в x86-SSE-инструкциях порядок автоматического выпуска-получения?

Как мы знаем из C11-memory_order: http://en.cppreference.com/w/c/atomic/memory_order

И то же самое из C++ 11-std:: memory_order: http://en.cppreference.com/w/cpp/atomic/memory_order

В строго упорядоченных системах (x86, SPARC, мэйнфрейм IBM) упорядочение при получении релизов происходит автоматически. Никаких дополнительных инструкций ЦП для этого режима синхронизации не выдается, затрагиваются только некоторые оптимизации компилятора (например, компилятору запрещено перемещать неатомарные хранилища после выпуска атомарного хранилища или выполнять неатомарные загрузки раньше, чем получение атомарной загрузки)

Но так ли это для x86-SSE-инструкций (кроме [NT] - не временных, где мы всегда должны использовать L/S/MFENCE)?

Здесь сказано, что "инструкции sse... не являются обязательными для обратной совместимости и порядок памяти не определен". Считается, что строгая упорядоченность оставлена ​​для совместимости со старыми версиями процессоров x86, когда это было необходимо, но новые команды, а именно SSE(за исключением [NT]) - лишены автоматически выпуска-приобретения порядка, не так ли?

2 ответа

Решение

Вот выдержка из Руководства Intel для разработчиков программного обеспечения, том 3, раздел 8.2.2 (издание 325384-052US от сентября 2014 г.):

  • Чтения не переупорядочиваются с другими чтениями.
  • Записи не переупорядочиваются со старыми чтениями.
  • Записи в память не переупорядочиваются с другими записями, за следующими исключениями:
    • запись выполняется с помощью инструкции CLFLUSH;
    • потоковые хранилища (записи), выполняемые с помощью временных инструкций перемещения (MOVNTI, MOVNTQ, MOVNTDQ, MOVNTPS и MOVNTPD); а также
    • строковые операции (см. раздел 8.2.4.1).
  • Чтения могут быть переупорядочены со старыми записями в разных местах, но не со старыми записями в том же месте.
  • Чтение или запись не могут быть переупорядочены с помощью инструкций ввода / вывода, заблокированных инструкций или инструкций сериализации.
  • Чтение не может пройти более ранние инструкции LFENCE и MFENCE.
  • Пишет не может пройти более ранние инструкции LFENCE, SFENCE и MFENCE.
  • Инструкции LFENCE не могут пройти ранее прочитанные.
  • Инструкции SFENCE не могут проходить ранее записи.
  • Инструкции MFENCE не могут передавать ранее прочитанные или записанные данные.

Первые три маркера описывают порядок получения релиза, и исключения там явно перечислены. Как видите, только инструкции по контролю кеширования (MOVNT*) находятся в списке исключений, в то время как остальные SSE/SSE2 и другие векторные инструкции подчиняются общим правилам упорядочения памяти и не требуют использования [LSM]FENCE,

Это правда, что обычные инструкции загрузки и хранения 1 SSE, а также подразумеваемая загрузка при использовании операнда источника памяти имеют то же поведение при получении и освобождении с точки зрения упорядочения, что и обычные загрузки и сохранения регистров GP.

Они, однако, как правило, не являются полезными непосредственно для реализации std::memory_order_acquire или же std::memory_order_release операции на std::atomic объекты размером более 8 байт, поскольку нет гарантии атомарности для загрузок SSE или AVX и хранилищ размером более 8 байт. Отсутствующая гарантия не просто теоретическая: есть несколько реализаций (включая новые, такие как AMD Ryzen), которые разделяют большие нагрузки или складывают в две меньшие.


1 Т.е. те, которые не указаны в списке исключений в принятом ответе: NT store, clflush и строковые операции.

Другие вопросы по тегам