1fd4e5da5Sopenharmony_ci// Copyright (c) 2018 Google LLC
2fd4e5da5Sopenharmony_ci//
3fd4e5da5Sopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License");
4fd4e5da5Sopenharmony_ci// you may not use this file except in compliance with the License.
5fd4e5da5Sopenharmony_ci// You may obtain a copy of the License at
6fd4e5da5Sopenharmony_ci//
7fd4e5da5Sopenharmony_ci//     http://www.apache.org/licenses/LICENSE-2.0
8fd4e5da5Sopenharmony_ci//
9fd4e5da5Sopenharmony_ci// Unless required by applicable law or agreed to in writing, software
10fd4e5da5Sopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS,
11fd4e5da5Sopenharmony_ci// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12fd4e5da5Sopenharmony_ci// See the License for the specific language governing permissions and
13fd4e5da5Sopenharmony_ci// limitations under the License.
14fd4e5da5Sopenharmony_ci
15fd4e5da5Sopenharmony_ci#include "source/reduce/reduction_pass.h"
16fd4e5da5Sopenharmony_ci
17fd4e5da5Sopenharmony_ci#include <algorithm>
18fd4e5da5Sopenharmony_ci
19fd4e5da5Sopenharmony_ci#include "source/opt/build_module.h"
20fd4e5da5Sopenharmony_ci
21fd4e5da5Sopenharmony_cinamespace spvtools {
22fd4e5da5Sopenharmony_cinamespace reduce {
23fd4e5da5Sopenharmony_ci
24fd4e5da5Sopenharmony_cistd::vector<uint32_t> ReductionPass::TryApplyReduction(
25fd4e5da5Sopenharmony_ci    const std::vector<uint32_t>& binary, uint32_t target_function) {
26fd4e5da5Sopenharmony_ci  // We represent modules as binaries because (a) attempts at reduction need to
27fd4e5da5Sopenharmony_ci  // end up in binary form to be passed on to SPIR-V-consuming tools, and (b)
28fd4e5da5Sopenharmony_ci  // when we apply a reduction step we need to do it on a fresh version of the
29fd4e5da5Sopenharmony_ci  // module as if the reduction step proves to be uninteresting we need to
30fd4e5da5Sopenharmony_ci  // backtrack; re-parsing from binary provides a very clean way of cloning the
31fd4e5da5Sopenharmony_ci  // module.
32fd4e5da5Sopenharmony_ci  std::unique_ptr<opt::IRContext> context =
33fd4e5da5Sopenharmony_ci      BuildModule(target_env_, consumer_, binary.data(), binary.size());
34fd4e5da5Sopenharmony_ci  assert(context);
35fd4e5da5Sopenharmony_ci
36fd4e5da5Sopenharmony_ci  std::vector<std::unique_ptr<ReductionOpportunity>> opportunities =
37fd4e5da5Sopenharmony_ci      finder_->GetAvailableOpportunities(context.get(), target_function);
38fd4e5da5Sopenharmony_ci
39fd4e5da5Sopenharmony_ci  // There is no point in having a granularity larger than the number of
40fd4e5da5Sopenharmony_ci  // opportunities, so reduce the granularity in this case.
41fd4e5da5Sopenharmony_ci  if (granularity_ > opportunities.size()) {
42fd4e5da5Sopenharmony_ci    granularity_ = std::max((uint32_t)1, (uint32_t)opportunities.size());
43fd4e5da5Sopenharmony_ci  }
44fd4e5da5Sopenharmony_ci
45fd4e5da5Sopenharmony_ci  assert(granularity_ > 0);
46fd4e5da5Sopenharmony_ci
47fd4e5da5Sopenharmony_ci  if (index_ >= opportunities.size()) {
48fd4e5da5Sopenharmony_ci    // We have reached the end of the available opportunities and, therefore,
49fd4e5da5Sopenharmony_ci    // the end of the round for this pass, so reset the index and decrease the
50fd4e5da5Sopenharmony_ci    // granularity for the next round. Return an empty vector to signal the end
51fd4e5da5Sopenharmony_ci    // of the round.
52fd4e5da5Sopenharmony_ci    index_ = 0;
53fd4e5da5Sopenharmony_ci    granularity_ = std::max((uint32_t)1, granularity_ / 2);
54fd4e5da5Sopenharmony_ci    return std::vector<uint32_t>();
55fd4e5da5Sopenharmony_ci  }
56fd4e5da5Sopenharmony_ci
57fd4e5da5Sopenharmony_ci  for (uint32_t i = index_;
58fd4e5da5Sopenharmony_ci       i < std::min(index_ + granularity_, (uint32_t)opportunities.size());
59fd4e5da5Sopenharmony_ci       ++i) {
60fd4e5da5Sopenharmony_ci    opportunities[i]->TryToApply();
61fd4e5da5Sopenharmony_ci  }
62fd4e5da5Sopenharmony_ci
63fd4e5da5Sopenharmony_ci  std::vector<uint32_t> result;
64fd4e5da5Sopenharmony_ci  context->module()->ToBinary(&result, false);
65fd4e5da5Sopenharmony_ci  return result;
66fd4e5da5Sopenharmony_ci}
67fd4e5da5Sopenharmony_ci
68fd4e5da5Sopenharmony_civoid ReductionPass::SetMessageConsumer(MessageConsumer consumer) {
69fd4e5da5Sopenharmony_ci  consumer_ = std::move(consumer);
70fd4e5da5Sopenharmony_ci}
71fd4e5da5Sopenharmony_ci
72fd4e5da5Sopenharmony_cibool ReductionPass::ReachedMinimumGranularity() const {
73fd4e5da5Sopenharmony_ci  assert(granularity_ != 0);
74fd4e5da5Sopenharmony_ci  return granularity_ == 1;
75fd4e5da5Sopenharmony_ci}
76fd4e5da5Sopenharmony_ci
77fd4e5da5Sopenharmony_cistd::string ReductionPass::GetName() const { return finder_->GetName(); }
78fd4e5da5Sopenharmony_ci
79fd4e5da5Sopenharmony_civoid ReductionPass::NotifyInteresting(bool interesting) {
80fd4e5da5Sopenharmony_ci  if (!interesting) {
81fd4e5da5Sopenharmony_ci    index_ += granularity_;
82fd4e5da5Sopenharmony_ci  }
83fd4e5da5Sopenharmony_ci}
84fd4e5da5Sopenharmony_ci
85fd4e5da5Sopenharmony_ci}  // namespace reduce
86fd4e5da5Sopenharmony_ci}  // namespace spvtools
87