Mercurial > hg > CbC > CbC_gcc
diff gcc/config/sh/sh.c @ 63:b7f97abdc517 gcc-4.6-20100522
update gcc from gcc-4.5.0 to gcc-4.6
author | ryoma <e075725@ie.u-ryukyu.ac.jp> |
---|---|
date | Mon, 24 May 2010 12:47:05 +0900 |
parents | 77e2b8dfacca |
children | f6334be47118 |
line wrap: on
line diff
--- a/gcc/config/sh/sh.c Fri Feb 12 23:41:23 2010 +0900 +++ b/gcc/config/sh/sh.c Mon May 24 12:47:05 2010 +0900 @@ -1,6 +1,7 @@ /* 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, 2009 Free Software Foundation, Inc. + 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 + Free Software Foundation, Inc. Contributed by Steve Chamberlain (sac@cygnus.com). Improved by Jim Wilson (wilson@cygnus.com). @@ -30,6 +31,7 @@ #include "flags.h" #include "expr.h" #include "optabs.h" +#include "reload.h" #include "function.h" #include "regs.h" #include "hard-reg-set.h" @@ -42,7 +44,6 @@ #include "tm_p.h" #include "target.h" #include "target-def.h" -#include "real.h" #include "langhooks.h" #include "basic-block.h" #include "df.h" @@ -106,6 +107,9 @@ and returned from sh_reorder2. */ static short cached_can_issue_more; +/* Unique number for UNSPEC_BBR pattern. */ +static unsigned int unspec_bbr_uid = 1; + /* Provides the class number of the smallest class containing reg number. */ @@ -184,6 +188,7 @@ static void push_regs (HARD_REG_SET *, int); static int calc_live_regs (HARD_REG_SET *); static HOST_WIDE_INT rounded_frame_size (int); +static bool sh_frame_pointer_required (void); static rtx mark_constant_pool_use (rtx); static tree sh_handle_interrupt_handler_attribute (tree *, tree, tree, int, bool *); static tree sh_handle_resbank_handler_attribute (tree *, tree, @@ -498,6 +503,9 @@ #undef TARGET_DWARF_CALLING_CONVENTION #define TARGET_DWARF_CALLING_CONVENTION sh_dwarf_calling_convention +#undef TARGET_FRAME_POINTER_REQUIRED +#define TARGET_FRAME_POINTER_REQUIRED sh_frame_pointer_required + /* Return regmode weight for insn. */ #define INSN_REGMODE_WEIGHT(INSN, MODE) regmode_weight[((MODE) == SImode) ? 0 : 1][INSN_UID (INSN)] @@ -661,7 +669,6 @@ { if (level) { - flag_omit_frame_pointer = 2; if (!size) sh_div_str = "inv:minlat"; } @@ -851,22 +858,13 @@ if (! VALID_REGISTER_P (ADDREGNAMES_REGNO (regno))) sh_additional_register_names[regno][0] = '\0'; - if (flag_omit_frame_pointer == 2) - { - /* The debugging information is sufficient, - but gdb doesn't implement this yet */ - if (0) - flag_omit_frame_pointer - = (PREFERRED_DEBUGGING_TYPE == DWARF2_DEBUG); - else - flag_omit_frame_pointer = 0; - } + flag_omit_frame_pointer = (PREFERRED_DEBUGGING_TYPE == DWARF2_DEBUG); if ((flag_pic && ! TARGET_PREFERGOT) || (TARGET_SHMEDIA && !TARGET_PT_FIXED)) flag_no_function_cse = 1; - if (SMALL_REGISTER_CLASSES) + if (targetm.small_register_classes_for_mode_p (VOIDmode)) \ { /* Never run scheduling before reload, since that can break global alloc, and generates slower code anyway due @@ -892,6 +890,24 @@ flag_schedule_insns = 0; } + if ((target_flags_explicit & MASK_ACCUMULATE_OUTGOING_ARGS) == 0) + target_flags |= MASK_ACCUMULATE_OUTGOING_ARGS; + + /* Unwind info is not correct around the CFG unless either a frame + pointer is present or M_A_O_A is set. Fixing this requires rewriting + unwind info generation to be aware of the CFG and propagating states + around edges. */ + if ((flag_unwind_tables || flag_asynchronous_unwind_tables + || flag_exceptions || flag_non_call_exceptions) + && flag_omit_frame_pointer + && !(target_flags & MASK_ACCUMULATE_OUTGOING_ARGS)) + { + if (target_flags_explicit & MASK_ACCUMULATE_OUTGOING_ARGS) + warning (0, "unwind tables currently require either a frame pointer " + "or -maccumulate-outgoing-args for correctness"); + target_flags |= MASK_ACCUMULATE_OUTGOING_ARGS; + } + /* Unwinding with -freorder-blocks-and-partition does not work on this architecture, because it requires far jumps to label crossing between hot/cold sections which are rejected on this architecture. */ @@ -4392,6 +4408,8 @@ int si_limit; int hi_limit; rtx orig = from; + rtx last_got = NULL_RTX; + rtx last_symoff = NULL_RTX; /* For HImode: range is 510, add 4 because pc counts from address of second instruction after this one, subtract 2 for the jump instruction @@ -4482,6 +4500,16 @@ dst = SET_DEST (pat); mode = GET_MODE (dst); + /* GOT pcrelat setting comes in pair of + mova .L8,r0 + mov.l .L8,r12 + instructions. (plus add r0,r12). + Remember if we see one without the other. */ + if (GET_CODE (src) == UNSPEC && PIC_ADDR_P (XVECEXP (src, 0, 0))) + last_got = last_got ? NULL_RTX : from; + else if (PIC_ADDR_P (src)) + last_got = last_got ? NULL_RTX : from; + /* We must explicitly check the mode, because sometimes the front end will generate code to load unsigned constants into HImode targets without properly sign extending them. */ @@ -4523,6 +4551,16 @@ { switch (untangle_mova (&num_mova, &mova, from)) { + case 1: + if (flag_pic) + { + rtx src = SET_SRC (PATTERN (from)); + if (GET_CODE (src) == CONST + && GET_CODE (XEXP (src, 0)) == UNSPEC + && XINT (XEXP (src, 0), 1) == UNSPEC_SYMOFF) + last_symoff = from; + } + break; case 0: return find_barrier (0, 0, mova); case 2: { @@ -4567,6 +4605,13 @@ && ! TARGET_SMALLCODE) new_align = 4; + /* There is a possibility that a bf is transformed into a bf/s by the + delay slot scheduler. */ + if (JUMP_P (from) && !JUMP_TABLE_DATA_P (from) + && get_attr_type (from) == TYPE_CBRANCH + && GET_CODE (PATTERN (NEXT_INSN (PREV_INSN (from)))) != SEQUENCE) + inc += 2; + if (found_si) { count_si += inc; @@ -4619,6 +4664,12 @@ so we'll make one. */ rtx label = gen_label_rtx (); + /* Don't emit a constant table in the middle of insns for + casesi_worker_2. This is a bit overkill but is enough + because casesi_worker_2 wouldn't appear so frequently. */ + if (last_symoff) + from = last_symoff; + /* If we exceeded the range, then we must back up over the last instruction we looked at. Otherwise, we just need to undo the NEXT_INSN at the end of the loop. */ @@ -4628,6 +4679,20 @@ else from = PREV_INSN (from); + /* Don't emit a constant table int the middle of global pointer setting, + since that that would move the addressing base GOT into another table. + We need the first mov instruction before the _GLOBAL_OFFSET_TABLE_ + in the pool anyway, so just move up the whole constant pool. */ + if (last_got) + from = PREV_INSN (last_got); + + /* Don't insert the constant pool table at the position which + may be the landing pad. */ + if (flag_exceptions + && CALL_P (from) + && find_reg_note (from, REG_EH_REGION, NULL_RTX)) + from = PREV_INSN (from); + /* Walk back to be just before any jump or label. Putting it before a label reduces the number of times the branch around the constant pool table will be hit. Putting it before @@ -4979,8 +5044,8 @@ branch; simplejump_p fails for indirect jumps even if they have a JUMP_LABEL. */ rtx insn = emit_insn_before (gen_indirect_jump_scratch - (reg, GEN_INT (INSN_UID (JUMP_LABEL (jump)))) - , jump); + (reg, GEN_INT (unspec_bbr_uid++)), + jump); /* ??? We would like this to have the scope of the jump, but that scope will change when a delay slot insn of an inner scope is added. Hence, after delay slot scheduling, we'll have to expect @@ -4995,8 +5060,8 @@ /* We can't use JUMP_LABEL here because it might be undefined when not optimizing. */ return emit_insn_before (gen_block_branch_redirect - (GEN_INT (INSN_UID (XEXP (SET_SRC (PATTERN (jump)), 0)))) - , jump); + (GEN_INT (unspec_bbr_uid++)), + jump); return prev; } @@ -5055,7 +5120,7 @@ if (bp->far_label) (emit_insn_after (gen_stuff_delay_slot - (GEN_INT (INSN_UID (XEXP (SET_SRC (PATTERN (jump)), 0))), + (GEN_INT (unspec_bbr_uid++), GEN_INT (recog_memoized (insn) == CODE_FOR_branch_false)), insn)); /* Prevent reorg from undoing our splits. */ @@ -6546,6 +6611,9 @@ HOST_WIDE_INT size = get_frame_size (); HOST_WIDE_INT align = STACK_BOUNDARY / BITS_PER_UNIT; + if (ACCUMULATE_OUTGOING_ARGS) + size += crtl->outgoing_args_size; + return ((size + pushed + align - 1) & -align) - pushed; } @@ -7254,13 +7322,13 @@ pop (PR_REG); } - /* Banked registers are poped first to avoid being scheduled in the + /* Banked registers are popped first to avoid being scheduled in the delay slot. RTE switches banks before the ds instruction. */ if (current_function_interrupt) { - for (i = FIRST_BANKED_REG; i <= LAST_BANKED_REG; i++) - if (TEST_HARD_REG_BIT (live_regs_mask, i)) - pop (LAST_BANKED_REG - i); + for (i = LAST_BANKED_REG; i >= FIRST_BANKED_REG; i--) + if (TEST_HARD_REG_BIT (live_regs_mask, i)) + pop (i); last_reg = FIRST_PSEUDO_REGISTER - LAST_BANKED_REG - 1; } @@ -7394,7 +7462,11 @@ pr_offset = rounded_frame_size (d); emit_insn (GEN_MOV (tmp, GEN_INT (pr_offset))); - emit_insn (GEN_ADD3 (tmp, tmp, hard_frame_pointer_rtx)); + + if (frame_pointer_needed) + emit_insn (GEN_ADD3 (tmp, tmp, hard_frame_pointer_rtx)); + else + emit_insn (GEN_ADD3 (tmp, tmp, stack_pointer_rtx)); tmp = gen_frame_mem (Pmode, tmp); emit_insn (GEN_MOV (tmp, ra)); @@ -9238,7 +9310,7 @@ if (! TEST_HARD_REG_BIT (regs_live, 1)) return gen_rtx_REG (Pmode, 1); - /* Hard reg 1 is live; since this is a SMALL_REGISTER_CLASSES target, + /* Hard reg 1 is live; since this is a small register classes target, there shouldn't be anything but a jump before the function end. */ gcc_assert (!TEST_HARD_REG_BIT (regs_live, 7)); return gen_rtx_REG (Pmode, 7); @@ -9271,9 +9343,7 @@ && GET_CODE (PATTERN (insn)) != USE && GET_CODE (PATTERN (insn)) != CLOBBER) || CALL_P (insn) - || (JUMP_P (insn) - && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC - && GET_CODE (PATTERN (insn)) != ADDR_VEC)) + || (JUMP_P (insn) && !JUMP_TABLE_DATA_P (insn))) && GET_CODE (PATTERN (NEXT_INSN (PREV_INSN (insn)))) != SEQUENCE && get_attr_needs_delay_slot (insn) == NEEDS_DELAY_SLOT_YES) return 2; @@ -9281,9 +9351,7 @@ /* 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_attr == CPU_SH2E - && JUMP_P (insn) - && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC - && GET_CODE (PATTERN (insn)) != ADDR_VEC + && JUMP_P (insn) && !JUMP_TABLE_DATA_P (insn) && get_attr_type (insn) == TYPE_CBRANCH && GET_CODE (PATTERN (NEXT_INSN (PREV_INSN (insn)))) != SEQUENCE) return 2; @@ -9593,6 +9661,87 @@ return x; } +/* Attempt to replace *P, which is an address that needs reloading, with + a valid memory address for an operand of mode MODE. + Like for sh_legitimize_address, for the SH we try to get a normal form + of the address. That will allow inheritance of the address reloads. */ + +bool +sh_legitimize_reload_address (rtx *p, enum machine_mode mode, int opnum, + int itype) +{ + enum reload_type type = (enum reload_type) itype; + + if (GET_CODE (*p) == PLUS + && (GET_MODE_SIZE (mode) == 4 || GET_MODE_SIZE (mode) == 8) + && CONST_INT_P (XEXP (*p, 1)) + && MAYBE_BASE_REGISTER_RTX_P (XEXP (*p, 0), true) + && ! TARGET_SHMEDIA + && ! (TARGET_SH4 && mode == DFmode) + && ! (mode == PSImode && type == RELOAD_FOR_INPUT_ADDRESS) + && (ALLOW_INDEXED_ADDRESS + || XEXP (*p, 0) == stack_pointer_rtx + || XEXP (*p, 0) == hard_frame_pointer_rtx)) + { + rtx index_rtx = XEXP (*p, 1); + HOST_WIDE_INT offset = INTVAL (index_rtx), offset_base; + rtx sum; + + if (TARGET_SH2A && mode == DFmode && (offset & 0x7)) + { + push_reload (*p, NULL_RTX, p, NULL, + BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, opnum, type); + goto win; + } + if (TARGET_SH2E && mode == SFmode) + { + *p = copy_rtx (*p); + push_reload (*p, NULL_RTX, p, NULL, + BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, opnum, type); + goto win; + } + /* 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 = gen_rtx_PLUS (Pmode, XEXP (*p, 0), GEN_INT (offset_base)); + *p = gen_rtx_PLUS (Pmode, sum, GEN_INT (offset - offset_base)); + push_reload (sum, NULL_RTX, &XEXP (*p, 0), NULL, + BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, opnum, type); + goto win; + } + } + /* We must re-recognize what we created before. */ + else if (GET_CODE (*p) == PLUS + && (GET_MODE_SIZE (mode) == 4 || GET_MODE_SIZE (mode) == 8) + && GET_CODE (XEXP (*p, 0)) == PLUS + && CONST_INT_P (XEXP (XEXP (*p, 0), 1)) + && MAYBE_BASE_REGISTER_RTX_P (XEXP (XEXP (*p, 0), 0), true) + && CONST_INT_P (XEXP (*p, 1)) + && ! TARGET_SHMEDIA + && ! (TARGET_SH2E && mode == SFmode)) + { + /* Because this address is so complex, we know it must have + been created by LEGITIMIZE_RELOAD_ADDRESS before; thus, + it is already unshared, and needs no further unsharing. */ + push_reload (XEXP (*p, 0), NULL_RTX, &XEXP (*p, 0), NULL, + BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, opnum, type); + goto win; + } + + return false; + + win: + return true; +} + /* Mark the use of a constant in the literal table. If the constant has multiple labels, make it unique. */ static rtx @@ -10822,6 +10971,20 @@ return false; } +bool +sh_frame_pointer_required (void) +{ +/* If needed override this in other tm.h files to cope with various OS + lossage requiring a frame pointer. */ + if (SUBTARGET_FRAME_POINTER_REQUIRED) + return true; + + if (crtl->profile) + return true; + + return false; +} + /* Implements target hook dwarf_calling_convention. Return an enum of dwarf_calling_convention. */ int @@ -11088,6 +11251,14 @@ return 0; } +/* Return true if registers in machine mode MODE will likely be + allocated to registers in small register classes. */ + +bool +sh_small_register_classes_for_mode_p (enum machine_mode mode ATTRIBUTE_UNUSED) +{ + return (! TARGET_SHMEDIA); +} /* If ADDRESS refers to a CODE_LABEL, add NUSES to the number of times that label is used. */