• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2018 Google Inc.
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 #include "source/reduce/remove_unused_instruction_reduction_opportunity_finder.h"
16 
17 #include "source/opcode.h"
18 #include "source/opt/instruction.h"
19 #include "source/reduce/remove_instruction_reduction_opportunity.h"
20 
21 namespace spvtools {
22 namespace reduce {
23 
24 RemoveUnusedInstructionReductionOpportunityFinder::
RemoveUnusedInstructionReductionOpportunityFinder(bool remove_constants_and_undefs)25     RemoveUnusedInstructionReductionOpportunityFinder(
26         bool remove_constants_and_undefs)
27     : remove_constants_and_undefs_(remove_constants_and_undefs) {}
28 
29 std::vector<std::unique_ptr<ReductionOpportunity>>
GetAvailableOpportunities(opt::IRContext * context,uint32_t target_function) const30 RemoveUnusedInstructionReductionOpportunityFinder::GetAvailableOpportunities(
31     opt::IRContext* context, uint32_t target_function) const {
32   std::vector<std::unique_ptr<ReductionOpportunity>> result;
33 
34   if (!target_function) {
35     // We are not restricting reduction to a specific function, so we consider
36     // unused instructions defined outside functions.
37 
38     for (auto& inst : context->module()->debugs1()) {
39       if (context->get_def_use_mgr()->NumUses(&inst) > 0) {
40         continue;
41       }
42       result.push_back(
43           MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
44     }
45 
46     for (auto& inst : context->module()->debugs2()) {
47       if (context->get_def_use_mgr()->NumUses(&inst) > 0) {
48         continue;
49       }
50       result.push_back(
51           MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
52     }
53 
54     for (auto& inst : context->module()->debugs3()) {
55       if (context->get_def_use_mgr()->NumUses(&inst) > 0) {
56         continue;
57       }
58       result.push_back(
59           MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
60     }
61 
62     for (auto& inst : context->module()->ext_inst_debuginfo()) {
63       if (context->get_def_use_mgr()->NumUses(&inst) > 0) {
64         continue;
65       }
66       result.push_back(
67           MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
68     }
69 
70     for (auto& inst : context->module()->types_values()) {
71       if (!remove_constants_and_undefs_ &&
72           spvOpcodeIsConstantOrUndef(inst.opcode())) {
73         continue;
74       }
75       if (!OnlyReferencedByIntimateDecorationOrEntryPointInterface(context,
76                                                                    inst)) {
77         continue;
78       }
79       result.push_back(
80           MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
81     }
82 
83     for (auto& inst : context->module()->annotations()) {
84       if (context->get_def_use_mgr()->NumUsers(&inst) > 0) {
85         continue;
86       }
87       if (!IsIndependentlyRemovableDecoration(inst)) {
88         continue;
89       }
90       result.push_back(
91           MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
92     }
93   }
94 
95   for (auto* function : GetTargetFunctions(context, target_function)) {
96     for (auto& block : *function) {
97       for (auto& inst : block) {
98         if (context->get_def_use_mgr()->NumUses(&inst) > 0) {
99           continue;
100         }
101         if (!remove_constants_and_undefs_ &&
102             spvOpcodeIsConstantOrUndef(inst.opcode())) {
103           continue;
104         }
105         if (spvOpcodeIsBlockTerminator(inst.opcode()) ||
106             inst.opcode() == SpvOpSelectionMerge ||
107             inst.opcode() == SpvOpLoopMerge) {
108           // In this reduction pass we do not want to affect static
109           // control flow.
110           continue;
111         }
112         // Given that we're in a block, we should only get here if
113         // the instruction is not directly related to control flow;
114         // i.e., it's some straightforward instruction with an
115         // unused result, like an arithmetic operation or function
116         // call.
117         result.push_back(
118             MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
119       }
120     }
121   }
122   return result;
123 }
124 
GetName() const125 std::string RemoveUnusedInstructionReductionOpportunityFinder::GetName() const {
126   return "RemoveUnusedInstructionReductionOpportunityFinder";
127 }
128 
129 bool RemoveUnusedInstructionReductionOpportunityFinder::
OnlyReferencedByIntimateDecorationOrEntryPointInterface(opt::IRContext * context,const opt::Instruction & inst) const130     OnlyReferencedByIntimateDecorationOrEntryPointInterface(
131         opt::IRContext* context, const opt::Instruction& inst) const {
132   return context->get_def_use_mgr()->WhileEachUse(
133       &inst, [this](opt::Instruction* user, uint32_t use_index) -> bool {
134         return (user->IsDecoration() &&
135                 !IsIndependentlyRemovableDecoration(*user)) ||
136                (user->opcode() == SpvOpEntryPoint && use_index > 2);
137       });
138 }
139 
140 bool RemoveUnusedInstructionReductionOpportunityFinder::
IsIndependentlyRemovableDecoration(const opt::Instruction & inst) const141     IsIndependentlyRemovableDecoration(const opt::Instruction& inst) const {
142   uint32_t decoration;
143   switch (inst.opcode()) {
144     case SpvOpDecorate:
145     case SpvOpDecorateId:
146     case SpvOpDecorateString:
147       decoration = inst.GetSingleWordInOperand(1u);
148       break;
149     case SpvOpMemberDecorate:
150     case SpvOpMemberDecorateString:
151       decoration = inst.GetSingleWordInOperand(2u);
152       break;
153     default:
154       // The instruction is not a decoration.  It is legitimate for this to be
155       // reached: it allows the method to be invoked on arbitrary instructions.
156       return false;
157   }
158 
159   // We conservatively only remove specific decorations that we believe will
160   // not change the shader interface, will not make the shader invalid, will
161   // actually be found in practice, etc.
162 
163   switch (decoration) {
164     case SpvDecorationRelaxedPrecision:
165     case SpvDecorationNoSignedWrap:
166     case SpvDecorationNoContraction:
167     case SpvDecorationNoUnsignedWrap:
168     case SpvDecorationUserSemantic:
169       return true;
170     default:
171       return false;
172   }
173 }
174 
175 }  // namespace reduce
176 }  // namespace spvtools
177