2012-05-06 14 views
6

Sto scrivendo un compilatore per un semplice linguaggio di tipo C per un corso che sto seguendo. Questo bit di codice:Cosa c'è di sbagliato con questo numero di registro LLVM?

int main() { 
    printInt(not(0)); 
    return 0; 
} 

int not(int n) { 
    if (n == 0) { 
     return 1; 
    } else { 
     int result = 0; 
     return result; 
    } 
} 

..Io ingenuamente compilare a questo codice binario che:

declare void @printInt(i32) 
declare void @printDouble(double) 
declare void @printString(i8*) 
declare i32 @readInt() 
declare double @readDouble() 

define i32 @main() { 
entry: 
    %0 = call i32 @not(i32 0) 
    call void @printInt(i32 %0) 
    ret i32 0 
    unreachable 
} 

define i32 @not(i32 %n_0) { 
entry: 
    %0 = icmp eq i32 %n_0, 0 
    br i1 %0, label %lab0, label %lab1 
lab0: 
    ret i32 1 
    br label %lab2 
lab1: 
    %result_0 = alloca i32 
    store i32 0, i32* %result_0 
    %1 = load i32* %result_0 
    ret i32 %1 
    br label %lab2 
lab2: 
    unreachable 
} 

Tuttavia, opt non accetta quel codice.

opt: core023.ll:25:5: error: instruction expected to be numbered '%2' 
%1 = load i32* %result_0 

Ora, da quanto ho capito di registri temporanei senza nome che si suppone di essere numerati in sequenza a partire da 0. che è il caso qui. Ma a quanto pare la riga "% 1 = sub .." avrebbe dovuto essere numerata% 2. Perché? Qualcuna delle istruzioni tra% 0 e% 1 aumenta il numero di sequenza? O forse è solo un difetto successivo di qualcos'altro?

risposta

9

In LLVM, tutto che può hanno un nome, ma non significa viene assegnato un numero. Questo include anche blocchi di base. Nel suo caso

lab0: 
    ret i32 1 
    br label %lab2 

definisce due blocchi base perché ogni terminator instruction termina un blocco di base. Ciò significa che, concettualmente, il codice viene analizzato come

lab0: 
    ret i32 1 
1: 
    br label %lab2 

e il successivo numero libero dopo che è 2.

per prevenire comportamenti strani come questo, vi consiglio sempre nominare esplicitamente blocchi di base.

+0

Un altro modo di interpretare la causa del problema è che è necessario evitare la ramificazione immediatamente dopo una dichiarazione di ritorno. Se la tua lingua ha il codice per garantire che tutti i percorsi di controllo ritornino, allora dovrebbe essere banale verificare se il tuo precedente ramo è stato restituito o meno. Nel caso in cui sia ritornato, non è necessario inserire l'istruzione branch (br). C'è una certa quantità di contabilità statale che dovrai fare per rendere LLVM felice con i tuoi blocchi di base. –

Problemi correlati