Split a cross-file Lower::Context out of Lower::FileContext. (#5583)

In preparation for lowering information from multiple `SemIR::File`s
into a single `llvm::Module`. The primary purpose of this is to support
lowering a local specific for an imported generic function, where the
instructions for the generic function are in a different file than the
instructions for the specific. See #5475 for a draft PR implementing
that functionality on top of this.

The per-`llvm::Module` state now lives in `Lower::Context`, and
`Lower::FileContext` tracks only the per-`SemIR::File` information.
`Lower::Context` should not mention any `SemIR` IDs that are
file-specific. For now, the C++ lowering and the specific coalescing
logic are kept per-file for simplicity.
This commit is contained in:
Richard Smith
2025-06-02 18:02:32 +00:00
committed by GitHub
parent 0fd129ec95
commit e91840e1b6
9 changed files with 309 additions and 172 deletions
+2 -2
View File
@@ -713,8 +713,8 @@ auto CompilationUnit::RunLower() -> void {
subtrees = cache_->tree_and_subtrees_getters();
}
module_ = Lower::LowerToLLVM(*llvm_context_, driver_env_->fs, subtrees,
input_filename_, *sem_ir_, sem_ir_->cpp_ast(),
&inst_namer, vlog_stream_);
input_filename_, *sem_ir_, &inst_namer,
vlog_stream_);
});
if (vlog_stream_) {
CARBON_VLOG("*** llvm::Module ***\n");
+2
View File
@@ -30,6 +30,7 @@ cc_library(
srcs = [
"constant.cpp",
"constant.h",
"context.cpp",
"file_context.cpp",
"function_context.cpp",
"mangler.cpp",
@@ -40,6 +41,7 @@ cc_library(
"handle*.cpp",
]),
hdrs = [
"context.h",
"file_context.h",
"function_context.h",
],
+88
View File
@@ -0,0 +1,88 @@
// 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 "toolchain/lower/context.h"
#include "common/check.h"
#include "common/vlog.h"
#include "llvm/Transforms/Utils/ModuleUtils.h"
#include "toolchain/lower/file_context.h"
#include "toolchain/sem_ir/inst_namer.h"
namespace Carbon::Lower {
Context::Context(llvm::LLVMContext& llvm_context,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs,
std::optional<llvm::ArrayRef<Parse::GetTreeAndSubtreesFn>>
tree_and_subtrees_getters_for_debug_info,
llvm::StringRef module_name, llvm::raw_ostream* vlog_stream)
: llvm_context_(&llvm_context),
llvm_module_(std::make_unique<llvm::Module>(module_name, llvm_context)),
file_system_(std::move(fs)),
di_builder_(*llvm_module_),
di_compile_unit_(
tree_and_subtrees_getters_for_debug_info
? BuildDICompileUnit(module_name, *llvm_module_, di_builder_)
: nullptr),
tree_and_subtrees_getters_for_debug_info_(
tree_and_subtrees_getters_for_debug_info),
vlog_stream_(vlog_stream) {}
auto Context::GetFileContext(const SemIR::File* file,
const SemIR::InstNamer* inst_namer)
-> FileContext& {
auto insert_result = file_contexts_.Insert(file->check_ir_id(), [&] {
auto file_context =
std::make_unique<FileContext>(*this, *file, inst_namer, vlog_stream_);
file_context->PrepareToLower();
return file_context;
});
return *insert_result.value();
}
auto Context::Finalize() && -> std::unique_ptr<llvm::Module> {
file_contexts_.ForEach(
[](auto, auto& file_context) { file_context->Finalize(); });
return std::move(llvm_module_);
}
auto Context::BuildDICompileUnit(llvm::StringRef module_name,
llvm::Module& llvm_module,
llvm::DIBuilder& di_builder)
-> llvm::DICompileUnit* {
llvm_module.addModuleFlag(llvm::Module::Max, "Dwarf Version", 5);
llvm_module.addModuleFlag(llvm::Module::Warning, "Debug Info Version",
llvm::DEBUG_METADATA_VERSION);
// TODO: Include directory path in the compile_unit_file.
llvm::DIFile* compile_unit_file = di_builder.createFile(module_name, "");
// TODO: Introduce a new language code for Carbon. C works well for now since
// it's something debuggers will already know/have support for at least.
// Probably have to bump to C++ at some point for virtual functions,
// templates, etc.
return di_builder.createCompileUnit(llvm::dwarf::DW_LANG_C, compile_unit_file,
"carbon",
/*isOptimized=*/false, /*Flags=*/"",
/*RV=*/0);
}
auto Context::GetLocForDI(SemIR::AbsoluteNodeId abs_node_id) -> LocForDI {
const auto& tree_and_subtrees =
(*tree_and_subtrees_getters_for_debug_info_)[abs_node_id.check_ir_id()
.index]();
const auto& tokens = tree_and_subtrees.tree().tokens();
if (abs_node_id.node_id().has_value()) {
auto token =
tree_and_subtrees.GetSubtreeTokenRange(abs_node_id.node_id()).begin;
return {.filename = tokens.source().filename(),
.line_number = tokens.GetLineNumber(token),
.column_number = tokens.GetColumnNumber(token)};
} else {
return {.filename = tokens.source().filename(),
.line_number = 0,
.column_number = 0};
}
}
} // namespace Carbon::Lower
+133
View File
@@ -0,0 +1,133 @@
// 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
#ifndef CARBON_TOOLCHAIN_LOWER_CONTEXT_H_
#define CARBON_TOOLCHAIN_LOWER_CONTEXT_H_
#include <memory>
#include <optional>
#include <utility>
#include "llvm/IR/Constants.h"
#include "llvm/IR/DIBuilder.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "toolchain/parse/tree_and_subtrees.h"
#include "toolchain/sem_ir/absolute_node_id.h"
#include "toolchain/sem_ir/ids.h"
#include "toolchain/sem_ir/inst_namer.h"
namespace Carbon::Lower {
class FileContext;
// Context for lowering to an LLVM module.
class Context {
public:
// Location information for use with DebugInfo. The line_number and
// column_number are >= 0, with 0 as unknown, so that they can be passed
// directly to DebugInfo.
struct LocForDI {
llvm::StringRef filename;
int32_t line_number;
int32_t column_number;
};
explicit Context(llvm::LLVMContext& llvm_context,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs,
std::optional<llvm::ArrayRef<Parse::GetTreeAndSubtreesFn>>
tree_and_subtrees_getters_for_debug_info,
llvm::StringRef module_name, llvm::raw_ostream* vlog_stream);
// Gets or creates the `FileContext` for a given SemIR file. If an
// `inst_namer` is specified the first time this is called for a file, it will
// be used for that file. Otherwise, no instruction namer will be used.
// TODO: Consider building an InstNamer if we're not given one.
auto GetFileContext(const SemIR::File* file,
const SemIR::InstNamer* inst_namer = nullptr)
-> FileContext&;
// Finishes lowering and takes ownership of the LLVM module. The context
// cannot be used further after calling this.
auto Finalize() && -> std::unique_ptr<llvm::Module>;
// Returns location information for use with DebugInfo.
auto GetLocForDI(SemIR::AbsoluteNodeId abs_node_id) -> LocForDI;
// Returns a lowered value to use for a value of type `type`.
auto GetTypeAsValue() -> llvm::Constant* {
return llvm::ConstantStruct::get(GetTypeType());
}
// Returns a lowered value to use for a value of int literal type.
auto GetIntLiteralAsValue() -> llvm::Constant* {
// TODO: Consider adding a named struct type for integer literals.
return llvm::ConstantStruct::get(llvm::StructType::get(llvm_context()));
}
// Returns the empty LLVM struct type used to represent the type `type`.
auto GetTypeType() -> llvm::StructType* {
if (!type_type_) {
// `type` is lowered to an empty LLVM StructType.
type_type_ = llvm::StructType::create(*llvm_context_, {}, "type");
}
return type_type_;
}
auto llvm_context() -> llvm::LLVMContext& { return *llvm_context_; }
auto llvm_module() -> llvm::Module& { return *llvm_module_; }
auto file_system() -> llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>& {
return file_system_;
}
auto di_builder() -> llvm::DIBuilder& { return di_builder_; }
auto di_compile_unit() -> llvm::DICompileUnit* { return di_compile_unit_; }
auto printf_int_format_string() -> llvm::Value* {
return printf_int_format_string_;
}
auto SetPrintfIntFormatString(llvm::Value* printf_int_format_string) {
CARBON_CHECK(!printf_int_format_string_,
"PrintInt formatting string already generated");
printf_int_format_string_ = printf_int_format_string;
}
private:
// Create the DICompileUnit metadata for this compilation.
auto BuildDICompileUnit(llvm::StringRef module_name,
llvm::Module& llvm_module,
llvm::DIBuilder& di_builder) -> llvm::DICompileUnit*;
// State for building the LLVM IR.
llvm::LLVMContext* llvm_context_;
std::unique_ptr<llvm::Module> llvm_module_;
// The filesystem for source code.
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> file_system_;
// State for building the LLVM IR debug info metadata.
llvm::DIBuilder di_builder_;
// The DICompileUnit, if any - null implies debug info is not being emitted.
llvm::DICompileUnit* di_compile_unit_;
// The trees are only provided when debug info should be emitted.
std::optional<llvm::ArrayRef<Parse::GetTreeAndSubtreesFn>>
tree_and_subtrees_getters_for_debug_info_;
// The optional vlog stream.
llvm::raw_ostream* vlog_stream_;
// The `FileContext`s for each IR that is involved in this lowering action.
Map<SemIR::CheckIRId, std::unique_ptr<FileContext>> file_contexts_;
// Lowered version of the builtin type `type`.
llvm::StructType* type_type_ = nullptr;
// Global format string for `printf.int.format` used by the PrintInt builtin.
llvm::Value* printf_int_format_string_ = nullptr;
};
} // namespace Carbon::Lower
#endif // CARBON_TOOLCHAIN_LOWER_CONTEXT_H_
+41 -83
View File
@@ -36,26 +36,11 @@
namespace Carbon::Lower {
FileContext::FileContext(
llvm::LLVMContext& llvm_context,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs,
std::optional<llvm::ArrayRef<Parse::GetTreeAndSubtreesFn>>
tree_and_subtrees_getters_for_debug_info,
llvm::StringRef module_name, const SemIR::File& sem_ir,
clang::ASTUnit* cpp_ast, const SemIR::InstNamer* inst_namer,
llvm::raw_ostream* vlog_stream)
: llvm_context_(&llvm_context),
llvm_module_(std::make_unique<llvm::Module>(module_name, llvm_context)),
fs_(std::move(fs)),
di_builder_(*llvm_module_),
di_compile_unit_(
tree_and_subtrees_getters_for_debug_info
? BuildDICompileUnit(module_name, *llvm_module_, di_builder_)
: nullptr),
tree_and_subtrees_getters_for_debug_info_(
tree_and_subtrees_getters_for_debug_info),
FileContext::FileContext(Context& context, const SemIR::File& sem_ir,
const SemIR::InstNamer* inst_namer,
llvm::raw_ostream* vlog_stream)
: context_(&context),
sem_ir_(&sem_ir),
cpp_ast_(cpp_ast),
inst_namer_(inst_namer),
vlog_stream_(vlog_stream) {
// Initialization that relies on invariants of the class.
@@ -65,11 +50,12 @@ FileContext::FileContext(
}
// TODO: Move this to lower.cpp.
auto FileContext::Run() -> std::unique_ptr<llvm::Module> {
CARBON_CHECK(llvm_module_, "Run can only be called once.");
auto FileContext::PrepareToLower() -> void {
if (cpp_code_generator_) {
cpp_code_generator_->Initialize(cpp_ast()->getASTContext());
// Clang code generation should not actually modify the AST, but isn't
// const-correct.
cpp_code_generator_->Initialize(
const_cast<clang::ASTContext&>(cpp_ast()->getASTContext()));
}
// Lower all types that were required to be complete.
@@ -86,12 +72,6 @@ auto FileContext::Run() -> std::unique_ptr<llvm::Module> {
functions_[id.index] = BuildFunctionDecl(id);
}
for (const auto& class_info : sem_ir_->classes().array_ref()) {
if (auto* llvm_vtable = BuildVtable(class_info)) {
global_variables_.Insert(class_info.vtable_id, llvm_vtable);
}
}
// Specific functions are lowered when we emit a reference to them.
specific_functions_.resize(sem_ir_->specifics().size());
// Additional data stored for specifics, for when attempting to coalesce.
@@ -106,6 +86,15 @@ auto FileContext::Run() -> std::unique_ptr<llvm::Module> {
// Lower constants.
constants_.resize(sem_ir_->insts().size());
LowerConstants(*this, constants_);
}
// TODO: Move this to lower.cpp.
auto FileContext::LowerDefinitions() -> void {
for (const auto& class_info : sem_ir_->classes().array_ref()) {
if (auto* llvm_vtable = BuildVtable(class_info)) {
global_variables_.Insert(class_info.vtable_id, llvm_vtable);
}
}
// Lower global variable definitions.
// TODO: Storing both a `constants_` array and a separate `global_variables_`
@@ -148,10 +137,6 @@ auto FileContext::Run() -> std::unique_ptr<llvm::Module> {
BuildFunctionDefinition(function_id, specific_id);
}
// Find equivalent specifics (from the same generic), replace all uses and
// remove duplicately lowered function definitions.
CoalesceEquivalentSpecifics();
// Append `__global_init` to `llvm::global_ctors` to initialize global
// variables.
if (sem_ir().global_ctor_id().has_value()) {
@@ -161,15 +146,22 @@ auto FileContext::Run() -> std::unique_ptr<llvm::Module> {
}
if (cpp_code_generator_) {
cpp_code_generator_->HandleTranslationUnit(cpp_ast()->getASTContext());
// Clang code generation should not actually modify the AST, but isn't
// const-correct.
cpp_code_generator_->HandleTranslationUnit(
const_cast<clang::ASTContext&>(cpp_ast()->getASTContext()));
bool link_error = llvm::Linker::linkModules(
/*Dest=*/*llvm_module_,
/*Dest=*/llvm_module(),
/*Src=*/std::unique_ptr<llvm::Module>(
cpp_code_generator_->ReleaseModule()));
CARBON_CHECK(!link_error);
}
}
return std::move(llvm_module_);
auto FileContext::Finalize() -> void {
// Find equivalent specifics (from the same generic), replace all uses and
// remove duplicately lowered function definitions.
CoalesceEquivalentSpecifics();
}
auto FileContext::InsertPair(
@@ -395,25 +387,6 @@ auto FileContext::AreFunctionBodiesEquivalent(
return true;
}
auto FileContext::BuildDICompileUnit(llvm::StringRef module_name,
llvm::Module& llvm_module,
llvm::DIBuilder& di_builder)
-> llvm::DICompileUnit* {
llvm_module.addModuleFlag(llvm::Module::Max, "Dwarf Version", 5);
llvm_module.addModuleFlag(llvm::Module::Warning, "Debug Info Version",
llvm::DEBUG_METADATA_VERSION);
// TODO: Include directory path in the compile_unit_file.
llvm::DIFile* compile_unit_file = di_builder.createFile(module_name, "");
// TODO: Introduce a new language code for Carbon. C works well for now since
// it's something debuggers will already know/have support for at least.
// Probably have to bump to C++ at some point for virtual functions,
// templates, etc.
return di_builder.createCompileUnit(llvm::dwarf::DW_LANG_C, compile_unit_file,
"carbon",
/*isOptimized=*/false, /*Flags=*/"",
/*RV=*/0);
}
auto FileContext::CreateCppCodeGenerator()
-> std::unique_ptr<clang::CodeGenerator> {
if (!cpp_ast()) {
@@ -421,15 +394,16 @@ auto FileContext::CreateCppCodeGenerator()
}
RawStringOstream clang_module_name_stream;
clang_module_name_stream << llvm_module_->getName() << ".clang";
clang_module_name_stream << llvm_module().getName() << ".clang";
// Do not emit Clang's name and version as the creator of the output file.
cpp_code_gen_options_.EmitVersionIdentMetadata = false;
return std::unique_ptr<clang::CodeGenerator>(clang::CreateLLVMCodeGen(
cpp_ast()->getASTContext().getDiagnostics(),
clang_module_name_stream.TakeStr(), fs_, cpp_header_search_options_,
cpp_preprocessor_options_, cpp_code_gen_options_, *llvm_context_));
clang_module_name_stream.TakeStr(), context().file_system(),
cpp_header_search_options_, cpp_preprocessor_options_,
cpp_code_gen_options_, llvm_context()));
}
auto FileContext::GetGlobal(SemIR::InstId inst_id,
@@ -858,7 +832,7 @@ auto FileContext::BuildFunctionBody(SemIR::FunctionId function_id,
auto FileContext::BuildDISubprogram(const SemIR::Function& function,
const llvm::Function* llvm_function)
-> llvm::DISubprogram* {
if (!di_compile_unit_) {
if (!context().di_compile_unit()) {
return nullptr;
}
auto name = sem_ir().names().GetAsStringIfIdentifier(function.name_id);
@@ -867,12 +841,12 @@ auto FileContext::BuildDISubprogram(const SemIR::Function& function,
auto loc = GetLocForDI(function.definition_id);
// TODO: Add more details here, including real subroutine type (once type
// information is built), etc.
return di_builder_.createFunction(
di_compile_unit_, *name, llvm_function->getName(),
/*File=*/di_builder_.createFile(loc.filename, ""),
return context().di_builder().createFunction(
context().di_compile_unit(), *name, llvm_function->getName(),
/*File=*/context().di_builder().createFile(loc.filename, ""),
/*LineNo=*/loc.line_number,
di_builder_.createSubroutineType(
di_builder_.getOrCreateTypeArray(std::nullopt)),
context().di_builder().createSubroutineType(
context().di_builder().getOrCreateTypeArray(std::nullopt)),
/*ScopeLine=*/0, llvm::DINode::FlagZero,
llvm::DISubprogram::SPFlagDefinition);
}
@@ -1079,25 +1053,9 @@ auto FileContext::BuildGlobalVariableDecl(SemIR::VarStorage var_storage)
/*Initializer=*/nullptr, mangled_name);
}
auto FileContext::GetLocForDI(SemIR::InstId inst_id) -> LocForDI {
SemIR::AbsoluteNodeId resolved =
GetAbsoluteNodeId(sem_ir_, SemIR::LocId(inst_id)).back();
const auto& tree_and_subtrees =
(*tree_and_subtrees_getters_for_debug_info_)[resolved.check_ir_id()
.index]();
const auto& tokens = tree_and_subtrees.tree().tokens();
if (resolved.node_id().has_value()) {
auto token =
tree_and_subtrees.GetSubtreeTokenRange(resolved.node_id()).begin;
return {.filename = tokens.source().filename(),
.line_number = tokens.GetLineNumber(token),
.column_number = tokens.GetColumnNumber(token)};
} else {
return {.filename = tokens.source().filename(),
.line_number = 0,
.column_number = 0};
}
auto FileContext::GetLocForDI(SemIR::InstId inst_id) -> Context::LocForDI {
return context().GetLocForDI(
GetAbsoluteNodeId(sem_ir_, SemIR::LocId(inst_id)).back());
}
auto FileContext::BuildVtable(const SemIR::Class& class_info)
+28 -77
View File
@@ -8,13 +8,8 @@
#include "clang/Basic/CodeGenOptions.h"
#include "clang/CodeGen/ModuleBuilder.h"
#include "clang/Lex/PreprocessorOptions.h"
#include "common/raw_string_ostream.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DIBuilder.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/BLAKE3.h"
#include "toolchain/lower/context.h"
#include "toolchain/parse/tree_and_subtrees.h"
#include "toolchain/sem_ir/file.h"
#include "toolchain/sem_ir/ids.h"
@@ -22,18 +17,9 @@
namespace Carbon::Lower {
// Context and shared functionality for lowering handlers.
// Context and shared functionality for lowering within a SemIR file.
class FileContext {
public:
// Location information for use with DebugInfo. The line_number and
// column_number are >= 0, with 0 as unknown, so that they can be passed
// directly to DebugInfo.
struct LocForDI {
llvm::StringRef filename;
int32_t line_number;
int32_t column_number;
};
// Describes a specific function's body fingerprint.
struct SpecificFunctionFingerprint {
// Fingerprint with all specific-dependent instructions, except specific
@@ -50,28 +36,25 @@ class FileContext {
llvm::SmallVector<SemIR::SpecificId> calls;
};
explicit FileContext(
llvm::LLVMContext& llvm_context,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs,
std::optional<llvm::ArrayRef<Parse::GetTreeAndSubtreesFn>>
tree_and_subtrees_getters_for_debug_info,
llvm::StringRef module_name, const SemIR::File& sem_ir,
clang::ASTUnit* cpp_ast, const SemIR::InstNamer* inst_namer,
llvm::raw_ostream* vlog_stream);
// Lowers the SemIR::File to LLVM IR. Should only be called once, and handles
// the main execution loop.
auto Run() -> std::unique_ptr<llvm::Module>;
// Create the DICompileUnit metadata for this compilation.
auto BuildDICompileUnit(llvm::StringRef module_name,
llvm::Module& llvm_module,
llvm::DIBuilder& di_builder) -> llvm::DICompileUnit*;
explicit FileContext(Context& context, const SemIR::File& sem_ir,
const SemIR::InstNamer* inst_namer,
llvm::raw_ostream* vlog_stream);
// Creates the Clang `CodeGenerator` to generate LLVM module from imported C++
// code. Returns null when not importing C++.
auto CreateCppCodeGenerator() -> std::unique_ptr<clang::CodeGenerator>;
// Prepares to lower code in this IR, by precomputing needed LLVM types,
// constants, declarations, etc. Should only be called once, before we lower
// anything in this file.
auto PrepareToLower() -> void;
// Lowers all the definitions provided by the SemIR::File to LLVM IR.
auto LowerDefinitions() -> void;
// Perform final cleanup tasks once all lowering has been completed.
auto Finalize() -> void;
// Gets a callable's function. Returns nullptr for a builtin.
auto GetFunction(SemIR::FunctionId function_id) -> llvm::Function* {
return functions_[function_id.index];
@@ -92,17 +75,16 @@ class FileContext {
}
// Returns location information for use with DebugInfo.
auto GetLocForDI(SemIR::InstId inst_id) -> LocForDI;
auto GetLocForDI(SemIR::InstId inst_id) -> Context::LocForDI;
// Returns a lowered value to use for a value of type `type`.
auto GetTypeAsValue() -> llvm::Constant* {
return llvm::ConstantStruct::get(GetTypeType());
return context().GetTypeAsValue();
}
// Returns a lowered value to use for a value of int literal type.
auto GetIntLiteralAsValue() -> llvm::Constant* {
// TODO: Consider adding a named struct type for integer literals.
return llvm::ConstantStruct::get(llvm::StructType::get(llvm_context()));
return context().GetIntLiteralAsValue();
}
// Returns a global value for the given instruction.
@@ -110,29 +92,22 @@ class FileContext {
-> llvm::Value*;
// Returns the empty LLVM struct type used to represent the type `type`.
auto GetTypeType() -> llvm::StructType* {
if (!type_type_) {
// `type` is lowered to an empty LLVM StructType.
type_type_ = llvm::StructType::create(*llvm_context_, {}, "type");
}
return type_type_;
}
auto GetTypeType() -> llvm::StructType* { return context().GetTypeType(); }
auto llvm_context() -> llvm::LLVMContext& { return *llvm_context_; }
auto llvm_module() -> llvm::Module& { return *llvm_module_; }
auto context() -> Context& { return *context_; }
auto llvm_context() -> llvm::LLVMContext& { return context().llvm_context(); }
auto llvm_module() -> llvm::Module& { return context().llvm_module(); }
auto sem_ir() -> const SemIR::File& { return *sem_ir_; }
auto cpp_ast() -> clang::ASTUnit* { return cpp_ast_; }
auto cpp_ast() -> const clang::ASTUnit* { return sem_ir().cpp_ast(); }
auto inst_namer() -> const SemIR::InstNamer* { return inst_namer_; }
auto global_variables() -> const Map<SemIR::InstId, llvm::GlobalVariable*>& {
return global_variables_;
}
auto printf_int_format_string() -> llvm::Value* {
return printf_int_format_string_;
return context().printf_int_format_string();
}
auto SetPrintfIntFormatString(llvm::Value* printf_int_format_string) {
CARBON_CHECK(!printf_int_format_string_,
"PrintInt formatting string already generated");
printf_int_format_string_ = printf_int_format_string;
context().SetPrintfIntFormatString(printf_int_format_string);
}
struct FunctionTypeInfo {
@@ -253,30 +228,12 @@ class FileContext {
const Set<std::pair<SemIR::SpecificId, SemIR::SpecificId>>& set_of_pairs)
-> bool;
// State for building the LLVM IR.
llvm::LLVMContext* llvm_context_;
std::unique_ptr<llvm::Module> llvm_module_;
// The filesystem for source code.
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs_;
// State for building the LLVM IR debug info metadata.
llvm::DIBuilder di_builder_;
// The DICompileUnit, if any - null implies debug info is not being emitted.
llvm::DICompileUnit* di_compile_unit_;
// The trees are only provided when debug info should be emitted.
std::optional<llvm::ArrayRef<Parse::GetTreeAndSubtreesFn>>
tree_and_subtrees_getters_for_debug_info_;
// The overall lowering context.
Context* context_;
// The input SemIR.
const SemIR::File* const sem_ir_;
// A mutable Clang AST is necessary for lowering since using the AST in lower
// modifies it.
clang::ASTUnit* cpp_ast_;
// The options used to create the Clang Code Generator.
clang::HeaderSearchOptions cpp_header_search_options_;
clang::PreprocessorOptions cpp_preprocessor_options_;
@@ -315,9 +272,6 @@ class FileContext {
// resize this directly to the (often large) correct size.
llvm::SmallVector<llvm::Type*, 0> types_;
// Lowered version of the builtin type `type`.
llvm::StructType* type_type_ = nullptr;
// Maps constants to their lowered values.
// Vector indexes correspond to `InstId` indexes for constant instructions. We
// resize this directly to the (often large) correct size.
@@ -326,9 +280,6 @@ class FileContext {
// Maps global variables to their lowered variant.
Map<SemIR::InstId, llvm::GlobalVariable*> global_variables_;
// Global format string for `printf.int.format` used by the PrintInt builtin.
llvm::Value* printf_int_format_string_ = nullptr;
// For a generic function, keep track of the specifics for which LLVM
// function declarations were created. Those can be retrieved then from
// `specific_functions_`. We resize this to the correct size. Vector indexes
+7 -5
View File
@@ -7,6 +7,7 @@
#include <memory>
#include <optional>
#include "toolchain/lower/context.h"
#include "toolchain/lower/file_context.h"
namespace Carbon::Lower {
@@ -16,13 +17,14 @@ auto LowerToLLVM(llvm::LLVMContext& llvm_context,
std::optional<llvm::ArrayRef<Parse::GetTreeAndSubtreesFn>>
tree_and_subtrees_getters_for_debug_info,
llvm::StringRef module_name, const SemIR::File& sem_ir,
clang::ASTUnit* cpp_ast, const SemIR::InstNamer* inst_namer,
const SemIR::InstNamer* inst_namer,
llvm::raw_ostream* vlog_stream)
-> std::unique_ptr<llvm::Module> {
FileContext context(llvm_context, std::move(fs),
tree_and_subtrees_getters_for_debug_info, module_name,
sem_ir, cpp_ast, inst_namer, vlog_stream);
return context.Run();
Context context(llvm_context, std::move(fs),
tree_and_subtrees_getters_for_debug_info, module_name,
vlog_stream);
context.GetFileContext(&sem_ir, inst_namer).LowerDefinitions();
return std::move(context).Finalize();
}
} // namespace Carbon::Lower
+1 -1
View File
@@ -20,7 +20,7 @@ auto LowerToLLVM(llvm::LLVMContext& llvm_context,
std::optional<llvm::ArrayRef<Parse::GetTreeAndSubtreesFn>>
tree_and_subtrees_getters_for_debug_info,
llvm::StringRef module_name, const SemIR::File& sem_ir,
clang::ASTUnit* cpp_ast, const SemIR::InstNamer* inst_namer,
const SemIR::InstNamer* inst_namer,
llvm::raw_ostream* vlog_stream)
-> std::unique_ptr<llvm::Module>;
+7 -4
View File
@@ -24,10 +24,13 @@ class Mangler {
// specified `FileContext`.
explicit Mangler(FileContext& file_context)
: file_context_(file_context),
cpp_mangle_context_(
file_context.cpp_ast()
? file_context.cpp_ast()->getASTContext().createMangleContext()
: nullptr) {}
cpp_mangle_context_(file_context.cpp_ast()
// Clang's createMangleContext is not
// const-correct, but doesn't modify the AST.
? const_cast<clang::ASTContext&>(
file_context.cpp_ast()->getASTContext())
.createMangleContext()
: nullptr) {}
// Produce a deterministically unique mangled name for the function specified
// by `function_id` and `specific_id`.