diff options
author | Kyrylo Tkachov <kyrylo.tkachov@arm.com> | 2015-08-13 09:11:13 +0000 |
---|---|---|
committer | Kyrylo Tkachov <ktkachov@gcc.gnu.org> | 2015-08-13 09:11:13 +0000 |
commit | d27555bfeeb3f58037d5d399df5ae22c7c90d3fa (patch) | |
tree | aa4ac4831baaf9824599309f3611f743a9366fe3 /gcc | |
parent | 89711ff6cbe5455fb5f4b42038e072d764b30579 (diff) | |
download | gcc-d27555bfeeb3f58037d5d399df5ae22c7c90d3fa.zip gcc-d27555bfeeb3f58037d5d399df5ae22c7c90d3fa.tar.gz gcc-d27555bfeeb3f58037d5d399df5ae22c7c90d3fa.tar.bz2 |
[RTL-ifcvt] Improve conditional select ops on immediates (fix failing x86_64 cmov tests)
PR rtl-optimization/67103
* ifcvt.c (noce_try_store_flag_constants): Move
x = (-(test != 0) & (b - a)) + a transformation to...
(noce_try_cmove): ... Here. Try it if normal conditional
move fails.
From-SVN: r226853
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/ifcvt.c | 77 |
2 files changed, 69 insertions, 16 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 858eede..a677510 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2015-08-13 Kyrylo Tkachov <kyrylo.tkachov@arm.com> + + PR rtl-optimization/67103 + * ifcvt.c (noce_try_store_flag_constants): Move + x = (-(test != 0) & (b - a)) + a transformation to... + (noce_try_cmove): ... Here. Try it if normal conditional + move fails. + 2015-08-13 Robert Suchanek <robert.suchanek@imgtec.com> * config/mips/mips.c (mips_rtx_cost_data): Remove costs for W32 and W64 diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c index 1f29646..9b6f682 100644 --- a/gcc/ifcvt.c +++ b/gcc/ifcvt.c @@ -1239,9 +1239,6 @@ noce_try_store_flag_constants (struct noce_if_info *if_info) normalize = -1; reversep = true; } - else if ((if_info->branch_cost >= 2 && STORE_FLAG_VALUE == -1) - || if_info->branch_cost >= 3) - normalize = -1; else return FALSE; @@ -1287,18 +1284,10 @@ noce_try_store_flag_constants (struct noce_if_info *if_info) target, gen_int_mode (ifalse, mode), if_info->x, 0, OPTAB_WIDEN); } - - /* if (test) x = a; else x = b; - => x = (-(test != 0) & (b - a)) + a; */ else { - target = expand_simple_binop (mode, AND, - target, gen_int_mode (diff, mode), - if_info->x, 0, OPTAB_WIDEN); - if (target) - target = expand_simple_binop (mode, PLUS, - target, gen_int_mode (ifalse, mode), - if_info->x, 0, OPTAB_WIDEN); + end_sequence (); + return FALSE; } if (! target) @@ -1615,11 +1604,67 @@ noce_try_cmove (struct noce_if_info *if_info) INSN_LOCATION (if_info->insn_a)); return TRUE; } - else + /* If both a and b are constants try a last-ditch transformation: + if (test) x = a; else x = b; + => x = (-(test != 0) & (b - a)) + a; + Try this only if the target-specific expansion above has failed. + The target-specific expander may want to generate sequences that + we don't know about, so give them a chance before trying this + approach. */ + else if (!targetm.have_conditional_execution () + && CONST_INT_P (if_info->a) && CONST_INT_P (if_info->b) + && ((if_info->branch_cost >= 2 && STORE_FLAG_VALUE == -1) + || if_info->branch_cost >= 3)) { - end_sequence (); - return FALSE; + machine_mode mode = GET_MODE (if_info->x); + HOST_WIDE_INT ifalse = INTVAL (if_info->a); + HOST_WIDE_INT itrue = INTVAL (if_info->b); + rtx target = noce_emit_store_flag (if_info, if_info->x, false, -1); + if (!target) + { + end_sequence (); + return FALSE; + } + + HOST_WIDE_INT diff = (unsigned HOST_WIDE_INT) itrue - ifalse; + /* Make sure we can represent the difference + between the two values. */ + if ((diff > 0) + != ((ifalse < 0) != (itrue < 0) ? ifalse < 0 : ifalse < itrue)) + { + end_sequence (); + return FALSE; + } + + diff = trunc_int_for_mode (diff, mode); + target = expand_simple_binop (mode, AND, + target, gen_int_mode (diff, mode), + if_info->x, 0, OPTAB_WIDEN); + if (target) + target = expand_simple_binop (mode, PLUS, + target, gen_int_mode (ifalse, mode), + if_info->x, 0, OPTAB_WIDEN); + if (target) + { + if (target != if_info->x) + noce_emit_move_insn (if_info->x, target); + + seq = end_ifcvt_sequence (if_info); + if (!seq) + return FALSE; + + emit_insn_before_setloc (seq, if_info->jump, + INSN_LOCATION (if_info->insn_a)); + return TRUE; + } + else + { + end_sequence (); + return FALSE; + } } + else + end_sequence (); } return FALSE; |