aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Meissner <meissner@linux.ibm.com>2018-12-06 22:38:48 +0000
committerMichael Meissner <meissner@linux.ibm.com>2018-12-06 22:38:48 +0000
commit580bea528adc686cca50093b5b955bc80ea96f01 (patch)
treeeac655bae83ebe08a2c6f2fa18773602ba755b8a
parent49bdbef0b502c3728ac04ac9e507e5061c736cc6 (diff)
checkpoint new xform passibm/ltc168854
git-svn-id: https://gcc.gnu.org/svn/gcc/branches/ibm/ltc168854@266872 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog.meissner43
-rw-r--r--gcc/config.gcc4
-rw-r--r--gcc/config/rs6000/predicates.md16
-rw-r--r--gcc/config/rs6000/rs6000-passes.def1
-rw-r--r--gcc/config/rs6000/rs6000-protos.h1
-rw-r--r--gcc/config/rs6000/rs6000-xform.c425
-rw-r--r--gcc/config/rs6000/rs6000.c8
-rw-r--r--gcc/config/rs6000/rs6000.md64
-rw-r--r--gcc/config/rs6000/rs6000.opt8
-rw-r--r--gcc/config/rs6000/t-rs60004
10 files changed, 534 insertions, 40 deletions
diff --git a/gcc/ChangeLog.meissner b/gcc/ChangeLog.meissner
index a7315b29c82..d05d9d145f1 100644
--- a/gcc/ChangeLog.meissner
+++ b/gcc/ChangeLog.meissner
@@ -1,12 +1,39 @@
-2018-11-30 Michael Meissner <meissner@linux.ibm.com>
+2018-12-06 Michael Meissner <meissner@linux.ibm.com>
- * config/rs6000/rs6000.c (rs6000_rtx_costs): The new HACK insn has
- cost 1.
- (rs6000_force_indexed_or_indirect_mem): Push constant offset to a
- hack insn that makes the offsets optimizable.
- * config/rs6000/rs6000.md (UNSPEC_HACK): New unspec.
- (hack<mode>2): New insn to allow integer constants for offsets to
- be optimized.
+ * config.gcc (powerpc*-*-*, rs6000*-*-*): Add rs6000-xform.o.
+ * config/rs6000/predicates.md (reg_or_indexed_operand): Before
+ register allocation, allow any memory operation unless we are not
+ running the optimize xform pass.
+ * config/rs6000/rs6000-passes.def: Add xform optimization.
+ * config/rs6000/rs6000-protos.h (make_pass_optimize_xform): Add
+ declaration.
+ * config/rs6000/rs6000-xform.c: New target pass to optimize x-form
+ addresses.
+ * config/rs6000/rs6000.c (rs6000_opt_masks): Add -moptimize-xform.
+ (rs6000_force_indexed_or_indirect_mem): Only push signed 16-bit
+ constants, and set REG_EQUAL note.
+ * config/rs6000/rs6000.md (xform_memory attribute): New
+ attribute.
+ (lfiwax): Set the xform_memory attribute.
+ (floatsi<mode>2_lfiwax): If the optimize xform pass is enabled,
+ don't call rs6000_force_indexed_or_indirect_mem. Set the
+ xform_memory attribute.
+ (floatsi<mode>2_lfiwax_mem): Set the xform_memory attribute.
+ (lfiwzx): Likewise.
+ (floatunssi<mode>2_lfiwzx): If the optimize xform pass is enabled,
+ don't call rs6000_force_indexed_or_indirect_mem. Set the
+ xform_memory attribute.
+ (floatunssi<mode>2_lfiwzx_mem): Set the xform_memory attribute.
+ (floatuns<QHI:mode><FP_ISA3:mode>2_internal): Likewise.
+ (fix_trunc<mode>si2_stfiwx): If the optimize xform pass is
+ enabled, don't call rs6000_force_indexed_or_indirect_mem. Set the
+ xform_memory attribute.
+ (fix<uns>_trunc<SFDF:mode><QHSI:mode>2_mem): Set the xform_memory
+ attribute.
+ (float_<mode>si2_hw): Set the xform_memory attribute.
+ (floatuns_<mode>si2_hw): Set the xform_memory attribute.
+ * config/rs6000/rs6000.opt (-moptimize-xform): New debug switch.
+ * config/rs6000/t-rs6000: Build rs6000-xform.o.
2018-11-30 Michael Meissner <meissner@linux.ibm.com>
diff --git a/gcc/config.gcc b/gcc/config.gcc
index f6162ed496e..33d38c3f28b 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -499,7 +499,7 @@ powerpc*-*-*spe*)
;;
powerpc*-*-*)
cpu_type=rs6000
- extra_objs="rs6000-string.o rs6000-p8swap.o"
+ extra_objs="rs6000-string.o rs6000-p8swap.o rs6000-xform.o"
extra_headers="ppc-asm.h altivec.h htmintrin.h htmxlintrin.h"
extra_headers="${extra_headers} bmi2intrin.h bmiintrin.h"
extra_headers="${extra_headers} xmmintrin.h mm_malloc.h emmintrin.h"
@@ -521,7 +521,7 @@ riscv*)
;;
rs6000*-*-*)
extra_options="${extra_options} g.opt fused-madd.opt rs6000/rs6000-tables.opt"
- extra_objs="rs6000-string.o rs6000-p8swap.o"
+ extra_objs="rs6000-string.o rs6000-p8swap.o rs6000-xform.o"
;;
sparc*-*-*)
cpu_type=sparc
diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md
index 5589ea19519..312d620ba85 100644
--- a/gcc/config/rs6000/predicates.md
+++ b/gcc/config/rs6000/predicates.md
@@ -801,16 +801,24 @@
})
;; Like indexed_or_indirect_operand, but also allow a GPR register if direct
-;; moves are supported.
+;; moves are supported. Before register allocation allow any memory operation.
+;; During and after register allocation only allow strict indexed or indirect
+;; addressing. If we are disabling the xform optimization pass, also require
+;; reg+reg addressing.
(define_predicate "reg_or_indexed_operand"
(match_code "mem,reg,subreg")
{
if (MEM_P (op))
- return indexed_or_indirect_operand (op, mode);
+ {
+ if (reload_in_progress || reload_completed || !TARGET_OPT_XFORM)
+ return indexed_or_indirect_operand (op, mode);
+ else
+ return memory_operand (op, mode);
+ }
else if (TARGET_DIRECT_MOVE)
return register_operand (op, mode);
- return
- 0;
+
+ return 0;
})
;; Return 1 if the operand is an indexed or indirect memory operand with an
diff --git a/gcc/config/rs6000/rs6000-passes.def b/gcc/config/rs6000/rs6000-passes.def
index a1c6dde8428..82784c96193 100644
--- a/gcc/config/rs6000/rs6000-passes.def
+++ b/gcc/config/rs6000/rs6000-passes.def
@@ -25,3 +25,4 @@ along with GCC; see the file COPYING3. If not see
*/
INSERT_PASS_BEFORE (pass_cse, 1, pass_analyze_swaps);
+ INSERT_PASS_BEFORE (pass_ira, 1, pass_optimize_xform);
diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h
index 6e58ce78d08..9f1f06eb08f 100644
--- a/gcc/config/rs6000/rs6000-protos.h
+++ b/gcc/config/rs6000/rs6000-protos.h
@@ -241,6 +241,7 @@ namespace gcc { class context; }
class rtl_opt_pass;
extern rtl_opt_pass *make_pass_analyze_swaps (gcc::context *);
+extern rtl_opt_pass *make_pass_optimize_xform (gcc::context *);
extern bool rs6000_sum_of_two_registers_p (const_rtx expr);
extern bool rs6000_quadword_masked_address_p (const_rtx exp);
extern rtx rs6000_gen_lvx (enum machine_mode, rtx, rtx);
diff --git a/gcc/config/rs6000/rs6000-xform.c b/gcc/config/rs6000/rs6000-xform.c
new file mode 100644
index 00000000000..0f9edb3d7cf
--- /dev/null
+++ b/gcc/config/rs6000/rs6000-xform.c
@@ -0,0 +1,425 @@
+/* Subroutines used to improve addressing in PowerPC.
+ Copyright (C) 2018 Free Software Foundation, Inc.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GCC is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+/* This pass optimizes x-form addresses (register or register+register) for the
+ instructions that require x-form loads or stores. The idea is do the x-form
+ addressing before the register allocation does it, changing:
+
+ (SET (REG reg) (MEM (PLUS (base, constant))))
+
+ to:
+
+ (SET (REG tmp) (CONST_INT constant))
+ (SET (REG reg) (MEM (PLUS (base, tmp))))
+
+ We optimize using the same constants in the same basic block. */
+
+#define IN_TARGET_CODE 1
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "rtl.h"
+#include "tree.h"
+#include "memmodel.h"
+#include "df.h"
+#include "tm_p.h"
+#include "ira.h"
+#include "print-tree.h"
+#include "varasm.h"
+#include "explow.h"
+#include "expr.h"
+#include "output.h"
+#include "tree-pass.h"
+#include "rtx-vector-builder.h"
+#include "print-rtl.h"
+#include "expmed.h"
+#include "optabs.h"
+#include "insn-attr.h"
+
+// Statistics
+static unsigned long num_modifications = 0;
+static unsigned long constants_saved = 0;
+static unsigned long constants_reused = 0;
+static unsigned long constants_moved = 0;
+
+// Structure to remember a few constants that have been stored in the basic
+// block. We want to remember a few, but we don't want to remember too many
+// and cause extra spills.
+struct prev_consts {
+ HOST_WIDE_INT value; // constant value saved
+ rtx reg; // register it was saved in
+ rtx_insn *insn; // insn that set the value
+};
+
+#define SAVE_CONSTS 4 // remember the last 4 constants
+
+// Information needed for optimizing non x-form addresses
+class xform_opts {
+ private:
+ struct prev_consts consts[SAVE_CONSTS]; // constants that we save
+ unsigned int num_consts; // # constants saved
+
+ public:
+ // Clear any saved settings to prevent registers being saved across a call
+ void clear (void)
+ {
+ num_consts = 0;
+ memset (consts, '\0', sizeof (consts));
+ }
+
+ xform_opts ()
+ {
+ clear ();
+ }
+
+ ~xform_opts ()
+ {
+ }
+
+ // Fix a memory address, return either the new address if the address was not
+ // x-form or NULL_RTX if the address is valid.
+ rtx fix_memory (rtx, rtx_insn *);
+
+ // Remember a constant's register
+ void remember_constant (HOST_WIDE_INT, rtx, rtx_insn *);
+
+ // Return a register that holds a constant, if need be, allocating a new
+ // register
+ rtx constant_to_reg (HOST_WIDE_INT, rtx_insn *);
+};
+
+
+// Remember a constant's register with the VALUE that is stored in REG in the
+// insn INSN.
+void
+xform_opts::remember_constant (HOST_WIDE_INT value,
+ rtx reg,
+ rtx_insn * insn)
+{
+ // See if we already have the constant stored. If so, just update the
+ // register and insn.
+ for (size_t i = 0; i < num_consts; i++)
+ {
+ if (consts[i].value == value)
+ {
+ consts[i].reg = reg;
+ consts[i].insn = insn;
+ constants_reused++;
+ return;
+ }
+ }
+
+ constants_saved++;
+
+ // New constant, see if we have an empty slot.
+ if (num_consts < SAVE_CONSTS)
+ {
+ consts[num_consts].value = value;
+ consts[num_consts].reg = reg;
+ consts[num_consts].insn = insn;
+ num_consts++;
+ return;
+ }
+
+ // No empty slots, move all of the constants down and create a new constant.
+ for (size_t i = 0; i < SAVE_CONSTS-1; i++)
+ consts[i] = consts[i+1];
+
+ constants_moved++;
+ num_consts = SAVE_CONSTS-1;
+ consts[num_consts].value = value;
+ consts[num_consts].reg = reg;
+ consts[num_consts].insn = insn;
+ return;
+}
+
+
+ // Return a register that holds a constant VALUE, if need be, allocating a new
+ // register. INSN is the current instruction.
+rtx
+xform_opts::constant_to_reg (HOST_WIDE_INT value, rtx_insn *insn)
+{
+ // Have we seen this constant already? If so, use it.
+ for (size_t i = 0; i < num_consts; i++)
+ {
+ if (consts[i].value == value)
+ {
+ gcc_assert (consts[i].reg);
+ gcc_assert (consts[i].insn);
+ rtx_insn *next_insn = NEXT_INSN (consts[i].insn);
+
+ if (!next_insn || !reg_set_between_p (consts[i].reg, next_insn, insn))
+ {
+ constants_reused++;
+ return consts[i].reg;
+ }
+ }
+ }
+
+ // Allocate a new constant
+ rtx new_reg = gen_reg_rtx (Pmode);
+ rtx value_rtx = GEN_INT (value);
+ rtx new_pattern = gen_rtx_SET (new_reg, value_rtx);
+ rtx_insn *new_insn = emit_insn_before (new_pattern, insn);
+ set_block_for_insn (new_insn, BLOCK_FOR_INSN (insn));
+ set_unique_reg_note (new_insn, REG_EQUAL, value_rtx);
+ df_insn_rescan (new_insn);
+ remember_constant (value, new_reg, new_insn);
+ return new_reg;
+}
+
+
+// Fix a memory address, return either the new address if the address was not
+// x-form or NULL_RTX if the address is valid.
+rtx
+xform_opts::fix_memory (rtx mem, rtx_insn *insn)
+{
+ machine_mode mode = GET_MODE (mem);
+ rtx addr = XEXP (mem, 0);
+
+ if (indexed_or_indirect_address (addr, Pmode))
+ return NULL_RTX;
+
+ if (GET_CODE (addr) == PRE_INC || GET_CODE (addr) == PRE_DEC)
+ {
+ rtx reg = XEXP (addr, 0);
+ HOST_WIDE_INT size = GET_MODE_SIZE (mode);
+ rtx size_rtx = GEN_INT ((GET_CODE (addr) == PRE_DEC) ? -size : size);
+ gcc_assert (REG_P (reg));
+
+ rtx new_pattern = gen_add3_insn (reg, reg, size_rtx);
+ rtx_insn *new_insn = emit_insn_before (new_pattern, insn);
+ set_block_for_insn (new_insn, BLOCK_FOR_INSN (insn));
+ df_insn_rescan (new_insn);
+ addr = reg;
+ }
+ else if (GET_CODE (addr) == PRE_MODIFY)
+ {
+ rtx reg = XEXP (addr, 0);
+ rtx expr = XEXP (addr, 1);
+ gcc_assert (REG_P (reg));
+ gcc_assert (GET_CODE (expr) == PLUS);
+
+ rtx new_pattern = gen_add3_insn (reg, XEXP (expr, 0), XEXP (expr, 1));
+ rtx_insn *new_insn = emit_insn_before (new_pattern, insn);
+ set_block_for_insn (new_insn, BLOCK_FOR_INSN (insn));
+ df_insn_rescan (new_insn);
+ addr = reg;
+ }
+
+ /* If the address is of the form reg+constant, push the constant to a new
+ register, and create an indexed form instead of using an indirect form. */
+ if (GET_CODE (addr) == PLUS
+ && (REG_P (XEXP (addr, 0)) || SUBREG_P (XEXP (addr, 0)))
+ && CONSTANT_P (XEXP (addr, 1)))
+ {
+ rtx addr0 = XEXP (addr, 0);
+ rtx addr1 = constant_to_reg (INTVAL (XEXP (addr, 1)), insn);
+
+ addr = gen_rtx_PLUS (Pmode, addr0, addr1);
+ return replace_equiv_address (mem, addr);
+ }
+
+ /* Otherwise, just let LRA/reload create an address. */
+ return NULL_RTX;
+}
+
+
+// Main entry point for this pass.
+unsigned int
+rs6000_optimize_xform (function *fun)
+{
+ xform_opts info;
+ basic_block bb;
+ rtx_insn *insn, *curr_insn = 0;
+
+ num_modifications = 0;
+ constants_saved = 0;
+ constants_reused = 0;
+
+ // Dataflow analysis for use-def chains.
+ df_set_flags (DF_RD_PRUNE_DEAD_DEFS);
+ df_chain_add_problem (DF_DU_CHAIN | DF_UD_CHAIN);
+ df_analyze ();
+ df_set_flags (DF_DEFER_INSN_RESCAN);
+
+ // Walk the insns to look for the memory addresses that need to be x-form.
+ FOR_ALL_BB_FN (bb, fun)
+ {
+ rtx set;
+
+ info.clear ();
+ FOR_BB_INSNS_SAFE (bb, insn, curr_insn)
+ {
+ if (NONJUMP_INSN_P (insn)
+ && (set = single_set (insn)) != NULL_RTX)
+ {
+ rtx dest = SET_DEST (set);
+ rtx src = SET_SRC (set);
+
+ if (get_attr_xform_memory (insn) == XFORM_MEMORY_YES)
+ {
+ if (MEM_P (dest))
+ {
+ rtx new_dest = info.fix_memory (dest, insn);
+ if (new_dest)
+ {
+ SET_DEST (set) = new_dest;
+ num_modifications++;
+ df_insn_rescan (insn);
+ }
+ }
+
+ else if (MEM_P (src))
+ {
+ rtx new_src = info.fix_memory (src, insn);
+ if (new_src)
+ {
+ SET_SRC (set) = new_src;
+ num_modifications++;
+ df_insn_rescan (insn);
+ }
+ }
+
+ else if (GET_CODE (src) == SIGN_EXTEND
+ || GET_CODE (src) == ZERO_EXTEND
+ || GET_CODE (src) == BSWAP
+ || GET_CODE (src) == FIX
+ || GET_CODE (src) == UNSIGNED_FIX)
+ {
+ rtx arg = XEXP (src, 0);
+ if (MEM_P (arg))
+ {
+ rtx new_mem = info.fix_memory (arg, insn);
+ if (new_mem)
+ {
+ XEXP (set, 0) = new_mem;
+ num_modifications++;
+ df_insn_rescan (insn);
+ }
+ }
+
+ else if ((GET_CODE (arg) == SIGN_EXTEND
+ || GET_CODE (arg) == ZERO_EXTEND)
+ && MEM_P (XEXP (arg, 0)))
+ {
+ rtx new_mem = info.fix_memory (XEXP (arg, 0), insn);
+ if (new_mem)
+ {
+ XEXP (arg, 0) = new_mem;
+ num_modifications++;
+ df_insn_rescan (insn);
+ }
+ }
+ }
+
+ else if (GET_CODE (src) == UNSPEC)
+ {
+ for (int i = 0; i < XVECLEN (src, 0); i++)
+ {
+ if (MEM_P (XVECEXP (src, 0, i)))
+ {
+ rtx new_mem = info.fix_memory (XVECEXP (src, 0, i), insn);
+ if (new_mem)
+ {
+ XVECEXP (src, 0, 0) = new_mem;
+ num_modifications++;
+ df_insn_rescan (insn);
+ }
+ }
+ }
+ }
+ }
+
+ // If this is a simple set of a constant integer, remember the
+ // integer.
+ else if (REG_P (dest) && CONST_INT_P (src))
+ info.remember_constant (INTVAL (src), dest, insn);
+ }
+ else if (CALL_P (insn))
+ info.clear ();
+ }
+ }
+
+ // Rebuild ud chains.
+ df_remove_problem (df_chain);
+ df_process_deferred_rescans ();
+ df_set_flags (DF_RD_PRUNE_DEAD_DEFS);
+ df_chain_add_problem (DF_UD_CHAIN);
+ df_analyze ();
+
+ // Print status
+ if (dump_file)
+ {
+ fprintf (dump_file, "\nInsns modified = %lu\n", num_modifications);
+ fprintf (dump_file, "Constants saved = %lu\n", constants_saved);
+ fprintf (dump_file, "Constants reused = %lu\n", constants_reused);
+ fprintf (dump_file, "Constants moved = %lu\n", constants_moved);
+ }
+
+ return 0;
+}
+
+
+// Normal pass, run just before IRA (-mopt-xform)
+const pass_data pass_optimize_xform_rtl =
+{
+ RTL_PASS, // type
+ "xform", // name
+ OPTGROUP_NONE, // optinfo_flags
+ TV_NONE, // tv_id
+ 0, // properties_required
+ 0, // properties_provided
+ 0, // properties_destroyed
+ 0, // todo_flags_start
+ TODO_df_finish, // todo_flags_finish
+};
+
+class pass_optimize_xform : public rtl_opt_pass
+{
+public:
+ pass_optimize_xform(gcc::context *ctxt)
+ : rtl_opt_pass(pass_optimize_xform_rtl, ctxt)
+ {}
+
+ // opt_pass methods:
+ virtual bool gate (function *)
+ {
+ return (optimize > 0 && TARGET_OPT_XFORM);
+ }
+
+ virtual unsigned int execute (function *fun)
+ {
+ return rs6000_optimize_xform (fun);
+ }
+
+ opt_pass *clone ()
+ {
+ return new pass_optimize_xform (m_ctxt);
+ }
+
+}; // class pass_optimize_xform
+
+rtl_opt_pass *
+make_pass_optimize_xform (gcc::context *ctxt)
+{
+ return new pass_optimize_xform (ctxt);
+}
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 30c1d955541..1739c429549 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -35992,6 +35992,7 @@ static struct rs6000_opt_mask const rs6000_opt_masks[] =
{ "modulo", OPTION_MASK_MODULO, false, true },
{ "mulhw", OPTION_MASK_MULHW, false, true },
{ "multiple", OPTION_MASK_MULTIPLE, false, true },
+ { "optimize-xform", OPTION_MASK_NO_OPT_XFORM, true, false },
{ "popcntb", OPTION_MASK_POPCNTB, false, true },
{ "popcntd", OPTION_MASK_POPCNTD, false, true },
{ "power8-fusion", OPTION_MASK_P8_FUSION, false, true },
@@ -37318,9 +37319,12 @@ rs6000_force_indexed_or_indirect_mem (rtx x)
addressing. */
if (GET_CODE (addr) == PLUS
&& (REG_P (XEXP (addr, 0)) || SUBREG_P (XEXP (addr, 0)))
- && CONSTANT_P (XEXP (addr, 1)))
+ && satisfies_constraint_I (XEXP (addr, 1)))
{
- rtx reg = force_reg (Pmode, XEXP (addr, 1));
+ rtx reg = gen_reg_rtx (Pmode);
+ rtx cst = XEXP (addr, 1);
+ rtx insn = emit_move_insn (reg, cst);
+ set_unique_reg_note (insn, REG_EQUAL, cst);
addr = gen_rtx_PLUS (Pmode, XEXP (addr, 0), reg);
}
else
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index f2b10afe35b..6c50b75a97f 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -248,6 +248,9 @@
;; Is copying of this instruction disallowed?
(define_attr "cannot_copy" "no,yes" (const_string "no"))
+;; Does this insn require indexed or indirect (x-form) memory addressing?
+(define_attr "xform_memory" "no,yes" (const_string "no"))
+
;; Length of the instruction (in bytes).
(define_attr "length" "" (const_int 4))
@@ -5174,8 +5177,11 @@
;; Conversions to and from floating-point.
-; We don't define lfiwax/lfiwzx with the normal definition, because we
-; don't want to support putting SImode in FPR registers.
+;; We don't define lfiwax/lfiwzx with the normal definition. On ISA 2.05/2.06
+;; (power6/power7), SImode is not allowed in FPR registers. On ISA 2.07 and
+;; above, SImode is allowed, but we prefer to have a special definition so that
+;; the register allocator isn't tempted to load the value into a GPR and use
+;; direct move.
(define_insn "lfiwax"
[(set (match_operand:DI 0 "gpc_reg_operand" "=d,wj,wj,wK")
(unspec:DI [(match_operand:SI 1 "reg_or_indexed_operand" "Z,Z,r,wK")]
@@ -5186,7 +5192,8 @@
lxsiwax %x0,%y1
mtvsrwa %x0,%1
vextsw2d %0,%1"
- [(set_attr "type" "fpload,fpload,mffgpr,vecexts")])
+ [(set_attr "type" "fpload,fpload,mffgpr,vecexts")
+ (set_attr "xform_memory" "yes")])
; This split must be run before register allocation because it allocates the
; memory slot that is needed to move values to/from the FPR. We don't allocate
@@ -5217,7 +5224,8 @@
tmp = gen_reg_rtx (DImode);
if (MEM_P (src))
{
- src = rs6000_force_indexed_or_indirect_mem (src);
+ if (!TARGET_OPT_XFORM)
+ src = rs6000_force_indexed_or_indirect_mem (src);
emit_insn (gen_lfiwax (tmp, src));
}
else
@@ -5231,7 +5239,8 @@
DONE;
}
[(set_attr "length" "12")
- (set_attr "type" "fpload")])
+ (set_attr "type" "fpload")
+ (set_attr "xform_memory" "yes")])
(define_insn_and_split "floatsi<mode>2_lfiwax_mem"
[(set (match_operand:SFDF 0 "gpc_reg_operand" "=<Fv>")
@@ -5255,7 +5264,8 @@
DONE;
}
[(set_attr "length" "8")
- (set_attr "type" "fpload")])
+ (set_attr "type" "fpload")
+ (set_attr "xform_memory" "yes")])
(define_insn "lfiwzx"
[(set (match_operand:DI 0 "gpc_reg_operand" "=d,wj,wj,wJwK")
@@ -5267,7 +5277,8 @@
lxsiwzx %x0,%y1
mtvsrwz %x0,%1
xxextractuw %x0,%x1,4"
- [(set_attr "type" "fpload,fpload,mftgpr,vecexts")])
+ [(set_attr "type" "fpload,fpload,mftgpr,vecexts")
+ (set_attr "xform_memory" "yes")])
(define_insn_and_split "floatunssi<mode>2_lfiwzx"
[(set (match_operand:SFDF 0 "gpc_reg_operand" "=<Fv>")
@@ -5292,7 +5303,8 @@
tmp = gen_reg_rtx (DImode);
if (MEM_P (src))
{
- src = rs6000_force_indexed_or_indirect_mem (src);
+ if (!TARGET_OPT_XFORM)
+ src = rs6000_force_indexed_or_indirect_mem (src);
emit_insn (gen_lfiwzx (tmp, src));
}
else
@@ -5306,7 +5318,8 @@
DONE;
}
[(set_attr "length" "12")
- (set_attr "type" "fpload")])
+ (set_attr "type" "fpload")
+ (set_attr "xform_memory" "yes")])
(define_insn_and_split "floatunssi<mode>2_lfiwzx_mem"
[(set (match_operand:SFDF 0 "gpc_reg_operand" "=<Fv>")
@@ -5546,7 +5559,8 @@
emit_insn (gen_floatdi<FP_ISA3:mode>2 (result, di));
DONE;
-})
+}
+ [(set_attr "xform_memory" "yes")])
(define_expand "floatuns<QHI:mode><FP_ISA3:mode>2"
[(parallel [(set (match_operand:FP_ISA3 0 "vsx_register_operand")
@@ -5591,7 +5605,8 @@
emit_insn (gen_floatdi<FP_ISA3:mode>2 (result, di));
DONE;
-})
+}
+ [(set_attr "xform_memory" "yes")])
(define_expand "fix_trunc<mode>si2"
[(set (match_operand:SI 0 "gpc_reg_operand")
@@ -5638,7 +5653,8 @@
emit_insn (gen_fctiwz_<mode> (tmp, src));
if (MEM_P (dest))
{
- dest = rs6000_force_indexed_or_indirect_mem (dest);
+ if (!TARGET_OPT_XFORM)
+ dest = rs6000_force_indexed_or_indirect_mem (dest);
emit_insn (gen_stfiwx (dest, tmp));
DONE;
}
@@ -5657,7 +5673,8 @@
}
}
[(set_attr "length" "12")
- (set_attr "type" "fp")])
+ (set_attr "type" "fp")
+ (set_attr "xform_memory" "yes")])
(define_insn_and_split "fix_trunc<mode>si2_internal"
[(set (match_operand:SI 0 "gpc_reg_operand" "=r,?r")
@@ -5750,7 +5767,8 @@
operands[3] = (<QHSI:MODE>mode == SImode
? operands[2]
: gen_rtx_REG (<QHSI:MODE>mode, REGNO (operands[2])));
-})
+}
+ [(set_attr "xform_memory" "yes")])
(define_expand "fixuns_trunc<mode>si2"
[(set (match_operand:SI 0 "gpc_reg_operand")
@@ -5785,7 +5803,8 @@
emit_insn (gen_fctiwuz_<mode> (tmp, src));
if (MEM_P (dest))
{
- dest = rs6000_force_indexed_or_indirect_mem (dest);
+ if (!TARGET_OPT_XFORM)
+ dest = rs6000_force_indexed_or_indirect_mem (dest);
emit_insn (gen_stfiwx (dest, tmp));
DONE;
}
@@ -5804,7 +5823,8 @@
}
}
[(set_attr "length" "12")
- (set_attr "type" "fp")])
+ (set_attr "type" "fp")
+ (set_attr "xform_memory" "yes")])
(define_insn "fixuns_trunc<mode>di2"
[(set (match_operand:DI 0 "gpc_reg_operand" "=d,wi")
@@ -14248,10 +14268,8 @@
{
if (GET_CODE (operands[2]) == SCRATCH)
operands[2] = gen_reg_rtx (DImode);
-
- if (MEM_P (operands[1]))
- operands[1] = rs6000_force_indexed_or_indirect_mem (operands[1]);
-})
+}
+ [(set_attr "xform_memory" "yes")])
(define_insn_and_split "float<QHI:mode><IEEE128:mode>2"
[(set (match_operand:IEEE128 0 "altivec_register_operand" "=v,v,v")
@@ -14314,10 +14332,8 @@
{
if (GET_CODE (operands[2]) == SCRATCH)
operands[2] = gen_reg_rtx (DImode);
-
- if (MEM_P (operands[1]))
- operands[1] = rs6000_force_indexed_or_indirect_mem (operands[1]);
-})
+}
+ [(set_attr "xform_memory" "yes")])
(define_insn_and_split "floatuns<QHI:mode><IEEE128:mode>2"
[(set (match_operand:IEEE128 0 "altivec_register_operand" "=v,v,v")
diff --git a/gcc/config/rs6000/rs6000.opt b/gcc/config/rs6000/rs6000.opt
index 794f887bbea..55fb74659f7 100644
--- a/gcc/config/rs6000/rs6000.opt
+++ b/gcc/config/rs6000/rs6000.opt
@@ -562,3 +562,11 @@ long rs6000_stack_protector_guard_offset = 0
;; branches via the CTR.
mspeculate-indirect-jumps
Target Undocumented Var(rs6000_speculate_indirect_jumps) Init(1) Save
+
+mno-optimize-xform
+Target Undocumented RejectNegative Mask(NO_OPT_XFORM) Var(rs6000_isa_flags)
+Do not generate optimize x-form addresses.
+
+moptimize-xform
+Target Undocumented RejectNegative InverseMask(NO_OPT_XFORM, OPT_XFORM) Var(rs6000_isa_flags)
+Optimize x-form addresses
diff --git a/gcc/config/rs6000/t-rs6000 b/gcc/config/rs6000/t-rs6000
index d9249b079f2..27c1d461931 100644
--- a/gcc/config/rs6000/t-rs6000
+++ b/gcc/config/rs6000/t-rs6000
@@ -35,6 +35,10 @@ rs6000-p8swap.o: $(srcdir)/config/rs6000/rs6000-p8swap.c
$(COMPILE) $<
$(POSTCOMPILE)
+rs6000-xform.o: $(srcdir)/config/rs6000/rs6000-xform.c
+ $(COMPILE) $<
+ $(POSTCOMPILE)
+
rs6000-d.o: $(srcdir)/config/rs6000/rs6000-d.c
$(COMPILE) $<
$(POSTCOMPILE)