transformation_copy_object.cpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  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_copy_object.h"
  15. #include "source/fuzz/data_descriptor.h"
  16. #include "source/fuzz/fuzzer_util.h"
  17. #include "source/fuzz/instruction_descriptor.h"
  18. #include "source/opt/instruction.h"
  19. #include "source/util/make_unique.h"
  20. namespace spvtools {
  21. namespace fuzz {
  22. TransformationCopyObject::TransformationCopyObject(
  23. const protobufs::TransformationCopyObject& message)
  24. : message_(message) {}
  25. TransformationCopyObject::TransformationCopyObject(
  26. uint32_t object,
  27. const protobufs::InstructionDescriptor& instruction_to_insert_before,
  28. uint32_t fresh_id) {
  29. message_.set_object(object);
  30. *message_.mutable_instruction_to_insert_before() =
  31. instruction_to_insert_before;
  32. message_.set_fresh_id(fresh_id);
  33. }
  34. bool TransformationCopyObject::IsApplicable(
  35. opt::IRContext* context, const FactManager& /*fact_manager*/) const {
  36. if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) {
  37. // We require the id for the object copy to be unused.
  38. return false;
  39. }
  40. // The id of the object to be copied must exist
  41. auto object_inst = context->get_def_use_mgr()->GetDef(message_.object());
  42. if (!object_inst) {
  43. return false;
  44. }
  45. if (!fuzzerutil::CanMakeSynonymOf(context, object_inst)) {
  46. return false;
  47. }
  48. auto insert_before =
  49. FindInstruction(message_.instruction_to_insert_before(), context);
  50. if (!insert_before) {
  51. // The instruction before which the copy should be inserted was not found.
  52. return false;
  53. }
  54. if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpCopyObject,
  55. insert_before)) {
  56. return false;
  57. }
  58. // |message_object| must be available at the point where we want to add the
  59. // copy. It is available if it is at global scope (in which case it has no
  60. // block), or if it dominates the point of insertion but is different from the
  61. // point of insertion.
  62. //
  63. // The reason why the object needs to be different from the insertion point is
  64. // that the copy will be added *before* this point, and we do not want to
  65. // insert it before the object's defining instruction.
  66. return !context->get_instr_block(object_inst) ||
  67. (object_inst != &*insert_before &&
  68. context
  69. ->GetDominatorAnalysis(
  70. context->get_instr_block(insert_before)->GetParent())
  71. ->Dominates(object_inst, &*insert_before));
  72. }
  73. void TransformationCopyObject::Apply(opt::IRContext* context,
  74. FactManager* fact_manager) const {
  75. auto object_inst = context->get_def_use_mgr()->GetDef(message_.object());
  76. assert(object_inst && "The object to be copied must exist.");
  77. auto insert_before_inst =
  78. FindInstruction(message_.instruction_to_insert_before(), context);
  79. auto destination_block = context->get_instr_block(insert_before_inst);
  80. assert(destination_block && "The base instruction must be in a block.");
  81. auto insert_before = fuzzerutil::GetIteratorForInstruction(
  82. destination_block, insert_before_inst);
  83. assert(insert_before != destination_block->end() &&
  84. "There must be an instruction before which the copy can be inserted.");
  85. opt::Instruction::OperandList operands = {
  86. {SPV_OPERAND_TYPE_ID, {message_.object()}}};
  87. insert_before->InsertBefore(MakeUnique<opt::Instruction>(
  88. context, SpvOp::SpvOpCopyObject, object_inst->type_id(),
  89. message_.fresh_id(), operands));
  90. fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id());
  91. context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone);
  92. fact_manager->AddFactDataSynonym(MakeDataDescriptor(message_.object(), {}),
  93. MakeDataDescriptor(message_.fresh_id(), {}),
  94. context);
  95. }
  96. protobufs::Transformation TransformationCopyObject::ToMessage() const {
  97. protobufs::Transformation result;
  98. *result.mutable_copy_object() = message_;
  99. return result;
  100. }
  101. } // namespace fuzz
  102. } // namespace spvtools