diff --git a/toolchain/check/check.cpp b/toolchain/check/check.cpp index b62ceb5ee2e4..899ae21eb7b9 100644 --- a/toolchain/check/check.cpp +++ b/toolchain/check/check.cpp @@ -507,14 +507,23 @@ auto CheckParseTrees( // Create C++ domains for Cpp imports. if (options.share_cpp_ast) { + llvm::SmallVector inputs; + for (auto& unit_info : unit_infos) { + if (unit_info.cpp_imports.empty()) { + continue; + } + inputs.push_back({.check_ir_id = unit_info.unit->sem_ir->check_ir_id(), + .filename = unit_info.unit->sem_ir->filename()}); + } // TODO: Remove dependence on properties of the first unit here. if (auto cpp_domain = InitializeCppDomain( - unit_infos.front().err_tracker, - unit_infos.front().unit->sem_ir->filename(), fs, + unit_infos.front().err_tracker, inputs, fs, unit_infos.front().unit->llvm_context, clang_invocation)) { cpp_domains.push_back(std::move(cpp_domain)); - for (auto& target_info : unit_infos) { - target_info.cpp_domain = cpp_domains.back().get(); + for (auto& unit_info : unit_infos) { + if (!unit_info.cpp_imports.empty()) { + unit_info.cpp_domain = cpp_domains.back().get(); + } } } } else { @@ -523,8 +532,10 @@ auto CheckParseTrees( continue; } if (auto cpp_domain = InitializeCppDomain( - unit_info.err_tracker, unit_info.unit->sem_ir->filename(), fs, - unit_info.unit->llvm_context, clang_invocation)) { + unit_info.err_tracker, + {{.check_ir_id = unit_info.unit->sem_ir->check_ir_id(), + .filename = unit_info.unit->sem_ir->filename()}}, + fs, unit_info.unit->llvm_context, clang_invocation)) { cpp_domains.push_back(std::move(cpp_domain)); unit_info.cpp_domain = cpp_domains.back().get(); } diff --git a/toolchain/check/cpp/domain.cpp b/toolchain/check/cpp/domain.cpp index 68a0f939fda3..527c7328706a 100644 --- a/toolchain/check/cpp/domain.cpp +++ b/toolchain/check/cpp/domain.cpp @@ -10,12 +10,20 @@ namespace Carbon::Check { CppDomain::CppDomain(std::shared_ptr clang_instance, std::unique_ptr parser, - clang::CodeGenerator* code_generator, + llvm::ArrayRef inputs, + llvm::ArrayRef code_generators, llvm::LLVMContext* llvm_context) : clang_instance_(std::move(clang_instance)), parser_(std::move(parser)), - code_generator_(code_generator), - llvm_context_(llvm_context) {} + llvm_context_(llvm_context) { + CARBON_CHECK(inputs.size() == code_generators.size()); + for (size_t i = 0; i < inputs.size(); ++i) { + auto res = + code_generators_.Insert(inputs[i].check_ir_id, code_generators[i]); + CARBON_CHECK(res.is_inserted(), "Duplicate CheckIRId {0} in CppDomain", + inputs[i].check_ir_id); + } +} CppDomain::~CppDomain() = default; diff --git a/toolchain/check/cpp/domain.h b/toolchain/check/cpp/domain.h index 8f08be69125e..1b586f7e4565 100644 --- a/toolchain/check/cpp/domain.h +++ b/toolchain/check/cpp/domain.h @@ -7,6 +7,11 @@ #include +#include "common/check.h" +#include "common/map.h" +#include "llvm/ADT/ArrayRef.h" +#include "toolchain/sem_ir/ids.h" + namespace clang { class CodeGenerator; class CompilerInstance; @@ -19,13 +24,20 @@ class LLVMContext; namespace Carbon::Check { +// An input Carbon file and its CheckIRId for C++ domain code generation. +struct CppInputFile { + SemIR::CheckIRId check_ir_id; + llvm::StringRef filename; +}; + // A C++ compilation domain, including a live Clang instance that can be used to // parse more code into that domain. May be shared across multiple Carbon files. class CppDomain { public: explicit CppDomain(std::shared_ptr clang_instance, std::unique_ptr parser, - clang::CodeGenerator* code_generator, + llvm::ArrayRef inputs, + llvm::ArrayRef code_generators, llvm::LLVMContext* llvm_context); ~CppDomain(); @@ -36,15 +48,19 @@ class CppDomain { return clang_instance_; } auto parser() const -> clang::Parser& { return *parser_; } - auto code_generator() const -> clang::CodeGenerator* { - return code_generator_; - } auto llvm_context() const -> llvm::LLVMContext* { return llvm_context_; } + auto GetCodeGenerator(SemIR::CheckIRId check_ir_id) const + -> clang::CodeGenerator* { + auto res = code_generators_.Lookup(check_ir_id); + CARBON_CHECK(res, "No CodeGenerator found for CheckIRId {0}", check_ir_id); + return res.value(); + } + private: std::shared_ptr clang_instance_; std::unique_ptr parser_; - clang::CodeGenerator* code_generator_ = nullptr; + Map code_generators_; llvm::LLVMContext* llvm_context_ = nullptr; }; diff --git a/toolchain/check/cpp/generate_ast.cpp b/toolchain/check/cpp/generate_ast.cpp index 36780e94e290..e46a03b2eb00 100644 --- a/toolchain/check/cpp/generate_ast.cpp +++ b/toolchain/check/cpp/generate_ast.cpp @@ -9,12 +9,14 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" +#include "clang/AST/Mangle.h" #include "clang/Basic/DiagnosticParse.h" #include "clang/Basic/FileManager.h" #include "clang/CodeGen/ModuleBuilder.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendAction.h" +#include "clang/Frontend/MultiplexConsumer.h" #include "clang/Frontend/TextDiagnostic.h" #include "clang/Lex/PreprocessorOptions.h" #include "clang/Parse/Parser.h" @@ -714,12 +716,12 @@ namespace { // from a set of Cpp imports. class GenerateASTAction : public clang::ASTFrontendAction { public: - explicit GenerateASTAction(llvm::StringRef filename, + explicit GenerateASTAction(llvm::ArrayRef inputs, llvm::LLVMContext* llvm_context) - : filename_(filename), llvm_context_(llvm_context) {} + : inputs_(inputs), llvm_context_(llvm_context) {} - auto code_generator() const -> clang::CodeGenerator* { - return code_generator_; + auto code_generators() const -> llvm::ArrayRef { + return code_generators_; } auto TakeParser() -> std::unique_ptr { @@ -733,15 +735,28 @@ class GenerateASTAction : public clang::ASTFrontendAction { if (!llvm_context_) { return std::make_unique(); } - auto code_generator = - std::unique_ptr(clang::CreateLLVMCodeGen( - clang_instance.getDiagnostics(), filename_, - clang_instance.getVirtualFileSystemPtr(), - clang_instance.getHeaderSearchOpts(), - clang_instance.getPreprocessorOpts(), - clang_instance.getCodeGenOpts(), *llvm_context_)); - code_generator_ = code_generator.get(); - return code_generator; + // Build a code generator for each object file we will be building. For now + // we assume that we want one object file per Carbon source file. + // TODO: Only build CodeGenerators for the files we're actually generating + // code for. + // TODO: Consider supporting generating code for multiple Carbon files into + // a single object file, for a faster `carbon build` mode. + std::vector> consumers; + for (const auto& input : inputs_) { + // TODO: Filter what goes into each code generator. If there are strong + // external C++ definitions in a Carbon file (for example, in inline C++ + // code), they should be emitted only in that one file. + auto code_generator = + std::unique_ptr(clang::CreateLLVMCodeGen( + clang_instance.getDiagnostics(), input.filename, + clang_instance.getVirtualFileSystemPtr(), + clang_instance.getHeaderSearchOpts(), + clang_instance.getPreprocessorOpts(), + clang_instance.getCodeGenOpts(), *llvm_context_)); + code_generators_.push_back(code_generator.get()); + consumers.push_back(std::move(code_generator)); + } + return std::make_unique(std::move(consumers)); } auto BeginSourceFileAction(clang::CompilerInstance& /*clang_instance*/) @@ -776,9 +791,9 @@ class GenerateASTAction : public clang::ASTFrontendAction { } private: - std::string filename_; + llvm::ArrayRef inputs_; llvm::LLVMContext* llvm_context_; - clang::CodeGenerator* code_generator_ = nullptr; + llvm::SmallVector code_generators_; std::unique_ptr parser_; }; @@ -788,7 +803,7 @@ class GenerateASTAction : public clang::ASTFrontendAction { // creating a diagnostics engine, and parsing a dummy main file containing a // semicolon. Returns the initialized state, or null on failure. auto InitializeCppDomain( - Diagnostics::Consumer& consumer, llvm::StringRef filename, + Diagnostics::Consumer& consumer, llvm::ArrayRef inputs, llvm::IntrusiveRefCntPtr fs, llvm::LLVMContext* llvm_context, std::shared_ptr base_invocation) @@ -816,11 +831,12 @@ auto InitializeCppDomain( // Extract the input from the frontend invocation and make sure it makes // sense. - const auto& inputs = invocation->getFrontendOpts().Inputs; - CARBON_CHECK(inputs.size() == 1 && - inputs[0].getKind().getLanguage() == clang::Language::CXX && - inputs[0].getKind().getFormat() == clang::InputKind::Source); - llvm::StringRef file_name = inputs[0].getFile(); + const auto& clang_inputs = invocation->getFrontendOpts().Inputs; + CARBON_CHECK(clang_inputs.size() == 1); + CARBON_CHECK(clang_inputs[0].getKind().getLanguage() == clang::Language::CXX); + CARBON_CHECK(clang_inputs[0].getKind().getFormat() == + clang::InputKind::Source); + llvm::StringRef file_name = clang_inputs[0].getFile(); // Remap the input file to a dummy buffer containing a semicolon to start // with an empty AST. Clang requires at least one token in the main file @@ -841,8 +857,8 @@ auto InitializeCppDomain( return nullptr; } - GenerateASTAction action(filename, llvm_context); - if (!action.BeginSourceFile(*clang_instance, inputs[0])) { + GenerateASTAction action(inputs, llvm_context); + if (!action.BeginSourceFile(*clang_instance, clang_inputs[0])) { return nullptr; } @@ -880,9 +896,10 @@ auto InitializeCppDomain( auto parser = action.TakeParser(); CARBON_CHECK(parser); + CARBON_CHECK(action.code_generators().size() == inputs.size()); return std::make_unique(std::move(clang_instance), - std::move(parser), action.code_generator(), - llvm_context); + std::move(parser), inputs, + action.code_generators(), llvm_context); } auto GenerateAst(Context& context, @@ -900,23 +917,19 @@ auto GenerateAst(Context& context, auto clang_instance = domain.clang_instance_ptr(); + auto mangle_context = std::unique_ptr( + clang_instance->getASTContext().createMangleContext()); + // Set up CppFile for the current SemIR::File. - auto cpp_file = - std::make_unique(clang_instance, domain.llvm_context()); - if (domain.code_generator()) { - cpp_file->SetCodeGenerator(domain.code_generator()); - } - context.sem_ir().set_cpp_file(std::move(cpp_file)); + context.sem_ir().set_cpp_file(std::make_unique( + clang_instance, std::move(mangle_context), domain.llvm_context(), + domain.GetCodeGenerator(context.sem_ir().check_ir_id()))); // Set up CppContext for the current Context. context.set_cpp_context(std::make_unique( domain, MakeContextDiagnosticListener( *clang_instance->getDiagnostics().getClient(), context))); - // The AST context is now available, so the mangle context (used to compute - // stable identities for imported C++ types) can be created. - context.sem_ir().cpp_file()->CreateMangleContext(); - // Add an external source referring to this context. auto* multiplex_source = cast( context.ast_context().getExternalSource()); diff --git a/toolchain/check/cpp/generate_ast.h b/toolchain/check/cpp/generate_ast.h index 0a6794527be6..733c8eddba06 100644 --- a/toolchain/check/cpp/generate_ast.h +++ b/toolchain/check/cpp/generate_ast.h @@ -12,6 +12,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Support/VirtualFileSystem.h" #include "toolchain/check/context.h" +#include "toolchain/check/cpp/domain.h" #include "toolchain/parse/tree.h" #include "toolchain/sem_ir/ids.h" @@ -35,7 +36,7 @@ class CppDomain; // within one or more Carbon files. Returns the initialized state, or null on // failure. auto InitializeCppDomain( - Diagnostics::Consumer& consumer, llvm::StringRef filename, + Diagnostics::Consumer& consumer, llvm::ArrayRef inputs, llvm::IntrusiveRefCntPtr fs, llvm::LLVMContext* llvm_context, std::shared_ptr base_invocation) diff --git a/toolchain/check/testdata/interop/cpp/basics/share_ast.carbon b/toolchain/check/testdata/interop/cpp/basics/share_ast.carbon index d3efea075c01..3546bc8f8daa 100644 --- a/toolchain/check/testdata/interop/cpp/basics/share_ast.carbon +++ b/toolchain/check/testdata/interop/cpp/basics/share_ast.carbon @@ -2,9 +2,8 @@ // Exceptions. See /LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // -// ARGS: compile --phase=check --share-cpp-ast %s -// // INCLUDE-FILE: toolchain/testing/testdata/min_prelude/int.carbon +// EXTRA-ARGS: --share-cpp-ast // // AUTOUPDATE // TIP: To test this file alone, run: @@ -39,7 +38,7 @@ import Cpp; fn CallLeakedA() -> i32 { // This should not be found as we have not imported "a.h". - // CHECK:STDERR: fail_a_does_not_leak.carbon:[[@LINE+4]]:10: error: member name `GetA` not found in `Cpp` + // CHECK:STDERR: fail_a_does_not_leak.carbon:[[@LINE+4]]:10: error: member name `GetA` not found in `Cpp` [MemberNameNotFoundInInstScope] // CHECK:STDERR: return Cpp.GetA(); // CHECK:STDERR: ^~~~~~~~ // CHECK:STDERR: diff --git a/toolchain/driver/compile_driver.cpp b/toolchain/driver/compile_driver.cpp index 506ff42d8c18..a5f1d3ce3981 100644 --- a/toolchain/driver/compile_driver.cpp +++ b/toolchain/driver/compile_driver.cpp @@ -40,13 +40,11 @@ namespace Carbon { -CompilationUnit::CompilationUnit(SemIR::CheckIRId check_ir_id, - int total_ir_count, DriverEnv* driver_env, - const CompileOptions* options, - Diagnostics::Consumer* consumer, - llvm::StringRef input_filename, - std::string output_filename, - const llvm::Target* target) +CompilationUnit::CompilationUnit( + SemIR::CheckIRId check_ir_id, int total_ir_count, DriverEnv* driver_env, + const CompileOptions* options, Diagnostics::Consumer* consumer, + llvm::StringRef input_filename, std::string output_filename, + const llvm::Target* target, llvm::LLVMContext* llvm_context) : check_ir_id_(check_ir_id), total_ir_count_(total_ir_count), driver_env_(driver_env), @@ -54,7 +52,8 @@ CompilationUnit::CompilationUnit(SemIR::CheckIRId check_ir_id, target_(target), input_filename_(input_filename), output_filename_(std::move(output_filename)), - vlog_stream_(driver_env_->vlog_stream) { + vlog_stream_(driver_env_->vlog_stream), + llvm_context_(llvm_context) { if (vlog_stream_ != nullptr || options_->stream_errors) { consumer_ = consumer; } else { @@ -150,14 +149,11 @@ auto CompilationUnit::GetCheckUnit() -> Check::Unit { }; sem_ir_.emplace(&*parse_tree_, check_ir_id_, parse_tree_->packaging_decl(), value_stores_, input_filename_); - if (!llvm_context_) { - llvm_context_ = std::make_unique(); - } return {.consumer = consumer_, .value_stores = &value_stores_, .timings = timings_ ? &*timings_ : nullptr, .sem_ir = &*sem_ir_, - .llvm_context = llvm_context_.get(), + .llvm_context = llvm_context_, .total_ir_count = total_ir_count_}; } @@ -180,9 +176,6 @@ auto CompilationUnit::PostCheck() -> void { auto CompilationUnit::RunLower() -> void { LogCall("Lower::LowerToLLVM", "lower", [&] { - if (!llvm_context_) { - llvm_context_ = std::make_unique(); - } Lower::LowerToLLVMOptions options; options.llvm_verifier_stream = options_->run_llvm_verifier ? driver_env_->error_stream : nullptr; @@ -498,6 +491,8 @@ auto CompileDriver::Initialize( } } + llvm_context_ = std::make_unique(); + // Prepare CompilationUnits before building scope exit handlers. int unit_index = -1; int total_unit_count = @@ -506,7 +501,8 @@ auto CompileDriver::Initialize( ++unit_index; return std::make_unique( SemIR::CheckIRId(unit_index), total_unit_count, &driver_env, options_, - driver_env.consumer, filename, map_input(filename), target); + driver_env.consumer, filename, map_input(filename), target, + llvm_context_.get()); }; llvm::append_range(units_, llvm::map_range(prelude, unit_builder)); llvm::append_range(units_, llvm::map_range(core_library, unit_builder)); diff --git a/toolchain/driver/compile_driver.h b/toolchain/driver/compile_driver.h index 35b3ee08a868..f421775683db 100644 --- a/toolchain/driver/compile_driver.h +++ b/toolchain/driver/compile_driver.h @@ -26,7 +26,8 @@ class CompilationUnit { Diagnostics::Consumer* consumer, llvm::StringRef input_filename, std::string output_filename, - const llvm::Target* target); + const llvm::Target* target, + llvm::LLVMContext* llvm_context); // Sets the multi-unit cache and initializes dependent member state. auto SetMultiUnitCache(MultiUnitCache* cache) -> void; @@ -146,7 +147,7 @@ class CompilationUnit { mutable std::optional parse_tree_and_subtrees_; std::optionalconst Parse::TreeAndSubtrees&>> tree_and_subtrees_getter_; - std::unique_ptr llvm_context_; + llvm::LLVMContext* llvm_context_ = nullptr; std::optional sem_ir_; std::unique_ptr module_; std::unique_ptr target_machine_; @@ -260,6 +261,7 @@ class CompileDriver { private: CompileOptions* options_; size_t input_filenames_index_ = 0; + std::unique_ptr llvm_context_; llvm::SmallVector, 256> units_; std::unique_ptr cache_; std::shared_ptr clang_invocation_; diff --git a/toolchain/lower/context.cpp b/toolchain/lower/context.cpp index db8b4a165f2d..915d270987fc 100644 --- a/toolchain/lower/context.cpp +++ b/toolchain/lower/context.cpp @@ -34,17 +34,16 @@ Context::Context( llvm::LLVMContext* llvm_context, llvm::IntrusiveRefCntPtr fs, bool want_debug_info, const Parse::GetTreeAndSubtreesStore* tree_and_subtrees_getters, - clang::CodeGenerator* clang_code_generator, llvm::StringRef module_name, + clang::CodeGenerator* cpp_code_generator, llvm::StringRef module_name, int total_ir_count, Lower::OptimizationLevel opt_level, bool mangle_string_fingerprint, llvm::raw_ostream* vlog_stream) : llvm_context_(llvm_context), - clang_code_generator_(clang_code_generator), - llvm_module_owner_( - clang_code_generator_ - ? nullptr - : std::make_unique(module_name, *llvm_context)), + cpp_code_generator_(cpp_code_generator), + llvm_module_owner_(cpp_code_generator_ ? nullptr + : std::make_unique( + module_name, *llvm_context)), llvm_module_(llvm_module_owner_ ? llvm_module_owner_.get() - : clang_code_generator_->GetModule()), + : cpp_code_generator_->GetModule()), file_system_(std::move(fs)), opt_level_(opt_level), di_builder_(*llvm_module_), @@ -95,9 +94,9 @@ auto Context::Finalize() && -> std::unique_ptr { "Debug Info Version", llvm::DEBUG_METADATA_VERSION); } - return clang_code_generator_ ? std::unique_ptr( - clang_code_generator_->ReleaseModule()) - : std::move(llvm_module_owner_); + return cpp_code_generator_ ? std::unique_ptr( + cpp_code_generator_->ReleaseModule()) + : std::move(llvm_module_owner_); } auto Context::BuildDICompileUnit(llvm::StringRef module_name, diff --git a/toolchain/lower/context.h b/toolchain/lower/context.h index 6a61f04ac2b1..60f9e0162553 100644 --- a/toolchain/lower/context.h +++ b/toolchain/lower/context.h @@ -121,6 +121,9 @@ class Context { auto file_system() -> llvm::IntrusiveRefCntPtr& { return file_system_; } + auto cpp_code_generator() -> clang::CodeGenerator* { + return cpp_code_generator_; + } auto opt_level() -> Lower::OptimizationLevel { return opt_level_; } auto di_builder() -> llvm::DIBuilder& { return di_builder_; } auto di_compile_unit() -> llvm::DICompileUnit* { return di_compile_unit_; } @@ -153,7 +156,7 @@ class Context { // State for building the LLVM IR. llvm::LLVMContext* llvm_context_; - clang::CodeGenerator* clang_code_generator_; + clang::CodeGenerator* cpp_code_generator_; std::unique_ptr llvm_module_owner_; llvm::Module* llvm_module_; diff --git a/toolchain/lower/file_context.cpp b/toolchain/lower/file_context.cpp index a00b7b1247e4..11e64ec1bc7e 100644 --- a/toolchain/lower/file_context.cpp +++ b/toolchain/lower/file_context.cpp @@ -63,11 +63,6 @@ FileContext::FileContext(Context& context, const SemIR::File& sem_ir, coalescer_(vlog_stream_, sem_ir.specifics()), vtables_(decltype(vtables_)::MakeForOverwrite(sem_ir.vtables())), specific_vtables_(sem_ir.specifics(), nullptr) { - // Initialization that relies on invariants of the class. - cpp_code_generator_ = cpp_file() ? cpp_file()->GetCodeGenerator() : nullptr; - CARBON_CHECK( - !cpp_code_generator_ || - (&cpp_code_generator_->GetModule()->getContext() == &llvm_context())); CARBON_CHECK(!sem_ir.has_errors(), "Generating LLVM IR from invalid SemIR::File is unsupported."); } @@ -184,10 +179,14 @@ auto FileContext::LowerDefinitions() -> void { } auto FileContext::Finalize() -> void { - if (cpp_code_generator_) { + // TODO: This is an ugly way to check if we're supposed to finalize this code + // generator. Context::Finalize should finalize its own code generator, but + // doesn't have a reference to its `ASTContext`. + if (cpp_file() && + cpp_file()->code_generator() == context().cpp_code_generator()) { // Clang code generation should not actually modify the AST, but isn't // const-correct. - cpp_code_generator_->HandleTranslationUnit( + cpp_file()->code_generator()->HandleTranslationUnit( const_cast(cpp_file()->ast_context())); } @@ -316,9 +315,12 @@ auto FileContext::HandleReferencedCppFunction(clang::FunctionDecl* cpp_decl) // so that code generation (`CodeGenModule::EmitGlobal()`) would see this // function name (`CodeGenModule::getMangledName()`), and will generate // its definition. - auto* function_address = dyn_cast( - cpp_code_generator_->GetAddrOfGlobal(CreateGlobalDecl(cpp_decl), - /*isForDefinition=*/false)); + // TODO: This code generator can be for the wrong AST if we're not using + // --share-cpp-ast. + auto* function_address = + dyn_cast(context().cpp_code_generator()->GetAddrOfGlobal( + CreateGlobalDecl(cpp_decl), + /*isForDefinition=*/false)); CARBON_CHECK(function_address); return function_address; @@ -724,7 +726,9 @@ auto FileContext::BuildGlobalVariableDecl(SemIR::VarStorage var_storage) // llvm::GlobalVariable. if (const auto* clang_decl = sem_ir().clang_decls().Lookup(var_storage.pattern_id)) { - auto* constant = cpp_code_generator_->GetAddrOfGlobal( + // TODO: This code generator can be for the wrong AST if we're not using + // --share-cpp-ast. + auto* constant = context().cpp_code_generator()->GetAddrOfGlobal( CreateGlobalDecl(cast(clang_decl->decl())), /*isForDefinition=*/false); if (constant) { @@ -772,7 +776,9 @@ auto FileContext::BuildVtable(const SemIR::Vtable& vtable, if (!vtable.carbon_native_vtable) { auto* cxx_record_decl = cast( sem_ir().clang_decls().Lookup(class_info.latest_decl_id())->key.decl); - return cpp_code_generator_->GetAddrOfVTable( + // TODO: This code generator can be for the wrong AST if we're not using + // --share-cpp-ast. + return context().cpp_code_generator()->GetAddrOfVTable( clang::BaseSubobject(cxx_record_decl, clang::CharUnits::fromQuantity(0)), cxx_record_decl); diff --git a/toolchain/lower/file_context.h b/toolchain/lower/file_context.h index b135a2f517ff..cc9a18fc4d3c 100644 --- a/toolchain/lower/file_context.h +++ b/toolchain/lower/file_context.h @@ -166,10 +166,6 @@ class FileContext { auto context() -> Context& { return *context_; } auto llvm_context() -> llvm::LLVMContext& { return context().llvm_context(); } auto llvm_module() -> llvm::Module& { return context().llvm_module(); } - auto cpp_code_generator() -> clang::CodeGenerator& { - CARBON_CHECK(cpp_code_generator_); - return *cpp_code_generator_; - } auto sem_ir() const -> const SemIR::File& { return *sem_ir_; } auto cpp_file() -> const SemIR::CppFile* { return sem_ir().cpp_file(); } auto inst_namer() -> const SemIR::InstNamer* { return inst_namer_; } @@ -270,10 +266,6 @@ class FileContext { // The input SemIR. const SemIR::File* const sem_ir_; - // The Clang `CodeGenerator` to generate LLVM module from imported C++ - // code. Can be null if no C++ code is imported. - clang::CodeGenerator* cpp_code_generator_; - // The instruction namer, if given. const SemIR::InstNamer* const inst_namer_; diff --git a/toolchain/lower/handle_call.cpp b/toolchain/lower/handle_call.cpp index b37fa1d078b7..a5722af833ae 100644 --- a/toolchain/lower/handle_call.cpp +++ b/toolchain/lower/handle_call.cpp @@ -744,9 +744,17 @@ auto HandleInst(FunctionContext& context, SemIR::InstId inst_id, // Lower args in the LLVM parameter order, rather than the SemIR parameter // order. std::vector args; + bool args_ok = true; + auto* callee_type = function_info->llvm_function->getFunctionType(); for (auto index : function_info->lowered_param_indices) { args.push_back(context.GetValue(arg_ids[index.index])); + + if (args.size() > callee_type->getNumParams() || + callee_type->getParamType(args.size() - 1) != args.back()->getType()) { + args_ok = false; + } } + args_ok &= args.size() == callee_type->getNumParams(); llvm::CallInst* call; if (function.virtual_index == -1) { @@ -765,8 +773,7 @@ auto HandleInst(FunctionContext& context, SemIR::InstId inst_id, llvm_callee->print(out); return out.TakeStr(); }; - CARBON_CHECK(llvm_callee->arg_size() == args.size(), - "Argument count mismatch: {0}", describe_call()); + CARBON_CHECK(args_ok, "Argument mismatch: {0}", describe_call()); call = context.builder().CreateCall(llvm_callee, args); } else { call = HandleVirtualCall(context, args, function, *function_info); diff --git a/toolchain/lower/lower.cpp b/toolchain/lower/lower.cpp index 5101dd3cf83c..83d24b2c2243 100644 --- a/toolchain/lower/lower.cpp +++ b/toolchain/lower/lower.cpp @@ -23,7 +23,7 @@ auto LowerToLLVM( Context context( &llvm_context, std::move(fs), options.want_debug_info, &tree_and_subtrees_getters, - sem_ir.cpp_file() ? sem_ir.cpp_file()->GetCodeGenerator() : nullptr, + sem_ir.cpp_file() ? sem_ir.cpp_file()->code_generator() : nullptr, sem_ir.filename(), total_ir_count, options.opt_level, options.mangle_string_fingerprint, options.vlog_stream); diff --git a/toolchain/lower/testdata/function/generic/call.carbon b/toolchain/lower/testdata/function/generic/call.carbon index 7872988602b7..47af9f4c7f69 100644 --- a/toolchain/lower/testdata/function/generic/call.carbon +++ b/toolchain/lower/testdata/function/generic/call.carbon @@ -33,7 +33,7 @@ fn G() { // CHECK:STDOUT: ; ModuleID = 'call.carbon' // CHECK:STDOUT: source_filename = "call.carbon" // CHECK:STDOUT: -// CHECK:STDOUT: %type = type {} +// CHECK:STDOUT: %type.26 = type {} // CHECK:STDOUT: // CHECK:STDOUT: @C.val.loc20_3 = internal constant {} zeroinitializer // CHECK:STDOUT: @D.val.loc21_3 = internal constant {} zeroinitializer @@ -59,7 +59,7 @@ fn G() { // CHECK:STDOUT: call void @_CF.Main.84588f41d61dafba(i32 %.loc27), !dbg !14 // CHECK:STDOUT: %.loc28 = load double, ptr %m.var, align 8, !dbg !15 // CHECK:STDOUT: call void @_CF.Main.073fbce68be6103e(double %.loc28), !dbg !16 -// CHECK:STDOUT: call void @_CF.Main.5754c7a55c7cbe4a(%type zeroinitializer), !dbg !17 +// CHECK:STDOUT: call void @_CF.Main.5754c7a55c7cbe4a(%type.26 zeroinitializer), !dbg !17 // CHECK:STDOUT: call void @"_COp.30d8007fdcc57f83:core.Destroy.Core"(ptr %m.var), !dbg !10 // CHECK:STDOUT: call void @"_COp.5e27612b9dd31a14:core.Destroy.Core"(ptr %n.var), !dbg !9 // CHECK:STDOUT: call void @"_COp.7fd3b6c3a3c15807:core.Destroy.Core"(ptr %d.var), !dbg !8 @@ -116,7 +116,7 @@ fn G() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind -// CHECK:STDOUT: define linkonce_odr void @_CF.Main.5754c7a55c7cbe4a(%type %_) #0 !dbg !53 { +// CHECK:STDOUT: define linkonce_odr void @_CF.Main.5754c7a55c7cbe4a(%type.26 %_) #0 !dbg !53 { // CHECK:STDOUT: entry: // CHECK:STDOUT: ret void, !dbg !56 // CHECK:STDOUT: } diff --git a/toolchain/lower/testdata/function/generic/call_basic.carbon b/toolchain/lower/testdata/function/generic/call_basic.carbon index c84994ed7438..1278139b46c9 100644 --- a/toolchain/lower/testdata/function/generic/call_basic.carbon +++ b/toolchain/lower/testdata/function/generic/call_basic.carbon @@ -59,7 +59,7 @@ fn M() { // CHECK:STDOUT: ; ModuleID = 'call_basic.carbon' // CHECK:STDOUT: source_filename = "call_basic.carbon" // CHECK:STDOUT: -// CHECK:STDOUT: %type = type {} +// CHECK:STDOUT: %type.26 = type {} // CHECK:STDOUT: // CHECK:STDOUT: @C.val.loc15_43 = internal constant {} zeroinitializer // CHECK:STDOUT: @@ -138,7 +138,7 @@ fn M() { // CHECK:STDOUT: %H.call.loc29 = call i32 @_CH.Main.5bd8d5767580997a(i32 %x), !dbg !51 // CHECK:STDOUT: store i32 %H.call.loc29, ptr %.loc29_6.3.temp, align 4, !dbg !51 // CHECK:STDOUT: call void @"_COp.5e27612b9dd31a14:core.Destroy.Core"(ptr %.loc29_6.3.temp), !dbg !51 -// CHECK:STDOUT: %H.call.loc30 = call %type @_CH.Main.ee509b43cf4eb3c5(%type zeroinitializer), !dbg !60 +// CHECK:STDOUT: %H.call.loc30 = call %type.26 @_CH.Main.ee509b43cf4eb3c5(%type.26 zeroinitializer), !dbg !60 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc31_8.3.temp), !dbg !52 // CHECK:STDOUT: %G.call = call i32 @_CG.Main.58016a73bff04416(i32 %x), !dbg !52 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc31_9.3.temp), !dbg !53 @@ -195,7 +195,7 @@ fn M() { // CHECK:STDOUT: %H.call.loc29 = call double @_CH.Main.c27b765f2159c9a0(double %x), !dbg !77 // CHECK:STDOUT: store double %H.call.loc29, ptr %.loc29_6.3.temp, align 8, !dbg !77 // CHECK:STDOUT: call void @"_COp.30d8007fdcc57f83:core.Destroy.Core"(ptr %.loc29_6.3.temp), !dbg !77 -// CHECK:STDOUT: %H.call.loc30 = call %type @_CH.Main.ee509b43cf4eb3c5(%type zeroinitializer), !dbg !86 +// CHECK:STDOUT: %H.call.loc30 = call %type.26 @_CH.Main.ee509b43cf4eb3c5(%type.26 zeroinitializer), !dbg !86 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc31_8.3.temp), !dbg !78 // CHECK:STDOUT: %G.call = call double @_CG.Main.fa1f0912a5bbe922(double %x), !dbg !78 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc31_9.3.temp), !dbg !79 @@ -237,9 +237,9 @@ fn M() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind -// CHECK:STDOUT: define linkonce_odr %type @_CH.Main.ee509b43cf4eb3c5(%type %x) #0 !dbg !100 { +// CHECK:STDOUT: define linkonce_odr %type.26 @_CH.Main.ee509b43cf4eb3c5(%type.26 %x) #0 !dbg !100 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: ret %type %x, !dbg !103 +// CHECK:STDOUT: ret %type.26 %x, !dbg !103 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind diff --git a/toolchain/lower/testdata/function/generic/call_deref_ptr.carbon b/toolchain/lower/testdata/function/generic/call_deref_ptr.carbon index 3b7850c12933..11997ae2eb3b 100644 --- a/toolchain/lower/testdata/function/generic/call_deref_ptr.carbon +++ b/toolchain/lower/testdata/function/generic/call_deref_ptr.carbon @@ -44,7 +44,7 @@ fn M() { // CHECK:STDOUT: ; ModuleID = 'call_deref_ptr.carbon' // CHECK:STDOUT: source_filename = "call_deref_ptr.carbon" // CHECK:STDOUT: -// CHECK:STDOUT: %type = type {} +// CHECK:STDOUT: %type.26 = type {} // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind // CHECK:STDOUT: define void @_CM.Main() #0 !dbg !4 { @@ -80,7 +80,7 @@ fn M() { // CHECK:STDOUT: ; Function Attrs: nounwind // CHECK:STDOUT: define linkonce_odr void @_CF.Main.58016a73bff04416(ptr %x) #0 !dbg !28 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %A.call = call %type @_CA.Main.ee509b43cf4eb3c5(%type zeroinitializer), !dbg !31 +// CHECK:STDOUT: %A.call = call %type.26 @_CA.Main.ee509b43cf4eb3c5(%type.26 zeroinitializer), !dbg !31 // CHECK:STDOUT: call void @_CB.Main.58016a73bff04416(ptr %x), !dbg !32 // CHECK:STDOUT: ret void, !dbg !33 // CHECK:STDOUT: } @@ -88,15 +88,15 @@ fn M() { // CHECK:STDOUT: ; Function Attrs: nounwind // CHECK:STDOUT: define linkonce_odr void @_CF.Main.fa1f0912a5bbe922(ptr %x) #0 !dbg !34 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %A.call = call %type @_CA.Main.ee509b43cf4eb3c5(%type zeroinitializer), !dbg !37 +// CHECK:STDOUT: %A.call = call %type.26 @_CA.Main.ee509b43cf4eb3c5(%type.26 zeroinitializer), !dbg !37 // CHECK:STDOUT: call void @_CB.Main.fa1f0912a5bbe922(ptr %x), !dbg !38 // CHECK:STDOUT: ret void, !dbg !39 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind -// CHECK:STDOUT: define linkonce_odr %type @_CA.Main.ee509b43cf4eb3c5(%type %x) #0 !dbg !40 { +// CHECK:STDOUT: define linkonce_odr %type.26 @_CA.Main.ee509b43cf4eb3c5(%type.26 %x) #0 !dbg !40 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: ret %type %x, !dbg !45 +// CHECK:STDOUT: ret %type.26 %x, !dbg !45 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind diff --git a/toolchain/lower/testdata/function/generic/call_different_specific.carbon b/toolchain/lower/testdata/function/generic/call_different_specific.carbon index d10edc0dae35..dc454daec477 100644 --- a/toolchain/lower/testdata/function/generic/call_different_specific.carbon +++ b/toolchain/lower/testdata/function/generic/call_different_specific.carbon @@ -48,7 +48,7 @@ fn M(ptr_i32: i32*, ptr_f64: f64*) { // CHECK:STDOUT: ; ModuleID = 'call_different_specific.carbon' // CHECK:STDOUT: source_filename = "call_different_specific.carbon" // CHECK:STDOUT: -// CHECK:STDOUT: %type = type {} +// CHECK:STDOUT: %type.58 = type {} // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind // CHECK:STDOUT: define void @_CM.Main(ptr %ptr_i32, ptr %ptr_f64) #0 !dbg !4 { @@ -73,7 +73,7 @@ fn M(ptr_i32: i32*, ptr_f64: f64*) { // CHECK:STDOUT: ; Function Attrs: nounwind // CHECK:STDOUT: define linkonce_odr void @_CF.Main.58016a73bff04416(ptr %x) #0 !dbg !27 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %A.call = call %type @_CA.Main.ee509b43cf4eb3c5(%type zeroinitializer), !dbg !30 +// CHECK:STDOUT: %A.call = call %type.58 @_CA.Main.ee509b43cf4eb3c5(%type.58 zeroinitializer), !dbg !30 // CHECK:STDOUT: call void @_CB.Main.58016a73bff04416(ptr %x), !dbg !31 // CHECK:STDOUT: ret void, !dbg !32 // CHECK:STDOUT: } @@ -81,15 +81,15 @@ fn M(ptr_i32: i32*, ptr_f64: f64*) { // CHECK:STDOUT: ; Function Attrs: nounwind // CHECK:STDOUT: define linkonce_odr void @_CF.Main.fa1f0912a5bbe922(ptr %x) #0 !dbg !33 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %A.call = call %type @_CA.Main.ee509b43cf4eb3c5(%type zeroinitializer), !dbg !36 +// CHECK:STDOUT: %A.call = call %type.58 @_CA.Main.ee509b43cf4eb3c5(%type.58 zeroinitializer), !dbg !36 // CHECK:STDOUT: call void @_CB.Main.fa1f0912a5bbe922(ptr %x), !dbg !37 // CHECK:STDOUT: ret void, !dbg !38 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind -// CHECK:STDOUT: define linkonce_odr %type @_CA.Main.ee509b43cf4eb3c5(%type %x) #0 !dbg !39 { +// CHECK:STDOUT: define linkonce_odr %type.58 @_CA.Main.ee509b43cf4eb3c5(%type.58 %x) #0 !dbg !39 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: ret %type %x, !dbg !44 +// CHECK:STDOUT: ret %type.58 %x, !dbg !44 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind diff --git a/toolchain/lower/testdata/function/generic/call_specific_in_class.carbon b/toolchain/lower/testdata/function/generic/call_specific_in_class.carbon index db4d28deca30..11ed3eb270bb 100644 --- a/toolchain/lower/testdata/function/generic/call_specific_in_class.carbon +++ b/toolchain/lower/testdata/function/generic/call_specific_in_class.carbon @@ -48,7 +48,7 @@ fn M() { // CHECK:STDOUT: ; ModuleID = 'call_specific_in_class.carbon' // CHECK:STDOUT: source_filename = "call_specific_in_class.carbon" // CHECK:STDOUT: -// CHECK:STDOUT: %type = type {} +// CHECK:STDOUT: %type.26 = type {} // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind // CHECK:STDOUT: define weak_odr void @"_COp.807eb4f2d3ed7e54:core.Destroy.Core"(ptr %self) #0 !dbg !4 { @@ -86,7 +86,7 @@ fn M() { // CHECK:STDOUT: %.loc42_5 = load double, ptr %var_f64.var, align 8, !dbg !28 // CHECK:STDOUT: %F.call.loc42 = call double @_CF.Main.c27b765f2159c9a0(double %.loc42_5), !dbg !29 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %_.var), !dbg !19 -// CHECK:STDOUT: %F.call.loc44 = call %type @_CF.Main.ee509b43cf4eb3c5(%type zeroinitializer), !dbg !30 +// CHECK:STDOUT: %F.call.loc44 = call %type.26 @_CF.Main.ee509b43cf4eb3c5(%type.26 zeroinitializer), !dbg !30 // CHECK:STDOUT: call void @"_COp.807eb4f2d3ed7e54:core.Destroy.Core"(ptr %_.var), !dbg !19 // CHECK:STDOUT: call void @"_COp.30d8007fdcc57f83:core.Destroy.Core"(ptr %var_f64.var), !dbg !18 // CHECK:STDOUT: call void @"_COp.5e27612b9dd31a14:core.Destroy.Core"(ptr %var_i32.var), !dbg !17 @@ -130,10 +130,10 @@ fn M() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind -// CHECK:STDOUT: define linkonce_odr %type @_CF.Main.ee509b43cf4eb3c5(%type %x) #0 !dbg !62 { +// CHECK:STDOUT: define linkonce_odr %type.26 @_CF.Main.ee509b43cf4eb3c5(%type.26 %x) #0 !dbg !62 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %G.call = call %type @_CG.Main.ee509b43cf4eb3c5(%type %x), !dbg !65 -// CHECK:STDOUT: ret %type %G.call, !dbg !66 +// CHECK:STDOUT: %G.call = call %type.26 @_CG.Main.ee509b43cf4eb3c5(%type.26 %x), !dbg !65 +// CHECK:STDOUT: ret %type.26 %G.call, !dbg !66 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind @@ -167,13 +167,13 @@ fn M() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind -// CHECK:STDOUT: define linkonce_odr %type @_CG.Main.ee509b43cf4eb3c5(%type %x) #0 !dbg !85 { +// CHECK:STDOUT: define linkonce_odr %type.26 @_CG.Main.ee509b43cf4eb3c5(%type.26 %x) #0 !dbg !85 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %c.var = alloca {}, align 1, !dbg !88 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %c.var), !dbg !88 -// CHECK:STDOUT: %C.Cfn.call = call %type @_CCfn.C.Main.ee509b43cf4eb3c5(ptr %c.var, %type %x), !dbg !89 +// CHECK:STDOUT: %C.Cfn.call = call %type.26 @_CCfn.C.Main.ee509b43cf4eb3c5(ptr %c.var, %type.26 %x), !dbg !89 // CHECK:STDOUT: call void @"_COp.807eb4f2d3ed7e54:core.Destroy.Core"(ptr %c.var), !dbg !88 -// CHECK:STDOUT: ret %type %C.Cfn.call, !dbg !90 +// CHECK:STDOUT: ret %type.26 %C.Cfn.call, !dbg !90 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind @@ -195,9 +195,9 @@ fn M() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind -// CHECK:STDOUT: define linkonce_odr %type @_CCfn.C.Main.ee509b43cf4eb3c5(ptr %self, %type %x) #0 !dbg !110 { +// CHECK:STDOUT: define linkonce_odr %type.26 @_CCfn.C.Main.ee509b43cf4eb3c5(ptr %self, %type.26 %x) #0 !dbg !110 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: ret %type %x, !dbg !114 +// CHECK:STDOUT: ret %type.26 %x, !dbg !114 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; uselistorder directives diff --git a/toolchain/lower/testdata/interop/cpp/class/export/class.carbon b/toolchain/lower/testdata/interop/cpp/class/export/class.carbon index 0f11fd76ebca..82ff728f5950 100644 --- a/toolchain/lower/testdata/interop/cpp/class/export/class.carbon +++ b/toolchain/lower/testdata/interop/cpp/class/export/class.carbon @@ -458,7 +458,7 @@ fn G() { // 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: %"class.Carbon::C" = type { i32, i32 } +// CHECK:STDOUT: %"class.Carbon::C.0" = type { i32, i32 } // CHECK:STDOUT: // CHECK:STDOUT: @C.val.loc19_3 = internal constant { i32, i32 } zeroinitializer // CHECK:STDOUT: @@ -468,10 +468,10 @@ fn G() { // CHECK:STDOUT: %c.addr = alloca ptr, align 8 // CHECK:STDOUT: store ptr %c, ptr %c.addr, align 8, !tbaa !12 // CHECK:STDOUT: %0 = load ptr, ptr %c.addr, align 8, !tbaa !12, !nonnull !15, !align !16 -// CHECK:STDOUT: %a = getelementptr inbounds nuw %"class.Carbon::C", ptr %0, i32 0, i32 0 +// CHECK:STDOUT: %a = getelementptr inbounds nuw %"class.Carbon::C.0", ptr %0, i32 0, i32 0 // CHECK:STDOUT: store i32 12, ptr %a, align 4, !tbaa !17 // CHECK:STDOUT: %1 = load ptr, ptr %c.addr, align 8, !tbaa !12, !nonnull !15, !align !16 -// CHECK:STDOUT: %b = getelementptr inbounds nuw %"class.Carbon::C", ptr %1, i32 0, i32 1 +// CHECK:STDOUT: %b = getelementptr inbounds nuw %"class.Carbon::C.0", ptr %1, i32 0, i32 1 // CHECK:STDOUT: store i32 34, ptr %b, align 4, !tbaa !19 // CHECK:STDOUT: ret void // CHECK:STDOUT: } diff --git a/toolchain/lower/testdata/interop/cpp/class/export/method.carbon b/toolchain/lower/testdata/interop/cpp/class/export/method.carbon index 73a87ea14a8f..79f74f5f322e 100644 --- a/toolchain/lower/testdata/interop/cpp/class/export/method.carbon +++ b/toolchain/lower/testdata/interop/cpp/class/export/method.carbon @@ -188,14 +188,14 @@ fn CallCallF() { Cpp.CallF(); } // 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: %"class.Carbon::A" = type {} +// CHECK:STDOUT: %"class.Carbon::A.0" = type {} // CHECK:STDOUT: // CHECK:STDOUT: $_ZN6Carbon1AD2Ev = comdat any // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: mustprogress nounwind uwtable // CHECK:STDOUT: define dso_local noundef i32 @_Z5CallFv() #0 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %ref.tmp = alloca %"class.Carbon::A", align 1 +// CHECK:STDOUT: %ref.tmp = alloca %"class.Carbon::A.0", align 1 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %ref.tmp) #4 // CHECK:STDOUT: %call = call noundef i32 @_ZNK6Carbon1A1FEi(ptr noundef nonnull align 1 %ref.tmp, i32 noundef 123) // CHECK:STDOUT: call void @_ZN6Carbon1AD2Ev(ptr noundef nonnull align 1 %ref.tmp) #4 diff --git a/toolchain/lower/testdata/interop/cpp/class/import/constructor.carbon b/toolchain/lower/testdata/interop/cpp/class/import/constructor.carbon index 6a544bf3cde2..8ae6417f3d19 100644 --- a/toolchain/lower/testdata/interop/cpp/class/import/constructor.carbon +++ b/toolchain/lower/testdata/interop/cpp/class/import/constructor.carbon @@ -276,7 +276,7 @@ fn Four() { // 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: %class.C = type { i32, i32 } +// CHECK:STDOUT: %class.C.18 = type { i32, i32 } // CHECK:STDOUT: // CHECK:STDOUT: $_ZN1CC2Ev = comdat any // CHECK:STDOUT: @@ -321,9 +321,9 @@ fn Four() { // CHECK:STDOUT: %this.addr = alloca ptr, align 8 // CHECK:STDOUT: store ptr %this, ptr %this.addr, align 8, !tbaa !17 // CHECK:STDOUT: %this1 = load ptr, ptr %this.addr, align 8 -// CHECK:STDOUT: %x_ = getelementptr inbounds nuw %class.C, ptr %this1, i32 0, i32 0 +// CHECK:STDOUT: %x_ = getelementptr inbounds nuw %class.C.18, ptr %this1, i32 0, i32 0 // CHECK:STDOUT: store i32 8, ptr %x_, align 4, !tbaa !30 -// CHECK:STDOUT: %y_ = getelementptr inbounds nuw %class.C, ptr %this1, i32 0, i32 1 +// CHECK:STDOUT: %y_ = getelementptr inbounds nuw %class.C.18, ptr %this1, i32 0, i32 1 // CHECK:STDOUT: store i32 9, ptr %y_, align 4, !tbaa !32 // CHECK:STDOUT: ret void // CHECK:STDOUT: } diff --git a/toolchain/lower/testdata/interop/cpp/class/import/method.carbon b/toolchain/lower/testdata/interop/cpp/class/import/method.carbon index 8c7dd90ef293..477067ab5b44 100644 --- a/toolchain/lower/testdata/interop/cpp/class/import/method.carbon +++ b/toolchain/lower/testdata/interop/cpp/class/import/method.carbon @@ -184,8 +184,8 @@ fn F(ref r: Cpp.A) { // 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: %struct.A = type <{ %struct.Base, i32, [4 x i8] }> -// CHECK:STDOUT: %struct.Base = type { ptr } +// CHECK:STDOUT: %struct.A.18 = type <{ %struct.Base.19, i32, [4 x i8] }> +// CHECK:STDOUT: %struct.Base.19 = type { ptr } // CHECK:STDOUT: // CHECK:STDOUT: $_ZN1A6by_refEv = comdat any // CHECK:STDOUT: @@ -211,7 +211,7 @@ fn F(ref r: Cpp.A) { // CHECK:STDOUT: %this.addr = alloca ptr, align 8 // CHECK:STDOUT: store ptr %this, ptr %this.addr, align 8, !tbaa !21 // CHECK:STDOUT: %this1 = load ptr, ptr %this.addr, align 8 -// CHECK:STDOUT: %n = getelementptr inbounds nuw %struct.A, ptr %this1, i32 0, i32 1 +// CHECK:STDOUT: %n = getelementptr inbounds nuw %struct.A.18, ptr %this1, i32 0, i32 1 // CHECK:STDOUT: %0 = load i32, ptr %n, align 8, !tbaa !24 // CHECK:STDOUT: ret i32 %0 // CHECK:STDOUT: } diff --git a/toolchain/lower/testdata/interop/cpp/globals.carbon b/toolchain/lower/testdata/interop/cpp/globals.carbon index 0aedb0a9e113..97f39c42a0c7 100644 --- a/toolchain/lower/testdata/interop/cpp/globals.carbon +++ b/toolchain/lower/testdata/interop/cpp/globals.carbon @@ -528,10 +528,10 @@ fn ReadStaticVarTemplateWithConstructor() -> Cpp.Y* { // 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: %struct.Y = type { i8 } +// CHECK:STDOUT: %struct.Y.26 = type { i8 } // CHECK:STDOUT: // CHECK:STDOUT: @_ZN1X11static_tmplIiEE = external global i32, align 4 -// CHECK:STDOUT: @_ZN1X11static_tmplI1YEE = external global %struct.Y, align 1 +// CHECK:STDOUT: @_ZN1X11static_tmplI1YEE = external global %struct.Y.26, align 1 // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind // CHECK:STDOUT: define i32 @_CReadStaticVarTemplate.Main() #0 !dbg !12 { diff --git a/toolchain/lower/testdata/interop/cpp/operators.carbon b/toolchain/lower/testdata/interop/cpp/operators.carbon index d1de98480052..610f3dad578a 100644 --- a/toolchain/lower/testdata/interop/cpp/operators.carbon +++ b/toolchain/lower/testdata/interop/cpp/operators.carbon @@ -290,7 +290,7 @@ fn Driver(x: Cpp.A, y: Cpp.A) { // 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: %struct.A = type { i32 } +// CHECK:STDOUT: %struct.A.62 = type { i32 } // CHECK:STDOUT: // CHECK:STDOUT: $_Zlt1AS_ = comdat any // CHECK:STDOUT: @@ -313,8 +313,8 @@ fn Driver(x: Cpp.A, y: Cpp.A) { // CHECK:STDOUT: %x.addr = alloca ptr, align 8 // CHECK:STDOUT: %y.addr = alloca ptr, align 8 // CHECK:STDOUT: %return.addr = alloca ptr, align 8 -// CHECK:STDOUT: %agg.tmp = alloca %struct.A, align 4 -// CHECK:STDOUT: %agg.tmp1 = alloca %struct.A, align 4 +// CHECK:STDOUT: %agg.tmp = alloca %struct.A.62, align 4 +// CHECK:STDOUT: %agg.tmp1 = alloca %struct.A.62, align 4 // CHECK:STDOUT: store ptr %x, ptr %x.addr, align 8, !tbaa !21 // CHECK:STDOUT: store ptr %y, ptr %y.addr, align 8, !tbaa !21 // CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !24 @@ -323,9 +323,9 @@ fn Driver(x: Cpp.A, y: Cpp.A) { // CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %agg.tmp, ptr align 4 %1, i64 4, i1 false), !tbaa.struct !26 // CHECK:STDOUT: %2 = load ptr, ptr %y.addr, align 8, !tbaa !21 // CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %agg.tmp1, ptr align 4 %2, i64 4, i1 false), !tbaa.struct !26 -// CHECK:STDOUT: %coerce.dive = getelementptr inbounds nuw %struct.A, ptr %agg.tmp, i32 0, i32 0 +// CHECK:STDOUT: %coerce.dive = getelementptr inbounds nuw %struct.A.62, ptr %agg.tmp, i32 0, i32 0 // CHECK:STDOUT: %3 = load i32, ptr %coerce.dive, align 4 -// CHECK:STDOUT: %coerce.dive2 = getelementptr inbounds nuw %struct.A, ptr %agg.tmp1, i32 0, i32 0 +// CHECK:STDOUT: %coerce.dive2 = getelementptr inbounds nuw %struct.A.62, ptr %agg.tmp1, i32 0, i32 0 // CHECK:STDOUT: %4 = load i32, ptr %coerce.dive2, align 4 // CHECK:STDOUT: %call = call noundef zeroext i1 @_Zlt1AS_(i32 %3, i32 %4) // CHECK:STDOUT: %storedv = zext i1 %call to i8 @@ -339,8 +339,8 @@ fn Driver(x: Cpp.A, y: Cpp.A) { // CHECK:STDOUT: %x.addr = alloca ptr, align 8 // CHECK:STDOUT: %y.addr = alloca ptr, align 8 // CHECK:STDOUT: %return.addr = alloca ptr, align 8 -// CHECK:STDOUT: %agg.tmp = alloca %struct.A, align 4 -// CHECK:STDOUT: %agg.tmp1 = alloca %struct.A, align 4 +// CHECK:STDOUT: %agg.tmp = alloca %struct.A.62, align 4 +// CHECK:STDOUT: %agg.tmp1 = alloca %struct.A.62, align 4 // CHECK:STDOUT: store ptr %x, ptr %x.addr, align 8, !tbaa !21 // CHECK:STDOUT: store ptr %y, ptr %y.addr, align 8, !tbaa !21 // CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !24 @@ -349,9 +349,9 @@ fn Driver(x: Cpp.A, y: Cpp.A) { // CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %agg.tmp, ptr align 4 %1, i64 4, i1 false), !tbaa.struct !26 // CHECK:STDOUT: %2 = load ptr, ptr %y.addr, align 8, !tbaa !21 // CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %agg.tmp1, ptr align 4 %2, i64 4, i1 false), !tbaa.struct !26 -// CHECK:STDOUT: %coerce.dive = getelementptr inbounds nuw %struct.A, ptr %agg.tmp, i32 0, i32 0 +// CHECK:STDOUT: %coerce.dive = getelementptr inbounds nuw %struct.A.62, ptr %agg.tmp, i32 0, i32 0 // CHECK:STDOUT: %3 = load i32, ptr %coerce.dive, align 4 -// CHECK:STDOUT: %coerce.dive2 = getelementptr inbounds nuw %struct.A, ptr %agg.tmp1, i32 0, i32 0 +// CHECK:STDOUT: %coerce.dive2 = getelementptr inbounds nuw %struct.A.62, ptr %agg.tmp1, i32 0, i32 0 // CHECK:STDOUT: %4 = load i32, ptr %coerce.dive2, align 4 // CHECK:STDOUT: %call = call noundef zeroext i1 @_Zle1AS_(i32 %3, i32 %4) // CHECK:STDOUT: %storedv = zext i1 %call to i8 @@ -365,8 +365,8 @@ fn Driver(x: Cpp.A, y: Cpp.A) { // CHECK:STDOUT: %x.addr = alloca ptr, align 8 // CHECK:STDOUT: %y.addr = alloca ptr, align 8 // CHECK:STDOUT: %return.addr = alloca ptr, align 8 -// CHECK:STDOUT: %agg.tmp = alloca %struct.A, align 4 -// CHECK:STDOUT: %agg.tmp1 = alloca %struct.A, align 4 +// CHECK:STDOUT: %agg.tmp = alloca %struct.A.62, align 4 +// CHECK:STDOUT: %agg.tmp1 = alloca %struct.A.62, align 4 // CHECK:STDOUT: store ptr %x, ptr %x.addr, align 8, !tbaa !21 // CHECK:STDOUT: store ptr %y, ptr %y.addr, align 8, !tbaa !21 // CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !24 @@ -375,9 +375,9 @@ fn Driver(x: Cpp.A, y: Cpp.A) { // CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %agg.tmp, ptr align 4 %1, i64 4, i1 false), !tbaa.struct !26 // CHECK:STDOUT: %2 = load ptr, ptr %y.addr, align 8, !tbaa !21 // CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %agg.tmp1, ptr align 4 %2, i64 4, i1 false), !tbaa.struct !26 -// CHECK:STDOUT: %coerce.dive = getelementptr inbounds nuw %struct.A, ptr %agg.tmp, i32 0, i32 0 +// CHECK:STDOUT: %coerce.dive = getelementptr inbounds nuw %struct.A.62, ptr %agg.tmp, i32 0, i32 0 // CHECK:STDOUT: %3 = load i32, ptr %coerce.dive, align 4 -// CHECK:STDOUT: %coerce.dive2 = getelementptr inbounds nuw %struct.A, ptr %agg.tmp1, i32 0, i32 0 +// CHECK:STDOUT: %coerce.dive2 = getelementptr inbounds nuw %struct.A.62, ptr %agg.tmp1, i32 0, i32 0 // CHECK:STDOUT: %4 = load i32, ptr %coerce.dive2, align 4 // CHECK:STDOUT: %call = call noundef zeroext i1 @_Zgt1AS_(i32 %3, i32 %4) // CHECK:STDOUT: %storedv = zext i1 %call to i8 @@ -391,8 +391,8 @@ fn Driver(x: Cpp.A, y: Cpp.A) { // CHECK:STDOUT: %x.addr = alloca ptr, align 8 // CHECK:STDOUT: %y.addr = alloca ptr, align 8 // CHECK:STDOUT: %return.addr = alloca ptr, align 8 -// CHECK:STDOUT: %agg.tmp = alloca %struct.A, align 4 -// CHECK:STDOUT: %agg.tmp1 = alloca %struct.A, align 4 +// CHECK:STDOUT: %agg.tmp = alloca %struct.A.62, align 4 +// CHECK:STDOUT: %agg.tmp1 = alloca %struct.A.62, align 4 // CHECK:STDOUT: store ptr %x, ptr %x.addr, align 8, !tbaa !21 // CHECK:STDOUT: store ptr %y, ptr %y.addr, align 8, !tbaa !21 // CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !24 @@ -401,9 +401,9 @@ fn Driver(x: Cpp.A, y: Cpp.A) { // CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %agg.tmp, ptr align 4 %1, i64 4, i1 false), !tbaa.struct !26 // CHECK:STDOUT: %2 = load ptr, ptr %y.addr, align 8, !tbaa !21 // CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %agg.tmp1, ptr align 4 %2, i64 4, i1 false), !tbaa.struct !26 -// CHECK:STDOUT: %coerce.dive = getelementptr inbounds nuw %struct.A, ptr %agg.tmp, i32 0, i32 0 +// CHECK:STDOUT: %coerce.dive = getelementptr inbounds nuw %struct.A.62, ptr %agg.tmp, i32 0, i32 0 // CHECK:STDOUT: %3 = load i32, ptr %coerce.dive, align 4 -// CHECK:STDOUT: %coerce.dive2 = getelementptr inbounds nuw %struct.A, ptr %agg.tmp1, i32 0, i32 0 +// CHECK:STDOUT: %coerce.dive2 = getelementptr inbounds nuw %struct.A.62, ptr %agg.tmp1, i32 0, i32 0 // CHECK:STDOUT: %4 = load i32, ptr %coerce.dive2, align 4 // CHECK:STDOUT: %call = call noundef zeroext i1 @_Zge1AS_(i32 %3, i32 %4) // CHECK:STDOUT: %storedv = zext i1 %call to i8 @@ -467,15 +467,15 @@ fn Driver(x: Cpp.A, y: Cpp.A) { // CHECK:STDOUT: ; Function Attrs: mustprogress nounwind uwtable // CHECK:STDOUT: define linkonce_odr dso_local noundef zeroext i1 @_Zlt1AS_(i32 %x.coerce, i32 %y.coerce) #4 comdat { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %x = alloca %struct.A, align 4 -// CHECK:STDOUT: %y = alloca %struct.A, align 4 -// CHECK:STDOUT: %coerce.dive = getelementptr inbounds nuw %struct.A, ptr %x, i32 0, i32 0 +// CHECK:STDOUT: %x = alloca %struct.A.62, align 4 +// CHECK:STDOUT: %y = alloca %struct.A.62, align 4 +// CHECK:STDOUT: %coerce.dive = getelementptr inbounds nuw %struct.A.62, ptr %x, i32 0, i32 0 // CHECK:STDOUT: store i32 %x.coerce, ptr %coerce.dive, align 4 -// CHECK:STDOUT: %coerce.dive1 = getelementptr inbounds nuw %struct.A, ptr %y, i32 0, i32 0 +// CHECK:STDOUT: %coerce.dive1 = getelementptr inbounds nuw %struct.A.62, ptr %y, i32 0, i32 0 // CHECK:STDOUT: store i32 %y.coerce, ptr %coerce.dive1, align 4 -// CHECK:STDOUT: %value = getelementptr inbounds nuw %struct.A, ptr %x, i32 0, i32 0 +// CHECK:STDOUT: %value = getelementptr inbounds nuw %struct.A.62, ptr %x, i32 0, i32 0 // CHECK:STDOUT: %0 = load i32, ptr %value, align 4, !tbaa !61 -// CHECK:STDOUT: %value2 = getelementptr inbounds nuw %struct.A, ptr %y, i32 0, i32 0 +// CHECK:STDOUT: %value2 = getelementptr inbounds nuw %struct.A.62, ptr %y, i32 0, i32 0 // CHECK:STDOUT: %1 = load i32, ptr %value2, align 4, !tbaa !61 // CHECK:STDOUT: %cmp = icmp slt i32 %0, %1 // CHECK:STDOUT: ret i1 %cmp @@ -487,19 +487,19 @@ fn Driver(x: Cpp.A, y: Cpp.A) { // CHECK:STDOUT: ; Function Attrs: mustprogress nounwind uwtable // CHECK:STDOUT: define linkonce_odr dso_local noundef zeroext i1 @_Zle1AS_(i32 %x.coerce, i32 %y.coerce) #4 comdat { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %x = alloca %struct.A, align 4 -// CHECK:STDOUT: %y = alloca %struct.A, align 4 -// CHECK:STDOUT: %agg.tmp = alloca %struct.A, align 4 -// CHECK:STDOUT: %agg.tmp2 = alloca %struct.A, align 4 -// CHECK:STDOUT: %coerce.dive = getelementptr inbounds nuw %struct.A, ptr %x, i32 0, i32 0 +// CHECK:STDOUT: %x = alloca %struct.A.62, align 4 +// CHECK:STDOUT: %y = alloca %struct.A.62, align 4 +// CHECK:STDOUT: %agg.tmp = alloca %struct.A.62, align 4 +// CHECK:STDOUT: %agg.tmp2 = alloca %struct.A.62, align 4 +// CHECK:STDOUT: %coerce.dive = getelementptr inbounds nuw %struct.A.62, ptr %x, i32 0, i32 0 // CHECK:STDOUT: store i32 %x.coerce, ptr %coerce.dive, align 4 -// CHECK:STDOUT: %coerce.dive1 = getelementptr inbounds nuw %struct.A, ptr %y, i32 0, i32 0 +// CHECK:STDOUT: %coerce.dive1 = getelementptr inbounds nuw %struct.A.62, ptr %y, i32 0, i32 0 // CHECK:STDOUT: store i32 %y.coerce, ptr %coerce.dive1, align 4 // CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %agg.tmp, ptr align 4 %y, i64 4, i1 false), !tbaa.struct !26 // CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %agg.tmp2, ptr align 4 %x, i64 4, i1 false), !tbaa.struct !26 -// CHECK:STDOUT: %coerce.dive3 = getelementptr inbounds nuw %struct.A, ptr %agg.tmp, i32 0, i32 0 +// CHECK:STDOUT: %coerce.dive3 = getelementptr inbounds nuw %struct.A.62, ptr %agg.tmp, i32 0, i32 0 // CHECK:STDOUT: %0 = load i32, ptr %coerce.dive3, align 4 -// CHECK:STDOUT: %coerce.dive4 = getelementptr inbounds nuw %struct.A, ptr %agg.tmp2, i32 0, i32 0 +// CHECK:STDOUT: %coerce.dive4 = getelementptr inbounds nuw %struct.A.62, ptr %agg.tmp2, i32 0, i32 0 // CHECK:STDOUT: %1 = load i32, ptr %coerce.dive4, align 4 // CHECK:STDOUT: %call = call noundef zeroext i1 @_Zlt1AS_(i32 %0, i32 %1) // CHECK:STDOUT: %lnot = xor i1 %call, true @@ -509,19 +509,19 @@ fn Driver(x: Cpp.A, y: Cpp.A) { // CHECK:STDOUT: ; Function Attrs: mustprogress nounwind uwtable // CHECK:STDOUT: define linkonce_odr dso_local noundef zeroext i1 @_Zgt1AS_(i32 %x.coerce, i32 %y.coerce) #4 comdat { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %x = alloca %struct.A, align 4 -// CHECK:STDOUT: %y = alloca %struct.A, align 4 -// CHECK:STDOUT: %agg.tmp = alloca %struct.A, align 4 -// CHECK:STDOUT: %agg.tmp2 = alloca %struct.A, align 4 -// CHECK:STDOUT: %coerce.dive = getelementptr inbounds nuw %struct.A, ptr %x, i32 0, i32 0 +// CHECK:STDOUT: %x = alloca %struct.A.62, align 4 +// CHECK:STDOUT: %y = alloca %struct.A.62, align 4 +// CHECK:STDOUT: %agg.tmp = alloca %struct.A.62, align 4 +// CHECK:STDOUT: %agg.tmp2 = alloca %struct.A.62, align 4 +// CHECK:STDOUT: %coerce.dive = getelementptr inbounds nuw %struct.A.62, ptr %x, i32 0, i32 0 // CHECK:STDOUT: store i32 %x.coerce, ptr %coerce.dive, align 4 -// CHECK:STDOUT: %coerce.dive1 = getelementptr inbounds nuw %struct.A, ptr %y, i32 0, i32 0 +// CHECK:STDOUT: %coerce.dive1 = getelementptr inbounds nuw %struct.A.62, ptr %y, i32 0, i32 0 // CHECK:STDOUT: store i32 %y.coerce, ptr %coerce.dive1, align 4 // CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %agg.tmp, ptr align 4 %y, i64 4, i1 false), !tbaa.struct !26 // CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %agg.tmp2, ptr align 4 %x, i64 4, i1 false), !tbaa.struct !26 -// CHECK:STDOUT: %coerce.dive3 = getelementptr inbounds nuw %struct.A, ptr %agg.tmp, i32 0, i32 0 +// CHECK:STDOUT: %coerce.dive3 = getelementptr inbounds nuw %struct.A.62, ptr %agg.tmp, i32 0, i32 0 // CHECK:STDOUT: %0 = load i32, ptr %coerce.dive3, align 4 -// CHECK:STDOUT: %coerce.dive4 = getelementptr inbounds nuw %struct.A, ptr %agg.tmp2, i32 0, i32 0 +// CHECK:STDOUT: %coerce.dive4 = getelementptr inbounds nuw %struct.A.62, ptr %agg.tmp2, i32 0, i32 0 // CHECK:STDOUT: %1 = load i32, ptr %coerce.dive4, align 4 // CHECK:STDOUT: %call = call noundef zeroext i1 @_Zlt1AS_(i32 %0, i32 %1) // CHECK:STDOUT: ret i1 %call @@ -530,19 +530,19 @@ fn Driver(x: Cpp.A, y: Cpp.A) { // CHECK:STDOUT: ; Function Attrs: mustprogress nounwind uwtable // CHECK:STDOUT: define linkonce_odr dso_local noundef zeroext i1 @_Zge1AS_(i32 %x.coerce, i32 %y.coerce) #4 comdat { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %x = alloca %struct.A, align 4 -// CHECK:STDOUT: %y = alloca %struct.A, align 4 -// CHECK:STDOUT: %agg.tmp = alloca %struct.A, align 4 -// CHECK:STDOUT: %agg.tmp2 = alloca %struct.A, align 4 -// CHECK:STDOUT: %coerce.dive = getelementptr inbounds nuw %struct.A, ptr %x, i32 0, i32 0 +// CHECK:STDOUT: %x = alloca %struct.A.62, align 4 +// CHECK:STDOUT: %y = alloca %struct.A.62, align 4 +// CHECK:STDOUT: %agg.tmp = alloca %struct.A.62, align 4 +// CHECK:STDOUT: %agg.tmp2 = alloca %struct.A.62, align 4 +// CHECK:STDOUT: %coerce.dive = getelementptr inbounds nuw %struct.A.62, ptr %x, i32 0, i32 0 // CHECK:STDOUT: store i32 %x.coerce, ptr %coerce.dive, align 4 -// CHECK:STDOUT: %coerce.dive1 = getelementptr inbounds nuw %struct.A, ptr %y, i32 0, i32 0 +// CHECK:STDOUT: %coerce.dive1 = getelementptr inbounds nuw %struct.A.62, ptr %y, i32 0, i32 0 // CHECK:STDOUT: store i32 %y.coerce, ptr %coerce.dive1, align 4 // CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %agg.tmp, ptr align 4 %x, i64 4, i1 false), !tbaa.struct !26 // CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %agg.tmp2, ptr align 4 %y, i64 4, i1 false), !tbaa.struct !26 -// CHECK:STDOUT: %coerce.dive3 = getelementptr inbounds nuw %struct.A, ptr %agg.tmp, i32 0, i32 0 +// CHECK:STDOUT: %coerce.dive3 = getelementptr inbounds nuw %struct.A.62, ptr %agg.tmp, i32 0, i32 0 // CHECK:STDOUT: %0 = load i32, ptr %coerce.dive3, align 4 -// CHECK:STDOUT: %coerce.dive4 = getelementptr inbounds nuw %struct.A, ptr %agg.tmp2, i32 0, i32 0 +// CHECK:STDOUT: %coerce.dive4 = getelementptr inbounds nuw %struct.A.62, ptr %agg.tmp2, i32 0, i32 0 // CHECK:STDOUT: %1 = load i32, ptr %coerce.dive4, align 4 // CHECK:STDOUT: %call = call noundef zeroext i1 @_Zlt1AS_(i32 %0, i32 %1) // CHECK:STDOUT: %lnot = xor i1 %call, true diff --git a/toolchain/lower/testdata/interop/cpp/reference.carbon b/toolchain/lower/testdata/interop/cpp/reference.carbon index 0527ddcd7764..b195c43b3b60 100644 --- a/toolchain/lower/testdata/interop/cpp/reference.carbon +++ b/toolchain/lower/testdata/interop/cpp/reference.carbon @@ -599,7 +599,7 @@ fn GetRefs() { // 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: %class.ForceThunk = type { i8 } +// CHECK:STDOUT: %class.ForceThunk.23 = type { i8 } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind // CHECK:STDOUT: define void @_CGetRefs.Main() #0 !dbg !12 { @@ -616,7 +616,7 @@ fn GetRefs() { // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable // CHECK:STDOUT: define internal noundef nonnull align 1 dereferenceable(1) ptr @_Z10ReturnCRef10ForceThunk.carbon_thunk.() #1 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %agg.tmp = alloca %class.ForceThunk, align 1 +// CHECK:STDOUT: %agg.tmp = alloca %class.ForceThunk.23, align 1 // CHECK:STDOUT: %call = call noundef nonnull align 1 dereferenceable(1) ptr @_Z10ReturnCRef10ForceThunk() // CHECK:STDOUT: ret ptr %call // CHECK:STDOUT: } @@ -624,7 +624,7 @@ fn GetRefs() { // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable // CHECK:STDOUT: define internal noundef nonnull align 1 dereferenceable(1) ptr @_Z11ReturnCRRef10ForceThunk.carbon_thunk.() #1 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %agg.tmp = alloca %class.ForceThunk, align 1 +// CHECK:STDOUT: %agg.tmp = alloca %class.ForceThunk.23, align 1 // CHECK:STDOUT: %call = call noundef nonnull align 1 dereferenceable(1) ptr @_Z11ReturnCRRef10ForceThunk() // CHECK:STDOUT: ret ptr %call // CHECK:STDOUT: } @@ -632,7 +632,7 @@ fn GetRefs() { // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable // CHECK:STDOUT: define internal noundef nonnull align 1 dereferenceable(1) ptr @_Z15ReturnConstCRef10ForceThunk.carbon_thunk.() #1 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %agg.tmp = alloca %class.ForceThunk, align 1 +// CHECK:STDOUT: %agg.tmp = alloca %class.ForceThunk.23, align 1 // CHECK:STDOUT: %call = call noundef nonnull align 1 dereferenceable(1) ptr @_Z15ReturnConstCRef10ForceThunk() // CHECK:STDOUT: ret ptr %call // CHECK:STDOUT: } @@ -640,7 +640,7 @@ fn GetRefs() { // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable // CHECK:STDOUT: define internal noundef nonnull align 4 dereferenceable(4) ptr @_Z12ReturnIntRef10ForceThunk.carbon_thunk.() #1 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %agg.tmp = alloca %class.ForceThunk, align 1 +// CHECK:STDOUT: %agg.tmp = alloca %class.ForceThunk.23, align 1 // CHECK:STDOUT: %call = call noundef nonnull align 4 dereferenceable(4) ptr @_Z12ReturnIntRef10ForceThunk() // CHECK:STDOUT: ret ptr %call // CHECK:STDOUT: } @@ -648,7 +648,7 @@ fn GetRefs() { // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable // CHECK:STDOUT: define internal noundef nonnull align 4 dereferenceable(4) ptr @_Z13ReturnIntRRef10ForceThunk.carbon_thunk.() #1 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %agg.tmp = alloca %class.ForceThunk, align 1 +// CHECK:STDOUT: %agg.tmp = alloca %class.ForceThunk.23, align 1 // CHECK:STDOUT: %call = call noundef nonnull align 4 dereferenceable(4) ptr @_Z13ReturnIntRRef10ForceThunk() // CHECK:STDOUT: ret ptr %call // CHECK:STDOUT: } @@ -656,7 +656,7 @@ fn GetRefs() { // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable // CHECK:STDOUT: define internal noundef nonnull align 4 dereferenceable(4) ptr @_Z17ReturnConstIntRef10ForceThunk.carbon_thunk.() #1 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %agg.tmp = alloca %class.ForceThunk, align 1 +// CHECK:STDOUT: %agg.tmp = alloca %class.ForceThunk.23, align 1 // CHECK:STDOUT: %call = call noundef nonnull align 4 dereferenceable(4) ptr @_Z17ReturnConstIntRef10ForceThunk() // CHECK:STDOUT: ret ptr %call // CHECK:STDOUT: } diff --git a/toolchain/lower/testdata/interop/cpp/share_ast.carbon b/toolchain/lower/testdata/interop/cpp/share_ast.carbon new file mode 100644 index 000000000000..a0505dc25f11 --- /dev/null +++ b/toolchain/lower/testdata/interop/cpp/share_ast.carbon @@ -0,0 +1,364 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/primitives.carbon +// EXTRA-ARGS: --share-cpp-ast +// +// AUTOUPDATE +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/lower/testdata/interop/cpp/share_ast.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/lower/testdata/interop/cpp/share_ast.carbon + +// --- a.h +#ifndef A_H +#define A_H +struct A { + int a, b; +}; +inline A make_a() { return {1, 2}; } +#endif + +// --- b.h +#ifndef B_H +#define B_H +struct B { + int x, y; +}; +inline B make_b() { return {3, 4}; } +#endif + +// --- use_a.carbon +library "[[@TEST_NAME]]"; +import Cpp library "a.h"; + +fn Test() -> i32 { + var a: Cpp.A = Cpp.make_a(); + return a.b; +} + +// --- use_b.carbon +library "[[@TEST_NAME]]"; +import Cpp library "b.h"; + +fn Test() -> i32 { + var b: Cpp.B = Cpp.make_b(); + return b.x; +} + +// --- use_both.carbon +library "[[@TEST_NAME]]"; +import Cpp library "a.h"; +import Cpp library "b.h"; + +fn TestA() -> i32 { + var a: Cpp.A = Cpp.make_a(); + return a.b; +} + +fn TestB() -> i32 { + var b: Cpp.B = Cpp.make_b(); + return b.x; +} + + +// CHECK:STDOUT: ; --- +// CHECK:STDOUT: ; ModuleID = 'use_a.carbon' +// CHECK:STDOUT: source_filename = "use_a.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: %struct.A = type { i32, i32 } +// CHECK:STDOUT: +// CHECK:STDOUT: $_Z6make_av = comdat any +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define i32 @_CTest.Main() #0 !dbg !12 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %a.var = alloca [8 x i8], align 4, !dbg !16 +// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %a.var), !dbg !16 +// CHECK:STDOUT: call void @_Z6make_av.carbon_thunk.(ptr %a.var), !dbg !17 +// CHECK:STDOUT: %.loc6_11.1.b = getelementptr inbounds nuw [8 x i8], ptr %a.var, i32 0, i32 4, !dbg !18 +// CHECK:STDOUT: %.loc6_11.2 = load i32, ptr %.loc6_11.1.b, align 4, !dbg !18 +// CHECK:STDOUT: ret i32 %.loc6_11.2, !dbg !19 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable +// CHECK:STDOUT: define internal void @_Z6make_av.carbon_thunk.(ptr noundef %return) #1 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %return.addr = alloca ptr, align 8 +// CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !20 +// CHECK:STDOUT: %0 = load ptr, ptr %return.addr, align 8, !tbaa !20 +// CHECK:STDOUT: %call = call i64 @_Z6make_av() +// CHECK:STDOUT: store i64 %call, ptr %0, align 4 +// CHECK:STDOUT: ret void +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) +// CHECK:STDOUT: declare void @llvm.lifetime.start.p0(ptr captures(none)) #2 +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: inlinehint mustprogress nounwind uwtable +// CHECK:STDOUT: define linkonce_odr dso_local i64 @_Z6make_av() #3 comdat { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %retval = alloca %struct.A, align 4 +// CHECK:STDOUT: %a = getelementptr inbounds nuw %struct.A, ptr %retval, i32 0, i32 0 +// CHECK:STDOUT: store i32 1, ptr %a, align 4, !tbaa !23 +// CHECK:STDOUT: %b = getelementptr inbounds nuw %struct.A, ptr %retval, i32 0, i32 1 +// CHECK:STDOUT: store i32 2, ptr %b, align 4, !tbaa !25 +// CHECK:STDOUT: %0 = load i64, ptr %retval, align 4 +// CHECK:STDOUT: ret i64 %0 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: attributes #0 = { nounwind } +// CHECK:STDOUT: attributes #1 = { alwaysinline mustprogress uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +// CHECK:STDOUT: attributes #2 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) } +// CHECK:STDOUT: attributes #3 = { inlinehint mustprogress nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +// CHECK:STDOUT: +// CHECK:STDOUT: !llvm.dbg.cu = !{!0} +// CHECK:STDOUT: !llvm.module.flags = !{!2, !3, !4, !5, !6} +// CHECK:STDOUT: !llvm.errno.tbaa = !{!7} +// CHECK:STDOUT: +// CHECK:STDOUT: !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) +// CHECK:STDOUT: !1 = !DIFile(filename: "use_a.carbon", directory: "") +// CHECK:STDOUT: !2 = !{i32 8, !"PIC Level", i32 2} +// CHECK:STDOUT: !3 = !{i32 7, !"PIE Level", i32 2} +// CHECK:STDOUT: !4 = !{i32 7, !"uwtable", i32 2} +// CHECK:STDOUT: !5 = !{i32 7, !"Dwarf Version", i32 5} +// CHECK:STDOUT: !6 = !{i32 2, !"Debug Info Version", i32 3} +// CHECK:STDOUT: !7 = !{!8, !9, i64 0} +// CHECK:STDOUT: !8 = !{!"__libc_errno", !9, i64 0} +// CHECK:STDOUT: !9 = !{!"int", !10, i64 0} +// CHECK:STDOUT: !10 = !{!"omnipotent char", !11, i64 0} +// CHECK:STDOUT: !11 = !{!"Simple C++ TBAA"} +// CHECK:STDOUT: !12 = distinct !DISubprogram(name: "Test", linkageName: "_CTest.Main", scope: null, file: !1, line: 4, type: !13, spFlags: DISPFlagDefinition, unit: !0) +// CHECK:STDOUT: !13 = !DISubroutineType(types: !14) +// CHECK:STDOUT: !14 = !{!15} +// CHECK:STDOUT: !15 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +// CHECK:STDOUT: !16 = !DILocation(line: 5, column: 3, scope: !12) +// CHECK:STDOUT: !17 = !DILocation(line: 5, column: 18, scope: !12) +// CHECK:STDOUT: !18 = !DILocation(line: 6, column: 10, scope: !12) +// CHECK:STDOUT: !19 = !DILocation(line: 6, column: 3, scope: !12) +// CHECK:STDOUT: !20 = !{!21, !21, i64 0} +// CHECK:STDOUT: !21 = !{!"p1 _ZTS1A", !22, i64 0} +// CHECK:STDOUT: !22 = !{!"any pointer", !10, i64 0} +// CHECK:STDOUT: !23 = !{!24, !9, i64 0} +// CHECK:STDOUT: !24 = !{!"_ZTS1A", !9, i64 0, !9, i64 4} +// CHECK:STDOUT: !25 = !{!24, !9, i64 4} +// CHECK:STDOUT: +// CHECK:STDOUT: ; --- +// CHECK:STDOUT: ; ModuleID = 'use_b.carbon' +// CHECK:STDOUT: source_filename = "use_b.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: %struct.B = type { i32, i32 } +// CHECK:STDOUT: +// CHECK:STDOUT: $_Z6make_bv = comdat any +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define i32 @_CTest.Main() #0 !dbg !12 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %b.var = alloca [8 x i8], align 4, !dbg !16 +// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %b.var), !dbg !16 +// CHECK:STDOUT: call void @_Z6make_bv.carbon_thunk.(ptr %b.var), !dbg !17 +// CHECK:STDOUT: %.loc6_11.1.x = getelementptr inbounds nuw [8 x i8], ptr %b.var, i32 0, i32 0, !dbg !18 +// CHECK:STDOUT: %.loc6_11.2 = load i32, ptr %.loc6_11.1.x, align 4, !dbg !18 +// CHECK:STDOUT: ret i32 %.loc6_11.2, !dbg !19 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable +// CHECK:STDOUT: define internal void @_Z6make_bv.carbon_thunk.(ptr noundef %return) #1 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %return.addr = alloca ptr, align 8 +// CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !20 +// CHECK:STDOUT: %0 = load ptr, ptr %return.addr, align 8, !tbaa !20 +// CHECK:STDOUT: %call = call i64 @_Z6make_bv() +// CHECK:STDOUT: store i64 %call, ptr %0, align 4 +// CHECK:STDOUT: ret void +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) +// CHECK:STDOUT: declare void @llvm.lifetime.start.p0(ptr captures(none)) #2 +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: inlinehint mustprogress nounwind uwtable +// CHECK:STDOUT: define linkonce_odr dso_local i64 @_Z6make_bv() #3 comdat { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %retval = alloca %struct.B, align 4 +// CHECK:STDOUT: %x = getelementptr inbounds nuw %struct.B, ptr %retval, i32 0, i32 0 +// CHECK:STDOUT: store i32 3, ptr %x, align 4, !tbaa !23 +// CHECK:STDOUT: %y = getelementptr inbounds nuw %struct.B, ptr %retval, i32 0, i32 1 +// CHECK:STDOUT: store i32 4, ptr %y, align 4, !tbaa !25 +// CHECK:STDOUT: %0 = load i64, ptr %retval, align 4 +// CHECK:STDOUT: ret i64 %0 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: attributes #0 = { nounwind } +// CHECK:STDOUT: attributes #1 = { alwaysinline mustprogress uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +// CHECK:STDOUT: attributes #2 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) } +// CHECK:STDOUT: attributes #3 = { inlinehint mustprogress nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +// CHECK:STDOUT: +// CHECK:STDOUT: !llvm.dbg.cu = !{!0} +// CHECK:STDOUT: !llvm.module.flags = !{!2, !3, !4, !5, !6} +// CHECK:STDOUT: !llvm.errno.tbaa = !{!7} +// CHECK:STDOUT: +// CHECK:STDOUT: !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) +// CHECK:STDOUT: !1 = !DIFile(filename: "use_b.carbon", directory: "") +// CHECK:STDOUT: !2 = !{i32 8, !"PIC Level", i32 2} +// CHECK:STDOUT: !3 = !{i32 7, !"PIE Level", i32 2} +// CHECK:STDOUT: !4 = !{i32 7, !"uwtable", i32 2} +// CHECK:STDOUT: !5 = !{i32 7, !"Dwarf Version", i32 5} +// CHECK:STDOUT: !6 = !{i32 2, !"Debug Info Version", i32 3} +// CHECK:STDOUT: !7 = !{!8, !9, i64 0} +// CHECK:STDOUT: !8 = !{!"__libc_errno", !9, i64 0} +// CHECK:STDOUT: !9 = !{!"int", !10, i64 0} +// CHECK:STDOUT: !10 = !{!"omnipotent char", !11, i64 0} +// CHECK:STDOUT: !11 = !{!"Simple C++ TBAA"} +// CHECK:STDOUT: !12 = distinct !DISubprogram(name: "Test", linkageName: "_CTest.Main", scope: null, file: !1, line: 4, type: !13, spFlags: DISPFlagDefinition, unit: !0) +// CHECK:STDOUT: !13 = !DISubroutineType(types: !14) +// CHECK:STDOUT: !14 = !{!15} +// CHECK:STDOUT: !15 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +// CHECK:STDOUT: !16 = !DILocation(line: 5, column: 3, scope: !12) +// CHECK:STDOUT: !17 = !DILocation(line: 5, column: 18, scope: !12) +// CHECK:STDOUT: !18 = !DILocation(line: 6, column: 10, scope: !12) +// CHECK:STDOUT: !19 = !DILocation(line: 6, column: 3, scope: !12) +// CHECK:STDOUT: !20 = !{!21, !21, i64 0} +// CHECK:STDOUT: !21 = !{!"p1 _ZTS1B", !22, i64 0} +// CHECK:STDOUT: !22 = !{!"any pointer", !10, i64 0} +// CHECK:STDOUT: !23 = !{!24, !9, i64 0} +// CHECK:STDOUT: !24 = !{!"_ZTS1B", !9, i64 0, !9, i64 4} +// CHECK:STDOUT: !25 = !{!24, !9, i64 4} +// CHECK:STDOUT: +// CHECK:STDOUT: ; --- +// CHECK:STDOUT: ; ModuleID = 'use_both.carbon' +// CHECK:STDOUT: source_filename = "use_both.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: %struct.A.32 = type { i32, i32 } +// CHECK:STDOUT: %struct.B.33 = type { i32, i32 } +// CHECK:STDOUT: +// CHECK:STDOUT: $_Z6make_av = comdat any +// CHECK:STDOUT: +// CHECK:STDOUT: $_Z6make_bv = comdat any +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define i32 @_CTestA.Main() #0 !dbg !12 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %a.var = alloca [8 x i8], align 4, !dbg !16 +// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %a.var), !dbg !16 +// CHECK:STDOUT: call void @_Z6make_av.carbon_thunk.(ptr %a.var), !dbg !17 +// CHECK:STDOUT: %.loc7_11.1.b = getelementptr inbounds nuw [8 x i8], ptr %a.var, i32 0, i32 4, !dbg !18 +// CHECK:STDOUT: %.loc7_11.2 = load i32, ptr %.loc7_11.1.b, align 4, !dbg !18 +// CHECK:STDOUT: ret i32 %.loc7_11.2, !dbg !19 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable +// CHECK:STDOUT: define internal void @_Z6make_av.carbon_thunk.(ptr noundef %return) #1 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %return.addr = alloca ptr, align 8 +// CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !20 +// CHECK:STDOUT: %0 = load ptr, ptr %return.addr, align 8, !tbaa !20 +// CHECK:STDOUT: %call = call i64 @_Z6make_av() +// CHECK:STDOUT: store i64 %call, ptr %0, align 4 +// CHECK:STDOUT: ret void +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define i32 @_CTestB.Main() #0 !dbg !23 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %b.var = alloca [8 x i8], align 4, !dbg !24 +// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %b.var), !dbg !24 +// CHECK:STDOUT: call void @_Z6make_bv.carbon_thunk.(ptr %b.var), !dbg !25 +// CHECK:STDOUT: %.loc12_11.1.x = getelementptr inbounds nuw [8 x i8], ptr %b.var, i32 0, i32 0, !dbg !26 +// CHECK:STDOUT: %.loc12_11.2 = load i32, ptr %.loc12_11.1.x, align 4, !dbg !26 +// CHECK:STDOUT: ret i32 %.loc12_11.2, !dbg !27 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable +// CHECK:STDOUT: define internal void @_Z6make_bv.carbon_thunk.(ptr noundef %return) #1 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %return.addr = alloca ptr, align 8 +// CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !28 +// CHECK:STDOUT: %0 = load ptr, ptr %return.addr, align 8, !tbaa !28 +// CHECK:STDOUT: %call = call i64 @_Z6make_bv() +// CHECK:STDOUT: store i64 %call, ptr %0, align 4 +// CHECK:STDOUT: ret void +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) +// CHECK:STDOUT: declare void @llvm.lifetime.start.p0(ptr captures(none)) #2 +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: inlinehint mustprogress nounwind uwtable +// CHECK:STDOUT: define linkonce_odr dso_local i64 @_Z6make_av() #3 comdat { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %retval = alloca %struct.A.32, align 4 +// CHECK:STDOUT: %a = getelementptr inbounds nuw %struct.A.32, ptr %retval, i32 0, i32 0 +// CHECK:STDOUT: store i32 1, ptr %a, align 4, !tbaa !30 +// CHECK:STDOUT: %b = getelementptr inbounds nuw %struct.A.32, ptr %retval, i32 0, i32 1 +// CHECK:STDOUT: store i32 2, ptr %b, align 4, !tbaa !32 +// CHECK:STDOUT: %0 = load i64, ptr %retval, align 4 +// CHECK:STDOUT: ret i64 %0 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: inlinehint mustprogress nounwind uwtable +// CHECK:STDOUT: define linkonce_odr dso_local i64 @_Z6make_bv() #3 comdat { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %retval = alloca %struct.B.33, align 4 +// CHECK:STDOUT: %x = getelementptr inbounds nuw %struct.B.33, ptr %retval, i32 0, i32 0 +// CHECK:STDOUT: store i32 3, ptr %x, align 4, !tbaa !33 +// CHECK:STDOUT: %y = getelementptr inbounds nuw %struct.B.33, ptr %retval, i32 0, i32 1 +// CHECK:STDOUT: store i32 4, ptr %y, align 4, !tbaa !35 +// CHECK:STDOUT: %0 = load i64, ptr %retval, align 4 +// CHECK:STDOUT: ret i64 %0 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; uselistorder directives +// CHECK:STDOUT: uselistorder ptr @llvm.lifetime.start.p0, { 1, 0 } +// CHECK:STDOUT: +// CHECK:STDOUT: attributes #0 = { nounwind } +// CHECK:STDOUT: attributes #1 = { alwaysinline mustprogress uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +// CHECK:STDOUT: attributes #2 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) } +// CHECK:STDOUT: attributes #3 = { inlinehint mustprogress nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +// CHECK:STDOUT: +// CHECK:STDOUT: !llvm.dbg.cu = !{!0} +// CHECK:STDOUT: !llvm.module.flags = !{!2, !3, !4, !5, !6} +// CHECK:STDOUT: !llvm.errno.tbaa = !{!7} +// CHECK:STDOUT: +// CHECK:STDOUT: !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) +// CHECK:STDOUT: !1 = !DIFile(filename: "use_both.carbon", directory: "") +// CHECK:STDOUT: !2 = !{i32 8, !"PIC Level", i32 2} +// CHECK:STDOUT: !3 = !{i32 7, !"PIE Level", i32 2} +// CHECK:STDOUT: !4 = !{i32 7, !"uwtable", i32 2} +// CHECK:STDOUT: !5 = !{i32 7, !"Dwarf Version", i32 5} +// CHECK:STDOUT: !6 = !{i32 2, !"Debug Info Version", i32 3} +// CHECK:STDOUT: !7 = !{!8, !9, i64 0} +// CHECK:STDOUT: !8 = !{!"__libc_errno", !9, i64 0} +// CHECK:STDOUT: !9 = !{!"int", !10, i64 0} +// CHECK:STDOUT: !10 = !{!"omnipotent char", !11, i64 0} +// CHECK:STDOUT: !11 = !{!"Simple C++ TBAA"} +// CHECK:STDOUT: !12 = distinct !DISubprogram(name: "TestA", linkageName: "_CTestA.Main", scope: null, file: !1, line: 5, type: !13, spFlags: DISPFlagDefinition, unit: !0) +// CHECK:STDOUT: !13 = !DISubroutineType(types: !14) +// CHECK:STDOUT: !14 = !{!15} +// CHECK:STDOUT: !15 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +// CHECK:STDOUT: !16 = !DILocation(line: 6, column: 3, scope: !12) +// CHECK:STDOUT: !17 = !DILocation(line: 6, column: 18, scope: !12) +// CHECK:STDOUT: !18 = !DILocation(line: 7, column: 10, scope: !12) +// CHECK:STDOUT: !19 = !DILocation(line: 7, column: 3, scope: !12) +// CHECK:STDOUT: !20 = !{!21, !21, i64 0} +// CHECK:STDOUT: !21 = !{!"p1 _ZTS1A", !22, i64 0} +// CHECK:STDOUT: !22 = !{!"any pointer", !10, i64 0} +// CHECK:STDOUT: !23 = distinct !DISubprogram(name: "TestB", linkageName: "_CTestB.Main", scope: null, file: !1, line: 10, type: !13, spFlags: DISPFlagDefinition, unit: !0) +// CHECK:STDOUT: !24 = !DILocation(line: 11, column: 3, scope: !23) +// CHECK:STDOUT: !25 = !DILocation(line: 11, column: 18, scope: !23) +// CHECK:STDOUT: !26 = !DILocation(line: 12, column: 10, scope: !23) +// CHECK:STDOUT: !27 = !DILocation(line: 12, column: 3, scope: !23) +// CHECK:STDOUT: !28 = !{!29, !29, i64 0} +// CHECK:STDOUT: !29 = !{!"p1 _ZTS1B", !22, i64 0} +// CHECK:STDOUT: !30 = !{!31, !9, i64 0} +// CHECK:STDOUT: !31 = !{!"_ZTS1A", !9, i64 0, !9, i64 4} +// CHECK:STDOUT: !32 = !{!31, !9, i64 4} +// CHECK:STDOUT: !33 = !{!34, !9, i64 0} +// CHECK:STDOUT: !34 = !{!"_ZTS1B", !9, i64 0, !9, i64 4} +// CHECK:STDOUT: !35 = !{!34, !9, i64 4} +// CHECK:STDOUT: diff --git a/toolchain/lower/testdata/interop/cpp/std_initializer_list.carbon b/toolchain/lower/testdata/interop/cpp/std_initializer_list.carbon index 11571025a4ef..dd0d76773517 100644 --- a/toolchain/lower/testdata/interop/cpp/std_initializer_list.carbon +++ b/toolchain/lower/testdata/interop/cpp/std_initializer_list.carbon @@ -368,7 +368,7 @@ fn InitNontrivialDtor() { // 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: %"class.std::initializer_list" = type { ptr, i64 } +// CHECK:STDOUT: %"class.std::initializer_list.64" = type { ptr, i64 } // CHECK:STDOUT: // CHECK:STDOUT: $_ZN11vector_likeD2Ev = comdat any // CHECK:STDOUT: @@ -442,7 +442,7 @@ fn InitNontrivialDtor() { // CHECK:STDOUT: entry: // CHECK:STDOUT: %list.addr = alloca ptr, align 8 // CHECK:STDOUT: %return.addr = alloca ptr, align 8 -// CHECK:STDOUT: %agg.tmp = alloca %"class.std::initializer_list", align 8 +// CHECK:STDOUT: %agg.tmp = alloca %"class.std::initializer_list.64", align 8 // CHECK:STDOUT: store ptr %list, ptr %list.addr, align 8, !tbaa !38 // CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !41 // CHECK:STDOUT: %0 = load ptr, ptr %return.addr, align 8, !tbaa !41 @@ -521,7 +521,7 @@ fn InitNontrivialDtor() { // CHECK:STDOUT: ; Function Attrs: mustprogress nounwind uwtable // CHECK:STDOUT: define linkonce_odr dso_local void @_ZN11vector_likeC2ESt16initializer_listIiE(ptr noundef nonnull align 1 dereferenceable(1) %this, ptr %list.coerce0, i64 %list.coerce1) unnamed_addr #2 comdat align 2 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %list = alloca %"class.std::initializer_list", align 8 +// CHECK:STDOUT: %list = alloca %"class.std::initializer_list.64", align 8 // CHECK:STDOUT: %this.addr = alloca ptr, align 8 // CHECK:STDOUT: %0 = getelementptr inbounds nuw { ptr, i64 }, ptr %list, i32 0, i32 0 // CHECK:STDOUT: store ptr %list.coerce0, ptr %0, align 8 diff --git a/toolchain/lower/testdata/primitives/type_values.carbon b/toolchain/lower/testdata/primitives/type_values.carbon index e689b5e65744..e9be58a34b96 100644 --- a/toolchain/lower/testdata/primitives/type_values.carbon +++ b/toolchain/lower/testdata/primitives/type_values.carbon @@ -29,24 +29,24 @@ fn F64() -> type { // CHECK:STDOUT: ; ModuleID = 'type_values.carbon' // CHECK:STDOUT: source_filename = "type_values.carbon" // CHECK:STDOUT: -// CHECK:STDOUT: %type = type {} +// CHECK:STDOUT: %type.26 = type {} // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind -// CHECK:STDOUT: define %type @_CI32.Main() #0 !dbg !4 { +// CHECK:STDOUT: define %type.26 @_CI32.Main() #0 !dbg !4 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: ret %type zeroinitializer, !dbg !8 +// CHECK:STDOUT: ret %type.26 zeroinitializer, !dbg !8 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind -// CHECK:STDOUT: define %type @_CI48.Main() #0 !dbg !9 { +// CHECK:STDOUT: define %type.26 @_CI48.Main() #0 !dbg !9 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: ret %type zeroinitializer, !dbg !10 +// CHECK:STDOUT: ret %type.26 zeroinitializer, !dbg !10 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind -// CHECK:STDOUT: define %type @_CF64.Main() #0 !dbg !11 { +// CHECK:STDOUT: define %type.26 @_CF64.Main() #0 !dbg !11 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: ret %type zeroinitializer, !dbg !12 +// CHECK:STDOUT: ret %type.26 zeroinitializer, !dbg !12 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: attributes #0 = { nounwind } diff --git a/toolchain/sem_ir/cpp_file.cpp b/toolchain/sem_ir/cpp_file.cpp index f7e97a3d50c6..dabbfcc62b6c 100644 --- a/toolchain/sem_ir/cpp_file.cpp +++ b/toolchain/sem_ir/cpp_file.cpp @@ -12,8 +12,13 @@ namespace Carbon::SemIR { CppFile::CppFile(std::shared_ptr clang, - llvm::LLVMContext* llvm_context) - : clang_(std::move(clang)), llvm_context_(llvm_context) {} + std::unique_ptr mangle_context, + llvm::LLVMContext* llvm_context, + clang::CodeGenerator* code_generator) + : clang_(std::move(clang)), + mangle_context_(std::move(mangle_context)), + llvm_context_(llvm_context), + code_generator_(code_generator) {} CppFile::~CppFile() = default; @@ -45,11 +50,6 @@ auto CppFile::ast_context() const -> const clang::ASTContext& { return clang_->getASTContext(); } -auto CppFile::CreateMangleContext() -> void { - CARBON_CHECK(!mangle_context_); - mangle_context_.reset(ast_context().createMangleContext()); -} - auto CppFile::mangle_context() const -> clang::MangleContext& { return *mangle_context_; } diff --git a/toolchain/sem_ir/cpp_file.h b/toolchain/sem_ir/cpp_file.h index ecab3f701a2d..a046f1af71fb 100644 --- a/toolchain/sem_ir/cpp_file.h +++ b/toolchain/sem_ir/cpp_file.h @@ -29,7 +29,9 @@ namespace Carbon::SemIR { class CppFile { public: explicit CppFile(std::shared_ptr clang, - llvm::LLVMContext* llvm_context); + std::unique_ptr mangle_context, + llvm::LLVMContext* llvm_context, + clang::CodeGenerator* code_generator); ~CppFile(); // Access to compilation options. @@ -47,28 +49,18 @@ class CppFile { auto ast_context() -> clang::ASTContext&; auto ast_context() const -> const clang::ASTContext&; - // Creates the mangle context for this file's C++ AST. Must be called once the - // AST context is available (after the frontend begins the source file) and - // before `mangle_context()` is used. - auto CreateMangleContext() -> void; auto mangle_context() const -> clang::MangleContext&; auto llvm_context() const -> llvm::LLVMContext* { return llvm_context_; } - auto SetCodeGenerator(clang::CodeGenerator* code_generator) -> void { - code_generator_ = code_generator; - } - auto GetCodeGenerator() const -> clang::CodeGenerator* { - // Clang code generation should not actually modify the AST, but isn't - // const-correct. + auto code_generator() const -> clang::CodeGenerator* { return code_generator_; } private: std::shared_ptr clang_; - llvm::LLVMContext* llvm_context_; - clang::CodeGenerator* code_generator_ = nullptr; - // Created by `CreateMangleContext()` once the AST context is available. std::unique_ptr mangle_context_; + llvm::LLVMContext* llvm_context_; + clang::CodeGenerator* code_generator_; }; } // namespace Carbon::SemIR diff --git a/toolchain/sem_ir/mangler.cpp b/toolchain/sem_ir/mangler.cpp index 4dfc3900323a..7f49b410b1a8 100644 --- a/toolchain/sem_ir/mangler.cpp +++ b/toolchain/sem_ir/mangler.cpp @@ -271,7 +271,7 @@ auto Mangler::MangleWithPlatform(SemIR::FunctionId function_id, // The only platform mangling that's relevant for us is applying a global // prefix, if the platform has one. if (char prefix = sem_ir_.cpp_file() - ->GetCodeGenerator() + ->code_generator() ->GetModule() ->getDataLayout() .getGlobalPrefix()) {