diff --git a/src/gallium/drivers/i915/i915_fpc_nir.c b/src/gallium/drivers/i915/i915_fpc_nir.c index 346e06d0a34..4df750d4734 100644 --- a/src/gallium/drivers/i915/i915_fpc_nir.c +++ b/src/gallium/drivers/i915/i915_fpc_nir.c @@ -22,8 +22,51 @@ struct nir_to_i915 { uint32_t *ureg_map; unsigned ureg_map_size; + + int *last_use; + int ip; }; +static bool +mark_last_use_cb(nir_src *src, void *state) +{ + struct nir_to_i915 *c = state; + if (src->ssa->index < c->ureg_map_size) + c->last_use[src->ssa->index] = c->ip; + return true; +} + +static void +compute_last_use(struct nir_to_i915 *c, nir_function_impl *impl) +{ + c->ip = 0; + nir_foreach_block(block, impl) { + nir_foreach_instr(instr, block) { + nir_foreach_src(instr, mark_last_use_cb, c); + c->ip++; + } + } +} + +static bool +release_if_last_use_cb(nir_src *src, void *state) +{ + struct nir_to_i915 *c = state; + unsigned idx = src->ssa->index; + if (idx < c->ureg_map_size && c->last_use[idx] == c->ip) { + uint32_t ureg = c->ureg_map[idx]; + if (GET_UREG_TYPE(ureg) == REG_TYPE_R) + i915_release_temp(c->p, GET_UREG_NR(ureg)); + } + return true; +} + +static void +release_dead_temps(struct nir_to_i915 *c, nir_instr *instr) +{ + nir_foreach_src(instr, release_if_last_use_cb, c); +} + static void set_ureg(struct nir_to_i915 *c, nir_def *def, uint32_t ureg) { @@ -185,6 +228,9 @@ emit_alu(struct nir_to_i915 *c, nir_alu_instr *alu) i915_release_temp(p, GET_UREG_NR(dest)); set_ureg(c, def, alu->op == nir_op_fneg ? negate(src0, 1, 1, 1, 1) : src0); + unsigned src_idx = alu->src[0].src.ssa->index; + if (c->last_use[src_idx] == c->ip) + c->last_use[src_idx] = c->last_use[def->index]; return; } case nir_op_fabs: @@ -727,13 +773,20 @@ i915_translate_fragment_program_nir(struct i915_context *i915, .opts = *opts, .ureg_map_size = impl->ssa_alloc, .ureg_map = CALLOC(impl->ssa_alloc, sizeof(uint32_t)), + .last_use = CALLOC(impl->ssa_alloc, sizeof(int)), }; + memset(c.last_use, -1, impl->ssa_alloc * sizeof(int)); + compute_last_use(&c, impl); + + c.ip = 0; nir_foreach_block(block, impl) { nir_foreach_instr(instr, block) { emit_instr(&c, instr); if (p->error[0]) break; + release_dead_temps(&c, instr); + c.ip++; } if (p->error[0]) break; @@ -799,6 +852,7 @@ cleanup: else ralloc_free(p->error); + FREE(c.last_use); FREE(c.ureg_map); FREE(p);