[patch] sibling calls for s390

Andreas Krebbel krebbel1@de.ibm.com
Fri Apr 30 07:58:00 GMT 2004


Hello,

the attached patch implements sibling call support for the s390/s390x
backend and enables the respective test cases.

Sibling calls on s390 can be used in a lot of cases. 
However there are two when we've to avoid them:

- direct calls in position independent code on 31 bit:
  the 31 bit plt code uses register 12 which is call saved

- register 6 is used for parameter passing
  according to the s390 ABI this register is also call saved
  Nevertheless we could allow a sibling call in this case if
  we can be sure that the content of register 6 wasn't modified since
  the current function got called with it. Unfortunately I've no idea how to
  figure this out when s390_function_ok_for_sibling_call gets called. At this 
  point there is no data flow info which can be used.
 

Bootstrapped without regressions on s390 and s390x.
OK for mainline?

Bye,

Andreas

2004-04-29  Andreas Krebbel  <krebbel1@de.ibm.com>

	* config/s390/s390-protos.h (s390_emit_epilogue): Parameter added.
	(s390_emit_call): New function prototype added.
	(s390_tls_get_offset): Function removed.
	* config/s390/s390.c (s390_function_ok_for_sibcall,
	s390_call_saved_register_used_p): New functions.
	(TARGET_FUNCTION_OK_FOR_SIBCALL): Definition of target macro added.
	(s390_tls_get_offset): Function merged into s390_emit_tls_call_insn.
	(s390_emit_tls_call_insn): New function.
	(legitimize_tls_address): Call s390_emit_tls_call_insn instead of
	emit_call_insn.
	(s390_emit_prologue): Use s390_emit_call instead of emit_call_insn.
	(s390_emit_epilogue): Like s390_emit_prologue. Parameter for sibcalls 
	added.
	* config/s390/s390.h (SIBCALL_REGNUM): New macro representing the 
	register number used to hold the target address for sibcalls.
	* config/s390/s390.md ("sibcall", "sibcall_value", "sibcall_epilogue"):
	New expanders.
	("*sibcall_br", "*sibcall_brc", "*sibcall_brcl", "*sibcall_value_br", 
	"*sibcall_value_brc", "*sibcall_value_brcl"): New insns.
	("call_exp", "call_value_exp", "call_value_tls", "call_value_tls_exp"): 
	Expanders removed.
	("call", "call_value"): Call s390_emit_call to emit the call patterns.
	("*bras", "*brasl", "*bras_r", "*brasl_r", "*bras_tls", "*brasl_tls", 
	"*basr", "*basr_r", "*basr_tls"): Added constraint: !SIBLING_CALL_P.
	("epilogue"): Changed the call to s390_emit_epilogue to use the
	new parameter.
	* testsuite/gcc.dg/sibcall-3.c: Delete s390 from expected fail list.
	* testsuite/gcc.dg/sibcall-4.c: Likewise.
	* testsuite/gcc.dg/sibcall-6.c: Enable s390 as test platform.


Index: testsuite/gcc.dg/sibcall-3.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/gcc.dg/sibcall-3.c,v
retrieving revision 1.5
diff -p -c -r1.5 sibcall-3.c
*** testsuite/gcc.dg/sibcall-3.c	7 Mar 2004 00:59:25 -0000	1.5
--- testsuite/gcc.dg/sibcall-3.c	29 Apr 2004 14:18:18 -0000
***************
*** 5,11 ****
     Copyright (C) 2002 Free Software Foundation Inc.
     Contributed by Hans-Peter Nilsson  <hp@bitrange.com>  */
  
! /* { dg-do run { xfail arc-*-* avr-*-* c4x-*-* cris-*-* h8300-*-* ip2k-*-* m32r-*-* m68hc1?-*-* m681?-*-* m680*-*-* m68k-*-* mcore-*-* mips*-*-* mn10300-*-* ns32k-*-* s390*-*-* xstormy16-*-* v850*-*-* vax-*-* xtensa-*-* } } */
  /* { dg-options "-O2 -foptimize-sibling-calls" } */
  
  /* The option -foptimize-sibling-calls is the default, but serves as
--- 5,11 ----
     Copyright (C) 2002 Free Software Foundation Inc.
     Contributed by Hans-Peter Nilsson  <hp@bitrange.com>  */
  
! /* { dg-do run { xfail arc-*-* avr-*-* c4x-*-* cris-*-* h8300-*-* ip2k-*-* m32r-*-* m68hc1?-*-* m681?-*-* m680*-*-* m68k-*-* mcore-*-* mips*-*-* mn10300-*-* ns32k-*-* xstormy16-*-* v850*-*-* vax-*-* xtensa-*-* } } */
  /* { dg-options "-O2 -foptimize-sibling-calls" } */
  
  /* The option -foptimize-sibling-calls is the default, but serves as
Index: testsuite/gcc.dg/sibcall-4.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/gcc.dg/sibcall-4.c,v
retrieving revision 1.5
diff -p -c -r1.5 sibcall-4.c
*** testsuite/gcc.dg/sibcall-4.c	7 Mar 2004 00:59:25 -0000	1.5
--- testsuite/gcc.dg/sibcall-4.c	29 Apr 2004 14:18:18 -0000
***************
*** 5,11 ****
     Copyright (C) 2002 Free Software Foundation Inc.
     Contributed by Hans-Peter Nilsson  <hp@bitrange.com>  */
  
