icc не выполняет перемещение инвариантного кода цикла

Может ли кто-нибудь объяснить причину, по которой icc не выполняет циклически инвариантное движение кода (назначения перемещения указателя a) в коде 1 ниже. Я вижу улучшение производительности на 40%, когда назначение указателя a перемещается из цикла t6, как это сделано в коде 2. Я попытался пометить указатель «a» как константу и ограничить, чтобы компилятор знал, что указатель «a» не будет быть изменен внутри цикла t6. Я компилирую код с опцией -ansi-alias в icc.

//код 1

          for (t4=256*t1; t4<=256*t1+254; t4++) {
            lbv=256*t2;
            ubv=256*t2+255;
            for (t6=lbv; t6<=ubv; t6++) { 
                double *restrict const a = a_trans[lbv /256]; //loop invariant code
                a[t6-lbv]=a[t6-lbv]/a[t6-lbv];
            }
          }

//код 2

       for (t4=256*t1; t4<=256*t1+254; t4++) {
            lbv=256*t2;
            ubv=256*t2+255;
            double *restrict const a = a_trans[lbv /256];
            for (t6=lbv; t6<=ubv; t6++) {
                a[t6-lbv]=a[t6-lbv]/a[t6-lbv];
            }
       }

Этот код генерируется транслятором исходного кода. Очень утомительно вручную применять это преобразование к большому количеству циклов. Есть ли способ позволить icc автоматически выполнять это преобразование?


person ChandanG    schedule 19.10.2013    source источник


Ответы (1)


Кажется, что и a_trans, и lbv определены во внешней области видимости и не являются константами. Вы не можете ожидать, что icc достаточно умен, чтобы понять, что a не изменится. Для больших переменных области видимости, таких как a_trans и lbv, компилятор назначит их в ОЗУ. Возможно, они меняются во время цикла. На самом деле, если они определены как локальные переменные (назначенные в регистрах), компилятор может их оптимизировать.

      for (t4=256*t1; t4<=256*t1+254; t4++) {
        lbv=256*t2;
        ubv=256*t2+255;
        const int local_lbv=lbv;
        const double** local_a_trans=a_trans;
        for (t6=lbv; t6<=ubv; t6++) { 
            double *restrict const a = local_a_trans[local_lbv /256];
            a[t6-lbv]=a[t6-lbv]/a[t6-lbv];
        }
      }

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

С другой стороны, вы можете попытаться выполнить более агрессивную оптимизацию кода с помощью -O3 и -ipo.

РЕДАКТИРОВАТЬ

После попытки локализовать переменные улучшения производительности по-прежнему нет. Думаю, можно сделать вывод, что генератор кода не будет генерировать код с достаточно высокой производительностью. После автоматической генерации рекомендуется перезапись вручную.

person kangshiyin    schedule 19.10.2013
comment
Если вы можете это сделать, почему бы просто не убрать эту строку из цикла? - person kangshiyin; 20.10.2013
comment
Проблема существует даже после того, как вы сделаете «lbv» локальной переменной и пометите «a_trans» как const/restrict в функции. Я использовал опции «-03» и «-ipo» в icc. Есть ли какое-либо другое ключевое слово, которое я могу использовать, чтобы сообщить icc, что «a_trans» не будет изменен с циклом? - person ChandanG; 20.10.2013
comment
Как я упоминал ранее, этот код генерируется транслятором исходного кода в исходный, я могу легко изменить текст в самом внутреннем теле цикла for, но не могу добавить текст между циклами for. lbv уже является локальным в сгенерированном коде. - person ChandanG; 20.10.2013
comment
Попробуйте сделать их как локальными, так и константными. Вы можете ожидать многого, если рассчитываете на переводчик исходного кода. - person kangshiyin; 20.10.2013
comment
Я попытался сделать a_trans также локальным, добавив 'double** local_a_trans=a_trans;' перед самим циклом t4, все еще не получая производительности - person ChandanG; 20.10.2013
comment
лучше перед циклом t6 сделать его достаточно локальным и использовать const double** - person kangshiyin; 20.10.2013