For divisions by a compile-time-constant divisor, expand_divmod calls
choose_multiplier with the dividend's full type precision (size or
size - 1).  When the dividend's value range is known to be narrower
than the type, choose_multiplier could pick a smaller multiplier and
post-shift, but expand_divmod has no path to receive that hint.

This patch threads the VRP-derived value range from the GIMPLE side
into expand_divmod and forwards it to choose_multiplier:

  * expand_expr_divmod (gcc/expr.cc) computes a precision hint from
    treeop0's range via a new helper determine_value_range, which
    queries the active range_query during pass_expand.

  * For unsigned (or non-negative-known signed) operands the hint is
    wi::min_precision(max_val, UNSIGNED).  For signed operands with
    possibly negative values it is wi::min_precision of the larger
    of -min - 1 and max under unsigned interpretation -- the bound
    choose_multiplier itself relies on.

  * expand_divmod gets a new dividend_prec parameter (default -1
    meaning "no hint") and an inline helper adjusted_dividend_prec
    that hands the hint to choose_multiplier raised to LGUP, so the
    lgup <= precision precondition is preserved.  The helper is
    invoked at three call sites: unsigned TRUNC, signed TRUNC, and
    signed FLOOR.

For the example in PR target/91883,

  unsigned g (unsigned a) {
    if (a > 1000000) __builtin_unreachable ();
    return a / 10;
  }

baseline -O2 emits

  movl    %edi, %eax
  movl    $3435973837, %edx
  imulq   %rdx, %rax
  shrq    $35, %rax

with this patch:

  movl    %edi, %eax
  imulq   $429497139, %rax, %rax
  shrq    $32, %rax

The smaller multiplier fits imulq's 32-bit signed immediate, saving
the separate movl, and the post-shift drops from 35 to 32.  Similar
effects for /3, /7, /100.  For signed /7, codegen also shifts from
the long path (addl-fixup) to the short path, reducing seven
instructions to five.

The new parameter defaults to -1 and produces baseline codegen for
that case; functions without VRP range info are unaffected.

