Почему GCC не автоматически векторизует этот цикл?

Я пытаюсь оптимизировать цикл, на который приходится большая часть времени вычислений моей программы.

Но когда я включаю автоматическую векторизацию с помощью -O3 -ffast-math -ftree-vectorizer-verbose=6, GCC выводит, что он не может векторизовать цикл.

Я использую GCC 4.4.5.

Код:

/// Find the point in the path with the largest v parameter
void prediction::find_knife_edge(
    const float * __restrict__ const elevation_path,
    float * __restrict__ const diff_path,
    const float path_res,
    const unsigned a,
    const unsigned b,
    const float h_a,
    const float h_b,
    const float f,
    const float r_e,
) const
{
    float wavelength = (speed_of_light * 1e-6f) / f;

    float d_ab = path_res * static_cast<float>(b - a);

    for (unsigned n = a + 1; n <= b - 1; n++)
    {
        float d_an = path_res * static_cast<float>(n - a);
        float d_nb = path_res * static_cast<float>(b - n);

        float h = elevation_path[n] + (d_an * d_nb) / (2.0f * r_e) - (h_a * d_nb + h_b * d_an) / d_ab;
        float v = h * std::sqrt((2.0f * d_ab) / (wavelength * d_an * d_nb));

        diff_path[n] = v;
    }
}

Сообщения от GCC:

note: not vectorized: number of iterations cannot be computed.
note: not vectorized: unhandled data-ref 

На странице об автовекторизации ( http://gcc.gnu.org/projects/tree-ssa/vectorization.html ) утверждает, что поддерживает неизвестные границы цикла.

Если я заменю for на

for (unsigned n = 0; n <= 100; n++)

затем он векторизует его.

Что я делаю неправильно?

Отсутствие подробной документации о том, что именно означают эти сообщения, а также о плюсах и минусах автоматической векторизации GCC, довольно раздражает.

ИЗМЕНИТЬ:

Благодаря Дэвиду я изменил цикл на это:

 for (unsigned n = a + 1; n < b; n++)

Теперь GCC пытается векторизовать цикл, но выдает эту ошибку:

 note: not vectorized: unhandled data-ref
 note: Alignment of access forced using peeling.
 note: Vectorizing an unaligned access.
 note: vect_model_induction_cost: inside_cost = 1, outside_cost = 2 .
 note: not vectorized: relevant stmt not supported: D.76777_65 = (float) n_34;

Что означает "D.76777_65 = (с плавающей запятой) n_34;" значит?


person ljbade    schedule 15.11.2011    source источник
comment
IIRC, tree-ssa - это новый инструмент, разрабатываемый для преодоления ограничений векторизатора gcc, я не думаю, что он в настоящее время используется в основной магистрали gcc.   -  person Ben Voigt    schedule 16.11.2011
comment
Измените n <= b - 1 на n < b.   -  person David Schwartz    schedule 16.11.2011
comment
Я почти уверен, что у моего GCC есть tree-ssa, иначе он будет жаловаться на то, что флаг -ftree-vectorizer-verbose не поддерживается.   -  person ljbade    schedule 16.11.2011
comment
Дэвид: это сработало... однако теперь я получаю новую ошибку... Я обновлю вопрос.   -  person ljbade    schedule 16.11.2011


Ответы (1)


Возможно, я немного испортил детали, но именно так вам нужно реструктурировать цикл, чтобы он стал векторным. Хитрость заключается в том, чтобы предварительно вычислить количество итераций и выполнить итерацию от 0 до единицы меньше этого числа. Не изменяйте оператор for. Возможно, вам придется исправить две линии перед ним и две линии в верхней части петли. Они приблизительно правы. ;)

const unsigned it=(b-a)-1;
const unsigned diff=b-a;
for (unsigned n = 0; n < it; n++)
{
    float d_an = path_res * static_cast<float>(n);
    float d_nb = path_res * static_cast<float>(diff - n);

    float h = elevation_path[n] + (d_an * d_nb) / (2.0f * r_e) - (h_a * d_nb + h_b * d_an) / d_ab;
    float v = h * sqrt((2.0f * d_ab) / (wavelength * d_an * d_nb));

    diff_path[n] = v;
}
person David Schwartz    schedule 15.11.2011
comment
Это работает. Спасибо. Однако теперь мне нужно выяснить, как получить индекс до максимального значения в массиве... - person ljbade; 16.11.2011