summaryrefslogtreecommitdiffstats
path: root/contrib/gcc/config/sparc
diff options
context:
space:
mode:
authorkan <kan@FreeBSD.org>2005-06-03 03:28:44 +0000
committerkan <kan@FreeBSD.org>2005-06-03 03:28:44 +0000
commitd7b0b4f3c615794b038ed6a64e85e9621c90bc91 (patch)
tree9f886db2860fe9f635cc7c5892af5f347ab96fb5 /contrib/gcc/config/sparc
parentf2254cf7022e4e6909272699c8e1f774b7e4e3f1 (diff)
parent2156e40a831a8e0ab68e4bc091c2940bf46ca6df (diff)
downloadFreeBSD-src-d7b0b4f3c615794b038ed6a64e85e9621c90bc91.zip
FreeBSD-src-d7b0b4f3c615794b038ed6a64e85e9621c90bc91.tar.gz
This commit was generated by cvs2svn to compensate for changes in r146895,
which included commits to RCS files with non-trunk default branches.
Diffstat (limited to 'contrib/gcc/config/sparc')
-rw-r--r--contrib/gcc/config/sparc/sparc.c156
-rw-r--r--contrib/gcc/config/sparc/sparc.md1
-rw-r--r--contrib/gcc/config/sparc/t-elf4
3 files changed, 107 insertions, 54 deletions
diff --git a/contrib/gcc/config/sparc/sparc.c b/contrib/gcc/config/sparc/sparc.c
index c959370..0b07e46 100644
--- a/contrib/gcc/config/sparc/sparc.c
+++ b/contrib/gcc/config/sparc/sparc.c
@@ -187,6 +187,8 @@ static bool sparc_function_ok_for_sibcall (tree, tree);
static void sparc_init_libfuncs (void);
static void sparc_output_mi_thunk (FILE *, tree, HOST_WIDE_INT,
HOST_WIDE_INT, tree);
+static bool sparc_can_output_mi_thunk (tree, HOST_WIDE_INT,
+ HOST_WIDE_INT, tree);
static struct machine_function * sparc_init_machine_status (void);
static bool sparc_cannot_force_const_mem (rtx);
static rtx sparc_tls_get_addr (void);
@@ -270,7 +272,7 @@ enum processor_type sparc_cpu;
#undef TARGET_ASM_OUTPUT_MI_THUNK
#define TARGET_ASM_OUTPUT_MI_THUNK sparc_output_mi_thunk
#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
-#define TARGET_ASM_CAN_OUTPUT_MI_THUNK default_can_output_mi_thunk_no_vcall
+#define TARGET_ASM_CAN_OUTPUT_MI_THUNK sparc_can_output_mi_thunk
#undef TARGET_RTX_COSTS
#define TARGET_RTX_COSTS sparc_rtx_costs
@@ -1315,23 +1317,7 @@ input_operand (rtx op, enum machine_mode mode)
/* Check for valid MEM forms. */
if (GET_CODE (op) == MEM)
- {
- rtx inside = XEXP (op, 0);
-
- if (GET_CODE (inside) == LO_SUM)
- {
- /* We can't allow these because all of the splits
- (eventually as they trickle down into DFmode
- splits) require offsettable memory references. */
- if (! TARGET_V9
- && GET_MODE (op) == TFmode)
- return 0;
-
- return (register_operand (XEXP (inside, 0), Pmode)
- && CONSTANT_P (XEXP (inside, 1)));
- }
- return memory_address_p (mode, inside);
- }
+ return memory_address_p (mode, XEXP (op, 0));
return 0;
}
@@ -3334,7 +3320,7 @@ legitimate_pic_operand_p (rtx x)
int
legitimate_address_p (enum machine_mode mode, rtx addr, int strict)
{
- rtx rs1 = NULL, rs2 = NULL, imm1 = NULL, imm2;
+ rtx rs1 = NULL, rs2 = NULL, imm1 = NULL;
if (REG_P (addr) || GET_CODE (addr) == SUBREG)
rs1 = addr;
@@ -3374,15 +3360,14 @@ legitimate_address_p (enum machine_mode mode, rtx addr, int strict)
else if ((REG_P (rs1) || GET_CODE (rs1) == SUBREG)
&& (REG_P (rs2) || GET_CODE (rs2) == SUBREG))
{
- /* We prohibit REG + REG for TFmode when there are no instructions
- which accept REG+REG instructions. We do this because REG+REG
- is not an offsetable address. If we get the situation in reload
+ /* We prohibit REG + REG for TFmode when there are no quad move insns
+ and we consequently need to split. We do this because REG+REG
+ is not an offsettable address. If we get the situation in reload
where source and destination of a movtf pattern are both MEMs with
REG+REG address, then only one of them gets converted to an
- offsetable address. */
+ offsettable address. */
if (mode == TFmode
- && !(TARGET_FPU && TARGET_ARCH64 && TARGET_V9
- && TARGET_HARD_QUAD))
+ && ! (TARGET_FPU && TARGET_ARCH64 && TARGET_HARD_QUAD))
return 0;
/* We prohibit REG + REG on ARCH32 if not optimizing for
@@ -3399,7 +3384,6 @@ legitimate_address_p (enum machine_mode mode, rtx addr, int strict)
&& ! TARGET_CM_MEDMID
&& RTX_OK_FOR_OLO10_P (rs2))
{
- imm2 = rs2;
rs2 = NULL;
imm1 = XEXP (rs1, 1);
rs1 = XEXP (rs1, 0);
@@ -3415,9 +3399,9 @@ legitimate_address_p (enum machine_mode mode, rtx addr, int strict)
if (! CONSTANT_P (imm1) || tls_symbolic_operand (rs1))
return 0;
- /* We can't allow TFmode, because an offset greater than or equal to the
- alignment (8) may cause the LO_SUM to overflow if !v9. */
- if (mode == TFmode && !TARGET_V9)
+ /* We can't allow TFmode in 32-bit mode, because an offset greater
+ than the alignment (8) may cause the LO_SUM to overflow. */
+ if (mode == TFmode && TARGET_ARCH32)
return 0;
}
else if (GET_CODE (addr) == CONST_INT && SMALL_INT (addr))
@@ -5101,7 +5085,7 @@ static void function_arg_record_value_2
static void function_arg_record_value_1
(tree, HOST_WIDE_INT, struct function_arg_record_value_parms *, bool);
static rtx function_arg_record_value (tree, enum machine_mode, int, int, int);
-static rtx function_arg_union_value (int, enum machine_mode, int);
+static rtx function_arg_union_value (int, enum machine_mode, int, int);
/* A subroutine of function_arg_record_value. Traverse the structure
recursively and determine how many registers will be required. */
@@ -5445,11 +5429,19 @@ function_arg_record_value (tree type, enum machine_mode mode,
REGNO is the hard register the union will be passed in. */
static rtx
-function_arg_union_value (int size, enum machine_mode mode, int regno)
+function_arg_union_value (int size, enum machine_mode mode, int slotno,
+ int regno)
{
int nwords = ROUND_ADVANCE (size), i;
rtx regs;
+ /* See comment in previous function for empty structures. */
+ if (nwords == 0)
+ return gen_rtx_REG (mode, regno);
+
+ if (slotno == SPARC_INT_ARG_MAX - 1)
+ nwords = 1;
+
/* Unions are passed left-justified. */
regs = gen_rtx_PARALLEL (mode, rtvec_alloc (nwords));
@@ -5516,7 +5508,7 @@ function_arg (const struct sparc_args *cum, enum machine_mode mode,
if (size > 16)
abort (); /* shouldn't get here */
- return function_arg_union_value (size, mode, regno);
+ return function_arg_union_value (size, mode, slotno, regno);
}
/* v9 fp args in reg slots beyond the int reg slots get passed in regs
but also have the slot allocated for them.
@@ -5796,7 +5788,7 @@ function_value (tree type, enum machine_mode mode, int incoming_p)
if (size > 32)
abort (); /* shouldn't get here */
- return function_arg_union_value (size, mode, regbase);
+ return function_arg_union_value (size, mode, 0, regbase);
}
else if (AGGREGATE_TYPE_P (type))
{
@@ -5819,7 +5811,7 @@ function_value (tree type, enum machine_mode mode, int incoming_p)
try to be unduly clever, and simply follow the ABI
for unions in that case. */
if (mode == BLKmode)
- return function_arg_union_value (bytes, mode, regbase);
+ return function_arg_union_value (bytes, mode, 0, regbase);
}
else if (GET_MODE_CLASS (mode) == MODE_INT
&& GET_MODE_SIZE (mode) < UNITS_PER_WORD)
@@ -9288,16 +9280,18 @@ sparc_rtx_costs (rtx x, int code, int outer_code, int *total)
}
}
-/* Output code to add DELTA to the first argument, and then jump to FUNCTION.
- Used for C++ multiple inheritance. */
+/* Output the assembler code for a thunk function. THUNK_DECL is the
+ declaration for the thunk function itself, FUNCTION is the decl for
+ the target function. DELTA is an immediate constant offset to be
+ added to THIS. If VCALL_OFFSET is nonzero, the word at address
+ (*THIS + VCALL_OFFSET) should be additionally added to THIS. */
static void
sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
- HOST_WIDE_INT delta,
- HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED,
+ HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
tree function)
{
- rtx this, insn, funexp, delta_rtx, tmp;
+ rtx this, insn, funexp;
reload_completed = 1;
epilogue_completed = 1;
@@ -9315,26 +9309,73 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
/* Add DELTA. When possible use a plain add, otherwise load it into
a register first. */
- delta_rtx = GEN_INT (delta);
- if (!SPARC_SIMM13_P (delta))
+ if (delta)
+ {
+ rtx delta_rtx = GEN_INT (delta);
+
+ if (! SPARC_SIMM13_P (delta))
+ {
+ rtx scratch = gen_rtx_REG (Pmode, 1);
+ emit_move_insn (scratch, delta_rtx);
+ delta_rtx = scratch;
+ }
+
+ /* THIS += DELTA. */
+ emit_insn (gen_add2_insn (this, delta_rtx));
+ }
+
+ /* Add the word at address (*THIS + VCALL_OFFSET). */
+ if (vcall_offset)
{
+ rtx vcall_offset_rtx = GEN_INT (vcall_offset);
rtx scratch = gen_rtx_REG (Pmode, 1);
- if (input_operand (delta_rtx, GET_MODE (scratch)))
- emit_insn (gen_rtx_SET (VOIDmode, scratch, delta_rtx));
+ if (vcall_offset >= 0)
+ abort ();
+
+ /* SCRATCH = *THIS. */
+ emit_move_insn (scratch, gen_rtx_MEM (Pmode, this));
+
+ /* Prepare for adding VCALL_OFFSET. The difficulty is that we
+ may not have any available scratch register at this point. */
+ if (SPARC_SIMM13_P (vcall_offset))
+ ;
+ /* This is the case if ARCH64 (unless -ffixed-g5 is passed). */
+ else if (! fixed_regs[5]
+ /* The below sequence is made up of at least 2 insns,
+ while the default method may need only one. */
+ && vcall_offset < -8192)
+ {
+ rtx scratch2 = gen_rtx_REG (Pmode, 5);
+ emit_move_insn (scratch2, vcall_offset_rtx);
+ vcall_offset_rtx = scratch2;
+ }
else
{
- if (TARGET_ARCH64)
- sparc_emit_set_const64 (scratch, delta_rtx);
- else
- sparc_emit_set_const32 (scratch, delta_rtx);
+ rtx increment = GEN_INT (-4096);
+
+ /* VCALL_OFFSET is a negative number whose typical range can be
+ estimated as -32768..0 in 32-bit mode. In almost all cases
+ it is therefore cheaper to emit multiple add insns than
+ spilling and loading the constant into a register (at least
+ 6 insns). */
+ while (! SPARC_SIMM13_P (vcall_offset))
+ {
+ emit_insn (gen_add2_insn (scratch, increment));
+ vcall_offset += 4096;
+ }
+ vcall_offset_rtx = GEN_INT (vcall_offset); /* cannot be 0 */
}
- delta_rtx = scratch;
- }
+ /* SCRATCH = *(*THIS + VCALL_OFFSET). */
+ emit_move_insn (scratch, gen_rtx_MEM (Pmode,
+ gen_rtx_PLUS (Pmode,
+ scratch,
+ vcall_offset_rtx)));
- tmp = gen_rtx_PLUS (Pmode, this, delta_rtx);
- emit_insn (gen_rtx_SET (VOIDmode, this, tmp));
+ /* THIS += *(*THIS + VCALL_OFFSET). */
+ emit_insn (gen_add2_insn (this, scratch));
+ }
/* Generate a tail call to the target function. */
if (! TREE_USED (function))
@@ -9364,6 +9405,19 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
no_new_pseudos = 0;
}
+/* Return true if sparc_output_mi_thunk would be able to output the
+ assembler code for the thunk function specified by the arguments
+ it is passed, and false otherwise. */
+static bool
+sparc_can_output_mi_thunk (tree thunk_fndecl ATTRIBUTE_UNUSED,
+ HOST_WIDE_INT delta ATTRIBUTE_UNUSED,
+ HOST_WIDE_INT vcall_offset,
+ tree function ATTRIBUTE_UNUSED)
+{
+ /* Bound the loop used in the default method above. */
+ return (vcall_offset >= -32768 || ! fixed_regs[5]);
+}
+
/* How to allocate a 'struct machine_function'. */
static struct machine_function *
diff --git a/contrib/gcc/config/sparc/sparc.md b/contrib/gcc/config/sparc/sparc.md
index c7da780..b50d10a 100644
--- a/contrib/gcc/config/sparc/sparc.md
+++ b/contrib/gcc/config/sparc/sparc.md
@@ -2076,7 +2076,6 @@
if (! CONSTANT_P (operands[1]) || input_operand (operands[1], DImode))
;
else if (TARGET_ARCH64
- && CONSTANT_P (operands[1])
&& GET_CODE (operands[1]) != HIGH
&& GET_CODE (operands[1]) != LO_SUM)
{
diff --git a/contrib/gcc/config/sparc/t-elf b/contrib/gcc/config/sparc/t-elf
index 027940b..6868736 100644
--- a/contrib/gcc/config/sparc/t-elf
+++ b/contrib/gcc/config/sparc/t-elf
@@ -24,6 +24,6 @@ INSTALL_LIBGCC = install-multilib
# Assemble startup files.
crti.o: $(srcdir)/config/sparc/sol2-ci.asm $(GCC_PASSES)
- $(GCC_FOR_TARGET) -c -o crti.o -x assembler $(srcdir)/config/sparc/sol2-ci.asm
+ $(GCC_FOR_TARGET) -c -o crti.o -x assembler-with-cpp $(srcdir)/config/sparc/sol2-ci.asm
crtn.o: $(srcdir)/config/sparc/sol2-cn.asm $(GCC_PASSES)
- $(GCC_FOR_TARGET) -c -o crtn.o -x assembler $(srcdir)/config/sparc/sol2-cn.asm
+ $(GCC_FOR_TARGET) -c -o crtn.o -x assembler-with-cpp $(srcdir)/config/sparc/sol2-cn.asm
OpenPOWER on IntegriCloud