nir: Add all allocated instructions to a GC list.
authorEmma Anholt <emma@anholt.net>
Wed, 7 Jul 2021 17:22:21 +0000 (10:22 -0700)
committerMarge Bot <eric+marge@anholt.net>
Tue, 14 Sep 2021 17:53:06 +0000 (17:53 +0000)
Right now we're using ralloc to GC our NIR instructions, but ralloc has
significant overhead for its recursive nature so it would be nice to use a
simpler mechanism for GCing instructions.

Reviewed-by: Matt Turner <mattst88@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/11776>

src/compiler/nir/nir.c
src/compiler/nir/nir.h
src/compiler/nir/nir_clone.c
src/compiler/nir/nir_sweep.c
src/compiler/nir/nir_validate.c

index 924f50e..c6bc24b 100644 (file)
@@ -121,6 +121,8 @@ nir_shader_create(void *mem_ctx,
 
    exec_list_make_empty(&shader->functions);
 
+   list_inithead(&shader->gc_list);
+
    shader->num_inputs = 0;
    shader->num_outputs = 0;
    shader->num_uniforms = 0;
@@ -576,6 +578,8 @@ nir_alu_instr_create(nir_shader *shader, nir_op op)
    for (unsigned i = 0; i < num_srcs; i++)
       alu_src_init(&instr->src[i]);
 
+   list_add(&instr->instr.gc_node, &shader->gc_list);
+
    return instr;
 }
 
@@ -597,6 +601,8 @@ nir_deref_instr_create(nir_shader *shader, nir_deref_type deref_type)
 
    dest_init(&instr->dest);
 
+   list_add(&instr->instr.gc_node, &shader->gc_list);
+
    return instr;
 }
 
@@ -609,6 +615,9 @@ nir_jump_instr_create(nir_shader *shader, nir_jump_type type)
    instr->type = type;
    instr->target = NULL;
    instr->else_target = NULL;
+
+   list_add(&instr->instr.gc_node, &shader->gc_list);
+
    return instr;
 }
 
@@ -622,6 +631,8 @@ nir_load_const_instr_create(nir_shader *shader, unsigned num_components,
 
    nir_ssa_def_init(&instr->instr, &instr->def, num_components, bit_size);
 
+   list_add(&instr->instr.gc_node, &shader->gc_list);
+
    return instr;
 }
 
@@ -643,6 +654,8 @@ nir_intrinsic_instr_create(nir_shader *shader, nir_intrinsic_op op)
    for (unsigned i = 0; i < num_srcs; i++)
       src_init(&instr->src[i]);
 
+   list_add(&instr->instr.gc_node, &shader->gc_list);
+
    return instr;
 }
 
@@ -660,6 +673,8 @@ nir_call_instr_create(nir_shader *shader, nir_function *callee)
    for (unsigned i = 0; i < num_params; i++)
       src_init(&instr->params[i]);
 
+   list_add(&instr->instr.gc_node, &shader->gc_list);
+
    return instr;
 }
 
@@ -688,6 +703,8 @@ nir_tex_instr_create(nir_shader *shader, unsigned num_srcs)
    instr->sampler_index = 0;
    memcpy(instr->tg4_offsets, default_tg4_offsets, sizeof(instr->tg4_offsets));
 
+   list_add(&instr->instr.gc_node, &shader->gc_list);
+
    return instr;
 }
 
@@ -746,6 +763,9 @@ nir_phi_instr_create(nir_shader *shader)
 
    dest_init(&instr->dest);
    exec_list_make_empty(&instr->srcs);
+
+   list_add(&instr->instr.gc_node, &shader->gc_list);
+
    return instr;
 }
 
@@ -779,6 +799,8 @@ nir_parallel_copy_instr_create(nir_shader *shader)
 
    exec_list_make_empty(&instr->entries);
 
+   list_add(&instr->instr.gc_node, &shader->gc_list);
+
    return instr;
 }
 
@@ -792,6 +814,8 @@ nir_ssa_undef_instr_create(nir_shader *shader,
 
    nir_ssa_def_init(&instr->instr, &instr->def, num_components, bit_size);
 
+   list_add(&instr->instr.gc_node, &shader->gc_list);
+
    return instr;
 }
 
@@ -1093,6 +1117,7 @@ void nir_instr_remove_v(nir_instr *instr)
 
 void nir_instr_free(nir_instr *instr)
 {
+   list_del(&instr->gc_node);
    ralloc_free(instr);
 }
 
