简体   繁体   English

核心对象的 LLVM C-API 生命周期

[英]LLVM C-API Lifecycles of core objects

I've started playing with LLVM, making a pet language.我已经开始玩 LLVM,制作一种宠物语言。 I'm using the C-API.我正在使用 C-API。 I have a parser and basic AST, but I am at a bit of a road block with LLVM.我有一个解析器和基本的 AST,但我在 LLVM 方面遇到了一些障碍。

The following is a minified version of my code to illustrate my current issue:以下是我的代码的缩小版本,用于说明我当前的问题:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "llvm-c/Core.h"
#include "llvm-c/ExecutionEngine.h"
#include "llvm-c/Target.h"
#include "llvm-c/Analysis.h"
#include "llvm-c/BitWriter.h"

static LLVMModuleRef mod;
static LLVMBuilderRef builder;
static LLVMExecutionEngineRef engine;

typedef struct oper_t {
    const char * name;
    
    LLVMTypeRef args[2];
    LLVMTypeRef ret; 
    LLVMValueRef val;
} oper_t;

#define NUM_OPER 2
static oper_t oper[NUM_OPER] = {
    { .name = "function1" },
    { .name = "function2" },
};

void codegen_init(const char * filename)
{
    char *error;
 
    mod = LLVMModuleCreateWithName(filename);
    builder = LLVMCreateBuilder();
    
    error = NULL;
    LLVMVerifyModule(mod, LLVMAbortProcessAction, &error);
    if(error) printf("LLVM init Verify message \"%s\"\n", error);
    LLVMDisposeMessage(error);
    
    error = NULL;
    LLVMLinkInMCJIT();
    LLVMInitializeNativeTarget();
    LLVMInitializeNativeAsmPrinter();
    if (LLVMCreateExecutionEngineForModule(&engine, mod, &error) != 0)
    {
        fprintf(stderr, "LLVM failed to create execution engine\n");
        abort();
    }
    if(error) 
    {
        printf("LLVM Execution Engine message %s\n", error);
        LLVMDisposeMessage(error);
        exit(EXIT_FAILURE);
    }
}

int runOper(oper_t * o, long a, long b) 
{
    LLVMValueRef v, l, r;
    
    o->args[0] = LLVMInt32Type();
    o->args[1] = LLVMInt32Type();
    
    o->ret = LLVMFunctionType(LLVMInt32Type(), o->args, 2, 0);
    o->val = LLVMAddFunction(mod, o->name, o->ret);
    
    LLVMBasicBlockRef entry = LLVMAppendBasicBlock(o->val, "entry");
    LLVMPositionBuilderAtEnd(builder, entry);
    
    l = LLVMConstInt(LLVMInt32Type(), a, 0); 
    r = LLVMConstInt(LLVMInt32Type(), b, 0); 
    v = LLVMBuildAdd(builder, l, r, "add");
    
    LLVMBuildRet(builder, v);
    
    char *error = NULL;
    LLVMVerifyModule(mod, LLVMAbortProcessAction, &error);
    if(error) printf("LLVM func Verify message \"%s\"\n", error);
    LLVMDisposeMessage(error);
    
    LLVMGenericValueRef g = LLVMRunFunction(engine, o->val, 0, NULL);
    
    printf("LLVM func executed without crash\n");
    
    LLVMDeleteFunction(o->val);
    
    return (long)LLVMGenericValueToInt(g, 1);
}

int main(int argc, char const *argv[])
{
    long val;
    
    codegen_init("test");

    val = runOper(&oper[0], 3, 4);
    printf("3 + 4 is %ld\n", val);
    
    val = runOper(&oper[1], 6, 7);
    printf("6 + 7 is %ld\n", val);
}

I can compile this using the command:我可以使用以下命令编译它:

gcc test.c `llvm-config --cflags --cppflags --ldflags --libs core executionengine mcjit interpreter analysis native bitwriter --system-libs` -o test.exe

Or alternatively I've also tried:或者,我也尝试过:

gcc `llvm-config --cflags --cppflags` -c test.c
g++ test.o `llvm-config --cxxflags --ldflags --libs core executionengine mcjit interpreter analysis native bitwriter --system-libs` -o test.exe

