From be609b5a0edcf2b2865317e71f43af54a5238e59 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Mon, 6 Apr 2020 15:49:22 -0400
Subject: [PATCH 07/44] FIXME: initial impl of uniq_manager

---
 gcc/Makefile.in                    |   3 +-
 gcc/analyzer/analyzer-selftests.cc |   1 +
 gcc/analyzer/analyzer-selftests.h  |   1 +
 gcc/analyzer/uniq-manager.cc       | 152 ++++++++++++++++++++++++
 gcc/analyzer/uniq-manager.h        | 183 +++++++++++++++++++++++++++++
 5 files changed, 339 insertions(+), 1 deletion(-)
 create mode 100644 gcc/analyzer/uniq-manager.cc
 create mode 100644 gcc/analyzer/uniq-manager.h

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 3f2a032b67d..a3b3427fea3 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1241,7 +1241,8 @@ ANALYZER_OBJS = \
 	analyzer/sm-signal.o \
 	analyzer/sm-taint.o \
 	analyzer/state-purge.o \
-	analyzer/supergraph.o
+	analyzer/supergraph.o \
+	analyzer/uniq-manager.o
 
 # Language-independent object files.
 # We put the *-match.o and insn-*.o files first so that a parallel make
diff --git a/gcc/analyzer/analyzer-selftests.cc b/gcc/analyzer/analyzer-selftests.cc
index 8e200a3844b..c157bda3bff 100644
--- a/gcc/analyzer/analyzer-selftests.cc
+++ b/gcc/analyzer/analyzer-selftests.cc
@@ -58,6 +58,7 @@ run_analyzer_selftests ()
   analyzer_region_model_cc_tests ();
   analyzer_sm_file_cc_tests ();
   analyzer_sm_signal_cc_tests ();
+  analyzer_uniq_manager_cc_tests ();
 #endif /* #if ENABLE_ANALYZER */
 }
 
diff --git a/gcc/analyzer/analyzer-selftests.h b/gcc/analyzer/analyzer-selftests.h
index 7924b8c8f01..29c2aeae120 100644
--- a/gcc/analyzer/analyzer-selftests.h
+++ b/gcc/analyzer/analyzer-selftests.h
@@ -41,6 +41,7 @@ extern void analyzer_program_state_cc_tests ();
 extern void analyzer_region_model_cc_tests ();
 extern void analyzer_sm_file_cc_tests ();
 extern void analyzer_sm_signal_cc_tests ();
+extern void analyzer_uniq_manager_cc_tests ();
 
 } /* end of namespace ana::selftest.  */
 
