gigi.h (is_simple_additive_expression): Declare.
* 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
This commit is contained in:
parent
f8125f0c9c
commit
933a73251d
@ -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.
|
||||
|
@ -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. */
|
||||
|
@ -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 low_ok, high_ok;
|
||||
|
||||
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;
|
||||
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)),
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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" } }
|
||||
|
Loading…
Reference in New Issue
Block a user