Require an OpSelectionMerge before an OpSwitch (#4154)

Fixes #4153

* OpSwitch is required to be preceeded by OpSelectionMerge
* Update newly invalid tests
diff --git a/source/val/validate_cfg.cpp b/source/val/validate_cfg.cpp
index a5f6e6a..36f632a 100644
--- a/source/val/validate_cfg.cpp
+++ b/source/val/validate_cfg.cpp
@@ -654,18 +654,15 @@
                << "Selection must be structured";
       }
     } else if (terminator->opcode() == SpvOpSwitch) {
-      uint32_t count = 0;
-      // Mark the targets as seen now, but only error out if this block was
-      // missing a merge instruction and there were multiple unseen labels.
+      if (!merge) {
+        return _.diag(SPV_ERROR_INVALID_CFG, terminator)
+               << "OpSwitch must be preceeded by an OpSelectionMerge "
+                  "instruction";
+      }
+      // Mark the targets as seen.
       for (uint32_t i = 1; i < terminator->operands().size(); i += 2) {
         const auto target = terminator->GetOperandAs<uint32_t>(i);
-        if (seen.insert(target).second) {
-          count++;
-        }
-      }
-      if (!merge && count > 1) {
-        return _.diag(SPV_ERROR_INVALID_CFG, terminator)
-               << "Selection must be structured";
+        seen.insert(target);
       }
     }
   }
diff --git a/test/opt/aggressive_dead_code_elim_test.cpp b/test/opt/aggressive_dead_code_elim_test.cpp
index 972e6e5..5b4291d 100644
--- a/test/opt/aggressive_dead_code_elim_test.cpp
+++ b/test/opt/aggressive_dead_code_elim_test.cpp
@@ -3948,12 +3948,15 @@
 OpLoopMerge %14 %15 None
 OpBranch %16
 %16 = OpLabel
-OpSwitch %13 %14 0 %17 1 %15
+OpSelectionMerge %18 None
+OpSwitch %13 %18 0 %17 1 %15
 %17 = OpLabel
 OpStore %3 %uint_1
 OpBranch %15
 %15 = OpLabel
 OpBranch %12
+%18 = OpLabel
+OpBranch %14
 %14 = OpLabel
 OpStore %3 %uint_0
 OpReturn
diff --git a/test/opt/block_merge_test.cpp b/test/opt/block_merge_test.cpp
index 7381908..140a5c0 100644
--- a/test/opt/block_merge_test.cpp
+++ b/test/opt/block_merge_test.cpp
@@ -744,6 +744,7 @@
 ; CHECK: OpLoopMerge [[merge:%\w+]] [[cont:%\w+]] None
 ; CHECK-NEXT: OpBranch [[ret:%\w+]]
 ; CHECK: [[ret:%\w+]] = OpLabel
+; CHECK-NEXT: OpSelectionMerge
 ; CHECK-NEXT: OpSwitch
 ; CHECK-DAG: [[cont]] = OpLabel
 ; CHECK-DAG: [[merge]] = OpLabel
@@ -763,6 +764,7 @@
 OpLoopMerge %3 %4 None
 OpBranch %5
 %5 = OpLabel
+OpSelectionMerge %6 None
 OpSwitch %int_0 %6
 %6 = OpLabel
 OpReturn
diff --git a/test/opt/dead_branch_elim_test.cpp b/test/opt/dead_branch_elim_test.cpp
index 41ce31d..f89befb 100644
--- a/test/opt/dead_branch_elim_test.cpp
+++ b/test/opt/dead_branch_elim_test.cpp
@@ -2722,6 +2722,7 @@
 ; CHECK: [[bb1]] = OpLabel
 ; CHECK-NEXT: OpBranch [[bb2:%\w+]]
 ; CHECK: [[bb2]] = OpLabel
+; CHECK-NEXT: OpSelectionMerge
 ; CHECK-NEXT: OpSwitch {{%\w+}} [[bb3:%\w+]] 0 [[loop_merge]] 1 [[bb3:%\w+]]
 ; CHECK: [[bb3]] = OpLabel
 ; CHECK-NEXT: OpBranch [[sel_merge:%\w+]]
@@ -2739,6 +2740,7 @@
 OpSelectionMerge %sel_merge None
 OpBranchConditional %true %bb2 %bb4
 %bb2 = OpLabel
+OpSelectionMerge %bb3 None
 OpSwitch %undef_int %bb3 0 %loop_merge 1 %bb3
 %bb3 = OpLabel
 OpBranch %sel_merge
