From: Rob Clark Date: Sat, 16 May 2020 20:32:14 +0000 (-0700) Subject: freedreno/ir3/validate: add checking for types and opcodes X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=3c355f1ae8be2a7e1f9141c5433bdbb35fdcd7e6;p=mesa.git freedreno/ir3/validate: add checking for types and opcodes 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 Part-of: --- diff --git a/src/freedreno/ir3/ir3.h b/src/freedreno/ir3/ir3.h index d6ff469b26e..218fc04ab5a 100644 --- a/src/freedreno/ir3/ir3.h +++ b/src/freedreno/ir3/ir3.h @@ -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: */ diff --git a/src/freedreno/ir3/ir3_ra.c b/src/freedreno/ir3/ir3_ra.c index 8196203848e..44dc6f1b8e4 100644 --- a/src/freedreno/ir3/ir3_ra.c +++ b/src/freedreno/ir3/ir3_ra.c @@ -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); } } diff --git a/src/freedreno/ir3/ir3_validate.c b/src/freedreno/ir3/ir3_validate.c index 422c9f49f6f..ec8bb937da8 100644 --- a/src/freedreno/ir3/ir3_validate.c +++ b/src/freedreno/ir3/ir3_validate.c @@ -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