aboutsummaryrefslogtreecommitdiff
path: root/gcc/ada/gcc-interface/utils.c
diff options
context:
space:
mode:
authorEric Botcazou <ebotcazou@gcc.gnu.org>2011-10-12 22:00:14 +0000
committerEric Botcazou <ebotcazou@gcc.gnu.org>2011-10-12 22:00:14 +0000
commit15bf7d19d4a0dc2eed0ae5dcac5cdb3a35ec7db8 (patch)
tree41c1d92f48d823ae6099ab833bb5304343a3034e /gcc/ada/gcc-interface/utils.c
parent578f023490bab56ea603aa4374ecbf31b38c24b5 (diff)
downloadgcc-15bf7d19d4a0dc2eed0ae5dcac5cdb3a35ec7db8.zip
gcc-15bf7d19d4a0dc2eed0ae5dcac5cdb3a35ec7db8.tar.gz
gcc-15bf7d19d4a0dc2eed0ae5dcac5cdb3a35ec7db8.tar.bz2
ada-tree.h (DECL_LOOP_PARM_P): New flag.
* gcc-interface/ada-tree.h (DECL_LOOP_PARM_P): New flag. (DECL_INDUCTION_VAR): New macro. (SET_DECL_INDUCTION_VAR): Likewise. * gcc-interface/gigi.h (convert_to_index_type): Declare. (gnat_invariant_expr): Likewise. * gcc-interface/decl.c (gnat_to_gnu_entity) <object>: If this is a loop parameter, set DECL_LOOP_PARM_P on it. * gcc-interface/misc.c (gnat_print_decl) <VAR_DECL>: If DECL_LOOP_PARM_P is set, print DECL_INDUCTION_VAR instead of DECL_RENAMED_OBJECT. * gcc-interface/trans.c (gnu_loop_label_stack): Delete. (struct range_check_info_d): New type. (struct loop_info_d): Likewise. (gnu_loop_stack): New stack. (Identifier_to_gnu): Set TREE_READONLY flag on the first dereference built for a by-double-ref read-only parameter. If DECL_LOOP_PARM_P is set, do not test DECL_RENAMED_OBJECT. (push_range_check_info): New function. (Loop_Statement_to_gnu): Push a new struct loop_info_d instead of just the label. Reference the label and the iteration variable from it. Build the special induction variable in the unsigned version of the size type, if it is larger than the base type. And attach it to the iteration variable if the latter isn't by-ref. In the iteration scheme case, initialize the invariant conditions in front of the loop if deemed profitable. Use gnu_loop_stack. (gnat_to_gnu) <N_Exit_Statement>: Use gnu_loop_stack. <N_Raise_Constraint_Error>: Always process the reason. In the range check and related cases, and if loop unswitching is enabled, compute invariant conditions and push this information onto the stack. Do not translate again the condition if it has been already translated. * gcc-interface/utils.c (record_global_renaming_pointer): Assert that DECL_LOOP_PARM_P isn't set. (convert_to_index_type): New function. * gcc-interface/utils2.c (build_binary_op) <ARRAY_REF>: Use it in order to convert the index from the base index type to sizetype. (gnat_invariant_expr): New function. From-SVN: r179868
Diffstat (limited to 'gcc/ada/gcc-interface/utils.c')
-rw-r--r--gcc/ada/gcc-interface/utils.c88
1 files changed, 87 insertions, 1 deletions
diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c
index 7c7e7c6..c4cfde7 100644
--- a/gcc/ada/gcc-interface/utils.c
+++ b/gcc/ada/gcc-interface/utils.c
@@ -1771,7 +1771,7 @@ process_attributes (tree decl, struct attrib *attr_list)
void
record_global_renaming_pointer (tree decl)
{
- gcc_assert (DECL_RENAMED_OBJECT (decl));
+ gcc_assert (!DECL_LOOP_PARM_P (decl) && DECL_RENAMED_OBJECT (decl));
VEC_safe_push (tree, gc, global_renaming_pointers, decl);
}
@@ -4247,6 +4247,92 @@ convert (tree type, tree expr)
gcc_unreachable ();
}
}
+
+/* Create an expression whose value is that of EXPR converted to the common
+ index type, which is sizetype. EXPR is supposed to be in the base type
+ of the GNAT index type. Calling it is equivalent to doing
+
+ convert (sizetype, expr)
+
+ but we try to distribute the type conversion with the knowledge that EXPR
+ cannot overflow in its type. This is a best-effort approach and we fall
+ back to the above expression as soon as difficulties are encountered.
+
+ This is necessary to overcome issues that arise when the GNAT base index
+ type and the GCC common index type (sizetype) don't have the same size,
+ which is quite frequent on 64-bit architectures. In this case, and if
+ the GNAT base index type is signed but the iteration type of the loop has
+ been forced to unsigned, the loop scalar evolution engine cannot compute
+ a simple evolution for the general induction variables associated with the
+ array indices, because it will preserve the wrap-around semantics in the
+ unsigned type of their "inner" part. As a result, many loop optimizations
+ are blocked.
+
+ The solution is to use a special (basic) induction variable that is at
+ least as large as sizetype, and to express the aforementioned general
+ induction variables in terms of this induction variable, eliminating
+ the problematic intermediate truncation to the GNAT base index type.
+ This is possible as long as the original expression doesn't overflow
+ and if the middle-end hasn't introduced artificial overflows in the
+ course of the various simplification it can make to the expression. */
+
+tree
+convert_to_index_type (tree expr)
+{
+ enum tree_code code = TREE_CODE (expr);
+ tree type = TREE_TYPE (expr);
+
+ /* If the type is unsigned, overflow is allowed so we cannot be sure that
+ EXPR doesn't overflow. Keep it simple if optimization is disabled. */
+ if (TYPE_UNSIGNED (type) || !optimize)
+ return convert (sizetype, expr);
+
+ switch (code)
+ {
+ case VAR_DECL:
+ /* The main effect of the function: replace a loop parameter with its
+ associated special induction variable. */
+ if (DECL_LOOP_PARM_P (expr) && DECL_INDUCTION_VAR (expr))
+ expr = DECL_INDUCTION_VAR (expr);
+ break;
+
+ CASE_CONVERT:
+ {
+ tree otype = TREE_TYPE (TREE_OPERAND (expr, 0));
+ /* Bail out as soon as we suspect some sort of type frobbing. */
+ if (TYPE_PRECISION (type) != TYPE_PRECISION (otype)
+ || TYPE_UNSIGNED (type) != TYPE_UNSIGNED (otype))
+ break;
+ }
+
+ /* ... fall through ... */
+
+ case NON_LVALUE_EXPR:
+ return fold_build1 (code, sizetype,
+ convert_to_index_type (TREE_OPERAND (expr, 0)));
+
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ case MULT_EXPR:
+ return fold_build2 (code, sizetype,
+ convert_to_index_type (TREE_OPERAND (expr, 0)),
+ convert_to_index_type (TREE_OPERAND (expr, 1)));
+
+ case COMPOUND_EXPR:
+ return fold_build2 (code, sizetype, TREE_OPERAND (expr, 0),
+ convert_to_index_type (TREE_OPERAND (expr, 1)));
+
+ case COND_EXPR:
+ return fold_build3 (code, sizetype, TREE_OPERAND (expr, 0),
+ convert_to_index_type (TREE_OPERAND (expr, 1)),
+ convert_to_index_type (TREE_OPERAND (expr, 2)));
+
+ default:
+ break;
+ }
+
+ return convert (sizetype, expr);
+}
/* Remove all conversions that are done in EXP. This includes converting
from a padded type or to a justified modular type. If TRUE_ADDRESS