aco/isel: implement 16bit vec2 shifts

The source bit size mismatch is a bit annoying, but it's still worth it to
vectorize these.

Foz-DB Navi48:
Totals from 85 (0.11% of 80251) affected shaders:
Instrs: 119073 -> 118827 (-0.21%); split: -0.21%, +0.00%
CodeSize: 669604 -> 667552 (-0.31%); split: -0.31%, +0.00%
VGPRs: 4796 -> 4736 (-1.25%)
Latency: 1907685 -> 1901983 (-0.30%); split: -0.32%, +0.02%
InvThroughput: 642603 -> 640680 (-0.30%); split: -0.33%, +0.03%
VClause: 2088 -> 2091 (+0.14%)
Copies: 18300 -> 18394 (+0.51%); split: -0.01%, +0.52%
Branches: 3452 -> 3440 (-0.35%)
VALU: 63378 -> 63144 (-0.37%); split: -0.37%, +0.00%
SALU: 23065 -> 23076 (+0.05%); split: -0.00%, +0.05%

Reviewed-by: Daniel Schürmann <daniel@schuermann.dev>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/35825>
This commit is contained in:
Georg Lehmann
2025-06-30 09:49:02 +02:00
committed by Marge Bot
parent 4e258f8579
commit 96793fb0c1
2 changed files with 58 additions and 7 deletions
+4 -4
View File
@@ -469,10 +469,10 @@ aco_nir_op_supports_packed_math_16bit(const nir_alu_instr* alu)
case nir_op_imin:
case nir_op_imax:
case nir_op_umin:
case nir_op_umax: return true;
case nir_op_ishl: /* TODO: in NIR, these have 32bit shift operands */
case nir_op_ishr: /* while Radeon needs 16bit operands when vectorized */
case nir_op_ushr:
case nir_op_umax:
case nir_op_ishl:
case nir_op_ishr:
case nir_op_ushr: return true;
default: return false;
}
}
@@ -318,6 +318,57 @@ emit_idot_instruction(isel_context* ctx, nir_alu_instr* instr, aco_opcode op, Te
vop3p.neg_lo = neg_lo;
}
void
emit_pk_shift(isel_context* ctx, nir_alu_instr* instr, aco_opcode op, Temp dst)
{
Builder bld = create_alu_builder(ctx, instr);
Temp src1 = get_alu_src_vop3p(ctx, instr->src[0]);
Temp src0;
bitarray8 opsel_lo = (instr->src[0].swizzle[0] & 1) << 1;
bitarray8 opsel_hi = (instr->src[0].swizzle[1] & 1) << 1;
/* NIR's shift operand is always 32bit, but we want 16bit here. */
if (instr->src[1].swizzle[0] == instr->src[1].swizzle[1]) {
src0 = get_alu_src(ctx, instr->src[1], 1);
} else {
Operand comps[2];
for (unsigned i = 0; i < 2; i++) {
nir_scalar s = nir_scalar_resolved(instr->src[1].src.ssa, instr->src[1].swizzle[i]);
if (nir_scalar_is_const(s)) {
comps[i] = Operand::c16(nir_scalar_as_uint(s));
} else if (nir_scalar_is_alu(s) &&
(nir_scalar_alu_op(s) == nir_op_u2u32 ||
nir_scalar_alu_op(s) == nir_op_i2i32) &&
nir_instr_as_alu(s.def->parent_instr)->src[0].src.ssa->bit_size == 16) {
assert(s.def->num_components == 1);
Temp comp = get_alu_src(ctx, nir_instr_as_alu(s.def->parent_instr)->src[0]);
comps[i] = Operand(emit_extract_vector(ctx, comp, 0, v2b));
} else {
Temp vec = get_ssa_temp(ctx, instr->src[1].src.ssa);
RegClass rc = RegClass::get(vec.type(), 4);
Temp comp = emit_extract_vector(ctx, vec, instr->src[1].swizzle[i], rc);
comps[i] = Operand(emit_extract_vector(ctx, comp, 0, v2b));
}
}
opsel_hi[0] = 1;
if (comps[0].isConstant() && comps[1].isConstant()) {
uint32_t packed = (comps[1].constantValue() << 16) | comps[0].constantValue();
src0 = bld.copy(bld.def(s1), Operand::c32(packed));
} else {
src0 = bld.pseudo(aco_opcode::p_create_vector, bld.def(v1), comps[0], comps[1]);
}
}
if (src0.type() == RegType::sgpr && src1.type() == RegType::sgpr)
src1 = as_vgpr(ctx, src1);
bld.vop3p(op, Definition(dst), src0, src1, opsel_lo, opsel_hi);
emit_split_vector(ctx, dst, 2);
}
void
emit_vop1_instruction(isel_context* ctx, nir_alu_instr* instr, aco_opcode op, Temp dst)
{
@@ -1038,7 +1089,7 @@ visit_alu_instr(isel_context* ctx, nir_alu_instr* instr)
} else if (dst.regClass() == v2b) {
emit_vop2_instruction(ctx, instr, aco_opcode::v_lshrrev_b16, dst, false, true);
} else if (dst.regClass() == v1 && instr->def.bit_size == 16) {
emit_vop3p_instruction(ctx, instr, aco_opcode::v_pk_lshrrev_b16, dst, true);
emit_pk_shift(ctx, instr, aco_opcode::v_pk_lshrrev_b16, dst);
} else if (dst.regClass() == v1) {
emit_vop2_instruction(ctx, instr, aco_opcode::v_lshrrev_b32, dst, false, true);
} else if (dst.regClass() == v2 && ctx->program->gfx_level >= GFX8) {
@@ -1061,7 +1112,7 @@ visit_alu_instr(isel_context* ctx, nir_alu_instr* instr)
} else if (dst.regClass() == v2b) {
emit_vop2_instruction(ctx, instr, aco_opcode::v_lshlrev_b16, dst, false, true);
} else if (dst.regClass() == v1 && instr->def.bit_size == 16) {
emit_vop3p_instruction(ctx, instr, aco_opcode::v_pk_lshlrev_b16, dst, true);
emit_pk_shift(ctx, instr, aco_opcode::v_pk_lshlrev_b16, dst);
} else if (dst.regClass() == v1) {
emit_vop2_instruction(ctx, instr, aco_opcode::v_lshlrev_b32, dst, false, true, false,
false, 1);
@@ -1085,7 +1136,7 @@ visit_alu_instr(isel_context* ctx, nir_alu_instr* instr)
} else if (dst.regClass() == v2b) {
emit_vop2_instruction(ctx, instr, aco_opcode::v_ashrrev_i16, dst, false, true);
} else if (dst.regClass() == v1 && instr->def.bit_size == 16) {
emit_vop3p_instruction(ctx, instr, aco_opcode::v_pk_ashrrev_i16, dst, true);
emit_pk_shift(ctx, instr, aco_opcode::v_pk_ashrrev_i16, dst);
} else if (dst.regClass() == v1) {
emit_vop2_instruction(ctx, instr, aco_opcode::v_ashrrev_i32, dst, false, true);
} else if (dst.regClass() == v2 && ctx->program->gfx_level >= GFX8) {