cris: Enable single-bit btst/btstq to set condition codes.
authorHans-Peter Nilsson <hp@axis.com>
Thu, 6 Feb 2020 03:46:34 +0000 (04:46 +0100)
committerHans-Peter Nilsson <hp@axis.com>
Sat, 9 May 2020 02:20:26 +0000 (04:20 +0200)
Enables the use of btst / btstq for a single bit (at other bits
than 0, including as indicated by a variable) to set
condition-codes.  There's also a bug-fix for the bit-0-btstq
pattern; it shouldn't generate CCmode as only the Z flag is
valid, still using CC_NZmode is ok, as only equality-tests are
generated.  The cris_rtx_costs tweak is necessary or else
combine will consider the btst not preferable.  It reduces the
difference to cc0-costs beyond the threshold to the
transformation being seen as profitable, but there's still a
difference in values for the pre-split-time btst+branch as
opposed to the cc0 btst and branch, with both appearing to be
the cost of several insns (18 and 22).

gcc:
* config/cris/cris-modes.def (CC_ZnN): New CC_MODE.
* config/cris/cris.c (cris_rtx_costs): Handle pre-split bit-test
* config/cris/cris.md (ZnNNZSET, ZnNNZUSE): New mode_iterators.
(znnCC, rznnCC): New code_attrs.
("*btst<mode>"): Iterator over ZnNNZSET instead of NZVCSET.  Remove
obseolete comment.  Add belt-and-suspenders mode-test to condition.
Add fixme regarding remaining matched-but-not-generated case.
("*cbranch<mode>4_btstrq1_<CC>"): New insn_and_split.
("*cbranch<mode>4_btstqb0_<CC>"): Rename from
"*cbranch<mode>4_btstq<CC>".  Split to CC_NZ instead of CC.
("*b<zcond:code><mode>"): Iterate over ZnNNZUSE instead of NZUSE.
Handle output of CC_ZnNmode.
("*b<nzcond:code>_reversed<mode>"): Ditto.

gcc/ChangeLog
gcc/config/cris/cris-modes.def
gcc/config/cris/cris.c
gcc/config/cris/cris.md

index 9aca1c3310ecf5b8f66008ce955aadcb0c529cef..8f14fdba64a73b9e3a20ec5321db152be632d082 100644 (file)
        from "bswapsi2".
        ("*uminsi3<setcc><setnz><setnzvc>"): Rename from "*uminsi3".
 
+       * config/cris/cris-modes.def (CC_ZnN): New CC_MODE.
+       * config/cris/cris.c (cris_rtx_costs): Handle pre-split bit-test
+       * config/cris/cris.md (ZnNNZSET, ZnNNZUSE): New mode_iterators.
+       (znnCC, rznnCC): New code_attrs.
+       ("*btst<mode>"): Iterator over ZnNNZSET instead of NZVCSET.  Remove
+       obseolete comment.  Add belt-and-suspenders mode-test to condition.
+       Add fixme regarding remaining matched-but-not-generated case.
+       ("*cbranch<mode>4_btstrq1_<CC>"): New insn_and_split.
+       ("*cbranch<mode>4_btstqb0_<CC>"): Rename from
+       "*cbranch<mode>4_btstq<CC>".  Split to CC_NZ instead of CC.
+       ("*b<zcond:code><mode>"): Iterate over ZnNNZUSE instead of NZUSE.
+       Handle output of CC_ZnNmode.
+       ("*b<nzcond:code>_reversed<mode>"): Ditto.
+
 2020-05-08  Vladimir Makarov  <vmakarov@redhat.com>
 
        * ira-color.c (update_costs_from_allocno): Remove
index 1e72b539caff96fd59746a2959fcf1a793de953c..1aaf12a0f5ba04d6eed718aab6772c8157234651 100644 (file)
@@ -28,8 +28,6 @@ along with GCC; see the file COPYING3.  If not see
    (fpcraz).  The two subsets meaningful to gcc are all of N, Z, V, C
    versus just N, Z; some CC-users care only about N and/or Z and some
    that care about at least one of those flags together with V and/or C.
-   (FIXME: the result of testing a single bit using the btst instruction
-   should be described as a separate mode.)
 
    The plain "CC_MODE (CC)" (which is always present in gcc), is used to
    reflect the "unoptimized" state, where the CC-setter is a compare
