1 | // Copyright (c) 2018 Google LLC. |
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 | #ifndef SOURCE_OPT_VECTOR_DCE_H_ |
16 | #define SOURCE_OPT_VECTOR_DCE_H_ |
17 | |
18 | #include <unordered_map> |
19 | #include <vector> |
20 | |
21 | #include "source/opt/mem_pass.h" |
22 | #include "source/util/bit_vector.h" |
23 | |
24 | namespace spvtools { |
25 | namespace opt { |
26 | |
27 | class VectorDCE : public MemPass { |
28 | private: |
29 | using LiveComponentMap = std::unordered_map<uint32_t, utils::BitVector>; |
30 | |
31 | // According to the SPEC the maximum size for a vector is 16. See the data |
32 | // rules in the universal validation rules (section 2.16.1). |
33 | enum { kMaxVectorSize = 16 }; |
34 | |
35 | struct WorkListItem { |
36 | WorkListItem() : instruction(nullptr), components(kMaxVectorSize) {} |
37 | |
38 | Instruction* instruction; |
39 | utils::BitVector components; |
40 | }; |
41 | |
42 | public: |
43 | VectorDCE() : all_components_live_(kMaxVectorSize) { |
44 | for (uint32_t i = 0; i < kMaxVectorSize; i++) { |
45 | all_components_live_.Set(i); |
46 | } |
47 | } |
48 | |
49 | const char* name() const override { return "vector-dce" ; } |
50 | Status Process() override; |
51 | |
52 | IRContext::Analysis GetPreservedAnalyses() override { |
53 | return IRContext::kAnalysisDefUse | IRContext::kAnalysisCFG | |
54 | IRContext::kAnalysisInstrToBlockMapping | |
55 | IRContext::kAnalysisLoopAnalysis | IRContext::kAnalysisDecorations | |
56 | IRContext::kAnalysisDominatorAnalysis | IRContext::kAnalysisNameMap | |
57 | IRContext::kAnalysisConstants | IRContext::kAnalysisTypes; |
58 | } |
59 | |
60 | private: |
61 | // Runs the vector dce pass on |function|. Returns true if |function| was |
62 | // modified. |
63 | bool VectorDCEFunction(Function* function); |
64 | |
65 | // Identifies the live components of the vectors that are results of |
66 | // instructions in |function|. The results are stored in |live_components|. |
67 | void FindLiveComponents(Function* function, |
68 | LiveComponentMap* live_components); |
69 | |
70 | // Rewrites instructions in |function| that are dead or partially dead. If an |
71 | // instruction does not have an entry in |live_components|, then it is not |
72 | // changed. Returns true if |function| was modified. |
73 | bool RewriteInstructions(Function* function, |
74 | const LiveComponentMap& live_components); |
75 | |
76 | // Rewrites the OpCompositeInsert instruction |current_inst| to avoid |
77 | // unnecessary computes given that the only components of the result that are |
78 | // live are |live_components|. |
79 | // |
80 | // If the value being inserted is not live, then the result of |current_inst| |
81 | // is replaced by the composite input to |current_inst|. |
82 | // |
83 | // If the composite input to |current_inst| is not live, then it is replaced |
84 | // by and OpUndef in |current_inst|. |
85 | bool RewriteInsertInstruction(Instruction* current_inst, |
86 | const utils::BitVector& live_components); |
87 | |
88 | // Returns true if the result of |inst| is a vector or a scalar. |
89 | bool HasVectorOrScalarResult(const Instruction* inst) const; |
90 | |
91 | // Returns true if the result of |inst| is a scalar. |
92 | bool HasVectorResult(const Instruction* inst) const; |
93 | |
94 | // Returns true if the result of |inst| is a vector. |
95 | bool HasScalarResult(const Instruction* inst) const; |
96 | |
97 | // Adds |work_item| to |work_list| if it is not already live according to |
98 | // |live_components|. |live_components| is updated to indicate that |
99 | // |work_item| is now live. |
100 | void AddItemToWorkListIfNeeded(WorkListItem work_item, |
101 | LiveComponentMap* live_components, |
102 | std::vector<WorkListItem>* work_list); |
103 | |
104 | // Marks the components |live_elements| of the uses in |current_inst| as live |
105 | // according to |live_components|. If they were not live before, then they are |
106 | // added to |work_list|. |
107 | void MarkUsesAsLive(Instruction* current_inst, |
108 | const utils::BitVector& live_elements, |
109 | LiveComponentMap* live_components, |
110 | std::vector<WorkListItem>* work_list); |
111 | |
112 | // Marks the uses in the OpVectorShuffle instruction in |current_item| as live |
113 | // based on the live components in |current_item|. If anything becomes live |
114 | // they are added to |work_list| and |live_components| is updated |
115 | // accordingly. |
116 | void MarkVectorShuffleUsesAsLive(const WorkListItem& current_item, |
117 | VectorDCE::LiveComponentMap* live_components, |
118 | std::vector<WorkListItem>* work_list); |
119 | |
120 | // Marks the uses in the OpCompositeInsert instruction in |current_item| as |
121 | // live based on the live components in |current_item|. If anything becomes |
122 | // live they are added to |work_list| and |live_components| is updated |
123 | // accordingly. |
124 | void MarkInsertUsesAsLive(const WorkListItem& current_item, |
125 | LiveComponentMap* live_components, |
126 | std::vector<WorkListItem>* work_list); |
127 | |
128 | // Marks the uses in the OpCompositeExtract instruction |current_inst| as |
129 | // live. If anything becomes live they are added to |work_list| and |
130 | // |live_components| is updated accordingly. |
131 | void (const Instruction* current_inst, |
132 | const utils::BitVector& live_elements, |
133 | LiveComponentMap* live_components, |
134 | std::vector<WorkListItem>* work_list); |
135 | |
136 | // Marks the uses in the OpCompositeConstruct instruction |current_inst| as |
137 | // live. If anything becomes live they are added to |work_list| and |
138 | // |live_components| is updated accordingly. |
139 | void MarkCompositeContructUsesAsLive(WorkListItem work_item, |
140 | LiveComponentMap* live_components, |
141 | std::vector<WorkListItem>* work_list); |
142 | |
143 | // A BitVector that can always be used to say that all components of a vector |
144 | // are live. |
145 | utils::BitVector all_components_live_; |
146 | }; |
147 | |
148 | } // namespace opt |
149 | } // namespace spvtools |
150 | |
151 | #endif // SOURCE_OPT_VECTOR_DCE_H_ |
152 | |