Генерация высококачественного кода для программ на СИ
Страница 6. Методы оптимизации. Часть 4




 Рис. 3 демонстрирует вынесение инвариантного кода компилятором Microsoft C
 5.0. Дальнейший анализ примера показывает, что значение переменной i,
 индекса цикла, изменяется непосредственно с каждой итерацией. Отдельное
 присваивание i, известной как "переменная индукции цикла", может быть
 удалено:
      T1 = j + k;
  for(x = 0; x< T1 * v; x += T1)
       ;
       i = v;

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

  --------------------------------------------------------------¬
  ¦РИСУНОК 4: Удаление переменных индукции цикла      ¦
  +-------------------------------------------------------------+
  ¦Исходный текст на Си MICROSOFT     DATALIGHT  ¦
  ¦      C 5.0    Optimum-C 3.14  ¦
  +-------------------------------------------------------------+
  ¦for(i=0;i<100;i++)        mov  AX,0 ¦
  ¦ ivector5[i*2+3]=5;   mov  i,100    mov  i,AX ¦
  ¦   mov  SI,OFFSET ivector5+6   cmp  AX,100    ¦
  ¦   $L20006:     jge  L134 ¦
  ¦        mov  [SI],5   L11B:    ¦
  ¦        add  SI,4    mov  BX,i ¦
  ¦      cmp  SI,OFFSET ivector5+406   shl  BX,1 ¦
  ¦        jb   $L20006      shl  BX,1 ¦
  ¦           mov ivector+6[BX],5 ¦
  ¦           inc  i    ¦
  ¦           cmp  i,100     ¦
  ¦           jl   L11B ¦
  ¦       L134:    ¦
  +-------------------------------------------------------------+
  ¦ Удаление переменных индукции цикла помогает минимизировать  ¦
  ¦ время, проводимое в каждой итерации цикла, путем вынесения  ¦
  ¦ индексирующих  цикл  переменных  (переменных  индукции) из  ¦
  ¦ тела цикла. В то время, как компилятор Datalight Optimum-C  ¦
  ¦ использует переменную индукции i  для  индексации  массива  ¦
  ¦ ivector5,  компилятор Microsoft C 5.0 удаляет ее благодаря  ¦
  ¦ накоплению  смещения  для  каждого  элемента   массива   и  ¦
  ¦ добавлению результата к базовому адресу массива.  ¦
  L--------------------------------------------------------------



 "Слияние циклов" минимизирует управляющие заголовки циклов путем
 сращивания кода из циклов, имеющих одинаковые управляющие заголовки, в
 один цикл. Для того, чтобы удалить управляющий заголовок второго цикла,
 два простых цикла
  for(i = 0; i < 10; i++)
   a = b + c;
  for(i = 0; i < 10; i++)
   d = e + f;

 могут быть объединены в один цикл
  for(i = 0; i < 10; i++) {
   a = b + c;
   d = e + f;
  }

 Поскольку для поддержки слияния циклов требуется процедурная оптимизация,
 в общем случае это действие не выполняется. Ни один из включенных в обзор
 компиляторов этот метод не применяет.
 Непосредственно связано со слиянием циклов "разворачивание циклов",
 которое минимизирует количество проходов через цикл путем увеличения числа
 операций, выполняемых внутри каждой итерации. Цикл инициализации массива
  int a[3];
  int i;
  for(i = 0; i < 3; i++)
   a[i] = 0;

 странслированный компилятором без оптимизации, может получить следующий
 эквивалент в языке ассемблера:
  mov  i,0
  LOOP:
  mov  BX,i
  shl  BX,1
  mov  a[BX],0
  inc  i
  cmp  i,3
  jl   LOOP

 В том же коде, оптимизированном по методу разворачивания цикла, удаляется
 цикл путем замещения его тремя инструкциями присваивания:
  mov  a,0
  mov  a+2,0
  mov  a+4,0

 Хотя ни один из компиляторов, включенных в обзор, не выполняет буквальное
 разворачивание циклов, некоторые из них оптимизируют цикл путем
 использования "специализированных инструкций прцессора". Многие процессоры
 предоставляют специализированные инструкции для управления перемещением
 блоков данных, инициализации памяти и других часто встречающихся ситуаций
 управления данными. К примеру, строковые инструкции с префиксом повторения
 (в семействе процессоров 80x86), выполняющиеся быстрее, чем посимвольные
 команды в цикле. Оптимизирующий компилятор использует, когда возможно,
 инструкции процессора для управления ситуациями в специальных случаях.
 Применение специализированных инструкций процессора к расширенной версии
 предыдущего примера разворачивания циклов
  int a[10000];
  int i;
  for(i = 0; i < 10000; i++)
   a[i] = 0;

 дает приведенный ниже ассемблерный код процессора 80x86. Он гораздо
 быстрее, чем его аналог, записанный в виде цикла или набора инструкций
 непосредственной засылки в память, имеющего соответствующую длину:
  mov  CX,10000
  mov  i,CX
  sub  AX,AX
  mov  DI,offset a
  push DS
  pop  ES
  cld
  rep  stosw

 
« Предыдущая статья   Следующая статья »