@@ -52,3 +50,7 @@ CC_MODE (CC_NZ);
    are set to usable values, fpcraz.  For a condition-code user: at least
    one of V and C are used and possibly N and Z too.  */
 CC_MODE (CC_NZVC);
+
+/* The result of a btst / btstq instruction for extracting a single bit
+   goes negated into the N flag, or in olde cc0-parlance, CC_Z_IN_NOT_N.  */
+CC_MODE (CC_ZnN);
index 04c80c314a33d6d283700d34814a5a4b44a947a7..d0807adc87f1801f29b1fafdb498a4c7becfe91c 100644 (file)
@@ -1772,8 +1772,30 @@ cris_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno,
       return false;
 
     case ZERO_EXTRACT:
-      if (outer_code != COMPARE)
-        return false;
+      /* Conditionals are split after reload, giving a different look.  */
+      if (reload_completed)
+       {
+         if (outer_code != COMPARE)
+           return false;
+       }
+      else
+       switch (outer_code)
+         {
+         case EQ:
+         case NE:
+         case LT:
+         case LTU:
+         case LE:
+         case LEU:
+         case GT:
+         case GTU:
+         case GE:
+         case GEU:
+           break;
+
+         default:
+           return false;
+         }
       /* fall through */
 
     case ZERO_EXTEND: case SIGN_EXTEND:
index c085e26602e6201bc85a5a94fd7ae23503c044f4..1e895a375c33e10b780007c8de1dbadfb4d247b2 100644 (file)
 (define_mode_iterator NZUSE [CC CC_NZ CC_NZVC])
 (define_mode_iterator NZVCSET [CC CC_NZVC CC_NZ])
 (define_mode_iterator NZVCUSE [CC_NZVC])
+(define_mode_iterator ZnNNZSET [CC_ZnN CC_NZ])
+(define_mode_iterator ZnNNZUSE [CC CC_ZnN CC_NZ CC_NZVC])
 
 ;; All conditions.
 (define_code_iterator cond [eq ne gtu ltu geu leu gt le lt ge])
 ;; Reverse of oCC.
 (define_code_attr roCC [(lt "pl") (ge "mi") (gtu "eq") (ltu "ne")])
 
