Skip to content

Commit 5493072

Browse files
zygoloidbricknerb
authored andcommitted
Split a cross-file Lower::Context out of Lower::FileContext. (carbon-language#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 carbon-language#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.
1 parent 1f806c0 commit 5493072

File tree

9 files changed

+309
-172
lines changed

9 files changed

+309
-172
lines changed

toolchain/driver/compile_subcommand.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -713,8 +713,8 @@ auto CompilationUnit::RunLower() -> void {
713713
subtrees = cache_->tree_and_subtrees_getters();
714714
}
715715
module_ = Lower::LowerToLLVM(*llvm_context_, driver_env_->fs, subtrees,
716-
input_filename_, *sem_ir_, sem_ir_->cpp_ast(),
717-
&inst_namer, vlog_stream_);
716+
input_filename_, *sem_ir_, &inst_namer,
717+
vlog_stream_);
718718
});
719719
if (vlog_stream_) {
720720
CARBON_VLOG("*** llvm::Module ***\n");

toolchain/lower/BUILD

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ cc_library(
3030
srcs = [
3131
"constant.cpp",
3232
"constant.h",
33+
"context.cpp",
3334
"file_context.cpp",
3435
"function_context.cpp",
3536
"mangler.cpp",
@@ -40,6 +41,7 @@ cc_library(
4041
"handle*.cpp",
4142
]),
4243
hdrs = [
44+
"context.h",
4345
"file_context.h",
4446
"function_context.h",
4547
],

toolchain/lower/context.cpp

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
2+
// Exceptions. See /LICENSE for license information.
3+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4+
5+
#include "toolchain/lower/context.h"
6+
7+
#include "common/check.h"
8+
#include "common/vlog.h"
9+
#include "llvm/Transforms/Utils/ModuleUtils.h"
10+
#include "toolchain/lower/file_context.h"
11+
#include "toolchain/sem_ir/inst_namer.h"
12+
13+
namespace Carbon::Lower {
14+
15+
Context::Context(llvm::LLVMContext& llvm_context,
16+
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs,
17+
std::optional<llvm::ArrayRef<Parse::GetTreeAndSubtreesFn>>
18+
tree_and_subtrees_getters_for_debug_info,
19+
llvm::StringRef module_name, llvm::raw_ostream* vlog_stream)
20+
: llvm_context_(&llvm_context),
21+
llvm_module_(std::make_unique<llvm::Module>(module_name, llvm_context)),
22+
file_system_(std::move(fs)),
23+
di_builder_(*llvm_module_),
24+
di_compile_unit_(
25+
tree_and_subtrees_getters_for_debug_info
26+
? BuildDICompileUnit(module_name, *llvm_module_, di_builder_)
27+
: nullptr),
28+
tree_and_subtrees_getters_for_debug_info_(
29+
tree_and_subtrees_getters_for_debug_info),
30+
vlog_stream_(vlog_stream) {}
31+
32+
auto Context::GetFileContext(const SemIR::File* file,
33+
const SemIR::InstNamer* inst_namer)
34+
-> FileContext& {
35+
auto insert_result = file_contexts_.Insert(file->check_ir_id(), [&] {
36+
auto file_context =
37+
std::make_unique<FileContext>(*this, *file, inst_namer, vlog_stream_);
38+
file_context->PrepareToLower();
39+
return file_context;
40+
});
41+
return *insert_result.value();
42+
}
43+
44+
auto Context::Finalize() && -> std::unique_ptr<llvm::Module> {
45+
file_contexts_.ForEach(
46+
[](auto, auto& file_context) { file_context->Finalize(); });
47+
return std::move(llvm_module_);
48+
}
49+
50+
auto Context::BuildDICompileUnit(llvm::StringRef module_name,
51+
llvm::Module& llvm_module,
52+
llvm::DIBuilder& di_builder)
53+
-> llvm::DICompileUnit* {
54+
llvm_module.addModuleFlag(llvm::Module::Max, "Dwarf Version", 5);
55+
llvm_module.addModuleFlag(llvm::Module::Warning, "Debug Info Version",
56+
llvm::DEBUG_METADATA_VERSION);
57+
// TODO: Include directory path in the compile_unit_file.
58+
llvm::DIFile* compile_unit_file = di_builder.createFile(module_name, "");
59+
// TODO: Introduce a new language code for Carbon. C works well for now since
60+
// it's something debuggers will already know/have support for at least.
61+
// Probably have to bump to C++ at some point for virtual functions,
62+
// templates, etc.
63+
return di_builder.createCompileUnit(llvm::dwarf::DW_LANG_C, compile_unit_file,
64+
"carbon",
65+
/*isOptimized=*/false, /*Flags=*/"",
66+
/*RV=*/0);
67+
}
68+
69+
auto Context::GetLocForDI(SemIR::AbsoluteNodeId abs_node_id) -> LocForDI {
70+
const auto& tree_and_subtrees =
71+
(*tree_and_subtrees_getters_for_debug_info_)[abs_node_id.check_ir_id()
72+
.index]();
73+
const auto& tokens = tree_and_subtrees.tree().tokens();
74+
75+
if (abs_node_id.node_id().has_value()) {
76+
auto token =
77+
tree_and_subtrees.GetSubtreeTokenRange(abs_node_id.node_id()).begin;
78+
return {.filename = tokens.source().filename(),
79+
.line_number = tokens.GetLineNumber(token),
80+
.column_number = tokens.GetColumnNumber(token)};
81+
} else {
82+
return {.filename = tokens.source().filename(),
83+
.line_number = 0,
84+
.column_number = 0};
85+
}
86+
}
87+
88+
} // namespace Carbon::Lower

toolchain/lower/context.h

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
2+
// Exceptions. See /LICENSE for license information.
3+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4+
5+
#ifndef CARBON_TOOLCHAIN_LOWER_CONTEXT_H_
6+
#define CARBON_TOOLCHAIN_LOWER_CONTEXT_H_
7+
8+
#include <memory>
9+
#include <optional>
10+
#include <utility>
11+
12+
#include "llvm/IR/Constants.h"
13+
#include "llvm/IR/DIBuilder.h"
14+
#include "llvm/IR/LLVMContext.h"
15+
#include "llvm/IR/Module.h"
16+
#include "toolchain/parse/tree_and_subtrees.h"
17+
#include "toolchain/sem_ir/absolute_node_id.h"
18+
#include "toolchain/sem_ir/ids.h"
19+
#include "toolchain/sem_ir/inst_namer.h"
20+
21+
namespace Carbon::Lower {
22+
23+
class FileContext;
24+
25+
// Context for lowering to an LLVM module.
26+
class Context {
27+
public:
28+
// Location information for use with DebugInfo. The line_number and
29+
// column_number are >= 0, with 0 as unknown, so that they can be passed
30+
// directly to DebugInfo.
31+
struct LocForDI {
32+
llvm::StringRef filename;
33+
int32_t line_number;
34+
int32_t column_number;
35+
};
36+
37+
explicit Context(llvm::LLVMContext& llvm_context,
38+
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs,
39+
std::optional<llvm::ArrayRef<Parse::GetTreeAndSubtreesFn>>
40+
tree_and_subtrees_getters_for_debug_info,
41+
llvm::StringRef module_name, llvm::raw_ostream* vlog_stream);
42+
43+
// Gets or creates the `FileContext` for a given SemIR file. If an
44+
// `inst_namer` is specified the first time this is called for a file, it will
45+
// be used for that file. Otherwise, no instruction namer will be used.
46+
// TODO: Consider building an InstNamer if we're not given one.
47+
auto GetFileContext(const SemIR::File* file,
48+
const SemIR::InstNamer* inst_namer = nullptr)
49+
-> FileContext&;
50+
51+
// Finishes lowering and takes ownership of the LLVM module. The context
52+
// cannot be used further after calling this.
53+
auto Finalize() && -> std::unique_ptr<llvm::Module>;
54+
55+
// Returns location information for use with DebugInfo.
56+
auto GetLocForDI(SemIR::AbsoluteNodeId abs_node_id) -> LocForDI;
57+
58+
// Returns a lowered value to use for a value of type `type`.
59+
auto GetTypeAsValue() -> llvm::Constant* {
60+
return llvm::ConstantStruct::get(GetTypeType());
61+
}
62+
63+
// Returns a lowered value to use for a value of int literal type.
64+
auto GetIntLiteralAsValue() -> llvm::Constant* {
65+
// TODO: Consider adding a named struct type for integer literals.
66+
return llvm::ConstantStruct::get(llvm::StructType::get(llvm_context()));
67+
}
68+
69+
// Returns the empty LLVM struct type used to represent the type `type`.
70+
auto GetTypeType() -> llvm::StructType* {
71+
if (!type_type_) {
72+
// `type` is lowered to an empty LLVM StructType.
73+
type_type_ = llvm::StructType::create(*llvm_context_, {}, "type");
74+
}
75+
return type_type_;
76+
}
77+
78+
auto llvm_context() -> llvm::LLVMContext& { return *llvm_context_; }
79+
auto llvm_module() -> llvm::Module& { return *llvm_module_; }
80+
auto file_system() -> llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>& {
81+
return file_system_;
82+
}
83+
auto di_builder() -> llvm::DIBuilder& { return di_builder_; }
84+
auto di_compile_unit() -> llvm::DICompileUnit* { return di_compile_unit_; }
85+
86+
auto printf_int_format_string() -> llvm::Value* {
87+
return printf_int_format_string_;
88+
}
89+
auto SetPrintfIntFormatString(llvm::Value* printf_int_format_string) {
90+
CARBON_CHECK(!printf_int_format_string_,
91+
"PrintInt formatting string already generated");
92+
printf_int_format_string_ = printf_int_format_string;
93+
}
94+
95+
private:
96+
// Create the DICompileUnit metadata for this compilation.
97+
auto BuildDICompileUnit(llvm::StringRef module_name,
98+
llvm::Module& llvm_module,
99+
llvm::DIBuilder& di_builder) -> llvm::DICompileUnit*;
100+
101+
// State for building the LLVM IR.
102+
llvm::LLVMContext* llvm_context_;
103+
std::unique_ptr<llvm::Module> llvm_module_;
104+
105+
// The filesystem for source code.
106+
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> file_system_;
107+
108+
// State for building the LLVM IR debug info metadata.
109+
llvm::DIBuilder di_builder_;
110+
111+
// The DICompileUnit, if any - null implies debug info is not being emitted.
112+
llvm::DICompileUnit* di_compile_unit_;
113+
114+
// The trees are only provided when debug info should be emitted.
115+
std::optional<llvm::ArrayRef<Parse::GetTreeAndSubtreesFn>>
116+
tree_and_subtrees_getters_for_debug_info_;
117+
118+
// The optional vlog stream.
119+
llvm::raw_ostream* vlog_stream_;
120+
121+
// The `FileContext`s for each IR that is involved in this lowering action.
122+
Map<SemIR::CheckIRId, std::unique_ptr<FileContext>> file_contexts_;
123+
124+
// Lowered version of the builtin type `type`.
125+
llvm::StructType* type_type_ = nullptr;
126+
127+
// Global format string for `printf.int.format` used by the PrintInt builtin.
128+
llvm::Value* printf_int_format_string_ = nullptr;
129+
};
130+
131+
} // namespace Carbon::Lower
132+
133+
#endif // CARBON_TOOLCHAIN_LOWER_CONTEXT_H_

0 commit comments

Comments
 (0)