瀏覽代碼

Add names for LLVM IR entries. (#2832)

This adds names for more LLVM IR entries. For now, `var` is just a placeholder due to the difficulty of associating a name, but the rest reasonably reflect intent.

I'm trying to comment logic for this because I suspect we'll want to make it more conditional later. Even though chandlerc noted the expectation that IRBuilder would have a way to disable them in output, that's fine for things like anonymous names; other places they'll still take extra work to calculate. e.g., as with struct fields where the type's fields are only fetched to print a name, not otherwise needed for the gep.
Jon Ross-Perkins 3 年之前
父節點
當前提交
75f1ac3a08

+ 5 - 3
toolchain/lowering/lowering_context.cpp

@@ -65,8 +65,9 @@ auto LoweringContext::BuildLoweredNodeAsType(SemanticsNodeId node_id)
       // returns. LLVM doesn't allow declaring variables with a void type, so
       // that may require significant special casing.
       // TODO: Work to remove EmptyTuple here.
-      return llvm::StructType::create(*llvm_context_,
-                                      llvm::ArrayRef<llvm::Type*>());
+      return llvm::StructType::create(
+          *llvm_context_, llvm::ArrayRef<llvm::Type*>(),
+          SemanticsBuiltinKind::FromInt(node_id.index).name());
     case SemanticsBuiltinKind::FloatingPointType.AsInt():
       // TODO: Handle different sizes.
       return builder_.getDoubleTy();
@@ -89,7 +90,8 @@ auto LoweringContext::BuildLoweredNodeAsType(SemanticsNodeId node_id)
             << type_id;
         subtypes.push_back(GetLoweredNodeAsType(type_id));
       }
