• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2015-2016 The Khronos Group 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 #include <cassert>
16 #include <cstdio>
17 #include <cstring>
18 #include <iostream>
19 #include <vector>
20 
21 #include "source/spirv_target_env.h"
22 #include "source/spirv_validator_options.h"
23 #include "spirv-tools/libspirv.hpp"
24 #include "tools/io.h"
25 #include "tools/util/cli_consumer.h"
26 
print_usage(char * argv0)27 void print_usage(char* argv0) {
28   std::string target_env_list = spvTargetEnvList(36, 105);
29   printf(
30       R"(%s - Validate a SPIR-V binary file.
31 
32 USAGE: %s [options] [<filename>]
33 
34 The SPIR-V binary is read from <filename>. If no file is specified,
35 or if the filename is "-", then the binary is read from standard input.
36 
37 NOTE: The validator is a work in progress.
38 
39 Options:
40   -h, --help                       Print this help.
41   --max-struct-members             <maximum number of structure members allowed>
42   --max-struct-depth               <maximum allowed nesting depth of structures>
43   --max-local-variables            <maximum number of local variables allowed>
44   --max-global-variables           <maximum number of global variables allowed>
45   --max-switch-branches            <maximum number of branches allowed in switch statements>
46   --max-function-args              <maximum number arguments allowed per function>
47   --max-control-flow-nesting-depth <maximum Control Flow nesting depth allowed>
48   --max-access-chain-indexes       <maximum number of indexes allowed to use for Access Chain instructions>
49   --max-id-bound                   <maximum value for the id bound>
50   --relax-logical-pointer          Allow allocating an object of a pointer type and returning
51                                    a pointer value from a function in logical addressing mode
52   --relax-block-layout             Enable VK_KHR_relaxed_block_layout when checking standard
53                                    uniform, storage buffer, and push constant layouts.
54                                    This is the default when targeting Vulkan 1.1 or later.
55   --uniform-buffer-standard-layout Enable VK_KHR_uniform_buffer_standard_layout when checking standard
56                                    uniform buffer layouts.
57   --scalar-block-layout            Enable VK_EXT_scalar_block_layout when checking standard
58                                    uniform, storage buffer, and push constant layouts.  Scalar layout
59                                    rules are more permissive than relaxed block layout so in effect
60                                    this will override the --relax-block-layout option.
61   --workgroup-scalar-block-layout  Enable scalar block layout when checking Workgroup block layouts.
62   --skip-block-layout              Skip checking standard uniform/storage buffer layout.
63                                    Overrides any --relax-block-layout or --scalar-block-layout option.
64   --relax-struct-store             Allow store from one struct type to a
65                                    different type with compatible layout and
66                                    members.
67   --allow-localsizeid              Allow use of the LocalSizeId decoration where it would otherwise not
68                                    be allowed by the target environment.
69   --before-hlsl-legalization       Allows code patterns that are intended to be
70                                    fixed by spirv-opt's legalization passes.
71   --version                        Display validator version information.
72   --target-env                     {%s}
73                                    Use validation rules from the specified environment.
74 )",
75       argv0, argv0, target_env_list.c_str());
76 }
77 
main(int argc,char ** argv)78 int main(int argc, char** argv) {
79   const char* inFile = nullptr;
80   spv_target_env target_env = SPV_ENV_UNIVERSAL_1_6;
81   spvtools::ValidatorOptions options;
82   bool continue_processing = true;
83   int return_code = 0;
84 
85   for (int argi = 1; continue_processing && argi < argc; ++argi) {
86     const char* cur_arg = argv[argi];
87     if ('-' == cur_arg[0]) {
88       if (0 == strncmp(cur_arg, "--max-", 6)) {
89         if (argi + 1 < argc) {
90           spv_validator_limit limit_type;
91           if (spvParseUniversalLimitsOptions(cur_arg, &limit_type)) {
92             uint32_t limit = 0;
93             if (sscanf(argv[++argi], "%u", &limit)) {
94               options.SetUniversalLimit(limit_type, limit);
95             } else {
96               fprintf(stderr, "error: missing argument to %s\n", cur_arg);
97               continue_processing = false;
98               return_code = 1;
99             }
100           } else {
101             fprintf(stderr, "error: unrecognized option: %s\n", cur_arg);
102             continue_processing = false;
103             return_code = 1;
104           }
105         } else {
106           fprintf(stderr, "error: Missing argument to %s\n", cur_arg);
107           continue_processing = false;
108           return_code = 1;
109         }
110       } else if (0 == strcmp(cur_arg, "--version")) {
111         printf("%s\n", spvSoftwareVersionDetailsString());
112         printf(
113             "Targets:\n  %s\n  %s\n  %s\n  %s\n  %s\n  %s\n  %s\n  %s\n  %s\n  "
114             "%s\n %s\n %s\n %s\n",
115             spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_0),
116             spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_1),
117             spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_2),
118             spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_3),
119             spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_4),
120             spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_5),
121             spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_6),
122             spvTargetEnvDescription(SPV_ENV_OPENCL_2_2),
123             spvTargetEnvDescription(SPV_ENV_VULKAN_1_0),
124             spvTargetEnvDescription(SPV_ENV_VULKAN_1_1),
125             spvTargetEnvDescription(SPV_ENV_VULKAN_1_1_SPIRV_1_4),
126             spvTargetEnvDescription(SPV_ENV_VULKAN_1_2),
127             spvTargetEnvDescription(SPV_ENV_VULKAN_1_3));
128         continue_processing = false;
129         return_code = 0;
130       } else if (0 == strcmp(cur_arg, "--help") || 0 == strcmp(cur_arg, "-h")) {
131         print_usage(argv[0]);
132         continue_processing = false;
133         return_code = 0;
134       } else if (0 == strcmp(cur_arg, "--target-env")) {
135         if (argi + 1 < argc) {
136           const auto env_str = argv[++argi];
137           if (!spvParseTargetEnv(env_str, &target_env)) {
138             fprintf(stderr, "error: Unrecognized target env: %s\n", env_str);
139             continue_processing = false;
140             return_code = 1;
141           }
142         } else {
143           fprintf(stderr, "error: Missing argument to --target-env\n");
144           continue_processing = false;
145           return_code = 1;
146         }
147       } else if (0 == strcmp(cur_arg, "--before-hlsl-legalization")) {
148         options.SetBeforeHlslLegalization(true);
149       } else if (0 == strcmp(cur_arg, "--relax-logical-pointer")) {
150         options.SetRelaxLogicalPointer(true);
151       } else if (0 == strcmp(cur_arg, "--relax-block-layout")) {
152         options.SetRelaxBlockLayout(true);
153       } else if (0 == strcmp(cur_arg, "--uniform-buffer-standard-layout")) {
154         options.SetUniformBufferStandardLayout(true);
155       } else if (0 == strcmp(cur_arg, "--scalar-block-layout")) {
156         options.SetScalarBlockLayout(true);
157       } else if (0 == strcmp(cur_arg, "--workgroup-scalar-block-layout")) {
158         options.SetWorkgroupScalarBlockLayout(true);
159       } else if (0 == strcmp(cur_arg, "--skip-block-layout")) {
160         options.SetSkipBlockLayout(true);
161       } else if (0 == strcmp(cur_arg, "--allow-localsizeid")) {
162         options.SetAllowLocalSizeId(true);
163       } else if (0 == strcmp(cur_arg, "--relax-struct-store")) {
164         options.SetRelaxStructStore(true);
165       } else if (0 == cur_arg[1]) {
166         // Setting a filename of "-" to indicate stdin.
167         if (!inFile) {
168           inFile = cur_arg;
169         } else {
170           fprintf(stderr, "error: More than one input file specified\n");
171           continue_processing = false;
172           return_code = 1;
173         }
174       } else {
175         print_usage(argv[0]);
176         continue_processing = false;
177         return_code = 1;
178       }
179     } else {
180       if (!inFile) {
181         inFile = cur_arg;
182       } else {
183         fprintf(stderr, "error: More than one input file specified\n");
184         continue_processing = false;
185         return_code = 1;
186       }
187     }
188   }
189 
190   // Exit if command line parsing was not successful.
191   if (!continue_processing) {
192     return return_code;
193   }
194 
195   std::vector<uint32_t> contents;
196   if (!ReadBinaryFile<uint32_t>(inFile, &contents)) return 1;
197 
198   spvtools::SpirvTools tools(target_env);
199   tools.SetMessageConsumer(spvtools::utils::CLIMessageConsumer);
200 
201   bool succeed = tools.Validate(contents.data(), contents.size(), options);
202 
203   return !succeed;
204 }
205