Hi, I’m trying to get a simple AST visitor pattern going, but I’m having trouble with getting non-const globals working. When I’m talking about non-const globals I’m talking about the following:
i32 a = 1;
i32 b = 2 + a; // this would be a non-const assignment
i32 main() {}
Since LLVM doesn’t support non-const assignments to globals I’ve come up with a possible solution, which involves a global_init
function, which is called in the beginning of my main function. This function would then initialize the necessary values, but I’m having trouble getting this working. This is my related AST visitor source code:
llvm::Value* codegen_visitor::visit_declaration_node(declaration_node& node) {
// evaluate the expression to get the initial value
llvm::Value* initial_value;
// assume i32 type for now
// todo: generalize
llvm::Type* var_type = llvm::Type::getInt32Ty(m_context);
if (node.get_expression()) {
// evaluate the expression to get the initial value
initial_value = node.get_expression()->accept(*this);
}
else {
// use a default value for unassigned variables
// todo: generalize
initial_value = llvm::ConstantInt::get(var_type, 0);
}
// create a global variable
if (node.is_global()) {
llvm::GlobalVariable* global_variable = new llvm::GlobalVariable(*m_module,
var_type,
false,
llvm::GlobalValue::ExternalLinkage,
llvm::Constant::getNullValue(var_type), // default initializer
node.get_name()
);
// add the variable to the m_global_named_values map
m_global_named_values[node.get_name()] = global_variable;
// create a special global initialization function if it doesn't exist
llvm::Function* global_init_func = m_module->getFunction("_global_init");
if (!global_init_func) {
llvm::FunctionType* func_type = llvm::FunctionType::get(llvm::Type::getVoidTy(m_context), false);
global_init_func = llvm::Function::Create(func_type, llvm::Function::InternalLinkage, "_global_init", m_module.get());
llvm::BasicBlock::Create(m_context, "entry", global_init_func);
}
// store the non-constant initial value in the global variable
llvm::BasicBlock* init_block = &global_init_func->getEntryBlock();
if (!init_block->getTerminator()) {
llvm::IRBuilder<> tmp_builder(init_block);
tmp_builder.CreateStore(initial_value, global_variable);
tmp_builder.CreateRetVoid();
}
return global_variable;
}
// create a local variable
ASSERT(m_builder.GetInsertBlock(), "[codegen]: invalid insert block");
const llvm::Function* current_function = m_builder.GetInsertBlock()->getParent();
ASSERT(current_function, "[codegen]: invalid function");
// store the initial value in the memory
llvm::AllocaInst* alloca = m_builder.CreateAlloca(var_type, nullptr, node.get_name());
m_builder.CreateStore(initial_value, alloca);
m_named_values[node.get_name()] = alloca;
return initial_value;
}
llvm::Value* codegen_visitor::visit_keyword_i32_node(keyword_i32_node& node) {
return llvm::ConstantInt::get(m_context, llvm::APInt(32, node.get_value()));
}
llvm::Value* codegen_visitor::visit_operator_addition_node(operator_addition_node& node) {
llvm::Value* left = node.left->accept(*this);
llvm::Value* right = node.right->accept(*this);
return m_builder.CreateAdd(left, right, "add");
}
llvm::Value* codegen_visitor::visit_variable_node(variable_node& node) {
// local variable
if (llvm::Value* variable_value = m_named_values[node.get_name()]) {
// load the value from the memory location
const llvm::AllocaInst* alloca = llvm::dyn_cast<llvm::AllocaInst>(variable_value);
ASSERT(alloca, "[codegen]: alloca is nullptr");
return m_builder.CreateLoad(alloca->getAllocatedType(), variable_value, node.get_name());
}
// global variable
llvm::Value* pointer_to_global_variable = m_global_named_values[node.get_name()];
ASSERT(pointer_to_global_variable, "[codegen]: variable not found (" + node.get_name() + ")");
const llvm::GlobalValue* global_variable_value = llvm::dyn_cast<llvm::GlobalValue>(pointer_to_global_variable);
return m_builder.CreateLoad(global_variable_value->getValueType(), pointer_to_global_variable, node.get_name());
}
And here is my visitor accept hierarchy for the example program described above:
accepting top level node:
accepting declaration_node
accepting keyword_i32_node
accepting top level node:
accepting declaration_node
accepting operator_addition_node
accepting keyword_i32_node
accepting variable_node
// error in BasicBlock.h ->line 122 (Error reading location)
How can I get rid of the error described above?
In case you need some context here is a link to my repo.
Thanks in advance