fuzzer_pass_wrap_vector_synonym.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  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/fuzzer_pass_wrap_vector_synonym.h"
  15. #include "source/fuzz/fuzzer_context.h"
  16. #include "source/fuzz/fuzzer_util.h"
  17. #include "source/fuzz/transformation_composite_construct.h"
  18. #include "source/fuzz/transformation_wrap_vector_synonym.h"
  19. namespace spvtools {
  20. namespace fuzz {
  21. FuzzerPassWrapVectorSynonym::FuzzerPassWrapVectorSynonym(
  22. opt::IRContext* ir_context, TransformationContext* transformation_context,
  23. FuzzerContext* fuzzer_context,
  24. protobufs::TransformationSequence* transformations,
  25. bool ignore_inapplicable_transformations)
  26. : FuzzerPass(ir_context, transformation_context, fuzzer_context,
  27. transformations, ignore_inapplicable_transformations) {}
  28. void FuzzerPassWrapVectorSynonym::Apply() {
  29. ForEachInstructionWithInstructionDescriptor(
  30. [this](opt::Function* /*unused*/, opt::BasicBlock* /*unused*/,
  31. opt::BasicBlock::iterator instruction_iterator,
  32. const protobufs::InstructionDescriptor& instruction_descriptor)
  33. -> void {
  34. // Randomly decide whether to wrap it to a vector operation.
  35. if (!GetFuzzerContext()->ChoosePercentage(
  36. GetFuzzerContext()->GetChanceOfWrappingVectorSynonym())) {
  37. return;
  38. }
  39. // The transformation is not applicable if the instruction has missing
  40. // result id, type id, or is not supported type.
  41. if (!TransformationWrapVectorSynonym::IsInstructionSupported(
  42. GetIRContext(), *instruction_iterator)) {
  43. return;
  44. }
  45. // It must be valid to insert an OpCompositeConstruct instruction
  46. // before |instruction_iterator|.
  47. if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(
  48. spv::Op::OpCompositeConstruct, instruction_iterator)) {
  49. return;
  50. }
  51. // Get the scalar operands from the original instruction.
  52. opt::Instruction* operand1 = GetIRContext()->get_def_use_mgr()->GetDef(
  53. instruction_iterator->GetSingleWordInOperand(0));
  54. opt::Instruction* operand2 = GetIRContext()->get_def_use_mgr()->GetDef(
  55. instruction_iterator->GetSingleWordInOperand(1));
  56. // We need to be able to make a synonym of the scalar operation's result
  57. // id, as well as the operand ids (for example, they cannot be
  58. // irrelevant).
  59. if (!fuzzerutil::CanMakeSynonymOf(GetIRContext(),
  60. *GetTransformationContext(),
  61. *instruction_iterator)) {
  62. return;
  63. }
  64. if (!fuzzerutil::CanMakeSynonymOf(
  65. GetIRContext(), *GetTransformationContext(), *operand1)) {
  66. return;
  67. }
  68. if (!fuzzerutil::CanMakeSynonymOf(
  69. GetIRContext(), *GetTransformationContext(), *operand2)) {
  70. return;
  71. }
  72. // Get a random vector size from 2 to 4.
  73. uint32_t vector_size = GetFuzzerContext()->GetWidthOfWrappingVector();
  74. // Randomly choose a position that target ids should be placed at.
  75. // The position is in range [0, n - 1], where n is the size of the
  76. // vector.
  77. uint32_t position =
  78. GetFuzzerContext()->GetRandomIndexForWrappingVector(vector_size);
  79. // Stores the ids of scalar constants.
  80. std::vector<uint32_t> vec1_components;
  81. std::vector<uint32_t> vec2_components;
  82. // Populate components based on vector type and size.
  83. for (uint32_t i = 0; i < vector_size; ++i) {
  84. if (i == position) {
  85. vec1_components.emplace_back(operand1->result_id());
  86. vec2_components.emplace_back(operand2->result_id());
  87. } else {
  88. vec1_components.emplace_back(
  89. FindOrCreateZeroConstant(operand1->type_id(), true));
  90. vec2_components.emplace_back(
  91. FindOrCreateZeroConstant(operand2->type_id(), true));
  92. }
  93. }
  94. // Add two OpCompositeConstruct to the module with result id returned.
  95. // The added vectors may have different types, for instance if the
  96. // scalar instruction operates on integers with differing sign.
  97. // Add the first OpCompositeConstruct that wraps the id of the first
  98. // operand.
  99. uint32_t result_id1 = GetFuzzerContext()->GetFreshId();
  100. ApplyTransformation(TransformationCompositeConstruct(
  101. FindOrCreateVectorType(operand1->type_id(), vector_size),
  102. vec1_components, instruction_descriptor, result_id1));
  103. // Add the second OpCompositeConstruct that wraps the id of the second
  104. // operand.
  105. uint32_t result_id2 = GetFuzzerContext()->GetFreshId();
  106. ApplyTransformation(TransformationCompositeConstruct(
  107. FindOrCreateVectorType(operand2->type_id(), vector_size),
  108. vec2_components, instruction_descriptor, result_id2));
  109. // The result of the vector instruction that
  110. // TransformationWrapVectorSynonym will create should be a vector of the
  111. // right size, with the scalar instruction's result type as its element
  112. // type. This can be distinct from the types of the operands, if the
  113. // scalar instruction adds two signed integers and stores the result in
  114. // an unsigned id, for example. A transformation is applied to add the
  115. // right type to the module.
  116. FindOrCreateVectorType(instruction_iterator->type_id(), vector_size);
  117. // Apply transformation to do vector operation and add synonym between
  118. // the result vector id and the id of the original instruction.
  119. ApplyTransformation(TransformationWrapVectorSynonym(
  120. instruction_iterator->result_id(), result_id1, result_id2,
  121. GetFuzzerContext()->GetFreshId(), position));
  122. });
  123. }
  124. } // namespace fuzz
  125. } // namespace spvtools