[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