Как я могу реализовать строковый тип данных в LLVM? - PullRequest
14 голосов
/ 30 июня 2009

В последнее время я смотрю на LLVM , и я считаю, что это довольно интересная архитектура. Однако, просматривая учебник и справочный материал, я не вижу примеров того, как можно реализовать тип данных string .

Существует много документации о целых числах, вещественных числах и других типах чисел, и даже массивах, функциях и структурах, но AFAIK ничего о строках. Должен ли я добавить новый тип данных в бэкэнд? Есть ли способ использовать встроенные типы данных? Любое понимание будет оценено.

Ответы [ 5 ]

17 голосов
/ 01 июля 2009

Что такое строка? Массив символов.

Что такое персонаж? Целое число.

Так что, хотя я и не являюсь экспертом по 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*)

Обратите внимание на ссылку на функцию put, объявленную в конце файла. В С ставит это

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*)
11 голосов
/ 11 февраля 2010

[Чтобы узнать о других ответах, объясняющих, что это за строки, вот некоторая помощь по реализации]

Используя интерфейс 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;
}
2 голосов
/ 01 июля 2009

Подумайте, как строка представлена ​​на общих языках:

  • C: указатель на символ. Вам не нужно делать ничего особенного.
  • C ++: string - сложный объект с конструктором, деструктором и конструктором копирования. Внутри он обычно содержит строку C.
  • Java / C # / ...: строка представляет собой сложный объект, содержащий массив символов.

Имя LLVM самоочевидно. Это действительно "низкий уровень". Вы должны реализовать строки так, как хотите. Для LLVM было бы глупо заставлять кого-либо заниматься конкретной реализацией.

1 голос
/ 15 июля 2018

Используя C API, вместо LLVMConstString, вы можете использовать LLVMBuildGlobalString. Вот моя реализация

int main() {
    printf("Hello World, %s!\n", "there");
    return;
}

с использованием C API:

LLVMTypeRef main_type = LLVMFunctionType(LLVMVoidType(), NULL, 0, false);
LLVMValueRef main = LLVMAddFunction(mod, "main", main_type);

LLVMTypeRef param_types[] = { LLVMPointerType(LLVMInt8Type(), 0) };
LLVMTypeRef llvm_printf_type = LLVMFunctionType(LLVMInt32Type(), param_types, 0, true);
LLVMValueRef llvm_printf = LLVMAddFunction(mod, "printf", llvm_printf_type);

LLVMBasicBlockRef entry = LLVMAppendBasicBlock(main, "entry");
LLVMPositionBuilderAtEnd(builder, entry);

LLVMValueRef format = LLVMBuildGlobalStringPtr(builder, "Hello World, %s!\n", "format");
LLVMValueRef value = LLVMBuildGlobalStringPtr(builder, "there", "value");

LLVMValueRef args[] = { format, value };
LLVMBuildCall(builder, llvm_printf, args, 2, "printf");

LLVMBuildRetVoid(builder);

Я создал строки примерно так:

LLVMValueRef format = LLVMBuildGlobalStringPtr(builder, "Hello World, %s!\n", "format");
LLVMValueRef value = LLVMBuildGlobalStringPtr(builder, "there", "value");

Сгенерированный IR:

; ModuleID = 'printf.bc'
source_filename = "my_module"
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"

@format = private unnamed_addr constant [18 x i8] c"Hello World, %s!\0A\00"
@value = private unnamed_addr constant [6 x i8] c"there\00"

define void @main() {
entry:
  %printf = call i32 (...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @format, i32 0, i32 0), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @value, i32 0, i32 0))
  ret void
}

declare i32 @printf(...)
0 голосов
/ 30 июня 2019

Для тех, кто использует C ++ API LLVM, вы можете положиться на IRBuilder s CreateGlobalStringPtr:

Builder.CreateGlobalStringPtr(StringRef("Hello, world!"));

Это будет представлено как i8* в окончательной версии LLVM IR.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...