#include "target-def.h"
#include "cfglayout.h"
-/* 1 if the caller has placed an "unimp" insn immediately after the call.
- This is used in v8 code when calling a function that returns a structure.
- v9 doesn't have this. Be careful to have this test be the same as that
- used on the call. */
-
-#define SKIP_CALLERS_UNIMP_P \
-(!TARGET_ARCH64 && current_function_returns_struct \
- && ! integer_zerop (DECL_SIZE (DECL_RESULT (current_function_decl))) \
- && (TREE_CODE (DECL_SIZE (DECL_RESULT (current_function_decl))) \
- == INTEGER_CST))
-
/* Global variables for machine-dependent things. */
/* Size of frame. Need to know this to emit return insns from leaf procedures.
/* Coordinate with the md file wrt special insns created by
sparc_function_epilogue. */
bool sparc_emitting_epilogue;
+bool sparc_skip_caller_unimp;
/* Vector to say how input registers are mapped to output registers.
HARD_FRAME_POINTER_REGNUM cannot be remapped by this function to
{
const char *ret;
+ /* True if the caller has placed an "unimp" insn immediately after the call.
+ This insn is used in the 32-bit ABI when calling a function that returns
+ a non zero-sized structure. The 64-bit ABI doesn't have it. Be careful
+ to have this test be the same as that used on the call. */
+ sparc_skip_caller_unimp =
+ ! TARGET_ARCH64
+ && current_function_returns_struct
+ && (TREE_CODE (DECL_SIZE (DECL_RESULT (current_function_decl)))
+ == INTEGER_CST)
+ && ! integer_zerop (DECL_SIZE (DECL_RESULT (current_function_decl)));
+
if (current_function_epilogue_delay_list == 0)
{
/* If code does not drop into the epilogue, we need
/* Work out how to skip the caller's unimp instruction if required. */
if (leaf_function)
- ret = (SKIP_CALLERS_UNIMP_P ? "jmp\t%o7+12" : "retl");
+ ret = (sparc_skip_caller_unimp ? "jmp\t%o7+12" : "retl");
else
- ret = (SKIP_CALLERS_UNIMP_P ? "jmp\t%i7+12" : "ret");
+ ret = (sparc_skip_caller_unimp ? "jmp\t%i7+12" : "ret");
if (! leaf_function)
{
{
if (current_function_epilogue_delay_list)
abort ();
- if (SKIP_CALLERS_UNIMP_P)
+ if (sparc_skip_caller_unimp)
abort ();
fputs ("\trestore\n\tretl\n\tadd\t%sp, %g1, %sp\n", file);
if (TARGET_V9 && ! epilogue_renumber (&delay, 1))
{
epilogue_renumber (&delay, 0);
- fputs (SKIP_CALLERS_UNIMP_P
+ fputs (sparc_skip_caller_unimp
? "\treturn\t%i7+12\n"
: "\treturn\t%i7+8\n", file);
final_scan_insn (XEXP (current_function_epilogue_delay_list, 0),
sparc_emitting_epilogue = false;
}
}
- else if (TARGET_V9 && ! SKIP_CALLERS_UNIMP_P)
+ else if (TARGET_V9 && ! sparc_skip_caller_unimp)
fputs ("\treturn\t%i7+8\n\tnop\n", file);
else
fprintf (file, "\t%s\n\trestore\n", ret);
{
rtx fn_rtx;
- if (GET_MODE (operands[0]) != FUNCTION_MODE)
+ if (GET_MODE (operands[0]) != FUNCTION_MODE)
abort ();
+ if (GET_CODE (operands[3]) != CONST_INT)
+ abort();
+
if (GET_CODE (XEXP (operands[0], 0)) == LABEL_REF)
{
/* This is really a PIC sequence. We want to represent
call-clobbered registers? We lose this if it is a JUMP_INSN.
Why cannot we have delay slots filled if it were a CALL? */
+ /* We accept negative sizes for untyped calls. */
if (! TARGET_ARCH64 && INTVAL (operands[3]) != 0)
emit_jump_insn
(gen_rtx_PARALLEL
fn_rtx = operands[0];
+ /* We accept negative sizes for untyped calls. */
if (! TARGET_ARCH64 && INTVAL (operands[3]) != 0)
emit_call_insn
(gen_rtx_PARALLEL
(match_operand 2 "immediate_operand" "")
(clobber (reg:SI 15))]
;;- Do not use operand 1 for most machines.
- "! TARGET_ARCH64 && GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) >= 0"
+ "! TARGET_ARCH64 && GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) > 0"
"call\t%a0, %1\n\tnop\n\tunimp\t%2"
[(set_attr "type" "call_no_delay_slot")
(set_attr "length" "3")])
(match_operand 2 "immediate_operand" "")
(clobber (reg:SI 15))]
;;- Do not use operand 1 for most machines.
- "! TARGET_ARCH64 && GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) >= 0"
+ "! TARGET_ARCH64 && GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) > 0"
"call\t%a0, %1\n\tnop\n\tunimp\t%2"
[(set_attr "type" "call_no_delay_slot")
(set_attr "length" "3")])
[(set_attr "type" "call_no_delay_slot")
(set_attr "length" "3")])
-;; This is a call that wants a structure value.
+;; This is a call that may want a structure value. This is used for
+;; untyped_calls.
(define_insn "*call_symbolic_untyped_struct_value_sp32"
[(call (mem:SI (match_operand:SI 0 "symbolic_operand" "s"))
(match_operand 1 "" ""))
(return)]
"sparc_emitting_epilogue"
{
- if (! TARGET_ARCH64 && current_function_returns_struct)
+ if (sparc_skip_caller_unimp)
return "jmp\t%%i7+12\n\trestore %%g0, %1, %Y0";
else if (TARGET_V9 && (GET_CODE (operands[1]) == CONST_INT
|| IN_OR_GLOBAL_P (operands[1])))
(return)]
"sparc_emitting_epilogue"
{
- if (! TARGET_ARCH64 && current_function_returns_struct)
+ if (sparc_skip_caller_unimp)
return "jmp\t%%i7+12\n\trestore %%g0, %1, %Y0";
else if (TARGET_V9 && (GET_CODE (operands[1]) == CONST_INT
|| IN_OR_GLOBAL_P (operands[1])))
(return)]
"sparc_emitting_epilogue"
{
- if (! TARGET_ARCH64 && current_function_returns_struct)
+ if (sparc_skip_caller_unimp)
return "jmp\t%%i7+12\n\trestore %%g0, %1, %Y0";
else if (TARGET_V9 && (GET_CODE (operands[1]) == CONST_INT
|| IN_OR_GLOBAL_P (operands[1])))
(return)]
"sparc_emitting_epilogue"
{
- if (! TARGET_ARCH64 && current_function_returns_struct)
+ if (sparc_skip_caller_unimp)
return "jmp\t%%i7+12\n\trestore %%g0, %1, %Y0";
else if (TARGET_V9 && IN_OR_GLOBAL_P (operands[1]))
return "return\t%%i7+8\n\tmov\t%Y1, %Y0";
(return)]
"sparc_emitting_epilogue"
{
- if (! TARGET_ARCH64 && current_function_returns_struct)
+ if (sparc_skip_caller_unimp)
return "jmp\t%%i7+12\n\trestore %r1, %2, %Y0";
/* If operands are global or in registers, can use return */
else if (TARGET_V9 && IN_OR_GLOBAL_P (operands[1])
(return)]
"sparc_emitting_epilogue && ! TARGET_CM_MEDMID"
{
- if (! TARGET_ARCH64 && current_function_returns_struct)
+ if (sparc_skip_caller_unimp)
return "jmp\t%%i7+12\n\trestore %r1, %%lo(%a2), %Y0";
/* If operands are global or in registers, can use return */
else if (TARGET_V9 && IN_OR_GLOBAL_P (operands[1]))