mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-11-26 05:10:05 +00:00
spirv-fuzz: Transformation to extract from a composite object (#2991)
At present, TransformationReplaceIdWithSynonym both extracts elements from composite objects and replaces uses of ids with synonyms. This new TransformationCompositeExtract class will allow that transformation to be broken into smaller transformations.
This commit is contained in:
parent
ec12de9131
commit
fac166162f
@ -69,6 +69,7 @@ if(SPIRV_BUILD_FUZZER)
|
||||
transformation_add_type_int.h
|
||||
transformation_add_type_pointer.h
|
||||
transformation_composite_construct.h
|
||||
transformation_composite_extract.h
|
||||
transformation_copy_object.h
|
||||
transformation_move_block_down.h
|
||||
transformation_replace_boolean_constant_with_constant_binary.h
|
||||
@ -120,6 +121,7 @@ if(SPIRV_BUILD_FUZZER)
|
||||
transformation_add_type_int.cpp
|
||||
transformation_add_type_pointer.cpp
|
||||
transformation_composite_construct.cpp
|
||||
transformation_composite_extract.cpp
|
||||
transformation_copy_object.cpp
|
||||
transformation_move_block_down.cpp
|
||||
transformation_replace_boolean_constant_with_constant_binary.cpp
|
||||
|
@ -283,7 +283,7 @@ bool FactManager::ConstantUniformFacts::AddFact(
|
||||
auto composite_type =
|
||||
should_be_uniform_pointer_instruction->GetSingleWordInOperand(1);
|
||||
|
||||
auto final_element_type_id = fuzzerutil::WalkCompositeIndices(
|
||||
auto final_element_type_id = fuzzerutil::WalkCompositeTypeIndices(
|
||||
context, composite_type,
|
||||
fact.uniform_buffer_element_descriptor().index());
|
||||
if (!final_element_type_id) {
|
||||
|
@ -330,7 +330,7 @@ bool IsCompositeType(const opt::analysis::Type* type) {
|
||||
type->AsVector());
|
||||
}
|
||||
|
||||
uint32_t WalkCompositeIndices(
|
||||
uint32_t WalkCompositeTypeIndices(
|
||||
opt::IRContext* context, uint32_t base_object_type_id,
|
||||
const google::protobuf::RepeatedField<google::protobuf::uint32>& indices) {
|
||||
uint32_t sub_object_type_id = base_object_type_id;
|
||||
|
@ -98,7 +98,7 @@ bool IsCompositeType(const opt::analysis::Type* type);
|
||||
// |indices| is suitable for indexing into this type. Returns the id of the
|
||||
// type of the final sub-object reached via the indices if they are valid, and
|
||||
// 0 otherwise.
|
||||
uint32_t WalkCompositeIndices(
|
||||
uint32_t WalkCompositeTypeIndices(
|
||||
opt::IRContext* context, uint32_t base_object_type_id,
|
||||
const google::protobuf::RepeatedField<google::protobuf::uint32>& indices);
|
||||
|
||||
|
@ -192,6 +192,7 @@ message Transformation {
|
||||
TransformationSetFunctionControl set_function_control = 18;
|
||||
TransformationAddNoContractionDecoration add_no_contraction_decoration = 19;
|
||||
TransformationSetMemoryOperandsMask set_memory_operands_mask = 20;
|
||||
TransformationCompositeExtract composite_extract = 21;
|
||||
// Add additional option using the next available number.
|
||||
}
|
||||
}
|
||||
@ -345,6 +346,26 @@ message TransformationCompositeConstruct {
|
||||
|
||||
}
|
||||
|
||||
message TransformationCompositeExtract {
|
||||
|
||||
// A transformation that adds an instruction to extract an element from a
|
||||
// composite.
|
||||
|
||||
// A descriptor for an instruction in a block before which the new
|
||||
// OpCompositeExtract instruction should be inserted
|
||||
InstructionDescriptor instruction_to_insert_before = 1;
|
||||
|
||||
// Result id for the extract operation.
|
||||
uint32 fresh_id = 2;
|
||||
|
||||
// Id of the composite from which data is to be extracted.
|
||||
uint32 composite_id = 3;
|
||||
|
||||
// Indices that indicate which part of the composite should be extracted.
|
||||
repeated uint32 index = 4;
|
||||
|
||||
}
|
||||
|
||||
message TransformationCopyObject {
|
||||
|
||||
// A transformation that introduces an OpCopyObject instruction to make a
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "source/fuzz/transformation_add_type_int.h"
|
||||
#include "source/fuzz/transformation_add_type_pointer.h"
|
||||
#include "source/fuzz/transformation_composite_construct.h"
|
||||
#include "source/fuzz/transformation_composite_extract.h"
|
||||
#include "source/fuzz/transformation_copy_object.h"
|
||||
#include "source/fuzz/transformation_move_block_down.h"
|
||||
#include "source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h"
|
||||
@ -74,6 +75,9 @@ std::unique_ptr<Transformation> Transformation::FromMessage(
|
||||
case protobufs::Transformation::TransformationCase::kCompositeConstruct:
|
||||
return MakeUnique<TransformationCompositeConstruct>(
|
||||
message.composite_construct());
|
||||
case protobufs::Transformation::TransformationCase::kCompositeExtract:
|
||||
return MakeUnique<TransformationCompositeExtract>(
|
||||
message.composite_extract());
|
||||
case protobufs::Transformation::TransformationCase::kCopyObject:
|
||||
return MakeUnique<TransformationCopyObject>(message.copy_object());
|
||||
case protobufs::Transformation::TransformationCase::kMoveBlockDown:
|
||||
|
123
source/fuzz/transformation_composite_extract.cpp
Normal file
123
source/fuzz/transformation_composite_extract.cpp
Normal file
@ -0,0 +1,123 @@
|
||||
// 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_composite_extract.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "source/fuzz/data_descriptor.h"
|
||||
#include "source/fuzz/fuzzer_util.h"
|
||||
#include "source/fuzz/instruction_descriptor.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
TransformationCompositeExtract::TransformationCompositeExtract(
|
||||
const spvtools::fuzz::protobufs::TransformationCompositeExtract& message)
|
||||
: message_(message) {}
|
||||
|
||||
TransformationCompositeExtract::TransformationCompositeExtract(
|
||||
const protobufs::InstructionDescriptor& instruction_to_insert_before,
|
||||
uint32_t fresh_id, uint32_t composite_id, std::vector<uint32_t>&& index) {
|
||||
*message_.mutable_instruction_to_insert_before() =
|
||||
instruction_to_insert_before;
|
||||
message_.set_fresh_id(fresh_id);
|
||||
message_.set_composite_id(composite_id);
|
||||
for (auto an_index : index) {
|
||||
message_.add_index(an_index);
|
||||
}
|
||||
}
|
||||
|
||||
bool TransformationCompositeExtract::IsApplicable(
|
||||
opt::IRContext* context,
|
||||
const spvtools::fuzz::FactManager& /*unused*/) const {
|
||||
if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) {
|
||||
return false;
|
||||
}
|
||||
auto instruction_to_insert_before =
|
||||
FindInstruction(message_.instruction_to_insert_before(), context);
|
||||
if (!instruction_to_insert_before) {
|
||||
return false;
|
||||
}
|
||||
auto composite_instruction =
|
||||
context->get_def_use_mgr()->GetDef(message_.composite_id());
|
||||
if (!composite_instruction) {
|
||||
return false;
|
||||
}
|
||||
if (auto block = context->get_instr_block(composite_instruction)) {
|
||||
if (composite_instruction == instruction_to_insert_before ||
|
||||
!context->GetDominatorAnalysis(block->GetParent())
|
||||
->Dominates(composite_instruction, instruction_to_insert_before)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
assert(composite_instruction->type_id() &&
|
||||
"An instruction in a block cannot have a result id but no type id.");
|
||||
|
||||
auto composite_type =
|
||||
context->get_type_mgr()->GetType(composite_instruction->type_id());
|
||||
if (!composite_type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(
|
||||
SpvOpCompositeExtract, instruction_to_insert_before)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return fuzzerutil::WalkCompositeTypeIndices(
|
||||
context, composite_instruction->type_id(), message_.index()) != 0;
|
||||
}
|
||||
|
||||
void TransformationCompositeExtract::Apply(
|
||||
opt::IRContext* context, spvtools::fuzz::FactManager* fact_manager) const {
|
||||
opt::Instruction::OperandList extract_operands;
|
||||
extract_operands.push_back({SPV_OPERAND_TYPE_ID, {message_.composite_id()}});
|
||||
for (auto an_index : message_.index()) {
|
||||
extract_operands.push_back({SPV_OPERAND_TYPE_LITERAL_INTEGER, {an_index}});
|
||||
}
|
||||
auto composite_instruction =
|
||||
context->get_def_use_mgr()->GetDef(message_.composite_id());
|
||||
auto extracted_type = fuzzerutil::WalkCompositeTypeIndices(
|
||||
context, composite_instruction->type_id(), message_.index());
|
||||
|
||||
FindInstruction(message_.instruction_to_insert_before(), context)
|
||||
->InsertBefore(MakeUnique<opt::Instruction>(
|
||||
context, SpvOpCompositeExtract, extracted_type, message_.fresh_id(),
|
||||
extract_operands));
|
||||
|
||||
fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id());
|
||||
|
||||
// Add the fact that the id storing the extracted element is synonymous with
|
||||
// the index into the structure.
|
||||
std::vector<uint32_t> indices;
|
||||
for (auto an_index : message_.index()) {
|
||||
indices.push_back(an_index);
|
||||
}
|
||||
protobufs::DataDescriptor data_descriptor_for_extracted_element =
|
||||
MakeDataDescriptor(message_.composite_id(), std::move(indices), 1);
|
||||
protobufs::DataDescriptor data_descriptor_for_result_id =
|
||||
MakeDataDescriptor(message_.fresh_id(), {}, 1);
|
||||
fact_manager->AddFactDataSynonym(data_descriptor_for_extracted_element,
|
||||
data_descriptor_for_result_id);
|
||||
}
|
||||
|
||||
protobufs::Transformation TransformationCompositeExtract::ToMessage() const {
|
||||
protobufs::Transformation result;
|
||||
*result.mutable_composite_extract() = message_;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
63
source/fuzz/transformation_composite_extract.h
Normal file
63
source/fuzz/transformation_composite_extract.h
Normal file
@ -0,0 +1,63 @@
|
||||
// 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.
|
||||
|
||||
#ifndef SOURCE_FUZZ_TRANSFORMATION_COMPOSITE_EXTRACT_H_
|
||||
#define SOURCE_FUZZ_TRANSFORMATION_COMPOSITE_EXTRACT_H_
|
||||
|
||||
#include "source/fuzz/fact_manager.h"
|
||||
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
|
||||
#include "source/fuzz/transformation.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
class TransformationCompositeExtract : public Transformation {
|
||||
public:
|
||||
explicit TransformationCompositeExtract(
|
||||
const protobufs::TransformationCompositeExtract& message);
|
||||
|
||||
TransformationCompositeExtract(
|
||||
const protobufs::InstructionDescriptor& instruction_to_insert_before,
|
||||
uint32_t fresh_id, uint32_t composite_id, std::vector<uint32_t>&& index);
|
||||
|
||||
// - |message_.fresh_id| must be available
|
||||
// - |message_.instruction_to_insert_before| must identify an instruction
|
||||
// before which it is valid to place an OpCompositeExtract
|
||||
// - |message_.composite_id| must be the id of an instruction that defines
|
||||
// a composite object, and this id must be available at the instruction
|
||||
// identified by |message_.instruction_to_insert_before|
|
||||
// - |message_.index| must be a suitable set of indices for
|
||||
// |message_.composite_id|, i.e. it must be possible to follow this chain
|
||||
// of indices to reach a sub-object of |message_.composite_id|
|
||||
bool IsApplicable(opt::IRContext* context,
|
||||
const FactManager& fact_manager) const override;
|
||||
|
||||
// Adds an OpCompositeConstruct instruction before the instruction identified
|
||||
// by |message_.instruction_to_insert_before|, that extracts from
|
||||
// |message_.composite_id| via indices |message_.index| into
|
||||
// |message_.fresh_id|. Generates a data synonym fact relating
|
||||
// |message_.fresh_id| to the extracted element.
|
||||
void Apply(opt::IRContext* context, FactManager* fact_manager) const override;
|
||||
|
||||
protobufs::Transformation ToMessage() const override;
|
||||
|
||||
private:
|
||||
protobufs::TransformationCompositeExtract message_;
|
||||
};
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_FUZZ_TRANSFORMATION_COMPOSITE_EXTRACT_H_
|
@ -32,6 +32,7 @@ if (${SPIRV_BUILD_FUZZER})
|
||||
transformation_add_type_int_test.cpp
|
||||
transformation_add_type_pointer_test.cpp
|
||||
transformation_composite_construct_test.cpp
|
||||
transformation_composite_extract_test.cpp
|
||||
transformation_copy_object_test.cpp
|
||||
transformation_move_block_down_test.cpp
|
||||
transformation_replace_boolean_constant_with_constant_binary_test.cpp
|
||||
|
393
test/fuzz/transformation_composite_extract_test.cpp
Normal file
393
test/fuzz/transformation_composite_extract_test.cpp
Normal file
@ -0,0 +1,393 @@
|
||||
// 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_composite_extract.h"
|
||||
#include "source/fuzz/instruction_descriptor.h"
|
||||
#include "test/fuzz/fuzz_test_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace {
|
||||
|
||||
bool IsSynonymous(const FactManager& fact_manager, uint32_t id,
|
||||
uint32_t composite_id, std::vector<uint32_t>&& indices) {
|
||||
protobufs::DataDescriptor data_descriptor =
|
||||
MakeDataDescriptor(composite_id, std::move(indices), 1);
|
||||
return fact_manager.GetSynonymsForId(id).count(&data_descriptor) == 1;
|
||||
}
|
||||
|
||||
TEST(TransformationCompositeExtractTest, BasicTest) {
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "a"
|
||||
OpName %10 "b"
|
||||
OpName %17 "FunnyPoint"
|
||||
OpMemberName %17 0 "x"
|
||||
OpMemberName %17 1 "y"
|
||||
OpMemberName %17 2 "z"
|
||||
OpName %19 "p"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%12 = OpTypeBool
|
||||
%16 = OpTypeFloat 32
|
||||
%17 = OpTypeStruct %16 %16 %6
|
||||
%81 = OpTypeStruct %17 %16
|
||||
%18 = OpTypePointer Function %17
|
||||
%20 = OpConstant %6 0
|
||||
%23 = OpTypePointer Function %16
|
||||
%26 = OpConstant %6 1
|
||||
%30 = OpConstant %6 2
|
||||
%80 = OpUndef %16
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%10 = OpVariable %7 Function
|
||||
%19 = OpVariable %18 Function
|
||||
%9 = OpLoad %6 %8
|
||||
%11 = OpLoad %6 %10
|
||||
%100 = OpCompositeConstruct %17 %80 %80 %26
|
||||
%104 = OpCompositeConstruct %81 %100 %80
|
||||
%13 = OpIEqual %12 %9 %11
|
||||
OpSelectionMerge %15 None
|
||||
OpBranchConditional %13 %14 %25
|
||||
%14 = OpLabel
|
||||
%21 = OpLoad %6 %8
|
||||
%22 = OpConvertSToF %16 %21
|
||||
%101 = OpCompositeConstruct %17 %22 %80 %30
|
||||
%24 = OpAccessChain %23 %19 %20
|
||||
OpStore %24 %22
|
||||
OpBranch %15
|
||||
%25 = OpLabel
|
||||
%27 = OpLoad %6 %10
|
||||
%28 = OpConvertSToF %16 %27
|
||||
%102 = OpCompositeConstruct %17 %80 %28 %27
|
||||
%29 = OpAccessChain %23 %19 %26
|
||||
OpStore %29 %28
|
||||
OpBranch %15
|
||||
%15 = OpLabel
|
||||
%31 = OpAccessChain %23 %19 %20
|
||||
%32 = OpLoad %16 %31
|
||||
%33 = OpAccessChain %23 %19 %26
|
||||
%34 = OpLoad %16 %33
|
||||
%103 = OpCompositeConstruct %17 %34 %32 %9
|
||||
%35 = OpFAdd %16 %32 %34
|
||||
%36 = OpConvertFToS %6 %35
|
||||
%37 = OpAccessChain %7 %19 %30
|
||||
OpStore %37 %36
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_4;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
// Instruction does not exist.
|
||||
ASSERT_FALSE(TransformationCompositeExtract(
|
||||
MakeInstructionDescriptor(36, SpvOpIAdd, 0), 200, 101, {0})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Id for composite is not a composite.
|
||||
ASSERT_FALSE(TransformationCompositeExtract(
|
||||
MakeInstructionDescriptor(36, SpvOpIAdd, 0), 200, 27, {})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Composite does not dominate instruction being inserted before.
|
||||
ASSERT_FALSE(
|
||||
TransformationCompositeExtract(
|
||||
MakeInstructionDescriptor(37, SpvOpAccessChain, 0), 200, 101, {0})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Too many indices for extraction from struct composite.
|
||||
ASSERT_FALSE(
|
||||
TransformationCompositeExtract(
|
||||
MakeInstructionDescriptor(24, SpvOpAccessChain, 0), 200, 101, {0, 0})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Too many indices for extraction from struct composite.
|
||||
ASSERT_FALSE(
|
||||
TransformationCompositeExtract(
|
||||
MakeInstructionDescriptor(13, SpvOpIEqual, 0), 200, 104, {0, 0, 0})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Out of bounds index for extraction from struct composite.
|
||||
ASSERT_FALSE(
|
||||
TransformationCompositeExtract(
|
||||
MakeInstructionDescriptor(13, SpvOpIEqual, 0), 200, 104, {0, 3})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Result id already used.
|
||||
ASSERT_FALSE(TransformationCompositeExtract(
|
||||
MakeInstructionDescriptor(35, SpvOpFAdd, 0), 80, 103, {0})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
TransformationCompositeExtract transformation_1(
|
||||
MakeInstructionDescriptor(36, SpvOpConvertFToS, 0), 201, 100, {2});
|
||||
ASSERT_TRUE(transformation_1.IsApplicable(context.get(), fact_manager));
|
||||
transformation_1.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
TransformationCompositeExtract transformation_2(
|
||||
MakeInstructionDescriptor(37, SpvOpAccessChain, 0), 202, 104, {0, 2});
|
||||
ASSERT_TRUE(transformation_2.IsApplicable(context.get(), fact_manager));
|
||||
transformation_2.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
TransformationCompositeExtract transformation_3(
|
||||
MakeInstructionDescriptor(29, SpvOpAccessChain, 0), 203, 104, {0});
|
||||
ASSERT_TRUE(transformation_3.IsApplicable(context.get(), fact_manager));
|
||||
transformation_3.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
TransformationCompositeExtract transformation_4(
|
||||
MakeInstructionDescriptor(24, SpvOpStore, 0), 204, 101, {0});
|
||||
ASSERT_TRUE(transformation_4.IsApplicable(context.get(), fact_manager));
|
||||
transformation_4.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
TransformationCompositeExtract transformation_5(
|
||||
MakeInstructionDescriptor(29, SpvOpBranch, 0), 205, 102, {2});
|
||||
ASSERT_TRUE(transformation_5.IsApplicable(context.get(), fact_manager));
|
||||
transformation_5.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
TransformationCompositeExtract transformation_6(
|
||||
MakeInstructionDescriptor(37, SpvOpReturn, 0), 206, 103, {1});
|
||||
ASSERT_TRUE(transformation_6.IsApplicable(context.get(), fact_manager));
|
||||
transformation_6.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
ASSERT_TRUE(IsSynonymous(fact_manager, 201, 100, {2}));
|
||||
ASSERT_TRUE(IsSynonymous(fact_manager, 202, 104, {0, 2}));
|
||||
ASSERT_TRUE(IsSynonymous(fact_manager, 203, 104, {0}));
|
||||
ASSERT_TRUE(IsSynonymous(fact_manager, 204, 101, {0}));
|
||||
ASSERT_TRUE(IsSynonymous(fact_manager, 205, 102, {2}));
|
||||
ASSERT_TRUE(IsSynonymous(fact_manager, 206, 103, {1}));
|
||||
|
||||
std::string after_transformation = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "a"
|
||||
OpName %10 "b"
|
||||
OpName %17 "FunnyPoint"
|
||||
OpMemberName %17 0 "x"
|
||||
OpMemberName %17 1 "y"
|
||||
OpMemberName %17 2 "z"
|
||||
OpName %19 "p"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%12 = OpTypeBool
|
||||
%16 = OpTypeFloat 32
|
||||
%17 = OpTypeStruct %16 %16 %6
|
||||
%81 = OpTypeStruct %17 %16
|
||||
%18 = OpTypePointer Function %17
|
||||
%20 = OpConstant %6 0
|
||||
%23 = OpTypePointer Function %16
|
||||
%26 = OpConstant %6 1
|
||||
%30 = OpConstant %6 2
|
||||
%80 = OpUndef %16
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%10 = OpVariable %7 Function
|
||||
%19 = OpVariable %18 Function
|
||||
%9 = OpLoad %6 %8
|
||||
%11 = OpLoad %6 %10
|
||||
%100 = OpCompositeConstruct %17 %80 %80 %26
|
||||
%104 = OpCompositeConstruct %81 %100 %80
|
||||
%13 = OpIEqual %12 %9 %11
|
||||
OpSelectionMerge %15 None
|
||||
OpBranchConditional %13 %14 %25
|
||||
%14 = OpLabel
|
||||
%21 = OpLoad %6 %8
|
||||
%22 = OpConvertSToF %16 %21
|
||||
%101 = OpCompositeConstruct %17 %22 %80 %30
|
||||
%24 = OpAccessChain %23 %19 %20
|
||||
%204 = OpCompositeExtract %16 %101 0
|
||||
OpStore %24 %22
|
||||
OpBranch %15
|
||||
%25 = OpLabel
|
||||
%27 = OpLoad %6 %10
|
||||
%28 = OpConvertSToF %16 %27
|
||||
%102 = OpCompositeConstruct %17 %80 %28 %27
|
||||
%203 = OpCompositeExtract %17 %104 0
|
||||
%29 = OpAccessChain %23 %19 %26
|
||||
OpStore %29 %28
|
||||
%205 = OpCompositeExtract %6 %102 2
|
||||
OpBranch %15
|
||||
%15 = OpLabel
|
||||
%31 = OpAccessChain %23 %19 %20
|
||||
%32 = OpLoad %16 %31
|
||||
%33 = OpAccessChain %23 %19 %26
|
||||
%34 = OpLoad %16 %33
|
||||
%103 = OpCompositeConstruct %17 %34 %32 %9
|
||||
%35 = OpFAdd %16 %32 %34
|
||||
%201 = OpCompositeExtract %6 %100 2
|
||||
%36 = OpConvertFToS %6 %35
|
||||
%202 = OpCompositeExtract %6 %104 0 2
|
||||
%37 = OpAccessChain %7 %19 %30
|
||||
OpStore %37 %36
|
||||
%206 = OpCompositeExtract %16 %103 1
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
|
||||
}
|
||||
|
||||
TEST(TransformationCompositeExtractTest, IllegalInsertionPoints) {
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main" %51 %27
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %25 "buf"
|
||||
OpMemberName %25 0 "value"
|
||||
OpName %27 ""
|
||||
OpName %51 "color"
|
||||
OpMemberDecorate %25 0 Offset 0
|
||||
OpDecorate %25 Block
|
||||
OpDecorate %27 DescriptorSet 0
|
||||
OpDecorate %27 Binding 0
|
||||
OpDecorate %51 Location 0
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeFloat 32
|
||||
%7 = OpTypeVector %6 4
|
||||
%10 = OpConstant %6 0.300000012
|
||||
%11 = OpConstant %6 0.400000006
|
||||
%12 = OpConstant %6 0.5
|
||||
%13 = OpConstant %6 1
|
||||
%14 = OpConstantComposite %7 %10 %11 %12 %13
|
||||
%15 = OpTypeInt 32 1
|
||||
%18 = OpConstant %15 0
|
||||
%25 = OpTypeStruct %6
|
||||
%26 = OpTypePointer Uniform %25
|
||||
%27 = OpVariable %26 Uniform
|
||||
%28 = OpTypePointer Uniform %6
|
||||
%32 = OpTypeBool
|
||||
%103 = OpConstantTrue %32
|
||||
%34 = OpConstant %6 0.100000001
|
||||
%48 = OpConstant %15 1
|
||||
%50 = OpTypePointer Output %7
|
||||
%51 = OpVariable %50 Output
|
||||
%100 = OpTypePointer Function %6
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%101 = OpVariable %100 Function
|
||||
%102 = OpVariable %100 Function
|
||||
OpBranch %19
|
||||
%19 = OpLabel
|
||||
%60 = OpPhi %7 %14 %5 %58 %20
|
||||
%59 = OpPhi %15 %18 %5 %49 %20
|
||||
%29 = OpAccessChain %28 %27 %18
|
||||
%30 = OpLoad %6 %29
|
||||
%31 = OpConvertFToS %15 %30
|
||||
%33 = OpSLessThan %32 %59 %31
|
||||
OpLoopMerge %21 %20 None
|
||||
OpBranchConditional %33 %20 %21
|
||||
%20 = OpLabel
|
||||
%39 = OpCompositeExtract %6 %60 0
|
||||
%40 = OpFAdd %6 %39 %34
|
||||
%55 = OpCompositeInsert %7 %40 %60 0
|
||||
%44 = OpCompositeExtract %6 %60 1
|
||||
%45 = OpFSub %6 %44 %34
|
||||
%58 = OpCompositeInsert %7 %45 %55 1
|
||||
%49 = OpIAdd %15 %59 %48
|
||||
OpBranch %19
|
||||
%21 = OpLabel
|
||||
OpStore %51 %60
|
||||
OpSelectionMerge %105 None
|
||||
OpBranchConditional %103 %104 %105
|
||||
%104 = OpLabel
|
||||
OpBranch %105
|
||||
%105 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_4;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
// Cannot insert before the OpVariables of a function.
|
||||
ASSERT_FALSE(
|
||||
TransformationCompositeExtract(
|
||||
MakeInstructionDescriptor(101, SpvOpVariable, 0), 200, 14, {0})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
TransformationCompositeExtract(
|
||||
MakeInstructionDescriptor(101, SpvOpVariable, 1), 200, 14, {1})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
TransformationCompositeExtract(
|
||||
MakeInstructionDescriptor(102, SpvOpVariable, 0), 200, 14, {1})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
// OK to insert right after the OpVariables.
|
||||
ASSERT_FALSE(TransformationCompositeExtract(
|
||||
MakeInstructionDescriptor(102, SpvOpBranch, 1), 200, 14, {1})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Cannot insert before the OpPhis of a block.
|
||||
ASSERT_FALSE(TransformationCompositeExtract(
|
||||
MakeInstructionDescriptor(60, SpvOpPhi, 0), 200, 14, {2})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationCompositeExtract(
|
||||
MakeInstructionDescriptor(59, SpvOpPhi, 0), 200, 14, {3})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
// OK to insert after the OpPhis.
|
||||
ASSERT_TRUE(
|
||||
TransformationCompositeExtract(
|
||||
MakeInstructionDescriptor(59, SpvOpAccessChain, 0), 200, 14, {3})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Cannot insert before OpLoopMerge
|
||||
ASSERT_FALSE(TransformationCompositeExtract(
|
||||
MakeInstructionDescriptor(33, SpvOpBranchConditional, 0),
|
||||
200, 14, {3})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Cannot insert before OpSelectionMerge
|
||||
ASSERT_FALSE(TransformationCompositeExtract(
|
||||
MakeInstructionDescriptor(21, SpvOpBranchConditional, 0),
|
||||
200, 14, {2})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
Loading…
Reference in New Issue
Block a user