diff options
Diffstat (limited to 'gcc/config/sparc/sparc.c')
-rw-r--r-- | gcc/config/sparc/sparc.c | 38 |
1 files changed, 35 insertions, 3 deletions
diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c index 9f608c352eb..aed7e4b79d5 100644 --- a/gcc/config/sparc/sparc.c +++ b/gcc/config/sparc/sparc.c @@ -24,6 +24,8 @@ Boston, MA 02111-1307, USA. */ #include "config.h" #include "system.h" +#include "coretypes.h" +#include "tm.h" #include "tree.h" #include "rtl.h" #include "regs.h" @@ -176,6 +178,7 @@ static void emit_soft_tfmode_cvt PARAMS ((enum rtx_code, rtx *)); static void emit_hard_tfmode_operation PARAMS ((enum rtx_code, rtx *)); static void sparc_encode_section_info PARAMS ((tree, int)); +static bool sparc_function_ok_for_sibcall PARAMS ((tree, tree)); static void sparc_output_mi_thunk PARAMS ((FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT, tree)); @@ -241,6 +244,9 @@ enum processor_type sparc_cpu; #undef TARGET_ENCODE_SECTION_INFO #define TARGET_ENCODE_SECTION_INFO sparc_encode_section_info +#undef TARGET_FUNCTION_OK_FOR_SIBCALL +#define TARGET_FUNCTION_OK_FOR_SIBCALL sparc_function_ok_for_sibcall + #undef TARGET_ASM_OUTPUT_MI_THUNK #define TARGET_ASM_OUTPUT_MI_THUNK sparc_output_mi_thunk #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK @@ -3294,7 +3300,7 @@ load_pic_register () align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT); if (align > 0) ASM_OUTPUT_ALIGN (asm_out_file, align); - ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LGETPC", 0); + (*targetm.asm_out.internal_label) (asm_out_file, "LGETPC", 0); fputs ("\tretl\n\tadd\t%o7, %l7, %l7\n", asm_out_file); } @@ -7819,7 +7825,7 @@ sparc_output_addr_vec (vec) ASM_OUTPUT_CASE_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (lab), NEXT_INSN (lab)); #else - ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (lab)); + (*targetm.asm_out.internal_label) (asm_out_file, "L", CODE_LABEL_NUMBER (lab)); #endif for (idx = 0; idx < vlen; idx++) @@ -7849,7 +7855,7 @@ sparc_output_addr_diff_vec (vec) ASM_OUTPUT_CASE_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (lab), NEXT_INSN (lab)); #else - ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (lab)); + (*targetm.asm_out.internal_label) (asm_out_file, "L", CODE_LABEL_NUMBER (lab)); #endif for (idx = 0; idx < vlen; idx++) @@ -8028,6 +8034,32 @@ sparc_elf_asm_named_section (name, flags) } #endif /* OBJECT_FORMAT_ELF */ +/* We do not allow sibling calls if -mflat, nor + we do not allow indirect calls to be optimized into sibling calls. + + Also, on sparc 32-bit we cannot emit a sibling call when the + current function returns a structure. This is because the "unimp + after call" convention would cause the callee to return to the + wrong place. The generic code already disallows cases where the + function being called returns a structure. + + It may seem strange how this last case could occur. Usually there + is code after the call which jumps to epilogue code which dumps the + return value into the struct return area. That ought to invalidate + the sibling call right? Well, in the c++ case we can end up passing + the pointer to the struct return area to a constructor (which returns + void) and then nothing else happens. Such a sibling call would look + valid without the added check here. */ +static bool +sparc_function_ok_for_sibcall (decl, exp) + tree decl; + tree exp ATTRIBUTE_UNUSED; +{ + return (decl + && ! TARGET_FLAT + && (TARGET_ARCH64 || ! current_function_returns_struct)); +} + /* ??? Similar to the standard section selection, but force reloc-y-ness if SUNOS4_SHARED_LIBRARIES. Unclear why this helps (as opposed to pretending PIC always on), but that's what the old code did. */ |