Просмотр исходного кода

Split out a per-function lowering context from `LoweringContext`. (#2901)

This is being done in preparation for adding more state to per-function
lowering, to handle lowering functions containing more than one block.
Richard Smith 2 лет назад
Родитель
Сommit
f7f73d42ca

+ 5 - 1
toolchain/lowering/BUILD

@@ -23,9 +23,13 @@ cc_library(
     name = "lowering_context",
     srcs = [
         "lowering_context.cpp",
+        "lowering_function_context.cpp",
         "lowering_handle.cpp",
     ],
-    hdrs = ["lowering_context.h"],
+    hdrs = [
+        "lowering_context.h",
+        "lowering_function_context.h",
+    ],
     deps = [
         "//common:check",
         "//common:vlog",

+ 14 - 32
toolchain/lowering/lowering_context.cpp

@@ -5,6 +5,7 @@
 #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"
 
@@ -16,13 +17,13 @@ LoweringContext::LoweringContext(llvm::LLVMContext& llvm_context,
                                  llvm::raw_ostream* vlog_stream)
     : llvm_context_(&llvm_context),
       llvm_module_(std::make_unique<llvm::Module>(module_name, llvm_context)),
-      builder_(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.";
 
@@ -90,38 +91,30 @@ auto LoweringContext::BuildFunctionDefinition(SemanticsFunctionId function_id)
     // Function is probably defined in another file; not an error.
     return;
   }
-  auto* llvm_function = GetFunction(function_id);
 
-  // Create a new basic block to start insertion into.
-  builder_.SetInsertPoint(llvm::BasicBlock::Create(llvm_context(), "entry",
-                                                   GetFunction(function_id)));
-  CARBON_CHECK(locals_.empty());
+  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;
-    CARBON_CHECK(
-        locals_.insert({param_storage, llvm_function->getArg(i)}).second)
-        << "Duplicate param: " << param_refs[i];
+    function_lowering.SetLocal(param_storage, llvm_function->getArg(i));
   }
 
-  CARBON_VLOG() << "Lowering " << body_id << "\n";
-  for (const auto& node_id : semantics_ir_->GetNodeBlock(body_id)) {
-    auto node = semantics_ir_->GetNode(node_id);
+  CARBON_VLOG() << "Lowering " << function.body_id << "\n";
+  for (const auto& node_id : semantics_ir().GetNodeBlock(function.body_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(*this, node_id, node); \
+#define CARBON_SEMANTICS_NODE_KIND(Name)                    \
+  case SemanticsNodeKind::Name:                             \
+    LoweringHandle##Name(function_lowering, node_id, node); \
     break;
 #include "toolchain/semantics/semantics_node_kind.def"
     }
   }
-
-  // Clear locals.
-  locals_.clear();
 }
 
 auto LoweringContext::BuildType(SemanticsNodeId node_id) -> llvm::Type* {
@@ -137,14 +130,14 @@ auto LoweringContext::BuildType(SemanticsNodeId node_id) -> llvm::Type* {
           SemanticsBuiltinKind::FromInt(node_id.index).name());
     case SemanticsBuiltinKind::FloatingPointType.AsInt():
       // TODO: Handle different sizes.
-      return builder_.getDoubleTy();
+      return llvm::Type::getDoubleTy(*llvm_context_);
     case SemanticsBuiltinKind::IntegerType.AsInt():
       // TODO: Handle different sizes.
-      return builder_.getInt32Ty();
+      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 builder_.getInt1Ty();
+      return llvm::Type::getInt1Ty(*llvm_context_);
   }
 
   auto node = semantics_ir_->GetNode(node_id);
@@ -170,15 +163,4 @@ auto LoweringContext::BuildType(SemanticsNodeId node_id) -> llvm::Type* {
   }
 }
 
-auto LoweringContext::GetLocalLoaded(SemanticsNodeId node_id) -> llvm::Value* {
-  auto* value = GetLocal(node_id);
-  if (llvm::isa<llvm::AllocaInst, llvm::GetElementPtrInst>(value)) {
-    auto* load_type = GetType(semantics_ir().GetNode(node_id).type_id());
-    return builder().CreateLoad(load_type, value);
-  } else {
-    // No load is needed.
-    return value;
-  }
-}
-
 }  // namespace Carbon

+ 0 - 32
toolchain/lowering/lowering_context.h