! /* { dg-do run { xfail arc-*-* avr-*-* c4x-*-* cris-*-* h8300-*-* ip2k-*-* m32r-*-* m68hc1?-*-* m681?-*-* m680*-*-* m68k-*-* mcore-*-* mips*-*-* mn10300-*-* ns32k-*-* s390*-*-* xstormy16-*-* v850*-*-* vax-*-* xtensa-*-* } } */
  /* { dg-options "-O2 -foptimize-sibling-calls" } */
  
  /* The option -foptimize-sibling-calls is the default, but serves as
--- 5,11 ----
     Copyright (C) 2002 Free Software Foundation Inc.
     Contributed by Hans-Peter Nilsson  <hp@bitrange.com>  */
  
! /* { dg-do run { xfail arc-*-* avr-*-* c4x-*-* cris-*-* h8300-*-* ip2k-*-* m32r-*-* m68hc1?-*-* m681?-*-* m680*-*-* m68k-*-* mcore-*-* mips*-*-* mn10300-*-* ns32k-*-* xstormy16-*-* v850*-*-* vax-*-* xtensa-*-* } } */
  /* { dg-options "-O2 -foptimize-sibling-calls" } */
  
  /* The option -foptimize-sibling-calls is the default, but serves as
Index: testsuite/gcc.dg/sibcall-6.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/gcc.dg/sibcall-6.c,v
retrieving revision 1.2
diff -p -c -r1.2 sibcall-6.c
*** testsuite/gcc.dg/sibcall-6.c	16 Dec 2002 18:22:43 -0000	1.2
--- testsuite/gcc.dg/sibcall-6.c	29 Apr 2004 14:18:18 -0000
***************
*** 6,12 ****
     Copyright (C) 2002 Free Software Foundation Inc.
     Contributed by Andreas Bauer <baueran@in.tum.de>  */
  
! /* { dg-do run { target i?86-*-* x86_64-*-*} } */
  /* { dg-options "-O2 -foptimize-sibling-calls" } */
  
  int foo (int);
--- 6,12 ----
     Copyright (C) 2002 Free Software Foundation Inc.
     Contributed by Andreas Bauer <baueran@in.tum.de>  */
  
! /* { dg-do run { target i?86-*-* s390*-*-* x86_64-*-*} } */
  /* { dg-options "-O2 -foptimize-sibling-calls" } */
  
  int foo (int);
Index: config/s390/s390-protos.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390-protos.h,v
retrieving revision 1.44
diff -p -c -r1.44 s390-protos.h
*** config/s390/s390-protos.h	13 Feb 2004 14:57:25 -0000	1.44
--- config/s390/s390-protos.h	29 Apr 2004 14:18:19 -0000
*************** extern void override_options (void);
*** 26,33 ****
  extern HOST_WIDE_INT s390_arg_frame_offset (void);
  extern void s390_load_got (int);
  extern void s390_emit_prologue (void);
! extern void s390_emit_epilogue (void);
  extern void s390_function_profiler (FILE *, int);
  
  #ifdef RTX_CODE
  extern int s390_extra_constraint_str (rtx, int, const char *);
--- 26,34 ----
  extern HOST_WIDE_INT s390_arg_frame_offset (void);
  extern void s390_load_got (int);
  extern void s390_emit_prologue (void);
! extern void s390_emit_epilogue (bool);
  extern void s390_function_profiler (FILE *, int);
+ extern rtx  s390_emit_call (rtx, rtx, rtx, rtx);
  
  #ifdef RTX_CODE
  extern int s390_extra_constraint_str (rtx, int, const char *);
