LLVM Global function declaration with non-const values

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

As discussed on Discord, but documenting here for others to be able to refer to, this is what @llvm.global_ctors is for.

1 Like