Revert array location validation (#6187)
* Revert "Fix calculation of locations for matrices (#6062)"
This reverts commit ada1771a9f7a125573aa94fe551fdc44b45769bd.
* Revert "Update location/component conflict validation (#5993)"
This reverts commit ba1359d203e544bd458373ba249a47c44e97b071.
diff --git a/source/val/validate_interfaces.cpp b/source/val/validate_interfaces.cpp
index fcb5e32..b80c7d8 100644
--- a/source/val/validate_interfaces.cpp
+++ b/source/val/validate_interfaces.cpp
@@ -166,20 +166,17 @@
}
break;
case spv::Op::OpTypeMatrix:
- // Matrices consume locations equivalent to arrays.
- if (auto error = NumConsumedLocations(
- _, _.FindDef(type->GetOperandAs<uint32_t>(1)), num_locations)) {
- return error;
- }
+ // Matrices consume locations equal to the underlying vector type for
+ // each column.
+ NumConsumedLocations(_, _.FindDef(type->GetOperandAs<uint32_t>(1)),
+ num_locations);
*num_locations *= type->GetOperandAs<uint32_t>(2);
break;
case spv::Op::OpTypeArray: {
// Arrays consume locations equal to the underlying type times the number
// of elements in the vector.
- if (auto error = NumConsumedLocations(
- _, _.FindDef(type->GetOperandAs<uint32_t>(1)), num_locations)) {
- return error;
- }
+ NumConsumedLocations(_, _.FindDef(type->GetOperandAs<uint32_t>(1)),
+ num_locations);
bool is_int = false;
bool is_const = false;
uint32_t value = 0;
@@ -249,31 +246,10 @@
NumConsumedComponents(_, _.FindDef(type->GetOperandAs<uint32_t>(1)));
num_components *= type->GetOperandAs<uint32_t>(2);
break;
- case spv::Op::OpTypeMatrix:
- // Matrices consume all components of the location.
- // Round up to next multiple of 4.
- num_components =
- NumConsumedComponents(_, _.FindDef(type->GetOperandAs<uint32_t>(1)));
- num_components *= type->GetOperandAs<uint32_t>(2);
- num_components = ((num_components + 3) / 4) * 4;
- break;
- case spv::Op::OpTypeArray: {
- // Arrays consume all components of the location.
- // Round up to next multiple of 4.
- num_components =
- NumConsumedComponents(_, _.FindDef(type->GetOperandAs<uint32_t>(1)));
-
- bool is_int = false;
- bool is_const = false;
- uint32_t value = 0;
- // Attempt to evaluate the number of array elements.
- std::tie(is_int, is_const, value) =
- _.EvalInt32IfConst(type->GetOperandAs<uint32_t>(2));
- if (is_int && is_const) num_components *= value;
-
- num_components = ((num_components + 3) / 4) * 4;
- return num_components;
- }
+ case spv::Op::OpTypeArray:
+ // Skip the array.
+ return NumConsumedComponents(_,
+ _.FindDef(type->GetOperandAs<uint32_t>(1)));
case spv::Op::OpTypePointer:
if (_.addressing_model() ==
spv::AddressingModel::PhysicalStorageBuffer64 &&
@@ -356,10 +332,9 @@
}
}
- // Vulkan 15.1.3 (Interface Matching): Tessellation control and mesh
- // per-vertex outputs and tessellation control, evaluation and geometry
- // per-vertex inputs have a layer of arraying that is not included in
- // interface matching.
+ // Vulkan 14.1.3: Tessellation control and mesh per-vertex outputs and
+ // tessellation control, evaluation and geometry per-vertex inputs have a
+ // layer of arraying that is not included in interface matching.
bool is_arrayed = false;
switch (entry_point->GetOperandAs<spv::ExecutionModel>(0)) {
case spv::ExecutionModel::TessellationControl:
@@ -413,33 +388,51 @@
const std::string storage_class = is_output ? "output" : "input";
if (has_location) {
+ auto sub_type = type;
+ bool is_int = false;
+ bool is_const = false;
+ uint32_t array_size = 1;
+ // If the variable is still arrayed, mark the locations/components per
+ // index.
+ if (type->opcode() == spv::Op::OpTypeArray) {
+ // Determine the array size if possible and get the element type.
+ std::tie(is_int, is_const, array_size) =
+ _.EvalInt32IfConst(type->GetOperandAs<uint32_t>(2));
+ if (!is_int || !is_const) array_size = 1;
+ auto sub_type_id = type->GetOperandAs<uint32_t>(1);
+ sub_type = _.FindDef(sub_type_id);
+ }
+
uint32_t num_locations = 0;
- if (auto error = NumConsumedLocations(_, type, &num_locations))
+ if (auto error = NumConsumedLocations(_, sub_type, &num_locations))
return error;
- uint32_t num_components = NumConsumedComponents(_, type);
+ uint32_t num_components = NumConsumedComponents(_, sub_type);
- uint32_t start = location * 4;
- uint32_t end = (location + num_locations) * 4;
- if (num_components % 4 != 0) {
- start += component;
- end = start + num_components;
- }
+ for (uint32_t array_idx = 0; array_idx < array_size; ++array_idx) {
+ uint32_t array_location = location + (num_locations * array_idx);
+ uint32_t start = array_location * 4;
+ if (kMaxLocations <= start) {
+ // Too many locations, give up.
+ break;
+ }
- if (kMaxLocations <= start) {
- // Too many locations, give up.
- return SPV_SUCCESS;
- }
+ uint32_t end = (array_location + num_locations) * 4;
+ if (num_components != 0) {
+ start += component;
+ end = array_location * 4 + component + num_components;
+ }
- auto locs = locations;
- if (has_index && index == 1) locs = output_index1_locations;
+ auto locs = locations;
+ if (has_index && index == 1) locs = output_index1_locations;
- for (uint32_t i = start; i < end; ++i) {
- if (!locs->insert(i).second) {
- return _.diag(SPV_ERROR_INVALID_DATA, entry_point)
- << (is_output ? _.VkErrorID(8722) : _.VkErrorID(8721))
- << "Entry-point has conflicting " << storage_class
- << " location assignment at location " << i / 4 << ", component "
- << i % 4;
+ for (uint32_t i = start; i < end; ++i) {
+ if (!locs->insert(i).second) {
+ return _.diag(SPV_ERROR_INVALID_DATA, entry_point)
+ << (is_output ? _.VkErrorID(8722) : _.VkErrorID(8721))
+ << "Entry-point has conflicting " << storage_class
+ << " location assignment at location " << i / 4
+ << ", component " << i % 4;
+ }
}
}
} else {
@@ -498,19 +491,38 @@
continue;
}
- uint32_t end = (location + num_locations) * 4;
- if (num_components % 4 != 0) {
- start += component;
- end = location * 4 + component + num_components;
- }
-
- for (uint32_t l = start; l < end; ++l) {
- if (!locations->insert(l).second) {
- return _.diag(SPV_ERROR_INVALID_DATA, entry_point)
- << (is_output ? _.VkErrorID(8722) : _.VkErrorID(8721))
- << "Entry-point has conflicting " << storage_class
- << " location assignment at location " << l / 4
- << ", component " << l % 4;
+ if (member->opcode() == spv::Op::OpTypeArray && num_components >= 1 &&
+ num_components < 4) {
+ // When an array has an element that takes less than a location in
+ // size, calculate the used locations in a strided manner.
+ for (uint32_t l = location; l < num_locations + location; ++l) {
+ for (uint32_t c = component; c < component + num_components; ++c) {
+ uint32_t check = 4 * l + c;
+ if (!locations->insert(check).second) {
+ return _.diag(SPV_ERROR_INVALID_DATA, entry_point)
+ << (is_output ? _.VkErrorID(8722) : _.VkErrorID(8721))
+ << "Entry-point has conflicting " << storage_class
+ << " location assignment at location " << l
+ << ", component " << c;
+ }
+ }
+ }
+ } else {
+ // TODO: There is a hole here is the member is an array of 3- or
+ // 4-element vectors of 64-bit types.
+ uint32_t end = (location + num_locations) * 4;
+ if (num_components != 0) {
+ start += component;
+ end = location * 4 + component + num_components;
+ }
+ for (uint32_t l = start; l < end; ++l) {
+ if (!locations->insert(l).second) {
+ return _.diag(SPV_ERROR_INVALID_DATA, entry_point)
+ << (is_output ? _.VkErrorID(8722) : _.VkErrorID(8721))
+ << "Entry-point has conflicting " << storage_class
+ << " location assignment at location " << l / 4
+ << ", component " << l % 4;
+ }
}
}
}
diff --git a/test/val/val_decoration_test.cpp b/test/val/val_decoration_test.cpp
index 3500414..087d416 100644
--- a/test/val/val_decoration_test.cpp
+++ b/test/val/val_decoration_test.cpp
@@ -10394,7 +10394,7 @@
OpDecorate %gl_PerVertex Block
OpDecorate %FOO Component 2
OpDecorate %FOO Location 1
- OpDecorate %FOO0 Location 4
+ OpDecorate %FOO0 Location 1
OpDecorate %FOO0 Component 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
diff --git a/test/val/val_interfaces_test.cpp b/test/val/val_interfaces_test.cpp
index f12ae72..e5cc97d 100644
--- a/test/val/val_interfaces_test.cpp
+++ b/test/val/val_interfaces_test.cpp
@@ -1415,12 +1415,7 @@
)";
CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
- EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
- EXPECT_THAT(getDiagnosticString(),
- AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08722"));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("Entry-point has conflicting output location "
- "assignment at location 0, component 0"));
+ EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
}
TEST_F(ValidateInterfacesTest, VulkanLocationsArrayWithComponentBad) {
@@ -1433,7 +1428,7 @@
OpDecorate %18 Component 0
OpDecorate %18 Location 0
OpDecorate %28 Component 1
-OpDecorate %28 Location 1
+OpDecorate %28 Location 0
OpDecorate %36 Location 1
OpDecorate %40 Component 1
OpDecorate %40 Location 1
@@ -1548,12 +1543,7 @@
)";
CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
- EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
- EXPECT_THAT(getDiagnosticString(),
- AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721"));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("Entry-point has conflicting input location "
- "assignment at location 0, component 0"));
+ EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
}
TEST_F(ValidateInterfacesTest, VulkanLocationArrayWithComponent2) {
@@ -1585,82 +1575,9 @@
)";
CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
- EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
- EXPECT_THAT(getDiagnosticString(),
- AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721"));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("Entry-point has conflicting input location "
- "assignment at location 0, component 0"));
-}
-
-TEST_F(ValidateInterfacesTest, VulkanLocationMatrix2x2DoubleGood) {
- const std::string text = R"(
-OpCapability Shader
-OpCapability Float64
-OpMemoryModel Logical GLSL450
-OpEntryPoint Fragment %main "main" %in
-OpExecutionMode %main OriginUpperLeft
-OpDecorate %struct Block
-OpMemberDecorate %struct 0 Location 0
-OpMemberDecorate %struct 1 Location 2
-%void = OpTypeVoid
-%void_fn = OpTypeFunction %void
-%float = OpTypeFloat 32
-%double = OpTypeFloat 64
-%int = OpTypeInt 32 0
-%int_2 = OpConstant %int 2
-%double2 = OpTypeVector %double 2
-%mat2x2_double = OpTypeMatrix %double2 2
-%struct = OpTypeStruct %mat2x2_double %int
-%ptr = OpTypePointer Input %struct
-%in = OpVariable %ptr Input
-%main = OpFunction %void None %void_fn
-%entry = OpLabel
-OpReturn
-OpFunctionEnd
-)";
-
- CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
}
-TEST_F(ValidateInterfacesTest, VulkanLocationMatrix2x2DoubleBad) {
- const std::string text = R"(
-OpCapability Shader
-OpCapability Float64
-OpMemoryModel Logical GLSL450
-OpEntryPoint Fragment %main "main" %in
-OpExecutionMode %main OriginUpperLeft
-OpDecorate %struct Block
-OpMemberDecorate %struct 0 Location 0
-OpMemberDecorate %struct 1 Location 1
-OpMemberDecorate %struct 1 Component 3
-%void = OpTypeVoid
-%void_fn = OpTypeFunction %void
-%float = OpTypeFloat 32
-%double = OpTypeFloat 64
-%int = OpTypeInt 32 0
-%int_2 = OpConstant %int 2
-%double2 = OpTypeVector %double 2
-%mat2x2_double = OpTypeMatrix %double2 2
-%struct = OpTypeStruct %mat2x2_double %int
-%ptr = OpTypePointer Input %struct
-%in = OpVariable %ptr Input
-%main = OpFunction %void None %void_fn
-%entry = OpLabel
-OpReturn
-OpFunctionEnd
-)";
-
- CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
- EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
- EXPECT_THAT(getDiagnosticString(),
- AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721"));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("Entry-point has conflicting input location "
- "assignment at location 1, component 3"));
-}
-
TEST_F(ValidateInterfacesTest, DuplicateInterfaceVariableSuccess) {
const std::string text = R"(
OpCapability Shader