From 4a42a5058564a1d862e29eee80925ecd8b0ed1a2 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Fri, 24 Apr 2020 11:45:31 -0700 Subject: [PATCH] freedreno/ir3: Add support for disasm of cat2 float32 immediates. Part-of: --- src/freedreno/ir3/disasm-a3xx.c | 36 +++++++++++++++++++++++++------ src/freedreno/ir3/instr-a3xx.h | 37 ++++++++++++++++++++++++++++++++ src/freedreno/ir3/ir3.h | 36 ------------------------------- src/freedreno/ir3/ir3_cp.c | 10 ++++----- src/freedreno/ir3/tests/disasm.c | 14 ++++++++++++ 5 files changed, 86 insertions(+), 47 deletions(-) diff --git a/src/freedreno/ir3/disasm-a3xx.c b/src/freedreno/ir3/disasm-a3xx.c index 8d4604fa714..54ed027f55c 100644 --- a/src/freedreno/ir3/disasm-a3xx.c +++ b/src/freedreno/ir3/disasm-a3xx.c @@ -88,7 +88,23 @@ struct disasm_ctx { unsigned instructions; }; -static void print_reg(struct disasm_ctx *ctx, reg_t reg, bool full, bool r, +static const char *float_imms[] = { + "0.0", + "0.5", + "1.0", + "2.0", + "e", + "pi", + "1/pi", + "1/log2(e)", + "log2(e)", + "1/log2(10)", + "log2(10)", + "4.0", +}; + +static void print_reg(struct disasm_ctx *ctx, reg_t reg, bool full, + bool is_float, bool r, bool c, bool im, bool neg, bool abs, bool addr_rel) { const char type = c ? 'c' : 'r'; @@ -107,7 +123,11 @@ static void print_reg(struct disasm_ctx *ctx, reg_t reg, bool full, bool r, fprintf(ctx->out, "(r)"); if (im) { - fprintf(ctx->out, "%d", reg.iim_val); + if (is_float && full && reg.iim_val < ARRAY_SIZE(float_imms)) { + fprintf(ctx->out, "(%s)", float_imms[reg.iim_val]); + } else { + fprintf(ctx->out, "%d", reg.iim_val); + } } else if (addr_rel) { /* I would just use %+d but trying to make it diff'able with * libllvm-a3xx... @@ -146,7 +166,7 @@ static reg_t idxreg(unsigned idx) static void print_reg_dst(struct disasm_ctx *ctx, reg_t reg, bool full, bool addr_rel) { reg = idxreg(regidx(reg) + ctx->repeatidx); - print_reg(ctx, reg, full, false, false, false, false, false, addr_rel); + print_reg(ctx, reg, full, false, false, false, false, false, false, addr_rel); } /* TODO switch to using reginfo struct everywhere, since more readable @@ -158,6 +178,7 @@ struct reginfo { bool full; bool r; bool c; + bool f; /* src reg is interpreted as float, used for printing immediates */ bool im; bool neg; bool abs; @@ -171,7 +192,7 @@ static void print_src(struct disasm_ctx *ctx, struct reginfo *info) if (info->r) reg = idxreg(regidx(info->reg) + ctx->repeatidx); - print_reg(ctx, reg, info->full, info->r, info->c, info->im, + print_reg(ctx, reg, info->full, info->f, info->r, info->c, info->im, info->neg, info->abs, info->addr_rel); } @@ -273,6 +294,7 @@ static void print_instr_cat1(struct disasm_ctx *ctx, instr_t *instr) static void print_instr_cat2(struct disasm_ctx *ctx, instr_t *instr) { instr_cat2_t *cat2 = &instr->cat2; + int opc = _OPC(2, cat2->opc); static const char *cond[] = { "lt", "le", @@ -283,7 +305,7 @@ static void print_instr_cat2(struct disasm_ctx *ctx, instr_t *instr) "?6?", }; - switch (_OPC(2, cat2->opc)) { + switch (opc) { case OPC_CMPS_F: case OPC_CMPS_U: case OPC_CMPS_S: @@ -303,6 +325,7 @@ static void print_instr_cat2(struct disasm_ctx *ctx, instr_t *instr) struct reginfo src1 = { .full = cat2->full, .r = cat2->repeat ? cat2->src1_r : 0, + .f = is_cat2_float(opc), .im = cat2->src1_im, .abs = cat2->src1_abs, .neg = cat2->src1_neg, @@ -323,11 +346,12 @@ static void print_instr_cat2(struct disasm_ctx *ctx, instr_t *instr) struct reginfo src2 = { .r = cat2->repeat ? cat2->src2_r : 0, .full = cat2->full, + .f = is_cat2_float(opc), .abs = cat2->src2_abs, .neg = cat2->src2_neg, .im = cat2->src2_im, }; - switch (_OPC(2, cat2->opc)) { + switch (opc) { case OPC_ABSNEG_F: case OPC_ABSNEG_S: case OPC_CLZ_B: diff --git a/src/freedreno/ir3/instr-a3xx.h b/src/freedreno/ir3/instr-a3xx.h index f36c73b88e2..565b296739f 100644 --- a/src/freedreno/ir3/instr-a3xx.h +++ b/src/freedreno/ir3/instr-a3xx.h @@ -1050,6 +1050,43 @@ static inline bool is_isam(opc_t opc) } } + +static inline bool is_cat2_float(opc_t opc) +{ + switch (opc) { + case OPC_ADD_F: + case OPC_MIN_F: + case OPC_MAX_F: + case OPC_MUL_F: + case OPC_SIGN_F: + case OPC_CMPS_F: + case OPC_ABSNEG_F: + case OPC_CMPV_F: + case OPC_FLOOR_F: + case OPC_CEIL_F: + case OPC_RNDNE_F: + case OPC_RNDAZ_F: + case OPC_TRUNC_F: + return true; + + default: + return false; + } +} + +static inline bool is_cat3_float(opc_t opc) +{ + switch (opc) { + case OPC_MAD_F16: + case OPC_MAD_F32: + case OPC_SEL_F16: + case OPC_SEL_F32: + return true; + default: + return false; + } +} + int disasm_a3xx(uint32_t *dwords, int sizedwords, int level, FILE *out, unsigned gpu_id); #endif /* INSTR_A3XX_H_ */ diff --git a/src/freedreno/ir3/ir3.h b/src/freedreno/ir3/ir3.h index 44175888200..0f3bb54f316 100644 --- a/src/freedreno/ir3/ir3.h +++ b/src/freedreno/ir3/ir3.h @@ -957,42 +957,6 @@ static inline bool ir3_cat2_int(opc_t opc) } } -static inline bool ir3_cat2_float(opc_t opc) -{ - switch (opc) { - case OPC_ADD_F: - case OPC_MIN_F: - case OPC_MAX_F: - case OPC_MUL_F: - case OPC_SIGN_F: - case OPC_CMPS_F: - case OPC_ABSNEG_F: - case OPC_CMPV_F: - case OPC_FLOOR_F: - case OPC_CEIL_F: - case OPC_RNDNE_F: - case OPC_RNDAZ_F: - case OPC_TRUNC_F: - return true; - - default: - return false; - } -} - -static inline bool ir3_cat3_float(opc_t opc) -{ - switch (opc) { - case OPC_MAD_F16: - case OPC_MAD_F32: - case OPC_SEL_F16: - case OPC_SEL_F32: - return true; - default: - return false; - } -} - /* map cat2 instruction to valid abs/neg flags: */ static inline unsigned ir3_cat2_absneg(opc_t opc) { diff --git a/src/freedreno/ir3/ir3_cp.c b/src/freedreno/ir3/ir3_cp.c index 782be12c192..22023b0ac67 100644 --- a/src/freedreno/ir3/ir3_cp.c +++ b/src/freedreno/ir3/ir3_cp.c @@ -478,8 +478,8 @@ reg_cp(struct ir3_cp_ctx *ctx, struct ir3_instruction *instr, if (!valid_flags(instr, n, new_flags)) { /* See if lowering an immediate to const would help. */ if (valid_flags(instr, n, (new_flags & ~IR3_REG_IMMED) | IR3_REG_CONST)) { - bool f_opcode = (ir3_cat2_float(instr->opc) || - ir3_cat3_float(instr->opc)) ? true : false; + bool f_opcode = (is_cat2_float(instr->opc) || + is_cat3_float(instr->opc)) ? true : false; debug_assert(new_flags & IR3_REG_IMMED); @@ -533,7 +533,7 @@ reg_cp(struct ir3_cp_ctx *ctx, struct ir3_instruction *instr, if (src->cat1.dst_type == TYPE_F16) { if (instr->opc == OPC_MOV && !type_float(instr->cat1.src_type)) return false; - if (!ir3_cat2_float(instr->opc) && !ir3_cat3_float(instr->opc)) + if (!is_cat2_float(instr->opc) && !is_cat3_float(instr->opc)) return false; } @@ -594,8 +594,8 @@ reg_cp(struct ir3_cp_ctx *ctx, struct ir3_instruction *instr, return true; } else if (valid_flags(instr, n, (new_flags & ~IR3_REG_IMMED) | IR3_REG_CONST)) { - bool f_opcode = (ir3_cat2_float(instr->opc) || - ir3_cat3_float(instr->opc)) ? true : false; + bool f_opcode = (is_cat2_float(instr->opc) || + is_cat3_float(instr->opc)) ? true : false; /* See if lowering an immediate to const would help. */ instr->regs[n+1] = lower_immed(ctx, src_reg, new_flags, f_opcode); diff --git a/src/freedreno/ir3/tests/disasm.c b/src/freedreno/ir3/tests/disasm.c index b6aa5ed39d5..ee94578391e 100644 --- a/src/freedreno/ir3/tests/disasm.c +++ b/src/freedreno/ir3/tests/disasm.c @@ -77,6 +77,20 @@ static const struct test { /* discard stuff */ INSTR_6XX(42b400f8_20010004, "cmps.s.eq p0.x, r1.x, 1"), INSTR_6XX(02800000_00000000, "kill p0.x"), + + /* Immediates */ + INSTR_6XX(40100007_68000008, "add.f r1.w, r2.x, (neg)(0.0)"), + INSTR_6XX(40100007_68010008, "add.f r1.w, r2.x, (neg)(0.5)"), + INSTR_6XX(40100007_68020008, "add.f r1.w, r2.x, (neg)(1.0)"), + INSTR_6XX(40100007_68030008, "add.f r1.w, r2.x, (neg)(2.0)"), + INSTR_6XX(40100007_68040008, "add.f r1.w, r2.x, (neg)(e)"), + INSTR_6XX(40100007_68050008, "add.f r1.w, r2.x, (neg)(pi)"), + INSTR_6XX(40100007_68060008, "add.f r1.w, r2.x, (neg)(1/pi)"), + INSTR_6XX(40100007_68070008, "add.f r1.w, r2.x, (neg)(1/log2(e))"), + INSTR_6XX(40100007_68080008, "add.f r1.w, r2.x, (neg)(log2(e))"), + INSTR_6XX(40100007_68090008, "add.f r1.w, r2.x, (neg)(1/log2(10))"), + INSTR_6XX(40100007_680a0008, "add.f r1.w, r2.x, (neg)(log2(10))"), + INSTR_6XX(40100007_680b0008, "add.f r1.w, r2.x, (neg)(4.0)"), }; static void