blob: 94a5b36674e3704726b4fadd111fbfaf2edeb237 [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_set_loop_control.h"
#include "gtest/gtest.h"
#include "source/fuzz/fuzzer_util.h"
#include "test/fuzz/fuzz_test_util.h"
namespace spvtools {
namespace fuzz {
namespace {
TEST(TransformationSetLoopControlTest, VariousScenarios) {
// This test features loops with various different controls, and goes through
// a number of acceptable and unacceptable transformations to those controls.
std::string shader = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 310
OpName %4 "main"
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeInt 32 1
%7 = OpTypePointer Function %6
%9 = OpConstant %6 0
%16 = OpConstant %6 100
%17 = OpTypeBool
%20 = OpConstant %6 1
%4 = OpFunction %2 None %3
%5 = OpLabel
%8 = OpVariable %7 Function
%22 = OpVariable %7 Function
%32 = OpVariable %7 Function
%42 = OpVariable %7 Function
%52 = OpVariable %7 Function
%62 = OpVariable %7 Function
%72 = OpVariable %7 Function
%82 = OpVariable %7 Function
%92 = OpVariable %7 Function
%102 = OpVariable %7 Function
%112 = OpVariable %7 Function
%122 = OpVariable %7 Function
OpStore %8 %9
OpBranch %10
%10 = OpLabel
%132 = OpPhi %6 %9 %5 %21 %13
OpLoopMerge %12 %13 None
OpBranch %14
%14 = OpLabel
%18 = OpSLessThan %17 %132 %16
OpBranchConditional %18 %11 %12
%11 = OpLabel
OpBranch %13
%13 = OpLabel
%21 = OpIAdd %6 %132 %20
OpStore %8 %21
OpBranch %10
%12 = OpLabel
OpStore %22 %9
OpBranch %23
%23 = OpLabel
%133 = OpPhi %6 %9 %12 %31 %26
OpLoopMerge %25 %26 Unroll
OpBranch %27
%27 = OpLabel
%29 = OpSLessThan %17 %133 %16
OpBranchConditional %29 %24 %25
%24 = OpLabel
OpBranch %26
%26 = OpLabel
%31 = OpIAdd %6 %133 %20
OpStore %22 %31
OpBranch %23
%25 = OpLabel
OpStore %32 %9
OpBranch %33
%33 = OpLabel
%134 = OpPhi %6 %9 %25 %41 %36
OpLoopMerge %35 %36 DontUnroll
OpBranch %37
%37 = OpLabel
%39 = OpSLessThan %17 %134 %16
OpBranchConditional %39 %34 %35
%34 = OpLabel
OpBranch %36
%36 = OpLabel
%41 = OpIAdd %6 %134 %20
OpStore %32 %41
OpBranch %33
%35 = OpLabel
OpStore %42 %9
OpBranch %43
%43 = OpLabel
%135 = OpPhi %6 %9 %35 %51 %46
OpLoopMerge %45 %46 DependencyInfinite
OpBranch %47
%47 = OpLabel
%49 = OpSLessThan %17 %135 %16
OpBranchConditional %49 %44 %45
%44 = OpLabel
OpBranch %46
%46 = OpLabel
%51 = OpIAdd %6 %135 %20
OpStore %42 %51
OpBranch %43
%45 = OpLabel
OpStore %52 %9
OpBranch %53
%53 = OpLabel
%136 = OpPhi %6 %9 %45 %61 %56
OpLoopMerge %55 %56 DependencyLength 3
OpBranch %57
%57 = OpLabel
%59 = OpSLessThan %17 %136 %16
OpBranchConditional %59 %54 %55
%54 = OpLabel
OpBranch %56
%56 = OpLabel
%61 = OpIAdd %6 %136 %20
OpStore %52 %61
OpBranch %53
%55 = OpLabel
OpStore %62 %9
OpBranch %63
%63 = OpLabel
%137 = OpPhi %6 %9 %55 %71 %66
OpLoopMerge %65 %66 MinIterations 10
OpBranch %67
%67 = OpLabel
%69 = OpSLessThan %17 %137 %16
OpBranchConditional %69 %64 %65
%64 = OpLabel
OpBranch %66
%66 = OpLabel
%71 = OpIAdd %6 %137 %20
OpStore %62 %71
OpBranch %63
%65 = OpLabel
OpStore %72 %9
OpBranch %73
%73 = OpLabel
%138 = OpPhi %6 %9 %65 %81 %76
OpLoopMerge %75 %76 MaxIterations 50
OpBranch %77
%77 = OpLabel
%79 = OpSLessThan %17 %138 %16
OpBranchConditional %79 %74 %75
%74 = OpLabel
OpBranch %76
%76 = OpLabel
%81 = OpIAdd %6 %138 %20
OpStore %72 %81
OpBranch %73
%75 = OpLabel
OpStore %82 %9
OpBranch %83
%83 = OpLabel
%139 = OpPhi %6 %9 %75 %91 %86
OpLoopMerge %85 %86 IterationMultiple 4
OpBranch %87
%87 = OpLabel
%89 = OpSLessThan %17 %139 %16
OpBranchConditional %89 %84 %85
%84 = OpLabel
OpBranch %86
%86 = OpLabel
%91 = OpIAdd %6 %139 %20
OpStore %82 %91
OpBranch %83
%85 = OpLabel
OpStore %92 %9
OpBranch %93
%93 = OpLabel
%140 = OpPhi %6 %9 %85 %101 %96
OpLoopMerge %95 %96 PeelCount 2
OpBranch %97
%97 = OpLabel
%99 = OpSLessThan %17 %140 %16
OpBranchConditional %99 %94 %95
%94 = OpLabel
OpBranch %96
%96 = OpLabel
%101 = OpIAdd %6 %140 %20
OpStore %92 %101
OpBranch %93
%95 = OpLabel
OpStore %102 %9
OpBranch %103
%103 = OpLabel
%141 = OpPhi %6 %9 %95 %111 %106
OpLoopMerge %105 %106 PartialCount 3
OpBranch %107
%107 = OpLabel
%109 = OpSLessThan %17 %141 %16
OpBranchConditional %109 %104 %105
%104 = OpLabel
OpBranch %106
%106 = OpLabel
%111 = OpIAdd %6 %141 %20
OpStore %102 %111
OpBranch %103
%105 = OpLabel
OpStore %112 %9
OpBranch %113
%113 = OpLabel
%142 = OpPhi %6 %9 %105 %121 %116
OpLoopMerge %115 %116 Unroll|PeelCount|PartialCount 3 4
OpBranch %117
%117 = OpLabel
%119 = OpSLessThan %17 %142 %16
OpBranchConditional %119 %114 %115
%114 = OpLabel
OpBranch %116
%116 = OpLabel
%121 = OpIAdd %6 %142 %20
OpStore %112 %121
OpBranch %113
%115 = OpLabel
OpStore %122 %9
OpBranch %123
%123 = OpLabel
%143 = OpPhi %6 %9 %115 %131 %126
OpLoopMerge %125 %126 DependencyLength|MinIterations|MaxIterations|IterationMultiple|PeelCount|PartialCount 2 5 90 4 7 14
OpBranch %127
%127 = OpLabel
%129 = OpSLessThan %17 %143 %16
OpBranchConditional %129 %124 %125
%124 = OpLabel
OpBranch %126
%126 = OpLabel
%131 = OpIAdd %6 %143 %20
OpStore %122 %131
OpBranch %123
%125 = OpLabel
OpReturn
OpFunctionEnd
)";
const auto env = SPV_ENV_UNIVERSAL_1_4;
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);
// These are the loop headers together with the selection controls of their
// merge instructions:
// %10 None
// %23 Unroll
// %33 DontUnroll
// %43 DependencyInfinite
// %53 DependencyLength 3
// %63 MinIterations 10
// %73 MaxIterations 50
// %83 IterationMultiple 4
// %93 PeelCount 2
// %103 PartialCount 3
// %113 Unroll|PeelCount|PartialCount 3 4
// %123
// DependencyLength|MinIterations|MaxIterations|IterationMultiple|PeelCount|PartialCount
// 2 5 90 4 7 14
ASSERT_TRUE(TransformationSetLoopControl(
10, (uint32_t)spv::LoopControlMask::MaskNone, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
10, (uint32_t)spv::LoopControlMask::Unroll, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
10, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_FALSE(TransformationSetLoopControl(
10, (uint32_t)spv::LoopControlMask::DependencyInfinite, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_FALSE(TransformationSetLoopControl(
10, (uint32_t)spv::LoopControlMask::DependencyLength, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_FALSE(TransformationSetLoopControl(
10, (uint32_t)spv::LoopControlMask::MinIterations, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_FALSE(TransformationSetLoopControl(
10, (uint32_t)spv::LoopControlMask::MaxIterations, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_FALSE(TransformationSetLoopControl(
10, (uint32_t)spv::LoopControlMask::IterationMultiple, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
10, (uint32_t)spv::LoopControlMask::PeelCount, 3, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_FALSE(TransformationSetLoopControl(
10, (uint32_t)spv::LoopControlMask::PeelCount, 3, 3)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
10, (uint32_t)spv::LoopControlMask::PartialCount, 0, 3)
.IsApplicable(context.get(), transformation_context));
ASSERT_FALSE(TransformationSetLoopControl(
10, (uint32_t)spv::LoopControlMask::PartialCount, 3, 3)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
10,
(uint32_t)spv::LoopControlMask::PeelCount |
(uint32_t)spv::LoopControlMask::PartialCount,
3, 3)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
10,
(uint32_t)spv::LoopControlMask::Unroll |
(uint32_t)spv::LoopControlMask::PeelCount |
(uint32_t)spv::LoopControlMask::PartialCount,
3, 3)
.IsApplicable(context.get(), transformation_context));
ASSERT_FALSE(TransformationSetLoopControl(
10,
(uint32_t)spv::LoopControlMask::DontUnroll |
(uint32_t)spv::LoopControlMask::PeelCount |
(uint32_t)spv::LoopControlMask::PartialCount,
3, 3)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
23, (uint32_t)spv::LoopControlMask::MaskNone, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
23, (uint32_t)spv::LoopControlMask::Unroll, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
23, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
23,
(uint32_t)spv::LoopControlMask::PeelCount |
(uint32_t)spv::LoopControlMask::PartialCount,
3, 3)
.IsApplicable(context.get(), transformation_context));
ASSERT_FALSE(TransformationSetLoopControl(
23, (uint32_t)spv::LoopControlMask::MaxIterations, 2, 3)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
33, (uint32_t)spv::LoopControlMask::MaskNone, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
33, (uint32_t)spv::LoopControlMask::Unroll, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
33, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_FALSE(TransformationSetLoopControl(
33, (uint32_t)spv::LoopControlMask::MinIterations, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
33,
(uint32_t)spv::LoopControlMask::Unroll |
(uint32_t)spv::LoopControlMask::PeelCount,
5, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_FALSE(TransformationSetLoopControl(
33,
(uint32_t)spv::LoopControlMask::DontUnroll |
(uint32_t)spv::LoopControlMask::PartialCount,
0, 10)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
43, (uint32_t)spv::LoopControlMask::MaskNone, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
43, (uint32_t)spv::LoopControlMask::Unroll, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
43, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
43,
(uint32_t)spv::LoopControlMask::MaskNone |
(uint32_t)spv::LoopControlMask::DependencyInfinite,
0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
43,
(uint32_t)spv::LoopControlMask::Unroll |
(uint32_t)spv::LoopControlMask::DependencyInfinite,
0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
43,
(uint32_t)spv::LoopControlMask::DontUnroll |
(uint32_t)spv::LoopControlMask::DependencyInfinite,
0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_FALSE(TransformationSetLoopControl(
43,
(uint32_t)spv::LoopControlMask::DependencyInfinite |
(uint32_t)spv::LoopControlMask::DependencyLength,
0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
43,
(uint32_t)spv::LoopControlMask::Unroll |
(uint32_t)spv::LoopControlMask::PeelCount,
5, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
53, (uint32_t)spv::LoopControlMask::MaskNone, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
53, (uint32_t)spv::LoopControlMask::Unroll, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
53, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_FALSE(TransformationSetLoopControl(
53, (uint32_t)spv::LoopControlMask::MaxIterations, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
53,
(uint32_t)spv::LoopControlMask::MaskNone |
(uint32_t)spv::LoopControlMask::DependencyLength,
0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_FALSE(TransformationSetLoopControl(
53,
(uint32_t)spv::LoopControlMask::Unroll |
(uint32_t)spv::LoopControlMask::DependencyInfinite,
0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
53,
(uint32_t)spv::LoopControlMask::DontUnroll |
(uint32_t)spv::LoopControlMask::DependencyLength,
0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_FALSE(TransformationSetLoopControl(
53,
(uint32_t)spv::LoopControlMask::DependencyInfinite |
(uint32_t)spv::LoopControlMask::DependencyLength,
0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
53,
(uint32_t)spv::LoopControlMask::Unroll |
(uint32_t)spv::LoopControlMask::DependencyLength |
(uint32_t)spv::LoopControlMask::PeelCount |
(uint32_t)spv::LoopControlMask::PartialCount,
5, 3)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
63, (uint32_t)spv::LoopControlMask::MaskNone, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
63, (uint32_t)spv::LoopControlMask::Unroll, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
63, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
63,
(uint32_t)spv::LoopControlMask::Unroll |
(uint32_t)spv::LoopControlMask::MinIterations |
(uint32_t)spv::LoopControlMask::PeelCount |
(uint32_t)spv::LoopControlMask::PartialCount,
5, 3)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
63,
(uint32_t)spv::LoopControlMask::Unroll |
(uint32_t)spv::LoopControlMask::MinIterations |
(uint32_t)spv::LoopControlMask::PeelCount,
23, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_FALSE(TransformationSetLoopControl(
63,
(uint32_t)spv::LoopControlMask::Unroll |
(uint32_t)spv::LoopControlMask::MinIterations |
(uint32_t)spv::LoopControlMask::PeelCount,
2, 23)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
73, (uint32_t)spv::LoopControlMask::MaskNone, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
73, (uint32_t)spv::LoopControlMask::Unroll, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
73, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_FALSE(TransformationSetLoopControl(
73,
(uint32_t)spv::LoopControlMask::Unroll |
(uint32_t)spv::LoopControlMask::MinIterations |
(uint32_t)spv::LoopControlMask::PeelCount |
(uint32_t)spv::LoopControlMask::PartialCount,
5, 3)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
73,
(uint32_t)spv::LoopControlMask::Unroll |
(uint32_t)spv::LoopControlMask::MaxIterations |
(uint32_t)spv::LoopControlMask::PeelCount,
23, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_FALSE(TransformationSetLoopControl(
73,
(uint32_t)spv::LoopControlMask::Unroll |
(uint32_t)spv::LoopControlMask::MaxIterations |
(uint32_t)spv::LoopControlMask::PeelCount,
2, 23)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
83, (uint32_t)spv::LoopControlMask::MaskNone, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
83, (uint32_t)spv::LoopControlMask::Unroll, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
83, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_FALSE(TransformationSetLoopControl(
83,
(uint32_t)spv::LoopControlMask::Unroll |
(uint32_t)spv::LoopControlMask::MinIterations |
(uint32_t)spv::LoopControlMask::PeelCount |
(uint32_t)spv::LoopControlMask::PartialCount,
5, 3)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
83,
(uint32_t)spv::LoopControlMask::Unroll |
(uint32_t)spv::LoopControlMask::IterationMultiple |
(uint32_t)spv::LoopControlMask::PeelCount,
23, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_FALSE(TransformationSetLoopControl(
83,
(uint32_t)spv::LoopControlMask::Unroll |
(uint32_t)spv::LoopControlMask::IterationMultiple |
(uint32_t)spv::LoopControlMask::PeelCount,
2, 23)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
93, (uint32_t)spv::LoopControlMask::MaskNone, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
93, (uint32_t)spv::LoopControlMask::Unroll, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
93, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
93, (uint32_t)spv::LoopControlMask::PeelCount, 8, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_FALSE(TransformationSetLoopControl(
93, (uint32_t)spv::LoopControlMask::PeelCount, 8, 8)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
93, (uint32_t)spv::LoopControlMask::PartialCount, 0, 8)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
93,
(uint32_t)spv::LoopControlMask::PeelCount |
(uint32_t)spv::LoopControlMask::PartialCount,
16, 8)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
103, (uint32_t)spv::LoopControlMask::MaskNone, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
103, (uint32_t)spv::LoopControlMask::Unroll, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
103, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
103, (uint32_t)spv::LoopControlMask::PartialCount, 0, 60)
.IsApplicable(context.get(), transformation_context));
ASSERT_FALSE(TransformationSetLoopControl(
103,
(uint32_t)spv::LoopControlMask::DontUnroll |
(uint32_t)spv::LoopControlMask::PartialCount,
0, 60)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
113, (uint32_t)spv::LoopControlMask::MaskNone, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
113, (uint32_t)spv::LoopControlMask::Unroll, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
113, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
113, (uint32_t)spv::LoopControlMask::PeelCount, 12, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_FALSE(TransformationSetLoopControl(
113,
(uint32_t)spv::LoopControlMask::IterationMultiple |
(uint32_t)spv::LoopControlMask::PeelCount,
12, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
123, (uint32_t)spv::LoopControlMask::MaskNone, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
123, (uint32_t)spv::LoopControlMask::Unroll, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
123, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
123,
(uint32_t)spv::LoopControlMask::MinIterations |
(uint32_t)spv::LoopControlMask::MaxIterations |
(uint32_t)spv::LoopControlMask::IterationMultiple |
(uint32_t)spv::LoopControlMask::PeelCount |
(uint32_t)spv::LoopControlMask::PartialCount,
7, 8)
.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(TransformationSetLoopControl(
123,
(uint32_t)spv::LoopControlMask::Unroll |
(uint32_t)spv::LoopControlMask::MinIterations |
(uint32_t)spv::LoopControlMask::MaxIterations |
(uint32_t)spv::LoopControlMask::PartialCount,
0, 9)
.IsApplicable(context.get(), transformation_context));
ASSERT_FALSE(TransformationSetLoopControl(
123,
(uint32_t)spv::LoopControlMask::Unroll |
(uint32_t)spv::LoopControlMask::MinIterations |
(uint32_t)spv::LoopControlMask::MaxIterations |
(uint32_t)spv::LoopControlMask::PartialCount,
7, 9)
.IsApplicable(context.get(), transformation_context));
ASSERT_FALSE(TransformationSetLoopControl(
123,
(uint32_t)spv::LoopControlMask::DontUnroll |
(uint32_t)spv::LoopControlMask::MinIterations |
(uint32_t)spv::LoopControlMask::MaxIterations |
(uint32_t)spv::LoopControlMask::PartialCount,
7, 9)
.IsApplicable(context.get(), transformation_context));
ApplyAndCheckFreshIds(TransformationSetLoopControl(
10,
(uint32_t)spv::LoopControlMask::Unroll |
(uint32_t)spv::LoopControlMask::PeelCount |
(uint32_t)spv::LoopControlMask::PartialCount,
3, 3),
context.get(), &transformation_context);
ApplyAndCheckFreshIds(
TransformationSetLoopControl(
23, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0),
context.get(), &transformation_context);
ApplyAndCheckFreshIds(TransformationSetLoopControl(
33, (uint32_t)spv::LoopControlMask::Unroll, 0, 0),
context.get(), &transformation_context);
ApplyAndCheckFreshIds(
TransformationSetLoopControl(
43,
(uint32_t)spv::LoopControlMask::DontUnroll |
(uint32_t)spv::LoopControlMask::DependencyInfinite,
0, 0),
context.get(), &transformation_context);
ApplyAndCheckFreshIds(TransformationSetLoopControl(
53, (uint32_t)spv::LoopControlMask::MaskNone, 0, 0),
context.get(), &transformation_context);
ApplyAndCheckFreshIds(TransformationSetLoopControl(
63,
(uint32_t)spv::LoopControlMask::Unroll |
(uint32_t)spv::LoopControlMask::MinIterations |
(uint32_t)spv::LoopControlMask::PeelCount,
23, 0),
context.get(), &transformation_context);
ApplyAndCheckFreshIds(TransformationSetLoopControl(
73,
(uint32_t)spv::LoopControlMask::Unroll |
(uint32_t)spv::LoopControlMask::MaxIterations |
(uint32_t)spv::LoopControlMask::PeelCount,
23, 0),
context.get(), &transformation_context);
ApplyAndCheckFreshIds(
TransformationSetLoopControl(
83, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0),
context.get(), &transformation_context);
ApplyAndCheckFreshIds(TransformationSetLoopControl(
93,
(uint32_t)spv::LoopControlMask::PeelCount |
(uint32_t)spv::LoopControlMask::PartialCount,
16, 8),
context.get(), &transformation_context);
ApplyAndCheckFreshIds(
TransformationSetLoopControl(
103, (uint32_t)spv::LoopControlMask::PartialCount, 0, 60),
context.get(), &transformation_context);
ApplyAndCheckFreshIds(
TransformationSetLoopControl(
113, (uint32_t)spv::LoopControlMask::PeelCount, 12, 0),
context.get(), &transformation_context);
ApplyAndCheckFreshIds(TransformationSetLoopControl(
123,
(uint32_t)spv::LoopControlMask::Unroll |
(uint32_t)spv::LoopControlMask::MinIterations |
(uint32_t)spv::LoopControlMask::MaxIterations |
(uint32_t)spv::LoopControlMask::PartialCount,
0, 9),
context.get(), &transformation_context);
std::string after_transformation = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 310
OpName %4 "main"
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeInt 32 1
%7 = OpTypePointer Function %6
%9 = OpConstant %6 0
%16 = OpConstant %6 100
%17 = OpTypeBool
%20 = OpConstant %6 1
%4 = OpFunction %2 None %3
%5 = OpLabel
%8 = OpVariable %7 Function
%22 = OpVariable %7 Function
%32 = OpVariable %7 Function
%42 = OpVariable %7 Function
%52 = OpVariable %7 Function
%62 = OpVariable %7 Function
%72 = OpVariable %7 Function
%82 = OpVariable %7 Function
%92 = OpVariable %7 Function
%102 = OpVariable %7 Function
%112 = OpVariable %7 Function
%122 = OpVariable %7 Function
OpStore %8 %9
OpBranch %10
%10 = OpLabel
%132 = OpPhi %6 %9 %5 %21 %13
OpLoopMerge %12 %13 Unroll|PeelCount|PartialCount 3 3
OpBranch %14
%14 = OpLabel
%18 = OpSLessThan %17 %132 %16
OpBranchConditional %18 %11 %12
%11 = OpLabel
OpBranch %13
%13 = OpLabel
%21 = OpIAdd %6 %132 %20
OpStore %8 %21
OpBranch %10
%12 = OpLabel
OpStore %22 %9
OpBranch %23
%23 = OpLabel
%133 = OpPhi %6 %9 %12 %31 %26
OpLoopMerge %25 %26 DontUnroll
OpBranch %27
%27 = OpLabel
%29 = OpSLessThan %17 %133 %16
OpBranchConditional %29 %24 %25
%24 = OpLabel
OpBranch %26
%26 = OpLabel
%31 = OpIAdd %6 %133 %20
OpStore %22 %31
OpBranch %23
%25 = OpLabel
OpStore %32 %9
OpBranch %33
%33 = OpLabel
%134 = OpPhi %6 %9 %25 %41 %36
OpLoopMerge %35 %36 Unroll
OpBranch %37
%37 = OpLabel
%39 = OpSLessThan %17 %134 %16
OpBranchConditional %39 %34 %35
%34 = OpLabel
OpBranch %36
%36 = OpLabel
%41 = OpIAdd %6 %134 %20
OpStore %32 %41
OpBranch %33
%35 = OpLabel
OpStore %42 %9
OpBranch %43
%43 = OpLabel
%135 = OpPhi %6 %9 %35 %51 %46
OpLoopMerge %45 %46 DontUnroll|DependencyInfinite
OpBranch %47
%47 = OpLabel
%49 = OpSLessThan %17 %135 %16
OpBranchConditional %49 %44 %45
%44 = OpLabel
OpBranch %46
%46 = OpLabel
%51 = OpIAdd %6 %135 %20
OpStore %42 %51
OpBranch %43
%45 = OpLabel
OpStore %52 %9
OpBranch %53
%53 = OpLabel
%136 = OpPhi %6 %9 %45 %61 %56
OpLoopMerge %55 %56 None
OpBranch %57
%57 = OpLabel
%59 = OpSLessThan %17 %136 %16
OpBranchConditional %59 %54 %55
%54 = OpLabel
OpBranch %56
%56 = OpLabel
%61 = OpIAdd %6 %136 %20
OpStore %52 %61
OpBranch %53
%55 = OpLabel
OpStore %62 %9
OpBranch %63
%63 = OpLabel
%137 = OpPhi %6 %9 %55 %71 %66
OpLoopMerge %65 %66 Unroll|MinIterations|PeelCount 10 23
OpBranch %67
%67 = OpLabel
%69 = OpSLessThan %17 %137 %16
OpBranchConditional %69 %64 %65
%64 = OpLabel
OpBranch %66
%66 = OpLabel
%71 = OpIAdd %6 %137 %20
OpStore %62 %71
OpBranch %63
%65 = OpLabel
OpStore %72 %9
OpBranch %73
%73 = OpLabel
%138 = OpPhi %6 %9 %65 %81 %76
OpLoopMerge %75 %76 Unroll|MaxIterations|PeelCount 50 23
OpBranch %77
%77 = OpLabel
%79 = OpSLessThan %17 %138 %16
OpBranchConditional %79 %74 %75
%74 = OpLabel
OpBranch %76
%76 = OpLabel
%81 = OpIAdd %6 %138 %20
OpStore %72 %81
OpBranch %73
%75 = OpLabel
OpStore %82 %9
OpBranch %83
%83 = OpLabel
%139 = OpPhi %6 %9 %75 %91 %86
OpLoopMerge %85 %86 DontUnroll
OpBranch %87
%87 = OpLabel
%89 = OpSLessThan %17 %139 %16
OpBranchConditional %89 %84 %85
%84 = OpLabel
OpBranch %86
%86 = OpLabel
%91 = OpIAdd %6 %139 %20
OpStore %82 %91
OpBranch %83
%85 = OpLabel
OpStore %92 %9
OpBranch %93
%93 = OpLabel
%140 = OpPhi %6 %9 %85 %101 %96
OpLoopMerge %95 %96 PeelCount|PartialCount 16 8
OpBranch %97
%97 = OpLabel
%99 = OpSLessThan %17 %140 %16
OpBranchConditional %99 %94 %95
%94 = OpLabel
OpBranch %96
%96 = OpLabel
%101 = OpIAdd %6 %140 %20
OpStore %92 %101
OpBranch %93
%95 = OpLabel
OpStore %102 %9
OpBranch %103
%103 = OpLabel
%141 = OpPhi %6 %9 %95 %111 %106
OpLoopMerge %105 %106 PartialCount 60
OpBranch %107
%107 = OpLabel
%109 = OpSLessThan %17 %141 %16
OpBranchConditional %109 %104 %105
%104 = OpLabel
OpBranch %106
%106 = OpLabel
%111 = OpIAdd %6 %141 %20
OpStore %102 %111
OpBranch %103
%105 = OpLabel
OpStore %112 %9
OpBranch %113
%113 = OpLabel
%142 = OpPhi %6 %9 %105 %121 %116
OpLoopMerge %115 %116 PeelCount 12
OpBranch %117
%117 = OpLabel
%119 = OpSLessThan %17 %142 %16
OpBranchConditional %119 %114 %115
%114 = OpLabel
OpBranch %116
%116 = OpLabel
%121 = OpIAdd %6 %142 %20
OpStore %112 %121
OpBranch %113
%115 = OpLabel
OpStore %122 %9
OpBranch %123
%123 = OpLabel
%143 = OpPhi %6 %9 %115 %131 %126
OpLoopMerge %125 %126 Unroll|MinIterations|MaxIterations|PartialCount 5 90 9
OpBranch %127
%127 = OpLabel
%129 = OpSLessThan %17 %143 %16
OpBranchConditional %129 %124 %125
%124 = OpLabel
OpBranch %126
%126 = OpLabel
%131 = OpIAdd %6 %143 %20
OpStore %122 %131
OpBranch %123
%125 = OpLabel
OpReturn
OpFunctionEnd
)";
ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
}
TEST(TransformationSetLoopControlTest, CheckSPIRVVersionsRespected) {
// This test checks that we do not allow introducing PeelCount and
// PartialCount loop controls if the SPIR-V version being used does not
// support them.
std::string shader = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 310
OpName %4 "main"
OpName %8 "i"
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeInt 32 1
%7 = OpTypePointer Function %6
%9 = OpConstant %6 0
%16 = OpConstant %6 10
%17 = OpTypeBool
%20 = OpConstant %6 1
%4 = OpFunction %2 None %3
%5 = OpLabel
%8 = OpVariable %7 Function
OpStore %8 %9
OpBranch %10
%10 = OpLabel
OpLoopMerge %12 %13 None
OpBranch %14
%14 = OpLabel
%15 = OpLoad %6 %8
%18 = OpSLessThan %17 %15 %16
OpBranchConditional %18 %11 %12
%11 = OpLabel
OpBranch %13
%13 = OpLabel
%19 = OpLoad %6 %8
%21 = OpIAdd %6 %19 %20
OpStore %8 %21
OpBranch %10
%12 = OpLabel
OpReturn
OpFunctionEnd
)";
for (auto env :
{SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1, SPV_ENV_UNIVERSAL_1_2,
SPV_ENV_UNIVERSAL_1_3, SPV_ENV_UNIVERSAL_1_4, SPV_ENV_UNIVERSAL_1_5,
SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_1, SPV_ENV_VULKAN_1_1_SPIRV_1_4,
SPV_ENV_VULKAN_1_2}) {
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);
TransformationSetLoopControl peel_count(
10, (uint32_t)spv::LoopControlMask::PeelCount, 4, 0);
TransformationSetLoopControl partial_count(
10, (uint32_t)spv::LoopControlMask::PartialCount, 0, 4);
switch (env) {
case SPV_ENV_UNIVERSAL_1_0:
case SPV_ENV_UNIVERSAL_1_1:
case SPV_ENV_UNIVERSAL_1_2:
case SPV_ENV_UNIVERSAL_1_3:
case SPV_ENV_VULKAN_1_0:
case SPV_ENV_VULKAN_1_1:
// PeelCount and PartialCount were introduced in SPIRV 1.4, so are not
// valid in the context of older versions.
ASSERT_FALSE(
peel_count.IsApplicable(context.get(), transformation_context));
ASSERT_FALSE(
partial_count.IsApplicable(context.get(), transformation_context));
break;
case SPV_ENV_UNIVERSAL_1_4:
case SPV_ENV_UNIVERSAL_1_5:
case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
case SPV_ENV_VULKAN_1_2:
ASSERT_TRUE(
peel_count.IsApplicable(context.get(), transformation_context));
ASSERT_TRUE(
partial_count.IsApplicable(context.get(), transformation_context));
break;
default:
assert(false && "Unhandled environment");
break;
}
}
}
} // namespace
} // namespace fuzz
} // namespace spvtools