|
|
@@ -200,25 +200,19 @@ auto FileContext::GetOrCreateFunction(SemIR::FunctionId function_id,
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
-auto FileContext::BuildFunctionDecl(SemIR::FunctionId function_id,
|
|
|
- SemIR::SpecificId specific_id)
|
|
|
- -> llvm::Function* {
|
|
|
- const auto& function = sem_ir().functions().Get(function_id);
|
|
|
-
|
|
|
- // Don't lower generic functions. Note that associated functions in interfaces
|
|
|
- // have `Self` in scope, so are implicitly generic functions.
|
|
|
- if (function.generic_id.has_value() && !specific_id.has_value()) {
|
|
|
- return nullptr;
|
|
|
- }
|
|
|
+auto FileContext::BuildFunctionTypeInfo(const SemIR::Function& function,
|
|
|
+ SemIR::SpecificId specific_id)
|
|
|
+ -> FunctionTypeInfo {
|
|
|
+ const auto return_info =
|
|
|
+ SemIR::ReturnTypeInfo::ForFunction(sem_ir(), function, specific_id);
|
|
|
|
|
|
- // Don't lower builtins.
|
|
|
- if (function.builtin_function_kind != SemIR::BuiltinFunctionKind::None) {
|
|
|
- return nullptr;
|
|
|
+ if (!return_info.is_valid()) {
|
|
|
+ // The return type has not been completed, create a trivial type instead.
|
|
|
+ return {.type =
|
|
|
+ llvm::FunctionType::get(llvm::Type::getVoidTy(llvm_context()),
|
|
|
+ /*isVarArg=*/false)};
|
|
|
}
|
|
|
|
|
|
- // TODO: Consider tracking whether the function has been used, and only
|
|
|
- // lowering it if it's needed.
|
|
|
-
|
|
|
// TODO nit: add is_symbolic() to type_id to forward to
|
|
|
// type_id.AsConstantId().is_symbolic(). Update call below too.
|
|
|
auto get_llvm_type = [&](SemIR::TypeId type_id) -> llvm::Type* {
|
|
|
@@ -228,10 +222,6 @@ auto FileContext::BuildFunctionDecl(SemIR::FunctionId function_id,
|
|
|
return GetType(SemIR::GetTypeInSpecific(sem_ir(), specific_id, type_id));
|
|
|
};
|
|
|
|
|
|
- const auto return_info =
|
|
|
- SemIR::ReturnTypeInfo::ForFunction(sem_ir(), function, specific_id);
|
|
|
- CARBON_CHECK(return_info.is_valid(), "Should not lower invalid functions.");
|
|
|
-
|
|
|
auto implicit_param_patterns =
|
|
|
sem_ir().inst_blocks().GetOrEmpty(function.implicit_param_patterns_id);
|
|
|
// TODO: Include parameters corresponding to positional parameters.
|
|
|
@@ -241,6 +231,16 @@ auto FileContext::BuildFunctionDecl(SemIR::FunctionId function_id,
|
|
|
auto* return_type = get_llvm_type(return_info.type_id);
|
|
|
|
|
|
llvm::SmallVector<llvm::Type*> param_types;
|
|
|
+ // Compute the return type to use for the LLVM function. If the initializing
|
|
|
+ // representation doesn't produce a value, set the return type to void.
|
|
|
+ // TODO: For the `Run` entry point, remap return type to i32 if it doesn't
|
|
|
+ // return a value.
|
|
|
+ llvm::Type* function_return_type =
|
|
|
+ (return_info.is_valid() &&
|
|
|
+ return_info.init_repr.kind == SemIR::InitRepr::ByCopy)
|
|
|
+ ? return_type
|
|
|
+ : llvm::Type::getVoidTy(llvm_context());
|
|
|
+
|
|
|
// TODO: Consider either storing `param_inst_ids` somewhere so that we can
|
|
|
// reuse it from `BuildFunctionDefinition` and when building calls, or factor
|
|
|
// out a mechanism to compute the mapping between parameters and arguments on
|
|
|
@@ -273,7 +273,11 @@ auto FileContext::BuildFunctionDecl(SemIR::FunctionId function_id,
|
|
|
switch (auto value_rep = SemIR::ValueRepr::ForType(sem_ir(), param_type_id);
|
|
|
value_rep.kind) {
|
|
|
case SemIR::ValueRepr::Unknown:
|
|
|
- CARBON_FATAL("Incomplete parameter type lowering function declaration");
|
|
|
+ // This parameter type is incomplete. Fallback to describing the
|
|
|
+ // function type as `void()`.
|
|
|
+ return {.type = llvm::FunctionType::get(
|
|
|
+ llvm::Type::getVoidTy(llvm_context()),
|
|
|
+ /*isVarArg=*/false)};
|
|
|
case SemIR::ValueRepr::None:
|
|
|
break;
|
|
|
case SemIR::ValueRepr::Copy:
|
|
|
@@ -285,36 +289,52 @@ auto FileContext::BuildFunctionDecl(SemIR::FunctionId function_id,
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
+ return {.type = llvm::FunctionType::get(function_return_type, param_types,
|
|
|
+ /*isVarArg=*/false),
|
|
|
+ .param_inst_ids = std::move(param_inst_ids),
|
|
|
+ .return_type = return_type,
|
|
|
+ .return_param_id = return_param_id};
|
|
|
+}
|
|
|
|
|
|
- // Compute the return type to use for the LLVM function. If the initializing
|
|
|
- // representation doesn't produce a value, set the return type to void.
|
|
|
- // TODO: For the `Run` entry point, remap return type to i32 if it doesn't
|
|
|
- // return a value.
|
|
|
- llvm::Type* function_return_type =
|
|
|
- return_info.init_repr.kind == SemIR::InitRepr::ByCopy
|
|
|
- ? return_type
|
|
|
- : llvm::Type::getVoidTy(llvm_context());
|
|
|
+auto FileContext::BuildFunctionDecl(SemIR::FunctionId function_id,
|
|
|
+ SemIR::SpecificId specific_id)
|
|
|
+ -> llvm::Function* {
|
|
|
+ const auto& function = sem_ir().functions().Get(function_id);
|
|
|
+
|
|
|
+ // Don't lower generic functions. Note that associated functions in interfaces
|
|
|
+ // have `Self` in scope, so are implicitly generic functions.
|
|
|
+ if (function.generic_id.has_value() && !specific_id.has_value()) {
|
|
|
+ return nullptr;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Don't lower builtins.
|
|
|
+ if (function.builtin_function_kind != SemIR::BuiltinFunctionKind::None) {
|
|
|
+ return nullptr;
|
|
|
+ }
|
|
|
+
|
|
|
+ // TODO: Consider tracking whether the function has been used, and only
|
|
|
+ // lowering it if it's needed.
|
|
|
+
|
|
|
+ auto function_type_info = BuildFunctionTypeInfo(function, specific_id);
|
|
|
|
|
|
Mangler m(*this);
|
|
|
std::string mangled_name = m.Mangle(function_id, specific_id);
|
|
|
|
|
|
- llvm::FunctionType* function_type = llvm::FunctionType::get(
|
|
|
- function_return_type, param_types, /*isVarArg=*/false);
|
|
|
- auto* llvm_function =
|
|
|
- llvm::Function::Create(function_type, llvm::Function::ExternalLinkage,
|
|
|
- mangled_name, llvm_module());
|
|
|
+ auto* llvm_function = llvm::Function::Create(function_type_info.type,
|
|
|
+ llvm::Function::ExternalLinkage,
|
|
|
+ mangled_name, llvm_module());
|
|
|
|
|
|
CARBON_CHECK(llvm_function->getName() == mangled_name,
|
|
|
"Mangled name collision: {0}", mangled_name);
|
|
|
|
|
|
// Set up parameters and the return slot.
|
|
|
- for (auto [inst_id, arg] :
|
|
|
- llvm::zip_equal(param_inst_ids, llvm_function->args())) {
|
|
|
+ for (auto [inst_id, arg] : llvm::zip_equal(function_type_info.param_inst_ids,
|
|
|
+ llvm_function->args())) {
|
|
|
auto name_id = SemIR::NameId::None;
|
|
|
- if (inst_id == return_param_id) {
|
|
|
+ if (inst_id == function_type_info.return_param_id) {
|
|
|
name_id = SemIR::NameId::ReturnSlot;
|
|
|
- arg.addAttr(
|
|
|
- llvm::Attribute::getWithStructRetType(llvm_context(), return_type));
|
|
|
+ arg.addAttr(llvm::Attribute::getWithStructRetType(
|
|
|
+ llvm_context(), function_type_info.return_type));
|
|
|
} else {
|
|
|
name_id = SemIR::Function::GetNameFromPatternId(sem_ir(), inst_id);
|
|
|
}
|