diff mbox series

[ppc/darwin,2/2] Make Darwin's call handling follow the style of AIX/ELFv2/sysv.

Message ID 717C1E4D-2D29-4278-BD07-9E97512F3A7E@sandoe.co.uk
State New
Headers show
Series [ppc/darwin,1/2] Fix bootstrap. | expand

Commit Message

Iain Sandoe Dec. 3, 2018, 1:28 a.m. UTC
Hi,

The second patch normalises Darwin’s call handling to follow the same pattern that Alan introduced recently.

Hopefully it makes it clearer where there are differences (actually quite small in this case, but enough to make it better to separate the lowering).  It isn’t needed to fix bootstrap, but it was a good time to figure it out when dealing with this.

OK for trunk / next stage #1 / comments?
Iain

gcc/

	* config/rs6000/rs6000-protos.h (rs6000_call_darwin, rs6000_sibcall_darwin): New.
	(macho_call_template): remove.
	* config/rs6000/rs6000.c (get_prev_label): Forward declaration. 
	(rs6000_call_template_1): Handle Darwin. (macho_call_template): Remove.
	(rs6000_call_sysv): Remove handling for Darwin, save cookie value.
	(rs6000_call_darwin_1, rs6000_call_darwin, rs6000_sibcall_darwin): New.
	* config/rs6000/rs6000.md (define_expand “call”): Handle Darwin with its own
	expander. (define_expand “call_value”): Likewise. (define_expand “sibcall”): Likewise.
	(define_expand “sibcall_value”): Likewise.  (call_nonlocal_sysv): Remove 
	Darwin special-casing.  (call_value_nonlocal_sysv): Likewise.

From cf45459dc7f317bcf5f415219884e6b846fe01a1 Mon Sep 17 00:00:00 2001
From: Iain Sandoe <iain@sandoe.co.uk>
Date: Sat, 1 Dec 2018 16:23:20 +0000
Subject: [PATCH] [darwin,ppc] Update call expansions to follow the new scheme.

This also makes it a bit more apparent what we can remove when the
mlongcall optimisation is removed.
---
 gcc/config/rs6000/rs6000-protos.h |   8 +-
 gcc/config/rs6000/rs6000.c        | 195 +++++++++++++++++++++---------
 gcc/config/rs6000/rs6000.md       |  47 +++++--
 3 files changed, 180 insertions(+), 70 deletions(-)

Comments

Iain Sandoe Dec. 3, 2018, 7:18 p.m. UTC | #1
> On 3 Dec 2018, at 01:28, Iain Sandoe <iain@sandoe.co.uk> wrote:

> The second patch normalises Darwin’s call handling to follow the same pattern that Alan introduced recently.

revised version, on top of the revised patch 1 attached.  I’ve taken the opportunity to reduce the number of TARGET_MACHO conditionals in rs6000.md (handle in rs6000.c instead)

Iain

