Почему GCC не оптимизирует этот набор ветвлений и условий настолько, насколько мог бы?

Следующие три фрагмента кода достигают точно такого же эффекта. Тем не менее, при компиляции с -O3 в GCC 4.5.2 время для многих итераций сильно различается.

1 - Нормальное ветвление с использованием нескольких условий, лучшее время 1.0:

// a, b, c, d are set to random values 0-255 before each iteration.
if (a < 16 or b < 32 or c < 64 or d < 128) result += a+b+c+d;

2 - Ветвление, вручную с использованием побитовых или проверочных условий, лучшее время 0,92:

if (a < 16 | b < 32 | c < 64 | d < 128) result += a+b+c+d;

3 - Наконец, получение того же результата без ветвления, лучшее время 0,85:

result += (a+b+c+d) * (a < 16 | b < 32 | c < 64 | d < 128);

Вышеуказанное время лучше всего подходит для каждый метод при запуске как внутренний цикл созданной мной тестовой программы. random () заполняется одинаково перед каждым запуском.

Перед тем, как я сделал этот тест, я предполагал, что GCC оптимизирует различия. Особенно второй пример заставляет почесать затылок. Может ли кто-нибудь объяснить, почему GCC не превращает такой код в эквивалентный более быстрый код?

РЕДАКТИРОВАТЬ: Исправлены некоторые ошибки, а также разъяснено, что случайные числа создаются независимо и используются, чтобы их нельзя было оптимизировать. Они всегда были в исходном тесте, я просто испортил код, который здесь разместил.

Вот пример действующей функции тестирования:

boost::random::mt19937 rng;
boost::random::uniform_int_distribution<> ranchar(0, 255);

double quadruple_or(uint64_t runs) {
  uint64_t result = 0;
  rng.seed(0);

  boost::chrono::high_resolution_clock::time_point start = 
    boost::chrono::high_resolution_clock::now();
  for (; runs; runs--) {
    int a = ranchar(rng);
    int b = ranchar(rng);
    int c = ranchar(rng);
    int d = ranchar(rng);
    if (a < 16 or b < 32 or c < 64 or d < 128) result += a;
    if (d > 16 or c > 32 or b > 64 or a > 128) result += b;
    if (a < 96 or b < 53 or c < 199 or d < 177) result += c;
    if (d > 66 or c > 35 or b > 99 or a > 77) result += d;
  }

  // Force gcc to not optimize away result.
  std::cout << "Result check " << result << std::endl;
  boost::chrono::duration sec = 
    boost::chrono::high_resolution_clock::now() - start;
  return sec.count();
}

Полную версию теста можно найти здесь .

8
задан Nightfirecat 14 November 2011 в 23:57
поделиться