summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Botcazou <ebotcazou@adacore.com>2015-06-26 10:03:22 +0000
committerEric Botcazou <ebotcazou@gcc.gnu.org>2015-06-26 10:03:22 +0000
commit87ab2b04ae1997b5b90f5dd11494f2186ee4f3a8 (patch)
tree02d1c7bd4feb8917b2ba8c73342c9d9ba436756f
parent63be509029db0b15f445400c75722862cf252b25 (diff)
downloadgcc-87ab2b04ae1997b5b90f5dd11494f2186ee4f3a8.tar.gz
trans.c (loop_info_d): Add low_bound...
* gcc-interface/trans.c (loop_info_d): Add low_bound, high_bound, artificial, has_checks and warned_aggressive_loop_optimizations. (gigi): Set warn_aggressive_loop_optimizations to 0. (inside_loop_p): New inline predicate. (push_range_check_info): Rename into... (find_loop_for): ...this and do not push range_check_info_d object. (Loop_Statement_to_gnu): Set artificial, low_bound and high_bound fields of gnu_loop_info. Adjust detection of checks enabled by -funswitch-loops and adds one for -faggressive-loop-optimizations. (gnat_to_gnu) <N_Indexed_Component>: If aggressive loop optimizations are enabled, warn for loops overrunning an array of size 1 not at the end of a record. From-SVN: r224998
-rw-r--r--gcc/ada/ChangeLog15
-rw-r--r--gcc/ada/gcc-interface/trans.c87
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/gnat.dg/warn11.adb2
-rw-r--r--gcc/testsuite/gnat.dg/warn12.adb48
-rw-r--r--gcc/testsuite/gnat.dg/warn12_pkg.ads21
6 files changed, 161 insertions, 18 deletions
diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog
index 3926d2df39f..b2319aa0d5b 100644
--- a/gcc/ada/ChangeLog
+++ b/gcc/ada/ChangeLog
@@ -1,3 +1,18 @@
+2015-06-26 Eric Botcazou <ebotcazou@adacore.com>
+
+ * gcc-interface/trans.c (loop_info_d): Add low_bound, high_bound,
+ artificial, has_checks and warned_aggressive_loop_optimizations.
+ (gigi): Set warn_aggressive_loop_optimizations to 0.
+ (inside_loop_p): New inline predicate.
+ (push_range_check_info): Rename into...
+ (find_loop_for): ...this and do not push range_check_info_d object.
+ (Loop_Statement_to_gnu): Set artificial, low_bound and high_bound
+ fields of gnu_loop_info. Adjust detection of checks enabled by
+ -funswitch-loops and adds one for -faggressive-loop-optimizations.
+ (gnat_to_gnu) <N_Indexed_Component>: If aggressive loop optimizations
+ are enabled, warn for loops overrunning an array of size 1 not at the
+ end of a record.
+
2015-06-25 Andrew MacLeod <amacleod@redhat.com>
* gcc-interface/trans.c: Remove ipa-ref.h and plugin-api.h from include
diff --git a/gcc/ada/gcc-interface/trans.c b/gcc/ada/gcc-interface/trans.c
index e9a9e4ae5f8..ff910cec343 100644
--- a/gcc/ada/gcc-interface/trans.c
+++ b/gcc/ada/gcc-interface/trans.c
@@ -209,7 +209,12 @@ typedef struct range_check_info_d *range_check_info;
struct GTY(()) loop_info_d {
tree stmt;
tree loop_var;
+ tree low_bound;
+ tree high_bound;
vec<range_check_info, va_gc> *checks;
+ bool artificial;
+ bool has_checks;
+ bool warned_aggressive_loop_optimizations;
};
typedef struct loop_info_d *loop_info;
@@ -671,6 +676,10 @@ gigi (Node_Id gnat_root,
/* Now translate the compilation unit proper. */
Compilation_Unit_to_gnu (gnat_root);
+ /* Disable -Waggressive-loop-optimizations since we implement our own
+ version of the warning. */
+ warn_aggressive_loop_optimizations = 0;
+
/* Then process the N_Validate_Unchecked_Conversion nodes. We do this at
the very end to avoid having to second-guess the front-end when we run
into dummy nodes during the regular processing. */
@@ -2622,12 +2631,19 @@ Case_Statement_to_gnu (Node_Id gnat_node)
return gnu_result;
}
-/* Find out whether VAR is an iteration variable of an enclosing loop in the
- current function. If so, push a range_check_info structure onto the stack
- of this enclosing loop and return it. Otherwise, return NULL. */
+/* Return true if we are in the body of a loop. */
+
+static inline bool
+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. */
-static struct range_check_info_d *
-push_range_check_info (tree var)
+static struct loop_info_d *
+find_loop_for (tree var)
{
struct loop_info_d *iter = NULL;
unsigned int i;
@@ -2648,14 +2664,7 @@ push_range_check_info (tree var)
if (var == iter->loop_var)
break;
- if (iter)
- {
- struct range_check_info_d *rci = ggc_alloc<range_check_info_d> ();
- vec_safe_push (iter->checks, rci);
- return rci;
- }
-
- return NULL;
+ return iter;
}
/* Return true if VAL (of type TYPE) can equal the minimum value if MAX is
@@ -2746,6 +2755,7 @@ Loop_Statement_to_gnu (Node_Id gnat_node)
/* Save the statement for later reuse. */
gnu_loop_info->stmt = gnu_loop_stmt;
+ gnu_loop_info->artificial = !Comes_From_Source (gnat_node);
/* Set the condition under which the loop must keep going.
For the case "LOOP .... END LOOP;" the condition is always true. */
@@ -2941,6 +2951,8 @@ Loop_Statement_to_gnu (Node_Id gnat_node)
SET_DECL_INDUCTION_VAR (gnu_loop_var, gnu_loop_iv);
}
gnu_loop_info->loop_var = gnu_loop_var;
+ gnu_loop_info->low_bound = gnu_low;
+ gnu_loop_info->high_bound = gnu_high;
/* Do all the arithmetics in the base type. */
gnu_loop_var = convert (gnu_base_type, gnu_loop_var);
@@ -5334,7 +5346,7 @@ Raise_Error_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p)
{
Node_Id gnat_range, gnat_index, gnat_type;
tree gnu_index, gnu_low_bound, gnu_high_bound;
- struct range_check_info_d *rci;
+ struct loop_info_d *loop;
switch (Nkind (Right_Opnd (gnat_cond)))
{
@@ -5382,24 +5394,36 @@ Raise_Error_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p)
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
- && !vec_safe_is_empty (gnu_loop_stack)
+ if (optimize
+ && flag_unswitch_loops
+ && inside_loop_p ()
&& (!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)))
+ && (loop = find_loop_for (gnu_index)))
{
+ 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->type = get_unpadded_type (gnat_type);
rci->invariant_cond = build1 (SAVE_EXPR, boolean_type_node,
boolean_true_node);
+ vec_safe_push (loop->checks, rci);
+ loop->has_checks = true;
gnu_cond = build_binary_op (TRUTH_ANDIF_EXPR,
boolean_type_node,
rci->invariant_cond,
gnat_to_gnu (gnat_cond));
}
+
+ /* Or else, if aggressive loop optimizations are enabled, we just
+ record that there are checks applied to iteration variables. */
+ else if (optimize
+ && flag_aggressive_loop_optimizations
+ && inside_loop_p ()
+ && (loop = find_loop_for (gnu_index)))
+ loop->has_checks = true;
}
break;
@@ -5939,11 +5963,13 @@ gnat_to_gnu (Node_Id gnat_node)
gnat_expr_array[i] = gnat_temp;
for (i = 0, gnu_type = TREE_TYPE (gnu_array_object);
- i < ndim; i++, gnu_type = TREE_TYPE (gnu_type))
+ i < ndim;
+ i++, gnu_type = TREE_TYPE (gnu_type))
{
gcc_assert (TREE_CODE (gnu_type) == ARRAY_TYPE);
gnat_temp = gnat_expr_array[i];
gnu_expr = gnat_to_gnu (gnat_temp);
+ struct loop_info_d *loop;
if (Do_Range_Check (gnat_temp))
gnu_expr
@@ -5965,6 +5991,31 @@ gnat_to_gnu (Node_Id gnat_node)
&& !(Nkind (gnat_temp) == N_Identifier
&& Ekind (Entity (gnat_temp)) == E_Constant))
TREE_THIS_NOTRAP (gnu_result) = 1;
+
+ /* If aggressive loop optimizations are enabled, we warn for loops
+ overrunning a simple array of size 1 not at the end of a record.
+ This is aimed to catch misuses of the trailing array idiom. */
+ if (optimize
+ && flag_aggressive_loop_optimizations
+ && inside_loop_p ()
+ && TREE_CODE (TREE_TYPE (gnu_type)) != ARRAY_TYPE
+ && TREE_CODE (gnu_array_object) != ARRAY_REF
+ && 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->artificial
+ && !loop->has_checks
+ && tree_int_cst_equal (TYPE_MIN_VALUE (TYPE_DOMAIN (gnu_type)),
+ loop->low_bound)
+ && can_be_lower_p (loop->low_bound, loop->high_bound)
+ && !loop->warned_aggressive_loop_optimizations
+ && warning (OPT_Waggressive_loop_optimizations,
+ "out-of-bounds access may be optimized away"))
+ {
+ inform (EXPR_LOCATION (loop->stmt), "containing loop");
+ loop->warned_aggressive_loop_optimizations = true;
+ }
}
gnu_result_type = get_unpadded_type (Etype (gnat_node));
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index bccda4a31df..e3ae30a0a38 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2015-06-26 Eric Botcazou <ebotcazou@adacore.com>
+
+ * gnat.dg/warn11.adb: Add missing dg directive.
+ * gnat.dg/warn12.adb: New test.
+ * gnat.dg/warn12_pkg.ads: New helper.
+
2015-06-26 Richard Biener <rguenther@suse.de>
* gfortran.dg/reassoc_3.f90: Adjust.
diff --git a/gcc/testsuite/gnat.dg/warn11.adb b/gcc/testsuite/gnat.dg/warn11.adb
index ff24d7c336c..e92835f0533 100644
--- a/gcc/testsuite/gnat.dg/warn11.adb
+++ b/gcc/testsuite/gnat.dg/warn11.adb
@@ -1,3 +1,5 @@
+-- { dg-do compile }
+
with Ada.Text_IO; use Ada.Text_IO;
procedure Warn11 is
diff --git a/gcc/testsuite/gnat.dg/warn12.adb b/gcc/testsuite/gnat.dg/warn12.adb
new file mode 100644
index 00000000000..8ffd0c7dff0
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/warn12.adb
@@ -0,0 +1,48 @@
+-- { dg-do compile }
+-- { dg-options "-O2" }
+
+with Text_IO; use Text_IO;
+with System.Storage_Elements; use System.Storage_Elements;
+with Warn12_Pkg; use Warn12_Pkg;
+
+procedure Warn12 (N : Natural) is
+
+ Buffer_Size : constant Storage_Offset
+ := Token_Groups'Size/System.Storage_Unit + 4096;
+
+ Buffer : Storage_Array (1 .. Buffer_Size);
+ for Buffer'Alignment use 8;
+
+ Tg1 : Token_Groups;
+ for Tg1'Address use Buffer'Address;
+
+ Tg2 : Token_Groups;
+ pragma Warnings (Off, Tg2);
+
+ sid : Sid_And_Attributes;
+
+ pragma Suppress (Index_Check, Sid_And_Attributes_Array);
+
+begin
+
+ for I in 0 .. 7 loop
+ sid := Tg1.Groups(I); -- { dg-bogus "out-of-bounds access" }
+ Put_Line("Iteration");
+ end loop;
+
+ for I in 0 .. N loop
+ sid := Tg1.Groups(I); -- { dg-bogus "out-of-bounds access" }
+ Put_Line("Iteration");
+ end loop;
+
+ for I in 0 .. 7 loop
+ sid := Tg2.Groups(I); -- { dg-warning "out-of-bounds access" }
+ Put_Line("Iteration");
+ end loop;
+
+ for I in 0 .. N loop
+ sid := Tg2.Groups(I); -- { dg-warning "out-of-bounds access" }
+ Put_Line("Iteration");
+ end loop;
+
+end;
diff --git a/gcc/testsuite/gnat.dg/warn12_pkg.ads b/gcc/testsuite/gnat.dg/warn12_pkg.ads
new file mode 100644
index 00000000000..b3191cc304f
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/warn12_pkg.ads
@@ -0,0 +1,21 @@
+with Interfaces.C; use Interfaces.C;
+with System;
+
+package Warn12_Pkg is
+
+ Anysize_Array: constant := 0;
+
+ type Sid_And_Attributes is record
+ Sid : System.Address;
+ Attributes : Interfaces.C.Unsigned_Long;
+ end record;
+
+ type Sid_And_Attributes_Array
+ is array (Integer range 0..Anysize_Array) of aliased Sid_And_Attributes;
+
+ type Token_Groups is record
+ GroupCount : Interfaces.C.Unsigned_Long;
+ Groups : Sid_And_Attributes_Array;
+ end record;
+
+end Warn12_Pkg;