2009-06-30 14 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*) 

お知らせputs関数への参照を宣言ファイルの終わりに。 Cにおいて、LLVMで

int puts(const char *s) 

で置き、それは対応

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

うーん、大丈夫です - もし私が今日のような多くの翻訳された言語のような文字列を使用したいのであれば(配列だけではなく長さなども含む)、余分な手荷物を運ぶ何らかの構造として宣言する必要があります。バックエンドにまったく新しいタイプであること –

+0

うん、それは基本的には正しいですが、バックエンドに新しいタイプである必要はありません。 LLVM構造体を使用して必要なデータを格納し、文字列ラッパーに作用するいくつかの関数を定義することができます。 Zifre氏のように、実際には低レベルの仮想マシンです。 –

+0

さて、私はllvmで素敵な小さな配列を作ることができることを知りましたが、これらの配列を別のサイズにどのように再配置するかはわかりませんでした。 string longer) –

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

これはありがたいことですが、LLVM C APIを使用した例が十分ではないと感じています。ちょうど1つ:これを行う際にInitVal-> getType()== getType() - > getElementType()&& "初期化タイプはGlobalVariableタイプ"、ファイルGlobals.cpp、ライン168と一致しなければなりません。どんな考え? –

関連する問題