> Hopefully it makes it clearer where there are differences (actually quite small in this case, but enough to make it better to separate the lowering).  It isn’t needed to fix bootstrap, but it was a good time to figure it out when dealing with this.
> 
> OK for trunk / next stage #1 / comments?
> Iain
> 
> gcc/
> 
> 	* config/rs6000/rs6000-protos.h (rs6000_call_darwin, rs6000_sibcall_darwin): New.
> 	(macho_call_template): remove.
> 	* config/rs6000/rs6000.c (get_prev_label): Forward declaration. 
> 	(rs6000_call_template_1): Handle Darwin. (macho_call_template): Remove.
> 	(rs6000_call_sysv): Remove handling for Darwin, save cookie value.
> 	(rs6000_call_darwin_1, rs6000_call_darwin, rs6000_sibcall_darwin): New.
> 	* config/rs6000/rs6000.md (define_expand “call”): Handle Darwin with its own
> 	expander. (define_expand “call_value”): Likewise. (define_expand “sibcall”): Likewise.
> 	(define_expand “sibcall_value”): Likewise.  (call_nonlocal_sysv): Remove 
> 	Darwin special-casing.  (call_value_nonlocal_sysv): Likewise.
> 
> From cf45459dc7f317bcf5f415219884e6b846fe01a1 Mon Sep 17 00:00:00 2001
> From: Iain Sandoe <iain@sandoe.co.uk>
> Date: Sat, 1 Dec 2018 16:23:20 +0000
> Subject: [PATCH] [darwin,ppc] Update call expansions to follow the new scheme.
> 
> This also makes it a bit more apparent what we can remove when the
> mlongcall optimisation is removed.
> ---
> gcc/config/rs6000/rs6000-protos.h |   8 +-
> gcc/config/rs6000/rs6000.c        | 195 +++++++++++++++++++++---------
> gcc/config/rs6000/rs6000.md       |  47 +++++--
> 3 files changed, 180 insertions(+), 70 deletions(-)
> 
> diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h
> index dfee1f28aa..6d2b7ed917 100644
> --- a/gcc/config/rs6000/rs6000-protos.h
> +++ b/gcc/config/rs6000/rs6000-protos.h
> @@ -199,6 +199,10 @@ extern void rs6000_call_aix (rtx, rtx, rtx, rtx);
> extern void rs6000_sibcall_aix (rtx, rtx, rtx, rtx);
> extern void rs6000_call_sysv (rtx, rtx, rtx, rtx);
> extern void rs6000_sibcall_sysv (rtx, rtx, rtx, rtx);
> +#if TARGET_MACHO
> +extern void rs6000_call_darwin (rtx, rtx, rtx, rtx);
> +extern void rs6000_sibcall_darwin (rtx, rtx, rtx, rtx);
> +#endif
> 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);
> @@ -226,10 +230,6 @@ extern void (*rs6000_target_modify_macros_ptr) (bool, HOST_WIDE_INT,
> /* Declare functions in rs6000-d.c  */
> extern void rs6000_d_target_versions (void);
> 
> -#if TARGET_MACHO
> -char *macho_call_template (rtx_insn *, rtx *, int, int);
> -#endif
> -
> #ifdef NO_DOLLAR_IN_LABEL
> const char * rs6000_xcoff_strip_dollar (const char *);
> #endif
> diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
> index bce968516c..5fef3fa036 100644
> --- a/gcc/config/rs6000/rs6000.c
> +++ b/gcc/config/rs6000/rs6000.c
> @@ -1364,6 +1364,7 @@ static rtx rs6000_darwin64_record_arg (CUMULATIVE_ARGS *, const_tree,
> 				       bool, bool);
> #if TARGET_MACHO
> static void macho_branch_islands (void);
> +static tree get_prev_label (tree);
> #endif
> static rtx rs6000_legitimize_reload_address (rtx, machine_mode, int, int,
> 					     int, int *);
> @@ -21513,13 +21514,39 @@ rs6000_call_template_1 (rtx *operands, unsigned int funop, bool sibcall)
> 	    ? "+32768" : ""));
> 
>   static char str[32];  /* 2 spare */
> -  if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2
> -      || DEFAULT_ABI == ABI_DARWIN)
> +  if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
>     sprintf (str, "b%s %s%s%s", sibcall ? "" : "l", z, arg,
> 	     sibcall ? "" : "\n\tnop");
>   else if (DEFAULT_ABI == ABI_V4)
>     sprintf (str, "b%s %s%s%s", sibcall ? "" : "l", z, arg,
> 	     flag_pic ? "@plt" : "");
> +#if TARGET_MACHO
> +  /* If/when we remove the mlongcall opt, we can share the AIX/ELFv2 case. */
> +   else if (DEFAULT_ABI == ABI_DARWIN)
> +    {
> +      /* The cookie is in operand func+2.  */
> +      gcc_checking_assert (GET_CODE (operands[funop + 2]) == CONST_INT);
> +      int cookie = INTVAL (operands[funop + 2]);
> +      if (cookie & CALL_LONG)
> +	{
> +	  tree funname = get_identifier (XSTR (operands[funop], 0));
> +	  tree labelname = get_prev_label (funname);
> +	  gcc_checking_assert (labelname && !sibcall);
> +
> +	  /* "jbsr foo, L42" is Mach-O for "Link as 'bl foo' if a 'bl'
> +	     instruction will reach 'foo', otherwise link as 'bl L42'".
> +	     "L42" should be a 'branch island', that will do a far jump to
> +	     'foo'.  Branch islands are generated in
> +	     macho_branch_islands().  */
> +	  sprintf (str, "jbsr %%z%u,%.10s", funop,
> +		   IDENTIFIER_POINTER (labelname));
> +	}
> +      else
> +        /* Same as AIX or ELFv2, except to keep backwards compat, no nop
> +	   after the call.  */
> +	sprintf (str, "b%s %s%s", sibcall ? "" : "l", z, arg);
> +    }
> +#endif
>   else
>     gcc_unreachable ();
>   return str;
> @@ -33167,49 +33194,6 @@ get_prev_label (tree function_name)
>   return NULL_TREE;
> }
> 
> -/* INSN is either a function call or a millicode call.  It may have an
> -   unconditional jump in its delay slot.
> -
> -   CALL_DEST is the routine we are calling.  */
> -
> -char *
> -macho_call_template (rtx_insn *insn, rtx *operands, int dest_operand_number,
> -		     int cookie_operand_number)
> -{
> -  static char buf[256];
> -  if (darwin_emit_branch_islands
> -      && GET_CODE (operands[dest_operand_number]) == SYMBOL_REF
> -      && (INTVAL (operands[cookie_operand_number]) & CALL_LONG))
> -    {
> -      tree labelname;
> -      tree funname = get_identifier (XSTR (operands[dest_operand_number], 0));
> -
> -      if (no_previous_def (funname))
> -	{
> -	  rtx label_rtx = gen_label_rtx ();
> -	  char *label_buf, temp_buf[256];
> -	  ASM_GENERATE_INTERNAL_LABEL (temp_buf, "L",
> -				       CODE_LABEL_NUMBER (label_rtx));
> -	  label_buf = temp_buf[0] == '*' ? temp_buf + 1 : temp_buf;
> -	  labelname = get_identifier (label_buf);
> -	  add_compiler_branch_island (labelname, funname, insn_line (insn));
> -	}
> -      else
> -	labelname = get_prev_label (funname);
> -
> -      /* "jbsr foo, L42" is Mach-O for "Link as 'bl foo' if a 'bl'
> -	 instruction will reach 'foo', otherwise link as 'bl L42'".
> -	 "L42" should be a 'branch island', that will do a far jump to
> -	 'foo'.  Branch islands are generated in
> -	 macho_branch_islands().  */
> -      sprintf (buf, "jbsr %%z%d,%.246s",
> -	       dest_operand_number, IDENTIFIER_POINTER (labelname));
> -    }
> -  else
> -    sprintf (buf, "bl %%z%d", dest_operand_number);
> -  return buf;
> -}
> -
> /* Generate PIC and indirect symbol stubs.  */
> 
> void
> @@ -37932,13 +37916,13 @@ rs6000_call_sysv (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
>   rtx call[3];
>   rtx insn;
>   rtx abi_reg = NULL_RTX;
> +  int cookie_val = INTVAL (cookie);
> 
>   if (global_tlsarg)
>     tlsarg = global_tlsarg;
> 
>   /* Handle longcall attributes.  */
> -  if ((INTVAL (cookie) & CALL_LONG) != 0
> -      && DEFAULT_ABI != ABI_DARWIN /* Darwin does it's own thing.  */
> +  if ((cookie_val & CALL_LONG) != 0
>       && GET_CODE (func_desc) == SYMBOL_REF)
>     {
>       func = rs6000_longcall_ref (func_desc, tlsarg);
> @@ -37979,14 +37963,8 @@ rs6000_call_sysv (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
>   if (value != NULL_RTX)
>     call[0] = gen_rtx_SET (value, call[0]);
> 
> -  if (DEFAULT_ABI == ABI_DARWIN && TARGET_32BIT)
> -    call[1] = gen_rtx_USE (VOIDmode, GEN_INT (INTVAL (cookie)));
> -  else
> -    {
> -      unsigned int mask = CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS;
> -      call[1] = gen_rtx_USE (VOIDmode, GEN_INT (INTVAL (cookie) & mask));
> -    }
> -
> +  unsigned int mask = CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS;
> +  call[1] = gen_rtx_USE (VOIDmode, GEN_INT (cookie_val & mask));
>   call[2] = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, LR_REGNO));
> 
>   insn = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (3, call));
> @@ -38060,6 +38038,113 @@ rs6000_sibcall_sysv (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
>     use_reg (&CALL_INSN_FUNCTION_USAGE (insn), abi_reg);
> }
> 
> +#if TARGET_MACHO
> +
> +/* Expand code to perform a call under the Darwin ABI.
> +   Modulo handling of mlongcall, this is much the same as sysv.
> +   if/when the longcall optimisation is removed, we could drop this
> +   code and use the sysv case (taking care to avoid the tls stuff).
> +
> +   We can use this for sibcalls too, if needed.  */
> +
> +void
> +rs6000_call_darwin_1 (rtx value, rtx func_desc, rtx tlsarg,
> +		      rtx cookie, bool sibcall)
> +{
> +  rtx func = func_desc;
> +  rtx func_addr;
> +  rtx call[3];
> +  rtx insn;
> +  int cookie_val = INTVAL (cookie);
> +  bool make_island = false;
> +
> +  /* Handle longcall attributes, there are two cases for Darwin:
> +     1) Newer linkers are capable of synthesising any branch islands needed.
> +     2) We need a helper branch island synthesised by the compiler.
> +     The second case has mostly been retired and we don't use it for m64.
> +     In fact, it's is an optimisation, we could just indirect as sysv does..
> +     ... however, backwards compatibility for now.
> +     If we're going to use this, then we need to keep the CALL_LONG bit set,
> +     so that we can pick up the special insn form later.  */
> +  if ((cookie_val & CALL_LONG) != 0
> +      && GET_CODE (func_desc) == SYMBOL_REF)
> +    {
> +      if (darwin_emit_branch_islands && TARGET_32BIT)
> +	make_island = true; /* Do nothing yet, retain the CALL_LONG flag.  */
> +      else
> +	{
> +	  /* The linker is capable of doing this, but the user explicitly
> +	     asked for -mlongcall, so we'll do the 'normal' version.  */
> +	  func = rs6000_longcall_ref (func_desc, NULL_RTX);
> +	  cookie_val &= ~CALL_LONG; /* Handled, zap it.  */
> +	}
> +    }
> +
> +  /* Handle indirect calls.  */
> +  if (GET_CODE (func) != SYMBOL_REF)
> +    {
> +      func = force_reg (Pmode, func);
> +
> +      /* Indirect calls via CTR are strongly preferred over indirect
> +	 calls via LR, and are required for indirect sibcalls, so move
> +	 the address there.   */
> +      func_addr = gen_rtx_REG (Pmode, CTR_REGNO);
> +      emit_move_insn (func_addr, func);
> +    }
> +  else
> +    func_addr = func;
> +
> +  /* Create the call.  */
> +  call[0] = gen_rtx_CALL (VOIDmode, gen_rtx_MEM (SImode, func_addr), tlsarg);
> +  if (value != NULL_RTX)
> +    call[0] = gen_rtx_SET (value, call[0]);
> +
> +  call[1] = gen_rtx_USE (VOIDmode, GEN_INT (cookie_val));
> +
> +  if (sibcall)
> +    call[2] = simple_return_rtx;
> +  else
> +    call[2] = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, LR_REGNO));
> +
> +  insn = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (3, call));
> +  insn = emit_call_insn (insn);
> +  /* Now we have the debug info in the insn, we can set up the branch island
> +     if we're using one.  */
> +  if (make_island)
> +    {
> +      tree funname = get_identifier (XSTR (func_desc, 0));
> +
> +      if (no_previous_def (funname))
> +	{
> +	  rtx label_rtx = gen_label_rtx ();
> +	  char *label_buf, temp_buf[256];
> +	  ASM_GENERATE_INTERNAL_LABEL (temp_buf, "L",
> +				       CODE_LABEL_NUMBER (label_rtx));
> +	  label_buf = temp_buf[0] == '*' ? temp_buf + 1 : temp_buf;
> +	  tree labelname = get_identifier (label_buf);
> +	  add_compiler_branch_island (labelname, funname,
> +				     insn_line ((const rtx_insn*)insn));
> +	}
> +     }
> +}
> +
> +void
> +rs6000_call_darwin (rtx value, rtx func_desc,
> +		    rtx tlsarg ATTRIBUTE_UNUSED, rtx cookie)
> +{
> +  rs6000_call_darwin_1 (value, func_desc, tlsarg, cookie, false);
> +}
> +
> +
> +void
> +rs6000_sibcall_darwin (rtx value, rtx func_desc,
> +		       rtx tlsarg ATTRIBUTE_UNUSED, rtx cookie)
> +{
> +  rs6000_call_darwin_1 (value, func_desc, tlsarg, cookie, true);
> +}
> +
> +#endif
> +
> /* Return whether we need to always update the saved TOC pointer when we update
>    the stack pointer.  */
> 
> diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
> index d684bed3ae..e4a71439ef 100644
> --- a/gcc/config/rs6000/rs6000.md
> +++ b/gcc/config/rs6000/rs6000.md
> @@ -10289,12 +10289,20 @@
>       DONE;
>     }
> 
> -  if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_DARWIN)
> +  if (DEFAULT_ABI == ABI_V4)
>     {
>       rs6000_call_sysv (NULL_RTX, operands[0], operands[1], operands[2]);
>       DONE;
>     }
> 
> +#if TARGET_MACHO
> +  if (DEFAULT_ABI == ABI_DARWIN)
> +    {
> +      rs6000_call_darwin (NULL_RTX, operands[0], operands[1], operands[2]);
> +      DONE;
> +    }
> +#endif
> +
>   if (GET_CODE (operands[0]) != SYMBOL_REF)
>     operands[0] = force_reg (Pmode, operands[0]);
> })
> @@ -10322,12 +10330,20 @@
>       DONE;
>     }
> 
> -  if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_DARWIN)
> +  if (DEFAULT_ABI == ABI_V4)
>     {
>       rs6000_call_sysv (operands[0], operands[1], operands[2], operands[3]);
>       DONE;
>     }
> 
> +#if TARGET_MACHO
> +  if (DEFAULT_ABI == ABI_DARWIN)
> +    {
> +      rs6000_call_darwin (operands[0], operands[1], operands[2], operands[3]);
> +      DONE;
> +    }
> +#endif
> +
>   if (GET_CODE (operands[1]) != SYMBOL_REF)
>     operands[1] = force_reg (Pmode, operands[1]);
> })
> @@ -10463,11 +10479,7 @@
>   else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
>     output_asm_insn ("creqv 6,6,6", operands);
> 
> -#if TARGET_MACHO
> -  return macho_call_template (insn, operands, 0, 2);
> -#else
>   return rs6000_call_template (operands, 0);
> -#endif
> }
>   "DEFAULT_ABI == ABI_V4
>    && TARGET_SECURE_PLT && flag_pic && !SYMBOL_REF_LOCAL_P (operands[0])
> @@ -10549,11 +10561,7 @@
>   else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
>     output_asm_insn ("creqv 6,6,6", operands);
> 
> -#if TARGET_MACHO
> -  return macho_call_template (insn, operands, 1, 3);
> -#else
>   return rs6000_call_template (operands, 1);
> -#endif
> }
>   "DEFAULT_ABI == ABI_V4
>    && TARGET_SECURE_PLT && flag_pic && !SYMBOL_REF_LOCAL_P (operands[1])
> @@ -10771,6 +10779,14 @@
>       rs6000_sibcall_sysv (NULL_RTX, operands[0], operands[1], operands[2]);
>       DONE;
>     }
> +
> +#if TARGET_MACHO
> +  if (DEFAULT_ABI == ABI_DARWIN)
> +    {
> +      rs6000_sibcall_darwin (NULL_RTX, operands[0], operands[1], operands[2]);
> +      DONE;
> +    }
> +#endif
> })
> 
> (define_expand "sibcall_value"
> @@ -10797,11 +10813,20 @@
>       DONE;
>     }
> 
> -  if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_DARWIN)
> +  if (DEFAULT_ABI == ABI_V4)
>     {
>       rs6000_sibcall_sysv (operands[0], operands[1], operands[2], operands[3]);
>       DONE;
>     }
> +
> +#if TARGET_MACHO
> +  if (DEFAULT_ABI == ABI_DARWIN)
> +    {
> +      rs6000_sibcall_darwin (operands[0], operands[1],
> +			     operands[2], operands[3]);
> +      DONE;
> +    }
> +#endif
> })
> 
> (define_insn "*sibcall_local32"
> -- 
> 2.17.1
From 82ac030d49fd2ae78b75a350c5efc59375df42a6 Mon Sep 17 00:00:00 2001
From: Iain Sandoe <iain@sandoe.co.uk>
Date: Sat, 1 Dec 2018 16:23:20 +0000
Subject: [PATCH] [darwin,ppc] Update call expansions to follow the new scheme.

This also makes it a bit more apparent what we can remove when the
mlongcall optimisation is removed.
---
 gcc/config/rs6000/rs6000-protos.h |   6 +-
 gcc/config/rs6000/rs6000.c        | 205 ++++++++++++++++++++++--------
 gcc/config/rs6000/rs6000.md       |  24 ++--
 3 files changed, 163 insertions(+), 72 deletions(-)

diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h
index dfee1f28aa..5ac864e83e 100644
--- a/gcc/config/rs6000/rs6000-protos.h
+++ b/gcc/config/rs6000/rs6000-protos.h
@@ -199,6 +199,8 @@ extern void rs6000_call_aix (rtx, rtx, rtx, rtx);
 extern void rs6000_sibcall_aix (rtx, rtx, rtx, rtx);
 extern void rs6000_call_sysv (rtx, rtx, rtx, rtx);
 extern void rs6000_sibcall_sysv (rtx, rtx, rtx, rtx);
+extern void rs6000_call_darwin (rtx, rtx, rtx, rtx);
+extern void rs6000_sibcall_darwin (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);
@@ -226,10 +228,6 @@ extern void (*rs6000_target_modify_macros_ptr) (bool, HOST_WIDE_INT,
 /* Declare functions in rs6000-d.c  */
 extern void rs6000_d_target_versions (void);
 
-#if TARGET_MACHO
-char *macho_call_template (rtx_insn *, rtx *, int, int);
-#endif
-
 #ifdef NO_DOLLAR_IN_LABEL
 const char * rs6000_xcoff_strip_dollar (const char *);
 #endif
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index bce968516c..a036a3cb50 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -1364,6 +1364,7 @@ static rtx rs6000_darwin64_record_arg (CUMULATIVE_ARGS *, const_tree,
 				       bool, bool);
 #if TARGET_MACHO
 static void macho_branch_islands (void);
+static tree get_prev_label (tree);
 #endif
 static rtx rs6000_legitimize_reload_address (rtx, machine_mode, int, int,
 					     int, int *);
@@ -21513,13 +21514,39 @@ rs6000_call_template_1 (rtx *operands, unsigned int funop, bool sibcall)
 	    ? "+32768" : ""));
 
   static char str[32];  /* 2 spare */
