diff options
Diffstat (limited to 'gcc/config/rs6000/rs6000.c')
-rw-r--r-- | gcc/config/rs6000/rs6000.c | 262 |
1 files changed, 97 insertions, 165 deletions
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 34071f20a19..2af2bf0c655 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -2391,148 +2391,28 @@ ccr_bit (op, scc_p) } } -/* Return the GOT register, creating it if needed. */ +/* Return the GOT register. */ struct rtx_def * rs6000_got_register (value) rtx value; { - if (! current_function_uses_pic_offset_table || ! pic_offset_table_rtx) - { - if (no_new_pseudos) - fatal_insn ("internal error -- needed new GOT register during reload phase to load:", - value); - - current_function_uses_pic_offset_table = 1; - pic_offset_table_rtx = gen_rtx_REG (Pmode, GOT_TOC_REGNUM); - } + /* The second flow pass currently (June 1999) can't update regs_ever_live + without disturbing other parts of the compiler, so update it here to + make the prolog/epilogue code happy. */ + if (no_new_pseudos && !regs_ever_live[PIC_OFFSET_TABLE_REGNUM]) + regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1; + current_function_uses_pic_offset_table = 1; return pic_offset_table_rtx; } - -/* Replace all occurrences of register FROM with an new pseudo register in an insn X. - Store the pseudo register used in REG. - This is only safe during FINALIZE_PIC, since the registers haven't been setup - yet. */ - -static rtx -rs6000_replace_regno (x, from, reg) - rtx x; - int from; - rtx *reg; -{ - register int i, j; - register const char *fmt; - - /* Allow this function to make replacements in EXPR_LISTs. */ - if (!x) - return x; - - switch (GET_CODE (x)) - { - case SCRATCH: - case PC: - case CC0: - case CONST_INT: - case CONST_DOUBLE: - case CONST: - case SYMBOL_REF: - case LABEL_REF: - return x; - - case REG: - if (REGNO (x) == from) - { - if (! *reg) - *reg = pic_offset_table_rtx = gen_reg_rtx (Pmode); - - return *reg; - } - - return x; - - default: - break; - } - - fmt = GET_RTX_FORMAT (GET_CODE (x)); - for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--) - { - if (fmt[i] == 'e') - XEXP (x, i) = rs6000_replace_regno (XEXP (x, i), from, reg); - else if (fmt[i] == 'E') - for (j = XVECLEN (x, i) - 1; j >= 0; j--) - XVECEXP (x, i, j) = rs6000_replace_regno (XVECEXP (x, i, j), from, reg); - } - - return x; -} - - -/* By generating position-independent code, when two different - programs (A and B) share a common library (libC.a), the text of - the library can be shared whether or not the library is linked at - the same address for both programs. In some of these - environments, position-independent code requires not only the use - of different addressing modes, but also special code to enable the - use of these addressing modes. - - The `FINALIZE_PIC' macro serves as a hook to emit these special - codes once the function is being compiled into assembly code, but - not before. (It is not done before, because in the case of - compiling an inline function, it would lead to multiple PIC - prologues being included in functions which used inline functions - and were compiled to assembly language.) */ - -void -rs6000_finalize_pic () -{ - /* Loop through all of the insns, replacing the special GOT_TOC_REGNUM - with an appropriate pseudo register. If we find we need GOT/TOC, - add the appropriate init code. */ - if (flag_pic && (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS)) - { - rtx insn = get_insns (); - rtx reg = NULL_RTX; - rtx first_insn; - rtx last_insn = NULL_RTX; - - if (GET_CODE (insn) == NOTE) - insn = next_nonnote_insn (insn); - - first_insn = insn; - for ( ; insn != NULL_RTX; insn = NEXT_INSN (insn)) - { - if (GET_RTX_CLASS (GET_CODE (insn)) == 'i') - { - PATTERN (insn) = rs6000_replace_regno (PATTERN (insn), - GOT_TOC_REGNUM, - ®); - - if (REG_NOTES (insn)) - REG_NOTES (insn) = rs6000_replace_regno (REG_NOTES (insn), - GOT_TOC_REGNUM, - ®); - } - - if (GET_CODE (insn) != NOTE) - last_insn = insn; - } - - if (reg) - { - rtx init = gen_init_v4_pic (reg); - emit_insn_before (init, first_insn); - if (!optimize && last_insn) - emit_insn_after (gen_rtx_USE (VOIDmode, reg), last_insn); - } - } -} - - /* Search for any occurrence of the GOT_TOC register marker that should - have been eliminated, but may have crept back in. */ + have been eliminated, but may have crept back in. + + This function could completely go away now (June 1999), but we leave it + in for a while until all the possible issues with the new -fpic handling + are resolved. */ void rs6000_reorg (insn) @@ -2540,7 +2420,7 @@ rs6000_reorg (insn) { if (flag_pic && (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS)) { - rtx got_reg = gen_rtx_REG (Pmode, GOT_TOC_REGNUM); + rtx got_reg = gen_rtx_REG (Pmode, 2); for ( ; insn != NULL_RTX; insn = NEXT_INSN (insn)) if (GET_RTX_CLASS (GET_CODE (insn)) == 'i' && reg_mentioned_p (got_reg, PATTERN (insn))) @@ -2556,7 +2436,6 @@ struct machine_function int save_toc_p; int fpmem_size; int fpmem_offset; - rtx pic_offset_table_rtx; }; /* Functions to save and restore rs6000_fpmem_size. @@ -2574,7 +2453,6 @@ rs6000_save_machine_status (p) machine->sysv_varargs_p = rs6000_sysv_varargs_p; machine->fpmem_size = rs6000_fpmem_size; machine->fpmem_offset = rs6000_fpmem_offset; - machine->pic_offset_table_rtx = pic_offset_table_rtx; } void @@ -2586,7 +2464,6 @@ rs6000_restore_machine_status (p) rs6000_sysv_varargs_p = machine->sysv_varargs_p; rs6000_fpmem_size = machine->fpmem_size; rs6000_fpmem_offset = machine->fpmem_offset; - pic_offset_table_rtx = machine->pic_offset_table_rtx; free (machine); p->machine = (struct machine_function *)0; @@ -2601,7 +2478,6 @@ rs6000_init_expanders () rs6000_sysv_varargs_p = 0; rs6000_fpmem_size = 0; rs6000_fpmem_offset = 0; - pic_offset_table_rtx = (rtx)0; /* Arrange to save and restore machine status around nested functions. */ save_machine_status = rs6000_save_machine_status; @@ -2646,7 +2522,7 @@ print_operand (file, x, code) case '*': /* Write the register number of the TOC register. */ - fputs (TARGET_MINIMAL_TOC ? reg_names[30] : reg_names[2], file); + fputs (TARGET_MINIMAL_TOC ? reg_names[30] : reg_names[2 /* PIC_OFFSET_TABLE_REGNUM? */ ], file); return; case '$': @@ -2817,10 +2693,11 @@ print_operand (file, x, code) we have already done it, we can just use an offset of word. */ if (GET_CODE (XEXP (x, 0)) == PRE_INC || GET_CODE (XEXP (x, 0)) == PRE_DEC) - output_address (plus_constant (XEXP (XEXP (x, 0), 0), - UNITS_PER_WORD)); + output_address (plus_constant_for_output (XEXP (XEXP (x, 0), 0), + UNITS_PER_WORD)); else - output_address (plus_constant (XEXP (x, 0), UNITS_PER_WORD)); + output_address (plus_constant_for_output (XEXP (x, 0), + UNITS_PER_WORD)); if (small_data_operand (x, GET_MODE (x))) fprintf (file, "@%s(%s)", SMALL_DATA_RELOC, reg_names[SMALL_DATA_REG]); @@ -3252,7 +3129,7 @@ print_operand_address (file, x) ; #endif else - fprintf (file, "(%s)", reg_names[ TARGET_MINIMAL_TOC ? 30 : 2 ]); + fprintf (file, "(%s)", reg_names[ TARGET_MINIMAL_TOC ? 30 : 2 /* PIC_OFFSET_TABLE_REGNUM? */ ]); } else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == REG) { @@ -4121,6 +3998,20 @@ output_prolog (file, size) reg_names[sp_reg]); } + /* If we need PIC_OFFSET_TABLE_REGNUM, initialize it now */ + if ((DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) + && flag_pic == 1 && regs_ever_live[PIC_OFFSET_TABLE_REGNUM]) + { + if (!info->lr_save_p) + asm_fprintf (file, "\tmflr %s\n", reg_names[0]); + + fputs ("\tbl _GLOBAL_OFFSET_TABLE_@local-4\n", file); + asm_fprintf (file, "\tmflr %s\n", reg_names[PIC_OFFSET_TABLE_REGNUM]); + + if (!info->lr_save_p) + asm_fprintf (file, "\tmtlr %s\n", reg_names[0]); + } + /* NT needs us to probe the stack frame every 4k pages for large frames, so do it here. */ if (DEFAULT_ABI == ABI_NT && info->total_size > 4096) @@ -4595,7 +4486,6 @@ output_mi_thunk (file, thunk_fndecl, delta, function) const char *this_reg = reg_names[ aggregate_value_p (TREE_TYPE (TREE_TYPE (function))) ? 4 : 3 ]; const char *prefix; char *fname; -#if 0 const char *r0 = reg_names[0]; const char *sp = reg_names[1]; const char *toc = reg_names[2]; @@ -4603,12 +4493,11 @@ output_mi_thunk (file, thunk_fndecl, delta, function) const char *r12 = reg_names[12]; char buf[512]; static int labelno = 0; -#endif /* Small constants that can be done by one add instruction */ if (delta >= -32768 && delta <= 32767) { - if (!TARGET_NEW_MNEMONICS) + if (! TARGET_NEW_MNEMONICS) fprintf (file, "\tcal %s,%d(%s)\n", this_reg, delta, this_reg); else fprintf (file, "\taddi %s,%s,%d\n", this_reg, this_reg, delta); @@ -4622,7 +4511,7 @@ output_mi_thunk (file, thunk_fndecl, delta, function) /* 32-bit constants that can be done by an add and addis instruction. */ else if (TARGET_32BIT || num_insns_constant_wide (delta) == 1) { - /* Break into two pieces, propigating the sign bit from the low word to + /* Break into two pieces, propagating the sign bit from the low word to the upper word. */ int delta_high = delta >> 16; int delta_low = delta & 0xffff; @@ -4635,7 +4524,7 @@ output_mi_thunk (file, thunk_fndecl, delta, function) asm_fprintf (file, "\t{cau|addis} %s,%s,%d\n", this_reg, this_reg, delta_high); - if (!TARGET_NEW_MNEMONICS) + if (! TARGET_NEW_MNEMONICS) fprintf (file, "\tcal %s,%d(%s)\n", this_reg, delta_low, this_reg); else fprintf (file, "\taddi %s,%s,%d\n", this_reg, this_reg, delta_low); @@ -4670,21 +4559,15 @@ output_mi_thunk (file, thunk_fndecl, delta, function) Otherwise, load up its address and jump to it. */ fname = XSTR (XEXP (DECL_RTL (function), 0), 0); -#if 1 - /* For now, just emit a branch always, until we can figure out better when we - need to load the address into the count register and emit the slower bctr - instruction. */ - fprintf (file, "\tb %s", prefix); - assemble_name (file, fname); - fprintf (file, "\n"); -#else if (current_file_function_operand (XEXP (DECL_RTL (function), 0)) - && !lookup_attribute ("longcall", TYPE_ATTRIBUTES (TREE_TYPE (function)))) + && ! lookup_attribute ("longcall", + TYPE_ATTRIBUTES (TREE_TYPE (function)))) { fprintf (file, "\tb %s", prefix); assemble_name (file, fname); - fprintf (file, "\n"); + if (DEFAULT_ABI == ABI_V4 && flag_pic) fputs ("@local", file); + fputs ("\n", file); } else @@ -4729,8 +4612,14 @@ output_mi_thunk (file, thunk_fndecl, delta, function) asm_fprintf (file, "\tbctr\n"); break; - /* Don't use r11, that contains the static chain, just use r0/r12. */ case ABI_V4: + fprintf (file, "\tb %s", prefix); + assemble_name (file, fname); + if (flag_pic) fputs ("@plt", file); + fputs ("\n", file); + break; + + /* Don't use r11, that contains the static chain, just use r0/r12. */ case ABI_AIX_NODESC: case ABI_SOLARIS: if (flag_pic == 1) @@ -4785,7 +4674,6 @@ output_mi_thunk (file, thunk_fndecl, delta, function) break; } } -#endif /* #if 0 out code to use bctr for far away jumps */ } @@ -4838,6 +4726,7 @@ output_toc (file, x, labelno) REAL_VALUE_FROM_CONST_DOUBLE (rv, x); REAL_VALUE_TO_TARGET_DOUBLE (rv, k); + if (TARGET_64BIT) { if (TARGET_MINIMAL_TOC) @@ -4850,9 +4739,9 @@ output_toc (file, x, labelno) else { if (TARGET_MINIMAL_TOC) - fprintf (file, "\t.long %ld\n\t.long %ld\n", k[0], k[1]); + fprintf (file, "\t.long 0x%lx\n\t.long 0x%lx\n", k[0], k[1]); else - fprintf (file, "\t.tc FD_%lx_%lx[TC],%ld,%ld\n", + fprintf (file, "\t.tc FD_%lx_%lx[TC],0x%lx,0x%lx\n", k[0], k[1], k[0], k[1]); return; } @@ -4866,11 +4755,22 @@ output_toc (file, x, labelno) REAL_VALUE_FROM_CONST_DOUBLE (rv, x); REAL_VALUE_TO_TARGET_SINGLE (rv, l); - if (TARGET_MINIMAL_TOC) - fprintf (file, TARGET_32BIT ? "\t.long %ld\n" : "\t.llong %ld\n", l); + if (TARGET_64BIT) + { + if (TARGET_MINIMAL_TOC) + fprintf (file, "\t.llong 0x%lx00000000\n", l); + else + fprintf (file, "\t.tc FS_%lx[TC],0x%lx00000000\n", l, l); + return; + } else - fprintf (file, "\t.tc FS_%lx[TC],%ld\n", l, l); - return; + { + if (TARGET_MINIMAL_TOC) + fprintf (file, "\t.long 0x%lx\n", l); + else + fprintf (file, "\t.tc FS_%lx[TC],0x%lx\n", l, l); + return; + } } else if (GET_MODE (x) == DImode && (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE) @@ -5789,7 +5689,39 @@ rs6000_encode_section_info (decl) } #endif /* USING_SVR4_H */ + +/* Return a REG that occurs in ADDR with coefficient 1. + ADDR can be effectively incremented by incrementing REG. + + r0 is special and we must not select it as an address + register by this routine since our caller will try to + increment the returned register via an "la" instruction. */ + +struct rtx_def * +find_addr_reg (addr) + rtx addr; +{ + while (GET_CODE (addr) == PLUS) + { + if (GET_CODE (XEXP (addr, 0)) == REG + && REGNO (XEXP (addr, 0)) != 0) + addr = XEXP (addr, 0); + else if (GET_CODE (XEXP (addr, 1)) == REG + && REGNO (XEXP (addr, 1)) != 0) + addr = XEXP (addr, 1); + else if (CONSTANT_P (XEXP (addr, 0))) + addr = XEXP (addr, 1); + else if (CONSTANT_P (XEXP (addr, 1))) + addr = XEXP (addr, 0); + else + abort (); + } + if (GET_CODE (addr) == REG && REGNO (addr) != 0) + return addr; + abort (); +} + void rs6000_fatal_bad_address (op) rtx op; |