val: Fix CullPrimitiveEXT array of bool (#6155)

* val: Fix CullPrimitiveEXT array of bool

* val: Add CullPrimitiveEXT Block case
diff --git a/source/val/validate_builtins.cpp b/source/val/validate_builtins.cpp
index 11d926f..d25ebaf 100644
--- a/source/val/validate_builtins.cpp
+++ b/source/val/validate_builtins.cpp
@@ -590,6 +590,9 @@
   spv_result_t ValidateBool(
       const Decoration& decoration, const Instruction& inst,
       const std::function<spv_result_t(const std::string& message)>& diag);
+  spv_result_t ValidateBlockBoolOrArrayedBool(
+      const Decoration& decoration, const Instruction& inst,
+      const std::function<spv_result_t(const std::string& message)>& diag);
   spv_result_t ValidateI(
       const Decoration& decoration, const Instruction& inst,
       const std::function<spv_result_t(const std::string& message)>& diag);
@@ -820,6 +823,30 @@
   return SPV_SUCCESS;
 }
 
+spv_result_t BuiltInsValidator::ValidateBlockBoolOrArrayedBool(
+    const Decoration& decoration, const Instruction& inst,
+    const std::function<spv_result_t(const std::string& message)>& diag) {
+  uint32_t underlying_type = 0;
+  if (spv_result_t error =
+          GetUnderlyingType(_, decoration, inst, &underlying_type)) {
+    return error;
+  }
+  // Strip the array, if present.
+  if (_.GetIdOpcode(underlying_type) == spv::Op::OpTypeArray) {
+    underlying_type = _.FindDef(underlying_type)->word(2u);
+  } else if (!_.HasDecoration(inst.id(), spv::Decoration::Block)) {
+    // If not in array, and bool is in a struct, must be in a Block struct
+    return diag(GetDefinitionDesc(decoration, inst) +
+                " Scalar boolean must be in a Block.");
+  }
+
+  if (!_.IsBoolScalarType(underlying_type)) {
+    return diag(GetDefinitionDesc(decoration, inst) + " is not a bool scalar.");
+  }
+
+  return SPV_SUCCESS;
+}
+
 spv_result_t BuiltInsValidator::ValidateI(
     const Decoration& decoration, const Instruction& inst,
     const std::function<spv_result_t(const std::string& message)>& diag) {
@@ -4339,7 +4366,7 @@
         }
         break;
       case spv::BuiltIn::CullPrimitiveEXT:
-        if (spv_result_t error = ValidateBool(
+        if (spv_result_t error = ValidateBlockBoolOrArrayedBool(
                 decoration, inst,
                 [this, &inst, &decoration,
                  &vuid](const std::string& message) -> spv_result_t {
@@ -4350,8 +4377,8 @@
                          << _.grammar().lookupOperandName(
                                 SPV_OPERAND_TYPE_BUILT_IN,
                                 (uint32_t)decoration.builtin())
-                         << " variable needs to be a boolean value "
-                            "array."
+                         << " variable needs to be a either a boolean or an "
+                            "array of booleans."
                          << message;
                 })) {
           return error;
diff --git a/test/val/val_builtins_test.cpp b/test/val/val_builtins_test.cpp
index d2a77e2..2032ff2 100644
--- a/test/val/val_builtins_test.cpp
+++ b/test/val/val_builtins_test.cpp
@@ -5255,6 +5255,50 @@
   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_3));
 }
 
