gigi.h (is_simple_additive_expression): Declare.
authorEric Botcazou <ebotcazou@adacore.com>
Mon, 30 Nov 2015 11:46:32 +0000 (11:46 +0000)
committerEric Botcazou <ebotcazou@gcc.gnu.org>
Mon, 30 Nov 2015 11:46:32 +0000 (11:46 +0000)
* gcc-interface/gigi.h (is_simple_additive_expression): Declare.
* gcc-interface/trans.c (struct range_check_info_d): Add DISP and
NEG_P fields.
(find_loop_for): Add DISP and NEG_P parameters with default value.
Call is_simple_additive_expression to handle additive expressions.
(Loop_Statement_to_gnu): Deal with displacement in range checks.
(Raise_Error_to_gnu): Likewise.
(gnat_to_gnu): Add call to find_loop_for.
(is_simple_additive_expression): New function extracted from...
(gnat_invariant_expr): ...here.  Call it on the expression.

From-SVN: r231064

gcc/ada/ChangeLog
gcc/ada/gcc-interface/gigi.h
gcc/ada/gcc-interface/trans.c
gcc/ada/gcc-interface/utils2.c
gcc/testsuite/gnat.dg/loop_optimization22.adb

index cc0add237d1e23cd8b563d604d0842ce89ee6f7c..fa64fd5b1109f0a868fcdc8749f83b65f07412d3 100644 (file)
@@ -1,3 +1,16 @@
+2015-11-30  Eric Botcazou  <ebotcazou@adacore.com>
+
+       * gcc-interface/gigi.h (is_simple_additive_expression): Declare.
+       * gcc-interface/trans.c (struct range_check_info_d): Add DISP and
+       NEG_P fields.
+       (find_loop_for): Add DISP and NEG_P parameters with default value.
+       Call is_simple_additive_expression to handle additive expressions.
+       (Loop_Statement_to_gnu): Deal with displacement in range checks.
+       (Raise_Error_to_gnu): Likewise.
+       (gnat_to_gnu): Add call to find_loop_for.
+       (is_simple_additive_expression): New function extracted from...
+       (gnat_invariant_expr): ...here.  Call it on the expression.
+
 2015-11-30  Eric Botcazou  <ebotcazou@adacore.com>
 
        * gcc-interface/utils2.c (gnat_invariant_expr): Add type conversions.
