mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-29 09:44:56 +01:00
This switches types to using SemanticsTypeId instead of SemanticsNodeId, and lowering pre-builds its list of types. The empty tuple type is special-cased because we don't want to emit it unless it's in-use, but as the implicit return for functions, it's frequently used. Callables use invalid to indicate the implicit return, and that seems undesirable to change due to the size increase.
239 lines
9.9 KiB
C++
239 lines
9.9 KiB
C++
// 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"
|
|
|
|
namespace Carbon {
|
|
|
|
auto LoweringHandleInvalid(LoweringContext& /*context*/,
|
|
SemanticsNodeId /*node_id*/, SemanticsNode /*node*/)
|
|
-> void {
|
|
llvm_unreachable("never in actual IR");
|
|
}
|
|
|
|
auto LoweringHandleCrossReference(LoweringContext& /*context*/,
|
|
SemanticsNodeId /*node_id*/,
|
|
SemanticsNode node) -> void {
|
|
CARBON_FATAL() << "TODO: Add support: " << node;
|
|
}
|
|
|
|
auto LoweringHandleAssign(LoweringContext& context, SemanticsNodeId /*node_id*/,
|
|
SemanticsNode node) -> void {
|
|
auto [storage_id, value_id] = node.GetAsAssign();
|
|
context.builder().CreateStore(context.GetLoweredNodeAsValue(value_id),
|
|
context.GetLoweredNodeAsValue(storage_id));
|
|
}
|
|
|
|
auto LoweringHandleBinaryOperatorAdd(LoweringContext& /*context*/,
|
|
SemanticsNodeId /*node_id*/,
|
|
SemanticsNode node) -> void {
|
|
CARBON_FATAL() << "TODO: Add support: " << node;
|
|
}
|
|
|
|
auto LoweringHandleBindName(LoweringContext& /*context*/,
|
|
SemanticsNodeId /*node_id*/, SemanticsNode /*node*/)
|
|
-> void {
|
|
// Probably need to do something here, but not necessary for now.
|
|
}
|
|
|
|
auto LoweringHandleBuiltin(LoweringContext& /*context*/,
|
|
SemanticsNodeId /*node_id*/, SemanticsNode node)
|
|
-> void {
|
|
CARBON_FATAL() << "TODO: Add support: " << node;
|
|
}
|
|
|
|
auto LoweringHandleCall(LoweringContext& context, SemanticsNodeId node_id,
|
|
SemanticsNode node) -> void {
|
|
auto [refs_id, callable_id] = node.GetAsCall();
|
|
auto* function = context.GetLoweredCallable(callable_id);
|
|
std::vector<llvm::Value*> args;
|
|
for (auto ref_id : context.semantics_ir().GetNodeBlock(refs_id)) {
|
|
args.push_back(context.GetLoweredNodeAsValue(ref_id));
|
|
}
|
|
auto* value =
|
|
context.builder().CreateCall(function, args, function->getName());
|
|
context.SetLoweredNodeAsValue(node_id, value);
|
|
}
|
|
|
|
auto LoweringHandleCodeBlock(LoweringContext& /*context*/,
|
|
SemanticsNodeId /*node_id*/, SemanticsNode node)
|
|
-> void {
|
|
CARBON_FATAL() << "TODO: Add support: " << node;
|
|
}
|
|
|
|
auto LoweringHandleFunctionDeclaration(LoweringContext& context,
|
|
SemanticsNodeId /*node_id*/,
|
|
SemanticsNode node) -> void {
|
|
auto [name_id, callable_id] = node.GetAsFunctionDeclaration();
|
|
auto callable = context.semantics_ir().GetCallable(callable_id);
|
|
|
|
// TODO: Lower type information for the arguments prior to building args.
|
|
auto param_refs = context.semantics_ir().GetNodeBlock(callable.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] = context.GetType(
|
|
context.semantics_ir().GetNode(param_refs[i]).type_id());
|
|
}
|
|
|
|
llvm::Type* return_type =
|
|
context.GetType(callable.return_type_id.is_valid()
|
|
? callable.return_type_id
|
|
: context.semantics_ir().empty_tuple_type_id());
|
|
llvm::FunctionType* function_type =
|
|
llvm::FunctionType::get(return_type, args, /*isVarArg=*/false);
|
|
auto* function = llvm::Function::Create(
|
|
function_type, llvm::Function::ExternalLinkage,
|
|
context.semantics_ir().GetString(name_id), context.llvm_module());
|
|
context.SetLoweredCallable(callable_id, function);
|
|
|
|
// Set parameter names.
|
|
for (int i = 0; i < static_cast<int>(param_refs.size()); ++i) {
|
|
auto [param_name_id, _] =
|
|
context.semantics_ir().GetNode(param_refs[i]).GetAsBindName();
|
|
function->getArg(i)->setName(
|
|
context.semantics_ir().GetString(param_name_id));
|
|
}
|
|
}
|
|
|
|
auto LoweringHandleFunctionDefinition(LoweringContext& context,
|
|
SemanticsNodeId /*node_id*/,
|
|
SemanticsNode node) -> void {
|
|
auto [declaration_id, body_block_id] = node.GetAsFunctionDefinition();
|
|
auto [name_id, callable_id] =
|
|
context.semantics_ir().GetNode(declaration_id).GetAsFunctionDeclaration();
|
|
|
|
llvm::Function* function = context.llvm_module().getFunction(
|
|
context.semantics_ir().GetString(name_id));
|
|
|
|
// Create a new basic block to start insertion into.
|
|
llvm::BasicBlock* body =
|
|
llvm::BasicBlock::Create(context.llvm_context(), "entry", function);
|
|
context.todo_blocks().push_back({body, body_block_id});
|
|
}
|
|
|
|
auto LoweringHandleIntegerLiteral(LoweringContext& context,
|
|
SemanticsNodeId node_id, SemanticsNode node)
|
|
-> void {
|
|
llvm::APInt i =
|
|
context.semantics_ir().GetIntegerLiteral(node.GetAsIntegerLiteral());
|
|
// TODO: This won't offer correct semantics, but seems close enough for now.
|
|
llvm::Value* v =
|
|
llvm::ConstantInt::get(context.builder().getInt32Ty(), i.getSExtValue());
|
|
context.SetLoweredNodeAsValue(node_id, v);
|
|
}
|
|
|
|
auto LoweringHandleRealLiteral(LoweringContext& context,
|
|
SemanticsNodeId node_id, SemanticsNode node)
|
|
-> void {
|
|
SemanticsRealLiteral real =
|
|
context.semantics_ir().GetRealLiteral(node.GetAsRealLiteral());
|
|
// TODO: This will probably have overflow issues, and should be fixed.
|
|
double val =
|
|
real.mantissa.getSExtValue() *
|
|
std::pow((real.is_decimal ? 10 : 2), real.exponent.getSExtValue());
|
|
llvm::APFloat llvm_val(val);
|
|
context.SetLoweredNodeAsValue(
|
|
node_id,
|
|
llvm::ConstantFP::get(context.builder().getDoubleTy(), llvm_val));
|
|
}
|
|
|
|
auto LoweringHandleReturn(LoweringContext& context, SemanticsNodeId /*node_id*/,
|
|
SemanticsNode /*node*/) -> void {
|
|
context.builder().CreateRetVoid();
|
|
}
|
|
|
|
auto LoweringHandleReturnExpression(LoweringContext& context,
|
|
SemanticsNodeId /*node_id*/,
|
|
SemanticsNode node) -> void {
|
|
SemanticsNodeId expr_id = node.GetAsReturnExpression();
|
|
context.builder().CreateRet(context.GetLoweredNodeAsValue(expr_id));
|
|
}
|
|
|
|
auto LoweringHandleStringLiteral(LoweringContext& /*context*/,
|
|
SemanticsNodeId /*node_id*/,
|
|
SemanticsNode node) -> void {
|
|
CARBON_FATAL() << "TODO: Add support: " << node;
|
|
}
|
|
|
|
auto LoweringHandleStructMemberAccess(LoweringContext& context,
|
|
SemanticsNodeId node_id,
|
|
SemanticsNode node) -> void {
|
|
auto [struct_id, member_index] = node.GetAsStructMemberAccess();
|
|
auto struct_type_id = context.semantics_ir().GetNode(struct_id).type_id();
|
|
auto* llvm_type = context.GetType(struct_type_id);
|
|
|
|
// Get type information for member names.
|
|
auto type_refs = context.semantics_ir().GetNodeBlock(
|
|
context.semantics_ir()
|
|
.GetNode(context.semantics_ir().GetType(struct_type_id))
|
|
.GetAsStructType());
|
|
auto member_name = context.semantics_ir().GetString(
|
|
context.semantics_ir()
|
|
.GetNode(type_refs[member_index.index])
|
|
.GetAsStructTypeField());
|
|
|
|
auto* gep = context.builder().CreateStructGEP(
|
|
llvm_type, context.GetLoweredNodeAsValue(struct_id), member_index.index,
|
|
member_name);
|
|
context.SetLoweredNodeAsValue(node_id, gep);
|
|
}
|
|
|
|
auto LoweringHandleStructType(LoweringContext& /*context*/,
|
|
SemanticsNodeId /*node_id*/,
|
|
SemanticsNode /*node*/) -> void {
|
|
// No action to take.
|
|
}
|
|
|
|
auto LoweringHandleStructTypeField(LoweringContext& /*context*/,
|
|
SemanticsNodeId /*node_id*/,
|
|
SemanticsNode /*node*/) -> void {
|
|
// No action to take.
|
|
}
|
|
|
|
auto LoweringHandleStructValue(LoweringContext& context,
|
|
SemanticsNodeId node_id, SemanticsNode node)
|
|
-> void {
|
|
auto* llvm_type = context.GetType(node.type_id());
|
|
auto* alloca = context.builder().CreateAlloca(
|
|
llvm_type, /*ArraySize=*/nullptr, "StructLiteralValue");
|
|
context.SetLoweredNodeAsValue(node_id, alloca);
|
|
|
|
auto refs = context.semantics_ir().GetNodeBlock(node.GetAsStructValue());
|
|
// Get type information for member names.
|
|
auto type_refs = context.semantics_ir().GetNodeBlock(
|
|
context.semantics_ir()
|
|
.GetNode(context.semantics_ir().GetType(node.type_id()))
|
|
.GetAsStructType());
|
|
for (int i = 0; i < static_cast<int>(refs.size()); ++i) {
|
|
auto member_name = context.semantics_ir().GetString(
|
|
context.semantics_ir().GetNode(type_refs[i]).GetAsStructTypeField());
|
|
auto* gep =
|
|
context.builder().CreateStructGEP(llvm_type, alloca, i, member_name);
|
|
context.builder().CreateStore(context.GetLoweredNodeAsValue(refs[i]), gep);
|
|
}
|
|
}
|
|
|
|
auto LoweringHandleStubReference(LoweringContext& context,
|
|
SemanticsNodeId node_id, SemanticsNode node)
|
|
-> void {
|
|
context.SetLoweredNodeAsValue(
|
|
node_id, context.GetLoweredNodeAsValue(node.GetAsStubReference()));
|
|
}
|
|
|
|
auto LoweringHandleVarStorage(LoweringContext& context, SemanticsNodeId node_id,
|
|
SemanticsNode node) -> void {
|
|
// TODO: This should provide a name, not just `var`. Also, LLVM requires
|
|
// globals to have a name. Do we want to generate a name, which would need to
|
|
// be consistent across translation units, or use the given name, which
|
|
// requires either looking ahead for BindName or restructuring semantics,
|
|
// either of which affects the destructuring due to the difference in
|
|
// storage?
|
|
auto* alloca = context.builder().CreateAlloca(context.GetType(node.type_id()),
|
|
/*ArraySize=*/nullptr, "var");
|
|
context.SetLoweredNodeAsValue(node_id, alloca);
|
|
}
|
|
|
|
} // namespace Carbon
|