diff options
Diffstat (limited to 'gcc/config/rs6000/rs6000.c')
-rw-r--r-- | gcc/config/rs6000/rs6000.c | 161 |
1 files changed, 113 insertions, 48 deletions
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 5c0ef2f6f30..3c17f2156f2 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -1,6 +1,6 @@ /* Subroutines used for code generation on IBM RS/6000. Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001, 2002 Free Software Foundation, Inc. + 2000, 2001, 2002, 2003 Free Software Foundation, Inc. Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu) This file is part of GNU CC. @@ -284,7 +284,9 @@ char rs6000_reg_names[][8] = "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", - "vrsave" + "vrsave", "vscr", + /* SPE registers. */ + "spe_acc", "spefscr" }; #ifdef TARGET_REGNAMES @@ -301,12 +303,14 @@ static const char alt_reg_names[][8] = "mq", "lr", "ctr", "ap", "%cr0", "%cr1", "%cr2", "%cr3", "%cr4", "%cr5", "%cr6", "%cr7", "xer", - /* AltiVec registers. */ + /* AltiVec registers. */ "%v0", "%v1", "%v2", "%v3", "%v4", "%v5", "%v6", "%v7", - "%v8", "%v9", "%v10", "%v11", "%v12", "%v13", "%v14", "%v15", - "%v16", "%v17", "%v18", "%v19", "%v20", "%v21", "%v22", "%v23", - "%v24", "%v25", "%v26", "%v27", "%v28", "%v29", "%v30", "%v31", - "vrsave" + "%v8", "%v9", "%v10", "%v11", "%v12", "%v13", "%v14", "%v15", + "%v16", "%v17", "%v18", "%v19", "%v20", "%v21", "%v22", "%v23", + "%v24", "%v25", "%v26", "%v27", "%v28", "%v29", "%v30", "%v31", + "vrsave", "vscr", + /* SPE registers. */ + "spe_acc", "spefscr" }; #endif @@ -2636,16 +2640,15 @@ rs6000_emit_move (dest, source, mode) } } - /* Handle the case where reload calls us with an invalid address; - and the case of CONSTANT_P_RTX. */ - if (!ALTIVEC_VECTOR_MODE (mode) + /* Handle the case where reload calls us with an invalid address. */ + if (reload_in_progress && mode == Pmode && (! general_operand (operands[1], mode) - || ! nonimmediate_operand (operands[0], mode) - || GET_CODE (operands[1]) == CONSTANT_P_RTX)) - { - emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1])); - return; - } + || ! nonimmediate_operand (operands[0], mode))) + goto emit_set; + + /* Handle the case of CONSTANT_P_RTX. */ + if (GET_CODE (operands[1]) == CONSTANT_P_RTX) + goto emit_set; /* FIXME: In the long term, this switch statement should go away and be replaced by a sequence of tests based on things like @@ -2841,6 +2844,16 @@ rs6000_emit_move (dest, source, mode) operands[1] = replace_equiv_address (operands[1], copy_addr_to_reg (XEXP (operands[1], 0))); + if (TARGET_POWER) + { + emit_insn (gen_rtx_PARALLEL (VOIDmode, + gen_rtvec (2, + gen_rtx_SET (VOIDmode, + operands[0], operands[1]), + gen_rtx_CLOBBER (VOIDmode, + gen_rtx_SCRATCH (SImode))))); + return; + } break; default: @@ -2850,13 +2863,11 @@ rs6000_emit_move (dest, source, mode) /* Above, we may have called force_const_mem which may have returned an invalid address. If we can, fix this up; otherwise, reload will have to deal with it. */ - if (GET_CODE (operands[1]) == MEM - && ! memory_address_p (mode, XEXP (operands[1], 0)) - && ! reload_in_progress) - operands[1] = adjust_address (operands[1], mode, 0); + if (GET_CODE (operands[1]) == MEM && ! reload_in_progress) + operands[1] = validize_mem (operands[1]); + emit_set: emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1])); - return; } /* Initialize a variable CUM of type CUMULATIVE_ARGS @@ -2867,11 +2878,12 @@ rs6000_emit_move (dest, source, mode) so we never return a PARALLEL. */ void -init_cumulative_args (cum, fntype, libname, incoming) +init_cumulative_args (cum, fntype, libname, incoming, libcall) CUMULATIVE_ARGS *cum; tree fntype; rtx libname ATTRIBUTE_UNUSED; int incoming; + int libcall; { static CUMULATIVE_ARGS zero_cumulative; @@ -2880,7 +2892,8 @@ init_cumulative_args (cum, fntype, libname, incoming) cum->fregno = FP_ARG_MIN_REG; cum->vregno = ALTIVEC_ARG_MIN_REG; cum->prototype = (fntype && TYPE_ARG_TYPES (fntype)); - cum->call_cookie = CALL_NORMAL; + cum->call_cookie = ((DEFAULT_ABI == ABI_V4 && libcall) + ? CALL_LIBCALL : CALL_NORMAL); cum->sysv_gregno = GP_ARG_MIN_REG; if (incoming) @@ -3088,7 +3101,7 @@ function_arg_advance (cum, mode, type, named) If this is floating-point and no prototype is specified, we use both an FP and integer register (or possibly FP reg and stack). Library - functions (when TYPE is zero) always have the proper types for args, + functions (when CALL_LIBCALL is set) always have the proper types for args, so we can pass the FP value just in one register. emit_library_function doesn't support PARALLEL anyway. */ @@ -3109,7 +3122,8 @@ function_arg (cum, mode, type, named) { if (abi == ABI_V4 && cum->nargs_prototype < 0 - && type && (cum->prototype || TARGET_NO_PROTOTYPE)) + && (cum->call_cookie & CALL_LIBCALL) == 0 + && (cum->prototype || TARGET_NO_PROTOTYPE)) { /* For the SPE, we need to crxor CR6 always. */ if (TARGET_SPE_ABI) @@ -3275,7 +3289,10 @@ function_arg_partial_nregs (cum, mode, type, named) the argument itself. The pointer is passed in whatever way is appropriate for passing a pointer to that type. - Under V.4, structures and unions are passed by reference. */ + Under V.4, structures and unions are passed by reference. + + As an extension to all ABIs, variable sized types are passed by + reference. */ int function_arg_pass_by_reference (cum, mode, type, named) @@ -3293,8 +3310,7 @@ function_arg_pass_by_reference (cum, mode, type, named) return 1; } - - return 0; + return type && int_size_in_bytes (type) <= 0; } /* Perform any needed actions needed for a function that is receiving a @@ -3533,7 +3549,28 @@ rs6000_va_arg (valist, type) rtx lab_false, lab_over, addr_rtx, r; if (DEFAULT_ABI != ABI_V4) - return std_expand_builtin_va_arg (valist, type); + { + /* Variable sized types are passed by reference. */ + if (int_size_in_bytes (type) <= 0) + { + u = build_pointer_type (type); + + /* Args grow upward. */ + t = build (POSTINCREMENT_EXPR, TREE_TYPE (valist), valist, + build_int_2 (POINTER_SIZE / BITS_PER_UNIT, 0)); + TREE_SIDE_EFFECTS (t) = 1; + + t = build1 (NOP_EXPR, build_pointer_type (u), t); + TREE_SIDE_EFFECTS (t) = 1; + + t = build1 (INDIRECT_REF, u, t); + TREE_SIDE_EFFECTS (t) = 1; + + return expand_expr (t, NULL_RTX, VOIDmode, EXPAND_NORMAL); + } + else + return std_expand_builtin_va_arg (valist, type); + } f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node)); f_fpr = TREE_CHAIN (f_gpr); @@ -8837,7 +8874,7 @@ first_reg_to_save () if (regs_ever_live[first_reg] && (! call_used_regs[first_reg] || (first_reg == RS6000_PIC_OFFSET_TABLE_REGNUM - && ((DEFAULT_ABI == ABI_V4 && flag_pic == 1) + && ((DEFAULT_ABI == ABI_V4 && flag_pic != 0) || (DEFAULT_ABI == ABI_DARWIN && flag_pic))))) break; @@ -9265,7 +9302,6 @@ rs6000_stack_info () + ehrd_size + info_ptr->cr_size + info_ptr->lr_size - + info_ptr->vrsave_size + info_ptr->toc_size, (TARGET_ALTIVEC_ABI || ABI_DARWIN) ? 16 : 8); @@ -9609,7 +9645,7 @@ void rs6000_emit_load_toc_table (fromprolog) int fromprolog; { - rtx dest; + rtx dest, insn; dest = gen_rtx_REG (Pmode, RS6000_PIC_OFFSET_TABLE_REGNUM); if (TARGET_ELF && DEFAULT_ABI == ABI_V4 && flag_pic == 1) @@ -9617,8 +9653,12 @@ rs6000_emit_load_toc_table (fromprolog) rtx temp = (fromprolog ? gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM) : gen_reg_rtx (Pmode)); - rs6000_maybe_dead (emit_insn (gen_load_toc_v4_pic_si (temp))); - rs6000_maybe_dead (emit_move_insn (dest, temp)); + insn = emit_insn (gen_load_toc_v4_pic_si (temp)); + if (fromprolog) + rs6000_maybe_dead (insn); + insn = emit_move_insn (dest, temp); + if (fromprolog) + rs6000_maybe_dead (insn); } else if (TARGET_ELF && DEFAULT_ABI != ABI_AIX && flag_pic == 2) { @@ -9665,14 +9705,13 @@ rs6000_emit_load_toc_table (fromprolog) ASM_GENERATE_INTERNAL_LABEL (buf, "LCG", reload_toc_labelno++); symF = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf)); - rs6000_maybe_dead (emit_insn (gen_load_toc_v4_PIC_1b (tempLR, - symF, - tocsym))); - rs6000_maybe_dead (emit_move_insn (dest, tempLR)); - rs6000_maybe_dead (emit_move_insn (temp0, - gen_rtx_MEM (Pmode, dest))); + 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)); } - rs6000_maybe_dead (emit_insn (gen_addsi3 (dest, temp0, dest))); + insn = emit_insn (gen_addsi3 (dest, temp0, dest)); + if (fromprolog) + rs6000_maybe_dead (insn); } else if (TARGET_ELF && !TARGET_AIX && flag_pic == 0 && TARGET_MINIMAL_TOC) { @@ -9682,15 +9721,21 @@ rs6000_emit_load_toc_table (fromprolog) ASM_GENERATE_INTERNAL_LABEL (buf, "LCTOC", 1); realsym = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf)); - rs6000_maybe_dead (emit_insn (gen_elf_high (dest, realsym))); - rs6000_maybe_dead (emit_insn (gen_elf_low (dest, dest, realsym))); + insn = emit_insn (gen_elf_high (dest, realsym)); + if (fromprolog) + rs6000_maybe_dead (insn); + insn = emit_insn (gen_elf_low (dest, dest, realsym)); + if (fromprolog) + rs6000_maybe_dead (insn); } else if (DEFAULT_ABI == ABI_AIX) { if (TARGET_32BIT) - rs6000_maybe_dead (emit_insn (gen_load_toc_aix_si (dest))); + insn = emit_insn (gen_load_toc_aix_si (dest)); else - rs6000_maybe_dead (emit_insn (gen_load_toc_aix_di (dest))); + insn = emit_insn (gen_load_toc_aix_di (dest)); + if (fromprolog) + rs6000_maybe_dead (insn); } else abort (); @@ -10423,7 +10468,7 @@ rs6000_emit_prologue () 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 == RS6000_PIC_OFFSET_TABLE_REGNUM - && ((DEFAULT_ABI == ABI_V4 && flag_pic == 1) + && ((DEFAULT_ABI == ABI_V4 && flag_pic != 0) || (DEFAULT_ABI == ABI_DARWIN && flag_pic)))) { rtx addr, reg, mem; @@ -10839,7 +10884,7 @@ rs6000_emit_epilogue (sibcall) 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 == RS6000_PIC_OFFSET_TABLE_REGNUM - && ((DEFAULT_ABI == ABI_V4 && flag_pic == 1) + && ((DEFAULT_ABI == ABI_V4 && flag_pic != 0) || (DEFAULT_ABI == ABI_DARWIN && flag_pic)))) { rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, @@ -11065,6 +11110,23 @@ rs6000_output_function_epilogue (file, size) } } +#if TARGET_OBJECT_FORMAT == OBJECT_MACHO + /* Mach-O doesn't support labels at the end of objects, so if + it looks like we might want one, insert a NOP. */ + { + rtx insn = get_last_insn (); + while (insn + && NOTE_P (insn) + && NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED_LABEL) + insn = PREV_INSN (insn); + if (insn + && (LABEL_P (insn) + || (NOTE_P (insn) + && NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED_LABEL))) + fputs ("\tnop\n", file); + } +#endif + /* Output a traceback table here. See /usr/include/sys/debug.h for info on its format. @@ -12617,11 +12679,15 @@ rs6000_elf_encode_section_info (decl, first) && DEFAULT_ABI == ABI_V4 && TREE_CODE (decl) == VAR_DECL) { + rtx sym_ref = XEXP (DECL_RTL (decl), 0); int size = int_size_in_bytes (TREE_TYPE (decl)); tree section_name = DECL_SECTION_NAME (decl); const char *name = (char *)0; int len = 0; + if ((*targetm.binds_local_p) (decl)) + SYMBOL_REF_FLAG (sym_ref) = 1; + if (section_name) { if (TREE_CODE (section_name) == STRING_CST) @@ -12648,7 +12714,6 @@ rs6000_elf_encode_section_info (decl, first) || (len == sizeof (".PPC.EMB.sbss0") - 1 && strcmp (name, ".PPC.EMB.sbss0") == 0)))) { - rtx sym_ref = XEXP (DECL_RTL (decl), 0); size_t len = strlen (XSTR (sym_ref, 0)); char *str = alloca (len + 2); |