diff --git a/toolchain/check/check.cpp b/toolchain/check/check.cpp index f52a68f15c18..dc47a08b2f80 100644 --- a/toolchain/check/check.cpp +++ b/toolchain/check/check.cpp @@ -326,7 +326,8 @@ auto CheckParseTrees( llvm::MutableArrayRef units, llvm::ArrayRef tree_and_subtrees_getters, bool prelude_import, llvm::IntrusiveRefCntPtr fs, - llvm::raw_ostream* vlog_stream, bool fuzzing) -> void { + llvm::StringRef target, llvm::raw_ostream* vlog_stream, bool fuzzing) + -> void { // UnitAndImports is big due to its SmallVectors, so we default to 0 on the // stack. llvm::SmallVector unit_infos( @@ -380,7 +381,8 @@ auto CheckParseTrees( for (int check_index = 0; check_index < static_cast(ready_to_check.size()); ++check_index) { auto* unit_info = ready_to_check[check_index]; - CheckUnit(unit_info, tree_and_subtrees_getters, fs, vlog_stream).Run(); + CheckUnit(unit_info, tree_and_subtrees_getters, fs, target, vlog_stream) + .Run(); for (auto* incoming_import : unit_info->incoming_imports) { --incoming_import->imports_remaining; if (incoming_import->imports_remaining == 0) { @@ -427,7 +429,9 @@ auto CheckParseTrees( // incomplete imports. for (auto& unit_info : unit_infos) { if (unit_info.imports_remaining > 0) { - CheckUnit(&unit_info, tree_and_subtrees_getters, fs, vlog_stream).Run(); + CheckUnit(&unit_info, tree_and_subtrees_getters, fs, target, + vlog_stream) + .Run(); } } } diff --git a/toolchain/check/check.h b/toolchain/check/check.h index 1fdbd96c159a..3a64b74a2026 100644 --- a/toolchain/check/check.h +++ b/toolchain/check/check.h @@ -35,7 +35,8 @@ auto CheckParseTrees( llvm::MutableArrayRef units, llvm::ArrayRef tree_and_subtrees_getters, bool prelude_import, llvm::IntrusiveRefCntPtr fs, - llvm::raw_ostream* vlog_stream, bool fuzzing) -> void; + llvm::StringRef target, llvm::raw_ostream* vlog_stream, bool fuzzing) + -> void; } // namespace Carbon::Check diff --git a/toolchain/check/check_unit.cpp b/toolchain/check/check_unit.cpp index 05c6ba2f6335..7be853df89e0 100644 --- a/toolchain/check/check_unit.cpp +++ b/toolchain/check/check_unit.cpp @@ -53,7 +53,7 @@ static auto GetImportedIRCount(UnitAndImports* unit_and_imports) -> int { CheckUnit::CheckUnit( UnitAndImports* unit_and_imports, llvm::ArrayRef tree_and_subtrees_getters, - llvm::IntrusiveRefCntPtr fs, + llvm::IntrusiveRefCntPtr fs, llvm::StringRef target, llvm::raw_ostream* vlog_stream) : unit_and_imports_(unit_and_imports), tree_and_subtrees_getter_( @@ -61,6 +61,7 @@ CheckUnit::CheckUnit( [unit_and_imports->unit->sem_ir->check_ir_id().index]), total_ir_count_(tree_and_subtrees_getters.size()), fs_(std::move(fs)), + target_(target), vlog_stream_(vlog_stream), emitter_(&unit_and_imports_->err_tracker, tree_and_subtrees_getters, unit_and_imports_->unit->sem_ir), @@ -154,7 +155,7 @@ auto CheckUnit::InitPackageScopeAndImports() -> void { CARBON_CHECK(!cpp_ast->get()); *cpp_ast = ImportCppFiles(context_, unit_and_imports_->unit->sem_ir->filename(), - cpp_import_names, fs_); + cpp_import_names, fs_, target_); } } diff --git a/toolchain/check/check_unit.h b/toolchain/check/check_unit.h index 4be9d19af0f9..05593de9bd5c 100644 --- a/toolchain/check/check_unit.h +++ b/toolchain/check/check_unit.h @@ -124,7 +124,7 @@ class CheckUnit { UnitAndImports* unit_and_imports, llvm::ArrayRef tree_and_subtrees_getters, llvm::IntrusiveRefCntPtr fs, - llvm::raw_ostream* vlog_stream); + llvm::StringRef target, llvm::raw_ostream* vlog_stream); // Produces and checks the IR for the provided unit. auto Run() -> void; @@ -191,6 +191,7 @@ class CheckUnit { // The number of IRs being checked in total. int total_ir_count_; llvm::IntrusiveRefCntPtr fs_; + llvm::StringRef target_; llvm::raw_ostream* vlog_stream_; DiagnosticEmitter emitter_; diff --git a/toolchain/check/import_cpp.cpp b/toolchain/check/import_cpp.cpp index 73835789ae7f..b0b13fa9dcfd 100644 --- a/toolchain/check/import_cpp.cpp +++ b/toolchain/check/import_cpp.cpp @@ -179,7 +179,8 @@ class CarbonClangDiagnosticConsumer : public clang::DiagnosticConsumer { // TODO: Consider to always have a (non-null) AST. static auto GenerateAst(Context& context, llvm::StringRef importing_file_path, llvm::ArrayRef imports, - llvm::IntrusiveRefCntPtr fs) + llvm::IntrusiveRefCntPtr fs, + llvm::StringRef target) -> std::pair, bool> { // TODO: Use all import locations by referring each Clang diagnostic to the // relevant import. @@ -190,9 +191,12 @@ static auto GenerateAst(Context& context, llvm::StringRef importing_file_path, // TODO: Share compilation flags with ClangRunner. auto ast = clang::tooling::buildASTFromCodeWithArgs( GenerateCppIncludesHeaderCode(context, imports), - // Parse C++ (and not C) - {"-x", "c++"}, (importing_file_path + ".generated.cpp_imports.h").str(), - "clang-tool", std::make_shared(), + // Parse C++ (and not C). + {"-x", "c++", + // Propagate the target to Clang. + "-target", target.str()}, + (importing_file_path + ".generated.cpp_imports.h").str(), "clang-tool", + std::make_shared(), clang::tooling::getClangStripDependencyFileAdjuster(), clang::tooling::FileContentMappings(), &diagnostics_consumer, fs); // Remove link to the diagnostics consumer before its deletion. @@ -235,8 +239,8 @@ static auto AddNamespace(Context& context, PackageNameId cpp_package_id, auto ImportCppFiles(Context& context, llvm::StringRef importing_file_path, llvm::ArrayRef imports, - llvm::IntrusiveRefCntPtr fs) - -> std::unique_ptr { + llvm::IntrusiveRefCntPtr fs, + llvm::StringRef target) -> std::unique_ptr { if (imports.empty()) { return nullptr; } @@ -244,7 +248,7 @@ auto ImportCppFiles(Context& context, llvm::StringRef importing_file_path, CARBON_CHECK(!context.sem_ir().cpp_ast()); auto [generated_ast, ast_has_error] = - GenerateAst(context, importing_file_path, imports, fs); + GenerateAst(context, importing_file_path, imports, fs, target); PackageNameId package_id = imports.front().package_id; CARBON_CHECK( @@ -422,7 +426,7 @@ static auto GetReturnType(Context& context, SemIR::LocId loc_id, static auto ImportFunctionDecl(Context& context, SemIR::LocId loc_id, SemIR::NameScopeId scope_id, SemIR::NameId name_id, - const clang::FunctionDecl* clang_decl) + clang::FunctionDecl* clang_decl) -> SemIR::InstId { if (clang_decl->isVariadic()) { context.TODO(loc_id, "Unsupported: Variadic function"); @@ -603,7 +607,7 @@ static auto ImportCXXRecordDecl(Context& context, SemIR::LocId loc_id, static auto ImportNameDecl(Context& context, SemIR::LocId loc_id, SemIR::NameScopeId scope_id, SemIR::NameId name_id, clang::NamedDecl* clang_decl) -> SemIR::InstId { - if (const auto* clang_function_decl = + if (auto* clang_function_decl = clang::dyn_cast(clang_decl)) { return ImportFunctionDecl(context, loc_id, scope_id, name_id, clang_function_decl); diff --git a/toolchain/check/import_cpp.h b/toolchain/check/import_cpp.h index b9303c6569fe..df950be88442 100644 --- a/toolchain/check/import_cpp.h +++ b/toolchain/check/import_cpp.h @@ -16,8 +16,8 @@ namespace Carbon::Check { // and warnings. If successful, adds a `Cpp` namespace and returns the AST. auto ImportCppFiles(Context& context, llvm::StringRef importing_file_path, llvm::ArrayRef imports, - llvm::IntrusiveRefCntPtr fs) - -> std::unique_ptr; + llvm::IntrusiveRefCntPtr fs, + llvm::StringRef target) -> std::unique_ptr; // Looks up the given name in the Clang AST generated when importing C++ code. // If successful, generates the instruction and returns the new `InstId`. diff --git a/toolchain/driver/compile_subcommand.cpp b/toolchain/driver/compile_subcommand.cpp index 56a25510d74f..5d4ec46cbc21 100644 --- a/toolchain/driver/compile_subcommand.cpp +++ b/toolchain/driver/compile_subcommand.cpp @@ -712,9 +712,9 @@ auto CompilationUnit::RunLower() -> void { if (options_->include_debug_info) { subtrees = cache_->tree_and_subtrees_getters(); } - module_ = - Lower::LowerToLLVM(*llvm_context_, subtrees, input_filename_, *sem_ir_, - sem_ir_->cpp_ast(), &inst_namer, vlog_stream_); + module_ = Lower::LowerToLLVM(*llvm_context_, driver_env_->fs, subtrees, + input_filename_, *sem_ir_, sem_ir_->cpp_ast(), + &inst_namer, vlog_stream_); }); if (vlog_stream_) { CARBON_VLOG("*** llvm::Module ***\n"); @@ -964,6 +964,7 @@ auto CompileSubcommand::Run(DriverEnv& driver_env) -> DriverResult { CARBON_VLOG_TO(driver_env.vlog_stream, "*** Check::CheckParseTrees ***\n"); Check::CheckParseTrees(check_units, cache.tree_and_subtrees_getters(), options_.prelude_import, driver_env.fs, + options_.codegen_options.target, driver_env.vlog_stream, driver_env.fuzzing); CARBON_VLOG_TO(driver_env.vlog_stream, "*** Check::CheckParseTrees done ***\n"); diff --git a/toolchain/language_server/BUILD b/toolchain/language_server/BUILD index 786d87b8c900..1b62ceb68193 100644 --- a/toolchain/language_server/BUILD +++ b/toolchain/language_server/BUILD @@ -45,6 +45,7 @@ cc_library( "//toolchain/sem_ir:file", "//toolchain/source:source_buffer", "@llvm-project//clang-tools-extra/clangd:ClangDaemon", + "@llvm-project//llvm:TargetParser", ], ) diff --git a/toolchain/language_server/context.cpp b/toolchain/language_server/context.cpp index 3de116b8105a..204a7fe5b28d 100644 --- a/toolchain/language_server/context.cpp +++ b/toolchain/language_server/context.cpp @@ -10,6 +10,7 @@ #include "common/check.h" #include "common/raw_string_ostream.h" +#include "llvm/TargetParser/Host.h" #include "toolchain/base/shared_value_stores.h" #include "toolchain/check/check.h" #include "toolchain/diagnostics/diagnostic.h" @@ -152,7 +153,8 @@ auto Context::File::SetText(Context& context, std::optional version, // TODO: Include the prelude. Check::CheckParseTrees( units, llvm::ArrayRef(getter), - /*prelude_import=*/false, fs, context.vlog_stream(), /*fuzzing=*/false); + /*prelude_import=*/false, fs, llvm::sys::getDefaultTargetTriple(), + context.vlog_stream(), /*fuzzing=*/false); // Note we need to publish diagnostics even when empty. // TODO: Consider caching previously published diagnostics and only publishing diff --git a/toolchain/lower/BUILD b/toolchain/lower/BUILD index bdee7797ec38..44676d59181a 100644 --- a/toolchain/lower/BUILD +++ b/toolchain/lower/BUILD @@ -57,7 +57,11 @@ cc_library( "//toolchain/sem_ir:inst_namer", "//toolchain/sem_ir:typed_insts", "@llvm-project//clang:ast", + "@llvm-project//clang:basic", + "@llvm-project//clang:codegen", + "@llvm-project//clang:lex", "@llvm-project//llvm:Core", + "@llvm-project//llvm:Linker", "@llvm-project//llvm:Support", "@llvm-project//llvm:TransformUtils", ], diff --git a/toolchain/lower/file_context.cpp b/toolchain/lower/file_context.cpp index b4bdbba7e985..b09845382c64 100644 --- a/toolchain/lower/file_context.cpp +++ b/toolchain/lower/file_context.cpp @@ -9,10 +9,12 @@ #include #include +#include "clang/CodeGen/ModuleBuilder.h" #include "common/check.h" #include "common/vlog.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Sequence.h" +#include "llvm/Linker/Linker.h" #include "llvm/Transforms/Utils/ModuleUtils.h" #include "toolchain/base/kind_switch.h" #include "toolchain/lower/constant.h" @@ -33,6 +35,7 @@ namespace Carbon::Lower { FileContext::FileContext( llvm::LLVMContext& llvm_context, + llvm::IntrusiveRefCntPtr fs, std::optional> tree_and_subtrees_getters_for_debug_info, llvm::StringRef module_name, const SemIR::File& sem_ir, @@ -40,6 +43,7 @@ FileContext::FileContext( llvm::raw_ostream* vlog_stream) : llvm_context_(&llvm_context), llvm_module_(std::make_unique(module_name, llvm_context)), + fs_(std::move(fs)), di_builder_(*llvm_module_), di_compile_unit_( tree_and_subtrees_getters_for_debug_info @@ -51,6 +55,8 @@ FileContext::FileContext( cpp_ast_(cpp_ast), inst_namer_(inst_namer), vlog_stream_(vlog_stream) { + // Initialization that relies on invariants of the class. + cpp_code_generator_ = CreateCppCodeGenerator(); CARBON_CHECK(!sem_ir.has_errors(), "Generating LLVM IR from invalid SemIR::File is unsupported."); } @@ -59,6 +65,10 @@ FileContext::FileContext( auto FileContext::Run() -> std::unique_ptr { CARBON_CHECK(llvm_module_, "Run can only be called once."); + if (cpp_code_generator_) { + cpp_code_generator_->Initialize(cpp_ast()->getASTContext()); + } + // Lower all types that were required to be complete. types_.resize(sem_ir_->insts().size()); for (auto type_id : sem_ir_->types().complete_types()) { @@ -124,6 +134,15 @@ auto FileContext::Run() -> std::unique_ptr { /*Priority=*/0); } + if (cpp_code_generator_) { + cpp_code_generator_->HandleTranslationUnit(cpp_ast()->getASTContext()); + bool link_error = llvm::Linker::linkModules( + /*Dest=*/*llvm_module_, + /*Src=*/std::unique_ptr( + cpp_code_generator_->ReleaseModule())); + CARBON_CHECK(!link_error); + } + return std::move(llvm_module_); } @@ -146,6 +165,21 @@ auto FileContext::BuildDICompileUnit(llvm::StringRef module_name, /*RV=*/0); } +auto FileContext::CreateCppCodeGenerator() + -> std::unique_ptr { + if (!cpp_ast()) { + return nullptr; + } + + RawStringOstream clang_module_name_stream; + clang_module_name_stream << llvm_module_->getName() << ".clang"; + + return std::unique_ptr(clang::CreateLLVMCodeGen( + cpp_ast()->getASTContext().getDiagnostics(), + clang_module_name_stream.TakeStr(), fs_, cpp_header_search_options_, + cpp_preprocessor_options_, cpp_code_gen_options_, *llvm_context_)); +} + auto FileContext::GetGlobal(SemIR::InstId inst_id, SemIR::SpecificId specific_id) -> llvm::Value* { auto const_id = GetConstantValueInSpecific(sem_ir(), specific_id, inst_id); @@ -367,7 +401,8 @@ auto FileContext::BuildFunctionDefinition(SemIR::FunctionId function_id, -> void { const auto& function = sem_ir().functions().Get(function_id); const auto& body_block_ids = function.body_block_ids; - if (body_block_ids.empty()) { + if (body_block_ids.empty() && + (!function.cpp_decl || !function.cpp_decl->isDefined())) { // Function is probably defined in another file; not an error. return; } @@ -396,6 +431,29 @@ auto FileContext::BuildFunctionBody(SemIR::FunctionId function_id, SemIR::SpecificId specific_id) -> void { const auto& body_block_ids = function.body_block_ids; CARBON_DCHECK(llvm_function, "LLVM Function not found when lowering body."); + + if (function.cpp_decl) { + // TODO: To support recursive inline functions, collect all calls to + // `HandleTopLevelDecl()` in a custom `ASTConsumer` configured in the + // `ASTUnit`, and replay them in lowering in the `CodeGenerator`. See + // https://discord.com/channels/655572317891461132/768530752592805919/1370509111585935443 + clang::FunctionDecl* cpp_def = function.cpp_decl->getDefinition(); + CARBON_DCHECK(cpp_def, "No Clang function body found during lowering"); + + // Create the LLVM function (`CodeGenModule::GetOrCreateLLVMFunction()`) so + // that code generation (`CodeGenModule::EmitGlobal()`) would see this + // function name (`CodeGenModule::getMangledName()`), and will generate its + // definition. + llvm::Constant* function_address = + cpp_code_generator_->GetAddrOfGlobal(clang::GlobalDecl(cpp_def), + /*isForDefinition=*/false); + CARBON_DCHECK(function_address); + + // Emit the function code. + cpp_code_generator_->HandleTopLevelDecl(clang::DeclGroupRef(cpp_def)); + return; + } + CARBON_DCHECK(!body_block_ids.empty(), "No function body blocks found during lowering."); diff --git a/toolchain/lower/file_context.h b/toolchain/lower/file_context.h index 3d2dcc0b370a..edbf593a8437 100644 --- a/toolchain/lower/file_context.h +++ b/toolchain/lower/file_context.h @@ -5,6 +5,9 @@ #ifndef CARBON_TOOLCHAIN_LOWER_FILE_CONTEXT_H_ #define CARBON_TOOLCHAIN_LOWER_FILE_CONTEXT_H_ +#include "clang/Basic/CodeGenOptions.h" +#include "clang/CodeGen/ModuleBuilder.h" +#include "clang/Lex/PreprocessorOptions.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DIBuilder.h" #include "llvm/IR/LLVMContext.h" @@ -30,6 +33,7 @@ class FileContext { explicit FileContext( llvm::LLVMContext& llvm_context, + llvm::IntrusiveRefCntPtr fs, std::optional> tree_and_subtrees_getters_for_debug_info, llvm::StringRef module_name, const SemIR::File& sem_ir, @@ -45,6 +49,10 @@ class FileContext { llvm::Module& llvm_module, llvm::DIBuilder& di_builder) -> llvm::DICompileUnit*; + // Creates the Clang `CodeGenerator` to generate LLVM module from imported C++ + // code. Returns null when not importing C++. + auto CreateCppCodeGenerator() -> std::unique_ptr; + // Gets a callable's function. Returns nullptr for a builtin. auto GetFunction(SemIR::FunctionId function_id) -> llvm::Function* { return functions_[function_id.index]; @@ -161,6 +169,9 @@ class FileContext { llvm::LLVMContext* llvm_context_; std::unique_ptr llvm_module_; + // The filesystem for source code. + llvm::IntrusiveRefCntPtr fs_; + // State for building the LLVM IR debug info metadata. llvm::DIBuilder di_builder_; @@ -178,6 +189,16 @@ class FileContext { // modifies it. clang::ASTUnit* cpp_ast_; + // The options used to create the Clang Code Generator. + clang::HeaderSearchOptions cpp_header_search_options_; + clang::PreprocessorOptions cpp_preprocessor_options_; + clang::CodeGenOptions cpp_code_gen_options_; + + // The Clang `CodeGenerator` to generate LLVM module from imported C++ + // code. Should be initialized using `CreateCppCodeGenerator()`. Can be null + // if no C++ code is imported. + std::unique_ptr cpp_code_generator_; + // The instruction namer, if given. const SemIR::InstNamer* const inst_namer_; diff --git a/toolchain/lower/lower.cpp b/toolchain/lower/lower.cpp index 6956d42b0b2f..25b17d7fb0a3 100644 --- a/toolchain/lower/lower.cpp +++ b/toolchain/lower/lower.cpp @@ -12,14 +12,16 @@ namespace Carbon::Lower { auto LowerToLLVM(llvm::LLVMContext& llvm_context, + llvm::IntrusiveRefCntPtr fs, std::optional> tree_and_subtrees_getters_for_debug_info, llvm::StringRef module_name, const SemIR::File& sem_ir, clang::ASTUnit* cpp_ast, const SemIR::InstNamer* inst_namer, llvm::raw_ostream* vlog_stream) -> std::unique_ptr { - FileContext context(llvm_context, tree_and_subtrees_getters_for_debug_info, - module_name, sem_ir, cpp_ast, inst_namer, vlog_stream); + FileContext context(llvm_context, std::move(fs), + tree_and_subtrees_getters_for_debug_info, module_name, + sem_ir, cpp_ast, inst_namer, vlog_stream); return context.Run(); } diff --git a/toolchain/lower/lower.h b/toolchain/lower/lower.h index 90aacdc7d12d..48f356805db1 100644 --- a/toolchain/lower/lower.h +++ b/toolchain/lower/lower.h @@ -16,6 +16,7 @@ namespace Carbon::Lower { // Lowers SemIR to LLVM IR. auto LowerToLLVM(llvm::LLVMContext& llvm_context, + llvm::IntrusiveRefCntPtr fs, std::optional> tree_and_subtrees_getters_for_debug_info, llvm::StringRef module_name, const SemIR::File& sem_ir, diff --git a/toolchain/lower/testdata/interop/cpp/function_decl.carbon b/toolchain/lower/testdata/interop/cpp/function_decl.carbon index f8480d3d07f5..61ad00431ec9 100644 --- a/toolchain/lower/testdata/interop/cpp/function_decl.carbon +++ b/toolchain/lower/testdata/interop/cpp/function_decl.carbon @@ -2,6 +2,8 @@ // Exceptions. See /LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // +// ARGS: compile --phase=lower --dump-llvm-ir --exclude-dump-file-prefix=%{core_package_dir} --target=x86_64-unknown-linux-gnu %s +// // AUTOUPDATE // TIP: To test this file alone, run: // TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/lower/testdata/interop/cpp/function_decl.carbon @@ -34,60 +36,284 @@ fn MyF() { inline void foo() {} -// --- todo_import_inline_function_decl.carbon +// --- import_inline_function_decl.carbon library "[[@TEST_NAME]]"; import Cpp library "inline_function_decl.h"; fn MyF() { - // TODO: This should generate the definition of the inline function `foo()`. Cpp.foo(); } +// ============================================================================ +// inline_used_function_decl +// ============================================================================ + +// --- inline_used_function_decl.h + +inline __attribute__((used)) void foo() {} + +// --- import_inline_used_function_decl.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "inline_used_function_decl.h"; + +fn MyF() { + Cpp.foo(); +} + +// ============================================================================ +// multiple_inline_function_decls +// ============================================================================ + +// --- multiple_inline_function_decls.h + +inline void foo1() {} +inline void foo2() {} +inline void foo3() {} + +// --- import_multiple_inline_function_decls.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "multiple_inline_function_decls.h"; + +fn MyF() { + Cpp.foo1(); + Cpp.foo2(); + Cpp.foo3(); +} + +// ============================================================================ +// inline_recursive_function_decl +// ============================================================================ + +// --- inline_recursive_function_decl.h + +inline void foo1() {} +inline void foo2() { foo1(); } + +// --- todo_import_inline_recursive_function_decl.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "inline_recursive_function_decl.h"; + +fn MyF() { + // TODO: This should generate the definition of the inline function `foo1()`. + Cpp.foo2(); +} + // CHECK:STDOUT: ; ModuleID = 'import_function_decl.carbon' // CHECK:STDOUT: source_filename = "import_function_decl.carbon" +// CHECK:STDOUT: target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" +// CHECK:STDOUT: target triple = "x86_64-unknown-linux-gnu" // CHECK:STDOUT: -// CHECK:STDOUT: define void @_CMyF.Main() !dbg !4 { +// CHECK:STDOUT: define void @_CMyF.Main() !dbg !8 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: call void @_Z3foov(), !dbg !7 -// CHECK:STDOUT: ret void, !dbg !8 +// CHECK:STDOUT: call void @_Z3foov(), !dbg !11 +// CHECK:STDOUT: ret void, !dbg !12 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: declare void @_Z3foov() // CHECK:STDOUT: -// CHECK:STDOUT: !llvm.module.flags = !{!0, !1} -// CHECK:STDOUT: !llvm.dbg.cu = !{!2} +// CHECK:STDOUT: !llvm.module.flags = !{!0, !1, !2, !3, !4} +// CHECK:STDOUT: !llvm.dbg.cu = !{!5} +// CHECK:STDOUT: !llvm.ident = !{!7} // CHECK:STDOUT: // CHECK:STDOUT: !0 = !{i32 7, !"Dwarf Version", i32 5} // CHECK:STDOUT: !1 = !{i32 2, !"Debug Info Version", i32 3} -// CHECK:STDOUT: !2 = distinct !DICompileUnit(language: DW_LANG_C, file: !3, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) -// CHECK:STDOUT: !3 = !DIFile(filename: "import_function_decl.carbon", directory: "") -// CHECK:STDOUT: !4 = distinct !DISubprogram(name: "MyF", linkageName: "_CMyF.Main", scope: null, file: !3, line: 6, type: !5, spFlags: DISPFlagDefinition, unit: !2) -// CHECK:STDOUT: !5 = !DISubroutineType(types: !6) -// CHECK:STDOUT: !6 = !{} -// CHECK:STDOUT: !7 = !DILocation(line: 7, column: 3, scope: !4) -// CHECK:STDOUT: !8 = !DILocation(line: 6, column: 1, scope: !4) -// CHECK:STDOUT: ; ModuleID = 'todo_import_inline_function_decl.carbon' -// CHECK:STDOUT: source_filename = "todo_import_inline_function_decl.carbon" +// CHECK:STDOUT: !2 = !{i32 1, !"wchar_size", i32 4} +// CHECK:STDOUT: !3 = !{i32 8, !"PIC Level", i32 0} +// CHECK:STDOUT: !4 = !{i32 7, !"PIE Level", i32 2} +// CHECK:STDOUT: !5 = distinct !DICompileUnit(language: DW_LANG_C, file: !6, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) +// CHECK:STDOUT: !6 = !DIFile(filename: "import_function_decl.carbon", directory: "") +// CHECK:STDOUT: !7 = !{!"clang version 21.0.0git"} +// CHECK:STDOUT: !8 = distinct !DISubprogram(name: "MyF", linkageName: "_CMyF.Main", scope: null, file: !6, line: 6, type: !9, spFlags: DISPFlagDefinition, unit: !5) +// CHECK:STDOUT: !9 = !DISubroutineType(types: !10) +// CHECK:STDOUT: !10 = !{} +// CHECK:STDOUT: !11 = !DILocation(line: 7, column: 3, scope: !8) +// CHECK:STDOUT: !12 = !DILocation(line: 6, column: 1, scope: !8) +// CHECK:STDOUT: ; ModuleID = 'import_inline_function_decl.carbon' +// CHECK:STDOUT: source_filename = "import_inline_function_decl.carbon" +// CHECK:STDOUT: target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" +// CHECK:STDOUT: target triple = "x86_64-unknown-linux-gnu" // CHECK:STDOUT: -// CHECK:STDOUT: define void @_CMyF.Main() !dbg !4 { +// CHECK:STDOUT: $_Z3foov = comdat any +// CHECK:STDOUT: +// CHECK:STDOUT: define void @_CMyF.Main() !dbg !8 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: call void @_Z3foov(), !dbg !7 -// CHECK:STDOUT: ret void, !dbg !8 +// CHECK:STDOUT: call void @_Z3foov(), !dbg !11 +// CHECK:STDOUT: ret void, !dbg !12 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: declare void @_Z3foov() +// CHECK:STDOUT: ; Function Attrs: mustprogress noinline nounwind optnone +// CHECK:STDOUT: define linkonce_odr dso_local void @_Z3foov() #0 comdat { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: ret void +// CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: !llvm.module.flags = !{!0, !1} -// CHECK:STDOUT: !llvm.dbg.cu = !{!2} +// CHECK:STDOUT: attributes #0 = { mustprogress noinline nounwind optnone "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="0" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +// CHECK:STDOUT: +// CHECK:STDOUT: !llvm.module.flags = !{!0, !1, !2, !3, !4} +// CHECK:STDOUT: !llvm.dbg.cu = !{!5} +// CHECK:STDOUT: !llvm.ident = !{!7} // CHECK:STDOUT: // CHECK:STDOUT: !0 = !{i32 7, !"Dwarf Version", i32 5} // CHECK:STDOUT: !1 = !{i32 2, !"Debug Info Version", i32 3} -// CHECK:STDOUT: !2 = distinct !DICompileUnit(language: DW_LANG_C, file: !3, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) -// CHECK:STDOUT: !3 = !DIFile(filename: "todo_import_inline_function_decl.carbon", directory: "") -// CHECK:STDOUT: !4 = distinct !DISubprogram(name: "MyF", linkageName: "_CMyF.Main", scope: null, file: !3, line: 6, type: !5, spFlags: DISPFlagDefinition, unit: !2) -// CHECK:STDOUT: !5 = !DISubroutineType(types: !6) -// CHECK:STDOUT: !6 = !{} -// CHECK:STDOUT: !7 = !DILocation(line: 8, column: 3, scope: !4) -// CHECK:STDOUT: !8 = !DILocation(line: 6, column: 1, scope: !4) +// CHECK:STDOUT: !2 = !{i32 1, !"wchar_size", i32 4} +// CHECK:STDOUT: !3 = !{i32 8, !"PIC Level", i32 0} +// CHECK:STDOUT: !4 = !{i32 7, !"PIE Level", i32 2} +// CHECK:STDOUT: !5 = distinct !DICompileUnit(language: DW_LANG_C, file: !6, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) +// CHECK:STDOUT: !6 = !DIFile(filename: "import_inline_function_decl.carbon", directory: "") +// CHECK:STDOUT: !7 = !{!"clang version 21.0.0git"} +// CHECK:STDOUT: !8 = distinct !DISubprogram(name: "MyF", linkageName: "_CMyF.Main", scope: null, file: !6, line: 6, type: !9, spFlags: DISPFlagDefinition, unit: !5) +// CHECK:STDOUT: !9 = !DISubroutineType(types: !10) +// CHECK:STDOUT: !10 = !{} +// CHECK:STDOUT: !11 = !DILocation(line: 7, column: 3, scope: !8) +// CHECK:STDOUT: !12 = !DILocation(line: 6, column: 1, scope: !8) +// CHECK:STDOUT: ; ModuleID = 'import_inline_used_function_decl.carbon' +// CHECK:STDOUT: source_filename = "import_inline_used_function_decl.carbon" +// CHECK:STDOUT: target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" +// CHECK:STDOUT: target triple = "x86_64-unknown-linux-gnu" +// CHECK:STDOUT: +// CHECK:STDOUT: $_Z3foov = comdat any +// CHECK:STDOUT: +// CHECK:STDOUT: @llvm.compiler.used = appending global [1 x ptr] [ptr @_Z3foov], section "llvm.metadata" +// CHECK:STDOUT: +// CHECK:STDOUT: define void @_CMyF.Main() !dbg !8 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: call void @_Z3foov(), !dbg !11 +// CHECK:STDOUT: ret void, !dbg !12 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: mustprogress noinline nounwind optnone +// CHECK:STDOUT: define linkonce_odr dso_local void @_Z3foov() #0 comdat { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: ret void +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; uselistorder directives +// CHECK:STDOUT: uselistorder ptr @_Z3foov, { 1, 0 } +// CHECK:STDOUT: +// CHECK:STDOUT: attributes #0 = { mustprogress noinline nounwind optnone "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="0" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +// CHECK:STDOUT: +// CHECK:STDOUT: !llvm.module.flags = !{!0, !1, !2, !3, !4} +// CHECK:STDOUT: !llvm.dbg.cu = !{!5} +// CHECK:STDOUT: !llvm.ident = !{!7} +// CHECK:STDOUT: +// CHECK:STDOUT: !0 = !{i32 7, !"Dwarf Version", i32 5} +// CHECK:STDOUT: !1 = !{i32 2, !"Debug Info Version", i32 3} +// CHECK:STDOUT: !2 = !{i32 1, !"wchar_size", i32 4} +// CHECK:STDOUT: !3 = !{i32 8, !"PIC Level", i32 0} +// CHECK:STDOUT: !4 = !{i32 7, !"PIE Level", i32 2} +// CHECK:STDOUT: !5 = distinct !DICompileUnit(language: DW_LANG_C, file: !6, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) +// CHECK:STDOUT: !6 = !DIFile(filename: "import_inline_used_function_decl.carbon", directory: "") +// CHECK:STDOUT: !7 = !{!"clang version 21.0.0git"} +// CHECK:STDOUT: !8 = distinct !DISubprogram(name: "MyF", linkageName: "_CMyF.Main", scope: null, file: !6, line: 6, type: !9, spFlags: DISPFlagDefinition, unit: !5) +// CHECK:STDOUT: !9 = !DISubroutineType(types: !10) +// CHECK:STDOUT: !10 = !{} +// CHECK:STDOUT: !11 = !DILocation(line: 7, column: 3, scope: !8) +// CHECK:STDOUT: !12 = !DILocation(line: 6, column: 1, scope: !8) +// CHECK:STDOUT: ; ModuleID = 'import_multiple_inline_function_decls.carbon' +// CHECK:STDOUT: source_filename = "import_multiple_inline_function_decls.carbon" +// CHECK:STDOUT: target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" +// CHECK:STDOUT: target triple = "x86_64-unknown-linux-gnu" +// CHECK:STDOUT: +// CHECK:STDOUT: $_Z4foo1v = comdat any +// CHECK:STDOUT: +// CHECK:STDOUT: $_Z4foo2v = comdat any +// CHECK:STDOUT: +// CHECK:STDOUT: $_Z4foo3v = comdat any +// CHECK:STDOUT: +// CHECK:STDOUT: define void @_CMyF.Main() !dbg !8 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: call void @_Z4foo1v(), !dbg !11 +// CHECK:STDOUT: call void @_Z4foo2v(), !dbg !12 +// CHECK:STDOUT: call void @_Z4foo3v(), !dbg !13 +// CHECK:STDOUT: ret void, !dbg !14 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: mustprogress noinline nounwind optnone +// CHECK:STDOUT: define linkonce_odr dso_local void @_Z4foo1v() #0 comdat { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: ret void +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: mustprogress noinline nounwind optnone +// CHECK:STDOUT: define linkonce_odr dso_local void @_Z4foo2v() #0 comdat { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: ret void +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: mustprogress noinline nounwind optnone +// CHECK:STDOUT: define linkonce_odr dso_local void @_Z4foo3v() #0 comdat { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: ret void +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: attributes #0 = { mustprogress noinline nounwind optnone "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="0" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +// CHECK:STDOUT: +// CHECK:STDOUT: !llvm.module.flags = !{!0, !1, !2, !3, !4} +// CHECK:STDOUT: !llvm.dbg.cu = !{!5} +// CHECK:STDOUT: !llvm.ident = !{!7} +// CHECK:STDOUT: +// CHECK:STDOUT: !0 = !{i32 7, !"Dwarf Version", i32 5} +// CHECK:STDOUT: !1 = !{i32 2, !"Debug Info Version", i32 3} +// CHECK:STDOUT: !2 = !{i32 1, !"wchar_size", i32 4} +// CHECK:STDOUT: !3 = !{i32 8, !"PIC Level", i32 0} +// CHECK:STDOUT: !4 = !{i32 7, !"PIE Level", i32 2} +// CHECK:STDOUT: !5 = distinct !DICompileUnit(language: DW_LANG_C, file: !6, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) +// CHECK:STDOUT: !6 = !DIFile(filename: "import_multiple_inline_function_decls.carbon", directory: "") +// CHECK:STDOUT: !7 = !{!"clang version 21.0.0git"} +// CHECK:STDOUT: !8 = distinct !DISubprogram(name: "MyF", linkageName: "_CMyF.Main", scope: null, file: !6, line: 6, type: !9, spFlags: DISPFlagDefinition, unit: !5) +// CHECK:STDOUT: !9 = !DISubroutineType(types: !10) +// CHECK:STDOUT: !10 = !{} +// CHECK:STDOUT: !11 = !DILocation(line: 7, column: 3, scope: !8) +// CHECK:STDOUT: !12 = !DILocation(line: 8, column: 3, scope: !8) +// CHECK:STDOUT: !13 = !DILocation(line: 9, column: 3, scope: !8) +// CHECK:STDOUT: !14 = !DILocation(line: 6, column: 1, scope: !8) +// CHECK:STDOUT: ; ModuleID = 'todo_import_inline_recursive_function_decl.carbon' +// CHECK:STDOUT: source_filename = "todo_import_inline_recursive_function_decl.carbon" +// CHECK:STDOUT: target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" +// CHECK:STDOUT: target triple = "x86_64-unknown-linux-gnu" +// CHECK:STDOUT: +// CHECK:STDOUT: $_Z4foo2v = comdat any +// CHECK:STDOUT: +// CHECK:STDOUT: define void @_CMyF.Main() !dbg !8 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: call void @_Z4foo2v(), !dbg !11 +// CHECK:STDOUT: ret void, !dbg !12 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: mustprogress noinline optnone +// CHECK:STDOUT: define linkonce_odr dso_local void @_Z4foo2v() #0 comdat { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: call void @_Z4foo1v() +// CHECK:STDOUT: ret void +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: declare void @_Z4foo1v() #1 +// CHECK:STDOUT: +// CHECK:STDOUT: attributes #0 = { mustprogress noinline optnone "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="0" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +// CHECK:STDOUT: attributes #1 = { "no-trapping-math"="true" "stack-protector-buffer-size"="0" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +// CHECK:STDOUT: +// CHECK:STDOUT: !llvm.module.flags = !{!0, !1, !2, !3, !4} +// CHECK:STDOUT: !llvm.dbg.cu = !{!5} +// CHECK:STDOUT: !llvm.ident = !{!7} +// CHECK:STDOUT: +// CHECK:STDOUT: !0 = !{i32 7, !"Dwarf Version", i32 5} +// CHECK:STDOUT: !1 = !{i32 2, !"Debug Info Version", i32 3} +// CHECK:STDOUT: !2 = !{i32 1, !"wchar_size", i32 4} +// CHECK:STDOUT: !3 = !{i32 8, !"PIC Level", i32 0} +// CHECK:STDOUT: !4 = !{i32 7, !"PIE Level", i32 2} +// CHECK:STDOUT: !5 = distinct !DICompileUnit(language: DW_LANG_C, file: !6, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) +// CHECK:STDOUT: !6 = !DIFile(filename: "todo_import_inline_recursive_function_decl.carbon", directory: "") +// CHECK:STDOUT: !7 = !{!"clang version 21.0.0git"} +// CHECK:STDOUT: !8 = distinct !DISubprogram(name: "MyF", linkageName: "_CMyF.Main", scope: null, file: !6, line: 6, type: !9, spFlags: DISPFlagDefinition, unit: !5) +// CHECK:STDOUT: !9 = !DISubroutineType(types: !10) +// CHECK:STDOUT: !10 = !{} +// CHECK:STDOUT: !11 = !DILocation(line: 8, column: 3, scope: !8) +// CHECK:STDOUT: !12 = !DILocation(line: 6, column: 1, scope: !8) diff --git a/toolchain/sem_ir/function.h b/toolchain/sem_ir/function.h index 2847a9175b72..664d7b7820c3 100644 --- a/toolchain/sem_ir/function.h +++ b/toolchain/sem_ir/function.h @@ -76,11 +76,12 @@ struct FunctionFields { llvm::SmallVector body_block_ids = {}; // If the function is imported from C++, points to the Clang declaration in - // the AST. Used for mangling. The AST is owned by `CompileSubcommand` so we - // expect it to be live from `Function` creation to mangling. + // the AST. Used for mangling and inline function definition code generation. + // The AST is owned by `CompileSubcommand` so we expect it to be live from + // `Function` creation to mangling. // TODO: #4666 Ensure we can easily serialize/deserialize this. Consider decl // ID to point into the AST. - const clang::NamedDecl* cpp_decl = nullptr; + clang::FunctionDecl* cpp_decl = nullptr; }; // A function. See EntityWithParamsBase regarding the inheritance here.