diff options
author | Michael Meissner <meissner@linux.ibm.com> | 2018-12-06 22:38:48 +0000 |
---|---|---|
committer | Michael Meissner <meissner@linux.ibm.com> | 2018-12-06 22:38:48 +0000 |
commit | 580bea528adc686cca50093b5b955bc80ea96f01 (patch) | |
tree | eac655bae83ebe08a2c6f2fa18773602ba755b8a | |
parent | 49bdbef0b502c3728ac04ac9e507e5061c736cc6 (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.meissner | 43 | ||||
-rw-r--r-- | gcc/config.gcc | 4 | ||||
-rw-r--r-- | gcc/config/rs6000/predicates.md | 16 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000-passes.def | 1 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000-protos.h | 1 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000-xform.c | 425 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.c | 8 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.md | 64 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.opt | 8 | ||||
-rw-r--r-- | gcc/config/rs6000/t-rs6000 | 4 |
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) |