sparc.c (sparc_indent_opcode): New variable.

* config/sparc/sparc.c (sparc_indent_opcode): New variable.
	(output_return): Do not test for the presence of the 'unimp' insn.
	Use 'current_function_uses_only_leaf_regs' and 'final_sequence'
	as predicates instead of custom ones.  Return raw strings when
	possible.
	(output_sibcall): Likewise.  Concatenate strings.
	(output_ubranch): Remove kludge for TurboSPARC.
	(output_cbranch): Remove 'noop' parameter.  Do not output 'nop'.
	(output_v9branch): Likewise.
	(print_operand): Use 'final_sequence' instead of 'dbr_sequence_length'.
	<#>: Set sparc_indent_opcode if the delay slot is filled.
	<(>: Likewise.
	<)>: New operand to emit the displacement from the saved PC on return.
	<@>: Remove.
	* config/sparc/sparc.h (sparc_indent_opcode): Declare it.
	(ASM_OUTPUT_OPCODE): New macro.
	(PRINT_OPERAND_PUNCT_VALID_P): Remove '^' and add ')'.
	* config/sparc/sparc.md (normal_branch, inverted_branch,
	normal_fp_branch, inverted_fp_branch, normal_fpe_branch,
	inverted_fpe_branch): Adjust call to output_cbranch.
	(normal_int_branch_sp64, inverted_int_branch_sp64): Adjust
	call to output_v9branch.
	* config/sparc/sparc-protos.h (output_cbranch): Adjust.
	(output_v9branch): Likewise.

From-SVN: r87198
This commit is contained in:
Eric Botcazou 2004-09-08 21:17:53 +02:00 committed by Eric Botcazou
parent 5826770c62
commit 4e5b002baa
5 changed files with 132 additions and 152 deletions

View File

@ -1,3 +1,30 @@
2004-09-08 Eric Botcazou <ebotcazou@libertysurf.fr>
* config/sparc/sparc.c (sparc_indent_opcode): New variable.
(output_return): Do not test for the presence of the 'unimp' insn.
Use 'current_function_uses_only_leaf_regs' and 'final_sequence'
as predicates instead of custom ones. Return raw strings when
possible.
(output_sibcall): Likewise. Concatenate strings.
(output_ubranch): Remove kludge for TurboSPARC.
(output_cbranch): Remove 'noop' parameter. Do not output 'nop'.
(output_v9branch): Likewise.
(print_operand): Use 'final_sequence' instead of 'dbr_sequence_length'.
<#>: Set sparc_indent_opcode if the delay slot is filled.
<(>: Likewise.
<)>: New operand to emit the displacement from the saved PC on return.
<@>: Remove.
* config/sparc/sparc.h (sparc_indent_opcode): Declare it.
(ASM_OUTPUT_OPCODE): New macro.
(PRINT_OPERAND_PUNCT_VALID_P): Remove '^' and add ')'.
* config/sparc/sparc.md (normal_branch, inverted_branch,
normal_fp_branch, inverted_fp_branch, normal_fpe_branch,
inverted_fpe_branch): Adjust call to output_cbranch.
(normal_int_branch_sp64, inverted_int_branch_sp64): Adjust
call to output_v9branch.
* config/sparc/sparc-protos.h (output_cbranch): Adjust.
(output_v9branch): Likewise.
2004-09-08 Devang Patel <dpatel@apple.com>
* config/darwin.h (TARGET_OPTION_TRANSLATE_TABLE): Add -segaddr,

View File

@ -81,11 +81,11 @@ extern void sparc_emit_set_symbolic_const64 (rtx, rtx, rtx);
extern int sparc_splitdi_legitimate (rtx, rtx);
extern int sparc_absnegfloat_split_legitimate (rtx, rtx);
extern const char *output_ubranch (rtx, int, rtx);
extern const char *output_cbranch (rtx, rtx, int, int, int, int, rtx);
extern const char *output_cbranch (rtx, rtx, int, int, int, rtx);
extern const char *output_return (rtx);
extern const char *output_sibcall (rtx, rtx);
extern const char *output_v8plus_shift (rtx *, rtx, const char *);
extern const char *output_v9branch (rtx, rtx, int, int, int, int, int, rtx);
extern const char *output_v9branch (rtx, rtx, int, int, int, int, rtx);
extern void emit_v9_brxx_insn (enum rtx_code, rtx, rtx);
extern void print_operand (FILE *, rtx, int);
extern int mems_ok_for_ldd_peep (rtx, rtx, rtx);

