Fixes #1338. Handle OpConstantNull in branch/switch conditions

* No longer assume the branch/switch condition must be bool or int
constants (respectively)
* Added a couple unit tests for each case
diff --git a/source/opt/ccp_pass.cpp b/source/opt/ccp_pass.cpp
index a777003..498a668 100644
--- a/source/opt/ccp_pass.cpp
+++ b/source/opt/ccp_pass.cpp
@@ -183,9 +183,15 @@
     uint32_t pred_val_id = it->second;
     const analysis::Constant* c = const_mgr_->FindDeclaredConstant(pred_val_id);
     assert(c && "Expected to find a constant declaration for a known value.");
-    const analysis::BoolConstant* val = c->AsBoolConstant();
-    dest_label = val->value() ? instr->GetSingleWordOperand(1)
-                              : instr->GetSingleWordOperand(2);
+    // Undef values should have returned as varying above.
+    assert(c->AsBoolConstant() || c->AsNullConstant());
+    if (c->AsNullConstant()) {
+      dest_label = instr->GetSingleWordOperand(2u);
+    } else {
+      const analysis::BoolConstant* val = c->AsBoolConstant();
+      dest_label = val->value() ? instr->GetSingleWordOperand(1)
+                                : instr->GetSingleWordOperand(2);
+    }
   } else {
     // For an OpSwitch, extract the value taken by the switch selector and check
     // which of the target literals it matches.  The branch associated with that
@@ -209,12 +215,20 @@
     const analysis::Constant* c =
         const_mgr_->FindDeclaredConstant(select_val_id);
     assert(c && "Expected to find a constant declaration for a known value.");
-    const analysis::IntConstant* val = c->AsIntConstant();
+    // TODO: support 64-bit integer switches.
+    uint32_t constant_cond = 0;
+    if (const analysis::IntConstant* val = c->AsIntConstant()) {
+      constant_cond = val->words()[0];
+    } else {
+      // Undef values should have returned varying above.
+      assert(c->AsNullConstant());
+      constant_cond = 0;
+    }
 
     // Start assuming that the selector will take the default value;
     dest_label = instr->GetSingleWordOperand(1);
     for (uint32_t i = 2; i < instr->NumOperands(); i += 2) {
-      if (val->words()[0] == instr->GetSingleWordOperand(i)) {
+      if (constant_cond == instr->GetSingleWordOperand(i)) {
         dest_label = instr->GetSingleWordOperand(i + 1);
         break;
       }
diff --git a/test/opt/ccp_test.cpp b/test/opt/ccp_test.cpp
index 009dd62..3bc9fb6 100644
--- a/test/opt/ccp_test.cpp
+++ b/test/opt/ccp_test.cpp
@@ -733,6 +733,128 @@
   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
   SinglePassRunToBinary<opt::CCPPass>(text, true);
 }
+
+TEST_F(CCPTest, NullBranchCondition) {
+  const std::string text = R"(
+; CHECK: [[int1:%\w+]] = OpConstant {{%\w+}} 1
+; CHECK: [[int2:%\w+]] = OpConstant {{%\w+}} 2
+; CHECK: OpIAdd {{%\w+}} [[int1]] [[int2]]
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %func "func"
+%void = OpTypeVoid
+%bool = OpTypeBool
+%int = OpTypeInt 32 1
+%null = OpConstantNull %bool
+%int_1 = OpConstant %int 1
+%int_2 = OpConstant %int 2
+%functy = OpTypeFunction %void
+%func = OpFunction %void None %functy
+%1 = OpLabel
+OpSelectionMerge %2 None
+OpBranchConditional %null %2 %3
+%3 = OpLabel
+OpBranch %2
+%2 = OpLabel
+%phi = OpPhi %int %int_1 %1 %int_2 %3
+%add = OpIAdd %int %int_1 %phi
+OpReturn
+OpFunctionEnd
+)";
+
+  SinglePassRunAndMatch<opt::CCPPass>(text, true);
+}
+
+TEST_F(CCPTest, UndefBranchCondition) {
+  const std::string text = R"(
+; CHECK: [[int1:%\w+]] = OpConstant {{%\w+}} 1
+; CHECK: [[phi:%\w+]] = OpPhi
+; CHECK: OpIAdd {{%\w+}} [[int1]] [[phi]]
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %func "func"
+%void = OpTypeVoid
+%bool = OpTypeBool
+%int = OpTypeInt 32 1
+%undef = OpUndef %bool
+%int_1 = OpConstant %int 1
+%int_2 = OpConstant %int 2
+%functy = OpTypeFunction %void
+%func = OpFunction %void None %functy
+%1 = OpLabel
+OpSelectionMerge %2 None
+OpBranchConditional %undef %2 %3
+%3 = OpLabel
+OpBranch %2
+%2 = OpLabel
+%phi = OpPhi %int %int_1 %1 %int_2 %3
+%add = OpIAdd %int %int_1 %phi
+OpReturn
+OpFunctionEnd
+)";
+
+  SinglePassRunAndMatch<opt::CCPPass>(text, true);
+}
+
+TEST_F(CCPTest, NullSwitchCondition) {
+  const std::string text = R"(
+; CHECK: [[int1:%\w+]] = OpConstant {{%\w+}} 1
+; CHECK: [[int2:%\w+]] = OpConstant {{%\w+}} 2
+; CHECK: OpIAdd {{%\w+}} [[int1]] [[int2]]
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %func "func"
+%void = OpTypeVoid
+%int = OpTypeInt 32 1
+%null = OpConstantNull %int
+%int_1 = OpConstant %int 1
+%int_2 = OpConstant %int 2
+%functy = OpTypeFunction %void
+%func = OpFunction %void None %functy
+%1 = OpLabel
+OpSelectionMerge %2 None
+OpSwitch %null %2 0 %3
+%3 = OpLabel
+OpBranch %2
+%2 = OpLabel
+%phi = OpPhi %int %int_1 %1 %int_2 %3
+%add = OpIAdd %int %int_1 %phi
+OpReturn
+OpFunctionEnd
+)";
+
+  SinglePassRunAndMatch<opt::CCPPass>(text, true);
+}
+
+TEST_F(CCPTest, UndefSwitchCondition) {
+  const std::string text = R"(
+; CHECK: [[int1:%\w+]] = OpConstant {{%\w+}} 1
+; CHECK: [[phi:%\w+]] = OpPhi
+; CHECK: OpIAdd {{%\w+}} [[int1]] [[phi]]
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %func "func"
+%void = OpTypeVoid
+%int = OpTypeInt 32 1
+%undef = OpUndef %int
+%int_1 = OpConstant %int 1
+%int_2 = OpConstant %int 2
+%functy = OpTypeFunction %void
+%func = OpFunction %void None %functy
+%1 = OpLabel
+OpSelectionMerge %2 None
+OpSwitch %undef %2 0 %3
+%3 = OpLabel
+OpBranch %2
+%2 = OpLabel
+%phi = OpPhi %int %int_1 %1 %int_2 %3
+%add = OpIAdd %int %int_1 %phi
+OpReturn
+OpFunctionEnd
+)";
+
+  SinglePassRunAndMatch<opt::CCPPass>(text, true);
+}
 #endif
 
 }  // namespace