re PR target/82981 (unnecessary __multi3 call for mips64r6 linux kernel)
authorJakub Jelinek <jakub@redhat.com>
Wed, 15 Nov 2017 09:01:42 +0000 (10:01 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Wed, 15 Nov 2017 09:01:42 +0000 (10:01 +0100)
PR target/82981
* internal-fn.c: Include gimple-ssa.h, tree-phinodes.h and
ssa-iterators.h.
(can_widen_mult_without_libcall): New function.
(expand_mul_overflow): If only checking unsigned mul overflow,
not result, and can do efficiently MULT_HIGHPART_EXPR, emit that.
Don't use WIDEN_MULT_EXPR if it would involve a libcall, unless
no other way works.  Add MULT_HIGHPART_EXPR + MULT_EXPR support.
(expand_DIVMOD): Formatting fix.
* expmed.h (expand_mult): Add NO_LIBCALL argument.
* expmed.c (expand_mult): Likewise.  Use OPTAB_WIDEN rather
than OPTAB_LIB_WIDEN if NO_LIBCALL is true, and allow it to fail.

* gcc.target/mips/pr82981.c: New test.

From-SVN: r254758

gcc/ChangeLog
gcc/expmed.c
gcc/expmed.h
gcc/internal-fn.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/mips/pr82981.c [new file with mode: 0644]

index fd72410e1867daf298de36deeeedb65913c0289d..277c5578707dba6b745a223f54ec53545d841a10 100644 (file)
@@ -1,5 +1,18 @@
 2017-11-15  Jakub Jelinek  <jakub@redhat.com>
 
+       PR target/82981
+       * internal-fn.c: Include gimple-ssa.h, tree-phinodes.h and
+       ssa-iterators.h.
+       (can_widen_mult_without_libcall): New function.
+       (expand_mul_overflow): If only checking unsigned mul overflow,
+       not result, and can do efficiently MULT_HIGHPART_EXPR, emit that.
+       Don't use WIDEN_MULT_EXPR if it would involve a libcall, unless
+       no other way works.  Add MULT_HIGHPART_EXPR + MULT_EXPR support.
+       (expand_DIVMOD): Formatting fix.
+       * expmed.h (expand_mult): Add NO_LIBCALL argument.
+       * expmed.c (expand_mult): Likewise.  Use OPTAB_WIDEN rather
+       than OPTAB_LIB_WIDEN if NO_LIBCALL is true, and allow it to fail.
+
        PR tree-optimization/82977
        * tree-ssa-strlen.c (strlen_optimize_stmt): Pass a reference to a copy
        constructed temporary to strlen_to_stridx.put.
index 8e9f15d6a65fb06acd317da5b9ad9e3e42e9aeaa..dacb2b9771ae45d0a17162777138b404f48be8ca 100644 (file)
@@ -3284,7 +3284,7 @@ expand_mult_const (machine_mode mode, rtx op0, HOST_WIDE_INT val,
 
 rtx
 expand_mult (machine_mode mode, rtx op0, rtx op1, rtx target,
-            int unsignedp)
+            int unsignedp, bool no_libcall)
 {
   enum mult_variant variant;
   struct algorithm algorithm;
@@ -3420,14 +3420,16 @@ expand_mult (machine_mode mode, rtx op0, rtx op1, rtx target,
     {
       op0 = force_reg (GET_MODE (op0), op0);
       return expand_binop (mode, add_optab, op0, op0,
-                          target, unsignedp, OPTAB_LIB_WIDEN);
+                          target, unsignedp,
+                          no_libcall ? OPTAB_WIDEN : OPTAB_LIB_WIDEN);
     }
 
   /* This used to use umul_optab if unsigned, but for non-widening multiply
      there is no difference between signed and unsigned.  */
   op0 = expand_binop (mode, do_trapv ? smulv_optab : smul_optab,
-                     op0, op1, target, unsignedp, OPTAB_LIB_WIDEN);
-  gcc_assert (op0);
+                     op0, op1, target, unsignedp,
+                     no_libcall ? OPTAB_WIDEN : OPTAB_LIB_WIDEN);
+  gcc_assert (op0 || no_libcall);
   return op0;
 }
 
