Store location values sparsely (#3488)

Fixes http://crbug.com/1102149

* Switch from boolean vectors to unordered sets for location storage
diff --git a/source/val/validate_interfaces.cpp b/source/val/validate_interfaces.cpp
index ed8cb9c..833734f 100644
--- a/source/val/validate_interfaces.cpp
+++ b/source/val/validate_interfaces.cpp
@@ -208,8 +208,8 @@
 // 4 * location + component.
 spv_result_t GetLocationsForVariable(
     ValidationState_t& _, const Instruction* entry_point,
-    const Instruction* variable, std::vector<bool>* locations,
-    std::vector<bool>* output_index1_locations) {
+    const Instruction* variable, std::unordered_set<uint32_t>* locations,
+    std::unordered_set<uint32_t>* output_index1_locations) {
   const bool is_fragment = entry_point->GetOperandAs<SpvExecutionModel>(0) ==
                            SpvExecutionModelFragment;
   const bool is_output =
@@ -356,17 +356,13 @@
       auto locs = locations;
       if (has_index && index == 1) locs = output_index1_locations;
 
-      if (end > locs->size()) {
-        locs->resize(end, false);
-      }
       for (uint32_t i = start; i < end; ++i) {
-        if (locs->at(i)) {
+        if (!locs->insert(i).second) {
           return _.diag(SPV_ERROR_INVALID_DATA, entry_point)
                  << "Entry-point has conflicting " << storage_class
                  << " location assignment at location " << i / 4
                  << ", component " << i % 4;
         }
-        (*locs)[i] = true;
       }
     }
   } else {
@@ -425,17 +421,13 @@
         start += component;
         end = location * 4 + component + num_components;
       }
-      if (end > locations->size()) {
-        locations->resize(end, false);
-      }
       for (uint32_t l = start; l < end; ++l) {
-        if (locations->at(l)) {
+        if (!locations->insert(l).second) {
           return _.diag(SPV_ERROR_INVALID_DATA, entry_point)
                  << "Entry-point has conflicting " << storage_class
                  << " location assignment at location " << l / 4
                  << ", component " << l % 4;
         }
-        (*locations)[l] = true;
       }
     }
   }
@@ -445,10 +437,10 @@
 
 spv_result_t ValidateLocations(ValidationState_t& _,
                                const Instruction* entry_point) {
-  // Reserve space for 16 locations with 4 components each.
-  std::vector<bool> input_locations(16 * 4, false);
-  std::vector<bool> output_locations_index0(16 * 4, false);
-  std::vector<bool> output_locations_index1(16 * 4, false);
+  // Locations are stored as a combined location and component values.
+  std::unordered_set<uint32_t> input_locations;
+  std::unordered_set<uint32_t> output_locations_index0;
+  std::unordered_set<uint32_t> output_locations_index1;
   for (uint32_t i = 3; i < entry_point->operands().size(); ++i) {
     auto interface_id = entry_point->GetOperandAs<uint32_t>(i);
     auto interface_var = _.FindDef(interface_id);
diff --git a/test/val/val_interfaces_test.cpp b/test/val/val_interfaces_test.cpp
index c274fec..f2fb45a 100644
--- a/test/val/val_interfaces_test.cpp
+++ b/test/val/val_interfaces_test.cpp
@@ -1356,6 +1356,29 @@
                         "assignment at location 1, component 1"));
 }
 
+TEST_F(ValidateInterfacesTest, VulkanLocationsLargeLocation) {
+  const std::string text = R"(
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "????????" %17
+               OpExecutionMode %4 OriginUpperLeft
+               OpDecorate %17 Location 4227868160
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %v3float = OpTypeVector %float 3
+%_ptr_Input_v3float = OpTypePointer Input %v3float
+         %17 = OpVariable %_ptr_Input_v3float Input
+          %4 = OpFunction %void None %3
+          %5 = OpLabel
+               OpUnreachable
+               OpFunctionEnd
+)";
+
+  CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+}
+
 }  // namespace
 }  // namespace val
 }  // namespace spvtools