53692d48e2899f432a8a8faf1cea367171a23af8
[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(CreateInlineExhaustivePass())
71       .RegisterPass(CreateLocalAccessChainConvertPass())
72       .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
73       .RegisterPass(CreateLocalSingleStoreElimPass())
74       .RegisterPass(CreateInsertExtractElimPass())
75       .RegisterPass(CreateAggressiveDCEPass())
76       .RegisterPass(CreateDeadBranchElimPass())
77       .RegisterPass(CreateBlockMergePass())
78       .RegisterPass(CreateLocalMultiStoreElimPass())
79       .RegisterPass(CreateInsertExtractElimPass())
80       // Currently exposing driver bugs resulting in crashes (#946)
81       // .RegisterPass(CreateCommonUniformElimPass())
82       .RegisterPass(CreateDeadVariableEliminationPass());
83 }
84
85 Optimizer& Optimizer::RegisterSizePasses() {
86   return RegisterPass(CreateInlineExhaustivePass())
87       .RegisterPass(CreateLocalAccessChainConvertPass())
88       .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass())
89       .RegisterPass(CreateLocalSingleStoreElimPass())
90       .RegisterPass(CreateInsertExtractElimPass())
91       .RegisterPass(CreateAggressiveDCEPass())
92       .RegisterPass(CreateDeadBranchElimPass())
93       .RegisterPass(CreateBlockMergePass())
94       .RegisterPass(CreateLocalMultiStoreElimPass())
95       .RegisterPass(CreateInsertExtractElimPass())
96       // Currently exposing driver bugs resulting in crashes (#946)
97       // .RegisterPass(CreateCommonUniformElimPass())
98       .RegisterPass(CreateDeadVariableEliminationPass());
99 }
100
101 bool Optimizer::Run(const uint32_t* original_binary,
102                     const size_t original_binary_size,
103                     std::vector<uint32_t>* optimized_binary) const {
104   std::unique_ptr<ir::Module> module =
105       BuildModule(impl_->target_env, impl_->pass_manager.consumer(),
106                   original_binary, original_binary_size);
107   if (module == nullptr) return false;
108   ir::IRContext context(std::move(module), impl_->pass_manager.consumer());
109
110   auto status = impl_->pass_manager.Run(&context);
111   if (status == opt::Pass::Status::SuccessWithChange ||
112       (status == opt::Pass::Status::SuccessWithoutChange &&
113        (optimized_binary->data() != original_binary ||
114         optimized_binary->size() != original_binary_size))) {
115     optimized_binary->clear();
116     context.module()->ToBinary(optimized_binary, /* skip_nop = */ true);
117   }
118
119   return status != opt::Pass::Status::Failure;
120 }
121
122 Optimizer::PassToken CreateNullPass() {
123   return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::NullPass>());
124 }
125
126 Optimizer::PassToken CreateStripDebugInfoPass() {
127   return MakeUnique<Optimizer::PassToken::Impl>(
128       MakeUnique<opt::StripDebugInfoPass>());
129 }
130
131 Optimizer::PassToken CreateEliminateDeadFunctionsPass() {
132   return MakeUnique<Optimizer::PassToken::Impl>(
133       MakeUnique<opt::EliminateDeadFunctionsPass>());
134 }
135
136 Optimizer::PassToken CreateSetSpecConstantDefaultValuePass(
137     const std::unordered_map<uint32_t, std::string>& id_value_map) {
138   return MakeUnique<Optimizer::PassToken::Impl>(
139       MakeUnique<opt::SetSpecConstantDefaultValuePass>(id_value_map));
140 }
141
142 Optimizer::PassToken CreateSetSpecConstantDefaultValuePass(
143     const std::unordered_map<uint32_t, std::vector<uint32_t>>& id_value_map) {
144   return MakeUnique<Optimizer::PassToken::Impl>(
145       MakeUnique<opt::SetSpecConstantDefaultValuePass>(id_value_map));
146 }
147
148 Optimizer::PassToken CreateFlattenDecorationPass() {
149   return MakeUnique<Optimizer::PassToken::Impl>(
150       MakeUnique<opt::FlattenDecorationPass>());
151 }
152
153 Optimizer::PassToken CreateFreezeSpecConstantValuePass() {
154   return MakeUnique<Optimizer::PassToken::Impl>(
155       MakeUnique<opt::FreezeSpecConstantValuePass>());
156 }
157
158 Optimizer::PassToken CreateFoldSpecConstantOpAndCompositePass() {
159   return MakeUnique<Optimizer::PassToken::Impl>(
160       MakeUnique<opt::FoldSpecConstantOpAndCompositePass>());
161 }
162
163 Optimizer::PassToken CreateUnifyConstantPass() {
164   return MakeUnique<Optimizer::PassToken::Impl>(
165       MakeUnique<opt::UnifyConstantPass>());
166 }
167
168 Optimizer::PassToken CreateEliminateDeadConstantPass() {
169   return MakeUnique<Optimizer::PassToken::Impl>(
170       MakeUnique<opt::EliminateDeadConstantPass>());
171 }
172
173 Optimizer::PassToken CreateDeadVariableEliminationPass() {
174   return MakeUnique<Optimizer::PassToken::Impl>(
175       MakeUnique<opt::DeadVariableElimination>());
176 }
177
178 Optimizer::PassToken CreateStrengthReductionPass() {
179   return MakeUnique<Optimizer::PassToken::Impl>(
180       MakeUnique<opt::StrengthReductionPass>());
181 }
182
183 Optimizer::PassToken CreateBlockMergePass() {
184   return MakeUnique<Optimizer::PassToken::Impl>(
185       MakeUnique<opt::BlockMergePass>());
186 }
187
188 Optimizer::PassToken CreateInlineExhaustivePass() {
189   return MakeUnique<Optimizer::PassToken::Impl>(
190       MakeUnique<opt::InlineExhaustivePass>());
191 }
192
193 Optimizer::PassToken CreateInlineOpaquePass() {
194   return MakeUnique<Optimizer::PassToken::Impl>(
195       MakeUnique<opt::InlineOpaquePass>());
196 }
197
198 Optimizer::PassToken CreateLocalAccessChainConvertPass() {
199   return MakeUnique<Optimizer::PassToken::Impl>(
200       MakeUnique<opt::LocalAccessChainConvertPass>());
201 }
202
203 Optimizer::PassToken CreateLocalSingleBlockLoadStoreElimPass() {
204   return MakeUnique<Optimizer::PassToken::Impl>(
205       MakeUnique<opt::LocalSingleBlockLoadStoreElimPass>());
206 }
207
208 Optimizer::PassToken CreateLocalSingleStoreElimPass() {
209   return MakeUnique<Optimizer::PassToken::Impl>(
210       MakeUnique<opt::LocalSingleStoreElimPass>());
211 }
212
213 Optimizer::PassToken CreateInsertExtractElimPass() {
214   return MakeUnique<Optimizer::PassToken::Impl>(
215       MakeUnique<opt::InsertExtractElimPass>());
216 }
217
218 Optimizer::PassToken CreateDeadBranchElimPass() {
219   return MakeUnique<Optimizer::PassToken::Impl>(
220       MakeUnique<opt::DeadBranchElimPass>());
221 }
222
223 Optimizer::PassToken CreateLocalMultiStoreElimPass() {
224   return MakeUnique<Optimizer::PassToken::Impl>(
225       MakeUnique<opt::LocalMultiStoreElimPass>());
226 }
227
228 Optimizer::PassToken CreateAggressiveDCEPass() {
229   return MakeUnique<Optimizer::PassToken::Impl>(
230       MakeUnique<opt::AggressiveDCEPass>());
231 }
232
233 Optimizer::PassToken CreateCommonUniformElimPass() {
234   return MakeUnique<Optimizer::PassToken::Impl>(
235       MakeUnique<opt::CommonUniformElimPass>());
236 }
237
238 Optimizer::PassToken CreateCompactIdsPass() {
239   return MakeUnique<Optimizer::PassToken::Impl>(
240       MakeUnique<opt::CompactIdsPass>());
241 }
242
243 std::vector<const char*> Optimizer::GetPassNames() const {
244   std::vector<const char*> v;
245   for (uint32_t i = 0; i < impl_->pass_manager.NumPasses(); i++) {
246     v.push_back(impl_->pass_manager.GetPass(i)->name());
247   }
248   return v;
249 }
250
251 Optimizer::PassToken CreateCFGCleanupPass() {
252   return MakeUnique<Optimizer::PassToken::Impl>(
253       MakeUnique<opt::CFGCleanupPass>());
254 }
255
256 }  // namespace spvtools