| 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 |  | 
|---|