[spirv-reader] Rename Edge::kToMerge to kIfBreak

Change-Id: I187b88cb68a04e46a16b6391013bdaf148191cc2
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/21221
Reviewed-by: dan sinclair <dsinclair@google.com>
diff --git a/src/reader/spirv/construct.h b/src/reader/spirv/construct.h
index 55ea5fc..2437e4e 100644
--- a/src/reader/spirv/construct.h
+++ b/src/reader/spirv/construct.h
@@ -25,21 +25,61 @@
 namespace reader {
 namespace spirv {
 
-/// A structured construct, consisting of a set of basic blocks.
+/// A structured control flow construct, consisting of a set of basic blocks.
 /// A construct is a span of blocks in the computed block order,
 /// and will appear contiguously in the WGSL source.
+///
+/// SPIR-V (2.11 Structured Control Flow) defines:
+///   - loop construct
+///   - continue construct
+///   - selection construct
+/// We also define a "function construct" consisting of all the basic blocks in
+/// the function.
+///
+/// The first block in a construct (by computed block order) is called a
+/// "header". For the constructs defined by SPIR-V, the header block is the
+/// basic block containing the merge instruction.  The header for the function
+/// construct is the entry block of the function.
+///
+/// Given two constructs A and B, we say "A encloses B" if B is a subset of A,
+/// i.e. if every basic block in B is also in A.  Note that a construct encloses
+/// itself.
+///
+/// In a valid SPIR-V module, constructs will nest, meaning given
+/// constructs A and B, either A encloses B, or B encloses A, or
+/// or they are disjoint (have no basic blocks in commont).
+///
+/// A loop in a high level language translates into either:
+//
+///  - a single-block loop, where the loop header branches back to itself.
+///     In this case this single-block loop consists only of the *continue
+///     construct*.  There is no "loop construct" for this case.
+//
+///  - a multi-block loop, where the loop back-edge is different from the loop
+///     header.
+///     This case has both a non-empty loop construct containing at least the
+///     loop header, and a non-empty continue construct, containing at least the
+///     back-edge block.
+///
+/// We care about two kinds of selection constructs:
+///
+///  - if-selection: where the header block ends in OpBranchConditional
+///
+///  - switch-selection: where the header block ends in OpSwitch
+///
 struct Construct {
   /// Enumeration for the kinds of structured constructs.
   enum Kind {
     /// The whole function.
     kFunction,
-    /// A SPIR-V selection construct, header ending in OpBrancConditional
+    /// A SPIR-V selection construct, header basic block ending in
+    /// OpBrancConditional.
     kIfSelection,
-    /// A SPIR-V selection construct, header ending in OpSwitch
+    /// A SPIR-V selection construct, header basic block ending in OpSwitch.
     kSwitchSelection,
-    /// A SPIR-V loop construct
+    /// A SPIR-V loop construct.
     kLoop,
-    /// A SPIR-V continue construct
+    /// A SPIR-V continue construct.
     kContinue,
   };
 
@@ -65,20 +105,20 @@
     return begin_pos <= pos && pos < end_pos;
   }
 
-  /// The nearest enclosing construct (other than itself), or nullptr if
+  /// The nearest enclosing construct other than itself, or nullptr if
   /// this construct represents the entire function.
   const Construct* const parent = nullptr;
-  /// The nearest enclosing loop construct, if one exists. A construct
-  /// encloses itself.
+  /// The nearest enclosing loop construct, if one exists.  Points to |this|
+  /// when this is a loop construct.
   const Construct* const enclosing_loop = nullptr;
-  /// The nearest enclosing continue construct, if one exists. A construct
-  /// encloses itself.
+  /// The nearest enclosing continue construct, if one exists.  Points to
+  /// |this| when this is a contnue construct.
   const Construct* const enclosing_continue = nullptr;
   /// The nearest enclosing loop construct or continue construct or
   /// switch-selection construct, if one exists. The signficance is
   /// that a high level language "break" will branch to the merge block
-  /// of such an enclosing construct.
-  /// A construct encloses itself.
+  /// of such an enclosing construct.  Points to |this| when this is
+  /// a loop construct, a continue construct, or a switch-selection construct.
   const Construct* const enclosing_loop_or_continue_or_switch = nullptr;
 
   /// Control flow nesting depth. The entry block is at nesting depth 0.
diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc
index 2176aae..b3756b6 100644
--- a/src/reader/spirv/function.cc
+++ b/src/reader/spirv/function.cc
@@ -1090,7 +1090,7 @@
           if (dest == header_info.merge_for_header) {
             // Branch to construct's merge block.  The loop break and
             // switch break cases have already been covered.
-            edge_kind = EdgeKind::kToMerge;
+            edge_kind = EdgeKind::kIfBreak;
           }
         }
 
diff --git a/src/reader/spirv/function.h b/src/reader/spirv/function.h
index 51c32c5..00a8641 100644
--- a/src/reader/spirv/function.h
+++ b/src/reader/spirv/function.h
@@ -58,9 +58,7 @@
   // construct, but which is neither a kSwitchBreak or a kLoopBreak.
   // This can only occur for an "if" selection, i.e. where the selection
   // header ends in OpBranchConditional.
-  // TODO(dneto): Rename this to kIfBreak after we correctly classify edges
-  // as kSwitchBreak.
-  kToMerge,
+  kIfBreak,
   // An edge from one switch case to the next sibling switch case.
   kCaseFallThrough,
   // None of the above. By structured control flow rules, there can be at most
diff --git a/src/reader/spirv/function_cfg_test.cc b/src/reader/spirv/function_cfg_test.cc
index 2db7687..8fe36fe 100644
--- a/src/reader/spirv/function_cfg_test.cc
+++ b/src/reader/spirv/function_cfg_test.cc
@@ -4550,7 +4550,7 @@
   EXPECT_EQ(bi->succ_edge[99], EdgeKind::kLoopBreak);
 }
 
