spirv-tools: vendor as full-fork recipe (path=source, patches baked)
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
# Copyright (c) 2017 Google Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
|
||||
add_spvtools_unittest(TARGET opt_loops
|
||||
SRCS ../function_utils.h
|
||||
dependence_analysis.cpp
|
||||
dependence_analysis_helpers.cpp
|
||||
fusion_compatibility.cpp
|
||||
fusion_illegal.cpp
|
||||
fusion_legal.cpp
|
||||
fusion_pass.cpp
|
||||
hoist_access_chains.cpp
|
||||
hoist_all_loop_types.cpp
|
||||
hoist_double_nested_loops.cpp
|
||||
hoist_from_independent_loops.cpp
|
||||
hoist_simple_case.cpp
|
||||
hoist_single_nested_loops.cpp
|
||||
hoist_without_preheader.cpp
|
||||
lcssa.cpp
|
||||
loop_descriptions.cpp
|
||||
loop_fission.cpp
|
||||
nested_loops.cpp
|
||||
peeling.cpp
|
||||
peeling_pass.cpp
|
||||
unroll_assumptions.cpp
|
||||
unroll_simple.cpp
|
||||
unswitch.cpp
|
||||
LIBS SPIRV-Tools-opt
|
||||
PCH_FILE pch_test_opt_loop
|
||||
)
|
||||
+4199
File diff suppressed because it is too large
Load Diff
+3011
File diff suppressed because it is too large
Load Diff
+1782
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,717 @@
|
||||
// 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 <string>
|
||||
|
||||
#include "effcee/effcee.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "test/opt/pass_fixture.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
namespace {
|
||||
|
||||
using FusionPassTest = PassTest<::testing::Test>;
|
||||
|
||||
/*
|
||||
Generated from the following GLSL + --eliminate-local-multi-store
|
||||
|
||||
#version 440 core
|
||||
void main() {
|
||||
int[10] a;
|
||||
int[10] b;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
a[i] = a[i]*2;
|
||||
}
|
||||
for (int i = 0; i < 10; i++) {
|
||||
b[i] = a[i]+2;
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
TEST_F(FusionPassTest, SimpleFusion) {
|
||||
const std::string text = R"(
|
||||
; CHECK: OpPhi
|
||||
; CHECK: OpLoad
|
||||
; CHECK: OpStore
|
||||
; CHECK-NOT: OpPhi
|
||||
; CHECK: OpLoad
|
||||
; CHECK: OpStore
|
||||
|
||||
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 %23 "a"
|
||||
OpName %34 "i"
|
||||
OpName %42 "b"
|
||||
%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
|
||||
%28 = OpConstant %6 2
|
||||
%32 = OpConstant %6 1
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%23 = OpVariable %22 Function
|
||||
%34 = OpVariable %7 Function
|
||||
%42 = OpVariable %22 Function
|
||||
OpStore %8 %9
|
||||
OpBranch %10
|
||||
%10 = OpLabel
|
||||
%51 = OpPhi %6 %9 %5 %33 %13
|
||||
OpLoopMerge %12 %13 None
|
||||
OpBranch %14
|
||||
%14 = OpLabel
|
||||
%18 = OpSLessThan %17 %51 %16
|
||||
OpBranchConditional %18 %11 %12
|
||||
%11 = OpLabel
|
||||
%26 = OpAccessChain %7 %23 %51
|
||||
%27 = OpLoad %6 %26
|
||||
%29 = OpIMul %6 %27 %28
|
||||
%30 = OpAccessChain %7 %23 %51
|
||||
OpStore %30 %29
|
||||
OpBranch %13
|
||||
%13 = OpLabel
|
||||
%33 = OpIAdd %6 %51 %32
|
||||
OpStore %8 %33
|
||||
OpBranch %10
|
||||
%12 = OpLabel
|
||||
OpStore %34 %9
|
||||
OpBranch %35
|
||||
%35 = OpLabel
|
||||
%52 = OpPhi %6 %9 %12 %50 %38
|
||||
OpLoopMerge %37 %38 None
|
||||
OpBranch %39
|
||||
%39 = OpLabel
|
||||
%41 = OpSLessThan %17 %52 %16
|
||||
OpBranchConditional %41 %36 %37
|
||||
%36 = OpLabel
|
||||
%45 = OpAccessChain %7 %23 %52
|
||||
%46 = OpLoad %6 %45
|
||||
%47 = OpIAdd %6 %46 %28
|
||||
%48 = OpAccessChain %7 %42 %52
|
||||
OpStore %48 %47
|
||||
OpBranch %38
|
||||
%38 = OpLabel
|
||||
%50 = OpIAdd %6 %52 %32
|
||||
OpStore %34 %50
|
||||
OpBranch %35
|
||||
%37 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<LoopFusionPass>(text, true, 20);
|
||||
}
|
||||
|
||||
/*
|
||||
Generated from the following GLSL + --eliminate-local-multi-store
|
||||
|
||||
#version 440 core
|
||||
void main() {
|
||||
int[10] a;
|
||||
int[10] b;
|
||||
int[10] c;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
a[i] = b[i] + 1;
|
||||
}
|
||||
for (int i = 0; i < 10; i++) {
|
||||
c[i] = a[i] + 2;
|
||||
}
|
||||
for (int i = 0; i < 10; i++) {
|
||||
b[i] = c[i] + 10;
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
TEST_F(FusionPassTest, ThreeLoopsFused) {
|
||||
const std::string text = R"(
|
||||
; CHECK: OpPhi
|
||||
; CHECK: OpLoad
|
||||
; CHECK: OpStore
|
||||
; CHECK-NOT: OpPhi
|
||||
; CHECK: OpLoad
|
||||
; CHECK: OpStore
|
||||
; CHECK-NOT: OpPhi
|
||||
; CHECK: OpLoad
|
||||
; CHECK: OpStore
|
||||
|
||||
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 %23 "a"
|
||||
OpName %25 "b"
|
||||
OpName %34 "i"
|
||||
OpName %42 "c"
|
||||
OpName %52 "i"
|
||||
%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
|
||||
%29 = OpConstant %6 1
|
||||
%47 = OpConstant %6 2
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%23 = OpVariable %22 Function
|
||||
%25 = OpVariable %22 Function
|
||||
%34 = OpVariable %7 Function
|
||||
%42 = OpVariable %22 Function
|
||||
%52 = OpVariable %7 Function
|
||||
OpStore %8 %9
|
||||
OpBranch %10
|
||||
%10 = OpLabel
|
||||
%68 = OpPhi %6 %9 %5 %33 %13
|
||||
OpLoopMerge %12 %13 None
|
||||
OpBranch %14
|
||||
%14 = OpLabel
|
||||
%18 = OpSLessThan %17 %68 %16
|
||||
OpBranchConditional %18 %11 %12
|
||||
%11 = OpLabel
|
||||
%27 = OpAccessChain %7 %25 %68
|
||||
%28 = OpLoad %6 %27
|
||||
%30 = OpIAdd %6 %28 %29
|
||||
%31 = OpAccessChain %7 %23 %68
|
||||
OpStore %31 %30
|
||||
OpBranch %13
|
||||
%13 = OpLabel
|
||||
%33 = OpIAdd %6 %68 %29
|
||||
OpStore %8 %33
|
||||
OpBranch %10
|
||||
%12 = OpLabel
|
||||
OpStore %34 %9
|
||||
OpBranch %35
|
||||
%35 = OpLabel
|
||||
%69 = OpPhi %6 %9 %12 %51 %38
|
||||
OpLoopMerge %37 %38 None
|
||||
OpBranch %39
|
||||
%39 = OpLabel
|
||||
%41 = OpSLessThan %17 %69 %16
|
||||
OpBranchConditional %41 %36 %37
|
||||
%36 = OpLabel
|
||||
%45 = OpAccessChain %7 %23 %69
|
||||
%46 = OpLoad %6 %45
|
||||
%48 = OpIAdd %6 %46 %47
|
||||
%49 = OpAccessChain %7 %42 %69
|
||||
OpStore %49 %48
|
||||
OpBranch %38
|
||||
%38 = OpLabel
|
||||
%51 = OpIAdd %6 %69 %29
|
||||
OpStore %34 %51
|
||||
OpBranch %35
|
||||
%37 = OpLabel
|
||||
OpStore %52 %9
|
||||
OpBranch %53
|
||||
%53 = OpLabel
|
||||
%70 = OpPhi %6 %9 %37 %67 %56
|
||||
OpLoopMerge %55 %56 None
|
||||
OpBranch %57
|
||||
%57 = OpLabel
|
||||
%59 = OpSLessThan %17 %70 %16
|
||||
OpBranchConditional %59 %54 %55
|
||||
%54 = OpLabel
|
||||
%62 = OpAccessChain %7 %42 %70
|
||||
%63 = OpLoad %6 %62
|
||||
%64 = OpIAdd %6 %63 %16
|
||||
%65 = OpAccessChain %7 %25 %70
|
||||
OpStore %65 %64
|
||||
OpBranch %56
|
||||
%56 = OpLabel
|
||||
%67 = OpIAdd %6 %70 %29
|
||||
OpStore %52 %67
|
||||
OpBranch %53
|
||||
%55 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<LoopFusionPass>(text, true, 20);
|
||||
}
|
||||
|
||||
/*
|
||||
Generated from the following GLSL + --eliminate-local-multi-store
|
||||
|
||||
#version 440 core
|
||||
void main() {
|
||||
int[10][10] a;
|
||||
int[10][10] b;
|
||||
int[10][10] c;
|
||||
// Legal both
|
||||
for (int i = 0; i < 10; i++) {
|
||||
for (int j = 0; j < 10; j++) {
|
||||
c[i][j] = a[i][j] + 2;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 10; i++) {
|
||||
for (int j = 0; j < 10; j++) {
|
||||
b[i][j] = c[i][j] + 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
TEST_F(FusionPassTest, NestedLoopsFused) {
|
||||
const std::string text = R"(
|
||||
; CHECK: OpPhi
|
||||
; CHECK: OpPhi
|
||||
; CHECK: OpLoad
|
||||
; CHECK: OpStore
|
||||
; CHECK-NOT: OpPhi
|
||||
; CHECK: OpLoad
|
||||
; CHECK: OpStore
|
||||
|
||||
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 %19 "j"
|
||||
OpName %32 "c"
|
||||
OpName %35 "a"
|
||||
OpName %48 "i"
|
||||
OpName %56 "j"
|
||||
OpName %64 "b"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 0
|
||||
%16 = OpConstant %6 10
|
||||
%17 = OpTypeBool
|
||||
%27 = OpTypeInt 32 0
|
||||
%28 = OpConstant %27 10
|
||||
%29 = OpTypeArray %6 %28
|
||||
%30 = OpTypeArray %29 %28
|
||||
%31 = OpTypePointer Function %30
|
||||
%40 = OpConstant %6 2
|
||||
%44 = OpConstant %6 1
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%19 = OpVariable %7 Function
|
||||
%32 = OpVariable %31 Function
|
||||
%35 = OpVariable %31 Function
|
||||
%48 = OpVariable %7 Function
|
||||
%56 = OpVariable %7 Function
|
||||
%64 = OpVariable %31 Function
|
||||
OpStore %8 %9
|
||||
OpBranch %10
|
||||
%10 = OpLabel
|
||||
%77 = OpPhi %6 %9 %5 %47 %13
|
||||
OpLoopMerge %12 %13 None
|
||||
OpBranch %14
|
||||
%14 = OpLabel
|
||||
%18 = OpSLessThan %17 %77 %16
|
||||
OpBranchConditional %18 %11 %12
|
||||
%11 = OpLabel
|
||||
OpStore %19 %9
|
||||
OpBranch %20
|
||||
%20 = OpLabel
|
||||
%81 = OpPhi %6 %9 %11 %45 %23
|
||||
OpLoopMerge %22 %23 None
|
||||
OpBranch %24
|
||||
%24 = OpLabel
|
||||
%26 = OpSLessThan %17 %81 %16
|
||||
OpBranchConditional %26 %21 %22
|
||||
%21 = OpLabel
|
||||
%38 = OpAccessChain %7 %35 %77 %81
|
||||
%39 = OpLoad %6 %38
|
||||
%41 = OpIAdd %6 %39 %40
|
||||
%42 = OpAccessChain %7 %32 %77 %81
|
||||
OpStore %42 %41
|
||||
OpBranch %23
|
||||
%23 = OpLabel
|
||||
%45 = OpIAdd %6 %81 %44
|
||||
OpStore %19 %45
|
||||
OpBranch %20
|
||||
%22 = OpLabel
|
||||
OpBranch %13
|
||||
%13 = OpLabel
|
||||
%47 = OpIAdd %6 %77 %44
|
||||
OpStore %8 %47
|
||||
OpBranch %10
|
||||
%12 = OpLabel
|
||||
OpStore %48 %9
|
||||
OpBranch %49
|
||||
%49 = OpLabel
|
||||
%78 = OpPhi %6 %9 %12 %76 %52
|
||||
OpLoopMerge %51 %52 None
|
||||
OpBranch %53
|
||||
%53 = OpLabel
|
||||
%55 = OpSLessThan %17 %78 %16
|
||||
OpBranchConditional %55 %50 %51
|
||||
%50 = OpLabel
|
||||
OpStore %56 %9
|
||||
OpBranch %57
|
||||
%57 = OpLabel
|
||||
%79 = OpPhi %6 %9 %50 %74 %60
|
||||
OpLoopMerge %59 %60 None
|
||||
OpBranch %61
|
||||
%61 = OpLabel
|
||||
%63 = OpSLessThan %17 %79 %16
|
||||
OpBranchConditional %63 %58 %59
|
||||
%58 = OpLabel
|
||||
%69 = OpAccessChain %7 %32 %78 %79
|
||||
%70 = OpLoad %6 %69
|
||||
%71 = OpIAdd %6 %70 %16
|
||||
%72 = OpAccessChain %7 %64 %78 %79
|
||||
OpStore %72 %71
|
||||
OpBranch %60
|
||||
%60 = OpLabel
|
||||
%74 = OpIAdd %6 %79 %44
|
||||
OpStore %56 %74
|
||||
OpBranch %57
|
||||
%59 = OpLabel
|
||||
OpBranch %52
|
||||
%52 = OpLabel
|
||||
%76 = OpIAdd %6 %78 %44
|
||||
OpStore %48 %76
|
||||
OpBranch %49
|
||||
%51 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<LoopFusionPass>(text, true, 20);
|
||||
}
|
||||
|
||||
/*
|
||||
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(FusionPassTest, Incompatible) {
|
||||
const std::string text = R"(
|
||||
; CHECK: OpPhi
|
||||
; CHECK-NEXT: OpLoopMerge
|
||||
; CHECK: OpPhi
|
||||
; CHECK-NEXT: OpLoopMerge
|
||||
|
||||
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
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<LoopFusionPass>(text, true, 20);
|
||||
}
|
||||
|
||||
/*
|
||||
Generated from the following GLSL + --eliminate-local-multi-store
|
||||
|
||||
#version 440 core
|
||||
void main() {
|
||||
int[10] a;
|
||||
int[10] b;
|
||||
int[10] c;
|
||||
// Illegal, loop-independent dependence will become a
|
||||
// backward loop-carried antidependence
|
||||
for (int i = 0; i < 10; i++) {
|
||||
a[i] = b[i] + 1;
|
||||
}
|
||||
for (int i = 0; i < 10; i++) {
|
||||
c[i] = a[i+1] + 2;
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
TEST_F(FusionPassTest, Illegal) {
|
||||
std::string text = R"(
|
||||
; CHECK: OpPhi
|
||||
; CHECK-NEXT: OpLoopMerge
|
||||
; CHECK: OpLoad
|
||||
; CHECK: OpStore
|
||||
; CHECK: OpPhi
|
||||
; CHECK-NEXT: OpLoopMerge
|
||||
; CHECK: OpLoad
|
||||
; CHECK: OpStore
|
||||
|
||||
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 %23 "a"
|
||||
OpName %25 "b"
|
||||
OpName %34 "i"
|
||||
OpName %42 "c"
|
||||
%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
|
||||
%29 = 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
|
||||
%34 = OpVariable %7 Function
|
||||
%42 = OpVariable %22 Function
|
||||
OpStore %8 %9
|
||||
OpBranch %10
|
||||
%10 = OpLabel
|
||||
%53 = OpPhi %6 %9 %5 %33 %13
|
||||
OpLoopMerge %12 %13 None
|
||||
OpBranch %14
|
||||
%14 = OpLabel
|
||||
%18 = OpSLessThan %17 %53 %16
|
||||
OpBranchConditional %18 %11 %12
|
||||
%11 = OpLabel
|
||||
%27 = OpAccessChain %7 %25 %53
|
||||
%28 = OpLoad %6 %27
|
||||
%30 = OpIAdd %6 %28 %29
|
||||
%31 = OpAccessChain %7 %23 %53
|
||||
OpStore %31 %30
|
||||
OpBranch %13
|
||||
%13 = OpLabel
|
||||
%33 = OpIAdd %6 %53 %29
|
||||
OpStore %8 %33
|
||||
OpBranch %10
|
||||
%12 = OpLabel
|
||||
OpStore %34 %9
|
||||
OpBranch %35
|
||||
%35 = OpLabel
|
||||
%54 = OpPhi %6 %9 %12 %52 %38
|
||||
OpLoopMerge %37 %38 None
|
||||
OpBranch %39
|
||||
%39 = OpLabel
|
||||
%41 = OpSLessThan %17 %54 %16
|
||||
OpBranchConditional %41 %36 %37
|
||||
%36 = OpLabel
|
||||
%45 = OpIAdd %6 %54 %29
|
||||
%46 = OpAccessChain %7 %23 %45
|
||||
%47 = OpLoad %6 %46
|
||||
%49 = OpIAdd %6 %47 %48
|
||||
%50 = OpAccessChain %7 %42 %54
|
||||
OpStore %50 %49
|
||||
OpBranch %38
|
||||
%38 = OpLabel
|
||||
%52 = OpIAdd %6 %54 %29
|
||||
OpStore %34 %52
|
||||
OpBranch %35
|
||||
%37 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<LoopFusionPass>(text, true, 20);
|
||||
}
|
||||
|
||||
/*
|
||||
Generated from the following GLSL + --eliminate-local-multi-store
|
||||
|
||||
#version 440 core
|
||||
void main() {
|
||||
int[10] a;
|
||||
int[10] b;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
a[i] = a[i]*2;
|
||||
}
|
||||
for (int i = 0; i < 10; i++) {
|
||||
b[i] = a[i]+2;
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
TEST_F(FusionPassTest, TooManyRegisters) {
|
||||
const std::string text = R"(
|
||||
; CHECK: OpPhi
|
||||
; CHECK-NEXT: OpLoopMerge
|
||||
; CHECK: OpLoad
|
||||
; CHECK: OpStore
|
||||
; CHECK: OpPhi
|
||||
; CHECK-NEXT: OpLoopMerge
|
||||
; CHECK: OpLoad
|
||||
; CHECK: OpStore
|
||||
|
||||
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 %23 "a"
|
||||
OpName %34 "i"
|
||||
OpName %42 "b"
|
||||
%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
|
||||
%28 = OpConstant %6 2
|
||||
%32 = OpConstant %6 1
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%23 = OpVariable %22 Function
|
||||
%34 = OpVariable %7 Function
|
||||
%42 = OpVariable %22 Function
|
||||
OpStore %8 %9
|
||||
OpBranch %10
|
||||
%10 = OpLabel
|
||||
%51 = OpPhi %6 %9 %5 %33 %13
|
||||
OpLoopMerge %12 %13 None
|
||||
OpBranch %14
|
||||
%14 = OpLabel
|
||||
%18 = OpSLessThan %17 %51 %16
|
||||
OpBranchConditional %18 %11 %12
|
||||
%11 = OpLabel
|
||||
%26 = OpAccessChain %7 %23 %51
|
||||
%27 = OpLoad %6 %26
|
||||
%29 = OpIMul %6 %27 %28
|
||||
%30 = OpAccessChain %7 %23 %51
|
||||
OpStore %30 %29
|
||||
OpBranch %13
|
||||
%13 = OpLabel
|
||||
%33 = OpIAdd %6 %51 %32
|
||||
OpStore %8 %33
|
||||
OpBranch %10
|
||||
%12 = OpLabel
|
||||
OpStore %34 %9
|
||||
OpBranch %35
|
||||
%35 = OpLabel
|
||||
%52 = OpPhi %6 %9 %12 %50 %38
|
||||
OpLoopMerge %37 %38 None
|
||||
OpBranch %39
|
||||
%39 = OpLabel
|
||||
%41 = OpSLessThan %17 %52 %16
|
||||
OpBranchConditional %41 %36 %37
|
||||
%36 = OpLabel
|
||||
%45 = OpAccessChain %7 %23 %52
|
||||
%46 = OpLoad %6 %45
|
||||
%47 = OpIAdd %6 %46 %28
|
||||
%48 = OpAccessChain %7 %42 %52
|
||||
OpStore %48 %47
|
||||
OpBranch %38
|
||||
%38 = OpLabel
|
||||
%50 = OpIAdd %6 %52 %32
|
||||
OpStore %34 %50
|
||||
OpBranch %35
|
||||
%37 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<LoopFusionPass>(text, true, 5);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
||||
+157
@@ -0,0 +1,157 @@
|
||||
// Copyright (c) 2023 The Khronos Group Inc.
|
||||
//
|
||||
// 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 <string>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "source/opt/licm_pass.h"
|
||||
#include "test/opt/pass_fixture.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
namespace {
|
||||
|
||||
using PassClassTest = PassTest<::testing::Test>;
|
||||
|
||||
/*
|
||||
Tests for the LICM pass to check it handles access chains correctly
|
||||
|
||||
Generated from the following GLSL fragment shader
|
||||
--eliminate-local-multi-store has also been run on the spv binary
|
||||
#version 460
|
||||
void main() {
|
||||
for (uint i = 0; i < 123u; ++i) {
|
||||
vec2 do_not_hoist_store = vec2(0.0f);
|
||||
float do_not_hoist_access_chain_load = do_not_hoist_store.x;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
TEST_F(PassClassTest, HoistAccessChains) {
|
||||
const std::string before_hoist = R"(OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource GLSL 460
|
||||
OpName %main "main"
|
||||
OpName %i "i"
|
||||
OpName %do_not_hoist_store "do_not_hoist_store"
|
||||
OpName %do_not_hoist_access_chain_load "do_not_hoist_access_chain_load"
|
||||
%void = OpTypeVoid
|
||||
%7 = OpTypeFunction %void
|
||||
%uint = OpTypeInt 32 0
|
||||
%_ptr_Function_uint = OpTypePointer Function %uint
|
||||
%uint_0 = OpConstant %uint 0
|
||||
%uint_123 = OpConstant %uint 123
|
||||
%bool = OpTypeBool
|
||||
%float = OpTypeFloat 32
|
||||
%v2float = OpTypeVector %float 2
|
||||
%_ptr_Function_v2float = OpTypePointer Function %v2float
|
||||
%float_0 = OpConstant %float 0
|
||||
%17 = OpConstantComposite %v2float %float_0 %float_0
|
||||
%_ptr_Function_float = OpTypePointer Function %float
|
||||
%int = OpTypeInt 32 1
|
||||
%int_1 = OpConstant %int 1
|
||||
%main = OpFunction %void None %7
|
||||
%21 = OpLabel
|
||||
%i = OpVariable %_ptr_Function_uint Function
|
||||
%do_not_hoist_store = OpVariable %_ptr_Function_v2float Function
|
||||
%do_not_hoist_access_chain_load = OpVariable %_ptr_Function_float Function
|
||||
OpStore %i %uint_0
|
||||
OpBranch %22
|
||||
%22 = OpLabel
|
||||
OpLoopMerge %23 %24 None
|
||||
OpBranch %25
|
||||
%25 = OpLabel
|
||||
%26 = OpLoad %uint %i
|
||||
%27 = OpULessThan %bool %26 %uint_123
|
||||
OpBranchConditional %27 %28 %23
|
||||
%28 = OpLabel
|
||||
OpStore %do_not_hoist_store %17
|
||||
%29 = OpAccessChain %_ptr_Function_float %do_not_hoist_store %uint_0
|
||||
%30 = OpLoad %float %29
|
||||
OpStore %do_not_hoist_access_chain_load %30
|
||||
OpBranch %24
|
||||
%24 = OpLabel
|
||||
%31 = OpLoad %uint %i
|
||||
%32 = OpIAdd %uint %31 %int_1
|
||||
OpStore %i %32
|
||||
OpBranch %22
|
||||
%23 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const std::string after_hoist = R"(OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource GLSL 460
|
||||
OpName %main "main"
|
||||
OpName %i "i"
|
||||
OpName %do_not_hoist_store "do_not_hoist_store"
|
||||
OpName %do_not_hoist_access_chain_load "do_not_hoist_access_chain_load"
|
||||
%void = OpTypeVoid
|
||||
%7 = OpTypeFunction %void
|
||||
%uint = OpTypeInt 32 0
|
||||
%_ptr_Function_uint = OpTypePointer Function %uint
|
||||
%uint_0 = OpConstant %uint 0
|
||||
%uint_123 = OpConstant %uint 123
|
||||
%bool = OpTypeBool
|
||||
%float = OpTypeFloat 32
|
||||
%v2float = OpTypeVector %float 2
|
||||
%_ptr_Function_v2float = OpTypePointer Function %v2float
|
||||
%float_0 = OpConstant %float 0
|
||||
%17 = OpConstantComposite %v2float %float_0 %float_0
|
||||
%_ptr_Function_float = OpTypePointer Function %float
|
||||
%int = OpTypeInt 32 1
|
||||
%int_1 = OpConstant %int 1
|
||||
%main = OpFunction %void None %7
|
||||
%21 = OpLabel
|
||||
%i = OpVariable %_ptr_Function_uint Function
|
||||
%do_not_hoist_store = OpVariable %_ptr_Function_v2float Function
|
||||
%do_not_hoist_access_chain_load = OpVariable %_ptr_Function_float Function
|
||||
OpStore %i %uint_0
|
||||
%29 = OpAccessChain %_ptr_Function_float %do_not_hoist_store %uint_0
|
||||
OpBranch %22
|
||||
%22 = OpLabel
|
||||
OpLoopMerge %23 %24 None
|
||||
OpBranch %25
|
||||
%25 = OpLabel
|
||||
%26 = OpLoad %uint %i
|
||||
%27 = OpULessThan %bool %26 %uint_123
|
||||
OpBranchConditional %27 %28 %23
|
||||
%28 = OpLabel
|
||||
OpStore %do_not_hoist_store %17
|
||||
%30 = OpLoad %float %29
|
||||
OpStore %do_not_hoist_access_chain_load %30
|
||||
OpBranch %24
|
||||
%24 = OpLabel
|
||||
%31 = OpLoad %uint %i
|
||||
%32 = OpIAdd %uint %31 %int_1
|
||||
OpStore %i %32
|
||||
OpBranch %22
|
||||
%23 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndCheck<LICMPass>(before_hoist, after_hoist, true);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
||||
+285
@@ -0,0 +1,285 @@
|
||||
// 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 <string>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "source/opt/licm_pass.h"
|
||||
#include "test/opt/pass_fixture.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
namespace {
|
||||
|
||||
using ::testing::UnorderedElementsAre;
|
||||
using PassClassTest = PassTest<::testing::Test>;
|
||||
|
||||
/*
|
||||
Tests that all loop types are handled appropriately by the LICM pass.
|
||||
|
||||
Generated from the following GLSL fragment shader
|
||||
--eliminate-local-multi-store has also been run on the spv binary
|
||||
#version 440 core
|
||||
void main(){
|
||||
int i_1 = 0;
|
||||
for (i_1 = 0; i_1 < 10; i_1++) {
|
||||
}
|
||||
int i_2 = 0;
|
||||
while (i_2 < 10) {
|
||||
i_2++;
|
||||
}
|
||||
int i_3 = 0;
|
||||
do {
|
||||
i_3++;
|
||||
} while (i_3 < 10);
|
||||
int hoist = 0;
|
||||
int i_4 = 0;
|
||||
int i_5 = 0;
|
||||
int i_6 = 0;
|
||||
for (i_4 = 0; i_4 < 10; i_4++) {
|
||||
while (i_5 < 10) {
|
||||
do {
|
||||
hoist = i_1 + i_2 + i_3;
|
||||
i_6++;
|
||||
} while (i_6 < 10);
|
||||
i_5++;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
TEST_F(PassClassTest, AllLoopTypes) {
|
||||
const std::string before_hoist = R"(OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource GLSL 440
|
||||
OpName %main "main"
|
||||
%void = OpTypeVoid
|
||||
%4 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Function_int = OpTypePointer Function %int
|
||||
%int_0 = OpConstant %int 0
|
||||
%int_10 = OpConstant %int 10
|
||||
%bool = OpTypeBool
|
||||
%int_1 = OpConstant %int 1
|
||||
%main = OpFunction %void None %4
|
||||
%11 = OpLabel
|
||||
OpBranch %12
|
||||
%12 = OpLabel
|
||||
%13 = OpPhi %int %int_0 %11 %14 %15
|
||||
OpLoopMerge %16 %15 None
|
||||
OpBranch %17
|
||||
%17 = OpLabel
|
||||
%18 = OpSLessThan %bool %13 %int_10
|
||||
OpBranchConditional %18 %19 %16
|
||||
%19 = OpLabel
|
||||
OpBranch %15
|
||||
%15 = OpLabel
|
||||
%14 = OpIAdd %int %13 %int_1
|
||||
OpBranch %12
|
||||
%16 = OpLabel
|
||||
OpBranch %20
|
||||
%20 = OpLabel
|
||||
%21 = OpPhi %int %int_0 %16 %22 %23
|
||||
OpLoopMerge %24 %23 None
|
||||
OpBranch %25
|
||||
%25 = OpLabel
|
||||
%26 = OpSLessThan %bool %21 %int_10
|
||||
OpBranchConditional %26 %27 %24
|
||||
%27 = OpLabel
|
||||
%22 = OpIAdd %int %21 %int_1
|
||||
OpBranch %23
|
||||
%23 = OpLabel
|
||||
OpBranch %20
|
||||
%24 = OpLabel
|
||||
OpBranch %28
|
||||
%28 = OpLabel
|
||||
%29 = OpPhi %int %int_0 %24 %30 %31
|
||||
OpLoopMerge %32 %31 None
|
||||
OpBranch %33
|
||||
%33 = OpLabel
|
||||
%30 = OpIAdd %int %29 %int_1
|
||||
OpBranch %31
|
||||
%31 = OpLabel
|
||||
%34 = OpSLessThan %bool %30 %int_10
|
||||
OpBranchConditional %34 %28 %32
|
||||
%32 = OpLabel
|
||||
OpBranch %35
|
||||
%35 = OpLabel
|
||||
%36 = OpPhi %int %int_0 %32 %37 %38
|
||||
%39 = OpPhi %int %int_0 %32 %40 %38
|
||||
%41 = OpPhi %int %int_0 %32 %42 %38
|
||||
%43 = OpPhi %int %int_0 %32 %44 %38
|
||||
OpLoopMerge %45 %38 None
|
||||
OpBranch %46
|
||||
%46 = OpLabel
|
||||
%47 = OpSLessThan %bool %39 %int_10
|
||||
OpBranchConditional %47 %48 %45
|
||||
%48 = OpLabel
|
||||
OpBranch %49
|
||||
%49 = OpLabel
|
||||
%37 = OpPhi %int %36 %48 %50 %51
|
||||
%42 = OpPhi %int %41 %48 %52 %51
|
||||
%44 = OpPhi %int %43 %48 %53 %51
|
||||
OpLoopMerge %54 %51 None
|
||||
OpBranch %55
|
||||
%55 = OpLabel
|
||||
%56 = OpSLessThan %bool %42 %int_10
|
||||
OpBranchConditional %56 %57 %54
|
||||
%57 = OpLabel
|
||||
OpBranch %58
|
||||
%58 = OpLabel
|
||||
%59 = OpPhi %int %37 %57 %50 %60
|
||||
%61 = OpPhi %int %44 %57 %53 %60
|
||||
OpLoopMerge %62 %60 None
|
||||
OpBranch %63
|
||||
%63 = OpLabel
|
||||
%64 = OpIAdd %int %13 %21
|
||||
%50 = OpIAdd %int %64 %30
|
||||
%53 = OpIAdd %int %61 %int_1
|
||||
OpBranch %60
|
||||
%60 = OpLabel
|
||||
%65 = OpSLessThan %bool %53 %int_10
|
||||
OpBranchConditional %65 %58 %62
|
||||
%62 = OpLabel
|
||||
%52 = OpIAdd %int %42 %int_1
|
||||
OpBranch %51
|
||||
%51 = OpLabel
|
||||
OpBranch %49
|
||||
%54 = OpLabel
|
||||
OpBranch %38
|
||||
%38 = OpLabel
|
||||
%40 = OpIAdd %int %39 %int_1
|
||||
OpBranch %35
|
||||
%45 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const std::string after_hoist = R"(OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource GLSL 440
|
||||
OpName %main "main"
|
||||
%void = OpTypeVoid
|
||||
%4 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Function_int = OpTypePointer Function %int
|
||||
%int_0 = OpConstant %int 0
|
||||
%int_10 = OpConstant %int 10
|
||||
%bool = OpTypeBool
|
||||
%int_1 = OpConstant %int 1
|
||||
%main = OpFunction %void None %4
|
||||
%11 = OpLabel
|
||||
OpBranch %12
|
||||
%12 = OpLabel
|
||||
%13 = OpPhi %int %int_0 %11 %14 %15
|
||||
OpLoopMerge %16 %15 None
|
||||
OpBranch %17
|
||||
%17 = OpLabel
|
||||
%18 = OpSLessThan %bool %13 %int_10
|
||||
OpBranchConditional %18 %19 %16
|
||||
%19 = OpLabel
|
||||
OpBranch %15
|
||||
%15 = OpLabel
|
||||
%14 = OpIAdd %int %13 %int_1
|
||||
OpBranch %12
|
||||
%16 = OpLabel
|
||||
OpBranch %20
|
||||
%20 = OpLabel
|
||||
%21 = OpPhi %int %int_0 %16 %22 %23
|
||||
OpLoopMerge %24 %23 None
|
||||
OpBranch %25
|
||||
%25 = OpLabel
|
||||
%26 = OpSLessThan %bool %21 %int_10
|
||||
OpBranchConditional %26 %27 %24
|
||||
%27 = OpLabel
|
||||
%22 = OpIAdd %int %21 %int_1
|
||||
OpBranch %23
|
||||
%23 = OpLabel
|
||||
OpBranch %20
|
||||
%24 = OpLabel
|
||||
OpBranch %28
|
||||
%28 = OpLabel
|
||||
%29 = OpPhi %int %int_0 %24 %30 %31
|
||||
OpLoopMerge %32 %31 None
|
||||
OpBranch %33
|
||||
%33 = OpLabel
|
||||
%30 = OpIAdd %int %29 %int_1
|
||||
OpBranch %31
|
||||
%31 = OpLabel
|
||||
%34 = OpSLessThan %bool %30 %int_10
|
||||
OpBranchConditional %34 %28 %32
|
||||
%32 = OpLabel
|
||||
%64 = OpIAdd %int %13 %21
|
||||
%50 = OpIAdd %int %64 %30
|
||||
OpBranch %35
|
||||
%35 = OpLabel
|
||||
%36 = OpPhi %int %int_0 %32 %37 %38
|
||||
%39 = OpPhi %int %int_0 %32 %40 %38
|
||||
%41 = OpPhi %int %int_0 %32 %42 %38
|
||||
%43 = OpPhi %int %int_0 %32 %44 %38
|
||||
OpLoopMerge %45 %38 None
|
||||
OpBranch %46
|
||||
%46 = OpLabel
|
||||
%47 = OpSLessThan %bool %39 %int_10
|
||||
OpBranchConditional %47 %48 %45
|
||||
%48 = OpLabel
|
||||
OpBranch %49
|
||||
%49 = OpLabel
|
||||
%37 = OpPhi %int %36 %48 %50 %51
|
||||
%42 = OpPhi %int %41 %48 %52 %51
|
||||
%44 = OpPhi %int %43 %48 %53 %51
|
||||
OpLoopMerge %54 %51 None
|
||||
OpBranch %55
|
||||
%55 = OpLabel
|
||||
%56 = OpSLessThan %bool %42 %int_10
|
||||
OpBranchConditional %56 %57 %54
|
||||
%57 = OpLabel
|
||||
OpBranch %58
|
||||
%58 = OpLabel
|
||||
%59 = OpPhi %int %37 %57 %50 %60
|
||||
%61 = OpPhi %int %44 %57 %53 %60
|
||||
OpLoopMerge %62 %60 None
|
||||
OpBranch %63
|
||||
%63 = OpLabel
|
||||
%53 = OpIAdd %int %61 %int_1
|
||||
OpBranch %60
|
||||
%60 = OpLabel
|
||||
%65 = OpSLessThan %bool %53 %int_10
|
||||
OpBranchConditional %65 %58 %62
|
||||
%62 = OpLabel
|
||||
%52 = OpIAdd %int %42 %int_1
|
||||
OpBranch %51
|
||||
%51 = OpLabel
|
||||
OpBranch %49
|
||||
%54 = OpLabel
|
||||
OpBranch %38
|
||||
%38 = OpLabel
|
||||
%40 = OpIAdd %int %39 %int_1
|
||||
OpBranch %35
|
||||
%45 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndCheck<LICMPass>(before_hoist, after_hoist, true);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
// 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 <string>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "source/opt/licm_pass.h"
|
||||
#include "test/opt/pass_fixture.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
namespace {
|
||||
|
||||
using ::testing::UnorderedElementsAre;
|
||||
using PassClassTest = PassTest<::testing::Test>;
|
||||
|
||||
/*
|
||||
Tests that the LICM pass will move invariants through multiple loops
|
||||
|
||||
Generated from the following GLSL fragment shader
|
||||
--eliminate-local-multi-store has also been run on the spv binary
|
||||
#version 440 core
|
||||
void main(){
|
||||
int a = 2;
|
||||
int b = 1;
|
||||
int hoist = 0;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
for (int j = 0; j < 10; j++) {
|
||||
// hoist 'hoist = a - b' out of both loops
|
||||
hoist = a - b;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
TEST_F(PassClassTest, NestedDoubleHoist) {
|
||||
const std::string before_hoist = R"(OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource GLSL 440
|
||||
OpName %main "main"
|
||||
%void = OpTypeVoid
|
||||
%4 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Function_int = OpTypePointer Function %int
|
||||
%int_2 = OpConstant %int 2
|
||||
%int_1 = OpConstant %int 1
|
||||
%int_0 = OpConstant %int 0
|
||||
%int_10 = OpConstant %int 10
|
||||
%bool = OpTypeBool
|
||||
%12 = OpUndef %int
|
||||
%main = OpFunction %void None %4
|
||||
%13 = OpLabel
|
||||
OpBranch %14
|
||||
%14 = OpLabel
|
||||
%15 = OpPhi %int %int_0 %13 %16 %17
|
||||
%18 = OpPhi %int %int_0 %13 %19 %17
|
||||
%20 = OpPhi %int %12 %13 %21 %17
|
||||
OpLoopMerge %22 %17 None
|
||||
OpBranch %23
|
||||
%23 = OpLabel
|
||||
%24 = OpSLessThan %bool %18 %int_10
|
||||
OpBranchConditional %24 %25 %22
|
||||
%25 = OpLabel
|
||||
OpBranch %26
|
||||
%26 = OpLabel
|
||||
%16 = OpPhi %int %15 %25 %27 %28
|
||||
%21 = OpPhi %int %int_0 %25 %29 %28
|
||||
OpLoopMerge %30 %28 None
|
||||
OpBranch %31
|
||||
%31 = OpLabel
|
||||
%32 = OpSLessThan %bool %21 %int_10
|
||||
OpBranchConditional %32 %33 %30
|
||||
%33 = OpLabel
|
||||
%27 = OpISub %int %int_2 %int_1
|
||||
OpBranch %28
|
||||
%28 = OpLabel
|
||||
%29 = OpIAdd %int %21 %int_1
|
||||
OpBranch %26
|
||||
%30 = OpLabel
|
||||
OpBranch %17
|
||||
%17 = OpLabel
|
||||
%19 = OpIAdd %int %18 %int_1
|
||||
OpBranch %14
|
||||
%22 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const std::string after_hoist = R"(OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource GLSL 440
|
||||
OpName %main "main"
|
||||
%void = OpTypeVoid
|
||||
%4 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Function_int = OpTypePointer Function %int
|
||||
%int_2 = OpConstant %int 2
|
||||
%int_1 = OpConstant %int 1
|
||||
%int_0 = OpConstant %int 0
|
||||
%int_10 = OpConstant %int 10
|
||||
%bool = OpTypeBool
|
||||
%12 = OpUndef %int
|
||||
%main = OpFunction %void None %4
|
||||
%13 = OpLabel
|
||||
%27 = OpISub %int %int_2 %int_1
|
||||
OpBranch %14
|
||||
%14 = OpLabel
|
||||
%15 = OpPhi %int %int_0 %13 %16 %17
|
||||
%18 = OpPhi %int %int_0 %13 %19 %17
|
||||
%20 = OpPhi %int %12 %13 %21 %17
|
||||
OpLoopMerge %22 %17 None
|
||||
OpBranch %23
|
||||
%23 = OpLabel
|
||||
%24 = OpSLessThan %bool %18 %int_10
|
||||
OpBranchConditional %24 %25 %22
|
||||
%25 = OpLabel
|
||||
OpBranch %26
|
||||
%26 = OpLabel
|
||||
%16 = OpPhi %int %15 %25 %27 %28
|
||||
%21 = OpPhi %int %int_0 %25 %29 %28
|
||||
OpLoopMerge %30 %28 None
|
||||
OpBranch %31
|
||||
%31 = OpLabel
|
||||
%32 = OpSLessThan %bool %21 %int_10
|
||||
OpBranchConditional %32 %33 %30
|
||||
%33 = OpLabel
|
||||
OpBranch %28
|
||||
%28 = OpLabel
|
||||
%29 = OpIAdd %int %21 %int_1
|
||||
OpBranch %26
|
||||
%30 = OpLabel
|
||||
OpBranch %17
|
||||
%17 = OpLabel
|
||||
%19 = OpIAdd %int %18 %int_1
|
||||
OpBranch %14
|
||||
%22 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndCheck<LICMPass>(before_hoist, after_hoist, true);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
||||
+201
@@ -0,0 +1,201 @@
|
||||
// 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 <string>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "source/opt/licm_pass.h"
|
||||
#include "test/opt/pass_fixture.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
namespace {
|
||||
|
||||
using ::testing::UnorderedElementsAre;
|
||||
using PassClassTest = PassTest<::testing::Test>;
|
||||
|
||||
/*
|
||||
Tests that the LICM pass will analyse multiple independent loops in a function
|
||||
|
||||
Generated from the following GLSL fragment shader
|
||||
--eliminate-local-multi-store has also been run on the spv binary
|
||||
#version 440 core
|
||||
void main(){
|
||||
int a = 1;
|
||||
int b = 2;
|
||||
int hoist = 0;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
// invariant
|
||||
hoist = a + b;
|
||||
}
|
||||
for (int i = 0; i < 10; i++) {
|
||||
// invariant
|
||||
hoist = a + b;
|
||||
}
|
||||
int c = 1;
|
||||
int d = 2;
|
||||
int hoist2 = 0;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
// invariant
|
||||
hoist2 = c + d;
|
||||
}
|
||||
}
|
||||
*/
|
||||
TEST_F(PassClassTest, HoistFromIndependentLoops) {
|
||||
const std::string before_hoist = R"(OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource GLSL 440
|
||||
OpName %main "main"
|
||||
%void = OpTypeVoid
|
||||
%4 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Function_int = OpTypePointer Function %int
|
||||
%int_1 = OpConstant %int 1
|
||||
%int_2 = OpConstant %int 2
|
||||
%int_0 = OpConstant %int 0
|
||||
%int_10 = OpConstant %int 10
|
||||
%bool = OpTypeBool
|
||||
%main = OpFunction %void None %4
|
||||
%12 = OpLabel
|
||||
OpBranch %13
|
||||
%13 = OpLabel
|
||||
%14 = OpPhi %int %int_0 %12 %15 %16
|
||||
%17 = OpPhi %int %int_0 %12 %18 %16
|
||||
OpLoopMerge %19 %16 None
|
||||
OpBranch %20
|
||||
%20 = OpLabel
|
||||
%21 = OpSLessThan %bool %17 %int_10
|
||||
OpBranchConditional %21 %22 %19
|
||||
%22 = OpLabel
|
||||
%15 = OpIAdd %int %int_1 %int_2
|
||||
OpBranch %16
|
||||
%16 = OpLabel
|
||||
%18 = OpIAdd %int %17 %int_1
|
||||
OpBranch %13
|
||||
%19 = OpLabel
|
||||
OpBranch %23
|
||||
%23 = OpLabel
|
||||
%24 = OpPhi %int %14 %19 %25 %26
|
||||
%27 = OpPhi %int %int_0 %19 %28 %26
|
||||
OpLoopMerge %29 %26 None
|
||||
OpBranch %30
|
||||
%30 = OpLabel
|
||||
%31 = OpSLessThan %bool %27 %int_10
|
||||
OpBranchConditional %31 %32 %29
|
||||
%32 = OpLabel
|
||||
%25 = OpIAdd %int %int_1 %int_2
|
||||
OpBranch %26
|
||||
%26 = OpLabel
|
||||
%28 = OpIAdd %int %27 %int_1
|
||||
OpBranch %23
|
||||
%29 = OpLabel
|
||||
OpBranch %33
|
||||
%33 = OpLabel
|
||||
%34 = OpPhi %int %int_0 %29 %35 %36
|
||||
%37 = OpPhi %int %int_0 %29 %38 %36
|
||||
OpLoopMerge %39 %36 None
|
||||
OpBranch %40
|
||||
%40 = OpLabel
|
||||
%41 = OpSLessThan %bool %37 %int_10
|
||||
OpBranchConditional %41 %42 %39
|
||||
%42 = OpLabel
|
||||
%35 = OpIAdd %int %int_1 %int_2
|
||||
OpBranch %36
|
||||
%36 = OpLabel
|
||||
%38 = OpIAdd %int %37 %int_1
|
||||
OpBranch %33
|
||||
%39 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const std::string after_hoist = R"(OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource GLSL 440
|
||||
OpName %main "main"
|
||||
%void = OpTypeVoid
|
||||
%4 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Function_int = OpTypePointer Function %int
|
||||
%int_1 = OpConstant %int 1
|
||||
%int_2 = OpConstant %int 2
|
||||
%int_0 = OpConstant %int 0
|
||||
%int_10 = OpConstant %int 10
|
||||
%bool = OpTypeBool
|
||||
%main = OpFunction %void None %4
|
||||
%12 = OpLabel
|
||||
%15 = OpIAdd %int %int_1 %int_2
|
||||
OpBranch %13
|
||||
%13 = OpLabel
|
||||
%14 = OpPhi %int %int_0 %12 %15 %16
|
||||
%17 = OpPhi %int %int_0 %12 %18 %16
|
||||
OpLoopMerge %19 %16 None
|
||||
OpBranch %20
|
||||
%20 = OpLabel
|
||||
%21 = OpSLessThan %bool %17 %int_10
|
||||
OpBranchConditional %21 %22 %19
|
||||
%22 = OpLabel
|
||||
OpBranch %16
|
||||
%16 = OpLabel
|
||||
%18 = OpIAdd %int %17 %int_1
|
||||
OpBranch %13
|
||||
%19 = OpLabel
|
||||
%25 = OpIAdd %int %int_1 %int_2
|
||||
OpBranch %23
|
||||
%23 = OpLabel
|
||||
%24 = OpPhi %int %14 %19 %25 %26
|
||||
%27 = OpPhi %int %int_0 %19 %28 %26
|
||||
OpLoopMerge %29 %26 None
|
||||
OpBranch %30
|
||||
%30 = OpLabel
|
||||
%31 = OpSLessThan %bool %27 %int_10
|
||||
OpBranchConditional %31 %32 %29
|
||||
%32 = OpLabel
|
||||
OpBranch %26
|
||||
%26 = OpLabel
|
||||
%28 = OpIAdd %int %27 %int_1
|
||||
OpBranch %23
|
||||
%29 = OpLabel
|
||||
%35 = OpIAdd %int %int_1 %int_2
|
||||
OpBranch %33
|
||||
%33 = OpLabel
|
||||
%34 = OpPhi %int %int_0 %29 %35 %36
|
||||
%37 = OpPhi %int %int_0 %29 %38 %36
|
||||
OpLoopMerge %39 %36 None
|
||||
OpBranch %40
|
||||
%40 = OpLabel
|
||||
%41 = OpSLessThan %bool %37 %int_10
|
||||
OpBranchConditional %41 %42 %39
|
||||
%42 = OpLabel
|
||||
OpBranch %36
|
||||
%36 = OpLabel
|
||||
%38 = OpIAdd %int %37 %int_1
|
||||
OpBranch %33
|
||||
%39 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndCheck<LICMPass>(before_hoist, after_hoist, true);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
// 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 <string>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "source/opt/licm_pass.h"
|
||||
#include "test/opt/pass_fixture.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
namespace {
|
||||
|
||||
using ::testing::UnorderedElementsAre;
|
||||
using PassClassTest = PassTest<::testing::Test>;
|
||||
|
||||
/*
|
||||
A simple test for the LICM pass
|
||||
|
||||
Generated from the following GLSL fragment shader
|
||||
--eliminate-local-multi-store has also been run on the spv binary
|
||||
#version 440 core
|
||||
void main(){
|
||||
int a = 1;
|
||||
int b = 2;
|
||||
int hoist = 0;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
// invariant
|
||||
hoist = a + b;
|
||||
}
|
||||
}
|
||||
*/
|
||||
TEST_F(PassClassTest, SimpleHoist) {
|
||||
const std::string before_hoist = R"(OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource GLSL 440
|
||||
OpName %main "main"
|
||||
%void = OpTypeVoid
|
||||
%4 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Function_int = OpTypePointer Function %int
|
||||
%int_1 = OpConstant %int 1
|
||||
%int_2 = OpConstant %int 2
|
||||
%int_0 = OpConstant %int 0
|
||||
%int_10 = OpConstant %int 10
|
||||
%bool = OpTypeBool
|
||||
%main = OpFunction %void None %4
|
||||
%12 = OpLabel
|
||||
OpBranch %13
|
||||
%13 = OpLabel
|
||||
%14 = OpPhi %int %int_0 %12 %15 %16
|
||||
%17 = OpPhi %int %int_0 %12 %18 %16
|
||||
OpLoopMerge %19 %16 None
|
||||
OpBranch %20
|
||||
%20 = OpLabel
|
||||
%21 = OpSLessThan %bool %17 %int_10
|
||||
OpBranchConditional %21 %22 %19
|
||||
%22 = OpLabel
|
||||
%15 = OpIAdd %int %int_1 %int_2
|
||||
OpBranch %16
|
||||
%16 = OpLabel
|
||||
%18 = OpIAdd %int %17 %int_1
|
||||
OpBranch %13
|
||||
%19 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const std::string after_hoist = R"(OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource GLSL 440
|
||||
OpName %main "main"
|
||||
%void = OpTypeVoid
|
||||
%4 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Function_int = OpTypePointer Function %int
|
||||
%int_1 = OpConstant %int 1
|
||||
%int_2 = OpConstant %int 2
|
||||
%int_0 = OpConstant %int 0
|
||||
%int_10 = OpConstant %int 10
|
||||
%bool = OpTypeBool
|
||||
%main = OpFunction %void None %4
|
||||
%12 = OpLabel
|
||||
%15 = OpIAdd %int %int_1 %int_2
|
||||
OpBranch %13
|
||||
%13 = OpLabel
|
||||
%14 = OpPhi %int %int_0 %12 %15 %16
|
||||
%17 = OpPhi %int %int_0 %12 %18 %16
|
||||
OpLoopMerge %19 %16 None
|
||||
OpBranch %20
|
||||
%20 = OpLabel
|
||||
%21 = OpSLessThan %bool %17 %int_10
|
||||
OpBranchConditional %21 %22 %19
|
||||
%22 = OpLabel
|
||||
OpBranch %16
|
||||
%16 = OpLabel
|
||||
%18 = OpIAdd %int %17 %int_1
|
||||
OpBranch %13
|
||||
%19 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndCheck<LICMPass>(before_hoist, after_hoist, true);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
||||
+209
@@ -0,0 +1,209 @@
|
||||
// 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 <string>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "source/opt/licm_pass.h"
|
||||
#include "test/opt/pass_fixture.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
namespace {
|
||||
|
||||
using ::testing::UnorderedElementsAre;
|
||||
|
||||
using PassClassTest = PassTest<::testing::Test>;
|
||||
|
||||
/*
|
||||
Tests that the LICM pass will detect an move an invariant from a nested loop,
|
||||
but not it's parent loop
|
||||
|
||||
Generated from the following GLSL fragment shader
|
||||
--eliminate-local-multi-store has also been run on the spv binary
|
||||
#version 440 core
|
||||
void main(){
|
||||
int a = 2;
|
||||
int hoist = 0;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
for (int j = 0; j < 10; j++) {
|
||||
// hoist 'hoist = a - i' out of j loop, but not i loop
|
||||
hoist = a - i;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
TEST_F(PassClassTest, NestedSingleHoist) {
|
||||
const std::string before_hoist = R"(OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource GLSL 440
|
||||
OpName %main "main"
|
||||
%void = OpTypeVoid
|
||||
%4 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Function_int = OpTypePointer Function %int
|
||||
%int_2 = OpConstant %int 2
|
||||
%int_0 = OpConstant %int 0
|
||||
%int_10 = OpConstant %int 10
|
||||
%bool = OpTypeBool
|
||||
%int_1 = OpConstant %int 1
|
||||
%12 = OpUndef %int
|
||||
%main = OpFunction %void None %4
|
||||
%13 = OpLabel
|
||||
OpBranch %14
|
||||
%14 = OpLabel
|
||||
%15 = OpPhi %int %int_0 %13 %16 %17
|
||||
%18 = OpPhi %int %int_0 %13 %19 %17
|
||||
%20 = OpPhi %int %12 %13 %21 %17
|
||||
OpLoopMerge %22 %17 None
|
||||
OpBranch %23
|
||||
%23 = OpLabel
|
||||
%24 = OpSLessThan %bool %18 %int_10
|
||||
OpBranchConditional %24 %25 %22
|
||||
%25 = OpLabel
|
||||
OpBranch %26
|
||||
%26 = OpLabel
|
||||
%16 = OpPhi %int %15 %25 %27 %28
|
||||
%21 = OpPhi %int %int_0 %25 %29 %28
|
||||
OpLoopMerge %30 %28 None
|
||||
OpBranch %31
|
||||
%31 = OpLabel
|
||||
%32 = OpSLessThan %bool %21 %int_10
|
||||
OpBranchConditional %32 %33 %30
|
||||
%33 = OpLabel
|
||||
%27 = OpISub %int %int_2 %18
|
||||
OpBranch %28
|
||||
%28 = OpLabel
|
||||
%29 = OpIAdd %int %21 %int_1
|
||||
OpBranch %26
|
||||
%30 = OpLabel
|
||||
OpBranch %17
|
||||
%17 = OpLabel
|
||||
%19 = OpIAdd %int %18 %int_1
|
||||
OpBranch %14
|
||||
%22 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const std::string after_hoist = R"(OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource GLSL 440
|
||||
OpName %main "main"
|
||||
%void = OpTypeVoid
|
||||
%4 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Function_int = OpTypePointer Function %int
|
||||
%int_2 = OpConstant %int 2
|
||||
%int_0 = OpConstant %int 0
|
||||
%int_10 = OpConstant %int 10
|
||||
%bool = OpTypeBool
|
||||
%int_1 = OpConstant %int 1
|
||||
%12 = OpUndef %int
|
||||
%main = OpFunction %void None %4
|
||||
%13 = OpLabel
|
||||
OpBranch %14
|
||||
%14 = OpLabel
|
||||
%15 = OpPhi %int %int_0 %13 %16 %17
|
||||
%18 = OpPhi %int %int_0 %13 %19 %17
|
||||
%20 = OpPhi %int %12 %13 %21 %17
|
||||
OpLoopMerge %22 %17 None
|
||||
OpBranch %23
|
||||
%23 = OpLabel
|
||||
%24 = OpSLessThan %bool %18 %int_10
|
||||
OpBranchConditional %24 %25 %22
|
||||
%25 = OpLabel
|
||||
%27 = OpISub %int %int_2 %18
|
||||
OpBranch %26
|
||||
%26 = OpLabel
|
||||
%16 = OpPhi %int %15 %25 %27 %28
|
||||
%21 = OpPhi %int %int_0 %25 %29 %28
|
||||
OpLoopMerge %30 %28 None
|
||||
OpBranch %31
|
||||
%31 = OpLabel
|
||||
%32 = OpSLessThan %bool %21 %int_10
|
||||
OpBranchConditional %32 %33 %30
|
||||
%33 = OpLabel
|
||||
OpBranch %28
|
||||
%28 = OpLabel
|
||||
%29 = OpIAdd %int %21 %int_1
|
||||
OpBranch %26
|
||||
%30 = OpLabel
|
||||
OpBranch %17
|
||||
%17 = OpLabel
|
||||
%19 = OpIAdd %int %18 %int_1
|
||||
OpBranch %14
|
||||
%22 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndCheck<LICMPass>(before_hoist, after_hoist, true);
|
||||
}
|
||||
|
||||
TEST_F(PassClassTest, PreHeaderIsAlsoHeader) {
|
||||
// Move OpSLessThan out of the inner loop. The preheader for the inner loop
|
||||
// is the header of the outer loop. The loop merge should not be separated
|
||||
// from the branch in that block.
|
||||
const std::string text = R"(
|
||||
; CHECK: OpFunction
|
||||
; CHECK-NEXT: OpLabel
|
||||
; CHECK-NEXT: OpBranch [[header:%\w+]]
|
||||
; CHECK: [[header]] = OpLabel
|
||||
; CHECK-NEXT: OpSLessThan %bool %int_1 %int_1
|
||||
; CHECK-NEXT: OpLoopMerge
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %2 "main"
|
||||
OpExecutionMode %2 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
%void = OpTypeVoid
|
||||
%4 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%int_1 = OpConstant %int 1
|
||||
%bool = OpTypeBool
|
||||
%2 = OpFunction %void None %4
|
||||
%18 = OpLabel
|
||||
OpBranch %21
|
||||
%21 = OpLabel
|
||||
OpLoopMerge %22 %23 None
|
||||
OpBranch %24
|
||||
%24 = OpLabel
|
||||
%25 = OpSLessThan %bool %int_1 %int_1
|
||||
OpLoopMerge %26 %27 None
|
||||
OpBranchConditional %25 %27 %26
|
||||
%27 = OpLabel
|
||||
OpBranch %24
|
||||
%26 = OpLabel
|
||||
OpBranch %22
|
||||
%23 = OpLabel
|
||||
OpBranch %21
|
||||
%22 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<LICMPass>(text, true);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
||||
+197
@@ -0,0 +1,197 @@
|
||||
// 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 <string>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "source/opt/licm_pass.h"
|
||||
#include "test/opt/pass_fixture.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
namespace {
|
||||
|
||||
using ::testing::UnorderedElementsAre;
|
||||
using PassClassTest = PassTest<::testing::Test>;
|
||||
|
||||
/*
|
||||
Tests that the LICM pass will generate a preheader when one is not present
|
||||
|
||||
Generated from the following GLSL fragment shader
|
||||
--eliminate-local-multi-store has also been run on the spv binary
|
||||
#version 440 core
|
||||
void main(){
|
||||
int a = 1;
|
||||
int b = 2;
|
||||
int hoist = 0;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (i == 5) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 10; i++) {
|
||||
hoist = a + b;
|
||||
}
|
||||
}
|
||||
*/
|
||||
TEST_F(PassClassTest, HoistWithoutPreheader) {
|
||||
const std::string text = R"(OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource GLSL 440
|
||||
OpName %main "main"
|
||||
%void = OpTypeVoid
|
||||
%4 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Function_int = OpTypePointer Function %int
|
||||
%int_1 = OpConstant %int 1
|
||||
%int_2 = OpConstant %int 2
|
||||
%int_0 = OpConstant %int 0
|
||||
%int_10 = OpConstant %int 10
|
||||
%bool = OpTypeBool
|
||||
%int_5 = OpConstant %int 5
|
||||
%main = OpFunction %void None %4
|
||||
%13 = OpLabel
|
||||
OpBranch %14
|
||||
%14 = OpLabel
|
||||
%15 = OpPhi %int %int_0 %13 %16 %17
|
||||
; CHECK: OpLoopMerge [[preheader:%\w+]]
|
||||
OpLoopMerge %25 %17 None
|
||||
OpBranch %19
|
||||
%19 = OpLabel
|
||||
%20 = OpSLessThan %bool %15 %int_10
|
||||
OpBranchConditional %20 %21 %25
|
||||
%21 = OpLabel
|
||||
%22 = OpIEqual %bool %15 %int_5
|
||||
OpSelectionMerge %23 None
|
||||
OpBranchConditional %22 %24 %23
|
||||
%24 = OpLabel
|
||||
OpBranch %25
|
||||
%23 = OpLabel
|
||||
OpBranch %17
|
||||
%17 = OpLabel
|
||||
%16 = OpIAdd %int %15 %int_1
|
||||
OpBranch %14
|
||||
; Check that we hoisted the code to the preheader
|
||||
; CHECK: [[preheader]] = OpLabel
|
||||
; CHECK-NEXT: OpPhi
|
||||
; CHECK-NEXT: OpPhi
|
||||
; CHECK-NEXT: OpIAdd
|
||||
; CHECK-NEXT: OpBranch [[header:%\w+]]
|
||||
; CHECK: [[header]] = OpLabel
|
||||
; CHECK-NEXT: OpPhi
|
||||
; CHECK-NEXT: OpPhi
|
||||
; CHECK: OpLoopMerge
|
||||
%25 = OpLabel
|
||||
%26 = OpPhi %int %int_0 %24 %int_0 %19 %27 %28
|
||||
%29 = OpPhi %int %int_0 %24 %int_0 %19 %30 %28
|
||||
OpLoopMerge %31 %28 None
|
||||
OpBranch %32
|
||||
%32 = OpLabel
|
||||
%33 = OpSLessThan %bool %29 %int_10
|
||||
OpBranchConditional %33 %34 %31
|
||||
%34 = OpLabel
|
||||
%27 = OpIAdd %int %int_1 %int_2
|
||||
OpBranch %28
|
||||
%28 = OpLabel
|
||||
%30 = OpIAdd %int %29 %int_1
|
||||
OpBranch %25
|
||||
%31 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<LICMPass>(text, false);
|
||||
}
|
||||
|
||||
TEST_F(PassClassTest, HoistWithoutPreheaderAtIdBound) {
|
||||
const std::string text = R"(OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource GLSL 440
|
||||
OpName %main "main"
|
||||
%void = OpTypeVoid
|
||||
%4 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Function_int = OpTypePointer Function %int
|
||||
%int_1 = OpConstant %int 1
|
||||
%int_2 = OpConstant %int 2
|
||||
%int_0 = OpConstant %int 0
|
||||
%int_10 = OpConstant %int 10
|
||||
%bool = OpTypeBool
|
||||
%int_5 = OpConstant %int 5
|
||||
%main = OpFunction %void None %4
|
||||
%13 = OpLabel
|
||||
OpBranch %14
|
||||
%14 = OpLabel
|
||||
%15 = OpPhi %int %int_0 %13 %16 %17
|
||||
OpLoopMerge %25 %17 None
|
||||
OpBranch %19
|
||||
%19 = OpLabel
|
||||
%20 = OpSLessThan %bool %15 %int_10
|
||||
OpBranchConditional %20 %21 %25
|
||||
%21 = OpLabel
|
||||
%22 = OpIEqual %bool %15 %int_5
|
||||
OpSelectionMerge %23 None
|
||||
OpBranchConditional %22 %24 %23
|
||||
%24 = OpLabel
|
||||
OpBranch %25
|
||||
%23 = OpLabel
|
||||
OpBranch %17
|
||||
%17 = OpLabel
|
||||
%16 = OpIAdd %int %15 %int_1
|
||||
OpBranch %14
|
||||
%25 = OpLabel
|
||||
%26 = OpPhi %int %int_0 %24 %int_0 %19 %27 %28
|
||||
%29 = OpPhi %int %int_0 %24 %int_0 %19 %30 %28
|
||||
OpLoopMerge %31 %28 None
|
||||
OpBranch %32
|
||||
%32 = OpLabel
|
||||
%33 = OpSLessThan %bool %29 %int_10
|
||||
OpBranchConditional %33 %34 %31
|
||||
%34 = OpLabel
|
||||
%27 = OpIAdd %int %int_1 %int_2
|
||||
OpBranch %28
|
||||
%28 = OpLabel
|
||||
%30 = OpIAdd %int %29 %int_1
|
||||
OpBranch %25
|
||||
%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);
|
||||
uint32_t current_bound = context->module()->id_bound();
|
||||
context->set_max_id_bound(current_bound);
|
||||
|
||||
auto pass = MakeUnique<LICMPass>();
|
||||
auto result = pass->Run(context.get());
|
||||
EXPECT_EQ(result, Pass::Status::Failure);
|
||||
|
||||
std::vector<uint32_t> binary;
|
||||
context->module()->ToBinary(&binary, false);
|
||||
std::string optimized_asm;
|
||||
SpirvTools tools_(SPV_ENV_UNIVERSAL_1_1);
|
||||
tools_.Disassemble(binary, &optimized_asm);
|
||||
std::cout << optimized_asm << std::endl;
|
||||
}
|
||||
} // namespace
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
||||
@@ -0,0 +1,605 @@
|
||||
// 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 <vector>
|
||||
|
||||
#include "effcee/effcee.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "source/opt/build_module.h"
|
||||
#include "source/opt/loop_descriptor.h"
|
||||
#include "source/opt/loop_utils.h"
|
||||
#include "test/opt//assembly_builder.h"
|
||||
#include "test/opt/function_utils.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
namespace {
|
||||
|
||||
bool Validate(const std::vector<uint32_t>& bin) {
|
||||
spv_target_env target_env = SPV_ENV_UNIVERSAL_1_2;
|
||||
spv_context spvContext = spvContextCreate(target_env);
|
||||
spv_diagnostic diagnostic = nullptr;
|
||||
spv_const_binary_t binary = {bin.data(), bin.size()};
|
||||
spv_result_t error = spvValidate(spvContext, &binary, &diagnostic);
|
||||
if (error != 0) spvDiagnosticPrint(diagnostic);
|
||||
spvDiagnosticDestroy(diagnostic);
|
||||
spvContextDestroy(spvContext);
|
||||
return error == 0;
|
||||
}
|
||||
|
||||
void Match(const std::string& original, IRContext* context,
|
||||
bool do_validation = true) {
|
||||
std::vector<uint32_t> bin;
|
||||
context->module()->ToBinary(&bin, true);
|
||||
if (do_validation) {
|
||||
EXPECT_TRUE(Validate(bin));
|
||||
}
|
||||
std::string assembly;
|
||||
SpirvTools tools(SPV_ENV_UNIVERSAL_1_2);
|
||||
EXPECT_TRUE(
|
||||
tools.Disassemble(bin, &assembly, SPV_BINARY_TO_TEXT_OPTION_NO_HEADER))
|
||||
<< "Disassembling failed for shader:\n"
|
||||
<< assembly << std::endl;
|
||||
auto match_result = effcee::Match(assembly, original);
|
||||
EXPECT_EQ(effcee::Result::Status::Ok, match_result.status())
|
||||
<< match_result.message() << "\nChecking result:\n"
|
||||
<< assembly;
|
||||
}
|
||||
|
||||
using LCSSATest = ::testing::Test;
|
||||
|
||||
/*
|
||||
Generated from the following GLSL + --eliminate-local-multi-store
|
||||
|
||||
#version 330 core
|
||||
layout(location = 0) out vec4 c;
|
||||
void main() {
|
||||
int i = 0;
|
||||
for (; i < 10; i++) {
|
||||
}
|
||||
if (i != 0) {
|
||||
i = 1;
|
||||
}
|
||||
}
|
||||
*/
|
||||
TEST_F(LCSSATest, SimpleLCSSA) {
|
||||
const std::string text = R"(
|
||||
; CHECK: OpLoopMerge [[merge:%\w+]] %19 None
|
||||
; CHECK: [[merge]] = OpLabel
|
||||
; CHECK-NEXT: [[phi:%\w+]] = OpPhi {{%\w+}} %30 %20
|
||||
; CHECK-NEXT: %27 = OpINotEqual {{%\w+}} [[phi]] %9
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %2 "main" %3
|
||||
OpExecutionMode %2 OriginUpperLeft
|
||||
OpSource GLSL 330
|
||||
OpName %2 "main"
|
||||
OpName %3 "c"
|
||||
OpDecorate %3 Location 0
|
||||
%5 = OpTypeVoid
|
||||
%6 = OpTypeFunction %5
|
||||
%7 = OpTypeInt 32 1
|
||||
%8 = OpTypePointer Function %7
|
||||
%9 = OpConstant %7 0
|
||||
%10 = OpConstant %7 10
|
||||
%11 = OpTypeBool
|
||||
%12 = OpConstant %7 1
|
||||
%13 = OpTypeFloat 32
|
||||
%14 = OpTypeVector %13 4
|
||||
%15 = OpTypePointer Output %14
|
||||
%3 = OpVariable %15 Output
|
||||
%2 = OpFunction %5 None %6
|
||||
%16 = OpLabel
|
||||
OpBranch %17
|
||||
%17 = OpLabel
|
||||
%30 = OpPhi %7 %9 %16 %25 %19
|
||||
OpLoopMerge %18 %19 None
|
||||
OpBranch %20
|
||||
%20 = OpLabel
|
||||
%22 = OpSLessThan %11 %30 %10
|
||||
OpBranchConditional %22 %23 %18
|
||||
%23 = OpLabel
|
||||
OpBranch %19
|
||||
%19 = OpLabel
|
||||
%25 = OpIAdd %7 %30 %12
|
||||
OpBranch %17
|
||||
%18 = OpLabel
|
||||
%27 = OpINotEqual %11 %30 %9
|
||||
OpSelectionMerge %28 None
|
||||
OpBranchConditional %27 %29 %28
|
||||
%29 = OpLabel
|
||||
OpBranch %28
|
||||
%28 = OpLabel
|
||||
%31 = OpPhi %7 %30 %18 %12 %29
|
||||
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;
|
||||
const Function* f = spvtest::GetFunction(module, 2);
|
||||
LoopDescriptor ld{context.get(), f};
|
||||
|
||||
Loop* loop = ld[17];
|
||||
EXPECT_FALSE(loop->IsLCSSA());
|
||||
LoopUtils Util(context.get(), loop);
|
||||
Util.MakeLoopClosedSSA();
|
||||
EXPECT_TRUE(loop->IsLCSSA());
|
||||
Match(text, context.get());
|
||||
}
|
||||
|
||||
/*
|
||||
Generated from the following GLSL + --eliminate-local-multi-store
|
||||
|
||||
#version 330 core
|
||||
layout(location = 0) out vec4 c;
|
||||
void main() {
|
||||
int i = 0;
|
||||
for (; i < 10; i++) {
|
||||
}
|
||||
if (i != 0) {
|
||||
i = 1;
|
||||
}
|
||||
}
|
||||
*/
|
||||
// Same test as above, but should reuse an existing phi.
|
||||
TEST_F(LCSSATest, PhiReuseLCSSA) {
|
||||
const std::string text = R"(
|
||||
; CHECK: OpLoopMerge [[merge:%\w+]] %19 None
|
||||
; CHECK: [[merge]] = OpLabel
|
||||
; CHECK-NEXT: [[phi:%\w+]] = OpPhi {{%\w+}} %30 %20
|
||||
; CHECK-NEXT: %27 = OpINotEqual {{%\w+}} [[phi]] %9
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %2 "main" %3
|
||||
OpExecutionMode %2 OriginUpperLeft
|
||||
OpSource GLSL 330
|
||||
OpName %2 "main"
|
||||
OpName %3 "c"
|
||||
OpDecorate %3 Location 0
|
||||
%5 = OpTypeVoid
|
||||
%6 = OpTypeFunction %5
|
||||
%7 = OpTypeInt 32 1
|
||||
%8 = OpTypePointer Function %7
|
||||
%9 = OpConstant %7 0
|
||||
%10 = OpConstant %7 10
|
||||
%11 = OpTypeBool
|
||||
%12 = OpConstant %7 1
|
||||
%13 = OpTypeFloat 32
|
||||
%14 = OpTypeVector %13 4
|
||||
%15 = OpTypePointer Output %14
|
||||
%3 = OpVariable %15 Output
|
||||
%2 = OpFunction %5 None %6
|
||||
%16 = OpLabel
|
||||
OpBranch %17
|
||||
%17 = OpLabel
|
||||
%30 = OpPhi %7 %9 %16 %25 %19
|
||||
OpLoopMerge %18 %19 None
|
||||
OpBranch %20
|
||||
%20 = OpLabel
|
||||
%22 = OpSLessThan %11 %30 %10
|
||||
OpBranchConditional %22 %23 %18
|
||||
%23 = OpLabel
|
||||
OpBranch %19
|
||||
%19 = OpLabel
|
||||
%25 = OpIAdd %7 %30 %12
|
||||
OpBranch %17
|
||||
%18 = OpLabel
|
||||
%32 = OpPhi %7 %30 %20
|
||||
%27 = OpINotEqual %11 %30 %9
|
||||
OpSelectionMerge %28 None
|
||||
OpBranchConditional %27 %29 %28
|
||||
%29 = OpLabel
|
||||
OpBranch %28
|
||||
%28 = OpLabel
|
||||
%31 = OpPhi %7 %30 %18 %12 %29
|
||||
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;
|
||||
const Function* f = spvtest::GetFunction(module, 2);
|
||||
LoopDescriptor ld{context.get(), f};
|
||||
|
||||
Loop* loop = ld[17];
|
||||
EXPECT_FALSE(loop->IsLCSSA());
|
||||
LoopUtils Util(context.get(), loop);
|
||||
Util.MakeLoopClosedSSA();
|
||||
EXPECT_TRUE(loop->IsLCSSA());
|
||||
Match(text, context.get());
|
||||
}
|
||||
|
||||
/*
|
||||
Generated from the following GLSL + --eliminate-local-multi-store
|
||||
|
||||
#version 330 core
|
||||
layout(location = 0) out vec4 c;
|
||||
void main() {
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
for (; i < 10; i++) {}
|
||||
for (; j < 10; j++) {}
|
||||
if (j != 0) {
|
||||
i = 1;
|
||||
}
|
||||
}
|
||||
*/
|
||||
TEST_F(LCSSATest, DualLoopLCSSA) {
|
||||
const std::string text = R"(
|
||||
; CHECK: %20 = OpLabel
|
||||
; CHECK-NEXT: [[phi:%\w+]] = OpPhi %6 %17 %21
|
||||
; CHECK: %33 = OpLabel
|
||||
; CHECK-NEXT: {{%\w+}} = OpPhi {{%\w+}} [[phi]] %28 %11 %34
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %2 "main" %3
|
||||
OpExecutionMode %2 OriginUpperLeft
|
||||
OpSource GLSL 330
|
||||
OpName %2 "main"
|
||||
OpName %3 "c"
|
||||
OpDecorate %3 Location 0
|
||||
%4 = OpTypeVoid
|
||||
%5 = OpTypeFunction %4
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%8 = OpConstant %6 0
|
||||
%9 = OpConstant %6 10
|
||||
%10 = OpTypeBool
|
||||
%11 = OpConstant %6 1
|
||||
%12 = OpTypeFloat 32
|
||||
%13 = OpTypeVector %12 4
|
||||
%14 = OpTypePointer Output %13
|
||||
%3 = OpVariable %14 Output
|
||||
%2 = OpFunction %4 None %5
|
||||
%15 = OpLabel
|
||||
OpBranch %16
|
||||
%16 = OpLabel
|
||||
%17 = OpPhi %6 %8 %15 %18 %19
|
||||
OpLoopMerge %20 %19 None
|
||||
OpBranch %21
|
||||
%21 = OpLabel
|
||||
%22 = OpSLessThan %10 %17 %9
|
||||
OpBranchConditional %22 %23 %20
|
||||
%23 = OpLabel
|
||||
OpBranch %19
|
||||
%19 = OpLabel
|
||||
%18 = OpIAdd %6 %17 %11
|
||||
OpBranch %16
|
||||
%20 = OpLabel
|
||||
OpBranch %24
|
||||
%24 = OpLabel
|
||||
%25 = OpPhi %6 %8 %20 %26 %27
|
||||
OpLoopMerge %28 %27 None
|
||||
OpBranch %29
|
||||
%29 = OpLabel
|
||||
%30 = OpSLessThan %10 %25 %9
|
||||
OpBranchConditional %30 %31 %28
|
||||
%31 = OpLabel
|
||||
OpBranch %27
|
||||
%27 = OpLabel
|
||||
%26 = OpIAdd %6 %25 %11
|
||||
OpBranch %24
|
||||
%28 = OpLabel
|
||||
%32 = OpINotEqual %10 %25 %8
|
||||
OpSelectionMerge %33 None
|
||||
OpBranchConditional %32 %34 %33
|
||||
%34 = OpLabel
|
||||
OpBranch %33
|
||||
%33 = OpLabel
|
||||
%35 = OpPhi %6 %17 %28 %11 %34
|
||||
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;
|
||||
const Function* f = spvtest::GetFunction(module, 2);
|
||||
LoopDescriptor ld{context.get(), f};
|
||||
|
||||
Loop* loop = ld[16];
|
||||
EXPECT_FALSE(loop->IsLCSSA());
|
||||
LoopUtils Util(context.get(), loop);
|
||||
Util.MakeLoopClosedSSA();
|
||||
EXPECT_TRUE(loop->IsLCSSA());
|
||||
Match(text, context.get());
|
||||
}
|
||||
|
||||
/*
|
||||
Generated from the following GLSL + --eliminate-local-multi-store
|
||||
|
||||
#version 330 core
|
||||
layout(location = 0) out vec4 c;
|
||||
void main() {
|
||||
int i = 0;
|
||||
if (i != 0) {
|
||||
for (; i < 10; i++) {}
|
||||
}
|
||||
if (i != 0) {
|
||||
i = 1;
|
||||
}
|
||||
}
|
||||
*/
|
||||
TEST_F(LCSSATest, PhiUserLCSSA) {
|
||||
const std::string text = R"(
|
||||
; CHECK: OpLoopMerge [[merge:%\w+]] %22 None
|
||||
; CHECK: [[merge]] = OpLabel
|
||||
; CHECK-NEXT: [[phi:%\w+]] = OpPhi {{%\w+}} %20 %24
|
||||
; CHECK: %17 = OpLabel
|
||||
; CHECK-NEXT: {{%\w+}} = OpPhi {{%\w+}} %8 %15 [[phi]] %23
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %2 "main" %3
|
||||
OpExecutionMode %2 OriginUpperLeft
|
||||
OpSource GLSL 330
|
||||
OpName %2 "main"
|
||||
OpName %3 "c"
|
||||
OpDecorate %3 Location 0
|
||||
%4 = OpTypeVoid
|
||||
%5 = OpTypeFunction %4
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%8 = OpConstant %6 0
|
||||
%9 = OpTypeBool
|
||||
%10 = OpConstant %6 10
|
||||
%11 = OpConstant %6 1
|
||||
%12 = OpTypeFloat 32
|
||||
%13 = OpTypeVector %12 4
|
||||
%14 = OpTypePointer Output %13
|
||||
%3 = OpVariable %14 Output
|
||||
%2 = OpFunction %4 None %5
|
||||
%15 = OpLabel
|
||||
%16 = OpINotEqual %9 %8 %8
|
||||
OpSelectionMerge %17 None
|
||||
OpBranchConditional %16 %18 %17
|
||||
%18 = OpLabel
|
||||
OpBranch %19
|
||||
%19 = OpLabel
|
||||
%20 = OpPhi %6 %8 %18 %21 %22
|
||||
OpLoopMerge %23 %22 None
|
||||
OpBranch %24
|
||||
%24 = OpLabel
|
||||
%25 = OpSLessThan %9 %20 %10
|
||||
OpBranchConditional %25 %26 %23
|
||||
%26 = OpLabel
|
||||
OpBranch %22
|
||||
%22 = OpLabel
|
||||
%21 = OpIAdd %6 %20 %11
|
||||
OpBranch %19
|
||||
%23 = OpLabel
|
||||
OpBranch %17
|
||||
%17 = OpLabel
|
||||
%27 = OpPhi %6 %8 %15 %20 %23
|
||||
%28 = OpINotEqual %9 %27 %8
|
||||
OpSelectionMerge %29 None
|
||||
OpBranchConditional %28 %30 %29
|
||||
%30 = OpLabel
|
||||
OpBranch %29
|
||||
%29 = OpLabel
|
||||
%31 = OpPhi %6 %27 %17 %11 %30
|
||||
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;
|
||||
const Function* f = spvtest::GetFunction(module, 2);
|
||||
LoopDescriptor ld{context.get(), f};
|
||||
|
||||
Loop* loop = ld[19];
|
||||
EXPECT_FALSE(loop->IsLCSSA());
|
||||
LoopUtils Util(context.get(), loop);
|
||||
Util.MakeLoopClosedSSA();
|
||||
EXPECT_TRUE(loop->IsLCSSA());
|
||||
Match(text, context.get());
|
||||
}
|
||||
|
||||
/*
|
||||
Generated from the following GLSL + --eliminate-local-multi-store
|
||||
|
||||
#version 330 core
|
||||
void main() {
|
||||
int i = 0;
|
||||
if (i != 0) {
|
||||
for (; i < 10; i++) {
|
||||
if (i > 5) break;
|
||||
}
|
||||
}
|
||||
if (i != 0) {
|
||||
i = 1;
|
||||
}
|
||||
}
|
||||
*/
|
||||
TEST_F(LCSSATest, LCSSAWithBreak) {
|
||||
const std::string text = R"(
|
||||
; CHECK: OpLoopMerge [[merge:%\w+]] %19 None
|
||||
; CHECK: [[merge]] = OpLabel
|
||||
; CHECK-NEXT: [[phi:%\w+]] = OpPhi {{%\w+}} %17 %21 %17 %26
|
||||
; CHECK: %14 = OpLabel
|
||||
; CHECK-NEXT: {{%\w+}} = OpPhi {{%\w+}} %7 %12 [[phi]] [[merge]]
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %2 "main"
|
||||
OpExecutionMode %2 OriginUpperLeft
|
||||
OpSource GLSL 330
|
||||
OpName %2 "main"
|
||||
%3 = OpTypeVoid
|
||||
%4 = OpTypeFunction %3
|
||||
%5 = OpTypeInt 32 1
|
||||
%6 = OpTypePointer Function %5
|
||||
%7 = OpConstant %5 0
|
||||
%8 = OpTypeBool
|
||||
%9 = OpConstant %5 10
|
||||
%10 = OpConstant %5 5
|
||||
%11 = OpConstant %5 1
|
||||
%2 = OpFunction %3 None %4
|
||||
%12 = OpLabel
|
||||
%13 = OpINotEqual %8 %7 %7
|
||||
OpSelectionMerge %14 None
|
||||
OpBranchConditional %13 %15 %14
|
||||
%15 = OpLabel
|
||||
OpBranch %16
|
||||
%16 = OpLabel
|
||||
%17 = OpPhi %5 %7 %15 %18 %19
|
||||
OpLoopMerge %20 %19 None
|
||||
OpBranch %21
|
||||
%21 = OpLabel
|
||||
%22 = OpSLessThan %8 %17 %9
|
||||
OpBranchConditional %22 %23 %20
|
||||
%23 = OpLabel
|
||||
%24 = OpSGreaterThan %8 %17 %10
|
||||
OpSelectionMerge %25 None
|
||||
OpBranchConditional %24 %26 %25
|
||||
%26 = OpLabel
|
||||
OpBranch %20
|
||||
%25 = OpLabel
|
||||
OpBranch %19
|
||||
%19 = OpLabel
|
||||
%18 = OpIAdd %5 %17 %11
|
||||
OpBranch %16
|
||||
%20 = OpLabel
|
||||
OpBranch %14
|
||||
%14 = OpLabel
|
||||
%27 = OpPhi %5 %7 %12 %17 %20
|
||||
%28 = OpINotEqual %8 %27 %7
|
||||
OpSelectionMerge %29 None
|
||||
OpBranchConditional %28 %30 %29
|
||||
%30 = OpLabel
|
||||
OpBranch %29
|
||||
%29 = OpLabel
|
||||
%31 = OpPhi %5 %27 %14 %11 %30
|
||||
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;
|
||||
const Function* f = spvtest::GetFunction(module, 2);
|
||||
LoopDescriptor ld{context.get(), f};
|
||||
|
||||
Loop* loop = ld[19];
|
||||
EXPECT_FALSE(loop->IsLCSSA());
|
||||
LoopUtils Util(context.get(), loop);
|
||||
Util.MakeLoopClosedSSA();
|
||||
EXPECT_TRUE(loop->IsLCSSA());
|
||||
Match(text, context.get());
|
||||
}
|
||||
|
||||
/*
|
||||
Generated from the following GLSL + --eliminate-local-multi-store
|
||||
|
||||
#version 330 core
|
||||
void main() {
|
||||
int i = 0;
|
||||
for (; i < 10; i++) {}
|
||||
for (int j = i; j < 10;) { j = i + j; }
|
||||
}
|
||||
*/
|
||||
TEST_F(LCSSATest, LCSSAUseInNonEligiblePhi) {
|
||||
const std::string text = R"(
|
||||
; CHECK: %12 = OpLabel
|
||||
; CHECK-NEXT: [[def_to_close:%\w+]] = OpPhi {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} [[continue:%\w+]]
|
||||
; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
|
||||
; CHECK: [[merge]] = OpLabel
|
||||
; CHECK-NEXT: [[closing_phi:%\w+]] = OpPhi {{%\w+}} [[def_to_close]] %17
|
||||
; CHECK: %16 = OpLabel
|
||||
; CHECK-NEXT: [[use_in_phi:%\w+]] = OpPhi {{%\w+}} %21 %22 [[closing_phi]] [[merge]]
|
||||
; CHECK: OpIAdd {{%\w+}} [[closing_phi]] [[use_in_phi]]
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %2 "main"
|
||||
OpExecutionMode %2 OriginUpperLeft
|
||||
OpSource GLSL 330
|
||||
OpName %2 "main"
|
||||
%3 = OpTypeVoid
|
||||
%4 = OpTypeFunction %3
|
||||
%5 = OpTypeInt 32 1
|
||||
%6 = OpTypePointer Function %5
|
||||
%7 = OpConstant %5 0
|
||||
%8 = OpConstant %5 10
|
||||
%9 = OpTypeBool
|
||||
%10 = OpConstant %5 1
|
||||
%2 = OpFunction %3 None %4
|
||||
%11 = OpLabel
|
||||
OpBranch %12
|
||||
%12 = OpLabel
|
||||
%13 = OpPhi %5 %7 %11 %14 %15
|
||||
OpLoopMerge %16 %15 None
|
||||
OpBranch %17
|
||||
%17 = OpLabel
|
||||
%18 = OpSLessThan %9 %13 %8
|
||||
OpBranchConditional %18 %19 %16
|
||||
%19 = OpLabel
|
||||
OpBranch %15
|
||||
%15 = OpLabel
|
||||
%14 = OpIAdd %5 %13 %10
|
||||
OpBranch %12
|
||||
%16 = OpLabel
|
||||
%20 = OpPhi %5 %13 %17 %21 %22
|
||||
OpLoopMerge %23 %22 None
|
||||
OpBranch %24
|
||||
%24 = OpLabel
|
||||
%25 = OpSLessThan %9 %20 %8
|
||||
OpBranchConditional %25 %26 %23
|
||||
%26 = OpLabel
|
||||
%21 = OpIAdd %5 %13 %20
|
||||
OpBranch %22
|
||||
%22 = OpLabel
|
||||
OpBranch %16
|
||||
%23 = 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;
|
||||
const Function* f = spvtest::GetFunction(module, 2);
|
||||
LoopDescriptor ld{context.get(), f};
|
||||
|
||||
Loop* loop = ld[12];
|
||||
EXPECT_FALSE(loop->IsLCSSA());
|
||||
LoopUtils Util(context.get(), loop);
|
||||
Util.MakeLoopClosedSSA();
|
||||
EXPECT_TRUE(loop->IsLCSSA());
|
||||
Match(text, context.get());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
||||
+420
@@ -0,0 +1,420 @@
|
||||
// Copyright (c) 2017 Google Inc.
|
||||
//
|
||||
// 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 <vector>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "source/opt/loop_descriptor.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 PassClassTest = PassTest<::testing::Test>;
|
||||
|
||||
/*
|
||||
Generated from the following GLSL
|
||||
#version 330 core
|
||||
layout(location = 0) out vec4 c;
|
||||
void main() {
|
||||
int i = 0;
|
||||
for(; i < 10; ++i) {
|
||||
}
|
||||
}
|
||||
*/
|
||||
TEST_F(PassClassTest, BasicVisitFromEntryPoint) {
|
||||
const std::string text = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %2 "main" %3
|
||||
OpExecutionMode %2 OriginUpperLeft
|
||||
OpSource GLSL 330
|
||||
OpName %2 "main"
|
||||
OpName %5 "i"
|
||||
OpName %3 "c"
|
||||
OpDecorate %3 Location 0
|
||||
%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 = OpTypeVector %14 4
|
||||
%16 = OpTypePointer Output %15
|
||||
%3 = OpVariable %16 Output
|
||||
%2 = OpFunction %6 None %7
|
||||
%17 = OpLabel
|
||||
%5 = OpVariable %9 Function
|
||||
OpStore %5 %10
|
||||
OpBranch %18
|
||||
%18 = OpLabel
|
||||
OpLoopMerge %19 %20 None
|
||||
OpBranch %21
|
||||
%21 = OpLabel
|
||||
%22 = OpLoad %8 %5
|
||||
%23 = OpSLessThan %12 %22 %11
|
||||
OpBranchConditional %23 %24 %19
|
||||
%24 = OpLabel
|
||||
OpBranch %20
|
||||
%20 = OpLabel
|
||||
%25 = OpLoad %8 %5
|
||||
%26 = OpIAdd %8 %25 %13
|
||||
OpStore %5 %26
|
||||
OpBranch %18
|
||||
%19 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
// clang-format on
|
||||
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;
|
||||
const Function* f = spvtest::GetFunction(module, 2);
|
||||
LoopDescriptor& ld = *context->GetLoopDescriptor(f);
|
||||
|
||||
EXPECT_EQ(ld.NumLoops(), 1u);
|
||||
|
||||
Loop& loop = ld.GetLoopByIndex(0);
|
||||
EXPECT_EQ(loop.GetHeaderBlock(), spvtest::GetBasicBlock(f, 18));
|
||||
EXPECT_EQ(loop.GetLatchBlock(), spvtest::GetBasicBlock(f, 20));
|
||||
EXPECT_EQ(loop.GetMergeBlock(), spvtest::GetBasicBlock(f, 19));
|
||||
|
||||
EXPECT_FALSE(loop.HasNestedLoops());
|
||||
EXPECT_FALSE(loop.IsNested());
|
||||
EXPECT_EQ(loop.GetDepth(), 1u);
|
||||
}
|
||||
|
||||
/*
|
||||
Generated from the following GLSL:
|
||||
#version 330 core
|
||||
layout(location = 0) out vec4 c;
|
||||
void main() {
|
||||
for(int i = 0; i < 10; ++i) {}
|
||||
for(int i = 0; i < 10; ++i) {}
|
||||
}
|
||||
|
||||
But it was "hacked" to make the first loop merge block the second loop header.
|
||||
*/
|
||||
TEST_F(PassClassTest, LoopWithNoPreHeader) {
|
||||
const std::string text = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %2 "main" %3
|
||||
OpExecutionMode %2 OriginUpperLeft
|
||||
OpSource GLSL 330
|
||||
OpName %2 "main"
|
||||
OpName %4 "i"
|
||||
OpName %5 "i"
|
||||
OpName %3 "c"
|
||||
OpDecorate %3 Location 0
|
||||
%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 = OpTypeVector %14 4
|
||||
%16 = OpTypePointer Output %15
|
||||
%3 = OpVariable %16 Output
|
||||
%2 = OpFunction %6 None %7
|
||||
%17 = OpLabel
|
||||
%4 = OpVariable %9 Function
|
||||
%5 = OpVariable %9 Function
|
||||
OpStore %4 %10
|
||||
OpStore %5 %10
|
||||
OpBranch %18
|
||||
%18 = OpLabel
|
||||
OpLoopMerge %27 %20 None
|
||||
OpBranch %21
|
||||
%21 = OpLabel
|
||||
%22 = OpLoad %8 %4
|
||||
%23 = OpSLessThan %12 %22 %11
|
||||
OpBranchConditional %23 %24 %27
|
||||
%24 = OpLabel
|
||||
OpBranch %20
|
||||
%20 = OpLabel
|
||||
%25 = OpLoad %8 %4
|
||||
%26 = OpIAdd %8 %25 %13
|
||||
OpStore %4 %26
|
||||
OpBranch %18
|
||||
%27 = OpLabel
|
||||
OpLoopMerge %28 %29 None
|
||||
OpBranch %30
|
||||
%30 = OpLabel
|
||||
%31 = OpLoad %8 %5
|
||||
%32 = OpSLessThan %12 %31 %11
|
||||
OpBranchConditional %32 %33 %28
|
||||
%33 = OpLabel
|
||||
OpBranch %29
|
||||
%29 = OpLabel
|
||||
%34 = OpLoad %8 %5
|
||||
%35 = OpIAdd %8 %34 %13
|
||||
OpStore %5 %35
|
||||
OpBranch %27
|
||||
%28 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
// clang-format on
|
||||
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;
|
||||
const Function* f = spvtest::GetFunction(module, 2);
|
||||
LoopDescriptor& ld = *context->GetLoopDescriptor(f);
|
||||
|
||||
EXPECT_EQ(ld.NumLoops(), 2u);
|
||||
|
||||
Loop* loop = ld[27];
|
||||
EXPECT_EQ(loop->GetPreHeaderBlock(), nullptr);
|
||||
EXPECT_NE(loop->GetOrCreatePreHeaderBlock(), nullptr);
|
||||
}
|
||||
|
||||
/*
|
||||
Generated from the following GLSL + --eliminate-local-multi-store
|
||||
|
||||
#version 330 core
|
||||
in vec4 c;
|
||||
void main() {
|
||||
int i = 0;
|
||||
bool cond = c[0] == 0;
|
||||
for (; i < 10; i++) {
|
||||
if (cond) {
|
||||
return;
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
bool cond2 = i == 9;
|
||||
}
|
||||
*/
|
||||
TEST_F(PassClassTest, NoLoop) {
|
||||
const std::string text = R"(; SPIR-V
|
||||
; Version: 1.0
|
||||
; Generator: Khronos Glslang Reference Front End; 3
|
||||
; Bound: 47
|
||||
; Schema: 0
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main" %16
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource GLSL 330
|
||||
OpName %4 "main"
|
||||
OpName %16 "c"
|
||||
OpDecorate %16 Location 0
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 0
|
||||
%10 = OpTypeBool
|
||||
%11 = OpTypePointer Function %10
|
||||
%13 = OpTypeFloat 32
|
||||
%14 = OpTypeVector %13 4
|
||||
%15 = OpTypePointer Input %14
|
||||
%16 = OpVariable %15 Input
|
||||
%17 = OpTypeInt 32 0
|
||||
%18 = OpConstant %17 0
|
||||
%19 = OpTypePointer Input %13
|
||||
%22 = OpConstant %13 0
|
||||
%30 = OpConstant %6 10
|
||||
%39 = OpConstant %6 1
|
||||
%46 = OpUndef %6
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%20 = OpAccessChain %19 %16 %18
|
||||
%21 = OpLoad %13 %20
|
||||
%23 = OpFOrdEqual %10 %21 %22
|
||||
OpBranch %24
|
||||
%24 = OpLabel
|
||||
%45 = OpPhi %6 %9 %5 %40 %27
|
||||
OpLoopMerge %26 %27 None
|
||||
OpBranch %28
|
||||
%28 = OpLabel
|
||||
%31 = OpSLessThan %10 %45 %30
|
||||
OpBranchConditional %31 %25 %26
|
||||
%25 = OpLabel
|
||||
OpSelectionMerge %34 None
|
||||
OpBranchConditional %23 %33 %36
|
||||
%33 = OpLabel
|
||||
OpReturn
|
||||
%36 = OpLabel
|
||||
OpReturn
|
||||
%34 = OpLabel
|
||||
OpBranch %27
|
||||
%27 = OpLabel
|
||||
%40 = OpIAdd %6 %46 %39
|
||||
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;
|
||||
const Function* f = spvtest::GetFunction(module, 4);
|
||||
LoopDescriptor ld{context.get(), f};
|
||||
|
||||
EXPECT_EQ(ld.NumLoops(), 0u);
|
||||
}
|
||||
|
||||
/*
|
||||
Generated from following GLSL with latch block artificially inserted to be
|
||||
separate from continue.
|
||||
#version 430
|
||||
void main(void) {
|
||||
float x[10];
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
x[i] = i;
|
||||
}
|
||||
}
|
||||
*/
|
||||
TEST_F(PassClassTest, LoopLatchNotContinue) {
|
||||
const std::string text = 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 "x"
|
||||
%5 = OpTypeVoid
|
||||
%6 = OpTypeFunction %5
|
||||
%7 = OpTypeInt 32 1
|
||||
%8 = OpTypePointer Function %7
|
||||
%9 = OpConstant %7 0
|
||||
%10 = OpConstant %7 10
|
||||
%11 = OpTypeBool
|
||||
%12 = OpTypeFloat 32
|
||||
%13 = OpTypeInt 32 0
|
||||
%14 = OpConstant %13 10
|
||||
%15 = OpTypeArray %12 %14
|
||||
%16 = OpTypePointer Function %15
|
||||
%17 = OpTypePointer Function %12
|
||||
%18 = OpConstant %7 1
|
||||
%2 = OpFunction %5 None %6
|
||||
%19 = OpLabel
|
||||
%3 = OpVariable %8 Function
|
||||
%4 = OpVariable %16 Function
|
||||
OpStore %3 %9
|
||||
OpBranch %20
|
||||
%20 = OpLabel
|
||||
%21 = OpPhi %7 %9 %19 %22 %30
|
||||
OpLoopMerge %24 %23 None
|
||||
OpBranch %25
|
||||
%25 = OpLabel
|
||||
%26 = OpSLessThan %11 %21 %10
|
||||
OpBranchConditional %26 %27 %24
|
||||
%27 = OpLabel
|
||||
%28 = OpConvertSToF %12 %21
|
||||
%29 = OpAccessChain %17 %4 %21
|
||||
OpStore %29 %28
|
||||
OpBranch %23
|
||||
%23 = OpLabel
|
||||
%22 = OpIAdd %7 %21 %18
|
||||
OpStore %3 %22
|
||||
OpBranch %30
|
||||
%30 = OpLabel
|
||||
OpBranch %20
|
||||
%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;
|
||||
const Function* f = spvtest::GetFunction(module, 2);
|
||||
LoopDescriptor ld{context.get(), f};
|
||||
|
||||
EXPECT_EQ(ld.NumLoops(), 1u);
|
||||
|
||||
Loop& loop = ld.GetLoopByIndex(0u);
|
||||
|
||||
EXPECT_NE(loop.GetLatchBlock(), loop.GetContinueBlock());
|
||||
|
||||
EXPECT_EQ(loop.GetContinueBlock()->id(), 23u);
|
||||
EXPECT_EQ(loop.GetLatchBlock()->id(), 30u);
|
||||
}
|
||||
|
||||
TEST_F(PassClassTest, UnreachableMerge) {
|
||||
const std::string text = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %1 "main"
|
||||
OpExecutionMode %1 OriginUpperLeft
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%1 = OpFunction %void None %3
|
||||
%4 = OpLabel
|
||||
OpBranch %5
|
||||
%5 = OpLabel
|
||||
OpLoopMerge %6 %7 None
|
||||
OpBranch %8
|
||||
%8 = OpLabel
|
||||
OpBranch %9
|
||||
%9 = OpLabel
|
||||
OpBranch %7
|
||||
%7 = OpLabel
|
||||
OpBranch %5
|
||||
%6 = OpLabel
|
||||
OpUnreachable
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
std::unique_ptr<IRContext> context =
|
||||
BuildModule(SPV_ENV_UNIVERSAL_1_3, 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;
|
||||
const Function* f = spvtest::GetFunction(module, 1);
|
||||
LoopDescriptor ld{context.get(), f};
|
||||
|
||||
EXPECT_EQ(ld.NumLoops(), 1u);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,795 @@
|
||||
// Copyright (c) 2017 Google Inc.
|
||||
//
|
||||
// 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 <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "source/opt/iterator.h"
|
||||
#include "source/opt/loop_descriptor.h"
|
||||
#include "source/opt/pass.h"
|
||||
#include "source/opt/tree_iterator.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;
|
||||
|
||||
bool Validate(const std::vector<uint32_t>& bin) {
|
||||
spv_target_env target_env = SPV_ENV_UNIVERSAL_1_2;
|
||||
spv_context spvContext = spvContextCreate(target_env);
|
||||
spv_diagnostic diagnostic = nullptr;
|
||||
spv_const_binary_t binary = {bin.data(), bin.size()};
|
||||
spv_result_t error = spvValidate(spvContext, &binary, &diagnostic);
|
||||
if (error != 0) spvDiagnosticPrint(diagnostic);
|
||||
spvDiagnosticDestroy(diagnostic);
|
||||
spvContextDestroy(spvContext);
|
||||
return error == 0;
|
||||
}
|
||||
|
||||
using PassClassTest = PassTest<::testing::Test>;
|
||||
|
||||
/*
|
||||
Generated from the following GLSL
|
||||
#version 330 core
|
||||
layout(location = 0) out vec4 c;
|
||||
void main() {
|
||||
int i = 0;
|
||||
for (; i < 10; ++i) {
|
||||
int j = 0;
|
||||
int k = 0;
|
||||
for (; j < 11; ++j) {}
|
||||
for (; k < 12; ++k) {}
|
||||
}
|
||||
}
|
||||
*/
|
||||
TEST_F(PassClassTest, BasicVisitFromEntryPoint) {
|
||||
const std::string text = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %2 "main" %3
|
||||
OpExecutionMode %2 OriginUpperLeft
|
||||
OpSource GLSL 330
|
||||
OpName %2 "main"
|
||||
OpName %4 "i"
|
||||
OpName %5 "j"
|
||||
OpName %6 "k"
|
||||
OpName %3 "c"
|
||||
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 = OpConstant %9 11
|
||||
%15 = OpConstant %9 1
|
||||
%16 = OpConstant %9 12
|
||||
%17 = OpTypeFloat 32
|
||||
%18 = OpTypeVector %17 4
|
||||
%19 = OpTypePointer Output %18
|
||||
%3 = OpVariable %19 Output
|
||||
%2 = OpFunction %7 None %8
|
||||
%20 = OpLabel
|
||||
%4 = OpVariable %10 Function
|
||||
%5 = OpVariable %10 Function
|
||||
%6 = OpVariable %10 Function
|
||||
OpStore %4 %11
|
||||
OpBranch %21
|
||||
%21 = OpLabel
|
||||
OpLoopMerge %22 %23 None
|
||||
OpBranch %24
|
||||
%24 = OpLabel
|
||||
%25 = OpLoad %9 %4
|
||||
%26 = OpSLessThan %13 %25 %12
|
||||
OpBranchConditional %26 %27 %22
|
||||
%27 = OpLabel
|
||||
OpStore %5 %11
|
||||
OpStore %6 %11
|
||||
OpBranch %28
|
||||
%28 = OpLabel
|
||||
OpLoopMerge %29 %30 None
|
||||
OpBranch %31
|
||||
%31 = OpLabel
|
||||
%32 = OpLoad %9 %5
|
||||
%33 = OpSLessThan %13 %32 %14
|
||||
OpBranchConditional %33 %34 %29
|
||||
%34 = OpLabel
|
||||
OpBranch %30
|
||||
%30 = OpLabel
|
||||
%35 = OpLoad %9 %5
|
||||
%36 = OpIAdd %9 %35 %15
|
||||
OpStore %5 %36
|
||||
OpBranch %28
|
||||
%29 = OpLabel
|
||||
OpBranch %37
|
||||
%37 = OpLabel
|
||||
OpLoopMerge %38 %39 None
|
||||
OpBranch %40
|
||||
%40 = OpLabel
|
||||
%41 = OpLoad %9 %6
|
||||
%42 = OpSLessThan %13 %41 %16
|
||||
OpBranchConditional %42 %43 %38
|
||||
%43 = OpLabel
|
||||
OpBranch %39
|
||||
%39 = OpLabel
|
||||
%44 = OpLoad %9 %6
|
||||
%45 = OpIAdd %9 %44 %15
|
||||
OpStore %6 %45
|
||||
OpBranch %37
|
||||
%38 = OpLabel
|
||||
OpBranch %23
|
||||
%23 = OpLabel
|
||||
%46 = OpLoad %9 %4
|
||||
%47 = OpIAdd %9 %46 %15
|
||||
OpStore %4 %47
|
||||
OpBranch %21
|
||||
%22 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
// clang-format on
|
||||
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;
|
||||
const Function* f = spvtest::GetFunction(module, 2);
|
||||
LoopDescriptor& ld = *context->GetLoopDescriptor(f);
|
||||
|
||||
EXPECT_EQ(ld.NumLoops(), 3u);
|
||||
|
||||
// Invalid basic block id.
|
||||
EXPECT_EQ(ld[0u], nullptr);
|
||||
// Not a loop header.
|
||||
EXPECT_EQ(ld[20], nullptr);
|
||||
|
||||
Loop& parent_loop = *ld[21];
|
||||
EXPECT_TRUE(parent_loop.HasNestedLoops());
|
||||
EXPECT_FALSE(parent_loop.IsNested());
|
||||
EXPECT_EQ(parent_loop.GetDepth(), 1u);
|
||||
EXPECT_EQ(std::distance(parent_loop.begin(), parent_loop.end()), 2u);
|
||||
EXPECT_EQ(parent_loop.GetHeaderBlock(), spvtest::GetBasicBlock(f, 21));
|
||||
EXPECT_EQ(parent_loop.GetLatchBlock(), spvtest::GetBasicBlock(f, 23));
|
||||
EXPECT_EQ(parent_loop.GetMergeBlock(), spvtest::GetBasicBlock(f, 22));
|
||||
|
||||
Loop& child_loop_1 = *ld[28];
|
||||
EXPECT_FALSE(child_loop_1.HasNestedLoops());
|
||||
EXPECT_TRUE(child_loop_1.IsNested());
|
||||
EXPECT_EQ(child_loop_1.GetDepth(), 2u);
|
||||
EXPECT_EQ(std::distance(child_loop_1.begin(), child_loop_1.end()), 0u);
|
||||
EXPECT_EQ(child_loop_1.GetHeaderBlock(), spvtest::GetBasicBlock(f, 28));
|
||||
EXPECT_EQ(child_loop_1.GetLatchBlock(), spvtest::GetBasicBlock(f, 30));
|
||||
EXPECT_EQ(child_loop_1.GetMergeBlock(), spvtest::GetBasicBlock(f, 29));
|
||||
|
||||
Loop& child_loop_2 = *ld[37];
|
||||
EXPECT_FALSE(child_loop_2.HasNestedLoops());
|
||||
EXPECT_TRUE(child_loop_2.IsNested());
|
||||
EXPECT_EQ(child_loop_2.GetDepth(), 2u);
|
||||
EXPECT_EQ(std::distance(child_loop_2.begin(), child_loop_2.end()), 0u);
|
||||
EXPECT_EQ(child_loop_2.GetHeaderBlock(), spvtest::GetBasicBlock(f, 37));
|
||||
EXPECT_EQ(child_loop_2.GetLatchBlock(), spvtest::GetBasicBlock(f, 39));
|
||||
EXPECT_EQ(child_loop_2.GetMergeBlock(), spvtest::GetBasicBlock(f, 38));
|
||||
}
|
||||
|
||||
static void CheckLoopBlocks(Loop* loop,
|
||||
std::unordered_set<uint32_t>* expected_ids) {
|
||||
SCOPED_TRACE("Check loop " + std::to_string(loop->GetHeaderBlock()->id()));
|
||||
for (uint32_t bb_id : loop->GetBlocks()) {
|
||||
EXPECT_EQ(expected_ids->count(bb_id), 1u);
|
||||
expected_ids->erase(bb_id);
|
||||
}
|
||||
EXPECT_FALSE(loop->IsInsideLoop(loop->GetMergeBlock()));
|
||||
EXPECT_EQ(expected_ids->size(), 0u);
|
||||
}
|
||||
|
||||
/*
|
||||
Generated from the following GLSL
|
||||
#version 330 core
|
||||
layout(location = 0) out vec4 c;
|
||||
void main() {
|
||||
int i = 0;
|
||||
for (; i < 10; ++i) {
|
||||
for (int j = 0; j < 11; ++j) {
|
||||
if (j < 5) {
|
||||
for (int k = 0; k < 12; ++k) {}
|
||||
}
|
||||
else {}
|
||||
for (int k = 0; k < 12; ++k) {}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
TEST_F(PassClassTest, TripleNestedLoop) {
|
||||
const std::string text = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %2 "main" %3
|
||||
OpExecutionMode %2 OriginUpperLeft
|
||||
OpSource GLSL 330
|
||||
OpName %2 "main"
|
||||
OpName %4 "i"
|
||||
OpName %5 "j"
|
||||
OpName %6 "k"
|
||||
OpName %7 "k"
|
||||
OpName %3 "c"
|
||||
OpDecorate %3 Location 0
|
||||
%8 = OpTypeVoid
|
||||
%9 = OpTypeFunction %8
|
||||
%10 = OpTypeInt 32 1
|
||||
%11 = OpTypePointer Function %10
|
||||
%12 = OpConstant %10 0
|
||||
%13 = OpConstant %10 10
|
||||
%14 = OpTypeBool
|
||||
%15 = OpConstant %10 11
|
||||
%16 = OpConstant %10 5
|
||||
%17 = OpConstant %10 12
|
||||
%18 = OpConstant %10 1
|
||||
%19 = OpTypeFloat 32
|
||||
%20 = OpTypeVector %19 4
|
||||
%21 = OpTypePointer Output %20
|
||||
%3 = OpVariable %21 Output
|
||||
%2 = OpFunction %8 None %9
|
||||
%22 = OpLabel
|
||||
%4 = OpVariable %11 Function
|
||||
%5 = OpVariable %11 Function
|
||||
%6 = OpVariable %11 Function
|
||||
%7 = OpVariable %11 Function
|
||||
OpStore %4 %12
|
||||
OpBranch %23
|
||||
%23 = OpLabel
|
||||
OpLoopMerge %24 %25 None
|
||||
OpBranch %26
|
||||
%26 = OpLabel
|
||||
%27 = OpLoad %10 %4
|
||||
%28 = OpSLessThan %14 %27 %13
|
||||
OpBranchConditional %28 %29 %24
|
||||
%29 = OpLabel
|
||||
OpStore %5 %12
|
||||
OpBranch %30
|
||||
%30 = OpLabel
|
||||
OpLoopMerge %31 %32 None
|
||||
OpBranch %33
|
||||
%33 = OpLabel
|
||||
%34 = OpLoad %10 %5
|
||||
%35 = OpSLessThan %14 %34 %15
|
||||
OpBranchConditional %35 %36 %31
|
||||
%36 = OpLabel
|
||||
%37 = OpLoad %10 %5
|
||||
%38 = OpSLessThan %14 %37 %16
|
||||
OpSelectionMerge %39 None
|
||||
OpBranchConditional %38 %40 %39
|
||||
%40 = OpLabel
|
||||
OpStore %6 %12
|
||||
OpBranch %41
|
||||
%41 = OpLabel
|
||||
OpLoopMerge %42 %43 None
|
||||
OpBranch %44
|
||||
%44 = OpLabel
|
||||
%45 = OpLoad %10 %6
|
||||
%46 = OpSLessThan %14 %45 %17
|
||||
OpBranchConditional %46 %47 %42
|
||||
%47 = OpLabel
|
||||
OpBranch %43
|
||||
%43 = OpLabel
|
||||
%48 = OpLoad %10 %6
|
||||
%49 = OpIAdd %10 %48 %18
|
||||
OpStore %6 %49
|
||||
OpBranch %41
|
||||
%42 = OpLabel
|
||||
OpBranch %39
|
||||
%39 = OpLabel
|
||||
OpStore %7 %12
|
||||
OpBranch %50
|
||||
%50 = OpLabel
|
||||
OpLoopMerge %51 %52 None
|
||||
OpBranch %53
|
||||
%53 = OpLabel
|
||||
%54 = OpLoad %10 %7
|
||||
%55 = OpSLessThan %14 %54 %17
|
||||
OpBranchConditional %55 %56 %51
|
||||
%56 = OpLabel
|
||||
OpBranch %52
|
||||
%52 = OpLabel
|
||||
%57 = OpLoad %10 %7
|
||||
%58 = OpIAdd %10 %57 %18
|
||||
OpStore %7 %58
|
||||
OpBranch %50
|
||||
%51 = OpLabel
|
||||
OpBranch %32
|
||||
%32 = OpLabel
|
||||
%59 = OpLoad %10 %5
|
||||
%60 = OpIAdd %10 %59 %18
|
||||
OpStore %5 %60
|
||||
OpBranch %30
|
||||
%31 = OpLabel
|
||||
OpBranch %25
|
||||
%25 = OpLabel
|
||||
%61 = OpLoad %10 %4
|
||||
%62 = OpIAdd %10 %61 %18
|
||||
OpStore %4 %62
|
||||
OpBranch %23
|
||||
%24 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
// clang-format on
|
||||
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;
|
||||
const Function* f = spvtest::GetFunction(module, 2);
|
||||
LoopDescriptor& ld = *context->GetLoopDescriptor(f);
|
||||
|
||||
EXPECT_EQ(ld.NumLoops(), 4u);
|
||||
|
||||
// Invalid basic block id.
|
||||
EXPECT_EQ(ld[0u], nullptr);
|
||||
// Not in a loop.
|
||||
EXPECT_EQ(ld[22], nullptr);
|
||||
|
||||
// Check that we can map basic block to the correct loop.
|
||||
// The following block ids do not belong to a loop.
|
||||
for (uint32_t bb_id : {22, 24}) EXPECT_EQ(ld[bb_id], nullptr);
|
||||
|
||||
{
|
||||
std::unordered_set<uint32_t> basic_block_in_loop = {
|
||||
{23, 26, 29, 30, 33, 36, 40, 41, 44, 47, 43,
|
||||
42, 39, 50, 53, 56, 52, 51, 32, 31, 25}};
|
||||
Loop* loop = ld[23];
|
||||
CheckLoopBlocks(loop, &basic_block_in_loop);
|
||||
|
||||
EXPECT_TRUE(loop->HasNestedLoops());
|
||||
EXPECT_FALSE(loop->IsNested());
|
||||
EXPECT_EQ(loop->GetDepth(), 1u);
|
||||
EXPECT_EQ(std::distance(loop->begin(), loop->end()), 1u);
|
||||
EXPECT_EQ(loop->GetPreHeaderBlock(), spvtest::GetBasicBlock(f, 22));
|
||||
EXPECT_EQ(loop->GetHeaderBlock(), spvtest::GetBasicBlock(f, 23));
|
||||
EXPECT_EQ(loop->GetLatchBlock(), spvtest::GetBasicBlock(f, 25));
|
||||
EXPECT_EQ(loop->GetMergeBlock(), spvtest::GetBasicBlock(f, 24));
|
||||
EXPECT_FALSE(loop->IsInsideLoop(loop->GetMergeBlock()));
|
||||
EXPECT_FALSE(loop->IsInsideLoop(loop->GetPreHeaderBlock()));
|
||||
}
|
||||
|
||||
{
|
||||
std::unordered_set<uint32_t> basic_block_in_loop = {
|
||||
{30, 33, 36, 40, 41, 44, 47, 43, 42, 39, 50, 53, 56, 52, 51, 32}};
|
||||
Loop* loop = ld[30];
|
||||
CheckLoopBlocks(loop, &basic_block_in_loop);
|
||||
|
||||
EXPECT_TRUE(loop->HasNestedLoops());
|
||||
EXPECT_TRUE(loop->IsNested());
|
||||
EXPECT_EQ(loop->GetDepth(), 2u);
|
||||
EXPECT_EQ(std::distance(loop->begin(), loop->end()), 2u);
|
||||
EXPECT_EQ(loop->GetPreHeaderBlock(), spvtest::GetBasicBlock(f, 29));
|
||||
EXPECT_EQ(loop->GetHeaderBlock(), spvtest::GetBasicBlock(f, 30));
|
||||
EXPECT_EQ(loop->GetLatchBlock(), spvtest::GetBasicBlock(f, 32));
|
||||
EXPECT_EQ(loop->GetMergeBlock(), spvtest::GetBasicBlock(f, 31));
|
||||
EXPECT_FALSE(loop->IsInsideLoop(loop->GetMergeBlock()));
|
||||
EXPECT_FALSE(loop->IsInsideLoop(loop->GetPreHeaderBlock()));
|
||||
}
|
||||
|
||||
{
|
||||
std::unordered_set<uint32_t> basic_block_in_loop = {{41, 44, 47, 43}};
|
||||
Loop* loop = ld[41];
|
||||
CheckLoopBlocks(loop, &basic_block_in_loop);
|
||||
|
||||
EXPECT_FALSE(loop->HasNestedLoops());
|
||||
EXPECT_TRUE(loop->IsNested());
|
||||
EXPECT_EQ(loop->GetDepth(), 3u);
|
||||
EXPECT_EQ(std::distance(loop->begin(), loop->end()), 0u);
|
||||
EXPECT_EQ(loop->GetPreHeaderBlock(), spvtest::GetBasicBlock(f, 40));
|
||||
EXPECT_EQ(loop->GetHeaderBlock(), spvtest::GetBasicBlock(f, 41));
|
||||
EXPECT_EQ(loop->GetLatchBlock(), spvtest::GetBasicBlock(f, 43));
|
||||
EXPECT_EQ(loop->GetMergeBlock(), spvtest::GetBasicBlock(f, 42));
|
||||
EXPECT_FALSE(loop->IsInsideLoop(loop->GetMergeBlock()));
|
||||
EXPECT_FALSE(loop->IsInsideLoop(loop->GetPreHeaderBlock()));
|
||||
}
|
||||
|
||||
{
|
||||
std::unordered_set<uint32_t> basic_block_in_loop = {{50, 53, 56, 52}};
|
||||
Loop* loop = ld[50];
|
||||
CheckLoopBlocks(loop, &basic_block_in_loop);
|
||||
|
||||
EXPECT_FALSE(loop->HasNestedLoops());
|
||||
EXPECT_TRUE(loop->IsNested());
|
||||
EXPECT_EQ(loop->GetDepth(), 3u);
|
||||
EXPECT_EQ(std::distance(loop->begin(), loop->end()), 0u);
|
||||
EXPECT_EQ(loop->GetPreHeaderBlock(), spvtest::GetBasicBlock(f, 39));
|
||||
EXPECT_EQ(loop->GetHeaderBlock(), spvtest::GetBasicBlock(f, 50));
|
||||
EXPECT_EQ(loop->GetLatchBlock(), spvtest::GetBasicBlock(f, 52));
|
||||
EXPECT_EQ(loop->GetMergeBlock(), spvtest::GetBasicBlock(f, 51));
|
||||
EXPECT_FALSE(loop->IsInsideLoop(loop->GetMergeBlock()));
|
||||
EXPECT_FALSE(loop->IsInsideLoop(loop->GetPreHeaderBlock()));
|
||||
}
|
||||
|
||||
// Make sure LoopDescriptor gives us the inner most loop when we query for
|
||||
// loops.
|
||||
for (const BasicBlock& bb : *f) {
|
||||
if (Loop* loop = ld[&bb]) {
|
||||
for (Loop& sub_loop :
|
||||
make_range(++TreeDFIterator<Loop>(loop), TreeDFIterator<Loop>())) {
|
||||
EXPECT_FALSE(sub_loop.IsInsideLoop(bb.id()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Generated from the following GLSL
|
||||
#version 330 core
|
||||
layout(location = 0) out vec4 c;
|
||||
void main() {
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
for (int j = 0; j < 11; ++j) {
|
||||
for (int k = 0; k < 11; ++k) {}
|
||||
}
|
||||
for (int k = 0; k < 12; ++k) {}
|
||||
}
|
||||
}
|
||||
*/
|
||||
TEST_F(PassClassTest, LoopParentTest) {
|
||||
const std::string text = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %2 "main" %3
|
||||
OpExecutionMode %2 OriginUpperLeft
|
||||
OpSource GLSL 330
|
||||
OpName %2 "main"
|
||||
OpName %4 "i"
|
||||
OpName %5 "j"
|
||||
OpName %6 "k"
|
||||
OpName %7 "k"
|
||||
OpName %3 "c"
|
||||
OpDecorate %3 Location 0
|
||||
%8 = OpTypeVoid
|
||||
%9 = OpTypeFunction %8
|
||||
%10 = OpTypeInt 32 1
|
||||
%11 = OpTypePointer Function %10
|
||||
%12 = OpConstant %10 0
|
||||
%13 = OpConstant %10 10
|
||||
%14 = OpTypeBool
|
||||
%15 = OpConstant %10 11
|
||||
%16 = OpConstant %10 1
|
||||
%17 = OpConstant %10 12
|
||||
%18 = OpTypeFloat 32
|
||||
%19 = OpTypeVector %18 4
|
||||
%20 = OpTypePointer Output %19
|
||||
%3 = OpVariable %20 Output
|
||||
%2 = OpFunction %8 None %9
|
||||
%21 = OpLabel
|
||||
%4 = OpVariable %11 Function
|
||||
%5 = OpVariable %11 Function
|
||||
%6 = OpVariable %11 Function
|
||||
%7 = OpVariable %11 Function
|
||||
OpStore %4 %12
|
||||
OpBranch %22
|
||||
%22 = OpLabel
|
||||
OpLoopMerge %23 %24 None
|
||||
OpBranch %25
|
||||
%25 = OpLabel
|
||||
%26 = OpLoad %10 %4
|
||||
%27 = OpSLessThan %14 %26 %13
|
||||
OpBranchConditional %27 %28 %23
|
||||
%28 = OpLabel
|
||||
OpStore %5 %12
|
||||
OpBranch %29
|
||||
%29 = OpLabel
|
||||
OpLoopMerge %30 %31 None
|
||||
OpBranch %32
|
||||
%32 = OpLabel
|
||||
%33 = OpLoad %10 %5
|
||||
%34 = OpSLessThan %14 %33 %15
|
||||
OpBranchConditional %34 %35 %30
|
||||
%35 = OpLabel
|
||||
OpStore %6 %12
|
||||
OpBranch %36
|
||||
%36 = OpLabel
|
||||
OpLoopMerge %37 %38 None
|
||||
OpBranch %39
|
||||
%39 = OpLabel
|
||||
%40 = OpLoad %10 %6
|
||||
%41 = OpSLessThan %14 %40 %15
|
||||
OpBranchConditional %41 %42 %37
|
||||
%42 = OpLabel
|
||||
OpBranch %38
|
||||
%38 = OpLabel
|
||||
%43 = OpLoad %10 %6
|
||||
%44 = OpIAdd %10 %43 %16
|
||||
OpStore %6 %44
|
||||
OpBranch %36
|
||||
%37 = OpLabel
|
||||
OpBranch %31
|
||||
%31 = OpLabel
|
||||
%45 = OpLoad %10 %5
|
||||
%46 = OpIAdd %10 %45 %16
|
||||
OpStore %5 %46
|
||||
OpBranch %29
|
||||
%30 = OpLabel
|
||||
OpStore %7 %12
|
||||
OpBranch %47
|
||||
%47 = OpLabel
|
||||
OpLoopMerge %48 %49 None
|
||||
OpBranch %50
|
||||
%50 = OpLabel
|
||||
%51 = OpLoad %10 %7
|
||||
%52 = OpSLessThan %14 %51 %17
|
||||
OpBranchConditional %52 %53 %48
|
||||
%53 = OpLabel
|
||||
OpBranch %49
|
||||
%49 = OpLabel
|
||||
%54 = OpLoad %10 %7
|
||||
%55 = OpIAdd %10 %54 %16
|
||||
OpStore %7 %55
|
||||
OpBranch %47
|
||||
%48 = OpLabel
|
||||
OpBranch %24
|
||||
%24 = OpLabel
|
||||
%56 = OpLoad %10 %4
|
||||
%57 = OpIAdd %10 %56 %16
|
||||
OpStore %4 %57
|
||||
OpBranch %22
|
||||
%23 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
// clang-format on
|
||||
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;
|
||||
const Function* f = spvtest::GetFunction(module, 2);
|
||||
LoopDescriptor& ld = *context->GetLoopDescriptor(f);
|
||||
|
||||
EXPECT_EQ(ld.NumLoops(), 4u);
|
||||
|
||||
{
|
||||
Loop& loop = *ld[22];
|
||||
EXPECT_TRUE(loop.HasNestedLoops());
|
||||
EXPECT_FALSE(loop.IsNested());
|
||||
EXPECT_EQ(loop.GetDepth(), 1u);
|
||||
EXPECT_EQ(loop.GetParent(), nullptr);
|
||||
}
|
||||
|
||||
{
|
||||
Loop& loop = *ld[29];
|
||||
EXPECT_TRUE(loop.HasNestedLoops());
|
||||
EXPECT_TRUE(loop.IsNested());
|
||||
EXPECT_EQ(loop.GetDepth(), 2u);
|
||||
EXPECT_EQ(loop.GetParent(), ld[22]);
|
||||
}
|
||||
|
||||
{
|
||||
Loop& loop = *ld[36];
|
||||
EXPECT_FALSE(loop.HasNestedLoops());
|
||||
EXPECT_TRUE(loop.IsNested());
|
||||
EXPECT_EQ(loop.GetDepth(), 3u);
|
||||
EXPECT_EQ(loop.GetParent(), ld[29]);
|
||||
}
|
||||
|
||||
{
|
||||
Loop& loop = *ld[47];
|
||||
EXPECT_FALSE(loop.HasNestedLoops());
|
||||
EXPECT_TRUE(loop.IsNested());
|
||||
EXPECT_EQ(loop.GetDepth(), 2u);
|
||||
EXPECT_EQ(loop.GetParent(), ld[22]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Generated from the following GLSL + --eliminate-local-multi-store
|
||||
The preheader of loop %33 and %41 were removed as well.
|
||||
|
||||
#version 330 core
|
||||
void main() {
|
||||
int a = 0;
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
if (i == 0) {
|
||||
a = 1;
|
||||
} else {
|
||||
a = 2;
|
||||
}
|
||||
for (int j = 0; j < 11; ++j) {
|
||||
a++;
|
||||
}
|
||||
}
|
||||
for (int k = 0; k < 12; ++k) {}
|
||||
}
|
||||
*/
|
||||
TEST_F(PassClassTest, CreatePreheaderTest) {
|
||||
const std::string text = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %2 "main"
|
||||
OpExecutionMode %2 OriginUpperLeft
|
||||
OpSource GLSL 330
|
||||
OpName %2 "main"
|
||||
%3 = OpTypeVoid
|
||||
%4 = OpTypeFunction %3
|
||||
%5 = OpTypeInt 32 1
|
||||
%6 = OpTypePointer Function %5
|
||||
%7 = OpConstant %5 0
|
||||
%8 = OpConstant %5 10
|
||||
%9 = OpTypeBool
|
||||
%10 = OpConstant %5 1
|
||||
%11 = OpConstant %5 2
|
||||
%12 = OpConstant %5 11
|
||||
%13 = OpConstant %5 12
|
||||
%14 = OpUndef %5
|
||||
%2 = OpFunction %3 None %4
|
||||
%15 = OpLabel
|
||||
OpBranch %16
|
||||
%16 = OpLabel
|
||||
%17 = OpPhi %5 %7 %15 %18 %19
|
||||
%20 = OpPhi %5 %7 %15 %21 %19
|
||||
%22 = OpPhi %5 %14 %15 %23 %19
|
||||
OpLoopMerge %41 %19 None
|
||||
OpBranch %25
|
||||
%25 = OpLabel
|
||||
%26 = OpSLessThan %9 %20 %8
|
||||
OpBranchConditional %26 %27 %41
|
||||
%27 = OpLabel
|
||||
%28 = OpIEqual %9 %20 %7
|
||||
OpSelectionMerge %33 None
|
||||
OpBranchConditional %28 %30 %31
|
||||
%30 = OpLabel
|
||||
OpBranch %33
|
||||
%31 = OpLabel
|
||||
OpBranch %33
|
||||
%33 = OpLabel
|
||||
%18 = OpPhi %5 %10 %30 %11 %31 %34 %35
|
||||
%23 = OpPhi %5 %7 %30 %7 %31 %36 %35
|
||||
OpLoopMerge %37 %35 None
|
||||
OpBranch %38
|
||||
%38 = OpLabel
|
||||
%39 = OpSLessThan %9 %23 %12
|
||||
OpBranchConditional %39 %40 %37
|
||||
%40 = OpLabel
|
||||
%34 = OpIAdd %5 %18 %10
|
||||
OpBranch %35
|
||||
%35 = OpLabel
|
||||
%36 = OpIAdd %5 %23 %10
|
||||
OpBranch %33
|
||||
%37 = OpLabel
|
||||
OpBranch %19
|
||||
%19 = OpLabel
|
||||
%21 = OpIAdd %5 %20 %10
|
||||
OpBranch %16
|
||||
%41 = OpLabel
|
||||
%42 = OpPhi %5 %7 %25 %43 %44
|
||||
OpLoopMerge %45 %44 None
|
||||
OpBranch %46
|
||||
%46 = OpLabel
|
||||
%47 = OpSLessThan %9 %42 %13
|
||||
OpBranchConditional %47 %48 %45
|
||||
%48 = OpLabel
|
||||
OpBranch %44
|
||||
%44 = OpLabel
|
||||
%43 = OpIAdd %5 %42 %10
|
||||
OpBranch %41
|
||||
%45 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
// clang-format on
|
||||
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;
|
||||
const Function* f = spvtest::GetFunction(module, 2);
|
||||
LoopDescriptor& ld = *context->GetLoopDescriptor(f);
|
||||
// No invalidation of the cfg should occur during this test.
|
||||
CFG* cfg = context->cfg();
|
||||
|
||||
EXPECT_EQ(ld.NumLoops(), 3u);
|
||||
|
||||
{
|
||||
Loop& loop = *ld[16];
|
||||
EXPECT_TRUE(loop.HasNestedLoops());
|
||||
EXPECT_FALSE(loop.IsNested());
|
||||
EXPECT_EQ(loop.GetDepth(), 1u);
|
||||
EXPECT_EQ(loop.GetParent(), nullptr);
|
||||
}
|
||||
|
||||
{
|
||||
Loop& loop = *ld[33];
|
||||
EXPECT_EQ(loop.GetPreHeaderBlock(), nullptr);
|
||||
EXPECT_NE(loop.GetOrCreatePreHeaderBlock(), nullptr);
|
||||
// Make sure the loop descriptor was properly updated.
|
||||
EXPECT_EQ(ld[loop.GetPreHeaderBlock()], ld[16]);
|
||||
{
|
||||
const std::vector<uint32_t>& preds =
|
||||
cfg->preds(loop.GetPreHeaderBlock()->id());
|
||||
std::unordered_set<uint32_t> pred_set(preds.begin(), preds.end());
|
||||
EXPECT_EQ(pred_set.size(), 2u);
|
||||
EXPECT_TRUE(pred_set.count(30));
|
||||
EXPECT_TRUE(pred_set.count(31));
|
||||
// Check the phi instructions.
|
||||
loop.GetPreHeaderBlock()->ForEachPhiInst([&pred_set](Instruction* phi) {
|
||||
for (uint32_t i = 1; i < phi->NumInOperands(); i += 2) {
|
||||
EXPECT_TRUE(pred_set.count(phi->GetSingleWordInOperand(i)));
|
||||
}
|
||||
});
|
||||
}
|
||||
{
|
||||
const std::vector<uint32_t>& preds =
|
||||
cfg->preds(loop.GetHeaderBlock()->id());
|
||||
std::unordered_set<uint32_t> pred_set(preds.begin(), preds.end());
|
||||
EXPECT_EQ(pred_set.size(), 2u);
|
||||
EXPECT_TRUE(pred_set.count(loop.GetPreHeaderBlock()->id()));
|
||||
EXPECT_TRUE(pred_set.count(35));
|
||||
// Check the phi instructions.
|
||||
loop.GetHeaderBlock()->ForEachPhiInst([&pred_set](Instruction* phi) {
|
||||
for (uint32_t i = 1; i < phi->NumInOperands(); i += 2) {
|
||||
EXPECT_TRUE(pred_set.count(phi->GetSingleWordInOperand(i)));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Loop& loop = *ld[41];
|
||||
EXPECT_EQ(loop.GetPreHeaderBlock(), nullptr);
|
||||
EXPECT_NE(loop.GetOrCreatePreHeaderBlock(), nullptr);
|
||||
EXPECT_EQ(ld[loop.GetPreHeaderBlock()], nullptr);
|
||||
EXPECT_EQ(cfg->preds(loop.GetPreHeaderBlock()->id()).size(), 1u);
|
||||
EXPECT_EQ(cfg->preds(loop.GetPreHeaderBlock()->id())[0], 25u);
|
||||
// Check the phi instructions.
|
||||
loop.GetPreHeaderBlock()->ForEachPhiInst([](Instruction* phi) {
|
||||
EXPECT_EQ(phi->NumInOperands(), 2u);
|
||||
EXPECT_EQ(phi->GetSingleWordInOperand(1), 25u);
|
||||
});
|
||||
{
|
||||
const std::vector<uint32_t>& preds =
|
||||
cfg->preds(loop.GetHeaderBlock()->id());
|
||||
std::unordered_set<uint32_t> pred_set(preds.begin(), preds.end());
|
||||
EXPECT_EQ(pred_set.size(), 2u);
|
||||
EXPECT_TRUE(pred_set.count(loop.GetPreHeaderBlock()->id()));
|
||||
EXPECT_TRUE(pred_set.count(44));
|
||||
// Check the phi instructions.
|
||||
loop.GetHeaderBlock()->ForEachPhiInst([&pred_set](Instruction* phi) {
|
||||
for (uint32_t i = 1; i < phi->NumInOperands(); i += 2) {
|
||||
EXPECT_TRUE(pred_set.count(phi->GetSingleWordInOperand(i)));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure pre-header insertion leaves the module valid.
|
||||
std::vector<uint32_t> bin;
|
||||
context->module()->ToBinary(&bin, true);
|
||||
EXPECT_TRUE(Validate(bin));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
// Copyright (c) 2018 The Khronos Group Inc.
|
||||
//
|
||||
// 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 "pch_test_opt_loop.h"
|
||||
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) 2018 The Khronos Group Inc.
|
||||
//
|
||||
// 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 "gmock/gmock.h"
|
||||
#include "source/opt/iterator.h"
|
||||
#include "source/opt/loop_dependence.h"
|
||||
#include "source/opt/loop_descriptor.h"
|
||||
#include "source/opt/pass.h"
|
||||
#include "source/opt/scalar_analysis.h"
|
||||
#include "source/opt/tree_iterator.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"
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+1545
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,967 @@
|
||||
// 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 <string>
|
||||
|
||||
#include "effcee/effcee.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "test/opt/pass_fixture.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
namespace {
|
||||
|
||||
using UnswitchTest = PassTest<::testing::Test>;
|
||||
|
||||
/*
|
||||
Generated from the following GLSL + --eliminate-local-multi-store
|
||||
|
||||
#version 450 core
|
||||
uniform vec4 c;
|
||||
void main() {
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
bool cond = c[0] == 0;
|
||||
for (; i < 10; i++, j++) {
|
||||
if (cond) {
|
||||
i++;
|
||||
}
|
||||
else {
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
TEST_F(UnswitchTest, SimpleUnswitch) {
|
||||
const std::string text = R"(
|
||||
; CHECK: [[cst_cond:%\w+]] = OpFOrdEqual
|
||||
; CHECK-NEXT: OpSelectionMerge [[if_merge:%\w+]] None
|
||||
; CHECK-NEXT: OpBranchConditional [[cst_cond]] [[loop_t:%\w+]] [[loop_f:%\w+]]
|
||||
|
||||
; Loop specialized for false.
|
||||
; CHECK: [[loop_f]] = OpLabel
|
||||
; CHECK-NEXT: OpBranch [[loop:%\w+]]
|
||||
; CHECK: [[loop]] = OpLabel
|
||||
; CHECK-NEXT: [[phi_i:%\w+]] = OpPhi %int %int_0 [[loop_f]] [[iv_i:%\w+]] [[continue:%\w+]]
|
||||
; CHECK-NEXT: [[phi_j:%\w+]] = OpPhi %int %int_0 [[loop_f]] [[iv_j:%\w+]] [[continue]]
|
||||
; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
|
||||
; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_i]] {{%\w+}}
|
||||
; CHECK-NEXT: OpBranchConditional [[loop_exit]] [[loop_body:%\w+]] [[merge]]
|
||||
; [[loop_body]] = OpLabel
|
||||
; CHECK: OpSelectionMerge [[sel_merge:%\w+]] None
|
||||
; CHECK: OpBranchConditional %false [[bb1:%\w+]] [[bb2:%\w+]]
|
||||
; CHECK: [[bb2]] = OpLabel
|
||||
; CHECK-NEXT: [[inc_j:%\w+]] = OpIAdd %int [[phi_j]] %int_1
|
||||
; CHECK-NEXT: OpBranch [[sel_merge]]
|
||||
; CHECK: [[bb1]] = OpLabel
|
||||
; CHECK-NEXT: [[inc_i:%\w+]] = OpIAdd %int [[phi_i]] %int_1
|
||||
; CHECK-NEXT: OpBranch [[sel_merge]]
|
||||
; CHECK: [[sel_merge]] = OpLabel
|
||||
; CHECK: OpBranch [[if_merge]]
|
||||
|
||||
; Loop specialized for true.
|
||||
; CHECK: [[loop_t]] = OpLabel
|
||||
; CHECK-NEXT: OpBranch [[loop:%\w+]]
|
||||
; CHECK: [[loop]] = OpLabel
|
||||
; CHECK-NEXT: [[phi_i:%\w+]] = OpPhi %int %int_0 [[loop_t]] [[iv_i:%\w+]] [[continue:%\w+]]
|
||||
; CHECK-NEXT: [[phi_j:%\w+]] = OpPhi %int %int_0 [[loop_t]] [[iv_j:%\w+]] [[continue]]
|
||||
; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
|
||||
; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_i]] {{%\w+}}
|
||||
; CHECK-NEXT: OpBranchConditional [[loop_exit]] [[loop_body:%\w+]] [[merge]]
|
||||
; [[loop_body]] = OpLabel
|
||||
; CHECK: OpSelectionMerge [[sel_merge:%\w+]] None
|
||||
; CHECK: OpBranchConditional %true [[bb1:%\w+]] [[bb2:%\w+]]
|
||||
; CHECK: [[bb1]] = OpLabel
|
||||
; CHECK-NEXT: [[inc_i:%\w+]] = OpIAdd %int [[phi_i]] %int_1
|
||||
; CHECK-NEXT: OpBranch [[sel_merge]]
|
||||
; CHECK: [[bb2]] = OpLabel
|
||||
; CHECK-NEXT: [[inc_j:%\w+]] = OpIAdd %int [[phi_j]] %int_1
|
||||
; CHECK-NEXT: OpBranch [[sel_merge]]
|
||||
; CHECK: [[sel_merge]] = OpLabel
|
||||
; CHECK: OpBranch [[if_merge]]
|
||||
|
||||
; CHECK: [[if_merge]] = OpLabel
|
||||
; CHECK-NEXT: OpReturn
|
||||
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginLowerLeft
|
||||
OpSource GLSL 450
|
||||
OpName %main "main"
|
||||
OpName %c "c"
|
||||
OpDecorate %c Location 0
|
||||
OpDecorate %c DescriptorSet 0
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Function_int = OpTypePointer Function %int
|
||||
%int_0 = OpConstant %int 0
|
||||
%bool = OpTypeBool
|
||||
%_ptr_Function_bool = OpTypePointer Function %bool
|
||||
%float = OpTypeFloat 32
|
||||
%v4float = OpTypeVector %float 4
|
||||
%_ptr_UniformConstant_v4float = OpTypePointer UniformConstant %v4float
|
||||
%c = OpVariable %_ptr_UniformConstant_v4float UniformConstant
|
||||
%uint = OpTypeInt 32 0
|
||||
%uint_0 = OpConstant %uint 0
|
||||
%_ptr_UniformConstant_float = OpTypePointer UniformConstant %float
|
||||
%float_0 = OpConstant %float 0
|
||||
%int_10 = OpConstant %int 10
|
||||
%int_1 = OpConstant %int 1
|
||||
%main = OpFunction %void None %3
|
||||
%5 = OpLabel
|
||||
%21 = OpAccessChain %_ptr_UniformConstant_float %c %uint_0
|
||||
%22 = OpLoad %float %21
|
||||
%24 = OpFOrdEqual %bool %22 %float_0
|
||||
OpBranch %25
|
||||
%25 = OpLabel
|
||||
%46 = OpPhi %int %int_0 %5 %43 %28
|
||||
%47 = OpPhi %int %int_0 %5 %45 %28
|
||||
OpLoopMerge %27 %28 None
|
||||
OpBranch %29
|
||||
%29 = OpLabel
|
||||
%32 = OpSLessThan %bool %46 %int_10
|
||||
OpBranchConditional %32 %26 %27
|
||||
%26 = OpLabel
|
||||
OpSelectionMerge %35 None
|
||||
OpBranchConditional %24 %34 %39
|
||||
%34 = OpLabel
|
||||
%38 = OpIAdd %int %46 %int_1
|
||||
OpBranch %35
|
||||
%39 = OpLabel
|
||||
%41 = OpIAdd %int %47 %int_1
|
||||
OpBranch %35
|
||||
%35 = OpLabel
|
||||
%48 = OpPhi %int %38 %34 %46 %39
|
||||
%49 = OpPhi %int %47 %34 %41 %39
|
||||
OpBranch %28
|
||||
%28 = OpLabel
|
||||
%43 = OpIAdd %int %48 %int_1
|
||||
%45 = OpIAdd %int %49 %int_1
|
||||
OpBranch %25
|
||||
%27 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<LoopUnswitchPass>(text, true);
|
||||
}
|
||||
|
||||
/*
|
||||
Generated from the following GLSL + --eliminate-local-multi-store
|
||||
|
||||
#version 330 core
|
||||
in vec4 c;
|
||||
void main() {
|
||||
int i = 0;
|
||||
bool cond = c[0] == 0;
|
||||
for (; i < 10; i++) {
|
||||
if (cond) {
|
||||
i++;
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
TEST_F(UnswitchTest, UnswitchExit) {
|
||||
const std::string text = R"(
|
||||
; CHECK: [[cst_cond:%\w+]] = OpFOrdEqual
|
||||
; CHECK-NEXT: OpSelectionMerge [[if_merge:%\w+]] None
|
||||
; CHECK-NEXT: OpBranchConditional [[cst_cond]] [[loop_t:%\w+]] [[loop_f:%\w+]]
|
||||
|
||||
; Loop specialized for false.
|
||||
; CHECK: [[loop_f]] = OpLabel
|
||||
; CHECK: OpReturn
|
||||
|
||||
; Loop specialized for true.
|
||||
; CHECK: [[loop_t]] = OpLabel
|
||||
; CHECK-NEXT: OpBranch [[loop:%\w+]]
|
||||
; CHECK: [[loop]] = OpLabel
|
||||
; CHECK-NEXT: [[phi_i:%\w+]] = OpPhi %int %int_0 [[loop_t]] [[iv_i:%\w+]] [[continue:%\w+]]
|
||||
; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
|
||||
; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_i]] {{%\w+}}
|
||||
; CHECK-NEXT: OpBranchConditional [[loop_exit]] {{%\w+}} [[merge]]
|
||||
; Check that we have i+=2.
|
||||
; CHECK: [[phi_i:%\w+]] = OpIAdd %int [[phi_i]] %int_1
|
||||
; CHECK: [[iv_i]] = OpIAdd %int [[phi_i]] %int_1
|
||||
; CHECK: [[merge]] = OpLabel
|
||||
; CHECK-NEXT: OpBranch [[if_merge]]
|
||||
|
||||
; CHECK: [[if_merge]] = OpLabel
|
||||
; CHECK-NEXT: OpReturn
|
||||
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main" %c
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource GLSL 330
|
||||
OpName %main "main"
|
||||
OpName %c "c"
|
||||
OpDecorate %c Location 0
|
||||
OpDecorate %23 Uniform
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Function_int = OpTypePointer Function %int
|
||||
%int_0 = OpConstant %int 0
|
||||
%bool = OpTypeBool
|
||||
%_ptr_Function_bool = OpTypePointer Function %bool
|
||||
%float = OpTypeFloat 32
|
||||
%v4float = OpTypeVector %float 4
|
||||
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
||||
%c = OpVariable %_ptr_Input_v4float Input
|
||||
%uint = OpTypeInt 32 0
|
||||
%uint_0 = OpConstant %uint 0
|
||||
%_ptr_Input_float = OpTypePointer Input %float
|
||||
%float_0 = OpConstant %float 0
|
||||
%int_10 = OpConstant %int 10
|
||||
%int_1 = OpConstant %int 1
|
||||
%main = OpFunction %void None %3
|
||||
%5 = OpLabel
|
||||
%20 = OpAccessChain %_ptr_Input_float %c %uint_0
|
||||
%21 = OpLoad %float %20
|
||||
%23 = OpFOrdEqual %bool %21 %float_0
|
||||
OpBranch %24
|
||||
%24 = OpLabel
|
||||
%42 = OpPhi %int %int_0 %5 %41 %27
|
||||
OpLoopMerge %26 %27 None
|
||||
OpBranch %28
|
||||
%28 = OpLabel
|
||||
%31 = OpSLessThan %bool %42 %int_10
|
||||
OpBranchConditional %31 %25 %26
|
||||
%25 = OpLabel
|
||||
OpSelectionMerge %34 None
|
||||
OpBranchConditional %23 %33 %38
|
||||
%33 = OpLabel
|
||||
%37 = OpIAdd %int %42 %int_1
|
||||
OpBranch %34
|
||||
%38 = OpLabel
|
||||
OpReturn
|
||||
%34 = OpLabel
|
||||
OpBranch %27
|
||||
%27 = OpLabel
|
||||
%41 = OpIAdd %int %37 %int_1
|
||||
OpBranch %24
|
||||
%26 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<LoopUnswitchPass>(text, true);
|
||||
}
|
||||
|
||||
/*
|
||||
Generated from the following GLSL + --eliminate-local-multi-store
|
||||
|
||||
#version 330 core
|
||||
in vec4 c;
|
||||
void main() {
|
||||
int i = 0;
|
||||
bool cond = c[0] == 0;
|
||||
for (; i < 10; i++) {
|
||||
if (cond) {
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
TEST_F(UnswitchTest, UnswitchContinue) {
|
||||
const std::string text = R"(
|
||||
; CHECK: [[cst_cond:%\w+]] = OpFOrdEqual
|
||||
; CHECK-NEXT: OpSelectionMerge [[if_merge:%\w+]] None
|
||||
; CHECK-NEXT: OpBranchConditional [[cst_cond]] [[loop_t:%\w+]] [[loop_f:%\w+]]
|
||||
|
||||
; Loop specialized for false.
|
||||
; CHECK: [[loop_f]] = OpLabel
|
||||
; CHECK-NEXT: OpBranch [[loop:%\w+]]
|
||||
; CHECK: [[loop]] = OpLabel
|
||||
; CHECK-NEXT: [[phi_i:%\w+]] = OpPhi %int %int_0 [[loop_f]] [[iv_i:%\w+]] [[continue:%\w+]]
|
||||
; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
|
||||
; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_i]] {{%\w+}}
|
||||
; CHECK-NEXT: OpBranchConditional [[loop_exit]] [[loop_body:%\w+]] [[merge]]
|
||||
; CHECK: [[loop_body:%\w+]] = OpLabel
|
||||
; CHECK-NEXT: OpSelectionMerge
|
||||
; CHECK-NEXT: OpBranchConditional %false
|
||||
; CHECK: [[merge]] = OpLabel
|
||||
; CHECK-NEXT: OpBranch [[if_merge]]
|
||||
|
||||
; Loop specialized for true.
|
||||
; CHECK: [[loop_t]] = OpLabel
|
||||
; CHECK-NEXT: OpBranch [[loop:%\w+]]
|
||||
; CHECK: [[loop]] = OpLabel
|
||||
; CHECK-NEXT: [[phi_i:%\w+]] = OpPhi %int %int_0 [[loop_t]] [[iv_i:%\w+]] [[continue:%\w+]]
|
||||
; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
|
||||
; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_i]] {{%\w+}}
|
||||
; CHECK-NEXT: OpBranchConditional [[loop_exit]] [[loop_body:%\w+]] [[merge]]
|
||||
; CHECK: [[loop_body:%\w+]] = OpLabel
|
||||
; CHECK-NEXT: OpSelectionMerge
|
||||
; CHECK-NEXT: OpBranchConditional %true
|
||||
; CHECK: [[merge]] = OpLabel
|
||||
; CHECK-NEXT: OpBranch [[if_merge]]
|
||||
|
||||
; CHECK: [[if_merge]] = OpLabel
|
||||
; CHECK-NEXT: OpReturn
|
||||
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main" %c
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource GLSL 330
|
||||
OpName %main "main"
|
||||
OpName %c "c"
|
||||
OpDecorate %c Location 0
|
||||
OpDecorate %23 Uniform
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Function_int = OpTypePointer Function %int
|
||||
%int_0 = OpConstant %int 0
|
||||
%bool = OpTypeBool
|
||||
%_ptr_Function_bool = OpTypePointer Function %bool
|
||||
%float = OpTypeFloat 32
|
||||
%v4float = OpTypeVector %float 4
|
||||
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
||||
%c = OpVariable %_ptr_Input_v4float Input
|
||||
%uint = OpTypeInt 32 0
|
||||
%uint_0 = OpConstant %uint 0
|
||||
%_ptr_Input_float = OpTypePointer Input %float
|
||||
%float_0 = OpConstant %float 0
|
||||
%int_10 = OpConstant %int 10
|
||||
%int_1 = OpConstant %int 1
|
||||
%main = OpFunction %void None %3
|
||||
%5 = OpLabel
|
||||
%20 = OpAccessChain %_ptr_Input_float %c %uint_0
|
||||
%21 = OpLoad %float %20
|
||||
%23 = OpFOrdEqual %bool %21 %float_0
|
||||
OpBranch %24
|
||||
%24 = OpLabel
|
||||
%42 = OpPhi %int %int_0 %5 %41 %27
|
||||
OpLoopMerge %26 %27 None
|
||||
OpBranch %28
|
||||
%28 = OpLabel
|
||||
%31 = OpSLessThan %bool %42 %int_10
|
||||
OpBranchConditional %31 %25 %26
|
||||
%25 = OpLabel
|
||||
OpSelectionMerge %34 None
|
||||
OpBranchConditional %23 %33 %36
|
||||
%33 = OpLabel
|
||||
OpBranch %27
|
||||
%36 = OpLabel
|
||||
%39 = OpIAdd %int %42 %int_1
|
||||
OpBranch %34
|
||||
%34 = OpLabel
|
||||
OpBranch %27
|
||||
%27 = OpLabel
|
||||
%43 = OpPhi %int %42 %33 %39 %34
|
||||
%41 = OpIAdd %int %43 %int_1
|
||||
OpBranch %24
|
||||
%26 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<LoopUnswitchPass>(text, true);
|
||||
}
|
||||
|
||||
/*
|
||||
Generated from the following GLSL + --eliminate-local-multi-store
|
||||
|
||||
#version 330 core
|
||||
in vec4 c;
|
||||
void main() {
|
||||
int i = 0;
|
||||
bool cond = c[0] == 0;
|
||||
for (; i < 10; i++) {
|
||||
if (cond) {
|
||||
i++;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
TEST_F(UnswitchTest, UnswitchKillLoop) {
|
||||
const std::string text = R"(
|
||||
; CHECK: [[cst_cond:%\w+]] = OpFOrdEqual
|
||||
; CHECK-NEXT: OpSelectionMerge [[if_merge:%\w+]] None
|
||||
; CHECK-NEXT: OpBranchConditional [[cst_cond]] [[loop_t:%\w+]] [[loop_f:%\w+]]
|
||||
|
||||
; Loop specialized for false.
|
||||
; CHECK: [[loop_f]] = OpLabel
|
||||
; CHECK: OpBranch [[if_merge]]
|
||||
|
||||
; Loop specialized for true.
|
||||
; CHECK: [[loop_t]] = OpLabel
|
||||
; CHECK-NEXT: OpBranch [[loop:%\w+]]
|
||||
; CHECK: [[loop]] = OpLabel
|
||||
; CHECK-NEXT: [[phi_i:%\w+]] = OpPhi %int %int_0 [[loop_t]] [[iv_i:%\w+]] [[continue:%\w+]]
|
||||
; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
|
||||
; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_i]] {{%\w+}}
|
||||
; CHECK-NEXT: OpBranchConditional [[loop_exit]] {{%\w+}} [[merge]]
|
||||
; Check that we have i+=2.
|
||||
; CHECK: [[phi_i:%\w+]] = OpIAdd %int [[phi_i]] %int_1
|
||||
; CHECK: [[iv_i]] = OpIAdd %int [[phi_i]] %int_1
|
||||
; CHECK: [[merge]] = OpLabel
|
||||
; CHECK-NEXT: OpBranch [[if_merge]]
|
||||
|
||||
; CHECK: [[if_merge]] = OpLabel
|
||||
; CHECK-NEXT: OpReturn
|
||||
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main" %c
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource GLSL 330
|
||||
OpName %main "main"
|
||||
OpName %c "c"
|
||||
OpDecorate %c Location 0
|
||||
OpDecorate %23 Uniform
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Function_int = OpTypePointer Function %int
|
||||
%int_0 = OpConstant %int 0
|
||||
%bool = OpTypeBool
|
||||
%_ptr_Function_bool = OpTypePointer Function %bool
|
||||
%float = OpTypeFloat 32
|
||||
%v4float = OpTypeVector %float 4
|
||||
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
||||
%c = OpVariable %_ptr_Input_v4float Input
|
||||
%uint = OpTypeInt 32 0
|
||||
%uint_0 = OpConstant %uint 0
|
||||
%_ptr_Input_float = OpTypePointer Input %float
|
||||
%float_0 = OpConstant %float 0
|
||||
%int_10 = OpConstant %int 10
|
||||
%int_1 = OpConstant %int 1
|
||||
%main = OpFunction %void None %3
|
||||
%5 = OpLabel
|
||||
%20 = OpAccessChain %_ptr_Input_float %c %uint_0
|
||||
%21 = OpLoad %float %20
|
||||
%23 = OpFOrdEqual %bool %21 %float_0
|
||||
OpBranch %24
|
||||
%24 = OpLabel
|
||||
%42 = OpPhi %int %int_0 %5 %41 %27
|
||||
OpLoopMerge %26 %27 None
|
||||
OpBranch %28
|
||||
%28 = OpLabel
|
||||
%31 = OpSLessThan %bool %42 %int_10
|
||||
OpBranchConditional %31 %25 %26
|
||||
%25 = OpLabel
|
||||
OpSelectionMerge %34 None
|
||||
OpBranchConditional %23 %33 %38
|
||||
%33 = OpLabel
|
||||
%37 = OpIAdd %int %42 %int_1
|
||||
OpBranch %34
|
||||
%38 = OpLabel
|
||||
OpBranch %26
|
||||
%34 = OpLabel
|
||||
OpBranch %27
|
||||
%27 = OpLabel
|
||||
%41 = OpIAdd %int %37 %int_1
|
||||
OpBranch %24
|
||||
%26 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<LoopUnswitchPass>(text, true);
|
||||
}
|
||||
|
||||
/*
|
||||
Generated from the following GLSL + --eliminate-local-multi-store
|
||||
|
||||
#version 330 core
|
||||
in vec4 c;
|
||||
void main() {
|
||||
int i = 0;
|
||||
int cond = int(c[0]);
|
||||
for (; i < 10; i++) {
|
||||
switch (cond) {
|
||||
case 0:
|
||||
return;
|
||||
case 1:
|
||||
discard;
|
||||
case 2:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
bool cond2 = i == 9;
|
||||
}
|
||||
*/
|
||||
TEST_F(UnswitchTest, UnswitchSwitch) {
|
||||
const std::string text = R"(
|
||||
; CHECK: [[cst_cond:%\w+]] = OpConvertFToS
|
||||
; CHECK-NEXT: OpSelectionMerge [[if_merge:%\w+]] None
|
||||
; CHECK-NEXT: OpSwitch [[cst_cond]] [[default:%\w+]] 0 [[loop_0:%\w+]] 1 [[loop_1:%\w+]] 2 [[loop_2:%\w+]]
|
||||
|
||||
; Loop specialized for 2.
|
||||
; CHECK: [[loop_2]] = OpLabel
|
||||
; CHECK-NEXT: OpBranch [[loop:%\w+]]
|
||||
; CHECK: [[loop]] = OpLabel
|
||||
; CHECK-NEXT: [[phi_i:%\w+]] = OpPhi %int %int_0 [[loop_2]] [[iv_i:%\w+]] [[continue:%\w+]]
|
||||
; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
|
||||
; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_i]] {{%\w+}}
|
||||
; CHECK-NEXT: OpBranchConditional [[loop_exit]] [[loop_body:%\w+]] [[merge]]
|
||||
; CHECK: [[loop_body]] = OpLabel
|
||||
; CHECK-NEXT: OpSelectionMerge
|
||||
; CHECK-NEXT: OpSwitch %int_2
|
||||
; CHECK: [[merge]] = OpLabel
|
||||
; CHECK-NEXT: OpBranch [[if_merge]]
|
||||
|
||||
; Loop specialized for 1.
|
||||
; CHECK: [[loop_1]] = OpLabel
|
||||
; CHECK-NEXT: OpBranch [[loop:%\w+]]
|
||||
; CHECK: [[loop]] = OpLabel
|
||||
; CHECK-NEXT: [[phi_i:%\w+]] = OpPhi %int %int_0 [[loop_1]] [[iv_i:%\w+]] [[continue:%\w+]]
|
||||
; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
|
||||
; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_i]] {{%\w+}}
|
||||
; CHECK-NEXT: OpBranchConditional [[loop_exit]] [[loop_body:%\w+]] [[merge]]
|
||||
; CHECK: [[loop_body]] = OpLabel
|
||||
; CHECK-NEXT: OpSelectionMerge
|
||||
; CHECK-NEXT: OpSwitch %int_1
|
||||
; CHECK: [[merge]] = OpLabel
|
||||
; CHECK-NEXT: OpBranch [[if_merge]]
|
||||
|
||||
; Loop specialized for 0.
|
||||
; CHECK: [[loop_0]] = OpLabel
|
||||
; CHECK-NEXT: OpBranch [[loop:%\w+]]
|
||||
; CHECK: [[loop]] = OpLabel
|
||||
; CHECK-NEXT: [[phi_i:%\w+]] = OpPhi %int %int_0 [[loop_0]] [[iv_i:%\w+]] [[continue:%\w+]]
|
||||
; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
|
||||
; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_i]] {{%\w+}}
|
||||
; CHECK-NEXT: OpBranchConditional [[loop_exit]] [[loop_body:%\w+]] [[merge]]
|
||||
; CHECK: [[loop_body]] = OpLabel
|
||||
; CHECK-NEXT: OpSelectionMerge
|
||||
; CHECK-NEXT: OpSwitch %int_0
|
||||
; CHECK: [[merge]] = OpLabel
|
||||
; CHECK-NEXT: OpBranch [[if_merge]]
|
||||
|
||||
; Loop specialized for the default case.
|
||||
; CHECK: [[default]] = OpLabel
|
||||
; CHECK-NEXT: OpBranch [[loop:%\w+]]
|
||||
; CHECK: [[loop]] = OpLabel
|
||||
; CHECK-NEXT: [[phi_i:%\w+]] = OpPhi %int %int_0 [[default]] [[iv_i:%\w+]] [[continue:%\w+]]
|
||||
; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
|
||||
; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_i]] {{%\w+}}
|
||||
; CHECK-NEXT: OpBranchConditional [[loop_exit]] [[loop_body:%\w+]] [[merge]]
|
||||
; CHECK: [[loop_body]] = OpLabel
|
||||
; CHECK-NEXT: OpSelectionMerge
|
||||
; CHECK-NEXT: OpSwitch %uint_3
|
||||
; CHECK: [[merge]] = OpLabel
|
||||
; CHECK-NEXT: OpBranch [[if_merge]]
|
||||
|
||||
; CHECK: [[if_merge]] = OpLabel
|
||||
; CHECK-NEXT: OpReturn
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main" %c
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource GLSL 330
|
||||
OpName %main "main"
|
||||
OpName %c "c"
|
||||
OpDecorate %c Location 0
|
||||
OpDecorate %20 Uniform
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Function_int = OpTypePointer Function %int
|
||||
%int_0 = OpConstant %int 0
|
||||
%float = OpTypeFloat 32
|
||||
%v4float = OpTypeVector %float 4
|
||||
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
||||
%c = OpVariable %_ptr_Input_v4float Input
|
||||
%uint = OpTypeInt 32 0
|
||||
%uint_0 = OpConstant %uint 0
|
||||
%_ptr_Input_float = OpTypePointer Input %float
|
||||
%int_10 = OpConstant %int 10
|
||||
%bool = OpTypeBool
|
||||
%int_1 = OpConstant %int 1
|
||||
%_ptr_Function_bool = OpTypePointer Function %bool
|
||||
%main = OpFunction %void None %3
|
||||
%5 = OpLabel
|
||||
%18 = OpAccessChain %_ptr_Input_float %c %uint_0
|
||||
%19 = OpLoad %float %18
|
||||
%20 = OpConvertFToS %int %19
|
||||
OpBranch %21
|
||||
%21 = OpLabel
|
||||
%49 = OpPhi %int %int_0 %5 %43 %24
|
||||
OpLoopMerge %23 %24 None
|
||||
OpBranch %25
|
||||
%25 = OpLabel
|
||||
%29 = OpSLessThan %bool %49 %int_10
|
||||
OpBranchConditional %29 %22 %23
|
||||
%22 = OpLabel
|
||||
OpSelectionMerge %35 None
|
||||
OpSwitch %20 %34 0 %31 1 %32 2 %33
|
||||
%34 = OpLabel
|
||||
OpBranch %35
|
||||
%31 = OpLabel
|
||||
OpReturn
|
||||
%32 = OpLabel
|
||||
OpKill
|
||||
%33 = OpLabel
|
||||
OpBranch %35
|
||||
%35 = OpLabel
|
||||
OpBranch %24
|
||||
%24 = OpLabel
|
||||
%43 = OpIAdd %int %49 %int_1
|
||||
OpBranch %21
|
||||
%23 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<LoopUnswitchPass>(text, true);
|
||||
}
|
||||
|
||||
/*
|
||||
Generated from the following GLSL + --eliminate-local-multi-store
|
||||
|
||||
#version 440 core
|
||||
layout(location = 0)in vec4 c;
|
||||
void main() {
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int k = 0;
|
||||
bool cond = c[0] == 0;
|
||||
for (; i < 10; i++) {
|
||||
for (; j < 10; j++) {
|
||||
if (cond) {
|
||||
i++;
|
||||
} else {
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
TEST_F(UnswitchTest, UnSwitchNested) {
|
||||
// Test that an branch can be unswitched out of two nested loops.
|
||||
const std::string text = R"(
|
||||
; CHECK: [[cst_cond:%\w+]] = OpFOrdEqual
|
||||
; CHECK-NEXT: OpSelectionMerge [[if_merge:%\w+]] None
|
||||
; CHECK-NEXT: OpBranchConditional [[cst_cond]] [[loop_t:%\w+]] [[loop_f:%\w+]]
|
||||
|
||||
; Loop specialized for false
|
||||
; CHECK: [[loop_f]] = OpLabel
|
||||
; CHECK-NEXT: OpBranch [[loop:%\w+]]
|
||||
; CHECK: [[loop]] = OpLabel
|
||||
; CHECK-NEXT: {{%\w+}} = OpPhi %int %int_0 [[loop_f]] {{%\w+}} [[continue:%\w+]]
|
||||
; CHECK-NEXT: {{%\w+}} = OpPhi %int %int_0 [[loop_f]] {{%\w+}} [[continue]]
|
||||
; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
|
||||
; CHECK-NOT: [[merge]] = OpLabel
|
||||
; CHECK: OpLoopMerge
|
||||
; CHECK-NEXT: OpBranch [[bb1:%\w+]]
|
||||
; CHECK: [[bb1]] = OpLabel
|
||||
; CHECK-NEXT: OpSLessThan
|
||||
; CHECK-NEXT: OpBranchConditional {{%\w+}} [[bb2:%\w+]]
|
||||
; CHECK: [[bb2]] = OpLabel
|
||||
; CHECK-NEXT: OpSelectionMerge
|
||||
; CHECK-NEXT: OpBranchConditional %false
|
||||
; CHECK: [[merge]] = OpLabel
|
||||
|
||||
; Loop specialized for true. Same as first loop except the branch condition is true.
|
||||
; CHECK: [[loop_t]] = OpLabel
|
||||
; CHECK-NEXT: OpBranch [[loop:%\w+]]
|
||||
; CHECK: [[loop]] = OpLabel
|
||||
; CHECK-NEXT: {{%\w+}} = OpPhi %int %int_0 [[loop_t]] {{%\w+}} [[continue:%\w+]]
|
||||
; CHECK-NEXT: {{%\w+}} = OpPhi %int %int_0 [[loop_t]] {{%\w+}} [[continue]]
|
||||
; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
|
||||
; CHECK-NOT: [[merge]] = OpLabel
|
||||
; CHECK: OpLoopMerge
|
||||
; CHECK-NEXT: OpBranch [[bb1:%\w+]]
|
||||
; CHECK: [[bb1]] = OpLabel
|
||||
; CHECK-NEXT: OpSLessThan
|
||||
; CHECK-NEXT: OpBranchConditional {{%\w+}} [[bb2:%\w+]]
|
||||
; CHECK: [[bb2]] = OpLabel
|
||||
; CHECK-NEXT: OpSelectionMerge
|
||||
; CHECK-NEXT: OpBranchConditional %true
|
||||
; CHECK: [[merge]] = OpLabel
|
||||
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main" %c
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource GLSL 440
|
||||
OpName %main "main"
|
||||
OpName %c "c"
|
||||
OpDecorate %c Location 0
|
||||
OpDecorate %25 Uniform
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Function_int = OpTypePointer Function %int
|
||||
%int_0 = OpConstant %int 0
|
||||
%bool = OpTypeBool
|
||||
%_ptr_Function_bool = OpTypePointer Function %bool
|
||||
%float = OpTypeFloat 32
|
||||
%v4float = OpTypeVector %float 4
|
||||
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
||||
%c = OpVariable %_ptr_Input_v4float Input
|
||||
%uint = OpTypeInt 32 0
|
||||
%uint_0 = OpConstant %uint 0
|
||||
%_ptr_Input_float = OpTypePointer Input %float
|
||||
%float_0 = OpConstant %float 0
|
||||
%int_10 = OpConstant %int 10
|
||||
%int_1 = OpConstant %int 1
|
||||
%main = OpFunction %void None %3
|
||||
%5 = OpLabel
|
||||
%22 = OpAccessChain %_ptr_Input_float %c %uint_0
|
||||
%23 = OpLoad %float %22
|
||||
%25 = OpFOrdEqual %bool %23 %float_0
|
||||
OpBranch %26
|
||||
%26 = OpLabel
|
||||
%67 = OpPhi %int %int_0 %5 %52 %29
|
||||
%68 = OpPhi %int %int_0 %5 %70 %29
|
||||
OpLoopMerge %28 %29 None
|
||||
OpBranch %30
|
||||
%30 = OpLabel
|
||||
%33 = OpSLessThan %bool %67 %int_10
|
||||
OpBranchConditional %33 %27 %28
|
||||
%27 = OpLabel
|
||||
OpBranch %34
|
||||
%34 = OpLabel
|
||||
%69 = OpPhi %int %67 %27 %46 %37
|
||||
%70 = OpPhi %int %68 %27 %50 %37
|
||||
OpLoopMerge %36 %37 None
|
||||
OpBranch %38
|
||||
%38 = OpLabel
|
||||
%40 = OpSLessThan %bool %70 %int_10
|
||||
OpBranchConditional %40 %35 %36
|
||||
%35 = OpLabel
|
||||
OpSelectionMerge %43 None
|
||||
OpBranchConditional %25 %42 %47
|
||||
%42 = OpLabel
|
||||
%46 = OpIAdd %int %69 %int_1
|
||||
OpBranch %43
|
||||
%47 = OpLabel
|
||||
OpReturn
|
||||
%43 = OpLabel
|
||||
OpBranch %37
|
||||
%37 = OpLabel
|
||||
%50 = OpIAdd %int %70 %int_1
|
||||
OpBranch %34
|
||||
%36 = OpLabel
|
||||
OpBranch %29
|
||||
%29 = OpLabel
|
||||
%52 = OpIAdd %int %69 %int_1
|
||||
OpBranch %26
|
||||
%28 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<LoopUnswitchPass>(text, true);
|
||||
}
|
||||
|
||||
/*
|
||||
Generated from the following GLSL + --eliminate-local-multi-store
|
||||
|
||||
#version 330 core
|
||||
in vec4 c;
|
||||
void main() {
|
||||
bool cond = false;
|
||||
if (c[0] == 0) {
|
||||
cond = c[1] == 0;
|
||||
} else {
|
||||
cond = c[2] == 0;
|
||||
}
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (cond) {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
TEST_F(UnswitchTest, UnswitchNotUniform) {
|
||||
// Check that the unswitch is not triggered (condition loop invariant but not
|
||||
// uniform)
|
||||
const std::string text = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main" %c
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource GLSL 330
|
||||
OpName %main "main"
|
||||
OpName %c "c"
|
||||
OpDecorate %c Location 0
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%bool = OpTypeBool
|
||||
%_ptr_Function_bool = OpTypePointer Function %bool
|
||||
%float = OpTypeFloat 32
|
||||
%v4float = OpTypeVector %float 4
|
||||
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
||||
%c = OpVariable %_ptr_Input_v4float Input
|
||||
%uint = OpTypeInt 32 0
|
||||
%uint_0 = OpConstant %uint 0
|
||||
%_ptr_Input_float = OpTypePointer Input %float
|
||||
%float_0 = OpConstant %float 0
|
||||
%uint_1 = OpConstant %uint 1
|
||||
%uint_2 = OpConstant %uint 2
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Function_int = OpTypePointer Function %int
|
||||
%int_0 = OpConstant %int 0
|
||||
%int_10 = OpConstant %int 10
|
||||
%int_1 = OpConstant %int 1
|
||||
%main = OpFunction %void None %3
|
||||
%5 = OpLabel
|
||||
%17 = OpAccessChain %_ptr_Input_float %c %uint_0
|
||||
%18 = OpLoad %float %17
|
||||
%20 = OpFOrdEqual %bool %18 %float_0
|
||||
OpSelectionMerge %22 None
|
||||
OpBranchConditional %20 %21 %27
|
||||
%21 = OpLabel
|
||||
%24 = OpAccessChain %_ptr_Input_float %c %uint_1
|
||||
%25 = OpLoad %float %24
|
||||
%26 = OpFOrdEqual %bool %25 %float_0
|
||||
OpBranch %22
|
||||
%27 = OpLabel
|
||||
%29 = OpAccessChain %_ptr_Input_float %c %uint_2
|
||||
%30 = OpLoad %float %29
|
||||
%31 = OpFOrdEqual %bool %30 %float_0
|
||||
OpBranch %22
|
||||
%22 = OpLabel
|
||||
%52 = OpPhi %bool %26 %21 %31 %27
|
||||
OpBranch %36
|
||||
%36 = OpLabel
|
||||
%53 = OpPhi %int %int_0 %22 %51 %39
|
||||
OpLoopMerge %38 %39 None
|
||||
OpBranch %40
|
||||
%40 = OpLabel
|
||||
%43 = OpSLessThan %bool %53 %int_10
|
||||
OpBranchConditional %43 %37 %38
|
||||
%37 = OpLabel
|
||||
OpSelectionMerge %46 None
|
||||
OpBranchConditional %52 %45 %46
|
||||
%45 = OpLabel
|
||||
%49 = OpIAdd %int %53 %int_1
|
||||
OpBranch %46
|
||||
%46 = OpLabel
|
||||
%54 = OpPhi %int %53 %37 %49 %45
|
||||
OpBranch %39
|
||||
%39 = OpLabel
|
||||
%51 = OpIAdd %int %54 %int_1
|
||||
OpBranch %36
|
||||
%38 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
auto result =
|
||||
SinglePassRunAndDisassemble<LoopUnswitchPass>(text, true, false);
|
||||
|
||||
EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
|
||||
}
|
||||
|
||||
TEST_F(UnswitchTest, DontUnswitchLatch) {
|
||||
// Check that the unswitch is not triggered for the latch branch.
|
||||
const std::string text = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%bool = OpTypeBool
|
||||
%false = OpConstantFalse %bool
|
||||
%4 = OpFunction %void None %3
|
||||
%5 = OpLabel
|
||||
OpBranch %6
|
||||
%6 = OpLabel
|
||||
OpLoopMerge %8 %9 None
|
||||
OpBranch %7
|
||||
%7 = OpLabel
|
||||
OpBranch %9
|
||||
%9 = OpLabel
|
||||
OpBranchConditional %false %6 %8
|
||||
%8 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
auto result =
|
||||
SinglePassRunAndDisassemble<LoopUnswitchPass>(text, true, false);
|
||||
EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
|
||||
}
|
||||
|
||||
TEST_F(UnswitchTest, DontUnswitchConstantCondition) {
|
||||
const std::string text = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginLowerLeft
|
||||
OpSource GLSL 450
|
||||
OpName %main "main"
|
||||
%void = OpTypeVoid
|
||||
%4 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%int_0 = OpConstant %int 0
|
||||
%bool = OpTypeBool
|
||||
%true = OpConstantTrue %bool
|
||||
%int_1 = OpConstant %int 1
|
||||
%main = OpFunction %void None %4
|
||||
%10 = OpLabel
|
||||
OpBranch %11
|
||||
%11 = OpLabel
|
||||
%12 = OpPhi %int %int_0 %10 %13 %14
|
||||
OpLoopMerge %15 %14 None
|
||||
OpBranch %16
|
||||
%16 = OpLabel
|
||||
%17 = OpSLessThan %bool %12 %int_1
|
||||
OpBranchConditional %17 %18 %15
|
||||
%18 = OpLabel
|
||||
OpSelectionMerge %19 None
|
||||
OpBranchConditional %true %20 %19
|
||||
%20 = OpLabel
|
||||
%21 = OpIAdd %int %12 %int_1
|
||||
OpBranch %19
|
||||
%19 = OpLabel
|
||||
%22 = OpPhi %int %21 %20 %12 %18
|
||||
OpBranch %14
|
||||
%14 = OpLabel
|
||||
%13 = OpIAdd %int %22 %int_1
|
||||
OpBranch %11
|
||||
%15 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
auto result =
|
||||
SinglePassRunAndDisassemble<LoopUnswitchPass>(text, true, false);
|
||||
EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
||||
Reference in New Issue
Block a user