]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Shorten right-shift again in C++.
authorJason Merrill <jason@redhat.com>
Fri, 10 Jan 2020 18:53:17 +0000 (13:53 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Fri, 10 Jan 2020 18:53:17 +0000 (13:53 -0500)
Back in SVN r131862 richi removed this code to fix PR 34235, but didn't
remove the parallel code from the C front-end because the bug had previously
been fixed in r44080.  This patch copies the code from C again.

* typeck.c (cp_build_binary_op): Restore short_shift code.

From-SVN: r280128

gcc/cp/ChangeLog
gcc/cp/typeck.c

index 1a36cd3c89ec44c5b2e6793640881b65e015c95c..1dad238028acb84af68feff2019259d738cbc473 100644 (file)
@@ -1,5 +1,7 @@
 2020-01-10  Jason Merrill  <jason@redhat.com>
 
+       * typeck.c (cp_build_binary_op): Restore short_shift code.
+
        PR c++/93143 - incorrect tree sharing with constexpr.
        * constexpr.c (cxx_eval_outermost_constant_expr): Don't assume
        CONSTRUCTORs are already unshared.
index 9f4f535f41ad0fcbeddf24c49579e0bb6509bab4..7b653cebca0a5da760e732491b73371d43a4c80a 100644 (file)
@@ -4452,6 +4452,10 @@ cp_build_binary_op (const op_location_t &location,
      Also implies COMMON.  */
   int short_compare = 0;
 
+  /* Nonzero if this is a right-shift operation, which can be computed on the
+     original short and then promoted if the operand is a promoted short.  */
+  int short_shift = 0;
+
   /* Nonzero means set RESULT_TYPE to the common type of the args.  */
   int common = 0;
 
@@ -4844,6 +4848,9 @@ cp_build_binary_op (const op_location_t &location,
                }
              else
                {
+                 if (!integer_zerop (op1))
+                   short_shift = 1;
+
                  if (compare_tree_int (const_op1, TYPE_PRECISION (type0)) >= 0
                      && (complain & tf_warning)
                      && c_inhibit_evaluation_warnings == 0)
@@ -5586,6 +5593,37 @@ cp_build_binary_op (const op_location_t &location,
                                           shorten == -1);
        }
 
+      /* Shifts can be shortened if shifting right.  */
+
+      if (short_shift)
+       {
+         int unsigned_arg;
+         tree arg0 = get_narrower (op0, &unsigned_arg);
+
+         final_type = result_type;
+
+         if (arg0 == op0 && final_type == TREE_TYPE (op0))
+           unsigned_arg = TYPE_UNSIGNED (TREE_TYPE (op0));
+
+         if (TYPE_PRECISION (TREE_TYPE (arg0)) < TYPE_PRECISION (result_type)
+             && tree_int_cst_sgn (op1) > 0
+             /* We can shorten only if the shift count is less than the
+                number of bits in the smaller type size.  */
+             && compare_tree_int (op1, TYPE_PRECISION (TREE_TYPE (arg0))) < 0
+             /* We cannot drop an unsigned shift after sign-extension.  */
+             && (!TYPE_UNSIGNED (final_type) || unsigned_arg))
+           {
+             /* Do an unsigned shift if the operand was zero-extended.  */
+             result_type
+               = c_common_signed_or_unsigned_type (unsigned_arg,
+                                                   TREE_TYPE (arg0));
+             /* Convert value-to-be-shifted to that type.  */
+             if (TREE_TYPE (op0) != result_type)
+               op0 = convert (result_type, op0);
+             converted = 1;
+           }
+       }
+
       /* Comparison operations are shortened too but differently.
         They identify themselves by setting short_compare = 1.  */