diff --git a/src/compiler/nir/meson.build b/src/compiler/nir/meson.build index 79abe6df9d7..408ff0a1c39 100644 --- a/src/compiler/nir/meson.build +++ b/src/compiler/nir/meson.build @@ -458,6 +458,7 @@ if with_tests 'tests/opt_varyings_tests_dead_input.cpp', 'tests/opt_varyings_tests_dead_output.cpp', 'tests/opt_varyings_tests_dedup.cpp', + 'tests/opt_varyings_tests_dedup_multiple.cpp', 'tests/opt_varyings_tests_prop_const.cpp', 'tests/opt_varyings_tests_prop_ubo.cpp', 'tests/opt_varyings_tests_prop_uniform.cpp', diff --git a/src/compiler/nir/nir_opt_varyings.c b/src/compiler/nir/nir_opt_varyings.c index 4a2fe57c266..b8211f97c63 100644 --- a/src/compiler/nir/nir_opt_varyings.c +++ b/src/compiler/nir/nir_opt_varyings.c @@ -149,18 +149,21 @@ * * 4. Remove duplicated output components * - * * By comparing SSA defs. - * * If there are multiple stores to the same output, all such stores - * should store the same SSA as all stores of another output for - * the output to be considered duplicated. If an output has multiple - * vertices, all vertices should store the same SSA. + * * The value equality between outputs is determined by comparing + * the stored SSA defs. + * * 2 outputs are duplicated if both have stores in the same blocks and + * storing the same SSA defs in those blocks. + * * If an output has multiple vertices, all vertices should store the same + * SSA def for the output to be considered duplicated. This constraint + * allows the vertex index to be non-constant. (only possible in TCS + * and MS) * * Deduplication can only be done between outputs of the same category. * Those are: interpolated, patch, flat, interpolated color, flat color, * and conditionally interpolated color based on the flat * shade state * * Everything is deduplicated except TEXn due to the coord replace state. - * * Eliminated output stores get the "no_varying" flag if they are also - * xfb stores or write sysval outputs. + * * Duplicated output stores that can't be removed because they are also + * xfb stores or write sysval outputs get the "no_varying" flag. * * 5. Link signed zero information * @@ -507,6 +510,9 @@ #include "nir_builder.h" #include "nir_xfb_info.h" +#define XXH_INLINE_ALL +#include "util/xxhash.h" + /* nir_opt_varyings works at scalar 16-bit granularity across all varyings. * * Slots (i % 8 == 0,2,4,6) are 32-bit channels or low bits of 16-bit channels. @@ -616,14 +622,22 @@ vec4_slot(unsigned scalar_slot) struct list_node { struct list_head head; - nir_intrinsic_instr *instr; + nir_intrinsic_instr *instr; /* load or store */ + + /* The number of emit_vertex instructions that precede this store + * in the current block. It's the index of the following emit_vertex, + * effectively identifying which emit_vertex section this store belongs + * to within a block. + */ + unsigned gs_emit_index; }; /* Information about 1 scalar varying slot for both shader stages. */ struct scalar_slot { struct { /* Linked list of all store instructions writing into the scalar slot - * in the producer. + * in the producer. The stores are inserted in the order in which they + * occur in the shader. */ struct list_head stores; @@ -751,7 +765,6 @@ struct linkage_info { * the same value. If the output has multiple vertices, all vertices store * the same value. This is a useful property for: * - constant and uniform propagation to the next shader - * - deduplicating outputs */ BITSET_DECLARE(output_equal_mask, NUM_SCALAR_SLOTS); @@ -775,6 +788,11 @@ struct linkage_info { * cares about the sign of zero. */ BITSET_DECLARE(signed_zero_mask, NUM_SCALAR_SLOTS); + + struct { + nir_block *last_gs_emit_block; + unsigned gs_emit_index; + } gather_outputs_state; }; /****************************************************************** @@ -1513,6 +1531,22 @@ gather_outputs(struct nir_builder *builder, nir_intrinsic_instr *intr, void *cb_ { struct linkage_info *linkage = (struct linkage_info *)cb_data; + /* Track the index of emit_vertex in the same block, so that we can identify + * which GS output stores belong to which emit_vertex section in the same + * block. + */ + if (intr->intrinsic == nir_intrinsic_emit_vertex || + intr->intrinsic == nir_intrinsic_emit_vertex_with_counter) { + if (linkage->gather_outputs_state.last_gs_emit_block == + intr->instr.block) { + linkage->gather_outputs_state.gs_emit_index++; + } else { + linkage->gather_outputs_state.last_gs_emit_block = intr->instr.block; + linkage->gather_outputs_state.gs_emit_index = 0; + } + return false; + } + if (intr->intrinsic != nir_intrinsic_store_output && intr->intrinsic != nir_intrinsic_load_output && intr->intrinsic != nir_intrinsic_store_per_vertex_output && @@ -1573,6 +1607,7 @@ gather_outputs(struct nir_builder *builder, nir_intrinsic_instr *intr, void *cb_ struct list_node *node = linear_alloc_child(linkage->linear_mem_ctx, sizeof(struct list_node)); node->instr = intr; + node->gs_emit_index = linkage->gather_outputs_state.gs_emit_index; out->num_slots = MAX2(out->num_slots, sem.num_slots); list_addtail(&node->head, is_store ? &out->producer.stores : &out->producer.loads); @@ -1974,9 +2009,11 @@ remove_all_stores(struct linkage_info *linkage, unsigned i, /* Remove all stores. */ list_for_each_entry_safe(struct list_node, iter, &slot->producer.stores, head) { + /* nir_remove_varying always makes progress. */ + *progress |= nir_progress_producer; + if (nir_remove_varying(iter->instr, linkage->consumer_stage)) { list_del(&iter->head); - *progress |= nir_progress_producer; } else { if (has_xfb(iter->instr)) { *uses_xfb = true; @@ -2746,22 +2783,93 @@ get_input_qualifier(struct linkage_info *linkage, unsigned i) return qual + pixel_location; } -static uint32_t -nir_ht_scalar_hash(const void *key) -{ - nir_scalar s; - static_assert(offsetof(nir_scalar, def) == 0, "known layout"); - static_assert(offsetof(nir_scalar, comp) == sizeof(s.def), "no padding"); - static_assert(sizeof(s.comp) == sizeof(unsigned), "known layout"); +/* Duplicated outputs are those outputs that have stores in the same blocks and + * store equal values in each such block. + * + * It's implemented by representing each output store as entries. 1 output slot is represented as + * a set of such entries. 2 outputs store identical values if their sets are + * equal. + * + * dedup_entry is the entry. Entries are in "struct set". The sets are keys in + * the hash table storing all outputs. An output slot is a duplicate of + * another if its set of dedup_entries is equal to the set of dedup_entries + * of another slot that's already in the hash table. + */ +typedef struct { + /* The block and the value stored in that block. */ + nir_block *block; + nir_scalar value; - /* Don't include structure padding of nir_scalar. */ - return _mesa_hash_data(key, offsetof(nir_scalar, comp) + sizeof(unsigned)); + /* If a block has multiple emits, this is the index of the next emit. + * There is one dedup_entry per emit. + */ + unsigned gs_emit_index; + + /* Treat back colors as different outputs from front colors because both + * front and back colors happen to be in the same output slot and set. + */ + bool is_back_color; +} dedup_entry; + +#define DEBUG_PRINT_DEDUP 0 + +static void +print_dedup_entry(const char *place, struct set *set, dedup_entry *entry) +{ + printf("%s> set=0x%lx, entry=0x%lx, block=0x%lx, def=0x%lx, comp=%u, emit=%u\n", + place, (uintptr_t)set, (uintptr_t)entry, (uintptr_t)entry->block, + (uintptr_t)entry->value.def, entry->value.comp, + entry->gs_emit_index); +} + +static uint32_t +dedup_entry_hash_accum(const void *_key, uint32_t hash) +{ + return XXH32(_key, sizeof(dedup_entry), hash); +} + +static uint32_t +dedup_entry_set_hash(const void *key) +{ + return dedup_entry_hash_accum(key, 0); } static bool -nir_ht_scalar_equal(const void *a, const void *b) +dedup_entry_set_equal(const void *_a, const void *_b) { - return nir_scalar_equal(*(nir_scalar*)a, *(nir_scalar*)b); + dedup_entry *a = (dedup_entry *)_a; + dedup_entry *b = (dedup_entry *)_b; + + return a->block == b->block && a->value.def == b->value.def && + a->value.comp == b->value.comp; +} + +static uint32_t +dedup_ht_key_hash(const void *_key) +{ + struct set *set = (struct set *)_key; + uint32_t hash = 0; + + set_foreach(set, entry) { + if (DEBUG_PRINT_DEDUP) + print_dedup_entry("ht_key_hash", set, (dedup_entry *)entry->key); + + hash = dedup_entry_hash_accum((dedup_entry *)entry->key, hash); + } + + if (DEBUG_PRINT_DEDUP) + printf("ht_key_hash key=0x%lu hash=%u\n", (uintptr_t)_key, hash); + return hash; +} + +static bool +dedup_ht_key_equal(const void *_a, const void *_b) +{ + struct set *a = (struct set *)_a; + struct set *b = (struct set *)_b; + + return _mesa_set_equal(a, b); } static void @@ -2769,24 +2877,31 @@ deduplicate_outputs(struct linkage_info *linkage, nir_opt_varyings_progress *progress, bool *consumer_progress) { - struct hash_table *tables[NUM_DEDUP_QUALIFIERS] = { NULL }; + struct hash_table tables[NUM_DEDUP_QUALIFIERS] = { 0 }; unsigned i; + void *mem_ctx = ralloc_context(NULL); - /* Find duplicated outputs. If there are multiple stores, they should all - * store the same value as all stores of some other output. That's - * guaranteed by output_equal_mask. - */ - BITSET_FOREACH_SET(i, linkage->output_equal_mask, NUM_SCALAR_SLOTS) { + /* Find duplicated outputs. */ + BITSET_FOREACH_SET(i, linkage->removable_mask, NUM_SCALAR_SLOTS) { if (!can_optimize_varying(linkage, vec4_slot(i)).deduplicate) continue; + /* Skip indirect indexing. */ + if (BITSET_TEST(linkage->indirect_mask, i)) + continue; + struct scalar_slot *slot = &linkage->slot[i]; + assert(!list_is_empty(&slot->producer.stores)); + enum var_qualifier qualifier; gl_varying_slot var_slot = vec4_slot(i); /* Determine which qualifier this slot has. */ - if ((var_slot >= VARYING_SLOT_PATCH0 && - var_slot <= VARYING_SLOT_PATCH31) || + if (list_is_empty(&slot->consumer.loads)) { + /* XFB or TCS outputs not consumed by the next stage */ + qualifier = QUAL_VAR_FLAT; + } else if ((var_slot >= VARYING_SLOT_PATCH0 && + var_slot <= VARYING_SLOT_PATCH31) || var_slot == VARYING_SLOT_TESS_LEVEL_INNER || var_slot == VARYING_SLOT_TESS_LEVEL_OUTER) qualifier = QUAL_PATCH; @@ -2798,21 +2913,69 @@ deduplicate_outputs(struct linkage_info *linkage, if (qualifier == QUAL_SKIP) continue; - struct hash_table **table = &tables[qualifier]; - if (!*table) - *table = _mesa_hash_table_create(NULL, nir_ht_scalar_hash, - nir_ht_scalar_equal); - - nir_scalar value = slot->producer.value; - - struct hash_entry *entry = _mesa_hash_table_search(*table, &value); - if (!entry) { - _mesa_hash_table_insert(*table, &value, (void *)(uintptr_t)i); - continue; + struct hash_table *table = &tables[qualifier]; + if (!table->table) { + _mesa_hash_table_init(table, mem_ctx, dedup_ht_key_hash, + dedup_ht_key_equal); } + /* Create the hash table key. */ + struct set *key = _mesa_set_create(mem_ctx, dedup_entry_set_hash, + dedup_entry_set_equal); + + /* Only looking at SSA def equality is insufficient. + * + * TCS proof: + * + * if (invocation_id == 0) + * patch_output[0] = invocation_id; + * else + * patch_output[1] = invocation_id; // not duplicated + * + * VS proof: + * + * if (vertex_id == 0) + * output[0] = vertex_id; + * else + * output[1] = vertex_id; // can't remove because output[0] is + * // uninitialized for vertex_id > 0 + */ + + /* Add all stores to the set of entries. + */ + list_for_each_entry(struct list_node, iter, &slot->producer.stores, + head) { + unsigned location = nir_intrinsic_io_semantics(iter->instr).location; + dedup_entry *entry = rzalloc(mem_ctx, dedup_entry); + entry->block = iter->instr->instr.block; + entry->value = + nir_scalar_resolved(nir_get_io_data_src(iter->instr)->ssa, 0); + entry->gs_emit_index = iter->gs_emit_index; + entry->is_back_color = location == VARYING_SLOT_BFC0 || + location == VARYING_SLOT_BFC1; + + if (DEBUG_PRINT_DEDUP) + print_dedup_entry("add/block", key, entry); + + _mesa_set_add(key, entry); + } + + /* Search in the table for an identical output. */ + struct hash_entry *entry = _mesa_hash_table_search(table, key); + if (!entry) { + if (DEBUG_PRINT_DEDUP) + printf("ht miss slot=%u\n", i); + _mesa_hash_table_insert(table, key, slot); + if (DEBUG_PRINT_DEDUP) + printf("ht inserted slot=%u\n", i); + continue; + } + if (DEBUG_PRINT_DEDUP) + printf("ht hit slot=%u\n", i); + /* We've found a duplicate. Redirect loads and remove stores. */ - struct scalar_slot *found_slot = &linkage->slot[(uintptr_t)entry->data]; + struct scalar_slot *found_slot = (struct scalar_slot *)entry->data; nir_intrinsic_instr *store = list_first_entry(&found_slot->producer.stores, struct list_node, head) @@ -2863,8 +3026,7 @@ deduplicate_outputs(struct linkage_info *linkage, remove_all_stores_and_clear_slot(linkage, i, progress); } - for (unsigned i = 0; i < ARRAY_SIZE(tables); i++) - _mesa_hash_table_destroy(tables[i], NULL); + ralloc_free(mem_ctx); } /****************************************************************** diff --git a/src/compiler/nir/tests/nir_opt_varyings_test.h b/src/compiler/nir/tests/nir_opt_varyings_test.h index a773b2b7244..32f4c0aa090 100644 --- a/src/compiler/nir/tests/nir_opt_varyings_test.h +++ b/src/compiler/nir/tests/nir_opt_varyings_test.h @@ -664,3 +664,5 @@ movable_across_interp(nir_builder *b, nir_op op, unsigned interp[3], return false; } } + +} diff --git a/src/compiler/nir/tests/opt_varyings_tests_bicm_binary_alu.cpp b/src/compiler/nir/tests/opt_varyings_tests_bicm_binary_alu.cpp index 35b7034b19e..72cb5525ff5 100644 --- a/src/compiler/nir/tests/opt_varyings_tests_bicm_binary_alu.cpp +++ b/src/compiler/nir/tests/opt_varyings_tests_bicm_binary_alu.cpp @@ -8,6 +8,8 @@ #include "nir_opt_varyings_test.h" +namespace { + class nir_opt_varyings_test_bicm_binary_alu : public nir_opt_varyings_test {}; diff --git a/src/compiler/nir/tests/opt_varyings_tests_bicm_sysval.cpp b/src/compiler/nir/tests/opt_varyings_tests_bicm_sysval.cpp index 5cd2a1de3e8..8f3707e5225 100644 --- a/src/compiler/nir/tests/opt_varyings_tests_bicm_sysval.cpp +++ b/src/compiler/nir/tests/opt_varyings_tests_bicm_sysval.cpp @@ -6,6 +6,8 @@ #include "nir_opt_varyings_test.h" +namespace { + static bool shader_contains_sysval(nir_builder *b, nir_intrinsic_op op) { diff --git a/src/compiler/nir/tests/opt_varyings_tests_dead_input.cpp b/src/compiler/nir/tests/opt_varyings_tests_dead_input.cpp index 2cc801b4233..cb0de2f8e5c 100644 --- a/src/compiler/nir/tests/opt_varyings_tests_dead_input.cpp +++ b/src/compiler/nir/tests/opt_varyings_tests_dead_input.cpp @@ -6,6 +6,8 @@ #include "nir_opt_varyings_test.h" +namespace { + class nir_opt_varyings_test_dead_input : public nir_opt_varyings_test {}; @@ -16,7 +18,7 @@ TEST_F(nir_opt_varyings_test_dead_input, producer_stage##_##consumer_stage##_##s nir_def *input = load_input(b2, VARYING_SLOT_##slot, 0, nir_type_float##bitsize, 0, 0); \ store_output(b2, VARYING_SLOT_POS, 0, nir_type_float##bitsize, input, 0); \ \ - ASSERT_TRUE(opt_varyings() == nir_progress_consumer); \ + ASSERT_EQ(opt_varyings(), nir_progress_consumer); \ ASSERT_TRUE(b2->shader->info.inputs_read == 0 && \ b2->shader->info.patch_inputs_read == 0 && \ b2->shader->info.inputs_read_16bit == 0); \ @@ -31,7 +33,7 @@ TEST_F(nir_opt_varyings_test_dead_input, producer_stage##_##consumer_stage##_##s nir_def *input = load_input(b2, VARYING_SLOT_##slot, comp, nir_type_float##bitsize, 0, 0); \ store_output(b2, VARYING_SLOT_POS, 0, nir_type_float##bitsize, input, 0); \ \ - ASSERT_TRUE(opt_varyings() == nir_progress_consumer); \ + ASSERT_EQ(opt_varyings(), nir_progress_consumer); \ ASSERT_TRUE(b2->shader->info.inputs_read == 0 && \ b2->shader->info.patch_inputs_read == 0 && \ b2->shader->info.inputs_read_16bit == 0); \ @@ -46,8 +48,8 @@ TEST_F(nir_opt_varyings_test_dead_input, producer_stage##_##consumer_stage##_##s nir_def *input = load_input(b2, VARYING_SLOT_##slot, 0, nir_type_float##bitsize, 0, 0); \ store_output(b2, VARYING_SLOT_POS, 0, nir_type_float##bitsize, input, 0); \ \ - ASSERT_TRUE(opt_varyings() == 0); \ - ASSERT_TRUE(b2->shader->info.inputs_read == VARYING_BIT_##slot); \ + ASSERT_EQ(opt_varyings(), 0); \ + ASSERT_EQ(b2->shader->info.inputs_read, VARYING_BIT_##slot); \ ASSERT_TRUE(shader_contains_def(b2, input)); \ } @@ -70,9 +72,9 @@ TEST_F(nir_opt_varyings_test_dead_input, \ cindex--; \ } \ \ - ASSERT_TRUE(opt_varyings() == 0); \ - ASSERT_TRUE(b1->shader->info.outputs_written == BITFIELD64_BIT(pindex)); \ - ASSERT_TRUE(b2->shader->info.inputs_read == BITFIELD64_BIT(cindex)); \ + ASSERT_EQ(opt_varyings(), 0); \ + ASSERT_EQ(b1->shader->info.outputs_written, BITFIELD64_BIT(pindex)); \ + ASSERT_EQ(b2->shader->info.inputs_read, BITFIELD64_BIT(cindex)); \ ASSERT_TRUE(shader_contains_def(b2, input)); \ } diff --git a/src/compiler/nir/tests/opt_varyings_tests_dead_output.cpp b/src/compiler/nir/tests/opt_varyings_tests_dead_output.cpp index c55cc1465e5..7880e6e0c09 100644 --- a/src/compiler/nir/tests/opt_varyings_tests_dead_output.cpp +++ b/src/compiler/nir/tests/opt_varyings_tests_dead_output.cpp @@ -6,6 +6,8 @@ #include "nir_opt_varyings_test.h" +namespace { + class nir_opt_varyings_test_dead_output : public nir_opt_varyings_test {}; @@ -18,7 +20,7 @@ TEST_F(nir_opt_varyings_test_dead_output, \ store_output(b1, VARYING_SLOT_##slot, 0, nir_type_float##bitsize, \ nir_imm_floatN_t(b1, 0, bitsize), 0); \ \ - ASSERT_TRUE(opt_varyings() == nir_progress_producer); \ + ASSERT_EQ(opt_varyings(), nir_progress_producer); \ ASSERT_TRUE(b1->shader->info.outputs_written == 0 && \ b1->shader->info.patch_outputs_written == 0 && \ b1->shader->info.outputs_written_16bit == 0); \ @@ -34,10 +36,10 @@ TEST_F(nir_opt_varyings_test_dead_output, \ store_output(b1, VARYING_SLOT_##slot, 0, nir_type_float##bitsize, \ nir_imm_floatN_t(b1, 0, bitsize), 0); \ \ - opt_varyings(); \ - ASSERT_TRUE(b1->shader->info.outputs_written == VARYING_BIT_##slot); \ + ASSERT_EQ(opt_varyings(), nir_progress_producer); \ + ASSERT_EQ(b1->shader->info.outputs_written, VARYING_BIT_##slot); \ ASSERT_TRUE(shader_contains_instr(b1, &intr->instr)); \ - ASSERT_TRUE(nir_intrinsic_io_semantics(intr).no_varying == \ + ASSERT_EQ(nir_intrinsic_io_semantics(intr).no_varying, \ (VARYING_SLOT_##slot != VARYING_SLOT_POS && \ VARYING_SLOT_##slot != VARYING_SLOT_PSIZ && \ VARYING_SLOT_##slot != VARYING_SLOT_CLIP_VERTEX)); \ @@ -67,20 +69,25 @@ TEST_F(nir_opt_varyings_test_dead_output, \ if (index == VARYING_SLOT_FOGC || index == VARYING_SLOT_PRIMITIVE_ID || \ index == VARYING_SLOT_TEX0 || index == VARYING_SLOT_VAR0_16BIT) \ index = VARYING_SLOT_VAR0; \ + \ + if (index == VARYING_SLOT_POS || index == VARYING_SLOT_PSIZ || \ + index == VARYING_SLOT_CLIP_VERTEX) \ + ASSERT_EQ(opt_varyings(), 0); \ + else \ + ASSERT_EQ(opt_varyings(), nir_progress_producer); \ \ - ASSERT_TRUE(opt_varyings() == 0); \ if (index >= VARYING_SLOT_VAR0_16BIT) { \ - ASSERT_TRUE(b1->shader->info.outputs_written_16bit == \ + ASSERT_EQ(b1->shader->info.outputs_written_16bit, \ BITFIELD_BIT(index - VARYING_SLOT_VAR0_16BIT)); \ } else { \ - ASSERT_TRUE(b1->shader->info.outputs_written == BITFIELD64_BIT(index)); \ + ASSERT_EQ(b1->shader->info.outputs_written, BITFIELD64_BIT(index)); \ } \ ASSERT_TRUE(shader_contains_instr(b1, &intr->instr)); \ - ASSERT_TRUE(nir_intrinsic_io_semantics(intr).no_varying == \ + ASSERT_EQ(nir_intrinsic_io_semantics(intr).no_varying, \ (VARYING_SLOT_##slot != VARYING_SLOT_POS && \ VARYING_SLOT_##slot != VARYING_SLOT_PSIZ && \ VARYING_SLOT_##slot != VARYING_SLOT_CLIP_VERTEX)); \ - ASSERT_TRUE(nir_intrinsic_io_xfb(intr).out[0].num_components == 1); \ + ASSERT_EQ(nir_intrinsic_io_xfb(intr).out[0].num_components, 1); \ } #define TEST_DEAD_OUTPUT_LOAD_TO_UNDEF(producer_stage, consumer_stage, slot, bitsize) \ @@ -91,7 +98,7 @@ TEST_F(nir_opt_varyings_test_dead_output, \ nir_def *output = load_output(b1, VARYING_SLOT_##slot, 0, nir_type_float##bitsize, 0); \ store_ssbo(b1, output); \ \ - ASSERT_TRUE(opt_varyings() == nir_progress_producer); \ + ASSERT_EQ(opt_varyings(), nir_progress_producer); \ ASSERT_TRUE(b1->shader->info.outputs_read == 0 && \ b1->shader->info.patch_outputs_read == 0 && \ b1->shader->info.outputs_read_16bit == 0); \ diff --git a/src/compiler/nir/tests/opt_varyings_tests_dedup.cpp b/src/compiler/nir/tests/opt_varyings_tests_dedup.cpp index ebceb76f4b0..d7d614270a7 100644 --- a/src/compiler/nir/tests/opt_varyings_tests_dedup.cpp +++ b/src/compiler/nir/tests/opt_varyings_tests_dedup.cpp @@ -6,6 +6,8 @@ #include "nir_opt_varyings_test.h" +namespace { + class nir_opt_varyings_test_dedup : public nir_opt_varyings_test {}; diff --git a/src/compiler/nir/tests/opt_varyings_tests_dedup_multiple.cpp b/src/compiler/nir/tests/opt_varyings_tests_dedup_multiple.cpp new file mode 100644 index 00000000000..8c23aa909e8 --- /dev/null +++ b/src/compiler/nir/tests/opt_varyings_tests_dedup_multiple.cpp @@ -0,0 +1,187 @@ +/* Copyright © 2026 Valve Corporation + * SPDX-License-Identifier: MIT + */ + +/* Verify that deduplication works when each slot has multiple stores. */ + +#include "nir_opt_varyings_test.h" + +namespace { + +class nir_opt_varyings_test_dedup_multiple : public nir_opt_varyings_test +{}; + +TEST_F(nir_opt_varyings_test_dedup_multiple, if_store2_else_store2) +{ + create_shaders(MESA_SHADER_GEOMETRY, MESA_SHADER_FRAGMENT); + + /* if (..) { + * output[0] = a; + * output[1] = a; // eliminated + * } else { + * output[0] = b; + * output[1] = b; // eliminated + * } + */ + + nir_intrinsic_instr *store[4] = {0}; + + nir_if *if_block = + nir_push_if(b1, nir_ieq_imm(b1, nir_load_primitive_id(b1), 0)); + + for (unsigned block = 0; block < 2; block++) { + nir_def *input = load_input(b1, VARYING_SLOT_VAR0, block, + nir_type_float32, 0, 0); + + for (unsigned s = 0; s < 2; s++) { + store[block * 2 + s] = store_output(b1, VARYING_SLOT_VAR0, s, + nir_type_float32, input, 0); + } + nir_emit_vertex(b1, 0); + + if (block == 0) + nir_push_else(b1, if_block); + } + + nir_end_primitive(b1); + nir_pop_if(b1, if_block); + + nir_def *load[2] = {0}; + for (unsigned s = 0; s < 2; s++) { + load[s] = load_input(b2, VARYING_SLOT_VAR0, s, + nir_type_float32, 0, INTERP_PERSP_PIXEL); + store_output(b2, (gl_varying_slot)FRAG_RESULT_DATA0, s, + nir_type_float32, load[s], 0); + } + + ASSERT_EQ(opt_varyings(), (nir_progress_producer | nir_progress_consumer)); + ASSERT_TRUE(shader_contains_instr(b1, &store[0]->instr)); + ASSERT_TRUE(!shader_contains_instr(b1, &store[1]->instr)); + ASSERT_TRUE(shader_contains_instr(b1, &store[2]->instr)); + ASSERT_TRUE(!shader_contains_instr(b1, &store[3]->instr)); + ASSERT_TRUE(shader_contains_def(b2, load[0])); + ASSERT_TRUE(!shader_contains_def(b2, load[1])); +} + +TEST_F(nir_opt_varyings_test_dedup_multiple, store2_emit_store2_emit) +{ + create_shaders(MESA_SHADER_GEOMETRY, MESA_SHADER_FRAGMENT); + + /* output[0] = a; + * output[1] = a; // eliminated + * emit_vertex; + * output[0] = b; + * output[1] = b; // eliminated + * emit_vertex; + */ + + nir_intrinsic_instr *store[4] = {0}; + + for (unsigned emit = 0; emit < 2; emit++) { + nir_def *input = load_input(b1, VARYING_SLOT_VAR0, emit, + nir_type_float32, 0, 0); + + for (unsigned s = 0; s < 2; s++) { + store[emit * 2 + s] = store_output(b1, VARYING_SLOT_VAR0, s, + nir_type_float32, input, 0); + } + nir_emit_vertex(b1, 0); + + } + + nir_end_primitive(b1); + + nir_def *load[2] = {0}; + for (unsigned s = 0; s < 2; s++) { + load[s] = load_input(b2, VARYING_SLOT_VAR0, s, + nir_type_float32, 0, INTERP_PERSP_PIXEL); + store_output(b2, (gl_varying_slot)FRAG_RESULT_DATA0, s, + nir_type_float32, load[s], 0); + } + + ASSERT_EQ(opt_varyings(), (nir_progress_producer | nir_progress_consumer)); + ASSERT_TRUE(shader_contains_instr(b1, &store[0]->instr)); + ASSERT_TRUE(!shader_contains_instr(b1, &store[1]->instr)); + ASSERT_TRUE(shader_contains_instr(b1, &store[2]->instr)); + ASSERT_TRUE(!shader_contains_instr(b1, &store[3]->instr)); + ASSERT_TRUE(shader_contains_def(b2, load[0])); + ASSERT_TRUE(!shader_contains_def(b2, load[1])); +} + +TEST_F(nir_opt_varyings_test_dedup_multiple, vs_invalid_case) +{ + create_shaders(MESA_SHADER_VERTEX, MESA_SHADER_FRAGMENT); + + /* if (vertex_id == 0) + * output[0] = vertex_id; + * else + * output[1] = vertex_id; // can't remove because output[0] is not set + * // for vertex_id > 0 + */ + + nir_intrinsic_instr *store[2] = {0}; + nir_def *invoc_id = nir_load_invocation_id(b1); + + nir_if *if_block = nir_push_if(b1, nir_ieq_imm(b1, invoc_id, 0)); + store[0] = store_output(b1, VARYING_SLOT_VAR0, 0, nir_type_float32, + invoc_id, 0); + nir_push_else(b1, if_block); + store[1] = store_output(b1, VARYING_SLOT_VAR0, 1, nir_type_float32, + invoc_id, 0); + nir_pop_if(b1, if_block); + + nir_def *load[2] = {0}; + for (unsigned s = 0; s < 2; s++) { + load[s] = load_input(b2, VARYING_SLOT_VAR0, s, + nir_type_float32, 0, INTERP_FLAT); + store_output(b2, VARYING_SLOT_VAR0, s, + nir_type_float32, load[s], 0); + } + + ASSERT_EQ(opt_varyings(), 0); + ASSERT_TRUE(shader_contains_instr(b1, &store[0]->instr)); + ASSERT_TRUE(shader_contains_instr(b1, &store[1]->instr)); + ASSERT_TRUE(shader_contains_def(b2, load[0])); + ASSERT_TRUE(shader_contains_def(b2, load[1])); +} + +TEST_F(nir_opt_varyings_test_dedup_multiple, tcs_invalid_case) +{ + create_shaders(MESA_SHADER_TESS_CTRL, MESA_SHADER_TESS_EVAL); + + /* if (invocation_id == 0) + * output[0] = invocation_id; + * else + * output[1] = invocation_id; + * + * These outputs aren't duplicated even if they store the same SSA def. + * nir_opt_varyings should do nothing. + */ + + nir_intrinsic_instr *store[2] = {0}; + nir_def *invoc_id = nir_load_invocation_id(b1); + + nir_if *if_block = nir_push_if(b1, nir_ieq_imm(b1, invoc_id, 0)); + store[0] = store_output(b1, VARYING_SLOT_PATCH0, 0, nir_type_float32, + invoc_id, 0); + nir_push_else(b1, if_block); + store[1] = store_output(b1, VARYING_SLOT_PATCH0, 1, nir_type_float32, + invoc_id, 0); + nir_pop_if(b1, if_block); + + nir_def *load[2] = {0}; + for (unsigned s = 0; s < 2; s++) { + load[s] = load_input(b2, VARYING_SLOT_PATCH0, s, nir_type_float32, 0, + INTERP_FLAT); + store_output(b2, VARYING_SLOT_VAR0, s, + nir_type_float32, load[s], 0); + } + + ASSERT_EQ(opt_varyings(), 0); + ASSERT_TRUE(shader_contains_instr(b1, &store[0]->instr)); + ASSERT_TRUE(shader_contains_instr(b1, &store[1]->instr)); + ASSERT_TRUE(shader_contains_def(b2, load[0])); + ASSERT_TRUE(shader_contains_def(b2, load[1])); +} + +} diff --git a/src/compiler/nir/tests/opt_varyings_tests_prop_const.cpp b/src/compiler/nir/tests/opt_varyings_tests_prop_const.cpp index 958ba352589..864c60813df 100644 --- a/src/compiler/nir/tests/opt_varyings_tests_prop_const.cpp +++ b/src/compiler/nir/tests/opt_varyings_tests_prop_const.cpp @@ -6,6 +6,8 @@ #include "nir_opt_varyings_test.h" +namespace { + class nir_opt_varyings_test_prop_const : public nir_opt_varyings_test {}; @@ -59,11 +61,11 @@ TEST_F(nir_opt_varyings_test_prop_const, \ SHADER_CONST_OUTPUT(producer_stage, consumer_stage, slot, comp, type, bitsize, value, value) \ \ if (nir_slot_is_sysval_output((gl_varying_slot)pindex, MESA_SHADER_##consumer_stage)) { \ - ASSERT_TRUE(opt_varyings() & nir_progress_consumer); \ - ASSERT_TRUE(b1->shader->info.outputs_written == BITFIELD64_BIT(pindex)); \ + ASSERT_EQ(opt_varyings(), (nir_progress_producer | nir_progress_consumer)); \ + ASSERT_EQ(b1->shader->info.outputs_written, BITFIELD64_BIT(pindex)); \ ASSERT_TRUE(nir_intrinsic_io_semantics(store).no_varying); \ } else { \ - ASSERT_TRUE(opt_varyings() == (nir_progress_producer | nir_progress_consumer)); \ + ASSERT_EQ(opt_varyings(), (nir_progress_producer | nir_progress_consumer)); \ ASSERT_TRUE(b1->shader->info.outputs_written == 0 && \ b1->shader->info.patch_outputs_written == 0 && \ b1->shader->info.outputs_written_16bit == 0); \ @@ -98,8 +100,8 @@ TEST_F(nir_opt_varyings_test_prop_const, \ if (store3) \ nir_intrinsic_set_io_xfb(store3, xfb); \ \ - ASSERT_TRUE(opt_varyings() == nir_progress_consumer); \ - ASSERT_TRUE(b1->shader->info.outputs_written == BITFIELD64_BIT(pindex)); \ + ASSERT_EQ(opt_varyings(), (nir_progress_producer | nir_progress_consumer)); \ + ASSERT_EQ(b1->shader->info.outputs_written, BITFIELD64_BIT(pindex)); \ ASSERT_TRUE(nir_intrinsic_io_semantics(store).no_varying); \ ASSERT_TRUE(b2->shader->info.inputs_read == 0 && \ b2->shader->info.patch_inputs_read == 0 && \ @@ -114,18 +116,18 @@ TEST_F(nir_opt_varyings_test_prop_const, \ { \ SHADER_CONST_OUTPUT(producer_stage, consumer_stage, slot, comp, type, bitsize, val0, val1) \ \ - ASSERT_TRUE(opt_varyings() == 0); \ + ASSERT_EQ(opt_varyings(), 0); \ if (pindex >= VARYING_SLOT_VAR0_16BIT) { \ - ASSERT_TRUE(b1->shader->info.outputs_written_16bit == \ + ASSERT_EQ(b1->shader->info.outputs_written_16bit, \ BITFIELD_BIT(pindex - VARYING_SLOT_VAR0_16BIT)); \ - ASSERT_TRUE(b2->shader->info.inputs_read_16bit == \ + ASSERT_EQ(b2->shader->info.inputs_read_16bit, \ BITFIELD_BIT(cindex - VARYING_SLOT_VAR0_16BIT)); \ } else if (pindex >= VARYING_SLOT_PATCH0) { \ - ASSERT_TRUE(b1->shader->info.patch_outputs_written == BITFIELD_BIT(pindex)); \ - ASSERT_TRUE(b2->shader->info.patch_inputs_read == BITFIELD_BIT(cindex)); \ + ASSERT_EQ(b1->shader->info.patch_outputs_written, BITFIELD_BIT(pindex)); \ + ASSERT_EQ(b2->shader->info.patch_inputs_read, BITFIELD_BIT(cindex)); \ } else { \ - ASSERT_TRUE(b1->shader->info.outputs_written == BITFIELD64_BIT(pindex)); \ - ASSERT_TRUE(b2->shader->info.inputs_read == BITFIELD64_BIT(cindex)); \ + ASSERT_EQ(b1->shader->info.outputs_written, BITFIELD64_BIT(pindex)); \ + ASSERT_EQ(b2->shader->info.inputs_read, BITFIELD64_BIT(cindex)); \ } \ ASSERT_TRUE(shader_contains_instr(b1, &store->instr)); \ ASSERT_TRUE(shader_contains_def(b2, input)); \ diff --git a/src/compiler/nir/tests/opt_varyings_tests_prop_ubo.cpp b/src/compiler/nir/tests/opt_varyings_tests_prop_ubo.cpp index ecd0c6e60be..235c0d74ad3 100644 --- a/src/compiler/nir/tests/opt_varyings_tests_prop_ubo.cpp +++ b/src/compiler/nir/tests/opt_varyings_tests_prop_ubo.cpp @@ -6,6 +6,8 @@ #include "nir_opt_varyings_test.h" +namespace { + class nir_opt_varyings_test_prop_ubo : public nir_opt_varyings_test {}; @@ -59,11 +61,11 @@ TEST_F(nir_opt_varyings_test_prop_ubo, \ SHADER_UBO_OUTPUT(producer_stage, consumer_stage, slot, comp, type, bitsize, 1, 1) \ \ if (nir_slot_is_sysval_output((gl_varying_slot)pindex, MESA_SHADER_##consumer_stage)) { \ - ASSERT_TRUE(opt_varyings() & nir_progress_consumer); \ - ASSERT_TRUE(b1->shader->info.outputs_written == BITFIELD64_BIT(pindex)); \ + ASSERT_EQ(opt_varyings(), (nir_progress_producer | nir_progress_consumer)); \ + ASSERT_EQ(b1->shader->info.outputs_written, BITFIELD64_BIT(pindex)); \ ASSERT_TRUE(nir_intrinsic_io_semantics(store).no_varying); \ } else { \ - ASSERT_TRUE(opt_varyings() == (nir_progress_producer | nir_progress_consumer)); \ + ASSERT_EQ(opt_varyings(), (nir_progress_producer | nir_progress_consumer)); \ ASSERT_TRUE(b1->shader->info.outputs_written == 0 && \ b1->shader->info.patch_outputs_written == 0 && \ b1->shader->info.outputs_written_16bit == 0); \ @@ -98,8 +100,8 @@ TEST_F(nir_opt_varyings_test_prop_ubo, \ if (store3) \ nir_intrinsic_set_io_xfb(store3, xfb); \ \ - ASSERT_TRUE(opt_varyings() == nir_progress_consumer); \ - ASSERT_TRUE(b1->shader->info.outputs_written == BITFIELD64_BIT(pindex)); \ + ASSERT_EQ(opt_varyings(), (nir_progress_producer | nir_progress_consumer)); \ + ASSERT_EQ(b1->shader->info.outputs_written, BITFIELD64_BIT(pindex)); \ ASSERT_TRUE(nir_intrinsic_io_semantics(store).no_varying); \ ASSERT_TRUE(b2->shader->info.inputs_read == 0 && \ b2->shader->info.patch_inputs_read == 0 && \ @@ -114,18 +116,18 @@ TEST_F(nir_opt_varyings_test_prop_ubo, \ { \ SHADER_UBO_OUTPUT(producer_stage, consumer_stage, slot, comp, type, bitsize, index0, index1) \ \ - ASSERT_TRUE(opt_varyings() == 0); \ + ASSERT_EQ(opt_varyings(), 0); \ if (pindex >= VARYING_SLOT_VAR0_16BIT) { \ - ASSERT_TRUE(b1->shader->info.outputs_written_16bit == \ + ASSERT_EQ(b1->shader->info.outputs_written_16bit, \ BITFIELD_BIT(pindex - VARYING_SLOT_VAR0_16BIT)); \ - ASSERT_TRUE(b2->shader->info.inputs_read_16bit == \ + ASSERT_EQ(b2->shader->info.inputs_read_16bit, \ BITFIELD_BIT(cindex - VARYING_SLOT_VAR0_16BIT)); \ } else if (pindex >= VARYING_SLOT_PATCH0) { \ - ASSERT_TRUE(b1->shader->info.patch_outputs_written == BITFIELD_BIT(pindex)); \ - ASSERT_TRUE(b2->shader->info.patch_inputs_read == BITFIELD_BIT(cindex)); \ + ASSERT_EQ(b1->shader->info.patch_outputs_written, BITFIELD_BIT(pindex)); \ + ASSERT_EQ(b2->shader->info.patch_inputs_read, BITFIELD_BIT(cindex)); \ } else { \ - ASSERT_TRUE(b1->shader->info.outputs_written == BITFIELD64_BIT(pindex)); \ - ASSERT_TRUE(b2->shader->info.inputs_read == BITFIELD64_BIT(cindex)); \ + ASSERT_EQ(b1->shader->info.outputs_written, BITFIELD64_BIT(pindex)); \ + ASSERT_EQ(b2->shader->info.inputs_read, BITFIELD64_BIT(cindex)); \ } \ ASSERT_TRUE(shader_contains_instr(b1, &store->instr)); \ ASSERT_TRUE(shader_contains_def(b2, input)); \ diff --git a/src/compiler/nir/tests/opt_varyings_tests_prop_uniform.cpp b/src/compiler/nir/tests/opt_varyings_tests_prop_uniform.cpp index 0382fc800c0..eac380803f2 100644 --- a/src/compiler/nir/tests/opt_varyings_tests_prop_uniform.cpp +++ b/src/compiler/nir/tests/opt_varyings_tests_prop_uniform.cpp @@ -6,6 +6,8 @@ #include "nir_opt_varyings_test.h" +namespace { + class nir_opt_varyings_test_prop_uniform : public nir_opt_varyings_test {}; @@ -59,11 +61,11 @@ TEST_F(nir_opt_varyings_test_prop_uniform, \ SHADER_UNIFORM_OUTPUT(producer_stage, consumer_stage, slot, comp, type, bitsize, 1, 1) \ \ if (nir_slot_is_sysval_output((gl_varying_slot)pindex, MESA_SHADER_##consumer_stage)) { \ - ASSERT_TRUE(opt_varyings() & nir_progress_consumer); \ - ASSERT_TRUE(b1->shader->info.outputs_written == BITFIELD64_BIT(pindex)); \ + ASSERT_EQ(opt_varyings(), (nir_progress_producer | nir_progress_consumer)); \ + ASSERT_EQ(b1->shader->info.outputs_written, BITFIELD64_BIT(pindex)); \ ASSERT_TRUE(nir_intrinsic_io_semantics(store).no_varying); \ } else { \ - ASSERT_TRUE(opt_varyings() == (nir_progress_producer | nir_progress_consumer)); \ + ASSERT_EQ(opt_varyings(), (nir_progress_producer | nir_progress_consumer)); \ ASSERT_TRUE(b1->shader->info.outputs_written == 0 && \ b1->shader->info.patch_outputs_written == 0 && \ b1->shader->info.outputs_written_16bit == 0); \ @@ -98,8 +100,8 @@ TEST_F(nir_opt_varyings_test_prop_uniform, \ if (store3) \ nir_intrinsic_set_io_xfb(store3, xfb); \ \ - ASSERT_TRUE(opt_varyings() == nir_progress_consumer); \ - ASSERT_TRUE(b1->shader->info.outputs_written == BITFIELD64_BIT(pindex)); \ + ASSERT_EQ(opt_varyings(), (nir_progress_producer | nir_progress_consumer)); \ + ASSERT_EQ(b1->shader->info.outputs_written, BITFIELD64_BIT(pindex)); \ ASSERT_TRUE(nir_intrinsic_io_semantics(store).no_varying); \ ASSERT_TRUE(b2->shader->info.inputs_read == 0 && \ b2->shader->info.patch_inputs_read == 0 && \ @@ -114,18 +116,18 @@ TEST_F(nir_opt_varyings_test_prop_uniform, \ { \ SHADER_UNIFORM_OUTPUT(producer_stage, consumer_stage, slot, comp, type, bitsize, index0, index1) \ \ - ASSERT_TRUE(opt_varyings() == 0); \ + ASSERT_EQ(opt_varyings(), 0); \ if (pindex >= VARYING_SLOT_VAR0_16BIT) { \ - ASSERT_TRUE(b1->shader->info.outputs_written_16bit == \ + ASSERT_EQ(b1->shader->info.outputs_written_16bit, \ BITFIELD_BIT(pindex - VARYING_SLOT_VAR0_16BIT)); \ - ASSERT_TRUE(b2->shader->info.inputs_read_16bit == \ + ASSERT_EQ(b2->shader->info.inputs_read_16bit, \ BITFIELD_BIT(cindex - VARYING_SLOT_VAR0_16BIT)); \ } else if (pindex >= VARYING_SLOT_PATCH0) { \ - ASSERT_TRUE(b1->shader->info.patch_outputs_written == BITFIELD_BIT(pindex)); \ - ASSERT_TRUE(b2->shader->info.patch_inputs_read == BITFIELD_BIT(cindex)); \ + ASSERT_EQ(b1->shader->info.patch_outputs_written, BITFIELD_BIT(pindex)); \ + ASSERT_EQ(b2->shader->info.patch_inputs_read, BITFIELD_BIT(cindex)); \ } else { \ - ASSERT_TRUE(b1->shader->info.outputs_written == BITFIELD64_BIT(pindex)); \ - ASSERT_TRUE(b2->shader->info.inputs_read == BITFIELD64_BIT(cindex)); \ + ASSERT_EQ(b1->shader->info.outputs_written, BITFIELD64_BIT(pindex)); \ + ASSERT_EQ(b2->shader->info.inputs_read, BITFIELD64_BIT(cindex)); \ } \ ASSERT_TRUE(shader_contains_instr(b1, &store->instr)); \ ASSERT_TRUE(shader_contains_def(b2, input)); \ diff --git a/src/compiler/nir/tests/opt_varyings_tests_prop_uniform_expr.cpp b/src/compiler/nir/tests/opt_varyings_tests_prop_uniform_expr.cpp index 15e8d4208bf..16504a87c00 100644 --- a/src/compiler/nir/tests/opt_varyings_tests_prop_uniform_expr.cpp +++ b/src/compiler/nir/tests/opt_varyings_tests_prop_uniform_expr.cpp @@ -6,6 +6,8 @@ #include "nir_opt_varyings_test.h" +namespace { + class nir_opt_varyings_test_prop_uniform_expr : public nir_opt_varyings_test {}; @@ -58,12 +60,11 @@ TEST_F(nir_opt_varyings_test_prop_uniform_expr, \ { \ SHADER_UNI_EXPR_OUTPUT(producer_stage, consumer_stage, slot, comp, type, bitsize, 1, 1) \ \ + ASSERT_EQ(opt_varyings(), (nir_progress_producer | nir_progress_consumer)); \ if (nir_slot_is_sysval_output((gl_varying_slot)pindex, MESA_SHADER_##consumer_stage)) { \ - ASSERT_TRUE(opt_varyings() & nir_progress_consumer); \ - ASSERT_TRUE(b1->shader->info.outputs_written == BITFIELD64_BIT(pindex)); \ + ASSERT_EQ(b1->shader->info.outputs_written, BITFIELD64_BIT(pindex)); \ ASSERT_TRUE(nir_intrinsic_io_semantics(store).no_varying); \ } else { \ - ASSERT_TRUE(opt_varyings() == (nir_progress_producer | nir_progress_consumer)); \ ASSERT_TRUE(b1->shader->info.outputs_written == 0 && \ b1->shader->info.patch_outputs_written == 0 && \ b1->shader->info.outputs_written_16bit == 0); \ @@ -98,8 +99,8 @@ TEST_F(nir_opt_varyings_test_prop_uniform_expr, \ if (store3) \ nir_intrinsic_set_io_xfb(store3, xfb); \ \ - ASSERT_TRUE(opt_varyings() == nir_progress_consumer); \ - ASSERT_TRUE(b1->shader->info.outputs_written == BITFIELD64_BIT(pindex)); \ + ASSERT_EQ(opt_varyings(), (nir_progress_producer | nir_progress_consumer)); \ + ASSERT_EQ(b1->shader->info.outputs_written, BITFIELD64_BIT(pindex)); \ ASSERT_TRUE(nir_intrinsic_io_semantics(store).no_varying); \ ASSERT_TRUE(b2->shader->info.inputs_read == 0 && \ b2->shader->info.patch_inputs_read == 0 && \ @@ -114,18 +115,18 @@ TEST_F(nir_opt_varyings_test_prop_uniform_expr, \ { \ SHADER_UNI_EXPR_OUTPUT(producer_stage, consumer_stage, slot, comp, type, bitsize, index0, index1) \ \ - ASSERT_TRUE(opt_varyings() == 0); \ + ASSERT_EQ(opt_varyings(), 0); \ if (pindex >= VARYING_SLOT_VAR0_16BIT) { \ - ASSERT_TRUE(b1->shader->info.outputs_written_16bit == \ + ASSERT_EQ(b1->shader->info.outputs_written_16bit, \ BITFIELD_BIT(pindex - VARYING_SLOT_VAR0_16BIT)); \ - ASSERT_TRUE(b2->shader->info.inputs_read_16bit == \ + ASSERT_EQ(b2->shader->info.inputs_read_16bit, \ BITFIELD_BIT(cindex - VARYING_SLOT_VAR0_16BIT)); \ } else if (pindex >= VARYING_SLOT_PATCH0) { \ - ASSERT_TRUE(b1->shader->info.patch_outputs_written == BITFIELD_BIT(pindex)); \ - ASSERT_TRUE(b2->shader->info.patch_inputs_read == BITFIELD_BIT(cindex)); \ + ASSERT_EQ(b1->shader->info.patch_outputs_written, BITFIELD_BIT(pindex)); \ + ASSERT_EQ(b2->shader->info.patch_inputs_read, BITFIELD_BIT(cindex)); \ } else { \ - ASSERT_TRUE(b1->shader->info.outputs_written == BITFIELD64_BIT(pindex)); \ - ASSERT_TRUE(b2->shader->info.inputs_read == BITFIELD64_BIT(cindex)); \ + ASSERT_EQ(b1->shader->info.outputs_written, BITFIELD64_BIT(pindex)); \ + ASSERT_EQ(b2->shader->info.inputs_read, BITFIELD64_BIT(cindex)); \ } \ ASSERT_TRUE(shader_contains_instr(b1, &store->instr)); \ ASSERT_TRUE(shader_contains_def(b2, input)); \ diff --git a/src/util/set.c b/src/util/set.c index d6c06235a3c..6c478ca34e2 100644 --- a/src/util/set.c +++ b/src/util/set.c @@ -700,3 +700,25 @@ _mesa_set_intersects(struct set *a, struct set *b) } return false; } + +bool +_mesa_set_equal(const struct set *a, const struct set *b) +{ + assert(a->key_hash_function == b->key_hash_function); + assert(a->key_equals_function == b->key_equals_function); + + if (a->entries != b->entries) + return false; + + set_foreach(a, entry) { + if (!_mesa_set_search_pre_hashed(b, entry->hash, entry->key)) + return false; + } + + set_foreach(b, entry) { + if (!_mesa_set_search_pre_hashed(a, entry->hash, entry->key)) + return false; + } + + return true; +} diff --git a/src/util/set.h b/src/util/set.h index 13cbb794d09..76c4e8ea2cb 100644 --- a/src/util/set.h +++ b/src/util/set.h @@ -142,6 +142,9 @@ _mesa_pointer_set_create(void *mem_ctx); bool _mesa_set_intersects(struct set *a, struct set *b); +bool +_mesa_set_equal(const struct set *a, const struct set *b); + /** * This foreach function is safe against deletion, but not against * insertion (which may rehash the set, making entry a dangling