- •Глава 14 Генерация
- •1 Примером контекстной зависимости, часто встречающейся во многих языках программирования, может служить необходимость предварительно описать идентификатор до его первого использования.
- •Этапы семантического анализа
- •Идентификация лексических единиц языков программирования
- •Распределение памяти. Принципы распределения памяти
- •1 Некоторые вычислительные системы даже вообще не могут работать с адресами, не кратными определенному числу байт.
- •Глобальная и локальная память
- •Статическая и динамическая память
- •Дисплей памяти процедуры (функции). Стековая организация дисплея памяти
- •Стековая организация дисплея памяти процедуры (функции)
- •Память для типов данных (rtti-информация)
- •Способы внутреннего представления программ
- •Синтаксические деревья
- •Многоадресный код с явно именуемым результатом (тетрады)
- •Многоадресный код с неявно именуемым результатом (триады)
- •Обратная польская запись операций
- •Вычисление выражений с помощью обратной польской записи
- •Схемы су-перевода
- •Пример схемы су-перевода дерева операций на язык ассемблера
- •Пример схемы су-перевода дерева операций в последовательность триад
- •Оптимизация линейных участков программы Принципы оптимизации линейных участков
- •Свертка объектного кода
- •Исключение лишних операций
- •Другие методы оптимизации программ Оптимизация вычисления логических выражений
- •Оптимизация передачи параметров в процедуры и функции
- •Оптимизация циклов
- •1 Незначительный выигрыш в скорости достигается за счет исключения всех операций с индуктивной переменной, однако объем программы может существенно возрасти.
- •Машинно-зависимые методы оптимизации
- •Распределение регистров процессора
- •Оптимизация кода для процессоров, допускающих распараллеливание вычислений
Другие методы оптимизации программ Оптимизация вычисления логических выражений
Особенность оптимизации логических выражений заключается в том, что не всегда необходимо полностью выполнять вычисление всего выражения для того, чтобы знать его результат. Иногда по результату первой операции или даже по значению одного операнда можно заранее определить результат вычисления всего выражения.
Операция называется предопределенной для некоторого значения операнда, если ее результат зависит только от этого операнда и остается неизменным (инвариантным) относительно значений других операндов.
Операция логического сложения (or) является предопределенной для логического значения «истина» (true), a операция логического умножения — предопределена для логического значения «ложь» (false).
Эти факты могут быть использованы для оптимизации логических выражений. Действительно, получив значение «истина» в последовательности логических сложений или значение «ложь» в последовательности логических умножений, нет никакой необходимости далее производить вычисления — результат уже определен и известен.
Например, выражение A ог B ог C ог D не имеет смысла вычислять, если известно, что значение переменной A есть True («истина»).
Компиляторы строят объектный код вычисления логических выражений таким образом, что вычисление выражения прекращается сразу же, как только его значение становится предопределенным. Это позволяет ускорить вычисления при выполнении результирующей программы. B сочетании с преобразованиями логических выражений на основе тождеств булевой алгебры и перестановкой операций эффективность данного метода может быть несколько увеличена.
He всегда такие преобразования инвариантны к смыслу программы. Например, при вычислении выражения A ог F(B) ог G(C) функции F и G не будут вызваны и выполнены, если значением переменной A является true. Это не важно, если результатом этих функций является только возвращаемое ими значение, но если они обладают «побочным эффектом» (о котором было сказано выше в замечаниях), то семантика программы может измениться.
B большинстве случаев современные компиляторы позволяют исключить такого рода оптимизацию, и тогда все логические выражения будут вычисляться до конца, без учета предопределенности результата. Однако лучше избегать такого рода «побочных эффектов», которые, как правило, говорят о плохом стиле программирования.
Хорошим стилем считается также принимать во внимание эту особенность вычисления логических выражений. Тогда операнды в логических выражениях следует стремиться располагать таким образом, чтобы в первую очередь вычислялись те из них, которые чаще определяют все значение выражения. Кроме того, значения функций лучше вычислять в конце, а не в начале логического выражения, чтобы избежать лишних обращений к ним. Так, рассмотренное выше выражение лучше записывать и вычислять в порядке A or F(B) ог G(C), чем в порядке F(B) or G(C) ог A.
He только логические операции могут иметь предопределенный результат. Некоторые математические операции и функции также обладают этим свойством. Например, умножение на O не имеет смысла выполнять.
Другой пример такого рода преобразований — это исключение вычислений для инвариантных операндов.
Операция называется инвариантной относительно некоторого значения операнда, если ее результат не зависит от этого значения операнда и определяется другими операндами.
Например, логическое сложение (ог) инвариантно относительно значения «ложь» (False), логическое умножение (and) — относительно значения «истина»; алгебраическое сложение инвариантно относительно O, а алгебраическое умножение — относительно 1.
Выполнение такого рода операций можно исключить из текста программы, если известен инвариантный для них операнд. Этот метод оптимизации имеет смысл в сочетании с методом свертки операций.
