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