xref: /aosp_15_r20/external/angle/third_party/spirv-tools/src/tools/as/as.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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