| 117 | } |
| 118 | |
| 119 | void LoopFissionImpl::TraverseUseDef(Instruction* inst, |
| 120 | std::set<Instruction*>* returned_set, |
| 121 | bool ignore_phi_users, bool report_loads) { |
| 122 | assert(returned_set && "Set to be returned cannot be null."); |
| 123 | |
| 124 | analysis::DefUseManager* def_use = context_->get_def_use_mgr(); |
| 125 | std::set<Instruction*>& inst_set = *returned_set; |
| 126 | |
| 127 | // We create this functor to traverse the use def chain to build the |
| 128 | // grouping of related instructions. The lambda captures the std::function |
| 129 | // to allow it to recurse. |
| 130 | std::function<void(Instruction*)> traverser_functor; |
| 131 | traverser_functor = [this, def_use, &inst_set, &traverser_functor, |
| 132 | ignore_phi_users, report_loads](Instruction* user) { |
| 133 | // If we've seen the instruction before or it is not inside the loop end the |
| 134 | // traversal. |
| 135 | if (!user || seen_instructions_.count(user) != 0 || |
| 136 | !context_->get_instr_block(user) || |
| 137 | !loop_->IsInsideLoop(context_->get_instr_block(user))) { |
| 138 | return; |
| 139 | } |
| 140 | |
| 141 | // Don't include labels or loop merge instructions in the instruction sets. |
| 142 | // Including them would mean we group instructions related only by using the |
| 143 | // same labels (i.e phis). We already preempt the inclusion of |
| 144 | // OpSelectionMerge by adding related instructions to the seen_instructions_ |
| 145 | // set. |
| 146 | if (user->opcode() == spv::Op::OpLoopMerge || |
| 147 | user->opcode() == spv::Op::OpLabel) |
| 148 | return; |
| 149 | |
| 150 | // If the |report_loads| flag is set, set the class field |
| 151 | // load_used_in_condition_ to false. This is used to check that none of the |
| 152 | // condition checks in the loop rely on loads. |
| 153 | if (user->opcode() == spv::Op::OpLoad && report_loads) { |
| 154 | load_used_in_condition_ = true; |
| 155 | } |
| 156 | |
| 157 | // Add the instruction to the set of instructions already seen, this breaks |
| 158 | // recursion and allows us to ignore certain instructions. |
| 159 | seen_instructions_.insert(user); |
| 160 | |
| 161 | inst_set.insert(user); |
| 162 | |
| 163 | // Wrapper functor to traverse the operands of each instruction. |
| 164 | auto traverse_operand = [&traverser_functor, def_use](const uint32_t* id) { |
| 165 | traverser_functor(def_use->GetDef(*id)); |
| 166 | }; |
| 167 | user->ForEachInOperand(traverse_operand); |
| 168 | |
| 169 | // For the first traversal we want to ignore the users of the phi. |
| 170 | if (ignore_phi_users && user->opcode() == spv::Op::OpPhi) return; |
| 171 | |
| 172 | // Traverse each user with this lambda. |
| 173 | def_use->ForEachUser(user, traverser_functor); |
| 174 | |
| 175 | // Wrapper functor for the use traversal. |
| 176 | auto traverse_use = [&traverser_functor](Instruction* use, uint32_t) { |
nothing calls this directly
no test coverage detected