-  if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2
-      || DEFAULT_ABI == ABI_DARWIN)
+  if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
     sprintf (str, "b%s %s%s%s", sibcall ? "" : "l", z, arg,
 	     sibcall ? "" : "\n\tnop");
   else if (DEFAULT_ABI == ABI_V4)
     sprintf (str, "b%s %s%s%s", sibcall ? "" : "l", z, arg,
 	     flag_pic ? "@plt" : "");
+#if TARGET_MACHO
+  /* If/when we remove the mlongcall opt, we can share the AIX/ELGv2 case. */
+   else if (DEFAULT_ABI == ABI_DARWIN)
+    {
+      /* The cookie is in operand func+2.  */
+      gcc_checking_assert (GET_CODE (operands[funop + 2]) == CONST_INT);
+      int cookie = INTVAL (operands[funop + 2]);
+      if (cookie & CALL_LONG)
+	{
+	  tree funname = get_identifier (XSTR (operands[funop], 0));
+	  tree labelname = get_prev_label (funname);
+	  gcc_checking_assert (labelname && !sibcall);
+
+	  /* "jbsr foo, L42" is Mach-O for "Link as 'bl foo' if a 'bl'
+	     instruction will reach 'foo', otherwise link as 'bl L42'".
+	     "L42" should be a 'branch island', that will do a far jump to
+	     'foo'.  Branch islands are generated in
+	     macho_branch_islands().  */
+	  sprintf (str, "jbsr %%z%u,%.10s", funop,
+		   IDENTIFIER_POINTER (labelname));
+	}
+      else
+        /* Same as AIX or ELFv2, except to keep backwards compat, no nop
+	   after the call.  */
+	sprintf (str, "b%s %s%s", sibcall ? "" : "l", z, arg);
+    }
+#endif
   else
     gcc_unreachable ();
   return str;
