From e6a4e0b0b71ab5215758cadd8000abf98477ba66 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Mon, 20 Apr 2020 12:45:36 -0400
Subject: [PATCH 054/193] FIXME: initial WIP on binops

---
 gcc/analyzer/region-model2.cc |  48 ++++++++++++-
 gcc/analyzer/region-model2.h  | 132 +++++++++++++++++++++++++++++++++-
 2 files changed, 177 insertions(+), 3 deletions(-)

diff --git a/gcc/analyzer/region-model2.cc b/gcc/analyzer/region-model2.cc
index d01cecffade..f9aa1e8964f 100644
--- a/gcc/analyzer/region-model2.cc
+++ b/gcc/analyzer/region-model2.cc
@@ -722,6 +722,32 @@ initial_svalue2::print_details (const region_model2 &model ATTRIBUTE_UNUSED,
 }
 #endif
 
+/* class binop_svalue2 : public svalue2.  */
+
+void
+binop_svalue2::dump_to_pp (pretty_printer *pp, bool simple) const
+{
+  if (simple)
+    {
+      pp_character (pp, '(');
+      m_arg0->dump_to_pp (pp, simple);
+      pp_string (pp, op_symbol_code (m_op));
+      m_arg1->dump_to_pp (pp, simple);
+      pp_character (pp, ')');
+    }
+  else
+    {
+      pp_string (pp, "binop_svalue2 (");
+      // TODO: type?
+      pp_string (pp, get_tree_code_name (m_op));
+      pp_string (pp, ", ");
+      m_arg0->dump_to_pp (pp, simple);
+      pp_string (pp, ", ");
+      m_arg1->dump_to_pp (pp, simple);
+      pp_character (pp, ')');
+    }
+}
+
 /* class region2 and its various subclasses.  */
 
 /* Get a string for KIND for use in debug dumps.  */
@@ -2859,6 +2885,18 @@ region_model2_manager::get_ptr_svalue2 (tree ptr_type, region2 *pointee)
   return sval;
 }
 
+svalue2 *
+region_model2_manager::get_or_create_binop (tree type, enum tree_code op,
+					    svalue2 *arg0, svalue2 *arg1)
+{
+  binop_svalue2::key_t key (type, op, arg0, arg1);
+  if (binop_svalue2 **slot = m_binop_values_map.get (key))
+    return *slot;
+  binop_svalue2 *binop_sval = new binop_svalue2 (type, op, arg0, arg1);
+  m_binop_values_map.put (key, binop_sval);
+  return binop_sval;
+}
+
 /* region2 consolidation.  */
 
 /* FIXME.  */
@@ -3579,6 +3617,7 @@ region_model2::on_gassign (const supernode */*snode*/,
 	copy_region2 (lhs_reg, rhs_reg, ctxt);
       }
       break;
+#endif
 
     case EQ_EXPR:
     case GE_EXPR:
@@ -3602,10 +3641,17 @@ region_model2::on_gassign (const supernode */*snode*/,
 				 ctxt),
 		     ctxt);
 	else
-	  set_to_new_unknown_value (lhs_reg, TREE_TYPE (lhs), ctxt);
+	  {
+	    // TODO: symbolic value for binop
+	    svalue2 *sval_binop
+	      = m_mgr->get_or_create_binop (TREE_TYPE (lhs), op,
+					    rhs1_sval, rhs2_sval);
+	    set_value (lhs_reg, sval_binop, ctxt);
+	  }
       }
       break;
 
+#if 0
     case NEGATE_EXPR:
     case BIT_NOT_EXPR:
       {
diff --git a/gcc/analyzer/region-model2.h b/gcc/analyzer/region-model2.h
index f7a3b9539a4..a3ea15945de 100644
--- a/gcc/analyzer/region-model2.h
+++ b/gcc/analyzer/region-model2.h
@@ -126,7 +126,8 @@ public:
    SK_UNKNOWN,
    SK_POISONED,
    SK_SETJMP,
-   SK_INITIAL
+   SK_INITIAL,
+   SK_BINOP
   };
 
   virtual ~svalue2 () {}
