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(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());
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());
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());
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);
121 return status != opt::Pass::Status::Failure;
124 Optimizer::PassToken CreateNullPass() {
125 return MakeUnique<Optimizer::PassToken::Impl>(MakeUnique<opt::NullPass>());
128 Optimizer::PassToken CreateStripDebugInfoPass() {
129 return MakeUnique<Optimizer::PassToken::Impl>(
130 MakeUnique<opt::StripDebugInfoPass>());
133 Optimizer::PassToken CreateEliminateDeadFunctionsPass() {
134 return MakeUnique<Optimizer::PassToken::Impl>(
135 MakeUnique<opt::EliminateDeadFunctionsPass>());
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));
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));
150 Optimizer::PassToken CreateFlattenDecorationPass() {
151 return MakeUnique<Optimizer::PassToken::Impl>(
152 MakeUnique<opt::FlattenDecorationPass>());
155 Optimizer::PassToken CreateFreezeSpecConstantValuePass() {
156 return MakeUnique<Optimizer::PassToken::Impl>(
157 MakeUnique<opt::FreezeSpecConstantValuePass>());
160 Optimizer::PassToken CreateFoldSpecConstantOpAndCompositePass() {
161 return MakeUnique<Optimizer::PassToken::Impl>(
162 MakeUnique<opt::FoldSpecConstantOpAndCompositePass>());
165 Optimizer::PassToken CreateUnifyConstantPass() {
166 return MakeUnique<Optimizer::PassToken::Impl>(
167 MakeUnique<opt::UnifyConstantPass>());
170 Optimizer::PassToken CreateEliminateDeadConstantPass() {
171 return MakeUnique<Optimizer::PassToken::Impl>(
172 MakeUnique<opt::EliminateDeadConstantPass>());
175 Optimizer::PassToken CreateDeadVariableEliminationPass() {
176 return MakeUnique<Optimizer::PassToken::Impl>(
177 MakeUnique<opt::DeadVariableElimination>());
180 Optimizer::PassToken CreateStrengthReductionPass() {
181 return MakeUnique<Optimizer::PassToken::Impl>(
182 MakeUnique<opt::StrengthReductionPass>());
185 Optimizer::PassToken CreateBlockMergePass() {
186 return MakeUnique<Optimizer::PassToken::Impl>(
187 MakeUnique<opt::BlockMergePass>());
190 Optimizer::PassToken CreateInlineExhaustivePass() {
191 return MakeUnique<Optimizer::PassToken::Impl>(
192 MakeUnique<opt::InlineExhaustivePass>());
195 Optimizer::PassToken CreateInlineOpaquePass() {
196 return MakeUnique<Optimizer::PassToken::Impl>(
197 MakeUnique<opt::InlineOpaquePass>());
200 Optimizer::PassToken CreateLocalAccessChainConvertPass() {
201 return MakeUnique<Optimizer::PassToken::Impl>(
202 MakeUnique<opt::LocalAccessChainConvertPass>());
205 Optimizer::PassToken CreateLocalSingleBlockLoadStoreElimPass() {
206 return MakeUnique<Optimizer::PassToken::Impl>(
207 MakeUnique<opt::LocalSingleBlockLoadStoreElimPass>());
210 Optimizer::PassToken CreateLocalSingleStoreElimPass() {
211 return MakeUnique<Optimizer::PassToken::Impl>(
212 MakeUnique<opt::LocalSingleStoreElimPass>());
215 Optimizer::PassToken CreateInsertExtractElimPass() {
216 return MakeUnique<Optimizer::PassToken::Impl>(
217 MakeUnique<opt::InsertExtractElimPass>());
220 Optimizer::PassToken CreateDeadBranchElimPass() {
221 return MakeUnique<Optimizer::PassToken::Impl>(
222 MakeUnique<opt::DeadBranchElimPass>());
225 Optimizer::PassToken CreateLocalMultiStoreElimPass() {
226 return MakeUnique<Optimizer::PassToken::Impl>(
227 MakeUnique<opt::LocalMultiStoreElimPass>());
230 Optimizer::PassToken CreateAggressiveDCEPass() {
231 return MakeUnique<Optimizer::PassToken::Impl>(
232 MakeUnique<opt::AggressiveDCEPass>());
235 Optimizer::PassToken CreateCommonUniformElimPass() {
236 return MakeUnique<Optimizer::PassToken::Impl>(
237 MakeUnique<opt::CommonUniformElimPass>());
240 Optimizer::PassToken CreateCompactIdsPass() {
241 return MakeUnique<Optimizer::PassToken::Impl>(
242 MakeUnique<opt::CompactIdsPass>());
245 Optimizer::PassToken CreateMergeReturnPass() {
246 return MakeUnique<Optimizer::PassToken::Impl>(
247 MakeUnique<opt::MergeReturnPass>());
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());
258 Optimizer::PassToken CreateCFGCleanupPass() {
259 return MakeUnique<Optimizer::PassToken::Impl>(
260 MakeUnique<opt::CFGCleanupPass>());
263 } // namespace spvtools