index 712c7715ec812a1181660f76e64e07866c20afe2..6b57ec634d56fb54c5445a1c1e050020dec7bc2f 100644 (file)
@@ -727,7 +727,7 @@ extern rtx extract_bit_field (rtx, unsigned HOST_WIDE_INT,
                              unsigned HOST_WIDE_INT, int, rtx,
                              machine_mode, machine_mode, bool, rtx *);
 extern rtx extract_low_bits (machine_mode, machine_mode, rtx);
-extern rtx expand_mult (machine_mode, rtx, rtx, rtx, int);
+extern rtx expand_mult (machine_mode, rtx, rtx, rtx, int, bool = false);
 extern rtx expand_mult_highpart_adjust (scalar_int_mode, rtx, rtx, rtx,
                                        rtx, int);
 
index 94873c2948ad01c8ffaeb2a3473409b74b9ed6f5..1c00792fec79323ddc456bd7d9e75efd0aa2dfe4 100644 (file)
@@ -46,6 +46,9 @@ along with GCC; see the file COPYING3.  If not see
 #include "recog.h"
 #include "builtins.h"
 #include "optabs-tree.h"
+#include "gimple-ssa.h"
+#include "tree-phinodes.h"
+#include "ssa-iterators.h"
 
 /* The names of each internal function, indexed by function number.  */
 const char *const internal_fn_name_array[] = {
@@ -1172,6 +1175,35 @@ expand_neg_overflow (location_t loc, tree lhs, tree arg1, bool is_ubsan,
     }
 }
 
+/* Return true if UNS WIDEN_MULT_EXPR with result mode WMODE and operand
+   mode MODE can be expanded without using a libcall.  */
+
+static bool
+can_widen_mult_without_libcall (scalar_int_mode wmode, scalar_int_mode mode,
+                               rtx op0, rtx op1, bool uns)
+{
+  if (find_widening_optab_handler (umul_widen_optab, wmode, mode)
+      != CODE_FOR_nothing)
+    return true;
+    
+  if (find_widening_optab_handler (smul_widen_optab, wmode, mode)
+      != CODE_FOR_nothing)
+    return true;
+
+  rtx_insn *last = get_last_insn ();
+  if (CONSTANT_P (op0))
+    op0 = convert_modes (wmode, mode, op0, uns);
+  else
+    op0 = gen_raw_REG (wmode, LAST_VIRTUAL_REGISTER + 1);
+  if (CONSTANT_P (op1))
+    op1 = convert_modes (wmode, mode, op1, uns);
+  else
+    op1 = gen_raw_REG (wmode, LAST_VIRTUAL_REGISTER + 2);
+  rtx ret = expand_mult (wmode, op0, op1, NULL_RTX, uns, true);
+  delete_insns_since (last);
+  return ret != NULL_RTX;
+} 
+
 /* Add mul overflow checking to the statement STMT.  */
 
 static void
@@ -1465,9 +1497,29 @@ expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1,
       ops.op1 = make_tree (type, op1);
       ops.op2 = NULL_TREE;
       ops.location = loc;
+
+      /* Optimize unsigned overflow check where we don't use the
+        multiplication result, just whether overflow happened.
+        If we can do MULT_HIGHPART_EXPR, that followed by
+        comparison of the result against zero is cheapest.
+        We'll still compute res, but it should be DCEd later.  */
+      use_operand_p use;
+      gimple *use_stmt;
+      if (!is_ubsan
+         && lhs
+         && uns
+         && !(uns0_p && uns1_p && !unsr_p)
+         && can_mult_highpart_p (mode, uns) == 1
+         && single_imm_use (lhs, &use, &use_stmt)
+         && is_gimple_assign (use_stmt)
+         && gimple_assign_rhs_code (use_stmt) == IMAGPART_EXPR)
+       goto highpart;
+
       if (GET_MODE_2XWIDER_MODE (mode).exists (&wmode)
-         && targetm.scalar_mode_supported_p (wmode))
+         && targetm.scalar_mode_supported_p (wmode)
+         && can_widen_mult_without_libcall (wmode, mode, op0, op1, uns))
        {
+       twoxwider:
          ops.code = WIDEN_MULT_EXPR;
          ops.type
            = build_nonstandard_integer_type (GET_MODE_PRECISION (wmode), uns);
@@ -1495,6 +1547,35 @@ expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1,
                                       profile_probability::very_likely ());
            }
        }
