/* Subroutines for insn-output.c for SPARC.
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com)
64-bit SPARC-V9 support by Michael Tiemann, Jim Wilson, and Doug Evans,
static void emit_save_or_restore_regs (int);
static void sparc_asm_function_prologue (FILE *, HOST_WIDE_INT);
static void sparc_asm_function_epilogue (FILE *, HOST_WIDE_INT);
-#ifdef OBJECT_FORMAT_ELF
+#if defined (OBJECT_FORMAT_ELF) && !defined (HAVE_GNU_AS)
static void sparc_elf_asm_named_section (const char *, unsigned int, tree);
#endif
static bool sparc_rtx_costs (rtx, int, int, int *, bool);
static bool sparc_promote_prototypes (const_tree);
static rtx sparc_struct_value_rtx (tree, int);
+static enum machine_mode sparc_promote_function_mode (const_tree, enum machine_mode,
+ int *, const_tree, int);
static bool sparc_return_in_memory (const_tree, const_tree);
static bool sparc_strict_argument_naming (CUMULATIVE_ARGS *);
static void sparc_va_start (tree, rtx);
static tree sparc_gimplify_va_arg (tree, tree, gimple_seq *, gimple_seq *);
static bool sparc_vector_mode_supported_p (enum machine_mode);
+static bool sparc_tls_referenced_p (rtx);
+static rtx legitimize_tls_address (rtx);
+static rtx legitimize_pic_address (rtx, rtx);
static rtx sparc_legitimize_address (rtx, rtx, enum machine_mode);
static bool sparc_pass_by_reference (CUMULATIVE_ARGS *,
enum machine_mode, const_tree, bool);
static void sparc_dwarf_handle_frame_unspec (const char *, rtx, int);
static void sparc_output_dwarf_dtprel (FILE *, int, rtx) ATTRIBUTE_UNUSED;
static void sparc_file_end (void);
+static bool sparc_frame_pointer_required (void);
+static bool sparc_can_eliminate (const int, const int);
#ifdef TARGET_ALTERNATE_LONG_DOUBLE_MANGLING
static const char *sparc_mangle_type (const_tree);
#endif
+static void sparc_trampoline_init (rtx, tree, rtx);
\f
#ifdef SUBTARGET_ATTRIBUTE_TABLE
/* Table of valid machine attributes. */
#undef TARGET_ADDRESS_COST
#define TARGET_ADDRESS_COST hook_int_rtx_bool_0
-/* This is only needed for TARGET_ARCH64, but since PROMOTE_FUNCTION_MODE is a
- no-op for TARGET_ARCH32 this is ok. Otherwise we'd need to add a runtime
- test for this value. */
-#undef TARGET_PROMOTE_FUNCTION_ARGS
-#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_const_tree_true
-
-/* This is only needed for TARGET_ARCH64, but since PROMOTE_FUNCTION_MODE is a
- no-op for TARGET_ARCH32 this is ok. Otherwise we'd need to add a runtime
- test for this value. */
-#undef TARGET_PROMOTE_FUNCTION_RETURN
-#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_const_tree_true
+#undef TARGET_PROMOTE_FUNCTION_MODE
+#define TARGET_PROMOTE_FUNCTION_MODE sparc_promote_function_mode
#undef TARGET_PROMOTE_PROTOTYPES
#define TARGET_PROMOTE_PROTOTYPES sparc_promote_prototypes
#undef TARGET_ASM_FILE_END
#define TARGET_ASM_FILE_END sparc_file_end
+#undef TARGET_FRAME_POINTER_REQUIRED
+#define TARGET_FRAME_POINTER_REQUIRED sparc_frame_pointer_required
+
+#undef TARGET_CAN_ELIMINATE
+#define TARGET_CAN_ELIMINATE sparc_can_eliminate
+
#ifdef TARGET_ALTERNATE_LONG_DOUBLE_MANGLING
#undef TARGET_MANGLE_TYPE
#define TARGET_MANGLE_TYPE sparc_mangle_type
#undef TARGET_LEGITIMATE_ADDRESS_P
#define TARGET_LEGITIMATE_ADDRESS_P sparc_legitimate_address_p
+#undef TARGET_TRAMPOLINE_INIT
+#define TARGET_TRAMPOLINE_INIT sparc_trampoline_init
+
struct gcc_target targetm = TARGET_INITIALIZER;
/* Implement TARGET_HANDLE_OPTION. */
const struct cpu_table *cpu;
const struct sparc_cpu_select *sel;
int fpu;
-
+
#ifndef SPARC_BI_ARCH
/* Check for unsupported architecture size. */
if (! TARGET_64BIT != DEFAULT_ARCH32_P)
/* Code model selection. */
sparc_cmodel = SPARC_DEFAULT_CMODEL;
-
+
#ifdef SPARC_BI_ARCH
if (TARGET_ARCH32)
sparc_cmodel = CM_32;
/* Don't use stack biasing in 32 bit mode. */
if (TARGET_ARCH32)
target_flags &= ~MASK_STACK_BIAS;
-
+
/* Supply a default value for align_functions. */
if (align_functions == 0
&& (sparc_cpu == PROCESSOR_ULTRASPARC
: (sparc_cpu == PROCESSOR_ULTRASPARC3
? 8 : 3)));
if (!PARAM_SET_P (PARAM_L1_CACHE_LINE_SIZE))
- set_param_value ("l1-cache-line-size",
+ set_param_value ("l1-cache-line-size",
((sparc_cpu == PROCESSOR_ULTRASPARC
|| sparc_cpu == PROCESSOR_ULTRASPARC3
|| sparc_cpu == PROCESSOR_NIAGARA
/* Fixup TLS cases. */
if (TARGET_HAVE_TLS
&& CONSTANT_P (operands[1])
- && GET_CODE (operands[1]) != HIGH
&& sparc_tls_referenced_p (operands [1]))
{
- rtx sym = operands[1];
- rtx addend = NULL;
-
- if (GET_CODE (sym) == CONST && GET_CODE (XEXP (sym, 0)) == PLUS)
- {
- addend = XEXP (XEXP (sym, 0), 1);
- sym = XEXP (XEXP (sym, 0), 0);
- }
-
- gcc_assert (SPARC_SYMBOL_REF_TLS_P (sym));
-
- sym = legitimize_tls_address (sym);
- if (addend)
- {
- sym = gen_rtx_PLUS (mode, sym, addend);
- sym = force_operand (sym, operands[0]);
- }
- operands[1] = sym;
+ operands[1] = legitimize_tls_address (operands[1]);
+ return false;
}
-
+
/* Fixup PIC cases. */
if (flag_pic && CONSTANT_P (operands[1]))
{
if (pic_address_needs_scratch (operands[1]))
- operands[1] = legitimize_pic_address (operands[1], mode, 0);
+ operands[1] = legitimize_pic_address (operands[1], NULL_RTX);
/* VxWorks does not impose a fixed gap between segments; the run-time
gap can be different from the object-file gap. We therefore can't
if (symbolic_operand (operands[1], mode))
{
operands[1] = legitimize_pic_address (operands[1],
- mode,
- (reload_in_progress ?
- operands[0] :
- NULL_RTX));
+ reload_in_progress
+ ? operands[0] : NULL_RTX);
return false;
}
}
/* input_operand should have filtered out 32-bit mode. */
sparc_emit_set_const64 (operands[0], operands[1]);
return true;
-
+
default:
gcc_unreachable ();
}
if (code == LTU || code == GEU)
{
emit_insn (gen_rtx_SET (VOIDmode, operands[0],
- gen_rtx_fmt_ee (code, SImode,
+ gen_rtx_fmt_ee (code, SImode,
gen_compare_reg_1 (code, x, y),
const0_rtx)));
return true;
}
}
-/* Return true if X is an address which needs a temporary register when
+/* Return true if X is an address which needs a temporary register when
reloaded while generating PIC code. */
int
bool
legitimate_constant_p (rtx x)
{
- rtx inner;
-
switch (GET_CODE (x))
{
- case SYMBOL_REF:
- /* TLS symbols are not constant. */
- if (SYMBOL_REF_TLS_MODEL (x))
- return false;
- break;
-
case CONST:
- inner = XEXP (x, 0);
-
- /* Offsets of TLS symbols are never valid.
- Discourage CSE from creating them. */
- if (GET_CODE (inner) == PLUS
- && SPARC_SYMBOL_REF_TLS_P (XEXP (inner, 0)))
+ case SYMBOL_REF:
+ if (sparc_tls_referenced_p (x))
return false;
break;
{
if (pic_address_needs_scratch (x))
return false;
- if (SPARC_SYMBOL_REF_TLS_P (x)
- || (GET_CODE (x) == CONST
- && GET_CODE (XEXP (x, 0)) == PLUS
- && SPARC_SYMBOL_REF_TLS_P (XEXP (XEXP (x, 0), 0))))
+ if (sparc_tls_referenced_p (x))
return false;
return true;
}
/* Return nonzero if ADDR is a valid memory address.
STRICT specifies whether strict register checking applies. */
-
+
static bool
sparc_legitimate_address_p (enum machine_mode mode, rtx addr, bool strict)
{
&& GET_CODE (rs2) != SUBREG
&& GET_CODE (rs2) != LO_SUM
&& GET_CODE (rs2) != MEM
- && ! SPARC_SYMBOL_REF_TLS_P (rs2)
+ && !(GET_CODE (rs2) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (rs2))
&& (! symbolic_operand (rs2, VOIDmode) || mode == Pmode)
&& (GET_CODE (rs2) != CONST_INT || SMALL_INT (rs2)))
|| ((REG_P (rs1)
rs2 = NULL;
imm1 = XEXP (rs1, 1);
rs1 = XEXP (rs1, 0);
- if (! CONSTANT_P (imm1) || SPARC_SYMBOL_REF_TLS_P (rs1))
+ if (!CONSTANT_P (imm1)
+ || (GET_CODE (rs1) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (rs1)))
return 0;
}
}
rs1 = XEXP (addr, 0);
imm1 = XEXP (addr, 1);
- if (! CONSTANT_P (imm1) || SPARC_SYMBOL_REF_TLS_P (rs1))
+ if (!CONSTANT_P (imm1)
+ || (GET_CODE (rs1) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (rs1)))
return 0;
/* We can't allow TFmode in 32-bit mode, because an offset greater
return temp;
}
-/* Return 1 if *X is a thread-local symbol. */
+/* Return true if X contains a thread-local symbol. */
-static int
-sparc_tls_symbol_ref_1 (rtx *x, void *data ATTRIBUTE_UNUSED)
-{
- return SPARC_SYMBOL_REF_TLS_P (*x);
-}
-
-/* Return 1 if X contains a thread-local symbol. */
-
-bool
+static bool
sparc_tls_referenced_p (rtx x)
{
if (!TARGET_HAVE_TLS)
return false;
- return for_each_rtx (&x, &sparc_tls_symbol_ref_1, 0);
+ if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS)
+ x = XEXP (XEXP (x, 0), 0);
+
+ if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x))
+ return true;
+
+ /* That's all we handle in legitimize_tls_address for now. */
+ return false;
}
/* ADDR contains a thread-local SYMBOL_REF. Generate code to compute
this (thread-local) address. */
-rtx
+static rtx
legitimize_tls_address (rtx addr)
{
rtx temp1, temp2, temp3, ret, o0, got, insn;
gcc_unreachable ();
}
+ else if (GET_CODE (addr) == CONST)
+ {
+ rtx base, offset;
+
+ gcc_assert (GET_CODE (XEXP (addr, 0)) == PLUS);
+
+ base = legitimize_tls_address (XEXP (XEXP (addr, 0), 0));
+ offset = XEXP (XEXP (addr, 0), 1);
+
+ base = force_operand (base, NULL_RTX);
+ if (!(GET_CODE (offset) == CONST_INT && SMALL_INT (offset)))
+ offset = force_reg (Pmode, offset);
+ ret = gen_rtx_PLUS (Pmode, base, offset);
+ }
+
else
gcc_unreachable (); /* for now ... */
return ret;
}
-
/* Legitimize PIC addresses. If the address is already position-independent,
we return ORIG. Newly generated position-independent addresses go into a
reg. This is REG if nonzero, otherwise we allocate register(s) as
necessary. */
-rtx
-legitimize_pic_address (rtx orig, enum machine_mode mode ATTRIBUTE_UNUSED,
- rtx reg)
+static rtx
+legitimize_pic_address (rtx orig, rtx reg)
{
if (GET_CODE (orig) == SYMBOL_REF
/* See the comment in sparc_expand_move. */
}
gcc_assert (GET_CODE (XEXP (orig, 0)) == PLUS);
- base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg);
- offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
- base == reg ? 0 : reg);
+ base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), reg);
+ offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1),
+ base == reg ? NULL_RTX : reg);
if (GET_CODE (offset) == CONST_INT)
{
On SPARC, change REG+N into REG+REG, and REG+(X*Y) into REG+REG. */
-rtx
+static rtx
sparc_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
enum machine_mode mode)
{
if (x != orig_x && sparc_legitimate_address_p (mode, x, FALSE))
return x;
- if (SPARC_SYMBOL_REF_TLS_P (x))
+ if (sparc_tls_referenced_p (x))
x = legitimize_tls_address (x);
else if (flag_pic)
- x = legitimize_pic_address (x, mode, 0);
+ x = legitimize_pic_address (x, NULL_RTX);
else if (GET_CODE (x) == PLUS && CONSTANT_ADDRESS_P (XEXP (x, 1)))
x = gen_rtx_PLUS (Pmode, XEXP (x, 0),
copy_to_mode_reg (Pmode, XEXP (x, 1)));
copy_to_mode_reg (Pmode, XEXP (x, 0)));
else if (GET_CODE (x) == SYMBOL_REF
|| GET_CODE (x) == CONST
- || GET_CODE (x) == LABEL_REF)
+ || GET_CODE (x) == LABEL_REF)
x = copy_to_suggested_reg (x, NULL_RTX, Pmode);
+
return x;
}
it is to a constant address, or the address involves a LO_SUM. */
return 1;
}
-
+
/* An obviously unaligned address. */
return 0;
}
#define SF_MODES (S_MODES)
/* Modes for double-float and smaller quantities. */
-#define DF_MODES (S_MODES | D_MODES)
-
-/* Modes for double-float only quantities. */
-#define DF_MODES_NO_S ((1 << (int) D_MODE) | (1 << (int) DF_MODE))
-
-/* Modes for quad-float only quantities. */
-#define TF_ONLY_MODES (1 << (int) TF_MODE)
+#define DF_MODES (D_MODES)
/* Modes for quad-float and smaller quantities. */
-#define TF_MODES (DF_MODES | TF_ONLY_MODES)
+#define TF_MODES (DF_MODES | (1 << (int) TF_MODE))
-/* Modes for quad-float and double-float quantities. */
-#define TF_MODES_NO_S (DF_MODES_NO_S | TF_ONLY_MODES)
+/* Modes for quad-float pairs and smaller quantities. */
+#define OF_MODES (TF_MODES | (1 << (int) OF_MODE))
-/* Modes for quad-float pair only quantities. */
-#define OF_ONLY_MODES (1 << (int) OF_MODE)
+/* Modes for double-float only quantities. */
+#define DF_MODES_NO_S ((1 << (int) D_MODE) | (1 << (int) DF_MODE))
-/* Modes for quad-float pairs and smaller quantities. */
-#define OF_MODES (TF_MODES | OF_ONLY_MODES)
+/* Modes for quad-float and double-float only quantities. */
+#define TF_MODES_NO_S (DF_MODES_NO_S | (1 << (int) TF_MODE))
-#define OF_MODES_NO_S (TF_MODES_NO_S | OF_ONLY_MODES)
+/* Modes for quad-float pairs and double-float only quantities. */
+#define OF_MODES_NO_S (TF_MODES_NO_S | (1 << (int) OF_MODE))
/* Modes for condition codes. */
#define CC_MODES (1 << (int) CC_MODE)
sparc_mode_class[i] = 1 << (int) T_MODE;
else if (GET_MODE_SIZE (i) == 32)
sparc_mode_class[i] = 1 << (int) O_MODE;
- else
+ else
sparc_mode_class[i] = 0;
break;
case MODE_VECTOR_INT:
sparc_mode_class[i] = 1 << (int) TF_MODE;
else if (GET_MODE_SIZE (i) == 32)
sparc_mode_class[i] = 1 << (int) OF_MODE;
- else
+ else
sparc_mode_class[i] = 0;
break;
case MODE_CC:
if (flag_pic && crtl->uses_pic_offset_table)
load_pic_register (false);
}
-
+
/* This function generates the assembly code for function entry, which boils
down to emitting the necessary .register directives. */
return sparc_prologue_data_valid_p
&& (actual_fsize == 0 || !sparc_leaf_function_p);
}
-
+
/* This function generates the assembly code for function exit. */
-
+
static void
sparc_asm_function_epilogue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
{
sparc_output_deferred_case_vectors ();
}
-
+
/* Output a 'restore' instruction. */
-
+
static void
output_restore (rtx pat)
{
break;
}
}
-
+
/* Output a return. */
const char *
the appropriate fp reg and in memory.
- Summary of the calling conventions implemented by GCC on SPARC:
+ Summary of the calling conventions implemented by GCC on the SPARC:
32-bit ABI:
size argument return value
Note #2: integral vector types follow the scalar floating-point types
conventions to match what is implemented by the Sun VIS SDK.
-Note #3: floating-point vector types follow the aggregate types
+Note #3: floating-point vector types follow the aggregate types
conventions. */
return TARGET_ARCH32 ? true : false;
}
+/* Handle promotion of pointer and integer arguments. */
+
+static enum machine_mode
+sparc_promote_function_mode (const_tree type ATTRIBUTE_UNUSED,
+ enum machine_mode mode,
+ int *punsignedp ATTRIBUTE_UNUSED,
+ const_tree fntype ATTRIBUTE_UNUSED,
+ int for_return ATTRIBUTE_UNUSED)
+{
+ if (POINTER_TYPE_P (type))
+ {
+ *punsignedp = POINTERS_EXTEND_UNSIGNED;
+ return Pmode;
+ }
+
+ /* For TARGET_ARCH64 we need this, as we don't have instructions
+ for arithmetic operations which do zero/sign extension at the same time,
+ so without this we end up with a srl/sra after every assignment to an
+ user variable, which means very very bad code. */
+ if (TARGET_ARCH64
+ && GET_MODE_CLASS (mode) == MODE_INT
+ && GET_MODE_SIZE (mode) < UNITS_PER_WORD)
+ return word_mode;
+
+ return mode;
+}
+
/* Handle the TARGET_STRICT_ARGUMENT_NAMING target hook. */
static bool
/* A subroutine of function_arg_record_value. Assign the bits of the
structure between parms->intoffset and bitpos to integer registers. */
-static void
+static void
function_arg_record_value_3 (HOST_WIDE_INT bitpos,
struct function_arg_record_value_parms *parms)
{
NAMED is nonzero if this argument is a named parameter
(otherwise it is an extra parameter matching an ellipsis).
REGBASE is the regno of the base register for the parameter array. */
-
+
static rtx
function_arg_record_value (const_tree type, enum machine_mode mode,
int slotno, int named, int regbase)
/* Original SPARC 64-bit ABI says that structures and unions
smaller than 16 bytes are passed in registers, as well as
all other base types.
-
+
Extended ABI (as implemented by the Sun compiler) says that
complex floats are passed in registers up to 16 bytes. Pass
all complex integers in registers up to 16 bytes. More generally,
/* Original SPARC 64-bit ABI says that structures and unions
smaller than 32 bytes are returned in registers, as well as
all other base types.
-
+
Extended ABI (as implemented by the Sun compiler) says that all
complex floats are returned in registers (8 FP registers at most
for '_Complex long double'). Return all complex integers in
mem = gen_rtx_MEM (Pmode, plus_constant (stack_pointer_rtx,
STRUCT_VALUE_OFFSET));
- /* Only follow the SPARC ABI for fixed-size structure returns.
- Variable size structure returns are handled per the normal
+ /* Only follow the SPARC ABI for fixed-size structure returns.
+ Variable size structure returns are handled per the normal
procedures in GCC. This is enabled by -mstd-struct-return */
- if (incoming == 2
+ if (incoming == 2
&& sparc_std_struct_return
&& TYPE_SIZE_UNIT (TREE_TYPE (fndecl))
&& TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (fndecl))) == INTEGER_CST)
provided. */
rtx ret_rtx = gen_rtx_REG (Pmode, 31);
rtx scratch = gen_reg_rtx (SImode);
- rtx endlab = gen_label_rtx ();
+ rtx endlab = gen_label_rtx ();
/* Calculate the return object size */
tree size = TYPE_SIZE_UNIT (TREE_TYPE (fndecl));
rtx temp_val = assign_stack_local (Pmode, TREE_INT_CST_LOW (size), 0);
/* Implement SPARC 32-bit psABI callee returns struck checking
- requirements:
-
+ requirements:
+
Fetch the instruction where we will return to and see if
it's an unimp instruction (the most significant 10 bits
will be zero). */
emit_insn (gen_add3_insn (ret_rtx, ret_rtx, GEN_INT (4)));
emit_cmp_and_jump_insns (scratch, size_rtx, EQ, const0_rtx, SImode, 0, endlab);
emit_insn (gen_sub3_insn (ret_rtx, ret_rtx, GEN_INT (4)));
- /* Assign stack temp:
+ /* Assign stack temp:
Write the address of the memory pointed to by temp_val into
the memory pointed to by mem */
emit_move_insn (mem, XEXP (temp_val, 0));
mclass = MODE_INT;
}
- /* This must match PROMOTE_FUNCTION_MODE. */
+ /* This must match sparc_promote_function_mode.
+ ??? Maybe 32-bit pointers should actually remain in Pmode? */
else if (mclass == MODE_INT && GET_MODE_SIZE (mode) < UNITS_PER_WORD)
mode = word_mode;
}
sparc_emit_float_lib_cmp (rtx x, rtx y, enum rtx_code comparison)
{
const char *qpfunc;
- rtx slot0, slot1, result, tem, tem2;
+ rtx slot0, slot1, result, tem, tem2, libfunc;
enum machine_mode mode;
enum rtx_code new_comparison;
emit_move_insn (slot1, y);
}
- emit_library_call (gen_rtx_SYMBOL_REF (Pmode, qpfunc), LCT_NORMAL,
+ libfunc = gen_rtx_SYMBOL_REF (Pmode, qpfunc);
+ emit_library_call (libfunc, LCT_NORMAL,
DImode, 2,
XEXP (slot0, 0), Pmode,
XEXP (slot1, 0), Pmode);
}
else
{
- emit_library_call (gen_rtx_SYMBOL_REF (Pmode, qpfunc), LCT_NORMAL,
+ libfunc = gen_rtx_SYMBOL_REF (Pmode, qpfunc);
+ emit_library_call (libfunc, LCT_NORMAL,
SImode, 2,
x, TFmode, y, TFmode);
mode = SImode;
register so reload doesn't clobber the value if it needs
the return register for a spill reg. */
result = gen_reg_rtx (mode);
- emit_move_insn (result, hard_libcall_value (mode));
+ emit_move_insn (result, hard_libcall_value (mode, libfunc));
switch (comparison)
{
/* branch on register are limited to +-128KB. If it is too far away,
change
-
+
brnz,pt %g1, .LC30
-
+
to
-
+
brz,pn %g1, .+12
nop
ba,pt %xcc, .LC30
-
+
and
-
+
brgez,a,pn %o1, .LC29
-
+
to
-
+
brlz,pt %o1, .+16
nop
ba,pt %xcc, .LC29 */
}
/* Return 1 if REGNO (reg1) is even and REGNO (reg1) == REGNO (reg2) - 1.
- This makes them candidates for using ldd and std insns.
+ This makes them candidates for using ldd and std insns.
Note reg1 and reg2 *must* be hard registers. */
registers_ok_for_ldd_peep (rtx reg1, rtx reg2)
{
/* We might have been passed a SUBREG. */
- if (GET_CODE (reg1) != REG || GET_CODE (reg2) != REG)
+ if (GET_CODE (reg1) != REG || GET_CODE (reg2) != REG)
return 0;
if (REGNO (reg1) % 2 != 0)
return 0;
- /* Integer ldd is deprecated in SPARC V9 */
- if (TARGET_V9 && REGNO (reg1) < 32)
- return 0;
+ /* Integer ldd is deprecated in SPARC V9 */
+ if (TARGET_V9 && REGNO (reg1) < 32)
+ return 0;
return (REGNO (reg1) == REGNO (reg2) - 1);
}
/* Return 1 if the addresses in mem1 and mem2 are suitable for use in
an ldd or std insn.
-
+
This can only happen when addr1 and addr2, the addresses in mem1
and mem2, are consecutive memory locations (addr1 + 4 == addr2).
addr1 must also be aligned on a 64-bit boundary.
/* MEM1 should be aligned on a 64-bit boundary. */
if (MEM_ALIGN (mem1) < 64)
return 0;
-
+
addr1 = XEXP (mem1, 0);
addr2 = XEXP (mem2, 0);
-
+
/* Extract a register number and offset (if used) from the first addr. */
if (GET_CODE (addr1) == PLUS)
{
if (dependent_reg_rtx != NULL_RTX && reg1 == REGNO (dependent_reg_rtx))
return 0;
-
- /* The first offset must be evenly divisible by 8 to ensure the
+
+ /* The first offset must be evenly divisible by 8 to ensure the
address is 64 bit aligned. */
if (offset1 % 8 != 0)
return 0;
/* 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
+ 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. The exception here is that when
- sparc_std_struct_return is enabled, the psABI is followed exactly
- and the adjustment is made by the code in sparc_struct_value_rtx.
- The call emitted is the same when sparc_std_struct_return is
- present. */
- if (! TARGET_ARCH64
+ as that for the call. The exception is when sparc_std_struct_return
+ is enabled, the psABI is followed exactly and the adjustment is made
+ by the code in sparc_struct_value_rtx. The call emitted is the same
+ when sparc_std_struct_return is enabled. */
+ if (!TARGET_ARCH64
&& cfun->returns_struct
- && ! sparc_std_struct_return
- && (TREE_CODE (DECL_SIZE (DECL_RESULT (current_function_decl)))
- == INTEGER_CST)
- && ! integer_zerop (DECL_SIZE (DECL_RESULT (current_function_decl))))
+ && !sparc_std_struct_return
+ && DECL_SIZE (DECL_RESULT (current_function_decl))
+ && 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);
{
case ERROR_MARK:
return qualifiers;
-
+
case ARRAY_TYPE:
qualifiers |= (3 << shift);
break;
if (TYPE_PRECISION (type) <= CHAR_TYPE_SIZE)
return (qualifiers | (TYPE_UNSIGNED (type) ? 12 : 2));
-
+
else if (TYPE_PRECISION (type) <= SHORT_TYPE_SIZE)
return (qualifiers | (TYPE_UNSIGNED (type) ? 13 : 3));
-
+
else if (TYPE_PRECISION (type) <= INT_TYPE_SIZE)
return (qualifiers | (TYPE_UNSIGNED (type) ? 14 : 4));
-
+
else
return (qualifiers | (TYPE_UNSIGNED (type) ? 15 : 5));
-
+
case REAL_TYPE:
/* If this is a range type, consider it to be the underlying
type. */
if (TYPE_PRECISION (type) == FLOAT_TYPE_SIZE)
return (qualifiers | 6);
- else
+ else
return (qualifiers | 7);
-
+
case COMPLEX_TYPE: /* GNU Fortran COMPLEX type. */
/* ??? We need to distinguish between double and float complex types,
but I don't know how yet because I can't reach this code from
case BOOLEAN_TYPE: /* Boolean truth value type. */
case LANG_TYPE: /* ? */
return qualifiers;
-
+
default:
gcc_unreachable (); /* Not a type! */
}
Emit enough FLUSH insns to synchronize the data and instruction caches. */
-void
-sparc_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
+static void
+sparc32_initialize_trampoline (rtx m_tramp, rtx fnaddr, rtx cxt)
{
/* SPARC 32-bit trampoline:
*/
emit_move_insn
- (gen_rtx_MEM (SImode, plus_constant (tramp, 0)),
+ (adjust_address (m_tramp, SImode, 0),
expand_binop (SImode, ior_optab,
expand_shift (RSHIFT_EXPR, SImode, fnaddr,
size_int (10), 0, 1),
NULL_RTX, 1, OPTAB_DIRECT));
emit_move_insn
- (gen_rtx_MEM (SImode, plus_constant (tramp, 4)),
+ (adjust_address (m_tramp, SImode, 4),
expand_binop (SImode, ior_optab,
expand_shift (RSHIFT_EXPR, SImode, cxt,
size_int (10), 0, 1),
NULL_RTX, 1, OPTAB_DIRECT));
emit_move_insn
- (gen_rtx_MEM (SImode, plus_constant (tramp, 8)),
+ (adjust_address (m_tramp, SImode, 8),
expand_binop (SImode, ior_optab,
expand_and (SImode, fnaddr, GEN_INT (0x3ff), NULL_RTX),
GEN_INT (trunc_int_for_mode (0x81c06000, SImode)),
NULL_RTX, 1, OPTAB_DIRECT));
emit_move_insn
- (gen_rtx_MEM (SImode, plus_constant (tramp, 12)),
+ (adjust_address (m_tramp, SImode, 12),
expand_binop (SImode, ior_optab,
expand_and (SImode, cxt, GEN_INT (0x3ff), NULL_RTX),
GEN_INT (trunc_int_for_mode (0x8410a000, SImode)),
/* On UltraSPARC a flush flushes an entire cache line. The trampoline is
aligned on a 16 byte boundary so one flush clears it all. */
- emit_insn (gen_flush (validize_mem (gen_rtx_MEM (SImode, tramp))));
+ emit_insn (gen_flush (validize_mem (adjust_address (m_tramp, SImode, 0))));
if (sparc_cpu != PROCESSOR_ULTRASPARC
&& sparc_cpu != PROCESSOR_ULTRASPARC3
&& sparc_cpu != PROCESSOR_NIAGARA
&& sparc_cpu != PROCESSOR_NIAGARA2)
- emit_insn (gen_flush (validize_mem (gen_rtx_MEM (SImode,
- plus_constant (tramp, 8)))));
+ emit_insn (gen_flush (validize_mem (adjust_address (m_tramp, SImode, 8))));
/* Call __enable_execute_stack after writing onto the stack to make sure
the stack address is accessible. */
#ifdef ENABLE_EXECUTE_STACK
emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__enable_execute_stack"),
- LCT_NORMAL, VOIDmode, 1, tramp, Pmode);
+ LCT_NORMAL, VOIDmode, 1, XEXP (m_tramp, 0), Pmode);
#endif
}
values as "immediate" data out of the trampoline. It's also easier since
we can read the PC without clobbering a register. */
-void
-sparc64_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
+static void
+sparc64_initialize_trampoline (rtx m_tramp, rtx fnaddr, rtx cxt)
{
/* SPARC 64-bit trampoline:
+16 bytes data
*/
- emit_move_insn (gen_rtx_MEM (SImode, tramp),
+ emit_move_insn (adjust_address (m_tramp, SImode, 0),
GEN_INT (trunc_int_for_mode (0x83414000, SImode)));
- emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 4)),
+ emit_move_insn (adjust_address (m_tramp, SImode, 4),
GEN_INT (trunc_int_for_mode (0xca586018, SImode)));
- emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 8)),
+ emit_move_insn (adjust_address (m_tramp, SImode, 8),
GEN_INT (trunc_int_for_mode (0x81c14000, SImode)));
- emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 12)),
+ emit_move_insn (adjust_address (m_tramp, SImode, 12),
GEN_INT (trunc_int_for_mode (0xca586010, SImode)));
- emit_move_insn (gen_rtx_MEM (DImode, plus_constant (tramp, 16)), cxt);
- emit_move_insn (gen_rtx_MEM (DImode, plus_constant (tramp, 24)), fnaddr);
- emit_insn (gen_flushdi (validize_mem (gen_rtx_MEM (DImode, tramp))));
+ emit_move_insn (adjust_address (m_tramp, DImode, 16), cxt);
+ emit_move_insn (adjust_address (m_tramp, DImode, 24), fnaddr);
+ emit_insn (gen_flushdi (validize_mem (adjust_address (m_tramp, DImode, 0))));
if (sparc_cpu != PROCESSOR_ULTRASPARC
&& sparc_cpu != PROCESSOR_ULTRASPARC3
&& sparc_cpu != PROCESSOR_NIAGARA
&& sparc_cpu != PROCESSOR_NIAGARA2)
- emit_insn (gen_flushdi (validize_mem (gen_rtx_MEM (DImode, plus_constant (tramp, 8)))));
+ emit_insn (gen_flushdi (validize_mem (adjust_address (m_tramp, DImode, 8))));
/* Call __enable_execute_stack after writing onto the stack to make sure
the stack address is accessible. */
#ifdef ENABLE_EXECUTE_STACK
emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__enable_execute_stack"),
- LCT_NORMAL, VOIDmode, 1, tramp, Pmode);
+ LCT_NORMAL, VOIDmode, 1, XEXP (m_tramp, 0), Pmode);
#endif
}
+
+/* Worker for TARGET_TRAMPOLINE_INIT. */
+
+static void
+sparc_trampoline_init (rtx m_tramp, tree fndecl, rtx cxt)
+{
+ rtx fnaddr = force_reg (Pmode, XEXP (DECL_RTL (fndecl), 0));
+ cxt = force_reg (Pmode, cxt);
+ if (TARGET_ARCH64)
+ sparc64_initialize_trampoline (m_tramp, fnaddr, cxt);
+ else
+ sparc32_initialize_trampoline (m_tramp, fnaddr, cxt);
+}
\f
/* Adjust the cost of a scheduling dependency. Return the new cost of
a dependency LINK or INSN on DEP_INSN. COST is the current cost. */
if (dep_type == TYPE_STORE || dep_type == TYPE_FPSTORE)
{
if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET
- || GET_CODE (SET_DEST (dep_pat)) != MEM
+ || GET_CODE (SET_DEST (dep_pat)) != MEM
|| GET_CODE (SET_SRC (pat)) != MEM
|| ! rtx_equal_p (XEXP (SET_DEST (dep_pat), 0),
XEXP (SET_SRC (pat), 0)))
return cost + 2;
- return cost + 8;
+ return cost + 8;
}
break;
default:
break;
- }
+ }
return cost;
}
sparc_sched_init (FILE *dump ATTRIBUTE_UNUSED,
int sched_verbose ATTRIBUTE_UNUSED,
int max_ready ATTRIBUTE_UNUSED)
-{
-}
-
+{}
+
static int
sparc_use_sched_lookahead (void)
{
sparc_addr_list = gen_rtx_EXPR_LIST (VOIDmode, vec, sparc_addr_list);
}
-static void
+static void
sparc_output_addr_vec (rtx vec)
{
rtx lab = XEXP (vec, 0), body = XEXP (vec, 1);
int idx, vlen = XVECLEN (body, 0);
-#ifdef ASM_OUTPUT_ADDR_VEC_START
+#ifdef ASM_OUTPUT_ADDR_VEC_START
ASM_OUTPUT_ADDR_VEC_START (asm_out_file);
#endif
ASM_OUTPUT_ADDR_VEC_ELT
(asm_out_file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0)));
}
-
+
#ifdef ASM_OUTPUT_ADDR_VEC_END
ASM_OUTPUT_ADDR_VEC_END (asm_out_file);
#endif
}
-static void
+static void
sparc_output_addr_diff_vec (rtx vec)
{
rtx lab = XEXP (vec, 0), body = XEXP (vec, 1);
rtx base = XEXP (XEXP (body, 0), 0);
int idx, vlen = XVECLEN (body, 1);
-#ifdef ASM_OUTPUT_ADDR_VEC_START
+#ifdef ASM_OUTPUT_ADDR_VEC_START
ASM_OUTPUT_ADDR_VEC_START (asm_out_file);
#endif
CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 1, idx), 0)),
CODE_LABEL_NUMBER (base));
}
-
+
#ifdef ASM_OUTPUT_ADDR_VEC_END
ASM_OUTPUT_ADDR_VEC_END (asm_out_file);
#endif
align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
if (align > 0)
ASM_OUTPUT_ALIGN (asm_out_file, align);
-
+
for (t = sparc_addr_list; t ; t = XEXP (t, 1))
sparc_output_addr_vec (XEXP (t, 0));
for (t = sparc_addr_diff_list; t ; t = XEXP (t, 1))
}
}
\f
-#ifdef OBJECT_FORMAT_ELF
+#if defined (OBJECT_FORMAT_ELF) && !defined (HAVE_GNU_AS)
static void
sparc_elf_asm_named_section (const char *name, unsigned int flags,
tree decl)
{
- if (flags & SECTION_MERGE)
- {
- /* entsize cannot be expressed in this section attributes
- encoding style. */
- default_elf_asm_named_section (name, flags, decl);
- return;
- }
-
fprintf (asm_out_file, "\t.section\t\"%s\"", name);
if (!(flags & SECTION_DEBUG))
/* Find the "this" pointer. Normally in %o0, but in ARCH64 if the function
returns a structure, the structure return pointer is there instead. */
- if (TARGET_ARCH64 && aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
+ if (TARGET_ARCH64
+ && aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
this_rtx = gen_rtx_REG (Pmode, int_arg_first + 1);
else
this_rtx = gen_rtx_REG (Pmode, int_arg_first);
/* Delay emitting the PIC helper function because it needs to
change the section and we are emitting assembly code. */
load_pic_register (true); /* clobbers %o7 */
- scratch = legitimize_pic_address (funexp, Pmode, scratch);
+ scratch = legitimize_pic_address (funexp, scratch);
seq = get_insns ();
end_sequence ();
emit_and_preserve (seq, spill_reg, spill_reg2);
final_start_function (insn, file, 1);
final (insn, file, 1);
final_end_function ();
- free_after_compilation (cfun);
reload_completed = 0;
epilogue_completed = 0;
emit_move_insn (result, gen_lowpart (GET_MODE (result), res));
}
+/* Implement TARGET_FRAME_POINTER_REQUIRED. */
+
+bool
+sparc_frame_pointer_required (void)
+{
+ return !(leaf_function_p () && only_leaf_regs_used ());
+}
+
+/* The way this is structured, we can't eliminate SFP in favor of SP
+ if the frame pointer is required: we want to use the SFP->HFP elimination
+ in that case. But the test in update_eliminables doesn't know we are
+ assuming below that we only do the former elimination. */
+
+bool
+sparc_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to)
+{
+ return (to == HARD_FRAME_POINTER_REGNUM
+ || !targetm.frame_pointer_required ());
+}
+
#include "gt-sparc.h"