Either way I get this result:无论哪种方式,我都会得到这个结果:

$ ./test.exe
LLVM init Verify message ""
LLVM func Verify message ""
LLVM func executed without crash
3 + 4 is 7
LLVM func Verify message ""
Segmentation fault

I've also tried using clang just for good measure.我也试过使用 clang 只是为了很好的衡量。

Clearly I am misusing the LLVM C-API.显然我在滥用 LLVM C-API。 I'm struggling mostly to get some understanding of when the API functions are safe to call, and also when can I safely free/delete the memory referenced by LLVM.我一直在努力了解何时可以安全调用 API 函数,以及何时可以安全地释放/删除 LLVM 引用的 memory。 For instance the LLVMTypeRef args[2] parameter, I see in the LLVM C-API source code for LLVMFunctionType that it is creating an ArrayRef to the args parameter.例如LLVMTypeRef args[2]参数,我在LLVMFunctionType的 LLVM C-API 源代码中看到它正在为 args 参数创建一个 ArrayRef。 This means I must hang onto the args parameter until LLVM is done with it.这意味着我必须坚持使用 args 参数,直到 LLVM 完成它。 I can't really tell when that is exactly.我真的不知道那是什么时候。 (I plan to allocate this memory on the heap) (我打算在堆上分配这个memory)

Stated simply, I'd like it if someone could not just explain what I am doing wrong in this example, but more fundamentally explain how I should figure out what I am doing wrong.简单地说,如果有人不能在这个例子中解释我做错了什么,而是更根本地解释我应该如何找出我做错了什么,我会很高兴。

The LLVM C-API docs gives a great breakdown of the functions available in the API, but I haven't found it to give much description of how API functions should be called, ie. LLVM C-API 文档对 API 中可用的函数进行了很好的细分,但我没有发现它对如何调用 API 函数给出太多描述,即。 what order is safe/expected.什么顺序是安全的/预期的。

I have also found this documentation to be helpful, as it can be easily searched for individual function prototypes.我还发现此文档很有帮助,因为可以轻松搜索单个 function 原型。 But again it gives no context or examples of how to use the C-API.但同样它没有给出如何使用 C-API 的上下文或示例。

Finally I have to reference Paul Smith's Blog , it's a bit outdated now, but is definitely the reason I got this far.最后我不得不参考Paul Smith 的博客,它现在有点过时了,但绝对是我能走到这一步的原因。

PS I don't expect everything to be spelled out for me, I just want advise on how to self-learn LLVM PS我不希望一切都为我拼写出来,我只是想建议如何自学LLVM

The basic design is most easily understood in C++: If you pass a pointer to an object y as a constructor argument, ie. C++ 中最容易理解基本设计:如果将指向object的指针作为构造函数参数传递,即。 x=new Foo(…, y, …) , then y has to live longer than x . x=new Foo(…, y, …) ,那么y的寿命必须比x长。 This also applies to wrappers such as CallInst::Create() and ConstantInt::get() , both of which take pointers to objects and return constructed objects.这也适用于诸如CallInst::Create()ConstantInt::get()之类的包装器,它们都采用指向对象的指针并返回构造的对象。

But there's more.但还有更多。 Some objects assume ownership of the constructed objects, so that you aren't permitted to delete the constructed object at all.一些对象承担了构造对象的所有权,因此您根本不允许删除构造的 object。 You are for example not allowed to delete what ConstantInt::get() returns.例如,您不能删除ConstantInt::get()返回的内容。 As a general rule, anything that's called create… in the C++ API returns something you may delete and anything called get… returns something that's owned by another LLVM object.作为一般规则,任何在 C++ API 中称为 create... 的东西都会返回您可以删除的东西,而任何称为 get... 的东西都会返回由另一个 LLVM object 拥有的东西。 I'm sure there are exceptions.我敢肯定也有例外。

You may find it helpful to build a debug version of LLVM, unless you're much smarter than I. The extra assertions are great.你可能会发现构建 LLVM 的调试版本很有帮助,除非你比我聪明得多。额外的断言很棒。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM