2009-06-30 18 views
12

Ho guardato allo LLVM ultimamente e trovo che sia un'architettura piuttosto interessante. Tuttavia, esaminando il tutorial e il materiale di riferimento, non riesco a vedere alcun esempio su come implementare un tipo di dati string.Come posso implementare un tipo di dati stringa in LLVM?

C'è molta documentazione su interi, reali e altri tipi di numeri, e persino array, funzioni e strutture, ma AFAIK non parla di stringhe. Dovrei add a new data type per il back-end? C'è un modo per utilizzare i tipi di dati integrati? Qualsiasi intuizione sarebbe apprezzata.

risposta

14

Che cos'è una stringa? Una serie di personaggi.

Che cos'è un personaggio? Un numero intero

Così mentre non sono esperto di LLVM in alcun modo, direi che se, ad esempio, si desidera rappresentare un set di caratteri a 8 bit, si utilizzerà un array di i8 (interi a 8 bit), o un puntatore a i8. E in effetti, se abbiamo un semplice programma ciao mondo C:

#include <stdio.h> 

int main() { 
     puts("Hello, world!"); 
     return 0; 
} 

E noi compiliamo utilizzando LLVM-GCC e scaricare l'assemblea LLVM generato:

$ llvm-gcc -S -emit-llvm hello.c 
$ cat hello.s 
; ModuleID = 'hello.c' 
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128" 
target triple = "x86_64-linux-gnu" 
@.str = internal constant [14 x i8] c"Hello, world!\00"   ; <[14 x i8]*> [#uses=1] 

define i32 @main() { 
entry: 
     %retval = alloca i32   ; <i32*> [#uses=2] 
     %tmp = alloca i32    ; <i32*> [#uses=2] 
     %"alloca point" = bitcast i32 0 to i32   ; <i32> [#uses=0] 
     %tmp1 = getelementptr [14 x i8]* @.str, i32 0, i64 0   ; <i8*> [#uses=1] 
     %tmp2 = call i32 @puts(i8* %tmp1) nounwind   ; <i32> [#uses=0] 
     store i32 0, i32* %tmp, align 4 
     %tmp3 = load i32* %tmp, align 4   ; <i32> [#uses=1] 
     store i32 %tmp3, i32* %retval, align 4 
     br label %return 

return:   ; preds = %entry 
     %retval4 = load i32* %retval   ; <i32> [#uses=1] 
     ret i32 %retval4 
} 

declare i32 @puts(i8*) 

Avviso il riferimento alla funzione puts dichiarato alla fine del file. In C, puts è

int puts(const char *s) 

in LLVM, è

i32 @puts(i8*) 

La corrispondenza deve essere chiaro.

Per inciso, il LLVM generato è molto dettagliato qui perché ho compilato senza ottimizzazioni. Se si attiva quelli su, le istruzioni inutili spariscono:

$ llvm-gcc -O2 -S -emit-llvm hello.c 
$ cat hello.s 
; ModuleID = 'hello.c' 
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128" 
target triple = "x86_64-linux-gnu" 
@.str = internal constant [14 x i8] c"Hello, world!\00"   ; <[14 x i8]*> [#uses=1] 

define i32 @main() nounwind { 
entry: 
     %tmp2 = tail call i32 @puts(i8* getelementptr ([14 x i8]* @.str, i32 0, i64 0)) nounwind    ; <i32> [#uses=0] 
     ret i32 0 
} 

declare i32 @puts(i8*) 
+0

Hmm, okay - quindi se voglio usare stringhe come molte delle lingue interpretate oggigiorno (non solo un array ma includendo la lunghezza, ecc.) dovrei dichiararlo come una sorta di struttura che porta con sé il bagaglio extra - avrebbe essere un tipo completamente nuovo nel back-end? –

+0

Sì, è fondamentalmente giusto, ma non deve essere un nuovo tipo nel back-end. Puoi semplicemente utilizzare una struttura LLVM per archiviare i dati necessari e quindi definire alcune funzioni che agiscono sul wrapper di stringhe. Come dice Zifre, è davvero una macchina virtuale di basso livello. –

+0

Ok, ho scoperto che è possibile creare piccoli matrici in llvm, ma non ho trovato da nessuna parte che mostra come riassegnare questi array a una dimensione diversa (che dovrò fare se voglio fare un stringa più lunga) –

2

pensare a come una stringa è rappresentata in lingue comuni:

  • C: un puntatore a un carattere. Non devi fare niente di speciale.
  • C++: string è un oggetto complesso con un costruttore, un distruttore e un costruttore di copie. All'interno, di solito contiene essenzialmente una stringa C.
  • Java/C#/...: una stringa è un oggetto complesso che contiene una matrice di caratteri.

Il nome di LLVM è molto intuitivo. È davvero "di basso livello". Devi implementare stringhe come mai vuoi che siano. Sarebbe sciocco per LLVM forzare chiunque a implementare uno specifico.

11

[a dare seguito alle altre risposte che spiegano ciò che le stringhe sono, ecco qualche aiuto implementazione]

Tramite l'interfaccia di C, le chiamate si vorrà sono qualcosa come:

LLVMValueRef llvmGenLocalStringVar(const char* data, int len) 
{ 
    LLVMValueRef glob = LLVMAddGlobal(mod, LLVMArrayType(LLVMInt8Type(), len), "string"); 

    // set as internal linkage and constant 
    LLVMSetLinkage(glob, LLVMInternalLinkage); 
    LLVMSetGlobalConstant(glob, TRUE); 

    // Initialize with string: 
    LLVMSetInitializer(glob, LLVMConstString(data, len, TRUE)); 

    return glob; 
} 
+1

Grazie per questo, ritengo che non ci siano abbastanza esempi con l'API LLVM C. Solo una cosa: ottengo un 'Asserzione fallita: InitVal-> getType() == getType() -> getElementType() &&" Il tipo di inizializzatore deve corrispondere al tipo GlobalVariable ", file Globals.cpp, riga 168' quando si esegue questa operazione. Qualche idea del perché? –

Problemi correlati