-TEST_F(SpvParserTest, ClassifyCFGEdges_ToMerge_FromIfHeader) {
+TEST_F(SpvParserTest, ClassifyCFGEdges_IfBreak_FromIfHeader) {
   auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
@@ -4571,11 +4571,11 @@
 
   auto* bi = fe.GetBlockInfo(20);
   ASSERT_NE(bi, nullptr);
-  EXPECT_EQ(bi->succ_edge.count(99), 1u);
-  EXPECT_EQ(bi->succ_edge[99], EdgeKind::kToMerge);
+  EXPECT_EQ(bi->succ_edge.count(99), 1);
+  EXPECT_EQ(bi->succ_edge[99], EdgeKind::kIfBreak);
 }
 
-TEST_F(SpvParserTest, ClassifyCFGEdges_ToMerge_FromIfThenElse) {
+TEST_F(SpvParserTest, ClassifyCFGEdges_IfBreak_FromIfThenElse) {
   auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
@@ -4600,14 +4600,14 @@
   // Then clause
   auto* bi20 = fe.GetBlockInfo(20);
   ASSERT_NE(bi20, nullptr);
-  EXPECT_EQ(bi20->succ_edge.count(99), 1u);
-  EXPECT_EQ(bi20->succ_edge[99], EdgeKind::kToMerge);
+  EXPECT_EQ(bi20->succ_edge.count(99), 1);
+  EXPECT_EQ(bi20->succ_edge[99], EdgeKind::kIfBreak);
 
   // Else clause
   auto* bi50 = fe.GetBlockInfo(50);
   ASSERT_NE(bi50, nullptr);
-  EXPECT_EQ(bi50->succ_edge.count(99), 1u);
-  EXPECT_EQ(bi50->succ_edge[99], EdgeKind::kToMerge);
+  EXPECT_EQ(bi50->succ_edge.count(99), 1);
+  EXPECT_EQ(bi50->succ_edge[99], EdgeKind::kIfBreak);
 }
 
 TEST_F(SpvParserTest, ClassifyCFGEdges_SwitchBreak_FromSwitchCaseDirect) {
@@ -6011,8 +6011,8 @@
 
   auto* bi60 = fe.GetBlockInfo(60);
   ASSERT_NE(bi60, nullptr);
-  EXPECT_EQ(bi60->succ_edge.count(99), 1u);
-  EXPECT_EQ(bi60->succ_edge[99], EdgeKind::kToMerge);
+  EXPECT_EQ(bi60->succ_edge.count(99), 1);
+  EXPECT_EQ(bi60->succ_edge[99], EdgeKind::kIfBreak);
 }
 
 TEST_F(SpvParserTest, ClassifyCFGEdges_Pathological_Forward_Regardless) {
@@ -6042,8 +6042,8 @@
 
   auto* bi20 = fe.GetBlockInfo(20);
   ASSERT_NE(bi20, nullptr);
-  EXPECT_EQ(bi20->succ_edge.count(99), 1u);
-  EXPECT_EQ(bi20->succ_edge[99], EdgeKind::kToMerge);
+  EXPECT_EQ(bi20->succ_edge.count(99), 1);
+  EXPECT_EQ(bi20->succ_edge[99], EdgeKind::kIfBreak);
 }
 
 }  // namespace