diff --git a/src/freedreno/ir3/disasm-a3xx.c b/src/freedreno/ir3/disasm-a3xx.c index 6a48d503cca..d5c7c915073 100644 --- a/src/freedreno/ir3/disasm-a3xx.c +++ b/src/freedreno/ir3/disasm-a3xx.c @@ -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), diff --git a/src/freedreno/ir3/instr-a3xx.h b/src/freedreno/ir3/instr-a3xx.h index 8ea35524a8b..e17ace592d9 100644 --- a/src/freedreno/ir3/instr-a3xx.h +++ b/src/freedreno/ir3/instr-a3xx.h @@ -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 diff --git a/src/freedreno/ir3/ir3.h b/src/freedreno/ir3/ir3.h index 0c99f068abc..141036f5d85 100644 --- a/src/freedreno/ir3/ir3.h +++ b/src/freedreno/ir3/ir3.h @@ -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) diff --git a/src/freedreno/ir3/ir3_delay.c b/src/freedreno/ir3/ir3_delay.c index 054f4c831c6..a6a8ff70b69 100644 --- a/src/freedreno/ir3/ir3_delay.c +++ b/src/freedreno/ir3/ir3_delay.c @@ -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 diff --git a/src/freedreno/ir3/ir3_legalize.c b/src/freedreno/ir3/ir3_legalize.c index 9365d957f37..e9ad732eadb 100644 --- a/src/freedreno/ir3/ir3_legalize.c +++ b/src/freedreno/ir3/ir3_legalize.c @@ -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 = diff --git a/src/freedreno/ir3/ir3_lower_subgroups.c b/src/freedreno/ir3/ir3_lower_subgroups.c index 57680e9c646..d949ed536a2 100644 --- a/src/freedreno/ir3/ir3_lower_subgroups.c +++ b/src/freedreno/ir3/ir3_lower_subgroups.c @@ -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; diff --git a/src/freedreno/ir3/ir3_parser.y b/src/freedreno/ir3/ir3_parser.y index 4a09bc90a37..3a18f8674d9 100644 --- a/src/freedreno/ir3/ir3_parser.y +++ b/src/freedreno/ir3/ir3_parser.y @@ -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); } diff --git a/src/freedreno/ir3/ir3_postsched.c b/src/freedreno/ir3/ir3_postsched.c index 4213af11331..d642d559f4b 100644 --- a/src/freedreno/ir3/ir3_postsched.c +++ b/src/freedreno/ir3/ir3_postsched.c @@ -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: diff --git a/src/freedreno/ir3/ir3_print.c b/src/freedreno/ir3/ir3_print.c index 0890a8543cd..bd5d0cf0452 100644 --- a/src/freedreno/ir3/ir3_print.c +++ b/src/freedreno/ir3/ir3_print.c @@ -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)); } diff --git a/src/freedreno/isa/encode.c b/src/freedreno/isa/encode.c index 5e9bd34372f..025798577bb 100644 --- a/src/freedreno/isa/encode.c +++ b/src/freedreno/isa/encode.c @@ -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;