diff --git a/toolchain/lower/file_context.cpp b/toolchain/lower/file_context.cpp index a50c5aff880d..86309bb4c877 100644 --- a/toolchain/lower/file_context.cpp +++ b/toolchain/lower/file_context.cpp @@ -636,6 +636,70 @@ auto FileContext::HandleReferencedSpecificFunction( coalescer_.CreateTypeFingerprint(specific_id, llvm_type); } +auto FileContext::GetOrCreateLLVMFunction( + const FunctionTypeInfo& function_type_info, SemIR::FunctionId function_id, + SemIR::SpecificId specific_id) -> llvm::Function* { + // If this is a C++ function, tell Clang that we referenced it. + if (auto clang_decl_id = sem_ir().functions().Get(function_id).clang_decl_id; + clang_decl_id.has_value()) { + CARBON_CHECK(!specific_id.has_value(), + "Specific functions cannot have C++ definitions"); + return HandleReferencedCppFunction( + sem_ir().clang_decls().Get(clang_decl_id).key.decl->getAsFunction()); + } + + Mangler m(*this); + std::string mangled_name = m.Mangle(function_id, specific_id); + if (auto* existing = llvm_module().getFunction(mangled_name)) { + // We might have already lowered this function while lowering a different + // file. That's OK. + // TODO: Check-fail or maybe diagnose if the two LLVM functions are not + // produced by declarations of the same Carbon function. Name collisions + // between non-private members of the same library should have been + // diagnosed by check if detected, but it's not clear that check will + // always be able to see this problem. In theory, name collisions could + // also occur due to fingerprint collision. + return existing; + } + + // If this is a specific function, we may need to do additional work to + // emit its definition. + if (specific_id.has_value()) { + HandleReferencedSpecificFunction(function_id, specific_id, + function_type_info.type); + } + + // TODO: For an imported inline function, consider generating an + // `available_externally` definition. + auto linkage = specific_id.has_value() ? llvm::Function::LinkOnceODRLinkage + : llvm::Function::ExternalLinkage; + if (function_id == sem_ir().global_ctor_id()) { + // The global constructor name would collide with global constructors for + // other files in the same package, so use an internal linkage symbol. + linkage = llvm::Function::InternalLinkage; + } + + auto* llvm_function = llvm::Function::Create(function_type_info.type, linkage, + 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(function_type_info.lowered_param_pattern_ids, + llvm_function->args())) { + arg.setName(sem_ir().names().GetIRBaseName( + SemIR::GetPrettyNameFromPatternId(sem_ir(), inst_id))); + } + if (function_type_info.sret_type != nullptr) { + auto& return_arg = *llvm_function->args().begin(); + return_arg.addAttr(llvm::Attribute::getWithStructRetType( + llvm_context(), function_type_info.sret_type)); + } + + return llvm_function; +} + auto FileContext::BuildFunctionDecl(SemIR::FunctionId function_id, SemIR::SpecificId specific_id) -> std::optional { @@ -665,72 +729,8 @@ auto FileContext::BuildFunctionDecl(SemIR::FunctionId function_id, auto function_type_info = FunctionTypeInfoBuilder(this, specific_id).Build(function); - - // TODO: For an imported inline function, consider generating an - // `available_externally` definition. - auto linkage = specific_id.has_value() ? llvm::Function::LinkOnceODRLinkage - : llvm::Function::ExternalLinkage; - if (function_id == sem_ir().global_ctor_id()) { - // The global constructor name would collide with global constructors for - // other files in the same package, so use an internal linkage symbol. - linkage = llvm::Function::InternalLinkage; - } - - Mangler m(*this); - std::string mangled_name = m.Mangle(function_id, specific_id); - if (auto* existing = llvm_module().getFunction(mangled_name)) { - // We might have already lowered this function while lowering a different - // file. That's OK. - // TODO: Check-fail or maybe diagnose if the two LLVM functions are not - // produced by declarations of the same Carbon function. Name collisions - // between non-private members of the same library should have been - // diagnosed by check if detected, but it's not clear that check will always - // be able to see this problem. In theory, name collisions could also occur - // due to fingerprint collision. - return {{.type = function_type_info.type, - .di_type = function_type_info.di_type, - .lowered_param_pattern_ids = - std::move(function_type_info.lowered_param_pattern_ids), - .unused_param_pattern_ids = - std::move(function_type_info.unused_param_pattern_ids), - .llvm_function = existing}}; - } - - llvm::Function* llvm_function; - // If this is a C++ function, tell Clang that we referenced it. - if (auto clang_decl_id = sem_ir().functions().Get(function_id).clang_decl_id; - clang_decl_id.has_value()) { - CARBON_CHECK(!specific_id.has_value(), - "Specific functions cannot have C++ definitions"); - llvm_function = HandleReferencedCppFunction( - sem_ir().clang_decls().Get(clang_decl_id).key.decl->getAsFunction()); - } else { - // If this is a specific function, we may need to do additional work to emit - // its definition. - if (specific_id.has_value()) { - HandleReferencedSpecificFunction(function_id, specific_id, - function_type_info.type); - } - - llvm_function = llvm::Function::Create(function_type_info.type, linkage, - 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(function_type_info.lowered_param_pattern_ids, - llvm_function->args())) { - arg.setName(sem_ir().names().GetIRBaseName( - SemIR::GetPrettyNameFromPatternId(sem_ir(), inst_id))); - } - if (function_type_info.sret_type != nullptr) { - auto& return_arg = *llvm_function->args().begin(); - return_arg.addAttr(llvm::Attribute::getWithStructRetType( - llvm_context(), function_type_info.sret_type)); - } - } + auto* llvm_function = + GetOrCreateLLVMFunction(function_type_info, function_id, specific_id); return {{.type = function_type_info.type, .di_type = function_type_info.di_type, diff --git a/toolchain/lower/file_context.h b/toolchain/lower/file_context.h index 61d3fda806ef..669fc42398e8 100644 --- a/toolchain/lower/file_context.h +++ b/toolchain/lower/file_context.h @@ -209,6 +209,14 @@ class FileContext { class FunctionTypeInfoBuilder; + // Builds an LLVM function declaration for the given function, or returns an + // existing one if we've already lowered another declaration of the same + // function. + auto GetOrCreateLLVMFunction(const FunctionTypeInfo& function_type_info, + SemIR::FunctionId function_id, + SemIR::SpecificId specific_id) + -> llvm::Function*; + // Builds the declaration for the given function, which should then be cached // by the caller. auto BuildFunctionDecl( diff --git a/toolchain/lower/mangler.cpp b/toolchain/lower/mangler.cpp index 5d2cb6f58350..8cf42f379e59 100644 --- a/toolchain/lower/mangler.cpp +++ b/toolchain/lower/mangler.cpp @@ -8,8 +8,6 @@ #include "common/raw_string_ostream.h" #include "toolchain/base/kind_switch.h" -#include "toolchain/lower/clang_global_decl.h" -#include "toolchain/sem_ir/clang_decl.h" #include "toolchain/sem_ir/entry_point.h" #include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/pattern.h" @@ -177,15 +175,9 @@ auto Mangler::Mangle(SemIR::FunctionId function_id, return "main"; } - // TODO: We should never need to do this: Clang should emit C++ function - // declarations for us. - if (function.clang_decl_id.has_value()) { - CARBON_CHECK(function.special_function_kind != - SemIR::Function::SpecialFunctionKind::HasCppThunk, - "Shouldn't mangle C++ function that uses a thunk"); - const auto& clang_decl = sem_ir().clang_decls().Get(function.clang_decl_id); - return MangleCppClang(cast(clang_decl.key.decl)); - } + // Clang should emit C++ function declarations for us. + CARBON_CHECK(!function.clang_decl_id.has_value(), + "Shouldn't mangle C++ function"); RawStringOstream os; os << "_C"; @@ -255,12 +247,6 @@ auto Mangler::MangleGlobalVariable(SemIR::InstId pattern_id) -> std::string { return os.TakeStr(); } -auto Mangler::MangleCppClang(const clang::NamedDecl* decl) -> std::string { - return file_context_.cpp_code_generator() - .GetMangledName(CreateGlobalDecl(decl)) - .str(); -} - auto Mangler::MangleVTable(const SemIR::Class& class_info, SemIR::SpecificId specific_id) -> std::string { RawStringOstream os;