+TEST_F(ValidateBuiltIns, VulkanBuiltinCullPrimitiveEXTMissingBlock) {
+  const std::string text = R"(
+      OpCapability MeshShadingEXT
+      OpExtension "SPV_EXT_mesh_shader"
+ %1 = OpExtInstImport "GLSL.std.450"
+      OpMemoryModel Logical GLSL450
+      OpEntryPoint MeshEXT %main "main" %gl_MeshPrimitivesEXT
+      OpExecutionModeId %main LocalSizeId %uint_32 %uint_1 %uint_1
+      OpExecutionMode %main OutputVertices 81
+      OpExecutionMode %main OutputPrimitivesEXT 32
+      OpExecutionMode %main OutputTrianglesEXT
+      OpSource GLSL 450
+      OpSourceExtension "GL_EXT_mesh_shader"
+      OpName %main "main"
+      OpName %gl_MeshPerPrimitiveEXT "gl_MeshPerPrimitiveEXT"
+      OpMemberName %gl_MeshPerPrimitiveEXT 0 "gl_CullPrimitiveEXT"
+      OpName %gl_MeshPrimitivesEXT "gl_MeshPrimitivesEXT"
+      OpMemberDecorate %gl_MeshPerPrimitiveEXT 0 BuiltIn CullPrimitiveEXT
+      OpMemberDecorate %gl_MeshPerPrimitiveEXT 0 PerPrimitiveEXT
+%void = OpTypeVoid
+ %3 = OpTypeFunction %void
+%uint = OpTypeInt 32 0
+%uint_32 = OpConstant %uint 32
+%uint_1 = OpConstant %uint 1
+%int = OpTypeInt 32 1
+%bool = OpTypeBool
+%gl_MeshPerPrimitiveEXT = OpTypeStruct %bool
+%_arr_gl_MeshPerPrimitiveEXT_uint_32 = OpTypeArray %gl_MeshPerPrimitiveEXT %uint_32
+%_ptr_Output__arr_gl_MeshPerPrimitiveEXT_uint_32 = OpTypePointer Output %_arr_gl_MeshPerPrimitiveEXT_uint_32
+%gl_MeshPrimitivesEXT = OpVariable %_ptr_Output__arr_gl_MeshPerPrimitiveEXT_uint_32 Output
+%main = OpFunction %void None %3
+ %5 = OpLabel
+      OpReturn
+      OpFunctionEnd
+)";
+
+  CompileSuccessfully(text, SPV_ENV_VULKAN_1_3);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_3));
+  EXPECT_THAT(getDiagnosticString(),
+              AnyVUID("VUID-CullPrimitiveEXT-CullPrimitiveEXT-07036"));
+  EXPECT_THAT(getDiagnosticString(),
+              AnyVUID("Scalar boolean must be in a Block"));
+}
+
 TEST_F(ValidateBuiltIns, BadVulkanBuiltinCullPrimitiveEXTType) {
   const std::string text = R"(
       OpCapability MeshShadingEXT
@@ -5298,6 +5342,108 @@
               AnyVUID("VUID-CullPrimitiveEXT-CullPrimitiveEXT-07036"));
 }
 