View File

@ -276,10 +276,12 @@ struct machine_function GTY(())
Normally, this is %fp, but if we are in a leaf procedure, this
is %sp+"something". We record "something" separately as it may
be too big for reg+constant addressing. */
static rtx frame_base_reg;
static HOST_WIDE_INT frame_base_offset;
/* 1 if the next opcode is to be specially indented. */
int sparc_indent_opcode = 0;
static void sparc_init_modes (void);
static void scan_record_type (tree, int *, int *, int *);
static int function_arg_slotno (const CUMULATIVE_ARGS *, enum machine_mode,
@ -4675,44 +4677,17 @@ output_restore (rtx pat)
const char *
output_return (rtx insn)
{
int leaf_function_p = current_function_uses_only_leaf_regs;
bool delay_slot_filled_p = dbr_sequence_length () > 0;
/* 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. */
bool 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 (leaf_function_p)
if (current_function_uses_only_leaf_regs)
{
/* This is a leaf function so we don't have to bother restoring the
register window, which frees us from dealing with the convoluted
semantics of restore/return. We simply output the jump to the
return address and the insn in the delay slot, which usually is
the substraction restoring the stack pointer %sp. */
return address and the insn in the delay slot (if any). */
if (current_function_calls_eh_return)
abort ();
fprintf (asm_out_file, "\tjmp\t%%o7+%d\n", sparc_skip_caller_unimp ? 12 : 8);
if (delay_slot_filled_p)
{
rtx delay = NEXT_INSN (insn);
if (! delay)
abort ();
final_scan_insn (delay, asm_out_file, 1, 0, 1, NULL);
PATTERN (delay) = gen_blockage ();
INSN_CODE (delay) = -1;
}
else
fputs ("\t nop\n", asm_out_file);
return "jmp\t%%o7+%)%#";
}
else
{
@ -4725,7 +4700,7 @@ output_return (rtx insn)
{
/* If the function uses __builtin_eh_return, the eh_return
machinery occupies the delay slot. */
if (delay_slot_filled_p || sparc_skip_caller_unimp)
if (final_sequence)
abort ();
if (! flag_delayed_branch)
@ -4741,7 +4716,7 @@ output_return (rtx insn)
else
fputs ("\t nop\n", asm_out_file);
}
else if (delay_slot_filled_p)
else if (final_sequence)
{
rtx delay, pat;
@ -4754,32 +4729,25 @@ output_return (rtx insn)
if (TARGET_V9 && ! epilogue_renumber (&pat, 1))
{
epilogue_renumber (&pat, 0);
fprintf (asm_out_file, "\treturn\t%%i7+%d\n",
sparc_skip_caller_unimp ? 12 : 8);
final_scan_insn (delay, asm_out_file, 1, 0, 1, NULL);
return "return\t%%i7+%)%#";
}
else
{
fprintf (asm_out_file, "\tjmp\t%%i7+%d\n",
sparc_skip_caller_unimp ? 12 : 8);
output_asm_insn ("jmp\t%%i7+%)", NULL);
output_restore (pat);
PATTERN (delay) = gen_blockage ();
INSN_CODE (delay) = -1;
}
PATTERN (delay) = gen_blockage ();
INSN_CODE (delay) = -1;
}
else
{
/* The delay slot is empty. */
if (TARGET_V9)
fprintf (asm_out_file, "\treturn\t%%i7+%d\n\t nop\n",
sparc_skip_caller_unimp ? 12 : 8);
return "return\t%%i7+%)\n\t nop";
else if (flag_delayed_branch)
fprintf (asm_out_file, "\tjmp\t%%i7+%d\n\t restore\n",
sparc_skip_caller_unimp ? 12 : 8);
return "jmp\t%%i7+%)\n\t restore";
else
fprintf (asm_out_file, "\trestore\n\tjmp\t%%o7+%d\n\t nop\n",
sparc_skip_caller_unimp ? 12 : 8);
return "restore\n\tjmp\t%%o7+%)\n\t nop";
}
}
@ -4791,8 +4759,6 @@ output_return (rtx insn)
const char *
output_sibcall (rtx insn, rtx call_operand)
{
int leaf_function_p = current_function_uses_only_leaf_regs;
bool delay_slot_filled_p = dbr_sequence_length () > 0;
rtx operands[1];
if (! flag_delayed_branch)
@ -4800,36 +4766,23 @@ output_sibcall (rtx insn, rtx call_operand)
operands[0] = call_operand;
if (leaf_function_p)
if (current_function_uses_only_leaf_regs)
{
/* This is a leaf function so we don't have to bother restoring the
register window. We simply output the jump to the function and
the insn in the delay slot (if any). */
if (LEAF_SIBCALL_SLOT_RESERVED_P && delay_slot_filled_p)
if (LEAF_SIBCALL_SLOT_RESERVED_P && final_sequence)
abort();
if (delay_slot_filled_p)
{
rtx delay = NEXT_INSN (insn);
if (! delay)
abort ();
output_asm_insn ("sethi\t%%hi(%a0), %%g1", operands);
output_asm_insn ("jmp\t%%g1 + %%lo(%a0)", operands);
final_scan_insn (delay, asm_out_file, 1, 0, 1, NULL);
PATTERN (delay) = gen_blockage ();
INSN_CODE (delay) = -1;
}
if (final_sequence)
output_asm_insn ("sethi\t%%hi(%a0), %%g1\n\tjmp\t%%g1 + %%lo(%a0)%#",
operands);
else
{
/* Use or with rs2 %%g0 instead of mov, so that as/ld can optimize
it into branch if possible. */
output_asm_insn ("or\t%%o7, %%g0, %%g1", operands);
output_asm_insn ("call\t%a0, 0", operands);
output_asm_insn (" or\t%%g1, %%g0, %%o7", operands);
}
/* Use or with rs2 %%g0 instead of mov, so that as/ld can optimize
it into branch if possible. */
output_asm_insn ("or\t%%o7, %%g0, %%g1\n\tcall\t%a0, 0\n\t or\t%%g1, %%g0, %%o7",
operands);
}
else
{
@ -4839,7 +4792,7 @@ output_sibcall (rtx insn, rtx call_operand)
output_asm_insn ("call\t%a0, 0", operands);
if (delay_slot_filled_p)
if (final_sequence)
{
rtx delay = NEXT_INSN (insn);
if (! delay)
@ -6118,51 +6071,29 @@ const char *
output_ubranch (rtx dest, int label, rtx insn)
{
static char string[64];
bool noop = false;
bool v9_form = false;
char *p;
/* TurboSPARC is reported to have problems with
with
foo: b,a foo
i.e. an empty loop with the annul bit set. The workaround is to use
foo: b foo; nop
instead. */
if (! TARGET_V9 && flag_delayed_branch
&& (INSN_ADDRESSES (INSN_UID (dest))
== INSN_ADDRESSES (INSN_UID (insn))))
if (TARGET_V9 && INSN_ADDRESSES_SET_P ())
{
strcpy (string, "b\t");
noop = true;
int delta = (INSN_ADDRESSES (INSN_UID (dest))
- INSN_ADDRESSES (INSN_UID (insn)));
/* Leave some instructions for "slop". */
if (delta >= -260000 && delta < 260000)
v9_form = true;
}
if (v9_form)
strcpy (string, "ba%*,pt\t%%xcc, ");
else
{
bool v9_form = false;
if (TARGET_V9 && INSN_ADDRESSES_SET_P ())
{
int delta = (INSN_ADDRESSES (INSN_UID (dest))
- INSN_ADDRESSES (INSN_UID (insn)));
/* Leave some instructions for "slop". */
if (delta >= -260000 && delta < 260000)
v9_form = true;
}
if (v9_form)
strcpy (string, "ba%*,pt\t%%xcc, ");
else
strcpy (string, "b%*\t");
}
strcpy (string, "b%*\t");
p = strchr (string, '\0');
*p++ = '%';
*p++ = 'l';
*p++ = '0' + label;
*p++ = '%';
if (noop)
*p++ = '#';
else
*p++ = '(';
*p++ = '(';
*p = '\0';
return string;
@ -6177,13 +6108,11 @@ output_ubranch (rtx dest, int label, rtx insn)
REVERSED is nonzero if we should reverse the sense of the comparison.
ANNUL is nonzero if we should generate an annulling branch.
NOOP is nonzero if we have to follow this branch by a noop. */
ANNUL is nonzero if we should generate an annulling branch. */
const char *
output_cbranch (rtx op, rtx dest, int label, int reversed, int annul,
int noop, rtx insn)
rtx insn)
{
static char string[64];
enum rtx_code code = GET_CODE (op);
@ -6406,18 +6335,18 @@ output_cbranch (rtx op, rtx dest, int label, int reversed, int annul,
if (far)
{
strcpy (p, ".+12\n\t nop\n\tb\t");
if (annul || noop)
/* Skip the next insn if requested or
if we know that it will be a nop. */
if (annul || ! final_sequence)
p[3] = '6';
p += 14;
}
*p++ = '%';
*p++ = 'l';
/* Set the char indicating the number of the operand containing the
label_ref. */
*p++ = label + '0';
*p++ = '%';
*p++ = '#';
*p = '\0';
if (noop)
strcpy (p, "\n\t nop");
return string;
}
@ -6644,13 +6573,11 @@ sparc_emit_fixunsdi (rtx *operands, enum machine_mode mode)
REVERSED is nonzero if we should reverse the sense of the comparison.
ANNUL is nonzero if we should generate an annulling branch.
NOOP is nonzero if we have to follow this branch by a noop. */
ANNUL is nonzero if we should generate an annulling branch. */
const char *
output_v9branch (rtx op, rtx dest, int reg, int label, int reversed,
int annul, int noop, rtx insn)
int annul, rtx insn)
{
static char string[64];
enum rtx_code code = GET_CODE (op);
@ -6759,7 +6686,9 @@ output_v9branch (rtx op, rtx dest, int reg, int label, int reversed,
}
strcpy (p, ".+12\n\t nop\n\t");
if (annul || noop)
/* Skip the next insn if requested or
if we know that it will be a nop. */
if (annul || ! final_sequence)
p[3] = '6';
p += 12;
if (veryfar)
@ -6776,11 +6705,10 @@ output_v9branch (rtx op, rtx dest, int reg, int label, int reversed,
*p++ = '%';
*p++ = 'l';
*p++ = '0' + label;
*p++ = '%';
*p++ = '#';
*p = '\0';
if (noop)
strcpy (p, "\n\t nop");
return string;
}
@ -7077,43 +7005,55 @@ print_operand (FILE *file, rtx x, int code)
switch (code)
{
case '#':
/* Output a 'nop' if there's nothing for the delay slot. */
if (dbr_sequence_length () == 0)
/* Output an insn in a delay slot. */
if (final_sequence)
sparc_indent_opcode = 1;
else
fputs ("\n\t nop", file);
return;
case '*':
/* Output an annul flag if there's nothing for the delay slot and we
are optimizing. This is always used with '(' below. */
/* Sun OS 4.1.1 dbx can't handle an annulled unconditional branch;
this is a dbx bug. So, we only do this when optimizing. */
/* On UltraSPARC, a branch in a delay slot causes a pipeline flush.
are optimizing. This is always used with '(' below.
Sun OS 4.1.1 dbx can't handle an annulled unconditional branch;
this is a dbx bug. So, we only do this when optimizing.
On UltraSPARC, a branch in a delay slot causes a pipeline flush.
Always emit a nop in case the next instruction is a branch. */
if (dbr_sequence_length () == 0
&& (optimize && (int)sparc_cpu < PROCESSOR_V9))
if (! final_sequence && (optimize && (int)sparc_cpu < PROCESSOR_V9))
fputs (",a", file);
return;
case '(':
/* Output a 'nop' if there's nothing for the delay slot and we are
not optimizing. This is always used with '*' above. */
if (dbr_sequence_length () == 0
&& ! (optimize && (int)sparc_cpu < PROCESSOR_V9))
if (! final_sequence && ! (optimize && (int)sparc_cpu < PROCESSOR_V9))
fputs ("\n\t nop", file);
else if (final_sequence)
sparc_indent_opcode = 1;
return;
case ')':
/* Output the right displacement from the saved PC on function return.
The caller may have placed an "unimp" insn immediately after the call
so we have to account for it. 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. */
if (! 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))))
fputs ("12", file);
else
fputc ('8', file);
return;
case '_':
/* Output the Embedded Medium/Anywhere code model base register. */
fputs (EMBMEDANY_BASE_REG, file);
return;
case '@':
/* Print out what we are using as the frame pointer. This might
be %fp, or might be %sp+offset. */
/* ??? What if offset is too big? Perhaps the caller knows it isn't? */
fprintf (file, "%s+"HOST_WIDE_INT_PRINT_DEC,
reg_names[REGNO (frame_base_reg)], frame_base_offset);
return;
case '&':
/* Print some local dynamic TLS name. */
assemble_name (file, get_some_local_dynamic_name ());
return;
case 'Y':
/* Adjust the operand to take into account a RESTORE operation. */
if (GET_CODE (x) == CONST_INT)

View File

@ -2517,6 +2517,19 @@ do { \
#define ASM_OUTPUT_IDENT(FILE, NAME) \
fprintf (FILE, "%s\"%s\"\n", IDENT_ASM_OP, NAME);
/* Prettify the assembly. */
extern int sparc_indent_opcode;
#define ASM_OUTPUT_OPCODE(FILE, PTR) \
do { \
if (sparc_indent_opcode) \
{ \
putc (' ', FILE); \
sparc_indent_opcode = 0; \
} \
} while (0)
/* Emit a dtp-relative reference to a TLS variable. */
#ifdef HAVE_AS_TLS
@ -2525,8 +2538,8 @@ do { \
#endif
#define PRINT_OPERAND_PUNCT_VALID_P(CHAR) \
((CHAR) == '#' || (CHAR) == '*' || (CHAR) == '^' \
|| (CHAR) == '(' || (CHAR) == '_' || (CHAR) == '&')
((CHAR) == '#' || (CHAR) == '*' || (CHAR) == '(' \
|| (CHAR) == ')' || (CHAR) == '_' || (CHAR) == '&')
/* Print operand X (an rtx) in assembler syntax to file FILE.
CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified.

View File

@ -1549,7 +1549,7 @@
{
return output_cbranch (operands[0], operands[1], 1, 0,
final_sequence && INSN_ANNULLED_BRANCH_P (insn),
! final_sequence, insn);
insn);
}
[(set_attr "type" "branch")
(set_attr "branch_type" "icc")])
@ -1565,7 +1565,7 @@
{
return output_cbranch (operands[0], operands[1], 1, 1,
final_sequence && INSN_ANNULLED_BRANCH_P (insn),
! final_sequence, insn);
insn);
}
[(set_attr "type" "branch")
(set_attr "branch_type" "icc")])
@ -1582,7 +1582,7 @@
{
return output_cbranch (operands[1], operands[2], 2, 0,
final_sequence && INSN_ANNULLED_BRANCH_P (insn),
! final_sequence, insn);
insn);
}
[(set_attr "type" "branch")
(set_attr "branch_type" "fcc")])
@ -1599,7 +1599,7 @@
{
return output_cbranch (operands[1], operands[2], 2, 1,
final_sequence && INSN_ANNULLED_BRANCH_P (insn),
! final_sequence, insn);
insn);
}
[(set_attr "type" "branch")
(set_attr "branch_type" "fcc")])
@ -1616,7 +1616,7 @@
{
return output_cbranch (operands[1], operands[2], 2, 0,
final_sequence && INSN_ANNULLED_BRANCH_P (insn),
! final_sequence, insn);
insn);
}
[(set_attr "type" "branch")
(set_attr "branch_type" "fcc")])
@ -1633,7 +1633,7 @@
{
return output_cbranch (operands[1], operands[2], 2, 1,
final_sequence && INSN_ANNULLED_BRANCH_P (insn),
! final_sequence, insn);
insn);
}
[(set_attr "type" "branch")
(set_attr "branch_type" "fcc")])
@ -1655,7 +1655,7 @@
{
return output_v9branch (operands[0], operands[2], 1, 2, 0,
final_sequence && INSN_ANNULLED_BRANCH_P (insn),
! final_sequence, insn);
insn);
}
[(set_attr "type" "branch")
(set_attr "branch_type" "reg")])
@ -1672,7 +1672,7 @@
{
return output_v9branch (operands[0], operands[2], 1, 2, 1,
final_sequence && INSN_ANNULLED_BRANCH_P (insn),
! final_sequence, insn);
insn);
}
[(set_attr "type" "branch")
(set_attr "branch_type" "reg")])