ir3: remove OPC_B and brtype from cat0

We currently have a bit of a confusing situation where we have both
opcodes for the different branches (OPC_BR, OPC_BRAA,...) and branch
types which are supposed to be used with OPC_B (BRANCH_PLAIN,
BRANCH_AND,...). However, not every kind of branch has a corresponding
type. For example, getone is represented by OPC_GETONE instead of a
branch type.

This patch proposes to get rid of the branch types and use opcodes
everywhere. I think this makes the representation of branches more
consistent. It also removes the for the encoder to translate branch
types into opcodes.

Signed-off-by: Job Noorman <jnoorman@igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/27411>
This commit is contained in:
Job Noorman
2024-02-01 14:51:17 +01:00
committed by Marge Bot
parent 7a66523124
commit a720eef12d
10 changed files with 57 additions and 123 deletions
+1 -1
View File
@@ -153,8 +153,8 @@ static const struct opc_info {
/* clang-format off */
/* category 0: */
OPC(0, OPC_NOP, nop),
OPC(0, OPC_B, b),
OPC(0, OPC_BR, br),
OPC(0, OPC_BRAC, brac),
OPC(0, OPC_BRAA, braa),
OPC(0, OPC_BRAO, brao),
OPC(0, OPC_BALL, ball),
-11
View File
@@ -59,7 +59,6 @@ void ir3_assert_handler(const char *expr, const char *file, int line,
typedef enum {
/* category 0: */
OPC_NOP = _OPC(0, 0),
OPC_B = _OPC(0, 1),
OPC_JUMP = _OPC(0, 2),
OPC_CALL = _OPC(0, 3),
OPC_RET = _OPC(0, 4),
@@ -525,16 +524,6 @@ regid(int num, int comp)
#define REG_A0 61 /* address register */
#define REG_P0 62 /* predicate register */
typedef enum {
BRANCH_PLAIN = 0, /* br */
BRANCH_OR = 1, /* brao */
BRANCH_AND = 2, /* braa */
BRANCH_CONST = 3, /* brac */
BRANCH_ANY = 4, /* bany */
BRANCH_ALL = 5, /* ball */
BRANCH_X = 6, /* brax ??? */
} brtype_t;
/* With is_bindless_s2en = 1, this determines whether bindless is enabled and
* if so, how to get the (base, index) pair for both sampler and texture.
* There is a single base embedded in the instruction, which is always used
-3
View File
@@ -364,7 +364,6 @@ struct ir3_instruction {
int immed;
struct ir3_block *target;
const char *target_label;
brtype_t brtype;
unsigned idx; /* for brac.N */
} cat0;
struct {
@@ -870,7 +869,6 @@ static inline bool
is_terminator(struct ir3_instruction *instr)
{
switch (instr->opc) {
case OPC_B:
case OPC_BR:
case OPC_JUMP:
case OPC_BANY:
@@ -2336,7 +2334,6 @@ static inline struct ir3_instruction *ir3_##name( \
#define INSTR6NODST(name) __INSTR6((ir3_instruction_flags)0, 0, name, OPC_##name)
/* cat0 instructions: */
INSTR1NODST(B)
INSTR1NODST(BR)
INSTR1NODST(BALL)
INSTR1NODST(BANY)
+1 -1
View File
@@ -103,7 +103,7 @@ count_instruction(struct ir3_instruction *n)
* earlier so we don't have this constraint.
*/
return is_alu(n) ||
(is_flow(n) && (n->opc != OPC_JUMP) && (n->opc != OPC_B));
(is_flow(n) && (n->opc != OPC_JUMP) && (n->opc != OPC_BR));
}
/* Post-RA, we don't have arrays any more, so we have to be a bit careful here
+42 -29
View File
@@ -575,6 +575,21 @@ retarget_jump(struct ir3_instruction *instr, struct ir3_block *new_target)
return false;
}
static bool
is_invertible_branch(struct ir3_instruction *instr)
{
switch (instr->opc) {
case OPC_BR:
case OPC_BRAA:
case OPC_BRAO:
case OPC_BANY:
case OPC_BALL:
return true;
default:
return false;
}
}
static bool
opt_jump(struct ir3 *ir)
{
@@ -625,13 +640,14 @@ opt_jump(struct ir3 *ir)
if (jumps[0]->opc == OPC_JUMP)
jumps[1] = NULL;
else if (jumps[0]->opc != OPC_B || !jumps[1] || jumps[1]->opc != OPC_B)
else if (!is_invertible_branch(jumps[0]) || !jumps[1] ||
!is_invertible_branch(jumps[1])) {
continue;
}
for (unsigned i = 0; i < 2; i++) {
if (!jumps[i])
continue;
struct ir3_block *tblock = jumps[i]->cat0.target;
if (&tblock->node == block->node.next) {
list_delinit(&jumps[i]->node);
@@ -686,6 +702,27 @@ mark_xvergence_points(struct ir3 *ir)
}
}
static void
invert_branch(struct ir3_instruction *branch)
{
switch (branch->opc) {
case OPC_BR:
break;
case OPC_BALL:
branch->opc = OPC_BANY;
break;
case OPC_BANY:
branch->opc = OPC_BALL;
break;
default:
unreachable("can't get here");
}
branch->cat0.inv1 = !branch->cat0.inv1;
branch->cat0.inv2 = !branch->cat0.inv2;
branch->cat0.target = branch->block->successors[1];
}
/* Insert the branch/jump instructions for flow control between blocks.
* Initially this is done naively, without considering if the successor
* block immediately follows the current block (ie. so no jump required),
@@ -725,33 +762,9 @@ block_sched(struct ir3 *ir)
* frequently/always end up being a fall-thru):
*/
br1 = terminator;
br1->opc = OPC_B;
br1->srcs[0]->num = regid(REG_P0, 0);
br1->cat0.inv1 = true;
br1->cat0.target = block->successors[1];
/* "then" branch: */
br2 = ir3_instr_create(block, OPC_B, 0, 1);
ir3_src_create(br2, regid(REG_P0, 0), 0)->def =
terminator->srcs[0]->def;
br2 = ir3_instr_clone(br1);
invert_branch(br1);
br2->cat0.target = block->successors[0];
switch (opc) {
case OPC_B:
case OPC_BR:
br1->cat0.brtype = br2->cat0.brtype = BRANCH_PLAIN;
break;
case OPC_BALL:
br1->cat0.brtype = BRANCH_ANY;
br2->cat0.brtype = BRANCH_ALL;
break;
case OPC_BANY:
br1->cat0.brtype = BRANCH_ALL;
br2->cat0.brtype = BRANCH_ANY;
break;
default:
unreachable("can't get here");
}
}
/* Creating br2 caused it to be moved before the terminator b1, move it
@@ -812,7 +825,7 @@ kill_sched(struct ir3 *ir, struct ir3_shader_variant *so)
if (instr->opc != OPC_KILL)
continue;
struct ir3_instruction *br = ir3_instr_create(block, OPC_B, 0, 1);
struct ir3_instruction *br = ir3_instr_create(block, OPC_BR, 0, 1);
ir3_src_create(br, instr->srcs[0]->num, instr->srcs[0]->flags)->wrmask =
1;
br->cat0.target =
+1 -1
View File
@@ -441,7 +441,7 @@ lower_instr(struct ir3 *ir, struct ir3_block **block, struct ir3_instruction *in
case OPC_BALLOT_MACRO:
case OPC_READ_COND_MACRO:
after_block->reconvergence_point = true;
branch_opc = OPC_B;
branch_opc = OPC_BR;
break;
case OPC_ANY_MACRO:
branch_opc = OPC_BANY;
+7 -7
View File
@@ -855,13 +855,13 @@ cat0_immed: '#' integer { instr->cat0.immed = $2; }
| '#' T_IDENTIFIER { ralloc_steal(instr, (void *)$2); instr->cat0.target_label = $2; }
cat0_instr: T_OP_NOP { new_instr(OPC_NOP); }
| T_OP_BR { new_instr(OPC_B)->cat0.brtype = BRANCH_PLAIN; } cat0_src1 ',' cat0_immed
| T_OP_BRAO { new_instr(OPC_B)->cat0.brtype = BRANCH_OR; } cat0_src1 ',' cat0_src2 ',' cat0_immed
| T_OP_BRAA { new_instr(OPC_B)->cat0.brtype = BRANCH_AND; } cat0_src1 ',' cat0_src2 ',' cat0_immed
| T_OP_BRAC '.' integer { new_instr(OPC_B)->cat0.brtype = BRANCH_CONST; instr->cat0.idx = $3; } cat0_immed
| T_OP_BANY { new_instr(OPC_B)->cat0.brtype = BRANCH_ANY; } cat0_src1 ',' cat0_immed
| T_OP_BALL { new_instr(OPC_B)->cat0.brtype = BRANCH_ALL; } cat0_src1 ',' cat0_immed
| T_OP_BRAX { new_instr(OPC_B)->cat0.brtype = BRANCH_X; } cat0_immed
| T_OP_BR { new_instr(OPC_BR); } cat0_src1 ',' cat0_immed
| T_OP_BRAO { new_instr(OPC_BRAO); } cat0_src1 ',' cat0_src2 ',' cat0_immed
| T_OP_BRAA { new_instr(OPC_BRAA); } cat0_src1 ',' cat0_src2 ',' cat0_immed
| T_OP_BRAC '.' integer { new_instr(OPC_BRAC)->cat0.idx = $3; } cat0_immed
| T_OP_BANY { new_instr(OPC_BANY); } cat0_src1 ',' cat0_immed
| T_OP_BALL { new_instr(OPC_BALL); } cat0_src1 ',' cat0_immed
| T_OP_BRAX { new_instr(OPC_BRAX); } cat0_immed
| T_OP_JUMP { new_instr(OPC_JUMP); } cat0_immed
| T_OP_CALL { new_instr(OPC_CALL); } cat0_immed
| T_OP_RET { new_instr(OPC_RET); }
-2
View File
@@ -669,8 +669,6 @@ sched_block(struct ir3_postsched_ctx *ctx, struct ir3_block *block)
foreach_instr_safe (instr, &ctx->unscheduled_list) {
switch (instr->opc) {
case OPC_NOP:
case OPC_B:
case OPC_JUMP:
list_delinit(&instr->node);
break;
default:
+4 -50
View File
@@ -188,19 +188,6 @@ print_instr_name(struct log_stream *stream, struct ir3_instruction *instr,
type_name(instr->cat1.src_type),
type_name(instr->cat1.dst_type));
}
} else if (instr->opc == OPC_B) {
const char *name[8] = {
/* clang-format off */
[BRANCH_PLAIN] = "br",
[BRANCH_OR] = "brao",
[BRANCH_AND] = "braa",
[BRANCH_CONST] = "brac",
[BRANCH_ANY] = "bany",
[BRANCH_ALL] = "ball",
[BRANCH_X] = "brax",
/* clang-format on */
};
mesa_log_stream_printf(stream, "%s", name[instr->cat0.brtype]);
} else {
mesa_log_stream_printf(stream, "%s", disasm_a3xx_instr_name(instr->opc));
if (instr->flags & IR3_INSTR_3D)
@@ -241,6 +228,9 @@ print_instr_name(struct log_stream *stream, struct ir3_instruction *instr,
mesa_log_stream_printf(stream, ".%s",
cond[instr->cat2.condition & 0x7]);
break;
case OPC_BRAC:
mesa_log_stream_printf(stream, ".%u", instr->cat0.idx);
break;
default:
break;
}
@@ -366,8 +356,7 @@ print_instr(struct log_stream *stream, struct ir3_instruction *instr, int lvl)
if (instr->dsts[0]->wrmask & (1 << i))
mesa_log_stream_printf(stream, "%c", "xyzw"[i]);
mesa_log_stream_printf(stream, ")");
} else if ((instr->srcs_count > 0 || instr->dsts_count > 0) &&
(instr->opc != OPC_B)) {
} else if ((instr->srcs_count > 0 || instr->dsts_count > 0)) {
/* NOTE the b(ranch) instruction has a suffix, which is
* handled below
*/
@@ -416,41 +405,6 @@ print_instr(struct log_stream *stream, struct ir3_instruction *instr, int lvl)
}
if (is_flow(instr) && instr->cat0.target) {
/* the predicate register src is implied: */
if (instr->opc == OPC_B) {
static const struct {
int nsrc;
bool idx;
} brinfo[7] = {
/* clang-format off */
[BRANCH_PLAIN] = {1, false},
[BRANCH_OR] = {2, false},
[BRANCH_AND] = {2, false},
[BRANCH_CONST] = {0, true},
[BRANCH_ANY] = {1, false},
[BRANCH_ALL] = {1, false},
[BRANCH_X] = {0, false},
/* clang-format on */
};
if (brinfo[instr->cat0.brtype].idx) {
mesa_log_stream_printf(stream, ".%u", instr->cat0.idx);
}
if (brinfo[instr->cat0.brtype].nsrc >= 1) {
mesa_log_stream_printf(stream, " %sp0.%c (",
instr->cat0.inv1 ? "!" : "",
"xyzw"[instr->cat0.comp1 & 0x3]);
print_reg_name(stream, instr, instr->srcs[0], false);
mesa_log_stream_printf(stream, "), ");
}
if (brinfo[instr->cat0.brtype].nsrc >= 2) {
mesa_log_stream_printf(stream, " %sp0.%c (",
instr->cat0.inv2 ? "!" : "",
"xyzw"[instr->cat0.comp2 & 0x3]);
print_reg_name(stream, instr, instr->srcs[1], false);
mesa_log_stream_printf(stream, "), ");
}
}
mesa_log_stream_printf(stream, " target=block%u",
block_id(instr->cat0.target));
}
+1 -18
View File
@@ -82,24 +82,7 @@ __instruction_case(struct encode_state *s, struct ir3_instruction *instr)
* decoding and split up things which are logically different
* instructions
*/
if (instr->opc == OPC_B) {
switch (instr->cat0.brtype) {
case BRANCH_PLAIN:
return OPC_BR;
case BRANCH_OR:
return OPC_BRAO;
case BRANCH_AND:
return OPC_BRAA;
case BRANCH_CONST:
return OPC_BRAC;
case BRANCH_ANY:
return OPC_BANY;
case BRANCH_ALL:
return OPC_BALL;
case BRANCH_X:
return OPC_BRAX;
}
} else if (instr->opc == OPC_MOV) {
if (instr->opc == OPC_MOV) {
struct ir3_register *src = instr->srcs[0];
if (src->flags & IR3_REG_IMMED) {
return OPC_MOV_IMMED;