[Mesa-dev] [PATCH 1/2] nir/cse: invalidate SSBO loads in presence of ssbo writes or memory barriers
Iago Toral Quiroga
itoral at igalia.com
Thu Oct 22 04:21:18 PDT 2015
In the next commit we are going to allow CSE of SSBO loads, so we need
to make sure that we consider how SSBO stores/atomics invalidate previous
loads.
---
src/glsl/nir/nir_opt_cse.c | 142 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 142 insertions(+)
diff --git a/src/glsl/nir/nir_opt_cse.c b/src/glsl/nir/nir_opt_cse.c
index 93a6635..4a57eca 100644
--- a/src/glsl/nir/nir_opt_cse.c
+++ b/src/glsl/nir/nir_opt_cse.c
@@ -32,6 +32,143 @@
* Implements common subexpression elimination
*/
+static bool
+is_ssbo_atomic_intrinsic_opcode(unsigned opcode)
+{
+ switch (opcode) {
+ case nir_intrinsic_ssbo_atomic_add:
+ case nir_intrinsic_ssbo_atomic_imin:
+ case nir_intrinsic_ssbo_atomic_umin:
+ case nir_intrinsic_ssbo_atomic_imax:
+ case nir_intrinsic_ssbo_atomic_umax:
+ case nir_intrinsic_ssbo_atomic_and:
+ case nir_intrinsic_ssbo_atomic_or:
+ case nir_intrinsic_ssbo_atomic_xor:
+ case nir_intrinsic_ssbo_atomic_exchange:
+ case nir_intrinsic_ssbo_atomic_comp_swap:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool
+is_indirect_ssbo_write(nir_intrinsic_instr *instr)
+{
+ return instr->intrinsic == nir_intrinsic_store_ssbo_indirect ||
+ is_ssbo_atomic_intrinsic_opcode(instr->intrinsic);
+}
+
+static bool
+is_ssbo_write(nir_instr *instr)
+{
+ if (instr->type != nir_instr_type_intrinsic)
+ return false;
+
+ nir_intrinsic_instr *intrinsic = nir_instr_as_intrinsic(instr);
+ if (is_ssbo_atomic_intrinsic_opcode(intrinsic->intrinsic))
+ return true;
+
+ return (intrinsic->intrinsic == nir_intrinsic_store_ssbo ||
+ intrinsic->intrinsic == nir_intrinsic_store_ssbo_indirect);
+}
+
+static nir_src *
+get_indirect_ssbo_store_offset(nir_intrinsic_instr *instr)
+{
+ assert(is_indirect_ssbo_write(instr));
+
+ if (instr->intrinsic == nir_intrinsic_store_ssbo_indirect)
+ return &instr->src[2];
+
+ /* atomic */
+ return &instr->src[1];
+}
+
+static bool
+is_memory_barrier(nir_instr *instr)
+{
+ if (instr->type != nir_instr_type_intrinsic)
+ return false;
+
+ nir_intrinsic_instr *intrinsic = nir_instr_as_intrinsic(instr);
+ return intrinsic->intrinsic == nir_intrinsic_memory_barrier;
+}
+
+/*
+ * Removes any SSBO load from the set that get invalidated by this
+ * SSBO store/atomic instruction.
+ */
+static void
+invalidate_ssbo_loads(nir_intrinsic_instr *store, struct set *instr_set)
+{
+ nir_src *store_block = &store->src[1];
+ for (struct set_entry *entry = _mesa_set_next_entry(instr_set, NULL);
+ entry != NULL; entry = _mesa_set_next_entry(instr_set, entry)) {
+
+ nir_instr *cached = (nir_instr *) entry->key;
+ if (cached->type != nir_instr_type_intrinsic)
+ continue;
+
+ nir_intrinsic_instr *load = nir_instr_as_intrinsic(cached);
+ if (load->intrinsic != nir_intrinsic_load_ssbo &&
+ load->intrinsic != nir_intrinsic_load_ssbo_indirect)
+ continue;
+
+ /* if blocks don't match then the load is still valid */
+ nir_src *load_block = &load->src[0];
+ if ((load_block->ssa->parent_instr->type ==
+ store_block->ssa->parent_instr->type) &&
+ !nir_srcs_equal(*store_block, *load_block))
+ continue;
+
+ /* indirect store / direct load (or viceversa): assume they can conflict */
+ if ((is_indirect_ssbo_write(store) &&
+ load->intrinsic == nir_intrinsic_load_ssbo) ||
+ (store->intrinsic == nir_intrinsic_store_ssbo &&
+ load->intrinsic == nir_intrinsic_load_ssbo_indirect)) {
+ nir_instr_set_remove(instr_set, (nir_instr *)entry->key);
+ }
+ /* indirect store and load: check if src offsets match */
+ else if (is_indirect_ssbo_write(store) &&
+ load->intrinsic == nir_intrinsic_load_ssbo_indirect) {
+ nir_src *store_offset = get_indirect_ssbo_store_offset(store);
+ nir_src *load_offset = &load->src[1];
+ if (nir_srcs_equal(*store_offset, *load_offset)) {
+ nir_instr_set_remove(instr_set, (nir_instr *)entry->key);
+ }
+ }
+ /* direct store and load: check if const_index offsets match */
+ else if (store->intrinsic == nir_intrinsic_store_ssbo &&
+ load->intrinsic == nir_intrinsic_load_ssbo) {
+ unsigned store_offset = store->const_index[0];
+ unsigned load_offset = load->const_index[0];
+ if (store_offset == load_offset) {
+ nir_instr_set_remove(instr_set, (nir_instr *)entry->key);
+ }
+ }
+ }
+}
+
+static void
+invalidate_all_ssbo_loads(struct set *instr_set)
+{
+ for (struct set_entry *entry = _mesa_set_next_entry(instr_set, NULL);
+ entry != NULL;
+ entry = _mesa_set_next_entry(instr_set, entry)) {
+ nir_instr *cached = (nir_instr *) entry->key;
+ if (cached->type != nir_instr_type_intrinsic)
+ continue;
+
+ nir_intrinsic_instr *intrinsic = nir_instr_as_intrinsic(cached);
+ if (intrinsic->intrinsic != nir_intrinsic_load_ssbo &&
+ intrinsic->intrinsic != nir_intrinsic_load_ssbo_indirect)
+ continue;
+
+ nir_instr_set_remove(instr_set, (nir_instr *)entry->key);
+ }
+}
+
/*
* Visits and CSE's the given block and all its descendants in the dominance
* tree recursively. Note that the instr_set is guaranteed to only ever
@@ -48,6 +185,11 @@ cse_block(nir_block *block, struct set *instr_set)
progress = true;
nir_instr_remove(instr);
}
+
+ if (is_ssbo_write(instr))
+ invalidate_ssbo_loads(nir_instr_as_intrinsic(instr), instr_set);
+ else if (is_memory_barrier(instr))
+ invalidate_all_ssbo_loads(instr_set);
}
for (unsigned i = 0; i < block->num_dom_children; i++) {
--
1.9.1
More information about the mesa-dev
mailing list