freedreno/ir3: add helpers to deal with src/dst types
authorRob Clark <robdclark@chromium.org>
Sat, 16 May 2020 21:24:45 +0000 (14:24 -0700)
committerMarge Bot <eric+marge@anholt.net>
Tue, 19 May 2020 16:06:17 +0000 (16:06 +0000)
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 <robdclark@chromium.org>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/5048>

src/freedreno/ir3/ir3.c
src/freedreno/ir3/ir3.h
src/freedreno/ir3/ir3_cf.c
src/freedreno/ir3/ir3_context.c

index d575ee3ae42ea9eb862d08fc62cbecfa66e9d0f1..23f29664e82c093baba5f51c3802cbaa0a5dda2a 100644 (file)
@@ -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;
+       }
+}
index 2fb21b67d4da8fcc0453f5062d9f54e4b2201366..d6ff469b26ef1328c4d7c46d4197f32e0e2dd7ee 100644 (file)
@@ -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);
index c1dc5385d361dace2e4e611a1d6e828770dc3adb..62014f8700a76911b6a7b270489bc94034a4ffd5 100644 (file)
@@ -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;
index 4fe3ae74e31c521feb2def958091d1388639a107..b9905625b703703309ae117fbea3a3c1572af029 100644 (file)
@@ -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;
                        }
                }