1// Copyright (c) 2017 Google Inc. 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 <string> 16 17#include "source/opt/scalar_replacement_pass.h" 18#include "test/opt/assembly_builder.h" 19#include "test/opt/pass_fixture.h" 20#include "test/opt/pass_utils.h" 21 22namespace spvtools { 23namespace opt { 24namespace { 25 26using ScalarReplacementPassName = ::testing::Test; 27 28TEST_F(ScalarReplacementPassName, Default) { 29 auto srp = ScalarReplacementPass(); 30 EXPECT_STREQ(srp.name(), "scalar-replacement=100"); 31} 32 33TEST_F(ScalarReplacementPassName, Large) { 34 auto srp = ScalarReplacementPass(0xffffffffu); 35 EXPECT_STREQ(srp.name(), "scalar-replacement=4294967295"); 36} 37 38using ScalarReplacementTest = PassTest<::testing::Test>; 39 40TEST_F(ScalarReplacementTest, SimpleStruct) { 41 const std::string text = R"( 42; 43; CHECK: [[struct:%\w+]] = OpTypeStruct [[elem:%\w+]] 44; CHECK: [[struct_ptr:%\w+]] = OpTypePointer Function [[struct]] 45; CHECK: [[elem_ptr:%\w+]] = OpTypePointer Function [[elem]] 46; CHECK: OpConstantNull [[struct]] 47; CHECK: [[null:%\w+]] = OpConstantNull [[elem]] 48; CHECK-NOT: OpVariable [[struct_ptr]] 49; CHECK: [[one:%\w+]] = OpVariable [[elem_ptr]] Function [[null]] 50; CHECK-NEXT: [[two:%\w+]] = OpVariable [[elem_ptr]] Function [[null]] 51; CHECK-NOT: OpVariable [[elem_ptr]] Function [[null]] 52; CHECK-NOT: OpVariable [[struct_ptr]] 53; CHECK-NOT: OpInBoundsAccessChain 54; CHECK: [[l1:%\w+]] = OpLoad [[elem]] [[two]] 55; CHECK-NOT: OpAccessChain 56; CHECK: [[l2:%\w+]] = OpLoad [[elem]] [[one]] 57; CHECK: OpIAdd [[elem]] [[l1]] [[l2]] 58; 59OpCapability Shader 60OpCapability Linkage 61OpMemoryModel Logical GLSL450 62OpName %6 "simple_struct" 63%1 = OpTypeVoid 64%2 = OpTypeInt 32 0 65%3 = OpTypeStruct %2 %2 %2 %2 66%4 = OpTypePointer Function %3 67%5 = OpTypePointer Function %2 68%6 = OpTypeFunction %2 69%7 = OpConstantNull %3 70%8 = OpConstant %2 0 71%9 = OpConstant %2 1 72%10 = OpConstant %2 2 73%11 = OpConstant %2 3 74%12 = OpFunction %2 None %6 75%13 = OpLabel 76%14 = OpVariable %4 Function %7 77%15 = OpInBoundsAccessChain %5 %14 %8 78%16 = OpLoad %2 %15 79%17 = OpAccessChain %5 %14 %10 80%18 = OpLoad %2 %17 81%19 = OpIAdd %2 %16 %18 82OpReturnValue %19 83OpFunctionEnd 84 )"; 85 86 SinglePassRunAndMatch<ScalarReplacementPass>(text, true); 87} 88 89TEST_F(ScalarReplacementTest, StructInitialization) { 90 const std::string text = R"( 91; 92; CHECK: [[elem:%\w+]] = OpTypeInt 32 0 93; CHECK: [[struct:%\w+]] = OpTypeStruct [[elem]] [[elem]] [[elem]] [[elem]] 94; CHECK: [[struct_ptr:%\w+]] = OpTypePointer Function [[struct]] 95; CHECK: [[elem_ptr:%\w+]] = OpTypePointer Function [[elem]] 96; CHECK: [[zero:%\w+]] = OpConstant [[elem]] 0 97; CHECK: [[undef:%\w+]] = OpUndef [[elem]] 98; CHECK: [[two:%\w+]] = OpConstant [[elem]] 2 99; CHECK: [[null:%\w+]] = OpConstantNull [[elem]] 100; CHECK-NOT: OpVariable [[struct_ptr]] 101; CHECK: OpVariable [[elem_ptr]] Function [[null]] 102; CHECK-NEXT: OpVariable [[elem_ptr]] Function [[two]] 103; CHECK-NOT: OpVariable [[elem_ptr]] Function [[undef]] 104; CHECK-NEXT: OpVariable [[elem_ptr]] Function 105; CHECK-NEXT: OpVariable [[elem_ptr]] Function [[zero]] 106; CHECK-NOT: OpVariable [[elem_ptr]] Function [[undef]] 107; 108OpCapability Shader 109OpCapability Linkage 110OpMemoryModel Logical GLSL450 111OpName %6 "struct_init" 112%1 = OpTypeVoid 113%2 = OpTypeInt 32 0 114%3 = OpTypeStruct %2 %2 %2 %2 115%4 = OpTypePointer Function %3 116%20 = OpTypePointer Function %2 117%6 = OpTypeFunction %1 118%7 = OpConstant %2 0 119%8 = OpUndef %2 120%9 = OpConstant %2 2 121%30 = OpConstant %2 1 122%31 = OpConstant %2 3 123%10 = OpConstantNull %2 124%11 = OpConstantComposite %3 %7 %8 %9 %10 125%12 = OpFunction %1 None %6 126%13 = OpLabel 127%14 = OpVariable %4 Function %11 128%15 = OpAccessChain %20 %14 %7 129OpStore %15 %10 130%16 = OpAccessChain %20 %14 %9 131OpStore %16 %10 132%17 = OpAccessChain %20 %14 %30 133OpStore %17 %10 134%18 = OpAccessChain %20 %14 %31 135OpStore %18 %10 136OpReturn 137OpFunctionEnd 138 )"; 139 140 SinglePassRunAndMatch<ScalarReplacementPass>(text, true); 141} 142 143TEST_F(ScalarReplacementTest, SpecConstantInitialization) { 144 const std::string text = R"( 145; 146; CHECK: [[int:%\w+]] = OpTypeInt 32 0 147; CHECK: [[struct:%\w+]] = OpTypeStruct [[int]] [[int]] 148; CHECK: [[struct_ptr:%\w+]] = OpTypePointer Function [[struct]] 149; CHECK: [[int_ptr:%\w+]] = OpTypePointer Function [[int]] 150; CHECK: [[spec_comp:%\w+]] = OpSpecConstantComposite [[struct]] 151; CHECK: [[ex0:%\w+]] = OpSpecConstantOp [[int]] CompositeExtract [[spec_comp]] 0 152; CHECK: [[ex1:%\w+]] = OpSpecConstantOp [[int]] CompositeExtract [[spec_comp]] 1 153; CHECK-NOT: OpVariable [[struct]] 154; CHECK: OpVariable [[int_ptr]] Function [[ex1]] 155; CHECK-NEXT: OpVariable [[int_ptr]] Function [[ex0]] 156; CHECK-NOT: OpVariable [[struct]] 157; 158OpCapability Shader 159OpCapability Linkage 160OpMemoryModel Logical GLSL450 161OpName %6 "spec_const" 162%1 = OpTypeVoid 163%2 = OpTypeInt 32 0 164%3 = OpTypeStruct %2 %2 165%4 = OpTypePointer Function %3 166%20 = OpTypePointer Function %2 167%5 = OpTypeFunction %1 168%6 = OpConstant %2 0 169%30 = OpConstant %2 1 170%7 = OpSpecConstant %2 0 171%8 = OpSpecConstantOp %2 IAdd %7 %7 172%9 = OpSpecConstantComposite %3 %7 %8 173%10 = OpFunction %1 None %5 174%11 = OpLabel 175%12 = OpVariable %4 Function %9 176%13 = OpAccessChain %20 %12 %6 177%14 = OpLoad %2 %13 178%15 = OpAccessChain %20 %12 %30 179%16 = OpLoad %2 %15 180OpReturn 181OpFunctionEnd 182 )"; 183 184 SinglePassRunAndMatch<ScalarReplacementPass>(text, true); 185} 186 187// TODO(alanbaker): Re-enable when vector and matrix scalarization is supported. 188// TEST_F(ScalarReplacementTest, VectorInitialization) { 189// const std::string text = R"( 190// ; 191// ; CHECK: [[elem:%\w+]] = OpTypeInt 32 0 192// ; CHECK: [[vector:%\w+]] = OpTypeVector [[elem]] 4 193// ; CHECK: [[vector_ptr:%\w+]] = OpTypePointer Function [[vector]] 194// ; CHECK: [[elem_ptr:%\w+]] = OpTypePointer Function [[elem]] 195// ; CHECK: [[zero:%\w+]] = OpConstant [[elem]] 0 196// ; CHECK: [[undef:%\w+]] = OpUndef [[elem]] 197// ; CHECK: [[two:%\w+]] = OpConstant [[elem]] 2 198// ; CHECK: [[null:%\w+]] = OpConstantNull [[elem]] 199// ; CHECK-NOT: OpVariable [[vector_ptr]] 200// ; CHECK: OpVariable [[elem_ptr]] Function [[zero]] 201// ; CHECK-NOT: OpVariable [[elem_ptr]] Function [[undef]] 202// ; CHECK-NEXT: OpVariable [[elem_ptr]] Function 203// ; CHECK-NEXT: OpVariable [[elem_ptr]] Function [[two]] 204// ; CHECK-NEXT: OpVariable [[elem_ptr]] Function [[null]] 205// ; CHECK-NOT: OpVariable [[elem_ptr]] Function [[undef]] 206// ; 207// OpCapability Shader 208// OpCapability Linkage 209// OpMemoryModel Logical GLSL450 210// OpName %6 "vector_init" 211// %1 = OpTypeVoid 212// %2 = OpTypeInt 32 0 213// %3 = OpTypeVector %2 4 214// %4 = OpTypePointer Function %3 215// %20 = OpTypePointer Function %2 216// %6 = OpTypeFunction %1 217// %7 = OpConstant %2 0 218// %8 = OpUndef %2 219// %9 = OpConstant %2 2 220// %30 = OpConstant %2 1 221// %31 = OpConstant %2 3 222// %10 = OpConstantNull %2 223// %11 = OpConstantComposite %3 %10 %9 %8 %7 224// %12 = OpFunction %1 None %6 225// %13 = OpLabel 226// %14 = OpVariable %4 Function %11 227// %15 = OpAccessChain %20 %14 %7 228// OpStore %15 %10 229// %16 = OpAccessChain %20 %14 %9 230// OpStore %16 %10 231// %17 = OpAccessChain %20 %14 %30 232// OpStore %17 %10 233// %18 = OpAccessChain %20 %14 %31 234// OpStore %18 %10 235// OpReturn 236// OpFunctionEnd 237// )"; 238// 239// SinglePassRunAndMatch<opt::ScalarReplacementPass>(text, true); 240// } 241// 242// TEST_F(ScalarReplacementTest, MatrixInitialization) { 243// const std::string text = R"( 244// ; 245// ; CHECK: [[float:%\w+]] = OpTypeFloat 32 246// ; CHECK: [[vector:%\w+]] = OpTypeVector [[float]] 2 247// ; CHECK: [[matrix:%\w+]] = OpTypeMatrix [[vector]] 2 248// ; CHECK: [[matrix_ptr:%\w+]] = OpTypePointer Function [[matrix]] 249// ; CHECK: [[float_ptr:%\w+]] = OpTypePointer Function [[float]] 250// ; CHECK: [[vec_ptr:%\w+]] = OpTypePointer Function [[vector]] 251// ; CHECK: [[zerof:%\w+]] = OpConstant [[float]] 0 252// ; CHECK: [[onef:%\w+]] = OpConstant [[float]] 1 253// ; CHECK: [[one_zero:%\w+]] = OpConstantComposite [[vector]] [[onef]] 254// [[zerof]] ; CHECK: [[zero_one:%\w+]] = OpConstantComposite [[vector]] 255// [[zerof]] [[onef]] ; CHECK: [[const_mat:%\w+]] = OpConstantComposite 256// [[matrix]] [[one_zero]] 257// [[zero_one]] ; CHECK-NOT: OpVariable [[matrix]] ; CHECK-NOT: OpVariable 258// [[vector]] Function [[one_zero]] ; CHECK: [[f1:%\w+]] = OpVariable 259// [[float_ptr]] Function [[zerof]] ; CHECK-NEXT: [[f2:%\w+]] = OpVariable 260// [[float_ptr]] Function [[onef]] ; CHECK-NEXT: [[vec_var:%\w+]] = OpVariable 261// [[vec_ptr]] Function [[zero_one]] ; CHECK-NOT: OpVariable [[matrix]] ; 262// CHECK-NOT: OpVariable [[vector]] Function [[one_zero]] 263// ; 264// OpCapability Shader 265// OpCapability Linkage 266// OpMemoryModel Logical GLSL450 267// OpName %7 "matrix_init" 268// %1 = OpTypeVoid 269// %2 = OpTypeFloat 32 270// %3 = OpTypeVector %2 2 271// %4 = OpTypeMatrix %3 2 272// %5 = OpTypePointer Function %4 273// %6 = OpTypePointer Function %2 274// %30 = OpTypePointer Function %3 275// %10 = OpTypeInt 32 0 276// %7 = OpTypeFunction %1 %10 277// %8 = OpConstant %2 0.0 278// %9 = OpConstant %2 1.0 279// %11 = OpConstant %10 0 280// %12 = OpConstant %10 1 281// %13 = OpConstantComposite %3 %9 %8 282// %14 = OpConstantComposite %3 %8 %9 283// %15 = OpConstantComposite %4 %13 %14 284// %16 = OpFunction %1 None %7 285// %31 = OpFunctionParameter %10 286// %17 = OpLabel 287// %18 = OpVariable %5 Function %15 288// %19 = OpAccessChain %6 %18 %11 %12 289// OpStore %19 %8 290// %20 = OpAccessChain %6 %18 %11 %11 291// OpStore %20 %8 292// %21 = OpAccessChain %30 %18 %12 293// OpStore %21 %14 294// OpReturn 295// OpFunctionEnd 296// )"; 297// 298// SinglePassRunAndMatch<opt::ScalarReplacementPass>(text, true); 299// } 300 301TEST_F(ScalarReplacementTest, ElideAccessChain) { 302 const std::string text = R"( 303; 304; CHECK: [[var:%\w+]] = OpVariable 305; CHECK-NOT: OpAccessChain 306; CHECK: OpStore [[var]] 307; 308OpCapability Shader 309OpCapability Linkage 310OpMemoryModel Logical GLSL450 311OpName %6 "elide_access_chain" 312%1 = OpTypeVoid 313%2 = OpTypeInt 32 0 314%3 = OpTypeStruct %2 %2 %2 %2 315%4 = OpTypePointer Function %3 316%20 = OpTypePointer Function %2 317%6 = OpTypeFunction %1 318%7 = OpConstant %2 0 319%8 = OpUndef %2 320%9 = OpConstant %2 2 321%10 = OpConstantNull %2 322%11 = OpConstantComposite %3 %7 %8 %9 %10 323%12 = OpFunction %1 None %6 324%13 = OpLabel 325%14 = OpVariable %4 Function %11 326%15 = OpAccessChain %20 %14 %7 327OpStore %15 %10 328OpReturn 329OpFunctionEnd 330 )"; 331 332 SinglePassRunAndMatch<ScalarReplacementPass>(text, true); 333} 334 335TEST_F(ScalarReplacementTest, ElideMultipleAccessChains) { 336 const std::string text = R"( 337; 338; CHECK: [[var:%\w+]] = OpVariable 339; CHECK-NOT: OpInBoundsAccessChain 340; CHECK OpStore [[var]] 341; 342OpCapability Shader 343OpCapability Linkage 344OpMemoryModel Logical GLSL450 345OpName %6 "elide_two_access_chains" 346%1 = OpTypeVoid 347%2 = OpTypeFloat 32 348%3 = OpTypeStruct %2 %2 349%4 = OpTypeStruct %3 %3 350%5 = OpTypePointer Function %4 351%6 = OpTypePointer Function %2 352%7 = OpTypeFunction %1 353%8 = OpConstant %2 0.0 354%9 = OpConstant %2 1.0 355%10 = OpTypeInt 32 0 356%11 = OpConstant %10 0 357%12 = OpConstant %10 1 358%13 = OpConstantComposite %3 %9 %8 359%14 = OpConstantComposite %3 %8 %9 360%15 = OpConstantComposite %4 %13 %14 361%16 = OpFunction %1 None %7 362%17 = OpLabel 363%18 = OpVariable %5 Function %15 364%19 = OpInBoundsAccessChain %6 %18 %11 %12 365OpStore %19 %8 366OpReturn 367OpFunctionEnd 368 )"; 369 370 SinglePassRunAndMatch<ScalarReplacementPass>(text, true); 371} 372 373TEST_F(ScalarReplacementTest, ReplaceAccessChain) { 374 const std::string text = R"( 375; 376; CHECK: [[param:%\w+]] = OpFunctionParameter 377; CHECK: [[var:%\w+]] = OpVariable 378; CHECK: [[access:%\w+]] = OpAccessChain {{%\w+}} [[var]] [[param]] 379; CHECK: OpStore [[access]] 380; 381OpCapability Shader 382OpCapability Linkage 383OpMemoryModel Logical GLSL450 384OpName %7 "replace_access_chain" 385%1 = OpTypeVoid 386%2 = OpTypeFloat 32 387%10 = OpTypeInt 32 0 388%uint_2 = OpConstant %10 2 389%3 = OpTypeArray %2 %uint_2 390%4 = OpTypeStruct %3 %3 391%5 = OpTypePointer Function %4 392%20 = OpTypePointer Function %3 393%6 = OpTypePointer Function %2 394%7 = OpTypeFunction %1 %10 395%8 = OpConstant %2 0.0 396%9 = OpConstant %2 1.0 397%11 = OpConstant %10 0 398%12 = OpConstant %10 1 399%13 = OpConstantComposite %3 %9 %8 400%14 = OpConstantComposite %3 %8 %9 401%15 = OpConstantComposite %4 %13 %14 402%16 = OpFunction %1 None %7 403%32 = OpFunctionParameter %10 404%17 = OpLabel 405%18 = OpVariable %5 Function %15 406%19 = OpAccessChain %6 %18 %11 %32 407OpStore %19 %8 408OpReturn 409OpFunctionEnd 410 )"; 411 412 SinglePassRunAndMatch<ScalarReplacementPass>(text, true); 413} 414 415TEST_F(ScalarReplacementTest, ArrayInitialization) { 416 const std::string text = R"( 417; 418; CHECK: [[float:%\w+]] = OpTypeFloat 32 419; CHECK: [[array:%\w+]] = OpTypeArray 420; CHECK: [[array_ptr:%\w+]] = OpTypePointer Function [[array]] 421; CHECK: [[float_ptr:%\w+]] = OpTypePointer Function [[float]] 422; CHECK: [[float0:%\w+]] = OpConstant [[float]] 0 423; CHECK: [[float1:%\w+]] = OpConstant [[float]] 1 424; CHECK: [[float2:%\w+]] = OpConstant [[float]] 2 425; CHECK-NOT: OpVariable [[array_ptr]] 426; CHECK: [[var0:%\w+]] = OpVariable [[float_ptr]] Function [[float0]] 427; CHECK-NEXT: [[var1:%\w+]] = OpVariable [[float_ptr]] Function [[float1]] 428; CHECK-NEXT: [[var2:%\w+]] = OpVariable [[float_ptr]] Function [[float2]] 429; CHECK-NOT: OpVariable [[array_ptr]] 430; 431OpCapability Shader 432OpCapability Linkage 433OpMemoryModel Logical GLSL450 434OpName %func "array_init" 435%void = OpTypeVoid 436%uint = OpTypeInt 32 0 437%float = OpTypeFloat 32 438%uint_0 = OpConstant %uint 0 439%uint_1 = OpConstant %uint 1 440%uint_2 = OpConstant %uint 2 441%uint_3 = OpConstant %uint 3 442%float_array = OpTypeArray %float %uint_3 443%array_ptr = OpTypePointer Function %float_array 444%float_ptr = OpTypePointer Function %float 445%float_0 = OpConstant %float 0 446%float_1 = OpConstant %float 1 447%float_2 = OpConstant %float 2 448%const_array = OpConstantComposite %float_array %float_2 %float_1 %float_0 449%func = OpTypeFunction %void 450%1 = OpFunction %void None %func 451%2 = OpLabel 452%3 = OpVariable %array_ptr Function %const_array 453%4 = OpInBoundsAccessChain %float_ptr %3 %uint_0 454OpStore %4 %float_0 455%5 = OpInBoundsAccessChain %float_ptr %3 %uint_1 456OpStore %5 %float_0 457%6 = OpInBoundsAccessChain %float_ptr %3 %uint_2 458OpStore %6 %float_0 459OpReturn 460OpFunctionEnd 461 )"; 462 463 SinglePassRunAndMatch<ScalarReplacementPass>(text, true); 464} 465 466TEST_F(ScalarReplacementTest, NonUniformCompositeInitialization) { 467 const std::string text = R"( 468; 469; CHECK: [[uint:%\w+]] = OpTypeInt 32 0 470; CHECK: [[long:%\w+]] = OpTypeInt 64 1 471; CHECK: [[dvector:%\w+]] = OpTypeVector 472; CHECK: [[vector:%\w+]] = OpTypeVector 473; CHECK: [[array:%\w+]] = OpTypeArray 474; CHECK: [[matrix:%\w+]] = OpTypeMatrix 475; CHECK: [[struct1:%\w+]] = OpTypeStruct [[uint]] [[vector]] 476; CHECK: [[struct2:%\w+]] = OpTypeStruct [[struct1]] [[matrix]] [[array]] [[uint]] 477; CHECK: [[struct1_ptr:%\w+]] = OpTypePointer Function [[struct1]] 478; CHECK: [[matrix_ptr:%\w+]] = OpTypePointer Function [[matrix]] 479; CHECK: [[array_ptr:%\w+]] = OpTypePointer Function [[array]] 480; CHECK: [[uint_ptr:%\w+]] = OpTypePointer Function [[uint]] 481; CHECK: [[struct2_ptr:%\w+]] = OpTypePointer Function [[struct2]] 482; CHECK: [[const_array:%\w+]] = OpConstantComposite [[array]] 483; CHECK: [[const_matrix:%\w+]] = OpConstantNull [[matrix]] 484; CHECK: [[const_struct1:%\w+]] = OpConstantComposite [[struct1]] 485; CHECK: OpUndef [[uint]] 486; CHECK: OpUndef [[vector]] 487; CHECK: OpUndef [[long]] 488; CHECK: OpFunction 489; CHECK-NOT: OpVariable [[struct2_ptr]] Function 490; CHECK: OpVariable [[uint_ptr]] Function 491; CHECK-NEXT: OpVariable [[matrix_ptr]] Function [[const_matrix]] 492; CHECK-NOT: OpVariable [[struct1_ptr]] Function [[const_struct1]] 493; CHECK-NOT: OpVariable [[struct2_ptr]] Function 494; 495OpCapability Shader 496OpCapability Linkage 497OpCapability Int64 498OpCapability Float64 499OpMemoryModel Logical GLSL450 500OpName %func "non_uniform_composite_init" 501%void = OpTypeVoid 502%uint = OpTypeInt 32 0 503%int64 = OpTypeInt 64 1 504%float = OpTypeFloat 32 505%double = OpTypeFloat 64 506%double2 = OpTypeVector %double 2 507%float4 = OpTypeVector %float 4 508%int64_0 = OpConstant %int64 0 509%int64_1 = OpConstant %int64 1 510%int64_2 = OpConstant %int64 2 511%int64_3 = OpConstant %int64 3 512%int64_array3 = OpTypeArray %int64 %int64_3 513%matrix_double2 = OpTypeMatrix %double2 2 514%struct1 = OpTypeStruct %uint %float4 515%struct2 = OpTypeStruct %struct1 %matrix_double2 %int64_array3 %uint 516%struct1_ptr = OpTypePointer Function %struct1 517%matrix_double2_ptr = OpTypePointer Function %matrix_double2 518%int64_array_ptr = OpTypePointer Function %int64_array3 519%uint_ptr = OpTypePointer Function %uint 520%struct2_ptr = OpTypePointer Function %struct2 521%const_uint = OpConstant %uint 0 522%const_int64_array = OpConstantComposite %int64_array3 %int64_0 %int64_1 %int64_2 523%const_double2 = OpConstantNull %double2 524%const_matrix_double2 = OpConstantNull %matrix_double2 525%undef_float4 = OpUndef %float4 526%const_struct1 = OpConstantComposite %struct1 %const_uint %undef_float4 527%const_struct2 = OpConstantComposite %struct2 %const_struct1 %const_matrix_double2 %const_int64_array %const_uint 528%func = OpTypeFunction %void 529%1 = OpFunction %void None %func 530%2 = OpLabel 531%var = OpVariable %struct2_ptr Function %const_struct2 532%3 = OpAccessChain %struct1_ptr %var %int64_0 533OpStore %3 %const_struct1 534%4 = OpAccessChain %matrix_double2_ptr %var %int64_1 535OpStore %4 %const_matrix_double2 536%5 = OpAccessChain %int64_array_ptr %var %int64_2 537OpStore %5 %const_int64_array 538%6 = OpAccessChain %uint_ptr %var %int64_3 539OpStore %6 %const_uint 540OpReturn 541OpFunctionEnd 542 )"; 543 544 SinglePassRunAndMatch<ScalarReplacementPass>(text, true); 545} 546 547TEST_F(ScalarReplacementTest, ElideUncombinedAccessChains) { 548 const std::string text = R"( 549; 550; CHECK: [[uint:%\w+]] = OpTypeInt 32 0 551; CHECK: [[uint_ptr:%\w+]] = OpTypePointer Function [[uint]] 552; CHECK: [[const:%\w+]] = OpConstant [[uint]] 0 553; CHECK: [[var:%\w+]] = OpVariable [[uint_ptr]] Function 554; CHECK-NOT: OpAccessChain 555; CHECK: OpStore [[var]] [[const]] 556; 557OpCapability Shader 558OpCapability Linkage 559OpMemoryModel Logical GLSL450 560OpName %func "elide_uncombined_access_chains" 561%void = OpTypeVoid 562%uint = OpTypeInt 32 0 563%struct1 = OpTypeStruct %uint 564%struct2 = OpTypeStruct %struct1 565%uint_ptr = OpTypePointer Function %uint 566%struct1_ptr = OpTypePointer Function %struct1 567%struct2_ptr = OpTypePointer Function %struct2 568%uint_0 = OpConstant %uint 0 569%func = OpTypeFunction %void 570%1 = OpFunction %void None %func 571%2 = OpLabel 572%var = OpVariable %struct2_ptr Function 573%3 = OpAccessChain %struct1_ptr %var %uint_0 574%4 = OpAccessChain %uint_ptr %3 %uint_0 575OpStore %4 %uint_0 576OpReturn 577OpFunctionEnd 578 )"; 579 580 SinglePassRunAndMatch<ScalarReplacementPass>(text, true); 581} 582 583TEST_F(ScalarReplacementTest, ElideSingleUncombinedAccessChains) { 584 const std::string text = R"( 585; 586; CHECK: [[uint:%\w+]] = OpTypeInt 32 0 587; CHECK: [[array:%\w+]] = OpTypeArray [[uint]] 588; CHECK: [[array_ptr:%\w+]] = OpTypePointer Function [[array]] 589; CHECK: [[const:%\w+]] = OpConstant [[uint]] 0 590; CHECK: [[param:%\w+]] = OpFunctionParameter [[uint]] 591; CHECK: [[var:%\w+]] = OpVariable [[array_ptr]] Function 592; CHECK: [[access:%\w+]] = OpAccessChain {{.*}} [[var]] [[param]] 593; CHECK: OpStore [[access]] [[const]] 594; 595OpCapability Shader 596OpCapability Linkage 597OpMemoryModel Logical GLSL450 598OpName %func "elide_single_uncombined_access_chains" 599%void = OpTypeVoid 600%uint = OpTypeInt 32 0 601%uint_1 = OpConstant %uint 1 602%array = OpTypeArray %uint %uint_1 603%struct2 = OpTypeStruct %array 604%uint_ptr = OpTypePointer Function %uint 605%array_ptr = OpTypePointer Function %array 606%struct2_ptr = OpTypePointer Function %struct2 607%uint_0 = OpConstant %uint 0 608%func = OpTypeFunction %void %uint 609%1 = OpFunction %void None %func 610%param = OpFunctionParameter %uint 611%2 = OpLabel 612%var = OpVariable %struct2_ptr Function 613%3 = OpAccessChain %array_ptr %var %uint_0 614%4 = OpAccessChain %uint_ptr %3 %param 615OpStore %4 %uint_0 616OpReturn 617OpFunctionEnd 618 )"; 619 620 SinglePassRunAndMatch<ScalarReplacementPass>(text, true); 621} 622 623TEST_F(ScalarReplacementTest, ReplaceWholeLoad) { 624 const std::string text = R"( 625; 626; CHECK: [[uint:%\w+]] = OpTypeInt 32 0 627; CHECK: [[struct1:%\w+]] = OpTypeStruct [[uint]] [[uint]] 628; CHECK: [[uint_ptr:%\w+]] = OpTypePointer Function [[uint]] 629; CHECK: [[const:%\w+]] = OpConstant [[uint]] 0 630; CHECK: [[var1:%\w+]] = OpVariable [[uint_ptr]] Function 631; CHECK: [[var0:%\w+]] = OpVariable [[uint_ptr]] Function 632; CHECK: [[l1:%\w+]] = OpLoad [[uint]] [[var1]] 633; CHECK: [[l0:%\w+]] = OpLoad [[uint]] [[var0]] 634; CHECK: OpCompositeConstruct [[struct1]] [[l0]] [[l1]] 635; 636OpCapability Shader 637OpCapability Linkage 638OpMemoryModel Logical GLSL450 639OpName %func "replace_whole_load" 640%void = OpTypeVoid 641%uint = OpTypeInt 32 0 642%struct1 = OpTypeStruct %uint %uint 643%uint_ptr = OpTypePointer Function %uint 644%struct1_ptr = OpTypePointer Function %struct1 645%uint_0 = OpConstant %uint 0 646%uint_1 = OpConstant %uint 1 647%func = OpTypeFunction %void 648%1 = OpFunction %void None %func 649%2 = OpLabel 650%var = OpVariable %struct1_ptr Function 651%load = OpLoad %struct1 %var 652%3 = OpAccessChain %uint_ptr %var %uint_0 653OpStore %3 %uint_0 654%4 = OpAccessChain %uint_ptr %var %uint_1 655OpStore %4 %uint_0 656OpReturn 657OpFunctionEnd 658 )"; 659 660 SinglePassRunAndMatch<ScalarReplacementPass>(text, true); 661} 662 663TEST_F(ScalarReplacementTest, ReplaceWholeLoadCopyMemoryAccess) { 664 const std::string text = R"( 665; 666; CHECK: [[uint:%\w+]] = OpTypeInt 32 0 667; CHECK: [[struct1:%\w+]] = OpTypeStruct [[uint]] [[uint]] 668; CHECK: [[uint_ptr:%\w+]] = OpTypePointer Function [[uint]] 669; CHECK: [[undef:%\w+]] = OpUndef [[uint]] 670; CHECK: [[var0:%\w+]] = OpVariable [[uint_ptr]] Function 671; CHECK: [[l0:%\w+]] = OpLoad [[uint]] [[var0]] Nontemporal 672; CHECK: OpCompositeConstruct [[struct1]] [[l0]] [[undef]] 673; 674OpCapability Shader 675OpCapability Linkage 676OpMemoryModel Logical GLSL450 677OpName %func "replace_whole_load_copy_memory_access" 678%void = OpTypeVoid 679%uint = OpTypeInt 32 0 680%struct1 = OpTypeStruct %uint %uint 681%uint_ptr = OpTypePointer Function %uint 682%struct1_ptr = OpTypePointer Function %struct1 683%uint_0 = OpConstant %uint 0 684%func = OpTypeFunction %void 685%1 = OpFunction %void None %func 686%2 = OpLabel 687%var = OpVariable %struct1_ptr Function 688%load = OpLoad %struct1 %var Nontemporal 689%3 = OpAccessChain %uint_ptr %var %uint_0 690OpStore %3 %uint_0 691OpReturn 692OpFunctionEnd 693 )"; 694 695 SinglePassRunAndMatch<ScalarReplacementPass>(text, true); 696} 697 698TEST_F(ScalarReplacementTest, ReplaceWholeStore) { 699 const std::string text = R"( 700; 701; CHECK: [[uint:%\w+]] = OpTypeInt 32 0 702; CHECK: [[struct1:%\w+]] = OpTypeStruct [[uint]] [[uint]] 703; CHECK: [[uint_ptr:%\w+]] = OpTypePointer Function [[uint]] 704; CHECK: [[const:%\w+]] = OpConstant [[uint]] 0 705; CHECK: [[const_struct:%\w+]] = OpConstantComposite [[struct1]] [[const]] [[const]] 706; CHECK: [[var0:%\w+]] = OpVariable [[uint_ptr]] Function 707; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[uint]] [[const_struct]] 0 708; CHECK: OpStore [[var0]] [[ex0]] 709; 710OpCapability Shader 711OpCapability Linkage 712OpMemoryModel Logical GLSL450 713OpName %func "replace_whole_store" 714%void = OpTypeVoid 715%uint = OpTypeInt 32 0 716%struct1 = OpTypeStruct %uint %uint 717%uint_ptr = OpTypePointer Function %uint 718%struct1_ptr = OpTypePointer Function %struct1 719%uint_0 = OpConstant %uint 0 720%const_struct = OpConstantComposite %struct1 %uint_0 %uint_0 721%func = OpTypeFunction %void 722%1 = OpFunction %void None %func 723%2 = OpLabel 724%var = OpVariable %struct1_ptr Function 725OpStore %var %const_struct 726%3 = OpAccessChain %uint_ptr %var %uint_0 727%4 = OpLoad %uint %3 728OpReturn 729OpFunctionEnd 730 )"; 731 732 SinglePassRunAndMatch<ScalarReplacementPass>(text, true); 733} 734 735TEST_F(ScalarReplacementTest, ReplaceWholeStoreCopyMemoryAccess) { 736 const std::string text = R"( 737; 738; CHECK: [[uint:%\w+]] = OpTypeInt 32 0 739; CHECK: [[struct1:%\w+]] = OpTypeStruct [[uint]] [[uint]] 740; CHECK: [[uint_ptr:%\w+]] = OpTypePointer Function [[uint]] 741; CHECK: [[const:%\w+]] = OpConstant [[uint]] 0 742; CHECK: [[const_struct:%\w+]] = OpConstantComposite [[struct1]] [[const]] [[const]] 743; CHECK: [[var0:%\w+]] = OpVariable [[uint_ptr]] Function 744; CHECK-NOT: OpVariable 745; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[uint]] [[const_struct]] 0 746; CHECK: OpStore [[var0]] [[ex0]] Aligned 4 747; 748OpCapability Shader 749OpCapability Linkage 750OpMemoryModel Logical GLSL450 751OpName %func "replace_whole_store_copy_memory_access" 752%void = OpTypeVoid 753%uint = OpTypeInt 32 0 754%struct1 = OpTypeStruct %uint %uint 755%uint_ptr = OpTypePointer Function %uint 756%struct1_ptr = OpTypePointer Function %struct1 757%uint_0 = OpConstant %uint 0 758%const_struct = OpConstantComposite %struct1 %uint_0 %uint_0 759%func = OpTypeFunction %void 760%1 = OpFunction %void None %func 761%2 = OpLabel 762%var = OpVariable %struct1_ptr Function 763OpStore %var %const_struct Aligned 4 764%3 = OpAccessChain %uint_ptr %var %uint_0 765%4 = OpLoad %uint %3 766OpReturn 767OpFunctionEnd 768 )"; 769 770 SinglePassRunAndMatch<ScalarReplacementPass>(text, true); 771} 772 773TEST_F(ScalarReplacementTest, DontTouchVolatileLoad) { 774 const std::string text = R"( 775; 776; CHECK: [[struct:%\w+]] = OpTypeStruct 777; CHECK: [[struct_ptr:%\w+]] = OpTypePointer Function [[struct]] 778; CHECK: OpLabel 779; CHECK-NEXT: OpVariable [[struct_ptr]] 780; CHECK-NOT: OpVariable 781; 782OpCapability Shader 783OpCapability Linkage 784OpMemoryModel Logical GLSL450 785OpName %func "dont_touch_volatile_load" 786%void = OpTypeVoid 787%uint = OpTypeInt 32 0 788%struct1 = OpTypeStruct %uint 789%uint_ptr = OpTypePointer Function %uint 790%struct1_ptr = OpTypePointer Function %struct1 791%uint_0 = OpConstant %uint 0 792%func = OpTypeFunction %void 793%1 = OpFunction %void None %func 794%2 = OpLabel 795%var = OpVariable %struct1_ptr Function 796%3 = OpAccessChain %uint_ptr %var %uint_0 797%4 = OpLoad %uint %3 Volatile 798OpReturn 799OpFunctionEnd 800 )"; 801 802 SinglePassRunAndMatch<ScalarReplacementPass>(text, true); 803} 804 805TEST_F(ScalarReplacementTest, DontTouchVolatileStore) { 806 const std::string text = R"( 807; 808; CHECK: [[struct:%\w+]] = OpTypeStruct 809; CHECK: [[struct_ptr:%\w+]] = OpTypePointer Function [[struct]] 810; CHECK: OpLabel 811; CHECK-NEXT: OpVariable [[struct_ptr]] 812; CHECK-NOT: OpVariable 813; 814OpCapability Shader 815OpCapability Linkage 816OpMemoryModel Logical GLSL450 817OpName %func "dont_touch_volatile_store" 818%void = OpTypeVoid 819%uint = OpTypeInt 32 0 820%struct1 = OpTypeStruct %uint 821%uint_ptr = OpTypePointer Function %uint 822%struct1_ptr = OpTypePointer Function %struct1 823%uint_0 = OpConstant %uint 0 824%func = OpTypeFunction %void 825%1 = OpFunction %void None %func 826%2 = OpLabel 827%var = OpVariable %struct1_ptr Function 828%3 = OpAccessChain %uint_ptr %var %uint_0 829OpStore %3 %uint_0 Volatile 830OpReturn 831OpFunctionEnd 832 )"; 833 834 SinglePassRunAndMatch<ScalarReplacementPass>(text, true); 835} 836 837TEST_F(ScalarReplacementTest, DontTouchSpecNonFunctionVariable) { 838 const std::string text = R"( 839; 840; CHECK: [[struct:%\w+]] = OpTypeStruct 841; CHECK: [[struct_ptr:%\w+]] = OpTypePointer Uniform [[struct]] 842; CHECK: OpConstant 843; CHECK-NEXT: OpVariable [[struct_ptr]] 844; CHECK-NOT: OpVariable 845; 846OpCapability Shader 847OpCapability Linkage 848OpMemoryModel Logical GLSL450 849OpName %func "dont_touch_spec_constant_access_chain" 850%void = OpTypeVoid 851%uint = OpTypeInt 32 0 852%struct1 = OpTypeStruct %uint 853%uint_ptr = OpTypePointer Uniform %uint 854%struct1_ptr = OpTypePointer Uniform %struct1 855%uint_0 = OpConstant %uint 0 856%var = OpVariable %struct1_ptr Uniform 857%func = OpTypeFunction %void 858%1 = OpFunction %void None %func 859%2 = OpLabel 860%3 = OpAccessChain %uint_ptr %var %uint_0 861OpStore %3 %uint_0 Volatile 862OpReturn 863OpFunctionEnd 864 )"; 865 866 SinglePassRunAndMatch<ScalarReplacementPass>(text, true); 867} 868 869TEST_F(ScalarReplacementTest, DontTouchSpecConstantAccessChain) { 870 const std::string text = R"( 871; 872; CHECK: [[array:%\w+]] = OpTypeArray 873; CHECK: [[array_ptr:%\w+]] = OpTypePointer Function [[array]] 874; CHECK: OpLabel 875; CHECK-NEXT: OpVariable [[array_ptr]] 876; CHECK-NOT: OpVariable 877; 878OpCapability Shader 879OpCapability Linkage 880OpMemoryModel Logical GLSL450 881OpName %func "dont_touch_spec_constant_access_chain" 882%void = OpTypeVoid 883%uint = OpTypeInt 32 0 884%uint_1 = OpConstant %uint 1 885%array = OpTypeArray %uint %uint_1 886%uint_ptr = OpTypePointer Function %uint 887%array_ptr = OpTypePointer Function %array 888%uint_0 = OpConstant %uint 0 889%spec_const = OpSpecConstant %uint 0 890%func = OpTypeFunction %void 891%1 = OpFunction %void None %func 892%2 = OpLabel 893%var = OpVariable %array_ptr Function 894%3 = OpAccessChain %uint_ptr %var %spec_const 895OpStore %3 %uint_0 Volatile 896OpReturn 897OpFunctionEnd 898 )"; 899 900 SinglePassRunAndMatch<ScalarReplacementPass>(text, true); 901} 902 903TEST_F(ScalarReplacementTest, NoPartialAccesses) { 904 const std::string text = R"( 905; 906; CHECK: [[uint:%\w+]] = OpTypeInt 32 0 907; CHECK: [[uint_ptr:%\w+]] = OpTypePointer Function [[uint]] 908; CHECK: OpLabel 909; CHECK-NOT: OpVariable 910; 911OpCapability Shader 912OpCapability Linkage 913OpMemoryModel Logical GLSL450 914OpName %func "no_partial_accesses" 915%void = OpTypeVoid 916%uint = OpTypeInt 32 0 917%struct1 = OpTypeStruct %uint 918%uint_ptr = OpTypePointer Function %uint 919%struct1_ptr = OpTypePointer Function %struct1 920%const = OpConstantNull %struct1 921%func = OpTypeFunction %void 922%1 = OpFunction %void None %func 923%2 = OpLabel 924%var = OpVariable %struct1_ptr Function 925OpStore %var %const 926OpReturn 927OpFunctionEnd 928 )"; 929 930 SinglePassRunAndMatch<ScalarReplacementPass>(text, true); 931} 932 933TEST_F(ScalarReplacementTest, DontTouchPtrAccessChain) { 934 const std::string text = R"( 935; 936; CHECK: [[struct:%\w+]] = OpTypeStruct 937; CHECK: [[struct_ptr:%\w+]] = OpTypePointer Function [[struct]] 938; CHECK: OpLabel 939; CHECK-NEXT: OpVariable [[struct_ptr]] 940; CHECK-NOT: OpVariable 941; 942OpCapability Shader 943OpCapability Linkage 944OpMemoryModel Logical GLSL450 945OpName %func "dont_touch_ptr_access_chain" 946%void = OpTypeVoid 947%uint = OpTypeInt 32 0 948%struct1 = OpTypeStruct %uint 949%uint_ptr = OpTypePointer Function %uint 950%struct1_ptr = OpTypePointer Function %struct1 951%uint_0 = OpConstant %uint 0 952%func = OpTypeFunction %void 953%1 = OpFunction %void None %func 954%2 = OpLabel 955%var = OpVariable %struct1_ptr Function 956%3 = OpPtrAccessChain %uint_ptr %var %uint_0 %uint_0 957OpStore %3 %uint_0 958%4 = OpAccessChain %uint_ptr %var %uint_0 959OpStore %4 %uint_0 960OpReturn 961OpFunctionEnd 962 )"; 963 964 SinglePassRunAndMatch<ScalarReplacementPass>(text, false); 965} 966 967TEST_F(ScalarReplacementTest, DontTouchInBoundsPtrAccessChain) { 968 const std::string text = R"( 969; 970; CHECK: [[struct:%\w+]] = OpTypeStruct 971; CHECK: [[struct_ptr:%\w+]] = OpTypePointer Function [[struct]] 972; CHECK: OpLabel 973; CHECK-NEXT: OpVariable [[struct_ptr]] 974; CHECK-NOT: OpVariable 975; 976OpCapability Shader 977OpCapability Linkage 978OpMemoryModel Logical GLSL450 979OpName %func "dont_touch_in_bounds_ptr_access_chain" 980%void = OpTypeVoid 981%uint = OpTypeInt 32 0 982%struct1 = OpTypeStruct %uint 983%uint_ptr = OpTypePointer Function %uint 984%struct1_ptr = OpTypePointer Function %struct1 985%uint_0 = OpConstant %uint 0 986%func = OpTypeFunction %void 987%1 = OpFunction %void None %func 988%2 = OpLabel 989%var = OpVariable %struct1_ptr Function 990%3 = OpInBoundsPtrAccessChain %uint_ptr %var %uint_0 %uint_0 991OpStore %3 %uint_0 992%4 = OpInBoundsAccessChain %uint_ptr %var %uint_0 993OpStore %4 %uint_0 994OpReturn 995OpFunctionEnd 996 )"; 997 998 SinglePassRunAndMatch<ScalarReplacementPass>(text, false); 999} 1000 1001TEST_F(ScalarReplacementTest, DonTouchAliasedDecoration) { 1002 const std::string text = R"( 1003; 1004; CHECK: [[struct:%\w+]] = OpTypeStruct 1005; CHECK: [[struct_ptr:%\w+]] = OpTypePointer Function [[struct]] 1006; CHECK: OpLabel 1007; CHECK-NEXT: OpVariable [[struct_ptr]] 1008; CHECK-NOT: OpVariable 1009; 1010OpCapability Shader 1011OpCapability Linkage 1012OpMemoryModel Logical GLSL450 1013OpName %func "aliased" 1014OpDecorate %var Aliased 1015%void = OpTypeVoid 1016%uint = OpTypeInt 32 0 1017%struct1 = OpTypeStruct %uint 1018%uint_ptr = OpTypePointer Function %uint 1019%struct1_ptr = OpTypePointer Function %struct1 1020%uint_0 = OpConstant %uint 0 1021%func = OpTypeFunction %void 1022%1 = OpFunction %void None %func 1023%2 = OpLabel 1024%var = OpVariable %struct1_ptr Function 1025%3 = OpAccessChain %uint_ptr %var %uint_0 1026%4 = OpLoad %uint %3 1027OpReturn 1028OpFunctionEnd 1029 )"; 1030 1031 SinglePassRunAndMatch<ScalarReplacementPass>(text, true); 1032} 1033 1034TEST_F(ScalarReplacementTest, CopyRestrictDecoration) { 1035 const std::string text = R"( 1036; 1037; CHECK: OpName 1038; CHECK-NEXT: OpDecorate [[var0:%\w+]] Restrict 1039; CHECK-NEXT: OpDecorate [[var1:%\w+]] Restrict 1040; CHECK: [[int:%\w+]] = OpTypeInt 1041; CHECK: [[struct:%\w+]] = OpTypeStruct 1042; CHECK: [[int_ptr:%\w+]] = OpTypePointer Function [[int]] 1043; CHECK: [[struct_ptr:%\w+]] = OpTypePointer Function [[struct]] 1044; CHECK: OpLabel 1045; CHECK-NEXT: [[var1]] = OpVariable [[int_ptr]] 1046; CHECK-NEXT: [[var0]] = OpVariable [[int_ptr]] 1047; CHECK-NOT: OpVariable [[struct_ptr]] 1048; 1049OpCapability Shader 1050OpCapability Linkage 1051OpMemoryModel Logical GLSL450 1052OpName %func "restrict" 1053OpDecorate %var Restrict 1054%void = OpTypeVoid 1055%uint = OpTypeInt 32 0 1056%struct1 = OpTypeStruct %uint %uint 1057%uint_ptr = OpTypePointer Function %uint 1058%struct1_ptr = OpTypePointer Function %struct1 1059%uint_0 = OpConstant %uint 0 1060%uint_1 = OpConstant %uint 1 1061%func = OpTypeFunction %void 1062%1 = OpFunction %void None %func 1063%2 = OpLabel 1064%var = OpVariable %struct1_ptr Function 1065%3 = OpAccessChain %uint_ptr %var %uint_0 1066%4 = OpLoad %uint %3 1067%5 = OpAccessChain %uint_ptr %var %uint_1 1068%6 = OpLoad %uint %5 1069OpReturn 1070OpFunctionEnd 1071 )"; 1072 1073 SinglePassRunAndMatch<ScalarReplacementPass>(text, true); 1074} 1075 1076TEST_F(ScalarReplacementTest, DontClobberDecoratesOnSubtypes) { 1077 const std::string text = R"( 1078; 1079; CHECK: OpDecorate [[array:%\w+]] ArrayStride 1 1080; CHECK: [[uint:%\w+]] = OpTypeInt 32 0 1081; CHECK: [[array]] = OpTypeArray [[uint]] 1082; CHECK: [[array_ptr:%\w+]] = OpTypePointer Function [[array]] 1083; CHECK: OpLabel 1084; CHECK-NEXT: OpVariable [[array_ptr]] Function 1085; CHECK-NOT: OpVariable 1086; 1087OpCapability Shader 1088OpCapability Linkage 1089OpMemoryModel Logical GLSL450 1090OpName %func "array_stride" 1091OpDecorate %array ArrayStride 1 1092%void = OpTypeVoid 1093%uint = OpTypeInt 32 0 1094%uint_1 = OpConstant %uint 1 1095%array = OpTypeArray %uint %uint_1 1096%struct1 = OpTypeStruct %array 1097%uint_ptr = OpTypePointer Function %uint 1098%struct1_ptr = OpTypePointer Function %struct1 1099%uint_0 = OpConstant %uint 0 1100%func = OpTypeFunction %void %uint 1101%1 = OpFunction %void None %func 1102%param = OpFunctionParameter %uint 1103%2 = OpLabel 1104%var = OpVariable %struct1_ptr Function 1105%3 = OpAccessChain %uint_ptr %var %uint_0 %param 1106%4 = OpLoad %uint %3 1107OpReturn 1108OpFunctionEnd 1109 )"; 1110 1111 SinglePassRunAndMatch<ScalarReplacementPass>(text, true); 1112} 1113 1114TEST_F(ScalarReplacementTest, DontCopyMemberDecorate) { 1115 const std::string text = R"( 1116; 1117; CHECK-NOT: OpDecorate 1118; CHECK: [[uint:%\w+]] = OpTypeInt 32 0 1119; CHECK: [[struct:%\w+]] = OpTypeStruct [[uint]] 1120; CHECK: [[uint_ptr:%\w+]] = OpTypePointer Function [[uint]] 1121; CHECK: [[struct_ptr:%\w+]] = OpTypePointer Function [[struct]] 1122; CHECK: OpLabel 1123; CHECK-NEXT: OpVariable [[uint_ptr]] Function 1124; CHECK-NOT: OpVariable 1125; 1126OpCapability Shader 1127OpCapability Linkage 1128OpMemoryModel Logical GLSL450 1129OpName %func "member_decorate" 1130OpMemberDecorate %struct1 0 Offset 1 1131%void = OpTypeVoid 1132%uint = OpTypeInt 32 0 1133%uint_1 = OpConstant %uint 1 1134%struct1 = OpTypeStruct %uint 1135%uint_ptr = OpTypePointer Function %uint 1136%struct1_ptr = OpTypePointer Function %struct1 1137%uint_0 = OpConstant %uint 0 1138%func = OpTypeFunction %void %uint 1139%1 = OpFunction %void None %func 1140%2 = OpLabel 1141%var = OpVariable %struct1_ptr Function 1142%3 = OpAccessChain %uint_ptr %var %uint_0 1143%4 = OpLoad %uint %3 1144OpReturn 1145OpFunctionEnd 1146 )"; 1147 1148 SinglePassRunAndMatch<ScalarReplacementPass>(text, true); 1149} 1150 1151TEST_F(ScalarReplacementTest, NoPartialAccesses2) { 1152 const std::string text = R"( 1153; 1154; CHECK: [[float:%\w+]] = OpTypeFloat 32 1155; CHECK: [[float_ptr:%\w+]] = OpTypePointer Function [[float]] 1156; CHECK: OpVariable [[float_ptr]] Function 1157; CHECK: OpVariable [[float_ptr]] Function 1158; CHECK: OpVariable [[float_ptr]] Function 1159; CHECK: OpVariable [[float_ptr]] Function 1160; CHECK: OpVariable [[float_ptr]] Function 1161; CHECK: OpVariable [[float_ptr]] Function 1162; CHECK: OpVariable [[float_ptr]] Function 1163; CHECK-NOT: OpVariable 1164; 1165OpCapability Shader 1166%1 = OpExtInstImport "GLSL.std.450" 1167OpMemoryModel Logical GLSL450 1168OpEntryPoint Fragment %main "main" %fo 1169OpExecutionMode %main OriginUpperLeft 1170OpSource GLSL 430 1171OpName %main "main" 1172OpName %S "S" 1173OpMemberName %S 0 "x" 1174OpMemberName %S 1 "y" 1175OpName %ts1 "ts1" 1176OpName %S_0 "S" 1177OpMemberName %S_0 0 "x" 1178OpMemberName %S_0 1 "y" 1179OpName %U_t "U_t" 1180OpMemberName %U_t 0 "g_s1" 1181OpMemberName %U_t 1 "g_s2" 1182OpMemberName %U_t 2 "g_s3" 1183OpName %_ "" 1184OpName %ts2 "ts2" 1185OpName %_Globals_ "_Globals_" 1186OpMemberName %_Globals_ 0 "g_b" 1187OpName %__0 "" 1188OpName %ts3 "ts3" 1189OpName %ts4 "ts4" 1190OpName %fo "fo" 1191OpMemberDecorate %S_0 0 Offset 0 1192OpMemberDecorate %S_0 1 Offset 4 1193OpMemberDecorate %U_t 0 Offset 0 1194OpMemberDecorate %U_t 1 Offset 8 1195OpMemberDecorate %U_t 2 Offset 16 1196OpDecorate %U_t BufferBlock 1197OpDecorate %_ DescriptorSet 0 1198OpMemberDecorate %_Globals_ 0 Offset 0 1199OpDecorate %_Globals_ Block 1200OpDecorate %__0 DescriptorSet 0 1201OpDecorate %__0 Binding 0 1202OpDecorate %fo Location 0 1203%void = OpTypeVoid 1204%15 = OpTypeFunction %void 1205%float = OpTypeFloat 32 1206%S = OpTypeStruct %float %float 1207%_ptr_Function_S = OpTypePointer Function %S 1208%S_0 = OpTypeStruct %float %float 1209%U_t = OpTypeStruct %S_0 %S_0 %S_0 1210%_ptr_Uniform_U_t = OpTypePointer Uniform %U_t 1211%_ = OpVariable %_ptr_Uniform_U_t Uniform 1212%int = OpTypeInt 32 1 1213%int_0 = OpConstant %int 0 1214%_ptr_Uniform_S_0 = OpTypePointer Uniform %S_0 1215%_ptr_Function_float = OpTypePointer Function %float 1216%int_1 = OpConstant %int 1 1217%uint = OpTypeInt 32 0 1218%_Globals_ = OpTypeStruct %uint 1219%_ptr_Uniform__Globals_ = OpTypePointer Uniform %_Globals_ 1220%__0 = OpVariable %_ptr_Uniform__Globals_ Uniform 1221%_ptr_Uniform_uint = OpTypePointer Uniform %uint 1222%bool = OpTypeBool 1223%uint_0 = OpConstant %uint 0 1224%_ptr_Output_float = OpTypePointer Output %float 1225%fo = OpVariable %_ptr_Output_float Output 1226%main = OpFunction %void None %15 1227%30 = OpLabel 1228%ts1 = OpVariable %_ptr_Function_S Function 1229%ts2 = OpVariable %_ptr_Function_S Function 1230%ts3 = OpVariable %_ptr_Function_S Function 1231%ts4 = OpVariable %_ptr_Function_S Function 1232%31 = OpAccessChain %_ptr_Uniform_S_0 %_ %int_0 1233%32 = OpLoad %S_0 %31 1234%33 = OpCompositeExtract %float %32 0 1235%34 = OpAccessChain %_ptr_Function_float %ts1 %int_0 1236OpStore %34 %33 1237%35 = OpCompositeExtract %float %32 1 1238%36 = OpAccessChain %_ptr_Function_float %ts1 %int_1 1239OpStore %36 %35 1240%37 = OpAccessChain %_ptr_Uniform_S_0 %_ %int_1 1241%38 = OpLoad %S_0 %37 1242%39 = OpCompositeExtract %float %38 0 1243%40 = OpAccessChain %_ptr_Function_float %ts2 %int_0 1244OpStore %40 %39 1245%41 = OpCompositeExtract %float %38 1 1246%42 = OpAccessChain %_ptr_Function_float %ts2 %int_1 1247OpStore %42 %41 1248%43 = OpAccessChain %_ptr_Uniform_uint %__0 %int_0 1249%44 = OpLoad %uint %43 1250%45 = OpINotEqual %bool %44 %uint_0 1251OpSelectionMerge %46 None 1252OpBranchConditional %45 %47 %48 1253%47 = OpLabel 1254%49 = OpLoad %S %ts1 1255OpStore %ts3 %49 1256OpBranch %46 1257%48 = OpLabel 1258%50 = OpLoad %S %ts2 1259OpStore %ts3 %50 1260OpBranch %46 1261%46 = OpLabel 1262%51 = OpLoad %S %ts3 1263OpStore %ts4 %51 1264%52 = OpAccessChain %_ptr_Function_float %ts4 %int_1 1265%53 = OpLoad %float %52 1266OpStore %fo %53 1267OpReturn 1268OpFunctionEnd 1269 )"; 1270 1271 SinglePassRunAndMatch<ScalarReplacementPass>(text, true); 1272} 1273 1274TEST_F(ScalarReplacementTest, ReplaceWholeLoadAndStore) { 1275 const std::string text = R"( 1276; 1277; CHECK: [[uint:%\w+]] = OpTypeInt 32 0 1278; CHECK: [[struct1:%\w+]] = OpTypeStruct [[uint]] [[uint]] 1279; CHECK: [[uint_ptr:%\w+]] = OpTypePointer Function [[uint]] 1280; CHECK: [[const:%\w+]] = OpConstant [[uint]] 0 1281; CHECK: [[undef:%\w+]] = OpUndef [[uint]] 1282; CHECK: [[var0:%\w+]] = OpVariable [[uint_ptr]] Function 1283; CHECK: [[var1:%\w+]] = OpVariable [[uint_ptr]] Function 1284; CHECK-NOT: OpVariable 1285; CHECK: [[l0:%\w+]] = OpLoad [[uint]] [[var0]] 1286; CHECK: [[c0:%\w+]] = OpCompositeConstruct [[struct1]] [[l0]] [[undef]] 1287; CHECK: [[e0:%\w+]] = OpCompositeExtract [[uint]] [[c0]] 0 1288; CHECK: OpStore [[var1]] [[e0]] 1289; CHECK: [[l1:%\w+]] = OpLoad [[uint]] [[var1]] 1290; CHECK: [[c1:%\w+]] = OpCompositeConstruct [[struct1]] [[l1]] [[undef]] 1291; CHECK: [[e1:%\w+]] = OpCompositeExtract [[uint]] [[c1]] 0 1292; 1293OpCapability Shader 1294OpCapability Linkage 1295OpMemoryModel Logical GLSL450 1296OpName %func "replace_whole_load" 1297%void = OpTypeVoid 1298%uint = OpTypeInt 32 0 1299%struct1 = OpTypeStruct %uint %uint 1300%uint_ptr = OpTypePointer Function %uint 1301%struct1_ptr = OpTypePointer Function %struct1 1302%uint_0 = OpConstant %uint 0 1303%uint_1 = OpConstant %uint 1 1304%func = OpTypeFunction %void 1305%1 = OpFunction %void None %func 1306%2 = OpLabel 1307%var2 = OpVariable %struct1_ptr Function 1308%var1 = OpVariable %struct1_ptr Function 1309%load1 = OpLoad %struct1 %var1 1310OpStore %var2 %load1 1311%load2 = OpLoad %struct1 %var2 1312%3 = OpCompositeExtract %uint %load2 0 1313OpReturn 1314OpFunctionEnd 1315 )"; 1316 1317 SinglePassRunAndMatch<ScalarReplacementPass>(text, true); 1318} 1319 1320TEST_F(ScalarReplacementTest, ReplaceWholeLoadAndStore2) { 1321 // TODO: We can improve this case by ensuring that |var2| is processed first. 1322 const std::string text = R"( 1323; 1324; CHECK: [[uint:%\w+]] = OpTypeInt 32 0 1325; CHECK: [[struct1:%\w+]] = OpTypeStruct [[uint]] [[uint]] 1326; CHECK: [[uint_ptr:%\w+]] = OpTypePointer Function [[uint]] 1327; CHECK: [[const:%\w+]] = OpConstant [[uint]] 0 1328; CHECK: [[undef:%\w+]] = OpUndef [[uint]] 1329; CHECK: [[var1:%\w+]] = OpVariable [[uint_ptr]] Function 1330; CHECK: [[var0a:%\w+]] = OpVariable [[uint_ptr]] Function 1331; CHECK: [[var0b:%\w+]] = OpVariable [[uint_ptr]] Function 1332; CHECK-NOT: OpVariable 1333; CHECK: [[l0a:%\w+]] = OpLoad [[uint]] [[var0a]] 1334; CHECK: [[l0b:%\w+]] = OpLoad [[uint]] [[var0b]] 1335; CHECK: [[c0:%\w+]] = OpCompositeConstruct [[struct1]] [[l0b]] [[l0a]] 1336; CHECK: [[e0:%\w+]] = OpCompositeExtract [[uint]] [[c0]] 0 1337; CHECK: OpStore [[var1]] [[e0]] 1338; CHECK: [[l1:%\w+]] = OpLoad [[uint]] [[var1]] 1339; CHECK: [[c1:%\w+]] = OpCompositeConstruct [[struct1]] [[l1]] [[undef]] 1340; CHECK: [[e1:%\w+]] = OpCompositeExtract [[uint]] [[c1]] 0 1341; 1342OpCapability Shader 1343OpCapability Linkage 1344OpMemoryModel Logical GLSL450 1345OpName %func "replace_whole_load" 1346%void = OpTypeVoid 1347%uint = OpTypeInt 32 0 1348%struct1 = OpTypeStruct %uint %uint 1349%uint_ptr = OpTypePointer Function %uint 1350%struct1_ptr = OpTypePointer Function %struct1 1351%uint_0 = OpConstant %uint 0 1352%uint_1 = OpConstant %uint 1 1353%func = OpTypeFunction %void 1354%1 = OpFunction %void None %func 1355%2 = OpLabel 1356%var1 = OpVariable %struct1_ptr Function 1357%var2 = OpVariable %struct1_ptr Function 1358%load1 = OpLoad %struct1 %var1 1359OpStore %var2 %load1 1360%load2 = OpLoad %struct1 %var2 1361%3 = OpCompositeExtract %uint %load2 0 1362OpReturn 1363OpFunctionEnd 1364 )"; 1365 1366 SinglePassRunAndMatch<ScalarReplacementPass>(text, true); 1367} 1368 1369TEST_F(ScalarReplacementTest, CreateAmbiguousNullConstant1) { 1370 const std::string text = R"( 1371; 1372; CHECK: [[uint:%\w+]] = OpTypeInt 32 0 1373; CHECK: [[struct1:%\w+]] = OpTypeStruct [[uint]] [[struct_member:%\w+]] 1374; CHECK: [[uint_ptr:%\w+]] = OpTypePointer Function [[uint]] 1375; CHECK: [[const:%\w+]] = OpConstant [[uint]] 0 1376; CHECK: [[undef:%\w+]] = OpUndef [[struct_member]] 1377; CHECK: [[var0a:%\w+]] = OpVariable [[uint_ptr]] Function 1378; CHECK: [[var1:%\w+]] = OpVariable [[uint_ptr]] Function 1379; CHECK: [[var0b:%\w+]] = OpVariable [[uint_ptr]] Function 1380; CHECK-NOT: OpVariable 1381; CHECK: OpStore [[var1]] 1382; CHECK: [[l1:%\w+]] = OpLoad [[uint]] [[var1]] 1383; CHECK: [[c1:%\w+]] = OpCompositeConstruct [[struct1]] [[l1]] [[undef]] 1384; CHECK: [[e1:%\w+]] = OpCompositeExtract [[uint]] [[c1]] 0 1385; 1386OpCapability Shader 1387OpCapability Linkage 1388OpMemoryModel Logical GLSL450 1389OpName %func "replace_whole_load" 1390%void = OpTypeVoid 1391%uint = OpTypeInt 32 0 1392%struct2 = OpTypeStruct %uint 1393%struct3 = OpTypeStruct %uint 1394%struct1 = OpTypeStruct %uint %struct2 1395%uint_ptr = OpTypePointer Function %uint 1396%struct1_ptr = OpTypePointer Function %struct1 1397%uint_0 = OpConstant %uint 0 1398%uint_1 = OpConstant %uint 1 1399%func = OpTypeFunction %void 1400%1 = OpFunction %void None %func 1401%2 = OpLabel 1402%var1 = OpVariable %struct1_ptr Function 1403%var2 = OpVariable %struct1_ptr Function 1404%load1 = OpLoad %struct1 %var1 1405OpStore %var2 %load1 1406%load2 = OpLoad %struct1 %var2 1407%3 = OpCompositeExtract %uint %load2 0 1408OpReturn 1409OpFunctionEnd 1410 )"; 1411 1412 SinglePassRunAndMatch<ScalarReplacementPass>(text, true); 1413} 1414 1415TEST_F(ScalarReplacementTest, SpecConstantArray) { 1416 const std::string text = R"( 1417; CHECK: [[int:%\w+]] = OpTypeInt 1418; CHECK: [[spec_const:%\w+]] = OpSpecConstant [[int]] 4 1419; CHECK: [[spec_op:%\w+]] = OpSpecConstantOp [[int]] IAdd [[spec_const]] [[spec_const]] 1420; CHECK: [[array1:%\w+]] = OpTypeArray [[int]] [[spec_const]] 1421; CHECK: [[array2:%\w+]] = OpTypeArray [[int]] [[spec_op]] 1422; CHECK: [[ptr_array1:%\w+]] = OpTypePointer Function [[array1]] 1423; CHECK: [[ptr_array2:%\w+]] = OpTypePointer Function [[array2]] 1424; CHECK: OpLabel 1425; CHECK-NEXT: OpVariable [[ptr_array1]] Function 1426; CHECK-NEXT: OpVariable [[ptr_array2]] Function 1427; CHECK-NOT: OpVariable 1428OpCapability Shader 1429OpCapability Linkage 1430OpMemoryModel Logical GLSL450 1431%void = OpTypeVoid 1432%void_fn = OpTypeFunction %void 1433%int = OpTypeInt 32 0 1434%spec_const = OpSpecConstant %int 4 1435%spec_op = OpSpecConstantOp %int IAdd %spec_const %spec_const 1436%array_1 = OpTypeArray %int %spec_const 1437%array_2 = OpTypeArray %int %spec_op 1438%ptr_array_1_Function = OpTypePointer Function %array_1 1439%ptr_array_2_Function = OpTypePointer Function %array_2 1440%func = OpFunction %void None %void_fn 1441%1 = OpLabel 1442%var_1 = OpVariable %ptr_array_1_Function Function 1443%var_2 = OpVariable %ptr_array_2_Function Function 1444OpReturn 1445OpFunctionEnd 1446)"; 1447 1448 SinglePassRunAndMatch<ScalarReplacementPass>(text, true); 1449} 1450 1451TEST_F(ScalarReplacementTest, CreateAmbiguousNullConstant2) { 1452 const std::string text = R"( 1453; 1454; CHECK: [[uint:%\w+]] = OpTypeInt 32 0 1455; CHECK: [[struct1:%\w+]] = OpTypeStruct [[uint]] [[struct_member:%\w+]] 1456; CHECK: [[uint_ptr:%\w+]] = OpTypePointer Function [[uint]] 1457; CHECK: [[const:%\w+]] = OpConstant [[uint]] 0 1458; CHECK: [[undef:%\w+]] = OpUndef [[struct_member]] 1459; CHECK: [[var0a:%\w+]] = OpVariable [[uint_ptr]] Function 1460; CHECK: [[var1:%\w+]] = OpVariable [[uint_ptr]] Function 1461; CHECK: [[var0b:%\w+]] = OpVariable [[uint_ptr]] Function 1462; CHECK: OpStore [[var1]] 1463; CHECK: [[l1:%\w+]] = OpLoad [[uint]] [[var1]] 1464; CHECK: [[c1:%\w+]] = OpCompositeConstruct [[struct1]] [[l1]] [[undef]] 1465; CHECK: [[e1:%\w+]] = OpCompositeExtract [[uint]] [[c1]] 0 1466; 1467OpCapability Shader 1468OpCapability Linkage 1469OpMemoryModel Logical GLSL450 1470OpName %func "replace_whole_load" 1471%void = OpTypeVoid 1472%uint = OpTypeInt 32 0 1473%struct3 = OpTypeStruct %uint 1474%struct2 = OpTypeStruct %uint 1475%struct1 = OpTypeStruct %uint %struct2 1476%uint_ptr = OpTypePointer Function %uint 1477%struct1_ptr = OpTypePointer Function %struct1 1478%uint_0 = OpConstant %uint 0 1479%uint_1 = OpConstant %uint 1 1480%func = OpTypeFunction %void 1481%1 = OpFunction %void None %func 1482%2 = OpLabel 1483%var1 = OpVariable %struct1_ptr Function 1484%var2 = OpVariable %struct1_ptr Function 1485%load1 = OpLoad %struct1 %var1 1486OpStore %var2 %load1 1487%load2 = OpLoad %struct1 %var2 1488%3 = OpCompositeExtract %uint %load2 0 1489OpReturn 1490OpFunctionEnd 1491 )"; 1492 1493 SinglePassRunAndMatch<ScalarReplacementPass>(text, true); 1494} 1495 1496// Test that a struct of size 4 is not replaced when there is a limit of 2. 1497TEST_F(ScalarReplacementTest, TestLimit) { 1498 const std::string text = R"( 1499OpCapability Shader 1500OpCapability Linkage 1501OpMemoryModel Logical GLSL450 1502OpName %6 "simple_struct" 1503%1 = OpTypeVoid 1504%2 = OpTypeInt 32 0 1505%3 = OpTypeStruct %2 %2 %2 %2 1506%4 = OpTypePointer Function %3 1507%5 = OpTypePointer Function %2 1508%6 = OpTypeFunction %2 1509%7 = OpConstantNull %3 1510%8 = OpConstant %2 0 1511%9 = OpConstant %2 1 1512%10 = OpConstant %2 2 1513%11 = OpConstant %2 3 1514%12 = OpFunction %2 None %6 1515%13 = OpLabel 1516%14 = OpVariable %4 Function %7 1517%15 = OpInBoundsAccessChain %5 %14 %8 1518%16 = OpLoad %2 %15 1519%17 = OpAccessChain %5 %14 %10 1520%18 = OpLoad %2 %17 1521%19 = OpIAdd %2 %16 %18 1522OpReturnValue %19 1523OpFunctionEnd 1524 )"; 1525 1526 auto result = 1527 SinglePassRunAndDisassemble<ScalarReplacementPass>(text, true, false, 2); 1528 EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); 1529} 1530 1531// Test that a struct of size 4 is replaced when there is a limit of 0 (no 1532// limit). This is the same spir-v as a test above, so we do not check that it 1533// is correctly transformed. We leave that to the test above. 1534TEST_F(ScalarReplacementTest, TestUnimited) { 1535 const std::string text = R"( 1536OpCapability Shader 1537OpCapability Linkage 1538OpMemoryModel Logical GLSL450 1539OpName %6 "simple_struct" 1540%1 = OpTypeVoid 1541%2 = OpTypeInt 32 0 1542%3 = OpTypeStruct %2 %2 %2 %2 1543%4 = OpTypePointer Function %3 1544%5 = OpTypePointer Function %2 1545%6 = OpTypeFunction %2 1546%7 = OpConstantNull %3 1547%8 = OpConstant %2 0 1548%9 = OpConstant %2 1 1549%10 = OpConstant %2 2 1550%11 = OpConstant %2 3 1551%12 = OpFunction %2 None %6 1552%13 = OpLabel 1553%14 = OpVariable %4 Function %7 1554%15 = OpInBoundsAccessChain %5 %14 %8 1555%16 = OpLoad %2 %15 1556%17 = OpAccessChain %5 %14 %10 1557%18 = OpLoad %2 %17 1558%19 = OpIAdd %2 %16 %18 1559OpReturnValue %19 1560OpFunctionEnd 1561 )"; 1562 1563 auto result = 1564 SinglePassRunAndDisassemble<ScalarReplacementPass>(text, true, false, 0); 1565 EXPECT_EQ(Pass::Status::SuccessWithChange, std::get<1>(result)); 1566} 1567 1568TEST_F(ScalarReplacementTest, AmbigousPointer) { 1569 const std::string text = R"( 1570; CHECK: [[s1:%\w+]] = OpTypeStruct %uint 1571; CHECK: [[s2:%\w+]] = OpTypeStruct %uint 1572; CHECK: [[s3:%\w+]] = OpTypeStruct [[s2]] 1573; CHECK: [[s3_const:%\w+]] = OpConstantComposite [[s3]] 1574; CHECK: [[s2_ptr:%\w+]] = OpTypePointer Function [[s2]] 1575; CHECK: OpCompositeExtract [[s2]] [[s3_const]] 1576 1577 OpCapability Shader 1578 %1 = OpExtInstImport "GLSL.std.450" 1579 OpMemoryModel Logical GLSL450 1580 OpEntryPoint Fragment %2 "main" 1581 OpExecutionMode %2 OriginUpperLeft 1582 OpSource ESSL 310 1583 %void = OpTypeVoid 1584 %5 = OpTypeFunction %void 1585 %uint = OpTypeInt 32 0 1586 %_struct_7 = OpTypeStruct %uint 1587 %_struct_8 = OpTypeStruct %uint 1588 %_struct_9 = OpTypeStruct %_struct_8 1589 %uint_1 = OpConstant %uint 1 1590 %11 = OpConstantComposite %_struct_8 %uint_1 1591 %12 = OpConstantComposite %_struct_9 %11 1592%_ptr_Function__struct_9 = OpTypePointer Function %_struct_9 1593%_ptr_Function__struct_7 = OpTypePointer Function %_struct_7 1594 %2 = OpFunction %void None %5 1595 %15 = OpLabel 1596 %var = OpVariable %_ptr_Function__struct_9 Function 1597 OpStore %var %12 1598 %ld = OpLoad %_struct_9 %var 1599 %ex = OpCompositeExtract %_struct_8 %ld 0 1600 OpReturn 1601 OpFunctionEnd 1602 )"; 1603 1604 SinglePassRunAndMatch<ScalarReplacementPass>(text, true); 1605} 1606 1607// Test that scalar replacement does not crash when there is an OpAccessChain 1608// with no index. If we choose to handle this case in the future, then the 1609// result can change. 1610TEST_F(ScalarReplacementTest, TestAccessChainWithNoIndexes) { 1611 const std::string text = R"( 1612 OpCapability Shader 1613 OpMemoryModel Logical GLSL450 1614 OpEntryPoint Fragment %1 "main" 1615 OpExecutionMode %1 OriginLowerLeft 1616 %void = OpTypeVoid 1617 %3 = OpTypeFunction %void 1618 %float = OpTypeFloat 32 1619 %_struct_5 = OpTypeStruct %float 1620%_ptr_Function__struct_5 = OpTypePointer Function %_struct_5 1621 %1 = OpFunction %void None %3 1622 %7 = OpLabel 1623 %8 = OpVariable %_ptr_Function__struct_5 Function 1624 %9 = OpAccessChain %_ptr_Function__struct_5 %8 1625 OpReturn 1626 OpFunctionEnd 1627 )"; 1628 1629 auto result = 1630 SinglePassRunAndDisassemble<ScalarReplacementPass>(text, true, false); 1631 EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); 1632} 1633 1634// Test that id overflow is handled gracefully. 1635TEST_F(ScalarReplacementTest, IdBoundOverflow1) { 1636 const std::string text = R"( 1637OpCapability ImageQuery 1638OpMemoryModel Logical GLSL450 1639OpEntryPoint Fragment %4 "main" 1640OpExecutionMode %4 OriginUpperLeft 1641OpDecorate %4194302 DescriptorSet 1073495039 1642%2 = OpTypeVoid 1643%3 = OpTypeFunction %2 1644%6 = OpTypeFloat 32 1645%7 = OpTypeStruct %6 %6 1646%557056 = OpTypeStruct %7 1647%9 = OpTypePointer Function %7 1648%18 = OpTypeFunction %7 %9 1649%4 = OpFunction %2 Pure|Const %3 1650%1836763 = OpLabel 1651%4194302 = OpVariable %9 Function 1652%10 = OpVariable %9 Function 1653OpKill 1654%4194301 = OpLabel 1655%524296 = OpLoad %7 %4194302 1656OpKill 1657OpFunctionEnd 1658 )"; 1659 1660 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 1661 1662 std::vector<Message> messages = { 1663 {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}, 1664 {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}}; 1665 SetMessageConsumer(GetTestMessageConsumer(messages)); 1666 auto result = SinglePassRunToBinary<ScalarReplacementPass>(text, true, false); 1667 EXPECT_EQ(Pass::Status::Failure, std::get<1>(result)); 1668} 1669 1670// Test that id overflow is handled gracefully. 1671TEST_F(ScalarReplacementTest, IdBoundOverflow2) { 1672 const std::string text = R"( 1673OpCapability Shader 1674OpMemoryModel Logical GLSL450 1675OpEntryPoint Fragment %4 "main" %17 1676OpExecutionMode %4 OriginUpperLeft 1677%2 = OpTypeVoid 1678%3 = OpTypeFunction %2 1679%6 = OpTypeFloat 32 1680%7 = OpTypeVector %6 4 1681%8 = OpTypeStruct %7 1682%9 = OpTypePointer Function %8 1683%16 = OpTypePointer Output %7 1684%21 = OpTypeInt 32 1 1685%22 = OpConstant %21 0 1686%23 = OpTypePointer Function %7 1687%17 = OpVariable %16 Output 1688%4 = OpFunction %2 None %3 1689%5 = OpLabel 1690%4194300 = OpVariable %23 Function 1691%10 = OpVariable %9 Function 1692%4194301 = OpAccessChain %23 %10 %22 1693%4194302 = OpLoad %7 %4194301 1694OpStore %4194300 %4194302 1695%15 = OpLoad %7 %4194300 1696OpStore %17 %15 1697OpReturn 1698OpFunctionEnd 1699 )"; 1700 1701 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 1702 1703 std::vector<Message> messages = { 1704 {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}}; 1705 SetMessageConsumer(GetTestMessageConsumer(messages)); 1706 auto result = SinglePassRunToBinary<ScalarReplacementPass>(text, true, false); 1707 EXPECT_EQ(Pass::Status::Failure, std::get<1>(result)); 1708} 1709 1710// Test that id overflow is handled gracefully. 1711TEST_F(ScalarReplacementTest, IdBoundOverflow3) { 1712 const std::string text = R"( 1713OpCapability InterpolationFunction 1714OpExtension "z" 1715OpMemoryModel Logical GLSL450 1716OpEntryPoint Fragment %4 "main" 1717OpExecutionMode %4 OriginUpperLeft 1718%2 = OpTypeVoid 1719%3 = OpTypeFunction %2 1720%6 = OpTypeFloat 32 1721%7 = OpTypeStruct %6 %6 1722%9 = OpTypePointer Function %7 1723%18 = OpTypeFunction %7 %9 1724%21 = OpTypeInt 32 0 1725%22 = OpConstant %21 4293000676 1726%4194302 = OpConstantNull %6 1727%4 = OpFunction %2 Inline|Pure %3 1728%786464 = OpLabel 1729%4194298 = OpVariable %9 Function 1730%10 = OpVariable %9 Function 1731%4194299 = OpUDiv %21 %22 %22 1732%4194300 = OpLoad %7 %10 1733%50959 = OpLoad %7 %4194298 1734OpKill 1735OpFunctionEnd 1736%1 = OpFunction %7 None %18 1737%19 = OpFunctionParameter %9 1738%147667 = OpLabel 1739%2044391 = OpUDiv %21 %22 %22 1740%25 = OpLoad %7 %19 1741OpReturnValue %25 1742OpFunctionEnd 1743%4194295 = OpFunction %2 None %3 1744%4194296 = OpLabel 1745OpKill 1746OpFunctionEnd 1747 )"; 1748 1749 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 1750 1751 std::vector<Message> messages = { 1752 {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}, 1753 {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}, 1754 {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}, 1755 {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}, 1756 {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}, 1757 {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}, 1758 {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}, 1759 {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}, 1760 {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}}; 1761 SetMessageConsumer(GetTestMessageConsumer(messages)); 1762 auto result = SinglePassRunToBinary<ScalarReplacementPass>(text, true, false); 1763 EXPECT_EQ(Pass::Status::Failure, std::get<1>(result)); 1764} 1765 1766// Test that replacements for OpAccessChain do not go out of bounds. 1767// https://github.com/KhronosGroup/SPIRV-Tools/issues/2609. 1768TEST_F(ScalarReplacementTest, OutOfBoundOpAccessChain) { 1769 const std::string text = R"( 1770 OpCapability Shader 1771 %1 = OpExtInstImport "GLSL.std.450" 1772 OpMemoryModel Logical GLSL450 1773 OpEntryPoint Fragment %main "main" %_GLF_color 1774 OpExecutionMode %main OriginUpperLeft 1775 OpSource ESSL 310 1776 OpName %main "main" 1777 OpName %a "a" 1778 OpName %_GLF_color "_GLF_color" 1779 OpDecorate %_GLF_color Location 0 1780 %void = OpTypeVoid 1781 %3 = OpTypeFunction %void 1782 %int = OpTypeInt 32 1 1783%_ptr_Function_int = OpTypePointer Function %int 1784 %int_1 = OpConstant %int 1 1785 %float = OpTypeFloat 32 1786 %uint = OpTypeInt 32 0 1787 %uint_1 = OpConstant %uint 1 1788%_arr_float_uint_1 = OpTypeArray %float %uint_1 1789%_ptr_Function__arr_float_uint_1 = OpTypePointer Function %_arr_float_uint_1 1790%_ptr_Function_float = OpTypePointer Function %float 1791%_ptr_Output_float = OpTypePointer Output %float 1792 %_GLF_color = OpVariable %_ptr_Output_float Output 1793 %main = OpFunction %void None %3 1794 %5 = OpLabel 1795 %a = OpVariable %_ptr_Function__arr_float_uint_1 Function 1796 %21 = OpAccessChain %_ptr_Function_float %a %int_1 1797 %22 = OpLoad %float %21 1798 OpStore %_GLF_color %22 1799 OpReturn 1800 OpFunctionEnd 1801 )"; 1802 1803 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 1804 1805 auto result = 1806 SinglePassRunAndDisassemble<ScalarReplacementPass>(text, true, false); 1807 EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); 1808} 1809 1810TEST_F(ScalarReplacementTest, CharIndex) { 1811 const std::string text = R"( 1812; CHECK: [[int:%\w+]] = OpTypeInt 32 0 1813; CHECK: [[ptr:%\w+]] = OpTypePointer Function [[int]] 1814; CHECK: OpVariable [[ptr]] Function 1815OpCapability Shader 1816OpCapability Int8 1817OpMemoryModel Logical GLSL450 1818OpEntryPoint GLCompute %main "main" 1819OpExecutionMode %main LocalSize 1 1 1 1820%void = OpTypeVoid 1821%int = OpTypeInt 32 0 1822%int_1024 = OpConstant %int 1024 1823%char = OpTypeInt 8 0 1824%char_1 = OpConstant %char 1 1825%array = OpTypeArray %int %int_1024 1826%ptr_func_array = OpTypePointer Function %array 1827%ptr_func_int = OpTypePointer Function %int 1828%void_fn = OpTypeFunction %void 1829%main = OpFunction %void None %void_fn 1830%entry = OpLabel 1831%var = OpVariable %ptr_func_array Function 1832%gep = OpAccessChain %ptr_func_int %var %char_1 1833OpStore %gep %int_1024 1834OpReturn 1835OpFunctionEnd 1836)"; 1837 1838 SinglePassRunAndMatch<ScalarReplacementPass>(text, true, 0); 1839} 1840 1841TEST_F(ScalarReplacementTest, OutOfBoundsOpAccessChainNegative) { 1842 const std::string text = R"( 1843OpCapability Shader 1844OpCapability Int8 1845OpMemoryModel Logical GLSL450 1846OpEntryPoint GLCompute %main "main" 1847OpExecutionMode %main LocalSize 1 1 1 1848%void = OpTypeVoid 1849%int = OpTypeInt 32 0 1850%int_1024 = OpConstant %int 1024 1851%char = OpTypeInt 8 1 1852%char_n1 = OpConstant %char -1 1853%array = OpTypeArray %int %int_1024 1854%ptr_func_array = OpTypePointer Function %array 1855%ptr_func_int = OpTypePointer Function %int 1856%void_fn = OpTypeFunction %void 1857%main = OpFunction %void None %void_fn 1858%entry = OpLabel 1859%var = OpVariable %ptr_func_array Function 1860%gep = OpAccessChain %ptr_func_int %var %char_n1 1861OpStore %gep %int_1024 1862OpReturn 1863OpFunctionEnd 1864)"; 1865 1866 auto result = 1867 SinglePassRunAndDisassemble<ScalarReplacementPass>(text, true, true, 0); 1868 EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); 1869} 1870 1871TEST_F(ScalarReplacementTest, RelaxedPrecisionMemberDecoration) { 1872 const std::string text = R"( 1873; CHECK: OpDecorate {{%\w+}} RelaxedPrecision 1874; CHECK: OpDecorate [[new_var:%\w+]] RelaxedPrecision 1875; CHECK: [[new_var]] = OpVariable %_ptr_Function_v3float Function 1876; CHECK: OpLoad %v3float [[new_var]] 1877 OpCapability Shader 1878 OpMemoryModel Logical GLSL450 1879 OpEntryPoint Vertex %1 "Draw2DTexCol_VS" %2 %3 1880 OpSource HLSL 600 1881 OpDecorate %2 Location 0 1882 OpDecorate %3 Location 1 1883 OpDecorate %3 RelaxedPrecision 1884 OpMemberDecorate %_struct_4 1 RelaxedPrecision 1885 %float = OpTypeFloat 32 1886 %int = OpTypeInt 32 1 1887 %int_1 = OpConstant %int 1 1888 %v3float = OpTypeVector %float 3 1889%_ptr_Input_v3float = OpTypePointer Input %v3float 1890 %void = OpTypeVoid 1891 %11 = OpTypeFunction %void 1892 %_struct_4 = OpTypeStruct %v3float %v3float 1893%_ptr_Function__struct_4 = OpTypePointer Function %_struct_4 1894%_ptr_Function_v3float = OpTypePointer Function %v3float 1895 %2 = OpVariable %_ptr_Input_v3float Input 1896 %3 = OpVariable %_ptr_Input_v3float Input 1897 %1 = OpFunction %void None %11 1898 %14 = OpLabel 1899 %15 = OpVariable %_ptr_Function__struct_4 Function 1900 %16 = OpLoad %v3float %2 1901 %17 = OpLoad %v3float %3 1902 %18 = OpCompositeConstruct %_struct_4 %16 %17 1903 OpStore %15 %18 1904 %19 = OpAccessChain %_ptr_Function_v3float %15 %int_1 1905 %20 = OpLoad %v3float %19 1906 OpReturn 1907 OpFunctionEnd 1908)"; 1909 1910 SinglePassRunAndMatch<ScalarReplacementPass>(text, true); 1911} 1912 1913TEST_F(ScalarReplacementTest, DebugDeclare) { 1914 const std::string text = R"( 1915OpCapability Shader 1916OpCapability Linkage 1917%ext = OpExtInstImport "OpenCL.DebugInfo.100" 1918OpMemoryModel Logical GLSL450 1919%test = OpString "test" 1920OpName %6 "simple_struct" 1921%1 = OpTypeVoid 1922%2 = OpTypeInt 32 0 1923%uint_32 = OpConstant %2 32 1924%3 = OpTypeStruct %2 %2 %2 %2 1925%4 = OpTypePointer Function %3 1926%5 = OpTypePointer Function %2 1927%6 = OpTypeFunction %2 1928%7 = OpConstantNull %3 1929%8 = OpConstant %2 0 1930%9 = OpConstant %2 1 1931%10 = OpConstant %2 2 1932%11 = OpConstant %2 3 1933%null_expr = OpExtInst %1 %ext DebugExpression 1934%src = OpExtInst %1 %ext DebugSource %test 1935%cu = OpExtInst %1 %ext DebugCompilationUnit 1 4 %src HLSL 1936%dbg_tf = OpExtInst %1 %ext DebugTypeBasic %test %uint_32 Float 1937%main_ty = OpExtInst %1 %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %1 1938%dbg_main = OpExtInst %1 %ext DebugFunction %test %main_ty %src 0 0 %cu %test FlagIsProtected|FlagIsPrivate 0 %12 1939%dbg_foo = OpExtInst %1 %ext DebugLocalVariable %test %dbg_tf %src 0 0 %dbg_main FlagIsLocal 1940%12 = OpFunction %2 None %6 1941%13 = OpLabel 1942%scope = OpExtInst %1 %ext DebugScope %dbg_main 1943%14 = OpVariable %4 Function %7 1944 1945; CHECK: [[deref:%\w+]] = OpExtInst %void [[ext:%\w+]] DebugOperation Deref 1946; CHECK: [[dbg_local_var:%\w+]] = OpExtInst %void [[ext]] DebugLocalVariable 1947; CHECK: [[deref_expr:%\w+]] = OpExtInst %void [[ext]] DebugExpression [[deref]] 1948; CHECK: [[repl3:%\w+]] = OpVariable %_ptr_Function_uint Function 1949; CHECK: [[repl2:%\w+]] = OpVariable %_ptr_Function_uint Function 1950; CHECK: [[repl1:%\w+]] = OpVariable %_ptr_Function_uint Function 1951; CHECK: [[repl0:%\w+]] = OpVariable %_ptr_Function_uint Function 1952; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl3]] [[deref_expr]] %int_3 1953; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl2]] [[deref_expr]] %int_2 1954; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl1]] [[deref_expr]] %int_1 1955; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl0]] [[deref_expr]] %int_0 1956; CHECK-NOT: DebugDeclare 1957%decl = OpExtInst %1 %ext DebugDeclare %dbg_foo %14 %null_expr 1958 1959%15 = OpInBoundsAccessChain %5 %14 %8 1960%16 = OpLoad %2 %15 1961%17 = OpAccessChain %5 %14 %10 1962%18 = OpLoad %2 %17 1963%19 = OpIAdd %2 %16 %18 1964OpReturnValue %19 1965OpFunctionEnd 1966)"; 1967 1968 SinglePassRunAndMatch<ScalarReplacementPass>(text, true); 1969} 1970 1971TEST_F(ScalarReplacementTest, DebugValue) { 1972 const std::string text = R"( 1973OpCapability Shader 1974OpCapability Linkage 1975%ext = OpExtInstImport "OpenCL.DebugInfo.100" 1976OpMemoryModel Logical GLSL450 1977%test = OpString "test" 1978OpName %6 "simple_struct" 1979%1 = OpTypeVoid 1980%2 = OpTypeInt 32 0 1981%uint_32 = OpConstant %2 32 1982%3 = OpTypeStruct %2 %2 %2 %2 1983%4 = OpTypePointer Function %3 1984%5 = OpTypePointer Function %2 1985%6 = OpTypeFunction %2 1986%7 = OpConstantNull %3 1987%8 = OpConstant %2 0 1988%9 = OpConstant %2 1 1989%10 = OpConstant %2 2 1990%11 = OpConstant %2 3 1991%deref = OpExtInst %1 %ext DebugOperation Deref 1992%deref_expr = OpExtInst %1 %ext DebugExpression %deref 1993%null_expr = OpExtInst %1 %ext DebugExpression 1994%src = OpExtInst %1 %ext DebugSource %test 1995%cu = OpExtInst %1 %ext DebugCompilationUnit 1 4 %src HLSL 1996%dbg_tf = OpExtInst %1 %ext DebugTypeBasic %test %uint_32 Float 1997%main_ty = OpExtInst %1 %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %1 1998%dbg_main = OpExtInst %1 %ext DebugFunction %test %main_ty %src 0 0 %cu %test FlagIsProtected|FlagIsPrivate 0 %12 1999%dbg_foo = OpExtInst %1 %ext DebugLocalVariable %test %dbg_tf %src 0 0 %dbg_main FlagIsLocal 2000%12 = OpFunction %2 None %6 2001%13 = OpLabel 2002%scope = OpExtInst %1 %ext DebugScope %dbg_main 2003%14 = OpVariable %4 Function %7 2004 2005; CHECK: [[deref:%\w+]] = OpExtInst %void [[ext:%\w+]] DebugOperation Deref 2006; CHECK: [[deref_expr:%\w+]] = OpExtInst %void [[ext]] DebugExpression [[deref]] 2007; CHECK: [[dbg_local_var:%\w+]] = OpExtInst %void [[ext]] DebugLocalVariable 2008; CHECK: [[repl3:%\w+]] = OpVariable %_ptr_Function_uint Function 2009; CHECK: [[repl2:%\w+]] = OpVariable %_ptr_Function_uint Function 2010; CHECK: [[repl1:%\w+]] = OpVariable %_ptr_Function_uint Function 2011; CHECK: [[repl0:%\w+]] = OpVariable %_ptr_Function_uint Function 2012; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl0]] [[deref_expr]] %int_0 2013; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl1]] [[deref_expr]] %int_1 2014; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl2]] [[deref_expr]] %int_2 2015; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl3]] [[deref_expr]] %int_3 2016%value = OpExtInst %1 %ext DebugValue %dbg_foo %14 %deref_expr 2017 2018%15 = OpInBoundsAccessChain %5 %14 %8 2019%16 = OpLoad %2 %15 2020%17 = OpAccessChain %5 %14 %10 2021%18 = OpLoad %2 %17 2022%19 = OpIAdd %2 %16 %18 2023OpReturnValue %19 2024OpFunctionEnd 2025)"; 2026 2027 SinglePassRunAndMatch<ScalarReplacementPass>(text, true); 2028} 2029 2030TEST_F(ScalarReplacementTest, DebugDeclareRecursive) { 2031 const std::string text = R"( 2032OpCapability Shader 2033OpCapability Linkage 2034%ext = OpExtInstImport "OpenCL.DebugInfo.100" 2035OpMemoryModel Logical GLSL450 2036%test = OpString "test" 2037OpName %6 "simple_struct" 2038%1 = OpTypeVoid 2039%2 = OpTypeInt 32 0 2040%uint_32 = OpConstant %2 32 2041%float = OpTypeFloat 32 2042%float_1 = OpConstant %float 1 2043%member = OpTypeStruct %2 %float 2044%3 = OpTypeStruct %2 %member %float 2045%4 = OpTypePointer Function %3 2046%5 = OpTypePointer Function %2 2047%ptr_float_Function = OpTypePointer Function %float 2048%6 = OpTypeFunction %2 2049%cmember = OpConstantComposite %member %uint_32 %float_1 2050%7 = OpConstantComposite %3 %uint_32 %cmember %float_1 2051%8 = OpConstant %2 0 2052%9 = OpConstant %2 1 2053%10 = OpConstant %2 2 2054%null_expr = OpExtInst %1 %ext DebugExpression 2055%src = OpExtInst %1 %ext DebugSource %test 2056%cu = OpExtInst %1 %ext DebugCompilationUnit 1 4 %src HLSL 2057%dbg_tf = OpExtInst %1 %ext DebugTypeBasic %test %uint_32 Float 2058%main_ty = OpExtInst %1 %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %1 2059%dbg_main = OpExtInst %1 %ext DebugFunction %test %main_ty %src 0 0 %cu %test FlagIsProtected|FlagIsPrivate 0 %12 2060%dbg_foo = OpExtInst %1 %ext DebugLocalVariable %test %dbg_tf %src 0 0 %dbg_main FlagIsLocal 2061%12 = OpFunction %2 None %6 2062%13 = OpLabel 2063%scope = OpExtInst %1 %ext DebugScope %dbg_main 2064%14 = OpVariable %4 Function %7 2065 2066; CHECK: [[deref:%\w+]] = OpExtInst %void [[ext:%\w+]] DebugOperation Deref 2067; CHECK: [[dbg_local_var:%\w+]] = OpExtInst %void [[ext]] DebugLocalVariable 2068; CHECK: [[deref_expr:%\w+]] = OpExtInst %void [[ext]] DebugExpression [[deref]] 2069; CHECK: [[repl2:%\w+]] = OpVariable %_ptr_Function_float Function %float_1 2070; CHECK: [[repl1:%\w+]] = OpVariable %_ptr_Function_uint Function %uint_32 2071; CHECK: [[repl3:%\w+]] = OpVariable %_ptr_Function_float Function %float_1 2072; CHECK: [[repl0:%\w+]] = OpVariable %_ptr_Function_uint Function %uint_32 2073; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl3]] [[deref_expr]] %int_2 2074; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl1]] [[deref_expr]] %int_1 %int_0 2075; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl2]] [[deref_expr]] %int_1 %int_1 2076; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl0]] [[deref_expr]] %int_0 2077; CHECK-NOT: DebugDeclare 2078%decl = OpExtInst %1 %ext DebugDeclare %dbg_foo %14 %null_expr 2079 2080%15 = OpInBoundsAccessChain %5 %14 %8 2081%16 = OpLoad %2 %15 2082%17 = OpAccessChain %ptr_float_Function %14 %10 2083%18 = OpLoad %float %17 2084%value = OpConvertFToU %2 %18 2085%19 = OpIAdd %2 %16 %value 2086OpReturnValue %19 2087OpFunctionEnd 2088)"; 2089 2090 SinglePassRunAndMatch<ScalarReplacementPass>(text, true); 2091} 2092 2093TEST_F(ScalarReplacementTest, DebugValueWithIndex) { 2094 const std::string text = R"( 2095OpCapability Shader 2096OpCapability Linkage 2097%ext = OpExtInstImport "OpenCL.DebugInfo.100" 2098OpMemoryModel Logical GLSL450 2099%test = OpString "test" 2100OpName %6 "simple_struct" 2101%1 = OpTypeVoid 2102%2 = OpTypeInt 32 0 2103%uint_32 = OpConstant %2 32 2104%3 = OpTypeStruct %2 %2 %2 %2 2105%4 = OpTypePointer Function %3 2106%5 = OpTypePointer Function %2 2107%6 = OpTypeFunction %2 2108%7 = OpConstantNull %3 2109%8 = OpConstant %2 0 2110%9 = OpConstant %2 1 2111%10 = OpConstant %2 2 2112%11 = OpConstant %2 3 2113%deref = OpExtInst %1 %ext DebugOperation Deref 2114%deref_expr = OpExtInst %1 %ext DebugExpression %deref 2115%null_expr = OpExtInst %1 %ext DebugExpression 2116%src = OpExtInst %1 %ext DebugSource %test 2117%cu = OpExtInst %1 %ext DebugCompilationUnit 1 4 %src HLSL 2118%dbg_tf = OpExtInst %1 %ext DebugTypeBasic %test %uint_32 Float 2119%main_ty = OpExtInst %1 %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %1 2120%dbg_main = OpExtInst %1 %ext DebugFunction %test %main_ty %src 0 0 %cu %test FlagIsProtected|FlagIsPrivate 0 %12 2121%dbg_foo = OpExtInst %1 %ext DebugLocalVariable %test %dbg_tf %src 0 0 %dbg_main FlagIsLocal 2122%12 = OpFunction %2 None %6 2123%13 = OpLabel 2124%scope = OpExtInst %1 %ext DebugScope %dbg_main 2125%14 = OpVariable %4 Function %7 2126 2127; CHECK: [[deref:%\w+]] = OpExtInst %void [[ext:%\w+]] DebugOperation Deref 2128; CHECK: [[deref_expr:%\w+]] = OpExtInst %void [[ext]] DebugExpression [[deref]] 2129; CHECK: [[dbg_local_var:%\w+]] = OpExtInst %void [[ext]] DebugLocalVariable 2130; CHECK: [[repl3:%\w+]] = OpVariable %_ptr_Function_uint Function 2131; CHECK: [[repl2:%\w+]] = OpVariable %_ptr_Function_uint Function 2132; CHECK: [[repl1:%\w+]] = OpVariable %_ptr_Function_uint Function 2133; CHECK: [[repl0:%\w+]] = OpVariable %_ptr_Function_uint Function 2134; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl0]] [[deref_expr]] %uint_0 %uint_1 %uint_2 %int_0 2135; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl1]] [[deref_expr]] %uint_0 %uint_1 %uint_2 %int_1 2136; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl2]] [[deref_expr]] %uint_0 %uint_1 %uint_2 %int_2 2137; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl3]] [[deref_expr]] %uint_0 %uint_1 %uint_2 %int_3 2138%value = OpExtInst %1 %ext DebugValue %dbg_foo %14 %deref_expr %8 %9 %10 2139 2140%15 = OpInBoundsAccessChain %5 %14 %8 2141%16 = OpLoad %2 %15 2142%17 = OpAccessChain %5 %14 %10 2143%18 = OpLoad %2 %17 2144%19 = OpIAdd %2 %16 %18 2145OpReturnValue %19 2146OpFunctionEnd 2147)"; 2148 2149 SinglePassRunAndMatch<ScalarReplacementPass>(text, true); 2150} 2151 2152TEST_F(ScalarReplacementTest, DebugDeclareForVariableInOtherBB) { 2153 const std::string text = R"( 2154OpCapability Shader 2155OpCapability Linkage 2156%ext = OpExtInstImport "OpenCL.DebugInfo.100" 2157OpMemoryModel Logical GLSL450 2158%test = OpString "test" 2159OpName %6 "simple_struct" 2160%1 = OpTypeVoid 2161%2 = OpTypeInt 32 0 2162%uint_32 = OpConstant %2 32 2163%3 = OpTypeStruct %2 %2 %2 %2 2164%4 = OpTypePointer Function %3 2165%5 = OpTypePointer Function %2 2166%6 = OpTypeFunction %2 2167%7 = OpConstantNull %3 2168%8 = OpConstant %2 0 2169%9 = OpConstant %2 1 2170%10 = OpConstant %2 2 2171%11 = OpConstant %2 3 2172%deref = OpExtInst %1 %ext DebugOperation Deref 2173%deref_expr = OpExtInst %1 %ext DebugExpression %deref 2174%null_expr = OpExtInst %1 %ext DebugExpression 2175%src = OpExtInst %1 %ext DebugSource %test 2176%cu = OpExtInst %1 %ext DebugCompilationUnit 1 4 %src HLSL 2177%dbg_tf = OpExtInst %1 %ext DebugTypeBasic %test %uint_32 Float 2178%main_ty = OpExtInst %1 %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %1 2179%dbg_main = OpExtInst %1 %ext DebugFunction %test %main_ty %src 0 0 %cu %test FlagIsProtected|FlagIsPrivate 0 %12 2180%dbg_foo = OpExtInst %1 %ext DebugLocalVariable %test %dbg_tf %src 0 0 %dbg_main FlagIsLocal 2181%12 = OpFunction %2 None %6 2182%13 = OpLabel 2183%scope = OpExtInst %1 %ext DebugScope %dbg_main 2184%14 = OpVariable %4 Function %7 2185 2186; CHECK: [[dbg_local_var:%\w+]] = OpExtInst %void [[ext:%\w+]] DebugLocalVariable 2187; CHECK: [[repl3:%\w+]] = OpVariable %_ptr_Function_uint Function 2188; CHECK: [[repl2:%\w+]] = OpVariable %_ptr_Function_uint Function 2189; CHECK: [[repl1:%\w+]] = OpVariable %_ptr_Function_uint Function 2190; CHECK: [[repl0:%\w+]] = OpVariable %_ptr_Function_uint Function 2191; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl3]] [[deref_expr:%\w+]] %int_3 2192; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl2]] [[deref_expr]] %int_2 2193; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl1]] [[deref_expr]] %int_1 2194; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_local_var]] [[repl0]] [[deref_expr]] %int_0 2195 2196OpBranch %20 2197%20 = OpLabel 2198%value = OpExtInst %1 %ext DebugDeclare %dbg_foo %14 %null_expr 2199%15 = OpInBoundsAccessChain %5 %14 %8 2200%16 = OpLoad %2 %15 2201%17 = OpAccessChain %5 %14 %10 2202%18 = OpLoad %2 %17 2203%19 = OpIAdd %2 %16 %18 2204OpReturnValue %19 2205OpFunctionEnd 2206)"; 2207 2208 SinglePassRunAndMatch<ScalarReplacementPass>(text, true); 2209} 2210 2211TEST_F(ScalarReplacementTest, ImageTexelPointer) { 2212 // Test whether the scalar replacement correctly checks the 2213 // OpImageTexelPointer user of an aggregate with an image type. 2214 const std::string text = R"( 2215; 2216; CHECK: [[imgTy:%\w+]] = OpTypeImage %uint Buffer 2 0 0 2 R32ui 2217; CHECK: [[ptrImgTy:%\w+]] = OpTypePointer Function [[imgTy]] 2218; CHECK: [[img:%\w+]] = OpVariable [[ptrImgTy]] Function 2219; CHECK: [[imgTexelPtr:%\w+]] = OpImageTexelPointer {{%\w+}} [[img]] %uint_0 %uint_0 2220; CHECK: OpAtomicIAdd %uint [[imgTexelPtr]] %uint_1 %uint_0 %uint_1 2221; 2222OpCapability Shader 2223OpCapability SampledBuffer 2224OpCapability ImageBuffer 2225OpMemoryModel Logical GLSL450 2226OpEntryPoint GLCompute %1 "main" 2227OpExecutionMode %1 LocalSize 64 1 1 2228%void = OpTypeVoid 2229%uint = OpTypeInt 32 0 2230%uint_0 = OpConstant %uint 0 2231%uint_1 = OpConstant %uint 1 2232%_ptr_Image_uint = OpTypePointer Image %uint 2233%type_buffer_image = OpTypeImage %uint Buffer 2 0 0 2 R32ui 2234%_ptr_Function_type_buffer_image = OpTypePointer Function %type_buffer_image 2235%image_struct = OpTypeStruct %type_buffer_image %type_buffer_image 2236%_ptr_Function_image_struct = OpTypePointer Function %image_struct 2237%func = OpTypeFunction %void 2238%1 = OpFunction %void None %func 2239%2 = OpLabel 2240%3 = OpVariable %_ptr_Function_image_struct Function 2241%4 = OpAccessChain %_ptr_Function_type_buffer_image %3 %uint_1 2242%5 = OpImageTexelPointer %_ptr_Image_uint %4 %uint_0 %uint_0 2243%6 = OpAtomicIAdd %uint %5 %uint_1 %uint_0 %uint_1 2244OpReturn 2245OpFunctionEnd 2246 )"; 2247 2248 SinglePassRunAndMatch<ScalarReplacementPass>(text, false); 2249} 2250 2251TEST_F(ScalarReplacementTest, FunctionDeclaration) { 2252 // Make sure the pass works with a function declaration that is called. 2253 const std::string text = R"(OpCapability Addresses 2254OpCapability Linkage 2255OpCapability Kernel 2256OpCapability Int8 2257%1 = OpExtInstImport "OpenCL.std" 2258OpMemoryModel Physical64 OpenCL 2259OpEntryPoint Kernel %2 "_Z23julia__1166_kernel_77094Bool" 2260OpExecutionMode %2 ContractionOff 2261OpSource Unknown 0 2262OpDecorate %3 LinkageAttributes "julia_error_7712" Import 2263%void = OpTypeVoid 2264%5 = OpTypeFunction %void 2265%3 = OpFunction %void None %5 2266OpFunctionEnd 2267%2 = OpFunction %void None %5 2268%6 = OpLabel 2269%7 = OpFunctionCall %void %3 2270OpReturn 2271OpFunctionEnd 2272)"; 2273 2274 SinglePassRunAndCheck<ScalarReplacementPass>(text, text, false); 2275} 2276 2277TEST_F(ScalarReplacementTest, UndefImageMember) { 2278 // Test that scalar replacement creates an undef for a type that cannot have 2279 // and OpConstantNull. 2280 const std::string text = R"( 2281; CHECK: [[image_type:%\w+]] = OpTypeSampledImage {{%\w+}} 2282; CHECK: [[struct_type:%\w+]] = OpTypeStruct [[image_type]] 2283; CHECK: [[undef:%\w+]] = OpUndef [[image_type]] 2284; CHECK: {{%\w+}} = OpCompositeConstruct [[struct_type]] [[undef]] 2285 OpCapability Shader 2286 %1 = OpExtInstImport "GLSL.std.450" 2287 OpMemoryModel Logical GLSL450 2288 OpEntryPoint Fragment %2 "main" 2289 OpExecutionMode %2 OriginUpperLeft 2290 %void = OpTypeVoid 2291 %4 = OpTypeFunction %void 2292 %float = OpTypeFloat 32 2293 %6 = OpTypeImage %float 2D 0 0 0 1 Unknown 2294 %7 = OpTypeSampledImage %6 2295 %_struct_8 = OpTypeStruct %7 2296 %9 = OpTypeFunction %_struct_8 2297 %10 = OpUndef %_struct_8 2298%_ptr_Function__struct_8 = OpTypePointer Function %_struct_8 2299 %2 = OpFunction %void None %4 2300 %11 = OpLabel 2301 %16 = OpVariable %_ptr_Function__struct_8 Function 2302 OpStore %16 %10 2303 %12 = OpLoad %_struct_8 %16 2304 OpReturn 2305 OpFunctionEnd 2306 )"; 2307 2308 SinglePassRunAndMatch<ScalarReplacementPass>(text, true); 2309} 2310 2311TEST_F(ScalarReplacementTest, RestrictPointer) { 2312 // This test makes sure that a variable with the restrict pointer decoration 2313 // is replaced, and that the pointer is applied to the new variable. 2314 const std::string text = R"( 2315; CHECK: OpDecorate [[new_var:%\w+]] RestrictPointer 2316; CHECK: [[struct_type:%\w+]] = OpTypeStruct %int 2317; CHECK: [[ptr_type:%\w+]] = OpTypePointer PhysicalStorageBuffer [[struct_type]] 2318; CHECK: [[dup_struct_type:%\w+]] = OpTypeStruct %int 2319; CHECK: {{%\w+}} = OpTypePointer PhysicalStorageBuffer [[dup_struct_type]] 2320; CHECK: [[var_type:%\w+]] = OpTypePointer Function [[ptr_type]] 2321; CHECK: [[new_var]] = OpVariable [[var_type]] Function 2322 OpCapability Shader 2323 OpCapability PhysicalStorageBufferAddresses 2324 %1 = OpExtInstImport "GLSL.std.450" 2325 OpMemoryModel PhysicalStorageBuffer64 GLSL450 2326 OpEntryPoint Fragment %2 "main" 2327 OpExecutionMode %2 OriginUpperLeft 2328 OpMemberDecorate %3 0 Offset 0 2329 OpDecorate %3 Block 2330 OpMemberDecorate %4 0 Offset 0 2331 OpDecorate %4 Block 2332 OpDecorate %5 RestrictPointer 2333 %6 = OpTypeVoid 2334 %7 = OpTypeFunction %6 2335 %8 = OpTypeInt 32 1 2336 %9 = OpConstant %8 0 2337 %3 = OpTypeStruct %8 2338 %10 = OpTypePointer PhysicalStorageBuffer %3 2339 %11 = OpTypeStruct %10 2340 %4 = OpTypeStruct %8 2341 %12 = OpTypePointer PhysicalStorageBuffer %4 2342 %13 = OpTypePointer Function %11 2343 %14 = OpTypePointer Function %10 2344 %15 = OpTypePointer Function %12 2345 %16 = OpUndef %11 2346 %2 = OpFunction %6 None %7 2347 %17 = OpLabel 2348 %5 = OpVariable %13 Function 2349 OpStore %5 %16 2350 %18 = OpAccessChain %14 %5 %9 2351 OpReturn 2352 OpFunctionEnd 2353 )"; 2354 2355 SetTargetEnv(SPV_ENV_UNIVERSAL_1_6); 2356 SinglePassRunAndMatch<ScalarReplacementPass>(text, true); 2357} 2358 2359} // namespace 2360} // namespace opt 2361} // namespace spvtools 2362