diff options
author | ebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4> | 2004-10-13 14:04:32 +0000 |
---|---|---|
committer | ebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4> | 2004-10-13 14:04:32 +0000 |
commit | 3fc0f693e8a9cf3c1f60de576a10674db197851e (patch) | |
tree | 2a05cc75f88b727c5ea8b1c92233af46aedb9734 /gcc/config/sparc | |
parent | 420161405637c717509299702388f401cff5ceb2 (diff) | |
download | gcc-3fc0f693e8a9cf3c1f60de576a10674db197851e.tar.gz |
PR target/14454
* config/sparc/sparc.c (TARGET_ASM_CAN_OUTPUT_MI_THUNK): Set to
sparc_can_output_mi_thunk.
(sparc_output_mi_thunk): Simplify handling of delta offset. Add
handling of vcall offset.
(sparc_can_output_mi_thunk): New predicate.
* doc/tm.texi (TARGET_ASM_OUTPUT_MI_THUNK): Document VCALL_OFFSET.
(TARGET_ASM_OUTPUT_MI_VCALL_THUNK): Delete.
(TARGET_ASM_CAN_OUTPUT_MI_THUNK): New target hook.
* config/sparc/sparc.c (emit_and_preserve): Preserve stack alignment.
* config/sparc/sparc.md (movdi): Remove redundant test.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@88985 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/sparc')
-rw-r--r-- | gcc/config/sparc/sparc.c | 105 | ||||
-rw-r--r-- | gcc/config/sparc/sparc.md | 1 |
2 files changed, 84 insertions, 22 deletions
diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c index 3f75954e6cc..3371db95aef 100644 --- a/gcc/config/sparc/sparc.c +++ b/gcc/config/sparc/sparc.c @@ -334,6 +334,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); @@ -425,7 +427,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 @@ -8511,23 +8513,25 @@ emit_and_preserve (rtx seq, rtx reg) rtx slot = gen_rtx_MEM (word_mode, plus_constant (stack_pointer_rtx, SPARC_STACK_BIAS)); - emit_stack_pointer_decrement (GEN_INT (UNITS_PER_WORD)); + emit_stack_pointer_decrement (GEN_INT (STACK_BOUNDARY/BITS_PER_UNIT)); emit_insn (gen_rtx_SET (VOIDmode, slot, reg)); emit_insn (seq); emit_insn (gen_rtx_SET (VOIDmode, reg, slot)); - emit_stack_pointer_increment (GEN_INT (UNITS_PER_WORD)); + emit_stack_pointer_increment (GEN_INT (STACK_BOUNDARY/BITS_PER_UNIT)); } -/* 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; + rtx this, insn, funexp; unsigned int int_arg_first; reload_completed = 1; @@ -8566,27 +8570,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))); - emit_insn (gen_rtx_SET (VOIDmode, - this, - gen_rtx_PLUS (Pmode, this, delta_rtx))); + /* THIS += *(*THIS + VCALL_OFFSET). */ + emit_insn (gen_add2_insn (this, scratch)); + } /* Generate a tail call to the target function. */ if (! TREE_USED (function)) @@ -8674,6 +8724,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/gcc/config/sparc/sparc.md b/gcc/config/sparc/sparc.md index 182afb9a7cd..1000fbb3063 100644 --- a/gcc/config/sparc/sparc.md +++ b/gcc/config/sparc/sparc.md @@ -2099,7 +2099,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) { |