public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Sylvain Noiry <snoiry@kalrayinc.com>
To: gcc-patches@gcc.gnu.org
Cc: Sylvain Noiry <snoiry@kalrayinc.com>
Subject: [PATCH 1/9] Native complex operations: Conditional lowering
Date: Mon, 17 Jul 2023 11:02:42 +0200	[thread overview]
Message-ID: <20230717090250.4645-2-snoiry@kalrayinc.com> (raw)
In-Reply-To: <20230717090250.4645-1-snoiry@kalrayinc.com>

Allow the cplxlower pass to identify if an operation does not need
to be lowered through optabs. In this case, lowering is not performed.
The cplxlower pass now has to handle a mix of lowered and non-lowered
operations. A quick access to both parts of a complex constant is
also implemented.

gcc/lto/ChangeLog:

	* lto-common.cc (compare_tree_sccs_1): Handle both parts of a
	  complex constant

gcc/ChangeLog:

	* coretypes.h: Add enum for complex parts
	* gensupport.cc (match_pattern): Add complex types
	* lto-streamer-out.cc (DFS::DFS_write_tree_body):
	(hash_tree): Handle both parts of a complex constant
	* tree-complex.cc (get_component_var): Support handling of
	both parts of a complex
	(get_component_ssa_name): Likewise
	(set_component_ssa_name): Likewise
	(extract_component): Likewise
	(update_complex_components): Likewise
	(update_complex_components_on_edge): Likewise
	(update_complex_assignment): Likewise
	(update_phi_components): Likewise
	(expand_complex_move): Likewise
	(expand_complex_asm): Update with complex_part_t
	(complex_component_cst_p): New: check if a complex
	component is a constant
	(target_native_complex_operation): New: Check if complex
	operation is supported natively by the backend, through
	the optab
	(expand_complex_operations_1): Condionally lowered ops
	(tree_lower_complex): Support handling of both parts of
	 a complex
	* tree-core.h (struct GTY): Add field for both parts of
	the tree_complex struct
	* tree-streamer-in.cc (lto_input_ts_complex_tree_pointers):
	Handle both parts of a complex constant
	* tree-streamer-out.cc (write_ts_complex_tree_pointers):
	Likewise
	* tree.cc (build_complex): likewise
	* tree.h (class auto_suppress_location_wrappers):
	(type_has_mode_precision_p): Add special case for complex
---
 gcc/coretypes.h          |   9 +
 gcc/gensupport.cc        |   2 +
 gcc/lto-streamer-out.cc  |   2 +
 gcc/lto/lto-common.cc    |   2 +
 gcc/tree-complex.cc      | 434 +++++++++++++++++++++++++++++----------
 gcc/tree-core.h          |   1 +
 gcc/tree-streamer-in.cc  |   1 +
 gcc/tree-streamer-out.cc |   1 +
 gcc/tree.cc              |   8 +
 gcc/tree.h               |  15 +-
 10 files changed, 363 insertions(+), 112 deletions(-)

diff --git a/gcc/coretypes.h b/gcc/coretypes.h
index ca8837cef67..a000c104b53 100644
--- a/gcc/coretypes.h
+++ b/gcc/coretypes.h
@@ -443,6 +443,15 @@ enum optimize_size_level
   OPTIMIZE_SIZE_MAX
 };
 
+/* part of a complex */
+
+typedef enum
+{
+  REAL_P = 0,
+  IMAG_P = 1,
+  BOTH_P = 2
+} complex_part_t;
+
 /* Support for user-provided GGC and PCH markers.  The first parameter
    is a pointer to a pointer, the second either NULL if the pointer to
    pointer points into a GC object or the actual pointer address if
diff --git a/gcc/gensupport.cc b/gcc/gensupport.cc
index 959d1d9c83c..9aa2ba69fcd 100644
--- a/gcc/gensupport.cc
+++ b/gcc/gensupport.cc
@@ -3746,9 +3746,11 @@ match_pattern (optab_pattern *p, const char *name, const char *pat)
 		    break;
 		if (*p == 0
 		    && (! force_int || mode_class[i] == MODE_INT
+			|| mode_class[i] == MODE_COMPLEX_INT
 			|| mode_class[i] == MODE_VECTOR_INT)
 		    && (! force_partial_int
 			|| mode_class[i] == MODE_INT
+			|| mode_class[i] == MODE_COMPLEX_INT
 			|| mode_class[i] == MODE_PARTIAL_INT
 			|| mode_class[i] == MODE_VECTOR_INT)
 		    && (! force_float
diff --git a/gcc/lto-streamer-out.cc b/gcc/lto-streamer-out.cc
index 5ffa8954022..38c48e44867 100644
--- a/gcc/lto-streamer-out.cc
+++ b/gcc/lto-streamer-out.cc
@@ -985,6 +985,7 @@ DFS::DFS_write_tree_body (struct output_block *ob,
     {
       DFS_follow_tree_edge (TREE_REALPART (expr));
       DFS_follow_tree_edge (TREE_IMAGPART (expr));
+      DFS_follow_tree_edge (TREE_COMPLEX_BOTH_PARTS (expr));
     }
 
   if (CODE_CONTAINS_STRUCT (code, TS_DECL_MINIMAL))
@@ -1417,6 +1418,7 @@ hash_tree (struct streamer_tree_cache_d *cache, hash_map<tree, hashval_t> *map,
     {
       visit (TREE_REALPART (t));
       visit (TREE_IMAGPART (t));
+      visit (TREE_COMPLEX_BOTH_PARTS (t));
     }
 
   if (CODE_CONTAINS_STRUCT (code, TS_DECL_MINIMAL))
diff --git a/gcc/lto/lto-common.cc b/gcc/lto/lto-common.cc
index 703e665b698..f647ee62f9e 100644
--- a/gcc/lto/lto-common.cc
+++ b/gcc/lto/lto-common.cc
@@ -1408,6 +1408,8 @@ compare_tree_sccs_1 (tree t1, tree t2, tree **map)
     {
       compare_tree_edges (TREE_REALPART (t1), TREE_REALPART (t2));
       compare_tree_edges (TREE_IMAGPART (t1), TREE_IMAGPART (t2));
+      compare_tree_edges (TREE_COMPLEX_BOTH_PARTS (t1),
+			  TREE_COMPLEX_BOTH_PARTS (t2));
     }
 
   if (CODE_CONTAINS_STRUCT (code, TS_DECL_MINIMAL))
diff --git a/gcc/tree-complex.cc b/gcc/tree-complex.cc
index 688fe13989c..63753e4acf4 100644
--- a/gcc/tree-complex.cc
+++ b/gcc/tree-complex.cc
@@ -42,6 +42,10 @@ along with GCC; see the file COPYING3.  If not see
 #include "cfganal.h"
 #include "gimple-fold.h"
 #include "diagnostic-core.h"
+#include "target.h"
+#include "memmodel.h"
+#include "optabs-tree.h"
+#include "internal-fn.h"
 
 
 /* For each complex ssa name, a lattice value.  We're interested in finding
@@ -74,7 +78,7 @@ static vec<complex_lattice_t> complex_lattice_values;
    the hashtable.  */
 static int_tree_htab_type *complex_variable_components;
 
