diff options
author | Geoffrey Keating <geoffk@cygnus.com> | 2000-01-20 01:25:37 +0000 |
---|---|---|
committer | Geoffrey Keating <geoffk@cygnus.com> | 2000-01-20 01:25:37 +0000 |
commit | 2b875abc15ef265c68ae36a50ab4eae52340a5f0 (patch) | |
tree | 951874a231df76c1427d02b01bd715de6db7ea8d | |
parent | 298437d960aaefc1873a0559e6af996f62118d6b (diff) |
* rs6000.c (rs6000_pic_labelno): Always define.
(rs6000_pic_func_labelno): Delete.
(lmw_operation): Check for a zero base register,
which doesn't mean what we want.
(stmw_operation): New function.
(print_operand): Define new 'l' modifier.
(rs6000_stack_info): We must save all 64 bits of the registers
if TARGET_POWERPC64.
(rs6000_output_load_toc_table): Delete.
(rs6000_emit_load_toc_table): New function.
(rs6000_allocate_stack_space): Delete.
(rs6000_emit_allocate_stack): New function.
(rs6000_emit_prologue): New function.
(output_prolog): Use rs6000_emit_prologue.
(rs6000_emit_epilogue): Change a few variable names to be
more accurate. Restore all 64 bits of the registers if
TARGET_POWERPC64. Only restore the FP registers which were used
if they are being saved/restored one-at-a-time.
(output_mi_thunk): Delete inefficient code generation.
(output_function_profiler): Don't use rs6000_output_load_toc_table.
* rs6000.h: Declare rs6000_emit_load_toc_table,
rs6000_allocate_stack_space, stmw_operation. Don't declare
rs6000_output_load_toc_table.
* rs6000.md (elf_high): Allow register 0, but discourage it
heavily.
(elf_low): Support loading into register 0.
(load_toc_aix_si): New pattern.
(load_toc_aix_di): New pattern.
(load_toc_v4_pic_si): New pattern.
(load_toc_v4_pic_di): New pattern.
(load_toc_v4_PIC_1): New pattern.
(load_toc_v4_PIC_1b): New pattern.
(load_toc_v4_PIC_2): New pattern.
(builtin_setjmp_receiver): Use rs6000_emit_load_toc_table.
(nonlocal_goto_receiver): Use rs6000_emit_load_toc_table.
(prologue): New expander.
(movesi_from_cr): New pattern.
(stmw): New pattern.
(save_fpregs_si): New pattern.
(save_fpregs_di): New pattern.
git-svn-id: https://gcc.gnu.org/svn/gcc/branches/newppc-branch@31532 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/config/rs6000/ChangeLog | 43 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.c | 890 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.h | 4 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.md | 153 |
4 files changed, 679 insertions, 411 deletions
diff --git a/gcc/config/rs6000/ChangeLog b/gcc/config/rs6000/ChangeLog index f4a0f3e7392..087946970ad 100644 --- a/gcc/config/rs6000/ChangeLog +++ b/gcc/config/rs6000/ChangeLog @@ -1,3 +1,46 @@ +2000-01-19 Geoffrey Keating <geoffk@cygnus.com> + + * rs6000.c (rs6000_pic_labelno): Always define. + (rs6000_pic_func_labelno): Delete. + (lmw_operation): Check for a zero base register, + which doesn't mean what we want. + (stmw_operation): New function. + (print_operand): Define new 'l' modifier. + (rs6000_stack_info): We must save all 64 bits of the registers + if TARGET_POWERPC64. + (rs6000_output_load_toc_table): Delete. + (rs6000_emit_load_toc_table): New function. + (rs6000_allocate_stack_space): Delete. + (rs6000_emit_allocate_stack): New function. + (rs6000_emit_prologue): New function. + (output_prolog): Use rs6000_emit_prologue. + (rs6000_emit_epilogue): Change a few variable names to be + more accurate. Restore all 64 bits of the registers if + TARGET_POWERPC64. Only restore the FP registers which were used + if they are being saved/restored one-at-a-time. + (output_mi_thunk): Delete inefficient code generation. + (output_function_profiler): Don't use rs6000_output_load_toc_table. + * rs6000.h: Declare rs6000_emit_load_toc_table, + rs6000_allocate_stack_space, stmw_operation. Don't declare + rs6000_output_load_toc_table. + * rs6000.md (elf_high): Allow register 0, but discourage it + heavily. + (elf_low): Support loading into register 0. + (load_toc_aix_si): New pattern. + (load_toc_aix_di): New pattern. + (load_toc_v4_pic_si): New pattern. + (load_toc_v4_pic_di): New pattern. + (load_toc_v4_PIC_1): New pattern. + (load_toc_v4_PIC_1b): New pattern. + (load_toc_v4_PIC_2): New pattern. + (builtin_setjmp_receiver): Use rs6000_emit_load_toc_table. + (nonlocal_goto_receiver): Use rs6000_emit_load_toc_table. + (prologue): New expander. + (movesi_from_cr): New pattern. + (stmw): New pattern. + (save_fpregs_si): New pattern. + (save_fpregs_di): New pattern. + 2000-01-19 Geoff Keating <geoffk@cygnus.com> * rs6000.md (movsi): Don't use force_reg when no_new_pseudos. diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index ebbea80d603..a8d597c02b4 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -78,12 +78,11 @@ static int common_mode_defined; rtx rs6000_compare_op0, rs6000_compare_op1; int rs6000_compare_fp_p; -#ifdef USING_SVR4_H /* Label number of label created for -mrelocatable, to call to so we can get the address of the GOT section */ int rs6000_pic_labelno; -int rs6000_pic_func_labelno; +#ifdef USING_SVR4_H /* Which abi to adhere to */ const char *rs6000_abi_name = RS6000_ABI_NAME; @@ -2523,7 +2522,6 @@ mtcrf_operation (op, mode) return INTVAL (XEXP (XVECEXP (op, 0, 0), 0)) == bitmap; } - /* Return 1 for an PARALLEL suitable for lmw. */ int @@ -2556,6 +2554,8 @@ lmw_operation (op, mode) { offset = 0; base_regno = REGNO (src_addr); + if (base_regno == 0) + return 0; } else if (LEGITIMATE_OFFSET_ADDRESS_P (SImode, src_addr)) { @@ -2599,6 +2599,84 @@ lmw_operation (op, mode) return 1; } + +/* Return 1 for an PARALLEL suitable for stmw. */ + +int +stmw_operation (op, mode) + rtx op; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + int count = XVECLEN (op, 0); + int src_regno; + rtx dest_addr; + int base_regno; + HOST_WIDE_INT offset; + int i; + + /* Perform a quick check so we don't blow up below. */ + if (count <= 1 + || GET_CODE (XVECEXP (op, 0, 0)) != SET + || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != MEM + || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != REG) + return 0; + + src_regno = REGNO (SET_SRC (XVECEXP (op, 0, 0))); + dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, 0)), 0); + + if (src_regno > 31 + || count != 32 - src_regno) + return 0; + + if (LEGITIMATE_INDIRECT_ADDRESS_P (dest_addr)) + { + offset = 0; + base_regno = REGNO (dest_addr); + if (base_regno == 0) + return 0; + } + else if (LEGITIMATE_OFFSET_ADDRESS_P (SImode, dest_addr)) + { + offset = INTVAL (XEXP (dest_addr, 1)); + base_regno = REGNO (XEXP (dest_addr, 0)); + } + else + return 0; + + for (i = 0; i < count; i++) + { + rtx elt = XVECEXP (op, 0, i); + rtx newaddr; + rtx addr_reg; + HOST_WIDE_INT newoffset; + + if (GET_CODE (elt) != SET + || GET_CODE (SET_SRC (elt)) != REG + || GET_MODE (SET_SRC (elt)) != SImode + || REGNO (SET_SRC (elt)) != src_regno + i + || GET_CODE (SET_DEST (elt)) != MEM + || GET_MODE (SET_DEST (elt)) != SImode) + return 0; + newaddr = XEXP (SET_DEST (elt), 0); + if (LEGITIMATE_INDIRECT_ADDRESS_P (newaddr)) + { + newoffset = 0; + addr_reg = newaddr; + } + else if (LEGITIMATE_OFFSET_ADDRESS_P (SImode, newaddr)) + { + addr_reg = XEXP (newaddr, 0); + newoffset = INTVAL (XEXP (newaddr, 1)); + } + else + return 0; + if (REGNO (addr_reg) != base_regno + || newoffset != offset + 4 * i) + return 0; + } + + return 1; +} /* Return 1 if OP is a comparison operation that is valid for a branch insn. We only check the opcode against the mode of the CC value here. */ @@ -3190,6 +3268,27 @@ print_operand (file, x, code) fprintf (file, HOST_WIDE_INT_PRINT_DEC, ~ INT_LOWPART (x)); return; + case 'l': + /* X must be a symbolic constant on ELF. Write an + expression suitable for an 'addi' that adds in the low 16 + bits of the MEM. */ + if (GET_CODE (x) != CONST) + { + print_operand_address (file, x); + fputs ("@l", file); + } + else + { + if (GET_CODE (XEXP (x, 0)) != PLUS + || (GET_CODE (XEXP (XEXP (x, 0), 0)) != SYMBOL_REF + && GET_CODE (XEXP (XEXP (x, 0), 0)) != LABEL_REF) + || GET_CODE (XEXP (XEXP (x, 0), 1)) != CONST_INT) + output_operand_lossage ("invalid %%l value"); + print_operand_address (file, XEXP (XEXP (x, 0), 0)); + fputs ("@l", file); + print_operand (file, XEXP (XEXP (x, 0), 1), 0); + } + case 'L': /* Write second word of DImode or DFmode reference. Works on register or non-indexed memory only. */ @@ -3881,7 +3980,7 @@ rs6000_stack_info () { static rs6000_stack_t info, zero_info; rs6000_stack_t *info_ptr = &info; - int reg_size = TARGET_32BIT ? 4 : 8; + int reg_size = TARGET_POWERPC64 ? 8 : 4; enum rs6000_abi abi; int total_raw_size; @@ -3936,7 +4035,7 @@ rs6000_stack_info () info_ptr->lr_size = reg_size; } - /* Determine if we need to save the condition code registers */ + /* Determine if we need to save the condition code registers. */ if (regs_ever_live[70] || regs_ever_live[71] || regs_ever_live[72]) { info_ptr->cr_save_p = 1; @@ -4179,104 +4278,111 @@ debug_stack_info (info) fprintf (stderr, "\n"); } -/* Write out an instruction to load the TOC_TABLE address into register 30. +/* Emit instructions needed to load the TOC register. This is only needed when TARGET_TOC, TARGET_MINIMAL_TOC, and there is - a constant pool. */ + a constant pool; or for SVR4 -fpic. */ void -rs6000_output_load_toc_table (file, reg) - FILE *file; - int reg; +rs6000_emit_load_toc_table (fromprolog) + int fromprolog; { - char buf[256]; + rtx dest; + dest = gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM); -#ifdef USING_SVR4_H - if (TARGET_RELOCATABLE) + if (TARGET_ELF) { - ASM_GENERATE_INTERNAL_LABEL (buf, "LCF", rs6000_pic_labelno); - fprintf (file, "\tbl "); - assemble_name (file, buf); - fprintf (file, "\n"); - - /* possibly create the toc section */ - if (! toc_initialized) + if ((DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) + && flag_pic == 1) { - toc_section (); - function_section (current_function_decl); + rtx temp = (fromprolog + ? gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM) + : gen_reg_rtx (Pmode)); + if (TARGET_32BIT) + emit_insn (gen_load_toc_v4_pic_si (temp)); + else + emit_insn (gen_load_toc_v4_pic_di (temp)); + emit_move_insn (dest, temp); } - - /* If not first call in this function, we need to put the - different between .LCTOC1 and the address we get to right - after the bl. It will mess up disassembling the instructions - but that can't be helped. We will later need to bias the - address before loading. */ - if (rs6000_pic_func_labelno != rs6000_pic_labelno) - { - const char *init_ptr = TARGET_32BIT ? ".long" : ".quad"; - const char *buf_ptr; - - ASM_OUTPUT_INTERNAL_LABEL (file, "LCL", rs6000_pic_labelno); - - ASM_GENERATE_INTERNAL_LABEL (buf, "LCTOC", 1); - STRIP_NAME_ENCODING (buf_ptr, buf); - fprintf (file, "\t%s %s-", init_ptr, buf_ptr); - + else if (flag_pic == 2) + { + char buf[30]; + rtx tempLR = (fromprolog + ? gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM) + : gen_reg_rtx (Pmode)); + rtx temp0 = (fromprolog + ? gen_rtx_REG (Pmode, 0) + : gen_reg_rtx (Pmode)); + rtx symF; + ASM_GENERATE_INTERNAL_LABEL (buf, "LCF", rs6000_pic_labelno); - fprintf (file, "%s\n", buf_ptr); - } + symF = gen_rtx_SYMBOL_REF (Pmode, ggc_alloc_string (buf, -1)); - ASM_OUTPUT_INTERNAL_LABEL (file, "LCF", rs6000_pic_labelno); - fprintf (file, "\tmflr %s\n", reg_names[reg]); + /* possibly create the toc section */ + if (! toc_initialized) + { + toc_section (); + function_section (current_function_decl); + } + + if (fromprolog) + { + rtx symL; + ASM_GENERATE_INTERNAL_LABEL (buf, "LCL", rs6000_pic_labelno); + symL = gen_rtx_SYMBOL_REF (Pmode, ggc_alloc_string (buf, -1)); - if (rs6000_pic_func_labelno != rs6000_pic_labelno) - asm_fprintf(file, "\t{cal|la} %s,%d(%s)\n", reg_names[reg], - (TARGET_32BIT ? 4 : 8), reg_names[reg]); + emit_insn (gen_load_toc_v4_PIC_1 (tempLR, symF)); + emit_move_insn (dest, tempLR); + emit_insn (gen_load_toc_v4_PIC_2 (temp0, dest, symL, symF)); + } + else + { + rtx tocsym; + ASM_GENERATE_INTERNAL_LABEL (buf, "LCTOC", 1); + tocsym = gen_rtx_SYMBOL_REF (Pmode, ggc_alloc_string (buf, -1)); - asm_fprintf (file, (TARGET_32BIT) ? "\t{l|lwz} %s,(" : "\tld %s,(", - reg_names[0]); - ASM_GENERATE_INTERNAL_LABEL (buf, "LCL", rs6000_pic_labelno); - assemble_name (file, buf); - putc ('-', file); - ASM_GENERATE_INTERNAL_LABEL (buf, "LCF", rs6000_pic_labelno); - assemble_name (file, buf); - fprintf (file, ")(%s)\n", reg_names[reg]); - asm_fprintf (file, "\t{cax|add} %s,%s,%s\n", - reg_names[reg], reg_names[0], reg_names[reg]); - rs6000_pic_labelno++; + emit_insn (gen_load_toc_v4_PIC_1b (tempLR, symF, tocsym)); + emit_move_insn (dest, tempLR); + emit_move_insn (temp0, gen_rtx_MEM (Pmode, dest)); + } + emit_insn (gen_addsi3 (dest, temp0, dest)); + rs6000_pic_labelno++; + } + else if (flag_pic == 0 && TARGET_MINIMAL_TOC) + { + /* This is for AIX code running in non-PIC ELF. */ + char buf[30]; + rtx realsym; + ASM_GENERATE_INTERNAL_LABEL (buf, "LCTOC", 0); + realsym = gen_rtx_SYMBOL_REF (Pmode, ggc_alloc_string (buf, -1)); + + emit_insn (gen_elf_high (dest, realsym)); + emit_insn (gen_elf_low (dest, dest, realsym)); + } + else + abort(); } - else if (! TARGET_64BIT) + else { - ASM_GENERATE_INTERNAL_LABEL (buf, "LCTOC", 1); - asm_fprintf (file, "\t{liu|lis} %s,", reg_names[reg]); - assemble_name (file, buf); - fputs ("@ha\n", file); - asm_fprintf (file, "\t{cal|la} %s,", reg_names[reg]); - assemble_name (file, buf); - asm_fprintf (file, "@l(%s)\n", reg_names[reg]); + if (TARGET_32BIT) + emit_insn (gen_load_toc_aix_si (dest)); + else + emit_insn (gen_load_toc_aix_di (dest)); } - else - abort (); - -#else /* !USING_SVR4_H */ - ASM_GENERATE_INTERNAL_LABEL (buf, "LCTOC", 0); - asm_fprintf (file, TARGET_32BIT ? "\t{l|lwz} %s," : "\tld %s,", - reg_names[reg]); - assemble_name (file, buf); - asm_fprintf (file, "(%s)\n", reg_names[2]); -#endif /* USING_SVR4_H */ } - -/* Emit the correct code for allocating stack space. If COPY_R12, make sure a copy - of the old frame is left in r12. */ +/* Emit the correct code for allocating stack space, as insns. + If COPY_R12, make sure a copy of the old frame is left in r12. + The generated code may use hard register 0 as a temporary. */ -void -rs6000_allocate_stack_space (file, size, copy_r12) - FILE *file; - int size; +static void +rs6000_emit_allocate_stack (size, copy_r12) + HOST_WIDE_INT size; int copy_r12; { - int neg_size = -size; + rtx insn; + rtx stack_reg = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM); + rtx tmp_reg = gen_rtx_REG (Pmode, 0); + rtx todec = GEN_INT (-size); if (current_function_limit_stack) { @@ -4284,140 +4390,100 @@ rs6000_allocate_stack_space (file, size, copy_r12) && REGNO (stack_limit_rtx) > 1 && REGNO (stack_limit_rtx) <= 31) { - if (size <= 32767) - asm_fprintf (file, "\t{cal %s,%d(%s)|addi %s,%s,%d}\n", - reg_names[0], reg_names[REGNO (stack_limit_rtx)], - size); - else - { - asm_fprintf (file, "\t{cau|addis} %s,%s,0x%x\n", - reg_names[0], reg_names[REGNO (stack_limit_rtx)], - ((size + 0x8000) >> 16) & 0xffff); - asm_fprintf (file, "\t{ai|addic} %s,%s,%d\n", - reg_names[0], reg_names[0], - (size & 0x7fff) | -(size & 0x8000)); - } - if (TARGET_32BIT) - asm_fprintf (file, "\t{t|tw}llt %s,%s\n", - reg_names[1], reg_names[0]); - else - asm_fprintf (file, "\ttdllt %s,%s\n", reg_names[1], reg_names[0]); + insn = emit_insn (Pmode == SImode + ? gen_addsi3 (tmp_reg, + stack_limit_rtx, + GEN_INT (size)) + : gen_adddi3 (tmp_reg, + stack_limit_rtx, + GEN_INT (size))); + RTX_FRAME_RELATED_P (insn) = 1; + + insn = emit_insn (gen_cond_trap (LTU, stack_reg, tmp_reg, + const0_rtx)); + RTX_FRAME_RELATED_P (insn) = 1; } else if (GET_CODE (stack_limit_rtx) == SYMBOL_REF + && TARGET_32BIT && (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS)) { - char * l_name = XSTR (stack_limit_rtx, 0); - const char * stripped_name; - - STRIP_NAME_ENCODING (stripped_name, l_name); - asm_fprintf (file, "\t{liu|lis} %s,%s@ha+%d\n", - reg_names[0], stripped_name, size); - asm_fprintf (file, "\t{ai|addic} %s,%s,%s@l+%d\n", - reg_names[0], reg_names[0], stripped_name, size); - if (TARGET_32BIT) - asm_fprintf (file, "\t{t|tw}llt %s,%s\n", - reg_names[1], reg_names[0]); - else - asm_fprintf (file, "\ttdllt %s,%s\n", reg_names[1], reg_names[0]); + rtx toload = gen_rtx_CONST (VOIDmode, + gen_rtx_PLUS (Pmode, + stack_limit_rtx, + GEN_INT (size))); + + insn = emit_insn (gen_elf_high (tmp_reg, toload)); + RTX_FRAME_RELATED_P (insn) = 1; + insn = emit_insn (gen_elf_low (tmp_reg, tmp_reg, toload)); + RTX_FRAME_RELATED_P (insn) = 1; + insn = emit_insn (gen_cond_trap (LTU, stack_reg, tmp_reg, + const0_rtx)); + RTX_FRAME_RELATED_P (insn) = 1; } else warning ("stack limit expression is not supported"); } + if (copy_r12 || ! TARGET_UPDATE) + { + insn = emit_move_insn (gen_rtx_REG (Pmode, 12), stack_reg); + RTX_FRAME_RELATED_P (insn) = 1; + } + if (TARGET_UPDATE) { - if (size < 32767) - asm_fprintf (file, - (TARGET_32BIT) ? "\t{stu|stwu} %s,%d(%s)\n" : "\tstdu %s,%d(%s)\n", - reg_names[1], neg_size, reg_names[1]); - else + if (size > 32767) { - if (copy_r12) - fprintf (file, "\tmr %s,%s\n", reg_names[12], reg_names[1]); - - asm_fprintf (file, "\t{liu|lis} %s,0x%x\n\t{oril|ori} %s,%s,%d\n", - reg_names[0], (neg_size >> 16) & 0xffff, - reg_names[0], reg_names[0], neg_size & 0xffff); - asm_fprintf (file, - (TARGET_32BIT) ? "\t{stux|stwux} %s,%s,%s\n" : "\tstdux %s,%s,%s\n", - reg_names[1], reg_names[1], reg_names[0]); + /* Need a note here so that try_split doesn't get confused. */ + if (get_last_insn() == NULL_RTX) + emit_note (0, NOTE_INSN_DELETED); + insn = emit_move_insn (tmp_reg, todec); + insn = try_split (PATTERN (insn), insn, 0); + RTX_FRAME_RELATED_P (insn) = 1; + todec = tmp_reg; } + + if (Pmode == SImode) + insn = emit_insn (gen_movsi_update (stack_reg, stack_reg, + todec, stack_reg)); + else + insn = emit_insn (gen_movdi_update (stack_reg, stack_reg, + todec, stack_reg)); + RTX_FRAME_RELATED_P (insn) = 1; } else { - fprintf (file, "\tmr %s,%s\n", reg_names[12], reg_names[1]); - if (size < 32767) - asm_fprintf (file, "\t{cal|la} %s,%d(%s)\n", - reg_names[1], neg_size, reg_names[1]); + if (Pmode == SImode) + insn = emit_insn (gen_addsi3 (stack_reg, stack_reg, todec)); else - { - asm_fprintf (file, "\t{liu|lis} %s,0x%x\n\t{oril|ori} %s,%s,%d\n", - reg_names[0], (neg_size >> 16) & 0xffff, - reg_names[0], reg_names[0], neg_size & 0xffff); - asm_fprintf (file, "\t{cax|add} %s,%s,%s\n", reg_names[1], - reg_names[0], reg_names[1]); - } - - asm_fprintf (file, - (TARGET_32BIT) ? "\t{st|stw} %s,0(%s)\n" : "\tstd %s,0(%s)\n", - reg_names[12], reg_names[1]); + insn = emit_insn (gen_adddi3 (stack_reg, stack_reg, todec)); + RTX_FRAME_RELATED_P (insn) = 1; + insn = emit_move_insn (gen_rtx_MEM (Pmode, stack_reg), + gen_rtx_REG (Pmode, 12)); + RTX_FRAME_RELATED_P (insn) = 1; } } - -/* Write function prologue. */ +/* Emit function prologue as insns. */ + void -output_prolog (file, size) - FILE *file; - int size ATTRIBUTE_UNUSED; +rs6000_emit_prologue() { rs6000_stack_t *info = rs6000_stack_info (); - int reg_size = info->reg_size; - const char *store_reg; - const char *load_reg; - int sp_reg = 1; - int sp_offset = 0; - - if (TARGET_32BIT) - { - store_reg = "\t{st|stw} %s,%d(%s)\n"; - load_reg = "\t{l|lwz} %s,%d(%s)\n"; - } - else - { - store_reg = "\tstd %s,%d(%s)\n"; - load_reg = "\tlld %s,%d(%s)\n"; - } - - if (TARGET_DEBUG_STACK) - debug_stack_info (info); - - /* Write .extern for any function we will call to save and restore fp - values. */ - if (info->first_fp_reg_save < 64 && !FP_SAVE_INLINE (info->first_fp_reg_save)) - fprintf (file, "\t.extern %s%d%s\n\t.extern %s%d%s\n", - SAVE_FP_PREFIX, info->first_fp_reg_save - 32, SAVE_FP_SUFFIX, - RESTORE_FP_PREFIX, info->first_fp_reg_save - 32, RESTORE_FP_SUFFIX); - - /* Write .extern for truncation routines, if needed. */ - if (rs6000_trunc_used && ! trunc_defined) - { - fprintf (file, "\t.extern .%s\n\t.extern .%s\n", - RS6000_ITRUNC, RS6000_UITRUNC); - trunc_defined = 1; - } - - /* Write .extern for AIX common mode routines, if needed. */ - if (! TARGET_POWER && ! TARGET_POWERPC && ! common_mode_defined) - { - fputs ("\t.extern __mulh\n", file); - fputs ("\t.extern __mull\n", file); - fputs ("\t.extern __divss\n", file); - fputs ("\t.extern __divus\n", file); - fputs ("\t.extern __quoss\n", file); - fputs ("\t.extern __quous\n", file); - common_mode_defined = 1; - } + enum machine_mode reg_mode = TARGET_POWERPC64 ? DImode : SImode; + int reg_size = TARGET_POWERPC64 ? 8 : 4; + rtx sp_reg_rtx = gen_rtx_REG (Pmode, 1); + rtx frame_reg_rtx = sp_reg_rtx; + rtx cr_save_rtx = NULL; + rtx insn; + int saving_FPRs_inline; + int using_store_multiple; + HOST_WIDE_INT sp_offset = 0; + + using_store_multiple = (TARGET_MULTIPLE && ! TARGET_POWERPC64 + && info->first_gp_reg_save < 31); + saving_FPRs_inline = (info->first_fp_reg_save == 64 + || FP_SAVE_INLINE (info->first_fp_reg_save)); /* For V.4, update stack before we do any saving and set back pointer. */ if (info->push_p && (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS)) @@ -4425,148 +4491,245 @@ output_prolog (file, size) if (info->total_size < 32767) sp_offset = info->total_size; else - sp_reg = 12; - rs6000_allocate_stack_space (file, info->total_size, sp_reg == 12); + frame_reg_rtx = gen_rtx_REG (Pmode, 12); + rs6000_emit_allocate_stack (info->total_size, + (frame_reg_rtx != sp_reg_rtx + && (info->cr_save_p + || info->lr_save_p + || info->first_fp_reg_save < 64 + || info->first_gp_reg_save < 32 + ))); } /* If we use the link register, get it into r0. */ if (info->lr_save_p) - asm_fprintf (file, "\tmflr %s\n", reg_names[0]); + { + insn = emit_move_insn (gen_rtx_REG (Pmode, 0), + gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM)); + RTX_FRAME_RELATED_P (insn) = 1; + } /* If we need to save CR, put it into r12. */ - if (info->cr_save_p && sp_reg != 12) - asm_fprintf (file, "\tmfcr %s\n", reg_names[12]); + if (info->cr_save_p && REGNO (frame_reg_rtx) != 12) + { + cr_save_rtx = gen_rtx_REG (SImode, 12); + insn = emit_insn (gen_movesi_from_cr (cr_save_rtx)); + RTX_FRAME_RELATED_P (insn) = 1; + } /* Do any required saving of fpr's. If only one or two to save, do it - ourself. Otherwise, call function. Note that since they are statically - linked, we do not need a nop following them. */ - if (FP_SAVE_INLINE (info->first_fp_reg_save)) + ourself. Otherwise, call function. */ + if (saving_FPRs_inline) { - int regno = info->first_fp_reg_save; - int loc = info->fp_save_offset + sp_offset; - - for ( ; regno < 64; regno++, loc += 8) - asm_fprintf (file, "\tstfd %s,%d(%s)\n", reg_names[regno], loc, reg_names[sp_reg]); + int i; + for (i = 0; i < 64 - info->first_fp_reg_save; i++) + if ((regs_ever_live[info->first_fp_reg_save+i] + && ! call_used_regs[info->first_fp_reg_save+i])) + { + rtx addr; + addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, + GEN_INT (info->fp_save_offset + + sp_offset + + 8*i)); + insn = emit_move_insn (gen_rtx_MEM (DFmode, addr), + gen_rtx_REG (DFmode, + info->first_fp_reg_save + i)); + RTX_FRAME_RELATED_P (insn) = 1; + } } else if (info->first_fp_reg_save != 64) - asm_fprintf (file, "\tbl %s%d%s\n", SAVE_FP_PREFIX, - info->first_fp_reg_save - 32, SAVE_FP_SUFFIX); - - /* Now save gpr's. */ - if (! TARGET_MULTIPLE || info->first_gp_reg_save == 31 || TARGET_64BIT) { - int regno = info->first_gp_reg_save; - int loc = info->gp_save_offset + sp_offset; - - for ( ; regno < 32; regno++, loc += reg_size) - asm_fprintf (file, store_reg, reg_names[regno], loc, reg_names[sp_reg]); + int i; + char rname[30]; + char *alloc_rname; + rtvec p; + p = rtvec_alloc (2 + 64 - info->first_fp_reg_save); + + RTVEC_ELT (p, 0) = gen_rtx_CLOBBER (VOIDmode, + gen_rtx_REG (Pmode, + LINK_REGISTER_REGNUM)); + sprintf (rname, "%s%d%s", SAVE_FP_PREFIX, + info->first_fp_reg_save - 32, SAVE_FP_SUFFIX); + alloc_rname = ggc_alloc_string (rname, -1); + RTVEC_ELT (p, 1) = gen_rtx_USE (VOIDmode, + gen_rtx_SYMBOL_REF (Pmode, + alloc_rname)); + for (i = 0; i < 64 - info->first_fp_reg_save; i++) + { + rtx addr; + addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, + GEN_INT (info->fp_save_offset + + sp_offset + 8*i)); + RTVEC_ELT (p, i + 2) = + gen_rtx_SET (VOIDmode, + gen_rtx_MEM (DFmode, addr), + gen_rtx_REG (DFmode, info->first_fp_reg_save + i)); + } + insn = emit_insn (gen_rtx_PARALLEL (VOIDmode, p)); + RTX_FRAME_RELATED_P (insn) = 1; } - else if (info->first_gp_reg_save != 32) - asm_fprintf (file, "\t{stm|stmw} %s,%d(%s)\n", - reg_names[info->first_gp_reg_save], - info->gp_save_offset + sp_offset, - reg_names[sp_reg]); + /* Save GPRs. This is done as a PARALLEL if we are using + the store-multiple instructions. */ + if (using_store_multiple) + { + rtvec p; + int i; + p = rtvec_alloc (32 - info->first_gp_reg_save); + for (i = 0; i < 32 - info->first_gp_reg_save; i++) + { + rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, + GEN_INT (info->gp_save_offset + + sp_offset + + reg_size * i)); + RTVEC_ELT (p, i) = + gen_rtx_SET (VOIDmode, + gen_rtx_MEM (reg_mode, addr), + gen_rtx_REG (reg_mode, info->first_gp_reg_save + i)); + } + insn = emit_insn (gen_rtx_PARALLEL (VOIDmode, p)); + RTX_FRAME_RELATED_P (insn) = 1; + } + else + { + int i; + for (i = 0; i < 32 - info->first_gp_reg_save; i++) + if ((regs_ever_live[info->first_gp_reg_save+i] + && ! call_used_regs[info->first_gp_reg_save+i]) + || (i+info->first_gp_reg_save == PIC_OFFSET_TABLE_REGNUM + && (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) + && flag_pic == 1)) + { + rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, + GEN_INT (info->gp_save_offset + + sp_offset + + reg_size * i)); + insn = emit_move_insn (gen_rtx_MEM (reg_mode, addr), + gen_rtx_REG (reg_mode, + info->first_gp_reg_save + i)); + RTX_FRAME_RELATED_P (insn) = 1; + } + } /* Save lr if we used it. */ if (info->lr_save_p) - asm_fprintf (file, store_reg, reg_names[0], info->lr_save_offset + sp_offset, - reg_names[sp_reg]); + { + rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, + GEN_INT (info->lr_save_offset + sp_offset)); + insn = emit_move_insn (gen_rtx_MEM (Pmode, addr), + gen_rtx_REG (Pmode, 0)); + RTX_FRAME_RELATED_P (insn) = 1; + } /* Save CR if we use any that must be preserved. */ if (info->cr_save_p) { - if (sp_reg == 12) /* If r12 is used to hold the original sp, copy cr now */ + rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, + GEN_INT (info->cr_save_offset + sp_offset)); + + /* If r12 is used to hold the original sp, copy cr into it now. */ + if (REGNO (frame_reg_rtx) == 12) { - asm_fprintf (file, "\tmfcr %s\n", reg_names[0]); - asm_fprintf (file, store_reg, reg_names[0], - info->cr_save_offset + sp_offset, - reg_names[sp_reg]); + cr_save_rtx = gen_rtx_REG (SImode, 0); + insn = emit_insn (gen_movesi_from_cr (cr_save_rtx)); + RTX_FRAME_RELATED_P (insn) = 1; } - else - asm_fprintf (file, store_reg, reg_names[12], info->cr_save_offset + sp_offset, - reg_names[sp_reg]); + insn = emit_move_insn (gen_rtx_MEM (SImode, addr), cr_save_rtx); + RTX_FRAME_RELATED_P (insn) = 1; } - /* 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]) + /* Update stack and set back pointer unless this is V.4, + for which it was done previously. */ + if (info->push_p && DEFAULT_ABI != ABI_V4 && DEFAULT_ABI != ABI_SOLARIS) + rs6000_emit_allocate_stack (info->total_size, FALSE); + + /* Set frame pointer, if needed. */ + if (frame_pointer_needed) { - if (! info->lr_save_p) - asm_fprintf (file, "\tmflr %s\n", reg_names[0]); + insn = emit_move_insn (gen_rtx_REG (reg_mode, FRAME_POINTER_REGNUM), + sp_reg_rtx); + RTX_FRAME_RELATED_P (insn) = 1; + } - fputs ("\tbl _GLOBAL_OFFSET_TABLE_@local-4\n", file); - asm_fprintf (file, "\tmflr %s\n", reg_names[PIC_OFFSET_TABLE_REGNUM]); + /* If we are using PIC_OFFSET_TABLE_REGNUM, we need to set it up. */ + if ((TARGET_TOC && TARGET_MINIMAL_TOC && get_pool_size () != 0) + || ((DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) + && flag_pic == 1 && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])) + { + /* If emit_load_toc_table will use the link register, we need to save + it. We use R11 for this purpose because emit_load_toc_table + can use register 0. This allows us to use a plain 'blr' to return + from the procedure more often. */ + int save_LR_around_toc_setup = (TARGET_ELF && flag_pic != 0 && + ! info->lr_save_p); + if (save_LR_around_toc_setup) + emit_move_insn (gen_rtx_REG (Pmode, 11), + gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM)); + + rs6000_emit_load_toc_table (gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM)); - if (! info->lr_save_p) - asm_fprintf (file, "\tmtlr %s\n", reg_names[0]); - } + if (save_LR_around_toc_setup) + emit_move_insn (gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM), + gen_rtx_REG (Pmode, 11)); + } +} - /* 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) - { - if (info->total_size < 32768) - { - int probe_offset = 4096; - while (probe_offset < info->total_size) - { - asm_fprintf (file, "\t{l|lwz} %s,%d(%s)\n", reg_names[0], -probe_offset, reg_names[1]); - probe_offset += 4096; - } - } - else - { - int probe_iterations = info->total_size / 4096; - static int probe_labelno = 0; - char buf[256]; - if (probe_iterations < 32768) - asm_fprintf (file, "\tli %s,%d\n", reg_names[12], probe_iterations); - else - { - asm_fprintf (file, "\tlis %s,%d\n", reg_names[12], probe_iterations >> 16); - if (probe_iterations & 0xffff) - asm_fprintf (file, "\tori %s,%s,%d\n", reg_names[12], reg_names[12], - probe_iterations & 0xffff); - } - asm_fprintf (file, "\tmtctr %s\n", reg_names[12]); - asm_fprintf (file, "\tmr %s,%s\n", reg_names[12], reg_names[1]); - ASM_OUTPUT_INTERNAL_LABEL (file, "LCprobe", probe_labelno); - asm_fprintf (file, "\t{lu|lwzu} %s,-4096(%s)\n", reg_names[0], reg_names[12]); - ASM_GENERATE_INTERNAL_LABEL (buf, "LCprobe", probe_labelno++); - fputs ("\tbdnz ", file); - assemble_name (file, buf); - putc ('\n', file); - } - } +/* Write function prologue. */ +void +output_prolog (file, size) + FILE *file; + int size ATTRIBUTE_UNUSED; +{ + rs6000_stack_t *info = rs6000_stack_info (); - /* Update stack and set back pointer unless this is V.4, which was done previously */ - if (info->push_p && DEFAULT_ABI != ABI_V4 && DEFAULT_ABI != ABI_SOLARIS) - rs6000_allocate_stack_space (file, info->total_size, FALSE); + if (TARGET_DEBUG_STACK) + debug_stack_info (info); - /* Set frame pointer, if needed. */ - if (frame_pointer_needed) - asm_fprintf (file, "\tmr %s,%s\n", reg_names[31], reg_names[1]); + /* Write .extern for any function we will call to save and restore fp + values. */ + if (info->first_fp_reg_save < 64 && !FP_SAVE_INLINE (info->first_fp_reg_save)) + fprintf (file, "\t.extern %s%d%s\n\t.extern %s%d%s\n", + SAVE_FP_PREFIX, info->first_fp_reg_save - 32, SAVE_FP_SUFFIX, + RESTORE_FP_PREFIX, info->first_fp_reg_save - 32, RESTORE_FP_SUFFIX); - /* If TARGET_MINIMAL_TOC, and the constant pool is needed, then load the - TOC_TABLE address into register 30. */ - if (TARGET_TOC && TARGET_MINIMAL_TOC && get_pool_size () != 0) + /* Write .extern for truncation routines, if needed. */ + if (rs6000_trunc_used && ! trunc_defined) { -#ifdef USING_SVR4_H - if (! profile_flag) - rs6000_pic_func_labelno = rs6000_pic_labelno; -#endif - rs6000_output_load_toc_table (file, 30); + fprintf (file, "\t.extern .%s\n\t.extern .%s\n", + RS6000_ITRUNC, RS6000_UITRUNC); + trunc_defined = 1; } - if (DEFAULT_ABI == ABI_NT) + /* Write .extern for AIX common mode routines, if needed. */ + if (! TARGET_POWER && ! TARGET_POWERPC && ! common_mode_defined) { - assemble_name (file, XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0)); - fputs (".b:\n", file); + fputs ("\t.extern __mulh\n", file); + fputs ("\t.extern __mull\n", file); + fputs ("\t.extern __divss\n", file); + fputs ("\t.extern __divus\n", file); + fputs ("\t.extern __quoss\n", file); + fputs ("\t.extern __quous\n", file); + common_mode_defined = 1; } -} + if (! HAVE_prologue) + { + start_sequence (); + + /* A NOTE_INSN_DELETED is supposed to be at the start + and end of the "toplevel" insn chain. */ + emit_note (0, NOTE_INSN_DELETED); + rs6000_emit_prologue (); + emit_note (0, NOTE_INSN_DELETED); + + if (TARGET_DEBUG_STACK) + debug_rtx_list (get_insns(), 100); + final (get_insns(), file, FALSE, FALSE); + end_sequence (); + } +} + /* Emit function epilogue as insns. */ void @@ -4574,24 +4737,24 @@ rs6000_emit_epilogue(sibcall) int sibcall; { rs6000_stack_t *info; - int saving_FPRs_inline; + int restoring_FPRs_inline; int using_load_multiple; int using_mfcr_multiple; int use_backchain_to_restore_sp; int sp_offset = 0; rtx sp_reg_rtx = gen_rtx_REG (Pmode, 1); rtx frame_reg_rtx = sp_reg_rtx; - enum machine_mode reg_mode = (TARGET_32BIT) ? SImode : DImode; - int reg_size = (TARGET_32BIT) ? 4 : 8; + enum machine_mode reg_mode = TARGET_POWERPC64 ? DImode : SImode; + int reg_size = TARGET_POWERPC64 ? 8 : 4; rtx insn; int i; info = rs6000_stack_info (); - using_load_multiple = (TARGET_MULTIPLE && !TARGET_64BIT + using_load_multiple = (TARGET_MULTIPLE && ! TARGET_POWERPC64 && info->first_gp_reg_save < 31); - saving_FPRs_inline = (sibcall - || info->first_fp_reg_save == 64 - || FP_SAVE_INLINE (info->first_fp_reg_save)); + restoring_FPRs_inline = (sibcall + || info->first_fp_reg_save == 64 + || FP_SAVE_INLINE (info->first_fp_reg_save)); use_backchain_to_restore_sp = (frame_pointer_needed || current_function_calls_alloca || info->total_size > 32767); @@ -4611,7 +4774,7 @@ rs6000_emit_epilogue(sibcall) frame_reg_rtx = gen_rtx_REG (Pmode, 11); insn = emit_move_insn (frame_reg_rtx, - gen_rtx_MEM (reg_mode, sp_reg_rtx)); + gen_rtx_MEM (Pmode, sp_reg_rtx)); RTX_FRAME_RELATED_P (insn) = 1; } @@ -4646,8 +4809,8 @@ rs6000_emit_epilogue(sibcall) { rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, GEN_INT (info->cr_save_offset + sp_offset)); - insn = emit_move_insn (gen_rtx_REG (reg_mode, 12), - gen_rtx_MEM (reg_mode, addr)); + insn = emit_move_insn (gen_rtx_REG (SImode, 12), + gen_rtx_MEM (SImode, addr)); RTX_FRAME_RELATED_P (insn) = 1; } @@ -4696,19 +4859,21 @@ rs6000_emit_epilogue(sibcall) } /* Restore fpr's if we need to do it without calling a function. */ - if (saving_FPRs_inline) + if (restoring_FPRs_inline) for (i = 0; i < 64 - info->first_fp_reg_save; i++) - { - rtx addr; - addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, - GEN_INT (info->fp_save_offset - + sp_offset - + 8*i)); - insn = emit_move_insn (gen_rtx_REG (DFmode, - info->first_fp_reg_save + i), - gen_rtx_MEM (DFmode, addr)); - RTX_FRAME_RELATED_P (insn) = 1; - } + if ((regs_ever_live[info->first_fp_reg_save+i] + && ! call_used_regs[info->first_fp_reg_save+i])) + { + rtx addr; + addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, + GEN_INT (info->fp_save_offset + + sp_offset + + 8*i)); + insn = emit_move_insn (gen_rtx_REG (DFmode, + info->first_fp_reg_save + i), + gen_rtx_MEM (DFmode, addr)); + RTX_FRAME_RELATED_P (insn) = 1; + } /* If we saved cr, restore it here. Just those that were used. */ if (info->cr_save_p) @@ -4782,7 +4947,7 @@ rs6000_emit_epilogue(sibcall) if (!sibcall) { rtvec p; - if (! saving_FPRs_inline) + if (! restoring_FPRs_inline) p = rtvec_alloc (3 + 64 - info->first_fp_reg_save); else p = rtvec_alloc (2); @@ -4794,7 +4959,7 @@ rs6000_emit_epilogue(sibcall) /* If we have to restore more than two FP registers, branch to the restore function. It will return to our caller. */ - if (! saving_FPRs_inline) + if (! restoring_FPRs_inline) { int i; char rname[30]; @@ -4852,7 +5017,7 @@ output_epilog (file, size) rs6000_emit_epilogue (FALSE); emit_note (0, NOTE_INSN_DELETED); - if (TARGET_DEBUG_ARG) + if (TARGET_DEBUG_STACK) debug_rtx_list (get_insns(), 100); final (get_insns(), file, FALSE, FALSE); end_sequence (); @@ -5237,66 +5402,14 @@ output_mi_thunk (file, thunk_fndecl, delta, function) asm_fprintf (file, "\tbctr\n"); break; + case ABI_AIX_NODESC: + case ABI_SOLARIS: case ABI_V4: fprintf (file, "\tb %s", prefix); assemble_name (file, fname); if (flag_pic) fputs ("@plt", file); putc ('\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) - { - fprintf (file, "\tmflr %s\n", r0); - fputs ("\tbl _GLOBAL_OFFSET_TABLE_@local-4\n", file); - asm_fprintf (file, "\tmflr %s\n", r12); - asm_fprintf (file, "\tmtlr %s\n", r0); - asm_fprintf (file, "\t{l|lwz} %s,", r0); - assemble_name (file, fname); - asm_fprintf (file, "@got(%s)\n", r12); - asm_fprintf (file, "\tmtctr %s\n", r0); - asm_fprintf (file, "\tbctr\n"); - } -#if TARGET_ELF - else if (flag_pic > 1 || TARGET_RELOCATABLE) - { - ASM_GENERATE_INTERNAL_LABEL (buf, "Lthunk", labelno); - labelno++; - fprintf (file, "\tmflr %s\n", r0); - asm_fprintf (file, "\t{st|stw} %s,4(%s)\n", r0, sp); - rs6000_pic_func_labelno = rs6000_pic_labelno; - rs6000_output_load_toc_table (file, 12); - asm_fprintf (file, "\t{l|lwz} %s,", r0); - assemble_name (file, buf); - asm_fprintf (file, "(%s)\n", r12); - asm_fprintf (file, "\t{l|lwz} %s,4(%s)\n", r12, sp); - asm_fprintf (file, "\tmtlr %s\n", r12); - asm_fprintf (file, "\tmtctr %s\n", r0); - asm_fprintf (file, "\tbctr\n"); - asm_fprintf (file, "%s\n", MINIMAL_TOC_SECTION_ASM_OP); - assemble_name (file, buf); - fputs (" = .-.LCTOC1\n", file); - fputs ("\t.long ", file); - assemble_name (file, fname); - fputs ("\n\t.previous\n", file); - } -#endif /* TARGET_ELF */ - - else - { - asm_fprintf (file, "\t{liu|lis} %s,", r12); - assemble_name (file, fname); - asm_fprintf (file, "@ha\n"); - asm_fprintf (file, "\t{cal|la} %s,", r12); - assemble_name (file, fname); - asm_fprintf (file, "@l(%s)\n", r12); - asm_fprintf (file, "\tmtctr %s\n", r12); - asm_fprintf (file, "\tbctr\n"); - } - - break; } } } @@ -5313,6 +5426,9 @@ output_mi_thunk (file, thunk_fndecl, delta, function) SVR4/EABI -fpic SVR4 pic object file SVR4/EABI -fPIC SVR4 PIC translation unit SVR4/EABI -mrelocatable EABI TOC function + SVR4/EABI -maix AIX TOC object file + SVR4/EABI -maix -mminimal-toc + AIX minimal TOC translation unit Name Reg. Set by entries contains: made by addrs? fp? sum? @@ -5842,24 +5958,20 @@ output_function_profiler (file, labelno) assemble_name (file, buf); asm_fprintf (file, "@got(%s)\n", reg_names[12]); } -#if TARGET_ELF - else if (flag_pic > 1 || TARGET_RELOCATABLE) + else if (flag_pic > 1) { asm_fprintf (file, "\t{st|stw} %s,4(%s)\n", reg_names[0], reg_names[1]); - rs6000_pic_func_labelno = rs6000_pic_labelno; - rs6000_output_load_toc_table (file, 12); - asm_fprintf (file, "\t{l|lwz} %s,", reg_names[12]); - assemble_name (file, buf); - asm_fprintf (file, "X(%s)\n", reg_names[12]); - asm_fprintf (file, "%s\n", MINIMAL_TOC_SECTION_ASM_OP); + /* Now, we need to get the address of the label. */ + fputs ("\tbl 1f\n\t.word ", file); assemble_name (file, buf); - fputs ("X = .-.LCTOC1\n", file); - fputs ("\t.long ", file); - assemble_name (file, buf); - fputs ("\n\t.previous\n", file); + fputs ("-.\n1:", file); + asm_fprintf (file, "\tmflr %s\n", reg_names[11]); + asm_fprintf (file, "\t{l|lwz} %s,0(%s)\n", + reg_names[0], reg_names[11]); + asm_fprintf (file, "\t{cax|add} %s,%s,%s\n", + reg_names[0], reg_names[0], reg_names[11]); } -#endif else { asm_fprintf (file, "\t{liu|lis} %s,", reg_names[12]); diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h index 338ab3ea173..6c94ea8053b 100644 --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -3064,7 +3064,6 @@ extern int rs6000_adjust_priority (); extern void rs6000_trampoline_template (); extern int rs6000_trampoline_size (); extern void rs6000_initialize_trampoline (); -extern void rs6000_output_load_toc_table (); extern int rs6000_comp_type_attributes (); extern int rs6000_valid_decl_attribute_p (); extern int rs6000_valid_type_attribute_p (); @@ -3075,6 +3074,9 @@ extern int function_arg_padding (); extern void toc_section (); extern void private_data_section (); extern void rs6000_fatal_bad_address (); +extern void rs6000_emit_prologue (); +extern int stmw_operation (); +extern void rs6000_emit_load_toc_table (); extern void rs6000_emit_epilogue (); extern int mtcrf_operation (); extern int lmw_operation (); diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index 303835292df..77725591ff5 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -26,9 +26,11 @@ ;; 0 frsp for POWER machines ;; 0/v blockage ;; 1/v nonlocal_goto_receiver for MINIMAL_TOC +;; 6 address of a word pointing to the TOC ;; 7 clobber SP for NT -;; 7 address of the GOT under SVR4 -fpic +;; 7 address of the TOC (more-or-less) ;; 8 movsi_got +;; 19 movesi_from_cr ;; 20 movesi_to_cr ;; Define an insn type attribute. This is used in function unit delay @@ -1002,6 +1004,9 @@ if (low & 0x8000) high += 0x10000, low |= ((HOST_WIDE_INT) -1) << 16; + /* The ordering here is important for the prolog expander. + When space is allocated from the stack, adding 'low' first may + produce a temporary deallocation (which would be bad). */ emit_insn (gen_addsi3 (tmp, operands[1], GEN_INT (high))); emit_insn (gen_addsi3 (operands[0], tmp, GEN_INT (low))); DONE; @@ -5776,21 +5781,23 @@ ;; Now define ways of moving data around. ;; Elf specific ways of loading addresses for non-PIC code. -;; The output of this could be r0, but we limit it to base -;; registers, since almost all uses of this will need it -;; in a base register shortly. +;; The output of this could be r0, but we make a very strong +;; preference for a base register because it will usually +;; be needed there. (define_insn "elf_high" - [(set (match_operand:SI 0 "gpc_reg_operand" "=b") + [(set (match_operand:SI 0 "gpc_reg_operand" "=b*r") (high:SI (match_operand 1 "" "")))] "TARGET_ELF && ! TARGET_64BIT" "{liu|lis} %0,%1@ha") (define_insn "elf_low" - [(set (match_operand:SI 0 "gpc_reg_operand" "=r") - (lo_sum:SI (match_operand:SI 1 "gpc_reg_operand" "b") + [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (lo_sum:SI (match_operand:SI 1 "gpc_reg_operand" "b,!*r") (match_operand 2 "" "")))] "TARGET_ELF && ! TARGET_64BIT" - "{cal|la} %0,%2@l(%1)") + "@ + {cal|la} %0,%2@l(%1) + {ai|addic} %0,%1,%l2") ;; Set up a register with a value from the GOT table @@ -7895,16 +7902,81 @@ ;; TOC register handling. -;; Code to initialize the PIC register for SVR4 -fpic. +;; Code to initialize the TOC register... -(define_insn "init_v4_pic" +(define_insn "load_toc_aix_si" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(const_int 0)] 7))] + "! TARGET_ELF && TARGET_32BIT" + "* +{ + char buf[30]; + ASM_GENERATE_INTERNAL_LABEL (buf, \"LCTOC\", 0); + operands[1] = gen_rtx_SYMBOL_REF (Pmode, ggc_alloc_string (buf, -1)); + operands[2] = gen_rtx_REG (Pmode, 2); + return \"{l|lwz} %0,%1(%2)\"; +}" + [(set_attr "type" "load")]) + +(define_insn "load_toc_aix_di" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec:DI [(const_int 0)] 7))] + "! TARGET_ELF && TARGET_64BIT" + "* +{ + char buf[30]; + ASM_GENERATE_INTERNAL_LABEL (buf, \"LCTOC\", 0); + operands[1] = gen_rtx_SYMBOL_REF (Pmode, ggc_alloc_string (buf, -1)); + operands[2] = gen_rtx_REG (Pmode, 2); + return \"ld %0,%1(%2)\"; +}" + [(set_attr "type" "load")]) + +(define_insn "load_toc_v4_pic_si" [(set (match_operand:SI 0 "register_operand" "=l") (unspec:SI [(const_int 0)] 7))] - "DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS" + "(DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) && flag_pic == 1 + && TARGET_32BIT" "bl _GLOBAL_OFFSET_TABLE_@local-4" [(set_attr "type" "branch") (set_attr "length" "4")]) +(define_insn "load_toc_v4_pic_di" + [(set (match_operand:DI 0 "register_operand" "=l") + (unspec:DI [(const_int 0)] 7))] + "(DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) && flag_pic == 1 + && TARGET_64BIT" + "bl _GLOBAL_OFFSET_TABLE_@local-4" + [(set_attr "type" "branch") + (set_attr "length" "4")]) + +(define_insn "load_toc_v4_PIC_1" + [(set (match_operand:SI 0 "register_operand" "=l") + (match_operand:SI 1 "immediate_operand" "s")) + (unspec [(match_dup 1)] 7)] + "TARGET_ELF && flag_pic == 2" + "bl %1\\n%1:" + [(set_attr "type" "branch") + (set_attr "length" "4")]) + +(define_insn "load_toc_v4_PIC_1b" + [(set (match_operand:SI 0 "register_operand" "=l") + (match_operand:SI 1 "immediate_operand" "s")) + (unspec [(match_dup 1) (match_operand 2 "immediate_operand" "s")] 6)] + "TARGET_ELF && flag_pic == 2" + "bl %1\\n\\t.long %2-%1\\n%1:" + [(set_attr "type" "branch") + (set_attr "length" "8")]) + +(define_insn "load_toc_v4_PIC_2" + [(set (match_operand:SI 0 "register_operand" "=r") + (mem:SI (plus:SI (match_operand:SI 1 "register_operand" "r") + (minus:SI (match_operand:SI 2 "immediate_operand" "s") + (match_operand:SI 3 "immediate_operand" "s")))))] + "TARGET_ELF && flag_pic == 2" + "{l|lwz} %0,%2-%3(%1)" + [(set_attr "type" "load")]) + ;; If the TOC is shared over a translation unit, as in SVR4 -fpic ;; we need to restore the TOC pointer only when jumping over units ;; of translation. @@ -7914,24 +7986,21 @@ "(DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) && flag_pic == 1" " { - rtx temp = gen_reg_rtx (Pmode); - emit_insn (gen_init_v4_pic (temp)); - emit_move_insn (gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM), temp); + rs6000_emit_load_toc_table (FALSE); DONE; }") ;; If the TOC is procedure-specific (as in AIX -mminimal-toc and SVR4 -fPIC), ;; we must restore it with every nonlocal goto. -(define_insn "nonlocal_goto_receiver" - [(unspec_volatile [(const_int 0)] 1)] +(define_expand "nonlocal_goto_receiver" + [(use (const_int 0))] "TARGET_TOC && TARGET_MINIMAL_TOC" - "* + " { - rs6000_output_load_toc_table (asm_out_file, 30); - return \"\"; -}" - [(set_attr "type" "load")]) + rs6000_emit_load_toc_table (FALSE); + DONE; +}") ;; A function pointer under AIX is a pointer to a data area whose first word ;; contains the actual address of the function, whose second word contains a @@ -11071,6 +11140,48 @@ ;; Insns related to generating the function prologue and epilogue. +(define_expand "prologue" + [(use (const_int 0))] + "TARGET_SCHED_PROLOG" + " +{ + rs6000_emit_prologue (); + DONE; +}") + +(define_insn "movesi_from_cr" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (unspec:SI [(reg:CC 68) (reg:CC 69) (reg:CC 70) (reg:CC 71) + (reg:CC 72) (reg:CC 73) (reg:CC 74) (reg:CC 75)] 19))] + "" + "mfcr %0") + +(define_insn "*stmw" + [(match_parallel 0 "stmw_operation" + [(set (match_operand:SI 1 "memory_operand" "=m") + (match_operand:SI 2 "gpc_reg_operand" "r"))])] + "TARGET_MULTIPLE" + "stmw %2,%1") + +(define_insn "*save_fpregs_si" + [(match_parallel 0 "any_operand" + [(clobber (match_operand:SI 1 "register_operand" "=l")) + (use (match_operand:SI 2 "call_operand" "s")) + (set (match_operand:DF 3 "memory_operand" "=m") + (match_operand:DF 4 "gpc_reg_operand" "f"))])] + "TARGET_32BIT" + "bl %z2") + +(define_insn "*save_fpregs_di" + [(match_parallel 0 "any_operand" + [(clobber (match_operand:DI 1 "register_operand" "=l")) + (use (match_operand:DI 2 "call_operand" "s")) + (set (match_operand:DF 3 "memory_operand" "=m") + (match_operand:DF 4 "gpc_reg_operand" "f"))])] + "TARGET_64BIT" + "bl %z2") + + (define_expand "epilogue" [(use (const_int 0))] "TARGET_SCHED_PROLOG" |