1// Copyright (c) 2018 Google LLC 2// 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 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 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. 14 15#include "source/reduce/operand_to_const_reduction_opportunity_finder.h" 16 17#include "source/opt/build_module.h" 18#include "source/reduce/reduction_opportunity.h" 19#include "test/reduce/reduce_test_util.h" 20 21namespace spvtools { 22namespace reduce { 23namespace { 24 25TEST(OperandToConstantReductionPassTest, BasicCheck) { 26 std::string prologue = R"( 27 OpCapability Shader 28 %1 = OpExtInstImport "GLSL.std.450" 29 OpMemoryModel Logical GLSL450 30 OpEntryPoint Fragment %4 "main" %37 31 OpExecutionMode %4 OriginUpperLeft 32 OpSource ESSL 310 33 OpName %4 "main" 34 OpName %9 "buf1" 35 OpMemberName %9 0 "f" 36 OpName %11 "" 37 OpName %24 "buf2" 38 OpMemberName %24 0 "i" 39 OpName %26 "" 40 OpName %37 "_GLF_color" 41 OpMemberDecorate %9 0 Offset 0 42 OpDecorate %9 Block 43 OpDecorate %11 DescriptorSet 0 44 OpDecorate %11 Binding 1 45 OpMemberDecorate %24 0 Offset 0 46 OpDecorate %24 Block 47 OpDecorate %26 DescriptorSet 0 48 OpDecorate %26 Binding 2 49 OpDecorate %37 Location 0 50 %2 = OpTypeVoid 51 %3 = OpTypeFunction %2 52 %6 = OpTypeFloat 32 53 %9 = OpTypeStruct %6 54 %10 = OpTypePointer Uniform %9 55 %11 = OpVariable %10 Uniform 56 %12 = OpTypeInt 32 1 57 %13 = OpConstant %12 0 58 %14 = OpTypePointer Uniform %6 59 %20 = OpConstant %6 2 60 %24 = OpTypeStruct %12 61 %25 = OpTypePointer Uniform %24 62 %26 = OpVariable %25 Uniform 63 %27 = OpTypePointer Uniform %12 64 %33 = OpConstant %12 3 65 %35 = OpTypeVector %6 4 66 %36 = OpTypePointer Output %35 67 %37 = OpVariable %36 Output 68 %4 = OpFunction %2 None %3 69 %5 = OpLabel 70 %15 = OpAccessChain %14 %11 %13 71 %16 = OpLoad %6 %15 72 %19 = OpFAdd %6 %16 %16 73 %21 = OpFAdd %6 %19 %20 74 %28 = OpAccessChain %27 %26 %13 75 %29 = OpLoad %12 %28 76 )"; 77 78 std::string epilogue = R"( 79 %45 = OpConvertSToF %6 %34 80 %46 = OpCompositeConstruct %35 %16 %21 %43 %45 81 OpStore %37 %46 82 OpReturn 83 OpFunctionEnd 84 )"; 85 86 std::string original = prologue + R"( 87 %32 = OpIAdd %12 %29 %29 88 %34 = OpIAdd %12 %32 %33 89 %43 = OpConvertSToF %6 %29 90 )" + epilogue; 91 92 std::string expected = prologue + R"( 93 %32 = OpIAdd %12 %13 %13 ; %29 -> %13 x 2 94 %34 = OpIAdd %12 %13 %33 ; %32 -> %13 95 %43 = OpConvertSToF %6 %13 ; %29 -> %13 96 )" + epilogue; 97 98 const auto env = SPV_ENV_UNIVERSAL_1_3; 99 const auto consumer = nullptr; 100 const auto context = 101 BuildModule(env, consumer, original, kReduceAssembleOption); 102 const auto ops = 103 OperandToConstReductionOpportunityFinder().GetAvailableOpportunities( 104 context.get(), 0); 105 ASSERT_EQ(17, ops.size()); 106 ASSERT_TRUE(ops[0]->PreconditionHolds()); 107 ops[0]->TryToApply(); 108 ASSERT_TRUE(ops[1]->PreconditionHolds()); 109 ops[1]->TryToApply(); 110 ASSERT_TRUE(ops[2]->PreconditionHolds()); 111 ops[2]->TryToApply(); 112 ASSERT_TRUE(ops[3]->PreconditionHolds()); 113 ops[3]->TryToApply(); 114 115 CheckEqual(env, expected, context.get()); 116} 117 118TEST(OperandToConstantReductionPassTest, WithCalledFunction) { 119 std::string shader = R"( 120 OpCapability Shader 121 %1 = OpExtInstImport "GLSL.std.450" 122 OpMemoryModel Logical GLSL450 123 OpEntryPoint Fragment %4 "main" %10 %12 124 OpExecutionMode %4 OriginUpperLeft 125 OpSource ESSL 310 126 %2 = OpTypeVoid 127 %3 = OpTypeFunction %2 128 %6 = OpTypeFloat 32 129 %7 = OpTypeVector %6 4 130 %8 = OpTypeFunction %7 131 %9 = OpTypePointer Output %7 132 %10 = OpVariable %9 Output 133 %11 = OpTypePointer Input %7 134 %12 = OpVariable %11 Input 135 %13 = OpConstant %6 0 136 %14 = OpConstantComposite %7 %13 %13 %13 %13 137 %4 = OpFunction %2 None %3 138 %5 = OpLabel 139 %15 = OpFunctionCall %7 %16 140 OpReturn 141 OpFunctionEnd 142 %16 = OpFunction %7 None %8 143 %17 = OpLabel 144 OpReturnValue %14 145 OpFunctionEnd 146 )"; 147 148 const auto env = SPV_ENV_UNIVERSAL_1_3; 149 const auto consumer = nullptr; 150 const auto context = 151 BuildModule(env, consumer, shader, kReduceAssembleOption); 152 const auto ops = 153 OperandToConstReductionOpportunityFinder().GetAvailableOpportunities( 154 context.get(), 0); 155 ASSERT_EQ(0, ops.size()); 156} 157 158TEST(OperandToConstantReductionPassTest, TargetSpecificFunction) { 159 std::string shader = R"( 160 OpCapability Shader 161 %1 = OpExtInstImport "GLSL.std.450" 162 OpMemoryModel Logical GLSL450 163 OpEntryPoint Fragment %4 "main" 164 OpExecutionMode %4 OriginUpperLeft 165 OpSource ESSL 320 166 %2 = OpTypeVoid 167 %3 = OpTypeFunction %2 168 %6 = OpTypeInt 32 1 169 %7 = OpTypePointer Function %6 170 %8 = OpTypeFunction %6 %7 171 %17 = OpConstant %6 1 172 %20 = OpConstant %6 2 173 %23 = OpConstant %6 0 174 %24 = OpTypeBool 175 %35 = OpConstant %6 3 176 %53 = OpConstant %6 10 177 %4 = OpFunction %2 None %3 178 %5 = OpLabel 179 %65 = OpVariable %7 Function 180 %68 = OpVariable %7 Function 181 %73 = OpVariable %7 Function 182 OpStore %65 %35 183 %66 = OpLoad %6 %65 184 %67 = OpIAdd %6 %66 %17 185 OpStore %65 %67 186 %69 = OpLoad %6 %65 187 OpStore %68 %69 188 %70 = OpFunctionCall %6 %13 %68 189 %71 = OpLoad %6 %65 190 %72 = OpIAdd %6 %71 %70 191 OpStore %65 %72 192 %74 = OpLoad %6 %65 193 OpStore %73 %74 194 %75 = OpFunctionCall %6 %10 %73 195 %76 = OpLoad %6 %65 196 %77 = OpIAdd %6 %76 %75 197 OpStore %65 %77 198 OpReturn 199 OpFunctionEnd 200 %10 = OpFunction %6 None %8 201 %9 = OpFunctionParameter %7 202 %11 = OpLabel 203 %15 = OpVariable %7 Function 204 %16 = OpLoad %6 %9 205 %18 = OpIAdd %6 %16 %17 206 OpStore %15 %18 207 %19 = OpLoad %6 %15 208 %21 = OpIAdd %6 %19 %20 209 OpStore %15 %21 210 %22 = OpLoad %6 %15 211 %25 = OpSGreaterThan %24 %22 %23 212 OpSelectionMerge %27 None 213 OpBranchConditional %25 %26 %27 214 %26 = OpLabel 215 %28 = OpLoad %6 %9 216 OpReturnValue %28 217 %27 = OpLabel 218 %30 = OpLoad %6 %9 219 %31 = OpIAdd %6 %30 %17 220 OpReturnValue %31 221 OpFunctionEnd 222 %13 = OpFunction %6 None %8 223 %12 = OpFunctionParameter %7 224 %14 = OpLabel 225 %41 = OpVariable %7 Function 226 %46 = OpVariable %7 Function 227 %55 = OpVariable %7 Function 228 %34 = OpLoad %6 %12 229 %36 = OpIEqual %24 %34 %35 230 OpSelectionMerge %38 None 231 OpBranchConditional %36 %37 %38 232 %37 = OpLabel 233 %39 = OpLoad %6 %12 234 %40 = OpIMul %6 %20 %39 235 OpStore %41 %40 236 %42 = OpFunctionCall %6 %10 %41 237 OpReturnValue %42 238 %38 = OpLabel 239 %44 = OpLoad %6 %12 240 %45 = OpIAdd %6 %44 %17 241 OpStore %12 %45 242 OpStore %46 %23 243 OpBranch %47 244 %47 = OpLabel 245 OpLoopMerge %49 %50 None 246 OpBranch %51 247 %51 = OpLabel 248 %52 = OpLoad %6 %46 249 %54 = OpSLessThan %24 %52 %53 250 OpBranchConditional %54 %48 %49 251 %48 = OpLabel 252 %56 = OpLoad %6 %12 253 OpStore %55 %56 254 %57 = OpFunctionCall %6 %10 %55 255 %58 = OpLoad %6 %12 256 %59 = OpIAdd %6 %58 %57 257 OpStore %12 %59 258 OpBranch %50 259 %50 = OpLabel 260 %60 = OpLoad %6 %46 261 %61 = OpIAdd %6 %60 %17 262 OpStore %46 %61 263 OpBranch %47 264 %49 = OpLabel 265 %62 = OpLoad %6 %12 266 OpReturnValue %62 267 OpFunctionEnd 268 )"; 269 270 const auto env = SPV_ENV_UNIVERSAL_1_3; 271 const auto consumer = nullptr; 272 const auto context = 273 BuildModule(env, consumer, shader, kReduceAssembleOption); 274 275 // Targeting all functions, there are quite a few opportunities. To avoid 276 // making the test too sensitive, we check that there are more than a number 277 // somewhat lower than the real number. 278 const auto all_ops = 279 OperandToConstReductionOpportunityFinder().GetAvailableOpportunities( 280 context.get(), 0); 281 ASSERT_TRUE(all_ops.size() > 100); 282 283 // Targeting individual functions, there are fewer opportunities. Again, we 284 // avoid checking against an exact number so that the test is not too 285 // sensitive. 286 const auto ops_for_function_4 = 287 OperandToConstReductionOpportunityFinder().GetAvailableOpportunities( 288 context.get(), 4); 289 const auto ops_for_function_10 = 290 OperandToConstReductionOpportunityFinder().GetAvailableOpportunities( 291 context.get(), 10); 292 const auto ops_for_function_13 = 293 OperandToConstReductionOpportunityFinder().GetAvailableOpportunities( 294 context.get(), 13); 295 ASSERT_TRUE(ops_for_function_4.size() < 60); 296 ASSERT_TRUE(ops_for_function_10.size() < 50); 297 ASSERT_TRUE(ops_for_function_13.size() < 80); 298 299 // The total number of opportunities should be the sum of the per-function 300 // opportunities. 301 ASSERT_EQ(all_ops.size(), ops_for_function_4.size() + 302 ops_for_function_10.size() + 303 ops_for_function_13.size()); 304} 305 306} // namespace 307} // namespace reduce 308} // namespace spvtools 309