aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog12
-rw-r--r--gcc/config/s390/s390.md51
-rw-r--r--gcc/doc/md.texi11
-rw-r--r--gcc/expr.h2
-rw-r--r--gcc/lra.c13
-rw-r--r--gcc/optabs.c37
-rw-r--r--gcc/optabs.def1
7 files changed, 127 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index e24b5fa..d904fc0 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,15 @@
+2014-03-24 Andreas Krebbel <Andreas.Krebbel@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.
+
2014-03-24 Ulrich Drepper <drepper@gmail.com>
* config/i386/avx512fintrin.h: Define _mm512_set1_ps and
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")