Видалення мертвого кодуВ теорії компіляторів ви́даленням ме́ртвого ко́ду (англ. dead code elimination, DCE) називають оптимізацію, за якої видаляється мертвий код. Ме́ртвим ко́дом (або ма́рним ко́дом) називають код, виконання якого не впливає на вивід програми, всі результати обчислення такого коду є мертвими змінними[en], тобто змінними, значення яких надалі в програмі не використовуються[1][2]. Через існування різночитань терміна мертвий код[3][4], важливо відзначити, що оптимізація видалення мертвого коду не займається видаленням недосяжного коду. Локалізацією і видаленням недосяжного коду можуть займатися прибиральник[5] або інші оптимізації, наприклад, видалення недосяжного коду[2]. Видалення непотрібного коду здатне прискорити роботу програми завдяки зменшенню кількості виконуваних у ній операцій і зменшити обсяг програми або проміжного подання[en]. ПрикладиРозглянемо такий код мовою Сі: int foo(void)
{
int a = 24;
int b;
b = a + 3; /* Марний код */
return a << 2;
}
У цьому прикладі операція додавання int foo(void)
{
int a = 24;
int b; /* Мертва змінна */
return a << 2;
}
Після видалення операції додавання, змінна int foo(void)
{
int a = 24;
return a << 2;
}
Попри те що обчислення відбувається всередині функції, його результат записується в змінну, яка перебуває в області видимості тільки цієї функції; якщо врахувати що функція безумовно повертає число 96, її можна спростити оптимізацією згортання констант так, щоб її тіло складалося тільки з операції АлгоритмиКласичний алгоритм DCE («Dead») працює на SSA-поданні і складається з двох обходів: перший обхід («Mark») позначає (маркує) всі напевне живі операції (операції виходу з процедури, введення-виведення, що змінюють глобальні змінні); другий обхід («Sweep») починається з живих операцій і йде вгору по визначеннях аргументів, позначаючи всі операції на своєму шляху живими, закінчуючи тими операціями, які не мають попередників у SSA-поданні[6]. Максимальна обчислювальна складність такого алгоритму залежить від розміру програми як O(n2)[7]. DCE може не проводити ніякого самостійного аналізу, а просто скористатися результатами аналізу активних змінних[en][8], але обчислювальна складність такого аналізу становить у гіршому випадку O(n3)[7]. Існують специфічні алгоритми, які видаляють порожні вузли в графі потоку керування, об'єднують декілька базових блоків в один тощо, але для такого аналізу потрібен побудований граф потоку керування[9]. Алгоритм «Dead» вперше опубліковано в статті «Static Single Assignment Form and the Program Dependence Graph» в журналі ACM TOPLAS[en] 1991 року[10]. Алгоритм «Clean», що працює з графом потоку керування розробив і реалізував Роб Шиллер 1992 року[11]. ЗастосуванняВидалення мертвого коду може в процесі компіляції застосовуватися кілька разів, оскільки мертвий код може не тільки існувати в програмі від початку, але й з'являтися після деяких перетворень коду програми. Наприклад, оптимізації поширення копій[en] і поширення констант часто перетворюють інструкції в марний код[1][12]. Також доводиться видаляти мертвий код, створений іншими перетвореннями в компіляторі[12]. Наприклад, класичний алгоритм оптимізації зниження вартості операцій заміщає трудомісткі операції менш трудомісткими, після чого видалення мертвого коду усуває старі операції і завершує перетворення (без ускладнення алгоритму зниження вартості)[13]. Цікаві факти
Див. такожПримітки
Література
Посилання |