*************** extern int s390_alc_comparison (rtx op, 
*** 53,59 ****
  extern int s390_slb_comparison (rtx op, enum machine_mode mode);
  extern int symbolic_reference_mentioned_p (rtx);
  extern int tls_symbolic_reference_mentioned_p (rtx);
- extern rtx s390_tls_get_offset (void);
  extern int legitimate_la_operand_p (rtx);
  extern int preferred_la_operand_p (rtx);
  extern int legitimate_pic_operand_p (rtx);
--- 54,59 ----
Index: config/s390/s390.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390.c,v
retrieving revision 1.140
diff -p -c -r1.140 s390.c
*** config/s390/s390.c	1 Apr 2004 03:50:34 -0000	1.140
--- config/s390/s390.c	29 Apr 2004 14:18:20 -0000
*************** static int s390_address_cost (rtx);
*** 78,83 ****
--- 78,85 ----
  static void s390_reorg (void);
  static bool s390_valid_pointer_mode (enum machine_mode);
  static tree s390_build_builtin_va_list (void);
+ static bool s390_function_ok_for_sibcall (tree, tree);
+ static bool s390_call_saved_register_used (tree);
  
  #undef  TARGET_ASM_ALIGNED_HI_OP
  #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
*************** static tree s390_build_builtin_va_list (
*** 151,156 ****
--- 153,161 ----
  #undef TARGET_PROMOTE_FUNCTION_RETURN
  #define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
  
+ #undef TARGET_FUNCTION_OK_FOR_SIBCALL
+ #define TARGET_FUNCTION_OK_FOR_SIBCALL s390_function_ok_for_sibcall
+ 
  struct gcc_target targetm = TARGET_INITIALIZER;
  
  extern int reload_completed;
*************** get_thread_pointer (void)
*** 2610,2625 ****
    return tp;
  }
  
! /* Construct the SYMBOL_REF for the tls_get_offset function.  */
  
  static GTY(()) rtx s390_tls_symbol;
! rtx
! s390_tls_get_offset (void)
  {
    if (!s390_tls_symbol)
      s390_tls_symbol = gen_rtx_SYMBOL_REF (Pmode, "__tls_get_offset");
  
!   return s390_tls_symbol;
  }
  
  /* ADDR contains a thread-local SYMBOL_REF.  Generate code to compute
--- 2615,2643 ----
    return tp;
  }
  
! /* Emit a tls call insn. The call target is the SYMBOL_REF stored
!    in s390_tls_symbol which always refers to __tls_get_offset.
!    The returned offset is written to RESULT_REG and an USE rtx is
!    generated for TLS_CALL.  */
  
  static GTY(()) rtx s390_tls_symbol;
! 
! static void
! s390_emit_tls_call_insn (rtx result_reg, rtx tls_call)
  {
+   rtx insn;
+   
+   if (!flag_pic)
+     abort ();
+ 
    if (!s390_tls_symbol)
      s390_tls_symbol = gen_rtx_SYMBOL_REF (Pmode, "__tls_get_offset");
  
!   insn = s390_emit_call (s390_tls_symbol, tls_call, result_reg, 
! 			 gen_rtx_REG (Pmode, RETURN_REGNUM)); 
! 
!   use_reg (&CALL_INSN_FUNCTION_USAGE (insn), result_reg);
!   CONST_OR_PURE_CALL_P (insn) = 1;
  }
  
  /* ADDR contains a thread-local SYMBOL_REF.  Generate code to compute
*************** legitimize_tls_address (rtx addr, rtx re
*** 2640,2646 ****
  	new = gen_rtx_CONST (Pmode, tls_call);
  	new = force_const_mem (Pmode, new);
  	emit_move_insn (r2, new);
! 	emit_call_insn (gen_call_value_tls (r2, tls_call));
  	insn = get_insns ();
  	end_sequence ();
  
--- 2658,2664 ----
  	new = gen_rtx_CONST (Pmode, tls_call);
  	new = force_const_mem (Pmode, new);
  	emit_move_insn (r2, new);
! 	s390_emit_tls_call_insn (r2, tls_call);
  	insn = get_insns ();
  	end_sequence ();
  
*************** legitimize_tls_address (rtx addr, rtx re
*** 2663,2669 ****
  	new = gen_rtx_CONST (Pmode, tls_call);
  	new = force_const_mem (Pmode, new);
  	emit_move_insn (r2, new);
! 	emit_call_insn (gen_call_value_tls (r2, tls_call));
  	insn = get_insns ();
  	end_sequence ();
  
--- 2681,2687 ----
  	new = gen_rtx_CONST (Pmode, tls_call);
  	new = force_const_mem (Pmode, new);
  	emit_move_insn (r2, new);
! 	s390_emit_tls_call_insn (r2, tls_call);
  	insn = get_insns ();
  	end_sequence ();
  
*************** s390_emit_prologue (void)
*** 5668,5682 ****
  	 algorithms located at the branch target.
  
  	 This must use register 1.  */
!       rtx addr;
!       rtx unkn;
!       rtx link;
! 
!       addr = GEN_INT (0xfe0);
!       unkn = CONST0_RTX (SImode);
!       link = gen_rtx_REG (Pmode, 1);
! 
!       emit_call_insn (gen_call_exp (gen_rtx_MEM (QImode, addr), unkn, link));
  
        /* Emit a blockage here so that all code
  	 lies between the profiling mechanisms.  */
--- 5686,5693 ----
  	 algorithms located at the branch target.
  
  	 This must use register 1.  */
!       s390_emit_call (GEN_INT (0xfe0), NULL_RTX, NULL_RTX, 
! 		      gen_rtx_REG (Pmode, 1));
  
        /* Emit a blockage here so that all code
  	 lies between the profiling mechanisms.  */
*************** s390_emit_prologue (void)
*** 5687,5693 ****
  /* Expand the epilogue into a bunch of separate insns.  */
  
  void
! s390_emit_epilogue (void)
  {
    rtx frame_pointer, return_reg;
    int area_bottom, area_top, offset = 0;
--- 5698,5704 ----
  /* Expand the epilogue into a bunch of separate insns.  */
  
  void
! s390_emit_epilogue (bool sibcall)
  {
    rtx frame_pointer, return_reg;
    int area_bottom, area_top, offset = 0;
*************** s390_emit_epilogue (void)
*** 5703,5721 ****
  
  	 This must use register 1.  */
  
-       rtx addr;
-       rtx unkn;
-       rtx link;
- 
-       addr = GEN_INT (0xfe6);
-       unkn = CONST0_RTX (SImode);
-       link = gen_rtx_REG (Pmode, 1);
- 
        /* Emit a blockage here so that all code
           lies between the profiling mechanisms.  */
        emit_insn (gen_blockage ());
  
!       emit_call_insn (gen_call_exp (gen_rtx_MEM (QImode, addr), unkn, link));
      }
  
    /* Check whether to use frame or stack pointer for restore.  */
--- 5714,5725 ----
  
  	 This must use register 1.  */
  
        /* Emit a blockage here so that all code
           lies between the profiling mechanisms.  */
        emit_insn (gen_blockage ());
  
!       s390_emit_call (GEN_INT (0xfe6), NULL_RTX, NULL_RTX, 
! 		      gen_rtx_REG (Pmode, 1));
      }
  
    /* Check whether to use frame or stack pointer for restore.  */
*************** s390_emit_epilogue (void)
*** 5847,5869 ****
  	    }
  	}
  
