[Mesa-dev] [PATCH 03/11] mesa/st: Add helper classes for array merging and interleaving

Gert Wollny gw.fossdev at gmail.com
Fri Feb 9 10:11:08 UTC 2018


This class implements the live range merge and component interleave 
remapping logic.

Signed-off-by: Gert Wollny <gw.fossdev at gmail.com>
---
 src/mesa/Makefile.sources                          |   2 +
 src/mesa/meson.build                               |   2 +
 .../state_tracker/st_glsl_to_tgsi_array_merge.cpp  | 283 +++++++++++++++++++++
 .../state_tracker/st_glsl_to_tgsi_array_merge.h    | 116 +++++++++
 4 files changed, 403 insertions(+)
 create mode 100644 src/mesa/state_tracker/st_glsl_to_tgsi_array_merge.cpp
 create mode 100644 src/mesa/state_tracker/st_glsl_to_tgsi_array_merge.h

diff --git a/src/mesa/Makefile.sources b/src/mesa/Makefile.sources
index 0a9aad52d0..789feeb105 100644
--- a/src/mesa/Makefile.sources
+++ b/src/mesa/Makefile.sources
@@ -519,6 +519,8 @@ STATETRACKER_FILES = \
 	state_tracker/st_glsl_to_nir.cpp \
 	state_tracker/st_glsl_to_tgsi.cpp \
 	state_tracker/st_glsl_to_tgsi.h \
+	state_tracker/st_glsl_to_tgsi_array_merge.cpp \
+	state_tracker/st_glsl_to_tgsi_array_merge.h \
 	state_tracker/st_glsl_to_tgsi_private.cpp \
 	state_tracker/st_glsl_to_tgsi_private.h \
 	state_tracker/st_glsl_to_tgsi_temprename.cpp \