@@ -33122,7 +33149,7 @@ macho_branch_islands (void)
 	}
       else
 	{
-	  strcat (tmp_buf, ":\nlis r12,hi16(");
+	  strcat (tmp_buf, ":\n\tlis r12,hi16(");
 	  strcat (tmp_buf, name_buf);
 	  strcat (tmp_buf, ")\n\tori r12,r12,lo16(");
 	  strcat (tmp_buf, name_buf);
@@ -33167,49 +33194,6 @@ get_prev_label (tree function_name)
   return NULL_TREE;
 }
 
-/* INSN is either a function call or a millicode call.  It may have an
-   unconditional jump in its delay slot.
-
-   CALL_DEST is the routine we are calling.  */
-
-char *
-macho_call_template (rtx_insn *insn, rtx *operands, int dest_operand_number,
-		     int cookie_operand_number)
-{
-  static char buf[256];
-  if (darwin_emit_branch_islands
-      && GET_CODE (operands[dest_operand_number]) == SYMBOL_REF
-      && (INTVAL (operands[cookie_operand_number]) & CALL_LONG))
-    {
-      tree labelname;
-      tree funname = get_identifier (XSTR (operands[dest_operand_number], 0));
-
-      if (no_previous_def (funname))
-	{
-	  rtx label_rtx = gen_label_rtx ();
-	  char *label_buf, temp_buf[256];
-	  ASM_GENERATE_INTERNAL_LABEL (temp_buf, "L",
-				       CODE_LABEL_NUMBER (label_rtx));
-	  label_buf = temp_buf[0] == '*' ? temp_buf + 1 : temp_buf;
-	  labelname = get_identifier (label_buf);
-	  add_compiler_branch_island (labelname, funname, insn_line (insn));
-	}
-      else
-	labelname = get_prev_label (funname);
-
-      /* "jbsr foo, L42" is Mach-O for "Link as 'bl foo' if a 'bl'
-	 instruction will reach 'foo', otherwise link as 'bl L42'".
-	 "L42" should be a 'branch island', that will do a far jump to
-	 'foo'.  Branch islands are generated in
-	 macho_branch_islands().  */
-      sprintf (buf, "jbsr %%z%d,%.246s",
-	       dest_operand_number, IDENTIFIER_POINTER (labelname));
-    }
-  else
-    sprintf (buf, "bl %%z%d", dest_operand_number);
-  return buf;
-}
-
 /* Generate PIC and indirect symbol stubs.  */
 
 void
