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

Store SemanticsNode in a single list instead of per-block (#2475)

This switches to single list storage of SemanticsNode. The driving motivation behind this is to simplify cross-references within a given IR. Types of nodes will frequently refer to other blocks. This causes a significant increase in the number of cross-references, which can become difficult to manage (and reason about). By reducing to a single list of nodes, cross-references are only needed when crossing IR boundaries.

Because cross-references now only have 2 things to track (IR and index), they can be a regular SemanticsNode and don't need further indirection. This wasn't motivating, but feels like it reinforces the simplification.

Note this isn't being used to deduplicate nodes, at least right now. That could lead to difficult-to-update situations, but also most nodes are associated with the underlying ParseTree::Node in order to track sources for diagnostics; as a consequence, nodes representing equal text in different source locations wouldn't be the same node. There may be future opportunities here, discussed with @zygoloid, but no action is taken at present.

We may eventually want to switch the storage of NodeBlocks to have `[start, end)` ranges instead of individual numbers, but I'm leaving that alone for now.

As an aside, I noticed I was accidentally overloading the copy constructor on SemanticsIR. I've added some disambiguation on that, but am not deleting the copy constructor per style advice (even though the type should never be copied due to storage size).

codespell tries to change `CrossReference -> cross-reference` so disabling it there.
Jon Ross-Perkins 3 лет назад
Родитель
Сommit
e5d49f5989
31 измененных файлов с 495 добавлено и 482 удалено
  1. 1 0
      .codespell_ignore
  2. 3 0
      toolchain/parser/parse_tree.h
  3. 25 26
      toolchain/semantics/semantics_ir.cpp
  4. 17 87
      toolchain/semantics/semantics_ir.h
  5. 22 24
      toolchain/semantics/semantics_node.h
  6. 3 0
      toolchain/semantics/semantics_node_kind.def
  7. 5 15
      toolchain/semantics/semantics_parse_tree_handler.cpp
  8. 0 3
      toolchain/semantics/semantics_parse_tree_handler.h
  9. 7 7
      toolchain/semantics/testdata/basics/empty.carbon
  10. 7 7
      toolchain/semantics/testdata/basics/empty_decl.carbon
  11. 13 11
      toolchain/semantics/testdata/basics/fail_name_lookup.carbon
  12. 1 1
      toolchain/semantics/testdata/basics/verbose.carbon
  13. 13 11
      toolchain/semantics/testdata/function/basic.carbon
  14. 25 19
      toolchain/semantics/testdata/function/order.carbon
  15. 21 15
      toolchain/semantics/testdata/operators/binary_op.carbon
  16. 22 16
      toolchain/semantics/testdata/operators/fail_type_mismatch.carbon
  17. 26 18
      toolchain/semantics/testdata/operators/fail_type_mismatch_once.carbon
  18. 17 13
      toolchain/semantics/testdata/return/literal.carbon
  19. 15 12
      toolchain/semantics/testdata/return/trivial.carbon
  20. 17 14
      toolchain/semantics/testdata/var/decl.carbon
  21. 21 16
      toolchain/semantics/testdata/var/decl_with_init.carbon
  22. 29 20
      toolchain/semantics/testdata/var/fail_duplicate_decl.carbon
  23. 22 17
      toolchain/semantics/testdata/var/fail_init_type_mismatch.carbon
  24. 49 0
      toolchain/semantics/testdata/var/fail_lookup_outside_scope.carbon
  25. 11 10
      toolchain/semantics/testdata/var/global_decl.carbon
  26. 15 12
      toolchain/semantics/testdata/var/global_decl_with_init.carbon
  27. 21 16
      toolchain/semantics/testdata/var/global_lookup.carbon
  28. 27 20
      toolchain/semantics/testdata/var/global_lookup_in_scope.carbon
  29. 21 16
      toolchain/semantics/testdata/var/lookup.carbon
  30. 19 15
      toolchain/semantics/testdata/var/todo_bad_init_with_self.carbon
  31. 0 41
      toolchain/semantics/testdata/var/todo_bad_lookup_outside_scope.carbon

+ 1 - 0
.codespell_ignore

@@ -6,6 +6,7 @@ atleast
 circularly
 copyable
 crate
+crossreference
 falsy
 inout
 pullrequest

+ 3 - 0
toolchain/parser/parse_tree.h

@@ -242,6 +242,9 @@ class ParseTree {
 // That said, nodes can be compared and are part of a depth-first pre-order
 // sequence across all nodes in the parse tree.
 struct ParseTree::Node : public ComparableIndexBase {
+  // Constructs an explicitly invalid instance.
+  static auto MakeInvalid() -> Node { return Node(); }
+
   using ComparableIndexBase::ComparableIndexBase;
 };
 

+ 25 - 26
toolchain/semantics/semantics_ir.cpp

@@ -14,18 +14,14 @@
 namespace Carbon {
 
 auto SemanticsIR::MakeBuiltinIR() -> SemanticsIR {
-  SemanticsIR semantics;
-  static constexpr auto BuiltinIR = SemanticsCrossReferenceIRId(0);
+  SemanticsIR semantics(/*builtin_ir=*/nullptr);
   auto block_id = semantics.AddNodeBlock();
-  semantics.cross_references_.resize_for_overwrite(
-      SemanticsBuiltinKind::ValidCount);
+  semantics.nodes_.reserve(SemanticsBuiltinKind::ValidCount);
 
   constexpr int32_t TypeOfTypeType = 0;
   auto type_type = semantics.AddNode(
       block_id, SemanticsNode::MakeBuiltin(SemanticsBuiltinKind::TypeType(),
                                            SemanticsNodeId(TypeOfTypeType)));
-  semantics.cross_references_[SemanticsBuiltinKind::TypeType().AsInt()] =
-      SemanticsCrossReference(BuiltinIR, block_id, type_type);
   CARBON_CHECK(type_type.index == TypeOfTypeType)
       << "TypeType's type must be self-referential.";
 
@@ -33,22 +29,15 @@ auto SemanticsIR::MakeBuiltinIR() -> SemanticsIR {
   auto invalid_type = semantics.AddNode(
       block_id, SemanticsNode::MakeBuiltin(SemanticsBuiltinKind::InvalidType(),
                                            SemanticsNodeId(TypeOfInvalidType)));
-  semantics.cross_references_[SemanticsBuiltinKind::InvalidType().AsInt()] =
-      SemanticsCrossReference(BuiltinIR, block_id, invalid_type);
   CARBON_CHECK(invalid_type.index == TypeOfInvalidType)
       << "InvalidType's type must be self-referential.";
 
-  auto integer_literal_type = semantics.AddNode(
+  semantics.AddNode(
       block_id, SemanticsNode::MakeBuiltin(SemanticsBuiltinKind::IntegerType(),
                                            type_type));
-  semantics.cross_references_[SemanticsBuiltinKind::IntegerType().AsInt()] =
-      SemanticsCrossReference(BuiltinIR, block_id, integer_literal_type);
 
-  auto real_literal_type = semantics.AddNode(
-      block_id,
-      SemanticsNode::MakeBuiltin(SemanticsBuiltinKind::RealType(), type_type));
-  semantics.cross_references_[SemanticsBuiltinKind::RealType().AsInt()] =
-      SemanticsCrossReference(BuiltinIR, block_id, real_literal_type);
+  semantics.AddNode(block_id, SemanticsNode::MakeBuiltin(
+                                  SemanticsBuiltinKind::RealType(), type_type));
 
   CARBON_CHECK(semantics.node_blocks_.size() == 1)
       << "BuildBuiltins should only produce 1 block, actual: "
@@ -62,7 +51,18 @@ auto SemanticsIR::MakeFromParseTree(const SemanticsIR& builtin_ir,
                                     DiagnosticConsumer& consumer,
                                     llvm::raw_ostream* vlog_stream)
     -> SemanticsIR {
-  SemanticsIR semantics(builtin_ir);
+  SemanticsIR semantics(&builtin_ir);
+
+  // Copy builtins over.
+  semantics.nodes_.resize_for_overwrite(SemanticsBuiltinKind::ValidCount);
+  static constexpr auto BuiltinIR = SemanticsCrossReferenceIRId(0);
+  for (int i = 0; i < SemanticsBuiltinKind::ValidCount; ++i) {
+    // We can reuse the type node ID because the offsets of cross-references
+    // will be the same in this IR.
+    auto type = builtin_ir.nodes_[i].type();
+    semantics.nodes_[i] =
+        SemanticsNode::MakeCrossReference(type, BuiltinIR, SemanticsNodeId(i));
+  }
 
   TokenizedBuffer::TokenLocationTranslator translator(
       &tokens, /*last_line_lexed_to_column=*/nullptr);
@@ -79,14 +79,6 @@ auto SemanticsIR::Print(llvm::raw_ostream& out) const -> void {
 
   out << "cross_reference_irs.size == " << cross_reference_irs_.size() << ",\n";
 
-  out << "cross_references = {\n";
-  for (int32_t i = 0; i < static_cast<int32_t>(cross_references_.size()); ++i) {
-    out.indent(Indent);
-    out << SemanticsNodeId::MakeCrossReference(i) << " = "
-        << cross_references_[i] << ";\n";
-  }
-  out << "},\n";
-
   out << "integer_literals = {\n";
   for (int32_t i = 0; i < static_cast<int32_t>(integer_literals_.size()); ++i) {
     out.indent(Indent);
@@ -102,6 +94,13 @@ auto SemanticsIR::Print(llvm::raw_ostream& out) const -> void {
   }
   out << "},\n";
 
+  out << "nodes = {\n";
+  for (int32_t i = 0; i < static_cast<int32_t>(nodes_.size()); ++i) {
+    out.indent(Indent);
+    out << SemanticsNodeId(i) << " = " << nodes_[i] << ";\n";
+  }
+  out << "},\n";
+
   out << "node_blocks = {\n";
   for (int32_t i = 0; i < static_cast<int32_t>(node_blocks_.size()); ++i) {
     out.indent(Indent);
@@ -110,7 +109,7 @@ auto SemanticsIR::Print(llvm::raw_ostream& out) const -> void {
     const auto& node_block = node_blocks_[i];
     for (int32_t i = 0; i < static_cast<int32_t>(node_block.size()); ++i) {
       out.indent(2 * Indent);
-      out << SemanticsNodeId(i) << " = " << node_block[i] << ";\n";
+      out << node_block[i] << ";\n";
     }
 
     out.indent(Indent);

+ 17 - 87
toolchain/semantics/semantics_ir.h

@@ -16,36 +16,9 @@ class SemanticsIRForTest;
 
 namespace Carbon {
 
-// The ID of a cross-referenced IR (within cross_reference_irs_).
-struct SemanticsCrossReferenceIRId : public IndexBase {
-  using IndexBase::IndexBase;
-  auto Print(llvm::raw_ostream& out) const -> void { out << "ir" << index; }
-};
-
-// A cross-reference between node blocks or IRs; essentially, anything that's
-// not in the same SemanticsNodeBlock as the referencing node.
-struct SemanticsCrossReference {
-  SemanticsCrossReference() = default;
-  SemanticsCrossReference(SemanticsCrossReferenceIRId ir,
-                          SemanticsNodeBlockId node_block, SemanticsNodeId node)
-      : ir(ir), node_block(node_block), node(node) {}
-
-  auto Print(llvm::raw_ostream& out) const -> void {
-    out << "xref(" << ir << ", " << node_block << ", " << node << ")";
-  }
-
-  SemanticsCrossReferenceIRId ir;
-  SemanticsNodeBlockId node_block;
-  SemanticsNodeId node;
-};
-
 // Provides semantic analysis on a ParseTree.
 class SemanticsIR {
  public:
-  // As noted under cross_reference_irs_, the current IR must always be at
-  // index 1. This is a constant for that.
-  static constexpr auto ThisIR = SemanticsCrossReferenceIRId(1);
-
   // Produces the builtins.
   static auto MakeBuiltinIR() -> SemanticsIR;
 
@@ -65,57 +38,17 @@ class SemanticsIR {
  private:
   friend class SemanticsParseTreeHandler;
 
-  // For the builtin IR only.
-  SemanticsIR() : SemanticsIR(*this) {}
-  // For most IRs.
-  SemanticsIR(const SemanticsIR& builtins)
-      : cross_reference_irs_({&builtins, this}),
-        cross_references_(builtins.cross_references_) {}
-
-  // Returns the requested node, resolving cross references.
-  auto GetNode(SemanticsNodeBlockId block_id, SemanticsNodeId node_id)
-      -> SemanticsNode {
-    if (node_id.is_cross_reference()) {
-      auto ref = cross_references_[node_id.GetAsCrossReference()];
-      return cross_reference_irs_[ref.ir.index]
-          ->node_blocks_[ref.node_block.index][ref.node.index];
-    } else {
-      return node_blocks_[block_id.index][node_id.index];
-    }
-  }
+  explicit SemanticsIR(const SemanticsIR* builtin_ir)
+      : cross_reference_irs_({builtin_ir == nullptr ? this : builtin_ir}) {}
 
-  // Returns the type of the requested node, resolving cross references.
-  auto GetType(SemanticsNodeBlockId block_id, SemanticsNodeId node_id)
-      -> SemanticsNodeId {
-    if (node_id.is_cross_reference()) {
-      auto ref = cross_references_[node_id.GetAsCrossReference()];
-      auto type = cross_reference_irs_[ref.ir.index]
-                      ->node_blocks_[ref.node_block.index][ref.node.index]
-                      .type();
-      if (type.is_cross_reference() ||
-          (ref.ir == ThisIR && ref.node_block == block_id)) {
-        return type;
-      } else {
-        // TODO: If the type is a local reference within a block other than the
-        // present one, we don't really want to add a cross reference at this
-        // point. Does this mean types should be required to be cross
-        // references? And maybe always with a presence in the current IR's
-        // cross-references, so that equality is straightforward even though
-        // resolving the actual type is a two-step process?
-        CARBON_FATAL() << "Need to think more about this case";
-      }
-    } else {
-      return node_blocks_[block_id.index][node_id.index].type();
-    }
+  // Returns the requested node.
+  auto GetNode(SemanticsNodeId node_id) const -> const SemanticsNode& {
+    return nodes_[node_id.index];
   }
 
-  // Adds a cross reference, returning an ID to reference it.
-  auto AddCrossReference(SemanticsCrossReference cross_reference)
-      -> SemanticsNodeId {
-    SemanticsNodeId id =
-        SemanticsNodeId::MakeCrossReference(cross_references_.size());
-    cross_references_.push_back(cross_reference);
-    return id;
+  // Returns the type of the requested node.
+  auto GetType(SemanticsNodeId node_id) -> SemanticsNodeId {
+    return GetNode(node_id).type();
   }
 
   // Adds an integer literal, returning an ID to reference it.
@@ -137,9 +70,9 @@ class SemanticsIR {
   // Adds a node to a specified block, returning an ID to reference the node.
   auto AddNode(SemanticsNodeBlockId block_id, SemanticsNode node)
       -> SemanticsNodeId {
-    auto& block = node_blocks_[block_id.index];
-    SemanticsNodeId node_id(block.size());
-    block.push_back(node);
+    SemanticsNodeId node_id(nodes_.size());
+    nodes_.push_back(node);
+    node_blocks_[block_id.index].push_back(node_id);
     return node_id;
   }
 
@@ -173,13 +106,6 @@ class SemanticsIR {
   // crossing node blocks).
   llvm::SmallVector<const SemanticsIR*> cross_reference_irs_;
 
-  // Cross-references within the current IR across node blocks, and to other
-  // IRs. The first entries will always be builtins, at indices matching
-  // SemanticsBuiltinKind ordering.
-  // TODO: Deduplicate cross-references after they can be added outside
-  // builtins.
-  llvm::SmallVector<SemanticsCrossReference> cross_references_;
-
   // Storage for integer literals.
   llvm::SmallVector<llvm::APInt> integer_literals_;
 
@@ -188,8 +114,12 @@ class SemanticsIR {
   llvm::StringMap<SemanticsStringId> string_to_id_;
   llvm::SmallVector<llvm::StringRef> strings_;
 
-  // Storage for blocks within the IR.
-  llvm::SmallVector<llvm::SmallVector<SemanticsNode>> node_blocks_;
+  // All nodes. The first entries will always be cross-references to builtins,
+  // at indices matching SemanticsBuiltinKind ordering.
+  llvm::SmallVector<SemanticsNode> nodes_;
+
+  // Storage for blocks within the IR. These reference entries in nodes_.
+  llvm::SmallVector<llvm::SmallVector<SemanticsNodeId>> node_blocks_;
 };
 
 }  // namespace Carbon

+ 22 - 24
toolchain/semantics/semantics_node.h

@@ -17,39 +17,24 @@ namespace Carbon {
 
 // Type-safe storage of Node IDs.
 struct SemanticsNodeId : public IndexBase {
-  static constexpr int32_t CrossReferenceBit = 0x8000'0000;
-
-  // Constructs a cross-reference node ID.
-  static auto MakeCrossReference(int32_t index) -> SemanticsNodeId {
-    return SemanticsNodeId(index | CrossReferenceBit);
-  }
-
-  // Constructs a cross-reference node ID for a builtin. This relies on
-  // SemanticsIR guarantees for builtin cross-reference placement.
+  // Uses the cross-reference node ID for a builtin. This relies on SemanticsIR
+  // guarantees for builtin cross-reference placement.
   static auto MakeBuiltinReference(SemanticsBuiltinKind kind)
       -> SemanticsNodeId {
-    return MakeCrossReference(kind.AsInt());
+    return SemanticsNodeId(kind.AsInt());
   }
 
   // Constructs an explicitly invalid instance.
   static auto MakeInvalid() -> SemanticsNodeId { return SemanticsNodeId(); }
 
   using IndexBase::IndexBase;
+  auto Print(llvm::raw_ostream& out) const -> void { out << "node" << index; }
+};
 
-  auto is_cross_reference() const -> bool { return index & CrossReferenceBit; }
-  // Returns the ID for a cross-reference, just handling removal of the marker
-  // bit.
-  auto GetAsCrossReference() const -> int32_t {
-    return index & ~CrossReferenceBit;
-  }
-
-  auto Print(llvm::raw_ostream& out) const -> void {
-    if (is_cross_reference()) {
-      out << "node_xref" << GetAsCrossReference();
-    } else {
-      out << "node" << index;
-    }
-  }
+// The ID of a cross-referenced IR.
+struct SemanticsCrossReferenceIRId : public IndexBase {
+  using IndexBase::IndexBase;
+  auto Print(llvm::raw_ostream& out) const -> void { out << "ir" << index; }
 };
 
 // Type-safe storage of integer literals.
@@ -133,6 +118,19 @@ class SemanticsNode {
     return SemanticsNodeBlockId(arg0_);
   }
 
+  static auto MakeCrossReference(SemanticsNodeId type,
+                                 SemanticsCrossReferenceIRId ir,
+                                 SemanticsNodeId node) -> SemanticsNode {
+    return SemanticsNode(ParseTree::Node::MakeInvalid(),
+                         SemanticsNodeKind::CrossReference(), type, ir.index,
+                         node.index);
+  }
+  auto GetAsCrossReference() const
+      -> std::pair<SemanticsCrossReferenceIRId, SemanticsNodeBlockId> {
+    CARBON_CHECK(kind_ == SemanticsNodeKind::CrossReference());
+    return {SemanticsCrossReferenceIRId(arg0_), SemanticsNodeBlockId(arg1_)};
+  }
+
   // TODO: The signature should be added as a parameter.
   static auto MakeFunctionDeclaration(ParseTree::Node parse_node)
       -> SemanticsNode {

+ 3 - 0
toolchain/semantics/semantics_node_kind.def

@@ -15,6 +15,9 @@
 
 CARBON_SEMANTICS_NODE_KIND(Invalid)
 
+// A cross-reference between IRs.
+CARBON_SEMANTICS_NODE_KIND(CrossReference)
+
 CARBON_SEMANTICS_NODE_KIND(Assign)
 CARBON_SEMANTICS_NODE_KIND(BinaryOperatorAdd)
 CARBON_SEMANTICS_NODE_KIND(BindName)

+ 5 - 15
toolchain/semantics/semantics_parse_tree_handler.cpp

@@ -86,15 +86,6 @@ auto SemanticsParseTreeHandler::Build() -> void {
   CARBON_CHECK(scope_stack_.empty()) << scope_stack_.size();
 }
 
-auto SemanticsParseTreeHandler::AddCrossReference(SemanticsNodeId node_id)
-    -> SemanticsNodeId {
-  CARBON_CHECK(!node_id.is_cross_reference())
-      << "Should use the existing cross-reference. Might want to return this, "
-         "but lacking a use-case, it's treated as bad input.";
-  return semantics_->AddCrossReference(SemanticsCrossReference(
-      SemanticsIR::ThisIR, current_block_id(), node_id));
-}
-
 auto SemanticsParseTreeHandler::AddNode(SemanticsNode node) -> SemanticsNodeId {
   CARBON_VLOG() << "AddNode " << current_block_id() << ": " << node << "\n";
   return semantics_->AddNode(current_block_id(), node);
@@ -113,7 +104,7 @@ auto SemanticsParseTreeHandler::BindName(ParseTree::Node name_node,
       SemanticsNode::MakeBindName(name_node, type_id, name_id, target_id));
   auto [it, inserted] = current_scope().names.insert(name_id);
   if (inserted) {
-    name_lookup_[name_id].push_back(AddCrossReference(bind_id));
+    name_lookup_[name_id].push_back(bind_id);
   } else {
     CARBON_DIAGNOSTIC(NameRedefined, Error, "Redefining {0} in the same scope.",
                       llvm::StringRef);
@@ -122,7 +113,7 @@ auto SemanticsParseTreeHandler::BindName(ParseTree::Node name_node,
     // TODO: This should be a note and sorted with the above diagnostic.
     // But that depends on more diagnostic support we currently don't have.
     auto prev_def_id = name_lookup_[name_id].back();
-    auto prev_def = semantics_->GetNode(current_block_id(), prev_def_id);
+    auto prev_def = semantics_->GetNode(prev_def_id);
     CARBON_DIAGNOSTIC(PreviousDefinition, Error,
                       "Previous definition is here.");
     emitter_->Emit(parse_tree_->node_token(prev_def.parse_node()),
@@ -234,9 +225,8 @@ auto SemanticsParseTreeHandler::TryTypeConversion(ParseTree::Node parse_node,
                                                   SemanticsNodeId rhs_id,
                                                   bool /*can_convert_lhs*/)
     -> SemanticsNodeId {
-  auto block = current_block_id();
-  auto lhs_type = semantics_->GetType(block, lhs_id);
-  auto rhs_type = semantics_->GetType(block, rhs_id);
+  auto lhs_type = semantics_->GetType(lhs_id);
+  auto rhs_type = semantics_->GetType(rhs_id);
   // TODO: This should attempt a type conversion, but there's not enough
   // implemented to do that right now.
   if (lhs_type != rhs_type) {
@@ -615,7 +605,7 @@ auto SemanticsParseTreeHandler::HandleReturnStatement(
     Push(parse_node, SemanticsNode::MakeReturn(parse_node));
   } else {
     auto arg = PopWithResult();
-    auto arg_type = semantics_->GetType(current_block_id(), arg);
+    auto arg_type = semantics_->GetType(arg);
     Pop(ParseNodeKind::ReturnStatementStart());
     Push(parse_node,
          SemanticsNode::MakeReturnExpression(parse_node, arg_type, arg));

+ 0 - 3
toolchain/semantics/semantics_parse_tree_handler.h

@@ -74,9 +74,6 @@ class SemanticsParseTreeHandler {
     // TODO: This likely needs to track things which need to be destructed.
   };
 
-  // Adds a cross-reference for a node_id in the current block.
-  auto AddCrossReference(SemanticsNodeId node_id) -> SemanticsNodeId;
-
   // Adds a node to the current block, returning the produced ID.
   auto AddNode(SemanticsNode node) -> SemanticsNodeId;
 

+ 7 - 7
toolchain/semantics/testdata/basics/empty.carbon

@@ -4,17 +4,17 @@
 //
 // AUTOUPDATE
 // RUN: %{carbon-run-semantics}
-// CHECK:STDOUT: cross_reference_irs.size == 2,
-// CHECK:STDOUT: cross_references = {
-// CHECK:STDOUT:   node_xref0 = xref(ir0, block0, node0);
-// CHECK:STDOUT:   node_xref1 = xref(ir0, block0, node1);
-// CHECK:STDOUT:   node_xref2 = xref(ir0, block0, node2);
-// CHECK:STDOUT:   node_xref3 = xref(ir0, block0, node3);
-// CHECK:STDOUT: },
+// CHECK:STDOUT: cross_reference_irs.size == 1,
 // CHECK:STDOUT: integer_literals = {
 // CHECK:STDOUT: },
 // CHECK:STDOUT: strings = {
 // CHECK:STDOUT: },
+// CHECK:STDOUT: nodes = {
+// CHECK:STDOUT:   node0 = CrossReference(ir0, block0): node0;
+// CHECK:STDOUT:   node1 = CrossReference(ir0, block1): node1;
+// CHECK:STDOUT:   node2 = CrossReference(ir0, block2): node0;
+// CHECK:STDOUT:   node3 = CrossReference(ir0, block3): node0;
+// CHECK:STDOUT: },
 // CHECK:STDOUT: node_blocks = {
 // CHECK:STDOUT:   block0 = {
 // CHECK:STDOUT:   },

+ 7 - 7
toolchain/semantics/testdata/basics/empty_decl.carbon

@@ -4,17 +4,17 @@
 //
 // AUTOUPDATE
 // RUN: %{carbon-run-semantics}
-// CHECK:STDOUT: cross_reference_irs.size == 2,
-// CHECK:STDOUT: cross_references = {
-// CHECK:STDOUT:   node_xref0 = xref(ir0, block0, node0);
-// CHECK:STDOUT:   node_xref1 = xref(ir0, block0, node1);
-// CHECK:STDOUT:   node_xref2 = xref(ir0, block0, node2);
-// CHECK:STDOUT:   node_xref3 = xref(ir0, block0, node3);
-// CHECK:STDOUT: },
+// CHECK:STDOUT: cross_reference_irs.size == 1,
 // CHECK:STDOUT: integer_literals = {
 // CHECK:STDOUT: },
 // CHECK:STDOUT: strings = {
 // CHECK:STDOUT: },
+// CHECK:STDOUT: nodes = {
+// CHECK:STDOUT:   node0 = CrossReference(ir0, block0): node0;
+// CHECK:STDOUT:   node1 = CrossReference(ir0, block1): node1;
+// CHECK:STDOUT:   node2 = CrossReference(ir0, block2): node0;
+// CHECK:STDOUT:   node3 = CrossReference(ir0, block3): node0;
+// CHECK:STDOUT: },
 // CHECK:STDOUT: node_blocks = {
 // CHECK:STDOUT:   block0 = {
 // CHECK:STDOUT:   },

+ 13 - 11
toolchain/semantics/testdata/basics/fail_name_lookup.carbon

@@ -4,24 +4,26 @@
 //
 // AUTOUPDATE
 // RUN: %{not} %{carbon-run-semantics}
-// CHECK:STDOUT: cross_reference_irs.size == 2,
-// CHECK:STDOUT: cross_references = {
-// CHECK:STDOUT:   node_xref0 = xref(ir0, block0, node0);
-// CHECK:STDOUT:   node_xref1 = xref(ir0, block0, node1);
-// CHECK:STDOUT:   node_xref2 = xref(ir0, block0, node2);
-// CHECK:STDOUT:   node_xref3 = xref(ir0, block0, node3);
-// CHECK:STDOUT:   node_xref4 = xref(ir1, block0, node1);
-// CHECK:STDOUT: },
+// CHECK:STDOUT: cross_reference_irs.size == 1,
 // CHECK:STDOUT: integer_literals = {
 // CHECK:STDOUT: },
 // CHECK:STDOUT: strings = {
 // CHECK:STDOUT:   str0 = "Main";
 // CHECK:STDOUT: },
+// CHECK:STDOUT: nodes = {
+// CHECK:STDOUT:   node0 = CrossReference(ir0, block0): node0;
+// CHECK:STDOUT:   node1 = CrossReference(ir0, block1): node1;
+// CHECK:STDOUT:   node2 = CrossReference(ir0, block2): node0;
+// CHECK:STDOUT:   node3 = CrossReference(ir0, block3): node0;
+// CHECK:STDOUT:   node4 = FunctionDeclaration();
+// CHECK:STDOUT:   node5 = BindName(str0, node4);
+// CHECK:STDOUT:   node6 = FunctionDefinition(node4, block1);
+// CHECK:STDOUT: },
 // CHECK:STDOUT: node_blocks = {
 // CHECK:STDOUT:   block0 = {
-// CHECK:STDOUT:     node0 = FunctionDeclaration();
-// CHECK:STDOUT:     node1 = BindName(str0, node0);
-// CHECK:STDOUT:     node2 = FunctionDefinition(node0, block1);
+// CHECK:STDOUT:     node4;
+// CHECK:STDOUT:     node5;
+// CHECK:STDOUT:     node6;
 // CHECK:STDOUT:   },
 // CHECK:STDOUT:   block1 = {
 // CHECK:STDOUT:   },

+ 1 - 1
toolchain/semantics/testdata/basics/verbose.carbon

@@ -7,7 +7,7 @@
 //
 // Only checks a couple statements in order to minimize manual update churn.
 // CHECK:STDERR: Push 0: FunctionIntroducer
-// CHECK:STDERR: AddNode block0: BindName(str0, node0)
+// CHECK:STDERR: AddNode block0: BindName(str0, node{{[0-9]+}})
 
 fn Foo() {
   return;

+ 13 - 11
toolchain/semantics/testdata/function/basic.carbon

@@ -4,24 +4,26 @@
 //
 // AUTOUPDATE
 // RUN: %{carbon-run-semantics}
-// CHECK:STDOUT: cross_reference_irs.size == 2,
-// CHECK:STDOUT: cross_references = {
-// CHECK:STDOUT:   node_xref0 = xref(ir0, block0, node0);
-// CHECK:STDOUT:   node_xref1 = xref(ir0, block0, node1);
-// CHECK:STDOUT:   node_xref2 = xref(ir0, block0, node2);
-// CHECK:STDOUT:   node_xref3 = xref(ir0, block0, node3);
-// CHECK:STDOUT:   node_xref4 = xref(ir1, block0, node1);
-// CHECK:STDOUT: },
+// CHECK:STDOUT: cross_reference_irs.size == 1,
 // CHECK:STDOUT: integer_literals = {
 // CHECK:STDOUT: },
 // CHECK:STDOUT: strings = {
 // CHECK:STDOUT:   str0 = "Foo";
 // CHECK:STDOUT: },
+// CHECK:STDOUT: nodes = {
+// CHECK:STDOUT:   node0 = CrossReference(ir0, block0): node0;
+// CHECK:STDOUT:   node1 = CrossReference(ir0, block1): node1;
+// CHECK:STDOUT:   node2 = CrossReference(ir0, block2): node0;
+// CHECK:STDOUT:   node3 = CrossReference(ir0, block3): node0;
+// CHECK:STDOUT:   node4 = FunctionDeclaration();
+// CHECK:STDOUT:   node5 = BindName(str0, node4);
+// CHECK:STDOUT:   node6 = FunctionDefinition(node4, block1);
+// CHECK:STDOUT: },
 // CHECK:STDOUT: node_blocks = {
 // CHECK:STDOUT:   block0 = {
-// CHECK:STDOUT:     node0 = FunctionDeclaration();
-// CHECK:STDOUT:     node1 = BindName(str0, node0);
-// CHECK:STDOUT:     node2 = FunctionDefinition(node0, block1);
+// CHECK:STDOUT:     node4;
+// CHECK:STDOUT:     node5;
+// CHECK:STDOUT:     node6;
 // CHECK:STDOUT:   },
 // CHECK:STDOUT:   block1 = {
 // CHECK:STDOUT:   },

+ 25 - 19
toolchain/semantics/testdata/function/order.carbon

@@ -4,16 +4,7 @@
 //
 // AUTOUPDATE
 // RUN: %{carbon-run-semantics}
-// CHECK:STDOUT: cross_reference_irs.size == 2,
-// CHECK:STDOUT: cross_references = {
-// CHECK:STDOUT:   node_xref0 = xref(ir0, block0, node0);
-// CHECK:STDOUT:   node_xref1 = xref(ir0, block0, node1);
-// CHECK:STDOUT:   node_xref2 = xref(ir0, block0, node2);
-// CHECK:STDOUT:   node_xref3 = xref(ir0, block0, node3);
-// CHECK:STDOUT:   node_xref4 = xref(ir1, block0, node1);
-// CHECK:STDOUT:   node_xref5 = xref(ir1, block0, node4);
-// CHECK:STDOUT:   node_xref6 = xref(ir1, block0, node7);
-// CHECK:STDOUT: },
+// CHECK:STDOUT: cross_reference_irs.size == 1,
 // CHECK:STDOUT: integer_literals = {
 // CHECK:STDOUT: },
 // CHECK:STDOUT: strings = {
@@ -21,17 +12,32 @@
 // CHECK:STDOUT:   str1 = "Bar";
 // CHECK:STDOUT:   str2 = "Baz";
 // CHECK:STDOUT: },
+// CHECK:STDOUT: nodes = {
+// CHECK:STDOUT:   node0 = CrossReference(ir0, block0): node0;
+// CHECK:STDOUT:   node1 = CrossReference(ir0, block1): node1;
+// CHECK:STDOUT:   node2 = CrossReference(ir0, block2): node0;
+// CHECK:STDOUT:   node3 = CrossReference(ir0, block3): node0;
+// CHECK:STDOUT:   node4 = FunctionDeclaration();
+// CHECK:STDOUT:   node5 = BindName(str0, node4);
+// CHECK:STDOUT:   node6 = FunctionDefinition(node4, block1);
+// CHECK:STDOUT:   node7 = FunctionDeclaration();
+// CHECK:STDOUT:   node8 = BindName(str1, node7);
+// CHECK:STDOUT:   node9 = FunctionDefinition(node7, block2);
+// CHECK:STDOUT:   node10 = FunctionDeclaration();
+// CHECK:STDOUT:   node11 = BindName(str2, node10);
+// CHECK:STDOUT:   node12 = FunctionDefinition(node10, block3);
+// CHECK:STDOUT: },
 // CHECK:STDOUT: node_blocks = {
 // CHECK:STDOUT:   block0 = {
-// CHECK:STDOUT:     node0 = FunctionDeclaration();
-// CHECK:STDOUT:     node1 = BindName(str0, node0);
-// CHECK:STDOUT:     node2 = FunctionDefinition(node0, block1);
-// CHECK:STDOUT:     node3 = FunctionDeclaration();
-// CHECK:STDOUT:     node4 = BindName(str1, node3);
-// CHECK:STDOUT:     node5 = FunctionDefinition(node3, block2);
-// CHECK:STDOUT:     node6 = FunctionDeclaration();
-// CHECK:STDOUT:     node7 = BindName(str2, node6);
-// CHECK:STDOUT:     node8 = FunctionDefinition(node6, block3);
+// CHECK:STDOUT:     node4;
+// CHECK:STDOUT:     node5;
+// CHECK:STDOUT:     node6;
+// CHECK:STDOUT:     node7;
+// CHECK:STDOUT:     node8;
+// CHECK:STDOUT:     node9;
+// CHECK:STDOUT:     node10;
+// CHECK:STDOUT:     node11;
+// CHECK:STDOUT:     node12;
 // CHECK:STDOUT:   },
 // CHECK:STDOUT:   block1 = {
 // CHECK:STDOUT:   },

+ 21 - 15
toolchain/semantics/testdata/operators/binary_op.carbon

@@ -4,14 +4,7 @@
 //
 // AUTOUPDATE
 // RUN: %{carbon-run-semantics}
-// CHECK:STDOUT: cross_reference_irs.size == 2,
-// CHECK:STDOUT: cross_references = {
-// CHECK:STDOUT:   node_xref0 = xref(ir0, block0, node0);
-// CHECK:STDOUT:   node_xref1 = xref(ir0, block0, node1);
-// CHECK:STDOUT:   node_xref2 = xref(ir0, block0, node2);
-// CHECK:STDOUT:   node_xref3 = xref(ir0, block0, node3);
-// CHECK:STDOUT:   node_xref4 = xref(ir1, block0, node1);
-// CHECK:STDOUT: },
+// CHECK:STDOUT: cross_reference_irs.size == 1,
 // CHECK:STDOUT: integer_literals = {
 // CHECK:STDOUT:   int0 = 12;
 // CHECK:STDOUT:   int1 = 34;
@@ -19,17 +12,30 @@
 // CHECK:STDOUT: strings = {
 // CHECK:STDOUT:   str0 = "Main";
 // CHECK:STDOUT: },
+// CHECK:STDOUT: nodes = {
+// CHECK:STDOUT:   node0 = CrossReference(ir0, block0): node0;
+// CHECK:STDOUT:   node1 = CrossReference(ir0, block1): node1;
+// CHECK:STDOUT:   node2 = CrossReference(ir0, block2): node0;
+// CHECK:STDOUT:   node3 = CrossReference(ir0, block3): node0;
+// CHECK:STDOUT:   node4 = FunctionDeclaration();
+// CHECK:STDOUT:   node5 = BindName(str0, node4);
+// CHECK:STDOUT:   node6 = FunctionDefinition(node4, block1);
+// CHECK:STDOUT:   node7 = IntegerLiteral(int0): node2;
+// CHECK:STDOUT:   node8 = IntegerLiteral(int1): node2;
+// CHECK:STDOUT:   node9 = BinaryOperatorAdd(node7, node8): node2;
+// CHECK:STDOUT:   node10 = ReturnExpression(node9): node2;
+// CHECK:STDOUT: },
 // CHECK:STDOUT: node_blocks = {
 // CHECK:STDOUT:   block0 = {
-// CHECK:STDOUT:     node0 = FunctionDeclaration();
-// CHECK:STDOUT:     node1 = BindName(str0, node0);
-// CHECK:STDOUT:     node2 = FunctionDefinition(node0, block1);
+// CHECK:STDOUT:     node4;
+// CHECK:STDOUT:     node5;
+// CHECK:STDOUT:     node6;
 // CHECK:STDOUT:   },
 // CHECK:STDOUT:   block1 = {
-// CHECK:STDOUT:     node0 = IntegerLiteral(int0): node_xref2;
-// CHECK:STDOUT:     node1 = IntegerLiteral(int1): node_xref2;
-// CHECK:STDOUT:     node2 = BinaryOperatorAdd(node0, node1): node_xref2;
-// CHECK:STDOUT:     node3 = ReturnExpression(node2): node_xref2;
+// CHECK:STDOUT:     node7;
+// CHECK:STDOUT:     node8;
+// CHECK:STDOUT:     node9;
+// CHECK:STDOUT:     node10;
 // CHECK:STDOUT:   },
 // CHECK:STDOUT: }
 

+ 22 - 16
toolchain/semantics/testdata/operators/fail_type_mismatch.carbon

@@ -4,35 +4,41 @@
 //
 // AUTOUPDATE
 // RUN: %{not} %{carbon-run-semantics}
-// CHECK:STDOUT: cross_reference_irs.size == 2,
-// CHECK:STDOUT: cross_references = {
-// CHECK:STDOUT:   node_xref0 = xref(ir0, block0, node0);
-// CHECK:STDOUT:   node_xref1 = xref(ir0, block0, node1);
-// CHECK:STDOUT:   node_xref2 = xref(ir0, block0, node2);
-// CHECK:STDOUT:   node_xref3 = xref(ir0, block0, node3);
-// CHECK:STDOUT:   node_xref4 = xref(ir1, block0, node1);
-// CHECK:STDOUT: },
+// CHECK:STDOUT: cross_reference_irs.size == 1,
 // CHECK:STDOUT: integer_literals = {
 // CHECK:STDOUT:   int0 = 12;
 // CHECK:STDOUT: },
 // CHECK:STDOUT: strings = {
 // CHECK:STDOUT:   str0 = "Main";
 // CHECK:STDOUT: },
+// CHECK:STDOUT: nodes = {
+// CHECK:STDOUT:   node0 = CrossReference(ir0, block0): node0;
+// CHECK:STDOUT:   node1 = CrossReference(ir0, block1): node1;
+// CHECK:STDOUT:   node2 = CrossReference(ir0, block2): node0;
+// CHECK:STDOUT:   node3 = CrossReference(ir0, block3): node0;
+// CHECK:STDOUT:   node4 = FunctionDeclaration();
+// CHECK:STDOUT:   node5 = BindName(str0, node4);
+// CHECK:STDOUT:   node6 = FunctionDefinition(node4, block1);
+// CHECK:STDOUT:   node7 = IntegerLiteral(int0): node2;
+// CHECK:STDOUT:   node8 = RealLiteral(): node3;
+// CHECK:STDOUT:   node9 = BinaryOperatorAdd(node7, node8): node1;
+// CHECK:STDOUT:   node10 = ReturnExpression(node9): node1;
+// CHECK:STDOUT: },
 // CHECK:STDOUT: node_blocks = {
 // CHECK:STDOUT:   block0 = {
-// CHECK:STDOUT:     node0 = FunctionDeclaration();
-// CHECK:STDOUT:     node1 = BindName(str0, node0);
-// CHECK:STDOUT:     node2 = FunctionDefinition(node0, block1);
+// CHECK:STDOUT:     node4;
+// CHECK:STDOUT:     node5;
+// CHECK:STDOUT:     node6;
 // CHECK:STDOUT:   },
 // CHECK:STDOUT:   block1 = {
-// CHECK:STDOUT:     node0 = IntegerLiteral(int0): node_xref2;
-// CHECK:STDOUT:     node1 = RealLiteral(): node_xref3;
-// CHECK:STDOUT:     node2 = BinaryOperatorAdd(node0, node1): node_xref1;
-// CHECK:STDOUT:     node3 = ReturnExpression(node2): node_xref1;
+// CHECK:STDOUT:     node7;
+// CHECK:STDOUT:     node8;
+// CHECK:STDOUT:     node9;
+// CHECK:STDOUT:     node10;
 // CHECK:STDOUT:   },
 // CHECK:STDOUT: }
 
 fn Main() {
-  // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/operators/fail_type_mismatch.carbon:[[@LINE+1]]:13: Type mismatch: lhs is node_xref2, rhs is node_xref3
+  // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/operators/fail_type_mismatch.carbon:[[@LINE+1]]:13: Type mismatch: lhs is node2, rhs is node3
   return 12 + 3.4;
 }

+ 26 - 18
toolchain/semantics/testdata/operators/fail_type_mismatch_once.carbon

@@ -4,14 +4,7 @@
 //
 // AUTOUPDATE
 // RUN: %{not} %{carbon-run-semantics}
-// CHECK:STDOUT: cross_reference_irs.size == 2,
-// CHECK:STDOUT: cross_references = {
-// CHECK:STDOUT:   node_xref0 = xref(ir0, block0, node0);
-// CHECK:STDOUT:   node_xref1 = xref(ir0, block0, node1);
-// CHECK:STDOUT:   node_xref2 = xref(ir0, block0, node2);
-// CHECK:STDOUT:   node_xref3 = xref(ir0, block0, node3);
-// CHECK:STDOUT:   node_xref4 = xref(ir1, block0, node1);
-// CHECK:STDOUT: },
+// CHECK:STDOUT: cross_reference_irs.size == 1,
 // CHECK:STDOUT: integer_literals = {
 // CHECK:STDOUT:   int0 = 12;
 // CHECK:STDOUT:   int1 = 12;
@@ -19,25 +12,40 @@
 // CHECK:STDOUT: strings = {
 // CHECK:STDOUT:   str0 = "Main";
 // CHECK:STDOUT: },
+// CHECK:STDOUT: nodes = {
+// CHECK:STDOUT:   node0 = CrossReference(ir0, block0): node0;
+// CHECK:STDOUT:   node1 = CrossReference(ir0, block1): node1;
+// CHECK:STDOUT:   node2 = CrossReference(ir0, block2): node0;
+// CHECK:STDOUT:   node3 = CrossReference(ir0, block3): node0;
+// CHECK:STDOUT:   node4 = FunctionDeclaration();
+// CHECK:STDOUT:   node5 = BindName(str0, node4);
+// CHECK:STDOUT:   node6 = FunctionDefinition(node4, block1);
+// CHECK:STDOUT:   node7 = IntegerLiteral(int0): node2;
+// CHECK:STDOUT:   node8 = RealLiteral(): node3;
+// CHECK:STDOUT:   node9 = BinaryOperatorAdd(node7, node8): node1;
+// CHECK:STDOUT:   node10 = IntegerLiteral(int1): node2;
+// CHECK:STDOUT:   node11 = BinaryOperatorAdd(node9, node10): node1;
+// CHECK:STDOUT:   node12 = ReturnExpression(node11): node1;
+// CHECK:STDOUT: },
 // CHECK:STDOUT: node_blocks = {
 // CHECK:STDOUT:   block0 = {
-// CHECK:STDOUT:     node0 = FunctionDeclaration();
-// CHECK:STDOUT:     node1 = BindName(str0, node0);
-// CHECK:STDOUT:     node2 = FunctionDefinition(node0, block1);
+// CHECK:STDOUT:     node4;
+// CHECK:STDOUT:     node5;
+// CHECK:STDOUT:     node6;
 // CHECK:STDOUT:   },
 // CHECK:STDOUT:   block1 = {
-// CHECK:STDOUT:     node0 = IntegerLiteral(int0): node_xref2;
-// CHECK:STDOUT:     node1 = RealLiteral(): node_xref3;
-// CHECK:STDOUT:     node2 = BinaryOperatorAdd(node0, node1): node_xref1;
-// CHECK:STDOUT:     node3 = IntegerLiteral(int1): node_xref2;
-// CHECK:STDOUT:     node4 = BinaryOperatorAdd(node2, node3): node_xref1;
-// CHECK:STDOUT:     node5 = ReturnExpression(node4): node_xref1;
+// CHECK:STDOUT:     node7;
+// CHECK:STDOUT:     node8;
+// CHECK:STDOUT:     node9;
+// CHECK:STDOUT:     node10;
+// CHECK:STDOUT:     node11;
+// CHECK:STDOUT:     node12;
 // CHECK:STDOUT:   },
 // CHECK:STDOUT: }
 
 fn Main() {
   // The following line has two mismatches, but after the first, it shouldn't
   // keep erroring.
-  // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/operators/fail_type_mismatch_once.carbon:[[@LINE+1]]:13: Type mismatch: lhs is node_xref2, rhs is node_xref3
+  // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/operators/fail_type_mismatch_once.carbon:[[@LINE+1]]:13: Type mismatch: lhs is node2, rhs is node3
   return 12 + 3.4 + 12;
 }

+ 17 - 13
toolchain/semantics/testdata/return/literal.carbon

@@ -4,29 +4,33 @@
 //
 // AUTOUPDATE
 // RUN: %{carbon-run-semantics}
-// CHECK:STDOUT: cross_reference_irs.size == 2,
-// CHECK:STDOUT: cross_references = {
-// CHECK:STDOUT:   node_xref0 = xref(ir0, block0, node0);
-// CHECK:STDOUT:   node_xref1 = xref(ir0, block0, node1);
-// CHECK:STDOUT:   node_xref2 = xref(ir0, block0, node2);
-// CHECK:STDOUT:   node_xref3 = xref(ir0, block0, node3);
-// CHECK:STDOUT:   node_xref4 = xref(ir1, block0, node1);
-// CHECK:STDOUT: },
+// CHECK:STDOUT: cross_reference_irs.size == 1,
 // CHECK:STDOUT: integer_literals = {
 // CHECK:STDOUT:   int0 = 0;
 // CHECK:STDOUT: },
 // CHECK:STDOUT: strings = {
 // CHECK:STDOUT:   str0 = "Main";
 // CHECK:STDOUT: },
+// CHECK:STDOUT: nodes = {
+// CHECK:STDOUT:   node0 = CrossReference(ir0, block0): node0;
+// CHECK:STDOUT:   node1 = CrossReference(ir0, block1): node1;
+// CHECK:STDOUT:   node2 = CrossReference(ir0, block2): node0;
+// CHECK:STDOUT:   node3 = CrossReference(ir0, block3): node0;
+// CHECK:STDOUT:   node4 = FunctionDeclaration();
+// CHECK:STDOUT:   node5 = BindName(str0, node4);
+// CHECK:STDOUT:   node6 = FunctionDefinition(node4, block1);
+// CHECK:STDOUT:   node7 = IntegerLiteral(int0): node2;
+// CHECK:STDOUT:   node8 = ReturnExpression(node7): node2;
+// CHECK:STDOUT: },
 // CHECK:STDOUT: node_blocks = {
 // CHECK:STDOUT:   block0 = {
-// CHECK:STDOUT:     node0 = FunctionDeclaration();
-// CHECK:STDOUT:     node1 = BindName(str0, node0);
-// CHECK:STDOUT:     node2 = FunctionDefinition(node0, block1);
+// CHECK:STDOUT:     node4;
+// CHECK:STDOUT:     node5;
+// CHECK:STDOUT:     node6;
 // CHECK:STDOUT:   },
 // CHECK:STDOUT:   block1 = {
-// CHECK:STDOUT:     node0 = IntegerLiteral(int0): node_xref2;
-// CHECK:STDOUT:     node1 = ReturnExpression(node0): node_xref2;
+// CHECK:STDOUT:     node7;
+// CHECK:STDOUT:     node8;
 // CHECK:STDOUT:   },
 // CHECK:STDOUT: }
 

+ 15 - 12
toolchain/semantics/testdata/return/trivial.carbon

@@ -4,27 +4,30 @@
 //
 // AUTOUPDATE
 // RUN: %{carbon-run-semantics}
-// CHECK:STDOUT: cross_reference_irs.size == 2,
-// CHECK:STDOUT: cross_references = {
-// CHECK:STDOUT:   node_xref0 = xref(ir0, block0, node0);
-// CHECK:STDOUT:   node_xref1 = xref(ir0, block0, node1);
-// CHECK:STDOUT:   node_xref2 = xref(ir0, block0, node2);
-// CHECK:STDOUT:   node_xref3 = xref(ir0, block0, node3);
-// CHECK:STDOUT:   node_xref4 = xref(ir1, block0, node1);
-// CHECK:STDOUT: },
+// CHECK:STDOUT: cross_reference_irs.size == 1,
 // CHECK:STDOUT: integer_literals = {
 // CHECK:STDOUT: },
 // CHECK:STDOUT: strings = {
 // CHECK:STDOUT:   str0 = "Main";
 // CHECK:STDOUT: },
+// CHECK:STDOUT: nodes = {
+// CHECK:STDOUT:   node0 = CrossReference(ir0, block0): node0;
+// CHECK:STDOUT:   node1 = CrossReference(ir0, block1): node1;
+// CHECK:STDOUT:   node2 = CrossReference(ir0, block2): node0;
+// CHECK:STDOUT:   node3 = CrossReference(ir0, block3): node0;
+// CHECK:STDOUT:   node4 = FunctionDeclaration();
+// CHECK:STDOUT:   node5 = BindName(str0, node4);
+// CHECK:STDOUT:   node6 = FunctionDefinition(node4, block1);
+// CHECK:STDOUT:   node7 = Return();
+// CHECK:STDOUT: },
 // CHECK:STDOUT: node_blocks = {
 // CHECK:STDOUT:   block0 = {
-// CHECK:STDOUT:     node0 = FunctionDeclaration();
-// CHECK:STDOUT:     node1 = BindName(str0, node0);
-// CHECK:STDOUT:     node2 = FunctionDefinition(node0, block1);
+// CHECK:STDOUT:     node4;
+// CHECK:STDOUT:     node5;
+// CHECK:STDOUT:     node6;
 // CHECK:STDOUT:   },
 // CHECK:STDOUT:   block1 = {
-// CHECK:STDOUT:     node0 = Return();
+// CHECK:STDOUT:     node7;
 // CHECK:STDOUT:   },
 // CHECK:STDOUT: }
 

+ 17 - 14
toolchain/semantics/testdata/var/decl.carbon

@@ -4,30 +4,33 @@
 //
 // AUTOUPDATE
 // RUN: %{carbon-run-semantics}
-// CHECK:STDOUT: cross_reference_irs.size == 2,
-// CHECK:STDOUT: cross_references = {
-// CHECK:STDOUT:   node_xref0 = xref(ir0, block0, node0);
-// CHECK:STDOUT:   node_xref1 = xref(ir0, block0, node1);
-// CHECK:STDOUT:   node_xref2 = xref(ir0, block0, node2);
-// CHECK:STDOUT:   node_xref3 = xref(ir0, block0, node3);
-// CHECK:STDOUT:   node_xref4 = xref(ir1, block0, node1);
-// CHECK:STDOUT:   node_xref5 = xref(ir1, block1, node1);
-// CHECK:STDOUT: },
+// CHECK:STDOUT: cross_reference_irs.size == 1,
 // CHECK:STDOUT: integer_literals = {
 // CHECK:STDOUT: },
 // CHECK:STDOUT: strings = {
 // CHECK:STDOUT:   str0 = "Main";
 // CHECK:STDOUT:   str1 = "x";
 // CHECK:STDOUT: },
+// CHECK:STDOUT: nodes = {
+// CHECK:STDOUT:   node0 = CrossReference(ir0, block0): node0;
+// CHECK:STDOUT:   node1 = CrossReference(ir0, block1): node1;
+// CHECK:STDOUT:   node2 = CrossReference(ir0, block2): node0;
+// CHECK:STDOUT:   node3 = CrossReference(ir0, block3): node0;
+// CHECK:STDOUT:   node4 = FunctionDeclaration();
+// CHECK:STDOUT:   node5 = BindName(str0, node4);
+// CHECK:STDOUT:   node6 = FunctionDefinition(node4, block1);
+// CHECK:STDOUT:   node7 = VarStorage(): node2;
+// CHECK:STDOUT:   node8 = BindName(str1, node7): node2;
+// CHECK:STDOUT: },
 // CHECK:STDOUT: node_blocks = {
 // CHECK:STDOUT:   block0 = {
-// CHECK:STDOUT:     node0 = FunctionDeclaration();
-// CHECK:STDOUT:     node1 = BindName(str0, node0);
-// CHECK:STDOUT:     node2 = FunctionDefinition(node0, block1);
+// CHECK:STDOUT:     node4;
+// CHECK:STDOUT:     node5;
+// CHECK:STDOUT:     node6;
 // CHECK:STDOUT:   },
 // CHECK:STDOUT:   block1 = {
-// CHECK:STDOUT:     node0 = VarStorage(): node_xref2;
-// CHECK:STDOUT:     node1 = BindName(str1, node0): node_xref2;
+// CHECK:STDOUT:     node7;
+// CHECK:STDOUT:     node8;
 // CHECK:STDOUT:   },
 // CHECK:STDOUT: }
 

+ 21 - 16
toolchain/semantics/testdata/var/decl_with_init.carbon

@@ -4,15 +4,7 @@
 //
 // AUTOUPDATE
 // RUN: %{carbon-run-semantics}
-// CHECK:STDOUT: cross_reference_irs.size == 2,
-// CHECK:STDOUT: cross_references = {
-// CHECK:STDOUT:   node_xref0 = xref(ir0, block0, node0);
-// CHECK:STDOUT:   node_xref1 = xref(ir0, block0, node1);
-// CHECK:STDOUT:   node_xref2 = xref(ir0, block0, node2);
-// CHECK:STDOUT:   node_xref3 = xref(ir0, block0, node3);
-// CHECK:STDOUT:   node_xref4 = xref(ir1, block0, node1);
-// CHECK:STDOUT:   node_xref5 = xref(ir1, block1, node1);
-// CHECK:STDOUT: },
+// CHECK:STDOUT: cross_reference_irs.size == 1,
 // CHECK:STDOUT: integer_literals = {
 // CHECK:STDOUT:   int0 = 0;
 // CHECK:STDOUT: },
@@ -20,17 +12,30 @@
 // CHECK:STDOUT:   str0 = "Main";
 // CHECK:STDOUT:   str1 = "x";
 // CHECK:STDOUT: },
+// CHECK:STDOUT: nodes = {
+// CHECK:STDOUT:   node0 = CrossReference(ir0, block0): node0;
+// CHECK:STDOUT:   node1 = CrossReference(ir0, block1): node1;
+// CHECK:STDOUT:   node2 = CrossReference(ir0, block2): node0;
+// CHECK:STDOUT:   node3 = CrossReference(ir0, block3): node0;
+// CHECK:STDOUT:   node4 = FunctionDeclaration();
+// CHECK:STDOUT:   node5 = BindName(str0, node4);
+// CHECK:STDOUT:   node6 = FunctionDefinition(node4, block1);
+// CHECK:STDOUT:   node7 = VarStorage(): node2;
+// CHECK:STDOUT:   node8 = BindName(str1, node7): node2;
+// CHECK:STDOUT:   node9 = IntegerLiteral(int0): node2;
+// CHECK:STDOUT:   node10 = Assign(node7, node9): node2;
+// CHECK:STDOUT: },
 // CHECK:STDOUT: node_blocks = {
 // CHECK:STDOUT:   block0 = {
-// CHECK:STDOUT:     node0 = FunctionDeclaration();
-// CHECK:STDOUT:     node1 = BindName(str0, node0);
-// CHECK:STDOUT:     node2 = FunctionDefinition(node0, block1);
+// CHECK:STDOUT:     node4;
+// CHECK:STDOUT:     node5;
+// CHECK:STDOUT:     node6;
 // CHECK:STDOUT:   },
 // CHECK:STDOUT:   block1 = {
-// CHECK:STDOUT:     node0 = VarStorage(): node_xref2;
-// CHECK:STDOUT:     node1 = BindName(str1, node0): node_xref2;
-// CHECK:STDOUT:     node2 = IntegerLiteral(int0): node_xref2;
-// CHECK:STDOUT:     node3 = Assign(node0, node2): node_xref2;
+// CHECK:STDOUT:     node7;
+// CHECK:STDOUT:     node8;
+// CHECK:STDOUT:     node9;
+// CHECK:STDOUT:     node10;
 // CHECK:STDOUT:   },
 // CHECK:STDOUT: }
 

+ 29 - 20
toolchain/semantics/testdata/var/fail_duplicate_decl.carbon

@@ -4,15 +4,7 @@
 //
 // AUTOUPDATE
 // RUN: %{not} %{carbon-run-semantics}
-// CHECK:STDOUT: cross_reference_irs.size == 2,
-// CHECK:STDOUT: cross_references = {
-// CHECK:STDOUT:   node_xref0 = xref(ir0, block0, node0);
-// CHECK:STDOUT:   node_xref1 = xref(ir0, block0, node1);
-// CHECK:STDOUT:   node_xref2 = xref(ir0, block0, node2);
-// CHECK:STDOUT:   node_xref3 = xref(ir0, block0, node3);
-// CHECK:STDOUT:   node_xref4 = xref(ir1, block0, node1);
-// CHECK:STDOUT:   node_xref5 = xref(ir1, block1, node1);
-// CHECK:STDOUT: },
+// CHECK:STDOUT: cross_reference_irs.size == 1,
 // CHECK:STDOUT: integer_literals = {
 // CHECK:STDOUT:   int0 = 0;
 // CHECK:STDOUT:   int1 = 0;
@@ -21,21 +13,38 @@
 // CHECK:STDOUT:   str0 = "Main";
 // CHECK:STDOUT:   str1 = "x";
 // CHECK:STDOUT: },
+// CHECK:STDOUT: nodes = {
+// CHECK:STDOUT:   node0 = CrossReference(ir0, block0): node0;
+// CHECK:STDOUT:   node1 = CrossReference(ir0, block1): node1;
+// CHECK:STDOUT:   node2 = CrossReference(ir0, block2): node0;
+// CHECK:STDOUT:   node3 = CrossReference(ir0, block3): node0;
+// CHECK:STDOUT:   node4 = FunctionDeclaration();
+// CHECK:STDOUT:   node5 = BindName(str0, node4);
+// CHECK:STDOUT:   node6 = FunctionDefinition(node4, block1);
+// CHECK:STDOUT:   node7 = VarStorage(): node2;
+// CHECK:STDOUT:   node8 = BindName(str1, node7): node2;
+// CHECK:STDOUT:   node9 = IntegerLiteral(int0): node2;
+// CHECK:STDOUT:   node10 = Assign(node7, node9): node2;
+// CHECK:STDOUT:   node11 = VarStorage(): node2;
+// CHECK:STDOUT:   node12 = BindName(str1, node11): node2;
+// CHECK:STDOUT:   node13 = IntegerLiteral(int1): node2;
+// CHECK:STDOUT:   node14 = Assign(node11, node13): node2;
+// CHECK:STDOUT: },
 // CHECK:STDOUT: node_blocks = {
 // CHECK:STDOUT:   block0 = {
-// CHECK:STDOUT:     node0 = FunctionDeclaration();
-// CHECK:STDOUT:     node1 = BindName(str0, node0);
-// CHECK:STDOUT:     node2 = FunctionDefinition(node0, block1);
+// CHECK:STDOUT:     node4;
+// CHECK:STDOUT:     node5;
+// CHECK:STDOUT:     node6;
 // CHECK:STDOUT:   },
 // CHECK:STDOUT:   block1 = {
-// CHECK:STDOUT:     node0 = VarStorage(): node_xref2;
-// CHECK:STDOUT:     node1 = BindName(str1, node0): node_xref2;
-// CHECK:STDOUT:     node2 = IntegerLiteral(int0): node_xref2;
-// CHECK:STDOUT:     node3 = Assign(node0, node2): node_xref2;
-// CHECK:STDOUT:     node4 = VarStorage(): node_xref2;
-// CHECK:STDOUT:     node5 = BindName(str1, node4): node_xref2;
-// CHECK:STDOUT:     node6 = IntegerLiteral(int1): node_xref2;
-// CHECK:STDOUT:     node7 = Assign(node4, node6): node_xref2;
+// CHECK:STDOUT:     node7;
+// CHECK:STDOUT:     node8;
+// CHECK:STDOUT:     node9;
+// CHECK:STDOUT:     node10;
+// CHECK:STDOUT:     node11;
+// CHECK:STDOUT:     node12;
+// CHECK:STDOUT:     node13;
+// CHECK:STDOUT:     node14;
 // CHECK:STDOUT:   },
 // CHECK:STDOUT: }
 

+ 22 - 17
toolchain/semantics/testdata/var/fail_init_type_mismatch.carbon

@@ -4,36 +4,41 @@
 //
 // AUTOUPDATE
 // RUN: %{not} %{carbon-run-semantics}
-// CHECK:STDOUT: cross_reference_irs.size == 2,
-// CHECK:STDOUT: cross_references = {
-// CHECK:STDOUT:   node_xref0 = xref(ir0, block0, node0);
-// CHECK:STDOUT:   node_xref1 = xref(ir0, block0, node1);
-// CHECK:STDOUT:   node_xref2 = xref(ir0, block0, node2);
-// CHECK:STDOUT:   node_xref3 = xref(ir0, block0, node3);
-// CHECK:STDOUT:   node_xref4 = xref(ir1, block0, node1);
-// CHECK:STDOUT:   node_xref5 = xref(ir1, block1, node1);
-// CHECK:STDOUT: },
+// CHECK:STDOUT: cross_reference_irs.size == 1,
 // CHECK:STDOUT: integer_literals = {
 // CHECK:STDOUT: },
 // CHECK:STDOUT: strings = {
 // CHECK:STDOUT:   str0 = "Main";
 // CHECK:STDOUT:   str1 = "x";
 // CHECK:STDOUT: },
+// CHECK:STDOUT: nodes = {
+// CHECK:STDOUT:   node0 = CrossReference(ir0, block0): node0;
+// CHECK:STDOUT:   node1 = CrossReference(ir0, block1): node1;
+// CHECK:STDOUT:   node2 = CrossReference(ir0, block2): node0;
+// CHECK:STDOUT:   node3 = CrossReference(ir0, block3): node0;
+// CHECK:STDOUT:   node4 = FunctionDeclaration();
+// CHECK:STDOUT:   node5 = BindName(str0, node4);
+// CHECK:STDOUT:   node6 = FunctionDefinition(node4, block1);
+// CHECK:STDOUT:   node7 = VarStorage(): node2;
+// CHECK:STDOUT:   node8 = BindName(str1, node7): node2;
+// CHECK:STDOUT:   node9 = RealLiteral(): node3;
+// CHECK:STDOUT:   node10 = Assign(node7, node9): node1;
+// CHECK:STDOUT: },
 // CHECK:STDOUT: node_blocks = {
 // CHECK:STDOUT:   block0 = {
-// CHECK:STDOUT:     node0 = FunctionDeclaration();
-// CHECK:STDOUT:     node1 = BindName(str0, node0);
-// CHECK:STDOUT:     node2 = FunctionDefinition(node0, block1);
+// CHECK:STDOUT:     node4;
+// CHECK:STDOUT:     node5;
+// CHECK:STDOUT:     node6;
 // CHECK:STDOUT:   },
 // CHECK:STDOUT:   block1 = {
-// CHECK:STDOUT:     node0 = VarStorage(): node_xref2;
-// CHECK:STDOUT:     node1 = BindName(str1, node0): node_xref2;
-// CHECK:STDOUT:     node2 = RealLiteral(): node_xref3;
-// CHECK:STDOUT:     node3 = Assign(node0, node2): node_xref1;
+// CHECK:STDOUT:     node7;
+// CHECK:STDOUT:     node8;
+// CHECK:STDOUT:     node9;
+// CHECK:STDOUT:     node10;
 // CHECK:STDOUT:   },
 // CHECK:STDOUT: }
 
 fn Main() {
-  // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/var/fail_init_type_mismatch.carbon:[[@LINE+1]]:19: Type mismatch: lhs is node_xref2, rhs is node_xref3
+  // CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/var/fail_init_type_mismatch.carbon:[[@LINE+1]]:19: Type mismatch: lhs is node2, rhs is node3
   var x: i32 = 1.0;
 }

+ 49 - 0
toolchain/semantics/testdata/var/fail_lookup_outside_scope.carbon

@@ -0,0 +1,49 @@
+// 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
+// RUN: %{not} %{carbon-run-semantics}
+// CHECK:STDOUT: cross_reference_irs.size == 1,
+// CHECK:STDOUT: integer_literals = {
+// CHECK:STDOUT: },
+// CHECK:STDOUT: strings = {
+// CHECK:STDOUT:   str0 = "Main";
+// CHECK:STDOUT:   str1 = "x";
+// CHECK:STDOUT:   str2 = "y";
+// CHECK:STDOUT: },
+// CHECK:STDOUT: nodes = {
+// CHECK:STDOUT:   node0 = CrossReference(ir0, block0): node0;
+// CHECK:STDOUT:   node1 = CrossReference(ir0, block1): node1;
+// CHECK:STDOUT:   node2 = CrossReference(ir0, block2): node0;
+// CHECK:STDOUT:   node3 = CrossReference(ir0, block3): node0;
+// CHECK:STDOUT:   node4 = FunctionDeclaration();
+// CHECK:STDOUT:   node5 = BindName(str0, node4);
+// CHECK:STDOUT:   node6 = FunctionDefinition(node4, block1);
+// CHECK:STDOUT:   node7 = VarStorage(): node2;
+// CHECK:STDOUT:   node8 = BindName(str1, node7): node2;
+// CHECK:STDOUT:   node9 = VarStorage(): node2;
+// CHECK:STDOUT:   node10 = BindName(str2, node9): node2;
+// CHECK:STDOUT:   node11 = Assign(node9, node1): node1;
+// CHECK:STDOUT: },
+// CHECK:STDOUT: node_blocks = {
+// CHECK:STDOUT:   block0 = {
+// CHECK:STDOUT:     node4;
+// CHECK:STDOUT:     node5;
+// CHECK:STDOUT:     node6;
+// CHECK:STDOUT:     node9;
+// CHECK:STDOUT:     node10;
+// CHECK:STDOUT:     node11;
+// CHECK:STDOUT:   },
+// CHECK:STDOUT:   block1 = {
+// CHECK:STDOUT:     node7;
+// CHECK:STDOUT:     node8;
+// CHECK:STDOUT:   },
+// CHECK:STDOUT: }
+
+fn Main() {
+  var x: i32;
+}
+
+// CHECK:STDERR: {{.*}}/toolchain/semantics/testdata/var/fail_lookup_outside_scope.carbon:[[@LINE+1]]:14: Name x not found
+var y: i32 = x;

+ 11 - 10
toolchain/semantics/testdata/var/global_decl.carbon

@@ -4,23 +4,24 @@
 //
 // AUTOUPDATE
 // RUN: %{carbon-run-semantics}
-// CHECK:STDOUT: cross_reference_irs.size == 2,
-// CHECK:STDOUT: cross_references = {
-// CHECK:STDOUT:   node_xref0 = xref(ir0, block0, node0);
-// CHECK:STDOUT:   node_xref1 = xref(ir0, block0, node1);
-// CHECK:STDOUT:   node_xref2 = xref(ir0, block0, node2);
-// CHECK:STDOUT:   node_xref3 = xref(ir0, block0, node3);
-// CHECK:STDOUT:   node_xref4 = xref(ir1, block0, node1);
-// CHECK:STDOUT: },
+// CHECK:STDOUT: cross_reference_irs.size == 1,
 // CHECK:STDOUT: integer_literals = {
 // CHECK:STDOUT: },
 // CHECK:STDOUT: strings = {
 // CHECK:STDOUT:   str0 = "x";
 // CHECK:STDOUT: },
+// CHECK:STDOUT: nodes = {
+// CHECK:STDOUT:   node0 = CrossReference(ir0, block0): node0;
+// CHECK:STDOUT:   node1 = CrossReference(ir0, block1): node1;
+// CHECK:STDOUT:   node2 = CrossReference(ir0, block2): node0;
+// CHECK:STDOUT:   node3 = CrossReference(ir0, block3): node0;
+// CHECK:STDOUT:   node4 = VarStorage(): node2;
+// CHECK:STDOUT:   node5 = BindName(str0, node4): node2;
+// CHECK:STDOUT: },
 // CHECK:STDOUT: node_blocks = {
 // CHECK:STDOUT:   block0 = {
-// CHECK:STDOUT:     node0 = VarStorage(): node_xref2;
-// CHECK:STDOUT:     node1 = BindName(str0, node0): node_xref2;
+// CHECK:STDOUT:     node4;
+// CHECK:STDOUT:     node5;
 // CHECK:STDOUT:   },
 // CHECK:STDOUT: }
 

+ 15 - 12
toolchain/semantics/testdata/var/global_decl_with_init.carbon

@@ -4,26 +4,29 @@
 //
 // AUTOUPDATE
 // RUN: %{carbon-run-semantics}
-// CHECK:STDOUT: cross_reference_irs.size == 2,
-// CHECK:STDOUT: cross_references = {
-// CHECK:STDOUT:   node_xref0 = xref(ir0, block0, node0);
-// CHECK:STDOUT:   node_xref1 = xref(ir0, block0, node1);
-// CHECK:STDOUT:   node_xref2 = xref(ir0, block0, node2);
-// CHECK:STDOUT:   node_xref3 = xref(ir0, block0, node3);
-// CHECK:STDOUT:   node_xref4 = xref(ir1, block0, node1);
-// CHECK:STDOUT: },
+// CHECK:STDOUT: cross_reference_irs.size == 1,
 // CHECK:STDOUT: integer_literals = {
 // CHECK:STDOUT:   int0 = 0;
 // CHECK:STDOUT: },
 // CHECK:STDOUT: strings = {
 // CHECK:STDOUT:   str0 = "x";
 // CHECK:STDOUT: },
+// CHECK:STDOUT: nodes = {
+// CHECK:STDOUT:   node0 = CrossReference(ir0, block0): node0;
+// CHECK:STDOUT:   node1 = CrossReference(ir0, block1): node1;
+// CHECK:STDOUT:   node2 = CrossReference(ir0, block2): node0;
+// CHECK:STDOUT:   node3 = CrossReference(ir0, block3): node0;
+// CHECK:STDOUT:   node4 = VarStorage(): node2;
+// CHECK:STDOUT:   node5 = BindName(str0, node4): node2;
+// CHECK:STDOUT:   node6 = IntegerLiteral(int0): node2;
+// CHECK:STDOUT:   node7 = Assign(node4, node6): node2;
+// CHECK:STDOUT: },
 // CHECK:STDOUT: node_blocks = {
 // CHECK:STDOUT:   block0 = {
-// CHECK:STDOUT:     node0 = VarStorage(): node_xref2;
-// CHECK:STDOUT:     node1 = BindName(str0, node0): node_xref2;
-// CHECK:STDOUT:     node2 = IntegerLiteral(int0): node_xref2;
-// CHECK:STDOUT:     node3 = Assign(node0, node2): node_xref2;
+// CHECK:STDOUT:     node4;
+// CHECK:STDOUT:     node5;
+// CHECK:STDOUT:     node6;
+// CHECK:STDOUT:     node7;
 // CHECK:STDOUT:   },
 // CHECK:STDOUT: }
 

+ 21 - 16
toolchain/semantics/testdata/var/global_lookup.carbon

@@ -4,15 +4,7 @@
 //
 // AUTOUPDATE
 // RUN: %{carbon-run-semantics}
-// CHECK:STDOUT: cross_reference_irs.size == 2,
-// CHECK:STDOUT: cross_references = {
-// CHECK:STDOUT:   node_xref0 = xref(ir0, block0, node0);
-// CHECK:STDOUT:   node_xref1 = xref(ir0, block0, node1);
-// CHECK:STDOUT:   node_xref2 = xref(ir0, block0, node2);
-// CHECK:STDOUT:   node_xref3 = xref(ir0, block0, node3);
-// CHECK:STDOUT:   node_xref4 = xref(ir1, block0, node1);
-// CHECK:STDOUT:   node_xref5 = xref(ir1, block0, node5);
-// CHECK:STDOUT: },
+// CHECK:STDOUT: cross_reference_irs.size == 1,
 // CHECK:STDOUT: integer_literals = {
 // CHECK:STDOUT:   int0 = 0;
 // CHECK:STDOUT: },
@@ -20,15 +12,28 @@
 // CHECK:STDOUT:   str0 = "x";
 // CHECK:STDOUT:   str1 = "y";
 // CHECK:STDOUT: },
+// CHECK:STDOUT: nodes = {
+// CHECK:STDOUT:   node0 = CrossReference(ir0, block0): node0;
+// CHECK:STDOUT:   node1 = CrossReference(ir0, block1): node1;
+// CHECK:STDOUT:   node2 = CrossReference(ir0, block2): node0;
+// CHECK:STDOUT:   node3 = CrossReference(ir0, block3): node0;
+// CHECK:STDOUT:   node4 = VarStorage(): node2;
+// CHECK:STDOUT:   node5 = BindName(str0, node4): node2;
+// CHECK:STDOUT:   node6 = IntegerLiteral(int0): node2;
+// CHECK:STDOUT:   node7 = Assign(node4, node6): node2;
+// CHECK:STDOUT:   node8 = VarStorage(): node2;
+// CHECK:STDOUT:   node9 = BindName(str1, node8): node2;
+// CHECK:STDOUT:   node10 = Assign(node8, node5): node2;
+// CHECK:STDOUT: },
 // CHECK:STDOUT: node_blocks = {
 // CHECK:STDOUT:   block0 = {
-// CHECK:STDOUT:     node0 = VarStorage(): node_xref2;
-// CHECK:STDOUT:     node1 = BindName(str0, node0): node_xref2;
-// CHECK:STDOUT:     node2 = IntegerLiteral(int0): node_xref2;
-// CHECK:STDOUT:     node3 = Assign(node0, node2): node_xref2;
-// CHECK:STDOUT:     node4 = VarStorage(): node_xref2;
-// CHECK:STDOUT:     node5 = BindName(str1, node4): node_xref2;
-// CHECK:STDOUT:     node6 = Assign(node4, node_xref4): node_xref2;
+// CHECK:STDOUT:     node4;
+// CHECK:STDOUT:     node5;
+// CHECK:STDOUT:     node6;
+// CHECK:STDOUT:     node7;
+// CHECK:STDOUT:     node8;
+// CHECK:STDOUT:     node9;
+// CHECK:STDOUT:     node10;
 // CHECK:STDOUT:   },
 // CHECK:STDOUT: }
 

+ 27 - 20
toolchain/semantics/testdata/var/global_lookup_in_scope.carbon

@@ -4,16 +4,7 @@
 //
 // AUTOUPDATE
 // RUN: %{carbon-run-semantics}
-// CHECK:STDOUT: cross_reference_irs.size == 2,
-// CHECK:STDOUT: cross_references = {
-// CHECK:STDOUT:   node_xref0 = xref(ir0, block0, node0);
-// CHECK:STDOUT:   node_xref1 = xref(ir0, block0, node1);
-// CHECK:STDOUT:   node_xref2 = xref(ir0, block0, node2);
-// CHECK:STDOUT:   node_xref3 = xref(ir0, block0, node3);
-// CHECK:STDOUT:   node_xref4 = xref(ir1, block0, node1);
-// CHECK:STDOUT:   node_xref5 = xref(ir1, block0, node5);
-// CHECK:STDOUT:   node_xref6 = xref(ir1, block1, node1);
-// CHECK:STDOUT: },
+// CHECK:STDOUT: cross_reference_irs.size == 1,
 // CHECK:STDOUT: integer_literals = {
 // CHECK:STDOUT:   int0 = 0;
 // CHECK:STDOUT: },
@@ -22,20 +13,36 @@
 // CHECK:STDOUT:   str1 = "Main";
 // CHECK:STDOUT:   str2 = "y";
 // CHECK:STDOUT: },
+// CHECK:STDOUT: nodes = {
+// CHECK:STDOUT:   node0 = CrossReference(ir0, block0): node0;
+// CHECK:STDOUT:   node1 = CrossReference(ir0, block1): node1;
+// CHECK:STDOUT:   node2 = CrossReference(ir0, block2): node0;
+// CHECK:STDOUT:   node3 = CrossReference(ir0, block3): node0;
+// CHECK:STDOUT:   node4 = VarStorage(): node2;
+// CHECK:STDOUT:   node5 = BindName(str0, node4): node2;
+// CHECK:STDOUT:   node6 = IntegerLiteral(int0): node2;
+// CHECK:STDOUT:   node7 = Assign(node4, node6): node2;
+// CHECK:STDOUT:   node8 = FunctionDeclaration();
+// CHECK:STDOUT:   node9 = BindName(str1, node8);
+// CHECK:STDOUT:   node10 = FunctionDefinition(node8, block1);
+// CHECK:STDOUT:   node11 = VarStorage(): node2;
+// CHECK:STDOUT:   node12 = BindName(str2, node11): node2;
+// CHECK:STDOUT:   node13 = Assign(node11, node5): node2;
+// CHECK:STDOUT: },
 // CHECK:STDOUT: node_blocks = {
 // CHECK:STDOUT:   block0 = {
-// CHECK:STDOUT:     node0 = VarStorage(): node_xref2;
-// CHECK:STDOUT:     node1 = BindName(str0, node0): node_xref2;
-// CHECK:STDOUT:     node2 = IntegerLiteral(int0): node_xref2;
-// CHECK:STDOUT:     node3 = Assign(node0, node2): node_xref2;
-// CHECK:STDOUT:     node4 = FunctionDeclaration();
-// CHECK:STDOUT:     node5 = BindName(str1, node4);
-// CHECK:STDOUT:     node6 = FunctionDefinition(node4, block1);
+// CHECK:STDOUT:     node4;
+// CHECK:STDOUT:     node5;
+// CHECK:STDOUT:     node6;
+// CHECK:STDOUT:     node7;
+// CHECK:STDOUT:     node8;
+// CHECK:STDOUT:     node9;
+// CHECK:STDOUT:     node10;
 // CHECK:STDOUT:   },
 // CHECK:STDOUT:   block1 = {
-// CHECK:STDOUT:     node0 = VarStorage(): node_xref2;
-// CHECK:STDOUT:     node1 = BindName(str2, node0): node_xref2;
-// CHECK:STDOUT:     node2 = Assign(node0, node_xref4): node_xref2;
+// CHECK:STDOUT:     node11;
+// CHECK:STDOUT:     node12;
+// CHECK:STDOUT:     node13;
 // CHECK:STDOUT:   },
 // CHECK:STDOUT: }
 

+ 21 - 16
toolchain/semantics/testdata/var/lookup.carbon

@@ -4,15 +4,7 @@
 //
 // AUTOUPDATE
 // RUN: %{carbon-run-semantics}
-// CHECK:STDOUT: cross_reference_irs.size == 2,
-// CHECK:STDOUT: cross_references = {
-// CHECK:STDOUT:   node_xref0 = xref(ir0, block0, node0);
-// CHECK:STDOUT:   node_xref1 = xref(ir0, block0, node1);
-// CHECK:STDOUT:   node_xref2 = xref(ir0, block0, node2);
-// CHECK:STDOUT:   node_xref3 = xref(ir0, block0, node3);
-// CHECK:STDOUT:   node_xref4 = xref(ir1, block0, node1);
-// CHECK:STDOUT:   node_xref5 = xref(ir1, block1, node1);
-// CHECK:STDOUT: },
+// CHECK:STDOUT: cross_reference_irs.size == 1,
 // CHECK:STDOUT: integer_literals = {
 // CHECK:STDOUT:   int0 = 0;
 // CHECK:STDOUT: },
@@ -20,17 +12,30 @@
 // CHECK:STDOUT:   str0 = "Main";
 // CHECK:STDOUT:   str1 = "x";
 // CHECK:STDOUT: },
+// CHECK:STDOUT: nodes = {
+// CHECK:STDOUT:   node0 = CrossReference(ir0, block0): node0;
+// CHECK:STDOUT:   node1 = CrossReference(ir0, block1): node1;
+// CHECK:STDOUT:   node2 = CrossReference(ir0, block2): node0;
+// CHECK:STDOUT:   node3 = CrossReference(ir0, block3): node0;
+// CHECK:STDOUT:   node4 = FunctionDeclaration();
+// CHECK:STDOUT:   node5 = BindName(str0, node4);
+// CHECK:STDOUT:   node6 = FunctionDefinition(node4, block1);
+// CHECK:STDOUT:   node7 = VarStorage(): node2;
+// CHECK:STDOUT:   node8 = BindName(str1, node7): node2;
+// CHECK:STDOUT:   node9 = IntegerLiteral(int0): node2;
+// CHECK:STDOUT:   node10 = Assign(node7, node9): node2;
+// CHECK:STDOUT: },
 // CHECK:STDOUT: node_blocks = {
 // CHECK:STDOUT:   block0 = {
-// CHECK:STDOUT:     node0 = FunctionDeclaration();
-// CHECK:STDOUT:     node1 = BindName(str0, node0);
-// CHECK:STDOUT:     node2 = FunctionDefinition(node0, block1);
+// CHECK:STDOUT:     node4;
+// CHECK:STDOUT:     node5;
+// CHECK:STDOUT:     node6;
 // CHECK:STDOUT:   },
 // CHECK:STDOUT:   block1 = {
-// CHECK:STDOUT:     node0 = VarStorage(): node_xref2;
-// CHECK:STDOUT:     node1 = BindName(str1, node0): node_xref2;
-// CHECK:STDOUT:     node2 = IntegerLiteral(int0): node_xref2;
-// CHECK:STDOUT:     node3 = Assign(node0, node2): node_xref2;
+// CHECK:STDOUT:     node7;
+// CHECK:STDOUT:     node8;
+// CHECK:STDOUT:     node9;
+// CHECK:STDOUT:     node10;
 // CHECK:STDOUT:   },
 // CHECK:STDOUT: }
 

+ 19 - 15
toolchain/semantics/testdata/var/todo_bad_init_with_self.carbon

@@ -4,31 +4,35 @@
 //
 // AUTOUPDATE
 // RUN: %{carbon-run-semantics}
-// CHECK:STDOUT: cross_reference_irs.size == 2,
-// CHECK:STDOUT: cross_references = {
-// CHECK:STDOUT:   node_xref0 = xref(ir0, block0, node0);
-// CHECK:STDOUT:   node_xref1 = xref(ir0, block0, node1);
-// CHECK:STDOUT:   node_xref2 = xref(ir0, block0, node2);
-// CHECK:STDOUT:   node_xref3 = xref(ir0, block0, node3);
-// CHECK:STDOUT:   node_xref4 = xref(ir1, block0, node1);
-// CHECK:STDOUT:   node_xref5 = xref(ir1, block1, node1);
-// CHECK:STDOUT: },
+// CHECK:STDOUT: cross_reference_irs.size == 1,
 // CHECK:STDOUT: integer_literals = {
 // CHECK:STDOUT: },
 // CHECK:STDOUT: strings = {
 // CHECK:STDOUT:   str0 = "Main";
 // CHECK:STDOUT:   str1 = "x";
 // CHECK:STDOUT: },
+// CHECK:STDOUT: nodes = {
+// CHECK:STDOUT:   node0 = CrossReference(ir0, block0): node0;
+// CHECK:STDOUT:   node1 = CrossReference(ir0, block1): node1;
+// CHECK:STDOUT:   node2 = CrossReference(ir0, block2): node0;
+// CHECK:STDOUT:   node3 = CrossReference(ir0, block3): node0;
+// CHECK:STDOUT:   node4 = FunctionDeclaration();
+// CHECK:STDOUT:   node5 = BindName(str0, node4);
+// CHECK:STDOUT:   node6 = FunctionDefinition(node4, block1);
+// CHECK:STDOUT:   node7 = VarStorage(): node2;
+// CHECK:STDOUT:   node8 = BindName(str1, node7): node2;
+// CHECK:STDOUT:   node9 = Assign(node7, node8): node2;
+// CHECK:STDOUT: },
 // CHECK:STDOUT: node_blocks = {
 // CHECK:STDOUT:   block0 = {
-// CHECK:STDOUT:     node0 = FunctionDeclaration();
-// CHECK:STDOUT:     node1 = BindName(str0, node0);
-// CHECK:STDOUT:     node2 = FunctionDefinition(node0, block1);
+// CHECK:STDOUT:     node4;
+// CHECK:STDOUT:     node5;
+// CHECK:STDOUT:     node6;
 // CHECK:STDOUT:   },
 // CHECK:STDOUT:   block1 = {
-// CHECK:STDOUT:     node0 = VarStorage(): node_xref2;
-// CHECK:STDOUT:     node1 = BindName(str1, node0): node_xref2;
-// CHECK:STDOUT:     node2 = Assign(node0, node_xref5): node_xref2;
+// CHECK:STDOUT:     node7;
+// CHECK:STDOUT:     node8;
+// CHECK:STDOUT:     node9;
 // CHECK:STDOUT:   },
 // CHECK:STDOUT: }
 

+ 0 - 41
toolchain/semantics/testdata/var/todo_bad_lookup_outside_scope.carbon

@@ -1,41 +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
-//
-// AUTOUPDATE
-// RUN: %{carbon-run-semantics}
-// CHECK:STDOUT: cross_reference_irs.size == 2,
-// CHECK:STDOUT: cross_references = {
-// CHECK:STDOUT:   node_xref0 = xref(ir0, block0, node0);
-// CHECK:STDOUT:   node_xref1 = xref(ir0, block0, node1);
-// CHECK:STDOUT:   node_xref2 = xref(ir0, block0, node2);
-// CHECK:STDOUT:   node_xref3 = xref(ir0, block0, node3);
-// CHECK:STDOUT:   node_xref4 = xref(ir1, block0, node1);
-// CHECK:STDOUT:   node_xref5 = xref(ir1, block1, node1);
-// CHECK:STDOUT: },
-// CHECK:STDOUT: integer_literals = {
-// CHECK:STDOUT: },
-// CHECK:STDOUT: strings = {
-// CHECK:STDOUT:   str0 = "Main";
-// CHECK:STDOUT:   str1 = "x";
-// CHECK:STDOUT: },
-// CHECK:STDOUT: node_blocks = {
-// CHECK:STDOUT:   block0 = {
-// CHECK:STDOUT:     node0 = FunctionDeclaration();
-// CHECK:STDOUT:     node1 = BindName(str0, node0);
-// CHECK:STDOUT:     node2 = FunctionDefinition(node0, block1);
-// CHECK:STDOUT:   },
-// CHECK:STDOUT:   block1 = {
-// CHECK:STDOUT:     node0 = VarStorage(): node_xref2;
-// CHECK:STDOUT:     node1 = BindName(str1, node0): node_xref2;
-// CHECK:STDOUT:   },
-// CHECK:STDOUT: }
-
-fn Main() {
-  var x: i32;
-}
-
-// TODO: This is a crash because the type of `x` is incorrect. That needs to be
-// fixed, but it crashes due to cross-reference handling which I intend to
-// rewrite, so leaving this as a TODO.
-// var y: i32 = x;