| // Copyright (c) 2020 Vasyl Teliman |
| // |
| // 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_replace_params_with_struct.h" |
| |
| #include "test/fuzz/fuzz_test_util.h" |
| |
| namespace spvtools { |
| namespace fuzz { |
| namespace { |
| |
| TEST(TransformationReplaceParamsWithStructTest, 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 |
| OpMemberDecorate %13 0 RelaxedPrecision |
| OpDecorate %16 RelaxedPrecision |
| %2 = OpTypeVoid |
| %6 = OpTypeInt 32 1 |
| %3 = OpTypeFunction %2 |
| %7 = OpTypePointer Private %6 |
| %8 = OpTypeFloat 32 |
| %9 = OpTypePointer Private %8 |
| %10 = OpTypeVector %8 2 |
| %11 = OpTypePointer Private %10 |
| %12 = OpTypeBool |
| %51 = OpTypeFunction %2 %12 |
| %64 = OpTypeStruct %6 |
| %63 = OpTypeFunction %2 %64 |
| %65 = OpTypeFunction %2 %6 |
| %75 = OpTypeStruct %8 |
| %76 = OpTypeFunction %2 %75 |
| %77 = OpTypeFunction %2 %8 |
| %40 = OpTypePointer Function %12 |
| %13 = OpTypeStruct %6 %8 |
| %45 = OpTypeStruct %6 %10 %13 |
| %46 = OpTypeStruct %12 |
| %47 = OpTypeStruct %8 %45 %46 |
| %14 = OpTypePointer Private %13 |
| %15 = OpTypeFunction %2 %6 %8 %10 %13 %40 %12 |
| %22 = OpConstant %6 0 |
| %23 = OpConstant %8 0 |
| %26 = OpConstantComposite %10 %23 %23 |
| %27 = OpConstantTrue %12 |
| %28 = OpConstantComposite %13 %22 %23 |
| %4 = OpFunction %2 None %3 |
| %5 = OpLabel |
| %41 = OpVariable %40 Function %27 |
| %33 = OpFunctionCall %2 %20 %22 %23 %26 %28 %41 %27 |
| OpReturn |
| OpFunctionEnd |
| |
| ; adjust type of the function in-place |
| %20 = OpFunction %2 None %15 |
| %16 = OpFunctionParameter %6 |
| %17 = OpFunctionParameter %8 |
| %18 = OpFunctionParameter %10 |
| %19 = OpFunctionParameter %13 |
| %42 = OpFunctionParameter %40 |
| %43 = OpFunctionParameter %12 |
| %21 = OpLabel |
| OpReturn |
| OpFunctionEnd |
| |
| ; create a new function type |
| %50 = OpFunction %2 None %51 |
| %52 = OpFunctionParameter %12 |
| %53 = OpLabel |
| OpReturn |
| OpFunctionEnd |
| %54 = OpFunction %2 None %51 |
| %55 = OpFunctionParameter %12 |
| %56 = OpLabel |
| OpReturn |
| OpFunctionEnd |
| |
| ; reuse an existing function type |
| %57 = OpFunction %2 None %63 |
| %58 = OpFunctionParameter %64 |
| %59 = OpLabel |
| OpReturn |
| OpFunctionEnd |
| %60 = OpFunction %2 None %65 |
| %61 = OpFunctionParameter %6 |
| %62 = OpLabel |
| OpReturn |
| OpFunctionEnd |
| %66 = OpFunction %2 None %65 |
| %67 = OpFunctionParameter %6 |
| %68 = OpLabel |
| OpReturn |
| OpFunctionEnd |
| |
| ; don't adjust the type of the function if it creates a duplicate |
| %69 = OpFunction %2 None %76 |
| %70 = OpFunctionParameter %75 |
| %71 = OpLabel |
| OpReturn |
| OpFunctionEnd |
| %72 = OpFunction %2 None %77 |
| %73 = OpFunctionParameter %8 |
| %74 = OpLabel |
| OpReturn |
| OpFunctionEnd |
| )"; |
| |
| const auto env = SPV_ENV_UNIVERSAL_1_3; |
| const auto consumer = nullptr; |
| const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); |
| ASSERT_TRUE(IsValid(env, context.get())); |
| |
| FactManager fact_manager; |
| spvtools::ValidatorOptions validator_options; |
| TransformationContext transformation_context(&fact_manager, |
| validator_options); |
| |
| // |parameter_id| is empty. |
| ASSERT_FALSE( |
| TransformationReplaceParamsWithStruct({}, 90, 91, {{33, 92}, {90, 93}}) |
| .IsApplicable(context.get(), transformation_context)); |
| |
| // |parameter_id| has duplicates. |
| ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 16, 17}, 90, 91, |
| {{33, 92}, {90, 93}}) |
| .IsApplicable(context.get(), transformation_context)); |
| |
| // |parameter_id| has invalid values. |
| ASSERT_FALSE(TransformationReplaceParamsWithStruct({21, 16, 17}, 90, 91, |
| {{33, 92}, {90, 93}}) |
| .IsApplicable(context.get(), transformation_context)); |
| ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 90, 17}, 90, 91, |
| {{33, 92}, {90, 93}}) |
| .IsApplicable(context.get(), transformation_context)); |
| |
| // Parameter's belong to different functions. |
| ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 17, 52}, 90, 91, |
| {{33, 92}, {90, 93}}) |
| .IsApplicable(context.get(), transformation_context)); |
| |
| // Parameter has unsupported type. |
| ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 17, 42, 43}, 90, 91, |
| {{33, 92}, {90, 93}}) |
| .IsApplicable(context.get(), transformation_context)); |
| |
| // OpTypeStruct does not exist in the module. |
| ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 43}, 90, 91, |
| {{33, 92}, {90, 93}}) |
| .IsApplicable(context.get(), transformation_context)); |
| |
| // |caller_id_to_fresh_composite_id| misses values. |
| ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 17}, 90, 91, |
| {{33, 92}, {90, 93}}) |
| .IsApplicable(context.get(), transformation_context)); |
| |
| // All fresh ids must be unique. |
| ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 17}, 90, 90, |
| {{33, 92}, {90, 93}}) |
| .IsApplicable(context.get(), transformation_context)); |
| ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 17}, 90, 91, |
| {{33, 90}, {90, 93}}) |
| .IsApplicable(context.get(), transformation_context)); |
| ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 17}, 90, 91, |
| {{33, 92}, {90, 92}}) |
| .IsApplicable(context.get(), transformation_context)); |
| |
| // All 'fresh' ids must be fresh. |
| ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 17}, 90, 91, |
| {{33, 33}, {90, 93}}) |
| .IsApplicable(context.get(), transformation_context)); |
| ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 17}, 33, 91, |
| {{33, 92}, {90, 93}}) |
| .IsApplicable(context.get(), transformation_context)); |
| ASSERT_FALSE(TransformationReplaceParamsWithStruct({16, 17}, 90, 33, |
| {{33, 92}, {90, 93}}) |
| .IsApplicable(context.get(), transformation_context)); |
| |
| { |
| TransformationReplaceParamsWithStruct transformation({16, 18, 19}, 90, 91, |
| {{33, 92}, {90, 93}}); |
| ASSERT_TRUE( |
| transformation.IsApplicable(context.get(), transformation_context)); |
| transformation.Apply(context.get(), &transformation_context); |
| } |
| { |
| TransformationReplaceParamsWithStruct transformation({43}, 93, 94, |
| {{33, 95}}); |
| ASSERT_TRUE( |
| transformation.IsApplicable(context.get(), transformation_context)); |
| transformation.Apply(context.get(), &transformation_context); |
| } |
| { |
| TransformationReplaceParamsWithStruct transformation({17, 91, 94}, 96, 97, |
| {{33, 98}}); |
| ASSERT_TRUE( |
| transformation.IsApplicable(context.get(), transformation_context)); |
| transformation.Apply(context.get(), &transformation_context); |
| } |
| { |
| TransformationReplaceParamsWithStruct transformation({55}, 99, 100, {{}}); |
| ASSERT_TRUE( |
| transformation.IsApplicable(context.get(), transformation_context)); |
| transformation.Apply(context.get(), &transformation_context); |
| } |
| { |
| TransformationReplaceParamsWithStruct transformation({61}, 101, 102, {{}}); |
| ASSERT_TRUE( |
| transformation.IsApplicable(context.get(), transformation_context)); |
| transformation.Apply(context.get(), &transformation_context); |
| } |
| { |
| TransformationReplaceParamsWithStruct transformation({73}, 103, 104, {{}}); |
| ASSERT_TRUE( |
| transformation.IsApplicable(context.get(), transformation_context)); |
| transformation.Apply(context.get(), &transformation_context); |
| } |
| |
| ASSERT_TRUE(IsValid(env, context.get())); |
| |
| std::string expected_shader = R"( |
| OpCapability Shader |
| %1 = OpExtInstImport "GLSL.std.450" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint Fragment %4 "main" |
| OpExecutionMode %4 OriginUpperLeft |
| OpSource ESSL 310 |
| OpMemberDecorate %13 0 RelaxedPrecision |
| OpDecorate %16 RelaxedPrecision |
| %2 = OpTypeVoid |
| %6 = OpTypeInt 32 1 |
| %3 = OpTypeFunction %2 |
| %7 = OpTypePointer Private %6 |
| %8 = OpTypeFloat 32 |
| %9 = OpTypePointer Private %8 |
| %10 = OpTypeVector %8 2 |
| %11 = OpTypePointer Private %10 |
| %12 = OpTypeBool |
| %51 = OpTypeFunction %2 %12 |
| %64 = OpTypeStruct %6 |
| %63 = OpTypeFunction %2 %64 |
| %65 = OpTypeFunction %2 %6 |
| %75 = OpTypeStruct %8 |
| %76 = OpTypeFunction %2 %75 |
| %40 = OpTypePointer Function %12 |
| %13 = OpTypeStruct %6 %8 |
| %45 = OpTypeStruct %6 %10 %13 |
| %46 = OpTypeStruct %12 |
| %47 = OpTypeStruct %8 %45 %46 |
| %14 = OpTypePointer Private %13 |
| %22 = OpConstant %6 0 |
| %23 = OpConstant %8 0 |
| %26 = OpConstantComposite %10 %23 %23 |
| %27 = OpConstantTrue %12 |
| %28 = OpConstantComposite %13 %22 %23 |
| %15 = OpTypeFunction %2 %40 %47 |
| %99 = OpTypeFunction %2 %46 |
| %4 = OpFunction %2 None %3 |
| %5 = OpLabel |
| %41 = OpVariable %40 Function %27 |
| %92 = OpCompositeConstruct %45 %22 %26 %28 |
| %95 = OpCompositeConstruct %46 %27 |
| %98 = OpCompositeConstruct %47 %23 %92 %95 |
| %33 = OpFunctionCall %2 %20 %41 %98 |
| OpReturn |
| OpFunctionEnd |
| %20 = OpFunction %2 None %15 |
| %42 = OpFunctionParameter %40 |
| %97 = OpFunctionParameter %47 |
| %21 = OpLabel |
| %94 = OpCompositeExtract %46 %97 2 |
| %91 = OpCompositeExtract %45 %97 1 |
| %17 = OpCompositeExtract %8 %97 0 |
| %43 = OpCompositeExtract %12 %94 0 |
| %19 = OpCompositeExtract %13 %91 2 |
| %18 = OpCompositeExtract %10 %91 1 |
| %16 = OpCompositeExtract %6 %91 0 |
| OpReturn |
| OpFunctionEnd |
| %50 = OpFunction %2 None %51 |
| %52 = OpFunctionParameter %12 |
| %53 = OpLabel |
| OpReturn |
| OpFunctionEnd |
| %54 = OpFunction %2 None %99 |
| %100 = OpFunctionParameter %46 |
| %56 = OpLabel |
| %55 = OpCompositeExtract %12 %100 0 |
| OpReturn |
| OpFunctionEnd |
| %57 = OpFunction %2 None %63 |
| %58 = OpFunctionParameter %64 |
| %59 = OpLabel |
| OpReturn |
| OpFunctionEnd |
| %60 = OpFunction %2 None %63 |
| %102 = OpFunctionParameter %64 |
| %62 = OpLabel |
| %61 = OpCompositeExtract %6 %102 0 |
| OpReturn |
| OpFunctionEnd |
| %66 = OpFunction %2 None %65 |
| %67 = OpFunctionParameter %6 |
| %68 = OpLabel |
| OpReturn |
| OpFunctionEnd |
| %69 = OpFunction %2 None %76 |
| %70 = OpFunctionParameter %75 |
| %71 = OpLabel |
| OpReturn |
| OpFunctionEnd |
| %72 = OpFunction %2 None %76 |
| %104 = OpFunctionParameter %75 |
| %74 = OpLabel |
| %73 = OpCompositeExtract %8 %104 0 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| |
| ASSERT_TRUE(IsEqual(env, expected_shader, context.get())); |
| } |
| |
| } // namespace |
| } // namespace fuzz |
| } // namespace spvtools |