在 LLVM(特别是 llvmlite)中,如何声明一个全局变量并使用任意(运行时)表达式的结果初始化其内容?
我看到我可以创建一个 GlobalVariable 对象,但看起来它的initializer
参数需要一个Constant
. 如果我必须在启动/加载时运行任意代码以确定其值怎么办?那个代码去哪儿了?Builder
我应该向谁添加说明?我是否声明了一个特别命名的函数和/或向它添加魔术属性,以便在运行时将模块加载到内存中时它自动执行?
在 LLVM(特别是 llvmlite)中,如何声明一个全局变量并使用任意(运行时)表达式的结果初始化其内容?
我看到我可以创建一个 GlobalVariable 对象,但看起来它的initializer
参数需要一个Constant
. 如果我必须在启动/加载时运行任意代码以确定其值怎么办?那个代码去哪儿了?Builder
我应该向谁添加说明?我是否声明了一个特别命名的函数和/或向它添加魔术属性,以便在运行时将模块加载到内存中时它自动执行?
这完全取决于您的设置。在带有 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 插入符号表之前。在这种情况下,您可以创建全局变量并将其插入符号表并在所有分析完成后创建存储指令。
链接到@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.