• 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   printf(
29       R"(%s - Validate a SPIR-V binary file.
30 
31 USAGE: %s [options] [<filename>]
32 
33 The SPIR-V binary is read from <filename>. If no file is specified,
34 or if the filename is "-", then the binary is read from standard input.
35 
36 NOTE: The validator is a work in progress.
37 
38 Options:
39   -h, --help                       Print this help.
40   --max-struct-members             <maximum number of structure members allowed>
41   --max-struct-depth               <maximum allowed nesting depth of structures>
42   --max-local-variables            <maximum number of local variables allowed>
43   --max-global-variables           <maximum number of global variables allowed>
44   --max-switch-branches            <maximum number of branches allowed in switch statements>
45   --max-function-args              <maximum number arguments allowed per function>
46   --max-control-flow-nesting-depth <maximum Control Flow nesting depth allowed>
47   --max-access-chain-indexes       <maximum number of indexes allowed to use for Access Chain instructions>
48   --max-id-bound                   <maximum value for the id bound>
49   --relax-logical-pointer          Allow allocating an object of a pointer type and returning
50                                    a pointer value from a function in logical addressing mode
51   --relax-block-layout             Enable VK_KHR_relaxed_block_layout when checking standard
52                                    uniform, storage buffer, and push constant layouts.
53                                    This is the default when targeting Vulkan 1.1 or later.
54   --scalar-block-layout            Enable VK_EXT_scalar_block_layout when checking standard
55                                    uniform, storage buffer, and push constant layouts.  Scalar layout
56                                    rules are more permissive than relaxed block layout so in effect
57                                    this will override the --relax-block-layout option.
58   --skip-block-layout              Skip checking standard uniform/storage buffer layout.
59                                    Overrides any --relax-block-layout or --scalar-block-layout option.
60   --relax-struct-store             Allow store from one struct type to a
61                                    different type with compatible layout and
62                                    members.
63   --version                        Display validator version information.
64   --target-env                     {vulkan1.0|vulkan1.1|opencl2.2|spv1.0|spv1.1|spv1.2|spv1.3|webgpu0}
65                                    Use Vulkan 1.0, Vulkan 1.1, OpenCL 2.2, SPIR-V 1.0,
66                                    SPIR-V 1.1, SPIR-V 1.2, SPIR-V 1.3 or WIP WebGPU validation rules.
67 )",
68       argv0, argv0);
69 }
70 
main(int argc,char ** argv)71 int main(int argc, char** argv) {
72   const char* inFile = nullptr;
73   spv_target_env target_env = SPV_ENV_UNIVERSAL_1_3;
74   spvtools::ValidatorOptions options;
75   bool continue_processing = true;
76   int return_code = 0;
77 
78   for (int argi = 1; continue_processing && argi < argc; ++argi) {
79     const char* cur_arg = argv[argi];
80     if ('-' == cur_arg[0]) {
81       if (0 == strncmp(cur_arg, "--max-", 6)) {
82         if (argi + 1 < argc) {
83           spv_validator_limit limit_type;
84           if (spvParseUniversalLimitsOptions(cur_arg, &limit_type)) {
85             uint32_t limit = 0;
86             if (sscanf(argv[++argi], "%u", &limit)) {
87               options.SetUniversalLimit(limit_type, limit);
88             } else {
89               fprintf(stderr, "error: missing argument to %s\n", cur_arg);
90               continue_processing = false;
91               return_code = 1;
92             }
93           } else {
94             fprintf(stderr, "error: unrecognized option: %s\n", cur_arg);
95             continue_processing = false;
96             return_code = 1;
97           }
98         } else {
99           fprintf(stderr, "error: Missing argument to %s\n", cur_arg);
100           continue_processing = false;
101           return_code = 1;
102         }
103       } else if (0 == strcmp(cur_arg, "--version")) {
104         printf("%s\n", spvSoftwareVersionDetailsString());
105         printf("Targets:\n  %s\n  %s\n  %s\n  %s\n  %s\n  %s\n  %s\n  %s\n",
106                spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_0),
107                spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_1),
108                spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_2),
109                spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_3),
110                spvTargetEnvDescription(SPV_ENV_OPENCL_2_2),
111                spvTargetEnvDescription(SPV_ENV_VULKAN_1_0),
112                spvTargetEnvDescription(SPV_ENV_VULKAN_1_1),
113                spvTargetEnvDescription(SPV_ENV_WEBGPU_0));
114         continue_processing = false;
115         return_code = 0;
116       } else if (0 == strcmp(cur_arg, "--help") || 0 == strcmp(cur_arg, "-h")) {
117         print_usage(argv[0]);
118         continue_processing = false;
119         return_code = 0;
120       } else if (0 == strcmp(cur_arg, "--target-env")) {
121         if (argi + 1 < argc) {
122           const auto env_str = argv[++argi];
123           if (!spvParseTargetEnv(env_str, &target_env)) {
124             fprintf(stderr, "error: Unrecognized target env: %s\n", env_str);
125             continue_processing = false;
126             return_code = 1;
127           }
128         } else {
129           fprintf(stderr, "error: Missing argument to --target-env\n");
130           continue_processing = false;
131           return_code = 1;
132         }
133       } else if (0 == strcmp(cur_arg, "--relax-logical-pointer")) {
134         options.SetRelaxLogicalPointer(true);
135       } else if (0 == strcmp(cur_arg, "--relax-block-layout")) {
136         options.SetRelaxBlockLayout(true);
137       } else if (0 == strcmp(cur_arg, "--scalar-block-layout")) {
138         options.SetScalarBlockLayout(true);
139       } else if (0 == strcmp(cur_arg, "--skip-block-layout")) {
140         options.SetSkipBlockLayout(true);
141       } else if (0 == strcmp(cur_arg, "--relax-struct-store")) {
142         options.SetRelaxStructStore(true);
143       } else if (0 == cur_arg[1]) {
144         // Setting a filename of "-" to indicate stdin.
145         if (!inFile) {
146           inFile = cur_arg;
147         } else {
148           fprintf(stderr, "error: More than one input file specified\n");
149           continue_processing = false;
150           return_code = 1;
151         }
152       } else {
153         print_usage(argv[0]);
154         continue_processing = false;
155         return_code = 1;
156       }
157     } else {
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     }
166   }
167 
168   // Exit if command line parsing was not successful.
169   if (!continue_processing) {
170     return return_code;
171   }
172 
173   std::vector<uint32_t> contents;
174   if (!ReadFile<uint32_t>(inFile, "rb", &contents)) return 1;
175 
176   spvtools::SpirvTools tools(target_env);
177   tools.SetMessageConsumer(spvtools::utils::CLIMessageConsumer);
178 
179   bool succeed = tools.Validate(contents.data(), contents.size(), options);
180 
181   return !succeed;
182 }
183