!       /* Fetch return address from stack before load multiple,
! 	 this will do good for scheduling.  */
! 
!       if (cfun->machine->save_return_addr_p
! 	  || (cfun->machine->first_restore_gpr < BASE_REGISTER
! 	      && cfun->machine->last_save_gpr > RETURN_REGNUM))
! 	{
! 	  int return_regnum = find_unused_clobbered_reg();
! 	  if (!return_regnum)
! 	    return_regnum = 4;
! 	  return_reg = gen_rtx_REG (Pmode, return_regnum);
! 
! 	  addr = plus_constant (frame_pointer,
! 				offset + RETURN_REGNUM * UNITS_PER_WORD);
! 	  addr = gen_rtx_MEM (Pmode, addr);
! 	  set_mem_alias_set (addr, s390_sr_alias_set);
! 	  emit_move_insn (return_reg, addr);
  	}
  
        /* ??? As references to the base register are not made
--- 5851,5876 ----
  	    }
  	}
  
!       if (! sibcall)
! 	{
! 	  /* Fetch return address from stack before load multiple,
! 	     this will do good for scheduling.  */
! 	  
! 	  if (cfun->machine->save_return_addr_p
! 	      || (cfun->machine->first_restore_gpr < BASE_REGISTER
! 		  && cfun->machine->last_save_gpr > RETURN_REGNUM))
! 	    {
! 	      int return_regnum = find_unused_clobbered_reg();
! 	      if (!return_regnum)
! 		return_regnum = 4;
! 	      return_reg = gen_rtx_REG (Pmode, return_regnum);
! 	      
! 	      addr = plus_constant (frame_pointer,
! 				    offset + RETURN_REGNUM * UNITS_PER_WORD);
! 	      addr = gen_rtx_MEM (Pmode, addr);
! 	      set_mem_alias_set (addr, s390_sr_alias_set);
! 	      emit_move_insn (return_reg, addr);
! 	    }
  	}
  
        /* ??? As references to the base register are not made
*************** s390_emit_epilogue (void)
*** 5878,5890 ****
        emit_insn (insn);
      }
  
!   /* Return to caller.  */
! 
!   p = rtvec_alloc (2);
  
!   RTVEC_ELT (p, 0) = gen_rtx_RETURN (VOIDmode);
!   RTVEC_ELT (p, 1) = gen_rtx_USE (VOIDmode, return_reg);
!   emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, p));
  }
  
  
--- 5885,5901 ----
        emit_insn (insn);
      }
  
!   if (! sibcall)
!     {
  
!       /* Return to caller.  */
!       
!       p = rtvec_alloc (2);
!       
!       RTVEC_ELT (p, 0) = gen_rtx_RETURN (VOIDmode);
!       RTVEC_ELT (p, 1) = gen_rtx_USE (VOIDmode, return_reg);
!       emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, p));
!     }
  }
  
  
*************** static struct machine_function *
*** 6997,7002 ****
--- 7008,7188 ----
  s390_init_machine_status (void)
  {
    return ggc_alloc_cleared (sizeof (struct machine_function));
+ }
+ 
+ /* Checks whether the given ARGUMENT_LIST would use a caller
+    saved register.  This is used to decide whether sibling call
+    optimization could be performed on the respective function
+    call.  */
+ 
+ static bool
+ s390_call_saved_register_used (tree argument_list)
+ {
+   CUMULATIVE_ARGS cum;
+   tree parameter;
+   enum machine_mode mode;
+   tree type;
+   rtx parm_rtx;
+   int reg;
+ 
+   INIT_CUMULATIVE_ARGS (cum, NULL, NULL, 0, 0);
+ 
+   while (argument_list)
+     {
+       parameter = TREE_VALUE (argument_list);
+       argument_list = TREE_CHAIN (argument_list);
+ 
+       if (!parameter)
+ 	abort();
+ 
+       /* For an undeclared variable passed as parameter we will get
+ 	 an ERROR_MARK node here.  */
+       if (TREE_CODE (parameter) == ERROR_MARK)
+ 	return true;
+ 
+       if (! (type = TREE_TYPE (parameter)))
+ 	abort();
+       
+       if (! (mode = TYPE_MODE (TREE_TYPE (parameter))))
+ 	abort();
+ 
+       if (s390_function_arg_pass_by_reference (mode, type))
+  	{
+  	  mode = Pmode;
+  	  type = build_pointer_type (type);
+  	}
+       
+        parm_rtx = s390_function_arg (&cum, mode, type, 0);
+ 
+        s390_function_arg_advance (&cum, mode, type, 0);
+  
+        if (parm_rtx && REG_P (parm_rtx))
+ 	 {
+ 	   for (reg = 0;
+ 		reg < HARD_REGNO_NREGS (REGNO (parm_rtx), GET_MODE (parm_rtx)); 
+ 		reg++)
+ 	     if (! call_used_regs[reg + REGNO (parm_rtx)])
+ 	       return true;
+ 	 }
+     }
+   return false;
+ }
+ 
+ /* Return true if the given call expression can be 
+    turned into a sibling call.  
+    DECL holds the declaration of the function to be called whereas
+    EXP is the call expression itself.  */
+    
+ static bool
+ s390_function_ok_for_sibcall (tree decl, tree exp)
+ {
+   /* The TPF epilogue uses register 1.  */
+   if (TARGET_TPF)
+     return false;
+ 
+   /* The 31 bit PLT code uses register 12 (GOT pointer - caller saved) 
+      which would have to be restored before the sibcall.  */
+   if (!TARGET_64BIT && flag_pic && decl && TREE_PUBLIC (decl))
+     return false;
+ 
+   /* Register 6 on s390 is available as an argument register but unfortunately
+      "caller saved". This makes functions needing this register for arguments
+      not suitable for sibcalls.  */ 
+   if (TREE_OPERAND (exp, 1)
+       && s390_call_saved_register_used (TREE_OPERAND (exp, 1)))
+       return false;
+ 
+   return true;
+ }
+ 
+ /* This function is used by the call expanders of the machine description. 
+    It emits the call insn itself together with the necessary operations 
+    to adjust the target address and returns the emitted insn.
+    ADDR_LOCATION is the target address rtx
+    TLS_CALL the location of the thread-local symbol
+    RESULT_REG the register where the result of the call should be stored
+    RETADDR_REG the register where the return address should be stored
+                If this parameter is NULL_RTX the call is considered
+                to be a sibling call.  */
+ 
+ rtx
+ s390_emit_call (rtx addr_location, rtx tls_call, rtx result_reg, 
+ 		rtx retaddr_reg)
+ {
+   bool plt_call = false;
+   rtx insn;
+   rtx call;
+   rtx clobber;
+   rtvec vec;
+ 
+   /* Direct function calls need special treatment.  */
+   if (GET_CODE (addr_location) == SYMBOL_REF)
+     {
+       /* When calling a global routine in PIC mode, we must
+          replace the symbol itself with the PLT stub.  */
+       if (flag_pic && !SYMBOL_REF_LOCAL_P (addr_location))
+         {
+ 	  addr_location = gen_rtx_UNSPEC (Pmode, 
+ 					  gen_rtvec (1, addr_location), 
+ 					  UNSPEC_PLT);
+ 	  addr_location = gen_rtx_CONST (Pmode, addr_location);
+ 	  plt_call = true;
+         }
+       
+       /* Unless we can use the bras(l) insn, force the
+          routine address into a register.  */
+       if (!TARGET_SMALL_EXEC && !TARGET_CPU_ZARCH)
+         {
+ 	  if (flag_pic)
+ 	    addr_location = legitimize_pic_address (addr_location, 0);
+ 	  else
+ 	    addr_location = force_reg (Pmode, addr_location);
+ 	}
+     } 
+ 
+   /* If it is already an indirect call or the code above moved the
+      SYMBOL_REF to somewhere else make sure the address can be found in 
+      register 1.  */
+   if (retaddr_reg == NULL_RTX
+       && GET_CODE (addr_location) != SYMBOL_REF
+       && !plt_call)
+     {
+       emit_move_insn (gen_rtx_REG (Pmode, SIBCALL_REGNUM), addr_location);
+       addr_location = gen_rtx_REG (Pmode, SIBCALL_REGNUM);
+     }
+   
+   addr_location = gen_rtx_MEM (QImode, addr_location);
+   call = gen_rtx_CALL (VOIDmode, addr_location, const0_rtx);
+ 
+   if (result_reg != NULL_RTX)
+     call = gen_rtx_SET (VOIDmode, result_reg, call);
+     
+   if (retaddr_reg != NULL_RTX)
+     {
+       clobber = gen_rtx_CLOBBER (VOIDmode, retaddr_reg);
+ 
+       if (tls_call != NULL_RTX)
+ 	vec = gen_rtvec (3, call, clobber, 
+ 			 gen_rtx_USE (VOIDmode, tls_call));
+       else
+ 	vec = gen_rtvec (2, call, clobber);
+ 
+       call = gen_rtx_PARALLEL (VOIDmode, vec);
+     }
+ 
+   insn = emit_call_insn (call);
+  
+   /* 31-bit PLT stubs and tls calls use the GOT register implicitly.  */
+   if ((!TARGET_64BIT && plt_call) || tls_call != NULL_RTX)
+     {
+       /* s390_function_ok_for_sibcall should 
+ 	 have denied sibcalls in this case.  */
+       if (retaddr_reg == NULL_RTX)
+ 	abort ();
+       
+       use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx);
+     }
+   return insn;
  }
  
  #include "gt-s390.h"
