Я пытаюсь написать некоторый вычислительный код для Windows x64 target с SSE или новыми инструкциями AVX, компилируя в GCC 4.5.2 и 4.6.1, MinGW64 (сборка TDM GCC и некоторая пользовательская сборка). Мои параметры компилятора -O3 -mavx
. (-m64
подразумевается)
Короче говоря, я хочу выполнить несколько длинных вычислений для 4-х трехмерных векторов упакованных чисел с плавающей точкой. Это требует 4x3 = 12 xmm или ymm регистров для хранения и 2 или 3 регистра для временных результатов. Это должно ИМХО плотно вписаться в 16 доступных регистров SSE (или AVX), доступных для 64-битных целей. Тем не менее, GCC производит очень неоптимальный код с проливом регистров, используя только регистры xmm0-xmm10
и перетасовывая данные из стека и обратно. Мой вопрос:
Есть ли способ убедить GCC использовать все регистры xmm0-xmm15
?
Чтобы исправить идеи, рассмотрите следующий код SSE (только для иллюстрации):
void example(vect<__m128> q1, vect<__m128> q2, vect<__m128>& a1, vect<__m128>& a2) {
for (int i=0; i < 10; i++) {
vect<__m128> v = q2 - q1;
a1 += v;
// a2 -= v;
q2 *= _mm_set1_ps(2.);
}
}
Здесь vect<__m128>
- это просто struct
из 3 __m128
, с естественным сложением и умножением на скаляр. Когда строка a2 -= v
закомментирована, т. Е. Нам нужно только 3х3 регистра для хранения, так как мы игнорируем a2
, полученный код действительно прост и не перемещается, все выполняется в регистрах xmm0-xmm10
. Когда я удаляю комментарий a2 -= v
, код довольно ужасный с большим количеством перетасовок между регистрами и стеком. Даже если компилятор может просто использовать регистры xmm11-xmm13
или что-то в этом роде.
На самом деле я еще не видел, чтобы GCC нигде не использовал ни одного из регистров xmm11-xmm15
во всем моем коде. Что я делаю неправильно? Я понимаю, что это регистры, сохраненные вызываемым пользователем, но эти издержки полностью оправдываются упрощением кода цикла.