Shift instructions set ZN in the expected ways, *but* the H8's shifter, particularly in the older variants is quite limited.   THere's no variable shift and some variants can only shift 2 or even just 1 bit at a time.

Naturally the port tries to mitigate the cost of the limited shifter.  For example, (ashift (reg:HI) (const_int 8)) might be implemented by moving the low byte into the upper byte, then clearing the low byte.   That's a significant savings for both time and codesize.  Naturally some of those tricks do not leave the condition codes in a usable state.

So the port also encodes in its "shift strategy" datastructure, the state of the condition codes.  This was used in the old cc0 test/compare elimination code and we can re-use it in the new style.

Basically there's a routine (compute_a_shift_cc) which used to return the condition code state.  It's twiddled to just return a boolean indicating if ZN are set.   We might support the C bit one day, but for now ZN are what's needed to bring the port's code quality back to where it was before cc0 removal.

We use that routine in the predicate of the new insns which indicate that CCZN are live.  Easy.  There was one wrinkle I found while reviewing the assembly output.  I while back I added shift patterns which don't need a scratch register, but I added them *after* the existing patterns.  So we'd sometimes select those variant during combine.  So this patch does some pattern reordering and that makes the patch look larger than it really is.

 would use the more general pattern with the scratch because that came first in the MD file.  So some pattern reordering was necessary.  It makes the patch look bigger than it really is.

This isn't complete.  rotates need the same kind of changes.  And there's a few H8/SX specific patterns that need further work to be useful.  But I don't expect any of that work to be difficult or have as much of an impact as this core shift support.


commit 7aa5fb17a30ff0ce9928e5eac35b892d95e7eba5
Author: Jeff Law <jeffreya...@gmail.com>
Date:   Fri Jul 2 11:58:47 2021 -0400

    Use shift instructions to eliminate redundant compare/test instructions on 
the H8
    
    gcc/ChangeLog
    
            * config/h8300/h8300-protos.h (compute_a_shift_cc): Accept
            additional argument for the code.
            * config/h8300/h8300.c (compute_a_shift_cc): Accept additional
            argument for the code.  Just return if the ZN bits are useful or
            not rather than the old style CC_* enums.
            * config/h8300/shiftrotate.md (shiftqi_noscratch): Move before
            more generic shiftqi patterns.
            (shifthi_noscratch, shiftsi_noscratch): Similarly.
            (shiftqi_noscratch_set_flags): New pattern.
            (shifthi_noscratch_set_flags, shiftsi_noscratch_set_flags): 
Likewise.