@@ -2782,6 +2784,7 @@
 ; CHECK: [[bb1]] = OpLabel
 ; CHECK-NEXT: OpBranch [[bb2:%\w+]]
 ; CHECK: [[bb2]] = OpLabel
+; CHECK-NEXT: OpSelectionMerge
 ; CHECK-NEXT: OpSwitch {{%\w+}} [[bb3:%\w+]] 0 [[loop_cont]] 1 [[bb3:%\w+]]
 ; CHECK: [[bb3]] = OpLabel
 ; CHECK-NEXT: OpBranch [[sel_merge:%\w+]]
@@ -2799,6 +2802,7 @@
 OpSelectionMerge %sel_merge None
 OpBranchConditional %true %bb2 %bb4
 %bb2 = OpLabel
+OpSelectionMerge %bb3 None
 OpSwitch %undef_int %bb3 0 %cont 1 %bb3
 %bb3 = OpLabel
 OpBranch %sel_merge
diff --git a/test/val/val_cfg_test.cpp b/test/val/val_cfg_test.cpp
index 9698fb1..9715a5a 100644
--- a/test/val/val_cfg_test.cpp
+++ b/test/val/val_cfg_test.cpp
@@ -3520,7 +3520,10 @@
 
   CompileSuccessfully(text);
   EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
-  EXPECT_THAT(getDiagnosticString(), HasSubstr("Selection must be structured"));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr(
+          "OpSwitch must be preceeded by an OpSelectionMerge instruction"));
 }
 
 TEST_F(ValidateCFG, MissingMergeSwitchBad2) {
@@ -3544,7 +3547,10 @@
 
   CompileSuccessfully(text);
   EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
-  EXPECT_THAT(getDiagnosticString(), HasSubstr("Selection must be structured"));
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr(
+          "OpSwitch must be preceeded by an OpSelectionMerge instruction"));
 }
 
 TEST_F(ValidateCFG, MissingMergeOneBranchToMergeGood) {
@@ -3594,7 +3600,7 @@
   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
 }
 
-TEST_F(ValidateCFG, MissingMergeOneTargetSwitchGood) {
+TEST_F(ValidateCFG, MissingMergeOneTargetSwitchBad) {
   const std::string text = R"(
 OpCapability Shader
 OpCapability Linkage
@@ -3612,10 +3618,14 @@
 )";
 
   CompileSuccessfully(text);
-  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+  EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr(
+          "OpSwitch must be preceeded by an OpSelectionMerge instruction"));
 }
 
-TEST_F(ValidateCFG, MissingMergeOneUnseenTargetSwitchGood) {
+TEST_F(ValidateCFG, MissingMergeOneUnseenTargetSwitchBad) {
   const std::string text = R"(
 OpCapability Shader
 OpCapability Linkage
@@ -3640,7 +3650,11 @@
 )";
 
   CompileSuccessfully(text);
-  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+  EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
+  EXPECT_THAT(
+      getDiagnosticString(),
+      HasSubstr(
+          "OpSwitch must be preceeded by an OpSelectionMerge instruction"));
 }
 
 TEST_F(ValidateCFG, MissingMergeLoopBreakGood) {
diff --git a/test/val/val_limits_test.cpp b/test/val/val_limits_test.cpp
index 0ef61e2..8fb80a4 100644
--- a/test/val/val_limits_test.cpp
+++ b/test/val/val_limits_test.cpp
@@ -212,6 +212,7 @@
 %5 = OpFunction %1 None %2
 %7 = OpLabel
 %8 = OpIAdd %3 %4 %4
+     OpSelectionMerge %10 None
      OpSwitch %4 %10)";
 
   // Now add the (literal, label) pairs
@@ -240,6 +241,7 @@
 %5 = OpFunction %1 None %2
 %7 = OpLabel
 %8 = OpIAdd %3 %4 %4
+     OpSelectionMerge %10 None
      OpSwitch %4 %10)";
 
   // Now add the (literal, label) pairs
@@ -271,6 +273,7 @@
 %5 = OpFunction %1 None %2
 %7 = OpLabel
 %8 = OpIAdd %3 %4 %4
+     OpSelectionMerge %10 None
      OpSwitch %4 %10)";
 
   // Now add the (literal, label) pairs
@@ -301,6 +304,7 @@
 %5 = OpFunction %1 None %2
 %7 = OpLabel
 %8 = OpIAdd %3 %4 %4
+     OpSelectionMerge %10 None
      OpSwitch %4 %10)";
 
   // Now add the (literal, label) pairs