From eb8dbc2bbf00ee96c3f7ccd8c3704e7c5ea1fa52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Ol=C5=A1=C3=A1k?= Date: Mon, 27 Apr 2026 21:07:21 -0400 Subject: [PATCH 1/6] util/set: add helper _mesa_set_equal --- src/util/set.c | 22 ++++++++++++++++++++++ src/util/set.h | 3 +++ 2 files changed, 25 insertions(+) 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 From 3458eae4bc8354347e369a109f7af292b87143c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Ol=C5=A1=C3=A1k?= Date: Fri, 1 May 2026 22:29:36 -0400 Subject: [PATCH 2/6] nir/opt_varyings: rewrite elimination of duplicated outputs to strengthen it and fix a rare case of incorrect behavior. This is the incorrect behavior that's fixed: if (invocation_id == 0) patch_output[0] = invocation_id; else if (invocation_id == 1) patch_output[1] = invocation_id; else patch_output[2] = invocation_id; The stored SSA defs are the same, but each invocation writes a different value to different outputs, so they are not duplicated, but the code incorrectly treated them as duplicated and removed [1] and [2]. The requirement for correctness is that if an output is duplicated, it must have stores in the same blocks as the output it duplicates. To fix the incorrect behavior, awareness of blocks is added to the algorithm, which leads to the following new cases that are optimized: 1. Different blocks store different SSA defs, but equal in each block: if (..) { output[0] = a; output[1] = a; // eliminated } else { output[0] = b; output[1] = b; // eliminated } 2. Different GS emit sections store different SSA defs, but equal in each section: output[0] = a; output[1] = a; // eliminated emit_vertex; output[0] = b; output[1] = b; // eliminated emit_vertex; 3. A weird case that could be duplicated but is left alone due to the counterexample above: if (..) output[0] = a; else output[1] = a; --- src/compiler/nir/nir_opt_varyings.c | 246 +++++++++++++++++++++++----- 1 file changed, 203 insertions(+), 43 deletions(-) diff --git a/src/compiler/nir/nir_opt_varyings.c b/src/compiler/nir/nir_opt_varyings.c index db6c3400c0e..d21c502cc1a 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); @@ -2746,22 +2781,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 +2875,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 +2911,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 +3024,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); } /****************************************************************** From 5afa14f4a612af335c119d444a60c52cde492f02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Ol=C5=A1=C3=A1k?= Date: Sun, 3 May 2026 01:11:05 -0400 Subject: [PATCH 3/6] nir/tests: don't leave "namespace {" unclosed in nir_opt_varyings_tests.h --- src/compiler/nir/tests/nir_opt_varyings_test.h | 2 ++ src/compiler/nir/tests/opt_varyings_tests_bicm_binary_alu.cpp | 2 ++ src/compiler/nir/tests/opt_varyings_tests_bicm_sysval.cpp | 2 ++ src/compiler/nir/tests/opt_varyings_tests_dead_input.cpp | 2 ++ src/compiler/nir/tests/opt_varyings_tests_dead_output.cpp | 2 ++ src/compiler/nir/tests/opt_varyings_tests_dedup.cpp | 2 ++ src/compiler/nir/tests/opt_varyings_tests_prop_const.cpp | 2 ++ src/compiler/nir/tests/opt_varyings_tests_prop_ubo.cpp | 2 ++ src/compiler/nir/tests/opt_varyings_tests_prop_uniform.cpp | 2 ++ src/compiler/nir/tests/opt_varyings_tests_prop_uniform_expr.cpp | 2 ++ 10 files changed, 20 insertions(+) diff --git a/src/compiler/nir/tests/nir_opt_varyings_test.h b/src/compiler/nir/tests/nir_opt_varyings_test.h index b62e4c60547..73ab9d56c5c 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..4b29c41a31c 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 {}; 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..b02a271c92a 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 {}; 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_prop_const.cpp b/src/compiler/nir/tests/opt_varyings_tests_prop_const.cpp index 958ba352589..bbe23953f89 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 {}; 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..0677752bfe6 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 {}; 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..9af7a62d201 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 {}; 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..d049ef99431 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 {}; From a1da74d3cc5b080aa4291a6ddf16a68075e36b77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Ol=C5=A1=C3=A1k?= Date: Sun, 3 May 2026 01:40:53 -0400 Subject: [PATCH 4/6] nir/tests: test new output deduplication cases --- src/compiler/nir/meson.build | 1 + .../opt_varyings_tests_dedup_multiple.cpp | 187 ++++++++++++++++++ 2 files changed, 188 insertions(+) create mode 100644 src/compiler/nir/tests/opt_varyings_tests_dedup_multiple.cpp 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/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])); +} + +} From c1173f7a0b8651f6e63feafc7a167cb2ba64dda9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Ol=C5=A1=C3=A1k?= Date: Sat, 2 May 2026 10:21:47 -0400 Subject: [PATCH 5/6] nir/opt_varyings: always report progress when calling nir_remove_varying It changes IO semantics even if it doesn't remove the instruction. --- src/compiler/nir/nir_opt_varyings.c | 4 +++- .../nir/tests/opt_varyings_tests_dead_output.cpp | 9 +++++++-- src/compiler/nir/tests/opt_varyings_tests_prop_const.cpp | 4 ++-- src/compiler/nir/tests/opt_varyings_tests_prop_ubo.cpp | 4 ++-- .../nir/tests/opt_varyings_tests_prop_uniform.cpp | 4 ++-- .../nir/tests/opt_varyings_tests_prop_uniform_expr.cpp | 5 ++--- 6 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/compiler/nir/nir_opt_varyings.c b/src/compiler/nir/nir_opt_varyings.c index d21c502cc1a..e8d6b59cbcf 100644 --- a/src/compiler/nir/nir_opt_varyings.c +++ b/src/compiler/nir/nir_opt_varyings.c @@ -2009,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; 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 b02a271c92a..a2ea5367e19 100644 --- a/src/compiler/nir/tests/opt_varyings_tests_dead_output.cpp +++ b/src/compiler/nir/tests/opt_varyings_tests_dead_output.cpp @@ -36,7 +36,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); \ \ - opt_varyings(); \ + ASSERT_EQ(opt_varyings(), nir_progress_producer); \ ASSERT_TRUE(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 == \ @@ -69,8 +69,13 @@ 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 == \ BITFIELD_BIT(index - VARYING_SLOT_VAR0_16BIT)); \ 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 bbe23953f89..9c5a96e677c 100644 --- a/src/compiler/nir/tests/opt_varyings_tests_prop_const.cpp +++ b/src/compiler/nir/tests/opt_varyings_tests_prop_const.cpp @@ -61,7 +61,7 @@ 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_EQ(opt_varyings(), (nir_progress_producer | nir_progress_consumer)); \ ASSERT_TRUE(b1->shader->info.outputs_written == BITFIELD64_BIT(pindex)); \ ASSERT_TRUE(nir_intrinsic_io_semantics(store).no_varying); \ } else { \ @@ -100,7 +100,7 @@ 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_EQ(opt_varyings(), (nir_progress_producer | nir_progress_consumer)); \ ASSERT_TRUE(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 && \ 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 0677752bfe6..ecb5c301913 100644 --- a/src/compiler/nir/tests/opt_varyings_tests_prop_ubo.cpp +++ b/src/compiler/nir/tests/opt_varyings_tests_prop_ubo.cpp @@ -61,7 +61,7 @@ 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_EQ(opt_varyings(), (nir_progress_producer | nir_progress_consumer)); \ ASSERT_TRUE(b1->shader->info.outputs_written == BITFIELD64_BIT(pindex)); \ ASSERT_TRUE(nir_intrinsic_io_semantics(store).no_varying); \ } else { \ @@ -100,7 +100,7 @@ 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_EQ(opt_varyings(), (nir_progress_producer | nir_progress_consumer)); \ ASSERT_TRUE(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 && \ 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 9af7a62d201..07cb02f5b3c 100644 --- a/src/compiler/nir/tests/opt_varyings_tests_prop_uniform.cpp +++ b/src/compiler/nir/tests/opt_varyings_tests_prop_uniform.cpp @@ -61,7 +61,7 @@ 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_EQ(opt_varyings(), (nir_progress_producer | nir_progress_consumer)); \ ASSERT_TRUE(b1->shader->info.outputs_written == BITFIELD64_BIT(pindex)); \ ASSERT_TRUE(nir_intrinsic_io_semantics(store).no_varying); \ } else { \ @@ -100,7 +100,7 @@ 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_EQ(opt_varyings(), (nir_progress_producer | nir_progress_consumer)); \ ASSERT_TRUE(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 && \ 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 d049ef99431..33432575096 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 @@ -60,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_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); \ @@ -100,7 +99,7 @@ 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_EQ(opt_varyings(), (nir_progress_producer | nir_progress_consumer)); \ ASSERT_TRUE(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 && \ From d239887ce71bbe52357797ee8a6f7f66dffd998d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Ol=C5=A1=C3=A1k?= Date: Mon, 4 May 2026 07:26:54 -0400 Subject: [PATCH 6/6] nir/tests: use ASSERT_EQ instead of ASSERT_TRUE in nir_opt_varyings tests --- .../tests/opt_varyings_tests_dead_input.cpp | 14 ++++++------- .../tests/opt_varyings_tests_dead_output.cpp | 16 +++++++-------- .../tests/opt_varyings_tests_prop_const.cpp | 20 +++++++++---------- .../nir/tests/opt_varyings_tests_prop_ubo.cpp | 20 +++++++++---------- .../tests/opt_varyings_tests_prop_uniform.cpp | 20 +++++++++---------- .../opt_varyings_tests_prop_uniform_expr.cpp | 18 ++++++++--------- 6 files changed, 54 insertions(+), 54 deletions(-) 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 4b29c41a31c..cb0de2f8e5c 100644 --- a/src/compiler/nir/tests/opt_varyings_tests_dead_input.cpp +++ b/src/compiler/nir/tests/opt_varyings_tests_dead_input.cpp @@ -18,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); \ @@ -33,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); \ @@ -48,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)); \ } @@ -72,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 a2ea5367e19..7880e6e0c09 100644 --- a/src/compiler/nir/tests/opt_varyings_tests_dead_output.cpp +++ b/src/compiler/nir/tests/opt_varyings_tests_dead_output.cpp @@ -20,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); \ @@ -37,9 +37,9 @@ TEST_F(nir_opt_varyings_test_dead_output, \ nir_imm_floatN_t(b1, 0, bitsize), 0); \ \ ASSERT_EQ(opt_varyings(), nir_progress_producer); \ - ASSERT_TRUE(b1->shader->info.outputs_written == VARYING_BIT_##slot); \ + 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)); \ @@ -77,17 +77,17 @@ TEST_F(nir_opt_varyings_test_dead_output, \ ASSERT_EQ(opt_varyings(), nir_progress_producer); \ \ 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) \ @@ -98,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_prop_const.cpp b/src/compiler/nir/tests/opt_varyings_tests_prop_const.cpp index 9c5a96e677c..864c60813df 100644 --- a/src/compiler/nir/tests/opt_varyings_tests_prop_const.cpp +++ b/src/compiler/nir/tests/opt_varyings_tests_prop_const.cpp @@ -62,10 +62,10 @@ TEST_F(nir_opt_varyings_test_prop_const, \ \ if (nir_slot_is_sysval_output((gl_varying_slot)pindex, MESA_SHADER_##consumer_stage)) { \ ASSERT_EQ(opt_varyings(), (nir_progress_producer | 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_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); \ @@ -101,7 +101,7 @@ TEST_F(nir_opt_varyings_test_prop_const, \ nir_intrinsic_set_io_xfb(store3, xfb); \ \ ASSERT_EQ(opt_varyings(), (nir_progress_producer | 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); \ ASSERT_TRUE(b2->shader->info.inputs_read == 0 && \ b2->shader->info.patch_inputs_read == 0 && \ @@ -116,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 ecb5c301913..235c0d74ad3 100644 --- a/src/compiler/nir/tests/opt_varyings_tests_prop_ubo.cpp +++ b/src/compiler/nir/tests/opt_varyings_tests_prop_ubo.cpp @@ -62,10 +62,10 @@ TEST_F(nir_opt_varyings_test_prop_ubo, \ \ if (nir_slot_is_sysval_output((gl_varying_slot)pindex, MESA_SHADER_##consumer_stage)) { \ ASSERT_EQ(opt_varyings(), (nir_progress_producer | 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_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); \ @@ -101,7 +101,7 @@ TEST_F(nir_opt_varyings_test_prop_ubo, \ nir_intrinsic_set_io_xfb(store3, xfb); \ \ ASSERT_EQ(opt_varyings(), (nir_progress_producer | 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); \ ASSERT_TRUE(b2->shader->info.inputs_read == 0 && \ b2->shader->info.patch_inputs_read == 0 && \ @@ -116,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 07cb02f5b3c..eac380803f2 100644 --- a/src/compiler/nir/tests/opt_varyings_tests_prop_uniform.cpp +++ b/src/compiler/nir/tests/opt_varyings_tests_prop_uniform.cpp @@ -62,10 +62,10 @@ TEST_F(nir_opt_varyings_test_prop_uniform, \ \ if (nir_slot_is_sysval_output((gl_varying_slot)pindex, MESA_SHADER_##consumer_stage)) { \ ASSERT_EQ(opt_varyings(), (nir_progress_producer | 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_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); \ @@ -101,7 +101,7 @@ TEST_F(nir_opt_varyings_test_prop_uniform, \ nir_intrinsic_set_io_xfb(store3, xfb); \ \ ASSERT_EQ(opt_varyings(), (nir_progress_producer | 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); \ ASSERT_TRUE(b2->shader->info.inputs_read == 0 && \ b2->shader->info.patch_inputs_read == 0 && \ @@ -116,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 33432575096..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 @@ -62,7 +62,7 @@ TEST_F(nir_opt_varyings_test_prop_uniform_expr, \ \ 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(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(b1->shader->info.outputs_written == 0 && \ @@ -100,7 +100,7 @@ TEST_F(nir_opt_varyings_test_prop_uniform_expr, \ nir_intrinsic_set_io_xfb(store3, xfb); \ \ ASSERT_EQ(opt_varyings(), (nir_progress_producer | 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); \ ASSERT_TRUE(b2->shader->info.inputs_read == 0 && \ b2->shader->info.patch_inputs_read == 0 && \ @@ -115,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)); \