Mesa (main): freedreno/ir3: Add float immed "FLUT" support

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Tue Jul 13 14:57:40 UTC 2021


Module: Mesa
Branch: main
Commit: 7f5a01a47dc87b9513aa156030bb8d03963ba40f
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=7f5a01a47dc87b9513aa156030bb8d03963ba40f

Author: Rob Clark <robdclark at chromium.org>
Date:   Mon Jan 25 09:43:24 2021 -0800

freedreno/ir3: Add float immed "FLUT" support

We can encode a limited set of float immeds into cat2 instructions,
using hw's float lookup table (FLUT) feature.

Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/36
Signed-off-by: Rob Clark <robdclark at chromium.org>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/8705>

---

 src/freedreno/ir3/ir3.c    | 51 ++++++++++++++++++++++++++++++++++++++++++----
 src/freedreno/ir3/ir3.h    |  2 ++
 src/freedreno/ir3/ir3_cp.c | 28 +++++++++++++------------
 3 files changed, 64 insertions(+), 17 deletions(-)

diff --git a/src/freedreno/ir3/ir3.c b/src/freedreno/ir3/ir3.c
index 909228de328..41d10393895 100644
--- a/src/freedreno/ir3/ir3.c
+++ b/src/freedreno/ir3/ir3.c
@@ -31,6 +31,7 @@
 #include <string.h>
 
 #include "util/bitscan.h"
+#include "util/half_float.h"
 #include "util/ralloc.h"
 #include "util/u_math.h"
 
@@ -701,6 +702,51 @@ ir3_fixup_src_type(struct ir3_instruction *instr)
    }
 }
 
+/**
+ * Map a floating point immed to FLUT (float lookup table) value,
+ * returns negative for immediates that cannot be mapped.
+ */
+int
+ir3_flut(struct ir3_register *src_reg)
+{
+   static const struct {
+      uint32_t f32;
+      uint16_t f16;
+   } flut[] = {
+         { .f32 = 0x00000000, .f16 = 0x0000 },    /* 0.0 */
+         { .f32 = 0x3f000000, .f16 = 0x3800 },    /* 0.5 */
+         { .f32 = 0x3f800000, .f16 = 0x3c00 },    /* 1.0 */
+         { .f32 = 0x40000000, .f16 = 0x4000 },    /* 2.0 */
+         { .f32 = 0x402df854, .f16 = 0x4170 },    /* e */
+         { .f32 = 0x40490fdb, .f16 = 0x4248 },    /* pi */
+         { .f32 = 0x3ea2f983, .f16 = 0x3518 },    /* 1/pi */
+         { .f32 = 0x3f317218, .f16 = 0x398c },    /* 1/log2(e) */
+         { .f32 = 0x3fb8aa3b, .f16 = 0x3dc5 },    /* log2(e) */
+         { .f32 = 0x3e9a209b, .f16 = 0x34d1 },    /* 1/log2(10) */
+         { .f32 = 0x40549a78, .f16 = 0x42a5 },    /* log2(10) */
+         { .f32 = 0x40800000, .f16 = 0x4400 },    /* 4.0 */
+   };
+
+   if (src_reg->flags & IR3_REG_HALF) {
+      /* Note that half-float immeds are already lowered to 16b in nir: */
+      uint32_t imm = src_reg->uim_val;
+      for (unsigned i = 0; i < ARRAY_SIZE(flut); i++) {
+         if (flut[i].f16 == imm) {
+            return i;
+         }
+      }
+   } else {
+      uint32_t imm = src_reg->uim_val;
+      for (unsigned i = 0; i < ARRAY_SIZE(flut); i++) {
+         if (flut[i].f32 == imm) {
+            return i;
+         }
+      }
+   }
+
+   return -1;
+}
+
 static unsigned
 cp_flags(unsigned flags)
 {
@@ -782,10 +828,7 @@ ir3_valid_flags(struct ir3_instruction *instr, unsigned n, unsigned flags)
       break;
    case 2:
       valid_flags = ir3_cat2_absneg(instr->opc) | IR3_REG_CONST |
-                    IR3_REG_RELATIV | IR3_REG_SHARED;
-
-      if (ir3_cat2_int(instr->opc))
-         valid_flags |= IR3_REG_IMMED;
+                    IR3_REG_RELATIV | IR3_REG_IMMED | IR3_REG_SHARED;
 
       if (flags & ~valid_flags)
          return false;
diff --git a/src/freedreno/ir3/ir3.h b/src/freedreno/ir3/ir3.h
index 48f8192a702..53590ed8afb 100644
--- a/src/freedreno/ir3/ir3.h
+++ b/src/freedreno/ir3/ir3.h
@@ -700,6 +700,8 @@ 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);
 
+int ir3_flut(struct ir3_register *src_reg);
+
 bool ir3_valid_flags(struct ir3_instruction *instr, unsigned n, unsigned flags);
 
 #include "util/set.h"
diff --git a/src/freedreno/ir3/ir3_cp.c b/src/freedreno/ir3/ir3_cp.c
index 78a5247059a..50c43f3303f 100644
--- a/src/freedreno/ir3/ir3_cp.c
+++ b/src/freedreno/ir3/ir3_cp.c
@@ -440,22 +440,24 @@ reg_cp(struct ir3_cp_ctx *ctx, struct ir3_instruction *instr,
          return true;
       }
 
-      /* NOTE: seems we can only do immed integers, so don't
-       * need to care about float.  But we do need to handle
-       * abs/neg *before* checking that the immediate requires
-       * few enough bits to encode:
-       *
-       * TODO: do we need to do something to avoid accidentally
-       * catching a float immed?
-       */
       if (src_reg->flags & IR3_REG_IMMED) {
          int32_t iim_val = src_reg->iim_val;
 
          debug_assert((opc_cat(instr->opc) == 1) ||
-                      (opc_cat(instr->opc) == 6) || is_meta(instr) ||
-                      ir3_cat2_int(instr->opc) ||
+                      (opc_cat(instr->opc) == 2) ||
+                      (opc_cat(instr->opc) == 6) ||
+                      is_meta(instr) ||
                       (is_mad(instr->opc) && (n == 0)));
 
+         if ((opc_cat(instr->opc) == 2) &&
+               !ir3_cat2_int(instr->opc)) {
+            iim_val = ir3_flut(src_reg);
+            if (iim_val < 0) {
+               /* Fall back to trying to load the immediate as a const: */
+               return lower_immed(ctx, instr, n, src_reg, new_flags);
+            }
+         }
+
          if (new_flags & IR3_REG_SABS)
             iim_val = abs(iim_val);
 
@@ -476,9 +478,9 @@ reg_cp(struct ir3_cp_ctx *ctx, struct ir3_instruction *instr,
             instr->srcs[n] = src_reg;
 
             return true;
-         } else if (lower_immed(ctx, instr, n, src_reg, new_flags)) {
-            /* Fell back to loading the immediate as a const */
-            return true;
+         } else {
+            /* Fall back to trying to load the immediate as a const: */
+            return lower_immed(ctx, instr, n, src_reg, new_flags);
          }
       }
    }



More information about the mesa-commit mailing list