blob: 7c6d1263904aa5ffa312a6febfcae25b4ccd9d50 [file] [log] [blame]
// 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_replace_constant_with_uniform.h"
#include "gtest/gtest.h"
#include "source/fuzz/fuzzer_util.h"
#include "source/fuzz/instruction_descriptor.h"
#include "source/fuzz/uniform_buffer_element_descriptor.h"
#include "test/fuzz/fuzz_test_util.h"
namespace spvtools {
namespace fuzz {
namespace {
bool AddFactHelper(
TransformationContext* transformation_context, uint32_t word,
const protobufs::UniformBufferElementDescriptor& descriptor) {
protobufs::FactConstantUniform constant_uniform_fact;
constant_uniform_fact.add_constant_word(word);
*constant_uniform_fact.mutable_uniform_buffer_element_descriptor() =
descriptor;
protobufs::Fact fact;
*fact.mutable_constant_uniform_fact() = constant_uniform_fact;
return transformation_context->GetFactManager()->MaybeAddFact(fact);
}
TEST(TransformationReplaceConstantWithUniformTest, BasicReplacements) {
// This test came from the following GLSL:
//
// #version 450
//
// uniform blockname {
// int a;
// int b;
// int c;
// };
//
// void main()
// {
// int x;
// x = 1;
// x = x + 2;
// x = 3 + x;
// }
std::string shader = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource GLSL 450
OpName %4 "main"
OpName %8 "x"
OpName %16 "blockname"
OpMemberName %16 0 "a"
OpMemberName %16 1 "b"
OpMemberName %16 2 "c"
OpName %18 ""
OpMemberDecorate %16 0 Offset 0
OpMemberDecorate %16 1 Offset 4
OpMemberDecorate %16 2 Offset 8
OpDecorate %16 Block
OpDecorate %18 DescriptorSet 0
OpDecorate %18 Binding 0
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeInt 32 1
%7 = OpTypePointer Function %6
%50 = OpConstant %6 0
%9 = OpConstant %6 1
%11 = OpConstant %6 2
%14 = OpConstant %6 3
%16 = OpTypeStruct %6 %6 %6
%17 = OpTypePointer Uniform %16
%51 = OpTypePointer Uniform %6
%18 = OpVariable %17 Uniform
%4 = OpFunction %2 None %3
%5 = OpLabel
%8 = OpVariable %7 Function
OpStore %8 %9
%10 = OpLoad %6 %8
%12 = OpIAdd %6 %10 %11
OpStore %8 %12
%13 = OpLoad %6 %8
%15 = OpIAdd %6 %14 %13
OpStore %8 %15
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);
protobufs::UniformBufferElementDescriptor blockname_a =
MakeUniformBufferElementDescriptor(0, 0, {0});
protobufs::UniformBufferElementDescriptor blockname_b =
MakeUniformBufferElementDescriptor(0, 0, {1});
protobufs::UniformBufferElementDescriptor blockname_c =
MakeUniformBufferElementDescriptor(0, 0, {2});
ASSERT_TRUE(AddFactHelper(&transformation_context, 1, blockname_a));
ASSERT_TRUE(AddFactHelper(&transformation_context, 2, blockname_b));
ASSERT_TRUE(AddFactHelper(&transformation_context, 3, blockname_c));
// The constant ids are 9, 11 and 14, for 1, 2 and 3 respectively.
protobufs::IdUseDescriptor use_of_9_in_store = MakeIdUseDescriptor(
9, MakeInstructionDescriptor(8, spv::Op::OpStore, 0), 1);
protobufs::IdUseDescriptor use_of_11_in_add = MakeIdUseDescriptor(
11, MakeInstructionDescriptor(12, spv::Op::OpIAdd, 0), 1);
protobufs::IdUseDescriptor use_of_14_in_add = MakeIdUseDescriptor(
14, MakeInstructionDescriptor(15, spv::Op::OpIAdd, 0), 0);
// These transformations work: they match the facts.
auto transformation_use_of_9_in_store =
TransformationReplaceConstantWithUniform(use_of_9_in_store, blockname_a,
100, 101);
ASSERT_TRUE(transformation_use_of_9_in_store.IsApplicable(
context.get(), transformation_context));
auto transformation_use_of_11_in_add =
TransformationReplaceConstantWithUniform(use_of_11_in_add, blockname_b,
102, 103);
ASSERT_TRUE(transformation_use_of_11_in_add.IsApplicable(
context.get(), transformation_context));
auto transformation_use_of_14_in_add =
TransformationReplaceConstantWithUniform(use_of_14_in_add, blockname_c,
104, 105);
ASSERT_TRUE(transformation_use_of_14_in_add.IsApplicable(
context.get(), transformation_context));
// The transformations are not applicable if we change which uniforms are
// applied to which constants.
ASSERT_FALSE(TransformationReplaceConstantWithUniform(use_of_9_in_store,
blockname_b, 101, 102)
.IsApplicable(context.get(), transformation_context));
ASSERT_FALSE(TransformationReplaceConstantWithUniform(use_of_11_in_add,
blockname_c, 101, 102)
.IsApplicable(context.get(), transformation_context));
ASSERT_FALSE(TransformationReplaceConstantWithUniform(use_of_14_in_add,
blockname_a, 101, 102)
.IsApplicable(context.get(), transformation_context));
// The following transformations do not apply because the uniform descriptors
// are not sensible.
protobufs::UniformBufferElementDescriptor nonsense_uniform_descriptor1 =
MakeUniformBufferElementDescriptor(1, 2, {0});
protobufs::UniformBufferElementDescriptor nonsense_uniform_descriptor2 =
MakeUniformBufferElementDescriptor(0, 0, {5});
ASSERT_FALSE(TransformationReplaceConstantWithUniform(
use_of_9_in_store, nonsense_uniform_descriptor1, 101, 102)
.IsApplicable(context.get(), transformation_context));
ASSERT_FALSE(TransformationReplaceConstantWithUniform(
use_of_9_in_store, nonsense_uniform_descriptor2, 101, 102)
.IsApplicable(context.get(), transformation_context));
// The following transformation does not apply because the id descriptor is
// not sensible.
protobufs::IdUseDescriptor nonsense_id_use_descriptor = MakeIdUseDescriptor(
9, MakeInstructionDescriptor(15, spv::Op::OpIAdd, 0), 0);
ASSERT_FALSE(TransformationReplaceConstantWithUniform(
nonsense_id_use_descriptor, blockname_a, 101, 102)
.IsApplicable(context.get(), transformation_context));
// The following transformations do not apply because the ids are not fresh.
ASSERT_FALSE(TransformationReplaceConstantWithUniform(use_of_11_in_add,
blockname_b, 15, 103)
.IsApplicable(context.get(), transformation_context));
ASSERT_FALSE(TransformationReplaceConstantWithUniform(use_of_11_in_add,
blockname_b, 102, 15)
.IsApplicable(context.get(), transformation_context));
// Apply the use of 9 in a store.
ApplyAndCheckFreshIds(transformation_use_of_9_in_store, context.get(),
&transformation_context);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
kConsoleMessageConsumer));
std::string after_replacing_use_of_9_in_store = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource GLSL 450
OpName %4 "main"
OpName %8 "x"
OpName %16 "blockname"
OpMemberName %16 0 "a"
OpMemberName %16 1 "b"
OpMemberName %16 2 "c"
OpName %18 ""
OpMemberDecorate %16 0 Offset 0
OpMemberDecorate %16 1 Offset 4
OpMemberDecorate %16 2 Offset 8
OpDecorate %16 Block
OpDecorate %18 DescriptorSet 0
OpDecorate %18 Binding 0
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeInt 32 1
%7 = OpTypePointer Function %6
%50 = OpConstant %6 0
%9 = OpConstant %6 1
%11 = OpConstant %6 2
%14 = OpConstant %6 3
%16 = OpTypeStruct %6 %6 %6
%17 = OpTypePointer Uniform %16
%51 = OpTypePointer Uniform %6
%18 = OpVariable %17 Uniform
%4 = OpFunction %2 None %3
%5 = OpLabel
%8 = OpVariable %7 Function
%100 = OpAccessChain %51 %18 %50
%101 = OpLoad %6 %100
OpStore %8 %101
%10 = OpLoad %6 %8
%12 = OpIAdd %6 %10 %11
OpStore %8 %12
%13 = OpLoad %6 %8
%15 = OpIAdd %6 %14 %13
OpStore %8 %15
OpReturn
OpFunctionEnd
)";
ASSERT_TRUE(IsEqual(env, after_replacing_use_of_9_in_store, context.get()));
ASSERT_TRUE(transformation_use_of_11_in_add.IsApplicable(
context.get(), transformation_context));
// Apply the use of 11 in an add.
ApplyAndCheckFreshIds(transformation_use_of_11_in_add, context.get(),
&transformation_context);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
kConsoleMessageConsumer));
std::string after_replacing_use_of_11_in_add = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource GLSL 450
OpName %4 "main"
OpName %8 "x"
OpName %16 "blockname"
OpMemberName %16 0 "a"
OpMemberName %16 1 "b"
OpMemberName %16 2 "c"
OpName %18 ""
OpMemberDecorate %16 0 Offset 0
OpMemberDecorate %16 1 Offset 4
OpMemberDecorate %16 2 Offset 8
OpDecorate %16 Block
OpDecorate %18 DescriptorSet 0
OpDecorate %18 Binding 0
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeInt 32 1
%7 = OpTypePointer Function %6
%50 = OpConstant %6 0
%9 = OpConstant %6 1
%11 = OpConstant %6 2
%14 = OpConstant %6 3
%16 = OpTypeStruct %6 %6 %6
%17 = OpTypePointer Uniform %16
%51 = OpTypePointer Uniform %6
%18 = OpVariable %17 Uniform
%4 = OpFunction %2 None %3
%5 = OpLabel
%8 = OpVariable %7 Function
%100 = OpAccessChain %51 %18 %50
%101 = OpLoad %6 %100
OpStore %8 %101
%10 = OpLoad %6 %8
%102 = OpAccessChain %51 %18 %9
%103 = OpLoad %6 %102
%12 = OpIAdd %6 %10 %103
OpStore %8 %12
%13 = OpLoad %6 %8
%15 = OpIAdd %6 %14 %13
OpStore %8 %15
OpReturn
OpFunctionEnd
)";
ASSERT_TRUE(IsEqual(env, after_replacing_use_of_11_in_add, context.get()));
ASSERT_TRUE(transformation_use_of_14_in_add.IsApplicable(
context.get(), transformation_context));
// Apply the use of 15 in an add.
ApplyAndCheckFreshIds(transformation_use_of_14_in_add, context.get(),
&transformation_context);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
kConsoleMessageConsumer));
std::string after_replacing_use_of_14_in_add = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource GLSL 450
OpName %4 "main"
OpName %8 "x"
OpName %16 "blockname"
OpMemberName %16 0 "a"
OpMemberName %16 1 "b"
OpMemberName %16 2 "c"
OpName %18 ""
OpMemberDecorate %16 0 Offset 0
OpMemberDecorate %16 1 Offset 4
OpMemberDecorate %16 2 Offset 8
OpDecorate %16 Block
OpDecorate %18 DescriptorSet 0
OpDecorate %18 Binding 0
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeInt 32 1
%7 = OpTypePointer Function %6
%50 = OpConstant %6 0
%9 = OpConstant %6 1
%11 = OpConstant %6 2
%14 = OpConstant %6 3
%16 = OpTypeStruct %6 %6 %6
%17 = OpTypePointer Uniform %16
%51 = OpTypePointer Uniform %6
%18 = OpVariable %17 Uniform
%4 = OpFunction %2 None %3
%5 = OpLabel
%8 = OpVariable %7 Function
%100 = OpAccessChain %51 %18 %50
%101 = OpLoad %6 %100
OpStore %8 %101
%10 = OpLoad %6 %8
%102 = OpAccessChain %51 %18 %9
%103 = OpLoad %6 %102
%12 = OpIAdd %6 %10 %103
OpStore %8 %12
%13 = OpLoad %6 %8
%104 = OpAccessChain %51 %18 %11
%105 = OpLoad %6 %104
%15 = OpIAdd %6 %105 %13
OpStore %8 %15
OpReturn
OpFunctionEnd
)";
ASSERT_TRUE(IsEqual(env, after_replacing_use_of_14_in_add, context.get()));
}
TEST(TransformationReplaceConstantWithUniformTest, NestedStruct) {
// This test came from the following GLSL:
//
// #version 450
//
// struct U {
// int x; // == 4
// };
//
// struct T {
// int x; // == 3
// U y;
// };
//
// struct S {
// T x;
// int y; // == 2
// };
//
// uniform blockname {
// int x; // == 1
// S y;
// };
//
// void foo(int a) { }
//
// void main()
// {
// int x;
// x = 1;
// x = x + 2;
// x = 3 + x;
// foo(4);
// }
std::string shader = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource GLSL 450
OpName %4 "main"
OpName %10 "foo(i1;"
OpName %9 "a"
OpName %12 "x"
OpName %21 "param"
OpName %23 "U"
OpMemberName %23 0 "x"
OpName %24 "T"
OpMemberName %24 0 "x"
OpMemberName %24 1 "y"
OpName %25 "S"
OpMemberName %25 0 "x"
OpMemberName %25 1 "y"
OpName %26 "blockname"
OpMemberName %26 0 "x"
OpMemberName %26 1 "y"
OpName %28 ""
OpMemberDecorate %23 0 Offset 0
OpMemberDecorate %24 0 Offset 0
OpMemberDecorate %24 1 Offset 16
OpMemberDecorate %25 0 Offset 0
OpMemberDecorate %25 1 Offset 32
OpMemberDecorate %26 0 Offset 0
OpMemberDecorate %26 1 Offset 16
OpDecorate %26 Block
OpDecorate %28 DescriptorSet 0
OpDecorate %28 Binding 0
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeInt 32 1
%7 = OpTypePointer Function %6
%8 = OpTypeFunction %2 %7
%50 = OpConstant %6 0
%13 = OpConstant %6 1
%15 = OpConstant %6 2
%17 = OpConstant %6 3
%20 = OpConstant %6 4
%23 = OpTypeStruct %6
%24 = OpTypeStruct %6 %23
%25 = OpTypeStruct %24 %6
%26 = OpTypeStruct %6 %25
%27 = OpTypePointer Uniform %26
%51 = OpTypePointer Uniform %6
%28 = OpVariable %27 Uniform
%4 = OpFunction %2 None %3
%5 = OpLabel
%12 = OpVariable %7 Function
%21 = OpVariable %7 Function
OpStore %12 %13
%14 = OpLoad %6 %12
%16 = OpIAdd %6 %14 %15
OpStore %12 %16
%18 = OpLoad %6 %12
%19 = OpIAdd %6 %17 %18
OpStore %12 %19
OpStore %21 %20
%22 = OpFunctionCall %2 %10 %21
OpReturn
OpFunctionEnd
%10 = OpFunction %2 None %8
%9 = OpFunctionParameter %7
%11 = 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);
protobufs::UniformBufferElementDescriptor blockname_1 =
MakeUniformBufferElementDescriptor(0, 0, {0});
protobufs::UniformBufferElementDescriptor blockname_2 =
MakeUniformBufferElementDescriptor(0, 0, {1, 1});
protobufs::UniformBufferElementDescriptor blockname_3 =
MakeUniformBufferElementDescriptor(0, 0, {1, 0, 0});
protobufs::UniformBufferElementDescriptor blockname_4 =
MakeUniformBufferElementDescriptor(0, 0, {1, 0, 1, 0});
ASSERT_TRUE(AddFactHelper(&transformation_context, 1, blockname_1));
ASSERT_TRUE(AddFactHelper(&transformation_context, 2, blockname_2));
ASSERT_TRUE(AddFactHelper(&transformation_context, 3, blockname_3));
ASSERT_TRUE(AddFactHelper(&transformation_context, 4, blockname_4));
// The constant ids are 13, 15, 17 and 20, for 1, 2, 3 and 4 respectively.
protobufs::IdUseDescriptor use_of_13_in_store = MakeIdUseDescriptor(
13, MakeInstructionDescriptor(21, spv::Op::OpStore, 0), 1);
protobufs::IdUseDescriptor use_of_15_in_add = MakeIdUseDescriptor(
15, MakeInstructionDescriptor(16, spv::Op::OpIAdd, 0), 1);
protobufs::IdUseDescriptor use_of_17_in_add = MakeIdUseDescriptor(
17, MakeInstructionDescriptor(19, spv::Op::OpIAdd, 0), 0);
protobufs::IdUseDescriptor use_of_20_in_store = MakeIdUseDescriptor(
20, MakeInstructionDescriptor(19, spv::Op::OpStore, 1), 1);
// These transformations work: they match the facts.
auto transformation_use_of_13_in_store =
TransformationReplaceConstantWithUniform(use_of_13_in_store, blockname_1,
100, 101);
ASSERT_TRUE(transformation_use_of_13_in_store.IsApplicable(
context.get(), transformation_context));
auto transformation_use_of_15_in_add =
TransformationReplaceConstantWithUniform(use_of_15_in_add, blockname_2,
102, 103);
ASSERT_TRUE(transformation_use_of_15_in_add.IsApplicable(
context.get(), transformation_context));
auto transformation_use_of_17_in_add =
TransformationReplaceConstantWithUniform(use_of_17_in_add, blockname_3,
104, 105);
ASSERT_TRUE(transformation_use_of_17_in_add.IsApplicable(
context.get(), transformation_context));
auto transformation_use_of_20_in_store =
TransformationReplaceConstantWithUniform(use_of_20_in_store, blockname_4,
106, 107);
ASSERT_TRUE(transformation_use_of_20_in_store.IsApplicable(
context.get(), transformation_context));
ASSERT_TRUE(transformation_use_of_13_in_store.IsApplicable(
context.get(), transformation_context));
ASSERT_TRUE(transformation_use_of_15_in_add.IsApplicable(
context.get(), transformation_context));
ASSERT_TRUE(transformation_use_of_17_in_add.IsApplicable(
context.get(), transformation_context));
ASSERT_TRUE(transformation_use_of_20_in_store.IsApplicable(
context.get(), transformation_context));
ApplyAndCheckFreshIds(transformation_use_of_13_in_store, context.get(),
&transformation_context);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
kConsoleMessageConsumer));
ASSERT_FALSE(transformation_use_of_13_in_store.IsApplicable(
context.get(), transformation_context));
ASSERT_TRUE(transformation_use_of_15_in_add.IsApplicable(
context.get(), transformation_context));
ASSERT_TRUE(transformation_use_of_17_in_add.IsApplicable(
context.get(), transformation_context));
ASSERT_TRUE(transformation_use_of_20_in_store.IsApplicable(
context.get(), transformation_context));
ApplyAndCheckFreshIds(transformation_use_of_15_in_add, context.get(),
&transformation_context);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
kConsoleMessageConsumer));
ASSERT_FALSE(transformation_use_of_13_in_store.IsApplicable(
context.get(), transformation_context));
ASSERT_FALSE(transformation_use_of_15_in_add.IsApplicable(
context.get(), transformation_context));
ASSERT_TRUE(transformation_use_of_17_in_add.IsApplicable(
context.get(), transformation_context));
ASSERT_TRUE(transformation_use_of_20_in_store.IsApplicable(
context.get(), transformation_context));
ApplyAndCheckFreshIds(transformation_use_of_17_in_add, context.get(),
&transformation_context);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
kConsoleMessageConsumer));
ASSERT_FALSE(transformation_use_of_13_in_store.IsApplicable(
context.get(), transformation_context));
ASSERT_FALSE(transformation_use_of_15_in_add.IsApplicable(
context.get(), transformation_context));
ASSERT_FALSE(transformation_use_of_17_in_add.IsApplicable(
context.get(), transformation_context));
ASSERT_TRUE(transformation_use_of_20_in_store.IsApplicable(
context.get(), transformation_context));
ApplyAndCheckFreshIds(transformation_use_of_20_in_store, context.get(),
&transformation_context);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
kConsoleMessageConsumer));
ASSERT_FALSE(transformation_use_of_13_in_store.IsApplicable(
context.get(), transformation_context));
ASSERT_FALSE(transformation_use_of_15_in_add.IsApplicable(
context.get(), transformation_context));
ASSERT_FALSE(transformation_use_of_17_in_add.IsApplicable(
context.get(), transformation_context));
ASSERT_FALSE(transformation_use_of_20_in_store.IsApplicable(
context.get(), transformation_context));
std::string after = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource GLSL 450
OpName %4 "main"
OpName %10 "foo(i1;"
OpName %9 "a"
OpName %12 "x"
OpName %21 "param"
OpName %23 "U"
OpMemberName %23 0 "x"
OpName %24 "T"
OpMemberName %24 0 "x"
OpMemberName %24 1 "y"
OpName %25 "S"
OpMemberName %25 0 "x"
OpMemberName %25 1 "y"
OpName %26 "blockname"
OpMemberName %26 0 "x"
OpMemberName %26 1 "y"
OpName %28 ""
OpMemberDecorate %23 0 Offset 0
OpMemberDecorate %24 0 Offset 0
OpMemberDecorate %24 1 Offset 16
OpMemberDecorate %25 0 Offset 0
OpMemberDecorate %25 1 Offset 32
OpMemberDecorate %26 0 Offset 0
OpMemberDecorate %26 1 Offset 16
OpDecorate %26 Block
OpDecorate %28 DescriptorSet 0
OpDecorate %28 Binding 0
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeInt 32 1
%7 = OpTypePointer Function %6
%8 = OpTypeFunction %2 %7
%50 = OpConstant %6 0
%13 = OpConstant %6 1
%15 = OpConstant %6 2
%17 = OpConstant %6 3
%20 = OpConstant %6 4
%23 = OpTypeStruct %6
%24 = OpTypeStruct %6 %23
%25 = OpTypeStruct %24 %6
%26 = OpTypeStruct %6 %25
%27 = OpTypePointer Uniform %26
%51 = OpTypePointer Uniform %6
%28 = OpVariable %27 Uniform
%4 = OpFunction %2 None %3
%5 = OpLabel
%12 = OpVariable %7 Function
%21 = OpVariable %7 Function
%100 = OpAccessChain %51 %28 %50
%101 = OpLoad %6 %100
OpStore %12 %101
%14 = OpLoad %6 %12
%102 = OpAccessChain %51 %28 %13 %13
%103 = OpLoad %6 %102
%16 = OpIAdd %6 %14 %103
OpStore %12 %16
%18 = OpLoad %6 %12
%104 = OpAccessChain %51 %28 %13 %50 %50
%105 = OpLoad %6 %104
%19 = OpIAdd %6 %105 %18
OpStore %12 %19
%106 = OpAccessChain %51 %28 %13 %50 %13 %50
%107 = OpLoad %6 %106
OpStore %21 %107
%22 = OpFunctionCall %2 %10 %21
OpReturn
OpFunctionEnd
%10 = OpFunction %2 None %8
%9 = OpFunctionParameter %7
%11 = OpLabel
OpReturn
OpFunctionEnd
)";
ASSERT_TRUE(IsEqual(env, after, context.get()));
}
TEST(TransformationReplaceConstantWithUniformTest, NoUniformIntPointerPresent) {
// This test came from the following GLSL:
//
// #version 450
//
// uniform blockname {
// int x; // == 0
// };
//
// void main()
// {
// int a;
// a = 0;
// }
std::string shader = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource GLSL 450
OpName %4 "main"
OpName %8 "a"
OpName %10 "blockname"
OpMemberName %10 0 "x"
OpName %12 ""
OpMemberDecorate %10 0 Offset 0
OpDecorate %10 Block
OpDecorate %12 DescriptorSet 0
OpDecorate %12 Binding 0
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeInt 32 1
%7 = OpTypePointer Function %6
%9 = OpConstant %6 0
%10 = OpTypeStruct %6
%11 = OpTypePointer Uniform %10
%12 = OpVariable %11 Uniform
%4 = OpFunction %2 None %3
%5 = OpLabel
%8 = OpVariable %7 Function
OpStore %8 %9
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);
protobufs::UniformBufferElementDescriptor blockname_0 =
MakeUniformBufferElementDescriptor(0, 0, {0});
ASSERT_TRUE(AddFactHelper(&transformation_context, 0, blockname_0));
// The constant id is 9 for 0.
protobufs::IdUseDescriptor use_of_9_in_store = MakeIdUseDescriptor(
9, MakeInstructionDescriptor(8, spv::Op::OpStore, 0), 1);
// This transformation is not available because no uniform pointer to integer
// type is present:
ASSERT_FALSE(TransformationReplaceConstantWithUniform(use_of_9_in_store,
blockname_0, 100, 101)
.IsApplicable(context.get(), transformation_context));
}
TEST(TransformationReplaceConstantWithUniformTest, NoConstantPresentForIndex) {
// This test came from the following GLSL:
//
// #version 450
//
// uniform blockname {
// int x; // == 0
// int y; // == 9
// };
//
// void main()
// {
// int a;
// a = 9;
// }
std::string shader = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource GLSL 450
OpName %4 "main"
OpName %8 "a"
OpName %10 "blockname"
OpMemberName %10 0 "x"
OpMemberName %10 1 "y"
OpName %12 ""
OpMemberDecorate %10 0 Offset 0
OpMemberDecorate %10 1 Offset 4
OpDecorate %10 Block
OpDecorate %12 DescriptorSet 0
OpDecorate %12 Binding 0
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeInt 32 1
%7 = OpTypePointer Function %6
%9 = OpConstant %6 9
%10 = OpTypeStruct %6 %6
%11 = OpTypePointer Uniform %10
%50 = OpTypePointer Uniform %6
%12 = OpVariable %11 Uniform
%4 = OpFunction %2 None %3
%5 = OpLabel
%8 = OpVariable %7 Function
OpStore %8 %9
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);
protobufs::UniformBufferElementDescriptor blockname_0 =
MakeUniformBufferElementDescriptor(0, 0, {0});
protobufs::UniformBufferElementDescriptor blockname_9 =
MakeUniformBufferElementDescriptor(0, 0, {1});
ASSERT_TRUE(AddFactHelper(&transformation_context, 9, blockname_9));
// The constant id is 9 for 9.
protobufs::IdUseDescriptor use_of_9_in_store = MakeIdUseDescriptor(
9, MakeInstructionDescriptor(8, spv::Op::OpStore, 0), 1);
// This transformation is not available because no constant is present for the
// index 1 required to index into the uniform buffer:
ASSERT_FALSE(TransformationReplaceConstantWithUniform(use_of_9_in_store,
blockname_9, 100, 101)
.IsApplicable(context.get(), transformation_context));
}
TEST(TransformationReplaceConstantWithUniformTest,
NoIntTypePresentToEnableIndexing) {
// This test came from the following GLSL:
//
// #version 450
//
// uniform blockname {
// float f; // == 9
// };
//
// void main()
// {
// float a;
// a = 3.0;
// }
std::string shader = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource GLSL 450
OpName %4 "main"
OpName %8 "a"
OpName %10 "blockname"
OpMemberName %10 0 "f"
OpName %12 ""
OpMemberDecorate %10 0 Offset 0
OpDecorate %10 Block
OpDecorate %12 DescriptorSet 0
OpDecorate %12 Binding 0
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeFloat 32
%7 = OpTypePointer Function %6
%9 = OpConstant %6 3
%10 = OpTypeStruct %6
%11 = OpTypePointer Uniform %10
%12 = OpVariable %11 Uniform
%4 = OpFunction %2 None %3
%5 = OpLabel
%8 = OpVariable %7 Function
OpStore %8 %9
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);
protobufs::UniformBufferElementDescriptor blockname_3 =
MakeUniformBufferElementDescriptor(0, 0, {0});
uint32_t float_data[1];
float temp = 3.0;
memcpy(&float_data[0], &temp, sizeof(float));
ASSERT_TRUE(
AddFactHelper(&transformation_context, float_data[0], blockname_3));
// The constant id is 9 for 3.0.
protobufs::IdUseDescriptor use_of_9_in_store = MakeIdUseDescriptor(
9, MakeInstructionDescriptor(8, spv::Op::OpStore, 0), 1);
// This transformation is not available because no integer type is present to
// allow a constant index to be expressed:
ASSERT_FALSE(TransformationReplaceConstantWithUniform(use_of_9_in_store,
blockname_3, 100, 101)
.IsApplicable(context.get(), transformation_context));
}
TEST(TransformationReplaceConstantWithUniformTest,
UniformFactsDoNotMatchConstants) {
// This test came from the following GLSL:
//
// #version 450
//
// uniform blockname {
// int x; // == 9
// int y; // == 10
// };
//
// void main()
// {
// int a;
// int b;
// a = 9;
// b = 10;
// }
std::string shader = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource GLSL 450
OpName %4 "main"
OpName %8 "a"
OpName %10 "b"
OpName %12 "blockname"
OpMemberName %12 0 "x"
OpMemberName %12 1 "y"
OpName %14 ""
OpMemberDecorate %12 0 Offset 0
OpMemberDecorate %12 1 Offset 4
OpDecorate %12 Block
OpDecorate %14 DescriptorSet 0
OpDecorate %14 Binding 0
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeInt 32 1
%7 = OpTypePointer Function %6
%9 = OpConstant %6 9
%11 = OpConstant %6 10
%50 = OpConstant %6 0
%51 = OpConstant %6 1
%12 = OpTypeStruct %6 %6
%13 = OpTypePointer Uniform %12
%52 = OpTypePointer Uniform %6
%14 = OpVariable %13 Uniform
%4 = OpFunction %2 None %3
%5 = OpLabel
%8 = OpVariable %7 Function
%10 = OpVariable %7 Function
OpStore %8 %9
OpStore %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;
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
kConsoleMessageConsumer));
TransformationContext transformation_context(
MakeUnique<FactManager>(context.get()), validator_options);
protobufs::UniformBufferElementDescriptor blockname_9 =
MakeUniformBufferElementDescriptor(0, 0, {0});
protobufs::UniformBufferElementDescriptor blockname_10 =
MakeUniformBufferElementDescriptor(0, 0, {1});
ASSERT_TRUE(AddFactHelper(&transformation_context, 9, blockname_9));
ASSERT_TRUE(AddFactHelper(&transformation_context, 10, blockname_10));
// The constant ids for 9 and 10 are 9 and 11 respectively
protobufs::IdUseDescriptor use_of_9_in_store = MakeIdUseDescriptor(
9, MakeInstructionDescriptor(10, spv::Op::OpStore, 0), 1);
protobufs::IdUseDescriptor use_of_11_in_store = MakeIdUseDescriptor(
11, MakeInstructionDescriptor(10, spv::Op::OpStore, 1), 1);
// These are right:
ASSERT_TRUE(TransformationReplaceConstantWithUniform(use_of_9_in_store,
blockname_9, 100, 101)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationReplaceConstantWithUniform(use_of_11_in_store,
blockname_10, 102, 103)
.IsApplicable(context.get(), transformation_context));
// These are wrong because the constants do not match the facts about
// uniforms.
ASSERT_FALSE(TransformationReplaceConstantWithUniform(use_of_11_in_store,
blockname_9, 100, 101)
.IsApplicable(context.get(), transformation_context));
ASSERT_FALSE(TransformationReplaceConstantWithUniform(use_of_9_in_store,
blockname_10, 102, 103)
.IsApplicable(context.get(), transformation_context));
}
TEST(TransformationReplaceConstantWithUniformTest, ComplexReplacements) {
// The following GLSL was the basis for this test:
// #version 450
//
// struct T {
// float a[5]; // [1.0, 1.5, 1.75, 1.875, 1.9375]
// ivec4 b; // (1, 2, 3, 4)
// vec3 c; // (2.0, 2.5, 2.75)
// uint d; // 42u
// bool e; // Not used in test
// };
//
// uniform block {
// T f;
// int g; // 22
// uvec2 h; // (100u, 200u)
// };
//
// void main()
// {
// T myT;
//
// myT.a[0] = 1.9375;
// myT.a[1] = 1.875;
// myT.a[2] = 1.75;
// myT.a[3] = 1.5;
// myT.a[4] = 1.0;
//
// myT.b.x = 4;
// myT.b.y = 3;
// myT.b.z = 2;
// myT.b.w = 1;
//
// myT.b.r = 22;
//
// myT.c[0] = 2.75;
// myT.c[0] = 2.5;
// myT.c[0] = 2.0;
//
// myT.d = 42u;
// myT.d = 100u;
// myT.d = 200u;
//
// myT.e = true; // No attempt to replace 'true' by a uniform value
//
// }
std::string shader = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource GLSL 450
OpName %4 "main"
OpName %14 "T"
OpMemberName %14 0 "a"
OpMemberName %14 1 "b"
OpMemberName %14 2 "c"
OpMemberName %14 3 "d"
OpMemberName %14 4 "e"
OpName %16 "myT"
OpName %61 "T"
OpMemberName %61 0 "a"
OpMemberName %61 1 "b"
OpMemberName %61 2 "c"
OpMemberName %61 3 "d"
OpMemberName %61 4 "e"
OpName %63 "block"
OpMemberName %63 0 "f"
OpMemberName %63 1 "g"
OpMemberName %63 2 "h"
OpName %65 ""
OpDecorate %60 ArrayStride 16
OpMemberDecorate %61 0 Offset 0
OpMemberDecorate %61 1 Offset 80
OpMemberDecorate %61 2 Offset 96
OpMemberDecorate %61 3 Offset 108
OpMemberDecorate %61 4 Offset 112
OpMemberDecorate %63 0 Offset 0
OpMemberDecorate %63 1 Offset 128
OpMemberDecorate %63 2 Offset 136
OpDecorate %63 Block
OpDecorate %65 DescriptorSet 0
OpDecorate %65 Binding 0
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeFloat 32
%7 = OpTypeInt 32 0
%8 = OpConstant %7 5
%9 = OpTypeArray %6 %8
%10 = OpTypeInt 32 1
%11 = OpTypeVector %10 4
%12 = OpTypeVector %6 3
%13 = OpTypeBool
%14 = OpTypeStruct %9 %11 %12 %7 %13
%15 = OpTypePointer Function %14
%17 = OpConstant %10 0
%18 = OpConstant %6 1.9375
%19 = OpTypePointer Function %6
%21 = OpConstant %10 1
%22 = OpConstant %6 1.875
%24 = OpConstant %10 2
%25 = OpConstant %6 1.75
%27 = OpConstant %10 3
%28 = OpConstant %6 1.5
%30 = OpConstant %10 4
%31 = OpConstant %6 1
%33 = OpConstant %7 0
%34 = OpTypePointer Function %10
%36 = OpConstant %7 1
%38 = OpConstant %7 2
%40 = OpConstant %7 3
%42 = OpConstant %10 22
%44 = OpConstant %6 2.75
%46 = OpConstant %6 2.5
%48 = OpConstant %6 2
%50 = OpConstant %7 42
%51 = OpTypePointer Function %7
%53 = OpConstant %7 100
%55 = OpConstant %7 200
%57 = OpConstantTrue %13
%58 = OpTypePointer Function %13
%60 = OpTypeArray %6 %8
%61 = OpTypeStruct %60 %11 %12 %7 %7
%62 = OpTypeVector %7 2
%63 = OpTypeStruct %61 %10 %62
%64 = OpTypePointer Uniform %63
%100 = OpTypePointer Uniform %10
%101 = OpTypePointer Uniform %7
%102 = OpTypePointer Uniform %6
%103 = OpTypePointer Uniform %13
%65 = OpVariable %64 Uniform
%4 = OpFunction %2 None %3
%5 = OpLabel
%16 = OpVariable %15 Function
%20 = OpAccessChain %19 %16 %17 %17
OpStore %20 %18
%23 = OpAccessChain %19 %16 %17 %21
OpStore %23 %22
%26 = OpAccessChain %19 %16 %17 %24
OpStore %26 %25
%29 = OpAccessChain %19 %16 %17 %27
OpStore %29 %28
%32 = OpAccessChain %19 %16 %17 %30
OpStore %32 %31
%35 = OpAccessChain %34 %16 %21 %33
OpStore %35 %30
%37 = OpAccessChain %34 %16 %21 %36
OpStore %37 %27
%39 = OpAccessChain %34 %16 %21 %38
OpStore %39 %24
%41 = OpAccessChain %34 %16 %21 %40
OpStore %41 %21
%43 = OpAccessChain %34 %16 %21 %33
OpStore %43 %42
%45 = OpAccessChain %19 %16 %24 %33
OpStore %45 %44
%47 = OpAccessChain %19 %16 %24 %33
OpStore %47 %46
%49 = OpAccessChain %19 %16 %24 %33
OpStore %49 %48
%52 = OpAccessChain %51 %16 %27
OpStore %52 %50
%54 = OpAccessChain %51 %16 %27
OpStore %54 %53
%56 = OpAccessChain %51 %16 %27
OpStore %56 %55
%59 = OpAccessChain %58 %16 %30
OpStore %59 %57
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);
const float float_array_values[5] = {1.0, 1.5, 1.75, 1.875, 1.9375};
uint32_t float_array_data[5];
memcpy(&float_array_data, &float_array_values, sizeof(float_array_values));
const float float_vector_values[3] = {2.0, 2.5, 2.75};
uint32_t float_vector_data[3];
memcpy(&float_vector_data, &float_vector_values, sizeof(float_vector_values));
protobufs::UniformBufferElementDescriptor uniform_f_a_0 =
MakeUniformBufferElementDescriptor(0, 0, {0, 0, 0});
protobufs::UniformBufferElementDescriptor uniform_f_a_1 =
MakeUniformBufferElementDescriptor(0, 0, {0, 0, 1});
protobufs::UniformBufferElementDescriptor uniform_f_a_2 =
MakeUniformBufferElementDescriptor(0, 0, {0, 0, 2});
protobufs::UniformBufferElementDescriptor uniform_f_a_3 =
MakeUniformBufferElementDescriptor(0, 0, {0, 0, 3});
protobufs::UniformBufferElementDescriptor uniform_f_a_4 =
MakeUniformBufferElementDescriptor(0, 0, {0, 0, 4});
protobufs::UniformBufferElementDescriptor uniform_f_b_x =
MakeUniformBufferElementDescriptor(0, 0, {0, 1, 0});
protobufs::UniformBufferElementDescriptor uniform_f_b_y =
MakeUniformBufferElementDescriptor(0, 0, {0, 1, 1});
protobufs::UniformBufferElementDescriptor uniform_f_b_z =
MakeUniformBufferElementDescriptor(0, 0, {0, 1, 2});
protobufs::UniformBufferElementDescriptor uniform_f_b_w =
MakeUniformBufferElementDescriptor(0, 0, {0, 1, 3});
protobufs::UniformBufferElementDescriptor uniform_f_c_x =
MakeUniformBufferElementDescriptor(0, 0, {0, 2, 0});
protobufs::UniformBufferElementDescriptor uniform_f_c_y =
MakeUniformBufferElementDescriptor(0, 0, {0, 2, 1});
protobufs::UniformBufferElementDescriptor uniform_f_c_z =
MakeUniformBufferElementDescriptor(0, 0, {0, 2, 2});
protobufs::UniformBufferElementDescriptor uniform_f_d =
MakeUniformBufferElementDescriptor(0, 0, {0, 3});
protobufs::UniformBufferElementDescriptor uniform_g =
MakeUniformBufferElementDescriptor(0, 0, {1});
protobufs::UniformBufferElementDescriptor uniform_h_x =
MakeUniformBufferElementDescriptor(0, 0, {2, 0});
protobufs::UniformBufferElementDescriptor uniform_h_y =
MakeUniformBufferElementDescriptor(0, 0, {2, 1});
ASSERT_TRUE(AddFactHelper(&transformation_context, float_array_data[0],
uniform_f_a_0));
ASSERT_TRUE(AddFactHelper(&transformation_context, float_array_data[1],
uniform_f_a_1));
ASSERT_TRUE(AddFactHelper(&transformation_context, float_array_data[2],
uniform_f_a_2));
ASSERT_TRUE(AddFactHelper(&transformation_context, float_array_data[3],
uniform_f_a_3));
ASSERT_TRUE(AddFactHelper(&transformation_context, float_array_data[4],
uniform_f_a_4));
ASSERT_TRUE(AddFactHelper(&transformation_context, 1, uniform_f_b_x));
ASSERT_TRUE(AddFactHelper(&transformation_context, 2, uniform_f_b_y));
ASSERT_TRUE(AddFactHelper(&transformation_context, 3, uniform_f_b_z));
ASSERT_TRUE(AddFactHelper(&transformation_context, 4, uniform_f_b_w));
ASSERT_TRUE(AddFactHelper(&transformation_context, float_vector_data[0],
uniform_f_c_x));
ASSERT_TRUE(AddFactHelper(&transformation_context, float_vector_data[1],
uniform_f_c_y));
ASSERT_TRUE(AddFactHelper(&transformation_context, float_vector_data[2],
uniform_f_c_z));
ASSERT_TRUE(AddFactHelper(&transformation_context, 42, uniform_f_d));
ASSERT_TRUE(AddFactHelper(&transformation_context, 22, uniform_g));
ASSERT_TRUE(AddFactHelper(&transformation_context, 100, uniform_h_x));
ASSERT_TRUE(AddFactHelper(&transformation_context, 200, uniform_h_y));
std::vector<TransformationReplaceConstantWithUniform> transformations;
transformations.emplace_back(TransformationReplaceConstantWithUniform(
MakeIdUseDescriptor(
18, MakeInstructionDescriptor(20, spv::Op::OpStore, 0), 1),
uniform_f_a_4, 200, 201));
transformations.emplace_back(TransformationReplaceConstantWithUniform(
MakeIdUseDescriptor(
22, MakeInstructionDescriptor(23, spv::Op::OpStore, 0), 1),
uniform_f_a_3, 202, 203));
transformations.emplace_back(TransformationReplaceConstantWithUniform(
MakeIdUseDescriptor(
25, MakeInstructionDescriptor(26, spv::Op::OpStore, 0), 1),
uniform_f_a_2, 204, 205));
transformations.emplace_back(TransformationReplaceConstantWithUniform(
MakeIdUseDescriptor(
28, MakeInstructionDescriptor(29, spv::Op::OpStore, 0), 1),
uniform_f_a_1, 206, 207));
transformations.emplace_back(TransformationReplaceConstantWithUniform(
MakeIdUseDescriptor(
31, MakeInstructionDescriptor(32, spv::Op::OpStore, 0), 1),
uniform_f_a_0, 208, 209));
transformations.emplace_back(TransformationReplaceConstantWithUniform(
MakeIdUseDescriptor(
30, MakeInstructionDescriptor(35, spv::Op::OpStore, 0), 1),
uniform_f_b_w, 210, 211));
transformations.emplace_back(TransformationReplaceConstantWithUniform(
MakeIdUseDescriptor(
27, MakeInstructionDescriptor(37, spv::Op::OpStore, 0), 1),
uniform_f_b_z, 212, 213));
transformations.emplace_back(TransformationReplaceConstantWithUniform(
MakeIdUseDescriptor(
24, MakeInstructionDescriptor(39, spv::Op::OpStore, 0), 1),
uniform_f_b_y, 214, 215));
transformations.emplace_back(TransformationReplaceConstantWithUniform(
MakeIdUseDescriptor(
21, MakeInstructionDescriptor(41, spv::Op::OpStore, 0), 1),
uniform_f_b_x, 216, 217));
transformations.emplace_back(TransformationReplaceConstantWithUniform(
MakeIdUseDescriptor(
44, MakeInstructionDescriptor(45, spv::Op::OpStore, 0), 1),
uniform_f_c_z, 220, 221));
transformations.emplace_back(TransformationReplaceConstantWithUniform(
MakeIdUseDescriptor(
46, MakeInstructionDescriptor(47, spv::Op::OpStore, 0), 1),
uniform_f_c_y, 222, 223));
transformations.emplace_back(TransformationReplaceConstantWithUniform(
MakeIdUseDescriptor(
48, MakeInstructionDescriptor(49, spv::Op::OpStore, 0), 1),
uniform_f_c_x, 224, 225));
transformations.emplace_back(TransformationReplaceConstantWithUniform(
MakeIdUseDescriptor(
50, MakeInstructionDescriptor(52, spv::Op::OpStore, 0), 1),
uniform_f_d, 226, 227));
transformations.emplace_back(TransformationReplaceConstantWithUniform(
MakeIdUseDescriptor(
53, MakeInstructionDescriptor(54, spv::Op::OpStore, 0), 1),
uniform_h_x, 228, 229));
transformations.emplace_back(TransformationReplaceConstantWithUniform(
MakeIdUseDescriptor(
55, MakeInstructionDescriptor(56, spv::Op::OpStore, 0), 1),
uniform_h_y, 230, 231));
transformations.emplace_back(TransformationReplaceConstantWithUniform(
MakeIdUseDescriptor(
42, MakeInstructionDescriptor(43, spv::Op::OpStore, 0), 1),
uniform_g, 218, 219));
for (auto& transformation : transformations) {
ASSERT_TRUE(
transformation.IsApplicable(context.get(), transformation_context));
ApplyAndCheckFreshIds(transformation, context.get(),
&transformation_context);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
context.get(), validator_options, kConsoleMessageConsumer));
}
std::string after = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource GLSL 450
OpName %4 "main"
OpName %14 "T"
OpMemberName %14 0 "a"
OpMemberName %14 1 "b"
OpMemberName %14 2 "c"
OpMemberName %14 3 "d"
OpMemberName %14 4 "e"
OpName %16 "myT"
OpName %61 "T"
OpMemberName %61 0 "a"
OpMemberName %61 1 "b"
OpMemberName %61 2 "c"
OpMemberName %61 3 "d"
OpMemberName %61 4 "e"
OpName %63 "block"
OpMemberName %63 0 "f"
OpMemberName %63 1 "g"
OpMemberName %63 2 "h"
OpName %65 ""
OpDecorate %60 ArrayStride 16
OpMemberDecorate %61 0 Offset 0
OpMemberDecorate %61 1 Offset 80
OpMemberDecorate %61 2 Offset 96
OpMemberDecorate %61 3 Offset 108
OpMemberDecorate %61 4 Offset 112
OpMemberDecorate %63 0 Offset 0
OpMemberDecorate %63 1 Offset 128
OpMemberDecorate %63 2 Offset 136
OpDecorate %63 Block
OpDecorate %65 DescriptorSet 0
OpDecorate %65 Binding 0
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeFloat 32
%7 = OpTypeInt 32 0
%8 = OpConstant %7 5
%9 = OpTypeArray %6 %8
%10 = OpTypeInt 32 1
%11 = OpTypeVector %10 4
%12 = OpTypeVector %6 3
%13 = OpTypeBool
%14 = OpTypeStruct %9 %11 %12 %7 %13
%15 = OpTypePointer Function %14
%17 = OpConstant %10 0
%18 = OpConstant %6 1.9375
%19 = OpTypePointer Function %6
%21 = OpConstant %10 1
%22 = OpConstant %6 1.875
%24 = OpConstant %10 2
%25 = OpConstant %6 1.75
%27 = OpConstant %10 3
%28 = OpConstant %6 1.5
%30 = OpConstant %10 4
%31 = OpConstant %6 1
%33 = OpConstant %7 0
%34 = OpTypePointer Function %10
%36 = OpConstant %7 1
%38 = OpConstant %7 2
%40 = OpConstant %7 3
%42 = OpConstant %10 22
%44 = OpConstant %6 2.75
%46 = OpConstant %6 2.5
%48 = OpConstant %6 2
%50 = OpConstant %7 42
%51 = OpTypePointer Function %7
%53 = OpConstant %7 100
%55 = OpConstant %7 200
%57 = OpConstantTrue %13
%58 = OpTypePointer Function %13
%60 = OpTypeArray %6 %8
%61 = OpTypeStruct %60 %11 %12 %7 %7
%62 = OpTypeVector %7 2
%63 = OpTypeStruct %61 %10 %62
%64 = OpTypePointer Uniform %63
%100 = OpTypePointer Uniform %10
%101 = OpTypePointer Uniform %7
%102 = OpTypePointer Uniform %6
%103 = OpTypePointer Uniform %13
%65 = OpVariable %64 Uniform
%4 = OpFunction %2 None %3
%5 = OpLabel
%16 = OpVariable %15 Function
%20 = OpAccessChain %19 %16 %17 %17
%200 = OpAccessChain %102 %65 %17 %17 %30
%201 = OpLoad %6 %200
OpStore %20 %201
%23 = OpAccessChain %19 %16 %17 %21
%202 = OpAccessChain %102 %65 %17 %17 %27
%203 = OpLoad %6 %202
OpStore %23 %203
%26 = OpAccessChain %19 %16 %17 %24
%204 = OpAccessChain %102 %65 %17 %17 %24
%205 = OpLoad %6 %204
OpStore %26 %205
%29 = OpAccessChain %19 %16 %17 %27
%206 = OpAccessChain %102 %65 %17 %17 %21
%207 = OpLoad %6 %206
OpStore %29 %207
%32 = OpAccessChain %19 %16 %17 %30
%208 = OpAccessChain %102 %65 %17 %17 %17
%209 = OpLoad %6 %208
OpStore %32 %209
%35 = OpAccessChain %34 %16 %21 %33
%210 = OpAccessChain %100 %65 %17 %21 %27
%211 = OpLoad %10 %210
OpStore %35 %211
%37 = OpAccessChain %34 %16 %21 %36
%212 = OpAccessChain %100 %65 %17 %21 %24
%213 = OpLoad %10 %212
OpStore %37 %213
%39 = OpAccessChain %34 %16 %21 %38
%214 = OpAccessChain %100 %65 %17 %21 %21
%215 = OpLoad %10 %214
OpStore %39 %215
%41 = OpAccessChain %34 %16 %21 %40
%216 = OpAccessChain %100 %65 %17 %21 %17
%217 = OpLoad %10 %216
OpStore %41 %217
%43 = OpAccessChain %34 %16 %21 %33
%218 = OpAccessChain %100 %65 %21
%219 = OpLoad %10 %218
OpStore %43 %219
%45 = OpAccessChain %19 %16 %24 %33
%220 = OpAccessChain %102 %65 %17 %24 %24
%221 = OpLoad %6 %220
OpStore %45 %221
%47 = OpAccessChain %19 %16 %24 %33
%222 = OpAccessChain %102 %65 %17 %24 %21
%223 = OpLoad %6 %222
OpStore %47 %223
%49 = OpAccessChain %19 %16 %24 %33
%224 = OpAccessChain %102 %65 %17 %24 %17
%225 = OpLoad %6 %224
OpStore %49 %225
%52 = OpAccessChain %51 %16 %27
%226 = OpAccessChain %101 %65 %17 %27
%227 = OpLoad %7 %226
OpStore %52 %227
%54 = OpAccessChain %51 %16 %27
%228 = OpAccessChain %101 %65 %24 %17
%229 = OpLoad %7 %228
OpStore %54 %229
%56 = OpAccessChain %51 %16 %27
%230 = OpAccessChain %101 %65 %24 %21
%231 = OpLoad %7 %230
OpStore %56 %231
%59 = OpAccessChain %58 %16 %30
OpStore %59 %57
OpReturn
OpFunctionEnd
)";
ASSERT_TRUE(IsEqual(env, after, context.get()));
}
TEST(TransformationReplaceConstantWithUniformTest,
DoNotReplaceVariableInitializer) {
// If a local variable has a constant initializer, this cannot be replaced
// by a uniform.
std::string shader = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource GLSL 450
OpMemberDecorate %16 0 Offset 0
OpDecorate %16 Block
OpDecorate %18 DescriptorSet 0
OpDecorate %18 Binding 0
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeInt 32 1
%7 = OpTypePointer Function %6
%50 = OpConstant %6 0
%16 = OpTypeStruct %6
%17 = OpTypePointer Uniform %16
%51 = OpTypePointer Uniform %6
%18 = OpVariable %17 Uniform
%4 = OpFunction %2 None %3
%5 = OpLabel
%8 = OpVariable %7 Function %50
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);
protobufs::UniformBufferElementDescriptor blockname_a =
MakeUniformBufferElementDescriptor(0, 0, {0});
ASSERT_TRUE(AddFactHelper(&transformation_context, 0, blockname_a));
ASSERT_FALSE(
TransformationReplaceConstantWithUniform(
MakeIdUseDescriptor(
50, MakeInstructionDescriptor(8, spv::Op::OpVariable, 0), 1),
blockname_a, 100, 101)
.IsApplicable(context.get(), transformation_context));
}
TEST(TransformationReplaceConstantWithUniformTest, ReplaceOpPhiOperand) {
std::string shader = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 320
OpDecorate %32 DescriptorSet 0
OpDecorate %32 Binding 0
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeInt 32 1
%7 = OpConstant %6 2
%13 = OpConstant %6 4
%21 = OpConstant %6 1
%34 = OpConstant %6 0
%10 = OpTypeBool
%30 = OpTypeStruct %6
%31 = OpTypePointer Uniform %30
%32 = OpVariable %31 Uniform
%33 = OpTypePointer Uniform %6
%4 = OpFunction %2 None %3
%11 = OpLabel
OpBranch %5
%5 = OpLabel
%23 = OpPhi %6 %7 %11 %20 %15
%9 = OpSLessThan %10 %23 %13
OpLoopMerge %8 %15 None
OpBranchConditional %9 %15 %8
%15 = OpLabel
%20 = OpIAdd %6 %23 %21
OpBranch %5
%8 = 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);
auto int_descriptor = MakeUniformBufferElementDescriptor(0, 0, {0});
ASSERT_TRUE(AddFactHelper(&transformation_context, 2, int_descriptor));
{
TransformationReplaceConstantWithUniform transformation(
MakeIdUseDescriptor(7, MakeInstructionDescriptor(23, spv::Op::OpPhi, 0),
0),
int_descriptor, 50, 51);
ASSERT_TRUE(
transformation.IsApplicable(context.get(), transformation_context));
ApplyAndCheckFreshIds(transformation, context.get(),
&transformation_context);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
context.get(), validator_options, kConsoleMessageConsumer));
}
std::string after_transformation = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 320
OpDecorate %32 DescriptorSet 0
OpDecorate %32 Binding 0
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeInt 32 1
%7 = OpConstant %6 2
%13 = OpConstant %6 4
%21 = OpConstant %6 1
%34 = OpConstant %6 0
%10 = OpTypeBool
%30 = OpTypeStruct %6
%31 = OpTypePointer Uniform %30
%32 = OpVariable %31 Uniform
%33 = OpTypePointer Uniform %6
%4 = OpFunction %2 None %3
%11 = OpLabel
%50 = OpAccessChain %33 %32 %34
%51 = OpLoad %6 %50
OpBranch %5
%5 = OpLabel
%23 = OpPhi %6 %51 %11 %20 %15
%9 = OpSLessThan %10 %23 %13
OpLoopMerge %8 %15 None
OpBranchConditional %9 %15 %8
%15 = OpLabel
%20 = OpIAdd %6 %23 %21
OpBranch %5
%8 = OpLabel
OpReturn
OpFunctionEnd
)";
ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
}
} // namespace
} // namespace fuzz
} // namespace spvtools