1617a3babSopenharmony_ci//
2617a3babSopenharmony_ci// Copyright (C) 2014-2016 LunarG, Inc.
3617a3babSopenharmony_ci// Copyright (C) 2018-2020 Google, Inc.
4617a3babSopenharmony_ci//
5617a3babSopenharmony_ci// All rights reserved.
6617a3babSopenharmony_ci//
7617a3babSopenharmony_ci// Redistribution and use in source and binary forms, with or without
8617a3babSopenharmony_ci// modification, are permitted provided that the following conditions
9617a3babSopenharmony_ci// are met:
10617a3babSopenharmony_ci//
11617a3babSopenharmony_ci//    Redistributions of source code must retain the above copyright
12617a3babSopenharmony_ci//    notice, this list of conditions and the following disclaimer.
13617a3babSopenharmony_ci//
14617a3babSopenharmony_ci//    Redistributions in binary form must reproduce the above
15617a3babSopenharmony_ci//    copyright notice, this list of conditions and the following
16617a3babSopenharmony_ci//    disclaimer in the documentation and/or other materials provided
17617a3babSopenharmony_ci//    with the distribution.
18617a3babSopenharmony_ci//
19617a3babSopenharmony_ci//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
20617a3babSopenharmony_ci//    contributors may be used to endorse or promote products derived
21617a3babSopenharmony_ci//    from this software without specific prior written permission.
22617a3babSopenharmony_ci//
23617a3babSopenharmony_ci// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24617a3babSopenharmony_ci// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25617a3babSopenharmony_ci// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26617a3babSopenharmony_ci// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27617a3babSopenharmony_ci// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28617a3babSopenharmony_ci// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29617a3babSopenharmony_ci// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30617a3babSopenharmony_ci// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31617a3babSopenharmony_ci// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32617a3babSopenharmony_ci// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33617a3babSopenharmony_ci// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34617a3babSopenharmony_ci// POSSIBILITY OF SUCH DAMAGE.
35617a3babSopenharmony_ci
36617a3babSopenharmony_ci//
37617a3babSopenharmony_ci// Call into SPIRV-Tools to disassemble, validate, and optimize.
38617a3babSopenharmony_ci//
39617a3babSopenharmony_ci
40617a3babSopenharmony_ci#if ENABLE_OPT
41617a3babSopenharmony_ci
42617a3babSopenharmony_ci#include <cstdio>
43617a3babSopenharmony_ci#include <iostream>
44617a3babSopenharmony_ci
45617a3babSopenharmony_ci#include "SpvTools.h"
46617a3babSopenharmony_ci#include "spirv-tools/optimizer.hpp"
47617a3babSopenharmony_ci
48617a3babSopenharmony_cinamespace glslang {
49617a3babSopenharmony_ci
50617a3babSopenharmony_ci// Translate glslang's view of target versioning to what SPIRV-Tools uses.
51617a3babSopenharmony_cispv_target_env MapToSpirvToolsEnv(const SpvVersion& spvVersion, spv::SpvBuildLogger* logger)
52617a3babSopenharmony_ci{
53617a3babSopenharmony_ci    switch (spvVersion.vulkan) {
54617a3babSopenharmony_ci    case glslang::EShTargetVulkan_1_0:
55617a3babSopenharmony_ci        return spv_target_env::SPV_ENV_VULKAN_1_0;
56617a3babSopenharmony_ci    case glslang::EShTargetVulkan_1_1:
57617a3babSopenharmony_ci        switch (spvVersion.spv) {
58617a3babSopenharmony_ci        case EShTargetSpv_1_0:
59617a3babSopenharmony_ci        case EShTargetSpv_1_1:
60617a3babSopenharmony_ci        case EShTargetSpv_1_2:
61617a3babSopenharmony_ci        case EShTargetSpv_1_3:
62617a3babSopenharmony_ci            return spv_target_env::SPV_ENV_VULKAN_1_1;
63617a3babSopenharmony_ci        case EShTargetSpv_1_4:
64617a3babSopenharmony_ci            return spv_target_env::SPV_ENV_VULKAN_1_1_SPIRV_1_4;
65617a3babSopenharmony_ci        default:
66617a3babSopenharmony_ci            logger->missingFunctionality("Target version for SPIRV-Tools validator");
67617a3babSopenharmony_ci            return spv_target_env::SPV_ENV_VULKAN_1_1;
68617a3babSopenharmony_ci        }
69617a3babSopenharmony_ci    case glslang::EShTargetVulkan_1_2:
70617a3babSopenharmony_ci        return spv_target_env::SPV_ENV_VULKAN_1_2;
71617a3babSopenharmony_ci    case glslang::EShTargetVulkan_1_3:
72617a3babSopenharmony_ci        return spv_target_env::SPV_ENV_VULKAN_1_3;
73617a3babSopenharmony_ci    default:
74617a3babSopenharmony_ci        break;
75617a3babSopenharmony_ci    }
76617a3babSopenharmony_ci
77617a3babSopenharmony_ci    if (spvVersion.openGl > 0)
78617a3babSopenharmony_ci        return spv_target_env::SPV_ENV_OPENGL_4_5;
79617a3babSopenharmony_ci
80617a3babSopenharmony_ci    logger->missingFunctionality("Target version for SPIRV-Tools validator");
81617a3babSopenharmony_ci    return spv_target_env::SPV_ENV_UNIVERSAL_1_0;
82617a3babSopenharmony_ci}
83617a3babSopenharmony_ci
84617a3babSopenharmony_ci// Callback passed to spvtools::Optimizer::SetMessageConsumer
85617a3babSopenharmony_civoid OptimizerMesssageConsumer(spv_message_level_t level, const char *source,
86617a3babSopenharmony_ci        const spv_position_t &position, const char *message)
87617a3babSopenharmony_ci{
88617a3babSopenharmony_ci    auto &out = std::cerr;
89617a3babSopenharmony_ci    switch (level)
90617a3babSopenharmony_ci    {
91617a3babSopenharmony_ci    case SPV_MSG_FATAL:
92617a3babSopenharmony_ci    case SPV_MSG_INTERNAL_ERROR:
93617a3babSopenharmony_ci    case SPV_MSG_ERROR:
94617a3babSopenharmony_ci        out << "error: ";
95617a3babSopenharmony_ci        break;
96617a3babSopenharmony_ci    case SPV_MSG_WARNING:
97617a3babSopenharmony_ci        out << "warning: ";
98617a3babSopenharmony_ci        break;
99617a3babSopenharmony_ci    case SPV_MSG_INFO:
100617a3babSopenharmony_ci    case SPV_MSG_DEBUG:
101617a3babSopenharmony_ci        out << "info: ";
102617a3babSopenharmony_ci        break;
103617a3babSopenharmony_ci    default:
104617a3babSopenharmony_ci        break;
105617a3babSopenharmony_ci    }
106617a3babSopenharmony_ci    if (source)
107617a3babSopenharmony_ci    {
108617a3babSopenharmony_ci        out << source << ":";
109617a3babSopenharmony_ci    }
110617a3babSopenharmony_ci    out << position.line << ":" << position.column << ":" << position.index << ":";
111617a3babSopenharmony_ci    if (message)
112617a3babSopenharmony_ci    {
113617a3babSopenharmony_ci        out << " " << message;
114617a3babSopenharmony_ci    }
115617a3babSopenharmony_ci    out << std::endl;
116617a3babSopenharmony_ci}
117617a3babSopenharmony_ci
118617a3babSopenharmony_ci// Use the SPIRV-Tools disassembler to print SPIR-V using a SPV_ENV_UNIVERSAL_1_3 environment.
119617a3babSopenharmony_civoid SpirvToolsDisassemble(std::ostream& out, const std::vector<unsigned int>& spirv)
120617a3babSopenharmony_ci{
121617a3babSopenharmony_ci    SpirvToolsDisassemble(out, spirv, spv_target_env::SPV_ENV_UNIVERSAL_1_3);
122617a3babSopenharmony_ci}
123617a3babSopenharmony_ci
124617a3babSopenharmony_ci// Use the SPIRV-Tools disassembler to print SPIR-V with a provided SPIR-V environment.
125617a3babSopenharmony_civoid SpirvToolsDisassemble(std::ostream& out, const std::vector<unsigned int>& spirv,
126617a3babSopenharmony_ci                           spv_target_env requested_context)
127617a3babSopenharmony_ci{
128617a3babSopenharmony_ci    // disassemble
129617a3babSopenharmony_ci    spv_context context = spvContextCreate(requested_context);
130617a3babSopenharmony_ci    spv_text text;
131617a3babSopenharmony_ci    spv_diagnostic diagnostic = nullptr;
132617a3babSopenharmony_ci    spvBinaryToText(context, spirv.data(), spirv.size(),
133617a3babSopenharmony_ci        SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES | SPV_BINARY_TO_TEXT_OPTION_INDENT,
134617a3babSopenharmony_ci        &text, &diagnostic);
135617a3babSopenharmony_ci
136617a3babSopenharmony_ci    // dump
137617a3babSopenharmony_ci    if (diagnostic == nullptr)
138617a3babSopenharmony_ci        out << text->str;
139617a3babSopenharmony_ci    else
140617a3babSopenharmony_ci        spvDiagnosticPrint(diagnostic);
141617a3babSopenharmony_ci
142617a3babSopenharmony_ci    // teardown
143617a3babSopenharmony_ci    spvDiagnosticDestroy(diagnostic);
144617a3babSopenharmony_ci    spvContextDestroy(context);
145617a3babSopenharmony_ci}
146617a3babSopenharmony_ci
147617a3babSopenharmony_ci// Apply the SPIRV-Tools validator to generated SPIR-V.
148617a3babSopenharmony_civoid SpirvToolsValidate(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv,
149617a3babSopenharmony_ci                        spv::SpvBuildLogger* logger, bool prelegalization)
150617a3babSopenharmony_ci{
151617a3babSopenharmony_ci    // validate
152617a3babSopenharmony_ci    spv_context context = spvContextCreate(MapToSpirvToolsEnv(intermediate.getSpv(), logger));
153617a3babSopenharmony_ci    spv_const_binary_t binary = { spirv.data(), spirv.size() };
154617a3babSopenharmony_ci    spv_diagnostic diagnostic = nullptr;
155617a3babSopenharmony_ci    spv_validator_options options = spvValidatorOptionsCreate();
156617a3babSopenharmony_ci    spvValidatorOptionsSetRelaxBlockLayout(options, intermediate.usingHlslOffsets());
157617a3babSopenharmony_ci    spvValidatorOptionsSetBeforeHlslLegalization(options, prelegalization);
158617a3babSopenharmony_ci    spvValidatorOptionsSetScalarBlockLayout(options, intermediate.usingScalarBlockLayout());
159617a3babSopenharmony_ci    spvValidatorOptionsSetWorkgroupScalarBlockLayout(options, intermediate.usingScalarBlockLayout());
160617a3babSopenharmony_ci    spvValidateWithOptions(context, options, &binary, &diagnostic);
161617a3babSopenharmony_ci
162617a3babSopenharmony_ci    // report
163617a3babSopenharmony_ci    if (diagnostic != nullptr) {
164617a3babSopenharmony_ci        logger->error("SPIRV-Tools Validation Errors");
165617a3babSopenharmony_ci        logger->error(diagnostic->error);
166617a3babSopenharmony_ci    }
167617a3babSopenharmony_ci
168617a3babSopenharmony_ci    // tear down
169617a3babSopenharmony_ci    spvValidatorOptionsDestroy(options);
170617a3babSopenharmony_ci    spvDiagnosticDestroy(diagnostic);
171617a3babSopenharmony_ci    spvContextDestroy(context);
172617a3babSopenharmony_ci}
173617a3babSopenharmony_ci
174617a3babSopenharmony_ci// Apply the SPIRV-Tools optimizer to generated SPIR-V.  HLSL SPIR-V is legalized in the process.
175617a3babSopenharmony_civoid SpirvToolsTransform(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv,
176617a3babSopenharmony_ci                         spv::SpvBuildLogger* logger, const SpvOptions* options)
177617a3babSopenharmony_ci{
178617a3babSopenharmony_ci    spv_target_env target_env = MapToSpirvToolsEnv(intermediate.getSpv(), logger);
179617a3babSopenharmony_ci
180617a3babSopenharmony_ci    spvtools::Optimizer optimizer(target_env);
181617a3babSopenharmony_ci    optimizer.SetMessageConsumer(OptimizerMesssageConsumer);
182617a3babSopenharmony_ci
183617a3babSopenharmony_ci    // If debug (specifically source line info) is being generated, propagate
184617a3babSopenharmony_ci    // line information into all SPIR-V instructions. This avoids loss of
185617a3babSopenharmony_ci    // information when instructions are deleted or moved. Later, remove
186617a3babSopenharmony_ci    // redundant information to minimize final SPRIR-V size.
187617a3babSopenharmony_ci    if (options->stripDebugInfo) {
188617a3babSopenharmony_ci        optimizer.RegisterPass(spvtools::CreateStripDebugInfoPass());
189617a3babSopenharmony_ci    }
190617a3babSopenharmony_ci    optimizer.RegisterPass(spvtools::CreateWrapOpKillPass());
191617a3babSopenharmony_ci    optimizer.RegisterPass(spvtools::CreateDeadBranchElimPass());
192617a3babSopenharmony_ci    optimizer.RegisterPass(spvtools::CreateMergeReturnPass());
193617a3babSopenharmony_ci    optimizer.RegisterPass(spvtools::CreateInlineExhaustivePass());
194617a3babSopenharmony_ci    optimizer.RegisterPass(spvtools::CreateEliminateDeadFunctionsPass());
195617a3babSopenharmony_ci    optimizer.RegisterPass(spvtools::CreateScalarReplacementPass());
196617a3babSopenharmony_ci    optimizer.RegisterPass(spvtools::CreateLocalAccessChainConvertPass());
197617a3babSopenharmony_ci    optimizer.RegisterPass(spvtools::CreateLocalSingleBlockLoadStoreElimPass());
198617a3babSopenharmony_ci    optimizer.RegisterPass(spvtools::CreateLocalSingleStoreElimPass());
199617a3babSopenharmony_ci    optimizer.RegisterPass(spvtools::CreateSimplificationPass());
200617a3babSopenharmony_ci    optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass());
201617a3babSopenharmony_ci    optimizer.RegisterPass(spvtools::CreateVectorDCEPass());
202617a3babSopenharmony_ci    optimizer.RegisterPass(spvtools::CreateDeadInsertElimPass());
203617a3babSopenharmony_ci    optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass());
204617a3babSopenharmony_ci    optimizer.RegisterPass(spvtools::CreateDeadBranchElimPass());
205617a3babSopenharmony_ci    optimizer.RegisterPass(spvtools::CreateBlockMergePass());
206617a3babSopenharmony_ci    optimizer.RegisterPass(spvtools::CreateLocalMultiStoreElimPass());
207617a3babSopenharmony_ci    optimizer.RegisterPass(spvtools::CreateIfConversionPass());
208617a3babSopenharmony_ci    optimizer.RegisterPass(spvtools::CreateSimplificationPass());
209617a3babSopenharmony_ci    optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass());
210617a3babSopenharmony_ci    optimizer.RegisterPass(spvtools::CreateVectorDCEPass());
211617a3babSopenharmony_ci    optimizer.RegisterPass(spvtools::CreateDeadInsertElimPass());
212617a3babSopenharmony_ci    optimizer.RegisterPass(spvtools::CreateInterpolateFixupPass());
213617a3babSopenharmony_ci    if (options->optimizeSize) {
214617a3babSopenharmony_ci        optimizer.RegisterPass(spvtools::CreateRedundancyEliminationPass());
215617a3babSopenharmony_ci        optimizer.RegisterPass(spvtools::CreateEliminateDeadInputComponentsSafePass());
216617a3babSopenharmony_ci    }
217617a3babSopenharmony_ci    optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass());
218617a3babSopenharmony_ci    optimizer.RegisterPass(spvtools::CreateCFGCleanupPass());
219617a3babSopenharmony_ci
220617a3babSopenharmony_ci    spvtools::OptimizerOptions spvOptOptions;
221617a3babSopenharmony_ci    optimizer.SetTargetEnv(MapToSpirvToolsEnv(intermediate.getSpv(), logger));
222617a3babSopenharmony_ci    spvOptOptions.set_run_validator(false); // The validator may run as a separate step later on
223617a3babSopenharmony_ci    optimizer.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions);
224617a3babSopenharmony_ci}
225617a3babSopenharmony_ci
226617a3babSopenharmony_cibool SpirvToolsAnalyzeDeadOutputStores(spv_target_env target_env, std::vector<unsigned int>& spirv,
227617a3babSopenharmony_ci                                       std::unordered_set<uint32_t>* live_locs,
228617a3babSopenharmony_ci                                       std::unordered_set<uint32_t>* live_builtins,
229617a3babSopenharmony_ci                                       spv::SpvBuildLogger*)
230617a3babSopenharmony_ci{
231617a3babSopenharmony_ci  spvtools::Optimizer optimizer(target_env);
232617a3babSopenharmony_ci  optimizer.SetMessageConsumer(OptimizerMesssageConsumer);
233617a3babSopenharmony_ci
234617a3babSopenharmony_ci  optimizer.RegisterPass(spvtools::CreateAnalyzeLiveInputPass(live_locs, live_builtins));
235617a3babSopenharmony_ci
236617a3babSopenharmony_ci  spvtools::OptimizerOptions spvOptOptions;
237617a3babSopenharmony_ci  optimizer.SetTargetEnv(target_env);
238617a3babSopenharmony_ci  spvOptOptions.set_run_validator(false);
239617a3babSopenharmony_ci  return optimizer.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions);
240617a3babSopenharmony_ci}
241617a3babSopenharmony_ci
242617a3babSopenharmony_civoid SpirvToolsEliminateDeadOutputStores(spv_target_env target_env, std::vector<unsigned int>& spirv,
243617a3babSopenharmony_ci                                         std::unordered_set<uint32_t>* live_locs,
244617a3babSopenharmony_ci                                         std::unordered_set<uint32_t>* live_builtins,
245617a3babSopenharmony_ci                                         spv::SpvBuildLogger*)
246617a3babSopenharmony_ci{
247617a3babSopenharmony_ci  spvtools::Optimizer optimizer(target_env);
248617a3babSopenharmony_ci  optimizer.SetMessageConsumer(OptimizerMesssageConsumer);
249617a3babSopenharmony_ci
250617a3babSopenharmony_ci  optimizer.RegisterPass(spvtools::CreateEliminateDeadOutputStoresPass(live_locs, live_builtins));
251617a3babSopenharmony_ci  optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass(false, true));
252617a3babSopenharmony_ci  optimizer.RegisterPass(spvtools::CreateEliminateDeadOutputComponentsPass());
253617a3babSopenharmony_ci  optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass(false, true));
254617a3babSopenharmony_ci
255617a3babSopenharmony_ci  spvtools::OptimizerOptions spvOptOptions;
256617a3babSopenharmony_ci  optimizer.SetTargetEnv(target_env);
257617a3babSopenharmony_ci  spvOptOptions.set_run_validator(false);
258617a3babSopenharmony_ci  optimizer.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions);
259617a3babSopenharmony_ci}
260617a3babSopenharmony_ci
261617a3babSopenharmony_civoid SpirvToolsEliminateDeadInputComponents(spv_target_env target_env, std::vector<unsigned int>& spirv,
262617a3babSopenharmony_ci                                            spv::SpvBuildLogger*)
263617a3babSopenharmony_ci{
264617a3babSopenharmony_ci  spvtools::Optimizer optimizer(target_env);
265617a3babSopenharmony_ci  optimizer.SetMessageConsumer(OptimizerMesssageConsumer);
266617a3babSopenharmony_ci
267617a3babSopenharmony_ci  optimizer.RegisterPass(spvtools::CreateEliminateDeadInputComponentsPass());
268617a3babSopenharmony_ci  optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass());
269617a3babSopenharmony_ci
270617a3babSopenharmony_ci  spvtools::OptimizerOptions spvOptOptions;
271617a3babSopenharmony_ci  optimizer.SetTargetEnv(target_env);
272617a3babSopenharmony_ci  spvOptOptions.set_run_validator(false);
273617a3babSopenharmony_ci  optimizer.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions);
274617a3babSopenharmony_ci}
275617a3babSopenharmony_ci
276617a3babSopenharmony_ci// Apply the SPIRV-Tools optimizer to strip debug info from SPIR-V.  This is implicitly done by
277617a3babSopenharmony_ci// SpirvToolsTransform if spvOptions->stripDebugInfo is set, but can be called separately if
278617a3babSopenharmony_ci// optimization is disabled.
279617a3babSopenharmony_civoid SpirvToolsStripDebugInfo(const glslang::TIntermediate& intermediate,
280617a3babSopenharmony_ci        std::vector<unsigned int>& spirv, spv::SpvBuildLogger* logger)
281617a3babSopenharmony_ci{
282617a3babSopenharmony_ci    spv_target_env target_env = MapToSpirvToolsEnv(intermediate.getSpv(), logger);
283617a3babSopenharmony_ci
284617a3babSopenharmony_ci    spvtools::Optimizer optimizer(target_env);
285617a3babSopenharmony_ci    optimizer.SetMessageConsumer(OptimizerMesssageConsumer);
286617a3babSopenharmony_ci
287617a3babSopenharmony_ci    optimizer.RegisterPass(spvtools::CreateStripDebugInfoPass());
288617a3babSopenharmony_ci
289617a3babSopenharmony_ci    spvtools::OptimizerOptions spvOptOptions;
290617a3babSopenharmony_ci    optimizer.SetTargetEnv(MapToSpirvToolsEnv(intermediate.getSpv(), logger));
291617a3babSopenharmony_ci    spvOptOptions.set_run_validator(false); // The validator may run as a separate step later on
292617a3babSopenharmony_ci    optimizer.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions);
293617a3babSopenharmony_ci}
294617a3babSopenharmony_ci
295617a3babSopenharmony_ci}; // end namespace glslang
296617a3babSopenharmony_ci
297617a3babSopenharmony_ci#endif
298