> I agree with Vlad that we're better off with Andreas' patch than without, 
> since
> computing addresses is going to be 99% of what reload/LRA needs to do.
> 
> I also agree with Eric that some better commentary would be nice.

Ok. I've applied the following patch.

Bye,

-Andreas-

2014-03-24  Andreas Krebbel  <andreas.kreb...@de.ibm.com>

        PR rtl-optimization/60501
        * optabs.def (addptr3_optab): New optab.
        * optabs.c (gen_addptr3_insn, have_addptr3_insn): New function.
        * doc/md.texi ("addptrm3"): Document new RTL standard expander.
        * expr.h (gen_addptr3_insn, have_addptr3_insn): Add prototypes.

        * lra.c (emit_add3_insn): Use the addptr pattern if available.

        * config/s390/s390.md ("addptrdi3", "addptrsi3"): New expanders.

diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md
index 76902b5..7d9d1ad 100644
--- a/gcc/config/s390/s390.md
+++ b/gcc/config/s390/s390.md
@@ -5034,6 +5034,57 @@
   [(set_attr "op_type"  "<RRer>,RXE")
    (set_attr "type"     "fsimp<mode>")])
 
+;
+; Pointer add instruction patterns
+;
+
+; This will match "*la_64"
+(define_expand "addptrdi3"
+  [(set (match_operand:DI 0 "register_operand" "")
+        (plus:DI (match_operand:DI 1 "register_operand" "")
+                (match_operand:DI 2 "nonmemory_operand" "")))]
+  "TARGET_64BIT"
+{
+  HOST_WIDE_INT c = INTVAL (operands[2]);
+
+  if (GET_CODE (operands[2]) == CONST_INT)
+    {
+      if (!CONST_OK_FOR_CONSTRAINT_P (c, 'K', "K")
+         && !CONST_OK_FOR_CONSTRAINT_P (c, 'O', "Os"))
+        {
+         operands[2] = force_const_mem (DImode, operands[2]);
+         operands[2] = force_reg (DImode, operands[2]);
+        }
+      else if (!DISP_IN_RANGE (INTVAL (operands[2])))
+        operands[2] = force_reg (DImode, operands[2]);
+    }
+})
+
+; For 31 bit we have to prevent the generated pattern from matching
+; normal ADDs since la only does a 31 bit add.  This is supposed to
+; match "force_la_31".
+(define_expand "addptrsi3"
+  [(parallel
+    [(set (match_operand:SI 0 "register_operand" "")
+         (plus:SI (match_operand:SI 1 "register_operand" "")
+                  (match_operand:SI 2 "nonmemory_operand" "")))
+                  (use (const_int 0))])]
+  "!TARGET_64BIT"
+{
+  HOST_WIDE_INT c = INTVAL (operands[2]);
+
+  if (GET_CODE (operands[2]) == CONST_INT)
+    {
+      if (!CONST_OK_FOR_CONSTRAINT_P (c, 'K', "K")
+         && !CONST_OK_FOR_CONSTRAINT_P (c, 'O', "Os"))
+        {
+         operands[2] = force_const_mem (SImode, operands[2]);
+         operands[2] = force_reg (SImode, operands[2]);
+        }
+      else if (!DISP_IN_RANGE (INTVAL (operands[2])))
+        operands[2] = force_reg (SImode, operands[2]);
+    }
+})
 
 ;;
 ;;- Subtract instructions.
diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi
index 746acc2..85fd4b9 100644
--- a/gcc/doc/md.texi
+++ b/gcc/doc/md.texi
@@ -4720,6 +4720,17 @@ Add operand 2 and operand 1, storing the result in 
operand 0.  All operands
 must have mode @var{m}.  This can be used even on two-address machines, by
 means of constraints requiring operands 1 and 0 to be the same location.
 
+@cindex @code{addptr@var{m}3} instruction pattern
+@item @samp{addptr@var{m}3}
+Like @code{add@var{m}3} but is guaranteed to only be used for address
+calculations.  The expanded code is not allowed to clobber the
+condition code.  It only needs to be defined if @code{add@var{m}3}
+sets the condition code.  If adds used for address calculations and
+normal adds are not compatible it is required to expand a distinct
+pattern (e.g. using an unspec).  The pattern is used by LRA to emit
+address calculations.  @code{add@var{m}3} is used if
+@code{addptr@var{m}3} is not defined.
+
 @cindex @code{ssadd@var{m}3} instruction pattern
 @cindex @code{usadd@var{m}3} instruction pattern
 @cindex @code{sub@var{m}3} instruction pattern
