It's the simplify-rtx.c portion of the patch that fixes the i686 regression.

In the PR, Alan raises some good points, but I don't believe that we can address those for gcc6. A new rtl reassoc optimization that takes loop invariance into account will have to wait.

But we do need to take care of the rs6000 ice that results, and that's the bulk of the patch -- allowing CA to be sorted to any register of the plus chain.

Some notes:

ca_operand doesn't work as written, since CA_REGNO is not an available register, and thus doesn't satisfy register_operand.

Is there any particular reason that subf<>3_carry_in_m1 was written with minus rather than plus like all of the other patterns?


Tested on ppc64le-linux.


r~
        * simplify-rtx.c (simplify_plus_minus): If only PLUS of REG,
        rematerialize the canonical chain.

        * config/rs6000/predicates.md (ca_operand): Use match_code.
        (gpc_ca_reg_operand): New.
        * config/rs6000/rs6000.md (add<GPR>3_carry_in): Expand by hand.
        (subf<GPR>3_carry_in): Likewise.
        (*add<GPR>3_carry_in_reg): Rename from *add<GPR>3_carry_in_internal;
        accept CA at any register position, exactly once.
        (*add<GPR>3_carry_in_0): Similarly.
        (*add<GPR>3_carry_in_m1): Similarly.
        (*subf<GPR>3_carry_in_reg): Similarly.
        (*subf<GPR>3_carry_in_0): Rename with leading *.
        (*subf<GPR>3_carry_in_m1): Rename with leading *; use the same
        plus/plus/not form as subf<GPR>3_carry_in_reg.

diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md
index 072291e..98937bd 100644
--- a/gcc/config/rs6000/predicates.md
+++ b/gcc/config/rs6000/predicates.md
@@ -116,7 +116,7 @@
 
 ;; Return 1 if op is the carry register.
 (define_predicate "ca_operand"
-  (match_operand 0 "register_operand")
+  (match_code "reg,subreg")
 {
   if (GET_CODE (op) == SUBREG)
     op = SUBREG_REG (op);
@@ -230,6 +230,10 @@
   return INT_REGNO_P (REGNO (op)) || FP_REGNO_P (REGNO (op));
 })
 
+(define_predicate "gpc_ca_reg_operand"
+  (ior (match_operand 0 "gpc_reg_operand")
+       (match_operand 0 "ca_operand")))
+
 ;; Return 1 if op is a general purpose register.  Unlike gpc_reg_operand, don't
 ;; allow floating point or vector registers.
 (define_predicate "int_reg_operand"
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index 0299a00..b300727 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -1770,50 +1770,65 @@
 (define_expand "add<mode>3_carry_in"
   [(parallel [
      (set (match_operand:GPR 0 "gpc_reg_operand")
-         (plus:GPR (plus:GPR (match_operand:GPR 1 "gpc_reg_operand")
-                             (match_operand:GPR 2 "adde_operand"))
-                   (reg:GPR CA_REGNO)))
+         (plus:GPR
+           (plus:GPR
+             (reg:GPR CA_REGNO)
+              (match_operand:GPR 1 "gpc_reg_operand"))
+           (match_operand:GPR 2 "adde_operand")))
      (clobber (reg:GPR CA_REGNO))])]
   ""
 {
-  if (operands[2] == const0_rtx)
-    {
-      emit_insn (gen_add<mode>3_carry_in_0 (operands[0], operands[1]));
-      DONE;
-    }
-  if (operands[2] == constm1_rtx)
-    {
-      emit_insn (gen_add<mode>3_carry_in_m1 (operands[0], operands[1]));
-      DONE;
-    }
+  rtx ca = gen_rtx_REG (<MODE>mode, CA_REGNO);
+  rtx x, y;
+
+  x = gen_rtx_PLUS (<MODE>mode, ca, operands[1]);
+  if (operands[2] != const0_rtx)
+    x = gen_rtx_PLUS (<MODE>mode, x, operands[2]);
+  x = gen_rtx_SET (operands[0], x);
+  y = gen_rtx_CLOBBER (VOIDmode, ca);
+
+  emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, x, y)));
+  DONE;
 })
 