Index: config/s390/s390.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390.h,v
retrieving revision 1.101
diff -p -c -r1.101 s390.h
*** config/s390/s390.h	8 Apr 2004 18:26:08 -0000	1.101
--- config/s390/s390.h	29 Apr 2004 14:18:20 -0000
*************** if (INTEGRAL_MODE_P (MODE) &&	        	 
*** 299,304 ****
--- 299,305 ----
  #define CC_REG_P(X)		(REG_P (X) && CC_REGNO_P (REGNO (X)))
  #define FRAME_REG_P(X)		(REG_P (X) && FRAME_REGNO_P (REGNO (X)))
  
+ #define SIBCALL_REGNUM 1
  #define BASE_REGISTER 13
  #define RETURN_REGNUM 14
  #define CC_REGNUM 33
Index: config/s390/s390.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390.md,v
retrieving revision 1.106
diff -p -c -r1.106 s390.md
*** config/s390/s390.md	22 Mar 2004 02:28:11 -0000	1.106
--- config/s390/s390.md	29 Apr 2004 14:18:20 -0000
***************
*** 6968,6973 ****
--- 6968,7054 ----
    [(set_attr "type"    "none")
     (set_attr "length"  "0")])
  
+ ;
+ ; sibcall patterns
+ ;
+ 
+ (define_expand "sibcall"
+   [(call (match_operand 0 "" "")
+ 	 (match_operand 1 "" ""))]
+   ""
+ {
+   s390_emit_call (XEXP (operands[0], 0), NULL_RTX, NULL_RTX, NULL_RTX);
+   DONE;
+ })
+ 
+ (define_insn "*sibcall_br"
+   [(call (mem:QI (reg 1))
+          (match_operand 0 "const_int_operand" "n"))]
+   "SIBLING_CALL_P (insn) 
+    && GET_MODE (XEXP (XEXP (PATTERN (insn), 0), 0)) == Pmode"
+   "br\t%%r1"
+   [(set_attr "op_type" "RR")
+    (set_attr "type"  "branch")
+    (set_attr "atype" "agen")])
+ 
+ (define_insn "*sibcall_brc"
+   [(call (mem:QI (match_operand 0 "bras_sym_operand" "X"))
+          (match_operand 1 "const_int_operand" "n"))]
+   "SIBLING_CALL_P (insn) && TARGET_SMALL_EXEC"
+   "j\t%0"
+   [(set_attr "op_type" "RI")
+    (set_attr "type"    "branch")])
+ 
+ (define_insn "*sibcall_brcl"
+   [(call (mem:QI (match_operand 0 "bras_sym_operand" "X"))
+          (match_operand 1 "const_int_operand" "n"))]
+   "SIBLING_CALL_P (insn) && TARGET_CPU_ZARCH"
+   "jg\t%0"
+   [(set_attr "op_type" "RIL")
+    (set_attr "type"    "branch")])
+ 
+ ;
+ ; sibcall_value patterns
+ ;
+ 
+ (define_expand "sibcall_value"
+   [(set (match_operand 0 "" "")
+ 	(call (match_operand 1 "" "")
+ 	      (match_operand 2 "" "")))]
+   ""
+ {
+   s390_emit_call (XEXP (operands[1], 0), NULL_RTX, operands[0], NULL_RTX);
+   DONE;
+ })
+ 
+ (define_insn "*sibcall_value_br"
+   [(set (match_operand 0 "" "")
+ 	(call (mem:QI (reg 1))
+ 	      (match_operand 1 "const_int_operand" "n")))]
+   "SIBLING_CALL_P (insn) 
+    && GET_MODE (XEXP (XEXP (XEXP (PATTERN (insn), 1), 0), 0)) == Pmode"
+   "br\t%%r1"
+   [(set_attr "op_type" "RR")
+    (set_attr "type"  "branch")
+    (set_attr "atype" "agen")])
+ 
+ (define_insn "*sibcall_value_brc"
+   [(set (match_operand 0 "" "")
+ 	(call (mem:QI (match_operand 1 "bras_sym_operand" "X"))
+ 	      (match_operand 2 "const_int_operand" "n")))]
+   "SIBLING_CALL_P (insn) && TARGET_SMALL_EXEC"
+   "j\t%1"
+   [(set_attr "op_type" "RI")
+    (set_attr "type"    "branch")])
+ 
+ (define_insn "*sibcall_value_brcl"
+   [(set (match_operand 0 "" "")
+ 	(call (mem:QI (match_operand 1 "bras_sym_operand" "X"))
+ 	      (match_operand 2 "const_int_operand" "n")))]
+   "SIBLING_CALL_P (insn) && TARGET_CPU_ZARCH"
+   "jg\t%1"
+   [(set_attr "op_type" "RIL")
+    (set_attr "type"    "branch")])
  
  
  ;
