freedreno/ir3: don't DCE ij_pix if used for pre-fs-texture-fetch
[mesa.git] / src / freedreno / ir3 / ir3.h
index 8fde504196aa370d1db5a1b3c378850c352edcb8..8b8788a8a97571a84fcc32177423b2e977d40e64 100644 (file)
@@ -31,6 +31,7 @@
 
 #include "util/bitscan.h"
 #include "util/list.h"
+#include "util/set.h"
 #include "util/u_debug.h"
 
 #include "instr-a3xx.h"
@@ -267,8 +268,12 @@ struct ir3_instruction {
                        int off;              /* component/offset */
                } fo;
                struct {
-                       struct ir3_block *block;
-               } inout;
+                       /* for sysvals, identifies the sysval type.  Mostly so we can
+                        * identify the special cases where a sysval should not be DCE'd
+                        * (currently, just pre-fs texture fetch)
+                        */
+                       gl_system_value sysval;
+               } input;
        };
 
        /* transient values used during various algorithms: */
@@ -292,6 +297,11 @@ struct ir3_instruction {
        };
 
        /* used for per-pass extra instruction data.
+        *
+        * TODO we should remove the per-pass data like this and 'use_count'
+        * and do something similar to what RA does w/ ir3_ra_instr_data..
+        * ie. use the ir3_count_instructions pass, and then use instr->ip
+        * to index into a table of pass-private data.
         */
        void *data;
 
@@ -408,6 +418,7 @@ static inline int ir3_neighbor_count(struct ir3_instruction *instr)
 
 struct ir3 {
        struct ir3_compiler *compiler;
+       gl_shader_stage type;
 
        unsigned ninputs, noutputs;
        struct ir3_instruction **inputs;
@@ -492,8 +503,7 @@ struct ir3_block {
        struct ir3_instruction *condition;
        struct ir3_block *successors[2];
 
-       unsigned predecessors_count;
-       struct ir3_block **predecessors;
+       struct set *predecessors;     /* set of ir3_block */
 
        uint16_t start_ip, end_ip;
 
@@ -523,7 +533,7 @@ block_id(struct ir3_block *block)
 }
 
 struct ir3 * ir3_create(struct ir3_compiler *compiler,
-               unsigned nin, unsigned nout);
+               gl_shader_stage type, unsigned nin, unsigned nout);
 void ir3_destroy(struct ir3 *shader);
 void * ir3_assemble(struct ir3 *shader,
                struct ir3_info *info, uint32_t gpu_id);
@@ -608,6 +618,18 @@ static inline bool is_nop(struct ir3_instruction *instr)
        return instr->opc == OPC_NOP;
 }
 
+static inline bool is_same_type_reg(struct ir3_register *reg1,
+               struct ir3_register *reg2)
+{
+       unsigned type_reg1 = (reg1->flags & (IR3_REG_HIGH | IR3_REG_HALF));
+       unsigned type_reg2 = (reg2->flags & (IR3_REG_HIGH | IR3_REG_HALF));
+
+       if (type_reg1 ^ type_reg2)
+               return false;
+       else
+               return true;
+}
+
 /* Is it a non-transformative (ie. not type changing) mov?  This can
  * also include absneg.s/absneg.f, which for the most part can be
  * treated as a mov (single src argument).
@@ -625,6 +647,10 @@ static inline bool is_same_type_mov(struct ir3_instruction *instr)
        case OPC_ABSNEG_S:
                if (instr->flags & IR3_INSTR_SAT)
                        return false;
+               /* If the type of dest reg and src reg are different,
+                * it shouldn't be considered as same type mov */
+               if (!is_same_type_reg(instr->regs[0], instr->regs[1]))
+                       return false;
                break;
        default:
                return false;
@@ -855,6 +881,41 @@ static inline bool ir3_cat2_int(opc_t opc)
        }
 }
 
