1fd4e5da5Sopenharmony_ci// Copyright (c) 2020 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/fuzz/transformation_function_call.h" 16fd4e5da5Sopenharmony_ci 17fd4e5da5Sopenharmony_ci#include "gtest/gtest.h" 18fd4e5da5Sopenharmony_ci#include "source/fuzz/fuzzer_util.h" 19fd4e5da5Sopenharmony_ci#include "source/fuzz/instruction_descriptor.h" 20fd4e5da5Sopenharmony_ci#include "test/fuzz/fuzz_test_util.h" 21fd4e5da5Sopenharmony_ci 22fd4e5da5Sopenharmony_cinamespace spvtools { 23fd4e5da5Sopenharmony_cinamespace fuzz { 24fd4e5da5Sopenharmony_cinamespace { 25fd4e5da5Sopenharmony_ci 26fd4e5da5Sopenharmony_ciTEST(TransformationFunctionCallTest, BasicTest) { 27fd4e5da5Sopenharmony_ci std::string shader = R"( 28fd4e5da5Sopenharmony_ci OpCapability Shader 29fd4e5da5Sopenharmony_ci %1 = OpExtInstImport "GLSL.std.450" 30fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 31fd4e5da5Sopenharmony_ci OpEntryPoint Fragment %4 "main" 32fd4e5da5Sopenharmony_ci OpExecutionMode %4 OriginUpperLeft 33fd4e5da5Sopenharmony_ci OpSource ESSL 310 34fd4e5da5Sopenharmony_ci %2 = OpTypeVoid 35fd4e5da5Sopenharmony_ci %3 = OpTypeFunction %2 36fd4e5da5Sopenharmony_ci %6 = OpTypeInt 32 1 37fd4e5da5Sopenharmony_ci %7 = OpTypePointer Function %6 38fd4e5da5Sopenharmony_ci %8 = OpTypeFunction %6 %7 39fd4e5da5Sopenharmony_ci %12 = OpTypeFloat 32 40fd4e5da5Sopenharmony_ci %13 = OpTypePointer Function %12 41fd4e5da5Sopenharmony_ci %14 = OpTypeFunction %6 %7 %13 42fd4e5da5Sopenharmony_ci %27 = OpConstant %6 1 43fd4e5da5Sopenharmony_ci %50 = OpConstant %12 1 44fd4e5da5Sopenharmony_ci %57 = OpTypeBool 45fd4e5da5Sopenharmony_ci %58 = OpConstantFalse %57 46fd4e5da5Sopenharmony_ci %204 = OpUndef %6 47fd4e5da5Sopenharmony_ci %4 = OpFunction %2 None %3 48fd4e5da5Sopenharmony_ci %5 = OpLabel 49fd4e5da5Sopenharmony_ci %61 = OpVariable %7 Function 50fd4e5da5Sopenharmony_ci %62 = OpVariable %7 Function 51fd4e5da5Sopenharmony_ci %65 = OpVariable %13 Function 52fd4e5da5Sopenharmony_ci %66 = OpVariable %7 Function 53fd4e5da5Sopenharmony_ci %68 = OpVariable %13 Function 54fd4e5da5Sopenharmony_ci %71 = OpVariable %7 Function 55fd4e5da5Sopenharmony_ci %72 = OpVariable %13 Function 56fd4e5da5Sopenharmony_ci %73 = OpVariable %7 Function 57fd4e5da5Sopenharmony_ci %75 = OpVariable %13 Function 58fd4e5da5Sopenharmony_ci %78 = OpVariable %7 Function 59fd4e5da5Sopenharmony_ci %98 = OpAccessChain %7 %71 60fd4e5da5Sopenharmony_ci %99 = OpCopyObject %7 %71 61fd4e5da5Sopenharmony_ci OpSelectionMerge %60 None 62fd4e5da5Sopenharmony_ci OpBranchConditional %58 %59 %60 63fd4e5da5Sopenharmony_ci %59 = OpLabel 64fd4e5da5Sopenharmony_ci OpBranch %60 65fd4e5da5Sopenharmony_ci %60 = OpLabel 66fd4e5da5Sopenharmony_ci OpReturn 67fd4e5da5Sopenharmony_ci OpFunctionEnd 68fd4e5da5Sopenharmony_ci %10 = OpFunction %6 None %8 69fd4e5da5Sopenharmony_ci %9 = OpFunctionParameter %7 70fd4e5da5Sopenharmony_ci %11 = OpLabel 71fd4e5da5Sopenharmony_ci %26 = OpLoad %6 %9 72fd4e5da5Sopenharmony_ci %28 = OpIAdd %6 %26 %27 73fd4e5da5Sopenharmony_ci OpSelectionMerge %97 None 74fd4e5da5Sopenharmony_ci OpBranchConditional %58 %96 %97 75fd4e5da5Sopenharmony_ci %96 = OpLabel 76fd4e5da5Sopenharmony_ci OpBranch %97 77fd4e5da5Sopenharmony_ci %97 = OpLabel 78fd4e5da5Sopenharmony_ci OpReturnValue %28 79fd4e5da5Sopenharmony_ci OpFunctionEnd 80fd4e5da5Sopenharmony_ci %17 = OpFunction %6 None %14 81fd4e5da5Sopenharmony_ci %15 = OpFunctionParameter %7 82fd4e5da5Sopenharmony_ci %16 = OpFunctionParameter %13 83fd4e5da5Sopenharmony_ci %18 = OpLabel 84fd4e5da5Sopenharmony_ci %31 = OpVariable %7 Function 85fd4e5da5Sopenharmony_ci %32 = OpLoad %6 %15 86fd4e5da5Sopenharmony_ci OpStore %31 %32 87fd4e5da5Sopenharmony_ci %33 = OpFunctionCall %6 %10 %31 88fd4e5da5Sopenharmony_ci OpReturnValue %33 89fd4e5da5Sopenharmony_ci OpFunctionEnd 90fd4e5da5Sopenharmony_ci %21 = OpFunction %6 None %14 91fd4e5da5Sopenharmony_ci %19 = OpFunctionParameter %7 92fd4e5da5Sopenharmony_ci %20 = OpFunctionParameter %13 93fd4e5da5Sopenharmony_ci %22 = OpLabel 94fd4e5da5Sopenharmony_ci %36 = OpLoad %6 %19 95fd4e5da5Sopenharmony_ci %37 = OpLoad %12 %20 96fd4e5da5Sopenharmony_ci %38 = OpConvertFToS %6 %37 97fd4e5da5Sopenharmony_ci %39 = OpIAdd %6 %36 %38 98fd4e5da5Sopenharmony_ci OpReturnValue %39 99fd4e5da5Sopenharmony_ci OpFunctionEnd 100fd4e5da5Sopenharmony_ci %24 = OpFunction %6 None %8 101fd4e5da5Sopenharmony_ci %23 = OpFunctionParameter %7 102fd4e5da5Sopenharmony_ci %25 = OpLabel 103fd4e5da5Sopenharmony_ci %44 = OpVariable %7 Function 104fd4e5da5Sopenharmony_ci %46 = OpVariable %13 Function 105fd4e5da5Sopenharmony_ci %51 = OpVariable %7 Function 106fd4e5da5Sopenharmony_ci %52 = OpVariable %13 Function 107fd4e5da5Sopenharmony_ci %42 = OpLoad %6 %23 108fd4e5da5Sopenharmony_ci %43 = OpConvertSToF %12 %42 109fd4e5da5Sopenharmony_ci %45 = OpLoad %6 %23 110fd4e5da5Sopenharmony_ci OpStore %44 %45 111fd4e5da5Sopenharmony_ci OpStore %46 %43 112fd4e5da5Sopenharmony_ci %47 = OpFunctionCall %6 %17 %44 %46 113fd4e5da5Sopenharmony_ci %48 = OpLoad %6 %23 114fd4e5da5Sopenharmony_ci %49 = OpIAdd %6 %48 %27 115fd4e5da5Sopenharmony_ci OpStore %51 %49 116fd4e5da5Sopenharmony_ci OpStore %52 %50 117fd4e5da5Sopenharmony_ci %53 = OpFunctionCall %6 %17 %51 %52 118fd4e5da5Sopenharmony_ci %54 = OpIAdd %6 %47 %53 119fd4e5da5Sopenharmony_ci OpReturnValue %54 120fd4e5da5Sopenharmony_ci OpFunctionEnd 121fd4e5da5Sopenharmony_ci %200 = OpFunction %6 None %14 122fd4e5da5Sopenharmony_ci %201 = OpFunctionParameter %7 123fd4e5da5Sopenharmony_ci %202 = OpFunctionParameter %13 124fd4e5da5Sopenharmony_ci %203 = OpLabel 125fd4e5da5Sopenharmony_ci OpSelectionMerge %206 None 126fd4e5da5Sopenharmony_ci OpBranchConditional %58 %205 %206 127fd4e5da5Sopenharmony_ci %205 = OpLabel 128fd4e5da5Sopenharmony_ci OpBranch %206 129fd4e5da5Sopenharmony_ci %206 = OpLabel 130fd4e5da5Sopenharmony_ci OpReturnValue %204 131fd4e5da5Sopenharmony_ci OpFunctionEnd 132fd4e5da5Sopenharmony_ci )"; 133fd4e5da5Sopenharmony_ci 134fd4e5da5Sopenharmony_ci const auto env = SPV_ENV_UNIVERSAL_1_4; 135fd4e5da5Sopenharmony_ci const auto consumer = nullptr; 136fd4e5da5Sopenharmony_ci const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); 137fd4e5da5Sopenharmony_ci spvtools::ValidatorOptions validator_options; 138fd4e5da5Sopenharmony_ci ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 139fd4e5da5Sopenharmony_ci kConsoleMessageConsumer)); 140fd4e5da5Sopenharmony_ci TransformationContext transformation_context( 141fd4e5da5Sopenharmony_ci MakeUnique<FactManager>(context.get()), validator_options); 142fd4e5da5Sopenharmony_ci transformation_context.GetFactManager()->AddFactBlockIsDead(59); 143fd4e5da5Sopenharmony_ci transformation_context.GetFactManager()->AddFactBlockIsDead(11); 144fd4e5da5Sopenharmony_ci transformation_context.GetFactManager()->AddFactBlockIsDead(18); 145fd4e5da5Sopenharmony_ci transformation_context.GetFactManager()->AddFactBlockIsDead(25); 146fd4e5da5Sopenharmony_ci transformation_context.GetFactManager()->AddFactBlockIsDead(96); 147fd4e5da5Sopenharmony_ci transformation_context.GetFactManager()->AddFactBlockIsDead(205); 148fd4e5da5Sopenharmony_ci transformation_context.GetFactManager()->AddFactFunctionIsLivesafe(21); 149fd4e5da5Sopenharmony_ci transformation_context.GetFactManager()->AddFactFunctionIsLivesafe(200); 150fd4e5da5Sopenharmony_ci transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant( 151fd4e5da5Sopenharmony_ci 71); 152fd4e5da5Sopenharmony_ci transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant( 153fd4e5da5Sopenharmony_ci 72); 154fd4e5da5Sopenharmony_ci transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant( 155fd4e5da5Sopenharmony_ci 19); 156fd4e5da5Sopenharmony_ci transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant( 157fd4e5da5Sopenharmony_ci 20); 158fd4e5da5Sopenharmony_ci transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant( 159fd4e5da5Sopenharmony_ci 23); 160fd4e5da5Sopenharmony_ci transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant( 161fd4e5da5Sopenharmony_ci 44); 162fd4e5da5Sopenharmony_ci transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant( 163fd4e5da5Sopenharmony_ci 46); 164fd4e5da5Sopenharmony_ci transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant( 165fd4e5da5Sopenharmony_ci 51); 166fd4e5da5Sopenharmony_ci transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant( 167fd4e5da5Sopenharmony_ci 52); 168fd4e5da5Sopenharmony_ci 169fd4e5da5Sopenharmony_ci // Livesafe functions with argument types: 21(7, 13), 200(7, 13) 170fd4e5da5Sopenharmony_ci // Non-livesafe functions with argument types: 4(), 10(7), 17(7, 13), 24(7) 171fd4e5da5Sopenharmony_ci // Call graph edges: 172fd4e5da5Sopenharmony_ci // 17 -> 10 173fd4e5da5Sopenharmony_ci // 24 -> 17 174fd4e5da5Sopenharmony_ci 175fd4e5da5Sopenharmony_ci // Bad transformations 176fd4e5da5Sopenharmony_ci // Too many arguments 177fd4e5da5Sopenharmony_ci ASSERT_FALSE(TransformationFunctionCall( 178fd4e5da5Sopenharmony_ci 100, 21, {71, 72, 71}, 179fd4e5da5Sopenharmony_ci MakeInstructionDescriptor(59, spv::Op::OpBranch, 0)) 180fd4e5da5Sopenharmony_ci .IsApplicable(context.get(), transformation_context)); 181fd4e5da5Sopenharmony_ci // Too few arguments 182fd4e5da5Sopenharmony_ci ASSERT_FALSE( 183fd4e5da5Sopenharmony_ci TransformationFunctionCall( 184fd4e5da5Sopenharmony_ci 100, 21, {71}, MakeInstructionDescriptor(59, spv::Op::OpBranch, 0)) 185fd4e5da5Sopenharmony_ci .IsApplicable(context.get(), transformation_context)); 186fd4e5da5Sopenharmony_ci // Arguments are the wrong way around (types do not match) 187fd4e5da5Sopenharmony_ci ASSERT_FALSE(TransformationFunctionCall( 188fd4e5da5Sopenharmony_ci 100, 21, {72, 71}, 189fd4e5da5Sopenharmony_ci MakeInstructionDescriptor(59, spv::Op::OpBranch, 0)) 190fd4e5da5Sopenharmony_ci .IsApplicable(context.get(), transformation_context)); 191fd4e5da5Sopenharmony_ci // 21 is not an appropriate argument 192fd4e5da5Sopenharmony_ci ASSERT_FALSE(TransformationFunctionCall( 193fd4e5da5Sopenharmony_ci 100, 21, {21, 72}, 194fd4e5da5Sopenharmony_ci MakeInstructionDescriptor(59, spv::Op::OpBranch, 0)) 195fd4e5da5Sopenharmony_ci .IsApplicable(context.get(), transformation_context)); 196fd4e5da5Sopenharmony_ci // 300 does not exist 197fd4e5da5Sopenharmony_ci ASSERT_FALSE(TransformationFunctionCall( 198fd4e5da5Sopenharmony_ci 100, 21, {300, 72}, 199fd4e5da5Sopenharmony_ci MakeInstructionDescriptor(59, spv::Op::OpBranch, 0)) 200fd4e5da5Sopenharmony_ci .IsApplicable(context.get(), transformation_context)); 201fd4e5da5Sopenharmony_ci // 71 is not a function 202fd4e5da5Sopenharmony_ci ASSERT_FALSE(TransformationFunctionCall( 203fd4e5da5Sopenharmony_ci 100, 71, {71, 72}, 204fd4e5da5Sopenharmony_ci MakeInstructionDescriptor(59, spv::Op::OpBranch, 0)) 205fd4e5da5Sopenharmony_ci .IsApplicable(context.get(), transformation_context)); 206fd4e5da5Sopenharmony_ci // 500 does not exist 207fd4e5da5Sopenharmony_ci ASSERT_FALSE(TransformationFunctionCall( 208fd4e5da5Sopenharmony_ci 100, 500, {71, 72}, 209fd4e5da5Sopenharmony_ci MakeInstructionDescriptor(59, spv::Op::OpBranch, 0)) 210fd4e5da5Sopenharmony_ci .IsApplicable(context.get(), transformation_context)); 211fd4e5da5Sopenharmony_ci // Id is not fresh 212fd4e5da5Sopenharmony_ci ASSERT_FALSE( 213fd4e5da5Sopenharmony_ci TransformationFunctionCall( 214fd4e5da5Sopenharmony_ci 21, 21, {71, 72}, MakeInstructionDescriptor(59, spv::Op::OpBranch, 0)) 215fd4e5da5Sopenharmony_ci .IsApplicable(context.get(), transformation_context)); 216fd4e5da5Sopenharmony_ci // Access chain as pointer parameter 217fd4e5da5Sopenharmony_ci ASSERT_FALSE(TransformationFunctionCall( 218fd4e5da5Sopenharmony_ci 100, 21, {98, 72}, 219fd4e5da5Sopenharmony_ci MakeInstructionDescriptor(59, spv::Op::OpBranch, 0)) 220fd4e5da5Sopenharmony_ci .IsApplicable(context.get(), transformation_context)); 221fd4e5da5Sopenharmony_ci // Copied object as pointer parameter 222fd4e5da5Sopenharmony_ci ASSERT_FALSE(TransformationFunctionCall( 223fd4e5da5Sopenharmony_ci 100, 21, {99, 72}, 224fd4e5da5Sopenharmony_ci MakeInstructionDescriptor(59, spv::Op::OpBranch, 0)) 225fd4e5da5Sopenharmony_ci .IsApplicable(context.get(), transformation_context)); 226fd4e5da5Sopenharmony_ci // Non-livesafe called from original live block 227fd4e5da5Sopenharmony_ci ASSERT_FALSE(TransformationFunctionCall( 228fd4e5da5Sopenharmony_ci 100, 10, {71}, 229fd4e5da5Sopenharmony_ci MakeInstructionDescriptor(99, spv::Op::OpSelectionMerge, 0)) 230fd4e5da5Sopenharmony_ci .IsApplicable(context.get(), transformation_context)); 231fd4e5da5Sopenharmony_ci // Non-livesafe called from livesafe function 232fd4e5da5Sopenharmony_ci ASSERT_FALSE(TransformationFunctionCall( 233fd4e5da5Sopenharmony_ci 100, 10, {19}, 234fd4e5da5Sopenharmony_ci MakeInstructionDescriptor(38, spv::Op::OpConvertFToS, 0)) 235fd4e5da5Sopenharmony_ci .IsApplicable(context.get(), transformation_context)); 236fd4e5da5Sopenharmony_ci // Livesafe function called with pointer to non-arbitrary local variable 237fd4e5da5Sopenharmony_ci ASSERT_FALSE(TransformationFunctionCall( 238fd4e5da5Sopenharmony_ci 100, 21, {61, 72}, 239fd4e5da5Sopenharmony_ci MakeInstructionDescriptor(38, spv::Op::OpConvertFToS, 0)) 240fd4e5da5Sopenharmony_ci .IsApplicable(context.get(), transformation_context)); 241fd4e5da5Sopenharmony_ci // Direct recursion 242fd4e5da5Sopenharmony_ci ASSERT_FALSE( 243fd4e5da5Sopenharmony_ci TransformationFunctionCall( 244fd4e5da5Sopenharmony_ci 100, 4, {}, MakeInstructionDescriptor(59, spv::Op::OpBranch, 0)) 245fd4e5da5Sopenharmony_ci .IsApplicable(context.get(), transformation_context)); 246fd4e5da5Sopenharmony_ci // Indirect recursion 247fd4e5da5Sopenharmony_ci ASSERT_FALSE( 248fd4e5da5Sopenharmony_ci TransformationFunctionCall( 249fd4e5da5Sopenharmony_ci 100, 24, {9}, MakeInstructionDescriptor(96, spv::Op::OpBranch, 0)) 250fd4e5da5Sopenharmony_ci .IsApplicable(context.get(), transformation_context)); 251fd4e5da5Sopenharmony_ci // Parameter 23 is not available at the call site 252fd4e5da5Sopenharmony_ci ASSERT_FALSE( 253fd4e5da5Sopenharmony_ci TransformationFunctionCall( 254fd4e5da5Sopenharmony_ci 104, 10, {23}, MakeInstructionDescriptor(205, spv::Op::OpBranch, 0)) 255fd4e5da5Sopenharmony_ci .IsApplicable(context.get(), transformation_context)); 256fd4e5da5Sopenharmony_ci 257fd4e5da5Sopenharmony_ci // Good transformations 258fd4e5da5Sopenharmony_ci { 259fd4e5da5Sopenharmony_ci // Livesafe called from dead block: fine 260fd4e5da5Sopenharmony_ci TransformationFunctionCall transformation( 261fd4e5da5Sopenharmony_ci 100, 21, {71, 72}, MakeInstructionDescriptor(59, spv::Op::OpBranch, 0)); 262fd4e5da5Sopenharmony_ci ASSERT_TRUE( 263fd4e5da5Sopenharmony_ci transformation.IsApplicable(context.get(), transformation_context)); 264fd4e5da5Sopenharmony_ci ApplyAndCheckFreshIds(transformation, context.get(), 265fd4e5da5Sopenharmony_ci &transformation_context); 266fd4e5da5Sopenharmony_ci ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed( 267fd4e5da5Sopenharmony_ci context.get(), validator_options, kConsoleMessageConsumer)); 268fd4e5da5Sopenharmony_ci } 269fd4e5da5Sopenharmony_ci { 270fd4e5da5Sopenharmony_ci // Livesafe called from original live block: fine 271fd4e5da5Sopenharmony_ci TransformationFunctionCall transformation( 272fd4e5da5Sopenharmony_ci 101, 21, {71, 72}, 273fd4e5da5Sopenharmony_ci MakeInstructionDescriptor(98, spv::Op::OpAccessChain, 0)); 274fd4e5da5Sopenharmony_ci ASSERT_TRUE( 275fd4e5da5Sopenharmony_ci transformation.IsApplicable(context.get(), transformation_context)); 276fd4e5da5Sopenharmony_ci ApplyAndCheckFreshIds(transformation, context.get(), 277fd4e5da5Sopenharmony_ci &transformation_context); 278fd4e5da5Sopenharmony_ci ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed( 279fd4e5da5Sopenharmony_ci context.get(), validator_options, kConsoleMessageConsumer)); 280fd4e5da5Sopenharmony_ci } 281fd4e5da5Sopenharmony_ci { 282fd4e5da5Sopenharmony_ci // Livesafe called from livesafe function: fine 283fd4e5da5Sopenharmony_ci TransformationFunctionCall transformation( 284fd4e5da5Sopenharmony_ci 102, 200, {19, 20}, MakeInstructionDescriptor(36, spv::Op::OpLoad, 0)); 285fd4e5da5Sopenharmony_ci ASSERT_TRUE( 286fd4e5da5Sopenharmony_ci transformation.IsApplicable(context.get(), transformation_context)); 287fd4e5da5Sopenharmony_ci ApplyAndCheckFreshIds(transformation, context.get(), 288fd4e5da5Sopenharmony_ci &transformation_context); 289fd4e5da5Sopenharmony_ci ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed( 290fd4e5da5Sopenharmony_ci context.get(), validator_options, kConsoleMessageConsumer)); 291fd4e5da5Sopenharmony_ci } 292fd4e5da5Sopenharmony_ci { 293fd4e5da5Sopenharmony_ci // Dead called from dead block in injected function: fine 294fd4e5da5Sopenharmony_ci TransformationFunctionCall transformation( 295fd4e5da5Sopenharmony_ci 103, 10, {23}, MakeInstructionDescriptor(45, spv::Op::OpLoad, 0)); 296fd4e5da5Sopenharmony_ci ASSERT_TRUE( 297fd4e5da5Sopenharmony_ci transformation.IsApplicable(context.get(), transformation_context)); 298fd4e5da5Sopenharmony_ci ApplyAndCheckFreshIds(transformation, context.get(), 299fd4e5da5Sopenharmony_ci &transformation_context); 300fd4e5da5Sopenharmony_ci ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed( 301fd4e5da5Sopenharmony_ci context.get(), validator_options, kConsoleMessageConsumer)); 302fd4e5da5Sopenharmony_ci } 303fd4e5da5Sopenharmony_ci { 304fd4e5da5Sopenharmony_ci // Non-livesafe called from dead block in livesafe function: OK 305fd4e5da5Sopenharmony_ci TransformationFunctionCall transformation( 306fd4e5da5Sopenharmony_ci 104, 10, {201}, MakeInstructionDescriptor(205, spv::Op::OpBranch, 0)); 307fd4e5da5Sopenharmony_ci ASSERT_TRUE( 308fd4e5da5Sopenharmony_ci transformation.IsApplicable(context.get(), transformation_context)); 309fd4e5da5Sopenharmony_ci ApplyAndCheckFreshIds(transformation, context.get(), 310fd4e5da5Sopenharmony_ci &transformation_context); 311fd4e5da5Sopenharmony_ci ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed( 312fd4e5da5Sopenharmony_ci context.get(), validator_options, kConsoleMessageConsumer)); 313fd4e5da5Sopenharmony_ci } 314fd4e5da5Sopenharmony_ci { 315fd4e5da5Sopenharmony_ci // Livesafe called from dead block with non-arbitrary parameter 316fd4e5da5Sopenharmony_ci TransformationFunctionCall transformation( 317fd4e5da5Sopenharmony_ci 105, 21, {62, 65}, MakeInstructionDescriptor(59, spv::Op::OpBranch, 0)); 318fd4e5da5Sopenharmony_ci ASSERT_TRUE( 319fd4e5da5Sopenharmony_ci transformation.IsApplicable(context.get(), transformation_context)); 320fd4e5da5Sopenharmony_ci ApplyAndCheckFreshIds(transformation, context.get(), 321fd4e5da5Sopenharmony_ci &transformation_context); 322fd4e5da5Sopenharmony_ci ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed( 323fd4e5da5Sopenharmony_ci context.get(), validator_options, kConsoleMessageConsumer)); 324fd4e5da5Sopenharmony_ci } 325fd4e5da5Sopenharmony_ci 326fd4e5da5Sopenharmony_ci std::string after_transformation = R"( 327fd4e5da5Sopenharmony_ci OpCapability Shader 328fd4e5da5Sopenharmony_ci %1 = OpExtInstImport "GLSL.std.450" 329fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 330fd4e5da5Sopenharmony_ci OpEntryPoint Fragment %4 "main" 331fd4e5da5Sopenharmony_ci OpExecutionMode %4 OriginUpperLeft 332fd4e5da5Sopenharmony_ci OpSource ESSL 310 333fd4e5da5Sopenharmony_ci %2 = OpTypeVoid 334fd4e5da5Sopenharmony_ci %3 = OpTypeFunction %2 335fd4e5da5Sopenharmony_ci %6 = OpTypeInt 32 1 336fd4e5da5Sopenharmony_ci %7 = OpTypePointer Function %6 337fd4e5da5Sopenharmony_ci %8 = OpTypeFunction %6 %7 338fd4e5da5Sopenharmony_ci %12 = OpTypeFloat 32 339fd4e5da5Sopenharmony_ci %13 = OpTypePointer Function %12 340fd4e5da5Sopenharmony_ci %14 = OpTypeFunction %6 %7 %13 341fd4e5da5Sopenharmony_ci %27 = OpConstant %6 1 342fd4e5da5Sopenharmony_ci %50 = OpConstant %12 1 343fd4e5da5Sopenharmony_ci %57 = OpTypeBool 344fd4e5da5Sopenharmony_ci %58 = OpConstantFalse %57 345fd4e5da5Sopenharmony_ci %204 = OpUndef %6 346fd4e5da5Sopenharmony_ci %4 = OpFunction %2 None %3 347fd4e5da5Sopenharmony_ci %5 = OpLabel 348fd4e5da5Sopenharmony_ci %61 = OpVariable %7 Function 349fd4e5da5Sopenharmony_ci %62 = OpVariable %7 Function 350fd4e5da5Sopenharmony_ci %65 = OpVariable %13 Function 351fd4e5da5Sopenharmony_ci %66 = OpVariable %7 Function 352fd4e5da5Sopenharmony_ci %68 = OpVariable %13 Function 353fd4e5da5Sopenharmony_ci %71 = OpVariable %7 Function 354fd4e5da5Sopenharmony_ci %72 = OpVariable %13 Function 355fd4e5da5Sopenharmony_ci %73 = OpVariable %7 Function 356fd4e5da5Sopenharmony_ci %75 = OpVariable %13 Function 357fd4e5da5Sopenharmony_ci %78 = OpVariable %7 Function 358fd4e5da5Sopenharmony_ci %101 = OpFunctionCall %6 %21 %71 %72 359fd4e5da5Sopenharmony_ci %98 = OpAccessChain %7 %71 360fd4e5da5Sopenharmony_ci %99 = OpCopyObject %7 %71 361fd4e5da5Sopenharmony_ci OpSelectionMerge %60 None 362fd4e5da5Sopenharmony_ci OpBranchConditional %58 %59 %60 363fd4e5da5Sopenharmony_ci %59 = OpLabel 364fd4e5da5Sopenharmony_ci %100 = OpFunctionCall %6 %21 %71 %72 365fd4e5da5Sopenharmony_ci %105 = OpFunctionCall %6 %21 %62 %65 366fd4e5da5Sopenharmony_ci OpBranch %60 367fd4e5da5Sopenharmony_ci %60 = OpLabel 368fd4e5da5Sopenharmony_ci OpReturn 369fd4e5da5Sopenharmony_ci OpFunctionEnd 370fd4e5da5Sopenharmony_ci %10 = OpFunction %6 None %8 371fd4e5da5Sopenharmony_ci %9 = OpFunctionParameter %7 372fd4e5da5Sopenharmony_ci %11 = OpLabel 373fd4e5da5Sopenharmony_ci %26 = OpLoad %6 %9 374fd4e5da5Sopenharmony_ci %28 = OpIAdd %6 %26 %27 375fd4e5da5Sopenharmony_ci OpSelectionMerge %97 None 376fd4e5da5Sopenharmony_ci OpBranchConditional %58 %96 %97 377fd4e5da5Sopenharmony_ci %96 = OpLabel 378fd4e5da5Sopenharmony_ci OpBranch %97 379fd4e5da5Sopenharmony_ci %97 = OpLabel 380fd4e5da5Sopenharmony_ci OpReturnValue %28 381fd4e5da5Sopenharmony_ci OpFunctionEnd 382fd4e5da5Sopenharmony_ci %17 = OpFunction %6 None %14 383fd4e5da5Sopenharmony_ci %15 = OpFunctionParameter %7 384fd4e5da5Sopenharmony_ci %16 = OpFunctionParameter %13 385fd4e5da5Sopenharmony_ci %18 = OpLabel 386fd4e5da5Sopenharmony_ci %31 = OpVariable %7 Function 387fd4e5da5Sopenharmony_ci %32 = OpLoad %6 %15 388fd4e5da5Sopenharmony_ci OpStore %31 %32 389fd4e5da5Sopenharmony_ci %33 = OpFunctionCall %6 %10 %31 390fd4e5da5Sopenharmony_ci OpReturnValue %33 391fd4e5da5Sopenharmony_ci OpFunctionEnd 392fd4e5da5Sopenharmony_ci %21 = OpFunction %6 None %14 393fd4e5da5Sopenharmony_ci %19 = OpFunctionParameter %7 394fd4e5da5Sopenharmony_ci %20 = OpFunctionParameter %13 395fd4e5da5Sopenharmony_ci %22 = OpLabel 396fd4e5da5Sopenharmony_ci %102 = OpFunctionCall %6 %200 %19 %20 397fd4e5da5Sopenharmony_ci %36 = OpLoad %6 %19 398fd4e5da5Sopenharmony_ci %37 = OpLoad %12 %20 399fd4e5da5Sopenharmony_ci %38 = OpConvertFToS %6 %37 400fd4e5da5Sopenharmony_ci %39 = OpIAdd %6 %36 %38 401fd4e5da5Sopenharmony_ci OpReturnValue %39 402fd4e5da5Sopenharmony_ci OpFunctionEnd 403fd4e5da5Sopenharmony_ci %24 = OpFunction %6 None %8 404fd4e5da5Sopenharmony_ci %23 = OpFunctionParameter %7 405fd4e5da5Sopenharmony_ci %25 = OpLabel 406fd4e5da5Sopenharmony_ci %44 = OpVariable %7 Function 407fd4e5da5Sopenharmony_ci %46 = OpVariable %13 Function 408fd4e5da5Sopenharmony_ci %51 = OpVariable %7 Function 409fd4e5da5Sopenharmony_ci %52 = OpVariable %13 Function 410fd4e5da5Sopenharmony_ci %42 = OpLoad %6 %23 411fd4e5da5Sopenharmony_ci %43 = OpConvertSToF %12 %42 412fd4e5da5Sopenharmony_ci %103 = OpFunctionCall %6 %10 %23 413fd4e5da5Sopenharmony_ci %45 = OpLoad %6 %23 414fd4e5da5Sopenharmony_ci OpStore %44 %45 415fd4e5da5Sopenharmony_ci OpStore %46 %43 416fd4e5da5Sopenharmony_ci %47 = OpFunctionCall %6 %17 %44 %46 417fd4e5da5Sopenharmony_ci %48 = OpLoad %6 %23 418fd4e5da5Sopenharmony_ci %49 = OpIAdd %6 %48 %27 419fd4e5da5Sopenharmony_ci OpStore %51 %49 420fd4e5da5Sopenharmony_ci OpStore %52 %50 421fd4e5da5Sopenharmony_ci %53 = OpFunctionCall %6 %17 %51 %52 422fd4e5da5Sopenharmony_ci %54 = OpIAdd %6 %47 %53 423fd4e5da5Sopenharmony_ci OpReturnValue %54 424fd4e5da5Sopenharmony_ci OpFunctionEnd 425fd4e5da5Sopenharmony_ci %200 = OpFunction %6 None %14 426fd4e5da5Sopenharmony_ci %201 = OpFunctionParameter %7 427fd4e5da5Sopenharmony_ci %202 = OpFunctionParameter %13 428fd4e5da5Sopenharmony_ci %203 = OpLabel 429fd4e5da5Sopenharmony_ci OpSelectionMerge %206 None 430fd4e5da5Sopenharmony_ci OpBranchConditional %58 %205 %206 431fd4e5da5Sopenharmony_ci %205 = OpLabel 432fd4e5da5Sopenharmony_ci %104 = OpFunctionCall %6 %10 %201 433fd4e5da5Sopenharmony_ci OpBranch %206 434fd4e5da5Sopenharmony_ci %206 = OpLabel 435fd4e5da5Sopenharmony_ci OpReturnValue %204 436fd4e5da5Sopenharmony_ci OpFunctionEnd 437fd4e5da5Sopenharmony_ci )"; 438fd4e5da5Sopenharmony_ci ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); 439fd4e5da5Sopenharmony_ci} 440fd4e5da5Sopenharmony_ci 441fd4e5da5Sopenharmony_ciTEST(TransformationFunctionCallTest, DoNotInvokeEntryPoint) { 442fd4e5da5Sopenharmony_ci std::string shader = R"( 443fd4e5da5Sopenharmony_ci OpCapability Shader 444fd4e5da5Sopenharmony_ci %1 = OpExtInstImport "GLSL.std.450" 445fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 446fd4e5da5Sopenharmony_ci OpEntryPoint Fragment %4 "main" 447fd4e5da5Sopenharmony_ci OpExecutionMode %4 OriginUpperLeft 448fd4e5da5Sopenharmony_ci OpSource ESSL 310 449fd4e5da5Sopenharmony_ci %2 = OpTypeVoid 450fd4e5da5Sopenharmony_ci %3 = OpTypeFunction %2 451fd4e5da5Sopenharmony_ci %4 = OpFunction %2 None %3 452fd4e5da5Sopenharmony_ci %5 = OpLabel 453fd4e5da5Sopenharmony_ci OpReturn 454fd4e5da5Sopenharmony_ci OpFunctionEnd 455fd4e5da5Sopenharmony_ci %10 = OpFunction %2 None %3 456fd4e5da5Sopenharmony_ci %11 = OpLabel 457fd4e5da5Sopenharmony_ci OpReturn 458fd4e5da5Sopenharmony_ci OpFunctionEnd 459fd4e5da5Sopenharmony_ci )"; 460fd4e5da5Sopenharmony_ci 461fd4e5da5Sopenharmony_ci const auto env = SPV_ENV_UNIVERSAL_1_4; 462fd4e5da5Sopenharmony_ci const auto consumer = nullptr; 463fd4e5da5Sopenharmony_ci const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); 464fd4e5da5Sopenharmony_ci spvtools::ValidatorOptions validator_options; 465fd4e5da5Sopenharmony_ci ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 466fd4e5da5Sopenharmony_ci kConsoleMessageConsumer)); 467fd4e5da5Sopenharmony_ci TransformationContext transformation_context( 468fd4e5da5Sopenharmony_ci MakeUnique<FactManager>(context.get()), validator_options); 469fd4e5da5Sopenharmony_ci transformation_context.GetFactManager()->AddFactBlockIsDead(11); 470fd4e5da5Sopenharmony_ci 471fd4e5da5Sopenharmony_ci // 4 is an entry point, so it is not legal for it to be the target of a call. 472fd4e5da5Sopenharmony_ci ASSERT_FALSE( 473fd4e5da5Sopenharmony_ci TransformationFunctionCall( 474fd4e5da5Sopenharmony_ci 100, 4, {}, MakeInstructionDescriptor(11, spv::Op::OpReturn, 0)) 475fd4e5da5Sopenharmony_ci .IsApplicable(context.get(), transformation_context)); 476fd4e5da5Sopenharmony_ci} 477fd4e5da5Sopenharmony_ci 478fd4e5da5Sopenharmony_ci} // namespace 479fd4e5da5Sopenharmony_ci} // namespace fuzz 480fd4e5da5Sopenharmony_ci} // namespace spvtools 481