From ee9f883ef361b8f78621a48a73f8776ecc007b01 Mon Sep 17 00:00:00 2001 From: Jon Ross-Perkins Date: Mon, 15 May 2023 14:55:10 -0700 Subject: [PATCH] Refactoring lowering logic into separate files. (#2820) This echoes https://github.com/carbon-language/carbon-lang/pull/2818 and the philosophy is mostly covered there. This isn't necessary for lowering right now, but things are likely to head in that direction and maintaining the context boundary will reduce blurring of lines. For now I'm just putting all the handlers in one file. --- toolchain/lowering/BUILD | 11 +- toolchain/lowering/lower_to_llvm.cpp | 6 +- toolchain/lowering/lowering.cpp | 209 ------------------ toolchain/lowering/lowering_context.cpp | 65 ++++++ .../{lowering.h => lowering_context.h} | 54 +++-- toolchain/lowering/lowering_handle.cpp | 176 +++++++++++++++ 6 files changed, 284 insertions(+), 237 deletions(-) delete mode 100644 toolchain/lowering/lowering.cpp create mode 100644 toolchain/lowering/lowering_context.cpp rename toolchain/lowering/{lowering.h => lowering_context.h} (56%) create mode 100644 toolchain/lowering/lowering_handle.cpp 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