+static inline bool ir3_cat2_float(opc_t opc)
+{
+       switch (opc) {
+       case OPC_ADD_F:
+       case OPC_MIN_F:
+       case OPC_MAX_F:
+       case OPC_MUL_F:
+       case OPC_SIGN_F:
+       case OPC_CMPS_F:
+       case OPC_ABSNEG_F:
+       case OPC_CMPV_F:
+       case OPC_FLOOR_F:
+       case OPC_CEIL_F:
+       case OPC_RNDNE_F:
+       case OPC_RNDAZ_F:
+       case OPC_TRUNC_F:
+               return true;
+
+       default:
+               return false;
+       }
+}
+
+static inline bool ir3_cat3_float(opc_t opc)
+{
+       switch (opc) {
+       case OPC_MAD_F16:
+       case OPC_MAD_F32:
+       case OPC_SEL_F16:
+       case OPC_SEL_F32:
+               return true;
+       default:
+               return false;
+       }
+}
 
 /* map cat2 instruction to valid abs/neg flags: */
 static inline unsigned ir3_cat2_absneg(opc_t opc)
@@ -1001,13 +1062,13 @@ void ir3_print(struct ir3 *ir);
 void ir3_print_instr(struct ir3_instruction *instr);
 
 /* depth calculation: */
+struct ir3_shader_variant;
 int ir3_delayslots(struct ir3_instruction *assigner,
                struct ir3_instruction *consumer, unsigned n);
 void ir3_insert_by_depth(struct ir3_instruction *instr, struct list_head *list);
-void ir3_depth(struct ir3 *ir);
+void ir3_depth(struct ir3 *ir, struct ir3_shader_variant *so);
 
 /* copy-propagate: */
-struct ir3_shader_variant;
 void ir3_cp(struct ir3 *ir, struct ir3_shader_variant *so);
 
 /* group neighbors and insert mov's to resolve conflicts: */
@@ -1024,11 +1085,10 @@ void 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);
-int ir3_ra(struct ir3 *ir3, gl_shader_stage type,
-               bool frag_coord, bool frag_face);
+int ir3_ra(struct ir3_shader_variant *v, struct ir3_instruction **precolor, unsigned nprecolor);
 
 /* legalize: */
-void ir3_legalize(struct ir3 *ir, bool *has_ssbo, int *max_bary);
+void ir3_legalize(struct ir3 *ir, bool *has_ssbo, bool *need_pixlod, int *max_bary);
 
 /* ************************************************************************* */
 /* instruction helpers */
@@ -1055,20 +1115,26 @@ create_immed(struct ir3_block *block, uint32_t val)
 }
 
 static inline struct ir3_instruction *
-create_uniform(struct ir3_block *block, unsigned n)
+create_uniform_typed(struct ir3_block *block, unsigned n, type_t type)
 {
        struct ir3_instruction *mov;
+       unsigned flags = (type_size(type) < 32) ? IR3_REG_HALF : 0;
 
        mov = ir3_instr_create(block, OPC_MOV);
-       /* TODO get types right? */
-       mov->cat1.src_type = TYPE_F32;
-       mov->cat1.dst_type = TYPE_F32;
-       ir3_reg_create(mov, 0, 0);
-       ir3_reg_create(mov, n, IR3_REG_CONST);
+       mov->cat1.src_type = type;
+       mov->cat1.dst_type = type;
+       ir3_reg_create(mov, 0, flags);
+       ir3_reg_create(mov, n, IR3_REG_CONST | flags);
 
        return mov;
 }
 
+static inline struct ir3_instruction *
+create_uniform(struct ir3_block *block, unsigned n)
+{
+       return create_uniform_typed(block, n, TYPE_F32);
+}
+
 static inline struct ir3_instruction *
 create_uniform_indirect(struct ir3_block *block, int n,
                struct ir3_instruction *address)
@@ -1140,42 +1206,53 @@ ir3_NOP(struct ir3_block *block)
        return ir3_instr_create(block, OPC_NOP);
 }
 
