transformation_vector_shuffle.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. // Copyright (c) 2019 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 "source/fuzz/transformation_vector_shuffle.h"
  15. #include "source/fuzz/fuzzer_util.h"
  16. #include "source/fuzz/instruction_descriptor.h"
  17. namespace spvtools {
  18. namespace fuzz {
  19. TransformationVectorShuffle::TransformationVectorShuffle(
  20. protobufs::TransformationVectorShuffle message)
  21. : message_(std::move(message)) {}
  22. TransformationVectorShuffle::TransformationVectorShuffle(
  23. const protobufs::InstructionDescriptor& instruction_to_insert_before,
  24. uint32_t fresh_id, uint32_t vector1, uint32_t vector2,
  25. const std::vector<uint32_t>& component) {
  26. *message_.mutable_instruction_to_insert_before() =
  27. instruction_to_insert_before;
  28. message_.set_fresh_id(fresh_id);
  29. message_.set_vector1(vector1);
  30. message_.set_vector2(vector2);
  31. for (auto a_component : component) {
  32. message_.add_component(a_component);
  33. }
  34. }
  35. bool TransformationVectorShuffle::IsApplicable(
  36. opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
  37. // The fresh id must not already be in use.
  38. if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) {
  39. return false;
  40. }
  41. // The instruction before which the shuffle will be inserted must exist.
  42. auto instruction_to_insert_before =
  43. FindInstruction(message_.instruction_to_insert_before(), ir_context);
  44. if (!instruction_to_insert_before) {
  45. return false;
  46. }
  47. // The first vector must be an instruction with a type id
  48. auto vector1_instruction =
  49. ir_context->get_def_use_mgr()->GetDef(message_.vector1());
  50. if (!vector1_instruction || !vector1_instruction->type_id()) {
  51. return false;
  52. }
  53. // The second vector must be an instruction with a type id
  54. auto vector2_instruction =
  55. ir_context->get_def_use_mgr()->GetDef(message_.vector2());
  56. if (!vector2_instruction || !vector2_instruction->type_id()) {
  57. return false;
  58. }
  59. auto vector1_type =
  60. ir_context->get_type_mgr()->GetType(vector1_instruction->type_id());
  61. // The first vector instruction's type must actually be a vector type.
  62. if (!vector1_type->AsVector()) {
  63. return false;
  64. }
  65. auto vector2_type =
  66. ir_context->get_type_mgr()->GetType(vector2_instruction->type_id());
  67. // The second vector instruction's type must actually be a vector type.
  68. if (!vector2_type->AsVector()) {
  69. return false;
  70. }
  71. // The element types of the vectors must be the same.
  72. if (vector1_type->AsVector()->element_type() !=
  73. vector2_type->AsVector()->element_type()) {
  74. return false;
  75. }
  76. uint32_t combined_size = vector1_type->AsVector()->element_count() +
  77. vector2_type->AsVector()->element_count();
  78. for (auto a_compoment : message_.component()) {
  79. // 0xFFFFFFFF is used to represent an undefined component. Unless
  80. // undefined, a component must be less than the combined size of the
  81. // vectors.
  82. if (a_compoment != 0xFFFFFFFF && a_compoment >= combined_size) {
  83. return false;
  84. }
  85. }
  86. // The module must already declare an appropriate type in which to store the
  87. // result of the shuffle.
  88. if (!GetResultTypeId(ir_context, *vector1_type->AsVector()->element_type())) {
  89. return false;
  90. }
  91. // Each of the vectors used in the shuffle must be available at the insertion
  92. // point.
  93. for (auto used_instruction : {vector1_instruction, vector2_instruction}) {
  94. if (auto block = ir_context->get_instr_block(used_instruction)) {
  95. if (!ir_context->GetDominatorAnalysis(block->GetParent())
  96. ->Dominates(used_instruction, instruction_to_insert_before)) {
  97. return false;
  98. }
  99. }
  100. }
  101. // It must be legitimate to insert an OpVectorShuffle before the identified
  102. // instruction.
  103. return fuzzerutil::CanInsertOpcodeBeforeInstruction(
  104. spv::Op::OpVectorShuffle, instruction_to_insert_before);
  105. }
  106. void TransformationVectorShuffle::Apply(
  107. opt::IRContext* ir_context,
  108. TransformationContext* transformation_context) const {
  109. // Make input operands for a shuffle instruction - these comprise the two
  110. // vectors being shuffled, followed by the integer literal components.
  111. opt::Instruction::OperandList shuffle_operands = {
  112. {SPV_OPERAND_TYPE_ID, {message_.vector1()}},
  113. {SPV_OPERAND_TYPE_ID, {message_.vector2()}}};
  114. for (auto a_component : message_.component()) {
  115. shuffle_operands.push_back(
  116. {SPV_OPERAND_TYPE_LITERAL_INTEGER, {a_component}});
  117. }
  118. uint32_t result_type_id = GetResultTypeId(
  119. ir_context,
  120. *GetVectorType(ir_context, message_.vector1())->element_type());
  121. // Add a shuffle instruction right before the instruction identified by
  122. // |message_.instruction_to_insert_before|.
  123. auto insert_before =
  124. FindInstruction(message_.instruction_to_insert_before(), ir_context);
  125. opt::Instruction* new_instruction =
  126. insert_before->InsertBefore(MakeUnique<opt::Instruction>(
  127. ir_context, spv::Op::OpVectorShuffle, result_type_id,
  128. message_.fresh_id(), shuffle_operands));
  129. fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
  130. // Inform the def-use manager about the new instruction and record its basic
  131. // block.
  132. ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction);
  133. ir_context->set_instr_block(new_instruction,
  134. ir_context->get_instr_block(insert_before));
  135. AddDataSynonymFacts(ir_context, transformation_context);
  136. }
  137. protobufs::Transformation TransformationVectorShuffle::ToMessage() const {
  138. protobufs::Transformation result;
  139. *result.mutable_vector_shuffle() = message_;
  140. return result;
  141. }
  142. uint32_t TransformationVectorShuffle::GetResultTypeId(
  143. opt::IRContext* ir_context, const opt::analysis::Type& element_type) const {
  144. opt::analysis::Vector result_type(
  145. &element_type, static_cast<uint32_t>(message_.component_size()));
  146. return ir_context->get_type_mgr()->GetId(&result_type);
  147. }
  148. opt::analysis::Vector* TransformationVectorShuffle::GetVectorType(
  149. opt::IRContext* ir_context, uint32_t id_of_vector) {
  150. return ir_context->get_type_mgr()
  151. ->GetType(ir_context->get_def_use_mgr()->GetDef(id_of_vector)->type_id())
  152. ->AsVector();
  153. }
  154. std::unordered_set<uint32_t> TransformationVectorShuffle::GetFreshIds() const {
  155. return {message_.fresh_id()};
  156. }
  157. void TransformationVectorShuffle::AddDataSynonymFacts(
  158. opt::IRContext* ir_context,
  159. TransformationContext* transformation_context) const {
  160. // If the new instruction is irrelevant (because it is in a dead block), it
  161. // cannot participate in any DataSynonym fact.
  162. if (transformation_context->GetFactManager()->IdIsIrrelevant(
  163. message_.fresh_id())) {
  164. return;
  165. }
  166. // Add synonym facts relating the defined elements of the shuffle result to
  167. // the vector components that they come from.
  168. for (uint32_t component_index = 0;
  169. component_index < static_cast<uint32_t>(message_.component_size());
  170. component_index++) {
  171. uint32_t component = message_.component(component_index);
  172. if (component == 0xFFFFFFFF) {
  173. // This component is undefined, we do not introduce a synonym.
  174. continue;
  175. }
  176. // This describes the element of the result vector associated with
  177. // |component_index|.
  178. protobufs::DataDescriptor descriptor_for_result_component =
  179. MakeDataDescriptor(message_.fresh_id(), {component_index});
  180. protobufs::DataDescriptor descriptor_for_source_component;
  181. // Get a data descriptor for the component of the input vector to which
  182. // |component| refers.
  183. if (component <
  184. GetVectorType(ir_context, message_.vector1())->element_count()) {
  185. // Check that the first vector can participate in data synonym facts.
  186. if (!fuzzerutil::CanMakeSynonymOf(
  187. ir_context, *transformation_context,
  188. *ir_context->get_def_use_mgr()->GetDef(message_.vector1()))) {
  189. continue;
  190. }
  191. descriptor_for_source_component =
  192. MakeDataDescriptor(message_.vector1(), {component});
  193. } else {
  194. // Check that the second vector can participate in data synonym facts.
  195. if (!fuzzerutil::CanMakeSynonymOf(
  196. ir_context, *transformation_context,
  197. *ir_context->get_def_use_mgr()->GetDef(message_.vector2()))) {
  198. continue;
  199. }
  200. auto index_into_vector_2 =
  201. component -
  202. GetVectorType(ir_context, message_.vector1())->element_count();
  203. assert(
  204. index_into_vector_2 <
  205. GetVectorType(ir_context, message_.vector2())->element_count() &&
  206. "Vector shuffle index is out of bounds.");
  207. descriptor_for_source_component =
  208. MakeDataDescriptor(message_.vector2(), {index_into_vector_2});
  209. }
  210. // Add a fact relating this input vector component with the associated
  211. // result component.
  212. transformation_context->GetFactManager()->AddFactDataSynonym(
  213. descriptor_for_result_component, descriptor_for_source_component);
  214. }
  215. }
  216. } // namespace fuzz
  217. } // namespace spvtools