| 129 | } |
| 130 | |
| 131 | void TransformationReplaceParamsWithStruct::Apply( |
| 132 | opt::IRContext* ir_context, TransformationContext* /*unused*/) const { |
| 133 | auto* function = fuzzerutil::GetFunctionFromParameterId( |
| 134 | ir_context, message_.parameter_id(0)); |
| 135 | assert(function && |
| 136 | "All parameters' ids should've been checked in the IsApplicable"); |
| 137 | |
| 138 | // Get a type id of the OpTypeStruct used as a type id of the new parameter. |
| 139 | auto struct_type_id = MaybeGetRequiredStructType(ir_context); |
| 140 | assert(struct_type_id && |
| 141 | "IsApplicable should've guaranteed that this value isn't equal to 0"); |
| 142 | |
| 143 | // Add new parameter to the function. |
| 144 | function->AddParameter(MakeUnique<opt::Instruction>( |
| 145 | ir_context, spv::Op::OpFunctionParameter, struct_type_id, |
| 146 | message_.fresh_parameter_id(), opt::Instruction::OperandList())); |
| 147 | |
| 148 | fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_parameter_id()); |
| 149 | |
| 150 | // Compute indices of replaced parameters. This will be used to adjust |
| 151 | // OpFunctionCall instructions and create OpCompositeConstruct instructions at |
| 152 | // every call site. |
| 153 | const auto indices_of_replaced_params = |
| 154 | ComputeIndicesOfReplacedParameters(ir_context); |
| 155 | |
| 156 | const auto caller_id_to_fresh_composite_id = |
| 157 | fuzzerutil::RepeatedUInt32PairToMap( |
| 158 | message_.caller_id_to_fresh_composite_id()); |
| 159 | |
| 160 | // Update all function calls. |
| 161 | for (auto* inst : fuzzerutil::GetCallers(ir_context, function->result_id())) { |
| 162 | // Create a list of operands for the OpCompositeConstruct instruction. |
| 163 | opt::Instruction::OperandList composite_components; |
| 164 | for (auto index : indices_of_replaced_params) { |
| 165 | // +1 since the first in operand to OpFunctionCall is the result id of |
| 166 | // the function. |
| 167 | composite_components.emplace_back( |
| 168 | std::move(inst->GetInOperand(index + 1))); |
| 169 | } |
| 170 | |
| 171 | // Remove arguments from the function call. We do it in a separate loop |
| 172 | // and in decreasing order to make sure we have removed correct operands. |
| 173 | for (auto index : std::set<uint32_t, std::greater<uint32_t>>( |
| 174 | indices_of_replaced_params.begin(), |
| 175 | indices_of_replaced_params.end())) { |
| 176 | // +1 since the first in operand to OpFunctionCall is the result id of |
| 177 | // the function. |
| 178 | inst->RemoveInOperand(index + 1); |
| 179 | } |
| 180 | |
| 181 | // Insert OpCompositeConstruct before the function call. |
| 182 | auto fresh_composite_id = |
| 183 | caller_id_to_fresh_composite_id.at(inst->result_id()); |
| 184 | inst->InsertBefore(MakeUnique<opt::Instruction>( |
| 185 | ir_context, spv::Op::OpCompositeConstruct, struct_type_id, |
| 186 | fresh_composite_id, std::move(composite_components))); |
| 187 | |
| 188 | // Add a new operand to the OpFunctionCall instruction. |
nothing calls this directly
no test coverage detected