diff --git a/src/freedreno/ir3/ir3.h b/src/freedreno/ir3/ir3.h index 9f9c0477d5d..a742af06253 100644 --- a/src/freedreno/ir3/ir3.h +++ b/src/freedreno/ir3/ir3.h @@ -514,6 +514,13 @@ struct ir3_array { struct ir3_array * ir3_lookup_array(struct ir3 *ir, unsigned id); +enum ir3_branch_type { + IR3_BRANCH_COND, /* condition */ + IR3_BRANCH_ANY, /* subgroupAny(condition) */ + IR3_BRANCH_ALL, /* subgroupAll(condition) */ + IR3_BRANCH_GETONE, /* subgroupElect() */ +}; + struct ir3_block { struct list_head node; struct ir3 *shader; @@ -522,6 +529,9 @@ struct ir3_block { struct list_head instr_list; /* list of ir3_instruction */ + /* The actual branch condition, if there are two successors */ + enum ir3_branch_type brtype; + /* each block has either one or two successors.. in case of two * successors, 'condition' decides which one to follow. A block preceding * an if/else has two successors. @@ -1840,6 +1850,7 @@ INSTR0(CHMASK) INSTR1NODST(PREDT) INSTR0(PREDF) INSTR0(PREDE) +INSTR0(GETONE) /* cat2 instructions, most 2 src but some 1 src: */ INSTR2(ADD_F) diff --git a/src/freedreno/ir3/ir3_legalize.c b/src/freedreno/ir3/ir3_legalize.c index 6aa26096556..912fc3c878d 100644 --- a/src/freedreno/ir3/ir3_legalize.c +++ b/src/freedreno/ir3/ir3_legalize.c @@ -643,23 +643,51 @@ block_sched(struct ir3 *ir) foreach_block (block, &ir->block_list) { if (block->successors[1]) { /* if/else, conditional branches to "then" or "else": */ - struct ir3_instruction *br; + struct ir3_instruction *br1, *br2; - debug_assert(block->condition); + if (block->brtype == IR3_BRANCH_GETONE) { + /* getone can't be inverted, and it wouldn't even make sense + * to follow it with an inverted branch, so follow it by an + * unconditional branch. + */ + debug_assert(!block->condition); + br1 = ir3_GETONE(block); + br1->cat0.target = block->successors[1]; - /* create "else" branch first (since "then" block should - * frequently/always end up being a fall-thru): - */ - br = ir3_instr_create(block, OPC_B, 0, 1); - ir3_src_create(br, regid(REG_P0, 0), 0)->def = block->condition->dsts[0]; - br->cat0.inv1 = true; - br->cat0.target = block->successors[1]; + br2 = ir3_JUMP(block); + br2->cat0.target = block->successors[0]; + } else { + debug_assert(block->condition); - /* "then" branch: */ - br = ir3_instr_create(block, OPC_B, 0, 1); - ir3_src_create(br, regid(REG_P0, 0), 0)->def = block->condition->dsts[0]; - br->cat0.target = block->successors[0]; + /* create "else" branch first (since "then" block should + * frequently/always end up being a fall-thru): + */ + br1 = ir3_instr_create(block, OPC_B, 0, 1); + ir3_src_create(br1, regid(REG_P0, 0), 0)->def = block->condition->dsts[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 = block->condition->dsts[0]; + br2->cat0.target = block->successors[0]; + + switch (block->brtype) { + case IR3_BRANCH_COND: + br1->cat0.brtype = br2->cat0.brtype = BRANCH_PLAIN; + break; + case IR3_BRANCH_ALL: + br1->cat0.brtype = BRANCH_ANY; + br2->cat0.brtype = BRANCH_ALL; + break; + case IR3_BRANCH_ANY: + br1->cat0.brtype = BRANCH_ALL; + br2->cat0.brtype = BRANCH_ANY; + break; + case IR3_BRANCH_GETONE: + unreachable("can't get here"); + } + } } else if (block->successors[0]) { /* otherwise unconditional jump to next block: */ struct ir3_instruction *jmp; diff --git a/src/freedreno/ir3/ir3_print.c b/src/freedreno/ir3/ir3_print.c index f6ce0c8f39a..917a7f44fe3 100644 --- a/src/freedreno/ir3/ir3_print.c +++ b/src/freedreno/ir3/ir3_print.c @@ -123,6 +123,17 @@ static void print_instr_name(struct log_stream *stream, struct ir3_instruction * mesa_log_stream_printf(stream, ".%s%s", type_name(instr->cat1.src_type), type_name(instr->cat1.dst_type)); } + } else if (instr->opc == OPC_B) { + const char *name[8] = { + [BRANCH_PLAIN] = "br", + [BRANCH_OR] = "brao", + [BRANCH_AND] = "braa", + [BRANCH_CONST] = "brac", + [BRANCH_ANY] = "bany", + [BRANCH_ALL] = "ball", + [BRANCH_X] = "brax", + }; + 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) @@ -411,8 +422,23 @@ print_block(struct ir3_block *block, int lvl) if (block->successors[1]) { /* leading into if/else: */ tab(stream, lvl+1); - mesa_log_stream_printf(stream, "/* succs: if "SYN_SSA("ssa_%u")" block%u; else block%u */\n", - block->condition->serialno, + mesa_log_stream_printf(stream, "/* succs: if "); + switch (block->brtype) { + case IR3_BRANCH_COND: + break; + case IR3_BRANCH_ANY: + printf("any "); + break; + case IR3_BRANCH_ALL: + printf("all "); + break; + case IR3_BRANCH_GETONE: + printf("getone "); + break; + } + if (block->condition) + mesa_log_stream_printf(stream, SYN_SSA("ssa_%u")" ", block->condition->serialno); + mesa_log_stream_printf(stream, "block%u; else block%u; */\n", block_id(block->successors[0]), block_id(block->successors[1])); } else if (block->successors[0]) {