mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-11-24 04:20:13 +00:00
eda2cfbe12
This Cl cleans up the include paths to be relative to the top level directory. Various include-what-you-use fixes have been added.
3492 lines
85 KiB
C++
3492 lines
85 KiB
C++
// Copyright (c) 2018 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 <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "gmock/gmock.h"
|
|
#include "source/opt/loop_fission.h"
|
|
#include "source/opt/loop_unroller.h"
|
|
#include "source/opt/loop_utils.h"
|
|
#include "source/opt/pass.h"
|
|
#include "test/opt/assembly_builder.h"
|
|
#include "test/opt/function_utils.h"
|
|
#include "test/opt/pass_fixture.h"
|
|
#include "test/opt/pass_utils.h"
|
|
|
|
namespace spvtools {
|
|
namespace opt {
|
|
namespace {
|
|
|
|
using ::testing::UnorderedElementsAre;
|
|
using FissionClassTest = PassTest<::testing::Test>;
|
|
|
|
/*
|
|
Generated from the following GLSL
|
|
|
|
#version 430
|
|
|
|
void main(void) {
|
|
float A[10];
|
|
float B[10];
|
|
for (int i = 0; i < 10; i++) {
|
|
A[i] = B[i];
|
|
B[i] = A[i];
|
|
}
|
|
}
|
|
|
|
Result should be equivalent to:
|
|
|
|
void main(void) {
|
|
float A[10];
|
|
float B[10];
|
|
for (int i = 0; i < 10; i++) {
|
|
A[i] = B[i];
|
|
}
|
|
|
|
for (int i = 0; i < 10; i++) {
|
|
B[i] = A[i];
|
|
}
|
|
}
|
|
*/
|
|
TEST_F(FissionClassTest, SimpleFission) {
|
|
// clang-format off
|
|
// With LocalMultiStoreElimPass
|
|
const std::string source = R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
OpName %2 "main"
|
|
OpName %3 "i"
|
|
OpName %4 "A"
|
|
OpName %5 "B"
|
|
%6 = OpTypeVoid
|
|
%7 = OpTypeFunction %6
|
|
%8 = OpTypeInt 32 1
|
|
%9 = OpTypePointer Function %8
|
|
%10 = OpConstant %8 0
|
|
%11 = OpConstant %8 10
|
|
%12 = OpTypeBool
|
|
%13 = OpTypeFloat 32
|
|
%14 = OpTypeInt 32 0
|
|
%15 = OpConstant %14 10
|
|
%16 = OpTypeArray %13 %15
|
|
%17 = OpTypePointer Function %16
|
|
%18 = OpTypePointer Function %13
|
|
%19 = OpConstant %8 1
|
|
%2 = OpFunction %6 None %7
|
|
%20 = OpLabel
|
|
%3 = OpVariable %9 Function
|
|
%4 = OpVariable %17 Function
|
|
%5 = OpVariable %17 Function
|
|
OpBranch %21
|
|
%21 = OpLabel
|
|
%22 = OpPhi %8 %10 %20 %23 %24
|
|
OpLoopMerge %25 %24 None
|
|
OpBranch %26
|
|
%26 = OpLabel
|
|
%27 = OpSLessThan %12 %22 %11
|
|
OpBranchConditional %27 %28 %25
|
|
%28 = OpLabel
|
|
%29 = OpAccessChain %18 %5 %22
|
|
%30 = OpLoad %13 %29
|
|
%31 = OpAccessChain %18 %4 %22
|
|
OpStore %31 %30
|
|
%32 = OpAccessChain %18 %4 %22
|
|
%33 = OpLoad %13 %32
|
|
%34 = OpAccessChain %18 %5 %22
|
|
OpStore %34 %33
|
|
OpBranch %24
|
|
%24 = OpLabel
|
|
%23 = OpIAdd %8 %22 %19
|
|
OpBranch %21
|
|
%25 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string expected = R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
OpName %2 "main"
|
|
OpName %3 "i"
|
|
OpName %4 "A"
|
|
OpName %5 "B"
|
|
%6 = OpTypeVoid
|
|
%7 = OpTypeFunction %6
|
|
%8 = OpTypeInt 32 1
|
|
%9 = OpTypePointer Function %8
|
|
%10 = OpConstant %8 0
|
|
%11 = OpConstant %8 10
|
|
%12 = OpTypeBool
|
|
%13 = OpTypeFloat 32
|
|
%14 = OpTypeInt 32 0
|
|
%15 = OpConstant %14 10
|
|
%16 = OpTypeArray %13 %15
|
|
%17 = OpTypePointer Function %16
|
|
%18 = OpTypePointer Function %13
|
|
%19 = OpConstant %8 1
|
|
%2 = OpFunction %6 None %7
|
|
%20 = OpLabel
|
|
%3 = OpVariable %9 Function
|
|
%4 = OpVariable %17 Function
|
|
%5 = OpVariable %17 Function
|
|
OpBranch %35
|
|
%35 = OpLabel
|
|
%36 = OpPhi %8 %10 %20 %47 %46
|
|
OpLoopMerge %48 %46 None
|
|
OpBranch %37
|
|
%37 = OpLabel
|
|
%38 = OpSLessThan %12 %36 %11
|
|
OpBranchConditional %38 %39 %48
|
|
%39 = OpLabel
|
|
%40 = OpAccessChain %18 %5 %36
|
|
%41 = OpLoad %13 %40
|
|
%42 = OpAccessChain %18 %4 %36
|
|
OpStore %42 %41
|
|
OpBranch %46
|
|
%46 = OpLabel
|
|
%47 = OpIAdd %8 %36 %19
|
|
OpBranch %35
|
|
%48 = OpLabel
|
|
OpBranch %21
|
|
%21 = OpLabel
|
|
%22 = OpPhi %8 %10 %48 %23 %24
|
|
OpLoopMerge %25 %24 None
|
|
OpBranch %26
|
|
%26 = OpLabel
|
|
%27 = OpSLessThan %12 %22 %11
|
|
OpBranchConditional %27 %28 %25
|
|
%28 = OpLabel
|
|
%32 = OpAccessChain %18 %4 %22
|
|
%33 = OpLoad %13 %32
|
|
%34 = OpAccessChain %18 %5 %22
|
|
OpStore %34 %33
|
|
OpBranch %24
|
|
%24 = OpLabel
|
|
%23 = OpIAdd %8 %22 %19
|
|
OpBranch %21
|
|
%25 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
// clang-format on
|
|
std::unique_ptr<IRContext> context =
|
|
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
|
|
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
Module* module = context->module();
|
|
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
|
|
<< source << std::endl;
|
|
|
|
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
|
|
SinglePassRunAndCheck<LoopFissionPass>(source, expected, true);
|
|
|
|
// Check that the loop will NOT be split when provided with a pass-through
|
|
// register pressure functor which just returns false.
|
|
SinglePassRunAndCheck<LoopFissionPass>(
|
|
source, source, true,
|
|
[](const RegisterLiveness::RegionRegisterLiveness&) { return false; });
|
|
}
|
|
|
|
/*
|
|
Generated from the following GLSL
|
|
|
|
#version 430
|
|
|
|
void main(void) {
|
|
float A[10];
|
|
float B[10];
|
|
for (int i = 0; i < 10; i++) {
|
|
A[i] = B[i];
|
|
B[i] = A[i+1];
|
|
}
|
|
}
|
|
|
|
This loop should not be split, as the i+1 dependence would be broken by
|
|
splitting the loop.
|
|
*/
|
|
|
|
TEST_F(FissionClassTest, FissionInterdependency) {
|
|
// clang-format off
|
|
// With LocalMultiStoreElimPass
|
|
const std::string source = R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
OpName %2 "main"
|
|
OpName %3 "i"
|
|
OpName %4 "A"
|
|
OpName %5 "B"
|
|
%6 = OpTypeVoid
|
|
%7 = OpTypeFunction %6
|
|
%8 = OpTypeInt 32 1
|
|
%9 = OpTypePointer Function %8
|
|
%10 = OpConstant %8 0
|
|
%11 = OpConstant %8 10
|
|
%12 = OpTypeBool
|
|
%13 = OpTypeFloat 32
|
|
%14 = OpTypeInt 32 0
|
|
%15 = OpConstant %14 10
|
|
%16 = OpTypeArray %13 %15
|
|
%17 = OpTypePointer Function %16
|
|
%18 = OpTypePointer Function %13
|
|
%19 = OpConstant %8 1
|
|
%2 = OpFunction %6 None %7
|
|
%20 = OpLabel
|
|
%3 = OpVariable %9 Function
|
|
%4 = OpVariable %17 Function
|
|
%5 = OpVariable %17 Function
|
|
OpBranch %21
|
|
%21 = OpLabel
|
|
%22 = OpPhi %8 %10 %20 %23 %24
|
|
OpLoopMerge %25 %24 None
|
|
OpBranch %26
|
|
%26 = OpLabel
|
|
%27 = OpSLessThan %12 %22 %11
|
|
OpBranchConditional %27 %28 %25
|
|
%28 = OpLabel
|
|
%29 = OpAccessChain %18 %5 %22
|
|
%30 = OpLoad %13 %29
|
|
%31 = OpAccessChain %18 %4 %22
|
|
OpStore %31 %30
|
|
%32 = OpIAdd %8 %22 %19
|
|
%33 = OpAccessChain %18 %4 %32
|
|
%34 = OpLoad %13 %33
|
|
%35 = OpAccessChain %18 %5 %22
|
|
OpStore %35 %34
|
|
OpBranch %24
|
|
%24 = OpLabel
|
|
%23 = OpIAdd %8 %22 %19
|
|
OpBranch %21
|
|
%25 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
// clang-format on
|
|
std::unique_ptr<IRContext> context =
|
|
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
|
|
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
Module* module = context->module();
|
|
EXPECT_NE(nullptr, module) << "Assembling failed for ushader:\n"
|
|
<< source << std::endl;
|
|
|
|
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
|
|
SinglePassRunAndCheck<LoopFissionPass>(source, source, true);
|
|
}
|
|
|
|
/*
|
|
Generated from the following GLSL
|
|
|
|
#version 430
|
|
|
|
void main(void) {
|
|
float A[10];
|
|
float B[10];
|
|
for (int i = 0; i < 10; i++) {
|
|
A[i] = B[i];
|
|
B[i+1] = A[i];
|
|
}
|
|
}
|
|
|
|
|
|
This should not be split as the load B[i] is dependent on the store B[i+1]
|
|
*/
|
|
TEST_F(FissionClassTest, FissionInterdependency2) {
|
|
// clang-format off
|
|
// With LocalMultiStoreElimPass
|
|
const std::string source = R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
OpName %2 "main"
|
|
OpName %3 "i"
|
|
OpName %4 "A"
|
|
OpName %5 "B"
|
|
%6 = OpTypeVoid
|
|
%7 = OpTypeFunction %6
|
|
%8 = OpTypeInt 32 1
|
|
%9 = OpTypePointer Function %8
|
|
%10 = OpConstant %8 0
|
|
%11 = OpConstant %8 10
|
|
%12 = OpTypeBool
|
|
%13 = OpTypeFloat 32
|
|
%14 = OpTypeInt 32 0
|
|
%15 = OpConstant %14 10
|
|
%16 = OpTypeArray %13 %15
|
|
%17 = OpTypePointer Function %16
|
|
%18 = OpTypePointer Function %13
|
|
%19 = OpConstant %8 1
|
|
%2 = OpFunction %6 None %7
|
|
%20 = OpLabel
|
|
%3 = OpVariable %9 Function
|
|
%4 = OpVariable %17 Function
|
|
%5 = OpVariable %17 Function
|
|
OpBranch %21
|
|
%21 = OpLabel
|
|
%22 = OpPhi %8 %10 %20 %23 %24
|
|
OpLoopMerge %25 %24 None
|
|
OpBranch %26
|
|
%26 = OpLabel
|
|
%27 = OpSLessThan %12 %22 %11
|
|
OpBranchConditional %27 %28 %25
|
|
%28 = OpLabel
|
|
%29 = OpAccessChain %18 %5 %22
|
|
%30 = OpLoad %13 %29
|
|
%31 = OpAccessChain %18 %4 %22
|
|
OpStore %31 %30
|
|
%32 = OpIAdd %8 %22 %19
|
|
%33 = OpAccessChain %18 %4 %22
|
|
%34 = OpLoad %13 %33
|
|
%35 = OpAccessChain %18 %5 %32
|
|
OpStore %35 %34
|
|
OpBranch %24
|
|
%24 = OpLabel
|
|
%23 = OpIAdd %8 %22 %19
|
|
OpBranch %21
|
|
%25 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
// clang-format on
|
|
std::unique_ptr<IRContext> context =
|
|
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
|
|
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
Module* module = context->module();
|
|
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
|
|
<< source << std::endl;
|
|
|
|
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
|
|
SinglePassRunAndCheck<LoopFissionPass>(source, source, true);
|
|
}
|
|
|
|
/*
|
|
#version 430
|
|
void main(void) {
|
|
float A[10];
|
|
float B[10];
|
|
float C[10]
|
|
float D[10]
|
|
for (int i = 0; i < 10; i++) {
|
|
A[i] = B[i];
|
|
B[i] = A[i];
|
|
C[i] = D[i];
|
|
D[i] = C[i];
|
|
}
|
|
}
|
|
|
|
This should be split into the equivalent of:
|
|
|
|
for (int i = 0; i < 10; i++) {
|
|
A[i] = B[i];
|
|
B[i] = A[i];
|
|
}
|
|
for (int i = 0; i < 10; i++) {
|
|
C[i] = D[i];
|
|
D[i] = C[i];
|
|
}
|
|
|
|
We then check that the loop is broken into four for loops like so, if the pass
|
|
is run twice:
|
|
for (int i = 0; i < 10; i++)
|
|
A[i] = B[i];
|
|
for (int i = 0; i < 10; i++)
|
|
B[i] = A[i];
|
|
for (int i = 0; i < 10; i++)
|
|
C[i] = D[i];
|
|
for (int i = 0; i < 10; i++)
|
|
D[i] = C[i];
|
|
|
|
*/
|
|
|
|
TEST_F(FissionClassTest, FissionMultipleLoadStores) {
|
|
// clang-format off
|
|
// With LocalMultiStoreElimPass
|
|
const std::string source = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
OpName %2 "main"
|
|
OpName %3 "i"
|
|
OpName %4 "A"
|
|
OpName %5 "B"
|
|
OpName %6 "C"
|
|
OpName %7 "D"
|
|
%8 = OpTypeVoid
|
|
%9 = OpTypeFunction %8
|
|
%10 = OpTypeInt 32 1
|
|
%11 = OpTypePointer Function %10
|
|
%12 = OpConstant %10 0
|
|
%13 = OpConstant %10 10
|
|
%14 = OpTypeBool
|
|
%15 = OpTypeFloat 32
|
|
%16 = OpTypeInt 32 0
|
|
%17 = OpConstant %16 10
|
|
%18 = OpTypeArray %15 %17
|
|
%19 = OpTypePointer Function %18
|
|
%20 = OpTypePointer Function %15
|
|
%21 = OpConstant %10 1
|
|
%2 = OpFunction %8 None %9
|
|
%22 = OpLabel
|
|
%3 = OpVariable %11 Function
|
|
%4 = OpVariable %19 Function
|
|
%5 = OpVariable %19 Function
|
|
%6 = OpVariable %19 Function
|
|
%7 = OpVariable %19 Function
|
|
OpBranch %23
|
|
%23 = OpLabel
|
|
%24 = OpPhi %10 %12 %22 %25 %26
|
|
OpLoopMerge %27 %26 None
|
|
OpBranch %28
|
|
%28 = OpLabel
|
|
%29 = OpSLessThan %14 %24 %13
|
|
OpBranchConditional %29 %30 %27
|
|
%30 = OpLabel
|
|
%31 = OpAccessChain %20 %5 %24
|
|
%32 = OpLoad %15 %31
|
|
%33 = OpAccessChain %20 %4 %24
|
|
OpStore %33 %32
|
|
%34 = OpAccessChain %20 %4 %24
|
|
%35 = OpLoad %15 %34
|
|
%36 = OpAccessChain %20 %5 %24
|
|
OpStore %36 %35
|
|
%37 = OpAccessChain %20 %7 %24
|
|
%38 = OpLoad %15 %37
|
|
%39 = OpAccessChain %20 %6 %24
|
|
OpStore %39 %38
|
|
%40 = OpAccessChain %20 %6 %24
|
|
%41 = OpLoad %15 %40
|
|
%42 = OpAccessChain %20 %7 %24
|
|
OpStore %42 %41
|
|
OpBranch %26
|
|
%26 = OpLabel
|
|
%25 = OpIAdd %10 %24 %21
|
|
OpBranch %23
|
|
%27 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string expected = R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
OpName %2 "main"
|
|
OpName %3 "i"
|
|
OpName %4 "A"
|
|
OpName %5 "B"
|
|
OpName %6 "C"
|
|
OpName %7 "D"
|
|
%8 = OpTypeVoid
|
|
%9 = OpTypeFunction %8
|
|
%10 = OpTypeInt 32 1
|
|
%11 = OpTypePointer Function %10
|
|
%12 = OpConstant %10 0
|
|
%13 = OpConstant %10 10
|
|
%14 = OpTypeBool
|
|
%15 = OpTypeFloat 32
|
|
%16 = OpTypeInt 32 0
|
|
%17 = OpConstant %16 10
|
|
%18 = OpTypeArray %15 %17
|
|
%19 = OpTypePointer Function %18
|
|
%20 = OpTypePointer Function %15
|
|
%21 = OpConstant %10 1
|
|
%2 = OpFunction %8 None %9
|
|
%22 = OpLabel
|
|
%3 = OpVariable %11 Function
|
|
%4 = OpVariable %19 Function
|
|
%5 = OpVariable %19 Function
|
|
%6 = OpVariable %19 Function
|
|
%7 = OpVariable %19 Function
|
|
OpBranch %43
|
|
%43 = OpLabel
|
|
%44 = OpPhi %10 %12 %22 %61 %60
|
|
OpLoopMerge %62 %60 None
|
|
OpBranch %45
|
|
%45 = OpLabel
|
|
%46 = OpSLessThan %14 %44 %13
|
|
OpBranchConditional %46 %47 %62
|
|
%47 = OpLabel
|
|
%48 = OpAccessChain %20 %5 %44
|
|
%49 = OpLoad %15 %48
|
|
%50 = OpAccessChain %20 %4 %44
|
|
OpStore %50 %49
|
|
%51 = OpAccessChain %20 %4 %44
|
|
%52 = OpLoad %15 %51
|
|
%53 = OpAccessChain %20 %5 %44
|
|
OpStore %53 %52
|
|
OpBranch %60
|
|
%60 = OpLabel
|
|
%61 = OpIAdd %10 %44 %21
|
|
OpBranch %43
|
|
%62 = OpLabel
|
|
OpBranch %23
|
|
%23 = OpLabel
|
|
%24 = OpPhi %10 %12 %62 %25 %26
|
|
OpLoopMerge %27 %26 None
|
|
OpBranch %28
|
|
%28 = OpLabel
|
|
%29 = OpSLessThan %14 %24 %13
|
|
OpBranchConditional %29 %30 %27
|
|
%30 = OpLabel
|
|
%37 = OpAccessChain %20 %7 %24
|
|
%38 = OpLoad %15 %37
|
|
%39 = OpAccessChain %20 %6 %24
|
|
OpStore %39 %38
|
|
%40 = OpAccessChain %20 %6 %24
|
|
%41 = OpLoad %15 %40
|
|
%42 = OpAccessChain %20 %7 %24
|
|
OpStore %42 %41
|
|
OpBranch %26
|
|
%26 = OpLabel
|
|
%25 = OpIAdd %10 %24 %21
|
|
OpBranch %23
|
|
%27 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
|
|
const std::string expected_multiple_passes = R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
OpName %2 "main"
|
|
OpName %3 "i"
|
|
OpName %4 "A"
|
|
OpName %5 "B"
|
|
OpName %6 "C"
|
|
OpName %7 "D"
|
|
%8 = OpTypeVoid
|
|
%9 = OpTypeFunction %8
|
|
%10 = OpTypeInt 32 1
|
|
%11 = OpTypePointer Function %10
|
|
%12 = OpConstant %10 0
|
|
%13 = OpConstant %10 10
|
|
%14 = OpTypeBool
|
|
%15 = OpTypeFloat 32
|
|
%16 = OpTypeInt 32 0
|
|
%17 = OpConstant %16 10
|
|
%18 = OpTypeArray %15 %17
|
|
%19 = OpTypePointer Function %18
|
|
%20 = OpTypePointer Function %15
|
|
%21 = OpConstant %10 1
|
|
%2 = OpFunction %8 None %9
|
|
%22 = OpLabel
|
|
%3 = OpVariable %11 Function
|
|
%4 = OpVariable %19 Function
|
|
%5 = OpVariable %19 Function
|
|
%6 = OpVariable %19 Function
|
|
%7 = OpVariable %19 Function
|
|
OpBranch %63
|
|
%63 = OpLabel
|
|
%64 = OpPhi %10 %12 %22 %75 %74
|
|
OpLoopMerge %76 %74 None
|
|
OpBranch %65
|
|
%65 = OpLabel
|
|
%66 = OpSLessThan %14 %64 %13
|
|
OpBranchConditional %66 %67 %76
|
|
%67 = OpLabel
|
|
%68 = OpAccessChain %20 %5 %64
|
|
%69 = OpLoad %15 %68
|
|
%70 = OpAccessChain %20 %4 %64
|
|
OpStore %70 %69
|
|
OpBranch %74
|
|
%74 = OpLabel
|
|
%75 = OpIAdd %10 %64 %21
|
|
OpBranch %63
|
|
%76 = OpLabel
|
|
OpBranch %43
|
|
%43 = OpLabel
|
|
%44 = OpPhi %10 %12 %76 %61 %60
|
|
OpLoopMerge %62 %60 None
|
|
OpBranch %45
|
|
%45 = OpLabel
|
|
%46 = OpSLessThan %14 %44 %13
|
|
OpBranchConditional %46 %47 %62
|
|
%47 = OpLabel
|
|
%51 = OpAccessChain %20 %4 %44
|
|
%52 = OpLoad %15 %51
|
|
%53 = OpAccessChain %20 %5 %44
|
|
OpStore %53 %52
|
|
OpBranch %60
|
|
%60 = OpLabel
|
|
%61 = OpIAdd %10 %44 %21
|
|
OpBranch %43
|
|
%62 = OpLabel
|
|
OpBranch %77
|
|
%77 = OpLabel
|
|
%78 = OpPhi %10 %12 %62 %89 %88
|
|
OpLoopMerge %90 %88 None
|
|
OpBranch %79
|
|
%79 = OpLabel
|
|
%80 = OpSLessThan %14 %78 %13
|
|
OpBranchConditional %80 %81 %90
|
|
%81 = OpLabel
|
|
%82 = OpAccessChain %20 %7 %78
|
|
%83 = OpLoad %15 %82
|
|
%84 = OpAccessChain %20 %6 %78
|
|
OpStore %84 %83
|
|
OpBranch %88
|
|
%88 = OpLabel
|
|
%89 = OpIAdd %10 %78 %21
|
|
OpBranch %77
|
|
%90 = OpLabel
|
|
OpBranch %23
|
|
%23 = OpLabel
|
|
%24 = OpPhi %10 %12 %90 %25 %26
|
|
OpLoopMerge %27 %26 None
|
|
OpBranch %28
|
|
%28 = OpLabel
|
|
%29 = OpSLessThan %14 %24 %13
|
|
OpBranchConditional %29 %30 %27
|
|
%30 = OpLabel
|
|
%40 = OpAccessChain %20 %6 %24
|
|
%41 = OpLoad %15 %40
|
|
%42 = OpAccessChain %20 %7 %24
|
|
OpStore %42 %41
|
|
OpBranch %26
|
|
%26 = OpLabel
|
|
%25 = OpIAdd %10 %24 %21
|
|
OpBranch %23
|
|
%27 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
// clang-format on
|
|
std::unique_ptr<IRContext> context =
|
|
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
|
|
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
Module* module = context->module();
|
|
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
|
|
<< source << std::endl;
|
|
|
|
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
|
|
SinglePassRunAndCheck<LoopFissionPass>(source, expected, true);
|
|
|
|
// By passing 1 as argument we are using the constructor which makes the
|
|
// critera to split the loop be if the registers in the loop exceede 1. By
|
|
// using this constructor we are also enabling multiple passes (disabled by
|
|
// default).
|
|
SinglePassRunAndCheck<LoopFissionPass>(source, expected_multiple_passes, true,
|
|
1);
|
|
}
|
|
|
|
/*
|
|
#version 430
|
|
void main(void) {
|
|
int accumulator = 0;
|
|
float X[10];
|
|
float Y[10];
|
|
|
|
for (int i = 0; i < 10; i++) {
|
|
X[i] = Y[i];
|
|
Y[i] = X[i];
|
|
accumulator += i;
|
|
}
|
|
}
|
|
|
|
This should be split into the equivalent of:
|
|
|
|
#version 430
|
|
void main(void) {
|
|
int accumulator = 0;
|
|
float X[10];
|
|
float Y[10];
|
|
|
|
for (int i = 0; i < 10; i++) {
|
|
X[i] = Y[i];
|
|
}
|
|
for (int i = 0; i < 10; i++) {
|
|
Y[i] = X[i];
|
|
accumulator += i;
|
|
}
|
|
}
|
|
*/
|
|
TEST_F(FissionClassTest, FissionWithAccumulator) {
|
|
// clang-format off
|
|
// With LocalMultiStoreElimPass
|
|
const std::string source = R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
OpName %2 "main"
|
|
OpName %3 "accumulator"
|
|
OpName %4 "i"
|
|
OpName %5 "X"
|
|
OpName %6 "Y"
|
|
%7 = OpTypeVoid
|
|
%8 = OpTypeFunction %7
|
|
%9 = OpTypeInt 32 1
|
|
%10 = OpTypePointer Function %9
|
|
%11 = OpConstant %9 0
|
|
%12 = OpConstant %9 10
|
|
%13 = OpTypeBool
|
|
%14 = OpTypeFloat 32
|
|
%15 = OpTypeInt 32 0
|
|
%16 = OpConstant %15 10
|
|
%17 = OpTypeArray %14 %16
|
|
%18 = OpTypePointer Function %17
|
|
%19 = OpTypePointer Function %14
|
|
%20 = OpConstant %9 1
|
|
%2 = OpFunction %7 None %8
|
|
%21 = OpLabel
|
|
%3 = OpVariable %10 Function
|
|
%4 = OpVariable %10 Function
|
|
%5 = OpVariable %18 Function
|
|
%6 = OpVariable %18 Function
|
|
OpBranch %22
|
|
%22 = OpLabel
|
|
%23 = OpPhi %9 %11 %21 %24 %25
|
|
%26 = OpPhi %9 %11 %21 %27 %25
|
|
OpLoopMerge %28 %25 None
|
|
OpBranch %29
|
|
%29 = OpLabel
|
|
%30 = OpSLessThan %13 %26 %12
|
|
OpBranchConditional %30 %31 %28
|
|
%31 = OpLabel
|
|
%32 = OpAccessChain %19 %6 %26
|
|
%33 = OpLoad %14 %32
|
|
%34 = OpAccessChain %19 %5 %26
|
|
OpStore %34 %33
|
|
%35 = OpAccessChain %19 %5 %26
|
|
%36 = OpLoad %14 %35
|
|
%37 = OpAccessChain %19 %6 %26
|
|
OpStore %37 %36
|
|
%24 = OpIAdd %9 %23 %26
|
|
OpBranch %25
|
|
%25 = OpLabel
|
|
%27 = OpIAdd %9 %26 %20
|
|
OpBranch %22
|
|
%28 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string expected = R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
OpName %2 "main"
|
|
OpName %3 "accumulator"
|
|
OpName %4 "i"
|
|
OpName %5 "X"
|
|
OpName %6 "Y"
|
|
%7 = OpTypeVoid
|
|
%8 = OpTypeFunction %7
|
|
%9 = OpTypeInt 32 1
|
|
%10 = OpTypePointer Function %9
|
|
%11 = OpConstant %9 0
|
|
%12 = OpConstant %9 10
|
|
%13 = OpTypeBool
|
|
%14 = OpTypeFloat 32
|
|
%15 = OpTypeInt 32 0
|
|
%16 = OpConstant %15 10
|
|
%17 = OpTypeArray %14 %16
|
|
%18 = OpTypePointer Function %17
|
|
%19 = OpTypePointer Function %14
|
|
%20 = OpConstant %9 1
|
|
%2 = OpFunction %7 None %8
|
|
%21 = OpLabel
|
|
%3 = OpVariable %10 Function
|
|
%4 = OpVariable %10 Function
|
|
%5 = OpVariable %18 Function
|
|
%6 = OpVariable %18 Function
|
|
OpBranch %38
|
|
%38 = OpLabel
|
|
%40 = OpPhi %9 %11 %21 %52 %51
|
|
OpLoopMerge %53 %51 None
|
|
OpBranch %41
|
|
%41 = OpLabel
|
|
%42 = OpSLessThan %13 %40 %12
|
|
OpBranchConditional %42 %43 %53
|
|
%43 = OpLabel
|
|
%44 = OpAccessChain %19 %6 %40
|
|
%45 = OpLoad %14 %44
|
|
%46 = OpAccessChain %19 %5 %40
|
|
OpStore %46 %45
|
|
OpBranch %51
|
|
%51 = OpLabel
|
|
%52 = OpIAdd %9 %40 %20
|
|
OpBranch %38
|
|
%53 = OpLabel
|
|
OpBranch %22
|
|
%22 = OpLabel
|
|
%23 = OpPhi %9 %11 %53 %24 %25
|
|
%26 = OpPhi %9 %11 %53 %27 %25
|
|
OpLoopMerge %28 %25 None
|
|
OpBranch %29
|
|
%29 = OpLabel
|
|
%30 = OpSLessThan %13 %26 %12
|
|
OpBranchConditional %30 %31 %28
|
|
%31 = OpLabel
|
|
%35 = OpAccessChain %19 %5 %26
|
|
%36 = OpLoad %14 %35
|
|
%37 = OpAccessChain %19 %6 %26
|
|
OpStore %37 %36
|
|
%24 = OpIAdd %9 %23 %26
|
|
OpBranch %25
|
|
%25 = OpLabel
|
|
%27 = OpIAdd %9 %26 %20
|
|
OpBranch %22
|
|
%28 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
// clang-format on
|
|
std::unique_ptr<IRContext> context =
|
|
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
|
|
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
Module* module = context->module();
|
|
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
|
|
<< source << std::endl;
|
|
|
|
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
|
|
SinglePassRunAndCheck<LoopFissionPass>(source, expected, true);
|
|
}
|
|
|
|
/*
|
|
Generated from the following glsl:
|
|
|
|
#version 430
|
|
layout(location=0) out float x;
|
|
layout(location=1) out float y;
|
|
|
|
void main(void) {
|
|
float accumulator_1 = 0;
|
|
float accumulator_2 = 0;
|
|
for (int i = 0; i < 10; i++) {
|
|
accumulator_1 += i;
|
|
accumulator_2 += i;
|
|
}
|
|
|
|
x = accumulator_1;
|
|
y = accumulator_2;
|
|
}
|
|
|
|
Should be split into equivalent of:
|
|
|
|
void main(void) {
|
|
float accumulator_1 = 0;
|
|
float accumulator_2 = 0;
|
|
for (int i = 0; i < 10; i++) {
|
|
accumulator_1 += i;
|
|
}
|
|
|
|
for (int i = 0; i < 10; i++) {
|
|
accumulator_2 += i;
|
|
}
|
|
x = accumulator_1;
|
|
y = accumulator_2;
|
|
}
|
|
|
|
*/
|
|
TEST_F(FissionClassTest, FissionWithPhisUsedOutwithLoop) {
|
|
// clang-format off
|
|
// With LocalMultiStoreElimPass
|
|
const std::string source = R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main" %3 %4
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
OpName %2 "main"
|
|
OpName %5 "accumulator_1"
|
|
OpName %6 "accumulator_2"
|
|
OpName %7 "i"
|
|
OpName %3 "x"
|
|
OpName %4 "y"
|
|
OpDecorate %3 Location 0
|
|
OpDecorate %4 Location 1
|
|
%8 = OpTypeVoid
|
|
%9 = OpTypeFunction %8
|
|
%10 = OpTypeFloat 32
|
|
%11 = OpTypePointer Function %10
|
|
%12 = OpConstant %10 0
|
|
%13 = OpTypeInt 32 1
|
|
%14 = OpTypePointer Function %13
|
|
%15 = OpConstant %13 0
|
|
%16 = OpConstant %13 10
|
|
%17 = OpTypeBool
|
|
%18 = OpConstant %13 1
|
|
%19 = OpTypePointer Output %10
|
|
%3 = OpVariable %19 Output
|
|
%4 = OpVariable %19 Output
|
|
%2 = OpFunction %8 None %9
|
|
%20 = OpLabel
|
|
%5 = OpVariable %11 Function
|
|
%6 = OpVariable %11 Function
|
|
%7 = OpVariable %14 Function
|
|
OpBranch %21
|
|
%21 = OpLabel
|
|
%22 = OpPhi %10 %12 %20 %23 %24
|
|
%25 = OpPhi %10 %12 %20 %26 %24
|
|
%27 = OpPhi %13 %15 %20 %28 %24
|
|
OpLoopMerge %29 %24 None
|
|
OpBranch %30
|
|
%30 = OpLabel
|
|
%31 = OpSLessThan %17 %27 %16
|
|
OpBranchConditional %31 %32 %29
|
|
%32 = OpLabel
|
|
%33 = OpConvertSToF %10 %27
|
|
%26 = OpFAdd %10 %25 %33
|
|
%34 = OpConvertSToF %10 %27
|
|
%23 = OpFAdd %10 %22 %34
|
|
OpBranch %24
|
|
%24 = OpLabel
|
|
%28 = OpIAdd %13 %27 %18
|
|
OpStore %7 %28
|
|
OpBranch %21
|
|
%29 = OpLabel
|
|
OpStore %3 %25
|
|
OpStore %4 %22
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string expected = R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main" %3 %4
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
OpName %2 "main"
|
|
OpName %5 "accumulator_1"
|
|
OpName %6 "accumulator_2"
|
|
OpName %7 "i"
|
|
OpName %3 "x"
|
|
OpName %4 "y"
|
|
OpDecorate %3 Location 0
|
|
OpDecorate %4 Location 1
|
|
%8 = OpTypeVoid
|
|
%9 = OpTypeFunction %8
|
|
%10 = OpTypeFloat 32
|
|
%11 = OpTypePointer Function %10
|
|
%12 = OpConstant %10 0
|
|
%13 = OpTypeInt 32 1
|
|
%14 = OpTypePointer Function %13
|
|
%15 = OpConstant %13 0
|
|
%16 = OpConstant %13 10
|
|
%17 = OpTypeBool
|
|
%18 = OpConstant %13 1
|
|
%19 = OpTypePointer Output %10
|
|
%3 = OpVariable %19 Output
|
|
%4 = OpVariable %19 Output
|
|
%2 = OpFunction %8 None %9
|
|
%20 = OpLabel
|
|
%5 = OpVariable %11 Function
|
|
%6 = OpVariable %11 Function
|
|
%7 = OpVariable %14 Function
|
|
OpBranch %35
|
|
%35 = OpLabel
|
|
%37 = OpPhi %10 %12 %20 %43 %46
|
|
%38 = OpPhi %13 %15 %20 %47 %46
|
|
OpLoopMerge %48 %46 None
|
|
OpBranch %39
|
|
%39 = OpLabel
|
|
%40 = OpSLessThan %17 %38 %16
|
|
OpBranchConditional %40 %41 %48
|
|
%41 = OpLabel
|
|
%42 = OpConvertSToF %10 %38
|
|
%43 = OpFAdd %10 %37 %42
|
|
OpBranch %46
|
|
%46 = OpLabel
|
|
%47 = OpIAdd %13 %38 %18
|
|
OpStore %7 %47
|
|
OpBranch %35
|
|
%48 = OpLabel
|
|
OpBranch %21
|
|
%21 = OpLabel
|
|
%22 = OpPhi %10 %12 %48 %23 %24
|
|
%27 = OpPhi %13 %15 %48 %28 %24
|
|
OpLoopMerge %29 %24 None
|
|
OpBranch %30
|
|
%30 = OpLabel
|
|
%31 = OpSLessThan %17 %27 %16
|
|
OpBranchConditional %31 %32 %29
|
|
%32 = OpLabel
|
|
%34 = OpConvertSToF %10 %27
|
|
%23 = OpFAdd %10 %22 %34
|
|
OpBranch %24
|
|
%24 = OpLabel
|
|
%28 = OpIAdd %13 %27 %18
|
|
OpStore %7 %28
|
|
OpBranch %21
|
|
%29 = OpLabel
|
|
OpStore %3 %37
|
|
OpStore %4 %22
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
// clang-format on
|
|
std::unique_ptr<IRContext> context =
|
|
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
|
|
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
Module* module = context->module();
|
|
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
|
|
<< source << std::endl;
|
|
|
|
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
|
|
SinglePassRunAndCheck<LoopFissionPass>(source, expected, true);
|
|
}
|
|
|
|
/*
|
|
#version 430
|
|
void main(void) {
|
|
float A[10][10];
|
|
float B[10][10];
|
|
for (int i = 0; i < 10; i++) {
|
|
for (int j = 0; j < 10; j++) {
|
|
A[i][j] = B[i][j];
|
|
B[i][j] = A[i][j];
|
|
}
|
|
}
|
|
}
|
|
|
|
Should be split into equivalent of:
|
|
|
|
#version 430
|
|
void main(void) {
|
|
float A[10][10];
|
|
float B[10][10];
|
|
for (int i = 0; i < 10; i++) {
|
|
for (int j = 0; j < 10; j++) {
|
|
A[i][j] = B[i][j];
|
|
}
|
|
for (int j = 0; j < 10; j++) {
|
|
B[i][j] = A[i][j];
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
*/
|
|
TEST_F(FissionClassTest, FissionNested) {
|
|
// clang-format off
|
|
// With LocalMultiStoreElimPass
|
|
const std::string source = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
OpName %2 "main"
|
|
OpName %3 "i"
|
|
OpName %4 "j"
|
|
OpName %5 "A"
|
|
OpName %6 "B"
|
|
%7 = OpTypeVoid
|
|
%8 = OpTypeFunction %7
|
|
%9 = OpTypeInt 32 1
|
|
%10 = OpTypePointer Function %9
|
|
%11 = OpConstant %9 0
|
|
%12 = OpConstant %9 10
|
|
%13 = OpTypeBool
|
|
%14 = OpTypeFloat 32
|
|
%15 = OpTypeInt 32 0
|
|
%16 = OpConstant %15 10
|
|
%17 = OpTypeArray %14 %16
|
|
%18 = OpTypeArray %17 %16
|
|
%19 = OpTypePointer Function %18
|
|
%20 = OpTypePointer Function %14
|
|
%21 = OpConstant %9 1
|
|
%2 = OpFunction %7 None %8
|
|
%22 = OpLabel
|
|
%3 = OpVariable %10 Function
|
|
%4 = OpVariable %10 Function
|
|
%5 = OpVariable %19 Function
|
|
%6 = OpVariable %19 Function
|
|
OpStore %3 %11
|
|
OpBranch %23
|
|
%23 = OpLabel
|
|
%24 = OpPhi %9 %11 %22 %25 %26
|
|
OpLoopMerge %27 %26 None
|
|
OpBranch %28
|
|
%28 = OpLabel
|
|
%29 = OpSLessThan %13 %24 %12
|
|
OpBranchConditional %29 %30 %27
|
|
%30 = OpLabel
|
|
OpStore %4 %11
|
|
OpBranch %31
|
|
%31 = OpLabel
|
|
%32 = OpPhi %9 %11 %30 %33 %34
|
|
OpLoopMerge %35 %34 None
|
|
OpBranch %36
|
|
%36 = OpLabel
|
|
%37 = OpSLessThan %13 %32 %12
|
|
OpBranchConditional %37 %38 %35
|
|
%38 = OpLabel
|
|
%39 = OpAccessChain %20 %6 %24 %32
|
|
%40 = OpLoad %14 %39
|
|
%41 = OpAccessChain %20 %5 %24 %32
|
|
OpStore %41 %40
|
|
%42 = OpAccessChain %20 %5 %24 %32
|
|
%43 = OpLoad %14 %42
|
|
%44 = OpAccessChain %20 %6 %24 %32
|
|
OpStore %44 %43
|
|
OpBranch %34
|
|
%34 = OpLabel
|
|
%33 = OpIAdd %9 %32 %21
|
|
OpStore %4 %33
|
|
OpBranch %31
|
|
%35 = OpLabel
|
|
OpBranch %26
|
|
%26 = OpLabel
|
|
%25 = OpIAdd %9 %24 %21
|
|
OpStore %3 %25
|
|
OpBranch %23
|
|
%27 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string expected = R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
OpName %2 "main"
|
|
OpName %3 "i"
|
|
OpName %4 "j"
|
|
OpName %5 "A"
|
|
OpName %6 "B"
|
|
%7 = OpTypeVoid
|
|
%8 = OpTypeFunction %7
|
|
%9 = OpTypeInt 32 1
|
|
%10 = OpTypePointer Function %9
|
|
%11 = OpConstant %9 0
|
|
%12 = OpConstant %9 10
|
|
%13 = OpTypeBool
|
|
%14 = OpTypeFloat 32
|
|
%15 = OpTypeInt 32 0
|
|
%16 = OpConstant %15 10
|
|
%17 = OpTypeArray %14 %16
|
|
%18 = OpTypeArray %17 %16
|
|
%19 = OpTypePointer Function %18
|
|
%20 = OpTypePointer Function %14
|
|
%21 = OpConstant %9 1
|
|
%2 = OpFunction %7 None %8
|
|
%22 = OpLabel
|
|
%3 = OpVariable %10 Function
|
|
%4 = OpVariable %10 Function
|
|
%5 = OpVariable %19 Function
|
|
%6 = OpVariable %19 Function
|
|
OpStore %3 %11
|
|
OpBranch %23
|
|
%23 = OpLabel
|
|
%24 = OpPhi %9 %11 %22 %25 %26
|
|
OpLoopMerge %27 %26 None
|
|
OpBranch %28
|
|
%28 = OpLabel
|
|
%29 = OpSLessThan %13 %24 %12
|
|
OpBranchConditional %29 %30 %27
|
|
%30 = OpLabel
|
|
OpStore %4 %11
|
|
OpBranch %45
|
|
%45 = OpLabel
|
|
%46 = OpPhi %9 %11 %30 %57 %56
|
|
OpLoopMerge %58 %56 None
|
|
OpBranch %47
|
|
%47 = OpLabel
|
|
%48 = OpSLessThan %13 %46 %12
|
|
OpBranchConditional %48 %49 %58
|
|
%49 = OpLabel
|
|
%50 = OpAccessChain %20 %6 %24 %46
|
|
%51 = OpLoad %14 %50
|
|
%52 = OpAccessChain %20 %5 %24 %46
|
|
OpStore %52 %51
|
|
OpBranch %56
|
|
%56 = OpLabel
|
|
%57 = OpIAdd %9 %46 %21
|
|
OpStore %4 %57
|
|
OpBranch %45
|
|
%58 = OpLabel
|
|
OpBranch %31
|
|
%31 = OpLabel
|
|
%32 = OpPhi %9 %11 %58 %33 %34
|
|
OpLoopMerge %35 %34 None
|
|
OpBranch %36
|
|
%36 = OpLabel
|
|
%37 = OpSLessThan %13 %32 %12
|
|
OpBranchConditional %37 %38 %35
|
|
%38 = OpLabel
|
|
%42 = OpAccessChain %20 %5 %24 %32
|
|
%43 = OpLoad %14 %42
|
|
%44 = OpAccessChain %20 %6 %24 %32
|
|
OpStore %44 %43
|
|
OpBranch %34
|
|
%34 = OpLabel
|
|
%33 = OpIAdd %9 %32 %21
|
|
OpStore %4 %33
|
|
OpBranch %31
|
|
%35 = OpLabel
|
|
OpBranch %26
|
|
%26 = OpLabel
|
|
%25 = OpIAdd %9 %24 %21
|
|
OpStore %3 %25
|
|
OpBranch %23
|
|
%27 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
// clang-format on
|
|
std::unique_ptr<IRContext> context =
|
|
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
|
|
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
Module* module = context->module();
|
|
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
|
|
<< source << std::endl;
|
|
|
|
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
|
|
SinglePassRunAndCheck<LoopFissionPass>(source, expected, true);
|
|
}
|
|
|
|
/*
|
|
#version 430
|
|
void main(void) {
|
|
int accumulator = 0;
|
|
float A[10];
|
|
float B[10];
|
|
float C[10];
|
|
|
|
for (int i = 0; i < 10; i++) {
|
|
int c = C[i];
|
|
A[i] = B[i];
|
|
B[i] = A[i] + c;
|
|
}
|
|
}
|
|
|
|
This loop should not be split as we would have to break the order of the loads
|
|
to do so. It would be grouped into two sets:
|
|
|
|
1
|
|
int c = C[i];
|
|
B[i] = A[i] + c;
|
|
|
|
2
|
|
A[i] = B[i];
|
|
|
|
To keep the load C[i] in the same order we would need to put B[i] ahead of that
|
|
*/
|
|
TEST_F(FissionClassTest, FissionLoad) {
|
|
// clang-format off
|
|
// With LocalMultiStoreElimPass
|
|
const std::string source = R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
OpName %2 "main"
|
|
OpName %3 "i"
|
|
OpName %4 "c"
|
|
OpName %5 "C"
|
|
OpName %6 "A"
|
|
OpName %7 "B"
|
|
%8 = OpTypeVoid
|
|
%9 = OpTypeFunction %8
|
|
%10 = OpTypeInt 32 1
|
|
%11 = OpTypePointer Function %10
|
|
%12 = OpConstant %10 0
|
|
%13 = OpConstant %10 10
|
|
%14 = OpTypeBool
|
|
%15 = OpTypeFloat 32
|
|
%16 = OpTypePointer Function %15
|
|
%17 = OpTypeInt 32 0
|
|
%18 = OpConstant %17 10
|
|
%19 = OpTypeArray %15 %18
|
|
%20 = OpTypePointer Function %19
|
|
%21 = OpConstant %10 1
|
|
%2 = OpFunction %8 None %9
|
|
%22 = OpLabel
|
|
%3 = OpVariable %11 Function
|
|
%4 = OpVariable %16 Function
|
|
%5 = OpVariable %20 Function
|
|
%6 = OpVariable %20 Function
|
|
%7 = OpVariable %20 Function
|
|
OpBranch %23
|
|
%23 = OpLabel
|
|
%24 = OpPhi %10 %12 %22 %25 %26
|
|
OpLoopMerge %27 %26 None
|
|
OpBranch %28
|
|
%28 = OpLabel
|
|
%29 = OpSLessThan %14 %24 %13
|
|
OpBranchConditional %29 %30 %27
|
|
%30 = OpLabel
|
|
%31 = OpAccessChain %16 %5 %24
|
|
%32 = OpLoad %15 %31
|
|
OpStore %4 %32
|
|
%33 = OpAccessChain %16 %7 %24
|
|
%34 = OpLoad %15 %33
|
|
%35 = OpAccessChain %16 %6 %24
|
|
OpStore %35 %34
|
|
%36 = OpAccessChain %16 %6 %24
|
|
%37 = OpLoad %15 %36
|
|
%38 = OpFAdd %15 %37 %32
|
|
%39 = OpAccessChain %16 %7 %24
|
|
OpStore %39 %38
|
|
OpBranch %26
|
|
%26 = OpLabel
|
|
%25 = OpIAdd %10 %24 %21
|
|
OpBranch %23
|
|
%27 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
// clang-format on
|
|
std::unique_ptr<IRContext> context =
|
|
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
|
|
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
Module* module = context->module();
|
|
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
|
|
<< source << std::endl;
|
|
|
|
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
|
|
SinglePassRunAndCheck<LoopFissionPass>(source, source, true);
|
|
}
|
|
|
|
/*
|
|
#version 430
|
|
layout(location=0) flat in int condition;
|
|
void main(void) {
|
|
float A[10];
|
|
float B[10];
|
|
|
|
for (int i = 0; i < 10; i++) {
|
|
if (condition == 1)
|
|
A[i] = B[i];
|
|
else
|
|
B[i] = A[i];
|
|
}
|
|
}
|
|
|
|
|
|
When this is split we leave the condition check and control flow inplace and
|
|
leave its removal for dead code elimination.
|
|
|
|
#version 430
|
|
layout(location=0) flat in int condition;
|
|
void main(void) {
|
|
float A[10];
|
|
float B[10];
|
|
|
|
for (int i = 0; i < 10; i++) {
|
|
if (condition == 1)
|
|
A[i] = B[i];
|
|
else
|
|
;
|
|
}
|
|
for (int i = 0; i < 10; i++) {
|
|
if (condition == 1)
|
|
;
|
|
else
|
|
B[i] = A[i];
|
|
}
|
|
}
|
|
|
|
|
|
*/
|
|
TEST_F(FissionClassTest, FissionControlFlow) {
|
|
// clang-format off
|
|
// With LocalMultiStoreElimPass
|
|
const std::string source = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main" %3
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
OpName %2 "main"
|
|
OpName %4 "i"
|
|
OpName %3 "condition"
|
|
OpName %5 "A"
|
|
OpName %6 "B"
|
|
OpDecorate %3 Flat
|
|
OpDecorate %3 Location 0
|
|
%7 = OpTypeVoid
|
|
%8 = OpTypeFunction %7
|
|
%9 = OpTypeInt 32 1
|
|
%10 = OpTypePointer Function %9
|
|
%11 = OpConstant %9 0
|
|
%12 = OpConstant %9 10
|
|
%13 = OpTypeBool
|
|
%14 = OpTypePointer Input %9
|
|
%3 = OpVariable %14 Input
|
|
%15 = OpConstant %9 1
|
|
%16 = OpTypeFloat 32
|
|
%17 = OpTypeInt 32 0
|
|
%18 = OpConstant %17 10
|
|
%19 = OpTypeArray %16 %18
|
|
%20 = OpTypePointer Function %19
|
|
%21 = OpTypePointer Function %16
|
|
%2 = OpFunction %7 None %8
|
|
%22 = OpLabel
|
|
%4 = OpVariable %10 Function
|
|
%5 = OpVariable %20 Function
|
|
%6 = OpVariable %20 Function
|
|
%31 = OpLoad %9 %3
|
|
OpStore %4 %11
|
|
OpBranch %23
|
|
%23 = OpLabel
|
|
%24 = OpPhi %9 %11 %22 %25 %26
|
|
OpLoopMerge %27 %26 None
|
|
OpBranch %28
|
|
%28 = OpLabel
|
|
%29 = OpSLessThan %13 %24 %12
|
|
OpBranchConditional %29 %30 %27
|
|
%30 = OpLabel
|
|
%32 = OpIEqual %13 %31 %15
|
|
OpSelectionMerge %33 None
|
|
OpBranchConditional %32 %34 %35
|
|
%34 = OpLabel
|
|
%36 = OpAccessChain %21 %6 %24
|
|
%37 = OpLoad %16 %36
|
|
%38 = OpAccessChain %21 %5 %24
|
|
OpStore %38 %37
|
|
OpBranch %33
|
|
%35 = OpLabel
|
|
%39 = OpAccessChain %21 %5 %24
|
|
%40 = OpLoad %16 %39
|
|
%41 = OpAccessChain %21 %6 %24
|
|
OpStore %41 %40
|
|
OpBranch %33
|
|
%33 = OpLabel
|
|
OpBranch %26
|
|
%26 = OpLabel
|
|
%25 = OpIAdd %9 %24 %15
|
|
OpStore %4 %25
|
|
OpBranch %23
|
|
%27 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string expected = R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main" %3
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
OpName %2 "main"
|
|
OpName %4 "i"
|
|
OpName %3 "condition"
|
|
OpName %5 "A"
|
|
OpName %6 "B"
|
|
OpDecorate %3 Flat
|
|
OpDecorate %3 Location 0
|
|
%7 = OpTypeVoid
|
|
%8 = OpTypeFunction %7
|
|
%9 = OpTypeInt 32 1
|
|
%10 = OpTypePointer Function %9
|
|
%11 = OpConstant %9 0
|
|
%12 = OpConstant %9 10
|
|
%13 = OpTypeBool
|
|
%14 = OpTypePointer Input %9
|
|
%3 = OpVariable %14 Input
|
|
%15 = OpConstant %9 1
|
|
%16 = OpTypeFloat 32
|
|
%17 = OpTypeInt 32 0
|
|
%18 = OpConstant %17 10
|
|
%19 = OpTypeArray %16 %18
|
|
%20 = OpTypePointer Function %19
|
|
%21 = OpTypePointer Function %16
|
|
%2 = OpFunction %7 None %8
|
|
%22 = OpLabel
|
|
%4 = OpVariable %10 Function
|
|
%5 = OpVariable %20 Function
|
|
%6 = OpVariable %20 Function
|
|
%23 = OpLoad %9 %3
|
|
OpStore %4 %11
|
|
OpBranch %42
|
|
%42 = OpLabel
|
|
%43 = OpPhi %9 %11 %22 %58 %57
|
|
OpLoopMerge %59 %57 None
|
|
OpBranch %44
|
|
%44 = OpLabel
|
|
%45 = OpSLessThan %13 %43 %12
|
|
OpBranchConditional %45 %46 %59
|
|
%46 = OpLabel
|
|
%47 = OpIEqual %13 %23 %15
|
|
OpSelectionMerge %56 None
|
|
OpBranchConditional %47 %52 %48
|
|
%48 = OpLabel
|
|
OpBranch %56
|
|
%52 = OpLabel
|
|
%53 = OpAccessChain %21 %6 %43
|
|
%54 = OpLoad %16 %53
|
|
%55 = OpAccessChain %21 %5 %43
|
|
OpStore %55 %54
|
|
OpBranch %56
|
|
%56 = OpLabel
|
|
OpBranch %57
|
|
%57 = OpLabel
|
|
%58 = OpIAdd %9 %43 %15
|
|
OpStore %4 %58
|
|
OpBranch %42
|
|
%59 = OpLabel
|
|
OpBranch %24
|
|
%24 = OpLabel
|
|
%25 = OpPhi %9 %11 %59 %26 %27
|
|
OpLoopMerge %28 %27 None
|
|
OpBranch %29
|
|
%29 = OpLabel
|
|
%30 = OpSLessThan %13 %25 %12
|
|
OpBranchConditional %30 %31 %28
|
|
%31 = OpLabel
|
|
%32 = OpIEqual %13 %23 %15
|
|
OpSelectionMerge %33 None
|
|
OpBranchConditional %32 %34 %35
|
|
%34 = OpLabel
|
|
OpBranch %33
|
|
%35 = OpLabel
|
|
%39 = OpAccessChain %21 %5 %25
|
|
%40 = OpLoad %16 %39
|
|
%41 = OpAccessChain %21 %6 %25
|
|
OpStore %41 %40
|
|
OpBranch %33
|
|
%33 = OpLabel
|
|
OpBranch %27
|
|
%27 = OpLabel
|
|
%26 = OpIAdd %9 %25 %15
|
|
OpStore %4 %26
|
|
OpBranch %24
|
|
%28 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
// clang-format on
|
|
std::unique_ptr<IRContext> context =
|
|
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
|
|
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
Module* module = context->module();
|
|
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
|
|
<< source << std::endl;
|
|
|
|
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
|
|
SinglePassRunAndCheck<LoopFissionPass>(source, expected, true);
|
|
}
|
|
|
|
/*
|
|
#version 430
|
|
void main(void) {
|
|
float A[10];
|
|
float B[10];
|
|
for (int i = 0; i < 10; i++) {
|
|
if (i == 1)
|
|
B[i] = A[i];
|
|
else if (i == 2)
|
|
A[i] = B[i];
|
|
else
|
|
A[i] = 0;
|
|
}
|
|
}
|
|
|
|
After running the pass with multiple splits enabled (via register threshold of
|
|
1) we expect the equivalent of:
|
|
|
|
#version 430
|
|
void main(void) {
|
|
float A[10];
|
|
float B[10];
|
|
for (int i = 0; i < 10; i++) {
|
|
if (i == 1)
|
|
B[i] = A[i];
|
|
else if (i == 2)
|
|
else
|
|
}
|
|
for (int i = 0; i < 10; i++) {
|
|
if (i == 1)
|
|
else if (i == 2)
|
|
A[i] = B[i];
|
|
else
|
|
}
|
|
for (int i = 0; i < 10; i++) {
|
|
if (i == 1)
|
|
else if (i == 2)
|
|
else
|
|
A[i] = 0;
|
|
}
|
|
|
|
}
|
|
|
|
*/
|
|
TEST_F(FissionClassTest, FissionControlFlow2) {
|
|
// clang-format off
|
|
// With LocalMultiStoreElimPass
|
|
const std::string source = R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
OpName %2 "main"
|
|
OpName %3 "i"
|
|
OpName %4 "B"
|
|
OpName %5 "A"
|
|
%6 = OpTypeVoid
|
|
%7 = OpTypeFunction %6
|
|
%8 = OpTypeInt 32 1
|
|
%9 = OpTypePointer Function %8
|
|
%10 = OpConstant %8 0
|
|
%11 = OpConstant %8 10
|
|
%12 = OpTypeBool
|
|
%13 = OpConstant %8 1
|
|
%14 = OpTypeFloat 32
|
|
%15 = OpTypeInt 32 0
|
|
%16 = OpConstant %15 10
|
|
%17 = OpTypeArray %14 %16
|
|
%18 = OpTypePointer Function %17
|
|
%19 = OpTypePointer Function %14
|
|
%20 = OpConstant %8 2
|
|
%21 = OpConstant %14 0
|
|
%2 = OpFunction %6 None %7
|
|
%22 = OpLabel
|
|
%3 = OpVariable %9 Function
|
|
%4 = OpVariable %18 Function
|
|
%5 = OpVariable %18 Function
|
|
OpStore %3 %10
|
|
OpBranch %23
|
|
%23 = OpLabel
|
|
%24 = OpPhi %8 %10 %22 %25 %26
|
|
OpLoopMerge %27 %26 None
|
|
OpBranch %28
|
|
%28 = OpLabel
|
|
%29 = OpSLessThan %12 %24 %11
|
|
OpBranchConditional %29 %30 %27
|
|
%30 = OpLabel
|
|
%31 = OpIEqual %12 %24 %13
|
|
OpSelectionMerge %32 None
|
|
OpBranchConditional %31 %33 %34
|
|
%33 = OpLabel
|
|
%35 = OpAccessChain %19 %5 %24
|
|
%36 = OpLoad %14 %35
|
|
%37 = OpAccessChain %19 %4 %24
|
|
OpStore %37 %36
|
|
OpBranch %32
|
|
%34 = OpLabel
|
|
%38 = OpIEqual %12 %24 %20
|
|
OpSelectionMerge %39 None
|
|
OpBranchConditional %38 %40 %41
|
|
%40 = OpLabel
|
|
%42 = OpAccessChain %19 %4 %24
|
|
%43 = OpLoad %14 %42
|
|
%44 = OpAccessChain %19 %5 %24
|
|
OpStore %44 %43
|
|
OpBranch %39
|
|
%41 = OpLabel
|
|
%45 = OpAccessChain %19 %5 %24
|
|
OpStore %45 %21
|
|
OpBranch %39
|
|
%39 = OpLabel
|
|
OpBranch %32
|
|
%32 = OpLabel
|
|
OpBranch %26
|
|
%26 = OpLabel
|
|
%25 = OpIAdd %8 %24 %13
|
|
OpStore %3 %25
|
|
OpBranch %23
|
|
%27 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string expected = R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
OpName %2 "main"
|
|
OpName %3 "i"
|
|
OpName %4 "B"
|
|
OpName %5 "A"
|
|
%6 = OpTypeVoid
|
|
%7 = OpTypeFunction %6
|
|
%8 = OpTypeInt 32 1
|
|
%9 = OpTypePointer Function %8
|
|
%10 = OpConstant %8 0
|
|
%11 = OpConstant %8 10
|
|
%12 = OpTypeBool
|
|
%13 = OpConstant %8 1
|
|
%14 = OpTypeFloat 32
|
|
%15 = OpTypeInt 32 0
|
|
%16 = OpConstant %15 10
|
|
%17 = OpTypeArray %14 %16
|
|
%18 = OpTypePointer Function %17
|
|
%19 = OpTypePointer Function %14
|
|
%20 = OpConstant %8 2
|
|
%21 = OpConstant %14 0
|
|
%2 = OpFunction %6 None %7
|
|
%22 = OpLabel
|
|
%3 = OpVariable %9 Function
|
|
%4 = OpVariable %18 Function
|
|
%5 = OpVariable %18 Function
|
|
OpStore %3 %10
|
|
OpBranch %46
|
|
%46 = OpLabel
|
|
%47 = OpPhi %8 %10 %22 %67 %66
|
|
OpLoopMerge %68 %66 None
|
|
OpBranch %48
|
|
%48 = OpLabel
|
|
%49 = OpSLessThan %12 %47 %11
|
|
OpBranchConditional %49 %50 %68
|
|
%50 = OpLabel
|
|
%51 = OpIEqual %12 %47 %13
|
|
OpSelectionMerge %65 None
|
|
OpBranchConditional %51 %61 %52
|
|
%52 = OpLabel
|
|
%53 = OpIEqual %12 %47 %20
|
|
OpSelectionMerge %60 None
|
|
OpBranchConditional %53 %56 %54
|
|
%54 = OpLabel
|
|
OpBranch %60
|
|
%56 = OpLabel
|
|
OpBranch %60
|
|
%60 = OpLabel
|
|
OpBranch %65
|
|
%61 = OpLabel
|
|
%62 = OpAccessChain %19 %5 %47
|
|
%63 = OpLoad %14 %62
|
|
%64 = OpAccessChain %19 %4 %47
|
|
OpStore %64 %63
|
|
OpBranch %65
|
|
%65 = OpLabel
|
|
OpBranch %66
|
|
%66 = OpLabel
|
|
%67 = OpIAdd %8 %47 %13
|
|
OpStore %3 %67
|
|
OpBranch %46
|
|
%68 = OpLabel
|
|
OpBranch %69
|
|
%69 = OpLabel
|
|
%70 = OpPhi %8 %10 %68 %87 %86
|
|
OpLoopMerge %88 %86 None
|
|
OpBranch %71
|
|
%71 = OpLabel
|
|
%72 = OpSLessThan %12 %70 %11
|
|
OpBranchConditional %72 %73 %88
|
|
%73 = OpLabel
|
|
%74 = OpIEqual %12 %70 %13
|
|
OpSelectionMerge %85 None
|
|
OpBranchConditional %74 %84 %75
|
|
%75 = OpLabel
|
|
%76 = OpIEqual %12 %70 %20
|
|
OpSelectionMerge %83 None
|
|
OpBranchConditional %76 %79 %77
|
|
%77 = OpLabel
|
|
OpBranch %83
|
|
%79 = OpLabel
|
|
%80 = OpAccessChain %19 %4 %70
|
|
%81 = OpLoad %14 %80
|
|
%82 = OpAccessChain %19 %5 %70
|
|
OpStore %82 %81
|
|
OpBranch %83
|
|
%83 = OpLabel
|
|
OpBranch %85
|
|
%84 = OpLabel
|
|
OpBranch %85
|
|
%85 = OpLabel
|
|
OpBranch %86
|
|
%86 = OpLabel
|
|
%87 = OpIAdd %8 %70 %13
|
|
OpStore %3 %87
|
|
OpBranch %69
|
|
%88 = OpLabel
|
|
OpBranch %23
|
|
%23 = OpLabel
|
|
%24 = OpPhi %8 %10 %88 %25 %26
|
|
OpLoopMerge %27 %26 None
|
|
OpBranch %28
|
|
%28 = OpLabel
|
|
%29 = OpSLessThan %12 %24 %11
|
|
OpBranchConditional %29 %30 %27
|
|
%30 = OpLabel
|
|
%31 = OpIEqual %12 %24 %13
|
|
OpSelectionMerge %32 None
|
|
OpBranchConditional %31 %33 %34
|
|
%33 = OpLabel
|
|
OpBranch %32
|
|
%34 = OpLabel
|
|
%38 = OpIEqual %12 %24 %20
|
|
OpSelectionMerge %39 None
|
|
OpBranchConditional %38 %40 %41
|
|
%40 = OpLabel
|
|
OpBranch %39
|
|
%41 = OpLabel
|
|
%45 = OpAccessChain %19 %5 %24
|
|
OpStore %45 %21
|
|
OpBranch %39
|
|
%39 = OpLabel
|
|
OpBranch %32
|
|
%32 = OpLabel
|
|
OpBranch %26
|
|
%26 = OpLabel
|
|
%25 = OpIAdd %8 %24 %13
|
|
OpStore %3 %25
|
|
OpBranch %23
|
|
%27 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
// clang-format on
|
|
std::unique_ptr<IRContext> context =
|
|
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
|
|
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
Module* module = context->module();
|
|
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
|
|
<< source << std::endl;
|
|
|
|
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
|
|
SinglePassRunAndCheck<LoopFissionPass>(source, expected, true, 1);
|
|
}
|
|
|
|
/*
|
|
#version 430
|
|
layout(location=0) flat in int condition;
|
|
void main(void) {
|
|
float A[10];
|
|
float B[10];
|
|
for (int i = 0; i < 10; i++) {
|
|
B[i] = A[i];
|
|
memoryBarrier();
|
|
A[i] = B[i];
|
|
}
|
|
}
|
|
|
|
This should not be split due to the memory barrier.
|
|
*/
|
|
TEST_F(FissionClassTest, FissionBarrier) {
|
|
// clang-format off
|
|
// With LocalMultiStoreElimPass
|
|
const std::string source = R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main" %3
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
OpName %2 "main"
|
|
OpName %4 "i"
|
|
OpName %5 "B"
|
|
OpName %6 "A"
|
|
OpName %3 "condition"
|
|
OpDecorate %3 Flat
|
|
OpDecorate %3 Location 0
|
|
%7 = OpTypeVoid
|
|
%8 = OpTypeFunction %7
|
|
%9 = OpTypeInt 32 1
|
|
%10 = OpTypePointer Function %9
|
|
%11 = OpConstant %9 0
|
|
%12 = OpConstant %9 10
|
|
%13 = OpTypeBool
|
|
%14 = OpTypeFloat 32
|
|
%15 = OpTypeInt 32 0
|
|
%16 = OpConstant %15 10
|
|
%17 = OpTypeArray %14 %16
|
|
%18 = OpTypePointer Function %17
|
|
%19 = OpTypePointer Function %14
|
|
%20 = OpConstant %15 1
|
|
%21 = OpConstant %15 4048
|
|
%22 = OpConstant %9 1
|
|
%23 = OpTypePointer Input %9
|
|
%3 = OpVariable %23 Input
|
|
%2 = OpFunction %7 None %8
|
|
%24 = OpLabel
|
|
%4 = OpVariable %10 Function
|
|
%5 = OpVariable %18 Function
|
|
%6 = OpVariable %18 Function
|
|
OpStore %4 %11
|
|
OpBranch %25
|
|
%25 = OpLabel
|
|
%26 = OpPhi %9 %11 %24 %27 %28
|
|
OpLoopMerge %29 %28 None
|
|
OpBranch %30
|
|
%30 = OpLabel
|
|
%31 = OpSLessThan %13 %26 %12
|
|
OpBranchConditional %31 %32 %29
|
|
%32 = OpLabel
|
|
%33 = OpAccessChain %19 %6 %26
|
|
%34 = OpLoad %14 %33
|
|
%35 = OpAccessChain %19 %5 %26
|
|
OpStore %35 %34
|
|
OpMemoryBarrier %20 %21
|
|
%36 = OpAccessChain %19 %5 %26
|
|
%37 = OpLoad %14 %36
|
|
%38 = OpAccessChain %19 %6 %26
|
|
OpStore %38 %37
|
|
OpBranch %28
|
|
%28 = OpLabel
|
|
%27 = OpIAdd %9 %26 %22
|
|
OpStore %4 %27
|
|
OpBranch %25
|
|
%29 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
// clang-format on
|
|
std::unique_ptr<IRContext> context =
|
|
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
|
|
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
Module* module = context->module();
|
|
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
|
|
<< source << std::endl;
|
|
|
|
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
|
|
SinglePassRunAndCheck<LoopFissionPass>(source, source, true);
|
|
}
|
|
|
|
/*
|
|
#version 430
|
|
void main(void) {
|
|
float A[10];
|
|
float B[10];
|
|
for (int i = 0; i < 10; i++) {
|
|
B[i] = A[i];
|
|
if ( i== 1)
|
|
break;
|
|
A[i] = B[i];
|
|
}
|
|
}
|
|
|
|
This should not be split due to the break.
|
|
*/
|
|
TEST_F(FissionClassTest, FissionBreak) {
|
|
// clang-format off
|
|
// With LocalMultiStoreElimPass
|
|
const std::string source = R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
OpName %2 "main"
|
|
OpName %3 "i"
|
|
OpName %4 "B"
|
|
OpName %5 "A"
|
|
%6 = OpTypeVoid
|
|
%7 = OpTypeFunction %6
|
|
%8 = OpTypeInt 32 1
|
|
%9 = OpTypePointer Function %8
|
|
%10 = OpConstant %8 0
|
|
%11 = OpConstant %8 10
|
|
%12 = OpTypeBool
|
|
%13 = OpTypeFloat 32
|
|
%14 = OpTypeInt 32 0
|
|
%15 = OpConstant %14 10
|
|
%16 = OpTypeArray %13 %15
|
|
%17 = OpTypePointer Function %16
|
|
%18 = OpTypePointer Function %13
|
|
%19 = OpConstant %8 1
|
|
%2 = OpFunction %6 None %7
|
|
%20 = OpLabel
|
|
%3 = OpVariable %9 Function
|
|
%4 = OpVariable %17 Function
|
|
%5 = OpVariable %17 Function
|
|
OpStore %3 %10
|
|
OpBranch %21
|
|
%21 = OpLabel
|
|
%22 = OpPhi %8 %10 %20 %23 %24
|
|
OpLoopMerge %25 %24 None
|
|
OpBranch %26
|
|
%26 = OpLabel
|
|
%27 = OpSLessThan %12 %22 %11
|
|
OpBranchConditional %27 %28 %25
|
|
%28 = OpLabel
|
|
%29 = OpAccessChain %18 %5 %22
|
|
%30 = OpLoad %13 %29
|
|
%31 = OpAccessChain %18 %4 %22
|
|
OpStore %31 %30
|
|
%32 = OpIEqual %12 %22 %19
|
|
OpSelectionMerge %33 None
|
|
OpBranchConditional %32 %34 %33
|
|
%34 = OpLabel
|
|
OpBranch %25
|
|
%33 = OpLabel
|
|
%35 = OpAccessChain %18 %4 %22
|
|
%36 = OpLoad %13 %35
|
|
%37 = OpAccessChain %18 %5 %22
|
|
OpStore %37 %36
|
|
OpBranch %24
|
|
%24 = OpLabel
|
|
%23 = OpIAdd %8 %22 %19
|
|
OpStore %3 %23
|
|
OpBranch %21
|
|
%25 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
// clang-format on
|
|
std::unique_ptr<IRContext> context =
|
|
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
|
|
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
Module* module = context->module();
|
|
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
|
|
<< source << std::endl;
|
|
|
|
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
|
|
SinglePassRunAndCheck<LoopFissionPass>(source, source, true);
|
|
}
|
|
|
|
/*
|
|
#version 430
|
|
void main(void) {
|
|
float A[10];
|
|
float B[10];
|
|
for (int i = 0; i < 10; i++) {
|
|
B[i] = A[i];
|
|
if ( i== 1)
|
|
continue;
|
|
A[i] = B[i];
|
|
}
|
|
}
|
|
|
|
This loop should be split into:
|
|
|
|
for (int i = 0; i < 10; i++) {
|
|
B[i] = A[i];
|
|
if ( i== 1)
|
|
continue;
|
|
}
|
|
for (int i = 0; i < 10; i++) {
|
|
if ( i== 1)
|
|
continue;
|
|
A[i] = B[i];
|
|
}
|
|
The continue block in the first loop is left to DCE.
|
|
}
|
|
|
|
|
|
*/
|
|
TEST_F(FissionClassTest, FissionContinue) {
|
|
// clang-format off
|
|
// With LocalMultiStoreElimPass
|
|
const std::string source = R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
OpName %2 "main"
|
|
OpName %3 "i"
|
|
OpName %4 "B"
|
|
OpName %5 "A"
|
|
%6 = OpTypeVoid
|
|
%7 = OpTypeFunction %6
|
|
%8 = OpTypeInt 32 1
|
|
%9 = OpTypePointer Function %8
|
|
%10 = OpConstant %8 0
|
|
%11 = OpConstant %8 10
|
|
%12 = OpTypeBool
|
|
%13 = OpTypeFloat 32
|
|
%14 = OpTypeInt 32 0
|
|
%15 = OpConstant %14 10
|
|
%16 = OpTypeArray %13 %15
|
|
%17 = OpTypePointer Function %16
|
|
%18 = OpTypePointer Function %13
|
|
%19 = OpConstant %8 1
|
|
%2 = OpFunction %6 None %7
|
|
%20 = OpLabel
|
|
%3 = OpVariable %9 Function
|
|
%4 = OpVariable %17 Function
|
|
%5 = OpVariable %17 Function
|
|
OpStore %3 %10
|
|
OpBranch %21
|
|
%21 = OpLabel
|
|
%22 = OpPhi %8 %10 %20 %23 %24
|
|
OpLoopMerge %25 %24 None
|
|
OpBranch %26
|
|
%26 = OpLabel
|
|
%27 = OpSLessThan %12 %22 %11
|
|
OpBranchConditional %27 %28 %25
|
|
%28 = OpLabel
|
|
%29 = OpAccessChain %18 %5 %22
|
|
%30 = OpLoad %13 %29
|
|
%31 = OpAccessChain %18 %4 %22
|
|
OpStore %31 %30
|
|
%32 = OpIEqual %12 %22 %19
|
|
OpSelectionMerge %33 None
|
|
OpBranchConditional %32 %34 %33
|
|
%34 = OpLabel
|
|
OpBranch %24
|
|
%33 = OpLabel
|
|
%35 = OpAccessChain %18 %4 %22
|
|
%36 = OpLoad %13 %35
|
|
%37 = OpAccessChain %18 %5 %22
|
|
OpStore %37 %36
|
|
OpBranch %24
|
|
%24 = OpLabel
|
|
%23 = OpIAdd %8 %22 %19
|
|
OpStore %3 %23
|
|
OpBranch %21
|
|
%25 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string expected = R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
OpName %2 "main"
|
|
OpName %3 "i"
|
|
OpName %4 "B"
|
|
OpName %5 "A"
|
|
%6 = OpTypeVoid
|
|
%7 = OpTypeFunction %6
|
|
%8 = OpTypeInt 32 1
|
|
%9 = OpTypePointer Function %8
|
|
%10 = OpConstant %8 0
|
|
%11 = OpConstant %8 10
|
|
%12 = OpTypeBool
|
|
%13 = OpTypeFloat 32
|
|
%14 = OpTypeInt 32 0
|
|
%15 = OpConstant %14 10
|
|
%16 = OpTypeArray %13 %15
|
|
%17 = OpTypePointer Function %16
|
|
%18 = OpTypePointer Function %13
|
|
%19 = OpConstant %8 1
|
|
%2 = OpFunction %6 None %7
|
|
%20 = OpLabel
|
|
%3 = OpVariable %9 Function
|
|
%4 = OpVariable %17 Function
|
|
%5 = OpVariable %17 Function
|
|
OpStore %3 %10
|
|
OpBranch %38
|
|
%38 = OpLabel
|
|
%39 = OpPhi %8 %10 %20 %53 %52
|
|
OpLoopMerge %54 %52 None
|
|
OpBranch %40
|
|
%40 = OpLabel
|
|
%41 = OpSLessThan %12 %39 %11
|
|
OpBranchConditional %41 %42 %54
|
|
%42 = OpLabel
|
|
%43 = OpAccessChain %18 %5 %39
|
|
%44 = OpLoad %13 %43
|
|
%45 = OpAccessChain %18 %4 %39
|
|
OpStore %45 %44
|
|
%46 = OpIEqual %12 %39 %19
|
|
OpSelectionMerge %47 None
|
|
OpBranchConditional %46 %51 %47
|
|
%47 = OpLabel
|
|
OpBranch %52
|
|
%51 = OpLabel
|
|
OpBranch %52
|
|
%52 = OpLabel
|
|
%53 = OpIAdd %8 %39 %19
|
|
OpStore %3 %53
|
|
OpBranch %38
|
|
%54 = OpLabel
|
|
OpBranch %21
|
|
%21 = OpLabel
|
|
%22 = OpPhi %8 %10 %54 %23 %24
|
|
OpLoopMerge %25 %24 None
|
|
OpBranch %26
|
|
%26 = OpLabel
|
|
%27 = OpSLessThan %12 %22 %11
|
|
OpBranchConditional %27 %28 %25
|
|
%28 = OpLabel
|
|
%32 = OpIEqual %12 %22 %19
|
|
OpSelectionMerge %33 None
|
|
OpBranchConditional %32 %34 %33
|
|
%34 = OpLabel
|
|
OpBranch %24
|
|
%33 = OpLabel
|
|
%35 = OpAccessChain %18 %4 %22
|
|
%36 = OpLoad %13 %35
|
|
%37 = OpAccessChain %18 %5 %22
|
|
OpStore %37 %36
|
|
OpBranch %24
|
|
%24 = OpLabel
|
|
%23 = OpIAdd %8 %22 %19
|
|
OpStore %3 %23
|
|
OpBranch %21
|
|
%25 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
// clang-format on
|
|
std::unique_ptr<IRContext> context =
|
|
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
|
|
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
Module* module = context->module();
|
|
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
|
|
<< source << std::endl;
|
|
|
|
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
|
|
SinglePassRunAndCheck<LoopFissionPass>(source, expected, true);
|
|
}
|
|
|
|
/*
|
|
#version 430
|
|
void main(void) {
|
|
float A[10];
|
|
float B[10];
|
|
int i = 0;
|
|
do {
|
|
B[i] = A[i];
|
|
A[i] = B[i];
|
|
++i;
|
|
} while (i < 10);
|
|
}
|
|
|
|
|
|
Check that this is split into:
|
|
int i = 0;
|
|
do {
|
|
B[i] = A[i];
|
|
++i;
|
|
} while (i < 10);
|
|
|
|
i = 0;
|
|
do {
|
|
A[i] = B[i];
|
|
++i;
|
|
} while (i < 10);
|
|
|
|
|
|
*/
|
|
TEST_F(FissionClassTest, FissionDoWhile) {
|
|
// clang-format off
|
|
// With LocalMultiStoreElimPass
|
|
const std::string source = R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
OpName %2 "main"
|
|
OpName %3 "i"
|
|
OpName %4 "B"
|
|
OpName %5 "A"
|
|
%6 = OpTypeVoid
|
|
%7 = OpTypeFunction %6
|
|
%8 = OpTypeInt 32 1
|
|
%9 = OpTypePointer Function %8
|
|
%10 = OpConstant %8 0
|
|
%11 = OpTypeFloat 32
|
|
%12 = OpTypeInt 32 0
|
|
%13 = OpConstant %12 10
|
|
%14 = OpTypeArray %11 %13
|
|
%15 = OpTypePointer Function %14
|
|
%16 = OpTypePointer Function %11
|
|
%17 = OpConstant %8 1
|
|
%18 = OpConstant %8 10
|
|
%19 = OpTypeBool
|
|
%2 = OpFunction %6 None %7
|
|
%20 = OpLabel
|
|
%3 = OpVariable %9 Function
|
|
%4 = OpVariable %15 Function
|
|
%5 = OpVariable %15 Function
|
|
OpStore %3 %10
|
|
OpBranch %21
|
|
%21 = OpLabel
|
|
%22 = OpPhi %8 %10 %20 %23 %24
|
|
OpLoopMerge %25 %24 None
|
|
OpBranch %26
|
|
%26 = OpLabel
|
|
%27 = OpAccessChain %16 %5 %22
|
|
%28 = OpLoad %11 %27
|
|
%29 = OpAccessChain %16 %4 %22
|
|
OpStore %29 %28
|
|
%30 = OpAccessChain %16 %4 %22
|
|
%31 = OpLoad %11 %30
|
|
%32 = OpAccessChain %16 %5 %22
|
|
OpStore %32 %31
|
|
%23 = OpIAdd %8 %22 %17
|
|
OpStore %3 %23
|
|
OpBranch %24
|
|
%24 = OpLabel
|
|
%33 = OpSLessThan %19 %23 %18
|
|
OpBranchConditional %33 %21 %25
|
|
%25 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string expected = R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
OpName %2 "main"
|
|
OpName %3 "i"
|
|
OpName %4 "B"
|
|
OpName %5 "A"
|
|
%6 = OpTypeVoid
|
|
%7 = OpTypeFunction %6
|
|
%8 = OpTypeInt 32 1
|
|
%9 = OpTypePointer Function %8
|
|
%10 = OpConstant %8 0
|
|
%11 = OpTypeFloat 32
|
|
%12 = OpTypeInt 32 0
|
|
%13 = OpConstant %12 10
|
|
%14 = OpTypeArray %11 %13
|
|
%15 = OpTypePointer Function %14
|
|
%16 = OpTypePointer Function %11
|
|
%17 = OpConstant %8 1
|
|
%18 = OpConstant %8 10
|
|
%19 = OpTypeBool
|
|
%2 = OpFunction %6 None %7
|
|
%20 = OpLabel
|
|
%3 = OpVariable %9 Function
|
|
%4 = OpVariable %15 Function
|
|
%5 = OpVariable %15 Function
|
|
OpStore %3 %10
|
|
OpBranch %34
|
|
%34 = OpLabel
|
|
%35 = OpPhi %8 %10 %20 %43 %44
|
|
OpLoopMerge %46 %44 None
|
|
OpBranch %36
|
|
%36 = OpLabel
|
|
%37 = OpAccessChain %16 %5 %35
|
|
%38 = OpLoad %11 %37
|
|
%39 = OpAccessChain %16 %4 %35
|
|
OpStore %39 %38
|
|
%43 = OpIAdd %8 %35 %17
|
|
OpStore %3 %43
|
|
OpBranch %44
|
|
%44 = OpLabel
|
|
%45 = OpSLessThan %19 %43 %18
|
|
OpBranchConditional %45 %34 %46
|
|
%46 = OpLabel
|
|
OpBranch %21
|
|
%21 = OpLabel
|
|
%22 = OpPhi %8 %10 %46 %23 %24
|
|
OpLoopMerge %25 %24 None
|
|
OpBranch %26
|
|
%26 = OpLabel
|
|
%30 = OpAccessChain %16 %4 %22
|
|
%31 = OpLoad %11 %30
|
|
%32 = OpAccessChain %16 %5 %22
|
|
OpStore %32 %31
|
|
%23 = OpIAdd %8 %22 %17
|
|
OpStore %3 %23
|
|
OpBranch %24
|
|
%24 = OpLabel
|
|
%33 = OpSLessThan %19 %23 %18
|
|
OpBranchConditional %33 %21 %25
|
|
%25 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
// clang-format on
|
|
std::unique_ptr<IRContext> context =
|
|
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
|
|
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
Module* module = context->module();
|
|
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
|
|
<< source << std::endl;
|
|
|
|
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
|
|
SinglePassRunAndCheck<LoopFissionPass>(source, expected, true);
|
|
}
|
|
|
|
/*
|
|
|
|
#version 430
|
|
void main(void) {
|
|
float A[10][10];
|
|
float B[10][10];
|
|
for (int j = 0; j < 10; ++j) {
|
|
for (int i = 0; i < 10; ++i) {
|
|
B[i][j] = A[i][i];
|
|
A[i][i] = B[i][j + 1];
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
This loop can't be split because the load B[i][j + 1] is dependent on the store
|
|
B[i][j].
|
|
|
|
*/
|
|
TEST_F(FissionClassTest, FissionNestedDependency) {
|
|
// clang-format off
|
|
// With LocalMultiStoreElimPass
|
|
const std::string source = R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
OpName %2 "main"
|
|
OpName %3 "j"
|
|
OpName %4 "i"
|
|
OpName %5 "B"
|
|
OpName %6 "A"
|
|
%7 = OpTypeVoid
|
|
%8 = OpTypeFunction %7
|
|
%9 = OpTypeInt 32 1
|
|
%10 = OpTypePointer Function %9
|
|
%11 = OpConstant %9 0
|
|
%12 = OpConstant %9 10
|
|
%13 = OpTypeBool
|
|
%14 = OpTypeFloat 32
|
|
%15 = OpTypeInt 32 0
|
|
%16 = OpConstant %15 10
|
|
%17 = OpTypeArray %14 %16
|
|
%18 = OpTypeArray %17 %16
|
|
%19 = OpTypePointer Function %18
|
|
%20 = OpTypePointer Function %14
|
|
%21 = OpConstant %9 1
|
|
%2 = OpFunction %7 None %8
|
|
%22 = OpLabel
|
|
%3 = OpVariable %10 Function
|
|
%4 = OpVariable %10 Function
|
|
%5 = OpVariable %19 Function
|
|
%6 = OpVariable %19 Function
|
|
OpBranch %23
|
|
%23 = OpLabel
|
|
%24 = OpPhi %9 %11 %22 %25 %26
|
|
OpLoopMerge %27 %26 None
|
|
OpBranch %28
|
|
%28 = OpLabel
|
|
%29 = OpSLessThan %13 %24 %12
|
|
OpBranchConditional %29 %30 %27
|
|
%30 = OpLabel
|
|
OpBranch %31
|
|
%31 = OpLabel
|
|
%32 = OpPhi %9 %11 %30 %33 %34
|
|
OpLoopMerge %35 %34 None
|
|
OpBranch %36
|
|
%36 = OpLabel
|
|
%37 = OpSLessThan %13 %32 %12
|
|
OpBranchConditional %37 %38 %35
|
|
%38 = OpLabel
|
|
%39 = OpAccessChain %20 %6 %32 %32
|
|
%40 = OpLoad %14 %39
|
|
%41 = OpAccessChain %20 %5 %32 %24
|
|
OpStore %41 %40
|
|
%42 = OpIAdd %9 %24 %21
|
|
%43 = OpAccessChain %20 %5 %32 %42
|
|
%44 = OpLoad %14 %43
|
|
%45 = OpAccessChain %20 %6 %32 %32
|
|
OpStore %45 %44
|
|
OpBranch %34
|
|
%34 = OpLabel
|
|
%33 = OpIAdd %9 %32 %21
|
|
OpBranch %31
|
|
%35 = OpLabel
|
|
OpBranch %26
|
|
%26 = OpLabel
|
|
%25 = OpIAdd %9 %24 %21
|
|
OpBranch %23
|
|
%27 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
// clang-format on
|
|
std::unique_ptr<IRContext> context =
|
|
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
|
|
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
Module* module = context->module();
|
|
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
|
|
<< source << std::endl;
|
|
|
|
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
|
|
SinglePassRunAndCheck<LoopFissionPass>(source, source, true);
|
|
}
|
|
|
|
/*
|
|
#version 430
|
|
void main(void) {
|
|
float A[10][10];
|
|
float B[10][10];
|
|
for (int j = 0; j < 10; ++j) {
|
|
for (int i = 0; i < 10; ++i) {
|
|
B[i][i] = A[i][j];
|
|
A[i][j+1] = B[i][i];
|
|
}
|
|
}
|
|
}
|
|
|
|
This loop should not be split as the load A[i][j+1] would be reading a value
|
|
written in the store A[i][j] which would be hit before A[i][j+1] if the loops
|
|
where split but would not get hit before the read currently.
|
|
|
|
*/
|
|
TEST_F(FissionClassTest, FissionNestedDependency2) {
|
|
// clang-format off
|
|
// With LocalMultiStoreElimPass
|
|
const std::string source = R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
OpName %2 "main"
|
|
OpName %3 "j"
|
|
OpName %4 "i"
|
|
OpName %5 "B"
|
|
OpName %6 "A"
|
|
%7 = OpTypeVoid
|
|
%8 = OpTypeFunction %7
|
|
%9 = OpTypeInt 32 1
|
|
%10 = OpTypePointer Function %9
|
|
%11 = OpConstant %9 0
|
|
%12 = OpConstant %9 10
|
|
%13 = OpTypeBool
|
|
%14 = OpTypeFloat 32
|
|
%15 = OpTypeInt 32 0
|
|
%16 = OpConstant %15 10
|
|
%17 = OpTypeArray %14 %16
|
|
%18 = OpTypeArray %17 %16
|
|
%19 = OpTypePointer Function %18
|
|
%20 = OpTypePointer Function %14
|
|
%21 = OpConstant %9 1
|
|
%2 = OpFunction %7 None %8
|
|
%22 = OpLabel
|
|
%3 = OpVariable %10 Function
|
|
%4 = OpVariable %10 Function
|
|
%5 = OpVariable %19 Function
|
|
%6 = OpVariable %19 Function
|
|
OpStore %3 %11
|
|
OpBranch %23
|
|
%23 = OpLabel
|
|
%24 = OpPhi %9 %11 %22 %25 %26
|
|
OpLoopMerge %27 %26 None
|
|
OpBranch %28
|
|
%28 = OpLabel
|
|
%29 = OpSLessThan %13 %24 %12
|
|
OpBranchConditional %29 %30 %27
|
|
%30 = OpLabel
|
|
OpStore %4 %11
|
|
OpBranch %31
|
|
%31 = OpLabel
|
|
%32 = OpPhi %9 %11 %30 %33 %34
|
|
OpLoopMerge %35 %34 None
|
|
OpBranch %36
|
|
%36 = OpLabel
|
|
%37 = OpSLessThan %13 %32 %12
|
|
OpBranchConditional %37 %38 %35
|
|
%38 = OpLabel
|
|
%39 = OpAccessChain %20 %6 %32 %24
|
|
%40 = OpLoad %14 %39
|
|
%41 = OpAccessChain %20 %5 %32 %32
|
|
OpStore %41 %40
|
|
%42 = OpIAdd %9 %24 %21
|
|
%43 = OpAccessChain %20 %5 %32 %32
|
|
%44 = OpLoad %14 %43
|
|
%45 = OpAccessChain %20 %6 %32 %42
|
|
OpStore %45 %44
|
|
OpBranch %34
|
|
%34 = OpLabel
|
|
%33 = OpIAdd %9 %32 %21
|
|
OpStore %4 %33
|
|
OpBranch %31
|
|
%35 = OpLabel
|
|
OpBranch %26
|
|
%26 = OpLabel
|
|
%25 = OpIAdd %9 %24 %21
|
|
OpStore %3 %25
|
|
OpBranch %23
|
|
%27 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
// clang-format on
|
|
std::unique_ptr<IRContext> context =
|
|
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
|
|
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
Module* module = context->module();
|
|
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
|
|
<< source << std::endl;
|
|
|
|
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
|
|
SinglePassRunAndCheck<LoopFissionPass>(source, source, true);
|
|
}
|
|
|
|
/*
|
|
#version 430
|
|
void main(void) {
|
|
float A[10][10];
|
|
float B[10][10];
|
|
for (int j = 0; j < 10; ++j) {
|
|
for (int i = 0; i < 10; ++i) {
|
|
B[i][j] = A[i][j];
|
|
A[i][j] = B[i][j];
|
|
}
|
|
for (int i = 0; i < 10; ++i) {
|
|
B[i][j] = A[i][j];
|
|
A[i][j] = B[i][j];
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
Should be split into:
|
|
|
|
for (int j = 0; j < 10; ++j) {
|
|
for (int i = 0; i < 10; ++i)
|
|
B[i][j] = A[i][j];
|
|
for (int i = 0; i < 10; ++i)
|
|
A[i][j] = B[i][j];
|
|
for (int i = 0; i < 10; ++i)
|
|
B[i][j] = A[i][j];
|
|
for (int i = 0; i < 10; ++i)
|
|
A[i][j] = B[i][j];
|
|
*/
|
|
TEST_F(FissionClassTest, FissionMultipleLoopsNested) {
|
|
// clang-format off
|
|
// With LocalMultiStoreElimPass
|
|
const std::string source = R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
OpName %2 "main"
|
|
OpName %3 "j"
|
|
OpName %4 "i"
|
|
OpName %5 "B"
|
|
OpName %6 "A"
|
|
OpName %7 "i"
|
|
%8 = OpTypeVoid
|
|
%9 = OpTypeFunction %8
|
|
%10 = OpTypeInt 32 1
|
|
%11 = OpTypePointer Function %10
|
|
%12 = OpConstant %10 0
|
|
%13 = OpConstant %10 10
|
|
%14 = OpTypeBool
|
|
%15 = OpTypeFloat 32
|
|
%16 = OpTypeInt 32 0
|
|
%17 = OpConstant %16 10
|
|
%18 = OpTypeArray %15 %17
|
|
%19 = OpTypeArray %18 %17
|
|
%20 = OpTypePointer Function %19
|
|
%21 = OpTypePointer Function %15
|
|
%22 = OpConstant %10 1
|
|
%2 = OpFunction %8 None %9
|
|
%23 = OpLabel
|
|
%3 = OpVariable %11 Function
|
|
%4 = OpVariable %11 Function
|
|
%5 = OpVariable %20 Function
|
|
%6 = OpVariable %20 Function
|
|
%7 = OpVariable %11 Function
|
|
OpStore %3 %12
|
|
OpBranch %24
|
|
%24 = OpLabel
|
|
%25 = OpPhi %10 %12 %23 %26 %27
|
|
OpLoopMerge %28 %27 None
|
|
OpBranch %29
|
|
%29 = OpLabel
|
|
%30 = OpSLessThan %14 %25 %13
|
|
OpBranchConditional %30 %31 %28
|
|
%31 = OpLabel
|
|
OpStore %4 %12
|
|
OpBranch %32
|
|
%32 = OpLabel
|
|
%33 = OpPhi %10 %12 %31 %34 %35
|
|
OpLoopMerge %36 %35 None
|
|
OpBranch %37
|
|
%37 = OpLabel
|
|
%38 = OpSLessThan %14 %33 %13
|
|
OpBranchConditional %38 %39 %36
|
|
%39 = OpLabel
|
|
%40 = OpAccessChain %21 %6 %33 %25
|
|
%41 = OpLoad %15 %40
|
|
%42 = OpAccessChain %21 %5 %33 %25
|
|
OpStore %42 %41
|
|
%43 = OpAccessChain %21 %5 %33 %25
|
|
%44 = OpLoad %15 %43
|
|
%45 = OpAccessChain %21 %6 %33 %25
|
|
OpStore %45 %44
|
|
OpBranch %35
|
|
%35 = OpLabel
|
|
%34 = OpIAdd %10 %33 %22
|
|
OpStore %4 %34
|
|
OpBranch %32
|
|
%36 = OpLabel
|
|
OpStore %7 %12
|
|
OpBranch %46
|
|
%46 = OpLabel
|
|
%47 = OpPhi %10 %12 %36 %48 %49
|
|
OpLoopMerge %50 %49 None
|
|
OpBranch %51
|
|
%51 = OpLabel
|
|
%52 = OpSLessThan %14 %47 %13
|
|
OpBranchConditional %52 %53 %50
|
|
%53 = OpLabel
|
|
%54 = OpAccessChain %21 %6 %47 %25
|
|
%55 = OpLoad %15 %54
|
|
%56 = OpAccessChain %21 %5 %47 %25
|
|
OpStore %56 %55
|
|
%57 = OpAccessChain %21 %5 %47 %25
|
|
%58 = OpLoad %15 %57
|
|
%59 = OpAccessChain %21 %6 %47 %25
|
|
OpStore %59 %58
|
|
OpBranch %49
|
|
%49 = OpLabel
|
|
%48 = OpIAdd %10 %47 %22
|
|
OpStore %7 %48
|
|
OpBranch %46
|
|
%50 = OpLabel
|
|
OpBranch %27
|
|
%27 = OpLabel
|
|
%26 = OpIAdd %10 %25 %22
|
|
OpStore %3 %26
|
|
OpBranch %24
|
|
%28 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string expected = R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
OpName %2 "main"
|
|
OpName %3 "j"
|
|
OpName %4 "i"
|
|
OpName %5 "B"
|
|
OpName %6 "A"
|
|
OpName %7 "i"
|
|
%8 = OpTypeVoid
|
|
%9 = OpTypeFunction %8
|
|
%10 = OpTypeInt 32 1
|
|
%11 = OpTypePointer Function %10
|
|
%12 = OpConstant %10 0
|
|
%13 = OpConstant %10 10
|
|
%14 = OpTypeBool
|
|
%15 = OpTypeFloat 32
|
|
%16 = OpTypeInt 32 0
|
|
%17 = OpConstant %16 10
|
|
%18 = OpTypeArray %15 %17
|
|
%19 = OpTypeArray %18 %17
|
|
%20 = OpTypePointer Function %19
|
|
%21 = OpTypePointer Function %15
|
|
%22 = OpConstant %10 1
|
|
%2 = OpFunction %8 None %9
|
|
%23 = OpLabel
|
|
%3 = OpVariable %11 Function
|
|
%4 = OpVariable %11 Function
|
|
%5 = OpVariable %20 Function
|
|
%6 = OpVariable %20 Function
|
|
%7 = OpVariable %11 Function
|
|
OpStore %3 %12
|
|
OpBranch %24
|
|
%24 = OpLabel
|
|
%25 = OpPhi %10 %12 %23 %26 %27
|
|
OpLoopMerge %28 %27 None
|
|
OpBranch %29
|
|
%29 = OpLabel
|
|
%30 = OpSLessThan %14 %25 %13
|
|
OpBranchConditional %30 %31 %28
|
|
%31 = OpLabel
|
|
OpStore %4 %12
|
|
OpBranch %60
|
|
%60 = OpLabel
|
|
%61 = OpPhi %10 %12 %31 %72 %71
|
|
OpLoopMerge %73 %71 None
|
|
OpBranch %62
|
|
%62 = OpLabel
|
|
%63 = OpSLessThan %14 %61 %13
|
|
OpBranchConditional %63 %64 %73
|
|
%64 = OpLabel
|
|
%65 = OpAccessChain %21 %6 %61 %25
|
|
%66 = OpLoad %15 %65
|
|
%67 = OpAccessChain %21 %5 %61 %25
|
|
OpStore %67 %66
|
|
OpBranch %71
|
|
%71 = OpLabel
|
|
%72 = OpIAdd %10 %61 %22
|
|
OpStore %4 %72
|
|
OpBranch %60
|
|
%73 = OpLabel
|
|
OpBranch %32
|
|
%32 = OpLabel
|
|
%33 = OpPhi %10 %12 %73 %34 %35
|
|
OpLoopMerge %36 %35 None
|
|
OpBranch %37
|
|
%37 = OpLabel
|
|
%38 = OpSLessThan %14 %33 %13
|
|
OpBranchConditional %38 %39 %36
|
|
%39 = OpLabel
|
|
%43 = OpAccessChain %21 %5 %33 %25
|
|
%44 = OpLoad %15 %43
|
|
%45 = OpAccessChain %21 %6 %33 %25
|
|
OpStore %45 %44
|
|
OpBranch %35
|
|
%35 = OpLabel
|
|
%34 = OpIAdd %10 %33 %22
|
|
OpStore %4 %34
|
|
OpBranch %32
|
|
%36 = OpLabel
|
|
OpStore %7 %12
|
|
OpBranch %74
|
|
%74 = OpLabel
|
|
%75 = OpPhi %10 %12 %36 %86 %85
|
|
OpLoopMerge %87 %85 None
|
|
OpBranch %76
|
|
%76 = OpLabel
|
|
%77 = OpSLessThan %14 %75 %13
|
|
OpBranchConditional %77 %78 %87
|
|
%78 = OpLabel
|
|
%79 = OpAccessChain %21 %6 %75 %25
|
|
%80 = OpLoad %15 %79
|
|
%81 = OpAccessChain %21 %5 %75 %25
|
|
OpStore %81 %80
|
|
OpBranch %85
|
|
%85 = OpLabel
|
|
%86 = OpIAdd %10 %75 %22
|
|
OpStore %7 %86
|
|
OpBranch %74
|
|
%87 = OpLabel
|
|
OpBranch %46
|
|
%46 = OpLabel
|
|
%47 = OpPhi %10 %12 %87 %48 %49
|
|
OpLoopMerge %50 %49 None
|
|
OpBranch %51
|
|
%51 = OpLabel
|
|
%52 = OpSLessThan %14 %47 %13
|
|
OpBranchConditional %52 %53 %50
|
|
%53 = OpLabel
|
|
%57 = OpAccessChain %21 %5 %47 %25
|
|
%58 = OpLoad %15 %57
|
|
%59 = OpAccessChain %21 %6 %47 %25
|
|
OpStore %59 %58
|
|
OpBranch %49
|
|
%49 = OpLabel
|
|
%48 = OpIAdd %10 %47 %22
|
|
OpStore %7 %48
|
|
OpBranch %46
|
|
%50 = OpLabel
|
|
OpBranch %27
|
|
%27 = OpLabel
|
|
%26 = OpIAdd %10 %25 %22
|
|
OpStore %3 %26
|
|
OpBranch %24
|
|
%28 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
// clang-format on
|
|
std::unique_ptr<IRContext> context =
|
|
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
|
|
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
Module* module = context->module();
|
|
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
|
|
<< source << std::endl;
|
|
const Function* function = spvtest::GetFunction(module, 2);
|
|
LoopDescriptor& pre_pass_descriptor = *context->GetLoopDescriptor(function);
|
|
EXPECT_EQ(pre_pass_descriptor.NumLoops(), 3u);
|
|
EXPECT_EQ(pre_pass_descriptor.pre_begin()->NumImmediateChildren(), 2u);
|
|
|
|
// Test that the pass transforms the ir into the expected output.
|
|
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
|
|
SinglePassRunAndCheck<LoopFissionPass>(source, expected, true);
|
|
|
|
// Test that the loop descriptor is correctly maintained and updated by the
|
|
// pass.
|
|
LoopFissionPass loop_fission;
|
|
loop_fission.SetContextForTesting(context.get());
|
|
loop_fission.Process();
|
|
|
|
function = spvtest::GetFunction(module, 2);
|
|
LoopDescriptor& post_pass_descriptor = *context->GetLoopDescriptor(function);
|
|
EXPECT_EQ(post_pass_descriptor.NumLoops(), 5u);
|
|
EXPECT_EQ(post_pass_descriptor.pre_begin()->NumImmediateChildren(), 4u);
|
|
}
|
|
|
|
/*
|
|
#version 430
|
|
void main(void) {
|
|
float A[10][10];
|
|
float B[10][10];
|
|
for (int i = 0; i < 10; ++i) {
|
|
B[i][i] = A[i][i];
|
|
A[i][i] = B[i][i];
|
|
}
|
|
for (int i = 0; i < 10; ++i) {
|
|
B[i][i] = A[i][i];
|
|
A[i][i] = B[i][i]
|
|
}
|
|
}
|
|
|
|
|
|
|
|
Should be split into:
|
|
|
|
for (int i = 0; i < 10; ++i)
|
|
B[i][i] = A[i][i];
|
|
for (int i = 0; i < 10; ++i)
|
|
A[i][i] = B[i][i];
|
|
for (int i = 0; i < 10; ++i)
|
|
B[i][i] = A[i][i];
|
|
for (int i = 0; i < 10; ++i)
|
|
A[i][i] = B[i][i];
|
|
*/
|
|
TEST_F(FissionClassTest, FissionMultipleLoops) {
|
|
// clang-format off
|
|
// With LocalMultiStoreElimPass
|
|
const std::string source = R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
OpName %2 "main"
|
|
OpName %3 "i"
|
|
OpName %4 "B"
|
|
OpName %5 "A"
|
|
OpName %6 "i"
|
|
%7 = OpTypeVoid
|
|
%8 = OpTypeFunction %7
|
|
%9 = OpTypeInt 32 1
|
|
%10 = OpTypePointer Function %9
|
|
%11 = OpConstant %9 0
|
|
%12 = OpConstant %9 10
|
|
%13 = OpTypeBool
|
|
%14 = OpTypeFloat 32
|
|
%15 = OpTypeInt 32 0
|
|
%16 = OpConstant %15 10
|
|
%17 = OpTypeArray %14 %16
|
|
%18 = OpTypePointer Function %17
|
|
%19 = OpTypePointer Function %14
|
|
%20 = OpConstant %9 1
|
|
%2 = OpFunction %7 None %8
|
|
%21 = OpLabel
|
|
%3 = OpVariable %10 Function
|
|
%4 = OpVariable %18 Function
|
|
%5 = OpVariable %18 Function
|
|
%6 = OpVariable %10 Function
|
|
OpStore %3 %11
|
|
OpBranch %22
|
|
%22 = OpLabel
|
|
%23 = OpPhi %9 %11 %21 %24 %25
|
|
OpLoopMerge %26 %25 None
|
|
OpBranch %27
|
|
%27 = OpLabel
|
|
%28 = OpSLessThan %13 %23 %12
|
|
OpBranchConditional %28 %29 %26
|
|
%29 = OpLabel
|
|
%30 = OpAccessChain %19 %5 %23
|
|
%31 = OpLoad %14 %30
|
|
%32 = OpAccessChain %19 %4 %23
|
|
OpStore %32 %31
|
|
%33 = OpAccessChain %19 %4 %23
|
|
%34 = OpLoad %14 %33
|
|
%35 = OpAccessChain %19 %5 %23
|
|
OpStore %35 %34
|
|
OpBranch %25
|
|
%25 = OpLabel
|
|
%24 = OpIAdd %9 %23 %20
|
|
OpStore %3 %24
|
|
OpBranch %22
|
|
%26 = OpLabel
|
|
OpStore %6 %11
|
|
OpBranch %36
|
|
%36 = OpLabel
|
|
%37 = OpPhi %9 %11 %26 %38 %39
|
|
OpLoopMerge %40 %39 None
|
|
OpBranch %41
|
|
%41 = OpLabel
|
|
%42 = OpSLessThan %13 %37 %12
|
|
OpBranchConditional %42 %43 %40
|
|
%43 = OpLabel
|
|
%44 = OpAccessChain %19 %5 %37
|
|
%45 = OpLoad %14 %44
|
|
%46 = OpAccessChain %19 %4 %37
|
|
OpStore %46 %45
|
|
%47 = OpAccessChain %19 %4 %37
|
|
%48 = OpLoad %14 %47
|
|
%49 = OpAccessChain %19 %5 %37
|
|
OpStore %49 %48
|
|
OpBranch %39
|
|
%39 = OpLabel
|
|
%38 = OpIAdd %9 %37 %20
|
|
OpStore %6 %38
|
|
OpBranch %36
|
|
%40 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string expected = R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
OpName %2 "main"
|
|
OpName %3 "i"
|
|
OpName %4 "B"
|
|
OpName %5 "A"
|
|
OpName %6 "i"
|
|
%7 = OpTypeVoid
|
|
%8 = OpTypeFunction %7
|
|
%9 = OpTypeInt 32 1
|
|
%10 = OpTypePointer Function %9
|
|
%11 = OpConstant %9 0
|
|
%12 = OpConstant %9 10
|
|
%13 = OpTypeBool
|
|
%14 = OpTypeFloat 32
|
|
%15 = OpTypeInt 32 0
|
|
%16 = OpConstant %15 10
|
|
%17 = OpTypeArray %14 %16
|
|
%18 = OpTypePointer Function %17
|
|
%19 = OpTypePointer Function %14
|
|
%20 = OpConstant %9 1
|
|
%2 = OpFunction %7 None %8
|
|
%21 = OpLabel
|
|
%3 = OpVariable %10 Function
|
|
%4 = OpVariable %18 Function
|
|
%5 = OpVariable %18 Function
|
|
%6 = OpVariable %10 Function
|
|
OpStore %3 %11
|
|
OpBranch %64
|
|
%64 = OpLabel
|
|
%65 = OpPhi %9 %11 %21 %76 %75
|
|
OpLoopMerge %77 %75 None
|
|
OpBranch %66
|
|
%66 = OpLabel
|
|
%67 = OpSLessThan %13 %65 %12
|
|
OpBranchConditional %67 %68 %77
|
|
%68 = OpLabel
|
|
%69 = OpAccessChain %19 %5 %65
|
|
%70 = OpLoad %14 %69
|
|
%71 = OpAccessChain %19 %4 %65
|
|
OpStore %71 %70
|
|
OpBranch %75
|
|
%75 = OpLabel
|
|
%76 = OpIAdd %9 %65 %20
|
|
OpStore %3 %76
|
|
OpBranch %64
|
|
%77 = OpLabel
|
|
OpBranch %22
|
|
%22 = OpLabel
|
|
%23 = OpPhi %9 %11 %77 %24 %25
|
|
OpLoopMerge %26 %25 None
|
|
OpBranch %27
|
|
%27 = OpLabel
|
|
%28 = OpSLessThan %13 %23 %12
|
|
OpBranchConditional %28 %29 %26
|
|
%29 = OpLabel
|
|
%33 = OpAccessChain %19 %4 %23
|
|
%34 = OpLoad %14 %33
|
|
%35 = OpAccessChain %19 %5 %23
|
|
OpStore %35 %34
|
|
OpBranch %25
|
|
%25 = OpLabel
|
|
%24 = OpIAdd %9 %23 %20
|
|
OpStore %3 %24
|
|
OpBranch %22
|
|
%26 = OpLabel
|
|
OpStore %6 %11
|
|
OpBranch %50
|
|
%50 = OpLabel
|
|
%51 = OpPhi %9 %11 %26 %62 %61
|
|
OpLoopMerge %63 %61 None
|
|
OpBranch %52
|
|
%52 = OpLabel
|
|
%53 = OpSLessThan %13 %51 %12
|
|
OpBranchConditional %53 %54 %63
|
|
%54 = OpLabel
|
|
%55 = OpAccessChain %19 %5 %51
|
|
%56 = OpLoad %14 %55
|
|
%57 = OpAccessChain %19 %4 %51
|
|
OpStore %57 %56
|
|
OpBranch %61
|
|
%61 = OpLabel
|
|
%62 = OpIAdd %9 %51 %20
|
|
OpStore %6 %62
|
|
OpBranch %50
|
|
%63 = OpLabel
|
|
OpBranch %36
|
|
%36 = OpLabel
|
|
%37 = OpPhi %9 %11 %63 %38 %39
|
|
OpLoopMerge %40 %39 None
|
|
OpBranch %41
|
|
%41 = OpLabel
|
|
%42 = OpSLessThan %13 %37 %12
|
|
OpBranchConditional %42 %43 %40
|
|
%43 = OpLabel
|
|
%47 = OpAccessChain %19 %4 %37
|
|
%48 = OpLoad %14 %47
|
|
%49 = OpAccessChain %19 %5 %37
|
|
OpStore %49 %48
|
|
OpBranch %39
|
|
%39 = OpLabel
|
|
%38 = OpIAdd %9 %37 %20
|
|
OpStore %6 %38
|
|
OpBranch %36
|
|
%40 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
// clang-format on
|
|
std::unique_ptr<IRContext> context =
|
|
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
|
|
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
Module* module = context->module();
|
|
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
|
|
<< source << std::endl;
|
|
|
|
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
|
|
SinglePassRunAndCheck<LoopFissionPass>(source, expected, true);
|
|
|
|
const Function* function = spvtest::GetFunction(module, 2);
|
|
LoopDescriptor& pre_pass_descriptor = *context->GetLoopDescriptor(function);
|
|
EXPECT_EQ(pre_pass_descriptor.NumLoops(), 2u);
|
|
EXPECT_EQ(pre_pass_descriptor.pre_begin()->NumImmediateChildren(), 0u);
|
|
|
|
// Test that the pass transforms the ir into the expected output.
|
|
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
|
|
SinglePassRunAndCheck<LoopFissionPass>(source, expected, true);
|
|
|
|
// Test that the loop descriptor is correctly maintained and updated by the
|
|
// pass.
|
|
LoopFissionPass loop_fission;
|
|
loop_fission.SetContextForTesting(context.get());
|
|
loop_fission.Process();
|
|
|
|
function = spvtest::GetFunction(module, 2);
|
|
LoopDescriptor& post_pass_descriptor = *context->GetLoopDescriptor(function);
|
|
EXPECT_EQ(post_pass_descriptor.NumLoops(), 4u);
|
|
EXPECT_EQ(post_pass_descriptor.pre_begin()->NumImmediateChildren(), 0u);
|
|
}
|
|
|
|
/*
|
|
#version 430
|
|
int foo() { return 1; }
|
|
void main(void) {
|
|
float A[10];
|
|
float B[10];
|
|
for (int i = 0; i < 10; ++i) {
|
|
B[i] = A[i];
|
|
foo();
|
|
A[i] = B[i];
|
|
}
|
|
}
|
|
|
|
This should not be split as it has a function call in it so we can't determine
|
|
if it has side effects.
|
|
*/
|
|
TEST_F(FissionClassTest, FissionFunctionCall) {
|
|
// clang-format off
|
|
// With LocalMultiStoreElimPass
|
|
const std::string source = R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
OpName %2 "main"
|
|
OpName %3 "foo("
|
|
OpName %4 "i"
|
|
OpName %5 "B"
|
|
OpName %6 "A"
|
|
%7 = OpTypeVoid
|
|
%8 = OpTypeFunction %7
|
|
%9 = OpTypeInt 32 1
|
|
%10 = OpTypeFunction %9
|
|
%11 = OpConstant %9 1
|
|
%12 = OpTypePointer Function %9
|
|
%13 = OpConstant %9 0
|
|
%14 = OpConstant %9 10
|
|
%15 = OpTypeBool
|
|
%16 = OpTypeFloat 32
|
|
%17 = OpTypeInt 32 0
|
|
%18 = OpConstant %17 10
|
|
%19 = OpTypeArray %16 %18
|
|
%20 = OpTypePointer Function %19
|
|
%21 = OpTypePointer Function %16
|
|
%2 = OpFunction %7 None %8
|
|
%22 = OpLabel
|
|
%4 = OpVariable %12 Function
|
|
%5 = OpVariable %20 Function
|
|
%6 = OpVariable %20 Function
|
|
OpStore %4 %13
|
|
OpBranch %23
|
|
%23 = OpLabel
|
|
%24 = OpPhi %9 %13 %22 %25 %26
|
|
OpLoopMerge %27 %26 None
|
|
OpBranch %28
|
|
%28 = OpLabel
|
|
%29 = OpSLessThan %15 %24 %14
|
|
OpBranchConditional %29 %30 %27
|
|
%30 = OpLabel
|
|
%31 = OpAccessChain %21 %6 %24
|
|
%32 = OpLoad %16 %31
|
|
%33 = OpAccessChain %21 %5 %24
|
|
OpStore %33 %32
|
|
%34 = OpFunctionCall %9 %3
|
|
%35 = OpAccessChain %21 %5 %24
|
|
%36 = OpLoad %16 %35
|
|
%37 = OpAccessChain %21 %6 %24
|
|
OpStore %37 %36
|
|
OpBranch %26
|
|
%26 = OpLabel
|
|
%25 = OpIAdd %9 %24 %11
|
|
OpStore %4 %25
|
|
OpBranch %23
|
|
%27 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
%3 = OpFunction %9 None %10
|
|
%38 = OpLabel
|
|
OpReturnValue %11
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
// clang-format on
|
|
std::unique_ptr<IRContext> context =
|
|
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
|
|
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
Module* module = context->module();
|
|
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
|
|
<< source << std::endl;
|
|
|
|
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
|
|
SinglePassRunAndCheck<LoopFissionPass>(source, source, true);
|
|
}
|
|
|
|
/*
|
|
#version 430
|
|
void main(void) {
|
|
float A[10];
|
|
float B[10];
|
|
for (int i = 0; i < 10; ++i) {
|
|
switch (i) {
|
|
case 1:
|
|
B[i] = A[i];
|
|
break;
|
|
default:
|
|
A[i] = B[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
This should be split into:
|
|
for (int i = 0; i < 10; ++i) {
|
|
switch (i) {
|
|
case 1:
|
|
break;
|
|
default:
|
|
A[i] = B[i];
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < 10; ++i) {
|
|
switch (i) {
|
|
case 1:
|
|
B[i] = A[i];
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
*/
|
|
TEST_F(FissionClassTest, FissionSwitchStatement) {
|
|
// clang-format off
|
|
// With LocalMultiStoreElimPass
|
|
const std::string source = R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
OpName %2 "main"
|
|
OpName %3 "i"
|
|
OpName %4 "B"
|
|
OpName %5 "A"
|
|
%6 = OpTypeVoid
|
|
%7 = OpTypeFunction %6
|
|
%8 = OpTypeInt 32 1
|
|
%9 = OpTypePointer Function %8
|
|
%10 = OpConstant %8 0
|
|
%11 = OpConstant %8 10
|
|
%12 = OpTypeBool
|
|
%13 = OpTypeFloat 32
|
|
%14 = OpTypeInt 32 0
|
|
%15 = OpConstant %14 10
|
|
%16 = OpTypeArray %13 %15
|
|
%17 = OpTypePointer Function %16
|
|
%18 = OpTypePointer Function %13
|
|
%19 = OpConstant %8 1
|
|
%2 = OpFunction %6 None %7
|
|
%20 = OpLabel
|
|
%3 = OpVariable %9 Function
|
|
%4 = OpVariable %17 Function
|
|
%5 = OpVariable %17 Function
|
|
OpStore %3 %10
|
|
OpBranch %21
|
|
%21 = OpLabel
|
|
%22 = OpPhi %8 %10 %20 %23 %24
|
|
OpLoopMerge %25 %24 None
|
|
OpBranch %26
|
|
%26 = OpLabel
|
|
%27 = OpSLessThan %12 %22 %11
|
|
OpBranchConditional %27 %28 %25
|
|
%28 = OpLabel
|
|
OpSelectionMerge %29 None
|
|
OpSwitch %22 %30 1 %31
|
|
%30 = OpLabel
|
|
%32 = OpAccessChain %18 %4 %22
|
|
%33 = OpLoad %13 %32
|
|
%34 = OpAccessChain %18 %5 %22
|
|
OpStore %34 %33
|
|
OpBranch %29
|
|
%31 = OpLabel
|
|
%35 = OpAccessChain %18 %5 %22
|
|
%36 = OpLoad %13 %35
|
|
%37 = OpAccessChain %18 %4 %22
|
|
OpStore %37 %36
|
|
OpBranch %29
|
|
%29 = OpLabel
|
|
OpBranch %24
|
|
%24 = OpLabel
|
|
%23 = OpIAdd %8 %22 %19
|
|
OpStore %3 %23
|
|
OpBranch %21
|
|
%25 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
const std::string expected = R"(OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %2 "main"
|
|
OpExecutionMode %2 OriginUpperLeft
|
|
OpSource GLSL 430
|
|
OpName %2 "main"
|
|
OpName %3 "i"
|
|
OpName %4 "B"
|
|
OpName %5 "A"
|
|
%6 = OpTypeVoid
|
|
%7 = OpTypeFunction %6
|
|
%8 = OpTypeInt 32 1
|
|
%9 = OpTypePointer Function %8
|
|
%10 = OpConstant %8 0
|
|
%11 = OpConstant %8 10
|
|
%12 = OpTypeBool
|
|
%13 = OpTypeFloat 32
|
|
%14 = OpTypeInt 32 0
|
|
%15 = OpConstant %14 10
|
|
%16 = OpTypeArray %13 %15
|
|
%17 = OpTypePointer Function %16
|
|
%18 = OpTypePointer Function %13
|
|
%19 = OpConstant %8 1
|
|
%2 = OpFunction %6 None %7
|
|
%20 = OpLabel
|
|
%3 = OpVariable %9 Function
|
|
%4 = OpVariable %17 Function
|
|
%5 = OpVariable %17 Function
|
|
OpStore %3 %10
|
|
OpBranch %38
|
|
%38 = OpLabel
|
|
%39 = OpPhi %8 %10 %20 %53 %52
|
|
OpLoopMerge %54 %52 None
|
|
OpBranch %40
|
|
%40 = OpLabel
|
|
%41 = OpSLessThan %12 %39 %11
|
|
OpBranchConditional %41 %42 %54
|
|
%42 = OpLabel
|
|
OpSelectionMerge %51 None
|
|
OpSwitch %39 %47 1 %43
|
|
%43 = OpLabel
|
|
OpBranch %51
|
|
%47 = OpLabel
|
|
%48 = OpAccessChain %18 %4 %39
|
|
%49 = OpLoad %13 %48
|
|
%50 = OpAccessChain %18 %5 %39
|
|
OpStore %50 %49
|
|
OpBranch %51
|
|
%51 = OpLabel
|
|
OpBranch %52
|
|
%52 = OpLabel
|
|
%53 = OpIAdd %8 %39 %19
|
|
OpStore %3 %53
|
|
OpBranch %38
|
|
%54 = OpLabel
|
|
OpBranch %21
|
|
%21 = OpLabel
|
|
%22 = OpPhi %8 %10 %54 %23 %24
|
|
OpLoopMerge %25 %24 None
|
|
OpBranch %26
|
|
%26 = OpLabel
|
|
%27 = OpSLessThan %12 %22 %11
|
|
OpBranchConditional %27 %28 %25
|
|
%28 = OpLabel
|
|
OpSelectionMerge %29 None
|
|
OpSwitch %22 %30 1 %31
|
|
%30 = OpLabel
|
|
OpBranch %29
|
|
%31 = OpLabel
|
|
%35 = OpAccessChain %18 %5 %22
|
|
%36 = OpLoad %13 %35
|
|
%37 = OpAccessChain %18 %4 %22
|
|
OpStore %37 %36
|
|
OpBranch %29
|
|
%29 = OpLabel
|
|
OpBranch %24
|
|
%24 = OpLabel
|
|
%23 = OpIAdd %8 %22 %19
|
|
OpStore %3 %23
|
|
OpBranch %21
|
|
%25 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
// clang-format on
|
|
std::unique_ptr<IRContext> context =
|
|
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source,
|
|
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
Module* module = context->module();
|
|
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
|
|
<< source << std::endl;
|
|
|
|
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
|
|
SinglePassRunAndCheck<LoopFissionPass>(source, expected, true);
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace opt
|
|
} // namespace spvtools
|