diff --git a/gcc/expr.h b/gcc/expr.h
index 5111f06..524da67 100644
--- a/gcc/expr.h
+++ b/gcc/expr.h
@@ -180,10 +180,12 @@ extern void emit_libcall_block (rtx, rtx, rtx, rtx);
    Likewise for subtraction and for just copying.  */
 extern rtx gen_add2_insn (rtx, rtx);
 extern rtx gen_add3_insn (rtx, rtx, rtx);
+extern rtx gen_addptr3_insn (rtx, rtx, rtx);
 extern rtx gen_sub2_insn (rtx, rtx);
 extern rtx gen_sub3_insn (rtx, rtx, rtx);
 extern rtx gen_move_insn (rtx, rtx);
 extern int have_add2_insn (rtx, rtx);
+extern int have_addptr3_insn (rtx, rtx, rtx);
 extern int have_sub2_insn (rtx, rtx);
 
 /* Emit a pair of rtl insns to compare two rtx's and to jump
diff --git a/gcc/lra.c b/gcc/lra.c
index 77074e2..c1b92d8 100644
--- a/gcc/lra.c
+++ b/gcc/lra.c
@@ -254,6 +254,19 @@ emit_add3_insn (rtx x, rtx y, rtx z)
   rtx insn, last;
 
   last = get_last_insn ();
+
+  if (have_addptr3_insn (x, y, z))
+    {
+      insn = gen_addptr3_insn (x, y, z);
+
+      /* If the target provides an "addptr" pattern it hopefully does
+        for a reason.  So falling back to the normal add would be
+        a bug.  */
+      lra_assert (insn != NULL_RTX);
+      emit_insn (insn);
+      return insn;
+    }
+
   insn = emit_insn (gen_rtx_SET (VOIDmode, x,
                                 gen_rtx_PLUS (GET_MODE (y), y, z)));
   if (recog_memoized (insn) < 0)
diff --git a/gcc/optabs.c b/gcc/optabs.c
index cec25a4..c4540f8 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -4755,6 +4755,43 @@ have_add2_insn (rtx x, rtx y)
   return 1;
 }
 
+/* Generate and return an insn body to add Y to X.  */
+
+rtx
+gen_addptr3_insn (rtx x, rtx y, rtx z)
+{
+  enum insn_code icode = optab_handler (addptr3_optab, GET_MODE (x));
+
+  gcc_assert (insn_operand_matches (icode, 0, x));
+  gcc_assert (insn_operand_matches (icode, 1, y));
+  gcc_assert (insn_operand_matches (icode, 2, z));
+
+  return GEN_FCN (icode) (x, y, z);
+}
+
+/* Return true if the target implements an addptr pattern and X, Y,
+   and Z are valid for the pattern predicates.  */
+
+int
+have_addptr3_insn (rtx x, rtx y, rtx z)
+{
+  enum insn_code icode;
+
+  gcc_assert (GET_MODE (x) != VOIDmode);
+
+  icode = optab_handler (addptr3_optab, GET_MODE (x));
+
+  if (icode == CODE_FOR_nothing)
+    return 0;
+
+  if (!insn_operand_matches (icode, 0, x)
+      || !insn_operand_matches (icode, 1, y)
+      || !insn_operand_matches (icode, 2, z))
+    return 0;
+
+  return 1;
+}
+
 /* Generate and return an insn body to subtract Y from X.  */
 
 rtx
diff --git a/gcc/optabs.def b/gcc/optabs.def
index decdaf3..9b89740 100644
--- a/gcc/optabs.def
+++ b/gcc/optabs.def
@@ -191,6 +191,7 @@ OPTAB_D (addv4_optab, "addv$I$a4")
 OPTAB_D (subv4_optab, "subv$I$a4")
 OPTAB_D (mulv4_optab, "mulv$I$a4")
 OPTAB_D (negv3_optab, "negv$I$a3")
+OPTAB_D (addptr3_optab, "addptr$a3")
 
 OPTAB_D (smul_highpart_optab, "smul$a3_highpart")
 OPTAB_D (umul_highpart_optab, "umul$a3_highpart")

Reply via email to