xref: /aosp_15_r20/external/deqp/external/vulkancts/framework/vulkan/vkSpirVAsm.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * Vulkan CTS Framework
3  * --------------------
4  *
5  * Copyright (c) 2015 Google Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief SPIR-V assembly to binary.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vkSpirVAsm.hpp"
25 #include "vkSpirVProgram.hpp"
26 #include "deClock.h"
27 
28 #include <algorithm>
29 
30 #include "spirv-tools/libspirv.h"
31 
32 namespace vk
33 {
34 
35 using std::string;
36 using std::vector;
37 
38 // Returns the SPIRV-Tools target environment enum for the given dEQP Spirv validator options object.
39 // Do this here instead of as a method on SpirvValidatorOptions because only this file has access to
40 // the SPIRV-Tools headers.
getSpirvToolsEnvForValidatorOptions(SpirvValidatorOptions opts)41 static spv_target_env getSpirvToolsEnvForValidatorOptions(SpirvValidatorOptions opts)
42 {
43     const bool allow_1_4 = opts.supports_VK_KHR_spirv_1_4;
44     switch (opts.vulkanVersion)
45     {
46     case VK_MAKE_API_VERSION(0, 1, 0, 0):
47         return SPV_ENV_VULKAN_1_0;
48     case VK_MAKE_API_VERSION(0, 1, 1, 0):
49         return allow_1_4 ? SPV_ENV_VULKAN_1_1_SPIRV_1_4 : SPV_ENV_VULKAN_1_1;
50     case VK_MAKE_API_VERSION(0, 1, 2, 0):
51         return SPV_ENV_VULKAN_1_2;
52     case VK_MAKE_API_VERSION(1, 1, 0, 0):
53         return SPV_ENV_VULKAN_1_2;
54     case VK_MAKE_API_VERSION(0, 1, 3, 0):
55         return SPV_ENV_VULKAN_1_3;
56     default:
57         break;
58     }
59     TCU_THROW(InternalError, "Unexpected Vulkan Version version requested");
60     return SPV_ENV_VULKAN_1_0;
61 }
62 
mapTargetSpvEnvironment(SpirvVersion spirvVersion)63 static spv_target_env mapTargetSpvEnvironment(SpirvVersion spirvVersion)
64 {
65     spv_target_env result = SPV_ENV_UNIVERSAL_1_0;
66 
67     switch (spirvVersion)
68     {
69     case SPIRV_VERSION_1_0:
70         result = SPV_ENV_UNIVERSAL_1_0;
71         break; //!< SPIR-V 1.0
72     case SPIRV_VERSION_1_1:
73         result = SPV_ENV_UNIVERSAL_1_1;
74         break; //!< SPIR-V 1.1
75     case SPIRV_VERSION_1_2:
76         result = SPV_ENV_UNIVERSAL_1_2;
77         break; //!< SPIR-V 1.2
78     case SPIRV_VERSION_1_3:
79         result = SPV_ENV_UNIVERSAL_1_3;
80         break; //!< SPIR-V 1.3
81     case SPIRV_VERSION_1_4:
82         result = SPV_ENV_UNIVERSAL_1_4;
83         break; //!< SPIR-V 1.4
84     case SPIRV_VERSION_1_5:
85         result = SPV_ENV_UNIVERSAL_1_5;
86         break; //!< SPIR-V 1.5
87     case SPIRV_VERSION_1_6:
88         result = SPV_ENV_UNIVERSAL_1_6;
89         break; //!< SPIR-V 1.6
90     default:
91         TCU_THROW(InternalError, "Unknown SPIR-V version");
92     }
93 
94     return result;
95 }
96 
assembleSpirV(const SpirVAsmSource * program,std::vector<uint32_t> * dst,SpirVProgramInfo * buildInfo,SpirvVersion spirvVersion)97 bool assembleSpirV(const SpirVAsmSource *program, std::vector<uint32_t> *dst, SpirVProgramInfo *buildInfo,
98                    SpirvVersion spirvVersion)
99 {
100     const spv_context context = spvContextCreate(mapTargetSpvEnvironment(spirvVersion));
101     spv_binary binary         = DE_NULL;
102     spv_diagnostic diagnostic = DE_NULL;
103 
104     if (!context)
105         throw std::bad_alloc();
106 
107     try
108     {
109         const std::string &spvSource    = program->source;
110         const uint64_t compileStartTime = deGetMicroseconds();
111         const uint32_t options          = SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS;
112         const spv_result_t compileOk =
113             spvTextToBinaryWithOptions(context, spvSource.c_str(), spvSource.size(), options, &binary, &diagnostic);
114 
115         buildInfo->source        = spvSource;
116         buildInfo->infoLog       = diagnostic ? diagnostic->error : ""; // \todo [2015-07-13 pyry] Include debug log?
117         buildInfo->compileTimeUs = deGetMicroseconds() - compileStartTime;
118         buildInfo->compileOk     = (compileOk == SPV_SUCCESS);
119 
120         if (buildInfo->compileOk)
121         {
122             DE_ASSERT(binary->wordCount > 0);
123             dst->resize(binary->wordCount);
124             std::copy(&binary->code[0], &binary->code[0] + binary->wordCount, dst->begin());
125         }
126 
127         spvBinaryDestroy(binary);
128         spvDiagnosticDestroy(diagnostic);
129         spvContextDestroy(context);
130 
131         return compileOk == SPV_SUCCESS;
132     }
133     catch (...)
134     {
135         spvBinaryDestroy(binary);
136         spvDiagnosticDestroy(diagnostic);
137         spvContextDestroy(context);
138 
139         throw;
140     }
141 }
142 
disassembleSpirV(size_t binarySizeInWords,const uint32_t * binary,std::ostream * dst,SpirvVersion spirvVersion)143 void disassembleSpirV(size_t binarySizeInWords, const uint32_t *binary, std::ostream *dst, SpirvVersion spirvVersion)
144 {
145     const spv_context context = spvContextCreate(mapTargetSpvEnvironment(spirvVersion));
146     spv_text text             = DE_NULL;
147     spv_diagnostic diagnostic = DE_NULL;
148 
149     if (!context)
150         throw std::bad_alloc();
151 
152     try
153     {
154         const spv_result_t result = spvBinaryToText(context, binary, binarySizeInWords, 0, &text, &diagnostic);
155 
156         if (result != SPV_SUCCESS)
157             TCU_THROW(InternalError, "Disassembling SPIR-V failed");
158 
159         *dst << text->str;
160 
161         spvTextDestroy(text);
162         spvDiagnosticDestroy(diagnostic);
163         spvContextDestroy(context);
164     }
165     catch (...)
166     {
167         spvTextDestroy(text);
168         spvDiagnosticDestroy(diagnostic);
169         spvContextDestroy(context);
170 
171         throw;
172     }
173 }
174 
validateSpirV(size_t binarySizeInWords,const uint32_t * binary,std::ostream * infoLog,const SpirvValidatorOptions & val_options)175 bool validateSpirV(size_t binarySizeInWords, const uint32_t *binary, std::ostream *infoLog,
176                    const SpirvValidatorOptions &val_options)
177 {
178     const spv_context context     = spvContextCreate(getSpirvToolsEnvForValidatorOptions(val_options));
179     spv_diagnostic diagnostic     = DE_NULL;
180     spv_validator_options options = DE_NULL;
181     spv_text disasmText           = DE_NULL;
182 
183     if (!context)
184         throw std::bad_alloc();
185 
186     try
187     {
188         spv_const_binary_t cbinary = {binary, binarySizeInWords};
189 
190         options = spvValidatorOptionsCreate();
191 
192         if (options == DE_NULL)
193             throw std::bad_alloc();
194 
195         switch (val_options.blockLayout)
196         {
197         case SpirvValidatorOptions::kDefaultBlockLayout:
198             break;
199         case SpirvValidatorOptions::kNoneBlockLayout:
200             spvValidatorOptionsSetSkipBlockLayout(options, true);
201             break;
202         case SpirvValidatorOptions::kRelaxedBlockLayout:
203             spvValidatorOptionsSetRelaxBlockLayout(options, true);
204             break;
205         case SpirvValidatorOptions::kUniformStandardLayout:
206             spvValidatorOptionsSetUniformBufferStandardLayout(options, true);
207             break;
208         case SpirvValidatorOptions::kScalarBlockLayout:
209             spvValidatorOptionsSetScalarBlockLayout(options, true);
210             break;
211         }
212 
213         if (val_options.flags & SpirvValidatorOptions::FLAG_SPIRV_VALIDATOR_WORKGROUP_SCALAR_BLOCK_LAYOUT)
214         {
215             spvValidatorOptionsSetWorkgroupScalarBlockLayout(options, true);
216         }
217 
218         if (val_options.flags & SpirvValidatorOptions::FLAG_SPIRV_VALIDATOR_ALLOW_LOCALSIZEID)
219             spvValidatorOptionsSetAllowLocalSizeId(options, true);
220 
221         const spv_result_t valid = spvValidateWithOptions(context, options, &cbinary, &diagnostic);
222         const bool passed        = (valid == SPV_SUCCESS);
223 
224         *infoLog << "Validation " << (passed ? "PASSED: " : "FAILED: ");
225 
226         if (diagnostic && diagnostic->error)
227         {
228             // Print the diagnostic whether validation passes or fails.
229             // In theory we could get a warning even in the pass case, but there are no cases
230             // like that now.
231             *infoLog << diagnostic->error << "\n";
232 
233             const uint32_t disasmOptions = SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES | SPV_BINARY_TO_TEXT_OPTION_INDENT;
234             const spv_result_t disasmResult =
235                 spvBinaryToText(context, binary, binarySizeInWords, disasmOptions, &disasmText, DE_NULL);
236 
237             if (disasmResult != SPV_SUCCESS)
238                 *infoLog << "Disassembly failed with code: " << de::toString(disasmResult) << "\n";
239 
240             if (disasmText != DE_NULL)
241                 *infoLog << disasmText->str << "\n";
242         }
243 
244         spvTextDestroy(disasmText);
245         spvValidatorOptionsDestroy(options);
246         spvDiagnosticDestroy(diagnostic);
247         spvContextDestroy(context);
248 
249         return passed;
250     }
251     catch (...)
252     {
253         spvTextDestroy(disasmText);
254         spvValidatorOptionsDestroy(options);
255         spvDiagnosticDestroy(diagnostic);
256         spvContextDestroy(context);
257 
258         throw;
259     }
260 }
261 
262 } // namespace vk
263