From 7804b82294a7822f3b81a3f5fcb2bb712d0d3ace Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Mon, 20 Apr 2020 14:40:30 -0400
Subject: [PATCH 056/193] FIXME: initial impl of unary ops

---
 gcc/analyzer/region-model2.cc |  64 +++++++++++++++++---
 gcc/analyzer/region-model2.h  | 106 +++++++++++++++++++++++++++++-----
 2 files changed, 147 insertions(+), 23 deletions(-)

diff --git a/gcc/analyzer/region-model2.cc b/gcc/analyzer/region-model2.cc
index 1d4947b8054..36ebe60bff5 100644
--- a/gcc/analyzer/region-model2.cc
+++ b/gcc/analyzer/region-model2.cc
@@ -722,6 +722,29 @@ initial_svalue2::print_details (const region_model2 &model ATTRIBUTE_UNUSED,
 }
 #endif
 
+/* class unaryop_svalue2 : public svalue2.  */
+
+void
+unaryop_svalue2::dump_to_pp (pretty_printer *pp, bool simple) const
+{
+  if (simple)
+    {
+      pp_character (pp, '(');
+      pp_string (pp, op_symbol_code (m_op));
+      m_arg->dump_to_pp (pp, simple);
+      pp_character (pp, ')');
+    }
+  else
+    {
+      pp_string (pp, "unaryop_svalue2 (");
+      // TODO: type?
+      pp_string (pp, get_tree_code_name (m_op));
+      pp_string (pp, ", ");
+      m_arg->dump_to_pp (pp, simple);
+      pp_character (pp, ')');
+    }
+}
+
 /* class binop_svalue2 : public svalue2.  */
 
 void
@@ -2885,6 +2908,23 @@ region_model2_manager::get_ptr_svalue2 (tree ptr_type, region2 *pointee)
   return sval;
 }
 
+svalue2 *
+region_model2_manager::get_or_create_unaryop (tree type, enum tree_code op,
+					      svalue2 *arg)
+{
+  /* Folding.  */
+  if (tree cst = arg->maybe_get_constant ())
+    if (tree result = fold_unary (op, type, cst))
+      return get_or_create_constant_svalue2 (result);
+
+  unaryop_svalue2::key_t key (type, op, arg);
+  if (unaryop_svalue2 **slot = m_unaryop_values_map.get (key))
+    return *slot;
+  unaryop_svalue2 *unaryop_sval = new unaryop_svalue2 (type, op, arg);
+  m_unaryop_values_map.put (key, unaryop_sval);
+  return unaryop_sval;
+}
+
 svalue2 *
 region_model2_manager::get_or_create_binop (tree type, enum tree_code op,
 					    svalue2 *arg0, svalue2 *arg1)
@@ -3593,27 +3633,33 @@ region_model2::on_gassign (const supernode */*snode*/,
       break;
 #endif
 
-    /* Assignments from unary ops of the form
-	set_value (lvalue (LHS), rvalue (RHS))
-       We already got the lvalue for the LHS above, as "lhs_reg".  */
-    case COMPONENT_REF:
-      /* LHS = op0.op1;  */
+    /* Assignments of the form
+	set_value (lvalue (LHS), rvalue (EXPR))
+       for various EXPR.
+       We already have the lvalue for the LHS above, as "lhs_reg".  */
+    case COMPONENT_REF: /* LHS = op0.op1;  */
     case REAL_CST:
     case INTEGER_CST:
     case ARRAY_REF:
-	/* LHS = RHS;  */
       {
 	svalue2 *rhs_sval = get_rvalue (rhs1, ctxt);
 	set_value (lhs_reg, rhs_sval, ctxt);
       }
       break;
 
-#if 0
+    /* Unary ops.  */
     case FIX_TRUNC_EXPR:
     case FLOAT_EXPR:
     case NOP_EXPR:
-      // cast: TODO
-      // fall though for now
+      {
+	svalue2 *rhs_sval = get_rvalue (rhs1, ctxt);
+	svalue2 *sval_unaryop
+	  = m_mgr->get_or_create_unaryop (TREE_TYPE (lhs), op, rhs_sval);
+	set_value (lhs_reg, sval_unaryop, ctxt);
+      }
+      break;
+
+#if 0
     case SSA_NAME:
     case VAR_DECL:
     case PARM_DECL:
diff --git a/gcc/analyzer/region-model2.h b/gcc/analyzer/region-model2.h
index a3ea15945de..7c1b2632667 100644
--- a/gcc/analyzer/region-model2.h
+++ b/gcc/analyzer/region-model2.h
@@ -127,6 +127,7 @@ public:
    SK_POISONED,
    SK_SETJMP,
    SK_INITIAL,
+   SK_UNARYOP,
    SK_BINOP
   };
 
@@ -531,20 +532,6 @@ 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.  */
 
@@ -565,6 +552,92 @@ struct member_function_hash_traits : public typed_noop_remove<Type>
   static inline bool is_empty (Type t) { return t.is_empty (); }
 };
 
+/* Concrete subclass of svalue2 representing a unary operation on
+   another svalue2s (e.g. a cast).  */
+
+class unaryop_svalue2 : public svalue2
+{
+public:
+  /* A support class for uniquifying instances of unaryop_svalue2.  */
+  struct key_t
+  {
+    key_t (tree type, enum tree_code op, svalue2 *arg)
+    : m_type (type), m_op (op), m_arg (arg)
+    {}
+
+    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_arg == other.m_arg);
+    }
+
+    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_arg;
+  };
+
+  unaryop_svalue2 (tree type, enum tree_code op, svalue2 *arg)
+  : svalue2 (type), m_op (op), m_arg (arg)
+  {
+  }
+
+  enum kind get_kind () const FINAL OVERRIDE { return SK_UNARYOP; }
+
+#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
+  unaryop_svalue2 *dyn_cast_unaryop_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_arg;
+};
+
+} // namespace ana
+
+template <>
+template <>
+inline bool
+is_a_helper <unaryop_svalue2 *>::test (svalue2 *sval)
+{
+  return sval->get_kind () == svalue2::SK_UNARYOP;
+}
+
+template <> struct default_hash_traits<unaryop_svalue2::key_t>
+: public member_function_hash_traits<unaryop_svalue2::key_t>
+{
+  static const bool empty_zero_p = true;
+};
+
+namespace ana {
+
 /* Concrete subclass of svalue2 representing a binary operation of
    two svalue2s.  */
 
@@ -1403,6 +1476,7 @@ 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_unaryop (tree type, enum tree_code op, svalue2 *arg);
   svalue2 *get_or_create_binop (tree type,
 				enum tree_code op,
 				svalue2 *arg0, svalue2 *arg1);
@@ -1443,6 +1517,10 @@ private:
   typedef hash_map<const region2 *, region_svalue2 *> pointer_values_map_t;
   pointer_values_map_t m_pointer_values_map;
 
+  typedef hash_map<unaryop_svalue2::key_t,
+		   unaryop_svalue2 *> unaryop_values_map_t;
+  unaryop_values_map_t m_unaryop_values_map;
+
   typedef hash_map<binop_svalue2::key_t, binop_svalue2 *> binop_values_map_t;
   binop_values_map_t m_binop_values_map;
 
-- 
2.21.0

