| 33 | } |
| 34 | |
| 35 | bool TransformationInlineFunction::IsApplicable( |
| 36 | opt::IRContext* ir_context, |
| 37 | const TransformationContext& transformation_context) const { |
| 38 | // The values in the |message_.result_id_map| must be all fresh and all |
| 39 | // distinct. |
| 40 | const auto result_id_map = |
| 41 | fuzzerutil::RepeatedUInt32PairToMap(message_.result_id_map()); |
| 42 | std::set<uint32_t> ids_used_by_this_transformation; |
| 43 | for (auto& pair : result_id_map) { |
| 44 | if (!CheckIdIsFreshAndNotUsedByThisTransformation( |
| 45 | pair.second, ir_context, &ids_used_by_this_transformation)) { |
| 46 | return false; |
| 47 | } |
| 48 | } |
| 49 | |
| 50 | // |function_call_instruction| must be suitable for inlining. |
| 51 | auto* function_call_instruction = |
| 52 | ir_context->get_def_use_mgr()->GetDef(message_.function_call_id()); |
| 53 | if (!IsSuitableForInlining(ir_context, function_call_instruction)) { |
| 54 | return false; |
| 55 | } |
| 56 | |
| 57 | // |function_call_instruction| must be the penultimate instruction in its |
| 58 | // block and its block termination instruction must be an OpBranch. This |
| 59 | // avoids the case where the penultimate instruction is an OpLoopMerge, which |
| 60 | // would make the back-edge block not branch to the loop header. |
| 61 | auto* function_call_instruction_block = |
| 62 | ir_context->get_instr_block(function_call_instruction); |
| 63 | if (function_call_instruction != |
| 64 | &*--function_call_instruction_block->tail() || |
| 65 | function_call_instruction_block->terminator()->opcode() != |
| 66 | spv::Op::OpBranch) { |
| 67 | return false; |
| 68 | } |
| 69 | |
| 70 | auto* called_function = fuzzerutil::FindFunction( |
| 71 | ir_context, function_call_instruction->GetSingleWordInOperand(0)); |
| 72 | for (auto& block : *called_function) { |
| 73 | // Since the entry block label will not be inlined, only the remaining |
| 74 | // labels must have a corresponding value in the map. |
| 75 | if (&block != &*called_function->entry() && |
| 76 | !result_id_map.count(block.id()) && |
| 77 | !transformation_context.GetOverflowIdSource()->HasOverflowIds()) { |
| 78 | return false; |
| 79 | } |
| 80 | |
| 81 | // |result_id_map| must have an entry for every result id in the called |
| 82 | // function. |
| 83 | for (auto& instruction : block) { |
| 84 | // If |instruction| has result id, then it must have a mapped id in |
| 85 | // |result_id_map|. |
| 86 | if (instruction.HasResultId() && |
| 87 | !result_id_map.count(instruction.result_id()) && |
| 88 | !transformation_context.GetOverflowIdSource()->HasOverflowIds()) { |
| 89 | return false; |
| 90 | } |
| 91 | } |
| 92 | } |
nothing calls this directly
no test coverage detected