| 1 | // Copyright (c) 2016 Google 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 "source/opt/pass_manager.h" |
| 16 | |
| 17 | #include <iostream> |
| 18 | #include <string> |
| 19 | #include <vector> |
| 20 | |
| 21 | #include "source/opt/ir_context.h" |
| 22 | #include "source/util/timer.h" |
| 23 | #include "spirv-tools/libspirv.hpp" |
| 24 | |
| 25 | namespace spvtools { |
| 26 | |
| 27 | namespace opt { |
| 28 | |
| 29 | Pass::Status PassManager::Run(IRContext* context) { |
| 30 | auto status = Pass::Status::SuccessWithoutChange; |
| 31 | |
| 32 | // If print_all_stream_ is not null, prints the disassembly of the module |
| 33 | // to that stream, with the given preamble and optionally the pass name. |
| 34 | auto print_disassembly = [&context, this](const char* preamble, Pass* pass) { |
| 35 | if (print_all_stream_) { |
| 36 | std::vector<uint32_t> binary; |
| 37 | context->module()->ToBinary(&binary, false); |
| 38 | SpirvTools t(SPV_ENV_UNIVERSAL_1_2); |
| 39 | std::string disassembly; |
| 40 | t.Disassemble(binary, &disassembly, 0); |
| 41 | *print_all_stream_ << preamble << (pass ? pass->name() : "" ) << "\n" |
| 42 | << disassembly << std::endl; |
| 43 | } |
| 44 | }; |
| 45 | |
| 46 | SPIRV_TIMER_DESCRIPTION(time_report_stream_, /* measure_mem_usage = */ true); |
| 47 | for (auto& pass : passes_) { |
| 48 | print_disassembly("; IR before pass " , pass.get()); |
| 49 | SPIRV_TIMER_SCOPED(time_report_stream_, (pass ? pass->name() : "" ), true); |
| 50 | const auto one_status = pass->Run(context); |
| 51 | if (one_status == Pass::Status::Failure) return one_status; |
| 52 | if (one_status == Pass::Status::SuccessWithChange) status = one_status; |
| 53 | |
| 54 | if (validate_after_all_) { |
| 55 | spvtools::SpirvTools tools(target_env_); |
| 56 | tools.SetMessageConsumer(consumer()); |
| 57 | std::vector<uint32_t> binary; |
| 58 | context->module()->ToBinary(&binary, true); |
| 59 | if (!tools.Validate(binary.data(), binary.size(), val_options_)) { |
| 60 | std::string msg = "Validation failed after pass " ; |
| 61 | msg += pass->name(); |
| 62 | spv_position_t null_pos{0, 0, 0}; |
| 63 | consumer()(SPV_MSG_INTERNAL_ERROR, "" , null_pos, msg.c_str()); |
| 64 | return Pass::Status::Failure; |
| 65 | } |
| 66 | } |
| 67 | |
| 68 | // Reset the pass to free any memory used by the pass. |
| 69 | pass.reset(nullptr); |
| 70 | } |
| 71 | print_disassembly("; IR after last pass" , nullptr); |
| 72 | |
| 73 | // Set the Id bound in the header in case a pass forgot to do so. |
| 74 | // |
| 75 | // TODO(dnovillo): This should be unnecessary and automatically maintained by |
| 76 | // the IRContext. |
| 77 | if (status == Pass::Status::SuccessWithChange) { |
| 78 | context->module()->SetIdBound(context->module()->ComputeIdBound()); |
| 79 | } |
| 80 | passes_.clear(); |
| 81 | return status; |
| 82 | } |
| 83 | |
| 84 | } // namespace opt |
| 85 | } // namespace spvtools |
| 86 | |