@@ -37932,13 +37916,13 @@ rs6000_call_sysv (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
   rtx call[3];
   rtx insn;
   rtx abi_reg = NULL_RTX;
+  int cookie_val = INTVAL (cookie);
 
   if (global_tlsarg)
     tlsarg = global_tlsarg;
 
   /* Handle longcall attributes.  */
-  if ((INTVAL (cookie) & CALL_LONG) != 0
-      && DEFAULT_ABI != ABI_DARWIN /* Darwin does it's own thing.  */
+  if ((cookie_val & CALL_LONG) != 0
       && GET_CODE (func_desc) == SYMBOL_REF)
     {
       func = rs6000_longcall_ref (func_desc, tlsarg);
@@ -37979,14 +37963,8 @@ rs6000_call_sysv (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
   if (value != NULL_RTX)
     call[0] = gen_rtx_SET (value, call[0]);
 
-  if (DEFAULT_ABI == ABI_DARWIN && TARGET_32BIT)
-    call[1] = gen_rtx_USE (VOIDmode, GEN_INT (INTVAL (cookie)));
-  else
-    {
-      unsigned int mask = CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS;
-      call[1] = gen_rtx_USE (VOIDmode, GEN_INT (INTVAL (cookie) & mask));
-    }
-
+  unsigned int mask = CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS;
+  call[1] = gen_rtx_USE (VOIDmode, GEN_INT (cookie_val & mask));
   call[2] = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, LR_REGNO));
 
   insn = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (3, call));
@@ -38060,6 +38038,121 @@ rs6000_sibcall_sysv (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
     use_reg (&CALL_INSN_FUNCTION_USAGE (insn), abi_reg);
 }
 
+#if TARGET_MACHO
+
+/* Expand code to perform a call under the Darwin ABI.
+   Modulo handling of mlongcall, this is much the same as sysv.
+   if/when the longcall optimisation is removed, we could drop this
+   code and use the sysv case (taking care to avoid the tls stuff).
+
+   We can use this for sibcalls too, if needed.  */
+
+void
+rs6000_call_darwin_1 (rtx value, rtx func_desc, rtx tlsarg,
+		      rtx cookie, bool sibcall)
+{
+  rtx func = func_desc;
+  rtx func_addr;
+  rtx call[3];
+  rtx insn;
+  int cookie_val = INTVAL (cookie);
+  bool make_island = false;
+
+  /* Handle longcall attributes, there are two cases for Darwin:
+     1) Newer linkers are capable of synthesising any branch islands needed.
+     2) We need a helper branch island synthesised by the compiler.
+     The second case has mostly been retired and we don't use it for m64.
+     In fact, it's is an optimisation, we could just indirect as sysv does..
+     ... however, backwards compatibility for now.
+     If we're going to use this, then we need to keep the CALL_LONG bit set,
+     so that we can pick up the special insn form later.  */
+  if ((cookie_val & CALL_LONG) != 0
+      && GET_CODE (func_desc) == SYMBOL_REF)
+    {
+      if (darwin_emit_branch_islands && TARGET_32BIT)
+	make_island = true; /* Do nothing yet, retain the CALL_LONG flag.  */
+      else
+	{
+	  /* The linker is capable of doing this, but the user explicitly
+	     asked for -mlongcall, so we'll do the 'normal' version.  */
+	  func = rs6000_longcall_ref (func_desc, NULL_RTX);
+	  cookie_val &= ~CALL_LONG; /* Handled, zap it.  */
+	}
+    }
+
+  /* Handle indirect calls.  */
+  if (GET_CODE (func) != SYMBOL_REF)
+    {
+      func = force_reg (Pmode, func);
+
+      /* Indirect calls via CTR are strongly preferred over indirect
+	 calls via LR, and are required for indirect sibcalls, so move
+	 the address there.   */
+      func_addr = gen_rtx_REG (Pmode, CTR_REGNO);
+      emit_move_insn (func_addr, func);
+    }
+  else
+    func_addr = func;
+
+  /* Create the call.  */
+  call[0] = gen_rtx_CALL (VOIDmode, gen_rtx_MEM (SImode, func_addr), tlsarg);
+  if (value != NULL_RTX)
+    call[0] = gen_rtx_SET (value, call[0]);
+
+  call[1] = gen_rtx_USE (VOIDmode, GEN_INT (cookie_val));
+
+  if (sibcall)
+    call[2] = simple_return_rtx;
+  else
+    call[2] = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, LR_REGNO));
+
+  insn = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (3, call));
+  insn = emit_call_insn (insn);
+  /* Now we have the debug info in the insn, we can set up the branch island
+     if we're using one.  */
+  if (make_island)
+    {
+      tree funname = get_identifier (XSTR (func_desc, 0));
+
+      if (no_previous_def (funname))
+	{
+	  rtx label_rtx = gen_label_rtx ();
+	  char *label_buf, temp_buf[256];
+	  ASM_GENERATE_INTERNAL_LABEL (temp_buf, "L",
+				       CODE_LABEL_NUMBER (label_rtx));
+	  label_buf = temp_buf[0] == '*' ? temp_buf + 1 : temp_buf;
+	  tree labelname = get_identifier (label_buf);
+	  add_compiler_branch_island (labelname, funname,
+				     insn_line ((const rtx_insn*)insn));
+	}
+     }
+}
+#endif
+
+void
+rs6000_call_darwin (rtx value ATTRIBUTE_UNUSED, rtx func_desc ATTRIBUTE_UNUSED,
+		    rtx tlsarg ATTRIBUTE_UNUSED, rtx cookie ATTRIBUTE_UNUSED)
+{
+#if TARGET_MACHO
+  rs6000_call_darwin_1 (value, func_desc, tlsarg, cookie, false);
+#else
+  gcc_unreachable();
+#endif
+}
+
+
+void
+rs6000_sibcall_darwin (rtx value ATTRIBUTE_UNUSED, rtx func_desc ATTRIBUTE_UNUSED,
+		       rtx tlsarg ATTRIBUTE_UNUSED, rtx cookie ATTRIBUTE_UNUSED)
+{
+#if TARGET_MACHO
+  rs6000_call_darwin_1 (value, func_desc, tlsarg, cookie, true);
+#else
+  gcc_unreachable();
+#endif
+}
+
+
 /* Return whether we need to always update the saved TOC pointer when we update
    the stack pointer.  */
 
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index f84b09b35a..6e6c984a51 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -10285,8 +10285,10 @@
 
   if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
     rs6000_call_aix (NULL_RTX, operands[0], operands[1], operands[2]);
