1fd4e5da5Sopenharmony_ci// Copyright (c) 2019 Google LLC 2fd4e5da5Sopenharmony_ci// 3fd4e5da5Sopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License"); 4fd4e5da5Sopenharmony_ci// you may not use this file except in compliance with the License. 5fd4e5da5Sopenharmony_ci// You may obtain a copy of the License at 6fd4e5da5Sopenharmony_ci// 7fd4e5da5Sopenharmony_ci// http://www.apache.org/licenses/LICENSE-2.0 8fd4e5da5Sopenharmony_ci// 9fd4e5da5Sopenharmony_ci// Unless required by applicable law or agreed to in writing, software 10fd4e5da5Sopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS, 11fd4e5da5Sopenharmony_ci// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12fd4e5da5Sopenharmony_ci// See the License for the specific language governing permissions and 13fd4e5da5Sopenharmony_ci// limitations under the License. 14fd4e5da5Sopenharmony_ci 15fd4e5da5Sopenharmony_ci#include "source/reduce/remove_function_reduction_opportunity_finder.h" 16fd4e5da5Sopenharmony_ci 17fd4e5da5Sopenharmony_ci#include "source/opt/build_module.h" 18fd4e5da5Sopenharmony_ci#include "source/reduce/reduction_opportunity.h" 19fd4e5da5Sopenharmony_ci#include "test/reduce/reduce_test_util.h" 20fd4e5da5Sopenharmony_ci 21fd4e5da5Sopenharmony_cinamespace spvtools { 22fd4e5da5Sopenharmony_cinamespace reduce { 23fd4e5da5Sopenharmony_cinamespace { 24fd4e5da5Sopenharmony_ci 25fd4e5da5Sopenharmony_ci// Helper to count the number of functions in the module. 26fd4e5da5Sopenharmony_ci// Remove if there turns out to be a more direct way to do this. 27fd4e5da5Sopenharmony_ciuint32_t count_functions(opt::IRContext* context) { 28fd4e5da5Sopenharmony_ci uint32_t result = 0; 29fd4e5da5Sopenharmony_ci for (auto& function : *context->module()) { 30fd4e5da5Sopenharmony_ci (void)(function); 31fd4e5da5Sopenharmony_ci ++result; 32fd4e5da5Sopenharmony_ci } 33fd4e5da5Sopenharmony_ci return result; 34fd4e5da5Sopenharmony_ci} 35fd4e5da5Sopenharmony_ci 36fd4e5da5Sopenharmony_ciTEST(RemoveFunctionTest, BasicCheck) { 37fd4e5da5Sopenharmony_ci std::string shader = R"( 38fd4e5da5Sopenharmony_ci OpCapability Shader 39fd4e5da5Sopenharmony_ci %1 = OpExtInstImport "GLSL.std.450" 40fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 41fd4e5da5Sopenharmony_ci OpEntryPoint Fragment %4 "main" 42fd4e5da5Sopenharmony_ci OpExecutionMode %4 OriginUpperLeft 43fd4e5da5Sopenharmony_ci OpSource ESSL 310 44fd4e5da5Sopenharmony_ci %2 = OpTypeVoid 45fd4e5da5Sopenharmony_ci %3 = OpTypeFunction %2 46fd4e5da5Sopenharmony_ci %4 = OpFunction %2 None %3 47fd4e5da5Sopenharmony_ci %5 = OpLabel 48fd4e5da5Sopenharmony_ci OpReturn 49fd4e5da5Sopenharmony_ci OpFunctionEnd 50fd4e5da5Sopenharmony_ci %6 = OpFunction %2 None %3 51fd4e5da5Sopenharmony_ci %7 = OpLabel 52fd4e5da5Sopenharmony_ci OpReturn 53fd4e5da5Sopenharmony_ci OpFunctionEnd 54fd4e5da5Sopenharmony_ci %8 = OpFunction %2 None %3 55fd4e5da5Sopenharmony_ci %9 = OpLabel 56fd4e5da5Sopenharmony_ci %10 = OpFunctionCall %2 %6 57fd4e5da5Sopenharmony_ci OpReturn 58fd4e5da5Sopenharmony_ci OpFunctionEnd 59fd4e5da5Sopenharmony_ci )"; 60fd4e5da5Sopenharmony_ci 61fd4e5da5Sopenharmony_ci const auto env = SPV_ENV_UNIVERSAL_1_3; 62fd4e5da5Sopenharmony_ci const auto consumer = nullptr; 63fd4e5da5Sopenharmony_ci const auto context = 64fd4e5da5Sopenharmony_ci BuildModule(env, consumer, shader, kReduceAssembleOption); 65fd4e5da5Sopenharmony_ci 66fd4e5da5Sopenharmony_ci ASSERT_EQ(3, count_functions(context.get())); 67fd4e5da5Sopenharmony_ci 68fd4e5da5Sopenharmony_ci auto ops = 69fd4e5da5Sopenharmony_ci RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities( 70fd4e5da5Sopenharmony_ci context.get(), 0); 71fd4e5da5Sopenharmony_ci ASSERT_EQ(1, ops.size()); 72fd4e5da5Sopenharmony_ci 73fd4e5da5Sopenharmony_ci ASSERT_TRUE(ops[0]->PreconditionHolds()); 74fd4e5da5Sopenharmony_ci ops[0]->TryToApply(); 75fd4e5da5Sopenharmony_ci 76fd4e5da5Sopenharmony_ci ASSERT_EQ(2, count_functions(context.get())); 77fd4e5da5Sopenharmony_ci 78fd4e5da5Sopenharmony_ci std::string after_first = R"( 79fd4e5da5Sopenharmony_ci OpCapability Shader 80fd4e5da5Sopenharmony_ci %1 = OpExtInstImport "GLSL.std.450" 81fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 82fd4e5da5Sopenharmony_ci OpEntryPoint Fragment %4 "main" 83fd4e5da5Sopenharmony_ci OpExecutionMode %4 OriginUpperLeft 84fd4e5da5Sopenharmony_ci OpSource ESSL 310 85fd4e5da5Sopenharmony_ci %2 = OpTypeVoid 86fd4e5da5Sopenharmony_ci %3 = OpTypeFunction %2 87fd4e5da5Sopenharmony_ci %4 = OpFunction %2 None %3 88fd4e5da5Sopenharmony_ci %5 = OpLabel 89fd4e5da5Sopenharmony_ci OpReturn 90fd4e5da5Sopenharmony_ci OpFunctionEnd 91fd4e5da5Sopenharmony_ci %6 = OpFunction %2 None %3 92fd4e5da5Sopenharmony_ci %7 = OpLabel 93fd4e5da5Sopenharmony_ci OpReturn 94fd4e5da5Sopenharmony_ci OpFunctionEnd 95fd4e5da5Sopenharmony_ci )"; 96fd4e5da5Sopenharmony_ci 97fd4e5da5Sopenharmony_ci CheckEqual(env, after_first, context.get()); 98fd4e5da5Sopenharmony_ci 99fd4e5da5Sopenharmony_ci ops = RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities( 100fd4e5da5Sopenharmony_ci context.get(), 0); 101fd4e5da5Sopenharmony_ci 102fd4e5da5Sopenharmony_ci ASSERT_EQ(1, ops.size()); 103fd4e5da5Sopenharmony_ci 104fd4e5da5Sopenharmony_ci ASSERT_TRUE(ops[0]->PreconditionHolds()); 105fd4e5da5Sopenharmony_ci ops[0]->TryToApply(); 106fd4e5da5Sopenharmony_ci 107fd4e5da5Sopenharmony_ci ASSERT_EQ(1, count_functions(context.get())); 108fd4e5da5Sopenharmony_ci 109fd4e5da5Sopenharmony_ci std::string after_second = R"( 110fd4e5da5Sopenharmony_ci OpCapability Shader 111fd4e5da5Sopenharmony_ci %1 = OpExtInstImport "GLSL.std.450" 112fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 113fd4e5da5Sopenharmony_ci OpEntryPoint Fragment %4 "main" 114fd4e5da5Sopenharmony_ci OpExecutionMode %4 OriginUpperLeft 115fd4e5da5Sopenharmony_ci OpSource ESSL 310 116fd4e5da5Sopenharmony_ci %2 = OpTypeVoid 117fd4e5da5Sopenharmony_ci %3 = OpTypeFunction %2 118fd4e5da5Sopenharmony_ci %4 = OpFunction %2 None %3 119fd4e5da5Sopenharmony_ci %5 = OpLabel 120fd4e5da5Sopenharmony_ci OpReturn 121fd4e5da5Sopenharmony_ci OpFunctionEnd 122fd4e5da5Sopenharmony_ci )"; 123fd4e5da5Sopenharmony_ci 124fd4e5da5Sopenharmony_ci CheckEqual(env, after_second, context.get()); 125fd4e5da5Sopenharmony_ci} 126fd4e5da5Sopenharmony_ci 127fd4e5da5Sopenharmony_ciTEST(RemoveFunctionTest, NothingToRemove) { 128fd4e5da5Sopenharmony_ci std::string shader = R"( 129fd4e5da5Sopenharmony_ci OpCapability Shader 130fd4e5da5Sopenharmony_ci %1 = OpExtInstImport "GLSL.std.450" 131fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 132fd4e5da5Sopenharmony_ci OpEntryPoint Fragment %4 "main" 133fd4e5da5Sopenharmony_ci OpExecutionMode %4 OriginUpperLeft 134fd4e5da5Sopenharmony_ci OpSource ESSL 310 135fd4e5da5Sopenharmony_ci %2 = OpTypeVoid 136fd4e5da5Sopenharmony_ci %3 = OpTypeFunction %2 137fd4e5da5Sopenharmony_ci %4 = OpFunction %2 None %3 138fd4e5da5Sopenharmony_ci %5 = OpLabel 139fd4e5da5Sopenharmony_ci %11 = OpFunctionCall %2 %8 140fd4e5da5Sopenharmony_ci OpReturn 141fd4e5da5Sopenharmony_ci OpFunctionEnd 142fd4e5da5Sopenharmony_ci %6 = OpFunction %2 None %3 143fd4e5da5Sopenharmony_ci %7 = OpLabel 144fd4e5da5Sopenharmony_ci OpReturn 145fd4e5da5Sopenharmony_ci OpFunctionEnd 146fd4e5da5Sopenharmony_ci %8 = OpFunction %2 None %3 147fd4e5da5Sopenharmony_ci %9 = OpLabel 148fd4e5da5Sopenharmony_ci %10 = OpFunctionCall %2 %6 149fd4e5da5Sopenharmony_ci OpReturn 150fd4e5da5Sopenharmony_ci OpFunctionEnd 151fd4e5da5Sopenharmony_ci )"; 152fd4e5da5Sopenharmony_ci 153fd4e5da5Sopenharmony_ci const auto env = SPV_ENV_UNIVERSAL_1_3; 154fd4e5da5Sopenharmony_ci const auto consumer = nullptr; 155fd4e5da5Sopenharmony_ci const auto context = 156fd4e5da5Sopenharmony_ci BuildModule(env, consumer, shader, kReduceAssembleOption); 157fd4e5da5Sopenharmony_ci auto ops = 158fd4e5da5Sopenharmony_ci RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities( 159fd4e5da5Sopenharmony_ci context.get(), 0); 160fd4e5da5Sopenharmony_ci ASSERT_EQ(0, ops.size()); 161fd4e5da5Sopenharmony_ci} 162fd4e5da5Sopenharmony_ci 163fd4e5da5Sopenharmony_ciTEST(RemoveFunctionTest, TwoRemovableFunctions) { 164fd4e5da5Sopenharmony_ci std::string shader = R"( 165fd4e5da5Sopenharmony_ci OpCapability Shader 166fd4e5da5Sopenharmony_ci %1 = OpExtInstImport "GLSL.std.450" 167fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 168fd4e5da5Sopenharmony_ci OpEntryPoint Fragment %4 "main" 169fd4e5da5Sopenharmony_ci OpExecutionMode %4 OriginUpperLeft 170fd4e5da5Sopenharmony_ci OpSource ESSL 310 171fd4e5da5Sopenharmony_ci %2 = OpTypeVoid 172fd4e5da5Sopenharmony_ci %3 = OpTypeFunction %2 173fd4e5da5Sopenharmony_ci %4 = OpFunction %2 None %3 174fd4e5da5Sopenharmony_ci %5 = OpLabel 175fd4e5da5Sopenharmony_ci OpReturn 176fd4e5da5Sopenharmony_ci OpFunctionEnd 177fd4e5da5Sopenharmony_ci %6 = OpFunction %2 None %3 178fd4e5da5Sopenharmony_ci %7 = OpLabel 179fd4e5da5Sopenharmony_ci OpReturn 180fd4e5da5Sopenharmony_ci OpFunctionEnd 181fd4e5da5Sopenharmony_ci %8 = OpFunction %2 None %3 182fd4e5da5Sopenharmony_ci %9 = OpLabel 183fd4e5da5Sopenharmony_ci OpReturn 184fd4e5da5Sopenharmony_ci OpFunctionEnd 185fd4e5da5Sopenharmony_ci )"; 186fd4e5da5Sopenharmony_ci 187fd4e5da5Sopenharmony_ci const auto env = SPV_ENV_UNIVERSAL_1_3; 188fd4e5da5Sopenharmony_ci const auto consumer = nullptr; 189fd4e5da5Sopenharmony_ci const auto context = 190fd4e5da5Sopenharmony_ci BuildModule(env, consumer, shader, kReduceAssembleOption); 191fd4e5da5Sopenharmony_ci 192fd4e5da5Sopenharmony_ci ASSERT_EQ(3, count_functions(context.get())); 193fd4e5da5Sopenharmony_ci 194fd4e5da5Sopenharmony_ci auto ops = 195fd4e5da5Sopenharmony_ci RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities( 196fd4e5da5Sopenharmony_ci context.get(), 0); 197fd4e5da5Sopenharmony_ci ASSERT_EQ(2, ops.size()); 198fd4e5da5Sopenharmony_ci 199fd4e5da5Sopenharmony_ci ASSERT_TRUE(ops[0]->PreconditionHolds()); 200fd4e5da5Sopenharmony_ci ops[0]->TryToApply(); 201fd4e5da5Sopenharmony_ci ASSERT_EQ(2, count_functions(context.get())); 202fd4e5da5Sopenharmony_ci ASSERT_TRUE(ops[1]->PreconditionHolds()); 203fd4e5da5Sopenharmony_ci ops[1]->TryToApply(); 204fd4e5da5Sopenharmony_ci ASSERT_EQ(1, count_functions(context.get())); 205fd4e5da5Sopenharmony_ci 206fd4e5da5Sopenharmony_ci std::string after = R"( 207fd4e5da5Sopenharmony_ci OpCapability Shader 208fd4e5da5Sopenharmony_ci %1 = OpExtInstImport "GLSL.std.450" 209fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 210fd4e5da5Sopenharmony_ci OpEntryPoint Fragment %4 "main" 211fd4e5da5Sopenharmony_ci OpExecutionMode %4 OriginUpperLeft 212fd4e5da5Sopenharmony_ci OpSource ESSL 310 213fd4e5da5Sopenharmony_ci %2 = OpTypeVoid 214fd4e5da5Sopenharmony_ci %3 = OpTypeFunction %2 215fd4e5da5Sopenharmony_ci %4 = OpFunction %2 None %3 216fd4e5da5Sopenharmony_ci %5 = OpLabel 217fd4e5da5Sopenharmony_ci OpReturn 218fd4e5da5Sopenharmony_ci OpFunctionEnd 219fd4e5da5Sopenharmony_ci )"; 220fd4e5da5Sopenharmony_ci 221fd4e5da5Sopenharmony_ci CheckEqual(env, after, context.get()); 222fd4e5da5Sopenharmony_ci} 223fd4e5da5Sopenharmony_ci 224fd4e5da5Sopenharmony_ciTEST(RemoveFunctionTest, NoRemovalsDueToOpName) { 225fd4e5da5Sopenharmony_ci std::string shader = R"( 226fd4e5da5Sopenharmony_ci OpCapability Shader 227fd4e5da5Sopenharmony_ci %1 = OpExtInstImport "GLSL.std.450" 228fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 229fd4e5da5Sopenharmony_ci OpEntryPoint Fragment %4 "main" 230fd4e5da5Sopenharmony_ci OpExecutionMode %4 OriginUpperLeft 231fd4e5da5Sopenharmony_ci OpSource ESSL 310 232fd4e5da5Sopenharmony_ci OpName %4 "main" 233fd4e5da5Sopenharmony_ci OpName %6 "foo(" 234fd4e5da5Sopenharmony_ci OpName %8 "bar(" 235fd4e5da5Sopenharmony_ci %2 = OpTypeVoid 236fd4e5da5Sopenharmony_ci %3 = OpTypeFunction %2 237fd4e5da5Sopenharmony_ci %4 = OpFunction %2 None %3 238fd4e5da5Sopenharmony_ci %5 = OpLabel 239fd4e5da5Sopenharmony_ci OpReturn 240fd4e5da5Sopenharmony_ci OpFunctionEnd 241fd4e5da5Sopenharmony_ci %6 = OpFunction %2 None %3 242fd4e5da5Sopenharmony_ci %7 = OpLabel 243fd4e5da5Sopenharmony_ci OpReturn 244fd4e5da5Sopenharmony_ci OpFunctionEnd 245fd4e5da5Sopenharmony_ci %8 = OpFunction %2 None %3 246fd4e5da5Sopenharmony_ci %9 = OpLabel 247fd4e5da5Sopenharmony_ci OpReturn 248fd4e5da5Sopenharmony_ci OpFunctionEnd 249fd4e5da5Sopenharmony_ci )"; 250fd4e5da5Sopenharmony_ci 251fd4e5da5Sopenharmony_ci const auto env = SPV_ENV_UNIVERSAL_1_3; 252fd4e5da5Sopenharmony_ci const auto consumer = nullptr; 253fd4e5da5Sopenharmony_ci const auto context = 254fd4e5da5Sopenharmony_ci BuildModule(env, consumer, shader, kReduceAssembleOption); 255fd4e5da5Sopenharmony_ci auto ops = 256fd4e5da5Sopenharmony_ci RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities( 257fd4e5da5Sopenharmony_ci context.get(), 0); 258fd4e5da5Sopenharmony_ci ASSERT_EQ(0, ops.size()); 259fd4e5da5Sopenharmony_ci} 260fd4e5da5Sopenharmony_ci 261fd4e5da5Sopenharmony_ciTEST(RemoveFunctionTest, NoRemovalDueToLinkageDecoration) { 262fd4e5da5Sopenharmony_ci // The non-entry point function is not removable because it is referenced by a 263fd4e5da5Sopenharmony_ci // linkage decoration. Thus no function can be removed. 264fd4e5da5Sopenharmony_ci std::string shader = R"( 265fd4e5da5Sopenharmony_ci OpCapability Shader 266fd4e5da5Sopenharmony_ci OpCapability Linkage 267fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 268fd4e5da5Sopenharmony_ci OpEntryPoint Fragment %1 "main" 269fd4e5da5Sopenharmony_ci OpName %1 "main" 270fd4e5da5Sopenharmony_ci OpDecorate %2 LinkageAttributes "ExportedFunc" Export 271fd4e5da5Sopenharmony_ci %4 = OpTypeVoid 272fd4e5da5Sopenharmony_ci %5 = OpTypeFunction %4 273fd4e5da5Sopenharmony_ci %1 = OpFunction %4 None %5 274fd4e5da5Sopenharmony_ci %6 = OpLabel 275fd4e5da5Sopenharmony_ci OpReturn 276fd4e5da5Sopenharmony_ci OpFunctionEnd 277fd4e5da5Sopenharmony_ci %2 = OpFunction %4 None %5 278fd4e5da5Sopenharmony_ci %7 = OpLabel 279fd4e5da5Sopenharmony_ci OpReturn 280fd4e5da5Sopenharmony_ci OpFunctionEnd 281fd4e5da5Sopenharmony_ci )"; 282fd4e5da5Sopenharmony_ci 283fd4e5da5Sopenharmony_ci const auto env = SPV_ENV_UNIVERSAL_1_3; 284fd4e5da5Sopenharmony_ci const auto consumer = nullptr; 285fd4e5da5Sopenharmony_ci const auto context = 286fd4e5da5Sopenharmony_ci BuildModule(env, consumer, shader, kReduceAssembleOption); 287fd4e5da5Sopenharmony_ci auto ops = 288fd4e5da5Sopenharmony_ci RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities( 289fd4e5da5Sopenharmony_ci context.get(), 0); 290fd4e5da5Sopenharmony_ci ASSERT_EQ(0, ops.size()); 291fd4e5da5Sopenharmony_ci} 292fd4e5da5Sopenharmony_ci 293fd4e5da5Sopenharmony_ci} // namespace 294fd4e5da5Sopenharmony_ci} // namespace reduce 295fd4e5da5Sopenharmony_ci} // namespace spvtools 296