Handle extract with no index in VDCE. (#2305)

It is legal, but not generated by any SPIR-V producer: an OpCompositeExtract
with no indexes.  This is essentially just a copy of the object, so we
treat them that way.  We simply propagate the live variables of the
result to the operand.

Fixes https://crbug.com/919181.
diff --git a/source/opt/vector_dce.cpp b/source/opt/vector_dce.cpp
index 314d651..92532e3 100644
--- a/source/opt/vector_dce.cpp
+++ b/source/opt/vector_dce.cpp
@@ -66,7 +66,8 @@
 
     switch (current_inst->opcode()) {
       case SpvOpCompositeExtract:
-        MarkExtractUseAsLive(current_inst, live_components, &work_list);
+        MarkExtractUseAsLive(current_inst, current_item.components,
+                             live_components, &work_list);
         break;
       case SpvOpCompositeInsert:
         MarkInsertUsesAsLive(current_item, live_components, &work_list);
@@ -92,6 +93,7 @@
 }
 
 void VectorDCE::MarkExtractUseAsLive(const Instruction* current_inst,
+                                     const utils::BitVector& live_elements,
                                      LiveComponentMap* live_components,
                                      std::vector<WorkListItem>* work_list) {
   analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr();
@@ -102,7 +104,11 @@
   if (HasVectorOrScalarResult(operand_inst)) {
     WorkListItem new_item;
     new_item.instruction = operand_inst;
-    new_item.components.Set(current_inst->GetSingleWordInOperand(1));
+    if (current_inst->NumInOperands() < 2) {
+      new_item.components = live_elements;
+    } else {
+      new_item.components.Set(current_inst->GetSingleWordInOperand(1));
+    }
     AddItemToWorkListIfNeeded(new_item, live_components, work_list);
   }
 }
diff --git a/source/opt/vector_dce.h b/source/opt/vector_dce.h
index 638b34b..4f039c5 100644
--- a/source/opt/vector_dce.h
+++ b/source/opt/vector_dce.h
@@ -129,6 +129,7 @@
   // live. If anything becomes live they are added to |work_list| and
   // |live_components| is updated accordingly.
   void MarkExtractUseAsLive(const Instruction* current_inst,
+                            const utils::BitVector& live_elements,
                             LiveComponentMap* live_components,
                             std::vector<WorkListItem>* work_list);
 
diff --git a/test/opt/vector_dce_test.cpp b/test/opt/vector_dce_test.cpp
index 40f115c..a978a07 100644
--- a/test/opt/vector_dce_test.cpp
+++ b/test/opt/vector_dce_test.cpp
@@ -1190,6 +1190,42 @@
   SinglePassRunAndMatch<VectorDCE>(text, true);
 }
 
+TEST_F(VectorDCETest, ExtractWithNoIndices) {
+  const std::string text = R"(
+; CHECK: OpLoad %float
+; CHECK: [[ld:%\w+]] = OpLoad %v4float
+; CHECK: [[ex1:%\w+]] = OpCompositeExtract %v4float [[ld]]
+; CHECK: [[ex2:%\w+]] = OpCompositeExtract %float [[ex1]] 1
+; CHECK: OpStore {{%\w+}} [[ex2]]
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %1 "PSMain" %2 %14 %3
+               OpExecutionMode %1 OriginUpperLeft
+       %void = OpTypeVoid
+          %5 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Input_float = OpTypePointer Input %float
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%_ptr_Output_float = OpTypePointer Output %float
+          %2 = OpVariable %_ptr_Input_v4float Input
+          %14 = OpVariable %_ptr_Input_float Input
+          %3 = OpVariable %_ptr_Output_float Output
+          %1 = OpFunction %void None %5
+         %10 = OpLabel
+         %13 = OpLoad %float %14
+         %11 = OpLoad %v4float %2
+         %12 = OpCompositeInsert %v4float %13 %11 0
+         %20 = OpCompositeExtract %v4float %12
+         %21 = OpCompositeExtract %float %20 1
+               OpStore %3 %21
+               OpReturn
+               OpFunctionEnd
+)";
+
+  SinglePassRunAndMatch<VectorDCE>(text, true);
+}
+
 }  // namespace
 }  // namespace opt
 }  // namespace spvtools