transformation_wrap_vector_synonym.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. // Copyright (c) 2021 Shiyu Liu
  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. #include "source/fuzz/transformation_wrap_vector_synonym.h"
  15. #include "source/fuzz/data_descriptor.h"
  16. #include "source/fuzz/fuzzer_util.h"
  17. #include "source/opt/instruction.h"
  18. namespace spvtools {
  19. namespace fuzz {
  20. TransformationWrapVectorSynonym::TransformationWrapVectorSynonym(
  21. protobufs::TransformationWrapVectorSynonym message)
  22. : message_(std::move(message)) {}
  23. TransformationWrapVectorSynonym::TransformationWrapVectorSynonym(
  24. uint32_t instruction_id, uint32_t vector_operand1, uint32_t vector_operand2,
  25. uint32_t fresh_id, uint32_t pos) {
  26. message_.set_instruction_id(instruction_id);
  27. message_.set_vector_operand1(vector_operand1);
  28. message_.set_vector_operand2(vector_operand2);
  29. message_.set_fresh_id(fresh_id);
  30. message_.set_scalar_position(pos);
  31. }
  32. bool TransformationWrapVectorSynonym::IsApplicable(
  33. opt::IRContext* ir_context,
  34. const TransformationContext& transformation_context) const {
  35. // |fresh_id| must be fresh.
  36. if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) {
  37. return false;
  38. }
  39. const opt::Instruction* instruction =
  40. ir_context->get_def_use_mgr()->GetDef(message_.instruction_id());
  41. // |instruction_id| must refer to an existing instruction.
  42. if (instruction == nullptr) {
  43. return false;
  44. }
  45. if (!IsInstructionSupported(ir_context, *instruction)) {
  46. return false;
  47. }
  48. // It must be possible to make a synonym of the result id of the scalar
  49. // operation
  50. if (!fuzzerutil::CanMakeSynonymOf(ir_context, transformation_context,
  51. *instruction)) {
  52. return false;
  53. }
  54. // |vector_operand1| and |vector_operand2| must exist.
  55. auto vec1 = ir_context->get_def_use_mgr()->GetDef(message_.vector_operand1());
  56. auto vec2 = ir_context->get_def_use_mgr()->GetDef(message_.vector_operand2());
  57. if (vec1 == nullptr || vec2 == nullptr) {
  58. return false;
  59. }
  60. // The 2 vectors must have compatible vector types.
  61. auto vec1_type_id = vec1->type_id();
  62. auto vec2_type_id = vec2->type_id();
  63. for (auto operand_index : {0, 1}) {
  64. if (!fuzzerutil::TypesAreCompatible(ir_context, instruction->opcode(),
  65. operand_index, vec1_type_id,
  66. vec2_type_id)) {
  67. return false;
  68. }
  69. }
  70. auto vec1_type = ir_context->get_def_use_mgr()->GetDef(vec1_type_id);
  71. if (vec1_type->opcode() != spv::Op::OpTypeVector) {
  72. return false;
  73. }
  74. // A suitable vector for the result type of the new vector instruction must
  75. // exist in the module. This is a vector of the right length, whose element
  76. // type matches the result type of the scalar instruction.
  77. uint32_t vector_size = vec1_type->GetSingleWordInOperand(1);
  78. if (!fuzzerutil::MaybeGetVectorType(ir_context, instruction->type_id(),
  79. vector_size)) {
  80. return false;
  81. }
  82. // |scalar_position| needs to be a non-negative integer less than the vector
  83. // length.
  84. // OpTypeVector instruction has the component count at index 2.
  85. if (message_.scalar_position() >= ir_context->get_def_use_mgr()
  86. ->GetDef(vec1_type_id)
  87. ->GetSingleWordInOperand(1)) {
  88. return false;
  89. }
  90. if (!transformation_context.GetFactManager()->IsSynonymous(
  91. MakeDataDescriptor(message_.vector_operand1(),
  92. {message_.scalar_position()}),
  93. MakeDataDescriptor(instruction->GetSingleWordInOperand(0), {}))) {
  94. return false;
  95. }
  96. if (!transformation_context.GetFactManager()->IsSynonymous(
  97. MakeDataDescriptor(message_.vector_operand2(),
  98. {message_.scalar_position()}),
  99. MakeDataDescriptor(instruction->GetSingleWordInOperand(1), {}))) {
  100. return false;
  101. }
  102. return true;
  103. }
  104. void TransformationWrapVectorSynonym::Apply(
  105. opt::IRContext* ir_context,
  106. TransformationContext* transformation_context) const {
  107. // Create an instruction descriptor for the original instruction.
  108. auto instruction =
  109. ir_context->get_def_use_mgr()->GetDef(message_.instruction_id());
  110. auto destination_block = ir_context->get_instr_block(instruction);
  111. // Populate input operand list with two vectors for vector operation.
  112. opt::Instruction::OperandList in_operands;
  113. in_operands.push_back({SPV_OPERAND_TYPE_ID, {message_.vector_operand1()}});
  114. in_operands.push_back({SPV_OPERAND_TYPE_ID, {message_.vector_operand2()}});
  115. // Make a new arithmetic instruction: %fresh_id = OpXX %type_id %result_id1
  116. // %result_id2.
  117. auto vector_operand_type = ir_context->get_def_use_mgr()->GetDef(
  118. fuzzerutil::GetTypeId(ir_context, message_.vector_operand1()));
  119. uint32_t vector_size = vector_operand_type->GetSingleWordInOperand(1);
  120. auto vec_type_id = fuzzerutil::MaybeGetVectorType(
  121. ir_context, instruction->type_id(), vector_size);
  122. auto new_instruction = MakeUnique<opt::Instruction>(
  123. ir_context, instruction->opcode(), vec_type_id, message_.fresh_id(),
  124. std::move(in_operands));
  125. auto new_instruction_ptr = new_instruction.get();
  126. instruction->InsertBefore(std::move(new_instruction));
  127. ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction_ptr);
  128. ir_context->set_instr_block(new_instruction_ptr, destination_block);
  129. // Add |fresh_id| to id bound.
  130. fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
  131. // Add synonyms between |fresh_id| and |instruction_id|.
  132. transformation_context->GetFactManager()->AddFactDataSynonym(
  133. MakeDataDescriptor(message_.fresh_id(), {message_.scalar_position()}),
  134. MakeDataDescriptor(message_.instruction_id(), {}));
  135. }
  136. protobufs::Transformation TransformationWrapVectorSynonym::ToMessage() const {
  137. protobufs::Transformation result;
  138. *result.mutable_wrap_vector_synonym() = message_;
  139. return result;
  140. }
  141. std::unordered_set<uint32_t> TransformationWrapVectorSynonym::GetFreshIds()
  142. const {
  143. return std::unordered_set<uint32_t>{message_.fresh_id()};
  144. }
  145. bool TransformationWrapVectorSynonym::IsInstructionSupported(
  146. opt::IRContext* ir_context, const opt::Instruction& instruction) {
  147. if (!instruction.result_id() || !instruction.type_id()) {
  148. return false;
  149. }
  150. auto type_instruction =
  151. ir_context->get_def_use_mgr()->GetDef(instruction.type_id());
  152. if ((type_instruction->opcode() != spv::Op::OpTypeInt &&
  153. type_instruction->opcode() != spv::Op::OpTypeFloat)) {
  154. return false;
  155. }
  156. switch (instruction.opcode()) {
  157. case spv::Op::OpIAdd:
  158. case spv::Op::OpISub:
  159. case spv::Op::OpIMul:
  160. case spv::Op::OpFAdd:
  161. case spv::Op::OpFSub:
  162. case spv::Op::OpFMul:
  163. return true;
  164. default:
  165. return false;
  166. }
  167. }
  168. } // namespace fuzz
  169. } // namespace spvtools