@@ -530,6 +531,129 @@ is_a_helper <initial_svalue2 *>::test (svalue2 *sval)
 
 namespace ana {
 
+/* A hash_map traits class for "uniquifying" instances of some class using
+   a simpler key type.  */
+#if 0
+template <typename Key_t>
+struct foo_traits_t
+{
+  typedef Key_t key_type;
+  struct hash_entry;
+
+  static hashval_t hash (const Key_t &k) { return k.hash (); }
+  static bool is_empty (const hash_entry &e); // FIXME
+};
+#endif
+
+/* A hash traits class that uses member functions to implement
+   the various required ops.  */
+
+template <typename Type>
+struct member_function_hash_traits : public typed_noop_remove<Type>
+{
+  typedef Type value_type;
+  typedef Type compare_type;
+  static inline hashval_t hash (value_type v) { return v.hash (); }
+  static inline bool equal (const value_type &existing,
+			    const value_type &candidate)
+  {
+    return existing == candidate;
+  }
+  static inline void mark_deleted (Type &t) { t.mark_deleted (); }
+  static inline void mark_empty (Type &t) { t.mark_empty (); }
+  static inline bool is_deleted (Type t) { return t.is_deleted (); }
+  static inline bool is_empty (Type t) { return t.is_empty (); }
+};
+
+/* Concrete subclass of svalue2 representing a binary operation of
+   two svalue2s.  */
+
+class binop_svalue2 : public svalue2
+{
+public:
+  /* A support class for uniquifying instances of binop_svalue2.  */
+  struct key_t
+  {
+    key_t (tree type, enum tree_code op, svalue2 *arg0, svalue2 *arg1)
+    : m_type (type), m_op (op), m_arg0 (arg0), m_arg1 (arg1)
+    {}
+
+    hashval_t hash () const
+    {
+      return 42; // FIXME
+    }
+
+    bool operator== (const key_t &other) const
+    {
+      return (m_type == other.m_type
+	      && m_op == other.m_op
+	      && m_arg0 == other.m_arg0
+	      && m_arg1 == other.m_arg1);
+    }
+
+    void mark_deleted () { m_type = reinterpret_cast<tree> (1); }
+    void mark_empty () { m_type = NULL_TREE; }
+    bool is_deleted () const { return m_type == reinterpret_cast<tree> (1); }
+    bool is_empty () const { return m_type == NULL_TREE; }
+
+    tree m_type;
+    enum tree_code m_op;
+    svalue2 *m_arg0;
+    svalue2 *m_arg1;
+  };
+
+  binop_svalue2 (tree type, enum tree_code op, svalue2 *arg0, svalue2 *arg1)
+  : svalue2 (type), m_op (op), m_arg0 (arg0), m_arg1 (arg1)
+  {
+  }
+
+  enum kind get_kind () const FINAL OVERRIDE { return SK_BINOP; }
+
+#if 0
+  void dump_dot_to_pp (const region_model2 &model,
+		       pretty_printer *pp) const
+    FINAL OVERRIDE;
+#endif
+
+  void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE;
+
+#if 0
+  binop_svalue2 *dyn_cast_binop_svalue2 () FINAL OVERRIDE { return this; }
+#endif
+
+#if 0
+  void add_to_hash (inchash::hash &hstate) const FINAL OVERRIDE;
+#endif
+
+ private:
+#if 0
+  void print_details (const region_model2 &model, pretty_printer *pp) const
+    FINAL OVERRIDE;
+#endif
+
+  enum tree_code m_op;
+  svalue2 *m_arg0;
+  svalue2 *m_arg1;
+};
+
+} // namespace ana
+
+template <>
+template <>
+inline bool
+is_a_helper <binop_svalue2 *>::test (svalue2 *sval)
+{
+  return sval->get_kind () == svalue2::SK_BINOP;
+}
+
+template <> struct default_hash_traits<binop_svalue2::key_t>
+: public member_function_hash_traits<binop_svalue2::key_t>
+{
+  static const bool empty_zero_p = true;
+};
+
+namespace ana {
+
 /* Region and its subclasses.
 
    The class hierarchy looks like this (using indentation to show
@@ -1279,6 +1403,9 @@ public:
   svalue2 *get_or_create_constant_svalue2 (tree cst_expr);
   svalue2 *get_or_create_initial_value (const region2 *reg);
   svalue2 *get_ptr_svalue2 (tree ptr_type, region2 *pointee);
+  svalue2 *get_or_create_binop (tree type,
+				enum tree_code op,
+				svalue2 *arg0, svalue2 *arg1);
 
   /* region2 consolidation.  */
   function_region2 *get_region_for_fndecl (tree fndecl,
@@ -1316,7 +1443,8 @@ private:
   typedef hash_map<const region2 *, region_svalue2 *> pointer_values_map_t;
   pointer_values_map_t m_pointer_values_map;
 
-  uniq_manager<svalue2> m_ptr_svalues;
+  typedef hash_map<binop_svalue2::key_t, binop_svalue2 *> binop_values_map_t;
+  binop_values_map_t m_binop_values_map;
 
   /* region2 consolidation.  */
 
-- 
2.21.0

