freedreno/ir3: Fix the type of half-float indirect uniform loads.
[mesa.git] / src / freedreno / ir3 / ir3.h
index 9ec324e4e4a44ef0ebcdf87cf9a5e131f48e0fc2..2f5423238e0a6c9fff4b22ec7774bec155326ca1 100644 (file)
@@ -44,7 +44,7 @@ struct ir3_instruction;
 struct ir3_block;
 
 struct ir3_info {
-       uint32_t gpu_id;
+       void *data;              /* used internally in ir3 assembler */
        uint16_t sizedwords;
        uint16_t instrs_count;   /* expanded to account for rpt's */
        uint16_t nops_count;     /* # of nop instructions, including nopN */
@@ -121,9 +121,7 @@ struct ir3_register {
         * Note the size field isn't important for relative const (since
         * we don't have to do register allocation for constants).
         */
-       unsigned size : 15;
-
-       bool merged : 1;    /* half-regs conflict with full regs (ie >= a6xx) */
+       unsigned size : 16;
 
        /* normal registers:
         * the component is in the low two bits of the reg #, so
@@ -324,7 +322,6 @@ struct ir3_instruction {
         */
        struct set *uses;
 
-       int sun;            /* Sethi–Ullman number, used by sched */
        int use_count;      /* currently just updated/used by cp */
 
        /* Used during CP and RA stages.  For collect and shader inputs/
@@ -482,8 +479,6 @@ struct ir3 {
        /* List of ir3_array's: */
        struct list_head array_list;
 
-       unsigned max_sun;   /* max Sethi–Ullman number */
-
 #ifdef DEBUG
        unsigned block_count, instr_count;
 #endif
@@ -511,6 +506,8 @@ struct ir3_array {
 
        /* Indicates if half-precision */
        bool half;
+
+       bool unused;
 };
 
 struct ir3_array * ir3_lookup_array(struct ir3 *ir, unsigned id);
@@ -559,10 +556,12 @@ block_id(struct ir3_block *block)
 #endif
 }
 
-struct ir3 * ir3_create(struct ir3_compiler *compiler, gl_shader_stage type);
+struct ir3_shader_variant;
+
+struct ir3 * ir3_create(struct ir3_compiler *compiler, struct ir3_shader_variant *v);
 void ir3_destroy(struct ir3 *shader);
-void * ir3_assemble(struct ir3 *shader,
-               struct ir3_info *info, uint32_t gpu_id);
+
+void * ir3_assemble(struct ir3_shader_variant *v);
 void * ir3_alloc(struct ir3 *shader, int sz);
 
 struct ir3_block * ir3_block_create(struct ir3 *shader);
@@ -596,8 +595,35 @@ void ir3_clear_mark(struct ir3 *shader);
 unsigned ir3_count_instructions(struct ir3 *ir);
 unsigned ir3_count_instructions_ra(struct ir3 *ir);
 
+/**
+ * Move 'instr' to just before 'after'
+ */
+static inline void
+ir3_instr_move_before(struct ir3_instruction *instr,
+               struct ir3_instruction *after)
+{
+       list_delinit(&instr->node);
+       list_addtail(&instr->node, &after->node);
+}
+
+/**
+ * Move 'instr' to just after 'before':
+ */
+static inline void
+ir3_instr_move_after(struct ir3_instruction *instr,
+               struct ir3_instruction *before)
+{
+       list_delinit(&instr->node);
+       list_add(&instr->node, &before->node);
+}
+
 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);
+
+bool ir3_valid_flags(struct ir3_instruction *instr, unsigned n, unsigned flags);
+
 #include "util/set.h"
 #define foreach_ssa_use(__use, __instr) \
        for (struct ir3_instruction *__use = (void *)~0; \
@@ -605,19 +631,6 @@ void ir3_find_ssa_uses(struct ir3 *ir, void *mem_ctx, bool falsedeps);
                set_foreach ((__instr)->uses, __entry) \
                        if ((__use = (void *)__entry->key))
 
-#define MAX_ARRAYS 16
-
-/* comp:
- *   0 - x
- *   1 - y
- *   2 - z
- *   3 - w
- */
-static inline uint32_t regid(int num, int comp)
-{
-       return (num << 2) | (comp & 0x3);
-}
-
 static inline uint32_t reg_num(struct ir3_register *reg)
 {
        return reg->num >> 2;
@@ -628,10 +641,6 @@ static inline uint32_t reg_comp(struct ir3_register *reg)
        return reg->num & 0x3;
 }
 
-#define INVALID_REG      regid(63, 0)
-#define VALIDREG(r)      ((r) != INVALID_REG)
-#define CONDREG(r, val)  COND(VALIDREG(r), (val))
-
 static inline bool is_flow(struct ir3_instruction *instr)
 {
        return (opc_cat(instr->opc) == 0);
@@ -833,6 +842,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);
@@ -846,6 +903,20 @@ static inline unsigned dest_regs(struct ir3_instruction *instr)
        return util_last_bit(instr->regs[0]->wrmask);
 }
 
