Ответ 1
-mtune
не создает диспетчера, он не нужен: мы уже сообщаем компилятору, в какой архитектуре мы нацеливаемся.
Из Документы GCC:
-mtune = cpu-type
набор доступных инструкций.
Это означает, что GCC не будет использовать инструкции, доступные только для cpu-type 1 но он будет генерировать код, который выполняется оптимально для cpu-типа.
Чтобы понять это последнее утверждение, необходимо понять разницу между архитектурой и микроархитектурой.
Архитектура подразумевает ISA (архитектура набора инструкций) и не влияет на -mtune
.
Микроархитектура - это то, как архитектура реализована в аппаратном обеспечении.
Для равного набора команд (чтение: архитектура) последовательность кода может выполняться оптимально на процессоре (читая микро-архитектуру), но не на другом, из-за внутренних деталей реализации.
Это может привести к тому, что последовательность кода будет оптимальной только на одной микроархитектуре.
При генерации машинного кода часто GCC имеет определенную степень свободы в выборе того, как заказывать инструкции и какой вариант использовать.
Он будет использовать эвристику для генерации последовательности инструкций, которые быстро работают на наиболее распространенных процессорах, когда-нибудь она пожертвует 100% -ным оптимальным решением для CPU x, если это будет наказывать процессоры y, z и w.
Когда мы используем -mtune=x
, мы точно настраиваем вывод GCC для CPU x, создавая таким образом код, который на 100% оптимален (с точки зрения GCC) на этом CPU.
В качестве конкретного примера рассмотрим как скомпилирован этот код:
float bar(float a[4], float b[4])
{
for (int i = 0; i < 4; i++)
{
a[i] += b[i];
}
float r=0;
for (int i = 0; i < 4; i++)
{
r += a[i];
}
return r;
}
a[i] += b[i];
векторизован (если векторы не перекрываются) по-разному при ориентации на Skylake или Core2:
Skylake
movups xmm0, XMMWORD PTR [rsi]
movups xmm2, XMMWORD PTR [rdi]
addps xmm0, xmm2
movups XMMWORD PTR [rdi], xmm0
movss xmm0, DWORD PTR [rdi]
Core2
pxor xmm0, xmm0
pxor xmm1, xmm1
movlps xmm0, QWORD PTR [rdi]
movlps xmm1, QWORD PTR [rsi]
movhps xmm1, QWORD PTR [rsi+8]
movhps xmm0, QWORD PTR [rdi+8]
addps xmm0, xmm1
movlps QWORD PTR [rdi], xmm0
movhps QWORD PTR [rdi+8], xmm0
movss xmm0, DWORD PTR [rdi]
Основное отличие заключается в том, как загружается регистр xmm
, на Core2 он загружается двумя нагрузками, используя movlps
и movhps
вместо одного movups
.
Оба подхода с двумя нагрузками лучше подходят для микроархитектуры Core2, если вы посмотрите на таблицы инструкций Agner Fog, вы увидите, что movups
декодируется в 4 раза и имеет задержку в 2 цикла, тогда как каждый movXps
равен 1 uop и 1 цикл латентности.
Вероятно, это связано с тем, что 128-битные обращения были разделены на два 64-разрядных доступа в то время.
На Skylake верно обратное: movups
выполняет лучше двух movXps
.
Итак, мы должны подобрать один.
В общем, GCC выбирает первый вариант, потому что Core2 - это старая микроархитектура, но мы можем переопределить это с помощью -mtune
.
1 Набор команд выбирается другими клавишами.