i915/corm: direct output writes for vec construction

When a vec2/3/4 construction has a single consumer that is a
store_output, emit the partial-writemask MOVs directly to the
output register (oC/oD) instead of building in a temp and copying.
Skip this for the same_reg case which already collapses to a
zero-instruction swizzle alias.

Also fix TGSI-win reporting: preserve loser stats before freeing
so corm_win_reason shows the actual delta instead of "only".

shader-db (I915_FS=nir): 214/403 compiled, 3231 alu
shader-db (I915_FS=both): nir won 214 (26 identical, 1 tied, 184 better, 3 only),
  73 TGSI, 116 neither

Assisted-by: Claude
This commit is contained in:
Adam Jackson 2026-05-07 09:39:31 -04:00
parent 17b699ae24
commit 879cf1bd74

View file

@ -517,6 +517,27 @@ emit_alu(struct nir_to_i915 *c, nir_alu_instr *alu)
return;
}
/* If this vec's only consumer is a store_output, write directly
* to the output register instead of going through a temp.
*/
if (list_is_singular(&def->uses)) {
nir_src *use = list_first_entry(&def->uses, nir_src, use_link);
nir_instr *use_instr = nir_src_use_instr(use);
if (use_instr->type == nir_instr_type_intrinsic) {
nir_intrinsic_instr *store =
nir_instr_as_intrinsic(use_instr);
if (store->intrinsic == nir_intrinsic_store_output &&
nir_intrinsic_component(store) == 0) {
nir_io_semantics sem = nir_intrinsic_io_semantics(store);
uint32_t out = sem.location == FRAG_RESULT_DEPTH
? UREG(REG_TYPE_OD, 0) : UREG(REG_TYPE_OC, 0);
i915_release_temp(p, GET_UREG_NR(dest));
dest = out;
set_ureg(c, def, dest);
}
}
}
static const uint32_t chan_mask[] = {
A0_DEST_CHANNEL_X, A0_DEST_CHANNEL_Y,
A0_DEST_CHANNEL_Z, A0_DEST_CHANNEL_W,
@ -796,6 +817,11 @@ emit_intrinsic(struct nir_to_i915 *c, nir_intrinsic_instr *intr)
dest = UREG(REG_TYPE_OC, 0);
}
/* Vec direct-output already wrote to oC/oD */
uint32_t val_type = GET_UREG_TYPE(val);
if (val_type == REG_TYPE_OC || val_type == REG_TYPE_OD)
break;
nir_def *src_def = intr->src[0].ssa;
uint32_t *prev = c->def_csr[src_def->index];