@@ -5,7 +5,6 @@
 #ifndef CARBON_TOOLCHAIN_LOWERING_LOWERING_CONTEXT_H_
 #define CARBON_TOOLCHAIN_LOWERING_LOWERING_CONTEXT_H_
 
-#include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/Module.h"
 #include "toolchain/semantics/semantics_ir.h"
@@ -25,23 +24,6 @@ class LoweringContext {
   // the main execution loop.
   auto Run() -> std::unique_ptr<llvm::Module>;
 
-  // Returns a local (versus global) value for the given node.
-  auto GetLocal(SemanticsNodeId node_id) -> llvm::Value* {
-    auto it = locals_.find(node_id);
-    CARBON_CHECK(it != locals_.end()) << "Missing local: " << node_id;
-    return it->second;
-  }
-
-  // Returns a local (versus global) value for the given node in loaded state.
-  // Loads will only be inserted on an as-needed basis.
-  auto GetLocalLoaded(SemanticsNodeId node_id) -> llvm::Value*;
-
-  // Sets the value for the given node.
-  auto SetLocal(SemanticsNodeId node_id, llvm::Value* value) {
-    bool added = locals_.insert({node_id, value}).second;
-    CARBON_CHECK(added) << "Duplicate local insert: " << node_id;
-  }
-
   // Gets a callable's function.
   auto GetFunction(SemanticsFunctionId function_id) -> llvm::Function* {
     CARBON_CHECK(functions_[function_id.index] != nullptr) << function_id;
@@ -57,7 +39,6 @@ class LoweringContext {
 
   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_; }
 
  private:
@@ -77,7 +58,6 @@ class LoweringContext {
   // State for building the LLVM IR.
   llvm::LLVMContext* llvm_context_;
   std::unique_ptr<llvm::Module> llvm_module_;
-  llvm::IRBuilder<> builder_;
 
   // The input Semantics IR.
   const SemanticsIR* const semantics_ir_;
@@ -85,11 +65,6 @@ class LoweringContext {
   // The optional vlog stream.
   llvm::raw_ostream* vlog_stream_;
 
-  // Maps a function's SemanticsIR nodes to lowered values.
-  // TODO: Handle nested scopes. Right now this is just cleared at the end of
-  // every block.
-  llvm::DenseMap<SemanticsNodeId, llvm::Value*> locals_;
-
   // Maps callables to lowered functions. Semantics treats callables as the
   // canonical form of a function, so lowering needs to do the same.
   llvm::SmallVector<llvm::Function*> functions_;
@@ -98,13 +73,6 @@ class LoweringContext {
   llvm::SmallVector<llvm::Type*> types_;
 };
 
-// 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_CONTEXT_H_

+ 34 - 0
toolchain/lowering/lowering_function_context.cpp

@@ -0,0 +1,34 @@
+// 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_function_context.h"
+
+#include "common/vlog.h"
+#include "toolchain/semantics/semantics_ir.h"
+#include "toolchain/semantics/semantics_node_kind.h"
+
+namespace Carbon {
+
+LoweringFunctionContext::LoweringFunctionContext(
+    LoweringContext& lowering_context, llvm::Function* function)
+    : lowering_context_(&lowering_context),
+      function_(function),
+      builder_(lowering_context.llvm_context()) {
+  builder_.SetInsertPoint(
+      llvm::BasicBlock::Create(llvm_context(), "entry", function_));
+}
+
+auto LoweringFunctionContext::GetLocalLoaded(SemanticsNodeId node_id)
+    -> llvm::Value* {
+  auto* value = GetLocal(node_id);
+  if (llvm::isa<llvm::AllocaInst, llvm::GetElementPtrInst>(value)) {
+    auto* load_type = GetType(semantics_ir().GetNode(node_id).type_id());
+    return builder().CreateLoad(load_type, value);
+  } else {
+    // No load is needed.
+    return value;
+  }
+}
+
+}  // namespace Carbon

+ 86 - 0
toolchain/lowering/lowering_function_context.h

@@ -0,0 +1,86 @@
+// 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
+
+#ifndef CARBON_TOOLCHAIN_LOWERING_LOWERING_FUNCTION_CONTEXT_H_
+#define CARBON_TOOLCHAIN_LOWERING_LOWERING_FUNCTION_CONTEXT_H_
+
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "toolchain/lowering/lowering_context.h"
+#include "toolchain/semantics/semantics_ir.h"
+#include "toolchain/semantics/semantics_node.h"
+
+namespace Carbon {
+
+// Context and shared functionality for lowering handlers that produce an
+// `llvm::Function` definition.
+class LoweringFunctionContext {
+ public:
+  explicit LoweringFunctionContext(LoweringContext& lowering_context,
+                                   llvm::Function* function);
+
+  // Returns a local (versus global) value for the given node.
+  auto GetLocal(SemanticsNodeId node_id) -> llvm::Value* {
+    auto it = locals_.find(node_id);
+    CARBON_CHECK(it != locals_.end()) << "Missing local: " << node_id;
+    return it->second;
+  }
+
+  // Returns a local (versus global) value for the given node in loaded state.
+  // Loads will only be inserted on an as-needed basis.
+  auto GetLocalLoaded(SemanticsNodeId node_id) -> llvm::Value*;
+
+  // Sets the value for the given node.
+  auto SetLocal(SemanticsNodeId node_id, llvm::Value* value) {
+    bool added = locals_.insert({node_id, value}).second;
+    CARBON_CHECK(added) << "Duplicate local insert: " << node_id;
+  }
+
+  // Gets a callable's function.
+  auto GetFunction(SemanticsFunctionId function_id) -> llvm::Function* {
+    return lowering_context_->GetFunction(function_id);
+  }
+
+  // Returns a lowered type for the given type_id.
+  auto GetType(SemanticsTypeId type_id) -> llvm::Type* {
+    return lowering_context_->GetType(type_id);
+  }
+
+  auto llvm_context() -> llvm::LLVMContext& {
+    return lowering_context_->llvm_context();
+  }
+  auto llvm_module() -> llvm::Module& {
+    return lowering_context_->llvm_module();
+  }
+  auto builder() -> llvm::IRBuilder<>& { return builder_; }
+  auto semantics_ir() -> const SemanticsIR& {
+    return lowering_context_->semantics_ir();
+  }
+
+ private:
+  // Context for the overall lowering process.
+  LoweringContext* lowering_context_;
+
+  // The IR function we're generating.
+  llvm::Function* function_;
+
+  llvm::IRBuilder<> builder_;
+
+  // Maps a function's SemanticsIR nodes to lowered values.
+  // TODO: Handle nested scopes. Right now this is just cleared at the end of
+  // every block.
+  llvm::DenseMap<SemanticsNodeId, llvm::Value*> locals_;
+};
+
+// Declare handlers for each SemanticsIR node.
+#define CARBON_SEMANTICS_NODE_KIND(Name)                                 \
+  auto LoweringHandle##Name(LoweringFunctionContext& context,            \
+                            SemanticsNodeId node_id, SemanticsNode node) \
+      ->void;
+#include "toolchain/semantics/semantics_node_kind.def"
+
+}  // namespace Carbon
+
+#endif  // CARBON_TOOLCHAIN_LOWERING_LOWERING_FUNCTION_CONTEXT_H_

+ 34 - 31
toolchain/lowering/lowering_handle.cpp

@@ -2,48 +2,49 @@
 // Exceptions. See /LICENSE for license information.
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 
-#include "toolchain/lowering/lowering_context.h"
+#include "toolchain/lowering/lowering_function_context.h"
 
 namespace Carbon {
 
-auto LoweringHandleInvalid(LoweringContext& /*context*/,
+auto LoweringHandleInvalid(LoweringFunctionContext& /*context*/,
                            SemanticsNodeId /*node_id*/, SemanticsNode /*node*/)
     -> void {
   llvm_unreachable("never in actual IR");
 }
 
-auto LoweringHandleCrossReference(LoweringContext& /*context*/,
+auto LoweringHandleCrossReference(LoweringFunctionContext& /*context*/,
                                   SemanticsNodeId /*node_id*/,
                                   SemanticsNode node) -> void {
   CARBON_FATAL() << "TODO: Add support: " << node;
 }
 
-auto LoweringHandleAssign(LoweringContext& context, SemanticsNodeId /*node_id*/,
-                          SemanticsNode node) -> void {
+auto LoweringHandleAssign(LoweringFunctionContext& context,
+                          SemanticsNodeId /*node_id*/, SemanticsNode node)
+    -> void {
   auto [storage_id, value_id] = node.GetAsAssign();
   context.builder().CreateStore(context.GetLocalLoaded(value_id),
                                 context.GetLocal(storage_id));
 }
 
-auto LoweringHandleBinaryOperatorAdd(LoweringContext& /*context*/,
+auto LoweringHandleBinaryOperatorAdd(LoweringFunctionContext& /*context*/,
                                      SemanticsNodeId /*node_id*/,
                                      SemanticsNode node) -> void {
   CARBON_FATAL() << "TODO: Add support: " << node;
 }
 
-auto LoweringHandleBindName(LoweringContext& /*context*/,
+auto LoweringHandleBindName(LoweringFunctionContext& /*context*/,
                             SemanticsNodeId /*node_id*/, SemanticsNode /*node*/)
     -> void {
   // Probably need to do something here, but not necessary for now.
 }
 
-auto LoweringHandleBlockArg(LoweringContext& /*context*/,
+auto LoweringHandleBlockArg(LoweringFunctionContext& /*context*/,
                             SemanticsNodeId /*node_id*/, SemanticsNode node)
     -> void {
   CARBON_FATAL() << "TODO: Add support: " << node;
 }
 
-auto LoweringHandleBoolLiteral(LoweringContext& context,
+auto LoweringHandleBoolLiteral(LoweringFunctionContext& context,
                                SemanticsNodeId node_id, SemanticsNode node)
     -> void {
   llvm::Value* v = llvm::ConstantInt::get(context.builder().getInt1Ty(),
@@ -51,32 +52,32 @@ auto LoweringHandleBoolLiteral(LoweringContext& context,
   context.SetLocal(node_id, v);
 }
 
-auto LoweringHandleBranch(LoweringContext& /*context*/,
+auto LoweringHandleBranch(LoweringFunctionContext& /*context*/,
                           SemanticsNodeId /*node_id*/, SemanticsNode node)
     -> void {
   CARBON_FATAL() << "TODO: Add support: " << node;
 }
 
-auto LoweringHandleBranchIf(LoweringContext& /*context*/,
+auto LoweringHandleBranchIf(LoweringFunctionContext& /*context*/,
                             SemanticsNodeId /*node_id*/, SemanticsNode node)
     -> void {
   CARBON_FATAL() << "TODO: Add support: " << node;
 }
 
-auto LoweringHandleBranchWithArg(LoweringContext& /*context*/,
+auto LoweringHandleBranchWithArg(LoweringFunctionContext& /*context*/,
                                  SemanticsNodeId /*node_id*/,
                                  SemanticsNode node) -> void {
   CARBON_FATAL() << "TODO: Add support: " << node;
 }
 
-auto LoweringHandleBuiltin(LoweringContext& /*context*/,
+auto LoweringHandleBuiltin(LoweringFunctionContext& /*context*/,
                            SemanticsNodeId /*node_id*/, SemanticsNode node)
     -> void {
   CARBON_FATAL() << "TODO: Add support: " << node;
 }
 
-auto LoweringHandleCall(LoweringContext& context, SemanticsNodeId node_id,
-                        SemanticsNode node) -> void {
+auto LoweringHandleCall(LoweringFunctionContext& context,
+                        SemanticsNodeId node_id, SemanticsNode node) -> void {
   auto [refs_id, function_id] = node.GetAsCall();
   auto* function = context.GetFunction(function_id);
   std::vector<llvm::Value*> args;
@@ -88,13 +89,13 @@ auto LoweringHandleCall(LoweringContext& context, SemanticsNodeId node_id,
   context.SetLocal(node_id, value);
 }
 
-auto LoweringHandleCodeBlock(LoweringContext& /*context*/,
+auto LoweringHandleCodeBlock(LoweringFunctionContext& /*context*/,
                              SemanticsNodeId /*node_id*/, SemanticsNode node)
     -> void {
   CARBON_FATAL() << "TODO: Add support: " << node;
 }
 
-auto LoweringHandleFunctionDeclaration(LoweringContext& /*context*/,
+auto LoweringHandleFunctionDeclaration(LoweringFunctionContext& /*context*/,
                                        SemanticsNodeId /*node_id*/,
                                        SemanticsNode node) -> void {
   CARBON_FATAL()
@@ -103,7 +104,7 @@ auto LoweringHandleFunctionDeclaration(LoweringContext& /*context*/,
       << node;
 }
 
-auto LoweringHandleIntegerLiteral(LoweringContext& context,
+auto LoweringHandleIntegerLiteral(LoweringFunctionContext& context,
                                   SemanticsNodeId node_id, SemanticsNode node)
     -> void {
   llvm::APInt i =
@@ -114,7 +115,7 @@ auto LoweringHandleIntegerLiteral(LoweringContext& context,
   context.SetLocal(node_id, v);
 }
 
-auto LoweringHandleRealLiteral(LoweringContext& context,
+auto LoweringHandleRealLiteral(LoweringFunctionContext& context,
                                SemanticsNodeId node_id, SemanticsNode node)
     -> void {
   SemanticsRealLiteral real =
@@ -128,25 +129,26 @@ auto LoweringHandleRealLiteral(LoweringContext& context,
                                 context.builder().getDoubleTy(), llvm_val));
 }
 
-auto LoweringHandleReturn(LoweringContext& context, SemanticsNodeId /*node_id*/,
-                          SemanticsNode /*node*/) -> void {
+auto LoweringHandleReturn(LoweringFunctionContext& context,
+                          SemanticsNodeId /*node_id*/, SemanticsNode /*node*/)
+    -> void {
   context.builder().CreateRetVoid();
 }
 
-auto LoweringHandleReturnExpression(LoweringContext& context,
+auto LoweringHandleReturnExpression(LoweringFunctionContext& context,
                                     SemanticsNodeId /*node_id*/,
                                     SemanticsNode node) -> void {
   SemanticsNodeId expr_id = node.GetAsReturnExpression();
   context.builder().CreateRet(context.GetLocalLoaded(expr_id));
 }
 
-auto LoweringHandleStringLiteral(LoweringContext& /*context*/,
+auto LoweringHandleStringLiteral(LoweringFunctionContext& /*context*/,
                                  SemanticsNodeId /*node_id*/,
                                  SemanticsNode node) -> void {
   CARBON_FATAL() << "TODO: Add support: " << node;
 }
 
-auto LoweringHandleStructMemberAccess(LoweringContext& context,
+auto LoweringHandleStructMemberAccess(LoweringFunctionContext& context,
                                       SemanticsNodeId node_id,
                                       SemanticsNode node) -> void {
   auto [struct_id, member_index] = node.GetAsStructMemberAccess();
@@ -168,19 +170,19 @@ auto LoweringHandleStructMemberAccess(LoweringContext& context,
   context.SetLocal(node_id, gep);
 }
 
-auto LoweringHandleStructType(LoweringContext& /*context*/,
+auto LoweringHandleStructType(LoweringFunctionContext& /*context*/,
                               SemanticsNodeId /*node_id*/,
                               SemanticsNode /*node*/) -> void {
   // No action to take.
 }
 
-auto LoweringHandleStructTypeField(LoweringContext& /*context*/,
+auto LoweringHandleStructTypeField(LoweringFunctionContext& /*context*/,
                                    SemanticsNodeId /*node_id*/,
                                    SemanticsNode /*node*/) -> void {
   // No action to take.
 }
 
-auto LoweringHandleStructValue(LoweringContext& context,
+auto LoweringHandleStructValue(LoweringFunctionContext& context,
                                SemanticsNodeId node_id, SemanticsNode node)
     -> void {
   auto* llvm_type = context.GetType(node.type_id());
@@ -203,21 +205,22 @@ auto LoweringHandleStructValue(LoweringContext& context,
   }
 }
 
-auto LoweringHandleStubReference(LoweringContext& context,
+auto LoweringHandleStubReference(LoweringFunctionContext& context,
                                  SemanticsNodeId node_id, SemanticsNode node)
     -> void {
   context.SetLocal(node_id, context.GetLocal(node.GetAsStubReference()));
 }
 
-auto LoweringHandleUnaryOperatorNot(LoweringContext& context,
+auto LoweringHandleUnaryOperatorNot(LoweringFunctionContext& context,
                                     SemanticsNodeId node_id, SemanticsNode node)
     -> void {
   context.SetLocal(node_id, context.builder().CreateNot(context.GetLocal(
                                 node.GetAsUnaryOperatorNot())));
 }
 
-auto LoweringHandleVarStorage(LoweringContext& context, SemanticsNodeId node_id,
-                              SemanticsNode node) -> void {
+auto LoweringHandleVarStorage(LoweringFunctionContext& 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