turnip: Move tu_bo functions to tu_drm.c
[mesa.git] / src / freedreno / ir3 / ir3_ra.h
index f9c2155b7df18442f2d6ea346ac85b54e92caf74..d26f5b38966e5a2a60de6dedd2c8294451d850ee 100644 (file)
 #ifndef IR3_RA_H_
 #define IR3_RA_H_
 
-//#include "util/u_math.h"
-//#include "util/register_allocate.h"
-//#include "util/ralloc.h"
-#include "util/bitset.h"
+#include <setjmp.h>
 
-//#include "ir3.h"
-//#include "ir3_compiler.h"
+#include "util/bitset.h"
 
 
 static const unsigned class_sizes[] = {
@@ -63,9 +59,27 @@ static const unsigned high_class_sizes[] = {
 #define NUM_HIGH_REGS        (4 * 8)   /* r48 to r55 */
 #define FIRST_HIGH_REG       (4 * 48)
 /* Number of virtual regs in a given class: */
-#define CLASS_REGS(i)        (NUM_REGS - (class_sizes[i] - 1))
-#define HALF_CLASS_REGS(i)   (NUM_REGS - (half_class_sizes[i] - 1))
-#define HIGH_CLASS_REGS(i)   (NUM_HIGH_REGS - (high_class_sizes[i] - 1))
+
+static inline unsigned CLASS_REGS(unsigned i)
+{
+       assert(i < class_count);
+
+       return (NUM_REGS - (class_sizes[i] - 1));
+}
+
+static inline unsigned HALF_CLASS_REGS(unsigned i)
+{
+       assert(i < half_class_count);
+
+       return (NUM_REGS - (half_class_sizes[i] - 1));
+}
+
+static inline unsigned HIGH_CLASS_REGS(unsigned i)
+{
+       assert(i < high_class_count);
+
+       return (NUM_HIGH_REGS - (high_class_sizes[i] - 1));
+}
 
 #define HALF_OFFSET          (class_count)
 #define HIGH_OFFSET          (class_count + half_class_count)
@@ -76,6 +90,34 @@ struct ir3_ra_reg_set {
        unsigned int classes[class_count];
        unsigned int half_classes[half_class_count];
        unsigned int high_classes[high_class_count];
+
+       /* pre-fetched tex dst is limited, on current gens to regs
+        * 0x3f and below.  An additional register class, with one
+        * vreg, that is setup to conflict with any regs above that
+        * limit.
+        */
+       unsigned prefetch_exclude_class;
+       unsigned prefetch_exclude_reg;
+
+       /* The virtual register space flattens out all the classes,
+        * starting with full, followed by half and then high, ie:
+        *
+        *   scalar full  (starting at zero)
+        *   vec2 full
+        *   vec3 full
+        *   ...
+        *   vecN full
+        *   scalar half  (starting at first_half_reg)
+        *   vec2 half
+        *   ...
+        *   vecN half
+        *   scalar high  (starting at first_high_reg)
+        *   ...
+        *   vecN high
+        *
+        */
+       unsigned first_half_reg, first_high_reg;
+
        /* maps flat virtual register space to base gpr: */
        uint16_t *ra_reg_to_gpr;
        /* maps cls,gpr to flat virtual register space: */
@@ -112,6 +154,9 @@ struct ir3_ra_ctx {
        bool scalar_pass;
 
        unsigned alloc_count;
+       unsigned r0_xyz_nodes; /* ra node numbers for r0.[xyz] precolors */
+       unsigned hr0_xyz_nodes; /* ra node numbers for hr0.[xyz] precolors */
+       unsigned prefetch_exclude_node;
        /* one per class, plus one slot for arrays: */
        unsigned class_alloc_count[total_class_count + 1];
        unsigned class_base[total_class_count + 1];
@@ -122,20 +167,34 @@ struct ir3_ra_ctx {
        /* Mapping vreg name back to instruction, used select reg callback: */
        struct hash_table *name_to_instr;
 
-       /* Tracking for max half/full register assigned.  We don't need to
-        * track high registers.
-        *
-        * The feedback about registers used in first pass is used to choose
-        * a target register usage to round-robin between in the 2nd pass.
-        */
-       unsigned max_assigned;
-       unsigned max_half_assigned;
-
        /* Tracking for select_reg callback */
        unsigned start_search_reg;
        unsigned max_target;
+
+       /* Temporary buffer for def/use iterators
+        *
+        * The worst case should probably be an array w/ relative access (ie.
+        * all elements are def'd or use'd), and that can't be larger than
+        * the number of registers.
+        *
+        * NOTE we could declare this on the stack if needed, but I don't
+        * think there is a need for nested iterators.
+        */
+       unsigned namebuf[NUM_REGS];
+       unsigned namecnt, nameidx;
+
+       /* Error handling: */
+       jmp_buf jmp_env;
 };
 
+#define ra_assert(ctx, expr) do { \
+               if (!(expr)) { \
+                       _debug_printf("RA: %s:%u: %s: Assertion `%s' failed.\n", __FILE__, __LINE__, __func__, #expr); \
+                       longjmp((ctx)->jmp_env, -1); \
+               } \
+       } while (0)
+#define ra_unreachable(ctx, str) ra_assert(ctx, !str)
+
 static inline int
 ra_name(struct ir3_ra_ctx *ctx, struct ir3_ra_instr_data *id)
 {
@@ -168,20 +227,153 @@ scalar_name(struct ir3_ra_ctx *ctx, struct ir3_instruction *instr, unsigned n)
        return ra_name(ctx, &ctx->instrd[instr->ip]) + n;
 }
 
-static inline bool
-writes_gpr(struct ir3_instruction *instr)
+#define NO_NAME ~0
+
+/*
+ * Iterators to iterate the vreg names of an instructions def's and use's
+ */
+
+static inline unsigned
+__ra_name_cnt(struct ir3_ra_ctx *ctx, 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 == regid(REG_A0, 0)) ||
-                       (reg->num == regid(REG_P0, 0)))
-               return false;
-       return true;
+       if (!instr)
+               return 0;
+
+       /* Filter special cases, ie. writes to a0.x or p0.x, or non-ssa: */
+       if (!writes_gpr(instr) || (instr->regs[0]->flags & IR3_REG_ARRAY))
+               return 0;
+
+       /* in scalar pass, we aren't considering virtual register classes, ie.
+        * if an instruction writes a vec2, then it defines two different scalar
+        * register names.
+        */
+       if (ctx->scalar_pass)
+               return dest_regs(instr);
+
+       return 1;
+}
+
+#define foreach_name_n(__name, __n, __ctx, __instr) \
+       for (unsigned __cnt = __ra_name_cnt(__ctx, __instr), __n = 0, __name; \
+            (__n < __cnt) && ({__name = scalar_name(__ctx, __instr, __n); 1;}); __n++)
+
+#define foreach_name(__name, __ctx, __instr) \
+       foreach_name_n(__name, __n, __ctx, __instr)
+
+static inline unsigned
+__ra_itr_pop(struct ir3_ra_ctx *ctx)
+{
+       if (ctx->nameidx < ctx->namecnt)
+               return ctx->namebuf[ctx->nameidx++];
+       return NO_NAME;
+}
+
+static inline void
+__ra_itr_push(struct ir3_ra_ctx *ctx, unsigned name)
+{
+       assert(ctx->namecnt < ARRAY_SIZE(ctx->namebuf));
+       ctx->namebuf[ctx->namecnt++] = name;
+}
+
+static inline unsigned
+__ra_init_def_itr(struct ir3_ra_ctx *ctx, struct ir3_instruction *instr)
+{
+       /* nested use is not supported: */
+       assert(ctx->namecnt == ctx->nameidx);
+
+       ctx->namecnt = ctx->nameidx = 0;
+
+       if (!writes_gpr(instr))
+               return NO_NAME;
+
+       struct ir3_ra_instr_data *id = &ctx->instrd[instr->ip];
+       struct ir3_register *dst = instr->regs[0];
+
+       if (dst->flags & IR3_REG_ARRAY) {
+               struct ir3_array *arr = ir3_lookup_array(ctx->ir, dst->array.id);
+
+               /* indirect write is treated like a write to all array
+                * elements, since we don't know which one is actually
+                * written:
+                */
+               if (dst->flags & IR3_REG_RELATIV) {
+                       for (unsigned i = 0; i < arr->length; i++) {
+                               __ra_itr_push(ctx, arr->base + i);
+                       }
+               } else {
+                       __ra_itr_push(ctx, arr->base + dst->array.offset);
+                       debug_assert(dst->array.offset < arr->length);
+               }
+       } else if (id->defn == instr) {
+               foreach_name_n (name, i, ctx, instr) {
+                       /* tex instructions actually have a wrmask, and
+                        * don't touch masked out components.  We can't do
+                        * anything useful about that in the first pass,
+                        * but in the scalar pass we can realize these
+                        * registers are available:
+                        */
+                       if (ctx->scalar_pass && is_tex_or_prefetch(instr) &&
+                                       !(instr->regs[0]->wrmask & (1 << i)))
+                               continue;
+                       __ra_itr_push(ctx, name);
+               }
+       }
+
+       return __ra_itr_pop(ctx);
 }
 
+static inline unsigned
+__ra_init_use_itr(struct ir3_ra_ctx *ctx, struct ir3_instruction *instr)
+{
+       /* nested use is not supported: */
+       assert(ctx->namecnt == ctx->nameidx);
+
+       ctx->namecnt = ctx->nameidx = 0;
+
+       foreach_src (reg, instr) {
+               if (reg->flags & IR3_REG_ARRAY) {
+                       struct ir3_array *arr =
+                               ir3_lookup_array(ctx->ir, reg->array.id);
+
+                       /* indirect read is treated like a read from all array
+                        * elements, since we don't know which one is actually
+                        * read:
+                        */
+                       if (reg->flags & IR3_REG_RELATIV) {
+                               for (unsigned i = 0; i < arr->length; i++) {
+                                       __ra_itr_push(ctx, arr->base + i);
+                               }
+                       } else {
+                               __ra_itr_push(ctx, arr->base + reg->array.offset);
+                               debug_assert(reg->array.offset < arr->length);
+                       }
+               } else {
+                       foreach_name_n (name, i, ctx, reg->instr) {
+                               /* split takes a src w/ wrmask potentially greater
+                                * than 0x1, but it really only cares about a single
+                                * component.  This shows up in splits coming out of
+                                * a tex instruction w/ wrmask=.z, for example.
+                                */
+                               if (ctx->scalar_pass && (instr->opc == OPC_META_SPLIT) &&
+                                               !(i == instr->split.off))
+                                       continue;
+                               __ra_itr_push(ctx, name);
+                       }
+               }
+       }
+
+       return __ra_itr_pop(ctx);
+}
+
+#define foreach_def(__name, __ctx, __instr) \
+       for (unsigned __name = __ra_init_def_itr(__ctx, __instr); \
+            __name != NO_NAME; __name = __ra_itr_pop(__ctx))
+
+#define foreach_use(__name, __ctx, __instr) \
+       for (unsigned __name = __ra_init_use_itr(__ctx, __instr); \
+            __name != NO_NAME; __name = __ra_itr_pop(__ctx))
+
 int ra_size_to_class(unsigned sz, bool half, bool high);
+int ra_class_to_size(unsigned class, bool *half, bool *high);
 
 #endif  /* IR3_RA_H_ */