The compiler option -mindirect-branch=<value> converts indirect branch-and-link-register and branch-register instructions according to <value>.
The default is ``keep``, which keeps indirect branch-and-link-register and branch-register instructions unmodified. ``thunk`` converts indirect branch-and-link-register/branch-register instructions to a branch-and-link/branch to a function containing a retpoline (to stop speculative execution) followed by a branch-register to the target. ``thunk-inline`` is similar to ``thunk``, but inlines the retpoline before the branch-and-link-register/branch-register instruction. ``thunk-extern`` is also similar to ``thunk``, but does not insert the functions containing the retpoline. When using this option, these functions need to be provided in a separate object file. The retpoline functions exist for each register and are named ``__aarch64_indirect_thunk_xN`` (N being the register number). It is also possible to override the indirect-branch setting for individual fuctions using the function attribute ``indirect_branch``. The actual retpoline instruction sequence, which prevents speculative indirect branches looks like this:: str x30, [sp, #-16]! bl 101f 100: //speculation trap wfe b 100b 101: //do ROP adr x30, 102f ret 102: //non-spec code ldr x30, [sp], #16 This patch has been tested with the included testcases and various other source bases (benchmarks, retpoline-patched arm64 kernel, etc.). --- gcc/config/aarch64/aarch64-opts.h | 9 + gcc/config/aarch64/aarch64.c | 298 +++++++++++++++++- gcc/config/aarch64/aarch64.h | 2 + gcc/config/aarch64/aarch64.opt | 20 ++ gcc/doc/invoke.texi | 20 +- .../gcc.target/aarch64/indirect-thunk-1.c | 25 ++ .../gcc.target/aarch64/indirect-thunk-2.c | 26 ++ .../gcc.target/aarch64/indirect-thunk-3.c | 26 ++ .../gcc.target/aarch64/indirect-thunk-4.c | 27 ++ .../gcc.target/aarch64/indirect-thunk-5.c | 25 ++ .../gcc.target/aarch64/indirect-thunk-6.c | 26 ++ .../aarch64/indirect-thunk-attr-1.c | 28 ++ .../aarch64/indirect-thunk-attr-2.c | 27 ++ .../aarch64/indirect-thunk-attr-3.c | 29 ++ .../aarch64/indirect-thunk-attr-4.c | 28 ++ .../aarch64/indirect-thunk-attr-5.c | 24 ++ .../aarch64/indirect-thunk-attr-6.c | 24 ++ .../aarch64/indirect-thunk-extern-1.c | 22 ++ .../aarch64/indirect-thunk-extern-2.c | 23 ++ .../aarch64/indirect-thunk-extern-3.c | 23 ++ .../aarch64/indirect-thunk-extern-4.c | 24 ++ .../aarch64/indirect-thunk-extern-5.c | 20 ++ .../aarch64/indirect-thunk-extern-6.c | 21 ++ .../aarch64/indirect-thunk-inline-1.c | 26 ++ .../aarch64/indirect-thunk-inline-2.c | 26 ++ .../aarch64/indirect-thunk-inline-3.c | 26 ++ .../aarch64/indirect-thunk-inline-4.c | 27 ++ .../aarch64/indirect-thunk-inline-5.c | 23 ++ .../aarch64/indirect-thunk-inline-6.c | 24 ++ 29 files changed, 941 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-1.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-2.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-3.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-4.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-5.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-6.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-1.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-2.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-3.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-4.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-5.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-6.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-1.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-2.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-3.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-4.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-5.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-6.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-1.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-2.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-3.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-4.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-5.c create mode 100644 gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-6.c diff --git a/gcc/config/aarch64/aarch64-opts.h b/gcc/config/aarch64/aarch64-opts.h index ee7bed34924..0113533892d 100644 --- a/gcc/config/aarch64/aarch64-opts.h +++ b/gcc/config/aarch64/aarch64-opts.h @@ -98,4 +98,13 @@ enum stack_protector_guard { SSP_GLOBAL /* global canary */ }; +/* Values for -mindirect-branch option. */ +enum indirect_branch { + indirect_branch_unset = 0, + indirect_branch_keep, + indirect_branch_thunk, + indirect_branch_thunk_inline, + indirect_branch_thunk_extern +}; + #endif diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index 4799679f9e5..56366faeb69 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -1508,6 +1508,44 @@ handle_aarch64_vector_pcs_attribute (tree *node, tree name, tree, gcc_unreachable (); } +/* Check whether 'indirect_branch' fndecl attribute is valid. */ + +static tree +aarch64_handle_fndecl_attribute (tree *node, tree name, tree args, int, + bool *no_add_attrs) +{ + if (TREE_CODE (*node) != FUNCTION_DECL) + { + warning (OPT_Wattributes, "%qE attribute only applies to functions", + name); + *no_add_attrs = true; + } + + if (is_attribute_p ("indirect_branch", name)) + { + tree cst = TREE_VALUE (args); + if (TREE_CODE (cst) != STRING_CST) + { + warning (OPT_Wattributes, + "%qE attribute requires a string constant argument", + name); + *no_add_attrs = true; + } + else if (strcmp (TREE_STRING_POINTER (cst), "keep") != 0 + && strcmp (TREE_STRING_POINTER (cst), "thunk") != 0 + && strcmp (TREE_STRING_POINTER (cst), "thunk-inline") != 0 + && strcmp (TREE_STRING_POINTER (cst), "thunk-extern") != 0) + { + warning (OPT_Wattributes, + "argument to %qE attribute is not " + "(keep|thunk|thunk-inline|thunk-extern)", name); + *no_add_attrs = true; + } + } + + return NULL_TREE; +} + /* Table of machine attributes. */ static const struct attribute_spec aarch64_attribute_table[] = { @@ -1521,6 +1559,8 @@ static const struct attribute_spec aarch64_attribute_table[] = { "Advanced SIMD type", 1, 1, false, true, false, true, NULL, NULL }, { "SVE type", 3, 3, false, true, false, true, NULL, NULL }, { "SVE sizeless type", 0, 0, false, true, false, true, NULL, NULL }, + { "indirect_branch", 1, 1, true, false, false, false, + aarch64_handle_fndecl_attribute, NULL }, { NULL, 0, 0, false, false, false, false, NULL, NULL } }; @@ -15227,6 +15267,35 @@ aarch64_save_restore_target_globals (tree new_tree) TREE_TARGET_GLOBALS (new_tree) = save_target_globals_default_opts (); } +static void +aarch64_set_indirect_branch_type (tree fndecl) +{ + if (cfun->machine->indirect_branch_type == indirect_branch_unset) + { + tree attr = lookup_attribute ("indirect_branch", + DECL_ATTRIBUTES (fndecl)); + if (attr != NULL) + { + tree args = TREE_VALUE (attr); + if (args == NULL) + gcc_unreachable (); + tree cst = TREE_VALUE (args); + if (strcmp (TREE_STRING_POINTER (cst), "keep") == 0) + cfun->machine->indirect_branch_type = indirect_branch_keep; + else if (strcmp (TREE_STRING_POINTER (cst), "thunk") == 0) + cfun->machine->indirect_branch_type = indirect_branch_thunk; + else if (strcmp (TREE_STRING_POINTER (cst), "thunk-inline") == 0) + cfun->machine->indirect_branch_type = indirect_branch_thunk_inline; + else if (strcmp (TREE_STRING_POINTER (cst), "thunk-extern") == 0) + cfun->machine->indirect_branch_type = indirect_branch_thunk_extern; + else + gcc_unreachable (); + } + else + cfun->machine->indirect_branch_type = aarch64_indirect_branch; + } +} + /* Implement TARGET_SET_CURRENT_FUNCTION. Unpack the codegen decisions like tuning and ISA features from the DECL_FUNCTION_SPECIFIC_TARGET of the function, if such exists. This function may be called multiple @@ -15237,7 +15306,18 @@ static void aarch64_set_current_function (tree fndecl) { if (!fndecl || fndecl == aarch64_previous_fndecl) - return; + { + if (fndecl != NULL_TREE) + { + aarch64_set_indirect_branch_type (fndecl); + } + return; + } + + if (fndecl != NULL_TREE) + { + aarch64_set_indirect_branch_type (fndecl); + } tree old_tree = (aarch64_previous_fndecl ? DECL_FUNCTION_SPECIFIC_TARGET (aarch64_previous_fndecl) @@ -23659,27 +23739,225 @@ aarch64_asm_file_end () #endif } +/* Label count for call and return thunks. It is used to make unique + labels in call and return thunks. */ +static int indirectlabelno; + +/* Bit masks of integer registers, which contain branch target, used + by call and return thunks functions. */ +static int indirect_thunks_used; + +#ifndef INDIRECT_LABEL +# define INDIRECT_LABEL "LIND" +#endif + +/* Fills in the label name that should be used for the indirect thunk. */ + +static void +indirect_thunk_name (char name[32], int regno) +{ + sprintf (name, "__aarch64_indirect_thunk_%s", + reg_names[regno]); +} + +/* Output a retpoline thunk for aarch64: + + push lr + bl L2 +L1: wfe + b L1 +L2: mov lr, &L3 + ret +L3: pop lr + */ + +static void +output_indirect_thunk (bool save_lr) +{ + char indirectlabel1[32]; + char indirectlabel2[32]; + char indirectlabel3[32]; + + ASM_GENERATE_INTERNAL_LABEL (indirectlabel1, INDIRECT_LABEL, + indirectlabelno++); + ASM_GENERATE_INTERNAL_LABEL (indirectlabel2, INDIRECT_LABEL, + indirectlabelno++); + ASM_GENERATE_INTERNAL_LABEL (indirectlabel3, INDIRECT_LABEL, + indirectlabelno++); + + if (save_lr) + { + /* push lr */ + fputs ("\tstr\tx30, [sp, #-16]!\n", asm_out_file); + } + + /* bl L2 */ + fputs ("\tbl\t", asm_out_file); + assemble_name_raw (asm_out_file, indirectlabel2); + fputc ('\n', asm_out_file); + + /* L1: wfe/dsb loop */ + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel1); + fprintf (asm_out_file, "\twfe\n"); + fputs ("\tb\t", asm_out_file); + assemble_name_raw (asm_out_file, indirectlabel1); + fputc ('\n', asm_out_file); + + /* L2: lr=&L3; ret */ + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel2); + fputs ("\tadr\tx30, ", asm_out_file); + assemble_name_raw (asm_out_file, indirectlabel3); + fputc ('\n', asm_out_file); + fputs ("\tret\n", asm_out_file); + + /* L3: */ + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel3); + + if (save_lr) + { + /* pop lr */ + fputs ("\tldr\tx30, [sp], #16\n", asm_out_file); + } +} + +static void +output_indirect_thunk_function (int regno) +{ + char name[32]; + tree decl; + + /* Create __aarch64_indirect_thunk */ + indirect_thunk_name (name, regno); + decl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL, + get_identifier (name), + build_function_type_list (void_type_node, NULL_TREE)); + DECL_RESULT (decl) = build_decl (BUILTINS_LOCATION, RESULT_DECL, + NULL_TREE, void_type_node); + TREE_PUBLIC (decl) = 1; + TREE_STATIC (decl) = 1; + DECL_IGNORED_P (decl) = 1; + + cgraph_node::create (decl)->set_comdat_group (DECL_ASSEMBLER_NAME (decl)); + + targetm.asm_out.unique_section (decl, 0); + switch_to_section (get_named_section (decl, NULL, 0)); + + targetm.asm_out.globalize_label (asm_out_file, name); + fputs ("\t.hidden\t", asm_out_file); + assemble_name (asm_out_file, name); + putc ('\n', asm_out_file); + ASM_DECLARE_FUNCTION_NAME (asm_out_file, name, decl); + + DECL_INITIAL (decl) = make_node (BLOCK); + current_function_decl = decl; + allocate_struct_function (decl, false); + init_function_start (decl); + /* We're about to hide the function body from callees of final_* by + emitting it directly; tell them we're a thunk, if they care. */ + cfun->is_thunk = true; + first_function_block_is_cold = false; + /* Make sure unwind info is emitted for the thunk if needed. */ + final_start_function (emit_barrier (), asm_out_file, 1); + + output_indirect_thunk (true); + rtx xop = gen_rtx_REG (word_mode, regno); + output_asm_insn ("br\t%0", &xop); + + final_end_function (); + init_insn_lengths (); + free_after_compilation (cfun); + set_cfun (NULL); + current_function_decl = NULL; +} + const char * -aarch64_indirect_branch_asm (rtx addr) +aarch64_indirect_branch_asm (rtx call_op) { - output_asm_insn ("br\t%0", &addr); + char thunk_name_buf[32]; + char *thunk_name; + int regno = REGNO (call_op); + + if (cfun->machine->indirect_branch_type == indirect_branch_thunk_inline) + { + output_indirect_thunk (true); + output_asm_insn ("br\t%0", &call_op); + } + else if (cfun->machine->indirect_branch_type == indirect_branch_thunk) + { + indirect_thunks_used |= 1 << regno; + + indirect_thunk_name (thunk_name_buf, regno); + thunk_name = thunk_name_buf; + fprintf (asm_out_file, "\tb\t%s\n", thunk_name); + } + else if (cfun->machine->indirect_branch_type == indirect_branch_thunk_extern) + { + indirect_thunk_name (thunk_name_buf, regno); + thunk_name = thunk_name_buf; + fprintf (asm_out_file, "\tb\t%s\n", thunk_name); + } + else + { + output_asm_insn ("br\t%0", &call_op); + } return ""; } const char * -aarch64_indirect_call_asm (rtx addr) +aarch64_indirect_call_asm (rtx call_op) { - gcc_assert (REG_P (addr)); + char thunk_name_buf[32]; + char *thunk_name; + int regno = REGNO (call_op); + + gcc_assert (REG_P (call_op)); if (aarch64_harden_sls_blr_p ()) { - rtx stub_label = aarch64_sls_create_blr_label (REGNO (addr)); + rtx stub_label = aarch64_sls_create_blr_label (REGNO (call_op)); output_asm_insn ("bl\t%0", &stub_label); + return ""; + } + + if (cfun->machine->indirect_branch_type == indirect_branch_thunk_inline) + { + output_indirect_thunk (true); + output_asm_insn ("blr\t%0", &call_op); + } + else if (cfun->machine->indirect_branch_type == indirect_branch_thunk) + { + indirect_thunks_used |= 1 << regno; + + indirect_thunk_name (thunk_name_buf, regno); + thunk_name = thunk_name_buf; + fprintf (asm_out_file, "\tbl\t%s\n", thunk_name); + } + else if (cfun->machine->indirect_branch_type == indirect_branch_thunk_extern) + { + indirect_thunk_name (thunk_name_buf, regno); + thunk_name = thunk_name_buf; + fprintf (asm_out_file, "\tbl\t%s\n", thunk_name); } else - output_asm_insn ("blr\t%0", &addr); + { + output_asm_insn ("blr\t%0", &call_op); + } return ""; } +/* Implements TARGET_ASM_CODE_END. */ + +static void +aarch64_code_end (void) +{ + int regno; + + for (regno = R0_REGNUM; regno <= SP_REGNUM; regno++) + { + if (indirect_thunks_used & (1 << regno)) + output_indirect_thunk_function (regno); + } +} + /* Target-specific selftests. */ #if CHECKING_P @@ -23752,6 +24030,9 @@ aarch64_run_selftests (void) #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \ hook_bool_const_tree_hwi_hwi_const_tree_true +#undef TARGET_ASM_CODE_END +#define TARGET_ASM_CODE_END aarch64_code_end + #undef TARGET_ASM_FILE_START #define TARGET_ASM_FILE_START aarch64_start_file @@ -24203,6 +24484,9 @@ aarch64_libgcc_floating_mode_supported_p #undef TARGET_ATTRIBUTE_TABLE #define TARGET_ATTRIBUTE_TABLE aarch64_attribute_table +#undef TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P +#define TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P hook_bool_const_tree_true + #undef TARGET_SIMD_CLONE_COMPUTE_VECSIZE_AND_SIMDLEN #define TARGET_SIMD_CLONE_COMPUTE_VECSIZE_AND_SIMDLEN \ aarch64_simd_clone_compute_vecsize_and_simdlen diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h index 0bdcc74ace5..d23bb8e8981 100644 --- a/gcc/config/aarch64/aarch64.h +++ b/gcc/config/aarch64/aarch64.h @@ -903,6 +903,8 @@ typedef struct GTY (()) machine_function /* One entry for each general purpose register. */ rtx call_via[SP_REGNUM]; bool label_is_assembled; + /* How to generate indirect branch. */ + ENUM_BITFIELD (indirect_branch) indirect_branch_type : 3; } machine_function; #endif diff --git a/gcc/config/aarch64/aarch64.opt b/gcc/config/aarch64/aarch64.opt index 1b3d942e0f5..88b61d57600 100644 --- a/gcc/config/aarch64/aarch64.opt +++ b/gcc/config/aarch64/aarch64.opt @@ -138,6 +138,26 @@ mabi= Target RejectNegative Joined Enum(aarch64_abi) Var(aarch64_abi) Init(AARCH64_ABI_DEFAULT) Generate code that conforms to the specified ABI. +mindirect-branch= +Target Report RejectNegative Joined Enum(indirect_branch) Var(aarch64_indirect_branch) Init(indirect_branch_keep) +Insert return thunk before br and blr. + +Enum +Name(indirect_branch) Type(enum indirect_branch) +Known indirect branch choices (for use with the -mindirect-branch= options): + +EnumValue +Enum(indirect_branch) String(keep) Value(indirect_branch_keep) + +EnumValue +Enum(indirect_branch) String(thunk) Value(indirect_branch_thunk) + +EnumValue +Enum(indirect_branch) String(thunk-inline) Value(indirect_branch_thunk_inline) + +EnumValue +Enum(indirect_branch) String(thunk-extern) Value(indirect_branch_thunk_extern) + moverride= Target RejectNegative ToLower Joined Var(aarch64_override_tune_string) -moverride=<string> Power users only! Override CPU optimization parameters. diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 671b29702ea..b0d000b3380 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -721,7 +721,7 @@ Objective-C and Objective-C++ Dialects}. -moverride=@var{string} -mverbose-cost-dump @gol -mstack-protector-guard=@var{guard} -mstack-protector-guard-reg=@var{sysreg} @gol -mstack-protector-guard-offset=@var{offset} -mtrack-speculation @gol --moutline-atomics } +-moutline-atomics -mindirect-branch=@var{choice}} @emph{Adapteva Epiphany Options} @gccoptlist{-mhalf-reg-file -mprefer-short-insn-regs @gol @@ -18178,6 +18178,24 @@ hardware SVE vector lengths. The default is @samp{-msve-vector-bits=scalable}, which produces vector-length agnostic code. + +@item -mindirect-branch=@var{choice} +@opindex -mindirect-branch +Convert indirect branch-and-link-register and branch-register with @var{choice}. +The default is @samp{keep}, which keeps indirect branch-and-link-register and +branch-register instructions unmodified. +@samp{thunk} converts indirect branch-and-link-register/branch-register +instructions to a branch-and-link/branch to a function containing a retpoline +(to stop speculative execution) followed by a branch-register to the target. +@samp{thunk-inline} similar to @samp{thunk}, but inlines the retpoline +before the branch-and-link-register/branch-register instruction. +@samp{thunk-extern} similar to @samp{thunk}, but does not insert the functions +containing the retpoline. When using this option, these functions need to be +provided in a separate object file. The retpoline functions exist for each +register and are named __aarch64_indirect_thunk_xN (N being the register +number). You can control this behavior for a specific function by using the +function attribute @code{indirect_branch}. @xref{Function Attributes}. + @end table @subsubsection @option{-march} and @option{-mcpu} Feature Modifiers diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-1.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-1.c new file mode 100644 index 00000000000..424057e2db7 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-1.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch; + +void +male_indirect_jump (long offset) +{ + dispatch(offset); +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x1, .LANCHOR0" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x1, \\\[x1, #:lo12:.LANCHOR0\\\]" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*__aarch64_indirect_thunk_x1" } } */ + +/* { dg-final { scan-assembler "str\[ \t\]*x30, \\\[sp, #-16\\\]!" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler "wfe" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler "adr\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler "ret" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x30, \\\[sp\\\], #16" } } */ +/* { dg-final { scan-assembler "br\[ \t\]*x1" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-2.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-2.c new file mode 100644 index 00000000000..325fe8ee875 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-2.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch[256]; + +void +male_indirect_jump (long offset) +{ + dispatch[offset](offset); +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x1, .LANCHOR0" } } */ +/* { dg-final { scan-assembler "add\[ \t\]*x1, x1, :lo12:.LANCHOR0" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x1, \\\[x1, x0, lsl 3\\\]" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*__aarch64_indirect_thunk_x1" } } */ + +/* { dg-final { scan-assembler "str\[ \t\]*x30, \\\[sp, #-16\\\]!" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler "wfe" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler "adr\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler "ret" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x30, \\\[sp\\\], #16" } } */ +/* { dg-final { scan-assembler "br\[ \t\]*x1" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-3.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-3.c new file mode 100644 index 00000000000..17c0601060c --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-3.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch; + +int +male_indirect_jump (long offset) +{ + dispatch(offset); + return 0; +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x1, .LANCHOR0" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x1, \\\[x1, #:lo12:.LANCHOR0\\\]" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*__aarch64_indirect_thunk_x1" } } */ + +/* { dg-final { scan-assembler "str\[ \t\]*x30, \\\[sp, #-16\\\]!" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler "wfe" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler "adr\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler "ret" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x30, \\\[sp\\\], #16" } } */ +/* { dg-final { scan-assembler "br\[ \t\]*x1" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-4.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-4.c new file mode 100644 index 00000000000..42ae4322c04 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-4.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch[256]; + +int +male_indirect_jump (long offset) +{ + dispatch[offset](offset); + return 0; +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x1, .LANCHOR0" } } */ +/* { dg-final { scan-assembler "add\[ \t\]*x1, x1, :lo12:.LANCHOR0" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x1, \\\[x1, x0, lsl 3\\\]" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*__aarch64_indirect_thunk_x1" } } */ + +/* { dg-final { scan-assembler "str\[ \t\]*x30, \\\[sp, #-16\\\]!" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler "wfe" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler "adr\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler "ret" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x30, \\\[sp\\\], #16" } } */ +/* { dg-final { scan-assembler "br\[ \t\]*x1" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-5.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-5.c new file mode 100644 index 00000000000..e84350d51a1 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-5.c @@ -0,0 +1,25 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk" } */ + +extern void bar (void); + +void +foo (void) +{ + bar (); +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x0, _GLOBAL_OFFSET_TABLE_" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x16, \\\[x0, #:gotpage_lo15:bar\\\]" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*__aarch64_indirect_thunk_x16" } } */ + +/* { dg-final { scan-assembler "str\[ \t\]*x30, \\\[sp, #-16\\\]!" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler "wfe" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler "adr\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler "ret" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x30, \\\[sp\\\], #16" } } */ +/* { dg-final { scan-assembler "br\[ \t\]*x16" } } */ + +/* { dg-final { scan-assembler-not "__aarch64_indirect_thunk\n" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-6.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-6.c new file mode 100644 index 00000000000..4c21735dc3c --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-6.c @@ -0,0 +1,26 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk" } */ + +extern void bar (void); + +int +foo (void) +{ + bar (); + return 0; +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x0, _GLOBAL_OFFSET_TABLE_" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x0, \\\[x0, #:gotpage_lo15:bar\\\]" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*__aarch64_indirect_thunk_x0" } } */ + +/* { dg-final { scan-assembler "str\[ \t\]*x30, \\\[sp, #-16\\\]!" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler "wfe" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler "adr\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler "ret" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x30, \\\[sp\\\], #16" } } */ +/* { dg-final { scan-assembler "br\[ \t\]*x0" } } */ + +/* { dg-final { scan-assembler-not "__aarch64_indirect_thunk\n" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-1.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-1.c new file mode 100644 index 00000000000..92260b85ef2 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-1.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch; + +extern void male_indirect_jump (long) + __attribute__ ((indirect_branch("thunk"))); + +void +male_indirect_jump (long offset) +{ + dispatch(offset); +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x1, .LANCHOR0" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x1, \\\[x1, #:lo12:.LANCHOR0\\\]" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*__aarch64_indirect_thunk_x1" } } */ + +/* { dg-final { scan-assembler "str\[ \t\]*x30, \\\[sp, #-16\\\]!" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler "wfe" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler "adr\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler "ret" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x30, \\\[sp\\\], #16" } } */ +/* { dg-final { scan-assembler "br\[ \t\]*x1" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-2.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-2.c new file mode 100644 index 00000000000..89b3f8b310f --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-2.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch[256]; + +__attribute__ ((indirect_branch("thunk"))) +void +male_indirect_jump (long offset) +{ + dispatch[offset](offset); +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x1, .LANCHOR0" } } */ +/* { dg-final { scan-assembler "add\[ \t\]*x1, x1, :lo12:.LANCHOR0" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x1, \\\[x1, x0, lsl 3\\\]" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*__aarch64_indirect_thunk_x1" } } */ + +/* { dg-final { scan-assembler "str\[ \t\]*x30, \\\[sp, #-16\\\]!" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler "wfe" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler "adr\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler "ret" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x30, \\\[sp\\\], #16" } } */ +/* { dg-final { scan-assembler "br\[ \t\]*x1" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-3.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-3.c new file mode 100644 index 00000000000..47f5e1a8fcc --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-3.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch; +extern int male_indirect_jump (long) + __attribute__ ((indirect_branch("thunk-inline"))); + +int +male_indirect_jump (long offset) +{ + dispatch(offset); + return 0; +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x1, .LANCHOR0" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x1, \\\[x1, #:lo12:.LANCHOR0\\\]" } } */ +/* { dg-final { scan-assembler "str\[ \t\]*x30, \\\[sp, #-16\\\]!" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler "wfe" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler "adr\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler "ret" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x30, \\\[sp\\\], #16" } } */ +/* { dg-final { scan-assembler "blr\[ \t\]*x1" } } */ + +/* { dg-final { scan-assembler-not "__aarch64_indirect_thunk" } } */ + diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-4.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-4.c new file mode 100644 index 00000000000..35d640e36e4 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-4.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch[256]; + +__attribute__ ((indirect_branch("thunk-inline"))) +int +male_indirect_jump (long offset) +{ + dispatch[offset](offset); + return 0; +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x1, .LANCHOR0" } } */ +/* { dg-final { scan-assembler "add\[ \t\]*x1, x1, :lo12:.LANCHOR0" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x1, \\\[x1, x0, lsl 3\\\]" } } */ +/* { dg-final { scan-assembler "str\[ \t\]*x30, \\\[sp, #-16\\\]!" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler "wfe" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler "adr\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler "ret" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x30, \\\[sp\\\], #16" } } */ +/* { dg-final { scan-assembler "blr\[ \t\]*x1" } } */ + +/* { dg-final { scan-assembler-not "__aarch64_indirect_thunk" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-5.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-5.c new file mode 100644 index 00000000000..5dd9bf44d2b --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-5.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch; +extern int male_indirect_jump (long) + __attribute__ ((indirect_branch("thunk-extern"))); + +int +male_indirect_jump (long offset) +{ + dispatch(offset); + return 0; +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x1, .LANCHOR0" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x1, \\\[x1, #:lo12:.LANCHOR0\\\]" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*__aarch64_indirect_thunk_x1" } } */ + +/* { dg-final { scan-assembler-not "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler-not "wfe" } } */ +/* { dg-final { scan-assembler-not "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler-not "adr\[ \t\]*x30, .LIND2" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-6.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-6.c new file mode 100644 index 00000000000..5179a55dafd --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-attr-6.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch[256]; + +__attribute__ ((indirect_branch("thunk-extern"))) +int +male_indirect_jump (long offset) +{ + dispatch[offset](offset); + return 0; +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x1, .LANCHOR0" } } */ +/* { dg-final { scan-assembler "add\[ \t\]*x1, x1, :lo12:.LANCHOR0" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x1, \\\[x1, x0, lsl 3\\\]" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*__aarch64_indirect_thunk_x1" } } */ + +/* { dg-final { scan-assembler-not "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler-not "wfe" } } */ +/* { dg-final { scan-assembler-not "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler-not "adr\[ \t\]*x30, .LIND2" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-1.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-1.c new file mode 100644 index 00000000000..931d2136407 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-1.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch; + +void +male_indirect_jump (long offset) +{ + dispatch(offset); +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x1, .LANCHOR0" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x1, \\\[x1, #:lo12:.LANCHOR0\\\]" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*__aarch64_indirect_thunk_x1" } } */ + +/* { dg-final { scan-assembler-not "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler-not "wfe" } } */ +/* { dg-final { scan-assembler-not "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler-not "adrp\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler-not "add\[ \t\]*x30, x30, :lo12:.LIND2" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-2.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-2.c new file mode 100644 index 00000000000..93aaec3d624 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-2.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch[256]; + +void +male_indirect_jump (long offset) +{ + dispatch[offset](offset); +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x1, .LANCHOR0" } } */ +/* { dg-final { scan-assembler "add\[ \t\]*x1, x1, :lo12:.LANCHOR0" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x1, \\\[x1, x0, lsl 3\\\]" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*__aarch64_indirect_thunk_x1" } } */ + +/* { dg-final { scan-assembler-not "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler-not "wfe" } } */ +/* { dg-final { scan-assembler-not "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler-not "adrp\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler-not "add\[ \t\]*x30, x30, :lo12:.LIND2" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-3.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-3.c new file mode 100644 index 00000000000..66a1e80320e --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-3.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch; + +int +male_indirect_jump (long offset) +{ + dispatch(offset); + return 0; +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x1, .LANCHOR0" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x1, \\\[x1, #:lo12:.LANCHOR0\\\]" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*__aarch64_indirect_thunk_x1" } } */ + +/* { dg-final { scan-assembler-not "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler-not "wfe" } } */ +/* { dg-final { scan-assembler-not "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler-not "adrp\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler-not "add\[ \t\]*x30, x30, :lo12:.LIND2" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-4.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-4.c new file mode 100644 index 00000000000..5a26bb21e57 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-4.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch[256]; + +int +male_indirect_jump (long offset) +{ + dispatch[offset](offset); + return 0; +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x1, .LANCHOR0" } } */ +/* { dg-final { scan-assembler "add\[ \t\]*x1, x1, :lo12:.LANCHOR0" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x1, \\\[x1, x0, lsl 3\\\]" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*__aarch64_indirect_thunk_x1" } } */ + +/* { dg-final { scan-assembler-not "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler-not "wfe" } } */ +/* { dg-final { scan-assembler-not "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler-not "adrp\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler-not "add\[ \t\]*x30, x30, :lo12:.LIND2" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-5.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-5.c new file mode 100644 index 00000000000..6a3288e001f --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-5.c @@ -0,0 +1,20 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk-extern" } */ + +extern void bar (void); + +void +foo (void) +{ + bar (); +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x0, _GLOBAL_OFFSET_TABLE_" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x16, \\\[x0, #:gotpage_lo15:bar\\\]" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*__aarch64_indirect_thunk_x16" } } */ + +/* { dg-final { scan-assembler-not "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler-not "wfe" } } */ +/* { dg-final { scan-assembler-not "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler-not "adrp\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler-not "add\[ \t\]*x30, x30, :lo12:.LIND2" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-6.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-6.c new file mode 100644 index 00000000000..635b53b35b9 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-extern-6.c @@ -0,0 +1,21 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk-extern" } */ + +extern void bar (void); + +int +foo (void) +{ + bar (); + return 0; +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x0, _GLOBAL_OFFSET_TABLE_" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x0, \\\[x0, #:gotpage_lo15:bar\\\]" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*__aarch64_indirect_thunk_x0" } } */ + +/* { dg-final { scan-assembler-not "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler-not "wfe" } } */ +/* { dg-final { scan-assembler-not "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler-not "adrp\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler-not "add\[ \t\]*x30, x30, :lo12:.LIND2" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-1.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-1.c new file mode 100644 index 00000000000..4ed67ca19a1 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-1.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch; + +void +male_indirect_jump (long offset) +{ + dispatch(offset); +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x1, .LANCHOR0" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x1, \\\[x16, #:lo12:.LANCHOR0\\\]" } } */ +/* { dg-final { scan-assembler "mov\[ \t\]*x16, x1" } } */ +/* { dg-final { scan-assembler "str\[ \t\]*x30, \\\[sp, #-16\\\]!" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler "wfe" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler "adr\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler "ret" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x30, \\\[sp\\\], #16" } } */ +/* { dg-final { scan-assembler "br\[ \t\]*x16" } } */ + +/* { dg-final { scan-assembler-not "__aarch64_indirect_thunk" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-2.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-2.c new file mode 100644 index 00000000000..059f73b7129 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-2.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch[256]; + +void +male_indirect_jump (long offset) +{ + dispatch[offset](offset); +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x1, .LANCHOR0" } } */ +/* { dg-final { scan-assembler "add\[ \t\]*x1, x1, :lo12:.LANCHOR0" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x1, \\\[x1, x0, lsl 3\\\]" } } */ +/* { dg-final { scan-assembler "str\[ \t\]*x30, \\\[sp, #-16\\\]!" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler "wfe" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler "adr\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler "ret" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x30, \\\[sp\\\], #16" } } */ +/* { dg-final { scan-assembler "br\[ \t\]*x1" } } */ + +/* { dg-final { scan-assembler-not "__aarch64_indirect_thunk" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-3.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-3.c new file mode 100644 index 00000000000..81c60b7ef65 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-3.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch; + +int +male_indirect_jump (long offset) +{ + dispatch(offset); + return 0; +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x1, .LANCHOR0" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x1, \\\[x1, #:lo12:.LANCHOR0\\\]" } } */ +/* { dg-final { scan-assembler "str\[ \t\]*x30, \\\[sp, #-16\\\]!" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler "wfe" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler "adr\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler "ret" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x30, \\\[sp\\\], #16" } } */ +/* { dg-final { scan-assembler "blr\[ \t\]*x1" } } */ + +/* { dg-final { scan-assembler-not "__aarch64_indirect_thunk" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-4.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-4.c new file mode 100644 index 00000000000..ff1e3da0afe --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-4.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch[256]; + +int +male_indirect_jump (long offset) +{ + dispatch[offset](offset); + return 0; +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x1, .LANCHOR0" } } */ +/* { dg-final { scan-assembler "add\[ \t\]*x1, x1, :lo12:.LANCHOR0" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x1, \\\[x1, x0, lsl 3\\\]" } } */ +/* { dg-final { scan-assembler "str\[ \t\]*x30, \\\[sp, #-16\\\]!" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler "wfe" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler "adr\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler "ret" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x30, \\\[sp\\\], #16" } } */ +/* { dg-final { scan-assembler "blr\[ \t\]*x1" } } */ + +/* { dg-final { scan-assembler-not "__aarch64_indirect_thunk" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-5.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-5.c new file mode 100644 index 00000000000..05c8093d7ff --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-5.c @@ -0,0 +1,23 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk-inline" } */ + +extern void bar (void); + +void +foo (void) +{ + bar (); +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x0, _GLOBAL_OFFSET_TABLE_" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x16, \\\[x0, #:gotpage_lo15:bar\\\]" } } */ +/* { dg-final { scan-assembler "str\[ \t\]*x30, \\\[sp, #-16\\\]!" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler "wfe" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler "adr\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler "ret" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x30, \\\[sp\\\], #16" } } */ +/* { dg-final { scan-assembler "br\[ \t\]*x16" } } */ + +/* { dg-final { scan-assembler-not "__aarch64_indirect_thunk\n" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-6.c b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-6.c new file mode 100644 index 00000000000..9cedefadd8d --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/indirect-thunk-inline-6.c @@ -0,0 +1,24 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk-inline" } */ + +extern void bar (void); + +int +foo (void) +{ + bar (); + return 0; +} + +/* { dg-final { scan-assembler "adrp\[ \t\]*x0, _GLOBAL_OFFSET_TABLE_" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x0, \\\[x0, #:gotpage_lo15:bar\\\]" } } */ +/* { dg-final { scan-assembler "str\[ \t\]*x30, \\\[sp, #-16\\\]!" } } */ +/* { dg-final { scan-assembler "bl\[ \t\]*\.LIND1" } } */ +/* { dg-final { scan-assembler "wfe" } } */ +/* { dg-final { scan-assembler "b\[ \t\]*\.LIND0" } } */ +/* { dg-final { scan-assembler "adr\[ \t\]*x30, .LIND2" } } */ +/* { dg-final { scan-assembler "ret" } } */ +/* { dg-final { scan-assembler "ldr\[ \t\]*x30, \\\[sp\\\], #16" } } */ +/* { dg-final { scan-assembler "blr\[ \t\]*x0" } } */ + +/* { dg-final { scan-assembler-not "__aarch64_indirect_thunk\n" } } */ -- 2.29.2