The attached change adds mi_thunk support for vcalls on hppa. Tested on hppa-unknown-linux-gnu, hppa2.0w-hp-hpux11.11 and hppa64-hp-hpux11.11. Committed to trunk and gcc-10.
Dave -- John David Anglin dave.ang...@bell.net Add mi_thunk support for vcalls on hppa. gcc/ChangeLog: PR target/85074 * config/pa/pa.c (TARGET_ASM_CAN_OUTPUT_MI_THUNK): Define as hook_bool_const_tree_hwi_hwi_const_tree_true. (pa_asm_output_mi_thunk): Add support for nonzero vcall_offset. diff --git a/gcc/config/pa/pa.c b/gcc/config/pa/pa.c index 3921b5c98de..d7fcd11e504 100644 --- a/gcc/config/pa/pa.c +++ b/gcc/config/pa/pa.c @@ -293,7 +293,7 @@ static size_t n_deferred_plabels = 0; #undef TARGET_ASM_OUTPUT_MI_THUNK #define TARGET_ASM_OUTPUT_MI_THUNK pa_asm_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 hook_bool_const_tree_hwi_hwi_const_tree_true #undef TARGET_ASM_FILE_END #define TARGET_ASM_FILE_END pa_file_end @@ -8461,12 +8461,15 @@ pa_is_function_label_plus_const (rtx op) && GET_CODE (XEXP (op, 1)) == CONST_INT); } -/* Output assembly code for a thunk to FUNCTION. */ +/* 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 + *(*this + vcall_offset) should be added to THIS. */ static void pa_asm_output_mi_thunk (FILE *file, tree thunk_fndecl, HOST_WIDE_INT delta, - HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED, - tree function) + HOST_WIDE_INT vcall_offset, tree function) { const char *fnname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (thunk_fndecl)); static unsigned int current_thunk_number; @@ -8482,201 +8485,386 @@ pa_asm_output_mi_thunk (FILE *file, tree thunk_fndecl, HOST_WIDE_INT delta, assemble_start_function (thunk_fndecl, fnname); final_start_function (emit_barrier (), file, 1); - /* Output the thunk. We know that the function is in the same - translation unit (i.e., the same space) as the thunk, and that - thunks are output after their method. Thus, we don't need an - external branch to reach the function. With SOM and GAS, - functions and thunks are effectively in different sections. - Thus, we can always use a IA-relative branch and the linker - will add a long branch stub if necessary. - - However, we have to be careful when generating PIC code on the - SOM port to ensure that the sequence does not transfer to an - import stub for the target function as this could clobber the - return value saved at SP-24. This would also apply to the - 32-bit linux port if the multi-space model is implemented. */ - if ((!TARGET_LONG_CALLS && TARGET_SOM && !TARGET_PORTABLE_RUNTIME - && !(flag_pic && TREE_PUBLIC (function)) - && (TARGET_GAS || last_address < 262132)) - || (!TARGET_LONG_CALLS && !TARGET_SOM && !TARGET_PORTABLE_RUNTIME - && ((targetm_common.have_named_sections - && DECL_SECTION_NAME (thunk_fndecl) != NULL - /* The GNU 64-bit linker has rather poor stub management. - So, we use a long branch from thunks that aren't in - the same section as the target function. */ - && ((!TARGET_64BIT - && (DECL_SECTION_NAME (thunk_fndecl) - != DECL_SECTION_NAME (function))) - || ((DECL_SECTION_NAME (thunk_fndecl) - == DECL_SECTION_NAME (function)) - && last_address < 262132))) - /* In this case, we need to be able to reach the start of - the stub table even though the function is likely closer - and can be jumped to directly. */ - || (targetm_common.have_named_sections - && DECL_SECTION_NAME (thunk_fndecl) == NULL - && DECL_SECTION_NAME (function) == NULL - && total_code_bytes < MAX_PCREL17F_OFFSET) - /* Likewise. */ - || (!targetm_common.have_named_sections - && total_code_bytes < MAX_PCREL17F_OFFSET)))) - { - if (!val_14) - output_asm_insn ("addil L'%2,%%r26", xoperands); - - output_asm_insn ("b %0", xoperands); - - if (val_14) - { - output_asm_insn ("ldo %2(%%r26),%%r26", xoperands); - nbytes += 8; + if (!vcall_offset) + { + /* Output the thunk. We know that the function is in the same + translation unit (i.e., the same space) as the thunk, and that + thunks are output after their method. Thus, we don't need an + external branch to reach the function. With SOM and GAS, + functions and thunks are effectively in different sections. + Thus, we can always use a IA-relative branch and the linker + will add a long branch stub if necessary. + + However, we have to be careful when generating PIC code on the + SOM port to ensure that the sequence does not transfer to an + import stub for the target function as this could clobber the + return value saved at SP-24. This would also apply to the + 32-bit linux port if the multi-space model is implemented. */ + if ((!TARGET_LONG_CALLS && TARGET_SOM && !TARGET_PORTABLE_RUNTIME + && !(flag_pic && TREE_PUBLIC (function)) + && (TARGET_GAS || last_address < 262132)) + || (!TARGET_LONG_CALLS && !TARGET_SOM && !TARGET_PORTABLE_RUNTIME + && ((targetm_common.have_named_sections + && DECL_SECTION_NAME (thunk_fndecl) != NULL + /* The GNU 64-bit linker has rather poor stub management. + So, we use a long branch from thunks that aren't in + the same section as the target function. */ + && ((!TARGET_64BIT + && (DECL_SECTION_NAME (thunk_fndecl) + != DECL_SECTION_NAME (function))) + || ((DECL_SECTION_NAME (thunk_fndecl) + == DECL_SECTION_NAME (function)) + && last_address < 262132))) + /* In this case, we need to be able to reach the start of + the stub table even though the function is likely closer + and can be jumped to directly. */ + || (targetm_common.have_named_sections + && DECL_SECTION_NAME (thunk_fndecl) == NULL + && DECL_SECTION_NAME (function) == NULL + && total_code_bytes < MAX_PCREL17F_OFFSET) + /* Likewise. */ + || (!targetm_common.have_named_sections + && total_code_bytes < MAX_PCREL17F_OFFSET)))) + { + if (!val_14) + output_asm_insn ("addil L'%2,%%r26", xoperands); + + output_asm_insn ("b %0", xoperands); + + if (val_14) + { + output_asm_insn ("ldo %2(%%r26),%%r26", xoperands); + nbytes += 8; + } + else + { + output_asm_insn ("ldo R'%2(%%r1),%%r26", xoperands); + nbytes += 12; + } } - else + else if (TARGET_64BIT) { - output_asm_insn ("ldo R'%2(%%r1),%%r26", xoperands); - nbytes += 12; - } - } - else if (TARGET_64BIT) - { - rtx xop[4]; + rtx xop[4]; + + /* We only have one call-clobbered scratch register, so we can't + make use of the delay slot if delta doesn't fit in 14 bits. */ + if (!val_14) + { + output_asm_insn ("addil L'%2,%%r26", xoperands); + output_asm_insn ("ldo R'%2(%%r1),%%r26", xoperands); + } + + /* Load function address into %r1. */ + xop[0] = xoperands[0]; + xop[1] = gen_rtx_REG (Pmode, 1); + xop[2] = xop[1]; + pa_output_pic_pcrel_sequence (xop); - /* We only have one call-clobbered scratch register, so we can't - make use of the delay slot if delta doesn't fit in 14 bits. */ - if (!val_14) + if (val_14) + { + output_asm_insn ("bv %%r0(%%r1)", xoperands); + output_asm_insn ("ldo %2(%%r26),%%r26", xoperands); + nbytes += 20; + } + else + { + output_asm_insn ("bv,n %%r0(%%r1)", xoperands); + nbytes += 24; + } + } + else if (TARGET_PORTABLE_RUNTIME) { - output_asm_insn ("addil L'%2,%%r26", xoperands); - output_asm_insn ("ldo R'%2(%%r1),%%r26", xoperands); + output_asm_insn ("ldil L'%0,%%r1", xoperands); + output_asm_insn ("ldo R'%0(%%r1),%%r22", xoperands); + + if (!val_14) + output_asm_insn ("ldil L'%2,%%r26", xoperands); + + output_asm_insn ("bv %%r0(%%r22)", xoperands); + + if (val_14) + { + output_asm_insn ("ldo %2(%%r26),%%r26", xoperands); + nbytes += 16; + } + else + { + output_asm_insn ("ldo R'%2(%%r26),%%r26", xoperands); + nbytes += 20; + } } + else if (TARGET_SOM && flag_pic && TREE_PUBLIC (function)) + { + /* The function is accessible from outside this module. The only + way to avoid an import stub between the thunk and function is to + call the function directly with an indirect sequence similar to + that used by $$dyncall. This is possible because $$dyncall acts + as the import stub in an indirect call. */ + ASM_GENERATE_INTERNAL_LABEL (label, "LTHN", current_thunk_number); + xoperands[3] = gen_rtx_SYMBOL_REF (Pmode, label); + output_asm_insn ("addil LT'%3,%%r19", xoperands); + output_asm_insn ("ldw RT'%3(%%r1),%%r22", xoperands); + output_asm_insn ("ldw 0(%%sr0,%%r22),%%r22", xoperands); + output_asm_insn ("bb,>=,n %%r22,30,.+16", xoperands); + output_asm_insn ("depi 0,31,2,%%r22", xoperands); + output_asm_insn ("ldw 4(%%sr0,%%r22),%%r19", xoperands); + output_asm_insn ("ldw 0(%%sr0,%%r22),%%r22", xoperands); + + if (!val_14) + { + output_asm_insn ("addil L'%2,%%r26", xoperands); + nbytes += 4; + } - /* Load function address into %r1. */ - xop[0] = xoperands[0]; - xop[1] = gen_rtx_REG (Pmode, 1); - xop[2] = xop[1]; - pa_output_pic_pcrel_sequence (xop); + if (TARGET_PA_20) + { + output_asm_insn ("bve (%%r22)", xoperands); + nbytes += 36; + } + else if (TARGET_NO_SPACE_REGS) + { + output_asm_insn ("be 0(%%sr4,%%r22)", xoperands); + nbytes += 36; + } + else + { + output_asm_insn ("ldsid (%%sr0,%%r22),%%r21", xoperands); + output_asm_insn ("mtsp %%r21,%%sr0", xoperands); + output_asm_insn ("be 0(%%sr0,%%r22)", xoperands); + nbytes += 44; + } - if (val_14) - { - output_asm_insn ("bv %%r0(%%r1)", xoperands); - output_asm_insn ("ldo %2(%%r26),%%r26", xoperands); - nbytes += 20; + if (val_14) + output_asm_insn ("ldo %2(%%r26),%%r26", xoperands); + else + output_asm_insn ("ldo R'%2(%%r1),%%r26", xoperands); } - else + else if (flag_pic) { - output_asm_insn ("bv,n %%r0(%%r1)", xoperands); - nbytes += 24; - } - } - else if (TARGET_PORTABLE_RUNTIME) - { - output_asm_insn ("ldil L'%0,%%r1", xoperands); - output_asm_insn ("ldo R'%0(%%r1),%%r22", xoperands); + rtx xop[4]; - if (!val_14) - output_asm_insn ("ldil L'%2,%%r26", xoperands); + /* Load function address into %r22. */ + xop[0] = xoperands[0]; + xop[1] = gen_rtx_REG (Pmode, 1); + xop[2] = gen_rtx_REG (Pmode, 22); + pa_output_pic_pcrel_sequence (xop); - output_asm_insn ("bv %%r0(%%r22)", xoperands); + if (!val_14) + output_asm_insn ("addil L'%2,%%r26", xoperands); - if (val_14) - { - output_asm_insn ("ldo %2(%%r26),%%r26", xoperands); - nbytes += 16; + output_asm_insn ("bv %%r0(%%r22)", xoperands); + + if (val_14) + { + output_asm_insn ("ldo %2(%%r26),%%r26", xoperands); + nbytes += 20; + } + else + { + output_asm_insn ("ldo R'%2(%%r1),%%r26", xoperands); + nbytes += 24; + } } else { - output_asm_insn ("ldo R'%2(%%r26),%%r26", xoperands); - nbytes += 20; + if (!val_14) + output_asm_insn ("addil L'%2,%%r26", xoperands); + + output_asm_insn ("ldil L'%0,%%r22", xoperands); + output_asm_insn ("be R'%0(%%sr4,%%r22)", xoperands); + + if (val_14) + { + output_asm_insn ("ldo %2(%%r26),%%r26", xoperands); + nbytes += 12; + } + else + { + output_asm_insn ("ldo R'%2(%%r1),%%r26", xoperands); + nbytes += 16; + } } } - else if (TARGET_SOM && flag_pic && TREE_PUBLIC (function)) + else { - /* The function is accessible from outside this module. The only - way to avoid an import stub between the thunk and function is to - call the function directly with an indirect sequence similar to - that used by $$dyncall. This is possible because $$dyncall acts - as the import stub in an indirect call. */ - ASM_GENERATE_INTERNAL_LABEL (label, "LTHN", current_thunk_number); - xoperands[3] = gen_rtx_SYMBOL_REF (Pmode, label); - output_asm_insn ("addil LT'%3,%%r19", xoperands); - output_asm_insn ("ldw RT'%3(%%r1),%%r22", xoperands); - output_asm_insn ("ldw 0(%%sr0,%%r22),%%r22", xoperands); - output_asm_insn ("bb,>=,n %%r22,30,.+16", xoperands); - output_asm_insn ("depi 0,31,2,%%r22", xoperands); - output_asm_insn ("ldw 4(%%sr0,%%r22),%%r19", xoperands); - output_asm_insn ("ldw 0(%%sr0,%%r22),%%r22", xoperands); + rtx xop[4]; - if (!val_14) + /* Add DELTA to THIS. */ + if (val_14) { - output_asm_insn ("addil L'%2,%%r26", xoperands); + output_asm_insn ("ldo %2(%%r26),%%r26", xoperands); nbytes += 4; } - - if (TARGET_PA_20) + else { - output_asm_insn ("bve (%%r22)", xoperands); - nbytes += 36; + output_asm_insn ("addil L'%2,%%r26", xoperands); + output_asm_insn ("ldo R'%2(%%r1),%%r26", xoperands); + nbytes += 8; } - else if (TARGET_NO_SPACE_REGS) + + if (TARGET_64BIT) { - output_asm_insn ("be 0(%%sr4,%%r22)", xoperands); - nbytes += 36; + /* Load *(THIS + DELTA) to %r1. */ + output_asm_insn ("ldd 0(%%r26),%%r1", xoperands); + + val_14 = VAL_14_BITS_P (vcall_offset); + xoperands[2] = GEN_INT (vcall_offset); + + /* Load *(*(THIS + DELTA) + VCALL_OFFSET) to %r1. */ + if (val_14) + { + output_asm_insn ("ldd %2(%%r1),%%r1", xoperands); + nbytes += 8; + } + else + { + output_asm_insn ("addil L'%2,%%r1", xoperands); + output_asm_insn ("ldd R'%2(%%r1),%%r1", xoperands); + nbytes += 12; + } } else { - output_asm_insn ("ldsid (%%sr0,%%r22),%%r21", xoperands); - output_asm_insn ("mtsp %%r21,%%sr0", xoperands); - output_asm_insn ("be 0(%%sr0,%%r22)", xoperands); - nbytes += 44; - } + /* Load *(THIS + DELTA) to %r1. */ + output_asm_insn ("ldw 0(%%r26),%%r1", xoperands); - if (val_14) - output_asm_insn ("ldo %2(%%r26),%%r26", xoperands); - else - output_asm_insn ("ldo R'%2(%%r1),%%r26", xoperands); - } - else if (flag_pic) - { - rtx xop[4]; - - /* Load function address into %r22. */ - xop[0] = xoperands[0]; - xop[1] = gen_rtx_REG (Pmode, 1); - xop[2] = gen_rtx_REG (Pmode, 22); - pa_output_pic_pcrel_sequence (xop); + val_14 = VAL_14_BITS_P (vcall_offset); + xoperands[2] = GEN_INT (vcall_offset); - if (!val_14) - output_asm_insn ("addil L'%2,%%r26", xoperands); - - output_asm_insn ("bv %%r0(%%r22)", xoperands); + /* Load *(*(THIS + DELTA) + VCALL_OFFSET) to %r1. */ + if (val_14) + { + output_asm_insn ("ldw %2(%%r1),%%r1", xoperands); + nbytes += 8; + } + else + { + output_asm_insn ("addil L'%2,%%r1", xoperands); + output_asm_insn ("ldw R'%2(%%r1),%%r1", xoperands); + nbytes += 12; + } + } - if (val_14) + /* Branch to FUNCTION and add %r1 to THIS in delay slot if possible. */ + if ((!TARGET_LONG_CALLS && TARGET_SOM && !TARGET_PORTABLE_RUNTIME + && !(flag_pic && TREE_PUBLIC (function)) + && (TARGET_GAS || last_address < 262132)) + || (!TARGET_LONG_CALLS && !TARGET_SOM && !TARGET_PORTABLE_RUNTIME + && ((targetm_common.have_named_sections + && DECL_SECTION_NAME (thunk_fndecl) != NULL + /* The GNU 64-bit linker has rather poor stub management. + So, we use a long branch from thunks that aren't in + the same section as the target function. */ + && ((!TARGET_64BIT + && (DECL_SECTION_NAME (thunk_fndecl) + != DECL_SECTION_NAME (function))) + || ((DECL_SECTION_NAME (thunk_fndecl) + == DECL_SECTION_NAME (function)) + && last_address < 262132))) + /* In this case, we need to be able to reach the start of + the stub table even though the function is likely closer + and can be jumped to directly. */ + || (targetm_common.have_named_sections + && DECL_SECTION_NAME (thunk_fndecl) == NULL + && DECL_SECTION_NAME (function) == NULL + && total_code_bytes < MAX_PCREL17F_OFFSET) + /* Likewise. */ + || (!targetm_common.have_named_sections + && total_code_bytes < MAX_PCREL17F_OFFSET)))) { - output_asm_insn ("ldo %2(%%r26),%%r26", xoperands); - nbytes += 20; + nbytes += 4; + output_asm_insn ("b %0", xoperands); + + /* Add *(*(THIS + DELTA) + VCALL_OFFSET) to THIS. */ + output_asm_insn ("addl %%r1,%%r26,%%r26", xoperands); } - else + else if (TARGET_64BIT) { - output_asm_insn ("ldo R'%2(%%r1),%%r26", xoperands); - nbytes += 24; - } - } - else - { - if (!val_14) - output_asm_insn ("addil L'%2,%%r26", xoperands); + /* Add *(*(THIS + DELTA) + VCALL_OFFSET) to THIS. */ + output_asm_insn ("addl %%r1,%%r26,%%r26", xoperands); - output_asm_insn ("ldil L'%0,%%r22", xoperands); - output_asm_insn ("be R'%0(%%sr4,%%r22)", xoperands); + /* Load function address into %r1. */ + nbytes += 16; + xop[0] = xoperands[0]; + xop[1] = gen_rtx_REG (Pmode, 1); + xop[2] = xop[1]; + pa_output_pic_pcrel_sequence (xop); - if (val_14) + output_asm_insn ("bv,n %%r0(%%r1)", xoperands); + } + else if (TARGET_PORTABLE_RUNTIME) { - output_asm_insn ("ldo %2(%%r26),%%r26", xoperands); + /* Load function address into %r22. */ nbytes += 12; + output_asm_insn ("ldil L'%0,%%r22", xoperands); + output_asm_insn ("ldo R'%0(%%r22),%%r22", xoperands); + + output_asm_insn ("bv %%r0(%%r22)", xoperands); + + /* Add *(*(THIS + DELTA) + VCALL_OFFSET) to THIS. */ + output_asm_insn ("addl %%r1,%%r26,%%r26", xoperands); + } + else if (TARGET_SOM && flag_pic && TREE_PUBLIC (function)) + { + /* Add *(*(THIS + DELTA) + VCALL_OFFSET) to THIS. */ + output_asm_insn ("addl %%r1,%%r26,%%r26", xoperands); + + /* The function is accessible from outside this module. The only + way to avoid an import stub between the thunk and function is to + call the function directly with an indirect sequence similar to + that used by $$dyncall. This is possible because $$dyncall acts + as the import stub in an indirect call. */ + ASM_GENERATE_INTERNAL_LABEL (label, "LTHN", current_thunk_number); + xoperands[3] = gen_rtx_SYMBOL_REF (Pmode, label); + output_asm_insn ("addil LT'%3,%%r19", xoperands); + output_asm_insn ("ldw RT'%3(%%r1),%%r22", xoperands); + output_asm_insn ("ldw 0(%%sr0,%%r22),%%r22", xoperands); + output_asm_insn ("bb,>=,n %%r22,30,.+16", xoperands); + output_asm_insn ("depi 0,31,2,%%r22", xoperands); + output_asm_insn ("ldw 4(%%sr0,%%r22),%%r19", xoperands); + output_asm_insn ("ldw 0(%%sr0,%%r22),%%r22", xoperands); + + if (TARGET_PA_20) + { + output_asm_insn ("bve,n (%%r22)", xoperands); + nbytes += 32; + } + else if (TARGET_NO_SPACE_REGS) + { + output_asm_insn ("be,n 0(%%sr4,%%r22)", xoperands); + nbytes += 32; + } + else + { + output_asm_insn ("ldsid (%%sr0,%%r22),%%r21", xoperands); + output_asm_insn ("mtsp %%r21,%%sr0", xoperands); + output_asm_insn ("be,n 0(%%sr0,%%r22)", xoperands); + nbytes += 40; + } } - else + else if (flag_pic) { - output_asm_insn ("ldo R'%2(%%r1),%%r26", xoperands); + /* Add *(*(THIS + DELTA) + VCALL_OFFSET) to THIS. */ + output_asm_insn ("addl %%r1,%%r26,%%r26", xoperands); + + /* Load function address into %r1. */ nbytes += 16; + xop[0] = xoperands[0]; + xop[1] = gen_rtx_REG (Pmode, 1); + xop[2] = xop[1]; + pa_output_pic_pcrel_sequence (xop); + + output_asm_insn ("bv,n %%r0(%%r1)", xoperands); + } + else + { + /* Load function address into %r22. */ + nbytes += 8; + output_asm_insn ("ldil L'%0,%%r22", xoperands); + output_asm_insn ("be R'%0(%%sr4,%%r22)", xoperands); + + /* Add *(*(THIS + DELTA) + VCALL_OFFSET) to THIS. */ + output_asm_insn ("addl %%r1,%%r26,%%r26", xoperands); } }