[committed] Fix simd clone creation for noreturn functions (PR middle-end/78025)

Jakub Jelinek jakub@redhat.com
Thu Oct 27 18:55:00 GMT 2016


Hi!

In simd_clone_adjust we weren't taking into account the possibility of no
edges to the exit block.  If inbranch, we still want to create the loop over
the simd lanes, though of course don't have any edges from the body to the
increment bb - e.g. if one calls the function with all zeros mask, it will
still do nothing as it should; for notinbranch, there is no loop, we just
handle the first simd lane and not return to the following ones.

Bootstrapped/regtested on x86_64-linux and i686-linux, committed to trunk.

2016-10-27  Jakub Jelinek  <jakub@redhat.com>

	PR middle-end/78025
	* omp-simd-clone.c (simd_clone_adjust): Handle noreturn declare simd
	functions.

	* g++.dg/gomp/declare-simd-7.C: New test.

--- gcc/omp-simd-clone.c.jj	2016-10-26 18:14:26.869045304 +0200
+++ gcc/omp-simd-clone.c	2016-10-27 10:51:55.292277315 +0200
@@ -1107,7 +1107,7 @@ simd_clone_adjust (struct cgraph_node *n
      return values accordingly.  */
   tree iter = create_tmp_var (unsigned_type_node, "iter");
   tree iter1 = make_ssa_name (iter);
-  tree iter2 = make_ssa_name (iter);
+  tree iter2 = NULL_TREE;
   ipa_simd_modify_function_body (node, adjustments, retval, iter1);
   adjustments.release ();
 
@@ -1121,39 +1121,57 @@ simd_clone_adjust (struct cgraph_node *n
 
   pop_gimplify_context (NULL);
 
+  gimple *g;
+  basic_block incr_bb = NULL;
+  struct loop *loop = NULL;
+
   /* Create a new BB right before the original exit BB, to hold the
      iteration increment and the condition/branch.  */
-  basic_block orig_exit = EDGE_PRED (EXIT_BLOCK_PTR_FOR_FN (cfun), 0)->src;
-  basic_block incr_bb = create_empty_bb (orig_exit);
-  add_bb_to_loop (incr_bb, body_bb->loop_father);
-  /* The succ of orig_exit was EXIT_BLOCK_PTR_FOR_FN (cfun), with an empty
-     flag.  Set it now to be a FALLTHRU_EDGE.  */
-  gcc_assert (EDGE_COUNT (orig_exit->succs) == 1);
-  EDGE_SUCC (orig_exit, 0)->flags |= EDGE_FALLTHRU;
-  for (unsigned i = 0;
-       i < EDGE_COUNT (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds); ++i)
+  if (EDGE_COUNT (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds))
+    {
+      basic_block orig_exit = EDGE_PRED (EXIT_BLOCK_PTR_FOR_FN (cfun), 0)->src;
+      incr_bb = create_empty_bb (orig_exit);
+      add_bb_to_loop (incr_bb, body_bb->loop_father);
+      /* The succ of orig_exit was EXIT_BLOCK_PTR_FOR_FN (cfun), with an empty
+	 flag.  Set it now to be a FALLTHRU_EDGE.  */
+      gcc_assert (EDGE_COUNT (orig_exit->succs) == 1);
+      EDGE_SUCC (orig_exit, 0)->flags |= EDGE_FALLTHRU;
+      for (unsigned i = 0;
+	   i < EDGE_COUNT (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds); ++i)
+	{
+	  edge e = EDGE_PRED (EXIT_BLOCK_PTR_FOR_FN (cfun), i);
+	  redirect_edge_succ (e, incr_bb);
+	}
+    }
+  else if (node->simdclone->inbranch)
+    {
+      incr_bb = create_empty_bb (entry_bb);
+      add_bb_to_loop (incr_bb, body_bb->loop_father);
+    }
+
+  if (incr_bb)
     {
-      edge e = EDGE_PRED (EXIT_BLOCK_PTR_FOR_FN (cfun), i);
-      redirect_edge_succ (e, incr_bb);
+      edge e = make_edge (incr_bb, EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
+      e->probability = REG_BR_PROB_BASE;
+      gsi = gsi_last_bb (incr_bb);
+      iter2 = make_ssa_name (iter);
+      g = gimple_build_assign (iter2, PLUS_EXPR, iter1,
+			       build_int_cst (unsigned_type_node, 1));
+      gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
+
+      /* Mostly annotate the loop for the vectorizer (the rest is done
+	 below).  */
+      loop = alloc_loop ();
+      cfun->has_force_vectorize_loops = true;
+      loop->safelen = node->simdclone->simdlen;
+      loop->force_vectorize = true;
+      loop->header = body_bb;
     }
-  edge e = make_edge (incr_bb, EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
-  e->probability = REG_BR_PROB_BASE;
-  gsi = gsi_last_bb (incr_bb);
-  gimple *g = gimple_build_assign (iter2, PLUS_EXPR, iter1,
-				   build_int_cst (unsigned_type_node, 1));
-  gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
-
-  /* Mostly annotate the loop for the vectorizer (the rest is done below).  */
-  struct loop *loop = alloc_loop ();
-  cfun->has_force_vectorize_loops = true;
-  loop->safelen = node->simdclone->simdlen;
-  loop->force_vectorize = true;
-  loop->header = body_bb;
 
   /* Branch around the body if the mask applies.  */
   if (node->simdclone->inbranch)
     {
-      gimple_stmt_iterator gsi = gsi_last_bb (loop->header);
+      gsi = gsi_last_bb (loop->header);
       tree mask_array
 	= node->simdclone->args[node->simdclone->nargs - 1].simd_array;
       tree mask;
@@ -1227,50 +1245,59 @@ simd_clone_adjust (struct cgraph_node *n
       FALLTHRU_EDGE (loop->header)->flags = EDGE_FALSE_VALUE;
     }
 
+  basic_block latch_bb = NULL;
+  basic_block new_exit_bb = NULL;
+
   /* Generate the condition.  */
-  g = gimple_build_cond (LT_EXPR,
-			 iter2,
-			 build_int_cst (unsigned_type_node,
-					node->simdclone->simdlen),
-			 NULL, NULL);
-  gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
-  e = split_block (incr_bb, gsi_stmt (gsi));
-  basic_block latch_bb = e->dest;
-  basic_block new_exit_bb;
-  new_exit_bb = split_block_after_labels (latch_bb)->dest;
-  loop->latch = latch_bb;
-
-  redirect_edge_succ (FALLTHRU_EDGE (latch_bb), body_bb);
-
-  make_edge (incr_bb, new_exit_bb, EDGE_FALSE_VALUE);
-  /* The successor of incr_bb is already pointing to latch_bb; just
-     change the flags.
-     make_edge (incr_bb, latch_bb, EDGE_TRUE_VALUE);  */
-  FALLTHRU_EDGE (incr_bb)->flags = EDGE_TRUE_VALUE;
+  if (incr_bb)
+    {
+      gsi = gsi_last_bb (incr_bb);
+      g = gimple_build_cond (LT_EXPR, iter2,
+			     build_int_cst (unsigned_type_node,
+					    node->simdclone->simdlen),
+			     NULL, NULL);
+      gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
+      edge e = split_block (incr_bb, gsi_stmt (gsi));
+      latch_bb = e->dest;
+      new_exit_bb = split_block_after_labels (latch_bb)->dest;
+      loop->latch = latch_bb;
+
+      redirect_edge_succ (FALLTHRU_EDGE (latch_bb), body_bb);
+
+      make_edge (incr_bb, new_exit_bb, EDGE_FALSE_VALUE);
+      /* The successor of incr_bb is already pointing to latch_bb; just
+	 change the flags.
+	 make_edge (incr_bb, latch_bb, EDGE_TRUE_VALUE);  */
+      FALLTHRU_EDGE (incr_bb)->flags = EDGE_TRUE_VALUE;
+    }
 
   gphi *phi = create_phi_node (iter1, body_bb);
   edge preheader_edge = find_edge (entry_bb, body_bb);
-  edge latch_edge = single_succ_edge (latch_bb);
+  edge latch_edge = NULL;
   add_phi_arg (phi, build_zero_cst (unsigned_type_node), preheader_edge,
 	       UNKNOWN_LOCATION);
-  add_phi_arg (phi, iter2, latch_edge, UNKNOWN_LOCATION);
-
-  /* Generate the new return.  */
-  gsi = gsi_last_bb (new_exit_bb);
-  if (retval
-      && TREE_CODE (retval) == VIEW_CONVERT_EXPR
-      && TREE_CODE (TREE_OPERAND (retval, 0)) == RESULT_DECL)
-    retval = TREE_OPERAND (retval, 0);
-  else if (retval)
+  if (incr_bb)
     {
-      retval = build1 (VIEW_CONVERT_EXPR,
-		       TREE_TYPE (TREE_TYPE (node->decl)),
-		       retval);
-      retval = force_gimple_operand_gsi (&gsi, retval, true, NULL,
-					 false, GSI_CONTINUE_LINKING);
+      latch_edge = single_succ_edge (latch_bb);
+      add_phi_arg (phi, iter2, latch_edge, UNKNOWN_LOCATION);
+
+      /* Generate the new return.  */
+      gsi = gsi_last_bb (new_exit_bb);
+      if (retval
+	  && TREE_CODE (retval) == VIEW_CONVERT_EXPR
+	  && TREE_CODE (TREE_OPERAND (retval, 0)) == RESULT_DECL)
+	retval = TREE_OPERAND (retval, 0);
+      else if (retval)
+	{
+	  retval = build1 (VIEW_CONVERT_EXPR,
+			   TREE_TYPE (TREE_TYPE (node->decl)),
+			   retval);
+	  retval = force_gimple_operand_gsi (&gsi, retval, true, NULL,
+					     false, GSI_CONTINUE_LINKING);
+	}
+      g = gimple_build_return (retval);
+      gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
     }
-  g = gimple_build_return (retval);
-  gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING);
 
   /* Handle aligned clauses by replacing default defs of the aligned
      uniform args with __builtin_assume_aligned (arg_N(D), alignment)
@@ -1386,7 +1413,8 @@ simd_clone_adjust (struct cgraph_node *n
 	  {
 	    def = make_ssa_name (TREE_TYPE (orig_arg));
 	    iter1 = make_ssa_name (TREE_TYPE (orig_arg));
-	    iter2 = make_ssa_name (TREE_TYPE (orig_arg));
+	    if (incr_bb)
+	      iter2 = make_ssa_name (TREE_TYPE (orig_arg));
 	    gsi = gsi_after_labels (entry_bb);
 	    g = gimple_build_assign (def, orig_arg);
 	    gsi_insert_before (&gsi, g, GSI_NEW_STMT);
@@ -1399,23 +1427,27 @@ simd_clone_adjust (struct cgraph_node *n
 	    else
 	      {
 		iter1 = make_ssa_name (orig_arg);
-		iter2 = make_ssa_name (orig_arg);
+		if (incr_bb)
+		  iter2 = make_ssa_name (orig_arg);
 	      }
 	  }
 	if (def)
 	  {
 	    phi = create_phi_node (iter1, body_bb);
 	    add_phi_arg (phi, def, preheader_edge, UNKNOWN_LOCATION);
-	    add_phi_arg (phi, iter2, latch_edge, UNKNOWN_LOCATION);
-	    enum tree_code code = INTEGRAL_TYPE_P (TREE_TYPE (orig_arg))
-				  ? PLUS_EXPR : POINTER_PLUS_EXPR;
-	    tree addtype = INTEGRAL_TYPE_P (TREE_TYPE (orig_arg))
-			   ? TREE_TYPE (orig_arg) : sizetype;
-	    tree addcst = simd_clone_linear_addend (node, i, addtype,
-						    entry_bb);
-	    gsi = gsi_last_bb (incr_bb);
-	    g = gimple_build_assign (iter2, code, iter1, addcst);
-	    gsi_insert_before (&gsi, g, GSI_SAME_STMT);
+	    if (incr_bb)
+	      {
+		add_phi_arg (phi, iter2, latch_edge, UNKNOWN_LOCATION);
+		enum tree_code code = INTEGRAL_TYPE_P (TREE_TYPE (orig_arg))
+				      ? PLUS_EXPR : POINTER_PLUS_EXPR;
+		tree addtype = INTEGRAL_TYPE_P (TREE_TYPE (orig_arg))
+			       ? TREE_TYPE (orig_arg) : sizetype;
+		tree addcst = simd_clone_linear_addend (node, i, addtype,
+							entry_bb);
+		gsi = gsi_last_bb (incr_bb);
+		g = gimple_build_assign (iter2, code, iter1, addcst);
+		gsi_insert_before (&gsi, g, GSI_SAME_STMT);
+	      }
 
 	    imm_use_iterator iter;
 	    use_operand_p use_p;
@@ -1448,10 +1480,11 @@ simd_clone_adjust (struct cgraph_node *n
 	  {
 	    tree rtype = TREE_TYPE (TREE_TYPE (orig_arg));
 	    iter1 = make_ssa_name (orig_arg);
-	    iter2 = make_ssa_name (orig_arg);
+	    if (incr_bb)
+	      iter2 = make_ssa_name (orig_arg);
 	    tree iter3 = make_ssa_name (rtype);
 	    tree iter4 = make_ssa_name (rtype);
-	    tree iter5 = make_ssa_name (rtype);
+	    tree iter5 = incr_bb ? make_ssa_name (rtype) : NULL_TREE;
 	    gsi = gsi_after_labels (entry_bb);
 	    gimple *load
 	      = gimple_build_assign (iter3, build_simple_mem_ref (def));
@@ -1462,24 +1495,30 @@ simd_clone_adjust (struct cgraph_node *n
 	    tree ptr = build_fold_addr_expr (array);
 	    phi = create_phi_node (iter1, body_bb);
 	    add_phi_arg (phi, ptr, preheader_edge, UNKNOWN_LOCATION);
-	    add_phi_arg (phi, iter2, latch_edge, UNKNOWN_LOCATION);
-	    g = gimple_build_assign (iter2, POINTER_PLUS_EXPR, iter1,
-				     TYPE_SIZE_UNIT (TREE_TYPE (iter3)));
-	    gsi = gsi_last_bb (incr_bb);
-	    gsi_insert_before (&gsi, g, GSI_SAME_STMT);
+	    if (incr_bb)
+	      {
+		add_phi_arg (phi, iter2, latch_edge, UNKNOWN_LOCATION);
+		g = gimple_build_assign (iter2, POINTER_PLUS_EXPR, iter1,
+					 TYPE_SIZE_UNIT (TREE_TYPE (iter3)));
+		gsi = gsi_last_bb (incr_bb);
+		gsi_insert_before (&gsi, g, GSI_SAME_STMT);
+	      }
 
 	    phi = create_phi_node (iter4, body_bb);
 	    add_phi_arg (phi, iter3, preheader_edge, UNKNOWN_LOCATION);
-	    add_phi_arg (phi, iter5, latch_edge, UNKNOWN_LOCATION);
-	    enum tree_code code = INTEGRAL_TYPE_P (TREE_TYPE (iter3))
-				  ? PLUS_EXPR : POINTER_PLUS_EXPR;
-	    tree addtype = INTEGRAL_TYPE_P (TREE_TYPE (iter3))
-			   ? TREE_TYPE (iter3) : sizetype;
-	    tree addcst = simd_clone_linear_addend (node, i, addtype,
-						    entry_bb);
-	    g = gimple_build_assign (iter5, code, iter4, addcst);
-	    gsi = gsi_last_bb (incr_bb);
-	    gsi_insert_before (&gsi, g, GSI_SAME_STMT);
+	    if (incr_bb)
+	      {
+		add_phi_arg (phi, iter5, latch_edge, UNKNOWN_LOCATION);
+		enum tree_code code = INTEGRAL_TYPE_P (TREE_TYPE (iter3))
+				      ? PLUS_EXPR : POINTER_PLUS_EXPR;
+		tree addtype = INTEGRAL_TYPE_P (TREE_TYPE (iter3))
+			       ? TREE_TYPE (iter3) : sizetype;
+		tree addcst = simd_clone_linear_addend (node, i, addtype,
+							entry_bb);
+		g = gimple_build_assign (iter5, code, iter4, addcst);
+		gsi = gsi_last_bb (incr_bb);
+		gsi_insert_before (&gsi, g, GSI_SAME_STMT);
+	      }
 
 	    g = gimple_build_assign (build_simple_mem_ref (iter1), iter4);
 	    gsi = gsi_after_labels (body_bb);
@@ -1495,7 +1534,7 @@ simd_clone_adjust (struct cgraph_node *n
 		FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
 		  SET_USE (use_p, iter1);
 
-	    if (!TYPE_READONLY (rtype))
+	    if (!TYPE_READONLY (rtype) && incr_bb)
 	      {
 		tree v = make_ssa_name (rtype);
 		tree aref = build4 (ARRAY_REF, rtype, array,
@@ -1511,7 +1550,8 @@ simd_clone_adjust (struct cgraph_node *n
       }
 
   calculate_dominance_info (CDI_DOMINATORS);
-  add_loop (loop, loop->header->loop_father);
+  if (loop)
+    add_loop (loop, loop->header->loop_father);
   update_ssa (TODO_update_ssa);
 
   pop_cfun ();
--- gcc/testsuite/g++.dg/gomp/declare-simd-7.C.jj	2016-10-27 10:57:40.113925573 +0200
+++ gcc/testsuite/g++.dg/gomp/declare-simd-7.C	2016-10-27 11:00:24.585849893 +0200
@@ -0,0 +1,50 @@
+// PR middle-end/78025
+// { dg-do compile }
+// { dg-additional-options "-O2" }
+
+struct S { S (); ~S (); };
+
+int bar1 (int, int, float &, S &, int *, int, int &, int &, int &, int &, int &);
+int bar2 (int, int, float &, S &, int *, int, int &, int &, int &, int &, int &);
+int bar3 (int, int, float &, S &, int *, int, int &, int &, int &, int &, int &) __attribute__((noreturn));
+int bar4 (int, int, float &, S &, int *, int, int &, int &, int &, int &, int &) __attribute__((noreturn));
+
+#pragma omp declare simd notinbranch uniform (b, c, d, e) aligned (e : 16) \
+		    linear (f : 2) linear (ref (g) : 1) \
+		    linear (val (h) : 1) linear (uval (i) : 1) \
+		    linear (k : 4)
+int
+foo1 (int a, int b, float c, S d, int *e, int f, int &g, int &h, int &i, int j, int k)
+{
+  return bar1 (a, b, c, d, e, f, g, h, i, j, k);
+}
+
+#pragma omp declare simd inbranch uniform (b, c, d, e) aligned (e : 16) \
+		    linear (f : 2) linear (ref (g) : 1) \
+		    linear (val (h) : 1) linear (uval (i) : 1) \
+		    linear (k : 4)
+int
+foo2 (int a, int b, float c, S d, int *e, int f, int &g, int &h, int &i, int j, int k)
+{
+  return bar2 (a, b, c, d, e, f, g, h, i, j, k);
+}
+
+#pragma omp declare simd notinbranch uniform (b, c, d, e) aligned (e : 16) \
+		    linear (f : 2) linear (ref (g) : 1) \
+		    linear (val (h) : 1) linear (uval (i) : 1) \
+		    linear (k : 4)
+int
+foo3 (int a, int b, float c, S d, int *e, int f, int &g, int &h, int &i, int j, int k)
+{
+  return bar3 (a, b, c, d, e, f, g, h, i, j, k);
+}
+
+#pragma omp declare simd inbranch uniform (b, c, d, e) aligned (e : 16) \
+		    linear (f : 2) linear (ref (g) : 1) \
+		    linear (val (h) : 1) linear (uval (i) : 1) \
+		    linear (k : 4)
+int
+foo4 (int a, int b, float c, S d, int *e, int f, int &g, int &h, int &i, int j, int k)
+{
+  return bar4 (a, b, c, d, e, f, g, h, i, j, k);
+}

	Jakub



More information about the Gcc-patches mailing list