1 commit 9005adea32ef0cc14b3ef7ceacf5b67bf0862194
2 Author: H.J. Lu <hjl.tools@gmail.com>
3 Date: Mon Nov 6 09:11:08 2017 -0800
5 i386: Move struct ix86_frame to machine_function
7 Make ix86_frame available to i386 code generation.
9 * config/i386/i386.c (ix86_frame): Moved to ...
10 * config/i386/i386.h (ix86_frame): Here.
11 (machine_function): Add frame.
12 * config/i386/i386.c (ix86_compute_frame_layout): Repace the
13 frame argument with &cfun->machine->frame.
14 (ix86_can_use_return_insn_p): Don't pass &frame to
15 ix86_compute_frame_layout. Copy frame from cfun->machine->frame.
16 (ix86_can_eliminate): Likewise.
17 (ix86_expand_prologue): Likewise.
18 (ix86_expand_epilogue): Likewise.
19 (ix86_expand_split_stack_prologue): Likewise.
21 diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
22 index 8a3782c0298..813337242d8 100644
23 --- a/gcc/config/i386/i386.c
24 +++ b/gcc/config/i386/i386.c
25 @@ -2444,53 +2444,6 @@ struct GTY(()) stack_local_entry {
26 struct stack_local_entry *next;
29 -/* Structure describing stack frame layout.
30 - Stack grows downward:
36 - saved static chain if ix86_static_chain_on_stack
38 - saved frame pointer if frame_pointer_needed
39 - <- HARD_FRAME_POINTER
45 - <- sse_regs_save_offset
48 - [va_arg registers] |
52 - [padding2] | = to_allocate
61 - int outgoing_arguments_size;
63 - /* The offsets relative to ARG_POINTER. */
64 - HOST_WIDE_INT frame_pointer_offset;
65 - HOST_WIDE_INT hard_frame_pointer_offset;
66 - HOST_WIDE_INT stack_pointer_offset;
67 - HOST_WIDE_INT hfp_save_offset;
68 - HOST_WIDE_INT reg_save_offset;
69 - HOST_WIDE_INT sse_reg_save_offset;
71 - /* When save_regs_using_mov is set, emit prologue using
72 - move instead of push instructions. */
73 - bool save_regs_using_mov;
76 /* Which cpu are we scheduling for. */
77 enum attr_cpu ix86_schedule;
79 @@ -2582,7 +2535,7 @@ static unsigned int ix86_function_arg_boundary (machine_mode,
81 static rtx ix86_static_chain (const_tree, bool);
82 static int ix86_function_regparm (const_tree, const_tree);
83 -static void ix86_compute_frame_layout (struct ix86_frame *);
84 +static void ix86_compute_frame_layout (void);
85 static bool ix86_expand_vector_init_one_nonzero (bool, machine_mode,
87 static void ix86_add_new_builtins (HOST_WIDE_INT, HOST_WIDE_INT);
88 @@ -11903,7 +11856,8 @@ ix86_can_use_return_insn_p (void)
89 if (crtl->args.pops_args && crtl->args.size >= 32768)
92 - ix86_compute_frame_layout (&frame);
93 + ix86_compute_frame_layout ();
94 + frame = cfun->machine->frame;
95 return (frame.stack_pointer_offset == UNITS_PER_WORD
96 && (frame.nregs + frame.nsseregs) == 0);
98 @@ -12389,8 +12343,8 @@ ix86_can_eliminate (const int from, const int to)
100 ix86_initial_elimination_offset (int from, int to)
102 - struct ix86_frame frame;
103 - ix86_compute_frame_layout (&frame);
104 + ix86_compute_frame_layout ();
105 + struct ix86_frame frame = cfun->machine->frame;
107 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
108 return frame.hard_frame_pointer_offset;
109 @@ -12429,8 +12383,9 @@ ix86_builtin_setjmp_frame_value (void)
110 /* Fill structure ix86_frame about frame of currently computed function. */
113 -ix86_compute_frame_layout (struct ix86_frame *frame)
114 +ix86_compute_frame_layout (void)
116 + struct ix86_frame *frame = &cfun->machine->frame;
117 unsigned HOST_WIDE_INT stack_alignment_needed;
118 HOST_WIDE_INT offset;
119 unsigned HOST_WIDE_INT preferred_alignment;
120 @@ -13737,7 +13692,8 @@ ix86_expand_prologue (void)
121 m->fs.sp_offset = INCOMING_FRAME_SP_OFFSET;
122 m->fs.sp_valid = true;
124 - ix86_compute_frame_layout (&frame);
125 + ix86_compute_frame_layout ();
128 if (!TARGET_64BIT && ix86_function_ms_hook_prologue (current_function_decl))
130 @@ -14405,7 +14361,8 @@ ix86_expand_epilogue (int style)
133 ix86_finalize_stack_realign_flags ();
134 - ix86_compute_frame_layout (&frame);
135 + ix86_compute_frame_layout ();
138 m->fs.sp_valid = (!frame_pointer_needed
139 || (crtl->sp_is_unchanging
140 @@ -14915,7 +14872,8 @@ ix86_expand_split_stack_prologue (void)
141 gcc_assert (flag_split_stack && reload_completed);
143 ix86_finalize_stack_realign_flags ();
144 - ix86_compute_frame_layout (&frame);
145 + ix86_compute_frame_layout ();
146 + frame = cfun->machine->frame;
147 allocate = frame.stack_pointer_offset - INCOMING_FRAME_SP_OFFSET;
149 /* This is the label we will branch to if we have enough stack
150 diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
151 index 9c776dc5172..f9b91286a01 100644
152 --- a/gcc/config/i386/i386.h
153 +++ b/gcc/config/i386/i386.h
154 @@ -2451,9 +2451,56 @@ enum avx_u128_state
156 #define FASTCALL_PREFIX '@'
158 +#ifndef USED_FOR_TARGET
159 +/* Structure describing stack frame layout.
160 + Stack grows downward:
166 + saved static chain if ix86_static_chain_on_stack
168 + saved frame pointer if frame_pointer_needed
169 + <- HARD_FRAME_POINTER
171 + <- regs_save_offset
175 + <- sse_regs_save_offset
178 + [va_arg registers] |
182 + [padding2] | = to_allocate
185 +struct GTY(()) ix86_frame
191 + int outgoing_arguments_size;
193 + /* The offsets relative to ARG_POINTER. */
194 + HOST_WIDE_INT frame_pointer_offset;
195 + HOST_WIDE_INT hard_frame_pointer_offset;
196 + HOST_WIDE_INT stack_pointer_offset;
197 + HOST_WIDE_INT hfp_save_offset;
198 + HOST_WIDE_INT reg_save_offset;
199 + HOST_WIDE_INT sse_reg_save_offset;
201 + /* When save_regs_using_mov is set, emit prologue using
202 + move instead of push instructions. */
203 + bool save_regs_using_mov;
206 /* Machine specific frame tracking during prologue/epilogue generation. */
208 -#ifndef USED_FOR_TARGET
209 struct GTY(()) machine_frame_state
211 /* This pair tracks the currently active CFA as reg+offset. When reg
212 @@ -2512,6 +2559,9 @@ struct GTY(()) machine_function {
213 int varargs_fpr_size;
214 int optimize_mode_switching[MAX_386_ENTITIES];
216 + /* Cached initial frame layout for the current function. */
217 + struct ix86_frame frame;
219 /* Number of saved registers USE_FAST_PROLOGUE_EPILOGUE
220 has been computed for. */
221 int use_fast_prologue_epilogue_nregs;
222 @@ -2594,6 +2644,7 @@ struct GTY(()) machine_function {
223 #define ix86_current_function_calls_tls_descriptor \
224 (ix86_tls_descriptor_calls_expanded_in_cfun && df_regs_ever_live_p (SP_REG))
225 #define ix86_static_chain_on_stack (cfun->machine->static_chain_on_stack)
226 +#define ix86_red_zone_size (cfun->machine->frame.red_zone_size)
228 /* Control behavior of x86_file_start. */
229 #define X86_FILE_START_VERSION_DIRECTIVE false
231 commit b721283e4f4ff378a0bee2255b7d62163eab9f1e
232 Author: hjl <hjl@138bc75d-0d04-0410-961f-82ee72b054a4>
233 Date: Mon Nov 6 23:04:15 2017 +0000
235 i386: Use reference of struct ix86_frame to avoid copy
237 When there is no need to make a copy of ix86_frame, we can use reference
238 of struct ix86_frame to avoid copy.
242 * config/i386/i386.c (ix86_can_use_return_insn_p): Use reference
243 of struct ix86_frame.
244 (ix86_initial_elimination_offset): Likewise.
245 (ix86_expand_split_stack_prologue): Likewise.
247 git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@254480 138bc75d-0d04-0410-961f-82ee72b054a4
249 diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
250 index 813337242d8..397ef7cac26 100644
251 --- a/gcc/config/i386/i386.c
252 +++ b/gcc/config/i386/i386.c
253 @@ -11843,8 +11843,6 @@ symbolic_reference_mentioned_p (rtx op)
255 ix86_can_use_return_insn_p (void)
257 - struct ix86_frame frame;
259 /* Don't use `ret' instruction in interrupt handler. */
260 if (! reload_completed
261 || frame_pointer_needed
262 @@ -11857,7 +11855,7 @@ ix86_can_use_return_insn_p (void)
265 ix86_compute_frame_layout ();
266 - frame = cfun->machine->frame;
267 + struct ix86_frame &frame = cfun->machine->frame;
268 return (frame.stack_pointer_offset == UNITS_PER_WORD
269 && (frame.nregs + frame.nsseregs) == 0);
271 @@ -12344,7 +12342,7 @@ HOST_WIDE_INT
272 ix86_initial_elimination_offset (int from, int to)
274 ix86_compute_frame_layout ();
275 - struct ix86_frame frame = cfun->machine->frame;
276 + struct ix86_frame &frame = cfun->machine->frame;
278 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
279 return frame.hard_frame_pointer_offset;
280 @@ -14860,7 +14858,6 @@ static GTY(()) rtx split_stack_fn_large;
282 ix86_expand_split_stack_prologue (void)
284 - struct ix86_frame frame;
285 HOST_WIDE_INT allocate;
286 unsigned HOST_WIDE_INT args_size;
287 rtx_code_label *label;
288 @@ -14873,7 +14870,7 @@ ix86_expand_split_stack_prologue (void)
290 ix86_finalize_stack_realign_flags ();
291 ix86_compute_frame_layout ();
292 - frame = cfun->machine->frame;
293 + struct ix86_frame &frame = cfun->machine->frame;
294 allocate = frame.stack_pointer_offset - INCOMING_FRAME_SP_OFFSET;
296 /* This is the label we will branch to if we have enough stack
298 commit 3b89cfddd6276d3f13c210ed11ef638515392a04
299 Author: H.J. Lu <hjl.tools@gmail.com>
300 Date: Tue Nov 28 10:26:35 2017 -0800
302 i386: More use reference of struct ix86_frame to avoid copy
304 When there is no need to make a copy of ix86_frame, we can use reference
305 of struct ix86_frame to avoid copy.
307 * config/i386/i386.c (ix86_expand_prologue): Use reference of
309 (ix86_expand_epilogue): Likewise.
311 diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
312 index 397ef7cac26..986e6d79584 100644
313 --- a/gcc/config/i386/i386.c
314 +++ b/gcc/config/i386/i386.c
315 @@ -13667,7 +13667,6 @@ ix86_expand_prologue (void)
317 struct machine_function *m = cfun->machine;
319 - struct ix86_frame frame;
320 HOST_WIDE_INT allocate;
321 bool int_registers_saved;
322 bool sse_registers_saved;
323 @@ -13691,7 +13690,7 @@ ix86_expand_prologue (void)
324 m->fs.sp_valid = true;
326 ix86_compute_frame_layout ();
328 + struct ix86_frame &frame = cfun->machine->frame;
330 if (!TARGET_64BIT && ix86_function_ms_hook_prologue (current_function_decl))
332 @@ -14354,13 +14353,12 @@ ix86_expand_epilogue (int style)
334 struct machine_function *m = cfun->machine;
335 struct machine_frame_state frame_state_save = m->fs;
336 - struct ix86_frame frame;
337 bool restore_regs_via_mov;
340 ix86_finalize_stack_realign_flags ();
341 ix86_compute_frame_layout ();
343 + struct ix86_frame &frame = cfun->machine->frame;
345 m->fs.sp_valid = (!frame_pointer_needed
346 || (crtl->sp_is_unchanging
348 commit c89890ab6730606ecc8d3f5937fe352341f0f713
349 Author: H.J. Lu <hjl.tools@gmail.com>
350 Date: Sat Jan 6 22:29:55 2018 -0800
352 x86: Add -mindirect-branch=
354 Add -mindirect-branch= option to convert indirect call and jump to call
355 and return thunks. The default is 'keep', which keeps indirect call and
356 jump unmodified. 'thunk' converts indirect call and jump to call and
357 return thunk. 'thunk-inline' converts indirect call and jump to inlined
358 call and return thunk. 'thunk-extern' converts indirect call and jump to
359 external call and return thunk provided in a separate object file. You
360 can control this behavior for a specific function by using the function
361 attribute indirect_branch.
363 2 kinds of thunks are geneated. Memory thunk where the function address
364 is at the top of the stack:
366 __x86_indirect_thunk:
373 lea 8(%rsp), %rsp|lea 4(%esp), %esp
376 Indirect jmp via memory, "jmp mem", is converted to
379 jmp __x86_indirect_thunk
381 Indirect call via memory, "call mem", is converted to
386 jmp __x86_indirect_thunk
390 Register thunk where the function address is in a register, reg:
392 __x86_indirect_thunk_reg:
399 movq %reg, (%rsp)|movl %reg, (%esp)
402 where reg is one of (r|e)ax, (r|e)dx, (r|e)cx, (r|e)bx, (r|e)si, (r|e)di,
403 (r|e)bp, r8, r9, r10, r11, r12, r13, r14 and r15.
405 Indirect jmp via register, "jmp reg", is converted to
407 jmp __x86_indirect_thunk_reg
409 Indirect call via register, "call reg", is converted to
411 call __x86_indirect_thunk_reg
415 * config/i386/i386-opts.h (indirect_branch): New.
416 * config/i386/i386-protos.h (ix86_output_indirect_jmp): Likewise.
417 * config/i386/i386.c (ix86_using_red_zone): Disallow red-zone
418 with local indirect jump when converting indirect call and jump.
419 (ix86_set_indirect_branch_type): New.
420 (ix86_set_current_function): Call ix86_set_indirect_branch_type.
421 (indirectlabelno): New.
422 (indirect_thunk_needed): Likewise.
423 (indirect_thunk_bnd_needed): Likewise.
424 (indirect_thunks_used): Likewise.
425 (indirect_thunks_bnd_used): Likewise.
426 (INDIRECT_LABEL): Likewise.
427 (indirect_thunk_name): Likewise.
428 (output_indirect_thunk): Likewise.
429 (output_indirect_thunk_function): Likewise.
430 (ix86_output_indirect_branch): Likewise.
431 (ix86_output_indirect_jmp): Likewise.
432 (ix86_code_end): Call output_indirect_thunk_function if needed.
433 (ix86_output_call_insn): Call ix86_output_indirect_branch if
435 (ix86_handle_fndecl_attribute): Handle indirect_branch.
436 (ix86_attribute_table): Add indirect_branch.
437 * config/i386/i386.h (machine_function): Add indirect_branch_type
438 and has_local_indirect_jump.
439 * config/i386/i386.md (indirect_jump): Set has_local_indirect_jump
441 (tablejump): Likewise.
442 (*indirect_jump): Use ix86_output_indirect_jmp.
443 (*tablejump_1): Likewise.
444 (simple_return_indirect_internal): Likewise.
445 * config/i386/i386.opt (mindirect-branch=): New option.
446 (indirect_branch): New.
449 (thunk-inline): Likewise.
450 (thunk-extern): Likewise.
451 * doc/extend.texi: Document indirect_branch function attribute.
452 * doc/invoke.texi: Document -mindirect-branch= option.
456 * gcc.target/i386/indirect-thunk-1.c: New test.
457 * gcc.target/i386/indirect-thunk-2.c: Likewise.
458 * gcc.target/i386/indirect-thunk-3.c: Likewise.
459 * gcc.target/i386/indirect-thunk-4.c: Likewise.
460 * gcc.target/i386/indirect-thunk-5.c: Likewise.
461 * gcc.target/i386/indirect-thunk-6.c: Likewise.
462 * gcc.target/i386/indirect-thunk-7.c: Likewise.
463 * gcc.target/i386/indirect-thunk-attr-1.c: Likewise.
464 * gcc.target/i386/indirect-thunk-attr-2.c: Likewise.
465 * gcc.target/i386/indirect-thunk-attr-3.c: Likewise.
466 * gcc.target/i386/indirect-thunk-attr-4.c: Likewise.
467 * gcc.target/i386/indirect-thunk-attr-5.c: Likewise.
468 * gcc.target/i386/indirect-thunk-attr-6.c: Likewise.
469 * gcc.target/i386/indirect-thunk-attr-7.c: Likewise.
470 * gcc.target/i386/indirect-thunk-attr-8.c: Likewise.
471 * gcc.target/i386/indirect-thunk-bnd-1.c: Likewise.
472 * gcc.target/i386/indirect-thunk-bnd-2.c: Likewise.
473 * gcc.target/i386/indirect-thunk-bnd-3.c: Likewise.
474 * gcc.target/i386/indirect-thunk-bnd-4.c: Likewise.
475 * gcc.target/i386/indirect-thunk-extern-1.c: Likewise.
476 * gcc.target/i386/indirect-thunk-extern-2.c: Likewise.
477 * gcc.target/i386/indirect-thunk-extern-3.c: Likewise.
478 * gcc.target/i386/indirect-thunk-extern-4.c: Likewise.
479 * gcc.target/i386/indirect-thunk-extern-5.c: Likewise.
480 * gcc.target/i386/indirect-thunk-extern-6.c: Likewise.
481 * gcc.target/i386/indirect-thunk-extern-7.c: Likewise.
482 * gcc.target/i386/indirect-thunk-inline-1.c: Likewise.
483 * gcc.target/i386/indirect-thunk-inline-2.c: Likewise.
484 * gcc.target/i386/indirect-thunk-inline-3.c: Likewise.
485 * gcc.target/i386/indirect-thunk-inline-4.c: Likewise.
486 * gcc.target/i386/indirect-thunk-inline-5.c: Likewise.
487 * gcc.target/i386/indirect-thunk-inline-6.c: Likewise.
488 * gcc.target/i386/indirect-thunk-inline-7.c: Likewise.
490 diff --git a/gcc/config/i386/i386-opts.h b/gcc/config/i386/i386-opts.h
491 index 542cd0f3d67..efcdc3b1a14 100644
492 --- a/gcc/config/i386/i386-opts.h
493 +++ b/gcc/config/i386/i386-opts.h
494 @@ -99,4 +99,17 @@ enum stack_protector_guard {
495 SSP_GLOBAL /* global canary */
498 +/* This is used to mitigate variant #2 of the speculative execution
499 + vulnerabilities on x86 processors identified by CVE-2017-5715, aka
500 + Spectre. They convert indirect branches and function returns to
501 + call and return thunks to avoid speculative execution via indirect
502 + call, jmp and ret. */
503 +enum indirect_branch {
504 + indirect_branch_unset = 0,
505 + indirect_branch_keep,
506 + indirect_branch_thunk,
507 + indirect_branch_thunk_inline,
508 + indirect_branch_thunk_extern
512 diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h
513 index d2cccf14735..bcdd9872db9 100644
514 --- a/gcc/config/i386/i386-protos.h
515 +++ b/gcc/config/i386/i386-protos.h
516 @@ -313,6 +313,7 @@ extern enum attr_cpu ix86_schedule;
519 extern const char * ix86_output_call_insn (rtx_insn *insn, rtx call_op);
520 +extern const char * ix86_output_indirect_jmp (rtx call_op, bool ret_p);
521 extern bool ix86_operands_ok_for_move_multiple (rtx *operands, bool load,
522 enum machine_mode mode);
524 diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
525 index 986e6d79584..f1c58faa035 100644
526 --- a/gcc/config/i386/i386.c
527 +++ b/gcc/config/i386/i386.c
528 @@ -4212,12 +4212,23 @@ make_pass_stv (gcc::context *ctxt)
529 return new pass_stv (ctxt);
532 -/* Return true if a red-zone is in use. */
533 +/* Return true if a red-zone is in use. We can't use red-zone when
534 + there are local indirect jumps, like "indirect_jump" or "tablejump",
535 + which jumps to another place in the function, since "call" in the
536 + indirect thunk pushes the return address onto stack, destroying
539 + TODO: If we can reserve the first 2 WORDs, for PUSH and, another
540 + for CALL, in red-zone, we can allow local indirect jumps with
544 ix86_using_red_zone (void)
546 - return TARGET_RED_ZONE && !TARGET_64BIT_MS_ABI;
547 + return (TARGET_RED_ZONE
548 + && !TARGET_64BIT_MS_ABI
549 + && (!cfun->machine->has_local_indirect_jump
550 + || cfun->machine->indirect_branch_type == indirect_branch_keep));
553 /* Return a string that documents the current -m options. The caller is
554 @@ -7148,6 +7159,37 @@ ix86_set_func_type (tree fndecl)
558 +/* Set the indirect_branch_type field from the function FNDECL. */
561 +ix86_set_indirect_branch_type (tree fndecl)
563 + if (cfun->machine->indirect_branch_type == indirect_branch_unset)
565 + tree attr = lookup_attribute ("indirect_branch",
566 + DECL_ATTRIBUTES (fndecl));
569 + tree args = TREE_VALUE (attr);
571 + gcc_unreachable ();
572 + tree cst = TREE_VALUE (args);
573 + if (strcmp (TREE_STRING_POINTER (cst), "keep") == 0)
574 + cfun->machine->indirect_branch_type = indirect_branch_keep;
575 + else if (strcmp (TREE_STRING_POINTER (cst), "thunk") == 0)
576 + cfun->machine->indirect_branch_type = indirect_branch_thunk;
577 + else if (strcmp (TREE_STRING_POINTER (cst), "thunk-inline") == 0)
578 + cfun->machine->indirect_branch_type = indirect_branch_thunk_inline;
579 + else if (strcmp (TREE_STRING_POINTER (cst), "thunk-extern") == 0)
580 + cfun->machine->indirect_branch_type = indirect_branch_thunk_extern;
582 + gcc_unreachable ();
585 + cfun->machine->indirect_branch_type = ix86_indirect_branch;
589 /* Establish appropriate back-end context for processing the function
590 FNDECL. The argument might be NULL to indicate processing at top
591 level, outside of any function scope. */
592 @@ -7163,7 +7205,10 @@ ix86_set_current_function (tree fndecl)
593 one is extern inline and one isn't. Call ix86_set_func_type
594 to set the func_type field. */
595 if (fndecl != NULL_TREE)
596 - ix86_set_func_type (fndecl);
598 + ix86_set_func_type (fndecl);
599 + ix86_set_indirect_branch_type (fndecl);
604 @@ -7183,6 +7228,7 @@ ix86_set_current_function (tree fndecl)
607 ix86_set_func_type (fndecl);
608 + ix86_set_indirect_branch_type (fndecl);
610 tree new_tree = DECL_FUNCTION_SPECIFIC_TARGET (fndecl);
611 if (new_tree == NULL_TREE)
612 @@ -11920,6 +11966,220 @@ ix86_setup_frame_addresses (void)
616 +/* Label count for call and return thunks. It is used to make unique
617 + labels in call and return thunks. */
618 +static int indirectlabelno;
620 +/* True if call and return thunk functions are needed. */
621 +static bool indirect_thunk_needed = false;
622 +/* True if call and return thunk functions with the BND prefix are
624 +static bool indirect_thunk_bnd_needed = false;
626 +/* Bit masks of integer registers, which contain branch target, used
627 + by call and return thunks functions. */
628 +static int indirect_thunks_used;
629 +/* Bit masks of integer registers, which contain branch target, used
630 + by call and return thunks functions with the BND prefix. */
631 +static int indirect_thunks_bnd_used;
633 +#ifndef INDIRECT_LABEL
634 +# define INDIRECT_LABEL "LIND"
637 +/* Fills in the label name that should be used for the indirect thunk. */
640 +indirect_thunk_name (char name[32], int regno, bool need_bnd_p)
642 + if (USE_HIDDEN_LINKONCE)
644 + const char *bnd = need_bnd_p ? "_bnd" : "";
647 + const char *reg_prefix;
648 + if (LEGACY_INT_REGNO_P (regno))
649 + reg_prefix = TARGET_64BIT ? "r" : "e";
652 + sprintf (name, "__x86_indirect_thunk%s_%s%s",
653 + bnd, reg_prefix, reg_names[regno]);
656 + sprintf (name, "__x86_indirect_thunk%s", bnd);
663 + ASM_GENERATE_INTERNAL_LABEL (name, "LITBR", regno);
665 + ASM_GENERATE_INTERNAL_LABEL (name, "LITR", regno);
670 + ASM_GENERATE_INTERNAL_LABEL (name, "LITB", 0);
672 + ASM_GENERATE_INTERNAL_LABEL (name, "LIT", 0);
677 +/* Output a call and return thunk for indirect branch. If BND_P is
678 + true, the BND prefix is needed. If REGNO != -1, the function
679 + address is in REGNO and the call and return thunk looks like:
689 + Otherwise, the function address is on the top of stack and the
690 + call and return thunk looks like:
697 + lea WORD_SIZE(%sp), %sp
702 +output_indirect_thunk (bool need_bnd_p, int regno)
704 + char indirectlabel1[32];
705 + char indirectlabel2[32];
707 + ASM_GENERATE_INTERNAL_LABEL (indirectlabel1, INDIRECT_LABEL,
708 + indirectlabelno++);
709 + ASM_GENERATE_INTERNAL_LABEL (indirectlabel2, INDIRECT_LABEL,
710 + indirectlabelno++);
714 + fputs ("\tbnd call\t", asm_out_file);
716 + fputs ("\tcall\t", asm_out_file);
717 + assemble_name_raw (asm_out_file, indirectlabel2);
718 + fputc ('\n', asm_out_file);
720 + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel1);
722 + /* Pause + lfence. */
723 + fprintf (asm_out_file, "\tpause\n\tlfence\n");
726 + fputs ("\tjmp\t", asm_out_file);
727 + assemble_name_raw (asm_out_file, indirectlabel1);
728 + fputc ('\n', asm_out_file);
730 + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel2);
736 + xops[0] = gen_rtx_MEM (word_mode, stack_pointer_rtx);
737 + xops[1] = gen_rtx_REG (word_mode, regno);
738 + output_asm_insn ("mov\t{%1, %0|%0, %1}", xops);
744 + xops[0] = stack_pointer_rtx;
745 + xops[1] = plus_constant (Pmode, stack_pointer_rtx, UNITS_PER_WORD);
746 + output_asm_insn ("lea\t{%E1, %0|%0, %E1}", xops);
750 + fputs ("\tbnd ret\n", asm_out_file);
752 + fputs ("\tret\n", asm_out_file);
755 +/* Output a funtion with a call and return thunk for indirect branch.
756 + If BND_P is true, the BND prefix is needed. If REGNO != -1, the
757 + function address is in REGNO. Otherwise, the function address is
758 + on the top of stack. */
761 +output_indirect_thunk_function (bool need_bnd_p, int regno)
766 + /* Create __x86_indirect_thunk/__x86_indirect_thunk_bnd. */
767 + indirect_thunk_name (name, regno, need_bnd_p);
768 + decl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL,
769 + get_identifier (name),
770 + build_function_type_list (void_type_node, NULL_TREE));
771 + DECL_RESULT (decl) = build_decl (BUILTINS_LOCATION, RESULT_DECL,
772 + NULL_TREE, void_type_node);
773 + TREE_PUBLIC (decl) = 1;
774 + TREE_STATIC (decl) = 1;
775 + DECL_IGNORED_P (decl) = 1;
780 + switch_to_section (darwin_sections[picbase_thunk_section]);
781 + fputs ("\t.weak_definition\t", asm_out_file);
782 + assemble_name (asm_out_file, name);
783 + fputs ("\n\t.private_extern\t", asm_out_file);
784 + assemble_name (asm_out_file, name);
785 + putc ('\n', asm_out_file);
786 + ASM_OUTPUT_LABEL (asm_out_file, name);
787 + DECL_WEAK (decl) = 1;
791 + if (USE_HIDDEN_LINKONCE)
793 + cgraph_node::create (decl)->set_comdat_group (DECL_ASSEMBLER_NAME (decl));
795 + targetm.asm_out.unique_section (decl, 0);
796 + switch_to_section (get_named_section (decl, NULL, 0));
798 + targetm.asm_out.globalize_label (asm_out_file, name);
799 + fputs ("\t.hidden\t", asm_out_file);
800 + assemble_name (asm_out_file, name);
801 + putc ('\n', asm_out_file);
802 + ASM_DECLARE_FUNCTION_NAME (asm_out_file, name, decl);
806 + switch_to_section (text_section);
807 + ASM_OUTPUT_LABEL (asm_out_file, name);
810 + DECL_INITIAL (decl) = make_node (BLOCK);
811 + current_function_decl = decl;
812 + allocate_struct_function (decl, false);
813 + init_function_start (decl);
814 + /* We're about to hide the function body from callees of final_* by
815 + emitting it directly; tell them we're a thunk, if they care. */
816 + cfun->is_thunk = true;
817 + first_function_block_is_cold = false;
818 + /* Make sure unwind info is emitted for the thunk if needed. */
819 + final_start_function (emit_barrier (), asm_out_file, 1);
821 + output_indirect_thunk (need_bnd_p, regno);
823 + final_end_function ();
824 + init_insn_lengths ();
825 + free_after_compilation (cfun);
827 + current_function_decl = NULL;
830 static int pic_labels_used;
832 /* Fills in the label name that should be used for a pc thunk for
833 @@ -11946,11 +12206,32 @@ ix86_code_end (void)
837 + if (indirect_thunk_needed)
838 + output_indirect_thunk_function (false, -1);
839 + if (indirect_thunk_bnd_needed)
840 + output_indirect_thunk_function (true, -1);
842 + for (regno = FIRST_REX_INT_REG; regno <= LAST_REX_INT_REG; regno++)
844 + int i = regno - FIRST_REX_INT_REG + LAST_INT_REG + 1;
845 + if ((indirect_thunks_used & (1 << i)))
846 + output_indirect_thunk_function (false, regno);
848 + if ((indirect_thunks_bnd_used & (1 << i)))
849 + output_indirect_thunk_function (true, regno);
852 for (regno = AX_REG; regno <= SP_REG; regno++)
857 + if ((indirect_thunks_used & (1 << regno)))
858 + output_indirect_thunk_function (false, regno);
860 + if ((indirect_thunks_bnd_used & (1 << regno)))
861 + output_indirect_thunk_function (true, regno);
863 if (!(pic_labels_used & (1 << regno)))
866 @@ -28446,12 +28727,292 @@ ix86_nopic_noplt_attribute_p (rtx call_op)
870 +/* Output indirect branch via a call and return thunk. CALL_OP is a
871 + register which contains the branch target. XASM is the assembly
872 + template for CALL_OP. Branch is a tail call if SIBCALL_P is true.
873 + A normal call is converted to:
875 + call __x86_indirect_thunk_reg
877 + and a tail call is converted to:
879 + jmp __x86_indirect_thunk_reg
883 +ix86_output_indirect_branch_via_reg (rtx call_op, bool sibcall_p)
885 + char thunk_name_buf[32];
887 + bool need_bnd_p = ix86_bnd_prefixed_insn_p (current_output_insn);
888 + int regno = REGNO (call_op);
890 + if (cfun->machine->indirect_branch_type
891 + != indirect_branch_thunk_inline)
893 + if (cfun->machine->indirect_branch_type == indirect_branch_thunk)
896 + if (i >= FIRST_REX_INT_REG)
897 + i -= (FIRST_REX_INT_REG - LAST_INT_REG - 1);
899 + indirect_thunks_bnd_used |= 1 << i;
901 + indirect_thunks_used |= 1 << i;
903 + indirect_thunk_name (thunk_name_buf, regno, need_bnd_p);
904 + thunk_name = thunk_name_buf;
911 + if (thunk_name != NULL)
914 + fprintf (asm_out_file, "\tbnd jmp\t%s\n", thunk_name);
916 + fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name);
919 + output_indirect_thunk (need_bnd_p, regno);
923 + if (thunk_name != NULL)
926 + fprintf (asm_out_file, "\tbnd call\t%s\n", thunk_name);
928 + fprintf (asm_out_file, "\tcall\t%s\n", thunk_name);
932 + char indirectlabel1[32];
933 + char indirectlabel2[32];
935 + ASM_GENERATE_INTERNAL_LABEL (indirectlabel1,
937 + indirectlabelno++);
938 + ASM_GENERATE_INTERNAL_LABEL (indirectlabel2,
940 + indirectlabelno++);
944 + fputs ("\tbnd jmp\t", asm_out_file);
946 + fputs ("\tjmp\t", asm_out_file);
947 + assemble_name_raw (asm_out_file, indirectlabel2);
948 + fputc ('\n', asm_out_file);
950 + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel1);
952 + if (thunk_name != NULL)
955 + fprintf (asm_out_file, "\tbnd jmp\t%s\n", thunk_name);
957 + fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name);
960 + output_indirect_thunk (need_bnd_p, regno);
962 + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel2);
966 + fputs ("\tbnd call\t", asm_out_file);
968 + fputs ("\tcall\t", asm_out_file);
969 + assemble_name_raw (asm_out_file, indirectlabel1);
970 + fputc ('\n', asm_out_file);
974 +/* Output indirect branch via a call and return thunk. CALL_OP is
975 + the branch target. XASM is the assembly template for CALL_OP.
976 + Branch is a tail call if SIBCALL_P is true. A normal call is
982 + jmp __x86_indirect_thunk
986 + and a tail call is converted to:
989 + jmp __x86_indirect_thunk
993 +ix86_output_indirect_branch_via_push (rtx call_op, const char *xasm,
996 + char thunk_name_buf[32];
999 + bool need_bnd_p = ix86_bnd_prefixed_insn_p (current_output_insn);
1002 + if (cfun->machine->indirect_branch_type
1003 + != indirect_branch_thunk_inline)
1005 + if (cfun->machine->indirect_branch_type == indirect_branch_thunk)
1008 + indirect_thunk_bnd_needed = true;
1010 + indirect_thunk_needed = true;
1012 + indirect_thunk_name (thunk_name_buf, regno, need_bnd_p);
1013 + thunk_name = thunk_name_buf;
1016 + thunk_name = NULL;
1018 + snprintf (push_buf, sizeof (push_buf), "push{%c}\t%s",
1019 + TARGET_64BIT ? 'q' : 'l', xasm);
1023 + output_asm_insn (push_buf, &call_op);
1024 + if (thunk_name != NULL)
1027 + fprintf (asm_out_file, "\tbnd jmp\t%s\n", thunk_name);
1029 + fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name);
1032 + output_indirect_thunk (need_bnd_p, regno);
1036 + char indirectlabel1[32];
1037 + char indirectlabel2[32];
1039 + ASM_GENERATE_INTERNAL_LABEL (indirectlabel1,
1041 + indirectlabelno++);
1042 + ASM_GENERATE_INTERNAL_LABEL (indirectlabel2,
1044 + indirectlabelno++);
1048 + fputs ("\tbnd jmp\t", asm_out_file);
1050 + fputs ("\tjmp\t", asm_out_file);
1051 + assemble_name_raw (asm_out_file, indirectlabel2);
1052 + fputc ('\n', asm_out_file);
1054 + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel1);
1056 + /* An external function may be called via GOT, instead of PLT. */
1057 + if (MEM_P (call_op))
1059 + struct ix86_address parts;
1060 + rtx addr = XEXP (call_op, 0);
1061 + if (ix86_decompose_address (addr, &parts)
1062 + && parts.base == stack_pointer_rtx)
1064 + /* Since call will adjust stack by -UNITS_PER_WORD,
1065 + we must convert "disp(stack, index, scale)" to
1066 + "disp+UNITS_PER_WORD(stack, index, scale)". */
1069 + addr = gen_rtx_MULT (Pmode, parts.index,
1070 + GEN_INT (parts.scale));
1071 + addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
1075 + addr = stack_pointer_rtx;
1078 + if (parts.disp != NULL_RTX)
1079 + disp = plus_constant (Pmode, parts.disp,
1082 + disp = GEN_INT (UNITS_PER_WORD);
1084 + addr = gen_rtx_PLUS (Pmode, addr, disp);
1085 + call_op = gen_rtx_MEM (GET_MODE (call_op), addr);
1089 + output_asm_insn (push_buf, &call_op);
1091 + if (thunk_name != NULL)
1094 + fprintf (asm_out_file, "\tbnd jmp\t%s\n", thunk_name);
1096 + fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name);
1099 + output_indirect_thunk (need_bnd_p, regno);
1101 + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel2);
1105 + fputs ("\tbnd call\t", asm_out_file);
1107 + fputs ("\tcall\t", asm_out_file);
1108 + assemble_name_raw (asm_out_file, indirectlabel1);
1109 + fputc ('\n', asm_out_file);
1113 +/* Output indirect branch via a call and return thunk. CALL_OP is
1114 + the branch target. XASM is the assembly template for CALL_OP.
1115 + Branch is a tail call if SIBCALL_P is true. */
1118 +ix86_output_indirect_branch (rtx call_op, const char *xasm,
1121 + if (REG_P (call_op))
1122 + ix86_output_indirect_branch_via_reg (call_op, sibcall_p);
1124 + ix86_output_indirect_branch_via_push (call_op, xasm, sibcall_p);
1126 +/* Output indirect jump. CALL_OP is the jump target. Jump is a
1127 + function return if RET_P is true. */
1130 +ix86_output_indirect_jmp (rtx call_op, bool ret_p)
1132 + if (cfun->machine->indirect_branch_type != indirect_branch_keep)
1134 + /* We can't have red-zone if this isn't a function return since
1135 + "call" in the indirect thunk pushes the return address onto
1136 + stack, destroying red-zone. */
1137 + if (!ret_p && ix86_red_zone_size != 0)
1138 + gcc_unreachable ();
1140 + ix86_output_indirect_branch (call_op, "%0", true);
1144 + return "%!jmp\t%A0";
1147 /* Output the assembly for a call instruction. */
1150 ix86_output_call_insn (rtx_insn *insn, rtx call_op)
1152 bool direct_p = constant_call_address_operand (call_op, VOIDmode);
1153 + bool output_indirect_p
1155 + && cfun->machine->indirect_branch_type != indirect_branch_keep);
1156 bool seh_nop_p = false;
1159 @@ -28461,10 +29022,21 @@ ix86_output_call_insn (rtx_insn *insn, rtx call_op)
1161 if (ix86_nopic_noplt_attribute_p (call_op))
1165 - xasm = "%!jmp\t{*%p0@GOTPCREL(%%rip)|[QWORD PTR %p0@GOTPCREL[rip]]}";
1167 + if (output_indirect_p)
1168 + xasm = "{%p0@GOTPCREL(%%rip)|[QWORD PTR %p0@GOTPCREL[rip]]}";
1170 + xasm = "%!jmp\t{*%p0@GOTPCREL(%%rip)|[QWORD PTR %p0@GOTPCREL[rip]]}";
1173 - xasm = "%!jmp\t{*%p0@GOT|[DWORD PTR %p0@GOT]}";
1175 + if (output_indirect_p)
1176 + xasm = "{%p0@GOT|[DWORD PTR %p0@GOT]}";
1178 + xasm = "%!jmp\t{*%p0@GOT|[DWORD PTR %p0@GOT]}";
1182 xasm = "%!jmp\t%P0";
1183 @@ -28474,9 +29046,17 @@ ix86_output_call_insn (rtx_insn *insn, rtx call_op)
1184 else if (TARGET_SEH)
1185 xasm = "%!rex.W jmp\t%A0";
1187 - xasm = "%!jmp\t%A0";
1189 + if (output_indirect_p)
1192 + xasm = "%!jmp\t%A0";
1195 - output_asm_insn (xasm, &call_op);
1196 + if (output_indirect_p && !direct_p)
1197 + ix86_output_indirect_branch (call_op, xasm, true);
1199 + output_asm_insn (xasm, &call_op);
1203 @@ -28514,18 +29094,37 @@ ix86_output_call_insn (rtx_insn *insn, rtx call_op)
1205 if (ix86_nopic_noplt_attribute_p (call_op))
1209 - xasm = "%!call\t{*%p0@GOTPCREL(%%rip)|[QWORD PTR %p0@GOTPCREL[rip]]}";
1211 + if (output_indirect_p)
1212 + xasm = "{%p0@GOTPCREL(%%rip)|[QWORD PTR %p0@GOTPCREL[rip]]}";
1214 + xasm = "%!call\t{*%p0@GOTPCREL(%%rip)|[QWORD PTR %p0@GOTPCREL[rip]]}";
1217 - xasm = "%!call\t{*%p0@GOT|[DWORD PTR %p0@GOT]}";
1219 + if (output_indirect_p)
1220 + xasm = "{%p0@GOT|[DWORD PTR %p0@GOT]}";
1222 + xasm = "%!call\t{*%p0@GOT|[DWORD PTR %p0@GOT]}";
1226 xasm = "%!call\t%P0";
1229 - xasm = "%!call\t%A0";
1231 + if (output_indirect_p)
1234 + xasm = "%!call\t%A0";
1237 - output_asm_insn (xasm, &call_op);
1238 + if (output_indirect_p && !direct_p)
1239 + ix86_output_indirect_branch (call_op, xasm, false);
1241 + output_asm_insn (xasm, &call_op);
1245 @@ -41444,7 +42043,7 @@ ix86_handle_struct_attribute (tree *node, tree name, tree, int,
1249 -ix86_handle_fndecl_attribute (tree *node, tree name, tree, int,
1250 +ix86_handle_fndecl_attribute (tree *node, tree name, tree args, int,
1253 if (TREE_CODE (*node) != FUNCTION_DECL)
1254 @@ -41453,6 +42052,29 @@ ix86_handle_fndecl_attribute (tree *node, tree name, tree, int,
1256 *no_add_attrs = true;
1259 + if (is_attribute_p ("indirect_branch", name))
1261 + tree cst = TREE_VALUE (args);
1262 + if (TREE_CODE (cst) != STRING_CST)
1264 + warning (OPT_Wattributes,
1265 + "%qE attribute requires a string constant argument",
1267 + *no_add_attrs = true;
1269 + else if (strcmp (TREE_STRING_POINTER (cst), "keep") != 0
1270 + && strcmp (TREE_STRING_POINTER (cst), "thunk") != 0
1271 + && strcmp (TREE_STRING_POINTER (cst), "thunk-inline") != 0
1272 + && strcmp (TREE_STRING_POINTER (cst), "thunk-extern") != 0)
1274 + warning (OPT_Wattributes,
1275 + "argument to %qE attribute is not "
1276 + "(keep|thunk|thunk-inline|thunk-extern)", name);
1277 + *no_add_attrs = true;
1284 @@ -45761,6 +46383,8 @@ static const struct attribute_spec ix86_attribute_table[] =
1285 ix86_handle_interrupt_attribute, false },
1286 { "no_caller_saved_registers", 0, 0, false, true, true,
1287 ix86_handle_no_caller_saved_registers_attribute, false },
1288 + { "indirect_branch", 1, 1, true, false, false,
1289 + ix86_handle_fndecl_attribute, false },
1292 { NULL, 0, 0, false, false, false, NULL, false }
1293 diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
1294 index f9b91286a01..9d2209e605b 100644
1295 --- a/gcc/config/i386/i386.h
1296 +++ b/gcc/config/i386/i386.h
1297 @@ -2609,6 +2609,13 @@ struct GTY(()) machine_function {
1298 /* Function type. */
1299 ENUM_BITFIELD(function_type) func_type : 2;
1301 + /* How to generate indirec branch. */
1302 + ENUM_BITFIELD(indirect_branch) indirect_branch_type : 3;
1304 + /* If true, the current function has local indirect jumps, like
1305 + "indirect_jump" or "tablejump". */
1306 + BOOL_BITFIELD has_local_indirect_jump : 1;
1308 /* If true, the current function is a function specified with
1309 the "interrupt" or "no_caller_saved_registers" attribute. */
1310 BOOL_BITFIELD no_caller_saved_registers : 1;
1311 diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
1312 index 0281bb5f06c..e32f2311065 100644
1313 --- a/gcc/config/i386/i386.md
1314 +++ b/gcc/config/i386/i386.md
1315 @@ -11625,13 +11625,18 @@
1318 operands[0] = convert_memory_address (word_mode, operands[0]);
1319 + cfun->machine->has_local_indirect_jump = true;
1322 (define_insn "*indirect_jump"
1323 [(set (pc) (match_operand:W 0 "indirect_branch_operand" "rBw"))]
1326 - [(set_attr "type" "ibr")
1327 + "* return ix86_output_indirect_jmp (operands[0], false);"
1328 + [(set (attr "type")
1329 + (if_then_else (match_test "(cfun->machine->indirect_branch_type
1330 + != indirect_branch_keep)")
1331 + (const_string "multi")
1332 + (const_string "ibr")))
1333 (set_attr "length_immediate" "0")
1334 (set_attr "maybe_prefix_bnd" "1")])
1336 @@ -11674,14 +11679,19 @@
1339 operands[0] = convert_memory_address (word_mode, operands[0]);
1340 + cfun->machine->has_local_indirect_jump = true;
1343 (define_insn "*tablejump_1"
1344 [(set (pc) (match_operand:W 0 "indirect_branch_operand" "rBw"))
1345 (use (label_ref (match_operand 1)))]
1348 - [(set_attr "type" "ibr")
1349 + "* return ix86_output_indirect_jmp (operands[0], false);"
1350 + [(set (attr "type")
1351 + (if_then_else (match_test "(cfun->machine->indirect_branch_type
1352 + != indirect_branch_keep)")
1353 + (const_string "multi")
1354 + (const_string "ibr")))
1355 (set_attr "length_immediate" "0")
1356 (set_attr "maybe_prefix_bnd" "1")])
1358 @@ -12352,8 +12362,12 @@
1360 (use (match_operand:SI 0 "register_operand" "r"))]
1363 - [(set_attr "type" "ibr")
1364 + "* return ix86_output_indirect_jmp (operands[0], true);"
1365 + [(set (attr "type")
1366 + (if_then_else (match_test "(cfun->machine->indirect_branch_type
1367 + != indirect_branch_keep)")
1368 + (const_string "multi")
1369 + (const_string "ibr")))
1370 (set_attr "length_immediate" "0")
1371 (set_attr "maybe_prefix_bnd" "1")])
1373 diff --git a/gcc/config/i386/i386.opt b/gcc/config/i386/i386.opt
1374 index 9384e29b1de..c076d9c70ab 100644
1375 --- a/gcc/config/i386/i386.opt
1376 +++ b/gcc/config/i386/i386.opt
1377 @@ -927,3 +927,23 @@ Attempt to avoid generating instruction sequences containing ret bytes.
1379 Target Report RejectNegative Mask(GENERAL_REGS_ONLY) Var(ix86_target_flags) Save
1380 Generate code which uses only the general registers.
1383 +Target Report RejectNegative Joined Enum(indirect_branch) Var(ix86_indirect_branch) Init(indirect_branch_keep)
1384 +Convert indirect call and jump to call and return thunks.
1387 +Name(indirect_branch) Type(enum indirect_branch)
1388 +Known indirect branch choices (for use with the -mindirect-branch= option):
1391 +Enum(indirect_branch) String(keep) Value(indirect_branch_keep)
1394 +Enum(indirect_branch) String(thunk) Value(indirect_branch_thunk)
1397 +Enum(indirect_branch) String(thunk-inline) Value(indirect_branch_thunk_inline)
1400 +Enum(indirect_branch) String(thunk-extern) Value(indirect_branch_thunk_extern)
1401 diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
1402 index ba309d01a9b..935381da6fa 100644
1403 --- a/gcc/doc/extend.texi
1404 +++ b/gcc/doc/extend.texi
1405 @@ -5540,6 +5540,16 @@ Specify which floating-point unit to use. You must specify the
1406 @code{target("fpmath=sse,387")} option as
1407 @code{target("fpmath=sse+387")} because the comma would separate
1410 +@item indirect_branch("@var{choice}")
1411 +@cindex @code{indirect_branch} function attribute, x86
1412 +On x86 targets, the @code{indirect_branch} attribute causes the compiler
1413 +to convert indirect call and jump with @var{choice}. @samp{keep}
1414 +keeps indirect call and jump unmodified. @samp{thunk} converts indirect
1415 +call and jump to call and return thunk. @samp{thunk-inline} converts
1416 +indirect call and jump to inlined call and return thunk.
1417 +@samp{thunk-extern} converts indirect call and jump to external call
1418 +and return thunk provided in a separate object file.
1421 On the x86, the inliner does not inline a
1422 diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
1423 index 7311c10a754..4979c8c939d 100644
1424 --- a/gcc/doc/invoke.texi
1425 +++ b/gcc/doc/invoke.texi
1426 @@ -1210,7 +1210,8 @@ See RS/6000 and PowerPC Options.
1427 -msse2avx -mfentry -mrecord-mcount -mnop-mcount -m8bit-idiv @gol
1428 -mavx256-split-unaligned-load -mavx256-split-unaligned-store @gol
1429 -malign-data=@var{type} -mstack-protector-guard=@var{guard} @gol
1430 --mmitigate-rop -mgeneral-regs-only}
1431 +-mmitigate-rop -mgeneral-regs-only @gol
1432 +-mindirect-branch=@var{choice}}
1434 @emph{x86 Windows Options}
1435 @gccoptlist{-mconsole -mcygwin -mno-cygwin -mdll @gol
1436 @@ -25686,6 +25687,17 @@ Generate code that uses only the general-purpose registers. This
1437 prevents the compiler from using floating-point, vector, mask and bound
1440 +@item -mindirect-branch=@var{choice}
1441 +@opindex -mindirect-branch
1442 +Convert indirect call and jump with @var{choice}. The default is
1443 +@samp{keep}, which keeps indirect call and jump unmodified.
1444 +@samp{thunk} converts indirect call and jump to call and return thunk.
1445 +@samp{thunk-inline} converts indirect call and jump to inlined call
1446 +and return thunk. @samp{thunk-extern} converts indirect call and jump
1447 +to external call and return thunk provided in a separate object file.
1448 +You can control this behavior for a specific function by using the
1449 +function attribute @code{indirect_branch}. @xref{Function Attributes}.
1453 These @samp{-m} switches are supported in addition to the above
1454 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c
1455 new file mode 100644
1456 index 00000000000..d983e1c3e26
1458 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c
1460 +/* { dg-do compile } */
1461 +/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
1463 +typedef void (*dispatch_t)(long offset);
1465 +dispatch_t dispatch;
1468 +male_indirect_jump (long offset)
1473 +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1474 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1475 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1476 +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1477 +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1478 +/* { dg-final { scan-assembler {\tpause} } } */
1479 +/* { dg-final { scan-assembler {\tlfence} } } */
1480 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c
1481 new file mode 100644
1482 index 00000000000..58f09b42d8a
1484 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c
1486 +/* { dg-do compile } */
1487 +/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
1489 +typedef void (*dispatch_t)(long offset);
1491 +dispatch_t dispatch[256];
1494 +male_indirect_jump (long offset)
1496 + dispatch[offset](offset);
1499 +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1500 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1501 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1502 +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1503 +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1504 +/* { dg-final { scan-assembler {\tpause} } } */
1505 +/* { dg-final { scan-assembler {\tlfence} } } */
1506 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c
1507 new file mode 100644
1508 index 00000000000..f20d35c19b6
1510 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c
1512 +/* { dg-do compile } */
1513 +/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
1515 +typedef void (*dispatch_t)(long offset);
1517 +dispatch_t dispatch;
1520 +male_indirect_jump (long offset)
1526 +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1527 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1528 +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1529 +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1530 +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1531 +/* { dg-final { scan-assembler {\tpause} } } */
1532 +/* { dg-final { scan-assembler {\tlfence} } } */
1533 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c
1534 new file mode 100644
1535 index 00000000000..0eff8fb658a
1537 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c
1539 +/* { dg-do compile } */
1540 +/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
1542 +typedef void (*dispatch_t)(long offset);
1544 +dispatch_t dispatch[256];
1547 +male_indirect_jump (long offset)
1549 + dispatch[offset](offset);
1553 +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1554 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1555 +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1556 +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1557 +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1558 +/* { dg-final { scan-assembler {\tpause} } } */
1559 +/* { dg-final { scan-assembler {\tlfence} } } */
1560 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c
1561 new file mode 100644
1562 index 00000000000..a25b20dd808
1564 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c
1566 +/* { dg-do compile { target *-*-linux* } } */
1567 +/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk" } */
1569 +extern void bar (void);
1577 +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */
1578 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" } } */
1579 +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1580 +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1581 +/* { dg-final { scan-assembler {\tpause} } } */
1582 +/* { dg-final { scan-assembler {\tlfence} } } */
1583 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c
1584 new file mode 100644
1585 index 00000000000..cff114a6c29
1587 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c
1589 +/* { dg-do compile { target *-*-linux* } } */
1590 +/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk" } */
1592 +extern void bar (void);
1601 +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */
1602 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" } } */
1603 +/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */
1604 +/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */
1605 +/* { dg-final { scan-assembler {\tpause} } } */
1606 +/* { dg-final { scan-assembler {\tlfence} } } */
1607 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c
1608 new file mode 100644
1609 index 00000000000..afdb6007986
1611 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c
1613 +/* { dg-do compile } */
1614 +/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
1650 +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { ! x32 } } } } */
1651 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1652 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1653 +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1654 +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1655 +/* { dg-final { scan-assembler {\tpause} } } */
1656 +/* { dg-final { scan-assembler {\tlfence} } } */
1657 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c
1658 new file mode 100644
1659 index 00000000000..d64d978b699
1661 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c
1663 +/* { dg-do compile } */
1664 +/* { dg-options "-O2 -fno-pic" } */
1666 +typedef void (*dispatch_t)(long offset);
1668 +dispatch_t dispatch;
1670 +extern void male_indirect_jump (long)
1671 + __attribute__ ((indirect_branch("thunk")));
1674 +male_indirect_jump (long offset)
1679 +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1680 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1681 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1682 +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1683 +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1684 +/* { dg-final { scan-assembler {\tpause} } } */
1685 +/* { dg-final { scan-assembler {\tlfence} } } */
1686 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c
1687 new file mode 100644
1688 index 00000000000..93067454d3d
1690 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c
1692 +/* { dg-do compile } */
1693 +/* { dg-options "-O2 -fno-pic" } */
1695 +typedef void (*dispatch_t)(long offset);
1697 +dispatch_t dispatch[256];
1699 +__attribute__ ((indirect_branch("thunk")))
1701 +male_indirect_jump (long offset)
1703 + dispatch[offset](offset);
1706 +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1707 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1708 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1709 +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1710 +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1711 +/* { dg-final { scan-assembler {\tpause} } } */
1712 +/* { dg-final { scan-assembler {\tlfence} } } */
1713 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c
1714 new file mode 100644
1715 index 00000000000..97744d65729
1717 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c
1719 +/* { dg-do compile } */
1720 +/* { dg-options "-O2 -fno-pic" } */
1722 +typedef void (*dispatch_t)(long offset);
1724 +dispatch_t dispatch;
1725 +extern int male_indirect_jump (long)
1726 + __attribute__ ((indirect_branch("thunk-inline")));
1729 +male_indirect_jump (long offset)
1735 +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1736 +/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */
1737 +/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */
1738 +/* { dg-final { scan-assembler {\tpause} } } */
1739 +/* { dg-final { scan-assembler {\tlfence} } } */
1740 +/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
1741 +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
1742 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c
1743 new file mode 100644
1744 index 00000000000..bfce3ea5cb2
1746 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c
1748 +/* { dg-do compile } */
1749 +/* { dg-options "-O2 -fno-pic" } */
1751 +typedef void (*dispatch_t)(long offset);
1753 +dispatch_t dispatch[256];
1755 +__attribute__ ((indirect_branch("thunk-inline")))
1757 +male_indirect_jump (long offset)
1759 + dispatch[offset](offset);
1763 +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1764 +/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */
1765 +/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */
1766 +/* { dg-final { scan-assembler {\tpause} } } */
1767 +/* { dg-final { scan-assembler {\tlfence} } } */
1768 +/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
1769 +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
1770 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c
1771 new file mode 100644
1772 index 00000000000..0833606046b
1774 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c
1776 +/* { dg-do compile } */
1777 +/* { dg-options "-O2 -fno-pic" } */
1779 +typedef void (*dispatch_t)(long offset);
1781 +dispatch_t dispatch;
1782 +extern int male_indirect_jump (long)
1783 + __attribute__ ((indirect_branch("thunk-extern")));
1786 +male_indirect_jump (long offset)
1792 +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1793 +/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
1794 +/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
1795 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1796 +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1797 +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
1798 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c
1799 new file mode 100644
1800 index 00000000000..2eba0fbd9b2
1802 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c
1804 +/* { dg-do compile } */
1805 +/* { dg-options "-O2 -fno-pic" } */
1807 +typedef void (*dispatch_t)(long offset);
1809 +dispatch_t dispatch[256];
1811 +__attribute__ ((indirect_branch("thunk-extern")))
1813 +male_indirect_jump (long offset)
1815 + dispatch[offset](offset);
1819 +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1820 +/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
1821 +/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
1822 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1823 +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1824 +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
1825 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c
1826 new file mode 100644
1827 index 00000000000..f58427eae11
1829 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c
1831 +/* { dg-do compile } */
1832 +/* { dg-options "-O2 -fno-pic" } */
1842 +__attribute__ ((indirect_branch("thunk-extern")))
1869 +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { ! x32 } } } } */
1870 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1871 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" } } */
1872 +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
1873 +/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
1874 +/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
1875 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c
1876 new file mode 100644
1877 index 00000000000..564ed39547c
1879 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c
1881 +/* { dg-do compile } */
1882 +/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
1892 +__attribute__ ((indirect_branch("keep")))
1919 +/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
1920 +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
1921 +/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
1922 +/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
1923 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c
1924 new file mode 100644
1925 index 00000000000..50fbee20a5a
1927 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c
1929 +/* { dg-do compile { target { ! x32 } } } */
1930 +/* { dg-options "-O2 -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
1932 +void (*dispatch) (char *);
1941 +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1942 +/* { dg-final { scan-assembler "pushq\[ \t\]%rax" { target x32 } } } */
1943 +/* { dg-final { scan-assembler "bnd jmp\[ \t\]*__x86_indirect_thunk_bnd" } } */
1944 +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1945 +/* { dg-final { scan-assembler "bnd call\[ \t\]*\.LIND" } } */
1946 +/* { dg-final { scan-assembler "bnd ret" } } */
1947 +/* { dg-final { scan-assembler {\tpause} } } */
1948 +/* { dg-final { scan-assembler {\tlfence} } } */
1949 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c
1950 new file mode 100644
1951 index 00000000000..2976e67adce
1953 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c
1955 +/* { dg-do compile { target { ! x32 } } } */
1956 +/* { dg-options "-O2 -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
1958 +void (*dispatch) (char *);
1968 +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1969 +/* { dg-final { scan-assembler "pushq\[ \t\]%rax" { target x32 } } } */
1970 +/* { dg-final { scan-assembler "bnd jmp\[ \t\]*__x86_indirect_thunk_bnd" } } */
1971 +/* { dg-final { scan-assembler "bnd jmp\[ \t\]*\.LIND" } } */
1972 +/* { dg-final { scan-assembler "bnd call\[ \t\]*\.LIND" } } */
1973 +/* { dg-final { scan-assembler "bnd ret" } } */
1974 +/* { dg-final { scan-assembler {\tpause} } } */
1975 +/* { dg-final { scan-assembler {\tlfence} } } */
1976 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c
1977 new file mode 100644
1978 index 00000000000..da4bc98ef23
1980 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c
1982 +/* { dg-do compile { target { *-*-linux* && { ! x32 } } } } */
1983 +/* { dg-options "-O2 -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fpic -fno-plt" } */
1994 +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */
1995 +/* { dg-final { scan-assembler "bnd jmp\[ \t\]*__x86_indirect_thunk_bnd" } } */
1996 +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1997 +/* { dg-final { scan-assembler "bnd call\[ \t\]*\.LIND" } } */
1998 +/* { dg-final { scan-assembler "bnd ret" } } */
1999 +/* { dg-final { scan-assembler {\tpause} } } */
2000 +/* { dg-final { scan-assembler {\tlfence} } } */
2001 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c
2002 new file mode 100644
2003 index 00000000000..c64d12ef989
2005 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c
2007 +/* { dg-do compile { target { *-*-linux* && { ! x32 } } } } */
2008 +/* { dg-options "-O2 -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fpic -fno-plt" } */
2020 +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */
2021 +/* { dg-final { scan-assembler "bnd jmp\[ \t\]*__x86_indirect_thunk" } } */
2022 +/* { dg-final { scan-assembler "bnd jmp\[ \t\]*\.LIND" } } */
2023 +/* { dg-final { scan-assembler-times "bnd call\[ \t\]*\.LIND" 2 } } */
2024 +/* { dg-final { scan-assembler "bnd ret" } } */
2025 +/* { dg-final { scan-assembler {\tpause} } } */
2026 +/* { dg-final { scan-assembler {\tlfence} } } */
2027 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c
2028 new file mode 100644
2029 index 00000000000..49f27b49465
2031 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c
2033 +/* { dg-do compile } */
2034 +/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */
2036 +typedef void (*dispatch_t)(long offset);
2038 +dispatch_t dispatch;
2041 +male_indirect_jump (long offset)
2046 +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
2047 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
2048 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
2049 +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
2050 +/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
2051 +/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
2052 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c
2053 new file mode 100644
2054 index 00000000000..a1e3eb6fc74
2056 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c
2058 +/* { dg-do compile } */
2059 +/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */
2061 +typedef void (*dispatch_t)(long offset);
2063 +dispatch_t dispatch[256];
2066 +male_indirect_jump (long offset)
2068 + dispatch[offset](offset);
2071 +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
2072 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
2073 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
2074 +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
2075 +/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
2076 +/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
2077 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c
2078 new file mode 100644
2079 index 00000000000..395634e7e5c
2081 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c
2083 +/* { dg-do compile } */
2084 +/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */
2086 +typedef void (*dispatch_t)(long offset);
2088 +dispatch_t dispatch;
2091 +male_indirect_jump (long offset)
2097 +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
2098 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
2099 +/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
2100 +/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
2101 +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
2102 +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
2103 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c
2104 new file mode 100644
2105 index 00000000000..fd3f63379a1
2107 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c
2109 +/* { dg-do compile } */
2110 +/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */
2112 +typedef void (*dispatch_t)(long offset);
2114 +dispatch_t dispatch[256];
2117 +male_indirect_jump (long offset)
2119 + dispatch[offset](offset);
2123 +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
2124 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
2125 +/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
2126 +/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
2127 +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
2128 +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
2129 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c
2130 new file mode 100644
2131 index 00000000000..ba2f92b6f34
2133 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c
2135 +/* { dg-do compile { target *-*-linux* } } */
2136 +/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk-extern" } */
2138 +extern void bar (void);
2146 +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */
2147 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" } } */
2148 +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
2149 +/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
2150 +/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
2151 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c
2152 new file mode 100644
2153 index 00000000000..0c5a2d472c6
2155 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c
2157 +/* { dg-do compile { target *-*-linux* } } */
2158 +/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk-extern" } */
2160 +extern void bar (void);
2169 +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */
2170 +/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 } } */
2171 +/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 } } */
2172 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" } } */
2173 +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
2174 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c
2175 new file mode 100644
2176 index 00000000000..665252327aa
2178 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c
2180 +/* { dg-do compile } */
2181 +/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */
2217 +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { ! x32 } } } } */
2218 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
2219 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
2220 +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
2221 +/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
2222 +/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
2223 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c
2224 new file mode 100644
2225 index 00000000000..68c0ff713b3
2227 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c
2229 +/* { dg-do compile } */
2230 +/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */
2232 +typedef void (*dispatch_t)(long offset);
2234 +dispatch_t dispatch;
2237 +male_indirect_jump (long offset)
2242 +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
2243 +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
2244 +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
2245 +/* { dg-final { scan-assembler {\tpause} } } */
2246 +/* { dg-final { scan-assembler {\tlfence} } } */
2247 +/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
2248 +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
2249 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c
2250 new file mode 100644
2251 index 00000000000..e2da1fcb683
2253 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c
2255 +/* { dg-do compile } */
2256 +/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */
2258 +typedef void (*dispatch_t)(long offset);
2260 +dispatch_t dispatch[256];
2263 +male_indirect_jump (long offset)
2265 + dispatch[offset](offset);
2268 +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
2269 +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
2270 +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
2271 +/* { dg-final { scan-assembler {\tpause} } } */
2272 +/* { dg-final { scan-assembler {\tlfence} } } */
2273 +/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
2274 +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
2275 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c
2276 new file mode 100644
2277 index 00000000000..244fec708d6
2279 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c
2281 +/* { dg-do compile } */
2282 +/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */
2284 +typedef void (*dispatch_t)(long offset);
2286 +dispatch_t dispatch;
2289 +male_indirect_jump (long offset)
2295 +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
2296 +/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */
2297 +/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */
2298 +/* { dg-final { scan-assembler-times {\tpause} 1 } } */
2299 +/* { dg-final { scan-assembler-times {\tlfence} 1 } } */
2300 +/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
2301 +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
2302 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c
2303 new file mode 100644
2304 index 00000000000..107ebe32f54
2306 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c
2308 +/* { dg-do compile } */
2309 +/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */
2311 +typedef void (*dispatch_t)(long offset);
2313 +dispatch_t dispatch[256];
2316 +male_indirect_jump (long offset)
2318 + dispatch[offset](offset);
2322 +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
2323 +/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */
2324 +/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */
2325 +/* { dg-final { scan-assembler-times {\tpause} 1 } } */
2326 +/* { dg-final { scan-assembler-times {\tlfence} 1 } } */
2327 +/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
2328 +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
2329 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c
2330 new file mode 100644
2331 index 00000000000..17b04ef2229
2333 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c
2335 +/* { dg-do compile { target *-*-linux* } } */
2336 +/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk-inline" } */
2338 +extern void bar (void);
2346 +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */
2347 +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
2348 +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
2349 +/* { dg-final { scan-assembler {\tpause} } } */
2350 +/* { dg-final { scan-assembler {\tlfence} } } */
2351 +/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
2352 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c
2353 new file mode 100644
2354 index 00000000000..d9eb11285aa
2356 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c
2358 +/* { dg-do compile { target *-*-linux* } } */
2359 +/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk-inline" } */
2361 +extern void bar (void);
2370 +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */
2371 +/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */
2372 +/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */
2373 +/* { dg-final { scan-assembler-times {\tpause} 1 } } */
2374 +/* { dg-final { scan-assembler-times {\tlfence} 1 } } */
2375 +/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
2376 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c
2377 new file mode 100644
2378 index 00000000000..d02b1dcb1b9
2380 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c
2382 +/* { dg-do compile } */
2383 +/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */
2419 +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { ! x32 } } } } */
2420 +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
2421 +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
2422 +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
2423 +/* { dg-final { scan-assembler {\tpause} } } */
2424 +/* { dg-final { scan-assembler {\tlfence} } } */
2425 +/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
2427 commit ad272ea92bdadd7f94bc1dafb35529959d3de1f0
2428 Author: H.J. Lu <hjl.tools@gmail.com>
2429 Date: Sat Jan 6 22:29:56 2018 -0800
2431 x86: Add -mfunction-return=
2433 Add -mfunction-return= option to convert function return to call and
2434 return thunks. The default is 'keep', which keeps function return
2435 unmodified. 'thunk' converts function return to call and return thunk.
2436 'thunk-inline' converts function return to inlined call and return thunk.
2437 'thunk-extern' converts function return to external call and return
2438 thunk provided in a separate object file. You can control this behavior
2439 for a specific function by using the function attribute function_return.
2441 Function return thunk is the same as memory thunk for -mindirect-branch=
2442 where the return address is at the top of the stack:
2451 lea 8(%rsp), %rsp|lea 4(%esp), %esp
2454 and function return becomes
2456 jmp __x86_return_thunk
2458 -mindirect-branch= tests are updated with -mfunction-return=keep to
2459 avoid false test failures when -mfunction-return=thunk is added to
2460 RUNTESTFLAGS for "make check".
2464 * config/i386/i386-protos.h (ix86_output_function_return): New.
2465 * config/i386/i386.c (ix86_set_indirect_branch_type): Also
2466 set function_return_type.
2467 (indirect_thunk_name): Add ret_p to indicate thunk for function
2469 (output_indirect_thunk_function): Pass false to
2470 indirect_thunk_name.
2471 (ix86_output_indirect_branch): Likewise.
2472 (output_indirect_thunk_function): Create alias for function
2473 return thunk if regno < 0.
2474 (ix86_output_function_return): New function.
2475 (ix86_handle_fndecl_attribute): Handle function_return.
2476 (ix86_attribute_table): Add function_return.
2477 * config/i386/i386.h (machine_function): Add
2478 function_return_type.
2479 * config/i386/i386.md (simple_return_internal): Use
2480 ix86_output_function_return.
2481 (simple_return_internal_long): Likewise.
2482 * config/i386/i386.opt (mfunction-return=): New option.
2483 (indirect_branch): Mention -mfunction-return=.
2484 * doc/extend.texi: Document function_return function attribute.
2485 * doc/invoke.texi: Document -mfunction-return= option.
2489 * gcc.target/i386/indirect-thunk-1.c (dg-options): Add
2490 -mfunction-return=keep.
2491 * gcc.target/i386/indirect-thunk-2.c: Likewise.
2492 * gcc.target/i386/indirect-thunk-3.c: Likewise.
2493 * gcc.target/i386/indirect-thunk-4.c: Likewise.
2494 * gcc.target/i386/indirect-thunk-5.c: Likewise.
2495 * gcc.target/i386/indirect-thunk-6.c: Likewise.
2496 * gcc.target/i386/indirect-thunk-7.c: Likewise.
2497 * gcc.target/i386/indirect-thunk-attr-1.c: Likewise.
2498 * gcc.target/i386/indirect-thunk-attr-2.c: Likewise.
2499 * gcc.target/i386/indirect-thunk-attr-3.c: Likewise.
2500 * gcc.target/i386/indirect-thunk-attr-4.c: Likewise.
2501 * gcc.target/i386/indirect-thunk-attr-5.c: Likewise.
2502 * gcc.target/i386/indirect-thunk-attr-6.c: Likewise.
2503 * gcc.target/i386/indirect-thunk-attr-7.c: Likewise.
2504 * gcc.target/i386/indirect-thunk-attr-8.c: Likewise.
2505 * gcc.target/i386/indirect-thunk-bnd-1.c: Likewise.
2506 * gcc.target/i386/indirect-thunk-bnd-2.c: Likewise.
2507 * gcc.target/i386/indirect-thunk-bnd-3.c: Likewise.
2508 * gcc.target/i386/indirect-thunk-bnd-4.c: Likewise.
2509 * gcc.target/i386/indirect-thunk-extern-1.c: Likewise.
2510 * gcc.target/i386/indirect-thunk-extern-2.c: Likewise.
2511 * gcc.target/i386/indirect-thunk-extern-3.c: Likewise.
2512 * gcc.target/i386/indirect-thunk-extern-4.c: Likewise.
2513 * gcc.target/i386/indirect-thunk-extern-5.c: Likewise.
2514 * gcc.target/i386/indirect-thunk-extern-6.c: Likewise.
2515 * gcc.target/i386/indirect-thunk-extern-7.c: Likewise.
2516 * gcc.target/i386/indirect-thunk-inline-1.c: Likewise.
2517 * gcc.target/i386/indirect-thunk-inline-2.c: Likewise.
2518 * gcc.target/i386/indirect-thunk-inline-3.c: Likewise.
2519 * gcc.target/i386/indirect-thunk-inline-4.c: Likewise.
2520 * gcc.target/i386/indirect-thunk-inline-5.c: Likewise.
2521 * gcc.target/i386/indirect-thunk-inline-6.c: Likewise.
2522 * gcc.target/i386/indirect-thunk-inline-7.c: Likewise.
2523 * gcc.target/i386/ret-thunk-1.c: New test.
2524 * gcc.target/i386/ret-thunk-10.c: Likewise.
2525 * gcc.target/i386/ret-thunk-11.c: Likewise.
2526 * gcc.target/i386/ret-thunk-12.c: Likewise.
2527 * gcc.target/i386/ret-thunk-13.c: Likewise.
2528 * gcc.target/i386/ret-thunk-14.c: Likewise.
2529 * gcc.target/i386/ret-thunk-15.c: Likewise.
2530 * gcc.target/i386/ret-thunk-16.c: Likewise.
2531 * gcc.target/i386/ret-thunk-2.c: Likewise.
2532 * gcc.target/i386/ret-thunk-3.c: Likewise.
2533 * gcc.target/i386/ret-thunk-4.c: Likewise.
2534 * gcc.target/i386/ret-thunk-5.c: Likewise.
2535 * gcc.target/i386/ret-thunk-6.c: Likewise.
2536 * gcc.target/i386/ret-thunk-7.c: Likewise.
2537 * gcc.target/i386/ret-thunk-8.c: Likewise.
2538 * gcc.target/i386/ret-thunk-9.c: Likewise.
2540 diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h
2541 index bcdd9872db9..42eece35766 100644
2542 --- a/gcc/config/i386/i386-protos.h
2543 +++ b/gcc/config/i386/i386-protos.h
2544 @@ -314,6 +314,7 @@ extern enum attr_cpu ix86_schedule;
2546 extern const char * ix86_output_call_insn (rtx_insn *insn, rtx call_op);
2547 extern const char * ix86_output_indirect_jmp (rtx call_op, bool ret_p);
2548 +extern const char * ix86_output_function_return (bool long_p);
2549 extern bool ix86_operands_ok_for_move_multiple (rtx *operands, bool load,
2550 enum machine_mode mode);
2552 diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
2553 index f1c58faa035..4bfe2fa8c1d 100644
2554 --- a/gcc/config/i386/i386.c
2555 +++ b/gcc/config/i386/i386.c
2556 @@ -7188,6 +7188,31 @@ ix86_set_indirect_branch_type (tree fndecl)
2558 cfun->machine->indirect_branch_type = ix86_indirect_branch;
2561 + if (cfun->machine->function_return_type == indirect_branch_unset)
2563 + tree attr = lookup_attribute ("function_return",
2564 + DECL_ATTRIBUTES (fndecl));
2567 + tree args = TREE_VALUE (attr);
2569 + gcc_unreachable ();
2570 + tree cst = TREE_VALUE (args);
2571 + if (strcmp (TREE_STRING_POINTER (cst), "keep") == 0)
2572 + cfun->machine->function_return_type = indirect_branch_keep;
2573 + else if (strcmp (TREE_STRING_POINTER (cst), "thunk") == 0)
2574 + cfun->machine->function_return_type = indirect_branch_thunk;
2575 + else if (strcmp (TREE_STRING_POINTER (cst), "thunk-inline") == 0)
2576 + cfun->machine->function_return_type = indirect_branch_thunk_inline;
2577 + else if (strcmp (TREE_STRING_POINTER (cst), "thunk-extern") == 0)
2578 + cfun->machine->function_return_type = indirect_branch_thunk_extern;
2580 + gcc_unreachable ();
2583 + cfun->machine->function_return_type = ix86_function_return;
2587 /* Establish appropriate back-end context for processing the function
2588 @@ -11990,8 +12015,12 @@ static int indirect_thunks_bnd_used;
2589 /* Fills in the label name that should be used for the indirect thunk. */
2592 -indirect_thunk_name (char name[32], int regno, bool need_bnd_p)
2593 +indirect_thunk_name (char name[32], int regno, bool need_bnd_p,
2596 + if (regno >= 0 && ret_p)
2597 + gcc_unreachable ();
2599 if (USE_HIDDEN_LINKONCE)
2601 const char *bnd = need_bnd_p ? "_bnd" : "";
2602 @@ -12006,7 +12035,10 @@ indirect_thunk_name (char name[32], int regno, bool need_bnd_p)
2603 bnd, reg_prefix, reg_names[regno]);
2606 - sprintf (name, "__x86_indirect_thunk%s", bnd);
2608 + const char *ret = ret_p ? "return" : "indirect";
2609 + sprintf (name, "__x86_%s_thunk%s", ret, bnd);
2614 @@ -12019,10 +12051,20 @@ indirect_thunk_name (char name[32], int regno, bool need_bnd_p)
2619 - ASM_GENERATE_INTERNAL_LABEL (name, "LITB", 0);
2623 + ASM_GENERATE_INTERNAL_LABEL (name, "LRTB", 0);
2625 + ASM_GENERATE_INTERNAL_LABEL (name, "LRT", 0);
2628 - ASM_GENERATE_INTERNAL_LABEL (name, "LIT", 0);
2631 + ASM_GENERATE_INTERNAL_LABEL (name, "LITB", 0);
2633 + ASM_GENERATE_INTERNAL_LABEL (name, "LIT", 0);
2638 @@ -12117,7 +12159,7 @@ output_indirect_thunk_function (bool need_bnd_p, int regno)
2641 /* Create __x86_indirect_thunk/__x86_indirect_thunk_bnd. */
2642 - indirect_thunk_name (name, regno, need_bnd_p);
2643 + indirect_thunk_name (name, regno, need_bnd_p, false);
2644 decl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL,
2645 get_identifier (name),
2646 build_function_type_list (void_type_node, NULL_TREE));
2647 @@ -12160,6 +12202,35 @@ output_indirect_thunk_function (bool need_bnd_p, int regno)
2648 ASM_OUTPUT_LABEL (asm_out_file, name);
2653 + /* Create alias for __x86.return_thunk/__x86.return_thunk_bnd. */
2656 + indirect_thunk_name (alias, regno, need_bnd_p, true);
2657 + ASM_OUTPUT_DEF (asm_out_file, alias, name);
2661 + fputs ("\t.weak_definition\t", asm_out_file);
2662 + assemble_name (asm_out_file, alias);
2663 + fputs ("\n\t.private_extern\t", asm_out_file);
2664 + assemble_name (asm_out_file, alias);
2665 + putc ('\n', asm_out_file);
2668 + if (USE_HIDDEN_LINKONCE)
2670 + fputs ("\t.globl\t", asm_out_file);
2671 + assemble_name (asm_out_file, alias);
2672 + putc ('\n', asm_out_file);
2673 + fputs ("\t.hidden\t", asm_out_file);
2674 + assemble_name (asm_out_file, alias);
2675 + putc ('\n', asm_out_file);
2680 DECL_INITIAL (decl) = make_node (BLOCK);
2681 current_function_decl = decl;
2682 allocate_struct_function (decl, false);
2683 @@ -28760,7 +28831,7 @@ ix86_output_indirect_branch_via_reg (rtx call_op, bool sibcall_p)
2685 indirect_thunks_used |= 1 << i;
2687 - indirect_thunk_name (thunk_name_buf, regno, need_bnd_p);
2688 + indirect_thunk_name (thunk_name_buf, regno, need_bnd_p, false);
2689 thunk_name = thunk_name_buf;
2692 @@ -28869,7 +28940,7 @@ ix86_output_indirect_branch_via_push (rtx call_op, const char *xasm,
2694 indirect_thunk_needed = true;
2696 - indirect_thunk_name (thunk_name_buf, regno, need_bnd_p);
2697 + indirect_thunk_name (thunk_name_buf, regno, need_bnd_p, false);
2698 thunk_name = thunk_name_buf;
2701 @@ -29004,6 +29075,46 @@ ix86_output_indirect_jmp (rtx call_op, bool ret_p)
2702 return "%!jmp\t%A0";
2705 +/* Output function return. CALL_OP is the jump target. Add a REP
2706 + prefix to RET if LONG_P is true and function return is kept. */
2709 +ix86_output_function_return (bool long_p)
2711 + if (cfun->machine->function_return_type != indirect_branch_keep)
2713 + char thunk_name[32];
2714 + bool need_bnd_p = ix86_bnd_prefixed_insn_p (current_output_insn);
2716 + if (cfun->machine->function_return_type
2717 + != indirect_branch_thunk_inline)
2719 + bool need_thunk = (cfun->machine->function_return_type
2720 + == indirect_branch_thunk);
2721 + indirect_thunk_name (thunk_name, -1, need_bnd_p, true);
2724 + indirect_thunk_bnd_needed |= need_thunk;
2725 + fprintf (asm_out_file, "\tbnd jmp\t%s\n", thunk_name);
2729 + indirect_thunk_needed |= need_thunk;
2730 + fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name);
2734 + output_indirect_thunk (need_bnd_p, -1);
2739 + if (!long_p || ix86_bnd_prefixed_insn_p (current_output_insn))
2742 + return "rep%; ret";
2745 /* Output the assembly for a call instruction. */
2748 @@ -42075,6 +42186,28 @@ ix86_handle_fndecl_attribute (tree *node, tree name, tree args, int,
2752 + if (is_attribute_p ("function_return", name))
2754 + tree cst = TREE_VALUE (args);
2755 + if (TREE_CODE (cst) != STRING_CST)
2757 + warning (OPT_Wattributes,
2758 + "%qE attribute requires a string constant argument",
2760 + *no_add_attrs = true;
2762 + else if (strcmp (TREE_STRING_POINTER (cst), "keep") != 0
2763 + && strcmp (TREE_STRING_POINTER (cst), "thunk") != 0
2764 + && strcmp (TREE_STRING_POINTER (cst), "thunk-inline") != 0
2765 + && strcmp (TREE_STRING_POINTER (cst), "thunk-extern") != 0)
2767 + warning (OPT_Wattributes,
2768 + "argument to %qE attribute is not "
2769 + "(keep|thunk|thunk-inline|thunk-extern)", name);
2770 + *no_add_attrs = true;
2777 @@ -46385,6 +46518,8 @@ static const struct attribute_spec ix86_attribute_table[] =
2778 ix86_handle_no_caller_saved_registers_attribute, false },
2779 { "indirect_branch", 1, 1, true, false, false,
2780 ix86_handle_fndecl_attribute, false },
2781 + { "function_return", 1, 1, true, false, false,
2782 + ix86_handle_fndecl_attribute, false },
2785 { NULL, 0, 0, false, false, false, NULL, false }
2786 diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
2787 index 9d2209e605b..45593068905 100644
2788 --- a/gcc/config/i386/i386.h
2789 +++ b/gcc/config/i386/i386.h
2790 @@ -2616,6 +2616,9 @@ struct GTY(()) machine_function {
2791 "indirect_jump" or "tablejump". */
2792 BOOL_BITFIELD has_local_indirect_jump : 1;
2794 + /* How to generate function return. */
2795 + ENUM_BITFIELD(indirect_branch) function_return_type : 3;
2797 /* If true, the current function is a function specified with
2798 the "interrupt" or "no_caller_saved_registers" attribute. */
2799 BOOL_BITFIELD no_caller_saved_registers : 1;
2800 diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
2801 index e32f2311065..3ac79ff6ee6 100644
2802 --- a/gcc/config/i386/i386.md
2803 +++ b/gcc/config/i386/i386.md
2804 @@ -12313,7 +12313,7 @@
2805 (define_insn "simple_return_internal"
2809 + "* return ix86_output_function_return (false);"
2810 [(set_attr "length" "1")
2811 (set_attr "atom_unit" "jeu")
2812 (set_attr "length_immediate" "0")
2813 @@ -12335,12 +12335,7 @@
2815 (unspec [(const_int 0)] UNSPEC_REP)]
2818 - if (ix86_bnd_prefixed_insn_p (insn))
2821 - return "rep%; ret";
2823 + "* return ix86_output_function_return (true);"
2824 [(set_attr "length" "2")
2825 (set_attr "atom_unit" "jeu")
2826 (set_attr "length_immediate" "0")
2827 diff --git a/gcc/config/i386/i386.opt b/gcc/config/i386/i386.opt
2828 index c076d9c70ab..b07388d95a9 100644
2829 --- a/gcc/config/i386/i386.opt
2830 +++ b/gcc/config/i386/i386.opt
2831 @@ -932,9 +932,13 @@ mindirect-branch=
2832 Target Report RejectNegative Joined Enum(indirect_branch) Var(ix86_indirect_branch) Init(indirect_branch_keep)
2833 Convert indirect call and jump to call and return thunks.
2836 +Target Report RejectNegative Joined Enum(indirect_branch) Var(ix86_function_return) Init(indirect_branch_keep)
2837 +Convert function return to call and return thunk.
2840 Name(indirect_branch) Type(enum indirect_branch)
2841 -Known indirect branch choices (for use with the -mindirect-branch= option):
2842 +Known indirect branch choices (for use with the -mindirect-branch=/-mfunction-return= options):
2845 Enum(indirect_branch) String(keep) Value(indirect_branch_keep)
2846 diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
2847 index 935381da6fa..46e0a3623a6 100644
2848 --- a/gcc/doc/extend.texi
2849 +++ b/gcc/doc/extend.texi
2850 @@ -5550,6 +5550,15 @@ call and jump to call and return thunk. @samp{thunk-inline} converts
2851 indirect call and jump to inlined call and return thunk.
2852 @samp{thunk-extern} converts indirect call and jump to external call
2853 and return thunk provided in a separate object file.
2855 +@item function_return("@var{choice}")
2856 +@cindex @code{function_return} function attribute, x86
2857 +On x86 targets, the @code{function_return} attribute causes the compiler
2858 +to convert function return with @var{choice}. @samp{keep} keeps function
2859 +return unmodified. @samp{thunk} converts function return to call and
2860 +return thunk. @samp{thunk-inline} converts function return to inlined
2861 +call and return thunk. @samp{thunk-extern} converts function return to
2862 +external call and return thunk provided in a separate object file.
2865 On the x86, the inliner does not inline a
2866 diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
2867 index 4979c8c939d..f3eb54b1668 100644
2868 --- a/gcc/doc/invoke.texi
2869 +++ b/gcc/doc/invoke.texi
2870 @@ -1211,7 +1211,7 @@ See RS/6000 and PowerPC Options.
2871 -mavx256-split-unaligned-load -mavx256-split-unaligned-store @gol
2872 -malign-data=@var{type} -mstack-protector-guard=@var{guard} @gol
2873 -mmitigate-rop -mgeneral-regs-only @gol
2874 --mindirect-branch=@var{choice}}
2875 +-mindirect-branch=@var{choice} -mfunction-return==@var{choice}}
2877 @emph{x86 Windows Options}
2878 @gccoptlist{-mconsole -mcygwin -mno-cygwin -mdll @gol
2879 @@ -25698,6 +25698,17 @@ to external call and return thunk provided in a separate object file.
2880 You can control this behavior for a specific function by using the
2881 function attribute @code{indirect_branch}. @xref{Function Attributes}.
2883 +@item -mfunction-return=@var{choice}
2884 +@opindex -mfunction-return
2885 +Convert function return with @var{choice}. The default is @samp{keep},
2886 +which keeps function return unmodified. @samp{thunk} converts function
2887 +return to call and return thunk. @samp{thunk-inline} converts function
2888 +return to inlined call and return thunk. @samp{thunk-extern} converts
2889 +function return to external call and return thunk provided in a separate
2890 +object file. You can control this behavior for a specific function by
2891 +using the function attribute @code{function_return}.
2892 +@xref{Function Attributes}.
2896 These @samp{-m} switches are supported in addition to the above
2897 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c
2898 index d983e1c3e26..f076155c91a 100644
2899 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c
2900 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c
2902 /* { dg-do compile } */
2903 -/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
2904 +/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
2906 typedef void (*dispatch_t)(long offset);
2908 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c
2909 index 58f09b42d8a..d7984f592fe 100644
2910 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c
2911 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c
2913 /* { dg-do compile } */
2914 -/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
2915 +/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
2917 typedef void (*dispatch_t)(long offset);
2919 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c
2920 index f20d35c19b6..3257d0a2e16 100644
2921 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c
2922 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c
2924 /* { dg-do compile } */
2925 -/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
2926 +/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
2928 typedef void (*dispatch_t)(long offset);
2930 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c
2931 index 0eff8fb658a..7cab2df6474 100644
2932 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c
2933 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c
2935 /* { dg-do compile } */
2936 -/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
2937 +/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
2939 typedef void (*dispatch_t)(long offset);
2941 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c
2942 index a25b20dd808..b4836c38d6c 100644
2943 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c
2944 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c
2946 /* { dg-do compile { target *-*-linux* } } */
2947 -/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk" } */
2948 +/* { dg-options "-O2 -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk" } */
2950 extern void bar (void);
2952 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c
2953 index cff114a6c29..1f06bd1af74 100644
2954 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c
2955 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c
2957 /* { dg-do compile { target *-*-linux* } } */
2958 -/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk" } */
2959 +/* { dg-options "-O2 -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk" } */
2961 extern void bar (void);
2963 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c
2964 index afdb6007986..0b3fef86a20 100644
2965 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c
2966 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c
2968 /* { dg-do compile } */
2969 -/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
2970 +/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
2974 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c
2975 index d64d978b699..5f6cfc17b56 100644
2976 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c
2977 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c
2979 /* { dg-do compile } */
2980 -/* { dg-options "-O2 -fno-pic" } */
2981 +/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
2983 typedef void (*dispatch_t)(long offset);
2985 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c
2986 index 93067454d3d..b256160ec80 100644
2987 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c
2988 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c
2990 /* { dg-do compile } */
2991 -/* { dg-options "-O2 -fno-pic" } */
2992 +/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
2994 typedef void (*dispatch_t)(long offset);
2996 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c
2997 index 97744d65729..567c95051d6 100644
2998 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c
2999 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c
3001 /* { dg-do compile } */
3002 -/* { dg-options "-O2 -fno-pic" } */
3003 +/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
3005 typedef void (*dispatch_t)(long offset);
3007 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c
3008 index bfce3ea5cb2..3b662af7d5d 100644
3009 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c
3010 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c
3012 /* { dg-do compile } */
3013 -/* { dg-options "-O2 -fno-pic" } */
3014 +/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
3016 typedef void (*dispatch_t)(long offset);
3018 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c
3019 index 0833606046b..98785a38248 100644
3020 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c
3021 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c
3023 /* { dg-do compile } */
3024 -/* { dg-options "-O2 -fno-pic" } */
3025 +/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
3027 typedef void (*dispatch_t)(long offset);
3029 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c
3030 index 2eba0fbd9b2..a498a39e404 100644
3031 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c
3032 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c
3034 /* { dg-do compile } */
3035 -/* { dg-options "-O2 -fno-pic" } */
3036 +/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
3038 typedef void (*dispatch_t)(long offset);
3040 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c
3041 index f58427eae11..66f295d1eb6 100644
3042 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c
3043 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c
3045 /* { dg-do compile } */
3046 -/* { dg-options "-O2 -fno-pic" } */
3047 +/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
3051 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c
3052 index 564ed39547c..d730d31bda1 100644
3053 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c
3054 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c
3056 /* { dg-do compile } */
3057 -/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
3058 +/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
3062 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c
3063 index 50fbee20a5a..aacb814d737 100644
3064 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c
3065 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c
3067 /* { dg-do compile { target { ! x32 } } } */
3068 -/* { dg-options "-O2 -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
3069 +/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
3071 void (*dispatch) (char *);
3073 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c
3074 index 2976e67adce..7b44dda23df 100644
3075 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c
3076 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c
3078 /* { dg-do compile { target { ! x32 } } } */
3079 -/* { dg-options "-O2 -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
3080 +/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
3082 void (*dispatch) (char *);
3084 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c
3085 index da4bc98ef23..70b4fb36eea 100644
3086 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c
3087 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c
3089 /* { dg-do compile { target { *-*-linux* && { ! x32 } } } } */
3090 -/* { dg-options "-O2 -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fpic -fno-plt" } */
3091 +/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fpic -fno-plt" } */
3095 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c
3096 index c64d12ef989..3baf03ee77c 100644
3097 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c
3098 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c
3100 /* { dg-do compile { target { *-*-linux* && { ! x32 } } } } */
3101 -/* { dg-options "-O2 -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fpic -fno-plt" } */
3102 +/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fpic -fno-plt" } */
3106 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c
3107 index 49f27b49465..637fc3d3f4e 100644
3108 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c
3109 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c
3111 /* { dg-do compile } */
3112 -/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */
3113 +/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
3115 typedef void (*dispatch_t)(long offset);
3117 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c
3118 index a1e3eb6fc74..ff9efe03fe6 100644
3119 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c
3120 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c
3122 /* { dg-do compile } */
3123 -/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */
3124 +/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
3126 typedef void (*dispatch_t)(long offset);
3128 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c
3129 index 395634e7e5c..2686a5f2db4 100644
3130 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c
3131 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c
3133 /* { dg-do compile } */
3134 -/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */
3135 +/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
3137 typedef void (*dispatch_t)(long offset);
3139 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c
3140 index fd3f63379a1..f07f6b214ad 100644
3141 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c
3142 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c
3144 /* { dg-do compile } */
3145 -/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */
3146 +/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
3148 typedef void (*dispatch_t)(long offset);
3150 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c
3151 index ba2f92b6f34..21740ac5b7f 100644
3152 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c
3153 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c
3155 /* { dg-do compile { target *-*-linux* } } */
3156 -/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk-extern" } */
3157 +/* { dg-options "-O2 -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk-extern" } */
3159 extern void bar (void);
3161 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c
3162 index 0c5a2d472c6..a77c1f470b8 100644
3163 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c
3164 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c
3166 /* { dg-do compile { target *-*-linux* } } */
3167 -/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk-extern" } */
3168 +/* { dg-options "-O2 -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk-extern" } */
3170 extern void bar (void);
3172 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c
3173 index 665252327aa..e64910fd4aa 100644
3174 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c
3175 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c
3177 /* { dg-do compile } */
3178 -/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */
3179 +/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
3183 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c
3184 index 68c0ff713b3..365cf2ee226 100644
3185 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c
3186 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c
3188 /* { dg-do compile } */
3189 -/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */
3190 +/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
3192 typedef void (*dispatch_t)(long offset);
3194 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c
3195 index e2da1fcb683..72646a4960b 100644
3196 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c
3197 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c
3199 /* { dg-do compile } */
3200 -/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */
3201 +/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
3203 typedef void (*dispatch_t)(long offset);
3205 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c
3206 index 244fec708d6..f48945e3dfc 100644
3207 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c
3208 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c
3210 /* { dg-do compile } */
3211 -/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */
3212 +/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
3214 typedef void (*dispatch_t)(long offset);
3216 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c
3217 index 107ebe32f54..4b1d558fc4e 100644
3218 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c
3219 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c
3221 /* { dg-do compile } */
3222 -/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */
3223 +/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
3225 typedef void (*dispatch_t)(long offset);
3227 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c
3228 index 17b04ef2229..0f687c3b027 100644
3229 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c
3230 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c
3232 /* { dg-do compile { target *-*-linux* } } */
3233 -/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk-inline" } */
3234 +/* { dg-options "-O2 -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk-inline" } */
3236 extern void bar (void);
3238 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c
3239 index d9eb11285aa..b27c6fc96a2 100644
3240 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c
3241 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c
3243 /* { dg-do compile { target *-*-linux* } } */
3244 -/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk-inline" } */
3245 +/* { dg-options "-O2 -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk-inline" } */
3247 extern void bar (void);
3249 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c
3250 index d02b1dcb1b9..2c496492eaa 100644
3251 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c
3252 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c
3254 /* { dg-do compile } */
3255 -/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */
3256 +/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
3260 diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-1.c b/gcc/testsuite/gcc.target/i386/ret-thunk-1.c
3261 new file mode 100644
3262 index 00000000000..7223f67ba5e
3264 +++ b/gcc/testsuite/gcc.target/i386/ret-thunk-1.c
3266 +/* { dg-do compile } */
3267 +/* { dg-options "-O2 -mfunction-return=thunk" } */
3274 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk" } } */
3275 +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
3276 +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
3277 +/* { dg-final { scan-assembler {\tpause} } } */
3278 +/* { dg-final { scan-assembler {\tlfence} } } */
3279 diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-10.c b/gcc/testsuite/gcc.target/i386/ret-thunk-10.c
3280 new file mode 100644
3281 index 00000000000..1630e2fa2b5
3283 +++ b/gcc/testsuite/gcc.target/i386/ret-thunk-10.c
3285 +/* { dg-do compile } */
3286 +/* { dg-options "-O2 -mfunction-return=thunk-inline -mindirect-branch=thunk -fno-pic" } */
3288 +extern void (*bar) (void);
3297 +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
3298 +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
3299 +/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_return_thunk" } } */
3300 +/* { dg-final { scan-assembler-times {\tpause} 2 } } */
3301 +/* { dg-final { scan-assembler-times {\tlfence} 2 } } */
3302 +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { ! x32 } } } } */
3303 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
3304 +/* { dg-final { scan-assembler "__x86_indirect_thunk:" { target { ! x32 } } } } */
3305 +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target { x32 } } } } */
3306 +/* { dg-final { scan-assembler "__x86_indirect_thunk_(r|e)ax:" { target { x32 } } } } */
3307 +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
3308 diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-11.c b/gcc/testsuite/gcc.target/i386/ret-thunk-11.c
3309 new file mode 100644
3310 index 00000000000..876159cf783
3312 +++ b/gcc/testsuite/gcc.target/i386/ret-thunk-11.c
3314 +/* { dg-do compile } */
3315 +/* { dg-options "-O2 -mfunction-return=thunk-extern -mindirect-branch=thunk -fno-pic" } */
3317 +extern void (*bar) (void);
3326 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk" } } */
3327 +/* { dg-final { scan-assembler-times {\tpause} 1 } } */
3328 +/* { dg-final { scan-assembler-times {\tlfence} 1 } } */
3329 +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
3330 +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
3331 +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { ! x32 } } } } */
3332 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
3333 +/* { dg-final { scan-assembler "__x86_indirect_thunk:" { target { ! x32 } } } } */
3334 +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target { x32 } } } } */
3335 +/* { dg-final { scan-assembler "__x86_indirect_thunk_(r|e)ax:" { target { x32 } } } } */
3336 +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
3337 diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-12.c b/gcc/testsuite/gcc.target/i386/ret-thunk-12.c
3338 new file mode 100644
3339 index 00000000000..01b0a02f80b
3341 +++ b/gcc/testsuite/gcc.target/i386/ret-thunk-12.c
3343 +/* { dg-do compile } */
3344 +/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
3346 +extern void (*bar) (void);
3355 +/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_return_thunk" } } */
3356 +/* { dg-final { scan-assembler-times {\tpause} 1 } } */
3357 +/* { dg-final { scan-assembler-times {\tlfence} 1 } } */
3358 +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
3359 +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
3360 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
3361 +/* { dg-final { scan-assembler "__x86_indirect_thunk:" { target { ! x32 } } } } */
3362 +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target { x32 } } } } */
3363 +/* { dg-final { scan-assembler "__x86_indirect_thunk_(r|e)ax:" { target { x32 } } } } */
3364 +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
3365 diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-13.c b/gcc/testsuite/gcc.target/i386/ret-thunk-13.c
3366 new file mode 100644
3367 index 00000000000..e028c2b6a99
3369 +++ b/gcc/testsuite/gcc.target/i386/ret-thunk-13.c
3371 +/* { dg-do compile } */
3372 +/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
3374 +extern void (*bar) (void);
3375 +extern int foo (void) __attribute__ ((function_return("thunk")));
3384 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk" } } */
3385 +/* { dg-final { scan-assembler-times {\tpause} 2 } } */
3386 +/* { dg-final { scan-assembler-times {\tlfence} 2 } } */
3387 +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { ! x32 } } } } */
3388 +/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 3 } } */
3389 +/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 3 } } */
3390 +/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_indirect_thunk" } } */
3391 +/* { dg-final { scan-assembler-not "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target { x32 } } } } */
3392 +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
3393 diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-14.c b/gcc/testsuite/gcc.target/i386/ret-thunk-14.c
3394 new file mode 100644
3395 index 00000000000..c14ee3ae4c0
3397 +++ b/gcc/testsuite/gcc.target/i386/ret-thunk-14.c
3399 +/* { dg-do compile } */
3400 +/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
3402 +extern void (*bar) (void);
3404 +__attribute__ ((function_return("thunk-inline")))
3412 +/* { dg-final { scan-assembler-times {\tpause} 1 } } */
3413 +/* { dg-final { scan-assembler-times {\tlfence} 1 } } */
3414 +/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_return_thunk" } } */
3415 +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
3416 +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
3417 +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { ! x32 } } } } */
3418 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
3419 +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target { x32 } } } } */
3420 +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
3421 diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-15.c b/gcc/testsuite/gcc.target/i386/ret-thunk-15.c
3422 new file mode 100644
3423 index 00000000000..2f21e138ec2
3425 +++ b/gcc/testsuite/gcc.target/i386/ret-thunk-15.c
3427 +/* { dg-do compile } */
3428 +/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=keep -fno-pic" } */
3430 +extern void (*bar) (void);
3432 +__attribute__ ((function_return("thunk-extern"), indirect_branch("thunk")))
3440 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk" } } */
3441 +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
3442 +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
3443 +/* { dg-final { scan-assembler-times {\tpause} 1 } } */
3444 +/* { dg-final { scan-assembler-times {\tlfence} 1 } } */
3445 +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { ! x32 } } } } */
3446 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
3447 +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
3448 +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
3449 diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-16.c b/gcc/testsuite/gcc.target/i386/ret-thunk-16.c
3450 new file mode 100644
3451 index 00000000000..a16cad16aaa
3453 +++ b/gcc/testsuite/gcc.target/i386/ret-thunk-16.c
3455 +/* { dg-do compile } */
3456 +/* { dg-options "-O2 -mfunction-return=thunk-inline -mindirect-branch=thunk-extern -fno-pic" } */
3458 +extern void (*bar) (void);
3460 +__attribute__ ((function_return("keep"), indirect_branch("keep")))
3468 +/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
3469 +/* { dg-final { scan-assembler-not "__x86_return_thunk" } } */
3470 +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
3471 +/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
3472 +/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
3473 diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-2.c b/gcc/testsuite/gcc.target/i386/ret-thunk-2.c
3474 new file mode 100644
3475 index 00000000000..c6659e3ad09
3477 +++ b/gcc/testsuite/gcc.target/i386/ret-thunk-2.c
3479 +/* { dg-do compile } */
3480 +/* { dg-options "-O2 -mfunction-return=thunk-inline" } */
3487 +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
3488 +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
3489 +/* { dg-final { scan-assembler {\tpause} } } */
3490 +/* { dg-final { scan-assembler {\tlfence} } } */
3491 +/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_return_thunk" } } */
3492 diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-3.c b/gcc/testsuite/gcc.target/i386/ret-thunk-3.c
3493 new file mode 100644
3494 index 00000000000..0f7f388f459
3496 +++ b/gcc/testsuite/gcc.target/i386/ret-thunk-3.c
3498 +/* { dg-do compile } */
3499 +/* { dg-options "-O2 -mfunction-return=thunk-extern" } */
3506 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk" } } */
3507 +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
3508 +/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
3509 +/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
3510 diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-4.c b/gcc/testsuite/gcc.target/i386/ret-thunk-4.c
3511 new file mode 100644
3512 index 00000000000..9ae37e835a0
3514 +++ b/gcc/testsuite/gcc.target/i386/ret-thunk-4.c
3516 +/* { dg-do compile } */
3517 +/* { dg-options "-O2 -mfunction-return=keep" } */
3524 +/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_return_thunk" } } */
3525 +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
3526 +/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
3527 +/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
3528 diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-5.c b/gcc/testsuite/gcc.target/i386/ret-thunk-5.c
3529 new file mode 100644
3530 index 00000000000..4bd0d2a27bc
3532 +++ b/gcc/testsuite/gcc.target/i386/ret-thunk-5.c
3534 +/* { dg-do compile } */
3535 +/* { dg-options "-O2 -mfunction-return=keep" } */
3537 +extern void foo (void) __attribute__ ((function_return("thunk")));
3544 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk" } } */
3545 +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
3546 +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
3547 +/* { dg-final { scan-assembler {\tpause} } } */
3548 +/* { dg-final { scan-assembler {\tlfence} } } */
3549 diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-6.c b/gcc/testsuite/gcc.target/i386/ret-thunk-6.c
3550 new file mode 100644
3551 index 00000000000..053841f6f7d
3553 +++ b/gcc/testsuite/gcc.target/i386/ret-thunk-6.c
3555 +/* { dg-do compile } */
3556 +/* { dg-options "-O2 -mfunction-return=keep" } */
3558 +__attribute__ ((function_return("thunk-inline")))
3564 +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
3565 +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
3566 +/* { dg-final { scan-assembler {\tpause} } } */
3567 +/* { dg-final { scan-assembler {\tlfence} } } */
3568 +/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_return_thunk" } } */
3569 diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-7.c b/gcc/testsuite/gcc.target/i386/ret-thunk-7.c
3570 new file mode 100644
3571 index 00000000000..262e6780112
3573 +++ b/gcc/testsuite/gcc.target/i386/ret-thunk-7.c
3575 +/* { dg-do compile } */
3576 +/* { dg-options "-O2 -mfunction-return=keep" } */
3578 +__attribute__ ((function_return("thunk-extern")))
3584 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk" } } */
3585 +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
3586 +/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
3587 +/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
3588 diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-8.c b/gcc/testsuite/gcc.target/i386/ret-thunk-8.c
3589 new file mode 100644
3590 index 00000000000..c1658e96673
3592 +++ b/gcc/testsuite/gcc.target/i386/ret-thunk-8.c
3594 +/* { dg-do compile } */
3595 +/* { dg-options "-O2 -mfunction-return=thunk-inline" } */
3597 +extern void foo (void) __attribute__ ((function_return("keep")));
3604 +/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_return_thunk" } } */
3605 +/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
3606 +/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
3607 +/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
3608 diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-9.c b/gcc/testsuite/gcc.target/i386/ret-thunk-9.c
3609 new file mode 100644
3610 index 00000000000..f6ccad98da7
3612 +++ b/gcc/testsuite/gcc.target/i386/ret-thunk-9.c
3614 +/* { dg-do compile } */
3615 +/* { dg-options "-O2 -mfunction-return=thunk -mindirect-branch=thunk -fno-pic" } */
3617 +extern void (*bar) (void);
3626 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk" } } */
3627 +/* { dg-final { scan-assembler-not "__x86_return_thunk:" } } */
3628 +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
3629 +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
3630 +/* { dg-final { scan-assembler "__x86_indirect_thunk:" } } */
3631 +/* { dg-final { scan-assembler-times {\tpause} 1 { target { ! x32 } } } } */
3632 +/* { dg-final { scan-assembler-times {\tlfence} 1 { target { ! x32 } } } } */
3633 +/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { ! x32 } } } } */
3634 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
3635 +/* { dg-final { scan-assembler-times {\tpause} 2 { target { x32 } } } } */
3636 +/* { dg-final { scan-assembler-times {\tlfence} 2 { target { x32 } } } } */
3637 +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target { x32 } } } } */
3638 +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
3640 commit 443f274c129f9a4da28d1f796744d1179ec2fdc4
3641 Author: H.J. Lu <hjl.tools@gmail.com>
3642 Date: Sat Jan 6 22:29:56 2018 -0800
3644 x86: Add -mindirect-branch-register
3646 Add -mindirect-branch-register to force indirect branch via register.
3647 This is implemented by disabling patterns of indirect branch via memory,
3648 similar to TARGET_X32.
3650 -mindirect-branch= and -mfunction-return= tests are updated with
3651 -mno-indirect-branch-register to avoid false test failures when
3652 -mindirect-branch-register is added to RUNTESTFLAGS for "make check".
3656 * config/i386/constraints.md (Bs): Disallow memory operand for
3657 -mindirect-branch-register.
3659 * config/i386/predicates.md (indirect_branch_operand): Likewise.
3660 (GOT_memory_operand): Likewise.
3661 (call_insn_operand): Likewise.
3662 (sibcall_insn_operand): Likewise.
3663 (GOT32_symbol_operand): Likewise.
3664 * config/i386/i386.md (indirect_jump): Call convert_memory_address
3665 for -mindirect-branch-register.
3666 (tablejump): Likewise.
3667 (*sibcall_memory): Likewise.
3668 (*sibcall_value_memory): Likewise.
3669 Disallow peepholes of indirect call and jump via memory for
3670 -mindirect-branch-register.
3671 (*call_pop): Replace m with Bw.
3672 (*call_value_pop): Likewise.
3673 (*sibcall_pop_memory): Replace m with Bs.
3674 * config/i386/i386.opt (mindirect-branch-register): New option.
3675 * doc/invoke.texi: Document -mindirect-branch-register option.
3679 * gcc.target/i386/indirect-thunk-1.c (dg-options): Add
3680 -mno-indirect-branch-register.
3681 * gcc.target/i386/indirect-thunk-2.c: Likewise.
3682 * gcc.target/i386/indirect-thunk-3.c: Likewise.
3683 * gcc.target/i386/indirect-thunk-4.c: Likewise.
3684 * gcc.target/i386/indirect-thunk-5.c: Likewise.
3685 * gcc.target/i386/indirect-thunk-6.c: Likewise.
3686 * gcc.target/i386/indirect-thunk-7.c: Likewise.
3687 * gcc.target/i386/indirect-thunk-attr-1.c: Likewise.
3688 * gcc.target/i386/indirect-thunk-attr-2.c: Likewise.
3689 * gcc.target/i386/indirect-thunk-attr-3.c: Likewise.
3690 * gcc.target/i386/indirect-thunk-attr-4.c: Likewise.
3691 * gcc.target/i386/indirect-thunk-attr-5.c: Likewise.
3692 * gcc.target/i386/indirect-thunk-attr-6.c: Likewise.
3693 * gcc.target/i386/indirect-thunk-attr-7.c: Likewise.
3694 * gcc.target/i386/indirect-thunk-bnd-1.c: Likewise.
3695 * gcc.target/i386/indirect-thunk-bnd-2.c: Likewise.
3696 * gcc.target/i386/indirect-thunk-bnd-3.c: Likewise.
3697 * gcc.target/i386/indirect-thunk-bnd-4.c: Likewise.
3698 * gcc.target/i386/indirect-thunk-extern-1.c: Likewise.
3699 * gcc.target/i386/indirect-thunk-extern-2.c: Likewise.
3700 * gcc.target/i386/indirect-thunk-extern-3.c: Likewise.
3701 * gcc.target/i386/indirect-thunk-extern-4.c: Likewise.
3702 * gcc.target/i386/indirect-thunk-extern-5.c: Likewise.
3703 * gcc.target/i386/indirect-thunk-extern-6.c: Likewise.
3704 * gcc.target/i386/indirect-thunk-extern-7.c: Likewise.
3705 * gcc.target/i386/indirect-thunk-inline-1.c: Likewise.
3706 * gcc.target/i386/indirect-thunk-inline-2.c: Likewise.
3707 * gcc.target/i386/indirect-thunk-inline-3.c: Likewise.
3708 * gcc.target/i386/indirect-thunk-inline-4.c: Likewise.
3709 * gcc.target/i386/indirect-thunk-inline-5.c: Likewise.
3710 * gcc.target/i386/indirect-thunk-inline-6.c: Likewise.
3711 * gcc.target/i386/indirect-thunk-inline-7.c: Likewise.
3712 * gcc.target/i386/ret-thunk-10.c: Likewise.
3713 * gcc.target/i386/ret-thunk-11.c: Likewise.
3714 * gcc.target/i386/ret-thunk-12.c: Likewise.
3715 * gcc.target/i386/ret-thunk-13.c: Likewise.
3716 * gcc.target/i386/ret-thunk-14.c: Likewise.
3717 * gcc.target/i386/ret-thunk-15.c: Likewise.
3718 * gcc.target/i386/ret-thunk-9.c: Likewise.
3719 * gcc.target/i386/indirect-thunk-register-1.c: New test.
3720 * gcc.target/i386/indirect-thunk-register-2.c: Likewise.
3721 * gcc.target/i386/indirect-thunk-register-3.c: Likewise.
3723 diff --git a/gcc/config/i386/constraints.md b/gcc/config/i386/constraints.md
3724 index 38d604fdace..697caf704dd 100644
3725 --- a/gcc/config/i386/constraints.md
3726 +++ b/gcc/config/i386/constraints.md
3727 @@ -198,16 +198,20 @@
3729 (define_constraint "Bs"
3730 "@internal Sibcall memory operand."
3731 - (ior (and (not (match_test "TARGET_X32"))
3732 + (ior (and (not (match_test "TARGET_X32
3733 + || ix86_indirect_branch_thunk_register"))
3734 (match_operand 0 "sibcall_memory_operand"))
3735 - (and (match_test "TARGET_X32 && Pmode == DImode")
3736 + (and (match_test "TARGET_X32 && Pmode == DImode
3737 + && !ix86_indirect_branch_thunk_register")
3738 (match_operand 0 "GOT_memory_operand"))))
3740 (define_constraint "Bw"
3741 "@internal Call memory operand."
3742 - (ior (and (not (match_test "TARGET_X32"))
3743 + (ior (and (not (match_test "TARGET_X32
3744 + || ix86_indirect_branch_thunk_register"))
3745 (match_operand 0 "memory_operand"))
3746 - (and (match_test "TARGET_X32 && Pmode == DImode")
3747 + (and (match_test "TARGET_X32 && Pmode == DImode
3748 + && !ix86_indirect_branch_thunk_register")
3749 (match_operand 0 "GOT_memory_operand"))))
3751 (define_constraint "Bz"
3752 diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
3753 index 3ac79ff6ee6..02ab4d45fa6 100644
3754 --- a/gcc/config/i386/i386.md
3755 +++ b/gcc/config/i386/i386.md
3756 @@ -11623,7 +11623,7 @@
3757 [(set (pc) (match_operand 0 "indirect_branch_operand"))]
3761 + if (TARGET_X32 || ix86_indirect_branch_thunk_register)
3762 operands[0] = convert_memory_address (word_mode, operands[0]);
3763 cfun->machine->has_local_indirect_jump = true;
3765 @@ -11677,7 +11677,7 @@
3770 + if (TARGET_X32 || ix86_indirect_branch_thunk_register)
3771 operands[0] = convert_memory_address (word_mode, operands[0]);
3772 cfun->machine->has_local_indirect_jump = true;
3774 @@ -11869,7 +11869,7 @@
3775 [(call (mem:QI (match_operand:W 0 "memory_operand" "m"))
3777 (unspec [(const_int 0)] UNSPEC_PEEPSIB)]
3779 + "!TARGET_X32 && !ix86_indirect_branch_thunk_register"
3780 "* return ix86_output_call_insn (insn, operands[0]);"
3781 [(set_attr "type" "call")])
3783 @@ -11878,7 +11878,9 @@
3784 (match_operand:W 1 "memory_operand"))
3785 (call (mem:QI (match_dup 0))
3787 - "!TARGET_X32 && SIBLING_CALL_P (peep2_next_insn (1))
3789 + && !ix86_indirect_branch_thunk_register
3790 + && SIBLING_CALL_P (peep2_next_insn (1))
3791 && !reg_mentioned_p (operands[0],
3792 CALL_INSN_FUNCTION_USAGE (peep2_next_insn (1)))"
3793 [(parallel [(call (mem:QI (match_dup 1))
3794 @@ -11891,7 +11893,9 @@
3795 (unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)
3796 (call (mem:QI (match_dup 0))
3798 - "!TARGET_X32 && SIBLING_CALL_P (peep2_next_insn (2))
3800 + && !ix86_indirect_branch_thunk_register
3801 + && SIBLING_CALL_P (peep2_next_insn (2))
3802 && !reg_mentioned_p (operands[0],
3803 CALL_INSN_FUNCTION_USAGE (peep2_next_insn (2)))"
3804 [(unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)
3805 @@ -11913,7 +11917,7 @@
3808 (define_insn "*call_pop"
3809 - [(call (mem:QI (match_operand:SI 0 "call_insn_operand" "lmBz"))
3810 + [(call (mem:QI (match_operand:SI 0 "call_insn_operand" "lBwBz"))
3812 (set (reg:SI SP_REG)
3813 (plus:SI (reg:SI SP_REG)
3814 @@ -11933,7 +11937,7 @@
3815 [(set_attr "type" "call")])
3817 (define_insn "*sibcall_pop_memory"
3818 - [(call (mem:QI (match_operand:SI 0 "memory_operand" "m"))
3819 + [(call (mem:QI (match_operand:SI 0 "memory_operand" "Bs"))
3821 (set (reg:SI SP_REG)
3822 (plus:SI (reg:SI SP_REG)
3823 @@ -11987,7 +11991,9 @@
3824 [(set (match_operand:W 0 "register_operand")
3825 (match_operand:W 1 "memory_operand"))
3826 (set (pc) (match_dup 0))]
3827 - "!TARGET_X32 && peep2_reg_dead_p (2, operands[0])"
3829 + && !ix86_indirect_branch_thunk_register
3830 + && peep2_reg_dead_p (2, operands[0])"
3831 [(set (pc) (match_dup 1))])
3833 ;; Call subroutine, returning value in operand 0
3834 @@ -12068,7 +12074,7 @@
3835 (call (mem:QI (match_operand:W 1 "memory_operand" "m"))
3837 (unspec [(const_int 0)] UNSPEC_PEEPSIB)]
3839 + "!TARGET_X32 && !ix86_indirect_branch_thunk_register"
3840 "* return ix86_output_call_insn (insn, operands[1]);"
3841 [(set_attr "type" "callv")])
3843 @@ -12078,7 +12084,9 @@
3844 (set (match_operand 2)
3845 (call (mem:QI (match_dup 0))
3846 (match_operand 3)))]
3847 - "!TARGET_X32 && SIBLING_CALL_P (peep2_next_insn (1))
3849 + && !ix86_indirect_branch_thunk_register
3850 + && SIBLING_CALL_P (peep2_next_insn (1))
3851 && !reg_mentioned_p (operands[0],
3852 CALL_INSN_FUNCTION_USAGE (peep2_next_insn (1)))"
3853 [(parallel [(set (match_dup 2)
3854 @@ -12093,7 +12101,9 @@
3855 (set (match_operand 2)
3856 (call (mem:QI (match_dup 0))
3857 (match_operand 3)))]
3858 - "!TARGET_X32 && SIBLING_CALL_P (peep2_next_insn (2))
3860 + && !ix86_indirect_branch_thunk_register
3861 + && SIBLING_CALL_P (peep2_next_insn (2))
3862 && !reg_mentioned_p (operands[0],
3863 CALL_INSN_FUNCTION_USAGE (peep2_next_insn (2)))"
3864 [(unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)
3865 @@ -12118,7 +12128,7 @@
3867 (define_insn "*call_value_pop"
3868 [(set (match_operand 0)
3869 - (call (mem:QI (match_operand:SI 1 "call_insn_operand" "lmBz"))
3870 + (call (mem:QI (match_operand:SI 1 "call_insn_operand" "lBwBz"))
3872 (set (reg:SI SP_REG)
3873 (plus:SI (reg:SI SP_REG)
3874 diff --git a/gcc/config/i386/i386.opt b/gcc/config/i386/i386.opt
3875 index b07388d95a9..852033cbb67 100644
3876 --- a/gcc/config/i386/i386.opt
3877 +++ b/gcc/config/i386/i386.opt
3878 @@ -951,3 +951,7 @@ Enum(indirect_branch) String(thunk-inline) Value(indirect_branch_thunk_inline)
3881 Enum(indirect_branch) String(thunk-extern) Value(indirect_branch_thunk_extern)
3883 +mindirect-branch-register
3884 +Target Report Var(ix86_indirect_branch_thunk_register) Init(0)
3885 +Force indirect call and jump via register.
3886 diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md
3887 index 2fc2c60f6ac..a88b1d860ca 100644
3888 --- a/gcc/config/i386/predicates.md
3889 +++ b/gcc/config/i386/predicates.md
3891 ;; Test for a valid operand for indirect branch.
3892 (define_predicate "indirect_branch_operand"
3893 (ior (match_operand 0 "register_operand")
3894 - (and (not (match_test "TARGET_X32"))
3895 + (and (not (match_test "TARGET_X32
3896 + || ix86_indirect_branch_thunk_register"))
3897 (match_operand 0 "memory_operand"))))
3899 ;; Return true if OP is a memory operands that can be used in sibcalls.
3902 ;; Return true if OP is a GOT memory operand.
3903 (define_predicate "GOT_memory_operand"
3904 - (match_operand 0 "memory_operand")
3905 + (and (match_test "!ix86_indirect_branch_thunk_register")
3906 + (match_operand 0 "memory_operand"))
3909 return (GET_CODE (op) == CONST
3910 @@ -678,9 +680,11 @@
3911 (ior (match_test "constant_call_address_operand
3912 (op, mode == VOIDmode ? mode : Pmode)")
3913 (match_operand 0 "call_register_no_elim_operand")
3914 - (ior (and (not (match_test "TARGET_X32"))
3915 + (ior (and (not (match_test "TARGET_X32
3916 + || ix86_indirect_branch_thunk_register"))
3917 (match_operand 0 "memory_operand"))
3918 - (and (match_test "TARGET_X32 && Pmode == DImode")
3919 + (and (match_test "TARGET_X32 && Pmode == DImode
3920 + && !ix86_indirect_branch_thunk_register")
3921 (match_operand 0 "GOT_memory_operand")))))
3923 ;; Similarly, but for tail calls, in which we cannot allow memory references.
3924 @@ -688,14 +692,17 @@
3925 (ior (match_test "constant_call_address_operand
3926 (op, mode == VOIDmode ? mode : Pmode)")
3927 (match_operand 0 "register_no_elim_operand")
3928 - (ior (and (not (match_test "TARGET_X32"))
3929 + (ior (and (not (match_test "TARGET_X32
3930 + || ix86_indirect_branch_thunk_register"))
3931 (match_operand 0 "sibcall_memory_operand"))
3932 - (and (match_test "TARGET_X32 && Pmode == DImode")
3933 + (and (match_test "TARGET_X32 && Pmode == DImode
3934 + && !ix86_indirect_branch_thunk_register")
3935 (match_operand 0 "GOT_memory_operand")))))
3937 ;; Return true if OP is a 32-bit GOT symbol operand.
3938 (define_predicate "GOT32_symbol_operand"
3939 - (match_test "GET_CODE (op) == CONST
3940 + (match_test "!ix86_indirect_branch_thunk_register
3941 + && GET_CODE (op) == CONST
3942 && GET_CODE (XEXP (op, 0)) == UNSPEC
3943 && XINT (XEXP (op, 0), 1) == UNSPEC_GOT"))
3945 diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
3946 index f3eb54b1668..1e572b1f9a2 100644
3947 --- a/gcc/doc/invoke.texi
3948 +++ b/gcc/doc/invoke.texi
3949 @@ -1211,7 +1211,8 @@ See RS/6000 and PowerPC Options.
3950 -mavx256-split-unaligned-load -mavx256-split-unaligned-store @gol
3951 -malign-data=@var{type} -mstack-protector-guard=@var{guard} @gol
3952 -mmitigate-rop -mgeneral-regs-only @gol
3953 --mindirect-branch=@var{choice} -mfunction-return==@var{choice}}
3954 +-mindirect-branch=@var{choice} -mfunction-return==@var{choice} @gol
3955 +-mindirect-branch-register}
3957 @emph{x86 Windows Options}
3958 @gccoptlist{-mconsole -mcygwin -mno-cygwin -mdll @gol
3959 @@ -25709,6 +25710,10 @@ object file. You can control this behavior for a specific function by
3960 using the function attribute @code{function_return}.
3961 @xref{Function Attributes}.
3963 +@item -mindirect-branch-register
3964 +@opindex -mindirect-branch-register
3965 +Force indirect call and jump via register.
3969 These @samp{-m} switches are supported in addition to the above
3970 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c
3971 index f076155c91a..9eb9b273ade 100644
3972 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c
3973 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c
3975 /* { dg-do compile } */
3976 -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
3977 +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
3979 typedef void (*dispatch_t)(long offset);
3981 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c
3982 index d7984f592fe..c63795e4127 100644
3983 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c
3984 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c
3986 /* { dg-do compile } */
3987 -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
3988 +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
3990 typedef void (*dispatch_t)(long offset);
3992 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c
3993 index 3257d0a2e16..82973cda771 100644
3994 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c
3995 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c
3997 /* { dg-do compile } */
3998 -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
3999 +/* { dg-options "-O2 -mno-indirect-branch-register -mno-indirect-branch-register -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
4001 typedef void (*dispatch_t)(long offset);
4003 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c
4004 index 7cab2df6474..a5f3d1cbed8 100644
4005 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c
4006 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c
4008 /* { dg-do compile } */
4009 -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
4010 +/* { dg-options "-O2 -mno-indirect-branch-register -mno-indirect-branch-register -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
4012 typedef void (*dispatch_t)(long offset);
4014 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c
4015 index b4836c38d6c..fcaa18d10b7 100644
4016 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c
4017 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c
4019 /* { dg-do compile { target *-*-linux* } } */
4020 -/* { dg-options "-O2 -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk" } */
4021 +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk" } */
4023 extern void bar (void);
4025 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c
4026 index 1f06bd1af74..e4649283d10 100644
4027 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c
4028 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c
4030 /* { dg-do compile { target *-*-linux* } } */
4031 -/* { dg-options "-O2 -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk" } */
4032 +/* { dg-options "-O2 -mno-indirect-branch-register -mno-indirect-branch-register -mno-indirect-branch-register -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk" } */
4034 extern void bar (void);
4036 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c
4037 index 0b3fef86a20..ebfb8aab937 100644
4038 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c
4039 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c
4041 /* { dg-do compile } */
4042 -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
4043 +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
4047 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c
4048 index 5f6cfc17b56..a08022db8e4 100644
4049 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c
4050 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c
4052 /* { dg-do compile } */
4053 -/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
4054 +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic" } */
4056 typedef void (*dispatch_t)(long offset);
4058 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c
4059 index b256160ec80..b257c695ad1 100644
4060 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c
4061 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c
4063 /* { dg-do compile } */
4064 -/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
4065 +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic" } */
4067 typedef void (*dispatch_t)(long offset);
4069 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c
4070 index 567c95051d6..dfb1370d23d 100644
4071 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c
4072 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c
4074 /* { dg-do compile } */
4075 -/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
4076 +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic" } */
4078 typedef void (*dispatch_t)(long offset);
4080 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c
4081 index 3b662af7d5d..a6e3f6f9f2b 100644
4082 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c
4083 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c
4085 /* { dg-do compile } */
4086 -/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
4087 +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic" } */
4089 typedef void (*dispatch_t)(long offset);
4091 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c
4092 index 98785a38248..4bb1c5f9220 100644
4093 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c
4094 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c
4096 /* { dg-do compile } */
4097 -/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
4098 +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic" } */
4100 typedef void (*dispatch_t)(long offset);
4102 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c
4103 index a498a39e404..4e33a638862 100644
4104 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c
4105 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c
4107 /* { dg-do compile } */
4108 -/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
4109 +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic" } */
4111 typedef void (*dispatch_t)(long offset);
4113 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c
4114 index 66f295d1eb6..427ba3ddbb4 100644
4115 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c
4116 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c
4118 /* { dg-do compile } */
4119 -/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
4120 +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic" } */
4124 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c
4125 index aacb814d737..dc7143414fb 100644
4126 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c
4127 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c
4129 /* { dg-do compile { target { ! x32 } } } */
4130 -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
4131 +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
4133 void (*dispatch) (char *);
4135 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c
4136 index 7b44dda23df..737c60946f6 100644
4137 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c
4138 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c
4140 /* { dg-do compile { target { ! x32 } } } */
4141 -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
4142 +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
4144 void (*dispatch) (char *);
4146 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c
4147 index 70b4fb36eea..d34485a0010 100644
4148 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c
4149 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c
4151 /* { dg-do compile { target { *-*-linux* && { ! x32 } } } } */
4152 -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fpic -fno-plt" } */
4153 +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fpic -fno-plt" } */
4157 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c
4158 index 3baf03ee77c..0e19830de4d 100644
4159 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c
4160 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c
4162 /* { dg-do compile { target { *-*-linux* && { ! x32 } } } } */
4163 -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fpic -fno-plt" } */
4164 +/* { dg-options "-O2 -mno-indirect-branch-register -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fpic -fno-plt" } */
4168 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c
4169 index 637fc3d3f4e..5c20a35ecec 100644
4170 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c
4171 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c
4173 /* { dg-do compile } */
4174 -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
4175 +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
4177 typedef void (*dispatch_t)(long offset);
4179 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c
4180 index ff9efe03fe6..b2fb6e1bcd2 100644
4181 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c
4182 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c
4184 /* { dg-do compile } */
4185 -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
4186 +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
4188 typedef void (*dispatch_t)(long offset);
4190 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c
4191 index 2686a5f2db4..9c84547cd7c 100644
4192 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c
4193 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c
4195 /* { dg-do compile } */
4196 -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
4197 +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
4199 typedef void (*dispatch_t)(long offset);
4201 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c
4202 index f07f6b214ad..457849564bb 100644
4203 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c
4204 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c
4206 /* { dg-do compile } */
4207 -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
4208 +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
4210 typedef void (*dispatch_t)(long offset);
4212 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c
4213 index 21740ac5b7f..5c07e02df6a 100644
4214 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c
4215 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c
4217 /* { dg-do compile { target *-*-linux* } } */
4218 -/* { dg-options "-O2 -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk-extern" } */
4219 +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk-extern" } */
4221 extern void bar (void);
4223 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c
4224 index a77c1f470b8..3eb440693a0 100644
4225 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c
4226 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c
4228 /* { dg-do compile { target *-*-linux* } } */
4229 -/* { dg-options "-O2 -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk-extern" } */
4230 +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk-extern" } */
4232 extern void bar (void);
4234 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c
4235 index e64910fd4aa..d4747ea0764 100644
4236 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c
4237 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c
4239 /* { dg-do compile } */
4240 -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
4241 +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
4245 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c
4246 index 365cf2ee226..536abfa74e4 100644
4247 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c
4248 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c
4250 /* { dg-do compile } */
4251 -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
4252 +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
4254 typedef void (*dispatch_t)(long offset);
4256 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c
4257 index 72646a4960b..bd2b6246aa1 100644
4258 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c
4259 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c
4261 /* { dg-do compile } */
4262 -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
4263 +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
4265 typedef void (*dispatch_t)(long offset);
4267 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c
4268 index f48945e3dfc..9885eebbcff 100644
4269 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c
4270 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c
4272 /* { dg-do compile } */
4273 -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
4274 +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
4276 typedef void (*dispatch_t)(long offset);
4278 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c
4279 index 4b1d558fc4e..7b3983949d2 100644
4280 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c
4281 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c
4283 /* { dg-do compile } */
4284 -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
4285 +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
4287 typedef void (*dispatch_t)(long offset);
4289 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c
4290 index 0f687c3b027..c6d77e10352 100644
4291 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c
4292 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c
4294 /* { dg-do compile { target *-*-linux* } } */
4295 -/* { dg-options "-O2 -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk-inline" } */
4296 +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk-inline" } */
4298 extern void bar (void);
4300 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c
4301 index b27c6fc96a2..6454827b780 100644
4302 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c
4303 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c
4305 /* { dg-do compile { target *-*-linux* } } */
4306 -/* { dg-options "-O2 -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk-inline" } */
4307 +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk-inline" } */
4309 extern void bar (void);
4311 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c
4312 index 2c496492eaa..cc592f89aba 100644
4313 --- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c
4314 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c
4316 /* { dg-do compile } */
4317 -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
4318 +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
4322 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-register-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-register-1.c
4323 new file mode 100644
4324 index 00000000000..7d396a31953
4326 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-register-1.c
4328 +/* { dg-do compile } */
4329 +/* { dg-options "-O2 -mindirect-branch=thunk -mindirect-branch-register -fno-pic" } */
4331 +typedef void (*dispatch_t)(long offset);
4333 +dispatch_t dispatch;
4336 +male_indirect_jump (long offset)
4341 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" } } */
4342 +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
4343 +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
4344 +/* { dg-final { scan-assembler "mov\[ \t\](%eax|%rax), \\((%esp|%rsp)\\)" } } */
4345 +/* { dg-final { scan-assembler {\tpause} } } */
4346 +/* { dg-final { scan-assembler-not "push(?:l|q)\[ \t\]*_?dispatch" } } */
4347 +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" } } */
4348 +/* { dg-final { scan-assembler-not "__x86_indirect_thunk\n" } } */
4349 +/* { dg-final { scan-assembler-not "__x86_indirect_thunk_bnd\n" } } */
4350 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-register-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-register-2.c
4351 new file mode 100644
4352 index 00000000000..e7e616bb271
4354 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-register-2.c
4356 +/* { dg-do compile } */
4357 +/* { dg-options "-O2 -mindirect-branch=thunk-inline -mindirect-branch-register -fno-pic" } */
4359 +typedef void (*dispatch_t)(long offset);
4361 +dispatch_t dispatch;
4364 +male_indirect_jump (long offset)
4369 +/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
4370 +/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
4371 +/* { dg-final { scan-assembler "mov\[ \t\](%eax|%rax), \\((%esp|%rsp)\\)" } } */
4372 +/* { dg-final { scan-assembler {\tpause} } } */
4373 +/* { dg-final { scan-assembler-not "push(?:l|q)\[ \t\]*_?dispatch" } } */
4374 +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" } } */
4375 +/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
4376 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-register-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-register-3.c
4377 new file mode 100644
4378 index 00000000000..5320e923be2
4380 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-register-3.c
4382 +/* { dg-do compile } */
4383 +/* { dg-options "-O2 -mindirect-branch=thunk-extern -mindirect-branch-register -fno-pic" } */
4385 +typedef void (*dispatch_t)(long offset);
4387 +dispatch_t dispatch;
4390 +male_indirect_jump (long offset)
4395 +/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" } } */
4396 +/* { dg-final { scan-assembler-not "push(?:l|q)\[ \t\]*_?dispatch" } } */
4397 +/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" } } */
4398 +/* { dg-final { scan-assembler-not {\t(pause|pause|nop)} } } */
4399 +/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
4400 +/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
4401 diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-10.c b/gcc/testsuite/gcc.target/i386/ret-thunk-10.c
4402 index 1630e2fa2b5..b4f9d48065d 100644
4403 --- a/gcc/testsuite/gcc.target/i386/ret-thunk-10.c
4404 +++ b/gcc/testsuite/gcc.target/i386/ret-thunk-10.c
4406 /* { dg-do compile } */
4407 -/* { dg-options "-O2 -mfunction-return=thunk-inline -mindirect-branch=thunk -fno-pic" } */
4408 +/* { dg-options "-O2 -mno-indirect-branch-register -mno-indirect-branch-register -mfunction-return=thunk-inline -mindirect-branch=thunk -fno-pic" } */
4410 extern void (*bar) (void);
4412 diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-11.c b/gcc/testsuite/gcc.target/i386/ret-thunk-11.c
4413 index 876159cf783..0312577a043 100644
4414 --- a/gcc/testsuite/gcc.target/i386/ret-thunk-11.c
4415 +++ b/gcc/testsuite/gcc.target/i386/ret-thunk-11.c
4417 /* { dg-do compile } */
4418 -/* { dg-options "-O2 -mfunction-return=thunk-extern -mindirect-branch=thunk -fno-pic" } */
4419 +/* { dg-options "-O2 -mno-indirect-branch-register -mno-indirect-branch-register -mno-indirect-branch-register -mno-indirect-branch-register -mfunction-return=thunk-extern -mindirect-branch=thunk -fno-pic" } */
4421 extern void (*bar) (void);
4423 diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-12.c b/gcc/testsuite/gcc.target/i386/ret-thunk-12.c
4424 index 01b0a02f80b..fa3181303c9 100644
4425 --- a/gcc/testsuite/gcc.target/i386/ret-thunk-12.c
4426 +++ b/gcc/testsuite/gcc.target/i386/ret-thunk-12.c
4428 /* { dg-do compile } */
4429 -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
4430 +/* { dg-options "-O2 -mno-indirect-branch-register -mno-indirect-branch-register -mno-indirect-branch-register -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
4432 extern void (*bar) (void);
4434 diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-13.c b/gcc/testsuite/gcc.target/i386/ret-thunk-13.c
4435 index e028c2b6a99..7a08e71c76b 100644
4436 --- a/gcc/testsuite/gcc.target/i386/ret-thunk-13.c
4437 +++ b/gcc/testsuite/gcc.target/i386/ret-thunk-13.c
4439 /* { dg-do compile } */
4440 -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
4441 +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
4443 extern void (*bar) (void);
4444 extern int foo (void) __attribute__ ((function_return("thunk")));
4445 diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-14.c b/gcc/testsuite/gcc.target/i386/ret-thunk-14.c
4446 index c14ee3ae4c0..dacf0c769fc 100644
4447 --- a/gcc/testsuite/gcc.target/i386/ret-thunk-14.c
4448 +++ b/gcc/testsuite/gcc.target/i386/ret-thunk-14.c
4450 /* { dg-do compile } */
4451 -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
4452 +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
4454 extern void (*bar) (void);
4456 diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-15.c b/gcc/testsuite/gcc.target/i386/ret-thunk-15.c
4457 index 2f21e138ec2..cf06a5f35c7 100644
4458 --- a/gcc/testsuite/gcc.target/i386/ret-thunk-15.c
4459 +++ b/gcc/testsuite/gcc.target/i386/ret-thunk-15.c
4461 /* { dg-do compile } */
4462 -/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=keep -fno-pic" } */
4463 +/* { dg-options "-O2 -mno-indirect-branch-register -mno-indirect-branch-register -mno-indirect-branch-register -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=keep -fno-pic" } */
4465 extern void (*bar) (void);
4467 diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-9.c b/gcc/testsuite/gcc.target/i386/ret-thunk-9.c
4468 index f6ccad98da7..6da5ab97081 100644
4469 --- a/gcc/testsuite/gcc.target/i386/ret-thunk-9.c
4470 +++ b/gcc/testsuite/gcc.target/i386/ret-thunk-9.c
4472 /* { dg-do compile } */
4473 -/* { dg-options "-O2 -mfunction-return=thunk -mindirect-branch=thunk -fno-pic" } */
4474 +/* { dg-options "-O2 -mno-indirect-branch-register -mno-indirect-branch-register -mfunction-return=thunk -mindirect-branch=thunk -fno-pic" } */
4476 extern void (*bar) (void);
4479 commit 92cf48982b587b20c78ede2a456151d2f497997d
4480 Author: H.J. Lu <hjl.tools@gmail.com>
4481 Date: Sat Jan 6 22:29:56 2018 -0800
4483 x86: Add 'V' register operand modifier
4485 Add 'V', a special modifier which prints the name of the full integer
4486 register without '%'. For
4488 extern void (*func_p) (void);
4493 asm ("call __x86_indirect_thunk_%V0" : : "a" (func_p));
4499 movq func_p(%rip), %rax
4500 call __x86_indirect_thunk_rax
4505 * config/i386/i386.c (print_reg): Print the name of the full
4506 integer register without '%'.
4507 (ix86_print_operand): Handle 'V'.
4508 * doc/extend.texi: Document 'V' modifier.
4512 * gcc.target/i386/indirect-thunk-register-4.c: New test.
4514 diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
4515 index 4bfe2fa8c1d..e32de13688a 100644
4516 --- a/gcc/config/i386/i386.c
4517 +++ b/gcc/config/i386/i386.c
4518 @@ -17925,6 +17925,7 @@ put_condition_code (enum rtx_code code, machine_mode mode, bool reverse,
4519 If CODE is 'h', pretend the reg is the 'high' byte register.
4520 If CODE is 'y', print "st(0)" instead of "st", if the reg is stack op.
4521 If CODE is 'd', duplicate the operand for AVX instruction.
4522 + If CODE is 'V', print naked full integer register name without %.
4526 @@ -17935,7 +17936,7 @@ print_reg (rtx x, int code, FILE *file)
4530 - if (ASSEMBLER_DIALECT == ASM_ATT)
4531 + if (ASSEMBLER_DIALECT == ASM_ATT && code != 'V')
4535 @@ -17983,6 +17984,14 @@ print_reg (rtx x, int code, FILE *file)
4541 + if (GENERAL_REGNO_P (regno))
4542 + msize = GET_MODE_SIZE (word_mode);
4544 + error ("'V' modifier on non-integer register");
4547 duplicated = code == 'd' && TARGET_AVX;
4550 @@ -18102,6 +18111,7 @@ print_reg (rtx x, int code, FILE *file)
4551 & -- print some in-use local-dynamic symbol name.
4552 H -- print a memory address offset by 8; used for sse high-parts
4553 Y -- print condition for XOP pcom* instruction.
4554 + V -- print naked full integer register name without %.
4555 + -- print a branch hint as 'cs' or 'ds' prefix
4556 ; -- print a semicolon (after prefixes due to bug in older gas).
4557 ~ -- print "i" if TARGET_AVX2, "f" otherwise.
4558 @@ -18326,6 +18336,7 @@ ix86_print_operand (FILE *file, rtx x, int code)
4566 diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
4567 index 46e0a3623a6..9db9e0e27e9 100644
4568 --- a/gcc/doc/extend.texi
4569 +++ b/gcc/doc/extend.texi
4570 @@ -8778,6 +8778,9 @@ The table below shows the list of supported modifiers and their effects.
4574 +@code{V} is a special modifier which prints the name of the full integer
4575 +register without @code{%}.
4577 @anchor{x86floatingpointasmoperands}
4578 @subsubsection x86 Floating-Point @code{asm} Operands
4580 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-register-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-register-4.c
4581 new file mode 100644
4582 index 00000000000..f0cd9b75be8
4584 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-register-4.c
4586 +/* { dg-do compile } */
4587 +/* { dg-options "-O2 -mindirect-branch=keep -fno-pic" } */
4589 +extern void (*func_p) (void);
4594 + asm("call __x86_indirect_thunk_%V0" : : "a" (func_p));
4597 +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_eax" { target ia32 } } } */
4598 +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_rax" { target { ! ia32 } } } } */
4600 commit a19909d946ad1b8588595fab0b59eb9d4e027838
4601 Author: H.J. Lu <hjl.tools@gmail.com>
4602 Date: Sat Jan 13 18:01:54 2018 -0800
4604 x86: Disallow -mindirect-branch=/-mfunction-return= with -mcmodel=large
4606 Since the thunk function may not be reachable in large code model,
4607 -mcmodel=large is incompatible with -mindirect-branch=thunk,
4608 -mindirect-branch=thunk-extern, -mfunction-return=thunk and
4609 -mfunction-return=thunk-extern. Issue an error when they are used with
4614 * config/i386/i386.c (ix86_set_indirect_branch_type): Disallow
4615 -mcmodel=large with -mindirect-branch=thunk,
4616 -mindirect-branch=thunk-extern, -mfunction-return=thunk and
4617 -mfunction-return=thunk-extern.
4618 * doc/invoke.texi: Document -mcmodel=large is incompatible with
4619 -mindirect-branch=thunk, -mindirect-branch=thunk-extern,
4620 -mfunction-return=thunk and -mfunction-return=thunk-extern.
4624 * gcc.target/i386/indirect-thunk-10.c: New test.
4625 * gcc.target/i386/indirect-thunk-8.c: Likewise.
4626 * gcc.target/i386/indirect-thunk-9.c: Likewise.
4627 * gcc.target/i386/indirect-thunk-attr-10.c: Likewise.
4628 * gcc.target/i386/indirect-thunk-attr-11.c: Likewise.
4629 * gcc.target/i386/indirect-thunk-attr-9.c: Likewise.
4630 * gcc.target/i386/ret-thunk-17.c: Likewise.
4631 * gcc.target/i386/ret-thunk-18.c: Likewise.
4632 * gcc.target/i386/ret-thunk-19.c: Likewise.
4633 * gcc.target/i386/ret-thunk-20.c: Likewise.
4634 * gcc.target/i386/ret-thunk-21.c: Likewise.
4636 diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
4637 index e32de13688a..318a71840c9 100644
4638 --- a/gcc/config/i386/i386.c
4639 +++ b/gcc/config/i386/i386.c
4640 @@ -7187,6 +7187,19 @@ ix86_set_indirect_branch_type (tree fndecl)
4643 cfun->machine->indirect_branch_type = ix86_indirect_branch;
4645 + /* -mcmodel=large is not compatible with -mindirect-branch=thunk
4646 + nor -mindirect-branch=thunk-extern. */
4647 + if ((ix86_cmodel == CM_LARGE || ix86_cmodel == CM_LARGE_PIC)
4648 + && ((cfun->machine->indirect_branch_type
4649 + == indirect_branch_thunk_extern)
4650 + || (cfun->machine->indirect_branch_type
4651 + == indirect_branch_thunk)))
4652 + error ("%<-mindirect-branch=%s%> and %<-mcmodel=large%> are not "
4654 + ((cfun->machine->indirect_branch_type
4655 + == indirect_branch_thunk_extern)
4656 + ? "thunk-extern" : "thunk"));
4659 if (cfun->machine->function_return_type == indirect_branch_unset)
4660 @@ -7212,6 +7225,19 @@ ix86_set_indirect_branch_type (tree fndecl)
4663 cfun->machine->function_return_type = ix86_function_return;
4665 + /* -mcmodel=large is not compatible with -mfunction-return=thunk
4666 + nor -mfunction-return=thunk-extern. */
4667 + if ((ix86_cmodel == CM_LARGE || ix86_cmodel == CM_LARGE_PIC)
4668 + && ((cfun->machine->function_return_type
4669 + == indirect_branch_thunk_extern)
4670 + || (cfun->machine->function_return_type
4671 + == indirect_branch_thunk)))
4672 + error ("%<-mfunction-return=%s%> and %<-mcmodel=large%> are not "
4674 + ((cfun->machine->function_return_type
4675 + == indirect_branch_thunk_extern)
4676 + ? "thunk-extern" : "thunk"));
4680 diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
4681 index 1e572b1f9a2..6f3c344476c 100644
4682 --- a/gcc/doc/invoke.texi
4683 +++ b/gcc/doc/invoke.texi
4684 @@ -25699,6 +25699,11 @@ to external call and return thunk provided in a separate object file.
4685 You can control this behavior for a specific function by using the
4686 function attribute @code{indirect_branch}. @xref{Function Attributes}.
4688 +Note that @option{-mcmodel=large} is incompatible with
4689 +@option{-mindirect-branch=thunk} nor
4690 +@option{-mindirect-branch=thunk-extern} since the thunk function may
4691 +not be reachable in large code model.
4693 @item -mfunction-return=@var{choice}
4694 @opindex -mfunction-return
4695 Convert function return with @var{choice}. The default is @samp{keep},
4696 @@ -25710,6 +25715,12 @@ object file. You can control this behavior for a specific function by
4697 using the function attribute @code{function_return}.
4698 @xref{Function Attributes}.
4700 +Note that @option{-mcmodel=large} is incompatible with
4701 +@option{-mfunction-return=thunk} nor
4702 +@option{-mfunction-return=thunk-extern} since the thunk function may
4703 +not be reachable in large code model.
4706 @item -mindirect-branch-register
4707 @opindex -mindirect-branch-register
4708 Force indirect call and jump via register.
4709 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-10.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-10.c
4710 new file mode 100644
4711 index 00000000000..a0674bd2363
4713 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-10.c
4715 +/* { dg-do compile { target { lp64 } } } */
4716 +/* { dg-options "-O2 -mindirect-branch=thunk-inline -mfunction-return=keep -mcmodel=large" } */
4722 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-8.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-8.c
4723 new file mode 100644
4724 index 00000000000..7a80a8986e8
4726 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-8.c
4728 +/* { dg-do compile { target { lp64 } } } */
4729 +/* { dg-options "-O2 -mindirect-branch=thunk -mfunction-return=keep -mcmodel=large" } */
4733 +{ /* { dg-error "'-mindirect-branch=thunk' and '-mcmodel=large' are not compatible" } */
4735 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-9.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-9.c
4736 new file mode 100644
4737 index 00000000000..d4d45c5114d
4739 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-9.c
4741 +/* { dg-do compile { target { lp64 } } } */
4742 +/* { dg-options "-O2 -mindirect-branch=thunk-extern -mfunction-return=keep -mcmodel=large" } */
4746 +{ /* { dg-error "'-mindirect-branch=thunk-extern' and '-mcmodel=large' are not compatible" } */
4748 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-10.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-10.c
4749 new file mode 100644
4750 index 00000000000..3a2aeaddbc5
4752 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-10.c
4754 +/* { dg-do compile { target { lp64 } } } */
4755 +/* { dg-options "-O2 -mindirect-branch=keep -mfunction-return=keep -mcmodel=large" } */
4756 +/* { dg-additional-options "-fPIC" { target fpic } } */
4758 +__attribute__ ((indirect_branch("thunk-extern")))
4761 +{ /* { dg-error "'-mindirect-branch=thunk-extern' and '-mcmodel=large' are not compatible" } */
4763 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-11.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-11.c
4764 new file mode 100644
4765 index 00000000000..8e52f032b6c
4767 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-11.c
4769 +/* { dg-do compile { target { lp64 } } } */
4770 +/* { dg-options "-O2 -mindirect-branch=keep -mfunction-return=keep -mcmodel=large" } */
4771 +/* { dg-additional-options "-fPIC" { target fpic } } */
4773 +__attribute__ ((indirect_branch("thunk-inline")))
4778 diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-9.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-9.c
4779 new file mode 100644
4780 index 00000000000..bdaa4f6911b
4782 +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-9.c
4784 +/* { dg-do compile { target { lp64 } } } */
4785 +/* { dg-options "-O2 -mindirect-branch=keep -mfunction-return=keep -mcmodel=large" } */
4786 +/* { dg-additional-options "-fPIC" { target fpic } } */
4788 +__attribute__ ((indirect_branch("thunk")))
4791 +{ /* { dg-error "'-mindirect-branch=thunk' and '-mcmodel=large' are not compatible" } */
4793 diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-17.c b/gcc/testsuite/gcc.target/i386/ret-thunk-17.c
4794 new file mode 100644
4795 index 00000000000..0605e2c6542
4797 +++ b/gcc/testsuite/gcc.target/i386/ret-thunk-17.c
4799 +/* { dg-do compile { target { lp64 } } } */
4800 +/* { dg-options "-O2 -mfunction-return=thunk -mindirect-branch=keep -mcmodel=large" } */
4804 +{ /* { dg-error "'-mfunction-return=thunk' and '-mcmodel=large' are not compatible" } */
4806 diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-18.c b/gcc/testsuite/gcc.target/i386/ret-thunk-18.c
4807 new file mode 100644
4808 index 00000000000..307019dc242
4810 +++ b/gcc/testsuite/gcc.target/i386/ret-thunk-18.c
4812 +/* { dg-do compile { target { lp64 } } } */
4813 +/* { dg-options "-O2 -mfunction-return=thunk-extern -mindirect-branch=keep -mcmodel=large" } */
4814 +/* { dg-additional-options "-fPIC" { target fpic } } */
4818 +{ /* { dg-error "'-mfunction-return=thunk-extern' and '-mcmodel=large' are not compatible" } */
4820 diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-19.c b/gcc/testsuite/gcc.target/i386/ret-thunk-19.c
4821 new file mode 100644
4822 index 00000000000..772617f4010
4824 +++ b/gcc/testsuite/gcc.target/i386/ret-thunk-19.c
4826 +/* { dg-do compile { target { lp64 } } } */
4827 +/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=keep -mcmodel=large" } */
4829 +__attribute__ ((function_return("thunk")))
4832 +{ /* { dg-error "'-mfunction-return=thunk' and '-mcmodel=large' are not compatible" } */
4834 diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-20.c b/gcc/testsuite/gcc.target/i386/ret-thunk-20.c
4835 new file mode 100644
4836 index 00000000000..1e9f9bd5a66
4838 +++ b/gcc/testsuite/gcc.target/i386/ret-thunk-20.c
4840 +/* { dg-do compile { target { lp64 } } } */
4841 +/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=keep -mcmodel=large" } */
4842 +/* { dg-additional-options "-fPIC" { target fpic } } */
4844 +__attribute__ ((function_return("thunk-extern")))
4847 +{ /* { dg-error "'-mfunction-return=thunk-extern' and '-mcmodel=large' are not compatible" } */
4849 diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-21.c b/gcc/testsuite/gcc.target/i386/ret-thunk-21.c
4850 new file mode 100644
4851 index 00000000000..eea07f7abe1
4853 +++ b/gcc/testsuite/gcc.target/i386/ret-thunk-21.c
4855 +/* { dg-do compile { target { lp64 } } } */
4856 +/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=keep -mcmodel=large" } */
4857 +/* { dg-additional-options "-fPIC" { target fpic } } */
4859 +__attribute__ ((function_return("thunk-inline")))