https://gcc.gnu.org/g:02fff24e2c6d4affc47dac1433b2fb182dadd4db

commit r15-5472-g02fff24e2c6d4affc47dac1433b2fb182dadd4db
Author: Jakub Jelinek <ja...@redhat.com>
Date:   Tue Nov 19 20:34:36 2024 +0100

    c: Fix up __builtin_stdc_rotate_{left,right} lowering [PR117456]
    
    Apparently the middle-end/expansion can only handle {L,R}ROTATE_EXPR
    on types with mode precision, or large/huge BITINT_TYPE.
    So, the following patch uses the rotate exprs only in those cases
    where it can be handled, and emits code with shifts/ior otherwise.
    As types without mode precision including small/medium BITINT_TYPE
    have unlikely power of two precision and TRUNC_MOD_EXPR is on many targets
    quite expensive, I chose to expand e.g. __builtin_stdc_rotate_left (arg1,
    arg2) as
    ((tem = arg1, count = arg2 % prec)
     ? ((tem << count) | (tem >> (prec - count))) : tem)
    rather than
    (((tem = arg1) << (count = arg2 % prec))
     | (tem >> (-count % prec))
    (where the assignments are really save_exprs, so no UB), because
    I think another TRUNC_MOD_EXPR would be more costly in most cases
    when the shift count is non-constant (and when it is constant,
    it folds to 2 shifts by constant and ior in either case).
    
    2024-11-19  Jakub Jelinek  <ja...@redhat.com>
    
            PR c/117456
    gcc/c/
            * c-parser.cc (c_parser_postfix_expression): Use LROTATE_EXPR
            or RROTATE_EXPR only if type_has_mode_precision_p or if arg1
            has BITINT_TYPE with precision larger than MAX_FIXED_MODE_SIZE.
            Otherwise build BIT_IOR_EXPR of LSHIFT_EXPR and RSHIFT_EXPR
            and wrap it into a COND_EXPR depending on if arg2 is 0 or not.
            * c-fold.cc (c_fully_fold_internal): Check for suppression of
            -Wshift-count-overflow warning.
    gcc/testsuite/
            * gcc.dg/builtin-stdc-rotate-4.c: New test.

Diff:
---
 gcc/c/c-fold.cc                              |   3 +-
 gcc/c/c-parser.cc                            |  34 +++++++-
 gcc/testsuite/gcc.dg/builtin-stdc-rotate-4.c | 120 +++++++++++++++++++++++++++
 3 files changed, 154 insertions(+), 3 deletions(-)

diff --git a/gcc/c/c-fold.cc b/gcc/c/c-fold.cc
index deb6896589f5..0c4c5904e402 100644
--- a/gcc/c/c-fold.cc
+++ b/gcc/c/c-fold.cc
@@ -410,7 +410,8 @@ c_fully_fold_internal (tree expr, bool in_init, bool 
*maybe_const_operands,
                    || TREE_CODE (TREE_TYPE (orig_op0)) == FIXED_POINT_TYPE)
                   && compare_tree_int (op1,
                                        TYPE_PRECISION (TREE_TYPE (orig_op0)))
-                     >= 0)
+                     >= 0
+                  && !warning_suppressed_p (expr, OPT_Wshift_count_overflow))
            warning_at (loc, OPT_Wshift_count_overflow,
                        (code == LSHIFT_EXPR
                         ? G_("left shift count >= width of type")
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 70fbf9408353..def6b3004f25 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -12638,8 +12638,38 @@ c_parser_postfix_expression (c_parser *parser)
                                       build_int_cst (utype, prec));
                  }
 
