Я пытаюсь написать некоторый ресурсоемкий код для цели Windows x64, с 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
закомментирована, т.е. нам нужны только регистры 3x3 для хранения, так как мы игнорируем a2
, получаемый код действительно прям без ходов, все выполняется в регистрах xmm0-xmm10
. Когда я удаляю комментарий a2 -= v
, код становится довольно ужасным с большим количеством перетасовки между регистрами и стеком. Хотя компилятор может просто использовать регистры xmm11-xmm13
или что-то в этом роде.
На самом деле я еще не видел, чтобы GCC использовал какой-либо из регистров xmm11-xmm15
во всем моем коде. Что я делаю неправильно? Я понимаю, что это регистры, сохраняемые вызываемым пользователем, но эти накладные расходы полностью оправдываются упрощением кода цикла.