freedreno/ir3/validate: add checking for types and opcodes
authorRob Clark <robdclark@chromium.org>
Sat, 16 May 2020 20:32:14 +0000 (13:32 -0700)
committerMarge Bot <eric+marge@anholt.net>
Tue, 19 May 2020 16:06:17 +0000 (16:06 +0000)
For cases where instructions have a src and/or dst type, validate that
it matches the src/dst register types.  And for cases where there are
different opcodes for half vs full, validate that the opcode matches.

Now that we maintain this properly throughout the stages of the ir, we
can drop the fixups from the RA pass.

Signed-off-by: Rob Clark <robdclark@chromium.org>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/5048>

src/freedreno/ir3/ir3.h
src/freedreno/ir3/ir3_ra.c
src/freedreno/ir3/ir3_validate.c

index d6ff469b26ef1328c4d7c46d4197f32e0e2dd7ee..218fc04ab5a0d3328e7df4dd04be739dc64efad3 100644 (file)
@@ -976,6 +976,22 @@ static inline type_t half_type(type_t type)
        }
 }
 
+static inline type_t full_type(type_t type)
+{
+       switch (type) {
+       case TYPE_F16: return TYPE_F32;
+       case TYPE_U16: return TYPE_U32;
+       case TYPE_S16: return TYPE_S32;
+       case TYPE_F32:
+       case TYPE_U32:
+       case TYPE_S32:
+               return type;
+       default:
+               assert(0);
+               return ~0;
+       }
+}
+
 /* some cat2 instructions (ie. those which are not float) can embed an
  * immediate:
  */
index 8196203848eea207fc409cda9df3d01a7db69db9..44dc6f1b8e48ee90098bf3c3d7652156224f6ff4 100644 (file)
@@ -1105,60 +1105,6 @@ ra_add_interference(struct ir3_ra_ctx *ctx)
        }
 }
 
-/* some instructions need fix-up if dst register is half precision: */
-static void fixup_half_instr_dst(struct ir3_instruction *instr)
-{
-       switch (opc_cat(instr->opc)) {
-       case 1: /* move instructions */
-               instr->cat1.dst_type = half_type(instr->cat1.dst_type);
-               break;
-       case 4:
-               switch (instr->opc) {
-               case OPC_RSQ:
-                       instr->opc = OPC_HRSQ;
-                       break;
-               case OPC_LOG2:
-                       instr->opc = OPC_HLOG2;
-                       break;
-               case OPC_EXP2:
-                       instr->opc = OPC_HEXP2;
-                       break;
-               default:
-                       break;
-               }
-               break;
-       case 5:
-               instr->cat5.type = half_type(instr->cat5.type);
-               break;
-       }
-}
-/* some instructions need fix-up if src register is half precision: */
-static void fixup_half_instr_src(struct ir3_instruction *instr)
-{
-       switch (instr->opc) {
-       case OPC_MOV:
-               instr->cat1.src_type = half_type(instr->cat1.src_type);
-               break;
-       case OPC_MAD_F32:
-               instr->opc = OPC_MAD_F16;
-               break;
-       case OPC_SEL_B32:
-               instr->opc = OPC_SEL_B16;
-               break;
-       case OPC_SEL_S32:
-               instr->opc = OPC_SEL_S16;
-               break;
-       case OPC_SEL_F32:
-               instr->opc = OPC_SEL_F16;
-               break;
-       case OPC_SAD_S32:
-               instr->opc = OPC_SAD_S16;
-               break;
-       default:
-               break;
-       }
-}
-
 /* NOTE: instr could be NULL for IR3_REG_ARRAY case, for the first
  * array access(es) which do not have any previous access to depend
  * on from scheduling point of view
@@ -1241,8 +1187,6 @@ ra_block_alloc(struct ir3_ra_ctx *ctx, struct ir3_block *block)
                if (writes_gpr(instr)) {
                        if (should_assign(ctx, instr)) {
                                reg_assign(ctx, instr->regs[0], instr);
-                               if (instr->regs[0]->flags & IR3_REG_HALF)
-                                       fixup_half_instr_dst(instr);
                        }
                }
 
@@ -1258,9 +1202,6 @@ ra_block_alloc(struct ir3_ra_ctx *ctx, struct ir3_block *block)
                        /* Note: reg->instr could be null for IR3_REG_ARRAY */
                        if (src || (reg->flags & IR3_REG_ARRAY))
                                reg_assign(ctx, instr->regs[n+1], src);
-
-                       if (instr->regs[n+1]->flags & IR3_REG_HALF)
-                               fixup_half_instr_src(instr);
                }
        }
 
index 422c9f49f6f13f23348540986527996de00343af..ec8bb937da85a02f74bdaa2f07b80974e8c5ff75 100644 (file)
@@ -99,6 +99,50 @@ validate_instr(struct ir3_validate_ctx *ctx, struct ir3_instruction *instr)
        }
 
        _mesa_set_add(ctx->defs, instr);
+
+       /* Check that src/dst types match the register types, and for
+        * instructions that have different opcodes depending on type,
+        * that the opcodes are correct.
+        */
+       switch (opc_cat(instr->opc)) {
+       case 1: /* move instructions */
+               if (instr->regs[0]->flags & IR3_REG_HALF) {
+                       validate_assert(ctx, instr->cat1.dst_type == half_type(instr->cat1.dst_type));
+               } else {
+                       validate_assert(ctx, instr->cat1.dst_type == full_type(instr->cat1.dst_type));
+               }
+               if (instr->regs[1]->flags & IR3_REG_HALF) {
+                       validate_assert(ctx, instr->cat1.src_type == half_type(instr->cat1.src_type));
+               } else {
+                       validate_assert(ctx, instr->cat1.src_type == full_type(instr->cat1.src_type));
+               }
+               break;
+       case 3:
+               /* Validate that cat3 opc matches the src type.  We've already checked that all
+                * the src regs are same type
+                */
+               if (instr->regs[1]->flags & IR3_REG_HALF) {
+                       validate_assert(ctx, instr->opc == cat3_half_opc(instr->opc));
+               } else {
+                       validate_assert(ctx, instr->opc == cat3_full_opc(instr->opc));
+               }
+               break;
+       case 4:
+               /* Validate that cat4 opc matches the dst type: */
+               if (instr->regs[0]->flags & IR3_REG_HALF) {
+                       validate_assert(ctx, instr->opc == cat4_half_opc(instr->opc));
+               } else {
+                       validate_assert(ctx, instr->opc == cat4_full_opc(instr->opc));
+               }
+               break;
+       case 5:
+               if (instr->regs[0]->flags & IR3_REG_HALF) {
+                       validate_assert(ctx, instr->cat5.type == half_type(instr->cat5.type));
+               } else {
+                       validate_assert(ctx, instr->cat5.type == full_type(instr->cat5.type));
+               }
+               break;
+       }
 }
 
 void