gcc.target/i386/pr115910.c is updated.  The test has two functions
both doing x / 3U: foo with __builtin_unreachable when x < 0, and
bar with no hint.  Previously both produced identical codegen; the
test asserted 2 imulq + 2 shrq $33.  With this patch foo's
__builtin_unreachable narrows x to [0, INT_MAX] giving VRP-derived
precision 31, so choose_multiplier picks a smaller M (1431655766,
fits imulq's 32-bit immediate) and post-shift 32 instead of 33.
bar is unchanged.  The dg-final assertions are split: still 2 imulq,
plus 1 shrq $32 (foo) and 1 shrq $33 (bar).

One drawback of this patch is some code bloat: the same
divisor at two call sites with different ranges produces different
assembly instructions.  Unmodified GCC produces the same assembly
instructions regardless of range, allowing the linker's identical-
code-folding (ICF) pass to merge the two function bodies into a
single copy in the final binary.  With this patch the bodies differ,
so ICF cannot fold them.  Clang has the same drawback: it also
produces different assembly instructions for the same divisor at
different ranges, which ICF cannot fold.

For example, consider /3 at two different ranges:

  unsigned int f3 (unsigned int a) {
    if (a > 65535) __builtin_unreachable ();
    return a / 3;
  }
  unsigned int f (unsigned int a) {
    if (a > 655356) __builtin_unreachable ();
    return a / 3;
  }

Unmodified GCC produces byte-identical assembly instructions for
both functions, which ICF folds into a single copy:
  f3:
        mov     eax, edi
        mov     edx, 2863311531
        imul    rax, rdx
        shr     rax, 33
        ret
  f:
        mov     eax, edi
        mov     edx, 2863311531
        imul    rax, rdx
        shr     rax, 33
        ret

Clang produces different assembly instructions; ICF cannot fold them:
  f3:
        imul    eax, edi, 43691
        shr     eax, 17
        ret
  f:
        mov     ecx, edi
        mov     eax, 2863311531
        imul    rax, rcx
        shr     rax, 33
        ret

Patched GCC produces different assembly instructions; ICF cannot
fold them:
  f3:
        mov     eax, edi
        imul    rax, rax, 1431677610
        shr     rax, 32
        ret
  f:
        mov     eax, edi
        imul    rax, rax, 1431657130
        shr     rax, 32
        ret

A live demonstration: https://godbolt.org/z/75r6axnvG, compiled with

  -O2 -ffunction-sections -fuse-ld=gold -Wl,--icf=all

The flags:
  -ffunction-sections   put each function into its own section, so
                        the linker can compare and fold them
                        individually
  -fuse-ld=gold         use the gold linker (the default linker
                        does not support ICF)
  -Wl,--icf=all         enable ICF in the linker

Under unmodified GCC, f3 and f end up at the same address.  Under
clang and patched GCC, they end up at different addresses.

Under default compiler/linker flags this patch likely has no meaningful
downside: ICF is not enabled by default, so unmodified and patched
both keep two copies of the body in .text.  We consider this an
acceptable tradeoff: each individual division is at least as small
as before, and clang accepts the same one.

Bootstrapped on x86_64-pc-linux-gnu with the default language set
(c, c++, fortran, objc, obj-c++, lto): "make bootstrap" followed by
"make -k check" from the top of the build tree.  Stage-2 vs. stage-3
binary comparison successful (the two compilers GCC produces of itself
are byte-identical).  No new regressions in the testsuite, and all 30
dg-final assertions across the seven new gcc.target/i386/divmod-range-*.c
tests pass.

gcc/ChangeLog:

        PR target/91883
        * expmed.cc (choose_multiplier): Prepend comment stating the
        multiply-shift formula it computes.
        (adjusted_dividend_prec): New helper.
        (expand_divmod): Add dividend_prec parameter.  Forward to
        adjusted_dividend_prec at the unsigned TRUNC, signed TRUNC,
        and signed FLOOR XOR-sign-flip call sites.
        * expmed.h (expand_divmod): Add dividend_prec default arg.
        * expr.cc (determine_value_range): New helper, queries
        range_query during pass_expand.
        (expand_expr_divmod): Compute dividend_prec from treeop0's
        range and forward to expand_divmod.

gcc/testsuite/ChangeLog:

        PR target/91883
        * gcc.target/i386/pr115910.c: Adjust shrq assertions for
        VRP-narrowed multiplier on foo.
        * gcc.target/i386/divmod-range-1.c: New test: VRP-narrowed
        multiplier for unsigned /10.
        * gcc.target/i386/divmod-range-2.c: New test: VRP-narrowed
        multiplier for unsigned %10.
        * gcc.target/i386/divmod-range-3.c: New test: VRP-narrowed
        multiplier for signed /10.
        * gcc.target/i386/divmod-range-4.c: New test: VRP shifts
        signed /7 from the long (addl-fixup) path to the short path.
        * gcc.target/i386/divmod-range-5.c: New test: regression
        guard -- no-hint unsigned divmod preserves baseline codegen.
        * gcc.target/i386/divmod-range-6.c: New test: regression
        guard -- no-hint signed /7 preserves long-path codegen.
        * gcc.target/i386/divmod-range-7.c: New test: VRP-narrowed
        multiplier for signed FLOOR_DIV (uses GIMPLE Front End since
        FLOOR_DIV_EXPR cannot be produced from C source).
---
 gcc/expmed.cc                                 | 47 +++++++++++--
 gcc/expmed.h                                  |  3 +-
 gcc/expr.cc                                   | 69 ++++++++++++++++++-
 .../gcc.target/i386/divmod-range-1.c          | 15 ++++
 .../gcc.target/i386/divmod-range-2.c          | 14 ++++
 .../gcc.target/i386/divmod-range-3.c          | 14 ++++
 .../gcc.target/i386/divmod-range-4.c          | 14 ++++
 .../gcc.target/i386/divmod-range-5.c          | 12 ++++
 .../gcc.target/i386/divmod-range-6.c          | 12 ++++
 .../gcc.target/i386/divmod-range-7.c          | 34 +++++++++
 gcc/testsuite/gcc.target/i386/pr115910.c      |  3 +-
 11 files changed, 228 insertions(+), 9 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/i386/divmod-range-1.c
 create mode 100644 gcc/testsuite/gcc.target/i386/divmod-range-2.c
 create mode 100644 gcc/testsuite/gcc.target/i386/divmod-range-3.c
 create mode 100644 gcc/testsuite/gcc.target/i386/divmod-range-4.c
 create mode 100644 gcc/testsuite/gcc.target/i386/divmod-range-5.c
 create mode 100644 gcc/testsuite/gcc.target/i386/divmod-range-6.c
 create mode 100644 gcc/testsuite/gcc.target/i386/divmod-range-7.c

diff --git a/gcc/expmed.cc b/gcc/expmed.cc
index fe39506b6bd..52282668a7e 100644
--- a/gcc/expmed.cc
+++ b/gcc/expmed.cc
@@ -3733,6 +3733,15 @@ expand_widening_mult (machine_mode mode, rtx op0, rtx 
op1, rtx target,
                       unsignedp, OPTAB_LIB_WIDEN);
 }
 
