From 1113067bbc3906c081c5c7115818c5877298f6f4 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Wed, 19 Feb 2020 13:24:28 -0500
Subject: [PATCH 23/31] FIXME: more WIP on canon&purge: id_map
 compose/identity/selftests

---
 gcc/analyzer/region-model.cc | 48 ++++++++++++++++++
 gcc/analyzer/region-model.h  | 98 +++++++++++++++++++++++++++++++++++-
 2 files changed, 144 insertions(+), 2 deletions(-)

diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index 9acf7990d58..0ca0bb51a59 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -7244,6 +7244,53 @@ test_tree_cmp_on_constants ()
 	}
 }
 
+/* FIXME.  */
+
+static void
+test_id_map ()
+{
+  svalue_id sid0 = svalue_id::from_int (0);
+  svalue_id sid1 = svalue_id::from_int (1);
+  svalue_id sid2 = svalue_id::from_int (2);
+
+  /* A swap of sid1 and sid2.  */
+  svalue_id_map swap (3);
+  swap.put (sid0, sid0);
+  swap.put (sid1, sid2);
+  swap.put (sid2, sid1);
+
+  ASSERT_EQ (swap.get_dst_for_src (sid0), sid0);
+  ASSERT_EQ (swap.get_dst_for_src (sid1), sid2);
+  ASSERT_EQ (swap.get_dst_for_src (sid2), sid1);
+  ASSERT_EQ (swap.get_src_for_dst (sid0), sid0);
+  ASSERT_EQ (swap.get_src_for_dst (sid1), sid2);
+  ASSERT_EQ (swap.get_src_for_dst (sid2), sid1);
+
+  svalue_id s = sid1;
+  swap.update (&s);
+  ASSERT_EQ (s, sid2);
+
+  svalue_id_map identity (3);
+  identity.make_identity ();
+  ASSERT_NE (identity, swap);
+
+  /* Test that swap followed by identity == swap.  */
+  {
+    svalue_id_map t1 (swap);
+    ASSERT_EQ (t1, swap);
+    t1.compose (identity);
+    ASSERT_EQ (t1, swap);
+  }
+
+  /* Test that identity followed by swap == swap.  */
+  {
+    svalue_id_map t2 (identity);
+    ASSERT_EQ (t2, identity);
+    t2.compose (swap);
+    ASSERT_EQ (t2, swap);
+  }
+}
+
 /* Implementation detail of the ASSERT_CONDITION_* macros.  */
 
 void
@@ -8417,6 +8464,7 @@ void
 analyzer_region_model_cc_tests ()
 {
   test_tree_cmp_on_constants ();
+  test_id_map ();
   test_dump ();
   test_unique_constants ();
   test_svalue_equality ();
diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h
index 5193ca73bbd..992864276bd 100644
--- a/gcc/analyzer/region-model.h
+++ b/gcc/analyzer/region-model.h
@@ -152,12 +152,22 @@ class id_map
 {
  public:
   id_map (int num_ids);
+  id_map (const id_map &other);
+  id_map& operator= (const id_map &other);
+
   void put (T src, T dst);
+  void make_identity ();
+  void compose (const id_map &other);
+
   T get_dst_for_src (T src) const;
   T get_src_for_dst (T dst) const;
+  void update (T *) const;
+
+  bool operator== (const id_map &other) const;
+  bool operator!= (const id_map &other) const { return !(*this == other); }
+
   void dump_to_pp (pretty_printer *pp) const;
   void dump () const;
-  void update (T *) const;
 
  private:
   auto_vec<T> m_src_to_dst;
@@ -169,7 +179,7 @@ typedef id_map<region_id> region_id_map;
 
 /* class id_map.  */
 
-/* id_map's ctor, which populates the map with dummy null values.  */
+/* id_map ctor by size: populate the map with dummy null values.  */
 
 template <typename T>
 inline id_map<T>::id_map (int num_svalues)
@@ -183,6 +193,37 @@ inline id_map<T>::id_map (int num_svalues)
     }
 }
 
+/* id_map copy ctor.  */
+
+template <typename T>
+inline id_map<T>::id_map (const id_map &other)
+: m_src_to_dst (other.m_src_to_dst.length ()),
+  m_dst_to_src (other.m_dst_to_src.length ())
+{
+  gcc_assert (other.m_src_to_dst.length () == other.m_dst_to_src.length ());
+  for (unsigned i = 0; i < other.m_src_to_dst.length (); i++)
+    {
+      m_src_to_dst.quick_push (other.m_src_to_dst[i]);
+      m_dst_to_src.quick_push (other.m_dst_to_src[i]);
+    }
+}
+
+/* id_map assignment operator.  */
+
+template <typename T>
+inline id_map<T>&
+id_map<T>::operator= (const id_map &other)
+{
+  gcc_assert (m_src_to_dst.length () == other.m_src_to_dst.length ());
+  gcc_assert (other.m_src_to_dst.length () == other.m_dst_to_src.length ());
+  for (unsigned i = 0; i < other.m_src_to_dst.length (); i++)
+    {
+      m_src_to_dst[i] = other.m_src_to_dst[i];
+      m_dst_to_src[i] = other.m_dst_to_src[i];
+    }
+  return *this;
+}
+
 /* Record that SRC is to be mapped to DST.  */
 
 template <typename T>
@@ -193,6 +234,39 @@ id_map<T>::put (T src, T dst)
   m_dst_to_src[dst.as_int ()] = src;
 }
 
+/* Make every ID map to itself.  */
+
+template <typename T>
+inline void
+id_map<T>::make_identity ()
+{
+  gcc_assert (m_src_to_dst.length () == m_dst_to_src.length ());
+  for (unsigned i = 0; i < m_src_to_dst.length (); i++)
+    {
+      T id = T::from_int (i);
+      put (id, id);
+    }
+}
+
+/* FIXME.  */
+
+template <typename T>
+inline void
+id_map<T>::compose (const id_map &other)
+{
+  gcc_assert (m_src_to_dst.length () == m_dst_to_src.length ());
+
+  id_map result (m_src_to_dst.length ());
+  for (unsigned i = 0; i < m_src_to_dst.length (); i++)
+    {
+      T id = T::from_int (i);
+      result.m_src_to_dst[i] = other.get_dst_for_src (get_dst_for_src (id));
+      result.m_dst_to_src[i] = get_src_for_dst (other.get_src_for_dst (id));
+    }
+
+  *this = result;
+}
+
 /* Get the new value for SRC within the map.  */
 
 template <typename T>
@@ -216,6 +290,26 @@ id_map<T>::get_src_for_dst (T dst) const
   return m_dst_to_src[dst.as_int ()];
 }
 
+/* id_map's equality operator: compare elementwise.  */
+
+template <typename T>
+inline bool
+id_map<T>::operator== (const id_map &other) const
+{
+  if (m_src_to_dst.length () != other.m_src_to_dst.length ())
+    return false;
+
+  gcc_assert (m_src_to_dst.length () == m_dst_to_src.length ());
+  for (unsigned i = 0; i < m_src_to_dst.length (); i++)
+    {
+      if (m_src_to_dst[i] != other.m_src_to_dst[i])
+	return false;
+      if (m_dst_to_src[i] != other.m_dst_to_src[i])
+	return false;
+    }
+  return true;
+}
+
 /* Dump this id_map to PP.  */
 
 template <typename T>
-- 
2.21.0

