aboutsummaryrefslogtreecommitdiff
path: root/source/fuzz/transformation_replace_id_with_synonym.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/fuzz/transformation_replace_id_with_synonym.cpp')
-rw-r--r--source/fuzz/transformation_replace_id_with_synonym.cpp155
1 files changed, 155 insertions, 0 deletions
diff --git a/source/fuzz/transformation_replace_id_with_synonym.cpp b/source/fuzz/transformation_replace_id_with_synonym.cpp
new file mode 100644
index 00000000..a8874808
--- /dev/null
+++ b/source/fuzz/transformation_replace_id_with_synonym.cpp
@@ -0,0 +1,155 @@
+// 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"
+
+namespace spvtools {
+namespace fuzz {
+
+TransformationReplaceIdWithSynonym::TransformationReplaceIdWithSynonym(
+ const spvtools::fuzz::protobufs::TransformationReplaceIdWithSynonym&
+ message)
+ : message_(message) {}
+
+TransformationReplaceIdWithSynonym::TransformationReplaceIdWithSynonym(
+ protobufs::IdUseDescriptor id_use_descriptor,
+ protobufs::DataDescriptor data_descriptor,
+ uint32_t fresh_id_for_temporary) {
+ assert(fresh_id_for_temporary == 0 && data_descriptor.index().size() == 0 &&
+ "At present we do not support making an id that is synonymous with an "
+ "index into a composite.");
+ *message_.mutable_id_use_descriptor() = std::move(id_use_descriptor);
+ *message_.mutable_data_descriptor() = std::move(data_descriptor);
+ message_.set_fresh_id_for_temporary(fresh_id_for_temporary);
+}
+
+bool TransformationReplaceIdWithSynonym::IsApplicable(
+ spvtools::opt::IRContext* context,
+ const spvtools::fuzz::FactManager& fact_manager) const {
+ auto id_of_interest = message_.id_use_descriptor().id_of_interest();
+
+ // Does the fact manager know about the synonym?
+ if (fact_manager.GetIdsForWhichSynonymsAreKnown().count(id_of_interest) ==
+ 0) {
+ return false;
+ }
+
+ auto available_synonyms = fact_manager.GetSynonymsForId(id_of_interest);
+ if (std::find_if(available_synonyms.begin(), available_synonyms.end(),
+ [this](protobufs::DataDescriptor dd) -> bool {
+ return DataDescriptorEquals()(&dd,
+ &message_.data_descriptor());
+ }) == available_synonyms.end()) {
+ return false;
+ }
+
+ auto use_instruction =
+ transformation::FindInstruction(message_.id_use_descriptor(), context);
+ if (!use_instruction) {
+ return false;
+ }
+
+ if (!ReplacingUseWithSynonymIsOk(
+ context, use_instruction,
+ message_.id_use_descriptor().in_operand_index(),
+ message_.data_descriptor())) {
+ return false;
+ }
+
+ assert(message_.fresh_id_for_temporary() == 0);
+ assert(message_.data_descriptor().index().empty());
+
+ return true;
+}
+
+void TransformationReplaceIdWithSynonym::Apply(
+ spvtools::opt::IRContext* context,
+ spvtools::fuzz::FactManager* /*unused*/) const {
+ assert(message_.data_descriptor().index().empty());
+ auto instruction_to_change =
+ transformation::FindInstruction(message_.id_use_descriptor(), context);
+ instruction_to_change->SetInOperand(
+ message_.id_use_descriptor().in_operand_index(),
+ {message_.data_descriptor().object()});
+ context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone);
+}
+
+protobufs::Transformation TransformationReplaceIdWithSynonym::ToMessage()
+ const {
+ protobufs::Transformation result;
+ *result.mutable_replace_id_with_synonym() = message_;
+ return result;
+}
+
+bool TransformationReplaceIdWithSynonym::ReplacingUseWithSynonymIsOk(
+ opt::IRContext* context, opt::Instruction* use_instruction,
+ uint32_t use_in_operand_index, const protobufs::DataDescriptor& synonym) {
+ auto defining_instruction =
+ context->get_def_use_mgr()->GetDef(synonym.object());
+
+ if (use_instruction == defining_instruction) {
+ // If we have an instruction:
+ // %a = OpCopyObject %t %b
+ // then we know %a and %b are synonymous, but we do *not* want to turn
+ // this into:
+ // %a = OpCopyObject %t %a
+ // We require this special case because an instruction dominates itself.
+ return false;
+ }
+
+ if (use_instruction->opcode() == SpvOpAccessChain &&
+ use_in_operand_index > 0) {
+ // This is an access chain index. If the object being accessed has
+ // pointer-to-struct type then we cannot replace the use with a synonym, as
+ // the use needs to be an OpConstant.
+ auto object_being_accessed = context->get_def_use_mgr()->GetDef(
+ use_instruction->GetSingleWordInOperand(0));
+ auto pointer_type =
+ context->get_type_mgr()->GetType(object_being_accessed->type_id());
+ assert(pointer_type->AsPointer());
+ if (pointer_type->AsPointer()->pointee_type()->AsStruct()) {
+ return false;
+ }
+ }
+
+ // We now need to check that replacing the use with the synonym will respect
+ // dominance rules - i.e. the synonym needs to dominate the use.
+ auto dominator_analysis = context->GetDominatorAnalysis(
+ context->get_instr_block(use_instruction)->GetParent());
+ if (use_instruction->opcode() == SpvOpPhi) {
+ // In the case where the use is an operand to OpPhi, it is actually the
+ // *parent* block associated with the operand that must be dominated by the
+ // synonym.
+ auto parent_block =
+ use_instruction->GetSingleWordInOperand(use_in_operand_index + 1);
+ if (!dominator_analysis->Dominates(
+ context->get_instr_block(defining_instruction)->id(),
+ parent_block)) {
+ return false;
+ }
+ } else if (!dominator_analysis->Dominates(defining_instruction,
+ use_instruction)) {
+ return false;
+ }
+ return true;
+}
+
+} // namespace fuzz
+} // namespace spvtools