***************
*** 6980,7038 ****
     (use (match_operand 2 "" ""))]
    ""
  {
!   bool plt_call = false;
!   rtx insn;
! 
!   /* Direct function calls need special treatment.  */
!   if (GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF)
!     {
!       rtx sym = XEXP (operands[0], 0);
! 
!       /* When calling a global routine in PIC mode, we must
!          replace the symbol itself with the PLT stub.  */
!       if (flag_pic && !SYMBOL_REF_LOCAL_P (sym))
!         {
!           sym = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, sym), UNSPEC_PLT);
!           sym = gen_rtx_CONST (Pmode, sym);
! 	  plt_call = true;
!         }
! 
!       /* Unless we can use the bras(l) insn, force the
!          routine address into a register.  */
!       if (!TARGET_SMALL_EXEC && !TARGET_CPU_ZARCH)
! 	{
! 	  if (flag_pic)
! 	    sym = legitimize_pic_address (sym, 0);
! 	  else
! 	    sym = force_reg (Pmode, sym);
! 	}
! 
!       operands[0] = gen_rtx_MEM (QImode, sym);
!     }
! 
!   /* Emit insn.  */
!   insn = emit_call_insn (gen_call_exp (operands[0], operands[1],
!   				       gen_rtx_REG (Pmode, RETURN_REGNUM)));
! 
!   /* 31-bit PLT stubs use the GOT register implicitly.  */
!   if (!TARGET_64BIT && plt_call)
!     use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx);
!   
    DONE;
  })
  
- (define_expand "call_exp"
-   [(parallel [(call (match_operand 0 "" "")
-                     (match_operand 1 "" ""))
-               (clobber (match_operand 2 "" ""))])]
-   ""
-   "")
- 
  (define_insn "*bras"
    [(call (mem:QI (match_operand 0 "bras_sym_operand" "X"))
           (match_operand 1 "const_int_operand" "n"))
     (clobber (match_operand 2 "register_operand" "=r"))]
!   "TARGET_SMALL_EXEC && GET_MODE (operands[2]) == Pmode"
    "bras\t%2,%0"
    [(set_attr "op_type" "RI")
     (set_attr "type"    "jsr")])
--- 7061,7078 ----
     (use (match_operand 2 "" ""))]
    ""
  {
!   s390_emit_call (XEXP (operands[0], 0), NULL_RTX, NULL_RTX, 
! 		  gen_rtx_REG (Pmode, RETURN_REGNUM));
    DONE;
  })
  
  (define_insn "*bras"
    [(call (mem:QI (match_operand 0 "bras_sym_operand" "X"))
           (match_operand 1 "const_int_operand" "n"))
     (clobber (match_operand 2 "register_operand" "=r"))]
!   "!SIBLING_CALL_P (insn) 
!    && TARGET_SMALL_EXEC 
!    && GET_MODE (operands[2]) == Pmode"
    "bras\t%2,%0"
    [(set_attr "op_type" "RI")
     (set_attr "type"    "jsr")])
***************
*** 7041,7047 ****
    [(call (mem:QI (match_operand 0 "bras_sym_operand" "X"))
           (match_operand 1 "const_int_operand" "n"))
     (clobber (match_operand 2 "register_operand" "=r"))]
!   "TARGET_CPU_ZARCH && GET_MODE (operands[2]) == Pmode"
    "brasl\t%2,%0"
    [(set_attr "op_type" "RIL")
     (set_attr "type"    "jsr")])
--- 7081,7089 ----
    [(call (mem:QI (match_operand 0 "bras_sym_operand" "X"))
           (match_operand 1 "const_int_operand" "n"))
     (clobber (match_operand 2 "register_operand" "=r"))]
