1 // Copyright (c) 2016 Google Inc.
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 Universal Limits. (Section 2.17 of the SPIR-V Spec)
16 
17 #include <sstream>
18 #include <string>
19 #include <utility>
20 
21 #include "gmock/gmock.h"
22 #include "test/unit_spirv.h"
23 #include "test/val/val_fixtures.h"
24 
25 namespace spvtools {
26 namespace val {
27 namespace {
28 
29 using ::testing::HasSubstr;
30 using ::testing::MatchesRegex;
31 
32 using ValidateLimits = spvtest::ValidateBase<bool>;
33 
34 std::string header = R"(
35      OpCapability Shader
36      OpCapability Linkage
37      OpMemoryModel Logical GLSL450
38 )";
39 
TEST_F(ValidateLimits,IdLargerThanBoundBad)40 TEST_F(ValidateLimits, IdLargerThanBoundBad) {
41   std::string str = header + R"(
42 ;  %i32 has ID 1
43 %i32    = OpTypeInt 32 1
44 %c      = OpConstant %i32 100
45 
46 ; Fake an instruction with 64 as the result id.
47 ; !64 = OpConstantNull %i32
48 !0x3002e !1 !64
49 )";
50 
51   CompileSuccessfully(str);
52   ASSERT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
53   EXPECT_THAT(
54       getDiagnosticString(),
55       HasSubstr("Result <id> '64' must be less than the ID bound '3'."));
56 }
57 
TEST_F(ValidateLimits,IdEqualToBoundBad)58 TEST_F(ValidateLimits, IdEqualToBoundBad) {
59   std::string str = header + R"(
60 ;  %i32 has ID 1
61 %i32    = OpTypeInt 32 1
62 %c      = OpConstant %i32 100
63 
64 ; Fake an instruction with 64 as the result id.
65 ; !64 = OpConstantNull %i32
66 !0x3002e !1 !64
67 )";
68 
69   CompileSuccessfully(str);
70 
71   // The largest ID used in this program is 64. Let's overwrite the ID bound in
72   // the header to be 64. This should result in an error because all IDs must
73   // satisfy: 0 < id < bound.
74   OverwriteAssembledBinary(3, 64);
75 
76   ASSERT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
77   EXPECT_THAT(
78       getDiagnosticString(),
79       HasSubstr("Result <id> '64' must be less than the ID bound '64'."));
80 }
81 
TEST_F(ValidateLimits,IdBoundTooBigDeaultLimit)82 TEST_F(ValidateLimits, IdBoundTooBigDeaultLimit) {
83   std::string str = header;
84 
85   CompileSuccessfully(str);
86 
87   // The largest ID used in this program is 64. Let's overwrite the ID bound in
88   // the header to be 64. This should result in an error because all IDs must
89   // satisfy: 0 < id < bound.
90   OverwriteAssembledBinary(3, 0x4FFFFF);
91 
92   ASSERT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
93   EXPECT_THAT(getDiagnosticString(),
94               HasSubstr("Invalid SPIR-V.  The id bound is larger than the max "
95                         "id bound 4194303."));
96 }
97 
TEST_F(ValidateLimits,IdBoundAtSetLimit)98 TEST_F(ValidateLimits, IdBoundAtSetLimit) {
99   std::string str = header;
100 
101   CompileSuccessfully(str);
102 
103   // The largest ID used in this program is 64. Let's overwrite the ID bound in
104   // the header to be 64. This should result in an error because all IDs must
105   // satisfy: 0 < id < bound.
106   uint32_t id_bound = 0x4FFFFF;
107 
108   OverwriteAssembledBinary(3, id_bound);
109   getValidatorOptions()->universal_limits_.max_id_bound = id_bound;
110 
111   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
112 }
113 
TEST_F(ValidateLimits,IdBoundJustAboveSetLimit)114 TEST_F(ValidateLimits, IdBoundJustAboveSetLimit) {
115   std::string str = header;
116 
117   CompileSuccessfully(str);
118 
119   // The largest ID used in this program is 64. Let's overwrite the ID bound in
120   // the header to be 64. This should result in an error because all IDs must
121   // satisfy: 0 < id < bound.
122   uint32_t id_bound = 5242878;
123 
124   OverwriteAssembledBinary(3, id_bound);
125   getValidatorOptions()->universal_limits_.max_id_bound = id_bound - 1;
126 
127   ASSERT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
128   EXPECT_THAT(getDiagnosticString(),
129               HasSubstr("Invalid SPIR-V.  The id bound is larger than the max "
130                         "id bound 5242877."));
131 }
132 
TEST_F(ValidateLimits,IdBoundAtInMaxLimit)133 TEST_F(ValidateLimits, IdBoundAtInMaxLimit) {
134   std::string str = header;
135 
136   CompileSuccessfully(str);
137 
138   uint32_t id_bound = std::numeric_limits<uint32_t>::max();
139 
140   OverwriteAssembledBinary(3, id_bound);
141   getValidatorOptions()->universal_limits_.max_id_bound = id_bound;
142 
143   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
144 }
145 
TEST_F(ValidateLimits,StructNumMembersGood)146 TEST_F(ValidateLimits, StructNumMembersGood) {
147   std::ostringstream spirv;
148   spirv << header << R"(
149 %1 = OpTypeInt 32 0
150 %2 = OpTypeStruct)";
151   for (int i = 0; i < 16383; ++i) {
152     spirv << " %1";
153   }
154   CompileSuccessfully(spirv.str());
155   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
156 }
157 
TEST_F(ValidateLimits,StructNumMembersExceededBad)158 TEST_F(ValidateLimits, StructNumMembersExceededBad) {
159   std::ostringstream spirv;
160   spirv << header << R"(
161 %1 = OpTypeInt 32 0
162 %2 = OpTypeStruct)";
163   for (int i = 0; i < 16384; ++i) {
164     spirv << " %1";
165   }
166   CompileSuccessfully(spirv.str());
167   ASSERT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
168   EXPECT_THAT(getDiagnosticString(),
169               HasSubstr("Number of OpTypeStruct members (16384) has exceeded "
170                         "the limit (16383)."));
171 }
172 
TEST_F(ValidateLimits,CustomizedStructNumMembersGood)173 TEST_F(ValidateLimits, CustomizedStructNumMembersGood) {
174   std::ostringstream spirv;
175   spirv << header << R"(
176 %1 = OpTypeInt 32 0
177 %2 = OpTypeStruct)";
178   for (int i = 0; i < 32000; ++i) {
179     spirv << " %1";
180   }
181   spvValidatorOptionsSetUniversalLimit(
182       options_, spv_validator_limit_max_struct_members, 32000u);
183   CompileSuccessfully(spirv.str());
184   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
185 }
186 
TEST_F(ValidateLimits,CustomizedStructNumMembersBad)187 TEST_F(ValidateLimits, CustomizedStructNumMembersBad) {
188   std::ostringstream spirv;
189   spirv << header << R"(
190 %1 = OpTypeInt 32 0
191 %2 = OpTypeStruct)";
192   for (int i = 0; i < 32001; ++i) {
193     spirv << " %1";
194   }
195   spvValidatorOptionsSetUniversalLimit(
196       options_, spv_validator_limit_max_struct_members, 32000u);
197   CompileSuccessfully(spirv.str());
198   ASSERT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
199   EXPECT_THAT(getDiagnosticString(),
200               HasSubstr("Number of OpTypeStruct members (32001) has exceeded "
201                         "the limit (32000)."));
202 }
203 
204 // Valid: Switch statement has 16,383 branches.
TEST_F(ValidateLimits,SwitchNumBranchesGood)205 TEST_F(ValidateLimits, SwitchNumBranchesGood) {
206   std::ostringstream spirv;
207   spirv << header << R"(
208 %1 = OpTypeVoid
209 %2 = OpTypeFunction %1
210 %3 = OpTypeInt 32 0
211 %4 = OpConstant %3 1234
212 %5 = OpFunction %1 None %2
213 %7 = OpLabel
214 %8 = OpIAdd %3 %4 %4
215      OpSelectionMerge %10 None
216      OpSwitch %4 %10)";
217 
218   // Now add the (literal, label) pairs
219   for (int i = 0; i < 16383; ++i) {
220     spirv << " 1 %10";
221   }
222 
223   spirv << R"(
224 %10 = OpLabel
225 OpReturn
226 OpFunctionEnd
227   )";
228 
229   CompileSuccessfully(spirv.str());
230   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
231 }
232 
233 // Invalid: Switch statement has 16,384 branches.
TEST_F(ValidateLimits,SwitchNumBranchesBad)234 TEST_F(ValidateLimits, SwitchNumBranchesBad) {
235   std::ostringstream spirv;
236   spirv << header << R"(
237 %1 = OpTypeVoid
238 %2 = OpTypeFunction %1
239 %3 = OpTypeInt 32 0
240 %4 = OpConstant %3 1234
241 %5 = OpFunction %1 None %2
242 %7 = OpLabel
243 %8 = OpIAdd %3 %4 %4
244      OpSelectionMerge %10 None
245      OpSwitch %4 %10)";
246 
247   // Now add the (literal, label) pairs
248   for (int i = 0; i < 16384; ++i) {
249     spirv << " 1 %10";
250   }
251 
252   spirv << R"(
253 %10 = OpLabel
254 OpReturn
255 OpFunctionEnd
256   )";
257 
258   CompileSuccessfully(spirv.str());
259   ASSERT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
260   EXPECT_THAT(getDiagnosticString(),
261               HasSubstr("Number of (literal, label) pairs in OpSwitch (16384) "
262                         "exceeds the limit (16383)."));
263 }
264 
265 // Valid: Switch statement has 10 branches (limit is 10)
TEST_F(ValidateLimits,CustomizedSwitchNumBranchesGood)266 TEST_F(ValidateLimits, CustomizedSwitchNumBranchesGood) {
267   std::ostringstream spirv;
268   spirv << header << R"(
269 %1 = OpTypeVoid
270 %2 = OpTypeFunction %1
271 %3 = OpTypeInt 32 0
272 %4 = OpConstant %3 1234
273 %5 = OpFunction %1 None %2
274 %7 = OpLabel
275 %8 = OpIAdd %3 %4 %4
276      OpSelectionMerge %10 None
277      OpSwitch %4 %10)";
278 
279   // Now add the (literal, label) pairs
280   for (int i = 0; i < 10; ++i) {
281     spirv << " 1 %10";
282   }
283 
284   spirv << R"(
285 %10 = OpLabel
286 OpReturn
287 OpFunctionEnd
288   )";
289 
290   spvValidatorOptionsSetUniversalLimit(
291       options_, spv_validator_limit_max_switch_branches, 10u);
292   CompileSuccessfully(spirv.str());
293   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
294 }
295 
296 // Invalid: Switch statement has 11 branches (limit is 10)
TEST_F(ValidateLimits,CustomizedSwitchNumBranchesBad)297 TEST_F(ValidateLimits, CustomizedSwitchNumBranchesBad) {
298   std::ostringstream spirv;
299   spirv << header << R"(
300 %1 = OpTypeVoid
301 %2 = OpTypeFunction %1
302 %3 = OpTypeInt 32 0
303 %4 = OpConstant %3 1234
304 %5 = OpFunction %1 None %2
305 %7 = OpLabel
306 %8 = OpIAdd %3 %4 %4
307      OpSelectionMerge %10 None
308      OpSwitch %4 %10)";
309 
310   // Now add the (literal, label) pairs
311   for (int i = 0; i < 11; ++i) {
312     spirv << " 1 %10";
313   }
314 
315   spirv << R"(
316 %10 = OpLabel
317 OpReturn
318 OpFunctionEnd
319   )";
320 
321   spvValidatorOptionsSetUniversalLimit(
322       options_, spv_validator_limit_max_switch_branches, 10u);
323   CompileSuccessfully(spirv.str());
324   ASSERT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
325   EXPECT_THAT(getDiagnosticString(),
326               HasSubstr("Number of (literal, label) pairs in OpSwitch (11) "
327                         "exceeds the limit (10)."));
328 }
329 
330 // Valid: OpTypeFunction with 255 arguments.
TEST_F(ValidateLimits,OpTypeFunctionGood)331 TEST_F(ValidateLimits, OpTypeFunctionGood) {
332   int num_args = 255;
333   std::ostringstream spirv;
334   spirv << header << R"(
335 %1 = OpTypeInt 32 0
336 %2 = OpTypeFunction %1)";
337   // add parameters
338   for (int i = 0; i < num_args; ++i) {
339     spirv << " %1";
340   }
341   CompileSuccessfully(spirv.str());
342   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
343 }
344 
345 // Invalid: OpTypeFunction with 256 arguments. (limit is 255 according to the
346 // spec Universal Limits (2.17).
TEST_F(ValidateLimits,OpTypeFunctionBad)347 TEST_F(ValidateLimits, OpTypeFunctionBad) {
348   int num_args = 256;
349   std::ostringstream spirv;
350   spirv << header << R"(
351 %1 = OpTypeInt 32 0
352 %2 = OpTypeFunction %1)";
353   for (int i = 0; i < num_args; ++i) {
354     spirv << " %1";
355   }
356   CompileSuccessfully(spirv.str());
357   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
358   EXPECT_THAT(getDiagnosticString(),
359               HasSubstr("OpTypeFunction may not take more than 255 arguments. "
360                         "OpTypeFunction <id> '2[%2]' has 256 arguments."));
361 }
362 
363 // Valid: OpTypeFunction with 100 arguments (Custom limit: 100)
TEST_F(ValidateLimits,CustomizedOpTypeFunctionGood)364 TEST_F(ValidateLimits, CustomizedOpTypeFunctionGood) {
365   int num_args = 100;
366   std::ostringstream spirv;
367   spirv << header << R"(
368 %1 = OpTypeInt 32 0
369 %2 = OpTypeFunction %1)";
370   // add parameters
371   for (int i = 0; i < num_args; ++i) {
372     spirv << " %1";
373   }
374   spvValidatorOptionsSetUniversalLimit(
375       options_, spv_validator_limit_max_function_args, 100u);
376   CompileSuccessfully(spirv.str());
377   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
378 }
379 
380 // Invalid: OpTypeFunction with 101 arguments. (Custom limit: 100)
TEST_F(ValidateLimits,CustomizedOpTypeFunctionBad)381 TEST_F(ValidateLimits, CustomizedOpTypeFunctionBad) {
382   int num_args = 101;
383   std::ostringstream spirv;
384   spirv << header << R"(
385 %1 = OpTypeInt 32 0
386 %2 = OpTypeFunction %1)";
387   for (int i = 0; i < num_args; ++i) {
388     spirv << " %1";
389   }
390   spvValidatorOptionsSetUniversalLimit(
391       options_, spv_validator_limit_max_function_args, 100u);
392   CompileSuccessfully(spirv.str());
393   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
394   EXPECT_THAT(getDiagnosticString(),
395               HasSubstr("OpTypeFunction may not take more than 100 arguments. "
396                         "OpTypeFunction <id> '2[%2]' has 101 arguments."));
397 }
398 
399 // Valid: module has 65,535 global variables.
TEST_F(ValidateLimits,NumGlobalVarsGood)400 TEST_F(ValidateLimits, NumGlobalVarsGood) {
401   int num_globals = 65535;
402   std::ostringstream spirv;
403   spirv << header << R"(
404      %int = OpTypeInt 32 0
405 %_ptr_int = OpTypePointer Input %int
406   )";
407 
408   for (int i = 0; i < num_globals; ++i) {
409     spirv << "%var_" << i << " = OpVariable %_ptr_int Input\n";
410   }
411 
412   CompileSuccessfully(spirv.str());
413   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
414 }
415 
416 // Invalid: module has 65,536 global variables (limit is 65,535).
TEST_F(ValidateLimits,NumGlobalVarsBad)417 TEST_F(ValidateLimits, NumGlobalVarsBad) {
418   int num_globals = 65536;
419   std::ostringstream spirv;
420   spirv << header << R"(
421      %int = OpTypeInt 32 0
422 %_ptr_int = OpTypePointer Input %int
423   )";
424 
425   for (int i = 0; i < num_globals; ++i) {
426     spirv << "%var_" << i << " = OpVariable %_ptr_int Input\n";
427   }
428 
429   CompileSuccessfully(spirv.str());
430   EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
431   EXPECT_THAT(getDiagnosticString(),
432               HasSubstr("Number of Global Variables (Storage Class other than "
433                         "'Function') exceeded the valid limit (65535)."));
434 }
435 
436 // Valid: module has 50 global variables (limit is 50)
TEST_F(ValidateLimits,CustomizedNumGlobalVarsGood)437 TEST_F(ValidateLimits, CustomizedNumGlobalVarsGood) {
438   int num_globals = 50;
439   std::ostringstream spirv;
440   spirv << header << R"(
441      %int = OpTypeInt 32 0
442 %_ptr_int = OpTypePointer Input %int
443   )";
444 
445   for (int i = 0; i < num_globals; ++i) {
446     spirv << "%var_" << i << " = OpVariable %_ptr_int Input\n";
447   }
448 
449   spvValidatorOptionsSetUniversalLimit(
450       options_, spv_validator_limit_max_global_variables, 50u);
451   CompileSuccessfully(spirv.str());
452   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
453 }
454 
455 // Invalid: module has 51 global variables (limit is 50).
TEST_F(ValidateLimits,CustomizedNumGlobalVarsBad)456 TEST_F(ValidateLimits, CustomizedNumGlobalVarsBad) {
457   int num_globals = 51;
458   std::ostringstream spirv;
459   spirv << header << R"(
460      %int = OpTypeInt 32 0
461 %_ptr_int = OpTypePointer Input %int
462   )";
463 
464   for (int i = 0; i < num_globals; ++i) {
465     spirv << "%var_" << i << " = OpVariable %_ptr_int Input\n";
466   }
467 
468   spvValidatorOptionsSetUniversalLimit(
469       options_, spv_validator_limit_max_global_variables, 50u);
470   CompileSuccessfully(spirv.str());
471   EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
472   EXPECT_THAT(getDiagnosticString(),
473               HasSubstr("Number of Global Variables (Storage Class other than "
474                         "'Function') exceeded the valid limit (50)."));
475 }
476 
477 // Valid: module has 524,287 local variables.
478 // Note: AppVeyor limits process time to 300s.  For a VisualStudio Debug
479 // build, going up to 524287 local variables gets too close to that
480 // limit.  So test with an artificially lowered limit.
TEST_F(ValidateLimits,NumLocalVarsGoodArtificiallyLowLimit5K)481 TEST_F(ValidateLimits, NumLocalVarsGoodArtificiallyLowLimit5K) {
482   int num_locals = 5000;
483   std::ostringstream spirv;
484   spirv << header << R"(
485  %int      = OpTypeInt 32 0
486  %_ptr_int = OpTypePointer Function %int
487  %voidt    = OpTypeVoid
488  %funct    = OpTypeFunction %voidt
489  %main     = OpFunction %voidt None %funct
490  %entry    = OpLabel
491   )";
492 
493   for (int i = 0; i < num_locals; ++i) {
494     spirv << "%var_" << i << " = OpVariable %_ptr_int Function\n";
495   }
496 
497   spirv << R"(
498     OpReturn
499     OpFunctionEnd
500   )";
501 
502   CompileSuccessfully(spirv.str());
503   // Artificially limit it.
504   spvValidatorOptionsSetUniversalLimit(
505       options_, spv_validator_limit_max_local_variables, num_locals);
506   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
507 }
508 
509 // Invalid: module has 524,288 local variables (limit is 524,287).
510 // Artificially limit the check to 5001.
TEST_F(ValidateLimits,NumLocalVarsBadArtificiallyLowLimit5K)511 TEST_F(ValidateLimits, NumLocalVarsBadArtificiallyLowLimit5K) {
512   int num_locals = 5001;
513   std::ostringstream spirv;
514   spirv << header << R"(
515  %int      = OpTypeInt 32 0
516  %_ptr_int = OpTypePointer Function %int
517  %voidt    = OpTypeVoid
518  %funct    = OpTypeFunction %voidt
519  %main     = OpFunction %voidt None %funct
520  %entry    = OpLabel
521   )";
522 
523   for (int i = 0; i < num_locals; ++i) {
524     spirv << "%var_" << i << " = OpVariable %_ptr_int Function\n";
525   }
526 
527   spirv << R"(
528     OpReturn
529     OpFunctionEnd
530   )";
531 
532   CompileSuccessfully(spirv.str());
533   spvValidatorOptionsSetUniversalLimit(
534       options_, spv_validator_limit_max_local_variables, 5000u);
535   EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
536   EXPECT_THAT(getDiagnosticString(),
537               HasSubstr("Number of local variables ('Function' Storage Class) "
538                         "exceeded the valid limit (5000)."));
539 }
540 
541 // Valid: module has 100 local variables (limit is 100).
TEST_F(ValidateLimits,CustomizedNumLocalVarsGood)542 TEST_F(ValidateLimits, CustomizedNumLocalVarsGood) {
543   int num_locals = 100;
544   std::ostringstream spirv;
545   spirv << header << R"(
546  %int      = OpTypeInt 32 0
547  %_ptr_int = OpTypePointer Function %int
548  %voidt    = OpTypeVoid
549  %funct    = OpTypeFunction %voidt
550  %main     = OpFunction %voidt None %funct
551  %entry    = OpLabel
552   )";
553 
554   for (int i = 0; i < num_locals; ++i) {
555     spirv << "%var_" << i << " = OpVariable %_ptr_int Function\n";
556   }
557 
558   spirv << R"(
559     OpReturn
560     OpFunctionEnd
561   )";
562 
563   spvValidatorOptionsSetUniversalLimit(
564       options_, spv_validator_limit_max_local_variables, 100u);
565   CompileSuccessfully(spirv.str());
566   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
567 }
568 
569 // Invalid: module has 101 local variables (limit is 100).
TEST_F(ValidateLimits,CustomizedNumLocalVarsBad)570 TEST_F(ValidateLimits, CustomizedNumLocalVarsBad) {
571   int num_locals = 101;
572   std::ostringstream spirv;
573   spirv << header << R"(
574  %int      = OpTypeInt 32 0
575  %_ptr_int = OpTypePointer Function %int
576  %voidt    = OpTypeVoid
577  %funct    = OpTypeFunction %voidt
578  %main     = OpFunction %voidt None %funct
579  %entry    = OpLabel
580   )";
581 
582   for (int i = 0; i < num_locals; ++i) {
583     spirv << "%var_" << i << " = OpVariable %_ptr_int Function\n";
584   }
585 
586   spirv << R"(
587     OpReturn
588     OpFunctionEnd
589   )";
590 
591   spvValidatorOptionsSetUniversalLimit(
592       options_, spv_validator_limit_max_local_variables, 100u);
593   CompileSuccessfully(spirv.str());
594   EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
595   EXPECT_THAT(getDiagnosticString(),
596               HasSubstr("Number of local variables ('Function' Storage Class) "
597                         "exceeded the valid limit (100)."));
598 }
599 
600 // Valid: Structure nesting depth of 255.
TEST_F(ValidateLimits,StructNestingDepthGood)601 TEST_F(ValidateLimits, StructNestingDepthGood) {
602   std::ostringstream spirv;
603   spirv << header << R"(
604     %int = OpTypeInt 32 0
605     %s_depth_1  = OpTypeStruct %int
606   )";
607   for (auto i = 2; i <= 255; ++i) {
608     spirv << "%s_depth_" << i << " = OpTypeStruct %int %s_depth_" << i - 1;
609     spirv << "\n";
610   }
611   CompileSuccessfully(spirv.str());
612   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
613 }
614 
615 // Invalid: Structure nesting depth of 256.
TEST_F(ValidateLimits,StructNestingDepthBad)616 TEST_F(ValidateLimits, StructNestingDepthBad) {
617   std::ostringstream spirv;
618   spirv << header << R"(
619     %int = OpTypeInt 32 0
620     %s_depth_1  = OpTypeStruct %int
621   )";
622   for (auto i = 2; i <= 256; ++i) {
623     spirv << "%s_depth_" << i << " = OpTypeStruct %int %s_depth_" << i - 1;
624     spirv << "\n";
625   }
626   CompileSuccessfully(spirv.str());
627   EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
628   EXPECT_THAT(
629       getDiagnosticString(),
630       HasSubstr(
631           "Structure Nesting Depth may not be larger than 255. Found 256."));
632 }
633 
634 // Valid: Structure nesting depth of 100 (limit is 100).
TEST_F(ValidateLimits,CustomizedStructNestingDepthGood)635 TEST_F(ValidateLimits, CustomizedStructNestingDepthGood) {
636   std::ostringstream spirv;
637   spirv << header << R"(
638     %int = OpTypeInt 32 0
639     %s_depth_1  = OpTypeStruct %int
640   )";
641   for (auto i = 2; i <= 100; ++i) {
642     spirv << "%s_depth_" << i << " = OpTypeStruct %int %s_depth_" << i - 1;
643     spirv << "\n";
644   }
645   spvValidatorOptionsSetUniversalLimit(
646       options_, spv_validator_limit_max_struct_depth, 100u);
647   CompileSuccessfully(spirv.str());
648   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
649 }
650 
651 // Invalid: Structure nesting depth of 101 (limit is 100).
TEST_F(ValidateLimits,CustomizedStructNestingDepthBad)652 TEST_F(ValidateLimits, CustomizedStructNestingDepthBad) {
653   std::ostringstream spirv;
654   spirv << header << R"(
655     %int = OpTypeInt 32 0
656     %s_depth_1  = OpTypeStruct %int
657   )";
658   for (auto i = 2; i <= 101; ++i) {
659     spirv << "%s_depth_" << i << " = OpTypeStruct %int %s_depth_" << i - 1;
660     spirv << "\n";
661   }
662   spvValidatorOptionsSetUniversalLimit(
663       options_, spv_validator_limit_max_struct_depth, 100u);
664   CompileSuccessfully(spirv.str());
665   EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
666   EXPECT_THAT(
667       getDiagnosticString(),
668       HasSubstr(
669           "Structure Nesting Depth may not be larger than 100. Found 101."));
670 }
671 
672 // clang-format off
673 // Generates an SPIRV program with the given control flow nesting depth
GenerateSpirvProgramWithCfgNestingDepth(std::string & str,int depth)674 void GenerateSpirvProgramWithCfgNestingDepth(std::string& str, int depth) {
675   std::ostringstream spirv;
676   spirv << header << R"(
677        %void = OpTypeVoid
678           %3 = OpTypeFunction %void
679        %bool = OpTypeBool
680          %12 = OpConstantTrue %bool
681        %main = OpFunction %void None %3
682           %5 = OpLabel
683                OpBranch %6
684           %6 = OpLabel
685                OpLoopMerge %8 %9 None
686                OpBranch %10
687          %10 = OpLabel
688                OpBranchConditional %12 %7 %8
689           %7 = OpLabel
690   )";
691   int first_id = 13;
692   int last_id = 14;
693   // We already have 1 level of nesting due to the Loop.
694   int num_if_conditions = depth-1;
695   int largest_index = first_id + 2*num_if_conditions - 2;
696   for (int i = first_id; i <= largest_index; i = i + 2) {
697     spirv << "OpSelectionMerge %" << i+1 << " None" << "\n";
698     spirv << "OpBranchConditional %12 " << "%" << i << " %" << i+1 << "\n";
699     spirv << "%" << i << " = OpLabel" << "\n";
700   }
701   spirv << "OpBranch %9" << "\n";
702 
703   for (int i = largest_index+1; i > last_id; i = i - 2) {
704     spirv << "%" << i << " = OpLabel" << "\n";
705     spirv << "OpBranch %" << i-2 << "\n";
706   }
707   spirv << "%" << last_id << " = OpLabel" << "\n";
708   spirv << "OpBranch %9" << "\n";
709   spirv << R"(
710     %9 = OpLabel
711     OpBranch %6
712     %8 = OpLabel
713     OpReturn
714     OpFunctionEnd
715   )";
716   str = spirv.str();
717 }
718 // clang-format on
719 
720 // Invalid: Control Flow Nesting depth is 1024. (limit is 1023).
TEST_F(ValidateLimits,ControlFlowDepthBad)721 TEST_F(ValidateLimits, ControlFlowDepthBad) {
722   std::string spirv;
723   GenerateSpirvProgramWithCfgNestingDepth(spirv, 1024);
724   CompileSuccessfully(spirv);
725   EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
726   EXPECT_THAT(getDiagnosticString(),
727               HasSubstr("Maximum Control Flow nesting depth exceeded."));
728 }
729 
730 // Valid: Control Flow Nesting depth is 10 (custom limit: 10).
TEST_F(ValidateLimits,CustomizedControlFlowDepthGood)731 TEST_F(ValidateLimits, CustomizedControlFlowDepthGood) {
732   std::string spirv;
733   GenerateSpirvProgramWithCfgNestingDepth(spirv, 10);
734   spvValidatorOptionsSetUniversalLimit(
735       options_, spv_validator_limit_max_control_flow_nesting_depth, 10u);
736   CompileSuccessfully(spirv);
737   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
738 }
739 
740 // Invalid: Control Flow Nesting depth is 11. (custom limit: 10).
TEST_F(ValidateLimits,CustomizedControlFlowDepthBad)741 TEST_F(ValidateLimits, CustomizedControlFlowDepthBad) {
742   std::string spirv;
743   GenerateSpirvProgramWithCfgNestingDepth(spirv, 11);
744   spvValidatorOptionsSetUniversalLimit(
745       options_, spv_validator_limit_max_control_flow_nesting_depth, 10u);
746   CompileSuccessfully(spirv);
747   EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
748   EXPECT_THAT(getDiagnosticString(),
749               HasSubstr("Maximum Control Flow nesting depth exceeded."));
750 }
751 
752 // Valid. The purpose here is to test the CFG depth calculation code when a loop
753 // continue target is the loop iteself. It also exercises the case where a loop
754 // is unreachable.
TEST_F(ValidateLimits,ControlFlowNoEntryToLoopGood)755 TEST_F(ValidateLimits, ControlFlowNoEntryToLoopGood) {
756   std::string str = header + R"(
757            OpName %entry "entry"
758            OpName %loop "loop"
759            OpName %exit "exit"
760 %voidt   = OpTypeVoid
761 %boolt   = OpTypeBool
762 %undef   = OpUndef %boolt
763 %funct   = OpTypeFunction %voidt
764 %main    = OpFunction %voidt None %funct
765 %entry   = OpLabel
766            OpBranch %exit
767 %loop    = OpLabel
768            OpLoopMerge %dead %loop None
769            OpBranchConditional %undef %loop %loop
770 %dead    = OpLabel
771            OpUnreachable
772 %exit    = OpLabel
773            OpReturn
774            OpFunctionEnd
775   )";
776   CompileSuccessfully(str);
777   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
778 }
779 
780 }  // namespace
781 }  // namespace val
782 }  // namespace spvtools
783