1fd4e5da5Sopenharmony_ci// Copyright (c) 2016 Google Inc.
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// Basic tests for the ValidationState_t datastructure.
16fd4e5da5Sopenharmony_ci
17fd4e5da5Sopenharmony_ci#include <string>
18fd4e5da5Sopenharmony_ci
19fd4e5da5Sopenharmony_ci#include "gmock/gmock.h"
20fd4e5da5Sopenharmony_ci#include "source/spirv_validator_options.h"
21fd4e5da5Sopenharmony_ci#include "test/unit_spirv.h"
22fd4e5da5Sopenharmony_ci#include "test/val/val_fixtures.h"
23fd4e5da5Sopenharmony_ci
24fd4e5da5Sopenharmony_cinamespace spvtools {
25fd4e5da5Sopenharmony_cinamespace val {
26fd4e5da5Sopenharmony_cinamespace {
27fd4e5da5Sopenharmony_ci
28fd4e5da5Sopenharmony_ciusing ::testing::HasSubstr;
29fd4e5da5Sopenharmony_ci
30fd4e5da5Sopenharmony_ciusing ValidationStateTest = spvtest::ValidateBase<bool>;
31fd4e5da5Sopenharmony_ci
32fd4e5da5Sopenharmony_ciconst char kHeader[] =
33fd4e5da5Sopenharmony_ci    " OpCapability Shader"
34fd4e5da5Sopenharmony_ci    " OpCapability Linkage"
35fd4e5da5Sopenharmony_ci    " OpMemoryModel Logical GLSL450 ";
36fd4e5da5Sopenharmony_ci
37fd4e5da5Sopenharmony_ciconst char kVulkanMemoryHeader[] =
38fd4e5da5Sopenharmony_ci    " OpCapability Shader"
39fd4e5da5Sopenharmony_ci    " OpCapability VulkanMemoryModelKHR"
40fd4e5da5Sopenharmony_ci    " OpExtension \"SPV_KHR_vulkan_memory_model\""
41fd4e5da5Sopenharmony_ci    " OpMemoryModel Logical VulkanKHR ";
42fd4e5da5Sopenharmony_ci
43fd4e5da5Sopenharmony_ciconst char kVoidFVoid[] =
44fd4e5da5Sopenharmony_ci    " %void   = OpTypeVoid"
45fd4e5da5Sopenharmony_ci    " %void_f = OpTypeFunction %void"
46fd4e5da5Sopenharmony_ci    " %func   = OpFunction %void None %void_f"
47fd4e5da5Sopenharmony_ci    " %label  = OpLabel"
48fd4e5da5Sopenharmony_ci    "           OpReturn"
49fd4e5da5Sopenharmony_ci    "           OpFunctionEnd ";
50fd4e5da5Sopenharmony_ci
51fd4e5da5Sopenharmony_ci// k*RecursiveBody examples originally from test/opt/function_test.cpp
52fd4e5da5Sopenharmony_ciconst char* kNonRecursiveBody = R"(
53fd4e5da5Sopenharmony_ciOpEntryPoint Fragment %1 "main"
54fd4e5da5Sopenharmony_ciOpExecutionMode %1 OriginUpperLeft
55fd4e5da5Sopenharmony_ci%void = OpTypeVoid
56fd4e5da5Sopenharmony_ci%4 = OpTypeFunction %void
57fd4e5da5Sopenharmony_ci%float = OpTypeFloat 32
58fd4e5da5Sopenharmony_ci%_struct_6 = OpTypeStruct %float %float
59fd4e5da5Sopenharmony_ci%null = OpConstantNull %_struct_6
60fd4e5da5Sopenharmony_ci%7 = OpTypeFunction %_struct_6
61fd4e5da5Sopenharmony_ci%12 = OpFunction %_struct_6 None %7
62fd4e5da5Sopenharmony_ci%13 = OpLabel
63fd4e5da5Sopenharmony_ciOpReturnValue %null
64fd4e5da5Sopenharmony_ciOpFunctionEnd
65fd4e5da5Sopenharmony_ci%9 = OpFunction %_struct_6 None %7
66fd4e5da5Sopenharmony_ci%10 = OpLabel
67fd4e5da5Sopenharmony_ci%11 = OpFunctionCall %_struct_6 %12
68fd4e5da5Sopenharmony_ciOpReturnValue %null
69fd4e5da5Sopenharmony_ciOpFunctionEnd
70fd4e5da5Sopenharmony_ci%1 = OpFunction %void Pure|Const %4
71fd4e5da5Sopenharmony_ci%8 = OpLabel
72fd4e5da5Sopenharmony_ci%2 = OpFunctionCall %_struct_6 %9
73fd4e5da5Sopenharmony_ciOpKill
74fd4e5da5Sopenharmony_ciOpFunctionEnd
75fd4e5da5Sopenharmony_ci)";
76fd4e5da5Sopenharmony_ci
77fd4e5da5Sopenharmony_ciconst char* kDirectlyRecursiveBody = R"(
78fd4e5da5Sopenharmony_ciOpEntryPoint Fragment %1 "main"
79fd4e5da5Sopenharmony_ciOpExecutionMode %1 OriginUpperLeft
80fd4e5da5Sopenharmony_ci%void = OpTypeVoid
81fd4e5da5Sopenharmony_ci%4 = OpTypeFunction %void
82fd4e5da5Sopenharmony_ci%float = OpTypeFloat 32
83fd4e5da5Sopenharmony_ci%_struct_6 = OpTypeStruct %float %float
84fd4e5da5Sopenharmony_ci%7 = OpTypeFunction %_struct_6
85fd4e5da5Sopenharmony_ci%9 = OpFunction %_struct_6 None %7
86fd4e5da5Sopenharmony_ci%10 = OpLabel
87fd4e5da5Sopenharmony_ci%11 = OpFunctionCall %_struct_6 %9
88fd4e5da5Sopenharmony_ciOpKill
89fd4e5da5Sopenharmony_ciOpFunctionEnd
90fd4e5da5Sopenharmony_ci%1 = OpFunction %void Pure|Const %4
91fd4e5da5Sopenharmony_ci%8 = OpLabel
92fd4e5da5Sopenharmony_ci%2 = OpFunctionCall %_struct_6 %9
93fd4e5da5Sopenharmony_ciOpReturn
94fd4e5da5Sopenharmony_ciOpFunctionEnd
95fd4e5da5Sopenharmony_ci)";
96fd4e5da5Sopenharmony_ci
97fd4e5da5Sopenharmony_ciconst char* kIndirectlyRecursiveBody = R"(
98fd4e5da5Sopenharmony_ciOpEntryPoint Fragment %1 "main"
99fd4e5da5Sopenharmony_ciOpExecutionMode %1 OriginUpperLeft
100fd4e5da5Sopenharmony_ci%void = OpTypeVoid
101fd4e5da5Sopenharmony_ci%4 = OpTypeFunction %void
102fd4e5da5Sopenharmony_ci%float = OpTypeFloat 32
103fd4e5da5Sopenharmony_ci%_struct_6 = OpTypeStruct %float %float
104fd4e5da5Sopenharmony_ci%null = OpConstantNull %_struct_6
105fd4e5da5Sopenharmony_ci%7 = OpTypeFunction %_struct_6
106fd4e5da5Sopenharmony_ci%9 = OpFunction %_struct_6 None %7
107fd4e5da5Sopenharmony_ci%10 = OpLabel
108fd4e5da5Sopenharmony_ci%11 = OpFunctionCall %_struct_6 %12
109fd4e5da5Sopenharmony_ciOpReturnValue %null
110fd4e5da5Sopenharmony_ciOpFunctionEnd
111fd4e5da5Sopenharmony_ci%12 = OpFunction %_struct_6 None %7
112fd4e5da5Sopenharmony_ci%13 = OpLabel
113fd4e5da5Sopenharmony_ci%14 = OpFunctionCall %_struct_6 %9
114fd4e5da5Sopenharmony_ciOpReturnValue %null
115fd4e5da5Sopenharmony_ciOpFunctionEnd
116fd4e5da5Sopenharmony_ci%1 = OpFunction %void Pure|Const %4
117fd4e5da5Sopenharmony_ci%8 = OpLabel
118fd4e5da5Sopenharmony_ci%2 = OpFunctionCall %_struct_6 %9
119fd4e5da5Sopenharmony_ciOpKill
120fd4e5da5Sopenharmony_ciOpFunctionEnd
121fd4e5da5Sopenharmony_ci)";
122fd4e5da5Sopenharmony_ci
123fd4e5da5Sopenharmony_ci// Tests that the instruction count in ValidationState is correct.
124fd4e5da5Sopenharmony_ciTEST_F(ValidationStateTest, CheckNumInstructions) {
125fd4e5da5Sopenharmony_ci  std::string spirv = std::string(kHeader) + "%int = OpTypeInt 32 0";
126fd4e5da5Sopenharmony_ci  CompileSuccessfully(spirv);
127fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
128fd4e5da5Sopenharmony_ci  EXPECT_EQ(size_t(4), vstate_->ordered_instructions().size());
129fd4e5da5Sopenharmony_ci}
130fd4e5da5Sopenharmony_ci
131fd4e5da5Sopenharmony_ci// Tests that the number of global variables in ValidationState is correct.
132fd4e5da5Sopenharmony_ciTEST_F(ValidationStateTest, CheckNumGlobalVars) {
133fd4e5da5Sopenharmony_ci  std::string spirv = std::string(kHeader) + R"(
134fd4e5da5Sopenharmony_ci     %int = OpTypeInt 32 0
135fd4e5da5Sopenharmony_ci%_ptr_int = OpTypePointer Input %int
136fd4e5da5Sopenharmony_ci   %var_1 = OpVariable %_ptr_int Input
137fd4e5da5Sopenharmony_ci   %var_2 = OpVariable %_ptr_int Input
138fd4e5da5Sopenharmony_ci  )";
139fd4e5da5Sopenharmony_ci  CompileSuccessfully(spirv);
140fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
141fd4e5da5Sopenharmony_ci  EXPECT_EQ(unsigned(2), vstate_->num_global_vars());
142fd4e5da5Sopenharmony_ci}
143fd4e5da5Sopenharmony_ci
144fd4e5da5Sopenharmony_ci// Tests that the number of local variables in ValidationState is correct.
145fd4e5da5Sopenharmony_ciTEST_F(ValidationStateTest, CheckNumLocalVars) {
146fd4e5da5Sopenharmony_ci  std::string spirv = std::string(kHeader) + R"(
147fd4e5da5Sopenharmony_ci %int      = OpTypeInt 32 0
148fd4e5da5Sopenharmony_ci %_ptr_int = OpTypePointer Function %int
149fd4e5da5Sopenharmony_ci %voidt    = OpTypeVoid
150fd4e5da5Sopenharmony_ci %funct    = OpTypeFunction %voidt
151fd4e5da5Sopenharmony_ci %main     = OpFunction %voidt None %funct
152fd4e5da5Sopenharmony_ci %entry    = OpLabel
153fd4e5da5Sopenharmony_ci %var_1    = OpVariable %_ptr_int Function
154fd4e5da5Sopenharmony_ci %var_2    = OpVariable %_ptr_int Function
155fd4e5da5Sopenharmony_ci %var_3    = OpVariable %_ptr_int Function
156fd4e5da5Sopenharmony_ci OpReturn
157fd4e5da5Sopenharmony_ci OpFunctionEnd
158fd4e5da5Sopenharmony_ci  )";
159fd4e5da5Sopenharmony_ci  CompileSuccessfully(spirv);
160fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
161fd4e5da5Sopenharmony_ci  EXPECT_EQ(unsigned(3), vstate_->num_local_vars());
162fd4e5da5Sopenharmony_ci}
163fd4e5da5Sopenharmony_ci
164fd4e5da5Sopenharmony_ci// Tests that the "id bound" in ValidationState is correct.
165fd4e5da5Sopenharmony_ciTEST_F(ValidationStateTest, CheckIdBound) {
166fd4e5da5Sopenharmony_ci  std::string spirv = std::string(kHeader) + R"(
167fd4e5da5Sopenharmony_ci %int      = OpTypeInt 32 0
168fd4e5da5Sopenharmony_ci %voidt    = OpTypeVoid
169fd4e5da5Sopenharmony_ci  )";
170fd4e5da5Sopenharmony_ci  CompileSuccessfully(spirv);
171fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
172fd4e5da5Sopenharmony_ci  EXPECT_EQ(unsigned(3), vstate_->getIdBound());
173fd4e5da5Sopenharmony_ci}
174fd4e5da5Sopenharmony_ci
175fd4e5da5Sopenharmony_ci// Tests that the entry_points in ValidationState is correct.
176fd4e5da5Sopenharmony_ciTEST_F(ValidationStateTest, CheckEntryPoints) {
177fd4e5da5Sopenharmony_ci  std::string spirv = std::string(kHeader) +
178fd4e5da5Sopenharmony_ci                      " OpEntryPoint Vertex %func \"shader\"" +
179fd4e5da5Sopenharmony_ci                      std::string(kVoidFVoid);
180fd4e5da5Sopenharmony_ci  CompileSuccessfully(spirv);
181fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
182fd4e5da5Sopenharmony_ci  EXPECT_EQ(size_t(1), vstate_->entry_points().size());
183fd4e5da5Sopenharmony_ci  EXPECT_EQ(spv::Op::OpFunction,
184fd4e5da5Sopenharmony_ci            vstate_->FindDef(vstate_->entry_points()[0])->opcode());
185fd4e5da5Sopenharmony_ci}
186fd4e5da5Sopenharmony_ci
187fd4e5da5Sopenharmony_ciTEST_F(ValidationStateTest, CheckStructMemberLimitOption) {
188fd4e5da5Sopenharmony_ci  spvValidatorOptionsSetUniversalLimit(
189fd4e5da5Sopenharmony_ci      options_, spv_validator_limit_max_struct_members, 32000u);
190fd4e5da5Sopenharmony_ci  EXPECT_EQ(32000u, options_->universal_limits_.max_struct_members);
191fd4e5da5Sopenharmony_ci}
192fd4e5da5Sopenharmony_ci
193fd4e5da5Sopenharmony_ciTEST_F(ValidationStateTest, CheckNumGlobalVarsLimitOption) {
194fd4e5da5Sopenharmony_ci  spvValidatorOptionsSetUniversalLimit(
195fd4e5da5Sopenharmony_ci      options_, spv_validator_limit_max_global_variables, 100u);
196fd4e5da5Sopenharmony_ci  EXPECT_EQ(100u, options_->universal_limits_.max_global_variables);
197fd4e5da5Sopenharmony_ci}
198fd4e5da5Sopenharmony_ci
199fd4e5da5Sopenharmony_ciTEST_F(ValidationStateTest, CheckNumLocalVarsLimitOption) {
200fd4e5da5Sopenharmony_ci  spvValidatorOptionsSetUniversalLimit(
201fd4e5da5Sopenharmony_ci      options_, spv_validator_limit_max_local_variables, 100u);
202fd4e5da5Sopenharmony_ci  EXPECT_EQ(100u, options_->universal_limits_.max_local_variables);
203fd4e5da5Sopenharmony_ci}
204fd4e5da5Sopenharmony_ci
205fd4e5da5Sopenharmony_ciTEST_F(ValidationStateTest, CheckStructDepthLimitOption) {
206fd4e5da5Sopenharmony_ci  spvValidatorOptionsSetUniversalLimit(
207fd4e5da5Sopenharmony_ci      options_, spv_validator_limit_max_struct_depth, 100u);
208fd4e5da5Sopenharmony_ci  EXPECT_EQ(100u, options_->universal_limits_.max_struct_depth);
209fd4e5da5Sopenharmony_ci}
210fd4e5da5Sopenharmony_ci
211fd4e5da5Sopenharmony_ciTEST_F(ValidationStateTest, CheckSwitchBranchesLimitOption) {
212fd4e5da5Sopenharmony_ci  spvValidatorOptionsSetUniversalLimit(
213fd4e5da5Sopenharmony_ci      options_, spv_validator_limit_max_switch_branches, 100u);
214fd4e5da5Sopenharmony_ci  EXPECT_EQ(100u, options_->universal_limits_.max_switch_branches);
215fd4e5da5Sopenharmony_ci}
216fd4e5da5Sopenharmony_ci
217fd4e5da5Sopenharmony_ciTEST_F(ValidationStateTest, CheckFunctionArgsLimitOption) {
218fd4e5da5Sopenharmony_ci  spvValidatorOptionsSetUniversalLimit(
219fd4e5da5Sopenharmony_ci      options_, spv_validator_limit_max_function_args, 100u);
220fd4e5da5Sopenharmony_ci  EXPECT_EQ(100u, options_->universal_limits_.max_function_args);
221fd4e5da5Sopenharmony_ci}
222fd4e5da5Sopenharmony_ci
223fd4e5da5Sopenharmony_ciTEST_F(ValidationStateTest, CheckCFGDepthLimitOption) {
224fd4e5da5Sopenharmony_ci  spvValidatorOptionsSetUniversalLimit(
225fd4e5da5Sopenharmony_ci      options_, spv_validator_limit_max_control_flow_nesting_depth, 100u);
226fd4e5da5Sopenharmony_ci  EXPECT_EQ(100u, options_->universal_limits_.max_control_flow_nesting_depth);
227fd4e5da5Sopenharmony_ci}
228fd4e5da5Sopenharmony_ci
229fd4e5da5Sopenharmony_ciTEST_F(ValidationStateTest, CheckAccessChainIndexesLimitOption) {
230fd4e5da5Sopenharmony_ci  spvValidatorOptionsSetUniversalLimit(
231fd4e5da5Sopenharmony_ci      options_, spv_validator_limit_max_access_chain_indexes, 100u);
232fd4e5da5Sopenharmony_ci  EXPECT_EQ(100u, options_->universal_limits_.max_access_chain_indexes);
233fd4e5da5Sopenharmony_ci}
234fd4e5da5Sopenharmony_ci
235fd4e5da5Sopenharmony_ciTEST_F(ValidationStateTest, CheckNonRecursiveBodyGood) {
236fd4e5da5Sopenharmony_ci  std::string spirv = std::string(kHeader) + kNonRecursiveBody;
237fd4e5da5Sopenharmony_ci  CompileSuccessfully(spirv);
238fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
239fd4e5da5Sopenharmony_ci}
240fd4e5da5Sopenharmony_ci
241fd4e5da5Sopenharmony_ciTEST_F(ValidationStateTest, CheckVulkanNonRecursiveBodyGood) {
242fd4e5da5Sopenharmony_ci  std::string spirv = std::string(kVulkanMemoryHeader) + kNonRecursiveBody;
243fd4e5da5Sopenharmony_ci  CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
244fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_SUCCESS,
245fd4e5da5Sopenharmony_ci            ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
246fd4e5da5Sopenharmony_ci}
247fd4e5da5Sopenharmony_ci
248fd4e5da5Sopenharmony_ciTEST_F(ValidationStateTest, CheckDirectlyRecursiveBodyGood) {
249fd4e5da5Sopenharmony_ci  std::string spirv = std::string(kHeader) + kDirectlyRecursiveBody;
250fd4e5da5Sopenharmony_ci  CompileSuccessfully(spirv);
251fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
252fd4e5da5Sopenharmony_ci}
253fd4e5da5Sopenharmony_ci
254fd4e5da5Sopenharmony_ciTEST_F(ValidationStateTest, CheckVulkanDirectlyRecursiveBodyBad) {
255fd4e5da5Sopenharmony_ci  std::string spirv = std::string(kVulkanMemoryHeader) + kDirectlyRecursiveBody;
256fd4e5da5Sopenharmony_ci  CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
257fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
258fd4e5da5Sopenharmony_ci            ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
259fd4e5da5Sopenharmony_ci  EXPECT_THAT(getDiagnosticString(),
260fd4e5da5Sopenharmony_ci              AnyVUID("VUID-StandaloneSpirv-None-04634"));
261fd4e5da5Sopenharmony_ci  EXPECT_THAT(getDiagnosticString(),
262fd4e5da5Sopenharmony_ci              HasSubstr("Entry points may not have a call graph with cycles.\n "
263fd4e5da5Sopenharmony_ci                        " %1 = OpFunction %void Pure|Const %3\n"));
264fd4e5da5Sopenharmony_ci}
265fd4e5da5Sopenharmony_ci
266fd4e5da5Sopenharmony_ciTEST_F(ValidationStateTest, CheckIndirectlyRecursiveBodyGood) {
267fd4e5da5Sopenharmony_ci  std::string spirv = std::string(kHeader) + kIndirectlyRecursiveBody;
268fd4e5da5Sopenharmony_ci  CompileSuccessfully(spirv);
269fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
270fd4e5da5Sopenharmony_ci}
271fd4e5da5Sopenharmony_ci
272fd4e5da5Sopenharmony_ciTEST_F(ValidationStateTest, CheckVulkanIndirectlyRecursiveBodyBad) {
273fd4e5da5Sopenharmony_ci  std::string spirv =
274fd4e5da5Sopenharmony_ci      std::string(kVulkanMemoryHeader) + kIndirectlyRecursiveBody;
275fd4e5da5Sopenharmony_ci  CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1);
276fd4e5da5Sopenharmony_ci  EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
277fd4e5da5Sopenharmony_ci            ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1));
278fd4e5da5Sopenharmony_ci  EXPECT_THAT(getDiagnosticString(),
279fd4e5da5Sopenharmony_ci              AnyVUID("VUID-StandaloneSpirv-None-04634"));
280fd4e5da5Sopenharmony_ci  EXPECT_THAT(getDiagnosticString(),
281fd4e5da5Sopenharmony_ci              HasSubstr("Entry points may not have a call graph with cycles.\n "
282fd4e5da5Sopenharmony_ci                        " %1 = OpFunction %void Pure|Const %3\n"));
283fd4e5da5Sopenharmony_ci}
284fd4e5da5Sopenharmony_ci
285fd4e5da5Sopenharmony_ci}  // namespace
286fd4e5da5Sopenharmony_ci}  // namespace val
287fd4e5da5Sopenharmony_ci}  // namespace spvtools
288