diff options
author | Richard Biener <rguenther@suse.de> | 2013-01-17 09:53:19 +0000 |
---|---|---|
committer | Richard Biener <rguenth@gcc.gnu.org> | 2013-01-17 09:53:19 +0000 |
commit | c5e7e996fba2a45b4b36e8831c1d9dd4382d3b34 (patch) | |
tree | cabd8dda4fc2522cef651699779a9f00b577ba59 /gcc | |
parent | df69b59879e493a6b42c3a750e303cc15b163cec (diff) | |
download | gcc-c5e7e996fba2a45b4b36e8831c1d9dd4382d3b34.zip gcc-c5e7e996fba2a45b4b36e8831c1d9dd4382d3b34.tar.gz gcc-c5e7e996fba2a45b4b36e8831c1d9dd4382d3b34.tar.bz2 |
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
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/fortran/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/fortran/trans-stmt.c | 69 |
2 files changed, 42 insertions, 34 deletions
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 6477c48..730c41b 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -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 diff --git a/gcc/fortran/trans-stmt.c b/gcc/fortran/trans-stmt.c index 1d240cb..14c37f7 100644 --- a/gcc/fortran/trans-stmt.c +++ b/gcc/fortran/trans-stmt.c @@ -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)); - - tmp = fold_build2_loc (loc, GT_EXPR, boolean_type_node, to, - from); + fold_build2 (MODIFY_EXPR, void_type_node, + countm1, tmp2)); + + /* 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), |