1// Copyright (c) 2020 Vasyl Teliman 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/fuzz/transformation_add_parameter.h" 16 17#include "gtest/gtest.h" 18#include "source/fuzz/fuzzer_util.h" 19#include "test/fuzz/fuzz_test_util.h" 20 21namespace spvtools { 22namespace fuzz { 23namespace { 24 25TEST(TransformationAddParameterTest, NonPointerBasicTest) { 26 std::string shader = R"( 27 OpCapability Shader 28 %1 = OpExtInstImport "GLSL.std.450" 29 OpMemoryModel Logical GLSL450 30 OpEntryPoint Fragment %4 "main" 31 OpExecutionMode %4 OriginUpperLeft 32 OpSource ESSL 310 33 OpName %4 "main" 34 %2 = OpTypeVoid 35 %7 = OpTypeBool 36 %11 = OpTypeInt 32 1 37 %16 = OpTypeFloat 32 38 %51 = OpConstant %11 2 39 %52 = OpTypeArray %16 %51 40 %53 = OpConstant %16 7 41 %54 = OpConstantComposite %52 %53 %53 42 %3 = OpTypeFunction %2 43 %6 = OpTypeFunction %7 %7 44 %8 = OpConstant %11 23 45 %12 = OpConstantTrue %7 46 %15 = OpTypeFunction %2 %16 47 %24 = OpTypeFunction %2 %16 %7 48 %31 = OpTypeStruct %7 %11 49 %32 = OpConstant %16 23 50 %33 = OpConstantComposite %31 %12 %8 51 %41 = OpTypeStruct %11 %16 52 %42 = OpConstantComposite %41 %8 %32 53 %43 = OpTypeFunction %2 %41 54 %44 = OpTypeFunction %2 %41 %7 55 %4 = OpFunction %2 None %3 56 %5 = OpLabel 57 %13 = OpFunctionCall %7 %9 %12 58 OpReturn 59 OpFunctionEnd 60 61 ; adjust type of the function in-place 62 %9 = OpFunction %7 None %6 63 %14 = OpFunctionParameter %7 64 %10 = OpLabel 65 OpReturnValue %12 66 OpFunctionEnd 67 68 ; reuse an existing function type 69 %17 = OpFunction %2 None %15 70 %18 = OpFunctionParameter %16 71 %19 = OpLabel 72 OpReturn 73 OpFunctionEnd 74 %20 = OpFunction %2 None %15 75 %21 = OpFunctionParameter %16 76 %22 = OpLabel 77 OpReturn 78 OpFunctionEnd 79 %25 = OpFunction %2 None %24 80 %26 = OpFunctionParameter %16 81 %27 = OpFunctionParameter %7 82 %28 = OpLabel 83 OpReturn 84 OpFunctionEnd 85 86 ; create a new function type 87 %29 = OpFunction %2 None %3 88 %30 = OpLabel 89 OpReturn 90 OpFunctionEnd 91 92 ; don't adjust the type of the function if it creates a duplicate 93 %34 = OpFunction %2 None %43 94 %35 = OpFunctionParameter %41 95 %36 = OpLabel 96 OpReturn 97 OpFunctionEnd 98 %37 = OpFunction %2 None %44 99 %38 = OpFunctionParameter %41 100 %39 = OpFunctionParameter %7 101 %40 = OpLabel 102 OpReturn 103 OpFunctionEnd 104 )"; 105 106 const auto env = SPV_ENV_UNIVERSAL_1_3; 107 const auto consumer = nullptr; 108 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); 109 spvtools::ValidatorOptions validator_options; 110 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 111 kConsoleMessageConsumer)); 112 TransformationContext transformation_context( 113 MakeUnique<FactManager>(context.get()), validator_options); 114 // Can't modify entry point function. 115 ASSERT_FALSE(TransformationAddParameter(4, 60, 7, {{}}, 61) 116 .IsApplicable(context.get(), transformation_context)); 117 118 // There is no function with result id 60. 119 ASSERT_FALSE(TransformationAddParameter(60, 60, 11, {{}}, 61) 120 .IsApplicable(context.get(), transformation_context)); 121 122 // Parameter id is not fresh. 123 ASSERT_FALSE(TransformationAddParameter(9, 14, 11, {{{13, 8}}}, 61) 124 .IsApplicable(context.get(), transformation_context)); 125 126 // Function type id is not fresh. 127 ASSERT_FALSE(TransformationAddParameter(9, 60, 11, {{{13, 8}}}, 14) 128 .IsApplicable(context.get(), transformation_context)); 129 130 // Function type id and parameter type id are equal. 131 ASSERT_FALSE(TransformationAddParameter(9, 60, 11, {{{13, 8}}}, 60) 132 .IsApplicable(context.get(), transformation_context)); 133 134 // Parameter's initializer doesn't exist. 135 ASSERT_FALSE(TransformationAddParameter(9, 60, 11, {{{13, 60}}}, 61) 136 .IsApplicable(context.get(), transformation_context)); 137 138 // Correct transformations. 139 { 140 TransformationAddParameter correct(9, 60, 11, {{{13, 8}}}, 61); 141 ASSERT_TRUE(correct.IsApplicable(context.get(), transformation_context)); 142 ApplyAndCheckFreshIds(correct, context.get(), &transformation_context); 143 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed( 144 context.get(), validator_options, kConsoleMessageConsumer)); 145 ASSERT_TRUE(transformation_context.GetFactManager()->IdIsIrrelevant(60)); 146 } 147 { 148 TransformationAddParameter correct(9, 68, 52, {{{13, 54}}}, 69); 149 ASSERT_TRUE(correct.IsApplicable(context.get(), transformation_context)); 150 ApplyAndCheckFreshIds(correct, context.get(), &transformation_context); 151 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed( 152 context.get(), validator_options, kConsoleMessageConsumer)); 153 ASSERT_TRUE(transformation_context.GetFactManager()->IdIsIrrelevant(68)); 154 } 155 { 156 TransformationAddParameter correct(17, 62, 7, {{}}, 63); 157 ASSERT_TRUE(correct.IsApplicable(context.get(), transformation_context)); 158 ApplyAndCheckFreshIds(correct, context.get(), &transformation_context); 159 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed( 160 context.get(), validator_options, kConsoleMessageConsumer)); 161 ASSERT_TRUE(transformation_context.GetFactManager()->IdIsIrrelevant(62)); 162 } 163 { 164 TransformationAddParameter correct(29, 64, 31, {{}}, 65); 165 ASSERT_TRUE(correct.IsApplicable(context.get(), transformation_context)); 166 ApplyAndCheckFreshIds(correct, context.get(), &transformation_context); 167 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed( 168 context.get(), validator_options, kConsoleMessageConsumer)); 169 ASSERT_TRUE(transformation_context.GetFactManager()->IdIsIrrelevant(64)); 170 } 171 { 172 TransformationAddParameter correct(34, 66, 7, {{}}, 67); 173 ASSERT_TRUE(correct.IsApplicable(context.get(), transformation_context)); 174 ApplyAndCheckFreshIds(correct, context.get(), &transformation_context); 175 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed( 176 context.get(), validator_options, kConsoleMessageConsumer)); 177 ASSERT_TRUE(transformation_context.GetFactManager()->IdIsIrrelevant(66)); 178 } 179 180 std::string expected_shader = R"( 181 OpCapability Shader 182 %1 = OpExtInstImport "GLSL.std.450" 183 OpMemoryModel Logical GLSL450 184 OpEntryPoint Fragment %4 "main" 185 OpExecutionMode %4 OriginUpperLeft 186 OpSource ESSL 310 187 OpName %4 "main" 188 %2 = OpTypeVoid 189 %7 = OpTypeBool 190 %11 = OpTypeInt 32 1 191 %16 = OpTypeFloat 32 192 %51 = OpConstant %11 2 193 %52 = OpTypeArray %16 %51 194 %53 = OpConstant %16 7 195 %54 = OpConstantComposite %52 %53 %53 196 %3 = OpTypeFunction %2 197 %8 = OpConstant %11 23 198 %12 = OpConstantTrue %7 199 %15 = OpTypeFunction %2 %16 200 %24 = OpTypeFunction %2 %16 %7 201 %31 = OpTypeStruct %7 %11 202 %32 = OpConstant %16 23 203 %33 = OpConstantComposite %31 %12 %8 204 %41 = OpTypeStruct %11 %16 205 %42 = OpConstantComposite %41 %8 %32 206 %44 = OpTypeFunction %2 %41 %7 207 %6 = OpTypeFunction %7 %7 %11 %52 208 %65 = OpTypeFunction %2 %31 209 %4 = OpFunction %2 None %3 210 %5 = OpLabel 211 %13 = OpFunctionCall %7 %9 %12 %8 %54 212 OpReturn 213 OpFunctionEnd 214 215 ; adjust type of the function in-place 216 %9 = OpFunction %7 None %6 217 %14 = OpFunctionParameter %7 218 %60 = OpFunctionParameter %11 219 %68 = OpFunctionParameter %52 220 %10 = OpLabel 221 OpReturnValue %12 222 OpFunctionEnd 223 224 ; reuse an existing function type 225 %17 = OpFunction %2 None %24 226 %18 = OpFunctionParameter %16 227 %62 = OpFunctionParameter %7 228 %19 = OpLabel 229 OpReturn 230 OpFunctionEnd 231 %20 = OpFunction %2 None %15 232 %21 = OpFunctionParameter %16 233 %22 = OpLabel 234 OpReturn 235 OpFunctionEnd 236 %25 = OpFunction %2 None %24 237 %26 = OpFunctionParameter %16 238 %27 = OpFunctionParameter %7 239 %28 = OpLabel 240 OpReturn 241 OpFunctionEnd 242 243 ; create a new function type 244 %29 = OpFunction %2 None %65 245 %64 = OpFunctionParameter %31 246 %30 = OpLabel 247 OpReturn 248 OpFunctionEnd 249 250 ; don't adjust the type of the function if it creates a duplicate 251 %34 = OpFunction %2 None %44 252 %35 = OpFunctionParameter %41 253 %66 = OpFunctionParameter %7 254 %36 = OpLabel 255 OpReturn 256 OpFunctionEnd 257 %37 = OpFunction %2 None %44 258 %38 = OpFunctionParameter %41 259 %39 = OpFunctionParameter %7 260 %40 = OpLabel 261 OpReturn 262 OpFunctionEnd 263 )"; 264 ASSERT_TRUE(IsEqual(env, expected_shader, context.get())); 265} 266 267TEST(TransformationAddParameterTest, NonPointerNotApplicableTest) { 268 // This types handles case of adding a new parameter of a non-pointer type 269 // where the transformation is not applicable. 270 std::string shader = R"( 271 OpCapability Shader 272 %1 = OpExtInstImport "GLSL.std.450" 273 OpMemoryModel Logical GLSL450 274 OpEntryPoint Fragment %4 "main" 275 OpExecutionMode %4 OriginUpperLeft 276 OpSource ESSL 310 277 OpName %4 "main" 278 OpName %6 "fun1(" 279 OpName %12 "fun2(i1;" 280 OpName %11 "a" 281 OpName %14 "fun3(" 282 OpName %24 "f1" 283 OpName %27 "f2" 284 OpName %30 "i1" 285 OpName %31 "i2" 286 OpName %32 "param" 287 OpName %35 "i3" 288 OpName %36 "param" 289 %2 = OpTypeVoid 290 %3 = OpTypeFunction %2 291 %8 = OpTypeInt 32 1 292 %9 = OpTypePointer Function %8 293 %10 = OpTypeFunction %8 %9 294 %18 = OpConstant %8 2 295 %22 = OpTypeFloat 32 296 %23 = OpTypePointer Private %22 297 %24 = OpVariable %23 Private 298 %25 = OpConstant %22 1 299 %26 = OpTypePointer Function %22 300 %28 = OpConstant %22 2 301 %4 = OpFunction %2 None %3 302 %5 = OpLabel 303 %27 = OpVariable %26 Function 304 %30 = OpVariable %9 Function 305 %31 = OpVariable %9 Function 306 %32 = OpVariable %9 Function 307 %35 = OpVariable %9 Function 308 %36 = OpVariable %9 Function 309 OpStore %24 %25 310 OpStore %27 %28 311 %29 = OpFunctionCall %2 %6 312 OpStore %30 %18 313 %33 = OpLoad %8 %30 314 OpStore %32 %33 315 %34 = OpFunctionCall %8 %12 %32 316 OpStore %31 %34 317 %37 = OpLoad %8 %31 318 OpStore %36 %37 319 %38 = OpFunctionCall %8 %12 %36 320 OpStore %35 %38 321 ; %39 = OpFunctionCall %2 %14 322 OpReturn 323 OpFunctionEnd 324 %6 = OpFunction %2 None %3 325 %7 = OpLabel 326 OpReturn 327 OpFunctionEnd 328 %12 = OpFunction %8 None %10 329 %11 = OpFunctionParameter %9 330 %13 = OpLabel 331 %17 = OpLoad %8 %11 332 %19 = OpIAdd %8 %17 %18 333 OpReturnValue %19 334 OpFunctionEnd 335 %14 = OpFunction %2 None %3 336 %15 = OpLabel 337 OpReturn 338 OpFunctionEnd 339 )"; 340 341 const auto env = SPV_ENV_UNIVERSAL_1_3; 342 const auto consumer = nullptr; 343 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); 344 spvtools::ValidatorOptions validator_options; 345 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 346 kConsoleMessageConsumer)); 347 TransformationContext transformation_context( 348 MakeUnique<FactManager>(context.get()), validator_options); 349 // Bad: Id 19 is not available in the caller that has id 34. 350 TransformationAddParameter transformation_bad_1(12, 50, 8, 351 {{{34, 19}, {38, 19}}}, 51); 352 353 ASSERT_FALSE( 354 transformation_bad_1.IsApplicable(context.get(), transformation_context)); 355 356 // Bad: Id 8 does not have a type. 357 TransformationAddParameter transformation_bad_2(12, 50, 8, 358 {{{34, 8}, {38, 8}}}, 51); 359 360 ASSERT_FALSE( 361 transformation_bad_2.IsApplicable(context.get(), transformation_context)); 362 363 // Bad: Types of id 25 and id 18 are different. 364 TransformationAddParameter transformation_bad_3(12, 50, 22, 365 {{{34, 25}, {38, 18}}}, 51); 366 ASSERT_FALSE( 367 transformation_bad_3.IsApplicable(context.get(), transformation_context)); 368 369 // Function with id 14 does not have any callers. 370 // Bad: Id 18 is not a valid type. 371 TransformationAddParameter transformation_bad_4(14, 50, 18, {{}}, 51); 372 ASSERT_FALSE( 373 transformation_bad_4.IsApplicable(context.get(), transformation_context)); 374 375 // Function with id 14 does not have any callers. 376 // Bad: Id 3 refers to OpTypeVoid, which is not supported. 377 TransformationAddParameter transformation_bad_6(14, 50, 3, {{}}, 51); 378 ASSERT_FALSE( 379 transformation_bad_6.IsApplicable(context.get(), transformation_context)); 380} 381 382TEST(TransformationAddParameterTest, PointerFunctionTest) { 383 // This types handles case of adding a new parameter of a pointer type with 384 // storage class Function. 385 std::string shader = R"( 386 OpCapability Shader 387 %1 = OpExtInstImport "GLSL.std.450" 388 OpMemoryModel Logical GLSL450 389 OpEntryPoint Fragment %4 "main" 390 OpExecutionMode %4 OriginUpperLeft 391 OpSource ESSL 310 392 OpName %4 "main" 393 OpName %6 "fun1(" 394 OpName %12 "fun2(i1;" 395 OpName %11 "a" 396 OpName %14 "fun3(" 397 OpName %17 "s" 398 OpName %24 "s" 399 OpName %28 "f1" 400 OpName %31 "f2" 401 OpName %34 "i1" 402 OpName %35 "i2" 403 OpName %36 "param" 404 OpName %39 "i3" 405 OpName %40 "param" 406 %2 = OpTypeVoid 407 %3 = OpTypeFunction %2 408 %8 = OpTypeInt 32 1 409 %9 = OpTypePointer Function %8 410 %10 = OpTypeFunction %8 %9 411 %20 = OpConstant %8 2 412 %25 = OpConstant %8 0 413 %26 = OpTypeFloat 32 414 %27 = OpTypePointer Private %26 415 %28 = OpVariable %27 Private 416 %60 = OpTypePointer Output %26 417 %61 = OpVariable %60 Output 418 %29 = OpConstant %26 1 419 %30 = OpTypePointer Function %26 420 %32 = OpConstant %26 2 421 %4 = OpFunction %2 None %3 422 %5 = OpLabel 423 %31 = OpVariable %30 Function 424 %34 = OpVariable %9 Function 425 %35 = OpVariable %9 Function 426 %36 = OpVariable %9 Function 427 %39 = OpVariable %9 Function 428 %40 = OpVariable %9 Function 429 OpStore %28 %29 430 OpStore %31 %32 431 %33 = OpFunctionCall %2 %6 432 OpStore %34 %20 433 %37 = OpLoad %8 %34 434 OpStore %36 %37 435 %38 = OpFunctionCall %8 %12 %36 436 OpStore %35 %38 437 %41 = OpLoad %8 %35 438 OpStore %40 %41 439 %42 = OpFunctionCall %8 %12 %40 440 OpStore %39 %42 441 %43 = OpFunctionCall %2 %14 442 OpReturn 443 OpFunctionEnd 444 %6 = OpFunction %2 None %3 445 %7 = OpLabel 446 OpReturn 447 OpFunctionEnd 448 %12 = OpFunction %8 None %10 449 %11 = OpFunctionParameter %9 450 %13 = OpLabel 451 %17 = OpVariable %9 Function 452 %18 = OpLoad %8 %11 453 OpStore %17 %18 454 %19 = OpLoad %8 %17 455 %21 = OpIAdd %8 %19 %20 456 OpReturnValue %21 457 OpFunctionEnd 458 %14 = OpFunction %2 None %3 459 %15 = OpLabel 460 %24 = OpVariable %9 Function 461 OpStore %24 %25 462 OpReturn 463 OpFunctionEnd 464 )"; 465 466 const auto env = SPV_ENV_UNIVERSAL_1_3; 467 const auto consumer = nullptr; 468 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); 469 spvtools::ValidatorOptions validator_options; 470 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 471 kConsoleMessageConsumer)); 472 TransformationContext transformation_context( 473 MakeUnique<FactManager>(context.get()), validator_options); 474 // Bad: Pointer of id 61 has storage class Output, which is not supported. 475 TransformationAddParameter transformation_bad_1(12, 50, 60, 476 {{{38, 61}, {42, 61}}}, 51); 477 478 ASSERT_FALSE( 479 transformation_bad_1.IsApplicable(context.get(), transformation_context)); 480 481 // Good: Local variable of id 31 is defined in the caller (main). 482 TransformationAddParameter transformation_good_1(12, 50, 30, 483 {{{38, 31}, {42, 31}}}, 51); 484 ASSERT_TRUE(transformation_good_1.IsApplicable(context.get(), 485 transformation_context)); 486 ApplyAndCheckFreshIds(transformation_good_1, context.get(), 487 &transformation_context); 488 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 489 kConsoleMessageConsumer)); 490 491 // Good: Local variable of id 34 is defined in the caller (main). 492 TransformationAddParameter transformation_good_2(14, 52, 9, {{{43, 34}}}, 53); 493 ASSERT_TRUE(transformation_good_2.IsApplicable(context.get(), 494 transformation_context)); 495 ApplyAndCheckFreshIds(transformation_good_2, context.get(), 496 &transformation_context); 497 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 498 kConsoleMessageConsumer)); 499 500 // Good: Local variable of id 39 is defined in the caller (main). 501 TransformationAddParameter transformation_good_3(6, 54, 9, {{{33, 39}}}, 55); 502 ASSERT_TRUE(transformation_good_3.IsApplicable(context.get(), 503 transformation_context)); 504 ApplyAndCheckFreshIds(transformation_good_3, context.get(), 505 &transformation_context); 506 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 507 kConsoleMessageConsumer)); 508 509 // Good: This adds another pointer parameter to the function of id 6. 510 TransformationAddParameter transformation_good_4(6, 56, 30, {{{33, 31}}}, 57); 511 ASSERT_TRUE(transformation_good_4.IsApplicable(context.get(), 512 transformation_context)); 513 ApplyAndCheckFreshIds(transformation_good_4, context.get(), 514 &transformation_context); 515 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 516 kConsoleMessageConsumer)); 517 518 std::string expected_shader = R"( 519 OpCapability Shader 520 %1 = OpExtInstImport "GLSL.std.450" 521 OpMemoryModel Logical GLSL450 522 OpEntryPoint Fragment %4 "main" 523 OpExecutionMode %4 OriginUpperLeft 524 OpSource ESSL 310 525 OpName %4 "main" 526 OpName %6 "fun1(" 527 OpName %12 "fun2(i1;" 528 OpName %11 "a" 529 OpName %14 "fun3(" 530 OpName %17 "s" 531 OpName %24 "s" 532 OpName %28 "f1" 533 OpName %31 "f2" 534 OpName %34 "i1" 535 OpName %35 "i2" 536 OpName %36 "param" 537 OpName %39 "i3" 538 OpName %40 "param" 539 %2 = OpTypeVoid 540 %3 = OpTypeFunction %2 541 %8 = OpTypeInt 32 1 542 %9 = OpTypePointer Function %8 543 %20 = OpConstant %8 2 544 %25 = OpConstant %8 0 545 %26 = OpTypeFloat 32 546 %27 = OpTypePointer Private %26 547 %28 = OpVariable %27 Private 548 %60 = OpTypePointer Output %26 549 %61 = OpVariable %60 Output 550 %29 = OpConstant %26 1 551 %30 = OpTypePointer Function %26 552 %32 = OpConstant %26 2 553 %10 = OpTypeFunction %8 %9 %30 554 %53 = OpTypeFunction %2 %9 555 %57 = OpTypeFunction %2 %9 %30 556 %4 = OpFunction %2 None %3 557 %5 = OpLabel 558 %31 = OpVariable %30 Function 559 %34 = OpVariable %9 Function 560 %35 = OpVariable %9 Function 561 %36 = OpVariable %9 Function 562 %39 = OpVariable %9 Function 563 %40 = OpVariable %9 Function 564 OpStore %28 %29 565 OpStore %31 %32 566 %33 = OpFunctionCall %2 %6 %39 %31 567 OpStore %34 %20 568 %37 = OpLoad %8 %34 569 OpStore %36 %37 570 %38 = OpFunctionCall %8 %12 %36 %31 571 OpStore %35 %38 572 %41 = OpLoad %8 %35 573 OpStore %40 %41 574 %42 = OpFunctionCall %8 %12 %40 %31 575 OpStore %39 %42 576 %43 = OpFunctionCall %2 %14 %34 577 OpReturn 578 OpFunctionEnd 579 %6 = OpFunction %2 None %57 580 %54 = OpFunctionParameter %9 581 %56 = OpFunctionParameter %30 582 %7 = OpLabel 583 OpReturn 584 OpFunctionEnd 585 %12 = OpFunction %8 None %10 586 %11 = OpFunctionParameter %9 587 %50 = OpFunctionParameter %30 588 %13 = OpLabel 589 %17 = OpVariable %9 Function 590 %18 = OpLoad %8 %11 591 OpStore %17 %18 592 %19 = OpLoad %8 %17 593 %21 = OpIAdd %8 %19 %20 594 OpReturnValue %21 595 OpFunctionEnd 596 %14 = OpFunction %2 None %53 597 %52 = OpFunctionParameter %9 598 %15 = OpLabel 599 %24 = OpVariable %9 Function 600 OpStore %24 %25 601 OpReturn 602 OpFunctionEnd 603 )"; 604 ASSERT_TRUE(IsEqual(env, expected_shader, context.get())); 605} 606 607TEST(TransformationAddParameterTest, PointerPrivateWorkgroupTest) { 608 // This types handles case of adding a new parameter of a pointer type with 609 // storage class Private or Workgroup. 610 std::string shader = R"( 611 OpCapability Shader 612 %1 = OpExtInstImport "GLSL.std.450" 613 OpMemoryModel Logical GLSL450 614 OpEntryPoint Fragment %4 "main" 615 OpExecutionMode %4 OriginUpperLeft 616 OpSource ESSL 310 617 OpName %4 "main" 618 OpName %6 "fun1(" 619 OpName %12 "fun2(i1;" 620 OpName %11 "a" 621 OpName %14 "fun3(" 622 OpName %17 "s" 623 OpName %24 "s" 624 OpName %28 "f1" 625 OpName %31 "f2" 626 OpName %34 "i1" 627 OpName %35 "i2" 628 OpName %36 "param" 629 OpName %39 "i3" 630 OpName %40 "param" 631 %2 = OpTypeVoid 632 %3 = OpTypeFunction %2 633 %8 = OpTypeInt 32 1 634 %9 = OpTypePointer Function %8 635 %10 = OpTypeFunction %8 %9 636 %20 = OpConstant %8 2 637 %25 = OpConstant %8 0 638 %26 = OpTypeFloat 32 639 %27 = OpTypePointer Private %26 640 %28 = OpVariable %27 Private 641 %60 = OpTypePointer Workgroup %26 642 %61 = OpVariable %60 Workgroup 643 %29 = OpConstant %26 1 644 %30 = OpTypePointer Function %26 645 %32 = OpConstant %26 2 646 %4 = OpFunction %2 None %3 647 %5 = OpLabel 648 %31 = OpVariable %30 Function 649 %34 = OpVariable %9 Function 650 %35 = OpVariable %9 Function 651 %36 = OpVariable %9 Function 652 %39 = OpVariable %9 Function 653 %40 = OpVariable %9 Function 654 OpStore %28 %29 655 OpStore %31 %32 656 %33 = OpFunctionCall %2 %6 657 OpStore %34 %20 658 %37 = OpLoad %8 %34 659 OpStore %36 %37 660 %38 = OpFunctionCall %8 %12 %36 661 OpStore %35 %38 662 %41 = OpLoad %8 %35 663 OpStore %40 %41 664 %42 = OpFunctionCall %8 %12 %40 665 OpStore %39 %42 666 %43 = OpFunctionCall %2 %14 667 OpReturn 668 OpFunctionEnd 669 %6 = OpFunction %2 None %3 670 %7 = OpLabel 671 OpReturn 672 OpFunctionEnd 673 %12 = OpFunction %8 None %10 674 %11 = OpFunctionParameter %9 675 %13 = OpLabel 676 %17 = OpVariable %9 Function 677 %18 = OpLoad %8 %11 678 OpStore %17 %18 679 %19 = OpLoad %8 %17 680 %21 = OpIAdd %8 %19 %20 681 OpReturnValue %21 682 OpFunctionEnd 683 %14 = OpFunction %2 None %3 684 %15 = OpLabel 685 %24 = OpVariable %9 Function 686 OpStore %24 %25 687 OpReturn 688 OpFunctionEnd 689 )"; 690 691 const auto env = SPV_ENV_UNIVERSAL_1_3; 692 const auto consumer = nullptr; 693 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); 694 spvtools::ValidatorOptions validator_options; 695 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 696 kConsoleMessageConsumer)); 697 TransformationContext transformation_context( 698 MakeUnique<FactManager>(context.get()), validator_options); 699 // Good: Global variable of id 28 (storage class Private) is defined in the 700 // caller (main). 701 TransformationAddParameter transformation_good_1(12, 70, 27, 702 {{{38, 28}, {42, 28}}}, 71); 703 ASSERT_TRUE(transformation_good_1.IsApplicable(context.get(), 704 transformation_context)); 705 ApplyAndCheckFreshIds(transformation_good_1, context.get(), 706 &transformation_context); 707 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 708 kConsoleMessageConsumer)); 709 710 // Good: Global variable of id 61 is (storage class Workgroup) is defined in 711 // the caller (main). 712 TransformationAddParameter transformation_good_2(12, 72, 27, 713 {{{38, 28}, {42, 28}}}, 73); 714 ASSERT_TRUE(transformation_good_2.IsApplicable(context.get(), 715 transformation_context)); 716 ApplyAndCheckFreshIds(transformation_good_2, context.get(), 717 &transformation_context); 718 719 // Good: Global variable of id 28 (storage class Private) is defined in the 720 // caller (main). 721 TransformationAddParameter transformation_good_3(6, 74, 27, {{{33, 28}}}, 75); 722 ASSERT_TRUE(transformation_good_3.IsApplicable(context.get(), 723 transformation_context)); 724 ApplyAndCheckFreshIds(transformation_good_3, context.get(), 725 &transformation_context); 726 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 727 kConsoleMessageConsumer)); 728 729 // Good: Global variable of id 61 is (storage class Workgroup) is defined in 730 // the caller (main). 731 TransformationAddParameter transformation_good_4(6, 76, 60, {{{33, 61}}}, 77); 732 ASSERT_TRUE(transformation_good_4.IsApplicable(context.get(), 733 transformation_context)); 734 ApplyAndCheckFreshIds(transformation_good_4, context.get(), 735 &transformation_context); 736 737 // Good: Global variable of id 28 (storage class Private) is defined in the 738 // caller (main). 739 TransformationAddParameter transformation_good_5(14, 78, 27, {{{43, 28}}}, 740 79); 741 ASSERT_TRUE(transformation_good_5.IsApplicable(context.get(), 742 transformation_context)); 743 ApplyAndCheckFreshIds(transformation_good_5, context.get(), 744 &transformation_context); 745 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 746 kConsoleMessageConsumer)); 747 748 // Good: Global variable of id 61 is (storage class Workgroup) is defined in 749 // the caller (main). 750 TransformationAddParameter transformation_good_6(14, 80, 60, {{{43, 61}}}, 751 81); 752 ASSERT_TRUE(transformation_good_6.IsApplicable(context.get(), 753 transformation_context)); 754 ApplyAndCheckFreshIds(transformation_good_6, context.get(), 755 &transformation_context); 756 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 757 kConsoleMessageConsumer)); 758 759 std::string expected_shader = R"( 760 OpCapability Shader 761 %1 = OpExtInstImport "GLSL.std.450" 762 OpMemoryModel Logical GLSL450 763 OpEntryPoint Fragment %4 "main" 764 OpExecutionMode %4 OriginUpperLeft 765 OpSource ESSL 310 766 OpName %4 "main" 767 OpName %6 "fun1(" 768 OpName %12 "fun2(i1;" 769 OpName %11 "a" 770 OpName %14 "fun3(" 771 OpName %17 "s" 772 OpName %24 "s" 773 OpName %28 "f1" 774 OpName %31 "f2" 775 OpName %34 "i1" 776 OpName %35 "i2" 777 OpName %36 "param" 778 OpName %39 "i3" 779 OpName %40 "param" 780 %2 = OpTypeVoid 781 %3 = OpTypeFunction %2 782 %8 = OpTypeInt 32 1 783 %9 = OpTypePointer Function %8 784 %20 = OpConstant %8 2 785 %25 = OpConstant %8 0 786 %26 = OpTypeFloat 32 787 %27 = OpTypePointer Private %26 788 %28 = OpVariable %27 Private 789 %60 = OpTypePointer Workgroup %26 790 %61 = OpVariable %60 Workgroup 791 %29 = OpConstant %26 1 792 %30 = OpTypePointer Function %26 793 %32 = OpConstant %26 2 794 %10 = OpTypeFunction %8 %9 %27 %27 795 %75 = OpTypeFunction %2 %27 %60 796 %4 = OpFunction %2 None %3 797 %5 = OpLabel 798 %31 = OpVariable %30 Function 799 %34 = OpVariable %9 Function 800 %35 = OpVariable %9 Function 801 %36 = OpVariable %9 Function 802 %39 = OpVariable %9 Function 803 %40 = OpVariable %9 Function 804 OpStore %28 %29 805 OpStore %31 %32 806 %33 = OpFunctionCall %2 %6 %28 %61 807 OpStore %34 %20 808 %37 = OpLoad %8 %34 809 OpStore %36 %37 810 %38 = OpFunctionCall %8 %12 %36 %28 %28 811 OpStore %35 %38 812 %41 = OpLoad %8 %35 813 OpStore %40 %41 814 %42 = OpFunctionCall %8 %12 %40 %28 %28 815 OpStore %39 %42 816 %43 = OpFunctionCall %2 %14 %28 %61 817 OpReturn 818 OpFunctionEnd 819 %6 = OpFunction %2 None %75 820 %74 = OpFunctionParameter %27 821 %76 = OpFunctionParameter %60 822 %7 = OpLabel 823 OpReturn 824 OpFunctionEnd 825 %12 = OpFunction %8 None %10 826 %11 = OpFunctionParameter %9 827 %70 = OpFunctionParameter %27 828 %72 = OpFunctionParameter %27 829 %13 = OpLabel 830 %17 = OpVariable %9 Function 831 %18 = OpLoad %8 %11 832 OpStore %17 %18 833 %19 = OpLoad %8 %17 834 %21 = OpIAdd %8 %19 %20 835 OpReturnValue %21 836 OpFunctionEnd 837 %14 = OpFunction %2 None %75 838 %78 = OpFunctionParameter %27 839 %80 = OpFunctionParameter %60 840 %15 = OpLabel 841 %24 = OpVariable %9 Function 842 OpStore %24 %25 843 OpReturn 844 OpFunctionEnd 845 )"; 846 ASSERT_TRUE(IsEqual(env, expected_shader, context.get())); 847} 848 849TEST(TransformationAddParameterTest, PointerMoreEntriesInMapTest) { 850 // This types handles case where call_parameter_id has an entry for at least 851 // every caller (there are more entries than it is necessary). 852 std::string shader = R"( 853 OpCapability Shader 854 %1 = OpExtInstImport "GLSL.std.450" 855 OpMemoryModel Logical GLSL450 856 OpEntryPoint Fragment %4 "main" 857 OpExecutionMode %4 OriginUpperLeft 858 OpSource ESSL 310 859 OpName %4 "main" 860 OpName %10 "fun(i1;" 861 OpName %9 "a" 862 OpName %12 "s" 863 OpName %19 "i1" 864 OpName %21 "i2" 865 OpName %22 "i3" 866 OpName %24 "i4" 867 OpName %25 "param" 868 OpName %28 "i5" 869 OpName %29 "param" 870 %2 = OpTypeVoid 871 %3 = OpTypeFunction %2 872 %6 = OpTypeInt 32 1 873 %7 = OpTypePointer Function %6 874 %8 = OpTypeFunction %6 %7 875 %15 = OpConstant %6 2 876 %20 = OpConstant %6 1 877 %23 = OpConstant %6 3 878 %4 = OpFunction %2 None %3 879 %5 = OpLabel 880 %19 = OpVariable %7 Function 881 %21 = OpVariable %7 Function 882 %22 = OpVariable %7 Function 883 %24 = OpVariable %7 Function 884 %25 = OpVariable %7 Function 885 %28 = OpVariable %7 Function 886 %29 = OpVariable %7 Function 887 OpStore %19 %20 888 OpStore %21 %15 889 OpStore %22 %23 890 %26 = OpLoad %6 %19 891 OpStore %25 %26 892 %27 = OpFunctionCall %6 %10 %25 893 OpStore %24 %27 894 %30 = OpLoad %6 %21 895 OpStore %29 %30 896 %31 = OpFunctionCall %6 %10 %29 897 OpStore %28 %31 898 OpReturn 899 OpFunctionEnd 900 %10 = OpFunction %6 None %8 901 %9 = OpFunctionParameter %7 902 %11 = OpLabel 903 %12 = OpVariable %7 Function 904 %13 = OpLoad %6 %9 905 OpStore %12 %13 906 %14 = OpLoad %6 %12 907 %16 = OpIAdd %6 %14 %15 908 OpReturnValue %16 909 OpFunctionEnd 910 )"; 911 912 const auto env = SPV_ENV_UNIVERSAL_1_3; 913 const auto consumer = nullptr; 914 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); 915 spvtools::ValidatorOptions validator_options; 916 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 917 kConsoleMessageConsumer)); 918 TransformationContext transformation_context( 919 MakeUnique<FactManager>(context.get()), validator_options); 920 // Good: Local variable of id 21 is defined in every caller (id 27 and id 31). 921 TransformationAddParameter transformation_good_1( 922 10, 70, 7, {{{27, 21}, {31, 21}, {30, 21}}}, 71); 923 ASSERT_TRUE(transformation_good_1.IsApplicable(context.get(), 924 transformation_context)); 925 ApplyAndCheckFreshIds(transformation_good_1, context.get(), 926 &transformation_context); 927 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 928 kConsoleMessageConsumer)); 929 930 // Good: Local variable of id 28 is defined in every caller (id 27 and id 31). 931 TransformationAddParameter transformation_good_2( 932 10, 72, 7, {{{27, 28}, {31, 28}, {14, 21}, {16, 14}}}, 73); 933 ASSERT_TRUE(transformation_good_2.IsApplicable(context.get(), 934 transformation_context)); 935 ApplyAndCheckFreshIds(transformation_good_2, context.get(), 936 &transformation_context); 937 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 938 kConsoleMessageConsumer)); 939 940 std::string expected_shader = R"( 941 OpCapability Shader 942 %1 = OpExtInstImport "GLSL.std.450" 943 OpMemoryModel Logical GLSL450 944 OpEntryPoint Fragment %4 "main" 945 OpExecutionMode %4 OriginUpperLeft 946 OpSource ESSL 310 947 OpName %4 "main" 948 OpName %10 "fun(i1;" 949 OpName %9 "a" 950 OpName %12 "s" 951 OpName %19 "i1" 952 OpName %21 "i2" 953 OpName %22 "i3" 954 OpName %24 "i4" 955 OpName %25 "param" 956 OpName %28 "i5" 957 OpName %29 "param" 958 %2 = OpTypeVoid 959 %3 = OpTypeFunction %2 960 %6 = OpTypeInt 32 1 961 %7 = OpTypePointer Function %6 962 %15 = OpConstant %6 2 963 %20 = OpConstant %6 1 964 %23 = OpConstant %6 3 965 %8 = OpTypeFunction %6 %7 %7 %7 966 %4 = OpFunction %2 None %3 967 %5 = OpLabel 968 %19 = OpVariable %7 Function 969 %21 = OpVariable %7 Function 970 %22 = OpVariable %7 Function 971 %24 = OpVariable %7 Function 972 %25 = OpVariable %7 Function 973 %28 = OpVariable %7 Function 974 %29 = OpVariable %7 Function 975 OpStore %19 %20 976 OpStore %21 %15 977 OpStore %22 %23 978 %26 = OpLoad %6 %19 979 OpStore %25 %26 980 %27 = OpFunctionCall %6 %10 %25 %21 %28 981 OpStore %24 %27 982 %30 = OpLoad %6 %21 983 OpStore %29 %30 984 %31 = OpFunctionCall %6 %10 %29 %21 %28 985 OpStore %28 %31 986 OpReturn 987 OpFunctionEnd 988 %10 = OpFunction %6 None %8 989 %9 = OpFunctionParameter %7 990 %70 = OpFunctionParameter %7 991 %72 = OpFunctionParameter %7 992 %11 = OpLabel 993 %12 = OpVariable %7 Function 994 %13 = OpLoad %6 %9 995 OpStore %12 %13 996 %14 = OpLoad %6 %12 997 %16 = OpIAdd %6 %14 %15 998 OpReturnValue %16 999 OpFunctionEnd 1000 )"; 1001 ASSERT_TRUE(IsEqual(env, expected_shader, context.get())); 1002} 1003 1004TEST(TransformationAddParameterTest, PointeeValueIsIrrelevantTest) { 1005 // This test checks if the transformation has correctly applied the 1006 // PointeeValueIsIrrelevant fact for new pointer parameters. 1007 std::string shader = R"( 1008 OpCapability Shader 1009 %1 = OpExtInstImport "GLSL.std.450" 1010 OpMemoryModel Logical GLSL450 1011 OpEntryPoint Fragment %4 "main" 1012 OpExecutionMode %4 OriginUpperLeft 1013 OpSource ESSL 310 1014 OpName %4 "main" 1015 OpName %10 "fun(i1;" 1016 OpName %9 "a" 1017 OpName %12 "s" 1018 OpName %20 "b" 1019 OpName %22 "i1" 1020 OpName %24 "i2" 1021 OpName %25 "i3" 1022 OpName %26 "param" 1023 OpName %29 "i4" 1024 OpName %30 "param" 1025 %2 = OpTypeVoid 1026 %3 = OpTypeFunction %2 1027 %6 = OpTypeInt 32 1 1028 %7 = OpTypePointer Function %6 1029 %50 = OpTypePointer Workgroup %6 1030 %51 = OpVariable %50 Workgroup 1031 %8 = OpTypeFunction %6 %7 1032 %15 = OpConstant %6 2 1033 %19 = OpTypePointer Private %6 1034 %20 = OpVariable %19 Private 1035 %21 = OpConstant %6 0 1036 %23 = OpConstant %6 1 1037 %4 = OpFunction %2 None %3 1038 %5 = OpLabel 1039 %22 = OpVariable %7 Function 1040 %24 = OpVariable %7 Function 1041 %25 = OpVariable %7 Function 1042 %26 = OpVariable %7 Function 1043 %29 = OpVariable %7 Function 1044 %30 = OpVariable %7 Function 1045 OpStore %20 %21 1046 OpStore %22 %23 1047 OpStore %24 %15 1048 %27 = OpLoad %6 %22 1049 OpStore %26 %27 1050 %28 = OpFunctionCall %6 %10 %26 1051 OpStore %25 %28 1052 %31 = OpLoad %6 %24 1053 OpStore %30 %31 1054 %32 = OpFunctionCall %6 %10 %30 1055 OpStore %29 %32 1056 OpReturn 1057 OpFunctionEnd 1058 %10 = OpFunction %6 None %8 1059 %9 = OpFunctionParameter %7 1060 %11 = OpLabel 1061 %12 = OpVariable %7 Function 1062 %13 = OpLoad %6 %9 1063 OpStore %12 %13 1064 %14 = OpLoad %6 %12 1065 %16 = OpIAdd %6 %14 %15 1066 OpReturnValue %16 1067 OpFunctionEnd 1068 )"; 1069 1070 const auto env = SPV_ENV_UNIVERSAL_1_3; 1071 const auto consumer = nullptr; 1072 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); 1073 spvtools::ValidatorOptions validator_options; 1074 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 1075 kConsoleMessageConsumer)); 1076 TransformationContext transformation_context( 1077 MakeUnique<FactManager>(context.get()), validator_options); 1078 TransformationAddParameter transformation_good_1(10, 70, 7, 1079 {{{28, 22}, {32, 22}}}, 71); 1080 ASSERT_TRUE(transformation_good_1.IsApplicable(context.get(), 1081 transformation_context)); 1082 ApplyAndCheckFreshIds(transformation_good_1, context.get(), 1083 &transformation_context); 1084 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 1085 kConsoleMessageConsumer)); 1086 1087 // Check if the fact PointeeValueIsIrrelevant is set for the new parameter 1088 // (storage class Function). 1089 ASSERT_TRUE( 1090 transformation_context.GetFactManager()->PointeeValueIsIrrelevant(70)); 1091 1092 TransformationAddParameter transformation_good_2(10, 72, 19, 1093 {{{28, 20}, {32, 20}}}, 73); 1094 ASSERT_TRUE(transformation_good_2.IsApplicable(context.get(), 1095 transformation_context)); 1096 ApplyAndCheckFreshIds(transformation_good_2, context.get(), 1097 &transformation_context); 1098 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 1099 kConsoleMessageConsumer)); 1100 1101 // Check if the fact PointeeValueIsIrrelevant is set for the new parameter 1102 // (storage class Private). 1103 ASSERT_TRUE( 1104 transformation_context.GetFactManager()->PointeeValueIsIrrelevant(72)); 1105 1106 TransformationAddParameter transformation_good_3(10, 74, 50, 1107 {{{28, 51}, {32, 51}}}, 75); 1108 ASSERT_TRUE(transformation_good_3.IsApplicable(context.get(), 1109 transformation_context)); 1110 ApplyAndCheckFreshIds(transformation_good_3, context.get(), 1111 &transformation_context); 1112 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 1113 kConsoleMessageConsumer)); 1114 1115 // Check if the fact PointeeValueIsIrrelevant is set for the new parameter 1116 // (storage class Workgroup). 1117 ASSERT_TRUE( 1118 transformation_context.GetFactManager()->PointeeValueIsIrrelevant(74)); 1119} 1120 1121} // namespace 1122} // namespace fuzz 1123} // namespace spvtools 1124