Commit c5e7e996 by Richard Biener Committed by Richard Biener

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
parent df69b598
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> 2013-01-16 Janus Weil <janus@gcc.gnu.org>
PR fortran/55983 PR fortran/55983
......
...@@ -1543,7 +1543,6 @@ gfc_trans_do (gfc_code * code, tree exit_cond) ...@@ -1543,7 +1543,6 @@ gfc_trans_do (gfc_code * code, tree exit_cond)
tree cycle_label; tree cycle_label;
tree exit_label; tree exit_label;
tree tmp; tree tmp;
tree pos_step;
stmtblock_t block; stmtblock_t block;
stmtblock_t body; stmtblock_t body;
location_t loc; location_t loc;
...@@ -1588,8 +1587,6 @@ gfc_trans_do (gfc_code * code, tree exit_cond) ...@@ -1588,8 +1587,6 @@ gfc_trans_do (gfc_code * code, tree exit_cond)
|| tree_int_cst_equal (step, integer_minus_one_node))) || tree_int_cst_equal (step, integer_minus_one_node)))
return gfc_trans_simple_do (code, &block, dovar, from, to, step, exit_cond); 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) if (TREE_CODE (type) == INTEGER_TYPE)
utype = unsigned_type_for (type); utype = unsigned_type_for (type);
...@@ -1618,65 +1615,67 @@ gfc_trans_do (gfc_code * code, tree exit_cond) ...@@ -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. /* 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: This code is executed before we enter the loop body. We generate:
step_sign = sign(1,step);
if (step > 0) if (step > 0)
{ {
if (to < from) if (to < from)
goto exit_label; goto exit_label;
countm1 = (to - from) / step;
} }
else else
{ {
if (to > from) if (to > from)
goto exit_label; goto exit_label;
countm1 = (from - to) / -step;
} }
countm1 = (to*step_sign - from*step_sign) / (step*step_sign); */
*/
if (TREE_CODE (type) == INTEGER_TYPE) 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) */ /* The distance from FROM to TO cannot always be represented in a signed
type, thus use unsigned arithmetic, also to avoid any undefined
tmp = fold_build2_loc (loc, LT_EXPR, boolean_type_node, step, overflow issues. */
build_int_cst (TREE_TYPE (step), 0)); tou = fold_convert (utype, to);
step_sign = fold_build3_loc (loc, COND_EXPR, type, tmp, fromu = fold_convert (utype, from);
build_int_cst (type, -1), stepu = fold_convert (utype, step);
build_int_cst (type, 1));
/* 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); 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, pos = fold_build3_loc (loc, COND_EXPR, void_type_node, tmp,
fold_build1_loc (loc, GOTO_EXPR, void_type_node, fold_build1_loc (loc, GOTO_EXPR, void_type_node,
exit_label), 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, neg = fold_build3_loc (loc, COND_EXPR, void_type_node, tmp,
fold_build1_loc (loc, GOTO_EXPR, void_type_node, fold_build1_loc (loc, GOTO_EXPR, void_type_node,
exit_label), exit_label),
build_empty_stmt (loc)); fold_build2 (MODIFY_EXPR, void_type_node,
tmp = fold_build3_loc (loc, COND_EXPR, void_type_node, countm1, tmp2));
pos_step, pos, neg);
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); gfc_add_expr_to_block (&block, tmp);
} }
else else
{ {
tree pos_step;
/* TODO: We could use the same width as the real type. /* TODO: We could use the same width as the real type.
This would probably cause more problems that it solves This would probably cause more problems that it solves
when we implement "long double" types. */ when we implement "long double" types. */
...@@ -1688,6 +1687,8 @@ gfc_trans_do (gfc_code * code, tree exit_cond) ...@@ -1688,6 +1687,8 @@ gfc_trans_do (gfc_code * code, tree exit_cond)
/* We need a special check for empty loops: /* We need a special check for empty loops:
empty = (step > 0 ? to < from : to > from); */ 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, tmp = fold_build3_loc (loc, COND_EXPR, boolean_type_node, pos_step,
fold_build2_loc (loc, LT_EXPR, fold_build2_loc (loc, LT_EXPR,
boolean_type_node, to, from), boolean_type_node, to, from),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment