Home | History | Annotate | Download | only in reduce
      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