broadcom/compiler: support ldunifa with some 16-bit loads

Even though ldunifa is strictly 32-bit we may be able to use it
to load 16-bit values that sit at 32-bit aligned addresses.

Reviewed-by: Alejandro Piñeiro <apinheiro@igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/14648>
This commit is contained in:
Iago Toral Quiroga
2022-01-18 11:13:56 +01:00
committed by Marge Bot
parent 2a420bdf92
commit 2eb6910d96
+37 -6
View File
@@ -2762,7 +2762,7 @@ emit_ldunifa(struct v3d_compile *c, struct qreg *result)
c->current_unifa_offset += 4;
}
static void
static bool
ntq_emit_load_ubo_unifa(struct v3d_compile *c, nir_intrinsic_instr *instr)
{
/* Every ldunifa auto-increments the unifa address by 4 bytes, so our
@@ -2771,9 +2771,22 @@ ntq_emit_load_ubo_unifa(struct v3d_compile *c, nir_intrinsic_instr *instr)
static const int32_t max_unifa_skip_dist =
MAX_UNIFA_SKIP_DISTANCE - 4;
/* We can only use unifa if the offset is uniform */
if (nir_src_is_divergent(instr->src[1]))
return false;
/* ldunifa is a 32-bit load instruction so we can only use it with
* 32-bit aligned addresses. We always produce 32-bit aligned addresses
* except for types smaller than 32-bit, so in these cases we can only
* use ldunifa if we can verify alignment, which we can only do for
* loads with a constant offset.
*/
uint32_t bit_size = nir_dest_bit_size(instr->dest);
bool dynamic_src = !nir_src_is_const(instr->src[1]);
uint32_t const_offset =
dynamic_src ? 0 : nir_src_as_uint(instr->src[1]);
if (bit_size < 32 && (dynamic_src || (const_offset % 4) != 0))
return false;
/* On OpenGL QUNIFORM_UBO_ADDR takes a UBO index
* shifted up by 1 (0 is gallium's constant buffer 0).
@@ -2821,11 +2834,31 @@ ntq_emit_load_ubo_unifa(struct v3d_compile *c, nir_intrinsic_instr *instr)
emit_ldunifa(c, NULL);
}
for (uint32_t i = 0; i < nir_intrinsic_dest_components(instr); i++) {
uint32_t num_components = nir_intrinsic_dest_components(instr);
for (uint32_t i = 0; i < num_components; i++) {
struct qreg data;
emit_ldunifa(c, &data);
ntq_store_dest(c, &instr->dest, i, vir_MOV(c, data));
if (bit_size == 32) {
ntq_store_dest(c, &instr->dest, i, vir_MOV(c, data));
i++;
} else {
assert(bit_size == 16);
struct qreg tmp = vir_AND(c, vir_MOV(c, data),
vir_uniform_ui(c, 0xffff));
ntq_store_dest(c, &instr->dest, i, vir_MOV(c, tmp));
i++;
if (i < num_components) {
tmp = vir_SHR(c, data, vir_uniform_ui(c, 16));
ntq_store_dest(c, &instr->dest, i,
vir_MOV(c, tmp));
i++;
}
}
}
return true;
}
static inline struct qreg
@@ -2872,9 +2905,7 @@ ntq_emit_intrinsic(struct v3d_compile *c, nir_intrinsic_instr *instr)
break;
case nir_intrinsic_load_ubo:
if (!nir_src_is_divergent(instr->src[1]))
ntq_emit_load_ubo_unifa(c, instr);
else
if (!ntq_emit_load_ubo_unifa(c, instr))
ntq_emit_tmu_general(c, instr, false);
break;