transformation_invert_comparison_operator.cpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. // Copyright (c) 2020 Vasyl Teliman
  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_invert_comparison_operator.h"
  15. #include <utility>
  16. #include "source/fuzz/fuzzer_util.h"
  17. namespace spvtools {
  18. namespace fuzz {
  19. TransformationInvertComparisonOperator::TransformationInvertComparisonOperator(
  20. protobufs::TransformationInvertComparisonOperator message)
  21. : message_(std::move(message)) {}
  22. TransformationInvertComparisonOperator::TransformationInvertComparisonOperator(
  23. uint32_t operator_id, uint32_t fresh_id) {
  24. message_.set_operator_id(operator_id);
  25. message_.set_fresh_id(fresh_id);
  26. }
  27. bool TransformationInvertComparisonOperator::IsApplicable(
  28. opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
  29. // |message_.operator_id| must be valid and inversion must be supported for
  30. // it.
  31. auto* inst = ir_context->get_def_use_mgr()->GetDef(message_.operator_id());
  32. if (!inst || !IsInversionSupported(inst->opcode())) {
  33. return false;
  34. }
  35. // Check that we can insert negation instruction.
  36. auto* block = ir_context->get_instr_block(inst);
  37. assert(block && "Instruction must have a basic block");
  38. auto iter = fuzzerutil::GetIteratorForInstruction(block, inst);
  39. ++iter;
  40. assert(iter != block->end() && "Instruction can't be the last in the block");
  41. assert(fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpLogicalNot, iter) &&
  42. "Can't insert negation after comparison operator");
  43. // |message_.fresh_id| must be fresh.
  44. return fuzzerutil::IsFreshId(ir_context, message_.fresh_id());
  45. }
  46. void TransformationInvertComparisonOperator::Apply(
  47. opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
  48. auto* inst = ir_context->get_def_use_mgr()->GetDef(message_.operator_id());
  49. assert(inst && "Result id of an operator is invalid");
  50. // Insert negation after |inst|.
  51. auto iter = fuzzerutil::GetIteratorForInstruction(
  52. ir_context->get_instr_block(inst), inst);
  53. ++iter;
  54. iter.InsertBefore(MakeUnique<opt::Instruction>(
  55. ir_context, SpvOpLogicalNot, inst->type_id(), inst->result_id(),
  56. opt::Instruction::OperandList{
  57. {SPV_OPERAND_TYPE_ID, {message_.fresh_id()}}}));
  58. // Change the result id of the original operator to |fresh_id|.
  59. inst->SetResultId(message_.fresh_id());
  60. // Invert the operator.
  61. inst->SetOpcode(InvertOpcode(inst->opcode()));
  62. fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
  63. ir_context->InvalidateAnalysesExceptFor(
  64. opt::IRContext::Analysis::kAnalysisNone);
  65. }
  66. bool TransformationInvertComparisonOperator::IsInversionSupported(
  67. SpvOp opcode) {
  68. switch (opcode) {
  69. case SpvOpSGreaterThan:
  70. case SpvOpSGreaterThanEqual:
  71. case SpvOpSLessThan:
  72. case SpvOpSLessThanEqual:
  73. case SpvOpUGreaterThan:
  74. case SpvOpUGreaterThanEqual:
  75. case SpvOpULessThan:
  76. case SpvOpULessThanEqual:
  77. case SpvOpIEqual:
  78. case SpvOpINotEqual:
  79. return true;
  80. default:
  81. return false;
  82. }
  83. }
  84. SpvOp TransformationInvertComparisonOperator::InvertOpcode(SpvOp opcode) {
  85. assert(IsInversionSupported(opcode) && "Inversion must be supported");
  86. switch (opcode) {
  87. case SpvOpSGreaterThan:
  88. return SpvOpSLessThanEqual;
  89. case SpvOpSGreaterThanEqual:
  90. return SpvOpSLessThan;
  91. case SpvOpSLessThan:
  92. return SpvOpSGreaterThanEqual;
  93. case SpvOpSLessThanEqual:
  94. return SpvOpSGreaterThan;
  95. case SpvOpUGreaterThan:
  96. return SpvOpULessThanEqual;
  97. case SpvOpUGreaterThanEqual:
  98. return SpvOpULessThan;
  99. case SpvOpULessThan:
  100. return SpvOpUGreaterThanEqual;
  101. case SpvOpULessThanEqual:
  102. return SpvOpUGreaterThan;
  103. case SpvOpIEqual:
  104. return SpvOpINotEqual;
  105. case SpvOpINotEqual:
  106. return SpvOpIEqual;
  107. default:
  108. // The program will fail in the debug mode because of the assertion
  109. // at the beginning of the function.
  110. return SpvOpNop;
  111. }
  112. }
  113. protobufs::Transformation TransformationInvertComparisonOperator::ToMessage()
  114. const {
  115. protobufs::Transformation result;
  116. *result.mutable_invert_comparison_operator() = message_;
  117. return result;
  118. }
  119. } // namespace fuzz
  120. } // namespace spvtools