فهرست منبع

Add loads for data. (#2860)

Start inserting loads when getting a value. This is done conditionally, but in theory we could start tracking nodes which need loading differently if the `isa` is considered cumbersome.
Jon Ross-Perkins 2 سال پیش
والد
کامیت
4152cf720a

+ 13 - 2
toolchain/lowering/lowering_context.cpp

@@ -46,10 +46,10 @@ auto LoweringContext::Run() -> std::unique_ptr<llvm::Module> {
 }
 }
 
 
 auto LoweringContext::LowerBlock(SemanticsNodeBlockId block_id) -> void {
 auto LoweringContext::LowerBlock(SemanticsNodeBlockId block_id) -> void {
-  CARBON_VLOG() << "Lowering block " << block_id << "\n";
+  CARBON_VLOG() << "Lowering " << block_id << "\n";
   for (const auto& node_id : semantics_ir_->GetNodeBlock(block_id)) {
   for (const auto& node_id : semantics_ir_->GetNodeBlock(block_id)) {
     auto node = semantics_ir_->GetNode(node_id);
     auto node = semantics_ir_->GetNode(node_id);
-    CARBON_VLOG() << "Lowering node" << node_id << ": " << node << "\n";
+    CARBON_VLOG() << "Lowering " << node_id << ": " << node << "\n";
     switch (node.kind()) {
     switch (node.kind()) {
 #define CARBON_SEMANTICS_NODE_KIND(Name)        \
 #define CARBON_SEMANTICS_NODE_KIND(Name)        \
   case SemanticsNodeKind::Name:                 \
   case SemanticsNodeKind::Name:                 \
@@ -102,4 +102,15 @@ auto LoweringContext::BuildType(SemanticsNodeId node_id) -> llvm::Type* {
   }
   }
 }
 }
 
 
+auto LoweringContext::GetNodeLoaded(SemanticsNodeId node_id) -> llvm::Value* {
+  auto* value = GetNode(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
 }  // namespace Carbon

+ 4 - 0
toolchain/lowering/lowering_context.h

@@ -31,6 +31,10 @@ class LoweringContext {
     return nodes_[node_id.index];
     return nodes_[node_id.index];
   }
   }
 
 
+  // Returns a value for the given node in loaded state. Loads will only be
+  // inserted on an as-needed basis.
+  auto GetNodeLoaded(SemanticsNodeId node_id) -> llvm::Value*;
+
   // Sets the value for the given node.
   // Sets the value for the given node.
   auto SetNode(SemanticsNodeId node_id, llvm::Value* value) {
   auto SetNode(SemanticsNodeId node_id, llvm::Value* value) {
     CARBON_CHECK(!nodes_[node_id.index]) << node_id;
     CARBON_CHECK(!nodes_[node_id.index]) << node_id;

+ 3 - 3
toolchain/lowering/lowering_handle.cpp

@@ -21,7 +21,7 @@ auto LoweringHandleCrossReference(LoweringContext& /*context*/,
 auto LoweringHandleAssign(LoweringContext& context, SemanticsNodeId /*node_id*/,
 auto LoweringHandleAssign(LoweringContext& context, SemanticsNodeId /*node_id*/,
                           SemanticsNode node) -> void {
                           SemanticsNode node) -> void {
   auto [storage_id, value_id] = node.GetAsAssign();
   auto [storage_id, value_id] = node.GetAsAssign();
-  context.builder().CreateStore(context.GetNode(value_id),
+  context.builder().CreateStore(context.GetNodeLoaded(value_id),
                                 context.GetNode(storage_id));
                                 context.GetNode(storage_id));
 }
 }
 
 
@@ -49,7 +49,7 @@ auto LoweringHandleCall(LoweringContext& context, SemanticsNodeId node_id,
   auto* function = context.GetCallable(callable_id);
   auto* function = context.GetCallable(callable_id);
   std::vector<llvm::Value*> args;
   std::vector<llvm::Value*> args;
   for (auto ref_id : context.semantics_ir().GetNodeBlock(refs_id)) {
   for (auto ref_id : context.semantics_ir().GetNodeBlock(refs_id)) {
-    args.push_back(context.GetNode(ref_id));
+    args.push_back(context.GetNodeLoaded(ref_id));
   }
   }
   auto* value =
   auto* value =
       context.builder().CreateCall(function, args, function->getName());
       context.builder().CreateCall(function, args, function->getName());
@@ -147,7 +147,7 @@ auto LoweringHandleReturnExpression(LoweringContext& context,
                                     SemanticsNodeId /*node_id*/,
                                     SemanticsNodeId /*node_id*/,
                                     SemanticsNode node) -> void {
                                     SemanticsNode node) -> void {
   SemanticsNodeId expr_id = node.GetAsReturnExpression();
   SemanticsNodeId expr_id = node.GetAsReturnExpression();
-  context.builder().CreateRet(context.GetNode(expr_id));
+  context.builder().CreateRet(context.GetNodeLoaded(expr_id));
 }
 }
 
 
 auto LoweringHandleStringLiteral(LoweringContext& /*context*/,
 auto LoweringHandleStringLiteral(LoweringContext& /*context*/,

+ 30 - 0
toolchain/lowering/testdata/function/call/empty_struct.carbon

@@ -0,0 +1,30 @@
+// 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
+//
+// AUTOUPDATE
+// CHECK:STDOUT: ; ModuleID = 'empty_struct.carbon'
+// CHECK:STDOUT: source_filename = "empty_struct.carbon"
+// CHECK:STDOUT:
+// CHECK:STDOUT: %EmptyTupleType = type {}
+// CHECK:STDOUT: %StructLiteralType = type {}
+// CHECK:STDOUT:
+// CHECK:STDOUT: define %EmptyTupleType @Echo(%StructLiteralType %a) {
+// CHECK:STDOUT: entry:
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: define %EmptyTupleType @Main() {
+// CHECK:STDOUT: entry:
+// CHECK:STDOUT:   %StructLiteralValue = alloca %StructLiteralType, align 8
+// CHECK:STDOUT:   %0 = load %StructLiteralType, ptr %StructLiteralValue, align 1
+// CHECK:STDOUT:   %Echo = call %EmptyTupleType @Echo(%StructLiteralType %0)
+// CHECK:STDOUT: }
+
+fn Echo(a: {}) {
+  // TODO: Set return type to `{}` and return `a` back.
+}
+
+fn Main() {
+  // TODO: Store the returned `{}`.
+  Echo({});
+}

+ 28 - 0
toolchain/lowering/testdata/function/call/var_param.carbon

@@ -0,0 +1,28 @@
+// 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
+//
+// AUTOUPDATE
+// CHECK:STDOUT: ; ModuleID = 'var_param.carbon'
+// CHECK:STDOUT: source_filename = "var_param.carbon"
+// CHECK:STDOUT:
+// CHECK:STDOUT: %EmptyTupleType = type {}
+// CHECK:STDOUT:
+// CHECK:STDOUT: define %EmptyTupleType @DoNothing(i32 %a) {
+// CHECK:STDOUT: entry:
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: define %EmptyTupleType @Main() {
+// CHECK:STDOUT: entry:
+// CHECK:STDOUT:   %var = alloca i32, align 4
+// CHECK:STDOUT:   store i32 0, ptr %var, align 4
+// CHECK:STDOUT:   %0 = load i32, ptr %var, align 4
+// CHECK:STDOUT:   %DoNothing = call %EmptyTupleType @DoNothing(i32 %0)
+// CHECK:STDOUT: }
+
+fn DoNothing(a: i32) {}
+
+fn Main() {
+  var a: i32 = 0;
+  DoNothing(a);
+}

+ 20 - 0
toolchain/lowering/testdata/return/var.carbon

@@ -0,0 +1,20 @@
+// 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
+//
+// AUTOUPDATE
+// CHECK:STDOUT: ; ModuleID = 'var.carbon'
+// CHECK:STDOUT: source_filename = "var.carbon"
+// CHECK:STDOUT:
+// CHECK:STDOUT: define i32 @Main() {
+// CHECK:STDOUT: entry:
+// CHECK:STDOUT:   %var = alloca i32, align 4
+// CHECK:STDOUT:   store i32 0, ptr %var, align 4
+// CHECK:STDOUT:   %0 = load i32, ptr %var, align 4
+// CHECK:STDOUT:   ret i32 %0
+// CHECK:STDOUT: }
+
+fn Main() -> i32 {
+  var x: i32 = 0;
+  return x;
+}

+ 4 - 2
toolchain/lowering/testdata/struct/empty.carbon

@@ -13,10 +13,12 @@
 // CHECK:STDOUT:   %StructLiteralValue = alloca %StructLiteralType, align 8
 // CHECK:STDOUT:   %StructLiteralValue = alloca %StructLiteralType, align 8
 // CHECK:STDOUT:   %var = alloca %StructLiteralType, align 8
 // CHECK:STDOUT:   %var = alloca %StructLiteralType, align 8
 // CHECK:STDOUT:   %StructLiteralValue1 = alloca %StructLiteralType, align 8
 // CHECK:STDOUT:   %StructLiteralValue1 = alloca %StructLiteralType, align 8
-// CHECK:STDOUT:   store ptr %StructLiteralValue1, ptr %var, align 8
+// CHECK:STDOUT:   %0 = load %StructLiteralType, ptr %StructLiteralValue1, align 1
+// CHECK:STDOUT:   store %StructLiteralType %0, ptr %var, align 1
 // CHECK:STDOUT:   %StructLiteralValue2 = alloca %StructLiteralType, align 8
 // CHECK:STDOUT:   %StructLiteralValue2 = alloca %StructLiteralType, align 8
 // CHECK:STDOUT:   %var3 = alloca %StructLiteralType, align 8
 // CHECK:STDOUT:   %var3 = alloca %StructLiteralType, align 8
-// CHECK:STDOUT:   store ptr %var, ptr %var3, align 8
+// CHECK:STDOUT:   %1 = load %StructLiteralType, ptr %var, align 1
+// CHECK:STDOUT:   store %StructLiteralType %1, ptr %var3, align 1
 // CHECK:STDOUT:   ret i32 0
 // CHECK:STDOUT:   ret i32 0
 // CHECK:STDOUT: }
 // CHECK:STDOUT: }
 
 

+ 6 - 3
toolchain/lowering/testdata/struct/member_access.carbon

@@ -16,12 +16,15 @@
 // CHECK:STDOUT:   store double 0.000000e+00, ptr %a, align 8
 // CHECK:STDOUT:   store double 0.000000e+00, ptr %a, align 8
 // CHECK:STDOUT:   %b = getelementptr inbounds %StructLiteralType, ptr %StructLiteralValue, i32 0, i32 1
 // CHECK:STDOUT:   %b = getelementptr inbounds %StructLiteralType, ptr %StructLiteralValue, i32 0, i32 1
 // CHECK:STDOUT:   store i32 1, ptr %b, align 4
 // CHECK:STDOUT:   store i32 1, ptr %b, align 4
-// CHECK:STDOUT:   store ptr %StructLiteralValue, ptr %var, align 8
+// CHECK:STDOUT:   %0 = load %StructLiteralType, ptr %StructLiteralValue, align 8
+// CHECK:STDOUT:   store %StructLiteralType %0, ptr %var, align 8
 // CHECK:STDOUT:   %var1 = alloca i32, align 4
 // CHECK:STDOUT:   %var1 = alloca i32, align 4
 // CHECK:STDOUT:   %b2 = getelementptr inbounds %StructLiteralType, ptr %var, i32 0, i32 1
 // CHECK:STDOUT:   %b2 = getelementptr inbounds %StructLiteralType, ptr %var, i32 0, i32 1
-// CHECK:STDOUT:   store ptr %b2, ptr %var1, align 8
+// CHECK:STDOUT:   %1 = load i32, ptr %b2, align 4
+// CHECK:STDOUT:   store i32 %1, ptr %var1, align 4
 // CHECK:STDOUT:   %var3 = alloca i32, align 4
 // CHECK:STDOUT:   %var3 = alloca i32, align 4
-// CHECK:STDOUT:   store ptr %var1, ptr %var3, align 8
+// CHECK:STDOUT:   %2 = load i32, ptr %var1, align 4
+// CHECK:STDOUT:   store i32 %2, ptr %var3, align 4
 // CHECK:STDOUT:   ret i32 0
 // CHECK:STDOUT:   ret i32 0
 // CHECK:STDOUT: }
 // CHECK:STDOUT: }
 
 

+ 4 - 2
toolchain/lowering/testdata/struct/one_entry.carbon

@@ -14,9 +14,11 @@
 // CHECK:STDOUT:   %StructLiteralValue = alloca %StructLiteralType, align 8
 // CHECK:STDOUT:   %StructLiteralValue = alloca %StructLiteralType, align 8
 // CHECK:STDOUT:   %a = getelementptr inbounds %StructLiteralType, ptr %StructLiteralValue, i32 0, i32 0
 // CHECK:STDOUT:   %a = getelementptr inbounds %StructLiteralType, ptr %StructLiteralValue, i32 0, i32 0
 // CHECK:STDOUT:   store i32 4, ptr %a, align 4
 // CHECK:STDOUT:   store i32 4, ptr %a, align 4
-// CHECK:STDOUT:   store ptr %StructLiteralValue, ptr %var, align 8
+// CHECK:STDOUT:   %0 = load %StructLiteralType, ptr %StructLiteralValue, align 4
+// CHECK:STDOUT:   store %StructLiteralType %0, ptr %var, align 4
 // CHECK:STDOUT:   %var1 = alloca %StructLiteralType, align 8
 // CHECK:STDOUT:   %var1 = alloca %StructLiteralType, align 8
-// CHECK:STDOUT:   store ptr %var, ptr %var1, align 8
+// CHECK:STDOUT:   %1 = load %StructLiteralType, ptr %var, align 4
+// CHECK:STDOUT:   store %StructLiteralType %1, ptr %var1, align 4
 // CHECK:STDOUT:   ret i32 0
 // CHECK:STDOUT:   ret i32 0
 // CHECK:STDOUT: }
 // CHECK:STDOUT: }
 
 

+ 4 - 2
toolchain/lowering/testdata/struct/two_entries.carbon

@@ -16,9 +16,11 @@
 // CHECK:STDOUT:   store i32 1, ptr %a, align 4
 // CHECK:STDOUT:   store i32 1, ptr %a, align 4
 // CHECK:STDOUT:   %b = getelementptr inbounds %StructLiteralType, ptr %StructLiteralValue, i32 0, i32 1
 // CHECK:STDOUT:   %b = getelementptr inbounds %StructLiteralType, ptr %StructLiteralValue, i32 0, i32 1
 // CHECK:STDOUT:   store i32 2, ptr %b, align 4
 // CHECK:STDOUT:   store i32 2, ptr %b, align 4
-// CHECK:STDOUT:   store ptr %StructLiteralValue, ptr %var, align 8
+// CHECK:STDOUT:   %0 = load %StructLiteralType, ptr %StructLiteralValue, align 4
+// CHECK:STDOUT:   store %StructLiteralType %0, ptr %var, align 4
 // CHECK:STDOUT:   %var1 = alloca %StructLiteralType, align 8
 // CHECK:STDOUT:   %var1 = alloca %StructLiteralType, align 8
-// CHECK:STDOUT:   store ptr %var, ptr %var1, align 8
+// CHECK:STDOUT:   %1 = load %StructLiteralType, ptr %var, align 4
+// CHECK:STDOUT:   store %StructLiteralType %1, ptr %var1, align 4
 // CHECK:STDOUT:   ret i32 0
 // CHECK:STDOUT:   ret i32 0
 // CHECK:STDOUT: }
 // CHECK:STDOUT: }
 
 

+ 2 - 1
toolchain/lowering/testdata/var/local.carbon

@@ -10,7 +10,8 @@
 // CHECK:STDOUT: entry:
 // CHECK:STDOUT: entry:
 // CHECK:STDOUT:   %var = alloca i32, align 4
 // CHECK:STDOUT:   %var = alloca i32, align 4
 // CHECK:STDOUT:   store i32 1, ptr %var, align 4
 // CHECK:STDOUT:   store i32 1, ptr %var, align 4
-// CHECK:STDOUT:   ret ptr %var
+// CHECK:STDOUT:   %0 = load i32, ptr %var, align 4
+// CHECK:STDOUT:   ret i32 %0
 // CHECK:STDOUT: }
 // CHECK:STDOUT: }
 
 
 fn Run() -> i32 {
 fn Run() -> i32 {