Как сказать компилятору развернуть этот цикл

У меня есть следующий цикл, который я запускаю на процессоре ARM.

// pin here is pointer to some part of an array
for (i = 0; i < v->numelements; i++)
{
    pe   = pptr[i];
    peParent = pe->parent;

    SPHERE  *ps = (SPHERE *)(pe->data);

    pin[0] = FLOAT2FIX(ps->rad2);
    pin[1] = *peParent->procs->pe_intersect == &SphPeIntersect;
    fixifyVector( &pin[2], ps->center ); // Is an inline function

    pin = pin + 5;
}

По медленному выполнению цикла могу судить, что компилятору не удалось развернуть этот цикл, т.к. когда я вручную делаю раскрутку, она становится достаточно быстрой. Я думаю, что компилятор запутался в указателе pin. Можем ли мы использовать здесь ключевое слово restrict, чтобы помочь компилятору, или restrict зарезервировано только для параметров функции? В общем, как мы можем сказать компилятору развернуть его и не беспокоиться об указателе pin.


person MetallicPriest    schedule 15.04.2013    source источник
comment
Измеряли ли вы время выполнения отладочной или релизной сборки?   -  person Axel    schedule 15.04.2013
comment
Выпуск сборки с оптимизацией -O3.   -  person MetallicPriest    schedule 15.04.2013
comment
Вы пытались назначить v->numelements локальному и использовать его в цикле for? Возможно, компилятор не может развернуть цикл, потому что он должен предположить, что значение v->numelements будет изменено в fixifyVector.   -  person Axel    schedule 15.04.2013
comment
fixifyVector встроен, поэтому я не думаю, что это проблема.   -  person MetallicPriest    schedule 15.04.2013
comment
gcc также имеет флаг оптимизации -funroll-loops, смотрящий на docs его нужно включать отдельно от -O3   -  person Robert Prior    schedule 15.04.2013
comment
Я не вижу в этом коде ничего, чему бы значительно помогло развертывание цикла. Вам придется просмотреть сгенерированный объектный код для двух случаев, чтобы понять, что происходит.   -  person John R. Strohm    schedule 15.04.2013
comment
@RobertPrior Вы должны опубликовать это как ответ, так как я уверен, что это все. Я не думаю, что какой-либо компилятор будет выполнять (тяжелое) развертывание цикла без запроса, поскольку это совершенно неэффективно с точки зрения объема памяти программы.   -  person Lundin    schedule 15.04.2013
comment
@JohnR.Strohm Разве это не зависит от numelements? Если это миллионы, вы можете избежать многих переходов кода и, следовательно, сравнений, развернув код. Или есть другие преимущества развертывания цикла, которые нельзя получить в этом сегменте?   -  person jn1kk    schedule 15.04.2013
comment
Возможно, вы захотите добавить конкретный процессор ARM, это, вероятно, важно для вопроса, связанного с производительностью.   -  person artless noise    schedule 15.04.2013
comment
@jsn, я вижу поиск в массиве, несколько манипуляций с указателями и вызов функции. Я чувствую, что они будут полностью доминировать во времени на итерацию по сравнению с накладными расходами цикла. Парень мог бы добиться значительного улучшения, кэшируя v-›numelements в инициализации цикла, вместо того, чтобы каждый раз извлекать их, но это не должно быть такой дорогой операцией.   -  person John R. Strohm    schedule 08.06.2013


Ответы (2)


Чтобы указать gcc развернуть все циклы, вы можете использовать флаг оптимизации -funroll-loops.

Чтобы развернуть только определенный цикл, вы можете использовать:

__attribute__((optimize("unroll-loops")))

см. этот ответ для более подробной информации.

Изменить

Если компилятор не может определить количество итераций цикла при входе, вам нужно будет использовать -funroll-all-loops. Обратите внимание, что из документации: "Unroll all loops, even if their number of iterations is uncertain when the loop is entered. This usually makes programs run more slowly."

person Robert Prior    schedule 15.04.2013

Если вы увеличиваете размер pptr на единицу, вы можете использовать инструкцию pld.

  __asm__ __volatile__("pld\t[%0]" :: "r" (pptr[i+1]));

Или же вам может потребоваться предварительно загрузить следующий peParent и SPHERE *ps. Накладные расходы цикла на ARM очень малы. Маловероятно, что разматывание цикла принесет значительную пользу. Константы переменных цикла отсутствуют. Более вероятно, что планировщик компилятора может получить дополнительные данные до того, как они будут использованы, когда вы развернете цикл.

Вы не представили весь код, чтобы увидеть зависимости данных. Возможно, есть и другие переменные, для которых было бы полезно предварительно загрузить. Предоставление полного примера, вероятно, поможет всем ответить на ваш вопрос.

person artless noise    schedule 15.04.2013
comment
Этот ответ более вероятен для процессоров типа Cortex, где конвейер больше. Конкретный процессор ARM не упоминался. - person artless noise; 15.04.2013