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 <vector>
19
20 #include "source/spirv_target_env.h"
21 #include "spirv-tools/libspirv.h"
22 #include "tools/io.h"
23 #include "tools/util/flags.h"
24
25 constexpr auto kDefaultTarget = SPV_ENV_UNIVERSAL_1_6;
26 static const std::string kHelpText =
27 R"(%s - Create a SPIR-V binary module from SPIR-V assembly text
28
29 Usage: %s [options] [<filename>]
30
31 The SPIR-V assembly text is read from <filename>. If no file is specified,
32 or if the filename is "-", then the assembly text is read from standard input.
33 The SPIR-V binary module is written to file "out.spv", unless the -o option
34 is used.
35
36 Options:
37
38 -h, --help Print this help.
39
40 -o <filename> Set the output filename. Use '-' to mean stdout.
41 --version Display assembler version information.
42 --preserve-numeric-ids
43 Numeric IDs in the binary will have the same values as in the
44 source. Non-numeric IDs are allocated by filling in the gaps,
45 starting with 1 and going up.
46 --target-env %s
47 Use specified environment.
48 )";
49
50 // clang-format off
51 // flag name= default_value= required=
52 FLAG_SHORT_bool( h, false, false);
53 FLAG_LONG_bool( help, false, false);
54 FLAG_LONG_bool( version, false, false);
55 FLAG_LONG_bool( preserve_numeric_ids, false, false);
56 FLAG_SHORT_string(o, "", false);
57 FLAG_LONG_string( target_env, "", false);
58 // clang-format on
59
main(int,const char ** argv)60 int main(int, const char** argv) {
61 if (!flags::Parse(argv)) {
62 return 1;
63 }
64
65 if (flags::h.value() || flags::help.value()) {
66 const std::string target_env_list = spvTargetEnvList(19, 80);
67 printf(kHelpText.c_str(), argv[0], argv[0], target_env_list.c_str());
68 return 0;
69 }
70
71 if (flags::version.value()) {
72 printf("%s\n", spvSoftwareVersionDetailsString());
73 printf("Target: %s\n", spvTargetEnvDescription(kDefaultTarget));
74 return 0;
75 }
76
77 std::string outFile = flags::o.value();
78 if (outFile.empty()) {
79 outFile = "out.spv";
80 }
81
82 uint32_t options = 0;
83 if (flags::preserve_numeric_ids.value()) {
84 options |= SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS;
85 }
86
87 if (flags::positional_arguments.size() != 1) {
88 fprintf(stderr, "error: exactly one input file must be specified.\n");
89 return 1;
90 }
91 std::string inFile = flags::positional_arguments[0];
92
93 std::vector<char> contents;
94 if (!ReadTextFile(inFile.c_str(), &contents)) return 1;
95
96 // Can only deduce target after the file has been read
97 spv_target_env target_env;
98 if (flags::target_env.value().empty()) {
99 if (!spvReadEnvironmentFromText(contents, &target_env)) {
100 // Revert to default version since deduction failed
101 target_env = kDefaultTarget;
102 }
103 } else if (!spvParseTargetEnv(flags::target_env.value().c_str(),
104 &target_env)) {
105 fprintf(stderr, "error: Unrecognized target env: %s\n",
106 flags::target_env.value().c_str());
107 return 1;
108 }
109
110 spv_binary binary;
111 spv_diagnostic diagnostic = nullptr;
112 spv_context context = spvContextCreate(target_env);
113 spv_result_t error = spvTextToBinaryWithOptions(
114 context, contents.data(), contents.size(), options, &binary, &diagnostic);
115 spvContextDestroy(context);
116 if (error) {
117 spvDiagnosticPrint(diagnostic);
118 spvDiagnosticDestroy(diagnostic);
119 return error;
120 }
121
122 if (!WriteFile<uint32_t>(outFile.c_str(), "wb", binary->code,
123 binary->wordCount)) {
124 spvBinaryDestroy(binary);
125 return 1;
126 }
127
128 spvBinaryDestroy(binary);
129
130 return 0;
131 }
132