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