-/* For each complex SSA_NAME, a pair of ssa names for the components.  */
+/* For each complex SSA_NAME, three ssa names for the components.  */
 static vec<tree> complex_ssa_name_components;
 
 /* Vector of PHI triplets (original complex PHI and corresponding real and
@@ -476,17 +480,27 @@ create_one_component_var (tree type, tree orig, const char *prefix,
 /* Retrieve a value for a complex component of VAR.  */
 
 static tree
-get_component_var (tree var, bool imag_p)
+get_component_var (tree var, complex_part_t part)
 {
-  size_t decl_index = DECL_UID (var) * 2 + imag_p;
+  size_t decl_index = DECL_UID (var) * 3 + part;
   tree ret = cvc_lookup (decl_index);
 
   if (ret == NULL)
     {
-      ret = create_one_component_var (TREE_TYPE (TREE_TYPE (var)), var,
-				      imag_p ? "CI" : "CR",
-				      imag_p ? "$imag" : "$real",
-				      imag_p ? IMAGPART_EXPR : REALPART_EXPR);
+      switch (part)
+	{
+	case REAL_P:
+	  ret = create_one_component_var (TREE_TYPE (TREE_TYPE (var)), var,
+					  "CR", "$real", REALPART_EXPR);
+	  break;
+	case IMAG_P:
+	  ret = create_one_component_var (TREE_TYPE (TREE_TYPE (var)), var,
+					  "CI", "$imag", IMAGPART_EXPR);
+	  break;
+	case BOTH_P:
+	  ret = var;
+	  break;
+	}
       cvc_insert (decl_index, ret);
     }
 
@@ -496,13 +510,15 @@ get_component_var (tree var, bool imag_p)
 /* Retrieve a value for a complex component of SSA_NAME.  */
 
 static tree
-get_component_ssa_name (tree ssa_name, bool imag_p)
+get_component_ssa_name (tree ssa_name, complex_part_t part)
 {
   complex_lattice_t lattice = find_lattice_value (ssa_name);
   size_t ssa_name_index;
   tree ret;
 
-  if (lattice == (imag_p ? ONLY_REAL : ONLY_IMAG))
+  if (((lattice == ONLY_IMAG) && (part == REAL_P))
+      || ((lattice == ONLY_REAL) && (part == IMAG_P)))
+
     {
       tree inner_type = TREE_TYPE (TREE_TYPE (ssa_name));
       if (SCALAR_FLOAT_TYPE_P (inner_type))
@@ -511,14 +527,33 @@ get_component_ssa_name (tree ssa_name, bool imag_p)
 	return build_int_cst (inner_type, 0);
     }
 
-  ssa_name_index = SSA_NAME_VERSION (ssa_name) * 2 + imag_p;
+  if (part == BOTH_P)
+    return ssa_name;
+
+  ssa_name_index = SSA_NAME_VERSION (ssa_name) * 3 + part;
+
+  /* increase size of dynamic array if needed */
+  if (ssa_name_index >= complex_ssa_name_components.length ())
+    {
+      complex_ssa_name_components.safe_grow_cleared
+	(2 * complex_ssa_name_components.length (), true);
+      complex_lattice_values.safe_grow_cleared
+	(2 * complex_lattice_values.length (), true);
+    }
+
   ret = complex_ssa_name_components[ssa_name_index];
   if (ret == NULL)
     {
       if (SSA_NAME_VAR (ssa_name))
-	ret = get_component_var (SSA_NAME_VAR (ssa_name), imag_p);
+	ret = get_component_var (SSA_NAME_VAR (ssa_name), part);
       else
-	ret = TREE_TYPE (TREE_TYPE (ssa_name));
+	{
+	  if (part == BOTH_P)
+	    ret = TREE_TYPE (ssa_name);
+	  else
+	    ret = TREE_TYPE (TREE_TYPE (ssa_name));
+	}
+
       ret = make_ssa_name (ret);
 
       /* Copy some properties from the original.  In particular, whether it
@@ -542,7 +577,7 @@ get_component_ssa_name (tree ssa_name, bool imag_p)
    gimple_seq of stuff that needs doing.  */
 
 static gimple_seq
-set_component_ssa_name (tree ssa_name, bool imag_p, tree value)
+set_component_ssa_name (tree ssa_name, complex_part_t part, tree value)
 {
   complex_lattice_t lattice = find_lattice_value (ssa_name);
   size_t ssa_name_index;
@@ -553,14 +588,24 @@ set_component_ssa_name (tree ssa_name, bool imag_p, tree value)
   /* We know the value must be zero, else there's a bug in our lattice
      analysis.  But the value may well be a variable known to contain
      zero.  We should be safe ignoring it.  */
-  if (lattice == (imag_p ? ONLY_REAL : ONLY_IMAG))
+  if (((lattice == ONLY_IMAG) && (part == REAL_P))
+      || ((lattice == ONLY_REAL) && (part == IMAG_P)))
     return NULL;
 
   /* If we've already assigned an SSA_NAME to this component, then this
      means that our walk of the basic blocks found a use before the set.
      This is fine.  Now we should create an initialization for the value
      we created earlier.  */
-  ssa_name_index = SSA_NAME_VERSION (ssa_name) * 2 + imag_p;
+  ssa_name_index = SSA_NAME_VERSION (ssa_name) * 3 + part;
+
+  /* increase size of dynamic array if needed */
+  if (ssa_name_index >= complex_ssa_name_components.length ())
+    {
+      size_t old_size = complex_ssa_name_components.length ();
+      complex_ssa_name_components.safe_grow (2 * old_size, true);
+      complex_lattice_values.safe_grow (2 * old_size, true);
+    }
+
   comp = complex_ssa_name_components[ssa_name_index];
   if (comp)
     ;
@@ -584,7 +629,7 @@ set_component_ssa_name (tree ssa_name, bool imag_p, tree value)
 	  && (!SSA_NAME_VAR (value) || DECL_IGNORED_P (SSA_NAME_VAR (value)))
 	  && !DECL_IGNORED_P (SSA_NAME_VAR (ssa_name)))
 	{
-	  comp = get_component_var (SSA_NAME_VAR (ssa_name), imag_p);
+	  comp = get_component_var (SSA_NAME_VAR (ssa_name), part);
 	  replace_ssa_name_symbol (value, comp);
 	}
 
@@ -595,7 +640,7 @@ set_component_ssa_name (tree ssa_name, bool imag_p, tree value)
   /* Finally, we need to stabilize the result by installing the value into
      a new ssa name.  */
   else
-    comp = get_component_ssa_name (ssa_name, imag_p);
+    comp = get_component_ssa_name (ssa_name, part);
 
   /* Do all the work to assign VALUE to COMP.  */
   list = NULL;
@@ -612,13 +657,14 @@ set_component_ssa_name (tree ssa_name, bool imag_p, tree value)
    Emit any new code before gsi.  */
 
 static tree
-extract_component (gimple_stmt_iterator *gsi, tree t, bool imagpart_p,
+extract_component (gimple_stmt_iterator * gsi, tree t, complex_part_t part,
 		   bool gimple_p, bool phiarg_p = false)
 {
   switch (TREE_CODE (t))
     {
     case COMPLEX_CST:
-      return imagpart_p ? TREE_IMAGPART (t) : TREE_REALPART (t);
+      return (part == BOTH_P) ? t : (part == IMAG_P) ?
+	TREE_IMAGPART (t) : TREE_REALPART (t);
 
     case COMPLEX_EXPR:
       gcc_unreachable ();
@@ -629,7 +675,7 @@ extract_component (gimple_stmt_iterator *gsi, tree t, bool imagpart_p,
 	t = unshare_expr (t);
 	TREE_TYPE (t) = inner_type;
 	TREE_OPERAND (t, 1) = TYPE_SIZE (inner_type);
-	if (imagpart_p)
+	if (part == IMAG_P)
 	  TREE_OPERAND (t, 2) = size_binop (PLUS_EXPR, TREE_OPERAND (t, 2),
 					    TYPE_SIZE (inner_type));
 	if (gimple_p)
@@ -646,10 +692,11 @@ extract_component (gimple_stmt_iterator *gsi, tree t, bool imagpart_p,
     case VIEW_CONVERT_EXPR:
     case MEM_REF:
       {
-	tree inner_type = TREE_TYPE (TREE_TYPE (t));
-
-	t = build1 ((imagpart_p ? IMAGPART_EXPR : REALPART_EXPR),
-		    inner_type, unshare_expr (t));
+	if (part == BOTH_P)
+	  t = unshare_expr (t);
+	else
+	  t = build1 (((part == IMAG_P) ? IMAGPART_EXPR : REALPART_EXPR),
+		      (TREE_TYPE (TREE_TYPE (t))), unshare_expr (t));
 
 	if (gimple_p)
 	  t = force_gimple_operand_gsi (gsi, t, true, NULL, true,
@@ -659,10 +706,12 @@ extract_component (gimple_stmt_iterator *gsi, tree t, bool imagpart_p,
       }
 
     case SSA_NAME:
-      t = get_component_ssa_name (t, imagpart_p);
-      if (TREE_CODE (t) == SSA_NAME && SSA_NAME_DEF_STMT (t) == NULL)
-	gcc_assert (phiarg_p);
-      return t;
+      {
+	t = get_component_ssa_name (t, part);
+	if (TREE_CODE (t) == SSA_NAME && SSA_NAME_DEF_STMT (t) == NULL)
+	  gcc_assert (phiarg_p);
+	return t;
+      }
 
     default:
       gcc_unreachable ();
@@ -673,18 +722,29 @@ extract_component (gimple_stmt_iterator *gsi, tree t, bool imagpart_p,
 
 static void
 update_complex_components (gimple_stmt_iterator *gsi, gimple *stmt, tree r,
-			   tree i)
+			   tree i, tree b = NULL)
 {
   tree lhs;
   gimple_seq list;
 
+  gcc_assert (b || (r && i));
   lhs = gimple_get_lhs (stmt);
+  if (!b)
+    b = lhs;
+  if (!r)
+    r = build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (b)), unshare_expr (b));
+  if (!i)
+    i = build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (b)), unshare_expr (b));
+
+  list = set_component_ssa_name (lhs, REAL_P, r);
+  if (list)
+    gsi_insert_seq_after (gsi, list, GSI_CONTINUE_LINKING);
 
-  list = set_component_ssa_name (lhs, false, r);
+  list = set_component_ssa_name (lhs, IMAG_P, i);
   if (list)
     gsi_insert_seq_after (gsi, list, GSI_CONTINUE_LINKING);
 
-  list = set_component_ssa_name (lhs, true, i);
+  list = set_component_ssa_name (lhs, BOTH_P, b);
   if (list)
     gsi_insert_seq_after (gsi, list, GSI_CONTINUE_LINKING);
 }
@@ -694,11 +754,11 @@ update_complex_components_on_edge (edge e, tree lhs, tree r, tree i)
 {
   gimple_seq list;
 
-  list = set_component_ssa_name (lhs, false, r);
+  list = set_component_ssa_name (lhs, REAL_P, r);
   if (list)
     gsi_insert_seq_on_edge (e, list);
 
-  list = set_component_ssa_name (lhs, true, i);
+  list = set_component_ssa_name (lhs, IMAG_P, i);
   if (list)
     gsi_insert_seq_on_edge (e, list);
 }
@@ -707,19 +767,24 @@ update_complex_components_on_edge (edge e, tree lhs, tree r, tree i)
 /* Update an assignment to a complex variable in place.  */
 
 static void
-update_complex_assignment (gimple_stmt_iterator *gsi, tree r, tree i)
+update_complex_assignment (gimple_stmt_iterator * gsi, tree r, tree i,
+			   tree b = NULL)
 {
   gimple *old_stmt = gsi_stmt (*gsi);
-  gimple_assign_set_rhs_with_ops (gsi, COMPLEX_EXPR, r, i);
+  if (b == NULL)
+    gimple_assign_set_rhs_with_ops (gsi, COMPLEX_EXPR, r, i);
+  else
+    /* dummy assignment, but pr45569.C fails if removed */
+    gimple_assign_set_rhs_from_tree (gsi, b);
+
   gimple *stmt = gsi_stmt (*gsi);
   update_stmt (stmt);
   if (maybe_clean_or_replace_eh_stmt (old_stmt, stmt))
     bitmap_set_bit (need_eh_cleanup, gimple_bb (stmt)->index);
 
-  update_complex_components (gsi, gsi_stmt (*gsi), r, i);
+  update_complex_components (gsi, gsi_stmt (*gsi), r, i, b);
 }
 
-
 /* Generate code at the entry point of the function to initialize the
    component variables for a complex parameter.  */
 
@@ -768,7 +833,8 @@ update_phi_components (basic_block bb)
 
 	  for (j = 0; j < 2; j++)
 	    {
-	      tree l = get_component_ssa_name (gimple_phi_result (phi), j > 0);
+	      tree l = get_component_ssa_name (gimple_phi_result (phi),
+					       (complex_part_t) j);
 	      if (TREE_CODE (l) == SSA_NAME)
 		p[j] = create_phi_node (l, bb);
 	    }
@@ -779,7 +845,9 @@ update_phi_components (basic_block bb)
 	      for (j = 0; j < 2; j++)
 		if (p[j])
 		  {
-		    comp = extract_component (NULL, arg, j > 0, false, true);
+		    comp =
+		      extract_component (NULL, arg, (complex_part_t) j, false,
+					 true);
 		    if (TREE_CODE (comp) == SSA_NAME
 			&& SSA_NAME_DEF_STMT (comp) == NULL)
 		      {
@@ -809,13 +877,14 @@ update_phi_components (basic_block bb)
     }
 }
 
+
 /* Expand a complex move to scalars.  */
 
 static void
 expand_complex_move (gimple_stmt_iterator *gsi, tree type)
 {
   tree inner_type = TREE_TYPE (type);
-  tree r, i, lhs, rhs;
+  tree r, i, b, lhs, rhs;
   gimple *stmt = gsi_stmt (*gsi);
 
   if (is_gimple_assign (stmt))
@@ -862,16 +931,13 @@ expand_complex_move (gimple_stmt_iterator *gsi, tree type)
       else
 	{
 	  if (gimple_assign_rhs_code (stmt) != COMPLEX_EXPR)
-	    {
-	      r = extract_component (gsi, rhs, 0, true);
-	      i = extract_component (gsi, rhs, 1, true);
-	    }
+	    update_complex_assignment (gsi, NULL, NULL,
+				       extract_component (gsi, rhs,
+							  BOTH_P, true));
 	  else
-	    {
-	      r = gimple_assign_rhs1 (stmt);
-	      i = gimple_assign_rhs2 (stmt);
-	    }
-	  update_complex_assignment (gsi, r, i);
+	    update_complex_assignment (gsi,
+				       gimple_assign_rhs1 (stmt),
+				       gimple_assign_rhs2 (stmt), NULL);
 	}
     }
   else if (rhs
@@ -883,24 +949,18 @@ expand_complex_move (gimple_stmt_iterator *gsi, tree type)
       location_t loc;
 
       loc = gimple_location (stmt);
-      r = extract_component (gsi, rhs, 0, false);
-      i = extract_component (gsi, rhs, 1, false);
-
-      x = build1 (REALPART_EXPR, inner_type, unshare_expr (lhs));
-      t = gimple_build_assign (x, r);
-      gimple_set_location (t, loc);
-      gsi_insert_before (gsi, t, GSI_SAME_STMT);
+      b = extract_component (gsi, rhs, BOTH_P, false);
 
       if (stmt == gsi_stmt (*gsi))
 	{
-	  x = build1 (IMAGPART_EXPR, inner_type, unshare_expr (lhs));
+	  x = unshare_expr (lhs);
 	  gimple_assign_set_lhs (stmt, x);
-	  gimple_assign_set_rhs1 (stmt, i);
+	  gimple_assign_set_rhs1 (stmt, b);
 	}
       else
 	{
-	  x = build1 (IMAGPART_EXPR, inner_type, unshare_expr (lhs));
-	  t = gimple_build_assign (x, i);
+	  x = unshare_expr (lhs);
+	  t = gimple_build_assign (x, b);
 	  gimple_set_location (t, loc);
 	  gsi_insert_before (gsi, t, GSI_SAME_STMT);
 
@@ -1641,26 +1701,88 @@ expand_complex_asm (gimple_stmt_iterator *gsi)
 		}
 	      /* Make sure to not ICE later, see PR105165.  */
 	      tree zero = build_zero_cst (TREE_TYPE (TREE_TYPE (op)));
-	      set_component_ssa_name (op, false, zero);
-	      set_component_ssa_name (op, true, zero);
+	      set_component_ssa_name (op, REAL_P, zero);
+	      set_component_ssa_name (op, IMAG_P, zero);
+	      set_component_ssa_name (op, BOTH_P, zero);
 	      continue;
 	    }
 	  tree type = TREE_TYPE (op);
 	  tree inner_type = TREE_TYPE (type);
 	  tree r = build1 (REALPART_EXPR, inner_type, op);
 	  tree i = build1 (IMAGPART_EXPR, inner_type, op);
-	  gimple_seq list = set_component_ssa_name (op, false, r);
+	  tree b = op;
+	  gimple_seq list = set_component_ssa_name (op, REAL_P, r);
 
 	  if (list)
 	    gsi_insert_seq_after (gsi, list, GSI_CONTINUE_LINKING);
 
-	  list = set_component_ssa_name (op, true, i);
+	  list = set_component_ssa_name (op, IMAG_P, i);
+	  if (list)
+	    gsi_insert_seq_after (gsi, list, GSI_CONTINUE_LINKING);
+
+	  list = set_component_ssa_name (op, BOTH_P, b);
 	  if (list)
 	    gsi_insert_seq_after (gsi, list, GSI_CONTINUE_LINKING);
 	}
     }
 }
 
+/* Returns true if a complex component is a constant */
+
+static bool
+complex_component_cst_p (tree cplx, complex_part_t part)
+{
+  switch (TREE_CODE (cplx))
+    {
+    case COMPLEX_CST:
+      return true;
+
+    case SSA_NAME:
+      {
+	size_t ssa_name_index = SSA_NAME_VERSION (cplx) * 3 + part;
+	tree val = complex_ssa_name_components[ssa_name_index];
+	return (val) ? CONSTANT_CLASS_P (val) : false;
+      }
+
+    default:
+      return false;
+    }
+}
+
+/* Returns true if the target support a particular complex operation natively */
+
+static bool
+target_native_complex_operation (enum tree_code code, tree type,
+				 tree inner_type, tree ac, tree bc,
+				 complex_lattice_t al, complex_lattice_t bl)
+{
+  /* Native complex instructions are currently only used when both operands are varying,
+     but a finer grain approach may be interesting */
+  if ((al != VARYING) || ((bl != VARYING) && (bl != UNINITIALIZED)))
+    return false;
+
+  /* do not use native operations when a part of the result is constant */
+  if ((bl == UNINITIALIZED)
+      && (complex_component_cst_p (ac, REAL_P)
+	  || complex_component_cst_p (ac, IMAG_P)))
+    return false;
+  else if ((bl != UNINITIALIZED)
+	   &&
+	   ((complex_component_cst_p (ac, REAL_P)
+	     && complex_component_cst_p (bc, REAL_P))
+	    || (complex_component_cst_p (ac, IMAG_P)
+		&& complex_component_cst_p (bc, IMAG_P))))
+    return false;
+
+  optab op = optab_for_tree_code (code, inner_type, optab_default);
+
+  /* no need to search if operation is not in the optab */
+  if (op == unknown_optab)
+    return false;
+
+  return optab_handler (op, TYPE_MODE (type)) != CODE_FOR_nothing;
+}
+
 /* Process one statement.  If we identify a complex operation, expand it.  */
 
 static void
@@ -1729,14 +1851,17 @@ expand_complex_operations_1 (gimple_stmt_iterator *gsi)
 		 && TREE_CODE (lhs) == SSA_NAME)
 	  {
 	    rhs = gimple_assign_rhs1 (stmt);
+	    enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
 	    rhs = extract_component (gsi, TREE_OPERAND (rhs, 0),
-		                     gimple_assign_rhs_code (stmt)
-				       == IMAGPART_EXPR,
-				     false);
+				     (rhs_code == IMAGPART_EXPR) ? IMAG_P
+				     : (rhs_code == REALPART_EXPR) ? REAL_P
+				     : BOTH_P, false);
 	    gimple_assign_set_rhs_from_tree (gsi, rhs);
 	    stmt = gsi_stmt (*gsi);
 	    update_stmt (stmt);
 	  }
+	else if (is_gimple_call (stmt))
+	  return;
       }
       return;
     }