-  else
+  else if (DEFAULT_ABI == ABI_V4)
     rs6000_call_sysv (NULL_RTX, operands[0], operands[1], operands[2]);
+  else
+    rs6000_call_darwin (NULL_RTX, operands[0], operands[1], operands[2]);
 
   DONE;
 })
@@ -10310,8 +10312,10 @@
 
   if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
     rs6000_call_aix (operands[0], operands[1], operands[2], operands[3]);
-  else
+  else if (DEFAULT_ABI == ABI_V4)
     rs6000_call_sysv (operands[0], operands[1], operands[2], operands[3]);
+  else
+    rs6000_call_darwin (operands[0], operands[1], operands[2], operands[3]);
 
   DONE;
 })
@@ -10447,11 +10451,7 @@
   else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
     output_asm_insn ("creqv 6,6,6", operands);
 
-#if TARGET_MACHO
-  return macho_call_template (insn, operands, 0, 2);
-#else
   return rs6000_call_template (operands, 0);
-#endif
 }
   "DEFAULT_ABI == ABI_V4
    && TARGET_SECURE_PLT && flag_pic && !SYMBOL_REF_LOCAL_P (operands[0])
@@ -10533,11 +10533,7 @@
   else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
     output_asm_insn ("creqv 6,6,6", operands);
 
-#if TARGET_MACHO
-  return macho_call_template (insn, operands, 1, 3);
-#else
   return rs6000_call_template (operands, 1);
-#endif
 }
   "DEFAULT_ABI == ABI_V4
    && TARGET_SECURE_PLT && flag_pic && !SYMBOL_REF_LOCAL_P (operands[1])
@@ -10746,8 +10742,10 @@
 
   if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
     rs6000_sibcall_aix (NULL_RTX, operands[0], operands[1], operands[2]);
-  else
+  else if (DEFAULT_ABI == ABI_V4)
     rs6000_sibcall_sysv (NULL_RTX, operands[0], operands[1], operands[2]);
+  else
+    rs6000_sibcall_darwin (NULL_RTX, operands[0], operands[1], operands[2]);
 
   DONE;
 })
@@ -10772,8 +10770,10 @@
 
   if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
     rs6000_sibcall_aix (operands[0], operands[1], operands[2], operands[3]);
-  else
+  else if (DEFAULT_ABI == ABI_V4)
     rs6000_sibcall_sysv (operands[0], operands[1], operands[2], operands[3]);
+  else
+    rs6000_sibcall_darwin (operands[0], operands[1], operands[2], operands[3]);
 
   DONE;
 })
Segher Boessenkool Dec. 4, 2018, 5:38 p.m. UTC | #2
On Mon, Dec 03, 2018 at 07:18:20PM +0000, Iain Sandoe wrote:
> revised version, on top of the revised patch 1 attached.  I’ve taken the opportunity to reduce the number of TARGET_MACHO conditionals in rs6000.md (handle in rs6000.c instead)

> From 82ac030d49fd2ae78b75a350c5efc59375df42a6 Mon Sep 17 00:00:00 2001
> From: Iain Sandoe <iain@sandoe.co.uk>
> Date: Sat, 1 Dec 2018 16:23:20 +0000
> Subject: [PATCH] [darwin,ppc] Update call expansions to follow the new scheme.
> 
> This also makes it a bit more apparent what we can remove when the
> mlongcall optimisation is removed.

> --- a/gcc/config/rs6000/rs6000.md
> +++ b/gcc/config/rs6000/rs6000.md
> @@ -10285,8 +10285,10 @@
>  
>    if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
>      rs6000_call_aix (NULL_RTX, operands[0], operands[1], operands[2]);
> -  else
> +  else if (DEFAULT_ABI == ABI_V4)
>      rs6000_call_sysv (NULL_RTX, operands[0], operands[1], operands[2]);
> +  else
> +    rs6000_call_darwin (NULL_RTX, operands[0], operands[1], operands[2]);

Maybe

  else if (DEFAULT_ABI == ABI_DARWIN)
    ...
  else
    gcc_unreachable ();

?  Similar elsewhere.

And I think I saw a missing space-before-opening-paren somewhere, but I
cannot find it now.  Okay for trunk, anyhow.


Segher
diff mbox series

Patch

diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h
index dfee1f28aa..6d2b7ed917 100644
--- a/gcc/config/rs6000/rs6000-protos.h
+++ b/gcc/config/rs6000/rs6000-protos.h
@@ -199,6 +199,10 @@  extern void rs6000_call_aix (rtx, rtx, rtx, rtx);
 extern void rs6000_sibcall_aix (rtx, rtx, rtx, rtx);
 extern void rs6000_call_sysv (rtx, rtx, rtx, rtx);
 extern void rs6000_sibcall_sysv (rtx, rtx, rtx, rtx);
+#if TARGET_MACHO
+extern void rs6000_call_darwin (rtx, rtx, rtx, rtx);
+extern void rs6000_sibcall_darwin (rtx, rtx, rtx, rtx);
+#endif
 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);
@@ -226,10 +230,6 @@  extern void (*rs6000_target_modify_macros_ptr) (bool, HOST_WIDE_INT,
 /* Declare functions in rs6000-d.c  */
 extern void rs6000_d_target_versions (void);
 
-#if TARGET_MACHO
-char *macho_call_template (rtx_insn *, rtx *, int, int);
-#endif
-
 #ifdef NO_DOLLAR_IN_LABEL
 const char * rs6000_xcoff_strip_dollar (const char *);
 #endif
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index bce968516c..5fef3fa036 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -1364,6 +1364,7 @@  static rtx rs6000_darwin64_record_arg (CUMULATIVE_ARGS *, const_tree,
 				       bool, bool);
 #if TARGET_MACHO
 static void macho_branch_islands (void);
+static tree get_prev_label (tree);
 #endif
 static rtx rs6000_legitimize_reload_address (rtx, machine_mode, int, int,
 					     int, int *);
@@ -21513,13 +21514,39 @@  rs6000_call_template_1 (rtx *operands, unsigned int funop, bool sibcall)
 	    ? "+32768" : ""));
 
   static char str[32];  /* 2 spare */