!   "!SIBLING_CALL_P (insn) 
!    && TARGET_CPU_ZARCH 
!    && GET_MODE (operands[2]) == Pmode"
    "brasl\t%2,%0"
    [(set_attr "op_type" "RIL")
     (set_attr "type"    "jsr")])
***************
*** 7050,7056 ****
    [(call (mem:QI (match_operand 0 "address_operand" "U"))
           (match_operand 1 "const_int_operand" "n"))
     (clobber (match_operand 2 "register_operand" "=r"))]
!   "GET_MODE (operands[2]) == Pmode"
  {
    if (get_attr_op_type (insn) == OP_TYPE_RR)
      return "basr\t%2,%0";
--- 7092,7098 ----
    [(call (mem:QI (match_operand 0 "address_operand" "U"))
           (match_operand 1 "const_int_operand" "n"))
     (clobber (match_operand 2 "register_operand" "=r"))]
!   "!SIBLING_CALL_P (insn) && GET_MODE (operands[2]) == Pmode"
  {
    if (get_attr_op_type (insn) == OP_TYPE_RR)
      return "basr\t%2,%0";
***************
*** 7074,7135 ****
     (use (match_operand 3 "" ""))]
    ""
  {
!   bool plt_call = false;
!   rtx insn;
! 
!   /* Direct function calls need special treatment.  */
!   if (GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF)
!     {
!       rtx sym = XEXP (operands[1], 0);
! 
!       /* When calling a global routine in PIC mode, we must
!          replace the symbol itself with the PLT stub.  */
!       if (flag_pic && !SYMBOL_REF_LOCAL_P (sym))
!         {
!           sym = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, sym), UNSPEC_PLT);
!           sym = gen_rtx_CONST (Pmode, sym);
! 	  plt_call = true;
!         }
! 
!       /* Unless we can use the bras(l) insn, force the
!          routine address into a register.  */
!       if (!TARGET_SMALL_EXEC && !TARGET_CPU_ZARCH)
!         {
! 	  if (flag_pic)
! 	    sym = legitimize_pic_address (sym, 0);
! 	  else
! 	    sym = force_reg (Pmode, sym);
!         }
! 
!       operands[1] = gen_rtx_MEM (QImode, sym);
!     }
! 
!   /* Emit insn.  */
!   insn = emit_call_insn (
! 	    gen_call_value_exp (operands[0], operands[1], operands[2],
!   				gen_rtx_REG (Pmode, RETURN_REGNUM)));
! 
!   /* 31-bit PLT stubs use the GOT register implicitly.  */
!   if (!TARGET_64BIT && plt_call)
!     use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx);
!   
    DONE;
  })
  
- (define_expand "call_value_exp"
-   [(parallel [(set (match_operand 0 "" "")
-                    (call (match_operand 1 "" "")
-                          (match_operand 2 "" "")))
-               (clobber (match_operand 3 "" ""))])]
-   ""
-   "")
- 
  (define_insn "*bras_r"
    [(set (match_operand 0 "" "")
          (call (mem:QI (match_operand 1 "bras_sym_operand" "X"))
                (match_operand:SI 2 "const_int_operand" "n")))
     (clobber (match_operand 3 "register_operand" "=r"))]
!   "TARGET_SMALL_EXEC && GET_MODE (operands[3]) == Pmode"
    "bras\t%3,%1"
    [(set_attr "op_type" "RI")
     (set_attr "type"    "jsr")])
--- 7116,7134 ----
     (use (match_operand 3 "" ""))]
    ""
  {
!   s390_emit_call (XEXP (operands[1], 0), NULL_RTX, operands[0], 
! 		  gen_rtx_REG (Pmode, RETURN_REGNUM));
    DONE;
  })
  
  (define_insn "*bras_r"
    [(set (match_operand 0 "" "")
          (call (mem:QI (match_operand 1 "bras_sym_operand" "X"))
                (match_operand:SI 2 "const_int_operand" "n")))
     (clobber (match_operand 3 "register_operand" "=r"))]
!   "!SIBLING_CALL_P (insn) 
!    && TARGET_SMALL_EXEC 
!    && GET_MODE (operands[3]) == Pmode"
    "bras\t%3,%1"
    [(set_attr "op_type" "RI")
     (set_attr "type"    "jsr")])
***************
*** 7139,7145 ****
          (call (mem:QI (match_operand 1 "bras_sym_operand" "X"))
                (match_operand 2 "const_int_operand" "n")))
     (clobber (match_operand 3 "register_operand" "=r"))]
!   "TARGET_CPU_ZARCH && GET_MODE (operands[3]) == Pmode"
    "brasl\t%3,%1"
    [(set_attr "op_type" "RIL")
     (set_attr "type"    "jsr")])
--- 7138,7146 ----
          (call (mem:QI (match_operand 1 "bras_sym_operand" "X"))
                (match_operand 2 "const_int_operand" "n")))
     (clobber (match_operand 3 "register_operand" "=r"))]
!   "!SIBLING_CALL_P (insn) 
!    && TARGET_CPU_ZARCH 
!    && GET_MODE (operands[3]) == Pmode"
    "brasl\t%3,%1"
    [(set_attr "op_type" "RIL")
     (set_attr "type"    "jsr")])
***************
*** 7149,7155 ****
          (call (mem:QI (match_operand 1 "address_operand" "U"))
                (match_operand 2 "const_int_operand" "n")))
     (clobber (match_operand 3 "register_operand" "=r"))]
!   "GET_MODE (operands[3]) == Pmode"
  {
    if (get_attr_op_type (insn) == OP_TYPE_RR)
      return "basr\t%3,%1";
--- 7150,7156 ----
          (call (mem:QI (match_operand 1 "address_operand" "U"))
                (match_operand 2 "const_int_operand" "n")))
     (clobber (match_operand 3 "register_operand" "=r"))]
