nir: Use a tagged pointer for nir_src parents
authorAlyssa Rosenzweig <alyssa@rosenzweig.io>
Mon, 14 Aug 2023 14:38:03 +0000 (10:38 -0400)
committerAlyssa Rosenzweig <alyssa@rosenzweig.io>
Tue, 10 Oct 2023 08:58:05 +0000 (04:58 -0400)
This allows us to pack the is_if boolean into the bottom bit of the parent
pointer, eliminating the boolean and hence shrinking the nir_src by 8 bytes (due
to the extra 63 bits of padding incurred in the old layout).

Because all access is forced through helpers now, this is a local change.

Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
Reviewed-by: Rhys Perry <pendingchaos02@gmail.com>
Acked-by: Faith Ekstrand <faith.ekstrand@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/24671>

src/compiler/nir/nir.h

index 0597cdd..dbab63a 100644 (file)
@@ -997,56 +997,75 @@ struct nir_src;
 struct nir_if;
 
 typedef struct nir_src {
-   union {
-      /** Instruction that consumes this value as a source. */
-      nir_instr *renamed_parent_instr;
-      struct nir_if *parent_if;
-   };
+   /* Instruction or if-statement that consumes this value as a source. This
+    * should only be accessed through nir_src_* helpers.
+    *
+    * Internally, it is a tagged pointer to a nir_instr or nir_if.
+    */
+   uintptr_t _parent;
 
    struct list_head use_link;
    nir_def *ssa;
-
-   bool is_if;
 } nir_src;
 
+/* Layout of the _parent pointer. Bottom bit is set for nir_if parents (clear
+ * for nir_instr parents). Remaining bits are the pointer.
+ */
+#define NIR_SRC_PARENT_IS_IF (0x1)
+#define NIR_SRC_PARENT_MASK (~((uintptr_t) NIR_SRC_PARENT_IS_IF))
+
 static inline bool
 nir_src_is_if(const nir_src *src)
 {
-   return src->is_if;
+   return src->_parent & NIR_SRC_PARENT_IS_IF;
 }
 
 static inline nir_instr *
 nir_src_parent_instr(const nir_src *src)
 {
    assert(!nir_src_is_if(src));
-   return src->renamed_parent_instr;
+
+   /* Because it is not an if, the tag is 0, therefore we do not need to mask */
+   return (nir_instr *)(src->_parent);
 }
 
 static inline struct nir_if *
 nir_src_parent_if(const nir_src *src)
 {
    assert(nir_src_is_if(src));
-   return src->parent_if;
+
+   /* Because it is an if, the tag is 1, so we need to mask */
+   return (struct nir_if *)(src->_parent & NIR_SRC_PARENT_MASK);
+}
+
+static inline void
+_nir_src_set_parent(nir_src *src, void *parent, bool is_if)
+{
+    uintptr_t ptr = (uintptr_t) parent;
+    assert((ptr & ~NIR_SRC_PARENT_MASK) == 0 && "pointer must be aligned");
+
+    if (is_if)
+       ptr |= NIR_SRC_PARENT_IS_IF;
+
+    src->_parent = ptr;
 }
 
 static inline void
 nir_src_set_parent_instr(nir_src *src, nir_instr *parent_instr)
 {
-   src->is_if = false;
-   src->renamed_parent_instr = parent_instr;
+   _nir_src_set_parent(src, parent_instr, false);
 }
 
 static inline void
 nir_src_set_parent_if(nir_src *src, struct nir_if *parent_if)
 {
-   src->is_if = true;
-   src->parent_if = parent_if;
+   _nir_src_set_parent(src, parent_if, true);
 }
 
 static inline nir_src
 nir_src_init(void)
 {
-   nir_src src = { { NULL } };
+   nir_src src = { 0 };
    return src;
 }