@@ -1755,19 +1880,6 @@ expand_complex_operations_1 (gimple_stmt_iterator *gsi)
       bc = gimple_cond_rhs (stmt);
     }
 
-  ar = extract_component (gsi, ac, false, true);
-  ai = extract_component (gsi, ac, true, true);
-
-  if (ac == bc)
-    br = ar, bi = ai;
-  else if (bc)
-    {
-      br = extract_component (gsi, bc, 0, true);
-      bi = extract_component (gsi, bc, 1, true);
-    }
-  else
-    br = bi = NULL_TREE;
-
   al = find_lattice_value (ac);
   if (al == UNINITIALIZED)
     al = VARYING;
@@ -1783,44 +1895,142 @@ expand_complex_operations_1 (gimple_stmt_iterator *gsi)
 	bl = VARYING;
     }
 
-  switch (code)
+  if (target_native_complex_operation
+      (code, type, inner_type, ac, bc, al, bl))
     {
-    case PLUS_EXPR:
-    case MINUS_EXPR:
-      expand_complex_addition (gsi, inner_type, ar, ai, br, bi, code, al, bl);
-      break;
+      tree ab, bb, rb;
+      gimple_seq stmts = NULL;
+      location_t loc = gimple_location (gsi_stmt (*gsi));
+
+      ab = extract_component (gsi, ac, BOTH_P, true);
+      if (ac == bc)
+	bb = ab;
+      else if (bc)
+	{
+	  bb = extract_component (gsi, bc, BOTH_P, true);
+	}
+      else
+	bb = NULL_TREE;
 
-    case MULT_EXPR:
-      expand_complex_multiplication (gsi, type, ar, ai, br, bi, al, bl);
-      break;
+      switch (code)
+	{
+	case PLUS_EXPR:
+	case MINUS_EXPR:
+	case MULT_EXPR:
+	  rb = gimple_build (&stmts, loc, code, type, ab, bb);
+	  gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
+	  update_complex_assignment (gsi, NULL, NULL, rb);
+	  break;
 
-    case TRUNC_DIV_EXPR:
-    case CEIL_DIV_EXPR:
-    case FLOOR_DIV_EXPR:
-    case ROUND_DIV_EXPR:
-    case RDIV_EXPR:
-      expand_complex_division (gsi, type, ar, ai, br, bi, code, al, bl);
-      break;
+	case NEGATE_EXPR:
+	case CONJ_EXPR:
+	  rb = gimple_build (&stmts, loc, code, type, ab);
+	  gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
+	  update_complex_assignment (gsi, NULL, NULL, rb);
+	  break;
 
-    case NEGATE_EXPR:
-      expand_complex_negation (gsi, inner_type, ar, ai);
-      break;
+	case EQ_EXPR:
+	case NE_EXPR:
+	  /* FIXME */
+	  {
+	    gimple *stmt = gsi_stmt (*gsi);
+	    rb = gimple_build (&stmts, loc, code, type, ab, bb);
+	    switch (gimple_code (stmt))
+	      {
+	      case GIMPLE_RETURN:
+		{
+		  greturn *return_stmt = as_a < greturn * >(stmt);
+		  gimple_return_set_retval (return_stmt,
+					    fold_convert (type, rb));
+		}
+		break;
 
-    case CONJ_EXPR:
-      expand_complex_conjugate (gsi, inner_type, ar, ai);
-      break;
+	      case GIMPLE_ASSIGN:
+		update_complex_assignment (gsi, NULL, NULL, rb);
+		gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
+		break;
 
-    case EQ_EXPR:
-    case NE_EXPR:
-      expand_complex_comparison (gsi, ar, ai, br, bi, code);
-      break;
+	      case GIMPLE_COND:
+		{
+		  gcond *cond_stmt = as_a < gcond * >(stmt);
+		  gimple_cond_set_code (cond_stmt, EQ_EXPR);
+		  gimple_cond_set_lhs (cond_stmt, rb);
+		  gimple_cond_set_rhs (cond_stmt, boolean_true_node);
+		}
+		break;
 
-    default:
-      gcc_unreachable ();
+	      default:
+		break;
+	      }
+	    break;
+	  }
+
+
+	  /* not supported yet */
+	case TRUNC_DIV_EXPR:
+	case CEIL_DIV_EXPR:
+	case FLOOR_DIV_EXPR:
+	case ROUND_DIV_EXPR:
+	case RDIV_EXPR:
+
+	default:
+	  gcc_unreachable ();
+	}
+      return;
     }
