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