diff options
author | Jakub Jelinek <jakub@gcc.gnu.org> | 2017-02-23 08:49:06 +0100 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2017-02-23 08:49:06 +0100 |
commit | b607e75e25261ac2c81d71fe1a4dcf5fcd166603 (patch) | |
tree | c83ce2682d44020d9ccc173ce01b86a17929c8a2 /gcc/expr.c | |
parent | 18eb304e5f35d745dcb1a9bb41a2879a364f59fe (diff) | |
download | gcc-b607e75e25261ac2c81d71fe1a4dcf5fcd166603.zip gcc-b607e75e25261ac2c81d71fe1a4dcf5fcd166603.tar.gz gcc-b607e75e25261ac2c81d71fe1a4dcf5fcd166603.tar.bz2 |
re PR middle-end/79665 (gcc's signed (x*x)/200 is slower than clang's)
PR middle-end/79665
* internal-fn.c (get_range_pos_neg): Moved to ...
* tree.c (get_range_pos_neg): ... here. No longer static.
* tree.h (get_range_pos_neg): New prototype.
* expr.c (expand_expr_real_2) <case TRUNC_DIV_EXPR>: If both arguments
are known to be in between 0 and signed maximum inclusive, try to
expand both unsigned and signed divmod and use the cheaper one from
those.
From-SVN: r245676
Diffstat (limited to 'gcc/expr.c')
-rw-r--r-- | gcc/expr.c | 28 |
1 files changed, 28 insertions, 0 deletions
@@ -8809,6 +8809,34 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode, where some terms of the dividend have coeffs divisible by it. */ expand_operands (treeop0, treeop1, subtarget, &op0, &op1, EXPAND_NORMAL); + if (SCALAR_INT_MODE_P (mode) + && optimize >= 2 + && get_range_pos_neg (treeop0) == 1 + && get_range_pos_neg (treeop1) == 1) + { + /* If both arguments are known to be positive when interpreted + as signed, we can expand it as both signed and unsigned + division or modulo. Choose the cheaper sequence in that case. */ + bool speed_p = optimize_insn_for_speed_p (); + do_pending_stack_adjust (); + start_sequence (); + rtx uns_ret = expand_divmod (0, code, mode, op0, op1, target, 1); + rtx_insn *uns_insns = get_insns (); + end_sequence (); + start_sequence (); + rtx sgn_ret = expand_divmod (0, code, mode, op0, op1, target, 0); + rtx_insn *sgn_insns = get_insns (); + end_sequence (); + unsigned uns_cost = seq_cost (uns_insns, speed_p); + unsigned sgn_cost = seq_cost (sgn_insns, speed_p); + if (uns_cost < sgn_cost || (uns_cost == sgn_cost && unsignedp)) + { + emit_insn (uns_insns); + return uns_ret; + } + emit_insn (sgn_insns); + return sgn_ret; + } return expand_divmod (0, code, mode, op0, op1, target, unsignedp); case RDIV_EXPR: |