X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Fconfig%2Fsh%2Fsh.c;h=545ac0471217216c7b76aa5d9e414e6d7d99b4b2;hp=6b20ee3071d66207a79b58bd851f68b88b9c4790;hb=2b0c924289ff77444f1a10adeeb059e7a17b0984;hpb=9037a84cdb90ffa9a11a81cf0880e7cf5b864ede diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c index 6b20ee3071d..545ac047121 100644 --- a/gcc/config/sh/sh.c +++ b/gcc/config/sh/sh.c @@ -1,6 +1,6 @@ /* Output routines for GCC for Renesas / SuperH SH. Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, - 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. Contributed by Steve Chamberlain (sac@cygnus.com). Improved by Jim Wilson (wilson@cygnus.com). @@ -37,7 +37,6 @@ along with GCC; see the file COPYING3. If not see #include "insn-attr.h" #include "toplev.h" #include "recog.h" -#include "c-pragma.h" #include "integrate.h" #include "dwarf2.h" #include "tm_p.h" @@ -51,7 +50,7 @@ along with GCC; see the file COPYING3. If not see #include "intl.h" #include "sched-int.h" #include "ggc.h" -#include "tree-gimple.h" +#include "gimple.h" #include "cfgloop.h" #include "alloc-pool.h" #include "tm-constrs.h" @@ -106,12 +105,6 @@ static int skip_cycles = 0; and returned from sh_reorder2. */ static short cached_can_issue_more; -/* Saved operands from the last compare to use when we generate an scc - or bcc insn. */ - -rtx sh_compare_op0; -rtx sh_compare_op1; - /* Provides the class number of the smallest class containing reg number. */ @@ -224,7 +217,7 @@ static int sh_variable_issue (FILE *, int, rtx, int); static bool sh_function_ok_for_sibcall (tree, tree); static bool sh_cannot_modify_jumps_p (void); -static int sh_target_reg_class (void); +static enum reg_class sh_target_reg_class (void); static bool sh_optimize_target_register_callee_saved (bool); static bool sh_ms_bitfield_layout_p (const_tree); @@ -241,10 +234,12 @@ static int addsubcosts (rtx); static int multcosts (rtx); static bool unspec_caller_rtx_p (rtx); static bool sh_cannot_copy_insn_p (rtx); -static bool sh_rtx_costs (rtx, int, int, int *); -static int sh_address_cost (rtx); +static bool sh_rtx_costs (rtx, int, int, int *, bool); +static int sh_address_cost (rtx, bool); static int sh_pr_n_sets (void); static rtx sh_allocate_initial_value (rtx); +static bool sh_legitimate_address_p (enum machine_mode, rtx, bool); +static rtx sh_legitimize_address (rtx, rtx, enum machine_mode); static int shmedia_target_regs_stack_space (HARD_REG_SET *); static int shmedia_reserve_space_for_target_registers_p (int, HARD_REG_SET *); static int shmedia_target_regs_stack_adjust (HARD_REG_SET *); @@ -261,7 +256,7 @@ static bool sh_strict_argument_naming (CUMULATIVE_ARGS *); static bool sh_pretend_outgoing_varargs_named (CUMULATIVE_ARGS *); static tree sh_build_builtin_va_list (void); static void sh_va_start (tree, rtx); -static tree sh_gimplify_va_arg_expr (tree, tree, tree *, tree *); +static tree sh_gimplify_va_arg_expr (tree, tree, gimple_seq *, gimple_seq *); static bool sh_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode, const_tree, bool); static bool sh_callee_copies (CUMULATIVE_ARGS *, enum machine_mode, @@ -374,6 +369,9 @@ static int sh2a_function_vector_p (tree); #undef TARGET_SCHED_INIT #define TARGET_SCHED_INIT sh_md_init +#undef TARGET_LEGITIMIZE_ADDRESS +#define TARGET_LEGITIMIZE_ADDRESS sh_legitimize_address + #undef TARGET_CANNOT_MODIFY_JUMPS_P #define TARGET_CANNOT_MODIFY_JUMPS_P sh_cannot_modify_jumps_p #undef TARGET_BRANCH_TARGET_REGISTER_CLASS @@ -405,6 +403,9 @@ static int sh2a_function_vector_p (tree); #undef TARGET_MACHINE_DEPENDENT_REORG #define TARGET_MACHINE_DEPENDENT_REORG sh_reorg +#undef TARGET_DWARF_REGISTER_SPAN +#define TARGET_DWARF_REGISTER_SPAN sh_dwarf_register_span + #ifdef HAVE_AS_TLS #undef TARGET_HAVE_TLS #define TARGET_HAVE_TLS true @@ -480,6 +481,9 @@ static int sh2a_function_vector_p (tree); #undef TARGET_SECONDARY_RELOAD #define TARGET_SECONDARY_RELOAD sh_secondary_reload +#undef TARGET_LEGITIMATE_ADDRESS_P +#define TARGET_LEGITIMATE_ADDRESS_P sh_legitimate_address_p + /* Machine-specific symbol_ref flags. */ #define SYMBOL_FLAG_FUNCVEC_FUNCTION (SYMBOL_FLAG_MACH_DEP << 0) @@ -1031,45 +1035,6 @@ print_operand (FILE *stream, rtx x, int code) output_address (XEXP (x, 0)); break; - case CONST: - if (TARGET_SHMEDIA - && (GET_CODE (XEXP (x, 0)) == SIGN_EXTEND - || GET_CODE (XEXP (x, 0)) == ZERO_EXTEND) - && (GET_MODE (XEXP (x, 0)) == DImode - || GET_MODE (XEXP (x, 0)) == SImode) - && GET_CODE (XEXP (XEXP (x, 0), 0)) == TRUNCATE - && GET_MODE (XEXP (XEXP (x, 0), 0)) == HImode) - { - rtx val = XEXP (XEXP (XEXP (x, 0), 0), 0); - rtx val2 = val; - bool nested_expr = false; - - fputc ('(', stream); - if (GET_CODE (val) == ASHIFTRT) - { - fputc ('(', stream); - val2 = XEXP (val, 0); - } - if (GET_CODE (val2) == CONST - || GET_RTX_CLASS (GET_CODE (val2)) != RTX_OBJ) - { - fputc ('(', stream); - nested_expr = true; - } - output_addr_const (stream, val2); - if (nested_expr) - fputc (')', stream); - if (GET_CODE (val) == ASHIFTRT) - { - fputs (" >> ", stream); - output_addr_const (stream, XEXP (val, 1)); - fputc (')', stream); - } - fputs (" & 65535)", stream); - break; - } - - /* Fall through. */ default: if (TARGET_SH1) fputc ('#', stream); @@ -1254,7 +1219,7 @@ prepare_move_operands (rtx operands[], enum machine_mode mode) if ((mode == SImode || mode == DImode) && flag_pic && ! ((mode == Pmode || mode == ptr_mode) - && tls_symbolic_operand (operands[1], Pmode) != 0)) + && tls_symbolic_operand (operands[1], Pmode) != TLS_MODEL_NONE)) { rtx temp; if (SYMBOLIC_CONST_P (operands[1])) @@ -1300,9 +1265,9 @@ prepare_move_operands (rtx operands[], enum machine_mode mode) { /* This is like change_address_1 (operands[0], mode, 0, 1) , except that we can't use that function because it is static. */ - rtx new = change_address (operands[0], mode, 0); - MEM_COPY_ATTRIBUTES (new, operands[0]); - operands[0] = new; + rtx new_rtx = change_address (operands[0], mode, 0); + MEM_COPY_ATTRIBUTES (new_rtx, operands[0]); + operands[0] = new_rtx; } /* This case can happen while generating code to move the result @@ -1326,7 +1291,8 @@ prepare_move_operands (rtx operands[], enum machine_mode mode) op1 = operands[1]; if (GET_CODE (op1) == CONST && GET_CODE (XEXP (op1, 0)) == PLUS - && tls_symbolic_operand (XEXP (XEXP (op1, 0), 0), Pmode)) + && (tls_symbolic_operand (XEXP (XEXP (op1, 0), 0), Pmode) + != TLS_MODEL_NONE)) { opc = XEXP (XEXP (op1, 0), 1); op1 = XEXP (XEXP (op1, 0), 0); @@ -1334,7 +1300,7 @@ prepare_move_operands (rtx operands[], enum machine_mode mode) else opc = NULL_RTX; - if ((tls_kind = tls_symbolic_operand (op1, Pmode))) + if ((tls_kind = tls_symbolic_operand (op1, Pmode)) != TLS_MODEL_NONE) { rtx tga_op1, tga_ret, tmp, tmp2; @@ -1371,8 +1337,7 @@ prepare_move_operands (rtx operands[], enum machine_mode mode) if (flag_schedule_insns) emit_insn (gen_blockage ()); emit_insn (gen_GOTaddr2picreg ()); - emit_insn (gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, - PIC_REG))); + emit_use (gen_rtx_REG (SImode, PIC_REG)); if (flag_schedule_insns) emit_insn (gen_blockage ()); } @@ -1415,7 +1380,7 @@ prepare_cbranch_operands (rtx *operands, enum machine_mode mode, rtx op1; rtx scratch = NULL_RTX; - if (comparison == CODE_FOR_nothing) + if (comparison == LAST_AND_UNUSED_RTX_CODE) comparison = GET_CODE (operands[0]); else scratch = operands[4]; @@ -1515,9 +1480,7 @@ expand_cbranchsi4 (rtx *operands, enum rtx_code comparison, int probability) operands[1], operands[2]))); jump = emit_jump_insn (branch_expander (operands[3])); if (probability >= 0) - REG_NOTES (jump) - = gen_rtx_EXPR_LIST (REG_BR_PROB, GEN_INT (probability), - REG_NOTES (jump)); + add_reg_note (jump, REG_BR_PROB, GEN_INT (probability)); } @@ -1555,7 +1518,7 @@ expand_cbranchdi4 (rtx *operands, enum rtx_code comparison) op2h = gen_highpart_mode (SImode, DImode, operands[2]); op1l = gen_lowpart (SImode, operands[1]); op2l = gen_lowpart (SImode, operands[2]); - msw_taken = msw_skip = lsw_taken = CODE_FOR_nothing; + msw_taken = msw_skip = lsw_taken = LAST_AND_UNUSED_RTX_CODE; prob = split_branch_probability; rev_prob = REG_BR_PROB_BASE - prob; switch (comparison) @@ -1646,9 +1609,9 @@ expand_cbranchdi4 (rtx *operands, enum rtx_code comparison) break; default: return false; } - num_branches = ((msw_taken != CODE_FOR_nothing) - + (msw_skip != CODE_FOR_nothing) - + (lsw_taken != CODE_FOR_nothing)); + num_branches = ((msw_taken != LAST_AND_UNUSED_RTX_CODE) + + (msw_skip != LAST_AND_UNUSED_RTX_CODE) + + (lsw_taken != LAST_AND_UNUSED_RTX_CODE)); if (comparison != EQ && comparison != NE && num_branches > 1) { if (!CONSTANT_P (operands[2]) @@ -1673,21 +1636,23 @@ expand_cbranchdi4 (rtx *operands, enum rtx_code comparison) operands[2] = op2h; operands[4] = NULL_RTX; if (reload_completed - && ! arith_reg_or_0_operand (op2h, SImode) && true_regnum (op1h) - && (msw_taken != CODE_FOR_nothing || msw_skip != CODE_FOR_nothing)) + && ! arith_reg_or_0_operand (op2h, SImode) + && (true_regnum (op1h) || (comparison != EQ && comparison != NE)) + && (msw_taken != LAST_AND_UNUSED_RTX_CODE + || msw_skip != LAST_AND_UNUSED_RTX_CODE)) { emit_move_insn (scratch, operands[2]); operands[2] = scratch; } - if (msw_taken != CODE_FOR_nothing) + if (msw_taken != LAST_AND_UNUSED_RTX_CODE) expand_cbranchsi4 (operands, msw_taken, msw_taken_prob); - if (msw_skip != CODE_FOR_nothing) + if (msw_skip != LAST_AND_UNUSED_RTX_CODE) { rtx taken_label = operands[3]; /* Operands were possibly modified, but msw_skip doesn't expect this. Always use the original ones. */ - if (msw_taken != CODE_FOR_nothing) + if (msw_taken != LAST_AND_UNUSED_RTX_CODE) { operands[1] = op1h; operands[2] = op2h; @@ -1699,22 +1664,42 @@ expand_cbranchdi4 (rtx *operands, enum rtx_code comparison) } operands[1] = op1l; operands[2] = op2l; - if (lsw_taken != CODE_FOR_nothing) + if (lsw_taken != LAST_AND_UNUSED_RTX_CODE) { if (reload_completed - && ! arith_reg_or_0_operand (op2l, SImode) && true_regnum (op1l)) - operands[4] = scratch; + && ! arith_reg_or_0_operand (op2l, SImode) + && (true_regnum (op1l) || (lsw_taken != EQ && lsw_taken != NE))) + { + emit_move_insn (scratch, operands[2]); + operands[2] = scratch; + } expand_cbranchsi4 (operands, lsw_taken, lsw_taken_prob); } - if (msw_skip != CODE_FOR_nothing) + if (msw_skip != LAST_AND_UNUSED_RTX_CODE) emit_label (skip_label); return true; } +/* Emit INSN, possibly in a PARALLEL with an USE of fpscr for SH4. */ + +static void +sh_emit_set_t_insn (rtx insn, enum machine_mode mode) +{ + if ((TARGET_SH4 || TARGET_SH2A) && GET_MODE_CLASS (mode) == MODE_FLOAT) + { + insn = gen_rtx_PARALLEL (VOIDmode, + gen_rtvec (2, insn, + gen_rtx_USE (VOIDmode, get_fpscr_rtx ()))); + (mode == SFmode ? emit_sf_insn : emit_df_insn) (insn); + } + else + emit_insn (insn); +} + /* Prepare the operands for an scc instruction; make sure that the - compare has been done. */ -rtx -prepare_scc_operands (enum rtx_code code) + compare has been done and the result is in T_REG. */ +void +sh_emit_scc_to_t (enum rtx_code code, rtx op0, rtx op1) { rtx t_reg = gen_rtx_REG (SImode, T_REG); enum rtx_code oldcode = code; @@ -1743,77 +1728,222 @@ prepare_scc_operands (enum rtx_code code) } if (code != oldcode) { - rtx tmp = sh_compare_op0; - sh_compare_op0 = sh_compare_op1; - sh_compare_op1 = tmp; + rtx tmp = op0; + op0 = op1; + op1 = tmp; } - mode = GET_MODE (sh_compare_op0); + mode = GET_MODE (op0); if (mode == VOIDmode) - mode = GET_MODE (sh_compare_op1); + mode = GET_MODE (op1); - sh_compare_op0 = force_reg (mode, sh_compare_op0); + op0 = force_reg (mode, op0); if ((code != EQ && code != NE - && (sh_compare_op1 != const0_rtx + && (op1 != const0_rtx || code == GTU || code == GEU || code == LTU || code == LEU)) - || (mode == DImode && sh_compare_op1 != const0_rtx) + || (mode == DImode && op1 != const0_rtx) || (TARGET_SH2E && GET_MODE_CLASS (mode) == MODE_FLOAT)) - sh_compare_op1 = force_reg (mode, sh_compare_op1); + op1 = force_reg (mode, op1); - if ((TARGET_SH4 || TARGET_SH2A) && GET_MODE_CLASS (mode) == MODE_FLOAT) - (mode == SFmode ? emit_sf_insn : emit_df_insn) - (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, - gen_rtx_SET (VOIDmode, t_reg, - gen_rtx_fmt_ee (code, SImode, - sh_compare_op0, sh_compare_op1)), - gen_rtx_USE (VOIDmode, get_fpscr_rtx ())))); - else - emit_insn (gen_rtx_SET (VOIDmode, t_reg, - gen_rtx_fmt_ee (code, SImode, - sh_compare_op0, sh_compare_op1))); + sh_emit_set_t_insn (gen_rtx_SET (VOIDmode, t_reg, + gen_rtx_fmt_ee (code, SImode, op0, op1)), + mode); +} - return t_reg; +rtx +sh_emit_cheap_store_flag (enum machine_mode mode, enum rtx_code code, + rtx op0, rtx op1) +{ + rtx target = gen_reg_rtx (SImode); + rtx tmp; + + gcc_assert (TARGET_SHMEDIA); + switch (code) + { + case EQ: + case GT: + case LT: + case UNORDERED: + case GTU: + case LTU: + tmp = gen_rtx_fmt_ee (code, SImode, op0, op1); + emit_insn (gen_cstore4_media (target, tmp, op0, op1)); + code = NE; + break; + + case NE: + case GE: + case LE: + case ORDERED: + case GEU: + case LEU: + tmp = gen_rtx_fmt_ee (reverse_condition (code), mode, op0, op1); + emit_insn (gen_cstore4_media (target, tmp, op0, op1)); + code = EQ; + break; + + case UNEQ: + case UNGE: + case UNGT: + case UNLE: + case UNLT: + case LTGT: + return NULL_RTX; + + default: + gcc_unreachable (); + } + + if (mode == DImode) + { + rtx t2 = gen_reg_rtx (DImode); + emit_insn (gen_extendsidi2 (t2, target)); + target = t2; + } + + return gen_rtx_fmt_ee (code, VOIDmode, target, const0_rtx); } /* Called from the md file, set up the operands of a compare instruction. */ void -from_compare (rtx *operands, int code) +sh_emit_compare_and_branch (rtx *operands, enum machine_mode mode) { - enum machine_mode mode = GET_MODE (sh_compare_op0); - rtx insn; - if (mode == VOIDmode) - mode = GET_MODE (sh_compare_op1); - if (code != EQ - || mode == DImode - || (TARGET_SH2E && GET_MODE_CLASS (mode) == MODE_FLOAT)) + enum rtx_code code = GET_CODE (operands[0]); + enum rtx_code branch_code; + rtx op0 = operands[1]; + rtx op1 = operands[2]; + rtx insn, tem; + bool need_ccmpeq = false; + + if (TARGET_SH2E && GET_MODE_CLASS (mode) == MODE_FLOAT) { - /* Force args into regs, since we can't use constants here. */ - sh_compare_op0 = force_reg (mode, sh_compare_op0); - if (sh_compare_op1 != const0_rtx - || code == GTU || code == GEU - || (TARGET_SH2E && GET_MODE_CLASS (mode) == MODE_FLOAT)) - sh_compare_op1 = force_reg (mode, sh_compare_op1); + op0 = force_reg (mode, op0); + op1 = force_reg (mode, op1); + } + else + { + if (code != EQ || mode == DImode) + { + /* Force args into regs, since we can't use constants here. */ + op0 = force_reg (mode, op0); + if (op1 != const0_rtx || code == GTU || code == GEU) + op1 = force_reg (mode, op1); + } + } + + if (GET_MODE_CLASS (mode) == MODE_FLOAT) + { + if (code == LT + || (code == LE && TARGET_IEEE && TARGET_SH2E) + || (code == GE && !(TARGET_IEEE && TARGET_SH2E))) + { + tem = op0, op0 = op1, op1 = tem; + code = swap_condition (code); + } + + /* GE becomes fcmp/gt+fcmp/eq, for SH2E and TARGET_IEEE only. */ + if (code == GE) + { + gcc_assert (TARGET_IEEE && TARGET_SH2E); + need_ccmpeq = true; + code = GT; + } + + /* Now we can have EQ, NE, GT, LE. NE and LE are then transformed + to EQ/GT respectively. */ + gcc_assert (code == EQ || code == GT || code == NE || code == LE); } - if (TARGET_SH2E && GET_MODE_CLASS (mode) == MODE_FLOAT && code == GE) + + switch (code) { - from_compare (operands, GT); - insn = gen_ieee_ccmpeqsf_t (sh_compare_op0, sh_compare_op1); + case EQ: + case GT: + case GE: + case GTU: + case GEU: + branch_code = code; + break; + case NE: + case LT: + case LE: + case LTU: + case LEU: + branch_code = reverse_condition (code); + break; + default: + gcc_unreachable (); } + + insn = gen_rtx_SET (VOIDmode, + gen_rtx_REG (SImode, T_REG), + gen_rtx_fmt_ee (branch_code, SImode, op0, op1)); + + sh_emit_set_t_insn (insn, mode); + if (need_ccmpeq) + sh_emit_set_t_insn (gen_ieee_ccmpeqsf_t (op0, op1), mode); + + if (branch_code == code) + emit_jump_insn (gen_branch_true (operands[3])); else - insn = gen_rtx_SET (VOIDmode, - gen_rtx_REG (SImode, T_REG), - gen_rtx_fmt_ee (code, SImode, - sh_compare_op0, sh_compare_op1)); - if ((TARGET_SH4 || TARGET_SH2A) && GET_MODE_CLASS (mode) == MODE_FLOAT) + emit_jump_insn (gen_branch_false (operands[3])); +} + +void +sh_emit_compare_and_set (rtx *operands, enum machine_mode mode) +{ + enum rtx_code code = GET_CODE (operands[1]); + rtx op0 = operands[2]; + rtx op1 = operands[3]; + rtx lab = NULL_RTX; + bool invert = false; + rtx tem; + + op0 = force_reg (mode, op0); + if ((code != EQ && code != NE + && (op1 != const0_rtx + || code == GTU || code == GEU || code == LTU || code == LEU)) + || (mode == DImode && op1 != const0_rtx) + || (TARGET_SH2E && GET_MODE_CLASS (mode) == MODE_FLOAT)) + op1 = force_reg (mode, op1); + + if (GET_MODE_CLASS (mode) == MODE_FLOAT) { - insn = gen_rtx_PARALLEL (VOIDmode, - gen_rtvec (2, insn, - gen_rtx_USE (VOIDmode, get_fpscr_rtx ()))); - (mode == SFmode ? emit_sf_insn : emit_df_insn) (insn); + if (code == LT || code == LE) + { + code = swap_condition (code); + tem = op0, op0 = op1, op1 = tem; + } + if (code == GE) + { + if (TARGET_IEEE) + { + lab = gen_label_rtx (); + sh_emit_scc_to_t (EQ, op0, op1); + emit_jump_insn (gen_branch_true (lab)); + code = GT; + } + else + { + code = LT; + invert = true; + } + } } + + if (code == NE) + { + code = EQ; + invert = true; + } + + sh_emit_scc_to_t (code, op0, op1); + if (lab) + emit_label (lab); + if (invert) + emit_insn (gen_movnegt (operands[0])); else - emit_insn (insn); + emit_move_insn (operands[0], gen_rtx_REG (SImode, T_REG)); } /* Functions to output assembly code. */ @@ -1916,14 +2046,14 @@ print_slot (rtx insn) const char * output_far_jump (rtx insn, rtx op) { - struct { rtx lab, reg, op; } this; + struct { rtx lab, reg, op; } this_jmp; rtx braf_base_lab = NULL_RTX; const char *jump; int far; int offset = branch_dest (insn) - INSN_ADDRESSES (INSN_UID (insn)); rtx prev; - this.lab = gen_label_rtx (); + this_jmp.lab = gen_label_rtx (); if (TARGET_SH2 && offset >= -32764 @@ -1949,10 +2079,10 @@ output_far_jump (rtx insn, rtx op) if (GET_CODE ((prev = prev_nonnote_insn (insn))) == INSN && INSN_CODE (prev) == CODE_FOR_indirect_jump_scratch) { - this.reg = SET_DEST (XVECEXP (PATTERN (prev), 0, 0)); - if (REGNO (this.reg) == R0_REG && flag_pic && ! TARGET_SH2) + this_jmp.reg = SET_DEST (XVECEXP (PATTERN (prev), 0, 0)); + if (REGNO (this_jmp.reg) == R0_REG && flag_pic && ! TARGET_SH2) jump = "mov.l r1,@-r15; mova %O0,r0; mov.l @r0,r1; add r1,r0; mov.l @r15+,r1; jmp @%1"; - output_asm_insn (jump, &this.lab); + output_asm_insn (jump, &this_jmp.lab); if (dbr_sequence_length ()) print_slot (final_sequence); else @@ -1964,7 +2094,7 @@ output_far_jump (rtx insn, rtx op) if (dbr_sequence_length ()) print_slot (final_sequence); - this.reg = gen_rtx_REG (SImode, 13); + this_jmp.reg = gen_rtx_REG (SImode, 13); /* We must keep the stack aligned to 8-byte boundaries on SH5. Fortunately, MACL is fixed and call-clobbered, and we never need its value across jumps, so save r13 in it instead of in @@ -1973,7 +2103,7 @@ output_far_jump (rtx insn, rtx op) output_asm_insn ("lds r13, macl", 0); else output_asm_insn ("mov.l r13,@-r15", 0); - output_asm_insn (jump, &this.lab); + output_asm_insn (jump, &this_jmp.lab); if (TARGET_SH5) output_asm_insn ("sts macl, r13", 0); else @@ -1987,16 +2117,16 @@ output_far_jump (rtx insn, rtx op) } if (far) output_asm_insn (".align 2", 0); - (*targetm.asm_out.internal_label) (asm_out_file, "L", CODE_LABEL_NUMBER (this.lab)); - this.op = op; + (*targetm.asm_out.internal_label) (asm_out_file, "L", CODE_LABEL_NUMBER (this_jmp.lab)); + this_jmp.op = op; if (far && flag_pic) { if (TARGET_SH2) - this.lab = braf_base_lab; - output_asm_insn (".long %O2-%O0", &this.lab); + this_jmp.lab = braf_base_lab; + output_asm_insn (".long %O2-%O0", &this_jmp.lab); } else - output_asm_insn (far ? ".long %O2" : ".word %O2-%O0", &this.lab); + output_asm_insn (far ? ".long %O2" : ".word %O2-%O0", &this_jmp.lab); return ""; } @@ -2093,14 +2223,14 @@ output_branch (int logic, rtx insn, rtx *operands) } } -/* Output a code sequence for INSN using TEMPLATE with OPERANDS; but before, +/* Output a code sequence for INSN using TEMPL with OPERANDS; but before, fill in operands 9 as a label to the successor insn. We try to use jump threading where possible. IF CODE matches the comparison in the IF_THEN_ELSE of a following jump, we assume the jump is taken. I.e. EQ means follow jmp and bf, NE means follow jmp and bt, if the address is in range. */ const char * -output_branchy_insn (enum rtx_code code, const char *template, +output_branchy_insn (enum rtx_code code, const char *templ, rtx insn, rtx *operands) { rtx next_insn = NEXT_INSN (insn); @@ -2116,7 +2246,7 @@ output_branchy_insn (enum rtx_code code, const char *template, INSN_ADDRESSES_NEW (operands[9], INSN_ADDRESSES (INSN_UID (next_insn)) + get_attr_length (next_insn)); - return template; + return templ; } else { @@ -2128,7 +2258,7 @@ output_branchy_insn (enum rtx_code code, const char *template, /* branch_true */ src = XEXP (src, 1); operands[9] = src; - return template; + return templ; } } } @@ -2137,7 +2267,7 @@ output_branchy_insn (enum rtx_code code, const char *template, INSN_ADDRESSES_NEW (operands[9], INSN_ADDRESSES (INSN_UID (insn)) + get_attr_length (insn)); - return template; + return templ; } const char * @@ -2192,22 +2322,18 @@ sh_file_start (void) static bool unspec_caller_rtx_p (rtx pat) { - switch (GET_CODE (pat)) + rtx base, offset; + int i; + + split_const (pat, &base, &offset); + if (GET_CODE (base) == UNSPEC) { - case CONST: - return unspec_caller_rtx_p (XEXP (pat, 0)); - case PLUS: - case MINUS: - if (unspec_caller_rtx_p (XEXP (pat, 0))) - return true; - return unspec_caller_rtx_p (XEXP (pat, 1)); - case UNSPEC: - if (XINT (pat, 1) == UNSPEC_CALLER) + if (XINT (base, 1) == UNSPEC_CALLER) return true; - default: - break; + for (i = 0; i < XVECLEN (base, 0); i++) + if (unspec_caller_rtx_p (XVECEXP (base, 0, i))) + return true; } - return false; } @@ -2289,7 +2415,7 @@ int shift_insns_rtx (rtx insn) { rtx set_src = SET_SRC (XVECEXP (PATTERN (insn), 0, 0)); - int shift_count = INTVAL (XEXP (set_src, 1)); + int shift_count = INTVAL (XEXP (set_src, 1)) & 31; enum rtx_code shift_code = GET_CODE (set_src); switch (shift_code) @@ -2328,9 +2454,10 @@ shiftcosts (rtx x) if (GET_CODE (XEXP (x, 1)) != CONST_INT) return SH_DYNAMIC_SHIFT_COST; - value = INTVAL (XEXP (x, 1)); + /* Otherwise, return the true cost in instructions. Cope with out of range + shift counts more or less arbitrarily. */ + value = INTVAL (XEXP (x, 1)) & 31; - /* Otherwise, return the true cost in instructions. */ if (GET_CODE (x) == ASHIFTRT) { int cost = ashiftrt_insns[value]; @@ -2362,7 +2489,7 @@ andcosts (rtx x) || satisfies_constraint_J16 (XEXP (x, 1))) return 1; else - return 1 + rtx_cost (XEXP (x, 1), AND); + return 1 + rtx_cost (XEXP (x, 1), AND, !optimize_size); } /* These constants are single cycle extu.[bw] instructions. */ @@ -2462,7 +2589,8 @@ multcosts (rtx x ATTRIBUTE_UNUSED) scanned. In either case, *TOTAL contains the cost result. */ static bool -sh_rtx_costs (rtx x, int code, int outer_code, int *total) +sh_rtx_costs (rtx x, int code, int outer_code, int *total, + bool speed ATTRIBUTE_UNUSED) { switch (code) { @@ -2588,7 +2716,8 @@ sh_rtx_costs (rtx x, int code, int outer_code, int *total) since it increases pressure on r0. */ static int -sh_address_cost (rtx X) +sh_address_cost (rtx X, + bool speed ATTRIBUTE_UNUSED) { return (GET_CODE (X) == PLUS && ! CONSTANT_P (XEXP (X, 1)) @@ -2677,7 +2806,7 @@ gen_shifty_op (int code, rtx *operands) int max, i; /* Truncate the shift count in case it is out of bounds. */ - value = value & 0x1f; + value = value & 31; if (value == 31) { @@ -2830,7 +2959,7 @@ expand_ashiftrt (rtx *operands) int sh_dynamicalize_shift_p (rtx count) { - return shift_insns[INTVAL (count)] > 1 + SH_DYNAMIC_SHIFT_COST; + return shift_insns[INTVAL (count) & 31] > 1 + SH_DYNAMIC_SHIFT_COST; } /* Try to find a good way to implement the combiner pattern @@ -2990,11 +3119,11 @@ int shl_and_scr_length (rtx insn) { rtx set_src = SET_SRC (XVECEXP (PATTERN (insn), 0, 0)); - int len = shift_insns[INTVAL (XEXP (set_src, 1))]; + int len = shift_insns[INTVAL (XEXP (set_src, 1)) & 31]; rtx op = XEXP (set_src, 0); - len += shift_insns[INTVAL (XEXP (op, 1))] + 1; + len += shift_insns[INTVAL (XEXP (op, 1)) & 31] + 1; op = XEXP (XEXP (op, 0), 0); - return len + shift_insns[INTVAL (XEXP (op, 1))]; + return len + shift_insns[INTVAL (XEXP (op, 1)) & 31]; } /* Generate rtl for instructions for which shl_and_kind advised a particular @@ -3484,7 +3613,7 @@ static rtx add_constant (rtx x, enum machine_mode mode, rtx last_value) { int i; - rtx lab, new; + rtx lab, new_rtx; label_ref_list_t ref, newref; /* First see if we've already got it. */ @@ -3500,14 +3629,14 @@ add_constant (rtx x, enum machine_mode mode, rtx last_value) } if (rtx_equal_p (x, pool_vector[i].value)) { - lab = new = 0; + lab = new_rtx = 0; if (! last_value || ! i || ! rtx_equal_p (last_value, pool_vector[i-1].value)) { - new = gen_label_rtx (); - LABEL_REFS (new) = pool_vector[i].label; - pool_vector[i].label = lab = new; + new_rtx = gen_label_rtx (); + LABEL_REFS (new_rtx) = pool_vector[i].label; + pool_vector[i].label = lab = new_rtx; } if (lab && pool_window_label) { @@ -3517,8 +3646,8 @@ add_constant (rtx x, enum machine_mode mode, rtx last_value) newref->next = ref; pool_vector[pool_window_last].wend = newref; } - if (new) - pool_window_label = new; + if (new_rtx) + pool_window_label = new_rtx; pool_window_last = i; return lab; } @@ -3829,7 +3958,7 @@ fixup_mova (rtx mova) { rtx worker = mova; rtx lab = gen_label_rtx (); - rtx wpat, wpat0, wpat1, wsrc, diff; + rtx wpat, wpat0, wpat1, wsrc, target, base, diff; do { @@ -3848,9 +3977,9 @@ fixup_mova (rtx mova) XEXP (XVECEXP (wsrc, 0, 2), 0), lab, XEXP (wpat1, 0))); INSN_CODE (worker) = -1; - diff = gen_rtx_MINUS (Pmode, XVECEXP (SET_SRC (PATTERN (mova)), 0, 0), - gen_rtx_LABEL_REF (Pmode, lab)); - diff = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, diff), UNSPEC_PIC); + target = XVECEXP (SET_SRC (PATTERN (mova)), 0, 0); + base = gen_rtx_LABEL_REF (Pmode, lab); + diff = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, target, base), UNSPEC_SYMOFF); SET_SRC (PATTERN (mova)) = gen_rtx_CONST (Pmode, diff); INSN_CODE (mova) = -1; } @@ -3868,6 +3997,10 @@ untangle_mova (int *num_mova, rtx *first_mova, rtx new_mova) if (optimize) { + /* If NEW_MOVA has no address yet, it will be handled later. */ + if (INSN_ADDRESSES_SIZE() <= (unsigned) INSN_UID (new_mova)) + return -1; + n_addr = INSN_ADDRESSES (INSN_UID (new_mova)); n_target = INSN_ADDRESSES (INSN_UID (XEXP (MOVA_LABELREF (new_mova), 0))); if (n_addr > n_target || n_addr + 1022 < n_target) @@ -4422,7 +4555,7 @@ gen_block_redirect (rtx jump, int addr, int need_block) rtx scan; /* Don't look for the stack pointer as a scratch register, it would cause trouble if an interrupt occurred. */ - unsigned try = 0x7fff, used; + unsigned attempt = 0x7fff, used; int jump_left = flag_expensive_optimizations + 1; /* It is likely that the most recent eligible instruction is wanted for @@ -4443,7 +4576,7 @@ gen_block_redirect (rtx jump, int addr, int need_block) && GET_CODE (PATTERN (scan)) != CLOBBER && get_attr_in_delay_slot (scan) == IN_DELAY_SLOT_YES) { - try &= ~regs_used (PATTERN (scan), 0); + attempt &= ~regs_used (PATTERN (scan), 0); break; } } @@ -4461,9 +4594,9 @@ gen_block_redirect (rtx jump, int addr, int need_block) if (code == CALL_INSN) used |= regs_used (CALL_INSN_FUNCTION_USAGE (scan), 0); dead |= (used >> 16) & ~used; - if (dead & try) + if (dead & attempt) { - dead &= try; + dead &= attempt; break; } if (code == JUMP_INSN) @@ -4984,10 +5117,8 @@ sh_reorg (void) or pseudo-op. */ label = gen_label_rtx (); - REG_NOTES (link) = gen_rtx_INSN_LIST (REG_LABEL_OPERAND, label, - REG_NOTES (link)); - REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL_OPERAND, label, - REG_NOTES (insn)); + add_reg_note (link, REG_LABEL_OPERAND, label); + add_reg_note (insn, REG_LABEL_OPERAND, label); if (rescan) { scan = link; @@ -5001,9 +5132,7 @@ sh_reorg (void) && reg_mentioned_p (reg, scan)) || ((reg2 = sfunc_uses_reg (scan)) && REGNO (reg2) == REGNO (reg)))) - REG_NOTES (scan) - = gen_rtx_INSN_LIST (REG_LABEL_OPERAND, label, - REG_NOTES (scan)); + add_reg_note (scan, REG_LABEL_OPERAND, label); } while (scan != dies); } @@ -5164,7 +5293,7 @@ sh_reorg (void) /* If we are not optimizing, then there may not be a note. */ if (note) - PUT_MODE (note, REG_INC); + PUT_REG_NOTE_KIND (note, REG_INC); *last_float_addr = r0_inc_rtx; } @@ -5646,7 +5775,7 @@ output_stack_adjust (int size, rtx reg, int epilogue_p, } for (i = 0; i < nreg; i++) CLEAR_HARD_REG_BIT (temps, FIRST_RET_REG + i); - if (current_function_calls_eh_return) + if (crtl->calls_eh_return) { CLEAR_HARD_REG_BIT (temps, EH_RETURN_STACKADJ_REGNO); for (i = 0; i <= 3; i++) @@ -5723,8 +5852,8 @@ output_stack_adjust (int size, rtx reg, int epilogue_p, mem = gen_tmp_stack_mem (Pmode, gen_rtx_POST_INC (Pmode, reg)); emit_move_insn (tmp_reg, mem); /* Tell flow the insns that pop r4/r5 aren't dead. */ - emit_insn (gen_rtx_USE (VOIDmode, tmp_reg)); - emit_insn (gen_rtx_USE (VOIDmode, adj_reg)); + emit_use (tmp_reg); + emit_use (adj_reg); return; } const_reg = gen_rtx_REG (GET_MODE (reg), temp); @@ -5743,12 +5872,10 @@ output_stack_adjust (int size, rtx reg, int epilogue_p, insn = emit_fn (GEN_ADD3 (reg, reg, const_reg)); } if (! epilogue_p) - REG_NOTES (insn) - = (gen_rtx_EXPR_LIST - (REG_FRAME_RELATED_EXPR, - gen_rtx_SET (VOIDmode, reg, - gen_rtx_PLUS (SImode, reg, GEN_INT (size))), - REG_NOTES (insn))); + add_reg_note (insn, REG_FRAME_RELATED_EXPR, + gen_rtx_SET (VOIDmode, reg, + gen_rtx_PLUS (SImode, reg, + GEN_INT (size)))); } } } @@ -5784,9 +5911,7 @@ push (int rn) x = gen_push (gen_rtx_REG (SImode, rn)); x = frame_insn (x); - REG_NOTES (x) - = gen_rtx_EXPR_LIST (REG_INC, - gen_rtx_REG (SImode, STACK_POINTER_REGNUM), 0); + add_reg_note (x, REG_INC, gen_rtx_REG (SImode, STACK_POINTER_REGNUM)); return x; } @@ -5813,9 +5938,7 @@ pop (int rn) x = gen_pop (gen_rtx_REG (SImode, rn)); x = emit_insn (x); - REG_NOTES (x) - = gen_rtx_EXPR_LIST (REG_INC, - gen_rtx_REG (SImode, STACK_POINTER_REGNUM), 0); + add_reg_note (x, REG_INC, gen_rtx_REG (SImode, STACK_POINTER_REGNUM)); } /* Generate code to push the regs specified in the mask. */ @@ -5980,7 +6103,7 @@ calc_live_regs (HARD_REG_SET *live_regs_mask) if (TARGET_SHCOMPACT && ((crtl->args.info.call_cookie & ~ CALL_COOKIE_RET_TRAMP (1)) - || current_function_saves_all_registers)) + || crtl->saves_all_registers)) pr_live = 1; has_call = TARGET_SHMEDIA ? ! leaf_function_p () : pr_live; for (count = 0, reg = FIRST_PSEUDO_REGISTER; reg-- != 0; ) @@ -6008,9 +6131,11 @@ calc_live_regs (HARD_REG_SET *live_regs_mask) && crtl->args.info.call_cookie && reg == PIC_OFFSET_TABLE_REGNUM) || (df_regs_ever_live_p (reg) - && (!call_really_used_regs[reg] + && ((!call_really_used_regs[reg] + && !(reg != PIC_OFFSET_TABLE_REGNUM + && fixed_regs[reg] && call_used_regs[reg])) || (trapa_handler && reg == FPSCR_REG && TARGET_FPU_ANY))) - || (current_function_calls_eh_return + || (crtl->calls_eh_return && (reg == EH_RETURN_DATA_REGNO (0) || reg == EH_RETURN_DATA_REGNO (1) || reg == EH_RETURN_DATA_REGNO (2) @@ -6160,7 +6285,7 @@ sh5_schedule_saves (HARD_REG_SET *live_regs_mask, save_schedule *schedule, && ! FUNCTION_ARG_REGNO_P (i) && i != FIRST_RET_REG && ! (cfun->static_chain_decl != NULL && i == STATIC_CHAIN_REGNUM) - && ! (current_function_calls_eh_return + && ! (crtl->calls_eh_return && (i == EH_RETURN_STACKADJ_REGNO || ((unsigned) i >= EH_RETURN_DATA_REGNO (0) && (unsigned) i <= EH_RETURN_DATA_REGNO (3))))) @@ -6305,7 +6430,7 @@ sh_expand_prologue (void) } /* Emit the code for SETUP_VARARGS. */ - if (current_function_stdarg) + if (cfun->stdarg) { if (TARGET_VARARGS_PRETEND_ARGS (current_function_decl)) { @@ -6320,7 +6445,6 @@ sh_expand_prologue (void) )) break; insn = push (rn); - RTX_FRAME_RELATED_P (insn) = 0; } } } @@ -6392,7 +6516,7 @@ sh_expand_prologue (void) tmp_pnt = schedule.temps; for (entry = &schedule.entries[1]; entry->mode != VOIDmode; entry++) { - enum machine_mode mode = entry->mode; + enum machine_mode mode = (enum machine_mode) entry->mode; unsigned int reg = entry->reg; rtx reg_rtx, mem_rtx, pre_dec = NULL_RTX; rtx orig_reg_rtx; @@ -6406,32 +6530,27 @@ sh_expand_prologue (void) stack_pointer_rtx, GEN_INT (offset))); - GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (mem_rtx, 0), try_pre_dec); - - gcc_assert (r0); - mem_rtx = NULL_RTX; - - try_pre_dec: - do - if (HAVE_PRE_DECREMENT - && (offset_in_r0 - offset == GET_MODE_SIZE (mode) - || mem_rtx == NULL_RTX - || reg == PR_REG || SPECIAL_REGISTER_P (reg))) - { - pre_dec = gen_frame_mem (mode, gen_rtx_PRE_DEC (Pmode, r0)); + if (!memory_address_p (mode, XEXP (mem_rtx, 0))) + { + gcc_assert (r0); + mem_rtx = NULL_RTX; + } - GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (pre_dec, 0), - pre_dec_ok); + if (HAVE_PRE_DECREMENT + && (offset_in_r0 - offset == GET_MODE_SIZE (mode) + || mem_rtx == NULL_RTX + || reg == PR_REG || SPECIAL_REGISTER_P (reg))) + { + pre_dec = gen_frame_mem (mode, gen_rtx_PRE_DEC (Pmode, r0)); + if (!memory_address_p (mode, XEXP (pre_dec, 0))) pre_dec = NULL_RTX; - - break; - - pre_dec_ok: - mem_rtx = NULL_RTX; - offset += GET_MODE_SIZE (mode); - } - while (0); + else + { + mem_rtx = NULL_RTX; + offset += GET_MODE_SIZE (mode); + } + } if (mem_rtx != NULL_RTX) goto addr_ok; @@ -6519,27 +6638,23 @@ sh_expand_prologue (void) a direct save from the to-be-saved register. */ if (REGNO (reg_rtx) != reg) { - rtx set, note_rtx; + rtx set; set = gen_rtx_SET (VOIDmode, mem_rtx, orig_reg_rtx); - note_rtx = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, set, - REG_NOTES (insn)); - REG_NOTES (insn) = note_rtx; + add_reg_note (insn, REG_FRAME_RELATED_EXPR, set); } if (TARGET_SHCOMPACT && (offset_in_r0 != -1)) { rtx reg_rtx = gen_rtx_REG (mode, reg); - rtx set, note_rtx; + rtx set; rtx mem_rtx = gen_frame_mem (mode, gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (offset))); set = gen_rtx_SET (VOIDmode, mem_rtx, reg_rtx); - note_rtx = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, set, - REG_NOTES (insn)); - REG_NOTES (insn) = note_rtx; + add_reg_note (insn, REG_FRAME_RELATED_EXPR, set); } } } @@ -6631,10 +6746,9 @@ sh_expand_epilogue (bool sibcall_p) if (frame_pointer_needed) { - /* We must avoid scheduling the epilogue with previous basic blocks - when exception handling is enabled. See PR/18032. */ - if (flag_exceptions) - emit_insn (gen_blockage ()); + /* We must avoid scheduling the epilogue with previous basic blocks. + See PR/18032 and PR/40313. */ + emit_insn (gen_blockage ()); output_stack_adjust (frame_size, hard_frame_pointer_rtx, e, &live_regs_mask); @@ -6686,7 +6800,7 @@ sh_expand_epilogue (bool sibcall_p) tmp_pnt = schedule.temps; for (; entry->mode != VOIDmode; entry--) { - enum machine_mode mode = entry->mode; + enum machine_mode mode = (enum machine_mode) entry->mode; int reg = entry->reg; rtx reg_rtx, mem_rtx, post_inc = NULL_RTX, insn; @@ -6698,31 +6812,22 @@ sh_expand_epilogue (bool sibcall_p) stack_pointer_rtx, GEN_INT (offset))); - GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (mem_rtx, 0), try_post_inc); - - mem_rtx = NULL_RTX; + if (!memory_address_p (mode, XEXP (mem_rtx, 0))) + mem_rtx = NULL_RTX; - try_post_inc: - do - if (HAVE_POST_INCREMENT - && (offset == offset_in_r0 - || (offset + GET_MODE_SIZE (mode) != d + d_rounding - && mem_rtx == NULL_RTX) - || reg == PR_REG || SPECIAL_REGISTER_P (reg))) - { - post_inc = gen_frame_mem (mode, gen_rtx_POST_INC (Pmode, r0)); - - GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (post_inc, 0), - post_inc_ok); + if (HAVE_POST_INCREMENT + && (offset == offset_in_r0 + || (offset + GET_MODE_SIZE (mode) != d + d_rounding + && mem_rtx == NULL_RTX) + || reg == PR_REG || SPECIAL_REGISTER_P (reg))) + { + post_inc = gen_frame_mem (mode, gen_rtx_POST_INC (Pmode, r0)); + if (!memory_address_p (mode, XEXP (post_inc, 0))) post_inc = NULL_RTX; - - break; - - post_inc_ok: + else mem_rtx = NULL_RTX; - } - while (0); + } if (mem_rtx != NULL_RTX) goto addr_ok; @@ -6850,7 +6955,7 @@ sh_expand_epilogue (bool sibcall_p) + crtl->args.info.stack_regs * 8, stack_pointer_rtx, e, NULL); - if (current_function_calls_eh_return) + if (crtl->calls_eh_return) emit_insn (GEN_ADD3 (stack_pointer_rtx, stack_pointer_rtx, EH_RETURN_STACKADJ_RTX)); @@ -6863,7 +6968,7 @@ sh_expand_epilogue (bool sibcall_p) USE PR_MEDIA_REG, since it will be explicitly copied to TR0_REG by the return pattern. */ if (TEST_HARD_REG_BIT (live_regs_mask, PR_REG)) - emit_insn (gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, PR_REG))); + emit_use (gen_rtx_REG (SImode, PR_REG)); } static int sh_need_epilogue_known = 0; @@ -6917,7 +7022,7 @@ sh_set_return_address (rtx ra, rtx tmp) emit_insn (GEN_MOV (rr, ra)); /* Tell flow the register for return isn't dead. */ - emit_insn (gen_rtx_USE (VOIDmode, rr)); + emit_use (rr); return; } @@ -6949,6 +7054,8 @@ sh_set_return_address (rtx ra, rtx tmp) tmp = gen_frame_mem (Pmode, tmp); emit_insn (GEN_MOV (tmp, ra)); + /* Tell this store isn't dead. */ + emit_use (tmp); } /* Clear variables at function end. */ @@ -7195,7 +7302,7 @@ sh_va_start (tree valist, rtx nextarg) /* Call __builtin_saveregs. */ u = make_tree (sizetype, expand_builtin_saveregs ()); u = fold_convert (ptr_type_node, u); - t = build2 (GIMPLE_MODIFY_STMT, ptr_type_node, next_fp, u); + t = build2 (MODIFY_EXPR, ptr_type_node, next_fp, u); TREE_SIDE_EFFECTS (t) = 1; expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); @@ -7206,11 +7313,11 @@ sh_va_start (tree valist, rtx nextarg) nfp = 0; u = fold_build2 (POINTER_PLUS_EXPR, ptr_type_node, u, size_int (UNITS_PER_WORD * nfp)); - t = build2 (GIMPLE_MODIFY_STMT, ptr_type_node, next_fp_limit, u); + t = build2 (MODIFY_EXPR, ptr_type_node, next_fp_limit, u); TREE_SIDE_EFFECTS (t) = 1; expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); - t = build2 (GIMPLE_MODIFY_STMT, ptr_type_node, next_o, u); + t = build2 (MODIFY_EXPR, ptr_type_node, next_o, u); TREE_SIDE_EFFECTS (t) = 1; expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); @@ -7221,12 +7328,12 @@ sh_va_start (tree valist, rtx nextarg) nint = 0; u = fold_build2 (POINTER_PLUS_EXPR, ptr_type_node, u, size_int (UNITS_PER_WORD * nint)); - t = build2 (GIMPLE_MODIFY_STMT, ptr_type_node, next_o_limit, u); + t = build2 (MODIFY_EXPR, ptr_type_node, next_o_limit, u); TREE_SIDE_EFFECTS (t) = 1; expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); u = make_tree (ptr_type_node, nextarg); - t = build2 (GIMPLE_MODIFY_STMT, ptr_type_node, next_stack, u); + t = build2 (MODIFY_EXPR, ptr_type_node, next_stack, u); TREE_SIDE_EFFECTS (t) = 1; expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); } @@ -7255,8 +7362,8 @@ find_sole_member (tree type) /* Implement `va_arg'. */ static tree -sh_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, - tree *post_p ATTRIBUTE_UNUSED) +sh_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p, + gimple_seq *post_p ATTRIBUTE_UNUSED) { HOST_WIDE_INT size, rsize; tree tmp, pptr_type_node; @@ -7345,20 +7452,19 @@ sh_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree cmp; bool is_double = size == 8 && TREE_CODE (eff_type) == REAL_TYPE; - tmp = build1 (ADDR_EXPR, pptr_type_node, next_fp); - tmp = build2 (GIMPLE_MODIFY_STMT, void_type_node, addr, tmp); - gimplify_and_add (tmp, pre_p); + tmp = build1 (ADDR_EXPR, pptr_type_node, unshare_expr (next_fp)); + gimplify_assign (unshare_expr (addr), tmp, pre_p); - tmp = build2 (GIMPLE_MODIFY_STMT, ptr_type_node, next_fp_tmp, valist); - gimplify_and_add (tmp, pre_p); + gimplify_assign (unshare_expr (next_fp_tmp), valist, pre_p); tmp = next_fp_limit; if (size > 4 && !is_double) - tmp = build2 (POINTER_PLUS_EXPR, TREE_TYPE (tmp), tmp, - size_int (4 - size)); - tmp = build2 (GE_EXPR, boolean_type_node, next_fp_tmp, tmp); + tmp = build2 (POINTER_PLUS_EXPR, TREE_TYPE (tmp), + unshare_expr (tmp), size_int (4 - size)); + tmp = build2 (GE_EXPR, boolean_type_node, + unshare_expr (next_fp_tmp), unshare_expr (tmp)); cmp = build3 (COND_EXPR, void_type_node, tmp, - build1 (GOTO_EXPR, void_type_node, lab_false), - NULL_TREE); + build1 (GOTO_EXPR, void_type_node, + unshare_expr (lab_false)), NULL_TREE); if (!is_double) gimplify_and_add (cmp, pre_p); @@ -7369,10 +7475,8 @@ sh_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tmp = build2 (BIT_AND_EXPR, sizetype, tmp, size_int (UNITS_PER_WORD)); tmp = build2 (POINTER_PLUS_EXPR, ptr_type_node, - next_fp_tmp, tmp); - tmp = build2 (GIMPLE_MODIFY_STMT, ptr_type_node, - next_fp_tmp, tmp); - gimplify_and_add (tmp, pre_p); + unshare_expr (next_fp_tmp), tmp); + gimplify_assign (unshare_expr (next_fp_tmp), tmp, pre_p); } if (is_double) gimplify_and_add (cmp, pre_p); @@ -7392,62 +7496,60 @@ sh_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, = std_gimplify_va_arg_expr (next_fp_tmp, subtype, pre_p, NULL); real = get_initialized_tmp_var (real, pre_p, NULL); - result = build2 (COMPLEX_EXPR, type, real, imag); + result = build2 (COMPLEX_EXPR, eff_type, real, imag); + if (type != eff_type) + result = build1 (VIEW_CONVERT_EXPR, type, result); result = get_initialized_tmp_var (result, pre_p, NULL); } #endif /* FUNCTION_ARG_SCmode_WART */ - tmp = build1 (GOTO_EXPR, void_type_node, lab_over); + tmp = build1 (GOTO_EXPR, void_type_node, unshare_expr (lab_over)); gimplify_and_add (tmp, pre_p); - tmp = build1 (LABEL_EXPR, void_type_node, lab_false); + tmp = build1 (LABEL_EXPR, void_type_node, unshare_expr (lab_false)); gimplify_and_add (tmp, pre_p); - tmp = build1 (ADDR_EXPR, pptr_type_node, next_stack); - tmp = build2 (GIMPLE_MODIFY_STMT, void_type_node, addr, tmp); - gimplify_and_add (tmp, pre_p); - tmp = build2 (GIMPLE_MODIFY_STMT, ptr_type_node, next_fp_tmp, valist); - gimplify_and_add (tmp, pre_p); + tmp = build1 (ADDR_EXPR, pptr_type_node, unshare_expr (next_stack)); + gimplify_assign (unshare_expr (addr), tmp, pre_p); + gimplify_assign (unshare_expr (next_fp_tmp), + unshare_expr (valist), pre_p); - tmp = build2 (GIMPLE_MODIFY_STMT, ptr_type_node, valist, next_fp_tmp); - gimplify_and_add (tmp, post_p); + gimplify_assign (unshare_expr (valist), + unshare_expr (next_fp_tmp), post_p); valist = next_fp_tmp; } else { - tmp = build2 (POINTER_PLUS_EXPR, ptr_type_node, next_o, - size_int (rsize)); - tmp = build2 (GT_EXPR, boolean_type_node, tmp, next_o_limit); + tmp = build2 (POINTER_PLUS_EXPR, ptr_type_node, + unshare_expr (next_o), size_int (rsize)); + tmp = build2 (GT_EXPR, boolean_type_node, tmp, + unshare_expr (next_o_limit)); tmp = build3 (COND_EXPR, void_type_node, tmp, - build1 (GOTO_EXPR, void_type_node, lab_false), - NULL_TREE); + build1 (GOTO_EXPR, void_type_node, + unshare_expr (lab_false)), + NULL_TREE); gimplify_and_add (tmp, pre_p); - tmp = build1 (ADDR_EXPR, pptr_type_node, next_o); - tmp = build2 (GIMPLE_MODIFY_STMT, void_type_node, addr, tmp); - gimplify_and_add (tmp, pre_p); + tmp = build1 (ADDR_EXPR, pptr_type_node, unshare_expr (next_o)); + gimplify_assign (unshare_expr (addr), tmp, pre_p); - tmp = build1 (GOTO_EXPR, void_type_node, lab_over); + tmp = build1 (GOTO_EXPR, void_type_node, unshare_expr (lab_over)); gimplify_and_add (tmp, pre_p); - tmp = build1 (LABEL_EXPR, void_type_node, lab_false); + tmp = build1 (LABEL_EXPR, void_type_node, unshare_expr (lab_false)); gimplify_and_add (tmp, pre_p); if (size > 4 && ! (TARGET_SH4 || TARGET_SH2A)) - { - tmp = build2 (GIMPLE_MODIFY_STMT, ptr_type_node, - next_o, next_o_limit); - gimplify_and_add (tmp, pre_p); - } + gimplify_assign (unshare_expr (next_o), + unshare_expr (next_o_limit), pre_p); - tmp = build1 (ADDR_EXPR, pptr_type_node, next_stack); - tmp = build2 (GIMPLE_MODIFY_STMT, void_type_node, addr, tmp); - gimplify_and_add (tmp, pre_p); + tmp = build1 (ADDR_EXPR, pptr_type_node, unshare_expr (next_stack)); + gimplify_assign (unshare_expr (addr), tmp, pre_p); } if (!result) { - tmp = build1 (LABEL_EXPR, void_type_node, lab_over); + tmp = build1 (LABEL_EXPR, void_type_node, unshare_expr (lab_over)); gimplify_and_add (tmp, pre_p); } } @@ -7458,10 +7560,9 @@ sh_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tmp = std_gimplify_va_arg_expr (valist, type, pre_p, NULL); if (result) { - tmp = build2 (GIMPLE_MODIFY_STMT, void_type_node, result, tmp); - gimplify_and_add (tmp, pre_p); + gimplify_assign (result, tmp, pre_p); - tmp = build1 (LABEL_EXPR, void_type_node, lab_over); + tmp = build1 (LABEL_EXPR, void_type_node, unshare_expr (lab_over)); gimplify_and_add (tmp, pre_p); } else @@ -7473,6 +7574,26 @@ sh_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, return result; } +/* 64 bit floating points memory transfers are paired single precision loads + or store. So DWARF information needs fixing in little endian (unless + PR=SZ=1 in FPSCR). */ +rtx +sh_dwarf_register_span (rtx reg) +{ + unsigned regno = REGNO (reg); + + if (WORDS_BIG_ENDIAN || GET_MODE (reg) != DFmode) + return NULL_RTX; + + return + gen_rtx_PARALLEL (VOIDmode, + gen_rtvec (2, + gen_rtx_REG (SFmode, + DBX_REGISTER_NUMBER (regno+1)), + gen_rtx_REG (SFmode, + DBX_REGISTER_NUMBER (regno)))); +} + bool sh_promote_prototypes (const_tree type) { @@ -7864,7 +7985,7 @@ sh_setup_incoming_varargs (CUMULATIVE_ARGS *ca, int *pretend_arg_size, int second_time ATTRIBUTE_UNUSED) { - gcc_assert (current_function_stdarg); + gcc_assert (cfun->stdarg); if (TARGET_VARARGS_PRETEND_ARGS (current_function_decl)) { int named_parm_regs, anon_parm_regs; @@ -7974,6 +8095,68 @@ initial_elimination_offset (int from, int to) else return total_auto_space; } + +/* Parse the -mfixed-range= option string. */ +void +sh_fix_range (const char *const_str) +{ + int i, first, last; + char *str, *dash, *comma; + + /* str must be of the form REG1'-'REG2{,REG1'-'REG} where REG1 and + REG2 are either register names or register numbers. The effect + of this option is to mark the registers in the range from REG1 to + REG2 as ``fixed'' so they won't be used by the compiler. */ + + i = strlen (const_str); + str = (char *) alloca (i + 1); + memcpy (str, const_str, i + 1); + + while (1) + { + dash = strchr (str, '-'); + if (!dash) + { + warning (0, "value of -mfixed-range must have form REG1-REG2"); + return; + } + *dash = '\0'; + comma = strchr (dash + 1, ','); + if (comma) + *comma = '\0'; + + first = decode_reg_name (str); + if (first < 0) + { + warning (0, "unknown register name: %s", str); + return; + } + + last = decode_reg_name (dash + 1); + if (last < 0) + { + warning (0, "unknown register name: %s", dash + 1); + return; + } + + *dash = '-'; + + if (first > last) + { + warning (0, "%s-%s is an empty range", str, dash + 1); + return; + } + + for (i = first; i <= last; ++i) + fixed_regs[i] = call_used_regs[i] = 1; + + if (!comma) + break; + + *comma = ','; + str = comma + 1; + } +} /* Insert any deferred function attributes from earlier pragmas. */ static void @@ -8022,8 +8205,8 @@ sh_insert_attributes (tree node, tree *attributes) || is_attribute_p ("nosave_low_regs", TREE_PURPOSE (attrs)) || is_attribute_p ("resbank", TREE_PURPOSE (attrs))) warning (OPT_Wattributes, - "%qs attribute only applies to interrupt functions", - IDENTIFIER_POINTER (TREE_PURPOSE (attrs))); + "%qE attribute only applies to interrupt functions", + TREE_PURPOSE (attrs)); else { *tail = tree_cons (TREE_PURPOSE (attrs), NULL_TREE, @@ -8105,14 +8288,14 @@ sh_handle_resbank_handler_attribute (tree * node, tree name, { if (!TARGET_SH2A) { - warning (OPT_Wattributes, "%qs attribute is supported only for SH2A", - IDENTIFIER_POINTER (name)); + warning (OPT_Wattributes, "%qE attribute is supported only for SH2A", + name); *no_add_attrs = true; } if (TREE_CODE (*node) != FUNCTION_DECL) { - warning (OPT_Wattributes, "%qs attribute only applies to functions", - IDENTIFIER_POINTER (name)); + warning (OPT_Wattributes, "%qE attribute only applies to functions", + name); *no_add_attrs = true; } @@ -8129,8 +8312,8 @@ sh_handle_interrupt_handler_attribute (tree *node, tree name, { if (TREE_CODE (*node) != FUNCTION_DECL) { - warning (OPT_Wattributes, "%qs attribute only applies to functions", - IDENTIFIER_POINTER (name)); + warning (OPT_Wattributes, "%qE attribute only applies to functions", + name); *no_add_attrs = true; } else if (TARGET_SHCOMPACT) @@ -8152,30 +8335,30 @@ sh2a_handle_function_vector_handler_attribute (tree * node, tree name, { if (!TARGET_SH2A) { - warning (OPT_Wattributes, "%qs attribute only applies to SH2A", - IDENTIFIER_POINTER (name)); + warning (OPT_Wattributes, "%qE attribute only applies to SH2A", + name); *no_add_attrs = true; } else if (TREE_CODE (*node) != FUNCTION_DECL) { - warning (OPT_Wattributes, "%qs attribute only applies to functions", - IDENTIFIER_POINTER (name)); + warning (OPT_Wattributes, "%qE attribute only applies to functions", + name); *no_add_attrs = true; } else if (TREE_CODE (TREE_VALUE (args)) != INTEGER_CST) { /* The argument must be a constant integer. */ warning (OPT_Wattributes, - "`%s' attribute argument not an integer constant", - IDENTIFIER_POINTER (name)); + "%qE attribute argument not an integer constant", + name); *no_add_attrs = true; } else if (TREE_INT_CST_LOW (TREE_VALUE (args)) > 255) { /* The argument value must be between 0 to 255. */ warning (OPT_Wattributes, - "`%s' attribute argument should be between 0 to 255", - IDENTIFIER_POINTER (name)); + "%qE attribute argument should be between 0 to 255", + name); *no_add_attrs = true; } return NULL_TREE; @@ -8240,15 +8423,15 @@ sh_handle_sp_switch_attribute (tree *node, tree name, tree args, { if (TREE_CODE (*node) != FUNCTION_DECL) { - warning (OPT_Wattributes, "%qs attribute only applies to functions", - IDENTIFIER_POINTER (name)); + warning (OPT_Wattributes, "%qE attribute only applies to functions", + name); *no_add_attrs = true; } else if (TREE_CODE (TREE_VALUE (args)) != STRING_CST) { /* The argument must be a constant string. */ - warning (OPT_Wattributes, "%qs attribute argument not a string constant", - IDENTIFIER_POINTER (name)); + warning (OPT_Wattributes, "%qE attribute argument not a string constant", + name); *no_add_attrs = true; } @@ -8263,8 +8446,8 @@ sh_handle_trap_exit_attribute (tree *node, tree name, tree args, { if (TREE_CODE (*node) != FUNCTION_DECL) { - warning (OPT_Wattributes, "%qs attribute only applies to functions", - IDENTIFIER_POINTER (name)); + warning (OPT_Wattributes, "%qE attribute only applies to functions", + name); *no_add_attrs = true; } /* The argument specifies a trap number to be used in a trapa instruction @@ -8272,8 +8455,8 @@ sh_handle_trap_exit_attribute (tree *node, tree name, tree args, else if (TREE_CODE (TREE_VALUE (args)) != INTEGER_CST) { /* The argument must be a constant integer. */ - warning (OPT_Wattributes, "%qs attribute argument not an " - "integer constant", IDENTIFIER_POINTER (name)); + warning (OPT_Wattributes, "%qE attribute argument not an " + "integer constant", name); *no_add_attrs = true; } @@ -8438,11 +8621,11 @@ tertiary_reload_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) } /* Return the TLS type for TLS symbols, 0 for otherwise. */ -int +enum tls_model tls_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) { if (GET_CODE (op) != SYMBOL_REF) - return 0; + return TLS_MODEL_NONE; return SYMBOL_REF_TLS_MODEL (op); } @@ -8682,7 +8865,7 @@ get_free_reg (HARD_REG_SET regs_live) void fpscr_set_from_mem (int mode, HARD_REG_SET regs_live) { - enum attr_fp_mode fp_mode = mode; + enum attr_fp_mode fp_mode = (enum attr_fp_mode) mode; enum attr_fp_mode norm_mode = ACTUAL_NORMAL_MODE (FP_MODE); rtx addr_reg; @@ -8713,7 +8896,7 @@ sh_insn_length_adjustment (rtx insn) /* SH2e has a bug that prevents the use of annulled branches, so if the delay slot is not filled, we'll have to put a NOP in it. */ - if (sh_cpu == CPU_SH2E + if (sh_cpu_attr == CPU_SH2E && GET_CODE (insn) == JUMP_INSN && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC && GET_CODE (PATTERN (insn)) != ADDR_VEC @@ -8727,14 +8910,14 @@ sh_insn_length_adjustment (rtx insn) { int sum = 0; rtx body = PATTERN (insn); - const char *template; + const char *templ; char c; int maybe_label = 1; if (GET_CODE (body) == ASM_INPUT) - template = XSTR (body, 0); + templ = XSTR (body, 0); else if (asm_noperands (body) >= 0) - template + templ = decode_asm_operands (body, NULL, NULL, NULL, NULL, NULL); else return 0; @@ -8743,20 +8926,20 @@ sh_insn_length_adjustment (rtx insn) int ppi_adjust = 0; do - c = *template++; + c = *templ++; while (c == ' ' || c == '\t'); /* all sh-dsp parallel-processing insns start with p. The only non-ppi sh insn starting with p is pref. The only ppi starting with pr is prnd. */ - if ((c == 'p' || c == 'P') && strncasecmp ("re", template, 2)) + if ((c == 'p' || c == 'P') && strncasecmp ("re", templ, 2)) ppi_adjust = 2; /* The repeat pseudo-insn expands two three insns, a total of six bytes in size. */ else if ((c == 'r' || c == 'R') - && ! strncasecmp ("epeat", template, 5)) + && ! strncasecmp ("epeat", templ, 5)) ppi_adjust = 4; while (c && c != '\n' - && ! IS_ASM_LOGICAL_LINE_SEPARATOR (c, template)) + && ! IS_ASM_LOGICAL_LINE_SEPARATOR (c, templ)) { /* If this is a label, it is obviously not a ppi insn. */ if (c == ':' && maybe_label) @@ -8766,7 +8949,7 @@ sh_insn_length_adjustment (rtx insn) } else if (c == '\'' || c == '"') maybe_label = 0; - c = *template++; + c = *templ++; } sum += ppi_adjust; maybe_label = c != ':'; @@ -8777,6 +8960,124 @@ sh_insn_length_adjustment (rtx insn) return 0; } +/* Return TRUE for a valid displacement for the REG+disp addressing + with MODE. */ + +/* ??? The SH2e does not have the REG+disp addressing mode when loading values + into the FRx registers. We implement this by setting the maximum offset + to zero when the value is SFmode. This also restricts loading of SFmode + values into the integer registers, but that can't be helped. */ + +/* The SH allows a displacement in a QI or HI amode, but only when the + other operand is R0. GCC doesn't handle this very well, so we forgot + all of that. + + A legitimate index for a QI or HI is 0, SI can be any number 0..63, + DI can be any number 0..60. */ + +bool +sh_legitimate_index_p (enum machine_mode mode, rtx op) +{ + if (GET_CODE (op) == CONST_INT) + { + if (TARGET_SHMEDIA) + { + int size; + + /* Check if this the address of an unaligned load / store. */ + if (mode == VOIDmode) + return CONST_OK_FOR_I06 (INTVAL (op)); + + size = GET_MODE_SIZE (mode); + return (!(INTVAL (op) & (size - 1)) + && INTVAL (op) >= -512 * size + && INTVAL (op) < 512 * size); + } + + if (TARGET_SH2A) + { + if (GET_MODE_SIZE (mode) == 1 + && (unsigned) INTVAL (op) < 4096) + return true; + } + + if ((GET_MODE_SIZE (mode) == 4 + && (unsigned) INTVAL (op) < 64 + && !(INTVAL (op) & 3) + && !(TARGET_SH2E && mode == SFmode)) + || (GET_MODE_SIZE (mode) == 4 + && (unsigned) INTVAL (op) < 16383 + && !(INTVAL (op) & 3) && TARGET_SH2A)) + return true; + + if ((GET_MODE_SIZE (mode) == 8 + && (unsigned) INTVAL (op) < 60 + && !(INTVAL (op) & 3) + && !((TARGET_SH4 || TARGET_SH2A) && mode == DFmode)) + || ((GET_MODE_SIZE (mode)==8) + && (unsigned) INTVAL (op) < 8192 + && !(INTVAL (op) & (TARGET_SH2A_DOUBLE ? 7 : 3)) + && (TARGET_SH2A && mode == DFmode))) + return true; + } + + return false; +} + +/* Recognize an RTL expression that is a valid memory address for + an instruction. + The MODE argument is the machine mode for the MEM expression + that wants to use this address. + Allow REG + REG+disp + REG+r0 + REG++ + --REG */ + +static bool +sh_legitimate_address_p (enum machine_mode mode, rtx x, bool strict) +{ + if (MAYBE_BASE_REGISTER_RTX_P (x, strict)) + return true; + else if ((GET_CODE (x) == POST_INC || GET_CODE (x) == PRE_DEC) + && ! TARGET_SHMEDIA + && MAYBE_BASE_REGISTER_RTX_P (XEXP (x, 0), strict)) + return true; + else if (GET_CODE (x) == PLUS + && (mode != PSImode || reload_completed)) + { + rtx xop0 = XEXP (x, 0); + rtx xop1 = XEXP (x, 1); + + if (GET_MODE_SIZE (mode) <= 8 + && MAYBE_BASE_REGISTER_RTX_P (xop0, strict) + && sh_legitimate_index_p (mode, xop1)) + return true; + + if ((ALLOW_INDEXED_ADDRESS || GET_MODE (x) == DImode + || ((xop0 == stack_pointer_rtx + || xop0 == hard_frame_pointer_rtx) + && REG_P (xop1) && REGNO (xop1) == R0_REG) + || ((xop1 == stack_pointer_rtx + || xop1 == hard_frame_pointer_rtx) + && REG_P (xop0) && REGNO (xop0) == R0_REG)) + && ((!TARGET_SHMEDIA && GET_MODE_SIZE (mode) <= 4) + || (TARGET_SHMEDIA && GET_MODE_SIZE (mode) <= 8) + || ((TARGET_SH4 || TARGET_SH2A_DOUBLE) + && TARGET_FMOVD && mode == DFmode))) + { + if (MAYBE_BASE_REGISTER_RTX_P (xop1, strict) + && MAYBE_INDEX_REGISTER_RTX_P (xop0, strict)) + return true; + if (MAYBE_INDEX_REGISTER_RTX_P (xop1, strict) + && MAYBE_BASE_REGISTER_RTX_P (xop0, strict)) + return true; + } + } + + return false; +} + /* Return TRUE if X references a SYMBOL_REF or LABEL_REF whose symbol isn't protected by a PIC unspec. */ int @@ -8801,7 +9102,9 @@ nonpic_symbol_mentioned_p (rtx x) || XINT (x, 1) == UNSPEC_GOTPLT || XINT (x, 1) == UNSPEC_GOTTPOFF || XINT (x, 1) == UNSPEC_DTPOFF - || XINT (x, 1) == UNSPEC_PLT)) + || XINT (x, 1) == UNSPEC_PLT + || XINT (x, 1) == UNSPEC_SYMOFF + || XINT (x, 1) == UNSPEC_PCREL_SYMOFF)) return 0; fmt = GET_RTX_FORMAT (GET_CODE (x)); @@ -8828,7 +9131,7 @@ rtx legitimize_pic_address (rtx orig, enum machine_mode mode ATTRIBUTE_UNUSED, rtx reg) { - if (tls_symbolic_operand (orig, Pmode)) + if (tls_symbolic_operand (orig, Pmode) != TLS_MODEL_NONE) return orig; if (GET_CODE (orig) == LABEL_REF @@ -8851,6 +9154,60 @@ legitimize_pic_address (rtx orig, enum machine_mode mode ATTRIBUTE_UNUSED, return orig; } +/* Try machine-dependent ways of modifying an illegitimate address + to be legitimate. If we find one, return the new, valid address. + Otherwise, return X. + + For the SH, if X is almost suitable for indexing, but the offset is + out of range, convert it into a normal form so that CSE has a chance + of reducing the number of address registers used. */ + +static rtx +sh_legitimize_address (rtx x, rtx oldx, enum machine_mode mode) +{ + if (flag_pic) + x = legitimize_pic_address (oldx, mode, NULL_RTX); + + if (GET_CODE (x) == PLUS + && (GET_MODE_SIZE (mode) == 4 + || GET_MODE_SIZE (mode) == 8) + && GET_CODE (XEXP (x, 1)) == CONST_INT + && BASE_REGISTER_RTX_P (XEXP (x, 0)) + && ! TARGET_SHMEDIA + && ! ((TARGET_SH4 || TARGET_SH2A_DOUBLE) && mode == DFmode) + && ! (TARGET_SH2E && mode == SFmode)) + { + rtx index_rtx = XEXP (x, 1); + HOST_WIDE_INT offset = INTVAL (index_rtx), offset_base; + rtx sum; + + /* On rare occasions, we might get an unaligned pointer + that is indexed in a way to give an aligned address. + Therefore, keep the lower two bits in offset_base. */ + /* Instead of offset_base 128..131 use 124..127, so that + simple add suffices. */ + if (offset > 127) + offset_base = ((offset + 4) & ~60) - 4; + else + offset_base = offset & ~60; + + /* Sometimes the normal form does not suit DImode. We + could avoid that by using smaller ranges, but that + would give less optimized code when SImode is + prevalent. */ + if (GET_MODE_SIZE (mode) + offset - offset_base <= 64) + { + sum = expand_binop (Pmode, add_optab, XEXP (x, 0), + GEN_INT (offset_base), NULL_RTX, 0, + OPTAB_LIB_WIDEN); + + return gen_rtx_PLUS (Pmode, sum, GEN_INT (offset - offset_base)); + } + } + + return x; +} + /* Mark the use of a constant in the literal table. If the constant has multiple labels, make it unique. */ static rtx @@ -9216,7 +9573,7 @@ sh_allocate_initial_value (rtx hard_reg) && ! (TARGET_SHCOMPACT && ((crtl->args.info.call_cookie & ~ CALL_COOKIE_RET_TRAMP (1)) - || current_function_saves_all_registers))) + || crtl->saves_all_registers))) x = hard_reg; else x = gen_frame_mem (Pmode, return_address_pointer_rtx); @@ -9607,7 +9964,7 @@ sh_cannot_modify_jumps_p (void) return (TARGET_SHMEDIA && (reload_in_progress || reload_completed)); } -static int +static enum reg_class sh_target_reg_class (void) { return TARGET_SHMEDIA ? TARGET_REGS : NO_REGS; @@ -9796,7 +10153,7 @@ sh_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt) || (!(TARGET_SH4A_ARCH || TARGET_SH4_300) && TARGET_USERMODE)) emit_library_call (function_symbol (NULL, "__ic_invalidate", FUNCTION_ORDINARY), - 0, VOIDmode, 1, tramp, SImode); + LCT_NORMAL, VOIDmode, 1, tramp, SImode); else emit_insn (gen_ic_invalidate_line (tramp)); } @@ -10133,7 +10490,7 @@ sh_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, argmode = TYPE_MODE (TREE_TYPE (arg)); if (argmode != opmode) arg = build1 (NOP_EXPR, optype, arg); - op[nop] = expand_expr (arg, NULL_RTX, opmode, 0); + op[nop] = expand_expr (arg, NULL_RTX, opmode, EXPAND_NORMAL); if (! (*insn_data[icode].operand[nop].predicate) (op[nop], opmode)) op[nop] = copy_to_mode_reg (opmode, op[nop]); } @@ -10182,28 +10539,130 @@ sh_expand_binop_v2sf (enum rtx_code code, rtx op0, rtx op1, rtx op2) emit_insn (gen_binary_sf_op1 (op0, op1, op2, op)); } +/* Return true if hard register REGNO can hold a value of machine-mode MODE. + We can allow any mode in any general register. The special registers + only allow SImode. Don't allow any mode in the PR. + + We cannot hold DCmode values in the XD registers because alter_reg + handles subregs of them incorrectly. We could work around this by + spacing the XD registers like the DR registers, but this would require + additional memory in every compilation to hold larger register vectors. + We could hold SFmode / SCmode values in XD registers, but that + would require a tertiary reload when reloading from / to memory, + and a secondary reload to reload from / to general regs; that + seems to be a loosing proposition. + + We want to allow TImode FP regs so that when V4SFmode is loaded as TImode, + it won't be ferried through GP registers first. */ + +bool +sh_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode) +{ + if (SPECIAL_REGISTER_P (regno)) + return mode == SImode; + + if (regno == FPUL_REG) + return (mode == SImode || mode == SFmode); + + if (FP_REGISTER_P (regno) && mode == SFmode) + return true; + + if (mode == V2SFmode) + { + if (((FP_REGISTER_P (regno) && (regno - FIRST_FP_REG) % 2 == 0) + || GENERAL_REGISTER_P (regno))) + return true; + else + return false; + } + + if (mode == V4SFmode) + { + if ((FP_REGISTER_P (regno) && (regno - FIRST_FP_REG) % 4 == 0) + || GENERAL_REGISTER_P (regno)) + return true; + else + return false; + } + + if (mode == V16SFmode) + { + if (TARGET_SHMEDIA) + { + if (FP_REGISTER_P (regno) && (regno - FIRST_FP_REG) % 16 == 0) + return true; + else + return false; + } + else + return regno == FIRST_XD_REG; + } + + if (FP_REGISTER_P (regno)) + { + if (mode == SFmode + || mode == SImode + || ((TARGET_SH2E || TARGET_SHMEDIA) && mode == SCmode) + || ((((TARGET_SH4 || TARGET_SH2A_DOUBLE) && mode == DFmode) + || mode == DCmode + || (TARGET_SHMEDIA + && (mode == DFmode || mode == DImode + || mode == V2SFmode || mode == TImode))) + && ((regno - FIRST_FP_REG) & 1) == 0) + || ((TARGET_SH4 || TARGET_SHMEDIA) && mode == TImode + && ((regno - FIRST_FP_REG) & 3) == 0)) + return true; + else + return false; + } + + if (XD_REGISTER_P (regno)) + return mode == DFmode; + + if (TARGET_REGISTER_P (regno)) + return (mode == DImode || mode == SImode || mode == PDImode); + + if (regno == PR_REG) + return mode == SImode; + + if (regno == FPSCR_REG) + return mode == PSImode; + + /* FIXME. This works around PR target/37633 for -O0. */ + if (!optimize && TARGET_SHMEDIA32 && GET_MODE_SIZE (mode) > 4) + { + unsigned int n = GET_MODE_SIZE (mode) / 8; + + if (regno >= FIRST_GENERAL_REG + 10 - n + 1 + && regno <= FIRST_GENERAL_REG + 14) + return false; + } + + return true; +} + /* Return the class of registers for which a mode change from FROM to TO is invalid. */ bool sh_cannot_change_mode_class (enum machine_mode from, enum machine_mode to, - enum reg_class class) + enum reg_class rclass) { /* We want to enable the use of SUBREGs as a means to VEC_SELECT a single element of a vector. */ if (to == SFmode && VECTOR_MODE_P (from) && GET_MODE_INNER (from) == SFmode) - return (reg_classes_intersect_p (GENERAL_REGS, class)); + return (reg_classes_intersect_p (GENERAL_REGS, rclass)); if (GET_MODE_SIZE (from) != GET_MODE_SIZE (to)) { if (TARGET_LITTLE_ENDIAN) { if (GET_MODE_SIZE (to) < 8 || GET_MODE_SIZE (from) < 8) - return reg_classes_intersect_p (DF_REGS, class); + return reg_classes_intersect_p (DF_REGS, rclass); } else { if (GET_MODE_SIZE (from) < 8) - return reg_classes_intersect_p (DF_HI_REGS, class); + return reg_classes_intersect_p (DF_HI_REGS, rclass); } } return 0; @@ -10323,7 +10782,7 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, { CUMULATIVE_ARGS cum; int structure_value_byref = 0; - rtx this, this_value, sibcall, insns, funexp; + rtx this_rtx, this_value, sibcall, insns, funexp; tree funtype = TREE_TYPE (function); int simple_add = CONST_OK_FOR_ADD (delta); int did_load = 0; @@ -10351,7 +10810,7 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, FUNCTION_ARG_ADVANCE (cum, Pmode, ptype, 1); } - this = FUNCTION_ARG (cum, Pmode, ptr_type_node, 1); + this_rtx = FUNCTION_ARG (cum, Pmode, ptr_type_node, 1); /* For SHcompact, we only have r0 for a scratch register: r1 is the static chain pointer (even if you can't have nested virtual functions @@ -10392,7 +10851,7 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, error ("Need a call-clobbered target register"); } - this_value = plus_constant (this, delta); + this_value = plus_constant (this_rtx, delta); if (vcall_offset && (simple_add || scratch0 != scratch1) && strict_memory_address_p (ptr_mode, this_value)) @@ -10404,11 +10863,11 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, if (!delta) ; /* Do nothing. */ else if (simple_add) - emit_move_insn (this, this_value); + emit_move_insn (this_rtx, this_value); else { emit_move_insn (scratch1, GEN_INT (delta)); - emit_insn (gen_add2_insn (this, scratch1)); + emit_insn (gen_add2_insn (this_rtx, scratch1)); } if (vcall_offset) @@ -10416,7 +10875,7 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, rtx offset_addr; if (!did_load) - emit_load_ptr (scratch0, this); + emit_load_ptr (scratch0, this_rtx); offset_addr = plus_constant (scratch0, vcall_offset); if (strict_memory_address_p (ptr_mode, offset_addr)) @@ -10426,7 +10885,7 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, /* scratch0 != scratch1, and we have indexed loads. Get better schedule by loading the offset into r1 and using an indexed load - then the load of r1 can issue before the load from - (this + delta) finishes. */ + (this_rtx + delta) finishes. */ emit_move_insn (scratch1, GEN_INT (vcall_offset)); offset_addr = gen_rtx_PLUS (Pmode, scratch0, scratch1); } @@ -10447,7 +10906,7 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, if (Pmode != ptr_mode) scratch0 = gen_rtx_TRUNCATE (ptr_mode, scratch0); - emit_insn (gen_add2_insn (this, scratch0)); + emit_insn (gen_add2_insn (this_rtx, scratch0)); } /* Generate a tail call to the target function. */ @@ -10482,7 +10941,7 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, } sibcall = emit_call_insn (sibcall); SIBLING_CALL_P (sibcall) = 1; - use_reg (&CALL_INSN_FUNCTION_USAGE (sibcall), this); + use_reg (&CALL_INSN_FUNCTION_USAGE (sibcall), this_rtx); emit_barrier (); /* Run just enough of rest_of_compilation to do scheduling and get @@ -10492,41 +10951,12 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, insn_locators_alloc (); insns = get_insns (); -#if 0 if (optimize > 0) { - /* Initialize the bitmap obstacks. */ - bitmap_obstack_initialize (NULL); - bitmap_obstack_initialize (®_obstack); if (! cfun->cfg) - init_flow (); - rtl_register_cfg_hooks (); - init_rtl_bb_info (ENTRY_BLOCK_PTR); - init_rtl_bb_info (EXIT_BLOCK_PTR); - ENTRY_BLOCK_PTR->flags |= BB_RTL; - EXIT_BLOCK_PTR->flags |= BB_RTL; - find_basic_blocks (insns); - - if (flag_schedule_insns_after_reload) - { - life_analysis (PROP_FINAL); - - split_all_insns (1); - - schedule_insns (); - } - /* We must split jmp insn in PIC case. */ - else if (flag_pic) - split_all_insns_noflow (); - } -#else - if (optimize > 0) - { - if (! cfun->cfg) - init_flow (); + init_flow (cfun); split_all_insns_noflow (); } -#endif sh_reorg (); @@ -10612,7 +11042,7 @@ sh_get_pr_initial_val (void) if (TARGET_SHCOMPACT && ((crtl->args.info.call_cookie & ~ CALL_COOKIE_RET_TRAMP (1)) - || current_function_saves_all_registers)) + || crtl->saves_all_registers)) return gen_frame_mem (SImode, return_address_pointer_rtx); /* If we haven't finished rtl generation, there might be a nonlocal label @@ -10635,25 +11065,29 @@ sh_get_pr_initial_val (void) } int -sh_expand_t_scc (enum rtx_code code, rtx target) +sh_expand_t_scc (rtx operands[]) { + enum rtx_code code = GET_CODE (operands[1]); + rtx target = operands[0]; + rtx op0 = operands[2]; + rtx op1 = operands[3]; rtx result = target; HOST_WIDE_INT val; - if (GET_CODE (sh_compare_op0) != REG || REGNO (sh_compare_op0) != T_REG - || GET_CODE (sh_compare_op1) != CONST_INT) + if (GET_CODE (op0) != REG || REGNO (op0) != T_REG + || GET_CODE (op1) != CONST_INT) return 0; if (GET_CODE (result) != REG) result = gen_reg_rtx (SImode); - val = INTVAL (sh_compare_op1); + val = INTVAL (op1); if ((code == EQ && val == 1) || (code == NE && val == 0)) emit_insn (gen_movt (result)); else if (TARGET_SH2A && ((code == EQ && val == 0) || (code == NE && val == 1))) - emit_insn (gen_movrt (result)); + emit_insn (gen_xorsi3_movrt (result)); else if ((code == EQ && val == 0) || (code == NE && val == 1)) { - emit_insn (gen_rtx_CLOBBER (VOIDmode, result)); + emit_clobber (result); emit_insn (gen_subc (result, result, result)); emit_insn (gen_addsi3 (result, result, const1_rtx)); } @@ -10882,19 +11316,19 @@ replace_n_hard_rtx (rtx x, rtx *replacements, int n_replacements, int modify) if (GET_CODE (x) == SUBREG) { - rtx new = replace_n_hard_rtx (SUBREG_REG (x), replacements, + rtx new_rtx = replace_n_hard_rtx (SUBREG_REG (x), replacements, n_replacements, modify); - if (GET_CODE (new) == CONST_INT) + if (GET_CODE (new_rtx) == CONST_INT) { - x = simplify_subreg (GET_MODE (x), new, + x = simplify_subreg (GET_MODE (x), new_rtx, GET_MODE (SUBREG_REG (x)), SUBREG_BYTE (x)); if (! x) abort (); } else if (modify) - SUBREG_REG (x) = new; + SUBREG_REG (x) = new_rtx; return x; } @@ -10942,18 +11376,18 @@ replace_n_hard_rtx (rtx x, rtx *replacements, int n_replacements, int modify) } else if (GET_CODE (x) == ZERO_EXTEND) { - rtx new = replace_n_hard_rtx (XEXP (x, 0), replacements, + rtx new_rtx = replace_n_hard_rtx (XEXP (x, 0), replacements, n_replacements, modify); - if (GET_CODE (new) == CONST_INT) + if (GET_CODE (new_rtx) == CONST_INT) { x = simplify_unary_operation (ZERO_EXTEND, GET_MODE (x), - new, GET_MODE (XEXP (x, 0))); + new_rtx, GET_MODE (XEXP (x, 0))); if (! x) abort (); } else if (modify) - XEXP (x, 0) = new; + XEXP (x, 0) = new_rtx; return x; } @@ -10961,26 +11395,26 @@ replace_n_hard_rtx (rtx x, rtx *replacements, int n_replacements, int modify) fmt = GET_RTX_FORMAT (GET_CODE (x)); for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--) { - rtx new; + rtx new_rtx; if (fmt[i] == 'e') { - new = replace_n_hard_rtx (XEXP (x, i), replacements, + new_rtx = replace_n_hard_rtx (XEXP (x, i), replacements, n_replacements, modify); - if (!new) + if (!new_rtx) return NULL_RTX; if (modify) - XEXP (x, i) = new; + XEXP (x, i) = new_rtx; } else if (fmt[i] == 'E') for (j = XVECLEN (x, i) - 1; j >= 0; j--) { - new = replace_n_hard_rtx (XVECEXP (x, i, j), replacements, + new_rtx = replace_n_hard_rtx (XVECEXP (x, i, j), replacements, n_replacements, modify); - if (!new) + if (!new_rtx) return NULL_RTX; if (modify) - XVECEXP (x, i, j) = new; + XVECEXP (x, i, j) = new_rtx; } } @@ -11114,12 +11548,12 @@ shmedia_prepare_call_address (rtx fnaddr, int is_sibcall) } enum reg_class -sh_secondary_reload (bool in_p, rtx x, enum reg_class class, +sh_secondary_reload (bool in_p, rtx x, enum reg_class rclass, enum machine_mode mode, secondary_reload_info *sri) { if (in_p) { - if (REGCLASS_HAS_FP_REG (class) + if (REGCLASS_HAS_FP_REG (rclass) && ! TARGET_SHMEDIA && immediate_operand ((x), mode) && ! ((fp_zero_operand (x) || fp_one_operand (x)) @@ -11139,13 +11573,13 @@ sh_secondary_reload (bool in_p, rtx x, enum reg_class class, default: abort (); } - if (class == FPUL_REGS + if (rclass == FPUL_REGS && ((GET_CODE (x) == REG && (REGNO (x) == MACL_REG || REGNO (x) == MACH_REG || REGNO (x) == T_REG)) || GET_CODE (x) == PLUS)) return GENERAL_REGS; - if (class == FPUL_REGS && immediate_operand (x, mode)) + if (rclass == FPUL_REGS && immediate_operand (x, mode)) { if (satisfies_constraint_I08 (x) || fp_zero_operand (x)) return GENERAL_REGS; @@ -11154,11 +11588,11 @@ sh_secondary_reload (bool in_p, rtx x, enum reg_class class, sri->icode = CODE_FOR_reload_insi__i_fpul; return NO_REGS; } - if (class == FPSCR_REGS + if (rclass == FPSCR_REGS && ((GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER) || (GET_CODE (x) == MEM && GET_CODE (XEXP (x, 0)) == PLUS))) return GENERAL_REGS; - if (REGCLASS_HAS_FP_REG (class) + if (REGCLASS_HAS_FP_REG (rclass) && TARGET_SHMEDIA && immediate_operand (x, mode) && x != CONST0_RTX (GET_MODE (x)) @@ -11171,24 +11605,24 @@ sh_secondary_reload (bool in_p, rtx x, enum reg_class class, ? CODE_FOR_reload_inqi : CODE_FOR_reload_inhi); return NO_REGS; } - if (TARGET_SHMEDIA && class == GENERAL_REGS - && (GET_CODE (x) == LABEL_REF || PIC_DIRECT_ADDR_P (x))) + if (TARGET_SHMEDIA && rclass == GENERAL_REGS + && (GET_CODE (x) == LABEL_REF || PIC_ADDR_P (x))) return TARGET_REGS; } /* end of input-only processing. */ - if (((REGCLASS_HAS_FP_REG (class) + if (((REGCLASS_HAS_FP_REG (rclass) && (GET_CODE (x) == REG && (GENERAL_OR_AP_REGISTER_P (REGNO (x)) || (FP_REGISTER_P (REGNO (x)) && mode == SImode && TARGET_FMOVD)))) - || (REGCLASS_HAS_GENERAL_REG (class) + || (REGCLASS_HAS_GENERAL_REG (rclass) && GET_CODE (x) == REG && FP_REGISTER_P (REGNO (x)))) && ! TARGET_SHMEDIA && (mode == SFmode || mode == SImode)) return FPUL_REGS; - if ((class == FPUL_REGS - || (REGCLASS_HAS_FP_REG (class) + if ((rclass == FPUL_REGS + || (REGCLASS_HAS_FP_REG (rclass) && ! TARGET_SHMEDIA && mode == SImode)) && (GET_CODE (x) == MEM || (GET_CODE (x) == REG @@ -11196,20 +11630,20 @@ sh_secondary_reload (bool in_p, rtx x, enum reg_class class, || REGNO (x) == T_REG || system_reg_operand (x, VOIDmode))))) { - if (class == FPUL_REGS) + if (rclass == FPUL_REGS) return GENERAL_REGS; return FPUL_REGS; } - if ((class == TARGET_REGS - || (TARGET_SHMEDIA && class == SIBCALL_REGS)) + if ((rclass == TARGET_REGS + || (TARGET_SHMEDIA && rclass == SIBCALL_REGS)) && !satisfies_constraint_Csy (x) && (GET_CODE (x) != REG || ! GENERAL_REGISTER_P (REGNO (x)))) return GENERAL_REGS; - if ((class == MAC_REGS || class == PR_REGS) + if ((rclass == MAC_REGS || rclass == PR_REGS) && GET_CODE (x) == REG && ! GENERAL_REGISTER_P (REGNO (x)) - && class != REGNO_REG_CLASS (REGNO (x))) + && rclass != REGNO_REG_CLASS (REGNO (x))) return GENERAL_REGS; - if (class != GENERAL_REGS && GET_CODE (x) == REG + if (rclass != GENERAL_REGS && GET_CODE (x) == REG && TARGET_REGISTER_P (REGNO (x))) return GENERAL_REGS; return NO_REGS;