rs6000: Use isel for the cstore patterns
authorSegher Boessenkool <segher@kernel.crashing.org>
Tue, 7 Nov 2017 19:33:57 +0000 (20:33 +0100)
committerSegher Boessenkool <segher@gcc.gnu.org>
Tue, 7 Nov 2017 19:33:57 +0000 (20:33 +0100)
We currently generate (sometimes pretty long) sequences of integer
insns to implement the various cstore patterns.  If the CPU has a fast
isel, we can use that at the same latency as of just two integer insns
(you also get a load immediate of 1, and sometimes one of 0 as well,
but those are not in the critical path: they don't depend on any other
instruction).

There are a few patterns that already are implemented with just two
instructions; so don't use isel in that case (I still need to check
all lt/gt/ltu/gtu/le/leu/ge/geu patterns with all SI/DI combinations,
one or two might be better without isel).

This introduces a new GPR2 mode iterator, for those patterns that use
two independent integer modes.

* config/rs6000/rs6000.md (GPR2): New mode_iterator.
("cstore<mode>4"): Don't always expand with rs6000_emit_int_cmove for
eq and ne if TARGET_ISEL.
(cmp): New code_iterator.
(UNS, UNSU_, UNSIK): New code_attrs.
(<code><GPR:mode><GPR2:mode>2_isel): New define_insn_and_split.
("eq<mode>3"): New define_expand, rename the define_insn_and_split
to...
("eq<mode>3"): ... this.
("ne<mode>3"): New define_expand, rename the define_insn_and_split
to...
("ne<mode>3"): ... this.

From-SVN: r254508

gcc/ChangeLog
gcc/config/rs6000/rs6000.md

index 29c3349caec38a9c6f6cb41b4fa260fa87424de4..9c9f0ef8bb980a386d1c346b412130715ac2c8e9 100644 (file)
@@ -1,3 +1,18 @@
+2017-11-07  Segher Boessenkool  <segher@kernel.crashing.org>
+
+       * config/rs6000/rs6000.md (GPR2): New mode_iterator.
+       ("cstore<mode>4"): Don't always expand with rs6000_emit_int_cmove for
+       eq and ne if TARGET_ISEL.
+       (cmp): New code_iterator.
+       (UNS, UNSU_, UNSIK): New code_attrs.
+       (<code><GPR:mode><GPR2:mode>2_isel): New define_insn_and_split.
+       ("eq<mode>3"): New define_expand, rename the define_insn_and_split
+       to...
+       ("eq<mode>3"): ... this.
+       ("ne<mode>3"): New define_expand, rename the define_insn_and_split
+       to...
+       ("ne<mode>3"): ... this.
+
 2017-11-07  Julia Koval  <julia.koval@intel.com>
 
        PR target/82812
index ed5ff397e074c2f8df00bc47941f310e7b25e158..b800276692dbf8ae14b6d1fe2b1dfb689ddd3d8a 100644 (file)
 ; of whole values in GPRs.
 (define_mode_iterator GPR [SI (DI "TARGET_POWERPC64")])
 
+; And again, for patterns that need two (potentially) different integer modes.
+(define_mode_iterator GPR2 [SI (DI "TARGET_POWERPC64")])
+
 ; Any supported integer mode.
 (define_mode_iterator INT [QI HI SI DI TI PTI])
 
    (clobber (match_operand:GPR 0 "gpc_reg_operand"))]
   ""
 {
-  /* Use ISEL if the user asked for it.  */
-  if (TARGET_ISEL)
-    rs6000_emit_int_cmove (operands[0], operands[1], const1_rtx, const0_rtx);
-
   /* Expanding EQ and NE directly to some machine instructions does not help
      but does hurt combine.  So don't.  */
-  else if (GET_CODE (operands[1]) == EQ)
+  if (GET_CODE (operands[1]) == EQ)
     emit_insn (gen_eq<mode>3 (operands[0], operands[2], operands[3]));
   else if (<MODE>mode == Pmode
           && GET_CODE (operands[1]) == NE)
       emit_insn (gen_xor<mode>3 (operands[0], tmp, const1_rtx));
     }
 
-  /* Expanding the unsigned comparisons however helps a lot: all the neg_ltu
+  /* If ISEL is fast, expand to it.  */
+  else if (TARGET_ISEL)
+    rs6000_emit_int_cmove (operands[0], operands[1], const1_rtx, const0_rtx);
+
+  /* Expanding the unsigned comparisons helps a lot: all the neg_ltu
      etc. combinations magically work out just right.  */
   else if (<MODE>mode == Pmode
           && unsigned_comparison_operator (operands[1], VOIDmode))
   "")
 
 
