vc4: Implement live intervals using a CFG.
[mesa.git] / src / gallium / drivers / vc4 / vc4_qir.h
index 7ea6ec8a50f5bcc72a6f6316206bce38ef369e92..5099b7f1f1c908d3c7fa071922b6122dc6cd470e 100644 (file)
@@ -38,6 +38,7 @@
 
 #include "vc4_screen.h"
 #include "vc4_qpu_defines.h"
+#include "vc4_qpu.h"
 #include "kernel/vc4_packet.h"
 #include "pipe/p_state.h"
 
@@ -61,6 +62,12 @@ enum qfile {
         QFILE_FRAG_Y,
         QFILE_FRAG_REV_FLAG,
 
+        /**
+         * Stores an immediate value in the index field that will be used
+         * directly by qpu_load_imm().
+         */
+        QFILE_LOAD_IMM,
+
         /**
          * Stores an immediate value in the index field that can be turned
          * into a small immediate field by qpu_encode_small_immediate().
@@ -147,6 +154,8 @@ enum qop {
          * the destination
          */
         QOP_TEX_RESULT,
+
+        QOP_LOAD_IMM,
 };
 
 struct queued_qpu_inst {
@@ -332,6 +341,27 @@ struct vc4_vs_key {
         enum pipe_format attr_formats[8];
         bool is_coord;
         bool per_vertex_point_size;
+        bool clamp_color;
+};
+
+/** A basic block of QIR intructions. */
+struct qblock {
+        struct list_head link;
+
+        struct list_head instructions;
+
+        struct set *predecessors;
+        struct qblock *successors[2];
+
+        int index;
+
+        /** @{ used by vc4_qir_live_variables.c */
+        BITSET_WORD *def;
+        BITSET_WORD *use;
+        BITSET_WORD *live_in;
+        BITSET_WORD *live_out;
+        int start_ip, end_ip;
+        /** @} */
 };
 
 struct vc4_compile {
@@ -401,6 +431,9 @@ struct vc4_compile {
         struct vc4_fs_key *fs_key;
         struct vc4_vs_key *vs_key;
 
+        /* Live ranges of temps. */
+        int *temp_start, *temp_end;
+
         uint32_t *uniform_data;
         enum quniform_contents *uniform_contents;
         uint32_t uniform_array_size;
@@ -415,7 +448,10 @@ struct vc4_compile {
         struct qreg undef;
         enum qstage stage;
         uint32_t num_temps;
-        struct list_head instructions;
+
+        struct list_head blocks;
+        int next_block_index;
+        struct qblock *cur_block;
 
         struct list_head qpu_inst_list;
         uint64_t *qpu_insts;
@@ -441,6 +477,11 @@ struct vc4_compile {
 
 struct vc4_compile *qir_compile_init(void);
 void qir_compile_destroy(struct vc4_compile *c);
+struct qblock *qir_new_block(struct vc4_compile *c);
+void qir_set_emit_block(struct vc4_compile *c, struct qblock *block);
+void qir_link_blocks(struct qblock *predecessor, struct qblock *successor);
+struct qblock *qir_entry_block(struct vc4_compile *c);
+struct qblock *qir_exit_block(struct vc4_compile *c);
 struct qinst *qir_inst(enum qop op, struct qreg dst,
                        struct qreg src0, struct qreg src1);
 struct qinst *qir_inst4(enum qop op, struct qreg dst,
@@ -455,15 +496,11 @@ struct qreg qir_uniform(struct vc4_compile *c,
 void qir_schedule_instructions(struct vc4_compile *c);
 void qir_reorder_uniforms(struct vc4_compile *c);
 
-void qir_emit(struct vc4_compile *c, struct qinst *inst);
-static inline struct qinst *
-qir_emit_nodef(struct vc4_compile *c, struct qinst *inst)
-{
-        list_addtail(&inst->link, &c->instructions);
-        return inst;
-}
+struct qreg qir_emit_def(struct vc4_compile *c, struct qinst *inst);
+struct qinst *qir_emit_nondef(struct vc4_compile *c, struct qinst *inst);
 
 struct qreg qir_get_temp(struct vc4_compile *c);
+void qir_calculate_live_intervals(struct vc4_compile *c);
 int qir_get_op_nsrc(enum qop qop);
 bool qir_reg_equals(struct qreg a, struct qreg b);
 bool qir_has_side_effects(struct vc4_compile *c, struct qinst *inst);
@@ -475,16 +512,20 @@ bool qir_is_float_input(struct qinst *inst);
 bool qir_depends_on_flags(struct qinst *inst);
 bool qir_writes_r4(struct qinst *inst);
 struct qreg qir_follow_movs(struct vc4_compile *c, struct qreg reg);
+uint8_t qir_channels_written(struct qinst *inst);
 
 void qir_dump(struct vc4_compile *c);
 void qir_dump_inst(struct vc4_compile *c, struct qinst *inst);
 const char *qir_get_stage_name(enum qstage stage);
 
+void qir_validate(struct vc4_compile *c);
+
 void qir_optimize(struct vc4_compile *c);
 bool qir_opt_algebraic(struct vc4_compile *c);
 bool qir_opt_constant_folding(struct vc4_compile *c);
 bool qir_opt_copy_propagation(struct vc4_compile *c);
 bool qir_opt_dead_code(struct vc4_compile *c);
+bool qir_opt_peephole_sf(struct vc4_compile *c);
 bool qir_opt_small_immediates(struct vc4_compile *c);
 bool qir_opt_vpm(struct vc4_compile *c);
 void vc4_nir_lower_blend(nir_shader *s, struct vc4_compile *c);
@@ -516,68 +557,58 @@ qir_uniform_f(struct vc4_compile *c, float f)
 static inline struct qreg                                                \
 qir_##name(struct vc4_compile *c)                                        \
 {                                                                        \
-        struct qreg t = qir_get_temp(c);                                 \
-        qir_emit(c, qir_inst(QOP_##name, t, c->undef, c->undef));        \
-        return t;                                                        \
+        return qir_emit_def(c, qir_inst(QOP_##name, c->undef,            \
+                                        c->undef, c->undef));            \
+}                                                                        \
+static inline struct qinst *                                             \
+qir_##name##_dest(struct vc4_compile *c, struct qreg dest)               \
+{                                                                        \
+        return qir_emit_nondef(c, qir_inst(QOP_##name, dest,             \
+                                           c->undef, c->undef));         \
 }
 
 #define QIR_ALU1(name)                                                   \
 static inline struct qreg                                                \
 qir_##name(struct vc4_compile *c, struct qreg a)                         \
 {                                                                        \
-        struct qreg t = qir_get_temp(c);                                 \
-        qir_emit(c, qir_inst(QOP_##name, t, a, c->undef));               \
-        return t;                                                        \
+        return qir_emit_def(c, qir_inst(QOP_##name, c->undef,            \
+                                        a, c->undef));                   \
 }                                                                        \
 static inline struct qinst *                                             \
 qir_##name##_dest(struct vc4_compile *c, struct qreg dest,               \
                   struct qreg a)                                         \
 {                                                                        \
-        return qir_emit_nodef(c, qir_inst(QOP_##name, dest, a,           \
-                                          c->undef));                    \
+        return qir_emit_nondef(c, qir_inst(QOP_##name, dest, a,          \
+                                           c->undef));                   \
 }
 
 #define QIR_ALU2(name)                                                   \
 static inline struct qreg                                                \
 qir_##name(struct vc4_compile *c, struct qreg a, struct qreg b)          \
 {                                                                        \
-        struct qreg t = qir_get_temp(c);                                 \
-        qir_emit(c, qir_inst(QOP_##name, t, a, b));                      \
-        return t;                                                        \
+        return qir_emit_def(c, qir_inst(QOP_##name, c->undef, a, b));    \
 }                                                                        \
-static inline void                                                       \
+static inline struct qinst *                                             \
 qir_##name##_dest(struct vc4_compile *c, struct qreg dest,               \
                   struct qreg a, struct qreg b)                          \
 {                                                                        \
-        qir_emit_nodef(c, qir_inst(QOP_##name, dest, a, b));             \
+        return qir_emit_nondef(c, qir_inst(QOP_##name, dest, a, b));     \
 }
 
 #define QIR_NODST_1(name)                                               \
 static inline struct qinst *                                            \
 qir_##name(struct vc4_compile *c, struct qreg a)                        \
 {                                                                       \
-        struct qinst *inst = qir_inst(QOP_##name, c->undef,             \
-                                      a, c->undef);                     \
-        qir_emit(c, inst);                                              \
-        return inst;                                                    \
+        return qir_emit_nondef(c, qir_inst(QOP_##name, c->undef,        \
+                                           a, c->undef));               \
 }
 
 #define QIR_NODST_2(name)                                               \
 static inline struct qinst *                                            \
 qir_##name(struct vc4_compile *c, struct qreg a, struct qreg b)         \
 {                                                                       \
-        struct qinst *inst = qir_inst(QOP_##name, c->undef,             \
-                                      a, b);                            \
-        qir_emit(c, inst);                                              \
-        return inst;                                                    \
-}
-
-#define QIR_PACK(name)                                                   \
-static inline struct qreg                                                \
-qir_##name(struct vc4_compile *c, struct qreg dest, struct qreg a)       \
-{                                                                        \
-        qir_emit_nodef(c, qir_inst(QOP_##name, dest, a, c->undef));      \
-        return dest;                                                     \
+        return qir_emit_nondef(c, qir_inst(QOP_##name, c->undef,        \
+                                           a, b));                      \
 }
 
 #define QIR_PAYLOAD(name)                                                \
@@ -590,7 +621,8 @@ qir_##name(struct vc4_compile *c)                                        \
         *payload = qir_get_temp(c);                                      \
         struct qinst *inst = qir_inst(QOP_##name, *payload,              \
                                       c->undef, c->undef);               \
-        list_add(&inst->link, &c->instructions);                         \
+        struct qblock *entry = qir_entry_block(c);                       \
+        list_add(&inst->link, &entry->instructions);                     \
         c->defs[payload->index] = inst;                                  \
         return *payload;                                                 \
 }
@@ -649,7 +681,7 @@ qir_SEL(struct vc4_compile *c, uint8_t cond, struct qreg src0, struct qreg src1)
         struct qinst *a = qir_MOV_dest(c, t, src0);
         struct qinst *b = qir_MOV_dest(c, t, src1);
         a->cond = cond;
-        b->cond = cond ^ 1;
+        b->cond = qpu_cond_complement(cond);
         return t;
 }
 
@@ -690,9 +722,7 @@ qir_PACK_8_F(struct vc4_compile *c, struct qreg dest, struct qreg val, int chan)
 {
         assert(!dest.pack);
         dest.pack = QPU_PACK_MUL_8A + chan;
-        qir_emit(c, qir_inst(QOP_MMOV, dest, val, c->undef));
-        if (dest.file == QFILE_TEMP)
-                c->defs[dest.index] = NULL;
+        qir_emit_nondef(c, qir_inst(QOP_MMOV, dest, val, c->undef));
 }
 
 static inline struct qreg
@@ -717,4 +747,37 @@ qir_VPM_WRITE(struct vc4_compile *c, struct qreg val)
         qir_MOV_dest(c, qir_reg(QFILE_VPM, 0), val);
 }
 
+static inline struct qreg
+qir_LOAD_IMM(struct vc4_compile *c, uint32_t val)
+{
+        return qir_emit_def(c, qir_inst(QOP_LOAD_IMM, c->undef,
+                                        qir_reg(QFILE_LOAD_IMM, val), c->undef));
+}
+
+#define qir_for_each_block(block, c)                                    \
+        list_for_each_entry(struct qblock, block, &c->blocks, link)
+
+#define qir_for_each_block_rev(block, c)                                \
+        list_for_each_entry_rev(struct qblock, block, &c->blocks, link)
+
+/* Loop over the non-NULL members of the successors array. */
+#define qir_for_each_successor(succ, block)                             \
+        for (struct qblock *succ = block->successors[0];                \
+             succ != NULL;                                              \
+             succ = (succ == block->successors[1] ? NULL :              \
+                     block->successors[1]))
+
+#define qir_for_each_inst(inst, block)                                  \
+        list_for_each_entry(struct qinst, inst, &block->instructions, link)
+
+#define qir_for_each_inst_rev(inst, block)                                  \
+        list_for_each_entry_rev(struct qinst, inst, &block->instructions, link)
+
+#define qir_for_each_inst_safe(inst, block)                             \
+        list_for_each_entry_safe(struct qinst, inst, &block->instructions, link)
+
+#define qir_for_each_inst_inorder(inst, c)                              \
+        qir_for_each_block(_block, c)                                   \
+                qir_for_each_inst(inst, _block)
+
 #endif /* VC4_QIR_H */