MSVC 2013: как правильно включить AVX2?

#avx #avx2 #visual-c -2013

#avx #avx2 #visual-c -2013

Вопрос:

Я пытаюсь получить более быстрый двоичный файл для определенного программного обеспечения, включив /arch:AVX2, поскольку я запускаю его на процессорах, которые должны поддерживать этот набор команд (i7 4770 и i7 4800MQ).
Однако это приводит к сбою исполняемого файла с сообщением «xxx.exe перестал работать», как если бы я запускал его на оборудовании, отличном от AVX2.
Я знаю, что AVX2 правильно поддерживается в моей системе, запустив y-cruncher, который обнаруживает аппаратное обеспечение AVX2 и запускает соответствующий исполняемый файл.
Та же проблема возникает, если я укажу /arch:AVX .
Код выполняется нормально при сборке без опции /arch . Другие используемые параметры сборки:

 /Ox /Ob2 /Oi /Oy /GT /GL /Gm- /EHsc /MD /GS /fp:precise /Zc:wchar_t /Zc:forScope /GR /openmp /Gd /TP /GL /GF /Ot  /Qfast_transcendentals
  

Само ПО себе программное обеспечение не использует специфических встроенных функций AVX2, поскольку оно предназначено для работы на более широком наборе платформ. Я просто пытаюсь повысить производительность на своих платформах, не изменяя код (чего я даже не смог бы сделать, поскольку это сложная часть программного обеспечения, и я вообще не эксперт-программист).

Мой вопрос: почему этот параметр должен привести к сбою программы на компьютере с поддержкой AVX2? Я что-то упускаю, что мешает корректной работе /arch:AVX2, например, несовместимости с другими флагами? (Я проверил документы MS и не нашел никакой «перекрестной зависимости», связанной с AVX2).

Редактировать: я добавляю здесь еще немного информации о коде, как предложил Регис Порталез. Вот фрагмент кода, вызывающий проблему. VS debugger останавливается перед последней строкой, указывающей на нарушение доступа:

 void Film::ComputeGroupScale(u_int i)
{
    const Color white(space.ToXYZ(RGB(1.f)));
    if (groups[i].temperature > 0.f) {
        Color colorTemp(SPD(groups[i].temperature));
        colorTemp /= colorTemp.Y();
        groups[i].convert = Adapter(white,
            space.ToXYZ(groups[i].rgbScale)) *
            Adapter(white, colorTemp);
    } else {
        groups[i].convert = Adapter(white,
            space.ToXYZ(groups[i].rgbScale));
    }
    groups[i].convert *= groups[i].globalScale;
}
  

Ниже приведен код сборки для последней строки:

 }
    groups[i].convert *= groups[i].globalScale;
00007FFB28E43B2A  vbroadcastss ymm2,dword ptr [rax rbx 40h]  
00007FFB28E43B31  mov         rax,qword ptr [rdi 1B8h]  
00007FFB28E43B38  vmulps      ymm0,ymm2,ymmword ptr [rax rbx 54h]  
00007FFB28E43B3E  vmovups     ymmword ptr [rax rbx 54h],ymm0  
00007FFB28E43B44  vmulss      xmm0,xmm2,dword ptr [rax rbx 74h]  
00007FFB28E43B4A  vmovss      dword ptr [rax rbx 74h],xmm0  
00007FFB28E43B50  vzeroupper  
}
  

Отладчик указывает, что нарушение доступа происходит в vbroadcastss. Содержимое регистра выглядит следующим образом и показывает, что есть попытка прочитать местоположение 0:

 RAX = 000000003F800000 RBX = 0000000000000000 RCX = 000007FEDC1143A8 RDX = 000000000021B6E8 
RSI = 0000000007709710 RDI = 0000000002D165E0 R8  = 000000000021B6B0 R9  = 0000000004D25190 
R10 = 00000000003B0274 R11 = 000000000021B428 R12 = 0000000000000001 R13 = 0000000000000000 
R14 = 0000000000000000 R15 = 0000000002288480 RIP = 000007FEDBDC2C0A RSP = 000000000021B690 
RBP = 000000000021B790 EFL = 00010340 

0x000000003f800040 = 00000000 
  

Для сравнения, когда /arch:AVX2 не используется, это сборка:

     groups[i].convert *= groups[i].globalScale;
000007FEDCA019E8  movups      xmm0,xmmword ptr [rax rbx 54h]  
000007FEDCA019ED  shufps      xmm2,xmm2,0  
000007FEDCA019F1  mulps       xmm0,xmm2  
000007FEDCA019F4  movups      xmmword ptr [rax rbx 54h],xmm0  
000007FEDCA019F9  movups      xmm0,xmmword ptr [rax rbx 64h]  
000007FEDCA019FE  mulps       xmm0,xmm2  
000007FEDCA01A01  movups      xmmword ptr [rax rbx 64h],xmm0  
000007FEDCA01A06  mulss       xmm2,dword ptr [rax rbx 74h]  
000007FEDCA01A0C  movss       dword ptr [rax rbx 74h],xmm2  
}
  

Объект groups, участвующий в нарушении доступа, определяется как:

 std::vector<Group> groups;

class Group {
public:
    Group(const string amp;n) : samples(0.f), name(n),
        globalScale(1.f), temperature(0.f),
        rgbScale(1.f), convert(Color(1.f), Color(1.f)),
        enable(true) { }
    ~Group() {
        for(vector<Buffer *>::iterator buffer = buffers.begin(); buffer != buffers.end();   buffer)
            delete *buffer;
    }

    void CreateBuffers(const vector<BufferConfig> amp;configs, u_int x, u_int y);

    Buffer *getBuffer(u_int index) const {
        return buffers[index];
    }
    double samples;
    vector<Buffer *> buffers;
    string name;
    float globalScale, temperature;
    RGB rgbScale;
    Adapter convert;
    bool enable;
};
  

Я надеюсь, что эта информация позволит провести дополнительный анализ…

Комментарии:

1. Трудно сказать с таким уровнем детализации. Обычно я не сталкиваюсь с какой-либо конкретной проблемой с AVX2. Правильно ли работает ваша программа без поддержки AVX? В чем причина сбоя? Вы запускали отладчик?

2. Да, программа работает корректно без поддержки AVX. При добавлении /arch:AVX2 (или AVX ) к перечисленным выше параметрам происходит сбой. Причиной сбоя является нарушение доступа, и я определил строку кода, в которой это происходит с помощью отладчика (это доступ к члену объекта, но доступ к другим членам того же объекта в непосредственно предшествующих строках разрешен). Однако я не могу определить основную причину. Я думал отключить параметры оптимизации по одному и посмотреть, какие эффекты он имеет, но пока не было времени…

3. Не могли бы вы опубликовать здесь какую-то часть кода? Нравится структура, к которой обращаются. И сгенерированная сборка?

4. Я обновил текст исходным кодом и сгенерированной сборкой, как с /arch:AVX2 , так и без.

5. Какая инструкция asm на самом деле неисправна? И какие значения находятся в регистрах, задействованных в режиме адресации? Ваш отладчик должен быть в состоянии показать вам. Можете ли вы подтвердить, что это определенно не ошибка незаконных инструкций? Ваш процессор (i7 4xxx) поддерживает AVX2 (и это только AVX1), но виртуальная машина может быть проблемой, если вы работаете внутри виртуальной машины. Ни одна из задействованных инструкций AVX не имеет каких-либо требований к выравниванию, так что это не так. Возможно, ошибка компилятора или, возможно, оптимизация выявляет неопределенное поведение в исходном коде.