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