agx: Switch to dynamic allocation of srcs/dests
So we can handle parallel copies later. Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/18804>
This commit is contained in:

committed by
Marge Bot

parent
544c60a132
commit
7c9fba34bc
@@ -27,10 +27,19 @@ template = """/*
|
|||||||
#include "agx_compiler.h"
|
#include "agx_compiler.h"
|
||||||
|
|
||||||
static inline agx_instr *
|
static inline agx_instr *
|
||||||
agx_alloc_instr(agx_builder *b, enum agx_opcode op)
|
agx_alloc_instr(agx_builder *b, enum agx_opcode op, uint8_t nr_dests, uint8_t nr_srcs)
|
||||||
{
|
{
|
||||||
agx_instr *I = rzalloc(b->shader, agx_instr);
|
size_t size = sizeof(agx_instr);
|
||||||
|
size += sizeof(agx_index) * nr_dests;
|
||||||
|
size += sizeof(agx_index) * nr_srcs;
|
||||||
|
|
||||||
|
agx_instr *I = (agx_instr *) rzalloc_size(b->shader, size);
|
||||||
|
I->dest = (agx_index *) (I + 1);
|
||||||
|
I->src = I->dest + nr_dests;
|
||||||
|
|
||||||
I->op = op;
|
I->op = op;
|
||||||
|
I->nr_dests = nr_dests;
|
||||||
|
I->nr_srcs = nr_srcs;
|
||||||
return I;
|
return I;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,11 +50,17 @@ agx_alloc_instr(agx_builder *b, enum agx_opcode op)
|
|||||||
srcs = op.srcs
|
srcs = op.srcs
|
||||||
imms = op.imms
|
imms = op.imms
|
||||||
suffix = "_to" if dests > 0 else ""
|
suffix = "_to" if dests > 0 else ""
|
||||||
|
nr_dests = "nr_dests" if op.variable_dests else str(dests)
|
||||||
|
nr_srcs = "nr_srcs" if op.variable_srcs else str(srcs)
|
||||||
%>
|
%>
|
||||||
|
|
||||||
static inline agx_instr *
|
static inline agx_instr *
|
||||||
agx_${opcode}${suffix}(agx_builder *b
|
agx_${opcode}${suffix}(agx_builder *b
|
||||||
|
|
||||||
|
% if op.variable_dests:
|
||||||
|
, unsigned nr_dests
|
||||||
|
% endif
|
||||||
|
|
||||||
% for dest in range(dests):
|
% for dest in range(dests):
|
||||||
, agx_index dst${dest}
|
, agx_index dst${dest}
|
||||||
% endfor
|
% endfor
|
||||||
@@ -63,23 +78,15 @@ agx_${opcode}${suffix}(agx_builder *b
|
|||||||
% endfor
|
% endfor
|
||||||
|
|
||||||
) {
|
) {
|
||||||
agx_instr *I = agx_alloc_instr(b, AGX_OPCODE_${opcode.upper()});
|
agx_instr *I = agx_alloc_instr(b, AGX_OPCODE_${opcode.upper()}, ${nr_dests}, ${nr_srcs});
|
||||||
|
|
||||||
% for dest in range(dests):
|
% for dest in range(dests):
|
||||||
I->dest[${dest}] = dst${dest};
|
I->dest[${dest}] = dst${dest};
|
||||||
% endfor
|
% endfor
|
||||||
|
|
||||||
% if op.variable_srcs:
|
|
||||||
I->src = ralloc_array(I, agx_index, nr_srcs);
|
|
||||||
I->nr_srcs = nr_srcs;
|
|
||||||
% elif srcs > 0:
|
|
||||||
I->src = ralloc_array(I, agx_index, ${srcs});
|
|
||||||
I->nr_srcs = ${srcs};
|
|
||||||
|
|
||||||
% for src in range(srcs):
|
% for src in range(srcs):
|
||||||
I->src[${src}] = src${src};
|
I->src[${src}] = src${src};
|
||||||
% endfor
|
% endfor
|
||||||
% endif
|
|
||||||
|
|
||||||
% for imm in imms:
|
% for imm in imms:
|
||||||
I->${imm.name} = ${imm.name};
|
I->${imm.name} = ${imm.name};
|
||||||
@@ -89,7 +96,7 @@ agx_${opcode}${suffix}(agx_builder *b
|
|||||||
return I;
|
return I;
|
||||||
}
|
}
|
||||||
|
|
||||||
% if dests == 1 and not op.variable_srcs:
|
% if dests == 1 and not op.variable_srcs and not op.variable_dests:
|
||||||
static inline agx_index
|
static inline agx_index
|
||||||
agx_${opcode}(agx_builder *b
|
agx_${opcode}(agx_builder *b
|
||||||
|
|
||||||
|
@@ -1207,7 +1207,8 @@ agx_emit_jump(agx_builder *b, nir_jump_instr *instr)
|
|||||||
static void
|
static void
|
||||||
agx_emit_phi(agx_builder *b, nir_phi_instr *instr)
|
agx_emit_phi(agx_builder *b, nir_phi_instr *instr)
|
||||||
{
|
{
|
||||||
agx_instr *I = agx_phi_to(b, agx_dest_index(&instr->dest));
|
agx_instr *I = agx_phi_to(b, agx_dest_index(&instr->dest),
|
||||||
|
exec_list_length(&instr->srcs));
|
||||||
|
|
||||||
/* Deferred */
|
/* Deferred */
|
||||||
I->phi = instr;
|
I->phi = instr;
|
||||||
@@ -1230,9 +1231,6 @@ agx_emit_phi_deferred(agx_context *ctx, agx_block *block, agx_instr *I)
|
|||||||
/* Guaranteed by lower_phis_to_scalar */
|
/* Guaranteed by lower_phis_to_scalar */
|
||||||
assert(phi->dest.ssa.num_components == 1);
|
assert(phi->dest.ssa.num_components == 1);
|
||||||
|
|
||||||
I->nr_srcs = exec_list_length(&phi->srcs);
|
|
||||||
I->src = rzalloc_array(I, agx_index, I->nr_srcs);
|
|
||||||
|
|
||||||
nir_foreach_phi_src(src, phi) {
|
nir_foreach_phi_src(src, phi) {
|
||||||
agx_block *pred = agx_from_nir_block(ctx, src->pred);
|
agx_block *pred = agx_from_nir_block(ctx, src->pred);
|
||||||
unsigned i = agx_predecessor_index(block, pred);
|
unsigned i = agx_predecessor_index(block, pred);
|
||||||
|
@@ -288,12 +288,13 @@ typedef struct {
|
|||||||
nir_phi_instr *phi;
|
nir_phi_instr *phi;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Data flow */
|
||||||
|
agx_index *dest;
|
||||||
|
|
||||||
enum agx_opcode op;
|
enum agx_opcode op;
|
||||||
|
|
||||||
/* Data flow */
|
uint8_t nr_dests;
|
||||||
agx_index dest[AGX_MAX_DESTS];
|
uint8_t nr_srcs;
|
||||||
|
|
||||||
unsigned nr_srcs;
|
|
||||||
|
|
||||||
union {
|
union {
|
||||||
uint32_t imm;
|
uint32_t imm;
|
||||||
@@ -534,7 +535,7 @@ agx_vec_for_intr(agx_context *ctx, nir_intrinsic_instr *instr)
|
|||||||
for (unsigned v = 0; v < ins->nr_srcs; ++v)
|
for (unsigned v = 0; v < ins->nr_srcs; ++v)
|
||||||
|
|
||||||
#define agx_foreach_dest(ins, v) \
|
#define agx_foreach_dest(ins, v) \
|
||||||
for (unsigned v = 0; v < ARRAY_SIZE(ins->dest); ++v)
|
for (unsigned v = 0; v < ins->nr_dests; ++v)
|
||||||
|
|
||||||
/* Phis only come at the start so we stop as soon as we hit a non-phi */
|
/* Phis only come at the start so we stop as soon as we hit a non-phi */
|
||||||
#define agx_foreach_phi_in_block(block, v) \
|
#define agx_foreach_phi_in_block(block, v) \
|
||||||
|
@@ -25,40 +25,38 @@
|
|||||||
#include "agx_builder.h"
|
#include "agx_builder.h"
|
||||||
|
|
||||||
/* Lower pseudo instructions created during optimization. */
|
/* Lower pseudo instructions created during optimization. */
|
||||||
|
static agx_instr *
|
||||||
static void
|
lower(agx_builder *b, agx_instr *I)
|
||||||
agx_lower_to_unary_bitop(agx_instr *I, enum agx_bitop_table table)
|
|
||||||
{
|
{
|
||||||
I->op = AGX_OPCODE_BITOP;
|
switch (I->op) {
|
||||||
I->truth_table = table;
|
|
||||||
|
|
||||||
/* Allocate extra source */
|
/* Various instructions are implemented as bitwise truth tables */
|
||||||
I->src = reralloc_array_size(I, I->src, sizeof(agx_index), I->nr_srcs++);
|
case AGX_OPCODE_MOV:
|
||||||
I->src[1] = agx_zero();
|
return agx_bitop_to(b, I->dest[0], I->src[0], agx_zero(), AGX_BITOP_MOV);
|
||||||
|
|
||||||
|
case AGX_OPCODE_NOT:
|
||||||
|
return agx_bitop_to(b, I->dest[0], I->src[0], agx_zero(), AGX_BITOP_NOT);
|
||||||
|
|
||||||
|
case AGX_OPCODE_AND:
|
||||||
|
return agx_bitop_to(b, I->dest[0], I->src[0], I->src[1], AGX_BITOP_AND);
|
||||||
|
|
||||||
|
case AGX_OPCODE_XOR:
|
||||||
|
return agx_bitop_to(b, I->dest[0], I->src[0], I->src[1], AGX_BITOP_XOR);
|
||||||
|
|
||||||
|
case AGX_OPCODE_OR:
|
||||||
|
return agx_bitop_to(b, I->dest[0], I->src[0], I->src[1], AGX_BITOP_OR);
|
||||||
|
|
||||||
|
default: return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
agx_lower_to_binary_bitop(agx_instr *I, enum agx_bitop_table table)
|
|
||||||
{
|
|
||||||
I->op = AGX_OPCODE_BITOP;
|
|
||||||
I->truth_table = table;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
agx_lower_pseudo(agx_context *ctx)
|
agx_lower_pseudo(agx_context *ctx)
|
||||||
{
|
{
|
||||||
agx_foreach_instr_global(ctx, I) {
|
agx_foreach_instr_global_safe(ctx, I) {
|
||||||
switch (I->op) {
|
agx_builder b = agx_init_builder(ctx, agx_before_instr(I));
|
||||||
|
|
||||||
/* Various instructions are implemented as bitwise truth tables */
|
if (lower(&b, I))
|
||||||
case AGX_OPCODE_MOV: agx_lower_to_unary_bitop(I, AGX_BITOP_MOV); break;
|
agx_remove_instruction(I);
|
||||||
case AGX_OPCODE_NOT: agx_lower_to_unary_bitop(I, AGX_BITOP_NOT); break;
|
|
||||||
case AGX_OPCODE_AND: agx_lower_to_binary_bitop(I, AGX_BITOP_AND); break;
|
|
||||||
case AGX_OPCODE_XOR: agx_lower_to_binary_bitop(I, AGX_BITOP_XOR); break;
|
|
||||||
case AGX_OPCODE_OR: agx_lower_to_binary_bitop(I, AGX_BITOP_OR); break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -267,9 +267,6 @@ op("logical_end", _, dests = 0, srcs = 0, can_eliminate = False)
|
|||||||
|
|
||||||
op("combine", _, srcs = VARIABLE)
|
op("combine", _, srcs = VARIABLE)
|
||||||
op("split", _, srcs = 1, dests = 4)
|
op("split", _, srcs = 1, dests = 4)
|
||||||
|
op("phi", _, srcs = VARIABLE)
|
||||||
# Phis are special-cased in the IR as they (uniquely) can take an unbounded
|
|
||||||
# number of source.
|
|
||||||
op("phi", _, srcs = 0)
|
|
||||||
|
|
||||||
op("unit_test", _, dests = 0, srcs = 1, can_eliminate = False)
|
op("unit_test", _, dests = 0, srcs = 1, can_eliminate = False)
|
||||||
|
@@ -58,7 +58,7 @@ agx_test_builder(void *memctx)
|
|||||||
static inline bool
|
static inline bool
|
||||||
agx_instr_equal(agx_instr *A, agx_instr *B)
|
agx_instr_equal(agx_instr *A, agx_instr *B)
|
||||||
{
|
{
|
||||||
unsigned pointers = sizeof(struct list_head) + sizeof(agx_index *);
|
unsigned pointers = sizeof(struct list_head) + sizeof(agx_index *) * 2;
|
||||||
|
|
||||||
if (A->nr_srcs != B->nr_srcs)
|
if (A->nr_srcs != B->nr_srcs)
|
||||||
return false;
|
return false;
|
||||||
@@ -66,6 +66,12 @@ agx_instr_equal(agx_instr *A, agx_instr *B)
|
|||||||
if (memcmp(A->src, B->src, A->nr_srcs * sizeof(agx_index)))
|
if (memcmp(A->src, B->src, A->nr_srcs * sizeof(agx_index)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (A->nr_dests != B->nr_dests)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (memcmp(A->dest, B->dest, A->nr_dests * sizeof(agx_index)))
|
||||||
|
return false;
|
||||||
|
|
||||||
return memcmp((uint8_t *) A + pointers,
|
return memcmp((uint8_t *) A + pointers,
|
||||||
(uint8_t *) B + pointers,
|
(uint8_t *) B + pointers,
|
||||||
sizeof(agx_instr) - pointers) == 0;
|
sizeof(agx_instr) - pointers) == 0;
|
||||||
|
Reference in New Issue
Block a user