1 // Copyright (c) 2019 Google LLC.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 // Validation tests for non-semantic instructions
16
17 #include <string>
18 #include <vector>
19
20 #include "gmock/gmock.h"
21 #include "test/unit_spirv.h"
22 #include "test/val/val_code_generator.h"
23 #include "test/val/val_fixtures.h"
24
25 namespace spvtools {
26 namespace val {
27 namespace {
28
29 struct TestResult {
TestResultspvtools::val::__anon98967dd60111::TestResult30 TestResult(spv_result_t in_validation_result = SPV_SUCCESS,
31 const char* in_error_str = nullptr,
32 const char* in_error_str2 = nullptr)
33 : validation_result(in_validation_result),
34 error_str(in_error_str),
35 error_str2(in_error_str2) {}
36 spv_result_t validation_result;
37 const char* error_str;
38 const char* error_str2;
39 };
40
41 using ::testing::Combine;
42 using ::testing::HasSubstr;
43 using ::testing::Values;
44 using ::testing::ValuesIn;
45
46 using ValidateNonSemanticGenerated = spvtest::ValidateBase<
47 std::tuple<bool, bool, const char*, const char*, TestResult>>;
48 using ValidateNonSemanticString = spvtest::ValidateBase<bool>;
49
GetNonSemanticCodeGenerator(const bool declare_ext,const bool declare_extinst,const char * const global_extinsts,const char * const function_extinsts)50 CodeGenerator GetNonSemanticCodeGenerator(const bool declare_ext,
51 const bool declare_extinst,
52 const char* const global_extinsts,
53 const char* const function_extinsts) {
54 CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator();
55
56 if (declare_ext) {
57 generator.extensions_ += "OpExtension \"SPV_KHR_non_semantic_info\"\n";
58 }
59 if (declare_extinst) {
60 generator.extensions_ +=
61 "%extinst = OpExtInstImport \"NonSemantic.Testing.Set\"\n";
62 }
63
64 generator.after_types_ = global_extinsts;
65
66 generator.before_types_ = "%decorate_group = OpDecorationGroup";
67
68 EntryPoint entry_point;
69 entry_point.name = "main";
70 entry_point.execution_model = "Vertex";
71
72 entry_point.body = R"(
73 )";
74 entry_point.body += function_extinsts;
75 generator.entry_points_.push_back(std::move(entry_point));
76
77 return generator;
78 }
79
TEST_P(ValidateNonSemanticGenerated,InTest)80 TEST_P(ValidateNonSemanticGenerated, InTest) {
81 const bool declare_ext = std::get<0>(GetParam());
82 const bool declare_extinst = std::get<1>(GetParam());
83 const char* const global_extinsts = std::get<2>(GetParam());
84 const char* const function_extinsts = std::get<3>(GetParam());
85 const TestResult& test_result = std::get<4>(GetParam());
86
87 CodeGenerator generator = GetNonSemanticCodeGenerator(
88 declare_ext, declare_extinst, global_extinsts, function_extinsts);
89
90 CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0);
91 ASSERT_EQ(test_result.validation_result,
92 ValidateInstructions(SPV_ENV_VULKAN_1_0));
93 if (test_result.error_str) {
94 EXPECT_THAT(getDiagnosticString(),
95 testing::ContainsRegex(test_result.error_str));
96 }
97 if (test_result.error_str2) {
98 EXPECT_THAT(getDiagnosticString(),
99 testing::ContainsRegex(test_result.error_str2));
100 }
101 }
102
103 INSTANTIATE_TEST_SUITE_P(OnlyOpExtension, ValidateNonSemanticGenerated,
104 Combine(Values(true), Values(false), Values(""),
105 Values(""), Values(TestResult())));
106
107 INSTANTIATE_TEST_SUITE_P(
108 MissingOpExtension, ValidateNonSemanticGenerated,
109 Combine(Values(false), Values(true), Values(""), Values(""),
110 Values(TestResult(
111 SPV_ERROR_INVALID_DATA,
112 "NonSemantic extended instruction sets cannot be declared "
113 "without SPV_KHR_non_semantic_info."))));
114
115 INSTANTIATE_TEST_SUITE_P(NoExtInst, ValidateNonSemanticGenerated,
116 Combine(Values(true), Values(true), Values(""),
117 Values(""), Values(TestResult())));
118
119 INSTANTIATE_TEST_SUITE_P(
120 SimpleGlobalExtInst, ValidateNonSemanticGenerated,
121 Combine(Values(true), Values(true),
122 Values("%result = OpExtInst %void %extinst 123 %i32"), Values(""),
123 Values(TestResult())));
124
125 INSTANTIATE_TEST_SUITE_P(
126 ComplexGlobalExtInst, ValidateNonSemanticGenerated,
127 Combine(Values(true), Values(true),
128 Values("%result = OpExtInst %void %extinst 123 %i32 %u32_2 "
129 "%f32vec4_1234 %u32_0"),
130 Values(""), Values(TestResult())));
131
132 INSTANTIATE_TEST_SUITE_P(
133 SimpleFunctionLevelExtInst, ValidateNonSemanticGenerated,
134 Combine(Values(true), Values(true), Values(""),
135 Values("%result = OpExtInst %void %extinst 123 %i32"),
136 Values(TestResult())));
137
138 INSTANTIATE_TEST_SUITE_P(
139 FunctionTypeReference, ValidateNonSemanticGenerated,
140 Combine(Values(true), Values(true),
141 Values("%result = OpExtInst %void %extinst 123 %func"), Values(""),
142 Values(TestResult())));
143
144 INSTANTIATE_TEST_SUITE_P(
145 EntryPointReference, ValidateNonSemanticGenerated,
146 Combine(Values(true), Values(true), Values(""),
147 Values("%result = OpExtInst %void %extinst 123 %main"),
148 Values(TestResult())));
149
150 INSTANTIATE_TEST_SUITE_P(
151 DecorationGroupReference, ValidateNonSemanticGenerated,
152 Combine(Values(true), Values(true), Values(""),
153 Values("%result = OpExtInst %void %extinst 123 %decorate_group"),
154 Values(TestResult())));
155
156 INSTANTIATE_TEST_SUITE_P(
157 UnknownIDReference, ValidateNonSemanticGenerated,
158 Combine(Values(true), Values(true),
159 Values("%result = OpExtInst %void %extinst 123 %undefined_id"),
160 Values(""),
161 Values(TestResult(SPV_ERROR_INVALID_ID,
162 "ID .* has not been defined"))));
163
164 INSTANTIATE_TEST_SUITE_P(
165 NonSemanticUseInSemantic, ValidateNonSemanticGenerated,
166 Combine(Values(true), Values(true),
167 Values("%result = OpExtInst %f32 %extinst 123 %i32\n"
168 "%invalid = OpConstantComposite %f32vec2 %f32_0 %result"),
169 Values(""),
170 Values(TestResult(SPV_ERROR_INVALID_ID,
171 "in semantic instruction cannot be a "
172 "non-semantic instruction"))));
173
TEST_F(ValidateNonSemanticString,InvalidSectionOpExtInst)174 TEST_F(ValidateNonSemanticString, InvalidSectionOpExtInst) {
175 const std::string spirv = R"(
176 OpCapability Shader
177 OpExtension "SPV_KHR_non_semantic_info"
178 %extinst = OpExtInstImport "NonSemantic.Testing.Set"
179 %test = OpExtInst %void %extinst 4 %void
180 OpMemoryModel Logical GLSL450
181 OpEntryPoint Vertex %main "main"
182 )";
183
184 CompileSuccessfully(spirv);
185 EXPECT_THAT(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
186
187 // there's no specific error for using an OpExtInst too early, it requires a
188 // type so by definition any use of a type in it will be an undefined ID
189 EXPECT_THAT(getDiagnosticString(),
190 HasSubstr("ID 2[%2] has not been defined"));
191 }
192
193 } // namespace
194 } // namespace val
195 } // namespace spvtools
196