From 97b21110b8b845bb02596036bdbf9e9562cfa7a5 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Fri, 1 May 2020 14:37:27 -0700 Subject: [PATCH] freedreno/ir3: Sync some new changes from envytools. With this I also brought in a few new control flow instruction disasm tests that I'd made back when I wrote the disasm test, but which were too far from correct to include until now. Part-of: --- src/freedreno/ir3/disasm-a3xx.c | 65 ++++++++++++++++++++++------ src/freedreno/ir3/instr-a3xx.h | 43 ++++++++++++++---- src/freedreno/ir3/ir3.c | 15 ++----- src/freedreno/ir3/ir3.h | 8 ++-- src/freedreno/ir3/ir3_compiler_nir.c | 4 +- src/freedreno/ir3/ir3_delay.c | 2 +- src/freedreno/ir3/ir3_legalize.c | 8 ++-- src/freedreno/ir3/ir3_parser.y | 2 +- src/freedreno/ir3/ir3_postsched.c | 2 +- src/freedreno/ir3/ir3_print.c | 4 +- src/freedreno/ir3/tests/disasm.c | 3 ++ 11 files changed, 107 insertions(+), 49 deletions(-) diff --git a/src/freedreno/ir3/disasm-a3xx.c b/src/freedreno/ir3/disasm-a3xx.c index 54ed027f55c..697219ce405 100644 --- a/src/freedreno/ir3/disasm-a3xx.c +++ b/src/freedreno/ir3/disasm-a3xx.c @@ -203,26 +203,54 @@ static void print_src(struct disasm_ctx *ctx, struct reginfo *info) static void print_instr_cat0(struct disasm_ctx *ctx, instr_t *instr) { + static const struct { + const char *suffix; + int nsrc; + bool idx; + } brinfo[7] = { + [BRANCH_PLAIN] = { "r", 1, false }, + [BRANCH_OR] = { "rao", 2, false }, + [BRANCH_AND] = { "raa", 2, false }, + [BRANCH_CONST] = { "rac", 0, true }, + [BRANCH_ANY] = { "any", 1, false }, + [BRANCH_ALL] = { "all", 1, false }, + [BRANCH_X] = { "rax", 0, false }, + }; instr_cat0_t *cat0 = &instr->cat0; - switch (cat0->opc) { + switch (instr_opc(instr, ctx->gpu_id)) { case OPC_KILL: - case OPC_IF: - fprintf(ctx->out, " %sp0.%c", cat0->inv ? "!" : "", - component[cat0->comp]); + case OPC_PREDT: + case OPC_PREDF: + fprintf(ctx->out, " %sp0.%c", cat0->inv0 ? "!" : "", + component[cat0->comp0]); break; - case OPC_BR: - fprintf(ctx->out, " %sp0.%c, #%d", cat0->inv ? "!" : "", - component[cat0->comp], cat0->a3xx.immed); + case OPC_B: + fprintf(ctx->out, "%s", brinfo[cat0->brtype].suffix); + if (brinfo[cat0->brtype].idx) { + fprintf(ctx->out, ".%u", cat0->idx); + } + if (brinfo[cat0->brtype].nsrc >= 1) { + fprintf(ctx->out, " %sp0.%c,", cat0->inv0 ? "!" : "", + component[cat0->comp0]); + } + if (brinfo[cat0->brtype].nsrc >= 2) { + fprintf(ctx->out, " %sp0.%c,", cat0->inv1 ? "!" : "", + component[cat0->comp1]); + } + fprintf(ctx->out, " #%d", cat0->a3xx.immed); break; case OPC_JUMP: case OPC_CALL: + case OPC_BKT: + case OPC_GETONE: + case OPC_SHPS: fprintf(ctx->out, " #%d", cat0->a3xx.immed); break; } - if ((debug & PRINT_VERBOSE) && (cat0->dummy2|cat0->dummy3|cat0->dummy4)) - fprintf(ctx->out, "\t{0: %x,%x,%x}", cat0->dummy2, cat0->dummy3, cat0->dummy4); + if ((debug & PRINT_VERBOSE) && (cat0->dummy3|cat0->dummy4)) + fprintf(ctx->out, "\t{0: %x,%x}", cat0->dummy3, cat0->dummy4); } static void print_instr_cat1(struct disasm_ctx *ctx, instr_t *instr) @@ -1065,7 +1093,7 @@ static const struct opc_info { #define OPC(cat, opc, name) [(opc)] = { (cat), (opc), #name, print_instr_cat##cat } /* category 0: */ OPC(0, OPC_NOP, nop), - OPC(0, OPC_BR, br), + OPC(0, OPC_B, b), OPC(0, OPC_JUMP, jump), OPC(0, OPC_CALL, call), OPC(0, OPC_RET, ret), @@ -1076,9 +1104,18 @@ static const struct opc_info { OPC(0, OPC_CHMASK, chmask), OPC(0, OPC_CHSH, chsh), OPC(0, OPC_FLOW_REV, flow_rev), - OPC(0, OPC_IF, if), - OPC(0, OPC_ELSE, else), - OPC(0, OPC_ENDIF, endif), + OPC(0, OPC_PREDT, predt), + OPC(0, OPC_PREDF, predf), + OPC(0, OPC_PREDE, prede), + OPC(0, OPC_BKT, bkt), + OPC(0, OPC_STKS, stks), + OPC(0, OPC_STKR, stkr), + OPC(0, OPC_XSET, xset), + OPC(0, OPC_XCLR, xclr), + OPC(0, OPC_GETONE, getone), + OPC(0, OPC_DBG, dbg), + OPC(0, OPC_SHPS, shps), + OPC(0, OPC_SHPE, shpe), /* category 1: */ OPC(1, OPC_MOV, ), @@ -1292,6 +1329,8 @@ static bool print_instr(struct disasm_ctx *ctx, uint32_t *dwords, int n) } if (instr->jmp_tgt) fprintf(ctx->out, "(jp)"); + if ((instr->opc_cat == 0) && instr->cat0.eq) + fprintf(ctx->out, "(eq)"); if (instr_sat(instr)) fprintf(ctx->out, "(sat)"); if (ctx->repeat) diff --git a/src/freedreno/ir3/instr-a3xx.h b/src/freedreno/ir3/instr-a3xx.h index 565b296739f..23b21eb653d 100644 --- a/src/freedreno/ir3/instr-a3xx.h +++ b/src/freedreno/ir3/instr-a3xx.h @@ -39,7 +39,7 @@ typedef enum { /* category 0: */ OPC_NOP = _OPC(0, 0), - OPC_BR = _OPC(0, 1), + OPC_B = _OPC(0, 1), OPC_JUMP = _OPC(0, 2), OPC_CALL = _OPC(0, 3), OPC_RET = _OPC(0, 4), @@ -51,9 +51,19 @@ typedef enum { OPC_CHSH = _OPC(0, 10), OPC_FLOW_REV = _OPC(0, 11), - OPC_IF = _OPC(0, 13), - OPC_ELSE = _OPC(0, 14), - OPC_ENDIF = _OPC(0, 15), + OPC_BKT = _OPC(0, 16), + OPC_STKS = _OPC(0, 17), + OPC_STKR = _OPC(0, 18), + OPC_XSET = _OPC(0, 19), + OPC_XCLR = _OPC(0, 20), + OPC_GETONE = _OPC(0, 21), + OPC_DBG = _OPC(0, 22), + OPC_SHPS = _OPC(0, 23), /* shader prologue start */ + OPC_SHPE = _OPC(0, 24), /* shader prologue end */ + + OPC_PREDT = _OPC(0, 29), /* predicated true */ + OPC_PREDF = _OPC(0, 30), /* predicated false */ + OPC_PREDE = _OPC(0, 31), /* predicated end */ /* category 1: */ OPC_MOV = _OPC(1, 0), @@ -311,6 +321,16 @@ static inline int reg_special(reg_t reg) return (reg.num == REG_A0) || (reg.num == REG_P0); } +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; + typedef struct PACKED { /* dword0: */ union PACKED { @@ -328,13 +348,18 @@ typedef struct PACKED { }; /* dword1: */ - uint32_t dummy2 : 8; + uint32_t idx : 5; /* brac.N index */ + uint32_t brtype : 3; /* branch type, see brtype_t */ uint32_t repeat : 3; uint32_t dummy3 : 1; uint32_t ss : 1; - uint32_t dummy4 : 7; - uint32_t inv : 1; - uint32_t comp : 2; + uint32_t inv1 : 1; + uint32_t comp1 : 2; + uint32_t eq : 1; + uint32_t opc_hi : 1; /* at least one bit */ + uint32_t dummy4 : 2; + uint32_t inv0 : 1; + uint32_t comp0 : 2; /* component for first src */ uint32_t opc : 4; uint32_t jmp_tgt : 1; uint32_t sync : 1; @@ -963,7 +988,7 @@ static inline bool is_cat6_legacy(instr_t *instr, unsigned gpu_id) static inline uint32_t instr_opc(instr_t *instr, unsigned gpu_id) { switch (instr->opc_cat) { - case 0: return instr->cat0.opc; + case 0: return instr->cat0.opc | instr->cat0.opc_hi << 4; case 1: return 0; case 2: return instr->cat2.opc; case 3: return instr->cat3.opc; diff --git a/src/freedreno/ir3/ir3.c b/src/freedreno/ir3/ir3.c index cb7418bf2e0..8c30bf98298 100644 --- a/src/freedreno/ir3/ir3.c +++ b/src/freedreno/ir3/ir3.c @@ -141,23 +141,14 @@ static int emit_cat0(struct ir3_instruction *instr, void *ptr, } cat0->repeat = instr->repeat; cat0->ss = !!(instr->flags & IR3_INSTR_SS); - cat0->inv = instr->cat0.inv; - cat0->comp = instr->cat0.comp; + cat0->inv0 = instr->cat0.inv; + cat0->comp0 = instr->cat0.comp; cat0->opc = instr->opc; + cat0->opc_hi = instr->opc >= 16; cat0->jmp_tgt = !!(instr->flags & IR3_INSTR_JP); cat0->sync = !!(instr->flags & IR3_INSTR_SY); cat0->opc_cat = 0; - switch (instr->opc) { - case OPC_IF: - case OPC_ELSE: - case OPC_ENDIF: - cat0->dummy4 = 16; - break; - default: - break; - } - return 0; } diff --git a/src/freedreno/ir3/ir3.h b/src/freedreno/ir3/ir3.h index 0f3bb54f316..4e7550f5e8d 100644 --- a/src/freedreno/ir3/ir3.h +++ b/src/freedreno/ir3/ir3.h @@ -1423,15 +1423,15 @@ ir3_##name(struct ir3_block *block, \ #define INSTR4(name) __INSTR4(0, name, OPC_##name) /* cat0 instructions: */ -INSTR1(BR) +INSTR1(B) INSTR0(JUMP) INSTR1(KILL) INSTR0(END) INSTR0(CHSH) INSTR0(CHMASK) -INSTR1(IF) -INSTR0(ELSE) -INSTR0(ENDIF) +INSTR1(PREDT) +INSTR0(PREDF) +INSTR0(PREDE) /* cat2 instructions, most 2 src but some 1 src: */ INSTR2(ADD_F) diff --git a/src/freedreno/ir3/ir3_compiler_nir.c b/src/freedreno/ir3/ir3_compiler_nir.c index bd65f91e780..b3d0556a03e 100644 --- a/src/freedreno/ir3/ir3_compiler_nir.c +++ b/src/freedreno/ir3/ir3_compiler_nir.c @@ -1536,7 +1536,7 @@ emit_intrinsic(struct ir3_context *ctx, nir_intrinsic_instr *intr) case nir_intrinsic_end_patch_ir3: assert(ctx->so->type == MESA_SHADER_TESS_CTRL); - struct ir3_instruction *end = ir3_ENDIF(b); + struct ir3_instruction *end = ir3_PREDE(b); array_insert(b, b->keeps, end); end->barrier_class = IR3_BARRIER_EVERYTHING; @@ -1933,7 +1933,7 @@ emit_intrinsic(struct ir3_context *ctx, nir_intrinsic_instr *intr) /* condition always goes in predicate register: */ cond->regs[0]->num = regid(REG_P0, 0); - kill = ir3_IF(b, cond, 0); + kill = ir3_PREDT(b, cond, 0); kill->barrier_class = IR3_BARRIER_EVERYTHING; kill->barrier_conflict = IR3_BARRIER_EVERYTHING; diff --git a/src/freedreno/ir3/ir3_delay.c b/src/freedreno/ir3/ir3_delay.c index 3fc4d911f14..15434fdedd1 100644 --- a/src/freedreno/ir3/ir3_delay.c +++ b/src/freedreno/ir3/ir3_delay.c @@ -123,7 +123,7 @@ count_instruction(struct ir3_instruction *n) * be eliminated later in resolve_jumps().. really should do that * earlier so we don't have this constraint. */ - return is_alu(n) || (is_flow(n) && (n->opc != OPC_JUMP) && (n->opc != OPC_BR)); + return is_alu(n) || (is_flow(n) && (n->opc != OPC_JUMP) && (n->opc != OPC_B)); } /** diff --git a/src/freedreno/ir3/ir3_legalize.c b/src/freedreno/ir3/ir3_legalize.c index d0b0dd83b46..2b1f3b94d8b 100644 --- a/src/freedreno/ir3/ir3_legalize.c +++ b/src/freedreno/ir3/ir3_legalize.c @@ -138,7 +138,7 @@ legalize_block(struct ir3_legalize_ctx *ctx, struct ir3_block *block) regmask_init(&state->needs_sy); } - if (last_n && (last_n->opc == OPC_IF)) { + if (last_n && (last_n->opc == OPC_PREDT)) { n->flags |= IR3_INSTR_SS; regmask_init(&state->needs_ss_war); regmask_init(&state->needs_ss); @@ -574,12 +574,12 @@ block_sched(struct ir3 *ir) /* create "else" branch first (since "then" block should * frequently/always end up being a fall-thru): */ - br = ir3_BR(block, block->condition, 0); + br = ir3_B(block, block->condition, 0); br->cat0.inv = true; br->cat0.target = block->successors[1]; /* "then" branch: */ - br = ir3_BR(block, block->condition, 0); + br = ir3_B(block, block->condition, 0); br->cat0.target = block->successors[0]; } else if (block->successors[0]) { @@ -633,7 +633,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_BR); + struct ir3_instruction *br = ir3_instr_create(block, OPC_B); br->regs[1] = instr->regs[1]; br->cat0.target = list_last_entry(&ir->block_list, struct ir3_block, node); diff --git a/src/freedreno/ir3/ir3_parser.y b/src/freedreno/ir3/ir3_parser.y index c9cede4b725..08779380b12 100644 --- a/src/freedreno/ir3/ir3_parser.y +++ b/src/freedreno/ir3/ir3_parser.y @@ -596,7 +596,7 @@ cat0_src: '!' T_P0 { instr->cat0.inv = true; instr->cat0.comp = cat0_immed: '#' integer { instr->cat0.immed = $2; } cat0_instr: T_OP_NOP { new_instr(OPC_NOP); } -| T_OP_BR { new_instr(OPC_BR); } cat0_src ',' cat0_immed +| T_OP_BR { new_instr(OPC_B); } cat0_src ',' 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 521078a04c9..496c1d211b8 100644 --- a/src/freedreno/ir3/ir3_postsched.c +++ b/src/freedreno/ir3/ir3_postsched.c @@ -582,7 +582,7 @@ 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_BR: + case OPC_B: case OPC_JUMP: list_delinit(&instr->node); break; diff --git a/src/freedreno/ir3/ir3_print.c b/src/freedreno/ir3/ir3_print.c index 1b6908edefb..034bcd8248e 100644 --- a/src/freedreno/ir3/ir3_print.c +++ b/src/freedreno/ir3/ir3_print.c @@ -264,8 +264,8 @@ print_instr(struct ir3_instruction *instr, int lvl) if (is_flow(instr) && instr->cat0.target) { /* the predicate register src is implied: */ - if (instr->opc == OPC_BR) { - printf(" %sp0.x", instr->cat0.inv ? "!" : ""); + if (instr->opc == OPC_B) { + printf("r %sp0.x", instr->cat0.inv ? "!" : ""); } printf(", target=block%u", block_id(instr->cat0.target)); } diff --git a/src/freedreno/ir3/tests/disasm.c b/src/freedreno/ir3/tests/disasm.c index 81916c69e5a..ba6af205834 100644 --- a/src/freedreno/ir3/tests/disasm.c +++ b/src/freedreno/ir3/tests/disasm.c @@ -41,6 +41,9 @@ static const struct test { INSTR_6XX(03000000_00000000, "end"), INSTR_6XX(00800000_00000004, "br p0.x, #4"), INSTR_6XX(00900000_00000003, "br !p0.x, #3"), + INSTR_6XX(03820000_00000015, "shps #21"), /* emit */ + INSTR_6XX(04021000_00000000, "(ss)shpe"), /* cut */ + INSTR_6XX(02820000_00000014, "getone #20"), /* kill p0.x */ /* cat1 */ INSTR_6XX(20244000_00000020, "mov.f32f32 r0.x, c8.x"), -- 2.30.2