+;; CC_Z_IN_NOT_N, a.k.a. CC_ZnNmode.
+(define_code_attr znnCC [(eq "pl") (ne "mi")])
+
+;;; ...and the reverse
+(define_code_attr rznnCC [(eq "mi") (ne "pl")])
+
 ;; Required unoptimized CCmode, different for nzcond and nzvccond.
 (define_code_attr xCC [(eq "CC") (ne "CC") (gtu "CC") (ltu "CC_NZVC")
                       (geu "CC_NZVC") (leu "CC") (lt "CC") (ge "CC")
 ;; of zeros starting at bit 0).
 
 ;; SImode.  This mode is the only one needed, since gcc automatically
-;; extends subregs for lower-size modes.  FIXME: Add testcase.
+;; extends subregs for lower-size modes.
 (define_insn "*btst<mode>"
-  [(set (reg:NZVCSET CRIS_CC0_REGNUM)
-       (compare:NZVCSET
+  [(set (reg:ZnNNZSET CRIS_CC0_REGNUM)
+       (compare:ZnNNZSET
         (zero_extract:SI
          (match_operand:SI 0 "nonmemory_operand" "r, r,r, r,r, r,Kp")
          (match_operand:SI 1 "const_int_operand" "Kc,n,Kc,n,Kc,n,n")
          (match_operand:SI 2 "nonmemory_operand" "M, M,Kc,n,r, r,r"))
         (const_int 0)))]
   ;; Either it is a single bit, or consecutive ones starting at 0.
-  ;; The btst ones depend on stuff in NOTICE_UPDATE_CC.
   "reload_completed
    && CONST_INT_P (operands[1])
-   && (operands[1] == const1_rtx || operands[2] == const0_rtx)
+   && ((operands[1] == const1_rtx && <MODE>mode == CC_ZnNmode)
+       || (operands[2] == const0_rtx && <MODE>mode == CC_NZmode))
    && (REG_S_P (operands[0])
        || (operands[1] == const1_rtx
           && REG_S_P (operands[2])
 ;; The next-to-last "&&" condition above should be caught by some kind of
 ;; canonicalization in gcc, but we can easily help with it here.
 ;;  It results from expressions of the type
-;; "power_of_2_value & (1 << y)".
+;; "power_of_2_value & (1 << y)".  FIXME: Add testcase.
 ;;
 ;; Since there may be codes with tests in on bits (in constant position)
 ;; beyond the size of a word, handle that by assuming those bits are 0.
                      (pc)))]
   "")
 
-;; FIXME: this matches only a subset of what the "*btst" pattern can handle.
-(define_insn_and_split "*cbranch<mode>4_btstq<CC>"
+;; Test a single bit at operand[0] against 0/non-0.
+(define_insn_and_split "*cbranch<mode>4_btstrq1_<CC>"
+  [(set (pc)
+       (if_then_else
+        (zcond
+         (zero_extract:BWD
+          (match_operand:BWD 0 "register_operand" "r,r")
+          (const_int 1)
+          (match_operand:SI 1 "nonmemory_operand" "Kc,r"))
+         (const_int 0))
+        (label_ref (match_operand 2 ""))
+        (pc)))
+   (clobber (reg:CC CRIS_CC0_REGNUM))]
+  ""
+  "#"
+  "&& reload_completed"
+  [(set (reg:CC_ZnN CRIS_CC0_REGNUM)
+       (compare:CC_ZnN
+        (zero_extract:SI (match_dup 0) (const_int 1) (match_dup 1))
+        (const_int 0)))
+   (set (pc)
+       (if_then_else (zcond (reg:CC_ZnN CRIS_CC0_REGNUM) (const_int 0))
+                     (label_ref (match_dup 2))
+                     (pc)))]
+  "")
+
+;; Test a field of bits starting at bit 0 against 0/non-0.
+(define_insn_and_split "*cbranch<mode>4_btstqb0_<CC>"
   [(set (pc)
        (if_then_else
         (zcond
   ""
   "#"
   "&& reload_completed"
-  [(set (reg:CC CRIS_CC0_REGNUM)
-       (compare:CC
+  [(set (reg:CC_NZ CRIS_CC0_REGNUM)
+       (compare:CC_NZ
         (zero_extract:SI (match_dup 0) (match_dup 1) (const_int 0))
         (const_int 0)))
    (set (pc)
-       (if_then_else (zcond (reg:CC CRIS_CC0_REGNUM) (const_int 0))
+       (if_then_else (zcond (reg:CC_NZ CRIS_CC0_REGNUM) (const_int 0))
                      (label_ref (match_dup 2))
                      (pc)))]
   "")
 
 (define_insn "*b<zcond:code><mode>"
   [(set (pc)
-       (if_then_else (zcond (reg:NZUSE CRIS_CC0_REGNUM)
+       (if_then_else (zcond (reg:ZnNNZUSE CRIS_CC0_REGNUM)
                             (const_int 0))
                      (label_ref (match_operand 0 "" ""))
                      (pc)))]
   "reload_completed"
-  "b<CC> %l0%#"
+{
+  return <MODE>mode == CC_ZnNmode ? "b<znnCC> %l0%#" : "b<CC> %l0%#";
+}
   [(set_attr "slottable" "has_slot")])
 
 (define_insn "*b<nzvccond:code><mode>"
 
 (define_insn "*b<nzcond:code>_reversed<mode>"
   [(set (pc)
-       (if_then_else (nzcond (reg:NZUSE CRIS_CC0_REGNUM)
-                            (const_int 0))
+       (if_then_else (nzcond (reg:ZnNNZUSE CRIS_CC0_REGNUM)
+                             (const_int 0))
                      (pc)
                      (label_ref (match_operand 0 "" ""))))]
   "reload_completed"
-  "b<rCC> %l0%#"
+{
+  return <MODE>mode == CC_ZnNmode ? "b<rznnCC> %l0%#" : "b<rCC> %l0%#";
+}
   [(set_attr "slottable" "has_slot")])
 
 (define_insn "*b<nzvccond:code>_reversed<mode>"