trans-stmt.c (gfc_trans_do): Conditionally compute countm1 dependent on sign of step...
2013-01-17 Richard Biener <rguenther@suse.de> fortran/ * trans-stmt.c (gfc_trans_do): Conditionally compute countm1 dependent on sign of step, avoids repeated evaluation of step sign test. Avoid undefined overflow issues by using unsigned arithmetic. From-SVN: r195260
This commit is contained in:
parent
df69b59879
commit
c5e7e996fb
2 changed files with 41 additions and 33 deletions
|
@ -1,3 +1,10 @@
|
|||
2013-01-17 Richard Biener <rguenther@suse.de>
|
||||
|
||||
* trans-stmt.c (gfc_trans_do): Conditionally compute countm1
|
||||
dependent on sign of step, avoids repeated evaluation of
|
||||
step sign test. Avoid undefined overflow issues by using unsigned
|
||||
arithmetic.
|
||||
|
||||
2013-01-16 Janus Weil <janus@gcc.gnu.org>
|
||||
|
||||
PR fortran/55983
|
||||
|
|
|
@ -1543,7 +1543,6 @@ gfc_trans_do (gfc_code * code, tree exit_cond)
|
|||
tree cycle_label;
|
||||
tree exit_label;
|
||||
tree tmp;
|
||||
tree pos_step;
|
||||
stmtblock_t block;
|
||||
stmtblock_t body;
|
||||
location_t loc;
|
||||
|
@ -1588,8 +1587,6 @@ gfc_trans_do (gfc_code * code, tree exit_cond)
|
|||
|| tree_int_cst_equal (step, integer_minus_one_node)))
|
||||
return gfc_trans_simple_do (code, &block, dovar, from, to, step, exit_cond);
|
||||
|
||||
pos_step = fold_build2_loc (loc, GT_EXPR, boolean_type_node, step,
|
||||
build_zero_cst (type));
|
||||
|
||||
if (TREE_CODE (type) == INTEGER_TYPE)
|
||||
utype = unsigned_type_for (type);
|
||||
|
@ -1618,65 +1615,67 @@ gfc_trans_do (gfc_code * code, tree exit_cond)
|
|||
|
||||
/* Initialize loop count and jump to exit label if the loop is empty.
|
||||
This code is executed before we enter the loop body. We generate:
|
||||
step_sign = sign(1,step);
|
||||
if (step > 0)
|
||||
{
|
||||
if (to < from)
|
||||
goto exit_label;
|
||||
countm1 = (to - from) / step;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (to > from)
|
||||
goto exit_label;
|
||||
countm1 = (from - to) / -step;
|
||||
}
|
||||
countm1 = (to*step_sign - from*step_sign) / (step*step_sign);
|
||||
|
||||
*/
|
||||
*/
|
||||
|
||||
if (TREE_CODE (type) == INTEGER_TYPE)
|
||||
{
|
||||
tree pos, neg, step_sign, to2, from2, step2;
|
||||
tree pos, neg, tou, fromu, stepu, tmp2;
|
||||
|
||||
/* Calculate SIGN (1,step), as (step < 0 ? -1 : 1) */
|
||||
|
||||
tmp = fold_build2_loc (loc, LT_EXPR, boolean_type_node, step,
|
||||
build_int_cst (TREE_TYPE (step), 0));
|
||||
step_sign = fold_build3_loc (loc, COND_EXPR, type, tmp,
|
||||
build_int_cst (type, -1),
|
||||
build_int_cst (type, 1));
|
||||
/* The distance from FROM to TO cannot always be represented in a signed
|
||||
type, thus use unsigned arithmetic, also to avoid any undefined
|
||||
overflow issues. */
|
||||
tou = fold_convert (utype, to);
|
||||
fromu = fold_convert (utype, from);
|
||||
stepu = fold_convert (utype, step);
|
||||
|
||||
/* For a positive step, when to < from, exit, otherwise compute
|
||||
countm1 = ((unsigned)to - (unsigned)from) / (unsigned)step */
|
||||
tmp = fold_build2_loc (loc, LT_EXPR, boolean_type_node, to, from);
|
||||
tmp2 = fold_build2_loc (loc, TRUNC_DIV_EXPR, utype,
|
||||
fold_build2_loc (loc, MINUS_EXPR, utype,
|
||||
tou, fromu),
|
||||
stepu);
|
||||
pos = fold_build3_loc (loc, COND_EXPR, void_type_node, tmp,
|
||||
fold_build1_loc (loc, GOTO_EXPR, void_type_node,
|
||||
exit_label),
|
||||
build_empty_stmt (loc));
|
||||
fold_build2 (MODIFY_EXPR, void_type_node,
|
||||
countm1, tmp2));
|
||||
|
||||
tmp = fold_build2_loc (loc, GT_EXPR, boolean_type_node, to,
|
||||
from);
|
||||
/* For a negative step, when to > from, exit, otherwise compute
|
||||
countm1 = ((unsigned)from - (unsigned)to) / -(unsigned)step */
|
||||
tmp = fold_build2_loc (loc, GT_EXPR, boolean_type_node, to, from);
|
||||
tmp2 = fold_build2_loc (loc, TRUNC_DIV_EXPR, utype,
|
||||
fold_build2_loc (loc, MINUS_EXPR, utype,
|
||||
fromu, tou),
|
||||
fold_build1_loc (loc, NEGATE_EXPR, utype, stepu));
|
||||
neg = fold_build3_loc (loc, COND_EXPR, void_type_node, tmp,
|
||||
fold_build1_loc (loc, GOTO_EXPR, void_type_node,
|
||||
exit_label),
|
||||
build_empty_stmt (loc));
|
||||
tmp = fold_build3_loc (loc, COND_EXPR, void_type_node,
|
||||
pos_step, pos, neg);
|
||||
fold_build2 (MODIFY_EXPR, void_type_node,
|
||||
countm1, tmp2));
|
||||
|
||||
gfc_add_expr_to_block (&block, tmp);
|
||||
tmp = fold_build2_loc (loc, LT_EXPR, boolean_type_node, step,
|
||||
build_int_cst (TREE_TYPE (step), 0));
|
||||
tmp = fold_build3_loc (loc, COND_EXPR, void_type_node, tmp, neg, pos);
|
||||
|
||||
/* Calculate the loop count. to-from can overflow, so
|
||||
we cast to unsigned. */
|
||||
|
||||
to2 = fold_build2_loc (loc, MULT_EXPR, type, step_sign, to);
|
||||
from2 = fold_build2_loc (loc, MULT_EXPR, type, step_sign, from);
|
||||
step2 = fold_build2_loc (loc, MULT_EXPR, type, step_sign, step);
|
||||
step2 = fold_convert (utype, step2);
|
||||
tmp = fold_build2_loc (loc, MINUS_EXPR, type, to2, from2);
|
||||
tmp = fold_convert (utype, tmp);
|
||||
tmp = fold_build2_loc (loc, TRUNC_DIV_EXPR, utype, tmp, step2);
|
||||
tmp = fold_build2_loc (loc, MODIFY_EXPR, void_type_node, countm1, tmp);
|
||||
gfc_add_expr_to_block (&block, tmp);
|
||||
}
|
||||
else
|
||||
{
|
||||
tree pos_step;
|
||||
|
||||
/* TODO: We could use the same width as the real type.
|
||||
This would probably cause more problems that it solves
|
||||
when we implement "long double" types. */
|
||||
|
@ -1688,6 +1687,8 @@ gfc_trans_do (gfc_code * code, tree exit_cond)
|
|||
|
||||
/* We need a special check for empty loops:
|
||||
empty = (step > 0 ? to < from : to > from); */
|
||||
pos_step = fold_build2_loc (loc, GT_EXPR, boolean_type_node, step,
|
||||
build_zero_cst (type));
|
||||
tmp = fold_build3_loc (loc, COND_EXPR, boolean_type_node, pos_step,
|
||||
fold_build2_loc (loc, LT_EXPR,
|
||||
boolean_type_node, to, from),
|
||||
|
|
Loading…
Add table
Reference in a new issue