Extra small storage validation (#2732)
Fixes #2729
* Check acceptable uses of small type generators
diff --git a/Android.mk b/Android.mk
index 8e44378..075dc61 100644
--- a/Android.mk
+++ b/Android.mk
@@ -70,6 +70,7 @@
source/val/validate_non_uniform.cpp \
source/val/validate_primitives.cpp \
source/val/validate_scopes.cpp \
+ source/val/validate_small_type_uses.cpp \
source/val/validate_type.cpp
SPVTOOLS_OPT_SRC_FILES := \
diff --git a/BUILD.gn b/BUILD.gn
index ad71c1d..3c2a9f6 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -428,6 +428,7 @@
"source/val/validate_non_uniform.cpp",
"source/val/validate_primitives.cpp",
"source/val/validate_scopes.cpp",
+ "source/val/validate_small_type_uses.cpp",
"source/val/validate_type.cpp",
"source/val/validation_state.cpp",
]
diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt
index bd4c465..cb63ff0 100644
--- a/source/CMakeLists.txt
+++ b/source/CMakeLists.txt
@@ -304,6 +304,7 @@
${CMAKE_CURRENT_SOURCE_DIR}/val/validate_non_uniform.cpp
${CMAKE_CURRENT_SOURCE_DIR}/val/validate_primitives.cpp
${CMAKE_CURRENT_SOURCE_DIR}/val/validate_scopes.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_small_type_uses.cpp
${CMAKE_CURRENT_SOURCE_DIR}/val/validate_type.cpp
${CMAKE_CURRENT_SOURCE_DIR}/val/decoration.h
${CMAKE_CURRENT_SOURCE_DIR}/val/basic_block.cpp
diff --git a/source/val/validate.cpp b/source/val/validate.cpp
index 0840662..6f1a26c 100644
--- a/source/val/validate.cpp
+++ b/source/val/validate.cpp
@@ -412,6 +412,7 @@
// those checks register the limitation checked here.
for (const auto inst : vstate->ordered_instructions()) {
if (auto error = ValidateExecutionLimitations(*vstate, &inst)) return error;
+ if (auto error = ValidateSmallTypeUses(*vstate, &inst)) return error;
}
return SPV_SUCCESS;
diff --git a/source/val/validate.h b/source/val/validate.h
index aaae570..b6c4072 100644
--- a/source/val/validate.h
+++ b/source/val/validate.h
@@ -208,6 +208,13 @@
spv_result_t ValidateExecutionLimitations(ValidationState_t& _,
const Instruction* inst);
+/// Validates restricted uses of 8- and 16-bit types.
+///
+/// Validates shaders that uses 8- or 16-bit storage capabilities, but not full
+/// capabilities only have appropriate uses of those types.
+spv_result_t ValidateSmallTypeUses(ValidationState_t& _,
+ const Instruction* inst);
+
/// @brief Validate the ID's within a SPIR-V binary
///
/// @param[in] pInstructions array of instructions
diff --git a/source/val/validate_misc.cpp b/source/val/validate_misc.cpp
index 8e007ed..28e3fc6 100644
--- a/source/val/validate_misc.cpp
+++ b/source/val/validate_misc.cpp
@@ -22,9 +22,30 @@
namespace spvtools {
namespace val {
+namespace {
+
+spv_result_t ValidateUndef(ValidationState_t& _, const Instruction* inst) {
+ if (_.HasCapability(SpvCapabilityShader) &&
+ _.ContainsLimitedUseIntOrFloatType(inst->type_id()) &&
+ !_.IsPointerType(inst->type_id())) {
+ return _.diag(SPV_ERROR_INVALID_ID, inst)
+ << "Cannot create undefined values with 8- or 16-bit types";
+ }
+
+ return SPV_SUCCESS;
+}
+
+} // namespace
spv_result_t MiscPass(ValidationState_t& _, const Instruction* inst) {
switch (inst->opcode()) {
+ case SpvOpUndef:
+ if (auto error = ValidateUndef(_, inst)) return error;
+ break;
+ default:
+ break;
+ }
+ switch (inst->opcode()) {
case SpvOpBeginInvocationInterlockEXT:
case SpvOpEndInvocationInterlockEXT:
_.function(inst->function()->id())
diff --git a/source/val/validate_small_type_uses.cpp b/source/val/validate_small_type_uses.cpp
new file mode 100644
index 0000000..9db82e7
--- /dev/null
+++ b/source/val/validate_small_type_uses.cpp
@@ -0,0 +1,57 @@
+// Copyright (c) 2019 Google LLC.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "source/val/validate.h"
+
+#include "source/val/instruction.h"
+#include "source/val/validation_state.h"
+
+namespace spvtools {
+namespace val {
+
+spv_result_t ValidateSmallTypeUses(ValidationState_t& _,
+ const Instruction* inst) {
+ if (!_.HasCapability(SpvCapabilityShader) || inst->type_id() == 0 ||
+ !_.ContainsLimitedUseIntOrFloatType(inst->type_id())) {
+ return SPV_SUCCESS;
+ }
+
+ if (_.IsPointerType(inst->type_id())) return SPV_SUCCESS;
+
+ // The validator should previously have checked ways to generate 8- or 16-bit
+ // types. So we only need to considervalid paths from source to sink.
+ // When restricted, uses of 8- or 16-bit types can only be stores,
+ // width-only conversions, decorations and copy object.
+ for (auto use : inst->uses()) {
+ const auto* user = use.first;
+ switch (user->opcode()) {
+ case SpvOpDecorate:
+ case SpvOpDecorateId:
+ case SpvOpCopyObject:
+ case SpvOpStore:
+ case SpvOpFConvert:
+ case SpvOpUConvert:
+ case SpvOpSConvert:
+ break;
+ default:
+ return _.diag(SPV_ERROR_INVALID_ID, user)
+ << "Invalid use of 8- or 16-bit result";
+ }
+ }
+
+ return SPV_SUCCESS;
+}
+
+} // namespace val
+} // namespace spvtools
diff --git a/test/val/CMakeLists.txt b/test/val/CMakeLists.txt
index 8f4bc33..b52c764 100644
--- a/test/val/CMakeLists.txt
+++ b/test/val/CMakeLists.txt
@@ -61,6 +61,7 @@
val_literals_test.cpp
val_logicals_test.cpp
val_memory_test.cpp
+ val_misc_test.cpp
val_modes_test.cpp
val_non_uniform_test.cpp
val_opencl_test.cpp
@@ -72,6 +73,7 @@
add_spvtools_unittest(TARGET val_stuvw
SRCS
+ val_small_type_uses_test.cpp
val_ssa_test.cpp
val_state_test.cpp
val_storage_test.cpp
diff --git a/test/val/val_misc_test.cpp b/test/val/val_misc_test.cpp
new file mode 100644
index 0000000..350f561
--- /dev/null
+++ b/test/val/val_misc_test.cpp
@@ -0,0 +1,88 @@
+// Copyright (c) 2019 Google LLC.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Validation tests for misc instructions
+
+#include <string>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "test/unit_spirv.h"
+#include "test/val/val_fixtures.h"
+
+namespace spvtools {
+namespace val {
+namespace {
+
+using ::testing::Eq;
+using ::testing::HasSubstr;
+
+using ValidateMisc = spvtest::ValidateBase<bool>;
+
+TEST_F(ValidateMisc, UndefRestrictedShort) {
+ const std::string spirv = R"(
+OpCapability Shader
+OpCapability Linkage
+OpCapability StorageBuffer16BitAccess
+OpExtension "SPV_KHR_16bit_storage"
+OpMemoryModel Logical GLSL450
+%short = OpTypeInt 16 0
+%undef = OpUndef %short
+)";
+
+ CompileSuccessfully(spirv);
+ EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("Cannot create undefined values with 8- or 16-bit types"));
+}
+
+TEST_F(ValidateMisc, UndefRestrictedChar) {
+ const std::string spirv = R"(
+OpCapability Shader
+OpCapability Linkage
+OpCapability StorageBuffer8BitAccess
+OpExtension "SPV_KHR_8bit_storage"
+OpMemoryModel Logical GLSL450
+%char = OpTypeInt 8 0
+%undef = OpUndef %char
+)";
+
+ CompileSuccessfully(spirv);
+ EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("Cannot create undefined values with 8- or 16-bit types"));
+}
+
+TEST_F(ValidateMisc, UndefRestrictedHalf) {
+ const std::string spirv = R"(
+OpCapability Shader
+OpCapability Linkage
+OpCapability StorageBuffer16BitAccess
+OpExtension "SPV_KHR_16bit_storage"
+OpMemoryModel Logical GLSL450
+%half = OpTypeFloat 16
+%undef = OpUndef %half
+)";
+
+ CompileSuccessfully(spirv);
+ EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("Cannot create undefined values with 8- or 16-bit types"));
+}
+} // namespace
+} // namespace val
+} // namespace spvtools
diff --git a/test/val/val_small_type_uses_test.cpp b/test/val/val_small_type_uses_test.cpp
new file mode 100644
index 0000000..b950af5
--- /dev/null
+++ b/test/val/val_small_type_uses_test.cpp
@@ -0,0 +1,338 @@
+// Copyright (c) 2019 Google LLC.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Validation tests for 8- and 16-bit type uses.
+
+#include <string>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "test/unit_spirv.h"
+#include "test/val/val_code_generator.h"
+#include "test/val/val_fixtures.h"
+
+namespace spvtools {
+namespace val {
+namespace {
+
+using ::testing::Eq;
+using ::testing::HasSubstr;
+using ::testing::Values;
+
+using ValidateSmallTypeUses = spvtest::ValidateBase<bool>;
+
+CodeGenerator GetSmallTypesGenerator() {
+ CodeGenerator generator;
+ generator.capabilities_ = R"(
+OpCapability Shader
+OpCapability StorageBuffer16BitAccess
+OpCapability StorageBuffer8BitAccess
+)";
+ generator.extensions_ = R"(
+OpExtension "SPV_KHR_16bit_storage"
+OpExtension "SPV_KHR_8bit_storage"
+OpExtension "SPV_KHR_storage_buffer_storage_class"
+%ext = OpExtInstImport "GLSL.std.450"
+)";
+ generator.memory_model_ = "OpMemoryModel Logical GLSL450\n";
+ std::string body = R"(
+%short_gep = OpAccessChain %ptr_ssbo_short %var %int_0 %int_0
+%ld_short = OpLoad %short %short_gep
+%short_to_int = OpSConvert %int %ld_short
+%short_to_uint = OpUConvert %int %ld_short
+%short_to_char = OpSConvert %char %ld_short
+%short_to_uchar = OpSConvert %char %ld_short
+%short2_gep = OpAccessChain %ptr_ssbo_short2 %var %int_0
+%ld_short2 = OpLoad %short2 %short2_gep
+%short2_to_int2 = OpSConvert %int2 %ld_short2
+%short2_to_uint2 = OpUConvert %int2 %ld_short2
+%short2_to_char2 = OpSConvert %char2 %ld_short2
+%short2_to_uchar2 = OpSConvert %char2 %ld_short2
+
+%char_gep = OpAccessChain %ptr_ssbo_char %var %int_2 %int_0
+%ld_char = OpLoad %char %char_gep
+%char_to_int = OpSConvert %int %ld_char
+%char_to_uint = OpUConvert %int %ld_char
+%char_to_short = OpSConvert %short %ld_char
+%char_to_ushort = OpSConvert %short %ld_char
+%char2_gep = OpAccessChain %ptr_ssbo_char2 %var %int_2
+%ld_char2 = OpLoad %char2 %char2_gep
+%char2_to_int2 = OpSConvert %int2 %ld_char2
+%char2_to_uint2 = OpUConvert %int2 %ld_char2
+%char2_to_short2 = OpSConvert %short2 %ld_char2
+%char2_to_ushort2 = OpSConvert %short2 %ld_char2
+
+%half_gep = OpAccessChain %ptr_ssbo_half %var %int_1 %int_0
+%ld_half = OpLoad %half %half_gep
+%half_to_float = OpFConvert %float %ld_half
+%half2_gep = OpAccessChain %ptr_ssbo_half2 %var %int_1
+%ld_half2 = OpLoad %half2 %half2_gep
+%half2_to_float2 = OpFConvert %float2 %ld_half2
+
+%int_to_short = OpSConvert %short %int_0
+%int_to_ushort = OpUConvert %short %int_0
+%int_to_char = OpSConvert %char %int_0
+%int_to_uchar = OpUConvert %char %int_0
+%int2_to_short2 = OpSConvert %short2 %int2_0
+%int2_to_ushort2 = OpUConvert %short2 %int2_0
+%int2_to_char2 = OpSConvert %char2 %int2_0
+%int2_to_uchar2 = OpUConvert %char2 %int2_0
+%int_gep = OpAccessChain %ptr_ssbo_int %var %int_3 %int_0
+%int2_gep = OpAccessChain %ptr_ssbo_int2 %var %int_3
+
+%float_to_half = OpFConvert %half %float_0
+%float2_to_half2 = OpFConvert %half2 %float2_0
+%float_gep = OpAccessChain %ptr_ssbo_float %var %int_4 %int_0
+%float2_gep = OpAccessChain %ptr_ssbo_float2 %var %int_4
+)";
+ generator.entry_points_.push_back(
+ {"foo", "GLCompute", "OpExecutionMode %foo LocalSize 1 1 1", body, ""});
+ generator.before_types_ = R"(
+OpDecorate %block Block
+OpMemberDecorate %block 0 Offset 0
+OpMemberDecorate %block 1 Offset 8
+OpMemberDecorate %block 2 Offset 16
+OpMemberDecorate %block 3 Offset 32
+OpMemberDecorate %block 4 Offset 64
+)";
+ generator.types_ = R"(
+%void = OpTypeVoid
+%int = OpTypeInt 32 0
+%int2 = OpTypeVector %int 2
+%float = OpTypeFloat 32
+%float2 = OpTypeVector %float 2
+%bool = OpTypeBool
+%bool2 = OpTypeVector %bool 2
+%char = OpTypeInt 8 0
+%char2 = OpTypeVector %char 2
+%ptr_ssbo_char = OpTypePointer StorageBuffer %char
+%ptr_ssbo_char2 = OpTypePointer StorageBuffer %char2
+%short = OpTypeInt 16 0
+%short2 = OpTypeVector %short 2
+%ptr_ssbo_short = OpTypePointer StorageBuffer %short
+%ptr_ssbo_short2 = OpTypePointer StorageBuffer %short2
+%half = OpTypeFloat 16
+%half2 = OpTypeVector %half 2
+%ptr_ssbo_half = OpTypePointer StorageBuffer %half
+%ptr_ssbo_half2 = OpTypePointer StorageBuffer %half2
+%ptr_ssbo_int = OpTypePointer StorageBuffer %int
+%ptr_ssbo_int2 = OpTypePointer StorageBuffer %int2
+%ptr_ssbo_float = OpTypePointer StorageBuffer %float
+%ptr_ssbo_float2 = OpTypePointer StorageBuffer %float2
+%block = OpTypeStruct %short2 %half2 %char2 %int2 %float2
+%ptr_ssbo_block = OpTypePointer StorageBuffer %block
+%func = OpTypeFunction %void
+)";
+ generator.after_types_ = R"(
+%var = OpVariable %ptr_ssbo_block StorageBuffer
+%int_0 = OpConstant %int 0
+%int_1 = OpConstant %int 1
+%int_2 = OpConstant %int 2
+%int_3 = OpConstant %int 3
+%int_4 = OpConstant %int 4
+%int2_0 = OpConstantComposite %int2 %int_0 %int_0
+%float_0 = OpConstant %float 0
+%float2_0 = OpConstantComposite %float2 %float_0 %float_0
+
+%short_func_ty = OpTypeFunction %void %short
+%char_func_ty = OpTypeFunction %void %char
+%half_func_ty = OpTypeFunction %void %half
+)";
+ generator.add_at_the_end_ = R"(
+%short_func = OpFunction %void None %short_func_ty
+%short_param = OpFunctionParameter %short
+%short_func_entry = OpLabel
+OpReturn
+OpFunctionEnd
+%char_func = OpFunction %void None %char_func_ty
+%char_param = OpFunctionParameter %char
+%char_func_entry = OpLabel
+OpReturn
+OpFunctionEnd
+%half_func = OpFunction %void None %half_func_ty
+%half_param = OpFunctionParameter %half
+%half_func_entry = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+ return generator;
+}
+
+TEST_F(ValidateSmallTypeUses, BadCharPhi) {
+ CodeGenerator generator = GetSmallTypesGenerator();
+ generator.entry_points_[0].body += R"(
+OpBranch %next_block
+%next_block = OpLabel
+%phi = OpPhi %char %ld_char %foo_entry
+)";
+
+ CompileSuccessfully(generator.Build());
+ EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Invalid use of 8- or 16-bit result"));
+}
+
+TEST_F(ValidateSmallTypeUses, BadShortPhi) {
+ CodeGenerator generator = GetSmallTypesGenerator();
+ generator.entry_points_[0].body += R"(
+OpBranch %next_block
+%next_block = OpLabel
+%phi = OpPhi %short %ld_short %foo_entry
+)";
+
+ CompileSuccessfully(generator.Build());
+ EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Invalid use of 8- or 16-bit result"));
+}
+
+TEST_F(ValidateSmallTypeUses, BadHalfPhi) {
+ CodeGenerator generator = GetSmallTypesGenerator();
+ generator.entry_points_[0].body += R"(
+OpBranch %next_block
+%next_block = OpLabel
+%phi = OpPhi %half %ld_half %foo_entry
+)";
+
+ CompileSuccessfully(generator.Build());
+ EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Invalid use of 8- or 16-bit result"));
+}
+
+using ValidateGoodUses = spvtest::ValidateBase<std::string>;
+
+TEST_P(ValidateGoodUses, Inst) {
+ const std::string inst = GetParam();
+ CodeGenerator generator = GetSmallTypesGenerator();
+ generator.entry_points_[0].body += inst + "\n";
+
+ CompileSuccessfully(generator.Build());
+ EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ SmallTypeUsesValid, ValidateGoodUses,
+ Values(
+ "%inst = OpIAdd %int %short_to_int %int_0",
+ "%inst = OpIAdd %int %short_to_uint %int_0",
+ "%inst = OpIAdd %int2 %short2_to_int2 %int2_0",
+ "%inst = OpIAdd %int2 %short2_to_uint2 %int2_0",
+ "%inst = OpIAdd %int %char_to_int %int_0",
+ "%inst = OpIAdd %int %char_to_uint %int_0",
+ "%inst = OpIAdd %int2 %char2_to_int2 %int2_0",
+ "%inst = OpIAdd %int2 %char2_to_uint2 %int2_0",
+ "%inst = OpUConvert %int %ld_short",
+ "%inst = OpSConvert %int %ld_short",
+ "%inst = OpUConvert %char %ld_short",
+ "%inst = OpSConvert %char %ld_short",
+ "%inst = OpUConvert %int %ld_char", "%inst = OpSConvert %int %ld_char",
+ "%inst = OpUConvert %short %ld_char",
+ "%inst = OpSConvert %short %ld_char",
+ "%inst = OpUConvert %int2 %ld_short2",
+ "%inst = OpSConvert %int2 %ld_short2",
+ "%inst = OpUConvert %char2 %ld_short2",
+ "%inst = OpSConvert %char2 %ld_short2",
+ "%inst = OpUConvert %int2 %ld_char2",
+ "%inst = OpSConvert %int2 %ld_char2",
+ "%inst = OpUConvert %short2 %ld_char2",
+ "%inst = OpSConvert %short2 %ld_char2",
+ "OpStore %short_gep %int_to_short", "OpStore %short_gep %int_to_ushort",
+ "OpStore %short_gep %char_to_short",
+ "OpStore %short_gep %char_to_ushort",
+ "OpStore %short2_gep %int2_to_short2",
+ "OpStore %short2_gep %int2_to_ushort2",
+ "OpStore %short2_gep %char2_to_short2",
+ "OpStore %short2_gep %char2_to_ushort2",
+ "OpStore %char_gep %int_to_char", "OpStore %char_gep %int_to_uchar",
+ "OpStore %char_gep %short_to_char", "OpStore %char_gep %short_to_uchar",
+ "OpStore %char2_gep %int2_to_char2",
+ "OpStore %char2_gep %int2_to_uchar2",
+ "OpStore %char2_gep %short2_to_char2",
+ "OpStore %char2_gep %short2_to_uchar2",
+ "OpStore %int_gep %short_to_int", "OpStore %int_gep %short_to_uint",
+ "OpStore %int_gep %char_to_int", "OpStore %int2_gep %char2_to_uint2",
+ "OpStore %int2_gep %short2_to_int2",
+ "OpStore %int2_gep %short2_to_uint2",
+ "OpStore %int2_gep %char2_to_int2", "OpStore %int2_gep %char2_to_uint2",
+ "%inst = OpFAdd %float %half_to_float %float_0",
+ "%inst = OpFAdd %float2 %half2_to_float2 %float2_0",
+ "%inst = OpFConvert %float %ld_half",
+ "%inst = OpFConvert %float2 %ld_half2",
+ "OpStore %half_gep %float_to_half", "OpStore %half_gep %ld_half",
+ "OpStore %half2_gep %float2_to_half2", "OpStore %half2_gep %ld_half2",
+ "OpStore %float_gep %half_to_float",
+ "OpStore %float2_gep %half2_to_float2"));
+
+using ValidateBadUses = spvtest::ValidateBase<std::string>;
+
+TEST_P(ValidateBadUses, Inst) {
+ const std::string inst = GetParam();
+ CodeGenerator generator = GetSmallTypesGenerator();
+ generator.entry_points_[0].body += inst + "\n";
+
+ CompileSuccessfully(generator.Build());
+ EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Invalid use of 8- or 16-bit result"));
+}
+
+// A smattering of unacceptable use cases. Far too vast to cover exhaustively.
+INSTANTIATE_TEST_SUITE_P(
+ SmallTypeUsesInvalid, ValidateBadUses,
+ Values("%inst = OpIAdd %short %ld_short %ld_short",
+ "%inst = OpIAdd %short %char_to_short %char_to_short",
+ "%inst = OpIAdd %short %char_to_ushort %char_to_ushort",
+ "%inst = OpIAdd %short %int_to_short %int_to_short",
+ "%inst = OpIAdd %short %int_to_ushort %int_to_ushort",
+ "%inst = OpIAdd %short2 %ld_short2 %ld_short2",
+ "%inst = OpIAdd %short2 %char2_to_short2 %char2_to_short2",
+ "%inst = OpIAdd %short2 %char2_to_ushort2 %char2_to_ushort2",
+ "%inst = OpIAdd %short2 %int2_to_short2 %int2_to_short2",
+ "%inst = OpIAdd %short2 %int2_to_ushort2 %int2_to_ushort2",
+ "%inst = OpIEqual %bool %ld_short %ld_short",
+ "%inst = OpIEqual %bool %char_to_short %char_to_short",
+ "%inst = OpIEqual %bool %char_to_ushort %char_to_ushort",
+ "%inst = OpIEqual %bool %int_to_short %int_to_short",
+ "%inst = OpIEqual %bool %int_to_ushort %int_to_ushort",
+ "%inst = OpIEqual %bool2 %ld_short2 %ld_short2",
+ "%inst = OpIEqual %bool2 %char2_to_short2 %char2_to_short2",
+ "%inst = OpIEqual %bool2 %char2_to_ushort2 %char2_to_ushort2",
+ "%inst = OpIEqual %bool2 %int2_to_short2 %int2_to_short2",
+ "%inst = OpIEqual %bool2 %int2_to_ushort2 %int2_to_ushort2",
+ "%inst = OpFAdd %half %ld_half %ld_half",
+ "%inst = OpFAdd %half %float_to_half %float_to_half",
+ "%inst = OpFAdd %half2 %ld_half2 %ld_half2",
+ "%inst = OpFAdd %half2 %float2_to_half2 %float2_to_half2",
+ "%inst = OpFOrdGreaterThan %bool %ld_half %ld_half",
+ "%inst = OpFOrdGreaterThan %bool %float_to_half %float_to_half",
+ "%inst = OpFOrdGreaterThan %bool2 %ld_half2 %ld_half2",
+ "%inst = OpFOrdGreaterThan %bool2 %float2_to_half2 %float2_to_half2",
+ "%inst = OpFunctionCall %void %short_func %ld_short",
+ "%inst = OpFunctionCall %void %short_func %char_to_short",
+ "%inst = OpFunctionCall %void %short_func %char_to_ushort",
+ "%inst = OpFunctionCall %void %short_func %int_to_short",
+ "%inst = OpFunctionCall %void %short_func %int_to_ushort",
+ "%inst = OpFunctionCall %void %char_func %ld_char",
+ "%inst = OpFunctionCall %void %char_func %short_to_char",
+ "%inst = OpFunctionCall %void %char_func %short_to_uchar",
+ "%inst = OpFunctionCall %void %char_func %int_to_char",
+ "%inst = OpFunctionCall %void %char_func %int_to_uchar",
+ "%inst = OpFunctionCall %void %half_func %ld_half",
+ "%inst = OpFunctionCall %void %half_func %float_to_half"));
+
+} // namespace
+} // namespace val
+} // namespace spvtools