s390-protos.h (s390_emit_epilogue): Parameter added.

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

ChangeLog:

	* 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/ChangeLog:

	* gcc.dg/sibcall-3.c: Delete s390 from expected fail list.
	* gcc.dg/sibcall-4.c: Likewise.
	* gcc.dg/sibcall-6.c: Enable s390 as test platform.

From-SVN: r81347
This commit is contained in:
Andreas Krebbel 2004-04-30 16:40:22 +00:00 committed by Ulrich Weigand
parent 1ae58c30e2
commit ed9676cf0c
9 changed files with 386 additions and 205 deletions

View File

@ -1,3 +1,32 @@
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.
2004-04-30 Kazu Hirata <kazu@cs.umass.edu>
* bb-reorder.c, c-opts.c, cfglayout.c, cgraph.c, cgraphunit.c,

View File

@ -26,7 +26,7 @@ extern void override_options (void);
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_emit_epilogue (bool);
extern void s390_function_profiler (FILE *, int);
#ifdef RTX_CODE
@ -53,7 +53,6 @@ extern int s390_alc_comparison (rtx op, enum machine_mode mode);
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);
@ -77,6 +76,7 @@ extern void s390_expand_movstr (rtx, rtx, rtx);
extern void s390_expand_clrstr (rtx, rtx);
extern void s390_expand_cmpmem (rtx, rtx, rtx, rtx);
extern rtx s390_return_addr_rtx (int, rtx);
extern rtx s390_emit_call (rtx, rtx, rtx, rtx);
extern bool s390_output_addr_const_extra (FILE*, rtx);
extern void print_operand_address (FILE *, rtx);

View File

@ -78,6 +78,8 @@ static int s390_address_cost (rtx);
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"
@ -151,6 +153,9 @@ static tree s390_build_builtin_va_list (void);
#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;
@ -2610,16 +2615,29 @@ get_thread_pointer (void)
return tp;
}
/* Construct the SYMBOL_REF for the tls_get_offset function. */
/* 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;
rtx
s390_tls_get_offset (void)
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");
return s390_tls_symbol;
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
@ -2640,7 +2658,7 @@ legitimize_tls_address (rtx addr, rtx reg)
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));
s390_emit_tls_call_insn (r2, tls_call);
insn = get_insns ();
end_sequence ();
@ -2663,7 +2681,7 @@ legitimize_tls_address (rtx addr, rtx reg)
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));
s390_emit_tls_call_insn (r2, tls_call);
insn = get_insns ();
end_sequence ();
@ -5668,15 +5686,8 @@ s390_emit_prologue (void)
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));
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. */
@ -5687,7 +5698,7 @@ s390_emit_prologue (void)
/* Expand the epilogue into a bunch of separate insns. */
void
s390_emit_epilogue (void)
s390_emit_epilogue (bool sibcall)
{
rtx frame_pointer, return_reg;
int area_bottom, area_top, offset = 0;
@ -5703,19 +5714,12 @@ s390_emit_epilogue (void)
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));
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. */
@ -5847,23 +5851,26 @@ s390_emit_epilogue (void)
}
}
/* 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))
if (! sibcall)
{
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);
/* 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
@ -5878,13 +5885,17 @@ s390_emit_epilogue (void)
emit_insn (insn);
}
/* Return to caller. */
if (! sibcall)
{
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));
/* 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));
}
}
@ -6999,4 +7010,179 @@ 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"

View File

@ -299,6 +299,7 @@ if (INTEGRAL_MODE_P (MODE) && \
#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

View File

@ -6970,6 +6970,87 @@
[(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")])
;
@ -6982,59 +7063,18 @@
(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);
s390_emit_call (XEXP (operands[0], 0), NULL_RTX, NULL_RTX,
gen_rtx_REG (Pmode, RETURN_REGNUM));
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"
"!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")])
@ -7043,7 +7083,9 @@
[(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"
"!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")])
@ -7052,7 +7094,7 @@
[(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"
"!SIBLING_CALL_P (insn) && GET_MODE (operands[2]) == Pmode"
{
if (get_attr_op_type (insn) == OP_TYPE_RR)
return "basr\t%2,%0";
@ -7076,62 +7118,19 @@
(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);
s390_emit_call (XEXP (operands[1], 0), NULL_RTX, operands[0],
gen_rtx_REG (Pmode, RETURN_REGNUM));
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"
"!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")])
@ -7141,7 +7140,9 @@
(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"
"!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")])
@ -7151,7 +7152,7 @@
(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"
"!SIBLING_CALL_P (insn) && GET_MODE (operands[3]) == Pmode"
{
if (get_attr_op_type (insn) == OP_TYPE_RR)
return "basr\t%3,%1";
@ -7229,64 +7230,15 @@
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"
"!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")])
@ -7297,7 +7249,9 @@
(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"
"!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")])
@ -7308,7 +7262,7 @@
(match_operand 2 "const_int_operand" "n")))
(clobber (match_operand 3 "register_operand" "=r"))
(use (match_operand 4 "" ""))]
"GET_MODE (operands[3]) == Pmode"
"!SIBLING_CALL_P (insn) && GET_MODE (operands[3]) == Pmode"
{
if (get_attr_op_type (insn) == OP_TYPE_RR)
return "basr\t%3,%1%J4";
@ -7571,7 +7525,12 @@
(define_expand "epilogue"
[(use (const_int 1))]
""
"s390_emit_epilogue (); DONE;")
"s390_emit_epilogue (false); DONE;")
(define_expand "sibcall_epilogue"
[(use (const_int 0))]
""
"s390_emit_epilogue (true); DONE;")
(define_insn "*return"
[(return)

View File

@ -1,3 +1,9 @@
2004-04-29 Andreas Krebbel <krebbel1@de.ibm.com>
* gcc.dg/sibcall-3.c: Delete s390 from expected fail list.
* gcc.dg/sibcall-4.c: Likewise.
* gcc.dg/sibcall-6.c: Enable s390 as test platform.
2004-04-30 Kazu Hirata <kazu@cs.umass.edu>
* gcc.c-torture/execute/20040331-1.c: Don't use too wide a

View File

@ -5,7 +5,7 @@
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-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

View File

@ -5,7 +5,7 @@
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-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

View File

@ -6,7 +6,7 @@
Copyright (C) 2002 Free Software Foundation Inc.
Contributed by Andreas Bauer <baueran@in.tum.de> */
/* { dg-do run { target i?86-*-* x86_64-*-*} } */
/* { dg-do run { target i?86-*-* s390*-*-* x86_64-*-*} } */
/* { dg-options "-O2 -foptimize-sibling-calls" } */
int foo (int);