mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 19:40:10 +01:00
Fix C++ code generation in --share-cpp-ast mode (#7605)
Instead of creating a CodeGenerator per CppDomain, and then crashing in lowering when we try to consume the same llvm Module multiple times, create a CodeGenerator for each CppFile within the domain. For now, we mulitplex all of Clang's ASTConsumer output to all code generators, which means that any strong external definitions within a Carbon file (for example, in an inline `Cpp` fragment) will be emitted to all output files in the same `CppDomain`, resulting in link errors due to symbol redefinitions. This will be addressed later. But this should be sufficient for Carbon compilations in which such symbols are not defined. We also don't yet attempt to classify which compilations will need C++ code generation, and instead create a clang `CodeGenerator` for every Carbon file that has C++ imports. For `carbom compile`, only one Carbon file will need code generation, and yet we still build multiple `CodeGenerator` objects in general. Fixing this requires more plumbing from the driver, and this will also be handled in a follow-up. Assisted-by: Gemini via Antigravity
This commit is contained in:
@@ -507,14 +507,23 @@ auto CheckParseTrees(
|
||||
|
||||
// Create C++ domains for Cpp imports.
|
||||
if (options.share_cpp_ast) {
|
||||
llvm::SmallVector<CppInputFile> 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();
|
||||
}
|
||||
|
||||
@@ -10,12 +10,20 @@ namespace Carbon::Check {
|
||||
|
||||
CppDomain::CppDomain(std::shared_ptr<clang::CompilerInstance> clang_instance,
|
||||
std::unique_ptr<clang::Parser> parser,
|
||||
clang::CodeGenerator* code_generator,
|
||||
llvm::ArrayRef<CppInputFile> inputs,
|
||||
llvm::ArrayRef<clang::CodeGenerator*> 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;
|
||||
|
||||
|
||||
@@ -7,6 +7,11 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#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::CompilerInstance> clang_instance,
|
||||
std::unique_ptr<clang::Parser> parser,
|
||||
clang::CodeGenerator* code_generator,
|
||||
llvm::ArrayRef<CppInputFile> inputs,
|
||||
llvm::ArrayRef<clang::CodeGenerator*> 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::CompilerInstance> clang_instance_;
|
||||
std::unique_ptr<clang::Parser> parser_;
|
||||
clang::CodeGenerator* code_generator_ = nullptr;
|
||||
Map<SemIR::CheckIRId, clang::CodeGenerator*> code_generators_;
|
||||
llvm::LLVMContext* llvm_context_ = nullptr;
|
||||
};
|
||||
|
||||
|
||||
@@ -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<CppInputFile> 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<clang::CodeGenerator*> {
|
||||
return code_generators_;
|
||||
}
|
||||
|
||||
auto TakeParser() -> std::unique_ptr<clang::Parser> {
|
||||
@@ -733,15 +735,28 @@ class GenerateASTAction : public clang::ASTFrontendAction {
|
||||
if (!llvm_context_) {
|
||||
return std::make_unique<clang::ASTConsumer>();
|
||||
}
|
||||
auto code_generator =
|
||||
std::unique_ptr<clang::CodeGenerator>(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<std::unique_ptr<clang::ASTConsumer>> 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::CodeGenerator>(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<clang::MultiplexConsumer>(std::move(consumers));
|
||||
}
|
||||
|
||||
auto BeginSourceFileAction(clang::CompilerInstance& /*clang_instance*/)
|
||||
@@ -776,9 +791,9 @@ class GenerateASTAction : public clang::ASTFrontendAction {
|
||||
}
|
||||
|
||||
private:
|
||||
std::string filename_;
|
||||
llvm::ArrayRef<CppInputFile> inputs_;
|
||||
llvm::LLVMContext* llvm_context_;
|
||||
clang::CodeGenerator* code_generator_ = nullptr;
|
||||
llvm::SmallVector<clang::CodeGenerator*> code_generators_;
|
||||
std::unique_ptr<clang::Parser> 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<CppInputFile> inputs,
|
||||
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs,
|
||||
llvm::LLVMContext* llvm_context,
|
||||
std::shared_ptr<clang::CompilerInvocation> 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<CppDomain>(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::MangleContext>(
|
||||
clang_instance->getASTContext().createMangleContext());
|
||||
|
||||
// Set up CppFile for the current SemIR::File.
|
||||
auto cpp_file =
|
||||
std::make_unique<SemIR::CppFile>(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<SemIR::CppFile>(
|
||||
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<CppContext>(
|
||||
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<clang::MultiplexExternalSemaSource>(
|
||||
context.ast_context().getExternalSource());
|
||||
|
||||
@@ -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<CppInputFile> inputs,
|
||||
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs,
|
||||
llvm::LLVMContext* llvm_context,
|
||||
std::shared_ptr<clang::CompilerInvocation> base_invocation)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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<llvm::LLVMContext>();
|
||||
}
|
||||
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<llvm::LLVMContext>();
|
||||
}
|
||||
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<llvm::LLVMContext>();
|
||||
|
||||
// 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<CompilationUnit>(
|
||||
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));
|
||||
|
||||
@@ -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::TreeAndSubtrees> parse_tree_and_subtrees_;
|
||||
std::optional<std::function<auto()->const Parse::TreeAndSubtrees&>>
|
||||
tree_and_subtrees_getter_;
|
||||
std::unique_ptr<llvm::LLVMContext> llvm_context_;
|
||||
llvm::LLVMContext* llvm_context_ = nullptr;
|
||||
std::optional<SemIR::File> sem_ir_;
|
||||
std::unique_ptr<llvm::Module> module_;
|
||||
std::unique_ptr<llvm::TargetMachine> target_machine_;
|
||||
@@ -260,6 +261,7 @@ class CompileDriver {
|
||||
private:
|
||||
CompileOptions* options_;
|
||||
size_t input_filenames_index_ = 0;
|
||||
std::unique_ptr<llvm::LLVMContext> llvm_context_;
|
||||
llvm::SmallVector<std::unique_ptr<CompilationUnit>, 256> units_;
|
||||
std::unique_ptr<MultiUnitCache> cache_;
|
||||
std::shared_ptr<clang::CompilerInvocation> clang_invocation_;
|
||||
|
||||
@@ -34,17 +34,16 @@ Context::Context(
|
||||
llvm::LLVMContext* llvm_context,
|
||||
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> 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<llvm::Module>(module_name, *llvm_context)),
|
||||
cpp_code_generator_(cpp_code_generator),
|
||||
llvm_module_owner_(cpp_code_generator_ ? nullptr
|
||||
: std::make_unique<llvm::Module>(
|
||||
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<llvm::Module> {
|
||||
"Debug Info Version", llvm::DEBUG_METADATA_VERSION);
|
||||
}
|
||||
|
||||
return clang_code_generator_ ? std::unique_ptr<llvm::Module>(
|
||||
clang_code_generator_->ReleaseModule())
|
||||
: std::move(llvm_module_owner_);
|
||||
return cpp_code_generator_ ? std::unique_ptr<llvm::Module>(
|
||||
cpp_code_generator_->ReleaseModule())
|
||||
: std::move(llvm_module_owner_);
|
||||
}
|
||||
|
||||
auto Context::BuildDICompileUnit(llvm::StringRef module_name,
|
||||
|
||||
@@ -121,6 +121,9 @@ class Context {
|
||||
auto file_system() -> llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>& {
|
||||
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> llvm_module_owner_;
|
||||
llvm::Module* llvm_module_;
|
||||
|
||||
|
||||
@@ -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<clang::ASTContext&>(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<llvm::Function>(
|
||||
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<llvm::Function>(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::NamedDecl>(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<clang::CXXRecordDecl>(
|
||||
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);
|
||||
|
||||
@@ -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_;
|
||||
|
||||
|
||||
@@ -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<llvm::Value*> 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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
+3
-3
@@ -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: }
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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: }
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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: }
|
||||
|
||||
@@ -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: }
|
||||
|
||||
+2
-2
@@ -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 {
|
||||
|
||||
+47
-47
@@ -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
|
||||
|
||||
+7
-7
@@ -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: }
|
||||
|
||||
@@ -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:
|
||||
@@ -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
|
||||
|
||||
+7
-7
@@ -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 }
|
||||
|
||||
@@ -12,8 +12,13 @@
|
||||
namespace Carbon::SemIR {
|
||||
|
||||
CppFile::CppFile(std::shared_ptr<clang::CompilerInstance> clang,
|
||||
llvm::LLVMContext* llvm_context)
|
||||
: clang_(std::move(clang)), llvm_context_(llvm_context) {}
|
||||
std::unique_ptr<clang::MangleContext> 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_;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,9 @@ namespace Carbon::SemIR {
|
||||
class CppFile {
|
||||
public:
|
||||
explicit CppFile(std::shared_ptr<clang::CompilerInstance> clang,
|
||||
llvm::LLVMContext* llvm_context);
|
||||
std::unique_ptr<clang::MangleContext> 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::CompilerInstance> clang_;
|
||||
llvm::LLVMContext* llvm_context_;
|
||||
clang::CodeGenerator* code_generator_ = nullptr;
|
||||
// Created by `CreateMangleContext()` once the AST context is available.
|
||||
std::unique_ptr<clang::MangleContext> mangle_context_;
|
||||
llvm::LLVMContext* llvm_context_;
|
||||
clang::CodeGenerator* code_generator_;
|
||||
};
|
||||
|
||||
} // namespace Carbon::SemIR
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
Reference in New Issue
Block a user