Я изучал проблему, подал отчет об ошибке GCC и обнаружил, что это проблема, связанная с MinGW64. См. Ошибка GCC # 49001 . По-видимому, GCC не поддерживает 32-байтовое выравнивание стека в Windows. Это эффективно предотвращает использование 256-битных инструкций AVX.
Я исследовал пару способов решения этой проблемы. Самое простое и грубое решение - заменить выровненный доступ к памяти VMOVAPS / PD / DQA на невыровненные альтернативы VMOVUPS и т. Д. Итак, я изучил Python вчера вечером (кстати, очень хороший инструмент) и выполнил следующий скрипт, который выполняет работу с входной файл ассемблера, созданный GCC:
import re
import fileinput
import sys
# fix aligned stack access
# replace aligned vmov* by unaligned vmov* with 32-byte aligned operands
# see Intel's AVX programming guide, page 39
vmova = re.compile(r"\s*?vmov(\w+).*?((\(%r.*?%ymm)|(%ymm.*?\(%r))")
aligndict = {"aps" : "ups", "apd" : "upd", "dqa" : "dqu"};
for line in fileinput.FileInput(sys.argv[1:],inplace=1):
m = vmova.match(line)
if m and m.group(1) in aligndict:
s = m.group(1)
print line.replace("vmov"+s, "vmov"+aligndict[s]),
else:
print line,
Этот подход довольно безопасный и надежный. Хотя я наблюдал снижение производительности в редких случаях. Когда стек не выровнен, доступ к памяти пересекает границу строки кэша. К счастью, код выполняет так же быстро, как и выравниваемый доступ в большинстве случаев. Моя рекомендация: встроенные функции в критических циклах!
Я также попытался исправить распределение стека в каждом прологе функции, используя другой скрипт Python, пытаясь выровнять его всегда на границе 32 байта. Кажется, это работает для одного кода, но не для другого. Я должен полагаться на добрую волю GCC, что он будет выделять выровненные локальные переменные (по отношению к указателю стека), что он обычно делает. Это не всегда так, особенно когда происходит серьезное проливание регистра из-за необходимости сохранить весь регистр ymm перед вызовом функции. (Все регистры YMM сохраняются для вызываемого абонента). Я могу опубликовать сценарий, если есть интерес.
Лучшим решением будет исправить сборку GCC MinGW64. К сожалению, я ничего не знаю о его внутренней работе, только начал использовать его на прошлой неделе.