forked from carbon-language/carbon-lang
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlowering_context.cpp
184 lines (161 loc) · 7.26 KB
/
lowering_context.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
// 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/lowering/lowering_context.h"
#include "common/vlog.h"
#include "toolchain/lowering/lowering_function_context.h"
#include "toolchain/semantics/semantics_ir.h"
#include "toolchain/semantics/semantics_node_kind.h"
namespace Carbon {
LoweringContext::LoweringContext(llvm::LLVMContext& llvm_context,
llvm::StringRef module_name,
const SemanticsIR& semantics_ir,
llvm::raw_ostream* vlog_stream)
: llvm_context_(&llvm_context),
llvm_module_(std::make_unique<llvm::Module>(module_name, llvm_context)),
semantics_ir_(&semantics_ir),
vlog_stream_(vlog_stream) {
CARBON_CHECK(!semantics_ir.has_errors())
<< "Generating LLVM IR from invalid SemanticsIR is unsupported.";
}
// TODO: Move this to lower_to_llvm.cpp.
auto LoweringContext::Run() -> std::unique_ptr<llvm::Module> {
CARBON_CHECK(llvm_module_) << "Run can only be called once.";
// Lower types.
auto types = semantics_ir_->types();
types_.resize_for_overwrite(types.size());
for (int i = 0; i < static_cast<int>(types.size()); ++i) {
types_[i] = BuildType(types[i]);
}
// Lower function declarations.
functions_.resize_for_overwrite(semantics_ir_->functions_size());
for (int i = 0; i < semantics_ir_->functions_size(); ++i) {
functions_[i] = BuildFunctionDeclaration(SemanticsFunctionId(i));
}
// TODO: Lower global variable declarations.
// Lower function definitions.
for (int i = 0; i < semantics_ir_->functions_size(); ++i) {
BuildFunctionDefinition(SemanticsFunctionId(i));
}
// TODO: Lower global variable initializers.
return std::move(llvm_module_);
}
auto LoweringContext::BuildFunctionDeclaration(SemanticsFunctionId function_id)
-> llvm::Function* {
auto function = semantics_ir().GetFunction(function_id);
// TODO: Lower type information for the arguments prior to building args.
auto param_refs = semantics_ir().GetNodeBlock(function.param_refs_id);
llvm::SmallVector<llvm::Type*> args;
args.resize_for_overwrite(param_refs.size());
for (int i = 0; i < static_cast<int>(param_refs.size()); ++i) {
args[i] = GetType(semantics_ir().GetNode(param_refs[i]).type_id());
}
llvm::Type* return_type = GetType(function.return_type_id.is_valid()
? function.return_type_id
: semantics_ir().empty_tuple_type_id());
llvm::FunctionType* function_type =
llvm::FunctionType::get(return_type, args, /*isVarArg=*/false);
auto* llvm_function = llvm::Function::Create(
function_type, llvm::Function::ExternalLinkage,
semantics_ir().GetString(function.name_id), llvm_module());
// Set parameter names.
for (int i = 0; i < static_cast<int>(param_refs.size()); ++i) {
auto [param_name_id, _] =
semantics_ir().GetNode(param_refs[i]).GetAsBindName();
llvm_function->getArg(i)->setName(semantics_ir().GetString(param_name_id));
}
return llvm_function;
}
auto LoweringContext::BuildFunctionDefinition(SemanticsFunctionId function_id)
-> void {
auto function = semantics_ir().GetFunction(function_id);
const auto& body_block_ids = function.body_block_ids;
if (body_block_ids.empty()) {
// Function is probably defined in another file; not an error.
return;
}
llvm::Function* llvm_function = GetFunction(function_id);
LoweringFunctionContext function_lowering(*this, llvm_function);
// Add parameters to locals.
auto param_refs = semantics_ir().GetNodeBlock(function.param_refs_id);
for (int i = 0; i < static_cast<int>(param_refs.size()); ++i) {
auto param_storage =
semantics_ir().GetNode(param_refs[i]).GetAsBindName().second;
function_lowering.SetLocal(param_storage, llvm_function->getArg(i));
}
// Lower all blocks.
// TODO: Determine the set of reachable blocks, and only lower those ones.
for (auto block_id : body_block_ids) {
CARBON_VLOG() << "Lowering " << block_id << "\n";
auto* llvm_block = function_lowering.GetBlock(block_id);
// Keep the LLVM blocks in lexical order.
llvm_block->moveBefore(llvm_function->end());
function_lowering.builder().SetInsertPoint(llvm_block);
for (const auto& node_id : semantics_ir().GetNodeBlock(block_id)) {
auto node = semantics_ir().GetNode(node_id);
CARBON_VLOG() << "Lowering " << node_id << ": " << node << "\n";
switch (node.kind()) {
#define CARBON_SEMANTICS_NODE_KIND(Name) \
case SemanticsNodeKind::Name: \
LoweringHandle##Name(function_lowering, node_id, node); \
break;
#include "toolchain/semantics/semantics_node_kind.def"
}
}
}
}
auto LoweringContext::BuildType(SemanticsNodeId node_id) -> llvm::Type* {
switch (node_id.index) {
case SemanticsBuiltinKind::EmptyTupleType.AsInt():
// Represent empty types as empty structs.
// TODO: Investigate special-casing handling of these so that they can be
// collectively replaced with LLVM's void, particularly around function
// returns. LLVM doesn't allow declaring variables with a void type, so
// that may require significant special casing.
return llvm::StructType::create(
*llvm_context_, llvm::ArrayRef<llvm::Type*>(),
SemanticsBuiltinKind::FromInt(node_id.index).name());
case SemanticsBuiltinKind::FloatingPointType.AsInt():
// TODO: Handle different sizes.
return llvm::Type::getDoubleTy(*llvm_context_);
case SemanticsBuiltinKind::IntegerType.AsInt():
// TODO: Handle different sizes.
return llvm::Type::getInt32Ty(*llvm_context_);
case SemanticsBuiltinKind::BoolType.AsInt():
// TODO: We may want to have different representations for `bool` storage
// (`i8`) versus for `bool` values (`i1`).
return llvm::Type::getInt1Ty(*llvm_context_);
}
auto node = semantics_ir_->GetNode(node_id);
switch (node.kind()) {
case SemanticsNodeKind::StructType: {
auto refs = semantics_ir_->GetNodeBlock(node.GetAsStructType());
llvm::SmallVector<llvm::Type*> subtypes;
subtypes.reserve(refs.size());
for (auto ref_id : refs) {
auto type_id = semantics_ir_->GetNode(ref_id).type_id();
// TODO: Handle recursive types. The restriction for builtins prevents
// recursion while still letting them cache.
CARBON_CHECK(type_id.index < SemanticsBuiltinKind::ValidCount)
<< type_id;
subtypes.push_back(GetType(type_id));
}
return llvm::StructType::create(*llvm_context_, subtypes,
"StructLiteralType");
}
case SemanticsNodeKind::TupleType: {
auto refs = semantics_ir_->GetTypeBlock(node.GetAsTupleType());
llvm::SmallVector<llvm::Type*> subtypes;
subtypes.reserve(refs.size());
for (auto ref_id : refs) {
subtypes.push_back(GetType(ref_id));
}
return llvm::StructType::create(*llvm_context_, subtypes,
"TupleLiteralType");
}
default: {
CARBON_FATAL() << "Cannot use node as type: " << node_id;
}
}
}
} // namespace Carbon