• 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   --skip-block-layout              Skip checking standard uniform/storage buffer layout.
62                                    Overrides any --relax-block-layout or --scalar-block-layout option.
63   --relax-struct-store             Allow store from one struct type to a
64                                    different type with compatible layout and
65                                    members.
66   --before-hlsl-legalization       Allows code patterns that are intended to be
67                                    fixed by spirv-opt's legalization passes.
68   --version                        Display validator version information.
69   --target-env                     {%s}
70                                    Use validation rules from the specified environment.
71 )",
72       argv0, argv0, target_env_list.c_str());
73 }
74 
main(int argc,char ** argv)75 int main(int argc, char** argv) {
76   const char* inFile = nullptr;
77   spv_target_env target_env = SPV_ENV_UNIVERSAL_1_5;
78   spvtools::ValidatorOptions options;
79   bool continue_processing = true;
80   int return_code = 0;
81 
82   for (int argi = 1; continue_processing && argi < argc; ++argi) {
83     const char* cur_arg = argv[argi];
84     if ('-' == cur_arg[0]) {
85       if (0 == strncmp(cur_arg, "--max-", 6)) {
86         if (argi + 1 < argc) {
87           spv_validator_limit limit_type;
88           if (spvParseUniversalLimitsOptions(cur_arg, &limit_type)) {
89             uint32_t limit = 0;
90             if (sscanf(argv[++argi], "%u", &limit)) {
91               options.SetUniversalLimit(limit_type, limit);
92             } else {
93               fprintf(stderr, "error: missing argument to %s\n", cur_arg);
94               continue_processing = false;
95               return_code = 1;
96             }
97           } else {
98             fprintf(stderr, "error: unrecognized option: %s\n", cur_arg);
99             continue_processing = false;
100             return_code = 1;
101           }
102         } else {
103           fprintf(stderr, "error: Missing argument to %s\n", cur_arg);
104           continue_processing = false;
105           return_code = 1;
106         }
107       } else if (0 == strcmp(cur_arg, "--version")) {
108         printf("%s\n", spvSoftwareVersionDetailsString());
109         printf(
110             "Targets:\n  %s\n  %s\n  %s\n  %s\n  %s\n  %s\n  %s\n  %s\n  %s\n  "
111             "%s\n  %s\n",
112             spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_0),
113             spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_1),
114             spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_2),
115             spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_3),
116             spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_4),
117             spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_5),
118             spvTargetEnvDescription(SPV_ENV_OPENCL_2_2),
119             spvTargetEnvDescription(SPV_ENV_VULKAN_1_0),
120             spvTargetEnvDescription(SPV_ENV_VULKAN_1_1),
121             spvTargetEnvDescription(SPV_ENV_VULKAN_1_1_SPIRV_1_4),
122             spvTargetEnvDescription(SPV_ENV_WEBGPU_0));
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, "--skip-block-layout")) {
153         options.SetSkipBlockLayout(true);
154       } else if (0 == strcmp(cur_arg, "--relax-struct-store")) {
155         options.SetRelaxStructStore(true);
156       } else if (0 == cur_arg[1]) {
157         // Setting a filename of "-" to indicate stdin.
158         if (!inFile) {
159           inFile = cur_arg;
160         } else {
161           fprintf(stderr, "error: More than one input file specified\n");
162           continue_processing = false;
163           return_code = 1;
164         }
165       } else {
166         print_usage(argv[0]);
167         continue_processing = false;
168         return_code = 1;
169       }
170     } else {
171       if (!inFile) {
172         inFile = cur_arg;
173       } else {
174         fprintf(stderr, "error: More than one input file specified\n");
175         continue_processing = false;
176         return_code = 1;
177       }
178     }
179   }
180 
181   // Exit if command line parsing was not successful.
182   if (!continue_processing) {
183     return return_code;
184   }
185 
186   std::vector<uint32_t> contents;
187   if (!ReadFile<uint32_t>(inFile, "rb", &contents)) return 1;
188 
189   spvtools::SpirvTools tools(target_env);
190   tools.SetMessageConsumer(spvtools::utils::CLIMessageConsumer);
191 
192   bool succeed = tools.Validate(contents.data(), contents.size(), options);
193 
194   return !succeed;
195 }
196