!   "!SIBLING_CALL_P (insn) && GET_MODE (operands[3]) == Pmode"
  {
    if (get_attr_op_type (insn) == OP_TYPE_RR)
      return "basr\t%3,%1";
***************
*** 7227,7290 ****
     ly\t%0,%1%J2"
    [(set_attr "op_type" "RX,RXY")])
  
- (define_expand "call_value_tls"
-   [(set (match_operand 0 "" "")
-         (call (const_int 0) (const_int 0)))
-    (use (match_operand 1 "" ""))]
-   ""
- {
-   rtx insn, sym;
- 
-   if (!flag_pic)
-     abort ();
- 
-   sym = s390_tls_get_offset ();
-   sym = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, sym), UNSPEC_PLT);
-   sym = gen_rtx_CONST (Pmode, sym);
- 
-   /* Unless we can use the bras(l) insn, force the
-      routine address into a register.  */
-   if (!TARGET_SMALL_EXEC && !TARGET_CPU_ZARCH)
-     {
-       if (flag_pic)
- 	sym = legitimize_pic_address (sym, 0);
-       else
- 	sym = force_reg (Pmode, sym);
-     }
- 
-   sym = gen_rtx_MEM (QImode, sym);
- 
-   /* Emit insn.  */
-   insn = emit_call_insn (
- 	    gen_call_value_tls_exp (operands[0], sym, const0_rtx,
-   				    gen_rtx_REG (Pmode, RETURN_REGNUM),
- 				    operands[1]));
- 
-   /* The calling convention of __tls_get_offset uses the
-      GOT register implicitly.  */
-   use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx);
-   use_reg (&CALL_INSN_FUNCTION_USAGE (insn), operands[0]);
-   CONST_OR_PURE_CALL_P (insn) = 1;
- 
-   DONE;
- })
- 
- (define_expand "call_value_tls_exp"
-   [(parallel [(set (match_operand 0 "" "")
-                    (call (match_operand 1 "" "")
-                          (match_operand 2 "" "")))
-               (clobber (match_operand 3 "" ""))
- 	      (use (match_operand 4 "" ""))])]
-   ""
-   "")
- 
  (define_insn "*bras_tls"
    [(set (match_operand 0 "" "")
          (call (mem:QI (match_operand 1 "bras_sym_operand" "X"))
                (match_operand 2 "const_int_operand" "n")))
     (clobber (match_operand 3 "register_operand" "=r"))
     (use (match_operand 4 "" ""))]
!   "TARGET_SMALL_EXEC && GET_MODE (operands[3]) == Pmode"
    "bras\t%3,%1%J4"
    [(set_attr "op_type" "RI")
     (set_attr "type"    "jsr")])
--- 7228,7242 ----
     ly\t%0,%1%J2"
    [(set_attr "op_type" "RX,RXY")])
  
  (define_insn "*bras_tls"
    [(set (match_operand 0 "" "")
          (call (mem:QI (match_operand 1 "bras_sym_operand" "X"))
                (match_operand 2 "const_int_operand" "n")))
     (clobber (match_operand 3 "register_operand" "=r"))
     (use (match_operand 4 "" ""))]
!   "!SIBLING_CALL_P (insn) 
!    && TARGET_SMALL_EXEC 
!    && GET_MODE (operands[3]) == Pmode"
    "bras\t%3,%1%J4"
    [(set_attr "op_type" "RI")
     (set_attr "type"    "jsr")])
***************
*** 7295,7301 ****
                (match_operand 2 "const_int_operand" "n")))
     (clobber (match_operand 3 "register_operand" "=r"))
     (use (match_operand 4 "" ""))]
!   "TARGET_CPU_ZARCH && GET_MODE (operands[3]) == Pmode"
    "brasl\t%3,%1%J4"
    [(set_attr "op_type" "RIL")
     (set_attr "type"    "jsr")])
--- 7247,7255 ----
                (match_operand 2 "const_int_operand" "n")))
     (clobber (match_operand 3 "register_operand" "=r"))
     (use (match_operand 4 "" ""))]
!   "!SIBLING_CALL_P (insn) 
!    && TARGET_CPU_ZARCH 
!    && GET_MODE (operands[3]) == Pmode"
    "brasl\t%3,%1%J4"
    [(set_attr "op_type" "RIL")
     (set_attr "type"    "jsr")])
***************
*** 7306,7312 ****
                (match_operand 2 "const_int_operand" "n")))
     (clobber (match_operand 3 "register_operand" "=r"))
     (use (match_operand 4 "" ""))]
!   "GET_MODE (operands[3]) == Pmode"
  {
    if (get_attr_op_type (insn) == OP_TYPE_RR)
      return "basr\t%3,%1%J4";
--- 7260,7266 ----
                (match_operand 2 "const_int_operand" "n")))
     (clobber (match_operand 3 "register_operand" "=r"))
     (use (match_operand 4 "" ""))]
!   "!SIBLING_CALL_P (insn) && GET_MODE (operands[3]) == Pmode"
  {
    if (get_attr_op_type (insn) == OP_TYPE_RR)
      return "basr\t%3,%1%J4";
***************
*** 7569,7575 ****
  (define_expand "epilogue"
    [(use (const_int 1))]
    ""
!   "s390_emit_epilogue (); DONE;")
  
  (define_insn "*return"
    [(return)
--- 7523,7534 ----
  (define_expand "epilogue"
    [(use (const_int 1))]
    ""
!   "s390_emit_epilogue (false); DONE;")
! 
! (define_expand "sibcall_epilogue"
!   [(use (const_int 0))]
!   ""
!   "s390_emit_epilogue (true); DONE;")
  
  (define_insn "*return"
    [(return)



More information about the Gcc-patches mailing list