-  if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2
-      || DEFAULT_ABI == ABI_DARWIN)
+  if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
     sprintf (str, "b%s %s%s%s", sibcall ? "" : "l", z, arg,
 	     sibcall ? "" : "\n\tnop");
   else if (DEFAULT_ABI == ABI_V4)
     sprintf (str, "b%s %s%s%s", sibcall ? "" : "l", z, arg,
 	     flag_pic ? "@plt" : "");
+#if TARGET_MACHO
+  /* If/when we remove the mlongcall opt, we can share the AIX/ELFv2 case. */
+   else if (DEFAULT_ABI == ABI_DARWIN)
+    {
+      /* The cookie is in operand func+2.  */
+      gcc_checking_assert (GET_CODE (operands[funop + 2]) == CONST_INT);
+      int cookie = INTVAL (operands[funop + 2]);
+      if (cookie & CALL_LONG)
+	{
+	  tree funname = get_identifier (XSTR (operands[funop], 0));
+	  tree labelname = get_prev_label (funname);
+	  gcc_checking_assert (labelname && !sibcall);
+
+	  /* "jbsr foo, L42" is Mach-O for "Link as 'bl foo' if a 'bl'
+	     instruction will reach 'foo', otherwise link as 'bl L42'".
+	     "L42" should be a 'branch island', that will do a far jump to
+	     'foo'.  Branch islands are generated in
+	     macho_branch_islands().  */
+	  sprintf (str, "jbsr %%z%u,%.10s", funop,
+		   IDENTIFIER_POINTER (labelname));
+	}
+      else
+        /* Same as AIX or ELFv2, except to keep backwards compat, no nop
+	   after the call.  */
+	sprintf (str, "b%s %s%s", sibcall ? "" : "l", z, arg);
+    }
+#endif
   else
     gcc_unreachable ();
   return str;
@@ -33167,49 +33194,6 @@  get_prev_label (tree function_name)
   return NULL_TREE;
 }
 
-/* INSN is either a function call or a millicode call.  It may have an
-   unconditional jump in its delay slot.
-
-   CALL_DEST is the routine we are calling.  */
-
-char *
-macho_call_template (rtx_insn *insn, rtx *operands, int dest_operand_number,
-		     int cookie_operand_number)
-{
-  static char buf[256];
-  if (darwin_emit_branch_islands
-      && GET_CODE (operands[dest_operand_number]) == SYMBOL_REF
-      && (INTVAL (operands[cookie_operand_number]) & CALL_LONG))
-    {
-      tree labelname;
-      tree funname = get_identifier (XSTR (operands[dest_operand_number], 0));
-
-      if (no_previous_def (funname))
-	{
-	  rtx label_rtx = gen_label_rtx ();
-	  char *label_buf, temp_buf[256];
-	  ASM_GENERATE_INTERNAL_LABEL (temp_buf, "L",
-				       CODE_LABEL_NUMBER (label_rtx));
-	  label_buf = temp_buf[0] == '*' ? temp_buf + 1 : temp_buf;
-	  labelname = get_identifier (label_buf);
-	  add_compiler_branch_island (labelname, funname, insn_line (insn));
-	}
-      else
-	labelname = get_prev_label (funname);
-
-      /* "jbsr foo, L42" is Mach-O for "Link as 'bl foo' if a 'bl'
-	 instruction will reach 'foo', otherwise link as 'bl L42'".
-	 "L42" should be a 'branch island', that will do a far jump to
-	 'foo'.  Branch islands are generated in
-	 macho_branch_islands().  */
-      sprintf (buf, "jbsr %%z%d,%.246s",
-	       dest_operand_number, IDENTIFIER_POINTER (labelname));
-    }
-  else
-    sprintf (buf, "bl %%z%d", dest_operand_number);
-  return buf;
-}
-
 /* Generate PIC and indirect symbol stubs.  */
 
 void
