File: transformation_replace_id_with_synonym.cpp

package info (click to toggle)
spirv-tools 2020.6-2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 21,636 kB
  • sloc: cpp: 366,576; javascript: 5,849; python: 2,551; ansic: 387; sh: 327; ruby: 88; makefile: 19; lisp: 9
file content (168 lines) | stat: -rw-r--r-- 5,970 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
// Copyright (c) 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "source/fuzz/transformation_replace_id_with_synonym.h"

#include <algorithm>

#include "source/fuzz/data_descriptor.h"
#include "source/fuzz/fuzzer_util.h"
#include "source/fuzz/id_use_descriptor.h"
#include "source/opt/types.h"
#include "source/util/make_unique.h"

namespace spvtools {
namespace fuzz {

TransformationReplaceIdWithSynonym::TransformationReplaceIdWithSynonym(
    const spvtools::fuzz::protobufs::TransformationReplaceIdWithSynonym&
        message)
    : message_(message) {}

TransformationReplaceIdWithSynonym::TransformationReplaceIdWithSynonym(
    protobufs::IdUseDescriptor id_use_descriptor, uint32_t synonymous_id) {
  *message_.mutable_id_use_descriptor() = std::move(id_use_descriptor);
  message_.set_synonymous_id(synonymous_id);
}

bool TransformationReplaceIdWithSynonym::IsApplicable(
    opt::IRContext* ir_context,
    const TransformationContext& transformation_context) const {
  auto id_of_interest = message_.id_use_descriptor().id_of_interest();

  // Does the fact manager know about the synonym?
  auto data_descriptor_for_synonymous_id =
      MakeDataDescriptor(message_.synonymous_id(), {});
  if (!transformation_context.GetFactManager()->IsSynonymous(
          MakeDataDescriptor(id_of_interest, {}),
          data_descriptor_for_synonymous_id)) {
    return false;
  }

  // Does the id use descriptor in the transformation identify an instruction?
  auto use_instruction =
      FindInstructionContainingUse(message_.id_use_descriptor(), ir_context);
  if (!use_instruction) {
    return false;
  }

  uint32_t type_id_of_interest =
      ir_context->get_def_use_mgr()->GetDef(id_of_interest)->type_id();
  uint32_t type_id_synonym = ir_context->get_def_use_mgr()
                                 ->GetDef(message_.synonymous_id())
                                 ->type_id();

  // If the id of interest and the synonym are scalar or vector integer
  // constants with different signedness, their use can only be swapped if the
  // instruction is agnostic to the signedness of the operand.
  if (!TypesAreCompatible(ir_context, use_instruction->opcode(),
                          message_.id_use_descriptor().in_operand_index(),
                          type_id_of_interest, type_id_synonym)) {
    return false;
  }

  // Is the use suitable for being replaced in principle?
  if (!fuzzerutil::IdUseCanBeReplaced(
          ir_context, transformation_context, use_instruction,
          message_.id_use_descriptor().in_operand_index())) {
    return false;
  }

  // The transformation is applicable if the synonymous id is available at the
  // use point.
  return fuzzerutil::IdIsAvailableAtUse(
      ir_context, use_instruction,
      message_.id_use_descriptor().in_operand_index(),
      message_.synonymous_id());
}

void TransformationReplaceIdWithSynonym::Apply(
    spvtools::opt::IRContext* ir_context,
    TransformationContext* /*unused*/) const {
  auto instruction_to_change =
      FindInstructionContainingUse(message_.id_use_descriptor(), ir_context);
  instruction_to_change->SetInOperand(
      message_.id_use_descriptor().in_operand_index(),
      {message_.synonymous_id()});
  ir_context->InvalidateAnalysesExceptFor(
      opt::IRContext::Analysis::kAnalysisNone);
}

protobufs::Transformation TransformationReplaceIdWithSynonym::ToMessage()
    const {
  protobufs::Transformation result;
  *result.mutable_replace_id_with_synonym() = message_;
  return result;
}

// TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3582): Add all
//  opcodes that are agnostic to signedness of operands to function.
//  This is not exhaustive yet.
bool TransformationReplaceIdWithSynonym::IsAgnosticToSignednessOfOperand(
    SpvOp opcode, uint32_t use_in_operand_index) {
  switch (opcode) {
    case SpvOpSNegate:
    case SpvOpNot:
    case SpvOpIAdd:
    case SpvOpISub:
    case SpvOpIMul:
    case SpvOpSDiv:
    case SpvOpSRem:
    case SpvOpSMod:
    case SpvOpShiftRightLogical:
    case SpvOpShiftRightArithmetic:
    case SpvOpShiftLeftLogical:
    case SpvOpBitwiseOr:
    case SpvOpBitwiseXor:
    case SpvOpBitwiseAnd:
    case SpvOpIEqual:
    case SpvOpINotEqual:
    case SpvOpULessThan:
    case SpvOpSLessThan:
    case SpvOpUGreaterThan:
    case SpvOpSGreaterThan:
    case SpvOpULessThanEqual:
    case SpvOpSLessThanEqual:
    case SpvOpUGreaterThanEqual:
    case SpvOpSGreaterThanEqual:
      return true;
    case SpvOpAccessChain:
      // The signedness of indices does not matter.
      return use_in_operand_index > 0;
    default:
      // Conservatively assume that the id cannot be swapped in other
      // instructions.
      return false;
  }
}

bool TransformationReplaceIdWithSynonym::TypesAreCompatible(
    opt::IRContext* ir_context, SpvOp opcode, uint32_t use_in_operand_index,
    uint32_t type_id_1, uint32_t type_id_2) {
  assert(ir_context->get_type_mgr()->GetType(type_id_1) &&
         ir_context->get_type_mgr()->GetType(type_id_2) &&
         "Type ids are invalid");

  return type_id_1 == type_id_2 ||
         (IsAgnosticToSignednessOfOperand(opcode, use_in_operand_index) &&
          fuzzerutil::TypesAreEqualUpToSign(ir_context, type_id_1, type_id_2));
}

std::unordered_set<uint32_t> TransformationReplaceIdWithSynonym::GetFreshIds()
    const {
  return std::unordered_set<uint32_t>();
}

}  // namespace fuzz
}  // namespace spvtools