/* Subroutines for insn-output.c for Sun SPARC.
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000 Free Software Foundation, Inc.
+ 1999, 2000, 2001 Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com)
64 bit SPARC V9 support by Michael Tiemann, Jim Wilson, and Doug Evans,
at Cygnus Support.
88, 89, 90, 91, 92, 93, 94, 95,
96, 97, 98, 99, 100};
+/* Vector, indexed by hard register number, which contains 1
+ for a register that is allowable in a candidate for leaf
+ function treatment. */
+char sparc_leaf_regs[] =
+{ 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 0, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1};
+
#endif
/* Name of where we pretend to think the frame pointer points.
static const char *frame_base_name;
static int frame_base_offset;
-static rtx pic_setup_code PARAMS ((void));
static void sparc_init_modes PARAMS ((void));
static int save_regs PARAMS ((FILE *, int, int, const char *,
int, int, int));
static void ultra_build_types_avail PARAMS ((rtx *, int));
static void ultra_flush_pipeline PARAMS ((void));
static void ultra_rescan_pipeline_state PARAMS ((rtx *, int));
-static int set_extends PARAMS ((rtx, rtx));
+static int set_extends PARAMS ((rtx));
+static void output_restore_regs PARAMS ((FILE *, int));
\f
/* Option handling. */
{ "ultrasparc", PROCESSOR_ULTRASPARC, MASK_ISA, MASK_V9
/* Although insns using %y are deprecated, it is a clear win on current
ultrasparcs. */
- |MASK_DEPRECATED_V8_INSNS },
+ |MASK_DEPRECATED_V8_INSNS},
{ 0, 0, 0, 0 }
};
struct cpu_table *cpu;
#ifndef SPARC_BI_ARCH
/* Check for unsupported architecture size. */
if (! TARGET_64BIT != DEFAULT_ARCH32_P)
- {
- error ("%s is not supported by this configuration",
- DEFAULT_ARCH32_P ? "-m64" : "-m32");
- }
+ error ("%s is not supported by this configuration",
+ DEFAULT_ARCH32_P ? "-m64" : "-m32");
#endif
- /* At the moment we don't allow different pointer size and architecture */
- if (! TARGET_64BIT != ! TARGET_PTR64)
- {
- error ("-mptr%d not allowed on -m%d",
- TARGET_PTR64 ? 64 : 32, TARGET_64BIT ? 64 : 32);
- if (TARGET_64BIT)
- target_flags |= MASK_PTR64;
- else
- target_flags &= ~MASK_PTR64;
- }
-
/* We force all 64bit archs to use 128 bit long double */
if (TARGET_64BIT && ! TARGET_LONG_DOUBLE_128)
{
target_flags &= ~MASK_FPU_SET;
}
+ /* Don't allow -mvis if FPU is disabled. */
+ if (! TARGET_FPU)
+ target_flags &= ~MASK_VIS;
+
+ /* -mvis assumes UltraSPARC+, so we are sure v9 instructions
+ are available.
+ -m64 also implies v9. */
+ if (TARGET_VIS || TARGET_ARCH64)
+ target_flags |= MASK_V9;
+
/* Use the deprecated v8 insns for sparc64 in 32 bit mode. */
if (TARGET_V9 && TARGET_ARCH32)
target_flags |= MASK_DEPRECATED_V8_INSNS;
if (TARGET_ARCH32)
target_flags &= ~MASK_STACK_BIAS;
- /* Don't allow -mvis if FPU is disabled. */
- if (! TARGET_FPU)
- target_flags &= ~MASK_VIS;
-
/* Supply a default value for align_functions. */
if (align_functions == 0 && sparc_cpu == PROCESSOR_ULTRASPARC)
align_functions = 32;
(SPARC_SIMM13_P (CONST_DOUBLE_LOW (op))
&& (((CONST_DOUBLE_LOW (op) & 0x80000000) == 0
&& CONST_DOUBLE_HIGH (op) == 0)
- || (CONST_DOUBLE_HIGH (op) == -1)))
+ || (CONST_DOUBLE_HIGH (op) == -1
+ && CONST_DOUBLE_LOW (op) & 0x80000000) != 0))
#endif
))))
return 1;
rtx temp;
/* Sanity check that we know what we are working with. */
- if (! TARGET_ARCH64
- || GET_CODE (op0) != REG
- || (REGNO (op0) >= SPARC_FIRST_FP_REG
- && REGNO (op0) <= SPARC_LAST_V9_FP_REG))
+ if (! TARGET_ARCH64)
abort ();
+ if (GET_CODE (op0) != SUBREG)
+ {
+ if (GET_CODE (op0) != REG
+ || (REGNO (op0) >= SPARC_FIRST_FP_REG
+ && REGNO (op0) <= SPARC_LAST_V9_FP_REG))
+ abort ();
+ }
+
if (reload_in_progress || reload_completed)
temp = op0;
else
return 0;
}
+/* Return nonzero if TRIAL can go into the sibling call
+ delay slot. */
+
+int
+eligible_for_sibcall_delay (trial)
+ rtx trial;
+{
+ rtx pat, src;
+
+ if (GET_CODE (trial) != INSN || GET_CODE (PATTERN (trial)) != SET)
+ return 0;
+
+ if (get_attr_length (trial) != 1 || profile_block_flag == 2)
+ return 0;
+
+ pat = PATTERN (trial);
+
+ if (current_function_uses_only_leaf_regs)
+ {
+ /* If the tail call is done using the call instruction,
+ we have to restore %o7 in the delay slot. */
+ if ((TARGET_ARCH64 && ! TARGET_CM_MEDLOW) || flag_pic)
+ return 0;
+
+ /* %g1 is used to build the function address */
+ if (reg_mentioned_p (gen_rtx_REG (Pmode, 1), pat))
+ return 0;
+
+ return 1;
+ }
+
+ /* Otherwise, only operations which can be done in tandem with
+ a `restore' insn can go into the delay slot. */
+ if (GET_CODE (SET_DEST (pat)) != REG
+ || REGNO (SET_DEST (pat)) < 24
+ || REGNO (SET_DEST (pat)) >= 32)
+ return 0;
+
+ /* If it mentions %o7, it can't go in, because sibcall will clobber it
+ in most cases. */
+ if (reg_mentioned_p (gen_rtx_REG (Pmode, 15), pat))
+ return 0;
+
+ src = SET_SRC (pat);
+
+ if (arith_operand (src, GET_MODE (src)))
+ {
+ if (TARGET_ARCH64)
+ return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (DImode);
+ else
+ return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (SImode);
+ }
+
+ else if (arith_double_operand (src, GET_MODE (src)))
+ return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (DImode);
+
+ else if (! TARGET_FPU && restore_operand (SET_DEST (pat), SFmode)
+ && register_operand (src, SFmode))
+ return 1;
+
+ else if (GET_CODE (src) == PLUS
+ && arith_operand (XEXP (src, 0), SImode)
+ && arith_operand (XEXP (src, 1), SImode)
+ && (register_operand (XEXP (src, 0), SImode)
+ || register_operand (XEXP (src, 1), SImode)))
+ return 1;
+
+ else if (GET_CODE (src) == PLUS
+ && arith_double_operand (XEXP (src, 0), DImode)
+ && arith_double_operand (XEXP (src, 1), DImode)
+ && (register_operand (XEXP (src, 0), DImode)
+ || register_operand (XEXP (src, 1), DImode)))
+ return 1;
+
+ else if (GET_CODE (src) == LO_SUM
+ && ! TARGET_CM_MEDMID
+ && ((register_operand (XEXP (src, 0), SImode)
+ && immediate_operand (XEXP (src, 1), SImode))
+ || (TARGET_ARCH64
+ && register_operand (XEXP (src, 0), DImode)
+ && immediate_operand (XEXP (src, 1), DImode))))
+ return 1;
+
+ else if (GET_CODE (src) == ASHIFT
+ && (register_operand (XEXP (src, 0), SImode)
+ || register_operand (XEXP (src, 0), DImode))
+ && XEXP (src, 1) == const1_rtx)
+ return 1;
+
+ return 0;
+}
+
static int
check_return_regs (x)
rtx x;
short_branch (uid1, uid2)
int uid1, uid2;
{
- unsigned int delta = insn_addresses[uid1] - insn_addresses[uid2];
- if (delta + 1024 < 2048)
+ int delta = INSN_ADDRESSES (uid1) - INSN_ADDRESSES (uid2);
+
+ /* Leave a few words of "slop". */
+ if (delta >= -1023 && delta <= 1022)
return 1;
- /* warning ("long branch, distance %d", delta); */
+
return 0;
}
return orig;
}
-/* Return the RTX for insns to set the PIC register. */
-
-static rtx
-pic_setup_code ()
-{
- rtx seq;
-
- start_sequence ();
- emit_insn (gen_get_pc (pic_offset_table_rtx, global_offset_table,
- get_pc_symbol));
- seq = gen_sequence ();
- end_sequence ();
-
- return seq;
-}
-
-/* Emit special PIC prologues and epilogues. */
+/* Emit special PIC prologues. */
void
-finalize_pic ()
+load_pic_register ()
{
/* Labels to get the PC in the prologue of this function. */
int orig_flag_pic = flag_pic;
- rtx insn;
-
- if (current_function_uses_pic_offset_table == 0)
- return;
if (! flag_pic)
abort ();
if (align > 0)
ASM_OUTPUT_ALIGN (asm_out_file, align);
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LGETPC", 0);
- fputs ("\tretl\n\tadd %o7,%l7,%l7\n", asm_out_file);
+ fputs ("\tretl\n\tadd\t%o7, %l7, %l7\n", asm_out_file);
}
/* Initialize every time through, since we can't easily
get_pc_symbol = gen_rtx_SYMBOL_REF (Pmode, get_pc_symbol_name);
flag_pic = 0;
- emit_insn_after (pic_setup_code (), get_insns ());
-
- /* Insert the code in each nonlocal goto receiver.
- If you make changes here or to the nonlocal_goto_receiver
- pattern, make sure the unspec_volatile numbers still
- match. */
- for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
- if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == UNSPEC_VOLATILE
- && XINT (PATTERN (insn), 1) == 5)
- emit_insn_after (pic_setup_code (), insn);
+ emit_insn (gen_get_pc (pic_offset_table_rtx, global_offset_table,
+ get_pc_symbol));
flag_pic = orig_flag_pic;
{
/* Check if the compiler has recorded some information
about the alignment of the base REG. If reload has
- completed, we already matched with proper alignments. */
- if (((cfun != 0 && REGNO_POINTER_ALIGN (regno) >= desired)
- || reload_completed)
- && ((INTVAL (offset) & (desired - 1)) == 0))
+ completed, we already matched with proper alignments.
+ If not running global_alloc, reload might give us
+ unaligned pointer to local stack though. */
+ if (((cfun != 0
+ && REGNO_POINTER_ALIGN (regno) >= desired * BITS_PER_UNIT)
+ || (optimize && reload_completed))
+ && (INTVAL (offset) & (desired - 1)) == 0)
return 1;
}
else
base, offset + 4 * n_regs, reg_names[i]),
n_regs += 2;
else
- fprintf (file, "\tld\t[%s+%d],%s\n",
+ fprintf (file, "\tld\t[%s+%d], %s\n",
base, offset + 4 * n_regs, reg_names[i]),
n_regs += 2;
else if (regs_ever_live[i+1] && ! call_used_regs[i+1])
- fprintf (file, "\tld\t[%s+%d],%s\n",
+ fprintf (file, "\tld\t[%s+%d], %s\n",
base, offset + 4 * n_regs + 4, reg_names[i+1]),
n_regs += 2;
}
}
}
+/* Output code to restore any call saved registers. */
+
+static void
+output_restore_regs (file, leaf_function)
+ FILE *file;
+ int leaf_function;
+{
+ int offset, n_regs;
+ const char *base;
+
+ offset = -apparent_fsize + frame_base_offset;
+ if (offset < -4096 || offset + num_gfregs * 4 > 4096 - 8 /*double*/)
+ {
+ build_big_number (file, offset, "%g1");
+ fprintf (file, "\tadd\t%s, %%g1, %%g1\n", frame_base_name);
+ base = "%g1";
+ offset = 0;
+ }
+ else
+ {
+ base = frame_base_name;
+ }
+
+ n_regs = 0;
+ if (TARGET_EPILOGUE && ! leaf_function)
+ /* ??? Originally saved regs 0-15 here. */
+ n_regs = restore_regs (file, 0, 8, base, offset, 0);
+ else if (leaf_function)
+ /* ??? Originally saved regs 0-31 here. */
+ n_regs = restore_regs (file, 0, 8, base, offset, 0);
+ if (TARGET_EPILOGUE)
+ restore_regs (file, 32, TARGET_V9 ? 96 : 64, base, offset, n_regs);
+}
+
/* Output code for the function epilogue. */
void
goto output_vectors;
}
- /* Restore any call saved registers. */
if (num_gfregs)
- {
- int offset, n_regs;
- const char *base;
-
- offset = -apparent_fsize + frame_base_offset;
- if (offset < -4096 || offset + num_gfregs * 4 > 4096 - 8 /*double*/)
- {
- build_big_number (file, offset, "%g1");
- fprintf (file, "\tadd\t%s, %%g1, %%g1\n", frame_base_name);
- base = "%g1";
- offset = 0;
- }
- else
- {
- base = frame_base_name;
- }
-
- n_regs = 0;
- if (TARGET_EPILOGUE && ! leaf_function)
- /* ??? Originally saved regs 0-15 here. */
- n_regs = restore_regs (file, 0, 8, base, offset, 0);
- else if (leaf_function)
- /* ??? Originally saved regs 0-31 here. */
- n_regs = restore_regs (file, 0, 8, base, offset, 0);
- if (TARGET_EPILOGUE)
- restore_regs (file, 32, TARGET_V9 ? 96 : 64, base, offset, n_regs);
- }
+ output_restore_regs (file, leaf_function);
/* Work out how to skip the caller's unimp instruction if required. */
if (leaf_function)
output_vectors:
sparc_output_deferred_case_vectors ();
}
+
+/* Output a sibling call. */
+
+const char *
+output_sibcall (insn, call_operand)
+ rtx insn, call_operand;
+{
+ int leaf_regs = current_function_uses_only_leaf_regs;
+ rtx operands[3];
+ int delay_slot = dbr_sequence_length () > 0;
+
+ if (num_gfregs)
+ {
+ /* Call to restore global regs might clobber
+ the delay slot. Instead of checking for this
+ output the delay slot now. */
+ if (delay_slot)
+ {
+ rtx delay = NEXT_INSN (insn);
+
+ if (! delay)
+ abort ();
+
+ final_scan_insn (delay, asm_out_file, 1, 0, 1);
+ PATTERN (delay) = gen_blockage ();
+ INSN_CODE (delay) = -1;
+ delay_slot = 0;
+ }
+ output_restore_regs (asm_out_file, leaf_regs);
+ }
+
+ operands[0] = call_operand;
+
+ if (leaf_regs)
+ {
+#ifdef HAVE_AS_RELAX_OPTION
+ /* If as and ld are relaxing tail call insns into branch always,
+ use or %o7,%g0,X; call Y; or X,%g0,%o7 always, so that it can
+ be optimized. With sethi/jmpl as nor ld has no easy way how to
+ find out if somebody does not branch between the sethi and jmpl. */
+ int spare_slot = 0;
+#else
+ int spare_slot = ((TARGET_ARCH32 || TARGET_CM_MEDLOW) && ! flag_pic);
+#endif
+ int size = 0;
+
+ if ((actual_fsize || ! spare_slot) && delay_slot)
+ {
+ rtx delay = NEXT_INSN (insn);
+
+ if (! delay)
+ abort ();
+
+ final_scan_insn (delay, asm_out_file, 1, 0, 1);
+ PATTERN (delay) = gen_blockage ();
+ INSN_CODE (delay) = -1;
+ delay_slot = 0;
+ }
+ if (actual_fsize)
+ {
+ if (actual_fsize <= 4096)
+ size = actual_fsize;
+ else if (actual_fsize <= 8192)
+ {
+ fputs ("\tsub\t%sp, -4096, %sp\n", asm_out_file);
+ size = actual_fsize - 4096;
+ }
+ else if ((actual_fsize & 0x3ff) == 0)
+ fprintf (asm_out_file,
+ "\tsethi\t%%hi(%d), %%g1\n\tadd\t%%sp, %%g1, %%sp\n",
+ actual_fsize);
+ else
+ {
+ fprintf (asm_out_file,
+ "\tsethi\t%%hi(%d), %%g1\n\tor\t%%g1, %%lo(%d), %%g1\n",
+ actual_fsize, actual_fsize);
+ fputs ("\tadd\t%%sp, %%g1, %%sp\n", asm_out_file);
+ }
+ }
+ if (spare_slot)
+ {
+ output_asm_insn ("sethi\t%%hi(%a0), %%g1", operands);
+ output_asm_insn ("jmpl\t%%g1 + %%lo(%a0), %%g0", operands);
+ if (size)
+ fprintf (asm_out_file, "\t sub\t%%sp, -%d, %%sp\n", size);
+ else if (! delay_slot)
+ fputs ("\t nop\n", asm_out_file);
+ }
+ else
+ {
+ if (size)
+ fprintf (asm_out_file, "\tsub\t%%sp, -%d, %%sp\n", size);
+ /* 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);
+ }
+ return "";
+ }
+
+ output_asm_insn ("call\t%a0, 0", operands);
+ if (delay_slot)
+ {
+ rtx delay = NEXT_INSN (insn), pat;
+
+ if (! delay)
+ abort ();
+
+ pat = PATTERN (delay);
+ if (GET_CODE (pat) != SET)
+ abort ();
+
+ operands[0] = SET_DEST (pat);
+ pat = SET_SRC (pat);
+ switch (GET_CODE (pat))
+ {
+ case PLUS:
+ operands[1] = XEXP (pat, 0);
+ operands[2] = XEXP (pat, 1);
+ output_asm_insn (" restore %r1, %2, %Y0", operands);
+ break;
+ case LO_SUM:
+ operands[1] = XEXP (pat, 0);
+ operands[2] = XEXP (pat, 1);
+ output_asm_insn (" restore %r1, %%lo(%a2), %Y0", operands);
+ break;
+ case ASHIFT:
+ operands[1] = XEXP (pat, 0);
+ output_asm_insn (" restore %r1, %r1, %Y0", operands);
+ break;
+ default:
+ operands[1] = pat;
+ output_asm_insn (" restore %%g0, %1, %Y0", operands);
+ break;
+ }
+ PATTERN (delay) = gen_blockage ();
+ INSN_CODE (delay) = -1;
+ }
+ else
+ fputs ("\t restore\n", asm_out_file);
+ return "";
+}
\f
/* Functions for handling argument passing.
case HImode : case CHImode :
case SImode : case CSImode :
case DImode : case CDImode :
+ case TImode : case CTImode :
if (slotno >= SPARC_INT_ARG_MAX)
return -1;
regno = regbase + slotno;
{
rtx ret;
int slotno, named, regbase;
- int nregs, intoffset;
+ unsigned int nregs;
+ int intoffset;
};
static void function_arg_record_value_3
- PARAMS ((int, struct function_arg_record_value_parms *));
+ PARAMS ((HOST_WIDE_INT, struct function_arg_record_value_parms *));
static void function_arg_record_value_2
- PARAMS ((tree, int, struct function_arg_record_value_parms *));
+ PARAMS ((tree, HOST_WIDE_INT,
+ struct function_arg_record_value_parms *));
static void function_arg_record_value_1
- PARAMS ((tree, int, struct function_arg_record_value_parms *));
+ PARAMS ((tree, HOST_WIDE_INT,
+ struct function_arg_record_value_parms *));
static rtx function_arg_record_value
PARAMS ((tree, enum machine_mode, int, int, int));
static void
function_arg_record_value_1 (type, startbitpos, parms)
tree type;
- int startbitpos;
+ HOST_WIDE_INT startbitpos;
struct function_arg_record_value_parms *parms;
{
tree field;
{
if (TREE_CODE (field) == FIELD_DECL)
{
- int bitpos = startbitpos;
- if (DECL_FIELD_BITPOS (field))
- bitpos += TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field));
+ HOST_WIDE_INT bitpos = startbitpos;
+
+ if (DECL_SIZE (field) != 0
+ && host_integerp (bit_position (field), 1))
+ bitpos += int_bit_position (field);
+
/* ??? FIXME: else assume zero offset. */
if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE)
- {
- function_arg_record_value_1 (TREE_TYPE (field), bitpos, parms);
- }
+ function_arg_record_value_1 (TREE_TYPE (field), bitpos, parms);
else if (TREE_CODE (TREE_TYPE (field)) == REAL_TYPE
&& TARGET_FPU
&& ! packed_p
static void
function_arg_record_value_3 (bitpos, parms)
- int bitpos;
+ HOST_WIDE_INT bitpos;
struct function_arg_record_value_parms *parms;
{
enum machine_mode mode;
- int regno, this_slotno, intslots, intoffset;
+ unsigned int regno;
+ int this_slotno, intslots, intoffset;
rtx reg;
if (parms->intoffset == -1)
return;
+
intoffset = parms->intoffset;
parms->intoffset = -1;
at the moment but may wish to revisit. */
if (intoffset % BITS_PER_WORD != 0)
- {
- mode = mode_for_size (BITS_PER_WORD - intoffset%BITS_PER_WORD,
- MODE_INT, 0);
- }
+ mode = mode_for_size (BITS_PER_WORD - intoffset % BITS_PER_WORD,
+ MODE_INT, 0);
else
mode = word_mode;
static void
function_arg_record_value_2 (type, startbitpos, parms)
tree type;
- int startbitpos;
+ HOST_WIDE_INT startbitpos;
struct function_arg_record_value_parms *parms;
{
tree field;
{
if (TREE_CODE (field) == FIELD_DECL)
{
- int bitpos = startbitpos;
- if (DECL_FIELD_BITPOS (field))
- bitpos += TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field));
+ HOST_WIDE_INT bitpos = startbitpos;
+
+ if (DECL_SIZE (field) != 0
+ && host_integerp (bit_position (field), 1))
+ bitpos += int_bit_position (field);
+
/* ??? FIXME: else assume zero offset. */
if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE)
- {
- function_arg_record_value_2 (TREE_TYPE (field), bitpos, parms);
- }
+ function_arg_record_value_2 (TREE_TYPE (field), bitpos, parms);
else if (TREE_CODE (TREE_TYPE (field)) == REAL_TYPE
&& TARGET_FPU
&& ! packed_p
{
HOST_WIDE_INT typesize = int_size_in_bytes (type);
struct function_arg_record_value_parms parms;
- int nregs;
+ unsigned int nregs;
parms.ret = NULL_RTX;
parms.slotno = slotno;
indirect = 1;
size = rsize = UNITS_PER_WORD;
}
- else
- {
- /* ??? The old va-sparc.h implementation, for 8 byte objects
- copied stuff to a temporary -- I don't see that that
- provides any more alignment than the stack slot did. */
- }
}
incr = valist;
addr_rtx = expand_expr (addr, NULL, Pmode, EXPAND_NORMAL);
+ /* 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. */
+ if (align == 0
+ && TYPE_ALIGN (type) > BITS_PER_WORD
+ && !indirect)
+ {
+ /* FIXME: We really need to specify that the temporary is live
+ for the whole function because expand_builtin_va_arg wants
+ the alias set to be get_varargs_alias_set (), but in this
+ case the alias set is that for TYPE and if the memory gets
+ reused it will be reused with alias set TYPE. */
+ rtx tmp = assign_temp (type, 0, 1, 0);
+ rtx dest_addr;
+
+ addr_rtx = force_reg (Pmode, addr_rtx);
+ addr_rtx = gen_rtx_MEM (BLKmode, addr_rtx);
+ MEM_ALIAS_SET (addr_rtx) = get_varargs_alias_set ();
+ tmp = shallow_copy_rtx (tmp);
+ PUT_MODE (tmp, BLKmode);
+ MEM_ALIAS_SET (tmp) = 0;
+
+ dest_addr = emit_block_move (tmp, addr_rtx, GEN_INT (rsize),
+ BITS_PER_WORD);
+ if (dest_addr != NULL_RTX)
+ addr_rtx = dest_addr;
+ else
+ addr_rtx = XCEXP (tmp, 0, MEM);
+ }
+
if (indirect)
{
addr_rtx = force_reg (Pmode, addr_rtx);
rtx x, y;
enum rtx_code comparison;
{
- char *qpfunc;
+ const char *qpfunc;
rtx slot0, slot1, result, tem, tem2;
enum machine_mode mode;
else
{
if ((actual_fsize & 0x3ff) != 0)
- return "sethi %%hi(%a0),%%g1\n\tor %%g1,%%lo(%a0),%%g1\n\tretl\n\tadd %%sp,%%g1,%%sp";
+ return "sethi\t%%hi(%a0), %%g1\n\tor\t%%g1, %%lo(%a0), %%g1\n\tretl\n\tadd\t%%sp, %%g1, %%sp";
else
- return "sethi %%hi(%a0),%%g1\n\tretl\n\tadd %%sp,%%g1,%%sp";
+ return "sethi\t%%hi(%a0), %%g1\n\tretl\n\tadd\t%%sp, %%g1, %%sp";
}
}
else if (TARGET_V9)
if (regs_ever_live[15] != last_order_nonleaf)
{
last_order_nonleaf = !last_order_nonleaf;
- bcopy ((char *) reg_alloc_orders[last_order_nonleaf],
- (char *) reg_alloc_order, FIRST_PSEUDO_REGISTER * sizeof (int));
+ memcpy ((char *) reg_alloc_order,
+ (char *) reg_alloc_orders[last_order_nonleaf],
+ FIRST_PSEUDO_REGISTER * sizeof (int));
}
}
\f
return IEU0;
else if (type_mask & (TMASK (TYPE_COMPARE) |
TMASK (TYPE_CALL) |
+ TMASK (TYPE_SIBCALL) |
TMASK (TYPE_UNCOND_BRANCH)))
return IEU1;
else if (type_mask & (TMASK (TYPE_IALU) | TMASK (TYPE_BINARY) |
{
ultra_cur_hist = (ultra_cur_hist + 1) & (ULTRA_NUM_HIST - 1);
ultra_cycles_elapsed += 1;
- bzero ((char *) &ultra_pipe, sizeof ultra_pipe);
+ memset ((char *) &ultra_pipe, 0, sizeof ultra_pipe);
ultra_pipe.free_slot_mask = 0xf;
}
FILE *dump ATTRIBUTE_UNUSED;
int sched_verbose ATTRIBUTE_UNUSED;
{
- bzero ((char *) ultra_pipe_hist, sizeof ultra_pipe_hist);
+ memset ((char *) ultra_pipe_hist, 0, sizeof ultra_pipe_hist);
ultra_cur_hist = 0;
ultra_cycles_elapsed = 0;
ultra_pipe.free_slot_mask = 0xf;
/* If we are not in the process of emptying out the pipe, try to
obtain an instruction which must be the first in it's group. */
ip = ultra_find_type ((TMASK (TYPE_CALL) |
+ TMASK (TYPE_SIBCALL) |
TMASK (TYPE_CALL_NO_DELAY_SLOT) |
TMASK (TYPE_UNCOND_BRANCH)),
ready, this_insn);
}
else
{
- bzero ((char *) &ultra_pipe, sizeof ultra_pipe);
+ memset ((char *) &ultra_pipe, 0, sizeof ultra_pipe);
ultra_pipe.free_slot_mask = 0xf;
}
}
}
static int
-set_extends(x, insn)
- rtx x, insn;
+set_extends (insn)
+ rtx insn;
{
register rtx pat = PATTERN (insn);
return 1;
case AND:
{
+ rtx op0 = XEXP (SET_SRC (pat), 0);
rtx op1 = XEXP (SET_SRC (pat), 1);
if (GET_CODE (op1) == CONST_INT)
return INTVAL (op1) >= 0;
- if (GET_CODE (XEXP (SET_SRC (pat), 0)) == REG
- && sparc_check_64 (XEXP (SET_SRC (pat), 0), insn) == 1)
- return 1;
- if (GET_CODE (op1) == REG
- && sparc_check_64 ((op1), insn) == 1)
+ if (GET_CODE (op0) != REG)
+ return 0;
+ if (sparc_check_64 (op0, insn) == 1)
return 1;
+ return (GET_CODE (op1) == REG && sparc_check_64 (op1, insn) == 1);
+ }
+ case IOR:
+ case XOR:
+ {
+ rtx op0 = XEXP (SET_SRC (pat), 0);
+ rtx op1 = XEXP (SET_SRC (pat), 1);
+ if (GET_CODE (op0) != REG || sparc_check_64 (op0, insn) <= 0)
+ return 0;
+ if (GET_CODE (op1) == CONST_INT)
+ return INTVAL (op1) >= 0;
+ return (GET_CODE (op1) == REG && sparc_check_64 (op1, insn) == 1);
}
case ASHIFT:
case LSHIFTRT:
return GET_MODE (SET_SRC (pat)) == SImode;
/* Positive integers leave the high bits zero. */
case CONST_DOUBLE:
- return ! (CONST_DOUBLE_LOW (x) & 0x80000000);
+ return ! (CONST_DOUBLE_LOW (SET_SRC (pat)) & 0x80000000);
case CONST_INT:
- return ! (INTVAL (x) & 0x80000000);
+ return ! (INTVAL (SET_SRC (pat)) & 0x80000000);
case ASHIFTRT:
case SIGN_EXTEND:
return - (GET_MODE (SET_SRC (pat)) == SImode);
+ case REG:
+ return sparc_check_64 (SET_SRC (pat), insn);
default:
return 0;
}
the single set and return the correct value or fail to recognize
it and return 0. */
int set_once = 0;
+ rtx y = x;
+
+ if (GET_CODE (x) != REG)
+ abort ();
+
+ if (GET_MODE (x) == DImode)
+ y = gen_rtx_REG (SImode, REGNO (x) + WORDS_BIG_ENDIAN);
- if (GET_CODE (x) == REG
- && flag_expensive_optimizations
- && REG_N_SETS (REGNO (x)) == 1)
+ if (flag_expensive_optimizations
+ && REG_N_SETS (REGNO (y)) == 1)
set_once = 1;
if (insn == 0)
if (GET_CODE (pat) != SET)
return 0;
if (rtx_equal_p (x, SET_DEST (pat)))
- return set_extends (x, insn);
- if (reg_overlap_mentioned_p (SET_DEST (pat), x))
+ return set_extends (insn);
+ if (y && rtx_equal_p (y, SET_DEST (pat)))
+ return set_extends (insn);
+ if (reg_overlap_mentioned_p (SET_DEST (pat), y))
return 0;
}
}
operands[3] = operands[0];
if (GET_CODE (operands[1]) == CONST_INT)
{
- output_asm_insn ("mov %1,%3", operands);
+ output_asm_insn ("mov\t%1, %3", operands);
}
else
{
- output_asm_insn ("sllx %H1,32,%3", operands);
+ output_asm_insn ("sllx\t%H1, 32, %3", operands);
if (sparc_check_64 (operands[1], insn) <= 0)
- output_asm_insn ("srl %L1,0,%L1", operands);
- output_asm_insn ("or %L1,%3,%3", operands);
+ output_asm_insn ("srl\t%L1, 0, %L1", operands);
+ output_asm_insn ("or\t%L1, %3, %3", operands);
}
strcpy(asm_code, opcode);
if (which_alternative != 2)
- return strcat (asm_code, " %0,%2,%L0\n\tsrlx %L0,32,%H0");
+ return strcat (asm_code, "\t%0, %2, %L0\n\tsrlx\t%L0, 32, %H0");
else
- return strcat (asm_code, " %3,%2,%3\n\tsrlx %3,32,%H0\n\tmov %3,%L0");
+ return strcat (asm_code, "\t%3, %2, %3\n\tsrlx\t%3, 32, %H0\n\tmov\t%3, %L0");
}
ASM_GENERATE_INTERNAL_LABEL (buf, "LP", labelno);
if (! TARGET_ARCH64)
- fputs ("\tst\t%g2,[%fp-4]\n", file);
+ fputs ("\tst\t%g2, [%fp-4]\n", file);
fputs ("\tsethi\t%hi(", file);
assemble_name (file, buf);
- fputs ("),%o0\n", file);
+ fputs ("), %o0\n", file);
fputs ("\tcall\t", file);
assemble_name (file, MCOUNT_FUNCTION);
putc ('\n', file);
- fputs ("\t or\t%o0,%lo(", file);
+ fputs ("\t or\t%o0, %lo(", file);
assemble_name (file, buf);
- fputs ("),%o0\n", file);
+ fputs ("), %o0\n", file);
if (! TARGET_ARCH64)
- fputs ("\tld\t[%fp-4],%g2\n", file);
+ fputs ("\tld\t[%fp-4], %g2\n", file);
}
{
fputs ("\tsethi\t%hi(", file);
assemble_name (file, LPBX);
- fputs ("),%o0\n", file);
+ fputs ("), %o0\n", file);
- fprintf (file, "\tsethi\t%%hi(%d),%%o1\n", block_or_label);
+ fprintf (file, "\tsethi\t%%hi(%d), %%o1\n", block_or_label);
- fputs ("\tor\t%o0,%lo(", file);
+ fputs ("\tor\t%o0, %lo(", file);
assemble_name (file, LPBX);
- fputs ("),%o0\n", file);
+ fputs ("), %o0\n", file);
fprintf (file, "\tcall\t%s__bb_init_trace_func\n", user_label_prefix);
- fprintf (file, "\t or\t%%o1,%%lo(%d),%%o1\n", block_or_label);
+ fprintf (file, "\t or\t%%o1, %%lo(%d), %%o1\n", block_or_label);
}
else if (profile_block_flag != 0)
{
fputs ("\tsethi\t%hi(", file);
assemble_name (file, LPBX);
- fputs ("),%o0\n", file);
+ fputs ("), %o0\n", file);
fputs ("\tld\t[%lo(", file);
assemble_name (file, LPBX);
- fputs (")+%o0],%o1\n", file);
+ fputs (")+%o0], %o1\n", file);
fputs ("\ttst\t%o1\n", file);
putc ('\n', file);
}
- fputs ("\t or\t%o0,%lo(", file);
+ fputs ("\t or\t%o0, %lo(", file);
assemble_name (file, LPBX);
- fputs ("),%o0\n", file);
+ fputs ("), %o0\n", file);
fprintf (file, "\tcall\t%s__bb_init_func\n\t nop\n", user_label_prefix);
{
ASM_GENERATE_INTERNAL_LABEL (LPBX, "LPBX", 0);
- fprintf (file, "\tsethi\t%%hi(%s__bb),%%g1\n", user_label_prefix);
- fprintf (file, "\tsethi\t%%hi(%d),%%g%d\n", blockno, bbreg);
- fprintf (file, "\tor\t%%g1,%%lo(%s__bb),%%g1\n", user_label_prefix);
- fprintf (file, "\tor\t%%g%d,%%lo(%d),%%g%d\n", bbreg, blockno, bbreg);
+ fprintf (file, "\tsethi\t%%hi(%s__bb), %%g1\n", user_label_prefix);
+ fprintf (file, "\tsethi\t%%hi(%d), %%g%d\n", blockno, bbreg);
+ fprintf (file, "\tor\t%%g1, %%lo(%s__bb), %%g1\n", user_label_prefix);
+ fprintf (file, "\tor\t%%g%d, %%lo(%d), %%g%d\n", bbreg, blockno, bbreg);
- fprintf (file, "\tst\t%%g%d,[%%g1]\n", bbreg);
+ fprintf (file, "\tst\t%%g%d, [%%g1]\n", bbreg);
fputs ("\tsethi\t%hi(", file);
assemble_name (file, LPBX);
- fprintf (file, "),%%g%d\n", bbreg);
+ fprintf (file, "), %%g%d\n", bbreg);
- fputs ("\tor\t%o2,%lo(", file);
+ fputs ("\tor\t%o2, %lo(", file);
assemble_name (file, LPBX);
- fprintf (file, "),%%g%d\n", bbreg);
+ fprintf (file, "), %%g%d\n", bbreg);
- fprintf (file, "\tst\t%%g%d,[%%g1+4]\n", bbreg);
- fprintf (file, "\tmov\t%%o7,%%g%d\n", bbreg);
+ fprintf (file, "\tst\t%%g%d, [%%g1 + 4]\n", bbreg);
+ fprintf (file, "\tmov\t%%o7, %%g%d\n", bbreg);
fprintf (file, "\tcall\t%s__bb_trace_func\n\t nop\n", user_label_prefix);
- fprintf (file, "\tmov\t%%g%d,%%o7\n", bbreg);
+ fprintf (file, "\tmov\t%%g%d, %%o7\n", bbreg);
}
else if (profile_block_flag != 0)
{
fputs ("\tsethi\t%hi(", file);
assemble_name (file, LPBX);
- fprintf (file, "+%d),%%g1\n", blockno*4);
+ fprintf (file, "+%d), %%g1\n", blockno*4);
fputs ("\tld\t[%g1+%lo(", file);
assemble_name (file, LPBX);
if (TARGET_ARCH64 && USE_AS_OFFSETABLE_LO10)
- fprintf (file, ")+%d],%%g%d\n", blockno*4, bbreg);
+ fprintf (file, ")+%d], %%g%d\n", blockno*4, bbreg);
else
- fprintf (file, "+%d)],%%g%d\n", blockno*4, bbreg);
+ fprintf (file, "+%d)], %%g%d\n", blockno*4, bbreg);
- fprintf (file, "\tadd\t%%g%d,1,%%g%d\n", bbreg, bbreg);
+ fprintf (file, "\tadd\t%%g%d, 1, %%g%d\n", bbreg, bbreg);
- fprintf (file, "\tst\t%%g%d,[%%g1+%%lo(", bbreg);
+ fprintf (file, "\tst\t%%g%d, [%%g1+%%lo(", bbreg);
assemble_name (file, LPBX);
if (TARGET_ARCH64 && USE_AS_OFFSETABLE_LO10)
fprintf (file, ")+%d]\n", blockno*4);
ggc_add_rtx_root (&get_pc_symbol, 1);
ggc_add_rtx_root (&sparc_addr_diff_list, 1);
ggc_add_rtx_root (&sparc_addr_list, 1);
- ggc_add_root (ultra_pipe_hist,
- sizeof (ultra_pipe_hist) / sizeof (ultra_pipe_hist[0]),
- sizeof (ultra_pipe_hist[0]),
- &mark_ultrasparc_pipeline_state);
+ ggc_add_root (ultra_pipe_hist, ARRAY_SIZE (ultra_pipe_hist),
+ sizeof (ultra_pipe_hist[0]), &mark_ultrasparc_pipeline_state);
}