-               expr.value = build2_loc (loc, code, TREE_TYPE (arg1), arg1,
-                                        arg2);
+               /* The middle-end isn't prepared to handle {L,R}ROTATE_EXPR
+                  on types without mode precision, except for large/huge
+                  _BitInt types.  */
+               if (type_has_mode_precision_p (TREE_TYPE (arg1))
+                   || (TREE_CODE (TREE_TYPE (arg1)) == BITINT_TYPE
+                       && prec > MAX_FIXED_MODE_SIZE))
+                 expr.value = build2_loc (loc, code, TREE_TYPE (arg1), arg1,
+                                          arg2);
+               else
+                 {
+                   arg2 = save_expr (arg2);
+                   tree t1 = build2_loc (loc, (code == LROTATE_EXPR
+                                               ? LSHIFT_EXPR : RSHIFT_EXPR),
+                                         TREE_TYPE (arg1), arg1, arg2);
+                   tree t2 = build2_loc (loc, MINUS_EXPR,
+                                         TREE_TYPE (arg2),
+                                         build_int_cst (TREE_TYPE (arg2),
+                                                        prec), arg2);
+                   t2 = build2_loc (loc, (code == LROTATE_EXPR
+                                          ? RSHIFT_EXPR : LSHIFT_EXPR),
+                                    TREE_TYPE (arg1), arg1, t2);
+                   suppress_warning (t2, OPT_Wshift_count_overflow);
+                   tree t3 = build2_loc (loc, BIT_IOR_EXPR,
+                                         TREE_TYPE (arg1), t1, t2);
+                   tree t4 = build2_loc (loc, NE_EXPR, boolean_type_node,
+                                         arg2,
+                                         build_zero_cst (TREE_TYPE (arg2)));
+                   t4 = build2_loc (loc, COMPOUND_EXPR, boolean_type_node,
+                                    arg1, t4);
+                   expr.value = build3_loc (loc, COND_EXPR,
+                                            TREE_TYPE (arg1), t4, t3, arg1);
+                 }
                if (instrument_expr)
                  expr.value = build2_loc (loc, COMPOUND_EXPR,
                                           TREE_TYPE (expr.value),
diff --git a/gcc/testsuite/gcc.dg/builtin-stdc-rotate-4.c 
b/gcc/testsuite/gcc.dg/builtin-stdc-rotate-4.c
new file mode 100644
index 000000000000..590b3ab74dc1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtin-stdc-rotate-4.c
@@ -0,0 +1,120 @@
+/* PR c/117456 */
+/* { dg-do run } */
+/* { dg-options "-std=c11" } */
+
+struct S {
+  unsigned s : 5;
+};
+
+unsigned
+f1 (struct S s)
+{
+  return __builtin_stdc_rotate_left (s.s, 3);
+}
+
+unsigned
+f2 (struct S s, int n)
+{
+  return __builtin_stdc_rotate_left (s.s, n);
+}
+
+unsigned
+f3 (struct S s)
+{
+  return __builtin_stdc_rotate_right (s.s, 2);
+}
+
+unsigned
+f4 (struct S s, int n)
+{
+  return __builtin_stdc_rotate_right (s.s, n);
+}
+
+#if __BITINT_MAXWIDTH__ >= 64
+unsigned _BitInt(5)
+f5 (unsigned _BitInt(5) s)
+{
+  return __builtin_stdc_rotate_left (s, 3);
+}
+
+unsigned _BitInt(5)
+f6 (unsigned _BitInt(5) s, int n)
+{
+  return __builtin_stdc_rotate_left (s, n);
+}
+
+unsigned _BitInt(5)
+f7 (unsigned _BitInt(5) s)
+{
+  return __builtin_stdc_rotate_right (s, 2);
+}
+
+unsigned _BitInt(5)
+f8 (unsigned _BitInt(5) s, int n)
+{
+  return __builtin_stdc_rotate_right (s, n);
+}
+#endif
+
+#if __BITINT_MAXWIDTH__ >= 125
+unsigned _BitInt(125)
+f9 (unsigned _BitInt(125) s)
+{
+  return __builtin_stdc_rotate_left (s, 13);
+}
+
+unsigned _BitInt(125)
+f10 (unsigned _BitInt(125) s, int n)
+{
+  return __builtin_stdc_rotate_left (s, n);
+}
+
+unsigned _BitInt(125)
+f11 (unsigned _BitInt(125) s)
+{
+  return __builtin_stdc_rotate_right (s, 42);
+}
+
+unsigned _BitInt(125)
+f12 (unsigned _BitInt(125) s, int n)
+{
+  return __builtin_stdc_rotate_right (s, n);
+}
+#endif
+
+int
+main ()
+{
+  struct S s = { 0x12 };
+  if (f1 (s) != 0x14
+      || f2 (s, 0) != 0x12
+      || f2 (s, 2) != 0xa
+      || f2 (s, 1) != 0x5
+      || f3 (s) != 0x14
+      || f4 (s, 0) != 0x12
+      || f4 (s, 2) != 0x14
+      || f4 (s, 1) != 0x9)
+    __builtin_abort ();
+#if __BITINT_MAXWIDTH__ >= 64
+  if (f5 (0x12uwb) != 0x14uwb
+      || f6 (0x12uwb, 0) != 0x12uwb
+      || f6 (0x12uwb, 2) != 0xauwb
+      || f6 (0x12uwb, 1) != 0x5uwb
+      || f7 (0x12uwb) != 0x14uwb
+      || f8 (0x12uwb, 0) != 0x12uwb
+      || f8 (0x12uwb, 2) != 0x14uwb
+      || f8 (0x12uwb, 1) != 0x9uwb)
+    __builtin_abort ();
+#endif
+#if __BITINT_MAXWIDTH__ >= 125
+  if (f9 (12107255122146692213464668179507246062uwb) != 
32859299037257821061785486091897129243uwb
+      || f10 (12107255122146692213464668179507246062uwb, 0) != 
12107255122146692213464668179507246062uwb
+      || f10 (12107255122146692213464668179507246062uwb, 57) != 
786310737972746809290227161460052307uwb
+      || f10 (12107255122146692213464668179507246062uwb, 1) != 
24214510244293384426929336359014492124uwb
+      || f11 (12107255122146692213464668179507246062uwb) != 
25567301336572975565218391744704605699uwb
+      || f12 (12107255122146692213464668179507246062uwb, 0) != 
12107255122146692213464668179507246062uwb
+      || f12 (12107255122146692213464668179507246062uwb, 22) != 
27217840477347696606051931660144451082uwb
+      || f12 (12107255122146692213464668179507246062uwb, 1) != 
6053627561073346106732334089753623031uwb)
+    __builtin_abort ();
+#endif
+}

Reply via email to