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_set_function_control.h"
16
17 namespace spvtools {
18 namespace fuzz {
19
TransformationSetFunctionControl(const spvtools::fuzz::protobufs::TransformationSetFunctionControl & message)20 TransformationSetFunctionControl::TransformationSetFunctionControl(
21 const spvtools::fuzz::protobufs::TransformationSetFunctionControl& message)
22 : message_(message) {}
23
TransformationSetFunctionControl(uint32_t function_id,uint32_t function_control)24 TransformationSetFunctionControl::TransformationSetFunctionControl(
25 uint32_t function_id, uint32_t function_control) {
26 message_.set_function_id(function_id);
27 message_.set_function_control(function_control);
28 }
29
IsApplicable(opt::IRContext * ir_context,const TransformationContext &) const30 bool TransformationSetFunctionControl::IsApplicable(
31 opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
32 opt::Instruction* function_def_instruction =
33 FindFunctionDefInstruction(ir_context);
34 if (!function_def_instruction) {
35 // The given function id does not correspond to any function.
36 return false;
37 }
38 uint32_t existing_function_control_mask =
39 function_def_instruction->GetSingleWordInOperand(0);
40
41 // Check (via an assertion) that function control mask doesn't have any bad
42 // bits set.
43 uint32_t acceptable_function_control_bits =
44 SpvFunctionControlInlineMask | SpvFunctionControlDontInlineMask |
45 SpvFunctionControlPureMask | SpvFunctionControlConstMask;
46 // The following is to keep release-mode compilers happy as this variable is
47 // only used in an assertion.
48 (void)(acceptable_function_control_bits);
49 assert(!(message_.function_control() & ~acceptable_function_control_bits) &&
50 "Nonsensical loop control bits were found.");
51
52 // Check (via an assertion) that function control mask does not have both
53 // Inline and DontInline bits set.
54 assert(!((message_.function_control() & SpvFunctionControlInlineMask) &&
55 (message_.function_control() & SpvFunctionControlDontInlineMask)) &&
56 "It is not OK to set both the 'Inline' and 'DontInline' bits of a "
57 "function control mask");
58
59 // Check that Const and Pure are only present if they were present on the
60 // original function
61 for (auto mask_bit :
62 {SpvFunctionControlPureMask, SpvFunctionControlConstMask}) {
63 if ((message_.function_control() & mask_bit) &&
64 !(existing_function_control_mask & mask_bit)) {
65 return false;
66 }
67 }
68
69 return true;
70 }
71
Apply(opt::IRContext * ir_context,TransformationContext *) const72 void TransformationSetFunctionControl::Apply(
73 opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
74 opt::Instruction* function_def_instruction =
75 FindFunctionDefInstruction(ir_context);
76 function_def_instruction->SetInOperand(0, {message_.function_control()});
77 }
78
ToMessage() const79 protobufs::Transformation TransformationSetFunctionControl::ToMessage() const {
80 protobufs::Transformation result;
81 *result.mutable_set_function_control() = message_;
82 return result;
83 }
84
FindFunctionDefInstruction(opt::IRContext * ir_context) const85 opt::Instruction* TransformationSetFunctionControl ::FindFunctionDefInstruction(
86 opt::IRContext* ir_context) const {
87 // Look through all functions for a function whose defining instruction's
88 // result id matches |message_.function_id|, returning the defining
89 // instruction if found.
90 for (auto& function : *ir_context->module()) {
91 if (function.DefInst().result_id() == message_.function_id()) {
92 return &function.DefInst();
93 }
94 }
95 // A nullptr result indicates that no match was found.
96 return nullptr;
97 }
98
99 } // namespace fuzz
100 } // namespace spvtools
101