1// Copyright (c) 2019 Google LLC 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15#include "source/fuzz/transformation_composite_construct.h" 16 17#include "gtest/gtest.h" 18#include "source/fuzz/data_descriptor.h" 19#include "source/fuzz/fuzzer_util.h" 20#include "source/fuzz/instruction_descriptor.h" 21#include "test/fuzz/fuzz_test_util.h" 22 23namespace spvtools { 24namespace fuzz { 25namespace { 26 27TEST(TransformationCompositeConstructTest, ConstructArrays) { 28 std::string shader = R"( 29 OpCapability Shader 30 %1 = OpExtInstImport "GLSL.std.450" 31 OpMemoryModel Logical GLSL450 32 OpEntryPoint Fragment %4 "main" 33 OpExecutionMode %4 OriginUpperLeft 34 OpSource ESSL 310 35 OpName %4 "main" 36 OpName %11 "floats" 37 OpName %22 "x" 38 OpName %39 "vecs" 39 OpName %49 "bools" 40 OpName %60 "many_uvec3s" 41 OpDecorate %60 RelaxedPrecision 42 %2 = OpTypeVoid 43 %3 = OpTypeFunction %2 44 %6 = OpTypeFloat 32 45 %7 = OpTypeInt 32 0 46 %8 = OpConstant %7 2 47 %9 = OpTypeArray %6 %8 48 %10 = OpTypePointer Function %9 49 %12 = OpTypeInt 32 1 50 %13 = OpConstant %12 0 51 %14 = OpConstant %6 1 52 %15 = OpTypePointer Function %6 53 %17 = OpConstant %12 1 54 %18 = OpConstant %6 2 55 %20 = OpTypeVector %6 2 56 %21 = OpTypePointer Function %20 57 %32 = OpTypeBool 58 %36 = OpConstant %7 3 59 %37 = OpTypeArray %20 %36 60 %38 = OpTypePointer Private %37 61 %39 = OpVariable %38 Private 62 %40 = OpConstant %6 3 63 %41 = OpConstantComposite %20 %40 %40 64 %42 = OpTypePointer Private %20 65 %44 = OpConstant %12 2 66 %47 = OpTypeArray %32 %36 67 %48 = OpTypePointer Function %47 68 %50 = OpConstantTrue %32 69 %51 = OpTypePointer Function %32 70 %56 = OpTypeVector %7 3 71 %57 = OpTypeArray %56 %8 72 %58 = OpTypeArray %57 %8 73 %59 = OpTypePointer Function %58 74 %61 = OpConstant %7 4 75 %62 = OpConstantComposite %56 %61 %61 %61 76 %63 = OpTypePointer Function %56 77 %65 = OpConstant %7 5 78 %66 = OpConstantComposite %56 %65 %65 %65 79 %67 = OpConstant %7 6 80 %68 = OpConstantComposite %56 %67 %67 %67 81 %69 = OpConstantComposite %57 %66 %68 82 %100 = OpUndef %57 83 %70 = OpTypePointer Function %57 84 %4 = OpFunction %2 None %3 85 %5 = OpLabel 86 %11 = OpVariable %10 Function 87 %22 = OpVariable %21 Function 88 %49 = OpVariable %48 Function 89 %60 = OpVariable %59 Function 90 %16 = OpAccessChain %15 %11 %13 91 OpStore %16 %14 92 %19 = OpAccessChain %15 %11 %17 93 OpStore %19 %18 94 %23 = OpAccessChain %15 %11 %13 95 %24 = OpLoad %6 %23 96 %25 = OpAccessChain %15 %11 %17 97 %26 = OpLoad %6 %25 98 %27 = OpCompositeConstruct %20 %24 %26 99 OpStore %22 %27 100 %28 = OpAccessChain %15 %11 %13 101 %29 = OpLoad %6 %28 102 %30 = OpAccessChain %15 %11 %17 103 %31 = OpLoad %6 %30 104 %33 = OpFOrdGreaterThan %32 %29 %31 105 OpSelectionMerge %35 None 106 OpBranchConditional %33 %34 %35 107 %34 = OpLabel 108 %43 = OpAccessChain %42 %39 %17 109 OpStore %43 %41 110 %45 = OpLoad %20 %22 111 %46 = OpAccessChain %42 %39 %44 112 OpStore %46 %45 113 OpBranch %35 114 %35 = OpLabel 115 %52 = OpAccessChain %51 %49 %13 116 OpStore %52 %50 117 %53 = OpAccessChain %51 %49 %13 118 %54 = OpLoad %32 %53 119 %55 = OpAccessChain %51 %49 %17 120 OpStore %55 %54 121 %64 = OpAccessChain %63 %60 %13 %13 122 OpStore %64 %62 123 %71 = OpAccessChain %70 %60 %17 124 OpStore %71 %69 125 OpReturn 126 OpFunctionEnd 127 )"; 128 129 const auto env = SPV_ENV_UNIVERSAL_1_3; 130 const auto consumer = nullptr; 131 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); 132 spvtools::ValidatorOptions validator_options; 133 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 134 kConsoleMessageConsumer)); 135 TransformationContext transformation_context( 136 MakeUnique<FactManager>(context.get()), validator_options); 137 // Make a vec2[3] 138 TransformationCompositeConstruct make_vec2_array_length_3( 139 37, {41, 45, 27}, 140 MakeInstructionDescriptor(46, spv::Op::OpAccessChain, 0), 200); 141 // Bad: there are too many components 142 TransformationCompositeConstruct make_vec2_array_length_3_bad( 143 37, {41, 45, 27, 27}, 144 MakeInstructionDescriptor(46, spv::Op::OpAccessChain, 0), 200); 145 // The first component does not correspond to an instruction with a result 146 // type so this check should return false. 147 TransformationCompositeConstruct make_vec2_array_length_3_nores( 148 37, {2, 45, 27}, MakeInstructionDescriptor(46, spv::Op::OpAccessChain, 0), 149 200); 150 ASSERT_TRUE(make_vec2_array_length_3.IsApplicable(context.get(), 151 transformation_context)); 152 ASSERT_FALSE(make_vec2_array_length_3_bad.IsApplicable( 153 context.get(), transformation_context)); 154 ASSERT_FALSE(make_vec2_array_length_3_nores.IsApplicable( 155 context.get(), transformation_context)); 156 ASSERT_EQ(nullptr, context->get_def_use_mgr()->GetDef(200)); 157 ASSERT_EQ(nullptr, context->get_instr_block(200)); 158 uint32_t num_uses_of_41_before = context->get_def_use_mgr()->NumUses(41); 159 uint32_t num_uses_of_45_before = context->get_def_use_mgr()->NumUses(45); 160 uint32_t num_uses_of_27_before = context->get_def_use_mgr()->NumUses(27); 161 ApplyAndCheckFreshIds(make_vec2_array_length_3, context.get(), 162 &transformation_context); 163 ASSERT_EQ(spv::Op::OpCompositeConstruct, 164 context->get_def_use_mgr()->GetDef(200)->opcode()); 165 ASSERT_EQ(34, context->get_instr_block(200)->id()); 166 ASSERT_EQ(num_uses_of_41_before + 1, context->get_def_use_mgr()->NumUses(41)); 167 ASSERT_EQ(num_uses_of_45_before + 1, context->get_def_use_mgr()->NumUses(45)); 168 ASSERT_EQ(num_uses_of_27_before + 1, context->get_def_use_mgr()->NumUses(27)); 169 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 170 kConsoleMessageConsumer)); 171 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 172 MakeDataDescriptor(41, {}), MakeDataDescriptor(200, {0}))); 173 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 174 MakeDataDescriptor(45, {}), MakeDataDescriptor(200, {1}))); 175 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 176 MakeDataDescriptor(27, {}), MakeDataDescriptor(200, {2}))); 177 178 // Make a float[2] 179 TransformationCompositeConstruct make_float_array_length_2( 180 9, {24, 40}, MakeInstructionDescriptor(71, spv::Op::OpStore, 0), 201); 181 // Bad: %41 does not have type float 182 TransformationCompositeConstruct make_float_array_length_2_bad( 183 9, {41, 40}, MakeInstructionDescriptor(71, spv::Op::OpStore, 0), 201); 184 ASSERT_TRUE(make_float_array_length_2.IsApplicable(context.get(), 185 transformation_context)); 186 ASSERT_FALSE(make_float_array_length_2_bad.IsApplicable( 187 context.get(), transformation_context)); 188 ApplyAndCheckFreshIds(make_float_array_length_2, context.get(), 189 &transformation_context); 190 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 191 kConsoleMessageConsumer)); 192 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 193 MakeDataDescriptor(24, {}), MakeDataDescriptor(201, {0}))); 194 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 195 MakeDataDescriptor(40, {}), MakeDataDescriptor(201, {1}))); 196 197 // Make a bool[3] 198 TransformationCompositeConstruct make_bool_array_length_3( 199 47, {33, 50, 50}, 200 MakeInstructionDescriptor(33, spv::Op::OpSelectionMerge, 0), 202); 201 // Bad: %54 is not available at the desired program point. 202 TransformationCompositeConstruct make_bool_array_length_3_bad( 203 47, {33, 54, 50}, 204 MakeInstructionDescriptor(33, spv::Op::OpSelectionMerge, 0), 202); 205 ASSERT_TRUE(make_bool_array_length_3.IsApplicable(context.get(), 206 transformation_context)); 207 ASSERT_FALSE(make_bool_array_length_3_bad.IsApplicable( 208 context.get(), transformation_context)); 209 ApplyAndCheckFreshIds(make_bool_array_length_3, context.get(), 210 &transformation_context); 211 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 212 kConsoleMessageConsumer)); 213 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 214 MakeDataDescriptor(33, {}), MakeDataDescriptor(202, {0}))); 215 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 216 MakeDataDescriptor(50, {}), MakeDataDescriptor(202, {1}))); 217 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 218 MakeDataDescriptor(50, {}), MakeDataDescriptor(202, {2}))); 219 220 // make a uvec3[2][2] 221 TransformationCompositeConstruct make_uvec3_array_length_2_2( 222 58, {69, 100}, MakeInstructionDescriptor(64, spv::Op::OpStore, 0), 203); 223 // Bad: Skip count 100 is too large. 224 TransformationCompositeConstruct make_uvec3_array_length_2_2_bad( 225 58, {33, 54}, MakeInstructionDescriptor(64, spv::Op::OpStore, 100), 203); 226 ASSERT_TRUE(make_uvec3_array_length_2_2.IsApplicable(context.get(), 227 transformation_context)); 228 ASSERT_FALSE(make_uvec3_array_length_2_2_bad.IsApplicable( 229 context.get(), transformation_context)); 230 ApplyAndCheckFreshIds(make_uvec3_array_length_2_2, context.get(), 231 &transformation_context); 232 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 233 kConsoleMessageConsumer)); 234 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 235 MakeDataDescriptor(69, {}), MakeDataDescriptor(203, {0}))); 236 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 237 MakeDataDescriptor(100, {}), MakeDataDescriptor(203, {1}))); 238 239 std::string after_transformation = R"( 240 OpCapability Shader 241 %1 = OpExtInstImport "GLSL.std.450" 242 OpMemoryModel Logical GLSL450 243 OpEntryPoint Fragment %4 "main" 244 OpExecutionMode %4 OriginUpperLeft 245 OpSource ESSL 310 246 OpName %4 "main" 247 OpName %11 "floats" 248 OpName %22 "x" 249 OpName %39 "vecs" 250 OpName %49 "bools" 251 OpName %60 "many_uvec3s" 252 OpDecorate %60 RelaxedPrecision 253 %2 = OpTypeVoid 254 %3 = OpTypeFunction %2 255 %6 = OpTypeFloat 32 256 %7 = OpTypeInt 32 0 257 %8 = OpConstant %7 2 258 %9 = OpTypeArray %6 %8 259 %10 = OpTypePointer Function %9 260 %12 = OpTypeInt 32 1 261 %13 = OpConstant %12 0 262 %14 = OpConstant %6 1 263 %15 = OpTypePointer Function %6 264 %17 = OpConstant %12 1 265 %18 = OpConstant %6 2 266 %20 = OpTypeVector %6 2 267 %21 = OpTypePointer Function %20 268 %32 = OpTypeBool 269 %36 = OpConstant %7 3 270 %37 = OpTypeArray %20 %36 271 %38 = OpTypePointer Private %37 272 %39 = OpVariable %38 Private 273 %40 = OpConstant %6 3 274 %41 = OpConstantComposite %20 %40 %40 275 %42 = OpTypePointer Private %20 276 %44 = OpConstant %12 2 277 %47 = OpTypeArray %32 %36 278 %48 = OpTypePointer Function %47 279 %50 = OpConstantTrue %32 280 %51 = OpTypePointer Function %32 281 %56 = OpTypeVector %7 3 282 %57 = OpTypeArray %56 %8 283 %58 = OpTypeArray %57 %8 284 %59 = OpTypePointer Function %58 285 %61 = OpConstant %7 4 286 %62 = OpConstantComposite %56 %61 %61 %61 287 %63 = OpTypePointer Function %56 288 %65 = OpConstant %7 5 289 %66 = OpConstantComposite %56 %65 %65 %65 290 %67 = OpConstant %7 6 291 %68 = OpConstantComposite %56 %67 %67 %67 292 %69 = OpConstantComposite %57 %66 %68 293 %100 = OpUndef %57 294 %70 = OpTypePointer Function %57 295 %4 = OpFunction %2 None %3 296 %5 = OpLabel 297 %11 = OpVariable %10 Function 298 %22 = OpVariable %21 Function 299 %49 = OpVariable %48 Function 300 %60 = OpVariable %59 Function 301 %16 = OpAccessChain %15 %11 %13 302 OpStore %16 %14 303 %19 = OpAccessChain %15 %11 %17 304 OpStore %19 %18 305 %23 = OpAccessChain %15 %11 %13 306 %24 = OpLoad %6 %23 307 %25 = OpAccessChain %15 %11 %17 308 %26 = OpLoad %6 %25 309 %27 = OpCompositeConstruct %20 %24 %26 310 OpStore %22 %27 311 %28 = OpAccessChain %15 %11 %13 312 %29 = OpLoad %6 %28 313 %30 = OpAccessChain %15 %11 %17 314 %31 = OpLoad %6 %30 315 %33 = OpFOrdGreaterThan %32 %29 %31 316 %202 = OpCompositeConstruct %47 %33 %50 %50 317 OpSelectionMerge %35 None 318 OpBranchConditional %33 %34 %35 319 %34 = OpLabel 320 %43 = OpAccessChain %42 %39 %17 321 OpStore %43 %41 322 %45 = OpLoad %20 %22 323 %200 = OpCompositeConstruct %37 %41 %45 %27 324 %46 = OpAccessChain %42 %39 %44 325 OpStore %46 %45 326 OpBranch %35 327 %35 = OpLabel 328 %52 = OpAccessChain %51 %49 %13 329 OpStore %52 %50 330 %53 = OpAccessChain %51 %49 %13 331 %54 = OpLoad %32 %53 332 %55 = OpAccessChain %51 %49 %17 333 OpStore %55 %54 334 %64 = OpAccessChain %63 %60 %13 %13 335 %203 = OpCompositeConstruct %58 %69 %100 336 OpStore %64 %62 337 %71 = OpAccessChain %70 %60 %17 338 %201 = OpCompositeConstruct %9 %24 %40 339 OpStore %71 %69 340 OpReturn 341 OpFunctionEnd 342 )"; 343 344 ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); 345} 346 347TEST(TransformationCompositeConstructTest, ConstructMatrices) { 348 std::string shader = R"( 349 OpCapability Shader 350 %1 = OpExtInstImport "GLSL.std.450" 351 OpMemoryModel Logical GLSL450 352 OpEntryPoint Fragment %4 "main" 353 OpExecutionMode %4 OriginUpperLeft 354 OpSource ESSL 310 355 OpName %4 "main" 356 OpName %9 "v1" 357 OpName %12 "v2" 358 OpName %14 "v3" 359 OpName %19 "v4" 360 OpName %26 "v5" 361 OpName %29 "v6" 362 OpName %34 "m34" 363 OpName %37 "m43" 364 OpName %43 "vecs" 365 %2 = OpTypeVoid 366 %3 = OpTypeFunction %2 367 %6 = OpTypeFloat 32 368 %7 = OpTypeVector %6 3 369 %8 = OpTypePointer Function %7 370 %10 = OpConstant %6 1 371 %11 = OpConstantComposite %7 %10 %10 %10 372 %17 = OpTypeVector %6 4 373 %18 = OpTypePointer Function %17 374 %21 = OpConstant %6 2 375 %32 = OpTypeMatrix %17 3 376 %33 = OpTypePointer Private %32 377 %34 = OpVariable %33 Private 378 %35 = OpTypeMatrix %7 4 379 %36 = OpTypePointer Private %35 380 %37 = OpVariable %36 Private 381 %38 = OpTypeVector %6 2 382 %39 = OpTypeInt 32 0 383 %40 = OpConstant %39 3 384 %41 = OpTypeArray %38 %40 385 %42 = OpTypePointer Private %41 386 %43 = OpVariable %42 Private 387 %100 = OpUndef %7 388 %101 = OpUndef %17 389 %4 = OpFunction %2 None %3 390 %5 = OpLabel 391 %9 = OpVariable %8 Function 392 %12 = OpVariable %8 Function 393 %14 = OpVariable %8 Function 394 %19 = OpVariable %18 Function 395 %26 = OpVariable %18 Function 396 %29 = OpVariable %18 Function 397 OpStore %9 %11 398 %13 = OpLoad %7 %9 399 OpStore %12 %13 400 %15 = OpLoad %7 %12 401 %16 = OpVectorShuffle %7 %15 %15 2 1 0 402 OpStore %14 %16 403 %20 = OpLoad %7 %14 404 %22 = OpCompositeExtract %6 %20 0 405 %23 = OpCompositeExtract %6 %20 1 406 %24 = OpCompositeExtract %6 %20 2 407 %25 = OpCompositeConstruct %17 %22 %23 %24 %21 408 OpStore %19 %25 409 %27 = OpLoad %17 %19 410 %28 = OpVectorShuffle %17 %27 %27 3 2 1 0 411 OpStore %26 %28 412 %30 = OpLoad %7 %9 413 %31 = OpVectorShuffle %17 %30 %30 0 0 1 1 414 OpStore %29 %31 415 OpReturn 416 OpFunctionEnd 417 )"; 418 419 const auto env = SPV_ENV_UNIVERSAL_1_3; 420 const auto consumer = nullptr; 421 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); 422 spvtools::ValidatorOptions validator_options; 423 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 424 kConsoleMessageConsumer)); 425 TransformationContext transformation_context( 426 MakeUnique<FactManager>(context.get()), validator_options); 427 // make a mat3x4 428 TransformationCompositeConstruct make_mat34( 429 32, {25, 28, 31}, MakeInstructionDescriptor(31, spv::Op::OpReturn, 0), 430 200); 431 // Bad: %35 is mat4x3, not mat3x4. 432 TransformationCompositeConstruct make_mat34_bad( 433 35, {25, 28, 31}, MakeInstructionDescriptor(31, spv::Op::OpReturn, 0), 434 200); 435 // The first component does not correspond to an instruction with a result 436 // type so this check should return false. 437 TransformationCompositeConstruct make_mat34_nores( 438 32, {2, 28, 31}, MakeInstructionDescriptor(31, spv::Op::OpReturn, 0), 439 200); 440 ASSERT_TRUE(make_mat34.IsApplicable(context.get(), transformation_context)); 441 ASSERT_FALSE( 442 make_mat34_bad.IsApplicable(context.get(), transformation_context)); 443 ASSERT_FALSE( 444 make_mat34_nores.IsApplicable(context.get(), transformation_context)); 445 ApplyAndCheckFreshIds(make_mat34, context.get(), &transformation_context); 446 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 447 kConsoleMessageConsumer)); 448 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 449 MakeDataDescriptor(25, {}), MakeDataDescriptor(200, {0}))); 450 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 451 MakeDataDescriptor(28, {}), MakeDataDescriptor(200, {1}))); 452 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 453 MakeDataDescriptor(31, {}), MakeDataDescriptor(200, {2}))); 454 455 // make a mat4x3 456 TransformationCompositeConstruct make_mat43( 457 35, {11, 13, 16, 100}, MakeInstructionDescriptor(31, spv::Op::OpStore, 0), 458 201); 459 // Bad: %25 does not match the matrix's column type. 460 TransformationCompositeConstruct make_mat43_bad( 461 35, {25, 13, 16, 100}, MakeInstructionDescriptor(31, spv::Op::OpStore, 0), 462 201); 463 ASSERT_TRUE(make_mat43.IsApplicable(context.get(), transformation_context)); 464 ASSERT_FALSE( 465 make_mat43_bad.IsApplicable(context.get(), transformation_context)); 466 ApplyAndCheckFreshIds(make_mat43, context.get(), &transformation_context); 467 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 468 kConsoleMessageConsumer)); 469 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 470 MakeDataDescriptor(11, {}), MakeDataDescriptor(201, {0}))); 471 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 472 MakeDataDescriptor(13, {}), MakeDataDescriptor(201, {1}))); 473 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 474 MakeDataDescriptor(16, {}), MakeDataDescriptor(201, {2}))); 475 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 476 MakeDataDescriptor(100, {}), MakeDataDescriptor(201, {3}))); 477 478 std::string after_transformation = R"( 479 OpCapability Shader 480 %1 = OpExtInstImport "GLSL.std.450" 481 OpMemoryModel Logical GLSL450 482 OpEntryPoint Fragment %4 "main" 483 OpExecutionMode %4 OriginUpperLeft 484 OpSource ESSL 310 485 OpName %4 "main" 486 OpName %9 "v1" 487 OpName %12 "v2" 488 OpName %14 "v3" 489 OpName %19 "v4" 490 OpName %26 "v5" 491 OpName %29 "v6" 492 OpName %34 "m34" 493 OpName %37 "m43" 494 OpName %43 "vecs" 495 %2 = OpTypeVoid 496 %3 = OpTypeFunction %2 497 %6 = OpTypeFloat 32 498 %7 = OpTypeVector %6 3 499 %8 = OpTypePointer Function %7 500 %10 = OpConstant %6 1 501 %11 = OpConstantComposite %7 %10 %10 %10 502 %17 = OpTypeVector %6 4 503 %18 = OpTypePointer Function %17 504 %21 = OpConstant %6 2 505 %32 = OpTypeMatrix %17 3 506 %33 = OpTypePointer Private %32 507 %34 = OpVariable %33 Private 508 %35 = OpTypeMatrix %7 4 509 %36 = OpTypePointer Private %35 510 %37 = OpVariable %36 Private 511 %38 = OpTypeVector %6 2 512 %39 = OpTypeInt 32 0 513 %40 = OpConstant %39 3 514 %41 = OpTypeArray %38 %40 515 %42 = OpTypePointer Private %41 516 %43 = OpVariable %42 Private 517 %100 = OpUndef %7 518 %101 = OpUndef %17 519 %4 = OpFunction %2 None %3 520 %5 = OpLabel 521 %9 = OpVariable %8 Function 522 %12 = OpVariable %8 Function 523 %14 = OpVariable %8 Function 524 %19 = OpVariable %18 Function 525 %26 = OpVariable %18 Function 526 %29 = OpVariable %18 Function 527 OpStore %9 %11 528 %13 = OpLoad %7 %9 529 OpStore %12 %13 530 %15 = OpLoad %7 %12 531 %16 = OpVectorShuffle %7 %15 %15 2 1 0 532 OpStore %14 %16 533 %20 = OpLoad %7 %14 534 %22 = OpCompositeExtract %6 %20 0 535 %23 = OpCompositeExtract %6 %20 1 536 %24 = OpCompositeExtract %6 %20 2 537 %25 = OpCompositeConstruct %17 %22 %23 %24 %21 538 OpStore %19 %25 539 %27 = OpLoad %17 %19 540 %28 = OpVectorShuffle %17 %27 %27 3 2 1 0 541 OpStore %26 %28 542 %30 = OpLoad %7 %9 543 %31 = OpVectorShuffle %17 %30 %30 0 0 1 1 544 %201 = OpCompositeConstruct %35 %11 %13 %16 %100 545 OpStore %29 %31 546 %200 = OpCompositeConstruct %32 %25 %28 %31 547 OpReturn 548 OpFunctionEnd 549 )"; 550 551 ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); 552} 553 554TEST(TransformationCompositeConstructTest, ConstructStructs) { 555 std::string shader = R"( 556 OpCapability Shader 557 %1 = OpExtInstImport "GLSL.std.450" 558 OpMemoryModel Logical GLSL450 559 OpEntryPoint Fragment %4 "main" 560 OpExecutionMode %4 OriginUpperLeft 561 OpSource ESSL 310 562 OpName %4 "main" 563 OpName %9 "Inner" 564 OpMemberName %9 0 "a" 565 OpMemberName %9 1 "b" 566 OpName %11 "i1" 567 OpName %22 "i2" 568 OpName %33 "Outer" 569 OpMemberName %33 0 "c" 570 OpMemberName %33 1 "d" 571 OpMemberName %33 2 "e" 572 OpName %35 "o" 573 %2 = OpTypeVoid 574 %3 = OpTypeFunction %2 575 %6 = OpTypeFloat 32 576 %7 = OpTypeVector %6 2 577 %8 = OpTypeInt 32 1 578 %9 = OpTypeStruct %7 %8 579 %10 = OpTypePointer Function %9 580 %12 = OpConstant %8 0 581 %13 = OpConstant %6 2 582 %14 = OpTypeInt 32 0 583 %15 = OpConstant %14 0 584 %16 = OpTypePointer Function %6 585 %18 = OpConstant %8 1 586 %19 = OpConstant %8 3 587 %20 = OpTypePointer Function %8 588 %23 = OpTypePointer Function %7 589 %31 = OpConstant %14 2 590 %32 = OpTypeArray %9 %31 591 %33 = OpTypeStruct %32 %9 %6 592 %34 = OpTypePointer Function %33 593 %36 = OpConstant %6 1 594 %37 = OpConstantComposite %7 %36 %13 595 %38 = OpConstant %8 2 596 %39 = OpConstantComposite %9 %37 %38 597 %40 = OpConstant %6 3 598 %41 = OpConstant %6 4 599 %42 = OpConstantComposite %7 %40 %41 600 %56 = OpConstant %6 5 601 %100 = OpUndef %9 602 %4 = OpFunction %2 None %3 603 %5 = OpLabel 604 %11 = OpVariable %10 Function 605 %22 = OpVariable %10 Function 606 %35 = OpVariable %34 Function 607 %17 = OpAccessChain %16 %11 %12 %15 608 OpStore %17 %13 609 %21 = OpAccessChain %20 %11 %18 610 OpStore %21 %19 611 %24 = OpAccessChain %23 %11 %12 612 %25 = OpLoad %7 %24 613 %26 = OpAccessChain %23 %22 %12 614 OpStore %26 %25 615 %27 = OpAccessChain %20 %11 %18 616 %28 = OpLoad %8 %27 617 %29 = OpIAdd %8 %28 %18 618 %30 = OpAccessChain %20 %22 %18 619 OpStore %30 %29 620 %43 = OpAccessChain %20 %11 %18 621 %44 = OpLoad %8 %43 622 %45 = OpCompositeConstruct %9 %42 %44 623 %46 = OpCompositeConstruct %32 %39 %45 624 %47 = OpLoad %9 %22 625 %48 = OpCompositeConstruct %33 %46 %47 %40 626 OpStore %35 %48 627 %49 = OpLoad %9 %11 628 %50 = OpAccessChain %10 %35 %12 %12 629 OpStore %50 %49 630 %51 = OpLoad %9 %22 631 %52 = OpAccessChain %10 %35 %12 %18 632 OpStore %52 %51 633 %53 = OpAccessChain %10 %35 %12 %12 634 %54 = OpLoad %9 %53 635 %55 = OpAccessChain %10 %35 %18 636 OpStore %55 %54 637 %57 = OpAccessChain %16 %35 %38 638 OpStore %57 %56 639 OpReturn 640 OpFunctionEnd 641 )"; 642 643 const auto env = SPV_ENV_UNIVERSAL_1_3; 644 const auto consumer = nullptr; 645 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); 646 spvtools::ValidatorOptions validator_options; 647 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 648 kConsoleMessageConsumer)); 649 TransformationContext transformation_context( 650 MakeUnique<FactManager>(context.get()), validator_options); 651 // make an Inner 652 TransformationCompositeConstruct make_inner( 653 9, {25, 19}, MakeInstructionDescriptor(57, spv::Op::OpAccessChain, 0), 654 200); 655 // Bad: Too few fields to make the struct. 656 TransformationCompositeConstruct make_inner_bad( 657 9, {25}, MakeInstructionDescriptor(57, spv::Op::OpAccessChain, 0), 200); 658 // The first component does not correspond to an instruction with a result 659 // type so this check should return false. 660 TransformationCompositeConstruct make_inner_nores( 661 9, {2, 19}, MakeInstructionDescriptor(57, spv::Op::OpAccessChain, 0), 662 200); 663 ASSERT_TRUE(make_inner.IsApplicable(context.get(), transformation_context)); 664 ASSERT_FALSE( 665 make_inner_bad.IsApplicable(context.get(), transformation_context)); 666 ASSERT_FALSE( 667 make_inner_nores.IsApplicable(context.get(), transformation_context)); 668 ApplyAndCheckFreshIds(make_inner, context.get(), &transformation_context); 669 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 670 kConsoleMessageConsumer)); 671 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 672 MakeDataDescriptor(25, {}), MakeDataDescriptor(200, {0}))); 673 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 674 MakeDataDescriptor(19, {}), MakeDataDescriptor(200, {1}))); 675 676 // make an Outer 677 TransformationCompositeConstruct make_outer( 678 33, {46, 200, 56}, 679 MakeInstructionDescriptor(200, spv::Op::OpAccessChain, 0), 201); 680 // Bad: %200 is not available at the desired program point. 681 TransformationCompositeConstruct make_outer_bad( 682 33, {46, 200, 56}, 683 MakeInstructionDescriptor(200, spv::Op::OpCompositeConstruct, 0), 201); 684 ASSERT_TRUE(make_outer.IsApplicable(context.get(), transformation_context)); 685 ASSERT_FALSE( 686 make_outer_bad.IsApplicable(context.get(), transformation_context)); 687 ApplyAndCheckFreshIds(make_outer, context.get(), &transformation_context); 688 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 689 kConsoleMessageConsumer)); 690 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 691 MakeDataDescriptor(46, {}), MakeDataDescriptor(201, {0}))); 692 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 693 MakeDataDescriptor(200, {}), MakeDataDescriptor(201, {1}))); 694 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 695 MakeDataDescriptor(56, {}), MakeDataDescriptor(201, {2}))); 696 697 std::string after_transformation = R"( 698 OpCapability Shader 699 %1 = OpExtInstImport "GLSL.std.450" 700 OpMemoryModel Logical GLSL450 701 OpEntryPoint Fragment %4 "main" 702 OpExecutionMode %4 OriginUpperLeft 703 OpSource ESSL 310 704 OpName %4 "main" 705 OpName %9 "Inner" 706 OpMemberName %9 0 "a" 707 OpMemberName %9 1 "b" 708 OpName %11 "i1" 709 OpName %22 "i2" 710 OpName %33 "Outer" 711 OpMemberName %33 0 "c" 712 OpMemberName %33 1 "d" 713 OpMemberName %33 2 "e" 714 OpName %35 "o" 715 %2 = OpTypeVoid 716 %3 = OpTypeFunction %2 717 %6 = OpTypeFloat 32 718 %7 = OpTypeVector %6 2 719 %8 = OpTypeInt 32 1 720 %9 = OpTypeStruct %7 %8 721 %10 = OpTypePointer Function %9 722 %12 = OpConstant %8 0 723 %13 = OpConstant %6 2 724 %14 = OpTypeInt 32 0 725 %15 = OpConstant %14 0 726 %16 = OpTypePointer Function %6 727 %18 = OpConstant %8 1 728 %19 = OpConstant %8 3 729 %20 = OpTypePointer Function %8 730 %23 = OpTypePointer Function %7 731 %31 = OpConstant %14 2 732 %32 = OpTypeArray %9 %31 733 %33 = OpTypeStruct %32 %9 %6 734 %34 = OpTypePointer Function %33 735 %36 = OpConstant %6 1 736 %37 = OpConstantComposite %7 %36 %13 737 %38 = OpConstant %8 2 738 %39 = OpConstantComposite %9 %37 %38 739 %40 = OpConstant %6 3 740 %41 = OpConstant %6 4 741 %42 = OpConstantComposite %7 %40 %41 742 %56 = OpConstant %6 5 743 %100 = OpUndef %9 744 %4 = OpFunction %2 None %3 745 %5 = OpLabel 746 %11 = OpVariable %10 Function 747 %22 = OpVariable %10 Function 748 %35 = OpVariable %34 Function 749 %17 = OpAccessChain %16 %11 %12 %15 750 OpStore %17 %13 751 %21 = OpAccessChain %20 %11 %18 752 OpStore %21 %19 753 %24 = OpAccessChain %23 %11 %12 754 %25 = OpLoad %7 %24 755 %26 = OpAccessChain %23 %22 %12 756 OpStore %26 %25 757 %27 = OpAccessChain %20 %11 %18 758 %28 = OpLoad %8 %27 759 %29 = OpIAdd %8 %28 %18 760 %30 = OpAccessChain %20 %22 %18 761 OpStore %30 %29 762 %43 = OpAccessChain %20 %11 %18 763 %44 = OpLoad %8 %43 764 %45 = OpCompositeConstruct %9 %42 %44 765 %46 = OpCompositeConstruct %32 %39 %45 766 %47 = OpLoad %9 %22 767 %48 = OpCompositeConstruct %33 %46 %47 %40 768 OpStore %35 %48 769 %49 = OpLoad %9 %11 770 %50 = OpAccessChain %10 %35 %12 %12 771 OpStore %50 %49 772 %51 = OpLoad %9 %22 773 %52 = OpAccessChain %10 %35 %12 %18 774 OpStore %52 %51 775 %53 = OpAccessChain %10 %35 %12 %12 776 %54 = OpLoad %9 %53 777 %55 = OpAccessChain %10 %35 %18 778 OpStore %55 %54 779 %200 = OpCompositeConstruct %9 %25 %19 780 %201 = OpCompositeConstruct %33 %46 %200 %56 781 %57 = OpAccessChain %16 %35 %38 782 OpStore %57 %56 783 OpReturn 784 OpFunctionEnd 785 )"; 786 787 ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); 788} 789 790TEST(TransformationCompositeConstructTest, ConstructVectors) { 791 std::string shader = R"( 792 OpCapability Shader 793 %1 = OpExtInstImport "GLSL.std.450" 794 OpMemoryModel Logical GLSL450 795 OpEntryPoint Fragment %4 "main" 796 OpExecutionMode %4 OriginUpperLeft 797 OpSource ESSL 310 798 OpName %4 "main" 799 OpName %9 "v2" 800 OpName %27 "v3" 801 OpName %46 "v4" 802 OpName %53 "iv2" 803 OpName %61 "uv3" 804 OpName %72 "bv4" 805 OpName %88 "uv2" 806 OpName %95 "bv3" 807 OpName %104 "bv2" 808 OpName %116 "iv3" 809 OpName %124 "iv4" 810 OpName %133 "uv4" 811 %2 = OpTypeVoid 812 %3 = OpTypeFunction %2 813 %6 = OpTypeFloat 32 814 %7 = OpTypeVector %6 2 815 %8 = OpTypePointer Function %7 816 %10 = OpConstant %6 1 817 %11 = OpConstant %6 2 818 %12 = OpConstantComposite %7 %10 %11 819 %13 = OpTypeInt 32 0 820 %14 = OpConstant %13 0 821 %15 = OpTypePointer Function %6 822 %18 = OpConstant %13 1 823 %21 = OpTypeBool 824 %25 = OpTypeVector %6 3 825 %26 = OpTypePointer Function %25 826 %33 = OpConstant %6 3 827 %34 = OpConstant %6 -0.756802499 828 %38 = OpConstant %13 2 829 %44 = OpTypeVector %6 4 830 %45 = OpTypePointer Function %44 831 %50 = OpTypeInt 32 1 832 %51 = OpTypeVector %50 2 833 %52 = OpTypePointer Function %51 834 %57 = OpTypePointer Function %50 835 %59 = OpTypeVector %13 3 836 %60 = OpTypePointer Function %59 837 %65 = OpConstant %13 3 838 %67 = OpTypePointer Function %13 839 %70 = OpTypeVector %21 4 840 %71 = OpTypePointer Function %70 841 %73 = OpConstantTrue %21 842 %74 = OpTypePointer Function %21 843 %86 = OpTypeVector %13 2 844 %87 = OpTypePointer Function %86 845 %93 = OpTypeVector %21 3 846 %94 = OpTypePointer Function %93 847 %102 = OpTypeVector %21 2 848 %103 = OpTypePointer Function %102 849 %111 = OpConstantFalse %21 850 %114 = OpTypeVector %50 3 851 %115 = OpTypePointer Function %114 852 %117 = OpConstant %50 3 853 %122 = OpTypeVector %50 4 854 %123 = OpTypePointer Function %122 855 %131 = OpTypeVector %13 4 856 %132 = OpTypePointer Function %131 857 %4 = OpFunction %2 None %3 858 %5 = OpLabel 859 %9 = OpVariable %8 Function 860 %27 = OpVariable %26 Function 861 %46 = OpVariable %45 Function 862 %53 = OpVariable %52 Function 863 %61 = OpVariable %60 Function 864 %72 = OpVariable %71 Function 865 %88 = OpVariable %87 Function 866 %95 = OpVariable %94 Function 867 %104 = OpVariable %103 Function 868 %116 = OpVariable %115 Function 869 %124 = OpVariable %123 Function 870 %133 = OpVariable %132 Function 871 OpStore %9 %12 872 %16 = OpAccessChain %15 %9 %14 873 %17 = OpLoad %6 %16 874 %19 = OpAccessChain %15 %9 %18 875 %20 = OpLoad %6 %19 876 %22 = OpFOrdGreaterThan %21 %17 %20 877 OpSelectionMerge %24 None 878 OpBranchConditional %22 %23 %101 879 %23 = OpLabel 880 %28 = OpAccessChain %15 %9 %14 881 %29 = OpLoad %6 %28 882 %30 = OpAccessChain %15 %9 %18 883 %31 = OpLoad %6 %30 884 %32 = OpFAdd %6 %29 %31 885 %35 = OpCompositeConstruct %25 %32 %33 %34 886 OpStore %27 %35 887 %36 = OpAccessChain %15 %27 %14 888 %37 = OpLoad %6 %36 889 %39 = OpAccessChain %15 %27 %38 890 %40 = OpLoad %6 %39 891 %41 = OpFOrdLessThan %21 %37 %40 892 OpSelectionMerge %43 None 893 OpBranchConditional %41 %42 %69 894 %42 = OpLabel 895 %47 = OpAccessChain %15 %9 %18 896 %48 = OpLoad %6 %47 897 %49 = OpAccessChain %15 %46 %14 898 OpStore %49 %48 899 %54 = OpAccessChain %15 %27 %38 900 %55 = OpLoad %6 %54 901 %56 = OpConvertFToS %50 %55 902 %58 = OpAccessChain %57 %53 %14 903 OpStore %58 %56 904 %62 = OpAccessChain %15 %46 %14 905 %63 = OpLoad %6 %62 906 %64 = OpConvertFToU %13 %63 907 %66 = OpIAdd %13 %64 %65 908 %68 = OpAccessChain %67 %61 %14 909 OpStore %68 %66 910 OpBranch %43 911 %69 = OpLabel 912 %75 = OpAccessChain %74 %72 %14 913 OpStore %75 %73 914 %76 = OpAccessChain %74 %72 %14 915 %77 = OpLoad %21 %76 916 %78 = OpLogicalNot %21 %77 917 %79 = OpAccessChain %74 %72 %18 918 OpStore %79 %78 919 %80 = OpAccessChain %74 %72 %14 920 %81 = OpLoad %21 %80 921 %82 = OpAccessChain %74 %72 %18 922 %83 = OpLoad %21 %82 923 %84 = OpLogicalAnd %21 %81 %83 924 %85 = OpAccessChain %74 %72 %38 925 OpStore %85 %84 926 %89 = OpAccessChain %67 %88 %14 927 %90 = OpLoad %13 %89 928 %91 = OpINotEqual %21 %90 %14 929 %92 = OpAccessChain %74 %72 %65 930 OpStore %92 %91 931 OpBranch %43 932 %43 = OpLabel 933 %96 = OpLoad %70 %72 934 %97 = OpCompositeExtract %21 %96 0 935 %98 = OpCompositeExtract %21 %96 1 936 %99 = OpCompositeExtract %21 %96 2 937 %100 = OpCompositeConstruct %93 %97 %98 %99 938 OpStore %95 %100 939 OpBranch %24 940 %101 = OpLabel 941 %105 = OpAccessChain %67 %88 %14 942 %106 = OpLoad %13 %105 943 %107 = OpINotEqual %21 %106 %14 944 %108 = OpCompositeConstruct %102 %107 %107 945 OpStore %104 %108 946 OpBranch %24 947 %24 = OpLabel 948 %109 = OpAccessChain %74 %104 %18 949 %110 = OpLoad %21 %109 950 %112 = OpLogicalOr %21 %110 %111 951 %113 = OpAccessChain %74 %104 %14 952 OpStore %113 %112 953 %118 = OpAccessChain %57 %116 %14 954 OpStore %118 %117 955 %119 = OpAccessChain %57 %116 %14 956 %120 = OpLoad %50 %119 957 %121 = OpAccessChain %57 %53 %18 958 OpStore %121 %120 959 %125 = OpAccessChain %57 %116 %14 960 %126 = OpLoad %50 %125 961 %127 = OpAccessChain %57 %53 %18 962 %128 = OpLoad %50 %127 963 %129 = OpIAdd %50 %126 %128 964 %130 = OpAccessChain %57 %124 %65 965 OpStore %130 %129 966 %134 = OpAccessChain %57 %116 %14 967 %135 = OpLoad %50 %134 968 %136 = OpBitcast %13 %135 969 %137 = OpAccessChain %67 %133 %14 970 OpStore %137 %136 971 OpReturn 972 OpFunctionEnd 973 )"; 974 975 const auto env = SPV_ENV_UNIVERSAL_1_3; 976 const auto consumer = nullptr; 977 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); 978 spvtools::ValidatorOptions validator_options; 979 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 980 kConsoleMessageConsumer)); 981 TransformationContext transformation_context( 982 MakeUnique<FactManager>(context.get()), validator_options); 983 TransformationCompositeConstruct make_vec2( 984 7, {17, 11}, MakeInstructionDescriptor(100, spv::Op::OpStore, 0), 200); 985 // Bad: not enough data for a vec2 986 TransformationCompositeConstruct make_vec2_bad( 987 7, {11}, MakeInstructionDescriptor(100, spv::Op::OpStore, 0), 200); 988 ASSERT_TRUE(make_vec2.IsApplicable(context.get(), transformation_context)); 989 ASSERT_FALSE( 990 make_vec2_bad.IsApplicable(context.get(), transformation_context)); 991 ApplyAndCheckFreshIds(make_vec2, context.get(), &transformation_context); 992 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 993 kConsoleMessageConsumer)); 994 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 995 MakeDataDescriptor(17, {}), MakeDataDescriptor(200, {0}))); 996 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 997 MakeDataDescriptor(11, {}), MakeDataDescriptor(200, {1}))); 998 999 TransformationCompositeConstruct make_vec3( 1000 25, {12, 32}, 1001 MakeInstructionDescriptor(35, spv::Op::OpCompositeConstruct, 0), 201); 1002 // Bad: too much data for a vec3 1003 TransformationCompositeConstruct make_vec3_bad( 1004 25, {12, 32, 32}, 1005 MakeInstructionDescriptor(35, spv::Op::OpCompositeConstruct, 0), 201); 1006 ASSERT_TRUE(make_vec3.IsApplicable(context.get(), transformation_context)); 1007 ASSERT_FALSE( 1008 make_vec3_bad.IsApplicable(context.get(), transformation_context)); 1009 ApplyAndCheckFreshIds(make_vec3, context.get(), &transformation_context); 1010 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 1011 kConsoleMessageConsumer)); 1012 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1013 MakeDataDescriptor(12, {0}), MakeDataDescriptor(201, {0}))); 1014 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1015 MakeDataDescriptor(12, {1}), MakeDataDescriptor(201, {1}))); 1016 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1017 MakeDataDescriptor(32, {}), MakeDataDescriptor(201, {2}))); 1018 1019 TransformationCompositeConstruct make_vec4( 1020 44, {32, 32, 10, 11}, 1021 MakeInstructionDescriptor(75, spv::Op::OpAccessChain, 0), 202); 1022 // Bad: id 48 is not available at the insertion points 1023 TransformationCompositeConstruct make_vec4_bad( 1024 44, {48, 32, 10, 11}, 1025 MakeInstructionDescriptor(75, spv::Op::OpAccessChain, 0), 202); 1026 ASSERT_TRUE(make_vec4.IsApplicable(context.get(), transformation_context)); 1027 ASSERT_FALSE( 1028 make_vec4_bad.IsApplicable(context.get(), transformation_context)); 1029 ApplyAndCheckFreshIds(make_vec4, context.get(), &transformation_context); 1030 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 1031 kConsoleMessageConsumer)); 1032 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1033 MakeDataDescriptor(32, {}), MakeDataDescriptor(202, {0}))); 1034 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1035 MakeDataDescriptor(32, {}), MakeDataDescriptor(202, {1}))); 1036 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1037 MakeDataDescriptor(10, {}), MakeDataDescriptor(202, {2}))); 1038 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1039 MakeDataDescriptor(11, {}), MakeDataDescriptor(202, {3}))); 1040 1041 TransformationCompositeConstruct make_ivec2( 1042 51, {126, 120}, MakeInstructionDescriptor(128, spv::Op::OpLoad, 0), 203); 1043 // Bad: if 128 is not available at the instruction that defines 128 1044 TransformationCompositeConstruct make_ivec2_bad( 1045 51, {128, 120}, MakeInstructionDescriptor(128, spv::Op::OpLoad, 0), 203); 1046 ASSERT_TRUE(make_ivec2.IsApplicable(context.get(), transformation_context)); 1047 ASSERT_FALSE( 1048 make_ivec2_bad.IsApplicable(context.get(), transformation_context)); 1049 ApplyAndCheckFreshIds(make_ivec2, context.get(), &transformation_context); 1050 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 1051 kConsoleMessageConsumer)); 1052 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1053 MakeDataDescriptor(126, {}), MakeDataDescriptor(203, {0}))); 1054 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1055 MakeDataDescriptor(120, {}), MakeDataDescriptor(203, {1}))); 1056 1057 TransformationCompositeConstruct make_ivec3( 1058 114, {56, 117, 56}, 1059 MakeInstructionDescriptor(66, spv::Op::OpAccessChain, 0), 204); 1060 // Bad because 1300 is not an id 1061 TransformationCompositeConstruct make_ivec3_bad( 1062 114, {56, 117, 1300}, 1063 MakeInstructionDescriptor(66, spv::Op::OpAccessChain, 0), 204); 1064 ASSERT_TRUE(make_ivec3.IsApplicable(context.get(), transformation_context)); 1065 ASSERT_FALSE( 1066 make_ivec3_bad.IsApplicable(context.get(), transformation_context)); 1067 ApplyAndCheckFreshIds(make_ivec3, context.get(), &transformation_context); 1068 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 1069 kConsoleMessageConsumer)); 1070 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1071 MakeDataDescriptor(56, {}), MakeDataDescriptor(204, {0}))); 1072 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1073 MakeDataDescriptor(117, {}), MakeDataDescriptor(204, {1}))); 1074 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1075 MakeDataDescriptor(56, {}), MakeDataDescriptor(204, {2}))); 1076 1077 TransformationCompositeConstruct make_ivec4( 1078 122, {56, 117, 117, 117}, 1079 MakeInstructionDescriptor(66, spv::Op::OpIAdd, 0), 205); 1080 // Bad because 86 is the wrong type. 1081 TransformationCompositeConstruct make_ivec4_bad( 1082 86, {56, 117, 117, 117}, 1083 MakeInstructionDescriptor(66, spv::Op::OpIAdd, 0), 205); 1084 ASSERT_TRUE(make_ivec4.IsApplicable(context.get(), transformation_context)); 1085 ASSERT_FALSE( 1086 make_ivec4_bad.IsApplicable(context.get(), transformation_context)); 1087 ApplyAndCheckFreshIds(make_ivec4, context.get(), &transformation_context); 1088 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 1089 kConsoleMessageConsumer)); 1090 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1091 MakeDataDescriptor(56, {}), MakeDataDescriptor(205, {0}))); 1092 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1093 MakeDataDescriptor(117, {}), MakeDataDescriptor(205, {1}))); 1094 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1095 MakeDataDescriptor(117, {}), MakeDataDescriptor(205, {2}))); 1096 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1097 MakeDataDescriptor(117, {}), MakeDataDescriptor(205, {3}))); 1098 1099 TransformationCompositeConstruct make_uvec2( 1100 86, {18, 38}, MakeInstructionDescriptor(133, spv::Op::OpAccessChain, 0), 1101 206); 1102 TransformationCompositeConstruct make_uvec2_bad( 1103 86, {18, 38}, MakeInstructionDescriptor(133, spv::Op::OpAccessChain, 200), 1104 206); 1105 ASSERT_TRUE(make_uvec2.IsApplicable(context.get(), transformation_context)); 1106 ASSERT_FALSE( 1107 make_uvec2_bad.IsApplicable(context.get(), transformation_context)); 1108 ApplyAndCheckFreshIds(make_uvec2, context.get(), &transformation_context); 1109 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 1110 kConsoleMessageConsumer)); 1111 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1112 MakeDataDescriptor(18, {}), MakeDataDescriptor(206, {0}))); 1113 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1114 MakeDataDescriptor(38, {}), MakeDataDescriptor(206, {1}))); 1115 1116 TransformationCompositeConstruct make_uvec3( 1117 59, {14, 18, 136}, MakeInstructionDescriptor(137, spv::Op::OpReturn, 0), 1118 207); 1119 // Bad because 1300 is not an id 1120 TransformationCompositeConstruct make_uvec3_bad( 1121 59, {14, 18, 1300}, MakeInstructionDescriptor(137, spv::Op::OpReturn, 0), 1122 207); 1123 ASSERT_TRUE(make_uvec3.IsApplicable(context.get(), transformation_context)); 1124 ASSERT_FALSE( 1125 make_uvec3_bad.IsApplicable(context.get(), transformation_context)); 1126 ApplyAndCheckFreshIds(make_uvec3, context.get(), &transformation_context); 1127 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 1128 kConsoleMessageConsumer)); 1129 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1130 MakeDataDescriptor(14, {}), MakeDataDescriptor(207, {0}))); 1131 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1132 MakeDataDescriptor(18, {}), MakeDataDescriptor(207, {1}))); 1133 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1134 MakeDataDescriptor(136, {}), MakeDataDescriptor(207, {2}))); 1135 1136 TransformationCompositeConstruct make_uvec4( 1137 131, {14, 18, 136, 136}, 1138 MakeInstructionDescriptor(137, spv::Op::OpAccessChain, 0), 208); 1139 // Bad because 86 is the wrong type. 1140 TransformationCompositeConstruct make_uvec4_bad( 1141 86, {14, 18, 136, 136}, 1142 MakeInstructionDescriptor(137, spv::Op::OpAccessChain, 0), 208); 1143 ASSERT_TRUE(make_uvec4.IsApplicable(context.get(), transformation_context)); 1144 ASSERT_FALSE( 1145 make_uvec4_bad.IsApplicable(context.get(), transformation_context)); 1146 ApplyAndCheckFreshIds(make_uvec4, context.get(), &transformation_context); 1147 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 1148 kConsoleMessageConsumer)); 1149 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1150 MakeDataDescriptor(14, {}), MakeDataDescriptor(208, {0}))); 1151 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1152 MakeDataDescriptor(18, {}), MakeDataDescriptor(208, {1}))); 1153 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1154 MakeDataDescriptor(136, {}), MakeDataDescriptor(208, {2}))); 1155 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1156 MakeDataDescriptor(136, {}), MakeDataDescriptor(208, {3}))); 1157 1158 TransformationCompositeConstruct make_bvec2( 1159 102, 1160 { 1161 111, 1162 41, 1163 }, 1164 MakeInstructionDescriptor(75, spv::Op::OpAccessChain, 0), 209); 1165 // Bad because 0 is not a valid base instruction id 1166 TransformationCompositeConstruct make_bvec2_bad( 1167 102, 1168 { 1169 111, 1170 41, 1171 }, 1172 MakeInstructionDescriptor(0, spv::Op::OpExtInstImport, 0), 209); 1173 ASSERT_TRUE(make_bvec2.IsApplicable(context.get(), transformation_context)); 1174 ASSERT_FALSE( 1175 make_bvec2_bad.IsApplicable(context.get(), transformation_context)); 1176 ApplyAndCheckFreshIds(make_bvec2, context.get(), &transformation_context); 1177 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 1178 kConsoleMessageConsumer)); 1179 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1180 MakeDataDescriptor(111, {}), MakeDataDescriptor(209, {0}))); 1181 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1182 MakeDataDescriptor(41, {}), MakeDataDescriptor(209, {1}))); 1183 1184 TransformationCompositeConstruct make_bvec3( 1185 93, {108, 73}, MakeInstructionDescriptor(108, spv::Op::OpStore, 0), 210); 1186 // Bad because there are too many components for a bvec3 1187 TransformationCompositeConstruct make_bvec3_bad( 1188 93, {108, 108}, MakeInstructionDescriptor(108, spv::Op::OpStore, 0), 210); 1189 ASSERT_TRUE(make_bvec3.IsApplicable(context.get(), transformation_context)); 1190 ASSERT_FALSE( 1191 make_bvec3_bad.IsApplicable(context.get(), transformation_context)); 1192 ApplyAndCheckFreshIds(make_bvec3, context.get(), &transformation_context); 1193 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 1194 kConsoleMessageConsumer)); 1195 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1196 MakeDataDescriptor(108, {0}), MakeDataDescriptor(210, {0}))); 1197 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1198 MakeDataDescriptor(108, {1}), MakeDataDescriptor(210, {1}))); 1199 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1200 MakeDataDescriptor(73, {}), MakeDataDescriptor(210, {2}))); 1201 1202 TransformationCompositeConstruct make_bvec4( 1203 70, {108, 108}, MakeInstructionDescriptor(108, spv::Op::OpBranch, 0), 1204 211); 1205 // Bad because 21 is a type, not a result id 1206 TransformationCompositeConstruct make_bvec4_bad( 1207 70, {21, 108}, MakeInstructionDescriptor(108, spv::Op::OpBranch, 0), 211); 1208 ASSERT_TRUE(make_bvec4.IsApplicable(context.get(), transformation_context)); 1209 ASSERT_FALSE( 1210 make_bvec4_bad.IsApplicable(context.get(), transformation_context)); 1211 ApplyAndCheckFreshIds(make_bvec4, context.get(), &transformation_context); 1212 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 1213 kConsoleMessageConsumer)); 1214 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1215 MakeDataDescriptor(108, {0}), MakeDataDescriptor(211, {0}))); 1216 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1217 MakeDataDescriptor(108, {1}), MakeDataDescriptor(211, {1}))); 1218 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1219 MakeDataDescriptor(108, {0}), MakeDataDescriptor(211, {2}))); 1220 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1221 MakeDataDescriptor(108, {1}), MakeDataDescriptor(211, {3}))); 1222 1223 std::string after_transformation = R"( 1224 OpCapability Shader 1225 %1 = OpExtInstImport "GLSL.std.450" 1226 OpMemoryModel Logical GLSL450 1227 OpEntryPoint Fragment %4 "main" 1228 OpExecutionMode %4 OriginUpperLeft 1229 OpSource ESSL 310 1230 OpName %4 "main" 1231 OpName %9 "v2" 1232 OpName %27 "v3" 1233 OpName %46 "v4" 1234 OpName %53 "iv2" 1235 OpName %61 "uv3" 1236 OpName %72 "bv4" 1237 OpName %88 "uv2" 1238 OpName %95 "bv3" 1239 OpName %104 "bv2" 1240 OpName %116 "iv3" 1241 OpName %124 "iv4" 1242 OpName %133 "uv4" 1243 %2 = OpTypeVoid 1244 %3 = OpTypeFunction %2 1245 %6 = OpTypeFloat 32 1246 %7 = OpTypeVector %6 2 1247 %8 = OpTypePointer Function %7 1248 %10 = OpConstant %6 1 1249 %11 = OpConstant %6 2 1250 %12 = OpConstantComposite %7 %10 %11 1251 %13 = OpTypeInt 32 0 1252 %14 = OpConstant %13 0 1253 %15 = OpTypePointer Function %6 1254 %18 = OpConstant %13 1 1255 %21 = OpTypeBool 1256 %25 = OpTypeVector %6 3 1257 %26 = OpTypePointer Function %25 1258 %33 = OpConstant %6 3 1259 %34 = OpConstant %6 -0.756802499 1260 %38 = OpConstant %13 2 1261 %44 = OpTypeVector %6 4 1262 %45 = OpTypePointer Function %44 1263 %50 = OpTypeInt 32 1 1264 %51 = OpTypeVector %50 2 1265 %52 = OpTypePointer Function %51 1266 %57 = OpTypePointer Function %50 1267 %59 = OpTypeVector %13 3 1268 %60 = OpTypePointer Function %59 1269 %65 = OpConstant %13 3 1270 %67 = OpTypePointer Function %13 1271 %70 = OpTypeVector %21 4 1272 %71 = OpTypePointer Function %70 1273 %73 = OpConstantTrue %21 1274 %74 = OpTypePointer Function %21 1275 %86 = OpTypeVector %13 2 1276 %87 = OpTypePointer Function %86 1277 %93 = OpTypeVector %21 3 1278 %94 = OpTypePointer Function %93 1279 %102 = OpTypeVector %21 2 1280 %103 = OpTypePointer Function %102 1281 %111 = OpConstantFalse %21 1282 %114 = OpTypeVector %50 3 1283 %115 = OpTypePointer Function %114 1284 %117 = OpConstant %50 3 1285 %122 = OpTypeVector %50 4 1286 %123 = OpTypePointer Function %122 1287 %131 = OpTypeVector %13 4 1288 %132 = OpTypePointer Function %131 1289 %4 = OpFunction %2 None %3 1290 %5 = OpLabel 1291 %9 = OpVariable %8 Function 1292 %27 = OpVariable %26 Function 1293 %46 = OpVariable %45 Function 1294 %53 = OpVariable %52 Function 1295 %61 = OpVariable %60 Function 1296 %72 = OpVariable %71 Function 1297 %88 = OpVariable %87 Function 1298 %95 = OpVariable %94 Function 1299 %104 = OpVariable %103 Function 1300 %116 = OpVariable %115 Function 1301 %124 = OpVariable %123 Function 1302 %133 = OpVariable %132 Function 1303 OpStore %9 %12 1304 %206 = OpCompositeConstruct %86 %18 %38 1305 %16 = OpAccessChain %15 %9 %14 1306 %17 = OpLoad %6 %16 1307 %19 = OpAccessChain %15 %9 %18 1308 %20 = OpLoad %6 %19 1309 %22 = OpFOrdGreaterThan %21 %17 %20 1310 OpSelectionMerge %24 None 1311 OpBranchConditional %22 %23 %101 1312 %23 = OpLabel 1313 %28 = OpAccessChain %15 %9 %14 1314 %29 = OpLoad %6 %28 1315 %30 = OpAccessChain %15 %9 %18 1316 %31 = OpLoad %6 %30 1317 %32 = OpFAdd %6 %29 %31 1318 %201 = OpCompositeConstruct %25 %12 %32 1319 %35 = OpCompositeConstruct %25 %32 %33 %34 1320 OpStore %27 %35 1321 %36 = OpAccessChain %15 %27 %14 1322 %37 = OpLoad %6 %36 1323 %39 = OpAccessChain %15 %27 %38 1324 %40 = OpLoad %6 %39 1325 %41 = OpFOrdLessThan %21 %37 %40 1326 OpSelectionMerge %43 None 1327 OpBranchConditional %41 %42 %69 1328 %42 = OpLabel 1329 %47 = OpAccessChain %15 %9 %18 1330 %48 = OpLoad %6 %47 1331 %49 = OpAccessChain %15 %46 %14 1332 OpStore %49 %48 1333 %54 = OpAccessChain %15 %27 %38 1334 %55 = OpLoad %6 %54 1335 %56 = OpConvertFToS %50 %55 1336 %58 = OpAccessChain %57 %53 %14 1337 OpStore %58 %56 1338 %62 = OpAccessChain %15 %46 %14 1339 %63 = OpLoad %6 %62 1340 %64 = OpConvertFToU %13 %63 1341 %205 = OpCompositeConstruct %122 %56 %117 %117 %117 1342 %66 = OpIAdd %13 %64 %65 1343 %204 = OpCompositeConstruct %114 %56 %117 %56 1344 %68 = OpAccessChain %67 %61 %14 1345 OpStore %68 %66 1346 OpBranch %43 1347 %69 = OpLabel 1348 %202 = OpCompositeConstruct %44 %32 %32 %10 %11 1349 %209 = OpCompositeConstruct %102 %111 %41 1350 %75 = OpAccessChain %74 %72 %14 1351 OpStore %75 %73 1352 %76 = OpAccessChain %74 %72 %14 1353 %77 = OpLoad %21 %76 1354 %78 = OpLogicalNot %21 %77 1355 %79 = OpAccessChain %74 %72 %18 1356 OpStore %79 %78 1357 %80 = OpAccessChain %74 %72 %14 1358 %81 = OpLoad %21 %80 1359 %82 = OpAccessChain %74 %72 %18 1360 %83 = OpLoad %21 %82 1361 %84 = OpLogicalAnd %21 %81 %83 1362 %85 = OpAccessChain %74 %72 %38 1363 OpStore %85 %84 1364 %89 = OpAccessChain %67 %88 %14 1365 %90 = OpLoad %13 %89 1366 %91 = OpINotEqual %21 %90 %14 1367 %92 = OpAccessChain %74 %72 %65 1368 OpStore %92 %91 1369 OpBranch %43 1370 %43 = OpLabel 1371 %96 = OpLoad %70 %72 1372 %97 = OpCompositeExtract %21 %96 0 1373 %98 = OpCompositeExtract %21 %96 1 1374 %99 = OpCompositeExtract %21 %96 2 1375 %100 = OpCompositeConstruct %93 %97 %98 %99 1376 %200 = OpCompositeConstruct %7 %17 %11 1377 OpStore %95 %100 1378 OpBranch %24 1379 %101 = OpLabel 1380 %105 = OpAccessChain %67 %88 %14 1381 %106 = OpLoad %13 %105 1382 %107 = OpINotEqual %21 %106 %14 1383 %108 = OpCompositeConstruct %102 %107 %107 1384 %210 = OpCompositeConstruct %93 %108 %73 1385 OpStore %104 %108 1386 %211 = OpCompositeConstruct %70 %108 %108 1387 OpBranch %24 1388 %24 = OpLabel 1389 %109 = OpAccessChain %74 %104 %18 1390 %110 = OpLoad %21 %109 1391 %112 = OpLogicalOr %21 %110 %111 1392 %113 = OpAccessChain %74 %104 %14 1393 OpStore %113 %112 1394 %118 = OpAccessChain %57 %116 %14 1395 OpStore %118 %117 1396 %119 = OpAccessChain %57 %116 %14 1397 %120 = OpLoad %50 %119 1398 %121 = OpAccessChain %57 %53 %18 1399 OpStore %121 %120 1400 %125 = OpAccessChain %57 %116 %14 1401 %126 = OpLoad %50 %125 1402 %127 = OpAccessChain %57 %53 %18 1403 %203 = OpCompositeConstruct %51 %126 %120 1404 %128 = OpLoad %50 %127 1405 %129 = OpIAdd %50 %126 %128 1406 %130 = OpAccessChain %57 %124 %65 1407 OpStore %130 %129 1408 %134 = OpAccessChain %57 %116 %14 1409 %135 = OpLoad %50 %134 1410 %136 = OpBitcast %13 %135 1411 %208 = OpCompositeConstruct %131 %14 %18 %136 %136 1412 %137 = OpAccessChain %67 %133 %14 1413 OpStore %137 %136 1414 %207 = OpCompositeConstruct %59 %14 %18 %136 1415 OpReturn 1416 OpFunctionEnd 1417 )"; 1418 1419 ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); 1420} 1421 1422TEST(TransformationCompositeConstructTest, AddSynonymsForRelevantIds) { 1423 std::string shader = R"( 1424 OpCapability Shader 1425 %1 = OpExtInstImport "GLSL.std.450" 1426 OpMemoryModel Logical GLSL450 1427 OpEntryPoint Fragment %4 "main" 1428 OpExecutionMode %4 OriginUpperLeft 1429 OpSource ESSL 310 1430 %2 = OpTypeVoid 1431 %3 = OpTypeFunction %2 1432 %6 = OpTypeFloat 32 1433 %7 = OpTypeVector %6 3 1434 %8 = OpTypePointer Function %7 1435 %10 = OpConstant %6 1 1436 %11 = OpConstantComposite %7 %10 %10 %10 1437 %17 = OpTypeVector %6 4 1438 %18 = OpTypePointer Function %17 1439 %21 = OpConstant %6 2 1440 %32 = OpTypeMatrix %17 3 1441 %33 = OpTypePointer Private %32 1442 %34 = OpVariable %33 Private 1443 %35 = OpTypeMatrix %7 4 1444 %36 = OpTypePointer Private %35 1445 %37 = OpVariable %36 Private 1446 %38 = OpTypeVector %6 2 1447 %39 = OpTypeInt 32 0 1448 %40 = OpConstant %39 3 1449 %41 = OpTypeArray %38 %40 1450 %42 = OpTypePointer Private %41 1451 %43 = OpVariable %42 Private 1452 %100 = OpUndef %7 1453 %101 = OpUndef %17 1454 %4 = OpFunction %2 None %3 1455 %5 = OpLabel 1456 %9 = OpVariable %8 Function 1457 %12 = OpVariable %8 Function 1458 %14 = OpVariable %8 Function 1459 %19 = OpVariable %18 Function 1460 %26 = OpVariable %18 Function 1461 %29 = OpVariable %18 Function 1462 OpStore %9 %11 1463 %13 = OpLoad %7 %9 1464 OpStore %12 %13 1465 %15 = OpLoad %7 %12 1466 %16 = OpVectorShuffle %7 %15 %15 2 1 0 1467 OpStore %14 %16 1468 %20 = OpLoad %7 %14 1469 %22 = OpCompositeExtract %6 %20 0 1470 %23 = OpCompositeExtract %6 %20 1 1471 %24 = OpCompositeExtract %6 %20 2 1472 %25 = OpCompositeConstruct %17 %22 %23 %24 %21 1473 OpStore %19 %25 1474 %27 = OpLoad %17 %19 1475 %28 = OpVectorShuffle %17 %27 %27 3 2 1 0 1476 OpStore %26 %28 1477 %30 = OpLoad %7 %9 1478 %31 = OpVectorShuffle %17 %30 %30 0 0 1 1 1479 OpStore %29 %31 1480 OpReturn 1481 OpFunctionEnd 1482 )"; 1483 1484 const auto env = SPV_ENV_UNIVERSAL_1_3; 1485 const auto consumer = nullptr; 1486 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); 1487 spvtools::ValidatorOptions validator_options; 1488 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 1489 kConsoleMessageConsumer)); 1490 TransformationContext transformation_context( 1491 MakeUnique<FactManager>(context.get()), validator_options); 1492 TransformationCompositeConstruct transformation( 1493 32, {25, 28, 31}, MakeInstructionDescriptor(31, spv::Op::OpReturn, 0), 1494 200); 1495 ASSERT_TRUE( 1496 transformation.IsApplicable(context.get(), transformation_context)); 1497 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context); 1498 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 1499 kConsoleMessageConsumer)); 1500 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1501 MakeDataDescriptor(25, {}), MakeDataDescriptor(200, {0}))); 1502 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1503 MakeDataDescriptor(28, {}), MakeDataDescriptor(200, {1}))); 1504} 1505 1506TEST(TransformationCompositeConstructTest, DontAddSynonymsForIrrelevantIds) { 1507 std::string shader = R"( 1508 OpCapability Shader 1509 %1 = OpExtInstImport "GLSL.std.450" 1510 OpMemoryModel Logical GLSL450 1511 OpEntryPoint Fragment %4 "main" 1512 OpExecutionMode %4 OriginUpperLeft 1513 OpSource ESSL 310 1514 %2 = OpTypeVoid 1515 %3 = OpTypeFunction %2 1516 %6 = OpTypeFloat 32 1517 %7 = OpTypeVector %6 3 1518 %8 = OpTypePointer Function %7 1519 %10 = OpConstant %6 1 1520 %11 = OpConstantComposite %7 %10 %10 %10 1521 %17 = OpTypeVector %6 4 1522 %18 = OpTypePointer Function %17 1523 %21 = OpConstant %6 2 1524 %32 = OpTypeMatrix %17 3 1525 %33 = OpTypePointer Private %32 1526 %34 = OpVariable %33 Private 1527 %35 = OpTypeMatrix %7 4 1528 %36 = OpTypePointer Private %35 1529 %37 = OpVariable %36 Private 1530 %38 = OpTypeVector %6 2 1531 %39 = OpTypeInt 32 0 1532 %40 = OpConstant %39 3 1533 %41 = OpTypeArray %38 %40 1534 %42 = OpTypePointer Private %41 1535 %43 = OpVariable %42 Private 1536 %100 = OpUndef %7 1537 %101 = OpUndef %17 1538 %4 = OpFunction %2 None %3 1539 %5 = OpLabel 1540 %9 = OpVariable %8 Function 1541 %12 = OpVariable %8 Function 1542 %14 = OpVariable %8 Function 1543 %19 = OpVariable %18 Function 1544 %26 = OpVariable %18 Function 1545 %29 = OpVariable %18 Function 1546 OpStore %9 %11 1547 %13 = OpLoad %7 %9 1548 OpStore %12 %13 1549 %15 = OpLoad %7 %12 1550 %16 = OpVectorShuffle %7 %15 %15 2 1 0 1551 OpStore %14 %16 1552 %20 = OpLoad %7 %14 1553 %22 = OpCompositeExtract %6 %20 0 1554 %23 = OpCompositeExtract %6 %20 1 1555 %24 = OpCompositeExtract %6 %20 2 1556 %25 = OpCompositeConstruct %17 %22 %23 %24 %21 1557 OpStore %19 %25 1558 %27 = OpLoad %17 %19 1559 %28 = OpVectorShuffle %17 %27 %27 3 2 1 0 1560 OpStore %26 %28 1561 %30 = OpLoad %7 %9 1562 %31 = OpVectorShuffle %17 %30 %30 0 0 1 1 1563 OpStore %29 %31 1564 OpReturn 1565 OpFunctionEnd 1566 )"; 1567 1568 const auto env = SPV_ENV_UNIVERSAL_1_3; 1569 const auto consumer = nullptr; 1570 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); 1571 spvtools::ValidatorOptions validator_options; 1572 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 1573 kConsoleMessageConsumer)); 1574 TransformationContext transformation_context( 1575 MakeUnique<FactManager>(context.get()), validator_options); 1576 transformation_context.GetFactManager()->AddFactIdIsIrrelevant(25); 1577 1578 TransformationCompositeConstruct transformation( 1579 32, {25, 28, 31}, MakeInstructionDescriptor(31, spv::Op::OpReturn, 0), 1580 200); 1581 ASSERT_TRUE( 1582 transformation.IsApplicable(context.get(), transformation_context)); 1583 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context); 1584 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 1585 kConsoleMessageConsumer)); 1586 ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous( 1587 MakeDataDescriptor(25, {}), MakeDataDescriptor(200, {0}))); 1588 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1589 MakeDataDescriptor(28, {}), MakeDataDescriptor(200, {1}))); 1590 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1591 MakeDataDescriptor(31, {}), MakeDataDescriptor(200, {2}))); 1592} 1593 1594TEST(TransformationCompositeConstructTest, DontAddSynonymsInDeadBlock) { 1595 std::string shader = R"( 1596 OpCapability Shader 1597 %1 = OpExtInstImport "GLSL.std.450" 1598 OpMemoryModel Logical GLSL450 1599 OpEntryPoint Fragment %4 "main" 1600 OpExecutionMode %4 OriginUpperLeft 1601 OpSource ESSL 320 1602 %2 = OpTypeVoid 1603 %3 = OpTypeFunction %2 1604 %6 = OpTypeInt 32 1 1605 %7 = OpTypeVector %6 2 1606 %8 = OpTypePointer Function %7 1607 %10 = OpConstant %6 0 1608 %11 = OpConstant %6 1 1609 %12 = OpConstantComposite %7 %10 %11 1610 %13 = OpTypeBool 1611 %14 = OpConstantFalse %13 1612 %4 = OpFunction %2 None %3 1613 %5 = OpLabel 1614 %9 = OpVariable %8 Function 1615 OpStore %9 %12 1616 OpSelectionMerge %16 None 1617 OpBranchConditional %14 %15 %16 1618 %15 = OpLabel 1619 OpBranch %16 1620 %16 = OpLabel 1621 OpReturn 1622 OpFunctionEnd 1623 )"; 1624 1625 const auto env = SPV_ENV_UNIVERSAL_1_3; 1626 const auto consumer = nullptr; 1627 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); 1628 spvtools::ValidatorOptions validator_options; 1629 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 1630 kConsoleMessageConsumer)); 1631 TransformationContext transformation_context( 1632 MakeUnique<FactManager>(context.get()), validator_options); 1633 transformation_context.GetFactManager()->AddFactBlockIsDead(15); 1634 1635 TransformationCompositeConstruct transformation( 1636 7, {10, 11}, MakeInstructionDescriptor(15, spv::Op::OpBranch, 0), 100); 1637 ASSERT_TRUE( 1638 transformation.IsApplicable(context.get(), transformation_context)); 1639 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context); 1640 ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous( 1641 MakeDataDescriptor(100, {0}), MakeDataDescriptor(10, {}))); 1642 ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous( 1643 MakeDataDescriptor(100, {1}), MakeDataDescriptor(11, {}))); 1644} 1645 1646TEST(TransformationCompositeConstructTest, OneIrrelevantComponent) { 1647 std::string shader = R"( 1648 OpCapability Shader 1649 %1 = OpExtInstImport "GLSL.std.450" 1650 OpMemoryModel Logical GLSL450 1651 OpEntryPoint Fragment %4 "main" 1652 OpExecutionMode %4 OriginUpperLeft 1653 OpSource ESSL 320 1654 %2 = OpTypeVoid 1655 %3 = OpTypeFunction %2 1656 %6 = OpTypeInt 32 1 1657 %7 = OpTypeStruct %6 %6 %6 1658 %8 = OpConstant %6 42 1659 %9 = OpConstant %6 50 1660 %10 = OpConstant %6 51 1661 %4 = OpFunction %2 None %3 1662 %5 = OpLabel 1663 OpReturn 1664 OpFunctionEnd 1665 )"; 1666 1667 const auto env = SPV_ENV_UNIVERSAL_1_3; 1668 const auto consumer = nullptr; 1669 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); 1670 spvtools::ValidatorOptions validator_options; 1671 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 1672 kConsoleMessageConsumer)); 1673 TransformationContext transformation_context( 1674 MakeUnique<FactManager>(context.get()), validator_options); 1675 transformation_context.GetFactManager()->AddFactIdIsIrrelevant(8); 1676 1677 TransformationCompositeConstruct transformation( 1678 7, {8, 9, 10}, MakeInstructionDescriptor(5, spv::Op::OpReturn, 0), 100); 1679 ASSERT_TRUE( 1680 transformation.IsApplicable(context.get(), transformation_context)); 1681 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context); 1682 ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous( 1683 MakeDataDescriptor(100, {0}), MakeDataDescriptor(8, {}))); 1684 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1685 MakeDataDescriptor(100, {1}), MakeDataDescriptor(9, {}))); 1686 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1687 MakeDataDescriptor(100, {2}), MakeDataDescriptor(10, {}))); 1688} 1689 1690TEST(TransformationCompositeConstructTest, IrrelevantVec2ThenFloat) { 1691 std::string shader = R"( 1692 OpCapability Shader 1693 %1 = OpExtInstImport "GLSL.std.450" 1694 OpMemoryModel Logical GLSL450 1695 OpEntryPoint Fragment %4 "main" 1696 OpExecutionMode %4 OriginUpperLeft 1697 OpSource ESSL 320 1698 %2 = OpTypeVoid 1699 %3 = OpTypeFunction %2 1700 %6 = OpTypeFloat 32 1701 %7 = OpTypeVector %6 2 1702 %8 = OpTypeVector %6 3 1703 %9 = OpConstant %6 0 1704 %11 = OpConstant %6 1 1705 %12 = OpConstant %6 2 1706 %10 = OpConstantComposite %7 %11 %12 1707 %4 = OpFunction %2 None %3 1708 %5 = OpLabel 1709 OpReturn 1710 OpFunctionEnd 1711 )"; 1712 1713 const auto env = SPV_ENV_UNIVERSAL_1_3; 1714 const auto consumer = nullptr; 1715 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); 1716 spvtools::ValidatorOptions validator_options; 1717 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options, 1718 kConsoleMessageConsumer)); 1719 TransformationContext transformation_context( 1720 MakeUnique<FactManager>(context.get()), validator_options); 1721 1722 transformation_context.GetFactManager()->AddFactIdIsIrrelevant(10); 1723 1724 TransformationCompositeConstruct transformation( 1725 8, {10, 9}, MakeInstructionDescriptor(5, spv::Op::OpReturn, 0), 100); 1726 ASSERT_TRUE( 1727 transformation.IsApplicable(context.get(), transformation_context)); 1728 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context); 1729 ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous( 1730 MakeDataDescriptor(100, {0}), MakeDataDescriptor(10, {0}))); 1731 ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous( 1732 MakeDataDescriptor(100, {1}), MakeDataDescriptor(10, {1}))); 1733 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( 1734 MakeDataDescriptor(100, {2}), MakeDataDescriptor(9, {}))); 1735 ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous( 1736 MakeDataDescriptor(100, {1}), MakeDataDescriptor(9, {}))); 1737} 1738 1739} // namespace 1740} // namespace fuzz 1741} // namespace spvtools 1742