-}
 
+    ar = extract_component (gsi, ac, REAL_P, true);
+    ai = extract_component (gsi, ac, IMAG_P, true);
+
+    if (ac == bc)
+      br = ar, bi = ai;
+    else if (bc)
+      {
+	br = extract_component (gsi, bc, REAL_P, true);
+	bi = extract_component (gsi, bc, IMAG_P, true);
+      }
+    else
+	br = bi = NULL_TREE;
+
+    switch (code)
+      {
+      case PLUS_EXPR:
+      case MINUS_EXPR:
+	expand_complex_addition (gsi, inner_type, ar, ai, br, bi, code, al,
+				 bl);
+	break;
+
+      case MULT_EXPR:
+	expand_complex_multiplication (gsi, type, ar, ai, br, bi, al, bl);
+	break;
+
+      case TRUNC_DIV_EXPR:
+      case CEIL_DIV_EXPR:
+      case FLOOR_DIV_EXPR:
+      case ROUND_DIV_EXPR:
+      case RDIV_EXPR:
+	expand_complex_division (gsi, type, ar, ai, br, bi, code, al, bl);
+	break;
+
+      case NEGATE_EXPR:
+	expand_complex_negation (gsi, inner_type, ar, ai);
+	break;
+
+      case CONJ_EXPR:
+	expand_complex_conjugate (gsi, inner_type, ar, ai);
+	break;
+
+      case EQ_EXPR:
+      case NE_EXPR:
+	expand_complex_comparison (gsi, ar, ai, br, bi, code);
+	break;
+
+      default:
+	gcc_unreachable ();
+      }
+}
 \f
