transformation_composite_insert.cpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. // Copyright (c) 2020 Google LLC
  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 "transformation_composite_insert.h"
  15. #include "source/fuzz/fuzzer_pass_add_composite_inserts.h"
  16. #include "source/fuzz/fuzzer_util.h"
  17. #include "source/fuzz/instruction_descriptor.h"
  18. namespace spvtools {
  19. namespace fuzz {
  20. TransformationCompositeInsert::TransformationCompositeInsert(
  21. const spvtools::fuzz::protobufs::TransformationCompositeInsert& message)
  22. : message_(message) {}
  23. TransformationCompositeInsert::TransformationCompositeInsert(
  24. const protobufs::InstructionDescriptor& instruction_to_insert_before,
  25. uint32_t fresh_id, uint32_t composite_id, uint32_t object_id,
  26. const std::vector<uint32_t>& index) {
  27. *message_.mutable_instruction_to_insert_before() =
  28. instruction_to_insert_before;
  29. message_.set_fresh_id(fresh_id);
  30. message_.set_composite_id(composite_id);
  31. message_.set_object_id(object_id);
  32. for (auto an_index : index) {
  33. message_.add_index(an_index);
  34. }
  35. }
  36. bool TransformationCompositeInsert::IsApplicable(
  37. opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
  38. // |message_.fresh_id| must be fresh.
  39. if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) {
  40. return false;
  41. }
  42. // |message_.composite_id| must refer to an existing composite value.
  43. auto composite =
  44. ir_context->get_def_use_mgr()->GetDef(message_.composite_id());
  45. if (!IsCompositeInstructionSupported(ir_context, composite)) {
  46. return false;
  47. }
  48. // The indices in |message_.index| must be suitable for indexing into
  49. // |composite->type_id()|.
  50. auto component_to_be_replaced_type_id = fuzzerutil::WalkCompositeTypeIndices(
  51. ir_context, composite->type_id(), message_.index());
  52. if (component_to_be_replaced_type_id == 0) {
  53. return false;
  54. }
  55. // The instruction having the id of |message_.object_id| must be defined.
  56. auto object_instruction =
  57. ir_context->get_def_use_mgr()->GetDef(message_.object_id());
  58. if (object_instruction == nullptr || object_instruction->type_id() == 0) {
  59. return false;
  60. }
  61. // We ignore pointers for now.
  62. auto object_instruction_type =
  63. ir_context->get_type_mgr()->GetType(object_instruction->type_id());
  64. if (object_instruction_type->AsPointer() != nullptr) {
  65. return false;
  66. }
  67. // The type id of the object having |message_.object_id| and the type id of
  68. // the component of the composite at index |message_.index| must be the same.
  69. if (component_to_be_replaced_type_id != object_instruction->type_id()) {
  70. return false;
  71. }
  72. // |message_.instruction_to_insert_before| must be a defined instruction.
  73. auto instruction_to_insert_before =
  74. FindInstruction(message_.instruction_to_insert_before(), ir_context);
  75. if (instruction_to_insert_before == nullptr) {
  76. return false;
  77. }
  78. // |message_.composite_id| and |message_.object_id| must be available before
  79. // the |message_.instruction_to_insert_before|.
  80. if (!fuzzerutil::IdIsAvailableBeforeInstruction(
  81. ir_context, instruction_to_insert_before, message_.composite_id())) {
  82. return false;
  83. }
  84. if (!fuzzerutil::IdIsAvailableBeforeInstruction(
  85. ir_context, instruction_to_insert_before, message_.object_id())) {
  86. return false;
  87. }
  88. // It must be possible to insert an OpCompositeInsert before this
  89. // instruction.
  90. return fuzzerutil::CanInsertOpcodeBeforeInstruction(
  91. SpvOpCompositeInsert, instruction_to_insert_before);
  92. }
  93. void TransformationCompositeInsert::Apply(
  94. opt::IRContext* ir_context,
  95. TransformationContext* transformation_context) const {
  96. // |message_.struct_fresh_id| must be fresh.
  97. assert(fuzzerutil::IsFreshId(ir_context, message_.fresh_id()) &&
  98. "|message_.fresh_id| must be fresh");
  99. std::vector<uint32_t> index =
  100. fuzzerutil::RepeatedFieldToVector(message_.index());
  101. opt::Instruction::OperandList in_operands;
  102. in_operands.push_back({SPV_OPERAND_TYPE_ID, {message_.object_id()}});
  103. in_operands.push_back({SPV_OPERAND_TYPE_ID, {message_.composite_id()}});
  104. for (auto i : index) {
  105. in_operands.push_back({SPV_OPERAND_TYPE_LITERAL_INTEGER, {i}});
  106. }
  107. auto composite_type_id =
  108. fuzzerutil::GetTypeId(ir_context, message_.composite_id());
  109. FindInstruction(message_.instruction_to_insert_before(), ir_context)
  110. ->InsertBefore(MakeUnique<opt::Instruction>(
  111. ir_context, SpvOpCompositeInsert, composite_type_id,
  112. message_.fresh_id(), std::move(in_operands)));
  113. fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
  114. // We have modified the module so most analyzes are now invalid.
  115. ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
  116. // Add data synonym facts that arise from the insertion.
  117. AddDataSynonymFacts(ir_context, transformation_context);
  118. }
  119. protobufs::Transformation TransformationCompositeInsert::ToMessage() const {
  120. protobufs::Transformation result;
  121. *result.mutable_composite_insert() = message_;
  122. return result;
  123. }
  124. bool TransformationCompositeInsert::IsCompositeInstructionSupported(
  125. opt::IRContext* ir_context, opt::Instruction* instruction) {
  126. if (instruction == nullptr) {
  127. return false;
  128. }
  129. if (instruction->result_id() == 0 || instruction->type_id() == 0) {
  130. return false;
  131. }
  132. auto composite_type =
  133. ir_context->get_type_mgr()->GetType(instruction->type_id());
  134. if (!fuzzerutil::IsCompositeType(composite_type)) {
  135. return false;
  136. }
  137. // Empty composites are not supported.
  138. auto instruction_type_inst =
  139. ir_context->get_def_use_mgr()->GetDef(instruction->type_id());
  140. if (fuzzerutil::GetBoundForCompositeIndex(*instruction_type_inst,
  141. ir_context) == 0) {
  142. return false;
  143. }
  144. return true;
  145. }
  146. std::unordered_set<uint32_t> TransformationCompositeInsert::GetFreshIds()
  147. const {
  148. return {message_.fresh_id()};
  149. }
  150. void TransformationCompositeInsert::AddDataSynonymFacts(
  151. opt::IRContext* ir_context,
  152. TransformationContext* transformation_context) const {
  153. // If the result id arising from the insertion is irrelevant then do not add
  154. // any data synonym facts. (The result id can be irrelevant if the insertion
  155. // occurs in a dead block.)
  156. if (transformation_context->GetFactManager()->IdIsIrrelevant(
  157. message_.fresh_id())) {
  158. return;
  159. }
  160. // So long as the |message_.composite_id| is suitable for participating in
  161. // synonyms, every every element of the insertion result except for at the
  162. // index being inserted into is synonymous with the corresponding element of
  163. // |message_.composite_id|. In that case, for every index that is a prefix of
  164. // |index|, the components different from the one that contains the inserted
  165. // object are synonymous with corresponding elements in the original
  166. // composite.
  167. uint32_t current_node_type_id =
  168. fuzzerutil::GetTypeId(ir_context, message_.composite_id());
  169. std::vector<uint32_t> current_index;
  170. std::vector<uint32_t> index =
  171. fuzzerutil::RepeatedFieldToVector(message_.index());
  172. for (uint32_t current_level : index) {
  173. auto current_node_type_inst =
  174. ir_context->get_def_use_mgr()->GetDef(current_node_type_id);
  175. uint32_t index_to_skip = current_level;
  176. uint32_t num_of_components = fuzzerutil::GetBoundForCompositeIndex(
  177. *current_node_type_inst, ir_context);
  178. // Update the current_node_type_id.
  179. current_node_type_id = fuzzerutil::WalkOneCompositeTypeIndex(
  180. ir_context, current_node_type_id, index_to_skip);
  181. for (uint32_t i = 0; i < num_of_components; i++) {
  182. if (i == index_to_skip) {
  183. continue;
  184. }
  185. current_index.push_back(i);
  186. if (fuzzerutil::CanMakeSynonymOf(
  187. ir_context, *transformation_context,
  188. ir_context->get_def_use_mgr()->GetDef(message_.composite_id()))) {
  189. transformation_context->GetFactManager()->AddFactDataSynonym(
  190. MakeDataDescriptor(message_.fresh_id(), current_index),
  191. MakeDataDescriptor(message_.composite_id(), current_index));
  192. }
  193. current_index.pop_back();
  194. }
  195. // Store the prefix of the |index|.
  196. current_index.push_back(current_level);
  197. }
  198. // If the object being inserted supports synonym creation then it is
  199. // synonymous with the result of the insert instruction at the given index.
  200. if (fuzzerutil::CanMakeSynonymOf(
  201. ir_context, *transformation_context,
  202. ir_context->get_def_use_mgr()->GetDef(message_.object_id()))) {
  203. transformation_context->GetFactManager()->AddFactDataSynonym(
  204. MakeDataDescriptor(message_.object_id(), {}),
  205. MakeDataDescriptor(message_.fresh_id(), index));
  206. }
  207. }
  208. } // namespace fuzz
  209. } // namespace spvtools