+// from https://github.com/KhronosGroup/SPIRV-Tools/issues/5980
+TEST_F(ValidateBuiltIns, VulkanBuiltinCullPrimitiveArrayOfBool) {
+  const std::string text = R"(
+               OpCapability MeshShadingEXT
+               OpExtension "SPV_EXT_mesh_shader"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint MeshEXT %main "main" %gl_LocalInvocationIndex %gl_Position %4 %5
+               OpExecutionMode %main LocalSize 2 1 1
+               OpExecutionMode %main OutputTrianglesEXT
+               OpExecutionMode %main OutputVertices 2
+               OpExecutionMode %main OutputPrimitivesEXT 2
+               OpDecorate %gl_LocalInvocationIndex BuiltIn LocalInvocationIndex
+               OpDecorate %gl_Position BuiltIn Position
+               OpDecorate %4 BuiltIn PrimitiveTriangleIndicesEXT
+               OpDecorate %5 BuiltIn CullPrimitiveEXT
+               OpDecorate %5 PerPrimitiveEXT
+       %uint = OpTypeInt 32 0
+     %uint_2 = OpConstant %uint 2
+       %bool = OpTypeBool
+      %false = OpConstantFalse %bool
+%_ptr_Input_uint = OpTypePointer Input %uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_arr_v4float_uint_2 = OpTypeArray %v4float %uint_2
+%_ptr_Output__arr_v4float_uint_2 = OpTypePointer Output %_arr_v4float_uint_2
+     %v3uint = OpTypeVector %uint 3
+%_arr_v3uint_uint_2 = OpTypeArray %v3uint %uint_2
+%_ptr_Output__arr_v3uint_uint_2 = OpTypePointer Output %_arr_v3uint_uint_2
+%_arr_bool_uint_2 = OpTypeArray %bool %uint_2
+%_ptr_Output__arr_bool_uint_2 = OpTypePointer Output %_arr_bool_uint_2
+       %void = OpTypeVoid
+         %21 = OpTypeFunction %void
+%_ptr_Output_bool = OpTypePointer Output %bool
+%gl_LocalInvocationIndex = OpVariable %_ptr_Input_uint Input
+%gl_Position = OpVariable %_ptr_Output__arr_v4float_uint_2 Output
+          %4 = OpVariable %_ptr_Output__arr_v3uint_uint_2 Output
+          %5 = OpVariable %_ptr_Output__arr_bool_uint_2 Output
+       %main = OpFunction %void None %21
+         %23 = OpLabel
+         %24 = OpLoad %uint %gl_LocalInvocationIndex
+               OpSetMeshOutputsEXT %uint_2 %uint_2
+         %25 = OpAccessChain %_ptr_Output_bool %5 %24
+               OpStore %25 %false
+               OpReturn
+               OpFunctionEnd
+)";
+
+  CompileSuccessfully(text, SPV_ENV_VULKAN_1_3);
+  EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_3));
+}
+
+TEST_F(ValidateBuiltIns, BadVulkanBuiltinCullPrimitiveArrayOfBool) {
+  const std::string text = R"(
+               OpCapability MeshShadingEXT
+               OpExtension "SPV_EXT_mesh_shader"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint MeshEXT %main "main" %gl_LocalInvocationIndex %gl_Position %4 %5
+               OpExecutionMode %main LocalSize 2 1 1
+               OpExecutionMode %main OutputTrianglesEXT
+               OpExecutionMode %main OutputVertices 2
+               OpExecutionMode %main OutputPrimitivesEXT 2
+               OpDecorate %gl_LocalInvocationIndex BuiltIn LocalInvocationIndex
+               OpDecorate %gl_Position BuiltIn Position
+               OpDecorate %4 BuiltIn PrimitiveTriangleIndicesEXT
+               OpDecorate %5 BuiltIn CullPrimitiveEXT
+               OpDecorate %5 PerPrimitiveEXT
+       %uint = OpTypeInt 32 0
+     %uint_2 = OpConstant %uint 2
+       %bool = OpTypeBool
+      %false = OpConstantFalse %bool
+%_ptr_Input_uint = OpTypePointer Input %uint
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_arr_v4float_uint_2 = OpTypeArray %v4float %uint_2
+%_ptr_Output__arr_v4float_uint_2 = OpTypePointer Output %_arr_v4float_uint_2
+     %v3uint = OpTypeVector %uint 3
+%_arr_v3uint_uint_2 = OpTypeArray %v3uint %uint_2
+%_ptr_Output__arr_v3uint_uint_2 = OpTypePointer Output %_arr_v3uint_uint_2
+%_arr_uint_uint_2 = OpTypeArray %uint %uint_2
+%_ptr_Output__arr_uint_uint_2 = OpTypePointer Output %_arr_uint_uint_2
+       %void = OpTypeVoid
+         %21 = OpTypeFunction %void
+%_ptr_Output_uint = OpTypePointer Output %uint
+%gl_LocalInvocationIndex = OpVariable %_ptr_Input_uint Input
+%gl_Position = OpVariable %_ptr_Output__arr_v4float_uint_2 Output
+          %4 = OpVariable %_ptr_Output__arr_v3uint_uint_2 Output
+          %5 = OpVariable %_ptr_Output__arr_uint_uint_2 Output
+       %main = OpFunction %void None %21
+         %23 = OpLabel
+         %24 = OpLoad %uint %gl_LocalInvocationIndex
+               OpSetMeshOutputsEXT %uint_2 %uint_2
+         %25 = OpAccessChain %_ptr_Output_uint %5 %24
+               OpReturn
+               OpFunctionEnd
+)";
+
+  CompileSuccessfully(text, SPV_ENV_VULKAN_1_3);
+  EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_3));
+  EXPECT_THAT(getDiagnosticString(),
+              AnyVUID("VUID-CullPrimitiveEXT-CullPrimitiveEXT-07036"));
+}
+
 TEST_F(ValidateBuiltIns, BadVulkanBuiltinCullPrimitiveEXTStorageClass) {
   const std::string text = R"(
       OpCapability MeshShadingEXT