-      return llvm::StructType::create(*llvm_context_, subtypes);
+      return llvm::StructType::create(*llvm_context_, subtypes,
+                                      "StructLiteralType");
     }
     default: {
       CARBON_FATAL() << "Cannot use node as type: " << node_id;

+ 28 - 11
toolchain/lowering/lowering_handle.cpp

@@ -158,11 +158,20 @@ auto LoweringHandleStructMemberAccess(LoweringContext& context,
                                       SemanticsNodeId node_id,
                                       SemanticsNode node) -> void {
   auto [struct_id, member_index] = node.GetAsStructMemberAccess();
-  auto* struct_type = context.GetLoweredNodeAsType(
-      context.semantics_ir().GetNode(struct_id).type_id());
+  auto struct_type_id = context.semantics_ir().GetNode(struct_id).type_id();
+  auto* llvm_type = context.GetLoweredNodeAsType(struct_type_id);
+
+  // Get type information for member names.
+  auto type_refs = context.semantics_ir().GetNodeBlock(
+      context.semantics_ir().GetNode(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(
-      struct_type, context.GetLoweredNodeAsValue(struct_id),
-      member_index.index);
+      llvm_type, context.GetLoweredNodeAsValue(struct_id), member_index.index,
+      member_name);
   context.SetLoweredNodeAsValue(node_id, gep);
 }
 
@@ -181,13 +190,20 @@ auto LoweringHandleStructTypeField(LoweringContext& /*context*/,
 auto LoweringHandleStructValue(LoweringContext& context,
                                SemanticsNodeId node_id, SemanticsNode node)
     -> void {
-  auto* type = context.GetLoweredNodeAsType(node.type_id());
-  auto* alloca = context.builder().CreateAlloca(type);
+  auto* llvm_type = context.GetLoweredNodeAsType(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(node.type_id()).GetAsStructType());
   for (int i = 0; i < static_cast<int>(refs.size()); ++i) {
-    auto* gep = context.builder().CreateStructGEP(type, alloca, 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);
   }
 }
@@ -201,14 +217,15 @@ auto LoweringHandleStubReference(LoweringContext& context,
 
 auto LoweringHandleVarStorage(LoweringContext& context, SemanticsNodeId node_id,
                               SemanticsNode node) -> void {
-  // TODO: This doesn't handle globals. 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
+  // 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.GetLoweredNodeAsType(node.type_id()));
+      context.GetLoweredNodeAsType(node.type_id()), /*ArraySize=*/nullptr,
+      "var");
   context.SetLoweredNodeAsValue(node_id, alloca);
 }
 

+ 2 - 2
toolchain/lowering/testdata/function/definition/params_one.carbon

@@ -6,9 +6,9 @@
 // CHECK:STDOUT: ; ModuleID = 'params_one.carbon'
 // CHECK:STDOUT: source_filename = "params_one.carbon"
 // CHECK:STDOUT:
-// CHECK:STDOUT: %0 = type {}
+// CHECK:STDOUT: %EmptyTuple = type {}
 // CHECK:STDOUT:
-// CHECK:STDOUT: define %0 @Foo(i32 %a) {
+// CHECK:STDOUT: define %EmptyTuple @Foo(i32 %a) {
 // CHECK:STDOUT: entry:
 // CHECK:STDOUT: }
 

+ 2 - 2
toolchain/lowering/testdata/function/definition/params_two.carbon

@@ -6,9 +6,9 @@
 // CHECK:STDOUT: ; ModuleID = 'params_two.carbon'
 // CHECK:STDOUT: source_filename = "params_two.carbon"
 // CHECK:STDOUT:
-// CHECK:STDOUT: %0 = type {}
+// CHECK:STDOUT: %EmptyTuple = type {}
 // CHECK:STDOUT:
-// CHECK:STDOUT: define %0 @Foo(i32 %a, i32 %b) {
+// CHECK:STDOUT: define %EmptyTuple @Foo(i32 %a, i32 %b) {
 // CHECK:STDOUT: entry:
 // CHECK:STDOUT: }
 

+ 2 - 2
toolchain/lowering/testdata/function/definition/params_zero.carbon

@@ -6,9 +6,9 @@
 // CHECK:STDOUT: ; ModuleID = 'params_zero.carbon'
 // CHECK:STDOUT: source_filename = "params_zero.carbon"
 // CHECK:STDOUT:
-// CHECK:STDOUT: %0 = type {}
+// CHECK:STDOUT: %EmptyTuple = type {}
 // CHECK:STDOUT:
-// CHECK:STDOUT: define %0 @Foo() {
+// CHECK:STDOUT: define %EmptyTuple @Foo() {
 // CHECK:STDOUT: entry:
 // CHECK:STDOUT: }
 

+ 2 - 2
toolchain/lowering/testdata/return/no_value.carbon

@@ -6,9 +6,9 @@
 // CHECK:STDOUT: ; ModuleID = 'no_value.carbon'
 // CHECK:STDOUT: source_filename = "no_value.carbon"
 // CHECK:STDOUT:
-// CHECK:STDOUT: %0 = type {}
+// CHECK:STDOUT: %EmptyTuple = type {}
 // CHECK:STDOUT:
-// CHECK:STDOUT: define %0 @Main() {
+// CHECK:STDOUT: define %EmptyTuple @Main() {
 // CHECK:STDOUT: entry:
 // CHECK:STDOUT:   ret void
 // CHECK:STDOUT: }

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

@@ -6,13 +6,13 @@
 // CHECK:STDOUT: ; ModuleID = 'empty.carbon'
 // CHECK:STDOUT: source_filename = "empty.carbon"
 // CHECK:STDOUT:
-// CHECK:STDOUT: %0 = type {}
+// CHECK:STDOUT: %EmptyStructType = type {}
 // CHECK:STDOUT:
 // CHECK:STDOUT: define i32 @Run() {
 // CHECK:STDOUT: entry:
-// CHECK:STDOUT:   %0 = alloca %0, align 8
-// CHECK:STDOUT:   %1 = alloca %0, align 8
-// CHECK:STDOUT:   store ptr %0, ptr %1, align 8
+// CHECK:STDOUT:   %var = alloca %EmptyStructType, align 8
+// CHECK:STDOUT:   %var1 = alloca %EmptyStructType, align 8
+// CHECK:STDOUT:   store ptr %var, ptr %var1, align 8
 // CHECK:STDOUT:   ret i32 0
 // CHECK:STDOUT: }
 

+ 14 - 14
toolchain/lowering/testdata/struct/member_access.carbon

@@ -6,23 +6,23 @@
 // CHECK:STDOUT: ; ModuleID = 'member_access.carbon'
 // CHECK:STDOUT: source_filename = "member_access.carbon"
 // CHECK:STDOUT:
-// CHECK:STDOUT: %0 = type { double, i32 }
-// CHECK:STDOUT: %1 = type { double, i32 }
+// CHECK:STDOUT: %StructLiteralType = type { double, i32 }
+// CHECK:STDOUT: %StructLiteralType.0 = type { double, i32 }
 // CHECK:STDOUT:
 // CHECK:STDOUT: define i32 @Run() {
 // CHECK:STDOUT: entry:
-// CHECK:STDOUT:   %0 = alloca %0, align 8
-// CHECK:STDOUT:   %1 = alloca %1, align 8
-// CHECK:STDOUT:   %2 = getelementptr inbounds %1, ptr %1, i32 0, i32 0
-// CHECK:STDOUT:   store double 0.000000e+00, ptr %2, align 8
-// CHECK:STDOUT:   %3 = getelementptr inbounds %1, ptr %1, i32 0, i32 1
-// CHECK:STDOUT:   store i32 1, ptr %3, align 4
-// CHECK:STDOUT:   store ptr %1, ptr %0, align 8
-// CHECK:STDOUT:   %4 = alloca i32, align 4
-// CHECK:STDOUT:   %5 = getelementptr inbounds %0, ptr %0, i32 0, i32 1
-// CHECK:STDOUT:   store ptr %5, ptr %4, align 8
-// CHECK:STDOUT:   %6 = alloca i32, align 4
-// CHECK:STDOUT:   store ptr %4, ptr %6, align 8
+// CHECK:STDOUT:   %var = alloca %StructLiteralType, align 8
+// CHECK:STDOUT:   %StructLiteralValue = alloca %StructLiteralType.0, align 8
+// CHECK:STDOUT:   %a = getelementptr inbounds %StructLiteralType.0, ptr %StructLiteralValue, i32 0, i32 0
+// CHECK:STDOUT:   store double 0.000000e+00, ptr %a, align 8
+// CHECK:STDOUT:   %b = getelementptr inbounds %StructLiteralType.0, ptr %StructLiteralValue, i32 0, i32 1
+// CHECK:STDOUT:   store i32 1, ptr %b, align 4
+// CHECK:STDOUT:   store ptr %StructLiteralValue, ptr %var, align 8
+// CHECK:STDOUT:   %var1 = alloca i32, align 4
+// CHECK:STDOUT:   %b2 = getelementptr inbounds %StructLiteralType, ptr %var, i32 0, i32 1
+// CHECK:STDOUT:   store ptr %b2, ptr %var1, align 8
+// CHECK:STDOUT:   %var3 = alloca i32, align 4
+// CHECK:STDOUT:   store ptr %var1, ptr %var3, align 8
 // CHECK:STDOUT:   ret i32 0
 // CHECK:STDOUT: }
 

+ 10 - 10
toolchain/lowering/testdata/struct/one_entry.carbon

@@ -6,19 +6,19 @@
 // CHECK:STDOUT: ; ModuleID = 'one_entry.carbon'
 // CHECK:STDOUT: source_filename = "one_entry.carbon"
 // CHECK:STDOUT:
-// CHECK:STDOUT: %0 = type { i32 }
-// CHECK:STDOUT: %1 = type { i32 }
-// CHECK:STDOUT: %2 = type { i32 }
+// CHECK:STDOUT: %StructLiteralType = type { i32 }
+// CHECK:STDOUT: %StructLiteralType.0 = type { i32 }
+// CHECK:STDOUT: %StructLiteralType.1 = type { i32 }
 // CHECK:STDOUT:
 // CHECK:STDOUT: define i32 @Run() {
 // CHECK:STDOUT: entry:
-// CHECK:STDOUT:   %0 = alloca %0, align 8
-// CHECK:STDOUT:   %1 = alloca %1, align 8
-// CHECK:STDOUT:   %2 = getelementptr inbounds %1, ptr %1, i32 0, i32 0
-// CHECK:STDOUT:   store i32 4, ptr %2, align 4
-// CHECK:STDOUT:   store ptr %1, ptr %0, align 8
-// CHECK:STDOUT:   %3 = alloca %2, align 8
-// CHECK:STDOUT:   store ptr %0, ptr %3, align 8
+// CHECK:STDOUT:   %var = alloca %StructLiteralType, align 8
+// CHECK:STDOUT:   %StructLiteralValue = alloca %StructLiteralType.0, align 8
+// CHECK:STDOUT:   %a = getelementptr inbounds %StructLiteralType.0, ptr %StructLiteralValue, i32 0, i32 0
+// CHECK:STDOUT:   store i32 4, ptr %a, align 4
+// CHECK:STDOUT:   store ptr %StructLiteralValue, ptr %var, align 8
+// CHECK:STDOUT:   %var1 = alloca %StructLiteralType.1, align 8
+// CHECK:STDOUT:   store ptr %var, ptr %var1, align 8
 // CHECK:STDOUT:   ret i32 0
 // CHECK:STDOUT: }
 

+ 12 - 12
toolchain/lowering/testdata/struct/two_entries.carbon

@@ -6,21 +6,21 @@
 // CHECK:STDOUT: ; ModuleID = 'two_entries.carbon'
 // CHECK:STDOUT: source_filename = "two_entries.carbon"
 // CHECK:STDOUT:
-// CHECK:STDOUT: %0 = type { i32, i32 }
-// CHECK:STDOUT: %1 = type { i32, i32 }
-// CHECK:STDOUT: %2 = type { i32, i32 }
+// CHECK:STDOUT: %StructLiteralType = type { i32, i32 }
+// CHECK:STDOUT: %StructLiteralType.0 = type { i32, i32 }
+// CHECK:STDOUT: %StructLiteralType.1 = type { i32, i32 }
 // CHECK:STDOUT:
 // CHECK:STDOUT: define i32 @Run() {
 // CHECK:STDOUT: entry:
-// CHECK:STDOUT:   %0 = alloca %0, align 8
-// CHECK:STDOUT:   %1 = alloca %1, align 8
-// CHECK:STDOUT:   %2 = getelementptr inbounds %1, ptr %1, i32 0, i32 0
-// CHECK:STDOUT:   store i32 1, ptr %2, align 4
-// CHECK:STDOUT:   %3 = getelementptr inbounds %1, ptr %1, i32 0, i32 1
-// CHECK:STDOUT:   store i32 2, ptr %3, align 4
-// CHECK:STDOUT:   store ptr %1, ptr %0, align 8
-// CHECK:STDOUT:   %4 = alloca %2, align 8
-// CHECK:STDOUT:   store ptr %0, ptr %4, align 8
+// CHECK:STDOUT:   %var = alloca %StructLiteralType, align 8
+// CHECK:STDOUT:   %StructLiteralValue = alloca %StructLiteralType.0, align 8
+// CHECK:STDOUT:   %a = getelementptr inbounds %StructLiteralType.0, ptr %StructLiteralValue, i32 0, i32 0
+// CHECK:STDOUT:   store i32 1, ptr %a, align 4
+// CHECK:STDOUT:   %b = getelementptr inbounds %StructLiteralType.0, ptr %StructLiteralValue, i32 0, i32 1
+// CHECK:STDOUT:   store i32 2, ptr %b, align 4
+// CHECK:STDOUT:   store ptr %StructLiteralValue, ptr %var, align 8
+// CHECK:STDOUT:   %var1 = alloca %StructLiteralType.1, align 8
+// CHECK:STDOUT:   store ptr %var, ptr %var1, align 8
 // CHECK:STDOUT:   ret i32 0
 // CHECK:STDOUT: }
 

+ 3 - 3
toolchain/lowering/testdata/var/local.carbon

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