почему не происходит оптимизация? - PullRequest
2 голосов
/ 23 апреля 2010

У меня есть код C / C ++, который выглядит следующим образом:

static int function(double *I) {
    int n = 0;
    // more instructions, loops,
    for (int i; ...; ++i)
        n += fabs(I[i] > tolerance);
    return n;
}

function(I); // return value is not used.

встроенная функция компилятора, однако она не оптимизирует n манипуляции. Я ожидаю, что компилятор сможет распознать, что значение никогда не используется только как rhs. Есть ли побочный эффект, который мешает оптимизации?

компилятор, похоже, не имеет значения, я пробовал Intel и gcc. Агрессивная оптимизация, -O3

Спасибо

более полный код (полный код - повторение таких блоков):

  280         // function registers
  281         double q0 = 0.0;
  282         double q1 = 0.0;
  283         double q2 = 0.0;
  284
  285 #if defined (__INTEL_COMPILER)
  286 #pragma vector aligned
  287 #endif // alignment attribute
  288         for (int a = 0; a < int(N); ++a) {
  289             q0 += Ix(a,1,0)*Iy(a,0,0)*Iz(a,0,0);
  290             q1 += Ix(a,0,0)*Iy(a,1,0)*Iz(a,0,0);
  291             q2 += Ix(a,0,0)*Iy(a,0,0)*Iz(a,1,0);
  292         }
  293 #endif // not SSE
  294
  295         //contraction coefficients
  296         qK0 += q0*C[k+0];
  297         qK1 += q1*C[k+0];
  298         qK2 += q2*C[k+0];
  299
  300         Ix += 3*dim2d;
  301         Iy += 3*dim2d;
  302         Iz += 3*dim2d;
  303
  304     }
  305     Ix = Ix - 3*dim2d*K;
  306     Iy = Iy - 3*dim2d*K;
  307     Iz = Iz - 3*dim2d*K;
  308
  309     // normalization, scaling, and storage
  310     if(normalize) {
  311         I[0] = scale*NORMALIZE[1]*NORMALIZE[0]*(qK0 + I[0]);
  312         num += (fabs(I[0]) >= tol);
  313         I[1] = scale*NORMALIZE[2]*NORMALIZE[0]*(qK1 + I[1]);
  314         num += (fabs(I[1]) >= tol);
  315         I[2] = scale*NORMALIZE[3]*NORMALIZE[0]*(qK2 + I[2]);
  316         num += (fabs(I[2]) >= tol);
  317     }
  318     else {
  319         I[0] = scale*(qK0 + I[0]);
  320         num += (fabs(I[0]) >= tol);
  321         I[1] = scale*(qK1 + I[1]);
  322         num += (fabs(I[1]) >= tol);
  323         I[2] = scale*(qK2 + I[2]);
  324         num += (fabs(I[2]) >= tol);
  325     }
  326
  327
  328     return num;

Мое единственное предположение - потенциально исключения с плавающей точкой, которые привели к побочным эффектам

Ответы [ 4 ]

7 голосов
/ 23 апреля 2010

Код использует n, сначала, когда он инициализирует его 0, а затем внутри цикла с левой стороны функции с возможными побочными эффектами (fabs).

Независимо от того, действительно ли вы используете return функции, не имеет значения, n сама используется .

Обновление: я попробовал этот код в MSVC10, и он оптимизировал всю функцию. Приведите мне полный пример, который я мог бы попробовать.

#include <iostream>
#include <math.h>

const int tolerance=10;

static int function(double *I) {
    int n = 0;
    // more instructions, loops,
    for (int i=0; i<5; ++i)
        n += fabs((double)(I[i] > tolerance));
    return n;
}


int main()
{
    double I[]={1,2,3,4,5};

    function(I); // return value is not use
}
2 голосов
/ 24 апреля 2010

Я думаю, что короткий ответ на этот вопрос таков: просто то, что компилятор может провести некоторую оптимизацию в теории, не означает, что будет . Ничто не приходит бесплатно. Если компилятор собирается оптимизировать, то кто-то должен написать код, чтобы сделать это.

Это звучит как большая работа для чего-то, что является одновременно причудливым угловым случаем и тривиальной экономией пространства. Я имею в виду, как часто люди пишут функции, которые выполняют сложные вычисления только для того, чтобы отбросить результат? Стоит ли писать сложные оптимизации для восстановления стекового пространства размером 8 байт в таких случаях?

1 голос
/ 24 апреля 2010

Я не могу с уверенностью сказать, что это будет иметь эффект, но вы, возможно, захотите взглянуть на атрибуты pure и const GCC (http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html).) В основном это говорит компилятору, что функция работает только на его вход и не имеет побочных эффектов.

Учитывая эту дополнительную информацию, он может определить, что вызов не нужен.

0 голосов
/ 24 апреля 2010

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

Забавные, как это:

int fun ( int a )
{
   switch(a&3)
   {
      case 0: return(a+4); 
      case 1: return(a+2);
      case 2: return(a);
      case 3: return(0);
   }
   return(1);
}

В течение самого длительного времени, если вы оставите этот возврат в конце, вы получите ошибку, что функция определила тип возвращаемого значения, но не смогла вернуть значение. Некоторые компиляторы жалуются на return () в конце функции и жалуются без него.

Из того, что я могу сказать из gcc против, скажем, llvm, gcc оптимизирует функцию в файле, где llvm оптимизирует все, что ему подают. И вы можете объединить байт-код для всего проекта в один файл и оптимизировать все это в одном кадре. На данный момент производительность gcc превосходит llvm на дюжину и более процентов, что интересно. дай ему время.

Возможно, в вашем случае вы вычисляете, используя два входа, которые не объявлены как статические (const), поэтому результат n может измениться. Если оптимизировано для каждой функции, это не может уменьшить его дальше. Таким образом, я предполагаю, что она оптимизирует для каждой функции, и вызывающая функция не знает, как повлияет на динамический ввод, который я имею в системе, даже если возвращаемое значение не использовалось, ей все равно нужно будет вычислить функцию (I) для разрешения того, что зависит I. Я предполагаю, что это не бесконечный цикл, ... означает, что наложено какое-то ограничение? Если не здесь снова динамическая, а не статическая, функция (I) могла бы быть функцией завершающего бесконечного цикла, или она могла бы ожидать, что подпрограмма обработки прерывания изменит I и выведет ее из бесконечного цикла.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...