Codebase audit. In preparation to dynamically allocate destinations.
Signed-off-by: Alyssa Rosenzweig <alyssa@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/17794>
BITSET_WORD *replicates_16 = calloc(sizeof(bi_index), ctx->ssa_alloc);
bi_foreach_instr_global(ctx, ins) {
- if (bi_is_ssa(ins->dest[0]) && bi_instr_replicates(ins, replicates_16))
+ if (ins->nr_dests && bi_is_ssa(ins->dest[0]) && bi_instr_replicates(ins, replicates_16))
BITSET_SET(replicates_16, ins->dest[0].value);
if (ins->op == BI_OPCODE_SWZ_V2I16 && bi_is_ssa(ins->src[0]) &&
* Valhall, we will want to optimize this. For now, default
* to Bifrost compatible behaviour.
*/
- ins->dest[0].swizzle = BI_SWIZZLE_H01;
+ if (ins->nr_dests)
+ ins->dest[0].swizzle = BI_SWIZZLE_H01;
}
free(replicates_16);
if (unsupported) continue;
/* Replace with constant move, to be copypropped */
+ assert(ins->nr_dests == 1);
bi_builder b = bi_init_builder(ctx, bi_after_instr(ins));
bi_mov_i32_to(&b, ins->dest[0], bi_imm_u32(replace));
bi_remove_instruction(ins);
/* Lower the split to moves, copyprop cleans up */
bi_builder b = bi_init_builder(ctx, bi_before_instr(I));
- for (unsigned d = 0; d < I->nr_dests; ++d)
+ bi_foreach_dest(I, d)
bi_mov_i32_to(&b, I->dest[d], collect->src[d]);
bi_remove_instruction(I);
replace = chained;
}
+ assert(ins->nr_dests == 1);
replacement[ins->dest[0].value] = replace;
}
bi_builder b = bi_init_builder(ctx, bi_before_nonempty_block(block));
bi_foreach_instr_in_block_safe(block, I) {
- if (!bi_is_ssa(I->dest[0])) continue;
+ if (I->nr_dests != 1 || !bi_is_ssa(I->dest[0])) continue;
struct bifrost_message_preload msg;
bi_instr **lut = calloc(sizeof(bi_instr *), ctx->ssa_alloc);
bi_foreach_instr_global_safe(ctx, I) {
- if (bi_is_ssa(I->dest[0]))
- lut[I->dest[0].value] = I;
+ bi_foreach_dest(I, d) {
+ if (bi_is_ssa(I->dest[d]))
+ lut[I->dest[d].value] = I;
+ }
bi_foreach_src(I, s) {
if (!bi_is_ssa(I->src[s]))
}
}
- if (!bi_is_ssa(I->dest[0]))
+ if (!I->nr_dests || !bi_is_ssa(I->dest[0]))
continue;
bi_instr *use = uses[I->dest[0].value];
* +ATEST wants its destination written to both a staging register
* _and_ a regular write, because it may not generate a message */
- if (prev->add && (!write_dreg || prev->add->op == BI_OPCODE_ATEST)) {
+ if (prev->add && prev->add->nr_dests && (!write_dreg || prev->add->op == BI_OPCODE_ATEST)) {
bi_index idx = prev->add->dest[0];
if (idx.type == BI_INDEX_REGISTER) {
}
}
- if (prev->fma) {
- bi_index idx = (prev->fma)->dest[0];
+ if (prev->fma && prev->fma->nr_dests) {
+ bi_index idx = prev->fma->dest[0];
if (idx.type == BI_INDEX_REGISTER) {
if (now->regs.slot23.slot3) {
static bool
bi_must_not_last(bi_instr *ins)
{
- return !bi_is_null(ins->dest[0]) && !bi_is_null(ins->dest[1]) &&
- (ins->op != BI_OPCODE_TEXC_DUAL);
+ return (ins->nr_dests >= 2) && (ins->op != BI_OPCODE_TEXC_DUAL);
}
/* Check for a message-passing instruction. +DISCARD.f32 is special-cased; we
static bool
bi_has_cross_passthrough_hazard(bi_tuple *succ, bi_instr *ins)
{
+ if (ins->nr_dests == 0)
+ return false;
+
bi_foreach_instr_in_tuple(succ, pins) {
bi_foreach_src(pins, s) {
if (bi_is_word_equiv(ins->dest[0], pins->src[s]) &&
/* If this choice of FMA would force a staging passthrough, the ADD
* instruction must support such a passthrough */
- if (tuple->add && bi_has_staging_passthrough_hazard(instr->dest[0], tuple->add))
+ if (tuple->add && instr->nr_dests && bi_has_staging_passthrough_hazard(instr->dest[0], tuple->add))
return false;
/* If this choice of destination would force a cross-tuple passthrough, the next tuple must support that */
return false;
/* Count effective reads for the successor */
- unsigned succ_reads = bi_count_succ_reads(instr->dest[0],
- tuple->add ? tuple->add->dest[0] : bi_null(),
- tuple->prev_reads, tuple->nr_prev_reads);
+ unsigned succ_reads = 0;
+
+ if (instr->nr_dests) {
+ bool has_t1 = tuple->add && tuple->add->nr_dests;
+ succ_reads = bi_count_succ_reads(instr->dest[0],
+ has_t1 ? tuple->add->dest[0] : bi_null(),
+ tuple->prev_reads,
+ tuple->nr_prev_reads);
+ }
/* Successor must satisfy R+W <= 4, so we require W <= 4-R */
if ((signed) total_writes > (4 - (signed) succ_reads))
bool except_sr)
{
/* Optional for convenience */
- if (!ins || bi_is_null(old))
+ if (!ins)
return;
+ assert(!bi_is_null(old));
+
bi_foreach_src(ins, i) {
if ((i == 0 || i == 4) && except_sr)
continue;
{
bool sr_read = succ.add ? bi_opcode_props[succ.add->op].sr_read : false;
- if (prec.add) {
+ if (prec.add && prec.add->nr_dests) {
bi_use_passthrough(succ.fma, prec.add->dest[0], BIFROST_SRC_PASS_ADD, false);
bi_use_passthrough(succ.add, prec.add->dest[0], BIFROST_SRC_PASS_ADD, sr_read);
}
- if (prec.fma) {
+ if (prec.fma && prec.fma->nr_dests) {
bi_use_passthrough(succ.fma, prec.fma->dest[0], BIFROST_SRC_PASS_FMA, false);
bi_use_passthrough(succ.add, prec.fma->dest[0], BIFROST_SRC_PASS_FMA, sr_read);
}
* passthrough the sources of the ADD that read from the
* destination of the FMA */
- if (tuple->fma) {
+ if (tuple->fma && tuple->fma->nr_dests) {
bi_use_passthrough(tuple->add, tuple->fma->dest[0],
BIFROST_SRC_STAGE, false);
}
* Obscurely, ATOM_CX is sr_write but can ignore the staging register in
* certain circumstances; this does not require consideration.
*/
- if (bi_opcode_props[I->op].sr_write && bi_is_null(I->dest[0]) &&
- !bi_is_null(I->src[0])) {
+ if (bi_opcode_props[I->op].sr_write && I->nr_dests &&
+ bi_is_null(I->dest[0]) && !bi_is_null(I->src[0])) {
unsigned reg = I->src[0].value;
unsigned count = bi_count_write_registers(I, 0);
static unsigned
va_pack_dest(const bi_instr *I)
{
+ assert(I->nr_dests);
return va_pack_reg(I, I->dest[0]) | (va_pack_wrmask(I) << 6);
}
if (info.has_dest && info.nr_staging_dests == 0) {
hex |= (uint64_t) va_pack_dest(I) << 40;
} else if (info.nr_staging_dests == 0 && info.nr_staging_srcs == 0) {
- pack_assert(I, bi_is_null(I->dest[0]));
+ pack_assert(I, I->nr_dests == 0);
hex |= 0xC0ull << 40; /* Placeholder */
}