• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
15 #include "source/fuzz/transformation_add_constant_composite.h"
16 
17 #include <vector>
18 
19 #include "source/fuzz/fuzzer_util.h"
20 
21 namespace spvtools {
22 namespace fuzz {
23 
TransformationAddConstantComposite(spvtools::fuzz::protobufs::TransformationAddConstantComposite message)24 TransformationAddConstantComposite::TransformationAddConstantComposite(
25     spvtools::fuzz::protobufs::TransformationAddConstantComposite message)
26     : message_(std::move(message)) {}
27 
TransformationAddConstantComposite(uint32_t fresh_id,uint32_t type_id,const std::vector<uint32_t> & constituent_ids,bool is_irrelevant)28 TransformationAddConstantComposite::TransformationAddConstantComposite(
29     uint32_t fresh_id, uint32_t type_id,
30     const std::vector<uint32_t>& constituent_ids, bool is_irrelevant) {
31   message_.set_fresh_id(fresh_id);
32   message_.set_type_id(type_id);
33   message_.set_is_irrelevant(is_irrelevant);
34   for (auto constituent_id : constituent_ids) {
35     message_.add_constituent_id(constituent_id);
36   }
37 }
38 
IsApplicable(opt::IRContext * ir_context,const TransformationContext &) const39 bool TransformationAddConstantComposite::IsApplicable(
40     opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
41   // Check that the given id is fresh.
42   if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) {
43     return false;
44   }
45   // Check that the composite type id is an instruction id.
46   auto composite_type_instruction =
47       ir_context->get_def_use_mgr()->GetDef(message_.type_id());
48   if (!composite_type_instruction) {
49     return false;
50   }
51   // Gather up the operands for the composite constant, in the process checking
52   // whether the given type really defines a composite and - in the case of a
53   // struct - whether its decorations are OK.
54   std::vector<uint32_t> constituent_type_ids;
55   switch (composite_type_instruction->opcode()) {
56     case SpvOpTypeArray:
57       for (uint32_t index = 0;
58            index <
59            fuzzerutil::GetArraySize(*composite_type_instruction, ir_context);
60            index++) {
61         constituent_type_ids.push_back(
62             composite_type_instruction->GetSingleWordInOperand(0));
63       }
64       break;
65     case SpvOpTypeMatrix:
66     case SpvOpTypeVector:
67       for (uint32_t index = 0;
68            index < composite_type_instruction->GetSingleWordInOperand(1);
69            index++) {
70         constituent_type_ids.push_back(
71             composite_type_instruction->GetSingleWordInOperand(0));
72       }
73       break;
74     case SpvOpTypeStruct:
75       // We do not create constants of structs decorated with Block nor
76       // BufferBlock.  The SPIR-V spec does not explicitly disallow this, but it
77       // seems like a strange thing to do, so we disallow it to avoid triggering
78       // low priorty edge case issues related to it.
79       if (fuzzerutil::HasBlockOrBufferBlockDecoration(
80               ir_context, composite_type_instruction->result_id())) {
81         return false;
82       }
83       composite_type_instruction->ForEachInOperand(
84           [&constituent_type_ids](const uint32_t* member_type_id) {
85             constituent_type_ids.push_back(*member_type_id);
86           });
87       break;
88     default:
89       // Not a composite type.
90       return false;
91   }
92 
93   // Check that the number of provided operands matches the number of
94   // constituents required by the type.
95   if (constituent_type_ids.size() !=
96       static_cast<uint32_t>(message_.constituent_id().size())) {
97     return false;
98   }
99 
100   // Check that every provided operand refers to an instruction of the
101   // corresponding constituent type.
102   for (uint32_t index = 0; index < constituent_type_ids.size(); index++) {
103     auto constituent_instruction =
104         ir_context->get_def_use_mgr()->GetDef(message_.constituent_id(index));
105     if (!constituent_instruction) {
106       return false;
107     }
108     if (constituent_instruction->type_id() != constituent_type_ids.at(index)) {
109       return false;
110     }
111   }
112   return true;
113 }
114 
Apply(opt::IRContext * ir_context,TransformationContext * transformation_context) const115 void TransformationAddConstantComposite::Apply(
116     opt::IRContext* ir_context,
117     TransformationContext* transformation_context) const {
118   opt::Instruction::OperandList in_operands;
119   for (auto constituent_id : message_.constituent_id()) {
120     in_operands.push_back({SPV_OPERAND_TYPE_ID, {constituent_id}});
121   }
122   auto new_instruction = MakeUnique<opt::Instruction>(
123       ir_context, SpvOpConstantComposite, message_.type_id(),
124       message_.fresh_id(), in_operands);
125   auto new_instruction_ptr = new_instruction.get();
126   ir_context->module()->AddGlobalValue(std::move(new_instruction));
127   fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
128 
129   // Inform the def-use manager of the new instruction. Invalidate the constant
130   // manager as we have added a new constant.
131   ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction_ptr);
132   ir_context->InvalidateAnalyses(opt::IRContext::kAnalysisConstants);
133 
134   if (message_.is_irrelevant()) {
135     transformation_context->GetFactManager()->AddFactIdIsIrrelevant(
136         message_.fresh_id());
137   }
138 }
139 
ToMessage() const140 protobufs::Transformation TransformationAddConstantComposite::ToMessage()
141     const {
142   protobufs::Transformation result;
143   *result.mutable_add_constant_composite() = message_;
144   return result;
145 }
146 
GetFreshIds() const147 std::unordered_set<uint32_t> TransformationAddConstantComposite::GetFreshIds()
148     const {
149   return {message_.fresh_id()};
150 }
151 
152 }  // namespace fuzz
153 }  // namespace spvtools
154