| // 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_construct.h" |
| |
| #include "gtest/gtest.h" |
| #include "source/fuzz/data_descriptor.h" |
| #include "source/fuzz/fuzzer_util.h" |
| #include "source/fuzz/instruction_descriptor.h" |
| #include "test/fuzz/fuzz_test_util.h" |
| |
| namespace spvtools { |
| namespace fuzz { |
| namespace { |
| |
| TEST(TransformationCompositeConstructTest, ConstructArrays) { |
| 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 %11 "floats" |
| OpName %22 "x" |
| OpName %39 "vecs" |
| OpName %49 "bools" |
| OpName %60 "many_uvec3s" |
| OpDecorate %60 RelaxedPrecision |
| %2 = OpTypeVoid |
| %3 = OpTypeFunction %2 |
| %6 = OpTypeFloat 32 |
| %7 = OpTypeInt 32 0 |
| %8 = OpConstant %7 2 |
| %9 = OpTypeArray %6 %8 |
| %10 = OpTypePointer Function %9 |
| %12 = OpTypeInt 32 1 |
| %13 = OpConstant %12 0 |
| %14 = OpConstant %6 1 |
| %15 = OpTypePointer Function %6 |
| %17 = OpConstant %12 1 |
| %18 = OpConstant %6 2 |
| %20 = OpTypeVector %6 2 |
| %21 = OpTypePointer Function %20 |
| %32 = OpTypeBool |
| %36 = OpConstant %7 3 |
| %37 = OpTypeArray %20 %36 |
| %38 = OpTypePointer Private %37 |
| %39 = OpVariable %38 Private |
| %40 = OpConstant %6 3 |
| %41 = OpConstantComposite %20 %40 %40 |
| %42 = OpTypePointer Private %20 |
| %44 = OpConstant %12 2 |
| %47 = OpTypeArray %32 %36 |
| %48 = OpTypePointer Function %47 |
| %50 = OpConstantTrue %32 |
| %51 = OpTypePointer Function %32 |
| %56 = OpTypeVector %7 3 |
| %57 = OpTypeArray %56 %8 |
| %58 = OpTypeArray %57 %8 |
| %59 = OpTypePointer Function %58 |
| %61 = OpConstant %7 4 |
| %62 = OpConstantComposite %56 %61 %61 %61 |
| %63 = OpTypePointer Function %56 |
| %65 = OpConstant %7 5 |
| %66 = OpConstantComposite %56 %65 %65 %65 |
| %67 = OpConstant %7 6 |
| %68 = OpConstantComposite %56 %67 %67 %67 |
| %69 = OpConstantComposite %57 %66 %68 |
| %100 = OpUndef %57 |
| %70 = OpTypePointer Function %57 |
| %4 = OpFunction %2 None %3 |
| %5 = OpLabel |
| %11 = OpVariable %10 Function |
| %22 = OpVariable %21 Function |
| %49 = OpVariable %48 Function |
| %60 = OpVariable %59 Function |
| %16 = OpAccessChain %15 %11 %13 |
| OpStore %16 %14 |
| %19 = OpAccessChain %15 %11 %17 |
| OpStore %19 %18 |
| %23 = OpAccessChain %15 %11 %13 |
| %24 = OpLoad %6 %23 |
| %25 = OpAccessChain %15 %11 %17 |
| %26 = OpLoad %6 %25 |
| %27 = OpCompositeConstruct %20 %24 %26 |
| OpStore %22 %27 |
| %28 = OpAccessChain %15 %11 %13 |
| %29 = OpLoad %6 %28 |
| %30 = OpAccessChain %15 %11 %17 |
| %31 = OpLoad %6 %30 |
| %33 = OpFOrdGreaterThan %32 %29 %31 |
| OpSelectionMerge %35 None |
| OpBranchConditional %33 %34 %35 |
| %34 = OpLabel |
| %43 = OpAccessChain %42 %39 %17 |
| OpStore %43 %41 |
| %45 = OpLoad %20 %22 |
| %46 = OpAccessChain %42 %39 %44 |
| OpStore %46 %45 |
| OpBranch %35 |
| %35 = OpLabel |
| %52 = OpAccessChain %51 %49 %13 |
| OpStore %52 %50 |
| %53 = OpAccessChain %51 %49 %13 |
| %54 = OpLoad %32 %53 |
| %55 = OpAccessChain %51 %49 %17 |
| OpStore %55 %54 |
| %64 = OpAccessChain %63 %60 %13 %13 |
| OpStore %64 %62 |
| %71 = OpAccessChain %70 %60 %17 |
| OpStore %71 %69 |
| OpReturn |
| 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; |
| ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, |
| kConsoleMessageConsumer)); |
| TransformationContext transformation_context( |
| MakeUnique<FactManager>(context.get()), validator_options); |
| // Make a vec2[3] |
| TransformationCompositeConstruct make_vec2_array_length_3( |
| 37, {41, 45, 27}, |
| MakeInstructionDescriptor(46, spv::Op::OpAccessChain, 0), 200); |
| // Bad: there are too many components |
| TransformationCompositeConstruct make_vec2_array_length_3_bad( |
| 37, {41, 45, 27, 27}, |
| MakeInstructionDescriptor(46, spv::Op::OpAccessChain, 0), 200); |
| // The first component does not correspond to an instruction with a result |
| // type so this check should return false. |
| TransformationCompositeConstruct make_vec2_array_length_3_nores( |
| 37, {2, 45, 27}, MakeInstructionDescriptor(46, spv::Op::OpAccessChain, 0), |
| 200); |
| ASSERT_TRUE(make_vec2_array_length_3.IsApplicable(context.get(), |
| transformation_context)); |
| ASSERT_FALSE(make_vec2_array_length_3_bad.IsApplicable( |
| context.get(), transformation_context)); |
| ASSERT_FALSE(make_vec2_array_length_3_nores.IsApplicable( |
| context.get(), transformation_context)); |
| ASSERT_EQ(nullptr, context->get_def_use_mgr()->GetDef(200)); |
| ASSERT_EQ(nullptr, context->get_instr_block(200)); |
| uint32_t num_uses_of_41_before = context->get_def_use_mgr()->NumUses(41); |
| uint32_t num_uses_of_45_before = context->get_def_use_mgr()->NumUses(45); |
| uint32_t num_uses_of_27_before = context->get_def_use_mgr()->NumUses(27); |
| ApplyAndCheckFreshIds(make_vec2_array_length_3, context.get(), |
| &transformation_context); |
| ASSERT_EQ(spv::Op::OpCompositeConstruct, |
| context->get_def_use_mgr()->GetDef(200)->opcode()); |
| ASSERT_EQ(34, context->get_instr_block(200)->id()); |
| ASSERT_EQ(num_uses_of_41_before + 1, context->get_def_use_mgr()->NumUses(41)); |
| ASSERT_EQ(num_uses_of_45_before + 1, context->get_def_use_mgr()->NumUses(45)); |
| ASSERT_EQ(num_uses_of_27_before + 1, context->get_def_use_mgr()->NumUses(27)); |
| ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, |
| kConsoleMessageConsumer)); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(41, {}), MakeDataDescriptor(200, {0}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(45, {}), MakeDataDescriptor(200, {1}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(27, {}), MakeDataDescriptor(200, {2}))); |
| |
| // Make a float[2] |
| TransformationCompositeConstruct make_float_array_length_2( |
| 9, {24, 40}, MakeInstructionDescriptor(71, spv::Op::OpStore, 0), 201); |
| // Bad: %41 does not have type float |
| TransformationCompositeConstruct make_float_array_length_2_bad( |
| 9, {41, 40}, MakeInstructionDescriptor(71, spv::Op::OpStore, 0), 201); |
| ASSERT_TRUE(make_float_array_length_2.IsApplicable(context.get(), |
| transformation_context)); |
| ASSERT_FALSE(make_float_array_length_2_bad.IsApplicable( |
| context.get(), transformation_context)); |
| ApplyAndCheckFreshIds(make_float_array_length_2, context.get(), |
| &transformation_context); |
| ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, |
| kConsoleMessageConsumer)); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(24, {}), MakeDataDescriptor(201, {0}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(40, {}), MakeDataDescriptor(201, {1}))); |
| |
| // Make a bool[3] |
| TransformationCompositeConstruct make_bool_array_length_3( |
| 47, {33, 50, 50}, |
| MakeInstructionDescriptor(33, spv::Op::OpSelectionMerge, 0), 202); |
| // Bad: %54 is not available at the desired program point. |
| TransformationCompositeConstruct make_bool_array_length_3_bad( |
| 47, {33, 54, 50}, |
| MakeInstructionDescriptor(33, spv::Op::OpSelectionMerge, 0), 202); |
| ASSERT_TRUE(make_bool_array_length_3.IsApplicable(context.get(), |
| transformation_context)); |
| ASSERT_FALSE(make_bool_array_length_3_bad.IsApplicable( |
| context.get(), transformation_context)); |
| ApplyAndCheckFreshIds(make_bool_array_length_3, context.get(), |
| &transformation_context); |
| ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, |
| kConsoleMessageConsumer)); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(33, {}), MakeDataDescriptor(202, {0}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(50, {}), MakeDataDescriptor(202, {1}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(50, {}), MakeDataDescriptor(202, {2}))); |
| |
| // make a uvec3[2][2] |
| TransformationCompositeConstruct make_uvec3_array_length_2_2( |
| 58, {69, 100}, MakeInstructionDescriptor(64, spv::Op::OpStore, 0), 203); |
| // Bad: Skip count 100 is too large. |
| TransformationCompositeConstruct make_uvec3_array_length_2_2_bad( |
| 58, {33, 54}, MakeInstructionDescriptor(64, spv::Op::OpStore, 100), 203); |
| ASSERT_TRUE(make_uvec3_array_length_2_2.IsApplicable(context.get(), |
| transformation_context)); |
| ASSERT_FALSE(make_uvec3_array_length_2_2_bad.IsApplicable( |
| context.get(), transformation_context)); |
| ApplyAndCheckFreshIds(make_uvec3_array_length_2_2, context.get(), |
| &transformation_context); |
| ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, |
| kConsoleMessageConsumer)); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(69, {}), MakeDataDescriptor(203, {0}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(100, {}), MakeDataDescriptor(203, {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 %11 "floats" |
| OpName %22 "x" |
| OpName %39 "vecs" |
| OpName %49 "bools" |
| OpName %60 "many_uvec3s" |
| OpDecorate %60 RelaxedPrecision |
| %2 = OpTypeVoid |
| %3 = OpTypeFunction %2 |
| %6 = OpTypeFloat 32 |
| %7 = OpTypeInt 32 0 |
| %8 = OpConstant %7 2 |
| %9 = OpTypeArray %6 %8 |
| %10 = OpTypePointer Function %9 |
| %12 = OpTypeInt 32 1 |
| %13 = OpConstant %12 0 |
| %14 = OpConstant %6 1 |
| %15 = OpTypePointer Function %6 |
| %17 = OpConstant %12 1 |
| %18 = OpConstant %6 2 |
| %20 = OpTypeVector %6 2 |
| %21 = OpTypePointer Function %20 |
| %32 = OpTypeBool |
| %36 = OpConstant %7 3 |
| %37 = OpTypeArray %20 %36 |
| %38 = OpTypePointer Private %37 |
| %39 = OpVariable %38 Private |
| %40 = OpConstant %6 3 |
| %41 = OpConstantComposite %20 %40 %40 |
| %42 = OpTypePointer Private %20 |
| %44 = OpConstant %12 2 |
| %47 = OpTypeArray %32 %36 |
| %48 = OpTypePointer Function %47 |
| %50 = OpConstantTrue %32 |
| %51 = OpTypePointer Function %32 |
| %56 = OpTypeVector %7 3 |
| %57 = OpTypeArray %56 %8 |
| %58 = OpTypeArray %57 %8 |
| %59 = OpTypePointer Function %58 |
| %61 = OpConstant %7 4 |
| %62 = OpConstantComposite %56 %61 %61 %61 |
| %63 = OpTypePointer Function %56 |
| %65 = OpConstant %7 5 |
| %66 = OpConstantComposite %56 %65 %65 %65 |
| %67 = OpConstant %7 6 |
| %68 = OpConstantComposite %56 %67 %67 %67 |
| %69 = OpConstantComposite %57 %66 %68 |
| %100 = OpUndef %57 |
| %70 = OpTypePointer Function %57 |
| %4 = OpFunction %2 None %3 |
| %5 = OpLabel |
| %11 = OpVariable %10 Function |
| %22 = OpVariable %21 Function |
| %49 = OpVariable %48 Function |
| %60 = OpVariable %59 Function |
| %16 = OpAccessChain %15 %11 %13 |
| OpStore %16 %14 |
| %19 = OpAccessChain %15 %11 %17 |
| OpStore %19 %18 |
| %23 = OpAccessChain %15 %11 %13 |
| %24 = OpLoad %6 %23 |
| %25 = OpAccessChain %15 %11 %17 |
| %26 = OpLoad %6 %25 |
| %27 = OpCompositeConstruct %20 %24 %26 |
| OpStore %22 %27 |
| %28 = OpAccessChain %15 %11 %13 |
| %29 = OpLoad %6 %28 |
| %30 = OpAccessChain %15 %11 %17 |
| %31 = OpLoad %6 %30 |
| %33 = OpFOrdGreaterThan %32 %29 %31 |
| %202 = OpCompositeConstruct %47 %33 %50 %50 |
| OpSelectionMerge %35 None |
| OpBranchConditional %33 %34 %35 |
| %34 = OpLabel |
| %43 = OpAccessChain %42 %39 %17 |
| OpStore %43 %41 |
| %45 = OpLoad %20 %22 |
| %200 = OpCompositeConstruct %37 %41 %45 %27 |
| %46 = OpAccessChain %42 %39 %44 |
| OpStore %46 %45 |
| OpBranch %35 |
| %35 = OpLabel |
| %52 = OpAccessChain %51 %49 %13 |
| OpStore %52 %50 |
| %53 = OpAccessChain %51 %49 %13 |
| %54 = OpLoad %32 %53 |
| %55 = OpAccessChain %51 %49 %17 |
| OpStore %55 %54 |
| %64 = OpAccessChain %63 %60 %13 %13 |
| %203 = OpCompositeConstruct %58 %69 %100 |
| OpStore %64 %62 |
| %71 = OpAccessChain %70 %60 %17 |
| %201 = OpCompositeConstruct %9 %24 %40 |
| OpStore %71 %69 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| |
| ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); |
| } |
| |
| TEST(TransformationCompositeConstructTest, ConstructMatrices) { |
| 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 %9 "v1" |
| OpName %12 "v2" |
| OpName %14 "v3" |
| OpName %19 "v4" |
| OpName %26 "v5" |
| OpName %29 "v6" |
| OpName %34 "m34" |
| OpName %37 "m43" |
| OpName %43 "vecs" |
| %2 = OpTypeVoid |
| %3 = OpTypeFunction %2 |
| %6 = OpTypeFloat 32 |
| %7 = OpTypeVector %6 3 |
| %8 = OpTypePointer Function %7 |
| %10 = OpConstant %6 1 |
| %11 = OpConstantComposite %7 %10 %10 %10 |
| %17 = OpTypeVector %6 4 |
| %18 = OpTypePointer Function %17 |
| %21 = OpConstant %6 2 |
| %32 = OpTypeMatrix %17 3 |
| %33 = OpTypePointer Private %32 |
| %34 = OpVariable %33 Private |
| %35 = OpTypeMatrix %7 4 |
| %36 = OpTypePointer Private %35 |
| %37 = OpVariable %36 Private |
| %38 = OpTypeVector %6 2 |
| %39 = OpTypeInt 32 0 |
| %40 = OpConstant %39 3 |
| %41 = OpTypeArray %38 %40 |
| %42 = OpTypePointer Private %41 |
| %43 = OpVariable %42 Private |
| %100 = OpUndef %7 |
| %101 = OpUndef %17 |
| %4 = OpFunction %2 None %3 |
| %5 = OpLabel |
| %9 = OpVariable %8 Function |
| %12 = OpVariable %8 Function |
| %14 = OpVariable %8 Function |
| %19 = OpVariable %18 Function |
| %26 = OpVariable %18 Function |
| %29 = OpVariable %18 Function |
| OpStore %9 %11 |
| %13 = OpLoad %7 %9 |
| OpStore %12 %13 |
| %15 = OpLoad %7 %12 |
| %16 = OpVectorShuffle %7 %15 %15 2 1 0 |
| OpStore %14 %16 |
| %20 = OpLoad %7 %14 |
| %22 = OpCompositeExtract %6 %20 0 |
| %23 = OpCompositeExtract %6 %20 1 |
| %24 = OpCompositeExtract %6 %20 2 |
| %25 = OpCompositeConstruct %17 %22 %23 %24 %21 |
| OpStore %19 %25 |
| %27 = OpLoad %17 %19 |
| %28 = OpVectorShuffle %17 %27 %27 3 2 1 0 |
| OpStore %26 %28 |
| %30 = OpLoad %7 %9 |
| %31 = OpVectorShuffle %17 %30 %30 0 0 1 1 |
| OpStore %29 %31 |
| OpReturn |
| 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; |
| ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, |
| kConsoleMessageConsumer)); |
| TransformationContext transformation_context( |
| MakeUnique<FactManager>(context.get()), validator_options); |
| // make a mat3x4 |
| TransformationCompositeConstruct make_mat34( |
| 32, {25, 28, 31}, MakeInstructionDescriptor(31, spv::Op::OpReturn, 0), |
| 200); |
| // Bad: %35 is mat4x3, not mat3x4. |
| TransformationCompositeConstruct make_mat34_bad( |
| 35, {25, 28, 31}, MakeInstructionDescriptor(31, spv::Op::OpReturn, 0), |
| 200); |
| // The first component does not correspond to an instruction with a result |
| // type so this check should return false. |
| TransformationCompositeConstruct make_mat34_nores( |
| 32, {2, 28, 31}, MakeInstructionDescriptor(31, spv::Op::OpReturn, 0), |
| 200); |
| ASSERT_TRUE(make_mat34.IsApplicable(context.get(), transformation_context)); |
| ASSERT_FALSE( |
| make_mat34_bad.IsApplicable(context.get(), transformation_context)); |
| ASSERT_FALSE( |
| make_mat34_nores.IsApplicable(context.get(), transformation_context)); |
| ApplyAndCheckFreshIds(make_mat34, context.get(), &transformation_context); |
| ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, |
| kConsoleMessageConsumer)); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(25, {}), MakeDataDescriptor(200, {0}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(28, {}), MakeDataDescriptor(200, {1}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(31, {}), MakeDataDescriptor(200, {2}))); |
| |
| // make a mat4x3 |
| TransformationCompositeConstruct make_mat43( |
| 35, {11, 13, 16, 100}, MakeInstructionDescriptor(31, spv::Op::OpStore, 0), |
| 201); |
| // Bad: %25 does not match the matrix's column type. |
| TransformationCompositeConstruct make_mat43_bad( |
| 35, {25, 13, 16, 100}, MakeInstructionDescriptor(31, spv::Op::OpStore, 0), |
| 201); |
| ASSERT_TRUE(make_mat43.IsApplicable(context.get(), transformation_context)); |
| ASSERT_FALSE( |
| make_mat43_bad.IsApplicable(context.get(), transformation_context)); |
| ApplyAndCheckFreshIds(make_mat43, context.get(), &transformation_context); |
| ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, |
| kConsoleMessageConsumer)); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(11, {}), MakeDataDescriptor(201, {0}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(13, {}), MakeDataDescriptor(201, {1}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(16, {}), MakeDataDescriptor(201, {2}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(100, {}), MakeDataDescriptor(201, {3}))); |
| |
| 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 %9 "v1" |
| OpName %12 "v2" |
| OpName %14 "v3" |
| OpName %19 "v4" |
| OpName %26 "v5" |
| OpName %29 "v6" |
| OpName %34 "m34" |
| OpName %37 "m43" |
| OpName %43 "vecs" |
| %2 = OpTypeVoid |
| %3 = OpTypeFunction %2 |
| %6 = OpTypeFloat 32 |
| %7 = OpTypeVector %6 3 |
| %8 = OpTypePointer Function %7 |
| %10 = OpConstant %6 1 |
| %11 = OpConstantComposite %7 %10 %10 %10 |
| %17 = OpTypeVector %6 4 |
| %18 = OpTypePointer Function %17 |
| %21 = OpConstant %6 2 |
| %32 = OpTypeMatrix %17 3 |
| %33 = OpTypePointer Private %32 |
| %34 = OpVariable %33 Private |
| %35 = OpTypeMatrix %7 4 |
| %36 = OpTypePointer Private %35 |
| %37 = OpVariable %36 Private |
| %38 = OpTypeVector %6 2 |
| %39 = OpTypeInt 32 0 |
| %40 = OpConstant %39 3 |
| %41 = OpTypeArray %38 %40 |
| %42 = OpTypePointer Private %41 |
| %43 = OpVariable %42 Private |
| %100 = OpUndef %7 |
| %101 = OpUndef %17 |
| %4 = OpFunction %2 None %3 |
| %5 = OpLabel |
| %9 = OpVariable %8 Function |
| %12 = OpVariable %8 Function |
| %14 = OpVariable %8 Function |
| %19 = OpVariable %18 Function |
| %26 = OpVariable %18 Function |
| %29 = OpVariable %18 Function |
| OpStore %9 %11 |
| %13 = OpLoad %7 %9 |
| OpStore %12 %13 |
| %15 = OpLoad %7 %12 |
| %16 = OpVectorShuffle %7 %15 %15 2 1 0 |
| OpStore %14 %16 |
| %20 = OpLoad %7 %14 |
| %22 = OpCompositeExtract %6 %20 0 |
| %23 = OpCompositeExtract %6 %20 1 |
| %24 = OpCompositeExtract %6 %20 2 |
| %25 = OpCompositeConstruct %17 %22 %23 %24 %21 |
| OpStore %19 %25 |
| %27 = OpLoad %17 %19 |
| %28 = OpVectorShuffle %17 %27 %27 3 2 1 0 |
| OpStore %26 %28 |
| %30 = OpLoad %7 %9 |
| %31 = OpVectorShuffle %17 %30 %30 0 0 1 1 |
| %201 = OpCompositeConstruct %35 %11 %13 %16 %100 |
| OpStore %29 %31 |
| %200 = OpCompositeConstruct %32 %25 %28 %31 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| |
| ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); |
| } |
| |
| TEST(TransformationCompositeConstructTest, ConstructStructs) { |
| 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 %9 "Inner" |
| OpMemberName %9 0 "a" |
| OpMemberName %9 1 "b" |
| OpName %11 "i1" |
| OpName %22 "i2" |
| OpName %33 "Outer" |
| OpMemberName %33 0 "c" |
| OpMemberName %33 1 "d" |
| OpMemberName %33 2 "e" |
| OpName %35 "o" |
| %2 = OpTypeVoid |
| %3 = OpTypeFunction %2 |
| %6 = OpTypeFloat 32 |
| %7 = OpTypeVector %6 2 |
| %8 = OpTypeInt 32 1 |
| %9 = OpTypeStruct %7 %8 |
| %10 = OpTypePointer Function %9 |
| %12 = OpConstant %8 0 |
| %13 = OpConstant %6 2 |
| %14 = OpTypeInt 32 0 |
| %15 = OpConstant %14 0 |
| %16 = OpTypePointer Function %6 |
| %18 = OpConstant %8 1 |
| %19 = OpConstant %8 3 |
| %20 = OpTypePointer Function %8 |
| %23 = OpTypePointer Function %7 |
| %31 = OpConstant %14 2 |
| %32 = OpTypeArray %9 %31 |
| %33 = OpTypeStruct %32 %9 %6 |
| %34 = OpTypePointer Function %33 |
| %36 = OpConstant %6 1 |
| %37 = OpConstantComposite %7 %36 %13 |
| %38 = OpConstant %8 2 |
| %39 = OpConstantComposite %9 %37 %38 |
| %40 = OpConstant %6 3 |
| %41 = OpConstant %6 4 |
| %42 = OpConstantComposite %7 %40 %41 |
| %56 = OpConstant %6 5 |
| %100 = OpUndef %9 |
| %4 = OpFunction %2 None %3 |
| %5 = OpLabel |
| %11 = OpVariable %10 Function |
| %22 = OpVariable %10 Function |
| %35 = OpVariable %34 Function |
| %17 = OpAccessChain %16 %11 %12 %15 |
| OpStore %17 %13 |
| %21 = OpAccessChain %20 %11 %18 |
| OpStore %21 %19 |
| %24 = OpAccessChain %23 %11 %12 |
| %25 = OpLoad %7 %24 |
| %26 = OpAccessChain %23 %22 %12 |
| OpStore %26 %25 |
| %27 = OpAccessChain %20 %11 %18 |
| %28 = OpLoad %8 %27 |
| %29 = OpIAdd %8 %28 %18 |
| %30 = OpAccessChain %20 %22 %18 |
| OpStore %30 %29 |
| %43 = OpAccessChain %20 %11 %18 |
| %44 = OpLoad %8 %43 |
| %45 = OpCompositeConstruct %9 %42 %44 |
| %46 = OpCompositeConstruct %32 %39 %45 |
| %47 = OpLoad %9 %22 |
| %48 = OpCompositeConstruct %33 %46 %47 %40 |
| OpStore %35 %48 |
| %49 = OpLoad %9 %11 |
| %50 = OpAccessChain %10 %35 %12 %12 |
| OpStore %50 %49 |
| %51 = OpLoad %9 %22 |
| %52 = OpAccessChain %10 %35 %12 %18 |
| OpStore %52 %51 |
| %53 = OpAccessChain %10 %35 %12 %12 |
| %54 = OpLoad %9 %53 |
| %55 = OpAccessChain %10 %35 %18 |
| OpStore %55 %54 |
| %57 = OpAccessChain %16 %35 %38 |
| OpStore %57 %56 |
| OpReturn |
| 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; |
| ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, |
| kConsoleMessageConsumer)); |
| TransformationContext transformation_context( |
| MakeUnique<FactManager>(context.get()), validator_options); |
| // make an Inner |
| TransformationCompositeConstruct make_inner( |
| 9, {25, 19}, MakeInstructionDescriptor(57, spv::Op::OpAccessChain, 0), |
| 200); |
| // Bad: Too few fields to make the struct. |
| TransformationCompositeConstruct make_inner_bad( |
| 9, {25}, MakeInstructionDescriptor(57, spv::Op::OpAccessChain, 0), 200); |
| // The first component does not correspond to an instruction with a result |
| // type so this check should return false. |
| TransformationCompositeConstruct make_inner_nores( |
| 9, {2, 19}, MakeInstructionDescriptor(57, spv::Op::OpAccessChain, 0), |
| 200); |
| ASSERT_TRUE(make_inner.IsApplicable(context.get(), transformation_context)); |
| ASSERT_FALSE( |
| make_inner_bad.IsApplicable(context.get(), transformation_context)); |
| ASSERT_FALSE( |
| make_inner_nores.IsApplicable(context.get(), transformation_context)); |
| ApplyAndCheckFreshIds(make_inner, context.get(), &transformation_context); |
| ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, |
| kConsoleMessageConsumer)); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(25, {}), MakeDataDescriptor(200, {0}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(19, {}), MakeDataDescriptor(200, {1}))); |
| |
| // make an Outer |
| TransformationCompositeConstruct make_outer( |
| 33, {46, 200, 56}, |
| MakeInstructionDescriptor(200, spv::Op::OpAccessChain, 0), 201); |
| // Bad: %200 is not available at the desired program point. |
| TransformationCompositeConstruct make_outer_bad( |
| 33, {46, 200, 56}, |
| MakeInstructionDescriptor(200, spv::Op::OpCompositeConstruct, 0), 201); |
| ASSERT_TRUE(make_outer.IsApplicable(context.get(), transformation_context)); |
| ASSERT_FALSE( |
| make_outer_bad.IsApplicable(context.get(), transformation_context)); |
| ApplyAndCheckFreshIds(make_outer, context.get(), &transformation_context); |
| ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, |
| kConsoleMessageConsumer)); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(46, {}), MakeDataDescriptor(201, {0}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(200, {}), MakeDataDescriptor(201, {1}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(56, {}), MakeDataDescriptor(201, {2}))); |
| |
| 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 %9 "Inner" |
| OpMemberName %9 0 "a" |
| OpMemberName %9 1 "b" |
| OpName %11 "i1" |
| OpName %22 "i2" |
| OpName %33 "Outer" |
| OpMemberName %33 0 "c" |
| OpMemberName %33 1 "d" |
| OpMemberName %33 2 "e" |
| OpName %35 "o" |
| %2 = OpTypeVoid |
| %3 = OpTypeFunction %2 |
| %6 = OpTypeFloat 32 |
| %7 = OpTypeVector %6 2 |
| %8 = OpTypeInt 32 1 |
| %9 = OpTypeStruct %7 %8 |
| %10 = OpTypePointer Function %9 |
| %12 = OpConstant %8 0 |
| %13 = OpConstant %6 2 |
| %14 = OpTypeInt 32 0 |
| %15 = OpConstant %14 0 |
| %16 = OpTypePointer Function %6 |
| %18 = OpConstant %8 1 |
| %19 = OpConstant %8 3 |
| %20 = OpTypePointer Function %8 |
| %23 = OpTypePointer Function %7 |
| %31 = OpConstant %14 2 |
| %32 = OpTypeArray %9 %31 |
| %33 = OpTypeStruct %32 %9 %6 |
| %34 = OpTypePointer Function %33 |
| %36 = OpConstant %6 1 |
| %37 = OpConstantComposite %7 %36 %13 |
| %38 = OpConstant %8 2 |
| %39 = OpConstantComposite %9 %37 %38 |
| %40 = OpConstant %6 3 |
| %41 = OpConstant %6 4 |
| %42 = OpConstantComposite %7 %40 %41 |
| %56 = OpConstant %6 5 |
| %100 = OpUndef %9 |
| %4 = OpFunction %2 None %3 |
| %5 = OpLabel |
| %11 = OpVariable %10 Function |
| %22 = OpVariable %10 Function |
| %35 = OpVariable %34 Function |
| %17 = OpAccessChain %16 %11 %12 %15 |
| OpStore %17 %13 |
| %21 = OpAccessChain %20 %11 %18 |
| OpStore %21 %19 |
| %24 = OpAccessChain %23 %11 %12 |
| %25 = OpLoad %7 %24 |
| %26 = OpAccessChain %23 %22 %12 |
| OpStore %26 %25 |
| %27 = OpAccessChain %20 %11 %18 |
| %28 = OpLoad %8 %27 |
| %29 = OpIAdd %8 %28 %18 |
| %30 = OpAccessChain %20 %22 %18 |
| OpStore %30 %29 |
| %43 = OpAccessChain %20 %11 %18 |
| %44 = OpLoad %8 %43 |
| %45 = OpCompositeConstruct %9 %42 %44 |
| %46 = OpCompositeConstruct %32 %39 %45 |
| %47 = OpLoad %9 %22 |
| %48 = OpCompositeConstruct %33 %46 %47 %40 |
| OpStore %35 %48 |
| %49 = OpLoad %9 %11 |
| %50 = OpAccessChain %10 %35 %12 %12 |
| OpStore %50 %49 |
| %51 = OpLoad %9 %22 |
| %52 = OpAccessChain %10 %35 %12 %18 |
| OpStore %52 %51 |
| %53 = OpAccessChain %10 %35 %12 %12 |
| %54 = OpLoad %9 %53 |
| %55 = OpAccessChain %10 %35 %18 |
| OpStore %55 %54 |
| %200 = OpCompositeConstruct %9 %25 %19 |
| %201 = OpCompositeConstruct %33 %46 %200 %56 |
| %57 = OpAccessChain %16 %35 %38 |
| OpStore %57 %56 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| |
| ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); |
| } |
| |
| TEST(TransformationCompositeConstructTest, ConstructVectors) { |
| 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 %9 "v2" |
| OpName %27 "v3" |
| OpName %46 "v4" |
| OpName %53 "iv2" |
| OpName %61 "uv3" |
| OpName %72 "bv4" |
| OpName %88 "uv2" |
| OpName %95 "bv3" |
| OpName %104 "bv2" |
| OpName %116 "iv3" |
| OpName %124 "iv4" |
| OpName %133 "uv4" |
| %2 = OpTypeVoid |
| %3 = OpTypeFunction %2 |
| %6 = OpTypeFloat 32 |
| %7 = OpTypeVector %6 2 |
| %8 = OpTypePointer Function %7 |
| %10 = OpConstant %6 1 |
| %11 = OpConstant %6 2 |
| %12 = OpConstantComposite %7 %10 %11 |
| %13 = OpTypeInt 32 0 |
| %14 = OpConstant %13 0 |
| %15 = OpTypePointer Function %6 |
| %18 = OpConstant %13 1 |
| %21 = OpTypeBool |
| %25 = OpTypeVector %6 3 |
| %26 = OpTypePointer Function %25 |
| %33 = OpConstant %6 3 |
| %34 = OpConstant %6 -0.756802499 |
| %38 = OpConstant %13 2 |
| %44 = OpTypeVector %6 4 |
| %45 = OpTypePointer Function %44 |
| %50 = OpTypeInt 32 1 |
| %51 = OpTypeVector %50 2 |
| %52 = OpTypePointer Function %51 |
| %57 = OpTypePointer Function %50 |
| %59 = OpTypeVector %13 3 |
| %60 = OpTypePointer Function %59 |
| %65 = OpConstant %13 3 |
| %67 = OpTypePointer Function %13 |
| %70 = OpTypeVector %21 4 |
| %71 = OpTypePointer Function %70 |
| %73 = OpConstantTrue %21 |
| %74 = OpTypePointer Function %21 |
| %86 = OpTypeVector %13 2 |
| %87 = OpTypePointer Function %86 |
| %93 = OpTypeVector %21 3 |
| %94 = OpTypePointer Function %93 |
| %102 = OpTypeVector %21 2 |
| %103 = OpTypePointer Function %102 |
| %111 = OpConstantFalse %21 |
| %114 = OpTypeVector %50 3 |
| %115 = OpTypePointer Function %114 |
| %117 = OpConstant %50 3 |
| %122 = OpTypeVector %50 4 |
| %123 = OpTypePointer Function %122 |
| %131 = OpTypeVector %13 4 |
| %132 = OpTypePointer Function %131 |
| %4 = OpFunction %2 None %3 |
| %5 = OpLabel |
| %9 = OpVariable %8 Function |
| %27 = OpVariable %26 Function |
| %46 = OpVariable %45 Function |
| %53 = OpVariable %52 Function |
| %61 = OpVariable %60 Function |
| %72 = OpVariable %71 Function |
| %88 = OpVariable %87 Function |
| %95 = OpVariable %94 Function |
| %104 = OpVariable %103 Function |
| %116 = OpVariable %115 Function |
| %124 = OpVariable %123 Function |
| %133 = OpVariable %132 Function |
| OpStore %9 %12 |
| %16 = OpAccessChain %15 %9 %14 |
| %17 = OpLoad %6 %16 |
| %19 = OpAccessChain %15 %9 %18 |
| %20 = OpLoad %6 %19 |
| %22 = OpFOrdGreaterThan %21 %17 %20 |
| OpSelectionMerge %24 None |
| OpBranchConditional %22 %23 %101 |
| %23 = OpLabel |
| %28 = OpAccessChain %15 %9 %14 |
| %29 = OpLoad %6 %28 |
| %30 = OpAccessChain %15 %9 %18 |
| %31 = OpLoad %6 %30 |
| %32 = OpFAdd %6 %29 %31 |
| %35 = OpCompositeConstruct %25 %32 %33 %34 |
| OpStore %27 %35 |
| %36 = OpAccessChain %15 %27 %14 |
| %37 = OpLoad %6 %36 |
| %39 = OpAccessChain %15 %27 %38 |
| %40 = OpLoad %6 %39 |
| %41 = OpFOrdLessThan %21 %37 %40 |
| OpSelectionMerge %43 None |
| OpBranchConditional %41 %42 %69 |
| %42 = OpLabel |
| %47 = OpAccessChain %15 %9 %18 |
| %48 = OpLoad %6 %47 |
| %49 = OpAccessChain %15 %46 %14 |
| OpStore %49 %48 |
| %54 = OpAccessChain %15 %27 %38 |
| %55 = OpLoad %6 %54 |
| %56 = OpConvertFToS %50 %55 |
| %58 = OpAccessChain %57 %53 %14 |
| OpStore %58 %56 |
| %62 = OpAccessChain %15 %46 %14 |
| %63 = OpLoad %6 %62 |
| %64 = OpConvertFToU %13 %63 |
| %66 = OpIAdd %13 %64 %65 |
| %68 = OpAccessChain %67 %61 %14 |
| OpStore %68 %66 |
| OpBranch %43 |
| %69 = OpLabel |
| %75 = OpAccessChain %74 %72 %14 |
| OpStore %75 %73 |
| %76 = OpAccessChain %74 %72 %14 |
| %77 = OpLoad %21 %76 |
| %78 = OpLogicalNot %21 %77 |
| %79 = OpAccessChain %74 %72 %18 |
| OpStore %79 %78 |
| %80 = OpAccessChain %74 %72 %14 |
| %81 = OpLoad %21 %80 |
| %82 = OpAccessChain %74 %72 %18 |
| %83 = OpLoad %21 %82 |
| %84 = OpLogicalAnd %21 %81 %83 |
| %85 = OpAccessChain %74 %72 %38 |
| OpStore %85 %84 |
| %89 = OpAccessChain %67 %88 %14 |
| %90 = OpLoad %13 %89 |
| %91 = OpINotEqual %21 %90 %14 |
| %92 = OpAccessChain %74 %72 %65 |
| OpStore %92 %91 |
| OpBranch %43 |
| %43 = OpLabel |
| %96 = OpLoad %70 %72 |
| %97 = OpCompositeExtract %21 %96 0 |
| %98 = OpCompositeExtract %21 %96 1 |
| %99 = OpCompositeExtract %21 %96 2 |
| %100 = OpCompositeConstruct %93 %97 %98 %99 |
| OpStore %95 %100 |
| OpBranch %24 |
| %101 = OpLabel |
| %105 = OpAccessChain %67 %88 %14 |
| %106 = OpLoad %13 %105 |
| %107 = OpINotEqual %21 %106 %14 |
| %108 = OpCompositeConstruct %102 %107 %107 |
| OpStore %104 %108 |
| OpBranch %24 |
| %24 = OpLabel |
| %109 = OpAccessChain %74 %104 %18 |
| %110 = OpLoad %21 %109 |
| %112 = OpLogicalOr %21 %110 %111 |
| %113 = OpAccessChain %74 %104 %14 |
| OpStore %113 %112 |
| %118 = OpAccessChain %57 %116 %14 |
| OpStore %118 %117 |
| %119 = OpAccessChain %57 %116 %14 |
| %120 = OpLoad %50 %119 |
| %121 = OpAccessChain %57 %53 %18 |
| OpStore %121 %120 |
| %125 = OpAccessChain %57 %116 %14 |
| %126 = OpLoad %50 %125 |
| %127 = OpAccessChain %57 %53 %18 |
| %128 = OpLoad %50 %127 |
| %129 = OpIAdd %50 %126 %128 |
| %130 = OpAccessChain %57 %124 %65 |
| OpStore %130 %129 |
| %134 = OpAccessChain %57 %116 %14 |
| %135 = OpLoad %50 %134 |
| %136 = OpBitcast %13 %135 |
| %137 = OpAccessChain %67 %133 %14 |
| OpStore %137 %136 |
| OpReturn |
| 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; |
| ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, |
| kConsoleMessageConsumer)); |
| TransformationContext transformation_context( |
| MakeUnique<FactManager>(context.get()), validator_options); |
| TransformationCompositeConstruct make_vec2( |
| 7, {17, 11}, MakeInstructionDescriptor(100, spv::Op::OpStore, 0), 200); |
| // Bad: not enough data for a vec2 |
| TransformationCompositeConstruct make_vec2_bad( |
| 7, {11}, MakeInstructionDescriptor(100, spv::Op::OpStore, 0), 200); |
| ASSERT_TRUE(make_vec2.IsApplicable(context.get(), transformation_context)); |
| ASSERT_FALSE( |
| make_vec2_bad.IsApplicable(context.get(), transformation_context)); |
| ApplyAndCheckFreshIds(make_vec2, context.get(), &transformation_context); |
| ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, |
| kConsoleMessageConsumer)); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(17, {}), MakeDataDescriptor(200, {0}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(11, {}), MakeDataDescriptor(200, {1}))); |
| |
| TransformationCompositeConstruct make_vec3( |
| 25, {12, 32}, |
| MakeInstructionDescriptor(35, spv::Op::OpCompositeConstruct, 0), 201); |
| // Bad: too much data for a vec3 |
| TransformationCompositeConstruct make_vec3_bad( |
| 25, {12, 32, 32}, |
| MakeInstructionDescriptor(35, spv::Op::OpCompositeConstruct, 0), 201); |
| ASSERT_TRUE(make_vec3.IsApplicable(context.get(), transformation_context)); |
| ASSERT_FALSE( |
| make_vec3_bad.IsApplicable(context.get(), transformation_context)); |
| ApplyAndCheckFreshIds(make_vec3, context.get(), &transformation_context); |
| ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, |
| kConsoleMessageConsumer)); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(12, {0}), MakeDataDescriptor(201, {0}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(12, {1}), MakeDataDescriptor(201, {1}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(32, {}), MakeDataDescriptor(201, {2}))); |
| |
| TransformationCompositeConstruct make_vec4( |
| 44, {32, 32, 10, 11}, |
| MakeInstructionDescriptor(75, spv::Op::OpAccessChain, 0), 202); |
| // Bad: id 48 is not available at the insertion points |
| TransformationCompositeConstruct make_vec4_bad( |
| 44, {48, 32, 10, 11}, |
| MakeInstructionDescriptor(75, spv::Op::OpAccessChain, 0), 202); |
| ASSERT_TRUE(make_vec4.IsApplicable(context.get(), transformation_context)); |
| ASSERT_FALSE( |
| make_vec4_bad.IsApplicable(context.get(), transformation_context)); |
| ApplyAndCheckFreshIds(make_vec4, context.get(), &transformation_context); |
| ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, |
| kConsoleMessageConsumer)); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(32, {}), MakeDataDescriptor(202, {0}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(32, {}), MakeDataDescriptor(202, {1}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(10, {}), MakeDataDescriptor(202, {2}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(11, {}), MakeDataDescriptor(202, {3}))); |
| |
| TransformationCompositeConstruct make_ivec2( |
| 51, {126, 120}, MakeInstructionDescriptor(128, spv::Op::OpLoad, 0), 203); |
| // Bad: if 128 is not available at the instruction that defines 128 |
| TransformationCompositeConstruct make_ivec2_bad( |
| 51, {128, 120}, MakeInstructionDescriptor(128, spv::Op::OpLoad, 0), 203); |
| ASSERT_TRUE(make_ivec2.IsApplicable(context.get(), transformation_context)); |
| ASSERT_FALSE( |
| make_ivec2_bad.IsApplicable(context.get(), transformation_context)); |
| ApplyAndCheckFreshIds(make_ivec2, context.get(), &transformation_context); |
| ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, |
| kConsoleMessageConsumer)); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(126, {}), MakeDataDescriptor(203, {0}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(120, {}), MakeDataDescriptor(203, {1}))); |
| |
| TransformationCompositeConstruct make_ivec3( |
| 114, {56, 117, 56}, |
| MakeInstructionDescriptor(66, spv::Op::OpAccessChain, 0), 204); |
| // Bad because 1300 is not an id |
| TransformationCompositeConstruct make_ivec3_bad( |
| 114, {56, 117, 1300}, |
| MakeInstructionDescriptor(66, spv::Op::OpAccessChain, 0), 204); |
| ASSERT_TRUE(make_ivec3.IsApplicable(context.get(), transformation_context)); |
| ASSERT_FALSE( |
| make_ivec3_bad.IsApplicable(context.get(), transformation_context)); |
| ApplyAndCheckFreshIds(make_ivec3, context.get(), &transformation_context); |
| ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, |
| kConsoleMessageConsumer)); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(56, {}), MakeDataDescriptor(204, {0}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(117, {}), MakeDataDescriptor(204, {1}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(56, {}), MakeDataDescriptor(204, {2}))); |
| |
| TransformationCompositeConstruct make_ivec4( |
| 122, {56, 117, 117, 117}, |
| MakeInstructionDescriptor(66, spv::Op::OpIAdd, 0), 205); |
| // Bad because 86 is the wrong type. |
| TransformationCompositeConstruct make_ivec4_bad( |
| 86, {56, 117, 117, 117}, |
| MakeInstructionDescriptor(66, spv::Op::OpIAdd, 0), 205); |
| ASSERT_TRUE(make_ivec4.IsApplicable(context.get(), transformation_context)); |
| ASSERT_FALSE( |
| make_ivec4_bad.IsApplicable(context.get(), transformation_context)); |
| ApplyAndCheckFreshIds(make_ivec4, context.get(), &transformation_context); |
| ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, |
| kConsoleMessageConsumer)); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(56, {}), MakeDataDescriptor(205, {0}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(117, {}), MakeDataDescriptor(205, {1}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(117, {}), MakeDataDescriptor(205, {2}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(117, {}), MakeDataDescriptor(205, {3}))); |
| |
| TransformationCompositeConstruct make_uvec2( |
| 86, {18, 38}, MakeInstructionDescriptor(133, spv::Op::OpAccessChain, 0), |
| 206); |
| TransformationCompositeConstruct make_uvec2_bad( |
| 86, {18, 38}, MakeInstructionDescriptor(133, spv::Op::OpAccessChain, 200), |
| 206); |
| ASSERT_TRUE(make_uvec2.IsApplicable(context.get(), transformation_context)); |
| ASSERT_FALSE( |
| make_uvec2_bad.IsApplicable(context.get(), transformation_context)); |
| ApplyAndCheckFreshIds(make_uvec2, context.get(), &transformation_context); |
| ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, |
| kConsoleMessageConsumer)); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(18, {}), MakeDataDescriptor(206, {0}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(38, {}), MakeDataDescriptor(206, {1}))); |
| |
| TransformationCompositeConstruct make_uvec3( |
| 59, {14, 18, 136}, MakeInstructionDescriptor(137, spv::Op::OpReturn, 0), |
| 207); |
| // Bad because 1300 is not an id |
| TransformationCompositeConstruct make_uvec3_bad( |
| 59, {14, 18, 1300}, MakeInstructionDescriptor(137, spv::Op::OpReturn, 0), |
| 207); |
| ASSERT_TRUE(make_uvec3.IsApplicable(context.get(), transformation_context)); |
| ASSERT_FALSE( |
| make_uvec3_bad.IsApplicable(context.get(), transformation_context)); |
| ApplyAndCheckFreshIds(make_uvec3, context.get(), &transformation_context); |
| ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, |
| kConsoleMessageConsumer)); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(14, {}), MakeDataDescriptor(207, {0}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(18, {}), MakeDataDescriptor(207, {1}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(136, {}), MakeDataDescriptor(207, {2}))); |
| |
| TransformationCompositeConstruct make_uvec4( |
| 131, {14, 18, 136, 136}, |
| MakeInstructionDescriptor(137, spv::Op::OpAccessChain, 0), 208); |
| // Bad because 86 is the wrong type. |
| TransformationCompositeConstruct make_uvec4_bad( |
| 86, {14, 18, 136, 136}, |
| MakeInstructionDescriptor(137, spv::Op::OpAccessChain, 0), 208); |
| ASSERT_TRUE(make_uvec4.IsApplicable(context.get(), transformation_context)); |
| ASSERT_FALSE( |
| make_uvec4_bad.IsApplicable(context.get(), transformation_context)); |
| ApplyAndCheckFreshIds(make_uvec4, context.get(), &transformation_context); |
| ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, |
| kConsoleMessageConsumer)); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(14, {}), MakeDataDescriptor(208, {0}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(18, {}), MakeDataDescriptor(208, {1}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(136, {}), MakeDataDescriptor(208, {2}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(136, {}), MakeDataDescriptor(208, {3}))); |
| |
| TransformationCompositeConstruct make_bvec2( |
| 102, |
| { |
| 111, |
| 41, |
| }, |
| MakeInstructionDescriptor(75, spv::Op::OpAccessChain, 0), 209); |
| // Bad because 0 is not a valid base instruction id |
| TransformationCompositeConstruct make_bvec2_bad( |
| 102, |
| { |
| 111, |
| 41, |
| }, |
| MakeInstructionDescriptor(0, spv::Op::OpExtInstImport, 0), 209); |
| ASSERT_TRUE(make_bvec2.IsApplicable(context.get(), transformation_context)); |
| ASSERT_FALSE( |
| make_bvec2_bad.IsApplicable(context.get(), transformation_context)); |
| ApplyAndCheckFreshIds(make_bvec2, context.get(), &transformation_context); |
| ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, |
| kConsoleMessageConsumer)); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(111, {}), MakeDataDescriptor(209, {0}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(41, {}), MakeDataDescriptor(209, {1}))); |
| |
| TransformationCompositeConstruct make_bvec3( |
| 93, {108, 73}, MakeInstructionDescriptor(108, spv::Op::OpStore, 0), 210); |
| // Bad because there are too many components for a bvec3 |
| TransformationCompositeConstruct make_bvec3_bad( |
| 93, {108, 108}, MakeInstructionDescriptor(108, spv::Op::OpStore, 0), 210); |
| ASSERT_TRUE(make_bvec3.IsApplicable(context.get(), transformation_context)); |
| ASSERT_FALSE( |
| make_bvec3_bad.IsApplicable(context.get(), transformation_context)); |
| ApplyAndCheckFreshIds(make_bvec3, context.get(), &transformation_context); |
| ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, |
| kConsoleMessageConsumer)); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(108, {0}), MakeDataDescriptor(210, {0}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(108, {1}), MakeDataDescriptor(210, {1}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(73, {}), MakeDataDescriptor(210, {2}))); |
| |
| TransformationCompositeConstruct make_bvec4( |
| 70, {108, 108}, MakeInstructionDescriptor(108, spv::Op::OpBranch, 0), |
| 211); |
| // Bad because 21 is a type, not a result id |
| TransformationCompositeConstruct make_bvec4_bad( |
| 70, {21, 108}, MakeInstructionDescriptor(108, spv::Op::OpBranch, 0), 211); |
| ASSERT_TRUE(make_bvec4.IsApplicable(context.get(), transformation_context)); |
| ASSERT_FALSE( |
| make_bvec4_bad.IsApplicable(context.get(), transformation_context)); |
| ApplyAndCheckFreshIds(make_bvec4, context.get(), &transformation_context); |
| ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, |
| kConsoleMessageConsumer)); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(108, {0}), MakeDataDescriptor(211, {0}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(108, {1}), MakeDataDescriptor(211, {1}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(108, {0}), MakeDataDescriptor(211, {2}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(108, {1}), MakeDataDescriptor(211, {3}))); |
| |
| 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 %9 "v2" |
| OpName %27 "v3" |
| OpName %46 "v4" |
| OpName %53 "iv2" |
| OpName %61 "uv3" |
| OpName %72 "bv4" |
| OpName %88 "uv2" |
| OpName %95 "bv3" |
| OpName %104 "bv2" |
| OpName %116 "iv3" |
| OpName %124 "iv4" |
| OpName %133 "uv4" |
| %2 = OpTypeVoid |
| %3 = OpTypeFunction %2 |
| %6 = OpTypeFloat 32 |
| %7 = OpTypeVector %6 2 |
| %8 = OpTypePointer Function %7 |
| %10 = OpConstant %6 1 |
| %11 = OpConstant %6 2 |
| %12 = OpConstantComposite %7 %10 %11 |
| %13 = OpTypeInt 32 0 |
| %14 = OpConstant %13 0 |
| %15 = OpTypePointer Function %6 |
| %18 = OpConstant %13 1 |
| %21 = OpTypeBool |
| %25 = OpTypeVector %6 3 |
| %26 = OpTypePointer Function %25 |
| %33 = OpConstant %6 3 |
| %34 = OpConstant %6 -0.756802499 |
| %38 = OpConstant %13 2 |
| %44 = OpTypeVector %6 4 |
| %45 = OpTypePointer Function %44 |
| %50 = OpTypeInt 32 1 |
| %51 = OpTypeVector %50 2 |
| %52 = OpTypePointer Function %51 |
| %57 = OpTypePointer Function %50 |
| %59 = OpTypeVector %13 3 |
| %60 = OpTypePointer Function %59 |
| %65 = OpConstant %13 3 |
| %67 = OpTypePointer Function %13 |
| %70 = OpTypeVector %21 4 |
| %71 = OpTypePointer Function %70 |
| %73 = OpConstantTrue %21 |
| %74 = OpTypePointer Function %21 |
| %86 = OpTypeVector %13 2 |
| %87 = OpTypePointer Function %86 |
| %93 = OpTypeVector %21 3 |
| %94 = OpTypePointer Function %93 |
| %102 = OpTypeVector %21 2 |
| %103 = OpTypePointer Function %102 |
| %111 = OpConstantFalse %21 |
| %114 = OpTypeVector %50 3 |
| %115 = OpTypePointer Function %114 |
| %117 = OpConstant %50 3 |
| %122 = OpTypeVector %50 4 |
| %123 = OpTypePointer Function %122 |
| %131 = OpTypeVector %13 4 |
| %132 = OpTypePointer Function %131 |
| %4 = OpFunction %2 None %3 |
| %5 = OpLabel |
| %9 = OpVariable %8 Function |
| %27 = OpVariable %26 Function |
| %46 = OpVariable %45 Function |
| %53 = OpVariable %52 Function |
| %61 = OpVariable %60 Function |
| %72 = OpVariable %71 Function |
| %88 = OpVariable %87 Function |
| %95 = OpVariable %94 Function |
| %104 = OpVariable %103 Function |
| %116 = OpVariable %115 Function |
| %124 = OpVariable %123 Function |
| %133 = OpVariable %132 Function |
| OpStore %9 %12 |
| %206 = OpCompositeConstruct %86 %18 %38 |
| %16 = OpAccessChain %15 %9 %14 |
| %17 = OpLoad %6 %16 |
| %19 = OpAccessChain %15 %9 %18 |
| %20 = OpLoad %6 %19 |
| %22 = OpFOrdGreaterThan %21 %17 %20 |
| OpSelectionMerge %24 None |
| OpBranchConditional %22 %23 %101 |
| %23 = OpLabel |
| %28 = OpAccessChain %15 %9 %14 |
| %29 = OpLoad %6 %28 |
| %30 = OpAccessChain %15 %9 %18 |
| %31 = OpLoad %6 %30 |
| %32 = OpFAdd %6 %29 %31 |
| %201 = OpCompositeConstruct %25 %12 %32 |
| %35 = OpCompositeConstruct %25 %32 %33 %34 |
| OpStore %27 %35 |
| %36 = OpAccessChain %15 %27 %14 |
| %37 = OpLoad %6 %36 |
| %39 = OpAccessChain %15 %27 %38 |
| %40 = OpLoad %6 %39 |
| %41 = OpFOrdLessThan %21 %37 %40 |
| OpSelectionMerge %43 None |
| OpBranchConditional %41 %42 %69 |
| %42 = OpLabel |
| %47 = OpAccessChain %15 %9 %18 |
| %48 = OpLoad %6 %47 |
| %49 = OpAccessChain %15 %46 %14 |
| OpStore %49 %48 |
| %54 = OpAccessChain %15 %27 %38 |
| %55 = OpLoad %6 %54 |
| %56 = OpConvertFToS %50 %55 |
| %58 = OpAccessChain %57 %53 %14 |
| OpStore %58 %56 |
| %62 = OpAccessChain %15 %46 %14 |
| %63 = OpLoad %6 %62 |
| %64 = OpConvertFToU %13 %63 |
| %205 = OpCompositeConstruct %122 %56 %117 %117 %117 |
| %66 = OpIAdd %13 %64 %65 |
| %204 = OpCompositeConstruct %114 %56 %117 %56 |
| %68 = OpAccessChain %67 %61 %14 |
| OpStore %68 %66 |
| OpBranch %43 |
| %69 = OpLabel |
| %202 = OpCompositeConstruct %44 %32 %32 %10 %11 |
| %209 = OpCompositeConstruct %102 %111 %41 |
| %75 = OpAccessChain %74 %72 %14 |
| OpStore %75 %73 |
| %76 = OpAccessChain %74 %72 %14 |
| %77 = OpLoad %21 %76 |
| %78 = OpLogicalNot %21 %77 |
| %79 = OpAccessChain %74 %72 %18 |
| OpStore %79 %78 |
| %80 = OpAccessChain %74 %72 %14 |
| %81 = OpLoad %21 %80 |
| %82 = OpAccessChain %74 %72 %18 |
| %83 = OpLoad %21 %82 |
| %84 = OpLogicalAnd %21 %81 %83 |
| %85 = OpAccessChain %74 %72 %38 |
| OpStore %85 %84 |
| %89 = OpAccessChain %67 %88 %14 |
| %90 = OpLoad %13 %89 |
| %91 = OpINotEqual %21 %90 %14 |
| %92 = OpAccessChain %74 %72 %65 |
| OpStore %92 %91 |
| OpBranch %43 |
| %43 = OpLabel |
| %96 = OpLoad %70 %72 |
| %97 = OpCompositeExtract %21 %96 0 |
| %98 = OpCompositeExtract %21 %96 1 |
| %99 = OpCompositeExtract %21 %96 2 |
| %100 = OpCompositeConstruct %93 %97 %98 %99 |
| %200 = OpCompositeConstruct %7 %17 %11 |
| OpStore %95 %100 |
| OpBranch %24 |
| %101 = OpLabel |
| %105 = OpAccessChain %67 %88 %14 |
| %106 = OpLoad %13 %105 |
| %107 = OpINotEqual %21 %106 %14 |
| %108 = OpCompositeConstruct %102 %107 %107 |
| %210 = OpCompositeConstruct %93 %108 %73 |
| OpStore %104 %108 |
| %211 = OpCompositeConstruct %70 %108 %108 |
| OpBranch %24 |
| %24 = OpLabel |
| %109 = OpAccessChain %74 %104 %18 |
| %110 = OpLoad %21 %109 |
| %112 = OpLogicalOr %21 %110 %111 |
| %113 = OpAccessChain %74 %104 %14 |
| OpStore %113 %112 |
| %118 = OpAccessChain %57 %116 %14 |
| OpStore %118 %117 |
| %119 = OpAccessChain %57 %116 %14 |
| %120 = OpLoad %50 %119 |
| %121 = OpAccessChain %57 %53 %18 |
| OpStore %121 %120 |
| %125 = OpAccessChain %57 %116 %14 |
| %126 = OpLoad %50 %125 |
| %127 = OpAccessChain %57 %53 %18 |
| %203 = OpCompositeConstruct %51 %126 %120 |
| %128 = OpLoad %50 %127 |
| %129 = OpIAdd %50 %126 %128 |
| %130 = OpAccessChain %57 %124 %65 |
| OpStore %130 %129 |
| %134 = OpAccessChain %57 %116 %14 |
| %135 = OpLoad %50 %134 |
| %136 = OpBitcast %13 %135 |
| %208 = OpCompositeConstruct %131 %14 %18 %136 %136 |
| %137 = OpAccessChain %67 %133 %14 |
| OpStore %137 %136 |
| %207 = OpCompositeConstruct %59 %14 %18 %136 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| |
| ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); |
| } |
| |
| TEST(TransformationCompositeConstructTest, AddSynonymsForRelevantIds) { |
| std::string shader = R"( |
| OpCapability Shader |
| %1 = OpExtInstImport "GLSL.std.450" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint Fragment %4 "main" |
| OpExecutionMode %4 OriginUpperLeft |
| OpSource ESSL 310 |
| %2 = OpTypeVoid |
| %3 = OpTypeFunction %2 |
| %6 = OpTypeFloat 32 |
| %7 = OpTypeVector %6 3 |
| %8 = OpTypePointer Function %7 |
| %10 = OpConstant %6 1 |
| %11 = OpConstantComposite %7 %10 %10 %10 |
| %17 = OpTypeVector %6 4 |
| %18 = OpTypePointer Function %17 |
| %21 = OpConstant %6 2 |
| %32 = OpTypeMatrix %17 3 |
| %33 = OpTypePointer Private %32 |
| %34 = OpVariable %33 Private |
| %35 = OpTypeMatrix %7 4 |
| %36 = OpTypePointer Private %35 |
| %37 = OpVariable %36 Private |
| %38 = OpTypeVector %6 2 |
| %39 = OpTypeInt 32 0 |
| %40 = OpConstant %39 3 |
| %41 = OpTypeArray %38 %40 |
| %42 = OpTypePointer Private %41 |
| %43 = OpVariable %42 Private |
| %100 = OpUndef %7 |
| %101 = OpUndef %17 |
| %4 = OpFunction %2 None %3 |
| %5 = OpLabel |
| %9 = OpVariable %8 Function |
| %12 = OpVariable %8 Function |
| %14 = OpVariable %8 Function |
| %19 = OpVariable %18 Function |
| %26 = OpVariable %18 Function |
| %29 = OpVariable %18 Function |
| OpStore %9 %11 |
| %13 = OpLoad %7 %9 |
| OpStore %12 %13 |
| %15 = OpLoad %7 %12 |
| %16 = OpVectorShuffle %7 %15 %15 2 1 0 |
| OpStore %14 %16 |
| %20 = OpLoad %7 %14 |
| %22 = OpCompositeExtract %6 %20 0 |
| %23 = OpCompositeExtract %6 %20 1 |
| %24 = OpCompositeExtract %6 %20 2 |
| %25 = OpCompositeConstruct %17 %22 %23 %24 %21 |
| OpStore %19 %25 |
| %27 = OpLoad %17 %19 |
| %28 = OpVectorShuffle %17 %27 %27 3 2 1 0 |
| OpStore %26 %28 |
| %30 = OpLoad %7 %9 |
| %31 = OpVectorShuffle %17 %30 %30 0 0 1 1 |
| OpStore %29 %31 |
| OpReturn |
| 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; |
| ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, |
| kConsoleMessageConsumer)); |
| TransformationContext transformation_context( |
| MakeUnique<FactManager>(context.get()), validator_options); |
| TransformationCompositeConstruct transformation( |
| 32, {25, 28, 31}, MakeInstructionDescriptor(31, spv::Op::OpReturn, 0), |
| 200); |
| ASSERT_TRUE( |
| transformation.IsApplicable(context.get(), transformation_context)); |
| ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context); |
| ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, |
| kConsoleMessageConsumer)); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(25, {}), MakeDataDescriptor(200, {0}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(28, {}), MakeDataDescriptor(200, {1}))); |
| } |
| |
| TEST(TransformationCompositeConstructTest, DontAddSynonymsForIrrelevantIds) { |
| std::string shader = R"( |
| OpCapability Shader |
| %1 = OpExtInstImport "GLSL.std.450" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint Fragment %4 "main" |
| OpExecutionMode %4 OriginUpperLeft |
| OpSource ESSL 310 |
| %2 = OpTypeVoid |
| %3 = OpTypeFunction %2 |
| %6 = OpTypeFloat 32 |
| %7 = OpTypeVector %6 3 |
| %8 = OpTypePointer Function %7 |
| %10 = OpConstant %6 1 |
| %11 = OpConstantComposite %7 %10 %10 %10 |
| %17 = OpTypeVector %6 4 |
| %18 = OpTypePointer Function %17 |
| %21 = OpConstant %6 2 |
| %32 = OpTypeMatrix %17 3 |
| %33 = OpTypePointer Private %32 |
| %34 = OpVariable %33 Private |
| %35 = OpTypeMatrix %7 4 |
| %36 = OpTypePointer Private %35 |
| %37 = OpVariable %36 Private |
| %38 = OpTypeVector %6 2 |
| %39 = OpTypeInt 32 0 |
| %40 = OpConstant %39 3 |
| %41 = OpTypeArray %38 %40 |
| %42 = OpTypePointer Private %41 |
| %43 = OpVariable %42 Private |
| %100 = OpUndef %7 |
| %101 = OpUndef %17 |
| %4 = OpFunction %2 None %3 |
| %5 = OpLabel |
| %9 = OpVariable %8 Function |
| %12 = OpVariable %8 Function |
| %14 = OpVariable %8 Function |
| %19 = OpVariable %18 Function |
| %26 = OpVariable %18 Function |
| %29 = OpVariable %18 Function |
| OpStore %9 %11 |
| %13 = OpLoad %7 %9 |
| OpStore %12 %13 |
| %15 = OpLoad %7 %12 |
| %16 = OpVectorShuffle %7 %15 %15 2 1 0 |
| OpStore %14 %16 |
| %20 = OpLoad %7 %14 |
| %22 = OpCompositeExtract %6 %20 0 |
| %23 = OpCompositeExtract %6 %20 1 |
| %24 = OpCompositeExtract %6 %20 2 |
| %25 = OpCompositeConstruct %17 %22 %23 %24 %21 |
| OpStore %19 %25 |
| %27 = OpLoad %17 %19 |
| %28 = OpVectorShuffle %17 %27 %27 3 2 1 0 |
| OpStore %26 %28 |
| %30 = OpLoad %7 %9 |
| %31 = OpVectorShuffle %17 %30 %30 0 0 1 1 |
| OpStore %29 %31 |
| OpReturn |
| 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; |
| ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, |
| kConsoleMessageConsumer)); |
| TransformationContext transformation_context( |
| MakeUnique<FactManager>(context.get()), validator_options); |
| transformation_context.GetFactManager()->AddFactIdIsIrrelevant(25); |
| |
| TransformationCompositeConstruct transformation( |
| 32, {25, 28, 31}, MakeInstructionDescriptor(31, spv::Op::OpReturn, 0), |
| 200); |
| ASSERT_TRUE( |
| transformation.IsApplicable(context.get(), transformation_context)); |
| ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context); |
| ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, |
| kConsoleMessageConsumer)); |
| ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(25, {}), MakeDataDescriptor(200, {0}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(28, {}), MakeDataDescriptor(200, {1}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(31, {}), MakeDataDescriptor(200, {2}))); |
| } |
| |
| TEST(TransformationCompositeConstructTest, DontAddSynonymsInDeadBlock) { |
| std::string shader = R"( |
| OpCapability Shader |
| %1 = OpExtInstImport "GLSL.std.450" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint Fragment %4 "main" |
| OpExecutionMode %4 OriginUpperLeft |
| OpSource ESSL 320 |
| %2 = OpTypeVoid |
| %3 = OpTypeFunction %2 |
| %6 = OpTypeInt 32 1 |
| %7 = OpTypeVector %6 2 |
| %8 = OpTypePointer Function %7 |
| %10 = OpConstant %6 0 |
| %11 = OpConstant %6 1 |
| %12 = OpConstantComposite %7 %10 %11 |
| %13 = OpTypeBool |
| %14 = OpConstantFalse %13 |
| %4 = OpFunction %2 None %3 |
| %5 = OpLabel |
| %9 = OpVariable %8 Function |
| OpStore %9 %12 |
| OpSelectionMerge %16 None |
| OpBranchConditional %14 %15 %16 |
| %15 = OpLabel |
| OpBranch %16 |
| %16 = OpLabel |
| OpReturn |
| 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; |
| ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, |
| kConsoleMessageConsumer)); |
| TransformationContext transformation_context( |
| MakeUnique<FactManager>(context.get()), validator_options); |
| transformation_context.GetFactManager()->AddFactBlockIsDead(15); |
| |
| TransformationCompositeConstruct transformation( |
| 7, {10, 11}, MakeInstructionDescriptor(15, spv::Op::OpBranch, 0), 100); |
| ASSERT_TRUE( |
| transformation.IsApplicable(context.get(), transformation_context)); |
| ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context); |
| ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(100, {0}), MakeDataDescriptor(10, {}))); |
| ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(100, {1}), MakeDataDescriptor(11, {}))); |
| } |
| |
| TEST(TransformationCompositeConstructTest, OneIrrelevantComponent) { |
| std::string shader = R"( |
| OpCapability Shader |
| %1 = OpExtInstImport "GLSL.std.450" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint Fragment %4 "main" |
| OpExecutionMode %4 OriginUpperLeft |
| OpSource ESSL 320 |
| %2 = OpTypeVoid |
| %3 = OpTypeFunction %2 |
| %6 = OpTypeInt 32 1 |
| %7 = OpTypeStruct %6 %6 %6 |
| %8 = OpConstant %6 42 |
| %9 = OpConstant %6 50 |
| %10 = OpConstant %6 51 |
| %4 = OpFunction %2 None %3 |
| %5 = OpLabel |
| OpReturn |
| 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; |
| ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, |
| kConsoleMessageConsumer)); |
| TransformationContext transformation_context( |
| MakeUnique<FactManager>(context.get()), validator_options); |
| transformation_context.GetFactManager()->AddFactIdIsIrrelevant(8); |
| |
| TransformationCompositeConstruct transformation( |
| 7, {8, 9, 10}, MakeInstructionDescriptor(5, spv::Op::OpReturn, 0), 100); |
| ASSERT_TRUE( |
| transformation.IsApplicable(context.get(), transformation_context)); |
| ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context); |
| ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(100, {0}), MakeDataDescriptor(8, {}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(100, {1}), MakeDataDescriptor(9, {}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(100, {2}), MakeDataDescriptor(10, {}))); |
| } |
| |
| TEST(TransformationCompositeConstructTest, IrrelevantVec2ThenFloat) { |
| std::string shader = R"( |
| OpCapability Shader |
| %1 = OpExtInstImport "GLSL.std.450" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint Fragment %4 "main" |
| OpExecutionMode %4 OriginUpperLeft |
| OpSource ESSL 320 |
| %2 = OpTypeVoid |
| %3 = OpTypeFunction %2 |
| %6 = OpTypeFloat 32 |
| %7 = OpTypeVector %6 2 |
| %8 = OpTypeVector %6 3 |
| %9 = OpConstant %6 0 |
| %11 = OpConstant %6 1 |
| %12 = OpConstant %6 2 |
| %10 = OpConstantComposite %7 %11 %12 |
| %4 = OpFunction %2 None %3 |
| %5 = OpLabel |
| OpReturn |
| 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; |
| ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, |
| kConsoleMessageConsumer)); |
| TransformationContext transformation_context( |
| MakeUnique<FactManager>(context.get()), validator_options); |
| |
| transformation_context.GetFactManager()->AddFactIdIsIrrelevant(10); |
| |
| TransformationCompositeConstruct transformation( |
| 8, {10, 9}, MakeInstructionDescriptor(5, spv::Op::OpReturn, 0), 100); |
| ASSERT_TRUE( |
| transformation.IsApplicable(context.get(), transformation_context)); |
| ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context); |
| ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(100, {0}), MakeDataDescriptor(10, {0}))); |
| ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(100, {1}), MakeDataDescriptor(10, {1}))); |
| ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(100, {2}), MakeDataDescriptor(9, {}))); |
| ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous( |
| MakeDataDescriptor(100, {1}), MakeDataDescriptor(9, {}))); |
| } |
| |
| } // namespace |
| } // namespace fuzz |
| } // namespace spvtools |