1// Copyright (c) 2019 Google LLC 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15#include "assembly_builder.h" 16#include "pass_fixture.h" 17#include "pass_utils.h" 18 19namespace { 20 21using namespace spvtools; 22 23using EliminateDeadMemberTest = opt::PassTest<::testing::Test>; 24 25TEST_F(EliminateDeadMemberTest, RemoveMember1) { 26 // Test that the member "y" is removed. 27 // Update OpMemberName for |y| and |z|. 28 // Update OpMemberDecorate for |y| and |z|. 29 // Update OpAccessChain for access to |z|. 30 const std::string text = R"( 31; CHECK: OpName 32; CHECK-NEXT: OpMemberName %type__Globals 0 "x" 33; CHECK-NEXT: OpMemberName %type__Globals 1 "z" 34; CHECK-NOT: OpMemberName 35; CHECK: OpMemberDecorate %type__Globals 0 Offset 0 36; CHECK: OpMemberDecorate %type__Globals 1 Offset 8 37; CHECK: %type__Globals = OpTypeStruct %float %float 38; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals %int_0 39; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals %uint_1 40 OpCapability Shader 41 OpMemoryModel Logical GLSL450 42 OpEntryPoint Vertex %main "main" %in_var_Position %gl_Position 43 OpSource HLSL 600 44 OpName %type__Globals "type.$Globals" 45 OpMemberName %type__Globals 0 "x" 46 OpMemberName %type__Globals 1 "y" 47 OpMemberName %type__Globals 2 "z" 48 OpName %_Globals "$Globals" 49 OpName %in_var_Position "in.var.Position" 50 OpName %main "main" 51 OpDecorate %gl_Position BuiltIn Position 52 OpDecorate %in_var_Position Location 0 53 OpDecorate %_Globals DescriptorSet 0 54 OpDecorate %_Globals Binding 0 55 OpMemberDecorate %type__Globals 0 Offset 0 56 OpMemberDecorate %type__Globals 1 Offset 4 57 OpMemberDecorate %type__Globals 2 Offset 8 58 OpDecorate %type__Globals Block 59 %int = OpTypeInt 32 1 60 %int_0 = OpConstant %int 0 61 %float = OpTypeFloat 32 62 %int_2 = OpConstant %int 2 63%type__Globals = OpTypeStruct %float %float %float 64%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals 65 %v4float = OpTypeVector %float 4 66%_ptr_Input_v4float = OpTypePointer Input %v4float 67%_ptr_Output_v4float = OpTypePointer Output %v4float 68 %void = OpTypeVoid 69 %15 = OpTypeFunction %void 70%_ptr_Uniform_float = OpTypePointer Uniform %float 71 %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform 72%in_var_Position = OpVariable %_ptr_Input_v4float Input 73%gl_Position = OpVariable %_ptr_Output_v4float Output 74 %main = OpFunction %void None %15 75 %17 = OpLabel 76 %18 = OpLoad %v4float %in_var_Position 77 %19 = OpAccessChain %_ptr_Uniform_float %_Globals %int_0 78 %20 = OpLoad %float %19 79 %21 = OpCompositeExtract %float %18 0 80 %22 = OpFAdd %float %21 %20 81 %23 = OpCompositeInsert %v4float %22 %18 0 82 %24 = OpCompositeExtract %float %18 1 83 %25 = OpCompositeInsert %v4float %24 %23 1 84 %26 = OpAccessChain %_ptr_Uniform_float %_Globals %int_2 85 %27 = OpLoad %float %26 86 %28 = OpCompositeExtract %float %18 2 87 %29 = OpFAdd %float %28 %27 88 %30 = OpCompositeInsert %v4float %29 %25 2 89 OpStore %gl_Position %30 90 OpReturn 91 OpFunctionEnd 92)"; 93 94 SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true); 95} 96 97TEST_F(EliminateDeadMemberTest, RemoveMemberWithGroupDecorations) { 98 // Test that the member "y" is removed. 99 // Update OpGroupMemberDecorate for %type__Globals member 1 and 2. 100 // Update OpAccessChain for access to %type__Globals member 2. 101 const std::string text = R"( 102; CHECK: OpDecorate [[gr1:%\w+]] Offset 0 103; CHECK: OpDecorate [[gr2:%\w+]] Offset 4 104; CHECK: OpDecorate [[gr3:%\w+]] Offset 8 105; CHECK: [[gr1]] = OpDecorationGroup 106; CHECK: [[gr2]] = OpDecorationGroup 107; CHECK: [[gr3]] = OpDecorationGroup 108; CHECK: OpGroupMemberDecorate [[gr1]] %type__Globals 0 109; CHECK-NOT: OpGroupMemberDecorate [[gr2]] 110; CHECK: OpGroupMemberDecorate [[gr3]] %type__Globals 1 111; CHECK: %type__Globals = OpTypeStruct %float %float 112; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals %int_0 113; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals %uint_1 114 OpCapability Shader 115 OpMemoryModel Logical GLSL450 116 OpEntryPoint Vertex %main "main" %in_var_Position %gl_Position 117 OpSource HLSL 600 118 OpName %type__Globals "type.$Globals" 119 OpName %_Globals "$Globals" 120 OpDecorate %gl_Position BuiltIn Position 121 OpDecorate %in_var_Position Location 0 122 OpDecorate %_Globals DescriptorSet 0 123 OpDecorate %_Globals Binding 0 124 OpDecorate %gr1 Offset 0 125 OpDecorate %gr2 Offset 4 126 OpDecorate %gr3 Offset 8 127 OpDecorate %type__Globals Block 128 %gr1 = OpDecorationGroup 129 %gr2 = OpDecorationGroup 130 %gr3 = OpDecorationGroup 131 OpGroupMemberDecorate %gr1 %type__Globals 0 132 OpGroupMemberDecorate %gr2 %type__Globals 1 133 OpGroupMemberDecorate %gr3 %type__Globals 2 134 %int = OpTypeInt 32 1 135 %int_0 = OpConstant %int 0 136 %float = OpTypeFloat 32 137 %int_2 = OpConstant %int 2 138%type__Globals = OpTypeStruct %float %float %float 139%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals 140 %v4float = OpTypeVector %float 4 141%_ptr_Input_v4float = OpTypePointer Input %v4float 142%_ptr_Output_v4float = OpTypePointer Output %v4float 143 %void = OpTypeVoid 144 %15 = OpTypeFunction %void 145%_ptr_Uniform_float = OpTypePointer Uniform %float 146 %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform 147%in_var_Position = OpVariable %_ptr_Input_v4float Input 148%gl_Position = OpVariable %_ptr_Output_v4float Output 149 %main = OpFunction %void None %15 150 %17 = OpLabel 151 %18 = OpLoad %v4float %in_var_Position 152 %19 = OpAccessChain %_ptr_Uniform_float %_Globals %int_0 153 %20 = OpLoad %float %19 154 %21 = OpCompositeExtract %float %18 0 155 %22 = OpFAdd %float %21 %20 156 %23 = OpCompositeInsert %v4float %22 %18 0 157 %24 = OpCompositeExtract %float %18 1 158 %25 = OpCompositeInsert %v4float %24 %23 1 159 %26 = OpAccessChain %_ptr_Uniform_float %_Globals %int_2 160 %27 = OpLoad %float %26 161 %28 = OpCompositeExtract %float %18 2 162 %29 = OpFAdd %float %28 %27 163 %30 = OpCompositeInsert %v4float %29 %25 2 164 OpStore %gl_Position %30 165 OpReturn 166 OpFunctionEnd 167)"; 168 169 // Skipping validation because of a bug in the validator. See issue #2376. 170 SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, false); 171} 172 173TEST_F(EliminateDeadMemberTest, RemoveMemberUpdateConstant) { 174 // Test that the member "x" is removed. 175 // Update the OpConstantComposite instruction. 176 const std::string text = R"( 177; CHECK: OpName 178; CHECK-NEXT: OpMemberName %type__Globals 0 "y" 179; CHECK-NEXT: OpMemberName %type__Globals 1 "z" 180; CHECK-NOT: OpMemberName 181; CHECK: OpMemberDecorate %type__Globals 0 Offset 4 182; CHECK: OpMemberDecorate %type__Globals 1 Offset 8 183; CHECK: %type__Globals = OpTypeStruct %float %float 184; CHECK: OpConstantComposite %type__Globals %float_1 %float_2 185; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals %uint_0 186; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals %uint_1 187 OpCapability Shader 188 OpMemoryModel Logical GLSL450 189 OpEntryPoint Vertex %main "main" %in_var_Position %gl_Position 190 OpSource HLSL 600 191 OpName %type__Globals "type.$Globals" 192 OpMemberName %type__Globals 0 "x" 193 OpMemberName %type__Globals 1 "y" 194 OpMemberName %type__Globals 2 "z" 195 OpName %_Globals "$Globals" 196 OpName %in_var_Position "in.var.Position" 197 OpName %main "main" 198 OpDecorate %gl_Position BuiltIn Position 199 OpDecorate %in_var_Position Location 0 200 OpDecorate %_Globals DescriptorSet 0 201 OpDecorate %_Globals Binding 0 202 OpMemberDecorate %type__Globals 0 Offset 0 203 OpMemberDecorate %type__Globals 1 Offset 4 204 OpMemberDecorate %type__Globals 2 Offset 8 205 OpDecorate %type__Globals Block 206 %int = OpTypeInt 32 1 207 %int_1 = OpConstant %int 1 208 %float = OpTypeFloat 32 209 %float_0 = OpConstant %float 0 210 %float_1 = OpConstant %float 1 211 %float_2 = OpConstant %float 2 212 %int_2 = OpConstant %int 2 213%type__Globals = OpTypeStruct %float %float %float 214 %13 = OpConstantComposite %type__Globals %float_0 %float_1 %float_2 215%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals 216 %v4float = OpTypeVector %float 4 217%_ptr_Input_v4float = OpTypePointer Input %v4float 218%_ptr_Output_v4float = OpTypePointer Output %v4float 219 %void = OpTypeVoid 220 %19 = OpTypeFunction %void 221%_ptr_Uniform_float = OpTypePointer Uniform %float 222 %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform 223%in_var_Position = OpVariable %_ptr_Input_v4float Input 224%gl_Position = OpVariable %_ptr_Output_v4float Output 225 %main = OpFunction %void None %19 226 %21 = OpLabel 227 %22 = OpLoad %v4float %in_var_Position 228 %23 = OpAccessChain %_ptr_Uniform_float %_Globals %int_1 229 %24 = OpLoad %float %23 230 %25 = OpCompositeExtract %float %22 0 231 %26 = OpFAdd %float %25 %24 232 %27 = OpCompositeInsert %v4float %26 %22 0 233 %28 = OpCompositeExtract %float %22 1 234 %29 = OpCompositeInsert %v4float %28 %27 1 235 %30 = OpAccessChain %_ptr_Uniform_float %_Globals %int_2 236 %31 = OpLoad %float %30 237 %32 = OpCompositeExtract %float %22 2 238 %33 = OpFAdd %float %32 %31 239 %34 = OpCompositeInsert %v4float %33 %29 2 240 OpStore %gl_Position %34 241 OpReturn 242 OpFunctionEnd 243)"; 244 245 SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true); 246} 247 248TEST_F(EliminateDeadMemberTest, RemoveMemberUpdateCompositeConstruct) { 249 // Test that the member "x" is removed. 250 // Update the OpConstantComposite instruction. 251 const std::string text = R"( 252; CHECK: OpName 253; CHECK-NEXT: OpMemberName %type__Globals 0 "y" 254; CHECK-NEXT: OpMemberName %type__Globals 1 "z" 255; CHECK-NOT: OpMemberName 256; CHECK: OpMemberDecorate %type__Globals 0 Offset 4 257; CHECK: OpMemberDecorate %type__Globals 1 Offset 8 258; CHECK: %type__Globals = OpTypeStruct %float %float 259; CHECK: OpCompositeConstruct %type__Globals %float_1 %float_2 260; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals %uint_0 261; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals %uint_1 262 OpCapability Shader 263 OpMemoryModel Logical GLSL450 264 OpEntryPoint Vertex %main "main" %in_var_Position %gl_Position 265 OpSource HLSL 600 266 OpName %type__Globals "type.$Globals" 267 OpMemberName %type__Globals 0 "x" 268 OpMemberName %type__Globals 1 "y" 269 OpMemberName %type__Globals 2 "z" 270 OpName %_Globals "$Globals" 271 OpName %in_var_Position "in.var.Position" 272 OpName %main "main" 273 OpDecorate %gl_Position BuiltIn Position 274 OpDecorate %in_var_Position Location 0 275 OpDecorate %_Globals DescriptorSet 0 276 OpDecorate %_Globals Binding 0 277 OpMemberDecorate %type__Globals 0 Offset 0 278 OpMemberDecorate %type__Globals 1 Offset 4 279 OpMemberDecorate %type__Globals 2 Offset 8 280 OpDecorate %type__Globals Block 281 %int = OpTypeInt 32 1 282 %int_1 = OpConstant %int 1 283 %float = OpTypeFloat 32 284 %float_0 = OpConstant %float 0 285 %float_1 = OpConstant %float 1 286 %float_2 = OpConstant %float 2 287 %int_2 = OpConstant %int 2 288%type__Globals = OpTypeStruct %float %float %float 289%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals 290 %v4float = OpTypeVector %float 4 291%_ptr_Input_v4float = OpTypePointer Input %v4float 292%_ptr_Output_v4float = OpTypePointer Output %v4float 293 %void = OpTypeVoid 294 %19 = OpTypeFunction %void 295%_ptr_Uniform_float = OpTypePointer Uniform %float 296 %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform 297%in_var_Position = OpVariable %_ptr_Input_v4float Input 298%gl_Position = OpVariable %_ptr_Output_v4float Output 299 %main = OpFunction %void None %19 300 %21 = OpLabel 301 %13 = OpCompositeConstruct %type__Globals %float_0 %float_1 %float_2 302 %22 = OpLoad %v4float %in_var_Position 303 %23 = OpAccessChain %_ptr_Uniform_float %_Globals %int_1 304 %24 = OpLoad %float %23 305 %25 = OpCompositeExtract %float %22 0 306 %26 = OpFAdd %float %25 %24 307 %27 = OpCompositeInsert %v4float %26 %22 0 308 %28 = OpCompositeExtract %float %22 1 309 %29 = OpCompositeInsert %v4float %28 %27 1 310 %30 = OpAccessChain %_ptr_Uniform_float %_Globals %int_2 311 %31 = OpLoad %float %30 312 %32 = OpCompositeExtract %float %22 2 313 %33 = OpFAdd %float %32 %31 314 %34 = OpCompositeInsert %v4float %33 %29 2 315 OpStore %gl_Position %34 316 OpReturn 317 OpFunctionEnd 318)"; 319 320 SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true); 321} 322 323TEST_F(EliminateDeadMemberTest, RemoveMembersUpdateInserExtract1) { 324 // Test that the members "x" and "z" are removed. 325 // Update the OpCompositeExtract instruction. 326 // Remove the OpCompositeInsert instruction since the member being inserted is 327 // dead. 328 const std::string text = R"( 329; CHECK: OpName 330; CHECK-NEXT: OpMemberName %type__Globals 0 "y" 331; CHECK-NOT: OpMemberName 332; CHECK: OpMemberDecorate %type__Globals 0 Offset 4 333; CHECK-NOT: OpMemberDecorate %type__Globals 1 Offset 334; CHECK: %type__Globals = OpTypeStruct %float 335; CHECK: [[ld:%\w+]] = OpLoad %type__Globals %_Globals 336; CHECK: OpCompositeExtract %float [[ld]] 0 337; CHECK-NOT: OpCompositeInsert 338; CHECK: OpReturn 339 OpCapability Shader 340 OpMemoryModel Logical GLSL450 341 OpEntryPoint Vertex %main "main" 342 OpSource HLSL 600 343 OpName %type__Globals "type.$Globals" 344 OpMemberName %type__Globals 0 "x" 345 OpMemberName %type__Globals 1 "y" 346 OpMemberName %type__Globals 2 "z" 347 OpName %_Globals "$Globals" 348 OpName %main "main" 349 OpDecorate %_Globals DescriptorSet 0 350 OpDecorate %_Globals Binding 0 351 OpMemberDecorate %type__Globals 0 Offset 0 352 OpMemberDecorate %type__Globals 1 Offset 4 353 OpMemberDecorate %type__Globals 2 Offset 8 354 OpDecorate %type__Globals Block 355 %float = OpTypeFloat 32 356%type__Globals = OpTypeStruct %float %float %float 357%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals 358 %void = OpTypeVoid 359 %7 = OpTypeFunction %void 360 %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform 361 %main = OpFunction %void None %7 362 %8 = OpLabel 363 %9 = OpLoad %type__Globals %_Globals 364 %10 = OpCompositeExtract %float %9 1 365 %11 = OpCompositeInsert %type__Globals %10 %9 2 366 OpReturn 367 OpFunctionEnd 368 369)"; 370 371 SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true); 372} 373 374TEST_F(EliminateDeadMemberTest, RemoveMembersUpdateInserExtract2) { 375 // Test that the members "x" and "z" are removed. 376 // Update the OpCompositeExtract instruction. 377 // Update the OpCompositeInsert instruction. 378 const std::string text = R"( 379; CHECK: OpName 380; CHECK-NEXT: OpMemberName %type__Globals 0 "y" 381; CHECK-NOT: OpMemberName 382; CHECK: OpMemberDecorate %type__Globals 0 Offset 4 383; CHECK-NOT: OpMemberDecorate %type__Globals 1 Offset 384; CHECK: %type__Globals = OpTypeStruct %float 385; CHECK: [[ld:%\w+]] = OpLoad %type__Globals %_Globals 386; CHECK: [[ex:%\w+]] = OpCompositeExtract %float [[ld]] 0 387; CHECK: OpCompositeInsert %type__Globals [[ex]] [[ld]] 0 388; CHECK: OpReturn 389 OpCapability Shader 390 OpMemoryModel Logical GLSL450 391 OpEntryPoint Vertex %main "main" 392 OpSource HLSL 600 393 OpName %type__Globals "type.$Globals" 394 OpMemberName %type__Globals 0 "x" 395 OpMemberName %type__Globals 1 "y" 396 OpMemberName %type__Globals 2 "z" 397 OpName %_Globals "$Globals" 398 OpName %main "main" 399 OpDecorate %_Globals DescriptorSet 0 400 OpDecorate %_Globals Binding 0 401 OpMemberDecorate %type__Globals 0 Offset 0 402 OpMemberDecorate %type__Globals 1 Offset 4 403 OpMemberDecorate %type__Globals 2 Offset 8 404 OpDecorate %type__Globals Block 405 %float = OpTypeFloat 32 406%type__Globals = OpTypeStruct %float %float %float 407%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals 408 %void = OpTypeVoid 409 %7 = OpTypeFunction %void 410 %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform 411 %main = OpFunction %void None %7 412 %8 = OpLabel 413 %9 = OpLoad %type__Globals %_Globals 414 %10 = OpCompositeExtract %float %9 1 415 %11 = OpCompositeInsert %type__Globals %10 %9 1 416 OpReturn 417 OpFunctionEnd 418 419)"; 420 421 SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true); 422} 423 424TEST_F(EliminateDeadMemberTest, RemoveMembersUpdateInserExtract3) { 425 // Test that the members "x" and "z" are removed, and one member from the 426 // substruct. Update the OpCompositeExtract instruction. Update the 427 // OpCompositeInsert instruction. 428 const std::string text = R"( 429; CHECK: OpName 430; CHECK-NEXT: OpMemberName %type__Globals 0 "y" 431; CHECK-NOT: OpMemberName 432; CHECK: OpMemberDecorate %type__Globals 0 Offset 16 433; CHECK-NOT: OpMemberDecorate %type__Globals 1 Offset 434; CHECK: OpMemberDecorate [[struct:%\w+]] 0 Offset 4 435; CHECK: [[struct:%\w+]] = OpTypeStruct %float 436; CHECK: %type__Globals = OpTypeStruct [[struct]] 437; CHECK: [[ld:%\w+]] = OpLoad %type__Globals %_Globals 438; CHECK: [[ex:%\w+]] = OpCompositeExtract %float [[ld]] 0 0 439; CHECK: OpCompositeInsert %type__Globals [[ex]] [[ld]] 0 0 440; CHECK: OpReturn 441 OpCapability Shader 442 OpMemoryModel Logical GLSL450 443 OpEntryPoint Vertex %main "main" 444 OpSource HLSL 600 445 OpName %type__Globals "type.$Globals" 446 OpMemberName %type__Globals 0 "x" 447 OpMemberName %type__Globals 1 "y" 448 OpMemberName %type__Globals 2 "z" 449 OpName %_Globals "$Globals" 450 OpName %main "main" 451 OpDecorate %_Globals DescriptorSet 0 452 OpDecorate %_Globals Binding 0 453 OpMemberDecorate %type__Globals 0 Offset 0 454 OpMemberDecorate %type__Globals 1 Offset 16 455 OpMemberDecorate %type__Globals 2 Offset 24 456 OpMemberDecorate %_struct_6 0 Offset 0 457 OpMemberDecorate %_struct_6 1 Offset 4 458 OpDecorate %type__Globals Block 459 %float = OpTypeFloat 32 460 %_struct_6 = OpTypeStruct %float %float 461%type__Globals = OpTypeStruct %float %_struct_6 %float 462%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals 463 %void = OpTypeVoid 464 %7 = OpTypeFunction %void 465 %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform 466 %main = OpFunction %void None %7 467 %8 = OpLabel 468 %9 = OpLoad %type__Globals %_Globals 469 %10 = OpCompositeExtract %float %9 1 1 470 %11 = OpCompositeInsert %type__Globals %10 %9 1 1 471 OpReturn 472 OpFunctionEnd 473 474)"; 475 476 SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true); 477} 478 479TEST_F(EliminateDeadMemberTest, RemoveMembersUpdateInserExtract4) { 480 // Test that the members "x" and "z" are removed, and one member from the 481 // substruct. Update the OpCompositeExtract instruction. Update the 482 // OpCompositeInsert instruction. 483 const std::string text = R"( 484; CHECK: OpName 485; CHECK-NEXT: OpMemberName %type__Globals 0 "y" 486; CHECK-NOT: OpMemberName 487; CHECK: OpMemberDecorate %type__Globals 0 Offset 16 488; CHECK-NOT: OpMemberDecorate %type__Globals 1 Offset 489; CHECK: OpMemberDecorate [[struct:%\w+]] 0 Offset 4 490; CHECK: [[struct:%\w+]] = OpTypeStruct %float 491; CHECK: [[array:%\w+]] = OpTypeArray [[struct]] 492; CHECK: %type__Globals = OpTypeStruct [[array]] 493; CHECK: [[ld:%\w+]] = OpLoad %type__Globals %_Globals 494; CHECK: [[ex:%\w+]] = OpCompositeExtract %float [[ld]] 0 1 0 495; CHECK: OpCompositeInsert %type__Globals [[ex]] [[ld]] 0 1 0 496; CHECK: OpReturn 497 OpCapability Shader 498 OpMemoryModel Logical GLSL450 499 OpEntryPoint Vertex %main "main" 500 OpSource HLSL 600 501 OpName %type__Globals "type.$Globals" 502 OpMemberName %type__Globals 0 "x" 503 OpMemberName %type__Globals 1 "y" 504 OpMemberName %type__Globals 2 "z" 505 OpName %_Globals "$Globals" 506 OpName %main "main" 507 OpDecorate %_Globals DescriptorSet 0 508 OpDecorate %_Globals Binding 0 509 OpMemberDecorate %type__Globals 0 Offset 0 510 OpMemberDecorate %type__Globals 1 Offset 16 511 OpMemberDecorate %type__Globals 2 Offset 80 512 OpMemberDecorate %_struct_6 0 Offset 0 513 OpMemberDecorate %_struct_6 1 Offset 4 514 OpDecorate %array ArrayStride 16 515 OpDecorate %type__Globals Block 516 %uint = OpTypeInt 32 0 ; 32-bit int, sign-less 517 %uint_4 = OpConstant %uint 4 518 %float = OpTypeFloat 32 519 %_struct_6 = OpTypeStruct %float %float 520 %array = OpTypeArray %_struct_6 %uint_4 521%type__Globals = OpTypeStruct %float %array %float 522%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals 523 %void = OpTypeVoid 524 %7 = OpTypeFunction %void 525 %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform 526 %main = OpFunction %void None %7 527 %8 = OpLabel 528 %9 = OpLoad %type__Globals %_Globals 529 %10 = OpCompositeExtract %float %9 1 1 1 530 %11 = OpCompositeInsert %type__Globals %10 %9 1 1 1 531 OpReturn 532 OpFunctionEnd 533 534)"; 535 536 SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true); 537} 538 539TEST_F(EliminateDeadMemberTest, RemoveMembersUpdateArrayLength) { 540 // Test that the members "x" and "y" are removed. 541 // Member "z" is live because of the OpArrayLength instruction. 542 // Update the OpArrayLength instruction. 543 const std::string text = R"( 544; CHECK: OpName 545; CHECK-NEXT: OpMemberName %type__Globals 0 "z" 546; CHECK-NOT: OpMemberName 547; CHECK: OpMemberDecorate %type__Globals 0 Offset 16 548; CHECK-NOT: OpMemberDecorate %type__Globals 1 Offset 549; CHECK: %type__Globals = OpTypeStruct %_runtimearr_float 550; CHECK: OpArrayLength %uint %_Globals 0 551 OpCapability Shader 552 OpMemoryModel Logical GLSL450 553 OpEntryPoint Vertex %main "main" 554 OpSource HLSL 600 555 OpName %type__Globals "type.$Globals" 556 OpMemberName %type__Globals 0 "x" 557 OpMemberName %type__Globals 1 "y" 558 OpMemberName %type__Globals 2 "z" 559 OpName %_Globals "$Globals" 560 OpName %main "main" 561 OpDecorate %_Globals DescriptorSet 0 562 OpDecorate %_Globals Binding 0 563 OpDecorate %_runtimearr_float ArrayStride 16 564 OpMemberDecorate %type__Globals 0 Offset 0 565 OpMemberDecorate %type__Globals 1 Offset 4 566 OpMemberDecorate %type__Globals 2 Offset 16 567 OpDecorate %type__Globals Block 568 %uint = OpTypeInt 32 0 569 %float = OpTypeFloat 32 570%_runtimearr_float = OpTypeRuntimeArray %float 571%type__Globals = OpTypeStruct %float %float %_runtimearr_float 572%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals 573 %void = OpTypeVoid 574 %9 = OpTypeFunction %void 575 %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform 576 %main = OpFunction %void None %9 577 %10 = OpLabel 578 %12 = OpArrayLength %uint %_Globals 2 579 OpReturn 580 OpFunctionEnd 581)"; 582 583 SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true); 584} 585 586TEST_F(EliminateDeadMemberTest, KeepMembersOpStore) { 587 // Test that all members are kept because of an OpStore. 588 // No change expected. 589 const std::string text = R"( 590 OpCapability Shader 591 OpMemoryModel Logical GLSL450 592 OpEntryPoint Vertex %main "main" 593 OpSource HLSL 600 594 OpName %type__Globals "type.$Globals" 595 OpMemberName %type__Globals 0 "x" 596 OpMemberName %type__Globals 1 "y" 597 OpMemberName %type__Globals 2 "z" 598 OpName %_Globals "$Globals" 599 OpName %_Globals "$Globals2" 600 OpName %main "main" 601 OpDecorate %_Globals DescriptorSet 0 602 OpDecorate %_Globals Binding 0 603 OpMemberDecorate %type__Globals 0 Offset 0 604 OpMemberDecorate %type__Globals 1 Offset 4 605 OpMemberDecorate %type__Globals 2 Offset 16 606 OpDecorate %type__Globals Block 607 %uint = OpTypeInt 32 0 608 %float = OpTypeFloat 32 609%type__Globals = OpTypeStruct %float %float %float 610%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals 611 %void = OpTypeVoid 612 %9 = OpTypeFunction %void 613 %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform 614 %_Globals2 = OpVariable %_ptr_Uniform_type__Globals Uniform 615 %main = OpFunction %void None %9 616 %10 = OpLabel 617 %11 = OpLoad %type__Globals %_Globals 618 OpStore %_Globals2 %11 619 OpReturn 620 OpFunctionEnd 621)"; 622 623 auto result = SinglePassRunAndDisassemble<opt::EliminateDeadMembersPass>( 624 text, /* skip_nop = */ true, /* do_validation = */ true); 625 EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result)); 626} 627 628TEST_F(EliminateDeadMemberTest, KeepStorageBufferMembers) { 629 // Test that all members of the storage buffer struct %S are kept. 630 // No change expected. 631 const std::string text = R"( 632 OpCapability Shader 633 OpExtension "SPV_GOOGLE_hlsl_functionality1" 634 OpExtension "SPV_GOOGLE_user_type" 635 %1 = OpExtInstImport "GLSL.std.450" 636 OpMemoryModel Logical GLSL450 637 OpEntryPoint Fragment %PSMain "PSMain" %out_var_SV_TARGET 638 OpExecutionMode %PSMain OriginUpperLeft 639 OpSource HLSL 600 640 OpName %type_StructuredBuffer_S "type.StructuredBuffer.S" 641 OpName %S "S" 642 OpMemberName %S 0 "A" 643 OpMemberName %S 1 "B" 644 OpName %Buf "Buf" 645 OpName %out_var_SV_TARGET "out.var.SV_TARGET" 646 OpName %PSMain "PSMain" 647 OpDecorateString %out_var_SV_TARGET UserSemantic "SV_TARGET" 648 OpDecorate %out_var_SV_TARGET Location 0 649 OpDecorate %Buf DescriptorSet 0 650 OpDecorate %Buf Binding 0 651 OpMemberDecorate %S 0 Offset 0 652 OpMemberDecorate %S 1 Offset 16 653 OpDecorate %_runtimearr_S ArrayStride 32 654 OpMemberDecorate %type_StructuredBuffer_S 0 Offset 0 655 OpMemberDecorate %type_StructuredBuffer_S 0 NonWritable 656 OpDecorate %type_StructuredBuffer_S BufferBlock 657 OpDecorateString %Buf UserTypeGOOGLE "structuredbuffer" 658 %int = OpTypeInt 32 1 659 %int_0 = OpConstant %int 0 660 %uint = OpTypeInt 32 0 661 %uint_0 = OpConstant %uint 0 662 %int_1 = OpConstant %int 1 663 %float = OpTypeFloat 32 664 %v4float = OpTypeVector %float 4 665 %S = OpTypeStruct %v4float %v4float 666%_runtimearr_S = OpTypeRuntimeArray %S 667%type_StructuredBuffer_S = OpTypeStruct %_runtimearr_S 668%_ptr_Uniform_type_StructuredBuffer_S = OpTypePointer Uniform %type_StructuredBuffer_S 669%_ptr_Output_v4float = OpTypePointer Output %v4float 670 %void = OpTypeVoid 671 %18 = OpTypeFunction %void 672%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float 673 %Buf = OpVariable %_ptr_Uniform_type_StructuredBuffer_S Uniform 674%out_var_SV_TARGET = OpVariable %_ptr_Output_v4float Output 675 %PSMain = OpFunction %void None %18 676 %20 = OpLabel 677 %21 = OpAccessChain %_ptr_Uniform_v4float %Buf %int_0 %uint_0 %int_1 678 %22 = OpLoad %v4float %21 679 OpStore %out_var_SV_TARGET %22 680 OpReturn 681 OpFunctionEnd 682)"; 683 684 auto result = SinglePassRunAndDisassemble<opt::EliminateDeadMembersPass>( 685 text, /* skip_nop = */ true, /* do_validation = */ true); 686 EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result)); 687} 688 689TEST_F(EliminateDeadMemberTest, KeepMembersOpCopyMemory) { 690 // Test that all members are kept because of an OpCopyMemory. 691 // No change expected. 692 const std::string text = R"( 693 OpCapability Shader 694 OpMemoryModel Logical GLSL450 695 OpEntryPoint Vertex %main "main" 696 OpSource HLSL 600 697 OpName %type__Globals "type.$Globals" 698 OpMemberName %type__Globals 0 "x" 699 OpMemberName %type__Globals 1 "y" 700 OpMemberName %type__Globals 2 "z" 701 OpName %_Globals "$Globals" 702 OpName %_Globals "$Globals2" 703 OpName %main "main" 704 OpDecorate %_Globals DescriptorSet 0 705 OpDecorate %_Globals Binding 0 706 OpMemberDecorate %type__Globals 0 Offset 0 707 OpMemberDecorate %type__Globals 1 Offset 4 708 OpMemberDecorate %type__Globals 2 Offset 16 709 OpDecorate %type__Globals Block 710 %uint = OpTypeInt 32 0 711 %float = OpTypeFloat 32 712%type__Globals = OpTypeStruct %float %float %float 713%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals 714 %void = OpTypeVoid 715 %9 = OpTypeFunction %void 716 %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform 717 %_Globals2 = OpVariable %_ptr_Uniform_type__Globals Uniform 718 %main = OpFunction %void None %9 719 %10 = OpLabel 720 OpCopyMemory %_Globals2 %_Globals 721 OpReturn 722 OpFunctionEnd 723)"; 724 725 auto result = SinglePassRunAndDisassemble<opt::EliminateDeadMembersPass>( 726 text, /* skip_nop = */ true, /* do_validation = */ true); 727 EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result)); 728} 729 730TEST_F(EliminateDeadMemberTest, KeepMembersOpCopyMemorySized) { 731 // Test that all members are kept because of an OpCopyMemorySized. 732 // No change expected. 733 const std::string text = R"( 734 OpCapability Shader 735 OpCapability Addresses 736 OpMemoryModel Logical GLSL450 737 OpEntryPoint Vertex %main "main" 738 OpSource HLSL 600 739 OpName %type__Globals "type.$Globals" 740 OpMemberName %type__Globals 0 "x" 741 OpMemberName %type__Globals 1 "y" 742 OpMemberName %type__Globals 2 "z" 743 OpName %_Globals "$Globals" 744 OpName %_Globals "$Globals2" 745 OpName %main "main" 746 OpDecorate %_Globals DescriptorSet 0 747 OpDecorate %_Globals Binding 0 748 OpMemberDecorate %type__Globals 0 Offset 0 749 OpMemberDecorate %type__Globals 1 Offset 4 750 OpMemberDecorate %type__Globals 2 Offset 16 751 OpDecorate %type__Globals Block 752 %uint = OpTypeInt 32 0 753 %uint_20 = OpConstant %uint 20 754 %float = OpTypeFloat 32 755%type__Globals = OpTypeStruct %float %float %float 756%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals 757 %void = OpTypeVoid 758 %9 = OpTypeFunction %void 759 %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform 760 %_Globals2 = OpVariable %_ptr_Uniform_type__Globals Uniform 761 %main = OpFunction %void None %9 762 %10 = OpLabel 763 OpCopyMemorySized %_Globals2 %_Globals %uint_20 764 OpReturn 765 OpFunctionEnd 766)"; 767 768 auto result = SinglePassRunAndDisassemble<opt::EliminateDeadMembersPass>( 769 text, /* skip_nop = */ true, /* do_validation = */ true); 770 EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result)); 771} 772 773TEST_F(EliminateDeadMemberTest, KeepMembersOpReturnValue) { 774 // Test that all members are kept because of an OpCopyMemorySized. 775 // No change expected. 776 const std::string text = R"( 777 OpCapability Shader 778 OpCapability Linkage 779 OpMemoryModel Logical GLSL450 780 OpSource HLSL 600 781 OpName %type__Globals "type.$Globals" 782 OpMemberName %type__Globals 0 "x" 783 OpMemberName %type__Globals 1 "y" 784 OpMemberName %type__Globals 2 "z" 785 OpName %_Globals "$Globals" 786 OpName %_Globals "$Globals2" 787 OpName %main "main" 788 OpDecorate %_Globals DescriptorSet 0 789 OpDecorate %_Globals Binding 0 790 OpMemberDecorate %type__Globals 0 Offset 0 791 OpMemberDecorate %type__Globals 1 Offset 4 792 OpMemberDecorate %type__Globals 2 Offset 16 793 OpDecorate %type__Globals Block 794 %uint = OpTypeInt 32 0 795 %uint_20 = OpConstant %uint 20 796 %float = OpTypeFloat 32 797%type__Globals = OpTypeStruct %float %float %float 798%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals 799 %void = OpTypeVoid 800 %9 = OpTypeFunction %type__Globals 801 %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform 802 %_Globals2 = OpVariable %_ptr_Uniform_type__Globals Uniform 803 %main = OpFunction %type__Globals None %9 804 %10 = OpLabel 805 %11 = OpLoad %type__Globals %_Globals 806 OpReturnValue %11 807 OpFunctionEnd 808)"; 809 810 auto result = SinglePassRunAndDisassemble<opt::EliminateDeadMembersPass>( 811 text, /* skip_nop = */ true, /* do_validation = */ true); 812 EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result)); 813} 814 815TEST_F(EliminateDeadMemberTest, RemoveMemberAccessChainWithArrays) { 816 // Leave only 1 member in each of the structs. 817 // Update OpMemberName, OpMemberDecorate, and OpAccessChain. 818 const std::string text = R"( 819; CHECK: OpName 820; CHECK-NEXT: OpMemberName %type__Globals 0 "y" 821; CHECK-NOT: OpMemberName 822; CHECK: OpMemberDecorate %type__Globals 0 Offset 16 823; CHECK: OpMemberDecorate [[struct:%\w+]] 0 Offset 4 824; CHECK: [[struct]] = OpTypeStruct %float 825; CHECK: [[array:%\w+]] = OpTypeArray [[struct]] 826; CHECK: %type__Globals = OpTypeStruct [[array]] 827; CHECK: [[undef:%\w+]] = OpUndef %uint 828; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals [[undef]] %uint_0 [[undef]] %uint_0 829 OpCapability Shader 830 OpCapability VariablePointersStorageBuffer 831 OpMemoryModel Logical GLSL450 832 OpEntryPoint Vertex %main "main" 833 OpSource HLSL 600 834 OpName %type__Globals "type.$Globals" 835 OpMemberName %type__Globals 0 "x" 836 OpMemberName %type__Globals 1 "y" 837 OpMemberName %type__Globals 2 "z" 838 OpName %_Globals "$Globals" 839 OpName %main "main" 840 OpDecorate %_Globals DescriptorSet 0 841 OpDecorate %_Globals Binding 0 842 OpMemberDecorate %type__Globals 0 Offset 0 843 OpMemberDecorate %type__Globals 1 Offset 16 844 OpMemberDecorate %type__Globals 2 Offset 48 845 OpMemberDecorate %_struct_4 0 Offset 0 846 OpMemberDecorate %_struct_4 1 Offset 4 847 OpDecorate %_arr__struct_4_uint_2 ArrayStride 16 848 OpDecorate %type__Globals Block 849 %uint = OpTypeInt 32 0 850 %uint_0 = OpConstant %uint 0 851 %uint_1 = OpConstant %uint 1 852 %uint_2 = OpConstant %uint 2 853 %uint_3 = OpConstant %uint 3 854 %float = OpTypeFloat 32 855 %_struct_4 = OpTypeStruct %float %float 856%_arr__struct_4_uint_2 = OpTypeArray %_struct_4 %uint_2 857%type__Globals = OpTypeStruct %float %_arr__struct_4_uint_2 %float 858%_arr_type__Globals_uint_3 = OpTypeArray %type__Globals %uint_3 859%_ptr_Uniform__arr_type__Globals_uint_3 = OpTypePointer Uniform %_arr_type__Globals_uint_3 860 %void = OpTypeVoid 861 %15 = OpTypeFunction %void 862%_ptr_Uniform_float = OpTypePointer Uniform %float 863 %_Globals = OpVariable %_ptr_Uniform__arr_type__Globals_uint_3 Uniform 864 %main = OpFunction %void None %15 865 %17 = OpLabel 866 %18 = OpUndef %uint 867 %19 = OpAccessChain %_ptr_Uniform_float %_Globals %18 %uint_1 %18 %uint_1 868 OpReturn 869 OpFunctionEnd 870)"; 871 872 SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true); 873} 874 875TEST_F(EliminateDeadMemberTest, RemoveMemberInboundsAccessChain) { 876 // Test that the member "y" is removed. 877 // Update OpMemberName for |y| and |z|. 878 // Update OpMemberDecorate for |y| and |z|. 879 // Update OpInboundsAccessChain for access to |z|. 880 const std::string text = R"( 881; CHECK: OpName 882; CHECK-NEXT: OpMemberName %type__Globals 0 "x" 883; CHECK-NEXT: OpMemberName %type__Globals 1 "z" 884; CHECK-NOT: OpMemberName 885; CHECK: OpMemberDecorate %type__Globals 0 Offset 0 886; CHECK: OpMemberDecorate %type__Globals 1 Offset 8 887; CHECK: %type__Globals = OpTypeStruct %float %float 888; CHECK: OpInBoundsAccessChain %_ptr_Uniform_float %_Globals %int_0 889; CHECK: OpInBoundsAccessChain %_ptr_Uniform_float %_Globals %uint_1 890 OpCapability Shader 891 OpMemoryModel Logical GLSL450 892 OpEntryPoint Vertex %main "main" %in_var_Position %gl_Position 893 OpSource HLSL 600 894 OpName %type__Globals "type.$Globals" 895 OpMemberName %type__Globals 0 "x" 896 OpMemberName %type__Globals 1 "y" 897 OpMemberName %type__Globals 2 "z" 898 OpName %_Globals "$Globals" 899 OpName %in_var_Position "in.var.Position" 900 OpName %main "main" 901 OpDecorate %gl_Position BuiltIn Position 902 OpDecorate %in_var_Position Location 0 903 OpDecorate %_Globals DescriptorSet 0 904 OpDecorate %_Globals Binding 0 905 OpMemberDecorate %type__Globals 0 Offset 0 906 OpMemberDecorate %type__Globals 1 Offset 4 907 OpMemberDecorate %type__Globals 2 Offset 8 908 OpDecorate %type__Globals Block 909 %int = OpTypeInt 32 1 910 %int_0 = OpConstant %int 0 911 %float = OpTypeFloat 32 912 %int_2 = OpConstant %int 2 913%type__Globals = OpTypeStruct %float %float %float 914%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals 915 %v4float = OpTypeVector %float 4 916%_ptr_Input_v4float = OpTypePointer Input %v4float 917%_ptr_Output_v4float = OpTypePointer Output %v4float 918 %void = OpTypeVoid 919 %15 = OpTypeFunction %void 920%_ptr_Uniform_float = OpTypePointer Uniform %float 921 %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform 922%in_var_Position = OpVariable %_ptr_Input_v4float Input 923%gl_Position = OpVariable %_ptr_Output_v4float Output 924 %main = OpFunction %void None %15 925 %17 = OpLabel 926 %18 = OpLoad %v4float %in_var_Position 927 %19 = OpInBoundsAccessChain %_ptr_Uniform_float %_Globals %int_0 928 %20 = OpLoad %float %19 929 %21 = OpCompositeExtract %float %18 0 930 %22 = OpFAdd %float %21 %20 931 %23 = OpCompositeInsert %v4float %22 %18 0 932 %24 = OpCompositeExtract %float %18 1 933 %25 = OpCompositeInsert %v4float %24 %23 1 934 %26 = OpInBoundsAccessChain %_ptr_Uniform_float %_Globals %int_2 935 %27 = OpLoad %float %26 936 %28 = OpCompositeExtract %float %18 2 937 %29 = OpFAdd %float %28 %27 938 %30 = OpCompositeInsert %v4float %29 %25 2 939 OpStore %gl_Position %30 940 OpReturn 941 OpFunctionEnd 942)"; 943 944 SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true); 945} 946 947TEST_F(EliminateDeadMemberTest, RemoveMemberPtrAccessChain) { 948 // Test that the member "y" is removed. 949 // Update OpMemberName for |y| and |z|. 950 // Update OpMemberDecorate for |y| and |z|. 951 // Update OpInboundsAccessChain for access to |z|. 952 const std::string text = R"( 953; CHECK: OpName 954; CHECK-NEXT: OpMemberName %type__Globals 0 "x" 955; CHECK-NEXT: OpMemberName %type__Globals 1 "z" 956; CHECK-NOT: OpMemberName 957; CHECK: OpMemberDecorate %type__Globals 0 Offset 0 958; CHECK: OpMemberDecorate %type__Globals 1 Offset 16 959; CHECK: %type__Globals = OpTypeStruct %float %float 960; CHECK: [[ac:%\w+]] = OpAccessChain %_ptr_Uniform_type__Globals %_Globals %uint_0 961; CHECK: OpPtrAccessChain %_ptr_Uniform_float [[ac]] %uint_1 %uint_0 962; CHECK: OpPtrAccessChain %_ptr_Uniform_float [[ac]] %uint_0 %uint_1 963 OpCapability Shader 964 OpCapability VariablePointersStorageBuffer 965 OpMemoryModel Logical GLSL450 966 OpEntryPoint Vertex %main "main" 967 OpSource HLSL 600 968 OpName %type__Globals "type.$Globals" 969 OpMemberName %type__Globals 0 "x" 970 OpMemberName %type__Globals 1 "y" 971 OpMemberName %type__Globals 2 "z" 972 OpName %_Globals "$Globals" 973 OpName %main "main" 974 OpDecorate %_Globals DescriptorSet 0 975 OpDecorate %_Globals Binding 0 976 OpMemberDecorate %type__Globals 0 Offset 0 977 OpMemberDecorate %type__Globals 1 Offset 4 978 OpMemberDecorate %type__Globals 2 Offset 16 979 OpDecorate %type__Globals Block 980 OpDecorate %_ptr_Uniform_type__Globals ArrayStride 8 981 %uint = OpTypeInt 32 0 982 %uint_0 = OpConstant %uint 0 983 %uint_1 = OpConstant %uint 1 984 %uint_2 = OpConstant %uint 2 985 %uint_3 = OpConstant %uint 3 986 %float = OpTypeFloat 32 987%type__Globals = OpTypeStruct %float %float %float 988%_arr_type__Globals_uint_3 = OpTypeArray %type__Globals %uint_3 989%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals 990%_ptr_Uniform__arr_type__Globals_uint_3 = OpTypePointer Uniform %_arr_type__Globals_uint_3 991 %void = OpTypeVoid 992 %14 = OpTypeFunction %void 993%_ptr_Uniform_float = OpTypePointer Uniform %float 994 %_Globals = OpVariable %_ptr_Uniform__arr_type__Globals_uint_3 Uniform 995 %main = OpFunction %void None %14 996 %16 = OpLabel 997 %17 = OpAccessChain %_ptr_Uniform_type__Globals %_Globals %uint_0 998 %18 = OpPtrAccessChain %_ptr_Uniform_float %17 %uint_1 %uint_0 999 %19 = OpPtrAccessChain %_ptr_Uniform_float %17 %uint_0 %uint_2 1000 OpReturn 1001 OpFunctionEnd 1002)"; 1003 1004 SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true); 1005} 1006 1007TEST_F(EliminateDeadMemberTest, RemoveMemberInBoundsPtrAccessChain) { 1008 // Test that the member "y" is removed. 1009 // Update OpMemberName for |y| and |z|. 1010 // Update OpMemberDecorate for |y| and |z|. 1011 // Update OpInboundsAccessChain for access to |z|. 1012 const std::string text = R"( 1013; CHECK: OpName 1014; CHECK-NEXT: OpMemberName %type__Globals 0 "x" 1015; CHECK-NEXT: OpMemberName %type__Globals 1 "z" 1016; CHECK-NOT: OpMemberName 1017; CHECK: OpMemberDecorate %type__Globals 0 Offset 0 1018; CHECK: OpMemberDecorate %type__Globals 1 Offset 16 1019; CHECK: %type__Globals = OpTypeStruct %float %float 1020; CHECK: [[ac:%\w+]] = OpAccessChain %_ptr_Uniform_type__Globals %_Globals %uint_0 1021; CHECK: OpInBoundsPtrAccessChain %_ptr_Uniform_float [[ac]] %uint_1 %uint_0 1022; CHECK: OpInBoundsPtrAccessChain %_ptr_Uniform_float [[ac]] %uint_0 %uint_1 1023 OpCapability Shader 1024 OpCapability Addresses 1025 OpMemoryModel Logical GLSL450 1026 OpEntryPoint Vertex %main "main" 1027 OpSource HLSL 600 1028 OpName %type__Globals "type.$Globals" 1029 OpMemberName %type__Globals 0 "x" 1030 OpMemberName %type__Globals 1 "y" 1031 OpMemberName %type__Globals 2 "z" 1032 OpName %_Globals "$Globals" 1033 OpName %main "main" 1034 OpDecorate %_Globals DescriptorSet 0 1035 OpDecorate %_Globals Binding 0 1036 OpMemberDecorate %type__Globals 0 Offset 0 1037 OpMemberDecorate %type__Globals 1 Offset 4 1038 OpMemberDecorate %type__Globals 2 Offset 16 1039 OpDecorate %type__Globals Block 1040 %uint = OpTypeInt 32 0 1041 %uint_0 = OpConstant %uint 0 1042 %uint_1 = OpConstant %uint 1 1043 %uint_2 = OpConstant %uint 2 1044 %uint_3 = OpConstant %uint 3 1045 %float = OpTypeFloat 32 1046%type__Globals = OpTypeStruct %float %float %float 1047%_arr_type__Globals_uint_3 = OpTypeArray %type__Globals %uint_3 1048%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals 1049%_ptr_Uniform__arr_type__Globals_uint_3 = OpTypePointer Uniform %_arr_type__Globals_uint_3 1050 %void = OpTypeVoid 1051 %14 = OpTypeFunction %void 1052%_ptr_Uniform_float = OpTypePointer Uniform %float 1053 %_Globals = OpVariable %_ptr_Uniform__arr_type__Globals_uint_3 Uniform 1054 %main = OpFunction %void None %14 1055 %16 = OpLabel 1056 %17 = OpAccessChain %_ptr_Uniform_type__Globals %_Globals %uint_0 1057 %18 = OpInBoundsPtrAccessChain %_ptr_Uniform_float %17 %uint_1 %uint_0 1058 %19 = OpInBoundsPtrAccessChain %_ptr_Uniform_float %17 %uint_0 %uint_2 1059 OpReturn 1060 OpFunctionEnd 1061)"; 1062 1063 SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true); 1064} 1065 1066TEST_F(EliminateDeadMemberTest, DontRemoveModfStructResultTypeMembers) { 1067 const std::string text = R"( 1068 OpCapability Shader 1069 %1 = OpExtInstImport "GLSL.std.450" 1070 OpMemoryModel Logical GLSL450 1071 OpEntryPoint Fragment %main "main" 1072 OpExecutionMode %main OriginUpperLeft 1073 OpSource HLSL 600 1074 %float = OpTypeFloat 32 1075 %void = OpTypeVoid 1076 %21 = OpTypeFunction %void 1077%ModfStructType = OpTypeStruct %float %float 1078%main = OpFunction %void None %21 1079 %22 = OpLabel 1080 %23 = OpUndef %float 1081 %24 = OpExtInst %ModfStructType %1 ModfStruct %23 1082 %25 = OpCompositeExtract %float %24 1 1083 OpReturn 1084 OpFunctionEnd 1085)"; 1086 1087 auto result = SinglePassRunAndDisassemble<opt::EliminateDeadMembersPass>( 1088 text, /* skip_nop = */ true, /* do_validation = */ true); 1089 EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result)); 1090} 1091 1092TEST_F(EliminateDeadMemberTest, DontChangeInputStructs) { 1093 // The input for a shader has to match the type of the output from the 1094 // previous shader in the pipeline. Because of that, we cannot change the 1095 // types of input variables. 1096 const std::string text = R"( 1097 OpCapability Shader 1098 %1 = OpExtInstImport "GLSL.std.450" 1099 OpMemoryModel Logical GLSL450 1100 OpEntryPoint Fragment %main "main" %input_var 1101 OpExecutionMode %main OriginUpperLeft 1102 OpSource HLSL 600 1103 %float = OpTypeFloat 32 1104 %void = OpTypeVoid 1105 %21 = OpTypeFunction %void 1106%in_var_type = OpTypeStruct %float %float 1107%in_ptr_type = OpTypePointer Input %in_var_type 1108%input_var = OpVariable %in_ptr_type Input 1109%main = OpFunction %void None %21 1110 %22 = OpLabel 1111 OpReturn 1112 OpFunctionEnd 1113)"; 1114 1115 auto result = SinglePassRunAndDisassemble<opt::EliminateDeadMembersPass>( 1116 text, /* skip_nop = */ true, /* do_validation = */ true); 1117 EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result)); 1118} 1119 1120TEST_F(EliminateDeadMemberTest, DontChangeOutputStructs) { 1121 // The output for a shader has to match the type of the output from the 1122 // previous shader in the pipeline. Because of that, we cannot change the 1123 // types of output variables. 1124 const std::string text = R"( 1125 OpCapability Shader 1126 %1 = OpExtInstImport "GLSL.std.450" 1127 OpMemoryModel Logical GLSL450 1128 OpEntryPoint Fragment %main "main" %output_var 1129 OpExecutionMode %main OriginUpperLeft 1130 OpSource HLSL 600 1131 %float = OpTypeFloat 32 1132 %void = OpTypeVoid 1133 %21 = OpTypeFunction %void 1134%out_var_type = OpTypeStruct %float %float 1135%out_ptr_type = OpTypePointer Output %out_var_type 1136%output_var = OpVariable %out_ptr_type Output 1137%main = OpFunction %void None %21 1138 %22 = OpLabel 1139 OpReturn 1140 OpFunctionEnd 1141)"; 1142 1143 auto result = SinglePassRunAndDisassemble<opt::EliminateDeadMembersPass>( 1144 text, /* skip_nop = */ true, /* do_validation = */ true); 1145 EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result)); 1146} 1147 1148TEST_F(EliminateDeadMemberTest, UpdateSpecConstOpExtract) { 1149 // Test that an extract in an OpSpecConstantOp is correctly updated. 1150 const std::string text = R"( 1151; CHECK: OpName 1152; CHECK-NEXT: OpMemberName %type__Globals 0 "y" 1153; CHECK-NOT: OpMemberName 1154; CHECK: OpDecorate [[spec_const:%\w+]] SpecId 1 1155; CHECK: OpMemberDecorate %type__Globals 0 Offset 4 1156; CHECK: %type__Globals = OpTypeStruct %uint 1157; CHECK: [[struct:%\w+]] = OpSpecConstantComposite %type__Globals [[spec_const]] 1158; CHECK: OpSpecConstantOp %uint CompositeExtract [[struct]] 0 1159 OpCapability Shader 1160 OpCapability Addresses 1161 OpMemoryModel Logical GLSL450 1162 OpEntryPoint Vertex %main "main" 1163 OpSource HLSL 600 1164 OpName %type__Globals "type.$Globals" 1165 OpMemberName %type__Globals 0 "x" 1166 OpMemberName %type__Globals 1 "y" 1167 OpMemberName %type__Globals 2 "z" 1168 OpName %main "main" 1169 OpDecorate %c_0 SpecId 0 1170 OpDecorate %c_1 SpecId 1 1171 OpDecorate %c_2 SpecId 2 1172 OpMemberDecorate %type__Globals 0 Offset 0 1173 OpMemberDecorate %type__Globals 1 Offset 4 1174 OpMemberDecorate %type__Globals 2 Offset 16 1175 %uint = OpTypeInt 32 0 1176 %c_0 = OpSpecConstant %uint 0 1177 %c_1 = OpSpecConstant %uint 1 1178 %c_2 = OpSpecConstant %uint 2 1179 %uint_0 = OpConstant %uint 0 1180 %uint_1 = OpConstant %uint 1 1181 %uint_2 = OpConstant %uint 2 1182 %uint_3 = OpConstant %uint 3 1183%type__Globals = OpTypeStruct %uint %uint %uint 1184%spec_const_global = OpSpecConstantComposite %type__Globals %c_0 %c_1 %c_2 1185%extract = OpSpecConstantOp %uint CompositeExtract %spec_const_global 1 1186 %void = OpTypeVoid 1187 %14 = OpTypeFunction %void 1188 %main = OpFunction %void None %14 1189 %16 = OpLabel 1190 OpReturn 1191 OpFunctionEnd 1192)"; 1193 1194 SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true); 1195} 1196 1197TEST_F(EliminateDeadMemberTest, UpdateSpecConstOpInsert) { 1198 // Test that an insert in an OpSpecConstantOp is correctly updated. 1199 const std::string text = R"( 1200; CHECK: OpName 1201; CHECK-NEXT: OpMemberName %type__Globals 0 "y" 1202; CHECK-NOT: OpMemberName 1203; CHECK: OpDecorate [[spec_const:%\w+]] SpecId 1 1204; CHECK: OpMemberDecorate %type__Globals 0 Offset 4 1205; CHECK: %type__Globals = OpTypeStruct %uint 1206; CHECK: [[struct:%\w+]] = OpSpecConstantComposite %type__Globals [[spec_const]] 1207; CHECK: OpSpecConstantOp %type__Globals CompositeInsert %uint_3 [[struct]] 0 1208 OpCapability Shader 1209 OpCapability Addresses 1210 OpMemoryModel Logical GLSL450 1211 OpEntryPoint Vertex %main "main" 1212 OpSource HLSL 600 1213 OpName %type__Globals "type.$Globals" 1214 OpMemberName %type__Globals 0 "x" 1215 OpMemberName %type__Globals 1 "y" 1216 OpMemberName %type__Globals 2 "z" 1217 OpName %main "main" 1218 OpDecorate %c_0 SpecId 0 1219 OpDecorate %c_1 SpecId 1 1220 OpDecorate %c_2 SpecId 2 1221 OpMemberDecorate %type__Globals 0 Offset 0 1222 OpMemberDecorate %type__Globals 1 Offset 4 1223 OpMemberDecorate %type__Globals 2 Offset 16 1224 %uint = OpTypeInt 32 0 1225 %c_0 = OpSpecConstant %uint 0 1226 %c_1 = OpSpecConstant %uint 1 1227 %c_2 = OpSpecConstant %uint 2 1228 %uint_0 = OpConstant %uint 0 1229 %uint_1 = OpConstant %uint 1 1230 %uint_2 = OpConstant %uint 2 1231 %uint_3 = OpConstant %uint 3 1232%type__Globals = OpTypeStruct %uint %uint %uint 1233%spec_const_global = OpSpecConstantComposite %type__Globals %c_0 %c_1 %c_2 1234%insert = OpSpecConstantOp %type__Globals CompositeInsert %uint_3 %spec_const_global 1 1235%extract = OpSpecConstantOp %uint CompositeExtract %insert 1 1236 %void = OpTypeVoid 1237 %14 = OpTypeFunction %void 1238 %main = OpFunction %void None %14 1239 %16 = OpLabel 1240 OpReturn 1241 OpFunctionEnd 1242)"; 1243 1244 SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true); 1245} 1246 1247TEST_F(EliminateDeadMemberTest, 8BitIndexNoChange) { 1248 // Test that the pass does not crash when an 8 bit index is used in an 1249 // OpAccessChain. No change is expected. 1250 const std::string text = R"( 1251 OpCapability ImageQuery 1252 OpCapability Int8 1253 OpMemoryModel Logical GLSL450 1254 OpEntryPoint Fragment %1 "OpnSeman/" %2 1255 OpExecutionMode %1 OriginUpperLeft 1256 %void = OpTypeVoid 1257 %4 = OpTypeFunction %void 1258 %float = OpTypeFloat 32 1259 %v4float = OpTypeVector %float 4 1260 %_struct_7 = OpTypeStruct %v4float 1261%_ptr_Function__struct_7 = OpTypePointer Function %_struct_7 1262%_ptr_Output_v4float = OpTypePointer Output %v4float 1263 %10 = OpTypeFunction %v4float %_ptr_Function__struct_7 1264 %char = OpTypeInt 8 1 1265 %char_0 = OpConstant %char 0 1266%_ptr_Function_v4float = OpTypePointer Function %v4float 1267 %2 = OpVariable %_ptr_Output_v4float Output 1268 %1 = OpFunction %void None %4 1269 %14 = OpLabel 1270 %15 = OpVariable %_ptr_Function__struct_7 Function 1271 %16 = OpFunctionCall %v4float %17 %15 1272 OpReturn 1273 OpFunctionEnd 1274 %17 = OpFunction %v4float DontInline %10 1275 %18 = OpFunctionParameter %_ptr_Function__struct_7 1276 %19 = OpLabel 1277 %20 = OpAccessChain %_ptr_Function_v4float %18 %char_0 1278 %21 = OpLoad %v4float %20 1279 OpReturnValue %21 1280 OpFunctionEnd 1281)"; 1282 1283 auto result = SinglePassRunAndDisassemble<opt::EliminateDeadMembersPass>( 1284 text, /* skip_nop = */ true, /* do_validation = */ true); 1285 EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result)); 1286} 1287 1288TEST_F(EliminateDeadMemberTest, 8BitIndexWithChange) { 1289 // Test that the pass does not crash when an 8 bit index is used in an 1290 // OpAccessChain. The index in the access change should be changed to 0. 1291 const std::string text = R"( 1292 OpCapability ImageQuery 1293 OpCapability Int8 1294 OpMemoryModel Logical GLSL450 1295 OpEntryPoint Fragment %1 "OpnSeman/" %2 1296 OpExecutionMode %1 OriginUpperLeft 1297 %void = OpTypeVoid 1298 %4 = OpTypeFunction %void 1299 %float = OpTypeFloat 32 1300 %v4float = OpTypeVector %float 4 1301 %_struct_7 = OpTypeStruct %v4float %v4float 1302%_ptr_Function__struct_7 = OpTypePointer Function %_struct_7 1303%_ptr_Output_v4float = OpTypePointer Output %v4float 1304 %10 = OpTypeFunction %v4float %_ptr_Function__struct_7 1305 %char = OpTypeInt 8 1 1306 %char_1 = OpConstant %char 1 1307%_ptr_Function_v4float = OpTypePointer Function %v4float 1308 %2 = OpVariable %_ptr_Output_v4float Output 1309 %1 = OpFunction %void None %4 1310 %14 = OpLabel 1311 %15 = OpVariable %_ptr_Function__struct_7 Function 1312 %16 = OpFunctionCall %v4float %17 %15 1313 OpReturn 1314 OpFunctionEnd 1315 %17 = OpFunction %v4float DontInline %10 1316; CHECK: [[param:%\w+]] = OpFunctionParameter 1317 %18 = OpFunctionParameter %_ptr_Function__struct_7 1318 %19 = OpLabel 1319; CHECK: OpAccessChain %_ptr_Function_v4float [[param]] %uint_0 1320 %20 = OpAccessChain %_ptr_Function_v4float %18 %char_1 1321 %21 = OpLoad %v4float %20 1322 OpReturnValue %21 1323 OpFunctionEnd 1324)"; 1325 1326 SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true); 1327} 1328 1329} // namespace 1330