2012-05-06 3 views
6

Je suis en train d'écrire un compilateur pour un simple langage C-like pour un cours que je prends. Ce bit de code:Quel est le problème avec ce numéro de registre LLVM?

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

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

..Je à cette compilation naïvement code binaire:

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 
} 

Cependant, opt n'accepte pas ce code.

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

Maintenant, ce que je comprends des registres temporaires anonymes, ils sont censés être numérotés de manière séquentielle à partir de 0. Ce qui est le cas ici. Mais apparemment la ligne "% 1 = sub .." aurait dû être numérotée% 2. Pourquoi donc? Est-ce que l'une des instructions entre% 0 et% 1 augmente le numéro de séquence? Ou peut-être que c'est juste une faute de suivi de quelque chose d'autre?

Répondre

9

En LLVM, tout que peut ont un nom mais ne se voit attribuer un numéro. Cela inclut également les blocs de base. Dans votre cas

lab0: 
    ret i32 1 
    br label %lab2 

définit deux blocs de base parce que chaque terminator instruction se termine un bloc de base. Cela signifie que, sur le plan conceptuel, votre code est analysé comme

lab0: 
    ret i32 1 
1: 
    br label %lab2 

et le prochain numéro gratuit après est 2.

Pour éviter des comportements étranges comme ça, je vous recommande de toujours nommer explicitement les blocs de base.

+0

Une autre façon d'interpréter la cause du problème est que vous devez éviter de vous ramifier immédiatement après une instruction return. Si votre langage a du code pour garantir le retour de tous les chemins de contrôle, il devrait être trivial de vérifier si votre branche précédente est déjà retournée ou non. Dans le cas où il est retourné, il n'est pas nécessaire d'insérer l'instruction branch (br). Vous aurez besoin d'une certaine quantité de comptabilité d'état pour rendre LLVM heureux avec vos blocs de base. –