1/* 2 * Copyright © 2018 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 */ 23 24#include <gtest/gtest.h> 25 26#include "nir.h" 27#include "nir_builder.h" 28 29namespace { 30 31class nir_vars_test : public ::testing::Test { 32protected: 33 nir_vars_test(); 34 ~nir_vars_test(); 35 36 nir_variable *create_var(nir_variable_mode mode, const glsl_type *type, 37 const char *name) { 38 if (mode == nir_var_function_temp) 39 return nir_local_variable_create(b->impl, type, name); 40 else 41 return nir_variable_create(b->shader, mode, type, name); 42 } 43 44 nir_variable *create_int(nir_variable_mode mode, const char *name) { 45 return create_var(mode, glsl_int_type(), name); 46 } 47 48 nir_variable *create_ivec2(nir_variable_mode mode, const char *name) { 49 return create_var(mode, glsl_vector_type(GLSL_TYPE_INT, 2), name); 50 } 51 52 nir_variable *create_ivec4(nir_variable_mode mode, const char *name) { 53 return create_var(mode, glsl_vector_type(GLSL_TYPE_INT, 4), name); 54 } 55 56 nir_variable **create_many_int(nir_variable_mode mode, const char *prefix, unsigned count) { 57 nir_variable **result = (nir_variable **)linear_alloc_child(lin_ctx, sizeof(nir_variable *) * count); 58 for (unsigned i = 0; i < count; i++) 59 result[i] = create_int(mode, linear_asprintf(lin_ctx, "%s%u", prefix, i)); 60 return result; 61 } 62 63 nir_variable **create_many_ivec2(nir_variable_mode mode, const char *prefix, unsigned count) { 64 nir_variable **result = (nir_variable **)linear_alloc_child(lin_ctx, sizeof(nir_variable *) * count); 65 for (unsigned i = 0; i < count; i++) 66 result[i] = create_ivec2(mode, linear_asprintf(lin_ctx, "%s%u", prefix, i)); 67 return result; 68 } 69 70 nir_variable **create_many_ivec4(nir_variable_mode mode, const char *prefix, unsigned count) { 71 nir_variable **result = (nir_variable **)linear_alloc_child(lin_ctx, sizeof(nir_variable *) * count); 72 for (unsigned i = 0; i < count; i++) 73 result[i] = create_ivec4(mode, linear_asprintf(lin_ctx, "%s%u", prefix, i)); 74 return result; 75 } 76 77 unsigned count_derefs(nir_deref_type deref_type); 78 unsigned count_intrinsics(nir_intrinsic_op intrinsic); 79 unsigned count_function_temp_vars(void) { 80 return exec_list_length(&b->impl->locals); 81 } 82 83 unsigned count_shader_temp_vars(void) { 84 unsigned count = 0; 85 nir_foreach_variable_with_modes(var, b->shader, nir_var_shader_temp) 86 count++; 87 return count; 88 } 89 90 nir_intrinsic_instr *get_intrinsic(nir_intrinsic_op intrinsic, 91 unsigned index); 92 93 nir_deref_instr *get_deref(nir_deref_type deref_type, 94 unsigned index); 95 void *lin_ctx; 96 97 nir_builder *b, _b; 98}; 99 100nir_vars_test::nir_vars_test() 101{ 102 glsl_type_singleton_init_or_ref(); 103 104 static const nir_shader_compiler_options options = { }; 105 _b = nir_builder_init_simple_shader(MESA_SHADER_COMPUTE, &options, 106 "vars test"); 107 b = &_b; 108 lin_ctx = linear_alloc_parent(b->shader, 0); 109} 110 111nir_vars_test::~nir_vars_test() 112{ 113 if (HasFailure()) { 114 printf("\nShader from the failed test:\n\n"); 115 nir_print_shader(b->shader, stdout); 116 } 117 118 ralloc_free(b->shader); 119 120 glsl_type_singleton_decref(); 121} 122 123unsigned 124nir_vars_test::count_intrinsics(nir_intrinsic_op intrinsic) 125{ 126 unsigned count = 0; 127 nir_foreach_block(block, b->impl) { 128 nir_foreach_instr(instr, block) { 129 if (instr->type != nir_instr_type_intrinsic) 130 continue; 131 nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); 132 if (intrin->intrinsic == intrinsic) 133 count++; 134 } 135 } 136 return count; 137} 138 139unsigned 140nir_vars_test::count_derefs(nir_deref_type deref_type) 141{ 142 unsigned count = 0; 143 nir_foreach_block(block, b->impl) { 144 nir_foreach_instr(instr, block) { 145 if (instr->type != nir_instr_type_deref) 146 continue; 147 nir_deref_instr *intrin = nir_instr_as_deref(instr); 148 if (intrin->deref_type == deref_type) 149 count++; 150 } 151 } 152 return count; 153} 154 155nir_intrinsic_instr * 156nir_vars_test::get_intrinsic(nir_intrinsic_op intrinsic, 157 unsigned index) 158{ 159 nir_foreach_block(block, b->impl) { 160 nir_foreach_instr(instr, block) { 161 if (instr->type != nir_instr_type_intrinsic) 162 continue; 163 nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); 164 if (intrin->intrinsic == intrinsic) { 165 if (index == 0) 166 return intrin; 167 index--; 168 } 169 } 170 } 171 return NULL; 172} 173 174nir_deref_instr * 175nir_vars_test::get_deref(nir_deref_type deref_type, 176 unsigned index) 177{ 178 nir_foreach_block(block, b->impl) { 179 nir_foreach_instr(instr, block) { 180 if (instr->type != nir_instr_type_deref) 181 continue; 182 nir_deref_instr *deref = nir_instr_as_deref(instr); 183 if (deref->deref_type == deref_type) { 184 if (index == 0) 185 return deref; 186 index--; 187 } 188 } 189 } 190 return NULL; 191} 192 193/* Allow grouping the tests while still sharing the helpers. */ 194class nir_redundant_load_vars_test : public nir_vars_test {}; 195class nir_copy_prop_vars_test : public nir_vars_test {}; 196class nir_dead_write_vars_test : public nir_vars_test {}; 197class nir_combine_stores_test : public nir_vars_test {}; 198class nir_split_vars_test : public nir_vars_test {}; 199class nir_remove_dead_variables_test : public nir_vars_test {}; 200 201} // namespace 202 203static nir_ssa_def * 204nir_load_var_volatile(nir_builder *b, nir_variable *var) 205{ 206 return nir_load_deref_with_access(b, nir_build_deref_var(b, var), 207 ACCESS_VOLATILE); 208} 209 210static void 211nir_store_var_volatile(nir_builder *b, nir_variable *var, 212 nir_ssa_def *value, nir_component_mask_t writemask) 213{ 214 nir_store_deref_with_access(b, nir_build_deref_var(b, var), 215 value, writemask, ACCESS_VOLATILE); 216} 217 218TEST_F(nir_redundant_load_vars_test, duplicated_load) 219{ 220 /* Load a variable twice in the same block. One should be removed. */ 221 222 nir_variable *in = create_int(nir_var_mem_global, "in"); 223 nir_variable **out = create_many_int(nir_var_shader_out, "out", 2); 224 225 nir_store_var(b, out[0], nir_load_var(b, in), 1); 226 nir_store_var(b, out[1], nir_load_var(b, in), 1); 227 228 nir_validate_shader(b->shader, NULL); 229 230 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 2); 231 232 bool progress = nir_opt_copy_prop_vars(b->shader); 233 EXPECT_TRUE(progress); 234 235 nir_validate_shader(b->shader, NULL); 236 237 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1); 238} 239 240TEST_F(nir_redundant_load_vars_test, duplicated_load_volatile) 241{ 242 /* Load a variable twice in the same block. One should be removed. */ 243 244 nir_variable *in = create_int(nir_var_mem_global, "in"); 245 nir_variable **out = create_many_int(nir_var_shader_out, "out", 3); 246 247 /* Volatile prevents us from eliminating a load by combining it with 248 * another. It shouldn't however, prevent us from combing other 249 * non-volatile loads. 250 */ 251 nir_store_var(b, out[0], nir_load_var(b, in), 1); 252 nir_store_var(b, out[1], nir_load_var_volatile(b, in), 1); 253 nir_store_var(b, out[2], nir_load_var(b, in), 1); 254 255 nir_validate_shader(b->shader, NULL); 256 257 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 3); 258 259 bool progress = nir_opt_copy_prop_vars(b->shader); 260 EXPECT_TRUE(progress); 261 262 nir_validate_shader(b->shader, NULL); 263 264 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 2); 265 266 nir_intrinsic_instr *first_store = get_intrinsic(nir_intrinsic_store_deref, 0); 267 ASSERT_TRUE(first_store->src[1].is_ssa); 268 269 nir_intrinsic_instr *third_store = get_intrinsic(nir_intrinsic_store_deref, 2); 270 ASSERT_TRUE(third_store->src[1].is_ssa); 271 272 EXPECT_EQ(first_store->src[1].ssa, third_store->src[1].ssa); 273} 274 275TEST_F(nir_redundant_load_vars_test, duplicated_load_in_two_blocks) 276{ 277 /* Load a variable twice in different blocks. One should be removed. */ 278 279 nir_variable *in = create_int(nir_var_mem_global, "in"); 280 nir_variable **out = create_many_int(nir_var_shader_out, "out", 2); 281 282 nir_store_var(b, out[0], nir_load_var(b, in), 1); 283 284 /* Forces the stores to be in different blocks. */ 285 nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0))); 286 287 nir_store_var(b, out[1], nir_load_var(b, in), 1); 288 289 nir_validate_shader(b->shader, NULL); 290 291 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 2); 292 293 bool progress = nir_opt_copy_prop_vars(b->shader); 294 EXPECT_TRUE(progress); 295 296 nir_validate_shader(b->shader, NULL); 297 298 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1); 299} 300 301TEST_F(nir_redundant_load_vars_test, invalidate_inside_if_block) 302{ 303 /* Load variables, then write to some of then in different branches of the 304 * if statement. They should be invalidated accordingly. 305 */ 306 307 nir_variable **g = create_many_int(nir_var_shader_temp, "g", 3); 308 nir_variable **out = create_many_int(nir_var_shader_out, "out", 3); 309 310 nir_load_var(b, g[0]); 311 nir_load_var(b, g[1]); 312 nir_load_var(b, g[2]); 313 314 nir_if *if_stmt = nir_push_if(b, nir_imm_int(b, 0)); 315 nir_store_var(b, g[0], nir_imm_int(b, 10), 1); 316 317 nir_push_else(b, if_stmt); 318 nir_store_var(b, g[1], nir_imm_int(b, 20), 1); 319 320 nir_pop_if(b, if_stmt); 321 322 nir_store_var(b, out[0], nir_load_var(b, g[0]), 1); 323 nir_store_var(b, out[1], nir_load_var(b, g[1]), 1); 324 nir_store_var(b, out[2], nir_load_var(b, g[2]), 1); 325 326 nir_validate_shader(b->shader, NULL); 327 328 bool progress = nir_opt_copy_prop_vars(b->shader); 329 EXPECT_TRUE(progress); 330 331 /* There are 3 initial loads, plus 2 loads for the values invalidated 332 * inside the if statement. 333 */ 334 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 5); 335 336 /* We only load g[2] once. */ 337 unsigned g2_load_count = 0; 338 for (int i = 0; i < 5; i++) { 339 nir_intrinsic_instr *load = get_intrinsic(nir_intrinsic_load_deref, i); 340 if (nir_intrinsic_get_var(load, 0) == g[2]) 341 g2_load_count++; 342 } 343 EXPECT_EQ(g2_load_count, 1); 344} 345 346TEST_F(nir_redundant_load_vars_test, invalidate_live_load_in_the_end_of_loop) 347{ 348 /* Invalidating a load in the end of loop body will apply to the whole loop 349 * body. 350 */ 351 352 nir_variable *v = create_int(nir_var_mem_global, "v"); 353 354 nir_load_var(b, v); 355 356 nir_loop *loop = nir_push_loop(b); 357 358 nir_if *if_stmt = nir_push_if(b, nir_imm_int(b, 0)); 359 nir_jump(b, nir_jump_break); 360 nir_pop_if(b, if_stmt); 361 362 nir_load_var(b, v); 363 nir_store_var(b, v, nir_imm_int(b, 10), 1); 364 365 nir_pop_loop(b, loop); 366 367 bool progress = nir_opt_copy_prop_vars(b->shader); 368 ASSERT_FALSE(progress); 369} 370 371TEST_F(nir_copy_prop_vars_test, simple_copies) 372{ 373 nir_variable *in = create_int(nir_var_shader_in, "in"); 374 nir_variable *temp = create_int(nir_var_function_temp, "temp"); 375 nir_variable *out = create_int(nir_var_shader_out, "out"); 376 377 nir_copy_var(b, temp, in); 378 nir_copy_var(b, out, temp); 379 380 nir_validate_shader(b->shader, NULL); 381 382 bool progress = nir_opt_copy_prop_vars(b->shader); 383 EXPECT_TRUE(progress); 384 385 nir_validate_shader(b->shader, NULL); 386 387 ASSERT_EQ(count_intrinsics(nir_intrinsic_copy_deref), 2); 388 389 nir_intrinsic_instr *first_copy = get_intrinsic(nir_intrinsic_copy_deref, 0); 390 ASSERT_TRUE(first_copy->src[1].is_ssa); 391 392 nir_intrinsic_instr *second_copy = get_intrinsic(nir_intrinsic_copy_deref, 1); 393 ASSERT_TRUE(second_copy->src[1].is_ssa); 394 395 EXPECT_EQ(first_copy->src[1].ssa, second_copy->src[1].ssa); 396} 397 398TEST_F(nir_copy_prop_vars_test, self_copy) 399{ 400 nir_variable *v = create_int(nir_var_mem_global, "v"); 401 402 nir_copy_var(b, v, v); 403 404 nir_validate_shader(b->shader, NULL); 405 406 bool progress = nir_opt_copy_prop_vars(b->shader); 407 EXPECT_TRUE(progress); 408 409 nir_validate_shader(b->shader, NULL); 410 411 ASSERT_EQ(count_intrinsics(nir_intrinsic_copy_deref), 0); 412} 413 414TEST_F(nir_copy_prop_vars_test, simple_store_load) 415{ 416 nir_variable **v = create_many_ivec2(nir_var_function_temp, "v", 2); 417 unsigned mask = 1 | 2; 418 419 nir_ssa_def *stored_value = nir_imm_ivec2(b, 10, 20); 420 nir_store_var(b, v[0], stored_value, mask); 421 422 nir_ssa_def *read_value = nir_load_var(b, v[0]); 423 nir_store_var(b, v[1], read_value, mask); 424 425 nir_validate_shader(b->shader, NULL); 426 427 bool progress = nir_opt_copy_prop_vars(b->shader); 428 EXPECT_TRUE(progress); 429 430 nir_validate_shader(b->shader, NULL); 431 432 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 2); 433 434 for (int i = 0; i < 2; i++) { 435 nir_intrinsic_instr *store = get_intrinsic(nir_intrinsic_store_deref, i); 436 ASSERT_TRUE(store->src[1].is_ssa); 437 EXPECT_EQ(store->src[1].ssa, stored_value); 438 } 439} 440 441TEST_F(nir_copy_prop_vars_test, store_store_load) 442{ 443 nir_variable **v = create_many_ivec2(nir_var_function_temp, "v", 2); 444 unsigned mask = 1 | 2; 445 446 nir_ssa_def *first_value = nir_imm_ivec2(b, 10, 20); 447 nir_store_var(b, v[0], first_value, mask); 448 449 nir_ssa_def *second_value = nir_imm_ivec2(b, 30, 40); 450 nir_store_var(b, v[0], second_value, mask); 451 452 nir_ssa_def *read_value = nir_load_var(b, v[0]); 453 nir_store_var(b, v[1], read_value, mask); 454 455 nir_validate_shader(b->shader, NULL); 456 457 bool progress = nir_opt_copy_prop_vars(b->shader); 458 EXPECT_TRUE(progress); 459 460 nir_validate_shader(b->shader, NULL); 461 462 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3); 463 464 /* Store to v[1] should use second_value directly. */ 465 nir_intrinsic_instr *store_to_v1 = get_intrinsic(nir_intrinsic_store_deref, 2); 466 ASSERT_EQ(nir_intrinsic_get_var(store_to_v1, 0), v[1]); 467 ASSERT_TRUE(store_to_v1->src[1].is_ssa); 468 EXPECT_EQ(store_to_v1->src[1].ssa, second_value); 469} 470 471TEST_F(nir_copy_prop_vars_test, store_store_load_different_components) 472{ 473 nir_variable **v = create_many_ivec2(nir_var_function_temp, "v", 2); 474 475 nir_ssa_def *first_value = nir_imm_ivec2(b, 10, 20); 476 nir_store_var(b, v[0], first_value, 1 << 1); 477 478 nir_ssa_def *second_value = nir_imm_ivec2(b, 30, 40); 479 nir_store_var(b, v[0], second_value, 1 << 0); 480 481 nir_ssa_def *read_value = nir_load_var(b, v[0]); 482 nir_store_var(b, v[1], read_value, 1 << 1); 483 484 nir_validate_shader(b->shader, NULL); 485 486 bool progress = nir_opt_copy_prop_vars(b->shader); 487 EXPECT_TRUE(progress); 488 489 nir_validate_shader(b->shader, NULL); 490 491 nir_opt_constant_folding(b->shader); 492 nir_validate_shader(b->shader, NULL); 493 494 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3); 495 496 /* Store to v[1] should use first_value directly. The write of 497 * second_value did not overwrite the component it uses. 498 */ 499 nir_intrinsic_instr *store_to_v1 = get_intrinsic(nir_intrinsic_store_deref, 2); 500 ASSERT_EQ(nir_intrinsic_get_var(store_to_v1, 0), v[1]); 501 ASSERT_EQ(nir_src_comp_as_uint(store_to_v1->src[1], 1), 20); 502} 503 504TEST_F(nir_copy_prop_vars_test, store_store_load_different_components_in_many_blocks) 505{ 506 nir_variable **v = create_many_ivec2(nir_var_function_temp, "v", 2); 507 508 nir_ssa_def *first_value = nir_imm_ivec2(b, 10, 20); 509 nir_store_var(b, v[0], first_value, 1 << 1); 510 511 /* Adding an if statement will cause blocks to be created. */ 512 nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0))); 513 514 nir_ssa_def *second_value = nir_imm_ivec2(b, 30, 40); 515 nir_store_var(b, v[0], second_value, 1 << 0); 516 517 /* Adding an if statement will cause blocks to be created. */ 518 nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0))); 519 520 nir_ssa_def *read_value = nir_load_var(b, v[0]); 521 nir_store_var(b, v[1], read_value, 1 << 1); 522 523 nir_validate_shader(b->shader, NULL); 524 525 bool progress = nir_opt_copy_prop_vars(b->shader); 526 EXPECT_TRUE(progress); 527 528 nir_validate_shader(b->shader, NULL); 529 530 nir_opt_constant_folding(b->shader); 531 nir_validate_shader(b->shader, NULL); 532 533 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3); 534 535 /* Store to v[1] should use first_value directly. The write of 536 * second_value did not overwrite the component it uses. 537 */ 538 nir_intrinsic_instr *store_to_v1 = get_intrinsic(nir_intrinsic_store_deref, 2); 539 ASSERT_EQ(nir_intrinsic_get_var(store_to_v1, 0), v[1]); 540 ASSERT_EQ(nir_src_comp_as_uint(store_to_v1->src[1], 1), 20); 541} 542 543TEST_F(nir_copy_prop_vars_test, store_volatile) 544{ 545 nir_variable **v = create_many_ivec2(nir_var_function_temp, "v", 2); 546 unsigned mask = 1 | 2; 547 548 nir_ssa_def *first_value = nir_imm_ivec2(b, 10, 20); 549 nir_store_var(b, v[0], first_value, mask); 550 551 nir_ssa_def *second_value = nir_imm_ivec2(b, 30, 40); 552 nir_store_var_volatile(b, v[0], second_value, mask); 553 554 nir_ssa_def *third_value = nir_imm_ivec2(b, 50, 60); 555 nir_store_var(b, v[0], third_value, mask); 556 557 nir_ssa_def *read_value = nir_load_var(b, v[0]); 558 nir_store_var(b, v[1], read_value, mask); 559 560 nir_validate_shader(b->shader, NULL); 561 562 bool progress = nir_opt_copy_prop_vars(b->shader); 563 EXPECT_TRUE(progress); 564 565 nir_validate_shader(b->shader, NULL); 566 567 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 4); 568 569 /* Our approach here is a bit scorched-earth. We expect the volatile store 570 * in the middle to cause both that store and the one before it to be kept. 571 * Technically, volatile only prevents combining the volatile store with 572 * another store and one could argue that the store before the volatile and 573 * the one after it could be combined. However, it seems safer to just 574 * treat a volatile store like an atomic and prevent any combining across 575 * it. 576 */ 577 nir_intrinsic_instr *store_to_v1 = get_intrinsic(nir_intrinsic_store_deref, 3); 578 ASSERT_EQ(nir_intrinsic_get_var(store_to_v1, 0), v[1]); 579 ASSERT_TRUE(store_to_v1->src[1].is_ssa); 580 EXPECT_EQ(store_to_v1->src[1].ssa, third_value); 581} 582 583TEST_F(nir_copy_prop_vars_test, self_copy_volatile) 584{ 585 nir_variable *v = create_int(nir_var_mem_global, "v"); 586 587 nir_copy_var(b, v, v); 588 nir_copy_deref_with_access(b, nir_build_deref_var(b, v), 589 nir_build_deref_var(b, v), 590 (gl_access_qualifier)0, ACCESS_VOLATILE); 591 nir_copy_deref_with_access(b, nir_build_deref_var(b, v), 592 nir_build_deref_var(b, v), 593 ACCESS_VOLATILE, (gl_access_qualifier)0); 594 nir_copy_var(b, v, v); 595 596 nir_validate_shader(b->shader, NULL); 597 598 bool progress = nir_opt_copy_prop_vars(b->shader); 599 EXPECT_TRUE(progress); 600 601 nir_validate_shader(b->shader, NULL); 602 603 ASSERT_EQ(count_intrinsics(nir_intrinsic_copy_deref), 2); 604 605 /* Store to v[1] should use second_value directly. */ 606 nir_intrinsic_instr *first = get_intrinsic(nir_intrinsic_copy_deref, 0); 607 nir_intrinsic_instr *second = get_intrinsic(nir_intrinsic_copy_deref, 1); 608 ASSERT_EQ(nir_intrinsic_src_access(first), ACCESS_VOLATILE); 609 ASSERT_EQ(nir_intrinsic_dst_access(first), (gl_access_qualifier)0); 610 ASSERT_EQ(nir_intrinsic_src_access(second), (gl_access_qualifier)0); 611 ASSERT_EQ(nir_intrinsic_dst_access(second), ACCESS_VOLATILE); 612} 613 614TEST_F(nir_copy_prop_vars_test, memory_barrier_in_two_blocks) 615{ 616 nir_variable **v = create_many_int(nir_var_mem_global, "v", 4); 617 618 nir_store_var(b, v[0], nir_imm_int(b, 1), 1); 619 nir_store_var(b, v[1], nir_imm_int(b, 2), 1); 620 621 /* Split into many blocks. */ 622 nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0))); 623 624 nir_store_var(b, v[2], nir_load_var(b, v[0]), 1); 625 626 nir_scoped_memory_barrier(b, NIR_SCOPE_DEVICE, NIR_MEMORY_ACQ_REL, 627 nir_var_mem_global); 628 629 nir_store_var(b, v[3], nir_load_var(b, v[1]), 1); 630 631 bool progress = nir_opt_copy_prop_vars(b->shader); 632 ASSERT_TRUE(progress); 633 634 /* Only the second load will remain after the optimization. */ 635 ASSERT_EQ(1, count_intrinsics(nir_intrinsic_load_deref)); 636 nir_intrinsic_instr *load = get_intrinsic(nir_intrinsic_load_deref, 0); 637 ASSERT_EQ(nir_intrinsic_get_var(load, 0), v[1]); 638} 639 640TEST_F(nir_redundant_load_vars_test, acquire_barrier_prevents_load_removal) 641{ 642 nir_variable **x = create_many_int(nir_var_mem_global, "x", 1); 643 644 nir_load_var(b, x[0]); 645 646 nir_scoped_memory_barrier(b, NIR_SCOPE_DEVICE, NIR_MEMORY_ACQUIRE, 647 nir_var_mem_global); 648 649 nir_load_var(b, x[0]); 650 651 bool progress = nir_opt_copy_prop_vars(b->shader); 652 ASSERT_FALSE(progress); 653 654 ASSERT_EQ(2, count_intrinsics(nir_intrinsic_load_deref)); 655} 656 657TEST_F(nir_redundant_load_vars_test, acquire_barrier_prevents_same_mode_load_removal) 658{ 659 nir_variable **x = create_many_int(nir_var_mem_global, "x", 2); 660 661 nir_load_var(b, x[0]); 662 nir_load_var(b, x[1]); 663 664 nir_scoped_memory_barrier(b, NIR_SCOPE_DEVICE, NIR_MEMORY_ACQUIRE, 665 nir_var_mem_global); 666 667 nir_load_var(b, x[0]); 668 nir_load_var(b, x[1]); 669 670 bool progress = nir_opt_copy_prop_vars(b->shader); 671 ASSERT_FALSE(progress); 672 673 ASSERT_EQ(4, count_intrinsics(nir_intrinsic_load_deref)); 674} 675 676TEST_F(nir_redundant_load_vars_test, acquire_barrier_allows_different_mode_load_removal) 677{ 678 nir_variable **x = create_many_int(nir_var_mem_global, "x", 2); 679 nir_variable **y = create_many_int(nir_var_mem_shared, "y", 2); 680 681 nir_load_var(b, x[0]); 682 nir_load_var(b, x[1]); 683 nir_load_var(b, y[0]); 684 nir_load_var(b, y[1]); 685 686 nir_scoped_memory_barrier(b, NIR_SCOPE_DEVICE, NIR_MEMORY_ACQUIRE, 687 nir_var_mem_global); 688 689 nir_load_var(b, x[0]); 690 nir_load_var(b, x[1]); 691 nir_load_var(b, y[0]); 692 nir_load_var(b, y[1]); 693 694 bool progress = nir_opt_copy_prop_vars(b->shader); 695 ASSERT_TRUE(progress); 696 697 ASSERT_EQ(6, count_intrinsics(nir_intrinsic_load_deref)); 698 699 nir_intrinsic_instr *load; 700 701 load = get_intrinsic(nir_intrinsic_load_deref, 0); 702 ASSERT_EQ(nir_intrinsic_get_var(load, 0), x[0]); 703 load = get_intrinsic(nir_intrinsic_load_deref, 1); 704 ASSERT_EQ(nir_intrinsic_get_var(load, 0), x[1]); 705 706 load = get_intrinsic(nir_intrinsic_load_deref, 2); 707 ASSERT_EQ(nir_intrinsic_get_var(load, 0), y[0]); 708 load = get_intrinsic(nir_intrinsic_load_deref, 3); 709 ASSERT_EQ(nir_intrinsic_get_var(load, 0), y[1]); 710 711 load = get_intrinsic(nir_intrinsic_load_deref, 4); 712 ASSERT_EQ(nir_intrinsic_get_var(load, 0), x[0]); 713 load = get_intrinsic(nir_intrinsic_load_deref, 5); 714 ASSERT_EQ(nir_intrinsic_get_var(load, 0), x[1]); 715} 716 717TEST_F(nir_redundant_load_vars_test, release_barrier_allows_load_removal) 718{ 719 nir_variable **x = create_many_int(nir_var_mem_global, "x", 1); 720 721 nir_load_var(b, x[0]); 722 723 nir_scoped_memory_barrier(b, NIR_SCOPE_DEVICE, NIR_MEMORY_RELEASE, 724 nir_var_mem_global); 725 726 nir_load_var(b, x[0]); 727 728 bool progress = nir_opt_copy_prop_vars(b->shader); 729 ASSERT_TRUE(progress); 730 731 ASSERT_EQ(1, count_intrinsics(nir_intrinsic_load_deref)); 732} 733 734TEST_F(nir_redundant_load_vars_test, release_barrier_allows_same_mode_load_removal) 735{ 736 nir_variable **x = create_many_int(nir_var_mem_global, "x", 2); 737 738 nir_load_var(b, x[0]); 739 nir_load_var(b, x[1]); 740 741 nir_scoped_memory_barrier(b, NIR_SCOPE_DEVICE, NIR_MEMORY_RELEASE, 742 nir_var_mem_global); 743 744 nir_load_var(b, x[0]); 745 nir_load_var(b, x[1]); 746 747 bool progress = nir_opt_copy_prop_vars(b->shader); 748 ASSERT_TRUE(progress); 749 750 ASSERT_EQ(2, count_intrinsics(nir_intrinsic_load_deref)); 751} 752 753TEST_F(nir_redundant_load_vars_test, release_barrier_allows_different_mode_load_removal) 754{ 755 nir_variable **x = create_many_int(nir_var_mem_global, "x", 2); 756 nir_variable **y = create_many_int(nir_var_mem_shared, "y", 2); 757 758 nir_load_var(b, x[0]); 759 nir_load_var(b, x[1]); 760 nir_load_var(b, y[0]); 761 nir_load_var(b, y[1]); 762 763 nir_scoped_memory_barrier(b, NIR_SCOPE_DEVICE, NIR_MEMORY_RELEASE, 764 nir_var_mem_global); 765 766 nir_load_var(b, x[0]); 767 nir_load_var(b, x[1]); 768 nir_load_var(b, y[0]); 769 nir_load_var(b, y[1]); 770 771 bool progress = nir_opt_copy_prop_vars(b->shader); 772 ASSERT_TRUE(progress); 773 774 ASSERT_EQ(4, count_intrinsics(nir_intrinsic_load_deref)); 775 776 nir_intrinsic_instr *load; 777 778 load = get_intrinsic(nir_intrinsic_load_deref, 0); 779 ASSERT_EQ(nir_intrinsic_get_var(load, 0), x[0]); 780 load = get_intrinsic(nir_intrinsic_load_deref, 1); 781 ASSERT_EQ(nir_intrinsic_get_var(load, 0), x[1]); 782 783 load = get_intrinsic(nir_intrinsic_load_deref, 2); 784 ASSERT_EQ(nir_intrinsic_get_var(load, 0), y[0]); 785 load = get_intrinsic(nir_intrinsic_load_deref, 3); 786 ASSERT_EQ(nir_intrinsic_get_var(load, 0), y[1]); 787} 788 789TEST_F(nir_copy_prop_vars_test, acquire_barrier_prevents_propagation) 790{ 791 nir_variable **x = create_many_int(nir_var_mem_global, "x", 1); 792 793 nir_store_var(b, x[0], nir_imm_int(b, 10), 1); 794 795 nir_scoped_memory_barrier(b, NIR_SCOPE_DEVICE, NIR_MEMORY_ACQUIRE, 796 nir_var_mem_global); 797 798 nir_load_var(b, x[0]); 799 800 bool progress = nir_opt_copy_prop_vars(b->shader); 801 ASSERT_FALSE(progress); 802 803 ASSERT_EQ(1, count_intrinsics(nir_intrinsic_store_deref)); 804 ASSERT_EQ(1, count_intrinsics(nir_intrinsic_load_deref)); 805} 806 807TEST_F(nir_copy_prop_vars_test, acquire_barrier_prevents_same_mode_propagation) 808{ 809 nir_variable **x = create_many_int(nir_var_mem_global, "x", 2); 810 811 nir_store_var(b, x[0], nir_imm_int(b, 10), 1); 812 nir_store_var(b, x[1], nir_imm_int(b, 20), 1); 813 814 nir_scoped_memory_barrier(b, NIR_SCOPE_DEVICE, NIR_MEMORY_ACQUIRE, 815 nir_var_mem_global); 816 817 nir_load_var(b, x[0]); 818 nir_load_var(b, x[1]); 819 820 bool progress = nir_opt_copy_prop_vars(b->shader); 821 ASSERT_FALSE(progress); 822 823 ASSERT_EQ(2, count_intrinsics(nir_intrinsic_store_deref)); 824 ASSERT_EQ(2, count_intrinsics(nir_intrinsic_load_deref)); 825} 826 827TEST_F(nir_copy_prop_vars_test, acquire_barrier_allows_different_mode_propagation) 828{ 829 nir_variable **x = create_many_int(nir_var_mem_global, "x", 2); 830 nir_variable **y = create_many_int(nir_var_mem_shared, "y", 2); 831 832 nir_store_var(b, x[0], nir_imm_int(b, 10), 1); 833 nir_store_var(b, x[1], nir_imm_int(b, 20), 1); 834 nir_store_var(b, y[0], nir_imm_int(b, 30), 1); 835 nir_store_var(b, y[1], nir_imm_int(b, 40), 1); 836 837 nir_scoped_memory_barrier(b, NIR_SCOPE_DEVICE, NIR_MEMORY_ACQUIRE, 838 nir_var_mem_global); 839 840 nir_load_var(b, x[0]); 841 nir_load_var(b, x[1]); 842 nir_load_var(b, y[0]); 843 nir_load_var(b, y[1]); 844 845 bool progress = nir_opt_copy_prop_vars(b->shader); 846 ASSERT_TRUE(progress); 847 848 ASSERT_EQ(4, count_intrinsics(nir_intrinsic_store_deref)); 849 ASSERT_EQ(2, count_intrinsics(nir_intrinsic_load_deref)); 850 851 nir_intrinsic_instr *store; 852 853 store = get_intrinsic(nir_intrinsic_store_deref, 0); 854 ASSERT_EQ(nir_intrinsic_get_var(store, 0), x[0]); 855 store = get_intrinsic(nir_intrinsic_store_deref, 1); 856 ASSERT_EQ(nir_intrinsic_get_var(store, 0), x[1]); 857 858 store = get_intrinsic(nir_intrinsic_store_deref, 2); 859 ASSERT_EQ(nir_intrinsic_get_var(store, 0), y[0]); 860 store = get_intrinsic(nir_intrinsic_store_deref, 3); 861 ASSERT_EQ(nir_intrinsic_get_var(store, 0), y[1]); 862 863 nir_intrinsic_instr *load; 864 865 load = get_intrinsic(nir_intrinsic_load_deref, 0); 866 ASSERT_EQ(nir_intrinsic_get_var(load, 0), x[0]); 867 load = get_intrinsic(nir_intrinsic_load_deref, 1); 868 ASSERT_EQ(nir_intrinsic_get_var(load, 0), x[1]); 869} 870 871TEST_F(nir_copy_prop_vars_test, release_barrier_allows_propagation) 872{ 873 nir_variable **x = create_many_int(nir_var_mem_global, "x", 1); 874 875 nir_store_var(b, x[0], nir_imm_int(b, 10), 1); 876 877 nir_scoped_memory_barrier(b, NIR_SCOPE_DEVICE, NIR_MEMORY_RELEASE, 878 nir_var_mem_global); 879 880 nir_load_var(b, x[0]); 881 882 bool progress = nir_opt_copy_prop_vars(b->shader); 883 ASSERT_TRUE(progress); 884 885 ASSERT_EQ(1, count_intrinsics(nir_intrinsic_store_deref)); 886} 887 888TEST_F(nir_copy_prop_vars_test, release_barrier_allows_same_mode_propagation) 889{ 890 nir_variable **x = create_many_int(nir_var_mem_global, "x", 2); 891 892 nir_store_var(b, x[0], nir_imm_int(b, 10), 1); 893 nir_store_var(b, x[1], nir_imm_int(b, 20), 1); 894 895 nir_scoped_memory_barrier(b, NIR_SCOPE_DEVICE, NIR_MEMORY_RELEASE, 896 nir_var_mem_global); 897 898 nir_load_var(b, x[0]); 899 nir_load_var(b, x[1]); 900 901 bool progress = nir_opt_copy_prop_vars(b->shader); 902 ASSERT_TRUE(progress); 903 904 ASSERT_EQ(2, count_intrinsics(nir_intrinsic_store_deref)); 905 ASSERT_EQ(0, count_intrinsics(nir_intrinsic_load_deref)); 906} 907 908TEST_F(nir_copy_prop_vars_test, release_barrier_allows_different_mode_propagation) 909{ 910 nir_variable **x = create_many_int(nir_var_mem_global, "x", 2); 911 nir_variable **y = create_many_int(nir_var_mem_shared, "y", 2); 912 913 nir_store_var(b, x[0], nir_imm_int(b, 10), 1); 914 nir_store_var(b, x[1], nir_imm_int(b, 20), 1); 915 nir_store_var(b, y[0], nir_imm_int(b, 30), 1); 916 nir_store_var(b, y[1], nir_imm_int(b, 40), 1); 917 918 nir_scoped_memory_barrier(b, NIR_SCOPE_DEVICE, NIR_MEMORY_RELEASE, 919 nir_var_mem_global); 920 921 nir_load_var(b, x[0]); 922 nir_load_var(b, x[1]); 923 nir_load_var(b, y[0]); 924 nir_load_var(b, y[1]); 925 926 bool progress = nir_opt_copy_prop_vars(b->shader); 927 ASSERT_TRUE(progress); 928 929 ASSERT_EQ(4, count_intrinsics(nir_intrinsic_store_deref)); 930 ASSERT_EQ(0, count_intrinsics(nir_intrinsic_load_deref)); 931 932 nir_intrinsic_instr *store; 933 934 store = get_intrinsic(nir_intrinsic_store_deref, 0); 935 ASSERT_EQ(nir_intrinsic_get_var(store, 0), x[0]); 936 store = get_intrinsic(nir_intrinsic_store_deref, 1); 937 ASSERT_EQ(nir_intrinsic_get_var(store, 0), x[1]); 938 939 store = get_intrinsic(nir_intrinsic_store_deref, 2); 940 ASSERT_EQ(nir_intrinsic_get_var(store, 0), y[0]); 941 store = get_intrinsic(nir_intrinsic_store_deref, 3); 942 ASSERT_EQ(nir_intrinsic_get_var(store, 0), y[1]); 943} 944 945TEST_F(nir_copy_prop_vars_test, acquire_barrier_prevents_propagation_from_copy) 946{ 947 nir_variable **x = create_many_int(nir_var_mem_global, "x", 3); 948 949 nir_copy_var(b, x[1], x[0]); 950 951 nir_scoped_memory_barrier(b, NIR_SCOPE_DEVICE, NIR_MEMORY_ACQUIRE, 952 nir_var_mem_global); 953 954 nir_copy_var(b, x[2], x[1]); 955 956 bool progress = nir_opt_copy_prop_vars(b->shader); 957 ASSERT_FALSE(progress); 958 959 ASSERT_EQ(2, count_intrinsics(nir_intrinsic_copy_deref)); 960 961 nir_intrinsic_instr *copy; 962 963 copy = get_intrinsic(nir_intrinsic_copy_deref, 0); 964 ASSERT_EQ(nir_intrinsic_get_var(copy, 1), x[0]); 965 966 copy = get_intrinsic(nir_intrinsic_copy_deref, 1); 967 ASSERT_EQ(nir_intrinsic_get_var(copy, 1), x[1]); 968} 969 970TEST_F(nir_copy_prop_vars_test, acquire_barrier_prevents_propagation_from_copy_to_different_mode) 971{ 972 nir_variable **x = create_many_int(nir_var_mem_global, "x", 2); 973 nir_variable **y = create_many_int(nir_var_mem_shared, "y", 1); 974 975 nir_copy_var(b, y[0], x[0]); 976 977 nir_scoped_memory_barrier(b, NIR_SCOPE_DEVICE, NIR_MEMORY_ACQUIRE, 978 nir_var_mem_global); 979 980 nir_copy_var(b, x[1], y[0]); 981 982 bool progress = nir_opt_copy_prop_vars(b->shader); 983 ASSERT_FALSE(progress); 984 985 ASSERT_EQ(2, count_intrinsics(nir_intrinsic_copy_deref)); 986 987 nir_intrinsic_instr *copy; 988 989 copy = get_intrinsic(nir_intrinsic_copy_deref, 0); 990 ASSERT_EQ(nir_intrinsic_get_var(copy, 1), x[0]); 991 992 copy = get_intrinsic(nir_intrinsic_copy_deref, 1); 993 ASSERT_EQ(nir_intrinsic_get_var(copy, 1), y[0]); 994} 995 996TEST_F(nir_copy_prop_vars_test, release_barrier_allows_propagation_from_copy) 997{ 998 nir_variable **x = create_many_int(nir_var_mem_global, "x", 3); 999 1000 nir_copy_var(b, x[1], x[0]); 1001 1002 nir_scoped_memory_barrier(b, NIR_SCOPE_DEVICE, NIR_MEMORY_RELEASE, 1003 nir_var_mem_global); 1004 1005 nir_copy_var(b, x[2], x[1]); 1006 1007 bool progress = nir_opt_copy_prop_vars(b->shader); 1008 ASSERT_TRUE(progress); 1009 1010 ASSERT_EQ(2, count_intrinsics(nir_intrinsic_copy_deref)); 1011 1012 nir_intrinsic_instr *copy; 1013 1014 copy = get_intrinsic(nir_intrinsic_copy_deref, 0); 1015 ASSERT_EQ(nir_intrinsic_get_var(copy, 1), x[0]); 1016 1017 copy = get_intrinsic(nir_intrinsic_copy_deref, 1); 1018 ASSERT_EQ(nir_intrinsic_get_var(copy, 1), x[0]); 1019} 1020 1021TEST_F(nir_copy_prop_vars_test, release_barrier_allows_propagation_from_copy_to_different_mode) 1022{ 1023 nir_variable **x = create_many_int(nir_var_mem_global, "x", 2); 1024 nir_variable **y = create_many_int(nir_var_mem_shared, "y", 1); 1025 1026 nir_copy_var(b, y[0], x[0]); 1027 1028 nir_scoped_memory_barrier(b, NIR_SCOPE_DEVICE, NIR_MEMORY_RELEASE, 1029 nir_var_mem_global); 1030 1031 nir_copy_var(b, x[1], y[0]); 1032 1033 bool progress = nir_opt_copy_prop_vars(b->shader); 1034 ASSERT_TRUE(progress); 1035 1036 ASSERT_EQ(2, count_intrinsics(nir_intrinsic_copy_deref)); 1037 1038 nir_intrinsic_instr *copy; 1039 1040 copy = get_intrinsic(nir_intrinsic_copy_deref, 0); 1041 ASSERT_EQ(nir_intrinsic_get_var(copy, 1), x[0]); 1042 1043 copy = get_intrinsic(nir_intrinsic_copy_deref, 1); 1044 ASSERT_EQ(nir_intrinsic_get_var(copy, 1), x[0]); 1045} 1046 1047TEST_F(nir_copy_prop_vars_test, simple_store_load_in_two_blocks) 1048{ 1049 nir_variable **v = create_many_ivec2(nir_var_function_temp, "v", 2); 1050 unsigned mask = 1 | 2; 1051 1052 nir_ssa_def *stored_value = nir_imm_ivec2(b, 10, 20); 1053 nir_store_var(b, v[0], stored_value, mask); 1054 1055 /* Adding an if statement will cause blocks to be created. */ 1056 nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0))); 1057 1058 nir_ssa_def *read_value = nir_load_var(b, v[0]); 1059 nir_store_var(b, v[1], read_value, mask); 1060 1061 nir_validate_shader(b->shader, NULL); 1062 1063 bool progress = nir_opt_copy_prop_vars(b->shader); 1064 EXPECT_TRUE(progress); 1065 1066 nir_validate_shader(b->shader, NULL); 1067 1068 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 2); 1069 1070 for (int i = 0; i < 2; i++) { 1071 nir_intrinsic_instr *store = get_intrinsic(nir_intrinsic_store_deref, i); 1072 ASSERT_TRUE(store->src[1].is_ssa); 1073 EXPECT_EQ(store->src[1].ssa, stored_value); 1074 } 1075} 1076 1077TEST_F(nir_copy_prop_vars_test, load_direct_array_deref_on_vector_reuses_previous_load) 1078{ 1079 nir_variable *in0 = create_ivec2(nir_var_mem_global, "in0"); 1080 nir_variable *in1 = create_ivec2(nir_var_mem_global, "in1"); 1081 nir_variable *vec = create_ivec2(nir_var_mem_global, "vec"); 1082 nir_variable *out = create_int(nir_var_mem_global, "out"); 1083 1084 nir_store_var(b, vec, nir_load_var(b, in0), 1 << 0); 1085 nir_store_var(b, vec, nir_load_var(b, in1), 1 << 1); 1086 1087 /* This load will be dropped, as vec.y (or vec[1]) is already known. */ 1088 nir_deref_instr *deref = 1089 nir_build_deref_array_imm(b, nir_build_deref_var(b, vec), 1); 1090 nir_ssa_def *loaded_from_deref = nir_load_deref(b, deref); 1091 1092 /* This store should use the value loaded from in1. */ 1093 nir_store_var(b, out, loaded_from_deref, 1 << 0); 1094 1095 nir_validate_shader(b->shader, NULL); 1096 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 3); 1097 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3); 1098 1099 bool progress = nir_opt_copy_prop_vars(b->shader); 1100 EXPECT_TRUE(progress); 1101 1102 nir_validate_shader(b->shader, NULL); 1103 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 2); 1104 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3); 1105 1106 nir_intrinsic_instr *store = get_intrinsic(nir_intrinsic_store_deref, 2); 1107 ASSERT_TRUE(store->src[1].is_ssa); 1108 1109 /* NOTE: The ALU instruction is how we get the vec.y. */ 1110 ASSERT_TRUE(nir_src_as_alu_instr(store->src[1])); 1111} 1112 1113TEST_F(nir_copy_prop_vars_test, load_direct_array_deref_on_vector_reuses_previous_copy) 1114{ 1115 nir_variable *in0 = create_ivec2(nir_var_mem_global, "in0"); 1116 nir_variable *vec = create_ivec2(nir_var_mem_global, "vec"); 1117 1118 nir_copy_var(b, vec, in0); 1119 1120 /* This load will be replaced with one from in0. */ 1121 nir_deref_instr *deref = 1122 nir_build_deref_array_imm(b, nir_build_deref_var(b, vec), 1); 1123 nir_load_deref(b, deref); 1124 1125 nir_validate_shader(b->shader, NULL); 1126 1127 bool progress = nir_opt_copy_prop_vars(b->shader); 1128 EXPECT_TRUE(progress); 1129 1130 nir_validate_shader(b->shader, NULL); 1131 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1); 1132 1133 nir_intrinsic_instr *load = get_intrinsic(nir_intrinsic_load_deref, 0); 1134 ASSERT_EQ(nir_intrinsic_get_var(load, 0), in0); 1135} 1136 1137TEST_F(nir_copy_prop_vars_test, load_direct_array_deref_on_vector_gets_reused) 1138{ 1139 nir_variable *in0 = create_ivec2(nir_var_mem_global, "in0"); 1140 nir_variable *vec = create_ivec2(nir_var_mem_global, "vec"); 1141 nir_variable *out = create_ivec2(nir_var_mem_global, "out"); 1142 1143 /* Loading "vec[1]" deref will save the information about vec.y. */ 1144 nir_deref_instr *deref = 1145 nir_build_deref_array_imm(b, nir_build_deref_var(b, vec), 1); 1146 nir_load_deref(b, deref); 1147 1148 /* Store to vec.x. */ 1149 nir_store_var(b, vec, nir_load_var(b, in0), 1 << 0); 1150 1151 /* This load will be dropped, since both vec.x and vec.y are known. */ 1152 nir_ssa_def *loaded_from_vec = nir_load_var(b, vec); 1153 nir_store_var(b, out, loaded_from_vec, 0x3); 1154 1155 nir_validate_shader(b->shader, NULL); 1156 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 3); 1157 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 2); 1158 1159 bool progress = nir_opt_copy_prop_vars(b->shader); 1160 EXPECT_TRUE(progress); 1161 1162 nir_validate_shader(b->shader, NULL); 1163 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 2); 1164 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 2); 1165 1166 nir_intrinsic_instr *store = get_intrinsic(nir_intrinsic_store_deref, 1); 1167 ASSERT_TRUE(store->src[1].is_ssa); 1168 ASSERT_TRUE(nir_src_as_alu_instr(store->src[1])); 1169} 1170 1171TEST_F(nir_copy_prop_vars_test, store_load_direct_array_deref_on_vector) 1172{ 1173 nir_variable *vec = create_ivec2(nir_var_mem_global, "vec"); 1174 nir_variable *out0 = create_int(nir_var_mem_global, "out0"); 1175 nir_variable *out1 = create_ivec2(nir_var_mem_global, "out1"); 1176 1177 /* Store to "vec[1]" and "vec[0]". */ 1178 nir_deref_instr *store_deref_y = 1179 nir_build_deref_array_imm(b, nir_build_deref_var(b, vec), 1); 1180 nir_store_deref(b, store_deref_y, nir_imm_int(b, 20), 1); 1181 1182 nir_deref_instr *store_deref_x = 1183 nir_build_deref_array_imm(b, nir_build_deref_var(b, vec), 0); 1184 nir_store_deref(b, store_deref_x, nir_imm_int(b, 10), 1); 1185 1186 /* Both loads below will be dropped, because the values are already known. */ 1187 nir_deref_instr *load_deref_y = 1188 nir_build_deref_array_imm(b, nir_build_deref_var(b, vec), 1); 1189 nir_store_var(b, out0, nir_load_deref(b, load_deref_y), 1); 1190 1191 nir_store_var(b, out1, nir_load_var(b, vec), 1); 1192 1193 nir_validate_shader(b->shader, NULL); 1194 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 2); 1195 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 4); 1196 1197 bool progress = nir_opt_copy_prop_vars(b->shader); 1198 EXPECT_TRUE(progress); 1199 1200 nir_validate_shader(b->shader, NULL); 1201 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 0); 1202 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 4); 1203 1204 /* Third store will just use the value from first store. */ 1205 nir_intrinsic_instr *first_store = get_intrinsic(nir_intrinsic_store_deref, 0); 1206 nir_intrinsic_instr *third_store = get_intrinsic(nir_intrinsic_store_deref, 2); 1207 ASSERT_TRUE(third_store->src[1].is_ssa); 1208 EXPECT_EQ(third_store->src[1].ssa, first_store->src[1].ssa); 1209 1210 /* Fourth store will compose first and second store values. */ 1211 nir_intrinsic_instr *fourth_store = get_intrinsic(nir_intrinsic_store_deref, 3); 1212 ASSERT_TRUE(fourth_store->src[1].is_ssa); 1213 EXPECT_TRUE(nir_src_as_alu_instr(fourth_store->src[1])); 1214} 1215 1216TEST_F(nir_copy_prop_vars_test, store_load_indirect_array_deref_on_vector) 1217{ 1218 nir_variable *vec = create_ivec2(nir_var_mem_global, "vec"); 1219 nir_variable *idx = create_int(nir_var_mem_global, "idx"); 1220 nir_variable *out = create_int(nir_var_mem_global, "out"); 1221 1222 nir_ssa_def *idx_ssa = nir_load_var(b, idx); 1223 1224 /* Store to vec[idx]. */ 1225 nir_deref_instr *store_deref = 1226 nir_build_deref_array(b, nir_build_deref_var(b, vec), idx_ssa); 1227 nir_store_deref(b, store_deref, nir_imm_int(b, 20), 1); 1228 1229 /* Load from vec[idx] to store in out. This load should be dropped. */ 1230 nir_deref_instr *load_deref = 1231 nir_build_deref_array(b, nir_build_deref_var(b, vec), idx_ssa); 1232 nir_store_var(b, out, nir_load_deref(b, load_deref), 1); 1233 1234 nir_validate_shader(b->shader, NULL); 1235 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 2); 1236 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 2); 1237 1238 bool progress = nir_opt_copy_prop_vars(b->shader); 1239 EXPECT_TRUE(progress); 1240 1241 nir_validate_shader(b->shader, NULL); 1242 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1); 1243 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 2); 1244 1245 /* Store to vec[idx] propagated to out. */ 1246 nir_intrinsic_instr *first = get_intrinsic(nir_intrinsic_store_deref, 0); 1247 nir_intrinsic_instr *second = get_intrinsic(nir_intrinsic_store_deref, 1); 1248 ASSERT_TRUE(first->src[1].is_ssa); 1249 ASSERT_TRUE(second->src[1].is_ssa); 1250 EXPECT_EQ(first->src[1].ssa, second->src[1].ssa); 1251} 1252 1253TEST_F(nir_copy_prop_vars_test, store_load_direct_and_indirect_array_deref_on_vector) 1254{ 1255 nir_variable *vec = create_ivec2(nir_var_mem_global, "vec"); 1256 nir_variable *idx = create_int(nir_var_mem_global, "idx"); 1257 nir_variable **out = create_many_int(nir_var_mem_global, "out", 2); 1258 1259 nir_ssa_def *idx_ssa = nir_load_var(b, idx); 1260 1261 /* Store to vec. */ 1262 nir_store_var(b, vec, nir_imm_ivec2(b, 10, 10), 1 | 2); 1263 1264 /* Load from vec[idx]. This load is currently not dropped. */ 1265 nir_deref_instr *indirect = 1266 nir_build_deref_array(b, nir_build_deref_var(b, vec), idx_ssa); 1267 nir_store_var(b, out[0], nir_load_deref(b, indirect), 1); 1268 1269 /* Load from vec[idx] again. This load should be dropped. */ 1270 nir_store_var(b, out[1], nir_load_deref(b, indirect), 1); 1271 1272 nir_validate_shader(b->shader, NULL); 1273 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 3); 1274 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3); 1275 1276 bool progress = nir_opt_copy_prop_vars(b->shader); 1277 EXPECT_TRUE(progress); 1278 1279 nir_validate_shader(b->shader, NULL); 1280 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 2); 1281 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3); 1282 1283 /* Store to vec[idx] propagated to out. */ 1284 nir_intrinsic_instr *second = get_intrinsic(nir_intrinsic_store_deref, 1); 1285 nir_intrinsic_instr *third = get_intrinsic(nir_intrinsic_store_deref, 2); 1286 ASSERT_TRUE(second->src[1].is_ssa); 1287 ASSERT_TRUE(third->src[1].is_ssa); 1288 EXPECT_EQ(second->src[1].ssa, third->src[1].ssa); 1289} 1290 1291TEST_F(nir_copy_prop_vars_test, store_load_indirect_array_deref) 1292{ 1293 nir_variable *arr = create_var(nir_var_mem_global, 1294 glsl_array_type(glsl_int_type(), 10, 0), 1295 "arr"); 1296 nir_variable *idx = create_int(nir_var_mem_global, "idx"); 1297 nir_variable *out = create_int(nir_var_mem_global, "out"); 1298 1299 nir_ssa_def *idx_ssa = nir_load_var(b, idx); 1300 1301 /* Store to arr[idx]. */ 1302 nir_deref_instr *store_deref = 1303 nir_build_deref_array(b, nir_build_deref_var(b, arr), idx_ssa); 1304 nir_store_deref(b, store_deref, nir_imm_int(b, 20), 1); 1305 1306 /* Load from arr[idx] to store in out. This load should be dropped. */ 1307 nir_deref_instr *load_deref = 1308 nir_build_deref_array(b, nir_build_deref_var(b, arr), idx_ssa); 1309 nir_store_var(b, out, nir_load_deref(b, load_deref), 1); 1310 1311 nir_validate_shader(b->shader, NULL); 1312 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 2); 1313 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 2); 1314 1315 bool progress = nir_opt_copy_prop_vars(b->shader); 1316 EXPECT_TRUE(progress); 1317 1318 nir_validate_shader(b->shader, NULL); 1319 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1); 1320 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 2); 1321 1322 /* Store to arr[idx] propagated to out. */ 1323 nir_intrinsic_instr *first = get_intrinsic(nir_intrinsic_store_deref, 0); 1324 nir_intrinsic_instr *second = get_intrinsic(nir_intrinsic_store_deref, 1); 1325 ASSERT_TRUE(first->src[1].is_ssa); 1326 ASSERT_TRUE(second->src[1].is_ssa); 1327 EXPECT_EQ(first->src[1].ssa, second->src[1].ssa); 1328} 1329 1330TEST_F(nir_copy_prop_vars_test, restrict_ssbo_bindings) 1331{ 1332 glsl_struct_field field = glsl_struct_field(); 1333 field.type = glsl_int_type(); 1334 field.name = "x"; 1335 const glsl_type *ifc_type = 1336 glsl_type::get_interface_instance(&field, 1, 1337 GLSL_INTERFACE_PACKING_STD430, 1338 false /* row_major */, "b"); 1339 nir_variable *ssbo0 = create_var(nir_var_mem_ssbo, ifc_type, "ssbo0"); 1340 nir_variable *ssbo1 = create_var(nir_var_mem_ssbo, ifc_type, "ssbo1"); 1341 ssbo0->data.access = ssbo1->data.access = ACCESS_RESTRICT; 1342 nir_variable *out = create_var(nir_var_mem_ssbo, ifc_type, "out"); 1343 out->data.access = ACCESS_RESTRICT; 1344 1345 nir_deref_instr *ssbo0_x = 1346 nir_build_deref_struct(b, nir_build_deref_var(b, ssbo0), 0); 1347 nir_store_deref(b, ssbo0_x, nir_imm_int(b, 20), 1); 1348 1349 nir_deref_instr *ssbo1_x = 1350 nir_build_deref_struct(b, nir_build_deref_var(b, ssbo1), 0); 1351 nir_store_deref(b, ssbo1_x, nir_imm_int(b, 30), 1); 1352 1353 /* Load ssbo0.x and store it in out.x. This load should be dropped */ 1354 nir_deref_instr *out_x = 1355 nir_build_deref_struct(b, nir_build_deref_var(b, out), 0); 1356 nir_store_deref(b, out_x, nir_load_deref(b, ssbo0_x), 1); 1357 1358 nir_validate_shader(b->shader, NULL); 1359 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1); 1360 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3); 1361 1362 bool progress = nir_opt_copy_prop_vars(b->shader); 1363 EXPECT_TRUE(progress); 1364 1365 nir_validate_shader(b->shader, NULL); 1366 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 0); 1367 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3); 1368 1369 /* Store to b0.x propagated to out. */ 1370 nir_intrinsic_instr *first = get_intrinsic(nir_intrinsic_store_deref, 0); 1371 nir_intrinsic_instr *third = get_intrinsic(nir_intrinsic_store_deref, 2); 1372 ASSERT_TRUE(first->src[1].is_ssa); 1373 ASSERT_TRUE(third->src[1].is_ssa); 1374 EXPECT_EQ(first->src[1].ssa, third->src[1].ssa); 1375} 1376 1377TEST_F(nir_copy_prop_vars_test, aliasing_ssbo_bindings) 1378{ 1379 glsl_struct_field field = glsl_struct_field(); 1380 field.type = glsl_int_type(); 1381 field.name = "x"; 1382 const glsl_type *ifc_type = 1383 glsl_type::get_interface_instance(&field, 1, 1384 GLSL_INTERFACE_PACKING_STD430, 1385 false /* row_major */, "b"); 1386 nir_variable *ssbo0 = create_var(nir_var_mem_ssbo, ifc_type, "ssbo0"); 1387 nir_variable *ssbo1 = create_var(nir_var_mem_ssbo, ifc_type, "ssbo1"); 1388 nir_variable *out = create_var(nir_var_mem_ssbo, ifc_type, "out"); 1389 out->data.access = ACCESS_RESTRICT; 1390 1391 nir_deref_instr *ssbo0_x = 1392 nir_build_deref_struct(b, nir_build_deref_var(b, ssbo0), 0); 1393 nir_store_deref(b, ssbo0_x, nir_imm_int(b, 20), 1); 1394 1395 nir_deref_instr *ssbo1_x = 1396 nir_build_deref_struct(b, nir_build_deref_var(b, ssbo1), 0); 1397 nir_store_deref(b, ssbo1_x, nir_imm_int(b, 30), 1); 1398 1399 /* Load ssbo0.x and store it in out.x. This load should not be dropped */ 1400 nir_deref_instr *out_x = 1401 nir_build_deref_struct(b, nir_build_deref_var(b, out), 0); 1402 nir_store_deref(b, out_x, nir_load_deref(b, ssbo0_x), 1); 1403 1404 nir_validate_shader(b->shader, NULL); 1405 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1); 1406 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3); 1407 1408 bool progress = nir_opt_copy_prop_vars(b->shader); 1409 EXPECT_FALSE(progress); 1410 1411 nir_validate_shader(b->shader, NULL); 1412 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1); 1413 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3); 1414} 1415 1416TEST_F(nir_copy_prop_vars_test, ssbo_array_binding_indirect) 1417{ 1418 glsl_struct_field field = glsl_struct_field(); 1419 field.type = glsl_int_type(); 1420 field.name = "x"; 1421 const glsl_type *ifc_type = 1422 glsl_type::get_interface_instance(&field, 1, 1423 GLSL_INTERFACE_PACKING_STD430, 1424 false /* row_major */, "b"); 1425 const glsl_type *arr_ifc_type = glsl_type::get_array_instance(ifc_type, 2); 1426 nir_variable *ssbo_arr = create_var(nir_var_mem_ssbo, arr_ifc_type, 1427 "ssbo_arr"); 1428 ssbo_arr->data.access = ACCESS_RESTRICT; 1429 nir_variable *out = create_var(nir_var_mem_ssbo, ifc_type, "out"); 1430 out->data.access = ACCESS_RESTRICT; 1431 1432 nir_deref_instr *ssbo_0 = 1433 nir_build_deref_array_imm(b, nir_build_deref_var(b, ssbo_arr), 0); 1434 nir_deref_instr *ssbo_0_x = nir_build_deref_struct(b, ssbo_0, 0); 1435 nir_store_deref(b, ssbo_0_x, nir_imm_int(b, 20), 1); 1436 1437 nir_deref_instr *ssbo_i = 1438 nir_build_deref_array(b, nir_build_deref_var(b, ssbo_arr), 1439 nir_load_local_invocation_index(b)); 1440 nir_deref_instr *ssbo_i_x = nir_build_deref_struct(b, ssbo_i, 0); 1441 nir_store_deref(b, ssbo_i_x, nir_imm_int(b, 30), 1); 1442 1443 /* Load ssbo_arr[0].x and store it in out.x. This load should not be dropped */ 1444 nir_deref_instr *out_x = 1445 nir_build_deref_struct(b, nir_build_deref_var(b, out), 0); 1446 nir_store_deref(b, out_x, nir_load_deref(b, ssbo_0_x), 1); 1447 1448 nir_validate_shader(b->shader, NULL); 1449 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1); 1450 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3); 1451 1452 bool progress = nir_opt_copy_prop_vars(b->shader); 1453 EXPECT_FALSE(progress); 1454 1455 nir_validate_shader(b->shader, NULL); 1456 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1); 1457 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3); 1458} 1459 1460TEST_F(nir_copy_prop_vars_test, restrict_ssbo_array_binding) 1461{ 1462 glsl_struct_field field = glsl_struct_field(); 1463 field.type = glsl_int_type(); 1464 field.name = "x"; 1465 const glsl_type *ifc_type = 1466 glsl_type::get_interface_instance(&field, 1, 1467 GLSL_INTERFACE_PACKING_STD430, 1468 false /* row_major */, "b"); 1469 const glsl_type *arr_ifc_type = glsl_type::get_array_instance(ifc_type, 2); 1470 nir_variable *ssbo_arr = create_var(nir_var_mem_ssbo, arr_ifc_type, 1471 "ssbo_arr"); 1472 ssbo_arr->data.access = ACCESS_RESTRICT; 1473 nir_variable *out = create_var(nir_var_mem_ssbo, ifc_type, "out"); 1474 out->data.access = ACCESS_RESTRICT; 1475 1476 nir_deref_instr *ssbo_0 = 1477 nir_build_deref_array_imm(b, nir_build_deref_var(b, ssbo_arr), 0); 1478 nir_deref_instr *ssbo_0_x = nir_build_deref_struct(b, ssbo_0, 0); 1479 nir_store_deref(b, ssbo_0_x, nir_imm_int(b, 20), 1); 1480 1481 nir_deref_instr *ssbo_1 = 1482 nir_build_deref_array_imm(b, nir_build_deref_var(b, ssbo_arr), 1); 1483 nir_deref_instr *ssbo_1_x = nir_build_deref_struct(b, ssbo_1, 0); 1484 nir_store_deref(b, ssbo_1_x, nir_imm_int(b, 30), 1); 1485 1486 /* Load ssbo_arr[0].x and store it in out.x. This load should be dropped */ 1487 nir_deref_instr *out_x = 1488 nir_build_deref_struct(b, nir_build_deref_var(b, out), 0); 1489 nir_store_deref(b, out_x, nir_load_deref(b, ssbo_0_x), 1); 1490 1491 nir_validate_shader(b->shader, NULL); 1492 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1); 1493 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3); 1494 1495 bool progress = nir_opt_copy_prop_vars(b->shader); 1496 EXPECT_TRUE(progress); 1497 1498 nir_validate_shader(b->shader, NULL); 1499 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 0); 1500 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3); 1501 1502 /* Store to b0.x propagated to out. */ 1503 nir_intrinsic_instr *first = get_intrinsic(nir_intrinsic_store_deref, 0); 1504 nir_intrinsic_instr *third = get_intrinsic(nir_intrinsic_store_deref, 2); 1505 ASSERT_TRUE(first->src[1].is_ssa); 1506 ASSERT_TRUE(third->src[1].is_ssa); 1507 EXPECT_EQ(first->src[1].ssa, third->src[1].ssa); 1508} 1509 1510TEST_F(nir_copy_prop_vars_test, aliasing_ssbo_array_binding) 1511{ 1512 glsl_struct_field field = glsl_struct_field(); 1513 field.type = glsl_int_type(); 1514 field.name = "x"; 1515 const glsl_type *ifc_type = 1516 glsl_type::get_interface_instance(&field, 1, 1517 GLSL_INTERFACE_PACKING_STD430, 1518 false /* row_major */, "b"); 1519 const glsl_type *arr_ifc_type = glsl_type::get_array_instance(ifc_type, 2); 1520 nir_variable *ssbo_arr = create_var(nir_var_mem_ssbo, arr_ifc_type, 1521 "ssbo_arr"); 1522 nir_variable *out = create_var(nir_var_mem_ssbo, ifc_type, "out"); 1523 out->data.access = ACCESS_RESTRICT; 1524 1525 nir_deref_instr *ssbo_0 = 1526 nir_build_deref_array_imm(b, nir_build_deref_var(b, ssbo_arr), 0); 1527 nir_deref_instr *ssbo_0_x = nir_build_deref_struct(b, ssbo_0, 0); 1528 nir_store_deref(b, ssbo_0_x, nir_imm_int(b, 20), 1); 1529 1530 nir_deref_instr *ssbo_1 = 1531 nir_build_deref_array_imm(b, nir_build_deref_var(b, ssbo_arr), 1); 1532 nir_deref_instr *ssbo_1_x = nir_build_deref_struct(b, ssbo_1, 0); 1533 nir_store_deref(b, ssbo_1_x, nir_imm_int(b, 30), 1); 1534 1535 /* Load ssbo_arr[0].x and store it in out.x. This load should not be dropped */ 1536 nir_deref_instr *out_x = 1537 nir_build_deref_struct(b, nir_build_deref_var(b, out), 0); 1538 nir_store_deref(b, out_x, nir_load_deref(b, ssbo_0_x), 1); 1539 1540 nir_validate_shader(b->shader, NULL); 1541 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1); 1542 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3); 1543 1544 bool progress = nir_opt_copy_prop_vars(b->shader); 1545 EXPECT_FALSE(progress); 1546 1547 nir_validate_shader(b->shader, NULL); 1548 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1); 1549 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3); 1550} 1551 1552TEST_F(nir_dead_write_vars_test, no_dead_writes_in_block) 1553{ 1554 nir_variable **v = create_many_int(nir_var_mem_global, "v", 2); 1555 1556 nir_store_var(b, v[0], nir_load_var(b, v[1]), 1); 1557 1558 bool progress = nir_opt_dead_write_vars(b->shader); 1559 ASSERT_FALSE(progress); 1560} 1561 1562TEST_F(nir_dead_write_vars_test, no_dead_writes_different_components_in_block) 1563{ 1564 nir_variable **v = create_many_ivec2(nir_var_mem_global, "v", 3); 1565 1566 nir_store_var(b, v[0], nir_load_var(b, v[1]), 1 << 0); 1567 nir_store_var(b, v[0], nir_load_var(b, v[2]), 1 << 1); 1568 1569 bool progress = nir_opt_dead_write_vars(b->shader); 1570 ASSERT_FALSE(progress); 1571} 1572 1573TEST_F(nir_dead_write_vars_test, volatile_write) 1574{ 1575 nir_variable *v = create_int(nir_var_mem_global, "v"); 1576 1577 nir_store_var(b, v, nir_imm_int(b, 0), 0x1); 1578 nir_store_var_volatile(b, v, nir_imm_int(b, 1), 0x1); 1579 nir_store_var(b, v, nir_imm_int(b, 2), 0x1); 1580 1581 /* Our approach here is a bit scorched-earth. We expect the volatile store 1582 * in the middle to cause both that store and the one before it to be kept. 1583 * Technically, volatile only prevents combining the volatile store with 1584 * another store and one could argue that the store before the volatile and 1585 * the one after it could be combined. However, it seems safer to just 1586 * treat a volatile store like an atomic and prevent any combining across 1587 * it. 1588 */ 1589 bool progress = nir_opt_dead_write_vars(b->shader); 1590 ASSERT_FALSE(progress); 1591} 1592 1593TEST_F(nir_dead_write_vars_test, volatile_copies) 1594{ 1595 nir_variable **v = create_many_int(nir_var_mem_global, "v", 2); 1596 1597 nir_copy_var(b, v[0], v[1]); 1598 nir_copy_deref_with_access(b, nir_build_deref_var(b, v[0]), 1599 nir_build_deref_var(b, v[1]), 1600 ACCESS_VOLATILE, (gl_access_qualifier)0); 1601 nir_copy_var(b, v[0], v[1]); 1602 1603 /* Our approach here is a bit scorched-earth. We expect the volatile store 1604 * in the middle to cause both that store and the one before it to be kept. 1605 * Technically, volatile only prevents combining the volatile store with 1606 * another store and one could argue that the store before the volatile and 1607 * the one after it could be combined. However, it seems safer to just 1608 * treat a volatile store like an atomic and prevent any combining across 1609 * it. 1610 */ 1611 bool progress = nir_opt_dead_write_vars(b->shader); 1612 ASSERT_FALSE(progress); 1613} 1614 1615TEST_F(nir_dead_write_vars_test, no_dead_writes_in_if_statement) 1616{ 1617 nir_variable **v = create_many_int(nir_var_mem_global, "v", 6); 1618 1619 nir_store_var(b, v[2], nir_load_var(b, v[0]), 1); 1620 nir_store_var(b, v[3], nir_load_var(b, v[1]), 1); 1621 1622 /* Each arm of the if statement will overwrite one store. */ 1623 nir_if *if_stmt = nir_push_if(b, nir_imm_int(b, 0)); 1624 nir_store_var(b, v[2], nir_load_var(b, v[4]), 1); 1625 1626 nir_push_else(b, if_stmt); 1627 nir_store_var(b, v[3], nir_load_var(b, v[5]), 1); 1628 1629 nir_pop_if(b, if_stmt); 1630 1631 bool progress = nir_opt_dead_write_vars(b->shader); 1632 ASSERT_FALSE(progress); 1633} 1634 1635TEST_F(nir_dead_write_vars_test, no_dead_writes_in_loop_statement) 1636{ 1637 nir_variable **v = create_many_int(nir_var_mem_global, "v", 3); 1638 1639 nir_store_var(b, v[0], nir_load_var(b, v[1]), 1); 1640 1641 /* Loop will write other value. Since it might not be executed, it doesn't 1642 * kill the first write. 1643 */ 1644 nir_loop *loop = nir_push_loop(b); 1645 1646 nir_if *if_stmt = nir_push_if(b, nir_imm_int(b, 0)); 1647 nir_jump(b, nir_jump_break); 1648 nir_pop_if(b, if_stmt); 1649 1650 nir_store_var(b, v[0], nir_load_var(b, v[2]), 1); 1651 nir_pop_loop(b, loop); 1652 1653 bool progress = nir_opt_dead_write_vars(b->shader); 1654 ASSERT_FALSE(progress); 1655} 1656 1657TEST_F(nir_dead_write_vars_test, dead_write_in_block) 1658{ 1659 nir_variable **v = create_many_int(nir_var_mem_global, "v", 3); 1660 1661 nir_store_var(b, v[0], nir_load_var(b, v[1]), 1); 1662 nir_ssa_def *load_v2 = nir_load_var(b, v[2]); 1663 nir_store_var(b, v[0], load_v2, 1); 1664 1665 bool progress = nir_opt_dead_write_vars(b->shader); 1666 ASSERT_TRUE(progress); 1667 1668 EXPECT_EQ(1, count_intrinsics(nir_intrinsic_store_deref)); 1669 1670 nir_intrinsic_instr *store = get_intrinsic(nir_intrinsic_store_deref, 0); 1671 ASSERT_TRUE(store->src[1].is_ssa); 1672 EXPECT_EQ(store->src[1].ssa, load_v2); 1673} 1674 1675TEST_F(nir_dead_write_vars_test, dead_write_components_in_block) 1676{ 1677 nir_variable **v = create_many_ivec2(nir_var_mem_global, "v", 3); 1678 1679 nir_store_var(b, v[0], nir_load_var(b, v[1]), 1 << 0); 1680 nir_ssa_def *load_v2 = nir_load_var(b, v[2]); 1681 nir_store_var(b, v[0], load_v2, 1 << 0); 1682 1683 bool progress = nir_opt_dead_write_vars(b->shader); 1684 ASSERT_TRUE(progress); 1685 1686 EXPECT_EQ(1, count_intrinsics(nir_intrinsic_store_deref)); 1687 1688 nir_intrinsic_instr *store = get_intrinsic(nir_intrinsic_store_deref, 0); 1689 ASSERT_TRUE(store->src[1].is_ssa); 1690 EXPECT_EQ(store->src[1].ssa, load_v2); 1691} 1692 1693 1694/* TODO: The DISABLED tests below depend on the dead write removal be able to 1695 * identify dead writes between multiple blocks. This is still not 1696 * implemented. 1697 */ 1698 1699TEST_F(nir_dead_write_vars_test, DISABLED_dead_write_in_two_blocks) 1700{ 1701 nir_variable **v = create_many_int(nir_var_mem_global, "v", 3); 1702 1703 nir_store_var(b, v[0], nir_load_var(b, v[1]), 1); 1704 nir_ssa_def *load_v2 = nir_load_var(b, v[2]); 1705 1706 /* Causes the stores to be in different blocks. */ 1707 nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0))); 1708 1709 nir_store_var(b, v[0], load_v2, 1); 1710 1711 bool progress = nir_opt_dead_write_vars(b->shader); 1712 ASSERT_TRUE(progress); 1713 1714 EXPECT_EQ(1, count_intrinsics(nir_intrinsic_store_deref)); 1715 1716 nir_intrinsic_instr *store = get_intrinsic(nir_intrinsic_store_deref, 0); 1717 ASSERT_TRUE(store->src[1].is_ssa); 1718 EXPECT_EQ(store->src[1].ssa, load_v2); 1719} 1720 1721TEST_F(nir_dead_write_vars_test, DISABLED_dead_write_components_in_two_blocks) 1722{ 1723 nir_variable **v = create_many_ivec2(nir_var_mem_global, "v", 3); 1724 1725 nir_store_var(b, v[0], nir_load_var(b, v[1]), 1 << 0); 1726 1727 /* Causes the stores to be in different blocks. */ 1728 nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0))); 1729 1730 nir_ssa_def *load_v2 = nir_load_var(b, v[2]); 1731 nir_store_var(b, v[0], load_v2, 1 << 0); 1732 1733 bool progress = nir_opt_dead_write_vars(b->shader); 1734 ASSERT_TRUE(progress); 1735 1736 EXPECT_EQ(1, count_intrinsics(nir_intrinsic_store_deref)); 1737 1738 nir_intrinsic_instr *store = get_intrinsic(nir_intrinsic_store_deref, 0); 1739 ASSERT_TRUE(store->src[1].is_ssa); 1740 EXPECT_EQ(store->src[1].ssa, load_v2); 1741} 1742 1743TEST_F(nir_dead_write_vars_test, DISABLED_dead_writes_in_if_statement) 1744{ 1745 nir_variable **v = create_many_int(nir_var_mem_global, "v", 4); 1746 1747 /* Both branches will overwrite, making the previous store dead. */ 1748 nir_store_var(b, v[0], nir_load_var(b, v[1]), 1); 1749 1750 nir_if *if_stmt = nir_push_if(b, nir_imm_int(b, 0)); 1751 nir_ssa_def *load_v2 = nir_load_var(b, v[2]); 1752 nir_store_var(b, v[0], load_v2, 1); 1753 1754 nir_push_else(b, if_stmt); 1755 nir_ssa_def *load_v3 = nir_load_var(b, v[3]); 1756 nir_store_var(b, v[0], load_v3, 1); 1757 1758 nir_pop_if(b, if_stmt); 1759 1760 bool progress = nir_opt_dead_write_vars(b->shader); 1761 ASSERT_TRUE(progress); 1762 EXPECT_EQ(2, count_intrinsics(nir_intrinsic_store_deref)); 1763 1764 nir_intrinsic_instr *first_store = get_intrinsic(nir_intrinsic_store_deref, 0); 1765 ASSERT_TRUE(first_store->src[1].is_ssa); 1766 EXPECT_EQ(first_store->src[1].ssa, load_v2); 1767 1768 nir_intrinsic_instr *second_store = get_intrinsic(nir_intrinsic_store_deref, 1); 1769 ASSERT_TRUE(second_store->src[1].is_ssa); 1770 EXPECT_EQ(second_store->src[1].ssa, load_v3); 1771} 1772 1773TEST_F(nir_dead_write_vars_test, DISABLED_memory_barrier_in_two_blocks) 1774{ 1775 nir_variable **v = create_many_int(nir_var_mem_global, "v", 2); 1776 1777 nir_store_var(b, v[0], nir_imm_int(b, 1), 1); 1778 nir_store_var(b, v[1], nir_imm_int(b, 2), 1); 1779 1780 /* Split into many blocks. */ 1781 nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0))); 1782 1783 /* Because it is before the barrier, this will kill the previous store to that target. */ 1784 nir_store_var(b, v[0], nir_imm_int(b, 3), 1); 1785 1786 nir_scoped_memory_barrier(b, NIR_SCOPE_DEVICE, NIR_MEMORY_ACQ_REL, 1787 nir_var_mem_global); 1788 1789 nir_store_var(b, v[1], nir_imm_int(b, 4), 1); 1790 1791 bool progress = nir_opt_dead_write_vars(b->shader); 1792 ASSERT_TRUE(progress); 1793 1794 EXPECT_EQ(3, count_intrinsics(nir_intrinsic_store_deref)); 1795} 1796 1797TEST_F(nir_dead_write_vars_test, DISABLED_unrelated_barrier_in_two_blocks) 1798{ 1799 nir_variable **v = create_many_int(nir_var_mem_global, "v", 3); 1800 nir_variable *out = create_int(nir_var_shader_out, "out"); 1801 1802 nir_store_var(b, out, nir_load_var(b, v[1]), 1); 1803 nir_store_var(b, v[0], nir_load_var(b, v[1]), 1); 1804 1805 /* Split into many blocks. */ 1806 nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0))); 1807 1808 /* Emit vertex will ensure writes to output variables are considered used, 1809 * but should not affect other types of variables. */ 1810 1811 nir_emit_vertex(b); 1812 1813 nir_store_var(b, out, nir_load_var(b, v[2]), 1); 1814 nir_store_var(b, v[0], nir_load_var(b, v[2]), 1); 1815 1816 bool progress = nir_opt_dead_write_vars(b->shader); 1817 ASSERT_TRUE(progress); 1818 1819 /* Verify the first write to v[0] was removed. */ 1820 EXPECT_EQ(3, count_intrinsics(nir_intrinsic_store_deref)); 1821 1822 nir_intrinsic_instr *first_store = get_intrinsic(nir_intrinsic_store_deref, 0); 1823 EXPECT_EQ(nir_intrinsic_get_var(first_store, 0), out); 1824 1825 nir_intrinsic_instr *second_store = get_intrinsic(nir_intrinsic_store_deref, 1); 1826 EXPECT_EQ(nir_intrinsic_get_var(second_store, 0), out); 1827 1828 nir_intrinsic_instr *third_store = get_intrinsic(nir_intrinsic_store_deref, 2); 1829 EXPECT_EQ(nir_intrinsic_get_var(third_store, 0), v[0]); 1830} 1831 1832TEST_F(nir_combine_stores_test, non_overlapping_stores) 1833{ 1834 nir_variable **v = create_many_ivec4(nir_var_mem_global, "v", 4); 1835 nir_variable *out = create_ivec4(nir_var_shader_out, "out"); 1836 1837 for (int i = 0; i < 4; i++) 1838 nir_store_var(b, out, nir_load_var(b, v[i]), 1 << i); 1839 1840 nir_validate_shader(b->shader, NULL); 1841 1842 bool progress = nir_opt_combine_stores(b->shader, nir_var_shader_out); 1843 ASSERT_TRUE(progress); 1844 1845 nir_validate_shader(b->shader, NULL); 1846 1847 /* Clean up to verify from where the values in combined store are coming. */ 1848 nir_copy_prop(b->shader); 1849 nir_opt_dce(b->shader); 1850 1851 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 1); 1852 nir_intrinsic_instr *combined = get_intrinsic(nir_intrinsic_store_deref, 0); 1853 ASSERT_EQ(nir_intrinsic_write_mask(combined), 0xf); 1854 ASSERT_EQ(nir_intrinsic_get_var(combined, 0), out); 1855 1856 nir_alu_instr *vec = nir_src_as_alu_instr(combined->src[1]); 1857 ASSERT_TRUE(vec); 1858 for (int i = 0; i < 4; i++) { 1859 nir_intrinsic_instr *load = nir_src_as_intrinsic(vec->src[i].src); 1860 ASSERT_EQ(load->intrinsic, nir_intrinsic_load_deref); 1861 ASSERT_EQ(nir_intrinsic_get_var(load, 0), v[i]) 1862 << "Source value for component " << i << " of store is wrong"; 1863 ASSERT_EQ(vec->src[i].swizzle[0], i) 1864 << "Source component for component " << i << " of store is wrong"; 1865 } 1866} 1867 1868TEST_F(nir_combine_stores_test, overlapping_stores) 1869{ 1870 nir_variable **v = create_many_ivec4(nir_var_mem_global, "v", 3); 1871 nir_variable *out = create_ivec4(nir_var_shader_out, "out"); 1872 1873 /* Make stores with xy, yz and zw masks. */ 1874 for (int i = 0; i < 3; i++) { 1875 nir_component_mask_t mask = (1 << i) | (1 << (i + 1)); 1876 nir_store_var(b, out, nir_load_var(b, v[i]), mask); 1877 } 1878 1879 nir_validate_shader(b->shader, NULL); 1880 1881 bool progress = nir_opt_combine_stores(b->shader, nir_var_shader_out); 1882 ASSERT_TRUE(progress); 1883 1884 nir_validate_shader(b->shader, NULL); 1885 1886 /* Clean up to verify from where the values in combined store are coming. */ 1887 nir_copy_prop(b->shader); 1888 nir_opt_dce(b->shader); 1889 1890 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 1); 1891 nir_intrinsic_instr *combined = get_intrinsic(nir_intrinsic_store_deref, 0); 1892 ASSERT_EQ(nir_intrinsic_write_mask(combined), 0xf); 1893 ASSERT_EQ(nir_intrinsic_get_var(combined, 0), out); 1894 1895 nir_alu_instr *vec = nir_src_as_alu_instr(combined->src[1]); 1896 ASSERT_TRUE(vec); 1897 1898 /* Component x comes from v[0]. */ 1899 nir_intrinsic_instr *load_for_x = nir_src_as_intrinsic(vec->src[0].src); 1900 ASSERT_EQ(nir_intrinsic_get_var(load_for_x, 0), v[0]); 1901 ASSERT_EQ(vec->src[0].swizzle[0], 0); 1902 1903 /* Component y comes from v[1]. */ 1904 nir_intrinsic_instr *load_for_y = nir_src_as_intrinsic(vec->src[1].src); 1905 ASSERT_EQ(nir_intrinsic_get_var(load_for_y, 0), v[1]); 1906 ASSERT_EQ(vec->src[1].swizzle[0], 1); 1907 1908 /* Components z and w come from v[2]. */ 1909 nir_intrinsic_instr *load_for_z = nir_src_as_intrinsic(vec->src[2].src); 1910 nir_intrinsic_instr *load_for_w = nir_src_as_intrinsic(vec->src[3].src); 1911 ASSERT_EQ(load_for_z, load_for_w); 1912 ASSERT_EQ(nir_intrinsic_get_var(load_for_z, 0), v[2]); 1913 ASSERT_EQ(vec->src[2].swizzle[0], 2); 1914 ASSERT_EQ(vec->src[3].swizzle[0], 3); 1915} 1916 1917TEST_F(nir_combine_stores_test, direct_array_derefs) 1918{ 1919 nir_variable **v = create_many_ivec4(nir_var_mem_global, "vec", 2); 1920 nir_variable **s = create_many_int(nir_var_mem_global, "scalar", 2); 1921 nir_variable *out = create_ivec4(nir_var_mem_global, "out"); 1922 1923 nir_deref_instr *out_deref = nir_build_deref_var(b, out); 1924 1925 /* Store to vector with mask x. */ 1926 nir_store_deref(b, out_deref, nir_load_var(b, v[0]), 1927 1 << 0); 1928 1929 /* Store to vector with mask yz. */ 1930 nir_store_deref(b, out_deref, nir_load_var(b, v[1]), 1931 (1 << 2) | (1 << 1)); 1932 1933 /* Store to vector[2], overlapping with previous store. */ 1934 nir_store_deref(b, 1935 nir_build_deref_array_imm(b, out_deref, 2), 1936 nir_load_var(b, s[0]), 1937 1 << 0); 1938 1939 /* Store to vector[3], no overlap. */ 1940 nir_store_deref(b, 1941 nir_build_deref_array_imm(b, out_deref, 3), 1942 nir_load_var(b, s[1]), 1943 1 << 0); 1944 1945 nir_validate_shader(b->shader, NULL); 1946 1947 bool progress = nir_opt_combine_stores(b->shader, nir_var_mem_global); 1948 ASSERT_TRUE(progress); 1949 1950 nir_validate_shader(b->shader, NULL); 1951 1952 /* Clean up to verify from where the values in combined store are coming. */ 1953 nir_copy_prop(b->shader); 1954 nir_opt_dce(b->shader); 1955 1956 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 1); 1957 nir_intrinsic_instr *combined = get_intrinsic(nir_intrinsic_store_deref, 0); 1958 ASSERT_EQ(nir_intrinsic_write_mask(combined), 0xf); 1959 ASSERT_EQ(nir_intrinsic_get_var(combined, 0), out); 1960 1961 nir_alu_instr *vec = nir_src_as_alu_instr(combined->src[1]); 1962 ASSERT_TRUE(vec); 1963 1964 /* Component x comes from v[0]. */ 1965 nir_intrinsic_instr *load_for_x = nir_src_as_intrinsic(vec->src[0].src); 1966 ASSERT_EQ(nir_intrinsic_get_var(load_for_x, 0), v[0]); 1967 ASSERT_EQ(vec->src[0].swizzle[0], 0); 1968 1969 /* Component y comes from v[1]. */ 1970 nir_intrinsic_instr *load_for_y = nir_src_as_intrinsic(vec->src[1].src); 1971 ASSERT_EQ(nir_intrinsic_get_var(load_for_y, 0), v[1]); 1972 ASSERT_EQ(vec->src[1].swizzle[0], 1); 1973 1974 /* Components z comes from s[0]. */ 1975 nir_intrinsic_instr *load_for_z = nir_src_as_intrinsic(vec->src[2].src); 1976 ASSERT_EQ(nir_intrinsic_get_var(load_for_z, 0), s[0]); 1977 ASSERT_EQ(vec->src[2].swizzle[0], 0); 1978 1979 /* Component w comes from s[1]. */ 1980 nir_intrinsic_instr *load_for_w = nir_src_as_intrinsic(vec->src[3].src); 1981 ASSERT_EQ(nir_intrinsic_get_var(load_for_w, 0), s[1]); 1982 ASSERT_EQ(vec->src[3].swizzle[0], 0); 1983} 1984 1985static int64_t 1986vec_src_comp_as_int(nir_src src, unsigned comp) 1987{ 1988 if (nir_src_is_const(src)) 1989 return nir_src_comp_as_int(src, comp); 1990 1991 assert(src.is_ssa); 1992 nir_ssa_scalar s = { src.ssa, comp }; 1993 assert(nir_op_is_vec(nir_ssa_scalar_alu_op(s))); 1994 return nir_ssa_scalar_as_int(nir_ssa_scalar_chase_alu_src(s, comp)); 1995} 1996 1997TEST_F(nir_combine_stores_test, store_volatile) 1998{ 1999 nir_variable *out = create_ivec4(nir_var_shader_out, "out"); 2000 2001 nir_store_var(b, out, nir_imm_ivec4(b, 0, 0, 0, 0), 1 << 0); 2002 nir_store_var(b, out, nir_imm_ivec4(b, 1, 1, 1, 1), 1 << 1); 2003 nir_store_var_volatile(b, out, nir_imm_ivec4(b, -1, -2, -3, -4), 0xf); 2004 nir_store_var(b, out, nir_imm_ivec4(b, 2, 2, 2, 2), 1 << 2); 2005 nir_store_var(b, out, nir_imm_ivec4(b, 3, 3, 3, 3), 1 << 3); 2006 2007 nir_validate_shader(b->shader, NULL); 2008 2009 bool progress = nir_opt_combine_stores(b->shader, nir_var_shader_out); 2010 ASSERT_TRUE(progress); 2011 2012 nir_validate_shader(b->shader, NULL); 2013 2014 /* Clean up the stored values */ 2015 nir_opt_constant_folding(b->shader); 2016 nir_opt_dce(b->shader); 2017 2018 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3); 2019 2020 nir_intrinsic_instr *first = get_intrinsic(nir_intrinsic_store_deref, 0); 2021 ASSERT_EQ(nir_intrinsic_write_mask(first), 0x3); 2022 ASSERT_EQ(vec_src_comp_as_int(first->src[1], 0), 0); 2023 ASSERT_EQ(vec_src_comp_as_int(first->src[1], 1), 1); 2024 2025 nir_intrinsic_instr *second = get_intrinsic(nir_intrinsic_store_deref, 1); 2026 ASSERT_EQ(nir_intrinsic_write_mask(second), 0xf); 2027 ASSERT_EQ(vec_src_comp_as_int(second->src[1], 0), -1); 2028 ASSERT_EQ(vec_src_comp_as_int(second->src[1], 1), -2); 2029 ASSERT_EQ(vec_src_comp_as_int(second->src[1], 2), -3); 2030 ASSERT_EQ(vec_src_comp_as_int(second->src[1], 3), -4); 2031 2032 nir_intrinsic_instr *third = get_intrinsic(nir_intrinsic_store_deref, 2); 2033 ASSERT_EQ(nir_intrinsic_write_mask(third), 0xc); 2034 ASSERT_EQ(vec_src_comp_as_int(third->src[1], 2), 2); 2035 ASSERT_EQ(vec_src_comp_as_int(third->src[1], 3), 3); 2036} 2037 2038TEST_F(nir_split_vars_test, simple_split) 2039{ 2040 nir_variable **in = create_many_int(nir_var_shader_in, "in", 4); 2041 nir_variable *temp = create_var(nir_var_function_temp, glsl_array_type(glsl_int_type(), 4, 0), 2042 "temp"); 2043 nir_deref_instr *temp_deref = nir_build_deref_var(b, temp); 2044 for (int i = 0; i < 4; i++) 2045 nir_store_deref(b, nir_build_deref_array_imm(b, temp_deref, i), nir_load_var(b, in[i]), 1); 2046 2047 nir_validate_shader(b->shader, NULL); 2048 ASSERT_EQ(count_derefs(nir_deref_type_array), 4); 2049 ASSERT_EQ(count_function_temp_vars(), 1); 2050 2051 bool progress = nir_split_array_vars(b->shader, nir_var_function_temp); 2052 EXPECT_TRUE(progress); 2053 2054 nir_validate_shader(b->shader, NULL); 2055 ASSERT_EQ(count_derefs(nir_deref_type_array), 0); 2056 ASSERT_EQ(count_function_temp_vars(), 4); 2057} 2058 2059TEST_F(nir_split_vars_test, simple_no_split_array_struct) 2060{ 2061 nir_variable **in = create_many_int(nir_var_shader_in, "in", 4); 2062 struct glsl_struct_field field; 2063 2064 field.type = glsl_float_type(); 2065 field.name = ralloc_asprintf(b->shader, "field1"); 2066 field.location = -1; 2067 field.offset = 0; 2068 2069 const struct glsl_type *st_type = glsl_struct_type(&field, 1, "struct", false); 2070 nir_variable *temp = create_var(nir_var_function_temp, glsl_array_type(st_type, 4, 0), 2071 "temp"); 2072 2073 nir_variable *temp2 = create_var(nir_var_function_temp, glsl_array_type(glsl_int_type(), 4, 0), "temp2"); 2074 2075 nir_deref_instr *temp_deref = nir_build_deref_var(b, temp); 2076 nir_deref_instr *temp2_deref = nir_build_deref_var(b, temp2); 2077 for (int i = 0; i < 4; i++) 2078 nir_store_deref(b, nir_build_deref_array_imm(b, temp2_deref, i), nir_load_var(b, in[i]), 1); 2079 2080 for (int i = 0; i < 4; i++) 2081 nir_store_deref(b, nir_build_deref_struct(b, nir_build_deref_array_imm(b, temp_deref, i), 0), nir_load_var(b, in[i]), 1); 2082 2083 nir_validate_shader(b->shader, NULL); 2084 ASSERT_EQ(count_derefs(nir_deref_type_array), 8); 2085 ASSERT_EQ(count_derefs(nir_deref_type_struct), 4); 2086 ASSERT_EQ(count_function_temp_vars(), 2); 2087 2088 bool progress = nir_split_array_vars(b->shader, nir_var_function_temp); 2089 EXPECT_TRUE(progress); 2090 2091 nir_validate_shader(b->shader, NULL); 2092 2093 ASSERT_EQ(count_derefs(nir_deref_type_array), 4); 2094 ASSERT_EQ(count_derefs(nir_deref_type_struct), 4); 2095 for (int i = 0; i < 4; i++) { 2096 nir_deref_instr *deref = get_deref(nir_deref_type_array, i); 2097 ASSERT_TRUE(deref); 2098 ASSERT_TRUE(glsl_type_is_struct(deref->type)); 2099 } 2100 2101 ASSERT_EQ(count_function_temp_vars(), 5); 2102} 2103 2104TEST_F(nir_split_vars_test, simple_split_shader_temp) 2105{ 2106 nir_variable **in = create_many_int(nir_var_shader_in, "in", 4); 2107 nir_variable *temp = create_var(nir_var_shader_temp, glsl_array_type(glsl_int_type(), 4, 0), 2108 "temp"); 2109 nir_deref_instr *temp_deref = nir_build_deref_var(b, temp); 2110 2111 for (int i = 0; i < 4; i++) 2112 nir_store_deref(b, nir_build_deref_array_imm(b, temp_deref, i), nir_load_var(b, in[i]), 1); 2113 2114 nir_validate_shader(b->shader, NULL); 2115 ASSERT_EQ(count_derefs(nir_deref_type_array), 4); 2116 ASSERT_EQ(count_shader_temp_vars(), 1); 2117 2118 bool progress = nir_split_array_vars(b->shader, nir_var_shader_temp); 2119 EXPECT_TRUE(progress); 2120 2121 nir_validate_shader(b->shader, NULL); 2122 ASSERT_EQ(count_derefs(nir_deref_type_array), 0); 2123 ASSERT_EQ(count_shader_temp_vars(), 4); 2124} 2125 2126TEST_F(nir_split_vars_test, simple_oob) 2127{ 2128 nir_variable **in = create_many_int(nir_var_shader_in, "in", 6); 2129 nir_variable *temp = create_var(nir_var_function_temp, glsl_array_type(glsl_int_type(), 4, 0), 2130 "temp"); 2131 nir_deref_instr *temp_deref = nir_build_deref_var(b, temp); 2132 2133 for (int i = 0; i < 6; i++) 2134 nir_store_deref(b, nir_build_deref_array_imm(b, temp_deref, i), nir_load_var(b, in[i]), 1); 2135 2136 nir_validate_shader(b->shader, NULL); 2137 ASSERT_EQ(count_derefs(nir_deref_type_array), 6); 2138 ASSERT_EQ(count_function_temp_vars(), 1); 2139 2140 bool progress = nir_split_array_vars(b->shader, nir_var_function_temp); 2141 EXPECT_TRUE(progress); 2142 2143 nir_validate_shader(b->shader, NULL); 2144 ASSERT_EQ(count_derefs(nir_deref_type_array), 0); 2145 ASSERT_EQ(count_function_temp_vars(), 4); 2146} 2147 2148TEST_F(nir_split_vars_test, simple_unused) 2149{ 2150 nir_variable **in = create_many_int(nir_var_shader_in, "in", 2); 2151 nir_variable *temp = create_var(nir_var_function_temp, glsl_array_type(glsl_int_type(), 4, 0), 2152 "temp"); 2153 nir_deref_instr *temp_deref = nir_build_deref_var(b, temp); 2154 2155 for (int i = 0; i < 2; i++) 2156 nir_store_deref(b, nir_build_deref_array_imm(b, temp_deref, i), nir_load_var(b, in[i]), 1); 2157 2158 nir_validate_shader(b->shader, NULL); 2159 ASSERT_EQ(count_derefs(nir_deref_type_array), 2); 2160 ASSERT_EQ(count_function_temp_vars(), 1); 2161 2162 bool progress = nir_split_array_vars(b->shader, nir_var_function_temp); 2163 EXPECT_TRUE(progress); 2164 2165 nir_validate_shader(b->shader, NULL); 2166 ASSERT_EQ(count_derefs(nir_deref_type_array), 0); 2167 /* this pass doesn't remove the unused ones */ 2168 ASSERT_EQ(count_function_temp_vars(), 4); 2169} 2170 2171TEST_F(nir_split_vars_test, two_level_split) 2172{ 2173 nir_variable **in = create_many_int(nir_var_shader_in, "in", 4); 2174 nir_variable *temp = create_var(nir_var_function_temp, glsl_array_type(glsl_array_type(glsl_int_type(), 4, 0), 4, 0), 2175 "temp"); 2176 nir_deref_instr *temp_deref = nir_build_deref_var(b, temp); 2177 for (int i = 0; i < 4; i++) { 2178 nir_deref_instr *level0 = nir_build_deref_array_imm(b, temp_deref, i); 2179 for (int j = 0; j < 4; j++) { 2180 nir_deref_instr *level1 = nir_build_deref_array_imm(b, level0, j); 2181 nir_store_deref(b, level1, nir_load_var(b, in[i]), 1); 2182 } 2183 } 2184 2185 nir_validate_shader(b->shader, NULL); 2186 ASSERT_EQ(count_derefs(nir_deref_type_array), 20); 2187 ASSERT_EQ(count_function_temp_vars(), 1); 2188 2189 bool progress = nir_split_array_vars(b->shader, nir_var_function_temp); 2190 EXPECT_TRUE(progress); 2191 2192 nir_validate_shader(b->shader, NULL); 2193 ASSERT_EQ(count_derefs(nir_deref_type_array), 0); 2194 ASSERT_EQ(count_function_temp_vars(), 16); 2195} 2196 2197TEST_F(nir_split_vars_test, simple_dont_split) 2198{ 2199 nir_variable **in = create_many_int(nir_var_shader_in, "in", 4); 2200 nir_variable *temp = create_var(nir_var_function_temp, glsl_array_type(glsl_int_type(), 4, 0), 2201 "temp"); 2202 nir_variable *ind = create_int(nir_var_shader_in, "ind"); 2203 2204 nir_deref_instr *ind_deref = nir_build_deref_var(b, ind); 2205 nir_deref_instr *temp_deref = nir_build_deref_var(b, temp); 2206 2207 for (int i = 0; i < 4; i++) 2208 nir_store_deref(b, nir_build_deref_array(b, temp_deref, &ind_deref->dest.ssa), nir_load_var(b, in[i]), 1); 2209 2210 nir_validate_shader(b->shader, NULL); 2211 ASSERT_EQ(count_derefs(nir_deref_type_array), 4); 2212 ASSERT_EQ(count_function_temp_vars(), 1); 2213 2214 bool progress = nir_split_array_vars(b->shader, nir_var_function_temp); 2215 EXPECT_FALSE(progress); 2216 2217 nir_validate_shader(b->shader, NULL); 2218 ASSERT_EQ(count_derefs(nir_deref_type_array), 4); 2219 ASSERT_EQ(count_function_temp_vars(), 1); 2220} 2221 2222TEST_F(nir_split_vars_test, twolevel_dont_split_lvl_0) 2223{ 2224 nir_variable **in = create_many_int(nir_var_shader_in, "in", 4); 2225 nir_variable *temp = create_var(nir_var_function_temp, glsl_array_type(glsl_array_type(glsl_int_type(), 6, 0), 4, 0), 2226 "temp"); 2227 nir_variable *ind = create_int(nir_var_shader_in, "ind"); 2228 2229 nir_deref_instr *ind_deref = nir_build_deref_var(b, ind); 2230 nir_deref_instr *temp_deref = nir_build_deref_var(b, temp); 2231 2232 for (int i = 0; i < 4; i++) { 2233 nir_deref_instr *level0 = nir_build_deref_array(b, temp_deref, &ind_deref->dest.ssa); 2234 for (int j = 0; j < 6; j++) { 2235 nir_deref_instr *level1 = nir_build_deref_array_imm(b, level0, j); 2236 nir_store_deref(b, level1, nir_load_var(b, in[i]), 1); 2237 } 2238 } 2239 2240 nir_validate_shader(b->shader, NULL); 2241 ASSERT_EQ(count_derefs(nir_deref_type_array), 28); 2242 ASSERT_EQ(count_function_temp_vars(), 1); 2243 2244 bool progress = nir_split_array_vars(b->shader, nir_var_function_temp); 2245 EXPECT_TRUE(progress); 2246 2247 nir_validate_shader(b->shader, NULL); 2248 ASSERT_EQ(count_derefs(nir_deref_type_array), 24); 2249 ASSERT_EQ(count_function_temp_vars(), 6); 2250} 2251 2252TEST_F(nir_split_vars_test, twolevel_dont_split_lvl_1) 2253{ 2254 nir_variable **in = create_many_int(nir_var_shader_in, "in", 6); 2255 nir_variable *temp = create_var(nir_var_function_temp, glsl_array_type(glsl_array_type(glsl_int_type(), 6, 0), 4, 0), 2256 "temp"); 2257 nir_variable *ind = create_int(nir_var_shader_in, "ind"); 2258 2259 nir_deref_instr *ind_deref = nir_build_deref_var(b, ind); 2260 nir_deref_instr *temp_deref = nir_build_deref_var(b, temp); 2261 2262 for (int i = 0; i < 4; i++) { 2263 nir_deref_instr *level0 = nir_build_deref_array_imm(b, temp_deref, i); 2264 for (int j = 0; j < 6; j++) { 2265 /* just add the inner index to get some different derefs */ 2266 nir_deref_instr *level1 = nir_build_deref_array(b, level0, nir_iadd(b, &ind_deref->dest.ssa, nir_imm_int(b, j))); 2267 nir_store_deref(b, level1, nir_load_var(b, in[i]), 1); 2268 } 2269 } 2270 2271 nir_validate_shader(b->shader, NULL); 2272 ASSERT_EQ(count_derefs(nir_deref_type_array), 28); 2273 ASSERT_EQ(count_function_temp_vars(), 1); 2274 2275 bool progress = nir_split_array_vars(b->shader, nir_var_function_temp); 2276 EXPECT_TRUE(progress); 2277 2278 nir_validate_shader(b->shader, NULL); 2279 ASSERT_EQ(count_derefs(nir_deref_type_array), 24); 2280 ASSERT_EQ(count_function_temp_vars(), 4); 2281} 2282 2283TEST_F(nir_split_vars_test, split_multiple_store) 2284{ 2285 nir_variable **in = create_many_int(nir_var_shader_in, "in", 4); 2286 nir_variable *temp = create_var(nir_var_function_temp, glsl_array_type(glsl_int_type(), 4, 0), 2287 "temp"); 2288 nir_variable *temp2 = create_var(nir_var_function_temp, glsl_array_type(glsl_int_type(), 4, 0), 2289 "temp2"); 2290 2291 nir_deref_instr *temp_deref = nir_build_deref_var(b, temp); 2292 nir_deref_instr *temp2_deref = nir_build_deref_var(b, temp2); 2293 2294 for (int i = 0; i < 4; i++) 2295 nir_store_deref(b, nir_build_deref_array_imm(b, temp_deref, i), nir_load_var(b, in[i]), 1); 2296 2297 for (int i = 0; i < 4; i++) 2298 nir_store_deref(b, nir_build_deref_array_imm(b, temp2_deref, i), nir_load_var(b, in[i]), 1); 2299 2300 nir_validate_shader(b->shader, NULL); 2301 ASSERT_EQ(count_derefs(nir_deref_type_array), 8); 2302 ASSERT_EQ(count_function_temp_vars(), 2); 2303 2304 bool progress = nir_split_array_vars(b->shader, nir_var_function_temp); 2305 EXPECT_TRUE(progress); 2306 2307 nir_validate_shader(b->shader, NULL); 2308 ASSERT_EQ(count_derefs(nir_deref_type_array), 0); 2309 ASSERT_EQ(count_function_temp_vars(), 8); 2310} 2311 2312TEST_F(nir_split_vars_test, split_load_store) 2313{ 2314 nir_variable **in = create_many_int(nir_var_shader_in, "in", 4); 2315 nir_variable *temp = create_var(nir_var_function_temp, glsl_array_type(glsl_int_type(), 4, 0), 2316 "temp"); 2317 nir_variable *temp2 = create_var(nir_var_function_temp, glsl_array_type(glsl_int_type(), 4, 0), 2318 "temp2"); 2319 2320 nir_deref_instr *temp_deref = nir_build_deref_var(b, temp); 2321 nir_deref_instr *temp2_deref = nir_build_deref_var(b, temp2); 2322 2323 for (int i = 0; i < 4; i++) 2324 nir_store_deref(b, nir_build_deref_array_imm(b, temp_deref, i), nir_load_var(b, in[i]), 1); 2325 2326 for (int i = 0; i < 4; i++) { 2327 nir_deref_instr *store_deref = nir_build_deref_array_imm(b, temp2_deref, i); 2328 nir_deref_instr *load_deref = nir_build_deref_array_imm(b, temp_deref, i); 2329 nir_store_deref(b, store_deref, nir_load_deref(b, load_deref), 1); 2330 } 2331 2332 nir_validate_shader(b->shader, NULL); 2333 ASSERT_EQ(count_derefs(nir_deref_type_array), 12); 2334 ASSERT_EQ(count_function_temp_vars(), 2); 2335 2336 bool progress = nir_split_array_vars(b->shader, nir_var_function_temp); 2337 EXPECT_TRUE(progress); 2338 2339 nir_validate_shader(b->shader, NULL); 2340 ASSERT_EQ(count_derefs(nir_deref_type_array), 0); 2341 ASSERT_EQ(count_function_temp_vars(), 8); 2342} 2343 2344TEST_F(nir_split_vars_test, split_copy) 2345{ 2346 nir_variable **in = create_many_int(nir_var_shader_in, "in", 4); 2347 nir_variable *temp = create_var(nir_var_function_temp, glsl_array_type(glsl_int_type(), 4, 0), 2348 "temp"); 2349 nir_variable *temp2 = create_var(nir_var_function_temp, glsl_array_type(glsl_int_type(), 4, 0), 2350 "temp2"); 2351 2352 nir_deref_instr *temp_deref = nir_build_deref_var(b, temp); 2353 nir_deref_instr *temp2_deref = nir_build_deref_var(b, temp2); 2354 2355 for (int i = 0; i < 4; i++) 2356 nir_store_deref(b, nir_build_deref_array_imm(b, temp_deref, i), nir_load_var(b, in[i]), 1); 2357 2358 for (int i = 0; i < 4; i++) { 2359 nir_deref_instr *store_deref = nir_build_deref_array_imm(b, temp2_deref, i); 2360 nir_deref_instr *load_deref = nir_build_deref_array_imm(b, temp_deref, i); 2361 nir_copy_deref(b, store_deref, load_deref); 2362 } 2363 2364 nir_validate_shader(b->shader, NULL); 2365 ASSERT_EQ(count_derefs(nir_deref_type_array), 12); 2366 ASSERT_EQ(count_function_temp_vars(), 2); 2367 2368 bool progress = nir_split_array_vars(b->shader, nir_var_function_temp); 2369 EXPECT_TRUE(progress); 2370 2371 nir_validate_shader(b->shader, NULL); 2372 ASSERT_EQ(count_derefs(nir_deref_type_array), 0); 2373 ASSERT_EQ(count_function_temp_vars(), 8); 2374} 2375 2376TEST_F(nir_split_vars_test, split_wildcard_copy) 2377{ 2378 nir_variable **in = create_many_int(nir_var_shader_in, "in", 4); 2379 nir_variable *temp = create_var(nir_var_function_temp, glsl_array_type(glsl_int_type(), 4, 0), 2380 "temp"); 2381 nir_variable *temp2 = create_var(nir_var_function_temp, glsl_array_type(glsl_int_type(), 4, 0), 2382 "temp2"); 2383 2384 nir_deref_instr *temp_deref = nir_build_deref_var(b, temp); 2385 nir_deref_instr *temp2_deref = nir_build_deref_var(b, temp2); 2386 2387 for (int i = 0; i < 4; i++) 2388 nir_store_deref(b, nir_build_deref_array_imm(b, temp_deref, i), nir_load_var(b, in[i]), 1); 2389 2390 nir_deref_instr *src_wildcard = nir_build_deref_array_wildcard(b, temp_deref); 2391 nir_deref_instr *dst_wildcard = nir_build_deref_array_wildcard(b, temp2_deref); 2392 2393 nir_copy_deref(b, dst_wildcard, src_wildcard); 2394 2395 nir_validate_shader(b->shader, NULL); 2396 ASSERT_EQ(count_derefs(nir_deref_type_array), 4); 2397 ASSERT_EQ(count_derefs(nir_deref_type_array_wildcard), 2); 2398 ASSERT_EQ(count_function_temp_vars(), 2); 2399 ASSERT_EQ(count_intrinsics(nir_intrinsic_copy_deref), 1); 2400 2401 bool progress = nir_split_array_vars(b->shader, nir_var_function_temp); 2402 EXPECT_TRUE(progress); 2403 2404 nir_validate_shader(b->shader, NULL); 2405 ASSERT_EQ(count_derefs(nir_deref_type_array), 0); 2406 ASSERT_EQ(count_derefs(nir_deref_type_array_wildcard), 0); 2407 ASSERT_EQ(count_function_temp_vars(), 8); 2408 ASSERT_EQ(count_intrinsics(nir_intrinsic_copy_deref), 4); 2409} 2410 2411TEST_F(nir_remove_dead_variables_test, pointer_initializer_used) 2412{ 2413 nir_variable *x = create_int(nir_var_shader_temp, "x"); 2414 nir_variable *y = create_int(nir_var_shader_temp, "y"); 2415 y->pointer_initializer = x; 2416 nir_variable *out = create_int(nir_var_shader_out, "out"); 2417 2418 nir_validate_shader(b->shader, NULL); 2419 2420 nir_copy_var(b, out, y); 2421 2422 bool progress = nir_remove_dead_variables(b->shader, nir_var_all, NULL); 2423 EXPECT_FALSE(progress); 2424 2425 nir_validate_shader(b->shader, NULL); 2426 2427 unsigned count = 0; 2428 nir_foreach_variable_in_shader(var, b->shader) 2429 count++; 2430 2431 ASSERT_EQ(count, 3); 2432} 2433 2434TEST_F(nir_remove_dead_variables_test, pointer_initializer_dead) 2435{ 2436 nir_variable *x = create_int(nir_var_shader_temp, "x"); 2437 nir_variable *y = create_int(nir_var_shader_temp, "y"); 2438 nir_variable *z = create_int(nir_var_shader_temp, "z"); 2439 y->pointer_initializer = x; 2440 z->pointer_initializer = y; 2441 2442 nir_validate_shader(b->shader, NULL); 2443 2444 bool progress = nir_remove_dead_variables(b->shader, nir_var_all, NULL); 2445 EXPECT_TRUE(progress); 2446 2447 nir_validate_shader(b->shader, NULL); 2448 2449 unsigned count = 0; 2450 nir_foreach_variable_in_shader(var, b->shader) 2451 count++; 2452 2453 ASSERT_EQ(count, 0); 2454} 2455 2456 2457