This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [4.8, PATCH 10/26] Backport Power8 and LE support: ELFv2 ABI


On Wed, 19 Mar 2014, Bill Schmidt wrote:

> Hi,
> 
> This patch (diff-abi-elfv2) backports the fundamental changes for the
> ELFv2 ABI for powerpc64le.  Copying Richard and Jakub for the libgcc,
> libitm, and libstdc++ bits.

Ok - the libstdc++ bits were discussed separately AFAIR and they
were "optional", so please refer to libstdc++ maintainers here.

Thanks,
Richard.

> Thanks,
> Bill
> 
> 
> [gcc]
> 
> 2014-03-29  Bill Schmidt  <wschmidt@linux.vnet.ibm.com>
> 
> 	Backport from mainline r204842:
> 
> 	2013-11-15  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>
> 
> 	* doc/invoke.texi (-mabi=elfv1, -mabi=elfv2): Document.
> 
> 	Backport from mainline r204809:
> 
> 	2013-11-14  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>
> 
> 	* config/rs6000/sysv4le.h (LINUX64_DEFAULT_ABI_ELFv2): Define.
> 
> 	Backport from mainline r204808:
> 
> 	2013-11-14  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>
> 		    Alan Modra  <amodra@gmail.com>
> 
> 	* config/rs6000/rs6000.h (RS6000_SAVE_AREA): Handle ABI_ELFv2.
> 	(RS6000_SAVE_TOC): Remove.
> 	(RS6000_TOC_SAVE_SLOT): New macro.
> 	* config/rs6000/rs6000.c (rs6000_parm_offset): New function.
> 	(rs6000_parm_start): Use it.
> 	(rs6000_function_arg_advance_1): Likewise.
> 	(rs6000_emit_prologue): Use RS6000_TOC_SAVE_SLOT.
> 	(rs6000_emit_epilogue): Likewise.
> 	(rs6000_call_aix): Likewise.
> 	(rs6000_output_function_prologue): Do not save/restore r11
> 	around calling _mcount for ABI_ELFv2.
> 
> 	2013-11-14  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>
> 		    Alan Modra  <amodra@gmail.com>
> 
> 	* config/rs6000/rs6000-protos.h (rs6000_reg_parm_stack_space):
> 	Add prototype.
> 	* config/rs6000/rs6000.h (RS6000_REG_SAVE): Remove.
> 	(REG_PARM_STACK_SPACE): Call rs6000_reg_parm_stack_space.
> 	* config/rs6000/rs6000.c (rs6000_parm_needs_stack): New function.
> 	(rs6000_function_parms_need_stack): Likewise.
> 	(rs6000_reg_parm_stack_space): Likewise.
> 	(rs6000_function_arg): Do not replace BLKmode by Pmode when
> 	returning a register argument.
> 
> 	2013-11-14  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>
> 		    Michael Gschwind  <mkg@us.ibm.com>
> 
> 	* config/rs6000/rs6000.h (FP_ARG_MAX_RETURN): New macro.
> 	(ALTIVEC_ARG_MAX_RETURN): Likewise.
> 	(FUNCTION_VALUE_REGNO_P): Use them.
> 	* config/rs6000/rs6000.c (TARGET_RETURN_IN_MSB): Define.
> 	(rs6000_return_in_msb): New function.
> 	(rs6000_return_in_memory): Handle ELFv2 homogeneous aggregates.
> 	Handle aggregates of up to 16 bytes for ELFv2.
> 	(rs6000_function_value): Handle ELFv2 homogeneous aggregates.
> 
> 	2013-11-14  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>
> 		    Michael Gschwind  <mkg@us.ibm.com>
> 
> 	* config/rs6000/rs6000.h (AGGR_ARG_NUM_REG): Define.
> 	* config/rs6000/rs6000.c (rs6000_aggregate_candidate): New function.
> 	(rs6000_discover_homogeneous_aggregate): Likewise.
> 	(rs6000_function_arg_boundary): Handle homogeneous aggregates.
> 	(rs6000_function_arg_advance_1): Likewise.
> 	(rs6000_function_arg): Likewise.
> 	(rs6000_arg_partial_bytes): Likewise.
> 	(rs6000_psave_function_arg): Handle BLKmode arguments.
> 
> 	2013-11-14  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>
> 		    Michael Gschwind  <mkg@us.ibm.com>
> 
> 	* config/rs6000/rs6000.h (AGGR_ARG_NUM_REG): Define.
> 	* config/rs6000/rs6000.c (rs6000_aggregate_candidate): New function.
> 	(rs6000_discover_homogeneous_aggregate): Likewise.
> 	(rs6000_function_arg_boundary): Handle homogeneous aggregates.
> 	(rs6000_function_arg_advance_1): Likewise.
> 	(rs6000_function_arg): Likewise.
> 	(rs6000_arg_partial_bytes): Likewise.
> 	(rs6000_psave_function_arg): Handle BLKmode arguments.
> 
> 	2013-11-14  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>
> 
> 	* config/rs6000/rs6000.c (machine_function): New member
> 	r2_setup_needed.
> 	(rs6000_emit_prologue): Set r2_setup_needed if necessary.
> 	(rs6000_output_mi_thunk): Set r2_setup_needed.
> 	(rs6000_output_function_prologue): Output global entry point
> 	prologue and local entry point marker if needed for ABI_ELFv2.
> 	Output -mprofile-kernel code here.
> 	(output_function_profiler): Do not output -mprofile-kernel
> 	code here; moved to rs6000_output_function_prologue.
> 	(rs6000_file_start): Output ".abiversion 2" for ABI_ELFv2.
> 
> 	(rs6000_emit_move): Do not handle dot symbols for ABI_ELFv2.
> 	(rs6000_output_function_entry): Likewise.
> 	(rs6000_assemble_integer): Likewise.
> 	(rs6000_elf_encode_section_info): Likewise.
> 	(rs6000_elf_declare_function_name): Do not create dot symbols
> 	or .opd section for ABI_ELFv2.
> 
> 	(rs6000_trampoline_size): Update for ABI_ELFv2 trampolines.
> 	(rs6000_trampoline_init): Likewise.
> 	(rs6000_elf_file_end): Call file_end_indicate_exec_stack
> 	for ABI_ELFv2.
> 
> 	(rs6000_call_aix): Handle ELFv2 indirect calls.  Do not check
> 	for function descriptors in ABI_ELFv2.
> 
> 	* config/rs6000/rs6000.md ("*call_indirect_aix<mode>"): Support
> 	on ABI_AIX only, not ABI_ELFv2.
> 	("*call_value_indirect_aix<mode>"): Likewise.
> 	("*call_indirect_elfv2<mode>"): New pattern.
> 	("*call_value_indirect_elfv2<mode>"): Likewise.
> 
> 	* config/rs6000/predicates.md ("symbol_ref_operand"): Do not
> 	check for function descriptors in ABI_ELFv2.
> 	("current_file_function_operand"): Likewise.
> 
> 	* config/rs6000/ppc-asm.h [__powerpc64__ && _CALL_ELF == 2]:
> 	(toc): Undefine.
> 	(FUNC_NAME): Define ELFv2 variant.
> 	(JUMP_TARGET): Likewise.
> 	(FUNC_START): Likewise.
> 	(HIDDEN_FUNC): Likewise.
> 	(FUNC_END): Likeiwse.
> 
> 	2013-11-14  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>
> 
> 	* config.gcc [powerpc*-*-* | rs6000-*-*]: Support --with-abi=elfv1
> 	and --with-abi=elfv2.
> 	* config/rs6000/option-defaults.h (OPTION_DEFAULT_SPECS): Add "abi".
> 	* config/rs6000/rs6000.opt (mabi=elfv1): New option.
> 	(mabi=elfv2): Likewise.
> 	* config/rs6000/rs6000-opts.h (enum rs6000_abi): Add ABI_ELFv2.
> 	* config/rs6000/linux64.h (DEFAULT_ABI): Do not hard-code to AIX_ABI
> 	if !RS6000_BI_ARCH.
> 	(ELFv2_ABI_CHECK): New macro.
> 	(SUBSUBTARGET_OVERRIDE_OPTIONS): Use it to decide whether to set
> 	rs6000_current_abi to ABI_AIX or ABI_ELFv2.
> 	(GLIBC_DYNAMIC_LINKER64): Support ELFv2 ld.so version.
> 	* config/rs6000/rs6000-c.c (rs6000_cpu_cpp_builtins): Predefine
> 	_CALL_ELF and __STRUCT_PARM_ALIGN__ if appropriate.
> 
> 	* config/rs6000/rs6000.c (rs6000_debug_reg_global): Handle ABI_ELFv2.
> 	(debug_stack_info): Likewise.
> 	(rs6000_file_start): Treat ABI_ELFv2 the same as ABI_AIX.
> 	(rs6000_legitimize_tls_address): Likewise.
> 	(rs6000_conditional_register_usage): Likewise.
> 	(rs6000_emit_move): Likewise.
> 	(init_cumulative_args): Likewise.
> 	(rs6000_function_arg_advance_1): Likewise.
> 	(rs6000_function_arg): Likewise.
> 	(rs6000_arg_partial_bytes): Likewise.
> 	(rs6000_output_function_entry): Likewise.
> 	(rs6000_assemble_integer): Likewise.
> 	(rs6000_savres_strategy): Likewise.
> 	(rs6000_stack_info): Likewise.
> 	(rs6000_function_ok_for_sibcall): Likewise.
> 	(rs6000_emit_load_toc_table): Likewise.
> 	(rs6000_savres_routine_name): Likewise.
> 	(ptr_regno_for_savres): Likewise.
> 	(rs6000_emit_prologue): Likewise.
> 	(rs6000_emit_epilogue): Likewise.
> 	(rs6000_output_function_epilogue): Likewise.
> 	(output_profile_hook): Likewise.
> 	(output_function_profiler): Likewise.
> 	(rs6000_trampoline_size): Likewise.
> 	(rs6000_trampoline_init): Likewise.
> 	(rs6000_elf_output_toc_section_asm_op): Likewise.
> 	(rs6000_elf_encode_section_info): Likewise.
> 	(rs6000_elf_reloc_rw_mask): Likewise.
> 	(rs6000_elf_declare_function_name): Likewise.
> 	(rs6000_function_arg_boundary): Treat ABI_ELFv2 the same as ABI_AIX,
> 	except that rs6000_compat_align_parm is always assumed false.
> 	(rs6000_gimplify_va_arg): Likewise.
> 	(rs6000_call_aix): Update comment.
> 	(rs6000_sibcall_aix): Likewise.
> 	* config/rs6000/rs6000.md ("tls_gd_aix<TLSmode:tls_abi_suffix>"):
> 	Treat ABI_ELFv2 the same as ABI_AIX.
> 	("*tls_gd_call_aix<TLSmode:tls_abi_suffix>"): Likewise.
> 	("tls_ld_aix<TLSmode:tls_abi_suffix>"): Likewise.
> 	("*tls_ld_call_aix<TLSmode:tls_abi_suffix>"): Likewise.
> 	("load_toc_aix_si"): Likewise.
> 	("load_toc_aix_di"): Likewise.
> 	("call"): Likewise.
> 	("call_value"): Likewise.
> 	("*call_local_aix<mode>"): Likewise.
> 	("*call_value_local_aix<mode>"): Likewise.
> 	("*call_nonlocal_aix<mode>"): Likewise.
> 	("*call_value_nonlocal_aix<mode>"): Likewise.
> 	("*call_indirect_aix<mode>"): Likewise.
> 	("*call_value_indirect_aix<mode>"): Likewise.
> 	("sibcall"): Likewise.
> 	("sibcall_value"): Likewise.
> 	("*sibcall_aix<mode>"): Likewise.
> 	("*sibcall_value_aix<mode>"): Likewise.
> 	* config/rs6000/predicates.md ("symbol_ref_operand"): Likewise.
> 	("current_file_function_operand"): Likewise.
> 
> 	Backport from mainline r204807:
> 
> 	2013-11-14  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>
> 
> 	* config/rs6000/rs6000.c (rs6000_arg_partial_bytes): Simplify logic
> 	by making use of the fact that for vector / floating point arguments
> 	passed both in VRs/FPRs and in the fixed parameter area, the partial
> 	bytes mechanism is in fact not used.
> 
> 	Backport from mainline r204806:
> 
> 	2013-11-14  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>
> 
> 	* config/rs6000/rs6000.c (rs6000_psave_function_arg): New function.
> 	(rs6000_finish_function_arg): Likewise.
> 	(rs6000_function_arg): Use rs6000_psave_function_arg and
> 	rs6000_finish_function_arg to handle both vector and floating
> 	point arguments that are also passed in GPRs / the stack.
> 
> 	Backport from mainline r204805:
> 
> 	2013-11-14  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>
> 
> 	* config/rs6000/rs6000.c (USE_FP_FOR_ARG_P): Remove TYPE argument.
> 	(USE_ALTIVEC_FOR_ARG_P): Likewise.
> 	(rs6000_darwin64_record_arg_advance_recurse): Update uses.
> 	(rs6000_function_arg_advance_1):Likewise.
> 	(rs6000_darwin64_record_arg_recurse): Likewise.
> 	(rs6000_function_arg): Likewise.
> 	(rs6000_arg_partial_bytes): Likewise.
> 
> 	Backport from mainline r204804:
> 
> 	2013-11-14  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>
> 
> 	* config/rs6000/rs6000.c (rs6000_option_override_internal): Replace
> 	"DEFAULT_ABI != ABI_AIX" test by testing for ABI_V4 or ABI_DARWIN.
> 	(rs6000_savres_strategy): Likewise.
> 	(rs6000_return_addr): Likewise.
> 	(rs6000_emit_load_toc_table): Replace "DEFAULT_ABI != ABI_AIX" by
> 	testing for ABI_V4 (since ABI_DARWIN is impossible here).
> 	(rs6000_emit_prologue): Likewise.
> 	(legitimate_lo_sum_address_p): Simplify DEFAULT_ABI test.
> 	(rs6000_elf_declare_function_name): Remove duplicated test.
> 	* config/rs6000/rs6000.md ("load_toc_v4_PIC_1"): Explicitly test
> 	for ABI_V4 (instead of "DEFAULT_ABI != ABI_AIX" test).
> 	("load_toc_v4_PIC_1_normal"): Likewise.
> 	("load_toc_v4_PIC_1_476"): Likewise.
> 	("load_toc_v4_PIC_1b"): Likewise.
> 	("load_toc_v4_PIC_1b_normal"): Likewise.
> 	("load_toc_v4_PIC_1b_476"): Likewise.
> 	("load_toc_v4_PIC_2"): Likewise.
> 	("load_toc_v4_PIC_3b"): Likewise.
> 	("load_toc_v4_PIC_3c"): Likewise.
> 	* config/rs6000/rs6000.h (RS6000_REG_SAVE): Simplify DEFAULT_ABI test.
> 	(RS6000_SAVE_AREA): Likewise.
> 	(FP_ARG_MAX_REG): Likewise.
> 	(RETURN_ADDRESS_OFFSET): Likewise.
> 	* config/rs6000/sysv.h (TARGET_TOC): Test for ABI_V4 instead
> 	of ABI_AIX.
> 	(SUBTARGET_OVERRIDE_OPTIONS): Likewise.
> 	(MINIMAL_TOC_SECTION_ASM_OP): Likewise.
> 
> 	Backport from mainline r204803:
> 
> 	2013-11-14  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>
> 
> 	* config/rs6000/rs6000.c (rs6000_call_indirect_aix): Rename to ...
> 	(rs6000_call_aix): ... this.  Handle both direct and indirect calls.
> 	Create call insn directly instead of via various gen_... routines.
> 	Mention special registers used by the call in CALL_INSN_FUNCTION_USAGE.
> 	(rs6000_sibcall_aix): New function.
> 	* config/rs6000/rs6000.md (TOC_SAVE_OFFSET_32BIT): Remove.
> 	(TOC_SAVE_OFFSET_64BIT): Likewise.
> 	(AIX_FUNC_DESC_TOC_32BIT): Likewise.
> 	(AIX_FUNC_DESC_TOC_64BIT): Likewise.
> 	(AIX_FUNC_DESC_SC_32BIT): Likewise.
> 	(AIX_FUNC_DESC_SC_64BIT): Likewise.
> 	("call" expander): Call rs6000_call_aix.
> 	("call_value" expander): Likewise.
> 	("call_indirect_aix<ptrsize>"): Replace this pattern ...
> 	("call_indirect_aix<ptrsize>_nor11"): ... and this pattern ...
> 	("*call_indirect_aix<mode>"): ... by this insn pattern.
> 	("call_value_indirect_aix<ptrsize>"): Replace this pattern ...
> 	("call_value_indirect_aix<ptrsize>_nor11"): ... and this pattern ...
> 	("*call_value_indirect_aix<mode>"): ... by this insn pattern.
> 	("*call_nonlocal_aix32", "*call_nonlocal_aix64"): Replace by ...
> 	("*call_nonlocal_aix<mode>"): ... this pattern.
> 	("*call_value_nonlocal_aix32", "*call_value_nonlocal_aix64"): Replace
> 	("*call_value_nonlocal_aix<mode>"): ... by this pattern.
> 	("*call_local_aix<mode>"): New insn pattern.
> 	("*call_value_local_aix<mode>"): Likewise.
> 	("sibcall" expander): Call rs6000_sibcall_aix.
> 	("sibcall_value" expander): Likewise.  Move earlier in file.
> 	("*sibcall_nonlocal_aix<mode>"): Replace by ...
> 	("*sibcall_aix<mode>"): ... this pattern.
> 	("*sibcall_value_nonlocal_aix<mode>"): Replace by ...
> 	("*sibcall_value_aix<mode>"): ... this pattern.
> 	* config/rs6000/rs6000-protos.h (rs6000_call_indirect_aix): Remove.
> 	(rs6000_call_aix): Add prototype.
> 	(rs6000_sibcall_aix): Likewise.
> 
> 	Backport from mainline r204799:
> 
> 	2013-11-14  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>
> 
> 	* config/rs6000/rs6000.c (rs6000_emit_prologue): Do not place a
> 	RTX_FRAME_RELATED_P marker on the UNSPEC_MOVESI_FROM_CR insn.
> 	Instead, add USEs of all modified call-saved CR fields to the
> 	insn storing the result to the stack slot, and provide an
> 	appropriate REG_FRAME_RELATED_EXPR for that insn.
> 	* config/rs6000/rs6000.md ("*crsave"): New insn pattern.
> 	* config/rs6000/predicates.md ("crsave_operation"): New predicate.
> 
> [gcc/testsuite]
> 
> 2014-03-29  Bill Schmidt  <wschmidt@linux.vnet.ibm.com>
> 
> 	Backport from mainline r204808:
> 
> 	2013-11-14  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>
> 
> 	* gcc.target/powerpc/ppc64-abi-1.c (stack_frame_t): Remove
> 	compiler and linker field if _CALL_ELF == 2.
> 	* gcc.target/powerpc/ppc64-abi-2.c (stack_frame_t): Likewise.
> 	* gcc.target/powerpc/ppc64-abi-dfp-1.c (stack_frame_t): Likewise.
> 	* gcc.dg/stack-usage-1.c (SIZE): Update value for _CALL_ELF == 2.
> 
> 	2013-11-14  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>
> 
> 	* gcc.target/powerpc/ppc64-abi-dfp-1.c (FUNC_START): New macro.
> 	(WRAPPER): Use it.
> 	* gcc.target/powerpc/no-r11-1.c: Skip on powerpc_elfv2.
> 	* gcc.target/powerpc/no-r11-2.c: Skip on powerpc_elfv2.
> 	* gcc.target/powerpc/no-r11-3.c: Skip on powerpc_elfv2.
> 
> 	2013-11-14  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>
> 
> 	* lib/target-supports.exp (check_effective_target_powerpc_elfv2):
> 	New function.
> 	* gcc.target/powerpc/pr57949-1.c: Disable for powerpc_elfv2.
> 	* gcc.target/powerpc/pr57949-2.c: Likewise.
> 
> 	Backport from mainline r204799:
> 
> 	2013-11-14  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>
> 
> 	* g++.dg/eh/ppc64-sighandle-cr.C: New test.
> 
> [libgcc]
> 
> 2014-03-29  Bill Schmidt  <wschmidt@linux.vnet.ibm.com>
> 
> 	Backport from mainline r204808:
> 
> 	2013-11-14  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>
> 		    Alan Modra  <amodra@gmail.com>
> 
> 	* config/rs6000/linux-unwind.h (TOC_SAVE_SLOT): Define.
> 	(frob_update_context): Use it.
> 
> 	2013-11-14  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>
> 		    Alan Modra  <amodra@gmail.com>
> 
> 	* config/rs6000/tramp.S [__powerpc64__ && _CALL_ELF == 2]:
> 	(trampoline_initial): Provide ELFv2 variant.
> 	(__trampoline_setup): Likewise.
> 
> 	* config/rs6000/linux-unwind.h (frob_update_context): Do not
> 	check for AIX indirect function call sequence if _CALL_ELF == 2.
> 
> 	2013-11-14  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>
> 		    Alan Modra  <amodra@gmail.com>
> 
> 	* config/rs6000/linux-unwind.h (get_regs): Do not support
> 	old kernel versions if _CALL_ELF == 2.
> 	(frob_update_context): Do not support PLT stub variants only
> 	generated by old linkers if _CALL_ELF == 2.
> 
> 	Backport from mainline r204800:
> 
> 	2013-11-14  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>
> 		    Alan Modra  <amodra@gmail.com>
> 
> 	* config/rs6000/linux-unwind.h (ppc_fallback_frame_state): Correct
> 	location of CR save area for 64-bit little-endian systems.
> 
> [libitm]
> 
> 2014-03-29  Bill Schmidt  <wschmidt@linux.vnet.ibm.com>
> 
> 	Backport from mainline r204808:
> 
> 	2013-11-14  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>
> 
> 	* config/powerpc/sjlj.S [__powerpc64__ && _CALL_ELF == 2]:
> 	(FUNC): Define ELFv2 variant.
> 	(END): Likewise.
> 	(HIDDEN): Likewise.
> 	(CALL): Likewise.
> 	(BASE): Likewise.
> 	(LR_SAVE): Likewise.
> 
> [libstdc++]
> 
> 2014-03-29  Bill Schmidt  <wschmidt@linux.vnet.ibm.com>
> 
> 	Backport from mainline r204808:
> 
> 	2013-11-14  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>
> 
> 	* scripts/extract_symvers.in: Ignore <localentry: > fields
> 	in readelf --symbols output.
> 
> Index: gcc-4_8-test/gcc/config/rs6000/rs6000.c
> ===================================================================
> --- gcc-4_8-test.orig/gcc/config/rs6000/rs6000.c
> +++ gcc-4_8-test/gcc/config/rs6000/rs6000.c
> @@ -96,6 +96,7 @@ typedef struct rs6000_stack {
>    int spe_gp_save_offset;	/* offset to save spe 64-bit gprs  */
>    int varargs_save_offset;	/* offset to save the varargs registers */
>    int ehrd_offset;		/* offset to EH return data */
> +  int ehcr_offset;		/* offset to EH CR field data */
>    int reg_size;			/* register size (4 or 8) */
>    HOST_WIDE_INT vars_size;	/* variable save area size */
>    int parm_size;		/* outgoing parameter size */
> @@ -139,6 +140,8 @@ typedef struct GTY(()) machine_function
>       64-bits wide and is allocated early enough so that the offset
>       does not overflow the 16-bit load/store offset field.  */
>    rtx sdmode_stack_slot;
> +  /* Flag if r2 setup is needed with ELFv2 ABI.  */
> +  bool r2_setup_needed;
>  } machine_function;
>  
>  /* Support targetm.vectorize.builtin_mask_for_load.  */
> @@ -1448,6 +1451,9 @@ static const struct attribute_spec rs600
>  #undef TARGET_RETURN_IN_MEMORY
>  #define TARGET_RETURN_IN_MEMORY rs6000_return_in_memory
>  
> +#undef TARGET_RETURN_IN_MSB
> +#define TARGET_RETURN_IN_MSB rs6000_return_in_msb
> +
>  #undef TARGET_SETUP_INCOMING_VARARGS
>  #define TARGET_SETUP_INCOMING_VARARGS setup_incoming_varargs
>  
> @@ -2230,6 +2236,7 @@ rs6000_debug_reg_global (void)
>      {
>      case ABI_NONE:	abi_str = "none";	break;
>      case ABI_AIX:	abi_str = "aix";	break;
> +    case ABI_ELFv2:	abi_str = "ELFv2";	break;
>      case ABI_V4:	abi_str = "V4";		break;
>      case ABI_DARWIN:	abi_str = "darwin";	break;
>      default:		abi_str = "unknown";	break;
> @@ -3663,7 +3670,7 @@ rs6000_option_override_internal (bool gl
>  
>        /* We should always be splitting complex arguments, but we can't break
>  	 Linux and Darwin ABIs at the moment.  For now, only AIX is fixed.  */
> -      if (DEFAULT_ABI != ABI_AIX)
> +      if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_DARWIN)
>  	targetm.calls.split_complex_arg = NULL;
>      }
>  
> @@ -4755,7 +4762,11 @@ rs6000_file_start (void)
>  	putc ('\n', file);
>      }
>  
> -  if (DEFAULT_ABI == ABI_AIX || (TARGET_ELF && flag_pic == 2))
> +  if (DEFAULT_ABI == ABI_ELFv2)
> +    fprintf (file, "\t.abiversion 2\n");
> +
> +  if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2
> +      || (TARGET_ELF && flag_pic == 2))
>      {
>        switch_to_section (toc_section);
>        switch_to_section (text_section);
> @@ -6342,7 +6353,7 @@ legitimate_lo_sum_address_p (enum machin
>  
>    if (TARGET_ELF || TARGET_MACHO)
>      {
> -      if (DEFAULT_ABI != ABI_AIX && DEFAULT_ABI != ABI_DARWIN && flag_pic)
> +      if (DEFAULT_ABI == ABI_V4 && flag_pic)
>  	return false;
>        if (TARGET_TOC)
>  	return false;
> @@ -6919,10 +6930,13 @@ rs6000_legitimize_tls_address (rtx addr,
>  				   1, const0_rtx, Pmode);
>  
>  	  r3 = gen_rtx_REG (Pmode, 3);
> -	  if (DEFAULT_ABI == ABI_AIX && TARGET_64BIT)
> -	    insn = gen_tls_gd_aix64 (r3, got, addr, tga, const0_rtx);
> -	  else if (DEFAULT_ABI == ABI_AIX && !TARGET_64BIT)
> -	    insn = gen_tls_gd_aix32 (r3, got, addr, tga, const0_rtx);
> +	  if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
> +	    {
> +	      if (TARGET_64BIT)
> +		insn = gen_tls_gd_aix64 (r3, got, addr, tga, const0_rtx);
> +	      else
> +		insn = gen_tls_gd_aix32 (r3, got, addr, tga, const0_rtx);
> +	    }
>  	  else if (DEFAULT_ABI == ABI_V4)
>  	    insn = gen_tls_gd_sysvsi (r3, got, addr, tga, const0_rtx);
>  	  else
> @@ -6941,10 +6955,13 @@ rs6000_legitimize_tls_address (rtx addr,
>  				   1, const0_rtx, Pmode);
>  
>  	  r3 = gen_rtx_REG (Pmode, 3);
> -	  if (DEFAULT_ABI == ABI_AIX && TARGET_64BIT)
> -	    insn = gen_tls_ld_aix64 (r3, got, tga, const0_rtx);
> -	  else if (DEFAULT_ABI == ABI_AIX && !TARGET_64BIT)
> -	    insn = gen_tls_ld_aix32 (r3, got, tga, const0_rtx);
> +	  if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
> +	    {
> +	      if (TARGET_64BIT)
> +		insn = gen_tls_ld_aix64 (r3, got, tga, const0_rtx);
> +	      else
> +		insn = gen_tls_ld_aix32 (r3, got, tga, const0_rtx);
> +	    }
>  	  else if (DEFAULT_ABI == ABI_V4)
>  	    insn = gen_tls_ld_sysvsi (r3, got, tga, const0_rtx);
>  	  else
> @@ -7573,7 +7590,7 @@ rs6000_conditional_register_usage (void)
>  
>    /* The TOC register is not killed across calls in a way that is
>       visible to the compiler.  */
> -  if (DEFAULT_ABI == ABI_AIX)
> +  if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
>      call_really_used_regs[2] = 0;
>  
>    if (DEFAULT_ABI == ABI_V4
> @@ -8353,18 +8370,231 @@ rs6000_member_type_forces_blk (const_tre
>  }
>  
>  /* Nonzero if we can use a floating-point register to pass this arg.  */
> -#define USE_FP_FOR_ARG_P(CUM,MODE,TYPE)		\
> +#define USE_FP_FOR_ARG_P(CUM,MODE)		\
>    (SCALAR_FLOAT_MODE_P (MODE)			\
>     && (CUM)->fregno <= FP_ARG_MAX_REG		\
>     && TARGET_HARD_FLOAT && TARGET_FPRS)
>  
>  /* Nonzero if we can use an AltiVec register to pass this arg.  */
> -#define USE_ALTIVEC_FOR_ARG_P(CUM,MODE,TYPE,NAMED)		\
> +#define USE_ALTIVEC_FOR_ARG_P(CUM,MODE,NAMED)			\
>    (ALTIVEC_OR_VSX_VECTOR_MODE (MODE)				\
>     && (CUM)->vregno <= ALTIVEC_ARG_MAX_REG			\
>     && TARGET_ALTIVEC_ABI					\
>     && (NAMED))
>  
> +/* Walk down the type tree of TYPE counting consecutive base elements.
> +   If *MODEP is VOIDmode, then set it to the first valid floating point
> +   or vector type.  If a non-floating point or vector type is found, or
> +   if a floating point or vector type that doesn't match a non-VOIDmode
> +   *MODEP is found, then return -1, otherwise return the count in the
> +   sub-tree.  */
> +
> +static int
> +rs6000_aggregate_candidate (const_tree type, enum machine_mode *modep)
> +{
> +  enum machine_mode mode;
> +  HOST_WIDE_INT size;
> +
> +  switch (TREE_CODE (type))
> +    {
> +    case REAL_TYPE:
> +      mode = TYPE_MODE (type);
> +      if (!SCALAR_FLOAT_MODE_P (mode))
> +	return -1;
> +
> +      if (*modep == VOIDmode)
> +	*modep = mode;
> +
> +      if (*modep == mode)
> +	return 1;
> +
> +      break;
> +
> +    case COMPLEX_TYPE:
> +      mode = TYPE_MODE (TREE_TYPE (type));
> +      if (!SCALAR_FLOAT_MODE_P (mode))
> +	return -1;
> +
> +      if (*modep == VOIDmode)
> +	*modep = mode;
> +
> +      if (*modep == mode)
> +	return 2;
> +
> +      break;
> +
> +    case VECTOR_TYPE:
> +      if (!TARGET_ALTIVEC_ABI || !TARGET_ALTIVEC)
> +	return -1;
> +
> +      /* Use V4SImode as representative of all 128-bit vector types.  */
> +      size = int_size_in_bytes (type);
> +      switch (size)
> +	{
> +	case 16:
> +	  mode = V4SImode;
> +	  break;
> +	default:
> +	  return -1;
> +	}
> +
> +      if (*modep == VOIDmode)
> +	*modep = mode;
> +
> +      /* Vector modes are considered to be opaque: two vectors are
> +	 equivalent for the purposes of being homogeneous aggregates
> +	 if they are the same size.  */
> +      if (*modep == mode)
> +	return 1;
> +
> +      break;
> +
> +    case ARRAY_TYPE:
> +      {
> +	int count;
> +	tree index = TYPE_DOMAIN (type);
> +
> +	/* Can't handle incomplete types.  */
> +	if (!COMPLETE_TYPE_P (type))
> +	  return -1;
> +
> +	count = rs6000_aggregate_candidate (TREE_TYPE (type), modep);
> +	if (count == -1
> +	    || !index
> +	    || !TYPE_MAX_VALUE (index)
> +	    || !host_integerp (TYPE_MAX_VALUE (index), 1)
> +	    || !TYPE_MIN_VALUE (index)
> +	    || !host_integerp (TYPE_MIN_VALUE (index), 1)
> +	    || count < 0)
> +	  return -1;
> +
> +	count *= (1 + tree_low_cst (TYPE_MAX_VALUE (index), 1)
> +		      - tree_low_cst (TYPE_MIN_VALUE (index), 1));
> +
> +	/* There must be no padding.  */
> +	if (!host_integerp (TYPE_SIZE (type), 1)
> +	    || (tree_low_cst (TYPE_SIZE (type), 1)
> +		!= count * GET_MODE_BITSIZE (*modep)))
> +	  return -1;
> +
> +	return count;
> +      }
> +
> +    case RECORD_TYPE:
> +      {
> +	int count = 0;
> +	int sub_count;
> +	tree field;
> +
> +	/* Can't handle incomplete types.  */
> +	if (!COMPLETE_TYPE_P (type))
> +	  return -1;
> +
> +	for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
> +	  {
> +	    if (TREE_CODE (field) != FIELD_DECL)
> +	      continue;
> +
> +	    sub_count = rs6000_aggregate_candidate (TREE_TYPE (field), modep);
> +	    if (sub_count < 0)
> +	      return -1;
> +	    count += sub_count;
> +	  }
> +
> +	/* There must be no padding.  */
> +	if (!host_integerp (TYPE_SIZE (type), 1)
> +	    || (tree_low_cst (TYPE_SIZE (type), 1)
> +		!= count * GET_MODE_BITSIZE (*modep)))
> +	  return -1;
> +
> +	return count;
> +      }
> +
> +    case UNION_TYPE:
> +    case QUAL_UNION_TYPE:
> +      {
> +	/* These aren't very interesting except in a degenerate case.  */
> +	int count = 0;
> +	int sub_count;
> +	tree field;
> +
> +	/* Can't handle incomplete types.  */
> +	if (!COMPLETE_TYPE_P (type))
> +	  return -1;
> +
> +	for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
> +	  {
> +	    if (TREE_CODE (field) != FIELD_DECL)
> +	      continue;
> +
> +	    sub_count = rs6000_aggregate_candidate (TREE_TYPE (field), modep);
> +	    if (sub_count < 0)
> +	      return -1;
> +	    count = count > sub_count ? count : sub_count;
> +	  }
> +
> +	/* There must be no padding.  */
> +	if (!host_integerp (TYPE_SIZE (type), 1)
> +	    || (tree_low_cst (TYPE_SIZE (type), 1)
> +		!= count * GET_MODE_BITSIZE (*modep)))
> +	  return -1;
> +
> +	return count;
> +      }
> +
> +    default:
> +      break;
> +    }
> +
> +  return -1;
> +}
> +
> +/* If an argument, whose type is described by TYPE and MODE, is a homogeneous
> +   float or vector aggregate that shall be passed in FP/vector registers
> +   according to the ELFv2 ABI, return the homogeneous element mode in
> +   *ELT_MODE and the number of elements in *N_ELTS, and return TRUE.
> +
> +   Otherwise, set *ELT_MODE to MODE and *N_ELTS to 1, and return FALSE.  */
> +
> +static bool
> +rs6000_discover_homogeneous_aggregate (enum machine_mode mode, const_tree type,
> +				       enum machine_mode *elt_mode,
> +				       int *n_elts)
> +{
> +  /* Note that we do not accept complex types at the top level as
> +     homogeneous aggregates; these types are handled via the
> +     targetm.calls.split_complex_arg mechanism.  Complex types
> +     can be elements of homogeneous aggregates, however.  */
> +  if (DEFAULT_ABI == ABI_ELFv2 && type && AGGREGATE_TYPE_P (type))
> +    {
> +      enum machine_mode field_mode = VOIDmode;
> +      int field_count = rs6000_aggregate_candidate (type, &field_mode);
> +
> +      if (field_count > 0)
> +	{
> +	  int n_regs = (SCALAR_FLOAT_MODE_P (field_mode)?
> +			(GET_MODE_SIZE (field_mode) + 7) >> 3 : 1);
> +
> +	  /* The ELFv2 ABI allows homogeneous aggregates to occupy
> +	     up to AGGR_ARG_NUM_REG registers.  */
> +	  if (field_count * n_regs <= AGGR_ARG_NUM_REG)
> +	    {
> +	      if (elt_mode)
> +		*elt_mode = field_mode;
> +	      if (n_elts)
> +		*n_elts = field_count;
> +	      return true;
> +	    }
> +	}
> +    }
> +
> +  if (elt_mode)
> +    *elt_mode = mode;
> +  if (n_elts)
> +    *n_elts = 1;
> +  return false;
> +}
> +
>  /* Return a nonzero value to say to return the function value in
>     memory, just as large structures are always returned.  TYPE will be
>     the data type of the value, and FNTYPE will be the type of the
> @@ -8417,6 +8647,16 @@ rs6000_return_in_memory (const_tree type
>        /* Otherwise fall through to more conventional ABI rules.  */
>      }
>  
> +  /* The ELFv2 ABI returns homogeneous VFP aggregates in registers */
> +  if (rs6000_discover_homogeneous_aggregate (TYPE_MODE (type), type,
> +					     NULL, NULL))
> +    return false;
> +
> +  /* The ELFv2 ABI returns aggregates up to 16B in registers */
> +  if (DEFAULT_ABI == ABI_ELFv2 && AGGREGATE_TYPE_P (type)
> +      && (unsigned HOST_WIDE_INT) int_size_in_bytes (type) <= 16)
> +    return false;
> +
>    if (AGGREGATE_TYPE_P (type)
>        && (aix_struct_return
>  	  || (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 8))
> @@ -8448,6 +8688,19 @@ rs6000_return_in_memory (const_tree type
>    return false;
>  }
>  
> +/* Specify whether values returned in registers should be at the most
> +   significant end of a register.  We want aggregates returned by
> +   value to match the way aggregates are passed to functions.  */
> +
> +static bool
> +rs6000_return_in_msb (const_tree valtype)
> +{
> +  return (DEFAULT_ABI == ABI_ELFv2
> +	  && BYTES_BIG_ENDIAN
> +	  && AGGREGATE_TYPE_P (valtype)
> +	  && FUNCTION_ARG_PADDING (TYPE_MODE (valtype), valtype) == upward);
> +}
> +
>  #ifdef HAVE_AS_GNU_ATTRIBUTE
>  /* Return TRUE if a call to function FNDECL may be one that
>     potentially affects the function calling ABI of the object file.  */
> @@ -8584,7 +8837,7 @@ init_cumulative_args (CUMULATIVE_ARGS *c
>  static bool
>  rs6000_must_pass_in_stack (enum machine_mode mode, const_tree type)
>  {
> -  if (DEFAULT_ABI == ABI_AIX || TARGET_64BIT)
> +  if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2 || TARGET_64BIT)
>      return must_pass_in_stack_var_size (mode, type);
>    else
>      return must_pass_in_stack_var_size_or_pad (mode, type);
> @@ -8665,6 +8918,11 @@ function_arg_padding (enum machine_mode
>  static unsigned int
>  rs6000_function_arg_boundary (enum machine_mode mode, const_tree type)
>  {
> +  enum machine_mode elt_mode;
> +  int n_elts;
> +
> +  rs6000_discover_homogeneous_aggregate (mode, type, &elt_mode, &n_elts);
> +
>    if (DEFAULT_ABI == ABI_V4
>        && (GET_MODE_SIZE (mode) == 8
>  	  || (TARGET_HARD_FLOAT
> @@ -8676,11 +8934,12 @@ rs6000_function_arg_boundary (enum machi
>  	       && int_size_in_bytes (type) >= 8
>  	       && int_size_in_bytes (type) < 16))
>      return 64;
> -  else if (ALTIVEC_OR_VSX_VECTOR_MODE (mode)
> +  else if (ALTIVEC_OR_VSX_VECTOR_MODE (elt_mode)
>  	   || (type && TREE_CODE (type) == VECTOR_TYPE
>  	       && int_size_in_bytes (type) >= 16))
>      return 128;
>    else if (((TARGET_MACHO && rs6000_darwin64_abi)
> +	    || DEFAULT_ABI == ABI_ELFv2
>              || (DEFAULT_ABI == ABI_AIX && !rs6000_compat_align_parm))
>   	   && mode == BLKmode
>  	   && type && TYPE_ALIGN (type) > 64)
> @@ -8689,6 +8948,16 @@ rs6000_function_arg_boundary (enum machi
>      return PARM_BOUNDARY;
>  }
>  
> +/* The offset in words to the start of the parameter save area.  */
> +
> +static unsigned int
> +rs6000_parm_offset (void)
> +{
> +  return (DEFAULT_ABI == ABI_V4 ? 2
> +	  : DEFAULT_ABI == ABI_ELFv2 ? 4
> +	  : 6);
> +}
> +
>  /* For a function parm of MODE and TYPE, return the starting word in
>     the parameter area.  NWORDS of the parameter area are already used.  */
>  
> @@ -8697,11 +8966,9 @@ rs6000_parm_start (enum machine_mode mod
>  		   unsigned int nwords)
>  {
>    unsigned int align;
> -  unsigned int parm_offset;
>  
>    align = rs6000_function_arg_boundary (mode, type) / PARM_BOUNDARY - 1;
> -  parm_offset = DEFAULT_ABI == ABI_V4 ? 2 : 6;
> -  return nwords + (-(parm_offset + nwords) & align);
> +  return nwords + (-(rs6000_parm_offset () + nwords) & align);
>  }
>  
>  /* Compute the size (in words) of a function argument.  */
> @@ -8808,7 +9075,7 @@ rs6000_darwin64_record_arg_advance_recur
>  
>  	if (TREE_CODE (ftype) == RECORD_TYPE)
>  	  rs6000_darwin64_record_arg_advance_recurse (cum, ftype, bitpos);
> -	else if (USE_FP_FOR_ARG_P (cum, mode, ftype))
> +	else if (USE_FP_FOR_ARG_P (cum, mode))
>  	  {
>  	    unsigned n_fpregs = (GET_MODE_SIZE (mode) + 7) >> 3;
>  	    rs6000_darwin64_record_arg_advance_flush (cum, bitpos, 0);
> @@ -8849,7 +9116,7 @@ rs6000_darwin64_record_arg_advance_recur
>  	    else
>  	      cum->words += n_fpregs;
>  	  }
> -	else if (USE_ALTIVEC_FOR_ARG_P (cum, mode, type, 1))
> +	else if (USE_ALTIVEC_FOR_ARG_P (cum, mode, 1))
>  	  {
>  	    rs6000_darwin64_record_arg_advance_flush (cum, bitpos, 0);
>  	    cum->vregno++;
> @@ -8886,6 +9153,11 @@ static void
>  rs6000_function_arg_advance_1 (CUMULATIVE_ARGS *cum, enum machine_mode mode,
>  			       const_tree type, bool named, int depth)
>  {
> +  enum machine_mode elt_mode;
> +  int n_elts;
> +
> +  rs6000_discover_homogeneous_aggregate (mode, type, &elt_mode, &n_elts);
> +
>    /* Only tick off an argument if we're not recursing.  */
>    if (depth == 0)
>      cum->nargs_prototype--;
> @@ -8906,15 +9178,16 @@ rs6000_function_arg_advance_1 (CUMULATIV
>  #endif
>  
>    if (TARGET_ALTIVEC_ABI
> -      && (ALTIVEC_OR_VSX_VECTOR_MODE (mode)
> +      && (ALTIVEC_OR_VSX_VECTOR_MODE (elt_mode)
>  	  || (type && TREE_CODE (type) == VECTOR_TYPE
>  	      && int_size_in_bytes (type) == 16)))
>      {
>        bool stack = false;
>  
> -      if (USE_ALTIVEC_FOR_ARG_P (cum, mode, type, named))
> +      if (USE_ALTIVEC_FOR_ARG_P (cum, elt_mode, named))
>  	{
> -	  cum->vregno++;
> +	  cum->vregno += n_elts;
> +
>  	  if (!TARGET_ALTIVEC)
>  	    error ("cannot pass argument in vector register because"
>  		   " altivec instructions are disabled, use -maltivec"
> @@ -8923,7 +9196,8 @@ rs6000_function_arg_advance_1 (CUMULATIV
>  	  /* PowerPC64 Linux and AIX allocate GPRs for a vector argument
>  	     even if it is going to be passed in a vector register.
>  	     Darwin does the same for variable-argument functions.  */
> -	  if ((DEFAULT_ABI == ABI_AIX && TARGET_64BIT)
> +	  if (((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
> +	       && TARGET_64BIT)
>  	      || (cum->stdarg && DEFAULT_ABI != ABI_V4))
>  	    stack = true;
>  	}
> @@ -8934,15 +9208,13 @@ rs6000_function_arg_advance_1 (CUMULATIV
>  	{
>  	  int align;
>  
> -	  /* Vector parameters must be 16-byte aligned.  This places
> -	     them at 2 mod 4 in terms of words in 32-bit mode, since
> -	     the parameter save area starts at offset 24 from the
> -	     stack.  In 64-bit mode, they just have to start on an
> -	     even word, since the parameter save area is 16-byte
> -	     aligned.  Space for GPRs is reserved even if the argument
> -	     will be passed in memory.  */
> +	  /* Vector parameters must be 16-byte aligned.  In 32-bit
> +	     mode this means we need to take into account the offset
> +	     to the parameter save area.  In 64-bit mode, they just
> +	     have to start on an even word, since the parameter save
> +	     area is 16-byte aligned.  */
>  	  if (TARGET_32BIT)
> -	    align = (2 - cum->words) & 3;
> +	    align = -(rs6000_parm_offset () + cum->words) & 3;
>  	  else
>  	    align = cum->words & 1;
>  	  cum->words += align + rs6000_arg_size (mode, type);
> @@ -9067,15 +9339,15 @@ rs6000_function_arg_advance_1 (CUMULATIV
>  
>        cum->words = align_words + n_words;
>  
> -      if (SCALAR_FLOAT_MODE_P (mode)
> +      if (SCALAR_FLOAT_MODE_P (elt_mode)
>  	  && TARGET_HARD_FLOAT && TARGET_FPRS)
>  	{
>  	  /* _Decimal128 must be passed in an even/odd float register pair.
>  	     This assumes that the register number is odd when fregno is
>  	     odd.  */
> -	  if (mode == TDmode && (cum->fregno % 2) == 1)
> +	  if (elt_mode == TDmode && (cum->fregno % 2) == 1)
>  	    cum->fregno++;
> -	  cum->fregno += (GET_MODE_SIZE (mode) + 7) >> 3;
> +	  cum->fregno += n_elts * ((GET_MODE_SIZE (elt_mode) + 7) >> 3);
>  	}
>  
>        if (TARGET_DEBUG_ARG)
> @@ -9285,7 +9557,7 @@ rs6000_darwin64_record_arg_recurse (CUMU
>  
>  	if (TREE_CODE (ftype) == RECORD_TYPE)
>  	  rs6000_darwin64_record_arg_recurse (cum, ftype, bitpos, rvec, k);
> -	else if (cum->named && USE_FP_FOR_ARG_P (cum, mode, ftype))
> +	else if (cum->named && USE_FP_FOR_ARG_P (cum, mode))
>  	  {
>  	    unsigned n_fpreg = (GET_MODE_SIZE (mode) + 7) >> 3;
>  #if 0
> @@ -9313,7 +9585,7 @@ rs6000_darwin64_record_arg_recurse (CUMU
>  	    if (mode == TFmode || mode == TDmode)
>  	      cum->fregno++;
>  	  }
> -	else if (cum->named && USE_ALTIVEC_FOR_ARG_P (cum, mode, ftype, 1))
> +	else if (cum->named && USE_ALTIVEC_FOR_ARG_P (cum, mode, 1))
>  	  {
>  	    rs6000_darwin64_record_arg_flush (cum, bitpos, rvec, k);
>  	    rvec[(*k)++]
> @@ -9430,6 +9702,84 @@ rs6000_mixed_function_arg (enum machine_
>    return gen_rtx_PARALLEL (mode, gen_rtvec_v (k, rvec));
>  }
>  
> +/* We have an argument of MODE and TYPE that goes into FPRs or VRs,
> +   but must also be copied into the parameter save area starting at
> +   offset ALIGN_WORDS.  Fill in RVEC with the elements corresponding
> +   to the GPRs and/or memory.  Return the number of elements used.  */
> +
> +static int
> +rs6000_psave_function_arg (enum machine_mode mode, const_tree type,
> +			   int align_words, rtx *rvec)
> +{
> +  int k = 0;
> +
> +  if (align_words < GP_ARG_NUM_REG)
> +    {
> +      int n_words = rs6000_arg_size (mode, type);
> +
> +      if (align_words + n_words > GP_ARG_NUM_REG
> +	  || mode == BLKmode
> +	  || (TARGET_32BIT && TARGET_POWERPC64))
> +	{
> +	  /* If this is partially on the stack, then we only
> +	     include the portion actually in registers here.  */
> +	  enum machine_mode rmode = TARGET_32BIT ? SImode : DImode;
> +	  int i = 0;
> +
> +	  if (align_words + n_words > GP_ARG_NUM_REG)
> +	    {
> +	      /* Not all of the arg fits in gprs.  Say that it goes in memory
> +		 too, using a magic NULL_RTX component.  Also see comment in
> +		 rs6000_mixed_function_arg for why the normal
> +		 function_arg_partial_nregs scheme doesn't work in this case. */
> +	      rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx);
> +	    }
> +
> +	  do
> +	    {
> +	      rtx r = gen_rtx_REG (rmode, GP_ARG_MIN_REG + align_words);
> +	      rtx off = GEN_INT (i++ * GET_MODE_SIZE (rmode));
> +	      rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, off);
> +	    }
> +	  while (++align_words < GP_ARG_NUM_REG && --n_words != 0);
> +	}
> +      else
> +	{
> +	  /* The whole arg fits in gprs.  */
> +	  rtx r = gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
> +	  rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, const0_rtx);
> +	}
> +    }
> +  else
> +    {
> +      /* It's entirely in memory.  */
> +      rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx);
> +    }
> +
> +  return k;
> +}
> +
> +/* RVEC is a vector of K components of an argument of mode MODE.
> +   Construct the final function_arg return value from it.  */
> +
> +static rtx
> +rs6000_finish_function_arg (enum machine_mode mode, rtx *rvec, int k)
> +{
> +  gcc_assert (k >= 1);
> +
> +  /* Avoid returning a PARALLEL in the trivial cases.  */
> +  if (k == 1)
> +    {
> +      if (XEXP (rvec[0], 0) == NULL_RTX)
> +	return NULL_RTX;
> +
> +      if (GET_MODE (XEXP (rvec[0], 0)) == mode)
> +	return XEXP (rvec[0], 0);
> +    }
> +
> +  return gen_rtx_PARALLEL (mode, gen_rtvec_v (k, rvec));
> +}
> +
>  /* Determine where to put an argument to a function.
>     Value is zero to push the argument on the stack,
>     or a hard register in which to store the argument.
> @@ -9464,6 +9814,8 @@ rs6000_function_arg (cumulative_args_t c
>  {
>    CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
>    enum rs6000_abi abi = DEFAULT_ABI;
> +  enum machine_mode elt_mode;
> +  int n_elts;
>  
>    /* Return a marker to indicate whether CR1 needs to set or clear the
>       bit that V.4 uses to say fp args were passed in registers.
> @@ -9490,6 +9842,8 @@ rs6000_function_arg (cumulative_args_t c
>        return GEN_INT (cum->call_cookie & ~CALL_LIBCALL);
>      }
>  
> +  rs6000_discover_homogeneous_aggregate (mode, type, &elt_mode, &n_elts);
> +
>    if (TARGET_MACHO && rs6000_darwin64_struct_check_p (mode, type))
>      {
>        rtx rslt = rs6000_darwin64_record_arg (cum, type, named, /*retval= */false);
> @@ -9498,33 +9852,30 @@ rs6000_function_arg (cumulative_args_t c
>        /* Else fall through to usual handling.  */
>      }
>  
> -  if (USE_ALTIVEC_FOR_ARG_P (cum, mode, type, named))
> -    if (TARGET_64BIT && ! cum->prototype)
> -      {
> -	/* Vector parameters get passed in vector register
> -	   and also in GPRs or memory, in absence of prototype.  */
> -	int align_words;
> -	rtx slot;
> -	align_words = (cum->words + 1) & ~1;
> +  if (USE_ALTIVEC_FOR_ARG_P (cum, elt_mode, named))
> +    {
> +      rtx rvec[GP_ARG_NUM_REG + AGGR_ARG_NUM_REG + 1];
> +      rtx r, off;
> +      int i, k = 0;
>  
> -	if (align_words >= GP_ARG_NUM_REG)
> -	  {
> -	    slot = NULL_RTX;
> -	  }
> -	else
> -	  {
> -	    slot = gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
> -	  }
> -	return gen_rtx_PARALLEL (mode,
> -		 gen_rtvec (2,
> -			    gen_rtx_EXPR_LIST (VOIDmode,
> -					       slot, const0_rtx),
> -			    gen_rtx_EXPR_LIST (VOIDmode,
> -					       gen_rtx_REG (mode, cum->vregno),
> -					       const0_rtx)));
> -      }
> -    else
> -      return gen_rtx_REG (mode, cum->vregno);
> +      /* Do we also need to pass this argument in the parameter
> +	 save area?  */
> +      if (TARGET_64BIT && ! cum->prototype)
> +	{
> +	  int align_words = (cum->words + 1) & ~1;
> +	  k = rs6000_psave_function_arg (mode, type, align_words, rvec);
> +	}
> +
> +      /* Describe where this argument goes in the vector registers.  */
> +      for (i = 0; i < n_elts && cum->vregno + i <= ALTIVEC_ARG_MAX_REG; i++)
> +	{
> +	  r = gen_rtx_REG (elt_mode, cum->vregno + i);
> +	  off = GEN_INT (i * GET_MODE_SIZE (elt_mode));
> +	  rvec[k++] =  gen_rtx_EXPR_LIST (VOIDmode, r, off);
> +	}
> +
> +      return rs6000_finish_function_arg (mode, rvec, k);
> +    }
>    else if (TARGET_ALTIVEC_ABI
>  	   && (ALTIVEC_OR_VSX_VECTOR_MODE (mode)
>  	       || (type && TREE_CODE (type) == VECTOR_TYPE
> @@ -9539,13 +9890,13 @@ rs6000_function_arg (cumulative_args_t c
>  	  int align, align_words, n_words;
>  	  enum machine_mode part_mode;
>  
> -	  /* Vector parameters must be 16-byte aligned.  This places them at
> -	     2 mod 4 in terms of words in 32-bit mode, since the parameter
> -	     save area starts at offset 24 from the stack.  In 64-bit mode,
> -	     they just have to start on an even word, since the parameter
> -	     save area is 16-byte aligned.  */
> +	  /* Vector parameters must be 16-byte aligned.  In 32-bit
> +	     mode this means we need to take into account the offset
> +	     to the parameter save area.  In 64-bit mode, they just
> +	     have to start on an even word, since the parameter save
> +	     area is 16-byte aligned.  */
>  	  if (TARGET_32BIT)
> -	    align = (2 - cum->words) & 3;
> +	    align = -(rs6000_parm_offset () + cum->words) & 3;
>  	  else
>  	    align = cum->words & 1;
>  	  align_words = cum->words + align;
> @@ -9623,101 +9974,50 @@ rs6000_function_arg (cumulative_args_t c
>  
>        /* _Decimal128 must be passed in an even/odd float register pair.
>  	 This assumes that the register number is odd when fregno is odd.  */
> -      if (mode == TDmode && (cum->fregno % 2) == 1)
> +      if (elt_mode == TDmode && (cum->fregno % 2) == 1)
>  	cum->fregno++;
>  
> -      if (USE_FP_FOR_ARG_P (cum, mode, type))
> +      if (USE_FP_FOR_ARG_P (cum, elt_mode))
>  	{
> -	  rtx rvec[GP_ARG_NUM_REG + 1];
> -	  rtx r;
> -	  int k;
> -	  bool needs_psave;
> -	  enum machine_mode fmode = mode;
> -	  unsigned long n_fpreg = (GET_MODE_SIZE (mode) + 7) >> 3;
> -
> -	  if (cum->fregno + n_fpreg > FP_ARG_MAX_REG + 1)
> -	    {
> -	      /* Currently, we only ever need one reg here because complex
> -		 doubles are split.  */
> -	      gcc_assert (cum->fregno == FP_ARG_MAX_REG
> -			  && (fmode == TFmode || fmode == TDmode));
> -
> -	      /* Long double or _Decimal128 split over regs and memory.  */
> -	      fmode = DECIMAL_FLOAT_MODE_P (fmode) ? DDmode : DFmode;
> -	    }
> -
> -	  /* Do we also need to pass this arg in the parameter save
> -	     area?  */
> -	  needs_psave = (type
> -			 && (cum->nargs_prototype <= 0
> -			     || (DEFAULT_ABI == ABI_AIX
> -				 && TARGET_XL_COMPAT
> -				 && align_words >= GP_ARG_NUM_REG)));
> -
> -	  if (!needs_psave && mode == fmode)
> -	    return gen_rtx_REG (fmode, cum->fregno);
> -
> -	  k = 0;
> -	  if (needs_psave)
> -	    {
> -	      /* Describe the part that goes in gprs or the stack.
> -		 This piece must come first, before the fprs.  */
> -	      if (align_words < GP_ARG_NUM_REG)
> +	  rtx rvec[GP_ARG_NUM_REG + AGGR_ARG_NUM_REG + 1];
> +	  rtx r, off;
> +	  int i, k = 0;
> +	  unsigned long n_fpreg = (GET_MODE_SIZE (elt_mode) + 7) >> 3;
> +
> +	  /* Do we also need to pass this argument in the parameter
> +	     save area?  */
> +	  if (type && (cum->nargs_prototype <= 0
> +		       || ((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
> +			   && TARGET_XL_COMPAT
> +			   && align_words >= GP_ARG_NUM_REG)))
> +	    k = rs6000_psave_function_arg (mode, type, align_words, rvec);
> +
> +	  /* Describe where this argument goes in the fprs.  */
> +	  for (i = 0; i < n_elts
> +		      && cum->fregno + i * n_fpreg <= FP_ARG_MAX_REG; i++)
> +	    {
> +	      /* Check if the argument is split over registers and memory.
> +		 This can only ever happen for long double or _Decimal128;
> +		 complex types are handled via split_complex_arg.  */
> +	      enum machine_mode fmode = elt_mode;
> +	      if (cum->fregno + (i + 1) * n_fpreg > FP_ARG_MAX_REG + 1)
>  		{
> -		  unsigned long n_words = rs6000_arg_size (mode, type);
> -
> -		  if (align_words + n_words > GP_ARG_NUM_REG
> -		      || (TARGET_32BIT && TARGET_POWERPC64))
> -		    {
> -		      /* If this is partially on the stack, then we only
> -			 include the portion actually in registers here.  */
> -		      enum machine_mode rmode = TARGET_32BIT ? SImode : DImode;
> -		      rtx off;
> -		      int i = 0;
> -		      if (align_words + n_words > GP_ARG_NUM_REG)
> -			/* Not all of the arg fits in gprs.  Say that it
> -			   goes in memory too, using a magic NULL_RTX
> -			   component.  Also see comment in
> -			   rs6000_mixed_function_arg for why the normal
> -			   function_arg_partial_nregs scheme doesn't work
> -			   in this case. */
> -			rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX,
> -						       const0_rtx);
> -		      do
> -			{
> -			  r = gen_rtx_REG (rmode,
> -					   GP_ARG_MIN_REG + align_words);
> -			  off = GEN_INT (i++ * GET_MODE_SIZE (rmode));
> -			  rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, off);
> -			}
> -		      while (++align_words < GP_ARG_NUM_REG && --n_words != 0);
> -		    }
> -		  else
> -		    {
> -		      /* The whole arg fits in gprs.  */
> -		      r = gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
> -		      rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, const0_rtx);
> -		    }
> +		  gcc_assert (fmode == TFmode || fmode == TDmode);
> +		  fmode = DECIMAL_FLOAT_MODE_P (fmode) ? DDmode : DFmode;
>  		}
> -	      else
> -		/* It's entirely in memory.  */
> -		rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx);
> -	    }
>  
> -	  /* Describe where this piece goes in the fprs.  */
> -	  r = gen_rtx_REG (fmode, cum->fregno);
> -	  rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, const0_rtx);
> +	      r = gen_rtx_REG (fmode, cum->fregno + i * n_fpreg);
> +	      off = GEN_INT (i * GET_MODE_SIZE (elt_mode));
> +	      rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, off);
> +	    }
>  
> -	  return gen_rtx_PARALLEL (mode, gen_rtvec_v (k, rvec));
> +	  return rs6000_finish_function_arg (mode, rvec, k);
>  	}
>        else if (align_words < GP_ARG_NUM_REG)
>  	{
>  	  if (TARGET_32BIT && TARGET_POWERPC64)
>  	    return rs6000_mixed_function_arg (mode, type, align_words);
>  
> -	  if (mode == BLKmode)
> -	    mode = Pmode;
> -
>  	  return gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
>  	}
>        else
> @@ -9736,15 +10036,31 @@ rs6000_arg_partial_bytes (cumulative_arg
>  			  tree type, bool named)
>  {
>    CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
> +  bool passed_in_gprs = true;
>    int ret = 0;
>    int align_words;
> +  enum machine_mode elt_mode;
> +  int n_elts;
> +
> +  rs6000_discover_homogeneous_aggregate (mode, type, &elt_mode, &n_elts);
>  
>    if (DEFAULT_ABI == ABI_V4)
>      return 0;
>  
> -  if (USE_ALTIVEC_FOR_ARG_P (cum, mode, type, named)
> -      && cum->nargs_prototype >= 0)
> -    return 0;
> +  if (USE_ALTIVEC_FOR_ARG_P (cum, elt_mode, named))
> +    {
> +      /* If we are passing this arg in the fixed parameter save area
> +         (gprs or memory) as well as VRs, we do not use the partial
> +	 bytes mechanism; instead, rs6000_function_arg will return a
> +	 PARALLEL including a memory element as necessary.  */
> +      if (TARGET_64BIT && ! cum->prototype)
> +	return 0;
> +
> +      /* Otherwise, we pass in VRs only.  Check for partial copies.  */
> +      passed_in_gprs = false;
> +      if (cum->vregno + n_elts > ALTIVEC_ARG_MAX_REG + 1)
> +	ret = (ALTIVEC_ARG_MAX_REG + 1 - cum->vregno) * 16;
> +    }
>  
>    /* In this complicated case we just disable the partial_nregs code.  */
>    if (TARGET_MACHO && rs6000_darwin64_struct_check_p (mode, type))
> @@ -9752,26 +10068,30 @@ rs6000_arg_partial_bytes (cumulative_arg
>  
>    align_words = rs6000_parm_start (mode, type, cum->words);
>  
> -  if (USE_FP_FOR_ARG_P (cum, mode, type))
> +  if (USE_FP_FOR_ARG_P (cum, elt_mode))
>      {
> +      unsigned long n_fpreg = (GET_MODE_SIZE (elt_mode) + 7) >> 3;
> +
>        /* If we are passing this arg in the fixed parameter save area
> -	 (gprs or memory) as well as fprs, then this function should
> -	 return the number of partial bytes passed in the parameter
> -	 save area rather than partial bytes passed in fprs.  */
> +         (gprs or memory) as well as FPRs, we do not use the partial
> +	 bytes mechanism; instead, rs6000_function_arg will return a
> +	 PARALLEL including a memory element as necessary.  */
>        if (type
>  	  && (cum->nargs_prototype <= 0
> -	      || (DEFAULT_ABI == ABI_AIX
> +	      || ((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
>  		  && TARGET_XL_COMPAT
>  		  && align_words >= GP_ARG_NUM_REG)))
>  	return 0;
> -      else if (cum->fregno + ((GET_MODE_SIZE (mode) + 7) >> 3)
> -	       > FP_ARG_MAX_REG + 1)
> -	ret = (FP_ARG_MAX_REG + 1 - cum->fregno) * 8;
> -      else if (cum->nargs_prototype >= 0)
> -	return 0;
> +
> +      /* Otherwise, we pass in FPRs only.  Check for partial copies.  */
> +      passed_in_gprs = false;
> +      if (cum->fregno + n_elts * n_fpreg > FP_ARG_MAX_REG + 1)
> +	ret = ((FP_ARG_MAX_REG + 1 - cum->fregno)
> +	       * MIN (8, GET_MODE_SIZE (elt_mode)));
>      }
>  
> -  if (align_words < GP_ARG_NUM_REG
> +  if (passed_in_gprs
> +      && align_words < GP_ARG_NUM_REG
>        && GP_ARG_NUM_REG < align_words + rs6000_arg_size (mode, type))
>      ret = (GP_ARG_NUM_REG - align_words) * (TARGET_32BIT ? 4 : 8);
>  
> @@ -9852,6 +10172,139 @@ rs6000_pass_by_reference (cumulative_arg
>    return 0;
>  }
>  
> +/* Process parameter of type TYPE after ARGS_SO_FAR parameters were
> +   already processes.  Return true if the parameter must be passed
> +   (fully or partially) on the stack.  */
> +
> +static bool
> +rs6000_parm_needs_stack (cumulative_args_t args_so_far, tree type)
> +{
> +  enum machine_mode mode;
> +  int unsignedp;
> +  rtx entry_parm;
> +
> +  /* Catch errors.  */
> +  if (type == NULL || type == error_mark_node)
> +    return true;
> +
> +  /* Handle types with no storage requirement.  */
> +  if (TYPE_MODE (type) == VOIDmode)
> +    return false;
> +
> +  /* Handle complex types.  */
> +  if (TREE_CODE (type) == COMPLEX_TYPE)
> +    return (rs6000_parm_needs_stack (args_so_far, TREE_TYPE (type))
> +	    || rs6000_parm_needs_stack (args_so_far, TREE_TYPE (type)));
> +
> +  /* Handle transparent aggregates.  */
> +  if ((TREE_CODE (type) == UNION_TYPE || TREE_CODE (type) == RECORD_TYPE)
> +      && TYPE_TRANSPARENT_AGGR (type))
> +    type = TREE_TYPE (first_field (type));
> +
> +  /* See if this arg was passed by invisible reference.  */
> +  if (pass_by_reference (get_cumulative_args (args_so_far),
> +			 TYPE_MODE (type), type, true))
> +    type = build_pointer_type (type);
> +
> +  /* Find mode as it is passed by the ABI.  */
> +  unsignedp = TYPE_UNSIGNED (type);
> +  mode = promote_mode (type, TYPE_MODE (type), &unsignedp);
> +
> +  /* If we must pass in stack, we need a stack.  */
> +  if (rs6000_must_pass_in_stack (mode, type))
> +    return true;
> +
> +  /* If there is no incoming register, we need a stack.  */
> +  entry_parm = rs6000_function_arg (args_so_far, mode, type, true);
> +  if (entry_parm == NULL)
> +    return true;
> +
> +  /* Likewise if we need to pass both in registers and on the stack.  */
> +  if (GET_CODE (entry_parm) == PARALLEL
> +      && XEXP (XVECEXP (entry_parm, 0, 0), 0) == NULL_RTX)
> +    return true;
> +
> +  /* Also true if we're partially in registers and partially not.  */
> +  if (rs6000_arg_partial_bytes (args_so_far, mode, type, true) != 0)
> +    return true;
> +
> +  /* Update info on where next arg arrives in registers.  */
> +  rs6000_function_arg_advance (args_so_far, mode, type, true);
> +  return false;
> +}
> +
> +/* Return true if FUN has no prototype, has a variable argument
> +   list, or passes any parameter in memory.  */
> +
> +static bool
> +rs6000_function_parms_need_stack (tree fun)
> +{
> +  function_args_iterator args_iter;
> +  tree arg_type;
> +  CUMULATIVE_ARGS args_so_far_v;
> +  cumulative_args_t args_so_far;
> +
> +  if (!fun)
> +    /* Must be a libcall, all of which only use reg parms.  */
> +    return false;
> +  if (!TYPE_P (fun))
> +    fun = TREE_TYPE (fun);
> +
> +  /* Varargs functions need the parameter save area.  */
> +  if (!prototype_p (fun) || stdarg_p (fun))
> +    return true;
> +
> +  INIT_CUMULATIVE_INCOMING_ARGS (args_so_far_v, fun, NULL_RTX);
> +  args_so_far = pack_cumulative_args (&args_so_far_v);
> +
> +  if (aggregate_value_p (TREE_TYPE (fun), fun))
> +    {
> +      tree type = build_pointer_type (TREE_TYPE (fun));
> +      rs6000_parm_needs_stack (args_so_far, type);
> +    }
> +
> +  FOREACH_FUNCTION_ARGS (fun, arg_type, args_iter)
> +    if (rs6000_parm_needs_stack (args_so_far, arg_type))
> +      return true;
> +
> +  return false;
> +}
> +
> +/* Return the size of the REG_PARM_STACK_SPACE are for FUN.  This is
> +   usually a constant depending on the ABI.  However, in the ELFv2 ABI
> +   the register parameter area is optional when calling a function that
> +   has a prototype is scope, has no variable argument list, and passes
> +   all parameters in registers.  */
> +
> +int
> +rs6000_reg_parm_stack_space (tree fun)
> +{
> +  int reg_parm_stack_space;
> +
> +  switch (DEFAULT_ABI)
> +    {
> +    default:
> +      reg_parm_stack_space = 0;
> +      break;
> +
> +    case ABI_AIX:
> +    case ABI_DARWIN:
> +      reg_parm_stack_space = TARGET_64BIT ? 64 : 32;
> +      break;
> +
> +    case ABI_ELFv2:
> +      /* ??? Recomputing this every time is a bit expensive.  Is there
> +	 a place to cache this information?  */
> +      if (rs6000_function_parms_need_stack (fun))
> +	reg_parm_stack_space = TARGET_64BIT ? 64 : 32;
> +      else
> +	reg_parm_stack_space = 0;
> +      break;
> +    }
> +
> +  return reg_parm_stack_space;
> +}
> +
>  static void
>  rs6000_move_block_from_reg (int regno, rtx x, int nregs)
>  {
> @@ -10235,6 +10688,7 @@ rs6000_gimplify_va_arg (tree valist, tre
>  
>    if (((TARGET_MACHO
>          && rs6000_darwin64_abi)
> +       || DEFAULT_ABI == ABI_ELFv2
>         || (DEFAULT_ABI == ABI_AIX && !rs6000_compat_align_parm))
>        && integer_zerop (TYPE_SIZE (type)))
>      {
> @@ -16660,6 +17114,7 @@ rs6000_output_function_entry (FILE *file
>  	    ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "L.");
>  	  break;
>  
> +	case ABI_ELFv2:
>  	case ABI_V4:
>  	case ABI_DARWIN:
>  	  break;
> @@ -19645,7 +20100,7 @@ rs6000_savres_strategy (rs6000_stack_t *
>      }
>    else
>      {
> -      gcc_checking_assert (DEFAULT_ABI == ABI_AIX);
> +      gcc_checking_assert (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2);
>        if (info->first_fp_reg_save > 61)
>  	strategy |= SAVE_INLINE_FPRS | REST_INLINE_FPRS;
>        strategy |= SAVE_INLINE_GPRS | REST_INLINE_GPRS;
> @@ -19656,7 +20111,8 @@ rs6000_savres_strategy (rs6000_stack_t *
>       by the static chain.  It would require too much fiddling and the
>       static chain is rarely used anyway.  FPRs are saved w.r.t the stack
>       pointer on Darwin, and AIX uses r1 or r12.  */
> -  if (using_static_chain_p && DEFAULT_ABI != ABI_AIX)
> +  if (using_static_chain_p
> +      && (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_DARWIN))
>      strategy |= ((DEFAULT_ABI == ABI_DARWIN ? 0 : SAVE_INLINE_FPRS)
>  		 | SAVE_INLINE_GPRS
>  		 | SAVE_INLINE_VRS | REST_INLINE_VRS);
> @@ -19789,6 +20245,34 @@ rs6000_savres_strategy (rs6000_stack_t *
>     The required alignment for AIX configurations is two words (i.e., 8
>     or 16 bytes).
>  
> +   The ELFv2 ABI is a variant of the AIX ABI.  Stack frames look like:
> +
> +	SP---->	+---------------------------------------+
> +		| Back chain to caller			|  0
> +		+---------------------------------------+
> +		| Save area for CR			|  8
> +		+---------------------------------------+
> +		| Saved LR				|  16
> +		+---------------------------------------+
> +		| Saved TOC pointer			|  24
> +		+---------------------------------------+
> +		| Parameter save area (P)		|  32
> +		+---------------------------------------+
> +		| Alloca space (A)			|  32+P
> +		+---------------------------------------+
> +		| Local variable space (L)		|  32+P+A
> +		+---------------------------------------+
> +		| Save area for AltiVec registers (W)	|  32+P+A+L
> +		+---------------------------------------+
> +		| AltiVec alignment padding (Y)		|  32+P+A+L+W
> +		+---------------------------------------+
> +		| Save area for GP registers (G)	|  32+P+A+L+W+Y
> +		+---------------------------------------+
> +		| Save area for FP registers (F)	|  32+P+A+L+W+Y+G
> +		+---------------------------------------+
> +	old SP->| back chain to caller's caller		|  32+P+A+L+W+Y+G+F
> +		+---------------------------------------+
> +
>  
>     V.4 stack frames look like:
>  
> @@ -19849,6 +20333,7 @@ rs6000_stack_info (void)
>    rs6000_stack_t *info_ptr = &stack_info;
>    int reg_size = TARGET_32BIT ? 4 : 8;
>    int ehrd_size;
> +  int ehcr_size;
>    int save_align;
>    int first_gp;
>    HOST_WIDE_INT non_fixed_size;
> @@ -19942,6 +20427,18 @@ rs6000_stack_info (void)
>    else
>      ehrd_size = 0;
>  
> +  /* In the ELFv2 ABI, we also need to allocate space for separate
> +     CR field save areas if the function calls __builtin_eh_return.  */
> +  if (DEFAULT_ABI == ABI_ELFv2 && crtl->calls_eh_return)
> +    {
> +      /* This hard-codes that we have three call-saved CR fields.  */
> +      ehcr_size = 3 * reg_size;
> +      /* We do *not* use the regular CR save mechanism.  */
> +      info_ptr->cr_save_p = 0;
> +    }
> +  else
> +    ehcr_size = 0;
> +
>    /* Determine various sizes.  */
>    info_ptr->reg_size     = reg_size;
>    info_ptr->fixed_size   = RS6000_SAVE_AREA;
> @@ -19981,6 +20478,7 @@ rs6000_stack_info (void)
>        gcc_unreachable ();
>  
>      case ABI_AIX:
> +    case ABI_ELFv2:
>      case ABI_DARWIN:
>        info_ptr->fp_save_offset   = - info_ptr->fp_size;
>        info_ptr->gp_save_offset   = info_ptr->fp_save_offset - info_ptr->gp_size;
> @@ -20010,6 +20508,8 @@ rs6000_stack_info (void)
>  	}
>        else
>  	info_ptr->ehrd_offset      = info_ptr->gp_save_offset - ehrd_size;
> +
> +      info_ptr->ehcr_offset      = info_ptr->ehrd_offset - ehcr_size;
>        info_ptr->cr_save_offset   = reg_size; /* first word when 64-bit.  */
>        info_ptr->lr_save_offset   = 2*reg_size;
>        break;
> @@ -20072,6 +20572,7 @@ rs6000_stack_info (void)
>  					 + info_ptr->spe_gp_size
>  					 + info_ptr->spe_padding_size
>  					 + ehrd_size
> +					 + ehcr_size
>  					 + info_ptr->cr_size
>  					 + info_ptr->vrsave_size,
>  					 save_align);
> @@ -20085,7 +20586,7 @@ rs6000_stack_info (void)
>  
>    /* Determine if we need to save the link register.  */
>    if (info_ptr->calls_p
> -      || (DEFAULT_ABI == ABI_AIX
> +      || ((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
>  	  && crtl->profile
>  	  && !TARGET_PROFILE_KERNEL)
>        || (DEFAULT_ABI == ABI_V4 && cfun->calls_alloca)
> @@ -20231,6 +20732,7 @@ debug_stack_info (rs6000_stack_t *info)
>      default:		 abi_string = "Unknown";	break;
>      case ABI_NONE:	 abi_string = "NONE";		break;
>      case ABI_AIX:	 abi_string = "AIX";		break;
> +    case ABI_ELFv2:	 abi_string = "ELFv2";		break;
>      case ABI_DARWIN:	 abi_string = "Darwin";		break;
>      case ABI_V4:	 abi_string = "V.4";		break;
>      }
> @@ -20352,7 +20854,8 @@ rs6000_return_addr (int count, rtx frame
>    /* Currently we don't optimize very well between prolog and body
>       code and for PIC code the code can be actually quite bad, so
>       don't try to be too clever here.  */
> -  if (count != 0 || (DEFAULT_ABI != ABI_AIX && flag_pic))
> +  if (count != 0
> +      || ((DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_DARWIN) && flag_pic))
>      {
>        cfun->machine->ra_needs_full_frame = 1;
>  
> @@ -20411,13 +20914,13 @@ rs6000_function_ok_for_sibcall (tree dec
>  	return false;
>      }
>  
> -  /* Under the AIX ABI we can't allow calls to non-local functions,
> -     because the callee may have a different TOC pointer to the
> -     caller and there's no way to ensure we restore the TOC when we
> -     return.  With the secure-plt SYSV ABI we can't make non-local
> +  /* Under the AIX or ELFv2 ABIs we can't allow calls to non-local
> +     functions, because the callee may have a different TOC pointer to
> +     the caller and there's no way to ensure we restore the TOC when
> +     we return.  With the secure-plt SYSV ABI we can't make non-local
>       calls when -fpic/PIC because the plt call stubs use r30.  */
>    if (DEFAULT_ABI == ABI_DARWIN
> -      || (DEFAULT_ABI == ABI_AIX
> +      || ((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
>  	  && decl
>  	  && !DECL_EXTERNAL (decl)
>  	  && (*targetm.binds_local_p) (decl))
> @@ -20518,7 +21021,7 @@ rs6000_emit_load_toc_table (int fromprol
>    rtx dest;
>    dest = gen_rtx_REG (Pmode, RS6000_PIC_OFFSET_TABLE_REGNUM);
>  
> -  if (TARGET_ELF && TARGET_SECURE_PLT && DEFAULT_ABI != ABI_AIX && flag_pic)
> +  if (TARGET_ELF && TARGET_SECURE_PLT && DEFAULT_ABI == ABI_V4 && flag_pic)
>      {
>        char buf[30];
>        rtx lab, tmp1, tmp2, got;
> @@ -20546,7 +21049,7 @@ rs6000_emit_load_toc_table (int fromprol
>        emit_insn (gen_load_toc_v4_pic_si ());
>        emit_move_insn (dest, gen_rtx_REG (Pmode, LR_REGNO));
>      }
> -  else if (TARGET_ELF && DEFAULT_ABI != ABI_AIX && flag_pic == 2)
> +  else if (TARGET_ELF && DEFAULT_ABI == ABI_V4 && flag_pic == 2)
>      {
>        char buf[30];
>        rtx temp0 = (fromprolog
> @@ -20594,7 +21097,7 @@ rs6000_emit_load_toc_table (int fromprol
>      }
>    else
>      {
> -      gcc_assert (DEFAULT_ABI == ABI_AIX);
> +      gcc_assert (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2);
>  
>        if (TARGET_32BIT)
>  	emit_insn (gen_load_toc_aix_si (dest));
> @@ -21318,7 +21821,7 @@ rs6000_savres_routine_name (rs6000_stack
>        if ((sel & SAVRES_LR))
>  	suffix = "_x";
>      }
> -  else if (DEFAULT_ABI == ABI_AIX)
> +  else if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
>      {
>  #if !defined (POWERPC_LINUX) && !defined (POWERPC_FREEBSD)
>        /* No out-of-line save/restore routines for GPRs on AIX.  */
> @@ -21459,7 +21962,7 @@ rs6000_emit_stack_reset (rs6000_stack_t
>  static inline unsigned
>  ptr_regno_for_savres (int sel)
>  {
> -  if (DEFAULT_ABI == ABI_AIX)
> +  if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
>      return (sel & SAVRES_REG) == SAVRES_FPR || (sel & SAVRES_LR) ? 1 : 12;
>    return DEFAULT_ABI == ABI_DARWIN && (sel & SAVRES_REG) == SAVRES_FPR ? 1 : 11;
>  }
> @@ -21544,6 +22047,43 @@ rs6000_emit_savres_rtx (rs6000_stack_t *
>    return insn;
>  }
>  
> +/* Emit code to store CR fields that need to be saved into REG.  */
> +
> +static void
> +rs6000_emit_move_from_cr (rtx reg)
> +{
> +  /* Only the ELFv2 ABI allows storing only selected fields.  */
> +  if (DEFAULT_ABI == ABI_ELFv2 && TARGET_MFCRF)
> +    {
> +      int i, cr_reg[8], count = 0;
> +
> +      /* Collect CR fields that must be saved.  */
> +      for (i = 0; i < 8; i++)
> +	if (save_reg_p (CR0_REGNO + i))
> +	  cr_reg[count++] = i;
> +
> +      /* If it's just a single one, use mfcrf.  */
> +      if (count == 1)
> +	{
> +	  rtvec p = rtvec_alloc (1);
> +	  rtvec r = rtvec_alloc (2);
> +	  RTVEC_ELT (r, 0) = gen_rtx_REG (CCmode, CR0_REGNO + cr_reg[0]);
> +	  RTVEC_ELT (r, 1) = GEN_INT (1 << (7 - cr_reg[0]));
> +	  RTVEC_ELT (p, 0)
> +	    = gen_rtx_SET (VOIDmode, reg,
> +			   gen_rtx_UNSPEC (SImode, r, UNSPEC_MOVESI_FROM_CR));
> +
> +	  emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
> +	  return;
> +	}
> +
> +      /* ??? It might be better to handle count == 2 / 3 cases here
> +	 as well, using logical operations to combine the values.  */
> +    }
> +
> +  emit_insn (gen_movesi_from_cr (reg));
> +}
> +
>  /* Determine whether the gp REG is really used.  */
>  
>  static bool
> @@ -21609,6 +22149,17 @@ rs6000_emit_prologue (void)
>  #define NOT_INUSE(R) do {} while (0)
>  #endif
>  
> +  if (DEFAULT_ABI == ABI_ELFv2)
> +    {
> +      cfun->machine->r2_setup_needed = df_regs_ever_live_p (TOC_REGNUM);
> +
> +      /* With -mminimal-toc we may generate an extra use of r2 below.  */
> +      if (!TARGET_SINGLE_PIC_BASE
> +	  && TARGET_TOC && TARGET_MINIMAL_TOC && get_pool_size () != 0)
> +	cfun->machine->r2_setup_needed = true;
> +    }
> +
> +
>    if (flag_stack_usage_info)
>      current_function_static_stack_size = info->total_size;
>  
> @@ -21815,7 +22366,7 @@ rs6000_emit_prologue (void)
>  
>    /* If we need to save CR, put it into r12 or r11.  Choose r12 except when
>       r12 will be needed by out-of-line gpr restore.  */
> -  cr_save_regno = (DEFAULT_ABI == ABI_AIX
> +  cr_save_regno = ((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
>  		   && !(strategy & (SAVE_INLINE_GPRS
>  				    | SAVE_NOINLINE_GPRS_SAVES_LR))
>  		   ? 11 : 12);
> @@ -21824,21 +22375,9 @@ rs6000_emit_prologue (void)
>        && REGNO (frame_reg_rtx) != cr_save_regno
>        && !(using_static_chain_p && cr_save_regno == 11))
>      {
> -      rtx set;
> -
>        cr_save_rtx = gen_rtx_REG (SImode, cr_save_regno);
>        START_USE (cr_save_regno);
> -      insn = emit_insn (gen_movesi_from_cr (cr_save_rtx));
> -      RTX_FRAME_RELATED_P (insn) = 1;
> -      /* Now, there's no way that dwarf2out_frame_debug_expr is going
> -	 to understand '(unspec:SI [(reg:CC 68) ...] UNSPEC_MOVESI_FROM_CR)'.
> -	 But that's OK.  All we have to do is specify that _one_ condition
> -	 code register is saved in this stack slot.  The thrower's epilogue
> -	 will then restore all the call-saved registers.
> -	 We use CR2_REGNO (70) to be compatible with gcc-2.95 on Linux.  */
> -      set = gen_rtx_SET (VOIDmode, cr_save_rtx,
> -			 gen_rtx_REG (SImode, CR2_REGNO));
> -      add_reg_note (insn, REG_FRAME_RELATED_EXPR, set);
> +      rs6000_emit_move_from_cr (cr_save_rtx);
>      }
>  
>    /* Do any required saving of fpr's.  If only one or two to save, do
> @@ -22090,7 +22629,8 @@ rs6000_emit_prologue (void)
>  	 be updated if we arrived at this function via a plt call or
>  	 toc adjusting stub.  */
>        emit_move_insn (tmp_reg_si, gen_rtx_MEM (SImode, tmp_reg));
> -      toc_restore_insn = TARGET_32BIT ? 0x80410014 : 0xE8410028;
> +      toc_restore_insn = ((TARGET_32BIT ? 0x80410000 : 0xE8410000)
> +			  + RS6000_TOC_SAVE_SLOT);
>        hi = gen_int_mode (toc_restore_insn & ~0xffff, SImode);
>        emit_insn (gen_xorsi3 (tmp_reg_si, tmp_reg_si, hi));
>        compare_result = gen_rtx_REG (CCUNSmode, CR0_REGNO);
> @@ -22109,7 +22649,7 @@ rs6000_emit_prologue (void)
>        LABEL_NUSES (toc_save_done) += 1;
>  
>        save_insn = emit_frame_save (frame_reg_rtx, reg_mode,
> -				   TOC_REGNUM, frame_off + 5 * reg_size,
> +				   TOC_REGNUM, frame_off + RS6000_TOC_SAVE_SLOT,
>  				   sp_off - frame_off);
>  
>        emit_label (toc_save_done);
> @@ -22149,26 +22689,121 @@ rs6000_emit_prologue (void)
>        rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
>  			       GEN_INT (info->cr_save_offset + frame_off));
>        rtx mem = gen_frame_mem (SImode, addr);
> -      /* See the large comment above about why CR2_REGNO is used.  */
> -      rtx magic_eh_cr_reg = gen_rtx_REG (SImode, CR2_REGNO);
>  
>        /* If we didn't copy cr before, do so now using r0.  */
>        if (cr_save_rtx == NULL_RTX)
>  	{
> -	  rtx set;
> -
>  	  START_USE (0);
>  	  cr_save_rtx = gen_rtx_REG (SImode, 0);
> -	  insn = emit_insn (gen_movesi_from_cr (cr_save_rtx));
> -	  RTX_FRAME_RELATED_P (insn) = 1;
> -	  set = gen_rtx_SET (VOIDmode, cr_save_rtx, magic_eh_cr_reg);
> -	  add_reg_note (insn, REG_FRAME_RELATED_EXPR, set);
> +	  rs6000_emit_move_from_cr (cr_save_rtx);
>  	}
> -      insn = emit_move_insn (mem, cr_save_rtx);
> +
> +      /* Saving CR requires a two-instruction sequence: one instruction
> +	 to move the CR to a general-purpose register, and a second
> +	 instruction that stores the GPR to memory.
> +
> +	 We do not emit any DWARF CFI records for the first of these,
> +	 because we cannot properly represent the fact that CR is saved in
> +	 a register.  One reason is that we cannot express that multiple
> +	 CR fields are saved; another reason is that on 64-bit, the size
> +	 of the CR register in DWARF (4 bytes) differs from the size of
> +	 a general-purpose register.
> +
> +	 This means if any intervening instruction were to clobber one of
> +	 the call-saved CR fields, we'd have incorrect CFI.  To prevent
> +	 this from happening, we mark the store to memory as a use of
> +	 those CR fields, which prevents any such instruction from being
> +	 scheduled in between the two instructions.  */
> +      rtx crsave_v[9];
> +      int n_crsave = 0;
> +      int i;
> +
> +      crsave_v[n_crsave++] = gen_rtx_SET (VOIDmode, mem, cr_save_rtx);
> +      for (i = 0; i < 8; i++)
> +	if (save_reg_p (CR0_REGNO + i))
> +	  crsave_v[n_crsave++]
> +	    = gen_rtx_USE (VOIDmode, gen_rtx_REG (CCmode, CR0_REGNO + i));
> +
> +      insn = emit_insn (gen_rtx_PARALLEL (VOIDmode,
> +					  gen_rtvec_v (n_crsave, crsave_v)));
>        END_USE (REGNO (cr_save_rtx));
>  
> -      rs6000_frame_related (insn, frame_reg_rtx, sp_off - frame_off,
> -			    NULL_RTX, NULL_RTX);
> +      /* Now, there's no way that dwarf2out_frame_debug_expr is going to
> +	 understand '(unspec:SI [(reg:CC 68) ...] UNSPEC_MOVESI_FROM_CR)',
> +	 so we need to construct a frame expression manually.  */
> +      RTX_FRAME_RELATED_P (insn) = 1;
> +
> +      /* Update address to be stack-pointer relative, like
> +	 rs6000_frame_related would do.  */
> +      addr = gen_rtx_PLUS (Pmode, gen_rtx_REG (Pmode, STACK_POINTER_REGNUM),
> +			   GEN_INT (info->cr_save_offset + sp_off));
> +      mem = gen_frame_mem (SImode, addr);
> +
> +      if (DEFAULT_ABI == ABI_ELFv2)
> +	{
> +	  /* In the ELFv2 ABI we generate separate CFI records for each
> +	     CR field that was actually saved.  They all point to the
> +	     same 32-bit stack slot.  */
> +	  rtx crframe[8];
> +	  int n_crframe = 0;
> +
> +	  for (i = 0; i < 8; i++)
> +	    if (save_reg_p (CR0_REGNO + i))
> +	      {
> +		crframe[n_crframe]
> +		  = gen_rtx_SET (VOIDmode, mem,
> +				 gen_rtx_REG (SImode, CR0_REGNO + i));
> +
> +		RTX_FRAME_RELATED_P (crframe[n_crframe]) = 1;
> +		n_crframe++;
> +	     }
> +
> +	  add_reg_note (insn, REG_FRAME_RELATED_EXPR,
> +			gen_rtx_PARALLEL (VOIDmode,
> +					  gen_rtvec_v (n_crframe, crframe)));
> +	}
> +      else
> +	{
> +	  /* In other ABIs, by convention, we use a single CR regnum to
> +	     represent the fact that all call-saved CR fields are saved.
> +	     We use CR2_REGNO to be compatible with gcc-2.95 on Linux.  */
> +	  rtx set = gen_rtx_SET (VOIDmode, mem,
> +				 gen_rtx_REG (SImode, CR2_REGNO));
> +	  add_reg_note (insn, REG_FRAME_RELATED_EXPR, set);
> +	}
> +    }
> +
> +  /* In the ELFv2 ABI we need to save all call-saved CR fields into
> +     *separate* slots if the routine calls __builtin_eh_return, so
> +     that they can be independently restored by the unwinder.  */
> +  if (DEFAULT_ABI == ABI_ELFv2 && crtl->calls_eh_return)
> +    {
> +      int i, cr_off = info->ehcr_offset;
> +      rtx crsave;
> +
> +      /* ??? We might get better performance by using multiple mfocrf
> +	 instructions.  */
> +      crsave = gen_rtx_REG (SImode, 0);
> +      emit_insn (gen_movesi_from_cr (crsave));
> +
> +      for (i = 0; i < 8; i++)
> +	if (!call_used_regs[CR0_REGNO + i])
> +	  {
> +	    rtvec p = rtvec_alloc (2);
> +	    RTVEC_ELT (p, 0)
> +	      = gen_frame_store (crsave, frame_reg_rtx, cr_off + frame_off);
> +	    RTVEC_ELT (p, 1)
> +	      = gen_rtx_USE (VOIDmode, gen_rtx_REG (CCmode, CR0_REGNO + i));
> +
> +	    insn = emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
> +
> +	    RTX_FRAME_RELATED_P (insn) = 1;
> +	    add_reg_note (insn, REG_FRAME_RELATED_EXPR,
> +			  gen_frame_store (gen_rtx_REG (SImode, CR0_REGNO + i),
> +					   sp_reg_rtx, cr_off + sp_off));
> +
> +	    cr_off += reg_size;
> +	  }
>      }
>  
>    /* Update stack and set back pointer unless this is V.4,
> @@ -22317,7 +22952,8 @@ rs6000_emit_prologue (void)
>  	 be using r12 as frame_reg_rtx and r11 as the static chain
>  	 pointer for nested functions.  */
>        save_regno = 12;
> -      if (DEFAULT_ABI == ABI_AIX && !using_static_chain_p)
> +      if ((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
> +	  && !using_static_chain_p)
>  	save_regno = 11;
>        else if (REGNO (frame_reg_rtx) == 12)
>  	{
> @@ -22356,7 +22992,7 @@ rs6000_emit_prologue (void)
>  	 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
> -				      && DEFAULT_ABI != ABI_AIX
> +				      && DEFAULT_ABI == ABI_V4
>  				      && flag_pic
>  				      && ! info->lr_save_p
>  				      && EDGE_COUNT (EXIT_BLOCK_PTR->preds) > 0);
> @@ -22418,7 +23054,7 @@ rs6000_emit_prologue (void)
>    if (rs6000_save_toc_in_prologue_p ())
>      {
>        rtx reg = gen_rtx_REG (reg_mode, TOC_REGNUM);
> -      emit_insn (gen_frame_store (reg, sp_reg_rtx, 5 * reg_size));
> +      emit_insn (gen_frame_store (reg, sp_reg_rtx, RS6000_TOC_SAVE_SLOT));
>      }
>  }
>  
> @@ -22459,6 +23095,49 @@ rs6000_output_function_prologue (FILE *f
>  	}
>      }
>  
> +  /* ELFv2 ABI r2 setup code and local entry point.  This must follow
> +     immediately after the global entry point label.  */
> +  if (DEFAULT_ABI == ABI_ELFv2 && cfun->machine->r2_setup_needed)
> +    {
> +      const char *name = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
> +
> +      fprintf (file, "0:\taddis 2,12,.TOC.-0b@ha\n");
> +      fprintf (file, "\taddi 2,2,.TOC.-0b@l\n");
> +
> +      fputs ("\t.localentry\t", file);
> +      assemble_name (file, name);
> +      fputs (",.-", file);
> +      assemble_name (file, name);
> +      fputs ("\n", file);
> +    }
> +
> +  /* Output -mprofile-kernel code.  This needs to be done here instead of
> +     in output_function_profile since it must go after the ELFv2 ABI
> +     local entry point.  */
> +  if (TARGET_PROFILE_KERNEL)
> +    {
> +      gcc_assert (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2);
> +      gcc_assert (!TARGET_32BIT);
> +
> +      asm_fprintf (file, "\tmflr %s\n", reg_names[0]);
> +      asm_fprintf (file, "\tstd %s,16(%s)\n", reg_names[0], reg_names[1]);
> +
> +      /* In the ELFv2 ABI we have no compiler stack word.  It must be
> +	 the resposibility of _mcount to preserve the static chain
> +	 register if required.  */
> +      if (DEFAULT_ABI != ABI_ELFv2
> +	  && cfun->static_chain_decl != NULL)
> +	{
> +	  asm_fprintf (file, "\tstd %s,24(%s)\n",
> +		       reg_names[STATIC_CHAIN_REGNUM], reg_names[1]);
> +	  fprintf (file, "\tbl %s\n", RS6000_MCOUNT);
> +	  asm_fprintf (file, "\tld %s,24(%s)\n",
> +		       reg_names[STATIC_CHAIN_REGNUM], reg_names[1]);
> +	}
> +      else
> +	fprintf (file, "\tbl %s\n", RS6000_MCOUNT);
> +    }
> +
>    rs6000_pic_labelno++;
>  }
>  
> @@ -22511,6 +23190,7 @@ restore_saved_cr (rtx reg, int using_mfc
>  
>    if (using_mfcr_multiple && count > 1)
>      {
> +      rtx insn;
>        rtvec p;
>        int ndx;
>  
> @@ -22528,16 +23208,43 @@ restore_saved_cr (rtx reg, int using_mfc
>  			   gen_rtx_UNSPEC (CCmode, r, UNSPEC_MOVESI_TO_CR));
>  	    ndx++;
>  	  }
> -      emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
> +      insn = emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
>        gcc_assert (ndx == count);
> +
> +      /* For the ELFv2 ABI we generate a CFA_RESTORE for each
> +	 CR field separately.  */
> +      if (!exit_func && DEFAULT_ABI == ABI_ELFv2 && flag_shrink_wrap)
> +	{
> +	  for (i = 0; i < 8; i++)
> +	    if (save_reg_p (CR0_REGNO + i))
> +	      add_reg_note (insn, REG_CFA_RESTORE,
> +			    gen_rtx_REG (SImode, CR0_REGNO + i));
> +
> +	  RTX_FRAME_RELATED_P (insn) = 1;
> +	}
>      }
>    else
>      for (i = 0; i < 8; i++)
>        if (save_reg_p (CR0_REGNO + i))
> -	emit_insn (gen_movsi_to_cr_one (gen_rtx_REG (CCmode, CR0_REGNO + i),
> -					reg));
> +	{
> +	  rtx insn = emit_insn (gen_movsi_to_cr_one
> +				 (gen_rtx_REG (CCmode, CR0_REGNO + i), reg));
> +
> +	  /* For the ELFv2 ABI we generate a CFA_RESTORE for each
> +	     CR field separately, attached to the insn that in fact
> +	     restores this particular CR field.  */
> +	  if (!exit_func && DEFAULT_ABI == ABI_ELFv2 && flag_shrink_wrap)
> +	    {
> +	      add_reg_note (insn, REG_CFA_RESTORE,
> +			    gen_rtx_REG (SImode, CR0_REGNO + i));
> +
> +	      RTX_FRAME_RELATED_P (insn) = 1;
> +	    }
> +	}
>  
> -  if (!exit_func && (DEFAULT_ABI == ABI_V4 || flag_shrink_wrap))
> +  /* For other ABIs, we just generate a single CFA_RESTORE for CR2.  */
> +  if (!exit_func && DEFAULT_ABI != ABI_ELFv2
> +      && (DEFAULT_ABI == ABI_V4 || flag_shrink_wrap))
>      {
>        rtx insn = get_last_insn ();
>        rtx cr = gen_rtx_REG (SImode, CR2_REGNO);
> @@ -22578,10 +23285,22 @@ restore_saved_lr (int regno, bool exit_f
>  static rtx
>  add_crlr_cfa_restore (const rs6000_stack_t *info, rtx cfa_restores)
>  {
> -  if (info->cr_save_p)
> +  if (DEFAULT_ABI == ABI_ELFv2)
> +    {
> +      int i;
> +      for (i = 0; i < 8; i++)
> +	if (save_reg_p (CR0_REGNO + i))
> +	  {
> +	    rtx cr = gen_rtx_REG (SImode, CR0_REGNO + i);
> +	    cfa_restores = alloc_reg_note (REG_CFA_RESTORE, cr,
> +					   cfa_restores);
> +	  }
> +    }
> +  else if (info->cr_save_p)
>      cfa_restores = alloc_reg_note (REG_CFA_RESTORE,
>  				   gen_rtx_REG (SImode, CR2_REGNO),
>  				   cfa_restores);
> +
>    if (info->lr_save_p)
>      cfa_restores = alloc_reg_note (REG_CFA_RESTORE,
>  				   gen_rtx_REG (Pmode, LR_REGNO),
> @@ -23079,6 +23798,35 @@ rs6000_emit_epilogue (int sibcall)
>  	       || (!restoring_GPRs_inline
>  		   && info->first_fp_reg_save == 64));
>  
> +  /* In the ELFv2 ABI we need to restore all call-saved CR fields from
> +     *separate* slots if the routine calls __builtin_eh_return, so
> +     that they can be independently restored by the unwinder.  */
> +  if (DEFAULT_ABI == ABI_ELFv2 && crtl->calls_eh_return)
> +    {
> +      int i, cr_off = info->ehcr_offset;
> +
> +      for (i = 0; i < 8; i++)
> +	if (!call_used_regs[CR0_REGNO + i])
> +	  {
> +	    rtx reg = gen_rtx_REG (SImode, 0);
> +	    emit_insn (gen_frame_load (reg, frame_reg_rtx,
> +				       cr_off + frame_off));
> +
> +	    insn = emit_insn (gen_movsi_to_cr_one
> +				(gen_rtx_REG (CCmode, CR0_REGNO + i), reg));
> +
> +	    if (!exit_func && flag_shrink_wrap)
> +	      {
> +		add_reg_note (insn, REG_CFA_RESTORE,
> +			      gen_rtx_REG (SImode, CR0_REGNO + i));
> +
> +		RTX_FRAME_RELATED_P (insn) = 1;
> +	      }
> +
> +	    cr_off += reg_size;
> +	  }
> +    }
> +
>    /* Get the old lr if we saved it.  If we are restoring registers
>       out-of-line, then the out-of-line routines can do this for us.  */
>    if (restore_lr && restoring_GPRs_inline)
> @@ -23122,7 +23870,7 @@ rs6000_emit_epilogue (int sibcall)
>  	{
>  	  rtx reg = gen_rtx_REG (reg_mode, 2);
>  	  emit_insn (gen_frame_load (reg, frame_reg_rtx,
> -				     frame_off + 5 * reg_size));
> +				     frame_off + RS6000_TOC_SAVE_SLOT));
>  	}
>  
>        for (i = 0; ; ++i)
> @@ -23408,6 +24156,7 @@ rs6000_emit_epilogue (int sibcall)
>        if (! restoring_FPRs_inline)
>  	{
>  	  int i;
> +	  int reg;
>  	  rtx sym;
>  
>  	  if (flag_shrink_wrap)
> @@ -23416,10 +24165,9 @@ rs6000_emit_epilogue (int sibcall)
>  	  sym = rs6000_savres_routine_sym (info,
>  					   SAVRES_FPR | (lr ? SAVRES_LR : 0));
>  	  RTVEC_ELT (p, 2) = gen_rtx_USE (VOIDmode, sym);
> -	  RTVEC_ELT (p, 3) = gen_rtx_USE (VOIDmode,
> -					  gen_rtx_REG (Pmode,
> -						       DEFAULT_ABI == ABI_AIX
> -						       ? 1 : 11));
> +	  reg = (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)? 1 : 11;
> +	  RTVEC_ELT (p, 3) = gen_rtx_USE (VOIDmode, gen_rtx_REG (Pmode, reg));
> +
>  	  for (i = 0; i < 64 - info->first_fp_reg_save; i++)
>  	    {
>  	      rtx reg = gen_rtx_REG (DFmode, info->first_fp_reg_save + i);
> @@ -23497,7 +24245,8 @@ rs6000_output_function_epilogue (FILE *f
>  
>       System V.4 Powerpc's (and the embedded ABI derived from it) use a
>       different traceback table.  */
> -  if (DEFAULT_ABI == ABI_AIX && ! flag_inhibit_size_directive
> +  if ((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
> +      && ! flag_inhibit_size_directive
>        && rs6000_traceback != traceback_none && !cfun->is_thunk)
>      {
>        const char *fname = NULL;
> @@ -23825,6 +24574,12 @@ rs6000_output_mi_thunk (FILE *file, tree
>    SIBLING_CALL_P (insn) = 1;
>    emit_barrier ();
>  
> +  /* Ensure we have a global entry point for the thunk.   ??? We could
> +     avoid that if the target routine doesn't need a global entry point,
> +     but we do not know whether this is the case at this point.  */
> +  if (DEFAULT_ABI == ABI_ELFv2)
> +    cfun->machine->r2_setup_needed = true;
> +
>    /* Run just enough of rest_of_compilation to get the insns emitted.
>       There's not really enough bulk here to make other passes such as
>       instruction scheduling worth while.  Note that use_thunk calls
> @@ -24521,7 +25276,7 @@ output_profile_hook (int labelno ATTRIBU
>    if (TARGET_PROFILE_KERNEL)
>      return;
>  
> -  if (DEFAULT_ABI == ABI_AIX)
> +  if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
>      {
>  #ifndef NO_PROFILE_COUNTERS
>  # define NO_PROFILE_COUNTERS 0
> @@ -24665,29 +25420,9 @@ output_function_profiler (FILE *file, in
>        break;
>  
>      case ABI_AIX:
> +    case ABI_ELFv2:
>      case ABI_DARWIN:
> -      if (!TARGET_PROFILE_KERNEL)
> -	{
> -	  /* Don't do anything, done in output_profile_hook ().  */
> -	}
> -      else
> -	{
> -	  gcc_assert (!TARGET_32BIT);
> -
> -	  asm_fprintf (file, "\tmflr %s\n", reg_names[0]);
> -	  asm_fprintf (file, "\tstd %s,16(%s)\n", reg_names[0], reg_names[1]);
> -
> -	  if (cfun->static_chain_decl != NULL)
> -	    {
> -	      asm_fprintf (file, "\tstd %s,24(%s)\n",
> -			   reg_names[STATIC_CHAIN_REGNUM], reg_names[1]);
> -	      fprintf (file, "\tbl %s\n", RS6000_MCOUNT);
> -	      asm_fprintf (file, "\tld %s,24(%s)\n",
> -			   reg_names[STATIC_CHAIN_REGNUM], reg_names[1]);
> -	    }
> -	  else
> -	    fprintf (file, "\tbl %s\n", RS6000_MCOUNT);
> -	}
> +      /* Don't do anything, done in output_profile_hook ().  */
>        break;
>      }
>  }
> @@ -26623,6 +27358,11 @@ rs6000_trampoline_size (void)
>        ret = (TARGET_32BIT) ? 12 : 24;
>        break;
>  
> +    case ABI_ELFv2:
> +      gcc_assert (!TARGET_32BIT);
> +      ret = 32;
> +      break;
> +
>      case ABI_DARWIN:
>      case ABI_V4:
>        ret = (TARGET_32BIT) ? 40 : 48;
> @@ -26678,6 +27418,7 @@ rs6000_trampoline_init (rtx m_tramp, tre
>        break;
>  
>      /* Under V.4/eabi/darwin, __trampoline_setup does the real work.  */
> +    case ABI_ELFv2:
>      case ABI_DARWIN:
>      case ABI_V4:
>        emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__trampoline_setup"),
> @@ -26972,7 +27713,7 @@ rs6000_ms_bitfield_layout_p (const_tree
>  static void
>  rs6000_elf_output_toc_section_asm_op (const void *data ATTRIBUTE_UNUSED)
>  {
> -  if (DEFAULT_ABI == ABI_AIX
> +  if ((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
>        && TARGET_MINIMAL_TOC
>        && !TARGET_RELOCATABLE)
>      {
> @@ -26993,7 +27734,8 @@ rs6000_elf_output_toc_section_asm_op (co
>        else
>  	fprintf (asm_out_file, "%s\n", MINIMAL_TOC_SECTION_ASM_OP);
>      }
> -  else if (DEFAULT_ABI == ABI_AIX && !TARGET_RELOCATABLE)
> +  else if ((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
> +	   && !TARGET_RELOCATABLE)
>      fprintf (asm_out_file, "%s\n", TOC_SECTION_ASM_OP);
>    else
>      {
> @@ -27543,7 +28285,7 @@ rs6000_elf_reloc_rw_mask (void)
>  {
>    if (flag_pic)
>      return 3;
> -  else if (DEFAULT_ABI == ABI_AIX)
> +  else if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
>      return 2;
>    else
>      return 0;
> @@ -27619,7 +28361,7 @@ rs6000_elf_asm_out_destructor (rtx symbo
>  void
>  rs6000_elf_declare_function_name (FILE *file, const char *name, tree decl)
>  {
> -  if (TARGET_64BIT)
> +  if (TARGET_64BIT && DEFAULT_ABI != ABI_ELFv2)
>      {
>        fputs ("\t.section\t\".opd\",\"aw\"\n\t.align 3\n", file);
>        ASM_OUTPUT_LABEL (file, name);
> @@ -27685,8 +28427,7 @@ rs6000_elf_declare_function_name (FILE *
>        fprintf (file, "%s:\n", desc_name);
>        fprintf (file, "\t.long %s\n", orig_name);
>        fputs ("\t.long _GLOBAL_OFFSET_TABLE_\n", file);
> -      if (DEFAULT_ABI == ABI_AIX)
> -	fputs ("\t.long 0\n", file);
> +      fputs ("\t.long 0\n", file);
>        fprintf (file, "\t.previous\n");
>      }
>    ASM_OUTPUT_LABEL (file, name);
> @@ -27715,7 +28456,7 @@ rs6000_elf_file_end (void)
>      }
>  #endif
>  #if defined (POWERPC_LINUX) || defined (POWERPC_FREEBSD)
> -  if (TARGET_32BIT)
> +  if (TARGET_32BIT || DEFAULT_ABI == ABI_ELFv2)
>      file_end_indicate_exec_stack ();
>  #endif
>  }
> @@ -29505,6 +30246,8 @@ rs6000_function_value (const_tree valtyp
>  {
>    enum machine_mode mode;
>    unsigned int regno;
> +  enum machine_mode elt_mode;
> +  int n_elts;
>  
>    /* Special handling for structs in darwin64.  */
>    if (TARGET_MACHO 
> @@ -29524,6 +30267,36 @@ rs6000_function_value (const_tree valtyp
>        /* Otherwise fall through to standard ABI rules.  */
>      }
>  
> +  /* The ELFv2 ABI returns homogeneous VFP aggregates in registers.  */
> +  if (rs6000_discover_homogeneous_aggregate (TYPE_MODE (valtype), valtype,
> +					     &elt_mode, &n_elts))
> +    {
> +      int first_reg, n_regs, i;
> +      rtx par;
> +
> +      if (SCALAR_FLOAT_MODE_P (elt_mode))
> +	{
> +	  /* _Decimal128 must use even/odd register pairs.  */
> +	  first_reg = (elt_mode == TDmode) ? FP_ARG_RETURN + 1 : FP_ARG_RETURN;
> +	  n_regs = (GET_MODE_SIZE (elt_mode) + 7) >> 3;
> +	}
> +      else
> +	{
> +	  first_reg = ALTIVEC_ARG_RETURN;
> +	  n_regs = 1;
> +	}
> +
> +      par = gen_rtx_PARALLEL (TYPE_MODE (valtype), rtvec_alloc (n_elts));
> +      for (i = 0; i < n_elts; i++)
> +	{
> +	  rtx r = gen_rtx_REG (elt_mode, first_reg + i * n_regs);
> +	  rtx off = GEN_INT (i * GET_MODE_SIZE (elt_mode));
> +	  XVECEXP (par, 0, i) = gen_rtx_EXPR_LIST (VOIDmode, r, off);
> +	}
> +
> +      return par;
> +    }
> +
>    if (TARGET_32BIT && TARGET_POWERPC64 && TYPE_MODE (valtype) == DImode)
>      {
>        /* Long long return value need be split in -mpowerpc64, 32bit ABI.  */
> @@ -30697,118 +31470,149 @@ rs6000_legitimate_constant_p (enum machi
>  }
>  
>  
> -/* 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
> -   pointer to its TOC, and whose third word contains a value to place in the
> -   static chain register (r11).  Note that if we load the static chain, our
> -   "trampoline" need not have any executable code.  */
> +
> +/* Expand code to perform a call under the AIX or ELFv2 ABI.  */
>  
>  void
> -rs6000_call_indirect_aix (rtx value, rtx func_desc, rtx flag)
> +rs6000_call_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
>  {
> +  rtx toc_reg = gen_rtx_REG (Pmode, TOC_REGNUM);
> +  rtx toc_load = NULL_RTX;
> +  rtx toc_restore = NULL_RTX;
>    rtx func_addr;
> -  rtx toc_reg;
> -  rtx sc_reg;
> -  rtx stack_ptr;
> -  rtx stack_toc_offset;
> -  rtx stack_toc_mem;
> -  rtx func_toc_offset;
> -  rtx func_toc_mem;
> -  rtx func_sc_offset;
> -  rtx func_sc_mem;
> +  rtx abi_reg = NULL_RTX;
> +  rtx call[4];
> +  int n_call;
>    rtx insn;
> -  rtx (*call_func) (rtx, rtx, rtx, rtx);
> -  rtx (*call_value_func) (rtx, rtx, rtx, rtx, rtx);
>  
> -  stack_ptr = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
> -  toc_reg = gen_rtx_REG (Pmode, TOC_REGNUM);
> +  /* Handle longcall attributes.  */
> +  if (INTVAL (cookie) & CALL_LONG)
> +    func_desc = rs6000_longcall_ref (func_desc);
>  
> -  /* Load up address of the actual function.  */
> -  func_desc = force_reg (Pmode, func_desc);
> -  func_addr = gen_reg_rtx (Pmode);
> -  emit_move_insn (func_addr, gen_rtx_MEM (Pmode, func_desc));
> -
> -  if (TARGET_32BIT)
> +  /* Handle indirect calls.  */
> +  if (GET_CODE (func_desc) != SYMBOL_REF
> +      || (DEFAULT_ABI == ABI_AIX && !SYMBOL_REF_FUNCTION_P (func_desc)))
>      {
> +      /* Save the TOC into its reserved slot before the call,
> +	 and prepare to restore it after the call.  */
> +      rtx stack_ptr = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
> +      rtx stack_toc_offset = GEN_INT (RS6000_TOC_SAVE_SLOT);
> +      rtx stack_toc_mem = gen_frame_mem (Pmode,
> +					 gen_rtx_PLUS (Pmode, stack_ptr,
> +						       stack_toc_offset));
> +      toc_restore = gen_rtx_SET (VOIDmode, toc_reg, stack_toc_mem);
>  
> -      stack_toc_offset = GEN_INT (TOC_SAVE_OFFSET_32BIT);
> -      func_toc_offset = GEN_INT (AIX_FUNC_DESC_TOC_32BIT);
> -      func_sc_offset = GEN_INT (AIX_FUNC_DESC_SC_32BIT);
> -      if (TARGET_POINTERS_TO_NESTED_FUNCTIONS)
> -	{
> -	  call_func = gen_call_indirect_aix32bit;
> -	  call_value_func = gen_call_value_indirect_aix32bit;
> -	}
> +      /* Can we optimize saving the TOC in the prologue or
> +	 do we need to do it at every call?  */
> +      if (TARGET_SAVE_TOC_INDIRECT && !cfun->calls_alloca)
> +	cfun->machine->save_toc_in_prologue = true;
>        else
>  	{
> -	  call_func = gen_call_indirect_aix32bit_nor11;
> -	  call_value_func = gen_call_value_indirect_aix32bit_nor11;
> +	  MEM_VOLATILE_P (stack_toc_mem) = 1;
> +	  emit_move_insn (stack_toc_mem, toc_reg);
>  	}
> -    }
> -  else
> -    {
> -      stack_toc_offset = GEN_INT (TOC_SAVE_OFFSET_64BIT);
> -      func_toc_offset = GEN_INT (AIX_FUNC_DESC_TOC_64BIT);
> -      func_sc_offset = GEN_INT (AIX_FUNC_DESC_SC_64BIT);
> -      if (TARGET_POINTERS_TO_NESTED_FUNCTIONS)
> +
> +      if (DEFAULT_ABI == ABI_ELFv2)
>  	{
> -	  call_func = gen_call_indirect_aix64bit;
> -	  call_value_func = gen_call_value_indirect_aix64bit;
> +	  /* A function pointer in the ELFv2 ABI is just a plain address, but
> +	     the ABI requires it to be loaded into r12 before the call.  */
> +	  func_addr = gen_rtx_REG (Pmode, 12);
> +	  emit_move_insn (func_addr, func_desc);
> +	  abi_reg = func_addr;
>  	}
>        else
>  	{
> -	  call_func = gen_call_indirect_aix64bit_nor11;
> -	  call_value_func = gen_call_value_indirect_aix64bit_nor11;
> -	}
> -    }
> +	  /* 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 pointer to its TOC, and whose third word
> +	     contains a value to place in the static chain register (r11).
> +	     Note that if we load the static chain, our "trampoline" need
> +	     not have any executable code.  */
>  
> -  /* Reserved spot to store the TOC.  */
> -  stack_toc_mem = gen_frame_mem (Pmode,
> -				 gen_rtx_PLUS (Pmode,
> -					       stack_ptr,
> -					       stack_toc_offset));
> +	  /* Load up address of the actual function.  */
> +	  func_desc = force_reg (Pmode, func_desc);
> +	  func_addr = gen_reg_rtx (Pmode);
> +	  emit_move_insn (func_addr, gen_rtx_MEM (Pmode, func_desc));
>  
> -  gcc_assert (cfun);
> -  gcc_assert (cfun->machine);
> -
> -  /* Can we optimize saving the TOC in the prologue or do we need to do it at
> -     every call?  */
> -  if (TARGET_SAVE_TOC_INDIRECT && !cfun->calls_alloca)
> -    cfun->machine->save_toc_in_prologue = true;
> +	  /* Prepare to load the TOC of the called function.  Note that the
> +	     TOC load must happen immediately before the actual call so
> +	     that unwinding the TOC registers works correctly.  See the
> +	     comment in frob_update_context.  */
> +	  rtx func_toc_offset = GEN_INT (GET_MODE_SIZE (Pmode));
> +	  rtx func_toc_mem = gen_rtx_MEM (Pmode,
> +					  gen_rtx_PLUS (Pmode, func_desc,
> +							func_toc_offset));
> +	  toc_load = gen_rtx_USE (VOIDmode, func_toc_mem);
>  
> +	  /* If we have a static chain, load it up.  */
> +	  if (TARGET_POINTERS_TO_NESTED_FUNCTIONS)
> +	    {
> +	      rtx sc_reg = gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM);
> +	      rtx func_sc_offset = GEN_INT (2 * GET_MODE_SIZE (Pmode));
> +	      rtx func_sc_mem = gen_rtx_MEM (Pmode,
> +					     gen_rtx_PLUS (Pmode, func_desc,
> +							   func_sc_offset));
> +	      emit_move_insn (sc_reg, func_sc_mem);
> +	      abi_reg = sc_reg;
> +	    }
> +	}
> +    }
>    else
>      {
> -      MEM_VOLATILE_P (stack_toc_mem) = 1;
> -      emit_move_insn (stack_toc_mem, toc_reg);
> +      /* Direct calls use the TOC: for local calls, the callee will
> +	 assume the TOC register is set; for non-local calls, the
> +	 PLT stub needs the TOC register.  */
> +      abi_reg = toc_reg;
> +      func_addr = func_desc;
>      }
>  
> -  /* Calculate the address to load the TOC of the called function.  We don't
> -     actually load this until the split after reload.  */
> -  func_toc_mem = gen_rtx_MEM (Pmode,
> -			      gen_rtx_PLUS (Pmode,
> -					    func_desc,
> -					    func_toc_offset));
> +  /* Create the call.  */
> +  call[0] = gen_rtx_CALL (VOIDmode, gen_rtx_MEM (SImode, func_addr), flag);
> +  if (value != NULL_RTX)
> +    call[0] = gen_rtx_SET (VOIDmode, value, call[0]);
> +  n_call = 1;
> +
> +  if (toc_load)
> +    call[n_call++] = toc_load;
> +  if (toc_restore)
> +    call[n_call++] = toc_restore;
>  
> -  /* If we have a static chain, load it up.  */
> -  if (TARGET_POINTERS_TO_NESTED_FUNCTIONS)
> -    {
> -      func_sc_mem = gen_rtx_MEM (Pmode,
> -				 gen_rtx_PLUS (Pmode,
> -					       func_desc,
> -					       func_sc_offset));
> +  call[n_call++] = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, LR_REGNO));
>  
> -      sc_reg = gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM);
> -      emit_move_insn (sc_reg, func_sc_mem);
> -    }
> +  insn = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (n_call, call));
> +  insn = emit_call_insn (insn);
>  
> -  /* Create the call.  */
> -  if (value)
> -    insn = call_value_func (value, func_addr, flag, func_toc_mem,
> -			    stack_toc_mem);
> -  else
> -    insn = call_func (func_addr, flag, func_toc_mem, stack_toc_mem);
> +  /* Mention all registers defined by the ABI to hold information
> +     as uses in CALL_INSN_FUNCTION_USAGE.  */
> +  if (abi_reg)
> +    use_reg (&CALL_INSN_FUNCTION_USAGE (insn), abi_reg);
> +}
> +
> +/* Expand code to perform a sibling call under the AIX or ELFv2 ABI.  */
>  
> -  emit_call_insn (insn);
> +void
> +rs6000_sibcall_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
> +{
> +  rtx call[2];
> +  rtx insn;
> +
> +  gcc_assert (INTVAL (cookie) == 0);
> +
> +  /* Create the call.  */
> +  call[0] = gen_rtx_CALL (VOIDmode, gen_rtx_MEM (SImode, func_desc), flag);
> +  if (value != NULL_RTX)
> +    call[0] = gen_rtx_SET (VOIDmode, value, call[0]);
> +
> +  call[1] = simple_return_rtx;
> +
> +  insn = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (2, call));
> +  insn = emit_call_insn (insn);
> +
> +  /* Note use of the TOC register.  */
> +  use_reg (&CALL_INSN_FUNCTION_USAGE (insn), gen_rtx_REG (Pmode, TOC_REGNUM));
> +  /* We need to also mark a use of the link register since the function we
> +     sibling-call to will use it to return to our caller.  */
> +  use_reg (&CALL_INSN_FUNCTION_USAGE (insn), gen_rtx_REG (Pmode, LR_REGNO));
>  }
>  
>  /* Return whether we need to always update the saved TOC pointer when we update
> Index: gcc-4_8-test/gcc/config/rs6000/rs6000.md
> ===================================================================
> --- gcc-4_8-test.orig/gcc/config/rs6000/rs6000.md
> +++ gcc-4_8-test/gcc/config/rs6000/rs6000.md
> @@ -56,18 +56,6 @@
>     (TFHAR_REGNO			114)
>     (TFIAR_REGNO			115)
>     (TEXASR_REGNO		116)
> -
> -   ; ABI defined stack offsets for storing the TOC pointer with AIX calls.
> -   (TOC_SAVE_OFFSET_32BIT	20)
> -   (TOC_SAVE_OFFSET_64BIT	40)
> -
> -   ; Function TOC offset in the AIX function descriptor.
> -   (AIX_FUNC_DESC_TOC_32BIT	4)
> -   (AIX_FUNC_DESC_TOC_64BIT	8)
> -
> -   ; Static chain offset in the AIX function descriptor.
> -   (AIX_FUNC_DESC_SC_32BIT	8)
> -   (AIX_FUNC_DESC_SC_64BIT	16)
>    ])
>  
>  ;;
> @@ -10683,7 +10671,7 @@
>  	 	    (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
>  		   UNSPEC_TLSGD)
>     (clobber (reg:SI LR_REGNO))]
> -  "HAVE_AS_TLS && DEFAULT_ABI == ABI_AIX"
> +  "HAVE_AS_TLS && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)"
>  {
>    if (TARGET_CMODEL != CMODEL_SMALL)
>      return "addis %0,%1,%2@got@tlsgd@ha\;addi %0,%0,%2@got@tlsgd@l\;"
> @@ -10791,7 +10779,8 @@
>     (unspec:TLSmode [(match_operand:TLSmode 3 "rs6000_tls_symbol_ref" "")]
>  		   UNSPEC_TLSGD)
>     (clobber (reg:SI LR_REGNO))]
> -  "HAVE_AS_TLS && DEFAULT_ABI == ABI_AIX && TARGET_TLS_MARKERS"
> +  "HAVE_AS_TLS && TARGET_TLS_MARKERS
> +   && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)"
>    "bl %z1(%3@tlsgd)\;nop"
>    [(set_attr "type" "branch")
>     (set_attr "length" "8")])
> @@ -10823,7 +10812,7 @@
>     (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")]
>  		   UNSPEC_TLSLD)
>     (clobber (reg:SI LR_REGNO))]
> -  "HAVE_AS_TLS && DEFAULT_ABI == ABI_AIX"
> +  "HAVE_AS_TLS && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)"
>  {
>    if (TARGET_CMODEL != CMODEL_SMALL)
>      return "addis %0,%1,%&@got@tlsld@ha\;addi %0,%0,%&@got@tlsld@l\;"
> @@ -10924,7 +10913,8 @@
>  	      (match_operand 2 "" "g")))
>     (unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD)
>     (clobber (reg:SI LR_REGNO))]
> -  "HAVE_AS_TLS && DEFAULT_ABI == ABI_AIX && TARGET_TLS_MARKERS"
> +  "HAVE_AS_TLS && TARGET_TLS_MARKERS
> +   && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)"
>    "bl %z1(%&@tlsld)\;nop"
>    [(set_attr "type" "branch")
>     (set_attr "length" "8")])
> @@ -11293,7 +11283,7 @@
>    [(parallel [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
>  		   (unspec:SI [(const_int 0)] UNSPEC_TOC))
>  	      (use (reg:SI 2))])]
> -  "DEFAULT_ABI == ABI_AIX && TARGET_32BIT"
> +  "(DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2) && TARGET_32BIT"
>    "*
>  {
>    char buf[30];
> @@ -11308,7 +11298,7 @@
>    [(parallel [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
>  		   (unspec:DI [(const_int 0)] UNSPEC_TOC))
>  	      (use (reg:DI 2))])]
> -  "DEFAULT_ABI == ABI_AIX && TARGET_64BIT"
> +  "(DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2) && TARGET_64BIT"
>    "*
>  {
>    char buf[30];
> @@ -11338,7 +11328,7 @@
>    [(parallel [(set (reg:SI LR_REGNO)
>  		   (match_operand:SI 0 "immediate_operand" "s"))
>  	      (use (unspec [(match_dup 0)] UNSPEC_TOC))])]
> -  "TARGET_ELF && DEFAULT_ABI != ABI_AIX
> +  "TARGET_ELF && DEFAULT_ABI == ABI_V4
>     && (flag_pic == 2 || (flag_pic && TARGET_SECURE_PLT))"
>    "")
>  
> @@ -11346,7 +11336,7 @@
>    [(set (reg:SI LR_REGNO)
>  	(match_operand:SI 0 "immediate_operand" "s"))
>     (use (unspec [(match_dup 0)] UNSPEC_TOC))]
> -  "!TARGET_LINK_STACK && TARGET_ELF && DEFAULT_ABI != ABI_AIX
> +  "!TARGET_LINK_STACK && TARGET_ELF && DEFAULT_ABI == ABI_V4
>     && (flag_pic == 2 || (flag_pic && TARGET_SECURE_PLT))"
>    "bcl 20,31,%0\\n%0:"
>    [(set_attr "type" "branch")
> @@ -11356,7 +11346,7 @@
>    [(set (reg:SI LR_REGNO)
>  	(match_operand:SI 0 "immediate_operand" "s"))
>     (use (unspec [(match_dup 0)] UNSPEC_TOC))]
> -  "TARGET_LINK_STACK && TARGET_ELF && DEFAULT_ABI != ABI_AIX
> +  "TARGET_LINK_STACK && TARGET_ELF && DEFAULT_ABI == ABI_V4
>     && (flag_pic == 2 || (flag_pic && TARGET_SECURE_PLT))"
>    "*
>  {
> @@ -11376,7 +11366,7 @@
>  			       (label_ref (match_operand 1 "" ""))]
>  		           UNSPEC_TOCPTR))
>  	      (match_dup 1)])]
> -  "TARGET_ELF && DEFAULT_ABI != ABI_AIX && flag_pic == 2"
> +  "TARGET_ELF && DEFAULT_ABI == ABI_V4 && flag_pic == 2"
>    "")
>  
>  (define_insn "load_toc_v4_PIC_1b_normal"
> @@ -11385,7 +11375,7 @@
>  		    (label_ref (match_operand 1 "" ""))]
>  		UNSPEC_TOCPTR))
>     (match_dup 1)]
> -  "!TARGET_LINK_STACK && TARGET_ELF && DEFAULT_ABI != ABI_AIX && flag_pic == 2"
> +  "!TARGET_LINK_STACK && TARGET_ELF && DEFAULT_ABI == ABI_V4 && flag_pic == 2"
>    "bcl 20,31,$+8\;.long %0-$"
>    [(set_attr "type" "branch")
>     (set_attr "length" "8")])
> @@ -11396,7 +11386,7 @@
>  		    (label_ref (match_operand 1 "" ""))]
>  		UNSPEC_TOCPTR))
>     (match_dup 1)]
> -  "TARGET_LINK_STACK && TARGET_ELF && DEFAULT_ABI != ABI_AIX && flag_pic == 2"
> +  "TARGET_LINK_STACK && TARGET_ELF && DEFAULT_ABI == ABI_V4 && flag_pic == 2"
>    "*
>  {
>    char name[32];
> @@ -11414,7 +11404,7 @@
>  	(mem:SI (plus:SI (match_operand:SI 1 "gpc_reg_operand" "b")
>  		   (minus:SI (match_operand:SI 2 "immediate_operand" "s")
>  			     (match_operand:SI 3 "immediate_operand" "s")))))]
> -  "TARGET_ELF && DEFAULT_ABI != ABI_AIX && flag_pic == 2"
> +  "TARGET_ELF && DEFAULT_ABI == ABI_V4 && flag_pic == 2"
>    "lwz %0,%2-%3(%1)"
>    [(set_attr "type" "load")])
>  
> @@ -11424,7 +11414,7 @@
>  		 (high:SI
>  		   (minus:SI (match_operand:SI 2 "symbol_ref_operand" "s")
>  			     (match_operand:SI 3 "symbol_ref_operand" "s")))))]
> -  "TARGET_ELF && TARGET_SECURE_PLT && DEFAULT_ABI != ABI_AIX && flag_pic"
> +  "TARGET_ELF && TARGET_SECURE_PLT && DEFAULT_ABI == ABI_V4 && flag_pic"
>    "addis %0,%1,%2-%3@ha")
>  
>  (define_insn "load_toc_v4_PIC_3c"
> @@ -11432,7 +11422,7 @@
>  	(lo_sum:SI (match_operand:SI 1 "gpc_reg_operand" "b")
>  		   (minus:SI (match_operand:SI 2 "symbol_ref_operand" "s")
>  			     (match_operand:SI 3 "symbol_ref_operand" "s"))))]
> -  "TARGET_ELF && TARGET_SECURE_PLT && DEFAULT_ABI != ABI_AIX && flag_pic"
> +  "TARGET_ELF && TARGET_SECURE_PLT && DEFAULT_ABI == ABI_V4 && flag_pic"
>    "addi %0,%1,%2-%3@l")
>  
>  ;; If the TOC is shared over a translation unit, as happens with all
> @@ -11574,8 +11564,13 @@
>  
>    operands[0] = XEXP (operands[0], 0);
>  
> +  if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
> +    {
> +      rs6000_call_aix (NULL_RTX, operands[0], operands[1], operands[2]);
> +      DONE;
> +    }
> +
>    if (GET_CODE (operands[0]) != SYMBOL_REF
> -      || (DEFAULT_ABI == ABI_AIX && !SYMBOL_REF_FUNCTION_P (operands[0]))
>        || (DEFAULT_ABI != ABI_DARWIN && (INTVAL (operands[2]) & CALL_LONG) != 0))
>      {
>        if (INTVAL (operands[2]) & CALL_LONG)
> @@ -11588,12 +11583,6 @@
>  	  operands[0] = force_reg (Pmode, operands[0]);
>  	  break;
>  
> -	case ABI_AIX:
> -	  /* AIX function pointers are really pointers to a three word
> -	     area.  */
> -	  rs6000_call_indirect_aix (NULL_RTX, operands[0], operands[1]);
> -	  DONE;
> -
>  	default:
>  	  gcc_unreachable ();
>  	}
> @@ -11619,8 +11608,13 @@
>  
>    operands[1] = XEXP (operands[1], 0);
>  
> +  if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
> +    {
> +      rs6000_call_aix (operands[0], operands[1], operands[2], operands[3]);
> +      DONE;
> +    }
> +
>    if (GET_CODE (operands[1]) != SYMBOL_REF
> -      || (DEFAULT_ABI == ABI_AIX && !SYMBOL_REF_FUNCTION_P (operands[1]))
>        || (DEFAULT_ABI != ABI_DARWIN && (INTVAL (operands[3]) & CALL_LONG) != 0))
>      {
>        if (INTVAL (operands[3]) & CALL_LONG)
> @@ -11633,12 +11627,6 @@
>  	  operands[1] = force_reg (Pmode, operands[1]);
>  	  break;
>  
> -	case ABI_AIX:
> -	  /* AIX function pointers are really pointers to a three word
> -	     area.  */
> -	  rs6000_call_indirect_aix (operands[0], operands[1], operands[2]);
> -	  DONE;
> -
>  	default:
>  	  gcc_unreachable ();
>  	}
> @@ -11730,135 +11718,6 @@
>    [(set_attr "type" "branch")
>     (set_attr "length" "4,8")])
>  
> -;; Call to indirect functions with the AIX abi using a 3 word descriptor.
> -;; Operand0 is the addresss of the function to call
> -;; Operand1 is the flag for System V.4 for unprototyped or FP registers
> -;; Operand2 is the location in the function descriptor to load r2 from
> -;; Operand3 is the stack location to hold the current TOC pointer
> -
> -(define_insn "call_indirect_aix<ptrsize>"
> -  [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l"))
> -	 (match_operand 1 "" "g,g"))
> -   (use (match_operand:P 2 "memory_operand" "<ptrm>,<ptrm>"))
> -   (set (reg:P TOC_REGNUM) (match_operand:P 3 "memory_operand" "<ptrm>,<ptrm>"))
> -   (use (reg:P STATIC_CHAIN_REGNUM))
> -   (clobber (reg:P LR_REGNO))]
> -  "DEFAULT_ABI == ABI_AIX && TARGET_POINTERS_TO_NESTED_FUNCTIONS"
> -  "<ptrload> 2,%2\;b%T0l\;<ptrload> 2,%3"
> -  [(set_attr "type" "jmpreg")
> -   (set_attr "length" "12")])
> -
> -;; Like call_indirect_aix<ptrsize>, but no use of the static chain
> -;; Operand0 is the addresss of the function to call
> -;; Operand1 is the flag for System V.4 for unprototyped or FP registers
> -;; Operand2 is the location in the function descriptor to load r2 from
> -;; Operand3 is the stack location to hold the current TOC pointer
> -
> -(define_insn "call_indirect_aix<ptrsize>_nor11"
> -  [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l"))
> -	 (match_operand 1 "" "g,g"))
> -   (use (match_operand:P 2 "memory_operand" "<ptrm>,<ptrm>"))
> -   (set (reg:P TOC_REGNUM) (match_operand:P 3 "memory_operand" "<ptrm>,<ptrm>"))
> -   (clobber (reg:P LR_REGNO))]
> -  "DEFAULT_ABI == ABI_AIX && !TARGET_POINTERS_TO_NESTED_FUNCTIONS"
> -  "<ptrload> 2,%2\;b%T0l\;<ptrload> 2,%3"
> -  [(set_attr "type" "jmpreg")
> -   (set_attr "length" "12")])
> -
> -;; Operand0 is the return result of the function
> -;; Operand1 is the addresss of the function to call
> -;; Operand2 is the flag for System V.4 for unprototyped or FP registers
> -;; Operand3 is the location in the function descriptor to load r2 from
> -;; Operand4 is the stack location to hold the current TOC pointer
> -
> -(define_insn "call_value_indirect_aix<ptrsize>"
> -  [(set (match_operand 0 "" "")
> -	(call (mem:SI (match_operand:P 1 "register_operand" "c,*l"))
> -	      (match_operand 2 "" "g,g")))
> -   (use (match_operand:P 3 "memory_operand" "<ptrm>,<ptrm>"))
> -   (set (reg:P TOC_REGNUM) (match_operand:P 4 "memory_operand" "<ptrm>,<ptrm>"))
> -   (use (reg:P STATIC_CHAIN_REGNUM))
> -   (clobber (reg:P LR_REGNO))]
> -  "DEFAULT_ABI == ABI_AIX && TARGET_POINTERS_TO_NESTED_FUNCTIONS"
> -  "<ptrload> 2,%3\;b%T1l\;<ptrload> 2,%4"
> -  [(set_attr "type" "jmpreg")
> -   (set_attr "length" "12")])
> -
> -;; Like call_value_indirect_aix<ptrsize>, but no use of the static chain
> -;; Operand0 is the return result of the function
> -;; Operand1 is the addresss of the function to call
> -;; Operand2 is the flag for System V.4 for unprototyped or FP registers
> -;; Operand3 is the location in the function descriptor to load r2 from
> -;; Operand4 is the stack location to hold the current TOC pointer
> -
> -(define_insn "call_value_indirect_aix<ptrsize>_nor11"
> -  [(set (match_operand 0 "" "")
> -	(call (mem:SI (match_operand:P 1 "register_operand" "c,*l"))
> -	      (match_operand 2 "" "g,g")))
> -   (use (match_operand:P 3 "memory_operand" "<ptrm>,<ptrm>"))
> -   (set (reg:P TOC_REGNUM) (match_operand:P 4 "memory_operand" "<ptrm>,<ptrm>"))
> -   (clobber (reg:P LR_REGNO))]
> -  "DEFAULT_ABI == ABI_AIX && !TARGET_POINTERS_TO_NESTED_FUNCTIONS"
> -  "<ptrload> 2,%3\;b%T1l\;<ptrload> 2,%4"
> -  [(set_attr "type" "jmpreg")
> -   (set_attr "length" "12")])
> -
> -;; Call to function which may be in another module.  Restore the TOC
> -;; pointer (r2) after the call unless this is System V.
> -;; Operand2 is nonzero if we are using the V.4 calling sequence and
> -;; either the function was not prototyped, or it was prototyped as a
> -;; variable argument function.  It is > 0 if FP registers were passed
> -;; and < 0 if they were not.
> -
> -(define_insn "*call_nonlocal_aix32"
> -  [(call (mem:SI (match_operand:SI 0 "symbol_ref_operand" "s"))
> -	 (match_operand 1 "" "g"))
> -   (use (match_operand:SI 2 "immediate_operand" "O"))
> -   (clobber (reg:SI LR_REGNO))]
> -  "TARGET_32BIT
> -   && DEFAULT_ABI == ABI_AIX
> -   && (INTVAL (operands[2]) & CALL_LONG) == 0"
> -  "bl %z0\;nop"
> -  [(set_attr "type" "branch")
> -   (set_attr "length" "8")])
> -   
> -(define_insn "*call_nonlocal_aix64"
> -  [(call (mem:SI (match_operand:DI 0 "symbol_ref_operand" "s"))
> -	 (match_operand 1 "" "g"))
> -   (use (match_operand:SI 2 "immediate_operand" "O"))
> -   (clobber (reg:SI LR_REGNO))]
> -  "TARGET_64BIT
> -   && DEFAULT_ABI == ABI_AIX
> -   && (INTVAL (operands[2]) & CALL_LONG) == 0"
> -  "bl %z0\;nop"
> -  [(set_attr "type" "branch")
> -   (set_attr "length" "8")])
> -
> -(define_insn "*call_value_nonlocal_aix32"
> -  [(set (match_operand 0 "" "")
> -	(call (mem:SI (match_operand:SI 1 "symbol_ref_operand" "s"))
> -	      (match_operand 2 "" "g")))
> -   (use (match_operand:SI 3 "immediate_operand" "O"))
> -   (clobber (reg:SI LR_REGNO))]
> -  "TARGET_32BIT
> -   && DEFAULT_ABI == ABI_AIX
> -   && (INTVAL (operands[3]) & CALL_LONG) == 0"
> -  "bl %z1\;nop"
> -  [(set_attr "type" "branch")
> -   (set_attr "length" "8")])
> -
> -(define_insn "*call_value_nonlocal_aix64"
> -  [(set (match_operand 0 "" "")
> -	(call (mem:SI (match_operand:DI 1 "symbol_ref_operand" "s"))
> -	      (match_operand 2 "" "g")))
> -   (use (match_operand:SI 3 "immediate_operand" "O"))
> -   (clobber (reg:SI LR_REGNO))]
> -  "TARGET_64BIT
> -   && DEFAULT_ABI == ABI_AIX
> -   && (INTVAL (operands[3]) & CALL_LONG) == 0"
> -  "bl %z1\;nop"
> -  [(set_attr "type" "branch")
> -   (set_attr "length" "8")])
>  
>  ;; A function pointer under System V is just a normal pointer
>  ;; operands[0] is the function pointer
> @@ -12041,6 +11900,104 @@
>    [(set_attr "type" "branch,branch")
>     (set_attr "length" "4,8")])
>  
> +
> +;; Call to AIX abi function in the same module.
> +
> +(define_insn "*call_local_aix<mode>"
> +  [(call (mem:SI (match_operand:P 0 "current_file_function_operand" "s"))
> +	 (match_operand 1 "" "g"))
> +   (clobber (reg:P LR_REGNO))]
> +  "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
> +  "bl %z0"
> +  [(set_attr "type" "branch")
> +   (set_attr "length" "4")])
> +
> +(define_insn "*call_value_local_aix<mode>"
> +  [(set (match_operand 0 "" "")
> +	(call (mem:SI (match_operand:P 1 "current_file_function_operand" "s"))
> +	      (match_operand 2 "" "g")))
> +   (clobber (reg:P LR_REGNO))]
> +  "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
> +  "bl %z1"
> +  [(set_attr "type" "branch")
> +   (set_attr "length" "4")])
> +
> +;; Call to AIX abi function which may be in another module.
> +;; Restore the TOC pointer (r2) after the call.
> +
> +(define_insn "*call_nonlocal_aix<mode>"
> +  [(call (mem:SI (match_operand:P 0 "symbol_ref_operand" "s"))
> +	 (match_operand 1 "" "g"))
> +   (clobber (reg:P LR_REGNO))]
> +  "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
> +  "bl %z0\;nop"
> +  [(set_attr "type" "branch")
> +   (set_attr "length" "8")])
> +
> +(define_insn "*call_value_nonlocal_aix<mode>"
> +  [(set (match_operand 0 "" "")
> +	(call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s"))
> +	      (match_operand 2 "" "g")))
> +   (clobber (reg:P LR_REGNO))]
> +  "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
> +  "bl %z1\;nop"
> +  [(set_attr "type" "branch")
> +   (set_attr "length" "8")])
> +
> +;; Call to indirect functions with the AIX abi using a 3 word descriptor.
> +;; Operand0 is the addresss of the function to call
> +;; Operand2 is the location in the function descriptor to load r2 from
> +;; Operand3 is the stack location to hold the current TOC pointer
> +
> +(define_insn "*call_indirect_aix<mode>"
> +  [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l"))
> +	 (match_operand 1 "" "g,g"))
> +   (use (match_operand:P 2 "memory_operand" "<ptrm>,<ptrm>"))
> +   (set (reg:P TOC_REGNUM) (match_operand:P 3 "memory_operand" "<ptrm>,<ptrm>"))
> +   (clobber (reg:P LR_REGNO))]
> +  "DEFAULT_ABI == ABI_AIX"
> +  "<ptrload> 2,%2\;b%T0l\;<ptrload> 2,%3"
> +  [(set_attr "type" "jmpreg")
> +   (set_attr "length" "12")])
> +
> +(define_insn "*call_value_indirect_aix<mode>"
> +  [(set (match_operand 0 "" "")
> +	(call (mem:SI (match_operand:P 1 "register_operand" "c,*l"))
> +	      (match_operand 2 "" "g,g")))
> +   (use (match_operand:P 3 "memory_operand" "<ptrm>,<ptrm>"))
> +   (set (reg:P TOC_REGNUM) (match_operand:P 4 "memory_operand" "<ptrm>,<ptrm>"))
> +   (clobber (reg:P LR_REGNO))]
> +  "DEFAULT_ABI == ABI_AIX"
> +  "<ptrload> 2,%3\;b%T1l\;<ptrload> 2,%4"
> +  [(set_attr "type" "jmpreg")
> +   (set_attr "length" "12")])
> +
> +;; Call to indirect functions with the ELFv2 ABI.
> +;; Operand0 is the addresss of the function to call
> +;; Operand2 is the stack location to hold the current TOC pointer
> +
> +(define_insn "*call_indirect_elfv2<mode>"
> +  [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l"))
> +	 (match_operand 1 "" "g,g"))
> +   (set (reg:P TOC_REGNUM) (match_operand:P 2 "memory_operand" "<ptrm>,<ptrm>"))
> +   (clobber (reg:P LR_REGNO))]
> +  "DEFAULT_ABI == ABI_ELFv2"
> +  "b%T0l\;<ptrload> 2,%2"
> +  [(set_attr "type" "jmpreg")
> +   (set_attr "length" "8")])
> +
> +(define_insn "*call_value_indirect_elfv2<mode>"
> +  [(set (match_operand 0 "" "")
> +	(call (mem:SI (match_operand:P 1 "register_operand" "c,*l"))
> +	      (match_operand 2 "" "g,g")))
> +   (set (reg:P TOC_REGNUM) (match_operand:P 3 "memory_operand" "<ptrm>,<ptrm>"))
> +   (clobber (reg:P LR_REGNO))]
> +  "DEFAULT_ABI == ABI_ELFv2"
> +  "b%T1l\;<ptrload> 2,%3"
> +  [(set_attr "type" "jmpreg")
> +   (set_attr "length" "8")])
> +
> +
>  ;; Call subroutine returning any type.
>  (define_expand "untyped_call"
>    [(parallel [(call (match_operand 0 "" "")
> @@ -12088,6 +12045,39 @@
>    gcc_assert (GET_CODE (operands[1]) == CONST_INT);
>  
>    operands[0] = XEXP (operands[0], 0);
> +
> +  if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
> +    {
> +      rs6000_sibcall_aix (NULL_RTX, operands[0], operands[1], operands[2]);
> +      DONE;
> +    }
> +}")
> +
> +(define_expand "sibcall_value"
> +  [(parallel [(set (match_operand 0 "register_operand" "")
> +		(call (mem:SI (match_operand 1 "address_operand" ""))
> +		      (match_operand 2 "" "")))
> +	      (use (match_operand 3 "" ""))
> +	      (use (reg:SI LR_REGNO))
> +	      (simple_return)])]
> +  ""
> +  "
> +{
> +#if TARGET_MACHO
> +  if (MACHOPIC_INDIRECT)
> +    operands[1] = machopic_indirect_call_target (operands[1]);
> +#endif
> +
> +  gcc_assert (GET_CODE (operands[1]) == MEM);
> +  gcc_assert (GET_CODE (operands[2]) == CONST_INT);
> +
> +  operands[1] = XEXP (operands[1], 0);
> +
> +  if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
> +    {
> +      rs6000_sibcall_aix (operands[0], operands[1], operands[2], operands[3]);
> +      DONE;
> +    }
>  }")
>  
>  ;; this and similar patterns must be marked as using LR, otherwise
> @@ -12155,7 +12145,6 @@
>    [(set_attr "type" "branch")
>     (set_attr "length" "4,8")])
>  
> -
>  (define_insn "*sibcall_value_local64"
>    [(set (match_operand 0 "" "")
>  	(call (mem:SI (match_operand:DI 1 "current_file_function_operand" "s,s"))
> @@ -12177,35 +12166,6 @@
>    [(set_attr "type" "branch")
>     (set_attr "length" "4,8")])
>  
> -(define_insn "*sibcall_nonlocal_aix<mode>"
> -  [(call (mem:SI (match_operand:P 0 "call_operand" "s,c"))
> -	 (match_operand 1 "" "g,g"))
> -   (use (match_operand:SI 2 "immediate_operand" "O,O"))
> -   (use (reg:SI LR_REGNO))
> -   (simple_return)]
> -  "DEFAULT_ABI == ABI_AIX
> -   && (INTVAL (operands[2]) & CALL_LONG) == 0"
> -  "@
> -   b %z0
> -   b%T0"
> -  [(set_attr "type" "branch")
> -   (set_attr "length" "4")])
> -
> -(define_insn "*sibcall_value_nonlocal_aix<mode>"
> -  [(set (match_operand 0 "" "")
> -	(call (mem:SI (match_operand:P 1 "call_operand" "s,c"))
> -	      (match_operand 2 "" "g,g")))
> -   (use (match_operand:SI 3 "immediate_operand" "O,O"))
> -   (use (reg:SI LR_REGNO))
> -   (simple_return)]
> -  "DEFAULT_ABI == ABI_AIX
> -   && (INTVAL (operands[3]) & CALL_LONG) == 0"
> -  "@
> -   b %z1
> -   b%T1"
> -  [(set_attr "type" "branch")
> -   (set_attr "length" "4")])
> -
>  (define_insn "*sibcall_nonlocal_sysv<mode>"
>    [(call (mem:SI (match_operand:P 0 "call_operand" "s,s,c,c"))
>  	 (match_operand 1 "" ""))
> @@ -12236,27 +12196,6 @@
>    [(set_attr "type" "branch")
>     (set_attr "length" "4,8,4,8")])
>  
> -(define_expand "sibcall_value"
> -  [(parallel [(set (match_operand 0 "register_operand" "")
> -		(call (mem:SI (match_operand 1 "address_operand" ""))
> -		      (match_operand 2 "" "")))
> -	      (use (match_operand 3 "" ""))
> -	      (use (reg:SI LR_REGNO))
> -	      (simple_return)])]
> -  ""
> -  "
> -{
> -#if TARGET_MACHO
> -  if (MACHOPIC_INDIRECT)
> -    operands[1] = machopic_indirect_call_target (operands[1]);
> -#endif
> -
> -  gcc_assert (GET_CODE (operands[1]) == MEM);
> -  gcc_assert (GET_CODE (operands[2]) == CONST_INT);
> -
> -  operands[1] = XEXP (operands[1], 0);
> -}")
> -
>  (define_insn "*sibcall_value_nonlocal_sysv<mode>"
>    [(set (match_operand 0 "" "")
>  	(call (mem:SI (match_operand:P 1 "call_operand" "s,s,c,c"))
> @@ -12288,6 +12227,31 @@
>    [(set_attr "type" "branch")
>     (set_attr "length" "4,8,4,8")])
>  
> +;; AIX ABI sibling call patterns.
> +
> +(define_insn "*sibcall_aix<mode>"
> +  [(call (mem:SI (match_operand:P 0 "call_operand" "s,c"))
> +	 (match_operand 1 "" "g,g"))
> +   (simple_return)]
> +  "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
> +  "@
> +   b %z0
> +   b%T0"
> +  [(set_attr "type" "branch")
> +   (set_attr "length" "4")])
> +
> +(define_insn "*sibcall_value_aix<mode>"
> +  [(set (match_operand 0 "" "")
> +	(call (mem:SI (match_operand:P 1 "call_operand" "s,c"))
> +	      (match_operand 2 "" "g,g")))
> +   (simple_return)]
> +  "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
> +  "@
> +   b %z1
> +   b%T1"
> +  [(set_attr "type" "branch")
> +   (set_attr "length" "4")])
> +
>  (define_expand "sibcall_epilogue"
>    [(use (const_int 0))]
>    ""
> @@ -14523,6 +14487,14 @@
>    "mfcr %0"
>    [(set_attr "type" "mfcr")])
>  
> +(define_insn "*crsave"
> +  [(match_parallel 0 "crsave_operation"
> +		   [(set (match_operand:SI 1 "memory_operand" "=m")
> +			 (match_operand:SI 2 "gpc_reg_operand" "r"))])]
> +  ""
> +  "stw %2,%1"
> +  [(set_attr "type" "store")])
> +
>  (define_insn "*stmw"
>    [(match_parallel 0 "stmw_operation"
>  		   [(set (match_operand:SI 1 "memory_operand" "=m")
> Index: gcc-4_8-test/gcc/testsuite/g++.dg/eh/ppc64-sighandle-cr.C
> ===================================================================
> --- /dev/null
> +++ gcc-4_8-test/gcc/testsuite/g++.dg/eh/ppc64-sighandle-cr.C
> @@ -0,0 +1,54 @@
> +// { dg-do run { target { powerpc64*-*-linux* } } }
> +// { dg-options "-fexceptions -fnon-call-exceptions" }
> +
> +#include <signal.h>
> +#include <stdlib.h>
> +#include <fenv.h>
> +
> +#define SET_CR(R,V) __asm__ __volatile__ ("mtcrf %0,%1" : : "n" (1<<(7-R)), "r" (V<<(4*(7-R))) : "cr" #R)
> +#define GET_CR(R) ({ int tmp; __asm__ __volatile__ ("mfcr %0" : "=r" (tmp)); (tmp >> 4*(7-R)) & 15; })
> +
> +void sighandler (int signo, siginfo_t * si, void * uc)
> +{
> +  SET_CR(2, 3);
> +  SET_CR(3, 2);
> +  SET_CR(4, 1);
> +
> +  throw 0;
> +}
> +
> +float test (float a, float b) __attribute__ ((__noinline__));
> +float test (float a, float b)
> +{
> +  float x;
> +  asm ("mtcrf %1,%2" : "=f" (x) : "n" (1 << (7-3)), "r" (0), "0" (b) : "cr3");
> +  return a / x;
> +}
> +
> +int main ()
> +{
> +  struct sigaction sa;
> +  int status;
> +
> +  sa.sa_sigaction = sighandler;
> +  sa.sa_flags = SA_SIGINFO;
> +
> +  status = sigaction (SIGFPE, & sa, NULL);
> +
> +  feenableexcept (FE_DIVBYZERO);
> +
> +  SET_CR(2, 6);
> +  SET_CR(3, 9);
> +  SET_CR(4, 12);
> +
> +  try {
> +    test (1, 0);
> +  }
> +  catch (...) {
> +    return GET_CR(2) != 6 || GET_CR(3) != 9 || GET_CR(4) != 12;
> +  }
> +
> +  return 1;
> +}
> +
> +
> Index: gcc-4_8-test/gcc/config/rs6000/predicates.md
> ===================================================================
> --- gcc-4_8-test.orig/gcc/config/rs6000/predicates.md
> +++ gcc-4_8-test/gcc/config/rs6000/predicates.md
> @@ -1077,7 +1077,8 @@
>    (and (match_code "symbol_ref")
>         (match_test "(DEFAULT_ABI != ABI_AIX || SYMBOL_REF_FUNCTION_P (op))
>  		    && ((SYMBOL_REF_LOCAL_P (op)
> -			 && (DEFAULT_ABI != ABI_AIX
> +			 && ((DEFAULT_ABI != ABI_AIX
> +			      && DEFAULT_ABI != ABI_ELFv2)
>  			     || !SYMBOL_REF_EXTERNAL_P (op)))
>  		        || (op == XEXP (DECL_RTL (current_function_decl),
>  						  0)))")))
> @@ -1556,6 +1557,26 @@
>  	return 0;
>      }
>    return 1;
> +})
> +
> +;; Return 1 if OP is valid for crsave insn, known to be a PARALLEL.
> +(define_predicate "crsave_operation"
> +  (match_code "parallel")
> +{
> +  int count = XVECLEN (op, 0);
> +  int i;
> +
> +  for (i = 1; i < count; i++)
> +    {
> +      rtx exp = XVECEXP (op, 0, i);
> +
> +      if (GET_CODE (exp) != USE
> +	  || GET_CODE (XEXP (exp, 0)) != REG
> +	  || GET_MODE (XEXP (exp, 0)) != CCmode
> +	  || ! CR_REGNO_P (REGNO (XEXP (exp, 0))))
> +	return 0;
> +    }
> +  return 1;
>  })
>  
>  ;; Return 1 if OP is valid for lmw insn, known to be a PARALLEL.
> Index: gcc-4_8-test/libgcc/config/rs6000/linux-unwind.h
> ===================================================================
> --- gcc-4_8-test.orig/libgcc/config/rs6000/linux-unwind.h
> +++ gcc-4_8-test/libgcc/config/rs6000/linux-unwind.h
> @@ -24,9 +24,19 @@
>  
>  #define R_LR		65
>  #define R_CR2		70
> +#define R_CR3		71
> +#define R_CR4		72
>  #define R_VR0		77
>  #define R_VRSAVE	109
>  
> +#ifdef __powerpc64__
> +#if _CALL_ELF == 2
> +#define TOC_SAVE_SLOT	24
> +#else
> +#define TOC_SAVE_SLOT	40
> +#endif
> +#endif
> +
>  struct gcc_vregs
>  {
>    __attribute__ ((vector_size (16))) int vr[32];
> @@ -107,6 +117,8 @@ get_regs (struct _Unwind_Context *contex
>      }
>    else if (pc[1] == 0x380000AC)
>      {
> +#if _CALL_ELF != 2
> +      /* These old kernel versions never supported ELFv2.  */
>        /* This works for 2.4 kernels, but not for 2.6 kernels with vdso
>  	 because pc isn't pointing into the stack.  Can be removed when
>  	 no one is running 2.4.19 or 2.4.20, the first two ppc64
> @@ -121,6 +133,7 @@ get_regs (struct _Unwind_Context *contex
>        if ((long) frame24->puc != -21 * 8)
>  	return frame24->puc->regs;
>        else
> +#endif
>  	{
>  	  /* This works for 2.4.21 and later kernels.  */
>  	  struct rt_sigframe {
> @@ -185,6 +198,7 @@ ppc_fallback_frame_state (struct _Unwind
>  {
>    struct gcc_regs *regs = get_regs (context);
>    struct gcc_vregs *vregs;
> +  long cr_offset;
>    long new_cfa;
>    int i;
>  
> @@ -206,11 +220,21 @@ ppc_fallback_frame_state (struct _Unwind
>        fs->regs.reg[i].loc.offset = (long) &regs->gpr[i] - new_cfa;
>      }
>  
> +  /* The CR is saved in the low 32 bits of regs->ccr.  */
> +  cr_offset = (long) &regs->ccr - new_cfa;
> +#ifndef __LITTLE_ENDIAN__
> +  cr_offset += sizeof (long) - 4;
> +#endif
> +  /* In the ELFv1 ABI, CR2 stands in for the whole CR.  */
>    fs->regs.reg[R_CR2].how = REG_SAVED_OFFSET;
> -  /* CR? regs are always 32-bit and PPC is big-endian, so in 64-bit
> -     libgcc loc.offset needs to point to the low 32 bits of regs->ccr.  */
> -  fs->regs.reg[R_CR2].loc.offset = (long) &regs->ccr - new_cfa
> -				   + sizeof (long) - 4;
> +  fs->regs.reg[R_CR2].loc.offset = cr_offset;
> +#if _CALL_ELF == 2
> +  /* In the ELFv2 ABI, every CR field has a separate CFI entry.  */
> +  fs->regs.reg[R_CR3].how = REG_SAVED_OFFSET;
> +  fs->regs.reg[R_CR3].loc.offset = cr_offset;
> +  fs->regs.reg[R_CR4].how = REG_SAVED_OFFSET;
> +  fs->regs.reg[R_CR4].loc.offset = cr_offset;
> +#endif
>  
>    fs->regs.reg[R_LR].how = REG_SAVED_OFFSET;
>    fs->regs.reg[R_LR].loc.offset = (long) &regs->link - new_cfa;
> @@ -294,9 +318,13 @@ frob_update_context (struct _Unwind_Cont
>  	 figure out if it was saved.  The big problem here is that the
>  	 code that does the save/restore is generated by the linker, so
>  	 we have no good way to determine at compile time what to do.  */
> -      if (pc[0] == 0xF8410028
> +      if (pc[0] == 0xF8410000 + TOC_SAVE_SLOT
> +#if _CALL_ELF != 2
> +	  /* The ELFv2 linker never generates the old PLT stub form.  */
>  	  || ((pc[0] & 0xFFFF0000) == 0x3D820000
> -	      && pc[1] == 0xF8410028))
> +	      && pc[1] == 0xF8410000 + TOC_SAVE_SLOT)
> +#endif
> +	  )
>  	{
>  	  /* We are in a plt call stub or r2 adjusting long branch stub,
>  	     before r2 has been saved.  Keep REG_UNSAVED.  */
> @@ -305,18 +333,21 @@ frob_update_context (struct _Unwind_Cont
>  	{
>  	  unsigned int *insn
>  	    = (unsigned int *) _Unwind_GetGR (context, R_LR);
> -	  if (insn && *insn == 0xE8410028)
> -	    _Unwind_SetGRPtr (context, 2, context->cfa + 40);
> +	  if (insn && *insn == 0xE8410000 + TOC_SAVE_SLOT)
> +	    _Unwind_SetGRPtr (context, 2, context->cfa + TOC_SAVE_SLOT);
> +#if _CALL_ELF != 2
> +	  /* ELFv2 does not use this function pointer call sequence.  */
>  	  else if (pc[0] == 0x4E800421
> -		   && pc[1] == 0xE8410028)
> +		   && pc[1] == 0xE8410000 + TOC_SAVE_SLOT)
>  	    {
>  	      /* We are at the bctrl instruction in a call via function
>  		 pointer.  gcc always emits the load of the new R2 just
>  		 before the bctrl so this is the first and only place
>  		 we need to use the stored R2.  */
>  	      _Unwind_Word sp = _Unwind_GetGR (context, 1);
> -	      _Unwind_SetGRPtr (context, 2, (void *)(sp + 40));
> +	      _Unwind_SetGRPtr (context, 2, (void *)(sp + TOC_SAVE_SLOT));
>  	    }
> +#endif
>  	}
>      }
>  #endif
> Index: gcc-4_8-test/gcc/config/rs6000/rs6000-protos.h
> ===================================================================
> --- gcc-4_8-test.orig/gcc/config/rs6000/rs6000-protos.h
> +++ gcc-4_8-test/gcc/config/rs6000/rs6000-protos.h
> @@ -155,6 +155,7 @@ extern tree altivec_resolve_overloaded_b
>  extern rtx rs6000_libcall_value (enum machine_mode);
>  extern rtx rs6000_va_arg (tree, tree);
>  extern int function_ok_for_sibcall (tree);
> +extern int rs6000_reg_parm_stack_space (tree);
>  extern void rs6000_elf_declare_function_name (FILE *, const char *, tree);
>  extern bool rs6000_elf_in_small_data_p (const_tree);
>  #ifdef ARGS_SIZE_RTX
> @@ -179,7 +180,8 @@ extern unsigned int rs6000_dbx_register_
>  extern void rs6000_emit_epilogue (int);
>  extern void rs6000_emit_eh_reg_restore (rtx, rtx);
>  extern const char * output_isel (rtx *);
> -extern void rs6000_call_indirect_aix (rtx, rtx, rtx);
> +extern void rs6000_call_aix (rtx, rtx, rtx, rtx);
> +extern void rs6000_sibcall_aix (rtx, rtx, rtx, rtx);
>  extern void rs6000_aix_asm_output_dwarf_table_ref (char *);
>  extern void get_ppc476_thunk_name (char name[32]);
>  extern bool rs6000_overloaded_builtin_p (enum rs6000_builtins);
> Index: gcc-4_8-test/gcc/config/rs6000/rs6000.h
> ===================================================================
> --- gcc-4_8-test.orig/gcc/config/rs6000/rs6000.h
> +++ gcc-4_8-test/gcc/config/rs6000/rs6000.h
> @@ -1531,21 +1531,14 @@ extern enum reg_class rs6000_constraints
>     arguments.  */
>  #define FRAME_GROWS_DOWNWARD (flag_stack_protect != 0 || flag_asan != 0)
>  
> -/* Size of the outgoing register save area */
> -#define RS6000_REG_SAVE ((DEFAULT_ABI == ABI_AIX			\
> -			  || DEFAULT_ABI == ABI_DARWIN)			\
> -			 ? (TARGET_64BIT ? 64 : 32)			\
> -			 : 0)
> -
>  /* Size of the fixed area on the stack */
>  #define RS6000_SAVE_AREA \
> -  (((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_DARWIN) ? 24 : 8)	\
> +  ((DEFAULT_ABI == ABI_V4 ? 8 : DEFAULT_ABI == ABI_ELFv2 ? 16 : 24)	\
>     << (TARGET_64BIT ? 1 : 0))
>  
> -/* MEM representing address to save the TOC register */
> -#define RS6000_SAVE_TOC gen_rtx_MEM (Pmode, \
> -				     plus_constant (Pmode, stack_pointer_rtx, \
> -						    (TARGET_32BIT ? 20 : 40)))
> +/* Stack offset for toc save slot.  */
> +#define RS6000_TOC_SAVE_SLOT \
> +  ((DEFAULT_ABI == ABI_ELFv2 ? 12 : 20) << (TARGET_64BIT ? 1 : 0))
>  
>  /* Align an address */
>  #define RS6000_ALIGN(n,a) (((n) + (a) - 1) & ~((a) - 1))
> @@ -1595,7 +1588,7 @@ extern enum reg_class rs6000_constraints
>  /* Define this if stack space is still allocated for a parameter passed
>     in a register.  The value is the number of bytes allocated to this
>     area.  */
> -#define REG_PARM_STACK_SPACE(FNDECL)	RS6000_REG_SAVE
> +#define REG_PARM_STACK_SPACE(FNDECL) rs6000_reg_parm_stack_space((FNDECL))
>  
>  /* Define this if the above stack space is to be considered part of the
>     space allocated by the caller.  */
> @@ -1639,9 +1632,8 @@ extern enum reg_class rs6000_constraints
>  #define FP_ARG_MIN_REG 33
>  #define	FP_ARG_AIX_MAX_REG 45
>  #define	FP_ARG_V4_MAX_REG  40
> -#define	FP_ARG_MAX_REG ((DEFAULT_ABI == ABI_AIX				\
> -			 || DEFAULT_ABI == ABI_DARWIN)			\
> -			? FP_ARG_AIX_MAX_REG : FP_ARG_V4_MAX_REG)
> +#define	FP_ARG_MAX_REG (DEFAULT_ABI == ABI_V4				\
> +			? FP_ARG_V4_MAX_REG : FP_ARG_AIX_MAX_REG)
>  #define FP_ARG_NUM_REG (FP_ARG_MAX_REG - FP_ARG_MIN_REG + 1)
>  
>  /* Minimum and maximum AltiVec registers used to hold arguments.  */
> @@ -1649,10 +1641,17 @@ extern enum reg_class rs6000_constraints
>  #define ALTIVEC_ARG_MAX_REG (ALTIVEC_ARG_MIN_REG + 11)
>  #define ALTIVEC_ARG_NUM_REG (ALTIVEC_ARG_MAX_REG - ALTIVEC_ARG_MIN_REG + 1)
>  
> +/* Maximum number of registers per ELFv2 homogeneous aggregate argument.  */
> +#define AGGR_ARG_NUM_REG 8
> +
>  /* Return registers */
>  #define GP_ARG_RETURN GP_ARG_MIN_REG
>  #define FP_ARG_RETURN FP_ARG_MIN_REG
>  #define ALTIVEC_ARG_RETURN (FIRST_ALTIVEC_REGNO + 2)
> +#define FP_ARG_MAX_RETURN (DEFAULT_ABI != ABI_ELFv2 ? FP_ARG_RETURN	\
> +			   : (FP_ARG_RETURN + AGGR_ARG_NUM_REG - 1))
> +#define ALTIVEC_ARG_MAX_RETURN (DEFAULT_ABI != ABI_ELFv2 ? ALTIVEC_ARG_RETURN \
> +			        : (ALTIVEC_ARG_RETURN + AGGR_ARG_NUM_REG - 1))
>  
>  /* Flags for the call/call_value rtl operations set up by function_arg */
>  #define CALL_NORMAL		0x00000000	/* no special processing */
> @@ -1672,8 +1671,10 @@ extern enum reg_class rs6000_constraints
>     On RS/6000, this is r3, fp1, and v2 (for AltiVec).  */
>  #define FUNCTION_VALUE_REGNO_P(N)					\
>    ((N) == GP_ARG_RETURN							\
> -   || ((N) == FP_ARG_RETURN && TARGET_HARD_FLOAT && TARGET_FPRS)	\
> -   || ((N) == ALTIVEC_ARG_RETURN && TARGET_ALTIVEC && TARGET_ALTIVEC_ABI))
> +   || ((N) >= FP_ARG_RETURN && (N) <= FP_ARG_MAX_RETURN			\
> +       && TARGET_HARD_FLOAT && TARGET_FPRS)				\
> +   || ((N) >= ALTIVEC_ARG_RETURN && (N) <= ALTIVEC_ARG_MAX_RETURN	\
> +       && TARGET_ALTIVEC && TARGET_ALTIVEC_ABI))
>  
>  /* 1 if N is a possible register number for function argument passing.
>     On RS/6000, these are r3-r10 and fp1-fp13.
> @@ -1797,11 +1798,8 @@ typedef struct rs6000_args
>  /* Number of bytes into the frame return addresses can be found.  See
>     rs6000_stack_info in rs6000.c for more information on how the different
>     abi's store the return address.  */
> -#define RETURN_ADDRESS_OFFSET						\
> - ((DEFAULT_ABI == ABI_AIX						\
> -   || DEFAULT_ABI == ABI_DARWIN)	? (TARGET_32BIT ? 8 : 16) :	\
> -  (DEFAULT_ABI == ABI_V4)		? 4 :				\
> -  (internal_error ("RETURN_ADDRESS_OFFSET not supported"), 0))
> +#define RETURN_ADDRESS_OFFSET \
> +  ((DEFAULT_ABI == ABI_V4 ? 4 : 8) << (TARGET_64BIT ? 1 : 0))
>  
>  /* The current return address is in link register (65).  The return address
>     of anything farther back is accessed normally at an offset of 8 from the
> Index: gcc-4_8-test/gcc/config/rs6000/sysv4.h
> ===================================================================
> --- gcc-4_8-test.orig/gcc/config/rs6000/sysv4.h
> +++ gcc-4_8-test/gcc/config/rs6000/sysv4.h
> @@ -45,7 +45,7 @@
>  				      & (OPTION_MASK_RELOCATABLE	\
>  					 | OPTION_MASK_MINIMAL_TOC))	\
>  				     && flag_pic > 1)			\
> -				 || DEFAULT_ABI == ABI_AIX)
> +				 || DEFAULT_ABI != ABI_V4)
>  
>  #define	TARGET_BITFIELD_TYPE	(! TARGET_NO_BITFIELD_TYPE)
>  #define	TARGET_BIG_ENDIAN	(! TARGET_LITTLE_ENDIAN)
> @@ -147,7 +147,7 @@ do {									\
>  	     rs6000_sdata_name);					\
>      }									\
>  									\
> -  else if (flag_pic && DEFAULT_ABI != ABI_AIX				\
> +  else if (flag_pic && DEFAULT_ABI == ABI_V4				\
>  	   && (rs6000_sdata == SDATA_EABI				\
>  	       || rs6000_sdata == SDATA_SYSV))				\
>      {									\
> @@ -173,14 +173,14 @@ do {									\
>        error ("-mrelocatable and -mno-minimal-toc are incompatible");	\
>      }									\
>  									\
> -  if (TARGET_RELOCATABLE && rs6000_current_abi == ABI_AIX)		\
> +  if (TARGET_RELOCATABLE && rs6000_current_abi != ABI_V4)		\
>      {									\
>        rs6000_isa_flags &= ~OPTION_MASK_RELOCATABLE;			\
>        error ("-mrelocatable and -mcall-%s are incompatible",		\
>  	     rs6000_abi_name);						\
>      }									\
>  									\
> -  if (!TARGET_64BIT && flag_pic > 1 && rs6000_current_abi == ABI_AIX)	\
> +  if (!TARGET_64BIT && flag_pic > 1 && rs6000_current_abi != ABI_V4)	\
>      {									\
>        flag_pic = 0;							\
>        error ("-fPIC and -mcall-%s are incompatible",			\
> @@ -193,7 +193,7 @@ do {									\
>      }									\
>  									\
>    /* Treat -fPIC the same as -mrelocatable.  */				\
> -  if (flag_pic > 1 && DEFAULT_ABI != ABI_AIX)				\
> +  if (flag_pic > 1 && DEFAULT_ABI == ABI_V4)				\
>      {									\
>        rs6000_isa_flags |= OPTION_MASK_RELOCATABLE | OPTION_MASK_MINIMAL_TOC; \
>        TARGET_NO_FP_IN_TOC = 1;						\
> @@ -317,7 +317,7 @@ do {									\
>  
>  /* Put PC relative got entries in .got2.  */
>  #define	MINIMAL_TOC_SECTION_ASM_OP \
> -  (TARGET_RELOCATABLE || (flag_pic && DEFAULT_ABI != ABI_AIX)		\
> +  (TARGET_RELOCATABLE || (flag_pic && DEFAULT_ABI == ABI_V4)		\
>     ? "\t.section\t\".got2\",\"aw\"" : "\t.section\t\".got1\",\"aw\"")
>  
>  #define	SDATA_SECTION_ASM_OP "\t.section\t\".sdata\",\"aw\""
> Index: gcc-4_8-test/gcc/config.gcc
> ===================================================================
> --- gcc-4_8-test.orig/gcc/config.gcc
> +++ gcc-4_8-test/gcc/config.gcc
> @@ -3509,7 +3509,7 @@ case "${target}" in
>  		;;
>  
>  	powerpc*-*-* | rs6000-*-*)
> -		supported_defaults="cpu cpu_32 cpu_64 float tune tune_32 tune_64"
> +		supported_defaults="abi cpu cpu_32 cpu_64 float tune tune_32 tune_64"
>  
>  		for which in cpu cpu_32 cpu_64 tune tune_32 tune_64; do
>  			eval "val=\$with_$which"
> @@ -3546,6 +3546,16 @@ case "${target}" in
>  				;;
>  			esac
>  		done
> +
> +		case "$with_abi" in
> +		"" | elfv1 | elfv2 )
> +			#OK
> +			;;
> +		*)
> +			echo "Unknown ABI used in --with-abi=$with_abi"
> +			exit 1
> +			;;
> +		esac
>  		;;
>  
>  	s390*-*-*)
> Index: gcc-4_8-test/gcc/config/rs6000/linux64.h
> ===================================================================
> --- gcc-4_8-test.orig/gcc/config/rs6000/linux64.h
> +++ gcc-4_8-test/gcc/config/rs6000/linux64.h
> @@ -25,9 +25,6 @@
>  
>  #ifndef RS6000_BI_ARCH
>  
> -#undef	DEFAULT_ABI
> -#define	DEFAULT_ABI ABI_AIX
> -
>  #undef	TARGET_64BIT
>  #define	TARGET_64BIT 1
>  
> @@ -88,6 +85,12 @@ extern int dot_symbols;
>  #define INVALID_64BIT "-m%s not supported in this configuration"
>  #define INVALID_32BIT INVALID_64BIT
>  
> +#ifdef LINUX64_DEFAULT_ABI_ELFv2
> +#define ELFv2_ABI_CHECK (rs6000_elf_abi != 1)
> +#else
> +#define ELFv2_ABI_CHECK (rs6000_elf_abi == 2)
> +#endif
> +
>  #undef	SUBSUBTARGET_OVERRIDE_OPTIONS
>  #define	SUBSUBTARGET_OVERRIDE_OPTIONS				\
>    do								\
> @@ -102,6 +105,12 @@ extern int dot_symbols;
>  	      error (INVALID_64BIT, "call");			\
>  	    }							\
>  	  dot_symbols = !strcmp (rs6000_abi_name, "aixdesc");	\
> +	  if (ELFv2_ABI_CHECK)					\
> +	    {							\
> +	      rs6000_current_abi = ABI_ELFv2;			\
> +	      if (dot_symbols)					\
> +		error ("-mcall-aixdesc incompatible with -mabi=elfv2"); \
> +	    }							\
>  	  if (rs6000_isa_flags & OPTION_MASK_RELOCATABLE)	\
>  	    {							\
>  	      rs6000_isa_flags &= ~OPTION_MASK_RELOCATABLE;	\
> @@ -351,7 +360,11 @@ extern int dot_symbols;
>  #define LINK_OS_DEFAULT_SPEC "%(link_os_linux)"
>  
>  #define GLIBC_DYNAMIC_LINKER32 "/lib/ld.so.1"
> -#define GLIBC_DYNAMIC_LINKER64 "/lib64/ld64.so.1"
> +#ifdef LINUX64_DEFAULT_ABI_ELFv2
> +#define GLIBC_DYNAMIC_LINKER64 "%{mabi=elfv1:/lib64/ld64.so.1;:/lib64/ld64.so.2}"
> +#else
> +#define GLIBC_DYNAMIC_LINKER64 "%{mabi=elfv2:/lib64/ld64.so.2;:/lib64/ld64.so.1}"
> +#endif
>  #define UCLIBC_DYNAMIC_LINKER32 "/lib/ld-uClibc.so.0"
>  #define UCLIBC_DYNAMIC_LINKER64 "/lib/ld64-uClibc.so.0"
>  #if DEFAULT_LIBC == LIBC_UCLIBC
> Index: gcc-4_8-test/gcc/config/rs6000/option-defaults.h
> ===================================================================
> --- gcc-4_8-test.orig/gcc/config/rs6000/option-defaults.h
> +++ gcc-4_8-test/gcc/config/rs6000/option-defaults.h
> @@ -54,6 +54,7 @@
>     --with-float is ignored if -mhard-float or -msoft-float are
>       specified.  */
>  #define OPTION_DEFAULT_SPECS \
> +  {"abi", "%{!mabi=elfv*:-mabi=%(VALUE)}" }, \
>    {"tune", "%{!mtune=*:%{!mcpu=*:-mtune=%(VALUE)}}" }, \
>    {"tune_32", "%{" OPT_ARCH32 ":%{!mtune=*:%{!mcpu=*:-mtune=%(VALUE)}}}" }, \
>    {"tune_64", "%{" OPT_ARCH64 ":%{!mtune=*:%{!mcpu=*:-mtune=%(VALUE)}}}" }, \
> Index: gcc-4_8-test/gcc/config/rs6000/ppc-asm.h
> ===================================================================
> --- gcc-4_8-test.orig/gcc/config/rs6000/ppc-asm.h
> +++ gcc-4_8-test/gcc/config/rs6000/ppc-asm.h
> @@ -256,7 +256,30 @@ see the files COPYING3 and COPYING.RUNTI
>   * the real function with one or two leading periods respectively.
>   */
>  
> -#if defined (__powerpc64__)
> +#if defined(__powerpc64__) && _CALL_ELF == 2
> +
> +/* Defining "toc" above breaks @toc in assembler code.  */
> +#undef toc
> +
> +#define FUNC_NAME(name) GLUE(__USER_LABEL_PREFIX__,name)
> +#define JUMP_TARGET(name) FUNC_NAME(name)
> +#define FUNC_START(name) \
> +	.type FUNC_NAME(name),@function; \
> +	.globl FUNC_NAME(name); \
> +FUNC_NAME(name): \
> +0:	addis 2,12,(.TOC.-0b)@ha; \
> +	addi 2,2,(.TOC.-0b)@l; \
> +	.localentry FUNC_NAME(name),.-FUNC_NAME(name)
> +
> +#define HIDDEN_FUNC(name) \
> +  FUNC_START(name) \
> +  .hidden FUNC_NAME(name);
> +
> +#define FUNC_END(name) \
> +	.size FUNC_NAME(name),.-FUNC_NAME(name)
> +
> +#elif defined (__powerpc64__)
> +
>  #define FUNC_NAME(name) GLUE(.,name)
>  #define JUMP_TARGET(name) FUNC_NAME(name)
>  #define FUNC_START(name) \
> Index: gcc-4_8-test/gcc/config/rs6000/rs6000-c.c
> ===================================================================
> --- gcc-4_8-test.orig/gcc/config/rs6000/rs6000-c.c
> +++ gcc-4_8-test/gcc/config/rs6000/rs6000-c.c
> @@ -461,6 +461,10 @@ rs6000_cpu_cpp_builtins (cpp_reader *pfi
>      case ABI_AIX:
>        builtin_define ("_CALL_AIXDESC");
>        builtin_define ("_CALL_AIX");
> +      builtin_define ("_CALL_ELF=1");
> +      break;
> +    case ABI_ELFv2:
> +      builtin_define ("_CALL_ELF=2");
>        break;
>      case ABI_DARWIN:
>        builtin_define ("_CALL_DARWIN");
> @@ -473,6 +477,13 @@ rs6000_cpu_cpp_builtins (cpp_reader *pfi
>    if (TARGET_SOFT_FLOAT || !TARGET_FPRS)
>      builtin_define ("__NO_FPRS__");
>  
> +  /* Whether aggregates passed by value are aligned to a 16 byte boundary
> +     if their alignment is 16 bytes or larger.  */
> +  if ((TARGET_MACHO && rs6000_darwin64_abi)
> +      || DEFAULT_ABI == ABI_ELFv2
> +      || (DEFAULT_ABI == ABI_AIX && !rs6000_compat_align_parm))
> +    builtin_define ("__STRUCT_PARM_ALIGN__=16");
> +
>    /* Generate defines for Xilinx FPU. */
>    if (rs6000_xilinx_fpu) 
>      {
> Index: gcc-4_8-test/gcc/config/rs6000/rs6000-opts.h
> ===================================================================
> --- gcc-4_8-test.orig/gcc/config/rs6000/rs6000-opts.h
> +++ gcc-4_8-test/gcc/config/rs6000/rs6000-opts.h
> @@ -101,7 +101,8 @@ enum group_termination
>  /* Enumeration to give which calling sequence to use.  */
>  enum rs6000_abi {
>    ABI_NONE,
> -  ABI_AIX,			/* IBM's AIX */
> +  ABI_AIX,			/* IBM's AIX, or Linux ELFv1 */
> +  ABI_ELFv2,			/* Linux ELFv2 ABI */
>    ABI_V4,			/* System V.4/eabi */
>    ABI_DARWIN			/* Apple's Darwin (OS X kernel) */
>  };
> Index: gcc-4_8-test/gcc/config/rs6000/rs6000.opt
> ===================================================================
> --- gcc-4_8-test.orig/gcc/config/rs6000/rs6000.opt
> +++ gcc-4_8-test/gcc/config/rs6000/rs6000.opt
> @@ -366,6 +366,14 @@ mabi=no-spe
>  Target RejectNegative Var(rs6000_spe_abi, 0)
>  Do not use the SPE ABI extensions
>  
> +mabi=elfv1
> +Target RejectNegative Var(rs6000_elf_abi, 1) Save
> +Use the ELFv1 ABI
> +
> +mabi=elfv2
> +Target RejectNegative Var(rs6000_elf_abi, 2)
> +Use the ELFv2 ABI
> +
>  ; These are here for testing during development only, do not document
>  ; in the manual please.
>  
> Index: gcc-4_8-test/gcc/testsuite/gcc.dg/stack-usage-1.c
> ===================================================================
> --- gcc-4_8-test.orig/gcc/testsuite/gcc.dg/stack-usage-1.c
> +++ gcc-4_8-test/gcc/testsuite/gcc.dg/stack-usage-1.c
> @@ -38,7 +38,11 @@
>  #  endif
>  #elif defined (__powerpc64__) || defined (__ppc64__) || defined (__POWERPC64__) \
>        || defined (__PPC64__)
> -#  define SIZE 180
> +#  if _CALL_ELF == 2
> +#     define SIZE 208
> +#  else
> +#     define SIZE 180
> +#  endif
>  #elif defined (__powerpc__) || defined (__PPC__) || defined (__ppc__) \
>        || defined (__POWERPC__) || defined (PPC) || defined (_IBMR2)
>  #  if defined (__ALTIVEC__)
> Index: gcc-4_8-test/gcc/testsuite/gcc.target/powerpc/no-r11-1.c
> ===================================================================
> --- gcc-4_8-test.orig/gcc/testsuite/gcc.target/powerpc/no-r11-1.c
> +++ gcc-4_8-test/gcc/testsuite/gcc.target/powerpc/no-r11-1.c
> @@ -1,5 +1,6 @@
>  /* { dg-do compile { target { powerpc*-*-* && lp64 } } } */
>  /* { dg-skip-if "" { *-*-darwin* } { "*" } { "" } } */
> +/* { dg-skip-if "" { powerpc_elfv2 } { "*" } { "" } } */
>  /* { dg-options "-O2 -mno-pointers-to-nested-functions" } */
>  
>  int
> Index: gcc-4_8-test/gcc/testsuite/gcc.target/powerpc/no-r11-2.c
> ===================================================================
> --- gcc-4_8-test.orig/gcc/testsuite/gcc.target/powerpc/no-r11-2.c
> +++ gcc-4_8-test/gcc/testsuite/gcc.target/powerpc/no-r11-2.c
> @@ -1,5 +1,6 @@
>  /* { dg-do compile { target { powerpc*-*-* && lp64 } } } */
>  /* { dg-skip-if "" { *-*-darwin* } { "*" } { "" } } */
> +/* { dg-skip-if "" { powerpc_elfv2 } { "*" } { "" } } */
>  /* { dg-options "-O2 -mpointers-to-nested-functions" } */
>  
>  int
> Index: gcc-4_8-test/gcc/testsuite/gcc.target/powerpc/no-r11-3.c
> ===================================================================
> --- gcc-4_8-test.orig/gcc/testsuite/gcc.target/powerpc/no-r11-3.c
> +++ gcc-4_8-test/gcc/testsuite/gcc.target/powerpc/no-r11-3.c
> @@ -1,5 +1,6 @@
>  /* { dg-do compile { target { powerpc*-*-* && lp64 } } } */
>  /* { dg-skip-if "" { *-*-darwin* } { "*" } { "" } } */
> +/* { dg-skip-if "" { powerpc_elfv2 } { "*" } { "" } } */
>  /* { dg-options "-O2 -mno-pointers-to-nested-functions" } */
>  
>  extern void ext_call (int (func) (void));
> Index: gcc-4_8-test/gcc/testsuite/gcc.target/powerpc/ppc64-abi-1.c
> ===================================================================
> --- gcc-4_8-test.orig/gcc/testsuite/gcc.target/powerpc/ppc64-abi-1.c
> +++ gcc-4_8-test/gcc/testsuite/gcc.target/powerpc/ppc64-abi-1.c
> @@ -89,8 +89,10 @@ typedef struct sf
>    long a1;
>    long a2;
>    long a3;
> +#if _CALL_ELF != 2
>    long a4;
>    long a5;
> +#endif
>    parm_t slot[100];
>  } stack_frame_t;
>  
> Index: gcc-4_8-test/gcc/testsuite/gcc.target/powerpc/ppc64-abi-2.c
> ===================================================================
> --- gcc-4_8-test.orig/gcc/testsuite/gcc.target/powerpc/ppc64-abi-2.c
> +++ gcc-4_8-test/gcc/testsuite/gcc.target/powerpc/ppc64-abi-2.c
> @@ -107,8 +107,10 @@ typedef struct sf
>    long a1;
>    long a2;
>    long a3;
> +#if _CALL_ELF != 2
>    long a4;
>    long a5;
> +#endif
>    parm_t slot[100];
>  } stack_frame_t;
>  
> Index: gcc-4_8-test/gcc/testsuite/gcc.target/powerpc/ppc64-abi-dfp-1.c
> ===================================================================
> --- gcc-4_8-test.orig/gcc/testsuite/gcc.target/powerpc/ppc64-abi-dfp-1.c
> +++ gcc-4_8-test/gcc/testsuite/gcc.target/powerpc/ppc64-abi-dfp-1.c
> @@ -33,15 +33,27 @@ reg_parms_t gparms;
>  
> 
>  /* Wrapper to save the GPRs and FPRs and then jump to the real function.  */
> +#if _CALL_ELF != 2
> +#define FUNC_START(NAME)						\
> +	"\t.globl\t" NAME "\n\t"					\
> +         ".section \".opd\",\"aw\"\n\t"					\
> +         ".align 3\n"							\
> +         NAME ":\n\t"							\
> +         ".quad .L." NAME ",.TOC.@tocbase,0\n\t"			\
> +         ".text\n\t"							\
> +         ".type " NAME ", @function\n"					\
> +         ".L." NAME ":\n\t"
> +#else
> +#define FUNC_START(NAME)						\
> +	"\t.globl\t" NAME "\n\t"					\
> +         ".text\n\t"							\
> +         NAME ":\n"							\
> +	"0:\taddis 2,12,(.TOC.-0b)@ha\n\t"				\
> +	"addi 2,2,(.TOC.-0b)@l\n\t"					\
> +	".localentry " NAME ",.-" NAME "\n\t"
> +#endif
>  #define WRAPPER(NAME)							\
> -__asm__ ("\t.globl\t" #NAME "_asm\n\t"					\
> -	 ".section \".opd\",\"aw\"\n\t"					\
> -	 ".align 3\n"							\
> -	 #NAME "_asm:\n\t"						\
> -	 ".quad .L." #NAME "_asm,.TOC.@tocbase,0\n\t"			\
> -	 ".text\n\t"							\
> -	 ".type " #NAME "_asm, @function\n"				\
> -	 ".L." #NAME "_asm:\n\t"					\
> +__asm__ (FUNC_START (#NAME "_asm")					\
>  	 "ld 11,gparms@got(2)\n\t"					\
>  	 "std 3,0(11)\n\t"						\
>  	 "std 4,8(11)\n\t"						\
> @@ -75,8 +87,10 @@ typedef struct sf
>    long a1;
>    long a2;
>    long a3;
> +#if _CALL_ELF != 2
>    long a4;
>    long a5;
> +#endif
>    unsigned long slot[100];
>  } stack_frame_t;
>  
> Index: gcc-4_8-test/gcc/testsuite/gcc.target/powerpc/pr57949-1.c
> ===================================================================
> --- gcc-4_8-test.orig/gcc/testsuite/gcc.target/powerpc/pr57949-1.c
> +++ gcc-4_8-test/gcc/testsuite/gcc.target/powerpc/pr57949-1.c
> @@ -1,5 +1,6 @@
>  /* { dg-do compile { target { powerpc64*-*-* && lp64 } } } */
>  /* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */
> +/* { dg-skip-if "" { powerpc_elfv2 } { "*" } { "" } } */
>  /* { dg-options "-O2 -mcpu=power7 -mno-compat-align-parm" } */
>  
>  /* Verify that vs is 16-byte aligned with -mcompat-align-parm.  */
> Index: gcc-4_8-test/gcc/testsuite/gcc.target/powerpc/pr57949-2.c
> ===================================================================
> --- gcc-4_8-test.orig/gcc/testsuite/gcc.target/powerpc/pr57949-2.c
> +++ gcc-4_8-test/gcc/testsuite/gcc.target/powerpc/pr57949-2.c
> @@ -1,5 +1,6 @@
>  /* { dg-do compile { target { powerpc64*-*-* && lp64 } } } */
>  /* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */
> +/* { dg-skip-if "" { powerpc_elfv2 } { "*" } { "" } } */
>  /* { dg-options "-O2 -mcpu=power7" } */
>  
>  /* Verify that vs is not 16-byte aligned in the absence of -mno-compat-align-parm.  */
> Index: gcc-4_8-test/gcc/testsuite/lib/target-supports.exp
> ===================================================================
> --- gcc-4_8-test.orig/gcc/testsuite/lib/target-supports.exp
> +++ gcc-4_8-test/gcc/testsuite/lib/target-supports.exp
> @@ -2868,6 +2868,22 @@ proc check_effective_target_powerpc_405_
>      }
>  }
>  
> +# Return 1 if this is a PowerPC target using the ELFv2 ABI.
> +
> +proc check_effective_target_powerpc_elfv2 { } {
> +    if { [istarget powerpc*-*-*] } {
> +	return [check_no_compiler_messages powerpc_elfv2 object {
> +	    #if _CALL_ELF != 2
> +	    #error not ELF v2 ABI
> +	    #else
> +	    int dummy;
> +	    #endif
> +	}]
> +    } else {
> +	return 0
> +    }
> +}
> +
>  # Return 1 if this is a SPU target with a toolchain that
>  # supports automatic overlay generation.
>  
> Index: gcc-4_8-test/libgcc/config/rs6000/tramp.S
> ===================================================================
> --- gcc-4_8-test.orig/libgcc/config/rs6000/tramp.S
> +++ gcc-4_8-test/libgcc/config/rs6000/tramp.S
> @@ -116,4 +116,70 @@ FUNC_END(__trampoline_setup)
>  
>  #endif
>  
> +#elif _CALL_ELF == 2
> +	.type	trampoline_initial,@object
> +	.align	3
> +trampoline_initial:
> +	ld	r11,.Lchain(r12)
> +	ld	r12,.Lfunc(r12)
> +	mtctr	r12
> +	bctr
> +.Lfunc = .-trampoline_initial
> +	.quad	0			/* will be replaced with function address */
> +.Lchain = .-trampoline_initial
> +	.quad	0			/* will be replaced with static chain */
> +
> +trampoline_size = .-trampoline_initial
> +	.size	trampoline_initial,trampoline_size
> +
> +
> +/* R3 = stack address to store trampoline */
> +/* R4 = length of trampoline area */
> +/* R5 = function address */
> +/* R6 = static chain */
> +
> +	.pushsection ".toc","aw"
> +.LC0:
> +	.quad	trampoline_initial-8
> +	.popsection
> +
> +FUNC_START(__trampoline_setup)
> +	addis 7,2,.LC0@toc@ha
> +	ld 7,.LC0@toc@l(7)	/* trampoline address -8 */
> +
> +	li	r8,trampoline_size	/* verify that the trampoline is big enough */
> +	cmpw	cr1,r8,r4
> +	srwi	r4,r4,3		/* # doublewords to move */
> +	addi	r9,r3,-8	/* adjust pointer for stdu */
> +	mtctr	r4
> +	blt	cr1,.Labort
> +
> +	/* Copy the instructions to the stack */
> +.Lmove:
> +	ldu	r10,8(r7)
> +	stdu	r10,8(r9)
> +	bdnz	.Lmove
> +
> +	/* Store correct function and static chain */
> +	std	r5,.Lfunc(r3)
> +	std	r6,.Lchain(r3)
> +
> +	/* Now flush both caches */
> +	mtctr	r4
> +.Lcache:
> +	icbi	0,r3
> +	dcbf	0,r3
> +	addi	r3,r3,8
> +	bdnz	.Lcache
> +
> +	/* Finally synchronize things & return */
> +	sync
> +	isync
> +	blr
> +
> +.Labort:
> +	bl	JUMP_TARGET(abort)
> +	nop
> +FUNC_END(__trampoline_setup)
> +
>  #endif
> Index: gcc-4_8-test/libitm/config/powerpc/sjlj.S
> ===================================================================
> --- gcc-4_8-test.orig/libitm/config/powerpc/sjlj.S
> +++ gcc-4_8-test/libitm/config/powerpc/sjlj.S
> @@ -26,7 +26,26 @@
>  
>  #include "asmcfi.h"
>  
> -#if defined(__powerpc64__) && defined(__ELF__)
> +#if defined(__powerpc64__) && _CALL_ELF == 2
> +.macro FUNC name
> +        .globl  \name
> +        .type   \name, @function
> +\name:
> +0:	addis 2,12,(.TOC.-0b)@ha
> +	addi 2,2,(.TOC.-0b)@l
> +	.localentry \name, . - \name
> +.endm
> +.macro END name
> +	.size	\name, . - \name
> +.endm
> +.macro HIDDEN name
> +	.hidden	\name
> +.endm
> +.macro CALL name
> +	bl	\name
> +	nop
> +.endm
> +#elif defined(__powerpc64__) && defined(__ELF__)
>  .macro FUNC name
>          .globl  \name, .\name
>          .section ".opd","aw"
> @@ -117,6 +136,9 @@ _$0:
>  #if defined(_CALL_AIXDESC)
>  # define BASE		6*WS
>  # define LR_SAVE	2*WS
> +#elif _CALL_ELF == 2
> +# define BASE		6*WS
> +# define LR_SAVE	2*WS
>  #elif defined(_CALL_SYSV)
>  # define BASE		2*WS
>  # define LR_SAVE	1*WS
> Index: gcc-4_8-test/libstdc++-v3/scripts/extract_symvers.in
> ===================================================================
> --- gcc-4_8-test.orig/libstdc++-v3/scripts/extract_symvers.in
> +++ gcc-4_8-test/libstdc++-v3/scripts/extract_symvers.in
> @@ -53,6 +53,7 @@ SunOS)
>    # present on Solaris.
>    ${readelf} ${lib} |\
>    sed -e 's/ \[<other>: [A-Fa-f0-9]*\] //' -e '/\.dynsym/,/^$/p;d' |\
> +  sed -e 's/ \[<localentry>: [0-9]*\] //' |\
>    egrep -v ' (LOCAL|UND) ' |\
>    egrep -v ' (_DYNAMIC|_GLOBAL_OFFSET_TABLE_|_PROCEDURE_LINKAGE_TABLE_|_edata|_end|_etext)$' |\
>    sed -e 's/ <processor specific>: / <processor_specific>:_/g' |\
> Index: gcc-4_8-test/gcc/config/rs6000/sysv4le.h
> ===================================================================
> --- gcc-4_8-test.orig/gcc/config/rs6000/sysv4le.h
> +++ gcc-4_8-test/gcc/config/rs6000/sysv4le.h
> @@ -34,3 +34,7 @@
>  
>  #undef	MULTILIB_DEFAULTS
>  #define	MULTILIB_DEFAULTS { "mlittle", "mcall-sysv" }
> +
> +/* Little-endian PowerPC64 Linux uses the ELF v2 ABI by default.  */
> +#define LINUX64_DEFAULT_ABI_ELFv2
> +
> Index: gcc-4_8-test/gcc/doc/invoke.texi
> ===================================================================
> --- gcc-4_8-test.orig/gcc/doc/invoke.texi
> +++ gcc-4_8-test/gcc/doc/invoke.texi
> @@ -17822,7 +17822,8 @@ SVR4 ABI)@.
>  @opindex mabi
>  Extend the current ABI with a particular extension, or remove such extension.
>  Valid values are @var{altivec}, @var{no-altivec}, @var{spe},
> -@var{no-spe}, @var{ibmlongdouble}, @var{ieeelongdouble}@.
> +@var{no-spe}, @var{ibmlongdouble}, @var{ieeelongdouble},
> +@var{elfv1}, @var{elfv2}@.
>  
>  @item -mabi=spe
>  @opindex mabi=spe
> @@ -17844,6 +17845,20 @@ This is a PowerPC 32-bit SYSV ABI option
>  Change the current ABI to use IEEE extended-precision long double.
>  This is a PowerPC 32-bit Linux ABI option.
>  
> +@item -mabi=elfv1
> +@opindex mabi=elfv1
> +Change the current ABI to use the ELFv1 ABI.
> +This is the default ABI for big-endian PowerPC 64-bit Linux.
> +Overriding the default ABI requires special system support and is
> +likely to fail in spectacular ways.
> +
> +@item -mabi=elfv2
> +@opindex mabi=elfv2
> +Change the current ABI to use the ELFv2 ABI.
> +This is the default ABI for little-endian PowerPC 64-bit Linux.
> +Overriding the default ABI requires special system support and is
> +likely to fail in spectacular ways.
> +
>  @item -mprototype
>  @itemx -mno-prototype
>  @opindex mprototype
> 
> 
> 
> 
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE / SUSE Labs
SUSE LINUX Products GmbH - Nuernberg - AG Nuernberg - HRB 16746
GF: Jeff Hawn, Jennifer Guild, Felix Imend"orffer


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]