mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-11-23 20:20:06 +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.
1786 lines
54 KiB
C++
1786 lines
54 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 <algorithm>
|
|
#include <iterator>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "gmock/gmock.h"
|
|
#include "source/opt/loop_descriptor.h"
|
|
#include "source/opt/loop_fusion.h"
|
|
#include "test/opt/pass_fixture.h"
|
|
|
|
namespace spvtools {
|
|
namespace opt {
|
|
namespace {
|
|
|
|
using FusionCompatibilityTest = PassTest<::testing::Test>;
|
|
|
|
/*
|
|
Generated from the following GLSL + --eliminate-local-multi-store
|
|
|
|
#version 440 core
|
|
void main() {
|
|
int i = 0; // Can't fuse, i=0 in first & i=10 in second
|
|
for (; i < 10; i++) {}
|
|
for (; i < 10; i++) {}
|
|
}
|
|
*/
|
|
TEST_F(FusionCompatibilityTest, SameInductionVariableDifferentBounds) {
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %4 "main"
|
|
OpExecutionMode %4 OriginUpperLeft
|
|
OpSource GLSL 440
|
|
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
|
|
%31 = OpPhi %6 %9 %5 %21 %13
|
|
OpLoopMerge %12 %13 None
|
|
OpBranch %14
|
|
%14 = OpLabel
|
|
%18 = OpSLessThan %17 %31 %16
|
|
OpBranchConditional %18 %11 %12
|
|
%11 = OpLabel
|
|
OpBranch %13
|
|
%13 = OpLabel
|
|
%21 = OpIAdd %6 %31 %20
|
|
OpStore %8 %21
|
|
OpBranch %10
|
|
%12 = OpLabel
|
|
OpBranch %22
|
|
%22 = OpLabel
|
|
%32 = OpPhi %6 %31 %12 %30 %25
|
|
OpLoopMerge %24 %25 None
|
|
OpBranch %26
|
|
%26 = OpLabel
|
|
%28 = OpSLessThan %17 %32 %16
|
|
OpBranchConditional %28 %23 %24
|
|
%23 = OpLabel
|
|
OpBranch %25
|
|
%25 = OpLabel
|
|
%30 = OpIAdd %6 %32 %20
|
|
OpStore %8 %30
|
|
OpBranch %22
|
|
%24 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
std::unique_ptr<IRContext> context =
|
|
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
|
|
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
Module* module = context->module();
|
|
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
|
|
<< text << std::endl;
|
|
Function& f = *module->begin();
|
|
LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
|
|
EXPECT_EQ(ld.NumLoops(), 2u);
|
|
|
|
auto loops = ld.GetLoopsInBinaryLayoutOrder();
|
|
|
|
LoopFusion fusion(context.get(), loops[0], loops[1]);
|
|
EXPECT_FALSE(fusion.AreCompatible());
|
|
}
|
|
|
|
/*
|
|
Generated from the following GLSL + --eliminate-local-multi-store
|
|
|
|
// 1
|
|
#version 440 core
|
|
void main() {
|
|
for (int i = 0; i < 10; i++) {}
|
|
for (int i = 0; i < 10; i++) {}
|
|
}
|
|
*/
|
|
TEST_F(FusionCompatibilityTest, Compatible) {
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %4 "main"
|
|
OpExecutionMode %4 OriginUpperLeft
|
|
OpSource GLSL 440
|
|
OpName %4 "main"
|
|
OpName %8 "i"
|
|
OpName %22 "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
|
|
%22 = OpVariable %7 Function
|
|
OpStore %8 %9
|
|
OpBranch %10
|
|
%10 = OpLabel
|
|
%32 = OpPhi %6 %9 %5 %21 %13
|
|
OpLoopMerge %12 %13 None
|
|
OpBranch %14
|
|
%14 = OpLabel
|
|
%18 = OpSLessThan %17 %32 %16
|
|
OpBranchConditional %18 %11 %12
|
|
%11 = OpLabel
|
|
OpBranch %13
|
|
%13 = OpLabel
|
|
%21 = OpIAdd %6 %32 %20
|
|
OpStore %8 %21
|
|
OpBranch %10
|
|
%12 = OpLabel
|
|
OpStore %22 %9
|
|
OpBranch %23
|
|
%23 = OpLabel
|
|
%33 = OpPhi %6 %9 %12 %31 %26
|
|
OpLoopMerge %25 %26 None
|
|
OpBranch %27
|
|
%27 = OpLabel
|
|
%29 = OpSLessThan %17 %33 %16
|
|
OpBranchConditional %29 %24 %25
|
|
%24 = OpLabel
|
|
OpBranch %26
|
|
%26 = OpLabel
|
|
%31 = OpIAdd %6 %33 %20
|
|
OpStore %22 %31
|
|
OpBranch %23
|
|
%25 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
std::unique_ptr<IRContext> context =
|
|
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
|
|
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
Module* module = context->module();
|
|
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
|
|
<< text << std::endl;
|
|
Function& f = *module->begin();
|
|
LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
|
|
EXPECT_EQ(ld.NumLoops(), 2u);
|
|
|
|
auto loops = ld.GetLoopsInBinaryLayoutOrder();
|
|
|
|
LoopFusion fusion(context.get(), loops[0], loops[1]);
|
|
EXPECT_TRUE(fusion.AreCompatible());
|
|
}
|
|
|
|
/*
|
|
Generated from the following GLSL + --eliminate-local-multi-store
|
|
|
|
// 2
|
|
#version 440 core
|
|
void main() {
|
|
for (int i = 0; i < 10; i++) {}
|
|
for (int j = 0; j < 10; j++) {}
|
|
}
|
|
|
|
*/
|
|
TEST_F(FusionCompatibilityTest, DifferentName) {
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %4 "main"
|
|
OpExecutionMode %4 OriginUpperLeft
|
|
OpSource GLSL 440
|
|
OpName %4 "main"
|
|
OpName %8 "i"
|
|
OpName %22 "j"
|
|
%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
|
|
%22 = OpVariable %7 Function
|
|
OpStore %8 %9
|
|
OpBranch %10
|
|
%10 = OpLabel
|
|
%32 = OpPhi %6 %9 %5 %21 %13
|
|
OpLoopMerge %12 %13 None
|
|
OpBranch %14
|
|
%14 = OpLabel
|
|
%18 = OpSLessThan %17 %32 %16
|
|
OpBranchConditional %18 %11 %12
|
|
%11 = OpLabel
|
|
OpBranch %13
|
|
%13 = OpLabel
|
|
%21 = OpIAdd %6 %32 %20
|
|
OpStore %8 %21
|
|
OpBranch %10
|
|
%12 = OpLabel
|
|
OpStore %22 %9
|
|
OpBranch %23
|
|
%23 = OpLabel
|
|
%33 = OpPhi %6 %9 %12 %31 %26
|
|
OpLoopMerge %25 %26 None
|
|
OpBranch %27
|
|
%27 = OpLabel
|
|
%29 = OpSLessThan %17 %33 %16
|
|
OpBranchConditional %29 %24 %25
|
|
%24 = OpLabel
|
|
OpBranch %26
|
|
%26 = OpLabel
|
|
%31 = OpIAdd %6 %33 %20
|
|
OpStore %22 %31
|
|
OpBranch %23
|
|
%25 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
std::unique_ptr<IRContext> context =
|
|
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
|
|
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
Module* module = context->module();
|
|
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
|
|
<< text << std::endl;
|
|
Function& f = *module->begin();
|
|
LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
|
|
EXPECT_EQ(ld.NumLoops(), 2u);
|
|
|
|
auto loops = ld.GetLoopsInBinaryLayoutOrder();
|
|
|
|
LoopFusion fusion(context.get(), loops[0], loops[1]);
|
|
EXPECT_TRUE(fusion.AreCompatible());
|
|
}
|
|
|
|
/*
|
|
Generated from the following GLSL + --eliminate-local-multi-store
|
|
|
|
#version 440 core
|
|
void main() {
|
|
// Can't fuse, different step
|
|
for (int i = 0; i < 10; i++) {}
|
|
for (int j = 0; j < 10; j=j+2) {}
|
|
}
|
|
|
|
*/
|
|
TEST_F(FusionCompatibilityTest, SameBoundsDifferentStep) {
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %4 "main"
|
|
OpExecutionMode %4 OriginUpperLeft
|
|
OpSource GLSL 440
|
|
OpName %4 "main"
|
|
OpName %8 "i"
|
|
OpName %22 "j"
|
|
%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
|
|
%31 = OpConstant %6 2
|
|
%4 = OpFunction %2 None %3
|
|
%5 = OpLabel
|
|
%8 = OpVariable %7 Function
|
|
%22 = OpVariable %7 Function
|
|
OpStore %8 %9
|
|
OpBranch %10
|
|
%10 = OpLabel
|
|
%33 = OpPhi %6 %9 %5 %21 %13
|
|
OpLoopMerge %12 %13 None
|
|
OpBranch %14
|
|
%14 = OpLabel
|
|
%18 = OpSLessThan %17 %33 %16
|
|
OpBranchConditional %18 %11 %12
|
|
%11 = OpLabel
|
|
OpBranch %13
|
|
%13 = OpLabel
|
|
%21 = OpIAdd %6 %33 %20
|
|
OpStore %8 %21
|
|
OpBranch %10
|
|
%12 = OpLabel
|
|
OpStore %22 %9
|
|
OpBranch %23
|
|
%23 = OpLabel
|
|
%34 = OpPhi %6 %9 %12 %32 %26
|
|
OpLoopMerge %25 %26 None
|
|
OpBranch %27
|
|
%27 = OpLabel
|
|
%29 = OpSLessThan %17 %34 %16
|
|
OpBranchConditional %29 %24 %25
|
|
%24 = OpLabel
|
|
OpBranch %26
|
|
%26 = OpLabel
|
|
%32 = OpIAdd %6 %34 %31
|
|
OpStore %22 %32
|
|
OpBranch %23
|
|
%25 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
std::unique_ptr<IRContext> context =
|
|
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
|
|
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
Module* module = context->module();
|
|
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
|
|
<< text << std::endl;
|
|
Function& f = *module->begin();
|
|
LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
|
|
EXPECT_EQ(ld.NumLoops(), 2u);
|
|
|
|
auto loops = ld.GetLoopsInBinaryLayoutOrder();
|
|
|
|
LoopFusion fusion(context.get(), loops[0], loops[1]);
|
|
EXPECT_FALSE(fusion.AreCompatible());
|
|
}
|
|
|
|
/*
|
|
Generated from the following GLSL + --eliminate-local-multi-store
|
|
|
|
// 4
|
|
#version 440 core
|
|
void main() {
|
|
// Can't fuse, different upper bound
|
|
for (int i = 0; i < 10; i++) {}
|
|
for (int j = 0; j < 20; j++) {}
|
|
}
|
|
|
|
*/
|
|
TEST_F(FusionCompatibilityTest, DifferentUpperBound) {
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %4 "main"
|
|
OpExecutionMode %4 OriginUpperLeft
|
|
OpSource GLSL 440
|
|
OpName %4 "main"
|
|
OpName %8 "i"
|
|
OpName %22 "j"
|
|
%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
|
|
%29 = OpConstant %6 20
|
|
%4 = OpFunction %2 None %3
|
|
%5 = OpLabel
|
|
%8 = OpVariable %7 Function
|
|
%22 = OpVariable %7 Function
|
|
OpStore %8 %9
|
|
OpBranch %10
|
|
%10 = OpLabel
|
|
%33 = OpPhi %6 %9 %5 %21 %13
|
|
OpLoopMerge %12 %13 None
|
|
OpBranch %14
|
|
%14 = OpLabel
|
|
%18 = OpSLessThan %17 %33 %16
|
|
OpBranchConditional %18 %11 %12
|
|
%11 = OpLabel
|
|
OpBranch %13
|
|
%13 = OpLabel
|
|
%21 = OpIAdd %6 %33 %20
|
|
OpStore %8 %21
|
|
OpBranch %10
|
|
%12 = OpLabel
|
|
OpStore %22 %9
|
|
OpBranch %23
|
|
%23 = OpLabel
|
|
%34 = OpPhi %6 %9 %12 %32 %26
|
|
OpLoopMerge %25 %26 None
|
|
OpBranch %27
|
|
%27 = OpLabel
|
|
%30 = OpSLessThan %17 %34 %29
|
|
OpBranchConditional %30 %24 %25
|
|
%24 = OpLabel
|
|
OpBranch %26
|
|
%26 = OpLabel
|
|
%32 = OpIAdd %6 %34 %20
|
|
OpStore %22 %32
|
|
OpBranch %23
|
|
%25 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
std::unique_ptr<IRContext> context =
|
|
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
|
|
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
Module* module = context->module();
|
|
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
|
|
<< text << std::endl;
|
|
Function& f = *module->begin();
|
|
LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
|
|
EXPECT_EQ(ld.NumLoops(), 2u);
|
|
|
|
auto loops = ld.GetLoopsInBinaryLayoutOrder();
|
|
|
|
LoopFusion fusion(context.get(), loops[0], loops[1]);
|
|
EXPECT_FALSE(fusion.AreCompatible());
|
|
}
|
|
|
|
/*
|
|
Generated from the following GLSL + --eliminate-local-multi-store
|
|
|
|
// 5
|
|
#version 440 core
|
|
void main() {
|
|
// Can't fuse, different lower bound
|
|
for (int i = 5; i < 10; i++) {}
|
|
for (int j = 0; j < 10; j++) {}
|
|
}
|
|
|
|
*/
|
|
TEST_F(FusionCompatibilityTest, DifferentLowerBound) {
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %4 "main"
|
|
OpExecutionMode %4 OriginUpperLeft
|
|
OpSource GLSL 440
|
|
OpName %4 "main"
|
|
OpName %8 "i"
|
|
OpName %22 "j"
|
|
%2 = OpTypeVoid
|
|
%3 = OpTypeFunction %2
|
|
%6 = OpTypeInt 32 1
|
|
%7 = OpTypePointer Function %6
|
|
%9 = OpConstant %6 5
|
|
%16 = OpConstant %6 10
|
|
%17 = OpTypeBool
|
|
%20 = OpConstant %6 1
|
|
%23 = OpConstant %6 0
|
|
%4 = OpFunction %2 None %3
|
|
%5 = OpLabel
|
|
%8 = OpVariable %7 Function
|
|
%22 = OpVariable %7 Function
|
|
OpStore %8 %9
|
|
OpBranch %10
|
|
%10 = OpLabel
|
|
%33 = OpPhi %6 %9 %5 %21 %13
|
|
OpLoopMerge %12 %13 None
|
|
OpBranch %14
|
|
%14 = OpLabel
|
|
%18 = OpSLessThan %17 %33 %16
|
|
OpBranchConditional %18 %11 %12
|
|
%11 = OpLabel
|
|
OpBranch %13
|
|
%13 = OpLabel
|
|
%21 = OpIAdd %6 %33 %20
|
|
OpStore %8 %21
|
|
OpBranch %10
|
|
%12 = OpLabel
|
|
OpStore %22 %23
|
|
OpBranch %24
|
|
%24 = OpLabel
|
|
%34 = OpPhi %6 %23 %12 %32 %27
|
|
OpLoopMerge %26 %27 None
|
|
OpBranch %28
|
|
%28 = OpLabel
|
|
%30 = OpSLessThan %17 %34 %16
|
|
OpBranchConditional %30 %25 %26
|
|
%25 = OpLabel
|
|
OpBranch %27
|
|
%27 = OpLabel
|
|
%32 = OpIAdd %6 %34 %20
|
|
OpStore %22 %32
|
|
OpBranch %24
|
|
%26 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
std::unique_ptr<IRContext> context =
|
|
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
|
|
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
Module* module = context->module();
|
|
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
|
|
<< text << std::endl;
|
|
Function& f = *module->begin();
|
|
LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
|
|
EXPECT_EQ(ld.NumLoops(), 2u);
|
|
|
|
auto loops = ld.GetLoopsInBinaryLayoutOrder();
|
|
|
|
LoopFusion fusion(context.get(), loops[0], loops[1]);
|
|
EXPECT_FALSE(fusion.AreCompatible());
|
|
}
|
|
|
|
/*
|
|
Generated from the following GLSL + --eliminate-local-multi-store
|
|
|
|
// 6
|
|
#version 440 core
|
|
void main() {
|
|
// Can't fuse, break in first loop
|
|
for (int i = 0; i < 10; i++) {
|
|
if (i == 5) {
|
|
break;
|
|
}
|
|
}
|
|
for (int j = 0; j < 10; j++) {}
|
|
}
|
|
|
|
*/
|
|
TEST_F(FusionCompatibilityTest, Break) {
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %4 "main"
|
|
OpExecutionMode %4 OriginUpperLeft
|
|
OpSource GLSL 440
|
|
OpName %4 "main"
|
|
OpName %8 "i"
|
|
OpName %28 "j"
|
|
%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 5
|
|
%26 = OpConstant %6 1
|
|
%4 = OpFunction %2 None %3
|
|
%5 = OpLabel
|
|
%8 = OpVariable %7 Function
|
|
%28 = OpVariable %7 Function
|
|
OpStore %8 %9
|
|
OpBranch %10
|
|
%10 = OpLabel
|
|
%38 = OpPhi %6 %9 %5 %27 %13
|
|
OpLoopMerge %12 %13 None
|
|
OpBranch %14
|
|
%14 = OpLabel
|
|
%18 = OpSLessThan %17 %38 %16
|
|
OpBranchConditional %18 %11 %12
|
|
%11 = OpLabel
|
|
%21 = OpIEqual %17 %38 %20
|
|
OpSelectionMerge %23 None
|
|
OpBranchConditional %21 %22 %23
|
|
%22 = OpLabel
|
|
OpBranch %12
|
|
%23 = OpLabel
|
|
OpBranch %13
|
|
%13 = OpLabel
|
|
%27 = OpIAdd %6 %38 %26
|
|
OpStore %8 %27
|
|
OpBranch %10
|
|
%12 = OpLabel
|
|
OpStore %28 %9
|
|
OpBranch %29
|
|
%29 = OpLabel
|
|
%39 = OpPhi %6 %9 %12 %37 %32
|
|
OpLoopMerge %31 %32 None
|
|
OpBranch %33
|
|
%33 = OpLabel
|
|
%35 = OpSLessThan %17 %39 %16
|
|
OpBranchConditional %35 %30 %31
|
|
%30 = OpLabel
|
|
OpBranch %32
|
|
%32 = OpLabel
|
|
%37 = OpIAdd %6 %39 %26
|
|
OpStore %28 %37
|
|
OpBranch %29
|
|
%31 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
std::unique_ptr<IRContext> context =
|
|
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
|
|
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
Module* module = context->module();
|
|
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
|
|
<< text << std::endl;
|
|
Function& f = *module->begin();
|
|
LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
|
|
EXPECT_EQ(ld.NumLoops(), 2u);
|
|
|
|
auto loops = ld.GetLoopsInBinaryLayoutOrder();
|
|
|
|
LoopFusion fusion(context.get(), loops[0], loops[1]);
|
|
EXPECT_FALSE(fusion.AreCompatible());
|
|
}
|
|
|
|
/*
|
|
Generated from the following GLSL + --eliminate-local-multi-store
|
|
|
|
#version 440 core
|
|
layout(location = 0) in vec4 c;
|
|
void main() {
|
|
int N = int(c.x);
|
|
for (int i = 0; i < N; i++) {}
|
|
for (int j = 0; j < N; j++) {}
|
|
}
|
|
|
|
*/
|
|
TEST_F(FusionCompatibilityTest, UnknownButSameUpperBound) {
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %4 "main" %12
|
|
OpExecutionMode %4 OriginUpperLeft
|
|
OpSource GLSL 440
|
|
OpName %4 "main"
|
|
OpName %8 "N"
|
|
OpName %12 "c"
|
|
OpName %19 "i"
|
|
OpName %33 "j"
|
|
OpDecorate %12 Location 0
|
|
%2 = OpTypeVoid
|
|
%3 = OpTypeFunction %2
|
|
%6 = OpTypeInt 32 1
|
|
%7 = OpTypePointer Function %6
|
|
%9 = OpTypeFloat 32
|
|
%10 = OpTypeVector %9 4
|
|
%11 = OpTypePointer Input %10
|
|
%12 = OpVariable %11 Input
|
|
%13 = OpTypeInt 32 0
|
|
%14 = OpConstant %13 0
|
|
%15 = OpTypePointer Input %9
|
|
%20 = OpConstant %6 0
|
|
%28 = OpTypeBool
|
|
%31 = OpConstant %6 1
|
|
%4 = OpFunction %2 None %3
|
|
%5 = OpLabel
|
|
%8 = OpVariable %7 Function
|
|
%19 = OpVariable %7 Function
|
|
%33 = OpVariable %7 Function
|
|
%16 = OpAccessChain %15 %12 %14
|
|
%17 = OpLoad %9 %16
|
|
%18 = OpConvertFToS %6 %17
|
|
OpStore %8 %18
|
|
OpStore %19 %20
|
|
OpBranch %21
|
|
%21 = OpLabel
|
|
%44 = OpPhi %6 %20 %5 %32 %24
|
|
OpLoopMerge %23 %24 None
|
|
OpBranch %25
|
|
%25 = OpLabel
|
|
%29 = OpSLessThan %28 %44 %18
|
|
OpBranchConditional %29 %22 %23
|
|
%22 = OpLabel
|
|
OpBranch %24
|
|
%24 = OpLabel
|
|
%32 = OpIAdd %6 %44 %31
|
|
OpStore %19 %32
|
|
OpBranch %21
|
|
%23 = OpLabel
|
|
OpStore %33 %20
|
|
OpBranch %34
|
|
%34 = OpLabel
|
|
%46 = OpPhi %6 %20 %23 %43 %37
|
|
OpLoopMerge %36 %37 None
|
|
OpBranch %38
|
|
%38 = OpLabel
|
|
%41 = OpSLessThan %28 %46 %18
|
|
OpBranchConditional %41 %35 %36
|
|
%35 = OpLabel
|
|
OpBranch %37
|
|
%37 = OpLabel
|
|
%43 = OpIAdd %6 %46 %31
|
|
OpStore %33 %43
|
|
OpBranch %34
|
|
%36 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
std::unique_ptr<IRContext> context =
|
|
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
|
|
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
Module* module = context->module();
|
|
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
|
|
<< text << std::endl;
|
|
Function& f = *module->begin();
|
|
LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
|
|
EXPECT_EQ(ld.NumLoops(), 2u);
|
|
|
|
auto loops = ld.GetLoopsInBinaryLayoutOrder();
|
|
|
|
LoopFusion fusion(context.get(), loops[0], loops[1]);
|
|
EXPECT_TRUE(fusion.AreCompatible());
|
|
}
|
|
|
|
/*
|
|
Generated from the following GLSL + --eliminate-local-multi-store
|
|
|
|
#version 440 core
|
|
layout(location = 0) in vec4 c;
|
|
void main() {
|
|
int N = int(c.x);
|
|
for (int i = 0; N > j; i++) {}
|
|
for (int j = 0; N > j; j++) {}
|
|
}
|
|
*/
|
|
TEST_F(FusionCompatibilityTest, UnknownButSameUpperBoundReverseCondition) {
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %4 "main" %12
|
|
OpExecutionMode %4 OriginUpperLeft
|
|
OpSource GLSL 440
|
|
OpName %4 "main"
|
|
OpName %8 "N"
|
|
OpName %12 "c"
|
|
OpName %19 "i"
|
|
OpName %33 "j"
|
|
OpDecorate %12 Location 0
|
|
%2 = OpTypeVoid
|
|
%3 = OpTypeFunction %2
|
|
%6 = OpTypeInt 32 1
|
|
%7 = OpTypePointer Function %6
|
|
%9 = OpTypeFloat 32
|
|
%10 = OpTypeVector %9 4
|
|
%11 = OpTypePointer Input %10
|
|
%12 = OpVariable %11 Input
|
|
%13 = OpTypeInt 32 0
|
|
%14 = OpConstant %13 0
|
|
%15 = OpTypePointer Input %9
|
|
%20 = OpConstant %6 0
|
|
%28 = OpTypeBool
|
|
%31 = OpConstant %6 1
|
|
%4 = OpFunction %2 None %3
|
|
%5 = OpLabel
|
|
%8 = OpVariable %7 Function
|
|
%19 = OpVariable %7 Function
|
|
%33 = OpVariable %7 Function
|
|
%16 = OpAccessChain %15 %12 %14
|
|
%17 = OpLoad %9 %16
|
|
%18 = OpConvertFToS %6 %17
|
|
OpStore %8 %18
|
|
OpStore %19 %20
|
|
OpBranch %21
|
|
%21 = OpLabel
|
|
%45 = OpPhi %6 %20 %5 %32 %24
|
|
OpLoopMerge %23 %24 None
|
|
OpBranch %25
|
|
%25 = OpLabel
|
|
%29 = OpSGreaterThan %28 %18 %45
|
|
OpBranchConditional %29 %22 %23
|
|
%22 = OpLabel
|
|
OpBranch %24
|
|
%24 = OpLabel
|
|
%32 = OpIAdd %6 %45 %31
|
|
OpStore %19 %32
|
|
OpBranch %21
|
|
%23 = OpLabel
|
|
OpStore %33 %20
|
|
OpBranch %34
|
|
%34 = OpLabel
|
|
%47 = OpPhi %6 %20 %23 %43 %37
|
|
OpLoopMerge %36 %37 None
|
|
OpBranch %38
|
|
%38 = OpLabel
|
|
%41 = OpSGreaterThan %28 %18 %47
|
|
OpBranchConditional %41 %35 %36
|
|
%35 = OpLabel
|
|
OpBranch %37
|
|
%37 = OpLabel
|
|
%43 = OpIAdd %6 %47 %31
|
|
OpStore %33 %43
|
|
OpBranch %34
|
|
%36 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
std::unique_ptr<IRContext> context =
|
|
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
|
|
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
Module* module = context->module();
|
|
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
|
|
<< text << std::endl;
|
|
Function& f = *module->begin();
|
|
LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
|
|
EXPECT_EQ(ld.NumLoops(), 2u);
|
|
|
|
auto loops = ld.GetLoopsInBinaryLayoutOrder();
|
|
|
|
LoopFusion fusion(context.get(), loops[0], loops[1]);
|
|
EXPECT_TRUE(fusion.AreCompatible());
|
|
}
|
|
|
|
/*
|
|
Generated from the following GLSL + --eliminate-local-multi-store
|
|
|
|
#version 440 core
|
|
layout(location = 0) in vec4 c;
|
|
void main() {
|
|
// Can't fuse different bound
|
|
int N = int(c.x);
|
|
for (int i = 0; i < N; i++) {}
|
|
for (int j = 0; j < N+1; j++) {}
|
|
}
|
|
|
|
*/
|
|
TEST_F(FusionCompatibilityTest, UnknownUpperBoundAddition) {
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %4 "main" %12
|
|
OpExecutionMode %4 OriginUpperLeft
|
|
OpSource GLSL 440
|
|
OpName %4 "main"
|
|
OpName %8 "N"
|
|
OpName %12 "c"
|
|
OpName %19 "i"
|
|
OpName %33 "j"
|
|
OpDecorate %12 Location 0
|
|
%2 = OpTypeVoid
|
|
%3 = OpTypeFunction %2
|
|
%6 = OpTypeInt 32 1
|
|
%7 = OpTypePointer Function %6
|
|
%9 = OpTypeFloat 32
|
|
%10 = OpTypeVector %9 4
|
|
%11 = OpTypePointer Input %10
|
|
%12 = OpVariable %11 Input
|
|
%13 = OpTypeInt 32 0
|
|
%14 = OpConstant %13 0
|
|
%15 = OpTypePointer Input %9
|
|
%20 = OpConstant %6 0
|
|
%28 = OpTypeBool
|
|
%31 = OpConstant %6 1
|
|
%4 = OpFunction %2 None %3
|
|
%5 = OpLabel
|
|
%8 = OpVariable %7 Function
|
|
%19 = OpVariable %7 Function
|
|
%33 = OpVariable %7 Function
|
|
%16 = OpAccessChain %15 %12 %14
|
|
%17 = OpLoad %9 %16
|
|
%18 = OpConvertFToS %6 %17
|
|
OpStore %8 %18
|
|
OpStore %19 %20
|
|
OpBranch %21
|
|
%21 = OpLabel
|
|
%45 = OpPhi %6 %20 %5 %32 %24
|
|
OpLoopMerge %23 %24 None
|
|
OpBranch %25
|
|
%25 = OpLabel
|
|
%29 = OpSLessThan %28 %45 %18
|
|
OpBranchConditional %29 %22 %23
|
|
%22 = OpLabel
|
|
OpBranch %24
|
|
%24 = OpLabel
|
|
%32 = OpIAdd %6 %45 %31
|
|
OpStore %19 %32
|
|
OpBranch %21
|
|
%23 = OpLabel
|
|
OpStore %33 %20
|
|
OpBranch %34
|
|
%34 = OpLabel
|
|
%47 = OpPhi %6 %20 %23 %44 %37
|
|
OpLoopMerge %36 %37 None
|
|
OpBranch %38
|
|
%38 = OpLabel
|
|
%41 = OpIAdd %6 %18 %31
|
|
%42 = OpSLessThan %28 %47 %41
|
|
OpBranchConditional %42 %35 %36
|
|
%35 = OpLabel
|
|
OpBranch %37
|
|
%37 = OpLabel
|
|
%44 = OpIAdd %6 %47 %31
|
|
OpStore %33 %44
|
|
OpBranch %34
|
|
%36 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
std::unique_ptr<IRContext> context =
|
|
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
|
|
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
Module* module = context->module();
|
|
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
|
|
<< text << std::endl;
|
|
Function& f = *module->begin();
|
|
LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
|
|
EXPECT_EQ(ld.NumLoops(), 2u);
|
|
|
|
auto loops = ld.GetLoopsInBinaryLayoutOrder();
|
|
|
|
LoopFusion fusion(context.get(), loops[0], loops[1]);
|
|
EXPECT_FALSE(fusion.AreCompatible());
|
|
}
|
|
|
|
/*
|
|
Generated from the following GLSL + --eliminate-local-multi-store
|
|
|
|
// 10
|
|
#version 440 core
|
|
void main() {
|
|
for (int i = 0; i < 10; i++) {}
|
|
for (int j = 0; j < 10; j++) {}
|
|
for (int k = 0; k < 10; k++) {}
|
|
}
|
|
|
|
*/
|
|
TEST_F(FusionCompatibilityTest, SeveralAdjacentLoops) {
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %4 "main"
|
|
OpExecutionMode %4 OriginUpperLeft
|
|
OpSource GLSL 440
|
|
OpName %4 "main"
|
|
OpName %8 "i"
|
|
OpName %22 "j"
|
|
OpName %32 "k"
|
|
%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
|
|
%22 = OpVariable %7 Function
|
|
%32 = OpVariable %7 Function
|
|
OpStore %8 %9
|
|
OpBranch %10
|
|
%10 = OpLabel
|
|
%42 = OpPhi %6 %9 %5 %21 %13
|
|
OpLoopMerge %12 %13 None
|
|
OpBranch %14
|
|
%14 = OpLabel
|
|
%18 = OpSLessThan %17 %42 %16
|
|
OpBranchConditional %18 %11 %12
|
|
%11 = OpLabel
|
|
OpBranch %13
|
|
%13 = OpLabel
|
|
%21 = OpIAdd %6 %42 %20
|
|
OpStore %8 %21
|
|
OpBranch %10
|
|
%12 = OpLabel
|
|
OpStore %22 %9
|
|
OpBranch %23
|
|
%23 = OpLabel
|
|
%43 = OpPhi %6 %9 %12 %31 %26
|
|
OpLoopMerge %25 %26 None
|
|
OpBranch %27
|
|
%27 = OpLabel
|
|
%29 = OpSLessThan %17 %43 %16
|
|
OpBranchConditional %29 %24 %25
|
|
%24 = OpLabel
|
|
OpBranch %26
|
|
%26 = OpLabel
|
|
%31 = OpIAdd %6 %43 %20
|
|
OpStore %22 %31
|
|
OpBranch %23
|
|
%25 = OpLabel
|
|
OpStore %32 %9
|
|
OpBranch %33
|
|
%33 = OpLabel
|
|
%44 = OpPhi %6 %9 %25 %41 %36
|
|
OpLoopMerge %35 %36 None
|
|
OpBranch %37
|
|
%37 = OpLabel
|
|
%39 = OpSLessThan %17 %44 %16
|
|
OpBranchConditional %39 %34 %35
|
|
%34 = OpLabel
|
|
OpBranch %36
|
|
%36 = OpLabel
|
|
%41 = OpIAdd %6 %44 %20
|
|
OpStore %32 %41
|
|
OpBranch %33
|
|
%35 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
std::unique_ptr<IRContext> context =
|
|
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
|
|
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
Module* module = context->module();
|
|
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
|
|
<< text << std::endl;
|
|
Function& f = *module->begin();
|
|
LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
|
|
EXPECT_EQ(ld.NumLoops(), 3u);
|
|
|
|
auto loops = ld.GetLoopsInBinaryLayoutOrder();
|
|
|
|
auto loop_0 = loops[0];
|
|
auto loop_1 = loops[1];
|
|
auto loop_2 = loops[2];
|
|
|
|
EXPECT_FALSE(LoopFusion(context.get(), loop_0, loop_0).AreCompatible());
|
|
EXPECT_FALSE(LoopFusion(context.get(), loop_0, loop_2).AreCompatible());
|
|
EXPECT_FALSE(LoopFusion(context.get(), loop_1, loop_0).AreCompatible());
|
|
EXPECT_TRUE(LoopFusion(context.get(), loop_0, loop_1).AreCompatible());
|
|
EXPECT_TRUE(LoopFusion(context.get(), loop_1, loop_2).AreCompatible());
|
|
}
|
|
|
|
/*
|
|
Generated from the following GLSL + --eliminate-local-multi-store
|
|
|
|
#version 440 core
|
|
void main() {
|
|
// Can't fuse, not adjacent
|
|
int x = 0;
|
|
for (int i = 0; i < 10; i++) {
|
|
if (i > 10) {
|
|
x++;
|
|
}
|
|
}
|
|
x++;
|
|
for (int j = 0; j < 10; j++) {}
|
|
for (int k = 0; k < 10; k++) {}
|
|
}
|
|
|
|
*/
|
|
TEST_F(FusionCompatibilityTest, NonAdjacentLoops) {
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %4 "main"
|
|
OpExecutionMode %4 OriginUpperLeft
|
|
OpSource GLSL 440
|
|
OpName %4 "main"
|
|
OpName %8 "x"
|
|
OpName %10 "i"
|
|
OpName %31 "j"
|
|
OpName %41 "k"
|
|
%2 = OpTypeVoid
|
|
%3 = OpTypeFunction %2
|
|
%6 = OpTypeInt 32 1
|
|
%7 = OpTypePointer Function %6
|
|
%9 = OpConstant %6 0
|
|
%17 = OpConstant %6 10
|
|
%18 = OpTypeBool
|
|
%25 = OpConstant %6 1
|
|
%4 = OpFunction %2 None %3
|
|
%5 = OpLabel
|
|
%8 = OpVariable %7 Function
|
|
%10 = OpVariable %7 Function
|
|
%31 = OpVariable %7 Function
|
|
%41 = OpVariable %7 Function
|
|
OpStore %8 %9
|
|
OpStore %10 %9
|
|
OpBranch %11
|
|
%11 = OpLabel
|
|
%52 = OpPhi %6 %9 %5 %56 %14
|
|
%51 = OpPhi %6 %9 %5 %28 %14
|
|
OpLoopMerge %13 %14 None
|
|
OpBranch %15
|
|
%15 = OpLabel
|
|
%19 = OpSLessThan %18 %51 %17
|
|
OpBranchConditional %19 %12 %13
|
|
%12 = OpLabel
|
|
%21 = OpSGreaterThan %18 %52 %17
|
|
OpSelectionMerge %23 None
|
|
OpBranchConditional %21 %22 %23
|
|
%22 = OpLabel
|
|
%26 = OpIAdd %6 %52 %25
|
|
OpStore %8 %26
|
|
OpBranch %23
|
|
%23 = OpLabel
|
|
%56 = OpPhi %6 %52 %12 %26 %22
|
|
OpBranch %14
|
|
%14 = OpLabel
|
|
%28 = OpIAdd %6 %51 %25
|
|
OpStore %10 %28
|
|
OpBranch %11
|
|
%13 = OpLabel
|
|
%30 = OpIAdd %6 %52 %25
|
|
OpStore %8 %30
|
|
OpStore %31 %9
|
|
OpBranch %32
|
|
%32 = OpLabel
|
|
%53 = OpPhi %6 %9 %13 %40 %35
|
|
OpLoopMerge %34 %35 None
|
|
OpBranch %36
|
|
%36 = OpLabel
|
|
%38 = OpSLessThan %18 %53 %17
|
|
OpBranchConditional %38 %33 %34
|
|
%33 = OpLabel
|
|
OpBranch %35
|
|
%35 = OpLabel
|
|
%40 = OpIAdd %6 %53 %25
|
|
OpStore %31 %40
|
|
OpBranch %32
|
|
%34 = OpLabel
|
|
OpStore %41 %9
|
|
OpBranch %42
|
|
%42 = OpLabel
|
|
%54 = OpPhi %6 %9 %34 %50 %45
|
|
OpLoopMerge %44 %45 None
|
|
OpBranch %46
|
|
%46 = OpLabel
|
|
%48 = OpSLessThan %18 %54 %17
|
|
OpBranchConditional %48 %43 %44
|
|
%43 = OpLabel
|
|
OpBranch %45
|
|
%45 = OpLabel
|
|
%50 = OpIAdd %6 %54 %25
|
|
OpStore %41 %50
|
|
OpBranch %42
|
|
%44 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
std::unique_ptr<IRContext> context =
|
|
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
|
|
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
Module* module = context->module();
|
|
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
|
|
<< text << std::endl;
|
|
Function& f = *module->begin();
|
|
LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
|
|
EXPECT_EQ(ld.NumLoops(), 3u);
|
|
|
|
auto loops = ld.GetLoopsInBinaryLayoutOrder();
|
|
|
|
auto loop_0 = loops[0];
|
|
auto loop_1 = loops[1];
|
|
auto loop_2 = loops[2];
|
|
|
|
EXPECT_FALSE(LoopFusion(context.get(), loop_0, loop_0).AreCompatible());
|
|
EXPECT_FALSE(LoopFusion(context.get(), loop_0, loop_2).AreCompatible());
|
|
EXPECT_FALSE(LoopFusion(context.get(), loop_0, loop_1).AreCompatible());
|
|
EXPECT_TRUE(LoopFusion(context.get(), loop_1, loop_2).AreCompatible());
|
|
}
|
|
|
|
/*
|
|
Generated from the following GLSL + --eliminate-local-multi-store
|
|
|
|
// 12
|
|
#version 440 core
|
|
void main() {
|
|
int j = 0;
|
|
int i = 0;
|
|
for (; i < 10; i++) {}
|
|
for (; j < 10; j++) {}
|
|
}
|
|
|
|
*/
|
|
TEST_F(FusionCompatibilityTest, CompatibleInitDeclaredBeforeLoops) {
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %4 "main"
|
|
OpExecutionMode %4 OriginUpperLeft
|
|
OpSource GLSL 440
|
|
OpName %4 "main"
|
|
OpName %8 "j"
|
|
OpName %10 "i"
|
|
%2 = OpTypeVoid
|
|
%3 = OpTypeFunction %2
|
|
%6 = OpTypeInt 32 1
|
|
%7 = OpTypePointer Function %6
|
|
%9 = OpConstant %6 0
|
|
%17 = OpConstant %6 10
|
|
%18 = OpTypeBool
|
|
%21 = OpConstant %6 1
|
|
%4 = OpFunction %2 None %3
|
|
%5 = OpLabel
|
|
%8 = OpVariable %7 Function
|
|
%10 = OpVariable %7 Function
|
|
OpStore %8 %9
|
|
OpStore %10 %9
|
|
OpBranch %11
|
|
%11 = OpLabel
|
|
%32 = OpPhi %6 %9 %5 %22 %14
|
|
OpLoopMerge %13 %14 None
|
|
OpBranch %15
|
|
%15 = OpLabel
|
|
%19 = OpSLessThan %18 %32 %17
|
|
OpBranchConditional %19 %12 %13
|
|
%12 = OpLabel
|
|
OpBranch %14
|
|
%14 = OpLabel
|
|
%22 = OpIAdd %6 %32 %21
|
|
OpStore %10 %22
|
|
OpBranch %11
|
|
%13 = OpLabel
|
|
OpBranch %23
|
|
%23 = OpLabel
|
|
%33 = OpPhi %6 %9 %13 %31 %26
|
|
OpLoopMerge %25 %26 None
|
|
OpBranch %27
|
|
%27 = OpLabel
|
|
%29 = OpSLessThan %18 %33 %17
|
|
OpBranchConditional %29 %24 %25
|
|
%24 = OpLabel
|
|
OpBranch %26
|
|
%26 = OpLabel
|
|
%31 = OpIAdd %6 %33 %21
|
|
OpStore %8 %31
|
|
OpBranch %23
|
|
%25 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
std::unique_ptr<IRContext> context =
|
|
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
|
|
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
Module* module = context->module();
|
|
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
|
|
<< text << std::endl;
|
|
Function& f = *module->begin();
|
|
LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
|
|
EXPECT_EQ(ld.NumLoops(), 2u);
|
|
|
|
auto loops = ld.GetLoopsInBinaryLayoutOrder();
|
|
|
|
EXPECT_TRUE(LoopFusion(context.get(), loops[0], loops[1]).AreCompatible());
|
|
}
|
|
|
|
/*
|
|
Generated from the following GLSL + --eliminate-local-multi-store
|
|
|
|
// 13 regenerate!
|
|
#version 440 core
|
|
void main() {
|
|
int[10] a;
|
|
int[10] b;
|
|
// Can't fuse, several induction variables
|
|
for (int j = 0; j < 10; j++) {
|
|
b[i] = a[i];
|
|
}
|
|
for (int i = 0, j = 0; i < 10; i++, j = j+2) {
|
|
}
|
|
}
|
|
|
|
*/
|
|
TEST_F(FusionCompatibilityTest, SeveralInductionVariables) {
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %4 "main"
|
|
OpExecutionMode %4 OriginUpperLeft
|
|
OpSource GLSL 440
|
|
OpName %4 "main"
|
|
OpName %8 "j"
|
|
OpName %23 "b"
|
|
OpName %25 "a"
|
|
OpName %33 "i"
|
|
OpName %34 "j"
|
|
%2 = OpTypeVoid
|
|
%3 = OpTypeFunction %2
|
|
%6 = OpTypeInt 32 1
|
|
%7 = OpTypePointer Function %6
|
|
%9 = OpConstant %6 0
|
|
%16 = OpConstant %6 10
|
|
%17 = OpTypeBool
|
|
%19 = OpTypeInt 32 0
|
|
%20 = OpConstant %19 10
|
|
%21 = OpTypeArray %6 %20
|
|
%22 = OpTypePointer Function %21
|
|
%31 = OpConstant %6 1
|
|
%48 = OpConstant %6 2
|
|
%4 = OpFunction %2 None %3
|
|
%5 = OpLabel
|
|
%8 = OpVariable %7 Function
|
|
%23 = OpVariable %22 Function
|
|
%25 = OpVariable %22 Function
|
|
%33 = OpVariable %7 Function
|
|
%34 = OpVariable %7 Function
|
|
OpStore %8 %9
|
|
OpBranch %10
|
|
%10 = OpLabel
|
|
%50 = OpPhi %6 %9 %5 %32 %13
|
|
OpLoopMerge %12 %13 None
|
|
OpBranch %14
|
|
%14 = OpLabel
|
|
%18 = OpSLessThan %17 %50 %16
|
|
OpBranchConditional %18 %11 %12
|
|
%11 = OpLabel
|
|
%27 = OpAccessChain %7 %25 %50
|
|
%28 = OpLoad %6 %27
|
|
%29 = OpAccessChain %7 %23 %50
|
|
OpStore %29 %28
|
|
OpBranch %13
|
|
%13 = OpLabel
|
|
%32 = OpIAdd %6 %50 %31
|
|
OpStore %8 %32
|
|
OpBranch %10
|
|
%12 = OpLabel
|
|
OpStore %33 %9
|
|
OpStore %34 %9
|
|
OpBranch %35
|
|
%35 = OpLabel
|
|
%52 = OpPhi %6 %9 %12 %49 %38
|
|
%51 = OpPhi %6 %9 %12 %46 %38
|
|
OpLoopMerge %37 %38 None
|
|
OpBranch %39
|
|
%39 = OpLabel
|
|
%41 = OpSLessThan %17 %51 %16
|
|
OpBranchConditional %41 %36 %37
|
|
%36 = OpLabel
|
|
%44 = OpAccessChain %7 %25 %52
|
|
OpStore %44 %51
|
|
OpBranch %38
|
|
%38 = OpLabel
|
|
%46 = OpIAdd %6 %51 %31
|
|
OpStore %33 %46
|
|
%49 = OpIAdd %6 %52 %48
|
|
OpStore %34 %49
|
|
OpBranch %35
|
|
%37 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
std::unique_ptr<IRContext> context =
|
|
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
|
|
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
Module* module = context->module();
|
|
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
|
|
<< text << std::endl;
|
|
Function& f = *module->begin();
|
|
LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
|
|
EXPECT_EQ(ld.NumLoops(), 2u);
|
|
|
|
auto loops = ld.GetLoopsInBinaryLayoutOrder();
|
|
|
|
EXPECT_FALSE(LoopFusion(context.get(), loops[0], loops[1]).AreCompatible());
|
|
}
|
|
|
|
/*
|
|
Generated from the following GLSL + --eliminate-local-multi-store
|
|
|
|
// 14
|
|
#version 440 core
|
|
void main() {
|
|
// Fine
|
|
for (int i = 0; i < 10; i = i + 2) {}
|
|
for (int j = 0; j < 10; j = j + 2) {}
|
|
}
|
|
|
|
*/
|
|
TEST_F(FusionCompatibilityTest, CompatibleNonIncrementStep) {
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %4 "main"
|
|
OpExecutionMode %4 OriginUpperLeft
|
|
OpSource GLSL 440
|
|
OpName %4 "main"
|
|
OpName %8 "j"
|
|
OpName %10 "i"
|
|
OpName %11 "i"
|
|
OpName %24 "j"
|
|
%2 = OpTypeVoid
|
|
%3 = OpTypeFunction %2
|
|
%6 = OpTypeInt 32 1
|
|
%7 = OpTypePointer Function %6
|
|
%9 = OpConstant %6 0
|
|
%18 = OpConstant %6 10
|
|
%19 = OpTypeBool
|
|
%22 = OpConstant %6 2
|
|
%4 = OpFunction %2 None %3
|
|
%5 = OpLabel
|
|
%8 = OpVariable %7 Function
|
|
%10 = OpVariable %7 Function
|
|
%11 = OpVariable %7 Function
|
|
%24 = OpVariable %7 Function
|
|
OpStore %8 %9
|
|
OpStore %10 %9
|
|
OpStore %11 %9
|
|
OpBranch %12
|
|
%12 = OpLabel
|
|
%34 = OpPhi %6 %9 %5 %23 %15
|
|
OpLoopMerge %14 %15 None
|
|
OpBranch %16
|
|
%16 = OpLabel
|
|
%20 = OpSLessThan %19 %34 %18
|
|
OpBranchConditional %20 %13 %14
|
|
%13 = OpLabel
|
|
OpBranch %15
|
|
%15 = OpLabel
|
|
%23 = OpIAdd %6 %34 %22
|
|
OpStore %11 %23
|
|
OpBranch %12
|
|
%14 = OpLabel
|
|
OpStore %24 %9
|
|
OpBranch %25
|
|
%25 = OpLabel
|
|
%35 = OpPhi %6 %9 %14 %33 %28
|
|
OpLoopMerge %27 %28 None
|
|
OpBranch %29
|
|
%29 = OpLabel
|
|
%31 = OpSLessThan %19 %35 %18
|
|
OpBranchConditional %31 %26 %27
|
|
%26 = OpLabel
|
|
OpBranch %28
|
|
%28 = OpLabel
|
|
%33 = OpIAdd %6 %35 %22
|
|
OpStore %24 %33
|
|
OpBranch %25
|
|
%27 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
std::unique_ptr<IRContext> context =
|
|
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
|
|
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
Module* module = context->module();
|
|
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
|
|
<< text << std::endl;
|
|
Function& f = *module->begin();
|
|
LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
|
|
EXPECT_EQ(ld.NumLoops(), 2u);
|
|
|
|
auto loops = ld.GetLoopsInBinaryLayoutOrder();
|
|
|
|
EXPECT_TRUE(LoopFusion(context.get(), loops[0], loops[1]).AreCompatible());
|
|
}
|
|
|
|
/*
|
|
Generated from the following GLSL + --eliminate-local-multi-store
|
|
|
|
// 15
|
|
#version 440 core
|
|
|
|
int j = 0;
|
|
|
|
void main() {
|
|
// Not compatible, unknown init for second.
|
|
for (int i = 0; i < 10; i = i + 2) {}
|
|
for (; j < 10; j = j + 2) {}
|
|
}
|
|
|
|
*/
|
|
TEST_F(FusionCompatibilityTest, UnknonInitForSecondLoop) {
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %4 "main"
|
|
OpExecutionMode %4 OriginUpperLeft
|
|
OpSource GLSL 440
|
|
OpName %4 "main"
|
|
OpName %8 "j"
|
|
OpName %11 "i"
|
|
%2 = OpTypeVoid
|
|
%3 = OpTypeFunction %2
|
|
%6 = OpTypeInt 32 1
|
|
%7 = OpTypePointer Private %6
|
|
%8 = OpVariable %7 Private
|
|
%9 = OpConstant %6 0
|
|
%10 = OpTypePointer Function %6
|
|
%18 = OpConstant %6 10
|
|
%19 = OpTypeBool
|
|
%22 = OpConstant %6 2
|
|
%4 = OpFunction %2 None %3
|
|
%5 = OpLabel
|
|
%11 = OpVariable %10 Function
|
|
OpStore %8 %9
|
|
OpStore %11 %9
|
|
OpBranch %12
|
|
%12 = OpLabel
|
|
%33 = OpPhi %6 %9 %5 %23 %15
|
|
OpLoopMerge %14 %15 None
|
|
OpBranch %16
|
|
%16 = OpLabel
|
|
%20 = OpSLessThan %19 %33 %18
|
|
OpBranchConditional %20 %13 %14
|
|
%13 = OpLabel
|
|
OpBranch %15
|
|
%15 = OpLabel
|
|
%23 = OpIAdd %6 %33 %22
|
|
OpStore %11 %23
|
|
OpBranch %12
|
|
%14 = OpLabel
|
|
OpBranch %24
|
|
%24 = OpLabel
|
|
OpLoopMerge %26 %27 None
|
|
OpBranch %28
|
|
%28 = OpLabel
|
|
%29 = OpLoad %6 %8
|
|
%30 = OpSLessThan %19 %29 %18
|
|
OpBranchConditional %30 %25 %26
|
|
%25 = OpLabel
|
|
OpBranch %27
|
|
%27 = OpLabel
|
|
%31 = OpLoad %6 %8
|
|
%32 = OpIAdd %6 %31 %22
|
|
OpStore %8 %32
|
|
OpBranch %24
|
|
%26 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
std::unique_ptr<IRContext> context =
|
|
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
|
|
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
Module* module = context->module();
|
|
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
|
|
<< text << std::endl;
|
|
Function& f = *module->begin();
|
|
LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
|
|
EXPECT_EQ(ld.NumLoops(), 2u);
|
|
|
|
auto loops = ld.GetLoopsInBinaryLayoutOrder();
|
|
|
|
EXPECT_FALSE(LoopFusion(context.get(), loops[0], loops[1]).AreCompatible());
|
|
}
|
|
|
|
/*
|
|
Generated from the following GLSL + --eliminate-local-multi-store
|
|
|
|
// 16
|
|
#version 440 core
|
|
void main() {
|
|
// Not compatible, continue in loop 0
|
|
for (int i = 0; i < 10; ++i) {
|
|
if (i % 2 == 1) {
|
|
continue;
|
|
}
|
|
}
|
|
for (int j = 0; j < 10; ++j) {}
|
|
}
|
|
|
|
*/
|
|
TEST_F(FusionCompatibilityTest, Continue) {
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %4 "main"
|
|
OpExecutionMode %4 OriginUpperLeft
|
|
OpSource GLSL 440
|
|
OpName %4 "main"
|
|
OpName %8 "i"
|
|
OpName %29 "j"
|
|
%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 2
|
|
%22 = OpConstant %6 1
|
|
%4 = OpFunction %2 None %3
|
|
%5 = OpLabel
|
|
%8 = OpVariable %7 Function
|
|
%29 = OpVariable %7 Function
|
|
OpStore %8 %9
|
|
OpBranch %10
|
|
%10 = OpLabel
|
|
%39 = OpPhi %6 %9 %5 %28 %13
|
|
OpLoopMerge %12 %13 None
|
|
OpBranch %14
|
|
%14 = OpLabel
|
|
%18 = OpSLessThan %17 %39 %16
|
|
OpBranchConditional %18 %11 %12
|
|
%11 = OpLabel
|
|
%21 = OpSMod %6 %39 %20
|
|
%23 = OpIEqual %17 %21 %22
|
|
OpSelectionMerge %25 None
|
|
OpBranchConditional %23 %24 %25
|
|
%24 = OpLabel
|
|
OpBranch %13
|
|
%25 = OpLabel
|
|
OpBranch %13
|
|
%13 = OpLabel
|
|
%28 = OpIAdd %6 %39 %22
|
|
OpStore %8 %28
|
|
OpBranch %10
|
|
%12 = OpLabel
|
|
OpStore %29 %9
|
|
OpBranch %30
|
|
%30 = OpLabel
|
|
%40 = OpPhi %6 %9 %12 %38 %33
|
|
OpLoopMerge %32 %33 None
|
|
OpBranch %34
|
|
%34 = OpLabel
|
|
%36 = OpSLessThan %17 %40 %16
|
|
OpBranchConditional %36 %31 %32
|
|
%31 = OpLabel
|
|
OpBranch %33
|
|
%33 = OpLabel
|
|
%38 = OpIAdd %6 %40 %22
|
|
OpStore %29 %38
|
|
OpBranch %30
|
|
%32 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
std::unique_ptr<IRContext> context =
|
|
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
|
|
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
Module* module = context->module();
|
|
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
|
|
<< text << std::endl;
|
|
Function& f = *module->begin();
|
|
LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
|
|
EXPECT_EQ(ld.NumLoops(), 2u);
|
|
|
|
auto loops = ld.GetLoopsInBinaryLayoutOrder();
|
|
|
|
EXPECT_FALSE(LoopFusion(context.get(), loops[0], loops[1]).AreCompatible());
|
|
}
|
|
|
|
/*
|
|
Generated from the following GLSL + --eliminate-local-multi-store
|
|
|
|
#version 440 core
|
|
void main() {
|
|
int[10] a;
|
|
// Compatible
|
|
for (int i = 0; i < 10; ++i) {
|
|
if (i % 2 == 1) {
|
|
} else {
|
|
a[i] = i;
|
|
}
|
|
}
|
|
for (int j = 0; j < 10; ++j) {}
|
|
}
|
|
|
|
*/
|
|
TEST_F(FusionCompatibilityTest, IfElseInLoop) {
|
|
const std::string text = R"(
|
|
OpCapability Shader
|
|
%1 = OpExtInstImport "GLSL.std.450"
|
|
OpMemoryModel Logical GLSL450
|
|
OpEntryPoint Fragment %4 "main"
|
|
OpExecutionMode %4 OriginUpperLeft
|
|
OpSource GLSL 440
|
|
OpName %4 "main"
|
|
OpName %8 "i"
|
|
OpName %31 "a"
|
|
OpName %37 "j"
|
|
%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 2
|
|
%22 = OpConstant %6 1
|
|
%27 = OpTypeInt 32 0
|
|
%28 = OpConstant %27 10
|
|
%29 = OpTypeArray %6 %28
|
|
%30 = OpTypePointer Function %29
|
|
%4 = OpFunction %2 None %3
|
|
%5 = OpLabel
|
|
%8 = OpVariable %7 Function
|
|
%31 = OpVariable %30 Function
|
|
%37 = OpVariable %7 Function
|
|
OpStore %8 %9
|
|
OpBranch %10
|
|
%10 = OpLabel
|
|
%47 = OpPhi %6 %9 %5 %36 %13
|
|
OpLoopMerge %12 %13 None
|
|
OpBranch %14
|
|
%14 = OpLabel
|
|
%18 = OpSLessThan %17 %47 %16
|
|
OpBranchConditional %18 %11 %12
|
|
%11 = OpLabel
|
|
%21 = OpSMod %6 %47 %20
|
|
%23 = OpIEqual %17 %21 %22
|
|
OpSelectionMerge %25 None
|
|
OpBranchConditional %23 %24 %26
|
|
%24 = OpLabel
|
|
OpBranch %25
|
|
%26 = OpLabel
|
|
%34 = OpAccessChain %7 %31 %47
|
|
OpStore %34 %47
|
|
OpBranch %25
|
|
%25 = OpLabel
|
|
OpBranch %13
|
|
%13 = OpLabel
|
|
%36 = OpIAdd %6 %47 %22
|
|
OpStore %8 %36
|
|
OpBranch %10
|
|
%12 = OpLabel
|
|
OpStore %37 %9
|
|
OpBranch %38
|
|
%38 = OpLabel
|
|
%48 = OpPhi %6 %9 %12 %46 %41
|
|
OpLoopMerge %40 %41 None
|
|
OpBranch %42
|
|
%42 = OpLabel
|
|
%44 = OpSLessThan %17 %48 %16
|
|
OpBranchConditional %44 %39 %40
|
|
%39 = OpLabel
|
|
OpBranch %41
|
|
%41 = OpLabel
|
|
%46 = OpIAdd %6 %48 %22
|
|
OpStore %37 %46
|
|
OpBranch %38
|
|
%40 = OpLabel
|
|
OpReturn
|
|
OpFunctionEnd
|
|
)";
|
|
|
|
std::unique_ptr<IRContext> context =
|
|
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
|
|
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
|
Module* module = context->module();
|
|
EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
|
|
<< text << std::endl;
|
|
Function& f = *module->begin();
|
|
LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
|
|
EXPECT_EQ(ld.NumLoops(), 2u);
|
|
|
|
auto loops = ld.GetLoopsInBinaryLayoutOrder();
|
|
|
|
EXPECT_TRUE(LoopFusion(context.get(), loops[0], loops[1]).AreCompatible());
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace opt
|
|
} // namespace spvtools
|