如何生成用于在 LLVM 中使用非常量值初始化全局变量的代码?

How to generate code for initializing global variables with non-const values in LLVM?

在 LLVM(特别是 llvmlite)中,如何声明全局变量并使用任意(运行time)表达式的结果初始化其内容?

我看到我可以创建一个 GlobalVariable 对象,但看起来它的 initializer 参数需要一个 Constant。如果我必须在 startup/load 时间 运行 任意代码来确定它的值怎么办?该代码去哪里了?我要向谁的 Builder 添加说明?我是否声明一个特别命名的函数 and/or 并为其添加魔法属性,以便在 运行 时间将模块加载到内存中时它自动执行?

这完全取决于您的设置。在具有 Visual Studio 的 C 或 C++ 中,C 和 C++ 初始化函数最终被放入 .CRT 部分的一个子部分,并由标准运行时库执行。

如果您在没有 CRT 的情况下进行编译并具有这些初始化函数,它们将不会触发,因为运行时会处理这些。

更正编辑:似乎 @llvm.global_ctors 存在。

我不确定这些是否会在没有有助于执行初始化程序的运行时库的环境中正确触发,但你有它。

您可以将表达式初始值设定项存储到主函数的全局变量中。

// all LLVM includes
using namespace std;

LLVMContext context;
Module* module = new Module("module_1", context);
IRBuilder<> builder(context);
SymbolTable symbolTable; // some structure to map the symbol names to the LLVM value

// ...

Value* createGlobalVar(const string& id, Type* type, Value* init) {
    Value* gv = new GlobalVariable(*module, type, false, GlobalValue::PrivateLinkage, Constant::getNullValue(type), id);

    Function* mainFunc = symbolTable.get("main");
    BasicBlock* entryBB = &(mainFunc->getEntryBlock());

    BasicBlock* currentBB = &(builder.GetInsertBlock());
    auto currentInsertPoint = builder.GetInsertPoint(); // returns an iterator
    builder.SetInsertPoint(entryBB, entryBB->begin());
    builder.CreateStore(init, gv);
    builder.SetInsertBlock(currentBB, currentInsertPoint);
    symbolTable.add(id, gv);
    return gv;
}

虽然您要用任意表达式替换初始值,但 GlobalVariable 必须有一个初始值设定项以表明它属于当前模块。否则它会期望与某些现有变量有某种联系。

我编写这个函数时认为您的全局变量声明可以在整个代码的任何地方找到。但是,如果您从抽象语法树 (AST) 生成代码,您的声明很可能会出现在 main 声明之前,也就是说,在将 main 插入符号 table 之前。在这种情况下,您可以创建全局变量并将其插入符号 table 并在完成所有分析后创建存储指令。

链接到@keyboardsmoke 的回答:

您可以使用 TransformUtils 生成 llvm.global_ctors。

#include "llvm/Transforms/Utils/ModuleUtils.h"
Function* globalInitFunction = llvm::getOrCreateInitFunction(*TheModule, "_VarDeclInitializations");
// add basic block to give body to _VarDeclInitializations, etc.