+
 /* Entry point for complex operation lowering during optimization.  */
 
 static unsigned int
@@ -1845,8 +2055,8 @@ tree_lower_complex (void)
 
   complex_variable_components = new int_tree_htab_type (10);
 
-  complex_ssa_name_components.create (2 * num_ssa_names);
-  complex_ssa_name_components.safe_grow_cleared (2 * num_ssa_names, true);
+  complex_ssa_name_components.create (3 * num_ssa_names);
+  complex_ssa_name_components.safe_grow_cleared (3 * num_ssa_names, true);
 
   update_parameter_components ();
 
@@ -1879,7 +2089,9 @@ tree_lower_complex (void)
 		      || is_gimple_min_invariant (op))
 		    continue;
 		  tree arg = gimple_phi_arg_def (phis_to_revisit[j], l);
-		  op = extract_component (NULL, arg, k > 0, false, false);
+		  op =
+		    extract_component (NULL, arg, (complex_part_t) k, false,
+				       false);
 		  SET_PHI_ARG_DEF (phi, l, op);
 		}
 	    }
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index 668808a29d0..da6daf99fc1 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -1486,6 +1486,7 @@ struct GTY(()) tree_complex {
   struct tree_typed typed;
   tree real;
   tree imag;
+  tree both;
 };
 
 struct GTY(()) tree_vector {
diff --git a/gcc/tree-streamer-in.cc b/gcc/tree-streamer-in.cc
index 5bead0c3c6a..a1fa2cb9eea 100644
--- a/gcc/tree-streamer-in.cc
+++ b/gcc/tree-streamer-in.cc
@@ -695,6 +695,7 @@ lto_input_ts_complex_tree_pointers (class lto_input_block *ib,
 {
   TREE_REALPART (expr) = stream_read_tree_ref (ib, data_in);
   TREE_IMAGPART (expr) = stream_read_tree_ref (ib, data_in);
+  TREE_COMPLEX_BOTH_PARTS (expr) = stream_read_tree_ref (ib, data_in);
 }
 
 
diff --git a/gcc/tree-streamer-out.cc b/gcc/tree-streamer-out.cc
index ff9694e17dd..be7314ef748 100644
--- a/gcc/tree-streamer-out.cc
+++ b/gcc/tree-streamer-out.cc
@@ -592,6 +592,7 @@ write_ts_complex_tree_pointers (struct output_block *ob, tree expr)
 {
   stream_write_tree_ref (ob, TREE_REALPART (expr));
   stream_write_tree_ref (ob, TREE_IMAGPART (expr));
+  stream_write_tree_ref (ob, TREE_COMPLEX_BOTH_PARTS (expr));
 }
 
 
diff --git a/gcc/tree.cc b/gcc/tree.cc
index 420857b110c..2bc1b0d1e3f 100644
--- a/gcc/tree.cc
+++ b/gcc/tree.cc
@@ -2497,6 +2497,14 @@ build_complex (tree type, tree real, tree imag)
 
   tree t = make_node (COMPLEX_CST);
 
+  /* represent both parts as a constant vector */
+  tree vector_type = build_vector_type (TREE_TYPE (real), 2);
+  tree_vector_builder v (vector_type, 1, 2);
+  v.quick_push (real);
+  v.quick_push (imag);
+  tree both = v.build ();
+
+  TREE_COMPLEX_BOTH_PARTS (t) = both;
   TREE_REALPART (t) = real;
   TREE_IMAGPART (t) = imag;
   TREE_TYPE (t) = type ? type : build_complex_type (TREE_TYPE (real));
diff --git a/gcc/tree.h b/gcc/tree.h
index fa02e2907a1..28716b53120 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -634,6 +634,12 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int,
 
 /* Nonzero if TYPE represents a complex floating-point type.  */
 
+#define COMPLEX_INTEGER_TYPE_P(TYPE)	\
+  (TREE_CODE (TYPE) == COMPLEX_TYPE	\
+   && TREE_CODE (TREE_TYPE (TYPE)) == INTEGER_TYPE)
+
+/* Nonzero if TYPE represents a complex floating-point type.  */
+
 #define COMPLEX_FLOAT_TYPE_P(TYPE)	\
   (TREE_CODE (TYPE) == COMPLEX_TYPE	\
    && TREE_CODE (TREE_TYPE (TYPE)) == REAL_TYPE)
@@ -1155,6 +1161,7 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int,
 /* In a COMPLEX_CST node.  */
 #define TREE_REALPART(NODE) (COMPLEX_CST_CHECK (NODE)->complex.real)
 #define TREE_IMAGPART(NODE) (COMPLEX_CST_CHECK (NODE)->complex.imag)
+#define TREE_COMPLEX_BOTH_PARTS(NODE) (COMPLEX_CST_CHECK (NODE)->complex.both)
 
 /* In a VECTOR_CST node.  See generic.texi for details.  */
 #define VECTOR_CST_NELTS(NODE) (TYPE_VECTOR_SUBPARTS (TREE_TYPE (NODE)))
@@ -2214,6 +2221,8 @@ class auto_suppress_location_wrappers
   (as_a <scalar_int_mode> (TYPE_CHECK (NODE)->type_common.mode))
 #define SCALAR_FLOAT_TYPE_MODE(NODE) \
   (as_a <scalar_float_mode> (TYPE_CHECK (NODE)->type_common.mode))
+#define COMPLEX_TYPE_MODE(NODE) \
+  (as_a <complex_mode> (TYPE_CHECK (NODE)->type_common.mode))
 #define SET_TYPE_MODE(NODE, MODE) \
   (TYPE_CHECK (NODE)->type_common.mode = (MODE))
 
@@ -6646,7 +6655,11 @@ extern const builtin_structptr_type builtin_structptr_types[6];
 inline bool
 type_has_mode_precision_p (const_tree t)
 {
-  return known_eq (TYPE_PRECISION (t), GET_MODE_PRECISION (TYPE_MODE (t)));
+  if (TREE_CODE (t) == COMPLEX_TYPE)
+    return known_eq (2*TYPE_PRECISION (TREE_TYPE(t)),
+		     GET_MODE_PRECISION (TYPE_MODE (t)));
+  else
+    return known_eq (TYPE_PRECISION (t), GET_MODE_PRECISION (TYPE_MODE (t)));
 }
 
 /* Helper functions for fndecl_built_in_p.  */
-- 
2.17.1






  reply	other threads:[~2023-07-17  9:03 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-07-17  9:02 [PATCH 0/9] Native complex operations Sylvain Noiry
2023-07-17  9:02 ` Sylvain Noiry [this message]
2023-07-17  9:02 ` [PATCH 2/9] Native complex operations: Move functions to hooks Sylvain Noiry
2023-07-17  9:02 ` [PATCH 3/9] Native complex operations: Add gen_rtx_complex hook Sylvain Noiry
2023-07-17  9:02 ` [PATCH 4/9] Native complex operations: Allow native complex regs and ops in rtl Sylvain Noiry
2023-07-17  9:02 ` [PATCH 5/9] Native complex operations: Add the conjugate op in optabs Sylvain Noiry
2023-07-17  9:02 ` [PATCH 6/9] Native complex operations: Update how complex rotations are handled Sylvain Noiry
2023-07-17  9:02 ` [PATCH 7/9] Native complex operations: Vectorization of native complex operations Sylvain Noiry
2023-07-17  9:02 ` [PATCH 8/9] Native complex operations: Add explicit vector of complex Sylvain Noiry
2023-07-17  9:02 ` [PATCH 9/9] Native complex operation: Experimental support in x86 backend Sylvain Noiry
2023-09-12 10:07   ` [PATCH v2 0/11] Native complex operations Sylvain Noiry
2023-09-12 10:07     ` [PATCH v2 01/11] Native complex ops : Conditional lowering Sylvain Noiry
2023-09-12 10:07     ` [PATCH v2 02/11] Native complex ops: Move functions to hooks Sylvain Noiry
2023-09-12 10:07     ` [PATCH v2 03/11] Native complex ops: Add gen_rtx_complex hook Sylvain Noiry
2023-09-12 10:07     ` [PATCH v2 04/11] Native complex ops: Allow native complex regs and ops in rtl Sylvain Noiry
2023-09-12 10:07     ` [PATCH v2 05/11] Native complex ops: Add the conjugate op in optabs Sylvain Noiry
2023-09-12 10:07     ` [PATCH v2 06/11] Native complex ops: Update how complex rotations are handled Sylvain Noiry
2023-09-12 10:07     ` [PATCH v2 07/11] Native complex ops: Vectorization of native complex operations Sylvain Noiry
2023-09-12 10:07     ` [PATCH v2 08/11] Native complex ops: Add explicit vector of complex Sylvain Noiry
2023-09-12 17:25       ` Joseph Myers
2023-09-13  6:48         ` Richard Biener
2023-09-12 10:07     ` [PATCH v2 09/11] Native complex ops: remove useless special cases Sylvain Noiry
2023-09-12 10:07     ` [PATCH v2 10/11] Native complex ops: Add a fast complex multiplication pattern Sylvain Noiry
2023-09-12 10:07     ` [PATCH v2 11/11] Native complex ops: Experimental support in x86 backend Sylvain Noiry

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230717090250.4645-2-snoiry@kalrayinc.com \
    --to=snoiry@kalrayinc.com \
    --cc=gcc-patches@gcc.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).