Initial implementation of merge return pass.
[platform/upstream/SPIRV-Tools.git] / source / opt / optimizer.cpp
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 "spirv-tools/optimizer.hpp"
16
17 #include "build_module.h"
18 #include "make_unique.h"
19 #include "pass_manager.h"
20 #include "passes.h"
21
22 namespace spvtools {
23
24 struct Optimizer::PassToken::Impl {
25   Impl(std::unique_ptr<opt::Pass> p) : pass(std::move(p)) {}
26
27   std::unique_ptr<opt::Pass> pass;  // Internal implementation pass.
28 };
29
30 Optimizer::PassToken::PassToken(
31     std::unique_ptr<Optimizer::PassToken::Impl> impl)
32     : impl_(std::move(impl)) {}
33 Optimizer::PassToken::PassToken(PassToken&& that)
34     : impl_(std::move(that.impl_)) {}
35
36 Optimizer::PassToken& Optimizer::PassToken::operator=(PassToken&& that) {
37   impl_ = std::move(that.impl_);
38   return *this;
39 }
40
41 Optimizer::PassToken::~PassToken() {}
42
43 struct Optimizer::Impl {
44   explicit Impl(spv_target_env env) : target_env(env), pass_manager() {}
45
46   const spv_target_env target_env;  // Target environment.
47   opt::PassManager pass_manager;    // Internal implementation pass manager.
48 };
49
50 Optimizer::Optimizer(spv_target_env env) : impl_(new Impl(env)) {}
51
52 Optimizer::~Optimizer() {}
53
54 void Optimizer::SetMessageConsumer(MessageConsumer c) {
55   // All passes' message consumer needs to be updated.
56   for (uint32_t i = 0; i < impl_->pass_manager.NumPasses(); ++i) {
57     impl_->pass_manager.GetPass(i)->SetMessageConsumer(c);
58   }
59   impl_->pass_manager.SetMessageConsumer(std::move(c));
60 }
61
62 Optimizer& Optimizer::RegisterPass(PassToken&& p) {
63   // Change to use the pass manager's consumer.
64   p.impl_->pass->SetMessageConsumer(impl_->pass_manager.consumer());
65   impl_->pass_manager.AddPass(std::move(p.impl_->pass));
66   return *this;
67 }
68
69 Optimizer& Optimizer::RegisterPerformancePasses() {
70   return RegisterPass(CreateMergeReturnPass())
71       .RegisterPass(CreateInlineExhaustivePass())
72       .RegisterPass(CreateLocalAccessChainConvertPass())
73       .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
74       .RegisterPass(CreateLocalSingleStoreElimPass())
75       .RegisterPass(CreateInsertExtractElimPass())
76       .RegisterPass(CreateAggressiveDCEPass())
77       .RegisterPass(CreateDeadBranchElimPass())
78       .RegisterPass(CreateBlockMergePass())
79       .RegisterPass(CreateLocalMultiStoreElimPass())
80       .RegisterPass(CreateInsertExtractElimPass())
81       // Currently exposing driver bugs resulting in crashes (#946)
82       // .RegisterPass(CreateCommonUniformElimPass())
83       .RegisterPass(CreateDeadVariableEliminationPass());
84 }
85
86 Optimizer& Optimizer::RegisterSizePasses() {
87   return RegisterPass(CreateMergeReturnPass())
88       .RegisterPass(CreateInlineExhaustivePass())
89       .RegisterPass(CreateLocalAccessChainConvertPass())
90       .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
91       .RegisterPass(CreateLocalSingleStoreElimPass())
92       .RegisterPass(CreateInsertExtractElimPass())
93       .RegisterPass(CreateAggressiveDCEPass())
94       .RegisterPass(CreateDeadBranchElimPass())
95       .RegisterPass(CreateBlockMergePass())
96       .RegisterPass(CreateLocalMultiStoreElimPass())
97       .RegisterPass(CreateInsertExtractElimPass())
98       // Currently exposing driver bugs resulting in crashes (#946)
99       // .RegisterPass(CreateCommonUniformElimPass())
100       .RegisterPass(CreateDeadVariableEliminationPass());
101 }
102
103 bool Optimizer::Run(const uint32_t* original_binary,
104                     const size_t original_binary_size,
105                     std::vector<uint32_t>* optimized_binary) const {
106   std::unique_ptr<ir::Module> module =
107       BuildModule(impl_->target_env, impl_->pass_manager.consumer(),
108                   original_binary, original_binary_size);
109   if (module == nullptr) return false;
110   ir::IRContext context(std::move(module), impl_->pass_manager.consumer());
111
112   auto status = impl_->pass_manager.Run(&context);
113   if (status == opt::Pass::Status::SuccessWithChange ||
114       (status == opt::Pass::Status::SuccessWithoutChange &&
115        (optimized_binary->data() != original_binary ||
116         optimized_binary->size() != original_binary_size))) {
117     optimized_binary->clear();
118     context.module()->ToBinary(optimized_binary, /* skip_nop = */ true);
119   }
120
121   return status != opt::Pass::Status::Failure;
122 }
123
124 Optimizer::PassToken CreateNullPass() {
125   return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::NullPass>());
126 }
127
128 Optimizer::PassToken CreateStripDebugInfoPass() {
129   return MakeUnique<Optimizer::PassToken::Impl>(
130       MakeUnique<opt::StripDebugInfoPass>());
131 }
132
133 Optimizer::PassToken CreateEliminateDeadFunctionsPass() {
134   return MakeUnique<Optimizer::PassToken::Impl>(
135       MakeUnique<opt::EliminateDeadFunctionsPass>());
136 }
137
138 Optimizer::PassToken CreateSetSpecConstantDefaultValuePass(
139     const std::unordered_map<uint32_t, std::string>& id_value_map) {
140   return MakeUnique<Optimizer::PassToken::Impl>(
141       MakeUnique<opt::SetSpecConstantDefaultValuePass>(id_value_map));
142 }
143
144 Optimizer::PassToken CreateSetSpecConstantDefaultValuePass(
145     const std::unordered_map<uint32_t, std::vector<uint32_t>>& id_value_map) {
146   return MakeUnique<Optimizer::PassToken::Impl>(
147       MakeUnique<opt::SetSpecConstantDefaultValuePass>(id_value_map));
148 }
149
150 Optimizer::PassToken CreateFlattenDecorationPass() {
151   return MakeUnique<Optimizer::PassToken::Impl>(
152       MakeUnique<opt::FlattenDecorationPass>());
153 }
154
155 Optimizer::PassToken CreateFreezeSpecConstantValuePass() {
156   return MakeUnique<Optimizer::PassToken::Impl>(
157       MakeUnique<opt::FreezeSpecConstantValuePass>());
158 }
159
160 Optimizer::PassToken CreateFoldSpecConstantOpAndCompositePass() {
161   return MakeUnique<Optimizer::PassToken::Impl>(
162       MakeUnique<opt::FoldSpecConstantOpAndCompositePass>());
163 }
164
165 Optimizer::PassToken CreateUnifyConstantPass() {
166   return MakeUnique<Optimizer::PassToken::Impl>(
167       MakeUnique<opt::UnifyConstantPass>());
168 }
169
170 Optimizer::PassToken CreateEliminateDeadConstantPass() {
171   return MakeUnique<Optimizer::PassToken::Impl>(
172       MakeUnique<opt::EliminateDeadConstantPass>());
173 }
174
175 Optimizer::PassToken CreateDeadVariableEliminationPass() {
176   return MakeUnique<Optimizer::PassToken::Impl>(
177       MakeUnique<opt::DeadVariableElimination>());
178 }
179
180 Optimizer::PassToken CreateStrengthReductionPass() {
181   return MakeUnique<Optimizer::PassToken::Impl>(
182       MakeUnique<opt::StrengthReductionPass>());
183 }
184
185 Optimizer::PassToken CreateBlockMergePass() {
186   return MakeUnique<Optimizer::PassToken::Impl>(
187       MakeUnique<opt::BlockMergePass>());
188 }
189
190 Optimizer::PassToken CreateInlineExhaustivePass() {
191   return MakeUnique<Optimizer::PassToken::Impl>(
192       MakeUnique<opt::InlineExhaustivePass>());
193 }
194
195 Optimizer::PassToken CreateInlineOpaquePass() {
196   return MakeUnique<Optimizer::PassToken::Impl>(
197       MakeUnique<opt::InlineOpaquePass>());
198 }
199
200 Optimizer::PassToken CreateLocalAccessChainConvertPass() {
201   return MakeUnique<Optimizer::PassToken::Impl>(
202       MakeUnique<opt::LocalAccessChainConvertPass>());
203 }
204
205 Optimizer::PassToken CreateLocalSingleBlockLoadStoreElimPass() {
206   return MakeUnique<Optimizer::PassToken::Impl>(
207       MakeUnique<opt::LocalSingleBlockLoadStoreElimPass>());
208 }
209
210 Optimizer::PassToken CreateLocalSingleStoreElimPass() {
211   return MakeUnique<Optimizer::PassToken::Impl>(
212       MakeUnique<opt::LocalSingleStoreElimPass>());
213 }
214
215 Optimizer::PassToken CreateInsertExtractElimPass() {
216   return MakeUnique<Optimizer::PassToken::Impl>(
217       MakeUnique<opt::InsertExtractElimPass>());
218 }
219
220 Optimizer::PassToken CreateDeadBranchElimPass() {
221   return MakeUnique<Optimizer::PassToken::Impl>(
222       MakeUnique<opt::DeadBranchElimPass>());
223 }
224
225 Optimizer::PassToken CreateLocalMultiStoreElimPass() {
226   return MakeUnique<Optimizer::PassToken::Impl>(
227       MakeUnique<opt::LocalMultiStoreElimPass>());
228 }
229
230 Optimizer::PassToken CreateAggressiveDCEPass() {
231   return MakeUnique<Optimizer::PassToken::Impl>(
232       MakeUnique<opt::AggressiveDCEPass>());
233 }
234
235 Optimizer::PassToken CreateCommonUniformElimPass() {
236   return MakeUnique<Optimizer::PassToken::Impl>(
237       MakeUnique<opt::CommonUniformElimPass>());
238 }
239
240 Optimizer::PassToken CreateCompactIdsPass() {
241   return MakeUnique<Optimizer::PassToken::Impl>(
242       MakeUnique<opt::CompactIdsPass>());
243 }
244
245 Optimizer::PassToken CreateMergeReturnPass() {
246   return MakeUnique<Optimizer::PassToken::Impl>(
247       MakeUnique<opt::MergeReturnPass>());
248 }
249
250 std::vector<const char*> Optimizer::GetPassNames() const {
251   std::vector<const char*> v;
252   for (uint32_t i = 0; i < impl_->pass_manager.NumPasses(); i++) {
253     v.push_back(impl_->pass_manager.GetPass(i)->name());
254   }
255   return v;
256 }
257
258 Optimizer::PassToken CreateCFGCleanupPass() {
259   return MakeUnique<Optimizer::PassToken::Impl>(
260       MakeUnique<opt::CFGCleanupPass>());
261 }
262
263 }  // namespace spvtools