diff --git a/gcc/config/h8300/h8300-protos.h b/gcc/config/h8300/h8300-protos.h
index 86bcc3fd324..744337d6667 100644
--- a/gcc/config/h8300/h8300-protos.h
+++ b/gcc/config/h8300/h8300-protos.h
@@ -41,7 +41,7 @@ extern const char *output_logical_op (machine_mode, rtx_code 
code,
 extern unsigned int compute_logical_op_length (machine_mode, rtx_code,
                                              rtx *, rtx_insn *);
 
-extern int compute_a_shift_cc (rtx, rtx *);
+extern int compute_a_shift_cc (rtx *, rtx_code);
 #ifdef HAVE_ATTR_cc
 extern enum attr_cc compute_plussi_cc (rtx *);
 #endif
diff --git a/gcc/config/h8300/h8300.c b/gcc/config/h8300/h8300.c
index 0fdc68bf65b..d2f6548a265 100644
--- a/gcc/config/h8300/h8300.c
+++ b/gcc/config/h8300/h8300.c
@@ -4297,11 +4297,9 @@ compute_a_shift_length (rtx operands[3], rtx_code code)
 /* Compute which flag bits are valid after a shift insn.  */
 
 int
-compute_a_shift_cc (rtx insn ATTRIBUTE_UNUSED, rtx *operands)
+compute_a_shift_cc (rtx operands[3], rtx_code code)
 {
-  rtx shift = operands[3];
-  machine_mode mode = GET_MODE (shift);
-  enum rtx_code code = GET_CODE (shift);
+  machine_mode mode = GET_MODE (operands[0]);
   enum shift_type shift_type;
   enum shift_mode shift_mode;
   struct shift_info info;
@@ -4358,16 +4356,18 @@ compute_a_shift_cc (rtx insn ATTRIBUTE_UNUSED, rtx 
*operands)
     {
     case SHIFT_SPECIAL:
       if (info.remainder == 0)
-       return info.cc_special;
+       return (info.cc_special == OLD_CC_SET_ZN
+               || info.cc_special == OLD_CC_SET_ZNV);
 
       /* Fall through.  */
 
     case SHIFT_INLINE:
-      return info.cc_inline;
+      return (info.cc_inline == OLD_CC_SET_ZN
+             || info.cc_inline == OLD_CC_SET_ZNV);
       
     case SHIFT_ROT_AND:
       /* This case always ends with an and instruction.  */
-      return OLD_CC_SET_ZNV;
+      return true;
       
     case SHIFT_LOOP:
       /* A loop to shift by a "large" constant value.
@@ -4375,9 +4375,11 @@ compute_a_shift_cc (rtx insn ATTRIBUTE_UNUSED, rtx 
*operands)
       if (info.shift2 != NULL)
        {
          if (n % 2)
-           return info.cc_inline;
+           return (info.cc_inline == OLD_CC_SET_ZN
+                   || info.cc_inline == OLD_CC_SET_ZNV);
+               
        }
-      return OLD_CC_CLOBBER;
+      return false;
       
     default:
       gcc_unreachable ();
diff --git a/gcc/config/h8300/shiftrotate.md b/gcc/config/h8300/shiftrotate.md
index c5d32cd6271..0476324bf22 100644
--- a/gcc/config/h8300/shiftrotate.md
+++ b/gcc/config/h8300/shiftrotate.md
@@ -150,33 +150,6 @@
 }
   [(set_attr "length" "4")])
 
-(define_insn_and_split "*shiftqi"
-  [(set (match_operand:QI 0 "register_operand" "=r,r")
-       (shifts:QI
-         (match_operand:QI 1 "register_operand" "0,0")
-         (match_operand:QI 2 "nonmemory_operand" "R,rn")))
-   (clobber (match_scratch:QI 3 "=X,&r"))]
-  ""
-  "#"
-  "&& reload_completed"
-  [(parallel [(set (match_dup 0) (shifts:QI (match_dup 1) (match_dup 2)))
-             (clobber (match_dup 3))
-             (clobber (reg:CC CC_REG))])])
-
-(define_insn "*shiftqi_clobber_flags"
-  [(set (match_operand:QI 0 "register_operand" "=r,r")
-       (shifts:QI
-         (match_operand:QI 1 "register_operand" "0,0")
-         (match_operand:QI 2 "nonmemory_operand" "R,rn")))
-   (clobber (match_scratch:QI 3 "=X,&r"))
-   (clobber (reg:CC CC_REG))]
-  ""
-{
-  return output_a_shift (operands, <CODE>);
-}
-  [(set (attr "length")
-       (symbol_ref "compute_a_shift_length (operands, <CODE>)"))])
-
 (define_insn_and_split "*shiftqi_noscratch"
   [(set (match_operand:QI 0 "register_operand" "=r,r")
        (shifts:QI
@@ -204,24 +177,43 @@
   [(set (attr "length")
        (symbol_ref "compute_a_shift_length (operands, <CODE>)"))])
 
-(define_insn_and_split "*shifthi"
-  [(set (match_operand:HI 0 "register_operand" "=r,r")
-       (shifts:HI
-         (match_operand:HI 1 "register_operand" "0,0")
-         (match_operand:QI 2 "nonmemory_operand" "S,rn")))
+(define_insn "*shiftqi_noscratch_set_flags"
+  [(set (reg:CCZN CC_REG)
+       (compare:CCZN
+         (shifts:QI
+           (match_operand:QI 1 "register_operand" "0,0")
+           (match_operand:QI 2 "nonmemory_operand" "R,rn"))
+         (const_int 0)))
+   (set (match_operand:QI 0 "register_operand" "=r,r")
+       (shifts:QI (match_dup 1) (match_dup 2)))]
+  "(GET_CODE (operands[2]) == CONST_INT
+    && !h8300_shift_needs_scratch_p (INTVAL (operands[2]), QImode, <CODE>)
+    && compute_a_shift_cc (operands, <CODE>))"
+{
+  return output_a_shift (operands, <CODE>);
+}
+  [(set (attr "length")
+       (symbol_ref "compute_a_shift_length (operands, <CODE>)"))])
+
+
+(define_insn_and_split "*shiftqi"
+  [(set (match_operand:QI 0 "register_operand" "=r,r")
+       (shifts:QI
+         (match_operand:QI 1 "register_operand" "0,0")
+         (match_operand:QI 2 "nonmemory_operand" "R,rn")))
    (clobber (match_scratch:QI 3 "=X,&r"))]
   ""
   "#"
   "&& reload_completed"
-  [(parallel [(set (match_dup 0) (shifts:HI (match_dup 1) (match_dup 2)))
+  [(parallel [(set (match_dup 0) (shifts:QI (match_dup 1) (match_dup 2)))
              (clobber (match_dup 3))
              (clobber (reg:CC CC_REG))])])
 
-(define_insn "*shifthi_clobber_flags"
-  [(set (match_operand:HI 0 "register_operand" "=r,r")
-       (shifts:HI
-         (match_operand:HI 1 "register_operand" "0,0")
-         (match_operand:QI 2 "nonmemory_operand" "S,rn")))
+(define_insn "*shiftqi_clobber_flags"
+  [(set (match_operand:QI 0 "register_operand" "=r,r")
+       (shifts:QI
+         (match_operand:QI 1 "register_operand" "0,0")
+         (match_operand:QI 2 "nonmemory_operand" "R,rn")))
    (clobber (match_scratch:QI 3 "=X,&r"))
    (clobber (reg:CC CC_REG))]
   ""
@@ -257,24 +249,41 @@
   [(set (attr "length")
        (symbol_ref "compute_a_shift_length (operands, <CODE>)"))])
 
-(define_insn_and_split "*shiftsi"
-  [(set (match_operand:SI 0 "register_operand" "=r,r")
-       (shifts:SI
-         (match_operand:SI 1 "register_operand" "0,0")
-         (match_operand:QI 2 "nonmemory_operand" "T,rn")))
+(define_insn "*shifthi_noscratch_setzn"
+  [(set (reg:CCZN CC_REG)
+       (compare:CCZN
+         (shifts:HI (match_operand:HI 1 "register_operand" "0,0")
+                    (match_operand:HI 2 "nonmemory_operand" "S,rn"))
+         (const_int 0)))
+   (set (match_operand:HI 0 "register_operand" "=r,r")
+       (shifts:HI (match_dup 1) (match_dup 2)))]
+  "(GET_CODE (operands[2]) == CONST_INT
+    && !h8300_shift_needs_scratch_p (INTVAL (operands[2]), HImode, <CODE>)
+    && compute_a_shift_cc (operands, <CODE>))"
+{
+  return output_a_shift (operands, <CODE>);
+}
+  [(set (attr "length")
+       (symbol_ref "compute_a_shift_length (operands, <CODE>)"))])
+
+(define_insn_and_split "*shifthi"
+  [(set (match_operand:HI 0 "register_operand" "=r,r")
+       (shifts:HI
+         (match_operand:HI 1 "register_operand" "0,0")
+         (match_operand:QI 2 "nonmemory_operand" "S,rn")))
    (clobber (match_scratch:QI 3 "=X,&r"))]
   ""
   "#"
   "&& reload_completed"
-  [(parallel [(set (match_dup 0) (shifts:SI (match_dup 1) (match_dup 2)))
+  [(parallel [(set (match_dup 0) (shifts:HI (match_dup 1) (match_dup 2)))
              (clobber (match_dup 3))
              (clobber (reg:CC CC_REG))])])
 
-(define_insn "*shiftsi_clobber_flags"
-  [(set (match_operand:SI 0 "register_operand" "=r,r")
-       (shifts:SI
-         (match_operand:SI 1 "register_operand" "0,0")
-         (match_operand:QI 2 "nonmemory_operand" "T,rn")))
+(define_insn "*shifthi_clobber_flags"
+  [(set (match_operand:HI 0 "register_operand" "=r,r")
+       (shifts:HI
+         (match_operand:HI 1 "register_operand" "0,0")
+         (match_operand:QI 2 "nonmemory_operand" "S,rn")))
    (clobber (match_scratch:QI 3 "=X,&r"))
    (clobber (reg:CC CC_REG))]
   ""
@@ -310,9 +319,55 @@
   [(set (attr "length")
        (symbol_ref "compute_a_shift_length (operands, <CODE>)"))])
 
+(define_insn "*shiftsi_noscratch_cczn"
+  [(set (reg:CCZN CC_REG)
+       (compare:CCZN
+         (shifts:SI
+           (match_operand:SI 1 "register_operand" "0,0")
+           (match_operand:SI 2 "nonmemory_operand" "T,rn"))
+         (const_int 0)))
+   (set (match_operand:SI 0 "register_operand" "=r,r")
+       (shifts:SI (match_dup 1) (match_dup 2)))]
+  "(GET_CODE (operands[2]) == CONST_INT
+    && !h8300_shift_needs_scratch_p (INTVAL (operands[2]), SImode, <CODE>)
+    && compute_a_shift_cc (operands, <CODE>))"
+{
+  return output_a_shift (operands, <CODE>);
+}
+  [(set (attr "length")
+       (symbol_ref "compute_a_shift_length (operands, <CODE>)"))])
+
 ;; Split a variable shift into a loop.  If the register containing
 ;; the shift count dies, then we just use that register.
 
+
+(define_insn_and_split "*shiftsi"
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (shifts:SI
+         (match_operand:SI 1 "register_operand" "0,0")
+         (match_operand:QI 2 "nonmemory_operand" "T,rn")))
+   (clobber (match_scratch:QI 3 "=X,&r"))]
+  ""
+  "#"
+  "&& reload_completed"
+  [(parallel [(set (match_dup 0) (shifts:SI (match_dup 1) (match_dup 2)))
+             (clobber (match_dup 3))
+             (clobber (reg:CC CC_REG))])])
+
+(define_insn "*shiftsi_clobber_flags"
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (shifts:SI
+         (match_operand:SI 1 "register_operand" "0,0")
+         (match_operand:QI 2 "nonmemory_operand" "T,rn")))
+   (clobber (match_scratch:QI 3 "=X,&r"))
+   (clobber (reg:CC CC_REG))]
+  ""
+{
+  return output_a_shift (operands, <CODE>);
+}
+  [(set (attr "length")
+       (symbol_ref "compute_a_shift_length (operands, <CODE>)"))])
+
 (define_split
   [(set (match_operand 0 "register_operand" "")
        (match_operator 2 "nshift_operator"

Reply via email to