You can store the expression initializer into the global variable from main function.
// 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;
}
Although you're gonna replace the initial value by an arbitrary expression, the GlobalVariable must have an initializer to indicates it belongs to the current module. Otherwise it will expects some linkage with some existing variable.
I wrote this function thinking that your global variable declaration can be found anywhere throughout the code. However, if you're generating code from an Abstract Syntax Tree (AST), it's likely your declaration will show up before main declaration, that is, before main is inserted into the symbol table. In that case, you can create the global variable and insert it into the symbol table and create the store instruction after all analysis is done.