• 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   --before-hlsl-legalization       Allows code patterns that are intended to be
68                                    fixed by spirv-opt's legalization passes.
69   --version                        Display validator version information.
70   --target-env                     {%s}
71                                    Use validation rules from the specified environment.
72 )",
73       argv0, argv0, target_env_list.c_str());
74 }
75 
main(int argc,char ** argv)76 int main(int argc, char** argv) {
77   const char* inFile = nullptr;
78   spv_target_env target_env = SPV_ENV_UNIVERSAL_1_5;
79   spvtools::ValidatorOptions options;
80   bool continue_processing = true;
81   int return_code = 0;
82 
83   for (int argi = 1; continue_processing && argi < argc; ++argi) {
84     const char* cur_arg = argv[argi];
85     if ('-' == cur_arg[0]) {
86       if (0 == strncmp(cur_arg, "--max-", 6)) {
87         if (argi + 1 < argc) {
88           spv_validator_limit limit_type;
89           if (spvParseUniversalLimitsOptions(cur_arg, &limit_type)) {
90             uint32_t limit = 0;
91             if (sscanf(argv[++argi], "%u", &limit)) {
92               options.SetUniversalLimit(limit_type, limit);
93             } else {
94               fprintf(stderr, "error: missing argument to %s\n", cur_arg);
95               continue_processing = false;
96               return_code = 1;
97             }
98           } else {
99             fprintf(stderr, "error: unrecognized option: %s\n", cur_arg);
100             continue_processing = false;
101             return_code = 1;
102           }
103         } else {
104           fprintf(stderr, "error: Missing argument to %s\n", cur_arg);
105           continue_processing = false;
106           return_code = 1;
107         }
108       } else if (0 == strcmp(cur_arg, "--version")) {
109         printf("%s\n", spvSoftwareVersionDetailsString());
110         printf(
111             "Targets:\n  %s\n  %s\n  %s\n  %s\n  %s\n  %s\n  %s\n  %s\n  %s\n  "
112             "%s\n",
113             spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_0),
114             spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_1),
115             spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_2),
116             spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_3),
117             spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_4),
118             spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_5),
119             spvTargetEnvDescription(SPV_ENV_OPENCL_2_2),
120             spvTargetEnvDescription(SPV_ENV_VULKAN_1_0),
121             spvTargetEnvDescription(SPV_ENV_VULKAN_1_1),
122             spvTargetEnvDescription(SPV_ENV_VULKAN_1_1_SPIRV_1_4));
123         continue_processing = false;
124         return_code = 0;
125       } else if (0 == strcmp(cur_arg, "--help") || 0 == strcmp(cur_arg, "-h")) {
126         print_usage(argv[0]);
127         continue_processing = false;
128         return_code = 0;
129       } else if (0 == strcmp(cur_arg, "--target-env")) {
130         if (argi + 1 < argc) {
131           const auto env_str = argv[++argi];
132           if (!spvParseTargetEnv(env_str, &target_env)) {
133             fprintf(stderr, "error: Unrecognized target env: %s\n", env_str);
134             continue_processing = false;
135             return_code = 1;
136           }
137         } else {
138           fprintf(stderr, "error: Missing argument to --target-env\n");
139           continue_processing = false;
140           return_code = 1;
141         }
142       } else if (0 == strcmp(cur_arg, "--before-hlsl-legalization")) {
143         options.SetBeforeHlslLegalization(true);
144       } else if (0 == strcmp(cur_arg, "--relax-logical-pointer")) {
145         options.SetRelaxLogicalPointer(true);
146       } else if (0 == strcmp(cur_arg, "--relax-block-layout")) {
147         options.SetRelaxBlockLayout(true);
148       } else if (0 == strcmp(cur_arg, "--uniform-buffer-standard-layout")) {
149         options.SetUniformBufferStandardLayout(true);
150       } else if (0 == strcmp(cur_arg, "--scalar-block-layout")) {
151         options.SetScalarBlockLayout(true);
152       } else if (0 == strcmp(cur_arg, "--workgroup-scalar-block-layout")) {
153         options.SetWorkgroupScalarBlockLayout(true);
154       } else if (0 == strcmp(cur_arg, "--skip-block-layout")) {
155         options.SetSkipBlockLayout(true);
156       } else if (0 == strcmp(cur_arg, "--relax-struct-store")) {
157         options.SetRelaxStructStore(true);
158       } else if (0 == cur_arg[1]) {
159         // Setting a filename of "-" to indicate stdin.
160         if (!inFile) {
161           inFile = cur_arg;
162         } else {
163           fprintf(stderr, "error: More than one input file specified\n");
164           continue_processing = false;
165           return_code = 1;
166         }
167       } else {
168         print_usage(argv[0]);
169         continue_processing = false;
170         return_code = 1;
171       }
172     } else {
173       if (!inFile) {
174         inFile = cur_arg;
175       } else {
176         fprintf(stderr, "error: More than one input file specified\n");
177         continue_processing = false;
178         return_code = 1;
179       }
180     }
181   }
182 
183   // Exit if command line parsing was not successful.
184   if (!continue_processing) {
185     return return_code;
186   }
187 
188   std::vector<uint32_t> contents;
189   if (!ReadBinaryFile<uint32_t>(inFile, &contents)) return 1;
190 
191   spvtools::SpirvTools tools(target_env);
192   tools.SetMessageConsumer(spvtools::utils::CLIMessageConsumer);
193 
194   bool succeed = tools.Validate(contents.data(), contents.size(), options);
195 
196   return !succeed;
197 }
198