| 104 | } |
| 105 | |
| 106 | void TransformationInlineFunction::Apply( |
| 107 | opt::IRContext* ir_context, |
| 108 | TransformationContext* transformation_context) const { |
| 109 | auto* function_call_instruction = |
| 110 | ir_context->get_def_use_mgr()->GetDef(message_.function_call_id()); |
| 111 | auto* caller_function = |
| 112 | ir_context->get_instr_block(function_call_instruction)->GetParent(); |
| 113 | auto* called_function = fuzzerutil::FindFunction( |
| 114 | ir_context, function_call_instruction->GetSingleWordInOperand(0)); |
| 115 | std::map<uint32_t, uint32_t> result_id_map = |
| 116 | fuzzerutil::RepeatedUInt32PairToMap(message_.result_id_map()); |
| 117 | |
| 118 | // If there are gaps in the result id map, fill them using overflow ids. |
| 119 | for (auto& block : *called_function) { |
| 120 | if (&block != &*called_function->entry() && |
| 121 | !result_id_map.count(block.id())) { |
| 122 | result_id_map.insert( |
| 123 | {block.id(), |
| 124 | transformation_context->GetOverflowIdSource()->GetNextOverflowId()}); |
| 125 | } |
| 126 | for (auto& instruction : block) { |
| 127 | // If |instruction| has result id, then it must have a mapped id in |
| 128 | // |result_id_map|. |
| 129 | if (instruction.HasResultId() && |
| 130 | !result_id_map.count(instruction.result_id())) { |
| 131 | result_id_map.insert({instruction.result_id(), |
| 132 | transformation_context->GetOverflowIdSource() |
| 133 | ->GetNextOverflowId()}); |
| 134 | } |
| 135 | } |
| 136 | } |
| 137 | |
| 138 | auto* successor_block = ir_context->cfg()->block( |
| 139 | ir_context->get_instr_block(function_call_instruction) |
| 140 | ->terminator() |
| 141 | ->GetSingleWordInOperand(0)); |
| 142 | |
| 143 | // Inline the |called_function| entry block. |
| 144 | for (auto& entry_block_instruction : *called_function->entry()) { |
| 145 | opt::Instruction* inlined_instruction; |
| 146 | |
| 147 | if (entry_block_instruction.opcode() == spv::Op::OpVariable) { |
| 148 | // All OpVariable instructions in a function must be in the first block |
| 149 | // in the function. |
| 150 | inlined_instruction = caller_function->begin()->begin()->InsertBefore( |
| 151 | std::unique_ptr<opt::Instruction>( |
| 152 | entry_block_instruction.Clone(ir_context))); |
| 153 | } else { |
| 154 | inlined_instruction = function_call_instruction->InsertBefore( |
| 155 | std::unique_ptr<opt::Instruction>( |
| 156 | entry_block_instruction.Clone(ir_context))); |
| 157 | } |
| 158 | |
| 159 | AdaptInlinedInstruction(result_id_map, ir_context, inlined_instruction); |
| 160 | } |
| 161 | |
| 162 | // If the function call's successor block contains OpPhi instructions that |
| 163 | // refer to the block containing the call then these will need to be rewritten |
nothing calls this directly
no test coverage detected