index 46ec42e4fd833db20ac3c55c995e5dce6fce2a6b..e98e7e6c8dd38031ccc7a273c13ad59ba2c38a2e 100644 (file)
@@ -962,6 +962,12 @@ extern tree gnat_rewrite_reference (tree ref, rewrite_fn func, void *data,
    i.e. if it doesn't depend on the context in which it is evaluated.  */
 extern tree get_inner_constant_reference (tree exp);
 
+/* Return true if EXPR is the addition or the subtraction of a constant and,
+   if so, set *ADD to the addend, *CST to the constant and *MINUS_P to true
+   if this is a subtraction.  */
+extern bool is_simple_additive_expression (tree expr, tree *add, tree *cst,
+                                          bool *minus_p);
+
 /* If EXPR is an expression that is invariant in the current function, in the
    sense that it can be evaluated anywhere in the function and any number of
    times, return EXPR or an equivalent expression.  Otherwise return NULL.  */
index fdcf9a3c2203114ef85aeb0cec70a7ded039ea25..4c1e3aa54dbcb770455e88149a2c976d1fa12f4a 100644 (file)
@@ -180,6 +180,8 @@ static GTY(()) vec<tree, va_gc> *gnu_return_var_stack;
 struct GTY(()) range_check_info_d {
   tree low_bound;
   tree high_bound;
+  tree disp;
+  bool neg_p;
   tree type;
   tree invariant_cond;
   tree inserted_cond;
@@ -2638,15 +2640,36 @@ inside_loop_p (void)
   return !vec_safe_is_empty (gnu_loop_stack);
 }
 
-/* Find out whether VAR is the iteration variable of an enclosing loop in the
-   current function.  If so, return the loop; otherwise, return NULL.  */
+/* Find out whether EXPR is a simple additive expression based on the iteration
+   variable of some enclosing loop in the current function.  If so, return the
+   loop and set *DISP to the displacement and *NEG_P to true if this is for a
+   subtraction; otherwise, return NULL.  */
 
 static struct loop_info_d *
-find_loop_for (tree var)
+find_loop_for (tree expr, tree *disp = NULL, bool *neg_p = NULL)
 {
+  tree var, add, cst;
+  bool minus_p;
   struct loop_info_d *iter = NULL;
   unsigned int i;
 
+  if (is_simple_additive_expression (expr, &add, &cst, &minus_p))
+    {
+      var = add;
+      if (disp)
+       *disp = cst;
+      if (neg_p)
+       *neg_p = minus_p;
+    }
+  else
+    {
+      var = expr;
+      if (disp)
+       *disp =  NULL_TREE;
+      if (neg_p)
+       *neg_p = false;
+    }
+
   var = remove_conversions (var, false);
 
   if (TREE_CODE (var) != VAR_DECL)
@@ -3123,19 +3146,35 @@ Loop_Statement_to_gnu (Node_Id gnat_node)
 
          FOR_EACH_VEC_ELT (*gnu_loop_info->checks, i, rci)
            {
-             tree low_ok
-               = 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
-               = rci->high_bound
-                 ? build_binary_op (LE_EXPR, boolean_type_node,
-                                    convert (rci->type, gnu_high),
-                                    rci->high_bound)
-                 : boolean_true_node;
+             tree low_ok, high_ok;
+
+             if (rci->low_bound)
+               {
+                 tree gnu_adjusted_low = convert (rci->type, gnu_low);
+                 if (rci->disp)
+                   gnu_adjusted_low
+                     = fold_build2 (rci->neg_p ? MINUS_EXPR : PLUS_EXPR,
+                                    rci->type, gnu_adjusted_low, rci->disp);
+                 low_ok
+                   = build_binary_op (GE_EXPR, boolean_type_node,
+                                      gnu_adjusted_low, rci->low_bound);
+               }
+             else
+               low_ok = boolean_true_node;
+
+             if (rci->high_bound)
+               {
+                 tree gnu_adjusted_high = convert (rci->type, gnu_high);
+                 if (rci->disp)
+                   gnu_adjusted_high
+                     = fold_build2 (rci->neg_p ? MINUS_EXPR : PLUS_EXPR,
+                                    rci->type, gnu_adjusted_high, rci->disp);
+                 high_ok
+                   = build_binary_op (LE_EXPR, boolean_type_node,
+                                      gnu_adjusted_high, rci->high_bound);
+               }
+             else
+               high_ok = boolean_true_node;
 
              tree range_ok
                = build_binary_op (TRUTH_ANDIF_EXPR, boolean_type_node,
@@ -5492,7 +5531,8 @@ Raise_Error_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p)
       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;
+         tree gnu_index, gnu_low_bound, gnu_high_bound, disp;
+         bool neg_p;
          struct loop_info_d *loop;
 
          switch (Nkind (Right_Opnd (gnat_cond)))
@@ -5559,11 +5599,13 @@ Raise_Error_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p)
                  || (gnu_low_bound = gnat_invariant_expr (gnu_low_bound)))
              && (!gnu_high_bound
                  || (gnu_high_bound = gnat_invariant_expr (gnu_high_bound)))
-             && (loop = find_loop_for (gnu_index)))
+             && (loop = find_loop_for (gnu_index, &disp, &neg_p)))
            {
              struct range_check_info_d *rci = ggc_alloc<range_check_info_d> ();
              rci->low_bound = gnu_low_bound;
              rci->high_bound = gnu_high_bound;
+             rci->disp = disp;
+             rci->neg_p = neg_p;
              rci->type = get_unpadded_type (gnat_type);
              rci->inserted_cond
                = build1 (SAVE_EXPR, boolean_type_node, boolean_true_node);
@@ -6197,7 +6239,7 @@ gnat_to_gnu (Node_Id gnat_node)
                && tree_int_cst_equal (TYPE_MIN_VALUE (TYPE_DOMAIN (gnu_type)),
                                       TYPE_MAX_VALUE (TYPE_DOMAIN (gnu_type)))
                && !array_at_struct_end_p (gnu_result)
-               && (loop = find_loop_for (skip_simple_arithmetic (gnu_expr)))
+               && (loop = find_loop_for (gnu_expr))
                && !loop->artificial
                && !loop->has_checks
                && tree_int_cst_equal (TYPE_MIN_VALUE (TYPE_DOMAIN (gnu_type)),
index a74b8a81018d3755e27cfd808591c87ba5632d1d..ca307f36b4b0abab3ddc53fbc767153d8ab52ce2 100644 (file)
@@ -2813,6 +2813,52 @@ done:
   return exp;
 }
 
+/* Return true if EXPR is the addition or the subtraction of a constant and,
+   if so, set *ADD to the addend, *CST to the constant and *MINUS_P to true
+   if this is a subtraction.  */
+
+bool
+is_simple_additive_expression (tree expr, tree *add, tree *cst, bool *minus_p)
+{
+  /* Skip overflow checks.  */
+  if (TREE_CODE (expr) == COND_EXPR
+      && TREE_CODE (COND_EXPR_THEN (expr)) == COMPOUND_EXPR
+      && TREE_CODE (TREE_OPERAND (COND_EXPR_THEN (expr), 0)) == CALL_EXPR
+      && get_callee_fndecl (TREE_OPERAND (COND_EXPR_THEN (expr), 0))
+         == gnat_raise_decls[CE_Overflow_Check_Failed])
+    expr = COND_EXPR_ELSE (expr);
+
+  if (TREE_CODE (expr) == PLUS_EXPR)
+    {
+      if (TREE_CONSTANT (TREE_OPERAND (expr, 0)))
+       {
+         *add = TREE_OPERAND (expr, 1);
+         *cst = TREE_OPERAND (expr, 0);
+         *minus_p = false;
+         return true;
+       }
+      else if (TREE_CONSTANT (TREE_OPERAND (expr, 1)))
+       {
+         *add = TREE_OPERAND (expr, 0);
+         *cst = TREE_OPERAND (expr, 1);
+         *minus_p = false;
+         return true;
+       }
+    }
+  else if (TREE_CODE (expr) == MINUS_EXPR)
+    {
+      if (TREE_CONSTANT (TREE_OPERAND (expr, 1)))
+       {
+         *add = TREE_OPERAND (expr, 0);
+         *cst = TREE_OPERAND (expr, 1);
+         *minus_p = true;
+         return true;
+       }
+    }
+
+  return false;
+}
+
 /* If EXPR is an expression that is invariant in the current function, in the
    sense that it can be evaluated anywhere in the function and any number of
    times, return EXPR or an equivalent expression.  Otherwise return NULL.  */
@@ -2821,6 +2867,8 @@ tree
 gnat_invariant_expr (tree expr)
 {
   const tree type = TREE_TYPE (expr);
+  tree add, cst;
+  bool minus_p;
 
   expr = remove_conversions (expr, false);
 
@@ -2846,23 +2894,14 @@ gnat_invariant_expr (tree expr)
   if (TREE_CONSTANT (expr))
     return fold_convert (type, expr);
 
-  /* Skip overflow checks since they don't change the invariantness.  */
-  if (TREE_CODE (expr) == COND_EXPR
-      && TREE_CODE (COND_EXPR_THEN (expr)) == COMPOUND_EXPR
-      && TREE_CODE (TREE_OPERAND (COND_EXPR_THEN (expr), 0)) == CALL_EXPR
-      && get_callee_fndecl (TREE_OPERAND (COND_EXPR_THEN (expr), 0))
-         == gnat_raise_decls[CE_Overflow_Check_Failed])
-    expr = COND_EXPR_ELSE (expr);
-
   /* Deal with addition or subtraction of constants.  */
-  if (TREE_CODE (expr) == PLUS_EXPR || TREE_CODE (expr) == MINUS_EXPR)
+  if (is_simple_additive_expression (expr, &add, &cst, &minus_p))
     {
-      tree op0 = gnat_invariant_expr (TREE_OPERAND (expr, 0));
-      tree op1 = TREE_OPERAND (expr, 1);
-      if (op0 && TREE_CONSTANT (op1))
+      add = gnat_invariant_expr (add);
+      if (add)
        return
-         fold_build2 (TREE_CODE (expr), type,
-                      fold_convert (type, op0), fold_convert (type, op1));
+         fold_build2 (minus_p ? MINUS_EXPR : PLUS_EXPR, type,
+                      fold_convert (type, add), fold_convert (type, cst));
       else
        return NULL_TREE;
     }
index 7fb307b8fbcab4e57b0d89584928fe0f0792c622..008d07360a8af0d1feb44e3828fc57db2e9adaf5 100644 (file)
@@ -1,5 +1,5 @@
 -- { dg-do compile }
--- { dg-options "-O" }
+-- { dg-options "-O -fdump-tree-optimized" }
 
 pragma Overflow_Mode (Minimized);
 
@@ -14,3 +14,5 @@ package body Loop_Optimization22 is
    end;
 
 end Loop_Optimization22;
+
+-- { dg-final { scan-tree-dump-not "Index_Check" "optimized" } }