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_intrinsics(nir_intrinsic_op intrinsic); 78 79 nir_intrinsic_instr *get_intrinsic(nir_intrinsic_op intrinsic, 80 unsigned index); 81 82 void *mem_ctx; 83 void *lin_ctx; 84 85 nir_builder *b; 86}; 87 88nir_vars_test::nir_vars_test() 89{ 90 mem_ctx = ralloc_context(NULL); 91 lin_ctx = linear_alloc_parent(mem_ctx, 0); 92 static const nir_shader_compiler_options options = { }; 93 b = rzalloc(mem_ctx, nir_builder); 94 nir_builder_init_simple_shader(b, mem_ctx, MESA_SHADER_FRAGMENT, &options); 95} 96 97nir_vars_test::~nir_vars_test() 98{ 99 if (HasFailure()) { 100 printf("\nShader from the failed test:\n\n"); 101 nir_print_shader(b->shader, stdout); 102 } 103 104 ralloc_free(mem_ctx); 105} 106 107unsigned 108nir_vars_test::count_intrinsics(nir_intrinsic_op intrinsic) 109{ 110 unsigned count = 0; 111 nir_foreach_block(block, b->impl) { 112 nir_foreach_instr(instr, block) { 113 if (instr->type != nir_instr_type_intrinsic) 114 continue; 115 nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); 116 if (intrin->intrinsic == intrinsic) 117 count++; 118 } 119 } 120 return count; 121} 122 123nir_intrinsic_instr * 124nir_vars_test::get_intrinsic(nir_intrinsic_op intrinsic, 125 unsigned index) 126{ 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 if (index == 0) 134 return intrin; 135 index--; 136 } 137 } 138 } 139 return NULL; 140} 141 142/* Allow grouping the tests while still sharing the helpers. */ 143class nir_redundant_load_vars_test : public nir_vars_test {}; 144class nir_copy_prop_vars_test : public nir_vars_test {}; 145class nir_dead_write_vars_test : public nir_vars_test {}; 146class nir_combine_stores_test : public nir_vars_test {}; 147 148} // namespace 149 150TEST_F(nir_redundant_load_vars_test, duplicated_load) 151{ 152 /* Load a variable twice in the same block. One should be removed. */ 153 154 nir_variable *in = create_int(nir_var_shader_in, "in"); 155 nir_variable **out = create_many_int(nir_var_shader_out, "out", 2); 156 157 nir_store_var(b, out[0], nir_load_var(b, in), 1); 158 nir_store_var(b, out[1], nir_load_var(b, in), 1); 159 160 nir_validate_shader(b->shader, NULL); 161 162 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 2); 163 164 bool progress = nir_opt_copy_prop_vars(b->shader); 165 EXPECT_TRUE(progress); 166 167 nir_validate_shader(b->shader, NULL); 168 169 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1); 170} 171 172TEST_F(nir_redundant_load_vars_test, duplicated_load_in_two_blocks) 173{ 174 /* Load a variable twice in different blocks. One should be removed. */ 175 176 nir_variable *in = create_int(nir_var_shader_in, "in"); 177 nir_variable **out = create_many_int(nir_var_shader_out, "out", 2); 178 179 nir_store_var(b, out[0], nir_load_var(b, in), 1); 180 181 /* Forces the stores to be in different blocks. */ 182 nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0))); 183 184 nir_store_var(b, out[1], nir_load_var(b, in), 1); 185 186 nir_validate_shader(b->shader, NULL); 187 188 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 2); 189 190 bool progress = nir_opt_copy_prop_vars(b->shader); 191 EXPECT_TRUE(progress); 192 193 nir_validate_shader(b->shader, NULL); 194 195 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1); 196} 197 198TEST_F(nir_redundant_load_vars_test, invalidate_inside_if_block) 199{ 200 /* Load variables, then write to some of then in different branches of the 201 * if statement. They should be invalidated accordingly. 202 */ 203 204 nir_variable **g = create_many_int(nir_var_shader_temp, "g", 3); 205 nir_variable **out = create_many_int(nir_var_shader_out, "out", 3); 206 207 nir_load_var(b, g[0]); 208 nir_load_var(b, g[1]); 209 nir_load_var(b, g[2]); 210 211 nir_if *if_stmt = nir_push_if(b, nir_imm_int(b, 0)); 212 nir_store_var(b, g[0], nir_imm_int(b, 10), 1); 213 214 nir_push_else(b, if_stmt); 215 nir_store_var(b, g[1], nir_imm_int(b, 20), 1); 216 217 nir_pop_if(b, if_stmt); 218 219 nir_store_var(b, out[0], nir_load_var(b, g[0]), 1); 220 nir_store_var(b, out[1], nir_load_var(b, g[1]), 1); 221 nir_store_var(b, out[2], nir_load_var(b, g[2]), 1); 222 223 nir_validate_shader(b->shader, NULL); 224 225 bool progress = nir_opt_copy_prop_vars(b->shader); 226 EXPECT_TRUE(progress); 227 228 /* There are 3 initial loads, plus 2 loads for the values invalidated 229 * inside the if statement. 230 */ 231 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 5); 232 233 /* We only load g[2] once. */ 234 unsigned g2_load_count = 0; 235 for (int i = 0; i < 5; i++) { 236 nir_intrinsic_instr *load = get_intrinsic(nir_intrinsic_load_deref, i); 237 if (nir_intrinsic_get_var(load, 0) == g[2]) 238 g2_load_count++; 239 } 240 EXPECT_EQ(g2_load_count, 1); 241} 242 243TEST_F(nir_redundant_load_vars_test, invalidate_live_load_in_the_end_of_loop) 244{ 245 /* Invalidating a load in the end of loop body will apply to the whole loop 246 * body. 247 */ 248 249 nir_variable *v = create_int(nir_var_mem_ssbo, "v"); 250 251 nir_load_var(b, v); 252 253 nir_loop *loop = nir_push_loop(b); 254 255 nir_if *if_stmt = nir_push_if(b, nir_imm_int(b, 0)); 256 nir_jump(b, nir_jump_break); 257 nir_pop_if(b, if_stmt); 258 259 nir_load_var(b, v); 260 nir_store_var(b, v, nir_imm_int(b, 10), 1); 261 262 nir_pop_loop(b, loop); 263 264 bool progress = nir_opt_copy_prop_vars(b->shader); 265 ASSERT_FALSE(progress); 266} 267 268TEST_F(nir_copy_prop_vars_test, simple_copies) 269{ 270 nir_variable *in = create_int(nir_var_shader_in, "in"); 271 nir_variable *temp = create_int(nir_var_function_temp, "temp"); 272 nir_variable *out = create_int(nir_var_shader_out, "out"); 273 274 nir_copy_var(b, temp, in); 275 nir_copy_var(b, out, temp); 276 277 nir_validate_shader(b->shader, NULL); 278 279 bool progress = nir_opt_copy_prop_vars(b->shader); 280 EXPECT_TRUE(progress); 281 282 nir_validate_shader(b->shader, NULL); 283 284 ASSERT_EQ(count_intrinsics(nir_intrinsic_copy_deref), 2); 285 286 nir_intrinsic_instr *first_copy = get_intrinsic(nir_intrinsic_copy_deref, 0); 287 ASSERT_TRUE(first_copy->src[1].is_ssa); 288 289 nir_intrinsic_instr *second_copy = get_intrinsic(nir_intrinsic_copy_deref, 1); 290 ASSERT_TRUE(second_copy->src[1].is_ssa); 291 292 EXPECT_EQ(first_copy->src[1].ssa, second_copy->src[1].ssa); 293} 294 295TEST_F(nir_copy_prop_vars_test, simple_store_load) 296{ 297 nir_variable **v = create_many_ivec2(nir_var_function_temp, "v", 2); 298 unsigned mask = 1 | 2; 299 300 nir_ssa_def *stored_value = nir_imm_ivec2(b, 10, 20); 301 nir_store_var(b, v[0], stored_value, mask); 302 303 nir_ssa_def *read_value = nir_load_var(b, v[0]); 304 nir_store_var(b, v[1], read_value, mask); 305 306 nir_validate_shader(b->shader, NULL); 307 308 bool progress = nir_opt_copy_prop_vars(b->shader); 309 EXPECT_TRUE(progress); 310 311 nir_validate_shader(b->shader, NULL); 312 313 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 2); 314 315 for (int i = 0; i < 2; i++) { 316 nir_intrinsic_instr *store = get_intrinsic(nir_intrinsic_store_deref, i); 317 ASSERT_TRUE(store->src[1].is_ssa); 318 EXPECT_EQ(store->src[1].ssa, stored_value); 319 } 320} 321 322TEST_F(nir_copy_prop_vars_test, store_store_load) 323{ 324 nir_variable **v = create_many_ivec2(nir_var_function_temp, "v", 2); 325 unsigned mask = 1 | 2; 326 327 nir_ssa_def *first_value = nir_imm_ivec2(b, 10, 20); 328 nir_store_var(b, v[0], first_value, mask); 329 330 nir_ssa_def *second_value = nir_imm_ivec2(b, 30, 40); 331 nir_store_var(b, v[0], second_value, mask); 332 333 nir_ssa_def *read_value = nir_load_var(b, v[0]); 334 nir_store_var(b, v[1], read_value, mask); 335 336 nir_validate_shader(b->shader, NULL); 337 338 bool progress = nir_opt_copy_prop_vars(b->shader); 339 EXPECT_TRUE(progress); 340 341 nir_validate_shader(b->shader, NULL); 342 343 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3); 344 345 /* Store to v[1] should use second_value directly. */ 346 nir_intrinsic_instr *store_to_v1 = get_intrinsic(nir_intrinsic_store_deref, 2); 347 ASSERT_EQ(nir_intrinsic_get_var(store_to_v1, 0), v[1]); 348 ASSERT_TRUE(store_to_v1->src[1].is_ssa); 349 EXPECT_EQ(store_to_v1->src[1].ssa, second_value); 350} 351 352TEST_F(nir_copy_prop_vars_test, store_store_load_different_components) 353{ 354 nir_variable **v = create_many_ivec2(nir_var_function_temp, "v", 2); 355 356 nir_ssa_def *first_value = nir_imm_ivec2(b, 10, 20); 357 nir_store_var(b, v[0], first_value, 1 << 1); 358 359 nir_ssa_def *second_value = nir_imm_ivec2(b, 30, 40); 360 nir_store_var(b, v[0], second_value, 1 << 0); 361 362 nir_ssa_def *read_value = nir_load_var(b, v[0]); 363 nir_store_var(b, v[1], read_value, 1 << 1); 364 365 nir_validate_shader(b->shader, NULL); 366 367 bool progress = nir_opt_copy_prop_vars(b->shader); 368 EXPECT_TRUE(progress); 369 370 nir_validate_shader(b->shader, NULL); 371 372 nir_opt_constant_folding(b->shader); 373 nir_validate_shader(b->shader, NULL); 374 375 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3); 376 377 /* Store to v[1] should use first_value directly. The write of 378 * second_value did not overwrite the component it uses. 379 */ 380 nir_intrinsic_instr *store_to_v1 = get_intrinsic(nir_intrinsic_store_deref, 2); 381 ASSERT_EQ(nir_intrinsic_get_var(store_to_v1, 0), v[1]); 382 ASSERT_EQ(nir_src_comp_as_uint(store_to_v1->src[1], 1), 20); 383} 384 385TEST_F(nir_copy_prop_vars_test, store_store_load_different_components_in_many_blocks) 386{ 387 nir_variable **v = create_many_ivec2(nir_var_function_temp, "v", 2); 388 389 nir_ssa_def *first_value = nir_imm_ivec2(b, 10, 20); 390 nir_store_var(b, v[0], first_value, 1 << 1); 391 392 /* Adding an if statement will cause blocks to be created. */ 393 nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0))); 394 395 nir_ssa_def *second_value = nir_imm_ivec2(b, 30, 40); 396 nir_store_var(b, v[0], second_value, 1 << 0); 397 398 /* Adding an if statement will cause blocks to be created. */ 399 nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0))); 400 401 nir_ssa_def *read_value = nir_load_var(b, v[0]); 402 nir_store_var(b, v[1], read_value, 1 << 1); 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 nir_opt_constant_folding(b->shader); 412 nir_validate_shader(b->shader, NULL); 413 414 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3); 415 416 /* Store to v[1] should use first_value directly. The write of 417 * second_value did not overwrite the component it uses. 418 */ 419 nir_intrinsic_instr *store_to_v1 = get_intrinsic(nir_intrinsic_store_deref, 2); 420 ASSERT_EQ(nir_intrinsic_get_var(store_to_v1, 0), v[1]); 421 ASSERT_EQ(nir_src_comp_as_uint(store_to_v1->src[1], 1), 20); 422} 423 424TEST_F(nir_copy_prop_vars_test, memory_barrier_in_two_blocks) 425{ 426 nir_variable **v = create_many_int(nir_var_mem_ssbo, "v", 4); 427 428 nir_store_var(b, v[0], nir_imm_int(b, 1), 1); 429 nir_store_var(b, v[1], nir_imm_int(b, 2), 1); 430 431 /* Split into many blocks. */ 432 nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0))); 433 434 nir_store_var(b, v[2], nir_load_var(b, v[0]), 1); 435 436 nir_builder_instr_insert(b, &nir_intrinsic_instr_create(b->shader, nir_intrinsic_memory_barrier)->instr); 437 438 nir_store_var(b, v[3], nir_load_var(b, v[1]), 1); 439 440 bool progress = nir_opt_copy_prop_vars(b->shader); 441 ASSERT_TRUE(progress); 442 443 /* Only the second load will remain after the optimization. */ 444 ASSERT_EQ(1, count_intrinsics(nir_intrinsic_load_deref)); 445 nir_intrinsic_instr *load = get_intrinsic(nir_intrinsic_load_deref, 0); 446 ASSERT_EQ(nir_intrinsic_get_var(load, 0), v[1]); 447} 448 449TEST_F(nir_copy_prop_vars_test, simple_store_load_in_two_blocks) 450{ 451 nir_variable **v = create_many_ivec2(nir_var_function_temp, "v", 2); 452 unsigned mask = 1 | 2; 453 454 nir_ssa_def *stored_value = nir_imm_ivec2(b, 10, 20); 455 nir_store_var(b, v[0], stored_value, mask); 456 457 /* Adding an if statement will cause blocks to be created. */ 458 nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0))); 459 460 nir_ssa_def *read_value = nir_load_var(b, v[0]); 461 nir_store_var(b, v[1], read_value, mask); 462 463 nir_validate_shader(b->shader, NULL); 464 465 bool progress = nir_opt_copy_prop_vars(b->shader); 466 EXPECT_TRUE(progress); 467 468 nir_validate_shader(b->shader, NULL); 469 470 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 2); 471 472 for (int i = 0; i < 2; i++) { 473 nir_intrinsic_instr *store = get_intrinsic(nir_intrinsic_store_deref, i); 474 ASSERT_TRUE(store->src[1].is_ssa); 475 EXPECT_EQ(store->src[1].ssa, stored_value); 476 } 477} 478 479TEST_F(nir_copy_prop_vars_test, load_direct_array_deref_on_vector_reuses_previous_load) 480{ 481 nir_variable *in0 = create_ivec2(nir_var_mem_ssbo, "in0"); 482 nir_variable *in1 = create_ivec2(nir_var_mem_ssbo, "in1"); 483 nir_variable *vec = create_ivec2(nir_var_mem_ssbo, "vec"); 484 nir_variable *out = create_int(nir_var_mem_ssbo, "out"); 485 486 nir_store_var(b, vec, nir_load_var(b, in0), 1 << 0); 487 nir_store_var(b, vec, nir_load_var(b, in1), 1 << 1); 488 489 /* This load will be dropped, as vec.y (or vec[1]) is already known. */ 490 nir_deref_instr *deref = 491 nir_build_deref_array_imm(b, nir_build_deref_var(b, vec), 1); 492 nir_ssa_def *loaded_from_deref = nir_load_deref(b, deref); 493 494 /* This store should use the value loaded from in1. */ 495 nir_store_var(b, out, loaded_from_deref, 1 << 0); 496 497 nir_validate_shader(b->shader, NULL); 498 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 3); 499 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3); 500 501 bool progress = nir_opt_copy_prop_vars(b->shader); 502 EXPECT_TRUE(progress); 503 504 nir_validate_shader(b->shader, NULL); 505 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 2); 506 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3); 507 508 nir_intrinsic_instr *store = get_intrinsic(nir_intrinsic_store_deref, 2); 509 ASSERT_TRUE(store->src[1].is_ssa); 510 511 /* NOTE: The ALU instruction is how we get the vec.y. */ 512 ASSERT_TRUE(nir_src_as_alu_instr(store->src[1])); 513} 514 515TEST_F(nir_copy_prop_vars_test, load_direct_array_deref_on_vector_reuses_previous_copy) 516{ 517 nir_variable *in0 = create_ivec2(nir_var_mem_ssbo, "in0"); 518 nir_variable *vec = create_ivec2(nir_var_mem_ssbo, "vec"); 519 520 nir_copy_var(b, vec, in0); 521 522 /* This load will be replaced with one from in0. */ 523 nir_deref_instr *deref = 524 nir_build_deref_array_imm(b, nir_build_deref_var(b, vec), 1); 525 nir_load_deref(b, deref); 526 527 nir_validate_shader(b->shader, NULL); 528 529 bool progress = nir_opt_copy_prop_vars(b->shader); 530 EXPECT_TRUE(progress); 531 532 nir_validate_shader(b->shader, NULL); 533 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1); 534 535 nir_intrinsic_instr *load = get_intrinsic(nir_intrinsic_load_deref, 0); 536 ASSERT_EQ(nir_intrinsic_get_var(load, 0), in0); 537} 538 539TEST_F(nir_copy_prop_vars_test, load_direct_array_deref_on_vector_gets_reused) 540{ 541 nir_variable *in0 = create_ivec2(nir_var_mem_ssbo, "in0"); 542 nir_variable *vec = create_ivec2(nir_var_mem_ssbo, "vec"); 543 nir_variable *out = create_ivec2(nir_var_mem_ssbo, "out"); 544 545 /* Loading "vec[1]" deref will save the information about vec.y. */ 546 nir_deref_instr *deref = 547 nir_build_deref_array_imm(b, nir_build_deref_var(b, vec), 1); 548 nir_load_deref(b, deref); 549 550 /* Store to vec.x. */ 551 nir_store_var(b, vec, nir_load_var(b, in0), 1 << 0); 552 553 /* This load will be dropped, since both vec.x and vec.y are known. */ 554 nir_ssa_def *loaded_from_vec = nir_load_var(b, vec); 555 nir_store_var(b, out, loaded_from_vec, 0x3); 556 557 nir_validate_shader(b->shader, NULL); 558 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 3); 559 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 2); 560 561 bool progress = nir_opt_copy_prop_vars(b->shader); 562 EXPECT_TRUE(progress); 563 564 nir_validate_shader(b->shader, NULL); 565 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 2); 566 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 2); 567 568 nir_intrinsic_instr *store = get_intrinsic(nir_intrinsic_store_deref, 1); 569 ASSERT_TRUE(store->src[1].is_ssa); 570 ASSERT_TRUE(nir_src_as_alu_instr(store->src[1])); 571} 572 573TEST_F(nir_copy_prop_vars_test, store_load_direct_array_deref_on_vector) 574{ 575 nir_variable *vec = create_ivec2(nir_var_mem_ssbo, "vec"); 576 nir_variable *out0 = create_int(nir_var_mem_ssbo, "out0"); 577 nir_variable *out1 = create_ivec2(nir_var_mem_ssbo, "out1"); 578 579 /* Store to "vec[1]" and "vec[0]". */ 580 nir_deref_instr *store_deref_y = 581 nir_build_deref_array_imm(b, nir_build_deref_var(b, vec), 1); 582 nir_store_deref(b, store_deref_y, nir_imm_int(b, 20), 1); 583 584 nir_deref_instr *store_deref_x = 585 nir_build_deref_array_imm(b, nir_build_deref_var(b, vec), 0); 586 nir_store_deref(b, store_deref_x, nir_imm_int(b, 10), 1); 587 588 /* Both loads below will be dropped, because the values are already known. */ 589 nir_deref_instr *load_deref_y = 590 nir_build_deref_array_imm(b, nir_build_deref_var(b, vec), 1); 591 nir_store_var(b, out0, nir_load_deref(b, load_deref_y), 1); 592 593 nir_store_var(b, out1, nir_load_var(b, vec), 1); 594 595 nir_validate_shader(b->shader, NULL); 596 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 2); 597 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 4); 598 599 bool progress = nir_opt_copy_prop_vars(b->shader); 600 EXPECT_TRUE(progress); 601 602 nir_validate_shader(b->shader, NULL); 603 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 0); 604 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 4); 605 606 /* Third store will just use the value from first store. */ 607 nir_intrinsic_instr *first_store = get_intrinsic(nir_intrinsic_store_deref, 0); 608 nir_intrinsic_instr *third_store = get_intrinsic(nir_intrinsic_store_deref, 2); 609 ASSERT_TRUE(third_store->src[1].is_ssa); 610 EXPECT_EQ(third_store->src[1].ssa, first_store->src[1].ssa); 611 612 /* Fourth store will compose first and second store values. */ 613 nir_intrinsic_instr *fourth_store = get_intrinsic(nir_intrinsic_store_deref, 3); 614 ASSERT_TRUE(fourth_store->src[1].is_ssa); 615 EXPECT_TRUE(nir_src_as_alu_instr(fourth_store->src[1])); 616} 617 618TEST_F(nir_copy_prop_vars_test, store_load_indirect_array_deref_on_vector) 619{ 620 nir_variable *vec = create_ivec2(nir_var_mem_ssbo, "vec"); 621 nir_variable *idx = create_int(nir_var_mem_ssbo, "idx"); 622 nir_variable *out = create_int(nir_var_mem_ssbo, "out"); 623 624 nir_ssa_def *idx_ssa = nir_load_var(b, idx); 625 626 /* Store to vec[idx]. */ 627 nir_deref_instr *store_deref = 628 nir_build_deref_array(b, nir_build_deref_var(b, vec), idx_ssa); 629 nir_store_deref(b, store_deref, nir_imm_int(b, 20), 1); 630 631 /* Load from vec[idx] to store in out. This load should be dropped. */ 632 nir_deref_instr *load_deref = 633 nir_build_deref_array(b, nir_build_deref_var(b, vec), idx_ssa); 634 nir_store_var(b, out, nir_load_deref(b, load_deref), 1); 635 636 nir_validate_shader(b->shader, NULL); 637 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 2); 638 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 2); 639 640 bool progress = nir_opt_copy_prop_vars(b->shader); 641 EXPECT_TRUE(progress); 642 643 nir_validate_shader(b->shader, NULL); 644 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1); 645 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 2); 646 647 /* Store to vec[idx] propagated to out. */ 648 nir_intrinsic_instr *first = get_intrinsic(nir_intrinsic_store_deref, 0); 649 nir_intrinsic_instr *second = get_intrinsic(nir_intrinsic_store_deref, 1); 650 ASSERT_TRUE(first->src[1].is_ssa); 651 ASSERT_TRUE(second->src[1].is_ssa); 652 EXPECT_EQ(first->src[1].ssa, second->src[1].ssa); 653} 654 655TEST_F(nir_copy_prop_vars_test, store_load_direct_and_indirect_array_deref_on_vector) 656{ 657 nir_variable *vec = create_ivec2(nir_var_mem_ssbo, "vec"); 658 nir_variable *idx = create_int(nir_var_mem_ssbo, "idx"); 659 nir_variable **out = create_many_int(nir_var_mem_ssbo, "out", 2); 660 661 nir_ssa_def *idx_ssa = nir_load_var(b, idx); 662 663 /* Store to vec. */ 664 nir_store_var(b, vec, nir_imm_ivec2(b, 10, 10), 1 | 2); 665 666 /* Load from vec[idx]. This load is currently not dropped. */ 667 nir_deref_instr *indirect = 668 nir_build_deref_array(b, nir_build_deref_var(b, vec), idx_ssa); 669 nir_store_var(b, out[0], nir_load_deref(b, indirect), 1); 670 671 /* Load from vec[idx] again. This load should be dropped. */ 672 nir_store_var(b, out[1], nir_load_deref(b, indirect), 1); 673 674 nir_validate_shader(b->shader, NULL); 675 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 3); 676 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3); 677 678 bool progress = nir_opt_copy_prop_vars(b->shader); 679 EXPECT_TRUE(progress); 680 681 nir_validate_shader(b->shader, NULL); 682 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 2); 683 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 3); 684 685 /* Store to vec[idx] propagated to out. */ 686 nir_intrinsic_instr *second = get_intrinsic(nir_intrinsic_store_deref, 1); 687 nir_intrinsic_instr *third = get_intrinsic(nir_intrinsic_store_deref, 2); 688 ASSERT_TRUE(second->src[1].is_ssa); 689 ASSERT_TRUE(third->src[1].is_ssa); 690 EXPECT_EQ(second->src[1].ssa, third->src[1].ssa); 691} 692 693TEST_F(nir_copy_prop_vars_test, store_load_indirect_array_deref) 694{ 695 nir_variable *arr = create_var(nir_var_mem_ssbo, 696 glsl_array_type(glsl_int_type(), 10, 0), 697 "arr"); 698 nir_variable *idx = create_int(nir_var_mem_ssbo, "idx"); 699 nir_variable *out = create_int(nir_var_mem_ssbo, "out"); 700 701 nir_ssa_def *idx_ssa = nir_load_var(b, idx); 702 703 /* Store to arr[idx]. */ 704 nir_deref_instr *store_deref = 705 nir_build_deref_array(b, nir_build_deref_var(b, arr), idx_ssa); 706 nir_store_deref(b, store_deref, nir_imm_int(b, 20), 1); 707 708 /* Load from arr[idx] to store in out. This load should be dropped. */ 709 nir_deref_instr *load_deref = 710 nir_build_deref_array(b, nir_build_deref_var(b, arr), idx_ssa); 711 nir_store_var(b, out, nir_load_deref(b, load_deref), 1); 712 713 nir_validate_shader(b->shader, NULL); 714 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 2); 715 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 2); 716 717 bool progress = nir_opt_copy_prop_vars(b->shader); 718 EXPECT_TRUE(progress); 719 720 nir_validate_shader(b->shader, NULL); 721 ASSERT_EQ(count_intrinsics(nir_intrinsic_load_deref), 1); 722 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 2); 723 724 /* Store to arr[idx] propagated to out. */ 725 nir_intrinsic_instr *first = get_intrinsic(nir_intrinsic_store_deref, 0); 726 nir_intrinsic_instr *second = get_intrinsic(nir_intrinsic_store_deref, 1); 727 ASSERT_TRUE(first->src[1].is_ssa); 728 ASSERT_TRUE(second->src[1].is_ssa); 729 EXPECT_EQ(first->src[1].ssa, second->src[1].ssa); 730} 731 732TEST_F(nir_dead_write_vars_test, no_dead_writes_in_block) 733{ 734 nir_variable **v = create_many_int(nir_var_mem_ssbo, "v", 2); 735 736 nir_store_var(b, v[0], nir_load_var(b, v[1]), 1); 737 738 bool progress = nir_opt_dead_write_vars(b->shader); 739 ASSERT_FALSE(progress); 740} 741 742TEST_F(nir_dead_write_vars_test, no_dead_writes_different_components_in_block) 743{ 744 nir_variable **v = create_many_ivec2(nir_var_mem_ssbo, "v", 3); 745 746 nir_store_var(b, v[0], nir_load_var(b, v[1]), 1 << 0); 747 nir_store_var(b, v[0], nir_load_var(b, v[2]), 1 << 1); 748 749 bool progress = nir_opt_dead_write_vars(b->shader); 750 ASSERT_FALSE(progress); 751} 752 753TEST_F(nir_dead_write_vars_test, no_dead_writes_in_if_statement) 754{ 755 nir_variable **v = create_many_int(nir_var_mem_ssbo, "v", 6); 756 757 nir_store_var(b, v[2], nir_load_var(b, v[0]), 1); 758 nir_store_var(b, v[3], nir_load_var(b, v[1]), 1); 759 760 /* Each arm of the if statement will overwrite one store. */ 761 nir_if *if_stmt = nir_push_if(b, nir_imm_int(b, 0)); 762 nir_store_var(b, v[2], nir_load_var(b, v[4]), 1); 763 764 nir_push_else(b, if_stmt); 765 nir_store_var(b, v[3], nir_load_var(b, v[5]), 1); 766 767 nir_pop_if(b, if_stmt); 768 769 bool progress = nir_opt_dead_write_vars(b->shader); 770 ASSERT_FALSE(progress); 771} 772 773TEST_F(nir_dead_write_vars_test, no_dead_writes_in_loop_statement) 774{ 775 nir_variable **v = create_many_int(nir_var_mem_ssbo, "v", 3); 776 777 nir_store_var(b, v[0], nir_load_var(b, v[1]), 1); 778 779 /* Loop will write other value. Since it might not be executed, it doesn't 780 * kill the first write. 781 */ 782 nir_loop *loop = nir_push_loop(b); 783 784 nir_if *if_stmt = nir_push_if(b, nir_imm_int(b, 0)); 785 nir_jump(b, nir_jump_break); 786 nir_pop_if(b, if_stmt); 787 788 nir_store_var(b, v[0], nir_load_var(b, v[2]), 1); 789 nir_pop_loop(b, loop); 790 791 bool progress = nir_opt_dead_write_vars(b->shader); 792 ASSERT_FALSE(progress); 793} 794 795TEST_F(nir_dead_write_vars_test, dead_write_in_block) 796{ 797 nir_variable **v = create_many_int(nir_var_mem_ssbo, "v", 3); 798 799 nir_store_var(b, v[0], nir_load_var(b, v[1]), 1); 800 nir_ssa_def *load_v2 = nir_load_var(b, v[2]); 801 nir_store_var(b, v[0], load_v2, 1); 802 803 bool progress = nir_opt_dead_write_vars(b->shader); 804 ASSERT_TRUE(progress); 805 806 EXPECT_EQ(1, count_intrinsics(nir_intrinsic_store_deref)); 807 808 nir_intrinsic_instr *store = get_intrinsic(nir_intrinsic_store_deref, 0); 809 ASSERT_TRUE(store->src[1].is_ssa); 810 EXPECT_EQ(store->src[1].ssa, load_v2); 811} 812 813TEST_F(nir_dead_write_vars_test, dead_write_components_in_block) 814{ 815 nir_variable **v = create_many_ivec2(nir_var_mem_ssbo, "v", 3); 816 817 nir_store_var(b, v[0], nir_load_var(b, v[1]), 1 << 0); 818 nir_ssa_def *load_v2 = nir_load_var(b, v[2]); 819 nir_store_var(b, v[0], load_v2, 1 << 0); 820 821 bool progress = nir_opt_dead_write_vars(b->shader); 822 ASSERT_TRUE(progress); 823 824 EXPECT_EQ(1, count_intrinsics(nir_intrinsic_store_deref)); 825 826 nir_intrinsic_instr *store = get_intrinsic(nir_intrinsic_store_deref, 0); 827 ASSERT_TRUE(store->src[1].is_ssa); 828 EXPECT_EQ(store->src[1].ssa, load_v2); 829} 830 831 832/* TODO: The DISABLED tests below depend on the dead write removal be able to 833 * identify dead writes between multiple blocks. This is still not 834 * implemented. 835 */ 836 837TEST_F(nir_dead_write_vars_test, DISABLED_dead_write_in_two_blocks) 838{ 839 nir_variable **v = create_many_int(nir_var_mem_ssbo, "v", 3); 840 841 nir_store_var(b, v[0], nir_load_var(b, v[1]), 1); 842 nir_ssa_def *load_v2 = nir_load_var(b, v[2]); 843 844 /* Causes the stores to be in different blocks. */ 845 nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0))); 846 847 nir_store_var(b, v[0], load_v2, 1); 848 849 bool progress = nir_opt_dead_write_vars(b->shader); 850 ASSERT_TRUE(progress); 851 852 EXPECT_EQ(1, count_intrinsics(nir_intrinsic_store_deref)); 853 854 nir_intrinsic_instr *store = get_intrinsic(nir_intrinsic_store_deref, 0); 855 ASSERT_TRUE(store->src[1].is_ssa); 856 EXPECT_EQ(store->src[1].ssa, load_v2); 857} 858 859TEST_F(nir_dead_write_vars_test, DISABLED_dead_write_components_in_two_blocks) 860{ 861 nir_variable **v = create_many_ivec2(nir_var_mem_ssbo, "v", 3); 862 863 nir_store_var(b, v[0], nir_load_var(b, v[1]), 1 << 0); 864 865 /* Causes the stores to be in different blocks. */ 866 nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0))); 867 868 nir_ssa_def *load_v2 = nir_load_var(b, v[2]); 869 nir_store_var(b, v[0], load_v2, 1 << 0); 870 871 bool progress = nir_opt_dead_write_vars(b->shader); 872 ASSERT_TRUE(progress); 873 874 EXPECT_EQ(1, count_intrinsics(nir_intrinsic_store_deref)); 875 876 nir_intrinsic_instr *store = get_intrinsic(nir_intrinsic_store_deref, 0); 877 ASSERT_TRUE(store->src[1].is_ssa); 878 EXPECT_EQ(store->src[1].ssa, load_v2); 879} 880 881TEST_F(nir_dead_write_vars_test, DISABLED_dead_writes_in_if_statement) 882{ 883 nir_variable **v = create_many_int(nir_var_mem_ssbo, "v", 4); 884 885 /* Both branches will overwrite, making the previous store dead. */ 886 nir_store_var(b, v[0], nir_load_var(b, v[1]), 1); 887 888 nir_if *if_stmt = nir_push_if(b, nir_imm_int(b, 0)); 889 nir_ssa_def *load_v2 = nir_load_var(b, v[2]); 890 nir_store_var(b, v[0], load_v2, 1); 891 892 nir_push_else(b, if_stmt); 893 nir_ssa_def *load_v3 = nir_load_var(b, v[3]); 894 nir_store_var(b, v[0], load_v3, 1); 895 896 nir_pop_if(b, if_stmt); 897 898 bool progress = nir_opt_dead_write_vars(b->shader); 899 ASSERT_TRUE(progress); 900 EXPECT_EQ(2, count_intrinsics(nir_intrinsic_store_deref)); 901 902 nir_intrinsic_instr *first_store = get_intrinsic(nir_intrinsic_store_deref, 0); 903 ASSERT_TRUE(first_store->src[1].is_ssa); 904 EXPECT_EQ(first_store->src[1].ssa, load_v2); 905 906 nir_intrinsic_instr *second_store = get_intrinsic(nir_intrinsic_store_deref, 1); 907 ASSERT_TRUE(second_store->src[1].is_ssa); 908 EXPECT_EQ(second_store->src[1].ssa, load_v3); 909} 910 911TEST_F(nir_dead_write_vars_test, DISABLED_memory_barrier_in_two_blocks) 912{ 913 nir_variable **v = create_many_int(nir_var_mem_ssbo, "v", 2); 914 915 nir_store_var(b, v[0], nir_imm_int(b, 1), 1); 916 nir_store_var(b, v[1], nir_imm_int(b, 2), 1); 917 918 /* Split into many blocks. */ 919 nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0))); 920 921 /* Because it is before the barrier, this will kill the previous store to that target. */ 922 nir_store_var(b, v[0], nir_imm_int(b, 3), 1); 923 924 nir_builder_instr_insert(b, &nir_intrinsic_instr_create(b->shader, nir_intrinsic_memory_barrier)->instr); 925 926 nir_store_var(b, v[1], nir_imm_int(b, 4), 1); 927 928 bool progress = nir_opt_dead_write_vars(b->shader); 929 ASSERT_TRUE(progress); 930 931 EXPECT_EQ(3, count_intrinsics(nir_intrinsic_store_deref)); 932} 933 934TEST_F(nir_dead_write_vars_test, DISABLED_unrelated_barrier_in_two_blocks) 935{ 936 nir_variable **v = create_many_int(nir_var_mem_ssbo, "v", 3); 937 nir_variable *out = create_int(nir_var_shader_out, "out"); 938 939 nir_store_var(b, out, nir_load_var(b, v[1]), 1); 940 nir_store_var(b, v[0], nir_load_var(b, v[1]), 1); 941 942 /* Split into many blocks. */ 943 nir_pop_if(b, nir_push_if(b, nir_imm_int(b, 0))); 944 945 /* Emit vertex will ensure writes to output variables are considered used, 946 * but should not affect other types of variables. */ 947 948 nir_builder_instr_insert(b, &nir_intrinsic_instr_create(b->shader, nir_intrinsic_emit_vertex)->instr); 949 950 nir_store_var(b, out, nir_load_var(b, v[2]), 1); 951 nir_store_var(b, v[0], nir_load_var(b, v[2]), 1); 952 953 bool progress = nir_opt_dead_write_vars(b->shader); 954 ASSERT_TRUE(progress); 955 956 /* Verify the first write to v[0] was removed. */ 957 EXPECT_EQ(3, count_intrinsics(nir_intrinsic_store_deref)); 958 959 nir_intrinsic_instr *first_store = get_intrinsic(nir_intrinsic_store_deref, 0); 960 EXPECT_EQ(nir_intrinsic_get_var(first_store, 0), out); 961 962 nir_intrinsic_instr *second_store = get_intrinsic(nir_intrinsic_store_deref, 1); 963 EXPECT_EQ(nir_intrinsic_get_var(second_store, 0), out); 964 965 nir_intrinsic_instr *third_store = get_intrinsic(nir_intrinsic_store_deref, 2); 966 EXPECT_EQ(nir_intrinsic_get_var(third_store, 0), v[0]); 967} 968 969TEST_F(nir_combine_stores_test, non_overlapping_stores) 970{ 971 nir_variable **v = create_many_ivec4(nir_var_mem_ssbo, "v", 4); 972 nir_variable *out = create_ivec4(nir_var_shader_out, "out"); 973 974 for (int i = 0; i < 4; i++) 975 nir_store_var(b, out, nir_load_var(b, v[i]), 1 << i); 976 977 nir_validate_shader(b->shader, NULL); 978 979 bool progress = nir_opt_combine_stores(b->shader, nir_var_shader_out); 980 ASSERT_TRUE(progress); 981 982 nir_validate_shader(b->shader, NULL); 983 984 /* Clean up to verify from where the values in combined store are coming. */ 985 nir_copy_prop(b->shader); 986 nir_opt_dce(b->shader); 987 988 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 1); 989 nir_intrinsic_instr *combined = get_intrinsic(nir_intrinsic_store_deref, 0); 990 ASSERT_EQ(nir_intrinsic_write_mask(combined), 0xf); 991 ASSERT_EQ(nir_intrinsic_get_var(combined, 0), out); 992 993 nir_alu_instr *vec = nir_src_as_alu_instr(combined->src[1]); 994 ASSERT_TRUE(vec); 995 for (int i = 0; i < 4; i++) { 996 nir_intrinsic_instr *load = nir_src_as_intrinsic(vec->src[i].src); 997 ASSERT_EQ(load->intrinsic, nir_intrinsic_load_deref); 998 ASSERT_EQ(nir_intrinsic_get_var(load, 0), v[i]) 999 << "Source value for component " << i << " of store is wrong"; 1000 ASSERT_EQ(vec->src[i].swizzle[0], i) 1001 << "Source component for component " << i << " of store is wrong"; 1002 } 1003} 1004 1005TEST_F(nir_combine_stores_test, overlapping_stores) 1006{ 1007 nir_variable **v = create_many_ivec4(nir_var_mem_ssbo, "v", 3); 1008 nir_variable *out = create_ivec4(nir_var_shader_out, "out"); 1009 1010 /* Make stores with xy, yz and zw masks. */ 1011 for (int i = 0; i < 3; i++) { 1012 nir_component_mask_t mask = (1 << i) | (1 << (i + 1)); 1013 nir_store_var(b, out, nir_load_var(b, v[i]), mask); 1014 } 1015 1016 nir_validate_shader(b->shader, NULL); 1017 1018 bool progress = nir_opt_combine_stores(b->shader, nir_var_shader_out); 1019 ASSERT_TRUE(progress); 1020 1021 nir_validate_shader(b->shader, NULL); 1022 1023 /* Clean up to verify from where the values in combined store are coming. */ 1024 nir_copy_prop(b->shader); 1025 nir_opt_dce(b->shader); 1026 1027 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 1); 1028 nir_intrinsic_instr *combined = get_intrinsic(nir_intrinsic_store_deref, 0); 1029 ASSERT_EQ(nir_intrinsic_write_mask(combined), 0xf); 1030 ASSERT_EQ(nir_intrinsic_get_var(combined, 0), out); 1031 1032 nir_alu_instr *vec = nir_src_as_alu_instr(combined->src[1]); 1033 ASSERT_TRUE(vec); 1034 1035 /* Component x comes from v[0]. */ 1036 nir_intrinsic_instr *load_for_x = nir_src_as_intrinsic(vec->src[0].src); 1037 ASSERT_EQ(nir_intrinsic_get_var(load_for_x, 0), v[0]); 1038 ASSERT_EQ(vec->src[0].swizzle[0], 0); 1039 1040 /* Component y comes from v[1]. */ 1041 nir_intrinsic_instr *load_for_y = nir_src_as_intrinsic(vec->src[1].src); 1042 ASSERT_EQ(nir_intrinsic_get_var(load_for_y, 0), v[1]); 1043 ASSERT_EQ(vec->src[1].swizzle[0], 1); 1044 1045 /* Components z and w come from v[2]. */ 1046 nir_intrinsic_instr *load_for_z = nir_src_as_intrinsic(vec->src[2].src); 1047 nir_intrinsic_instr *load_for_w = nir_src_as_intrinsic(vec->src[3].src); 1048 ASSERT_EQ(load_for_z, load_for_w); 1049 ASSERT_EQ(nir_intrinsic_get_var(load_for_z, 0), v[2]); 1050 ASSERT_EQ(vec->src[2].swizzle[0], 2); 1051 ASSERT_EQ(vec->src[3].swizzle[0], 3); 1052} 1053 1054TEST_F(nir_combine_stores_test, direct_array_derefs) 1055{ 1056 nir_variable **v = create_many_ivec4(nir_var_mem_ssbo, "vec", 2); 1057 nir_variable **s = create_many_int(nir_var_mem_ssbo, "scalar", 2); 1058 nir_variable *out = create_ivec4(nir_var_mem_ssbo, "out"); 1059 1060 nir_deref_instr *out_deref = nir_build_deref_var(b, out); 1061 1062 /* Store to vector with mask x. */ 1063 nir_store_deref(b, out_deref, nir_load_var(b, v[0]), 1064 1 << 0); 1065 1066 /* Store to vector with mask yz. */ 1067 nir_store_deref(b, out_deref, nir_load_var(b, v[1]), 1068 (1 << 2) | (1 << 1)); 1069 1070 /* Store to vector[2], overlapping with previous store. */ 1071 nir_store_deref(b, 1072 nir_build_deref_array_imm(b, out_deref, 2), 1073 nir_load_var(b, s[0]), 1074 1 << 0); 1075 1076 /* Store to vector[3], no overlap. */ 1077 nir_store_deref(b, 1078 nir_build_deref_array_imm(b, out_deref, 3), 1079 nir_load_var(b, s[1]), 1080 1 << 0); 1081 1082 nir_validate_shader(b->shader, NULL); 1083 1084 bool progress = nir_opt_combine_stores(b->shader, nir_var_mem_ssbo); 1085 ASSERT_TRUE(progress); 1086 1087 nir_validate_shader(b->shader, NULL); 1088 1089 /* Clean up to verify from where the values in combined store are coming. */ 1090 nir_copy_prop(b->shader); 1091 nir_opt_dce(b->shader); 1092 1093 ASSERT_EQ(count_intrinsics(nir_intrinsic_store_deref), 1); 1094 nir_intrinsic_instr *combined = get_intrinsic(nir_intrinsic_store_deref, 0); 1095 ASSERT_EQ(nir_intrinsic_write_mask(combined), 0xf); 1096 ASSERT_EQ(nir_intrinsic_get_var(combined, 0), out); 1097 1098 nir_alu_instr *vec = nir_src_as_alu_instr(combined->src[1]); 1099 ASSERT_TRUE(vec); 1100 1101 /* Component x comes from v[0]. */ 1102 nir_intrinsic_instr *load_for_x = nir_src_as_intrinsic(vec->src[0].src); 1103 ASSERT_EQ(nir_intrinsic_get_var(load_for_x, 0), v[0]); 1104 ASSERT_EQ(vec->src[0].swizzle[0], 0); 1105 1106 /* Component y comes from v[1]. */ 1107 nir_intrinsic_instr *load_for_y = nir_src_as_intrinsic(vec->src[1].src); 1108 ASSERT_EQ(nir_intrinsic_get_var(load_for_y, 0), v[1]); 1109 ASSERT_EQ(vec->src[1].swizzle[0], 1); 1110 1111 /* Components z comes from s[0]. */ 1112 nir_intrinsic_instr *load_for_z = nir_src_as_intrinsic(vec->src[2].src); 1113 ASSERT_EQ(nir_intrinsic_get_var(load_for_z, 0), s[0]); 1114 ASSERT_EQ(vec->src[2].swizzle[0], 0); 1115 1116 /* Component w comes from s[1]. */ 1117 nir_intrinsic_instr *load_for_w = nir_src_as_intrinsic(vec->src[3].src); 1118 ASSERT_EQ(nir_intrinsic_get_var(load_for_w, 0), s[1]); 1119 ASSERT_EQ(vec->src[3].swizzle[0], 0); 1120} 1121