/* 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
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com)
64-bit SPARC-V9 support by Michael Tiemann, Jim Wilson, and Doug Evans,
#include "target.h"
#include "target-def.h"
#include "cfglayout.h"
-#include "tree-gimple.h"
+#include "gimple.h"
#include "langhooks.h"
#include "params.h"
#include "df.h"
/* Save the operands last given to a compare for use when we
generate a scc or bcc insn. */
-rtx sparc_compare_op0, sparc_compare_op1, sparc_compare_emitted;
+rtx sparc_compare_op0, sparc_compare_op1;
/* Vector to say how input registers are mapped to output registers.
HARD_FRAME_POINTER_REGNUM cannot be remapped by this function to
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1};
-struct machine_function GTY(())
+struct GTY(()) machine_function
{
/* Some local-dynamic TLS symbol name. */
const char *some_ld_name;
static rtx sparc_tls_got (void);
static const char *get_some_local_dynamic_name (void);
static int get_some_local_dynamic_name_1 (rtx *, void *);
-static bool sparc_rtx_costs (rtx, int, int, int *);
+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 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, tree *, tree *);
+static tree sparc_gimplify_va_arg (tree, tree, gimple_seq *, gimple_seq *);
static bool sparc_vector_mode_supported_p (enum machine_mode);
+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 int sparc_arg_partial_bytes (CUMULATIVE_ARGS *,
#undef TARGET_INIT_BUILTINS
#define TARGET_INIT_BUILTINS sparc_init_builtins
+#undef TARGET_LEGITIMIZE_ADDRESS
+#define TARGET_LEGITIMIZE_ADDRESS sparc_legitimize_address
+
#undef TARGET_EXPAND_BUILTIN
#define TARGET_EXPAND_BUILTIN sparc_expand_builtin
#undef TARGET_FOLD_BUILTIN
#undef TARGET_RTX_COSTS
#define TARGET_RTX_COSTS sparc_rtx_costs
#undef TARGET_ADDRESS_COST
-#define TARGET_ADDRESS_COST hook_int_rtx_0
+#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
#undef TARGET_HANDLE_OPTION
#define TARGET_HANDLE_OPTION sparc_handle_option
-#if TARGET_GNU_TLS
+#if TARGET_GNU_TLS && defined(HAVE_AS_SPARC_UA_PCREL)
#undef TARGET_ASM_OUTPUT_DWARF_DTPREL
#define TARGET_ASM_OUTPUT_DWARF_DTPREL sparc_output_dwarf_dtprel
#endif
{
static struct code_model {
const char *const name;
- const int value;
+ const enum cmodel value;
} const cmodels[] = {
{ "32", CM_32 },
{ "medlow", CM_MEDLOW },
{ "medmid", CM_MEDMID },
{ "medany", CM_MEDANY },
{ "embmedany", CM_EMBMEDANY },
- { 0, 0 }
+ { NULL, (enum cmodel) 0 }
};
const struct code_model *cmodel;
/* Map TARGET_CPU_DEFAULT to value for -m{arch,tune}=. */
/* UltraSPARC T1 */
{ "niagara", PROCESSOR_NIAGARA, MASK_ISA, MASK_V9|MASK_DEPRECATED_V8_INSNS},
{ "niagara2", PROCESSOR_NIAGARA, MASK_ISA, MASK_V9},
- { 0, 0, 0, 0 }
+ { 0, (enum processor_type) 0, 0, 0 }
};
const struct cpu_table *cpu;
const struct sparc_cpu_select *sel;
}
}
-/* X and Y are two things to compare using CODE. Emit the compare insn and
- return the rtx for the cc reg in the proper mode. */
+/* Emit the compare insn and return the CC reg for a CODE comparison. */
rtx
gen_compare_reg (enum rtx_code code)
{
- rtx x = sparc_compare_op0;
- rtx y = sparc_compare_op1;
- enum machine_mode mode = SELECT_CC_MODE (code, x, y);
- rtx cc_reg;
+ enum machine_mode mode;
+ rtx x, y, cc_reg;
- if (sparc_compare_emitted != NULL_RTX)
- {
- cc_reg = sparc_compare_emitted;
- sparc_compare_emitted = NULL_RTX;
- return cc_reg;
- }
+ if (GET_MODE_CLASS (GET_MODE (sparc_compare_op0)) == MODE_CC)
+ return sparc_compare_op0;
+
+ x = sparc_compare_op0;
+ y = sparc_compare_op1;
+ mode = SELECT_CC_MODE (code, x, y);
/* ??? We don't have movcc patterns so we cannot generate pseudo regs for the
fcc regs (cse can't tell they're really call clobbered regs and will
else
cc_reg = gen_rtx_REG (mode, SPARC_ICC_REG);
- emit_insn (gen_rtx_SET (VOIDmode, cc_reg,
- gen_rtx_COMPARE (mode, x, y)));
+ /* We shouldn't get there for TFmode if !TARGET_HARD_QUAD. If we do, this
+ will only result in an unrecognizable insn so no point in asserting. */
+ emit_insn (gen_rtx_SET (VOIDmode, cc_reg, gen_rtx_COMPARE (mode, x, y)));
return cc_reg;
}
+/* Same as above but return the whole compare operator. */
+
+rtx
+gen_compare_operator (enum rtx_code code)
+{
+ rtx cc_reg;
+
+ if (GET_MODE (sparc_compare_op0) == TFmode && !TARGET_HARD_QUAD)
+ code
+ = sparc_emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, code);
+
+ cc_reg = gen_compare_reg (code);
+ return gen_rtx_fmt_ee (code, GET_MODE (cc_reg), cc_reg, const0_rtx);
+}
+
/* This function is used for v9 only.
CODE is the code for an Scc's comparison.
OPERANDS[0] is the target of the Scc insn.
void
emit_v9_brxx_insn (enum rtx_code code, rtx op0, rtx label)
{
- gcc_assert (sparc_compare_emitted == NULL_RTX);
+ gcc_assert (GET_MODE_CLASS (GET_MODE (sparc_compare_op0)) != MODE_CC);
emit_jump_insn (gen_rtx_SET (VOIDmode,
pc_rtx,
gen_rtx_IF_THEN_ELSE (VOIDmode,
{
case SImode:
func = "_Qp_itoq";
+ if (TARGET_ARCH64)
+ operands[1] = gen_rtx_SIGN_EXTEND (DImode, operands[1]);
break;
case DImode:
func = "_Qp_xtoq";
{
case SImode:
func = "_Qp_uitoq";
+ if (TARGET_ARCH64)
+ operands[1] = gen_rtx_ZERO_EXTEND (DImode, operands[1]);
break;
case DImode:
func = "_Qp_uxtoq";
/* If the function uses __builtin_eh_return, the eh_return machinery
occupies the delay slot. */
- if (current_function_calls_eh_return)
+ if (crtl->calls_eh_return)
return 0;
/* In the case of a true leaf function, anything can go into the slot. */
rtx temp;
if (flag_pic)
{
- current_function_uses_pic_offset_table = 1;
+ crtl->uses_pic_offset_table = 1;
return pic_offset_table_rtx;
}
pic_ref = gen_const_mem (Pmode,
gen_rtx_PLUS (Pmode,
pic_offset_table_rtx, address));
- current_function_uses_pic_offset_table = 1;
+ crtl->uses_pic_offset_table = 1;
insn = emit_move_insn (reg, pic_ref);
/* Put a REG_EQUAL note on this insn, so that it can be optimized
by loop. */
/* ??? Why do we do this? */
/* Now movsi_pic_label_ref uses it, but we ought to be checking that
the register is live instead, in case it is eliminated. */
- current_function_uses_pic_offset_table = 1;
+ crtl->uses_pic_offset_table = 1;
return orig;
}
OLDX is the address as it was before break_out_memory_refs was called.
In some cases it is useful to look at this to decide what needs to be done.
- MODE is the mode of the operand pointed to by X. */
+ MODE is the mode of the operand pointed to by X.
+
+ On SPARC, change REG+N into REG+REG, and REG+(X*Y) into REG+REG. */
rtx
-legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, enum machine_mode mode)
+sparc_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
+ enum machine_mode mode)
{
rtx orig_x = x;
if (TARGET_VXWORKS_RTP)
{
emit_insn (gen_vxworks_load_got ());
- emit_insn (gen_rtx_USE (VOIDmode, pic_offset_table_rtx));
+ emit_use (pic_offset_table_rtx);
return;
}
since setjmp/longjmp can cause life info to screw up.
??? In the case where we don't obey regdecls, this is not sufficient
since we may not fall out the bottom. */
- emit_insn (gen_rtx_USE (VOIDmode, pic_offset_table_rtx));
+ emit_use (pic_offset_table_rtx);
}
/* Emit a call instruction with the pattern given by PAT. ADDR is the
: !SYMBOL_REF_LOCAL_P (addr)))
{
use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx);
- current_function_uses_pic_offset_table = 1;
+ crtl->uses_pic_offset_table = 1;
}
}
\f
HOST_WIDE_INT
sparc_compute_frame_size (HOST_WIDE_INT size, int leaf_function_p)
{
- int outgoing_args_size = (current_function_outgoing_args_size
+ int outgoing_args_size = (crtl->outgoing_args_size
+ REG_PARM_STACK_SPACE (current_function_decl));
int n_regs = 0; /* N_REGS is the number of 4-byte regs saved thus far. */
int i;
if (leaf_function_p
&& n_regs == 0
&& size == 0
- && current_function_outgoing_args_size == 0)
+ && crtl->outgoing_args_size == 0)
actual_fsize = apparent_fsize = 0;
else
{
rtx reg = gen_rtx_REG (Pmode, 1);
emit_move_insn (reg, GEN_INT (-actual_fsize));
insn = emit_insn (gen_stack_pointer_inc (reg));
- REG_NOTES (insn) =
- gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
- gen_stack_pointer_inc (GEN_INT (-actual_fsize)),
- REG_NOTES (insn));
+ add_reg_note (insn, REG_FRAME_RELATED_EXPR,
+ gen_stack_pointer_inc (GEN_INT (-actual_fsize)));
}
RTX_FRAME_RELATED_P (insn) = 1;
emit_save_or_restore_regs (SORR_SAVE);
/* Load the PIC register if needed. */
- if (flag_pic && current_function_uses_pic_offset_table)
+ if (flag_pic && crtl->uses_pic_offset_table)
load_pic_register (false);
}
semantics of restore/return. We simply output the jump to the
return address and the insn in the delay slot (if any). */
- gcc_assert (! current_function_calls_eh_return);
+ gcc_assert (! crtl->calls_eh_return);
return "jmp\t%%o7+%)%#";
}
combined with the 'restore' instruction or put in the delay slot of
the 'return' instruction. */
- if (current_function_calls_eh_return)
+ if (crtl->calls_eh_return)
{
/* If the function uses __builtin_eh_return, the eh_return
machinery occupies the delay slot. */
{
case MODE_FLOAT:
case MODE_COMPLEX_FLOAT:
+ case MODE_VECTOR_INT:
if (TARGET_ARCH64 && TARGET_FPU && named)
{
if (slotno >= SPARC_FP_ARG_MAX)
Return an expression valid as a return value for the two macros
FUNCTION_ARG and FUNCTION_VALUE.
- SIZE is the size in bytes of the vector.
- BASE_MODE is the argument's base machine mode.
+ SIZE is the size in bytes of the vector (at least 8 bytes).
REGNO is the FP hard register the vector will be passed in. */
static rtx
-function_arg_vector_value (int size, enum machine_mode base_mode, int regno)
+function_arg_vector_value (int size, int regno)
{
- unsigned short base_mode_size = GET_MODE_SIZE (base_mode);
- int nregs = size / base_mode_size, i;
+ int i, nregs = size / 8;
rtx regs;
regs = gen_rtx_PARALLEL (BLKmode, rtvec_alloc (nregs));
{
XVECEXP (regs, 0, i)
= gen_rtx_EXPR_LIST (VOIDmode,
- gen_rtx_REG (base_mode, regno),
- GEN_INT (base_mode_size * i));
- regno += base_mode_size / 4;
+ gen_rtx_REG (DImode, regno + 2*i),
+ GEN_INT (i*8));
}
return regs;
if (mode == BLKmode)
return function_arg_vector_value (size,
- TYPE_MODE (TREE_TYPE (type)),
SPARC_FP_ARG_FIRST + 2*slotno);
else
mclass = MODE_FLOAT;
if (mode == BLKmode)
return function_arg_vector_value (size,
- TYPE_MODE (TREE_TYPE (type)),
SPARC_FP_ARG_FIRST);
else
mclass = MODE_FLOAT;
static rtx
sparc_builtin_saveregs (void)
{
- int first_reg = current_function_args_info.words;
+ int first_reg = crtl->args.info.words;
rtx address;
int regno;
/* Implement `va_arg' for stdarg. */
static tree
-sparc_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
+sparc_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p,
+ gimple_seq *post_p)
{
HOST_WIDE_INT size, rsize, align;
tree addr, incr;
size = int_size_in_bytes (type);
rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
align = 0;
-
+
if (TARGET_ARCH64)
{
/* For SPARC64, objects requiring 16-byte alignment get it. */
addr = fold_convert (build_pointer_type (ptrtype), addr);
addr = build_va_arg_indirect_ref (addr);
}
- /* If the address isn't aligned properly for the type,
- we may need to copy to a temporary.
- FIXME: This is inefficient. Usually we can do this
- in registers. */
- else if (align == 0
- && TYPE_ALIGN (type) > BITS_PER_WORD)
+
+ /* If the address isn't aligned properly for the type, we need a temporary.
+ FIXME: This is inefficient, usually we can do this in registers. */
+ else if (align == 0 && TYPE_ALIGN (type) > BITS_PER_WORD)
{
tree tmp = create_tmp_var (type, "va_arg_tmp");
tree dest_addr = build_fold_addr_expr (tmp);
-
- tree copy = build_call_expr (implicit_built_in_decls[BUILT_IN_MEMCPY], 3,
- dest_addr,
- addr,
- size_int (rsize));
-
+ tree copy = build_call_expr (implicit_built_in_decls[BUILT_IN_MEMCPY],
+ 3, dest_addr, addr, size_int (rsize));
+ TREE_ADDRESSABLE (tmp) = 1;
gimplify_and_add (copy, pre_p);
addr = dest_addr;
}
+
else
addr = fold_convert (ptrtype, addr);
- incr = fold_build2 (POINTER_PLUS_EXPR, ptr_type_node, incr, size_int (rsize));
- incr = build2 (GIMPLE_MODIFY_STMT, ptr_type_node, valist, incr);
- gimplify_and_add (incr, post_p);
+ incr
+ = fold_build2 (POINTER_PLUS_EXPR, ptr_type_node, incr, size_int (rsize));
+ gimplify_assign (valist, incr, post_p);
return build_va_arg_indirect_ref (addr);
}
}
/* Emit a library call comparison between floating point X and Y.
- COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.).
+ COMPARISON is the operator to compare with (EQ, NE, GT, etc).
+ Return the new operator to be used in the comparison sequence.
+
TARGET_ARCH64 uses _Qp_* functions, which use pointers to TFmode
values as arguments instead of the TFmode registers themselves,
that's why we cannot call emit_float_lib_cmp. */
-void
+
+enum rtx_code
sparc_emit_float_lib_cmp (rtx x, rtx y, enum rtx_code comparison)
{
const char *qpfunc;
rtx slot0, slot1, result, tem, tem2;
enum machine_mode mode;
+ enum rtx_code new_comparison;
switch (comparison)
{
case EQ:
- qpfunc = (TARGET_ARCH64) ? "_Qp_feq" : "_Q_feq";
+ qpfunc = (TARGET_ARCH64 ? "_Qp_feq" : "_Q_feq");
break;
case NE:
- qpfunc = (TARGET_ARCH64) ? "_Qp_fne" : "_Q_fne";
+ qpfunc = (TARGET_ARCH64 ? "_Qp_fne" : "_Q_fne");
break;
case GT:
- qpfunc = (TARGET_ARCH64) ? "_Qp_fgt" : "_Q_fgt";
+ qpfunc = (TARGET_ARCH64 ? "_Qp_fgt" : "_Q_fgt");
break;
case GE:
- qpfunc = (TARGET_ARCH64) ? "_Qp_fge" : "_Q_fge";
+ qpfunc = (TARGET_ARCH64 ? "_Qp_fge" : "_Q_fge");
break;
case LT:
- qpfunc = (TARGET_ARCH64) ? "_Qp_flt" : "_Q_flt";
+ qpfunc = (TARGET_ARCH64 ? "_Qp_flt" : "_Q_flt");
break;
case LE:
- qpfunc = (TARGET_ARCH64) ? "_Qp_fle" : "_Q_fle";
+ qpfunc = (TARGET_ARCH64 ? "_Qp_fle" : "_Q_fle");
break;
case ORDERED:
case UNGE:
case UNLE:
case LTGT:
- qpfunc = (TARGET_ARCH64) ? "_Qp_cmp" : "_Q_cmp";
+ qpfunc = (TARGET_ARCH64 ? "_Qp_cmp" : "_Q_cmp");
break;
default:
if (TARGET_ARCH64)
{
- if (GET_CODE (x) != MEM)
+ if (MEM_P (x))
+ slot0 = x;
+ else
{
slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
emit_move_insn (slot0, x);
}
- else
- slot0 = x;
- if (GET_CODE (y) != MEM)
+ if (MEM_P (y))
+ slot1 = y;
+ else
{
slot1 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
emit_move_insn (slot1, y);
}
- else
- slot1 = y;
emit_library_call (gen_rtx_SYMBOL_REF (Pmode, qpfunc), LCT_NORMAL,
DImode, 2,
XEXP (slot0, 0), Pmode,
XEXP (slot1, 0), Pmode);
-
mode = DImode;
}
else
emit_library_call (gen_rtx_SYMBOL_REF (Pmode, qpfunc), LCT_NORMAL,
SImode, 2,
x, TFmode, y, TFmode);
-
mode = SImode;
}
switch (comparison)
{
default:
- emit_cmp_insn (result, const0_rtx, NE, NULL_RTX, mode, 0);
+ new_comparison = NE;
+ emit_cmp_insn (result, const0_rtx, new_comparison, NULL_RTX, mode, 0);
break;
case ORDERED:
case UNORDERED:
- emit_cmp_insn (result, GEN_INT(3), comparison == UNORDERED ? EQ : NE,
- NULL_RTX, mode, 0);
+ new_comparison = (comparison == UNORDERED ? EQ : NE);
+ emit_cmp_insn (result, GEN_INT(3), new_comparison, NULL_RTX, mode, 0);
break;
case UNGT:
case UNGE:
- emit_cmp_insn (result, const1_rtx,
- comparison == UNGT ? GT : NE, NULL_RTX, mode, 0);
+ new_comparison = (comparison == UNGT ? GT : NE);
+ emit_cmp_insn (result, const1_rtx, new_comparison, NULL_RTX, mode, 0);
break;
case UNLE:
- emit_cmp_insn (result, const2_rtx, NE, NULL_RTX, mode, 0);
+ new_comparison = NE;
+ emit_cmp_insn (result, const2_rtx, new_comparison, NULL_RTX, mode, 0);
break;
case UNLT:
tem = gen_reg_rtx (mode);
emit_insn (gen_andsi3 (tem, result, const1_rtx));
else
emit_insn (gen_anddi3 (tem, result, const1_rtx));
- emit_cmp_insn (tem, const0_rtx, NE, NULL_RTX, mode, 0);
+ new_comparison = NE;
+ emit_cmp_insn (tem, const0_rtx, new_comparison, NULL_RTX, mode, 0);
break;
case UNEQ:
case LTGT:
emit_insn (gen_andsi3 (tem2, tem, const2_rtx));
else
emit_insn (gen_anddi3 (tem2, tem, const2_rtx));
- emit_cmp_insn (tem2, const0_rtx, comparison == UNEQ ? EQ : NE,
- NULL_RTX, mode, 0);
+ new_comparison = (comparison == UNEQ ? EQ : NE);
+ emit_cmp_insn (tem2, const0_rtx, new_comparison, NULL_RTX, mode, 0);
break;
}
+
+ return new_comparison;
}
/* Generate an unsigned DImode to FP conversion. This is the same code
return 1;
}
-/* Return 1 if reg is a pseudo, or is the first register in
- a hard register pair. This makes it a candidate for use in
+/* Return 1 if reg is a pseudo, or is the first register in
+ a hard register pair. This makes it suitable for use in
ldd and std insns. */
int
register_ok_for_ldd (rtx reg)
{
/* We might have been passed a SUBREG. */
- if (GET_CODE (reg) != REG)
+ if (!REG_P (reg))
return 0;
if (REGNO (reg) < FIRST_PSEUDO_REGISTER)
return (REGNO (reg) % 2 == 0);
- else
- return 1;
+
+ return 1;
+}
+
+/* Return 1 if OP is a memory whose address is known to be
+ aligned to 8-byte boundary, or a pseudo during reload.
+ This makes it suitable for use in ldd and std insns. */
+
+int
+memory_ok_for_ldd (rtx op)
+{
+ if (MEM_P (op))
+ {
+ /* In 64-bit mode, we assume that the address is word-aligned. */
+ if (TARGET_ARCH32 && !mem_min_alignment (op, 8))
+ return 0;
+
+ if ((reload_in_progress || reload_completed)
+ && !strict_memory_address_p (Pmode, XEXP (op, 0)))
+ return 0;
+ }
+ else if (REG_P (op) && REGNO (op) >= FIRST_PSEUDO_REGISTER)
+ {
+ if (!(reload_in_progress && reg_renumber [REGNO (op)] < 0))
+ return 0;
+ }
+ else
+ return 0;
+
+ return 1;
}
\f
/* Print operand X (an rtx) in assembler syntax to file FILE.
The call emitted is the same when sparc_std_struct_return is
present. */
if (! TARGET_ARCH64
- && current_function_returns_struct
+ && cfun->returns_struct
&& ! sparc_std_struct_return
&& (TREE_CODE (DECL_SIZE (DECL_RESULT (current_function_decl)))
== INTEGER_CST)
char buf[32];
rtx lab, fun;
- ASM_GENERATE_INTERNAL_LABEL (buf, "LP", labelno);
- lab = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
fun = gen_rtx_SYMBOL_REF (Pmode, MCOUNT_FUNCTION);
-
- emit_library_call (fun, LCT_NORMAL, VOIDmode, 1, lab, Pmode);
+ if (NO_PROFILE_COUNTERS)
+ {
+ emit_library_call (fun, LCT_NORMAL, VOIDmode, 0);
+ }
+ else
+ {
+ ASM_GENERATE_INTERNAL_LABEL (buf, "LP", labelno);
+ lab = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
+ emit_library_call (fun, LCT_NORMAL, VOIDmode, 1, lab, Pmode);
+ }
}
\f
#ifdef OBJECT_FORMAT_ELF
{
return (decl
&& flag_delayed_branch
- && (TARGET_ARCH64 || ! current_function_returns_struct)
+ && (TARGET_ARCH64 || ! cfun->returns_struct)
&& !(TARGET_VXWORKS_RTP
&& flag_pic
&& !targetm.binds_local_p (decl)));
{
tree arg0, arg1, arg2;
tree rtype = TREE_TYPE (TREE_TYPE (fndecl));
+ enum insn_code icode = (enum insn_code) DECL_FUNCTION_CODE (fndecl);
if (ignore
- && DECL_FUNCTION_CODE (fndecl) != CODE_FOR_alignaddrsi_vis
- && DECL_FUNCTION_CODE (fndecl) != CODE_FOR_alignaddrdi_vis)
+ && icode != CODE_FOR_alignaddrsi_vis
+ && icode != CODE_FOR_alignaddrdi_vis)
return fold_convert (rtype, integer_zero_node);
- switch (DECL_FUNCTION_CODE (fndecl))
+ switch (icode)
{
case CODE_FOR_fexpand_vis:
arg0 = TREE_VALUE (arglist);
tree inner_type = TREE_TYPE (rtype);
tree elts0 = TREE_VECTOR_CST_ELTS (arg0);
tree elts1 = TREE_VECTOR_CST_ELTS (arg1);
- tree n_elts = sparc_handle_vis_mul8x16 (DECL_FUNCTION_CODE (fndecl),
- inner_type, elts0, elts1);
+ tree n_elts = sparc_handle_vis_mul8x16 (icode, inner_type, elts0,
+ elts1);
return build_vector (rtype, n_elts);
}
return NULL_TREE;
}
\f
-int
-sparc_extra_constraint_check (rtx op, int c, int strict)
-{
- int reload_ok_mem;
-
- if (TARGET_ARCH64
- && (c == 'T' || c == 'U'))
- return 0;
-
- switch (c)
- {
- case 'Q':
- return fp_sethi_p (op);
-
- case 'R':
- return fp_mov_p (op);
-
- case 'S':
- return fp_high_losum_p (op);
-
- case 'U':
- if (! strict
- || (GET_CODE (op) == REG
- && (REGNO (op) < FIRST_PSEUDO_REGISTER
- || reg_renumber[REGNO (op)] >= 0)))
- return register_ok_for_ldd (op);
-
- return 0;
-
- case 'W':
- case 'T':
- break;
-
- case 'Y':
- return const_zero_operand (op, GET_MODE (op));
-
- default:
- return 0;
- }
-
- /* Our memory extra constraints have to emulate the
- behavior of 'm' and 'o' in order for reload to work
- correctly. */
- if (GET_CODE (op) == MEM)
- {
- reload_ok_mem = 0;
- if ((TARGET_ARCH64 || mem_min_alignment (op, 8))
- && (! strict
- || strict_memory_address_p (Pmode, XEXP (op, 0))))
- reload_ok_mem = 1;
- }
- else
- {
- reload_ok_mem = (reload_in_progress
- && GET_CODE (op) == REG
- && REGNO (op) >= FIRST_PSEUDO_REGISTER
- && reg_renumber [REGNO (op)] < 0);
- }
-
- return reload_ok_mem;
-}
-
/* ??? This duplicates information provided to the compiler by the
??? scheduler description. Some day, teach genautomata to output
??? the latencies and then CSE will just use that. */
static bool
-sparc_rtx_costs (rtx x, int code, int outer_code, int *total)
+sparc_rtx_costs (rtx x, int code, int outer_code, int *total,
+ bool speed ATTRIBUTE_UNUSED)
{
enum machine_mode mode = GET_MODE (x);
bool float_mode_p = FLOAT_MODE_P (mode);
HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
tree function)
{
- rtx this, insn, funexp;
+ rtx this_rtx, insn, funexp;
unsigned int int_arg_first;
reload_completed = 1;
/* 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))
- this = gen_rtx_REG (Pmode, int_arg_first + 1);
+ this_rtx = gen_rtx_REG (Pmode, int_arg_first + 1);
else
- this = gen_rtx_REG (Pmode, int_arg_first);
+ this_rtx = gen_rtx_REG (Pmode, int_arg_first);
/* Add DELTA. When possible use a plain add, otherwise load it into
a register first. */
delta_rtx = scratch;
}
- /* THIS += DELTA. */
- emit_insn (gen_add2_insn (this, delta_rtx));
+ /* THIS_RTX += DELTA. */
+ emit_insn (gen_add2_insn (this_rtx, delta_rtx));
}
- /* Add the word at address (*THIS + VCALL_OFFSET). */
+ /* Add the word at address (*THIS_RTX + VCALL_OFFSET). */
if (vcall_offset)
{
rtx vcall_offset_rtx = GEN_INT (vcall_offset);
gcc_assert (vcall_offset < 0);
- /* SCRATCH = *THIS. */
- emit_move_insn (scratch, gen_rtx_MEM (Pmode, this));
+ /* SCRATCH = *THIS_RTX. */
+ emit_move_insn (scratch, gen_rtx_MEM (Pmode, this_rtx));
/* Prepare for adding VCALL_OFFSET. The difficulty is that we
may not have any available scratch register at this point. */
vcall_offset_rtx = GEN_INT (vcall_offset); /* cannot be 0 */
}
- /* SCRATCH = *(*THIS + VCALL_OFFSET). */
+ /* SCRATCH = *(*THIS_RTX + VCALL_OFFSET). */
emit_move_insn (scratch, gen_rtx_MEM (Pmode,
gen_rtx_PLUS (Pmode,
scratch,
vcall_offset_rtx)));
- /* THIS += *(*THIS + VCALL_OFFSET). */
- emit_insn (gen_add2_insn (this, scratch));
+ /* THIS_RTX += *(*THIS_RTX + VCALL_OFFSET). */
+ emit_insn (gen_add2_insn (this_rtx, scratch));
}
/* Generate a tail call to the target function. */
static struct machine_function *
sparc_init_machine_status (void)
{
- return ggc_alloc_cleared (sizeof (struct machine_function));
+ return GGC_CNEW (struct machine_function);
}
/* Locate some local-dynamic symbol still in use by this function
emit_insn (gen_rtx_SET (VOIDmode, val, resv));
- sparc_compare_emitted = cc;
+ sparc_compare_op0 = cc;
+ sparc_compare_op1 = const0_rtx;
emit_jump_insn (gen_bne (loop_label));
emit_label (end_label);