diff --git a/gcc/analyzer/uniq-manager.cc b/gcc/analyzer/uniq-manager.cc
new file mode 100644
index 00000000000..6d878d030c1
--- /dev/null
+++ b/gcc/analyzer/uniq-manager.cc
@@ -0,0 +1,152 @@
+/* FIXME.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "selftest.h"
+#include "analyzer/uniq-manager.h"
+
+#if ENABLE_ANALYZER
+
+namespace ana {
+
+#if 0
+/* class uniq_id_t.  */
+
+hashval_t
+uniq_id_t::hash () const
+{
+  hashval_t result = 0;
+  int i;
+  char *ch;
+  FOR_EACH_VEC_ELT (m_data, i, ch)
+    {
+      result <<= 8;
+      result %= ch;
+    }
+  // FIXME: better impl
+  return result;
+}
+
+bool
+uniq_id_t::operator== (const uniq_id_t &other) const
+{
+  if (m_data.length () != other.m_data.length ())
+    return false;
+  return memcmp (&m_data[0], &other.m_data[0], m_data.length ()) == 0;
+}
+#endif
+
+#if CHECKING_P
+
+namespace selftest {
+
+class counted
+{
+public:
+  counted (unsigned *inst_counter)
+  : m_inst_counter (inst_counter)
+  {
+    (*m_inst_counter)++;
+  }
+  ~counted ()
+  {
+    (*m_inst_counter)--;
+  }
+private:
+  unsigned *m_inst_counter;
+};
+
+class int_wrapper : public counted
+{
+public:
+  int_wrapper (unsigned *inst_counter, int val)
+  : counted (inst_counter), m_val (val) {}
+
+  hashval_t hash () const { return m_val; }
+  bool operator== (const int_wrapper& other) const
+  {
+    return m_val == other.m_val;
+  }
+
+#if 0
+  void add_to_uniq_id (uniq_id_t *out) const
+  {
+    out->add_int (m_val);
+  }
+#endif
+
+private:
+  int m_val;
+};
+
+/* FIXME.  */
+
+static void
+test_int_wrapper ()
+{
+  unsigned inst_counter = 0;
+
+  {
+    uniq_manager<int_wrapper> m;
+    ASSERT_EQ (m.get_count (), 0);
+
+    int_wrapper *init_w0 = new int_wrapper (&inst_counter, 0);
+    ASSERT_EQ (inst_counter, 1);
+    const int_wrapper *cw0 = m.consolidate (init_w0);
+    ASSERT_EQ (init_w0, cw0);
+    ASSERT_EQ (m.get_count (), 1);
+
+    int_wrapper *w1 = new int_wrapper (&inst_counter, 1);
+    ASSERT_EQ (inst_counter, 2);
+    const int_wrapper *cw1 = m.consolidate (w1);
+    ASSERT_EQ (w1, cw1);
+    ASSERT_EQ (m.get_count (), 2);
+
+    /* Consolidating another instance of "0" should give us back the initial
+       instance of 0, and delete the new one.  */
+    int_wrapper *another_w0 = new int_wrapper (&inst_counter, 0);
+    ASSERT_EQ (inst_counter, 3);
+    const int_wrapper *another_cw0 = m.consolidate (another_w0);
+    ASSERT_EQ (inst_counter, 2);
+    ASSERT_EQ (init_w0, another_cw0);
+    ASSERT_EQ (m.get_count (), 2);
+  }
+
+  /* All instance should be cleaned up when the manager is destroyed.  */
+  ASSERT_EQ (inst_counter, 0);
+}
+
+/* Run all of the selftests within this file.  */
+
+void
+analyzer_uniq_manager_cc_tests ()
+{
+  test_int_wrapper ();
+}
+
+} // namespace selftest
+
+#endif /* CHECKING_P */
+
+} // namespace ana
+
+#endif /* #if ENABLE_ANALYZER */
diff --git a/gcc/analyzer/uniq-manager.h b/gcc/analyzer/uniq-manager.h
new file mode 100644
index 00000000000..c56630d7d61
--- /dev/null
+++ b/gcc/analyzer/uniq-manager.h
@@ -0,0 +1,183 @@
+/* FIXME.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_ANALYZER_UNIQ_MANAGER_H
+#define GCC_ANALYZER_UNIQ_MANAGER_H
+
+#if ENABLE_ANALYZER
+
+namespace ana {
+
+#if 0
+class uniq_id_t
+{
+public:
+  hashval_t hash () const;
+  bool operator== (const uniq_id_t &other) const;
+
+  bool add_int (int val);
+
+private:
+  // TODO: need copy-ctor etc
+  auto_vec<char> m_data;
+};
+#endif
+
+#if 0
+class hash_visitor
+{
+public:
+  bool on_int (int val)
+  {
+    m_hash ^= val;
+    return true;
+  }
+
+private:
+  hashval_t m_hash;
+};
+class eq_visitor
+{
+public:
+  bool on_int (int val)
+  {
+  }
+}
+#endif
+
+/* A class responsible for ensuring that instances of a class
+   that are sufficiently similar are unique.
+
+   FIXME: T should implement a get_id (instance_manager *id) method.
+
+   T should implement the following:
+     hashval_t hash () const;
+     bool operator== (const T &other) const;
+
+   FIXME: or maybe a visit_fields method?  */
+template <class T>
+class uniq_manager
+{
+ public:
+#if 0
+  struct map_value
+  {
+    uniq_id_t m_id;
+    T *m_unique_val;
+  };
+  typedef hash_map <uniq_id_t *, map_value *> map_t;
+#endif
+  struct traits_t
+  {
+    //typedef uniq_id_t *key_type;
+    typedef T *key_type;
+    typedef T *value_type;
+    typedef T *compare_type;
+
+    static inline hashval_t hash (const key_type &k)
+    {
+      gcc_assert (k != NULL);
+      return k->hash ();
+    }
+    static inline bool equal_keys (const key_type &k1, const key_type &k2)
+    {
+      gcc_assert (k1 != NULL);
+      gcc_assert (k2 != NULL);
+      return *k1 == *k2;
+    }
+    template <typename E>
+    static inline void remove (E &entry)
+    {
+      delete entry.m_key;
+    }
+    template <typename E>
+    static inline void mark_deleted (E &entry)
+    {
+      entry.m_key = reinterpret_cast<key_type> (1);
+    }
+    template <typename E>
+    static inline void mark_empty (E &entry)
+    {
+      entry.m_key = NULL;
+    }
+    template <typename E>
+    static inline bool is_deleted (const E &entry)
+    {
+      return entry.m_key == reinterpret_cast<key_type> (1);
+    }
+    template <typename E>
+    static inline bool is_empty (const E &entry)
+    {
+      return entry.m_key == NULL;
+    }
+    static const bool empty_zero_p = true;
+  };
+  //typedef hash_map <uniq_id_t *, T *, traits_t> map_t;
+  typedef hash_map <T *, T *, traits_t> map_t;
+  typedef typename map_t::iterator iterator_t;
+
+  /* Takes ownership of t, deleting it if there's a duplicate.  */
+  const T *consolidate (T *t)
+  {
+#if 1
+    gcc_assert (t);
+    //uniq_id_t *id = new uniq_id_t ();
+    //t->add_to_uniq_id (id);
+    bool existed;
+    T *&ptr = m_map.get_or_insert (t, &existed);  // FIXME: hash function!
+    if (existed)
+      {
+	//delete id;
+	delete t;
+	return ptr;
+      }
+    else
+      {
+	ptr = t;
+	return t;
+      }
+#else
+    uniq_id_t id;
+    t->get_id (&id);
+    if (map_value *slot = m_map.get (&id)) // FIXME: hash function!
+      {
+	delete t;
+	return slot->m_unique_val;
+      }
+    else
+      {
+	slot->m_id = id;
+	slot->m_unique_val = t;
+      }
+#endif
+  }
+
+  /* How many T are being managed.  */
+  size_t get_count () const { return m_map.elements (); }
+
+ private:
+  map_t m_map;
+};
+
+#endif /* CHECKING_P */
+
+} // namespace ana
+
+#endif /* GCC_ANALYZER_UNIQ_MANAGER_H */
-- 
2.21.0

