agx: Add udiv-by-constant routine

Uses the ridiculousfish algorithm, will be used to lower instanced
arrays into something efficient.

Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/12053>
This commit is contained in:
Alyssa Rosenzweig
2021-07-24 17:24:02 -04:00
parent 50a4c993fd
commit 0c353d47be

View File

@@ -27,6 +27,7 @@
#include "compiler/nir_types.h"
#include "compiler/nir/nir_builder.h"
#include "util/u_debug.h"
#include "util/fast_idiv_by_const.h"
#include "agx_compile.h"
#include "agx_compiler.h"
#include "agx_builder.h"
@@ -88,6 +89,49 @@ agx_emit_load_const(agx_builder *b, nir_load_const_instr *instr)
nir_const_value_as_uint(instr->value[0], bit_size));
}
/* Emit code dividing P by Q */
static agx_index
agx_udiv_const(agx_builder *b, agx_index P, uint32_t Q)
{
/* P / 1 = P */
if (Q == 1) {
return P;
}
/* P / UINT32_MAX = 0, unless P = UINT32_MAX when it's one */
if (Q == UINT32_MAX) {
agx_index max = agx_mov_imm(b, 32, UINT32_MAX);
agx_index one = agx_mov_imm(b, 32, 1);
return agx_icmpsel(b, P, max, one, agx_zero(), AGX_ICOND_UEQ);
}
/* P / 2^N = P >> N */
if (util_is_power_of_two_or_zero(Q)) {
return agx_ushr(b, P, agx_mov_imm(b, 32, util_logbase2(Q)));
}
/* Fall back on multiplication by a magic number */
struct util_fast_udiv_info info = util_compute_fast_udiv_info(Q, 32, 32);
agx_index preshift = agx_mov_imm(b, 32, info.pre_shift);
agx_index increment = agx_mov_imm(b, 32, info.increment);
agx_index postshift = agx_mov_imm(b, 32, info.post_shift);
agx_index multiplier = agx_mov_imm(b, 32, info.multiplier);
agx_index multiplied = agx_temp(b->shader, AGX_SIZE_64);
agx_index n = P;
if (info.pre_shift != 0) n = agx_ushr(b, n, preshift);
if (info.increment != 0) n = agx_iadd(b, n, increment, 0);
/* 64-bit multiplication, zero extending 32-bit x 32-bit, get the top word */
agx_imad_to(b, multiplied, agx_abs(n), agx_abs(multiplier), agx_zero(), 0);
n = agx_temp(b->shader, AGX_SIZE_32);
agx_p_extract_to(b, n, multiplied, 1);
if (info.post_shift != 0) n = agx_ushr(b, n, postshift);
return n;
}
/* AGX appears to lack support for vertex attributes. Lower to global loads. */
static agx_instr *
agx_emit_load_attr(agx_builder *b, nir_intrinsic_instr *instr)