Add basic lowering of generic function definitions. (#5015)

Very basic (incomplete) lowering of function definitions for generics.
This commit is contained in:
Alina Sbirlea
2025-02-27 21:17:46 +00:00
committed by GitHub
parent 0d10b5cd4c
commit 1f5e5a7b44
5 changed files with 222 additions and 30 deletions
+33 -11
View File
@@ -86,6 +86,16 @@ auto FileContext::Run() -> std::unique_ptr<llvm::Module> {
for (auto [id, _] : sem_ir_->functions().enumerate()) {
BuildFunctionDefinition(id);
}
// Lower function definitions for generics.
// This cannot be a range-based loop, as new definitions can be added
// while building other definitions.
// NOLINTNEXTLINE
for (size_t i = 0; i != specific_function_definitions_.size(); ++i) {
auto [function_id, specific_id] = specific_function_definitions_[i];
BuildFunctionDefinition(function_id, specific_id);
}
// Append `__global_init` to `llvm::global_ctors` to initialize global
// variables.
if (sem_ir().global_ctor_id().has_value()) {
@@ -185,8 +195,8 @@ auto FileContext::GetOrCreateFunction(SemIR::FunctionId function_id,
// TODO: Add this function to a list of specific functions whose definitions
// we need to emit.
specific_functions_[specific_id.index] = result;
// TODO: Should this be a pair of <function_id, specific_id> ?
specific_function_definitions_.push_back(specific_id);
// TODO: Use this to generate definitions for these functions.
specific_function_definitions_.push_back({function_id, specific_id});
return result;
}
@@ -302,7 +312,8 @@ auto FileContext::BuildFunctionDecl(SemIR::FunctionId function_id,
return llvm_function;
}
auto FileContext::BuildFunctionDefinition(SemIR::FunctionId function_id)
auto FileContext::BuildFunctionDefinition(SemIR::FunctionId function_id,
SemIR::SpecificId specific_id)
-> void {
const auto& function = sem_ir().functions().Get(function_id);
const auto& body_block_ids = function.body_block_ids;
@@ -311,14 +322,22 @@ auto FileContext::BuildFunctionDefinition(SemIR::FunctionId function_id)
return;
}
llvm::Function* llvm_function = GetFunction(function_id);
if (!llvm_function) {
// We chose not to lower this function at all, for example because it's a
// generic function.
return;
llvm::Function* llvm_function;
if (specific_id.has_value()) {
llvm_function = specific_functions_[specific_id.index];
} else {
llvm_function = GetFunction(function_id);
if (!llvm_function) {
// We chose not to lower this function at all, for example because it's a
// generic function.
return;
}
}
BuildFunctionBody(function_id, function, llvm_function);
// For non-generics we do not lower. For generics, the llvm function was
// created via GetOrCreateFunction prior to this when building the
// declaration.
BuildFunctionBody(function_id, function, llvm_function, specific_id);
}
auto FileContext::BuildFunctionBody(SemIR::FunctionId function_id,
@@ -350,12 +369,15 @@ auto FileContext::BuildFunctionBody(SemIR::FunctionId function_id,
auto lower_param = [&](SemIR::InstId param_id) {
// Get the value of the parameter from the function argument.
auto param_inst = sem_ir().insts().GetAs<SemIR::AnyParam>(param_id);
llvm::Value* param_value =
llvm::PoisonValue::get(GetType(param_inst.type_id));
llvm::Value* param_value;
if (SemIR::ValueRepr::ForType(sem_ir(), param_inst.type_id).kind !=
SemIR::ValueRepr::None) {
param_value = llvm_function->getArg(param_index);
++param_index;
} else {
param_value = llvm::PoisonValue::get(GetType(
SemIR::GetTypeInSpecific(sem_ir(), specific_id, param_inst.type_id)));
}
// The value of the parameter is the value of the argument.
function_lowering.SetLocal(param_id, param_value);