-#define INSTR0(name)                                                     \
+#define IR3_INSTR_0 0
+
+#define __INSTR0(flag, name, opc)                                        \
 static inline struct ir3_instruction *                                   \
 ir3_##name(struct ir3_block *block)                                      \
 {                                                                        \
        struct ir3_instruction *instr =                                      \
-               ir3_instr_create(block, OPC_##name);                             \
+               ir3_instr_create(block, opc);                                    \
+       instr->flags |= flag;                                                \
        return instr;                                                        \
 }
+#define INSTR0F(f, name)    __INSTR0(IR3_INSTR_##f, name##_##f, OPC_##name)
+#define INSTR0(name)        __INSTR0(0, name, OPC_##name)
 
-#define INSTR1(name)                                                     \
+#define __INSTR1(flag, name, opc)                                        \
 static inline struct ir3_instruction *                                   \
 ir3_##name(struct ir3_block *block,                                      \
                struct ir3_instruction *a, unsigned aflags)                      \
 {                                                                        \
        struct ir3_instruction *instr =                                      \
-               ir3_instr_create(block, OPC_##name);                             \
+               ir3_instr_create(block, opc);                                    \
        ir3_reg_create(instr, 0, 0);   /* dst */                             \
        __ssa_src(instr, a, aflags);                                         \
+       instr->flags |= flag;                                                \
        return instr;                                                        \
 }
+#define INSTR1F(f, name)    __INSTR1(IR3_INSTR_##f, name##_##f, OPC_##name)
+#define INSTR1(name)        __INSTR1(0, name, OPC_##name)
 
-#define INSTR2(name)                                                     \
+#define __INSTR2(flag, name, opc)                                        \
 static inline struct ir3_instruction *                                   \
 ir3_##name(struct ir3_block *block,                                      \
                struct ir3_instruction *a, unsigned aflags,                      \
                struct ir3_instruction *b, unsigned bflags)                      \
 {                                                                        \
        struct ir3_instruction *instr =                                      \
-               ir3_instr_create(block, OPC_##name);                             \
+               ir3_instr_create(block, opc);                                    \
        ir3_reg_create(instr, 0, 0);   /* dst */                             \
        __ssa_src(instr, a, aflags);                                         \
        __ssa_src(instr, b, bflags);                                         \
+       instr->flags |= flag;                                                \
        return instr;                                                        \
 }
+#define INSTR2F(f, name)    __INSTR2(IR3_INSTR_##f, name##_##f, OPC_##name)
+#define INSTR2(name)        __INSTR2(0, name, OPC_##name)
 
-#define INSTR3(name)                                                     \
+#define __INSTR3(flag, name, opc)                                        \
 static inline struct ir3_instruction *                                   \
 ir3_##name(struct ir3_block *block,                                      \
                struct ir3_instruction *a, unsigned aflags,                      \
@@ -1183,32 +1260,18 @@ ir3_##name(struct ir3_block *block,                                      \
                struct ir3_instruction *c, unsigned cflags)                      \
 {                                                                        \
        struct ir3_instruction *instr =                                      \
-               ir3_instr_create(block, OPC_##name);                             \
+               ir3_instr_create2(block, opc, 4);                                \
        ir3_reg_create(instr, 0, 0);   /* dst */                             \
        __ssa_src(instr, a, aflags);                                         \
        __ssa_src(instr, b, bflags);                                         \
        __ssa_src(instr, c, cflags);                                         \
+       instr->flags |= flag;                                                \
        return instr;                                                        \
 }
+#define INSTR3F(f, name)    __INSTR3(IR3_INSTR_##f, name##_##f, OPC_##name)
+#define INSTR3(name)        __INSTR3(0, name, OPC_##name)
 
-#define INSTR3F(f, name)                                                 \
-static inline struct ir3_instruction *                                   \
-ir3_##name##_##f(struct ir3_block *block,                                \
-               struct ir3_instruction *a, unsigned aflags,                      \
-               struct ir3_instruction *b, unsigned bflags,                      \
-               struct ir3_instruction *c, unsigned cflags)                      \
-{                                                                        \
-       struct ir3_instruction *instr =                                      \
-               ir3_instr_create2(block, OPC_##name, 5);                         \
-       ir3_reg_create(instr, 0, 0);   /* dst */                             \
-       __ssa_src(instr, a, aflags);                                         \
-       __ssa_src(instr, b, bflags);                                         \
-       __ssa_src(instr, c, cflags);                                         \
-       instr->flags |= IR3_INSTR_##f;                                       \
-       return instr;                                                        \
-}
-
-#define INSTR4(name)                                                     \
+#define __INSTR4(flag, name, opc)                                        \
 static inline struct ir3_instruction *                                   \
 ir3_##name(struct ir3_block *block,                                      \
                struct ir3_instruction *a, unsigned aflags,                      \
@@ -1217,39 +1280,25 @@ ir3_##name(struct ir3_block *block,                                      \
                struct ir3_instruction *d, unsigned dflags)                      \
 {                                                                        \
        struct ir3_instruction *instr =                                      \
-               ir3_instr_create2(block, OPC_##name, 5);                         \
-       ir3_reg_create(instr, 0, 0);   /* dst */                             \
-       __ssa_src(instr, a, aflags);                                         \
-       __ssa_src(instr, b, bflags);                                         \
-       __ssa_src(instr, c, cflags);                                         \
-       __ssa_src(instr, d, dflags);                                         \
-       return instr;                                                        \
-}
-
-#define INSTR4F(f, name)                                                 \
-static inline struct ir3_instruction *                                   \
-ir3_##name##_##f(struct ir3_block *block,                                \
-               struct ir3_instruction *a, unsigned aflags,                      \
-               struct ir3_instruction *b, unsigned bflags,                      \
-               struct ir3_instruction *c, unsigned cflags,                      \
-               struct ir3_instruction *d, unsigned dflags)                      \
-{                                                                        \
-       struct ir3_instruction *instr =                                      \
-               ir3_instr_create2(block, OPC_##name, 5);                         \
+               ir3_instr_create2(block, opc, 5);                                \
        ir3_reg_create(instr, 0, 0);   /* dst */                             \
        __ssa_src(instr, a, aflags);                                         \
        __ssa_src(instr, b, bflags);                                         \
        __ssa_src(instr, c, cflags);                                         \
        __ssa_src(instr, d, dflags);                                         \
-       instr->flags |= IR3_INSTR_##f;                                       \
+       instr->flags |= flag;                                                \
        return instr;                                                        \
 }
+#define INSTR4F(f, name)    __INSTR4(IR3_INSTR_##f, name##_##f, OPC_##name)
+#define INSTR4(name)        __INSTR4(0, name, OPC_##name)
 
 /* cat0 instructions: */
 INSTR0(BR)
 INSTR0(JUMP)
 INSTR1(KILL)
 INSTR0(END)
+INSTR0(CHSH)
+INSTR0(CHMASK)
 
 /* cat2 instructions, most 2 src but some 1 src: */
 INSTR2(ADD_F)
@@ -1329,21 +1378,22 @@ INSTR1(SQRT)
 /* cat5 instructions: */
 INSTR1(DSX)
 INSTR1(DSY)
+INSTR1F(3D, DSX)
+INSTR1F(3D, DSY)
+INSTR1(RGETPOS)
 
 static inline struct ir3_instruction *
 ir3_SAM(struct ir3_block *block, opc_t opc, type_t type,
-               unsigned wrmask, unsigned flags, unsigned samp, unsigned tex,
+               unsigned wrmask, unsigned flags, struct ir3_instruction *samp_tex,
                struct ir3_instruction *src0, struct ir3_instruction *src1)
 {
        struct ir3_instruction *sam;
        struct ir3_register *reg;
 
        sam = ir3_instr_create(block, opc);
-       sam->flags |= flags;
+       sam->flags |= flags | IR3_INSTR_S2EN;
        ir3_reg_create(sam, 0, 0)->wrmask = wrmask;
-       // temporary step, extra dummy src which will become the
-       // hvec2(samp, tex) argument:
-       ir3_reg_create(sam, 0, 0);
+       __ssa_src(sam, samp_tex, IR3_REG_HALF);
        if (src0) {
                reg = ir3_reg_create(sam, 0, IR3_REG_SSA);
                reg->wrmask = (1 << (src0->regs_count - 1)) - 1;
@@ -1354,8 +1404,6 @@ ir3_SAM(struct ir3_block *block, opc_t opc, type_t type,
                reg->instr = src1;
                reg->wrmask = (1 << (src1->regs_count - 1)) - 1;
        }
-       sam->cat5.samp = samp;
-       sam->cat5.tex  = tex;
        sam->cat5.type  = type;
 
        return sam;
@@ -1363,10 +1411,12 @@ ir3_SAM(struct ir3_block *block, opc_t opc, type_t type,
 
 /* cat6 instructions: */
 INSTR2(LDLV)
-INSTR2(LDG)
-INSTR2(LDL)
+INSTR3(LDG)
+INSTR3(LDL)
+INSTR3(LDLW)
 INSTR3(STG)
 INSTR3(STL)
+INSTR3(STLW)
 INSTR1(RESINFO)
 INSTR1(RESFMT)
 INSTR2(ATOMIC_ADD)