1 // Copyright (c) 2016 Google Inc.
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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.
15 #include "spirv-tools/optimizer.hpp"
17 #include "build_module.h"
18 #include "make_unique.h"
19 #include "pass_manager.h"
24 struct Optimizer::PassToken::Impl {
25 Impl(std::unique_ptr<opt::Pass> p) : pass(std::move(p)) {}
27 std::unique_ptr<opt::Pass> pass; // Internal implementation pass.
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_)) {}
36 Optimizer::PassToken& Optimizer::PassToken::operator=(PassToken&& that) {
37 impl_ = std::move(that.impl_);
41 Optimizer::PassToken::~PassToken() {}
43 struct Optimizer::Impl {
44 explicit Impl(spv_target_env env) : target_env(env), pass_manager() {}
46 const spv_target_env target_env; // Target environment.
47 opt::PassManager pass_manager; // Internal implementation pass manager.
50 Optimizer::Optimizer(spv_target_env env) : impl_(new Impl(env)) {}
52 Optimizer::~Optimizer() {}
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);
59 impl_->pass_manager.SetMessageConsumer(std::move(c));
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));
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());
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());
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());
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);
119 return status != opt::Pass::Status::Failure;
122 Optimizer::PassToken CreateNullPass() {
123 return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::NullPass>());
126 Optimizer::PassToken CreateStripDebugInfoPass() {
127 return MakeUnique<Optimizer::PassToken::Impl>(
128 MakeUnique<opt::StripDebugInfoPass>());
131 Optimizer::PassToken CreateEliminateDeadFunctionsPass() {
132 return MakeUnique<Optimizer::PassToken::Impl>(
133 MakeUnique<opt::EliminateDeadFunctionsPass>());
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));
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));
148 Optimizer::PassToken CreateFlattenDecorationPass() {
149 return MakeUnique<Optimizer::PassToken::Impl>(
150 MakeUnique<opt::FlattenDecorationPass>());
153 Optimizer::PassToken CreateFreezeSpecConstantValuePass() {
154 return MakeUnique<Optimizer::PassToken::Impl>(
155 MakeUnique<opt::FreezeSpecConstantValuePass>());
158 Optimizer::PassToken CreateFoldSpecConstantOpAndCompositePass() {
159 return MakeUnique<Optimizer::PassToken::Impl>(
160 MakeUnique<opt::FoldSpecConstantOpAndCompositePass>());
163 Optimizer::PassToken CreateUnifyConstantPass() {
164 return MakeUnique<Optimizer::PassToken::Impl>(
165 MakeUnique<opt::UnifyConstantPass>());
168 Optimizer::PassToken CreateEliminateDeadConstantPass() {
169 return MakeUnique<Optimizer::PassToken::Impl>(
170 MakeUnique<opt::EliminateDeadConstantPass>());
173 Optimizer::PassToken CreateDeadVariableEliminationPass() {
174 return MakeUnique<Optimizer::PassToken::Impl>(
175 MakeUnique<opt::DeadVariableElimination>());
178 Optimizer::PassToken CreateStrengthReductionPass() {
179 return MakeUnique<Optimizer::PassToken::Impl>(
180 MakeUnique<opt::StrengthReductionPass>());
183 Optimizer::PassToken CreateBlockMergePass() {
184 return MakeUnique<Optimizer::PassToken::Impl>(
185 MakeUnique<opt::BlockMergePass>());
188 Optimizer::PassToken CreateInlineExhaustivePass() {
189 return MakeUnique<Optimizer::PassToken::Impl>(
190 MakeUnique<opt::InlineExhaustivePass>());
193 Optimizer::PassToken CreateInlineOpaquePass() {
194 return MakeUnique<Optimizer::PassToken::Impl>(
195 MakeUnique<opt::InlineOpaquePass>());
198 Optimizer::PassToken CreateLocalAccessChainConvertPass() {
199 return MakeUnique<Optimizer::PassToken::Impl>(
200 MakeUnique<opt::LocalAccessChainConvertPass>());
203 Optimizer::PassToken CreateLocalSingleBlockLoadStoreElimPass() {
204 return MakeUnique<Optimizer::PassToken::Impl>(
205 MakeUnique<opt::LocalSingleBlockLoadStoreElimPass>());
208 Optimizer::PassToken CreateLocalSingleStoreElimPass() {
209 return MakeUnique<Optimizer::PassToken::Impl>(
210 MakeUnique<opt::LocalSingleStoreElimPass>());
213 Optimizer::PassToken CreateInsertExtractElimPass() {
214 return MakeUnique<Optimizer::PassToken::Impl>(
215 MakeUnique<opt::InsertExtractElimPass>());
218 Optimizer::PassToken CreateDeadBranchElimPass() {
219 return MakeUnique<Optimizer::PassToken::Impl>(
220 MakeUnique<opt::DeadBranchElimPass>());
223 Optimizer::PassToken CreateLocalMultiStoreElimPass() {
224 return MakeUnique<Optimizer::PassToken::Impl>(
225 MakeUnique<opt::LocalMultiStoreElimPass>());
228 Optimizer::PassToken CreateAggressiveDCEPass() {
229 return MakeUnique<Optimizer::PassToken::Impl>(
230 MakeUnique<opt::AggressiveDCEPass>());
233 Optimizer::PassToken CreateCommonUniformElimPass() {
234 return MakeUnique<Optimizer::PassToken::Impl>(
235 MakeUnique<opt::CommonUniformElimPass>());
238 Optimizer::PassToken CreateCompactIdsPass() {
239 return MakeUnique<Optimizer::PassToken::Impl>(
240 MakeUnique<opt::CompactIdsPass>());
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());
251 Optimizer::PassToken CreateCFGCleanupPass() {
252 return MakeUnique<Optimizer::PassToken::Impl>(
253 MakeUnique<opt::CFGCleanupPass>());
256 } // namespace spvtools