1 // Copyright (c) 2018 Google LLC.
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
17 #include <gmock/gmock.h>
19 #include "../pass_fixture.h"
20 #include "opt/licm_pass.h"
24 using namespace spvtools;
25 using ::testing::UnorderedElementsAre;
27 using PassClassTest = PassTest<::testing::Test>;
30 Tests that the LICM pass will detect an move an invariant from a nested loop,
31 but not it's parent loop
33 Generated from the following GLSL fragment shader
34 --eliminate-local-multi-store has also been run on the spv binary
39 for (int i = 0; i < 10; i++) {
40 for (int j = 0; j < 10; j++) {
41 // hoist 'hoist = a - i' out of j loop, but not i loop
47 TEST_F(PassClassTest, NestedSingleHoist) {
48 const std::string before_hoist = R"(OpCapability Shader
49 %1 = OpExtInstImport "GLSL.std.450"
50 OpMemoryModel Logical GLSL450
51 OpEntryPoint Fragment %main "main"
52 OpExecutionMode %main OriginUpperLeft
56 %4 = OpTypeFunction %void
58 %_ptr_Function_int = OpTypePointer Function %int
59 %int_2 = OpConstant %int 2
60 %int_0 = OpConstant %int 0
61 %int_10 = OpConstant %int 10
63 %int_1 = OpConstant %int 1
65 %main = OpFunction %void None %4
69 %15 = OpPhi %int %int_0 %13 %16 %17
70 %18 = OpPhi %int %int_0 %13 %19 %17
71 %20 = OpPhi %int %12 %13 %21 %17
72 OpLoopMerge %22 %17 None
75 %24 = OpSLessThan %bool %18 %int_10
76 OpBranchConditional %24 %25 %22
80 %16 = OpPhi %int %15 %25 %27 %28
81 %21 = OpPhi %int %int_0 %25 %29 %28
82 OpLoopMerge %30 %28 None
85 %32 = OpSLessThan %bool %21 %int_10
86 OpBranchConditional %32 %33 %30
88 %27 = OpISub %int %int_2 %18
91 %29 = OpIAdd %int %21 %int_1
96 %19 = OpIAdd %int %18 %int_1
103 const std::string after_hoist = R"(OpCapability Shader
104 %1 = OpExtInstImport "GLSL.std.450"
105 OpMemoryModel Logical GLSL450
106 OpEntryPoint Fragment %main "main"
107 OpExecutionMode %main OriginUpperLeft
111 %4 = OpTypeFunction %void
112 %int = OpTypeInt 32 1
113 %_ptr_Function_int = OpTypePointer Function %int
114 %int_2 = OpConstant %int 2
115 %int_0 = OpConstant %int 0
116 %int_10 = OpConstant %int 10
118 %int_1 = OpConstant %int 1
120 %main = OpFunction %void None %4
124 %15 = OpPhi %int %int_0 %13 %16 %17
125 %18 = OpPhi %int %int_0 %13 %19 %17
126 %20 = OpPhi %int %12 %13 %21 %17
127 OpLoopMerge %22 %17 None
130 %24 = OpSLessThan %bool %18 %int_10
131 OpBranchConditional %24 %25 %22
133 %27 = OpISub %int %int_2 %18
136 %16 = OpPhi %int %15 %25 %27 %28
137 %21 = OpPhi %int %int_0 %25 %29 %28
138 OpLoopMerge %30 %28 None
141 %32 = OpSLessThan %bool %21 %int_10
142 OpBranchConditional %32 %33 %30
146 %29 = OpIAdd %int %21 %int_1
151 %19 = OpIAdd %int %18 %int_1
158 SinglePassRunAndCheck<opt::LICMPass>(before_hoist, after_hoist, true);