index 0d9e09b..f80b2e7 100644 (file)
@@ -768,6 +768,7 @@ typedef enum PACKED {
 
 typedef struct nir_instr {
    struct exec_node node;
+   struct list_head gc_node;
    struct nir_block *block;
    nir_instr_type type;
 
@@ -3812,6 +3813,8 @@ typedef struct nir_shader {
 
    struct exec_list functions; /** < list of nir_function */
 
+   struct list_head gc_list; /** < list of all nir_instrs allocated on the shader but not yet freed. */
+
    /**
     * The size of the variable space for load_input_*, load_uniform_*, etc.
     * intrinsics.  This is in back-end specific units which is likely one of
index db46d40..d1bd0e5 100644 (file)
@@ -798,6 +798,8 @@ nir_shader_replace(nir_shader *dst, nir_shader *src)
    /* We have to move all the linked lists over separately because we need the
     * pointers in the list elements to point to the lists in dst and not src.
     */
+   list_replace(&src->gc_list, &dst->gc_list);
+   list_inithead(&src->gc_list);
    exec_list_move_nodes_to(&src->variables, &dst->variables);
 
    /* Now move the functions over.  This takes a tiny bit more work */
index e2b70f5..09fbddb 100644 (file)
@@ -73,6 +73,9 @@ sweep_block(nir_shader *nir, nir_block *block)
    block->live_out = NULL;
 
    nir_foreach_instr(instr, block) {
+      list_del(&instr->gc_node);
+      list_add(&instr->gc_node, &nir->gc_list);
+
       ralloc_steal(nir, instr);
 
       nir_foreach_src(instr, sweep_src_indirect, nir);
@@ -155,6 +158,12 @@ nir_sweep(nir_shader *nir)
 {
    void *rubbish = ralloc_context(NULL);
 
+   struct list_head instr_gc_list;
+   list_inithead(&instr_gc_list);
+
+   list_replace(&nir->gc_list, &instr_gc_list);
+   list_inithead(&nir->gc_list);
+
    /* First, move ownership of all the memory to a temporary context; assume dead. */
    ralloc_adopt(rubbish, nir);
 
@@ -170,6 +179,16 @@ nir_sweep(nir_shader *nir)
       sweep_function(nir, func);
    }
 
+   /* Manually GCed instrs now before ralloc_free()ing the other rubbish, to
+    * ensure that the shader's GC list was maintained without ralloc_freeing any
+    * instrs behind our back.  Note that the instr free routine will remove it
+    * from the list.
+    */
+   list_for_each_entry_safe(nir_instr, instr, &instr_gc_list, gc_node) {
+      nir_instr_free(instr);
+   }
+   assert(list_is_empty(&instr_gc_list));
+
    ralloc_steal(nir, nir->constant_data);
 
    /* Free everything we didn't steal back. */
index b27cbc0..62b23b0 100644 (file)
@@ -100,6 +100,8 @@ typedef struct {
 
    /* map of instruction/var/etc to failed assert string */
    struct hash_table *errors;
+
+   struct set *shader_gc_list;
 } validate_state;
 
 static void
@@ -1073,6 +1075,8 @@ validate_instr(nir_instr *instr, validate_state *state)
 
    state->instr = instr;
 
+   validate_assert(state, _mesa_set_search(state->shader_gc_list, instr));
+
    switch (instr->type) {
    case nir_instr_type_alu:
       validate_alu_instr(nir_instr_as_alu(instr), state);
@@ -1667,6 +1671,7 @@ init_validate_state(validate_state *state)
    state->blocks = _mesa_pointer_set_create(state->mem_ctx);
    state->var_defs = _mesa_pointer_hash_table_create(state->mem_ctx);
    state->errors = _mesa_pointer_hash_table_create(state->mem_ctx);
+   state->shader_gc_list = _mesa_pointer_set_create(state->mem_ctx);
 
    state->loop = NULL;
    state->instr = NULL;
@@ -1726,6 +1731,10 @@ nir_validate_shader(nir_shader *shader, const char *when)
    validate_state state;
    init_validate_state(&state);
 
+   list_for_each_entry(nir_instr, instr, &shader->gc_list, gc_node) {
+      _mesa_set_add(state.shader_gc_list, instr);
+   }
+
    state.shader = shader;
 
    nir_variable_mode valid_modes =