spirv-fuzz: Swap positions of two functions in a module (#4236)

Adds a new transformation class that swaps the syntactic position of
two functions in the module, and a fuzzer pass to apply it.

Fixes #4026.
This commit is contained in:
Shiyu Liu 2021-04-27 06:33:08 -05:00 коммит произвёл GitHub
Родитель 1b8341b8b1
Коммит 6cdf07d2b3
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
15 изменённых файлов: 512 добавлений и 3 удалений

Просмотреть файл

@ -121,6 +121,7 @@ if(SPIRV_BUILD_FUZZER)
fuzzer_pass_split_blocks.h
fuzzer_pass_swap_commutable_operands.h
fuzzer_pass_swap_conditional_branch_operands.h
fuzzer_pass_swap_functions.h
fuzzer_pass_toggle_access_chain_instruction.h
fuzzer_pass_wrap_regions_in_selections.h
fuzzer_util.h
@ -224,6 +225,7 @@ if(SPIRV_BUILD_FUZZER)
transformation_swap_commutable_operands.h
transformation_swap_conditional_branch_operands.h
transformation_swap_function_variables.h
transformation_swap_two_functions.h
transformation_toggle_access_chain_instruction.h
transformation_vector_shuffle.h
transformation_wrap_early_terminator_in_function.h
@ -314,6 +316,7 @@ if(SPIRV_BUILD_FUZZER)
fuzzer_pass_split_blocks.cpp
fuzzer_pass_swap_commutable_operands.cpp
fuzzer_pass_swap_conditional_branch_operands.cpp
fuzzer_pass_swap_functions.cpp
fuzzer_pass_toggle_access_chain_instruction.cpp
fuzzer_pass_wrap_regions_in_selections.cpp
fuzzer_util.cpp
@ -415,6 +418,7 @@ if(SPIRV_BUILD_FUZZER)
transformation_swap_commutable_operands.cpp
transformation_swap_conditional_branch_operands.cpp
transformation_swap_function_variables.cpp
transformation_swap_two_functions.cpp
transformation_toggle_access_chain_instruction.cpp
transformation_vector_shuffle.cpp
transformation_wrap_early_terminator_in_function.cpp

Просмотреть файл

@ -87,6 +87,7 @@
#include "source/fuzz/fuzzer_pass_split_blocks.h"
#include "source/fuzz/fuzzer_pass_swap_commutable_operands.h"
#include "source/fuzz/fuzzer_pass_swap_conditional_branch_operands.h"
#include "source/fuzz/fuzzer_pass_swap_functions.h"
#include "source/fuzz/fuzzer_pass_toggle_access_chain_instruction.h"
#include "source/fuzz/fuzzer_pass_wrap_regions_in_selections.h"
#include "source/fuzz/pass_management/repeated_pass_manager.h"
@ -240,6 +241,7 @@ Fuzzer::Fuzzer(std::unique_ptr<opt::IRContext> ir_context,
MaybeAddFinalPass<FuzzerPassPermuteFunctionVariables>(&final_passes_);
MaybeAddFinalPass<FuzzerPassPermutePhiOperands>(&final_passes_);
MaybeAddFinalPass<FuzzerPassSwapCommutableOperands>(&final_passes_);
MaybeAddFinalPass<FuzzerPassSwapFunctions>(&final_passes_);
MaybeAddFinalPass<FuzzerPassToggleAccessChainInstruction>(&final_passes_);
}

Просмотреть файл

@ -153,10 +153,11 @@ const std::pair<uint32_t, uint32_t> kChanceOfReplacingParametersWithGlobals = {
const std::pair<uint32_t, uint32_t> kChanceOfReplacingParametersWithStruct = {
20, 40};
const std::pair<uint32_t, uint32_t> kChanceOfSplittingBlock = {40, 95};
const std::pair<uint32_t, uint32_t> kChanceOfSwappingConditionalBranchOperands =
{10, 70};
const std::pair<uint32_t, uint32_t>
kChanceOfSwappingAnotherPairOfFunctionVariables = {30, 90};
const std::pair<uint32_t, uint32_t> kChanceOfSwappingConditionalBranchOperands =
{10, 70};
const std::pair<uint32_t, uint32_t> kChanceOfSwappingFunctions = {10, 90};
const std::pair<uint32_t, uint32_t> kChanceOfTogglingAccessChainInstruction = {
20, 90};
const std::pair<uint32_t, uint32_t> kChanceOfWrappingRegionInSelection = {70,
@ -362,6 +363,8 @@ FuzzerContext::FuzzerContext(std::unique_ptr<RandomGenerator> random_generator,
ChooseBetweenMinAndMax(kChanceOfSwappingAnotherPairOfFunctionVariables);
chance_of_swapping_conditional_branch_operands_ =
ChooseBetweenMinAndMax(kChanceOfSwappingConditionalBranchOperands);
chance_of_swapping_functions_ =
ChooseBetweenMinAndMax(kChanceOfSwappingFunctions);
chance_of_toggling_access_chain_instruction_ =
ChooseBetweenMinAndMax(kChanceOfTogglingAccessChainInstruction);
chance_of_wrapping_region_in_selection_ =

Просмотреть файл

@ -369,6 +369,11 @@ class FuzzerContext {
uint32_t GetChanceOfSwappingConditionalBranchOperands() const {
return chance_of_swapping_conditional_branch_operands_;
}
uint32_t GetChanceOfSwappingFunctions() const {
return chance_of_swapping_functions_;
}
uint32_t GetChanceOfTogglingAccessChainInstruction() const {
return chance_of_toggling_access_chain_instruction_;
}
@ -554,6 +559,7 @@ class FuzzerContext {
uint32_t chance_of_splitting_block_;
uint32_t chance_of_swapping_another_pair_of_function_variables_;
uint32_t chance_of_swapping_conditional_branch_operands_;
uint32_t chance_of_swapping_functions_;
uint32_t chance_of_toggling_access_chain_instruction_;
uint32_t chance_of_wrapping_region_in_selection_;

Просмотреть файл

@ -0,0 +1,53 @@
// Copyright (c) 2021 Shiyu Liu
//
// 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/fuzzer_pass_swap_functions.h"
#include "source/fuzz/fuzzer_context.h"
#include "source/fuzz/transformation_swap_two_functions.h"
namespace spvtools {
namespace fuzz {
FuzzerPassSwapFunctions::FuzzerPassSwapFunctions(
opt::IRContext* ir_context, TransformationContext* transformation_context,
FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations)
: FuzzerPass(ir_context, transformation_context, fuzzer_context,
transformations) {}
void FuzzerPassSwapFunctions::Apply() {
// Collect all function ids in a module.
std::vector<uint32_t> function_ids;
for (auto& function : *GetIRContext()->module()) {
function_ids.emplace_back(function.result_id());
}
size_t id_size = function_ids.size();
// Iterate through every combination of id i & j where i!=j.
for (size_t i = 0; i < id_size - 1; ++i) {
for (size_t j = i + 1; j < id_size; ++j) {
// Perform function swap randomly.
if (!GetFuzzerContext()->ChoosePercentage(
GetFuzzerContext()->GetChanceOfSwappingFunctions())) {
continue;
}
TransformationSwapTwoFunctions transformation(function_ids[i],
function_ids[j]);
}
}
}
} // namespace fuzz
} // namespace spvtools

Просмотреть файл

@ -0,0 +1,37 @@
// Copyright (c) 2021 Shiyu Liu
//
// 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_FUZZER_PASS_SWAP_FUNCTIONS_H_
#define SOURCE_FUZZ_FUZZER_PASS_SWAP_FUNCTIONS_H_
#include "source/fuzz/fuzzer_pass.h"
namespace spvtools {
namespace fuzz {
// Randomly swap functions within a module.
class FuzzerPassSwapFunctions : public FuzzerPass {
public:
FuzzerPassSwapFunctions(opt::IRContext* ir_context,
TransformationContext* transformation_context,
FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations);
void Apply() override;
};
} // namespace fuzz
} // namespace spvtools
#endif // SOURCE_FUZZ_FUZZER_PASS_SWAP_FUNCTIONS_H_

Просмотреть файл

@ -1925,6 +1925,15 @@ bool NewTerminatorPreservesDominationRules(opt::IRContext* ir_context,
return true;
}
opt::Module::iterator GetFunctionIterator(opt::IRContext* ir_context,
uint32_t function_id) {
for (auto iter = ir_context->module()->begin();
iter != ir_context->module()->end(); ++iter) {
if ((*iter).result_id() == function_id) return iter;
}
return ir_context->module()->end();
}
} // namespace fuzzerutil
} // namespace fuzz
} // namespace spvtools

Просмотреть файл

@ -24,6 +24,7 @@
#include "source/opt/basic_block.h"
#include "source/opt/instruction.h"
#include "source/opt/ir_context.h"
#include "source/opt/module.h"
#include "spirv-tools/libspirv.hpp"
namespace spvtools {
@ -596,6 +597,12 @@ bool NewTerminatorPreservesDominationRules(opt::IRContext* ir_context,
uint32_t block_id,
opt::Instruction new_terminator);
// Return the iterator that points to the function with the corresponding
// function id. If the function is not found, return the pointer pointing to
// module()->end().
opt::Module::iterator GetFunctionIterator(opt::IRContext* ir_context,
uint32_t function_id);
} // namespace fuzzerutil
} // namespace fuzz
} // namespace spvtools

Просмотреть файл

@ -558,6 +558,7 @@ message Transformation {
TransformationMergeFunctionReturns merge_function_returns = 84;
TransformationExpandVectorReduction expand_vector_reduction = 85;
TransformationSwapFunctionVariables swap_function_variables = 86;
TransformationSwapTwoFunctions swap_two_functions = 87;
// Add additional option using the next available number.
}
}
@ -2268,6 +2269,15 @@ message TransformationSwapFunctionVariables {
uint32 result_id1 = 1;
// Result id of the second variable.
uint32 result_id2 = 2;
}
message TransformationSwapTwoFunctions {
// A transformation that swaps the position of two functions within the same module.
// the IDs for the two functions that are swapped.
uint32 function_id1 = 1;
uint32 function_id2 = 2;
}
message TransformationToggleAccessChainInstruction {

Просмотреть файл

@ -99,6 +99,7 @@
#include "source/fuzz/transformation_swap_commutable_operands.h"
#include "source/fuzz/transformation_swap_conditional_branch_operands.h"
#include "source/fuzz/transformation_swap_function_variables.h"
#include "source/fuzz/transformation_swap_two_functions.h"
#include "source/fuzz/transformation_toggle_access_chain_instruction.h"
#include "source/fuzz/transformation_vector_shuffle.h"
#include "source/fuzz/transformation_wrap_early_terminator_in_function.h"
@ -365,6 +366,9 @@ std::unique_ptr<Transformation> Transformation::FromMessage(
case protobufs::Transformation::TransformationCase::kSwapFunctionVariables:
return MakeUnique<TransformationSwapFunctionVariables>(
message.swap_function_variables());
case protobufs::Transformation::TransformationCase::kSwapTwoFunctions:
return MakeUnique<TransformationSwapTwoFunctions>(
message.swap_two_functions());
case protobufs::Transformation::TransformationCase::
kToggleAccessChainInstruction:
return MakeUnique<TransformationToggleAccessChainInstruction>(

Просмотреть файл

@ -0,0 +1,72 @@
// Copyright (c) 2021 Shiyu Liu
//
// 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_swap_two_functions.h"
#include "source/opt/function.h"
#include "source/opt/module.h"
#include "source/fuzz/fuzzer_util.h"
namespace spvtools {
namespace fuzz {
TransformationSwapTwoFunctions::TransformationSwapTwoFunctions(
protobufs::TransformationSwapTwoFunctions message)
: message_(std::move(message)) {}
TransformationSwapTwoFunctions::TransformationSwapTwoFunctions(uint32_t id1,
uint32_t id2) {
assert(id1 != id2 && "The two function ids cannot be the same.");
message_.set_function_id1(id1);
message_.set_function_id2(id2);
}
bool TransformationSwapTwoFunctions::IsApplicable(
opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
auto func1_ptr = ir_context->GetFunction(message_.function_id1());
auto func2_ptr = ir_context->GetFunction(message_.function_id2());
return func1_ptr != nullptr && func2_ptr != nullptr;
}
void TransformationSwapTwoFunctions::Apply(
opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
opt::Module::iterator func1_it =
fuzzerutil::GetFunctionIterator(ir_context, message_.function_id1());
opt::Module::iterator func2_it =
fuzzerutil::GetFunctionIterator(ir_context, message_.function_id2());
assert(func1_it != ir_context->module()->end() &&
"Could not find function 1.");
assert(func2_it != ir_context->module()->end() &&
"Could not find function 2.");
// Two function pointers are all set, swap the two functions within the
// module.
std::iter_swap(func1_it.Get(), func2_it.Get());
}
protobufs::Transformation TransformationSwapTwoFunctions::ToMessage() const {
protobufs::Transformation result;
*result.mutable_swap_two_functions() = message_;
return result;
}
std::unordered_set<uint32_t> TransformationSwapTwoFunctions::GetFreshIds()
const {
return std::unordered_set<uint32_t>();
}
} // namespace fuzz
} // namespace spvtools

Просмотреть файл

@ -0,0 +1,56 @@
// Copyright (c) 2021 Shiyu Liu
//
// 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_SWAP_TWO_FUNCTIONS_H_
#define SOURCE_FUZZ_TRANSFORMATION_SWAP_TWO_FUNCTIONS_H_
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include "source/fuzz/transformation.h"
#include "source/fuzz/transformation_context.h"
#include "source/opt/ir_context.h"
namespace spvtools {
namespace fuzz {
class TransformationSwapTwoFunctions : public Transformation {
public:
explicit TransformationSwapTwoFunctions(
protobufs::TransformationSwapTwoFunctions message);
TransformationSwapTwoFunctions(uint32_t function_id1, uint32_t function_id2);
// |function_id1| and |function_id1| should all be existing ids.
// Swap function operation is only permitted if:
// - both ids must be ids of functions.
// - both ids can be found in the module.
// - function_id1 and function_id2 are not the same.
bool IsApplicable(
opt::IRContext* ir_context,
const TransformationContext& transformation_context) const override;
// OpFunction with |function_id1| and |function_id1| are swapped.
void Apply(opt::IRContext* ir_context,
TransformationContext* transformation_context) const override;
std::unordered_set<uint32_t> GetFreshIds() const override;
protobufs::Transformation ToMessage() const override;
private:
protobufs::TransformationSwapTwoFunctions message_;
};
} // namespace fuzz
} // namespace spvtools
#endif // SOURCE_FUZZ_TRANSFORMATION_SWAP_TWO_FUNCTIONS_H_

Просмотреть файл

@ -115,6 +115,7 @@ if (${SPIRV_BUILD_FUZZER})
transformation_swap_commutable_operands_test.cpp
transformation_swap_conditional_branch_operands_test.cpp
transformation_swap_function_variables_test.cpp
transformation_swap_two_functions_test.cpp
transformation_toggle_access_chain_instruction_test.cpp
transformation_record_synonymous_constants_test.cpp
transformation_vector_shuffle_test.cpp

Просмотреть файл

@ -0,0 +1,244 @@
// Copyright (c) 2021 Shiyu Liu
//
// 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_swap_two_functions.h"
#include "gtest/gtest.h"
#include "source/fuzz/fuzzer_util.h"
#include "test/fuzz/fuzz_test_util.h"
namespace spvtools {
namespace fuzz {
namespace {
TEST(TransformationSwapTwoFunctionsTest, SimpleTest) {
// float multiplyBy2(in float value) {
// return value*2.0;
// }
// float multiplyBy4(in float value) {
// return multiplyBy2(value)*2.0;
// }
// float multiplyBy8(in float value) {
// return multiplyBy2(value)*multiplyBy4(value);
// }
// layout(location=0) in float value;
// void main() { //4
// multiplyBy2(3.7); //10
// multiplyBy4(3.9); //13
// multiplyBy8(5.0); //16
// }
std::string shader = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main" %48
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 310
OpName %4 "main"
OpName %10 "multiplyBy2(f1;"
OpName %9 "value"
OpName %13 "multiplyBy4(f1;"
OpName %12 "value"
OpName %16 "multiplyBy8(f1;"
OpName %15 "value"
OpName %23 "param"
OpName %29 "param"
OpName %32 "param"
OpName %39 "param"
OpName %42 "param"
OpName %45 "param"
OpName %48 "value"
OpDecorate %48 Location 0
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeFloat 32
%7 = OpTypePointer Function %6
%8 = OpTypeFunction %6 %7
%19 = OpConstant %6 2
%38 = OpConstant %6 3.70000005
%41 = OpConstant %6 3.9000001
%44 = OpConstant %6 5
%47 = OpTypePointer Input %6
%48 = OpVariable %47 Input
%4 = OpFunction %2 None %3
%5 = OpLabel
%39 = OpVariable %7 Function
%42 = OpVariable %7 Function
%45 = OpVariable %7 Function
OpStore %39 %38
%40 = OpFunctionCall %6 %10 %39
OpStore %42 %41
%43 = OpFunctionCall %6 %13 %42
OpStore %45 %44
%46 = OpFunctionCall %6 %16 %45
OpReturn
OpFunctionEnd
%10 = OpFunction %6 None %8
%9 = OpFunctionParameter %7
%11 = OpLabel
%18 = OpLoad %6 %9
%20 = OpFMul %6 %18 %19
OpReturnValue %20
OpFunctionEnd
%13 = OpFunction %6 None %8
%12 = OpFunctionParameter %7
%14 = OpLabel
%23 = OpVariable %7 Function
%24 = OpLoad %6 %12
OpStore %23 %24
%25 = OpFunctionCall %6 %10 %23
%26 = OpFMul %6 %25 %19
OpReturnValue %26
OpFunctionEnd
%16 = OpFunction %6 None %8
%15 = OpFunctionParameter %7
%17 = OpLabel
%29 = OpVariable %7 Function
%32 = OpVariable %7 Function
%30 = OpLoad %6 %15
OpStore %29 %30
%31 = OpFunctionCall %6 %10 %29
%33 = OpLoad %6 %15
OpStore %32 %33
%34 = OpFunctionCall %6 %13 %32
%35 = OpFMul %6 %31 %34
OpReturnValue %35
OpFunctionEnd
)";
const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto consumer = nullptr;
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
spvtools::ValidatorOptions validator_options;
// Check context validity.
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
kConsoleMessageConsumer));
TransformationContext transformation_context(
MakeUnique<FactManager>(context.get()), validator_options);
#ifndef NDEBUG
// Function should not swap with itself.
ASSERT_DEATH(TransformationSwapTwoFunctions(4, 4).IsApplicable(
context.get(), transformation_context),
"The two function ids cannot be the same.");
#endif
// Function with id 29 does not exist.
ASSERT_FALSE(TransformationSwapTwoFunctions(10, 29).IsApplicable(
context.get(), transformation_context));
// Function with id 30 does not exist.
ASSERT_FALSE(TransformationSwapTwoFunctions(30, 13).IsApplicable(
context.get(), transformation_context));
// Both functions with id 5 and 6 do not exist.
ASSERT_FALSE(TransformationSwapTwoFunctions(5, 6).IsApplicable(
context.get(), transformation_context));
// Function with result_id 10 and 13 should swap successfully.
auto swap_test5 = TransformationSwapTwoFunctions(10, 13);
ASSERT_TRUE(swap_test5.IsApplicable(context.get(), transformation_context));
ApplyAndCheckFreshIds(swap_test5, context.get(), &transformation_context);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
kConsoleMessageConsumer));
std::string after_transformation = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main" %48
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 310
OpName %4 "main"
OpName %10 "multiplyBy2(f1;"
OpName %9 "value"
OpName %13 "multiplyBy4(f1;"
OpName %12 "value"
OpName %16 "multiplyBy8(f1;"
OpName %15 "value"
OpName %23 "param"
OpName %29 "param"
OpName %32 "param"
OpName %39 "param"
OpName %42 "param"
OpName %45 "param"
OpName %48 "value"
OpDecorate %48 Location 0
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeFloat 32
%7 = OpTypePointer Function %6
%8 = OpTypeFunction %6 %7
%19 = OpConstant %6 2
%38 = OpConstant %6 3.70000005
%41 = OpConstant %6 3.9000001
%44 = OpConstant %6 5
%47 = OpTypePointer Input %6
%48 = OpVariable %47 Input
%4 = OpFunction %2 None %3
%5 = OpLabel
%39 = OpVariable %7 Function
%42 = OpVariable %7 Function
%45 = OpVariable %7 Function
OpStore %39 %38
%40 = OpFunctionCall %6 %10 %39
OpStore %42 %41
%43 = OpFunctionCall %6 %13 %42
OpStore %45 %44
%46 = OpFunctionCall %6 %16 %45
OpReturn
OpFunctionEnd
%13 = OpFunction %6 None %8
%12 = OpFunctionParameter %7
%14 = OpLabel
%23 = OpVariable %7 Function
%24 = OpLoad %6 %12
OpStore %23 %24
%25 = OpFunctionCall %6 %10 %23
%26 = OpFMul %6 %25 %19
OpReturnValue %26
OpFunctionEnd
%10 = OpFunction %6 None %8
%9 = OpFunctionParameter %7
%11 = OpLabel
%18 = OpLoad %6 %9
%20 = OpFMul %6 %18 %19
OpReturnValue %20
OpFunctionEnd
%16 = OpFunction %6 None %8
%15 = OpFunctionParameter %7
%17 = OpLabel
%29 = OpVariable %7 Function
%32 = OpVariable %7 Function
%30 = OpLoad %6 %15
OpStore %29 %30
%31 = OpFunctionCall %6 %10 %29
%33 = OpLoad %6 %15
OpStore %32 %33
%34 = OpFunctionCall %6 %13 %32
%35 = OpFMul %6 %31 %34
OpReturnValue %35
OpFunctionEnd
)";
ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
}
} // namespace
} // namespace fuzz
} // namespace spvtools

Просмотреть файл

@ -38,7 +38,8 @@ AUTHORS = ['The Khronos Group Inc.',
'Advanced Micro Devices, Inc.',
'Stefano Milizia',
'Alastair F. Donaldson',
'Mostafa Ashraf']
'Mostafa Ashraf',
'Shiyu Liu']
CURRENT_YEAR='2021'
YEARS = '(2014-2016|2015-2016|2015-2020|2016|2016-2017|2017|2017-2019|2018|2019|2020|2021)'