}
}
+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:
*/
}
}
-/* 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
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);
}
}
/* 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);
}
}
}
_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