2009-06-30 8 views
12

Últimamente he estado buscando en LLVM, y creo que es una arquitectura bastante interesante. Sin embargo, al revisar el tutorial y el material de referencia, no veo ejemplos de cómo implementar un tipo de datos string.¿Cómo puedo implementar un tipo de datos de cadena en LLVM?

Hay una gran cantidad de documentación sobre enteros, reales y otros tipos de números, e incluso matrices, funciones y estructuras, pero no se trata de cadenas AFAIK. ¿Tendría que add a new data type al back-end? ¿Hay alguna manera de usar los tipos de datos incorporados? Cualquier idea sería apreciada.

Respuesta

14

¿Qué es un hilo? Una variedad de personajes.

¿Qué es un personaje? Un entero.

Entonces, aunque no soy experto en LLVM de ninguna manera, supongo que si, por ejemplo, quisieras representar un conjunto de caracteres de 8 bits, utilizarías una matriz de i8 (enteros de 8 bits), o un puntero a i8. Y de hecho, si tenemos un sencillo programa hola mundo C:

#include <stdio.h> 

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

y compilamos usando llvm-gcc y volcar el ensamblaje LLVM generada:

$ 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*) 

Aviso la referencia a la función pone declaró al final del archivo. En C, pone es

int puts(const char *s) 

en LLVM, es

i32 @puts(i8*) 

La correspondencia debe ser clara.

Como un lado, el LLVM generado es muy detallado aquí porque compilé sin optimizaciones. Si a su vez las de, las instrucciones innecesarias desaparecen:

$ 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, está bien, así que si quiero usar cadenas como muchos de los idiomas interpretados hoy en día (no solo una matriz, sino también la longitud, etc.) tendría que declarar que como una especie de estructura que lleva el equipaje extra con ella, ¿tendría? ser un tipo completamente nuevo en el back-end? –

+0

Sí, eso es básicamente correcto, pero no tiene que ser un nuevo tipo en el back-end. Puede usar una estructura LLVM para almacenar los datos que necesita y luego definir algunas funciones que actúan en su contenedor de cadenas. Como dice Zifre, realmente es una máquina virtual de bajo nivel. –

+0

Bien, he descubierto que puedes crear pequeñas y agradables matrices en llvm, pero no he encontrado en ninguna parte que muestre cómo reasignar estas matrices a un tamaño diferente (lo que tendré que hacer si quiero hacer una string longer) –

2

pensar acerca de cómo una cadena está representado en idiomas comunes:

  • C: un puntero a un carácter. No tienes que hacer nada especial.
  • C++: string es un objeto complejo con constructor, destructor y constructor de copia. En el interior, por lo general contiene esencialmente una cadena en C.
  • Java/C#/...: una cadena es un objeto complejo que contiene una matriz de caracteres.

El nombre de LLVM es muy auto explicativo. Realmente es de "bajo nivel". Tienes que implementar cadenas como quieras. Sería una tontería que LLVM forzara a alguien a una implementación específica.

11

[Para dar seguimiento a otras respuestas que explican lo que las cadenas son, aquí es un poco de aplicación ayuda]

Mediante la interfaz C, las llamadas que usted querrá son algo así como:

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

Gracias por esto, creo que no hay suficientes ejemplos con la API LLVM. Solo una cosa: obtengo una 'Aserción fallida: InitVal-> getType() == getType() -> getElementType() && "Tipo de inicializador debe coincidir con el tipo GlobalVariable", archivo Globals.cpp, línea 168' al hacer esto. ¿Alguna idea de por qué? –

Cuestiones relacionadas