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
24namespace spvtools {
25namespace val {
26namespace {
27
28using ::testing::HasSubstr;
29using ::testing::MatchesRegex;
30
31using ValidateLimits = spvtest::ValidateBase<bool>;
32
33std::string header = R"(
34     OpCapability Shader
35     OpCapability Linkage
36     OpMemoryModel Logical GLSL450
37)";
38
39TEST_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
57TEST_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
81TEST_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
97TEST_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
113TEST_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
132TEST_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
145TEST_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
157TEST_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
172TEST_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
186TEST_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.
204TEST_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
224OpReturn
225OpFunctionEnd
226  )";
227
228  CompileSuccessfully(spirv.str());
229  ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
230}
231
232// Invalid: Switch statement has 16,384 branches.
233TEST_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
253OpReturn
254OpFunctionEnd
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)
265TEST_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
285OpReturn
286OpFunctionEnd
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)
296TEST_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
316OpReturn
317OpFunctionEnd
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.
330TEST_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).
346TEST_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)
363TEST_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)
380TEST_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.
399TEST_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).
416TEST_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)
436TEST_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).
455TEST_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.
480TEST_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.
510TEST_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).
541TEST_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).
569TEST_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.
600TEST_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.
615TEST_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).
634TEST_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).
651TEST_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
673void 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).
720TEST_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).
730TEST_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).
740TEST_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.
754TEST_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