最近我一直在寻找LLVM,我发现它是一个非常有趣的建筑。但是,查看教程和参考资料,我看不到任何有关如何实现string数据类型的示例。如何在LLVM中实现字符串数据类型?
关于整数,实数和其他数字类型,甚至数组,函数和结构还有很多文档,但AFAIK没有任何关于字符串的内容。我需要add a new data type到后端吗?有没有办法使用内置的数据类型?任何洞察力将不胜感激。
最近我一直在寻找LLVM,我发现它是一个非常有趣的建筑。但是,查看教程和参考资料,我看不到任何有关如何实现string数据类型的示例。如何在LLVM中实现字符串数据类型?
关于整数,实数和其他数字类型,甚至数组,函数和结构还有很多文档,但AFAIK没有任何关于字符串的内容。我需要add a new data type到后端吗?有没有办法使用内置的数据类型?任何洞察力将不胜感激。
什么是字符串?一组字符。
什么是角色?一个整数。因此,尽管我不是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*)
想想一个字符串是如何在共同的语言表示:
string
是一个带有构造函数,析构函数和复制构造函数的复杂对象。在内部,它通常基本上持有C字符串。LLVM的名字很自我解释。它确实是“低级”。你必须实现你想要它们的字符串。 LLVM强迫任何人进入具体的实施将是愚蠢的。
[要在其中解释字符串是什么其他的答案跟进,这里是一些实施帮助]
使用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;
}
嗯,好的 - 所以如果我想使用像现在许多解释型语言那样的字符串(不仅仅是一个数组,而是包括长度等),我将不得不声明它是一种带有额外行李的结构 - 它是否会有在后端是一个全新的类型? – 2009-06-30 21:56:53
是的,这基本上是正确的,但它不一定是后端的新类型。您可以使用LLVM结构来存储您需要的数据,然后定义一些对字符串包装器起作用的函数。像Zifre说的那样,它确实是一个低级别的虚拟机。 – 2009-06-30 22:20:46