transformation_replace_irrelevant_id.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  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 "source/fuzz/transformation_replace_irrelevant_id.h"
  15. #include "source/fuzz/fuzzer_util.h"
  16. #include "source/fuzz/id_use_descriptor.h"
  17. namespace spvtools {
  18. namespace fuzz {
  19. TransformationReplaceIrrelevantId::TransformationReplaceIrrelevantId(
  20. protobufs::TransformationReplaceIrrelevantId message)
  21. : message_(std::move(message)) {}
  22. TransformationReplaceIrrelevantId::TransformationReplaceIrrelevantId(
  23. const protobufs::IdUseDescriptor& id_use_descriptor,
  24. uint32_t replacement_id) {
  25. *message_.mutable_id_use_descriptor() = id_use_descriptor;
  26. message_.set_replacement_id(replacement_id);
  27. }
  28. bool TransformationReplaceIrrelevantId::IsApplicable(
  29. opt::IRContext* ir_context,
  30. const TransformationContext& transformation_context) const {
  31. auto id_of_interest = message_.id_use_descriptor().id_of_interest();
  32. // The id must be irrelevant.
  33. if (!transformation_context.GetFactManager()->IdIsIrrelevant(
  34. id_of_interest)) {
  35. return false;
  36. }
  37. // Find the instruction containing the id use, which must exist.
  38. auto use_instruction =
  39. FindInstructionContainingUse(message_.id_use_descriptor(), ir_context);
  40. if (!use_instruction) {
  41. return false;
  42. }
  43. // Check that the replacement id exists and retrieve its definition.
  44. auto replacement_id_def =
  45. ir_context->get_def_use_mgr()->GetDef(message_.replacement_id());
  46. if (!replacement_id_def) {
  47. return false;
  48. }
  49. // The type of the id of interest and of the replacement id must be the same.
  50. uint32_t type_id_of_interest =
  51. ir_context->get_def_use_mgr()->GetDef(id_of_interest)->type_id();
  52. uint32_t type_replacement_id = replacement_id_def->type_id();
  53. if (type_id_of_interest != type_replacement_id) {
  54. return false;
  55. }
  56. // The replacement id must not be the result of an OpFunction instruction.
  57. if (replacement_id_def->opcode() == spv::Op::OpFunction) {
  58. return false;
  59. }
  60. // Consistency check: an irrelevant id cannot be a pointer.
  61. assert(
  62. !ir_context->get_type_mgr()->GetType(type_id_of_interest)->AsPointer() &&
  63. "An irrelevant id cannot be a pointer");
  64. uint32_t use_in_operand_index =
  65. message_.id_use_descriptor().in_operand_index();
  66. // The id use must be replaceable with any other id of the same type.
  67. if (!fuzzerutil::IdUseCanBeReplaced(ir_context, transformation_context,
  68. use_instruction, use_in_operand_index)) {
  69. return false;
  70. }
  71. if (AttemptsToReplaceVariableInitializerWithNonConstant(
  72. *use_instruction, *replacement_id_def)) {
  73. return false;
  74. }
  75. // The id must be available to use at the use point.
  76. return fuzzerutil::IdIsAvailableAtUse(
  77. ir_context, use_instruction,
  78. message_.id_use_descriptor().in_operand_index(),
  79. message_.replacement_id());
  80. }
  81. void TransformationReplaceIrrelevantId::Apply(
  82. opt::IRContext* ir_context,
  83. TransformationContext* /* transformation_context */) const {
  84. // Find the instruction.
  85. auto instruction_to_change =
  86. FindInstructionContainingUse(message_.id_use_descriptor(), ir_context);
  87. // Replace the instruction.
  88. instruction_to_change->SetInOperand(
  89. message_.id_use_descriptor().in_operand_index(),
  90. {message_.replacement_id()});
  91. ir_context->get_def_use_mgr()->EraseUseRecordsOfOperandIds(
  92. instruction_to_change);
  93. ir_context->get_def_use_mgr()->AnalyzeInstUse(instruction_to_change);
  94. // No analyses need to be invalidated, since the transformation is local to a
  95. // block, and the def-use analysis has been updated.
  96. }
  97. protobufs::Transformation TransformationReplaceIrrelevantId::ToMessage() const {
  98. protobufs::Transformation result;
  99. *result.mutable_replace_irrelevant_id() = message_;
  100. return result;
  101. }
  102. std::unordered_set<uint32_t> TransformationReplaceIrrelevantId::GetFreshIds()
  103. const {
  104. return std::unordered_set<uint32_t>();
  105. }
  106. bool TransformationReplaceIrrelevantId::
  107. AttemptsToReplaceVariableInitializerWithNonConstant(
  108. const opt::Instruction& use_instruction,
  109. const opt::Instruction& replacement_for_use) {
  110. return use_instruction.opcode() == spv::Op::OpVariable &&
  111. !spvOpcodeIsConstant(replacement_for_use.opcode());
  112. }
  113. } // namespace fuzz
  114. } // namespace spvtools