diff --git a/toolchain/lowering/BUILD b/toolchain/lowering/BUILD index 141ae59592a3..e91858876984 100644 --- a/toolchain/lowering/BUILD +++ b/toolchain/lowering/BUILD @@ -12,7 +12,7 @@ cc_library( srcs = ["lower_to_llvm.cpp"], hdrs = ["lower_to_llvm.h"], deps = [ - ":lowering", + ":lowering_context", "//toolchain/semantics:semantics_ir", "@llvm-project//llvm:Core", "@llvm-project//llvm:Support", @@ -20,9 +20,12 @@ cc_library( ) cc_library( - name = "lowering", - srcs = ["lowering.cpp"], - hdrs = ["lowering.h"], + name = "lowering_context", + srcs = [ + "lowering_context.cpp", + "lowering_handle.cpp", + ], + hdrs = ["lowering_context.h"], deps = [ "//common:check", "//toolchain/semantics:semantics_ir", diff --git a/toolchain/lowering/lower_to_llvm.cpp b/toolchain/lowering/lower_to_llvm.cpp index f2bae57b9e4e..35c695a162af 100644 --- a/toolchain/lowering/lower_to_llvm.cpp +++ b/toolchain/lowering/lower_to_llvm.cpp @@ -4,15 +4,15 @@ #include "toolchain/lowering/lower_to_llvm.h" -#include "toolchain/lowering/lowering.h" +#include "toolchain/lowering/lowering_context.h" namespace Carbon { auto LowerToLLVM(llvm::LLVMContext& llvm_context, llvm::StringRef module_name, const SemanticsIR& semantics_ir) -> std::unique_ptr { - Lowering lowering(llvm_context, module_name, semantics_ir); - return lowering.Run(); + LoweringContext context(llvm_context, module_name, semantics_ir); + return context.Run(); } } // namespace Carbon diff --git a/toolchain/lowering/lowering.cpp b/toolchain/lowering/lowering.cpp deleted file mode 100644 index a17c8930e382..000000000000 --- a/toolchain/lowering/lowering.cpp +++ /dev/null @@ -1,209 +0,0 @@ -// 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.h" - -#include "toolchain/semantics/semantics_ir.h" - -namespace Carbon { - -Lowering::Lowering(llvm::LLVMContext& llvm_context, llvm::StringRef module_name, - const SemanticsIR& semantics_ir) - : llvm_context_(&llvm_context), - llvm_module_(std::make_unique(module_name, llvm_context)), - builder_(llvm_context), - semantics_ir_(&semantics_ir), - lowered_nodes_(semantics_ir_->nodes_size(), nullptr) { - CARBON_CHECK(!semantics_ir.has_errors()) - << "Generating LLVM IR from invalid SemanticsIR is unsupported."; -} - -auto Lowering::Run() -> std::unique_ptr { - CARBON_CHECK(llvm_module_) << "Run can only be called once."; - - LowerBlock(semantics_ir_->top_node_block_id()); - - while (!todo_blocks_.empty()) { - auto [llvm_block, block_id] = todo_blocks_.pop_back_val(); - builder_.SetInsertPoint(llvm_block); - LowerBlock(block_id); - } - - return std::move(llvm_module_); -} - -auto Lowering::LowerBlock(SemanticsNodeBlockId block_id) -> void { - for (const auto& node_id : semantics_ir_->GetNodeBlock(block_id)) { - auto node = semantics_ir_->GetNode(node_id); - switch (node.kind()) { -#define CARBON_SEMANTICS_NODE_KIND(Name) \ - case SemanticsNodeKind::Name: \ - Handle##Name##Node(node_id, node); \ - break; -#include "toolchain/semantics/semantics_node_kind.def" - } - } -} - -auto Lowering::LowerNodeToType(SemanticsNodeId node_id) -> llvm::Type* { - CARBON_CHECK(node_id.is_valid()); - switch (node_id.index) { - case SemanticsBuiltinKind::EmptyTuple.AsInt(): - // TODO: Should probably switch this to an actual empty tuple in the - // future, but it's implemented as void for now. - return builder_.getVoidTy(); - case SemanticsBuiltinKind::IntegerType.AsInt(): - // TODO: Handle different sizes. - return builder_.getInt32Ty(); - default: - CARBON_FATAL() << "Cannot use node as type: " << node_id; - } -} - -auto Lowering::HandleInvalidNode(SemanticsNodeId /*node_id*/, - SemanticsNode /*node*/) -> void { - llvm_unreachable("never in actual IR"); -} - -auto Lowering::HandleCrossReferenceNode(SemanticsNodeId /*node_id*/, - SemanticsNode node) -> void { - CARBON_FATAL() << "TODO: Add support: " << node; -} - -auto Lowering::HandleAssignNode(SemanticsNodeId /*node_id*/, SemanticsNode node) - -> void { - CARBON_FATAL() << "TODO: Add support: " << node; -} - -auto Lowering::HandleBinaryOperatorAddNode(SemanticsNodeId /*node_id*/, - SemanticsNode node) -> void { - CARBON_FATAL() << "TODO: Add support: " << node; -} - -auto Lowering::HandleBindNameNode(SemanticsNodeId /*node_id*/, - SemanticsNode node) -> void { - CARBON_FATAL() << "TODO: Add support: " << node; -} - -auto Lowering::HandleBuiltinNode(SemanticsNodeId /*node_id*/, - SemanticsNode node) -> void { - CARBON_FATAL() << "TODO: Add support: " << node; -} - -auto Lowering::HandleCallNode(SemanticsNodeId /*node_id*/, SemanticsNode node) - -> void { - CARBON_FATAL() << "TODO: Add support: " << node; -} - -auto Lowering::HandleCodeBlockNode(SemanticsNodeId /*node_id*/, - SemanticsNode node) -> void { - CARBON_FATAL() << "TODO: Add support: " << node; -} - -auto Lowering::HandleFunctionDeclarationNode(SemanticsNodeId /*node_id*/, - SemanticsNode node) -> void { - auto [name_id, callable_id] = node.GetAsFunctionDeclaration(); - auto callable = semantics_ir_->GetCallable(callable_id); - - // TODO: Lower type information for the arguments prior to building args. - auto param_refs = semantics_ir_->GetNodeBlock(callable.param_refs_id); - llvm::SmallVector args; - args.resize_for_overwrite(param_refs.size()); - for (int i = 0; i < static_cast(param_refs.size()); ++i) { - args[i] = LowerNodeToType(semantics_ir_->GetNode(param_refs[i]).type_id()); - } - - llvm::Type* return_type = LowerNodeToType( - callable.return_type_id.is_valid() ? callable.return_type_id - : SemanticsNodeId::BuiltinEmptyTuple); - llvm::FunctionType* function_type = - llvm::FunctionType::get(return_type, args, /*isVarArg=*/false); - auto* function = llvm::Function::Create( - function_type, llvm::Function::ExternalLinkage, - semantics_ir_->GetString(name_id), llvm_module_.get()); - - // Set parameter names. - for (int i = 0; i < static_cast(param_refs.size()); ++i) { - auto [param_name_id, _] = - semantics_ir_->GetNode(param_refs[i]).GetAsBindName(); - function->getArg(i)->setName(semantics_ir_->GetString(param_name_id)); - } -} - -auto Lowering::HandleFunctionDefinitionNode(SemanticsNodeId /*node_id*/, - SemanticsNode node) -> void { - auto [declaration_id, body_block_id] = node.GetAsFunctionDefinition(); - auto [name_id, callable_id] = - semantics_ir_->GetNode(declaration_id).GetAsFunctionDeclaration(); - - llvm::Function* function = - llvm_module_->getFunction(semantics_ir_->GetString(name_id)); - - // Create a new basic block to start insertion into. - llvm::BasicBlock* body = - llvm::BasicBlock::Create(*llvm_context_, "entry", function); - todo_blocks_.push_back({body, body_block_id}); -} - -auto Lowering::HandleIntegerLiteralNode(SemanticsNodeId node_id, - SemanticsNode node) -> void { - SemanticsIntegerLiteralId int_id = node.GetAsIntegerLiteral(); - llvm::APInt i = semantics_ir_->GetIntegerLiteral(int_id); - llvm::Value* v = - llvm::ConstantInt::get(builder_.getInt32Ty(), i.getLimitedValue()); - lowered_nodes_[node_id.index] = v; -} - -auto Lowering::HandleRealLiteralNode(SemanticsNodeId /*node_id*/, - SemanticsNode node) -> void { - CARBON_FATAL() << "TODO: Add support: " << node; -} - -auto Lowering::HandleReturnNode(SemanticsNodeId /*node_id*/, - SemanticsNode /*node*/) -> void { - builder_.CreateRetVoid(); -} - -auto Lowering::HandleReturnExpressionNode(SemanticsNodeId /*node_id*/, - SemanticsNode node) -> void { - SemanticsNodeId expr_id = node.GetAsReturnExpression(); - builder_.CreateRet(lowered_nodes_[expr_id.index]); -} - -auto Lowering::HandleStringLiteralNode(SemanticsNodeId /*node_id*/, - SemanticsNode node) -> void { - CARBON_FATAL() << "TODO: Add support: " << node; -} - -auto Lowering::HandleStructMemberAccessNode(SemanticsNodeId /*node_id*/, - SemanticsNode node) -> void { - CARBON_FATAL() << "TODO: Add support: " << node; -} - -auto Lowering::HandleStructTypeNode(SemanticsNodeId /*node_id*/, - SemanticsNode node) -> void { - CARBON_FATAL() << "TODO: Add support: " << node; -} - -auto Lowering::HandleStructTypeFieldNode(SemanticsNodeId /*node_id*/, - SemanticsNode node) -> void { - CARBON_FATAL() << "TODO: Add support: " << node; -} - -auto Lowering::HandleStructValueNode(SemanticsNodeId /*node_id*/, - SemanticsNode node) -> void { - CARBON_FATAL() << "TODO: Add support: " << node; -} - -auto Lowering::HandleStubReferenceNode(SemanticsNodeId /*node_id*/, - SemanticsNode node) -> void { - CARBON_FATAL() << "TODO: Add support: " << node; -} - -auto Lowering::HandleVarStorageNode(SemanticsNodeId /*node_id*/, - SemanticsNode node) -> void { - CARBON_FATAL() << "TODO: Add support: " << node; -} - -} // namespace Carbon diff --git a/toolchain/lowering/lowering_context.cpp b/toolchain/lowering/lowering_context.cpp new file mode 100644 index 000000000000..9cf3764225f3 --- /dev/null +++ b/toolchain/lowering/lowering_context.cpp @@ -0,0 +1,65 @@ +// 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 "toolchain/semantics/semantics_ir.h" + +namespace Carbon { + +LoweringContext::LoweringContext(llvm::LLVMContext& llvm_context, + llvm::StringRef module_name, + const SemanticsIR& semantics_ir) + : llvm_context_(&llvm_context), + llvm_module_(std::make_unique(module_name, llvm_context)), + builder_(llvm_context), + semantics_ir_(&semantics_ir), + lowered_nodes_(semantics_ir_->nodes_size(), nullptr) { + CARBON_CHECK(!semantics_ir.has_errors()) + << "Generating LLVM IR from invalid SemanticsIR is unsupported."; +} + +auto LoweringContext::Run() -> std::unique_ptr { + CARBON_CHECK(llvm_module_) << "Run can only be called once."; + + LowerBlock(semantics_ir_->top_node_block_id()); + + while (!todo_blocks_.empty()) { + auto [llvm_block, block_id] = todo_blocks_.pop_back_val(); + builder_.SetInsertPoint(llvm_block); + LowerBlock(block_id); + } + + return std::move(llvm_module_); +} + +auto LoweringContext::LowerBlock(SemanticsNodeBlockId block_id) -> void { + for (const auto& node_id : semantics_ir_->GetNodeBlock(block_id)) { + auto node = semantics_ir_->GetNode(node_id); + switch (node.kind()) { +#define CARBON_SEMANTICS_NODE_KIND(Name) \ + case SemanticsNodeKind::Name: \ + LoweringHandle##Name(*this, node_id, node); \ + break; +#include "toolchain/semantics/semantics_node_kind.def" + } + } +} + +auto LoweringContext::LowerNodeToType(SemanticsNodeId node_id) -> llvm::Type* { + CARBON_CHECK(node_id.is_valid()); + switch (node_id.index) { + case SemanticsBuiltinKind::EmptyTuple.AsInt(): + // TODO: Should probably switch this to an actual empty tuple in the + // future, but it's implemented as void for now. + return builder_.getVoidTy(); + case SemanticsBuiltinKind::IntegerType.AsInt(): + // TODO: Handle different sizes. + return builder_.getInt32Ty(); + default: + CARBON_FATAL() << "Cannot use node as type: " << node_id; + } +} + +} // namespace Carbon diff --git a/toolchain/lowering/lowering.h b/toolchain/lowering/lowering_context.h similarity index 56% rename from toolchain/lowering/lowering.h rename to toolchain/lowering/lowering_context.h index 0c323f1b5f6b..3589b25b48c8 100644 --- a/toolchain/lowering/lowering.h +++ b/toolchain/lowering/lowering_context.h @@ -2,8 +2,8 @@ // Exceptions. See /LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#ifndef CARBON_TOOLCHAIN_LOWERING_LOWERING_H_ -#define CARBON_TOOLCHAIN_LOWERING_LOWERING_H_ +#ifndef CARBON_TOOLCHAIN_LOWERING_LOWERING_CONTEXT_H_ +#define CARBON_TOOLCHAIN_LOWERING_LOWERING_CONTEXT_H_ #include "llvm/IR/IRBuilder.h" #include "llvm/IR/LLVMContext.h" @@ -13,31 +13,36 @@ namespace Carbon { -// Use LowerToLLVM rather than calling this directly. -// -// This carries state for lowering. `Run()` should only be called once, and -// handles the main execution. -class Lowering { +// Context and shared functionality for lowering handlers. +class LoweringContext { public: - explicit Lowering(llvm::LLVMContext& llvm_context, - llvm::StringRef module_name, - const SemanticsIR& semantics_ir); + explicit LoweringContext(llvm::LLVMContext& llvm_context, + llvm::StringRef module_name, + const SemanticsIR& semantics_ir); - // Lowers the SemanticsIR to LLVM IR. + // Lowers the SemanticsIR to LLVM IR. Should only be called once, and handles + // the main execution loop. auto Run() -> std::unique_ptr; - private: - // Declare handlers for each SemanticsIR node. -#define CARBON_SEMANTICS_NODE_KIND(Name) \ - auto Handle##Name##Node(SemanticsNodeId node_id, SemanticsNode node)->void; -#include "toolchain/semantics/semantics_node_kind.def" - - // Runs lowering for a block. - auto LowerBlock(SemanticsNodeBlockId block_id) -> void; - // Returns a type for the given node. auto LowerNodeToType(SemanticsNodeId node_id) -> llvm::Type*; + auto llvm_context() -> llvm::LLVMContext& { return *llvm_context_; } + auto llvm_module() -> llvm::Module& { return *llvm_module_; } + auto builder() -> llvm::IRBuilder<>& { return builder_; } + auto semantics_ir() -> const SemanticsIR& { return *semantics_ir_; } + auto todo_blocks() -> llvm::SmallVector< + std::pair>& { + return todo_blocks_; + } + auto lowered_nodes() -> llvm::SmallVector& { + return lowered_nodes_; + } + + private: + // Runs lowering for a block. + auto LowerBlock(SemanticsNodeBlockId block_id) -> void; + // State for building the LLVM IR. llvm::LLVMContext* llvm_context_; std::unique_ptr llvm_module_; @@ -61,6 +66,13 @@ class Lowering { llvm::SmallVector lowered_nodes_; }; +// Declare handlers for each SemanticsIR node. +#define CARBON_SEMANTICS_NODE_KIND(Name) \ + auto LoweringHandle##Name(LoweringContext& context, SemanticsNodeId node_id, \ + SemanticsNode node) \ + ->void; +#include "toolchain/semantics/semantics_node_kind.def" + } // namespace Carbon -#endif // CARBON_TOOLCHAIN_LOWERING_LOWERING_H_ +#endif // CARBON_TOOLCHAIN_LOWERING_LOWERING_CONTEXT_H_ diff --git a/toolchain/lowering/lowering_handle.cpp b/toolchain/lowering/lowering_handle.cpp new file mode 100644 index 000000000000..ff1626e0e9a6 --- /dev/null +++ b/toolchain/lowering/lowering_handle.cpp @@ -0,0 +1,176 @@ +// 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 { + CARBON_FATAL() << "TODO: Add support: " << node; +} + +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 { + CARBON_FATAL() << "TODO: Add support: " << node; +} + +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 { + CARBON_FATAL() << "TODO: Add support: " << node; +} + +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 args; + args.resize_for_overwrite(param_refs.size()); + for (int i = 0; i < static_cast(param_refs.size()); ++i) { + args[i] = context.LowerNodeToType( + context.semantics_ir().GetNode(param_refs[i]).type_id()); + } + + llvm::Type* return_type = context.LowerNodeToType( + callable.return_type_id.is_valid() ? callable.return_type_id + : SemanticsNodeId::BuiltinEmptyTuple); + 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()); + + // Set parameter names. + for (int i = 0; i < static_cast(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 { + SemanticsIntegerLiteralId int_id = node.GetAsIntegerLiteral(); + llvm::APInt i = context.semantics_ir().GetIntegerLiteral(int_id); + llvm::Value* v = llvm::ConstantInt::get(context.builder().getInt32Ty(), + i.getLimitedValue()); + context.lowered_nodes()[node_id.index] = v; +} + +auto LoweringHandleRealLiteral(LoweringContext& /*context*/, + SemanticsNodeId /*node_id*/, SemanticsNode node) + -> void { + CARBON_FATAL() << "TODO: Add support: " << node; +} + +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.lowered_nodes()[expr_id.index]); +} + +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 { + CARBON_FATAL() << "TODO: Add support: " << node; +} + +auto LoweringHandleStructType(LoweringContext& /*context*/, + SemanticsNodeId /*node_id*/, SemanticsNode node) + -> void { + CARBON_FATAL() << "TODO: Add support: " << node; +} + +auto LoweringHandleStructTypeField(LoweringContext& /*context*/, + SemanticsNodeId /*node_id*/, + SemanticsNode node) -> void { + CARBON_FATAL() << "TODO: Add support: " << node; +} + +auto LoweringHandleStructValue(LoweringContext& /*context*/, + SemanticsNodeId /*node_id*/, SemanticsNode node) + -> void { + CARBON_FATAL() << "TODO: Add support: " << node; +} + +auto LoweringHandleStubReference(LoweringContext& /*context*/, + SemanticsNodeId /*node_id*/, + SemanticsNode node) -> void { + CARBON_FATAL() << "TODO: Add support: " << node; +} + +auto LoweringHandleVarStorage(LoweringContext& /*context*/, + SemanticsNodeId /*node_id*/, SemanticsNode node) + -> void { + CARBON_FATAL() << "TODO: Add support: " << node; +} + +} // namespace Carbon