-(define_insn "*add<mode>3_carry_in_internal"
-  [(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
-       (plus:GPR (plus:GPR (match_operand:GPR 1 "gpc_reg_operand" "r")
-                           (match_operand:GPR 2 "gpc_reg_operand" "r"))
-                 (reg:GPR CA_REGNO)))
+(define_insn "*add<mode>3_carry_in_reg"
+  [(set (match_operand:GPR 0 "gpc_reg_operand" "=r,r,r")
+       (plus:GPR
+         (plus:GPR
+           (match_operand:GPR 1 "gpc_ca_reg_operand" "z,r,r")
+           (match_operand:GPR 2 "gpc_ca_reg_operand" "r,z,r"))
+         (match_operand:GPR 3 "gpc_ca_reg_operand"   "r,r,z")))
    (clobber (reg:GPR CA_REGNO))]
-  ""
-  "adde %0,%1,%2"
+  "ca_operand (operands[1], <MODE>mode)
+   + ca_operand (operands[2], <MODE>mode)
+   + ca_operand (operands[3], <MODE>mode) == 1"
+  "@
+   adde %0,%2,%3
+   adde %0,%1,%3
+   adde %0,%1,%2"
   [(set_attr "type" "add")])
 
-(define_insn "add<mode>3_carry_in_0"
+(define_insn "*add<mode>3_carry_in_0"
   [(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
-       (plus:GPR (match_operand:GPR 1 "gpc_reg_operand" "r")
-                 (reg:GPR CA_REGNO)))
+       (plus:GPR
+         (match_operand:GPR 1 "gpc_ca_reg_operand" "%r")
+         (match_operand:GPR 2 "gpc_ca_reg_operand" "z")))
    (clobber (reg:GPR CA_REGNO))]
-  ""
+  "ca_operand (operands[1], <MODE>mode)
+   + ca_operand (operands[2], <MODE>mode) == 1"
   "addze %0,%1"
   [(set_attr "type" "add")])
 
-(define_insn "add<mode>3_carry_in_m1"
+(define_insn "*add<mode>3_carry_in_m1"
   [(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
-       (plus:GPR (plus:GPR (match_operand:GPR 1 "gpc_reg_operand" "r")
-                           (reg:GPR CA_REGNO))
-                 (const_int -1)))
+       (plus:GPR
+         (plus:GPR
+           (match_operand:GPR 1 "gpc_ca_reg_operand" "%r")
+           (match_operand:GPR 2 "gpc_ca_reg_operand" "z"))
+         (const_int -1)))
    (clobber (reg:GPR CA_REGNO))]
-  ""
+  "ca_operand (operands[1], <MODE>mode)
+   + ca_operand (operands[2], <MODE>mode) == 1"
   "addme %0,%1"
   [(set_attr "type" "add")])
 
@@ -2008,35 +2023,42 @@
 (define_expand "subf<mode>3_carry_in"
   [(parallel [
      (set (match_operand:GPR 0 "gpc_reg_operand")
-         (plus:GPR (plus:GPR (not:GPR (match_operand:GPR 1 "gpc_reg_operand"))
-                             (reg:GPR CA_REGNO))
-                   (match_operand:GPR 2 "adde_operand")))
+         (plus:GPR
+           (plus:GPR
+             (not:GPR (match_operand:GPR 1 "gpc_reg_operand"))
+             (reg:GPR CA_REGNO))
+           (match_operand:GPR 2 "adde_operand")))
      (clobber (reg:GPR CA_REGNO))])]
   ""
 {
-  if (operands[2] == const0_rtx)
-    {
-      emit_insn (gen_subf<mode>3_carry_in_0 (operands[0], operands[1]));
-      DONE;
-    }
-  if (operands[2] == constm1_rtx)
-    {
-      emit_insn (gen_subf<mode>3_carry_in_m1 (operands[0], operands[1]));
-      DONE;
-    }
+  rtx ca = gen_rtx_REG (<MODE>mode, CA_REGNO);
+  rtx x, y;
+
+  x = gen_rtx_NOT (<MODE>mode, operands[1]);
+  x = gen_rtx_PLUS (<MODE>mode, x, ca);
+  if (operands[2] != const0_rtx)
+    x = gen_rtx_PLUS (<MODE>mode, x, operands[2]);
+  x = gen_rtx_SET (operands[0], x);
+  y = gen_rtx_CLOBBER (VOIDmode, ca);
+
+  emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, x, y)));
+  DONE;
 })
 