diff --git a/src/mesa/meson.build b/src/mesa/meson.build
index aa27d59264..2ec50623aa 100644
--- a/src/mesa/meson.build
+++ b/src/mesa/meson.build
@@ -566,6 +566,8 @@ files_libmesa_gallium = files(
   'state_tracker/st_glsl_to_nir.cpp',
   'state_tracker/st_glsl_to_tgsi.cpp',
   'state_tracker/st_glsl_to_tgsi.h',
+  'state_tracker/st_glsl_to_tgsi_array_merge.cpp',
+  'state_tracker/st_glsl_to_tgsi_array_merge.h',
   'state_tracker/st_glsl_to_tgsi_private.cpp',
   'state_tracker/st_glsl_to_tgsi_private.h',
   'state_tracker/st_glsl_to_tgsi_temprename.cpp',
diff --git a/src/mesa/state_tracker/st_glsl_to_tgsi_array_merge.cpp b/src/mesa/state_tracker/st_glsl_to_tgsi_array_merge.cpp
new file mode 100644
index 0000000000..52d0d81796
--- /dev/null
+++ b/src/mesa/state_tracker/st_glsl_to_tgsi_array_merge.cpp
@@ -0,0 +1,283 @@
+/*
+ * Copyright © 2017 Gert Wollny
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "program/prog_instruction.h"
+#include "util/u_math.h"
+#include <ostream>
+#include <cassert>
+#include <algorithm>
+
+#include <iostream>
+
+#include "st_glsl_to_tgsi_array_merge.h"
+
+#if __cplusplus >= 201402L
+#include <memory>
+using std::unique_ptr;
+using std::make_unique;
+#endif
+
+namespace tgsi_array_merge {
+
+array_remapping::array_remapping():
+   target_id(0),
+   reswizzle(false),
+   finalized(true)
+{
+}
+
+array_remapping::array_remapping(int trgt_array_id, unsigned src_access_mask):
+   target_id(trgt_array_id),
+   original_src_access_mask(src_access_mask),
+   reswizzle(false),
+   finalized(false)
+{
+}
+
+array_remapping::array_remapping(int trgt_array_id, int trgt_access_mask,
+                                 int src_access_mask):
+   target_id(trgt_array_id),
+   summary_access_mask(trgt_access_mask),
+   original_src_access_mask(src_access_mask),
+   reswizzle(true),
+   finalized(false)
+{
+   for (int i = 0; i < 4; ++i) {
+      read_swizzle_map[i] = -1;
+      writemask_map[i] = 0;
+   }
+
+   int src_swizzle_bit = 1;
+   int next_free_swizzle_bit = 1;
+   int k = 0;
+   bool skip = true;
+   unsigned last_src_bit = util_last_bit(src_access_mask);
+
+   for (unsigned i = 0; i < 4; ++i, src_swizzle_bit <<= 1) {
+
+      /* The swizzle mapping fills the unused slots with the last used
+       * component (think temp[A].xyyy) and maps the write mask accordingly.
+       * Hence, if (i < last_src_bit) skip is true and mappings are only added
+       * for used the components, but for (i >= last_src_bit) the mapping
+       * is set for remaining slots.
+       */
+      if (skip && !(src_swizzle_bit & src_access_mask))
+         continue;
+      skip = (i < last_src_bit);
+
+      /* Find the next free access slot in the target.*/
+      while ((trgt_access_mask & next_free_swizzle_bit) &&
+             k < 4) {
+         next_free_swizzle_bit <<= 1;
+         ++k;
+      }
+      assert(k < 4 &&
+             "Interleaved array would have more then four components");
+
+      /* Set the mapping for this component. */
+      read_swizzle_map[i] = k;
+      writemask_map[i] = next_free_swizzle_bit;
+      trgt_access_mask |= next_free_swizzle_bit;
+
+      /* Update the joined access mask if we didn't just fill the mapping.*/
+      if (src_swizzle_bit & src_access_mask)
+         summary_access_mask |= next_free_swizzle_bit;
+   }
+}
+
+int array_remapping::map_writemask(int writemask_to_map) const
+{
+   assert(is_valid());
+   if (!reswizzle)
+      return writemask_to_map;
+
+   assert(original_src_access_mask & writemask_to_map);
+   int result = 0;
+   for (int i = 0; i < 4; ++i) {
+      if (1 << i & writemask_to_map)
+         result |= writemask_map[i];
+   }
+   return result;
+}
+
+uint16_t array_remapping::move_read_swizzles(uint16_t original_swizzle) const
+{
+   assert(is_valid());
+   if (!reswizzle)
+      return original_swizzle;
+
+   /* Since
+    *
+    *   dst.zw = src.xy in glsl actually is MOV dst.__zw src.__xy
+    *
+    * when interleaving the arrays the source swizzles must be moved
+    * according to the changed dst write mask.
+    */
+   uint16_t out_swizzle = 0;
+   for (int idx = 0; idx < 4; ++idx) {
+      uint16_t orig_swz = GET_SWZ(original_swizzle, idx);
+      int new_idx = read_swizzle_map[idx];
+      if (new_idx >= 0)
+         out_swizzle |= orig_swz << 3 * new_idx;
+   }
+   return out_swizzle;
+}
+
+int array_remapping::map_one_swizzle(int swizzle_to_map) const
+{
+   if (!reswizzle)
+      return swizzle_to_map;
+
+   assert(read_swizzle_map[swizzle_to_map] >= 0);
+   return read_swizzle_map[swizzle_to_map];
+}
+
+uint16_t array_remapping::map_swizzles(uint16_t old_swizzle) const
+{
+   if (!reswizzle)
+      return old_swizzle;
+
+   uint16_t out_swizzle = 0;
+   for (int idx = 0; idx < 4; ++idx) {
+      uint16_t swz = map_one_swizzle(GET_SWZ(old_swizzle, idx));
+      out_swizzle |= swz << 3 * idx;
+   }
+   return out_swizzle;
+}
+
+void array_remapping::print(std::ostream& os) const
+{
+   static const char xyzw[] = "xyzw";
+   if (is_valid()) {
+      os << "[aid: " << target_id;
+
+      if (reswizzle) {
+         os << " write-swz: ";
+         for (int i = 0; i < 4; ++i) {
+            if (1 << i & original_src_access_mask) {
+               switch (writemask_map[i]) {
+               case 1: os << "x"; break;
+               case 2: os << "y"; break;
+               case 4: os << "z"; break;
+               case 8: os << "w"; break;
+               }
+            } else {
+               os << "_";
+            }
+         }
+         os << ", read-swz: ";
+         for (int i = 0; i < 4; ++i) {
+            if (1 << i & original_src_access_mask && read_swizzle_map[i] >= 0)
+               os << xyzw[read_swizzle_map[i]];
+                else
+               os << "_";
+         }
+      }
+      os << "]";
+   } else {
+      os << "[unused]";
+   }
+}
+
+void array_remapping::finalize_mappings(array_remapping *arr_map)
+{
+   assert(is_valid());
+
+   array_remapping& forward_map = arr_map[target_id];
+
+   /* If no valid map is provided than we have a final target array
+    * at the target_id index, no finalization needed. */
+   if (!forward_map.is_valid())
+      return;
+
+   /* This mappoints to another mapped array that may need finalization. */
+   if (!forward_map.is_finalized())
+      forward_map.finalize_mappings(arr_map);
+
+   /* Now finalize this mapping by translating the map to represent
+    * a mapping to a final target array (i.e. one that is not mapped).
+    * This is only necessary if the target_id array map provides reswizzling.
+    */
+   if (forward_map.reswizzle) {
+
+      /* If this mapping doesn't have a reswizzle map build one now.*/
+      if (!reswizzle) {
+         for (int i = 0; i < 4; ++i) {
+            if (1 << i  & original_src_access_mask) {
+               read_swizzle_map[i] = i;
+               writemask_map[i] = 1 << i;
+            } else {
+               read_swizzle_map[i] = -1;
+               writemask_map[i] = 0;
+            }
+         }
+         reswizzle = true;
+      }
+
+      /* Propagate the swizzle mapping of the forward map.*/
+      for (int i = 0; i < 4; ++i) {
+         if ((1 << i & original_src_access_mask) == 0)
+            continue;
+         read_swizzle_map[i] = forward_map.map_one_swizzle(read_swizzle_map[i]);
+         writemask_map[i] = forward_map.map_writemask(writemask_map[i]);
+      }
+
+   }
+
+   /* Now we can skip the intermediate mapping.*/
+   target_id = forward_map.target_id;
+   finalized = true;
+}
+
+/* Required by the unit tests */
+bool operator == (const array_remapping& lhs, const array_remapping& rhs)
+{
+   if (lhs.target_id != rhs.target_id)
+      return false;
+
+   if (lhs.target_id == 0)
+      return true;
+
+   if (lhs.reswizzle) {
+      if (!rhs.reswizzle)
+         return false;
+
+      if (lhs.original_src_access_mask != rhs.original_src_access_mask)
+         return false;
+
+      for (int i = 0; i < 4; ++i) {
+         if (1 << i & lhs.original_src_access_mask) {
+            if (lhs.writemask_map[i] != rhs.writemask_map[i])
+               return false;
+            if (lhs.read_swizzle_map[i] != rhs.read_swizzle_map[i])
+               return false;
+         }
+      }
+   } else {
+      return !rhs.reswizzle;
+   }
+   return true;
+}
+
+/* end namespace tgsi_array_merge */
+}
diff --git a/src/mesa/state_tracker/st_glsl_to_tgsi_array_merge.h b/src/mesa/state_tracker/st_glsl_to_tgsi_array_merge.h
new file mode 100644
index 0000000000..c74c854e09
--- /dev/null
+++ b/src/mesa/state_tracker/st_glsl_to_tgsi_array_merge.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright © 2017 Gert Wollny
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef MESA_GLSL_TO_TGSI_ARRAY_MERGE_H
+#define MESA_GLSL_TO_TGSI_ARRAY_MERGE_H
+
+#include "st_glsl_to_tgsi_private.h"
+#include <iosfwd>
+
+namespace tgsi_array_merge {
+
+/* Helper class to merge and interleave arrays.
+ * The interface is exposed here to make unit tests possible.
+ */
+class array_remapping {
+public:
+
+   /** Create an invalid mapping that is used as place-holder for
+    * arrays that are not mapped at all.
+    */
+   array_remapping();
+
+   /** Simple remapping that is done when the lifetimes do not
+    * overlap.
+    * @param trgt_array_id ID of the array that the new array will
+    *        be interleaved with
+    */
+   array_remapping(int trgt_array_id, unsigned src_access_mask);
+
+   /** Component interleaving of arrays.
+    * @param target_array_id ID of the array that the new array will
+    *        be interleaved with
+    * @param trgt_access_mask the component mast of the target array
+    *        (the components that are already reserved)
+    * @param orig_component_mask
+    */
+   array_remapping(int trgt_array_id, int trgt_access_mask,
+                   int src_access_mask);
+
+   /* Defines a valid remapping */
+   bool is_valid() const {return target_id > 0;}
+
+   /* Resolve the mapping chain so that this mapping remaps to an
+    * array that is not remapped.
+    */
+   void finalize_mappings(array_remapping *arr_map);
+
+   void set_target_id(int tid) {target_id = tid;}
+
+   /* Translates the write mask to the new, interleaved component
+    * position
+    */
+   int map_writemask(int original_src_access_mask) const;
+
+   /* Translates all read swizzles to the new, interleaved component
+    * swizzles
+    */
+   uint16_t map_swizzles(uint16_t original_swizzle) const;
+
+   /** Move the read swizzles to the positiones that correspond to
+    * a changed write mask.
+    */
+   uint16_t move_read_swizzles(uint16_t original_swizzle) const;
+
+   unsigned target_array_id() const {return target_id;}
+
+   int combined_access_mask() const {return summary_access_mask;}
+
+   void print(std::ostream& os) const;
+
+   bool is_finalized() { return finalized;}
+
+   friend bool operator == (const array_remapping& lhs,
+                            const array_remapping& rhs);
+
+   int map_one_swizzle(int swizzle_to_map) const;
+
+private:
+   unsigned target_id;
+   uint16_t writemask_map[4];
+   int16_t read_swizzle_map[4];
+   unsigned summary_access_mask:4;
+   unsigned original_src_access_mask:4;
+   int reswizzle:1;
+   int finalized:1;
+};
+
+inline
+std::ostream& operator << (std::ostream& os, const array_remapping& am)
+{
+   am.print(os);
+   return os;
+}
+
+}
+#endif
-- 
2.13.6



More information about the mesa-dev mailing list