aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Meissner <meissner@linux.ibm.com>2018-07-12 18:27:23 +0000
committerMichael Meissner <meissner@linux.ibm.com>2018-07-12 18:27:23 +0000
commit5cd509d493e993ba74d7d1c0d9c82ffd59307329 (patch)
tree5b9018fcff11a8355831c9097c240310fb06af33
parentb7c7687856ee67811714b8f0ae11c7d52b32c0b9 (diff)
checkpoint
git-svn-id: https://gcc.gnu.org/svn/gcc/branches/ibm/addr@262601 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog.meissner136
-rw-r--r--gcc/config/rs6000/constraints.md12
-rw-r--r--gcc/config/rs6000/predicates.md31
-rw-r--r--gcc/config/rs6000/rs6000-protos.h7
-rw-r--r--gcc/config/rs6000/rs6000.c591
-rw-r--r--gcc/config/rs6000/rs6000.md692
-rw-r--r--gcc/config/rs6000/rs6000.opt4
7 files changed, 1102 insertions, 371 deletions
diff --git a/gcc/ChangeLog.meissner b/gcc/ChangeLog.meissner
index cc0b4acd163..0ac5a7d9eb9 100644
--- a/gcc/ChangeLog.meissner
+++ b/gcc/ChangeLog.meissner
@@ -1,3 +1,139 @@
+2018-07-12 Michael Meissner <meissner@linux.ibm.com>
+
+ * config/rs6000/constraints.md (wC constraint): Define new
+ constraints for large memory operations, and non-large memory
+ operations.
+ (wN constraint): Likewise.
+ * config/rs6000/predicates.md (s32bit_cint_operand): New predicate
+ for 32-bit signed integer constant.
+ (large_mem_operand): New predicate for large memory.
+ (any_mem_operand): New predicator for normal and large memory.
+ (reg_or_any_mem_operand): New predicate for register or any
+ memory.
+ * config/rs6000/rs6000-protos.h (fusion_wrap_memory_address): New
+ declarations.
+ (emit_large_address_load): Likewise.
+ (emit_large_address_store): Likewise.
+ (large_address_valid): Likewise.
+ (split_large_address_hilo): Likewise.
+ (split_large_address): Likewise.
+ (output_large_address_load_store): Likewise.
+ * config/rs6000/rs6000.c (rs6000_reg_addr): Delete fusion fields
+ that are no longer used. Add new fields to handle large memory.
+ (rs6000_debug_print_mode): Add support for large memory, and
+ delete old fusion support.
+ (rs6000_init_hard_regno_mode_ok): Drop setting old fusion fields
+ that were never used. Add support for large addresses.
+ (rs6000_option_override_internal): Add checks for large
+ addresses.
+ (move_valid_p): Add large address support.
+ (mem_operand_gpr): Do not allow large addresses.
+ (mem_operand_ds_form): Likewise.
+ (rs6000_legitimate_address_p): Do not allow large addresses after
+ register allocation has begun.
+ (rs6000_secondary_reload_memory): Add large address support.
+ (rs6000_secondary_reload): Likewise.
+ (rs6000_secondary_reload_inner): Likewise.
+ (rs6000_secondary_reload_gpr): Likewise.
+ (int_is_32bit): New function to return true if an integer is a
+ 32-bit integer constant.
+ (split_large_integer): Split a 32-bit integer into 16-bit high and
+ low values.
+ (rs6000_opt_masks): Add -mlarge-address support.
+ (fusion_gpr_load_p): Turn off the peephole if we have large
+ addresses. Add support for sign/zero extension.
+ (fusion_p9_p): Likewise.
+ (fusion_wrap_memory_address): Add back in again.
+ (emit_large_address_load): New functions for large address
+ support.
+ (emit_large_address_store): Likewise.
+ (large_address_valid): Likewise.
+ (split_large_address_hilo): Likewise.
+ (split_large_address): Likewise.
+ (output_large_address_load_store): Likewise.
+ * config/rs6000/rs6000.md (UNSPEC_FUSION_ADDIS):Add back in
+ again.
+ (UNSPEC_LADDR_LOAD): New unspecs for large address support.
+ (UNSPEC_LADDR_STORE): Likewise.
+ (LADDR): New iterators and attributes for large address support.
+ (LADDR_GLOAD): Likewise.
+ (LADDR_FLOAD): Likewise.
+ (LADDR_VLOAD): Likewise.
+ (LADDR_GSTORE): Likewise.
+ (LADDR_FSTORE): Likewise.
+ (LADDR_VSTORE): Likewise.
+ (large_mov<mode>_load, QHSI iterator): New insns for large address
+ support.
+ (large_mov<mode>_loadu_di, QHSI iterator): Likewise.
+ (large_mov<mode>_loads_di, HSI iterator): Likewise.
+ (large_mov<mode>_store, QHSI iterator): Likewise.
+ (large_movdi_load): Likewise.
+ (large_movdi_load_fp): Likewise.
+ (large_movdi_store): Likewise.
+ (large_mov<mode>_load, SFDF iterator): Likewise.
+ (large_mov<mode>_store, SFDF iterator): Likewise.
+ (large address move splitters): New splitters to convert normal
+ move to a special large address move.
+ (zero_extendqi<mode>2): Use wN constraint instead of m constraint
+ to prevent large addresses.
+ (zero_extendhi<mode>2): Likewise.
+ (zero_extendsi<mode>2): Likewise.
+ (extendhi<mode>): Likewise.
+ (ashdi3_extswsli): Break extswsli into separate insns for register
+ operations and memory operations. For the memory operations, add
+ large memory support.
+ (ashdi3_extswsli_mem): Likewise.
+ (ashdi3_extswsli_dot): Likewise.
+ (ashdi3_extswsli_dot_mem): Likewise.
+ (ashdi3_extswsli_dot2): Likewise.
+ (ashdi3_extswsli_dot2_mem): Likewise.
+ (extendsfdf2): Add large memory support.
+ (large_extendsfdf): Likewise.
+ (extendsfdf2_fpr): Use wN constraint instead of m to skip large
+ memory.
+ (fix_trunc<mode>si2_stfiwx): Likewise.
+ (floatdidf2_mem): Combine signed/unsigned conversion ops into a
+ single insn.
+ (floatunsdidf2_mem): Likewise.
+ (float<uns>di<mode>2_mem): Likewise.
+ (floatdisf2_mem): Likewise.
+ (floatunsdidf2): Combine generator and insn.
+ (floatunsdidf2_fcfidu): Likewise.
+ (movsi_low): Use wN constraint instead of m to skip large memory.
+ (movsi_from_sf): Likewise.
+ (movdi_from_sf_zero_ext): Don't allow large memory. Also use wN
+ instead of m.
+ (movsf_from_si): Likewise.
+ (mov<mode>_internal, QHI iterator): Use wN constraint instead of
+ m.
+ (movsf_hardfloat): Likewise.
+ (movsf_hardfloat): Likewise.
+ (movsd_hardfloat): Likewise.
+ (mov<mode>_hardfloat32, FMOVE64 iterator): Likewise.
+ (mov<mode>_softfloat32, FMOVE64 iterator): Likewise.
+ (mov<mode>_hardfloat64, FMOVE64 iterator): Likewise.
+ (mov<mode>_64bit_dm): Likewise.
+ (movtd_64bit_nodm): Likewise.
+ (mov<mode>_32bit, FMOVE128_FPR iterator): Likewise.
+ (extenddf<mode>2_fprs, IBM128 iterator): Likewise.
+ (extenddf<mode>2_vsx, IBM128 iterator): Likewise.
+ (movdi_internal32): Likewise.
+ (movdi_internal64): Likewise.
+ (high_plus_int): Recognize ADDIS generated by large addresses.
+ (probe_stack_<mode>): Don't allow large memory.
+ (stack_protect_setsi): Likewise.
+ (stack_protect_testsi): Likewise.
+ (<bd>_<mode): Likewise.
+ (<bd>tf_<mode>): Likewise.
+ (crsave): Likewise.
+ (stmw): Likewise.
+ (fusion_gpr_load_<mode>): Remove generator support.
+ (fusion_gpr_<P:mode>_<GPR_FUSION:mode>_load): Likewise.
+ (fusion_gpr_<P:mode>_<GPR_FUSION:mode>_store): Likewise.
+ (fusion_vsx_<P:mode>_<FPR_FUSION:mode>_load): Likewise.
+ (fusion_vsx_<P:mode>_<FPR_FUSION:mode>_store): Likewise.
+ * config/rs6000/rs6000.opt (-mlarge-address): New switch.
+
2018-07-11 Michael Meissner <meissner@linux.ibm.com>
* config/rs6000/rs6000-protos.h (fusion_wrap_memory_address):
diff --git a/gcc/config/rs6000/constraints.md b/gcc/config/rs6000/constraints.md
index 0683a6826d2..446229a1a54 100644
--- a/gcc/config/rs6000/constraints.md
+++ b/gcc/config/rs6000/constraints.md
@@ -143,6 +143,10 @@
(and (match_test "TARGET_P8_VECTOR")
(match_operand 0 "s5bit_cint_operand"))))
+(define_memory_constraint "wC"
+ "Large address memory operand"
+ (match_operand 0 "large_mem_operand"))
+
(define_constraint "wD"
"Int constant that is the element number of the 64-bit scalar in a vector."
(and (match_code "const_int")
@@ -157,7 +161,8 @@
"Memory operand suitable for power9 fusion load/stores"
(match_operand 0 "fusion_addis_mem_combo_load"))
-;; wG used to be for TOC fusion memory references
+;; wG is now available. Previously it was a memory operand suitable for TOC
+;; fusion.
(define_register_constraint "wH" "rs6000_constraints[RS6000_CONSTRAINT_wH]"
"Altivec register to hold 32-bit integers or NO_REGS.")
@@ -183,6 +188,11 @@
(and (match_test "TARGET_P8_VECTOR")
(match_operand 0 "all_ones_constant")))
+(define_memory_constraint "wN"
+ "Memory operand that is not a large address"
+ (and (match_operand 0 "memory_operand")
+ (not (match_operand 0 "large_mem_operand"))))
+
;; ISA 3.0 vector d-form addresses
(define_memory_constraint "wO"
"Memory operand suitable for the ISA 3.0 vector d-form instructions."
diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md
index 1d48927f450..a3f097ed784 100644
--- a/gcc/config/rs6000/predicates.md
+++ b/gcc/config/rs6000/predicates.md
@@ -245,6 +245,14 @@
(and (match_code "const_int")
(match_test "INTVAL (op) >= 0 && INTVAL (op) <= 1023")))
+;; Return 1 if op is a signed 32-bit constant integer.
+(define_predicate "s32bit_cint_operand"
+ (match_code "const_int")
+{
+ unsigned HOST_WIDE_INT v = UINTVAL (op);
+ return ((v + HOST_WIDE_INT_C (0x80000000U)) < HOST_WIDE_INT_C (0x100000000U));
+})
+
;; Return 1 if op is a constant integer that can fit in a D field.
(define_predicate "short_cint_operand"
(and (match_code "const_int")
@@ -903,6 +911,24 @@
|| (GET_CODE (XEXP (op, 0)) == PRE_MODIFY
&& indexed_address (XEXP (XEXP (op, 0), 1), mode))))"))
+;; Match a memory operation that uses a large address.
+(define_predicate "large_mem_operand"
+ (match_code "mem")
+{
+ return large_address_valid (XEXP (op, 0), mode);
+})
+
+;; Match a memory operand that might be large or normal. After register
+;; allocation, memory_operand will not return true for large addresses.
+(define_predicate "any_mem_operand"
+ (match_code "mem")
+{
+ if (TARGET_LARGE_ADDRESS && large_address_valid (XEXP (op, 0), mode))
+ return true;
+
+ return memory_operand (op, mode);
+})
+
;; Return 1 if the operand is either a non-special register or can be used
;; as the operand of a `mode' add insn.
(define_predicate "add_operand"
@@ -971,6 +997,11 @@
(match_operand 0 "volatile_mem_operand")
(match_operand 0 "gpc_reg_operand")))
+;; Like reg_or_mem_operand, but allow large addresses
+(define_predicate "reg_or_any_mem_operand"
+ (ior (match_operand 0 "reg_or_mem_operand")
+ (match_operand 0 "large_mem_operand")))
+
;; Return 1 if the operand is CONST_DOUBLE 0, register or memory operand.
(define_predicate "zero_reg_mem_operand"
(ior (and (match_test "TARGET_VSX")
diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h
index d77dbed04d7..9a19a57fd4f 100644
--- a/gcc/config/rs6000/rs6000-protos.h
+++ b/gcc/config/rs6000/rs6000-protos.h
@@ -99,6 +99,13 @@ extern void expand_fusion_p9_load (rtx *);
extern void expand_fusion_p9_store (rtx *);
extern const char *emit_fusion_p9_load (rtx, rtx, rtx);
extern const char *emit_fusion_p9_store (rtx, rtx, rtx);
+extern rtx fusion_wrap_memory_address (rtx);
+extern bool emit_large_address_load (rtx, rtx, machine_mode);
+extern bool emit_large_address_store (rtx, rtx, machine_mode);
+extern bool large_address_valid (rtx, machine_mode);
+extern enum rtx_code split_large_address_hilo (rtx, rtx *, rtx *);
+extern rtx split_large_address (rtx, rtx);
+extern void output_large_address_load_store (rtx, rtx, rtx, const char *);
extern enum reg_class (*rs6000_preferred_reload_class_ptr) (rtx,
enum reg_class);
extern enum reg_class (*rs6000_secondary_reload_class_ptr) (enum reg_class,
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 13389d6fbc6..10e64522c9e 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -531,17 +531,11 @@ struct rs6000_reg_addr {
enum insn_code reload_fpr_gpr; /* INSN to move from FPR to GPR. */
enum insn_code reload_gpr_vsx; /* INSN to move from GPR to VSX. */
enum insn_code reload_vsx_gpr; /* INSN to move from VSX to GPR. */
- enum insn_code fusion_gpr_ld; /* INSN for fusing gpr ADDIS/loads. */
- /* INSNs for fusing addi with loads
- or stores for each reg. class. */
- enum insn_code fusion_addi_ld[(int)N_RELOAD_REG];
- enum insn_code fusion_addi_st[(int)N_RELOAD_REG];
- /* INSNs for fusing addis with loads
- or stores for each reg. class. */
- enum insn_code fusion_addis_ld[(int)N_RELOAD_REG];
- enum insn_code fusion_addis_st[(int)N_RELOAD_REG];
+ enum insn_code large_addr_load; /* Large address load insn. */
+ enum insn_code large_addr_store; /* Large address store insn. */
addr_mask_type addr_mask[(int)N_RELOAD_REG]; /* Valid address masks. */
bool scalar_in_vmx_p; /* Scalar value can go in VMX. */
+ bool large_address_p; /* Mode supports large addresses. */
};
static struct rs6000_reg_addr reg_addr[NUM_MACHINE_MODES];
@@ -2375,18 +2369,34 @@ rs6000_debug_print_mode (ssize_t m)
{
ssize_t rc;
int spaces = 0;
- bool fuse_extra_p;
fprintf (stderr, "Mode: %-5s", GET_MODE_NAME (m));
for (rc = 0; rc < N_RELOAD_REG; rc++)
fprintf (stderr, " %s: %s", reload_reg_map[rc].name,
rs6000_debug_addr_mask (reg_addr[m].addr_mask[rc], true));
+ if (TARGET_LARGE_ADDRESS)
+ {
+ if (reg_addr[m].large_address_p)
+ {
+ char s = reg_addr[m].large_addr_store != CODE_FOR_nothing ? 's' : '*';
+ char l = reg_addr[m].large_addr_load != CODE_FOR_nothing ? 'l' : '*';
+
+ fprintf (stderr, "%*s Large-addr=%c%c", spaces, "", s, l);
+ spaces = 0;
+ }
+ else
+ spaces += sizeof (" Large-addr=sl") - 1;
+ }
+
if ((reg_addr[m].reload_store != CODE_FOR_nothing)
|| (reg_addr[m].reload_load != CODE_FOR_nothing))
- fprintf (stderr, " Reload=%c%c",
- (reg_addr[m].reload_store != CODE_FOR_nothing) ? 's' : '*',
- (reg_addr[m].reload_load != CODE_FOR_nothing) ? 'l' : '*');
+ {
+ fprintf (stderr, "%*s Reload=%c%c", spaces, "",
+ (reg_addr[m].reload_store != CODE_FOR_nothing) ? 's' : '*',
+ (reg_addr[m].reload_load != CODE_FOR_nothing) ? 'l' : '*');
+ spaces = 0;
+ }
else
spaces += sizeof (" Reload=sl") - 1;
@@ -2398,73 +2408,6 @@ rs6000_debug_print_mode (ssize_t m)
else
spaces += sizeof (" Upper=y") - 1;
- fuse_extra_p = (reg_addr[m].fusion_gpr_ld != CODE_FOR_nothing);
- if (!fuse_extra_p)
- {
- for (rc = 0; rc < N_RELOAD_REG; rc++)
- {
- if (rc != RELOAD_REG_ANY)
- {
- if (reg_addr[m].fusion_addi_ld[rc] != CODE_FOR_nothing
- || reg_addr[m].fusion_addi_ld[rc] != CODE_FOR_nothing
- || reg_addr[m].fusion_addi_st[rc] != CODE_FOR_nothing
- || reg_addr[m].fusion_addis_ld[rc] != CODE_FOR_nothing
- || reg_addr[m].fusion_addis_st[rc] != CODE_FOR_nothing)
- {
- fuse_extra_p = true;
- break;
- }
- }
- }
- }
-
- if (fuse_extra_p)
- {
- fprintf (stderr, "%*s Fuse:", spaces, "");
- spaces = 0;
-
- for (rc = 0; rc < N_RELOAD_REG; rc++)
- {
- if (rc != RELOAD_REG_ANY)
- {
- char load, store;
-
- if (reg_addr[m].fusion_addis_ld[rc] != CODE_FOR_nothing)
- load = 'l';
- else if (reg_addr[m].fusion_addi_ld[rc] != CODE_FOR_nothing)
- load = 'L';
- else
- load = '-';
-
- if (reg_addr[m].fusion_addis_st[rc] != CODE_FOR_nothing)
- store = 's';
- else if (reg_addr[m].fusion_addi_st[rc] != CODE_FOR_nothing)
- store = 'S';
- else
- store = '-';
-
- if (load == '-' && store == '-')
- spaces += 5;
- else
- {
- fprintf (stderr, "%*s%c=%c%c", (spaces + 1), "",
- reload_reg_map[rc].name[0], load, store);
- spaces = 0;
- }
- }
- }
-
- if (reg_addr[m].fusion_gpr_ld != CODE_FOR_nothing)
- {
- fprintf (stderr, "%*sP8gpr", (spaces + 1), "");
- spaces = 0;
- }
- else
- spaces += sizeof (" P8gpr") - 1;
- }
- else
- spaces += sizeof (" Fuse: G=ls F=ls v=ls P8gpr") - 1;
-
if (rs6000_vector_unit[m] != VECTOR_NONE
|| rs6000_vector_mem[m] != VECTOR_NONE)
{
@@ -3527,117 +3470,33 @@ rs6000_init_hard_regno_mode_ok (bool global_init_p)
}
}
- /* Setup the fusion operations. */
- if (TARGET_P8_FUSION)
- {
- reg_addr[QImode].fusion_gpr_ld = CODE_FOR_fusion_gpr_load_qi;
- reg_addr[HImode].fusion_gpr_ld = CODE_FOR_fusion_gpr_load_hi;
- reg_addr[SImode].fusion_gpr_ld = CODE_FOR_fusion_gpr_load_si;
- if (TARGET_64BIT)
- reg_addr[DImode].fusion_gpr_ld = CODE_FOR_fusion_gpr_load_di;
- }
-
- if (TARGET_P9_FUSION)
+ /* Note which types support large addresses. */
+ if (TARGET_LARGE_ADDRESS && TARGET_POWERPC64 && TARGET_VSX
+ && TARGET_CMODEL == CMODEL_MEDIUM)
{
- struct fuse_insns {
- enum machine_mode mode; /* mode of the fused type. */
- enum machine_mode pmode; /* pointer mode. */
- enum rs6000_reload_reg_type rtype; /* register type. */
- enum insn_code load; /* load insn. */
- enum insn_code store; /* store insn. */
- };
-
- static const struct fuse_insns addis_insns[] = {
- { E_SFmode, E_DImode, RELOAD_REG_FPR,
- CODE_FOR_fusion_vsx_di_sf_load,
- CODE_FOR_fusion_vsx_di_sf_store },
+ reg_addr[QImode].large_address_p = true;
+ reg_addr[QImode].large_addr_load = CODE_FOR_large_movqi_load;
+ reg_addr[QImode].large_addr_store = CODE_FOR_large_movqi_store;
- { E_SFmode, E_SImode, RELOAD_REG_FPR,
- CODE_FOR_fusion_vsx_si_sf_load,
- CODE_FOR_fusion_vsx_si_sf_store },
+ reg_addr[HImode].large_address_p = true;
+ reg_addr[HImode].large_addr_load = CODE_FOR_large_movhi_load;
+ reg_addr[HImode].large_addr_store = CODE_FOR_large_movhi_store;
- { E_DFmode, E_DImode, RELOAD_REG_FPR,
- CODE_FOR_fusion_vsx_di_df_load,
- CODE_FOR_fusion_vsx_di_df_store },
+ reg_addr[SImode].large_address_p = true;
+ reg_addr[SImode].large_addr_load = CODE_FOR_large_movsi_load;
+ reg_addr[SImode].large_addr_store = CODE_FOR_large_movsi_store;
- { E_DFmode, E_SImode, RELOAD_REG_FPR,
- CODE_FOR_fusion_vsx_si_df_load,
- CODE_FOR_fusion_vsx_si_df_store },
+ reg_addr[DImode].large_address_p = true;
+ reg_addr[DImode].large_addr_load = CODE_FOR_large_movdi_load;
+ reg_addr[DImode].large_addr_store = CODE_FOR_large_movdi_store;
- { E_DImode, E_DImode, RELOAD_REG_FPR,
- CODE_FOR_fusion_vsx_di_di_load,
- CODE_FOR_fusion_vsx_di_di_store },
-
- { E_DImode, E_SImode, RELOAD_REG_FPR,
- CODE_FOR_fusion_vsx_si_di_load,
- CODE_FOR_fusion_vsx_si_di_store },
-
- { E_QImode, E_DImode, RELOAD_REG_GPR,
- CODE_FOR_fusion_gpr_di_qi_load,
- CODE_FOR_fusion_gpr_di_qi_store },
-
- { E_QImode, E_SImode, RELOAD_REG_GPR,
- CODE_FOR_fusion_gpr_si_qi_load,
- CODE_FOR_fusion_gpr_si_qi_store },
-
- { E_HImode, E_DImode, RELOAD_REG_GPR,
- CODE_FOR_fusion_gpr_di_hi_load,
- CODE_FOR_fusion_gpr_di_hi_store },
-
- { E_HImode, E_SImode, RELOAD_REG_GPR,
- CODE_FOR_fusion_gpr_si_hi_load,
- CODE_FOR_fusion_gpr_si_hi_store },
-
- { E_SImode, E_DImode, RELOAD_REG_GPR,
- CODE_FOR_fusion_gpr_di_si_load,
- CODE_FOR_fusion_gpr_di_si_store },
-
- { E_SImode, E_SImode, RELOAD_REG_GPR,
- CODE_FOR_fusion_gpr_si_si_load,
- CODE_FOR_fusion_gpr_si_si_store },
-
- { E_SFmode, E_DImode, RELOAD_REG_GPR,
- CODE_FOR_fusion_gpr_di_sf_load,
- CODE_FOR_fusion_gpr_di_sf_store },
-
- { E_SFmode, E_SImode, RELOAD_REG_GPR,
- CODE_FOR_fusion_gpr_si_sf_load,
- CODE_FOR_fusion_gpr_si_sf_store },
-
- { E_DImode, E_DImode, RELOAD_REG_GPR,
- CODE_FOR_fusion_gpr_di_di_load,
- CODE_FOR_fusion_gpr_di_di_store },
-
- { E_DFmode, E_DImode, RELOAD_REG_GPR,
- CODE_FOR_fusion_gpr_di_df_load,
- CODE_FOR_fusion_gpr_di_df_store },
- };
-
- machine_mode cur_pmode = Pmode;
- size_t i;
-
- for (i = 0; i < ARRAY_SIZE (addis_insns); i++)
- {
- machine_mode xmode = addis_insns[i].mode;
- enum rs6000_reload_reg_type rtype = addis_insns[i].rtype;
+ reg_addr[SFmode].large_address_p = true;
+ reg_addr[SFmode].large_addr_load = CODE_FOR_large_movsf_load;
+ reg_addr[SFmode].large_addr_store = CODE_FOR_large_movsf_store;
- if (addis_insns[i].pmode != cur_pmode)
- continue;
-
- if (rtype == RELOAD_REG_FPR && !TARGET_HARD_FLOAT)
- continue;
-
- reg_addr[xmode].fusion_addis_ld[rtype] = addis_insns[i].load;
- reg_addr[xmode].fusion_addis_st[rtype] = addis_insns[i].store;
-
- if (rtype == RELOAD_REG_FPR && TARGET_P9_VECTOR)
- {
- reg_addr[xmode].fusion_addis_ld[RELOAD_REG_VMX]
- = addis_insns[i].load;
- reg_addr[xmode].fusion_addis_st[RELOAD_REG_VMX]
- = addis_insns[i].store;
- }
- }
+ reg_addr[DFmode].large_address_p = true;
+ reg_addr[DFmode].large_addr_load = CODE_FOR_large_movdf_load;
+ reg_addr[DFmode].large_addr_store = CODE_FOR_large_movdf_store;
}
/* Precalculate HARD_REGNO_NREGS. */
@@ -4739,6 +4598,29 @@ rs6000_option_override_internal (bool global_init_p)
SUB3TARGET_OVERRIDE_OPTIONS;
#endif
+ /* Don't allow -mlarge-address in 32-bit mode, or small code model. Disallow
+ it in large code model at present, because addresses might not be within
+ 32-bits of the TOC address. Enable it by default on systems with at least
+ load fusion by default. This test has to be after the subtarget options
+ are set in order to use medium code model. */
+ if (TARGET_POWERPC64 && TARGET_CMODEL == CMODEL_MEDIUM)
+ {
+ if (!TARGET_LARGE_ADDRESS && TARGET_P8_FUSION
+ && !(rs6000_isa_flags_explicit & OPTION_MASK_LARGE_ADDRESS))
+ rs6000_isa_flags |= OPTION_MASK_LARGE_ADDRESS;
+ }
+ else if (TARGET_LARGE_ADDRESS)
+ {
+ rs6000_isa_flags &= ~OPTION_MASK_LARGE_ADDRESS;
+ if (rs6000_isa_flags_explicit & OPTION_MASK_LARGE_ADDRESS)
+ {
+ if (!TARGET_POWERPC64)
+ error ("%qs requires 64-bit code.", "-mlarge-address");
+ else
+ error ("%qs requires %qs", "-mlarge-address", "-mcmodel=medium");
+ }
+ }
+
if (TARGET_DEBUG_REG || TARGET_DEBUG_TARGET)
rs6000_print_isa_options (stderr, 0, "after subtarget", rs6000_isa_flags);
@@ -7781,7 +7663,10 @@ small_data_operand (rtx op ATTRIBUTE_UNUSED,
#endif
}
-/* Return true if the operands are valid for a standard move. */
+/* Return true if the operands are valid for a standard move. We don't allow
+ large address moves after register allocation in the standard MOV insn.
+ Instead such moves should be done through an insn that has a base register
+ as a temporary. */
bool
move_valid_p (rtx dest, rtx src)
@@ -7808,7 +7693,17 @@ move_valid_p (rtx dest, rtx src)
&& !gpc_reg_operand (src, src_mode))
return false;
- return true;
+ if (!reg_addr[dest_mode].large_address_p || can_create_pseudo_p ())
+ return true;
+
+ if (MEM_P (dest))
+ return !large_address_valid (XEXP (dest, 0), dest_mode);
+
+ else if (MEM_P (src))
+ return !large_address_valid (XEXP (src, 0), src_mode);
+
+ else
+ return true;
}
/* Return true if either operand is a general purpose register. */
@@ -7981,6 +7876,11 @@ mem_operand_gpr (rtx op, machine_mode mode)
int extra;
rtx addr = XEXP (op, 0);
+ /* Don't recognize large addresses, here. Instead use, the dedicated
+ patterns. */
+ if (large_address_valid (addr, mode))
+ return false;
+
/* PR85755: Allow PRE_INC and PRE_DEC addresses. */
if (TARGET_UPDATE
&& (GET_CODE (addr) == PRE_INC || GET_CODE (addr) == PRE_DEC)
@@ -8022,6 +7922,11 @@ mem_operand_ds_form (rtx op, machine_mode mode)
int extra;
rtx addr = XEXP (op, 0);
+ /* Don't recognize large addresses, here. Instead use, the dedicated
+ patterns. */
+ if (large_address_valid (addr, mode))
+ return false;
+
if (!offsettable_address_p (false, mode, addr))
return false;
@@ -9511,6 +9416,12 @@ rs6000_legitimate_address_p (machine_mode mode, rtx x, bool reg_ok_strict)
if (legitimate_constant_pool_address_p (x, mode,
reg_ok_strict || lra_in_progress))
return 1;
+
+ /* We allow large addresses before register allocation for normal memory.
+ After register allocation, they should be using the special insns that
+ can allocate a scratch register. */
+ if (reg_addr[mode].large_address_p && large_address_valid (x, mode))
+ return !reg_ok_strict;
}
/* For TImode, if we have TImode in VSX registers, only allow register
@@ -18882,6 +18793,12 @@ rs6000_secondary_reload_memory (rtx addr,
extra_cost = 1;
type = "offset";
}
+
+ else if (large_address_valid (addr, mode))
+ {
+ extra_cost = 1;
+ type = "large address";
+ }
}
/* (plus (plus (reg) (constant)) (reg)) is also generated during
@@ -19296,6 +19213,28 @@ rs6000_secondary_reload (bool in_p,
done_p = true;
}
+ /* See if we should use the GPR reload helper for large addresses. If we are
+ loading to a base register, we don't need a reload, since the base
+ register can be used for the upper bits. */
+ if (!done_p && icode == CODE_FOR_nothing && memory_p && TARGET_POWERPC64
+ && reg_addr[mode].large_address_p
+ && reg_class_to_reg_type[(int)rclass] == GPR_REG_TYPE
+ && GET_MODE_SIZE (mode) <= UNITS_PER_WORD
+ && large_address_valid (XEXP (x, 0), mode))
+ {
+ done_p = true;
+ default_p = false;
+ ret = NO_REGS;
+
+ if (rclass != BASE_REGS || !in_p)
+ {
+ sri->extra_cost = 1;
+ sri->icode = (in_p
+ ? CODE_FOR_reload_di_load
+ : CODE_FOR_reload_di_store);
+ }
+ }
+
/* Handle reload of load/stores if we have reload helper functions. */
if (!done_p && icode != CODE_FOR_nothing && memory_p)
{
@@ -19615,6 +19554,10 @@ rs6000_secondary_reload_inner (rtx reg, rtx mem, rtx scratch, bool store_p)
}
}
+ else if (reg_addr[mode].large_address_p
+ && large_address_valid (addr, mode))
+ new_addr = split_large_address (addr, scratch);
+
else if (mode_supports_dq_form (mode) && CONST_INT_P (op1))
{
if (((addr_mask & RELOAD_REG_QUAD_OFFSET) == 0)
@@ -19716,6 +19659,8 @@ rs6000_secondary_reload_gpr (rtx reg, rtx mem, rtx scratch, bool store_p)
enum reg_class rclass;
rtx addr;
rtx scratch_or_premodify = scratch;
+ rtx new_mem;
+ machine_mode mode = GET_MODE (reg);
if (TARGET_DEBUG_ADDR)
{
@@ -19756,9 +19701,16 @@ rs6000_secondary_reload_gpr (rtx reg, rtx mem, rtx scratch, bool store_p)
}
gcc_assert (GET_CODE (addr) == PLUS || GET_CODE (addr) == LO_SUM);
- rs6000_emit_move (scratch_or_premodify, addr, Pmode);
+ /* Add support for large addresses. */
+ if (reg_addr[mode].large_address_p && large_address_valid (addr, mode))
+ new_mem = split_large_address (addr, scratch_or_premodify);
+ else
+ {
+ rs6000_emit_move (scratch_or_premodify, addr, Pmode);
+ new_mem = scratch_or_premodify;
+ }
- mem = replace_equiv_address_nv (mem, scratch_or_premodify);
+ mem = replace_equiv_address_nv (mem, new_mem);
/* Now create the move. */
if (store_p)
@@ -20450,6 +20402,38 @@ rs6000_init_machine_status (void)
return ggc_cleared_alloc<machine_function> ();
}
+/* Return true if an integer constant can be generated with ADDIS and ADDI. */
+
+static inline bool
+int_is_32bit (unsigned HOST_WIDE_INT v)
+{
+ return ((v + HOST_WIDE_INT_C (0x80000000U)) < HOST_WIDE_INT_C (0x100000000U));
+}
+
+/* Given a large integer, split it into parts for ADDIS and ADDI. */
+
+static HOST_WIDE_INT
+split_large_integer (HOST_WIDE_INT value, bool hi_p)
+{
+ HOST_WIDE_INT lo, hi;
+
+ gcc_assert (int_is_32bit (value));
+
+ lo = value & HOST_WIDE_INT_C (0xffff);
+ hi = value & ~HOST_WIDE_INT_C (0xffff);
+ if (lo & HOST_WIDE_INT_C (0x8000U))
+ {
+ lo |= ~HOST_WIDE_INT_C (0xffff);
+ hi += HOST_WIDE_INT_C (0x10000);
+ if (hi & HOST_WIDE_INT_C (0x80000000U))
+ hi |= ~HOST_WIDE_INT_C (0xffffffffU);
+ gcc_assert (int_is_32bit (hi));
+ }
+
+ return hi_p ? hi : lo;
+}
+
+
#define INT_P(X) (GET_CODE (X) == CONST_INT && GET_MODE (X) == VOIDmode)
/* Write out a function code label. */
@@ -35832,6 +35816,7 @@ static struct rs6000_opt_mask const rs6000_opt_masks[] =
{ "hard-dfp", OPTION_MASK_DFP, false, true },
{ "htm", OPTION_MASK_HTM, false, true },
{ "isel", OPTION_MASK_ISEL, false, true },
+ { "large-address", OPTION_MASK_LARGE_ADDRESS, false, true },
{ "mfcrf", OPTION_MASK_MFCRF, false, true },
{ "mfpgpr", OPTION_MASK_MFPGPR, false, true },
{ "modulo", OPTION_MASK_MODULO, false, true },
@@ -37739,12 +37724,22 @@ fusion_gpr_load_p (rtx addis_reg, /* register set via addis. */
{
rtx addr;
rtx base_reg;
+ machine_mode mode = GET_MODE (target);
+ machine_mode inner_mode = mode;
+
+ if (GET_CODE (mem) == ZERO_EXTEND || GET_CODE (mem) == SIGN_EXTEND)
+ inner_mode = GET_MODE (XEXP (mem, 0));
+
+ /* If large addresses are enabled, in theory we don't need the peephole.
+ Turn off the peephole for the types that support large addresses. */
+ if (reg_addr[inner_mode].large_address_p)
+ return false;
/* Validate arguments. */
if (!base_reg_operand (addis_reg, GET_MODE (addis_reg)))
return false;
- if (!base_reg_operand (target, GET_MODE (target)))
+ if (!base_reg_operand (target, mode))
return false;
if (!fusion_gpr_addis (addis_value, GET_MODE (addis_value)))
@@ -38015,6 +38010,18 @@ emit_fusion_load_store (rtx load_store_reg, rtx addis_reg, rtx offset,
return;
}
+/* Wrap a TOC address that can be fused to indicate that special fusion
+ processing is needed. */
+
+rtx
+fusion_wrap_memory_address (rtx old_mem)
+{
+ rtx old_addr = XEXP (old_mem, 0);
+ rtvec v = gen_rtvec (1, old_addr);
+ rtx new_addr = gen_rtx_UNSPEC (Pmode, v, UNSPEC_FUSION_ADDIS);
+ return replace_equiv_address_nv (old_mem, new_addr, false);
+}
+
/* Given an address, convert it into the addis and load offset parts. Addresses
created during the peephole2 process look like:
(lo_sum (high (unspec [(sym)] UNSPEC_TOCREL))
@@ -38111,6 +38118,16 @@ fusion_p9_p (rtx addis_reg, /* register set via addis. */
{
rtx addr, mem, offset;
machine_mode mode = GET_MODE (src);
+ machine_mode inner_mode = mode;
+
+ if (GET_CODE (src) == ZERO_EXTEND || GET_CODE (src) == SIGN_EXTEND
+ || GET_CODE (src) == FLOAT_EXTEND)
+ inner_mode = GET_MODE (XEXP (src, 0));
+
+ /* If large addresses are enabled, in theory we don't need the peephole.
+ Turn off the peephole for the types that support large addresses. */
+ if (reg_addr[inner_mode].large_address_p)
+ return false;
/* Validate arguments. */
if (!base_reg_operand (addis_reg, GET_MODE (addis_reg)))
@@ -38454,6 +38471,200 @@ emit_fusion_p9_store (rtx mem, rtx reg, rtx tmp_reg)
return "";
}
+
+/* Large address support. */
+
+/* Emit an insn to load a register from a large address. Return TRUE if it was
+ successful. */
+
+bool
+emit_large_address_load (rtx dest, rtx src, machine_mode mode)
+{
+ enum insn_code icode = reg_addr[mode].large_addr_load;
+
+ gcc_assert (MEM_P (src));
+ if (icode != CODE_FOR_nothing && large_address_valid (XEXP (src, 0), mode))
+ {
+ rtx pat = GEN_FCN (icode) (dest, src);
+ if (pat)
+ {
+ emit_insn (pat);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* Emit an insn to store a register to a large address. Return TRUE if it was
+ successful. */
+
+bool
+emit_large_address_store (rtx dest, rtx src, machine_mode mode)
+{
+ enum insn_code icode = reg_addr[mode].large_addr_store;
+
+ gcc_assert (MEM_P (dest));
+ if (icode != CODE_FOR_nothing && large_address_valid (XEXP (dest, 0), mode))
+ {
+ rtx pat = GEN_FCN (icode) (dest, src);
+ if (pat)
+ {
+ emit_insn (pat);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* Return if an address is a valid large address. */
+
+bool
+large_address_valid (rtx addr, machine_mode mode)
+{
+ if (!reg_addr[mode].large_address_p)
+ return false;
+
+ if (GET_CODE (addr) == PLUS && CONST_INT_P (XEXP (addr, 1)))
+ {
+ rtx op0 = XEXP (addr, 0);
+ rtx op1 = XEXP (addr, 1);
+
+ if (GET_CODE (op0) == UNSPEC
+ && XINT (op0, 1) == UNSPEC_TOCREL
+ && CONST_INT_P (op1))
+ {
+ if (!legitimate_constant_pool_address_p (addr, mode, false))
+ return false;
+ }
+
+ else
+ {
+ if (!base_reg_operand (op0, Pmode))
+ return false;
+
+ if (satisfies_constraint_I (op1)) /* bottom 16 bits. */
+ return false;
+ }
+
+ unsigned HOST_WIDE_INT value = UINTVAL (op1);
+
+ if (!int_is_32bit (value))
+ return false;
+
+ /* Limit any integer offset to support DQ-form loads or stores for
+ 128-bit type.
+
+ Limit any integer offset to support DS-form loads or stores for 64-bit
+ types and for SFmode.
+
+ If the address doesn't match, the compiler will use slower machine
+ independent methods of loading up the address. */
+ if ((value & 15) != 0 && GET_MODE_SIZE (mode) == 16)
+ return false;
+ else if ((value & 3) != 0 && (GET_MODE_SIZE (mode) == 8 || mode == SFmode))
+ return false;
+ else
+ return true;
+ }
+
+ else if (GET_CODE (addr) == UNSPEC && XINT (addr, 1) == UNSPEC_TOCREL)
+ return legitimate_constant_pool_address_p (addr, mode, false);
+
+ return false;
+}
+
+/* Helper function to split_large_address to return the upper and lower parts
+ of a large address. */
+
+enum rtx_code
+split_large_address_hilo (rtx addr, rtx *p_hi, rtx *p_lo)
+{
+ HOST_WIDE_INT value;
+ rtx hi, lo;
+ enum rtx_code rcode;
+
+ if (GET_CODE (addr) == UNSPEC && XINT (addr, 1) == UNSPEC_TOCREL)
+ {
+ hi = gen_rtx_HIGH (Pmode, addr);
+ lo = addr;
+ rcode = LO_SUM;
+ }
+
+ else if (GET_CODE (addr) == PLUS)
+ {
+ rtx op0 = XEXP (addr, 0);
+ rtx op1 = XEXP (addr, 1);
+
+ gcc_assert (CONST_INT_P (op1) && int_is_32bit (UINTVAL (op1)));
+
+ if (REG_P (op0))
+ {
+ value = INTVAL (op1);
+ hi = gen_rtx_PLUS (Pmode, op0,
+ GEN_INT (split_large_integer (value, true)));
+ lo = GEN_INT (split_large_integer (value, false));
+ rcode = PLUS;
+ }
+
+ else if (GET_CODE (op0) == UNSPEC && XINT (op0, 1) == UNSPEC_TOCREL)
+ {
+ hi = gen_rtx_HIGH (Pmode, addr);
+ lo = addr;
+ rcode = LO_SUM;
+ }
+
+ else
+ gcc_unreachable ();
+ }
+ else
+ gcc_unreachable ();
+
+ *p_hi = hi;
+ *p_lo = lo;
+ return rcode;
+}
+
+/* Split a large address into two insns, one to set the upper bits, and the
+ other to set the lower bits. Emit the first insn, and return the second
+ insn that can be used as an address. */
+
+rtx
+split_large_address (rtx addr, rtx tmp_reg)
+{
+ rtx hi, lo;
+ enum rtx_code rcode = split_large_address_hilo (addr, &hi, &lo);
+
+ emit_insn (gen_rtx_SET (tmp_reg, hi));
+ return gen_rtx_fmt_ee (rcode, Pmode, tmp_reg, lo);
+}
+
+/* Output the instructions to implement a large address load/store using a
+ scratch register to build a partial address. */
+
+void
+output_large_address_load_store (rtx reg,
+ rtx mem,
+ rtx tmp_reg,
+ const char *mnemonic)
+{
+ rtx hi, lo, addr;
+
+ gcc_assert (REG_P (reg) && MEM_P (mem));
+
+ addr = XEXP (mem, 0);
+ (void) split_large_address_hilo (addr, &hi, &lo);
+
+ /* Emit the addis instruction. */
+ emit_fusion_addis (tmp_reg, hi);
+
+ /* Emit the D-form load instruction. */
+ emit_fusion_load_store (reg, tmp_reg, lo, mnemonic);
+ return;
+}
+
+
#ifdef RS6000_GLIBC_ATOMIC_FENV
/* Function declarations for rs6000_atomic_assign_expand_fenv. */
static tree atomic_hold_decl, atomic_clear_decl, atomic_update_decl;
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index 6a600225f4b..9211808daef 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -137,6 +137,7 @@
UNSPEC_FUSION_GPR
UNSPEC_STACK_CHECK
UNSPEC_FUSION_P9
+ UNSPEC_FUSION_ADDIS
UNSPEC_ADD_ROUND_TO_ODD
UNSPEC_SUB_ROUND_TO_ODD
UNSPEC_MUL_ROUND_TO_ODD
@@ -147,6 +148,8 @@
UNSPEC_SIGNBIT
UNSPEC_SF_FROM_SI
UNSPEC_SI_FROM_SF
+ UNSPEC_LADDR_LOAD
+ UNSPEC_LADDR_STORE
])
;;
@@ -563,6 +566,9 @@
(float "")
(unsigned_float "uns")])
+(define_code_attr FP_CVT_P [(float "TARGET_FCFID")
+ (unsigned_float "TARGET_VSX")])
+
; Various instructions that come in SI and DI forms.
; A generic w/d attribute, for things like cmpw/cmpd.
(define_mode_attr wd [(QI "b")
@@ -703,12 +709,256 @@
(DI "TARGET_POWERPC64")])
+;; Modes that support large addresses
+(define_mode_iterator LADDR [QI HI SI DI SF DF])
+
+;; Attribute for the load instruction for GPRs, FPRs, and Altivec registers.
+(define_mode_attr LADDR_GLOAD [(SF "lwz") (DF "ld")])
+(define_mode_attr LADDR_FLOAD [(SF "lfs") (DF "lfd")])
+(define_mode_attr LADDR_VLOAD [(SF "lxssp") (DF "lxsd")])
+
+;; Attribute for the store instruction for GPRs, FPRs, and Altivec registers.
+(define_mode_attr LADDR_GSTORE [(SF "stw") (DF "std")])
+(define_mode_attr LADDR_FSTORE [(SF "stfs") (DF "stfd")])
+(define_mode_attr LADDR_VSTORE [(SF "stxssp") (DF "stxsd)")])
+
+;; Insns for large addresses.
+
+(define_insn "large_mov<mode>_load"
+ [(set (match_operand:QHSI 0 "base_reg_operand" "=b")
+ (match_operand:QHSI 1 "large_mem_operand" "wC"))
+ (unspec [(const_int 0)] UNSPEC_LADDR_LOAD)]
+ "TARGET_LARGE_ADDRESS && TARGET_POWERPC64"
+{
+ rtx reg = operands[0];
+ rtx mem = operands[1];
+ output_large_address_load_store (reg, mem, reg, "l<wd>z");
+ return "";
+}
+ [(set_attr "length" "8")
+ (set_attr "type" "load")])
+
+(define_insn "*large_mov<mode>_loadu_di"
+ [(set (match_operand:DI 0 "base_reg_operand" "=b")
+ (zero_extend:DI
+ (match_operand:QHSI 1 "large_mem_operand" "wC")))
+ (unspec [(const_int 0)] UNSPEC_LADDR_LOAD)]
+ "TARGET_LARGE_ADDRESS && TARGET_POWERPC64"
+{
+ rtx reg = operands[0];
+ rtx mem = operands[1];
+ output_large_address_load_store (reg, mem, reg, "l<wd>z");
+ return "";
+}
+ [(set_attr "length" "8")
+ (set_attr "type" "load")])
+
+(define_insn "*large_mov<mode>_loads_di"
+ [(set (match_operand:DI 0 "base_reg_operand" "=b")
+ (sign_extend:DI
+ (match_operand:HSI 1 "large_mem_operand" "wC")))
+ (unspec [(const_int 0)] UNSPEC_LADDR_LOAD)]
+ "TARGET_LARGE_ADDRESS && TARGET_POWERPC64"
+{
+ rtx reg = operands[0];
+ rtx mem = operands[1];
+ output_large_address_load_store (reg, mem, reg, "l<wd>a");
+ return "";
+}
+ [(set_attr "length" "8")
+ (set_attr "type" "load")])
+
+(define_insn "large_mov<mode>_store"
+ [(set (match_operand:QHSI 0 "large_mem_operand" "=wC")
+ (match_operand:QHSI 1 "int_reg_operand" "r"))
+ (unspec [(const_int 0)] UNSPEC_LADDR_STORE)
+ (clobber (match_scratch:DI 2 "=&b"))]
+ "TARGET_LARGE_ADDRESS && TARGET_POWERPC64"
+{
+ rtx mem = operands[0];
+ rtx reg = operands[1];
+ rtx tmp = operands[2];
+
+ output_large_address_load_store (reg, mem, tmp, "st<wd>");
+ return "";
+}
+ [(set_attr "length" "8")
+ (set_attr "type" "store")])
+
+(define_insn "large_movdi_load"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=b,*d,*wb")
+ (match_operand:DI 1 "large_mem_operand" "wC,wC,wC"))
+ (unspec [(const_int 0)] UNSPEC_LADDR_LOAD)
+ (clobber (match_scratch:DI 2 "=X,b,b"))]
+ "TARGET_LARGE_ADDRESS && TARGET_POWERPC64"
+{
+ rtx reg = operands[0];
+ rtx mem = operands[1];
+ rtx tmp = GET_CODE (operands[2]) == SCRATCH ? reg : operands[2];
+ static const char *const load[3] = { "ld", "lfd", "lxsd" };
+
+ output_large_address_load_store (reg, mem, tmp, load[which_alternative]);
+ return "";
+}
+ [(set_attr "length" "8")
+ (set_attr "type" "load,fpload,fpload")])
+
+;; Used by float<uns>di<mode>2_mem
+(define_insn "large_movdi_load_fp"
+ [(set (match_operand:DI 0 "vsx_register_operand" "=d,wb")
+ (match_operand:DI 1 "large_mem_operand" "wC,wC"))
+ (unspec [(const_int 1)] UNSPEC_LADDR_LOAD)
+ (clobber (match_operand:DI 2 "base_reg_operand" "=b,b"))]
+ "TARGET_LARGE_ADDRESS && TARGET_POWERPC64"
+{
+ rtx reg = operands[0];
+ rtx mem = operands[1];
+ rtx tmp = operands[2];
+ static const char *const load[3] = { "lfd", "lxsd" };
+
+ output_large_address_load_store (reg, mem, tmp, load[which_alternative]);
+ return "";
+}
+ [(set_attr "length" "8")
+ (set_attr "type" "fpload")])
+
+;; For store, separate the insns into two insns.
+(define_insn_and_split "large_movdi_store"
+ [(set (match_operand:DI 0 "large_mem_operand" "=wC,*wC,*wC")
+ (match_operand:DI 1 "gpc_reg_operand" "r,d,wb"))
+ (unspec [(const_int 0)] UNSPEC_LADDR_STORE)
+ (clobber (match_scratch:DI 2 "=&b,b,b"))]
+ "TARGET_LARGE_ADDRESS && TARGET_POWERPC64"
+ "#"
+ "&& reload_completed"
+ [(set (match_dup 2)
+ (match_dup 3))
+ (set (match_dup 4)
+ (match_dup 1))]
+{
+ rtx hi, lo, new_addr;
+ rtx mem = operands[0];
+ rtx addr = XEXP (mem, 0);
+ rtx tmp_reg = operands[2];
+ enum rtx_code add_code = split_large_address_hilo (addr, &hi, &lo);
+
+ new_addr = gen_rtx_fmt_ee (add_code, Pmode, tmp_reg, lo);
+ operands[3] = hi;
+ operands[4] = replace_equiv_address (mem, new_addr);
+}
+ [(set_attr "length" "8")
+ (set_attr "type" "store,fpstore,fpstore")])
+
+(define_insn "large_mov<mode>_load"
+ [(set (match_operand:SFDF 0 "gpc_reg_operand" "=d,wb,*b")
+ (match_operand:SFDF 1 "large_mem_operand" "wC,wC,wC"))
+ (unspec [(const_int 0)] UNSPEC_LADDR_LOAD)
+ (clobber (match_scratch:DI 2 "=b,b,X"))]
+ "TARGET_LARGE_ADDRESS && TARGET_POWERPC64"
+{
+ rtx reg = operands[0];
+ rtx mem = operands[1];
+ rtx tmp = GET_CODE (operands[2]) == SCRATCH ? reg : operands[2];
+ static const char *const fload[3] = {
+ "<LADDR_FLOAD>",
+ "<LADDR_VLOAD>",
+ "<LADDR_GLOAD>"
+ };
+
+ output_large_address_load_store (reg, mem, tmp,
+ fload[which_alternative]);
+ return "";
+}
+ [(set_attr "length" "8")
+ (set_attr "type" "fpload,fpload,load")])
+
+(define_insn "large_mov<mode>_store"
+ [(set (match_operand:SFDF 0 "large_mem_operand" "=wC,wC,wC")
+ (match_operand:SFDF 1 "gpc_reg_operand" "d,wb,*r"))
+ (unspec [(const_int 0)] UNSPEC_LADDR_STORE)
+ (clobber (match_scratch:DI 2 "=b,b,&b"))]
+ "TARGET_LARGE_ADDRESS && TARGET_POWERPC64"
+{
+ rtx mem = operands[0];
+ rtx reg = operands[1];
+ rtx tmp = operands[2];
+ static const char *const store[3] = {
+ "<LADDR_FSTORE>",
+ "<LADDR_VSTORE>",
+ "<LADDR_GSTORE>"
+ };
+
+ output_large_address_load_store (reg, mem, tmp, store[which_alternative]);
+ return "";
+}
+ [(set_attr "length" "8")
+ (set_attr "type" "fpstore,fpstore,store")])
+
+;; Split patterns run before register allocation to convert a large address
+;; into an appropriate insn. Assuming we have the appropriate fusion level, we
+;; try the integrated load/store first, and if that fails, split the address.
+
+(define_split
+ [(set (match_operand:LADDR 0 "gpc_reg_operand")
+ (match_operand:LADDR 1 "large_mem_operand"))]
+ "TARGET_LARGE_ADDRESS && TARGET_POWERPC64 && can_create_pseudo_p ()"
+ [(const_int 0)]
+{
+ rtx dest = operands[0];
+ rtx src = operands[1];
+
+ if (emit_large_address_load (dest, src, <MODE>mode))
+ DONE;
+
+ rtx tmp = gen_reg_rtx (DImode);
+ emit_insn (gen_rtx_SET (tmp, XEXP (src, 0)));
+ emit_insn (gen_rtx_SET (dest, replace_equiv_address (src, tmp)));
+ DONE;
+})
+
+(define_split
+ [(set (match_operand:DI 0 "base_reg_operand")
+ (zero_extend:DI
+ (match_operand:QHSI 1 "large_mem_operand")))]
+ "TARGET_LARGE_ADDRESS && TARGET_POWERPC64"
+ [(set (match_dup 0)
+ (zero_extend:DI
+ (unspec:QHSI [(match_dup 1)] UNSPEC_LADDR_LOAD)))])
+
+(define_split
+ [(set (match_operand:DI 0 "base_reg_operand")
+ (sign_extend:DI
+ (match_operand:HSI 1 "large_mem_operand")))]
+ "TARGET_LARGE_ADDRESS && TARGET_POWERPC64"
+ [(set (match_dup 0)
+ (sign_extend:DI
+ (unspec:HSI [(match_dup 1)] UNSPEC_LADDR_LOAD)))])
+
+(define_split
+ [(set (match_operand:LADDR 0 "large_mem_operand")
+ (match_operand:LADDR 1 "gpc_reg_operand"))]
+ "TARGET_LARGE_ADDRESS && TARGET_POWERPC64 && can_create_pseudo_p ()"
+ [(const_int 0)]
+{
+ rtx dest = operands[0];
+ rtx src = operands[1];
+
+ if (emit_large_address_store (dest, src, <MODE>mode))
+ DONE;
+
+ rtx tmp = gen_reg_rtx (DImode);
+ emit_insn (gen_rtx_SET (tmp, XEXP (dest, 0)));
+ emit_insn (gen_rtx_SET (replace_equiv_address (dest, tmp), src));
+ DONE;
+})
+
+
;; Start with fixed-point load and store insns. Here we put only the more
;; complex forms. Basic data transfer is done later.
(define_insn "zero_extendqi<mode>2"
[(set (match_operand:EXTQI 0 "gpc_reg_operand" "=r,r,^wJwK,^wK")
- (zero_extend:EXTQI (match_operand:QI 1 "reg_or_mem_operand" "m,r,Z,wK")))]
+ (zero_extend:EXTQI (match_operand:QI 1 "reg_or_mem_operand" "wN,r,Z,wK")))]
""
"@
lbz%U1%X1 %0,%1
@@ -761,7 +1011,7 @@
(define_insn "zero_extendhi<mode>2"
[(set (match_operand:EXTHI 0 "gpc_reg_operand" "=r,r,^wJwK,^wK")
- (zero_extend:EXTHI (match_operand:HI 1 "reg_or_mem_operand" "m,r,Z,wK")))]
+ (zero_extend:EXTHI (match_operand:HI 1 "reg_or_mem_operand" "wN,r,Z,wK")))]
""
"@
lhz%U1%X1 %0,%1
@@ -814,7 +1064,7 @@
(define_insn "zero_extendsi<mode>2"
[(set (match_operand:EXTSI 0 "gpc_reg_operand" "=r,r,wz,wu,wj,r,wJwK")
- (zero_extend:EXTSI (match_operand:SI 1 "reg_or_mem_operand" "m,r,Z,Z,r,wIwH,wJwK")))]
+ (zero_extend:EXTSI (match_operand:SI 1 "reg_or_mem_operand" "wN,r,Z,Z,r,wIwH,wJwK")))]
""
"@
lwz%U1%X1 %0,%1
@@ -927,7 +1177,7 @@
(define_insn "*extendhi<mode>2"
[(set (match_operand:EXTHI 0 "gpc_reg_operand" "=r,r,?*wK,?*wK")
- (sign_extend:EXTHI (match_operand:HI 1 "reg_or_mem_operand" "m,r,Z,wK")))]
+ (sign_extend:EXTHI (match_operand:HI 1 "reg_or_mem_operand" "wN,r,Z,wK")))]
""
"@
lha%U1%X1 %0,%1
@@ -4201,127 +4451,172 @@
(set_attr "dot" "yes")
(set_attr "length" "4,8")])
+(define_insn "ashdi3_extswsli"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (ashift:DI
+ (sign_extend:DI (match_operand:SI 1 "gpc_reg_operand" "r"))
+ (match_operand:DI 2 "u6bit_cint_operand" "n")))]
+ "TARGET_EXTSWSLI"
+ "extswsli %0,%1,%2"
+ [(set_attr "type" "shift")
+ (set_attr "maybe_var_shift" "no")])
+
;; Pretend we have a memory form of extswsli until register allocation is done
;; so that we use LWZ to load the value from memory, instead of LWA.
-(define_insn_and_split "ashdi3_extswsli"
- [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
+(define_insn_and_split "*ashdi3_extswsli_mem"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r,b")
(ashift:DI
- (sign_extend:DI (match_operand:SI 1 "reg_or_mem_operand" "r,m"))
+ (sign_extend:DI (match_operand:SI 1 "any_mem_operand" "wN,wC"))
(match_operand:DI 2 "u6bit_cint_operand" "n,n")))]
"TARGET_EXTSWSLI"
- "@
- extswsli %0,%1,%2
- #"
- "&& reload_completed && MEM_P (operands[1])"
- [(set (match_dup 3)
- (match_dup 1))
- (set (match_dup 0)
- (ashift:DI (sign_extend:DI (match_dup 3))
- (match_dup 2)))]
+ "#"
+ "&& reload_completed"
+ [(const_int 0)]
{
- operands[3] = gen_lowpart (SImode, operands[0]);
+ rtx dest = operands[0];
+ rtx dest_si = gen_lowpart (SImode, dest);
+ rtx mem = operands[1];
+ rtx shift = operands[2];
+
+ if (!large_mem_operand (mem, SImode))
+ emit_insn (gen_rtx_SET (dest_si, mem));
+ else
+ emit_insn (gen_large_movsi_load (dest_si, mem));
+
+ emit_insn (gen_ashdi3_extswsli (dest, dest_si, shift));
+ DONE;
}
[(set_attr "type" "shift")
- (set_attr "maybe_var_shift" "no")])
-
+ (set_attr "maybe_var_shift" "no")
+ (set_attr "length" "8,12")])
(define_insn_and_split "ashdi3_extswsli_dot"
- [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y,?x,??y")
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
(compare:CC
(ashift:DI
- (sign_extend:DI (match_operand:SI 1 "reg_or_mem_operand" "r,r,m,m"))
- (match_operand:DI 2 "u6bit_cint_operand" "n,n,n,n"))
+ (sign_extend:DI (match_operand:SI 1 "gpc_reg_operand" "r,r"))
+ (match_operand:DI 2 "u6bit_cint_operand" "n,n"))
(const_int 0)))
- (clobber (match_scratch:DI 0 "=r,r,r,r"))]
+ (clobber (match_scratch:DI 0 "=r,r"))]
"TARGET_EXTSWSLI"
"@
extswsli. %0,%1,%2
- #
- #
#"
- "&& reload_completed
- && (cc_reg_not_cr0_operand (operands[3], CCmode)
- || memory_operand (operands[1], SImode))"
+ "&& reload_completed && cc_reg_not_cr0_operand (operands[3], CCmode)"
[(pc)]
{
rtx dest = operands[0];
rtx src = operands[1];
rtx shift = operands[2];
rtx cr = operands[3];
- rtx src2;
- if (!MEM_P (src))
- src2 = src;
- else
- {
- src2 = gen_lowpart (SImode, dest);
- emit_move_insn (src2, src);
- }
+ emit_insn (gen_ashdi3_extswsli (dest, src, shift));
+ emit_insn (gen_rtx_SET (cr, gen_rtx_COMPARE (CCmode, dest, const0_rtx)));
+ DONE;
+}
+ [(set_attr "type" "shift")
+ (set_attr "maybe_var_shift" "no")
+ (set_attr "dot" "yes")
+ (set_attr "length" "4,8")])
- if (REGNO (cr) == CR0_REGNO)
- {
- emit_insn (gen_ashdi3_extswsli_dot2 (dest, src2, shift, cr));
- DONE;
- }
+(define_insn_and_split "*ashdi3_extswsli_dot_mem"
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y,x,?y")
+ (compare:CC
+ (ashift:DI
+ (sign_extend:DI
+ (match_operand:SI 1 "any_mem_operand" "wN,wN,wC,wC"))
+ (match_operand:DI 2 "u6bit_cint_operand" "n,n,n,n"))
+ (const_int 0)))
+ (clobber (match_scratch:DI 0 "=r,r,b,b"))]
+ "TARGET_EXTSWSLI"
+ "#"
+ "&& reload_completed"
+ [(const_int 0)]
+{
+ rtx dest = operands[0];
+ rtx dest_si = gen_lowpart (SImode, dest);
+ rtx mem = operands[1];
+ rtx shift = operands[2];
+ rtx cr = operands[3];
- emit_insn (gen_ashdi3_extswsli (dest, src2, shift));
- emit_insn (gen_rtx_SET (cr, gen_rtx_COMPARE (CCmode, dest, const0_rtx)));
+ if (!large_mem_operand (mem, SImode))
+ emit_insn (gen_rtx_SET (dest_si, mem));
+ else
+ emit_insn (gen_large_movsi_load (dest_si, mem));
+
+ emit_insn (gen_ashdi3_extswsli_dot2 (dest, dest_si, shift, cr));
DONE;
}
[(set_attr "type" "shift")
(set_attr "maybe_var_shift" "no")
(set_attr "dot" "yes")
- (set_attr "length" "4,8,8,12")])
+ (set_attr "length" "8,12,12,16")])
(define_insn_and_split "ashdi3_extswsli_dot2"
- [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y,?x,??y")
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
(compare:CC
(ashift:DI
- (sign_extend:DI (match_operand:SI 1 "reg_or_mem_operand" "r,r,m,m"))
- (match_operand:DI 2 "u6bit_cint_operand" "n,n,n,n"))
+ (sign_extend:DI (match_operand:SI 1 "gpc_reg_operand" "r,r"))
+ (match_operand:DI 2 "u6bit_cint_operand" "n,n"))
(const_int 0)))
- (set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r,r")
+ (set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
(ashift:DI (sign_extend:DI (match_dup 1))
(match_dup 2)))]
"TARGET_EXTSWSLI"
"@
extswsli. %0,%1,%2
- #
- #
#"
- "&& reload_completed
- && (cc_reg_not_cr0_operand (operands[3], CCmode)
- || memory_operand (operands[1], SImode))"
- [(pc)]
+ "&& reload_completed && cc_reg_not_cr0_operand (operands[3], CCmode)"
+ [(const_int 0)]
{
rtx dest = operands[0];
rtx src = operands[1];
rtx shift = operands[2];
rtx cr = operands[3];
- rtx src2;
- if (!MEM_P (src))
- src2 = src;
- else
- {
- src2 = gen_lowpart (SImode, dest);
- emit_move_insn (src2, src);
- }
+ emit_insn (gen_ashdi3_extswsli (dest, src, shift));
+ emit_insn (gen_rtx_SET (cr, gen_rtx_COMPARE (CCmode, dest, const0_rtx)));
+ DONE;
+}
+ [(set_attr "type" "shift")
+ (set_attr "maybe_var_shift" "no")
+ (set_attr "dot" "yes")
+ (set_attr "length" "4,8")])
- if (REGNO (cr) == CR0_REGNO)
- {
- emit_insn (gen_ashdi3_extswsli_dot2 (dest, src2, shift, cr));
- DONE;
- }
+(define_insn_and_split "*ashdi3_extswsli_dot2_mem"
+ [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y,x,?y")
+ (compare:CC
+ (ashift:DI
+ (sign_extend:DI
+ (match_operand:SI 1 "any_mem_operand" "wN,wN,wC,wC"))
+ (match_operand:DI 2 "u6bit_cint_operand" "n,n,n,n"))
+ (const_int 0)))
+ (set (match_operand:DI 0 "gpc_reg_operand" "=r,r,b,b")
+ (ashift:DI (sign_extend:DI (match_dup 1))
+ (match_dup 2)))]
+ "TARGET_EXTSWSLI"
+ "#"
+ "&& reload_completed"
+ [(const_int 0)]
+{
+ rtx dest = operands[0];
+ rtx dest_si = gen_lowpart (SImode, dest);
+ rtx mem = operands[1];
+ rtx shift = operands[2];
+ rtx cr = operands[3];
- emit_insn (gen_ashdi3_extswsli (dest, src2, shift));
- emit_insn (gen_rtx_SET (cr, gen_rtx_COMPARE (CCmode, dest, const0_rtx)));
+ if (!large_mem_operand (mem, SImode))
+ emit_insn (gen_rtx_SET (dest_si, mem));
+ else
+ emit_insn (gen_large_movsi_load (dest_si, mem));
+
+ emit_insn (gen_ashdi3_extswsli_dot2 (dest, dest_si, shift, cr));
DONE;
}
[(set_attr "type" "shift")
(set_attr "maybe_var_shift" "no")
(set_attr "dot" "yes")
- (set_attr "length" "4,8,8,12")])
+ (set_attr "length" "8,12,12,16")])
(define_insn "lshr<mode>3"
[(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
@@ -4693,12 +4988,48 @@
{
if (HONOR_SNANS (SFmode))
operands[1] = force_reg (SFmode, operands[1]);
+
+ else if (TARGET_LARGE_ADDRESS && TARGET_POWERPC64
+ && large_mem_operand (operands[1], SFmode))
+ {
+ if (TARGET_P9_FUSION)
+ {
+ emit_insn (gen_large_extendsfdf (operands[0], operands[1]));
+ DONE;
+ }
+ else
+ {
+ rtx tmp = gen_reg_rtx (DImode);
+ rtx new_addr = split_large_address (XEXP (operands[1], 0), tmp);
+ operands[1] = replace_equiv_address (operands[1], new_addr);
+ }
+ }
})
+(define_insn "large_extendsfdf"
+ [(set (match_operand:DF 0 "gpc_reg_operand" "=d,wb")
+ (float_extend:DF
+ (unspec:SF [(match_operand:SF 1 "large_mem_operand" "wC,wC")]
+ UNSPEC_LADDR_LOAD)))
+ (clobber (match_scratch:DI 2 "=b,b"))]
+ "TARGET_LARGE_ADDRESS && TARGET_POWERPC64 && !HONOR_SNANS (SFmode)
+ && TARGET_P9_FUSION"
+{
+ rtx reg = operands[0];
+ rtx mem = operands[1];
+ rtx tmp = operands[2];
+ static const char *const load_ext[] = { "lfs", "lxssp" };
+ output_large_address_load_store (reg, mem, tmp, load_ext[which_alternative]);
+ return "";
+}
+ [(set_attr "type" "fpload")
+ (set_attr "length" "8")])
+
(define_insn_and_split "*extendsfdf2_fpr"
[(set (match_operand:DF 0 "gpc_reg_operand" "=d,?d,d,ws,?ws,wu,wb")
- (float_extend:DF (match_operand:SF 1 "reg_or_mem_operand" "0,f,m,0,wy,Z,wY")))]
- "TARGET_HARD_FLOAT && !HONOR_SNANS (SFmode)"
+ (float_extend:DF (match_operand:SF 1 "reg_or_mem_operand" "0,f,wN,0,wy,Z,wY")))]
+ "TARGET_HARD_FLOAT && !HONOR_SNANS (SFmode)
+ && !large_mem_operand (operands[1], SFmode)"
"@
#
fmr %0,%1
@@ -5586,7 +5917,7 @@
; register allocation so that it can allocate the memory slot if it
; needed
(define_insn_and_split "fix_trunc<mode>si2_stfiwx"
- [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rwN")
(fix:SI (match_operand:SFDF 1 "gpc_reg_operand" "d")))
(clobber (match_scratch:DI 2 "=d"))]
"TARGET_HARD_FLOAT && TARGET_STFIWX && can_create_pseudo_p ()
@@ -5732,7 +6063,7 @@
})
(define_insn_and_split "fixuns_trunc<mode>si2_stfiwx"
- [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rwN")
(unsigned_fix:SI (match_operand:SFDF 1 "gpc_reg_operand" "d")))
(clobber (match_scratch:DI 2 "=d"))]
"TARGET_HARD_FLOAT && TARGET_FCTIWUZ
@@ -6017,52 +6348,53 @@
xscvsxddp %x0,%x1"
[(set_attr "type" "fp")])
-; Allow the combiner to merge source memory operands to the conversion so that
-; the optimizer/register allocator doesn't try to load the value too early in a
-; GPR and then use store/load to move it to a FPR and suffer from a store-load
-; hit. We will split after reload to avoid the trip through the GPRs
-
-(define_insn_and_split "*floatdidf2_mem"
- [(set (match_operand:DF 0 "gpc_reg_operand" "=d,ws")
- (float:DF (match_operand:DI 1 "memory_operand" "m,Z")))
- (clobber (match_scratch:DI 2 "=d,wi"))]
- "TARGET_HARD_FLOAT && TARGET_FCFID"
- "#"
- "&& reload_completed"
- [(set (match_dup 2) (match_dup 1))
- (set (match_dup 0) (float:DF (match_dup 2)))]
- ""
- [(set_attr "length" "8")
- (set_attr "type" "fpload")])
-
-(define_expand "floatunsdidf2"
- [(set (match_operand:DF 0 "gpc_reg_operand")
- (unsigned_float:DF
- (match_operand:DI 1 "gpc_reg_operand")))]
- "TARGET_HARD_FLOAT && TARGET_FCFIDU"
- "")
-
-(define_insn "*floatunsdidf2_fcfidu"
+(define_insn "floatunsdidf2"
[(set (match_operand:DF 0 "gpc_reg_operand" "=d,ws")
(unsigned_float:DF (match_operand:DI 1 "gpc_reg_operand" "d,wi")))]
"TARGET_HARD_FLOAT && TARGET_FCFIDU"
"@
fcfidu %0,%1
xscvuxddp %x0,%x1"
- [(set_attr "type" "fp")
- (set_attr "length" "4")])
+ [(set_attr "type" "fp")])
-(define_insn_and_split "*floatunsdidf2_mem"
- [(set (match_operand:DF 0 "gpc_reg_operand" "=d,ws")
- (unsigned_float:DF (match_operand:DI 1 "memory_operand" "m,Z")))
- (clobber (match_scratch:DI 2 "=d,wi"))]
- "TARGET_HARD_FLOAT && (TARGET_FCFIDU || VECTOR_UNIT_VSX_P (DFmode))"
+; Allow the combiner to merge source memory operands to the conversion so that
+; the optimizer/register allocator doesn't try to load the value too early in a
+; GPR and then use store/load or direct move to move it to a FPR and suffer
+; from a store-load hit. We will split after reload to avoid the trip through
+; the GPRs. Add support for large addresses that need to load the upper bits.
+
+(define_insn_and_split "*float<uns>di<mode>2_mem"
+ [(set (match_operand:SFDF 0 "gpc_reg_operand" "=d,<Fv>,<Fv>,wb,<Fv>,wb")
+ (any_float:SFDF
+ (match_operand:DI 1 "any_mem_operand" "wN,wN, Z, wY,wC,wC")))
+ (clobber (match_scratch:DI 2 "=d,d, wi, wi,d, wi"))
+ (clobber (match_scratch:DI 3 "=X,X, X, X, &b,&b"))]
+ "TARGET_HARD_FLOAT && <FP_CVT_P> && <SI_CONVERT_FP>"
"#"
"&& reload_completed"
[(set (match_dup 2) (match_dup 1))
- (set (match_dup 0) (unsigned_float:DF (match_dup 2)))]
- ""
- [(set_attr "length" "8")
+ (set (match_dup 0) (any_float:SFDF (match_dup 2)))]
+{
+ rtx mem = operands[1];
+ rtx addr = XEXP (mem, 0);
+ if (large_address_valid (addr, DImode))
+ {
+ rtx base_reg = operands[3];
+
+ /* If we have power9 fusion, keep the ADDIS and load together. */
+ if (TARGET_P9_FUSION)
+ {
+ rtx fpr_tmp = operands[2];
+ emit_insn (gen_large_movdi_load_fp (fpr_tmp, mem, base_reg));
+ emit_insn (gen_float<uns>di<mode>2 (operands[0], fpr_tmp));
+ DONE;
+ }
+
+ rtx new_addr = split_large_address (addr, base_reg);
+ operands[1] = replace_equiv_address (mem, new_addr);
+ }
+}
+ [(set_attr "length" "8,8,8,8,12,12")
(set_attr "type" "fpload")])
(define_expand "floatdisf2"
@@ -6095,21 +6427,6 @@
xscvsxdsp %x0,%x1"
[(set_attr "type" "fp")])
-(define_insn_and_split "*floatdisf2_mem"
- [(set (match_operand:SF 0 "gpc_reg_operand" "=f,wy,wy")
- (float:SF (match_operand:DI 1 "memory_operand" "m,m,Z")))
- (clobber (match_scratch:DI 2 "=d,d,wi"))]
- "TARGET_HARD_FLOAT && TARGET_FCFIDS"
- "#"
- "&& reload_completed"
- [(pc)]
-{
- emit_move_insn (operands[2], operands[1]);
- emit_insn (gen_floatdisf2_fcfids (operands[0], operands[2]));
- DONE;
-}
- [(set_attr "length" "8")])
-
;; This is not IEEE compliant if rounding mode is "round to nearest".
;; If the DI->DF conversion is inexact, then it's possible to suffer
;; from double rounding.
@@ -6676,13 +6993,13 @@
(define_insn "*movsi_internal1"
[(set (match_operand:SI 0 "nonimmediate_operand"
"=r, r, r, ?*wI, ?*wH,
- m, ?Z, ?Z, r, r,
+ wN, ?Z, ?Z, r, r,
r, ?*wIwH, ?*wJwK, ?*wJwK, ?*wu,
?*wJwK, ?*wH, ?*wK, ?*wIwH, ?r,
r, *c*l, *h, *h")
(match_operand:SI 1 "input_operand"
- "r, U, m, Z, Z,
+ "r, U, wN, Z, Z,
r, wI, wH, I, L,
n, wIwH, O, wM, wB,
O, wM, wS, r, wIwH,
@@ -6749,12 +7066,12 @@
(define_insn_and_split "movsi_from_sf"
[(set (match_operand:SI 0 "nonimmediate_operand"
- "=r, r, ?*wI, ?*wH, m,
- m, wY, Z, r, ?*wIwH,
+ "=r, r, ?*wI, ?*wH, wN,
+ wN, wY, Z, r, ?*wIwH,
wIwH")
(unspec:SI [(match_operand:SF 1 "input_operand"
- "r, m, Z, Z, r,
+ "r, wN, Z, Z, r,
f, wb, wu, wIwH, wIwH,
r")]
UNSPEC_SI_FROM_SF))
@@ -6765,6 +7082,8 @@
X"))]
"TARGET_NO_SF_SUBREG
+ && !large_mem_operand (operands[0], SImode)
+ && !large_mem_operand (operands[1], SFmode)
&& (register_operand (operands[0], SImode)
|| register_operand (operands[1], SFmode))"
"@
@@ -6816,7 +7135,7 @@
(zero_extend:DI
(unspec:SI [(match_operand:SF 1 "input_operand"
- "r, m, Z, Z, wIwH,
+ "r, wN, Z, Z, wIwH,
wIwH, r")]
UNSPEC_SI_FROM_SF)))
@@ -6825,6 +7144,7 @@
wIwH, X"))]
"TARGET_DIRECT_MOVE_64BIT
+ && !large_mem_operand (operands[1], SFmode)
&& (register_operand (operands[0], DImode)
|| register_operand (operands[1], SImode))"
"@
@@ -6954,12 +7274,12 @@
;; MTVSRWZ MF%1 MT%1 NOP
(define_insn "*mov<mode>_internal"
[(set (match_operand:QHI 0 "nonimmediate_operand"
- "=r, r, ?*wJwK, m, Z, r,
+ "=r, r, ?*wJwK, wN, Z, r,
?*wJwK, ?*wJwK, ?*wJwK, ?*wK, ?*wK, r,
?*wJwK, r, *c*l, *h")
(match_operand:QHI 1 "input_operand"
- "r, m, Z, r, wJwK, i,
+ "r, wN, Z, r, wJwK, i,
wJwK, O, wM, wB, wS, ?*wJwK,
r, *h, r, 0"))]
@@ -7095,11 +7415,11 @@
(define_insn "movsf_hardfloat"
[(set (match_operand:SF 0 "nonimmediate_operand"
- "=!r, f, wb, wu, m, wY,
- Z, m, ww, !r, f, ww,
+ "=!r, f, wb, wu, wN, wY,
+ Z, wN, ww, !r, f, ww,
!r, *c*l, !r, *h")
(match_operand:SF 1 "input_operand"
- "m, m, wY, Z, f, wb,
+ "wN, wN, wY, Z, f, wb,
wu, r, j, j, f, ww,
r, r, *h, 0"))]
"TARGET_HARD_FLOAT && move_valid_p (operands[0], operands[1])"
@@ -7129,10 +7449,10 @@
;; FMR MR MT%0 MF%1 NOP
(define_insn "movsd_hardfloat"
[(set (match_operand:SD 0 "nonimmediate_operand"
- "=!r, wz, m, Z, ?wh, ?r,
+ "=!r, wz, wN, Z, ?wh, ?r,
f, !r, *c*l, !r, *h")
(match_operand:SD 1 "input_operand"
- "m, Z, r, wx, r, wh,
+ "wN, Z, r, wx, r, wh,
f, r, r, *h, 0"))]
"TARGET_HARD_FLOAT && move_valid_p (operands[0], operands[1])"
"@
@@ -7155,11 +7475,11 @@
;; LIS G-const. F/n-const NOP
(define_insn "*mov<mode>_softfloat"
[(set (match_operand:FMOVE32 0 "nonimmediate_operand"
- "=r, cl, r, r, m, r,
+ "=r, cl, r, r, wN, r,
r, r, r, *h")
(match_operand:FMOVE32 1 "input_operand"
- "r, r, h, m, r, I,
+ "r, r, h, wN, r, I,
L, G, Fn, 0"))]
"TARGET_SOFT_FLOAT && move_valid_p (operands[0], operands[1])"
@@ -7201,11 +7521,11 @@
;; STXSIWX GPR->VSX VSX->GPR GPR->GPR
(define_insn_and_split "movsf_from_si"
[(set (match_operand:SF 0 "nonimmediate_operand"
- "=!r, f, wb, wu, m, Z,
+ "=!r, f, wb, wu, wN, Z,
Z, wy, ?r, !r")
(unspec:SF [(match_operand:SI 1 "input_operand"
- "m, m, wY, Z, r, f,
+ "wN, wN, wY, Z, r, f,
wu, r, wy, r")]
UNSPEC_SF_FROM_SI))
@@ -7214,6 +7534,8 @@
X, r, X, X"))]
"TARGET_NO_SF_SUBREG
+ && !large_mem_operand (operands[0], SFmode)
+ && !large_mem_operand (operands[0], SImode)
&& (register_operand (operands[0], SFmode)
|| register_operand (operands[1], SImode))"
"@
@@ -7347,15 +7669,14 @@
;; LXSD STXSD XXLOR XXLXOR GPR<-0
;; LWZ STW MR
-
(define_insn "*mov<mode>_hardfloat32"
[(set (match_operand:FMOVE64 0 "nonimmediate_operand"
- "=m, d, d, <f64_p9>, wY,
+ "=wN, d, d, <f64_p9>, wY,
<f64_av>, Z, <f64_vsx>, <f64_vsx>, !r,
Y, r, !r")
(match_operand:FMOVE64 1 "input_operand"
- "d, m, d, wY, <f64_p9>,
+ "d, wN, d, wY, <f64_p9>,
Z, <f64_av>, <f64_vsx>, <zero_fp>, <zero_fp>,
r, Y, r"))]
@@ -7395,7 +7716,7 @@
(match_operand:FMOVE64 1 "input_operand"
"r, Y, r, G, H, F"))]
- "! TARGET_POWERPC64 && TARGET_SOFT_FLOAT
+ "!TARGET_POWERPC64 && TARGET_SOFT_FLOAT
&& move_valid_p (operands[0], operands[1])"
"#"
[(set_attr "type"
@@ -7414,13 +7735,13 @@
(define_insn "*mov<mode>_hardfloat64"
[(set (match_operand:FMOVE64 0 "nonimmediate_operand"
- "=m, d, d, <f64_p9>, wY,
+ "=wN, d, d, <f64_p9>, wY,
<f64_av>, Z, <f64_vsx>, <f64_vsx>, !r,
Y, r, !r, *c*l, !r,
*h, r, wg, r, <f64_dm>")
(match_operand:FMOVE64 1 "input_operand"
- "d, m, d, wY, <f64_p9>,
+ "d, wN, d, wY, <f64_p9>,
Z, <f64_av>, <f64_vsx>, <zero_fp>, <zero_fp>,
r, Y, r, r, h,
0, wg, r, <f64_dm>, r"))]
@@ -7507,8 +7828,8 @@
;; problematical. Don't allow direct move for this case.
(define_insn_and_split "*mov<mode>_64bit_dm"
- [(set (match_operand:FMOVE128_FPR 0 "nonimmediate_operand" "=m,d,d,d,Y,r,r,r,wh")
- (match_operand:FMOVE128_FPR 1 "input_operand" "d,m,d,<zero_fp>,r,<zero_fp>Y,r,wh,r"))]
+ [(set (match_operand:FMOVE128_FPR 0 "nonimmediate_operand" "=wN,d,d,d,Y,r,r,r,wh")
+ (match_operand:FMOVE128_FPR 1 "input_operand" "d,wN,d,<zero_fp>,r,<zero_fp>Y,r,wh,r"))]
"TARGET_HARD_FLOAT && TARGET_POWERPC64 && FLOAT128_2REG_P (<MODE>mode)
&& (<MODE>mode != TDmode || WORDS_BIG_ENDIAN)
&& (gpc_reg_operand (operands[0], <MODE>mode)
@@ -7520,8 +7841,8 @@
[(set_attr "length" "8,8,8,8,12,12,8,8,8")])
(define_insn_and_split "*movtd_64bit_nodm"
- [(set (match_operand:TD 0 "nonimmediate_operand" "=m,d,d,Y,r,r")
- (match_operand:TD 1 "input_operand" "d,m,d,r,Y,r"))]
+ [(set (match_operand:TD 0 "nonimmediate_operand" "=wN,d,d,Y,r,r")
+ (match_operand:TD 1 "input_operand" "d,wN,d,r,Y,r"))]
"TARGET_HARD_FLOAT && TARGET_POWERPC64 && !WORDS_BIG_ENDIAN
&& (gpc_reg_operand (operands[0], TDmode)
|| gpc_reg_operand (operands[1], TDmode))"
@@ -7532,8 +7853,8 @@
[(set_attr "length" "8,8,8,12,12,8")])
(define_insn_and_split "*mov<mode>_32bit"
- [(set (match_operand:FMOVE128_FPR 0 "nonimmediate_operand" "=m,d,d,d,Y,r,r")
- (match_operand:FMOVE128_FPR 1 "input_operand" "d,m,d,<zero_fp>,r,<zero_fp>Y,r"))]
+ [(set (match_operand:FMOVE128_FPR 0 "nonimmediate_operand" "=wN,d,d,d,Y,r,r")
+ (match_operand:FMOVE128_FPR 1 "input_operand" "d,wN,d,<zero_fp>,r,<zero_fp>Y,r"))]
"TARGET_HARD_FLOAT && !TARGET_POWERPC64
&& (FLOAT128_2REG_P (<MODE>mode)
|| int_reg_operand_not_pseudo (operands[0], <MODE>mode)
@@ -7593,8 +7914,8 @@
(define_insn_and_split "extenddf<mode>2_fprs"
[(set (match_operand:IBM128 0 "gpc_reg_operand" "=d,d,&d")
(float_extend:IBM128
- (match_operand:DF 1 "nonimmediate_operand" "d,m,d")))
- (use (match_operand:DF 2 "nonimmediate_operand" "m,m,d"))]
+ (match_operand:DF 1 "nonimmediate_operand" "d,wN,d")))
+ (use (match_operand:DF 2 "nonimmediate_operand" "wN,wN,d"))]
"!TARGET_VSX && TARGET_HARD_FLOAT
&& TARGET_LONG_DOUBLE_128 && FLOAT128_IBM_P (<MODE>mode)"
"#"
@@ -7612,8 +7933,9 @@
(define_insn_and_split "extenddf<mode>2_vsx"
[(set (match_operand:IBM128 0 "gpc_reg_operand" "=d,d")
(float_extend:IBM128
- (match_operand:DF 1 "nonimmediate_operand" "ws,m")))]
- "TARGET_LONG_DOUBLE_128 && TARGET_VSX && FLOAT128_IBM_P (<MODE>mode)"
+ (match_operand:DF 1 "nonimmediate_operand" "ws,wN")))]
+ "TARGET_LONG_DOUBLE_128 && TARGET_VSX && FLOAT128_IBM_P (<MODE>mode)
+ && !large_mem_operand (operands[1], DFmode)"
"#"
"&& reload_completed"
[(set (match_dup 2) (match_dup 1))
@@ -8511,13 +8833,13 @@
(define_insn "*movdi_internal32"
[(set (match_operand:DI 0 "nonimmediate_operand"
- "=Y, r, r, m, ^d, ^d,
+ "=Y, r, r, wN, ^d, ^d,
r, wY, Z, ^wb, $wv, ^wi,
*wo, *wo, *wv, *wi, *wi, *wv,
*wv")
(match_operand:DI 1 "input_operand"
- "r, Y, r, ^d, m, ^d,
+ "r, Y, r, ^d, wN, ^d,
IJKnGHF, ^wb, $wv, wY, Z, ^wi,
Oj, wM, OjwM, Oj, wM, wS,
wB"))]
@@ -8585,14 +8907,14 @@
(define_insn "*movdi_internal64"
[(set (match_operand:DI 0 "nonimmediate_operand"
"=YZ, r, r, r, r, r,
- m, ^d, ^d, wY, Z, $wb,
+ wN, ^d, ^d, wY, Z, $wb,
$wv, ^wi, *wo, *wo, *wv, *wi,
*wi, *wv, *wv, r, *h, *h,
?*r, ?*wg, ?*r, ?*wj")
(match_operand:DI 1 "input_operand"
"r, YZ, r, I, L, nF,
- ^d, m, ^d, ^wb, $wv, wY,
+ ^d, wN, ^d, ^wb, $wv, wY,
Z, ^wi, Oj, wM, OjwM, Oj,
wM, wS, wB, *h, r, 0,
wg, r, wj, r"))]
@@ -10191,6 +10513,14 @@
"TARGET_XCOFF && TARGET_CMODEL != CMODEL_SMALL"
"la %0,%2@l(%1)")
+(define_insn "*high_plus_int"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=b*r")
+ (high:DI
+ (plus:DI (match_operand:DI 1 "gpc_reg_operand" "r")
+ (match_operand:DI 2 "s32bit_cint_operand" "n"))))]
+ "TARGET_POWERPC64"
+ "addis %0,%1,%v2")
+
(define_insn_and_split "*tocref<mode>"
[(set (match_operand:P 0 "gpc_reg_operand" "=b")
(match_operand:P 1 "small_toc_ref" "R"))]
@@ -11056,9 +11386,9 @@
})
(define_insn "probe_stack_<mode>"
- [(set (match_operand:P 0 "memory_operand" "=m")
+ [(set (match_operand:P 0 "memory_operand" "=wN")
(unspec:P [(const_int 0)] UNSPEC_PROBE_STACK))]
- ""
+ "!large_mem_operand (operands[0], <MODE>mode)"
{
operands[1] = gen_rtx_REG (Pmode, 0);
return "st<wd>%U0%X0 %1,%0";
@@ -11438,10 +11768,10 @@
})
(define_insn "stack_protect_setsi"
- [(set (match_operand:SI 0 "memory_operand" "=m")
+ [(set (match_operand:SI 0 "memory_operand" "=wN")
(unspec:SI [(match_operand:SI 1 "memory_operand" "m")] UNSPEC_SP_SET))
(set (match_scratch:SI 2 "=&r") (const_int 0))]
- "TARGET_32BIT"
+ "TARGET_32BIT && !large_mem_operand (operands[0], SImode)"
"lwz%U1%X1 %2,%1\;stw%U0%X0 %2,%0\;li %2,0"
[(set_attr "type" "three")
(set_attr "length" "12")])
@@ -11481,12 +11811,14 @@
(define_insn "stack_protect_testsi"
[(set (match_operand:CCEQ 0 "cc_reg_operand" "=x,?y")
- (unspec:CCEQ [(match_operand:SI 1 "memory_operand" "m,m")
- (match_operand:SI 2 "memory_operand" "m,m")]
+ (unspec:CCEQ [(match_operand:SI 1 "memory_operand" "wN,wN")
+ (match_operand:SI 2 "memory_operand" "wN,wN")]
UNSPEC_SP_TEST))
(set (match_scratch:SI 4 "=r,r") (const_int 0))
(clobber (match_scratch:SI 3 "=&r,&r"))]
- "TARGET_32BIT"
+ "TARGET_32BIT
+ && !large_mem_operand (operands[1], SImode)
+ && !large_mem_operand (operands[2], SImode)"
"@
lwz%U1%X1 %3,%1\;lwz%U2%X2 %4,%2\;xor. %3,%3,%4\;li %4,0
lwz%U1%X1 %3,%1\;lwz%U2%X2 %4,%2\;cmplw %0,%3,%4\;li %3,0\;li %4,0"
@@ -12655,7 +12987,7 @@
(const_int 1))
(label_ref (match_operand 0))
(pc)))
- (set (match_operand:P 2 "nonimmediate_operand" "=1,*r,m,*d*wi*c*l")
+ (set (match_operand:P 2 "nonimmediate_operand" "=1,*r,wN,*d*wi*c*l")
(plus:P (match_dup 1)
(const_int -1)))
(clobber (match_scratch:CC 3 "=X,&x,&x,&x"))
@@ -12722,7 +13054,7 @@
(const_int 0)]))
(label_ref (match_operand 0))
(pc)))
- (set (match_operand:P 2 "nonimmediate_operand" "=1,*r,m,*d*wi*c*l")
+ (set (match_operand:P 2 "nonimmediate_operand" "=1,*r,wN,*d*wi*c*l")
(plus:P (match_dup 1)
(const_int -1)))
(clobber (match_scratch:P 5 "=X,X,&r,r"))
@@ -12882,17 +13214,17 @@
(define_insn "*crsave"
[(match_parallel 0 "crsave_operation"
- [(set (match_operand:SI 1 "memory_operand" "=m")
+ [(set (match_operand:SI 1 "memory_operand" "=wN")
(match_operand:SI 2 "gpc_reg_operand" "r"))])]
- ""
+ "!large_mem_operand (operands[0], SImode)"
"stw %2,%1"
[(set_attr "type" "store")])
(define_insn "*stmw"
[(match_parallel 0 "stmw_operation"
- [(set (match_operand:SI 1 "memory_operand" "=m")
+ [(set (match_operand:SI 1 "memory_operand" "=wN")
(match_operand:SI 2 "gpc_reg_operand" "r"))])]
- "TARGET_MULTIPLE"
+ "TARGET_MULTIPLE && !large_mem_operand (operands[0], SImode)"
"stmw %2,%1"
[(set_attr "type" "store")
(set_attr "update" "yes")
@@ -13600,7 +13932,7 @@
;; Fusion insn, created by the define_peephole2 above (and eventually by
;; reload)
-(define_insn "fusion_gpr_load_<mode>"
+(define_insn "*fusion_gpr_load_<mode>"
[(set (match_operand:INT1 0 "base_reg_operand" "=b")
(unspec:INT1 [(match_operand:INT1 1 "fusion_addis_mem_combo_load" "wF")]
UNSPEC_FUSION_GPR))]
@@ -13669,7 +14001,7 @@
;; reload). Because we want to eventually have secondary_reload generate
;; these, they have to have a single alternative that gives the register
;; classes. This means we need to have separate gpr/fpr/altivec versions.
-(define_insn "fusion_gpr_<P:mode>_<GPR_FUSION:mode>_load"
+(define_insn "*fusion_gpr_<P:mode>_<GPR_FUSION:mode>_load"
[(set (match_operand:GPR_FUSION 0 "int_reg_operand" "=r")
(unspec:GPR_FUSION
[(match_operand:GPR_FUSION 1 "fusion_addis_mem_combo_load" "wF")]
@@ -13687,7 +14019,7 @@
[(set_attr "type" "load")
(set_attr "length" "8")])
-(define_insn "fusion_gpr_<P:mode>_<GPR_FUSION:mode>_store"
+(define_insn "*fusion_gpr_<P:mode>_<GPR_FUSION:mode>_store"
[(set (match_operand:GPR_FUSION 0 "fusion_addis_mem_combo_store" "=wF")
(unspec:GPR_FUSION
[(match_operand:GPR_FUSION 1 "int_reg_operand" "r")]
@@ -13700,7 +14032,7 @@
[(set_attr "type" "store")
(set_attr "length" "8")])
-(define_insn "fusion_vsx_<P:mode>_<FPR_FUSION:mode>_load"
+(define_insn "*fusion_vsx_<P:mode>_<FPR_FUSION:mode>_load"
[(set (match_operand:FPR_FUSION 0 "vsx_register_operand" "=dwb")
(unspec:FPR_FUSION
[(match_operand:FPR_FUSION 1 "fusion_addis_mem_combo_load" "wF")]
@@ -13713,7 +14045,7 @@
[(set_attr "type" "fpload")
(set_attr "length" "8")])
-(define_insn "fusion_vsx_<P:mode>_<FPR_FUSION:mode>_store"
+(define_insn "*fusion_vsx_<P:mode>_<FPR_FUSION:mode>_store"
[(set (match_operand:FPR_FUSION 0 "fusion_addis_mem_combo_store" "=wF")
(unspec:FPR_FUSION
[(match_operand:FPR_FUSION 1 "vsx_register_operand" "dwb")]
diff --git a/gcc/config/rs6000/rs6000.opt b/gcc/config/rs6000/rs6000.opt
index 488df56a134..ef65f00b811 100644
--- a/gcc/config/rs6000/rs6000.opt
+++ b/gcc/config/rs6000/rs6000.opt
@@ -570,3 +570,7 @@ long rs6000_stack_protector_guard_offset = 0
;; branches via the CTR.
mspeculate-indirect-jumps
Target Undocumented Var(rs6000_speculate_indirect_jumps) Init(1) Save
+
+mlarge-address
+Target Undocumented Mask(LARGE_ADDRESS) Var(rs6000_isa_flags)
+Add support for large addresses.