From f484d63617afe67f9eb8ba98f96e5c3617aa43c8 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Sat, 16 May 2020 14:24:45 -0700 Subject: [PATCH] freedreno/ir3: add helpers to deal with src/dst types Add some helpers to properly maintain src/dst types, and in the cases where opcode depends on src or dst type, maintain that as well. Signed-off-by: Rob Clark Part-of: --- src/freedreno/ir3/ir3.c | 66 +++++++++++++++++++++++++++++++++++++++++ src/freedreno/ir3/ir3.h | 51 +++++++++++++++++++++++++++++++ src/freedreno/ir3/ir3_cf.c | 7 +---- src/freedreno/ir3/ir3_context.c | 6 ++-- 4 files changed, 122 insertions(+), 8 deletions(-) diff --git a/src/freedreno/ir3/ir3.c b/src/freedreno/ir3/ir3.c index d575ee3..23f2966 100644 --- a/src/freedreno/ir3/ir3.c +++ b/src/freedreno/ir3/ir3.c @@ -1211,3 +1211,69 @@ ir3_find_ssa_uses(struct ir3 *ir, void *mem_ctx, bool falsedeps) } } } + +/** + * Set the destination type of an instruction, for example if a + * conversion is folded in, handling the special cases where the + * instruction's dest type or opcode needs to be fixed up. + */ +void +ir3_set_dst_type(struct ir3_instruction *instr, bool half) +{ + if (half) { + instr->regs[0]->flags |= IR3_REG_HALF; + } else { + instr->regs[0]->flags &= ~IR3_REG_HALF; + } + + switch (opc_cat(instr->opc)) { + case 1: /* move instructions */ + if (half) { + instr->cat1.dst_type = half_type(instr->cat1.dst_type); + } else { + instr->cat1.dst_type = full_type(instr->cat1.dst_type); + } + break; + case 4: + if (half) { + instr->opc = cat4_half_opc(instr->opc); + } else { + instr->opc = cat4_full_opc(instr->opc); + } + break; + case 5: + if (half) { + instr->cat5.type = half_type(instr->cat5.type); + } else { + instr->cat5.type = full_type(instr->cat5.type); + } + break; + } +} + +/** + * One-time fixup for instruction src-types. Other than cov's that + * are folded, an instruction's src type does not change. + */ +void +ir3_fixup_src_type(struct ir3_instruction *instr) +{ + bool half = !!(instr->regs[1]->flags & IR3_REG_HALF); + + switch (opc_cat(instr->opc)) { + case 1: /* move instructions */ + if (half) { + instr->cat1.src_type = half_type(instr->cat1.src_type); + } else { + instr->cat1.src_type = full_type(instr->cat1.src_type); + } + break; + case 3: + if (half) { + instr->opc = cat3_half_opc(instr->opc); + } else { + instr->opc = cat3_full_opc(instr->opc); + } + break; + } +} diff --git a/src/freedreno/ir3/ir3.h b/src/freedreno/ir3/ir3.h index 2fb21b6..d6ff469 100644 --- a/src/freedreno/ir3/ir3.h +++ b/src/freedreno/ir3/ir3.h @@ -595,6 +595,9 @@ unsigned ir3_count_instructions_ra(struct ir3 *ir); void ir3_find_ssa_uses(struct ir3 *ir, void *mem_ctx, bool falsedeps); +void ir3_set_dst_type(struct ir3_instruction *instr, bool half); +void ir3_fixup_src_type(struct ir3_instruction *instr); + #include "util/set.h" #define foreach_ssa_use(__use, __instr) \ for (struct ir3_instruction *__use = (void *)~0; \ @@ -830,6 +833,54 @@ static inline bool is_bool(struct ir3_instruction *instr) } } +static inline opc_t +cat3_half_opc(opc_t opc) +{ + switch (opc) { + case OPC_MAD_F32: return OPC_MAD_F16; + case OPC_SEL_B32: return OPC_SEL_B16; + case OPC_SEL_S32: return OPC_SEL_S16; + case OPC_SEL_F32: return OPC_SEL_F16; + case OPC_SAD_S32: return OPC_SAD_S16; + default: return opc; + } +} + +static inline opc_t +cat3_full_opc(opc_t opc) +{ + switch (opc) { + case OPC_MAD_F16: return OPC_MAD_F32; + case OPC_SEL_B16: return OPC_SEL_B32; + case OPC_SEL_S16: return OPC_SEL_S32; + case OPC_SEL_F16: return OPC_SEL_F32; + case OPC_SAD_S16: return OPC_SAD_S32; + default: return opc; + } +} + +static inline opc_t +cat4_half_opc(opc_t opc) +{ + switch (opc) { + case OPC_RSQ: return OPC_HRSQ; + case OPC_LOG2: return OPC_HLOG2; + case OPC_EXP2: return OPC_HEXP2; + default: return opc; + } +} + +static inline opc_t +cat4_full_opc(opc_t opc) +{ + switch (opc) { + case OPC_HRSQ: return OPC_RSQ; + case OPC_HLOG2: return OPC_LOG2; + case OPC_HEXP2: return OPC_EXP2; + default: return opc; + } +} + static inline bool is_meta(struct ir3_instruction *instr) { return (opc_cat(instr->opc) == -1); diff --git a/src/freedreno/ir3/ir3_cf.c b/src/freedreno/ir3/ir3_cf.c index c1dc538..62014f8 100644 --- a/src/freedreno/ir3/ir3_cf.c +++ b/src/freedreno/ir3/ir3_cf.c @@ -148,12 +148,7 @@ try_conversion_folding(struct ir3_instruction *conv) } } - if (is_half(conv)) { - src->regs[0]->flags |= IR3_REG_HALF; - } else { - src->regs[0]->flags &= ~IR3_REG_HALF; - } - + ir3_set_dst_type(src, is_half(conv)); rewrite_src_uses(src); return true; diff --git a/src/freedreno/ir3/ir3_context.c b/src/freedreno/ir3/ir3_context.c index 4fe3ae7..b990562 100644 --- a/src/freedreno/ir3/ir3_context.c +++ b/src/freedreno/ir3/ir3_context.c @@ -256,9 +256,11 @@ ir3_put_dst(struct ir3_context *ctx, nir_dest *dst) if (bit_size == 16) { for (unsigned i = 0; i < ctx->last_dst_n; i++) { struct ir3_instruction *dst = ctx->last_dst[i]; - dst->regs[0]->flags |= IR3_REG_HALF; + ir3_set_dst_type(dst, true); + ir3_fixup_src_type(dst); if (dst->opc == OPC_META_SPLIT) { - dst->regs[1]->instr->regs[0]->flags |= IR3_REG_HALF; + ir3_set_dst_type(ssa(dst->regs[1]), true); + ir3_fixup_src_type(ssa(dst->regs[1])); dst->regs[1]->flags |= IR3_REG_HALF; } } -- 2.7.4