-(define_insn "*subf<mode>3_carry_in_internal"
+(define_insn "*subf<mode>3_carry_in_reg"
   [(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
-       (plus:GPR (plus:GPR (not:GPR (match_operand:GPR 1 "gpc_reg_operand" 
"r"))
-                           (reg:GPR CA_REGNO))
-                 (match_operand:GPR 2 "gpc_reg_operand" "r")))
+       (plus:GPR
+         (plus:GPR
+           (not:GPR (match_operand:GPR 1 "gpc_reg_operand" "r"))
+           (match_operand:GPR 2 "gpc_ca_reg_operand"       "%r"))
+         (match_operand:GPR 3 "gpc_ca_reg_operand"         "z")))
    (clobber (reg:GPR CA_REGNO))]
-  ""
+  "ca_operand (operands[2], <MODE>mode)
+   + ca_operand (operands[3], <MODE>mode) == 1"
   "subfe %0,%1,%2"
   [(set_attr "type" "add")])
 
-(define_insn "subf<mode>3_carry_in_0"
+(define_insn "*subf<mode>3_carry_in_0"
   [(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
        (plus:GPR (not:GPR (match_operand:GPR 1 "gpc_reg_operand" "r"))
                  (reg:GPR CA_REGNO)))
@@ -2045,11 +2067,13 @@
   "subfze %0,%1"
   [(set_attr "type" "add")])
 
-(define_insn "subf<mode>3_carry_in_m1"
+(define_insn "*subf<mode>3_carry_in_m1"
   [(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
-       (plus:GPR (minus:GPR (reg:GPR CA_REGNO)
-                            (match_operand:GPR 1 "gpc_reg_operand" "r"))
-                 (const_int -2)))
+       (plus:GPR
+         (plus:GPR
+           (not:GPR (match_operand:GPR 1 "gpc_reg_operand" "r"))
+           (reg:GPR CA_REGNO))
+          (const_int -1)))
    (clobber (reg:GPR CA_REGNO))]
   ""
   "subfme %0,%1"
diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c
index 450fa8b..9d55e7b 100644
--- a/gcc/simplify-rtx.c
+++ b/gcc/simplify-rtx.c
@@ -4421,9 +4421,17 @@ simplify_plus_minus (enum rtx_code code, machine_mode 
mode, rtx op0,
       n_ops = i;
     }
 
-  /* If nothing changed, fail.  */
+  /* If nothing changed, check that rematerialization of rtl instructions
+     is still required.  */
   if (!canonicalized)
-    return NULL_RTX;
+    {
+      /* Perform rematerialization if only all operands are registers and
+         all operations are PLUS.  */
+      for (i = 0; i < n_ops; i++)
+       if (ops[i].neg || !REG_P (ops[i].op))
+         return NULL_RTX;
+      goto gen_result;
+    }
 
   /* Create (minus -C X) instead of (neg (const (plus X C))).  */
   if (n_ops == 2
@@ -4465,6 +4473,7 @@ simplify_plus_minus (enum rtx_code code, machine_mode 
mode, rtx op0,
     }
 
   /* Now make the result by performing the requested operations.  */
+ gen_result:
   result = ops[0].op;
   for (i = 1; i < n_ops; i++)
     result = gen_rtx_fmt_ee (ops[i].neg ? MINUS : PLUS,

Reply via email to