From d1a2870f782fd1ee75b2d6e179a7fc06e52a961d Mon Sep 17 00:00:00 2001 From: Emma Anholt Date: Wed, 7 Jul 2021 10:22:21 -0700 Subject: [PATCH] nir: Add all allocated instructions to a GC list. 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 Part-of: --- src/compiler/nir/nir.c | 25 +++++++++++++++++++++++++ src/compiler/nir/nir.h | 3 +++ src/compiler/nir/nir_clone.c | 2 ++ src/compiler/nir/nir_sweep.c | 19 +++++++++++++++++++ src/compiler/nir/nir_validate.c | 9 +++++++++ 5 files changed, 58 insertions(+) diff --git a/src/compiler/nir/nir.c b/src/compiler/nir/nir.c index 924f50eaa94..c6bc24b0dd4 100644 --- a/src/compiler/nir/nir.c +++ b/src/compiler/nir/nir.c @@ -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); } diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h index 0d9e09b41dc..f80b2e74491 100644 --- a/src/compiler/nir/nir.h +++ b/src/compiler/nir/nir.h @@ -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 diff --git a/src/compiler/nir/nir_clone.c b/src/compiler/nir/nir_clone.c index db46d405020..d1bd0e5fa3d 100644 --- a/src/compiler/nir/nir_clone.c +++ b/src/compiler/nir/nir_clone.c @@ -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 */ diff --git a/src/compiler/nir/nir_sweep.c b/src/compiler/nir/nir_sweep.c index e2b70f5f767..09fbddb5cd0 100644 --- a/src/compiler/nir/nir_sweep.c +++ b/src/compiler/nir/nir_sweep.c @@ -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. */ diff --git a/src/compiler/nir/nir_validate.c b/src/compiler/nir/nir_validate.c index b27cbc01d26..62b23b00bad 100644 --- a/src/compiler/nir/nir_validate.c +++ b/src/compiler/nir/nir_validate.c @@ -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 =