+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,
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
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);
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);
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"
#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;
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
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 ();
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 ();
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. */
/* 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;
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. */
}
}
- /* 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
emit_insn (insn);
}
- /* Return to caller. */
-
- p = rtvec_alloc (2);
+ if (! sibcall)
+ {
- 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));
+ }
}
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"
#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
[(set_attr "type" "none")
(set_attr "length" "0")])
-
-
;
-; call instruction pattern(s).
+; sibcall patterns
;
-(define_expand "call"
+(define_expand "sibcall"
[(call (match_operand 0 "" "")
- (match_operand 1 "" ""))
- (use (match_operand 2 "" ""))]
+ (match_operand 1 "" ""))]
""
{
- 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);
+ s390_emit_call (XEXP (operands[0], 0), NULL_RTX, NULL_RTX, NULL_RTX);
+ DONE;
+})
- /* 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;
- }
+(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")])
- /* 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);
- }
+(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")])
- operands[0] = gen_rtx_MEM (QImode, sym);
- }
+(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")])
- /* Emit insn. */
- insn = emit_call_insn (gen_call_exp (operands[0], operands[1],
- gen_rtx_REG (Pmode, RETURN_REGNUM)));
+;
+; sibcall_value patterns
+;
- /* 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);
-
+(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_expand "call_exp"
- [(parallel [(call (match_operand 0 "" "")
- (match_operand 1 "" ""))
- (clobber (match_operand 2 "" ""))])]
+(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")])
+
+
+;
+; call instruction pattern(s).
+;
+
+(define_expand "call"
+ [(call (match_operand 0 "" "")
+ (match_operand 1 "" ""))
+ (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"))]
- "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")])
[(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")])
[(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";
(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")])
(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")])
(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";
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")])
(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")])
(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";
(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)
+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
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
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
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);