diff --git a/src/gallium/drivers/r300/compiler/nir_to_rc.c b/src/gallium/drivers/r300/compiler/nir_to_rc.c index e0707b1a3dd..d146ae5ae2b 100644 --- a/src/gallium/drivers/r300/compiler/nir_to_rc.c +++ b/src/gallium/drivers/r300/compiler/nir_to_rc.c @@ -226,263 +226,6 @@ struct ntr_live_reg_state { nir_block_worklist worklist; }; -static void -ntr_live_reg_mark_use(struct ntr_compile *c, struct ntr_live_reg_block_state *bs, int ip, - unsigned index, unsigned used_mask) -{ - bs->use[index] |= used_mask & ~bs->def[index]; - - c->liveness[index].start = MIN2(c->liveness[index].start, ip); - c->liveness[index].end = MAX2(c->liveness[index].end, ip); -} -static void -ntr_live_reg_setup_def_use(struct ntr_compile *c, nir_function_impl *impl, - struct ntr_live_reg_state *state) -{ - for (int i = 0; i < impl->num_blocks; i++) { - state->blocks[i].def = rzalloc_array(state->blocks, uint8_t, c->num_temps); - state->blocks[i].defin = rzalloc_array(state->blocks, uint8_t, c->num_temps); - state->blocks[i].defout = rzalloc_array(state->blocks, uint8_t, c->num_temps); - state->blocks[i].use = rzalloc_array(state->blocks, uint8_t, c->num_temps); - state->blocks[i].livein = rzalloc_array(state->blocks, uint8_t, c->num_temps); - state->blocks[i].liveout = rzalloc_array(state->blocks, uint8_t, c->num_temps); - } - - int ip = 0; - nir_foreach_block (block, impl) { - struct ntr_live_reg_block_state *bs = &state->blocks[block->index]; - struct ntr_block *ntr_block = ntr_block_from_nir(c, block); - - ntr_block->start_ip = ip; - - util_dynarray_foreach (&ntr_block->insns, struct ntr_insn, insn) { - const struct tgsi_opcode_info *opcode_info = tgsi_get_opcode_info(insn->opcode); - - /* Set up use[] for the srcs. - * - * Uses are the channels of the reg read in the block that don't have a - * preceding def to screen them off. Note that we don't do per-element - * tracking of array regs, so they're never screened off. - */ - for (int i = 0; i < opcode_info->num_src; i++) { - if (insn->src[i].File != TGSI_FILE_TEMPORARY) - continue; - int index = insn->src[i].Index; - - uint32_t used_mask = tgsi_util_get_src_usage_mask( - insn->opcode, i, insn->dst->WriteMask, insn->src[i].SwizzleX, insn->src[i].SwizzleY, - insn->src[i].SwizzleZ, insn->src[i].SwizzleW, insn->tex_target, insn->tex_target); - - assert(!insn->src[i].Indirect || index < c->first_non_array_temp); - ntr_live_reg_mark_use(c, bs, ip, index, used_mask); - } - - if (insn->is_tex) { - for (int i = 0; i < ARRAY_SIZE(insn->tex_offset); i++) { - if (insn->tex_offset[i].File == TGSI_FILE_TEMPORARY) - ntr_live_reg_mark_use(c, bs, ip, insn->tex_offset[i].Index, 0xf); - } - } - - /* Set up def[] for the srcs. - * - * Defs are the unconditionally-written (not R/M/W) channels of the reg in - * the block that don't have a preceding use. - */ - for (int i = 0; i < opcode_info->num_dst; i++) { - if (insn->dst[i].File != TGSI_FILE_TEMPORARY) - continue; - int index = insn->dst[i].Index; - uint32_t writemask = insn->dst[i].WriteMask; - - bs->def[index] |= writemask & ~bs->use[index]; - bs->defout[index] |= writemask; - - assert(!insn->dst[i].Indirect || index < c->first_non_array_temp); - c->liveness[index].start = MIN2(c->liveness[index].start, ip); - c->liveness[index].end = MAX2(c->liveness[index].end, ip); - } - ip++; - } - - ntr_block->end_ip = ip; - } -} - -static void -ntr_live_regs(struct ntr_compile *c, nir_function_impl *impl) -{ - nir_metadata_require(impl, nir_metadata_block_index); - - c->liveness = rzalloc_array(c, struct ntr_reg_interval, c->num_temps); - - struct ntr_live_reg_state state = { - .blocks = rzalloc_array(impl, struct ntr_live_reg_block_state, impl->num_blocks), - }; - - /* The intervals start out with start > end (indicating unused) */ - for (int i = 0; i < c->num_temps; i++) - c->liveness[i].start = ~0; - - ntr_live_reg_setup_def_use(c, impl, &state); - - /* Make a forward-order worklist of all the blocks. */ - nir_block_worklist_init(&state.worklist, impl->num_blocks, NULL); - nir_foreach_block (block, impl) { - nir_block_worklist_push_tail(&state.worklist, block); - } - - /* Propagate defin/defout down the CFG to calculate the live variables - * potentially defined along any possible control flow path. We'll use this - * to keep things like conditional defs of the reg (or array regs where we - * don't track defs!) from making the reg's live range extend back to the - * start of the program. - */ - while (!nir_block_worklist_is_empty(&state.worklist)) { - nir_block *block = nir_block_worklist_pop_head(&state.worklist); - for (int j = 0; j < ARRAY_SIZE(block->successors); j++) { - nir_block *succ = block->successors[j]; - if (!succ || succ->index == impl->num_blocks) - continue; - - for (int i = 0; i < c->num_temps; i++) { - uint8_t new_def = - state.blocks[block->index].defout[i] & ~state.blocks[succ->index].defin[i]; - - if (new_def) { - state.blocks[succ->index].defin[i] |= new_def; - state.blocks[succ->index].defout[i] |= new_def; - nir_block_worklist_push_tail(&state.worklist, succ); - } - } - } - } - - /* Make a reverse-order worklist of all the blocks. */ - nir_foreach_block (block, impl) { - nir_block_worklist_push_head(&state.worklist, block); - } - - /* We're now ready to work through the worklist and update the liveness sets - * of each of the blocks. As long as we keep the worklist up-to-date as we - * go, everything will get covered. - */ - while (!nir_block_worklist_is_empty(&state.worklist)) { - /* We pop them off in the reverse order we pushed them on. This way - * the first walk of the instructions is backwards so we only walk - * once in the case of no control flow. - */ - nir_block *block = nir_block_worklist_pop_head(&state.worklist); - struct ntr_block *ntr_block = ntr_block_from_nir(c, block); - struct ntr_live_reg_block_state *bs = &state.blocks[block->index]; - - for (int i = 0; i < c->num_temps; i++) { - /* Collect livein from our successors to include in our liveout. */ - for (int j = 0; j < ARRAY_SIZE(block->successors); j++) { - nir_block *succ = block->successors[j]; - if (!succ || succ->index == impl->num_blocks) - continue; - struct ntr_live_reg_block_state *sbs = &state.blocks[succ->index]; - - uint8_t new_liveout = sbs->livein[i] & ~bs->liveout[i]; - if (new_liveout) { - if (state.blocks[block->index].defout[i]) - c->liveness[i].end = MAX2(c->liveness[i].end, ntr_block->end_ip); - bs->liveout[i] |= sbs->livein[i]; - } - } - - /* Propagate use requests from either our block's uses or our - * non-screened-off liveout up to our predecessors. - */ - uint8_t new_livein = ((bs->use[i] | (bs->liveout[i] & ~bs->def[i])) & ~bs->livein[i]); - if (new_livein) { - bs->livein[i] |= new_livein; - set_foreach (block->predecessors, entry) { - nir_block *pred = (void *)entry->key; - nir_block_worklist_push_tail(&state.worklist, pred); - } - - if (new_livein & state.blocks[block->index].defin[i]) - c->liveness[i].start = MIN2(c->liveness[i].start, ntr_block->start_ip); - } - } - } - - ralloc_free(state.blocks); - nir_block_worklist_fini(&state.worklist); -} - -static void -ntr_ra_check(struct ntr_compile *c, unsigned *ra_map, BITSET_WORD *released, int ip, unsigned index) -{ - if (index < c->first_non_array_temp) - return; - - if (c->liveness[index].start == ip && ra_map[index] == ~0) - ra_map[index] = ureg_DECL_temporary(c->ureg).Index; - - if (c->liveness[index].end == ip && !BITSET_TEST(released, index)) { - ureg_release_temporary(c->ureg, ureg_dst_register(TGSI_FILE_TEMPORARY, ra_map[index])); - BITSET_SET(released, index); - } -} - -static void -ntr_allocate_regs(struct ntr_compile *c, nir_function_impl *impl) -{ - ntr_live_regs(c, impl); - - unsigned *ra_map = ralloc_array(c, unsigned, c->num_temps); - unsigned *released = rzalloc_array(c, BITSET_WORD, BITSET_WORDS(c->num_temps)); - - /* No RA on NIR array regs */ - for (int i = 0; i < c->first_non_array_temp; i++) - ra_map[i] = i; - - for (int i = c->first_non_array_temp; i < c->num_temps; i++) - ra_map[i] = ~0; - - int ip = 0; - nir_foreach_block (block, impl) { - struct ntr_block *ntr_block = ntr_block_from_nir(c, block); - - for (int i = 0; i < c->num_temps; i++) - ntr_ra_check(c, ra_map, released, ip, i); - - util_dynarray_foreach (&ntr_block->insns, struct ntr_insn, insn) { - const struct tgsi_opcode_info *opcode_info = tgsi_get_opcode_info(insn->opcode); - - for (int i = 0; i < opcode_info->num_src; i++) { - if (insn->src[i].File == TGSI_FILE_TEMPORARY) { - ntr_ra_check(c, ra_map, released, ip, insn->src[i].Index); - insn->src[i].Index = ra_map[insn->src[i].Index]; - } - } - - if (insn->is_tex) { - for (int i = 0; i < ARRAY_SIZE(insn->tex_offset); i++) { - if (insn->tex_offset[i].File == TGSI_FILE_TEMPORARY) { - ntr_ra_check(c, ra_map, released, ip, insn->tex_offset[i].Index); - insn->tex_offset[i].Index = ra_map[insn->tex_offset[i].Index]; - } - } - } - - for (int i = 0; i < opcode_info->num_dst; i++) { - if (insn->dst[i].File == TGSI_FILE_TEMPORARY) { - ntr_ra_check(c, ra_map, released, ip, insn->dst[i].Index); - insn->dst[i].Index = ra_map[insn->dst[i].Index]; - } - } - ip++; - } - - for (int i = 0; i < c->num_temps; i++) - ntr_ra_check(c, ra_map, released, ip, i); - } -} - static void ntr_allocate_regs_unoptimized(struct ntr_compile *c, nir_function_impl *impl) { @@ -2035,10 +1778,7 @@ ntr_emit_impl(struct ntr_compile *c, nir_function_impl *impl) /* Emit the ntr insns */ ntr_emit_cf_list(c, &impl->body); - if (c->s->info.stage == MESA_SHADER_FRAGMENT) - ntr_allocate_regs(c, impl); - else - ntr_allocate_regs_unoptimized(c, impl); + ntr_allocate_regs_unoptimized(c, impl); /* Turn the ntr insns into actual TGSI tokens */ ntr_emit_cf_list_ureg(c, &impl->body);