X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fconfig%2Frs6000%2Frs6000.c;h=4dc83c103c27683bd7466fcf4cafa31074388462;hb=33aab1ad32b9b137f4f09b5d8cbfd89503546088;hp=8a7e0e64d95674f6cf12f8aa0f8f1c951a389dd9;hpb=582764be61fd98a6c445d188286e3d06f6ec304a;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 8a7e0e64d95..4dc83c103c2 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -399,6 +399,13 @@ static void rs6000_move_block_from_reg(int regno, rtx x, int nregs); static void setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode, tree, int *, int); +#if TARGET_MACHO +static void macho_branch_islands (void); +static void add_compiler_branch_island (tree, tree, int); +static int no_previous_def (tree function_name); +static tree get_prev_label (tree function_name); +#endif + static tree rs6000_build_builtin_va_list (void); /* Hash table stuff for keeping track of TOC entries. */ @@ -617,147 +624,79 @@ rs6000_override_options (const char *default_cpu) { size_t i, j; struct rs6000_cpu_select *ptr; + int set_masks; - /* Simplify the entries below by making a mask for any POWER - variant and any PowerPC variant. */ + /* Simplifications for entries below. */ -#define POWER_MASKS (MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING) -#define POWERPC_MASKS (MASK_POWERPC | MASK_PPC_GPOPT \ - | MASK_PPC_GFXOPT | MASK_POWERPC64) -#define POWERPC_OPT_MASKS (MASK_PPC_GPOPT | MASK_PPC_GFXOPT) + enum { + POWERPC_BASE_MASK = MASK_POWERPC | MASK_NEW_MNEMONICS, + POWERPC_7400_MASK = POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_ALTIVEC + }; + /* This table occasionally claims that a processor does not support + a particular feature even though it does, but the feature is slower + than the alternative. Thus, it shouldn't be relied on as a + complete description of the processor's support. + + Please keep this list in order, and don't forget to update the + documentation in invoke.texi when adding a new processor or + flag. */ static struct ptt { const char *const name; /* Canonical processor name. */ const enum processor_type processor; /* Processor type enum value. */ const int target_enable; /* Target flags to enable. */ - const int target_disable; /* Target flags to disable. */ } const processor_target_table[] - = {{"common", PROCESSOR_COMMON, MASK_NEW_MNEMONICS, - POWER_MASKS | POWERPC_MASKS}, - {"power", PROCESSOR_POWER, - MASK_POWER | MASK_MULTIPLE | MASK_STRING, - MASK_POWER2 | POWERPC_MASKS | MASK_NEW_MNEMONICS}, - {"power2", PROCESSOR_POWER, - MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING, - POWERPC_MASKS | MASK_NEW_MNEMONICS}, - {"power3", PROCESSOR_PPC630, - MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS, - POWER_MASKS}, - {"power4", PROCESSOR_POWER4, - MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS | MASK_MFCRF, - POWER_MASKS}, - {"powerpc", PROCESSOR_POWERPC, - MASK_POWERPC | MASK_NEW_MNEMONICS, - POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64}, - {"powerpc64", PROCESSOR_POWERPC64, - MASK_POWERPC | MASK_POWERPC64 | MASK_NEW_MNEMONICS, - POWER_MASKS | POWERPC_OPT_MASKS}, - {"rios", PROCESSOR_RIOS1, - MASK_POWER | MASK_MULTIPLE | MASK_STRING, - MASK_POWER2 | POWERPC_MASKS | MASK_NEW_MNEMONICS}, - {"rios1", PROCESSOR_RIOS1, - MASK_POWER | MASK_MULTIPLE | MASK_STRING, - MASK_POWER2 | POWERPC_MASKS | MASK_NEW_MNEMONICS}, - {"rsc", PROCESSOR_PPC601, - MASK_POWER | MASK_MULTIPLE | MASK_STRING, - MASK_POWER2 | POWERPC_MASKS | MASK_NEW_MNEMONICS}, - {"rsc1", PROCESSOR_PPC601, - MASK_POWER | MASK_MULTIPLE | MASK_STRING, - MASK_POWER2 | POWERPC_MASKS | MASK_NEW_MNEMONICS}, - {"rios2", PROCESSOR_RIOS2, - MASK_POWER | MASK_MULTIPLE | MASK_STRING | MASK_POWER2, - POWERPC_MASKS | MASK_NEW_MNEMONICS}, - {"rs64a", PROCESSOR_RS64A, - MASK_POWERPC | MASK_NEW_MNEMONICS, - POWER_MASKS | POWERPC_OPT_MASKS}, - {"401", PROCESSOR_PPC403, - MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS, - POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64}, + = {{"401", PROCESSOR_PPC403, POWERPC_BASE_MASK | MASK_SOFT_FLOAT}, {"403", PROCESSOR_PPC403, - MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS | MASK_STRICT_ALIGN, - POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64}, - {"405", PROCESSOR_PPC405, - MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS, - POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64}, - {"405fp", PROCESSOR_PPC405, - MASK_POWERPC | MASK_NEW_MNEMONICS, - POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64}, - {"440", PROCESSOR_PPC440, - MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS, - POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64}, - {"440fp", PROCESSOR_PPC440, - MASK_POWERPC | MASK_NEW_MNEMONICS, - POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64}, - {"505", PROCESSOR_MPCCORE, - MASK_POWERPC | MASK_NEW_MNEMONICS, - POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64}, + POWERPC_BASE_MASK | MASK_SOFT_FLOAT | MASK_STRICT_ALIGN}, + {"405", PROCESSOR_PPC405, POWERPC_BASE_MASK | MASK_SOFT_FLOAT}, + {"405fp", PROCESSOR_PPC405, POWERPC_BASE_MASK}, + {"440", PROCESSOR_PPC440, POWERPC_BASE_MASK | MASK_SOFT_FLOAT}, + {"440fp", PROCESSOR_PPC440, POWERPC_BASE_MASK}, + {"505", PROCESSOR_MPCCORE, POWERPC_BASE_MASK}, {"601", PROCESSOR_PPC601, - MASK_POWER | MASK_POWERPC | MASK_NEW_MNEMONICS | MASK_MULTIPLE | MASK_STRING, - MASK_POWER2 | POWERPC_OPT_MASKS | MASK_POWERPC64}, - {"602", PROCESSOR_PPC603, - MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS, - POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64}, - {"603", PROCESSOR_PPC603, - MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS, - POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64}, - {"603e", PROCESSOR_PPC603, - MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS, - POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64}, - {"ec603e", PROCESSOR_PPC603, - MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS, - POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64}, - {"604", PROCESSOR_PPC604, - MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS, - POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64}, - {"604e", PROCESSOR_PPC604e, - MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS, - POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64}, - {"620", PROCESSOR_PPC620, - MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS, - POWER_MASKS}, - {"630", PROCESSOR_PPC630, - MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS, - POWER_MASKS}, - {"740", PROCESSOR_PPC750, - MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS, - POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64}, - {"750", PROCESSOR_PPC750, - MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS, - POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64}, - {"G3", PROCESSOR_PPC750, - MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS, - POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64}, - {"7400", PROCESSOR_PPC7400, - MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS, - POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64}, - {"7450", PROCESSOR_PPC7450, - MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS, - POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64}, - {"G4", PROCESSOR_PPC7450, - MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS, - POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64}, - {"8540", PROCESSOR_PPC8540, - MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS, - POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64}, - {"801", PROCESSOR_MPCCORE, - MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS, - POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64}, - {"821", PROCESSOR_MPCCORE, - MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS, - POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64}, - {"823", PROCESSOR_MPCCORE, - MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS, - POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64}, - {"860", PROCESSOR_MPCCORE, - MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS, - POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64}, + MASK_POWER | POWERPC_BASE_MASK | MASK_MULTIPLE | MASK_STRING}, + {"602", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_PPC_GFXOPT}, + {"603", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_PPC_GFXOPT}, + {"603e", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_PPC_GFXOPT}, + {"604", PROCESSOR_PPC604, POWERPC_BASE_MASK | MASK_PPC_GFXOPT}, + {"604e", PROCESSOR_PPC604e, POWERPC_BASE_MASK | MASK_PPC_GFXOPT}, + {"620", PROCESSOR_PPC620, POWERPC_BASE_MASK | MASK_PPC_GFXOPT}, + {"630", PROCESSOR_PPC630, POWERPC_BASE_MASK | MASK_PPC_GFXOPT}, + {"740", PROCESSOR_PPC750, POWERPC_BASE_MASK | MASK_PPC_GFXOPT}, + {"7400", PROCESSOR_PPC7400, POWERPC_7400_MASK}, + {"7450", PROCESSOR_PPC7450, POWERPC_7400_MASK}, + {"750", PROCESSOR_PPC750, POWERPC_BASE_MASK | MASK_PPC_GFXOPT}, + {"801", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT}, + {"821", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT}, + {"823", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT}, + {"8540", PROCESSOR_PPC8540, POWERPC_BASE_MASK | MASK_PPC_GFXOPT}, + {"860", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT}, {"970", PROCESSOR_POWER4, - MASK_POWERPC | POWERPC_OPT_MASKS | MASK_NEW_MNEMONICS | MASK_MFCRF, - POWER_MASKS}, + POWERPC_7400_MASK | MASK_PPC_GPOPT | MASK_MFCRF | MASK_POWERPC64}, + {"common", PROCESSOR_COMMON, MASK_NEW_MNEMONICS}, + {"ec603e", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_SOFT_FLOAT}, + {"G3", PROCESSOR_PPC750, POWERPC_BASE_MASK | MASK_PPC_GFXOPT}, + {"G4", PROCESSOR_PPC7450, POWERPC_7400_MASK}, {"G5", PROCESSOR_POWER4, - MASK_POWERPC | POWERPC_OPT_MASKS | MASK_NEW_MNEMONICS | MASK_MFCRF, - POWER_MASKS}}; + POWERPC_7400_MASK | MASK_PPC_GPOPT | MASK_MFCRF | MASK_POWERPC64}, + {"power", PROCESSOR_POWER, MASK_POWER | MASK_MULTIPLE | MASK_STRING}, + {"power2", PROCESSOR_POWER, + MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING}, + {"power3", PROCESSOR_PPC630, POWERPC_BASE_MASK | MASK_PPC_GFXOPT}, + {"power4", PROCESSOR_POWER4, POWERPC_BASE_MASK | MASK_PPC_GFXOPT}, + {"powerpc", PROCESSOR_POWERPC, POWERPC_BASE_MASK}, + {"powerpc64", PROCESSOR_POWERPC64, + POWERPC_BASE_MASK | MASK_POWERPC64}, + {"rios", PROCESSOR_RIOS1, MASK_POWER | MASK_MULTIPLE | MASK_STRING}, + {"rios1", PROCESSOR_RIOS1, MASK_POWER | MASK_MULTIPLE | MASK_STRING}, + {"rios2", PROCESSOR_RIOS2, + MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING}, + {"rsc", PROCESSOR_PPC601, MASK_POWER | MASK_MULTIPLE | MASK_STRING}, + {"rsc1", PROCESSOR_PPC601, MASK_POWER | MASK_MULTIPLE | MASK_STRING}, + {"rs64a", PROCESSOR_RS64A, POWERPC_BASE_MASK}, + }; const size_t ptt_size = ARRAY_SIZE (processor_target_table); @@ -766,6 +705,28 @@ rs6000_override_options (const char *default_cpu) /* Save current -mstring/-mno-string status. */ int string = TARGET_STRING; + /* Some OSs don't support saving the high part of 64-bit registers on + context switch. Other OSs don't support saving Altivec registers. + On those OSs, we don't touch the MASK_POWERPC64 or MASK_ALTIVEC + settings; if the user wants either, the user must explicitly specify + them and we won't interfere with the user's specification. */ + + enum { + POWER_MASKS = MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING, + POWERPC_MASKS = (POWERPC_BASE_MASK | MASK_PPC_GPOPT + | MASK_PPC_GFXOPT | MASK_POWERPC64 | MASK_ALTIVEC + | MASK_MFCRF) + }; + set_masks = POWER_MASKS | POWERPC_MASKS | MASK_SOFT_FLOAT; +#ifdef OS_MISSING_POWERPC64 + if (OS_MISSING_POWERPC64) + set_masks &= ~MASK_POWERPC64; +#endif +#ifdef OS_MISSING_ALTIVEC + if (OS_MISSING_ALTIVEC) + set_masks &= ~MASK_ALTIVEC; +#endif + /* Identify the processor type. */ rs6000_select[0].string = default_cpu; rs6000_cpu = TARGET_POWERPC64 ? PROCESSOR_DEFAULT64 : PROCESSOR_DEFAULT; @@ -783,8 +744,9 @@ rs6000_override_options (const char *default_cpu) if (ptr->set_arch_p) { - target_flags |= processor_target_table[j].target_enable; - target_flags &= ~processor_target_table[j].target_disable; + target_flags &= ~set_masks; + target_flags |= (processor_target_table[j].target_enable + & set_masks); } break; } @@ -2486,7 +2448,7 @@ legitimate_offset_address_p (enum machine_mode mode, rtx x, int strict) case DFmode: case DImode: - if (TARGET_32BIT) + if (mode == DFmode || !TARGET_POWERPC64) extra = 4; else if (offset & 3) return false; @@ -2494,7 +2456,7 @@ legitimate_offset_address_p (enum machine_mode mode, rtx x, int strict) case TFmode: case TImode: - if (TARGET_32BIT) + if (mode == TFmode || !TARGET_POWERPC64) extra = 12; else if (offset & 3) return false; @@ -2564,7 +2526,7 @@ legitimate_lo_sum_address_p (enum machine_mode mode, rtx x, int strict) return false; x = XEXP (x, 1); - if (TARGET_ELF) + if (TARGET_ELF || TARGET_MACHO) { if (DEFAULT_ABI != ABI_AIX && flag_pic) return false; @@ -2945,6 +2907,9 @@ rs6000_tls_symbol_ref (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED) bool rs6000_tls_referenced_p (rtx x) { + if (! TARGET_HAVE_TLS) + return false; + return for_each_rtx (&x, &rs6000_tls_symbol_ref_1, 0); } @@ -3450,7 +3415,26 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode) /* Handle the case of CONSTANT_P_RTX. */ if (GET_CODE (operands[1]) == CONSTANT_P_RTX) goto emit_set; - + + /* 128-bit constant floating-point values on Darwin should really be + loaded as two parts. */ + if ((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_DARWIN) + && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128 + && mode == TFmode && GET_CODE (operands[1]) == CONST_DOUBLE) + { + /* DImode is used, not DFmode, because simplify_gen_subreg doesn't + know how to get a DFmode SUBREG of a TFmode. */ + rs6000_emit_move (simplify_gen_subreg (DImode, operands[0], mode, 0), + simplify_gen_subreg (DImode, operands[1], mode, 0), + DImode); + rs6000_emit_move (simplify_gen_subreg (DImode, operands[0], mode, + GET_MODE_SIZE (DImode)), + simplify_gen_subreg (DImode, operands[1], mode, + GET_MODE_SIZE (DImode)), + DImode); + return; + } + /* FIXME: In the long term, this switch statement should go away and be replaced by a sequence of tests based on things like mode == Pmode. */ @@ -3696,7 +3680,7 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode) (ALTIVEC_VECTOR_MODE (MODE) \ && (CUM)->vregno <= ALTIVEC_ARG_MAX_REG \ && TARGET_ALTIVEC_ABI \ - && (DEFAULT_ABI == ABI_V4 || (NAMED))) + && (NAMED)) /* Return a nonzero value to say to return the function value in memory, just as large structures are always returned. TYPE will be @@ -4223,7 +4207,7 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, value in GPRs is reported here. */ if (align_words + CLASS_MAX_NREGS (mode, GENERAL_REGS) > GP_ARG_NUM_REG) - /* Fortunately, there are only two possibilites, the value + /* Fortunately, there are only two possibilities, the value is either wholly in GPRs or half in GPRs and half not. */ part_mode = DImode; @@ -8295,7 +8279,8 @@ addrs_ok_for_quad_peep (rtx addr1, rtx addr2) enum reg_class secondary_reload_class (enum reg_class class, - enum machine_mode mode ATTRIBUTE_UNUSED, rtx in) + enum machine_mode mode ATTRIBUTE_UNUSED, + rtx in) { int regno; @@ -10000,73 +9985,72 @@ rs6000_emit_minmax (rtx dest, enum rtx_code code, rtx op0, rtx op1) emit_move_insn (dest, target); } -/* Called by splitter for multireg moves. - Input: - operands[0] : Destination of move - operands[1] : Source of move +/* Emit instructions to move SRC to DST. Called by splitters for + multi-register moves. It will emit at most one instruction for + each register that is accessed; that is, it won't emit li/lis pairs + (or equivalent for 64-bit code). One of SRC or DST must be a hard + register. */ - Output: - operands[2-n] : Destination slots - operands[n-m] : Source slots - where n = 2 + HARD_REGNO_NREGS (reg, GET_MODE (operands[0])) - m = 2 + 2 * HARD_REGNO_NREGS (reg, GET_MODE (operands[0])) - 1 - - Splits the move of operands[1] to operands[0]. - This is done, if GPRs are one of the operands. In this case - a sequence of simple move insns has to be issued. The sequence of these - move insns has to be done in correct order to avoid early clobber of the - base register or destructive overlap of registers. -*/ - void -rs6000_split_multireg_move (rtx *operands) +rs6000_split_multireg_move (rtx dst, rtx src) { - int nregs, reg, i, j, used_update = 0; - enum machine_mode mode; - rtx dst = operands[0]; - rtx src = operands[1]; - rtx insn = 0; - - /* Calculate number to move (2/4 for 32/64 bit mode). */ - - reg = REG_P (operands[0]) ? REGNO (operands[0]) : REGNO (operands[1]); - mode = GET_MODE (operands[0]); - nregs = HARD_REGNO_NREGS (reg, mode); + /* The register number of the first register being moved. */ + int reg; + /* The mode that is to be moved. */ + enum machine_mode mode; + /* The mode that the move is being done in, and its size. */ + enum machine_mode reg_mode; + int reg_mode_size; + /* The number of registers that will be moved. */ + int nregs; + + reg = REG_P (dst) ? REGNO (dst) : REGNO (src); + mode = GET_MODE (dst); + nregs = HARD_REGNO_NREGS (reg, mode); + if (FP_REGNO_P (reg)) + reg_mode = DFmode; + else if (ALTIVEC_REGNO_P (reg)) + reg_mode = V16QImode; + else + reg_mode = word_mode; + reg_mode_size = GET_MODE_SIZE (reg_mode); - if (REG_P (operands[1]) - && REG_P (operands[0]) - && (REGNO (operands[1]) < REGNO (operands[0]))) - { - /* Move register range backwards, if we have destructive overlap. */ - - j = nregs; - for (i = 0; i < nregs; i++) - { - j--; - operands[i+2] = operand_subword (operands[0], j, 0, mode); - operands[i+2+nregs] = - operand_subword (operands[1], j, 0, mode); - } - } + if (reg_mode_size * nregs != GET_MODE_SIZE (mode)) + abort (); + + if (REG_P (src) && REG_P (dst) && (REGNO (src) < REGNO (dst))) + { + /* Move register range backwards, if we might have destructive + overlap. */ + int i; + for (i = nregs - 1; i >= 0; i--) + emit_insn (gen_rtx_SET (VOIDmode, + simplify_gen_subreg (reg_mode, dst, mode, + i * reg_mode_size), + simplify_gen_subreg (reg_mode, src, mode, + i * reg_mode_size))); + } else { - j = -1; + int i; + int j = -1; + bool used_update = false; - if (GET_CODE (operands[1]) == MEM) + if (GET_CODE (src) == MEM && INT_REGNO_P (reg)) { rtx breg; - if (GET_CODE (XEXP (operands[1], 0)) == PRE_INC - || GET_CODE (XEXP (operands[1], 0)) == PRE_DEC) + if (GET_CODE (XEXP (src, 0)) == PRE_INC + || GET_CODE (XEXP (src, 0)) == PRE_DEC) { rtx delta_rtx; - breg = XEXP (XEXP (operands[1], 0), 0); - delta_rtx = GET_CODE (XEXP (operands[1], 0)) == PRE_INC - ? GEN_INT (GET_MODE_SIZE (GET_MODE (operands[1]))) - : GEN_INT (-GET_MODE_SIZE (GET_MODE (operands[1]))); - insn = emit_insn (TARGET_32BIT - ? gen_addsi3 (breg, breg, delta_rtx) - : gen_adddi3 (breg, breg, delta_rtx)); + breg = XEXP (XEXP (src, 0), 0); + delta_rtx = GET_CODE (XEXP (src, 0)) == PRE_INC + ? GEN_INT (GET_MODE_SIZE (GET_MODE (src))) + : GEN_INT (-GET_MODE_SIZE (GET_MODE (src))); + emit_insn (TARGET_32BIT + ? gen_addsi3 (breg, breg, delta_rtx) + : gen_adddi3 (breg, breg, delta_rtx)); src = gen_rtx_MEM (mode, breg); } @@ -10086,35 +10070,34 @@ rs6000_split_multireg_move (rtx *operands) j = REGNO (breg) - REGNO (dst); } - if (GET_CODE (operands[0]) == MEM) + if (GET_CODE (dst) == MEM && INT_REGNO_P (reg)) { rtx breg; - if (GET_CODE (XEXP (operands[0], 0)) == PRE_INC - || GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) + if (GET_CODE (XEXP (dst, 0)) == PRE_INC + || GET_CODE (XEXP (dst, 0)) == PRE_DEC) { rtx delta_rtx; - breg = XEXP (XEXP (operands[0], 0), 0); - delta_rtx = GET_CODE (XEXP (operands[0], 0)) == PRE_INC - ? GEN_INT (GET_MODE_SIZE (GET_MODE (operands[0]))) - : GEN_INT (-GET_MODE_SIZE (GET_MODE (operands[0]))); + breg = XEXP (XEXP (dst, 0), 0); + delta_rtx = GET_CODE (XEXP (dst, 0)) == PRE_INC + ? GEN_INT (GET_MODE_SIZE (GET_MODE (dst))) + : GEN_INT (-GET_MODE_SIZE (GET_MODE (dst))); /* We have to update the breg before doing the store. Use store with update, if available. */ if (TARGET_UPDATE) { - insn = emit_insn (TARGET_32BIT - ? gen_movsi_update (breg, breg, delta_rtx, - operand_subword (src, 0, 0, mode)) - : gen_movdi_update (breg, breg, delta_rtx, - operand_subword (src, 0, 0, mode))); - used_update = 1; + rtx nsrc = simplify_gen_subreg (reg_mode, src, mode, 0); + emit_insn (TARGET_32BIT + ? gen_movsi_update (breg, breg, delta_rtx, nsrc) + : gen_movdi_update (breg, breg, delta_rtx, nsrc)); + used_update = true; } else - insn = emit_insn (TARGET_32BIT - ? gen_addsi3 (breg, breg, delta_rtx) - : gen_adddi3 (breg, breg, delta_rtx)); + emit_insn (TARGET_32BIT + ? gen_addsi3 (breg, breg, delta_rtx) + : gen_adddi3 (breg, breg, delta_rtx)); dst = gen_rtx_MEM (mode, breg); } } @@ -10126,15 +10109,16 @@ rs6000_split_multireg_move (rtx *operands) if (j == nregs) j = 0; - operands[i+2] = operand_subword (dst, j, 0, mode); - operands[i+2+nregs] = operand_subword (src, j, 0, mode); - + /* If compiler already emited move of first word by + store with update, no need to do anything. */ if (j == 0 && used_update) - { - /* Already emited move of first word by - store with update -> emit dead insn instead (r := r). */ - operands[i+2] = operands[i+2+nregs]; - } + continue; + + emit_insn (gen_rtx_SET (VOIDmode, + simplify_gen_subreg (reg_mode, dst, mode, + j * reg_mode_size), + simplify_gen_subreg (reg_mode, src, mode, + j * reg_mode_size))); } } } @@ -12432,7 +12416,8 @@ rs6000_output_function_epilogue (FILE *file, } } -#if TARGET_OBJECT_FORMAT == OBJECT_MACHO +#if TARGET_MACHO + macho_branch_islands (); /* Mach-O doesn't support labels at the end of objects, so if it looks like we might want one, insert a NOP. */ { @@ -12511,8 +12496,7 @@ rs6000_output_function_epilogue (FILE *file, official way to get this info, so we use language_string. C is 0. C++ is 9. No number defined for Obj-C, so use the value for C for now. There is no official value for Java, - although IBM appears to be using 13. There is no official value - for Chill, so we've chosen 44 pseudo-randomly. */ + although IBM appears to be using 13. */ if (! strcmp (language_string, "GNU C") || ! strcmp (language_string, "GNU Objective-C")) i = 0; @@ -12526,8 +12510,6 @@ rs6000_output_function_epilogue (FILE *file, i = 9; else if (! strcmp (language_string, "GNU Java")) i = 13; - else if (! strcmp (language_string, "GNU CHILL")) - i = 44; else abort (); fprintf (file, "%d,", i); @@ -13616,7 +13598,7 @@ rs6000_adjust_cost (rtx insn, rtx link, rtx dep_insn ATTRIBUTE_UNUSED, } /* The function returns a true if INSN is microcoded. - Return false ptherwise. */ + Return false otherwise. */ static bool is_microcoded_insn (rtx insn) @@ -13640,7 +13622,7 @@ is_microcoded_insn (rtx insn) return false; } -/* The function returns a non-zero value if INSN can be scheduled only +/* The function returns a nonzero value if INSN can be scheduled only as the first insn in a dispatch group ("dispatch-slot restricted"). In this case, the returned value indicates how many dispatch slots the insn occupies (at the beginning of the group). @@ -14003,7 +13985,7 @@ get_next_active_insn (rtx insn, rtx tail) return next_insn; } -/* Return whether the presence of INSN causes a dispatch group terminatation +/* Return whether the presence of INSN causes a dispatch group termination of group WHICH_GROUP. If WHICH_GROUP == current_group, this function will return true if INSN @@ -14045,7 +14027,7 @@ insn_terminates_group_p (rtx insn, enum group_termination which_group) return false; } -/* Return true if it is recommended to keep NEXT_INSN "far" (in a seperate +/* Return true if it is recommended to keep NEXT_INSN "far" (in a separate dispatch group) from the insns in GROUP_INSNS. Return false otherwise. */ static bool @@ -14083,7 +14065,7 @@ is_costly_group (rtx *group_insns, rtx next_insn) one of the following schemes, depending on the value of the flag -minsert_sched_nops = X: (1) X == sched_finish_regroup_exact: insert exactly as many nops as needed - in order to force NEXT_INSN into a seperate group. + in order to force NEXT_INSN into a separate group. (2) X < sched_finish_regroup_exact: insert exactly X nops. GROUP_END, CAN_ISSUE_MORE and GROUP_COUNT record the state after nop insertion (has a group just ended, how many vacant issue slots remain in the @@ -14719,83 +14701,118 @@ symbolic_operand (rtx op) } #endif -#ifdef RS6000_LONG_BRANCH +#if TARGET_MACHO -static tree stub_list = 0; +static tree branch_island_list = 0; -/* ADD_COMPILER_STUB adds the compiler generated stub for handling - procedure calls to the linked list. */ +/* Remember to generate a branch island for far calls to the given + function. */ -void -add_compiler_stub (tree label_name, tree function_name, int line_number) +static void +add_compiler_branch_island (tree label_name, tree function_name, int line_number) { - tree stub = build_tree_list (function_name, label_name); - TREE_TYPE (stub) = build_int_2 (line_number, 0); - TREE_CHAIN (stub) = stub_list; - stub_list = stub; + tree branch_island = build_tree_list (function_name, label_name); + TREE_TYPE (branch_island) = build_int_2 (line_number, 0); + TREE_CHAIN (branch_island) = branch_island_list; + branch_island_list = branch_island; } -#define STUB_LABEL_NAME(STUB) TREE_VALUE (STUB) -#define STUB_FUNCTION_NAME(STUB) TREE_PURPOSE (STUB) -#define STUB_LINE_NUMBER(STUB) TREE_INT_CST_LOW (TREE_TYPE (STUB)) - -/* OUTPUT_COMPILER_STUB outputs the compiler generated stub for - handling procedure calls from the linked list and initializes the - linked list. */ - -void -output_compiler_stub (void) -{ - char tmp_buf[256]; - char label_buf[256]; - tree stub; +#define BRANCH_ISLAND_LABEL_NAME(BRANCH_ISLAND) TREE_VALUE (BRANCH_ISLAND) +#define BRANCH_ISLAND_FUNCTION_NAME(BRANCH_ISLAND) TREE_PURPOSE (BRANCH_ISLAND) +#define BRANCH_ISLAND_LINE_NUMBER(BRANCH_ISLAND) \ + TREE_INT_CST_LOW (TREE_TYPE (BRANCH_ISLAND)) - if (!flag_pic) - for (stub = stub_list; stub; stub = TREE_CHAIN (stub)) - { - fprintf (asm_out_file, - "%s:\n", IDENTIFIER_POINTER(STUB_LABEL_NAME(stub))); +/* Generate far-jump branch islands for everything on the + branch_island_list. Invoked immediately after the last instruction + of the epilogue has been emitted; the branch-islands must be + appended to, and contiguous with, the function body. Mach-O stubs + are generated in machopic_output_stub(). */ +static void +macho_branch_islands (void) +{ + char tmp_buf[512]; + tree branch_island; + + for (branch_island = branch_island_list; + branch_island; + branch_island = TREE_CHAIN (branch_island)) + { + const char *label = + IDENTIFIER_POINTER (BRANCH_ISLAND_LABEL_NAME (branch_island)); + const char *name = + darwin_strip_name_encoding ( + IDENTIFIER_POINTER (BRANCH_ISLAND_FUNCTION_NAME (branch_island))); + char name_buf[512]; + /* Cheap copy of the details from the Darwin ASM_OUTPUT_LABELREF(). */ + if (name[0] == '*' || name[0] == '&') + strcpy (name_buf, name+1); + else + { + name_buf[0] = '_'; + strcpy (name_buf+1, name); + } + strcpy (tmp_buf, "\n"); + strcat (tmp_buf, label); #if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO) - if (write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG) - fprintf (asm_out_file, "\t.stabd 68,0,%d\n", STUB_LINE_NUMBER(stub)); + if (write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG) + fprintf (asm_out_file, "\t.stabd 68,0," HOST_WIDE_INT_PRINT_UNSIGNED "\n", + BRANCH_ISLAND_LINE_NUMBER(branch_island)); #endif /* DBX_DEBUGGING_INFO || XCOFF_DEBUGGING_INFO */ - - if (IDENTIFIER_POINTER (STUB_FUNCTION_NAME (stub))[0] == '*') - strcpy (label_buf, - IDENTIFIER_POINTER (STUB_FUNCTION_NAME (stub))+1); - else - { - label_buf[0] = '_'; - strcpy (label_buf+1, - IDENTIFIER_POINTER (STUB_FUNCTION_NAME (stub))); - } - - strcpy (tmp_buf, "lis r12,hi16("); - strcat (tmp_buf, label_buf); - strcat (tmp_buf, ")\n\tori r12,r12,lo16("); - strcat (tmp_buf, label_buf); - strcat (tmp_buf, ")\n\tmtctr r12\n\tbctr"); - output_asm_insn (tmp_buf, 0); - + if (flag_pic) + { + strcat (tmp_buf, ":\n\tmflr r0\n\tbcl 20,31,"); + strcat (tmp_buf, label); + strcat (tmp_buf, "_pic\n"); + strcat (tmp_buf, label); + strcat (tmp_buf, "_pic:\n\tmflr r11\n"); + + strcat (tmp_buf, "\taddis r11,r11,ha16("); + strcat (tmp_buf, name_buf); + strcat (tmp_buf, " - "); + strcat (tmp_buf, label); + strcat (tmp_buf, "_pic)\n"); + + strcat (tmp_buf, "\tmtlr r0\n"); + + strcat (tmp_buf, "\taddi r12,r11,lo16("); + strcat (tmp_buf, name_buf); + strcat (tmp_buf, " - "); + strcat (tmp_buf, label); + strcat (tmp_buf, "_pic)\n"); + + strcat (tmp_buf, "\tmtctr r12\n\tbctr\n"); + } + else + { + strcat (tmp_buf, ":\nlis r12,hi16("); + strcat (tmp_buf, name_buf); + strcat (tmp_buf, ")\n\tori r12,r12,lo16("); + strcat (tmp_buf, name_buf); + strcat (tmp_buf, ")\n\tmtctr r12\n\tbctr"); + } + output_asm_insn (tmp_buf, 0); #if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO) - if (write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG) - fprintf(asm_out_file, "\t.stabd 68,0,%d\n", STUB_LINE_NUMBER (stub)); + if (write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG) + fprintf(asm_out_file, "\t.stabd 68,0," HOST_WIDE_INT_PRINT_UNSIGNED "\n", + BRANCH_ISLAND_LINE_NUMBER (branch_island)); #endif /* DBX_DEBUGGING_INFO || XCOFF_DEBUGGING_INFO */ - } + } - stub_list = 0; + branch_island_list = 0; } /* NO_PREVIOUS_DEF checks in the link list whether the function name is already there or not. */ -int +static int no_previous_def (tree function_name) { - tree stub; - for (stub = stub_list; stub; stub = TREE_CHAIN (stub)) - if (function_name == STUB_FUNCTION_NAME (stub)) + tree branch_island; + for (branch_island = branch_island_list; + branch_island; + branch_island = TREE_CHAIN (branch_island)) + if (function_name == BRANCH_ISLAND_FUNCTION_NAME (branch_island)) return 0; return 1; } @@ -14803,13 +14820,15 @@ no_previous_def (tree function_name) /* GET_PREV_LABEL gets the label name from the previous definition of the function. */ -tree +static tree get_prev_label (tree function_name) { - tree stub; - for (stub = stub_list; stub; stub = TREE_CHAIN (stub)) - if (function_name == STUB_FUNCTION_NAME (stub)) - return STUB_LABEL_NAME (stub); + tree branch_island; + for (branch_island = branch_island_list; + branch_island; + branch_island = TREE_CHAIN (branch_island)) + if (function_name == BRANCH_ISLAND_FUNCTION_NAME (branch_island)) + return BRANCH_ISLAND_LABEL_NAME (branch_island); return 0; } @@ -14819,13 +14838,14 @@ get_prev_label (tree function_name) CALL_DEST is the routine we are calling. */ char * -output_call (rtx insn, rtx call_dest, int operand_number) +output_call (rtx insn, rtx *operands, int dest_operand_number, int cookie_operand_number) { static char buf[256]; - if (GET_CODE (call_dest) == SYMBOL_REF && TARGET_LONG_BRANCH && !flag_pic) + if (GET_CODE (operands[dest_operand_number]) == SYMBOL_REF + && (INTVAL (operands[cookie_operand_number]) & CALL_LONG)) { tree labelname; - tree funname = get_identifier (XSTR (call_dest, 0)); + tree funname = get_identifier (XSTR (operands[dest_operand_number], 0)); if (no_previous_def (funname)) { @@ -14839,23 +14859,25 @@ output_call (rtx insn, rtx call_dest, int operand_number) for (; insn && GET_CODE (insn) != NOTE; insn = PREV_INSN (insn)); if (insn) line_number = NOTE_LINE_NUMBER (insn); - add_compiler_stub (labelname, funname, line_number); + add_compiler_branch_island (labelname, funname, line_number); } else labelname = get_prev_label (funname); + /* "jbsr foo, L42" is Mach-O for "Link as 'bl foo' if a 'bl' + instruction will reach 'foo', otherwise link as 'bl L42'". + "L42" should be a 'branch island', that will do a far jump to + 'foo'. Branch islands are generated in + macho_branch_islands(). */ sprintf (buf, "jbsr %%z%d,%.246s", - operand_number, IDENTIFIER_POINTER (labelname)); - return buf; + dest_operand_number, IDENTIFIER_POINTER (labelname)); } else - { - sprintf (buf, "bl %%z%d", operand_number); - return buf; - } + sprintf (buf, "bl %%z%d", dest_operand_number); + return buf; } -#endif /* RS6000_LONG_BRANCH */ +#endif /* TARGET_MACHO */ /* Generate PIC and indirect symbol stubs. */