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 | |