+      else if (can_mult_highpart_p (mode, uns) == 1)
+       {
+       highpart:
+         ops.code = MULT_HIGHPART_EXPR;
+         ops.type = type;
+
+         rtx hipart = expand_expr_real_2 (&ops, NULL_RTX, mode,
+                                          EXPAND_NORMAL);
+         ops.code = MULT_EXPR;
+         res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
+         if (uns)
+           /* For the unsigned multiplication, there was overflow if
+              HIPART is non-zero.  */
+           do_compare_rtx_and_jump (hipart, const0_rtx, EQ, true, mode,
+                                    NULL_RTX, NULL, done_label,
+                                    profile_probability::very_likely ());
+         else
+           {
+             rtx signbit = expand_shift (RSHIFT_EXPR, mode, res, prec - 1,
+                                         NULL_RTX, 0);
+             /* RES is low half of the double width result, HIPART
+                the high half.  There was overflow if
+                HIPART is different from RES < 0 ? -1 : 0.  */
+             do_compare_rtx_and_jump (signbit, hipart, EQ, true, mode,
+                                      NULL_RTX, NULL, done_label,
+                                      profile_probability::very_likely ());
+           }
+         
+       }
       else if (int_mode_for_size (prec / 2, 1).exists (&hmode)
               && 2 * GET_MODE_PRECISION (hmode) == prec)
        {
@@ -1800,6 +1881,11 @@ expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1,
          tem = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
          emit_move_insn (res, tem);
        }
+      else if (GET_MODE_2XWIDER_MODE (mode).exists (&wmode)
+              && targetm.scalar_mode_supported_p (wmode))
+       /* Even emitting a libcall is better than not detecting overflow
+          at all.  */
+       goto twoxwider;
       else
        {
          gcc_assert (!is_ubsan);
@@ -2588,7 +2674,7 @@ expand_DIVMOD (internal_fn, gcall *call_stmt)
   expand_expr (build2 (COMPLEX_EXPR, TREE_TYPE (lhs),
                       make_tree (TREE_TYPE (arg0), quotient),
                       make_tree (TREE_TYPE (arg1), remainder)),
-             target, VOIDmode, EXPAND_NORMAL);
+              target, VOIDmode, EXPAND_NORMAL);
 }
 
 /* Expand a call to FN using the operands in STMT.  FN has a single
index fd2b5d049ea0f9da9283826ffadffa374e6b4156..e006115e8fc7557fd42704e8a4f1d03bfedff491 100644 (file)
@@ -1,3 +1,8 @@
+2017-11-15  Jakub Jelinek  <jakub@redhat.com>
+
+       PR target/82981
+       * gcc.target/mips/pr82981.c: New test.
+
 2017-11-15  Martin Liska  <mliska@suse.cz>
 
        * g++.dg/ubsan/vptr-12.C: New test.
diff --git a/gcc/testsuite/gcc.target/mips/pr82981.c b/gcc/testsuite/gcc.target/mips/pr82981.c
new file mode 100644 (file)
index 0000000..677e4cc
--- /dev/null
@@ -0,0 +1,13 @@
+/* PR target/82981 */
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2" } } */
+/* { dg-options "-march=mips64r6 -mabi=64 -mexplicit-relocs" } */
+
+unsigned long
+func (unsigned long a, unsigned long b)
+{
+  return a > (~0UL) / b;
+}
+
+/* { dg-final { scan-assembler-not "__multi3" } } */
+/* { dg-final { scan-assembler "\tdmuhu" } } */