Отладчик Visual Studio устанавливает верхнюю половину регистров AVX в ноль

avatar
anatolyg
9 августа 2021 в 06:36
131
1
5

При отладке некоторого кода с использованием AVX я получал бессмысленные результаты. Я сократил свою программу до следующего:

#include <iostream>
#include <immintrin.h>

int main()
{
    while (1)
    {
        static float v[] = {1, 2, 3, 4, 5, 6, 7, 8};
        __m256 v8 = _mm256_load_ps(v);
        std::cout << v8.m256_f32[2] << v8.m256_f32[5];
    }
}

Когда я запускаю эту программу, она бесконечно печатает 36, что правильно (она печатает 3, а затем 6). Если я устанавливаю точку останова в отладчике внутри цикла и выполняю пошаговое выполнение, он печатает 30. Если я удалю точку останова и продолжу программу, она снова начнет печатать 36. Я вижу такое же поведение в Release/Debug, Win32/x86 (4 комбинации).

Чтобы иметь возможность использовать AVX, я установил для параметра «Включить расширенный набор инструкций» значение «Расширенные векторные расширения (/arch:AVX)» в свойствах конфигурации — C/C++ — Генерация кода. Я забыл установить какую-то другую конфигурацию?

В результате такого поведения я не могу использовать отладчик для отладки моей реальной программы (не включенной сюда). Это раздражает.

Я сделал что-то не так? Можно ли исправить это поведение?

Моя Visual Studio: MS Visual Studio Professional 2017, версия 15.9.3.

Источник
Frank
9 августа 2021 в 06:41
0

FWIW, я не наблюдаю такого поведения в MSVC2019, x64 Debug/Release. Я получаю 36 как при беге, так и при прохождении.

Peter Cordes
9 августа 2021 в 06:47
0

Если вы посмотрите на генератор кода asm, MSVC с этими параметрами должен генерировать обычные инструкции AVX с правильным использованием vzeroupper, например, на godbolt.org/z/YMobhKK56. (Используя -O2, мы видим, что VS19.28 сохраняет вектор в стеке и выполняет загрузку YMM + перетасовку для каждого доступа к элементу объединения, не используя преимущество сохраненного вызова xmm5..15). Вы строите для 32-битной или x86-64? Хотя, конечно, это похоже на проблему с отладчиком; этот код является законным и должен быть четко определен в MSVC, а изменение поведения при пошаговом или нет является огромным красным флагом.

anatolyg
9 августа 2021 в 06:56
1

Я вижу такое же поведение в Release/Debug, Win32/x86 (4 комбинации). Я вижу vzeroupper в разборке, но он находится в забавном месте внутри цикла. Я еще немного подправлю свой код, чтобы посмотреть, смогу ли я понять его.

Daniel Langr
9 августа 2021 в 07:21
0

Возможно, IT: Разве _mm256_load_ps не требует выравнивания границ по 32 байтам? Что, кажется, не гарантируется в вашем случае.

Alan Birtles
9 августа 2021 в 07:23
0

не могу воспроизвести в visual studio 2017 15.9.37

anatolyg
9 августа 2021 в 07:54
0

Первоначально я использовал _mm256_loadu_ps; изменен на _mm256_load_ps позже. Такое же поведение для обоих.

Peter Cordes
9 августа 2021 в 08:10
0

vzeroupper позволяет избежать остановок перехода AVX/SSE при вызове функции после использования регистров YMM. Стандартное соглашение состоит в том, чтобы иметь чистые верхние значения при вызове/возврате, если только функция фактически не принимает аргумент в регистре YMM и, таким образом, можно предположить, что она не использует устаревшие инструкции SSE. MSVC глуп и использует регистры YMM в процессе извлечения элемента из вектора в памяти, поэтому ему нужен vzeroupper, чтобы избежать риска производительности. Ваши правильные результаты при отсутствии пошагового выполнения доказывают, что vzeroupper не является причиной проблемы.

Peter Cordes
9 августа 2021 в 08:12
1

@DanielLangr: MSVC (и ICC) всегда использовать загрузки/сохранения AVX без выравнивания, такие как vmovups, даже если вы используете встроенную функцию, требующую выравнивания. Таким образом, они устраняют возможность обнаружения несовмещенных данных, намеренно используя требуемые для выравнивания загрузки/сохранения в отладочной сборке (где они не будут складываться в исходные операнды памяти для других инструкций, которые не требуют выравнивания).

Ответы (1)

avatar
Alan Birtles
9 августа 2021 в 08:18
2

Visual studio 2017 15.9.7 исправляет ошибку, которая повреждает регистры AVX/MPX/AVX512 во время отладки.

anatolyg
9 августа 2021 в 09:28
0

Не пробовал (обновление Visual Studio - отдельный кошмар), но это должно быть ответом!

Alan Birtles
9 августа 2021 в 09:38
0

@anatolyg Обновление в текущем выпуске никогда не вызывало у меня никаких проблем, в основном оно просто содержит исправления ошибок и, что более важно, исправления безопасности вашего кода.