2009-06-30 79 views
12

最近我一直在寻找LLVM,我发现它是一个非常有趣的建筑。但是,查看教程和参考资料,我看不到任何有关如何实现string数据类型的示例。如何在LLVM中实现字符串数据类型?

关于整数,实数和其他数字类型,甚至数组,函数和结构还有很多文档,但AFAIK没有任何关于字符串的内容。我需要add a new data type到后端吗?有没有办法使用内置的数据类型?任何洞察力将不胜感激。

回答

14

什么是字符串?一组字符。

什么是角色?一个整数。因此,尽管我不是LLVM专家,但我想如果你想要表示一些8位字符集,那么你会使用一组i8(8位整数)的数组,或者一个指向i8的指针。事实上,如果我们有一个简单的Hello World的C程序:

#include <stdio.h> 

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

我们编译它使用LLVM-gcc和转储生成LLVM组件:

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

通知的参考放功能声明在文件的末尾。在C,看跌期权是

int puts(const char *s) 

在LLVM,它是

i32 @puts(i8*) 

的对应关系应该是清楚的。

顺便说一句,生成的LLVM在这里非常详细,因为我没有进行优化编译。如果你把这些上,不必要的指令消失:

$ 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

嗯,好的 - 所以如果我想使用像现在许多解释型语言那样的字符串(不仅仅是一个数组,而是包括长度等),我将不得不声明它是一种带有额外行李的结构 - 它是否会有在后端是一个全新的类型? – 2009-06-30 21:56:53

+0

是的,这基本上是正确的,但它不一定是后端的新类型。您可以使用LLVM结构来存储您需要的数据,然后定义一些对字符串包装器起作用的函数。像Zifre说的那样,它确实是一个低级别的虚拟机。 – 2009-06-30 22:20:46

2

想想一个字符串是如何在共同的语言表示:

  • C:指向一个字符。你不必做任何特别的事情。
  • C++:string是一个带有构造函数,析构函数和复制构造函数的复杂对象。在内部,它通常基本上持有C字符串。
  • Java/C#/ ...:字符串是一个包含字符数组的复杂对象。

LLVM的名字很自我解释。它确实是“低级”。你必须实现你想要它们的字符串。 LLVM强迫任何人进入具体的实施将是愚蠢的。

11

[要在其中解释字符串是什么其他的答案跟进,这里是一些实施帮助]

使用C接口,你要的电话是一样的东西:

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; 
}