Как сгенерировать код для инициализации глобальных переменных неконстантными значениями в LLVM?
В LLVM (в частности, llvmlite), как можно объявить глобальную переменную и инициализировать ее содержимое результатом произвольного (во время выполнения) выражения?
Я вижу, что могу создать объект GlobalVariable, но похоже, что initializer
аргумент ожидает Constant
, Что если я должен запустить произвольный код при запуске / загрузке, чтобы определить его значение? Куда идет этот код? Чья Builder
добавить инструкции к? Объявляю ли я специально названную функцию и / или добавляю к ней магические атрибуты, чтобы она автоматически выполнялась при загрузке модуля в память во время выполнения?
2 ответа
Это полностью зависит от вашей настройки. В C или C++ с Visual Studio функции инициализации C и C++ в конечном итоге помещаются в подраздел раздела.CRT и выполняются стандартной библиотекой времени выполнения.
Если вы компилируете без CRT и у вас есть эти функции инициализации, они не сработают, потому что среда выполнения позаботится об этом.
Исправление редактирования: кажется, @lvm.global_ctors существует.
Я не уверен, что они будут работать правильно в среде без библиотеки времени выполнения, которая помогает выполнять инициализаторы, но там у вас есть.
Вы можете сохранить инициализатор выражения в глобальной переменной из функции main.
// 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 будет вставлен в таблицу символов. В этом случае вы можете создать глобальную переменную и вставить ее в таблицу символов и создать инструкцию сохранения после завершения всего анализа.
Ссылка на ответ @keyboardsmoke:
Вы можете создать llvm.global_ctors с помощью TransformUtils.
#include "llvm/Transforms/Utils/ModuleUtils.h"
Function* globalInitFunction = llvm::getOrCreateInitFunction(*TheModule, "_VarDeclInitializations");
// add basic block to give body to _VarDeclInitializations, etc.