I compilerteori er dead code elimination ( DCE ) en optimering , der fjerner død kode . Død kode (også ubrugelig kode ) er en kode, hvis udførelse ikke påvirker outputtet af programmet, alle resultaterne af beregning af en sådan kode er døde variabler , det vil sige variabler, hvis værdier ikke bruges senere i program [1] [2] .
I forbindelse med den eksisterende tvetydighed af begrebet død kode [3] [4] er det vigtigt at bemærke, at optimering af fjernelse af død kode ikke beskæftiger sig med fjernelse af uopnåelig kode . Lokalisering og fjernelse af uopnåelig kode kan håndteres af skraldeopsamleren [5] eller andre optimeringer, såsom fjernelse af uopnåelig kode [2] .
Fjernelse af ubrugelig kode kan fremskynde programmet ved at reducere antallet af operationer, der udføres i det, og reducere størrelsen af programmet eller mellemliggende repræsentation .
Overvej følgende C -kode :
int foo ( ugyldig ) { int a = 24 ; int b ; b = a + 3 ; /* Ubrugelig kode */ returnere en << 2 ; }I dette eksempel er additionsoperationen b = a + 3død kode, da variablen bikke bruges i yderligere beregninger og er død fra dette tidspunkt til slutningen af proceduren. Efter at have fjernet denne instruktion får vi:
int foo ( ugyldig ) { int a = 24 ; int b ; /* Død variabel */ returnere en << 2 ; }Efter fjernelse af additionsoperationen bbliver variablen død i hele proceduren. Da det er erklæret lokalt , kan det fjernes fuldstændigt fra programmet:
int foo ( ugyldig ) { int a = 24 ; returnere en << 2 ; }Selvom evalueringen foregår inde i en funktion, skrives dens resultat til en variabel, der kun er inden for denne funktions omfang; og i betragtning af at funktionen ubetinget returnerer tallet 96, kan den forenkles ved at optimere konstant udbredelse , så dens krop kun består af operationen return 96. Og så kan compileren erstatte alle kald til den funktion med returværdien.
Den klassiske DCE ( "Dead" ) algoritme virker på SSA-repræsentationen og består af to omgåelser: den første bypass ( "Mark" ) markerer (markerer) alle åbenlyst live-operationer (procedureudgangsoperationer, input-output-operationer, der ændrer globale variabler) ; det andet sweep ( "Sweep" ) starter med live-operationer og går op i argumentdefinitionerne, og markerer alle operationer på dens vej som live, og slutter med de operationer, der ikke har nogen forgængere i SSA-form [6] . Den maksimale beregningsmæssige kompleksitet af en sådan algoritme afhænger af programmets størrelse som O(n 2 ) [7] .
DCE udfører muligvis ikke nogen uafhængig analyse, men bruger blot resultaterne af analysen af aktive variable [8] , men den beregningsmæssige kompleksitet af en sådan analyse er O(n 3 ) i værste fald [7] . Der er specifikke algoritmer, der beskæftiger sig med at fjerne tomme noder i en CFG-graf , kombinere flere grundlæggende blokke til én osv. Til en sådan analyse er der behov for en indbygget kontrolflowgraf [9] .
"Døde" -algoritmen blev først offentliggjort i artiklen "Static Single Assignment Form and the Program Dependence Graph" i ACM TOPLAS i 1991 [10] . " Clean " -algoritmen , der fungerer med en CFG-graf, blev udviklet og implementeret af Rob Schiller i 1992 [11] .
Fjernelse af død kode kan anvendes flere gange under kompileringsprocessen, da død kode er i programmet, ikke kun fordi den er indeholdt i kildekoden - nogle andre transformationer kan gøre koden død. For eksempel forvandler kopiudbredelsesoptimeringer og konstante udbredelsesoptimeringer ofte instruktioner til ubrugelig kode [1] [12] . Du skal også fjerne død kode skabt af andre transformationer i compileren [12] . For eksempel erstatter den klassiske algoritme til at reducere styrken af en operation arbejdsintensive operationer med mindre arbejdsintensive, hvorefter fjernelse af den døde kode eliminerer de gamle operationer og fuldender transformationen (uden at komplicere algoritmen til at reducere styrken ) [13] .