diff options
author | Michael Meissner <meissner@linux.ibm.com> | 2018-07-12 18:27:23 +0000 |
---|---|---|
committer | Michael Meissner <meissner@linux.ibm.com> | 2018-07-12 18:27:23 +0000 |
commit | 5cd509d493e993ba74d7d1c0d9c82ffd59307329 (patch) | |
tree | 5b9018fcff11a8355831c9097c240310fb06af33 | |
parent | b7c7687856ee67811714b8f0ae11c7d52b32c0b9 (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.meissner | 136 | ||||
-rw-r--r-- | gcc/config/rs6000/constraints.md | 12 | ||||
-rw-r--r-- | gcc/config/rs6000/predicates.md | 31 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000-protos.h | 7 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.c | 591 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.md | 692 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.opt | 4 |
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. |