@@ -37932,13 +37916,13 @@  rs6000_call_sysv (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
   rtx call[3];
   rtx insn;
   rtx abi_reg = NULL_RTX;
+  int cookie_val = INTVAL (cookie);
 
   if (global_tlsarg)
     tlsarg = global_tlsarg;
 
   /* Handle longcall attributes.  */
-  if ((INTVAL (cookie) & CALL_LONG) != 0
-      && DEFAULT_ABI != ABI_DARWIN /* Darwin does it's own thing.  */
+  if ((cookie_val & CALL_LONG) != 0
       && GET_CODE (func_desc) == SYMBOL_REF)
     {
       func = rs6000_longcall_ref (func_desc, tlsarg);
@@ -37979,14 +37963,8 @@  rs6000_call_sysv (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
   if (value != NULL_RTX)
     call[0] = gen_rtx_SET (value, call[0]);
 
-  if (DEFAULT_ABI == ABI_DARWIN && TARGET_32BIT)
-    call[1] = gen_rtx_USE (VOIDmode, GEN_INT (INTVAL (cookie)));
-  else
-    {
-      unsigned int mask = CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS;
-      call[1] = gen_rtx_USE (VOIDmode, GEN_INT (INTVAL (cookie) & mask));
-    }
-
+  unsigned int mask = CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS;
+  call[1] = gen_rtx_USE (VOIDmode, GEN_INT (cookie_val & mask));
   call[2] = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, LR_REGNO));
 
   insn = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (3, call));
@@ -38060,6 +38038,113 @@  rs6000_sibcall_sysv (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
     use_reg (&CALL_INSN_FUNCTION_USAGE (insn), abi_reg);
 }
 
+#if TARGET_MACHO
+
+/* Expand code to perform a call under the Darwin ABI.
+   Modulo handling of mlongcall, this is much the same as sysv.
+   if/when the longcall optimisation is removed, we could drop this
+   code and use the sysv case (taking care to avoid the tls stuff).
+
+   We can use this for sibcalls too, if needed.  */
+
+void
+rs6000_call_darwin_1 (rtx value, rtx func_desc, rtx tlsarg,
+		      rtx cookie, bool sibcall)
+{
+  rtx func = func_desc;
+  rtx func_addr;
+  rtx call[3];
+  rtx insn;
+  int cookie_val = INTVAL (cookie);
+  bool make_island = false;
+
+  /* Handle longcall attributes, there are two cases for Darwin:
+     1) Newer linkers are capable of synthesising any branch islands needed.
+     2) We need a helper branch island synthesised by the compiler.
+     The second case has mostly been retired and we don't use it for m64.
+     In fact, it's is an optimisation, we could just indirect as sysv does..
+     ... however, backwards compatibility for now.
+     If we're going to use this, then we need to keep the CALL_LONG bit set,
+     so that we can pick up the special insn form later.  */
+  if ((cookie_val & CALL_LONG) != 0
+      && GET_CODE (func_desc) == SYMBOL_REF)
+    {
+      if (darwin_emit_branch_islands && TARGET_32BIT)
+	make_island = true; /* Do nothing yet, retain the CALL_LONG flag.  */
+      else
+	{
+	  /* The linker is capable of doing this, but the user explicitly
+	     asked for -mlongcall, so we'll do the 'normal' version.  */
+	  func = rs6000_longcall_ref (func_desc, NULL_RTX);
+	  cookie_val &= ~CALL_LONG; /* Handled, zap it.  */
+	}
+    }
+
+  /* Handle indirect calls.  */
+  if (GET_CODE (func) != SYMBOL_REF)
+    {
+      func = force_reg (Pmode, func);
+
+      /* Indirect calls via CTR are strongly preferred over indirect
+	 calls via LR, and are required for indirect sibcalls, so move
+	 the address there.   */
+      func_addr = gen_rtx_REG (Pmode, CTR_REGNO);
+      emit_move_insn (func_addr, func);
+    }
+  else
+    func_addr = func;
+
+  /* Create the call.  */
+  call[0] = gen_rtx_CALL (VOIDmode, gen_rtx_MEM (SImode, func_addr), tlsarg);
+  if (value != NULL_RTX)
+    call[0] = gen_rtx_SET (value, call[0]);
+
+  call[1] = gen_rtx_USE (VOIDmode, GEN_INT (cookie_val));
+
+  if (sibcall)
+    call[2] = simple_return_rtx;
+  else
+    call[2] = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, LR_REGNO));
+
+  insn = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (3, call));
+  insn = emit_call_insn (insn);
+  /* Now we have the debug info in the insn, we can set up the branch island
+     if we're using one.  */
+  if (make_island)
+    {
+      tree funname = get_identifier (XSTR (func_desc, 0));
+
+      if (no_previous_def (funname))
+	{
+	  rtx label_rtx = gen_label_rtx ();
+	  char *label_buf, temp_buf[256];
+	  ASM_GENERATE_INTERNAL_LABEL (temp_buf, "L",
+				       CODE_LABEL_NUMBER (label_rtx));
+	  label_buf = temp_buf[0] == '*' ? temp_buf + 1 : temp_buf;
+	  tree labelname = get_identifier (label_buf);
+	  add_compiler_branch_island (labelname, funname,
+				     insn_line ((const rtx_insn*)insn));
+	}
+     }
+}
+
+void
+rs6000_call_darwin (rtx value, rtx func_desc,
+		    rtx tlsarg ATTRIBUTE_UNUSED, rtx cookie)
+{
+  rs6000_call_darwin_1 (value, func_desc, tlsarg, cookie, false);
+}
+
+
+void
+rs6000_sibcall_darwin (rtx value, rtx func_desc,
+		       rtx tlsarg ATTRIBUTE_UNUSED, rtx cookie)
+{
+  rs6000_call_darwin_1 (value, func_desc, tlsarg, cookie, true);
+}
+
+#endif
+
 /* Return whether we need to always update the saved TOC pointer when we update
    the stack pointer.  */
 
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index d684bed3ae..e4a71439ef 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -10289,12 +10289,20 @@ 
       DONE;
     }
 
-  if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_DARWIN)
+  if (DEFAULT_ABI == ABI_V4)
     {
       rs6000_call_sysv (NULL_RTX, operands[0], operands[1], operands[2]);
       DONE;
     }
 
+#if TARGET_MACHO
+  if (DEFAULT_ABI == ABI_DARWIN)
+    {
+      rs6000_call_darwin (NULL_RTX, operands[0], operands[1], operands[2]);
+      DONE;
+    }
+#endif
+
   if (GET_CODE (operands[0]) != SYMBOL_REF)
     operands[0] = force_reg (Pmode, operands[0]);
 })
@@ -10322,12 +10330,20 @@ 
       DONE;
     }
 
-  if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_DARWIN)
+  if (DEFAULT_ABI == ABI_V4)
     {
       rs6000_call_sysv (operands[0], operands[1], operands[2], operands[3]);
       DONE;
     }
 
+#if TARGET_MACHO
+  if (DEFAULT_ABI == ABI_DARWIN)
+    {
+      rs6000_call_darwin (operands[0], operands[1], operands[2], operands[3]);
+      DONE;
+    }
+#endif
+
   if (GET_CODE (operands[1]) != SYMBOL_REF)
     operands[1] = force_reg (Pmode, operands[1]);
 })
@@ -10463,11 +10479,7 @@ 
   else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
     output_asm_insn ("creqv 6,6,6", operands);
 
-#if TARGET_MACHO
-  return macho_call_template (insn, operands, 0, 2);
-#else
   return rs6000_call_template (operands, 0);
-#endif
 }
   "DEFAULT_ABI == ABI_V4
    && TARGET_SECURE_PLT && flag_pic && !SYMBOL_REF_LOCAL_P (operands[0])
@@ -10549,11 +10561,7 @@ 
   else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
     output_asm_insn ("creqv 6,6,6", operands);
 
-#if TARGET_MACHO
-  return macho_call_template (insn, operands, 1, 3);
-#else
   return rs6000_call_template (operands, 1);
-#endif
 }
   "DEFAULT_ABI == ABI_V4
    && TARGET_SECURE_PLT && flag_pic && !SYMBOL_REF_LOCAL_P (operands[1])
@@ -10771,6 +10779,14 @@ 
       rs6000_sibcall_sysv (NULL_RTX, operands[0], operands[1], operands[2]);
       DONE;
     }
+
+#if TARGET_MACHO
+  if (DEFAULT_ABI == ABI_DARWIN)
+    {
+      rs6000_sibcall_darwin (NULL_RTX, operands[0], operands[1], operands[2]);
+      DONE;
+    }
+#endif
 })
 
 (define_expand "sibcall_value"
@@ -10797,11 +10813,20 @@ 
       DONE;
     }
 
-  if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_DARWIN)
+  if (DEFAULT_ABI == ABI_V4)
     {
       rs6000_sibcall_sysv (operands[0], operands[1], operands[2], operands[3]);
       DONE;
     }
+
+#if TARGET_MACHO
+  if (DEFAULT_ABI == ABI_DARWIN)
+    {
+      rs6000_sibcall_darwin (operands[0], operands[1],
+			     operands[2], operands[3]);
+      DONE;
+    }
+#endif
 })
 
 (define_insn "*sibcall_local32"