This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Ada] Missed vectorization opportunity for assignment loop


In Ada, we have issues with vectorization when full checks are enabled, most 
notably -gnato.  This patch makes it possible to vectorize more loops at -O3.

Tested on i586-suse-linux, applied on the mainline.


2012-05-06  Eric Botcazou  <ebotcazou@adacore.com>

	* gcc-interface/trans.c (Loop_Statement_to_gnu): Also handle invariant
	conditions with only one bound.
	(Raise_Error_to_gnu): Likewise.  New function extracted from...
	(gnat_to_gnu) <N_Raise_Constraint_Error>: ...here.  Call above function
	in regular mode only.


-- 
Eric Botcazou
Index: gcc-interface/trans.c
===================================================================
--- gcc-interface/trans.c	(revision 187206)
+++ gcc-interface/trans.c	(working copy)
@@ -2563,13 +2563,19 @@ Loop_Statement_to_gnu (Node_Id gnat_node
 	     i++)
 	  {
 	    tree low_ok
-	      = build_binary_op (GE_EXPR, boolean_type_node,
-				 convert (rci->type, gnu_low),
-				 rci->low_bound);
+	      = rci->low_bound
+	        ? build_binary_op (GE_EXPR, boolean_type_node,
+				   convert (rci->type, gnu_low),
+				   rci->low_bound)
+		: boolean_true_node;
+
 	    tree high_ok
-	      = build_binary_op (LE_EXPR, boolean_type_node,
-				 convert (rci->type, gnu_high),
-				 rci->high_bound);
+	      = rci->high_bound
+	        ? build_binary_op (LE_EXPR, boolean_type_node,
+				   convert (rci->type, gnu_high),
+				   rci->high_bound)
+		: boolean_true_node;
+
 	    tree range_ok
 	      = build_binary_op (TRUTH_ANDIF_EXPR, boolean_type_node,
 				 low_ok, high_ok);
@@ -2794,7 +2800,7 @@ finalize_nrv_r (tree *tp, int *walk_subt
       tree ret_val = TREE_OPERAND (TREE_OPERAND (t, 0), 1), init_expr;
 
       /* If this is the temporary created for a return value with variable
-	 size in call_to_gnu, we replace the RHS with the init expression.  */
+	 size in Call_to_gnu, we replace the RHS with the init expression.  */
       if (TREE_CODE (ret_val) == COMPOUND_EXPR
 	  && TREE_CODE (TREE_OPERAND (ret_val, 0)) == INIT_EXPR
 	  && TREE_OPERAND (TREE_OPERAND (ret_val, 0), 0)
@@ -3122,7 +3128,7 @@ build_return_expr (tree ret_obj, tree re
 	  && aggregate_value_p (operation_type, current_function_decl))
 	{
 	  /* Recognize the temporary created for a return value with variable
-	     size in call_to_gnu.  We want to eliminate it if possible.  */
+	     size in Call_to_gnu.  We want to eliminate it if possible.  */
 	  if (TREE_CODE (ret_val) == COMPOUND_EXPR
 	      && TREE_CODE (TREE_OPERAND (ret_val, 0)) == INIT_EXPR
 	      && TREE_OPERAND (TREE_OPERAND (ret_val, 0), 0)
@@ -3583,7 +3589,7 @@ create_init_temporary (const char *prefi
    requires atomic synchronization.  */
 
 static tree
-call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target,
+Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target,
 	     bool atomic_sync)
 {
   const bool function_call = (Nkind (gnat_node) == N_Function_Call);
@@ -4751,6 +4757,134 @@ Compilation_Unit_to_gnu (Node_Id gnat_no
   invalidate_global_renaming_pointers ();
 }
 
+/* Subroutine of gnat_to_gnu to translate gnat_node, an N_Raise_xxx_Error,
+   to a GCC tree, which is returned.  GNU_RESULT_TYPE_P is a pointer to where
+   we should place the result type.  LABEL_P is true if there is a label to
+   branch to for the exception.  */
+
+static tree
+Raise_Error_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p)
+{
+  const Node_Kind kind = Nkind (gnat_node);
+  const int reason = UI_To_Int (Reason (gnat_node));
+  const Node_Id gnat_cond = Condition (gnat_node);
+  const bool with_extra_info
+    = Exception_Extra_Info
+      && !No_Exception_Handlers_Set ()
+      && !get_exception_label (kind);
+  tree gnu_result = NULL_TREE, gnu_cond = NULL_TREE;
+
+  *gnu_result_type_p = get_unpadded_type (Etype (gnat_node));
+
+  switch (reason)
+    {
+    case CE_Access_Check_Failed:
+      if (with_extra_info)
+	gnu_result = build_call_raise_column (reason, gnat_node);
+      break;
+
+    case CE_Index_Check_Failed:
+    case CE_Range_Check_Failed:
+    case CE_Invalid_Data:
+      if (Present (gnat_cond) && Nkind (gnat_cond) == N_Op_Not)
+	{
+	  Node_Id gnat_range, gnat_index, gnat_type;
+	  tree gnu_index, gnu_low_bound, gnu_high_bound;
+	  struct range_check_info_d *rci;
+
+	  switch (Nkind (Right_Opnd (gnat_cond)))
+	    {
+	    case N_In:
+	      gnat_range = Right_Opnd (Right_Opnd (gnat_cond));
+	      gcc_assert (Nkind (gnat_range) == N_Range);
+	      gnu_low_bound = gnat_to_gnu (Low_Bound (gnat_range));
+	      gnu_high_bound = gnat_to_gnu (High_Bound (gnat_range));
+	      break;
+
+	    case N_Op_Ge:
+	      gnu_low_bound = gnat_to_gnu (Right_Opnd (Right_Opnd (gnat_cond)));
+	      gnu_high_bound = NULL_TREE;
+	      break;
+
+	    case N_Op_Le:
+	      gnu_low_bound = NULL_TREE;
+	      gnu_high_bound = gnat_to_gnu (Right_Opnd (Right_Opnd (gnat_cond)));
+	      break;
+
+	    default:
+	      goto common;
+	    }
+
+	  gnat_index = Left_Opnd (Right_Opnd (gnat_cond));
+	  gnat_type = Etype (gnat_index);
+	  gnu_index = gnat_to_gnu (gnat_index);
+
+	  if (with_extra_info
+	      && gnu_low_bound
+	      && gnu_high_bound
+	      && Known_Esize (gnat_type)
+	      && UI_To_Int (Esize (gnat_type)) <= 32)
+	    gnu_result
+	      = build_call_raise_range (reason, gnat_node, gnu_index,
+					gnu_low_bound, gnu_high_bound);
+
+	  /* If loop unswitching is enabled, we try to compute invariant
+	     conditions for checks applied to iteration variables, i.e.
+	     conditions that are both independent of the variable and
+	     necessary in order for the check to fail in the course of
+	     some iteration, and prepend them to the original condition
+	     of the checks.  This will make it possible later for the
+	     loop unswitching pass to replace the loop with two loops,
+	     one of which has the checks eliminated and the other has
+	     the original checks reinstated, and a run time selection.
+	     The former loop will be suitable for vectorization.  */
+	  if (flag_unswitch_loops
+	      && (!gnu_low_bound
+		  || (gnu_low_bound = gnat_invariant_expr (gnu_low_bound)))
+	      && (!gnu_high_bound
+		  || (gnu_high_bound = gnat_invariant_expr (gnu_high_bound)))
+	      && (rci = push_range_check_info (gnu_index)))
+	    {
+	      rci->low_bound = gnu_low_bound;
+	      rci->high_bound = gnu_high_bound;
+	      rci->type = gnat_to_gnu_type (gnat_type);
+	      rci->invariant_cond = build1 (SAVE_EXPR, boolean_type_node,
+					    boolean_true_node);
+	      gnu_cond = build_binary_op (TRUTH_ANDIF_EXPR,
+					  boolean_type_node,
+					  rci->invariant_cond,
+					  gnat_to_gnu (gnat_cond));
+	    }
+	}
+      break;
+
+    default:
+      break;
+    }
+
+common:
+  if (!gnu_result)
+    gnu_result = build_call_raise (reason, gnat_node, kind);
+  set_expr_location_from_node (gnu_result, gnat_node);
+
+  /* If the type is VOID, this is a statement, so we need to generate the code
+     for the call.  Handle a condition, if there is one.  */
+  if (VOID_TYPE_P (*gnu_result_type_p))
+    {
+      if (Present (gnat_cond))
+	{
+	  if (!gnu_cond)
+	    gnu_cond = gnat_to_gnu (gnat_cond);
+	  gnu_result = build3 (COND_EXPR, void_type_node, gnu_cond, gnu_result,
+			       alloc_stmt_list ());
+	}
+    }
+  else
+    gnu_result = build1 (NULL_EXPR, *gnu_result_type_p, gnu_result);
+
+  return gnu_result;
+}
+
 /* Return true if GNAT_NODE is on the LHS of an assignment or an actual
    parameter of a call.  */
 
@@ -5949,7 +6083,7 @@ gnat_to_gnu (Node_Id gnat_node)
 				       N_Raise_Storage_Error);
       else if (Nkind (Expression (gnat_node)) == N_Function_Call)
 	gnu_result
-	  = call_to_gnu (Expression (gnat_node), &gnu_result_type, gnu_lhs,
+	  = Call_to_gnu (Expression (gnat_node), &gnu_result_type, gnu_lhs,
 			 atomic_sync_required_p (Name (gnat_node)));
       else
 	{
@@ -6238,7 +6372,7 @@ gnat_to_gnu (Node_Id gnat_node)
 
     case N_Function_Call:
     case N_Procedure_Call_Statement:
-      gnu_result = call_to_gnu (gnat_node, &gnu_result_type, NULL_TREE, false);
+      gnu_result = Call_to_gnu (gnat_node, &gnu_result_type, NULL_TREE, false);
       break;
 
     /************************/
@@ -6661,105 +6795,10 @@ gnat_to_gnu (Node_Id gnat_node)
     case N_Raise_Constraint_Error:
     case N_Raise_Program_Error:
     case N_Raise_Storage_Error:
-      {
-	const int reason = UI_To_Int (Reason (gnat_node));
-	const Node_Id gnat_cond = Condition (gnat_node);
-	const bool with_extra_info = Exception_Extra_Info
-				     && !No_Exception_Handlers_Set ()
-				     && !get_exception_label (kind);
-	tree gnu_cond = NULL_TREE;
-
-	if (type_annotate_only)
-	  {
-	    gnu_result = alloc_stmt_list ();
-	    break;
-	  }
-
-        gnu_result_type = get_unpadded_type (Etype (gnat_node));
-
-	switch (reason)
-	  {
-	  case CE_Access_Check_Failed:
-	    if (with_extra_info)
-	      gnu_result = build_call_raise_column (reason, gnat_node);
-	    break;
-
-	  case CE_Index_Check_Failed:
-	  case CE_Range_Check_Failed:
-	  case CE_Invalid_Data:
-	    if (Present (gnat_cond)
-		&& Nkind (gnat_cond) == N_Op_Not
-		&& Nkind (Right_Opnd (gnat_cond)) == N_In
-		&& Nkind (Right_Opnd (Right_Opnd (gnat_cond))) == N_Range)
-	      {
-		Node_Id gnat_index = Left_Opnd (Right_Opnd (gnat_cond));
-		Node_Id gnat_type = Etype (gnat_index);
-		Node_Id gnat_range = Right_Opnd (Right_Opnd (gnat_cond));
-		tree gnu_index = gnat_to_gnu (gnat_index);
-		tree gnu_low_bound = gnat_to_gnu (Low_Bound (gnat_range));
-		tree gnu_high_bound = gnat_to_gnu (High_Bound (gnat_range));
-		struct range_check_info_d *rci;
-
-		if (with_extra_info
-		    && Known_Esize (gnat_type)
-		    && UI_To_Int (Esize (gnat_type)) <= 32)
-		  gnu_result
-		    = build_call_raise_range (reason, gnat_node, gnu_index,
-					      gnu_low_bound, gnu_high_bound);
-
-		/* If loop unswitching is enabled, we try to compute invariant
-		   conditions for checks applied to iteration variables, i.e.
-		   conditions that are both independent of the variable and
-		   necessary in order for the check to fail in the course of
-		   some iteration, and prepend them to the original condition
-		   of the checks.  This will make it possible later for the
-		   loop unswitching pass to replace the loop with two loops,
-		   one of which has the checks eliminated and the other has
-		   the original checks reinstated, and a run time selection.
-		   The former loop will be suitable for vectorization.  */
-		if (flag_unswitch_loops
-		    && (gnu_low_bound = gnat_invariant_expr (gnu_low_bound))
-		    && (gnu_high_bound = gnat_invariant_expr (gnu_high_bound))
-		    && (rci = push_range_check_info (gnu_index)))
-		  {
-		    rci->low_bound = gnu_low_bound;
-		    rci->high_bound = gnu_high_bound;
-		    rci->type = gnat_to_gnu_type (gnat_type);
-		    rci->invariant_cond = build1 (SAVE_EXPR, boolean_type_node,
-						  boolean_true_node);
-		    gnu_cond = build_binary_op (TRUTH_ANDIF_EXPR,
-						boolean_type_node,
-						rci->invariant_cond,
-						gnat_to_gnu (gnat_cond));
-		  }
-	      }
-	    break;
-
-	  default:
-	    break;
-	  }
-
-	if (gnu_result == error_mark_node)
-	  gnu_result = build_call_raise (reason, gnat_node, kind);
-
-	set_expr_location_from_node (gnu_result, gnat_node);
-
-	/* If the type is VOID, this is a statement, so we need to generate
-	   the code for the call.  Handle a condition, if there is one.  */
-	if (VOID_TYPE_P (gnu_result_type))
-	  {
-	    if (Present (gnat_cond))
-	      {
-		if (!gnu_cond)
-		  gnu_cond = gnat_to_gnu (gnat_cond);
-		gnu_result
-		  = build3 (COND_EXPR, void_type_node, gnu_cond, gnu_result,
-			    alloc_stmt_list ());
-	      }
-	  }
-	else
-	  gnu_result = build1 (NULL_EXPR, gnu_result_type, gnu_result);
-      }
+      if (type_annotate_only)
+	gnu_result = alloc_stmt_list ();
+      else
+	gnu_result = Raise_Error_to_gnu (gnat_node, &gnu_result_type);
       break;
 
     case N_Validate_Unchecked_Conversion:

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]