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