+(define_code_iterator cmp [eq ne lt ltu gt gtu le leu ge geu])
+(define_code_attr UNS [(eq "CC")
+                      (ne "CC")
+                      (lt "CC") (ltu "CCUNS")
+                      (gt "CC") (gtu "CCUNS")
+                      (le "CC") (leu "CCUNS")
+                      (ge "CC") (geu "CCUNS")])
+(define_code_attr UNSu_ [(eq "")
+                        (ne "")
+                        (lt "") (ltu "u_")
+                        (gt "") (gtu "u_")
+                        (le "") (leu "u_")
+                        (ge "") (geu "u_")])
+(define_code_attr UNSIK [(eq "I")
+                        (ne "I")
+                        (lt "I") (ltu "K")
+                        (gt "I") (gtu "K")
+                        (le "I") (leu "K")
+                        (ge "I") (geu "K")])
+
+(define_insn_and_split "<code><GPR:mode><GPR2:mode>2_isel"
+  [(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
+       (cmp:GPR (match_operand:GPR2 1 "gpc_reg_operand" "r")
+                (match_operand:GPR2 2 "reg_or_<cmp:UNSu_>short_operand" "r<cmp:UNSIK>")))
+   (clobber (match_scratch:GPR 3 "=r"))
+   (clobber (match_scratch:GPR 4 "=r"))
+   (clobber (match_scratch:<UNS> 5 "=y"))]
+  "TARGET_ISEL
+   && !(<CODE> == EQ && operands[2] == const0_rtx)
+   && !(<CODE> == NE && operands[2] == const0_rtx
+       && <GPR:MODE>mode == Pmode && <GPR2:MODE>mode == Pmode)"
+  "#"
+  "&& 1"
+  [(pc)]
+{
+  if (<CODE> == NE || <CODE> == LE || <CODE> == GE
+      || <CODE> == LEU || <CODE> == GEU)
+    operands[3] = const0_rtx;
+  else
+    {
+      if (GET_CODE (operands[3]) == SCRATCH)
+       operands[3] = gen_reg_rtx (<GPR:MODE>mode);
+      emit_move_insn (operands[3], const0_rtx);
+    }
+
+  if (GET_CODE (operands[4]) == SCRATCH)
+    operands[4] = gen_reg_rtx (<GPR:MODE>mode);
+  emit_move_insn (operands[4], const1_rtx);
+
+  if (GET_CODE (operands[5]) == SCRATCH)
+    operands[5] = gen_reg_rtx (<UNS>mode);
+
+  rtx c1 = gen_rtx_COMPARE (<UNS>mode, operands[1], operands[2]);
+  emit_insn (gen_rtx_SET (operands[5], c1));
+
+  rtx c2 = gen_rtx_fmt_ee (<CODE>, <GPR:MODE>mode, operands[5], const0_rtx);
+  rtx x = gen_rtx_IF_THEN_ELSE (<GPR:MODE>mode, c2, operands[4], operands[3]);
+  emit_move_insn (operands[0], x);
+
+  DONE;
+}
+  [(set (attr "cost")
+       (if_then_else (match_test "<CODE> == NE || <CODE> == LE || <CODE> == GE
+                                  || <CODE> == LEU || <CODE> == GEU")
+                     (const_string "9")
+                     (const_string "10")))])
+
 (define_mode_attr scc_eq_op2 [(SI "rKLI")
                              (DI "rKJI")])
 
-(define_insn_and_split "eq<mode>3"
+(define_expand "eq<mode>3"
+  [(parallel [
+     (set (match_operand:GPR 0 "gpc_reg_operand" "=r")
+         (eq:GPR (match_operand:GPR 1 "gpc_reg_operand" "r")
+                 (match_operand:GPR 2 "scc_eq_operand" "<scc_eq_op2>")))
+     (clobber (match_scratch:GPR 3 "=r"))
+     (clobber (match_scratch:GPR 4 "=r"))])]
+  ""
+{
+  if (TARGET_ISEL && operands[2] != const0_rtx)
+    {
+      emit_insn (gen_eq<mode><mode>2_isel (operands[0], operands[1],
+                                          operands[2]));
+      DONE;
+    }
+})
+
+(define_insn_and_split "*eq<mode>3"
   [(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
        (eq:GPR (match_operand:GPR 1 "gpc_reg_operand" "r")
                (match_operand:GPR 2 "scc_eq_operand" "<scc_eq_op2>")))
    (clobber (match_scratch:GPR 3 "=r"))
    (clobber (match_scratch:GPR 4 "=r"))]
-  ""
+  "!(TARGET_ISEL && operands[2] != const0_rtx)"
   "#"
-  ""
+  "&& 1"
   [(set (match_dup 4)
        (clz:GPR (match_dup 3)))
    (set (match_dup 0)
                      (const_string "8")
                      (const_string "12")))])
 
-(define_insn_and_split "ne<mode>3"
+(define_expand "ne<mode>3"
+  [(parallel [
+     (set (match_operand:P 0 "gpc_reg_operand" "=r")
+         (ne:P (match_operand:P 1 "gpc_reg_operand" "r")
+               (match_operand:P 2 "scc_eq_operand" "<scc_eq_op2>")))
+     (clobber (match_scratch:P 3 "=r"))
+     (clobber (match_scratch:P 4 "=r"))
+     (clobber (reg:P CA_REGNO))])]
+  ""
+{
+  if (TARGET_ISEL && operands[2] != const0_rtx)
+    {
+      emit_insn (gen_ne<mode><mode>2_isel (operands[0], operands[1],
+                                          operands[2]));
+      DONE;
+    }
+})
+
+(define_insn_and_split "*ne<mode>3"
   [(set (match_operand:P 0 "gpc_reg_operand" "=r")
        (ne:P (match_operand:P 1 "gpc_reg_operand" "r")
              (match_operand:P 2 "scc_eq_operand" "<scc_eq_op2>")))
    (clobber (match_scratch:P 3 "=r"))
    (clobber (match_scratch:P 4 "=r"))
    (clobber (reg:P CA_REGNO))]
-  "!TARGET_ISEL"
+  "!(TARGET_ISEL && operands[2] != const0_rtx)"
   "#"
-  ""
+  "&& 1"
   [(parallel [(set (match_dup 4)
                   (plus:P (match_dup 3)
                           (const_int -1)))
    (clobber (match_scratch:SI 3 "=r"))
    (clobber (match_scratch:SI 4 "=r"))
    (clobber (match_scratch:EXTSI 5 "=r"))]
-  ""
+  "!TARGET_ISEL"
   "#"
-  ""
+  "&& 1"
   [(set (match_dup 4)
        (clz:SI (match_dup 3)))
    (set (match_dup 5)