1 // Copyright (c) 2020 Google LLC
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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.
15 #include "source/fuzz/transformation_add_early_terminator_wrapper.h"
17 #include "source/fuzz/fuzzer_util.h"
18 #include "source/util/make_unique.h"
23 TransformationAddEarlyTerminatorWrapper::
24 TransformationAddEarlyTerminatorWrapper(
25 protobufs::TransformationAddEarlyTerminatorWrapper message
)
26 : message_(std::move(message
)) {}
28 TransformationAddEarlyTerminatorWrapper::
29 TransformationAddEarlyTerminatorWrapper(uint32_t function_fresh_id
,
30 uint32_t label_fresh_id
,
32 message_
.set_function_fresh_id(function_fresh_id
);
33 message_
.set_label_fresh_id(label_fresh_id
);
34 message_
.set_opcode(uint32_t(opcode
));
37 bool TransformationAddEarlyTerminatorWrapper::IsApplicable(
38 opt::IRContext
* ir_context
, const TransformationContext
& /*unused*/) const {
39 assert((spv::Op(message_
.opcode()) == spv::Op::OpKill
||
40 spv::Op(message_
.opcode()) == spv::Op::OpUnreachable
||
41 spv::Op(message_
.opcode()) == spv::Op::OpTerminateInvocation
) &&
44 if (!fuzzerutil::IsFreshId(ir_context
, message_
.function_fresh_id())) {
47 if (!fuzzerutil::IsFreshId(ir_context
, message_
.label_fresh_id())) {
50 if (message_
.function_fresh_id() == message_
.label_fresh_id()) {
53 uint32_t void_type_id
= fuzzerutil::MaybeGetVoidType(ir_context
);
57 return fuzzerutil::FindFunctionType(ir_context
, {void_type_id
});
60 void TransformationAddEarlyTerminatorWrapper::Apply(
61 opt::IRContext
* ir_context
, TransformationContext
* /*unused*/) const {
62 fuzzerutil::UpdateModuleIdBound(ir_context
, message_
.function_fresh_id());
63 fuzzerutil::UpdateModuleIdBound(ir_context
, message_
.label_fresh_id());
65 // Create a basic block of the form:
66 // %label_fresh_id = OpLabel
67 // OpKill|Unreachable|TerminateInvocation
68 auto basic_block
= MakeUnique
<opt::BasicBlock
>(MakeUnique
<opt::Instruction
>(
69 ir_context
, spv::Op::OpLabel
, 0, message_
.label_fresh_id(),
70 opt::Instruction::OperandList()));
71 basic_block
->AddInstruction(MakeUnique
<opt::Instruction
>(
72 ir_context
, static_cast<spv::Op
>(message_
.opcode()), 0, 0,
73 opt::Instruction::OperandList()));
75 // Create a zero-argument void function.
76 auto void_type_id
= fuzzerutil::MaybeGetVoidType(ir_context
);
77 auto function
= MakeUnique
<opt::Function
>(MakeUnique
<opt::Instruction
>(
78 ir_context
, spv::Op::OpFunction
, void_type_id
,
79 message_
.function_fresh_id(),
80 opt::Instruction::OperandList(
81 {{SPV_OPERAND_TYPE_FUNCTION_CONTROL
,
82 {uint32_t(spv::FunctionControlMask::MaskNone
)}},
83 {SPV_OPERAND_TYPE_TYPE_ID
,
84 {fuzzerutil::FindFunctionType(ir_context
, {void_type_id
})}}})));
86 // Add the basic block to the function as the sole block, and add the function
88 function
->AddBasicBlock(std::move(basic_block
));
89 function
->SetFunctionEnd(
90 MakeUnique
<opt::Instruction
>(ir_context
, spv::Op::OpFunctionEnd
, 0, 0,
91 opt::Instruction::OperandList()));
92 ir_context
->module()->AddFunction(std::move(function
));
94 ir_context
->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone
);
97 std::unordered_set
<uint32_t>
98 TransformationAddEarlyTerminatorWrapper::GetFreshIds() const {
99 return std::unordered_set
<uint32_t>(
100 {message_
.function_fresh_id(), message_
.label_fresh_id()});
103 protobufs::Transformation
TransformationAddEarlyTerminatorWrapper::ToMessage()
105 protobufs::Transformation result
;
106 *result
.mutable_add_early_terminator_wrapper() = message_
;
111 } // namespace spvtools