1 // Copyright (c) 2018 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 <memory> 16 #include <set> 17 #include <string> 18 #include <unordered_set> 19 #include <utility> 20 #include <vector> 21 22 #include "gmock/gmock.h" 23 #include "source/opt/iterator.h" 24 #include "source/opt/loop_dependence.h" 25 #include "source/opt/loop_descriptor.h" 26 #include "source/opt/pass.h" 27 #include "source/opt/tree_iterator.h" 28 #include "test/opt//assembly_builder.h" 29 #include "test/opt//function_utils.h" 30 #include "test/opt//pass_fixture.h" 31 #include "test/opt//pass_utils.h" 32 33 namespace spvtools { 34 namespace opt { 35 namespace { 36 37 using DependencyAnalysis = ::testing::Test; 38 39 /* 40 Generated from the following GLSL fragment shader 41 with --eliminate-local-multi-store 42 #version 440 core 43 void main(){ 44 int[10] arr; 45 int[10] arr2; 46 int a = 2; 47 for (int i = 0; i < 10; i++) { 48 arr[a] = arr[3]; 49 arr[a*2] = arr[a+3]; 50 arr[6] = arr2[6]; 51 arr[a+5] = arr2[7]; 52 } 53 } 54 */ 55 TEST(DependencyAnalysis, ZIV) { 56 const std::string text = R"( OpCapability Shader 57 %1 = OpExtInstImport "GLSL.std.450" 58 OpMemoryModel Logical GLSL450 59 OpEntryPoint Fragment %4 "main" 60 OpExecutionMode %4 OriginUpperLeft 61 OpSource GLSL 440 62 OpName %4 "main" 63 OpName %25 "arr" 64 OpName %39 "arr2" 65 %2 = OpTypeVoid 66 %3 = OpTypeFunction %2 67 %6 = OpTypeInt 32 1 68 %7 = OpTypePointer Function %6 69 %9 = OpConstant %6 2 70 %11 = OpConstant %6 0 71 %18 = OpConstant %6 10 72 %19 = OpTypeBool 73 %21 = OpTypeInt 32 0 74 %22 = OpConstant %21 10 75 %23 = OpTypeArray %6 %22 76 %24 = OpTypePointer Function %23 77 %27 = OpConstant %6 3 78 %38 = OpConstant %6 6 79 %44 = OpConstant %6 5 80 %46 = OpConstant %6 7 81 %51 = OpConstant %6 1 82 %4 = OpFunction %2 None %3 83 %5 = OpLabel 84 %25 = OpVariable %24 Function 85 %39 = OpVariable %24 Function 86 OpBranch %12 87 %12 = OpLabel 88 %53 = OpPhi %6 %11 %5 %52 %15 89 OpLoopMerge %14 %15 None 90 OpBranch %16 91 %16 = OpLabel 92 %20 = OpSLessThan %19 %53 %18 93 OpBranchConditional %20 %13 %14 94 %13 = OpLabel 95 %28 = OpAccessChain %7 %25 %27 96 %29 = OpLoad %6 %28 97 %30 = OpAccessChain %7 %25 %9 98 OpStore %30 %29 99 %32 = OpIMul %6 %9 %9 100 %34 = OpIAdd %6 %9 %27 101 %35 = OpAccessChain %7 %25 %34 102 %36 = OpLoad %6 %35 103 %37 = OpAccessChain %7 %25 %32 104 OpStore %37 %36 105 %40 = OpAccessChain %7 %39 %38 106 %41 = OpLoad %6 %40 107 %42 = OpAccessChain %7 %25 %38 108 OpStore %42 %41 109 %45 = OpIAdd %6 %9 %44 110 %47 = OpAccessChain %7 %39 %46 111 %48 = OpLoad %6 %47 112 %49 = OpAccessChain %7 %25 %45 113 OpStore %49 %48 114 OpBranch %15 115 %15 = OpLabel 116 %52 = OpIAdd %6 %53 %51 117 OpBranch %12 118 %14 = OpLabel 119 OpReturn 120 OpFunctionEnd 121 )"; 122 std::unique_ptr<IRContext> context = 123 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, 124 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 125 Module* module = context->module(); 126 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n" 127 << text << std::endl; 128 const Function* f = spvtest::GetFunction(module, 4); 129 LoopDescriptor& ld = *context->GetLoopDescriptor(f); 130 131 Loop* loop = &ld.GetLoopByIndex(0); 132 std::vector<const Loop*> loops{loop}; 133 LoopDependenceAnalysis analysis{context.get(), loops}; 134 135 const Instruction* store[4]; 136 int stores_found = 0; 137 for (const Instruction& inst : *spvtest::GetBasicBlock(f, 13)) { 138 if (inst.opcode() == SpvOp::SpvOpStore) { 139 store[stores_found] = &inst; 140 ++stores_found; 141 } 142 } 143 144 for (int i = 0; i < 4; ++i) { 145 EXPECT_TRUE(store[i]); 146 } 147 148 // 29 -> 30 tests looking through constants. 149 { 150 DistanceVector distance_vector{loops.size()}; 151 EXPECT_TRUE(analysis.GetDependence(context->get_def_use_mgr()->GetDef(29), 152 store[0], &distance_vector)); 153 } 154 155 // 36 -> 37 tests looking through additions. 156 { 157 DistanceVector distance_vector{loops.size()}; 158 EXPECT_TRUE(analysis.GetDependence(context->get_def_use_mgr()->GetDef(36), 159 store[1], &distance_vector)); 160 } 161 162 // 41 -> 42 tests looking at same index across two different arrays. 163 { 164 DistanceVector distance_vector{loops.size()}; 165 EXPECT_TRUE(analysis.GetDependence(context->get_def_use_mgr()->GetDef(41), 166 store[2], &distance_vector)); 167 } 168 169 // 48 -> 49 tests looking through additions for same index in two different 170 // arrays. 171 { 172 DistanceVector distance_vector{loops.size()}; 173 EXPECT_TRUE(analysis.GetDependence(context->get_def_use_mgr()->GetDef(48), 174 store[3], &distance_vector)); 175 } 176 } 177 178 /* 179 Generated from the following GLSL fragment shader 180 with --eliminate-local-multi-store 181 #version 440 core 182 layout(location = 0) in vec4 c; 183 void main(){ 184 int[10] arr; 185 int[10] arr2; 186 int[10] arr3; 187 int[10] arr4; 188 int[10] arr5; 189 int N = int(c.x); 190 for (int i = 0; i < N; i++) { 191 arr[2*N] = arr[N]; 192 arr2[2*N+1] = arr2[N]; 193 arr3[2*N] = arr3[N-1]; 194 arr4[N] = arr5[N]; 195 } 196 } 197 */ 198 TEST(DependencyAnalysis, SymbolicZIV) { 199 const std::string text = R"( OpCapability Shader 200 %1 = OpExtInstImport "GLSL.std.450" 201 OpMemoryModel Logical GLSL450 202 OpEntryPoint Fragment %4 "main" %12 203 OpExecutionMode %4 OriginUpperLeft 204 OpSource GLSL 440 205 OpName %4 "main" 206 OpName %12 "c" 207 OpName %33 "arr" 208 OpName %41 "arr2" 209 OpName %50 "arr3" 210 OpName %58 "arr4" 211 OpName %60 "arr5" 212 OpDecorate %12 Location 0 213 %2 = OpTypeVoid 214 %3 = OpTypeFunction %2 215 %6 = OpTypeInt 32 1 216 %7 = OpTypePointer Function %6 217 %9 = OpTypeFloat 32 218 %10 = OpTypeVector %9 4 219 %11 = OpTypePointer Input %10 220 %12 = OpVariable %11 Input 221 %13 = OpTypeInt 32 0 222 %14 = OpConstant %13 0 223 %15 = OpTypePointer Input %9 224 %20 = OpConstant %6 0 225 %28 = OpTypeBool 226 %30 = OpConstant %13 10 227 %31 = OpTypeArray %6 %30 228 %32 = OpTypePointer Function %31 229 %34 = OpConstant %6 2 230 %44 = OpConstant %6 1 231 %4 = OpFunction %2 None %3 232 %5 = OpLabel 233 %33 = OpVariable %32 Function 234 %41 = OpVariable %32 Function 235 %50 = OpVariable %32 Function 236 %58 = OpVariable %32 Function 237 %60 = OpVariable %32 Function 238 %16 = OpAccessChain %15 %12 %14 239 %17 = OpLoad %9 %16 240 %18 = OpConvertFToS %6 %17 241 OpBranch %21 242 %21 = OpLabel 243 %67 = OpPhi %6 %20 %5 %66 %24 244 OpLoopMerge %23 %24 None 245 OpBranch %25 246 %25 = OpLabel 247 %29 = OpSLessThan %28 %67 %18 248 OpBranchConditional %29 %22 %23 249 %22 = OpLabel 250 %36 = OpIMul %6 %34 %18 251 %38 = OpAccessChain %7 %33 %18 252 %39 = OpLoad %6 %38 253 %40 = OpAccessChain %7 %33 %36 254 OpStore %40 %39 255 %43 = OpIMul %6 %34 %18 256 %45 = OpIAdd %6 %43 %44 257 %47 = OpAccessChain %7 %41 %18 258 %48 = OpLoad %6 %47 259 %49 = OpAccessChain %7 %41 %45 260 OpStore %49 %48 261 %52 = OpIMul %6 %34 %18 262 %54 = OpISub %6 %18 %44 263 %55 = OpAccessChain %7 %50 %54 264 %56 = OpLoad %6 %55 265 %57 = OpAccessChain %7 %50 %52 266 OpStore %57 %56 267 %62 = OpAccessChain %7 %60 %18 268 %63 = OpLoad %6 %62 269 %64 = OpAccessChain %7 %58 %18 270 OpStore %64 %63 271 OpBranch %24 272 %24 = OpLabel 273 %66 = OpIAdd %6 %67 %44 274 OpBranch %21 275 %23 = OpLabel 276 OpReturn 277 OpFunctionEnd 278 )"; 279 std::unique_ptr<IRContext> context = 280 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, 281 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 282 Module* module = context->module(); 283 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n" 284 << text << std::endl; 285 const Function* f = spvtest::GetFunction(module, 4); 286 LoopDescriptor& ld = *context->GetLoopDescriptor(f); 287 288 Loop* loop = &ld.GetLoopByIndex(0); 289 std::vector<const Loop*> loops{loop}; 290 LoopDependenceAnalysis analysis{context.get(), loops}; 291 292 const Instruction* store[4]; 293 int stores_found = 0; 294 for (const Instruction& inst : *spvtest::GetBasicBlock(f, 22)) { 295 if (inst.opcode() == SpvOp::SpvOpStore) { 296 store[stores_found] = &inst; 297 ++stores_found; 298 } 299 } 300 301 for (int i = 0; i < 4; ++i) { 302 EXPECT_TRUE(store[i]); 303 } 304 305 // independent due to loop bounds (won't enter if N <= 0). 306 // 39 -> 40 tests looking through symbols and multiplicaiton. 307 { 308 DistanceVector distance_vector{loops.size()}; 309 EXPECT_TRUE(analysis.GetDependence(context->get_def_use_mgr()->GetDef(39), 310 store[0], &distance_vector)); 311 } 312 313 // 48 -> 49 tests looking through symbols and multiplication + addition. 314 { 315 DistanceVector distance_vector{loops.size()}; 316 EXPECT_TRUE(analysis.GetDependence(context->get_def_use_mgr()->GetDef(48), 317 store[1], &distance_vector)); 318 } 319 320 // 56 -> 57 tests looking through symbols and arithmetic on load and store. 321 { 322 DistanceVector distance_vector{loops.size()}; 323 EXPECT_TRUE(analysis.GetDependence(context->get_def_use_mgr()->GetDef(56), 324 store[2], &distance_vector)); 325 } 326 327 // independent as different arrays 328 // 63 -> 64 tests looking through symbols and load/store from/to different 329 // arrays. 330 { 331 DistanceVector distance_vector{loops.size()}; 332 EXPECT_TRUE(analysis.GetDependence(context->get_def_use_mgr()->GetDef(63), 333 store[3], &distance_vector)); 334 } 335 } 336 337 /* 338 Generated from the following GLSL fragment shader 339 with --eliminate-local-multi-store 340 #version 440 core 341 void a(){ 342 int[10] arr; 343 int[11] arr2; 344 int[20] arr3; 345 int[20] arr4; 346 int a = 2; 347 for (int i = 0; i < 10; i++) { 348 arr[i] = arr[i]; 349 arr2[i] = arr2[i+1]; 350 arr3[i] = arr3[i-1]; 351 arr4[2*i] = arr4[i]; 352 } 353 } 354 void b(){ 355 int[10] arr; 356 int[11] arr2; 357 int[20] arr3; 358 int[20] arr4; 359 int a = 2; 360 for (int i = 10; i > 0; i--) { 361 arr[i] = arr[i]; 362 arr2[i] = arr2[i+1]; 363 arr3[i] = arr3[i-1]; 364 arr4[2*i] = arr4[i]; 365 } 366 } 367 368 void main() { 369 a(); 370 b(); 371 } 372 */ 373 TEST(DependencyAnalysis, SIV) { 374 const std::string text = R"( OpCapability Shader 375 %1 = OpExtInstImport "GLSL.std.450" 376 OpMemoryModel Logical GLSL450 377 OpEntryPoint Fragment %4 "main" 378 OpExecutionMode %4 OriginUpperLeft 379 OpSource GLSL 440 380 OpName %4 "main" 381 OpName %6 "a(" 382 OpName %8 "b(" 383 OpName %12 "a" 384 OpName %14 "i" 385 OpName %29 "arr" 386 OpName %38 "arr2" 387 OpName %49 "arr3" 388 OpName %56 "arr4" 389 OpName %65 "a" 390 OpName %66 "i" 391 OpName %74 "arr" 392 OpName %80 "arr2" 393 OpName %87 "arr3" 394 OpName %94 "arr4" 395 %2 = OpTypeVoid 396 %3 = OpTypeFunction %2 397 %10 = OpTypeInt 32 1 398 %11 = OpTypePointer Function %10 399 %13 = OpConstant %10 2 400 %15 = OpConstant %10 0 401 %22 = OpConstant %10 10 402 %23 = OpTypeBool 403 %25 = OpTypeInt 32 0 404 %26 = OpConstant %25 10 405 %27 = OpTypeArray %10 %26 406 %28 = OpTypePointer Function %27 407 %35 = OpConstant %25 11 408 %36 = OpTypeArray %10 %35 409 %37 = OpTypePointer Function %36 410 %41 = OpConstant %10 1 411 %46 = OpConstant %25 20 412 %47 = OpTypeArray %10 %46 413 %48 = OpTypePointer Function %47 414 %4 = OpFunction %2 None %3 415 %5 = OpLabel 416 %103 = OpFunctionCall %2 %6 417 %104 = OpFunctionCall %2 %8 418 OpReturn 419 OpFunctionEnd 420 %6 = OpFunction %2 None %3 421 %7 = OpLabel 422 %12 = OpVariable %11 Function 423 %14 = OpVariable %11 Function 424 %29 = OpVariable %28 Function 425 %38 = OpVariable %37 Function 426 %49 = OpVariable %48 Function 427 %56 = OpVariable %48 Function 428 OpStore %12 %13 429 OpStore %14 %15 430 OpBranch %16 431 %16 = OpLabel 432 %105 = OpPhi %10 %15 %7 %64 %19 433 OpLoopMerge %18 %19 None 434 OpBranch %20 435 %20 = OpLabel 436 %24 = OpSLessThan %23 %105 %22 437 OpBranchConditional %24 %17 %18 438 %17 = OpLabel 439 %32 = OpAccessChain %11 %29 %105 440 %33 = OpLoad %10 %32 441 %34 = OpAccessChain %11 %29 %105 442 OpStore %34 %33 443 %42 = OpIAdd %10 %105 %41 444 %43 = OpAccessChain %11 %38 %42 445 %44 = OpLoad %10 %43 446 %45 = OpAccessChain %11 %38 %105 447 OpStore %45 %44 448 %52 = OpISub %10 %105 %41 449 %53 = OpAccessChain %11 %49 %52 450 %54 = OpLoad %10 %53 451 %55 = OpAccessChain %11 %49 %105 452 OpStore %55 %54 453 %58 = OpIMul %10 %13 %105 454 %60 = OpAccessChain %11 %56 %105 455 %61 = OpLoad %10 %60 456 %62 = OpAccessChain %11 %56 %58 457 OpStore %62 %61 458 OpBranch %19 459 %19 = OpLabel 460 %64 = OpIAdd %10 %105 %41 461 OpStore %14 %64 462 OpBranch %16 463 %18 = OpLabel 464 OpReturn 465 OpFunctionEnd 466 %8 = OpFunction %2 None %3 467 %9 = OpLabel 468 %65 = OpVariable %11 Function 469 %66 = OpVariable %11 Function 470 %74 = OpVariable %28 Function 471 %80 = OpVariable %37 Function 472 %87 = OpVariable %48 Function 473 %94 = OpVariable %48 Function 474 OpStore %65 %13 475 OpStore %66 %22 476 OpBranch %67 477 %67 = OpLabel 478 %106 = OpPhi %10 %22 %9 %102 %70 479 OpLoopMerge %69 %70 None 480 OpBranch %71 481 %71 = OpLabel 482 %73 = OpSGreaterThan %23 %106 %15 483 OpBranchConditional %73 %68 %69 484 %68 = OpLabel 485 %77 = OpAccessChain %11 %74 %106 486 %78 = OpLoad %10 %77 487 %79 = OpAccessChain %11 %74 %106 488 OpStore %79 %78 489 %83 = OpIAdd %10 %106 %41 490 %84 = OpAccessChain %11 %80 %83 491 %85 = OpLoad %10 %84 492 %86 = OpAccessChain %11 %80 %106 493 OpStore %86 %85 494 %90 = OpISub %10 %106 %41 495 %91 = OpAccessChain %11 %87 %90 496 %92 = OpLoad %10 %91 497 %93 = OpAccessChain %11 %87 %106 498 OpStore %93 %92 499 %96 = OpIMul %10 %13 %106 500 %98 = OpAccessChain %11 %94 %106 501 %99 = OpLoad %10 %98 502 %100 = OpAccessChain %11 %94 %96 503 OpStore %100 %99 504 OpBranch %70 505 %70 = OpLabel 506 %102 = OpISub %10 %106 %41 507 OpStore %66 %102 508 OpBranch %67 509 %69 = OpLabel 510 OpReturn 511 OpFunctionEnd 512 )"; 513 std::unique_ptr<IRContext> context = 514 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, 515 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 516 Module* module = context->module(); 517 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n" 518 << text << std::endl; 519 // For the loop in function a. 520 { 521 const Function* f = spvtest::GetFunction(module, 6); 522 LoopDescriptor& ld = *context->GetLoopDescriptor(f); 523 524 Loop* loop = &ld.GetLoopByIndex(0); 525 std::vector<const Loop*> loops{loop}; 526 LoopDependenceAnalysis analysis{context.get(), loops}; 527 528 const Instruction* store[4]; 529 int stores_found = 0; 530 for (const Instruction& inst : *spvtest::GetBasicBlock(f, 17)) { 531 if (inst.opcode() == SpvOp::SpvOpStore) { 532 store[stores_found] = &inst; 533 ++stores_found; 534 } 535 } 536 537 for (int i = 0; i < 4; ++i) { 538 EXPECT_TRUE(store[i]); 539 } 540 541 // = dependence 542 // 33 -> 34 tests looking at SIV in same array. 543 { 544 DistanceVector distance_vector{loops.size()}; 545 EXPECT_FALSE(analysis.GetDependence( 546 context->get_def_use_mgr()->GetDef(33), store[0], &distance_vector)); 547 EXPECT_EQ(distance_vector.GetEntries()[0].dependence_information, 548 DistanceEntry::DependenceInformation::DISTANCE); 549 EXPECT_EQ(distance_vector.GetEntries()[0].direction, 550 DistanceEntry::Directions::EQ); 551 EXPECT_EQ(distance_vector.GetEntries()[0].distance, 0); 552 } 553 554 // > -1 dependence 555 // 44 -> 45 tests looking at SIV in same array with addition. 556 { 557 DistanceVector distance_vector{loops.size()}; 558 EXPECT_FALSE(analysis.GetDependence( 559 context->get_def_use_mgr()->GetDef(44), store[1], &distance_vector)); 560 EXPECT_EQ(distance_vector.GetEntries()[0].dependence_information, 561 DistanceEntry::DependenceInformation::DISTANCE); 562 EXPECT_EQ(distance_vector.GetEntries()[0].direction, 563 DistanceEntry::Directions::GT); 564 EXPECT_EQ(distance_vector.GetEntries()[0].distance, -1); 565 } 566 567 // < 1 dependence 568 // 54 -> 55 tests looking at SIV in same array with subtraction. 569 { 570 DistanceVector distance_vector{loops.size()}; 571 EXPECT_FALSE(analysis.GetDependence( 572 context->get_def_use_mgr()->GetDef(54), store[2], &distance_vector)); 573 EXPECT_EQ(distance_vector.GetEntries()[0].dependence_information, 574 DistanceEntry::DependenceInformation::DISTANCE); 575 EXPECT_EQ(distance_vector.GetEntries()[0].direction, 576 DistanceEntry::Directions::LT); 577 EXPECT_EQ(distance_vector.GetEntries()[0].distance, 1); 578 } 579 580 // <=> dependence 581 // 61 -> 62 tests looking at SIV in same array with multiplication. 582 { 583 DistanceVector distance_vector{loops.size()}; 584 EXPECT_FALSE(analysis.GetDependence( 585 context->get_def_use_mgr()->GetDef(61), store[3], &distance_vector)); 586 EXPECT_EQ(distance_vector.GetEntries()[0].dependence_information, 587 DistanceEntry::DependenceInformation::UNKNOWN); 588 EXPECT_EQ(distance_vector.GetEntries()[0].direction, 589 DistanceEntry::Directions::ALL); 590 } 591 } 592 // For the loop in function b. 593 { 594 const Function* f = spvtest::GetFunction(module, 8); 595 LoopDescriptor& ld = *context->GetLoopDescriptor(f); 596 597 Loop* loop = &ld.GetLoopByIndex(0); 598 std::vector<const Loop*> loops{loop}; 599 LoopDependenceAnalysis analysis{context.get(), loops}; 600 601 const Instruction* store[4]; 602 int stores_found = 0; 603 for (const Instruction& inst : *spvtest::GetBasicBlock(f, 68)) { 604 if (inst.opcode() == SpvOp::SpvOpStore) { 605 store[stores_found] = &inst; 606 ++stores_found; 607 } 608 } 609 610 for (int i = 0; i < 4; ++i) { 611 EXPECT_TRUE(store[i]); 612 } 613 614 // = dependence 615 // 78 -> 79 tests looking at SIV in same array. 616 { 617 DistanceVector distance_vector{loops.size()}; 618 EXPECT_FALSE(analysis.GetDependence( 619 context->get_def_use_mgr()->GetDef(78), store[0], &distance_vector)); 620 EXPECT_EQ(distance_vector.GetEntries()[0].dependence_information, 621 DistanceEntry::DependenceInformation::DISTANCE); 622 EXPECT_EQ(distance_vector.GetEntries()[0].direction, 623 DistanceEntry::Directions::EQ); 624 EXPECT_EQ(distance_vector.GetEntries()[0].distance, 0); 625 } 626 627 // < 1 dependence 628 // 85 -> 86 tests looking at SIV in same array with addition. 629 { 630 DistanceVector distance_vector{loops.size()}; 631 EXPECT_FALSE(analysis.GetDependence( 632 context->get_def_use_mgr()->GetDef(85), store[1], &distance_vector)); 633 EXPECT_EQ(distance_vector.GetEntries()[0].dependence_information, 634 DistanceEntry::DependenceInformation::DISTANCE); 635 EXPECT_EQ(distance_vector.GetEntries()[0].direction, 636 DistanceEntry::Directions::LT); 637 EXPECT_EQ(distance_vector.GetEntries()[0].distance, 1); 638 } 639 640 // > -1 dependence 641 // 92 -> 93 tests looking at SIV in same array with subtraction. 642 { 643 DistanceVector distance_vector{loops.size()}; 644 EXPECT_FALSE(analysis.GetDependence( 645 context->get_def_use_mgr()->GetDef(92), store[2], &distance_vector)); 646 EXPECT_EQ(distance_vector.GetEntries()[0].dependence_information, 647 DistanceEntry::DependenceInformation::DISTANCE); 648 EXPECT_EQ(distance_vector.GetEntries()[0].direction, 649 DistanceEntry::Directions::GT); 650 EXPECT_EQ(distance_vector.GetEntries()[0].distance, -1); 651 } 652 653 // <=> dependence 654 // 99 -> 100 tests looking at SIV in same array with multiplication. 655 { 656 DistanceVector distance_vector{loops.size()}; 657 EXPECT_FALSE(analysis.GetDependence( 658 context->get_def_use_mgr()->GetDef(99), store[3], &distance_vector)); 659 EXPECT_EQ(distance_vector.GetEntries()[0].dependence_information, 660 DistanceEntry::DependenceInformation::UNKNOWN); 661 EXPECT_EQ(distance_vector.GetEntries()[0].direction, 662 DistanceEntry::Directions::ALL); 663 } 664 } 665 } 666 667 /* 668 Generated from the following GLSL fragment shader 669 with --eliminate-local-multi-store 670 #version 440 core 671 layout(location = 0) in vec4 c; 672 void a() { 673 int[13] arr; 674 int[15] arr2; 675 int[18] arr3; 676 int[18] arr4; 677 int N = int(c.x); 678 int C = 2; 679 int a = 2; 680 for (int i = 0; i < N; i++) { // Bounds are N - 1 681 arr[i+2*N] = arr[i+N]; // |distance| = N 682 arr2[i+N] = arr2[i+2*N] + C; // |distance| = N 683 arr3[2*i+2*N+1] = arr3[2*i+N+1]; // |distance| = N 684 arr4[a*i+N+1] = arr4[a*i+2*N+1]; // |distance| = N 685 } 686 } 687 void b() { 688 int[13] arr; 689 int[15] arr2; 690 int[18] arr3; 691 int[18] arr4; 692 int N = int(c.x); 693 int C = 2; 694 int a = 2; 695 for (int i = N; i > 0; i--) { // Bounds are N - 1 696 arr[i+2*N] = arr[i+N]; // |distance| = N 697 arr2[i+N] = arr2[i+2*N] + C; // |distance| = N 698 arr3[2*i+2*N+1] = arr3[2*i+N+1]; // |distance| = N 699 arr4[a*i+N+1] = arr4[a*i+2*N+1]; // |distance| = N 700 } 701 } 702 void main(){ 703 a(); 704 b(); 705 }*/ 706 TEST(DependencyAnalysis, SymbolicSIV) { 707 const std::string text = R"( OpCapability Shader 708 %1 = OpExtInstImport "GLSL.std.450" 709 OpMemoryModel Logical GLSL450 710 OpEntryPoint Fragment %4 "main" %16 711 OpExecutionMode %4 OriginUpperLeft 712 OpSource GLSL 440 713 OpName %4 "main" 714 OpName %6 "a(" 715 OpName %8 "b(" 716 OpName %12 "N" 717 OpName %16 "c" 718 OpName %23 "C" 719 OpName %25 "a" 720 OpName %26 "i" 721 OpName %40 "arr" 722 OpName %54 "arr2" 723 OpName %70 "arr3" 724 OpName %86 "arr4" 725 OpName %105 "N" 726 OpName %109 "C" 727 OpName %110 "a" 728 OpName %111 "i" 729 OpName %120 "arr" 730 OpName %131 "arr2" 731 OpName %144 "arr3" 732 OpName %159 "arr4" 733 OpDecorate %16 Location 0 734 %2 = OpTypeVoid 735 %3 = OpTypeFunction %2 736 %10 = OpTypeInt 32 1 737 %11 = OpTypePointer Function %10 738 %13 = OpTypeFloat 32 739 %14 = OpTypeVector %13 4 740 %15 = OpTypePointer Input %14 741 %16 = OpVariable %15 Input 742 %17 = OpTypeInt 32 0 743 %18 = OpConstant %17 0 744 %19 = OpTypePointer Input %13 745 %24 = OpConstant %10 2 746 %27 = OpConstant %10 0 747 %35 = OpTypeBool 748 %37 = OpConstant %17 13 749 %38 = OpTypeArray %10 %37 750 %39 = OpTypePointer Function %38 751 %51 = OpConstant %17 15 752 %52 = OpTypeArray %10 %51 753 %53 = OpTypePointer Function %52 754 %67 = OpConstant %17 18 755 %68 = OpTypeArray %10 %67 756 %69 = OpTypePointer Function %68 757 %76 = OpConstant %10 1 758 %4 = OpFunction %2 None %3 759 %5 = OpLabel 760 %178 = OpFunctionCall %2 %6 761 %179 = OpFunctionCall %2 %8 762 OpReturn 763 OpFunctionEnd 764 %6 = OpFunction %2 None %3 765 %7 = OpLabel 766 %12 = OpVariable %11 Function 767 %23 = OpVariable %11 Function 768 %25 = OpVariable %11 Function 769 %26 = OpVariable %11 Function 770 %40 = OpVariable %39 Function 771 %54 = OpVariable %53 Function 772 %70 = OpVariable %69 Function 773 %86 = OpVariable %69 Function 774 %20 = OpAccessChain %19 %16 %18 775 %21 = OpLoad %13 %20 776 %22 = OpConvertFToS %10 %21 777 OpStore %12 %22 778 OpStore %23 %24 779 OpStore %25 %24 780 OpStore %26 %27 781 OpBranch %28 782 %28 = OpLabel 783 %180 = OpPhi %10 %27 %7 %104 %31 784 OpLoopMerge %30 %31 None 785 OpBranch %32 786 %32 = OpLabel 787 %36 = OpSLessThan %35 %180 %22 788 OpBranchConditional %36 %29 %30 789 %29 = OpLabel 790 %43 = OpIMul %10 %24 %22 791 %44 = OpIAdd %10 %180 %43 792 %47 = OpIAdd %10 %180 %22 793 %48 = OpAccessChain %11 %40 %47 794 %49 = OpLoad %10 %48 795 %50 = OpAccessChain %11 %40 %44 796 OpStore %50 %49 797 %57 = OpIAdd %10 %180 %22 798 %60 = OpIMul %10 %24 %22 799 %61 = OpIAdd %10 %180 %60 800 %62 = OpAccessChain %11 %54 %61 801 %63 = OpLoad %10 %62 802 %65 = OpIAdd %10 %63 %24 803 %66 = OpAccessChain %11 %54 %57 804 OpStore %66 %65 805 %72 = OpIMul %10 %24 %180 806 %74 = OpIMul %10 %24 %22 807 %75 = OpIAdd %10 %72 %74 808 %77 = OpIAdd %10 %75 %76 809 %79 = OpIMul %10 %24 %180 810 %81 = OpIAdd %10 %79 %22 811 %82 = OpIAdd %10 %81 %76 812 %83 = OpAccessChain %11 %70 %82 813 %84 = OpLoad %10 %83 814 %85 = OpAccessChain %11 %70 %77 815 OpStore %85 %84 816 %89 = OpIMul %10 %24 %180 817 %91 = OpIAdd %10 %89 %22 818 %92 = OpIAdd %10 %91 %76 819 %95 = OpIMul %10 %24 %180 820 %97 = OpIMul %10 %24 %22 821 %98 = OpIAdd %10 %95 %97 822 %99 = OpIAdd %10 %98 %76 823 %100 = OpAccessChain %11 %86 %99 824 %101 = OpLoad %10 %100 825 %102 = OpAccessChain %11 %86 %92 826 OpStore %102 %101 827 OpBranch %31 828 %31 = OpLabel 829 %104 = OpIAdd %10 %180 %76 830 OpStore %26 %104 831 OpBranch %28 832 %30 = OpLabel 833 OpReturn 834 OpFunctionEnd 835 %8 = OpFunction %2 None %3 836 %9 = OpLabel 837 %105 = OpVariable %11 Function 838 %109 = OpVariable %11 Function 839 %110 = OpVariable %11 Function 840 %111 = OpVariable %11 Function 841 %120 = OpVariable %39 Function 842 %131 = OpVariable %53 Function 843 %144 = OpVariable %69 Function 844 %159 = OpVariable %69 Function 845 %106 = OpAccessChain %19 %16 %18 846 %107 = OpLoad %13 %106 847 %108 = OpConvertFToS %10 %107 848 OpStore %105 %108 849 OpStore %109 %24 850 OpStore %110 %24 851 OpStore %111 %108 852 OpBranch %113 853 %113 = OpLabel 854 %181 = OpPhi %10 %108 %9 %177 %116 855 OpLoopMerge %115 %116 None 856 OpBranch %117 857 %117 = OpLabel 858 %119 = OpSGreaterThan %35 %181 %27 859 OpBranchConditional %119 %114 %115 860 %114 = OpLabel 861 %123 = OpIMul %10 %24 %108 862 %124 = OpIAdd %10 %181 %123 863 %127 = OpIAdd %10 %181 %108 864 %128 = OpAccessChain %11 %120 %127 865 %129 = OpLoad %10 %128 866 %130 = OpAccessChain %11 %120 %124 867 OpStore %130 %129 868 %134 = OpIAdd %10 %181 %108 869 %137 = OpIMul %10 %24 %108 870 %138 = OpIAdd %10 %181 %137 871 %139 = OpAccessChain %11 %131 %138 872 %140 = OpLoad %10 %139 873 %142 = OpIAdd %10 %140 %24 874 %143 = OpAccessChain %11 %131 %134 875 OpStore %143 %142 876 %146 = OpIMul %10 %24 %181 877 %148 = OpIMul %10 %24 %108 878 %149 = OpIAdd %10 %146 %148 879 %150 = OpIAdd %10 %149 %76 880 %152 = OpIMul %10 %24 %181 881 %154 = OpIAdd %10 %152 %108 882 %155 = OpIAdd %10 %154 %76 883 %156 = OpAccessChain %11 %144 %155 884 %157 = OpLoad %10 %156 885 %158 = OpAccessChain %11 %144 %150 886 OpStore %158 %157 887 %162 = OpIMul %10 %24 %181 888 %164 = OpIAdd %10 %162 %108 889 %165 = OpIAdd %10 %164 %76 890 %168 = OpIMul %10 %24 %181 891 %170 = OpIMul %10 %24 %108 892 %171 = OpIAdd %10 %168 %170 893 %172 = OpIAdd %10 %171 %76 894 %173 = OpAccessChain %11 %159 %172 895 %174 = OpLoad %10 %173 896 %175 = OpAccessChain %11 %159 %165 897 OpStore %175 %174 898 OpBranch %116 899 %116 = OpLabel 900 %177 = OpISub %10 %181 %76 901 OpStore %111 %177 902 OpBranch %113 903 %115 = OpLabel 904 OpReturn 905 OpFunctionEnd 906 )"; 907 std::unique_ptr<IRContext> context = 908 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, 909 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 910 Module* module = context->module(); 911 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n" 912 << text << std::endl; 913 // For the loop in function a. 914 { 915 const Function* f = spvtest::GetFunction(module, 6); 916 LoopDescriptor& ld = *context->GetLoopDescriptor(f); 917 918 Loop* loop = &ld.GetLoopByIndex(0); 919 std::vector<const Loop*> loops{loop}; 920 LoopDependenceAnalysis analysis{context.get(), loops}; 921 922 const Instruction* store[4]; 923 int stores_found = 0; 924 for (const Instruction& inst : *spvtest::GetBasicBlock(f, 29)) { 925 if (inst.opcode() == SpvOp::SpvOpStore) { 926 store[stores_found] = &inst; 927 ++stores_found; 928 } 929 } 930 931 for (int i = 0; i < 4; ++i) { 932 EXPECT_TRUE(store[i]); 933 } 934 935 // independent due to loop bounds (won't enter when N <= 0) 936 // 49 -> 50 tests looking through SIV and symbols with multiplication 937 { 938 DistanceVector distance_vector{loops.size()}; 939 // Independent but not yet supported. 940 EXPECT_FALSE(analysis.GetDependence( 941 context->get_def_use_mgr()->GetDef(49), store[0], &distance_vector)); 942 } 943 944 // 63 -> 66 tests looking through SIV and symbols with multiplication and + 945 // C 946 { 947 DistanceVector distance_vector{loops.size()}; 948 // Independent. 949 EXPECT_TRUE(analysis.GetDependence(context->get_def_use_mgr()->GetDef(63), 950 store[1], &distance_vector)); 951 } 952 953 // 84 -> 85 tests looking through arithmetic on SIV and symbols 954 { 955 DistanceVector distance_vector{loops.size()}; 956 // Independent but not yet supported. 957 EXPECT_FALSE(analysis.GetDependence( 958 context->get_def_use_mgr()->GetDef(84), store[2], &distance_vector)); 959 } 960 961 // 101 -> 102 tests looking through symbol arithmetic on SIV and symbols 962 { 963 DistanceVector distance_vector{loops.size()}; 964 // Independent. 965 EXPECT_TRUE(analysis.GetDependence( 966 context->get_def_use_mgr()->GetDef(101), store[3], &distance_vector)); 967 } 968 } 969 // For the loop in function b. 970 { 971 const Function* f = spvtest::GetFunction(module, 8); 972 LoopDescriptor& ld = *context->GetLoopDescriptor(f); 973 974 Loop* loop = &ld.GetLoopByIndex(0); 975 std::vector<const Loop*> loops{loop}; 976 LoopDependenceAnalysis analysis{context.get(), loops}; 977 978 const Instruction* store[4]; 979 int stores_found = 0; 980 for (const Instruction& inst : *spvtest::GetBasicBlock(f, 114)) { 981 if (inst.opcode() == SpvOp::SpvOpStore) { 982 store[stores_found] = &inst; 983 ++stores_found; 984 } 985 } 986 987 for (int i = 0; i < 4; ++i) { 988 EXPECT_TRUE(store[i]); 989 } 990 991 // independent due to loop bounds (won't enter when N <= 0). 992 // 129 -> 130 tests looking through SIV and symbols with multiplication. 993 { 994 DistanceVector distance_vector{loops.size()}; 995 // Independent but not yet supported. 996 EXPECT_FALSE(analysis.GetDependence( 997 context->get_def_use_mgr()->GetDef(129), store[0], &distance_vector)); 998 } 999 1000 // 140 -> 143 tests looking through SIV and symbols with multiplication and 1001 // + C. 1002 { 1003 DistanceVector distance_vector{loops.size()}; 1004 // Independent. 1005 EXPECT_TRUE(analysis.GetDependence( 1006 context->get_def_use_mgr()->GetDef(140), store[1], &distance_vector)); 1007 } 1008 1009 // 157 -> 158 tests looking through arithmetic on SIV and symbols. 1010 { 1011 DistanceVector distance_vector{loops.size()}; 1012 // Independent but not yet supported. 1013 EXPECT_FALSE(analysis.GetDependence( 1014 context->get_def_use_mgr()->GetDef(157), store[2], &distance_vector)); 1015 } 1016 1017 // 174 -> 175 tests looking through symbol arithmetic on SIV and symbols. 1018 { 1019 DistanceVector distance_vector{loops.size()}; 1020 // Independent. 1021 EXPECT_TRUE(analysis.GetDependence( 1022 context->get_def_use_mgr()->GetDef(174), store[3], &distance_vector)); 1023 } 1024 } 1025 } 1026 1027 /* 1028 Generated from the following GLSL fragment shader 1029 with --eliminate-local-multi-store 1030 #version 440 core 1031 void a() { 1032 int[6] arr; 1033 int N = 5; 1034 for (int i = 1; i < N; i++) { 1035 arr[i] = arr[N-i]; 1036 } 1037 } 1038 void b() { 1039 int[6] arr; 1040 int N = 5; 1041 for (int i = 1; i < N; i++) { 1042 arr[N-i] = arr[i]; 1043 } 1044 } 1045 void c() { 1046 int[11] arr; 1047 int N = 10; 1048 for (int i = 1; i < N; i++) { 1049 arr[i] = arr[N-i+1]; 1050 } 1051 } 1052 void d() { 1053 int[11] arr; 1054 int N = 10; 1055 for (int i = 1; i < N; i++) { 1056 arr[N-i+1] = arr[i]; 1057 } 1058 } 1059 void e() { 1060 int[6] arr; 1061 int N = 5; 1062 for (int i = N; i > 0; i--) { 1063 arr[i] = arr[N-i]; 1064 } 1065 } 1066 void f() { 1067 int[6] arr; 1068 int N = 5; 1069 for (int i = N; i > 0; i--) { 1070 arr[N-i] = arr[i]; 1071 } 1072 } 1073 void g() { 1074 int[11] arr; 1075 int N = 10; 1076 for (int i = N; i > 0; i--) { 1077 arr[i] = arr[N-i+1]; 1078 } 1079 } 1080 void h() { 1081 int[11] arr; 1082 int N = 10; 1083 for (int i = N; i > 0; i--) { 1084 arr[N-i+1] = arr[i]; 1085 } 1086 } 1087 void main(){ 1088 a(); 1089 b(); 1090 c(); 1091 d(); 1092 e(); 1093 f(); 1094 g(); 1095 h(); 1096 } 1097 */ 1098 TEST(DependencyAnalysis, Crossing) { 1099 const std::string text = R"( OpCapability Shader 1100 %1 = OpExtInstImport "GLSL.std.450" 1101 OpMemoryModel Logical GLSL450 1102 OpEntryPoint Fragment %4 "main" 1103 OpExecutionMode %4 OriginUpperLeft 1104 OpSource GLSL 440 1105 OpName %4 "main" 1106 OpName %6 "a(" 1107 OpName %8 "b(" 1108 OpName %10 "c(" 1109 OpName %12 "d(" 1110 OpName %14 "e(" 1111 OpName %16 "f(" 1112 OpName %18 "g(" 1113 OpName %20 "h(" 1114 OpName %24 "N" 1115 OpName %26 "i" 1116 OpName %41 "arr" 1117 OpName %51 "N" 1118 OpName %52 "i" 1119 OpName %61 "arr" 1120 OpName %71 "N" 1121 OpName %73 "i" 1122 OpName %85 "arr" 1123 OpName %96 "N" 1124 OpName %97 "i" 1125 OpName %106 "arr" 1126 OpName %117 "N" 1127 OpName %118 "i" 1128 OpName %128 "arr" 1129 OpName %138 "N" 1130 OpName %139 "i" 1131 OpName %148 "arr" 1132 OpName %158 "N" 1133 OpName %159 "i" 1134 OpName %168 "arr" 1135 OpName %179 "N" 1136 OpName %180 "i" 1137 OpName %189 "arr" 1138 %2 = OpTypeVoid 1139 %3 = OpTypeFunction %2 1140 %22 = OpTypeInt 32 1 1141 %23 = OpTypePointer Function %22 1142 %25 = OpConstant %22 5 1143 %27 = OpConstant %22 1 1144 %35 = OpTypeBool 1145 %37 = OpTypeInt 32 0 1146 %38 = OpConstant %37 6 1147 %39 = OpTypeArray %22 %38 1148 %40 = OpTypePointer Function %39 1149 %72 = OpConstant %22 10 1150 %82 = OpConstant %37 11 1151 %83 = OpTypeArray %22 %82 1152 %84 = OpTypePointer Function %83 1153 %126 = OpConstant %22 0 1154 %4 = OpFunction %2 None %3 1155 %5 = OpLabel 1156 %200 = OpFunctionCall %2 %6 1157 %201 = OpFunctionCall %2 %8 1158 %202 = OpFunctionCall %2 %10 1159 %203 = OpFunctionCall %2 %12 1160 %204 = OpFunctionCall %2 %14 1161 %205 = OpFunctionCall %2 %16 1162 %206 = OpFunctionCall %2 %18 1163 %207 = OpFunctionCall %2 %20 1164 OpReturn 1165 OpFunctionEnd 1166 %6 = OpFunction %2 None %3 1167 %7 = OpLabel 1168 %24 = OpVariable %23 Function 1169 %26 = OpVariable %23 Function 1170 %41 = OpVariable %40 Function 1171 OpStore %24 %25 1172 OpStore %26 %27 1173 OpBranch %28 1174 %28 = OpLabel 1175 %208 = OpPhi %22 %27 %7 %50 %31 1176 OpLoopMerge %30 %31 None 1177 OpBranch %32 1178 %32 = OpLabel 1179 %36 = OpSLessThan %35 %208 %25 1180 OpBranchConditional %36 %29 %30 1181 %29 = OpLabel 1182 %45 = OpISub %22 %25 %208 1183 %46 = OpAccessChain %23 %41 %45 1184 %47 = OpLoad %22 %46 1185 %48 = OpAccessChain %23 %41 %208 1186 OpStore %48 %47 1187 OpBranch %31 1188 %31 = OpLabel 1189 %50 = OpIAdd %22 %208 %27 1190 OpStore %26 %50 1191 OpBranch %28 1192 %30 = OpLabel 1193 OpReturn 1194 OpFunctionEnd 1195 %8 = OpFunction %2 None %3 1196 %9 = OpLabel 1197 %51 = OpVariable %23 Function 1198 %52 = OpVariable %23 Function 1199 %61 = OpVariable %40 Function 1200 OpStore %51 %25 1201 OpStore %52 %27 1202 OpBranch %53 1203 %53 = OpLabel 1204 %209 = OpPhi %22 %27 %9 %70 %56 1205 OpLoopMerge %55 %56 None 1206 OpBranch %57 1207 %57 = OpLabel 1208 %60 = OpSLessThan %35 %209 %25 1209 OpBranchConditional %60 %54 %55 1210 %54 = OpLabel 1211 %64 = OpISub %22 %25 %209 1212 %66 = OpAccessChain %23 %61 %209 1213 %67 = OpLoad %22 %66 1214 %68 = OpAccessChain %23 %61 %64 1215 OpStore %68 %67 1216 OpBranch %56 1217 %56 = OpLabel 1218 %70 = OpIAdd %22 %209 %27 1219 OpStore %52 %70 1220 OpBranch %53 1221 %55 = OpLabel 1222 OpReturn 1223 OpFunctionEnd 1224 %10 = OpFunction %2 None %3 1225 %11 = OpLabel 1226 %71 = OpVariable %23 Function 1227 %73 = OpVariable %23 Function 1228 %85 = OpVariable %84 Function 1229 OpStore %71 %72 1230 OpStore %73 %27 1231 OpBranch %74 1232 %74 = OpLabel 1233 %210 = OpPhi %22 %27 %11 %95 %77 1234 OpLoopMerge %76 %77 None 1235 OpBranch %78 1236 %78 = OpLabel 1237 %81 = OpSLessThan %35 %210 %72 1238 OpBranchConditional %81 %75 %76 1239 %75 = OpLabel 1240 %89 = OpISub %22 %72 %210 1241 %90 = OpIAdd %22 %89 %27 1242 %91 = OpAccessChain %23 %85 %90 1243 %92 = OpLoad %22 %91 1244 %93 = OpAccessChain %23 %85 %210 1245 OpStore %93 %92 1246 OpBranch %77 1247 %77 = OpLabel 1248 %95 = OpIAdd %22 %210 %27 1249 OpStore %73 %95 1250 OpBranch %74 1251 %76 = OpLabel 1252 OpReturn 1253 OpFunctionEnd 1254 %12 = OpFunction %2 None %3 1255 %13 = OpLabel 1256 %96 = OpVariable %23 Function 1257 %97 = OpVariable %23 Function 1258 %106 = OpVariable %84 Function 1259 OpStore %96 %72 1260 OpStore %97 %27 1261 OpBranch %98 1262 %98 = OpLabel 1263 %211 = OpPhi %22 %27 %13 %116 %101 1264 OpLoopMerge %100 %101 None 1265 OpBranch %102 1266 %102 = OpLabel 1267 %105 = OpSLessThan %35 %211 %72 1268 OpBranchConditional %105 %99 %100 1269 %99 = OpLabel 1270 %109 = OpISub %22 %72 %211 1271 %110 = OpIAdd %22 %109 %27 1272 %112 = OpAccessChain %23 %106 %211 1273 %113 = OpLoad %22 %112 1274 %114 = OpAccessChain %23 %106 %110 1275 OpStore %114 %113 1276 OpBranch %101 1277 %101 = OpLabel 1278 %116 = OpIAdd %22 %211 %27 1279 OpStore %97 %116 1280 OpBranch %98 1281 %100 = OpLabel 1282 OpReturn 1283 OpFunctionEnd 1284 %14 = OpFunction %2 None %3 1285 %15 = OpLabel 1286 %117 = OpVariable %23 Function 1287 %118 = OpVariable %23 Function 1288 %128 = OpVariable %40 Function 1289 OpStore %117 %25 1290 OpStore %118 %25 1291 OpBranch %120 1292 %120 = OpLabel 1293 %212 = OpPhi %22 %25 %15 %137 %123 1294 OpLoopMerge %122 %123 None 1295 OpBranch %124 1296 %124 = OpLabel 1297 %127 = OpSGreaterThan %35 %212 %126 1298 OpBranchConditional %127 %121 %122 1299 %121 = OpLabel 1300 %132 = OpISub %22 %25 %212 1301 %133 = OpAccessChain %23 %128 %132 1302 %134 = OpLoad %22 %133 1303 %135 = OpAccessChain %23 %128 %212 1304 OpStore %135 %134 1305 OpBranch %123 1306 %123 = OpLabel 1307 %137 = OpISub %22 %212 %27 1308 OpStore %118 %137 1309 OpBranch %120 1310 %122 = OpLabel 1311 OpReturn 1312 OpFunctionEnd 1313 %16 = OpFunction %2 None %3 1314 %17 = OpLabel 1315 %138 = OpVariable %23 Function 1316 %139 = OpVariable %23 Function 1317 %148 = OpVariable %40 Function 1318 OpStore %138 %25 1319 OpStore %139 %25 1320 OpBranch %141 1321 %141 = OpLabel 1322 %213 = OpPhi %22 %25 %17 %157 %144 1323 OpLoopMerge %143 %144 None 1324 OpBranch %145 1325 %145 = OpLabel 1326 %147 = OpSGreaterThan %35 %213 %126 1327 OpBranchConditional %147 %142 %143 1328 %142 = OpLabel 1329 %151 = OpISub %22 %25 %213 1330 %153 = OpAccessChain %23 %148 %213 1331 %154 = OpLoad %22 %153 1332 %155 = OpAccessChain %23 %148 %151 1333 OpStore %155 %154 1334 OpBranch %144 1335 %144 = OpLabel 1336 %157 = OpISub %22 %213 %27 1337 OpStore %139 %157 1338 OpBranch %141 1339 %143 = OpLabel 1340 OpReturn 1341 OpFunctionEnd 1342 %18 = OpFunction %2 None %3 1343 %19 = OpLabel 1344 %158 = OpVariable %23 Function 1345 %159 = OpVariable %23 Function 1346 %168 = OpVariable %84 Function 1347 OpStore %158 %72 1348 OpStore %159 %72 1349 OpBranch %161 1350 %161 = OpLabel 1351 %214 = OpPhi %22 %72 %19 %178 %164 1352 OpLoopMerge %163 %164 None 1353 OpBranch %165 1354 %165 = OpLabel 1355 %167 = OpSGreaterThan %35 %214 %126 1356 OpBranchConditional %167 %162 %163 1357 %162 = OpLabel 1358 %172 = OpISub %22 %72 %214 1359 %173 = OpIAdd %22 %172 %27 1360 %174 = OpAccessChain %23 %168 %173 1361 %175 = OpLoad %22 %174 1362 %176 = OpAccessChain %23 %168 %214 1363 OpStore %176 %175 1364 OpBranch %164 1365 %164 = OpLabel 1366 %178 = OpISub %22 %214 %27 1367 OpStore %159 %178 1368 OpBranch %161 1369 %163 = OpLabel 1370 OpReturn 1371 OpFunctionEnd 1372 %20 = OpFunction %2 None %3 1373 %21 = OpLabel 1374 %179 = OpVariable %23 Function 1375 %180 = OpVariable %23 Function 1376 %189 = OpVariable %84 Function 1377 OpStore %179 %72 1378 OpStore %180 %72 1379 OpBranch %182 1380 %182 = OpLabel 1381 %215 = OpPhi %22 %72 %21 %199 %185 1382 OpLoopMerge %184 %185 None 1383 OpBranch %186 1384 %186 = OpLabel 1385 %188 = OpSGreaterThan %35 %215 %126 1386 OpBranchConditional %188 %183 %184 1387 %183 = OpLabel 1388 %192 = OpISub %22 %72 %215 1389 %193 = OpIAdd %22 %192 %27 1390 %195 = OpAccessChain %23 %189 %215 1391 %196 = OpLoad %22 %195 1392 %197 = OpAccessChain %23 %189 %193 1393 OpStore %197 %196 1394 OpBranch %185 1395 %185 = OpLabel 1396 %199 = OpISub %22 %215 %27 1397 OpStore %180 %199 1398 OpBranch %182 1399 %184 = OpLabel 1400 OpReturn 1401 OpFunctionEnd 1402 )"; 1403 std::unique_ptr<IRContext> context = 1404 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, 1405 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 1406 Module* module = context->module(); 1407 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n" 1408 << text << std::endl; 1409 1410 // First two tests can be split into two loops. 1411 // Tests even crossing subscripts from low to high indexes. 1412 // 47 -> 48 1413 { 1414 const Function* f = spvtest::GetFunction(module, 6); 1415 LoopDescriptor& ld = *context->GetLoopDescriptor(f); 1416 1417 Loop* loop = &ld.GetLoopByIndex(0); 1418 std::vector<const Loop*> loops{loop}; 1419 LoopDependenceAnalysis analysis{context.get(), loops}; 1420 1421 const Instruction* store = nullptr; 1422 for (const Instruction& inst : *spvtest::GetBasicBlock(f, 29)) { 1423 if (inst.opcode() == SpvOp::SpvOpStore) { 1424 store = &inst; 1425 } 1426 } 1427 DistanceVector distance_vector{loops.size()}; 1428 EXPECT_FALSE(analysis.GetDependence(context->get_def_use_mgr()->GetDef(47), 1429 store, &distance_vector)); 1430 } 1431 1432 // Tests even crossing subscripts from high to low indexes. 1433 // 67 -> 68 1434 { 1435 const Function* f = spvtest::GetFunction(module, 8); 1436 LoopDescriptor& ld = *context->GetLoopDescriptor(f); 1437 1438 Loop* loop = &ld.GetLoopByIndex(0); 1439 std::vector<const Loop*> loops{loop}; 1440 LoopDependenceAnalysis analysis{context.get(), loops}; 1441 1442 const Instruction* store = nullptr; 1443 for (const Instruction& inst : *spvtest::GetBasicBlock(f, 54)) { 1444 if (inst.opcode() == SpvOp::SpvOpStore) { 1445 store = &inst; 1446 } 1447 } 1448 DistanceVector distance_vector{loops.size()}; 1449 EXPECT_FALSE(analysis.GetDependence(context->get_def_use_mgr()->GetDef(67), 1450 store, &distance_vector)); 1451 } 1452 1453 // Next two tests can have an end peeled, then be split. 1454 // Tests uneven crossing subscripts from low to high indexes. 1455 // 92 -> 93 1456 { 1457 const Function* f = spvtest::GetFunction(module, 10); 1458 LoopDescriptor& ld = *context->GetLoopDescriptor(f); 1459 1460 Loop* loop = &ld.GetLoopByIndex(0); 1461 std::vector<const Loop*> loops{loop}; 1462 LoopDependenceAnalysis analysis{context.get(), loops}; 1463 1464 const Instruction* store = nullptr; 1465 for (const Instruction& inst : *spvtest::GetBasicBlock(f, 75)) { 1466 if (inst.opcode() == SpvOp::SpvOpStore) { 1467 store = &inst; 1468 } 1469 } 1470 DistanceVector distance_vector{loops.size()}; 1471 EXPECT_FALSE(analysis.GetDependence(context->get_def_use_mgr()->GetDef(92), 1472 store, &distance_vector)); 1473 } 1474 1475 // Tests uneven crossing subscripts from high to low indexes. 1476 // 113 -> 114 1477 { 1478 const Function* f = spvtest::GetFunction(module, 12); 1479 LoopDescriptor& ld = *context->GetLoopDescriptor(f); 1480 1481 Loop* loop = &ld.GetLoopByIndex(0); 1482 std::vector<const Loop*> loops{loop}; 1483 LoopDependenceAnalysis analysis{context.get(), loops}; 1484 1485 const Instruction* store = nullptr; 1486 for (const Instruction& inst : *spvtest::GetBasicBlock(f, 99)) { 1487 if (inst.opcode() == SpvOp::SpvOpStore) { 1488 store = &inst; 1489 } 1490 } 1491 DistanceVector distance_vector{loops.size()}; 1492 EXPECT_FALSE(analysis.GetDependence(context->get_def_use_mgr()->GetDef(113), 1493 store, &distance_vector)); 1494 } 1495 1496 // First two tests can be split into two loops. 1497 // Tests even crossing subscripts from low to high indexes. 1498 // 134 -> 135 1499 { 1500 const Function* f = spvtest::GetFunction(module, 14); 1501 LoopDescriptor& ld = *context->GetLoopDescriptor(f); 1502 1503 Loop* loop = &ld.GetLoopByIndex(0); 1504 std::vector<const Loop*> loops{loop}; 1505 LoopDependenceAnalysis analysis{context.get(), loops}; 1506 1507 const Instruction* store = nullptr; 1508 for (const Instruction& inst : *spvtest::GetBasicBlock(f, 121)) { 1509 if (inst.opcode() == SpvOp::SpvOpStore) { 1510 store = &inst; 1511 } 1512 } 1513 DistanceVector distance_vector{loops.size()}; 1514 EXPECT_FALSE(analysis.GetDependence(context->get_def_use_mgr()->GetDef(134), 1515 store, &distance_vector)); 1516 } 1517 1518 // Tests even crossing subscripts from high to low indexes. 1519 // 154 -> 155 1520 { 1521 const Function* f = spvtest::GetFunction(module, 16); 1522 LoopDescriptor& ld = *context->GetLoopDescriptor(f); 1523 1524 Loop* loop = &ld.GetLoopByIndex(0); 1525 std::vector<const Loop*> loops{loop}; 1526 LoopDependenceAnalysis analysis{context.get(), loops}; 1527 1528 const Instruction* store = nullptr; 1529 for (const Instruction& inst : *spvtest::GetBasicBlock(f, 142)) { 1530 if (inst.opcode() == SpvOp::SpvOpStore) { 1531 store = &inst; 1532 } 1533 } 1534 DistanceVector distance_vector{loops.size()}; 1535 EXPECT_FALSE(analysis.GetDependence(context->get_def_use_mgr()->GetDef(154), 1536 store, &distance_vector)); 1537 } 1538 1539 // Next two tests can have an end peeled, then be split. 1540 // Tests uneven crossing subscripts from low to high indexes. 1541 // 175 -> 176 1542 { 1543 const Function* f = spvtest::GetFunction(module, 18); 1544 LoopDescriptor& ld = *context->GetLoopDescriptor(f); 1545 1546 Loop* loop = &ld.GetLoopByIndex(0); 1547 std::vector<const Loop*> loops{loop}; 1548 LoopDependenceAnalysis analysis{context.get(), loops}; 1549 1550 const Instruction* store = nullptr; 1551 for (const Instruction& inst : *spvtest::GetBasicBlock(f, 162)) { 1552 if (inst.opcode() == SpvOp::SpvOpStore) { 1553 store = &inst; 1554 } 1555 } 1556 DistanceVector distance_vector{loops.size()}; 1557 EXPECT_FALSE(analysis.GetDependence(context->get_def_use_mgr()->GetDef(175), 1558 store, &distance_vector)); 1559 } 1560 1561 // Tests uneven crossing subscripts from high to low indexes. 1562 // 196 -> 197 1563 { 1564 const Function* f = spvtest::GetFunction(module, 20); 1565 LoopDescriptor& ld = *context->GetLoopDescriptor(f); 1566 1567 Loop* loop = &ld.GetLoopByIndex(0); 1568 std::vector<const Loop*> loops{loop}; 1569 LoopDependenceAnalysis analysis{context.get(), loops}; 1570 1571 const Instruction* store = nullptr; 1572 for (const Instruction& inst : *spvtest::GetBasicBlock(f, 183)) { 1573 if (inst.opcode() == SpvOp::SpvOpStore) { 1574 store = &inst; 1575 } 1576 } 1577 DistanceVector distance_vector{loops.size()}; 1578 EXPECT_FALSE(analysis.GetDependence(context->get_def_use_mgr()->GetDef(196), 1579 store, &distance_vector)); 1580 } 1581 } 1582 1583 /* 1584 Generated from the following GLSL fragment shader 1585 with --eliminate-local-multi-store 1586 #version 440 core 1587 void a() { 1588 int[10] arr; 1589 for (int i = 0; i < 10; i++) { 1590 arr[0] = arr[i]; // peel first 1591 arr[i] = arr[0]; // peel first 1592 arr[9] = arr[i]; // peel last 1593 arr[i] = arr[9]; // peel last 1594 } 1595 } 1596 void b() { 1597 int[11] arr; 1598 for (int i = 0; i <= 10; i++) { 1599 arr[0] = arr[i]; // peel first 1600 arr[i] = arr[0]; // peel first 1601 arr[10] = arr[i]; // peel last 1602 arr[i] = arr[10]; // peel last 1603 1604 } 1605 } 1606 void c() { 1607 int[11] arr; 1608 for (int i = 10; i > 0; i--) { 1609 arr[10] = arr[i]; // peel first 1610 arr[i] = arr[10]; // peel first 1611 arr[1] = arr[i]; // peel last 1612 arr[i] = arr[1]; // peel last 1613 1614 } 1615 } 1616 void d() { 1617 int[11] arr; 1618 for (int i = 10; i >= 0; i--) { 1619 arr[10] = arr[i]; // peel first 1620 arr[i] = arr[10]; // peel first 1621 arr[0] = arr[i]; // peel last 1622 arr[i] = arr[0]; // peel last 1623 1624 } 1625 } 1626 void main(){ 1627 a(); 1628 b(); 1629 c(); 1630 d(); 1631 } 1632 */ 1633 TEST(DependencyAnalysis, WeakZeroSIV) { 1634 const std::string text = R"( OpCapability Shader 1635 %1 = OpExtInstImport "GLSL.std.450" 1636 OpMemoryModel Logical GLSL450 1637 OpEntryPoint Fragment %4 "main" 1638 OpExecutionMode %4 OriginUpperLeft 1639 OpSource GLSL 440 1640 OpName %4 "main" 1641 OpName %6 "a(" 1642 OpName %8 "b(" 1643 OpName %10 "c(" 1644 OpName %12 "d(" 1645 OpName %16 "i" 1646 OpName %31 "arr" 1647 OpName %52 "i" 1648 OpName %63 "arr" 1649 OpName %82 "i" 1650 OpName %90 "arr" 1651 OpName %109 "i" 1652 OpName %117 "arr" 1653 %2 = OpTypeVoid 1654 %3 = OpTypeFunction %2 1655 %14 = OpTypeInt 32 1 1656 %15 = OpTypePointer Function %14 1657 %17 = OpConstant %14 0 1658 %24 = OpConstant %14 10 1659 %25 = OpTypeBool 1660 %27 = OpTypeInt 32 0 1661 %28 = OpConstant %27 10 1662 %29 = OpTypeArray %14 %28 1663 %30 = OpTypePointer Function %29 1664 %40 = OpConstant %14 9 1665 %50 = OpConstant %14 1 1666 %60 = OpConstant %27 11 1667 %61 = OpTypeArray %14 %60 1668 %62 = OpTypePointer Function %61 1669 %4 = OpFunction %2 None %3 1670 %5 = OpLabel 1671 %136 = OpFunctionCall %2 %6 1672 %137 = OpFunctionCall %2 %8 1673 %138 = OpFunctionCall %2 %10 1674 %139 = OpFunctionCall %2 %12 1675 OpReturn 1676 OpFunctionEnd 1677 %6 = OpFunction %2 None %3 1678 %7 = OpLabel 1679 %16 = OpVariable %15 Function 1680 %31 = OpVariable %30 Function 1681 OpStore %16 %17 1682 OpBranch %18 1683 %18 = OpLabel 1684 %140 = OpPhi %14 %17 %7 %51 %21 1685 OpLoopMerge %20 %21 None 1686 OpBranch %22 1687 %22 = OpLabel 1688 %26 = OpSLessThan %25 %140 %24 1689 OpBranchConditional %26 %19 %20 1690 %19 = OpLabel 1691 %33 = OpAccessChain %15 %31 %140 1692 %34 = OpLoad %14 %33 1693 %35 = OpAccessChain %15 %31 %17 1694 OpStore %35 %34 1695 %37 = OpAccessChain %15 %31 %17 1696 %38 = OpLoad %14 %37 1697 %39 = OpAccessChain %15 %31 %140 1698 OpStore %39 %38 1699 %42 = OpAccessChain %15 %31 %140 1700 %43 = OpLoad %14 %42 1701 %44 = OpAccessChain %15 %31 %40 1702 OpStore %44 %43 1703 %46 = OpAccessChain %15 %31 %40 1704 %47 = OpLoad %14 %46 1705 %48 = OpAccessChain %15 %31 %140 1706 OpStore %48 %47 1707 OpBranch %21 1708 %21 = OpLabel 1709 %51 = OpIAdd %14 %140 %50 1710 OpStore %16 %51 1711 OpBranch %18 1712 %20 = OpLabel 1713 OpReturn 1714 OpFunctionEnd 1715 %8 = OpFunction %2 None %3 1716 %9 = OpLabel 1717 %52 = OpVariable %15 Function 1718 %63 = OpVariable %62 Function 1719 OpStore %52 %17 1720 OpBranch %53 1721 %53 = OpLabel 1722 %141 = OpPhi %14 %17 %9 %81 %56 1723 OpLoopMerge %55 %56 None 1724 OpBranch %57 1725 %57 = OpLabel 1726 %59 = OpSLessThanEqual %25 %141 %24 1727 OpBranchConditional %59 %54 %55 1728 %54 = OpLabel 1729 %65 = OpAccessChain %15 %63 %141 1730 %66 = OpLoad %14 %65 1731 %67 = OpAccessChain %15 %63 %17 1732 OpStore %67 %66 1733 %69 = OpAccessChain %15 %63 %17 1734 %70 = OpLoad %14 %69 1735 %71 = OpAccessChain %15 %63 %141 1736 OpStore %71 %70 1737 %73 = OpAccessChain %15 %63 %141 1738 %74 = OpLoad %14 %73 1739 %75 = OpAccessChain %15 %63 %24 1740 OpStore %75 %74 1741 %77 = OpAccessChain %15 %63 %24 1742 %78 = OpLoad %14 %77 1743 %79 = OpAccessChain %15 %63 %141 1744 OpStore %79 %78 1745 OpBranch %56 1746 %56 = OpLabel 1747 %81 = OpIAdd %14 %141 %50 1748 OpStore %52 %81 1749 OpBranch %53 1750 %55 = OpLabel 1751 OpReturn 1752 OpFunctionEnd 1753 %10 = OpFunction %2 None %3 1754 %11 = OpLabel 1755 %82 = OpVariable %15 Function 1756 %90 = OpVariable %62 Function 1757 OpStore %82 %24 1758 OpBranch %83 1759 %83 = OpLabel 1760 %142 = OpPhi %14 %24 %11 %108 %86 1761 OpLoopMerge %85 %86 None 1762 OpBranch %87 1763 %87 = OpLabel 1764 %89 = OpSGreaterThan %25 %142 %17 1765 OpBranchConditional %89 %84 %85 1766 %84 = OpLabel 1767 %92 = OpAccessChain %15 %90 %142 1768 %93 = OpLoad %14 %92 1769 %94 = OpAccessChain %15 %90 %24 1770 OpStore %94 %93 1771 %96 = OpAccessChain %15 %90 %24 1772 %97 = OpLoad %14 %96 1773 %98 = OpAccessChain %15 %90 %142 1774 OpStore %98 %97 1775 %100 = OpAccessChain %15 %90 %142 1776 %101 = OpLoad %14 %100 1777 %102 = OpAccessChain %15 %90 %50 1778 OpStore %102 %101 1779 %104 = OpAccessChain %15 %90 %50 1780 %105 = OpLoad %14 %104 1781 %106 = OpAccessChain %15 %90 %142 1782 OpStore %106 %105 1783 OpBranch %86 1784 %86 = OpLabel 1785 %108 = OpISub %14 %142 %50 1786 OpStore %82 %108 1787 OpBranch %83 1788 %85 = OpLabel 1789 OpReturn 1790 OpFunctionEnd 1791 %12 = OpFunction %2 None %3 1792 %13 = OpLabel 1793 %109 = OpVariable %15 Function 1794 %117 = OpVariable %62 Function 1795 OpStore %109 %24 1796 OpBranch %110 1797 %110 = OpLabel 1798 %143 = OpPhi %14 %24 %13 %135 %113 1799 OpLoopMerge %112 %113 None 1800 OpBranch %114 1801 %114 = OpLabel 1802 %116 = OpSGreaterThanEqual %25 %143 %17 1803 OpBranchConditional %116 %111 %112 1804 %111 = OpLabel 1805 %119 = OpAccessChain %15 %117 %143 1806 %120 = OpLoad %14 %119 1807 %121 = OpAccessChain %15 %117 %24 1808 OpStore %121 %120 1809 %123 = OpAccessChain %15 %117 %24 1810 %124 = OpLoad %14 %123 1811 %125 = OpAccessChain %15 %117 %143 1812 OpStore %125 %124 1813 %127 = OpAccessChain %15 %117 %143 1814 %128 = OpLoad %14 %127 1815 %129 = OpAccessChain %15 %117 %17 1816 OpStore %129 %128 1817 %131 = OpAccessChain %15 %117 %17 1818 %132 = OpLoad %14 %131 1819 %133 = OpAccessChain %15 %117 %143 1820 OpStore %133 %132 1821 OpBranch %113 1822 %113 = OpLabel 1823 %135 = OpISub %14 %143 %50 1824 OpStore %109 %135 1825 OpBranch %110 1826 %112 = OpLabel 1827 OpReturn 1828 OpFunctionEnd 1829 )"; 1830 1831 std::unique_ptr<IRContext> context = 1832 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, 1833 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 1834 Module* module = context->module(); 1835 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n" 1836 << text << std::endl; 1837 // For the loop in function a 1838 { 1839 const Function* f = spvtest::GetFunction(module, 6); 1840 LoopDescriptor& ld = *context->GetLoopDescriptor(f); 1841 1842 Loop* loop = &ld.GetLoopByIndex(0); 1843 std::vector<const Loop*> loops{loop}; 1844 LoopDependenceAnalysis analysis{context.get(), loops}; 1845 1846 const Instruction* store[4]; 1847 int stores_found = 0; 1848 for (const Instruction& inst : *spvtest::GetBasicBlock(f, 19)) { 1849 if (inst.opcode() == SpvOp::SpvOpStore) { 1850 store[stores_found] = &inst; 1851 ++stores_found; 1852 } 1853 } 1854 1855 for (int i = 0; i < 4; ++i) { 1856 EXPECT_TRUE(store[i]); 1857 } 1858 1859 // Tests identifying peel first with weak zero with destination as zero 1860 // index. 1861 // 34 -> 35 1862 { 1863 DistanceVector distance_vector{loops.size()}; 1864 EXPECT_FALSE(analysis.GetDependence( 1865 context->get_def_use_mgr()->GetDef(34), store[0], &distance_vector)); 1866 EXPECT_EQ(distance_vector.GetEntries()[0].dependence_information, 1867 DistanceEntry::DependenceInformation::PEEL); 1868 EXPECT_TRUE(distance_vector.GetEntries()[0].peel_first); 1869 } 1870 1871 // Tests identifying peel first with weak zero with source as zero index. 1872 // 38 -> 39 1873 { 1874 DistanceVector distance_vector{loops.size()}; 1875 EXPECT_FALSE(analysis.GetDependence( 1876 context->get_def_use_mgr()->GetDef(38), store[1], &distance_vector)); 1877 EXPECT_EQ(distance_vector.GetEntries()[0].dependence_information, 1878 DistanceEntry::DependenceInformation::PEEL); 1879 EXPECT_TRUE(distance_vector.GetEntries()[0].peel_first); 1880 } 1881 1882 // Tests identifying peel first with weak zero with destination as zero 1883 // index. 1884 // 43 -> 44 1885 { 1886 DistanceVector distance_vector{loops.size()}; 1887 EXPECT_FALSE(analysis.GetDependence( 1888 context->get_def_use_mgr()->GetDef(43), store[2], &distance_vector)); 1889 EXPECT_EQ(distance_vector.GetEntries()[0].dependence_information, 1890 DistanceEntry::DependenceInformation::PEEL); 1891 EXPECT_TRUE(distance_vector.GetEntries()[0].peel_last); 1892 } 1893 1894 // Tests identifying peel first with weak zero with source as zero index. 1895 // 47 -> 48 1896 { 1897 DistanceVector distance_vector{loops.size()}; 1898 EXPECT_FALSE(analysis.GetDependence( 1899 context->get_def_use_mgr()->GetDef(47), store[3], &distance_vector)); 1900 EXPECT_EQ(distance_vector.GetEntries()[0].dependence_information, 1901 DistanceEntry::DependenceInformation::PEEL); 1902 EXPECT_TRUE(distance_vector.GetEntries()[0].peel_last); 1903 } 1904 } 1905 // For the loop in function b 1906 { 1907 const Function* f = spvtest::GetFunction(module, 8); 1908 LoopDescriptor& ld = *context->GetLoopDescriptor(f); 1909 1910 Loop* loop = &ld.GetLoopByIndex(0); 1911 std::vector<const Loop*> loops{loop}; 1912 LoopDependenceAnalysis analysis{context.get(), loops}; 1913 1914 const Instruction* store[4]; 1915 int stores_found = 0; 1916 for (const Instruction& inst : *spvtest::GetBasicBlock(f, 54)) { 1917 if (inst.opcode() == SpvOp::SpvOpStore) { 1918 store[stores_found] = &inst; 1919 ++stores_found; 1920 } 1921 } 1922 1923 for (int i = 0; i < 4; ++i) { 1924 EXPECT_TRUE(store[i]); 1925 } 1926 1927 // Tests identifying peel first with weak zero with destination as zero 1928 // index. 1929 // 66 -> 67 1930 { 1931 DistanceVector distance_vector{loops.size()}; 1932 EXPECT_FALSE(analysis.GetDependence( 1933 context->get_def_use_mgr()->GetDef(66), store[0], &distance_vector)); 1934 EXPECT_EQ(distance_vector.GetEntries()[0].dependence_information, 1935 DistanceEntry::DependenceInformation::PEEL); 1936 EXPECT_TRUE(distance_vector.GetEntries()[0].peel_first); 1937 } 1938 1939 // Tests identifying peel first with weak zero with source as zero index. 1940 // 70 -> 71 1941 { 1942 DistanceVector distance_vector{loops.size()}; 1943 EXPECT_FALSE(analysis.GetDependence( 1944 context->get_def_use_mgr()->GetDef(70), store[1], &distance_vector)); 1945 EXPECT_EQ(distance_vector.GetEntries()[0].dependence_information, 1946 DistanceEntry::DependenceInformation::PEEL); 1947 EXPECT_TRUE(distance_vector.GetEntries()[0].peel_first); 1948 } 1949 1950 // Tests identifying peel first with weak zero with destination as zero 1951 // index. 1952 // 74 -> 75 1953 { 1954 DistanceVector distance_vector{loops.size()}; 1955 EXPECT_FALSE(analysis.GetDependence( 1956 context->get_def_use_mgr()->GetDef(74), store[2], &distance_vector)); 1957 EXPECT_EQ(distance_vector.GetEntries()[0].dependence_information, 1958 DistanceEntry::DependenceInformation::PEEL); 1959 EXPECT_TRUE(distance_vector.GetEntries()[0].peel_last); 1960 } 1961 1962 // Tests identifying peel first with weak zero with source as zero index. 1963 // 78 -> 79 1964 { 1965 DistanceVector distance_vector{loops.size()}; 1966 EXPECT_FALSE(analysis.GetDependence( 1967 context->get_def_use_mgr()->GetDef(78), store[3], &distance_vector)); 1968 EXPECT_EQ(distance_vector.GetEntries()[0].dependence_information, 1969 DistanceEntry::DependenceInformation::PEEL); 1970 EXPECT_TRUE(distance_vector.GetEntries()[0].peel_last); 1971 } 1972 } 1973 // For the loop in function c 1974 { 1975 const Function* f = spvtest::GetFunction(module, 10); 1976 LoopDescriptor& ld = *context->GetLoopDescriptor(f); 1977 1978 Loop* loop = &ld.GetLoopByIndex(0); 1979 std::vector<const Loop*> loops{loop}; 1980 LoopDependenceAnalysis analysis{context.get(), loops}; 1981 const Instruction* store[4]; 1982 int stores_found = 0; 1983 for (const Instruction& inst : *spvtest::GetBasicBlock(f, 84)) { 1984 if (inst.opcode() == SpvOp::SpvOpStore) { 1985 store[stores_found] = &inst; 1986 ++stores_found; 1987 } 1988 } 1989 1990 for (int i = 0; i < 4; ++i) { 1991 EXPECT_TRUE(store[i]); 1992 } 1993 1994 // Tests identifying peel first with weak zero with destination as zero 1995 // index. 1996 // 93 -> 94 1997 { 1998 DistanceVector distance_vector{loops.size()}; 1999 EXPECT_FALSE(analysis.GetDependence( 2000 context->get_def_use_mgr()->GetDef(93), store[0], &distance_vector)); 2001 EXPECT_EQ(distance_vector.GetEntries()[0].dependence_information, 2002 DistanceEntry::DependenceInformation::PEEL); 2003 EXPECT_TRUE(distance_vector.GetEntries()[0].peel_first); 2004 } 2005 2006 // Tests identifying peel first with weak zero with source as zero index. 2007 // 97 -> 98 2008 { 2009 DistanceVector distance_vector{loops.size()}; 2010 EXPECT_FALSE(analysis.GetDependence( 2011 context->get_def_use_mgr()->GetDef(97), store[1], &distance_vector)); 2012 EXPECT_EQ(distance_vector.GetEntries()[0].dependence_information, 2013 DistanceEntry::DependenceInformation::PEEL); 2014 EXPECT_TRUE(distance_vector.GetEntries()[0].peel_first); 2015 } 2016 2017 // Tests identifying peel first with weak zero with destination as zero 2018 // index. 2019 // 101 -> 102 2020 { 2021 DistanceVector distance_vector{loops.size()}; 2022 EXPECT_FALSE(analysis.GetDependence( 2023 context->get_def_use_mgr()->GetDef(101), store[2], &distance_vector)); 2024 EXPECT_EQ(distance_vector.GetEntries()[0].dependence_information, 2025 DistanceEntry::DependenceInformation::PEEL); 2026 EXPECT_TRUE(distance_vector.GetEntries()[0].peel_last); 2027 } 2028 2029 // Tests identifying peel first with weak zero with source as zero index. 2030 // 105 -> 106 2031 { 2032 DistanceVector distance_vector{loops.size()}; 2033 EXPECT_FALSE(analysis.GetDependence( 2034 context->get_def_use_mgr()->GetDef(105), store[3], &distance_vector)); 2035 EXPECT_EQ(distance_vector.GetEntries()[0].dependence_information, 2036 DistanceEntry::DependenceInformation::PEEL); 2037 EXPECT_TRUE(distance_vector.GetEntries()[0].peel_last); 2038 } 2039 } 2040 // For the loop in function d 2041 { 2042 const Function* f = spvtest::GetFunction(module, 12); 2043 LoopDescriptor& ld = *context->GetLoopDescriptor(f); 2044 2045 Loop* loop = &ld.GetLoopByIndex(0); 2046 std::vector<const Loop*> loops{loop}; 2047 LoopDependenceAnalysis analysis{context.get(), loops}; 2048 2049 const Instruction* store[4]; 2050 int stores_found = 0; 2051 for (const Instruction& inst : *spvtest::GetBasicBlock(f, 111)) { 2052 if (inst.opcode() == SpvOp::SpvOpStore) { 2053 store[stores_found] = &inst; 2054 ++stores_found; 2055 } 2056 } 2057 2058 for (int i = 0; i < 4; ++i) { 2059 EXPECT_TRUE(store[i]); 2060 } 2061 2062 // Tests identifying peel first with weak zero with destination as zero 2063 // index. 2064 // 120 -> 121 2065 { 2066 DistanceVector distance_vector{loops.size()}; 2067 EXPECT_FALSE(analysis.GetDependence( 2068 context->get_def_use_mgr()->GetDef(120), store[0], &distance_vector)); 2069 EXPECT_EQ(distance_vector.GetEntries()[0].dependence_information, 2070 DistanceEntry::DependenceInformation::PEEL); 2071 EXPECT_TRUE(distance_vector.GetEntries()[0].peel_first); 2072 } 2073 2074 // Tests identifying peel first with weak zero with source as zero index. 2075 // 124 -> 125 2076 { 2077 DistanceVector distance_vector{loops.size()}; 2078 EXPECT_FALSE(analysis.GetDependence( 2079 context->get_def_use_mgr()->GetDef(124), store[1], &distance_vector)); 2080 EXPECT_EQ(distance_vector.GetEntries()[0].dependence_information, 2081 DistanceEntry::DependenceInformation::PEEL); 2082 EXPECT_TRUE(distance_vector.GetEntries()[0].peel_first); 2083 } 2084 2085 // Tests identifying peel first with weak zero with destination as zero 2086 // index. 2087 // 128 -> 129 2088 { 2089 DistanceVector distance_vector{loops.size()}; 2090 EXPECT_FALSE(analysis.GetDependence( 2091 context->get_def_use_mgr()->GetDef(128), store[2], &distance_vector)); 2092 EXPECT_EQ(distance_vector.GetEntries()[0].dependence_information, 2093 DistanceEntry::DependenceInformation::PEEL); 2094 EXPECT_TRUE(distance_vector.GetEntries()[0].peel_last); 2095 } 2096 2097 // Tests identifying peel first with weak zero with source as zero index. 2098 // 132 -> 133 2099 { 2100 DistanceVector distance_vector{loops.size()}; 2101 EXPECT_FALSE(analysis.GetDependence( 2102 context->get_def_use_mgr()->GetDef(132), store[3], &distance_vector)); 2103 EXPECT_EQ(distance_vector.GetEntries()[0].dependence_information, 2104 DistanceEntry::DependenceInformation::PEEL); 2105 EXPECT_TRUE(distance_vector.GetEntries()[0].peel_last); 2106 } 2107 } 2108 } 2109 2110 /* 2111 Generated from the following GLSL fragment shader 2112 with --eliminate-local-multi-store 2113 #version 440 core 2114 void main(){ 2115 int[10][10] arr; 2116 for (int i = 0; i < 10; i++) { 2117 arr[i][i] = arr[i][i]; 2118 arr[0][i] = arr[1][i]; 2119 arr[1][i] = arr[0][i]; 2120 arr[i][0] = arr[i][1]; 2121 arr[i][1] = arr[i][0]; 2122 arr[0][1] = arr[1][0]; 2123 } 2124 } 2125 */ 2126 TEST(DependencyAnalysis, MultipleSubscriptZIVSIV) { 2127 const std::string text = R"( OpCapability Shader 2128 %1 = OpExtInstImport "GLSL.std.450" 2129 OpMemoryModel Logical GLSL450 2130 OpEntryPoint Fragment %4 "main" 2131 OpExecutionMode %4 OriginUpperLeft 2132 OpSource GLSL 440 2133 OpName %4 "main" 2134 OpName %8 "i" 2135 OpName %24 "arr" 2136 %2 = OpTypeVoid 2137 %3 = OpTypeFunction %2 2138 %6 = OpTypeInt 32 1 2139 %7 = OpTypePointer Function %6 2140 %9 = OpConstant %6 0 2141 %16 = OpConstant %6 10 2142 %17 = OpTypeBool 2143 %19 = OpTypeInt 32 0 2144 %20 = OpConstant %19 10 2145 %21 = OpTypeArray %6 %20 2146 %22 = OpTypeArray %21 %20 2147 %23 = OpTypePointer Function %22 2148 %33 = OpConstant %6 1 2149 %4 = OpFunction %2 None %3 2150 %5 = OpLabel 2151 %8 = OpVariable %7 Function 2152 %24 = OpVariable %23 Function 2153 OpStore %8 %9 2154 OpBranch %10 2155 %10 = OpLabel 2156 %58 = OpPhi %6 %9 %5 %57 %13 2157 OpLoopMerge %12 %13 None 2158 OpBranch %14 2159 %14 = OpLabel 2160 %18 = OpSLessThan %17 %58 %16 2161 OpBranchConditional %18 %11 %12 2162 %11 = OpLabel 2163 %29 = OpAccessChain %7 %24 %58 %58 2164 %30 = OpLoad %6 %29 2165 %31 = OpAccessChain %7 %24 %58 %58 2166 OpStore %31 %30 2167 %35 = OpAccessChain %7 %24 %33 %58 2168 %36 = OpLoad %6 %35 2169 %37 = OpAccessChain %7 %24 %9 %58 2170 OpStore %37 %36 2171 %40 = OpAccessChain %7 %24 %9 %58 2172 %41 = OpLoad %6 %40 2173 %42 = OpAccessChain %7 %24 %33 %58 2174 OpStore %42 %41 2175 %45 = OpAccessChain %7 %24 %58 %33 2176 %46 = OpLoad %6 %45 2177 %47 = OpAccessChain %7 %24 %58 %9 2178 OpStore %47 %46 2179 %50 = OpAccessChain %7 %24 %58 %9 2180 %51 = OpLoad %6 %50 2181 %52 = OpAccessChain %7 %24 %58 %33 2182 OpStore %52 %51 2183 %53 = OpAccessChain %7 %24 %33 %9 2184 %54 = OpLoad %6 %53 2185 %55 = OpAccessChain %7 %24 %9 %33 2186 OpStore %55 %54 2187 OpBranch %13 2188 %13 = OpLabel 2189 %57 = OpIAdd %6 %58 %33 2190 OpStore %8 %57 2191 OpBranch %10 2192 %12 = OpLabel 2193 OpReturn 2194 OpFunctionEnd 2195 )"; 2196 2197 std::unique_ptr<IRContext> context = 2198 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, 2199 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 2200 Module* module = context->module(); 2201 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n" 2202 << text << std::endl; 2203 const Function* f = spvtest::GetFunction(module, 4); 2204 LoopDescriptor& ld = *context->GetLoopDescriptor(f); 2205 2206 Loop* loop = &ld.GetLoopByIndex(0); 2207 std::vector<const Loop*> loops{loop}; 2208 LoopDependenceAnalysis analysis{context.get(), loops}; 2209 2210 const Instruction* store[6]; 2211 int stores_found = 0; 2212 for (const Instruction& inst : *spvtest::GetBasicBlock(f, 11)) { 2213 if (inst.opcode() == SpvOp::SpvOpStore) { 2214 store[stores_found] = &inst; 2215 ++stores_found; 2216 } 2217 } 2218 2219 for (int i = 0; i < 6; ++i) { 2220 EXPECT_TRUE(store[i]); 2221 } 2222 2223 // 30 -> 31 2224 { 2225 DistanceVector distance_vector{loops.size()}; 2226 EXPECT_FALSE(analysis.GetDependence(context->get_def_use_mgr()->GetDef(30), 2227 store[0], &distance_vector)); 2228 EXPECT_EQ(distance_vector.GetEntries()[0].dependence_information, 2229 DistanceEntry::DependenceInformation::DISTANCE); 2230 EXPECT_EQ(distance_vector.GetEntries()[0].direction, 2231 DistanceEntry::Directions::EQ); 2232 EXPECT_EQ(distance_vector.GetEntries()[0].distance, 0); 2233 } 2234 2235 // 36 -> 37 2236 { 2237 DistanceVector distance_vector{loops.size()}; 2238 EXPECT_TRUE(analysis.GetDependence(context->get_def_use_mgr()->GetDef(36), 2239 store[1], &distance_vector)); 2240 } 2241 2242 // 41 -> 42 2243 { 2244 DistanceVector distance_vector{loops.size()}; 2245 EXPECT_TRUE(analysis.GetDependence(context->get_def_use_mgr()->GetDef(41), 2246 store[2], &distance_vector)); 2247 } 2248 2249 // 46 -> 47 2250 { 2251 DistanceVector distance_vector{loops.size()}; 2252 EXPECT_TRUE(analysis.GetDependence(context->get_def_use_mgr()->GetDef(46), 2253 store[3], &distance_vector)); 2254 EXPECT_EQ(distance_vector.GetEntries()[0].dependence_information, 2255 DistanceEntry::DependenceInformation::DISTANCE); 2256 EXPECT_EQ(distance_vector.GetEntries()[0].direction, 2257 DistanceEntry::Directions::EQ); 2258 EXPECT_EQ(distance_vector.GetEntries()[0].distance, 0); 2259 } 2260 2261 // 51 -> 52 2262 { 2263 DistanceVector distance_vector{loops.size()}; 2264 EXPECT_TRUE(analysis.GetDependence(context->get_def_use_mgr()->GetDef(51), 2265 store[4], &distance_vector)); 2266 EXPECT_EQ(distance_vector.GetEntries()[0].dependence_information, 2267 DistanceEntry::DependenceInformation::DISTANCE); 2268 EXPECT_EQ(distance_vector.GetEntries()[0].direction, 2269 DistanceEntry::Directions::EQ); 2270 EXPECT_EQ(distance_vector.GetEntries()[0].distance, 0); 2271 } 2272 2273 // 54 -> 55 2274 { 2275 DistanceVector distance_vector{loops.size()}; 2276 EXPECT_TRUE(analysis.GetDependence(context->get_def_use_mgr()->GetDef(54), 2277 store[5], &distance_vector)); 2278 } 2279 } 2280 2281 /* 2282 Generated from the following GLSL fragment shader 2283 with --eliminate-local-multi-store 2284 #version 440 core 2285 void a(){ 2286 int[10] arr; 2287 for (int i = 0; i < 10; i++) { 2288 for (int j = 0; j < 10; j++) { 2289 arr[j] = arr[j]; 2290 } 2291 } 2292 } 2293 void b(){ 2294 int[10] arr; 2295 for (int i = 0; i < 10; i++) { 2296 for (int j = 0; j < 10; j++) { 2297 arr[i] = arr[i]; 2298 } 2299 } 2300 } 2301 void main() { 2302 a(); 2303 b(); 2304 } 2305 */ 2306 TEST(DependencyAnalysis, IrrelevantSubscripts) { 2307 const std::string text = R"( OpCapability Shader 2308 %1 = OpExtInstImport "GLSL.std.450" 2309 OpMemoryModel Logical GLSL450 2310 OpEntryPoint Fragment %4 "main" 2311 OpExecutionMode %4 OriginUpperLeft 2312 OpSource GLSL 440 2313 OpName %4 "main" 2314 OpName %6 "a(" 2315 OpName %8 "b(" 2316 OpName %12 "i" 2317 OpName %23 "j" 2318 OpName %35 "arr" 2319 OpName %46 "i" 2320 OpName %54 "j" 2321 OpName %62 "arr" 2322 %2 = OpTypeVoid 2323 %3 = OpTypeFunction %2 2324 %10 = OpTypeInt 32 1 2325 %11 = OpTypePointer Function %10 2326 %13 = OpConstant %10 0 2327 %20 = OpConstant %10 10 2328 %21 = OpTypeBool 2329 %31 = OpTypeInt 32 0 2330 %32 = OpConstant %31 10 2331 %33 = OpTypeArray %10 %32 2332 %34 = OpTypePointer Function %33 2333 %42 = OpConstant %10 1 2334 %4 = OpFunction %2 None %3 2335 %5 = OpLabel 2336 %72 = OpFunctionCall %2 %6 2337 %73 = OpFunctionCall %2 %8 2338 OpReturn 2339 OpFunctionEnd 2340 %6 = OpFunction %2 None %3 2341 %7 = OpLabel 2342 %12 = OpVariable %11 Function 2343 %23 = OpVariable %11 Function 2344 %35 = OpVariable %34 Function 2345 OpStore %12 %13 2346 OpBranch %14 2347 %14 = OpLabel 2348 %74 = OpPhi %10 %13 %7 %45 %17 2349 OpLoopMerge %16 %17 None 2350 OpBranch %18 2351 %18 = OpLabel 2352 %22 = OpSLessThan %21 %74 %20 2353 OpBranchConditional %22 %15 %16 2354 %15 = OpLabel 2355 OpStore %23 %13 2356 OpBranch %24 2357 %24 = OpLabel 2358 %75 = OpPhi %10 %13 %15 %43 %27 2359 OpLoopMerge %26 %27 None 2360 OpBranch %28 2361 %28 = OpLabel 2362 %30 = OpSLessThan %21 %75 %20 2363 OpBranchConditional %30 %25 %26 2364 %25 = OpLabel 2365 %38 = OpAccessChain %11 %35 %75 2366 %39 = OpLoad %10 %38 2367 %40 = OpAccessChain %11 %35 %75 2368 OpStore %40 %39 2369 OpBranch %27 2370 %27 = OpLabel 2371 %43 = OpIAdd %10 %75 %42 2372 OpStore %23 %43 2373 OpBranch %24 2374 %26 = OpLabel 2375 OpBranch %17 2376 %17 = OpLabel 2377 %45 = OpIAdd %10 %74 %42 2378 OpStore %12 %45 2379 OpBranch %14 2380 %16 = OpLabel 2381 OpReturn 2382 OpFunctionEnd 2383 %8 = OpFunction %2 None %3 2384 %9 = OpLabel 2385 %46 = OpVariable %11 Function 2386 %54 = OpVariable %11 Function 2387 %62 = OpVariable %34 Function 2388 OpStore %46 %13 2389 OpBranch %47 2390 %47 = OpLabel 2391 %77 = OpPhi %10 %13 %9 %71 %50 2392 OpLoopMerge %49 %50 None 2393 OpBranch %51 2394 %51 = OpLabel 2395 %53 = OpSLessThan %21 %77 %20 2396 OpBranchConditional %53 %48 %49 2397 %48 = OpLabel 2398 OpStore %54 %13 2399 OpBranch %55 2400 %55 = OpLabel 2401 %78 = OpPhi %10 %13 %48 %69 %58 2402 OpLoopMerge %57 %58 None 2403 OpBranch %59 2404 %59 = OpLabel 2405 %61 = OpSLessThan %21 %78 %20 2406 OpBranchConditional %61 %56 %57 2407 %56 = OpLabel 2408 %65 = OpAccessChain %11 %62 %77 2409 %66 = OpLoad %10 %65 2410 %67 = OpAccessChain %11 %62 %77 2411 OpStore %67 %66 2412 OpBranch %58 2413 %58 = OpLabel 2414 %69 = OpIAdd %10 %78 %42 2415 OpStore %54 %69 2416 OpBranch %55 2417 %57 = OpLabel 2418 OpBranch %50 2419 %50 = OpLabel 2420 %71 = OpIAdd %10 %77 %42 2421 OpStore %46 %71 2422 OpBranch %47 2423 %49 = OpLabel 2424 OpReturn 2425 OpFunctionEnd 2426 )"; 2427 2428 std::unique_ptr<IRContext> context = 2429 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, 2430 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 2431 Module* module = context->module(); 2432 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n" 2433 << text << std::endl; 2434 // For the loop in function a 2435 { 2436 const Function* f = spvtest::GetFunction(module, 6); 2437 LoopDescriptor& ld = *context->GetLoopDescriptor(f); 2438 2439 std::vector<const Loop*> loops{&ld.GetLoopByIndex(1), 2440 &ld.GetLoopByIndex(0)}; 2441 LoopDependenceAnalysis analysis{context.get(), loops}; 2442 2443 const Instruction* store[1]; 2444 int stores_found = 0; 2445 for (const Instruction& inst : *spvtest::GetBasicBlock(f, 25)) { 2446 if (inst.opcode() == SpvOp::SpvOpStore) { 2447 store[stores_found] = &inst; 2448 ++stores_found; 2449 } 2450 } 2451 2452 for (int i = 0; i < 1; ++i) { 2453 EXPECT_TRUE(store[i]); 2454 } 2455 2456 // 39 -> 40 2457 { 2458 DistanceVector distance_vector{loops.size()}; 2459 analysis.SetDebugStream(std::cout); 2460 EXPECT_FALSE(analysis.GetDependence( 2461 context->get_def_use_mgr()->GetDef(39), store[0], &distance_vector)); 2462 EXPECT_EQ(distance_vector.GetEntries()[0].dependence_information, 2463 DistanceEntry::DependenceInformation::IRRELEVANT); 2464 EXPECT_EQ(distance_vector.GetEntries()[1].dependence_information, 2465 DistanceEntry::DependenceInformation::DISTANCE); 2466 EXPECT_EQ(distance_vector.GetEntries()[1].distance, 0); 2467 } 2468 } 2469 2470 // For the loop in function b 2471 { 2472 const Function* f = spvtest::GetFunction(module, 8); 2473 LoopDescriptor& ld = *context->GetLoopDescriptor(f); 2474 2475 std::vector<const Loop*> loops{&ld.GetLoopByIndex(1), 2476 &ld.GetLoopByIndex(0)}; 2477 LoopDependenceAnalysis analysis{context.get(), loops}; 2478 2479 const Instruction* store[1]; 2480 int stores_found = 0; 2481 for (const Instruction& inst : *spvtest::GetBasicBlock(f, 56)) { 2482 if (inst.opcode() == SpvOp::SpvOpStore) { 2483 store[stores_found] = &inst; 2484 ++stores_found; 2485 } 2486 } 2487 2488 for (int i = 0; i < 1; ++i) { 2489 EXPECT_TRUE(store[i]); 2490 } 2491 2492 // 66 -> 67 2493 { 2494 DistanceVector distance_vector{loops.size()}; 2495 EXPECT_FALSE(analysis.GetDependence( 2496 context->get_def_use_mgr()->GetDef(66), store[0], &distance_vector)); 2497 EXPECT_EQ(distance_vector.GetEntries()[0].dependence_information, 2498 DistanceEntry::DependenceInformation::DISTANCE); 2499 EXPECT_EQ(distance_vector.GetEntries()[0].distance, 0); 2500 EXPECT_EQ(distance_vector.GetEntries()[1].dependence_information, 2501 DistanceEntry::DependenceInformation::IRRELEVANT); 2502 } 2503 } 2504 } 2505 2506 void CheckDependenceAndDirection(const Instruction* source, 2507 const Instruction* destination, 2508 bool expected_dependence, 2509 DistanceVector expected_distance, 2510 LoopDependenceAnalysis* analysis) { 2511 DistanceVector dv_entry(2); 2512 EXPECT_EQ(expected_dependence, 2513 analysis->GetDependence(source, destination, &dv_entry)); 2514 EXPECT_EQ(expected_distance, dv_entry); 2515 } 2516 2517 /* 2518 Generated from the following GLSL fragment shader 2519 with --eliminate-local-multi-store 2520 #version 440 core 2521 layout(location = 0) in vec4 c; 2522 void main(){ 2523 int[10] arr; 2524 int a = 2; 2525 int b = 3; 2526 int N = int(c.x); 2527 for (int i = 0; i < 10; i++) { 2528 for (int j = 2; j < 10; j++) { 2529 arr[i] = arr[j]; // 0 2530 arr[j] = arr[i]; // 1 2531 arr[j-2] = arr[i+3]; // 2 2532 arr[j-a] = arr[i+b]; // 3 2533 arr[2*i] = arr[4*j+3]; // 4, independent 2534 arr[2*i] = arr[4*j]; // 5 2535 arr[i+j] = arr[i+j]; // 6 2536 arr[10*i+j] = arr[10*i+j]; // 7 2537 arr[10*i+10*j] = arr[10*i+10*j+3]; // 8, independent 2538 arr[10*i+10*j] = arr[10*i+N*j+3]; // 9, bail out because of N coefficient 2539 arr[10*i+10*j] = arr[10*i+10*j+N]; // 10, bail out because of N constant 2540 // term 2541 arr[10*i+N*j] = arr[10*i+10*j+3]; // 11, bail out because of N coefficient 2542 arr[10*i+10*j+N] = arr[10*i+10*j]; // 12, bail out because of N constant 2543 // term 2544 arr[10*i] = arr[5*j]; // 13, independent 2545 arr[5*i] = arr[10*j]; // 14, independent 2546 arr[9*i] = arr[3*j]; // 15, independent 2547 arr[3*i] = arr[9*j]; // 16, independent 2548 } 2549 } 2550 } 2551 */ 2552 TEST(DependencyAnalysis, MIV) { 2553 const std::string text = R"( 2554 OpCapability Shader 2555 %1 = OpExtInstImport "GLSL.std.450" 2556 OpMemoryModel Logical GLSL450 2557 OpEntryPoint Fragment %4 "main" %16 2558 OpExecutionMode %4 OriginUpperLeft 2559 OpSource GLSL 440 2560 OpName %4 "main" 2561 OpName %8 "a" 2562 OpName %10 "b" 2563 OpName %12 "N" 2564 OpName %16 "c" 2565 OpName %23 "i" 2566 OpName %34 "j" 2567 OpName %45 "arr" 2568 OpDecorate %16 Location 0 2569 %2 = OpTypeVoid 2570 %3 = OpTypeFunction %2 2571 %6 = OpTypeInt 32 1 2572 %7 = OpTypePointer Function %6 2573 %9 = OpConstant %6 2 2574 %11 = OpConstant %6 3 2575 %13 = OpTypeFloat 32 2576 %14 = OpTypeVector %13 4 2577 %15 = OpTypePointer Input %14 2578 %16 = OpVariable %15 Input 2579 %17 = OpTypeInt 32 0 2580 %18 = OpConstant %17 0 2581 %19 = OpTypePointer Input %13 2582 %24 = OpConstant %6 0 2583 %31 = OpConstant %6 10 2584 %32 = OpTypeBool 2585 %42 = OpConstant %17 10 2586 %43 = OpTypeArray %6 %42 2587 %44 = OpTypePointer Function %43 2588 %74 = OpConstant %6 4 2589 %184 = OpConstant %6 5 2590 %197 = OpConstant %6 9 2591 %213 = OpConstant %6 1 2592 %218 = OpUndef %6 2593 %4 = OpFunction %2 None %3 2594 %5 = OpLabel 2595 %8 = OpVariable %7 Function 2596 %10 = OpVariable %7 Function 2597 %12 = OpVariable %7 Function 2598 %23 = OpVariable %7 Function 2599 %34 = OpVariable %7 Function 2600 %45 = OpVariable %44 Function 2601 OpStore %8 %9 2602 OpStore %10 %11 2603 %20 = OpAccessChain %19 %16 %18 2604 %21 = OpLoad %13 %20 2605 %22 = OpConvertFToS %6 %21 2606 OpStore %12 %22 2607 OpStore %23 %24 2608 OpBranch %25 2609 %25 = OpLabel 2610 %217 = OpPhi %6 %24 %5 %216 %28 2611 %219 = OpPhi %6 %218 %5 %220 %28 2612 OpLoopMerge %27 %28 None 2613 OpBranch %29 2614 %29 = OpLabel 2615 %33 = OpSLessThan %32 %217 %31 2616 OpBranchConditional %33 %26 %27 2617 %26 = OpLabel 2618 OpStore %34 %9 2619 OpBranch %35 2620 %35 = OpLabel 2621 %220 = OpPhi %6 %9 %26 %214 %38 2622 OpLoopMerge %37 %38 None 2623 OpBranch %39 2624 %39 = OpLabel 2625 %41 = OpSLessThan %32 %220 %31 2626 OpBranchConditional %41 %36 %37 2627 %36 = OpLabel 2628 %48 = OpAccessChain %7 %45 %220 2629 %49 = OpLoad %6 %48 2630 %50 = OpAccessChain %7 %45 %217 2631 OpStore %50 %49 2632 %53 = OpAccessChain %7 %45 %217 2633 %54 = OpLoad %6 %53 2634 %55 = OpAccessChain %7 %45 %220 2635 OpStore %55 %54 2636 %57 = OpISub %6 %220 %9 2637 %59 = OpIAdd %6 %217 %11 2638 %60 = OpAccessChain %7 %45 %59 2639 %61 = OpLoad %6 %60 2640 %62 = OpAccessChain %7 %45 %57 2641 OpStore %62 %61 2642 %65 = OpISub %6 %220 %9 2643 %68 = OpIAdd %6 %217 %11 2644 %69 = OpAccessChain %7 %45 %68 2645 %70 = OpLoad %6 %69 2646 %71 = OpAccessChain %7 %45 %65 2647 OpStore %71 %70 2648 %73 = OpIMul %6 %9 %217 2649 %76 = OpIMul %6 %74 %220 2650 %77 = OpIAdd %6 %76 %11 2651 %78 = OpAccessChain %7 %45 %77 2652 %79 = OpLoad %6 %78 2653 %80 = OpAccessChain %7 %45 %73 2654 OpStore %80 %79 2655 %82 = OpIMul %6 %9 %217 2656 %84 = OpIMul %6 %74 %220 2657 %85 = OpAccessChain %7 %45 %84 2658 %86 = OpLoad %6 %85 2659 %87 = OpAccessChain %7 %45 %82 2660 OpStore %87 %86 2661 %90 = OpIAdd %6 %217 %220 2662 %93 = OpIAdd %6 %217 %220 2663 %94 = OpAccessChain %7 %45 %93 2664 %95 = OpLoad %6 %94 2665 %96 = OpAccessChain %7 %45 %90 2666 OpStore %96 %95 2667 %98 = OpIMul %6 %31 %217 2668 %100 = OpIAdd %6 %98 %220 2669 %102 = OpIMul %6 %31 %217 2670 %104 = OpIAdd %6 %102 %220 2671 %105 = OpAccessChain %7 %45 %104 2672 %106 = OpLoad %6 %105 2673 %107 = OpAccessChain %7 %45 %100 2674 OpStore %107 %106 2675 %109 = OpIMul %6 %31 %217 2676 %111 = OpIMul %6 %31 %220 2677 %112 = OpIAdd %6 %109 %111 2678 %114 = OpIMul %6 %31 %217 2679 %116 = OpIMul %6 %31 %220 2680 %117 = OpIAdd %6 %114 %116 2681 %118 = OpIAdd %6 %117 %11 2682 %119 = OpAccessChain %7 %45 %118 2683 %120 = OpLoad %6 %119 2684 %121 = OpAccessChain %7 %45 %112 2685 OpStore %121 %120 2686 %123 = OpIMul %6 %31 %217 2687 %125 = OpIMul %6 %31 %220 2688 %126 = OpIAdd %6 %123 %125 2689 %128 = OpIMul %6 %31 %217 2690 %131 = OpIMul %6 %22 %220 2691 %132 = OpIAdd %6 %128 %131 2692 %133 = OpIAdd %6 %132 %11 2693 %134 = OpAccessChain %7 %45 %133 2694 %135 = OpLoad %6 %134 2695 %136 = OpAccessChain %7 %45 %126 2696 OpStore %136 %135 2697 %138 = OpIMul %6 %31 %217 2698 %140 = OpIMul %6 %31 %220 2699 %141 = OpIAdd %6 %138 %140 2700 %143 = OpIMul %6 %31 %217 2701 %145 = OpIMul %6 %31 %220 2702 %146 = OpIAdd %6 %143 %145 2703 %148 = OpIAdd %6 %146 %22 2704 %149 = OpAccessChain %7 %45 %148 2705 %150 = OpLoad %6 %149 2706 %151 = OpAccessChain %7 %45 %141 2707 OpStore %151 %150 2708 %153 = OpIMul %6 %31 %217 2709 %156 = OpIMul %6 %22 %220 2710 %157 = OpIAdd %6 %153 %156 2711 %159 = OpIMul %6 %31 %217 2712 %161 = OpIMul %6 %31 %220 2713 %162 = OpIAdd %6 %159 %161 2714 %163 = OpIAdd %6 %162 %11 2715 %164 = OpAccessChain %7 %45 %163 2716 %165 = OpLoad %6 %164 2717 %166 = OpAccessChain %7 %45 %157 2718 OpStore %166 %165 2719 %168 = OpIMul %6 %31 %217 2720 %170 = OpIMul %6 %31 %220 2721 %171 = OpIAdd %6 %168 %170 2722 %173 = OpIAdd %6 %171 %22 2723 %175 = OpIMul %6 %31 %217 2724 %177 = OpIMul %6 %31 %220 2725 %178 = OpIAdd %6 %175 %177 2726 %179 = OpAccessChain %7 %45 %178 2727 %180 = OpLoad %6 %179 2728 %181 = OpAccessChain %7 %45 %173 2729 OpStore %181 %180 2730 %183 = OpIMul %6 %31 %217 2731 %186 = OpIMul %6 %184 %220 2732 %187 = OpAccessChain %7 %45 %186 2733 %188 = OpLoad %6 %187 2734 %189 = OpAccessChain %7 %45 %183 2735 OpStore %189 %188 2736 %191 = OpIMul %6 %184 %217 2737 %193 = OpIMul %6 %31 %220 2738 %194 = OpAccessChain %7 %45 %193 2739 %195 = OpLoad %6 %194 2740 %196 = OpAccessChain %7 %45 %191 2741 OpStore %196 %195 2742 %199 = OpIMul %6 %197 %217 2743 %201 = OpIMul %6 %11 %220 2744 %202 = OpAccessChain %7 %45 %201 2745 %203 = OpLoad %6 %202 2746 %204 = OpAccessChain %7 %45 %199 2747 OpStore %204 %203 2748 %206 = OpIMul %6 %11 %217 2749 %208 = OpIMul %6 %197 %220 2750 %209 = OpAccessChain %7 %45 %208 2751 %210 = OpLoad %6 %209 2752 %211 = OpAccessChain %7 %45 %206 2753 OpStore %211 %210 2754 OpBranch %38 2755 %38 = OpLabel 2756 %214 = OpIAdd %6 %220 %213 2757 OpStore %34 %214 2758 OpBranch %35 2759 %37 = OpLabel 2760 OpBranch %28 2761 %28 = OpLabel 2762 %216 = OpIAdd %6 %217 %213 2763 OpStore %23 %216 2764 OpBranch %25 2765 %27 = OpLabel 2766 OpReturn 2767 OpFunctionEnd 2768 )"; 2769 2770 std::unique_ptr<IRContext> context = 2771 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, 2772 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 2773 Module* module = context->module(); 2774 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n" 2775 << text << std::endl; 2776 const Function* f = spvtest::GetFunction(module, 4); 2777 LoopDescriptor& ld = *context->GetLoopDescriptor(f); 2778 2779 std::vector<const Loop*> loops{&ld.GetLoopByIndex(0), &ld.GetLoopByIndex(1)}; 2780 2781 LoopDependenceAnalysis analysis{context.get(), loops}; 2782 2783 const int instructions_expected = 17; 2784 const Instruction* store[instructions_expected]; 2785 const Instruction* load[instructions_expected]; 2786 int stores_found = 0; 2787 int loads_found = 0; 2788 2789 int block_id = 36; 2790 ASSERT_TRUE(spvtest::GetBasicBlock(f, block_id)); 2791 2792 for (const Instruction& inst : *spvtest::GetBasicBlock(f, block_id)) { 2793 if (inst.opcode() == SpvOp::SpvOpStore) { 2794 store[stores_found] = &inst; 2795 ++stores_found; 2796 } 2797 2798 if (inst.opcode() == SpvOp::SpvOpLoad) { 2799 load[loads_found] = &inst; 2800 ++loads_found; 2801 } 2802 } 2803 2804 EXPECT_EQ(instructions_expected, stores_found); 2805 EXPECT_EQ(instructions_expected, loads_found); 2806 2807 auto directions_all = DistanceEntry(DistanceEntry::Directions::ALL); 2808 auto directions_none = DistanceEntry(DistanceEntry::Directions::NONE); 2809 2810 auto dependent = DistanceVector({directions_all, directions_all}); 2811 auto independent = DistanceVector({directions_none, directions_none}); 2812 2813 CheckDependenceAndDirection(load[0], store[0], false, dependent, &analysis); 2814 CheckDependenceAndDirection(load[1], store[1], false, dependent, &analysis); 2815 CheckDependenceAndDirection(load[2], store[2], false, dependent, &analysis); 2816 CheckDependenceAndDirection(load[3], store[3], false, dependent, &analysis); 2817 CheckDependenceAndDirection(load[4], store[4], true, independent, &analysis); 2818 CheckDependenceAndDirection(load[5], store[5], false, dependent, &analysis); 2819 CheckDependenceAndDirection(load[6], store[6], false, dependent, &analysis); 2820 CheckDependenceAndDirection(load[7], store[7], false, dependent, &analysis); 2821 CheckDependenceAndDirection(load[8], store[8], true, independent, &analysis); 2822 CheckDependenceAndDirection(load[9], store[9], false, dependent, &analysis); 2823 CheckDependenceAndDirection(load[10], store[10], false, dependent, &analysis); 2824 CheckDependenceAndDirection(load[11], store[11], false, dependent, &analysis); 2825 CheckDependenceAndDirection(load[12], store[12], false, dependent, &analysis); 2826 CheckDependenceAndDirection(load[13], store[13], true, independent, 2827 &analysis); 2828 CheckDependenceAndDirection(load[14], store[14], true, independent, 2829 &analysis); 2830 CheckDependenceAndDirection(load[15], store[15], true, independent, 2831 &analysis); 2832 CheckDependenceAndDirection(load[16], store[16], true, independent, 2833 &analysis); 2834 } 2835 2836 void PartitionSubscripts(const Instruction* instruction_0, 2837 const Instruction* instruction_1, 2838 LoopDependenceAnalysis* analysis, 2839 std::vector<std::vector<int>> expected_ids) { 2840 auto subscripts_0 = analysis->GetSubscripts(instruction_0); 2841 auto subscripts_1 = analysis->GetSubscripts(instruction_1); 2842 2843 std::vector<std::set<std::pair<Instruction*, Instruction*>>> 2844 expected_partition{}; 2845 2846 for (const auto& partition : expected_ids) { 2847 expected_partition.push_back( 2848 std::set<std::pair<Instruction*, Instruction*>>{}); 2849 for (auto id : partition) { 2850 expected_partition.back().insert({subscripts_0[id], subscripts_1[id]}); 2851 } 2852 } 2853 2854 EXPECT_EQ(expected_partition, 2855 analysis->PartitionSubscripts(subscripts_0, subscripts_1)); 2856 } 2857 2858 /* 2859 Generated from the following GLSL fragment shader 2860 with --eliminate-local-multi-store 2861 #version 440 core 2862 void main(){ 2863 int[10][10][10][10] arr; 2864 for (int i = 0; i < 10; i++) { 2865 for (int j = 0; j < 10; j++) { 2866 for (int k = 0; k < 10; k++) { 2867 for (int l = 0; l < 10; l++) { 2868 arr[i][j][k][l] = arr[i][j][k][l]; // 0, all independent 2869 arr[i][j][k][l] = arr[i][j][l][0]; // 1, last 2 coupled 2870 arr[i][j][k][l] = arr[j][i][k][l]; // 2, first 2 coupled 2871 arr[i][j][k][l] = arr[l][j][k][i]; // 3, first & last coupled 2872 arr[i][j][k][l] = arr[i][k][j][l]; // 4, middle 2 coupled 2873 arr[i+j][j][k][l] = arr[i][j][k][l]; // 5, first 2 coupled 2874 arr[i+j+k][j][k][l] = arr[i][j][k][l]; // 6, first 3 coupled 2875 arr[i+j+k+l][j][k][l] = arr[i][j][k][l]; // 7, all 4 coupled 2876 arr[i][j][k][l] = arr[i][l][j][k]; // 8, last 3 coupled 2877 arr[i][j-k][k][l] = arr[i][j][l][k]; // 9, last 3 coupled 2878 arr[i][j][k][l] = arr[l][i][j][k]; // 10, all 4 coupled 2879 arr[i][j][k][l] = arr[j][i][l][k]; // 11, 2 coupled partitions (i,j) & 2880 (l&k) 2881 arr[i][j][k][l] = arr[k][l][i][j]; // 12, 2 coupled partitions (i,k) & 2882 (j&l) 2883 } 2884 } 2885 } 2886 } 2887 } 2888 */ 2889 TEST(DependencyAnalysis, SubscriptPartitioning) { 2890 const std::string text = R"( 2891 OpCapability Shader 2892 %1 = OpExtInstImport "GLSL.std.450" 2893 OpMemoryModel Logical GLSL450 2894 OpEntryPoint Fragment %4 "main" 2895 OpExecutionMode %4 OriginUpperLeft 2896 OpSource GLSL 440 2897 OpName %4 "main" 2898 OpName %8 "i" 2899 OpName %19 "j" 2900 OpName %27 "k" 2901 OpName %35 "l" 2902 OpName %50 "arr" 2903 %2 = OpTypeVoid 2904 %3 = OpTypeFunction %2 2905 %6 = OpTypeInt 32 1 2906 %7 = OpTypePointer Function %6 2907 %9 = OpConstant %6 0 2908 %16 = OpConstant %6 10 2909 %17 = OpTypeBool 2910 %43 = OpTypeInt 32 0 2911 %44 = OpConstant %43 10 2912 %45 = OpTypeArray %6 %44 2913 %46 = OpTypeArray %45 %44 2914 %47 = OpTypeArray %46 %44 2915 %48 = OpTypeArray %47 %44 2916 %49 = OpTypePointer Function %48 2917 %208 = OpConstant %6 1 2918 %217 = OpUndef %6 2919 %4 = OpFunction %2 None %3 2920 %5 = OpLabel 2921 %8 = OpVariable %7 Function 2922 %19 = OpVariable %7 Function 2923 %27 = OpVariable %7 Function 2924 %35 = OpVariable %7 Function 2925 %50 = OpVariable %49 Function 2926 OpStore %8 %9 2927 OpBranch %10 2928 %10 = OpLabel 2929 %216 = OpPhi %6 %9 %5 %215 %13 2930 %218 = OpPhi %6 %217 %5 %221 %13 2931 %219 = OpPhi %6 %217 %5 %222 %13 2932 %220 = OpPhi %6 %217 %5 %223 %13 2933 OpLoopMerge %12 %13 None 2934 OpBranch %14 2935 %14 = OpLabel 2936 %18 = OpSLessThan %17 %216 %16 2937 OpBranchConditional %18 %11 %12 2938 %11 = OpLabel 2939 OpStore %19 %9 2940 OpBranch %20 2941 %20 = OpLabel 2942 %221 = OpPhi %6 %9 %11 %213 %23 2943 %222 = OpPhi %6 %219 %11 %224 %23 2944 %223 = OpPhi %6 %220 %11 %225 %23 2945 OpLoopMerge %22 %23 None 2946 OpBranch %24 2947 %24 = OpLabel 2948 %26 = OpSLessThan %17 %221 %16 2949 OpBranchConditional %26 %21 %22 2950 %21 = OpLabel 2951 OpStore %27 %9 2952 OpBranch %28 2953 %28 = OpLabel 2954 %224 = OpPhi %6 %9 %21 %211 %31 2955 %225 = OpPhi %6 %223 %21 %226 %31 2956 OpLoopMerge %30 %31 None 2957 OpBranch %32 2958 %32 = OpLabel 2959 %34 = OpSLessThan %17 %224 %16 2960 OpBranchConditional %34 %29 %30 2961 %29 = OpLabel 2962 OpStore %35 %9 2963 OpBranch %36 2964 %36 = OpLabel 2965 %226 = OpPhi %6 %9 %29 %209 %39 2966 OpLoopMerge %38 %39 None 2967 OpBranch %40 2968 %40 = OpLabel 2969 %42 = OpSLessThan %17 %226 %16 2970 OpBranchConditional %42 %37 %38 2971 %37 = OpLabel 2972 %59 = OpAccessChain %7 %50 %216 %221 %224 %226 2973 %60 = OpLoad %6 %59 2974 %61 = OpAccessChain %7 %50 %216 %221 %224 %226 2975 OpStore %61 %60 2976 %69 = OpAccessChain %7 %50 %216 %221 %226 %9 2977 %70 = OpLoad %6 %69 2978 %71 = OpAccessChain %7 %50 %216 %221 %224 %226 2979 OpStore %71 %70 2980 %80 = OpAccessChain %7 %50 %221 %216 %224 %226 2981 %81 = OpLoad %6 %80 2982 %82 = OpAccessChain %7 %50 %216 %221 %224 %226 2983 OpStore %82 %81 2984 %91 = OpAccessChain %7 %50 %226 %221 %224 %216 2985 %92 = OpLoad %6 %91 2986 %93 = OpAccessChain %7 %50 %216 %221 %224 %226 2987 OpStore %93 %92 2988 %102 = OpAccessChain %7 %50 %216 %224 %221 %226 2989 %103 = OpLoad %6 %102 2990 %104 = OpAccessChain %7 %50 %216 %221 %224 %226 2991 OpStore %104 %103 2992 %107 = OpIAdd %6 %216 %221 2993 %115 = OpAccessChain %7 %50 %216 %221 %224 %226 2994 %116 = OpLoad %6 %115 2995 %117 = OpAccessChain %7 %50 %107 %221 %224 %226 2996 OpStore %117 %116 2997 %120 = OpIAdd %6 %216 %221 2998 %122 = OpIAdd %6 %120 %224 2999 %130 = OpAccessChain %7 %50 %216 %221 %224 %226 3000 %131 = OpLoad %6 %130 3001 %132 = OpAccessChain %7 %50 %122 %221 %224 %226 3002 OpStore %132 %131 3003 %135 = OpIAdd %6 %216 %221 3004 %137 = OpIAdd %6 %135 %224 3005 %139 = OpIAdd %6 %137 %226 3006 %147 = OpAccessChain %7 %50 %216 %221 %224 %226 3007 %148 = OpLoad %6 %147 3008 %149 = OpAccessChain %7 %50 %139 %221 %224 %226 3009 OpStore %149 %148 3010 %158 = OpAccessChain %7 %50 %216 %226 %221 %224 3011 %159 = OpLoad %6 %158 3012 %160 = OpAccessChain %7 %50 %216 %221 %224 %226 3013 OpStore %160 %159 3014 %164 = OpISub %6 %221 %224 3015 %171 = OpAccessChain %7 %50 %216 %221 %226 %224 3016 %172 = OpLoad %6 %171 3017 %173 = OpAccessChain %7 %50 %216 %164 %224 %226 3018 OpStore %173 %172 3019 %182 = OpAccessChain %7 %50 %226 %216 %221 %224 3020 %183 = OpLoad %6 %182 3021 %184 = OpAccessChain %7 %50 %216 %221 %224 %226 3022 OpStore %184 %183 3023 %193 = OpAccessChain %7 %50 %221 %216 %226 %224 3024 %194 = OpLoad %6 %193 3025 %195 = OpAccessChain %7 %50 %216 %221 %224 %226 3026 OpStore %195 %194 3027 %204 = OpAccessChain %7 %50 %224 %226 %216 %221 3028 %205 = OpLoad %6 %204 3029 %206 = OpAccessChain %7 %50 %216 %221 %224 %226 3030 OpStore %206 %205 3031 OpBranch %39 3032 %39 = OpLabel 3033 %209 = OpIAdd %6 %226 %208 3034 OpStore %35 %209 3035 OpBranch %36 3036 %38 = OpLabel 3037 OpBranch %31 3038 %31 = OpLabel 3039 %211 = OpIAdd %6 %224 %208 3040 OpStore %27 %211 3041 OpBranch %28 3042 %30 = OpLabel 3043 OpBranch %23 3044 %23 = OpLabel 3045 %213 = OpIAdd %6 %221 %208 3046 OpStore %19 %213 3047 OpBranch %20 3048 %22 = OpLabel 3049 OpBranch %13 3050 %13 = OpLabel 3051 %215 = OpIAdd %6 %216 %208 3052 OpStore %8 %215 3053 OpBranch %10 3054 %12 = OpLabel 3055 OpReturn 3056 OpFunctionEnd 3057 )"; 3058 3059 std::unique_ptr<IRContext> context = 3060 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, 3061 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 3062 Module* module = context->module(); 3063 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n" 3064 << text << std::endl; 3065 const Function* f = spvtest::GetFunction(module, 4); 3066 LoopDescriptor& ld = *context->GetLoopDescriptor(f); 3067 3068 std::vector<const Loop*> loop_nest{ 3069 &ld.GetLoopByIndex(0), &ld.GetLoopByIndex(1), &ld.GetLoopByIndex(2), 3070 &ld.GetLoopByIndex(3)}; 3071 LoopDependenceAnalysis analysis{context.get(), loop_nest}; 3072 3073 const int instructions_expected = 13; 3074 const Instruction* store[instructions_expected]; 3075 const Instruction* load[instructions_expected]; 3076 int stores_found = 0; 3077 int loads_found = 0; 3078 3079 int block_id = 37; 3080 ASSERT_TRUE(spvtest::GetBasicBlock(f, block_id)); 3081 3082 for (const Instruction& inst : *spvtest::GetBasicBlock(f, block_id)) { 3083 if (inst.opcode() == SpvOp::SpvOpStore) { 3084 store[stores_found] = &inst; 3085 ++stores_found; 3086 } 3087 3088 if (inst.opcode() == SpvOp::SpvOpLoad) { 3089 load[loads_found] = &inst; 3090 ++loads_found; 3091 } 3092 } 3093 3094 EXPECT_EQ(instructions_expected, stores_found); 3095 EXPECT_EQ(instructions_expected, loads_found); 3096 3097 PartitionSubscripts(load[0], store[0], &analysis, {{0}, {1}, {2}, {3}}); 3098 PartitionSubscripts(load[1], store[1], &analysis, {{0}, {1}, {2, 3}}); 3099 PartitionSubscripts(load[2], store[2], &analysis, {{0, 1}, {2}, {3}}); 3100 PartitionSubscripts(load[3], store[3], &analysis, {{0, 3}, {1}, {2}}); 3101 PartitionSubscripts(load[4], store[4], &analysis, {{0}, {1, 2}, {3}}); 3102 PartitionSubscripts(load[5], store[5], &analysis, {{0, 1}, {2}, {3}}); 3103 PartitionSubscripts(load[6], store[6], &analysis, {{0, 1, 2}, {3}}); 3104 PartitionSubscripts(load[7], store[7], &analysis, {{0, 1, 2, 3}}); 3105 PartitionSubscripts(load[8], store[8], &analysis, {{0}, {1, 2, 3}}); 3106 PartitionSubscripts(load[9], store[9], &analysis, {{0}, {1, 2, 3}}); 3107 PartitionSubscripts(load[10], store[10], &analysis, {{0, 1, 2, 3}}); 3108 PartitionSubscripts(load[11], store[11], &analysis, {{0, 1}, {2, 3}}); 3109 PartitionSubscripts(load[12], store[12], &analysis, {{0, 2}, {1, 3}}); 3110 } 3111 3112 /* 3113 Generated from the following GLSL fragment shader 3114 with --eliminate-local-multi-store 3115 3116 #version 440 core 3117 void a() { 3118 int[10][10] arr; 3119 for (int i = 0; i < 10; ++i) { 3120 for (int j = 0; j < 10; ++j) { 3121 // Dependent, distance vector (1, -1) 3122 arr[i+1][i+j] = arr[i][i+j]; 3123 } 3124 } 3125 } 3126 3127 void b() { 3128 int[10][10] arr; 3129 for (int i = 0; i < 10; ++i) { 3130 // Independent 3131 arr[i+1][i+2] = arr[i][i] + 2; 3132 } 3133 } 3134 3135 void c() { 3136 int[10][10] arr; 3137 for (int i = 0; i < 10; ++i) { 3138 // Dependence point (1,2) 3139 arr[i][i] = arr[1][i-1] + 2; 3140 } 3141 } 3142 3143 void d() { 3144 int[10][10][10] arr; 3145 for (int i = 0; i < 10; ++i) { 3146 for (int j = 0; j < 10; ++j) { 3147 for (int k = 0; k < 10; ++k) { 3148 // Dependent, distance vector (1,1,-1) 3149 arr[j-i][i+1][j+k] = arr[j-i][i][j+k]; 3150 } 3151 } 3152 } 3153 } 3154 3155 void e() { 3156 int[10][10] arr; 3157 for (int i = 0; i < 10; ++i) { 3158 for (int j = 0; j < 10; ++j) { 3159 // Independent with GCD after propagation 3160 arr[i][2*j+i] = arr[i][2*j-i+5]; 3161 } 3162 } 3163 } 3164 3165 void main(){ 3166 a(); 3167 b(); 3168 c(); 3169 d(); 3170 e(); 3171 } 3172 */ 3173 TEST(DependencyAnalysis, Delta) { 3174 const std::string text = R"( 3175 OpCapability Shader 3176 %1 = OpExtInstImport "GLSL.std.450" 3177 OpMemoryModel Logical GLSL450 3178 OpEntryPoint Fragment %4 "main" 3179 OpExecutionMode %4 OriginUpperLeft 3180 OpSource GLSL 440 3181 OpName %4 "main" 3182 OpName %6 "a(" 3183 OpName %8 "b(" 3184 OpName %10 "c(" 3185 OpName %12 "d(" 3186 OpName %14 "e(" 3187 OpName %18 "i" 3188 OpName %29 "j" 3189 OpName %42 "arr" 3190 OpName %60 "i" 3191 OpName %68 "arr" 3192 OpName %82 "i" 3193 OpName %90 "arr" 3194 OpName %101 "i" 3195 OpName %109 "j" 3196 OpName %117 "k" 3197 OpName %127 "arr" 3198 OpName %152 "i" 3199 OpName %160 "j" 3200 OpName %168 "arr" 3201 %2 = OpTypeVoid 3202 %3 = OpTypeFunction %2 3203 %16 = OpTypeInt 32 1 3204 %17 = OpTypePointer Function %16 3205 %19 = OpConstant %16 0 3206 %26 = OpConstant %16 10 3207 %27 = OpTypeBool 3208 %37 = OpTypeInt 32 0 3209 %38 = OpConstant %37 10 3210 %39 = OpTypeArray %16 %38 3211 %40 = OpTypeArray %39 %38 3212 %41 = OpTypePointer Function %40 3213 %44 = OpConstant %16 1 3214 %72 = OpConstant %16 2 3215 %125 = OpTypeArray %40 %38 3216 %126 = OpTypePointer Function %125 3217 %179 = OpConstant %16 5 3218 %4 = OpFunction %2 None %3 3219 %5 = OpLabel 3220 %188 = OpFunctionCall %2 %6 3221 %189 = OpFunctionCall %2 %8 3222 %190 = OpFunctionCall %2 %10 3223 %191 = OpFunctionCall %2 %12 3224 %192 = OpFunctionCall %2 %14 3225 OpReturn 3226 OpFunctionEnd 3227 %6 = OpFunction %2 None %3 3228 %7 = OpLabel 3229 %18 = OpVariable %17 Function 3230 %29 = OpVariable %17 Function 3231 %42 = OpVariable %41 Function 3232 OpStore %18 %19 3233 OpBranch %20 3234 %20 = OpLabel 3235 %193 = OpPhi %16 %19 %7 %59 %23 3236 OpLoopMerge %22 %23 None 3237 OpBranch %24 3238 %24 = OpLabel 3239 %28 = OpSLessThan %27 %193 %26 3240 OpBranchConditional %28 %21 %22 3241 %21 = OpLabel 3242 OpStore %29 %19 3243 OpBranch %30 3244 %30 = OpLabel 3245 %194 = OpPhi %16 %19 %21 %57 %33 3246 OpLoopMerge %32 %33 None 3247 OpBranch %34 3248 %34 = OpLabel 3249 %36 = OpSLessThan %27 %194 %26 3250 OpBranchConditional %36 %31 %32 3251 %31 = OpLabel 3252 %45 = OpIAdd %16 %193 %44 3253 %48 = OpIAdd %16 %193 %194 3254 %52 = OpIAdd %16 %193 %194 3255 %53 = OpAccessChain %17 %42 %193 %52 3256 %54 = OpLoad %16 %53 3257 %55 = OpAccessChain %17 %42 %45 %48 3258 OpStore %55 %54 3259 OpBranch %33 3260 %33 = OpLabel 3261 %57 = OpIAdd %16 %194 %44 3262 OpStore %29 %57 3263 OpBranch %30 3264 %32 = OpLabel 3265 OpBranch %23 3266 %23 = OpLabel 3267 %59 = OpIAdd %16 %193 %44 3268 OpStore %18 %59 3269 OpBranch %20 3270 %22 = OpLabel 3271 OpReturn 3272 OpFunctionEnd 3273 %8 = OpFunction %2 None %3 3274 %9 = OpLabel 3275 %60 = OpVariable %17 Function 3276 %68 = OpVariable %41 Function 3277 OpStore %60 %19 3278 OpBranch %61 3279 %61 = OpLabel 3280 %196 = OpPhi %16 %19 %9 %81 %64 3281 OpLoopMerge %63 %64 None 3282 OpBranch %65 3283 %65 = OpLabel 3284 %67 = OpSLessThan %27 %196 %26 3285 OpBranchConditional %67 %62 %63 3286 %62 = OpLabel 3287 %70 = OpIAdd %16 %196 %44 3288 %73 = OpIAdd %16 %196 %72 3289 %76 = OpAccessChain %17 %68 %196 %196 3290 %77 = OpLoad %16 %76 3291 %78 = OpIAdd %16 %77 %72 3292 %79 = OpAccessChain %17 %68 %70 %73 3293 OpStore %79 %78 3294 OpBranch %64 3295 %64 = OpLabel 3296 %81 = OpIAdd %16 %196 %44 3297 OpStore %60 %81 3298 OpBranch %61 3299 %63 = OpLabel 3300 OpReturn 3301 OpFunctionEnd 3302 %10 = OpFunction %2 None %3 3303 %11 = OpLabel 3304 %82 = OpVariable %17 Function 3305 %90 = OpVariable %41 Function 3306 OpStore %82 %19 3307 OpBranch %83 3308 %83 = OpLabel 3309 %197 = OpPhi %16 %19 %11 %100 %86 3310 OpLoopMerge %85 %86 None 3311 OpBranch %87 3312 %87 = OpLabel 3313 %89 = OpSLessThan %27 %197 %26 3314 OpBranchConditional %89 %84 %85 3315 %84 = OpLabel 3316 %94 = OpISub %16 %197 %44 3317 %95 = OpAccessChain %17 %90 %44 %94 3318 %96 = OpLoad %16 %95 3319 %97 = OpIAdd %16 %96 %72 3320 %98 = OpAccessChain %17 %90 %197 %197 3321 OpStore %98 %97 3322 OpBranch %86 3323 %86 = OpLabel 3324 %100 = OpIAdd %16 %197 %44 3325 OpStore %82 %100 3326 OpBranch %83 3327 %85 = OpLabel 3328 OpReturn 3329 OpFunctionEnd 3330 %12 = OpFunction %2 None %3 3331 %13 = OpLabel 3332 %101 = OpVariable %17 Function 3333 %109 = OpVariable %17 Function 3334 %117 = OpVariable %17 Function 3335 %127 = OpVariable %126 Function 3336 OpStore %101 %19 3337 OpBranch %102 3338 %102 = OpLabel 3339 %198 = OpPhi %16 %19 %13 %151 %105 3340 OpLoopMerge %104 %105 None 3341 OpBranch %106 3342 %106 = OpLabel 3343 %108 = OpSLessThan %27 %198 %26 3344 OpBranchConditional %108 %103 %104 3345 %103 = OpLabel 3346 OpStore %109 %19 3347 OpBranch %110 3348 %110 = OpLabel 3349 %199 = OpPhi %16 %19 %103 %149 %113 3350 OpLoopMerge %112 %113 None 3351 OpBranch %114 3352 %114 = OpLabel 3353 %116 = OpSLessThan %27 %199 %26 3354 OpBranchConditional %116 %111 %112 3355 %111 = OpLabel 3356 OpStore %117 %19 3357 OpBranch %118 3358 %118 = OpLabel 3359 %201 = OpPhi %16 %19 %111 %147 %121 3360 OpLoopMerge %120 %121 None 3361 OpBranch %122 3362 %122 = OpLabel 3363 %124 = OpSLessThan %27 %201 %26 3364 OpBranchConditional %124 %119 %120 3365 %119 = OpLabel 3366 %130 = OpISub %16 %199 %198 3367 %132 = OpIAdd %16 %198 %44 3368 %135 = OpIAdd %16 %199 %201 3369 %138 = OpISub %16 %199 %198 3370 %142 = OpIAdd %16 %199 %201 3371 %143 = OpAccessChain %17 %127 %138 %198 %142 3372 %144 = OpLoad %16 %143 3373 %145 = OpAccessChain %17 %127 %130 %132 %135 3374 OpStore %145 %144 3375 OpBranch %121 3376 %121 = OpLabel 3377 %147 = OpIAdd %16 %201 %44 3378 OpStore %117 %147 3379 OpBranch %118 3380 %120 = OpLabel 3381 OpBranch %113 3382 %113 = OpLabel 3383 %149 = OpIAdd %16 %199 %44 3384 OpStore %109 %149 3385 OpBranch %110 3386 %112 = OpLabel 3387 OpBranch %105 3388 %105 = OpLabel 3389 %151 = OpIAdd %16 %198 %44 3390 OpStore %101 %151 3391 OpBranch %102 3392 %104 = OpLabel 3393 OpReturn 3394 OpFunctionEnd 3395 %14 = OpFunction %2 None %3 3396 %15 = OpLabel 3397 %152 = OpVariable %17 Function 3398 %160 = OpVariable %17 Function 3399 %168 = OpVariable %41 Function 3400 OpStore %152 %19 3401 OpBranch %153 3402 %153 = OpLabel 3403 %204 = OpPhi %16 %19 %15 %187 %156 3404 OpLoopMerge %155 %156 None 3405 OpBranch %157 3406 %157 = OpLabel 3407 %159 = OpSLessThan %27 %204 %26 3408 OpBranchConditional %159 %154 %155 3409 %154 = OpLabel 3410 OpStore %160 %19 3411 OpBranch %161 3412 %161 = OpLabel 3413 %205 = OpPhi %16 %19 %154 %185 %164 3414 OpLoopMerge %163 %164 None 3415 OpBranch %165 3416 %165 = OpLabel 3417 %167 = OpSLessThan %27 %205 %26 3418 OpBranchConditional %167 %162 %163 3419 %162 = OpLabel 3420 %171 = OpIMul %16 %72 %205 3421 %173 = OpIAdd %16 %171 %204 3422 %176 = OpIMul %16 %72 %205 3423 %178 = OpISub %16 %176 %204 3424 %180 = OpIAdd %16 %178 %179 3425 %181 = OpAccessChain %17 %168 %204 %180 3426 %182 = OpLoad %16 %181 3427 %183 = OpAccessChain %17 %168 %204 %173 3428 OpStore %183 %182 3429 OpBranch %164 3430 %164 = OpLabel 3431 %185 = OpIAdd %16 %205 %44 3432 OpStore %160 %185 3433 OpBranch %161 3434 %163 = OpLabel 3435 OpBranch %156 3436 %156 = OpLabel 3437 %187 = OpIAdd %16 %204 %44 3438 OpStore %152 %187 3439 OpBranch %153 3440 %155 = OpLabel 3441 OpReturn 3442 OpFunctionEnd 3443 )"; 3444 3445 std::unique_ptr<IRContext> context = 3446 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, 3447 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 3448 ASSERT_NE(nullptr, context); 3449 Module* module = context->module(); 3450 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n" 3451 << text << std::endl; 3452 3453 { 3454 const Function* f = spvtest::GetFunction(module, 6); 3455 LoopDescriptor& ld = *context->GetLoopDescriptor(f); 3456 3457 const Instruction* store = nullptr; 3458 const Instruction* load = nullptr; 3459 3460 int block_id = 31; 3461 ASSERT_TRUE(spvtest::GetBasicBlock(f, block_id)); 3462 3463 for (const Instruction& inst : *spvtest::GetBasicBlock(f, block_id)) { 3464 if (inst.opcode() == SpvOp::SpvOpStore) { 3465 store = &inst; 3466 } 3467 3468 if (inst.opcode() == SpvOp::SpvOpLoad) { 3469 load = &inst; 3470 } 3471 } 3472 3473 EXPECT_NE(nullptr, store); 3474 EXPECT_NE(nullptr, load); 3475 3476 std::vector<const Loop*> loop_nest{&ld.GetLoopByIndex(0), 3477 &ld.GetLoopByIndex(1)}; 3478 LoopDependenceAnalysis analysis{context.get(), loop_nest}; 3479 3480 DistanceVector dv_entry(loop_nest.size()); 3481 3482 std::vector<DistanceEntry> expected_entries{ 3483 DistanceEntry(DistanceEntry::Directions::LT, 1), 3484 DistanceEntry(DistanceEntry::Directions::LT, 1)}; 3485 3486 DistanceVector expected_distance_vector(expected_entries); 3487 3488 auto is_independent = analysis.GetDependence(load, store, &dv_entry); 3489 3490 EXPECT_FALSE(is_independent); 3491 EXPECT_EQ(expected_distance_vector, dv_entry); 3492 } 3493 3494 { 3495 const Function* f = spvtest::GetFunction(module, 8); 3496 LoopDescriptor& ld = *context->GetLoopDescriptor(f); 3497 3498 const Instruction* store = nullptr; 3499 const Instruction* load = nullptr; 3500 3501 int block_id = 62; 3502 ASSERT_TRUE(spvtest::GetBasicBlock(f, block_id)); 3503 3504 for (const Instruction& inst : *spvtest::GetBasicBlock(f, block_id)) { 3505 if (inst.opcode() == SpvOp::SpvOpStore) { 3506 store = &inst; 3507 } 3508 3509 if (inst.opcode() == SpvOp::SpvOpLoad) { 3510 load = &inst; 3511 } 3512 } 3513 3514 EXPECT_NE(nullptr, store); 3515 EXPECT_NE(nullptr, load); 3516 3517 std::vector<const Loop*> loop_nest{&ld.GetLoopByIndex(0)}; 3518 LoopDependenceAnalysis analysis{context.get(), loop_nest}; 3519 3520 DistanceVector dv_entry(loop_nest.size()); 3521 auto is_independent = analysis.GetDependence(load, store, &dv_entry); 3522 3523 EXPECT_TRUE(is_independent); 3524 } 3525 3526 { 3527 const Function* f = spvtest::GetFunction(module, 10); 3528 LoopDescriptor& ld = *context->GetLoopDescriptor(f); 3529 3530 const Instruction* store = nullptr; 3531 const Instruction* load = nullptr; 3532 3533 int block_id = 84; 3534 ASSERT_TRUE(spvtest::GetBasicBlock(f, block_id)); 3535 3536 for (const Instruction& inst : *spvtest::GetBasicBlock(f, block_id)) { 3537 if (inst.opcode() == SpvOp::SpvOpStore) { 3538 store = &inst; 3539 } 3540 3541 if (inst.opcode() == SpvOp::SpvOpLoad) { 3542 load = &inst; 3543 } 3544 } 3545 3546 EXPECT_NE(nullptr, store); 3547 EXPECT_NE(nullptr, load); 3548 3549 std::vector<const Loop*> loop_nest{&ld.GetLoopByIndex(0)}; 3550 LoopDependenceAnalysis analysis{context.get(), loop_nest}; 3551 3552 DistanceVector dv_entry(loop_nest.size()); 3553 auto is_independent = analysis.GetDependence(load, store, &dv_entry); 3554 3555 DistanceVector expected_distance_vector({DistanceEntry(1, 2)}); 3556 3557 EXPECT_FALSE(is_independent); 3558 EXPECT_EQ(expected_distance_vector, dv_entry); 3559 } 3560 3561 { 3562 const Function* f = spvtest::GetFunction(module, 12); 3563 LoopDescriptor& ld = *context->GetLoopDescriptor(f); 3564 3565 const Instruction* store = nullptr; 3566 const Instruction* load = nullptr; 3567 3568 int block_id = 119; 3569 ASSERT_TRUE(spvtest::GetBasicBlock(f, block_id)); 3570 3571 for (const Instruction& inst : *spvtest::GetBasicBlock(f, block_id)) { 3572 if (inst.opcode() == SpvOp::SpvOpStore) { 3573 store = &inst; 3574 } 3575 3576 if (inst.opcode() == SpvOp::SpvOpLoad) { 3577 load = &inst; 3578 } 3579 } 3580 3581 EXPECT_NE(nullptr, store); 3582 EXPECT_NE(nullptr, load); 3583 3584 std::vector<const Loop*> loop_nest{ 3585 &ld.GetLoopByIndex(0), &ld.GetLoopByIndex(1), &ld.GetLoopByIndex(2)}; 3586 LoopDependenceAnalysis analysis{context.get(), loop_nest}; 3587 3588 DistanceVector dv_entry(loop_nest.size()); 3589 3590 std::vector<DistanceEntry> expected_entries{ 3591 DistanceEntry(DistanceEntry::Directions::LT, 1), 3592 DistanceEntry(DistanceEntry::Directions::LT, 1), 3593 DistanceEntry(DistanceEntry::Directions::GT, -1)}; 3594 3595 DistanceVector expected_distance_vector(expected_entries); 3596 3597 auto is_independent = analysis.GetDependence(store, load, &dv_entry); 3598 3599 EXPECT_FALSE(is_independent); 3600 EXPECT_EQ(expected_distance_vector, dv_entry); 3601 } 3602 3603 { 3604 const Function* f = spvtest::GetFunction(module, 14); 3605 LoopDescriptor& ld = *context->GetLoopDescriptor(f); 3606 3607 const Instruction* store = nullptr; 3608 const Instruction* load = nullptr; 3609 3610 int block_id = 162; 3611 ASSERT_TRUE(spvtest::GetBasicBlock(f, block_id)); 3612 3613 for (const Instruction& inst : *spvtest::GetBasicBlock(f, block_id)) { 3614 if (inst.opcode() == SpvOp::SpvOpStore) { 3615 store = &inst; 3616 } 3617 3618 if (inst.opcode() == SpvOp::SpvOpLoad) { 3619 load = &inst; 3620 } 3621 } 3622 3623 EXPECT_NE(nullptr, store); 3624 EXPECT_NE(nullptr, load); 3625 3626 std::vector<const Loop*> loop_nest{&ld.GetLoopByIndex(0), 3627 &ld.GetLoopByIndex(1)}; 3628 LoopDependenceAnalysis analysis{context.get(), loop_nest}; 3629 3630 DistanceVector dv_entry(loop_nest.size()); 3631 auto is_independent = analysis.GetDependence(load, store, &dv_entry); 3632 3633 EXPECT_TRUE(is_independent); 3634 } 3635 } 3636 3637 TEST(DependencyAnalysis, ConstraintIntersection) { 3638 LoopDependenceAnalysis analysis{nullptr, std::vector<const Loop*>{}}; 3639 auto scalar_evolution = analysis.GetScalarEvolution(); 3640 { 3641 // One is none. Other should be returned 3642 auto none = analysis.make_constraint<DependenceNone>(); 3643 auto x = scalar_evolution->CreateConstant(1); 3644 auto y = scalar_evolution->CreateConstant(10); 3645 auto point = analysis.make_constraint<DependencePoint>(x, y, nullptr); 3646 3647 auto ret_0 = analysis.IntersectConstraints(none, point, nullptr, nullptr); 3648 3649 auto ret_point_0 = ret_0->AsDependencePoint(); 3650 ASSERT_NE(nullptr, ret_point_0); 3651 EXPECT_EQ(*x, *ret_point_0->GetSource()); 3652 EXPECT_EQ(*y, *ret_point_0->GetDestination()); 3653 3654 auto ret_1 = analysis.IntersectConstraints(point, none, nullptr, nullptr); 3655 3656 auto ret_point_1 = ret_1->AsDependencePoint(); 3657 ASSERT_NE(nullptr, ret_point_1); 3658 EXPECT_EQ(*x, *ret_point_1->GetSource()); 3659 EXPECT_EQ(*y, *ret_point_1->GetDestination()); 3660 } 3661 3662 { 3663 // Both distances 3664 auto x = scalar_evolution->CreateConstant(1); 3665 auto y = scalar_evolution->CreateConstant(10); 3666 3667 auto distance_0 = analysis.make_constraint<DependenceDistance>(x, nullptr); 3668 auto distance_1 = analysis.make_constraint<DependenceDistance>(y, nullptr); 3669 3670 // Equal distances 3671 auto ret_0 = 3672 analysis.IntersectConstraints(distance_1, distance_1, nullptr, nullptr); 3673 3674 auto ret_distance = ret_0->AsDependenceDistance(); 3675 ASSERT_NE(nullptr, ret_distance); 3676 EXPECT_EQ(*y, *ret_distance->GetDistance()); 3677 3678 // Non-equal distances 3679 auto ret_1 = 3680 analysis.IntersectConstraints(distance_0, distance_1, nullptr, nullptr); 3681 EXPECT_NE(nullptr, ret_1->AsDependenceEmpty()); 3682 } 3683 3684 { 3685 // Both points 3686 auto x = scalar_evolution->CreateConstant(1); 3687 auto y = scalar_evolution->CreateConstant(10); 3688 3689 auto point_0 = analysis.make_constraint<DependencePoint>(x, y, nullptr); 3690 auto point_1 = analysis.make_constraint<DependencePoint>(x, y, nullptr); 3691 auto point_2 = analysis.make_constraint<DependencePoint>(y, y, nullptr); 3692 3693 // Equal points 3694 auto ret_0 = 3695 analysis.IntersectConstraints(point_0, point_1, nullptr, nullptr); 3696 auto ret_point_0 = ret_0->AsDependencePoint(); 3697 ASSERT_NE(nullptr, ret_point_0); 3698 EXPECT_EQ(*x, *ret_point_0->GetSource()); 3699 EXPECT_EQ(*y, *ret_point_0->GetDestination()); 3700 3701 // Non-equal points 3702 auto ret_1 = 3703 analysis.IntersectConstraints(point_0, point_2, nullptr, nullptr); 3704 EXPECT_NE(nullptr, ret_1->AsDependenceEmpty()); 3705 } 3706 3707 { 3708 // Both lines, parallel 3709 auto a0 = scalar_evolution->CreateConstant(3); 3710 auto b0 = scalar_evolution->CreateConstant(6); 3711 auto c0 = scalar_evolution->CreateConstant(9); 3712 3713 auto a1 = scalar_evolution->CreateConstant(6); 3714 auto b1 = scalar_evolution->CreateConstant(12); 3715 auto c1 = scalar_evolution->CreateConstant(18); 3716 3717 auto line_0 = analysis.make_constraint<DependenceLine>(a0, b0, c0, nullptr); 3718 auto line_1 = analysis.make_constraint<DependenceLine>(a1, b1, c1, nullptr); 3719 3720 // Same line, both ways 3721 auto ret_0 = 3722 analysis.IntersectConstraints(line_0, line_1, nullptr, nullptr); 3723 auto ret_1 = 3724 analysis.IntersectConstraints(line_1, line_0, nullptr, nullptr); 3725 3726 auto ret_line_0 = ret_0->AsDependenceLine(); 3727 auto ret_line_1 = ret_1->AsDependenceLine(); 3728 3729 EXPECT_NE(nullptr, ret_line_0); 3730 EXPECT_NE(nullptr, ret_line_1); 3731 3732 // Non-intersecting parallel lines 3733 auto c2 = scalar_evolution->CreateConstant(12); 3734 auto line_2 = analysis.make_constraint<DependenceLine>(a1, b1, c2, nullptr); 3735 3736 auto ret_2 = 3737 analysis.IntersectConstraints(line_0, line_2, nullptr, nullptr); 3738 auto ret_3 = 3739 analysis.IntersectConstraints(line_2, line_0, nullptr, nullptr); 3740 3741 EXPECT_NE(nullptr, ret_2->AsDependenceEmpty()); 3742 EXPECT_NE(nullptr, ret_3->AsDependenceEmpty()); 3743 3744 auto c3 = scalar_evolution->CreateConstant(20); 3745 auto line_3 = analysis.make_constraint<DependenceLine>(a1, b1, c3, nullptr); 3746 3747 auto ret_4 = 3748 analysis.IntersectConstraints(line_0, line_3, nullptr, nullptr); 3749 auto ret_5 = 3750 analysis.IntersectConstraints(line_3, line_0, nullptr, nullptr); 3751 3752 EXPECT_NE(nullptr, ret_4->AsDependenceEmpty()); 3753 EXPECT_NE(nullptr, ret_5->AsDependenceEmpty()); 3754 } 3755 3756 { 3757 // Non-constant line 3758 auto unknown = scalar_evolution->CreateCantComputeNode(); 3759 auto constant = scalar_evolution->CreateConstant(10); 3760 3761 auto line_0 = analysis.make_constraint<DependenceLine>(constant, constant, 3762 constant, nullptr); 3763 auto line_1 = analysis.make_constraint<DependenceLine>(unknown, unknown, 3764 unknown, nullptr); 3765 3766 auto ret_0 = 3767 analysis.IntersectConstraints(line_0, line_1, nullptr, nullptr); 3768 auto ret_1 = 3769 analysis.IntersectConstraints(line_1, line_0, nullptr, nullptr); 3770 3771 EXPECT_NE(nullptr, ret_0->AsDependenceNone()); 3772 EXPECT_NE(nullptr, ret_1->AsDependenceNone()); 3773 } 3774 3775 { 3776 auto bound_0 = scalar_evolution->CreateConstant(0); 3777 auto bound_1 = scalar_evolution->CreateConstant(20); 3778 3779 auto a0 = scalar_evolution->CreateConstant(1); 3780 auto b0 = scalar_evolution->CreateConstant(2); 3781 auto c0 = scalar_evolution->CreateConstant(6); 3782 3783 auto a1 = scalar_evolution->CreateConstant(-1); 3784 auto b1 = scalar_evolution->CreateConstant(2); 3785 auto c1 = scalar_evolution->CreateConstant(2); 3786 3787 auto line_0 = analysis.make_constraint<DependenceLine>(a0, b0, c0, nullptr); 3788 auto line_1 = analysis.make_constraint<DependenceLine>(a1, b1, c1, nullptr); 3789 3790 // Intersecting lines, has integer solution, in bounds 3791 auto ret_0 = 3792 analysis.IntersectConstraints(line_0, line_1, bound_0, bound_1); 3793 auto ret_1 = 3794 analysis.IntersectConstraints(line_1, line_0, bound_0, bound_1); 3795 3796 auto ret_point_0 = ret_0->AsDependencePoint(); 3797 auto ret_point_1 = ret_1->AsDependencePoint(); 3798 3799 EXPECT_NE(nullptr, ret_point_0); 3800 EXPECT_NE(nullptr, ret_point_1); 3801 3802 auto const_2 = scalar_evolution->CreateConstant(2); 3803 3804 EXPECT_EQ(*const_2, *ret_point_0->GetSource()); 3805 EXPECT_EQ(*const_2, *ret_point_0->GetDestination()); 3806 3807 EXPECT_EQ(*const_2, *ret_point_1->GetSource()); 3808 EXPECT_EQ(*const_2, *ret_point_1->GetDestination()); 3809 3810 // Intersecting lines, has integer solution, out of bounds 3811 auto ret_2 = 3812 analysis.IntersectConstraints(line_0, line_1, bound_0, bound_0); 3813 auto ret_3 = 3814 analysis.IntersectConstraints(line_1, line_0, bound_0, bound_0); 3815 3816 EXPECT_NE(nullptr, ret_2->AsDependenceEmpty()); 3817 EXPECT_NE(nullptr, ret_3->AsDependenceEmpty()); 3818 3819 auto a2 = scalar_evolution->CreateConstant(-4); 3820 auto b2 = scalar_evolution->CreateConstant(1); 3821 auto c2 = scalar_evolution->CreateConstant(0); 3822 3823 auto a3 = scalar_evolution->CreateConstant(4); 3824 auto b3 = scalar_evolution->CreateConstant(1); 3825 auto c3 = scalar_evolution->CreateConstant(4); 3826 3827 auto line_2 = analysis.make_constraint<DependenceLine>(a2, b2, c2, nullptr); 3828 auto line_3 = analysis.make_constraint<DependenceLine>(a3, b3, c3, nullptr); 3829 3830 // Intersecting, no integer solution 3831 auto ret_4 = 3832 analysis.IntersectConstraints(line_2, line_3, bound_0, bound_1); 3833 auto ret_5 = 3834 analysis.IntersectConstraints(line_3, line_2, bound_0, bound_1); 3835 3836 EXPECT_NE(nullptr, ret_4->AsDependenceEmpty()); 3837 EXPECT_NE(nullptr, ret_5->AsDependenceEmpty()); 3838 3839 auto unknown = scalar_evolution->CreateCantComputeNode(); 3840 3841 // Non-constant bound 3842 auto ret_6 = 3843 analysis.IntersectConstraints(line_0, line_1, unknown, bound_1); 3844 auto ret_7 = 3845 analysis.IntersectConstraints(line_1, line_0, bound_0, unknown); 3846 3847 EXPECT_NE(nullptr, ret_6->AsDependenceNone()); 3848 EXPECT_NE(nullptr, ret_7->AsDependenceNone()); 3849 } 3850 3851 { 3852 auto constant_0 = scalar_evolution->CreateConstant(0); 3853 auto constant_1 = scalar_evolution->CreateConstant(1); 3854 auto constant_neg_1 = scalar_evolution->CreateConstant(-1); 3855 auto constant_2 = scalar_evolution->CreateConstant(2); 3856 auto constant_neg_2 = scalar_evolution->CreateConstant(-2); 3857 3858 auto point_0_0 = analysis.make_constraint<DependencePoint>( 3859 constant_0, constant_0, nullptr); 3860 auto point_0_1 = analysis.make_constraint<DependencePoint>( 3861 constant_0, constant_1, nullptr); 3862 auto point_1_0 = analysis.make_constraint<DependencePoint>( 3863 constant_1, constant_0, nullptr); 3864 auto point_1_1 = analysis.make_constraint<DependencePoint>( 3865 constant_1, constant_1, nullptr); 3866 auto point_1_2 = analysis.make_constraint<DependencePoint>( 3867 constant_1, constant_2, nullptr); 3868 auto point_1_neg_1 = analysis.make_constraint<DependencePoint>( 3869 constant_1, constant_neg_1, nullptr); 3870 auto point_neg_1_1 = analysis.make_constraint<DependencePoint>( 3871 constant_neg_1, constant_1, nullptr); 3872 3873 auto line_y_0 = analysis.make_constraint<DependenceLine>( 3874 constant_0, constant_1, constant_0, nullptr); 3875 auto line_y_1 = analysis.make_constraint<DependenceLine>( 3876 constant_0, constant_1, constant_1, nullptr); 3877 auto line_y_2 = analysis.make_constraint<DependenceLine>( 3878 constant_0, constant_1, constant_2, nullptr); 3879 3880 // Parallel horizontal lines, y = 0 & y = 1, should return no intersection 3881 auto ret = 3882 analysis.IntersectConstraints(line_y_0, line_y_1, nullptr, nullptr); 3883 3884 EXPECT_NE(nullptr, ret->AsDependenceEmpty()); 3885 3886 // Parallel horizontal lines, y = 1 & y = 2, should return no intersection 3887 auto ret_y_12 = 3888 analysis.IntersectConstraints(line_y_1, line_y_2, nullptr, nullptr); 3889 3890 EXPECT_NE(nullptr, ret_y_12->AsDependenceEmpty()); 3891 3892 // Same horizontal lines, y = 0 & y = 0, should return the line 3893 auto ret_y_same_0 = 3894 analysis.IntersectConstraints(line_y_0, line_y_0, nullptr, nullptr); 3895 3896 EXPECT_NE(nullptr, ret_y_same_0->AsDependenceLine()); 3897 3898 // Same horizontal lines, y = 1 & y = 1, should return the line 3899 auto ret_y_same_1 = 3900 analysis.IntersectConstraints(line_y_1, line_y_1, nullptr, nullptr); 3901 3902 EXPECT_NE(nullptr, ret_y_same_1->AsDependenceLine()); 3903 3904 auto line_x_0 = analysis.make_constraint<DependenceLine>( 3905 constant_1, constant_0, constant_0, nullptr); 3906 auto line_x_1 = analysis.make_constraint<DependenceLine>( 3907 constant_1, constant_0, constant_1, nullptr); 3908 auto line_x_2 = analysis.make_constraint<DependenceLine>( 3909 constant_1, constant_0, constant_2, nullptr); 3910 auto line_2x_1 = analysis.make_constraint<DependenceLine>( 3911 constant_2, constant_0, constant_1, nullptr); 3912 auto line_2x_2 = analysis.make_constraint<DependenceLine>( 3913 constant_2, constant_0, constant_2, nullptr); 3914 3915 // Parallel vertical lines, x = 0 & x = 1, should return no intersection 3916 auto ret_x = 3917 analysis.IntersectConstraints(line_x_0, line_x_1, nullptr, nullptr); 3918 3919 EXPECT_NE(nullptr, ret_x->AsDependenceEmpty()); 3920 3921 // Parallel vertical lines, x = 1 & x = 2, should return no intersection 3922 auto ret_x_12 = 3923 analysis.IntersectConstraints(line_x_1, line_x_2, nullptr, nullptr); 3924 3925 EXPECT_NE(nullptr, ret_x_12->AsDependenceEmpty()); 3926 3927 // Parallel vertical lines, 2x = 1 & 2x = 2, should return no intersection 3928 auto ret_2x_2_2x_1 = 3929 analysis.IntersectConstraints(line_2x_2, line_2x_1, nullptr, nullptr); 3930 3931 EXPECT_NE(nullptr, ret_2x_2_2x_1->AsDependenceEmpty()); 3932 3933 // same line, 2x=2 & x = 1 3934 auto ret_2x_2_x_1 = 3935 analysis.IntersectConstraints(line_2x_2, line_x_1, nullptr, nullptr); 3936 3937 EXPECT_NE(nullptr, ret_2x_2_x_1->AsDependenceLine()); 3938 3939 // Same vertical lines, x = 0 & x = 0, should return the line 3940 auto ret_x_same_0 = 3941 analysis.IntersectConstraints(line_x_0, line_x_0, nullptr, nullptr); 3942 3943 EXPECT_NE(nullptr, ret_x_same_0->AsDependenceLine()); 3944 // EXPECT_EQ(*line_x_0, *ret_x_same_0->AsDependenceLine()); 3945 3946 // Same vertical lines, x = 1 & x = 1, should return the line 3947 auto ret_x_same_1 = 3948 analysis.IntersectConstraints(line_x_1, line_x_1, nullptr, nullptr); 3949 3950 EXPECT_NE(nullptr, ret_x_same_1->AsDependenceLine()); 3951 EXPECT_EQ(*line_x_1, *ret_x_same_1->AsDependenceLine()); 3952 3953 // x=1 & y = 0, intersect at (1, 0) 3954 auto ret_1_0 = analysis.IntersectConstraints(line_x_1, line_y_0, 3955 constant_neg_1, constant_2); 3956 3957 auto ret_point_1_0 = ret_1_0->AsDependencePoint(); 3958 EXPECT_NE(nullptr, ret_point_1_0); 3959 EXPECT_EQ(*point_1_0, *ret_point_1_0); 3960 3961 // x=1 & y = 1, intersect at (1, 1) 3962 auto ret_1_1 = analysis.IntersectConstraints(line_x_1, line_y_1, 3963 constant_neg_1, constant_2); 3964 3965 auto ret_point_1_1 = ret_1_1->AsDependencePoint(); 3966 EXPECT_NE(nullptr, ret_point_1_1); 3967 EXPECT_EQ(*point_1_1, *ret_point_1_1); 3968 3969 // x=0 & y = 0, intersect at (0, 0) 3970 auto ret_0_0 = analysis.IntersectConstraints(line_x_0, line_y_0, 3971 constant_neg_1, constant_2); 3972 3973 auto ret_point_0_0 = ret_0_0->AsDependencePoint(); 3974 EXPECT_NE(nullptr, ret_point_0_0); 3975 EXPECT_EQ(*point_0_0, *ret_point_0_0); 3976 3977 // x=0 & y = 1, intersect at (0, 1) 3978 auto ret_0_1 = analysis.IntersectConstraints(line_x_0, line_y_1, 3979 constant_neg_1, constant_2); 3980 auto ret_point_0_1 = ret_0_1->AsDependencePoint(); 3981 EXPECT_NE(nullptr, ret_point_0_1); 3982 EXPECT_EQ(*point_0_1, *ret_point_0_1); 3983 3984 // x = 1 & y = 2 3985 auto ret_1_2 = analysis.IntersectConstraints(line_x_1, line_y_2, 3986 constant_neg_1, constant_2); 3987 auto ret_point_1_2 = ret_1_2->AsDependencePoint(); 3988 EXPECT_NE(nullptr, ret_point_1_2); 3989 EXPECT_EQ(*point_1_2, *ret_point_1_2); 3990 3991 auto line_x_y_0 = analysis.make_constraint<DependenceLine>( 3992 constant_1, constant_1, constant_0, nullptr); 3993 auto line_x_y_1 = analysis.make_constraint<DependenceLine>( 3994 constant_1, constant_1, constant_1, nullptr); 3995 3996 // x+y=0 & x=0, intersect (0, 0) 3997 auto ret_xy_0_x_0 = analysis.IntersectConstraints( 3998 line_x_y_0, line_x_0, constant_neg_1, constant_2); 3999 4000 EXPECT_NE(nullptr, ret_xy_0_x_0->AsDependencePoint()); 4001 EXPECT_EQ(*point_0_0, *ret_xy_0_x_0); 4002 4003 // x+y=0 & y=0, intersect (0, 0) 4004 auto ret_xy_0_y_0 = analysis.IntersectConstraints( 4005 line_x_y_0, line_y_0, constant_neg_1, constant_2); 4006 4007 EXPECT_NE(nullptr, ret_xy_0_y_0->AsDependencePoint()); 4008 EXPECT_EQ(*point_0_0, *ret_xy_0_y_0); 4009 4010 // x+y=0 & x=1, intersect (1, -1) 4011 auto ret_xy_0_x_1 = analysis.IntersectConstraints( 4012 line_x_y_0, line_x_1, constant_neg_2, constant_2); 4013 4014 EXPECT_NE(nullptr, ret_xy_0_x_1->AsDependencePoint()); 4015 EXPECT_EQ(*point_1_neg_1, *ret_xy_0_x_1); 4016 4017 // x+y=0 & y=1, intersect (-1, 1) 4018 auto ret_xy_0_y_1 = analysis.IntersectConstraints( 4019 line_x_y_0, line_y_1, constant_neg_2, constant_2); 4020 4021 EXPECT_NE(nullptr, ret_xy_0_y_1->AsDependencePoint()); 4022 EXPECT_EQ(*point_neg_1_1, *ret_xy_0_y_1); 4023 4024 // x=0 & x+y=0, intersect (0, 0) 4025 auto ret_x_0_xy_0 = analysis.IntersectConstraints( 4026 line_x_0, line_x_y_0, constant_neg_1, constant_2); 4027 4028 EXPECT_NE(nullptr, ret_x_0_xy_0->AsDependencePoint()); 4029 EXPECT_EQ(*point_0_0, *ret_x_0_xy_0); 4030 4031 // y=0 & x+y=0, intersect (0, 0) 4032 auto ret_y_0_xy_0 = analysis.IntersectConstraints( 4033 line_y_0, line_x_y_0, constant_neg_1, constant_2); 4034 4035 EXPECT_NE(nullptr, ret_y_0_xy_0->AsDependencePoint()); 4036 EXPECT_EQ(*point_0_0, *ret_y_0_xy_0); 4037 4038 // x=1 & x+y=0, intersect (1, -1) 4039 auto ret_x_1_xy_0 = analysis.IntersectConstraints( 4040 line_x_1, line_x_y_0, constant_neg_2, constant_2); 4041 4042 EXPECT_NE(nullptr, ret_x_1_xy_0->AsDependencePoint()); 4043 EXPECT_EQ(*point_1_neg_1, *ret_x_1_xy_0); 4044 4045 // y=1 & x+y=0, intersect (-1, 1) 4046 auto ret_y_1_xy_0 = analysis.IntersectConstraints( 4047 line_y_1, line_x_y_0, constant_neg_2, constant_2); 4048 4049 EXPECT_NE(nullptr, ret_y_1_xy_0->AsDependencePoint()); 4050 EXPECT_EQ(*point_neg_1_1, *ret_y_1_xy_0); 4051 4052 // x+y=1 & x=0, intersect (0, 1) 4053 auto ret_xy_1_x_0 = analysis.IntersectConstraints( 4054 line_x_y_1, line_x_0, constant_neg_1, constant_2); 4055 4056 EXPECT_NE(nullptr, ret_xy_1_x_0->AsDependencePoint()); 4057 EXPECT_EQ(*point_0_1, *ret_xy_1_x_0); 4058 4059 // x+y=1 & y=0, intersect (1, 0) 4060 auto ret_xy_1_y_0 = analysis.IntersectConstraints( 4061 line_x_y_1, line_y_0, constant_neg_1, constant_2); 4062 4063 EXPECT_NE(nullptr, ret_xy_1_y_0->AsDependencePoint()); 4064 EXPECT_EQ(*point_1_0, *ret_xy_1_y_0); 4065 4066 // x+y=1 & x=1, intersect (1, 0) 4067 auto ret_xy_1_x_1 = analysis.IntersectConstraints( 4068 line_x_y_1, line_x_1, constant_neg_1, constant_2); 4069 4070 EXPECT_NE(nullptr, ret_xy_1_x_1->AsDependencePoint()); 4071 EXPECT_EQ(*point_1_0, *ret_xy_1_x_1); 4072 4073 // x+y=1 & y=1, intersect (0, 1) 4074 auto ret_xy_1_y_1 = analysis.IntersectConstraints( 4075 line_x_y_1, line_y_1, constant_neg_1, constant_2); 4076 4077 EXPECT_NE(nullptr, ret_xy_1_y_1->AsDependencePoint()); 4078 EXPECT_EQ(*point_0_1, *ret_xy_1_y_1); 4079 4080 // x=0 & x+y=1, intersect (0, 1) 4081 auto ret_x_0_xy_1 = analysis.IntersectConstraints( 4082 line_x_0, line_x_y_1, constant_neg_1, constant_2); 4083 4084 EXPECT_NE(nullptr, ret_x_0_xy_1->AsDependencePoint()); 4085 EXPECT_EQ(*point_0_1, *ret_x_0_xy_1); 4086 4087 // y=0 & x+y=1, intersect (1, 0) 4088 auto ret_y_0_xy_1 = analysis.IntersectConstraints( 4089 line_y_0, line_x_y_1, constant_neg_1, constant_2); 4090 4091 EXPECT_NE(nullptr, ret_y_0_xy_1->AsDependencePoint()); 4092 EXPECT_EQ(*point_1_0, *ret_y_0_xy_1); 4093 4094 // x=1 & x+y=1, intersect (1, 0) 4095 auto ret_x_1_xy_1 = analysis.IntersectConstraints( 4096 line_x_1, line_x_y_1, constant_neg_2, constant_2); 4097 4098 EXPECT_NE(nullptr, ret_x_1_xy_1->AsDependencePoint()); 4099 EXPECT_EQ(*point_1_0, *ret_x_1_xy_1); 4100 4101 // y=1 & x+y=1, intersect (0, 1) 4102 auto ret_y_1_xy_1 = analysis.IntersectConstraints( 4103 line_y_1, line_x_y_1, constant_neg_2, constant_2); 4104 4105 EXPECT_NE(nullptr, ret_y_1_xy_1->AsDependencePoint()); 4106 EXPECT_EQ(*point_0_1, *ret_y_1_xy_1); 4107 } 4108 4109 { 4110 // Line and point 4111 auto a = scalar_evolution->CreateConstant(3); 4112 auto b = scalar_evolution->CreateConstant(10); 4113 auto c = scalar_evolution->CreateConstant(16); 4114 4115 auto line = analysis.make_constraint<DependenceLine>(a, b, c, nullptr); 4116 4117 // Point on line 4118 auto x = scalar_evolution->CreateConstant(2); 4119 auto y = scalar_evolution->CreateConstant(1); 4120 auto point_0 = analysis.make_constraint<DependencePoint>(x, y, nullptr); 4121 4122 auto ret_0 = analysis.IntersectConstraints(line, point_0, nullptr, nullptr); 4123 auto ret_1 = analysis.IntersectConstraints(point_0, line, nullptr, nullptr); 4124 4125 auto ret_point_0 = ret_0->AsDependencePoint(); 4126 auto ret_point_1 = ret_1->AsDependencePoint(); 4127 ASSERT_NE(nullptr, ret_point_0); 4128 ASSERT_NE(nullptr, ret_point_1); 4129 4130 EXPECT_EQ(*x, *ret_point_0->GetSource()); 4131 EXPECT_EQ(*y, *ret_point_0->GetDestination()); 4132 4133 EXPECT_EQ(*x, *ret_point_1->GetSource()); 4134 EXPECT_EQ(*y, *ret_point_1->GetDestination()); 4135 4136 // Point not on line 4137 auto point_1 = analysis.make_constraint<DependencePoint>(a, a, nullptr); 4138 4139 auto ret_2 = analysis.IntersectConstraints(line, point_1, nullptr, nullptr); 4140 auto ret_3 = analysis.IntersectConstraints(point_1, line, nullptr, nullptr); 4141 4142 EXPECT_NE(nullptr, ret_2->AsDependenceEmpty()); 4143 EXPECT_NE(nullptr, ret_3->AsDependenceEmpty()); 4144 4145 // Non-constant 4146 auto unknown = scalar_evolution->CreateCantComputeNode(); 4147 4148 auto point_2 = 4149 analysis.make_constraint<DependencePoint>(unknown, x, nullptr); 4150 4151 auto ret_4 = analysis.IntersectConstraints(line, point_2, nullptr, nullptr); 4152 auto ret_5 = analysis.IntersectConstraints(point_2, line, nullptr, nullptr); 4153 4154 EXPECT_NE(nullptr, ret_4->AsDependenceNone()); 4155 EXPECT_NE(nullptr, ret_5->AsDependenceNone()); 4156 } 4157 4158 { 4159 // Distance and point 4160 auto d = scalar_evolution->CreateConstant(5); 4161 auto distance = analysis.make_constraint<DependenceDistance>(d, nullptr); 4162 4163 // Point on line 4164 auto x = scalar_evolution->CreateConstant(10); 4165 auto point_0 = analysis.make_constraint<DependencePoint>(d, x, nullptr); 4166 4167 auto ret_0 = 4168 analysis.IntersectConstraints(distance, point_0, nullptr, nullptr); 4169 auto ret_1 = 4170 analysis.IntersectConstraints(point_0, distance, nullptr, nullptr); 4171 4172 auto ret_point_0 = ret_0->AsDependencePoint(); 4173 auto ret_point_1 = ret_1->AsDependencePoint(); 4174 ASSERT_NE(nullptr, ret_point_0); 4175 ASSERT_NE(nullptr, ret_point_1); 4176 4177 // Point not on line 4178 auto point_1 = analysis.make_constraint<DependencePoint>(x, x, nullptr); 4179 4180 auto ret_2 = 4181 analysis.IntersectConstraints(distance, point_1, nullptr, nullptr); 4182 auto ret_3 = 4183 analysis.IntersectConstraints(point_1, distance, nullptr, nullptr); 4184 4185 EXPECT_NE(nullptr, ret_2->AsDependenceEmpty()); 4186 EXPECT_NE(nullptr, ret_3->AsDependenceEmpty()); 4187 4188 // Non-constant 4189 auto unknown = scalar_evolution->CreateCantComputeNode(); 4190 auto unknown_distance = 4191 analysis.make_constraint<DependenceDistance>(unknown, nullptr); 4192 4193 auto ret_4 = analysis.IntersectConstraints(unknown_distance, point_1, 4194 nullptr, nullptr); 4195 auto ret_5 = analysis.IntersectConstraints(point_1, unknown_distance, 4196 nullptr, nullptr); 4197 4198 EXPECT_NE(nullptr, ret_4->AsDependenceNone()); 4199 EXPECT_NE(nullptr, ret_5->AsDependenceNone()); 4200 } 4201 } 4202 4203 } // namespace 4204 } // namespace opt 4205 } // namespace spvtools 4206