+static inline bool
+writes_gpr(struct ir3_instruction *instr)
+{
+       if (dest_regs(instr) == 0)
+               return false;
+       /* is dest a normal temp register: */
+       struct ir3_register *reg = instr->regs[0];
+       debug_assert(!(reg->flags & (IR3_REG_CONST | IR3_REG_IMMED)));
+       if ((reg_num(reg) == REG_A0) ||
+                       (reg->num == regid(REG_P0, 0)))
+               return false;
+       return true;
+}
+
 static inline bool writes_addr0(struct ir3_instruction *instr)
 {
        if (instr->regs_count > 0) {
@@ -914,6 +985,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:
  */
@@ -1052,8 +1139,9 @@ static inline unsigned ir3_cat3_absneg(opc_t opc)
 /* iterator for an instructions's sources (reg), also returns src #: */
 #define foreach_src_n(__srcreg, __n, __instr) \
        if ((__instr)->regs_count) \
-               for (unsigned __cnt = (__instr)->regs_count - 1, __n = 0; __n < __cnt; __n++) \
-                       if ((__srcreg = (__instr)->regs[__n + 1]))
+               for (struct ir3_register *__srcreg = (void *)~0; __srcreg; __srcreg = NULL) \
+                       for (unsigned __cnt = (__instr)->regs_count - 1, __n = 0; __n < __cnt; __n++) \
+                               if ((__srcreg = (__instr)->regs[__n + 1]))
 
 /* iterator for an instructions's sources (reg): */
 #define foreach_src(__srcreg, __instr) \
@@ -1098,8 +1186,9 @@ static inline bool __is_false_dep(struct ir3_instruction *instr, unsigned n)
 
 /* iterator for an instruction's SSA sources (instr), also returns src #: */
 #define foreach_ssa_src_n(__srcinst, __n, __instr) \
-       foreach_ssa_srcp_n(__srcp, __n, __instr) \
-               if ((__srcinst = *__srcp))
+       for (struct ir3_instruction *__srcinst = (void *)~0; __srcinst; __srcinst = NULL) \
+               foreach_ssa_srcp_n(__srcp, __n, __instr) \
+                       if ((__srcinst = *__srcp))
 
 /* iterator for an instruction's SSA sources (instr): */
 #define foreach_ssa_src(__srcinst, __instr) \
@@ -1107,15 +1196,17 @@ static inline bool __is_false_dep(struct ir3_instruction *instr, unsigned n)
 
 /* iterators for shader inputs: */
 #define foreach_input_n(__ininstr, __cnt, __ir) \
-       for (unsigned __cnt = 0; __cnt < (__ir)->inputs_count; __cnt++) \
-               if ((__ininstr = (__ir)->inputs[__cnt]))
+       for (struct ir3_instruction *__ininstr = (void *)~0; __ininstr; __ininstr = NULL) \
+               for (unsigned __cnt = 0; __cnt < (__ir)->inputs_count; __cnt++) \
+                       if ((__ininstr = (__ir)->inputs[__cnt]))
 #define foreach_input(__ininstr, __ir) \
        foreach_input_n(__ininstr, __i, __ir)
 
 /* iterators for shader outputs: */
 #define foreach_output_n(__outinstr, __cnt, __ir) \
-       for (unsigned __cnt = 0; __cnt < (__ir)->outputs_count; __cnt++) \
-               if ((__outinstr = (__ir)->outputs[__cnt]))
+       for (struct ir3_instruction *__outinstr = (void *)~0; __outinstr; __outinstr = NULL) \
+               for (unsigned __cnt = 0; __cnt < (__ir)->outputs_count; __cnt++) \
+                       if ((__outinstr = (__ir)->outputs[__cnt]))
 #define foreach_output(__outinstr, __ir) \
        foreach_output_n(__outinstr, __i, __ir)
 
@@ -1138,14 +1229,14 @@ static inline bool __is_false_dep(struct ir3_instruction *instr, unsigned n)
 /* iterators for arrays: */
 #define foreach_array(__array, __list) \
        list_for_each_entry(struct ir3_array, __array, __list, node)
+#define foreach_array_safe(__array, __list) \
+       list_for_each_entry_safe(struct ir3_array, __array, __list, node)
 
 /* Check if condition is true for any src instruction.
  */
 static inline bool
 check_src_cond(struct ir3_instruction *instr, bool (*cond)(struct ir3_instruction *))
 {
-       struct ir3_register *reg;
-
        /* Note that this is also used post-RA so skip the ssa iterator: */
        foreach_src (reg, instr) {
                struct ir3_instruction *src = reg->instr;
@@ -1168,6 +1259,18 @@ check_src_cond(struct ir3_instruction *instr, bool (*cond)(struct ir3_instructio
        return false;
 }
 
+#define IR3_PASS(ir, pass, ...) ({ \
+               bool progress = pass(ir, ##__VA_ARGS__); \
+               if (progress) { \
+                       ir3_debug_print(ir, "AFTER: " #pass); \
+                       ir3_validate(ir); \
+               } \
+               progress; \
+       })
+
+/* validate: */
+void ir3_validate(struct ir3 *ir);
+
 /* dump: */
 void ir3_print(struct ir3 *ir);
 void ir3_print_instr(struct ir3_instruction *instr);
@@ -1181,35 +1284,33 @@ void ir3_remove_nops(struct ir3 *ir);
 
 /* dead code elimination: */
 struct ir3_shader_variant;
-void ir3_dce(struct ir3 *ir, struct ir3_shader_variant *so);
+bool ir3_dce(struct ir3 *ir, struct ir3_shader_variant *so);
 
 /* fp16 conversion folding */
-void ir3_cf(struct ir3 *ir);
+bool ir3_cf(struct ir3 *ir);
 
 /* copy-propagate: */
-void ir3_cp(struct ir3 *ir, struct ir3_shader_variant *so);
+bool ir3_cp(struct ir3 *ir, struct ir3_shader_variant *so);
+bool ir3_cp_postsched(struct ir3 *ir);
 
 /* group neighbors and insert mov's to resolve conflicts: */
-void ir3_group(struct ir3 *ir);
-
-/* Sethi–Ullman numbering: */
-void ir3_sun(struct ir3 *ir);
+bool ir3_group(struct ir3 *ir);
 
 /* scheduling: */
-void ir3_sched_add_deps(struct ir3 *ir);
+bool ir3_sched_add_deps(struct ir3 *ir);
 int ir3_sched(struct ir3 *ir);
 
 struct ir3_context;
-int ir3_postsched(struct ir3_context *ctx);
+bool ir3_postsched(struct ir3 *ir, struct ir3_shader_variant *v);
 
 bool ir3_a6xx_fixup_atomic_dests(struct ir3 *ir, struct ir3_shader_variant *so);
 
 /* register assignment: */
-struct ir3_ra_reg_set * ir3_ra_alloc_reg_set(struct ir3_compiler *compiler);
+struct ir3_ra_reg_set * ir3_ra_alloc_reg_set(struct ir3_compiler *compiler, bool mergedregs);
 int ir3_ra(struct ir3_shader_variant *v, struct ir3_instruction **precolor, unsigned nprecolor);
 
 /* legalize: */
-void ir3_legalize(struct ir3 *ir, struct ir3_shader_variant *so, int *max_bary);
+bool ir3_legalize(struct ir3 *ir, struct ir3_shader_variant *so, int *max_bary);
 
 static inline bool
 ir3_has_latency_to_hide(struct ir3 *ir)
@@ -1308,14 +1409,14 @@ create_uniform(struct ir3_block *block, unsigned n)
 }
 
 static inline struct ir3_instruction *
-create_uniform_indirect(struct ir3_block *block, int n,
+create_uniform_indirect(struct ir3_block *block, int n, type_t type,
                struct ir3_instruction *address)
 {
        struct ir3_instruction *mov;
 
        mov = ir3_instr_create(block, OPC_MOV);
-       mov->cat1.src_type = TYPE_U32;
-       mov->cat1.dst_type = TYPE_U32;
+       mov->cat1.src_type = type;
+       mov->cat1.dst_type = type;
        __ssa_dst(mov);
        ir3_reg_create(mov, 0, IR3_REG_CONST | IR3_REG_RELATIV)->array.offset = n;
 
@@ -1328,7 +1429,9 @@ static inline struct ir3_instruction *
 ir3_MOV(struct ir3_block *block, struct ir3_instruction *src, type_t type)
 {
        struct ir3_instruction *instr = ir3_instr_create(block, OPC_MOV);
-       __ssa_dst(instr);
+       unsigned flags = (type_size(type) < 32) ? IR3_REG_HALF : 0;
+
+       __ssa_dst(instr)->flags |= flags;
        if (src->regs[0]->flags & IR3_REG_ARRAY) {
                struct ir3_register *src_reg = __ssa_src(instr, src, IR3_REG_ARRAY);
                src_reg->array = src->regs[0]->array;
@@ -1543,9 +1646,9 @@ INSTR1(SQRT)
 
 /* cat5 instructions: */
 INSTR1(DSX)
-INSTR1(DSXPP_1)
+INSTR1(DSXPP_MACRO)
 INSTR1(DSY)
-INSTR1(DSYPP_1)
+INSTR1(DSYPP_MACRO)
 INSTR1F(3D, DSX)
 INSTR1F(3D, DSY)
 INSTR1(RGETPOS)
@@ -1561,7 +1664,7 @@ ir3_SAM(struct ir3_block *block, opc_t opc, type_t type,
        sam->flags |= flags;
        __ssa_dst(sam)->wrmask = wrmask;
        if (flags & IR3_INSTR_S2EN) {
-               __ssa_src(sam, samp_tex, IR3_REG_HALF);
+               __ssa_src(sam, samp_tex, (flags & IR3_INSTR_B) ? 0 : IR3_REG_HALF);
        }
        if (src0) {
                __ssa_src(sam, src0, 0);
@@ -1637,104 +1740,37 @@ INSTR0(FENCE)
 INSTR0(META_TEX_PREFETCH);
 
 /* ************************************************************************* */
-/* split this out or find some helper to use.. like main/bitset.h.. */
-
-#include <string.h>
-#include "util/bitset.h"
-
-#define MAX_REG 256
-
-typedef BITSET_DECLARE(regmask_t, 2 * MAX_REG);
-
-static inline bool
-__regmask_get(regmask_t *regmask, struct ir3_register *reg, unsigned n)
-{
-       if (reg->merged) {
-               /* a6xx+ case, with merged register file, we track things in terms
-                * of half-precision registers, with a full precisions register
-                * using two half-precision slots:
-                */
-               if (reg->flags & IR3_REG_HALF) {
-                       return BITSET_TEST(*regmask, n);
-               } else {
-                       n *= 2;
-                       return BITSET_TEST(*regmask, n) || BITSET_TEST(*regmask, n+1);
-               }
-       } else {
-               /* pre a6xx case, with separate register file for half and full
-                * precision:
-                */
-               if (reg->flags & IR3_REG_HALF)
-                       n += MAX_REG;
-               return BITSET_TEST(*regmask, n);
-       }
-}
-
-static inline void
-__regmask_set(regmask_t *regmask, struct ir3_register *reg, unsigned n)
-{
-       if (reg->merged) {
-               /* a6xx+ case, with merged register file, we track things in terms
-                * of half-precision registers, with a full precisions register
-                * using two half-precision slots:
-                */
-               if (reg->flags & IR3_REG_HALF) {
-                       BITSET_SET(*regmask, n);
-               } else {
-                       n *= 2;
-                       BITSET_SET(*regmask, n);
-                       BITSET_SET(*regmask, n+1);
-               }
-       } else {
-               /* pre a6xx case, with separate register file for half and full
-                * precision:
-                */
-               if (reg->flags & IR3_REG_HALF)
-                       n += MAX_REG;
-               BITSET_SET(*regmask, n);
-       }
-}
-
-static inline void regmask_init(regmask_t *regmask)
-{
-       memset(regmask, 0, sizeof(*regmask));
-}
+#include "regmask.h"
 
 static inline void regmask_set(regmask_t *regmask, struct ir3_register *reg)
 {
+       bool half = reg->flags & IR3_REG_HALF;
        if (reg->flags & IR3_REG_RELATIV) {
                for (unsigned i = 0; i < reg->size; i++)
-                       __regmask_set(regmask, reg, reg->array.offset + i);
+                       __regmask_set(regmask, half, reg->array.offset + i);
        } else {
                for (unsigned mask = reg->wrmask, n = reg->num; mask; mask >>= 1, n++)
                        if (mask & 1)
-                               __regmask_set(regmask, reg, n);
+                               __regmask_set(regmask, half, n);
        }
 }
 
-static inline void regmask_or(regmask_t *dst, regmask_t *a, regmask_t *b)
-{
-       unsigned i;
-       for (i = 0; i < ARRAY_SIZE(*dst); i++)
-               (*dst)[i] = (*a)[i] | (*b)[i];
-}
-
 static inline bool regmask_get(regmask_t *regmask,
                struct ir3_register *reg)
 {
+       bool half = reg->flags & IR3_REG_HALF;
        if (reg->flags & IR3_REG_RELATIV) {
                for (unsigned i = 0; i < reg->size; i++)
-                       if (__regmask_get(regmask, reg, reg->array.offset + i))
+                       if (__regmask_get(regmask, half, reg->array.offset + i))
                                return true;
        } else {
                for (unsigned mask = reg->wrmask, n = reg->num; mask; mask >>= 1, n++)
                        if (mask & 1)
-                               if (__regmask_get(regmask, reg, n))
+                               if (__regmask_get(regmask, half, n))
                                        return true;
        }
        return false;
 }
-
 /* ************************************************************************* */
 
 #endif /* IR3_H_ */