Gentoo Archives: gentoo-commits

From: Aric Belsito <lluixhi@×××××.com>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/musl:master commit in: sys-devel/gcc/files/, sys-devel/gcc/
Date: Tue, 16 Jan 2018 04:51:28
Message-Id: 1516078179.280308c77f05895c44d9eadd35ca8e505e9be30c.lluixhi@gentoo
1 commit: 280308c77f05895c44d9eadd35ca8e505e9be30c
2 Author: Aric Belsito <lluixhi <AT> gmail <DOT> com>
3 AuthorDate: Tue Jan 16 04:49:39 2018 +0000
4 Commit: Aric Belsito <lluixhi <AT> gmail <DOT> com>
5 CommitDate: Tue Jan 16 04:49:39 2018 +0000
6 URL: https://gitweb.gentoo.org/proj/musl.git/commit/?id=280308c7
7
8 sys-devel/gcc: sync 7.2.0-r1 with upstream
9
10 Add patches for spectre *WARNING, EXPERIMENTAL PORT*
11
12 The gcc-7.2.0-move-struct-ix86_frame-to-machine-function patches are
13 designed for gcc 7, but the spectre patches are taken from the final
14 version of the gcc 8 patchset, adapted for gcc 7.
15
16 ...ove-struct-ix86_frame-to-machine-function.patch | 237 +++
17 ...ove-struct-ix86_frame-to-machine-function.patch | 68 +
18 ...ove-struct-ix86_frame-to-machine-function.patch | 53 +
19 .../gcc/files/spectre-0001-mindirect-branch.patch | 2111 ++++++++++++++++++++
20 .../gcc/files/spectre-0002-mfunction-return.patch | 1200 +++++++++++
21 .../spectre-0003-mindirect-branch-register.patch | 887 ++++++++
22 .../files/spectre-0004-v-register-modifier.patch | 128 ++
23 .../gcc/files/spectre-0005-mcmodel-large.patch | 292 +++
24 sys-devel/gcc/gcc-7.2.0-r1.ebuild | 14 +-
25 9 files changed, 4988 insertions(+), 2 deletions(-)
26
27 diff --git a/sys-devel/gcc/files/0001-gcc-7.2.0-move-struct-ix86_frame-to-machine-function.patch b/sys-devel/gcc/files/0001-gcc-7.2.0-move-struct-ix86_frame-to-machine-function.patch
28 new file mode 100644
29 index 0000000..d85ed2c
30 --- /dev/null
31 +++ b/sys-devel/gcc/files/0001-gcc-7.2.0-move-struct-ix86_frame-to-machine-function.patch
32 @@ -0,0 +1,237 @@
33 +From: "H.J. Lu" <hjl.tools@×××××.com>
34 +To: gcc-patches@×××××××.org
35 +Subject: [1/3] GCC 7: i386: Move struct ix86_frame to machine_function
36 +Date: Sun, 14 Jan 2018 07:02:35 -0800
37 +
38 +Make ix86_frame available to i386 code generation. This is needed to
39 +backport the patch set of -mindirect-branch= to mitigate variant #2 of
40 +the speculative execution vulnerabilities on x86 processors identified
41 +by CVE-2017-5715, aka Spectre.
42 +
43 + Backport from mainline
44 + * config/i386/i386.c (ix86_frame): Moved to ...
45 + * config/i386/i386.h (ix86_frame): Here.
46 + (machine_function): Add frame.
47 + * config/i386/i386.c (ix86_compute_frame_layout): Repace the
48 + frame argument with &cfun->machine->frame.
49 + (ix86_can_use_return_insn_p): Don't pass &frame to
50 + ix86_compute_frame_layout. Copy frame from cfun->machine->frame.
51 + (ix86_can_eliminate): Likewise.
52 + (ix86_expand_prologue): Likewise.
53 + (ix86_expand_epilogue): Likewise.
54 + (ix86_expand_split_stack_prologue): Likewise.
55 +---
56 + gcc/config/i386/i386.c | 68 ++++++++++----------------------------------------
57 + gcc/config/i386/i386.h | 53 ++++++++++++++++++++++++++++++++++++++-
58 + 2 files changed, 65 insertions(+), 56 deletions(-)
59 +
60 +diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
61 +index 8a3782c0298..813337242d8 100644
62 +--- a/gcc/config/i386/i386.c
63 ++++ b/gcc/config/i386/i386.c
64 +@@ -2444,53 +2444,6 @@ struct GTY(()) stack_local_entry {
65 + struct stack_local_entry *next;
66 + };
67 +
68 +-/* Structure describing stack frame layout.
69 +- Stack grows downward:
70 +-
71 +- [arguments]
72 +- <- ARG_POINTER
73 +- saved pc
74 +-
75 +- saved static chain if ix86_static_chain_on_stack
76 +-
77 +- saved frame pointer if frame_pointer_needed
78 +- <- HARD_FRAME_POINTER
79 +- [saved regs]
80 +- <- regs_save_offset
81 +- [padding0]
82 +-
83 +- [saved SSE regs]
84 +- <- sse_regs_save_offset
85 +- [padding1] |
86 +- | <- FRAME_POINTER
87 +- [va_arg registers] |
88 +- |
89 +- [frame] |
90 +- |
91 +- [padding2] | = to_allocate
92 +- <- STACK_POINTER
93 +- */
94 +-struct ix86_frame
95 +-{
96 +- int nsseregs;
97 +- int nregs;
98 +- int va_arg_size;
99 +- int red_zone_size;
100 +- int outgoing_arguments_size;
101 +-
102 +- /* The offsets relative to ARG_POINTER. */
103 +- HOST_WIDE_INT frame_pointer_offset;
104 +- HOST_WIDE_INT hard_frame_pointer_offset;
105 +- HOST_WIDE_INT stack_pointer_offset;
106 +- HOST_WIDE_INT hfp_save_offset;
107 +- HOST_WIDE_INT reg_save_offset;
108 +- HOST_WIDE_INT sse_reg_save_offset;
109 +-
110 +- /* When save_regs_using_mov is set, emit prologue using
111 +- move instead of push instructions. */
112 +- bool save_regs_using_mov;
113 +-};
114 +-
115 + /* Which cpu are we scheduling for. */
116 + enum attr_cpu ix86_schedule;
117 +
118 +@@ -2582,7 +2535,7 @@ static unsigned int ix86_function_arg_boundary (machine_mode,
119 + const_tree);
120 + static rtx ix86_static_chain (const_tree, bool);
121 + static int ix86_function_regparm (const_tree, const_tree);
122 +-static void ix86_compute_frame_layout (struct ix86_frame *);
123 ++static void ix86_compute_frame_layout (void);
124 + static bool ix86_expand_vector_init_one_nonzero (bool, machine_mode,
125 + rtx, rtx, int);
126 + static void ix86_add_new_builtins (HOST_WIDE_INT, HOST_WIDE_INT);
127 +@@ -11903,7 +11856,8 @@ ix86_can_use_return_insn_p (void)
128 + if (crtl->args.pops_args && crtl->args.size >= 32768)
129 + return 0;
130 +
131 +- ix86_compute_frame_layout (&frame);
132 ++ ix86_compute_frame_layout ();
133 ++ frame = cfun->machine->frame;
134 + return (frame.stack_pointer_offset == UNITS_PER_WORD
135 + && (frame.nregs + frame.nsseregs) == 0);
136 + }
137 +@@ -12389,8 +12343,8 @@ ix86_can_eliminate (const int from, const int to)
138 + HOST_WIDE_INT
139 + ix86_initial_elimination_offset (int from, int to)
140 + {
141 +- struct ix86_frame frame;
142 +- ix86_compute_frame_layout (&frame);
143 ++ ix86_compute_frame_layout ();
144 ++ struct ix86_frame frame = cfun->machine->frame;
145 +
146 + if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
147 + return frame.hard_frame_pointer_offset;
148 +@@ -12429,8 +12383,9 @@ ix86_builtin_setjmp_frame_value (void)
149 + /* Fill structure ix86_frame about frame of currently computed function. */
150 +
151 + static void
152 +-ix86_compute_frame_layout (struct ix86_frame *frame)
153 ++ix86_compute_frame_layout (void)
154 + {
155 ++ struct ix86_frame *frame = &cfun->machine->frame;
156 + unsigned HOST_WIDE_INT stack_alignment_needed;
157 + HOST_WIDE_INT offset;
158 + unsigned HOST_WIDE_INT preferred_alignment;
159 +@@ -13737,7 +13692,8 @@ ix86_expand_prologue (void)
160 + m->fs.sp_offset = INCOMING_FRAME_SP_OFFSET;
161 + m->fs.sp_valid = true;
162 +
163 +- ix86_compute_frame_layout (&frame);
164 ++ ix86_compute_frame_layout ();
165 ++ frame = m->frame;
166 +
167 + if (!TARGET_64BIT && ix86_function_ms_hook_prologue (current_function_decl))
168 + {
169 +@@ -14405,7 +14361,8 @@ ix86_expand_epilogue (int style)
170 + bool using_drap;
171 +
172 + ix86_finalize_stack_realign_flags ();
173 +- ix86_compute_frame_layout (&frame);
174 ++ ix86_compute_frame_layout ();
175 ++ frame = m->frame;
176 +
177 + m->fs.sp_valid = (!frame_pointer_needed
178 + || (crtl->sp_is_unchanging
179 +@@ -14915,7 +14872,8 @@ ix86_expand_split_stack_prologue (void)
180 + gcc_assert (flag_split_stack && reload_completed);
181 +
182 + ix86_finalize_stack_realign_flags ();
183 +- ix86_compute_frame_layout (&frame);
184 ++ ix86_compute_frame_layout ();
185 ++ frame = cfun->machine->frame;
186 + allocate = frame.stack_pointer_offset - INCOMING_FRAME_SP_OFFSET;
187 +
188 + /* This is the label we will branch to if we have enough stack
189 +diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
190 +index 9c776dc5172..f9b91286a01 100644
191 +--- a/gcc/config/i386/i386.h
192 ++++ b/gcc/config/i386/i386.h
193 +@@ -2451,9 +2451,56 @@ enum avx_u128_state
194 +
195 + #define FASTCALL_PREFIX '@'
196 +
197 ++#ifndef USED_FOR_TARGET
198 ++/* Structure describing stack frame layout.
199 ++ Stack grows downward:
200 ++
201 ++ [arguments]
202 ++ <- ARG_POINTER
203 ++ saved pc
204 ++
205 ++ saved static chain if ix86_static_chain_on_stack
206 ++
207 ++ saved frame pointer if frame_pointer_needed
208 ++ <- HARD_FRAME_POINTER
209 ++ [saved regs]
210 ++ <- regs_save_offset
211 ++ [padding0]
212 ++
213 ++ [saved SSE regs]
214 ++ <- sse_regs_save_offset
215 ++ [padding1] |
216 ++ | <- FRAME_POINTER
217 ++ [va_arg registers] |
218 ++ |
219 ++ [frame] |
220 ++ |
221 ++ [padding2] | = to_allocate
222 ++ <- STACK_POINTER
223 ++ */
224 ++struct GTY(()) ix86_frame
225 ++{
226 ++ int nsseregs;
227 ++ int nregs;
228 ++ int va_arg_size;
229 ++ int red_zone_size;
230 ++ int outgoing_arguments_size;
231 ++
232 ++ /* The offsets relative to ARG_POINTER. */
233 ++ HOST_WIDE_INT frame_pointer_offset;
234 ++ HOST_WIDE_INT hard_frame_pointer_offset;
235 ++ HOST_WIDE_INT stack_pointer_offset;
236 ++ HOST_WIDE_INT hfp_save_offset;
237 ++ HOST_WIDE_INT reg_save_offset;
238 ++ HOST_WIDE_INT sse_reg_save_offset;
239 ++
240 ++ /* When save_regs_using_mov is set, emit prologue using
241 ++ move instead of push instructions. */
242 ++ bool save_regs_using_mov;
243 ++};
244 ++
245 + /* Machine specific frame tracking during prologue/epilogue generation. */
246 +
247 +-#ifndef USED_FOR_TARGET
248 + struct GTY(()) machine_frame_state
249 + {
250 + /* This pair tracks the currently active CFA as reg+offset. When reg
251 +@@ -2512,6 +2559,9 @@ struct GTY(()) machine_function {
252 + int varargs_fpr_size;
253 + int optimize_mode_switching[MAX_386_ENTITIES];
254 +
255 ++ /* Cached initial frame layout for the current function. */
256 ++ struct ix86_frame frame;
257 ++
258 + /* Number of saved registers USE_FAST_PROLOGUE_EPILOGUE
259 + has been computed for. */
260 + int use_fast_prologue_epilogue_nregs;
261 +@@ -2594,6 +2644,7 @@ struct GTY(()) machine_function {
262 + #define ix86_current_function_calls_tls_descriptor \
263 + (ix86_tls_descriptor_calls_expanded_in_cfun && df_regs_ever_live_p (SP_REG))
264 + #define ix86_static_chain_on_stack (cfun->machine->static_chain_on_stack)
265 ++#define ix86_red_zone_size (cfun->machine->frame.red_zone_size)
266 +
267 + /* Control behavior of x86_file_start. */
268 + #define X86_FILE_START_VERSION_DIRECTIVE false
269 +
270
271 diff --git a/sys-devel/gcc/files/0002-gcc-7.2.0-move-struct-ix86_frame-to-machine-function.patch b/sys-devel/gcc/files/0002-gcc-7.2.0-move-struct-ix86_frame-to-machine-function.patch
272 new file mode 100644
273 index 0000000..a086d03
274 --- /dev/null
275 +++ b/sys-devel/gcc/files/0002-gcc-7.2.0-move-struct-ix86_frame-to-machine-function.patch
276 @@ -0,0 +1,68 @@
277 +From: "H.J. Lu" <hjl.tools@×××××.com>
278 +To: gcc-patches@×××××××.org
279 +Subject: [2/3] GCC 7: i386: Use reference of struct ix86_frame to avoid copy
280 +Date: Sun, 14 Jan 2018 07:02:36 -0800
281 +
282 +When there is no need to make a copy of ix86_frame, we can use reference
283 +of struct ix86_frame to avoid copy.
284 +
285 +Tested on x86-64.
286 +
287 + Backport from mainline
288 + * config/i386/i386.c (ix86_can_use_return_insn_p): Use reference
289 + of struct ix86_frame.
290 + (ix86_initial_elimination_offset): Likewise.
291 + (ix86_expand_split_stack_prologue): Likewise.
292 +---
293 + gcc/config/i386/i386.c | 9 +++------
294 + 1 file changed, 3 insertions(+), 6 deletions(-)
295 +
296 +diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
297 +index 813337242d8..397ef7cac26 100644
298 +--- a/gcc/config/i386/i386.c
299 ++++ b/gcc/config/i386/i386.c
300 +@@ -11843,8 +11843,6 @@ symbolic_reference_mentioned_p (rtx op)
301 + bool
302 + ix86_can_use_return_insn_p (void)
303 + {
304 +- struct ix86_frame frame;
305 +-
306 + /* Don't use `ret' instruction in interrupt handler. */
307 + if (! reload_completed
308 + || frame_pointer_needed
309 +@@ -11857,7 +11855,7 @@ ix86_can_use_return_insn_p (void)
310 + return 0;
311 +
312 + ix86_compute_frame_layout ();
313 +- frame = cfun->machine->frame;
314 ++ struct ix86_frame &frame = cfun->machine->frame;
315 + return (frame.stack_pointer_offset == UNITS_PER_WORD
316 + && (frame.nregs + frame.nsseregs) == 0);
317 + }
318 +@@ -12344,7 +12342,7 @@ HOST_WIDE_INT
319 + ix86_initial_elimination_offset (int from, int to)
320 + {
321 + ix86_compute_frame_layout ();
322 +- struct ix86_frame frame = cfun->machine->frame;
323 ++ struct ix86_frame &frame = cfun->machine->frame;
324 +
325 + if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
326 + return frame.hard_frame_pointer_offset;
327 +@@ -14860,7 +14858,6 @@ static GTY(()) rtx split_stack_fn_large;
328 + void
329 + ix86_expand_split_stack_prologue (void)
330 + {
331 +- struct ix86_frame frame;
332 + HOST_WIDE_INT allocate;
333 + unsigned HOST_WIDE_INT args_size;
334 + rtx_code_label *label;
335 +@@ -14873,7 +14870,7 @@ ix86_expand_split_stack_prologue (void)
336 +
337 + ix86_finalize_stack_realign_flags ();
338 + ix86_compute_frame_layout ();
339 +- frame = cfun->machine->frame;
340 ++ struct ix86_frame &frame = cfun->machine->frame;
341 + allocate = frame.stack_pointer_offset - INCOMING_FRAME_SP_OFFSET;
342 +
343 + /* This is the label we will branch to if we have enough stack
344 +
345
346 diff --git a/sys-devel/gcc/files/0003-gcc-7.2.0-move-struct-ix86_frame-to-machine-function.patch b/sys-devel/gcc/files/0003-gcc-7.2.0-move-struct-ix86_frame-to-machine-function.patch
347 new file mode 100644
348 index 0000000..2f27301
349 --- /dev/null
350 +++ b/sys-devel/gcc/files/0003-gcc-7.2.0-move-struct-ix86_frame-to-machine-function.patch
351 @@ -0,0 +1,53 @@
352 +From: "H.J. Lu" <hjl.tools@×××××.com>
353 +To: gcc-patches@×××××××.org
354 +Subject: [3/3] GCC 7: i386: More use reference of struct ix86_frame to avoid
355 + copy
356 +Date: Sun, 14 Jan 2018 07:02:37 -0800
357 +
358 +When there is no need to make a copy of ix86_frame, we can use reference
359 +of struct ix86_frame to avoid copy.
360 +
361 + Backport from mainline
362 + * config/i386/i386.c (ix86_expand_prologue): Use reference of
363 + struct ix86_frame.
364 + (ix86_expand_epilogue): Likewise.
365 +---
366 + gcc/config/i386/i386.c | 6 ++----
367 + 1 file changed, 2 insertions(+), 4 deletions(-)
368 +
369 +diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
370 +index 397ef7cac26..986e6d79584 100644
371 +--- a/gcc/config/i386/i386.c
372 ++++ b/gcc/config/i386/i386.c
373 +@@ -13667,7 +13667,6 @@ ix86_expand_prologue (void)
374 + {
375 + struct machine_function *m = cfun->machine;
376 + rtx insn, t;
377 +- struct ix86_frame frame;
378 + HOST_WIDE_INT allocate;
379 + bool int_registers_saved;
380 + bool sse_registers_saved;
381 +@@ -13691,7 +13690,7 @@ ix86_expand_prologue (void)
382 + m->fs.sp_valid = true;
383 +
384 + ix86_compute_frame_layout ();
385 +- frame = m->frame;
386 ++ struct ix86_frame &frame = cfun->machine->frame;
387 +
388 + if (!TARGET_64BIT && ix86_function_ms_hook_prologue (current_function_decl))
389 + {
390 +@@ -14354,13 +14353,12 @@ ix86_expand_epilogue (int style)
391 + {
392 + struct machine_function *m = cfun->machine;
393 + struct machine_frame_state frame_state_save = m->fs;
394 +- struct ix86_frame frame;
395 + bool restore_regs_via_mov;
396 + bool using_drap;
397 +
398 + ix86_finalize_stack_realign_flags ();
399 + ix86_compute_frame_layout ();
400 +- frame = m->frame;
401 ++ struct ix86_frame &frame = cfun->machine->frame;
402 +
403 + m->fs.sp_valid = (!frame_pointer_needed
404 + || (crtl->sp_is_unchanging
405
406 diff --git a/sys-devel/gcc/files/spectre-0001-mindirect-branch.patch b/sys-devel/gcc/files/spectre-0001-mindirect-branch.patch
407 new file mode 100644
408 index 0000000..2e03cee
409 --- /dev/null
410 +++ b/sys-devel/gcc/files/spectre-0001-mindirect-branch.patch
411 @@ -0,0 +1,2111 @@
412 +From: "H dot J dot Lu" <hjl dot tools at gmail dot com>
413 +To: gcc-patches at gcc dot gnu dot org
414 +Subject: [PATCH 1/4] x86: Add -mindirect-branch=
415 +Date: Fri, 12 Jan 2018 05:15:46 -0800
416 +
417 +Add -mindirect-branch= option to convert indirect call and jump to call
418 +and return thunks. The default is 'keep', which keeps indirect call and
419 +jump unmodified. 'thunk' converts indirect call and jump to call and
420 +return thunk. 'thunk-inline' converts indirect call and jump to inlined
421 +call and return thunk. 'thunk-extern' converts indirect call and jump to
422 +external call and return thunk provided in a separate object file. You
423 +can control this behavior for a specific function by using the function
424 +attribute indirect_branch.
425 +
426 +2 kinds of thunks are geneated. Memory thunk where the function address
427 +is at the top of the stack:
428 +
429 +__x86_indirect_thunk:
430 + call L2
431 +L1:
432 + pause
433 + jmp L1
434 +L2:
435 + lea 8(%rsp), %rsp|lea 4(%esp), %esp
436 + ret
437 +
438 +Indirect jmp via memory, "jmp mem", is converted to
439 +
440 + push memory
441 + jmp __x86_indirect_thunk
442 +
443 +Indirect call via memory, "call mem", is converted to
444 +
445 + jmp L2
446 +L1:
447 + push [mem]
448 + jmp __x86_indirect_thunk
449 +L2:
450 + call L1
451 +
452 +Register thunk where the function address is in a register, reg:
453 +
454 +__x86_indirect_thunk_reg:
455 + call L2
456 +L1:
457 + pause
458 + jmp L1
459 +L2:
460 + movq %reg, (%rsp)|movl %reg, (%esp)
461 + ret
462 +
463 +where reg is one of (r|e)ax, (r|e)dx, (r|e)cx, (r|e)bx, (r|e)si, (r|e)di,
464 +(r|e)bp, r8, r9, r10, r11, r12, r13, r14 and r15.
465 +
466 +Indirect jmp via register, "jmp reg", is converted to
467 +
468 + jmp __x86_indirect_thunk_reg
469 +
470 +Indirect call via register, "call reg", is converted to
471 +
472 + call __x86_indirect_thunk_reg
473 +
474 +gcc/
475 +
476 + * config/i386/i386-opts.h (indirect_branch): New.
477 + * config/i386/i386-protos.h (ix86_output_indirect_jmp): Likewise.
478 + * config/i386/i386.c (ix86_using_red_zone): Disallow red-zone
479 + with local indirect jump when converting indirect call and jump.
480 + (ix86_set_indirect_branch_type): New.
481 + (ix86_set_current_function): Call ix86_set_indirect_branch_type.
482 + (indirectlabelno): New.
483 + (indirect_thunk_needed): Likewise.
484 + (indirect_thunk_bnd_needed): Likewise.
485 + (indirect_thunks_used): Likewise.
486 + (indirect_thunks_bnd_used): Likewise.
487 + (INDIRECT_LABEL): Likewise.
488 + (indirect_thunk_name): Likewise.
489 + (output_indirect_thunk): Likewise.
490 + (output_indirect_thunk_function): Likewise.
491 + (ix86_output_indirect_branch): Likewise.
492 + (ix86_output_indirect_jmp): Likewise.
493 + (ix86_code_end): Call output_indirect_thunk_function if needed.
494 + (ix86_output_call_insn): Call ix86_output_indirect_branch if
495 + needed.
496 + (ix86_handle_fndecl_attribute): Handle indirect_branch.
497 + (ix86_attribute_table): Add indirect_branch.
498 + * config/i386/i386.h (machine_function): Add indirect_branch_type
499 + and has_local_indirect_jump.
500 + * config/i386/i386.md (indirect_jump): Set has_local_indirect_jump
501 + to true.
502 + (tablejump): Likewise.
503 + (*indirect_jump): Use ix86_output_indirect_jmp.
504 + (*tablejump_1): Likewise.
505 + (simple_return_indirect_internal): Likewise.
506 + * config/i386/i386.opt (mindirect-branch=): New option.
507 + (indirect_branch): New.
508 + (keep): Likewise.
509 + (thunk): Likewise.
510 + (thunk-inline): Likewise.
511 + (thunk-extern): Likewise.
512 + * doc/extend.texi: Document indirect_branch function attribute.
513 + * doc/invoke.texi: Document -mindirect-branch= option.
514 +
515 +gcc/testsuite/
516 +
517 + * gcc.target/i386/indirect-thunk-1.c: New test.
518 + * gcc.target/i386/indirect-thunk-2.c: Likewise.
519 + * gcc.target/i386/indirect-thunk-3.c: Likewise.
520 + * gcc.target/i386/indirect-thunk-4.c: Likewise.
521 + * gcc.target/i386/indirect-thunk-5.c: Likewise.
522 + * gcc.target/i386/indirect-thunk-6.c: Likewise.
523 + * gcc.target/i386/indirect-thunk-7.c: Likewise.
524 + * gcc.target/i386/indirect-thunk-attr-1.c: Likewise.
525 + * gcc.target/i386/indirect-thunk-attr-2.c: Likewise.
526 + * gcc.target/i386/indirect-thunk-attr-3.c: Likewise.
527 + * gcc.target/i386/indirect-thunk-attr-4.c: Likewise.
528 + * gcc.target/i386/indirect-thunk-attr-5.c: Likewise.
529 + * gcc.target/i386/indirect-thunk-attr-6.c: Likewise.
530 + * gcc.target/i386/indirect-thunk-attr-7.c: Likewise.
531 + * gcc.target/i386/indirect-thunk-attr-8.c: Likewise.
532 + * gcc.target/i386/indirect-thunk-bnd-1.c: Likewise.
533 + * gcc.target/i386/indirect-thunk-bnd-2.c: Likewise.
534 + * gcc.target/i386/indirect-thunk-bnd-3.c: Likewise.
535 + * gcc.target/i386/indirect-thunk-bnd-4.c: Likewise.
536 + * gcc.target/i386/indirect-thunk-extern-1.c: Likewise.
537 + * gcc.target/i386/indirect-thunk-extern-2.c: Likewise.
538 + * gcc.target/i386/indirect-thunk-extern-3.c: Likewise.
539 + * gcc.target/i386/indirect-thunk-extern-4.c: Likewise.
540 + * gcc.target/i386/indirect-thunk-extern-5.c: Likewise.
541 + * gcc.target/i386/indirect-thunk-extern-6.c: Likewise.
542 + * gcc.target/i386/indirect-thunk-extern-7.c: Likewise.
543 + * gcc.target/i386/indirect-thunk-inline-1.c: Likewise.
544 + * gcc.target/i386/indirect-thunk-inline-2.c: Likewise.
545 + * gcc.target/i386/indirect-thunk-inline-3.c: Likewise.
546 + * gcc.target/i386/indirect-thunk-inline-4.c: Likewise.
547 + * gcc.target/i386/indirect-thunk-inline-5.c: Likewise.
548 + * gcc.target/i386/indirect-thunk-inline-6.c: Likewise.
549 + * gcc.target/i386/indirect-thunk-inline-7.c: Likewise.
550 +---
551 + gcc/config/i386/i386-opts.h | 8 +
552 + gcc/config/i386/i386-protos.h | 1 +
553 + gcc/config/i386/i386.c | 512 ++++++++++++++++++++-
554 + gcc/config/i386/i386.h | 7 +
555 + gcc/config/i386/i386.md | 8 +-
556 + gcc/config/i386/i386.opt | 20 +
557 + gcc/doc/extend.texi | 10 +
558 + gcc/doc/invoke.texi | 14 +-
559 + gcc/testsuite/gcc.target/i386/indirect-thunk-1.c | 19 +
560 + gcc/testsuite/gcc.target/i386/indirect-thunk-2.c | 19 +
561 + gcc/testsuite/gcc.target/i386/indirect-thunk-3.c | 20 +
562 + gcc/testsuite/gcc.target/i386/indirect-thunk-4.c | 20 +
563 + gcc/testsuite/gcc.target/i386/indirect-thunk-5.c | 16 +
564 + gcc/testsuite/gcc.target/i386/indirect-thunk-6.c | 17 +
565 + gcc/testsuite/gcc.target/i386/indirect-thunk-7.c | 43 ++
566 + .../gcc.target/i386/indirect-thunk-attr-1.c | 22 +
567 + .../gcc.target/i386/indirect-thunk-attr-2.c | 20 +
568 + .../gcc.target/i386/indirect-thunk-attr-3.c | 21 +
569 + .../gcc.target/i386/indirect-thunk-attr-4.c | 20 +
570 + .../gcc.target/i386/indirect-thunk-attr-5.c | 22 +
571 + .../gcc.target/i386/indirect-thunk-attr-6.c | 21 +
572 + .../gcc.target/i386/indirect-thunk-attr-7.c | 44 ++
573 + .../gcc.target/i386/indirect-thunk-attr-8.c | 41 ++
574 + .../gcc.target/i386/indirect-thunk-bnd-1.c | 19 +
575 + .../gcc.target/i386/indirect-thunk-bnd-2.c | 20 +
576 + .../gcc.target/i386/indirect-thunk-bnd-3.c | 18 +
577 + .../gcc.target/i386/indirect-thunk-bnd-4.c | 19 +
578 + .../gcc.target/i386/indirect-thunk-extern-1.c | 19 +
579 + .../gcc.target/i386/indirect-thunk-extern-2.c | 19 +
580 + .../gcc.target/i386/indirect-thunk-extern-3.c | 20 +
581 + .../gcc.target/i386/indirect-thunk-extern-4.c | 20 +
582 + .../gcc.target/i386/indirect-thunk-extern-5.c | 16 +
583 + .../gcc.target/i386/indirect-thunk-extern-6.c | 17 +
584 + .../gcc.target/i386/indirect-thunk-extern-7.c | 43 ++
585 + .../gcc.target/i386/indirect-thunk-inline-1.c | 18 +
586 + .../gcc.target/i386/indirect-thunk-inline-2.c | 18 +
587 + .../gcc.target/i386/indirect-thunk-inline-3.c | 19 +
588 + .../gcc.target/i386/indirect-thunk-inline-4.c | 19 +
589 + .../gcc.target/i386/indirect-thunk-inline-5.c | 15 +
590 + .../gcc.target/i386/indirect-thunk-inline-6.c | 16 +
591 + .../gcc.target/i386/indirect-thunk-inline-7.c | 42 ++
592 + 41 files changed, 1306 insertions(+), 16 deletions(-)
593 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-1.c
594 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-2.c
595 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-3.c
596 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-4.c
597 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-5.c
598 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-6.c
599 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-7.c
600 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c
601 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c
602 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c
603 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c
604 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c
605 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c
606 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c
607 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c
608 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c
609 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c
610 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c
611 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c
612 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c
613 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c
614 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c
615 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c
616 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c
617 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c
618 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c
619 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c
620 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c
621 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c
622 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c
623 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c
624 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c
625 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c
626 +
627 +diff -Naur gcc-7.2.0.orig/gcc/config/i386/i386-opts.h gcc-7.2.0/gcc/config/i386/i386-opts.h
628 +--- gcc-7.2.0.orig/gcc/config/i386/i386-opts.h 2018-01-15 17:52:48.888745684 -0800
629 ++++ gcc-7.2.0/gcc/config/i386/i386-opts.h 2018-01-15 17:54:02.363744368 -0800
630 +@@ -99,4 +99,17 @@
631 + SSP_GLOBAL /* global canary */
632 + };
633 +
634 ++/* This is used to mitigate variant #2 of the speculative execution
635 ++ vulnerabilities on x86 processors identified by CVE-2017-5715, aka
636 ++ Spectre. They convert indirect branches and function returns to
637 ++ call and return thunks to avoid speculative execution via indirect
638 ++ call, jmp and ret. */
639 ++enum indirect_branch {
640 ++ indirect_branch_unset = 0,
641 ++ indirect_branch_keep,
642 ++ indirect_branch_thunk,
643 ++ indirect_branch_thunk_inline,
644 ++ indirect_branch_thunk_extern
645 ++};
646 ++
647 + #endif
648 +diff -Naur gcc-7.2.0.orig/gcc/config/i386/i386-protos.h gcc-7.2.0/gcc/config/i386/i386-protos.h
649 +--- gcc-7.2.0.orig/gcc/config/i386/i386-protos.h 2018-01-15 17:52:48.894745684 -0800
650 ++++ gcc-7.2.0/gcc/config/i386/i386-protos.h 2018-01-15 17:54:28.538743900 -0800
651 +@@ -315,6 +315,7 @@
652 + #endif
653 +
654 + extern const char * ix86_output_call_insn (rtx_insn *insn, rtx call_op);
655 ++extern const char * ix86_output_indirect_jmp (rtx call_op, bool ret_p);
656 + extern bool ix86_operands_ok_for_move_multiple (rtx *operands, bool load,
657 + enum machine_mode mode);
658 +
659 +diff -Naur gcc-7.2.0.orig/gcc/config/i386/i386.c gcc-7.2.0/gcc/config/i386/i386.c
660 +--- gcc-7.2.0.orig/gcc/config/i386/i386.c 2018-01-15 17:52:48.896745684 -0800
661 ++++ gcc-7.2.0/gcc/config/i386/i386.c 2018-01-15 18:13:56.240722988 -0800
662 +@@ -4209,12 +4209,23 @@
663 + return new pass_stv (ctxt);
664 + }
665 +
666 +-/* Return true if a red-zone is in use. */
667 ++/* Return true if a red-zone is in use. We can't use red-zone when
668 ++ there are local indirect jumps, like "indirect_jump" or "tablejump",
669 ++ which jumps to another place in the function, since "call" in the
670 ++ indirect thunk pushes the return address onto stack, destroying
671 ++ red-zone.
672 ++
673 ++ TODO: If we can reserve the first 2 WORDs, for PUSH and, another
674 ++ for CALL, in red-zone, we can allow local indirect jumps with
675 ++ indirect thunk. */
676 +
677 + bool
678 + ix86_using_red_zone (void)
679 + {
680 +- return TARGET_RED_ZONE && !TARGET_64BIT_MS_ABI;
681 ++ return (TARGET_RED_ZONE
682 ++ && !TARGET_64BIT_MS_ABI
683 ++ && (!cfun->machine->has_local_indirect_jump
684 ++ || cfun->machine->indirect_branch_type == indirect_branch_keep));
685 + }
686 +
687 + /* Return a string that documents the current -m options. The caller is
688 +@@ -7137,6 +7144,37 @@
689 + }
690 + }
691 +
692 ++/* Set the indirect_branch_type field from the function FNDECL. */
693 ++
694 ++static void
695 ++ix86_set_indirect_branch_type (tree fndecl)
696 ++{
697 ++ if (cfun->machine->indirect_branch_type == indirect_branch_unset)
698 ++ {
699 ++ tree attr = lookup_attribute ("indirect_branch",
700 ++ DECL_ATTRIBUTES (fndecl));
701 ++ if (attr != NULL)
702 ++ {
703 ++ tree args = TREE_VALUE (attr);
704 ++ if (args == NULL)
705 ++ gcc_unreachable ();
706 ++ tree cst = TREE_VALUE (args);
707 ++ if (strcmp (TREE_STRING_POINTER (cst), "keep") == 0)
708 ++ cfun->machine->indirect_branch_type = indirect_branch_keep;
709 ++ else if (strcmp (TREE_STRING_POINTER (cst), "thunk") == 0)
710 ++ cfun->machine->indirect_branch_type = indirect_branch_thunk;
711 ++ else if (strcmp (TREE_STRING_POINTER (cst), "thunk-inline") == 0)
712 ++ cfun->machine->indirect_branch_type = indirect_branch_thunk_inline;
713 ++ else if (strcmp (TREE_STRING_POINTER (cst), "thunk-extern") == 0)
714 ++ cfun->machine->indirect_branch_type = indirect_branch_thunk_extern;
715 ++ else
716 ++ gcc_unreachable ();
717 ++ }
718 ++ else
719 ++ cfun->machine->indirect_branch_type = ix86_indirect_branch;
720 ++ }
721 ++}
722 ++
723 + /* Establish appropriate back-end context for processing the function
724 + FNDECL. The argument might be NULL to indicate processing at top
725 + level, outside of any function scope. */
726 +@@ -7152,7 +7190,10 @@
727 + one is extern inline and one isn't. Call ix86_set_func_type
728 + to set the func_type field. */
729 + if (fndecl != NULL_TREE)
730 +- ix86_set_func_type (fndecl);
731 ++ {
732 ++ ix86_set_func_type (fndecl);
733 ++ ix86_set_indirect_branch_type (fndecl);
734 ++ }
735 + return;
736 + }
737 +
738 +@@ -7172,6 +7213,7 @@
739 + }
740 +
741 + ix86_set_func_type (fndecl);
742 ++ ix86_set_indirect_branch_type (fndecl);
743 +
744 + tree new_tree = DECL_FUNCTION_SPECIFIC_TARGET (fndecl);
745 + if (new_tree == NULL_TREE)
746 +@@ -11909,6 +11951,220 @@
747 + # endif
748 + #endif
749 +
750 ++/* Label count for call and return thunks. It is used to make unique
751 ++ labels in call and return thunks. */
752 ++static int indirectlabelno;
753 ++
754 ++/* True if call and return thunk functions are needed. */
755 ++static bool indirect_thunk_needed = false;
756 ++/* True if call and return thunk functions with the BND prefix are
757 ++ needed. */
758 ++static bool indirect_thunk_bnd_needed = false;
759 ++
760 ++/* Bit masks of integer registers, which contain branch target, used
761 ++ by call and return thunks functions. */
762 ++static int indirect_thunks_used;
763 ++/* Bit masks of integer registers, which contain branch target, used
764 ++ by call and return thunks functions with the BND prefix. */
765 ++static int indirect_thunks_bnd_used;
766 ++
767 ++#ifndef INDIRECT_LABEL
768 ++# define INDIRECT_LABEL "LIND"
769 ++#endif
770 ++
771 ++/* Fills in the label name that should be used for the indirect thunk. */
772 ++
773 ++static void
774 ++indirect_thunk_name (char name[32], int regno, bool need_bnd_p)
775 ++{
776 ++ if (USE_HIDDEN_LINKONCE)
777 ++ {
778 ++ const char *bnd = need_bnd_p ? "_bnd" : "";
779 ++ if (regno >= 0)
780 ++ {
781 ++ const char *reg_prefix;
782 ++ if (LEGACY_INT_REGNO_P (regno))
783 ++ reg_prefix = TARGET_64BIT ? "r" : "e";
784 ++ else
785 ++ reg_prefix = "";
786 ++ sprintf (name, "__x86_indirect_thunk%s_%s%s",
787 ++ bnd, reg_prefix, reg_names[regno]);
788 ++ }
789 ++ else
790 ++ sprintf (name, "__x86_indirect_thunk%s", bnd);
791 ++ }
792 ++ else
793 ++ {
794 ++ if (regno >= 0)
795 ++ {
796 ++ if (need_bnd_p)
797 ++ ASM_GENERATE_INTERNAL_LABEL (name, "LITBR", regno);
798 ++ else
799 ++ ASM_GENERATE_INTERNAL_LABEL (name, "LITR", regno);
800 ++ }
801 ++ else
802 ++ {
803 ++ if (need_bnd_p)
804 ++ ASM_GENERATE_INTERNAL_LABEL (name, "LITB", 0);
805 ++ else
806 ++ ASM_GENERATE_INTERNAL_LABEL (name, "LIT", 0);
807 ++ }
808 ++ }
809 ++}
810 ++
811 ++/* Output a call and return thunk for indirect branch. If BND_P is
812 ++ true, the BND prefix is needed. If REGNO != -1, the function
813 ++ address is in REGNO and the call and return thunk looks like:
814 ++
815 ++ call L2
816 ++ L1:
817 ++ pause
818 ++ jmp L1
819 ++ L2:
820 ++ mov %REG, (%sp)
821 ++ ret
822 ++
823 ++ Otherwise, the function address is on the top of stack and the
824 ++ call and return thunk looks like:
825 ++
826 ++ call L2
827 ++ L1:
828 ++ pause
829 ++ jmp L1
830 ++ L2:
831 ++ lea WORD_SIZE(%sp), %sp
832 ++ ret
833 ++ */
834 ++
835 ++static void
836 ++output_indirect_thunk (bool need_bnd_p, int regno)
837 ++{
838 ++ char indirectlabel1[32];
839 ++ char indirectlabel2[32];
840 ++
841 ++ ASM_GENERATE_INTERNAL_LABEL (indirectlabel1, INDIRECT_LABEL,
842 ++ indirectlabelno++);
843 ++ ASM_GENERATE_INTERNAL_LABEL (indirectlabel2, INDIRECT_LABEL,
844 ++ indirectlabelno++);
845 ++
846 ++ /* Call */
847 ++ if (need_bnd_p)
848 ++ fputs ("\tbnd call\t", asm_out_file);
849 ++ else
850 ++ fputs ("\tcall\t", asm_out_file);
851 ++ assemble_name_raw (asm_out_file, indirectlabel2);
852 ++ fputc ('\n', asm_out_file);
853 ++
854 ++ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel1);
855 ++
856 ++ /* Pause . */
857 ++ fprintf (asm_out_file, "\tpause\n");
858 ++
859 ++ /* Jump. */
860 ++ fputs ("\tjmp\t", asm_out_file);
861 ++ assemble_name_raw (asm_out_file, indirectlabel1);
862 ++ fputc ('\n', asm_out_file);
863 ++
864 ++ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel2);
865 ++
866 ++ if (regno >= 0)
867 ++ {
868 ++ /* MOV. */
869 ++ rtx xops[2];
870 ++ xops[0] = gen_rtx_MEM (word_mode, stack_pointer_rtx);
871 ++ xops[1] = gen_rtx_REG (word_mode, regno);
872 ++ output_asm_insn ("mov\t{%1, %0|%0, %1}", xops);
873 ++ }
874 ++ else
875 ++ {
876 ++ /* LEA. */
877 ++ rtx xops[2];
878 ++ xops[0] = stack_pointer_rtx;
879 ++ xops[1] = plus_constant (Pmode, stack_pointer_rtx, UNITS_PER_WORD);
880 ++ output_asm_insn ("lea\t{%E1, %0|%0, %E1}", xops);
881 ++ }
882 ++
883 ++ if (need_bnd_p)
884 ++ fputs ("\tbnd ret\n", asm_out_file);
885 ++ else
886 ++ fputs ("\tret\n", asm_out_file);
887 ++}
888 ++
889 ++/* Output a funtion with a call and return thunk for indirect branch.
890 ++ If BND_P is true, the BND prefix is needed. If REGNO != -1, the
891 ++ function address is in REGNO. Otherwise, the function address is
892 ++ on the top of stack. */
893 ++
894 ++static void
895 ++output_indirect_thunk_function (bool need_bnd_p, int regno)
896 ++{
897 ++ char name[32];
898 ++ tree decl;
899 ++
900 ++ /* Create __x86_indirect_thunk/__x86_indirect_thunk_bnd. */
901 ++ indirect_thunk_name (name, regno, need_bnd_p);
902 ++ decl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL,
903 ++ get_identifier (name),
904 ++ build_function_type_list (void_type_node, NULL_TREE));
905 ++ DECL_RESULT (decl) = build_decl (BUILTINS_LOCATION, RESULT_DECL,
906 ++ NULL_TREE, void_type_node);
907 ++ TREE_PUBLIC (decl) = 1;
908 ++ TREE_STATIC (decl) = 1;
909 ++ DECL_IGNORED_P (decl) = 1;
910 ++
911 ++#if TARGET_MACHO
912 ++ if (TARGET_MACHO)
913 ++ {
914 ++ switch_to_section (darwin_sections[picbase_thunk_section]);
915 ++ fputs ("\t.weak_definition\t", asm_out_file);
916 ++ assemble_name (asm_out_file, name);
917 ++ fputs ("\n\t.private_extern\t", asm_out_file);
918 ++ assemble_name (asm_out_file, name);
919 ++ putc ('\n', asm_out_file);
920 ++ ASM_OUTPUT_LABEL (asm_out_file, name);
921 ++ DECL_WEAK (decl) = 1;
922 ++ }
923 ++ else
924 ++#endif
925 ++ if (USE_HIDDEN_LINKONCE)
926 ++ {
927 ++ cgraph_node::create (decl)->set_comdat_group (DECL_ASSEMBLER_NAME (decl));
928 ++
929 ++ targetm.asm_out.unique_section (decl, 0);
930 ++ switch_to_section (get_named_section (decl, NULL, 0));
931 ++
932 ++ targetm.asm_out.globalize_label (asm_out_file, name);
933 ++ fputs ("\t.hidden\t", asm_out_file);
934 ++ assemble_name (asm_out_file, name);
935 ++ putc ('\n', asm_out_file);
936 ++ ASM_DECLARE_FUNCTION_NAME (asm_out_file, name, decl);
937 ++ }
938 ++ else
939 ++ {
940 ++ switch_to_section (text_section);
941 ++ ASM_OUTPUT_LABEL (asm_out_file, name);
942 ++ }
943 ++
944 ++ DECL_INITIAL (decl) = make_node (BLOCK);
945 ++ current_function_decl = decl;
946 ++ allocate_struct_function (decl, false);
947 ++ init_function_start (decl);
948 ++ /* We're about to hide the function body from callees of final_* by
949 ++ emitting it directly; tell them we're a thunk, if they care. */
950 ++ cfun->is_thunk = true;
951 ++ first_function_block_is_cold = false;
952 ++ /* Make sure unwind info is emitted for the thunk if needed. */
953 ++ final_start_function (emit_barrier (), asm_out_file, 1);
954 ++
955 ++ output_indirect_thunk (need_bnd_p, regno);
956 ++
957 ++ final_end_function ();
958 ++ init_insn_lengths ();
959 ++ free_after_compilation (cfun);
960 ++ set_cfun (NULL);
961 ++ current_function_decl = NULL;
962 ++}
963 ++
964 + static int pic_labels_used;
965 +
966 + /* Fills in the label name that should be used for a pc thunk for
967 +@@ -11935,11 +12162,32 @@
968 + rtx xops[2];
969 + int regno;
970 +
971 ++ if (indirect_thunk_needed)
972 ++ output_indirect_thunk_function (false, -1);
973 ++ if (indirect_thunk_bnd_needed)
974 ++ output_indirect_thunk_function (true, -1);
975 ++
976 ++ for (regno = FIRST_REX_INT_REG; regno <= LAST_REX_INT_REG; regno++)
977 ++ {
978 ++ int i = regno - FIRST_REX_INT_REG + SP_REG + 1;
979 ++ if ((indirect_thunks_used & (1 << i)))
980 ++ output_indirect_thunk_function (false, regno);
981 ++
982 ++ if ((indirect_thunks_bnd_used & (1 << i)))
983 ++ output_indirect_thunk_function (true, regno);
984 ++ }
985 ++
986 + for (regno = AX_REG; regno <= SP_REG; regno++)
987 + {
988 + char name[32];
989 + tree decl;
990 +
991 ++ if ((indirect_thunks_used & (1 << regno)))
992 ++ output_indirect_thunk_function (false, regno);
993 ++
994 ++ if ((indirect_thunks_bnd_used & (1 << regno)))
995 ++ output_indirect_thunk_function (true, regno);
996 ++
997 + if (!(pic_labels_used & (1 << regno)))
998 + continue;
999 +
1000 +@@ -28452,12 +28700,292 @@
1001 + return false;
1002 + }
1003 +
1004 ++/* Output indirect branch via a call and return thunk. CALL_OP is a
1005 ++ register which contains the branch target. XASM is the assembly
1006 ++ template for CALL_OP. Branch is a tail call if SIBCALL_P is true.
1007 ++ A normal call is converted to:
1008 ++
1009 ++ call __x86_indirect_thunk_reg
1010 ++
1011 ++ and a tail call is converted to:
1012 ++
1013 ++ jmp __x86_indirect_thunk_reg
1014 ++ */
1015 ++
1016 ++static void
1017 ++ix86_output_indirect_branch_via_reg (rtx call_op, bool sibcall_p)
1018 ++{
1019 ++ char thunk_name_buf[32];
1020 ++ char *thunk_name;
1021 ++ bool need_bnd_p = ix86_bnd_prefixed_insn_p (current_output_insn);
1022 ++ int regno = REGNO (call_op);
1023 ++
1024 ++ if (cfun->machine->indirect_branch_type
1025 ++ != indirect_branch_thunk_inline)
1026 ++ {
1027 ++ if (cfun->machine->indirect_branch_type == indirect_branch_thunk)
1028 ++ {
1029 ++ int i = regno;
1030 ++ if (i >= FIRST_REX_INT_REG)
1031 ++ i -= (FIRST_REX_INT_REG - SP_REG - 1);
1032 ++ if (need_bnd_p)
1033 ++ indirect_thunks_bnd_used |= 1 << i;
1034 ++ else
1035 ++ indirect_thunks_used |= 1 << i;
1036 ++ }
1037 ++ indirect_thunk_name (thunk_name_buf, regno, need_bnd_p);
1038 ++ thunk_name = thunk_name_buf;
1039 ++ }
1040 ++ else
1041 ++ thunk_name = NULL;
1042 ++
1043 ++ if (sibcall_p)
1044 ++ {
1045 ++ if (thunk_name != NULL)
1046 ++ {
1047 ++ if (need_bnd_p)
1048 ++ fprintf (asm_out_file, "\tbnd jmp\t%s\n", thunk_name);
1049 ++ else
1050 ++ fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name);
1051 ++ }
1052 ++ else
1053 ++ output_indirect_thunk (need_bnd_p, regno);
1054 ++ }
1055 ++ else
1056 ++ {
1057 ++ if (thunk_name != NULL)
1058 ++ {
1059 ++ if (need_bnd_p)
1060 ++ fprintf (asm_out_file, "\tbnd call\t%s\n", thunk_name);
1061 ++ else
1062 ++ fprintf (asm_out_file, "\tcall\t%s\n", thunk_name);
1063 ++ return;
1064 ++ }
1065 ++
1066 ++ char indirectlabel1[32];
1067 ++ char indirectlabel2[32];
1068 ++
1069 ++ ASM_GENERATE_INTERNAL_LABEL (indirectlabel1,
1070 ++ INDIRECT_LABEL,
1071 ++ indirectlabelno++);
1072 ++ ASM_GENERATE_INTERNAL_LABEL (indirectlabel2,
1073 ++ INDIRECT_LABEL,
1074 ++ indirectlabelno++);
1075 ++
1076 ++ /* Jump. */
1077 ++ if (need_bnd_p)
1078 ++ fputs ("\tbnd jmp\t", asm_out_file);
1079 ++ else
1080 ++ fputs ("\tjmp\t", asm_out_file);
1081 ++ assemble_name_raw (asm_out_file, indirectlabel2);
1082 ++ fputc ('\n', asm_out_file);
1083 ++
1084 ++ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel1);
1085 ++
1086 ++ if (thunk_name != NULL)
1087 ++ {
1088 ++ if (need_bnd_p)
1089 ++ fprintf (asm_out_file, "\tbnd jmp\t%s\n", thunk_name);
1090 ++ else
1091 ++ fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name);
1092 ++ }
1093 ++ else
1094 ++ output_indirect_thunk (need_bnd_p, regno);
1095 ++
1096 ++ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel2);
1097 ++
1098 ++ /* Call. */
1099 ++ if (need_bnd_p)
1100 ++ fputs ("\tbnd call\t", asm_out_file);
1101 ++ else
1102 ++ fputs ("\tcall\t", asm_out_file);
1103 ++ assemble_name_raw (asm_out_file, indirectlabel1);
1104 ++ fputc ('\n', asm_out_file);
1105 ++ }
1106 ++}
1107 ++
1108 ++/* Output indirect branch via a call and return thunk. CALL_OP is
1109 ++ the branch target. XASM is the assembly template for CALL_OP.
1110 ++ Branch is a tail call if SIBCALL_P is true. A normal call is
1111 ++ converted to:
1112 ++
1113 ++ jmp L2
1114 ++ L1:
1115 ++ push CALL_OP
1116 ++ jmp __x86_indirect_thunk
1117 ++ L2:
1118 ++ call L1
1119 ++
1120 ++ and a tail call is converted to:
1121 ++
1122 ++ push CALL_OP
1123 ++ jmp __x86_indirect_thunk
1124 ++ */
1125 ++
1126 ++static void
1127 ++ix86_output_indirect_branch_via_push (rtx call_op, const char *xasm,
1128 ++ bool sibcall_p)
1129 ++{
1130 ++ char thunk_name_buf[32];
1131 ++ char *thunk_name;
1132 ++ char push_buf[64];
1133 ++ bool need_bnd_p = ix86_bnd_prefixed_insn_p (current_output_insn);
1134 ++ int regno = -1;
1135 ++
1136 ++ if (cfun->machine->indirect_branch_type
1137 ++ != indirect_branch_thunk_inline)
1138 ++ {
1139 ++ if (cfun->machine->indirect_branch_type == indirect_branch_thunk)
1140 ++ {
1141 ++ if (need_bnd_p)
1142 ++ indirect_thunk_bnd_needed = true;
1143 ++ else
1144 ++ indirect_thunk_needed = true;
1145 ++ }
1146 ++ indirect_thunk_name (thunk_name_buf, regno, need_bnd_p);
1147 ++ thunk_name = thunk_name_buf;
1148 ++ }
1149 ++ else
1150 ++ thunk_name = NULL;
1151 ++
1152 ++ snprintf (push_buf, sizeof (push_buf), "push{%c}\t%s",
1153 ++ TARGET_64BIT ? 'q' : 'l', xasm);
1154 ++
1155 ++ if (sibcall_p)
1156 ++ {
1157 ++ output_asm_insn (push_buf, &call_op);
1158 ++ if (thunk_name != NULL)
1159 ++ {
1160 ++ if (need_bnd_p)
1161 ++ fprintf (asm_out_file, "\tbnd jmp\t%s\n", thunk_name);
1162 ++ else
1163 ++ fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name);
1164 ++ }
1165 ++ else
1166 ++ output_indirect_thunk (need_bnd_p, regno);
1167 ++ }
1168 ++ else
1169 ++ {
1170 ++ char indirectlabel1[32];
1171 ++ char indirectlabel2[32];
1172 ++
1173 ++ ASM_GENERATE_INTERNAL_LABEL (indirectlabel1,
1174 ++ INDIRECT_LABEL,
1175 ++ indirectlabelno++);
1176 ++ ASM_GENERATE_INTERNAL_LABEL (indirectlabel2,
1177 ++ INDIRECT_LABEL,
1178 ++ indirectlabelno++);
1179 ++
1180 ++ /* Jump. */
1181 ++ if (need_bnd_p)
1182 ++ fputs ("\tbnd jmp\t", asm_out_file);
1183 ++ else
1184 ++ fputs ("\tjmp\t", asm_out_file);
1185 ++ assemble_name_raw (asm_out_file, indirectlabel2);
1186 ++ fputc ('\n', asm_out_file);
1187 ++
1188 ++ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel1);
1189 ++
1190 ++ /* An external function may be called via GOT, instead of PLT. */
1191 ++ if (MEM_P (call_op))
1192 ++ {
1193 ++ struct ix86_address parts;
1194 ++ rtx addr = XEXP (call_op, 0);
1195 ++ if (ix86_decompose_address (addr, &parts)
1196 ++ && parts.base == stack_pointer_rtx)
1197 ++ {
1198 ++ /* Since call will adjust stack by -UNITS_PER_WORD,
1199 ++ we must convert "disp(stack, index, scale)" to
1200 ++ "disp+UNITS_PER_WORD(stack, index, scale)". */
1201 ++ if (parts.index)
1202 ++ {
1203 ++ addr = gen_rtx_MULT (Pmode, parts.index,
1204 ++ GEN_INT (parts.scale));
1205 ++ addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
1206 ++ addr);
1207 ++ }
1208 ++ else
1209 ++ addr = stack_pointer_rtx;
1210 ++
1211 ++ rtx disp;
1212 ++ if (parts.disp != NULL_RTX)
1213 ++ disp = plus_constant (Pmode, parts.disp,
1214 ++ UNITS_PER_WORD);
1215 ++ else
1216 ++ disp = GEN_INT (UNITS_PER_WORD);
1217 ++
1218 ++ addr = gen_rtx_PLUS (Pmode, addr, disp);
1219 ++ call_op = gen_rtx_MEM (GET_MODE (call_op), addr);
1220 ++ }
1221 ++ }
1222 ++
1223 ++ output_asm_insn (push_buf, &call_op);
1224 ++
1225 ++ if (thunk_name != NULL)
1226 ++ {
1227 ++ if (need_bnd_p)
1228 ++ fprintf (asm_out_file, "\tbnd jmp\t%s\n", thunk_name);
1229 ++ else
1230 ++ fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name);
1231 ++ }
1232 ++ else
1233 ++ output_indirect_thunk (need_bnd_p, regno);
1234 ++
1235 ++ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel2);
1236 ++
1237 ++ /* Call. */
1238 ++ if (need_bnd_p)
1239 ++ fputs ("\tbnd call\t", asm_out_file);
1240 ++ else
1241 ++ fputs ("\tcall\t", asm_out_file);
1242 ++ assemble_name_raw (asm_out_file, indirectlabel1);
1243 ++ fputc ('\n', asm_out_file);
1244 ++ }
1245 ++}
1246 ++
1247 ++/* Output indirect branch via a call and return thunk. CALL_OP is
1248 ++ the branch target. XASM is the assembly template for CALL_OP.
1249 ++ Branch is a tail call if SIBCALL_P is true. */
1250 ++
1251 ++static void
1252 ++ix86_output_indirect_branch (rtx call_op, const char *xasm,
1253 ++ bool sibcall_p)
1254 ++{
1255 ++ if (REG_P (call_op))
1256 ++ ix86_output_indirect_branch_via_reg (call_op, sibcall_p);
1257 ++ else
1258 ++ ix86_output_indirect_branch_via_push (call_op, xasm, sibcall_p);
1259 ++}
1260 ++/* Output indirect jump. CALL_OP is the jump target. Jump is a
1261 ++ function return if RET_P is true. */
1262 ++
1263 ++const char *
1264 ++ix86_output_indirect_jmp (rtx call_op, bool ret_p)
1265 ++{
1266 ++ if (cfun->machine->indirect_branch_type != indirect_branch_keep)
1267 ++ {
1268 ++ /* We can't have red-zone if this isn't a function return since
1269 ++ "call" in the indirect thunk pushes the return address onto
1270 ++ stack, destroying red-zone. */
1271 ++ if (!ret_p && ix86_red_zone_size != 0)
1272 ++ gcc_unreachable ();
1273 ++
1274 ++ ix86_output_indirect_branch (call_op, "%0", true);
1275 ++ return "";
1276 ++ }
1277 ++ else
1278 ++ return "%!jmp\t%A0";
1279 ++}
1280 ++
1281 + /* Output the assembly for a call instruction. */
1282 +
1283 + const char *
1284 + ix86_output_call_insn (rtx_insn *insn, rtx call_op)
1285 + {
1286 + bool direct_p = constant_call_address_operand (call_op, VOIDmode);
1287 ++ bool output_indirect_p
1288 ++ = (!TARGET_SEH
1289 ++ && cfun->machine->indirect_branch_type != indirect_branch_keep);
1290 + bool seh_nop_p = false;
1291 + const char *xasm;
1292 +
1293 +@@ -28467,10 +28892,21 @@
1294 + {
1295 + if (ix86_nopic_noplt_attribute_p (call_op))
1296 + {
1297 ++ direct_p = false;
1298 + if (TARGET_64BIT)
1299 +- xasm = "%!jmp\t{*%p0@GOTPCREL(%%rip)|[QWORD PTR %p0@GOTPCREL[rip]]}";
1300 ++ {
1301 ++ if (output_indirect_p)
1302 ++ xasm = "{%p0@GOTPCREL(%%rip)|[QWORD PTR %p0@GOTPCREL[rip]]}";
1303 ++ else
1304 ++ xasm = "%!jmp\t{*%p0@GOTPCREL(%%rip)|[QWORD PTR %p0@GOTPCREL[rip]]}";
1305 ++ }
1306 + else
1307 +- xasm = "%!jmp\t{*%p0@GOT|[DWORD PTR %p0@GOT]}";
1308 ++ {
1309 ++ if (output_indirect_p)
1310 ++ xasm = "{%p0@GOT|[DWORD PTR %p0@GOT]}";
1311 ++ else
1312 ++ xasm = "%!jmp\t{*%p0@GOT|[DWORD PTR %p0@GOT]}";
1313 ++ }
1314 + }
1315 + else
1316 + xasm = "%!jmp\t%P0";
1317 +@@ -28480,9 +28916,17 @@
1318 + else if (TARGET_SEH)
1319 + xasm = "%!rex.W jmp\t%A0";
1320 + else
1321 +- xasm = "%!jmp\t%A0";
1322 ++ {
1323 ++ if (output_indirect_p)
1324 ++ xasm = "%0";
1325 ++ else
1326 ++ xasm = "%!jmp\t%A0";
1327 ++ }
1328 +
1329 +- output_asm_insn (xasm, &call_op);
1330 ++ if (output_indirect_p && !direct_p)
1331 ++ ix86_output_indirect_branch (call_op, xasm, true);
1332 ++ else
1333 ++ output_asm_insn (xasm, &call_op);
1334 + return "";
1335 + }
1336 +
1337 +@@ -28520,18 +28964,37 @@
1338 + {
1339 + if (ix86_nopic_noplt_attribute_p (call_op))
1340 + {
1341 ++ direct_p = false;
1342 + if (TARGET_64BIT)
1343 +- xasm = "%!call\t{*%p0@GOTPCREL(%%rip)|[QWORD PTR %p0@GOTPCREL[rip]]}";
1344 ++ {
1345 ++ if (output_indirect_p)
1346 ++ xasm = "{%p0@GOTPCREL(%%rip)|[QWORD PTR %p0@GOTPCREL[rip]]}";
1347 ++ else
1348 ++ xasm = "%!call\t{*%p0@GOTPCREL(%%rip)|[QWORD PTR %p0@GOTPCREL[rip]]}";
1349 ++ }
1350 + else
1351 +- xasm = "%!call\t{*%p0@GOT|[DWORD PTR %p0@GOT]}";
1352 ++ {
1353 ++ if (output_indirect_p)
1354 ++ xasm = "{%p0@GOT|[DWORD PTR %p0@GOT]}";
1355 ++ else
1356 ++ xasm = "%!call\t{*%p0@GOT|[DWORD PTR %p0@GOT]}";
1357 ++ }
1358 + }
1359 + else
1360 + xasm = "%!call\t%P0";
1361 + }
1362 + else
1363 +- xasm = "%!call\t%A0";
1364 ++ {
1365 ++ if (output_indirect_p)
1366 ++ xasm = "%0";
1367 ++ else
1368 ++ xasm = "%!call\t%A0";
1369 ++ }
1370 +
1371 +- output_asm_insn (xasm, &call_op);
1372 ++ if (output_indirect_p && !direct_p)
1373 ++ ix86_output_indirect_branch (call_op, xasm, false);
1374 ++ else
1375 ++ output_asm_insn (xasm, &call_op);
1376 +
1377 + if (seh_nop_p)
1378 + return "nop";
1379 +@@ -41435,7 +41898,7 @@
1380 + }
1381 +
1382 + static tree
1383 +-ix86_handle_fndecl_attribute (tree *node, tree name, tree, int,
1384 ++ix86_handle_fndecl_attribute (tree *node, tree name, tree args, int,
1385 + bool *no_add_attrs)
1386 + {
1387 + if (TREE_CODE (*node) != FUNCTION_DECL)
1388 +@@ -41444,6 +41907,29 @@
1389 + name);
1390 + *no_add_attrs = true;
1391 + }
1392 ++
1393 ++ if (is_attribute_p ("indirect_branch", name))
1394 ++ {
1395 ++ tree cst = TREE_VALUE (args);
1396 ++ if (TREE_CODE (cst) != STRING_CST)
1397 ++ {
1398 ++ warning (OPT_Wattributes,
1399 ++ "%qE attribute requires a string constant argument",
1400 ++ name);
1401 ++ *no_add_attrs = true;
1402 ++ }
1403 ++ else if (strcmp (TREE_STRING_POINTER (cst), "keep") != 0
1404 ++ && strcmp (TREE_STRING_POINTER (cst), "thunk") != 0
1405 ++ && strcmp (TREE_STRING_POINTER (cst), "thunk-inline") != 0
1406 ++ && strcmp (TREE_STRING_POINTER (cst), "thunk-extern") != 0)
1407 ++ {
1408 ++ warning (OPT_Wattributes,
1409 ++ "argument to %qE attribute is not "
1410 ++ "(keep|thunk|thunk-inline|thunk-extern)", name);
1411 ++ *no_add_attrs = true;
1412 ++ }
1413 ++ }
1414 ++
1415 + return NULL_TREE;
1416 + }
1417 +
1418 +@@ -45738,6 +46224,8 @@
1419 + ix86_handle_interrupt_attribute, false },
1420 + { "no_caller_saved_registers", 0, 0, false, true, true,
1421 + ix86_handle_no_caller_saved_registers_attribute, false },
1422 ++ { "indirect_branch", 1, 1, true, false, false,
1423 ++ ix86_handle_fndecl_attribute, NULL },
1424 +
1425 + /* End element. */
1426 + { NULL, 0, 0, false, false, false, NULL, false }
1427 +diff -Naur gcc-7.2.0.orig/gcc/config/i386/i386.h gcc-7.2.0/gcc/config/i386/i386.h
1428 +--- gcc-7.2.0.orig/gcc/config/i386/i386.h 2018-01-15 17:52:48.895745684 -0800
1429 ++++ gcc-7.2.0/gcc/config/i386/i386.h 2018-01-15 18:14:15.055722651 -0800
1430 +@@ -2604,6 +2604,13 @@
1431 + /* Function type. */
1432 + ENUM_BITFIELD(function_type) func_type : 2;
1433 +
1434 ++ /* How to generate indirec branch. */
1435 ++ ENUM_BITFIELD(indirect_branch) indirect_branch_type : 3;
1436 ++
1437 ++ /* If true, the current function has local indirect jumps, like
1438 ++ "indirect_jump" or "tablejump". */
1439 ++ BOOL_BITFIELD has_local_indirect_jump : 1;
1440 ++
1441 + /* If true, the current function is a function specified with
1442 + the "interrupt" or "no_caller_saved_registers" attribute. */
1443 + BOOL_BITFIELD no_caller_saved_registers : 1;
1444 +diff -Naur gcc-7.2.0.orig/gcc/config/i386/i386.md gcc-7.2.0/gcc/config/i386/i386.md
1445 +--- gcc-7.2.0.orig/gcc/config/i386/i386.md 2018-01-15 17:52:48.888745684 -0800
1446 ++++ gcc-7.2.0/gcc/config/i386/i386.md 2018-01-15 18:16:32.476720190 -0800
1447 +@@ -11610,12 +11610,17 @@
1448 + {
1449 + if (TARGET_X32)
1450 + operands[0] = convert_memory_address (word_mode, operands[0]);
1451 ++ cfun->machine->has_local_indirect_jump = true;
1452 + })
1453 +
1454 + (define_insn "*indirect_jump"
1455 + [(set (pc) (match_operand:W 0 "indirect_branch_operand" "rBw"))]
1456 + ""
1457 +- "%!jmp\t%A0"
1458 +- [(set_attr "type" "ibr")
1459 ++ "* return ix86_output_indirect_jmp (operands[0], false);"
1460 ++ [(set (attr "type")
1461 ++ (if_then_else (match_test "(cfun->machine->indirect_branch_type
1462 ++ != indirect_branch_keep)")
1463 ++ (const_string "multi")
1464 ++ (const_string "ibr")))
1465 + (set_attr "length_immediate" "0")
1466 + (set_attr "maybe_prefix_bnd" "1")])
1467 +@@ -11659,13 +11660,18 @@
1468 +
1469 + if (TARGET_X32)
1470 + operands[0] = convert_memory_address (word_mode, operands[0]);
1471 ++ cfun->machine->has_local_indirect_jump = true;
1472 + })
1473 +
1474 + (define_insn "*tablejump_1"
1475 + [(set (pc) (match_operand:W 0 "indirect_branch_operand" "rBw"))
1476 + (use (label_ref (match_operand 1)))]
1477 + ""
1478 +- "%!jmp\t%A0"
1479 +- [(set_attr "type" "ibr")
1480 ++ "* return ix86_output_indirect_jmp (operands[0], false);"
1481 ++ [(set (attr "type")
1482 ++ (if_then_else (match_test "(cfun->machine->indirect_branch_type
1483 ++ != indirect_branch_keep)")
1484 ++ (const_string "multi")
1485 ++ (const_string "ibr")))
1486 + (set_attr "length_immediate" "0")
1487 + (set_attr "maybe_prefix_bnd" "1")])
1488 +@@ -12337,7 +12339,11 @@
1489 + [(simple_return)
1490 + (use (match_operand:SI 0 "register_operand" "r"))]
1491 + "reload_completed"
1492 +- "%!jmp\t%A0"
1493 +- [(set_attr "type" "ibr")
1494 ++ "* return ix86_output_indirect_jmp (operands[0], true);"
1495 ++ [(set (attr "type")
1496 ++ (if_then_else (match_test "(cfun->machine->indirect_branch_type
1497 ++ != indirect_branch_keep)")
1498 ++ (const_string "multi")
1499 ++ (const_string "ibr")))
1500 + (set_attr "length_immediate" "0")
1501 + (set_attr "maybe_prefix_bnd" "1")])
1502 +diff -Naur gcc-7.2.0.orig/gcc/config/i386/i386.opt gcc-7.2.0/gcc/config/i386/i386.opt
1503 +--- gcc-7.2.0.orig/gcc/config/i386/i386.opt 2018-01-15 17:52:48.890745684 -0800
1504 ++++ gcc-7.2.0/gcc/config/i386/i386.opt 2018-01-15 18:17:13.972719447 -0800
1505 +@@ -927,3 +927,23 @@
1506 + mgeneral-regs-only
1507 + Target Report RejectNegative Mask(GENERAL_REGS_ONLY) Var(ix86_target_flags) Save
1508 + Generate code which uses only the general registers.
1509 ++
1510 ++mindirect-branch=
1511 ++Target Report RejectNegative Joined Enum(indirect_branch) Var(ix86_indirect_branch) Init(indirect_branch_keep)
1512 ++Convert indirect call and jump to call and return thunks.
1513 ++
1514 ++Enum
1515 ++Name(indirect_branch) Type(enum indirect_branch)
1516 ++Known indirect branch choices (for use with the -mindirect-branch= option):
1517 ++
1518 ++EnumValue
1519 ++Enum(indirect_branch) String(keep) Value(indirect_branch_keep)
1520 ++
1521 ++EnumValue
1522 ++Enum(indirect_branch) String(thunk) Value(indirect_branch_thunk)
1523 ++
1524 ++EnumValue
1525 ++Enum(indirect_branch) String(thunk-inline) Value(indirect_branch_thunk_inline)
1526 ++
1527 ++EnumValue
1528 ++Enum(indirect_branch) String(thunk-extern) Value(indirect_branch_thunk_extern)
1529 +diff -Naur gcc-7.2.0.orig/gcc/doc/extend.texi gcc-7.2.0/gcc/doc/extend.texi
1530 +--- gcc-7.2.0.orig/gcc/doc/extend.texi 2018-01-15 17:52:47.196745715 -0800
1531 ++++ gcc-7.2.0/gcc/doc/extend.texi 2018-01-15 18:17:49.790718806 -0800
1532 +@@ -5540,6 +5540,16 @@
1533 + @code{target("fpmath=sse,387")} option as
1534 + @code{target("fpmath=sse+387")} because the comma would separate
1535 + different options.
1536 ++
1537 ++@item indirect_branch("@var{choice}")
1538 ++@cindex @code{indirect_branch} function attribute, x86
1539 ++On x86 targets, the @code{indirect_branch} attribute causes the compiler
1540 ++to convert indirect call and jump with @var{choice}. @samp{keep}
1541 ++keeps indirect call and jump unmodified. @samp{thunk} converts indirect
1542 ++call and jump to call and return thunk. @samp{thunk-inline} converts
1543 ++indirect call and jump to inlined call and return thunk.
1544 ++@samp{thunk-extern} converts indirect call and jump to external call
1545 ++and return thunk provided in a separate object file.
1546 + @end table
1547 +
1548 + On the x86, the inliner does not inline a
1549 +diff -Naur gcc-7.2.0.orig/gcc/doc/invoke.texi gcc-7.2.0/gcc/doc/invoke.texi
1550 +--- gcc-7.2.0.orig/gcc/doc/invoke.texi 2018-01-15 17:52:47.197745715 -0800
1551 ++++ gcc-7.2.0/gcc/doc/invoke.texi 2018-01-15 18:20:56.174715468 -0800
1552 +@@ -1210,7 +1210,8 @@
1553 + -msse2avx -mfentry -mrecord-mcount -mnop-mcount -m8bit-idiv @gol
1554 + -mavx256-split-unaligned-load -mavx256-split-unaligned-store @gol
1555 + -malign-data=@var{type} -mstack-protector-guard=@var{guard} @gol
1556 +--mmitigate-rop -mgeneral-regs-only}
1557 ++-mmitigate-rop -mgeneral-regs-only @gol
1558 ++-mindirect-branch=@var{choice}}
1559 +
1560 + @emph{x86 Windows Options}
1561 + @gccoptlist{-mconsole -mcygwin -mno-cygwin -mdll @gol
1562 +@@ -25648,6 +25649,17 @@
1563 + prevents the compiler from using floating-point, vector, mask and bound
1564 + registers.
1565 +
1566 ++@item -mindirect-branch=@var{choice}
1567 ++@opindex -mindirect-branch
1568 ++Convert indirect call and jump with @var{choice}. The default is
1569 ++@samp{keep}, which keeps indirect call and jump unmodified.
1570 ++@samp{thunk} converts indirect call and jump to call and return thunk.
1571 ++@samp{thunk-inline} converts indirect call and jump to inlined call
1572 ++and return thunk. @samp{thunk-extern} converts indirect call and jump
1573 ++to external call and return thunk provided in a separate object file.
1574 ++You can control this behavior for a specific function by using the
1575 ++function attribute @code{indirect_branch}. @xref{Function Attributes}.
1576 ++
1577 + @end table
1578 +
1579 + These @samp{-m} switches are supported in addition to the above
1580 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c
1581 +new file mode 100644
1582 +index 00000000000..d1d2ee78797
1583 +--- /dev/null
1584 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c
1585 +@@ -0,0 +1,19 @@
1586 ++/* { dg-do compile } */
1587 ++/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
1588 ++
1589 ++typedef void (*dispatch_t)(long offset);
1590 ++
1591 ++dispatch_t dispatch;
1592 ++
1593 ++void
1594 ++male_indirect_jump (long offset)
1595 ++{
1596 ++ dispatch(offset);
1597 ++}
1598 ++
1599 ++/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1600 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1601 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1602 ++/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1603 ++/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1604 ++/* { dg-final { scan-assembler {\tpause} } } */
1605 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c
1606 +new file mode 100644
1607 +index 00000000000..08646c6b823
1608 +--- /dev/null
1609 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c
1610 +@@ -0,0 +1,19 @@
1611 ++/* { dg-do compile } */
1612 ++/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
1613 ++
1614 ++typedef void (*dispatch_t)(long offset);
1615 ++
1616 ++dispatch_t dispatch[256];
1617 ++
1618 ++void
1619 ++male_indirect_jump (long offset)
1620 ++{
1621 ++ dispatch[offset](offset);
1622 ++}
1623 ++
1624 ++/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1625 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1626 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1627 ++/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1628 ++/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1629 ++/* { dg-final { scan-assembler {\tpause} } } */
1630 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c
1631 +new file mode 100644
1632 +index 00000000000..af244de2238
1633 +--- /dev/null
1634 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c
1635 +@@ -0,0 +1,20 @@
1636 ++/* { dg-do compile } */
1637 ++/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
1638 ++
1639 ++typedef void (*dispatch_t)(long offset);
1640 ++
1641 ++dispatch_t dispatch;
1642 ++
1643 ++int
1644 ++male_indirect_jump (long offset)
1645 ++{
1646 ++ dispatch(offset);
1647 ++ return 0;
1648 ++}
1649 ++
1650 ++/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1651 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1652 ++/* { dg-final { scan-assembler "call\[ \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 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c
1657 +new file mode 100644
1658 +index 00000000000..b8aedd5a4e6
1659 +--- /dev/null
1660 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c
1661 +@@ -0,0 +1,20 @@
1662 ++/* { dg-do compile } */
1663 ++/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
1664 ++
1665 ++typedef void (*dispatch_t)(long offset);
1666 ++
1667 ++dispatch_t dispatch[256];
1668 ++
1669 ++int
1670 ++male_indirect_jump (long offset)
1671 ++{
1672 ++ dispatch[offset](offset);
1673 ++ return 0;
1674 ++}
1675 ++
1676 ++/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1677 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1678 ++/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1679 ++/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1680 ++/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1681 ++/* { dg-final { scan-assembler {\tpause} } } */
1682 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c
1683 +new file mode 100644
1684 +index 00000000000..6ffb9235f94
1685 +--- /dev/null
1686 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c
1687 +@@ -0,0 +1,16 @@
1688 ++/* { dg-do compile { target *-*-linux* } } */
1689 ++/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk" } */
1690 ++
1691 ++extern void bar (void);
1692 ++
1693 ++void
1694 ++foo (void)
1695 ++{
1696 ++ bar ();
1697 ++}
1698 ++
1699 ++/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */
1700 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" } } */
1701 ++/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1702 ++/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1703 ++/* { dg-final { scan-assembler {\tpause} } } */
1704 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c
1705 +new file mode 100644
1706 +index 00000000000..e6d9d148cd2
1707 +--- /dev/null
1708 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c
1709 +@@ -0,0 +1,17 @@
1710 ++/* { dg-do compile { target *-*-linux* } } */
1711 ++/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk" } */
1712 ++
1713 ++extern void bar (void);
1714 ++
1715 ++int
1716 ++foo (void)
1717 ++{
1718 ++ bar ();
1719 ++ return 0;
1720 ++}
1721 ++
1722 ++/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */
1723 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" } } */
1724 ++/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */
1725 ++/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */
1726 ++/* { dg-final { scan-assembler {\tpause} } } */
1727 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c
1728 +new file mode 100644
1729 +index 00000000000..d892d8f5992
1730 +--- /dev/null
1731 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c
1732 +@@ -0,0 +1,43 @@
1733 ++/* { dg-do compile } */
1734 ++/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
1735 ++
1736 ++void func0 (void);
1737 ++void func1 (void);
1738 ++void func2 (void);
1739 ++void func3 (void);
1740 ++void func4 (void);
1741 ++void func4 (void);
1742 ++void func5 (void);
1743 ++
1744 ++void
1745 ++bar (int i)
1746 ++{
1747 ++ switch (i)
1748 ++ {
1749 ++ default:
1750 ++ func0 ();
1751 ++ break;
1752 ++ case 1:
1753 ++ func1 ();
1754 ++ break;
1755 ++ case 2:
1756 ++ func2 ();
1757 ++ break;
1758 ++ case 3:
1759 ++ func3 ();
1760 ++ break;
1761 ++ case 4:
1762 ++ func4 ();
1763 ++ break;
1764 ++ case 5:
1765 ++ func5 ();
1766 ++ break;
1767 ++ }
1768 ++}
1769 ++
1770 ++/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { ! x32 } } } } */
1771 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1772 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1773 ++/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1774 ++/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1775 ++/* { dg-final { scan-assembler {\tpause} } } */
1776 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c
1777 +new file mode 100644
1778 +index 00000000000..24188d0b62d
1779 +--- /dev/null
1780 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c
1781 +@@ -0,0 +1,22 @@
1782 ++/* { dg-do compile } */
1783 ++/* { dg-options "-O2 -fno-pic" } */
1784 ++
1785 ++typedef void (*dispatch_t)(long offset);
1786 ++
1787 ++dispatch_t dispatch;
1788 ++
1789 ++extern void male_indirect_jump (long)
1790 ++ __attribute__ ((indirect_branch("thunk")));
1791 ++
1792 ++void
1793 ++male_indirect_jump (long offset)
1794 ++{
1795 ++ dispatch(offset);
1796 ++}
1797 ++
1798 ++/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1799 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1800 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1801 ++/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1802 ++/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1803 ++/* { dg-final { scan-assembler {\tpause} } } */
1804 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c
1805 +new file mode 100644
1806 +index 00000000000..03184b90cda
1807 +--- /dev/null
1808 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c
1809 +@@ -0,0 +1,20 @@
1810 ++/* { dg-do compile } */
1811 ++/* { dg-options "-O2 -fno-pic" } */
1812 ++
1813 ++typedef void (*dispatch_t)(long offset);
1814 ++
1815 ++dispatch_t dispatch[256];
1816 ++
1817 ++__attribute__ ((indirect_branch("thunk")))
1818 ++void
1819 ++male_indirect_jump (long offset)
1820 ++{
1821 ++ dispatch[offset](offset);
1822 ++}
1823 ++
1824 ++/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1825 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1826 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1827 ++/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1828 ++/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1829 ++/* { dg-final { scan-assembler {\tpause} } } */
1830 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c
1831 +new file mode 100644
1832 +index 00000000000..af167840b81
1833 +--- /dev/null
1834 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c
1835 +@@ -0,0 +1,21 @@
1836 ++/* { dg-do compile } */
1837 ++/* { dg-options "-O2 -fno-pic" } */
1838 ++
1839 ++typedef void (*dispatch_t)(long offset);
1840 ++
1841 ++dispatch_t dispatch;
1842 ++extern int male_indirect_jump (long)
1843 ++ __attribute__ ((indirect_branch("thunk-inline")));
1844 ++
1845 ++int
1846 ++male_indirect_jump (long offset)
1847 ++{
1848 ++ dispatch(offset);
1849 ++ return 0;
1850 ++}
1851 ++
1852 ++/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1853 ++/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */
1854 ++/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */
1855 ++/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
1856 ++/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
1857 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c
1858 +new file mode 100644
1859 +index 00000000000..146124894a0
1860 +--- /dev/null
1861 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c
1862 +@@ -0,0 +1,20 @@
1863 ++/* { dg-do compile } */
1864 ++/* { dg-options "-O2 -fno-pic" } */
1865 ++
1866 ++typedef void (*dispatch_t)(long offset);
1867 ++
1868 ++dispatch_t dispatch[256];
1869 ++
1870 ++__attribute__ ((indirect_branch("thunk-inline")))
1871 ++int
1872 ++male_indirect_jump (long offset)
1873 ++{
1874 ++ dispatch[offset](offset);
1875 ++ return 0;
1876 ++}
1877 ++
1878 ++/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1879 ++/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */
1880 ++/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */
1881 ++/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
1882 ++/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
1883 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c
1884 +new file mode 100644
1885 +index 00000000000..568327cd8e7
1886 +--- /dev/null
1887 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c
1888 +@@ -0,0 +1,22 @@
1889 ++/* { dg-do compile } */
1890 ++/* { dg-options "-O2 -fno-pic" } */
1891 ++
1892 ++typedef void (*dispatch_t)(long offset);
1893 ++
1894 ++dispatch_t dispatch;
1895 ++extern int male_indirect_jump (long)
1896 ++ __attribute__ ((indirect_branch("thunk-extern")));
1897 ++
1898 ++int
1899 ++male_indirect_jump (long offset)
1900 ++{
1901 ++ dispatch(offset);
1902 ++ return 0;
1903 ++}
1904 ++
1905 ++/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1906 ++/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
1907 ++/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
1908 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1909 ++/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1910 ++/* { dg-final { scan-assembler-not {\t(pause|pause)} } } */
1911 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c
1912 +new file mode 100644
1913 +index 00000000000..bd8a99e7828
1914 +--- /dev/null
1915 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c
1916 +@@ -0,0 +1,21 @@
1917 ++/* { dg-do compile } */
1918 ++/* { dg-options "-O2 -fno-pic" } */
1919 ++
1920 ++typedef void (*dispatch_t)(long offset);
1921 ++
1922 ++dispatch_t dispatch[256];
1923 ++
1924 ++__attribute__ ((indirect_branch("thunk-extern")))
1925 ++int
1926 ++male_indirect_jump (long offset)
1927 ++{
1928 ++ dispatch[offset](offset);
1929 ++ return 0;
1930 ++}
1931 ++
1932 ++/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1933 ++/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
1934 ++/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
1935 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1936 ++/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1937 ++/* { dg-final { scan-assembler-not {\t(pause|pause)} } } */
1938 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c
1939 +new file mode 100644
1940 +index 00000000000..356015c9799
1941 +--- /dev/null
1942 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c
1943 +@@ -0,0 +1,44 @@
1944 ++/* { dg-do compile } */
1945 ++/* { dg-options "-O2 -fno-pic" } */
1946 ++
1947 ++void func0 (void);
1948 ++void func1 (void);
1949 ++void func2 (void);
1950 ++void func3 (void);
1951 ++void func4 (void);
1952 ++void func4 (void);
1953 ++void func5 (void);
1954 ++
1955 ++__attribute__ ((indirect_branch("thunk-extern")))
1956 ++void
1957 ++bar (int i)
1958 ++{
1959 ++ switch (i)
1960 ++ {
1961 ++ default:
1962 ++ func0 ();
1963 ++ break;
1964 ++ case 1:
1965 ++ func1 ();
1966 ++ break;
1967 ++ case 2:
1968 ++ func2 ();
1969 ++ break;
1970 ++ case 3:
1971 ++ func3 ();
1972 ++ break;
1973 ++ case 4:
1974 ++ func4 ();
1975 ++ break;
1976 ++ case 5:
1977 ++ func5 ();
1978 ++ break;
1979 ++ }
1980 ++}
1981 ++
1982 ++/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { ! x32 } } } } */
1983 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1984 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" } } */
1985 ++/* { dg-final { scan-assembler-not {\t(pause|pause)} } } */
1986 ++/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
1987 ++/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
1988 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c
1989 +new file mode 100644
1990 +index 00000000000..6960fa0bbfb
1991 +--- /dev/null
1992 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c
1993 +@@ -0,0 +1,41 @@
1994 ++/* { dg-do compile } */
1995 ++/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
1996 ++
1997 ++void func0 (void);
1998 ++void func1 (void);
1999 ++void func2 (void);
2000 ++void func3 (void);
2001 ++void func4 (void);
2002 ++void func4 (void);
2003 ++void func5 (void);
2004 ++
2005 ++__attribute__ ((indirect_branch("keep")))
2006 ++void
2007 ++bar (int i)
2008 ++{
2009 ++ switch (i)
2010 ++ {
2011 ++ default:
2012 ++ func0 ();
2013 ++ break;
2014 ++ case 1:
2015 ++ func1 ();
2016 ++ break;
2017 ++ case 2:
2018 ++ func2 ();
2019 ++ break;
2020 ++ case 3:
2021 ++ func3 ();
2022 ++ break;
2023 ++ case 4:
2024 ++ func4 ();
2025 ++ break;
2026 ++ case 5:
2027 ++ func5 ();
2028 ++ break;
2029 ++ }
2030 ++}
2031 ++
2032 ++/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
2033 ++/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
2034 ++/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
2035 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c
2036 +new file mode 100644
2037 +index 00000000000..febf32d76ea
2038 +--- /dev/null
2039 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c
2040 +@@ -0,0 +1,19 @@
2041 ++/* { dg-do compile { target { ! x32 } } } */
2042 ++/* { dg-options "-O2 -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
2043 ++
2044 ++void (*dispatch) (char *);
2045 ++char buf[10];
2046 ++
2047 ++void
2048 ++foo (void)
2049 ++{
2050 ++ dispatch (buf);
2051 ++}
2052 ++
2053 ++/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
2054 ++/* { dg-final { scan-assembler "pushq\[ \t\]%rax" { target x32 } } } */
2055 ++/* { dg-final { scan-assembler "bnd jmp\[ \t\]*__x86_indirect_thunk_bnd" } } */
2056 ++/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
2057 ++/* { dg-final { scan-assembler "bnd call\[ \t\]*\.LIND" } } */
2058 ++/* { dg-final { scan-assembler "bnd ret" } } */
2059 ++/* { dg-final { scan-assembler {\tpause} } } */
2060 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c
2061 +new file mode 100644
2062 +index 00000000000..319ba30b78b
2063 +--- /dev/null
2064 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c
2065 +@@ -0,0 +1,20 @@
2066 ++/* { dg-do compile { target { ! x32 } } } */
2067 ++/* { dg-options "-O2 -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
2068 ++
2069 ++void (*dispatch) (char *);
2070 ++char buf[10];
2071 ++
2072 ++int
2073 ++foo (void)
2074 ++{
2075 ++ dispatch (buf);
2076 ++ return 0;
2077 ++}
2078 ++
2079 ++/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
2080 ++/* { dg-final { scan-assembler "pushq\[ \t\]%rax" { target x32 } } } */
2081 ++/* { dg-final { scan-assembler "bnd jmp\[ \t\]*__x86_indirect_thunk_bnd" } } */
2082 ++/* { dg-final { scan-assembler "bnd jmp\[ \t\]*\.LIND" } } */
2083 ++/* { dg-final { scan-assembler "bnd call\[ \t\]*\.LIND" } } */
2084 ++/* { dg-final { scan-assembler "bnd ret" } } */
2085 ++/* { dg-final { scan-assembler {\tpause} } } */
2086 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c
2087 +new file mode 100644
2088 +index 00000000000..9168b3146f5
2089 +--- /dev/null
2090 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c
2091 +@@ -0,0 +1,18 @@
2092 ++/* { dg-do compile { target { *-*-linux* && { ! x32 } } } } */
2093 ++/* { dg-options "-O2 -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fpic -fno-plt" } */
2094 ++
2095 ++void bar (char *);
2096 ++char buf[10];
2097 ++
2098 ++void
2099 ++foo (void)
2100 ++{
2101 ++ bar (buf);
2102 ++}
2103 ++
2104 ++/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */
2105 ++/* { dg-final { scan-assembler "bnd jmp\[ \t\]*__x86_indirect_thunk_bnd" } } */
2106 ++/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
2107 ++/* { dg-final { scan-assembler "bnd call\[ \t\]*\.LIND" } } */
2108 ++/* { dg-final { scan-assembler "bnd ret" } } */
2109 ++/* { dg-final { scan-assembler {\tpause} } } */
2110 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c
2111 +new file mode 100644
2112 +index 00000000000..d3b36d44c7c
2113 +--- /dev/null
2114 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c
2115 +@@ -0,0 +1,19 @@
2116 ++/* { dg-do compile { target { *-*-linux* && { ! x32 } } } } */
2117 ++/* { dg-options "-O2 -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fpic -fno-plt" } */
2118 ++
2119 ++void bar (char *);
2120 ++char buf[10];
2121 ++
2122 ++int
2123 ++foo (void)
2124 ++{
2125 ++ bar (buf);
2126 ++ return 0;
2127 ++}
2128 ++
2129 ++/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */
2130 ++/* { dg-final { scan-assembler "bnd jmp\[ \t\]*__x86_indirect_thunk" } } */
2131 ++/* { dg-final { scan-assembler "bnd jmp\[ \t\]*\.LIND" } } */
2132 ++/* { dg-final { scan-assembler-times "bnd call\[ \t\]*\.LIND" 2 } } */
2133 ++/* { dg-final { scan-assembler "bnd ret" } } */
2134 ++/* { dg-final { scan-assembler {\tpause} } } */
2135 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c
2136 +new file mode 100644
2137 +index 00000000000..9e50b282f77
2138 +--- /dev/null
2139 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c
2140 +@@ -0,0 +1,19 @@
2141 ++/* { dg-do compile } */
2142 ++/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */
2143 ++
2144 ++typedef void (*dispatch_t)(long offset);
2145 ++
2146 ++dispatch_t dispatch;
2147 ++
2148 ++void
2149 ++male_indirect_jump (long offset)
2150 ++{
2151 ++ dispatch(offset);
2152 ++}
2153 ++
2154 ++/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
2155 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
2156 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
2157 ++/* { dg-final { scan-assembler-not {\t(pause|pause)} } } */
2158 ++/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
2159 ++/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
2160 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c
2161 +new file mode 100644
2162 +index 00000000000..f897d1c0497
2163 +--- /dev/null
2164 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c
2165 +@@ -0,0 +1,19 @@
2166 ++/* { dg-do compile } */
2167 ++/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */
2168 ++
2169 ++typedef void (*dispatch_t)(long offset);
2170 ++
2171 ++dispatch_t dispatch[256];
2172 ++
2173 ++void
2174 ++male_indirect_jump (long offset)
2175 ++{
2176 ++ dispatch[offset](offset);
2177 ++}
2178 ++
2179 ++/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
2180 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
2181 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
2182 ++/* { dg-final { scan-assembler-not {\t(pause|pause)} } } */
2183 ++/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
2184 ++/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
2185 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c
2186 +new file mode 100644
2187 +index 00000000000..25905cd0016
2188 +--- /dev/null
2189 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c
2190 +@@ -0,0 +1,20 @@
2191 ++/* { dg-do compile } */
2192 ++/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */
2193 ++
2194 ++typedef void (*dispatch_t)(long offset);
2195 ++
2196 ++dispatch_t dispatch;
2197 ++
2198 ++int
2199 ++male_indirect_jump (long offset)
2200 ++{
2201 ++ dispatch(offset);
2202 ++ return 0;
2203 ++}
2204 ++
2205 ++/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
2206 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
2207 ++/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
2208 ++/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
2209 ++/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
2210 ++/* { dg-final { scan-assembler-not {\t(pause|pause)} } } */
2211 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c
2212 +new file mode 100644
2213 +index 00000000000..a7fa12183af
2214 +--- /dev/null
2215 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c
2216 +@@ -0,0 +1,20 @@
2217 ++/* { dg-do compile } */
2218 ++/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */
2219 ++
2220 ++typedef void (*dispatch_t)(long offset);
2221 ++
2222 ++dispatch_t dispatch[256];
2223 ++
2224 ++int
2225 ++male_indirect_jump (long offset)
2226 ++{
2227 ++ dispatch[offset](offset);
2228 ++ return 0;
2229 ++}
2230 ++
2231 ++/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
2232 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
2233 ++/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
2234 ++/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
2235 ++/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
2236 ++/* { dg-final { scan-assembler-not {\t(pause|pause)} } } */
2237 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c
2238 +new file mode 100644
2239 +index 00000000000..48a49760be6
2240 +--- /dev/null
2241 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c
2242 +@@ -0,0 +1,16 @@
2243 ++/* { dg-do compile { target *-*-linux* } } */
2244 ++/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk-extern" } */
2245 ++
2246 ++extern void bar (void);
2247 ++
2248 ++void
2249 ++foo (void)
2250 ++{
2251 ++ bar ();
2252 ++}
2253 ++
2254 ++/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */
2255 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" } } */
2256 ++/* { dg-final { scan-assembler-not {\t(pause|pause)} } } */
2257 ++/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
2258 ++/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
2259 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c
2260 +new file mode 100644
2261 +index 00000000000..a1c662f7d23
2262 +--- /dev/null
2263 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c
2264 +@@ -0,0 +1,17 @@
2265 ++/* { dg-do compile { target *-*-linux* } } */
2266 ++/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk-extern" } */
2267 ++
2268 ++extern void bar (void);
2269 ++
2270 ++int
2271 ++foo (void)
2272 ++{
2273 ++ bar ();
2274 ++ return 0;
2275 ++}
2276 ++
2277 ++/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */
2278 ++/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 } } */
2279 ++/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 } } */
2280 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" } } */
2281 ++/* { dg-final { scan-assembler-not {\t(pause|pause)} } } */
2282 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c
2283 +new file mode 100644
2284 +index 00000000000..40a665ea640
2285 +--- /dev/null
2286 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c
2287 +@@ -0,0 +1,43 @@
2288 ++/* { dg-do compile } */
2289 ++/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */
2290 ++
2291 ++void func0 (void);
2292 ++void func1 (void);
2293 ++void func2 (void);
2294 ++void func3 (void);
2295 ++void func4 (void);
2296 ++void func4 (void);
2297 ++void func5 (void);
2298 ++
2299 ++void
2300 ++bar (int i)
2301 ++{
2302 ++ switch (i)
2303 ++ {
2304 ++ default:
2305 ++ func0 ();
2306 ++ break;
2307 ++ case 1:
2308 ++ func1 ();
2309 ++ break;
2310 ++ case 2:
2311 ++ func2 ();
2312 ++ break;
2313 ++ case 3:
2314 ++ func3 ();
2315 ++ break;
2316 ++ case 4:
2317 ++ func4 ();
2318 ++ break;
2319 ++ case 5:
2320 ++ func5 ();
2321 ++ break;
2322 ++ }
2323 ++}
2324 ++
2325 ++/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { ! x32 } } } } */
2326 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
2327 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
2328 ++/* { dg-final { scan-assembler-not {\t(pause|pause)} } } */
2329 ++/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
2330 ++/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
2331 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c
2332 +new file mode 100644
2333 +index 00000000000..3ace8d1b031
2334 +--- /dev/null
2335 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c
2336 +@@ -0,0 +1,18 @@
2337 ++/* { dg-do compile } */
2338 ++/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */
2339 ++
2340 ++typedef void (*dispatch_t)(long offset);
2341 ++
2342 ++dispatch_t dispatch;
2343 ++
2344 ++void
2345 ++male_indirect_jump (long offset)
2346 ++{
2347 ++ dispatch(offset);
2348 ++}
2349 ++
2350 ++/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
2351 ++/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
2352 ++/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
2353 ++/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
2354 ++/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
2355 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c
2356 +new file mode 100644
2357 +index 00000000000..6c97b96f1f2
2358 +--- /dev/null
2359 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c
2360 +@@ -0,0 +1,18 @@
2361 ++/* { dg-do compile } */
2362 ++/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */
2363 ++
2364 ++typedef void (*dispatch_t)(long offset);
2365 ++
2366 ++dispatch_t dispatch[256];
2367 ++
2368 ++void
2369 ++male_indirect_jump (long offset)
2370 ++{
2371 ++ dispatch[offset](offset);
2372 ++}
2373 ++
2374 ++/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
2375 ++/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
2376 ++/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
2377 ++/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
2378 ++/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
2379 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c
2380 +new file mode 100644
2381 +index 00000000000..8f6759cbf06
2382 +--- /dev/null
2383 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c
2384 +@@ -0,0 +1,19 @@
2385 ++/* { dg-do compile } */
2386 ++/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */
2387 ++
2388 ++typedef void (*dispatch_t)(long offset);
2389 ++
2390 ++dispatch_t dispatch;
2391 ++
2392 ++int
2393 ++male_indirect_jump (long offset)
2394 ++{
2395 ++ dispatch(offset);
2396 ++ return 0;
2397 ++}
2398 ++
2399 ++/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
2400 ++/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */
2401 ++/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */
2402 ++/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
2403 ++/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
2404 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c
2405 +new file mode 100644
2406 +index 00000000000..b07d08cab0f
2407 +--- /dev/null
2408 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c
2409 +@@ -0,0 +1,19 @@
2410 ++/* { dg-do compile } */
2411 ++/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */
2412 ++
2413 ++typedef void (*dispatch_t)(long offset);
2414 ++
2415 ++dispatch_t dispatch[256];
2416 ++
2417 ++int
2418 ++male_indirect_jump (long offset)
2419 ++{
2420 ++ dispatch[offset](offset);
2421 ++ return 0;
2422 ++}
2423 ++
2424 ++/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
2425 ++/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */
2426 ++/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */
2427 ++/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
2428 ++/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
2429 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c
2430 +new file mode 100644
2431 +index 00000000000..10794886b1b
2432 +--- /dev/null
2433 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c
2434 +@@ -0,0 +1,15 @@
2435 ++/* { dg-do compile { target *-*-linux* } } */
2436 ++/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk-inline" } */
2437 ++
2438 ++extern void bar (void);
2439 ++
2440 ++void
2441 ++foo (void)
2442 ++{
2443 ++ bar ();
2444 ++}
2445 ++
2446 ++/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */
2447 ++/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
2448 ++/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
2449 ++/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
2450 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c
2451 +new file mode 100644
2452 +index 00000000000..a26ec4b06ed
2453 +--- /dev/null
2454 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c
2455 +@@ -0,0 +1,16 @@
2456 ++/* { dg-do compile { target *-*-linux* } } */
2457 ++/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk-inline" } */
2458 ++
2459 ++extern void bar (void);
2460 ++
2461 ++int
2462 ++foo (void)
2463 ++{
2464 ++ bar ();
2465 ++ return 0;
2466 ++}
2467 ++
2468 ++/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */
2469 ++/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */
2470 ++/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */
2471 ++/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
2472 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c
2473 +new file mode 100644
2474 +index 00000000000..77253af17c6
2475 +--- /dev/null
2476 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c
2477 +@@ -0,0 +1,42 @@
2478 ++/* { dg-do compile } */
2479 ++/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */
2480 ++
2481 ++void func0 (void);
2482 ++void func1 (void);
2483 ++void func2 (void);
2484 ++void func3 (void);
2485 ++void func4 (void);
2486 ++void func4 (void);
2487 ++void func5 (void);
2488 ++
2489 ++void
2490 ++bar (int i)
2491 ++{
2492 ++ switch (i)
2493 ++ {
2494 ++ default:
2495 ++ func0 ();
2496 ++ break;
2497 ++ case 1:
2498 ++ func1 ();
2499 ++ break;
2500 ++ case 2:
2501 ++ func2 ();
2502 ++ break;
2503 ++ case 3:
2504 ++ func3 ();
2505 ++ break;
2506 ++ case 4:
2507 ++ func4 ();
2508 ++ break;
2509 ++ case 5:
2510 ++ func5 ();
2511 ++ break;
2512 ++ }
2513 ++}
2514 ++
2515 ++/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { ! x32 } } } } */
2516 ++/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
2517 ++/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
2518 ++/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
2519 ++/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
2520 +--
2521 +2.14.3
2522 +
2523
2524 diff --git a/sys-devel/gcc/files/spectre-0002-mfunction-return.patch b/sys-devel/gcc/files/spectre-0002-mfunction-return.patch
2525 new file mode 100644
2526 index 0000000..d3fa601
2527 --- /dev/null
2528 +++ b/sys-devel/gcc/files/spectre-0002-mfunction-return.patch
2529 @@ -0,0 +1,1200 @@
2530 +From: "H dot J dot Lu" <hjl dot tools at gmail dot com>
2531 +To: gcc-patches at gcc dot gnu dot org
2532 +Subject: [PATCH 2/4] x86: Add -mfunction-return=
2533 +Date: Fri, 12 Jan 2018 05:15:47 -0800
2534 +
2535 +Add -mfunction-return= option to convert function return to call and
2536 +return thunks. The default is 'keep', which keeps function return
2537 +unmodified. 'thunk' converts function return to call and return thunk.
2538 +'thunk-inline' converts function return to inlined call and return thunk.
2539 +'thunk-extern' converts function return to external call and return
2540 +thunk provided in a separate object file. You can control this behavior
2541 +for a specific function by using the function attribute function_return.
2542 +
2543 +Function return thunk is the same as memory thunk for -mindirect-branch=
2544 +where the return address is at the top of the stack:
2545 +
2546 +__x86_return_thunk:
2547 + call L2
2548 +L1:
2549 + pause
2550 + jmp L1
2551 +L2:
2552 + lea 8(%rsp), %rsp|lea 4(%esp), %esp
2553 + ret
2554 +
2555 +and function return becomes
2556 +
2557 + jmp __x86_return_thunk
2558 +
2559 +-mindirect-branch= tests are updated with -mfunction-return=keep to
2560 +avoid false test failures when -mfunction-return=thunk is added to
2561 +RUNTESTFLAGS for "make check".
2562 +
2563 +gcc/
2564 +
2565 + * config/i386/i386-protos.h (ix86_output_function_return): New.
2566 + * config/i386/i386.c (ix86_set_indirect_branch_type): Also
2567 + set function_return_type.
2568 + (indirect_thunk_name): Add ret_p to indicate thunk for function
2569 + return.
2570 + (output_indirect_thunk_function): Pass false to
2571 + indirect_thunk_name.
2572 + (ix86_output_indirect_branch): Likewise.
2573 + (output_indirect_thunk_function): Create alias for function
2574 + return thunk if regno < 0.
2575 + (ix86_output_function_return): New function.
2576 + (ix86_handle_fndecl_attribute): Handle function_return.
2577 + (ix86_attribute_table): Add function_return.
2578 + * config/i386/i386.h (machine_function): Add
2579 + function_return_type.
2580 + * config/i386/i386.md (simple_return_internal): Use
2581 + ix86_output_function_return.
2582 + (simple_return_internal_long): Likewise.
2583 + * config/i386/i386.opt (mfunction-return=): New option.
2584 + (indirect_branch): Mention -mfunction-return=.
2585 + * doc/extend.texi: Document function_return function attribute.
2586 + * doc/invoke.texi: Document -mfunction-return= option.
2587 +
2588 +gcc/testsuite/
2589 +
2590 + * gcc.target/i386/indirect-thunk-1.c (dg-options): Add
2591 + -mfunction-return=keep.
2592 + * gcc.target/i386/indirect-thunk-2.c: Likewise.
2593 + * gcc.target/i386/indirect-thunk-3.c: Likewise.
2594 + * gcc.target/i386/indirect-thunk-4.c: Likewise.
2595 + * gcc.target/i386/indirect-thunk-5.c: Likewise.
2596 + * gcc.target/i386/indirect-thunk-6.c: Likewise.
2597 + * gcc.target/i386/indirect-thunk-7.c: Likewise.
2598 + * gcc.target/i386/indirect-thunk-attr-1.c: Likewise.
2599 + * gcc.target/i386/indirect-thunk-attr-2.c: Likewise.
2600 + * gcc.target/i386/indirect-thunk-attr-3.c: Likewise.
2601 + * gcc.target/i386/indirect-thunk-attr-4.c: Likewise.
2602 + * gcc.target/i386/indirect-thunk-attr-5.c: Likewise.
2603 + * gcc.target/i386/indirect-thunk-attr-6.c: Likewise.
2604 + * gcc.target/i386/indirect-thunk-attr-7.c: Likewise.
2605 + * gcc.target/i386/indirect-thunk-attr-8.c: Likewise.
2606 + * gcc.target/i386/indirect-thunk-bnd-1.c: Likewise.
2607 + * gcc.target/i386/indirect-thunk-bnd-2.c: Likewise.
2608 + * gcc.target/i386/indirect-thunk-bnd-3.c: Likewise.
2609 + * gcc.target/i386/indirect-thunk-bnd-4.c: Likewise.
2610 + * gcc.target/i386/indirect-thunk-extern-1.c: Likewise.
2611 + * gcc.target/i386/indirect-thunk-extern-2.c: Likewise.
2612 + * gcc.target/i386/indirect-thunk-extern-3.c: Likewise.
2613 + * gcc.target/i386/indirect-thunk-extern-4.c: Likewise.
2614 + * gcc.target/i386/indirect-thunk-extern-5.c: Likewise.
2615 + * gcc.target/i386/indirect-thunk-extern-6.c: Likewise.
2616 + * gcc.target/i386/indirect-thunk-extern-7.c: Likewise.
2617 + * gcc.target/i386/indirect-thunk-inline-1.c: Likewise.
2618 + * gcc.target/i386/indirect-thunk-inline-2.c: Likewise.
2619 + * gcc.target/i386/indirect-thunk-inline-3.c: Likewise.
2620 + * gcc.target/i386/indirect-thunk-inline-4.c: Likewise.
2621 + * gcc.target/i386/indirect-thunk-inline-5.c: Likewise.
2622 + * gcc.target/i386/indirect-thunk-inline-6.c: Likewise.
2623 + * gcc.target/i386/indirect-thunk-inline-7.c: Likewise.
2624 + * gcc.target/i386/ret-thunk-1.c: New test.
2625 + * gcc.target/i386/ret-thunk-10.c: Likewise.
2626 + * gcc.target/i386/ret-thunk-11.c: Likewise.
2627 + * gcc.target/i386/ret-thunk-12.c: Likewise.
2628 + * gcc.target/i386/ret-thunk-13.c: Likewise.
2629 + * gcc.target/i386/ret-thunk-14.c: Likewise.
2630 + * gcc.target/i386/ret-thunk-15.c: Likewise.
2631 + * gcc.target/i386/ret-thunk-16.c: Likewise.
2632 + * gcc.target/i386/ret-thunk-2.c: Likewise.
2633 + * gcc.target/i386/ret-thunk-3.c: Likewise.
2634 + * gcc.target/i386/ret-thunk-4.c: Likewise.
2635 + * gcc.target/i386/ret-thunk-5.c: Likewise.
2636 + * gcc.target/i386/ret-thunk-6.c: Likewise.
2637 + * gcc.target/i386/ret-thunk-7.c: Likewise.
2638 + * gcc.target/i386/ret-thunk-8.c: Likewise.
2639 + * gcc.target/i386/ret-thunk-9.c: Likewise.
2640 +---
2641 + gcc/config/i386/i386-protos.h | 1 +
2642 + gcc/config/i386/i386.c | 149 ++++++++++++++++++++-
2643 + gcc/config/i386/i386.h | 3 +
2644 + gcc/config/i386/i386.md | 9 +-
2645 + gcc/config/i386/i386.opt | 6 +-
2646 + gcc/doc/extend.texi | 9 ++
2647 + gcc/doc/invoke.texi | 13 +-
2648 + gcc/testsuite/gcc.target/i386/indirect-thunk-1.c | 2 +-
2649 + gcc/testsuite/gcc.target/i386/indirect-thunk-2.c | 2 +-
2650 + gcc/testsuite/gcc.target/i386/indirect-thunk-3.c | 2 +-
2651 + gcc/testsuite/gcc.target/i386/indirect-thunk-4.c | 2 +-
2652 + gcc/testsuite/gcc.target/i386/indirect-thunk-5.c | 2 +-
2653 + gcc/testsuite/gcc.target/i386/indirect-thunk-6.c | 2 +-
2654 + gcc/testsuite/gcc.target/i386/indirect-thunk-7.c | 2 +-
2655 + .../gcc.target/i386/indirect-thunk-attr-1.c | 2 +-
2656 + .../gcc.target/i386/indirect-thunk-attr-2.c | 2 +-
2657 + .../gcc.target/i386/indirect-thunk-attr-3.c | 2 +-
2658 + .../gcc.target/i386/indirect-thunk-attr-4.c | 2 +-
2659 + .../gcc.target/i386/indirect-thunk-attr-5.c | 2 +-
2660 + .../gcc.target/i386/indirect-thunk-attr-6.c | 2 +-
2661 + .../gcc.target/i386/indirect-thunk-attr-7.c | 2 +-
2662 + .../gcc.target/i386/indirect-thunk-attr-8.c | 2 +-
2663 + .../gcc.target/i386/indirect-thunk-bnd-1.c | 2 +-
2664 + .../gcc.target/i386/indirect-thunk-bnd-2.c | 2 +-
2665 + .../gcc.target/i386/indirect-thunk-bnd-3.c | 2 +-
2666 + .../gcc.target/i386/indirect-thunk-bnd-4.c | 2 +-
2667 + .../gcc.target/i386/indirect-thunk-extern-1.c | 2 +-
2668 + .../gcc.target/i386/indirect-thunk-extern-2.c | 2 +-
2669 + .../gcc.target/i386/indirect-thunk-extern-3.c | 2 +-
2670 + .../gcc.target/i386/indirect-thunk-extern-4.c | 2 +-
2671 + .../gcc.target/i386/indirect-thunk-extern-5.c | 2 +-
2672 + .../gcc.target/i386/indirect-thunk-extern-6.c | 2 +-
2673 + .../gcc.target/i386/indirect-thunk-extern-7.c | 2 +-
2674 + .../gcc.target/i386/indirect-thunk-inline-1.c | 2 +-
2675 + .../gcc.target/i386/indirect-thunk-inline-2.c | 2 +-
2676 + .../gcc.target/i386/indirect-thunk-inline-3.c | 2 +-
2677 + .../gcc.target/i386/indirect-thunk-inline-4.c | 2 +-
2678 + .../gcc.target/i386/indirect-thunk-inline-5.c | 2 +-
2679 + .../gcc.target/i386/indirect-thunk-inline-6.c | 2 +-
2680 + .../gcc.target/i386/indirect-thunk-inline-7.c | 2 +-
2681 + gcc/testsuite/gcc.target/i386/ret-thunk-1.c | 12 ++
2682 + gcc/testsuite/gcc.target/i386/ret-thunk-10.c | 22 +++
2683 + gcc/testsuite/gcc.target/i386/ret-thunk-11.c | 22 +++
2684 + gcc/testsuite/gcc.target/i386/ret-thunk-12.c | 21 +++
2685 + gcc/testsuite/gcc.target/i386/ret-thunk-13.c | 21 +++
2686 + gcc/testsuite/gcc.target/i386/ret-thunk-14.c | 21 +++
2687 + gcc/testsuite/gcc.target/i386/ret-thunk-15.c | 21 +++
2688 + gcc/testsuite/gcc.target/i386/ret-thunk-16.c | 18 +++
2689 + gcc/testsuite/gcc.target/i386/ret-thunk-2.c | 12 ++
2690 + gcc/testsuite/gcc.target/i386/ret-thunk-3.c | 12 ++
2691 + gcc/testsuite/gcc.target/i386/ret-thunk-4.c | 12 ++
2692 + gcc/testsuite/gcc.target/i386/ret-thunk-5.c | 14 ++
2693 + gcc/testsuite/gcc.target/i386/ret-thunk-6.c | 13 ++
2694 + gcc/testsuite/gcc.target/i386/ret-thunk-7.c | 13 ++
2695 + gcc/testsuite/gcc.target/i386/ret-thunk-8.c | 14 ++
2696 + gcc/testsuite/gcc.target/i386/ret-thunk-9.c | 23 ++++
2697 + 56 files changed, 478 insertions(+), 49 deletions(-)
2698 + create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-1.c
2699 + create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-10.c
2700 + create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-11.c
2701 + create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-12.c
2702 + create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-13.c
2703 + create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-14.c
2704 + create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-15.c
2705 + create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-16.c
2706 + create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-2.c
2707 + create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-3.c
2708 + create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-4.c
2709 + create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-5.c
2710 + create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-6.c
2711 + create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-7.c
2712 + create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-8.c
2713 + create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-9.c
2714 +
2715 +diff -Naur gcc-7.2.0.orig/gcc/config/i386/i386-protos.h gcc-7.2.0/gcc/config/i386/i386-protos.h
2716 +--- gcc-7.2.0.orig/gcc/config/i386/i386-protos.h 2018-01-15 19:51:30.252618154 -0800
2717 ++++ gcc-7.2.0/gcc/config/i386/i386-protos.h 2018-01-15 19:51:44.370617901 -0800
2718 +@@ -316,6 +316,7 @@
2719 +
2720 + extern const char * ix86_output_call_insn (rtx_insn *insn, rtx call_op);
2721 + extern const char * ix86_output_indirect_jmp (rtx call_op, bool ret_p);
2722 ++extern const char * ix86_output_function_return (bool long_p);
2723 + extern bool ix86_operands_ok_for_move_multiple (rtx *operands, bool load,
2724 + enum machine_mode mode);
2725 +
2726 +diff -Naur gcc-7.2.0.orig/gcc/config/i386/i386.c gcc-7.2.0/gcc/config/i386/i386.c
2727 +--- gcc-7.2.0.orig/gcc/config/i386/i386.c 2018-01-15 19:51:30.252618154 -0800
2728 ++++ gcc-7.2.0/gcc/config/i386/i386.c 2018-01-15 19:54:59.663614404 -0800
2729 +@@ -7177,6 +7177,31 @@
2730 + else
2731 + cfun->machine->indirect_branch_type = ix86_indirect_branch;
2732 + }
2733 ++
2734 ++ if (cfun->machine->function_return_type == indirect_branch_unset)
2735 ++ {
2736 ++ tree attr = lookup_attribute ("function_return",
2737 ++ DECL_ATTRIBUTES (fndecl));
2738 ++ if (attr != NULL)
2739 ++ {
2740 ++ tree args = TREE_VALUE (attr);
2741 ++ if (args == NULL)
2742 ++ gcc_unreachable ();
2743 ++ tree cst = TREE_VALUE (args);
2744 ++ if (strcmp (TREE_STRING_POINTER (cst), "keep") == 0)
2745 ++ cfun->machine->function_return_type = indirect_branch_keep;
2746 ++ else if (strcmp (TREE_STRING_POINTER (cst), "thunk") == 0)
2747 ++ cfun->machine->function_return_type = indirect_branch_thunk;
2748 ++ else if (strcmp (TREE_STRING_POINTER (cst), "thunk-inline") == 0)
2749 ++ cfun->machine->function_return_type = indirect_branch_thunk_inline;
2750 ++ else if (strcmp (TREE_STRING_POINTER (cst), "thunk-extern") == 0)
2751 ++ cfun->machine->function_return_type = indirect_branch_thunk_extern;
2752 ++ else
2753 ++ gcc_unreachable ();
2754 ++ }
2755 ++ else
2756 ++ cfun->machine->function_return_type = ix86_function_return;
2757 ++ }
2758 + }
2759 +
2760 + /* Establish appropriate back-end context for processing the function
2761 +@@ -11979,8 +12004,12 @@
2762 + /* Fills in the label name that should be used for the indirect thunk. */
2763 +
2764 + static void
2765 +-indirect_thunk_name (char name[32], int regno, bool need_bnd_p)
2766 ++indirect_thunk_name (char name[32], int regno, bool need_bnd_p,
2767 ++ bool ret_p)
2768 + {
2769 ++ if (regno >= 0 && ret_p)
2770 ++ gcc_unreachable ();
2771 ++
2772 + if (USE_HIDDEN_LINKONCE)
2773 + {
2774 + const char *bnd = need_bnd_p ? "_bnd" : "";
2775 +@@ -11995,7 +12024,10 @@
2776 + bnd, reg_prefix, reg_names[regno]);
2777 + }
2778 + else
2779 +- sprintf (name, "__x86_indirect_thunk%s", bnd);
2780 ++ {
2781 ++ const char *ret = ret_p ? "return" : "indirect";
2782 ++ sprintf (name, "__x86_%s_thunk%s", ret, bnd);
2783 ++ }
2784 + }
2785 + else
2786 + {
2787 +@@ -12008,10 +12040,20 @@
2788 + }
2789 + else
2790 + {
2791 +- if (need_bnd_p)
2792 +- ASM_GENERATE_INTERNAL_LABEL (name, "LITB", 0);
2793 ++ if (ret_p)
2794 ++ {
2795 ++ if (need_bnd_p)
2796 ++ ASM_GENERATE_INTERNAL_LABEL (name, "LRTB", 0);
2797 ++ else
2798 ++ ASM_GENERATE_INTERNAL_LABEL (name, "LRT", 0);
2799 ++ }
2800 + else
2801 +- ASM_GENERATE_INTERNAL_LABEL (name, "LIT", 0);
2802 ++ {
2803 ++ if (need_bnd_p)
2804 ++ ASM_GENERATE_INTERNAL_LABEL (name, "LITB", 0);
2805 ++ else
2806 ++ ASM_GENERATE_INTERNAL_LABEL (name, "LIT", 0);
2807 ++ }
2808 + }
2809 + }
2810 + }
2811 +@@ -12106,7 +12148,7 @@
2812 + tree decl;
2813 +
2814 + /* Create __x86_indirect_thunk/__x86_indirect_thunk_bnd. */
2815 +- indirect_thunk_name (name, regno, need_bnd_p);
2816 ++ indirect_thunk_name (name, regno, need_bnd_p, false);
2817 + decl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL,
2818 + get_identifier (name),
2819 + build_function_type_list (void_type_node, NULL_TREE));
2820 +@@ -12149,6 +12191,35 @@
2821 + ASM_OUTPUT_LABEL (asm_out_file, name);
2822 + }
2823 +
2824 ++ if (regno < 0)
2825 ++ {
2826 ++ /* Create alias for __x86.return_thunk/__x86.return_thunk_bnd. */
2827 ++ char alias[32];
2828 ++
2829 ++ indirect_thunk_name (alias, regno, need_bnd_p, true);
2830 ++ ASM_OUTPUT_DEF (asm_out_file, alias, name);
2831 ++#if TARGET_MACHO
2832 ++ if (TARGET_MACHO)
2833 ++ {
2834 ++ fputs ("\t.weak_definition\t", asm_out_file);
2835 ++ assemble_name (asm_out_file, alias);
2836 ++ fputs ("\n\t.private_extern\t", asm_out_file);
2837 ++ assemble_name (asm_out_file, alias);
2838 ++ putc ('\n', asm_out_file);
2839 ++ }
2840 ++#else
2841 ++ if (USE_HIDDEN_LINKONCE)
2842 ++ {
2843 ++ fputs ("\t.globl\t", asm_out_file);
2844 ++ assemble_name (asm_out_file, alias);
2845 ++ putc ('\n', asm_out_file);
2846 ++ fputs ("\t.hidden\t", asm_out_file);
2847 ++ assemble_name (asm_out_file, alias);
2848 ++ putc ('\n', asm_out_file);
2849 ++ }
2850 ++#endif
2851 ++ }
2852 ++
2853 + DECL_INITIAL (decl) = make_node (BLOCK);
2854 + current_function_decl = decl;
2855 + allocate_struct_function (decl, false);
2856 +@@ -28766,7 +28837,7 @@
2857 + else
2858 + indirect_thunks_used |= 1 << i;
2859 + }
2860 +- indirect_thunk_name (thunk_name_buf, regno, need_bnd_p);
2861 ++ indirect_thunk_name (thunk_name_buf, regno, need_bnd_p, false);
2862 + thunk_name = thunk_name_buf;
2863 + }
2864 + else
2865 +@@ -28875,7 +28946,7 @@
2866 + else
2867 + indirect_thunk_needed = true;
2868 + }
2869 +- indirect_thunk_name (thunk_name_buf, regno, need_bnd_p);
2870 ++ indirect_thunk_name (thunk_name_buf, regno, need_bnd_p, false);
2871 + thunk_name = thunk_name_buf;
2872 + }
2873 + else
2874 +@@ -29010,6 +29081,46 @@
2875 + return "%!jmp\t%A0";
2876 + }
2877 +
2878 ++/* Output function return. CALL_OP is the jump target. Add a REP
2879 ++ prefix to RET if LONG_P is true and function return is kept. */
2880 ++
2881 ++const char *
2882 ++ix86_output_function_return (bool long_p)
2883 ++{
2884 ++ if (cfun->machine->function_return_type != indirect_branch_keep)
2885 ++ {
2886 ++ char thunk_name[32];
2887 ++ bool need_bnd_p = ix86_bnd_prefixed_insn_p (current_output_insn);
2888 ++
2889 ++ if (cfun->machine->function_return_type
2890 ++ != indirect_branch_thunk_inline)
2891 ++ {
2892 ++ bool need_thunk = (cfun->machine->function_return_type
2893 ++ == indirect_branch_thunk);
2894 ++ indirect_thunk_name (thunk_name, -1, need_bnd_p, true);
2895 ++ if (need_bnd_p)
2896 ++ {
2897 ++ indirect_thunk_bnd_needed |= need_thunk;
2898 ++ fprintf (asm_out_file, "\tbnd jmp\t%s\n", thunk_name);
2899 ++ }
2900 ++ else
2901 ++ {
2902 ++ indirect_thunk_needed |= need_thunk;
2903 ++ fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name);
2904 ++ }
2905 ++ }
2906 ++ else
2907 ++ output_indirect_thunk (need_bnd_p, -1);
2908 ++
2909 ++ return "";
2910 ++ }
2911 ++
2912 ++ if (!long_p || ix86_bnd_prefixed_insn_p (current_output_insn))
2913 ++ return "%!ret";
2914 ++
2915 ++ return "rep%; ret";
2916 ++}
2917 ++
2918 + /* Output the assembly for a call instruction. */
2919 +
2920 + const char *
2921 +@@ -42066,6 +42177,28 @@
2922 + }
2923 + }
2924 +
2925 ++ if (is_attribute_p ("function_return", name))
2926 ++ {
2927 ++ tree cst = TREE_VALUE (args);
2928 ++ if (TREE_CODE (cst) != STRING_CST)
2929 ++ {
2930 ++ warning (OPT_Wattributes,
2931 ++ "%qE attribute requires a string constant argument",
2932 ++ name);
2933 ++ *no_add_attrs = true;
2934 ++ }
2935 ++ else if (strcmp (TREE_STRING_POINTER (cst), "keep") != 0
2936 ++ && strcmp (TREE_STRING_POINTER (cst), "thunk") != 0
2937 ++ && strcmp (TREE_STRING_POINTER (cst), "thunk-inline") != 0
2938 ++ && strcmp (TREE_STRING_POINTER (cst), "thunk-extern") != 0)
2939 ++ {
2940 ++ warning (OPT_Wattributes,
2941 ++ "argument to %qE attribute is not "
2942 ++ "(keep|thunk|thunk-inline|thunk-extern)", name);
2943 ++ *no_add_attrs = true;
2944 ++ }
2945 ++ }
2946 ++
2947 + return NULL_TREE;
2948 + }
2949 +
2950 +@@ -46362,6 +46495,8 @@
2951 + ix86_handle_no_caller_saved_registers_attribute, false },
2952 + { "indirect_branch", 1, 1, true, false, false,
2953 + ix86_handle_fndecl_attribute, NULL },
2954 ++ { "function_return", 1, 1, true, false, false,
2955 ++ ix86_handle_fndecl_attribute, NULL },
2956 +
2957 + /* End element. */
2958 + { NULL, 0, 0, false, false, false, NULL, false }
2959 +diff -Naur gcc-7.2.0.orig/gcc/config/i386/i386.h gcc-7.2.0/gcc/config/i386/i386.h
2960 +--- gcc-7.2.0.orig/gcc/config/i386/i386.h 2018-01-15 19:51:30.252618154 -0800
2961 ++++ gcc-7.2.0/gcc/config/i386/i386.h 2018-01-15 19:51:44.381617901 -0800
2962 +@@ -2611,6 +2611,9 @@
2963 + "indirect_jump" or "tablejump". */
2964 + BOOL_BITFIELD has_local_indirect_jump : 1;
2965 +
2966 ++ /* How to generate function return. */
2967 ++ ENUM_BITFIELD(indirect_branch) function_return_type : 3;
2968 ++
2969 + /* If true, the current function is a function specified with
2970 + the "interrupt" or "no_caller_saved_registers" attribute. */
2971 + BOOL_BITFIELD no_caller_saved_registers : 1;
2972 +diff -Naur gcc-7.2.0.orig/gcc/config/i386/i386.md gcc-7.2.0/gcc/config/i386/i386.md
2973 +--- gcc-7.2.0.orig/gcc/config/i386/i386.md 2018-01-15 19:51:30.252618154 -0800
2974 ++++ gcc-7.2.0/gcc/config/i386/i386.md 2018-01-15 19:51:44.385617901 -0800
2975 +@@ -12298,7 +12298,7 @@
2976 + (define_insn "simple_return_internal"
2977 + [(simple_return)]
2978 + "reload_completed"
2979 +- "%!ret"
2980 ++ "* return ix86_output_function_return (false);"
2981 + [(set_attr "length" "1")
2982 + (set_attr "atom_unit" "jeu")
2983 + (set_attr "length_immediate" "0")
2984 +@@ -12320,12 +12320,7 @@
2985 + [(simple_return)
2986 + (unspec [(const_int 0)] UNSPEC_REP)]
2987 + "reload_completed"
2988 +-{
2989 +- if (ix86_bnd_prefixed_insn_p (insn))
2990 +- return "%!ret";
2991 +-
2992 +- return "rep%; ret";
2993 +-}
2994 ++ "* return ix86_output_function_return (true);"
2995 + [(set_attr "length" "2")
2996 + (set_attr "atom_unit" "jeu")
2997 + (set_attr "length_immediate" "0")
2998 +diff -Naur gcc-7.2.0.orig/gcc/config/i386/i386.opt gcc-7.2.0/gcc/config/i386/i386.opt
2999 +--- gcc-7.2.0.orig/gcc/config/i386/i386.opt 2018-01-15 19:51:30.252618154 -0800
3000 ++++ gcc-7.2.0/gcc/config/i386/i386.opt 2018-01-15 19:51:44.386617901 -0800
3001 +@@ -932,9 +932,13 @@
3002 + Target Report RejectNegative Joined Enum(indirect_branch) Var(ix86_indirect_branch) Init(indirect_branch_keep)
3003 + Convert indirect call and jump to call and return thunks.
3004 +
3005 ++mfunction-return=
3006 ++Target Report RejectNegative Joined Enum(indirect_branch) Var(ix86_function_return) Init(indirect_branch_keep)
3007 ++Convert function return to call and return thunk.
3008 ++
3009 + Enum
3010 + Name(indirect_branch) Type(enum indirect_branch)
3011 +-Known indirect branch choices (for use with the -mindirect-branch= option):
3012 ++Known indirect branch choices (for use with the -mindirect-branch=/-mfunction-return= options):
3013 +
3014 + EnumValue
3015 + Enum(indirect_branch) String(keep) Value(indirect_branch_keep)
3016 +diff -Naur gcc-7.2.0.orig/gcc/doc/extend.texi gcc-7.2.0/gcc/doc/extend.texi
3017 +--- gcc-7.2.0.orig/gcc/doc/extend.texi 2018-01-15 19:51:28.536618185 -0800
3018 ++++ gcc-7.2.0/gcc/doc/extend.texi 2018-01-15 19:51:44.392617901 -0800
3019 +@@ -5550,6 +5550,15 @@
3020 + indirect call and jump to inlined call and return thunk.
3021 + @samp{thunk-extern} converts indirect call and jump to external call
3022 + and return thunk provided in a separate object file.
3023 ++
3024 ++@item function_return("@var{choice}")
3025 ++@cindex @code{function_return} function attribute, x86
3026 ++On x86 targets, the @code{function_return} attribute causes the compiler
3027 ++to convert function return with @var{choice}. @samp{keep} keeps function
3028 ++return unmodified. @samp{thunk} converts function return to call and
3029 ++return thunk. @samp{thunk-inline} converts function return to inlined
3030 ++call and return thunk. @samp{thunk-extern} converts function return to
3031 ++external call and return thunk provided in a separate object file.
3032 + @end table
3033 +
3034 + On the x86, the inliner does not inline a
3035 +diff -Naur gcc-7.2.0.orig/gcc/doc/invoke.texi gcc-7.2.0/gcc/doc/invoke.texi
3036 +--- gcc-7.2.0.orig/gcc/doc/invoke.texi 2018-01-15 19:51:28.537618185 -0800
3037 ++++ gcc-7.2.0/gcc/doc/invoke.texi 2018-01-15 19:51:44.397617901 -0800
3038 +@@ -1211,7 +1211,7 @@
3039 + -mavx256-split-unaligned-load -mavx256-split-unaligned-store @gol
3040 + -malign-data=@var{type} -mstack-protector-guard=@var{guard} @gol
3041 + -mmitigate-rop -mgeneral-regs-only @gol
3042 +--mindirect-branch=@var{choice}}
3043 ++-mindirect-branch=@var{choice} -mfunction-return==@var{choice}}
3044 +
3045 + @emph{x86 Windows Options}
3046 + @gccoptlist{-mconsole -mcygwin -mno-cygwin -mdll @gol
3047 +@@ -25660,6 +25660,17 @@
3048 + You can control this behavior for a specific function by using the
3049 + function attribute @code{indirect_branch}. @xref{Function Attributes}.
3050 +
3051 ++@item -mfunction-return=@var{choice}
3052 ++@opindex -mfunction-return
3053 ++Convert function return with @var{choice}. The default is @samp{keep},
3054 ++which keeps function return unmodified. @samp{thunk} converts function
3055 ++return to call and return thunk. @samp{thunk-inline} converts function
3056 ++return to inlined call and return thunk. @samp{thunk-extern} converts
3057 ++function return to external call and return thunk provided in a separate
3058 ++object file. You can control this behavior for a specific function by
3059 ++using the function attribute @code{function_return}.
3060 ++@xref{Function Attributes}.
3061 ++
3062 + @end table
3063 +
3064 + These @samp{-m} switches are supported in addition to the above
3065 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c
3066 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c 2018-01-15 19:51:28.901618178 -0800
3067 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c 2018-01-15 19:51:44.398617901 -0800
3068 +@@ -1,5 +1,5 @@
3069 + /* { dg-do compile } */
3070 +-/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
3071 ++/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
3072 +
3073 + typedef void (*dispatch_t)(long offset);
3074 +
3075 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c
3076 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c 2018-01-15 19:51:28.901618178 -0800
3077 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c 2018-01-15 19:51:44.398617901 -0800
3078 +@@ -1,5 +1,5 @@
3079 + /* { dg-do compile } */
3080 +-/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
3081 ++/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
3082 +
3083 + typedef void (*dispatch_t)(long offset);
3084 +
3085 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c
3086 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c 2018-01-15 19:51:28.901618178 -0800
3087 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c 2018-01-15 19:51:44.398617901 -0800
3088 +@@ -1,5 +1,5 @@
3089 + /* { dg-do compile } */
3090 +-/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
3091 ++/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
3092 +
3093 + typedef void (*dispatch_t)(long offset);
3094 +
3095 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c
3096 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c 2018-01-15 19:51:28.901618178 -0800
3097 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c 2018-01-15 19:51:44.398617901 -0800
3098 +@@ -1,5 +1,5 @@
3099 + /* { dg-do compile } */
3100 +-/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
3101 ++/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
3102 +
3103 + typedef void (*dispatch_t)(long offset);
3104 +
3105 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c
3106 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c 2018-01-15 19:51:28.901618178 -0800
3107 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c 2018-01-15 19:51:44.398617901 -0800
3108 +@@ -1,5 +1,5 @@
3109 + /* { dg-do compile { target *-*-linux* } } */
3110 +-/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk" } */
3111 ++/* { dg-options "-O2 -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk" } */
3112 +
3113 + extern void bar (void);
3114 +
3115 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c
3116 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c 2018-01-15 19:51:28.901618178 -0800
3117 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c 2018-01-15 19:51:44.398617901 -0800
3118 +@@ -1,5 +1,5 @@
3119 + /* { dg-do compile { target *-*-linux* } } */
3120 +-/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk" } */
3121 ++/* { dg-options "-O2 -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk" } */
3122 +
3123 + extern void bar (void);
3124 +
3125 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c
3126 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c 2018-01-15 19:51:28.901618178 -0800
3127 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c 2018-01-15 19:51:44.398617901 -0800
3128 +@@ -1,5 +1,5 @@
3129 + /* { dg-do compile } */
3130 +-/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
3131 ++/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
3132 +
3133 + void func0 (void);
3134 + void func1 (void);
3135 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c
3136 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c 2018-01-15 19:51:28.901618178 -0800
3137 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c 2018-01-15 19:51:44.398617901 -0800
3138 +@@ -1,5 +1,5 @@
3139 + /* { dg-do compile } */
3140 +-/* { dg-options "-O2 -fno-pic" } */
3141 ++/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
3142 +
3143 + typedef void (*dispatch_t)(long offset);
3144 +
3145 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c
3146 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c 2018-01-15 19:51:28.901618178 -0800
3147 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c 2018-01-15 19:51:44.398617901 -0800
3148 +@@ -1,5 +1,5 @@
3149 + /* { dg-do compile } */
3150 +-/* { dg-options "-O2 -fno-pic" } */
3151 ++/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
3152 +
3153 + typedef void (*dispatch_t)(long offset);
3154 +
3155 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c
3156 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c 2018-01-15 19:51:28.902618178 -0800
3157 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c 2018-01-15 19:51:44.398617901 -0800
3158 +@@ -1,5 +1,5 @@
3159 + /* { dg-do compile } */
3160 +-/* { dg-options "-O2 -fno-pic" } */
3161 ++/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
3162 +
3163 + typedef void (*dispatch_t)(long offset);
3164 +
3165 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c
3166 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c 2018-01-15 19:51:28.902618178 -0800
3167 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c 2018-01-15 19:51:44.399617901 -0800
3168 +@@ -1,5 +1,5 @@
3169 + /* { dg-do compile } */
3170 +-/* { dg-options "-O2 -fno-pic" } */
3171 ++/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
3172 +
3173 + typedef void (*dispatch_t)(long offset);
3174 +
3175 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c
3176 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c 2018-01-15 19:51:28.902618178 -0800
3177 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c 2018-01-15 19:51:44.399617901 -0800
3178 +@@ -1,5 +1,5 @@
3179 + /* { dg-do compile } */
3180 +-/* { dg-options "-O2 -fno-pic" } */
3181 ++/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
3182 +
3183 + typedef void (*dispatch_t)(long offset);
3184 +
3185 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c
3186 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c 2018-01-15 19:51:28.901618178 -0800
3187 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c 2018-01-15 19:51:44.399617901 -0800
3188 +@@ -1,5 +1,5 @@
3189 + /* { dg-do compile } */
3190 +-/* { dg-options "-O2 -fno-pic" } */
3191 ++/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
3192 +
3193 + typedef void (*dispatch_t)(long offset);
3194 +
3195 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c
3196 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c 2018-01-15 19:51:28.902618178 -0800
3197 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c 2018-01-15 19:51:44.399617901 -0800
3198 +@@ -1,5 +1,5 @@
3199 + /* { dg-do compile } */
3200 +-/* { dg-options "-O2 -fno-pic" } */
3201 ++/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
3202 +
3203 + void func0 (void);
3204 + void func1 (void);
3205 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c
3206 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c 2018-01-15 19:51:28.902618178 -0800
3207 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c 2018-01-15 19:51:44.399617901 -0800
3208 +@@ -1,5 +1,5 @@
3209 + /* { dg-do compile } */
3210 +-/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
3211 ++/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
3212 +
3213 + void func0 (void);
3214 + void func1 (void);
3215 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c
3216 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c 2018-01-15 19:51:28.902618178 -0800
3217 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c 2018-01-15 19:51:44.399617901 -0800
3218 +@@ -1,5 +1,5 @@
3219 + /* { dg-do compile { target { ! x32 } } } */
3220 +-/* { dg-options "-O2 -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
3221 ++/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
3222 +
3223 + void (*dispatch) (char *);
3224 + char buf[10];
3225 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c
3226 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c 2018-01-15 19:51:28.902618178 -0800
3227 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c 2018-01-15 19:51:44.399617901 -0800
3228 +@@ -1,5 +1,5 @@
3229 + /* { dg-do compile { target { ! x32 } } } */
3230 +-/* { dg-options "-O2 -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
3231 ++/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
3232 +
3233 + void (*dispatch) (char *);
3234 + char buf[10];
3235 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c
3236 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c 2018-01-15 19:51:28.902618178 -0800
3237 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c 2018-01-15 19:51:44.399617901 -0800
3238 +@@ -1,5 +1,5 @@
3239 + /* { dg-do compile { target { *-*-linux* && { ! x32 } } } } */
3240 +-/* { dg-options "-O2 -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fpic -fno-plt" } */
3241 ++/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fpic -fno-plt" } */
3242 +
3243 + void bar (char *);
3244 + char buf[10];
3245 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c
3246 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c 2018-01-15 19:51:28.902618178 -0800
3247 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c 2018-01-15 19:51:44.399617901 -0800
3248 +@@ -1,5 +1,5 @@
3249 + /* { dg-do compile { target { *-*-linux* && { ! x32 } } } } */
3250 +-/* { dg-options "-O2 -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fpic -fno-plt" } */
3251 ++/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fpic -fno-plt" } */
3252 +
3253 + void bar (char *);
3254 + char buf[10];
3255 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c
3256 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c 2018-01-15 19:51:28.902618178 -0800
3257 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c 2018-01-15 19:51:44.399617901 -0800
3258 +@@ -1,5 +1,5 @@
3259 + /* { dg-do compile } */
3260 +-/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */
3261 ++/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
3262 +
3263 + typedef void (*dispatch_t)(long offset);
3264 +
3265 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c
3266 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c 2018-01-15 19:51:28.902618178 -0800
3267 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c 2018-01-15 19:51:44.400617901 -0800
3268 +@@ -1,5 +1,5 @@
3269 + /* { dg-do compile } */
3270 +-/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */
3271 ++/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
3272 +
3273 + typedef void (*dispatch_t)(long offset);
3274 +
3275 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c
3276 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c 2018-01-15 19:51:28.902618178 -0800
3277 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c 2018-01-15 19:51:44.400617901 -0800
3278 +@@ -1,5 +1,5 @@
3279 + /* { dg-do compile } */
3280 +-/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */
3281 ++/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
3282 +
3283 + typedef void (*dispatch_t)(long offset);
3284 +
3285 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c
3286 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c 2018-01-15 19:51:28.902618178 -0800
3287 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c 2018-01-15 19:51:44.400617901 -0800
3288 +@@ -1,5 +1,5 @@
3289 + /* { dg-do compile } */
3290 +-/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */
3291 ++/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
3292 +
3293 + typedef void (*dispatch_t)(long offset);
3294 +
3295 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c
3296 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c 2018-01-15 19:51:28.902618178 -0800
3297 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c 2018-01-15 19:51:44.400617901 -0800
3298 +@@ -1,5 +1,5 @@
3299 + /* { dg-do compile { target *-*-linux* } } */
3300 +-/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk-extern" } */
3301 ++/* { dg-options "-O2 -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk-extern" } */
3302 +
3303 + extern void bar (void);
3304 +
3305 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c
3306 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c 2018-01-15 19:51:28.902618178 -0800
3307 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c 2018-01-15 19:51:44.400617901 -0800
3308 +@@ -1,5 +1,5 @@
3309 + /* { dg-do compile { target *-*-linux* } } */
3310 +-/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk-extern" } */
3311 ++/* { dg-options "-O2 -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk-extern" } */
3312 +
3313 + extern void bar (void);
3314 +
3315 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c
3316 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c 2018-01-15 19:51:28.902618178 -0800
3317 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c 2018-01-15 19:51:44.400617901 -0800
3318 +@@ -1,5 +1,5 @@
3319 + /* { dg-do compile } */
3320 +-/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */
3321 ++/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
3322 +
3323 + void func0 (void);
3324 + void func1 (void);
3325 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c
3326 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c 2018-01-15 19:51:28.902618178 -0800
3327 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c 2018-01-15 19:51:44.400617901 -0800
3328 +@@ -1,5 +1,5 @@
3329 + /* { dg-do compile } */
3330 +-/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */
3331 ++/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
3332 +
3333 + typedef void (*dispatch_t)(long offset);
3334 +
3335 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c
3336 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c 2018-01-15 19:51:28.902618178 -0800
3337 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c 2018-01-15 19:51:44.400617901 -0800
3338 +@@ -1,5 +1,5 @@
3339 + /* { dg-do compile } */
3340 +-/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */
3341 ++/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
3342 +
3343 + typedef void (*dispatch_t)(long offset);
3344 +
3345 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c
3346 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c 2018-01-15 19:51:28.902618178 -0800
3347 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c 2018-01-15 19:51:44.400617901 -0800
3348 +@@ -1,5 +1,5 @@
3349 + /* { dg-do compile } */
3350 +-/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */
3351 ++/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
3352 +
3353 + typedef void (*dispatch_t)(long offset);
3354 +
3355 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c
3356 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c 2018-01-15 19:51:28.902618178 -0800
3357 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c 2018-01-15 19:51:44.401617901 -0800
3358 +@@ -1,5 +1,5 @@
3359 + /* { dg-do compile } */
3360 +-/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */
3361 ++/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
3362 +
3363 + typedef void (*dispatch_t)(long offset);
3364 +
3365 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c
3366 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c 2018-01-15 19:51:28.902618178 -0800
3367 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c 2018-01-15 19:51:44.401617901 -0800
3368 +@@ -1,5 +1,5 @@
3369 + /* { dg-do compile { target *-*-linux* } } */
3370 +-/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk-inline" } */
3371 ++/* { dg-options "-O2 -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk-inline" } */
3372 +
3373 + extern void bar (void);
3374 +
3375 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c
3376 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c 2018-01-15 19:51:28.902618178 -0800
3377 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c 2018-01-15 19:51:44.401617901 -0800
3378 +@@ -1,5 +1,5 @@
3379 + /* { dg-do compile { target *-*-linux* } } */
3380 +-/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk-inline" } */
3381 ++/* { dg-options "-O2 -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk-inline" } */
3382 +
3383 + extern void bar (void);
3384 +
3385 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c
3386 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c 2018-01-15 19:51:28.902618178 -0800
3387 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c 2018-01-15 19:51:44.401617901 -0800
3388 +@@ -1,5 +1,5 @@
3389 + /* { dg-do compile } */
3390 +-/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */
3391 ++/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
3392 +
3393 + void func0 (void);
3394 + void func1 (void);
3395 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/ret-thunk-1.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/ret-thunk-1.c
3396 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/ret-thunk-1.c 1969-12-31 16:00:00.000000000 -0800
3397 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/ret-thunk-1.c 2018-01-15 19:51:44.401617901 -0800
3398 +@@ -0,0 +1,12 @@
3399 ++/* { dg-do compile } */
3400 ++/* { dg-options "-O2 -mfunction-return=thunk" } */
3401 ++
3402 ++void
3403 ++foo (void)
3404 ++{
3405 ++}
3406 ++
3407 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk" } } */
3408 ++/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
3409 ++/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
3410 ++/* { dg-final { scan-assembler {\tpause} } } */
3411 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/ret-thunk-10.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/ret-thunk-10.c
3412 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/ret-thunk-10.c 1969-12-31 16:00:00.000000000 -0800
3413 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/ret-thunk-10.c 2018-01-15 19:51:44.401617901 -0800
3414 +@@ -0,0 +1,22 @@
3415 ++/* { dg-do compile } */
3416 ++/* { dg-options "-O2 -mfunction-return=thunk-inline -mindirect-branch=thunk -fno-pic" } */
3417 ++
3418 ++extern void (*bar) (void);
3419 ++
3420 ++int
3421 ++foo (void)
3422 ++{
3423 ++ bar ();
3424 ++ return 0;
3425 ++}
3426 ++
3427 ++/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
3428 ++/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
3429 ++/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_return_thunk" } } */
3430 ++/* { dg-final { scan-assembler-times {\tpause} 2 } } */
3431 ++/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { ! x32 } } } } */
3432 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
3433 ++/* { dg-final { scan-assembler "__x86_indirect_thunk:" { target { ! x32 } } } } */
3434 ++/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target { x32 } } } } */
3435 ++/* { dg-final { scan-assembler "__x86_indirect_thunk_(r|e)ax:" { target { x32 } } } } */
3436 ++/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
3437 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/ret-thunk-11.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/ret-thunk-11.c
3438 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/ret-thunk-11.c 1969-12-31 16:00:00.000000000 -0800
3439 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/ret-thunk-11.c 2018-01-15 19:51:44.401617901 -0800
3440 +@@ -0,0 +1,22 @@
3441 ++/* { dg-do compile } */
3442 ++/* { dg-options "-O2 -mfunction-return=thunk-extern -mindirect-branch=thunk -fno-pic" } */
3443 ++
3444 ++extern void (*bar) (void);
3445 ++
3446 ++int
3447 ++foo (void)
3448 ++{
3449 ++ bar ();
3450 ++ return 0;
3451 ++}
3452 ++
3453 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk" } } */
3454 ++/* { dg-final { scan-assembler-times {\tpause} 1 } } */
3455 ++/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
3456 ++/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
3457 ++/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { ! x32 } } } } */
3458 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
3459 ++/* { dg-final { scan-assembler "__x86_indirect_thunk:" { target { ! x32 } } } } */
3460 ++/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target { x32 } } } } */
3461 ++/* { dg-final { scan-assembler "__x86_indirect_thunk_(r|e)ax:" { target { x32 } } } } */
3462 ++/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
3463 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/ret-thunk-12.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/ret-thunk-12.c
3464 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/ret-thunk-12.c 1969-12-31 16:00:00.000000000 -0800
3465 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/ret-thunk-12.c 2018-01-15 19:51:44.401617901 -0800
3466 +@@ -0,0 +1,21 @@
3467 ++/* { dg-do compile } */
3468 ++/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
3469 ++
3470 ++extern void (*bar) (void);
3471 ++
3472 ++int
3473 ++foo (void)
3474 ++{
3475 ++ bar ();
3476 ++ return 0;
3477 ++}
3478 ++
3479 ++/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_return_thunk" } } */
3480 ++/* { dg-final { scan-assembler-times {\tpause} 1 } } */
3481 ++/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
3482 ++/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
3483 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
3484 ++/* { dg-final { scan-assembler "__x86_indirect_thunk:" { target { ! x32 } } } } */
3485 ++/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target { x32 } } } } */
3486 ++/* { dg-final { scan-assembler "__x86_indirect_thunk_(r|e)ax:" { target { x32 } } } } */
3487 ++/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
3488 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/ret-thunk-13.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/ret-thunk-13.c
3489 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/ret-thunk-13.c 1969-12-31 16:00:00.000000000 -0800
3490 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/ret-thunk-13.c 2018-01-15 19:51:44.401617901 -0800
3491 +@@ -0,0 +1,21 @@
3492 ++/* { dg-do compile } */
3493 ++/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
3494 ++
3495 ++extern void (*bar) (void);
3496 ++extern int foo (void) __attribute__ ((function_return("thunk")));
3497 ++
3498 ++int
3499 ++foo (void)
3500 ++{
3501 ++ bar ();
3502 ++ return 0;
3503 ++}
3504 ++
3505 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk" } } */
3506 ++/* { dg-final { scan-assembler-times {\tpause} 2 } } */
3507 ++/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { ! x32 } } } } */
3508 ++/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 3 } } */
3509 ++/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 3 } } */
3510 ++/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_indirect_thunk" } } */
3511 ++/* { dg-final { scan-assembler-not "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target { x32 } } } } */
3512 ++/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
3513 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/ret-thunk-14.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/ret-thunk-14.c
3514 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/ret-thunk-14.c 1969-12-31 16:00:00.000000000 -0800
3515 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/ret-thunk-14.c 2018-01-15 19:51:44.401617901 -0800
3516 +@@ -0,0 +1,21 @@
3517 ++/* { dg-do compile } */
3518 ++/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
3519 ++
3520 ++extern void (*bar) (void);
3521 ++
3522 ++__attribute__ ((function_return("thunk-inline")))
3523 ++int
3524 ++foo (void)
3525 ++{
3526 ++ bar ();
3527 ++ return 0;
3528 ++}
3529 ++
3530 ++/* { dg-final { scan-assembler-times {\tpause} 1 } } */
3531 ++/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_return_thunk" } } */
3532 ++/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
3533 ++/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
3534 ++/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { ! x32 } } } } */
3535 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
3536 ++/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target { x32 } } } } */
3537 ++/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
3538 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/ret-thunk-15.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/ret-thunk-15.c
3539 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/ret-thunk-15.c 1969-12-31 16:00:00.000000000 -0800
3540 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/ret-thunk-15.c 2018-01-15 19:51:44.402617901 -0800
3541 +@@ -0,0 +1,21 @@
3542 ++/* { dg-do compile } */
3543 ++/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=keep -fno-pic" } */
3544 ++
3545 ++extern void (*bar) (void);
3546 ++
3547 ++__attribute__ ((function_return("thunk-extern"), indirect_branch("thunk")))
3548 ++int
3549 ++foo (void)
3550 ++{
3551 ++ bar ();
3552 ++ return 0;
3553 ++}
3554 ++
3555 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk" } } */
3556 ++/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
3557 ++/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
3558 ++/* { dg-final { scan-assembler-times {\tpause} 1 } } */
3559 ++/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { ! x32 } } } } */
3560 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
3561 ++/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
3562 ++/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
3563 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/ret-thunk-16.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/ret-thunk-16.c
3564 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/ret-thunk-16.c 1969-12-31 16:00:00.000000000 -0800
3565 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/ret-thunk-16.c 2018-01-15 19:51:44.402617901 -0800
3566 +@@ -0,0 +1,18 @@
3567 ++/* { dg-do compile } */
3568 ++/* { dg-options "-O2 -mfunction-return=thunk-inline -mindirect-branch=thunk-extern -fno-pic" } */
3569 ++
3570 ++extern void (*bar) (void);
3571 ++
3572 ++__attribute__ ((function_return("keep"), indirect_branch("keep")))
3573 ++int
3574 ++foo (void)
3575 ++{
3576 ++ bar ();
3577 ++ return 0;
3578 ++}
3579 ++
3580 ++/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
3581 ++/* { dg-final { scan-assembler-not "__x86_return_thunk" } } */
3582 ++/* { dg-final { scan-assembler-not {\tpause} } } */
3583 ++/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
3584 ++/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
3585 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/ret-thunk-2.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/ret-thunk-2.c
3586 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/ret-thunk-2.c 1969-12-31 16:00:00.000000000 -0800
3587 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/ret-thunk-2.c 2018-01-15 19:51:44.402617901 -0800
3588 +@@ -0,0 +1,12 @@
3589 ++/* { dg-do compile } */
3590 ++/* { dg-options "-O2 -mfunction-return=thunk-inline" } */
3591 ++
3592 ++void
3593 ++foo (void)
3594 ++{
3595 ++}
3596 ++
3597 ++/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
3598 ++/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
3599 ++/* { dg-final { scan-assembler {\tpause} } } */
3600 ++/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_return_thunk" } } */
3601 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/ret-thunk-3.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/ret-thunk-3.c
3602 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/ret-thunk-3.c 1969-12-31 16:00:00.000000000 -0800
3603 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/ret-thunk-3.c 2018-01-15 19:51:44.402617901 -0800
3604 +@@ -0,0 +1,12 @@
3605 ++/* { dg-do compile } */
3606 ++/* { dg-options "-O2 -mfunction-return=thunk-extern" } */
3607 ++
3608 ++void
3609 ++foo (void)
3610 ++{
3611 ++}
3612 ++
3613 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk" } } */
3614 ++/* { dg-final { scan-assembler-not {\tpause} } } */
3615 ++/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
3616 ++/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
3617 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/ret-thunk-4.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/ret-thunk-4.c
3618 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/ret-thunk-4.c 1969-12-31 16:00:00.000000000 -0800
3619 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/ret-thunk-4.c 2018-01-15 19:51:44.402617901 -0800
3620 +@@ -0,0 +1,12 @@
3621 ++/* { dg-do compile } */
3622 ++/* { dg-options "-O2 -mfunction-return=keep" } */
3623 ++
3624 ++void
3625 ++foo (void)
3626 ++{
3627 ++}
3628 ++
3629 ++/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_return_thunk" } } */
3630 ++/* { dg-final { scan-assembler-not {\tpause} } } */
3631 ++/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
3632 ++/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
3633 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/ret-thunk-5.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/ret-thunk-5.c
3634 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/ret-thunk-5.c 1969-12-31 16:00:00.000000000 -0800
3635 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/ret-thunk-5.c 2018-01-15 19:51:44.402617901 -0800
3636 +@@ -0,0 +1,14 @@
3637 ++/* { dg-do compile } */
3638 ++/* { dg-options "-O2 -mfunction-return=keep" } */
3639 ++
3640 ++extern void foo (void) __attribute__ ((function_return("thunk")));
3641 ++
3642 ++void
3643 ++foo (void)
3644 ++{
3645 ++}
3646 ++
3647 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk" } } */
3648 ++/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
3649 ++/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
3650 ++/* { dg-final { scan-assembler {\tpause} } } */
3651 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/ret-thunk-6.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/ret-thunk-6.c
3652 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/ret-thunk-6.c 1969-12-31 16:00:00.000000000 -0800
3653 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/ret-thunk-6.c 2018-01-15 19:51:44.403617901 -0800
3654 +@@ -0,0 +1,13 @@
3655 ++/* { dg-do compile } */
3656 ++/* { dg-options "-O2 -mfunction-return=keep" } */
3657 ++
3658 ++__attribute__ ((function_return("thunk-inline")))
3659 ++void
3660 ++foo (void)
3661 ++{
3662 ++}
3663 ++
3664 ++/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
3665 ++/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
3666 ++/* { dg-final { scan-assembler {\tpause} } } */
3667 ++/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_return_thunk" } } */
3668 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/ret-thunk-7.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/ret-thunk-7.c
3669 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/ret-thunk-7.c 1969-12-31 16:00:00.000000000 -0800
3670 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/ret-thunk-7.c 2018-01-15 19:51:44.403617901 -0800
3671 +@@ -0,0 +1,13 @@
3672 ++/* { dg-do compile } */
3673 ++/* { dg-options "-O2 -mfunction-return=keep" } */
3674 ++
3675 ++__attribute__ ((function_return("thunk-extern")))
3676 ++void
3677 ++foo (void)
3678 ++{
3679 ++}
3680 ++
3681 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk" } } */
3682 ++/* { dg-final { scan-assembler-not {\tpause} } } */
3683 ++/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
3684 ++/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
3685 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/ret-thunk-8.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/ret-thunk-8.c
3686 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/ret-thunk-8.c 1969-12-31 16:00:00.000000000 -0800
3687 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/ret-thunk-8.c 2018-01-15 19:51:44.403617901 -0800
3688 +@@ -0,0 +1,14 @@
3689 ++/* { dg-do compile } */
3690 ++/* { dg-options "-O2 -mfunction-return=thunk-inline" } */
3691 ++
3692 ++extern void foo (void) __attribute__ ((function_return("keep")));
3693 ++
3694 ++void
3695 ++foo (void)
3696 ++{
3697 ++}
3698 ++
3699 ++/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_return_thunk" } } */
3700 ++/* { dg-final { scan-assembler-not {\tpause} } } */
3701 ++/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
3702 ++/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
3703 +diff -Naur gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/ret-thunk-9.c gcc-7.2.0/gcc/testsuite/gcc.target/i386/ret-thunk-9.c
3704 +--- gcc-7.2.0.orig/gcc/testsuite/gcc.target/i386/ret-thunk-9.c 1969-12-31 16:00:00.000000000 -0800
3705 ++++ gcc-7.2.0/gcc/testsuite/gcc.target/i386/ret-thunk-9.c 2018-01-15 19:51:44.403617901 -0800
3706 +@@ -0,0 +1,23 @@
3707 ++/* { dg-do compile } */
3708 ++/* { dg-options "-O2 -mfunction-return=thunk -mindirect-branch=thunk -fno-pic" } */
3709 ++
3710 ++extern void (*bar) (void);
3711 ++
3712 ++int
3713 ++foo (void)
3714 ++{
3715 ++ bar ();
3716 ++ return 0;
3717 ++}
3718 ++
3719 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk" } } */
3720 ++/* { dg-final { scan-assembler-not "__x86_return_thunk:" } } */
3721 ++/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
3722 ++/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
3723 ++/* { dg-final { scan-assembler "__x86_indirect_thunk:" } } */
3724 ++/* { dg-final { scan-assembler-times {\tpause} 1 { target { ! x32 } } } } */
3725 ++/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { ! x32 } } } } */
3726 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
3727 ++/* { dg-final { scan-assembler-times {\tpause} 2 { target { x32 } } } } */
3728 ++/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target { x32 } } } } */
3729 ++/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
3730
3731 diff --git a/sys-devel/gcc/files/spectre-0003-mindirect-branch-register.patch b/sys-devel/gcc/files/spectre-0003-mindirect-branch-register.patch
3732 new file mode 100644
3733 index 0000000..50aff5a
3734 --- /dev/null
3735 +++ b/sys-devel/gcc/files/spectre-0003-mindirect-branch-register.patch
3736 @@ -0,0 +1,887 @@
3737 +From: "H dot J dot Lu" <hjl dot tools at gmail dot com>
3738 +To: gcc-patches at gcc dot gnu dot org
3739 +Subject: [PATCH 3/4] x86: Add -mindirect-branch-register
3740 +Date: Fri, 12 Jan 2018 05:15:48 -0800
3741 +
3742 +Add -mindirect-branch-register to force indirect branch via register.
3743 +This is implemented by disabling patterns of indirect branch via memory,
3744 +similar to TARGET_X32.
3745 +
3746 +-mindirect-branch= and -mfunction-return= tests are updated with
3747 +-mno-indirect-branch-register to avoid false test failures when
3748 +-mindirect-branch-register is added to RUNTESTFLAGS for "make check".
3749 +
3750 +gcc/
3751 +
3752 + * config/i386/constraints.md (Bs): Disallow memory operand for
3753 + -mindirect-branch-register.
3754 + (Bw): Likewise.
3755 + * config/i386/predicates.md (indirect_branch_operand): Likewise.
3756 + (GOT_memory_operand): Likewise.
3757 + (call_insn_operand): Likewise.
3758 + (sibcall_insn_operand): Likewise.
3759 + (GOT32_symbol_operand): Likewise.
3760 + * config/i386/i386.md (indirect_jump): Call convert_memory_address
3761 + for -mindirect-branch-register.
3762 + (tablejump): Likewise.
3763 + (*sibcall_memory): Likewise.
3764 + (*sibcall_value_memory): Likewise.
3765 + Disallow peepholes of indirect call and jump via memory for
3766 + -mindirect-branch-register.
3767 + (*call_pop): Replace m with Bw.
3768 + (*call_value_pop): Likewise.
3769 + (*sibcall_pop_memory): Replace m with Bs.
3770 + * config/i386/i386.opt (mindirect-branch-register): New option.
3771 + * doc/invoke.texi: Document -mindirect-branch-register option.
3772 +
3773 +gcc/testsuite/
3774 +
3775 + * gcc.target/i386/indirect-thunk-1.c (dg-options): Add
3776 + -mno-indirect-branch-register.
3777 + * gcc.target/i386/indirect-thunk-2.c: Likewise.
3778 + * gcc.target/i386/indirect-thunk-3.c: Likewise.
3779 + * gcc.target/i386/indirect-thunk-4.c: Likewise.
3780 + * gcc.target/i386/indirect-thunk-5.c: Likewise.
3781 + * gcc.target/i386/indirect-thunk-6.c: Likewise.
3782 + * gcc.target/i386/indirect-thunk-7.c: Likewise.
3783 + * gcc.target/i386/indirect-thunk-attr-1.c: Likewise.
3784 + * gcc.target/i386/indirect-thunk-attr-2.c: Likewise.
3785 + * gcc.target/i386/indirect-thunk-attr-3.c: Likewise.
3786 + * gcc.target/i386/indirect-thunk-attr-4.c: Likewise.
3787 + * gcc.target/i386/indirect-thunk-attr-5.c: Likewise.
3788 + * gcc.target/i386/indirect-thunk-attr-6.c: Likewise.
3789 + * gcc.target/i386/indirect-thunk-attr-7.c: Likewise.
3790 + * gcc.target/i386/indirect-thunk-bnd-1.c: Likewise.
3791 + * gcc.target/i386/indirect-thunk-bnd-2.c: Likewise.
3792 + * gcc.target/i386/indirect-thunk-bnd-3.c: Likewise.
3793 + * gcc.target/i386/indirect-thunk-bnd-4.c: Likewise.
3794 + * gcc.target/i386/indirect-thunk-extern-1.c: Likewise.
3795 + * gcc.target/i386/indirect-thunk-extern-2.c: Likewise.
3796 + * gcc.target/i386/indirect-thunk-extern-3.c: Likewise.
3797 + * gcc.target/i386/indirect-thunk-extern-4.c: Likewise.
3798 + * gcc.target/i386/indirect-thunk-extern-5.c: Likewise.
3799 + * gcc.target/i386/indirect-thunk-extern-6.c: Likewise.
3800 + * gcc.target/i386/indirect-thunk-extern-7.c: Likewise.
3801 + * gcc.target/i386/indirect-thunk-inline-1.c: Likewise.
3802 + * gcc.target/i386/indirect-thunk-inline-2.c: Likewise.
3803 + * gcc.target/i386/indirect-thunk-inline-3.c: Likewise.
3804 + * gcc.target/i386/indirect-thunk-inline-4.c: Likewise.
3805 + * gcc.target/i386/indirect-thunk-inline-5.c: Likewise.
3806 + * gcc.target/i386/indirect-thunk-inline-6.c: Likewise.
3807 + * gcc.target/i386/indirect-thunk-inline-7.c: Likewise.
3808 + * gcc.target/i386/ret-thunk-10.c: Likewise.
3809 + * gcc.target/i386/ret-thunk-11.c: Likewise.
3810 + * gcc.target/i386/ret-thunk-12.c: Likewise.
3811 + * gcc.target/i386/ret-thunk-13.c: Likewise.
3812 + * gcc.target/i386/ret-thunk-14.c: Likewise.
3813 + * gcc.target/i386/ret-thunk-15.c: Likewise.
3814 + * gcc.target/i386/ret-thunk-9.c: Likewise.
3815 + * gcc.target/i386/indirect-thunk-register-1.c: New test.
3816 + * gcc.target/i386/indirect-thunk-register-2.c: Likewise.
3817 + * gcc.target/i386/indirect-thunk-register-3.c: Likewise.
3818 +---
3819 + gcc/config/i386/constraints.md | 12 +++++---
3820 + gcc/config/i386/i386.md | 34 ++++++++++++++--------
3821 + gcc/config/i386/i386.opt | 4 +++
3822 + gcc/config/i386/predicates.md | 21 ++++++++-----
3823 + gcc/doc/invoke.texi | 7 ++++-
3824 + gcc/testsuite/gcc.target/i386/indirect-thunk-1.c | 2 +-
3825 + gcc/testsuite/gcc.target/i386/indirect-thunk-2.c | 2 +-
3826 + gcc/testsuite/gcc.target/i386/indirect-thunk-3.c | 2 +-
3827 + gcc/testsuite/gcc.target/i386/indirect-thunk-4.c | 2 +-
3828 + gcc/testsuite/gcc.target/i386/indirect-thunk-5.c | 2 +-
3829 + gcc/testsuite/gcc.target/i386/indirect-thunk-6.c | 2 +-
3830 + gcc/testsuite/gcc.target/i386/indirect-thunk-7.c | 2 +-
3831 + .../gcc.target/i386/indirect-thunk-attr-1.c | 2 +-
3832 + .../gcc.target/i386/indirect-thunk-attr-2.c | 2 +-
3833 + .../gcc.target/i386/indirect-thunk-attr-3.c | 2 +-
3834 + .../gcc.target/i386/indirect-thunk-attr-4.c | 2 +-
3835 + .../gcc.target/i386/indirect-thunk-attr-5.c | 2 +-
3836 + .../gcc.target/i386/indirect-thunk-attr-6.c | 2 +-
3837 + .../gcc.target/i386/indirect-thunk-attr-7.c | 2 +-
3838 + .../gcc.target/i386/indirect-thunk-bnd-1.c | 2 +-
3839 + .../gcc.target/i386/indirect-thunk-bnd-2.c | 2 +-
3840 + .../gcc.target/i386/indirect-thunk-bnd-3.c | 2 +-
3841 + .../gcc.target/i386/indirect-thunk-bnd-4.c | 2 +-
3842 + .../gcc.target/i386/indirect-thunk-extern-1.c | 2 +-
3843 + .../gcc.target/i386/indirect-thunk-extern-2.c | 2 +-
3844 + .../gcc.target/i386/indirect-thunk-extern-3.c | 2 +-
3845 + .../gcc.target/i386/indirect-thunk-extern-4.c | 2 +-
3846 + .../gcc.target/i386/indirect-thunk-extern-5.c | 2 +-
3847 + .../gcc.target/i386/indirect-thunk-extern-6.c | 2 +-
3848 + .../gcc.target/i386/indirect-thunk-extern-7.c | 2 +-
3849 + .../gcc.target/i386/indirect-thunk-inline-1.c | 2 +-
3850 + .../gcc.target/i386/indirect-thunk-inline-2.c | 2 +-
3851 + .../gcc.target/i386/indirect-thunk-inline-3.c | 2 +-
3852 + .../gcc.target/i386/indirect-thunk-inline-4.c | 2 +-
3853 + .../gcc.target/i386/indirect-thunk-inline-5.c | 2 +-
3854 + .../gcc.target/i386/indirect-thunk-inline-6.c | 2 +-
3855 + .../gcc.target/i386/indirect-thunk-inline-7.c | 2 +-
3856 + .../gcc.target/i386/indirect-thunk-register-1.c | 22 ++++++++++++++
3857 + .../gcc.target/i386/indirect-thunk-register-2.c | 20 +++++++++++++
3858 + .../gcc.target/i386/indirect-thunk-register-3.c | 19 ++++++++++++
3859 + gcc/testsuite/gcc.target/i386/ret-thunk-10.c | 2 +-
3860 + gcc/testsuite/gcc.target/i386/ret-thunk-11.c | 2 +-
3861 + gcc/testsuite/gcc.target/i386/ret-thunk-12.c | 2 +-
3862 + gcc/testsuite/gcc.target/i386/ret-thunk-13.c | 2 +-
3863 + gcc/testsuite/gcc.target/i386/ret-thunk-14.c | 2 +-
3864 + gcc/testsuite/gcc.target/i386/ret-thunk-15.c | 2 +-
3865 + gcc/testsuite/gcc.target/i386/ret-thunk-9.c | 2 +-
3866 + 47 files changed, 154 insertions(+), 63 deletions(-)
3867 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-register-1.c
3868 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-register-2.c
3869 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-register-3.c
3870 +
3871 +diff -Naur gcc-7.2.0.orig/gcc/config/i386/constraints.md gcc-7.2.0/gcc/config/i386/constraints.md
3872 +--- gcc-7.2.0.orig/gcc/config/i386/constraints.md 2018-01-15 18:36:46.557698449 -0800
3873 ++++ gcc-7.2.0/gcc/config/i386/constraints.md 2018-01-15 18:39:17.685695742 -0800
3874 +@@ -198,16 +198,20 @@
3875 +
3876 + (define_constraint "Bs"
3877 + "@internal Sibcall memory operand."
3878 +- (ior (and (not (match_test "TARGET_X32"))
3879 ++ (ior (and (not (match_test "TARGET_X32
3880 ++ || ix86_indirect_branch_thunk_register"))
3881 + (match_operand 0 "sibcall_memory_operand"))
3882 +- (and (match_test "TARGET_X32 && Pmode == DImode")
3883 ++ (and (match_test "TARGET_X32 && Pmode == DImode
3884 ++ && !ix86_indirect_branch_thunk_register")
3885 + (match_operand 0 "GOT_memory_operand"))))
3886 +
3887 + (define_constraint "Bw"
3888 + "@internal Call memory operand."
3889 +- (ior (and (not (match_test "TARGET_X32"))
3890 ++ (ior (and (not (match_test "TARGET_X32
3891 ++ || ix86_indirect_branch_thunk_register"))
3892 + (match_operand 0 "memory_operand"))
3893 +- (and (match_test "TARGET_X32 && Pmode == DImode")
3894 ++ (and (match_test "TARGET_X32 && Pmode == DImode
3895 ++ && !ix86_indirect_branch_thunk_register")
3896 + (match_operand 0 "GOT_memory_operand"))))
3897 +
3898 + (define_constraint "Bz"
3899 +diff -Naur gcc-7.2.0.orig/gcc/config/i386/i386.md gcc-7.2.0/gcc/config/i386/i386.md
3900 +--- gcc-7.2.0.orig/gcc/config/i386/i386.md 2018-01-15 18:36:46.571698448 -0800
3901 ++++ gcc-7.2.0/gcc/config/i386/i386.md 2018-01-15 18:44:19.035690346 -0800
3902 +@@ -11608,7 +11608,7 @@
3903 + [(set (pc) (match_operand 0 "indirect_branch_operand"))]
3904 + ""
3905 + {
3906 +- if (TARGET_X32)
3907 ++ if (TARGET_X32 || ix86_indirect_branch_thunk_register)
3908 + operands[0] = convert_memory_address (word_mode, operands[0]);
3909 + cfun->machine->has_local_indirect_jump = true;
3910 + })
3911 +@@ -11658,7 +11658,7 @@
3912 + OPTAB_DIRECT);
3913 + }
3914 +
3915 +- if (TARGET_X32)
3916 ++ if (TARGET_X32 || ix86_indirect_branch_thunk_register)
3917 + operands[0] = convert_memory_address (word_mode, operands[0]);
3918 + cfun->machine->has_local_indirect_jump = true;
3919 + })
3920 +@@ -11846,7 +11846,7 @@
3921 + [(call (mem:QI (match_operand:W 0 "memory_operand" "m"))
3922 + (match_operand 1))
3923 + (unspec [(const_int 0)] UNSPEC_PEEPSIB)]
3924 +- "!TARGET_X32"
3925 ++ "!TARGET_X32 && !ix86_indirect_branch_thunk_register"
3926 + "* return ix86_output_call_insn (insn, operands[0]);"
3927 + [(set_attr "type" "call")])
3928 +
3929 +@@ -11855,7 +11855,9 @@
3930 + (match_operand:W 1 "memory_operand"))
3931 + (call (mem:QI (match_dup 0))
3932 + (match_operand 3))]
3933 +- "!TARGET_X32 && SIBLING_CALL_P (peep2_next_insn (1))
3934 ++ "!TARGET_X32
3935 ++ && !ix86_indirect_branch_thunk_register
3936 ++ && SIBLING_CALL_P (peep2_next_insn (1))
3937 + && !reg_mentioned_p (operands[0],
3938 + CALL_INSN_FUNCTION_USAGE (peep2_next_insn (1)))"
3939 + [(parallel [(call (mem:QI (match_dup 1))
3940 +@@ -11868,7 +11870,9 @@
3941 + (unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)
3942 + (call (mem:QI (match_dup 0))
3943 + (match_operand 3))]
3944 +- "!TARGET_X32 && SIBLING_CALL_P (peep2_next_insn (2))
3945 ++ "!TARGET_X32
3946 ++ && !ix86_indirect_branch_thunk_register
3947 ++ && SIBLING_CALL_P (peep2_next_insn (2))
3948 + && !reg_mentioned_p (operands[0],
3949 + CALL_INSN_FUNCTION_USAGE (peep2_next_insn (2)))"
3950 + [(unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)
3951 +@@ -11890,7 +11894,7 @@
3952 + })
3953 +
3954 + (define_insn "*call_pop"
3955 +- [(call (mem:QI (match_operand:SI 0 "call_insn_operand" "lmBz"))
3956 ++ [(call (mem:QI (match_operand:SI 0 "call_insn_operand" "lBwBz"))
3957 + (match_operand 1))
3958 + (set (reg:SI SP_REG)
3959 + (plus:SI (reg:SI SP_REG)
3960 +@@ -11910,7 +11914,7 @@
3961 + [(set_attr "type" "call")])
3962 +
3963 + (define_insn "*sibcall_pop_memory"
3964 +- [(call (mem:QI (match_operand:SI 0 "memory_operand" "m"))
3965 ++ [(call (mem:QI (match_operand:SI 0 "memory_operand" "Bs"))
3966 + (match_operand 1))
3967 + (set (reg:SI SP_REG)
3968 + (plus:SI (reg:SI SP_REG)
3969 +@@ -11964,7 +11968,9 @@
3970 + [(set (match_operand:W 0 "register_operand")
3971 + (match_operand:W 1 "memory_operand"))
3972 + (set (pc) (match_dup 0))]
3973 +- "!TARGET_X32 && peep2_reg_dead_p (2, operands[0])"
3974 ++ "!TARGET_X32
3975 ++ && !ix86_indirect_branch_thunk_register
3976 ++ && peep2_reg_dead_p (2, operands[0])"
3977 + [(set (pc) (match_dup 1))])
3978 +
3979 + ;; Call subroutine, returning value in operand 0
3980 +@@ -12045,7 +12051,7 @@
3981 + (call (mem:QI (match_operand:W 1 "memory_operand" "m"))
3982 + (match_operand 2)))
3983 + (unspec [(const_int 0)] UNSPEC_PEEPSIB)]
3984 +- "!TARGET_X32"
3985 ++ "!TARGET_X32 && !ix86_indirect_branch_thunk_register"
3986 + "* return ix86_output_call_insn (insn, operands[1]);"
3987 + [(set_attr "type" "callv")])
3988 +
3989 +@@ -12055,7 +12061,9 @@
3990 + (set (match_operand 2)
3991 + (call (mem:QI (match_dup 0))
3992 + (match_operand 3)))]
3993 +- "!TARGET_X32 && SIBLING_CALL_P (peep2_next_insn (1))
3994 ++ "!TARGET_X32
3995 ++ && !ix86_indirect_branch_thunk_register
3996 ++ && SIBLING_CALL_P (peep2_next_insn (1))
3997 + && !reg_mentioned_p (operands[0],
3998 + CALL_INSN_FUNCTION_USAGE (peep2_next_insn (1)))"
3999 + [(parallel [(set (match_dup 2)
4000 +@@ -12070,7 +12078,9 @@
4001 + (set (match_operand 2)
4002 + (call (mem:QI (match_dup 0))
4003 + (match_operand 3)))]
4004 +- "!TARGET_X32 && SIBLING_CALL_P (peep2_next_insn (2))
4005 ++ "!TARGET_X32
4006 ++ && !ix86_indirect_branch_thunk_register
4007 ++ && SIBLING_CALL_P (peep2_next_insn (2))
4008 + && !reg_mentioned_p (operands[0],
4009 + CALL_INSN_FUNCTION_USAGE (peep2_next_insn (2)))"
4010 + [(unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)
4011 +@@ -12095,7 +12105,7 @@
4012 +
4013 + (define_insn "*call_value_pop"
4014 + [(set (match_operand 0)
4015 +- (call (mem:QI (match_operand:SI 1 "call_insn_operand" "lmBz"))
4016 ++ (call (mem:QI (match_operand:SI 1 "call_insn_operand" "lBwBz"))
4017 + (match_operand 2)))
4018 + (set (reg:SI SP_REG)
4019 + (plus:SI (reg:SI SP_REG)
4020 +diff -Naur gcc-7.2.0.orig/gcc/config/i386/i386.opt gcc-7.2.0/gcc/config/i386/i386.opt
4021 +--- gcc-7.2.0.orig/gcc/config/i386/i386.opt 2018-01-15 18:36:46.572698448 -0800
4022 ++++ gcc-7.2.0/gcc/config/i386/i386.opt 2018-01-15 18:44:35.515690050 -0800
4023 +@@ -951,3 +951,7 @@
4024 +
4025 + EnumValue
4026 + Enum(indirect_branch) String(thunk-extern) Value(indirect_branch_thunk_extern)
4027 ++
4028 ++mindirect-branch-register
4029 ++Target Report Var(ix86_indirect_branch_thunk_register) Init(0)
4030 ++Force indirect call and jump via register.
4031 +diff -Naur gcc-7.2.0.orig/gcc/config/i386/predicates.md gcc-7.2.0/gcc/config/i386/predicates.md
4032 +--- gcc-7.2.0.orig/gcc/config/i386/predicates.md 2018-01-15 18:36:46.564698448 -0800
4033 ++++ gcc-7.2.0/gcc/config/i386/predicates.md 2018-01-15 18:46:50.757687629 -0800
4034 +@@ -635,7 +635,8 @@
4035 + ;; Test for a valid operand for indirect branch.
4036 + (define_predicate "indirect_branch_operand"
4037 + (ior (match_operand 0 "register_operand")
4038 +- (and (not (match_test "TARGET_X32"))
4039 ++ (and (not (match_test "TARGET_X32
4040 ++ || ix86_indirect_branch_thunk_register"))
4041 + (match_operand 0 "memory_operand"))))
4042 +
4043 + ;; Return true if OP is a memory operands that can be used in sibcalls.
4044 +@@ -664,7 +665,8 @@
4045 +
4046 + ;; Return true if OP is a GOT memory operand.
4047 + (define_predicate "GOT_memory_operand"
4048 +- (match_operand 0 "memory_operand")
4049 ++ (and (match_test "!ix86_indirect_branch_thunk_register")
4050 ++ (match_operand 0 "memory_operand"))
4051 + {
4052 + op = XEXP (op, 0);
4053 + return (GET_CODE (op) == CONST
4054 +@@ -678,9 +680,11 @@
4055 + (ior (match_test "constant_call_address_operand
4056 + (op, mode == VOIDmode ? mode : Pmode)")
4057 + (match_operand 0 "call_register_no_elim_operand")
4058 +- (ior (and (not (match_test "TARGET_X32"))
4059 ++ (ior (and (not (match_test "TARGET_X32
4060 ++ || ix86_indirect_branch_thunk_register"))
4061 + (match_operand 0 "memory_operand"))
4062 +- (and (match_test "TARGET_X32 && Pmode == DImode")
4063 ++ (and (match_test "TARGET_X32 && Pmode == DImode
4064 ++ && !ix86_indirect_branch_thunk_register")
4065 + (match_operand 0 "GOT_memory_operand")))))
4066 +
4067 + ;; Similarly, but for tail calls, in which we cannot allow memory references.
4068 +@@ -688,14 +692,17 @@
4069 + (ior (match_test "constant_call_address_operand
4070 + (op, mode == VOIDmode ? mode : Pmode)")
4071 + (match_operand 0 "register_no_elim_operand")
4072 +- (ior (and (not (match_test "TARGET_X32"))
4073 ++ (ior (and (not (match_test "TARGET_X32
4074 ++ || ix86_indirect_branch_thunk_register"))
4075 + (match_operand 0 "sibcall_memory_operand"))
4076 +- (and (match_test "TARGET_X32 && Pmode == DImode")
4077 ++ (and (match_test "TARGET_X32 && Pmode == DImode
4078 ++ && !ix86_indirect_branch_thunk_register")
4079 + (match_operand 0 "GOT_memory_operand")))))
4080 +
4081 + ;; Return true if OP is a 32-bit GOT symbol operand.
4082 + (define_predicate "GOT32_symbol_operand"
4083 +- (match_test "GET_CODE (op) == CONST
4084 ++ (match_test "!ix86_indirect_branch_thunk_register
4085 ++ && GET_CODE (op) == CONST
4086 + && GET_CODE (XEXP (op, 0)) == UNSPEC
4087 + && XINT (XEXP (op, 0), 1) == UNSPEC_GOT"))
4088 +
4089 +diff -Naur gcc-7.2.0.orig/gcc/doc/invoke.texi gcc-7.2.0/gcc/doc/invoke.texi
4090 +--- gcc-7.2.0.orig/gcc/doc/invoke.texi 2018-01-15 18:36:44.485698486 -0800
4091 ++++ gcc-7.2.0/gcc/doc/invoke.texi 2018-01-15 18:47:25.682687003 -0800
4092 +@@ -1211,7 +1211,8 @@
4093 + -mavx256-split-unaligned-load -mavx256-split-unaligned-store @gol
4094 + -malign-data=@var{type} -mstack-protector-guard=@var{guard} @gol
4095 + -mmitigate-rop -mgeneral-regs-only @gol
4096 +--mindirect-branch=@var{choice} -mfunction-return==@var{choice}}
4097 ++-mindirect-branch=@var{choice} -mfunction-return==@var{choice} @gol
4098 ++-mindirect-branch-register}
4099 +
4100 + @emph{x86 Windows Options}
4101 + @gccoptlist{-mconsole -mcygwin -mno-cygwin -mdll @gol
4102 +@@ -25671,6 +25672,10 @@
4103 + using the function attribute @code{function_return}.
4104 + @xref{Function Attributes}.
4105 +
4106 ++@item -mindirect-branch-register
4107 ++@opindex -mindirect-branch-register
4108 ++Force indirect call and jump via register.
4109 ++
4110 + @end table
4111 +
4112 + These @samp{-m} switches are supported in addition to the above
4113 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c
4114 +index 527e447aea5..3f9b5f58ecc 100644
4115 +--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c
4116 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c
4117 +@@ -1,5 +1,5 @@
4118 + /* { dg-do compile } */
4119 +-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
4120 ++/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
4121 +
4122 + typedef void (*dispatch_t)(long offset);
4123 +
4124 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c
4125 +index 7dbc7607e2e..19f4d5e3a1e 100644
4126 +--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c
4127 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c
4128 +@@ -1,5 +1,5 @@
4129 + /* { dg-do compile } */
4130 +-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
4131 ++/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
4132 +
4133 + typedef void (*dispatch_t)(long offset);
4134 +
4135 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c
4136 +index c085b21582c..304a641db28 100644
4137 +--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c
4138 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c
4139 +@@ -1,5 +1,5 @@
4140 + /* { dg-do compile } */
4141 +-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
4142 ++/* { dg-options "-O2 -mno-indirect-branch-register -mno-indirect-branch-register -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
4143 +
4144 + typedef void (*dispatch_t)(long offset);
4145 +
4146 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c
4147 +index f92968bf616..c4eabadea7d 100644
4148 +--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c
4149 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c
4150 +@@ -1,5 +1,5 @@
4151 + /* { dg-do compile } */
4152 +-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
4153 ++/* { dg-options "-O2 -mno-indirect-branch-register -mno-indirect-branch-register -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
4154 +
4155 + typedef void (*dispatch_t)(long offset);
4156 +
4157 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c
4158 +index 4d19fac21d8..defe4389354 100644
4159 +--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c
4160 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c
4161 +@@ -1,5 +1,5 @@
4162 + /* { dg-do compile { target *-*-linux* } } */
4163 +-/* { dg-options "-O2 -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk" } */
4164 ++/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk" } */
4165 +
4166 + extern void bar (void);
4167 +
4168 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c
4169 +index 5cbdd85303e..5b202526968 100644
4170 +--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c
4171 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c
4172 +@@ -1,5 +1,5 @@
4173 + /* { dg-do compile { target *-*-linux* } } */
4174 +-/* { dg-options "-O2 -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk" } */
4175 ++/* { dg-options "-O2 -mno-indirect-branch-register -mno-indirect-branch-register -mno-indirect-branch-register -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk" } */
4176 +
4177 + extern void bar (void);
4178 +
4179 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c
4180 +index c59dd049883..d5aa68f52ca 100644
4181 +--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c
4182 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c
4183 +@@ -1,5 +1,5 @@
4184 + /* { dg-do compile } */
4185 +-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
4186 ++/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
4187 +
4188 + void func0 (void);
4189 + void func1 (void);
4190 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c
4191 +index 61b9c80de33..09c35e73443 100644
4192 +--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c
4193 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c
4194 +@@ -1,5 +1,5 @@
4195 + /* { dg-do compile } */
4196 +-/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
4197 ++/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic" } */
4198 +
4199 + typedef void (*dispatch_t)(long offset);
4200 +
4201 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c
4202 +index dcd2381c514..246300e8d71 100644
4203 +--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c
4204 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c
4205 +@@ -1,5 +1,5 @@
4206 + /* { dg-do compile } */
4207 +-/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
4208 ++/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic" } */
4209 +
4210 + typedef void (*dispatch_t)(long offset);
4211 +
4212 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c
4213 +index 21b69728796..02223f8d0f4 100644
4214 +--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c
4215 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c
4216 +@@ -1,5 +1,5 @@
4217 + /* { dg-do compile } */
4218 +-/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
4219 ++/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic" } */
4220 +
4221 + typedef void (*dispatch_t)(long offset);
4222 +
4223 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c
4224 +index 0bd6aab2fd6..a80b46af934 100644
4225 +--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c
4226 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c
4227 +@@ -1,5 +1,5 @@
4228 + /* { dg-do compile } */
4229 +-/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
4230 ++/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic" } */
4231 +
4232 + typedef void (*dispatch_t)(long offset);
4233 +
4234 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c
4235 +index 99226dbdd1f..e85057bc098 100644
4236 +--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c
4237 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c
4238 +@@ -1,5 +1,5 @@
4239 + /* { dg-do compile } */
4240 +-/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
4241 ++/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic" } */
4242 +
4243 + typedef void (*dispatch_t)(long offset);
4244 +
4245 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c
4246 +index aceb4041275..50a2d72ae16 100644
4247 +--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c
4248 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c
4249 +@@ -1,5 +1,5 @@
4250 + /* { dg-do compile } */
4251 +-/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
4252 ++/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic" } */
4253 +
4254 + typedef void (*dispatch_t)(long offset);
4255 +
4256 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c
4257 +index 43d19bbe876..eac9b3dee22 100644
4258 +--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c
4259 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c
4260 +@@ -1,5 +1,5 @@
4261 + /* { dg-do compile } */
4262 +-/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
4263 ++/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic" } */
4264 +
4265 + void func0 (void);
4266 + void func1 (void);
4267 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c
4268 +index bbfaf6ba7e7..58285f6ee6c 100644
4269 +--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c
4270 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c
4271 +@@ -1,5 +1,5 @@
4272 + /* { dg-do compile { target { ! x32 } } } */
4273 +-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
4274 ++/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
4275 +
4276 + void (*dispatch) (char *);
4277 + char buf[10];
4278 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c
4279 +index 6c82a236c1b..d3dec5623eb 100644
4280 +--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c
4281 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c
4282 +@@ -1,5 +1,5 @@
4283 + /* { dg-do compile { target { ! x32 } } } */
4284 +-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
4285 ++/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
4286 +
4287 + void (*dispatch) (char *);
4288 + char buf[10];
4289 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c
4290 +index 299940de399..c2e07d59ca4 100644
4291 +--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c
4292 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c
4293 +@@ -1,5 +1,5 @@
4294 + /* { dg-do compile { target { *-*-linux* && { ! x32 } } } } */
4295 +-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fpic -fno-plt" } */
4296 ++/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fpic -fno-plt" } */
4297 +
4298 + void bar (char *);
4299 + char buf[10];
4300 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c
4301 +index 77ee84b938b..16b64a46dbd 100644
4302 +--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c
4303 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c
4304 +@@ -1,5 +1,5 @@
4305 + /* { dg-do compile { target { *-*-linux* && { ! x32 } } } } */
4306 +-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fpic -fno-plt" } */
4307 ++/* { dg-options "-O2 -mno-indirect-branch-register -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fpic -fno-plt" } */
4308 +
4309 + void bar (char *);
4310 + char buf[10];
4311 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c
4312 +index 782960375af..cf499879513 100644
4313 +--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c
4314 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c
4315 +@@ -1,5 +1,5 @@
4316 + /* { dg-do compile } */
4317 +-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
4318 ++/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
4319 +
4320 + typedef void (*dispatch_t)(long offset);
4321 +
4322 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c
4323 +index 240c15be8a6..54c6e300295 100644
4324 +--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c
4325 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c
4326 +@@ -1,5 +1,5 @@
4327 + /* { dg-do compile } */
4328 +-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
4329 ++/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
4330 +
4331 + typedef void (*dispatch_t)(long offset);
4332 +
4333 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c
4334 +index 6e49707875e..925c7943662 100644
4335 +--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c
4336 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c
4337 +@@ -1,5 +1,5 @@
4338 + /* { dg-do compile } */
4339 +-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
4340 ++/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
4341 +
4342 + typedef void (*dispatch_t)(long offset);
4343 +
4344 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c
4345 +index e1d8891380c..0f7e39f914a 100644
4346 +--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c
4347 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c
4348 +@@ -1,5 +1,5 @@
4349 + /* { dg-do compile } */
4350 +-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
4351 ++/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
4352 +
4353 + typedef void (*dispatch_t)(long offset);
4354 +
4355 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c
4356 +index 6ad05b70604..1d34cb197a7 100644
4357 +--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c
4358 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c
4359 +@@ -1,5 +1,5 @@
4360 + /* { dg-do compile { target *-*-linux* } } */
4361 +-/* { dg-options "-O2 -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk-extern" } */
4362 ++/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk-extern" } */
4363 +
4364 + extern void bar (void);
4365 +
4366 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c
4367 +index cfb0894ae49..8d591d562a5 100644
4368 +--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c
4369 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c
4370 +@@ -1,5 +1,5 @@
4371 + /* { dg-do compile { target *-*-linux* } } */
4372 +-/* { dg-options "-O2 -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk-extern" } */
4373 ++/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk-extern" } */
4374 +
4375 + extern void bar (void);
4376 +
4377 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c
4378 +index 205b9b405bf..a288e3d61b9 100644
4379 +--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c
4380 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c
4381 +@@ -1,5 +1,5 @@
4382 + /* { dg-do compile } */
4383 +-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
4384 ++/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
4385 +
4386 + void func0 (void);
4387 + void func1 (void);
4388 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c
4389 +index efa0096e1e0..f7fad345ca4 100644
4390 +--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c
4391 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c
4392 +@@ -1,5 +1,5 @@
4393 + /* { dg-do compile } */
4394 +-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
4395 ++/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
4396 +
4397 + typedef void (*dispatch_t)(long offset);
4398 +
4399 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c
4400 +index 775d0b8c53e..91388544a20 100644
4401 +--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c
4402 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c
4403 +@@ -1,5 +1,5 @@
4404 + /* { dg-do compile } */
4405 +-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
4406 ++/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
4407 +
4408 + typedef void (*dispatch_t)(long offset);
4409 +
4410 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c
4411 +index 788271f049f..69f03e6472e 100644
4412 +--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c
4413 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c
4414 +@@ -1,5 +1,5 @@
4415 + /* { dg-do compile } */
4416 +-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
4417 ++/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
4418 +
4419 + typedef void (*dispatch_t)(long offset);
4420 +
4421 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c
4422 +index ef8a2c746a7..226b776abcf 100644
4423 +--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c
4424 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c
4425 +@@ -1,5 +1,5 @@
4426 + /* { dg-do compile } */
4427 +-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
4428 ++/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
4429 +
4430 + typedef void (*dispatch_t)(long offset);
4431 +
4432 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c
4433 +index 848ceefca02..b9120017c10 100644
4434 +--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c
4435 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c
4436 +@@ -1,5 +1,5 @@
4437 + /* { dg-do compile { target *-*-linux* } } */
4438 +-/* { dg-options "-O2 -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk-inline" } */
4439 ++/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk-inline" } */
4440 +
4441 + extern void bar (void);
4442 +
4443 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c
4444 +index 64608100782..fbd6f9ec457 100644
4445 +--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c
4446 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c
4447 +@@ -1,5 +1,5 @@
4448 + /* { dg-do compile { target *-*-linux* } } */
4449 +-/* { dg-options "-O2 -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk-inline" } */
4450 ++/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk-inline" } */
4451 +
4452 + extern void bar (void);
4453 +
4454 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c
4455 +index 3c2758360f5..2553c56f97f 100644
4456 +--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c
4457 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c
4458 +@@ -1,5 +1,5 @@
4459 + /* { dg-do compile } */
4460 +-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
4461 ++/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
4462 +
4463 + void func0 (void);
4464 + void func1 (void);
4465 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-register-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-register-1.c
4466 +new file mode 100644
4467 +index 00000000000..7d396a31953
4468 +--- /dev/null
4469 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-register-1.c
4470 +@@ -0,0 +1,22 @@
4471 ++/* { dg-do compile } */
4472 ++/* { dg-options "-O2 -mindirect-branch=thunk -mindirect-branch-register -fno-pic" } */
4473 ++
4474 ++typedef void (*dispatch_t)(long offset);
4475 ++
4476 ++dispatch_t dispatch;
4477 ++
4478 ++void
4479 ++male_indirect_jump (long offset)
4480 ++{
4481 ++ dispatch(offset);
4482 ++}
4483 ++
4484 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" } } */
4485 ++/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
4486 ++/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
4487 ++/* { dg-final { scan-assembler "mov\[ \t\](%eax|%rax), \\((%esp|%rsp)\\)" } } */
4488 ++/* { dg-final { scan-assembler {\tpause} } } */
4489 ++/* { dg-final { scan-assembler-not "push(?:l|q)\[ \t\]*_?dispatch" } } */
4490 ++/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" } } */
4491 ++/* { dg-final { scan-assembler-not "__x86_indirect_thunk\n" } } */
4492 ++/* { dg-final { scan-assembler-not "__x86_indirect_thunk_bnd\n" } } */
4493 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-register-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-register-2.c
4494 +new file mode 100644
4495 +index 00000000000..e7e616bb271
4496 +--- /dev/null
4497 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-register-2.c
4498 +@@ -0,0 +1,20 @@
4499 ++/* { dg-do compile } */
4500 ++/* { dg-options "-O2 -mindirect-branch=thunk-inline -mindirect-branch-register -fno-pic" } */
4501 ++
4502 ++typedef void (*dispatch_t)(long offset);
4503 ++
4504 ++dispatch_t dispatch;
4505 ++
4506 ++void
4507 ++male_indirect_jump (long offset)
4508 ++{
4509 ++ dispatch(offset);
4510 ++}
4511 ++
4512 ++/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
4513 ++/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
4514 ++/* { dg-final { scan-assembler "mov\[ \t\](%eax|%rax), \\((%esp|%rsp)\\)" } } */
4515 ++/* { dg-final { scan-assembler {\tpause} } } */
4516 ++/* { dg-final { scan-assembler-not "push(?:l|q)\[ \t\]*_?dispatch" } } */
4517 ++/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" } } */
4518 ++/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
4519 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-register-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-register-3.c
4520 +new file mode 100644
4521 +index 00000000000..5320e923be2
4522 +--- /dev/null
4523 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-register-3.c
4524 +@@ -0,0 +1,19 @@
4525 ++/* { dg-do compile } */
4526 ++/* { dg-options "-O2 -mindirect-branch=thunk-extern -mindirect-branch-register -fno-pic" } */
4527 ++
4528 ++typedef void (*dispatch_t)(long offset);
4529 ++
4530 ++dispatch_t dispatch;
4531 ++
4532 ++void
4533 ++male_indirect_jump (long offset)
4534 ++{
4535 ++ dispatch(offset);
4536 ++}
4537 ++
4538 ++/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" } } */
4539 ++/* { dg-final { scan-assembler-not "push(?:l|q)\[ \t\]*_?dispatch" } } */
4540 ++/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" } } */
4541 ++/* { dg-final { scan-assembler-not {\t(pause|pause|nop)} } } */
4542 ++/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
4543 ++/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
4544 +diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-10.c b/gcc/testsuite/gcc.target/i386/ret-thunk-10.c
4545 +index b5164bfc5ad..c440d68ec0d 100644
4546 +--- a/gcc/testsuite/gcc.target/i386/ret-thunk-10.c
4547 ++++ b/gcc/testsuite/gcc.target/i386/ret-thunk-10.c
4548 +@@ -1,5 +1,5 @@
4549 + /* { dg-do compile } */
4550 +-/* { dg-options "-O2 -mfunction-return=thunk-inline -mindirect-branch=thunk -fno-pic" } */
4551 ++/* { dg-options "-O2 -mno-indirect-branch-register -mno-indirect-branch-register -mfunction-return=thunk-inline -mindirect-branch=thunk -fno-pic" } */
4552 +
4553 + extern void (*bar) (void);
4554 +
4555 +diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-11.c b/gcc/testsuite/gcc.target/i386/ret-thunk-11.c
4556 +index a26ac963ea5..674a6bf96e8 100644
4557 +--- a/gcc/testsuite/gcc.target/i386/ret-thunk-11.c
4558 ++++ b/gcc/testsuite/gcc.target/i386/ret-thunk-11.c
4559 +@@ -1,5 +1,5 @@
4560 + /* { dg-do compile } */
4561 +-/* { dg-options "-O2 -mfunction-return=thunk-extern -mindirect-branch=thunk -fno-pic" } */
4562 ++/* { 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" } */
4563 +
4564 + extern void (*bar) (void);
4565 +
4566 +diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-12.c b/gcc/testsuite/gcc.target/i386/ret-thunk-12.c
4567 +index d0106da38ee..3f37e4375de 100644
4568 +--- a/gcc/testsuite/gcc.target/i386/ret-thunk-12.c
4569 ++++ b/gcc/testsuite/gcc.target/i386/ret-thunk-12.c
4570 +@@ -1,5 +1,5 @@
4571 + /* { dg-do compile } */
4572 +-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
4573 ++/* { 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" } */
4574 +
4575 + extern void (*bar) (void);
4576 +
4577 +diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-13.c b/gcc/testsuite/gcc.target/i386/ret-thunk-13.c
4578 +index 185ad366190..f96e6847f13 100644
4579 +--- a/gcc/testsuite/gcc.target/i386/ret-thunk-13.c
4580 ++++ b/gcc/testsuite/gcc.target/i386/ret-thunk-13.c
4581 +@@ -1,5 +1,5 @@
4582 + /* { dg-do compile } */
4583 +-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
4584 ++/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
4585 +
4586 + extern void (*bar) (void);
4587 + extern int foo (void) __attribute__ ((function_return("thunk")));
4588 +diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-14.c b/gcc/testsuite/gcc.target/i386/ret-thunk-14.c
4589 +index cce8b20b5f1..4c47b28691e 100644
4590 +--- a/gcc/testsuite/gcc.target/i386/ret-thunk-14.c
4591 ++++ b/gcc/testsuite/gcc.target/i386/ret-thunk-14.c
4592 +@@ -1,5 +1,5 @@
4593 + /* { dg-do compile } */
4594 +-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
4595 ++/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
4596 +
4597 + extern void (*bar) (void);
4598 +
4599 +diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-15.c b/gcc/testsuite/gcc.target/i386/ret-thunk-15.c
4600 +index 0316d301d9c..43d84743851 100644
4601 +--- a/gcc/testsuite/gcc.target/i386/ret-thunk-15.c
4602 ++++ b/gcc/testsuite/gcc.target/i386/ret-thunk-15.c
4603 +@@ -1,5 +1,5 @@
4604 + /* { dg-do compile } */
4605 +-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=keep -fno-pic" } */
4606 ++/* { 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" } */
4607 +
4608 + extern void (*bar) (void);
4609 +
4610 +diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-9.c b/gcc/testsuite/gcc.target/i386/ret-thunk-9.c
4611 +index 92298c362ec..a56a4849f76 100644
4612 +--- a/gcc/testsuite/gcc.target/i386/ret-thunk-9.c
4613 ++++ b/gcc/testsuite/gcc.target/i386/ret-thunk-9.c
4614 +@@ -1,5 +1,5 @@
4615 + /* { dg-do compile } */
4616 +-/* { dg-options "-O2 -mfunction-return=thunk -mindirect-branch=thunk -fno-pic" } */
4617 ++/* { dg-options "-O2 -mno-indirect-branch-register -mno-indirect-branch-register -mfunction-return=thunk -mindirect-branch=thunk -fno-pic" } */
4618 +
4619 + extern void (*bar) (void);
4620 +
4621 +--
4622 +2.14.3
4623 +
4624
4625 diff --git a/sys-devel/gcc/files/spectre-0004-v-register-modifier.patch b/sys-devel/gcc/files/spectre-0004-v-register-modifier.patch
4626 new file mode 100644
4627 index 0000000..afbccca
4628 --- /dev/null
4629 +++ b/sys-devel/gcc/files/spectre-0004-v-register-modifier.patch
4630 @@ -0,0 +1,128 @@
4631 +From: "H dot J dot Lu" <hjl dot tools at gmail dot com>
4632 +To: gcc-patches at gcc dot gnu dot org
4633 +Subject: [PATCH 4/4] x86: Add 'V' register operand modifier
4634 +Date: Fri, 12 Jan 2018 05:15:49 -0800
4635 +
4636 +Add 'V', a special modifier which prints the name of the full integer
4637 +register without '%'. For
4638 +
4639 +extern void (*func_p) (void);
4640 +
4641 +void
4642 +foo (void)
4643 +{
4644 + asm ("call __x86_indirect_thunk_%V0" : : "a" (func_p));
4645 +}
4646 +
4647 +it generates:
4648 +
4649 +foo:
4650 + movq func_p(%rip), %rax
4651 + call __x86_indirect_thunk_rax
4652 + ret
4653 +
4654 +gcc/
4655 +
4656 + * config/i386/i386.c (print_reg): Print the name of the full
4657 + integer register without '%'.
4658 + (ix86_print_operand): Handle 'V'.
4659 + * doc/extend.texi: Document 'V' modifier.
4660 +
4661 +gcc/testsuite/
4662 +
4663 + * gcc.target/i386/indirect-thunk-register-4.c: New test.
4664 +---
4665 + gcc/config/i386/i386.c | 13 ++++++++++++-
4666 + gcc/doc/extend.texi | 3 +++
4667 + gcc/testsuite/gcc.target/i386/indirect-thunk-register-4.c | 13 +++++++++++++
4668 + 3 files changed, 28 insertions(+), 1 deletion(-)
4669 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-register-4.c
4670 +
4671 +diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
4672 +index 9ffcb69d6d7..e69135d7191 100644
4673 +--- a/gcc/config/i386/i386.c
4674 ++++ b/gcc/config/i386/i386.c
4675 +@@ -17617,6 +17617,7 @@ put_condition_code (enum rtx_code code, machine_mode mode, bool reverse,
4676 + If CODE is 'h', pretend the reg is the 'high' byte register.
4677 + If CODE is 'y', print "st(0)" instead of "st", if the reg is stack op.
4678 + If CODE is 'd', duplicate the operand for AVX instruction.
4679 ++ If CODE is 'V', print naked full integer register name without %.
4680 + */
4681 +
4682 + void
4683 +@@ -17627,7 +17628,7 @@ print_reg (rtx x, int code, FILE *file)
4684 + unsigned int regno;
4685 + bool duplicated;
4686 +
4687 +- if (ASSEMBLER_DIALECT == ASM_ATT)
4688 ++ if (ASSEMBLER_DIALECT == ASM_ATT && code != 'V')
4689 + putc ('%', file);
4690 +
4691 + if (x == pc_rtx)
4692 +@@ -17679,6 +17680,14 @@ print_reg (rtx x, int code, FILE *file)
4693 + return;
4694 + }
4695 +
4696 ++ if (code == 'V')
4697 ++ {
4698 ++ if (GENERAL_REGNO_P (regno))
4699 ++ msize = GET_MODE_SIZE (word_mode);
4700 ++ else
4701 ++ error ("'V' modifier on non-integer register");
4702 ++ }
4703 ++
4704 + duplicated = code == 'd' && TARGET_AVX;
4705 +
4706 + switch (msize)
4707 +@@ -17798,6 +17807,7 @@ print_reg (rtx x, int code, FILE *file)
4708 + & -- print some in-use local-dynamic symbol name.
4709 + H -- print a memory address offset by 8; used for sse high-parts
4710 + Y -- print condition for XOP pcom* instruction.
4711 ++ V -- print naked full integer register name without %.
4712 + + -- print a branch hint as 'cs' or 'ds' prefix
4713 + ; -- print a semicolon (after prefixes due to bug in older gas).
4714 + ~ -- print "i" if TARGET_AVX2, "f" otherwise.
4715 +@@ -18021,6 +18031,7 @@ ix86_print_operand (FILE *file, rtx x, int code)
4716 + case 'X':
4717 + case 'P':
4718 + case 'p':
4719 ++ case 'V':
4720 + break;
4721 +
4722 + case 's':
4723 +diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
4724 +index f120b2a1429..dce808f1eab 100644
4725 +--- a/gcc/doc/extend.texi
4726 ++++ b/gcc/doc/extend.texi
4727 +@@ -9292,6 +9292,9 @@ The table below shows the list of supported modifiers and their effects.
4728 + @tab @code{2}
4729 + @end multitable
4730 +
4731 ++@code{V} is a special modifier which prints the name of the full integer
4732 ++register without @code{%}.
4733 ++
4734 + @anchor{x86floatingpointasmoperands}
4735 + @subsubsection x86 Floating-Point @code{asm} Operands
4736 +
4737 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-register-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-register-4.c
4738 +new file mode 100644
4739 +index 00000000000..f0cd9b75be8
4740 +--- /dev/null
4741 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-register-4.c
4742 +@@ -0,0 +1,13 @@
4743 ++/* { dg-do compile } */
4744 ++/* { dg-options "-O2 -mindirect-branch=keep -fno-pic" } */
4745 ++
4746 ++extern void (*func_p) (void);
4747 ++
4748 ++void
4749 ++foo (void)
4750 ++{
4751 ++ asm("call __x86_indirect_thunk_%V0" : : "a" (func_p));
4752 ++}
4753 ++
4754 ++/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_eax" { target ia32 } } } */
4755 ++/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_rax" { target { ! ia32 } } } } */
4756 +--
4757 +2.14.3
4758 +
4759
4760 diff --git a/sys-devel/gcc/files/spectre-0005-mcmodel-large.patch b/sys-devel/gcc/files/spectre-0005-mcmodel-large.patch
4761 new file mode 100644
4762 index 0000000..51c56c9
4763 --- /dev/null
4764 +++ b/sys-devel/gcc/files/spectre-0005-mcmodel-large.patch
4765 @@ -0,0 +1,292 @@
4766 +From: "H dot J dot Lu" <hjl dot tools at gmail dot com>
4767 +To: gcc-patches at gcc dot gnu dot org
4768 +Subject: [PATCH 5/5] x86: Disallow -mindirect-branch=/-mfunction-return= with -mcmodel=large
4769 +Date: Sat, 13 Jan 2018 19:37:07 -0800
4770 +
4771 +Since the thunk function may not be reachable in large code model,
4772 +-mcmodel=large is incompatible with -mindirect-branch=thunk,
4773 +-mindirect-branch=thunk-extern, -mfunction-return=thunk and
4774 +-mfunction-return=thunk-extern. Issue an error when they are used with
4775 +-mcmodel=large.
4776 +
4777 +gcc/
4778 +
4779 + * config/i386/i386.c (ix86_set_indirect_branch_type): Disallow
4780 + -mcmodel=large with -mindirect-branch=thunk,
4781 + -mindirect-branch=thunk-extern, -mfunction-return=thunk and
4782 + -mfunction-return=thunk-extern.
4783 + * doc/invoke.texi: Document -mcmodel=large is incompatible with
4784 + -mindirect-branch=thunk, -mindirect-branch=thunk-extern,
4785 + -mfunction-return=thunk and -mfunction-return=thunk-extern.
4786 +
4787 +gcc/testsuite/
4788 +
4789 + * gcc.target/i386/indirect-thunk-10.c: New test.
4790 + * gcc.target/i386/indirect-thunk-8.c: Likewise.
4791 + * gcc.target/i386/indirect-thunk-9.c: Likewise.
4792 + * gcc.target/i386/indirect-thunk-attr-10.c: Likewise.
4793 + * gcc.target/i386/indirect-thunk-attr-11.c: Likewise.
4794 + * gcc.target/i386/indirect-thunk-attr-9.c: Likewise.
4795 + * gcc.target/i386/ret-thunk-17.c: Likewise.
4796 + * gcc.target/i386/ret-thunk-18.c: Likewise.
4797 + * gcc.target/i386/ret-thunk-19.c: Likewise.
4798 + * gcc.target/i386/ret-thunk-20.c: Likewise.
4799 + * gcc.target/i386/ret-thunk-21.c: Likewise.
4800 +---
4801 + gcc/config/i386/i386.c | 26 ++++++++++++++++++++++
4802 + gcc/doc/invoke.texi | 11 +++++++++
4803 + gcc/testsuite/gcc.target/i386/indirect-thunk-10.c | 7 ++++++
4804 + gcc/testsuite/gcc.target/i386/indirect-thunk-8.c | 7 ++++++
4805 + gcc/testsuite/gcc.target/i386/indirect-thunk-9.c | 7 ++++++
4806 + .../gcc.target/i386/indirect-thunk-attr-10.c | 9 ++++++++
4807 + .../gcc.target/i386/indirect-thunk-attr-11.c | 9 ++++++++
4808 + .../gcc.target/i386/indirect-thunk-attr-9.c | 9 ++++++++
4809 + gcc/testsuite/gcc.target/i386/ret-thunk-17.c | 7 ++++++
4810 + gcc/testsuite/gcc.target/i386/ret-thunk-18.c | 8 +++++++
4811 + gcc/testsuite/gcc.target/i386/ret-thunk-19.c | 8 +++++++
4812 + gcc/testsuite/gcc.target/i386/ret-thunk-20.c | 9 ++++++++
4813 + gcc/testsuite/gcc.target/i386/ret-thunk-21.c | 9 ++++++++
4814 + 13 files changed, 126 insertions(+)
4815 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-10.c
4816 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-8.c
4817 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-9.c
4818 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-10.c
4819 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-11.c
4820 + create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-9.c
4821 + create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-17.c
4822 + create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-18.c
4823 + create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-19.c
4824 + create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-20.c
4825 + create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-21.c
4826 +
4827 +diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
4828 +index 9807de0c117..92b328ebfc2 100644
4829 +--- a/gcc/config/i386/i386.c
4830 ++++ b/gcc/config/i386/i386.c
4831 +@@ -5836,6 +5836,19 @@ ix86_set_indirect_branch_type (tree fndecl)
4832 + }
4833 + else
4834 + cfun->machine->indirect_branch_type = ix86_indirect_branch;
4835 ++
4836 ++ /* -mcmodel=large is not compatible with -mindirect-branch=thunk
4837 ++ nor -mindirect-branch=thunk-extern. */
4838 ++ if ((ix86_cmodel == CM_LARGE || ix86_cmodel == CM_LARGE_PIC)
4839 ++ && ((cfun->machine->indirect_branch_type
4840 ++ == indirect_branch_thunk_extern)
4841 ++ || (cfun->machine->indirect_branch_type
4842 ++ == indirect_branch_thunk)))
4843 ++ error ("%<-mindirect-branch=%s%> and %<-mcmodel=large%> are not "
4844 ++ "compatible",
4845 ++ ((cfun->machine->indirect_branch_type
4846 ++ == indirect_branch_thunk_extern)
4847 ++ ? "thunk-extern" : "thunk"));
4848 + }
4849 +
4850 + if (cfun->machine->function_return_type == indirect_branch_unset)
4851 +@@ -5861,6 +5874,19 @@ ix86_set_indirect_branch_type (tree fndecl)
4852 + }
4853 + else
4854 + cfun->machine->function_return_type = ix86_function_return;
4855 ++
4856 ++ /* -mcmodel=large is not compatible with -mfunction-return=thunk
4857 ++ nor -mfunction-return=thunk-extern. */
4858 ++ if ((ix86_cmodel == CM_LARGE || ix86_cmodel == CM_LARGE_PIC)
4859 ++ && ((cfun->machine->function_return_type
4860 ++ == indirect_branch_thunk_extern)
4861 ++ || (cfun->machine->function_return_type
4862 ++ == indirect_branch_thunk)))
4863 ++ error ("%<-mfunction-return=%s%> and %<-mcmodel=large%> are not "
4864 ++ "compatible",
4865 ++ ((cfun->machine->function_return_type
4866 ++ == indirect_branch_thunk_extern)
4867 ++ ? "thunk-extern" : "thunk"));
4868 + }
4869 + }
4870 +
4871 +diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
4872 +index d16006e653a..2495a45c957 100644
4873 +--- a/gcc/doc/invoke.texi
4874 ++++ b/gcc/doc/invoke.texi
4875 +@@ -26851,6 +26851,11 @@ to external call and return thunk provided in a separate object file.
4876 + You can control this behavior for a specific function by using the
4877 + function attribute @code{indirect_branch}. @xref{Function Attributes}.
4878 +
4879 ++Note that @option{-mcmodel=large} is incompatible with
4880 ++@option{-mindirect-branch=thunk} nor
4881 ++@option{-mindirect-branch=thunk-extern} since the thunk function may
4882 ++not be reachable in large code model.
4883 ++
4884 + @item -mfunction-return=@var{choice}
4885 + @opindex -mfunction-return
4886 + Convert function return with @var{choice}. The default is @samp{keep},
4887 +@@ -26862,6 +26867,12 @@ object file. You can control this behavior for a specific function by
4888 + using the function attribute @code{function_return}.
4889 + @xref{Function Attributes}.
4890 +
4891 ++Note that @option{-mcmodel=large} is incompatible with
4892 ++@option{-mfunction-return=thunk} nor
4893 ++@option{-mfunction-return=thunk-extern} since the thunk function may
4894 ++not be reachable in large code model.
4895 ++
4896 ++
4897 + @item -mindirect-branch-register
4898 + @opindex -mindirect-branch-register
4899 + Force indirect call and jump via register.
4900 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-10.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-10.c
4901 +new file mode 100644
4902 +index 00000000000..5623f162dea
4903 +--- /dev/null
4904 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-10.c
4905 +@@ -0,0 +1,7 @@
4906 ++/* { dg-do compile { target { ! ia32 } } } */
4907 ++/* { dg-options "-O2 -mindirect-branch=thunk-inline -mfunction-return=keep -mcmodel=large" } */
4908 ++
4909 ++void
4910 ++bar (void)
4911 ++{
4912 ++}
4913 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-8.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-8.c
4914 +new file mode 100644
4915 +index 00000000000..d6c1437bcf1
4916 +--- /dev/null
4917 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-8.c
4918 +@@ -0,0 +1,7 @@
4919 ++/* { dg-do compile { target { ! ia32 } } } */
4920 ++/* { dg-options "-O2 -mindirect-branch=thunk -mfunction-return=keep -mcmodel=large" } */
4921 ++
4922 ++void
4923 ++bar (void)
4924 ++{ /* { dg-error "'-mindirect-branch=thunk' and '-mcmodel=large' are not compatible" } */
4925 ++}
4926 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-9.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-9.c
4927 +new file mode 100644
4928 +index 00000000000..6914dac27ce
4929 +--- /dev/null
4930 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-9.c
4931 +@@ -0,0 +1,7 @@
4932 ++/* { dg-do compile { target { ! ia32 } } } */
4933 ++/* { dg-options "-O2 -mindirect-branch=thunk-extern -mfunction-return=keep -mcmodel=large" } */
4934 ++
4935 ++void
4936 ++bar (void)
4937 ++{ /* { dg-error "'-mindirect-branch=thunk-extern' and '-mcmodel=large' are not compatible" } */
4938 ++}
4939 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-10.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-10.c
4940 +new file mode 100644
4941 +index 00000000000..87c7684aa92
4942 +--- /dev/null
4943 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-10.c
4944 +@@ -0,0 +1,9 @@
4945 ++/* { dg-do compile { target { ! ia32 } } } */
4946 ++/* { dg-options "-O2 -mindirect-branch=keep -mfunction-return=keep -mcmodel=large" } */
4947 ++/* { dg-additional-options "-fPIC" { target fpic } } */
4948 ++
4949 ++__attribute__ ((indirect_branch("thunk-extern")))
4950 ++void
4951 ++bar (void)
4952 ++{ /* { dg-error "'-mindirect-branch=thunk-extern' and '-mcmodel=large' are not compatible" } */
4953 ++}
4954 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-11.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-11.c
4955 +new file mode 100644
4956 +index 00000000000..0499c1d7d27
4957 +--- /dev/null
4958 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-11.c
4959 +@@ -0,0 +1,9 @@
4960 ++/* { dg-do compile { target { ! ia32 } } } */
4961 ++/* { dg-options "-O2 -mindirect-branch=keep -mfunction-return=keep -mcmodel=large" } */
4962 ++/* { dg-additional-options "-fPIC" { target fpic } } */
4963 ++
4964 ++__attribute__ ((indirect_branch("thunk-inline")))
4965 ++void
4966 ++bar (void)
4967 ++{
4968 ++}
4969 +diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-9.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-9.c
4970 +new file mode 100644
4971 +index 00000000000..3f1d4f54884
4972 +--- /dev/null
4973 ++++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-9.c
4974 +@@ -0,0 +1,9 @@
4975 ++/* { dg-do compile { target { ! ia32 } } } */
4976 ++/* { dg-options "-O2 -mindirect-branch=keep -mfunction-return=keep -mcmodel=large" } */
4977 ++/* { dg-additional-options "-fPIC" { target fpic } } */
4978 ++
4979 ++__attribute__ ((indirect_branch("thunk")))
4980 ++void
4981 ++bar (void)
4982 ++{ /* { dg-error "'-mindirect-branch=thunk' and '-mcmodel=large' are not compatible" } */
4983 ++}
4984 +diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-17.c b/gcc/testsuite/gcc.target/i386/ret-thunk-17.c
4985 +new file mode 100644
4986 +index 00000000000..930f72713ae
4987 +--- /dev/null
4988 ++++ b/gcc/testsuite/gcc.target/i386/ret-thunk-17.c
4989 +@@ -0,0 +1,7 @@
4990 ++/* { dg-do compile { target { ! ia32 } } } */
4991 ++/* { dg-options "-O2 -mfunction-return=thunk -mindirect-branch=keep -mcmodel=large" } */
4992 ++
4993 ++void
4994 ++bar (void)
4995 ++{ /* { dg-error "'-mfunction-return=thunk' and '-mcmodel=large' are not compatible" } */
4996 ++}
4997 +diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-18.c b/gcc/testsuite/gcc.target/i386/ret-thunk-18.c
4998 +new file mode 100644
4999 +index 00000000000..5763fde84b1
5000 +--- /dev/null
5001 ++++ b/gcc/testsuite/gcc.target/i386/ret-thunk-18.c
5002 +@@ -0,0 +1,8 @@
5003 ++/* { dg-do compile { target { ! ia32 } } } */
5004 ++/* { dg-options "-O2 -mfunction-return=thunk-extern -mindirect-branch=keep -mcmodel=large" } */
5005 ++/* { dg-additional-options "-fPIC" { target fpic } } */
5006 ++
5007 ++void
5008 ++bar (void)
5009 ++{ /* { dg-error "'-mfunction-return=thunk-extern' and '-mcmodel=large' are not compatible" } */
5010 ++}
5011 +diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-19.c b/gcc/testsuite/gcc.target/i386/ret-thunk-19.c
5012 +new file mode 100644
5013 +index 00000000000..ff710d4c1fe
5014 +--- /dev/null
5015 ++++ b/gcc/testsuite/gcc.target/i386/ret-thunk-19.c
5016 +@@ -0,0 +1,8 @@
5017 ++/* { dg-do compile { target { ! ia32 } } } */
5018 ++/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=keep -mcmodel=large" } */
5019 ++
5020 ++__attribute__ ((function_return("thunk")))
5021 ++void
5022 ++bar (void)
5023 ++{ /* { dg-error "'-mfunction-return=thunk' and '-mcmodel=large' are not compatible" } */
5024 ++}
5025 +diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-20.c b/gcc/testsuite/gcc.target/i386/ret-thunk-20.c
5026 +new file mode 100644
5027 +index 00000000000..eeffbd2289a
5028 +--- /dev/null
5029 ++++ b/gcc/testsuite/gcc.target/i386/ret-thunk-20.c
5030 +@@ -0,0 +1,9 @@
5031 ++/* { dg-do compile { target { ! ia32 } } } */
5032 ++/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=keep -mcmodel=large" } */
5033 ++/* { dg-additional-options "-fPIC" { target fpic } } */
5034 ++
5035 ++__attribute__ ((function_return("thunk-extern")))
5036 ++void
5037 ++bar (void)
5038 ++{ /* { dg-error "'-mfunction-return=thunk-extern' and '-mcmodel=large' are not compatible" } */
5039 ++}
5040 +diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-21.c b/gcc/testsuite/gcc.target/i386/ret-thunk-21.c
5041 +new file mode 100644
5042 +index 00000000000..49ab118e04f
5043 +--- /dev/null
5044 ++++ b/gcc/testsuite/gcc.target/i386/ret-thunk-21.c
5045 +@@ -0,0 +1,9 @@
5046 ++/* { dg-do compile { target { ! ia32 } } } */
5047 ++/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=keep -mcmodel=large" } */
5048 ++/* { dg-additional-options "-fPIC" { target fpic } } */
5049 ++
5050 ++__attribute__ ((function_return("thunk-inline")))
5051 ++void
5052 ++bar (void)
5053 ++{
5054 ++}
5055 +--
5056 +2.14.3
5057 +
5058
5059 diff --git a/sys-devel/gcc/gcc-7.2.0-r1.ebuild b/sys-devel/gcc/gcc-7.2.0-r1.ebuild
5060 index 1ef1af3..c6f78df 100644
5061 --- a/sys-devel/gcc/gcc-7.2.0-r1.ebuild
5062 +++ b/sys-devel/gcc/gcc-7.2.0-r1.ebuild
5063 @@ -8,8 +8,7 @@ PATCH_VER="1.1"
5064
5065 inherit epatch toolchain
5066
5067 -# unkeyworded for testing bug #641474
5068 -#KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~m68k ~mips ~ppc ~ppc64 ~s390 ~sh ~sparc ~x86 ~amd64-fbsd ~x86-fbsd"
5069 +KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~m68k ~mips ~ppc ~ppc64 ~s390 ~sh ~sparc ~x86 ~amd64-fbsd ~x86-fbsd"
5070
5071 RDEPEND=""
5072 DEPEND="${RDEPEND}
5073 @@ -25,6 +24,17 @@ src_prepare() {
5074
5075 epatch "${FILESDIR}"/gcc-7.2.0-pr69728.patch
5076
5077 + # Meltdown/Spectre
5078 + epatch "${FILESDIR}"/0001-gcc-7.2.0-move-struct-ix86_frame-to-machine-function.patch
5079 + epatch "${FILESDIR}"/0002-gcc-7.2.0-move-struct-ix86_frame-to-machine-function.patch
5080 + epatch "${FILESDIR}"/0003-gcc-7.2.0-move-struct-ix86_frame-to-machine-function.patch
5081 +
5082 + epatch "${FILESDIR}"/spectre-0001-mindirect-branch.patch
5083 + epatch "${FILESDIR}"/spectre-0002-mfunction-return.patch
5084 + epatch "${FILESDIR}"/spectre-0003-mindirect-branch-register.patch
5085 + epatch "${FILESDIR}"/spectre-0004-v-register-modifier.patch
5086 + epatch "${FILESDIR}"/spectre-0005-mcmodel-large.patch
5087 +
5088 if use elibc_musl || [[ ${CATEGORY} = cross-*-musl* ]]; then
5089 epatch "${FILESDIR}"/6.3.0/cpu_indicator.patch
5090 epatch "${FILESDIR}"/7.1.0/posix_memalign.patch