1 // Copyright (c) 2019 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_global_variable.h"
17 #include "source/fuzz/fuzzer_util.h"
22 TransformationAddGlobalVariable::TransformationAddGlobalVariable(
23 spvtools::fuzz::protobufs::TransformationAddGlobalVariable message
)
24 : message_(std::move(message
)) {}
26 TransformationAddGlobalVariable::TransformationAddGlobalVariable(
27 uint32_t fresh_id
, uint32_t type_id
, spv::StorageClass storage_class
,
28 uint32_t initializer_id
, bool value_is_irrelevant
) {
29 message_
.set_fresh_id(fresh_id
);
30 message_
.set_type_id(type_id
);
31 message_
.set_storage_class(uint32_t(storage_class
));
32 message_
.set_initializer_id(initializer_id
);
33 message_
.set_value_is_irrelevant(value_is_irrelevant
);
36 bool TransformationAddGlobalVariable::IsApplicable(
37 opt::IRContext
* ir_context
, const TransformationContext
& /*unused*/) const {
38 // The result id must be fresh.
39 if (!fuzzerutil::IsFreshId(ir_context
, message_
.fresh_id())) {
43 // The storage class must be Private or Workgroup.
44 auto storage_class
= static_cast<spv::StorageClass
>(message_
.storage_class());
45 switch (storage_class
) {
46 case spv::StorageClass::Private
:
47 case spv::StorageClass::Workgroup
:
50 assert(false && "Unsupported storage class.");
53 // The type id must correspond to a type.
54 auto type
= ir_context
->get_type_mgr()->GetType(message_
.type_id());
58 // That type must be a pointer type ...
59 auto pointer_type
= type
->AsPointer();
63 // ... with the right storage class.
64 if (pointer_type
->storage_class() != storage_class
) {
67 if (message_
.initializer_id()) {
68 // An initializer is not allowed if the storage class is Workgroup.
69 if (storage_class
== spv::StorageClass::Workgroup
) {
71 "By construction this transformation should not have an "
72 "initializer when Workgroup storage class is used.");
75 // The initializer id must be the id of a constant. Check this with the
77 auto constant_id
= ir_context
->get_constant_mgr()->GetConstantsFromIds(
78 {message_
.initializer_id()});
79 if (constant_id
.empty()) {
82 assert(constant_id
.size() == 1 &&
83 "We asked for the constant associated with a single id; we should "
84 "get a single constant.");
85 // The type of the constant must match the pointee type of the pointer.
86 if (pointer_type
->pointee_type() != constant_id
[0]->type()) {
93 void TransformationAddGlobalVariable::Apply(
94 opt::IRContext
* ir_context
,
95 TransformationContext
* transformation_context
) const {
96 opt::Instruction
* new_instruction
= fuzzerutil::AddGlobalVariable(
97 ir_context
, message_
.fresh_id(), message_
.type_id(),
98 static_cast<spv::StorageClass
>(message_
.storage_class()),
99 message_
.initializer_id());
101 // Inform the def-use manager about the new instruction.
102 ir_context
->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction
);
104 if (message_
.value_is_irrelevant()) {
105 transformation_context
->GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
106 message_
.fresh_id());
110 protobufs::Transformation
TransformationAddGlobalVariable::ToMessage() const {
111 protobufs::Transformation result
;
112 *result
.mutable_add_global_variable() = message_
;
116 std::unordered_set
<uint32_t> TransformationAddGlobalVariable::GetFreshIds()
118 return {message_
.fresh_id()};
122 } // namespace spvtools