1fd4e5da5Sopenharmony_ci// Copyright (c) 2018 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/reducer.h" 16fd4e5da5Sopenharmony_ci#include "source/reduce/reduction_opportunity.h" 17fd4e5da5Sopenharmony_ci#include "source/reduce/remove_instruction_reduction_opportunity.h" 18fd4e5da5Sopenharmony_ci#include "test/reduce/reduce_test_util.h" 19fd4e5da5Sopenharmony_ci 20fd4e5da5Sopenharmony_cinamespace spvtools { 21fd4e5da5Sopenharmony_cinamespace reduce { 22fd4e5da5Sopenharmony_cinamespace { 23fd4e5da5Sopenharmony_ci 24fd4e5da5Sopenharmony_ciusing opt::Function; 25fd4e5da5Sopenharmony_ciusing opt::IRContext; 26fd4e5da5Sopenharmony_ciusing opt::Instruction; 27fd4e5da5Sopenharmony_ci 28fd4e5da5Sopenharmony_ci// A reduction opportunity finder that finds opportunities to remove global 29fd4e5da5Sopenharmony_ci// values regardless of whether they are referenced. This is very likely to make 30fd4e5da5Sopenharmony_ci// the resulting module invalid. We use this to test the reducer's behavior in 31fd4e5da5Sopenharmony_ci// the scenario where a bad reduction pass leads to an invalid module. 32fd4e5da5Sopenharmony_ciclass BlindlyRemoveGlobalValuesReductionOpportunityFinder 33fd4e5da5Sopenharmony_ci : public ReductionOpportunityFinder { 34fd4e5da5Sopenharmony_ci public: 35fd4e5da5Sopenharmony_ci BlindlyRemoveGlobalValuesReductionOpportunityFinder() = default; 36fd4e5da5Sopenharmony_ci 37fd4e5da5Sopenharmony_ci ~BlindlyRemoveGlobalValuesReductionOpportunityFinder() override = default; 38fd4e5da5Sopenharmony_ci 39fd4e5da5Sopenharmony_ci // The name of this pass. 40fd4e5da5Sopenharmony_ci std::string GetName() const final { return "BlindlyRemoveGlobalValuesPass"; } 41fd4e5da5Sopenharmony_ci 42fd4e5da5Sopenharmony_ci // Finds opportunities to remove all global values. Assuming they are all 43fd4e5da5Sopenharmony_ci // referenced (directly or indirectly) from elsewhere in the module, each such 44fd4e5da5Sopenharmony_ci // opportunity will make the module invalid. 45fd4e5da5Sopenharmony_ci std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities( 46fd4e5da5Sopenharmony_ci IRContext* context, uint32_t /*unused*/) const final { 47fd4e5da5Sopenharmony_ci std::vector<std::unique_ptr<ReductionOpportunity>> result; 48fd4e5da5Sopenharmony_ci for (auto& inst : context->module()->types_values()) { 49fd4e5da5Sopenharmony_ci if (inst.HasResultId()) { 50fd4e5da5Sopenharmony_ci result.push_back( 51fd4e5da5Sopenharmony_ci MakeUnique<RemoveInstructionReductionOpportunity>(&inst)); 52fd4e5da5Sopenharmony_ci } 53fd4e5da5Sopenharmony_ci } 54fd4e5da5Sopenharmony_ci return result; 55fd4e5da5Sopenharmony_ci } 56fd4e5da5Sopenharmony_ci}; 57fd4e5da5Sopenharmony_ci 58fd4e5da5Sopenharmony_ci// A reduction opportunity that exists at the start of every function whose 59fd4e5da5Sopenharmony_ci// first instruction is an OpVariable instruction. When applied, the OpVariable 60fd4e5da5Sopenharmony_ci// instruction is duplicated (with a fresh result id). This allows each 61fd4e5da5Sopenharmony_ci// reduction step to increase the number of variables to check if the validator 62fd4e5da5Sopenharmony_ci// limits are enforced. 63fd4e5da5Sopenharmony_ciclass OpVariableDuplicatorReductionOpportunity : public ReductionOpportunity { 64fd4e5da5Sopenharmony_ci public: 65fd4e5da5Sopenharmony_ci OpVariableDuplicatorReductionOpportunity(Function* function) 66fd4e5da5Sopenharmony_ci : function_(function) {} 67fd4e5da5Sopenharmony_ci 68fd4e5da5Sopenharmony_ci bool PreconditionHolds() override { 69fd4e5da5Sopenharmony_ci Instruction* first_instruction = &*function_->begin()[0].begin(); 70fd4e5da5Sopenharmony_ci return first_instruction->opcode() == spv::Op::OpVariable; 71fd4e5da5Sopenharmony_ci } 72fd4e5da5Sopenharmony_ci 73fd4e5da5Sopenharmony_ci protected: 74fd4e5da5Sopenharmony_ci void Apply() override { 75fd4e5da5Sopenharmony_ci // Duplicate the first OpVariable instruction. 76fd4e5da5Sopenharmony_ci 77fd4e5da5Sopenharmony_ci Instruction* first_instruction = &*function_->begin()[0].begin(); 78fd4e5da5Sopenharmony_ci assert(first_instruction->opcode() == spv::Op::OpVariable && 79fd4e5da5Sopenharmony_ci "Expected first instruction to be OpVariable"); 80fd4e5da5Sopenharmony_ci IRContext* context = first_instruction->context(); 81fd4e5da5Sopenharmony_ci Instruction* cloned_instruction = first_instruction->Clone(context); 82fd4e5da5Sopenharmony_ci cloned_instruction->SetResultId(context->TakeNextId()); 83fd4e5da5Sopenharmony_ci cloned_instruction->InsertBefore(first_instruction); 84fd4e5da5Sopenharmony_ci } 85fd4e5da5Sopenharmony_ci 86fd4e5da5Sopenharmony_ci private: 87fd4e5da5Sopenharmony_ci Function* function_; 88fd4e5da5Sopenharmony_ci}; 89fd4e5da5Sopenharmony_ci 90fd4e5da5Sopenharmony_ci// A reduction opportunity finder that finds 91fd4e5da5Sopenharmony_ci// OpVariableDuplicatorReductionOpportunity. 92fd4e5da5Sopenharmony_ciclass OpVariableDuplicatorReductionOpportunityFinder 93fd4e5da5Sopenharmony_ci : public ReductionOpportunityFinder { 94fd4e5da5Sopenharmony_ci public: 95fd4e5da5Sopenharmony_ci OpVariableDuplicatorReductionOpportunityFinder() = default; 96fd4e5da5Sopenharmony_ci 97fd4e5da5Sopenharmony_ci ~OpVariableDuplicatorReductionOpportunityFinder() override = default; 98fd4e5da5Sopenharmony_ci 99fd4e5da5Sopenharmony_ci std::string GetName() const final { 100fd4e5da5Sopenharmony_ci return "LocalVariableAdderReductionOpportunityFinder"; 101fd4e5da5Sopenharmony_ci } 102fd4e5da5Sopenharmony_ci 103fd4e5da5Sopenharmony_ci std::vector<std::unique_ptr<ReductionOpportunity>> GetAvailableOpportunities( 104fd4e5da5Sopenharmony_ci IRContext* context, uint32_t /*unused*/) const final { 105fd4e5da5Sopenharmony_ci std::vector<std::unique_ptr<ReductionOpportunity>> result; 106fd4e5da5Sopenharmony_ci for (auto& function : *context->module()) { 107fd4e5da5Sopenharmony_ci Instruction* first_instruction = &*function.begin()[0].begin(); 108fd4e5da5Sopenharmony_ci if (first_instruction->opcode() == spv::Op::OpVariable) { 109fd4e5da5Sopenharmony_ci result.push_back( 110fd4e5da5Sopenharmony_ci MakeUnique<OpVariableDuplicatorReductionOpportunity>(&function)); 111fd4e5da5Sopenharmony_ci } 112fd4e5da5Sopenharmony_ci } 113fd4e5da5Sopenharmony_ci return result; 114fd4e5da5Sopenharmony_ci } 115fd4e5da5Sopenharmony_ci}; 116fd4e5da5Sopenharmony_ci 117fd4e5da5Sopenharmony_ciTEST(ValidationDuringReductionTest, CheckInvalidPassMakesNoProgress) { 118fd4e5da5Sopenharmony_ci // A module whose global values are all referenced, so that any application of 119fd4e5da5Sopenharmony_ci // MakeModuleInvalidPass will make the module invalid. Check that the reducer 120fd4e5da5Sopenharmony_ci // makes no progress, as every step will be invalid and treated as 121fd4e5da5Sopenharmony_ci // uninteresting. 122fd4e5da5Sopenharmony_ci std::string original = R"( 123fd4e5da5Sopenharmony_ci OpCapability Shader 124fd4e5da5Sopenharmony_ci %1 = OpExtInstImport "GLSL.std.450" 125fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 126fd4e5da5Sopenharmony_ci OpEntryPoint Fragment %4 "main" %60 127fd4e5da5Sopenharmony_ci OpExecutionMode %4 OriginUpperLeft 128fd4e5da5Sopenharmony_ci OpSource ESSL 310 129fd4e5da5Sopenharmony_ci OpName %4 "main" 130fd4e5da5Sopenharmony_ci OpName %16 "buf2" 131fd4e5da5Sopenharmony_ci OpMemberName %16 0 "i" 132fd4e5da5Sopenharmony_ci OpName %18 "" 133fd4e5da5Sopenharmony_ci OpName %25 "buf1" 134fd4e5da5Sopenharmony_ci OpMemberName %25 0 "f" 135fd4e5da5Sopenharmony_ci OpName %27 "" 136fd4e5da5Sopenharmony_ci OpName %60 "_GLF_color" 137fd4e5da5Sopenharmony_ci OpMemberDecorate %16 0 Offset 0 138fd4e5da5Sopenharmony_ci OpDecorate %16 Block 139fd4e5da5Sopenharmony_ci OpDecorate %18 DescriptorSet 0 140fd4e5da5Sopenharmony_ci OpDecorate %18 Binding 2 141fd4e5da5Sopenharmony_ci OpMemberDecorate %25 0 Offset 0 142fd4e5da5Sopenharmony_ci OpDecorate %25 Block 143fd4e5da5Sopenharmony_ci OpDecorate %27 DescriptorSet 0 144fd4e5da5Sopenharmony_ci OpDecorate %27 Binding 1 145fd4e5da5Sopenharmony_ci OpDecorate %60 Location 0 146fd4e5da5Sopenharmony_ci %2 = OpTypeVoid 147fd4e5da5Sopenharmony_ci %3 = OpTypeFunction %2 148fd4e5da5Sopenharmony_ci %6 = OpTypeInt 32 1 149fd4e5da5Sopenharmony_ci %9 = OpConstant %6 0 150fd4e5da5Sopenharmony_ci %16 = OpTypeStruct %6 151fd4e5da5Sopenharmony_ci %17 = OpTypePointer Uniform %16 152fd4e5da5Sopenharmony_ci %18 = OpVariable %17 Uniform 153fd4e5da5Sopenharmony_ci %19 = OpTypePointer Uniform %6 154fd4e5da5Sopenharmony_ci %22 = OpTypeBool 155fd4e5da5Sopenharmony_ci %24 = OpTypeFloat 32 156fd4e5da5Sopenharmony_ci %25 = OpTypeStruct %24 157fd4e5da5Sopenharmony_ci %26 = OpTypePointer Uniform %25 158fd4e5da5Sopenharmony_ci %27 = OpVariable %26 Uniform 159fd4e5da5Sopenharmony_ci %28 = OpTypePointer Uniform %24 160fd4e5da5Sopenharmony_ci %31 = OpConstant %24 2 161fd4e5da5Sopenharmony_ci %56 = OpConstant %6 1 162fd4e5da5Sopenharmony_ci %58 = OpTypeVector %24 4 163fd4e5da5Sopenharmony_ci %59 = OpTypePointer Output %58 164fd4e5da5Sopenharmony_ci %60 = OpVariable %59 Output 165fd4e5da5Sopenharmony_ci %72 = OpUndef %24 166fd4e5da5Sopenharmony_ci %74 = OpUndef %6 167fd4e5da5Sopenharmony_ci %4 = OpFunction %2 None %3 168fd4e5da5Sopenharmony_ci %5 = OpLabel 169fd4e5da5Sopenharmony_ci OpBranch %10 170fd4e5da5Sopenharmony_ci %10 = OpLabel 171fd4e5da5Sopenharmony_ci %73 = OpPhi %6 %74 %5 %77 %34 172fd4e5da5Sopenharmony_ci %71 = OpPhi %24 %72 %5 %76 %34 173fd4e5da5Sopenharmony_ci %70 = OpPhi %6 %9 %5 %57 %34 174fd4e5da5Sopenharmony_ci %20 = OpAccessChain %19 %18 %9 175fd4e5da5Sopenharmony_ci %21 = OpLoad %6 %20 176fd4e5da5Sopenharmony_ci %23 = OpSLessThan %22 %70 %21 177fd4e5da5Sopenharmony_ci OpLoopMerge %12 %34 None 178fd4e5da5Sopenharmony_ci OpBranchConditional %23 %11 %12 179fd4e5da5Sopenharmony_ci %11 = OpLabel 180fd4e5da5Sopenharmony_ci %29 = OpAccessChain %28 %27 %9 181fd4e5da5Sopenharmony_ci %30 = OpLoad %24 %29 182fd4e5da5Sopenharmony_ci %32 = OpFOrdGreaterThan %22 %30 %31 183fd4e5da5Sopenharmony_ci OpSelectionMerge %90 None 184fd4e5da5Sopenharmony_ci OpBranchConditional %32 %33 %46 185fd4e5da5Sopenharmony_ci %33 = OpLabel 186fd4e5da5Sopenharmony_ci %40 = OpFAdd %24 %71 %30 187fd4e5da5Sopenharmony_ci %45 = OpISub %6 %73 %21 188fd4e5da5Sopenharmony_ci OpBranch %90 189fd4e5da5Sopenharmony_ci %46 = OpLabel 190fd4e5da5Sopenharmony_ci %50 = OpFMul %24 %71 %30 191fd4e5da5Sopenharmony_ci %54 = OpSDiv %6 %73 %21 192fd4e5da5Sopenharmony_ci OpBranch %90 193fd4e5da5Sopenharmony_ci %90 = OpLabel 194fd4e5da5Sopenharmony_ci %77 = OpPhi %6 %45 %33 %54 %46 195fd4e5da5Sopenharmony_ci %76 = OpPhi %24 %40 %33 %50 %46 196fd4e5da5Sopenharmony_ci OpBranch %34 197fd4e5da5Sopenharmony_ci %34 = OpLabel 198fd4e5da5Sopenharmony_ci %57 = OpIAdd %6 %70 %56 199fd4e5da5Sopenharmony_ci OpBranch %10 200fd4e5da5Sopenharmony_ci %12 = OpLabel 201fd4e5da5Sopenharmony_ci %61 = OpAccessChain %28 %27 %9 202fd4e5da5Sopenharmony_ci %62 = OpLoad %24 %61 203fd4e5da5Sopenharmony_ci %66 = OpConvertSToF %24 %21 204fd4e5da5Sopenharmony_ci %68 = OpConvertSToF %24 %73 205fd4e5da5Sopenharmony_ci %69 = OpCompositeConstruct %58 %62 %71 %66 %68 206fd4e5da5Sopenharmony_ci OpStore %60 %69 207fd4e5da5Sopenharmony_ci OpReturn 208fd4e5da5Sopenharmony_ci OpFunctionEnd 209fd4e5da5Sopenharmony_ci )"; 210fd4e5da5Sopenharmony_ci 211fd4e5da5Sopenharmony_ci spv_target_env env = SPV_ENV_UNIVERSAL_1_3; 212fd4e5da5Sopenharmony_ci Reducer reducer(env); 213fd4e5da5Sopenharmony_ci reducer.SetMessageConsumer(NopDiagnostic); 214fd4e5da5Sopenharmony_ci 215fd4e5da5Sopenharmony_ci // Say that every module is interesting. 216fd4e5da5Sopenharmony_ci reducer.SetInterestingnessFunction( 217fd4e5da5Sopenharmony_ci [](const std::vector<uint32_t>&, uint32_t) -> bool { return true; }); 218fd4e5da5Sopenharmony_ci 219fd4e5da5Sopenharmony_ci reducer.AddReductionPass( 220fd4e5da5Sopenharmony_ci MakeUnique<BlindlyRemoveGlobalValuesReductionOpportunityFinder>()); 221fd4e5da5Sopenharmony_ci 222fd4e5da5Sopenharmony_ci std::vector<uint32_t> binary_in; 223fd4e5da5Sopenharmony_ci SpirvTools t(env); 224fd4e5da5Sopenharmony_ci 225fd4e5da5Sopenharmony_ci ASSERT_TRUE(t.Assemble(original, &binary_in, kReduceAssembleOption)); 226fd4e5da5Sopenharmony_ci std::vector<uint32_t> binary_out; 227fd4e5da5Sopenharmony_ci spvtools::ReducerOptions reducer_options; 228fd4e5da5Sopenharmony_ci reducer_options.set_step_limit(500); 229fd4e5da5Sopenharmony_ci // Don't fail on a validation error; just treat it as uninteresting. 230fd4e5da5Sopenharmony_ci reducer_options.set_fail_on_validation_error(false); 231fd4e5da5Sopenharmony_ci spvtools::ValidatorOptions validator_options; 232fd4e5da5Sopenharmony_ci 233fd4e5da5Sopenharmony_ci Reducer::ReductionResultStatus status = reducer.Run( 234fd4e5da5Sopenharmony_ci std::move(binary_in), &binary_out, reducer_options, validator_options); 235fd4e5da5Sopenharmony_ci 236fd4e5da5Sopenharmony_ci ASSERT_EQ(status, Reducer::ReductionResultStatus::kComplete); 237fd4e5da5Sopenharmony_ci 238fd4e5da5Sopenharmony_ci // The reducer should have no impact. 239fd4e5da5Sopenharmony_ci CheckEqual(env, original, binary_out); 240fd4e5da5Sopenharmony_ci} 241fd4e5da5Sopenharmony_ci 242fd4e5da5Sopenharmony_ciTEST(ValidationDuringReductionTest, CheckNotAlwaysInvalidCanMakeProgress) { 243fd4e5da5Sopenharmony_ci // A module with just one unreferenced global value. All but one application 244fd4e5da5Sopenharmony_ci // of MakeModuleInvalidPass will make the module invalid. 245fd4e5da5Sopenharmony_ci std::string original = R"( 246fd4e5da5Sopenharmony_ci OpCapability Shader 247fd4e5da5Sopenharmony_ci %1 = OpExtInstImport "GLSL.std.450" 248fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 249fd4e5da5Sopenharmony_ci OpEntryPoint Fragment %4 "main" %60 250fd4e5da5Sopenharmony_ci OpExecutionMode %4 OriginUpperLeft 251fd4e5da5Sopenharmony_ci OpSource ESSL 310 252fd4e5da5Sopenharmony_ci OpName %4 "main" 253fd4e5da5Sopenharmony_ci OpName %16 "buf2" 254fd4e5da5Sopenharmony_ci OpMemberName %16 0 "i" 255fd4e5da5Sopenharmony_ci OpName %18 "" 256fd4e5da5Sopenharmony_ci OpName %25 "buf1" 257fd4e5da5Sopenharmony_ci OpMemberName %25 0 "f" 258fd4e5da5Sopenharmony_ci OpName %27 "" 259fd4e5da5Sopenharmony_ci OpName %60 "_GLF_color" 260fd4e5da5Sopenharmony_ci OpMemberDecorate %16 0 Offset 0 261fd4e5da5Sopenharmony_ci OpDecorate %16 Block 262fd4e5da5Sopenharmony_ci OpDecorate %18 DescriptorSet 0 263fd4e5da5Sopenharmony_ci OpDecorate %18 Binding 2 264fd4e5da5Sopenharmony_ci OpMemberDecorate %25 0 Offset 0 265fd4e5da5Sopenharmony_ci OpDecorate %25 Block 266fd4e5da5Sopenharmony_ci OpDecorate %27 DescriptorSet 0 267fd4e5da5Sopenharmony_ci OpDecorate %27 Binding 1 268fd4e5da5Sopenharmony_ci OpDecorate %60 Location 0 269fd4e5da5Sopenharmony_ci %2 = OpTypeVoid 270fd4e5da5Sopenharmony_ci %3 = OpTypeFunction %2 271fd4e5da5Sopenharmony_ci %6 = OpTypeInt 32 1 272fd4e5da5Sopenharmony_ci %9 = OpConstant %6 0 273fd4e5da5Sopenharmony_ci %16 = OpTypeStruct %6 274fd4e5da5Sopenharmony_ci %17 = OpTypePointer Uniform %16 275fd4e5da5Sopenharmony_ci %18 = OpVariable %17 Uniform 276fd4e5da5Sopenharmony_ci %19 = OpTypePointer Uniform %6 277fd4e5da5Sopenharmony_ci %22 = OpTypeBool 278fd4e5da5Sopenharmony_ci %24 = OpTypeFloat 32 279fd4e5da5Sopenharmony_ci %25 = OpTypeStruct %24 280fd4e5da5Sopenharmony_ci %26 = OpTypePointer Uniform %25 281fd4e5da5Sopenharmony_ci %27 = OpVariable %26 Uniform 282fd4e5da5Sopenharmony_ci %28 = OpTypePointer Uniform %24 283fd4e5da5Sopenharmony_ci %31 = OpConstant %24 2 284fd4e5da5Sopenharmony_ci %56 = OpConstant %6 1 285fd4e5da5Sopenharmony_ci %1000 = OpConstant %6 1000 ; It should be possible to remove this instruction without making the module invalid. 286fd4e5da5Sopenharmony_ci %58 = OpTypeVector %24 4 287fd4e5da5Sopenharmony_ci %59 = OpTypePointer Output %58 288fd4e5da5Sopenharmony_ci %60 = OpVariable %59 Output 289fd4e5da5Sopenharmony_ci %72 = OpUndef %24 290fd4e5da5Sopenharmony_ci %74 = OpUndef %6 291fd4e5da5Sopenharmony_ci %4 = OpFunction %2 None %3 292fd4e5da5Sopenharmony_ci %5 = OpLabel 293fd4e5da5Sopenharmony_ci OpBranch %10 294fd4e5da5Sopenharmony_ci %10 = OpLabel 295fd4e5da5Sopenharmony_ci %73 = OpPhi %6 %74 %5 %77 %34 296fd4e5da5Sopenharmony_ci %71 = OpPhi %24 %72 %5 %76 %34 297fd4e5da5Sopenharmony_ci %70 = OpPhi %6 %9 %5 %57 %34 298fd4e5da5Sopenharmony_ci %20 = OpAccessChain %19 %18 %9 299fd4e5da5Sopenharmony_ci %21 = OpLoad %6 %20 300fd4e5da5Sopenharmony_ci %23 = OpSLessThan %22 %70 %21 301fd4e5da5Sopenharmony_ci OpLoopMerge %12 %34 None 302fd4e5da5Sopenharmony_ci OpBranchConditional %23 %11 %12 303fd4e5da5Sopenharmony_ci %11 = OpLabel 304fd4e5da5Sopenharmony_ci %29 = OpAccessChain %28 %27 %9 305fd4e5da5Sopenharmony_ci %30 = OpLoad %24 %29 306fd4e5da5Sopenharmony_ci %32 = OpFOrdGreaterThan %22 %30 %31 307fd4e5da5Sopenharmony_ci OpSelectionMerge %90 None 308fd4e5da5Sopenharmony_ci OpBranchConditional %32 %33 %46 309fd4e5da5Sopenharmony_ci %33 = OpLabel 310fd4e5da5Sopenharmony_ci %40 = OpFAdd %24 %71 %30 311fd4e5da5Sopenharmony_ci %45 = OpISub %6 %73 %21 312fd4e5da5Sopenharmony_ci OpBranch %90 313fd4e5da5Sopenharmony_ci %46 = OpLabel 314fd4e5da5Sopenharmony_ci %50 = OpFMul %24 %71 %30 315fd4e5da5Sopenharmony_ci %54 = OpSDiv %6 %73 %21 316fd4e5da5Sopenharmony_ci OpBranch %90 317fd4e5da5Sopenharmony_ci %90 = OpLabel 318fd4e5da5Sopenharmony_ci %77 = OpPhi %6 %45 %33 %54 %46 319fd4e5da5Sopenharmony_ci %76 = OpPhi %24 %40 %33 %50 %46 320fd4e5da5Sopenharmony_ci OpBranch %34 321fd4e5da5Sopenharmony_ci %34 = OpLabel 322fd4e5da5Sopenharmony_ci %57 = OpIAdd %6 %70 %56 323fd4e5da5Sopenharmony_ci OpBranch %10 324fd4e5da5Sopenharmony_ci %12 = OpLabel 325fd4e5da5Sopenharmony_ci %61 = OpAccessChain %28 %27 %9 326fd4e5da5Sopenharmony_ci %62 = OpLoad %24 %61 327fd4e5da5Sopenharmony_ci %66 = OpConvertSToF %24 %21 328fd4e5da5Sopenharmony_ci %68 = OpConvertSToF %24 %73 329fd4e5da5Sopenharmony_ci %69 = OpCompositeConstruct %58 %62 %71 %66 %68 330fd4e5da5Sopenharmony_ci OpStore %60 %69 331fd4e5da5Sopenharmony_ci OpReturn 332fd4e5da5Sopenharmony_ci OpFunctionEnd 333fd4e5da5Sopenharmony_ci )"; 334fd4e5da5Sopenharmony_ci 335fd4e5da5Sopenharmony_ci // This is the same as the original, except that the constant declaration of 336fd4e5da5Sopenharmony_ci // 1000 is gone. 337fd4e5da5Sopenharmony_ci std::string expected = R"( 338fd4e5da5Sopenharmony_ci OpCapability Shader 339fd4e5da5Sopenharmony_ci %1 = OpExtInstImport "GLSL.std.450" 340fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 341fd4e5da5Sopenharmony_ci OpEntryPoint Fragment %4 "main" %60 342fd4e5da5Sopenharmony_ci OpExecutionMode %4 OriginUpperLeft 343fd4e5da5Sopenharmony_ci OpSource ESSL 310 344fd4e5da5Sopenharmony_ci OpName %4 "main" 345fd4e5da5Sopenharmony_ci OpName %16 "buf2" 346fd4e5da5Sopenharmony_ci OpMemberName %16 0 "i" 347fd4e5da5Sopenharmony_ci OpName %18 "" 348fd4e5da5Sopenharmony_ci OpName %25 "buf1" 349fd4e5da5Sopenharmony_ci OpMemberName %25 0 "f" 350fd4e5da5Sopenharmony_ci OpName %27 "" 351fd4e5da5Sopenharmony_ci OpName %60 "_GLF_color" 352fd4e5da5Sopenharmony_ci OpMemberDecorate %16 0 Offset 0 353fd4e5da5Sopenharmony_ci OpDecorate %16 Block 354fd4e5da5Sopenharmony_ci OpDecorate %18 DescriptorSet 0 355fd4e5da5Sopenharmony_ci OpDecorate %18 Binding 2 356fd4e5da5Sopenharmony_ci OpMemberDecorate %25 0 Offset 0 357fd4e5da5Sopenharmony_ci OpDecorate %25 Block 358fd4e5da5Sopenharmony_ci OpDecorate %27 DescriptorSet 0 359fd4e5da5Sopenharmony_ci OpDecorate %27 Binding 1 360fd4e5da5Sopenharmony_ci OpDecorate %60 Location 0 361fd4e5da5Sopenharmony_ci %2 = OpTypeVoid 362fd4e5da5Sopenharmony_ci %3 = OpTypeFunction %2 363fd4e5da5Sopenharmony_ci %6 = OpTypeInt 32 1 364fd4e5da5Sopenharmony_ci %9 = OpConstant %6 0 365fd4e5da5Sopenharmony_ci %16 = OpTypeStruct %6 366fd4e5da5Sopenharmony_ci %17 = OpTypePointer Uniform %16 367fd4e5da5Sopenharmony_ci %18 = OpVariable %17 Uniform 368fd4e5da5Sopenharmony_ci %19 = OpTypePointer Uniform %6 369fd4e5da5Sopenharmony_ci %22 = OpTypeBool 370fd4e5da5Sopenharmony_ci %24 = OpTypeFloat 32 371fd4e5da5Sopenharmony_ci %25 = OpTypeStruct %24 372fd4e5da5Sopenharmony_ci %26 = OpTypePointer Uniform %25 373fd4e5da5Sopenharmony_ci %27 = OpVariable %26 Uniform 374fd4e5da5Sopenharmony_ci %28 = OpTypePointer Uniform %24 375fd4e5da5Sopenharmony_ci %31 = OpConstant %24 2 376fd4e5da5Sopenharmony_ci %56 = OpConstant %6 1 377fd4e5da5Sopenharmony_ci %58 = OpTypeVector %24 4 378fd4e5da5Sopenharmony_ci %59 = OpTypePointer Output %58 379fd4e5da5Sopenharmony_ci %60 = OpVariable %59 Output 380fd4e5da5Sopenharmony_ci %72 = OpUndef %24 381fd4e5da5Sopenharmony_ci %74 = OpUndef %6 382fd4e5da5Sopenharmony_ci %4 = OpFunction %2 None %3 383fd4e5da5Sopenharmony_ci %5 = OpLabel 384fd4e5da5Sopenharmony_ci OpBranch %10 385fd4e5da5Sopenharmony_ci %10 = OpLabel 386fd4e5da5Sopenharmony_ci %73 = OpPhi %6 %74 %5 %77 %34 387fd4e5da5Sopenharmony_ci %71 = OpPhi %24 %72 %5 %76 %34 388fd4e5da5Sopenharmony_ci %70 = OpPhi %6 %9 %5 %57 %34 389fd4e5da5Sopenharmony_ci %20 = OpAccessChain %19 %18 %9 390fd4e5da5Sopenharmony_ci %21 = OpLoad %6 %20 391fd4e5da5Sopenharmony_ci %23 = OpSLessThan %22 %70 %21 392fd4e5da5Sopenharmony_ci OpLoopMerge %12 %34 None 393fd4e5da5Sopenharmony_ci OpBranchConditional %23 %11 %12 394fd4e5da5Sopenharmony_ci %11 = OpLabel 395fd4e5da5Sopenharmony_ci %29 = OpAccessChain %28 %27 %9 396fd4e5da5Sopenharmony_ci %30 = OpLoad %24 %29 397fd4e5da5Sopenharmony_ci %32 = OpFOrdGreaterThan %22 %30 %31 398fd4e5da5Sopenharmony_ci OpSelectionMerge %90 None 399fd4e5da5Sopenharmony_ci OpBranchConditional %32 %33 %46 400fd4e5da5Sopenharmony_ci %33 = OpLabel 401fd4e5da5Sopenharmony_ci %40 = OpFAdd %24 %71 %30 402fd4e5da5Sopenharmony_ci %45 = OpISub %6 %73 %21 403fd4e5da5Sopenharmony_ci OpBranch %90 404fd4e5da5Sopenharmony_ci %46 = OpLabel 405fd4e5da5Sopenharmony_ci %50 = OpFMul %24 %71 %30 406fd4e5da5Sopenharmony_ci %54 = OpSDiv %6 %73 %21 407fd4e5da5Sopenharmony_ci OpBranch %90 408fd4e5da5Sopenharmony_ci %90 = OpLabel 409fd4e5da5Sopenharmony_ci %77 = OpPhi %6 %45 %33 %54 %46 410fd4e5da5Sopenharmony_ci %76 = OpPhi %24 %40 %33 %50 %46 411fd4e5da5Sopenharmony_ci OpBranch %34 412fd4e5da5Sopenharmony_ci %34 = OpLabel 413fd4e5da5Sopenharmony_ci %57 = OpIAdd %6 %70 %56 414fd4e5da5Sopenharmony_ci OpBranch %10 415fd4e5da5Sopenharmony_ci %12 = OpLabel 416fd4e5da5Sopenharmony_ci %61 = OpAccessChain %28 %27 %9 417fd4e5da5Sopenharmony_ci %62 = OpLoad %24 %61 418fd4e5da5Sopenharmony_ci %66 = OpConvertSToF %24 %21 419fd4e5da5Sopenharmony_ci %68 = OpConvertSToF %24 %73 420fd4e5da5Sopenharmony_ci %69 = OpCompositeConstruct %58 %62 %71 %66 %68 421fd4e5da5Sopenharmony_ci OpStore %60 %69 422fd4e5da5Sopenharmony_ci OpReturn 423fd4e5da5Sopenharmony_ci OpFunctionEnd 424fd4e5da5Sopenharmony_ci )"; 425fd4e5da5Sopenharmony_ci 426fd4e5da5Sopenharmony_ci spv_target_env env = SPV_ENV_UNIVERSAL_1_3; 427fd4e5da5Sopenharmony_ci Reducer reducer(env); 428fd4e5da5Sopenharmony_ci reducer.SetMessageConsumer(NopDiagnostic); 429fd4e5da5Sopenharmony_ci 430fd4e5da5Sopenharmony_ci // Say that every module is interesting. 431fd4e5da5Sopenharmony_ci reducer.SetInterestingnessFunction( 432fd4e5da5Sopenharmony_ci [](const std::vector<uint32_t>&, uint32_t) -> bool { return true; }); 433fd4e5da5Sopenharmony_ci 434fd4e5da5Sopenharmony_ci reducer.AddReductionPass( 435fd4e5da5Sopenharmony_ci MakeUnique<BlindlyRemoveGlobalValuesReductionOpportunityFinder>()); 436fd4e5da5Sopenharmony_ci 437fd4e5da5Sopenharmony_ci std::vector<uint32_t> binary_in; 438fd4e5da5Sopenharmony_ci SpirvTools t(env); 439fd4e5da5Sopenharmony_ci 440fd4e5da5Sopenharmony_ci ASSERT_TRUE(t.Assemble(original, &binary_in, kReduceAssembleOption)); 441fd4e5da5Sopenharmony_ci std::vector<uint32_t> binary_out; 442fd4e5da5Sopenharmony_ci spvtools::ReducerOptions reducer_options; 443fd4e5da5Sopenharmony_ci reducer_options.set_step_limit(500); 444fd4e5da5Sopenharmony_ci // Don't fail on a validation error; just treat it as uninteresting. 445fd4e5da5Sopenharmony_ci reducer_options.set_fail_on_validation_error(false); 446fd4e5da5Sopenharmony_ci spvtools::ValidatorOptions validator_options; 447fd4e5da5Sopenharmony_ci 448fd4e5da5Sopenharmony_ci Reducer::ReductionResultStatus status = reducer.Run( 449fd4e5da5Sopenharmony_ci std::move(binary_in), &binary_out, reducer_options, validator_options); 450fd4e5da5Sopenharmony_ci 451fd4e5da5Sopenharmony_ci ASSERT_EQ(status, Reducer::ReductionResultStatus::kComplete); 452fd4e5da5Sopenharmony_ci 453fd4e5da5Sopenharmony_ci CheckEqual(env, expected, binary_out); 454fd4e5da5Sopenharmony_ci} 455fd4e5da5Sopenharmony_ci 456fd4e5da5Sopenharmony_ci// Sets up a Reducer for use in the CheckValidationOptions test; avoids 457fd4e5da5Sopenharmony_ci// repetition. 458fd4e5da5Sopenharmony_civoid SetupReducerForCheckValidationOptions(Reducer* reducer) { 459fd4e5da5Sopenharmony_ci reducer->SetMessageConsumer(NopDiagnostic); 460fd4e5da5Sopenharmony_ci 461fd4e5da5Sopenharmony_ci // Say that every module is interesting. 462fd4e5da5Sopenharmony_ci reducer->SetInterestingnessFunction( 463fd4e5da5Sopenharmony_ci [](const std::vector<uint32_t>&, uint32_t) -> bool { return true; }); 464fd4e5da5Sopenharmony_ci 465fd4e5da5Sopenharmony_ci // Each "reduction" step will duplicate the first OpVariable instruction in 466fd4e5da5Sopenharmony_ci // the function. 467fd4e5da5Sopenharmony_ci reducer->AddReductionPass( 468fd4e5da5Sopenharmony_ci MakeUnique<OpVariableDuplicatorReductionOpportunityFinder>()); 469fd4e5da5Sopenharmony_ci} 470fd4e5da5Sopenharmony_ci 471fd4e5da5Sopenharmony_ciTEST(ValidationDuringReductionTest, CheckValidationOptions) { 472fd4e5da5Sopenharmony_ci // A module that only validates when the "skip-block-layout" validator option 473fd4e5da5Sopenharmony_ci // is used. Also, the entry point's first instruction creates a local 474fd4e5da5Sopenharmony_ci // variable; this instruction will be duplicated on each reduction step. 475fd4e5da5Sopenharmony_ci std::string original = R"( 476fd4e5da5Sopenharmony_ci OpCapability Shader 477fd4e5da5Sopenharmony_ci %1 = OpExtInstImport "GLSL.std.450" 478fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 479fd4e5da5Sopenharmony_ci OpEntryPoint Vertex %2 "Main" %3 480fd4e5da5Sopenharmony_ci OpSource HLSL 600 481fd4e5da5Sopenharmony_ci OpDecorate %3 BuiltIn Position 482fd4e5da5Sopenharmony_ci OpDecorate %4 DescriptorSet 0 483fd4e5da5Sopenharmony_ci OpDecorate %4 Binding 99 484fd4e5da5Sopenharmony_ci OpDecorate %5 ArrayStride 16 485fd4e5da5Sopenharmony_ci OpMemberDecorate %6 0 Offset 0 486fd4e5da5Sopenharmony_ci OpMemberDecorate %6 1 Offset 32 487fd4e5da5Sopenharmony_ci OpMemberDecorate %6 1 MatrixStride 16 488fd4e5da5Sopenharmony_ci OpMemberDecorate %6 1 ColMajor 489fd4e5da5Sopenharmony_ci OpMemberDecorate %6 2 Offset 96 490fd4e5da5Sopenharmony_ci OpMemberDecorate %6 3 Offset 100 491fd4e5da5Sopenharmony_ci OpMemberDecorate %6 4 Offset 112 492fd4e5da5Sopenharmony_ci OpMemberDecorate %6 4 MatrixStride 16 493fd4e5da5Sopenharmony_ci OpMemberDecorate %6 4 ColMajor 494fd4e5da5Sopenharmony_ci OpMemberDecorate %6 5 Offset 176 495fd4e5da5Sopenharmony_ci OpDecorate %6 Block 496fd4e5da5Sopenharmony_ci %7 = OpTypeFloat 32 497fd4e5da5Sopenharmony_ci %8 = OpTypeVector %7 4 498fd4e5da5Sopenharmony_ci %9 = OpTypeMatrix %8 4 499fd4e5da5Sopenharmony_ci %10 = OpTypeVector %7 2 500fd4e5da5Sopenharmony_ci %11 = OpTypeInt 32 1 501fd4e5da5Sopenharmony_ci %12 = OpTypeInt 32 0 502fd4e5da5Sopenharmony_ci %13 = OpConstant %12 2 503fd4e5da5Sopenharmony_ci %14 = OpConstant %11 1 504fd4e5da5Sopenharmony_ci %15 = OpConstant %11 5 505fd4e5da5Sopenharmony_ci %5 = OpTypeArray %8 %13 506fd4e5da5Sopenharmony_ci %6 = OpTypeStruct %5 %9 %12 %10 %9 %7 507fd4e5da5Sopenharmony_ci %16 = OpTypePointer Uniform %6 508fd4e5da5Sopenharmony_ci %17 = OpTypePointer Output %8 509fd4e5da5Sopenharmony_ci %18 = OpTypeVoid 510fd4e5da5Sopenharmony_ci %19 = OpTypeFunction %18 511fd4e5da5Sopenharmony_ci %20 = OpTypePointer Uniform %7 512fd4e5da5Sopenharmony_ci %4 = OpVariable %16 Uniform 513fd4e5da5Sopenharmony_ci %3 = OpVariable %17 Output 514fd4e5da5Sopenharmony_ci %21 = OpTypePointer Function %11 515fd4e5da5Sopenharmony_ci %2 = OpFunction %18 None %19 516fd4e5da5Sopenharmony_ci %22 = OpLabel 517fd4e5da5Sopenharmony_ci %23 = OpVariable %21 Function 518fd4e5da5Sopenharmony_ci %24 = OpAccessChain %20 %4 %15 519fd4e5da5Sopenharmony_ci %25 = OpLoad %7 %24 520fd4e5da5Sopenharmony_ci %26 = OpCompositeConstruct %8 %25 %25 %25 %25 521fd4e5da5Sopenharmony_ci OpStore %3 %26 522fd4e5da5Sopenharmony_ci OpReturn 523fd4e5da5Sopenharmony_ci OpFunctionEnd 524fd4e5da5Sopenharmony_ci )"; 525fd4e5da5Sopenharmony_ci 526fd4e5da5Sopenharmony_ci spv_target_env env = SPV_ENV_VULKAN_1_0; 527fd4e5da5Sopenharmony_ci std::vector<uint32_t> binary_in; 528fd4e5da5Sopenharmony_ci SpirvTools t(env); 529fd4e5da5Sopenharmony_ci 530fd4e5da5Sopenharmony_ci ASSERT_TRUE(t.Assemble(original, &binary_in, kReduceAssembleOption)); 531fd4e5da5Sopenharmony_ci std::vector<uint32_t> binary_out; 532fd4e5da5Sopenharmony_ci spvtools::ReducerOptions reducer_options; 533fd4e5da5Sopenharmony_ci spvtools::ValidatorOptions validator_options; 534fd4e5da5Sopenharmony_ci 535fd4e5da5Sopenharmony_ci reducer_options.set_step_limit(3); 536fd4e5da5Sopenharmony_ci reducer_options.set_fail_on_validation_error(true); 537fd4e5da5Sopenharmony_ci 538fd4e5da5Sopenharmony_ci // Reduction should fail because the initial state is invalid without the 539fd4e5da5Sopenharmony_ci // "skip-block-layout" validator option. Note that the interestingness test 540fd4e5da5Sopenharmony_ci // always returns true. 541fd4e5da5Sopenharmony_ci { 542fd4e5da5Sopenharmony_ci Reducer reducer(env); 543fd4e5da5Sopenharmony_ci SetupReducerForCheckValidationOptions(&reducer); 544fd4e5da5Sopenharmony_ci 545fd4e5da5Sopenharmony_ci Reducer::ReductionResultStatus status = 546fd4e5da5Sopenharmony_ci reducer.Run(std::vector<uint32_t>(binary_in), &binary_out, 547fd4e5da5Sopenharmony_ci reducer_options, validator_options); 548fd4e5da5Sopenharmony_ci 549fd4e5da5Sopenharmony_ci ASSERT_EQ(status, Reducer::ReductionResultStatus::kInitialStateInvalid); 550fd4e5da5Sopenharmony_ci } 551fd4e5da5Sopenharmony_ci 552fd4e5da5Sopenharmony_ci // Try again with validator option. 553fd4e5da5Sopenharmony_ci validator_options.SetSkipBlockLayout(true); 554fd4e5da5Sopenharmony_ci 555fd4e5da5Sopenharmony_ci // Reduction should hit step limit; module is seen as valid, interestingness 556fd4e5da5Sopenharmony_ci // test always succeeds, and the finder yields infinite opportunities. 557fd4e5da5Sopenharmony_ci { 558fd4e5da5Sopenharmony_ci Reducer reducer(env); 559fd4e5da5Sopenharmony_ci SetupReducerForCheckValidationOptions(&reducer); 560fd4e5da5Sopenharmony_ci 561fd4e5da5Sopenharmony_ci Reducer::ReductionResultStatus status = 562fd4e5da5Sopenharmony_ci reducer.Run(std::vector<uint32_t>(binary_in), &binary_out, 563fd4e5da5Sopenharmony_ci reducer_options, validator_options); 564fd4e5da5Sopenharmony_ci 565fd4e5da5Sopenharmony_ci ASSERT_EQ(status, Reducer::ReductionResultStatus::kReachedStepLimit); 566fd4e5da5Sopenharmony_ci } 567fd4e5da5Sopenharmony_ci 568fd4e5da5Sopenharmony_ci // Now set a limit on the number of local variables. 569fd4e5da5Sopenharmony_ci validator_options.SetUniversalLimit(spv_validator_limit_max_local_variables, 570fd4e5da5Sopenharmony_ci 2); 571fd4e5da5Sopenharmony_ci 572fd4e5da5Sopenharmony_ci // Reduction should now fail due to reaching an invalid state; after one step, 573fd4e5da5Sopenharmony_ci // a local variable is added and the module becomes "invalid" given the 574fd4e5da5Sopenharmony_ci // validator limits. 575fd4e5da5Sopenharmony_ci { 576fd4e5da5Sopenharmony_ci Reducer reducer(env); 577fd4e5da5Sopenharmony_ci SetupReducerForCheckValidationOptions(&reducer); 578fd4e5da5Sopenharmony_ci 579fd4e5da5Sopenharmony_ci Reducer::ReductionResultStatus status = 580fd4e5da5Sopenharmony_ci reducer.Run(std::vector<uint32_t>(binary_in), &binary_out, 581fd4e5da5Sopenharmony_ci reducer_options, validator_options); 582fd4e5da5Sopenharmony_ci 583fd4e5da5Sopenharmony_ci ASSERT_EQ(status, Reducer::ReductionResultStatus::kStateInvalid); 584fd4e5da5Sopenharmony_ci } 585fd4e5da5Sopenharmony_ci} 586fd4e5da5Sopenharmony_ci 587fd4e5da5Sopenharmony_ci} // namespace 588fd4e5da5Sopenharmony_ci} // namespace reduce 589fd4e5da5Sopenharmony_ci} // namespace spvtools 590