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.

It's currently running final testing on power7 powerpc64-linux
{-m32,-m64}, and on power8 and power9, powerpc64le-linux.  I hope
to commit it later today.


Segher


2017-11-07  Segher Boessenkool  <seg...@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.

---
 gcc/config/rs6000/rs6000.md | 133 +++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 119 insertions(+), 14 deletions(-)

diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index ed5ff39..b800276 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -323,6 +323,9 @@ (define_attr "cell_micro" "not,conditional,always"
 ; 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])
 
@@ -11780,13 +11783,9 @@ (define_expand "cstore<mode>4"
    (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)
@@ -11798,7 +11797,11 @@ (define_expand "cstore<mode>4"
       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))
@@ -12280,18 +12283,102 @@ (define_split
   "")
 
 
+(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)
@@ -12311,16 +12398,34 @@ (define_insn_and_split "eq<mode>3"
                      (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)))
@@ -12573,9 +12678,9 @@ (define_insn_and_split "*nesi3_ext<mode>"
    (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)
-- 
1.8.3.1

Reply via email to