https://gcc.gnu.org/g:c435bbdd22a7fc2d18129f261fd2050e72f98411

commit r16-5481-gc435bbdd22a7fc2d18129f261fd2050e72f98411
Author: Loeka Rogge <[email protected]>
Date:   Fri Nov 21 11:45:01 2025 +0200

    arc: emit clobber of CC for -mcpu=em x >> 31
    
    Address PR target/120375
    
    Devices without a barrel shifter end up using a sequence of
    instructions. These can use the condition codes and/or loop count
    register, so those need to be marked as 'clobbered'. These clobbers were
    previously added only after split1, which is too late. This patch adds
    these clobbers from the beginning, in the define_expand.
    
    Previously, define_insn_and_split *<insn>si3_nobs would match any shift or
    rotate instruction and would generate the necessary patterns to emulate a
    barrel shifter, but it did not have any output assembly for itself.
    In many cases this would create a loop with parallel clobbers. This pattern
    is then matched by the <insn>si3_loop pattern.
    
    In the no-barrel-shifter.c test tree code:
    
    ;; no-barrel-shifter.c:9:     int sign = (x >> 31) & 1;
    _2 = x.0_1 >> 31;
    
    in the expand pass becomes the following pattern that matches *lshrsi3_nobs:
    
    (insn 18 17 19 4 (set (reg:SI 153 [ _2 ])
            (lshiftrt:SI (reg/v:SI 156 [ x ])
                (const_int 31 [0x1f]))) "test2.c":9:24 -1
         (nil))
    
    This pattern misses the necessary clobbers and remains untouched until the
    split1 pass. Together with the later branch it becomes
    
    ;; no-barrel-shifter.c:9:     int sign = (x >> 31) & 1;
            add.f   0,r0,r0
    ;; no-barrel-shifter.c:14:     if (mag == 0x7f800000)
            beq.d   .L8
    ;; no-barrel-shifter.c:9:     int sign = (x >> 31) & 1;
            rlc     r0,0
    
    Leading to an issue: the add.f instructions overwrites CC but beq expects
    CC to contain an earlier value indicating mag == 0x7f800000.
    
    Now, these are combined in define_insn_and_split <insn>si3_loop that is
    explicitly emitted in the define_expand and already contains the clobbers.
    This can then be split into another pattern or remain the loop pattern.
    
    In the expand pass, the same example now becomes:
    
    (insn 18 17 19 4 (parallel [
                (set (reg:SI 153 [ _2 ])
                    (lshiftrt:SI (reg/v:SI 156 [ x ])
                        (const_int 31 [0x1f])))
                (clobber (reg:SI 60 lp_count))
                (clobber (reg:CC 61 cc))
            ]) "test2.c":9:24 -1
         (nil))
    
    Because the correct clobbers are now taken into account, the branch 
condition
    is reevaluated by using breq instead of br.
    
    ;; no-barrel-shifter.c:9:     int sign = (x >> 31) & 1;
            add.f   0,r0,r0
            rlc     r0,0
    ;; no-barrel-shifter.c:14:     if (mag == 0x7f800000)
            breq    r2,2139095040,.L8
    
    Regtested for arc.
    
            PR target/120375
    
    gcc/ChangeLog:
    
            * config/arc/arc.md (*<insn>si3_nobs): merged with <insn>si3_loop.
            (<insn>si3_loop): splits to relevant pattern or emits loop assembly.
            (<insn>si3_cnt1_clobber): Removes clobber for shift or rotate by
            const1.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.target/arc/no-barrel-shifter.c: New test.
    
    Co-authored-by: Keith Packard <[email protected]>
    Signed-off-by: Loeka Rogge <[email protected]>

Diff:
---
 gcc/config/arc/arc.md                            | 60 ++++++++++++++----------
 gcc/testsuite/gcc.target/arc/no-barrel-shifter.c | 19 ++++++++
 2 files changed, 54 insertions(+), 25 deletions(-)

diff --git a/gcc/config/arc/arc.md b/gcc/config/arc/arc.md
index 55be6ce74da7..2b16ac5f2c74 100644
--- a/gcc/config/arc/arc.md
+++ b/gcc/config/arc/arc.md
@@ -3555,7 +3555,14 @@ archs4x, archs4xd"
   [(set (match_operand:SI 0 "dest_reg_operand" "")
        (ANY_SHIFT_ROTATE:SI (match_operand:SI 1 "register_operand" "")
                             (match_operand:SI 2 "nonmemory_operand" "")))]