+/* For any x satisfying 0 <= x < 2^PRECISION, this function picks
+   integers M and K satisfying
+
+   floor (x / D)  =  floor ((x * M) / 2^K)
+
+   so an unsigned divide by the constant D can be replaced by one
+   multiply and one right shift.  K is internal, recovered from the outputs as
+   K = N + (*POST_SHIFT_PTR).  */
+
 /* Choose a minimal N + 1 bit approximation to 2**K / D that can be used to
    replace division by D, put the least significant N bits of the result in
    *MULTIPLIER_PTR, the value K - N in *POST_SHIFT_PTR, and return the most
@@ -4243,6 +4252,21 @@ expand_sdiv_pow2 (scalar_int_mode mode, rtx op0, 
HOST_WIDE_INT d)
   emit_label (label);
   return expand_shift (RSHIFT_EXPR, mode, temp, logd, NULL_RTX, 0);
 }
+
+/* Return the precision to pass to choose_multiplier.  When DIVIDEND_PREC
+   is non-negative, use it as the value-range-derived hint, raised to
+   at least LGUP since choose_multiplier asserts lgup <= precision.
+   When -1, no hint is available; return DEFAULT_PREC.  By construction
+   in the caller, DIVIDEND_PREC never exceeds DEFAULT_PREC.  */
+
+static inline int
+adjusted_dividend_prec (int dividend_prec, int default_prec, int lgup)
+{
+  if (dividend_prec >= 0)
+    return dividend_prec < lgup ? lgup : dividend_prec;
+  return default_prec;
+}
+
 
 /* Emit the code to divide OP0 by OP1, putting the result in TARGET
    if that is convenient, and returning where the result is.
@@ -4285,7 +4309,7 @@ expand_sdiv_pow2 (scalar_int_mode mode, rtx op0, 
HOST_WIDE_INT d)
 rtx
 expand_divmod (int rem_flag, enum tree_code code, machine_mode mode,
               rtx op0, rtx op1, rtx target, int unsignedp,
-              enum optab_methods methods)
+              enum optab_methods methods, int dividend_prec)
 {
   machine_mode compute_mode;
   rtx tquotient;
@@ -4528,7 +4552,12 @@ expand_divmod (int rem_flag, enum tree_code code, 
machine_mode mode,
                      {
                        /* Find a suitable multiplier and right shift count
                           instead of directly dividing by D.  */
