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