-  "")
+  ""
+{
+  if (!TARGET_BARREL_SHIFTER && operands[2] != const1_rtx)
+    {
+      emit_insn (gen_<insn>si3_loop (operands[0], operands[1], operands[2]));
+      DONE;
+    }
+})
 
 ; asl, asr, lsr patterns:
 ; There is no point in including an 'I' alternative since only the lowest 5
@@ -3654,35 +3661,23 @@ archs4x, archs4xd"
   [(set_attr "type" "shift")
    (set_attr "length" "8")])
 
-(define_insn_and_split "*<insn>si3_nobs"
-  [(set (match_operand:SI 0 "dest_reg_operand")
-       (ANY_SHIFT_ROTATE:SI (match_operand:SI 1 "register_operand")
-                            (match_operand:SI 2 "nonmemory_operand")))]
+(define_insn_and_split "<insn>si3_loop"
+  [(set (match_operand:SI 0 "dest_reg_operand" "=r,r")
+  (ANY_SHIFT_ROTATE:SI (match_operand:SI 1 "register_operand" "0,0")
+        (match_operand:SI 2 "nonmemory_operand" "rn,Cal")))
+  (clobber (reg:SI LP_COUNT))
+  (clobber (reg:CC CC_REG))]
   "!TARGET_BARREL_SHIFTER
-   && operands[2] != const1_rtx
-   && arc_pre_reload_split ()"
-  "#"
-  "&& 1"
+  && operands[2] != const1_rtx"
+  "* return output_shift_loop (<CODE>, operands);"
+  "&& arc_pre_reload_split ()"
   [(const_int 0)]
 {
   arc_split_<insn> (operands);
   DONE;
-})
-
-;; <ANY_SHIFT_ROTATE>si3_loop appears after <ANY_SHIFT_ROTATE>si3_nobs
-(define_insn "<insn>si3_loop"
-  [(set (match_operand:SI 0 "dest_reg_operand" "=r,r")
-       (ANY_SHIFT_ROTATE:SI 
-         (match_operand:SI 1 "register_operand" "0,0")
-         (match_operand:SI 2 "nonmemory_operand" "rn,Cal")))
-   (clobber (reg:SI LP_COUNT))
-   (clobber (reg:CC CC_REG))
-  ]
-  "!TARGET_BARREL_SHIFTER
-   && operands[2] != const1_rtx"
-  "* return output_shift_loop (<CODE>, operands);"
-  [(set_attr "type" "shift")
-   (set_attr "length" "16,20")])
+}
+[(set_attr "type" "shift")
+ (set_attr "length" "16,20")])
 
 ;; DImode shifts
 
@@ -6414,6 +6409,21 @@ archs4x, archs4xd"
    (set_attr "length" "4")
    (set_attr "predicable" "no")])
 
+;; Match <insn>si3_loop pattern if operand 2 has become const_int 1 in the 
meantime
+(define_insn_and_split "<insn>si3_cnt1_clobber"
+  [(set (match_operand:SI 0 "dest_reg_operand")
+  (ANY_SHIFT_ROTATE:SI (match_operand:SI 1 "register_operand")
+        (const_int 1)))
+  (clobber (reg:SI LP_COUNT))
+  (clobber (reg:CC CC_REG))]
+  "!TARGET_BARREL_SHIFTER"
+  "#"
+  "&& arc_pre_reload_split ()"
+  [(set (match_dup 0) (ANY_SHIFT_ROTATE:SI (match_dup 1) (const_int 1)))]
+  ""
+[(set_attr "type" "shift")
+ (set_attr "length" "4")])
+
 (define_peephole2
   [(set (match_operand:SI 0 "register_operand" "")
        (zero_extract:SI (match_dup 0)
diff --git a/gcc/testsuite/gcc.target/arc/no-barrel-shifter.c 
b/gcc/testsuite/gcc.target/arc/no-barrel-shifter.c
new file mode 100644
index 000000000000..2506bdfcad87
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/no-barrel-shifter.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-skip-if "" { { barrelshifter } } } */
+int fromfloat(float fx);
+
+float foo(float fx)
+{
+  int x = fromfloat(fx);
+  int sign = (x >> 31) & 1;
+  unsigned int mag = x & 0x7fffffff;
+
+  if (mag > 0x7f800000)
+    return fx;
+  if (mag == 0x7f800000)
+    return (sign == 0);
+  return fx * (27 + sign);
+}
+
+/* { dg-final { scan-assembler-not 
"add.f\\s\+\[0-9\]\+,r\[0-9\]\+,r\[0-9\]\+\\n\\s\+beq.d" } } */

Reply via email to