-                       mh = choose_multiplier (d, size, size,
+
+                       /* Use reduced precision if range info available.  */
+                       int prec = adjusted_dividend_prec (dividend_prec, size,
+                                                          ceil_log2 (d));
+
+                       mh = choose_multiplier (d, size, prec,
                                                &ml, &post_shift);
 
                        /* If the suggested multiplier is more than SIZE bits,
@@ -4537,6 +4566,9 @@ expand_divmod (int rem_flag, enum tree_code code, 
machine_mode mode,
                        if (mh != 0 && (d & 1) == 0)
                          {
                            pre_shift = ctz_or_zero (d);
+
+                           /* Only reached when the prior call used full SIZE,
+                              so any hint here is saturated.  */
                            mh = choose_multiplier (d >> pre_shift, size,
                                                    size - pre_shift,
                                                    &ml, &post_shift);
@@ -4706,8 +4738,12 @@ expand_divmod (int rem_flag, enum tree_code code, 
machine_mode mode,
                  }
                else if (size <= HOST_BITS_PER_WIDE_INT)
                  {
-                   choose_multiplier (abs_d, size, size - 1,
+                   int prec = adjusted_dividend_prec (dividend_prec, size - 1,
+                                                      ceil_log2 (abs_d));
+
+                   choose_multiplier (abs_d, size, prec,
                                       &ml, &post_shift);
+
                    if (ml < HOST_WIDE_INT_1U << (size - 1))
                      {
                        rtx t1, t2, t3;
@@ -4827,7 +4863,10 @@ expand_divmod (int rem_flag, enum tree_code code, 
machine_mode mode,
                  {
                    rtx t1, t2, t3, t4;
 
-                   mh = choose_multiplier (d, size, size - 1,
+                   int prec = adjusted_dividend_prec (dividend_prec, size - 1,
+                                                      ceil_log2 (d));
+
+                   mh = choose_multiplier (d, size, prec,
                                            &ml, &post_shift);
                    gcc_assert (!mh);
 
diff --git a/gcc/expmed.h b/gcc/expmed.h
index 557b58392ba..cd0fe4e97da 100644
--- a/gcc/expmed.h
+++ b/gcc/expmed.h
@@ -711,7 +711,8 @@ extern rtx maybe_expand_shift (enum tree_code, 
machine_mode, rtx, int, rtx,
                               int);
 #ifdef GCC_OPTABS_H
 extern rtx expand_divmod (int, enum tree_code, machine_mode, rtx, rtx,
-                         rtx, int, enum optab_methods = OPTAB_LIB_WIDEN);
+                         rtx, int, enum optab_methods = OPTAB_LIB_WIDEN,
+                         int = -1);
 #endif
 #endif
 
diff --git a/gcc/expr.cc b/gcc/expr.cc
index 7ca5dd84ce9..e8947574eff 100644
--- a/gcc/expr.cc
+++ b/gcc/expr.cc
@@ -66,6 +66,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-pretty-print.h"
 #include "flags.h"
 #include "internal-fn.h"
+#include "value-query.h"
+#include "value-range.h"
 
 
 /* If this is nonzero, we do not bother generating VOLATILE
@@ -9765,6 +9767,35 @@ expand_misaligned_mem_ref (rtx temp, machine_mode mode, 
int unsignedp,
   return temp;
 }
 
+/* Determine the value range of OP at the current statement.
+   Returns true if range is known, stores bounds in MIN_VAL and MAX_VAL.  */
+
+static bool
+determine_value_range (tree op, wide_int *min_val, wide_int *max_val)
+{
+  if (!currently_expanding_gimple_stmt)
+    return false;
+
+  if (TREE_CODE (op) != SSA_NAME)
+    return false;
+
+  tree type = TREE_TYPE (op);
+  if (!INTEGRAL_TYPE_P (type))
+    return false;
+
+  int_range_max r;
+  if (!get_range_query (cfun)->range_of_expr (r, op,
+                                             currently_expanding_gimple_stmt))
+    return false;
+
+  if (r.undefined_p () || r.varying_p ())
+    return false;
+
+  *min_val = r.lower_bound ();
+  *max_val = r.upper_bound ();
+  return true;
+}
+
 /* Helper function of expand_expr_2, expand a division or modulo.
    op0 and op1 should be already expanded treeop0 and treeop1, using
    expand_operands.  */
@@ -9775,6 +9806,35 @@ expand_expr_divmod (tree_code code, machine_mode mode, 
tree treeop0,
 {
   bool mod_p = (code == TRUNC_MOD_EXPR || code == FLOOR_MOD_EXPR
                || code == CEIL_MOD_EXPR || code == ROUND_MOD_EXPR);
+
+  /* Calculate precision hint from value range if available.  */
+  int dividend_prec = -1;
+
+  if (SCALAR_INT_MODE_P (mode)
+      && optimize >= 2
+      && TREE_CODE (treeop1) == INTEGER_CST)
+    {
+      wide_int min_val, max_val;
+      if (determine_value_range (treeop0, &min_val, &max_val))
+       {
+         if (unsignedp || wi::ges_p (min_val, 0))
+           {
+             /* Unsigned or known non-negative: precision from upper bound.  */
+             dividend_prec = wi::min_precision (max_val, UNSIGNED);
+           }
+         else
+           {
+             /* Signed with possible negative values.  Take the unsigned
+                precision of the larger of -min - 1 and max (or just
+                -min - 1 when max < 0, since -min - 1 dominates then).  */
+             wide_int neg_side = -min_val - 1;
+             wide_int pos_side = wi::ges_p (max_val, 0) ? max_val : neg_side;
+             wide_int worst = wi::umax (neg_side, pos_side);
+             dividend_prec = wi::min_precision (worst, UNSIGNED);
+           }
+       }
+    }
+
   if (SCALAR_INT_MODE_P (mode)
       && optimize >= 2
       && get_range_pos_neg (treeop0, currently_expanding_gimple_stmt) == 1
@@ -9786,10 +9846,12 @@ expand_expr_divmod (tree_code code, machine_mode mode, 
tree treeop0,
       bool speed_p = optimize_insn_for_speed_p ();
       do_pending_stack_adjust ();
       start_sequence ();
-      rtx uns_ret = expand_divmod (mod_p, code, mode, op0, op1, target, 1);
+      rtx uns_ret = expand_divmod (mod_p, code, mode, op0, op1, target, 1,
+                                  OPTAB_LIB_WIDEN, dividend_prec);
       rtx_insn *uns_insns = end_sequence ();
       start_sequence ();
-      rtx sgn_ret = expand_divmod (mod_p, code, mode, op0, op1, target, 0);
+      rtx sgn_ret = expand_divmod (mod_p, code, mode, op0, op1, target, 0,
+                                  OPTAB_LIB_WIDEN, dividend_prec);
       rtx_insn *sgn_insns = end_sequence ();
       unsigned uns_cost = seq_cost (uns_insns, speed_p);
       unsigned sgn_cost = seq_cost (sgn_insns, speed_p);
@@ -9817,7 +9879,8 @@ expand_expr_divmod (tree_code code, machine_mode mode, 
tree treeop0,
       emit_insn (sgn_insns);
       return sgn_ret;
     }
-  return expand_divmod (mod_p, code, mode, op0, op1, target, unsignedp);
+  return expand_divmod (mod_p, code, mode, op0, op1, target, unsignedp,
+                       OPTAB_LIB_WIDEN, dividend_prec);
 }
 
 /* Return true if EXP has a range of values [0..1], false
diff --git a/gcc/testsuite/gcc.target/i386/divmod-range-1.c 
b/gcc/testsuite/gcc.target/i386/divmod-range-1.c
new file mode 100644
index 00000000000..57ab5149374
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/divmod-range-1.c
@@ -0,0 +1,15 @@
+/* Verify that VRP-derived range info reduces the unsigned divmod multiplier.  
*/
+/* { dg-do compile { target { ! ia32 } } } */
+/* { dg-options "-O2 -march=x86-64 -mtune=generic -masm=att" } */
+
+unsigned int
+foo (unsigned int a)
+{
+  if (a > 1000000) __builtin_unreachable ();
+  return a / 10;
+}
+
+/* { dg-final { scan-assembler {\timulq\t\$429497139,} } } */
+/* { dg-final { scan-assembler {\tshrq\t\$32,} } } */
+/* { dg-final { scan-assembler-not {\$3435973837} } } */
+/* { dg-final { scan-assembler-not {\tshrq\t\$35,} } } */
diff --git a/gcc/testsuite/gcc.target/i386/divmod-range-2.c 
b/gcc/testsuite/gcc.target/i386/divmod-range-2.c
new file mode 100644
index 00000000000..ac5e9edc7aa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/divmod-range-2.c
@@ -0,0 +1,14 @@
+/* Verify that VRP-derived range info reduces the unsigned modulo multiplier.  
*/
+/* { dg-do compile { target { ! ia32 } } } */
+/* { dg-options "-O2 -march=x86-64 -mtune=generic -masm=att" } */
+
+unsigned int
+foo (unsigned int a)
+{
+  if (a > 1000000) __builtin_unreachable ();
+  return a % 10;
+}
+
+/* { dg-final { scan-assembler {\timulq\t\$429497139,} } } */
+/* { dg-final { scan-assembler {\tshrq\t\$32,} } } */
+/* { dg-final { scan-assembler-not {\$3435973837} } } */
diff --git a/gcc/testsuite/gcc.target/i386/divmod-range-3.c 
b/gcc/testsuite/gcc.target/i386/divmod-range-3.c
new file mode 100644
index 00000000000..bbca89b42c0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/divmod-range-3.c
@@ -0,0 +1,14 @@
+/* Verify that VRP-derived range info reduces the signed-divide-by-10 
multiplier.  */
+/* { dg-do compile { target { ! ia32 } } } */
+/* { dg-options "-O2 -march=x86-64 -mtune=generic -masm=att" } */
+
+int
+foo (int a)
+{
+  if (a > 1000000 || a < -1000000) __builtin_unreachable ();
+  return a / 10;
+}
+
+/* { dg-final { scan-assembler {\timulq\t\$429497139,} } } */
+/* { dg-final { scan-assembler-not {\$1717986919} } } */
+/* { dg-final { scan-assembler-not {\tsarq\t\$34,} } } */
diff --git a/gcc/testsuite/gcc.target/i386/divmod-range-4.c 
b/gcc/testsuite/gcc.target/i386/divmod-range-4.c
new file mode 100644
index 00000000000..ea9b7926862
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/divmod-range-4.c
@@ -0,0 +1,14 @@
+/* Verify that VRP-derived range info shifts signed /7 from LONG to SHORT 
codegen.  */
+/* { dg-do compile { target { ! ia32 } } } */
+/* { dg-options "-O2 -march=x86-64 -mtune=generic -masm=att" } */
+
+int
+foo (int a)
+{
+  if (a > 1000000 || a < -1000000) __builtin_unreachable ();
+  return a / 7;
+}
+
+/* { dg-final { scan-assembler {\timulq\t\$613567341,} } } */
+/* { dg-final { scan-assembler-not {\$-1840700269} } } */
+/* { dg-final { scan-assembler-not {\taddl\t%edi, %eax} } } */
diff --git a/gcc/testsuite/gcc.target/i386/divmod-range-5.c 
b/gcc/testsuite/gcc.target/i386/divmod-range-5.c
new file mode 100644
index 00000000000..cf39c39628d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/divmod-range-5.c
@@ -0,0 +1,12 @@
+/* Regression test: no-hint unsigned divmod must preserve baseline codegen.  */
+/* { dg-do compile { target { ! ia32 } } } */
+/* { dg-options "-O2 -march=x86-64 -mtune=generic -masm=att" } */
+
+unsigned int
+foo (unsigned int a)
+{
+  return a / 10;
+}
+
+/* { dg-final { scan-assembler {\$3435973837} } } */
+/* { dg-final { scan-assembler {\tshrq\t\$35,} } } */
diff --git a/gcc/testsuite/gcc.target/i386/divmod-range-6.c 
b/gcc/testsuite/gcc.target/i386/divmod-range-6.c
new file mode 100644
index 00000000000..0699d0925ee
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/divmod-range-6.c
@@ -0,0 +1,12 @@
+/* Regression test: no-hint signed-/7 must preserve LONG-path codegen.  */
+/* { dg-do compile { target { ! ia32 } } } */
+/* { dg-options "-O2 -march=x86-64 -mtune=generic -masm=att" } */
+
+int
+foo (int a)
+{
+  return a / 7;
+}
+
+/* { dg-final { scan-assembler {\$-1840700269} } } */
+/* { dg-final { scan-assembler {\taddl\t%edi, %eax} } } */
diff --git a/gcc/testsuite/gcc.target/i386/divmod-range-7.c 
b/gcc/testsuite/gcc.target/i386/divmod-range-7.c
new file mode 100644
index 00000000000..524b14b824c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/divmod-range-7.c
@@ -0,0 +1,34 @@
+/* Verify that VRP-derived range info reduces the signed FLOOR_DIV multiplier.
+   Uses __GIMPLE FE because FLOOR_DIV_EXPR cannot be produced from C source.  
*/
+/* { dg-do compile { target { ! ia32 } } } */
+/* { dg-options "-O2 -fgimple -march=x86-64 -mtune=generic -masm=att" } */
+
+int __GIMPLE (ssa)
+foo (int a)
+{
+  int t_2;
+  unsigned int au_4;
+  unsigned int range_5;
+
+__BB(2):
+  au_4 = (unsigned int) a_3(D);
+  range_5 = au_4 + 1000000u;
+  if (range_5 > 2000000u)
+    goto __BB3;
+  else
+    goto __BB4;
+
+__BB(3):
+  __builtin_unreachable ();
+
+__BB(4):
+  t_2 = a_3(D) __FLOOR_DIV 7;
+  return t_2;
+}
+
+/* { dg-final { scan-assembler {\timulq\t\$613567341,} } } */
+/* { dg-final { scan-assembler {\tshrq\t\$32,} } } */
+/* { dg-final { scan-assembler {\tsarl\t\$31,} } } */
+/* { dg-final { scan-assembler-times {\txorl\t} 2 } } */
+/* { dg-final { scan-assembler-not {\$2454267027} } } */
+/* { dg-final { scan-assembler-not {\tshrq\t\$34,} } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr115910.c 
b/gcc/testsuite/gcc.target/i386/pr115910.c
index 5f1cd9aa010..41e94142392 100644
--- a/gcc/testsuite/gcc.target/i386/pr115910.c
+++ b/gcc/testsuite/gcc.target/i386/pr115910.c
@@ -2,7 +2,8 @@
 /* { dg-do compile { target { ! ia32 } } } */
 /* { dg-options "-O2 -march=x86-64 -mtune=generic -masm=att" } */
 /* { dg-final { scan-assembler-times {\timulq\t} 2 } } */
-/* { dg-final { scan-assembler-times {\tshrq\t\$33,} 2 } } */
+/* { dg-final { scan-assembler-times {\tshrq\t\$32,} 1 } } */
+/* { dg-final { scan-assembler-times {\tshrq\t\$33,} 1 } } */
 /* { dg-final { scan-assembler-not {\tsarl\t} } } */
 
 int
-- 
2.43.0

Reply via email to