2012-04-18 4 views
8

Легко видеть, что:Оптимизированы логические операции над несколькими модулями?

(i % 3 == 0) && (i % 5 == 0) 

Может быть упрощена:

(i % 15 == 0) 

Тем не менее, глядя на выходе GCC, кажется, это не сделано даже на высоких уровнях оптимизации.

Выполняют ли какие-либо компиляторы такие виды оптимизации, или есть веская причина, почему эти два теста не являются семантически эквивалентными?

Edit: В ответ на тех, кто говорит, что это бахрома случай, следующий подобный случай:

(i < 3) && (i < 5) 

Любое число меньше, чем 3, всегда должно быть меньше 5. Второй тест является излишним.

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

void foo(void) 
{ 
    int i; 
    for (i = 0; i <= 10; i++) 
    { 
     if (i > 20) 
     { 
      puts("Hi"); 
     } 
    } 
} 

Всего функция сводится к «REPZ отставке "по GCC с -O2. Это гораздо сложнее, чем все, о чем я говорю.

+1

Мое предположение заключается в том, чтобы гарантировать оценку короткого замыкания ... – Anycorn

+0

Соберите ли компиляторы для нескольких сравнений для одной и той же переменной для оптимизации? Это похоже на бахрому ... – trutheality

+2

@Anycorn, Вы говорите, что оценка 'i' может иметь побочные эффекты, а компилятор не делает это или нет? – ikegami

ответ

5

Игнорировать все глупые ответы, утверждая, что это сложно или невозможно сделать компилятору. Я не вижу причин, почему это было бы трудно, но, предположительно, никто не думал об этом или думал, что это будет достаточно важно для оптимизации. Если вы хотите получить более качественный ответ, вам нужно будет сообщить об этом в трекер GCC, как запрос на повышение, и посмотреть, что говорят разработчики.

+0

Я думаю вы имеете в виду * in * достаточно. Но да, я согласен с тобой. – Matt

+1

Моя грамматика верна. Субъект по-прежнему «никто», который обеспечивает отрицательную семантику. :-) –

3

Ваш пример довольно прост и действительно легко конденсируется в одну операцию. Однако общий пример такого утверждения не так прост. Возьмем, например, следующее:

((++i) % 3 == 0) && ((++i) % 5 == 0) 

Это изменение не может быть упрощена до одной операции модуля так же легко (я знаю, что это утверждение имеет множество других проблем, связанных с ней, но дело в том, что проблема ISN» t просто, когда вы используете что-либо, кроме простой ссылки на переменные). Компиляторы обычно не хотят видеть, что ваш случай включает только простые переменные и оптимизирует его по-другому, чем общий случай; они стараются поддерживать согласованность и предсказуемость, когда это возможно.

Обновление: Дополнительные случаи, которые вы добавили в свой вопрос, попадают в совершенно другой класс оптимизации, чем исходный фрагмент кода. Они оба оптимизированы, потому что они недостижимый код, и могут быть доказаны как таковые во время компиляции. Ваш первоначальный вопрос включал повторную запись двух операций в единую эквивалентную операцию, уникальную от оригинала. Два добавленных фрагмента не переписывают существующий код, они только удаляют код, который никогда не может быть выполнен. Компиляторы обычно очень хорошо разбираются и удаляют мертвый код.

Оптимизация, которую вы ищете, представляет собой форму сокращения математической силы сокращения. Большинство компиляторов предлагают некоторый уровень оптимизации MSR, хотя как они будут детально изучены, зависит от компилятора и возможностей целевой платформы. Например, компилятор, ориентированный на архитектуру ЦП, у которой нет инструкции по модулю (что означает, что вместо этого используется потенциально-длинная библиотечная функция), может более агрессивно оптимизировать такие утверждения. Если целевой процессор поддерживает аппаратный модуль, писатель компилятора может считать две или три сохраненных инструкции слишком малыми, чтобы выиграть время и усилия, необходимые для внедрения и тестирования улучшений оптимизации. Я видел это в прошлом с некоторыми операциями, которые могут быть выполнены в одной инструкции на процессоре x86 (например), но для этого потребуются десятки инструкций на CPU RISC.

+0

Я не согласен. Компиляторы хорошо находят общие подвыражения (из которых просто 'i' является тривиальным случаем) и оптимизируя их использование. –

+1

@R ..- Однако это не классифицируется как общее подвыражение. Оптимизация CSE ищет подкомпонент, который имеет несколько операторов, и затем использовал предварительно кэшированное значение вместо повторного вычисления выражения несколько раз. Здесь единственной общей частью является 'i%', которая не является полной операцией и не является расчетной. То, о чем просит ОП, более тесно связано с семейством оптимизаций «математической силы». – bta

+0

В дополнение ко всему этому помните, что оператор «&&» вводит точку последовательности (для операции «короткого замыкания»). Если левая часть оценивается до нуля, правая часть не выполняется вообще. Из-за множества возможных побочных эффектов компиляторы, вероятно, очень не решаются оптимизировать точку последовательности. Для простых случаев это кажется простым, но, как общая проблема, это гораздо труднее сделать. – bta

1

Честно говоря, это очень конкретный случай. Если какая-либо часть уравнения будет изменена, оптимизация больше не будет применяться. Я думаю, что речь идет о затратах и ​​выгодах, и затраты на реализацию этой оптимизации (увеличение времени компиляции, увеличение сложности обслуживания) перевешивают преимущества (несколько менее быстрых операций в редких случаях).

В общем, математический рефакторинг нельзя применять из-за ограничения точности и возможности переполнения. Хотя я не думаю, что это проблема.

Смежные вопросы