// 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_wrap_vector_synonym.h" #include "gtest/gtest.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(TransformationWrapVectorSynonym, BasicTest) { std::string shader = R"( OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %4 "main" %97 OpExecutionMode %4 OriginUpperLeft OpSource ESSL 310 OpName %4 "main" %2 = OpTypeVoid %3 = OpTypeFunction %2 %6 = OpTypeInt 32 1 %7 = OpTypePointer Function %6 %9 = OpConstant %6 10 %11 = OpConstant %6 -5 %12 = OpTypeVector %6 2 %13 = OpTypePointer Function %12 %18 = OpTypeInt 32 0 %19 = OpTypePointer Function %18 %21 = OpConstant %18 8 %23 = OpConstant %18 2 %24 = OpTypeVector %18 3 %25 = OpTypePointer Function %24 %31 = OpTypeFloat 32 %32 = OpTypePointer Function %31 %34 = OpConstant %31 3.29999995 %36 = OpConstant %31 1.10000002 %37 = OpTypeVector %31 4 %38 = OpTypePointer Function %37 %96 = OpTypePointer Input %31 %97 = OpVariable %96 Input %4 = OpFunction %2 None %3 %5 = OpLabel %8 = OpVariable %7 Function %10 = OpVariable %7 Function %14 = OpVariable %13 Function %20 = OpVariable %19 Function %22 = OpVariable %19 Function %26 = OpVariable %25 Function %33 = OpVariable %32 Function %35 = OpVariable %32 Function %39 = OpVariable %38 Function %47 = OpVariable %7 Function %51 = OpVariable %7 Function %55 = OpVariable %7 Function %59 = OpVariable %7 Function %63 = OpVariable %19 Function %67 = OpVariable %19 Function %71 = OpVariable %19 Function %75 = OpVariable %19 Function %79 = OpVariable %32 Function %83 = OpVariable %32 Function %87 = OpVariable %32 Function %91 = OpVariable %32 Function OpStore %8 %9 OpStore %10 %11 %15 = OpLoad %6 %8 %16 = OpLoad %6 %10 %17 = OpCompositeConstruct %12 %15 %16 OpStore %14 %17 OpStore %20 %21 OpStore %22 %23 %27 = OpLoad %18 %20 %28 = OpLoad %18 %20 %29 = OpLoad %18 %22 %30 = OpCompositeConstruct %24 %27 %28 %29 OpStore %26 %30 OpStore %33 %34 OpStore %35 %36 %40 = OpLoad %31 %33 %41 = OpLoad %31 %33 %42 = OpLoad %31 %35 %43 = OpLoad %31 %35 %44 = OpCompositeConstruct %37 %40 %41 %42 %43 %45 = OpLoad %37 %39 %46 = OpVectorShuffle %37 %45 %44 5 6 7 4 OpStore %39 %46 %48 = OpLoad %6 %8 %49 = OpLoad %6 %10 %100 = OpCompositeConstruct %12 %48 %48 %101 = OpCompositeConstruct %12 %49 %49 %50 = OpIAdd %6 %48 %49 OpStore %47 %50 %52 = OpLoad %6 %8 %53 = OpLoad %6 %10 %54 = OpISub %6 %52 %53 OpStore %51 %54 %56 = OpLoad %6 %8 %57 = OpLoad %6 %10 %58 = OpIMul %6 %56 %57 OpStore %55 %58 %60 = OpLoad %6 %8 %61 = OpLoad %6 %10 %62 = OpSDiv %6 %60 %61 OpStore %59 %62 %64 = OpLoad %18 %20 %65 = OpLoad %18 %22 %66 = OpIAdd %18 %64 %65 OpStore %63 %66 %68 = OpLoad %18 %20 %69 = OpLoad %18 %22 %70 = OpISub %18 %68 %69 OpStore %67 %70 %72 = OpLoad %18 %20 %73 = OpLoad %18 %22 %74 = OpIMul %18 %72 %73 OpStore %71 %74 %76 = OpLoad %18 %20 %77 = OpLoad %18 %22 %78 = OpUDiv %18 %76 %77 OpStore %75 %78 %80 = OpLoad %31 %33 %81 = OpLoad %31 %35 %82 = OpFAdd %31 %80 %81 OpStore %79 %82 %84 = OpLoad %31 %33 %85 = OpLoad %31 %35 %86 = OpFSub %31 %84 %85 OpStore %83 %86 %88 = OpLoad %31 %33 %89 = OpLoad %31 %35 %90 = OpFMul %31 %88 %89 OpStore %87 %90 %92 = OpLoad %31 %33 %93 = OpLoad %31 %35 %94 = OpFDiv %31 %92 %93 OpStore %91 %94 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; // Check context validity. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, kConsoleMessageConsumer)); TransformationContext transformation_context( MakeUnique(context.get()), validator_options); // Vec Type Id | Vector Type | Element Type id | Element Type | // ------------+----------------+------------------+-----------------+ // 12 | vec2 | 6 | int32 | // 24 | vec3 | 18 | uint32 | // 37 | vec4 | 31 | float | // Instruction Id | Opcode | Type Id | constant id 1 | constant id 2 | // ---------------+---------+---------+---------------+---------------+ // 50 | OpIAdd | 6 | 48 | 49 | // 54 | OpISub | 6 | 52 | 53 | // 58 | OpIMul | 6 | 56 | 57 | // 62 | OpSDiv | 6 | 60 | 61 | // 66 | OpIAdd | 18 | 64 | 65 | // 70 | OpISub | 18 | 68 | 69 | // 74 | OpIMul | 18 | 72 | 73 | // 78 | OpUDiv | 18 | 76 | 77 | // 82 | OpFAdd | 31 | 80 | 81 | // 86 | OpFSub | 31 | 84 | 85 | // 90 | OpFMul | 31 | 88 | 89 | // 94 | OpFDiv | 31 | 92 | 93 | // Assert that the target scalar instruction result id is relevant. ASSERT_FALSE(transformation_context.GetFactManager()->IdIsIrrelevant(50)); transformation_context.GetFactManager()->AddFactDataSynonym( MakeDataDescriptor(100, {1}), MakeDataDescriptor(48, {})); transformation_context.GetFactManager()->AddFactDataSynonym( MakeDataDescriptor(101, {1}), MakeDataDescriptor(49, {})); // The following are all invalid use. { // Bad: Instruction id does not exist. TransformationWrapVectorSynonym wrap_add_int_bad1(103, 100, 101, 102, 1); ASSERT_FALSE( wrap_add_int_bad1.IsApplicable(context.get(), transformation_context)); // Bad: Instruction id given is not of a valid arithmetic operation typed // instruction. TransformationWrapVectorSynonym wrap_add_int_bad2(80, 100, 101, 102, 1); ASSERT_FALSE( wrap_add_int_bad1.IsApplicable(context.get(), transformation_context)); // Bad: the id for the first vector does not exist. TransformationWrapVectorSynonym wrap_add_int_bad3(50, 105, 101, 102, 1); ASSERT_FALSE( wrap_add_int_bad3.IsApplicable(context.get(), transformation_context)); // Bad: the id for the second vector does not exist. TransformationWrapVectorSynonym wrap_add_int_bad4(50, 100, 105, 102, 1); ASSERT_FALSE( wrap_add_int_bad4.IsApplicable(context.get(), transformation_context)); // Bad: vector id is not fresh. TransformationWrapVectorSynonym wrap_add_int_bad6(50, 100, 101, 94, 1); ASSERT_FALSE( wrap_add_int_bad6.IsApplicable(context.get(), transformation_context)); // Bad: The position goes out of bound for the given vector type. TransformationWrapVectorSynonym wrap_add_int_bad8(50, 100, 101, 102, 2); ASSERT_FALSE( wrap_add_int_bad8.IsApplicable(context.get(), transformation_context)); // Bad: The original instruction is not a valid scalar operation // instruction. TransformationWrapVectorSynonym wrap_add_int(27, 100, 101, 102, 1); ASSERT_FALSE( wrap_add_int.IsApplicable(context.get(), transformation_context)); } // Good: The following transformation should be applicable. TransformationWrapVectorSynonym wrap_add_int(50, 100, 101, 102, 1); ASSERT_TRUE(wrap_add_int.IsApplicable(context.get(), transformation_context)); // Insert an arithmetic instruction of the same type to add two vectors. ApplyAndCheckFreshIds(wrap_add_int, context.get(), &transformation_context); // |instruction_id| and id at |scalar_position of the result vector should be // synonyms. ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( MakeDataDescriptor(102, {1}), MakeDataDescriptor(50, {}))); // After applying transformations, the instruction: // // %102 = OpIAdd %12 %100 %101 // // should be added before: // // %50 = OpIAdd %6 %48 %49 std::string after_transformation = R"( OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %4 "main" %97 OpExecutionMode %4 OriginUpperLeft OpSource ESSL 310 OpName %4 "main" %2 = OpTypeVoid %3 = OpTypeFunction %2 %6 = OpTypeInt 32 1 %7 = OpTypePointer Function %6 %9 = OpConstant %6 10 %11 = OpConstant %6 -5 %12 = OpTypeVector %6 2 %13 = OpTypePointer Function %12 %18 = OpTypeInt 32 0 %19 = OpTypePointer Function %18 %21 = OpConstant %18 8 %23 = OpConstant %18 2 %24 = OpTypeVector %18 3 %25 = OpTypePointer Function %24 %31 = OpTypeFloat 32 %32 = OpTypePointer Function %31 %34 = OpConstant %31 3.29999995 %36 = OpConstant %31 1.10000002 %37 = OpTypeVector %31 4 %38 = OpTypePointer Function %37 %96 = OpTypePointer Input %31 %97 = OpVariable %96 Input %4 = OpFunction %2 None %3 %5 = OpLabel %8 = OpVariable %7 Function %10 = OpVariable %7 Function %14 = OpVariable %13 Function %20 = OpVariable %19 Function %22 = OpVariable %19 Function %26 = OpVariable %25 Function %33 = OpVariable %32 Function %35 = OpVariable %32 Function %39 = OpVariable %38 Function %47 = OpVariable %7 Function %51 = OpVariable %7 Function %55 = OpVariable %7 Function %59 = OpVariable %7 Function %63 = OpVariable %19 Function %67 = OpVariable %19 Function %71 = OpVariable %19 Function %75 = OpVariable %19 Function %79 = OpVariable %32 Function %83 = OpVariable %32 Function %87 = OpVariable %32 Function %91 = OpVariable %32 Function OpStore %8 %9 OpStore %10 %11 %15 = OpLoad %6 %8 %16 = OpLoad %6 %10 %17 = OpCompositeConstruct %12 %15 %16 OpStore %14 %17 OpStore %20 %21 OpStore %22 %23 %27 = OpLoad %18 %20 %28 = OpLoad %18 %20 %29 = OpLoad %18 %22 %30 = OpCompositeConstruct %24 %27 %28 %29 OpStore %26 %30 OpStore %33 %34 OpStore %35 %36 %40 = OpLoad %31 %33 %41 = OpLoad %31 %33 %42 = OpLoad %31 %35 %43 = OpLoad %31 %35 %44 = OpCompositeConstruct %37 %40 %41 %42 %43 %45 = OpLoad %37 %39 %46 = OpVectorShuffle %37 %45 %44 5 6 7 4 OpStore %39 %46 %48 = OpLoad %6 %8 %49 = OpLoad %6 %10 %100 = OpCompositeConstruct %12 %48 %48 %101 = OpCompositeConstruct %12 %49 %49 %102 = OpIAdd %12 %100 %101 %50 = OpIAdd %6 %48 %49 OpStore %47 %50 %52 = OpLoad %6 %8 %53 = OpLoad %6 %10 %54 = OpISub %6 %52 %53 OpStore %51 %54 %56 = OpLoad %6 %8 %57 = OpLoad %6 %10 %58 = OpIMul %6 %56 %57 OpStore %55 %58 %60 = OpLoad %6 %8 %61 = OpLoad %6 %10 %62 = OpSDiv %6 %60 %61 OpStore %59 %62 %64 = OpLoad %18 %20 %65 = OpLoad %18 %22 %66 = OpIAdd %18 %64 %65 OpStore %63 %66 %68 = OpLoad %18 %20 %69 = OpLoad %18 %22 %70 = OpISub %18 %68 %69 OpStore %67 %70 %72 = OpLoad %18 %20 %73 = OpLoad %18 %22 %74 = OpIMul %18 %72 %73 OpStore %71 %74 %76 = OpLoad %18 %20 %77 = OpLoad %18 %22 %78 = OpUDiv %18 %76 %77 OpStore %75 %78 %80 = OpLoad %31 %33 %81 = OpLoad %31 %35 %82 = OpFAdd %31 %80 %81 OpStore %79 %82 %84 = OpLoad %31 %33 %85 = OpLoad %31 %35 %86 = OpFSub %31 %84 %85 OpStore %83 %86 %88 = OpLoad %31 %33 %89 = OpLoad %31 %35 %90 = OpFMul %31 %88 %89 OpStore %87 %90 %92 = OpLoad %31 %33 %93 = OpLoad %31 %35 %94 = OpFDiv %31 %92 %93 OpStore %91 %94 OpReturn OpFunctionEnd )"; ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); } TEST(TransformationWrapVectorSynonym, OperationSupportTest) { std::string shader = R"( OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %4 "main" %97 OpExecutionMode %4 OriginUpperLeft OpSource ESSL 310 OpName %4 "main" %2 = OpTypeVoid %3 = OpTypeFunction %2 %6 = OpTypeInt 32 1 %7 = OpTypePointer Function %6 %9 = OpConstant %6 10 %11 = OpConstant %6 -5 %12 = OpTypeVector %6 2 %13 = OpTypePointer Function %12 %18 = OpTypeInt 32 0 %19 = OpTypePointer Function %18 %21 = OpConstant %18 8 %23 = OpConstant %18 2 %24 = OpTypeVector %18 3 %25 = OpTypePointer Function %24 %31 = OpTypeFloat 32 %32 = OpTypePointer Function %31 %34 = OpConstant %31 3.29999995 %36 = OpConstant %31 1.10000002 %37 = OpTypeVector %31 4 %38 = OpTypePointer Function %37 %96 = OpTypePointer Input %31 %97 = OpVariable %96 Input %4 = OpFunction %2 None %3 %5 = OpLabel %8 = OpVariable %7 Function %10 = OpVariable %7 Function %14 = OpVariable %13 Function %20 = OpVariable %19 Function %22 = OpVariable %19 Function %26 = OpVariable %25 Function %33 = OpVariable %32 Function %35 = OpVariable %32 Function %39 = OpVariable %38 Function %47 = OpVariable %7 Function %51 = OpVariable %7 Function %55 = OpVariable %7 Function %59 = OpVariable %7 Function %63 = OpVariable %19 Function %67 = OpVariable %19 Function %71 = OpVariable %19 Function %75 = OpVariable %19 Function %79 = OpVariable %32 Function %83 = OpVariable %32 Function %87 = OpVariable %32 Function %91 = OpVariable %32 Function OpStore %8 %9 OpStore %10 %11 %15 = OpLoad %6 %8 %16 = OpLoad %6 %10 %17 = OpCompositeConstruct %12 %15 %16 OpStore %14 %17 OpStore %20 %21 OpStore %22 %23 %27 = OpLoad %18 %20 %28 = OpLoad %18 %20 %29 = OpLoad %18 %22 %30 = OpCompositeConstruct %24 %27 %28 %29 OpStore %26 %30 OpStore %33 %34 OpStore %35 %36 %40 = OpLoad %31 %33 %41 = OpLoad %31 %33 %42 = OpLoad %31 %35 %43 = OpLoad %31 %35 %44 = OpCompositeConstruct %37 %40 %41 %42 %43 %45 = OpLoad %37 %39 %46 = OpVectorShuffle %37 %45 %44 5 6 7 4 OpStore %39 %46 %48 = OpLoad %6 %8 %49 = OpLoad %6 %10 %50 = OpIAdd %6 %48 %49 OpStore %47 %50 %52 = OpLoad %6 %8 %53 = OpLoad %6 %10 %100 = OpCompositeConstruct %12 %52 %52 %101 = OpCompositeConstruct %12 %53 %53 %54 = OpISub %6 %52 %53 OpStore %51 %54 %56 = OpLoad %6 %8 %57 = OpLoad %6 %10 %103 = OpCompositeConstruct %12 %56 %56 %104 = OpCompositeConstruct %12 %57 %57 %58 = OpIMul %6 %56 %57 OpStore %55 %58 %60 = OpLoad %6 %8 %61 = OpLoad %6 %10 %62 = OpSDiv %6 %60 %61 OpStore %59 %62 %64 = OpLoad %18 %20 %65 = OpLoad %18 %22 %106 = OpCompositeConstruct %24 %64 %64 %64 %107 = OpCompositeConstruct %24 %65 %65 %65 %66 = OpIAdd %18 %64 %65 OpStore %63 %66 %68 = OpLoad %18 %20 %69 = OpLoad %18 %22 %109 = OpCompositeConstruct %24 %68 %68 %68 %110 = OpCompositeConstruct %24 %69 %69 %69 %70 = OpISub %18 %68 %69 OpStore %67 %70 %72 = OpLoad %18 %20 %73 = OpLoad %18 %22 %112 = OpCompositeConstruct %24 %72 %72 %72 %113 = OpCompositeConstruct %24 %73 %73 %73 %74 = OpIMul %18 %72 %73 OpStore %71 %74 %76 = OpLoad %18 %20 %77 = OpLoad %18 %22 %78 = OpUDiv %18 %76 %77 OpStore %75 %78 %80 = OpLoad %31 %33 %81 = OpLoad %31 %35 %115 = OpCompositeConstruct %37 %80 %80 %80 %80 %116 = OpCompositeConstruct %37 %81 %81 %81 %81 %82 = OpFAdd %31 %80 %81 OpStore %79 %82 %84 = OpLoad %31 %33 %85 = OpLoad %31 %35 %118 = OpCompositeConstruct %37 %84 %84 %84 %84 %119 = OpCompositeConstruct %37 %85 %85 %85 %85 %86 = OpFSub %31 %84 %85 OpStore %83 %86 %88 = OpLoad %31 %33 %89 = OpLoad %31 %35 %121 = OpCompositeConstruct %37 %88 %88 %88 %88 %122 = OpCompositeConstruct %37 %89 %89 %89 %89 %90 = OpFMul %31 %88 %89 OpStore %87 %90 %92 = OpLoad %31 %33 %93 = OpLoad %31 %35 %94 = OpFDiv %31 %92 %93 OpStore %91 %94 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(context.get()), validator_options); { // Add synonym facts between the vector operands at pos and the operands to // the scalar instruction. transformation_context.GetFactManager()->AddFactDataSynonym( MakeDataDescriptor(100, {1}), MakeDataDescriptor(52, {})); transformation_context.GetFactManager()->AddFactDataSynonym( MakeDataDescriptor(101, {1}), MakeDataDescriptor(53, {})); transformation_context.GetFactManager()->AddFactDataSynonym( MakeDataDescriptor(103, {0}), MakeDataDescriptor(56, {})); transformation_context.GetFactManager()->AddFactDataSynonym( MakeDataDescriptor(104, {0}), MakeDataDescriptor(57, {})); transformation_context.GetFactManager()->AddFactDataSynonym( MakeDataDescriptor(106, {2}), MakeDataDescriptor(64, {})); transformation_context.GetFactManager()->AddFactDataSynonym( MakeDataDescriptor(107, {2}), MakeDataDescriptor(65, {})); transformation_context.GetFactManager()->AddFactDataSynonym( MakeDataDescriptor(109, {2}), MakeDataDescriptor(68, {})); transformation_context.GetFactManager()->AddFactDataSynonym( MakeDataDescriptor(110, {2}), MakeDataDescriptor(69, {})); transformation_context.GetFactManager()->AddFactDataSynonym( MakeDataDescriptor(112, {1}), MakeDataDescriptor(72, {})); transformation_context.GetFactManager()->AddFactDataSynonym( MakeDataDescriptor(113, {1}), MakeDataDescriptor(73, {})); transformation_context.GetFactManager()->AddFactDataSynonym( MakeDataDescriptor(115, {2}), MakeDataDescriptor(80, {})); transformation_context.GetFactManager()->AddFactDataSynonym( MakeDataDescriptor(116, {2}), MakeDataDescriptor(81, {})); transformation_context.GetFactManager()->AddFactDataSynonym( MakeDataDescriptor(118, {3}), MakeDataDescriptor(84, {})); transformation_context.GetFactManager()->AddFactDataSynonym( MakeDataDescriptor(119, {3}), MakeDataDescriptor(85, {})); transformation_context.GetFactManager()->AddFactDataSynonym( MakeDataDescriptor(121, {1}), MakeDataDescriptor(88, {})); transformation_context.GetFactManager()->AddFactDataSynonym( MakeDataDescriptor(122, {1}), MakeDataDescriptor(89, {})); } // Test OpISub for signed integer. { // Good: The following transformation should be applicable. TransformationWrapVectorSynonym wrap_sub_int(54, 100, 101, 102, 1); ASSERT_TRUE( wrap_sub_int.IsApplicable(context.get(), transformation_context)); ApplyAndCheckFreshIds(wrap_sub_int, context.get(), &transformation_context); // |instruction_id| and id at |scalar_position of the result vector should // be synonyms. ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( MakeDataDescriptor(102, {1}), MakeDataDescriptor(54, {}))); } // Test OpIMul for signed integer. { // Good: The following transformation should be applicable. TransformationWrapVectorSynonym wrap_mul_int(58, 103, 104, 105, 0); ASSERT_TRUE( wrap_mul_int.IsApplicable(context.get(), transformation_context)); ApplyAndCheckFreshIds(wrap_mul_int, context.get(), &transformation_context); // |instruction_id| and id at |scalar_position of the result vector should // be synonyms. ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( MakeDataDescriptor(105, {0}), MakeDataDescriptor(58, {}))); } // Test OpIAdd for unsigned integer. { // Good: The following transformation should be applicable. TransformationWrapVectorSynonym wrap_add_uint(66, 106, 107, 108, 2); ASSERT_TRUE( wrap_add_uint.IsApplicable(context.get(), transformation_context)); ApplyAndCheckFreshIds(wrap_add_uint, context.get(), &transformation_context); // |instruction_id| and id at |scalar_position of the result vector should // be synonyms. ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( MakeDataDescriptor(108, {2}), MakeDataDescriptor(66, {}))); } // Test OpISub for signed integer. { // Good: The following transformation should be applicable. TransformationWrapVectorSynonym wrap_sub_uint(70, 109, 110, 111, 2); ASSERT_TRUE( wrap_sub_uint.IsApplicable(context.get(), transformation_context)); ApplyAndCheckFreshIds(wrap_sub_uint, context.get(), &transformation_context); // |instruction_id| and id at |scalar_position of the result vector should // be synonyms. ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( MakeDataDescriptor(111, {2}), MakeDataDescriptor(70, {}))); } // Test OpIMul for signed integer. { // Good: The following transformation should be applicable. TransformationWrapVectorSynonym wrap_mul_uint(74, 112, 113, 114, 1); ASSERT_TRUE( wrap_mul_uint.IsApplicable(context.get(), transformation_context)); ApplyAndCheckFreshIds(wrap_mul_uint, context.get(), &transformation_context); // |instruction_id| and id at |scalar_position of the result vector should // be synonyms. ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( MakeDataDescriptor(114, {1}), MakeDataDescriptor(74, {}))); } // Test OpFAdd for float. { // Good: The following transformation should be applicable. TransformationWrapVectorSynonym wrap_add_float(82, 115, 116, 117, 2); ASSERT_TRUE( wrap_add_float.IsApplicable(context.get(), transformation_context)); ApplyAndCheckFreshIds(wrap_add_float, context.get(), &transformation_context); // |instruction_id| and id at |scalar_position of the result vector should // be synonyms. ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( MakeDataDescriptor(117, {2}), MakeDataDescriptor(82, {}))); } // Test OpFSub for float. { // Good: The following transformation should be applicable. TransformationWrapVectorSynonym wrap_add_float(86, 118, 119, 120, 3); ASSERT_TRUE( wrap_add_float.IsApplicable(context.get(), transformation_context)); ApplyAndCheckFreshIds(wrap_add_float, context.get(), &transformation_context); // |instruction_id| and id at |scalar_position of the result vector should // be synonyms. ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( MakeDataDescriptor(120, {3}), MakeDataDescriptor(86, {}))); } // Test OpFMul for float. { // Good: The following transformation should be applicable. TransformationWrapVectorSynonym wrap_mul_float(90, 121, 122, 123, 1); ASSERT_TRUE( wrap_mul_float.IsApplicable(context.get(), transformation_context)); ApplyAndCheckFreshIds(wrap_mul_float, context.get(), &transformation_context); // |instruction_id| and id at |scalar_position of the result vector should // be synonyms. ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( MakeDataDescriptor(123, {1}), MakeDataDescriptor(90, {}))); } std::string after_transformation = R"( OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %4 "main" %97 OpExecutionMode %4 OriginUpperLeft OpSource ESSL 310 OpName %4 "main" %2 = OpTypeVoid %3 = OpTypeFunction %2 %6 = OpTypeInt 32 1 %7 = OpTypePointer Function %6 %9 = OpConstant %6 10 %11 = OpConstant %6 -5 %12 = OpTypeVector %6 2 %13 = OpTypePointer Function %12 %18 = OpTypeInt 32 0 %19 = OpTypePointer Function %18 %21 = OpConstant %18 8 %23 = OpConstant %18 2 %24 = OpTypeVector %18 3 %25 = OpTypePointer Function %24 %31 = OpTypeFloat 32 %32 = OpTypePointer Function %31 %34 = OpConstant %31 3.29999995 %36 = OpConstant %31 1.10000002 %37 = OpTypeVector %31 4 %38 = OpTypePointer Function %37 %96 = OpTypePointer Input %31 %97 = OpVariable %96 Input %4 = OpFunction %2 None %3 %5 = OpLabel %8 = OpVariable %7 Function %10 = OpVariable %7 Function %14 = OpVariable %13 Function %20 = OpVariable %19 Function %22 = OpVariable %19 Function %26 = OpVariable %25 Function %33 = OpVariable %32 Function %35 = OpVariable %32 Function %39 = OpVariable %38 Function %47 = OpVariable %7 Function %51 = OpVariable %7 Function %55 = OpVariable %7 Function %59 = OpVariable %7 Function %63 = OpVariable %19 Function %67 = OpVariable %19 Function %71 = OpVariable %19 Function %75 = OpVariable %19 Function %79 = OpVariable %32 Function %83 = OpVariable %32 Function %87 = OpVariable %32 Function %91 = OpVariable %32 Function OpStore %8 %9 OpStore %10 %11 %15 = OpLoad %6 %8 %16 = OpLoad %6 %10 %17 = OpCompositeConstruct %12 %15 %16 OpStore %14 %17 OpStore %20 %21 OpStore %22 %23 %27 = OpLoad %18 %20 %28 = OpLoad %18 %20 %29 = OpLoad %18 %22 %30 = OpCompositeConstruct %24 %27 %28 %29 OpStore %26 %30 OpStore %33 %34 OpStore %35 %36 %40 = OpLoad %31 %33 %41 = OpLoad %31 %33 %42 = OpLoad %31 %35 %43 = OpLoad %31 %35 %44 = OpCompositeConstruct %37 %40 %41 %42 %43 %45 = OpLoad %37 %39 %46 = OpVectorShuffle %37 %45 %44 5 6 7 4 OpStore %39 %46 %48 = OpLoad %6 %8 %49 = OpLoad %6 %10 %50 = OpIAdd %6 %48 %49 OpStore %47 %50 %52 = OpLoad %6 %8 %53 = OpLoad %6 %10 %100 = OpCompositeConstruct %12 %52 %52 %101 = OpCompositeConstruct %12 %53 %53 %102 = OpISub %12 %100 %101 %54 = OpISub %6 %52 %53 OpStore %51 %54 %56 = OpLoad %6 %8 %57 = OpLoad %6 %10 %103 = OpCompositeConstruct %12 %56 %56 %104 = OpCompositeConstruct %12 %57 %57 %105 = OpIMul %12 %103 %104 %58 = OpIMul %6 %56 %57 OpStore %55 %58 %60 = OpLoad %6 %8 %61 = OpLoad %6 %10 %62 = OpSDiv %6 %60 %61 OpStore %59 %62 %64 = OpLoad %18 %20 %65 = OpLoad %18 %22 %106 = OpCompositeConstruct %24 %64 %64 %64 %107 = OpCompositeConstruct %24 %65 %65 %65 %108 = OpIAdd %24 %106 %107 %66 = OpIAdd %18 %64 %65 OpStore %63 %66 %68 = OpLoad %18 %20 %69 = OpLoad %18 %22 %109 = OpCompositeConstruct %24 %68 %68 %68 %110 = OpCompositeConstruct %24 %69 %69 %69 %111 = OpISub %24 %109 %110 %70 = OpISub %18 %68 %69 OpStore %67 %70 %72 = OpLoad %18 %20 %73 = OpLoad %18 %22 %112 = OpCompositeConstruct %24 %72 %72 %72 %113 = OpCompositeConstruct %24 %73 %73 %73 %114 = OpIMul %24 %112 %113 %74 = OpIMul %18 %72 %73 OpStore %71 %74 %76 = OpLoad %18 %20 %77 = OpLoad %18 %22 %78 = OpUDiv %18 %76 %77 OpStore %75 %78 %80 = OpLoad %31 %33 %81 = OpLoad %31 %35 %115 = OpCompositeConstruct %37 %80 %80 %80 %80 %116 = OpCompositeConstruct %37 %81 %81 %81 %81 %117 = OpFAdd %37 %115 %116 %82 = OpFAdd %31 %80 %81 OpStore %79 %82 %84 = OpLoad %31 %33 %85 = OpLoad %31 %35 %118 = OpCompositeConstruct %37 %84 %84 %84 %84 %119 = OpCompositeConstruct %37 %85 %85 %85 %85 %120 = OpFSub %37 %118 %119 %86 = OpFSub %31 %84 %85 OpStore %83 %86 %88 = OpLoad %31 %33 %89 = OpLoad %31 %35 %121 = OpCompositeConstruct %37 %88 %88 %88 %88 %122 = OpCompositeConstruct %37 %89 %89 %89 %89 %123 = OpFMul %37 %121 %122 %90 = OpFMul %31 %88 %89 OpStore %87 %90 %92 = OpLoad %31 %33 %93 = OpLoad %31 %35 %94 = OpFDiv %31 %92 %93 OpStore %91 %94 OpReturn OpFunctionEnd )"; ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); } TEST(TransformationWrapVectorSynonym, DivSupportTest) { std::string shader = R"( OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %4 "main" %97 OpExecutionMode %4 OriginUpperLeft OpSource ESSL 310 OpName %4 "main" %2 = OpTypeVoid %3 = OpTypeFunction %2 %6 = OpTypeInt 32 1 %7 = OpTypePointer Function %6 %9 = OpConstant %6 10 %11 = OpConstant %6 -5 %12 = OpTypeVector %6 2 %13 = OpTypePointer Function %12 %18 = OpTypeInt 32 0 %19 = OpTypePointer Function %18 %21 = OpConstant %18 8 %23 = OpConstant %18 2 %24 = OpTypeVector %18 3 %25 = OpTypePointer Function %24 %31 = OpTypeFloat 32 %32 = OpTypePointer Function %31 %34 = OpConstant %31 3.29999995 %36 = OpConstant %31 1.10000002 %37 = OpTypeVector %31 4 %38 = OpTypePointer Function %37 %96 = OpTypePointer Input %31 %97 = OpVariable %96 Input %4 = OpFunction %2 None %3 %5 = OpLabel %8 = OpVariable %7 Function %10 = OpVariable %7 Function %14 = OpVariable %13 Function %20 = OpVariable %19 Function %22 = OpVariable %19 Function %26 = OpVariable %25 Function %33 = OpVariable %32 Function %35 = OpVariable %32 Function %39 = OpVariable %38 Function %47 = OpVariable %7 Function %51 = OpVariable %7 Function %55 = OpVariable %7 Function %59 = OpVariable %7 Function %63 = OpVariable %19 Function %67 = OpVariable %19 Function %71 = OpVariable %19 Function %75 = OpVariable %19 Function %79 = OpVariable %32 Function %83 = OpVariable %32 Function %87 = OpVariable %32 Function %91 = OpVariable %32 Function OpStore %8 %9 OpStore %10 %11 %15 = OpLoad %6 %8 %16 = OpLoad %6 %10 %17 = OpCompositeConstruct %12 %15 %16 OpStore %14 %17 OpStore %20 %21 OpStore %22 %23 %27 = OpLoad %18 %20 %28 = OpLoad %18 %20 %29 = OpLoad %18 %22 %30 = OpCompositeConstruct %24 %27 %28 %29 OpStore %26 %30 OpStore %33 %34 OpStore %35 %36 %40 = OpLoad %31 %33 %41 = OpLoad %31 %33 %42 = OpLoad %31 %35 %43 = OpLoad %31 %35 %44 = OpCompositeConstruct %37 %40 %41 %42 %43 %45 = OpLoad %37 %39 %46 = OpVectorShuffle %37 %45 %44 5 6 7 4 OpStore %39 %46 %48 = OpLoad %6 %8 %49 = OpLoad %6 %10 %50 = OpIAdd %6 %48 %49 OpStore %47 %50 %52 = OpLoad %6 %8 %53 = OpLoad %6 %10 %54 = OpISub %6 %52 %53 OpStore %51 %54 %56 = OpLoad %6 %8 %57 = OpLoad %6 %10 %58 = OpIMul %6 %56 %57 OpStore %55 %58 %60 = OpLoad %6 %8 %61 = OpLoad %6 %10 %100 = OpCompositeConstruct %12 %60 %60 %101 = OpCompositeConstruct %12 %61 %61 %62 = OpSDiv %6 %60 %61 OpStore %59 %62 %64 = OpLoad %18 %20 %65 = OpLoad %18 %22 %66 = OpIAdd %18 %64 %65 OpStore %63 %66 %68 = OpLoad %18 %20 %69 = OpLoad %18 %22 %70 = OpISub %18 %68 %69 OpStore %67 %70 %72 = OpLoad %18 %20 %73 = OpLoad %18 %22 %74 = OpIMul %18 %72 %73 OpStore %71 %74 %76 = OpLoad %18 %20 %77 = OpLoad %18 %22 %102 = OpCompositeConstruct %24 %76 %76 %76 %103 = OpCompositeConstruct %24 %77 %77 %77 %78 = OpUDiv %18 %76 %77 OpStore %75 %78 %80 = OpLoad %31 %33 %81 = OpLoad %31 %35 %82 = OpFAdd %31 %80 %81 OpStore %79 %82 %84 = OpLoad %31 %33 %85 = OpLoad %31 %35 %86 = OpFSub %31 %84 %85 OpStore %83 %86 %88 = OpLoad %31 %33 %89 = OpLoad %31 %35 %90 = OpFMul %31 %88 %89 OpStore %87 %90 %92 = OpLoad %31 %33 %93 = OpLoad %31 %35 %104 = OpCompositeConstruct %37 %92 %92 %92 %92 %105 = OpCompositeConstruct %37 %93 %93 %93 %93 %94 = OpFDiv %31 %92 %93 OpStore %91 %94 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(context.get()), validator_options); transformation_context.GetFactManager()->AddFactDataSynonym( MakeDataDescriptor(100, {1}), MakeDataDescriptor(60, {})); transformation_context.GetFactManager()->AddFactDataSynonym( MakeDataDescriptor(101, {1}), MakeDataDescriptor(61, {})); transformation_context.GetFactManager()->AddFactDataSynonym( MakeDataDescriptor(102, {1}), MakeDataDescriptor(76, {})); transformation_context.GetFactManager()->AddFactDataSynonym( MakeDataDescriptor(103, {1}), MakeDataDescriptor(77, {})); transformation_context.GetFactManager()->AddFactDataSynonym( MakeDataDescriptor(104, {1}), MakeDataDescriptor(92, {})); transformation_context.GetFactManager()->AddFactDataSynonym( MakeDataDescriptor(105, {1}), MakeDataDescriptor(93, {})); // Div operations are not currently supported. { TransformationWrapVectorSynonym wrap_div_bad1(62, 100, 101, 106, 1); ASSERT_FALSE( wrap_div_bad1.IsApplicable(context.get(), transformation_context)); TransformationWrapVectorSynonym wrap_div_bad2(78, 102, 103, 106, 1); ASSERT_FALSE( wrap_div_bad2.IsApplicable(context.get(), transformation_context)); TransformationWrapVectorSynonym wrap_div_bad3(94, 104, 105, 106, 1); ASSERT_FALSE( wrap_div_bad3.IsApplicable(context.get(), transformation_context)); } } TEST(TransformationWrapVectorSynonym, AdditionalWidthSupportTest) { std::string shader = R"( OpCapability Shader OpCapability Int64 OpCapability Float64 %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %4 "main" %97 OpExecutionMode %4 OriginUpperLeft OpSource ESSL 310 OpName %4 "main" %2 = OpTypeVoid %3 = OpTypeFunction %2 %6 = OpTypeInt 64 1 %7 = OpTypePointer Function %6 %9 = OpConstant %6 10 %11 = OpConstant %6 -5 %12 = OpTypeVector %6 2 %13 = OpTypePointer Function %12 %18 = OpTypeInt 64 0 %19 = OpTypePointer Function %18 %21 = OpConstant %18 8 %23 = OpConstant %18 2 %24 = OpTypeVector %18 3 %25 = OpTypePointer Function %24 %31 = OpTypeFloat 64 %32 = OpTypePointer Function %31 %34 = OpConstant %31 3.29999995 %36 = OpConstant %31 1.10000002 %37 = OpTypeVector %31 4 %38 = OpTypePointer Function %37 %96 = OpTypePointer Input %31 %97 = OpVariable %96 Input %4 = OpFunction %2 None %3 %5 = OpLabel %8 = OpVariable %7 Function %10 = OpVariable %7 Function %14 = OpVariable %13 Function %20 = OpVariable %19 Function %22 = OpVariable %19 Function %26 = OpVariable %25 Function %33 = OpVariable %32 Function %35 = OpVariable %32 Function %39 = OpVariable %38 Function %47 = OpVariable %7 Function %51 = OpVariable %7 Function %55 = OpVariable %7 Function %59 = OpVariable %7 Function %63 = OpVariable %19 Function %67 = OpVariable %19 Function %71 = OpVariable %19 Function %75 = OpVariable %19 Function %79 = OpVariable %32 Function %83 = OpVariable %32 Function %87 = OpVariable %32 Function %91 = OpVariable %32 Function OpStore %8 %9 OpStore %10 %11 %15 = OpLoad %6 %8 %16 = OpLoad %6 %10 %17 = OpCompositeConstruct %12 %15 %16 OpStore %14 %17 OpStore %20 %21 OpStore %22 %23 %27 = OpLoad %18 %20 %28 = OpLoad %18 %20 %29 = OpLoad %18 %22 %30 = OpCompositeConstruct %24 %27 %28 %29 OpStore %26 %30 OpStore %33 %34 OpStore %35 %36 %40 = OpLoad %31 %33 %41 = OpLoad %31 %33 %42 = OpLoad %31 %35 %43 = OpLoad %31 %35 %44 = OpCompositeConstruct %37 %40 %41 %42 %43 %45 = OpLoad %37 %39 %46 = OpVectorShuffle %37 %45 %44 5 6 7 4 OpStore %39 %46 %48 = OpLoad %6 %8 %49 = OpLoad %6 %10 %100 = OpCompositeConstruct %12 %48 %48 %101 = OpCompositeConstruct %12 %49 %49 %50 = OpIAdd %6 %48 %49 OpStore %47 %50 %52 = OpLoad %6 %8 %53 = OpLoad %6 %10 %54 = OpISub %6 %52 %53 OpStore %51 %54 %56 = OpLoad %6 %8 %57 = OpLoad %6 %10 %58 = OpIMul %6 %56 %57 OpStore %55 %58 %60 = OpLoad %6 %8 %61 = OpLoad %6 %10 %62 = OpSDiv %6 %60 %61 OpStore %59 %62 %64 = OpLoad %18 %20 %65 = OpLoad %18 %22 %66 = OpIAdd %18 %64 %65 OpStore %63 %66 %68 = OpLoad %18 %20 %69 = OpLoad %18 %22 %103 = OpCompositeConstruct %24 %68 %68 %68 %104 = OpCompositeConstruct %24 %69 %69 %69 %70 = OpISub %18 %68 %69 OpStore %67 %70 %72 = OpLoad %18 %20 %73 = OpLoad %18 %22 %74 = OpIMul %18 %72 %73 OpStore %71 %74 %76 = OpLoad %18 %20 %77 = OpLoad %18 %22 %78 = OpUDiv %18 %76 %77 OpStore %75 %78 %80 = OpLoad %31 %33 %81 = OpLoad %31 %35 %82 = OpFAdd %31 %80 %81 OpStore %79 %82 %84 = OpLoad %31 %33 %85 = OpLoad %31 %35 %86 = OpFSub %31 %84 %85 OpStore %83 %86 %88 = OpLoad %31 %33 %89 = OpLoad %31 %35 %106 = OpCompositeConstruct %37 %88 %88 %88 %88 %107 = OpCompositeConstruct %37 %89 %89 %89 %89 %90 = OpFMul %31 %88 %89 OpStore %87 %90 %92 = OpLoad %31 %33 %93 = OpLoad %31 %35 %94 = OpFDiv %31 %92 %93 OpStore %91 %94 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; // Check context validity. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, kConsoleMessageConsumer)); TransformationContext transformation_context( MakeUnique(context.get()), validator_options); // Vec Type Id | Vector Type | Element Type id | Element Type | // ------------+----------------+------------------+-----------------+ // 12 | vec2 | 6 | int64 | // 24 | vec3 | 18 | uint64 | // 37 | vec4 | 31 | float64 | // Test support for 64-bit signed int. { // Assert that the target scalar instruction result id is relevant. ASSERT_FALSE(transformation_context.GetFactManager()->IdIsIrrelevant(50)); transformation_context.GetFactManager()->AddFactDataSynonym( MakeDataDescriptor(100, {1}), MakeDataDescriptor(48, {})); transformation_context.GetFactManager()->AddFactDataSynonym( MakeDataDescriptor(101, {1}), MakeDataDescriptor(49, {})); // Good: The following transformation should be applicable. TransformationWrapVectorSynonym wrap_add_int64(50, 100, 101, 102, 1); ASSERT_TRUE( wrap_add_int64.IsApplicable(context.get(), transformation_context)); // Insert an arithmetic instruction of the same type to add two vectors. ApplyAndCheckFreshIds(wrap_add_int64, context.get(), &transformation_context); // |instruction_id| and id at |scalar_position of the result vector should // be synonyms. ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( MakeDataDescriptor(102, {1}), MakeDataDescriptor(50, {}))); } // Test support for 64-bit unsigned int. { ASSERT_FALSE(transformation_context.GetFactManager()->IdIsIrrelevant(70)); transformation_context.GetFactManager()->AddFactDataSynonym( MakeDataDescriptor(103, {2}), MakeDataDescriptor(68, {})); transformation_context.GetFactManager()->AddFactDataSynonym( MakeDataDescriptor(104, {2}), MakeDataDescriptor(69, {})); // Good: The following transformation should be applicable. TransformationWrapVectorSynonym wrap_sub_uint64(70, 103, 104, 105, 2); ASSERT_TRUE( wrap_sub_uint64.IsApplicable(context.get(), transformation_context)); ApplyAndCheckFreshIds(wrap_sub_uint64, context.get(), &transformation_context); ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( MakeDataDescriptor(105, {2}), MakeDataDescriptor(70, {}))); } // Test support for 64-bit float. { ASSERT_FALSE(transformation_context.GetFactManager()->IdIsIrrelevant(90)); transformation_context.GetFactManager()->AddFactDataSynonym( MakeDataDescriptor(106, {3}), MakeDataDescriptor(88, {})); transformation_context.GetFactManager()->AddFactDataSynonym( MakeDataDescriptor(107, {3}), MakeDataDescriptor(89, {})); // Good: The following transformation should be applicable. TransformationWrapVectorSynonym wrap_mul_float64(90, 106, 107, 108, 3); ASSERT_TRUE( wrap_mul_float64.IsApplicable(context.get(), transformation_context)); ApplyAndCheckFreshIds(wrap_mul_float64, context.get(), &transformation_context); ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( MakeDataDescriptor(108, {3}), MakeDataDescriptor(90, {}))); } std::string after_transformation = R"( OpCapability Shader OpCapability Int64 OpCapability Float64 %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %4 "main" %97 OpExecutionMode %4 OriginUpperLeft OpSource ESSL 310 OpName %4 "main" %2 = OpTypeVoid %3 = OpTypeFunction %2 %6 = OpTypeInt 64 1 %7 = OpTypePointer Function %6 %9 = OpConstant %6 10 %11 = OpConstant %6 -5 %12 = OpTypeVector %6 2 %13 = OpTypePointer Function %12 %18 = OpTypeInt 64 0 %19 = OpTypePointer Function %18 %21 = OpConstant %18 8 %23 = OpConstant %18 2 %24 = OpTypeVector %18 3 %25 = OpTypePointer Function %24 %31 = OpTypeFloat 64 %32 = OpTypePointer Function %31 %34 = OpConstant %31 3.29999995 %36 = OpConstant %31 1.10000002 %37 = OpTypeVector %31 4 %38 = OpTypePointer Function %37 %96 = OpTypePointer Input %31 %97 = OpVariable %96 Input %4 = OpFunction %2 None %3 %5 = OpLabel %8 = OpVariable %7 Function %10 = OpVariable %7 Function %14 = OpVariable %13 Function %20 = OpVariable %19 Function %22 = OpVariable %19 Function %26 = OpVariable %25 Function %33 = OpVariable %32 Function %35 = OpVariable %32 Function %39 = OpVariable %38 Function %47 = OpVariable %7 Function %51 = OpVariable %7 Function %55 = OpVariable %7 Function %59 = OpVariable %7 Function %63 = OpVariable %19 Function %67 = OpVariable %19 Function %71 = OpVariable %19 Function %75 = OpVariable %19 Function %79 = OpVariable %32 Function %83 = OpVariable %32 Function %87 = OpVariable %32 Function %91 = OpVariable %32 Function OpStore %8 %9 OpStore %10 %11 %15 = OpLoad %6 %8 %16 = OpLoad %6 %10 %17 = OpCompositeConstruct %12 %15 %16 OpStore %14 %17 OpStore %20 %21 OpStore %22 %23 %27 = OpLoad %18 %20 %28 = OpLoad %18 %20 %29 = OpLoad %18 %22 %30 = OpCompositeConstruct %24 %27 %28 %29 OpStore %26 %30 OpStore %33 %34 OpStore %35 %36 %40 = OpLoad %31 %33 %41 = OpLoad %31 %33 %42 = OpLoad %31 %35 %43 = OpLoad %31 %35 %44 = OpCompositeConstruct %37 %40 %41 %42 %43 %45 = OpLoad %37 %39 %46 = OpVectorShuffle %37 %45 %44 5 6 7 4 OpStore %39 %46 %48 = OpLoad %6 %8 %49 = OpLoad %6 %10 %100 = OpCompositeConstruct %12 %48 %48 %101 = OpCompositeConstruct %12 %49 %49 %102 = OpIAdd %12 %100 %101 %50 = OpIAdd %6 %48 %49 OpStore %47 %50 %52 = OpLoad %6 %8 %53 = OpLoad %6 %10 %54 = OpISub %6 %52 %53 OpStore %51 %54 %56 = OpLoad %6 %8 %57 = OpLoad %6 %10 %58 = OpIMul %6 %56 %57 OpStore %55 %58 %60 = OpLoad %6 %8 %61 = OpLoad %6 %10 %62 = OpSDiv %6 %60 %61 OpStore %59 %62 %64 = OpLoad %18 %20 %65 = OpLoad %18 %22 %66 = OpIAdd %18 %64 %65 OpStore %63 %66 %68 = OpLoad %18 %20 %69 = OpLoad %18 %22 %103 = OpCompositeConstruct %24 %68 %68 %68 %104 = OpCompositeConstruct %24 %69 %69 %69 %105 = OpISub %24 %103 %104 %70 = OpISub %18 %68 %69 OpStore %67 %70 %72 = OpLoad %18 %20 %73 = OpLoad %18 %22 %74 = OpIMul %18 %72 %73 OpStore %71 %74 %76 = OpLoad %18 %20 %77 = OpLoad %18 %22 %78 = OpUDiv %18 %76 %77 OpStore %75 %78 %80 = OpLoad %31 %33 %81 = OpLoad %31 %35 %82 = OpFAdd %31 %80 %81 OpStore %79 %82 %84 = OpLoad %31 %33 %85 = OpLoad %31 %35 %86 = OpFSub %31 %84 %85 OpStore %83 %86 %88 = OpLoad %31 %33 %89 = OpLoad %31 %35 %106 = OpCompositeConstruct %37 %88 %88 %88 %88 %107 = OpCompositeConstruct %37 %89 %89 %89 %89 %108 = OpFMul %37 %106 %107 %90 = OpFMul %31 %88 %89 OpStore %87 %90 %92 = OpLoad %31 %33 %93 = OpLoad %31 %35 %94 = OpFDiv %31 %92 %93 OpStore %91 %94 OpReturn OpFunctionEnd )"; ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); } TEST(TransformationWrapVectorSynonym, DifferentVectorSignedness) { 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 1 %11 = OpConstant %6 0 %12 = OpConstantComposite %7 %10 %11 %14 = OpTypeInt 32 0 %15 = OpTypeVector %14 2 %18 = OpConstant %14 3 %19 = OpConstant %14 0 %20 = OpConstantComposite %15 %18 %19 %21 = OpConstantComposite %15 %19 %18 %4 = OpFunction %2 None %3 %5 = OpLabel %100 = OpIAdd %14 %10 %18 %101 = OpIAdd %6 %10 %18 %102 = OpIAdd %6 %18 %19 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; // Check context validity. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, kConsoleMessageConsumer)); TransformationContext transformation_context( MakeUnique(context.get()), validator_options); transformation_context.GetFactManager()->AddFactDataSynonym( MakeDataDescriptor(10, {}), MakeDataDescriptor(12, {0})); transformation_context.GetFactManager()->AddFactDataSynonym( MakeDataDescriptor(18, {}), MakeDataDescriptor(20, {0})); transformation_context.GetFactManager()->AddFactDataSynonym( MakeDataDescriptor(19, {}), MakeDataDescriptor(21, {0})); { TransformationWrapVectorSynonym transformation1(100, 12, 20, 200, 0); ASSERT_TRUE( transformation1.IsApplicable(context.get(), transformation_context)); ApplyAndCheckFreshIds(transformation1, context.get(), &transformation_context); ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( MakeDataDescriptor(200, {0}), MakeDataDescriptor(100, {}))); } { TransformationWrapVectorSynonym transformation2(101, 12, 20, 201, 0); ASSERT_TRUE( transformation2.IsApplicable(context.get(), transformation_context)); ApplyAndCheckFreshIds(transformation2, context.get(), &transformation_context); ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( MakeDataDescriptor(201, {0}), MakeDataDescriptor(101, {}))); } { TransformationWrapVectorSynonym transformation3(102, 20, 21, 202, 0); ASSERT_TRUE( transformation3.IsApplicable(context.get(), transformation_context)); ApplyAndCheckFreshIds(transformation3, context.get(), &transformation_context); ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( MakeDataDescriptor(202, {0}), MakeDataDescriptor(102, {}))); } std::string after_transformation = 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 1 %11 = OpConstant %6 0 %12 = OpConstantComposite %7 %10 %11 %14 = OpTypeInt 32 0 %15 = OpTypeVector %14 2 %18 = OpConstant %14 3 %19 = OpConstant %14 0 %20 = OpConstantComposite %15 %18 %19 %21 = OpConstantComposite %15 %19 %18 %4 = OpFunction %2 None %3 %5 = OpLabel %200 = OpIAdd %15 %12 %20 %100 = OpIAdd %14 %10 %18 %201 = OpIAdd %7 %12 %20 %101 = OpIAdd %6 %10 %18 %202 = OpIAdd %7 %20 %21 %102 = OpIAdd %6 %18 %19 OpReturn OpFunctionEnd )"; ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); } TEST(TransformationWrapVectorSynonym, SignednessDoesNotMatchResultType) { 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 1 %11 = OpConstant %6 0 %12 = OpConstantComposite %7 %10 %11 %13 = OpConstantComposite %7 %11 %10 %14 = OpTypeInt 32 0 %4 = OpFunction %2 None %3 %5 = OpLabel %100 = OpIAdd %14 %10 %11 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; // Check context validity. ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, kConsoleMessageConsumer)); TransformationContext transformation_context( MakeUnique(context.get()), validator_options); transformation_context.GetFactManager()->AddFactDataSynonym( MakeDataDescriptor(10, {}), MakeDataDescriptor(12, {0})); transformation_context.GetFactManager()->AddFactDataSynonym( MakeDataDescriptor(11, {}), MakeDataDescriptor(13, {0})); ASSERT_FALSE(TransformationWrapVectorSynonym(100, 12, 13, 200, 0) .IsApplicable(context.get(), transformation_context)); } } // namespace } // namespace fuzz } // namespace spvtools