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      OpSwitch %4 %10)";
216 
217   // Now add the (literal, label) pairs
218   for (int i = 0; i < 16383; ++i) {
219     spirv << " 1 %10";
220   }
221 
222   spirv << R"(
223 %10 = OpLabel
224 OpReturn
225 OpFunctionEnd
226   )";
227 
228   CompileSuccessfully(spirv.str());
229   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
230 }
231 
232 // Invalid: Switch statement has 16,384 branches.
TEST_F(ValidateLimits,SwitchNumBranchesBad)233 TEST_F(ValidateLimits, SwitchNumBranchesBad) {
234   std::ostringstream spirv;
235   spirv << header << R"(
236 %1 = OpTypeVoid
237 %2 = OpTypeFunction %1
238 %3 = OpTypeInt 32 0
239 %4 = OpConstant %3 1234
240 %5 = OpFunction %1 None %2
241 %7 = OpLabel
242 %8 = OpIAdd %3 %4 %4
243      OpSwitch %4 %10)";
244 
245   // Now add the (literal, label) pairs
246   for (int i = 0; i < 16384; ++i) {
247     spirv << " 1 %10";
248   }
249 
250   spirv << R"(
251 %10 = OpLabel
252 OpReturn
253 OpFunctionEnd
254   )";
255 
256   CompileSuccessfully(spirv.str());
257   ASSERT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
258   EXPECT_THAT(getDiagnosticString(),
259               HasSubstr("Number of (literal, label) pairs in OpSwitch (16384) "
260                         "exceeds the limit (16383)."));
261 }
262 
263 // Valid: Switch statement has 10 branches (limit is 10)
TEST_F(ValidateLimits,CustomizedSwitchNumBranchesGood)264 TEST_F(ValidateLimits, CustomizedSwitchNumBranchesGood) {
265   std::ostringstream spirv;
266   spirv << header << R"(
267 %1 = OpTypeVoid
268 %2 = OpTypeFunction %1
269 %3 = OpTypeInt 32 0
270 %4 = OpConstant %3 1234
271 %5 = OpFunction %1 None %2
272 %7 = OpLabel
273 %8 = OpIAdd %3 %4 %4
274      OpSwitch %4 %10)";
275 
276   // Now add the (literal, label) pairs
277   for (int i = 0; i < 10; ++i) {
278     spirv << " 1 %10";
279   }
280 
281   spirv << R"(
282 %10 = OpLabel
283 OpReturn
284 OpFunctionEnd
285   )";
286 
287   spvValidatorOptionsSetUniversalLimit(
288       options_, spv_validator_limit_max_switch_branches, 10u);
289   CompileSuccessfully(spirv.str());
290   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
291 }
292 
293 // Invalid: Switch statement has 11 branches (limit is 10)
TEST_F(ValidateLimits,CustomizedSwitchNumBranchesBad)294 TEST_F(ValidateLimits, CustomizedSwitchNumBranchesBad) {
295   std::ostringstream spirv;
296   spirv << header << R"(
297 %1 = OpTypeVoid
298 %2 = OpTypeFunction %1
299 %3 = OpTypeInt 32 0
300 %4 = OpConstant %3 1234
301 %5 = OpFunction %1 None %2
302 %7 = OpLabel
303 %8 = OpIAdd %3 %4 %4
304      OpSwitch %4 %10)";
305 
306   // Now add the (literal, label) pairs
307   for (int i = 0; i < 11; ++i) {
308     spirv << " 1 %10";
309   }
310 
311   spirv << R"(
312 %10 = OpLabel
313 OpReturn
314 OpFunctionEnd
315   )";
316 
317   spvValidatorOptionsSetUniversalLimit(
318       options_, spv_validator_limit_max_switch_branches, 10u);
319   CompileSuccessfully(spirv.str());
320   ASSERT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
321   EXPECT_THAT(getDiagnosticString(),
322               HasSubstr("Number of (literal, label) pairs in OpSwitch (11) "
323                         "exceeds the limit (10)."));
324 }
325 
326 // Valid: OpTypeFunction with 255 arguments.
TEST_F(ValidateLimits,OpTypeFunctionGood)327 TEST_F(ValidateLimits, OpTypeFunctionGood) {
328   int num_args = 255;
329   std::ostringstream spirv;
330   spirv << header << R"(
331 %1 = OpTypeInt 32 0
332 %2 = OpTypeFunction %1)";
333   // add parameters
334   for (int i = 0; i < num_args; ++i) {
335     spirv << " %1";
336   }
337   CompileSuccessfully(spirv.str());
338   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
339 }
340 
341 // Invalid: OpTypeFunction with 256 arguments. (limit is 255 according to the
342 // spec Universal Limits (2.17).
TEST_F(ValidateLimits,OpTypeFunctionBad)343 TEST_F(ValidateLimits, OpTypeFunctionBad) {
344   int num_args = 256;
345   std::ostringstream spirv;
346   spirv << header << R"(
347 %1 = OpTypeInt 32 0
348 %2 = OpTypeFunction %1)";
349   for (int i = 0; i < num_args; ++i) {
350     spirv << " %1";
351   }
352   CompileSuccessfully(spirv.str());
353   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
354   EXPECT_THAT(getDiagnosticString(),
355               HasSubstr("OpTypeFunction may not take more than 255 arguments. "
356                         "OpTypeFunction <id> '2[%2]' has 256 arguments."));
357 }
358 
359 // Valid: OpTypeFunction with 100 arguments (Custom limit: 100)
TEST_F(ValidateLimits,CustomizedOpTypeFunctionGood)360 TEST_F(ValidateLimits, CustomizedOpTypeFunctionGood) {
361   int num_args = 100;
362   std::ostringstream spirv;
363   spirv << header << R"(
364 %1 = OpTypeInt 32 0
365 %2 = OpTypeFunction %1)";
366   // add parameters
367   for (int i = 0; i < num_args; ++i) {
368     spirv << " %1";
369   }
370   spvValidatorOptionsSetUniversalLimit(
371       options_, spv_validator_limit_max_function_args, 100u);
372   CompileSuccessfully(spirv.str());
373   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
374 }
375 
376 // Invalid: OpTypeFunction with 101 arguments. (Custom limit: 100)
TEST_F(ValidateLimits,CustomizedOpTypeFunctionBad)377 TEST_F(ValidateLimits, CustomizedOpTypeFunctionBad) {
378   int num_args = 101;
379   std::ostringstream spirv;
380   spirv << header << R"(
381 %1 = OpTypeInt 32 0
382 %2 = OpTypeFunction %1)";
383   for (int i = 0; i < num_args; ++i) {
384     spirv << " %1";
385   }
386   spvValidatorOptionsSetUniversalLimit(
387       options_, spv_validator_limit_max_function_args, 100u);
388   CompileSuccessfully(spirv.str());
389   EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
390   EXPECT_THAT(getDiagnosticString(),
391               HasSubstr("OpTypeFunction may not take more than 100 arguments. "
392                         "OpTypeFunction <id> '2[%2]' has 101 arguments."));
393 }
394 
395 // Valid: module has 65,535 global variables.
TEST_F(ValidateLimits,NumGlobalVarsGood)396 TEST_F(ValidateLimits, NumGlobalVarsGood) {
397   int num_globals = 65535;
398   std::ostringstream spirv;
399   spirv << header << R"(
400      %int = OpTypeInt 32 0
401 %_ptr_int = OpTypePointer Input %int
402   )";
403 
404   for (int i = 0; i < num_globals; ++i) {
405     spirv << "%var_" << i << " = OpVariable %_ptr_int Input\n";
406   }
407 
408   CompileSuccessfully(spirv.str());
409   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
410 }
411 
412 // Invalid: module has 65,536 global variables (limit is 65,535).
TEST_F(ValidateLimits,NumGlobalVarsBad)413 TEST_F(ValidateLimits, NumGlobalVarsBad) {
414   int num_globals = 65536;
415   std::ostringstream spirv;
416   spirv << header << R"(
417      %int = OpTypeInt 32 0
418 %_ptr_int = OpTypePointer Input %int
419   )";
420 
421   for (int i = 0; i < num_globals; ++i) {
422     spirv << "%var_" << i << " = OpVariable %_ptr_int Input\n";
423   }
424 
425   CompileSuccessfully(spirv.str());
426   EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
427   EXPECT_THAT(getDiagnosticString(),
428               HasSubstr("Number of Global Variables (Storage Class other than "
429                         "'Function') exceeded the valid limit (65535)."));
430 }
431 
432 // Valid: module has 50 global variables (limit is 50)
TEST_F(ValidateLimits,CustomizedNumGlobalVarsGood)433 TEST_F(ValidateLimits, CustomizedNumGlobalVarsGood) {
434   int num_globals = 50;
435   std::ostringstream spirv;
436   spirv << header << R"(
437      %int = OpTypeInt 32 0
438 %_ptr_int = OpTypePointer Input %int
439   )";
440 
441   for (int i = 0; i < num_globals; ++i) {
442     spirv << "%var_" << i << " = OpVariable %_ptr_int Input\n";
443   }
444 
445   spvValidatorOptionsSetUniversalLimit(
446       options_, spv_validator_limit_max_global_variables, 50u);
447   CompileSuccessfully(spirv.str());
448   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
449 }
450 
451 // Invalid: module has 51 global variables (limit is 50).
TEST_F(ValidateLimits,CustomizedNumGlobalVarsBad)452 TEST_F(ValidateLimits, CustomizedNumGlobalVarsBad) {
453   int num_globals = 51;
454   std::ostringstream spirv;
455   spirv << header << R"(
456      %int = OpTypeInt 32 0
457 %_ptr_int = OpTypePointer Input %int
458   )";
459 
460   for (int i = 0; i < num_globals; ++i) {
461     spirv << "%var_" << i << " = OpVariable %_ptr_int Input\n";
462   }
463 
464   spvValidatorOptionsSetUniversalLimit(
465       options_, spv_validator_limit_max_global_variables, 50u);
466   CompileSuccessfully(spirv.str());
467   EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
468   EXPECT_THAT(getDiagnosticString(),
469               HasSubstr("Number of Global Variables (Storage Class other than "
470                         "'Function') exceeded the valid limit (50)."));
471 }
472 
473 // Valid: module has 524,287 local variables.
474 // Note: AppVeyor limits process time to 300s.  For a VisualStudio Debug
475 // build, going up to 524287 local variables gets too close to that
476 // limit.  So test with an artificially lowered limit.
TEST_F(ValidateLimits,NumLocalVarsGoodArtificiallyLowLimit5K)477 TEST_F(ValidateLimits, NumLocalVarsGoodArtificiallyLowLimit5K) {
478   int num_locals = 5000;
479   std::ostringstream spirv;
480   spirv << header << R"(
481  %int      = OpTypeInt 32 0
482  %_ptr_int = OpTypePointer Function %int
483  %voidt    = OpTypeVoid
484  %funct    = OpTypeFunction %voidt
485  %main     = OpFunction %voidt None %funct
486  %entry    = OpLabel
487   )";
488 
489   for (int i = 0; i < num_locals; ++i) {
490     spirv << "%var_" << i << " = OpVariable %_ptr_int Function\n";
491   }
492 
493   spirv << R"(
494     OpReturn
495     OpFunctionEnd
496   )";
497 
498   CompileSuccessfully(spirv.str());
499   // Artificially limit it.
500   spvValidatorOptionsSetUniversalLimit(
501       options_, spv_validator_limit_max_local_variables, num_locals);
502   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
503 }
504 
505 // Invalid: module has 524,288 local variables (limit is 524,287).
506 // Artificially limit the check to 5001.
TEST_F(ValidateLimits,NumLocalVarsBadArtificiallyLowLimit5K)507 TEST_F(ValidateLimits, NumLocalVarsBadArtificiallyLowLimit5K) {
508   int num_locals = 5001;
509   std::ostringstream spirv;
510   spirv << header << R"(
511  %int      = OpTypeInt 32 0
512  %_ptr_int = OpTypePointer Function %int
513  %voidt    = OpTypeVoid
514  %funct    = OpTypeFunction %voidt
515  %main     = OpFunction %voidt None %funct
516  %entry    = OpLabel
517   )";
518 
519   for (int i = 0; i < num_locals; ++i) {
520     spirv << "%var_" << i << " = OpVariable %_ptr_int Function\n";
521   }
522 
523   spirv << R"(
524     OpReturn
525     OpFunctionEnd
526   )";
527 
528   CompileSuccessfully(spirv.str());
529   spvValidatorOptionsSetUniversalLimit(
530       options_, spv_validator_limit_max_local_variables, 5000u);
531   EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
532   EXPECT_THAT(getDiagnosticString(),
533               HasSubstr("Number of local variables ('Function' Storage Class) "
534                         "exceeded the valid limit (5000)."));
535 }
536 
537 // Valid: module has 100 local variables (limit is 100).
TEST_F(ValidateLimits,CustomizedNumLocalVarsGood)538 TEST_F(ValidateLimits, CustomizedNumLocalVarsGood) {
539   int num_locals = 100;
540   std::ostringstream spirv;
541   spirv << header << R"(
542  %int      = OpTypeInt 32 0
543  %_ptr_int = OpTypePointer Function %int
544  %voidt    = OpTypeVoid
545  %funct    = OpTypeFunction %voidt
546  %main     = OpFunction %voidt None %funct
547  %entry    = OpLabel
548   )";
549 
550   for (int i = 0; i < num_locals; ++i) {
551     spirv << "%var_" << i << " = OpVariable %_ptr_int Function\n";
552   }
553 
554   spirv << R"(
555     OpReturn
556     OpFunctionEnd
557   )";
558 
559   spvValidatorOptionsSetUniversalLimit(
560       options_, spv_validator_limit_max_local_variables, 100u);
561   CompileSuccessfully(spirv.str());
562   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
563 }
564 
565 // Invalid: module has 101 local variables (limit is 100).
TEST_F(ValidateLimits,CustomizedNumLocalVarsBad)566 TEST_F(ValidateLimits, CustomizedNumLocalVarsBad) {
567   int num_locals = 101;
568   std::ostringstream spirv;
569   spirv << header << R"(
570  %int      = OpTypeInt 32 0
571  %_ptr_int = OpTypePointer Function %int
572  %voidt    = OpTypeVoid
573  %funct    = OpTypeFunction %voidt
574  %main     = OpFunction %voidt None %funct
575  %entry    = OpLabel
576   )";
577 
578   for (int i = 0; i < num_locals; ++i) {
579     spirv << "%var_" << i << " = OpVariable %_ptr_int Function\n";
580   }
581 
582   spirv << R"(
583     OpReturn
584     OpFunctionEnd
585   )";
586 
587   spvValidatorOptionsSetUniversalLimit(
588       options_, spv_validator_limit_max_local_variables, 100u);
589   CompileSuccessfully(spirv.str());
590   EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
591   EXPECT_THAT(getDiagnosticString(),
592               HasSubstr("Number of local variables ('Function' Storage Class) "
593                         "exceeded the valid limit (100)."));
594 }
595 
596 // Valid: Structure nesting depth of 255.
TEST_F(ValidateLimits,StructNestingDepthGood)597 TEST_F(ValidateLimits, StructNestingDepthGood) {
598   std::ostringstream spirv;
599   spirv << header << R"(
600     %int = OpTypeInt 32 0
601     %s_depth_1  = OpTypeStruct %int
602   )";
603   for (auto i = 2; i <= 255; ++i) {
604     spirv << "%s_depth_" << i << " = OpTypeStruct %int %s_depth_" << i - 1;
605     spirv << "\n";
606   }
607   CompileSuccessfully(spirv.str());
608   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
609 }
610 
611 // Invalid: Structure nesting depth of 256.
TEST_F(ValidateLimits,StructNestingDepthBad)612 TEST_F(ValidateLimits, StructNestingDepthBad) {
613   std::ostringstream spirv;
614   spirv << header << R"(
615     %int = OpTypeInt 32 0
616     %s_depth_1  = OpTypeStruct %int
617   )";
618   for (auto i = 2; i <= 256; ++i) {
619     spirv << "%s_depth_" << i << " = OpTypeStruct %int %s_depth_" << i - 1;
620     spirv << "\n";
621   }
622   CompileSuccessfully(spirv.str());
623   EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
624   EXPECT_THAT(
625       getDiagnosticString(),
626       HasSubstr(
627           "Structure Nesting Depth may not be larger than 255. Found 256."));
628 }
629 
630 // Valid: Structure nesting depth of 100 (limit is 100).
TEST_F(ValidateLimits,CustomizedStructNestingDepthGood)631 TEST_F(ValidateLimits, CustomizedStructNestingDepthGood) {
632   std::ostringstream spirv;
633   spirv << header << R"(
634     %int = OpTypeInt 32 0
635     %s_depth_1  = OpTypeStruct %int
636   )";
637   for (auto i = 2; i <= 100; ++i) {
638     spirv << "%s_depth_" << i << " = OpTypeStruct %int %s_depth_" << i - 1;
639     spirv << "\n";
640   }
641   spvValidatorOptionsSetUniversalLimit(
642       options_, spv_validator_limit_max_struct_depth, 100u);
643   CompileSuccessfully(spirv.str());
644   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
645 }
646 
647 // Invalid: Structure nesting depth of 101 (limit is 100).
TEST_F(ValidateLimits,CustomizedStructNestingDepthBad)648 TEST_F(ValidateLimits, CustomizedStructNestingDepthBad) {
649   std::ostringstream spirv;
650   spirv << header << R"(
651     %int = OpTypeInt 32 0
652     %s_depth_1  = OpTypeStruct %int
653   )";
654   for (auto i = 2; i <= 101; ++i) {
655     spirv << "%s_depth_" << i << " = OpTypeStruct %int %s_depth_" << i - 1;
656     spirv << "\n";
657   }
658   spvValidatorOptionsSetUniversalLimit(
659       options_, spv_validator_limit_max_struct_depth, 100u);
660   CompileSuccessfully(spirv.str());
661   EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
662   EXPECT_THAT(
663       getDiagnosticString(),
664       HasSubstr(
665           "Structure Nesting Depth may not be larger than 100. Found 101."));
666 }
667 
668 // clang-format off
669 // Generates an SPIRV program with the given control flow nesting depth
GenerateSpirvProgramWithCfgNestingDepth(std::string & str,int depth)670 void GenerateSpirvProgramWithCfgNestingDepth(std::string& str, int depth) {
671   std::ostringstream spirv;
672   spirv << header << R"(
673        %void = OpTypeVoid
674           %3 = OpTypeFunction %void
675        %bool = OpTypeBool
676          %12 = OpConstantTrue %bool
677        %main = OpFunction %void None %3
678           %5 = OpLabel
679                OpBranch %6
680           %6 = OpLabel
681                OpLoopMerge %8 %9 None
682                OpBranch %10
683          %10 = OpLabel
684                OpBranchConditional %12 %7 %8
685           %7 = OpLabel
686   )";
687   int first_id = 13;
688   int last_id = 14;
689   // We already have 1 level of nesting due to the Loop.
690   int num_if_conditions = depth-1;
691   int largest_index = first_id + 2*num_if_conditions - 2;
692   for (int i = first_id; i <= largest_index; i = i + 2) {
693     spirv << "OpSelectionMerge %" << i+1 << " None" << "\n";
694     spirv << "OpBranchConditional %12 " << "%" << i << " %" << i+1 << "\n";
695     spirv << "%" << i << " = OpLabel" << "\n";
696   }
697   spirv << "OpBranch %9" << "\n";
698 
699   for (int i = largest_index+1; i > last_id; i = i - 2) {
700     spirv << "%" << i << " = OpLabel" << "\n";
701     spirv << "OpBranch %" << i-2 << "\n";
702   }
703   spirv << "%" << last_id << " = OpLabel" << "\n";
704   spirv << "OpBranch %9" << "\n";
705   spirv << R"(
706     %9 = OpLabel
707     OpBranch %6
708     %8 = OpLabel
709     OpReturn
710     OpFunctionEnd
711   )";
712   str = spirv.str();
713 }
714 // clang-format on
715 
716 // Invalid: Control Flow Nesting depth is 1024. (limit is 1023).
TEST_F(ValidateLimits,ControlFlowDepthBad)717 TEST_F(ValidateLimits, ControlFlowDepthBad) {
718   std::string spirv;
719   GenerateSpirvProgramWithCfgNestingDepth(spirv, 1024);
720   CompileSuccessfully(spirv);
721   EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
722   EXPECT_THAT(getDiagnosticString(),
723               HasSubstr("Maximum Control Flow nesting depth exceeded."));
724 }
725 
726 // Valid: Control Flow Nesting depth is 10 (custom limit: 10).
TEST_F(ValidateLimits,CustomizedControlFlowDepthGood)727 TEST_F(ValidateLimits, CustomizedControlFlowDepthGood) {
728   std::string spirv;
729   GenerateSpirvProgramWithCfgNestingDepth(spirv, 10);
730   spvValidatorOptionsSetUniversalLimit(
731       options_, spv_validator_limit_max_control_flow_nesting_depth, 10u);
732   CompileSuccessfully(spirv);
733   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
734 }
735 
736 // Invalid: Control Flow Nesting depth is 11. (custom limit: 10).
TEST_F(ValidateLimits,CustomizedControlFlowDepthBad)737 TEST_F(ValidateLimits, CustomizedControlFlowDepthBad) {
738   std::string spirv;
739   GenerateSpirvProgramWithCfgNestingDepth(spirv, 11);
740   spvValidatorOptionsSetUniversalLimit(
741       options_, spv_validator_limit_max_control_flow_nesting_depth, 10u);
742   CompileSuccessfully(spirv);
743   EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions());
744   EXPECT_THAT(getDiagnosticString(),
745               HasSubstr("Maximum Control Flow nesting depth exceeded."));
746 }
747 
748 // Valid. The purpose here is to test the CFG depth calculation code when a loop
749 // continue target is the loop iteself. It also exercises the case where a loop
750 // is unreachable.
TEST_F(ValidateLimits,ControlFlowNoEntryToLoopGood)751 TEST_F(ValidateLimits, ControlFlowNoEntryToLoopGood) {
752   std::string str = header + R"(
753            OpName %entry "entry"
754            OpName %loop "loop"
755            OpName %exit "exit"
756 %voidt   = OpTypeVoid
757 %boolt   = OpTypeBool
758 %undef   = OpUndef %boolt
759 %funct   = OpTypeFunction %voidt
760 %main    = OpFunction %voidt None %funct
761 %entry   = OpLabel
762            OpBranch %exit
763 %loop    = OpLabel
764            OpLoopMerge %dead %loop None
765            OpBranchConditional %undef %loop %loop
766 %dead    = OpLabel
767            OpUnreachable
768 %exit    = OpLabel
769            OpReturn
770            OpFunctionEnd
771   )";
772   CompileSuccessfully(str);
773   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
774 }
775 
776 }  // namespace
777 }  // namespace val
778 }  // namespace spvtools
779