1// Copyright (c) 2017 The Khronos Group Inc.
2// Copyright (c) 2017 Valve Corporation
3// Copyright (c) 2017 LunarG Inc.
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17#ifndef SOURCE_OPT_LOCAL_SINGLE_STORE_ELIM_PASS_H_
18#define SOURCE_OPT_LOCAL_SINGLE_STORE_ELIM_PASS_H_
19
20#include <algorithm>
21#include <map>
22#include <queue>
23#include <string>
24#include <unordered_map>
25#include <unordered_set>
26#include <utility>
27#include <vector>
28
29#include "source/opt/basic_block.h"
30#include "source/opt/def_use_manager.h"
31#include "source/opt/mem_pass.h"
32#include "source/opt/module.h"
33
34namespace spvtools {
35namespace opt {
36
37// See optimizer.hpp for documentation.
38class LocalSingleStoreElimPass : public Pass {
39 using cbb_ptr = const BasicBlock*;
40
41 public:
42 LocalSingleStoreElimPass();
43
44 const char* name() const override { return "eliminate-local-single-store"; }
45 Status Process() override;
46
47 IRContext::Analysis GetPreservedAnalyses() override {
48 return IRContext::kAnalysisDefUse |
49 IRContext::kAnalysisInstrToBlockMapping |
50 IRContext::kAnalysisConstants | IRContext::kAnalysisTypes;
51 }
52
53 private:
54 // Do "single-store" optimization of function variables defined only
55 // with a single non-access-chain store in |func|. Replace all their
56 // non-access-chain loads with the value that is stored and eliminate
57 // any resulting dead code.
58 bool LocalSingleStoreElim(Function* func);
59
60 // Initialize extensions whitelist
61 void InitExtensionWhiteList();
62
63 // Return true if all extensions in this module are allowed by this pass.
64 bool AllExtensionsSupported() const;
65
66 Pass::Status ProcessImpl();
67
68 // If there is a single store to |var_inst|, and it covers the entire
69 // variable, then replace all of the loads of the entire variable that are
70 // dominated by the store by the value that was stored. Returns true if the
71 // module was changed.
72 bool ProcessVariable(Instruction* var_inst);
73
74 // Collects all of the uses of |var_inst| into |uses|. This looks through
75 // OpObjectCopy's that copy the address of the variable, and collects those
76 // uses as well.
77 void FindUses(const Instruction* var_inst,
78 std::vector<Instruction*>* uses) const;
79
80 // Returns a store to |var_inst| if
81 // - it is a store to the entire variable,
82 // - and there are no other instructions that may modify |var_inst|.
83 Instruction* FindSingleStoreAndCheckUses(
84 Instruction* var_inst, const std::vector<Instruction*>& users) const;
85
86 // Returns true if the address that results from |inst| may be used as a base
87 // address in a store instruction or may be used to compute the base address
88 // of a store instruction.
89 bool FeedsAStore(Instruction* inst) const;
90
91 // Replaces all of the loads in |uses| by the value stored in |store_inst|.
92 // The load instructions are then killed.
93 bool RewriteLoads(Instruction* store_inst,
94 const std::vector<Instruction*>& uses);
95
96 // Extensions supported by this pass.
97 std::unordered_set<std::string> extensions_whitelist_;
98};
99
100} // namespace opt
101} // namespace spvtools
102
103#endif // SOURCE_OPT_LOCAL_SINGLE_STORE_ELIM_PASS_H_
104