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 #include "operand_to_const_reduction_pass.h" 16 #include "change_operand_reduction_opportunity.h" 17 #include "source/opt/instruction.h" 18 19 namespace spvtools { 20 namespace reduce { 21 22 using namespace opt; 23 24 std::vector<std::unique_ptr<ReductionOpportunity>> 25 OperandToConstReductionPass::GetAvailableOpportunities( 26 opt::IRContext* context) const { 27 std::vector<std::unique_ptr<ReductionOpportunity>> result; 28 assert(result.empty()); 29 30 // We first loop over all constants. This means that all the reduction 31 // opportunities to replace an operand with a particular constant will be 32 // contiguous, and in particular it means that multiple, incompatible 33 // reduction opportunities that try to replace the same operand with distinct 34 // constants are likely to be discontiguous. This is good because the 35 // reducer works in the spirit of delta debugging and tries applying large 36 // contiguous blocks of opportunities early on, and we want to avoid having a 37 // large block of incompatible opportunities if possible. 38 for (const auto& constant : context->GetConstants()) { 39 for (auto& function : *context->module()) { 40 for (auto& block : function) { 41 for (auto& inst : block) { 42 // We iterate through the operands using an explicit index (rather 43 // than using a lambda) so that we use said index in the construction 44 // of a ChangeOperandReductionOpportunity 45 for (uint32_t index = 0; index < inst.NumOperands(); index++) { 46 const auto& operand = inst.GetOperand(index); 47 if (spvIsInIdType(operand.type)) { 48 const auto id = operand.words[0]; 49 auto def = context->get_def_use_mgr()->GetDef(id); 50 if (spvOpcodeIsConstant(def->opcode())) { 51 // The argument is already a constant. 52 continue; 53 } 54 if (def->opcode() == SpvOpFunction) { 55 // The argument refers to a function, e.g. the function called 56 // by OpFunctionCall; avoid replacing this with a constant of 57 // the function's return type. 58 continue; 59 } 60 auto type_id = def->type_id(); 61 if (type_id) { 62 if (constant->type_id() == type_id) { 63 result.push_back( 64 MakeUnique<ChangeOperandReductionOpportunity>( 65 &inst, index, constant->result_id())); 66 } 67 } 68 } 69 } 70 } 71 } 72 } 73 } 74 return result; 75 } 76 77 std::string OperandToConstReductionPass::GetName() const { 78 return "OperandToConstReductionPass"; 79 } 80 81 } // namespace reduce 82 } // namespace spvtools 83