summaryrefslogtreecommitdiffstats
path: root/meta/recipes-devtools/gcc/gcc-6.4/backport/0004-x86-Add-mindirect-branch.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-devtools/gcc/gcc-6.4/backport/0004-x86-Add-mindirect-branch.patch')
-rw-r--r--meta/recipes-devtools/gcc/gcc-6.4/backport/0004-x86-Add-mindirect-branch.patch2154
1 files changed, 2154 insertions, 0 deletions
diff --git a/meta/recipes-devtools/gcc/gcc-6.4/backport/0004-x86-Add-mindirect-branch.patch b/meta/recipes-devtools/gcc/gcc-6.4/backport/0004-x86-Add-mindirect-branch.patch
new file mode 100644
index 0000000000..a9d6e5ff2d
--- /dev/null
+++ b/meta/recipes-devtools/gcc/gcc-6.4/backport/0004-x86-Add-mindirect-branch.patch
@@ -0,0 +1,2154 @@
1From 6140c2c0bb2b61e69d0da84315e0433ff3520aaa Mon Sep 17 00:00:00 2001
2From: "H.J. Lu" <hjl.tools@gmail.com>
3Date: Sat, 6 Jan 2018 22:29:55 -0800
4Subject: [PATCH 04/12] x86: Add -mindirect-branch=
5
6Add -mindirect-branch= option to convert indirect call and jump to call
7and return thunks. The default is 'keep', which keeps indirect call and
8jump unmodified. 'thunk' converts indirect call and jump to call and
9return thunk. 'thunk-inline' converts indirect call and jump to inlined
10call and return thunk. 'thunk-extern' converts indirect call and jump to
11external call and return thunk provided in a separate object file. You
12can control this behavior for a specific function by using the function
13attribute indirect_branch.
14
152 kinds of thunks are geneated. Memory thunk where the function address
16is at the top of the stack:
17
18__x86_indirect_thunk:
19 call L2
20L1:
21 pause
22 lfence
23 jmp L1
24L2:
25 lea 8(%rsp), %rsp|lea 4(%esp), %esp
26 ret
27
28Indirect jmp via memory, "jmp mem", is converted to
29
30 push memory
31 jmp __x86_indirect_thunk
32
33Indirect call via memory, "call mem", is converted to
34
35 jmp L2
36L1:
37 push [mem]
38 jmp __x86_indirect_thunk
39L2:
40 call L1
41
42Register thunk where the function address is in a register, reg:
43
44__x86_indirect_thunk_reg:
45 call L2
46L1:
47 pause
48 lfence
49 jmp L1
50L2:
51 movq %reg, (%rsp)|movl %reg, (%esp)
52 ret
53
54where reg is one of (r|e)ax, (r|e)dx, (r|e)cx, (r|e)bx, (r|e)si, (r|e)di,
55(r|e)bp, r8, r9, r10, r11, r12, r13, r14 and r15.
56
57Indirect jmp via register, "jmp reg", is converted to
58
59 jmp __x86_indirect_thunk_reg
60
61Indirect call via register, "call reg", is converted to
62
63 call __x86_indirect_thunk_reg
64
65gcc/
66
67 Backport from mainline
68 2018-01-14 H.J. Lu <hongjiu.lu@intel.com>
69
70 * config/i386/i386-opts.h (indirect_branch): New.
71 * config/i386/i386-protos.h (ix86_output_indirect_jmp): Likewise.
72 * config/i386/i386.c (ix86_using_red_zone): Disallow red-zone
73 with local indirect jump when converting indirect call and jump.
74 (ix86_set_indirect_branch_type): New.
75 (ix86_set_current_function): Call ix86_set_indirect_branch_type.
76 (indirectlabelno): New.
77 (indirect_thunk_needed): Likewise.
78 (indirect_thunk_bnd_needed): Likewise.
79 (indirect_thunks_used): Likewise.
80 (indirect_thunks_bnd_used): Likewise.
81 (INDIRECT_LABEL): Likewise.
82 (indirect_thunk_name): Likewise.
83 (output_indirect_thunk): Likewise.
84 (output_indirect_thunk_function): Likewise.
85 (ix86_output_indirect_branch_via_reg): Likewise.
86 (ix86_output_indirect_branch_via_push): Likewise.
87 (ix86_output_indirect_branch): Likewise.
88 (ix86_output_indirect_jmp): Likewise.
89 (ix86_code_end): Call output_indirect_thunk_function if needed.
90 (ix86_output_call_insn): Call ix86_output_indirect_branch if
91 needed.
92 (ix86_handle_fndecl_attribute): Handle indirect_branch.
93 (ix86_attribute_table): Add indirect_branch.
94 * config/i386/i386.h (machine_function): Add indirect_branch_type
95 and has_local_indirect_jump.
96 * config/i386/i386.md (indirect_jump): Set has_local_indirect_jump
97 to true.
98 (tablejump): Likewise.
99 (*indirect_jump): Use ix86_output_indirect_jmp.
100 (*tablejump_1): Likewise.
101 (simple_return_indirect_internal): Likewise.
102 * config/i386/i386.opt (mindirect-branch=): New option.
103 (indirect_branch): New.
104 (keep): Likewise.
105 (thunk): Likewise.
106 (thunk-inline): Likewise.
107 (thunk-extern): Likewise.
108 * doc/extend.texi: Document indirect_branch function attribute.
109 * doc/invoke.texi: Document -mindirect-branch= option.
110
111gcc/testsuite/
112
113 Backport from mainline
114 2018-01-14 H.J. Lu <hongjiu.lu@intel.com>
115
116 * gcc.target/i386/indirect-thunk-1.c: New test.
117 * gcc.target/i386/indirect-thunk-2.c: Likewise.
118 * gcc.target/i386/indirect-thunk-3.c: Likewise.
119 * gcc.target/i386/indirect-thunk-4.c: Likewise.
120 * gcc.target/i386/indirect-thunk-5.c: Likewise.
121 * gcc.target/i386/indirect-thunk-6.c: Likewise.
122 * gcc.target/i386/indirect-thunk-7.c: Likewise.
123 * gcc.target/i386/indirect-thunk-attr-1.c: Likewise.
124 * gcc.target/i386/indirect-thunk-attr-2.c: Likewise.
125 * gcc.target/i386/indirect-thunk-attr-3.c: Likewise.
126 * gcc.target/i386/indirect-thunk-attr-4.c: Likewise.
127 * gcc.target/i386/indirect-thunk-attr-5.c: Likewise.
128 * gcc.target/i386/indirect-thunk-attr-6.c: Likewise.
129 * gcc.target/i386/indirect-thunk-attr-7.c: Likewise.
130 * gcc.target/i386/indirect-thunk-attr-8.c: Likewise.
131 * gcc.target/i386/indirect-thunk-bnd-1.c: Likewise.
132 * gcc.target/i386/indirect-thunk-bnd-2.c: Likewise.
133 * gcc.target/i386/indirect-thunk-bnd-3.c: Likewise.
134 * gcc.target/i386/indirect-thunk-bnd-4.c: Likewise.
135 * gcc.target/i386/indirect-thunk-extern-1.c: Likewise.
136 * gcc.target/i386/indirect-thunk-extern-2.c: Likewise.
137 * gcc.target/i386/indirect-thunk-extern-3.c: Likewise.
138 * gcc.target/i386/indirect-thunk-extern-4.c: Likewise.
139 * gcc.target/i386/indirect-thunk-extern-5.c: Likewise.
140 * gcc.target/i386/indirect-thunk-extern-6.c: Likewise.
141 * gcc.target/i386/indirect-thunk-extern-7.c: Likewise.
142 * gcc.target/i386/indirect-thunk-inline-1.c: Likewise.
143 * gcc.target/i386/indirect-thunk-inline-2.c: Likewise.
144 * gcc.target/i386/indirect-thunk-inline-3.c: Likewise.
145 * gcc.target/i386/indirect-thunk-inline-4.c: Likewise.
146 * gcc.target/i386/indirect-thunk-inline-5.c: Likewise.
147 * gcc.target/i386/indirect-thunk-inline-6.c: Likewise.
148 * gcc.target/i386/indirect-thunk-inline-7.c: Likewise.
149
150Upstream-Status: Pending
151
152Signed-off-by: Juro Bystricky <juro.bystricky@intel.com>
153
154---
155 gcc/config/i386/i386-opts.h | 13 +
156 gcc/config/i386/i386-protos.h | 1 +
157 gcc/config/i386/i386.c | 639 ++++++++++++++++++++-
158 gcc/config/i386/i386.h | 7 +
159 gcc/config/i386/i386.md | 26 +-
160 gcc/config/i386/i386.opt | 20 +
161 gcc/doc/extend.texi | 10 +
162 gcc/doc/invoke.texi | 13 +-
163 gcc/testsuite/gcc.target/i386/indirect-thunk-1.c | 20 +
164 gcc/testsuite/gcc.target/i386/indirect-thunk-2.c | 20 +
165 gcc/testsuite/gcc.target/i386/indirect-thunk-3.c | 21 +
166 gcc/testsuite/gcc.target/i386/indirect-thunk-4.c | 21 +
167 gcc/testsuite/gcc.target/i386/indirect-thunk-5.c | 17 +
168 gcc/testsuite/gcc.target/i386/indirect-thunk-6.c | 18 +
169 gcc/testsuite/gcc.target/i386/indirect-thunk-7.c | 44 ++
170 .../gcc.target/i386/indirect-thunk-attr-1.c | 23 +
171 .../gcc.target/i386/indirect-thunk-attr-2.c | 21 +
172 .../gcc.target/i386/indirect-thunk-attr-3.c | 23 +
173 .../gcc.target/i386/indirect-thunk-attr-4.c | 22 +
174 .../gcc.target/i386/indirect-thunk-attr-5.c | 22 +
175 .../gcc.target/i386/indirect-thunk-attr-6.c | 21 +
176 .../gcc.target/i386/indirect-thunk-attr-7.c | 44 ++
177 .../gcc.target/i386/indirect-thunk-attr-8.c | 42 ++
178 .../gcc.target/i386/indirect-thunk-bnd-1.c | 20 +
179 .../gcc.target/i386/indirect-thunk-bnd-2.c | 21 +
180 .../gcc.target/i386/indirect-thunk-bnd-3.c | 19 +
181 .../gcc.target/i386/indirect-thunk-bnd-4.c | 20 +
182 .../gcc.target/i386/indirect-thunk-extern-1.c | 19 +
183 .../gcc.target/i386/indirect-thunk-extern-2.c | 19 +
184 .../gcc.target/i386/indirect-thunk-extern-3.c | 20 +
185 .../gcc.target/i386/indirect-thunk-extern-4.c | 20 +
186 .../gcc.target/i386/indirect-thunk-extern-5.c | 16 +
187 .../gcc.target/i386/indirect-thunk-extern-6.c | 17 +
188 .../gcc.target/i386/indirect-thunk-extern-7.c | 43 ++
189 .../gcc.target/i386/indirect-thunk-inline-1.c | 20 +
190 .../gcc.target/i386/indirect-thunk-inline-2.c | 20 +
191 .../gcc.target/i386/indirect-thunk-inline-3.c | 21 +
192 .../gcc.target/i386/indirect-thunk-inline-4.c | 21 +
193 .../gcc.target/i386/indirect-thunk-inline-5.c | 17 +
194 .../gcc.target/i386/indirect-thunk-inline-6.c | 18 +
195 .../gcc.target/i386/indirect-thunk-inline-7.c | 44 ++
196 41 files changed, 1486 insertions(+), 17 deletions(-)
197 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-1.c
198 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-2.c
199 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-3.c
200 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-4.c
201 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-5.c
202 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-6.c
203 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-7.c
204 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c
205 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c
206 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c
207 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c
208 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c
209 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c
210 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c
211 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c
212 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c
213 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c
214 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c
215 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c
216 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c
217 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c
218 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c
219 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c
220 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c
221 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c
222 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c
223 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c
224 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c
225 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c
226 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c
227 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c
228 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c
229 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c
230
231diff --git a/gcc/config/i386/i386-opts.h b/gcc/config/i386/i386-opts.h
232index b7f92e3..cc21152 100644
233--- a/gcc/config/i386/i386-opts.h
234+++ b/gcc/config/i386/i386-opts.h
235@@ -99,4 +99,17 @@ enum stack_protector_guard {
236 SSP_GLOBAL /* global canary */
237 };
238
239+/* This is used to mitigate variant #2 of the speculative execution
240+ vulnerabilities on x86 processors identified by CVE-2017-5715, aka
241+ Spectre. They convert indirect branches and function returns to
242+ call and return thunks to avoid speculative execution via indirect
243+ call, jmp and ret. */
244+enum indirect_branch {
245+ indirect_branch_unset = 0,
246+ indirect_branch_keep,
247+ indirect_branch_thunk,
248+ indirect_branch_thunk_inline,
249+ indirect_branch_thunk_extern
250+};
251+
252 #endif
253diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h
254index ff47bc1..eca4cbf 100644
255--- a/gcc/config/i386/i386-protos.h
256+++ b/gcc/config/i386/i386-protos.h
257@@ -311,6 +311,7 @@ extern enum attr_cpu ix86_schedule;
258 #endif
259
260 extern const char * ix86_output_call_insn (rtx_insn *insn, rtx call_op);
261+extern const char * ix86_output_indirect_jmp (rtx call_op, bool ret_p);
262 extern bool ix86_operands_ok_for_move_multiple (rtx *operands, bool load,
263 enum machine_mode mode);
264
265diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
266index 6c98f75..0b9fc4d 100644
267--- a/gcc/config/i386/i386.c
268+++ b/gcc/config/i386/i386.c
269@@ -3662,12 +3662,23 @@ make_pass_stv (gcc::context *ctxt)
270 return new pass_stv (ctxt);
271 }
272
273-/* Return true if a red-zone is in use. */
274+/* Return true if a red-zone is in use. We can't use red-zone when
275+ there are local indirect jumps, like "indirect_jump" or "tablejump",
276+ which jumps to another place in the function, since "call" in the
277+ indirect thunk pushes the return address onto stack, destroying
278+ red-zone.
279+
280+ TODO: If we can reserve the first 2 WORDs, for PUSH and, another
281+ for CALL, in red-zone, we can allow local indirect jumps with
282+ indirect thunk. */
283
284 bool
285 ix86_using_red_zone (void)
286 {
287- return TARGET_RED_ZONE && !TARGET_64BIT_MS_ABI;
288+ return (TARGET_RED_ZONE
289+ && !TARGET_64BIT_MS_ABI
290+ && (!cfun->machine->has_local_indirect_jump
291+ || cfun->machine->indirect_branch_type == indirect_branch_keep));
292 }
293
294 /* Return a string that documents the current -m options. The caller is
295@@ -6350,6 +6361,37 @@ ix86_reset_previous_fndecl (void)
296 ix86_previous_fndecl = NULL_TREE;
297 }
298
299+/* Set the indirect_branch_type field from the function FNDECL. */
300+
301+static void
302+ix86_set_indirect_branch_type (tree fndecl)
303+{
304+ if (cfun->machine->indirect_branch_type == indirect_branch_unset)
305+ {
306+ tree attr = lookup_attribute ("indirect_branch",
307+ DECL_ATTRIBUTES (fndecl));
308+ if (attr != NULL)
309+ {
310+ tree args = TREE_VALUE (attr);
311+ if (args == NULL)
312+ gcc_unreachable ();
313+ tree cst = TREE_VALUE (args);
314+ if (strcmp (TREE_STRING_POINTER (cst), "keep") == 0)
315+ cfun->machine->indirect_branch_type = indirect_branch_keep;
316+ else if (strcmp (TREE_STRING_POINTER (cst), "thunk") == 0)
317+ cfun->machine->indirect_branch_type = indirect_branch_thunk;
318+ else if (strcmp (TREE_STRING_POINTER (cst), "thunk-inline") == 0)
319+ cfun->machine->indirect_branch_type = indirect_branch_thunk_inline;
320+ else if (strcmp (TREE_STRING_POINTER (cst), "thunk-extern") == 0)
321+ cfun->machine->indirect_branch_type = indirect_branch_thunk_extern;
322+ else
323+ gcc_unreachable ();
324+ }
325+ else
326+ cfun->machine->indirect_branch_type = ix86_indirect_branch;
327+ }
328+}
329+
330 /* Establish appropriate back-end context for processing the function
331 FNDECL. The argument might be NULL to indicate processing at top
332 level, outside of any function scope. */
333@@ -6360,7 +6402,13 @@ ix86_set_current_function (tree fndecl)
334 several times in the course of compiling a function, and we don't want to
335 slow things down too much or call target_reinit when it isn't safe. */
336 if (fndecl == ix86_previous_fndecl)
337- return;
338+ {
339+ /* There may be 2 function bodies for the same function FNDECL,
340+ one is extern inline and one isn't. */
341+ if (fndecl != NULL_TREE)
342+ ix86_set_indirect_branch_type (fndecl);
343+ return;
344+ }
345
346 tree old_tree;
347 if (ix86_previous_fndecl == NULL_TREE)
348@@ -6377,6 +6425,8 @@ ix86_set_current_function (tree fndecl)
349 return;
350 }
351
352+ ix86_set_indirect_branch_type (fndecl);
353+
354 tree new_tree = DECL_FUNCTION_SPECIFIC_TARGET (fndecl);
355 if (new_tree == NULL_TREE)
356 new_tree = target_option_default_node;
357@@ -10962,6 +11012,220 @@ ix86_setup_frame_addresses (void)
358 # endif
359 #endif
360
361+/* Label count for call and return thunks. It is used to make unique
362+ labels in call and return thunks. */
363+static int indirectlabelno;
364+
365+/* True if call and return thunk functions are needed. */
366+static bool indirect_thunk_needed = false;
367+/* True if call and return thunk functions with the BND prefix are
368+ needed. */
369+static bool indirect_thunk_bnd_needed = false;
370+
371+/* Bit masks of integer registers, which contain branch target, used
372+ by call and return thunks functions. */
373+static int indirect_thunks_used;
374+/* Bit masks of integer registers, which contain branch target, used
375+ by call and return thunks functions with the BND prefix. */
376+static int indirect_thunks_bnd_used;
377+
378+#ifndef INDIRECT_LABEL
379+# define INDIRECT_LABEL "LIND"
380+#endif
381+
382+/* Fills in the label name that should be used for the indirect thunk. */
383+
384+static void
385+indirect_thunk_name (char name[32], int regno, bool need_bnd_p)
386+{
387+ if (USE_HIDDEN_LINKONCE)
388+ {
389+ const char *bnd = need_bnd_p ? "_bnd" : "";
390+ if (regno >= 0)
391+ {
392+ const char *reg_prefix;
393+ if (LEGACY_INT_REGNO_P (regno))
394+ reg_prefix = TARGET_64BIT ? "r" : "e";
395+ else
396+ reg_prefix = "";
397+ sprintf (name, "__x86_indirect_thunk%s_%s%s",
398+ bnd, reg_prefix, reg_names[regno]);
399+ }
400+ else
401+ sprintf (name, "__x86_indirect_thunk%s", bnd);
402+ }
403+ else
404+ {
405+ if (regno >= 0)
406+ {
407+ if (need_bnd_p)
408+ ASM_GENERATE_INTERNAL_LABEL (name, "LITBR", regno);
409+ else
410+ ASM_GENERATE_INTERNAL_LABEL (name, "LITR", regno);
411+ }
412+ else
413+ {
414+ if (need_bnd_p)
415+ ASM_GENERATE_INTERNAL_LABEL (name, "LITB", 0);
416+ else
417+ ASM_GENERATE_INTERNAL_LABEL (name, "LIT", 0);
418+ }
419+ }
420+}
421+
422+/* Output a call and return thunk for indirect branch. If BND_P is
423+ true, the BND prefix is needed. If REGNO != -1, the function
424+ address is in REGNO and the call and return thunk looks like:
425+
426+ call L2
427+ L1:
428+ pause
429+ jmp L1
430+ L2:
431+ mov %REG, (%sp)
432+ ret
433+
434+ Otherwise, the function address is on the top of stack and the
435+ call and return thunk looks like:
436+
437+ call L2
438+ L1:
439+ pause
440+ jmp L1
441+ L2:
442+ lea WORD_SIZE(%sp), %sp
443+ ret
444+ */
445+
446+static void
447+output_indirect_thunk (bool need_bnd_p, int regno)
448+{
449+ char indirectlabel1[32];
450+ char indirectlabel2[32];
451+
452+ ASM_GENERATE_INTERNAL_LABEL (indirectlabel1, INDIRECT_LABEL,
453+ indirectlabelno++);
454+ ASM_GENERATE_INTERNAL_LABEL (indirectlabel2, INDIRECT_LABEL,
455+ indirectlabelno++);
456+
457+ /* Call */
458+ if (need_bnd_p)
459+ fputs ("\tbnd call\t", asm_out_file);
460+ else
461+ fputs ("\tcall\t", asm_out_file);
462+ assemble_name_raw (asm_out_file, indirectlabel2);
463+ fputc ('\n', asm_out_file);
464+
465+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel1);
466+
467+ /* Pause + lfence. */
468+ fprintf (asm_out_file, "\tpause\n\tlfence\n");
469+
470+ /* Jump. */
471+ fputs ("\tjmp\t", asm_out_file);
472+ assemble_name_raw (asm_out_file, indirectlabel1);
473+ fputc ('\n', asm_out_file);
474+
475+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel2);
476+
477+ if (regno >= 0)
478+ {
479+ /* MOV. */
480+ rtx xops[2];
481+ xops[0] = gen_rtx_MEM (word_mode, stack_pointer_rtx);
482+ xops[1] = gen_rtx_REG (word_mode, regno);
483+ output_asm_insn ("mov\t{%1, %0|%0, %1}", xops);
484+ }
485+ else
486+ {
487+ /* LEA. */
488+ rtx xops[2];
489+ xops[0] = stack_pointer_rtx;
490+ xops[1] = plus_constant (Pmode, stack_pointer_rtx, UNITS_PER_WORD);
491+ output_asm_insn ("lea\t{%E1, %0|%0, %E1}", xops);
492+ }
493+
494+ if (need_bnd_p)
495+ fputs ("\tbnd ret\n", asm_out_file);
496+ else
497+ fputs ("\tret\n", asm_out_file);
498+}
499+
500+/* Output a funtion with a call and return thunk for indirect branch.
501+ If BND_P is true, the BND prefix is needed. If REGNO != -1, the
502+ function address is in REGNO. Otherwise, the function address is
503+ on the top of stack. */
504+
505+static void
506+output_indirect_thunk_function (bool need_bnd_p, int regno)
507+{
508+ char name[32];
509+ tree decl;
510+
511+ /* Create __x86_indirect_thunk/__x86_indirect_thunk_bnd. */
512+ indirect_thunk_name (name, regno, need_bnd_p);
513+ decl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL,
514+ get_identifier (name),
515+ build_function_type_list (void_type_node, NULL_TREE));
516+ DECL_RESULT (decl) = build_decl (BUILTINS_LOCATION, RESULT_DECL,
517+ NULL_TREE, void_type_node);
518+ TREE_PUBLIC (decl) = 1;
519+ TREE_STATIC (decl) = 1;
520+ DECL_IGNORED_P (decl) = 1;
521+
522+#if TARGET_MACHO
523+ if (TARGET_MACHO)
524+ {
525+ switch_to_section (darwin_sections[picbase_thunk_section]);
526+ fputs ("\t.weak_definition\t", asm_out_file);
527+ assemble_name (asm_out_file, name);
528+ fputs ("\n\t.private_extern\t", asm_out_file);
529+ assemble_name (asm_out_file, name);
530+ putc ('\n', asm_out_file);
531+ ASM_OUTPUT_LABEL (asm_out_file, name);
532+ DECL_WEAK (decl) = 1;
533+ }
534+ else
535+#endif
536+ if (USE_HIDDEN_LINKONCE)
537+ {
538+ cgraph_node::create (decl)->set_comdat_group (DECL_ASSEMBLER_NAME (decl));
539+
540+ targetm.asm_out.unique_section (decl, 0);
541+ switch_to_section (get_named_section (decl, NULL, 0));
542+
543+ targetm.asm_out.globalize_label (asm_out_file, name);
544+ fputs ("\t.hidden\t", asm_out_file);
545+ assemble_name (asm_out_file, name);
546+ putc ('\n', asm_out_file);
547+ ASM_DECLARE_FUNCTION_NAME (asm_out_file, name, decl);
548+ }
549+ else
550+ {
551+ switch_to_section (text_section);
552+ ASM_OUTPUT_LABEL (asm_out_file, name);
553+ }
554+
555+ DECL_INITIAL (decl) = make_node (BLOCK);
556+ current_function_decl = decl;
557+ allocate_struct_function (decl, false);
558+ init_function_start (decl);
559+ /* We're about to hide the function body from callees of final_* by
560+ emitting it directly; tell them we're a thunk, if they care. */
561+ cfun->is_thunk = true;
562+ first_function_block_is_cold = false;
563+ /* Make sure unwind info is emitted for the thunk if needed. */
564+ final_start_function (emit_barrier (), asm_out_file, 1);
565+
566+ output_indirect_thunk (need_bnd_p, regno);
567+
568+ final_end_function ();
569+ init_insn_lengths ();
570+ free_after_compilation (cfun);
571+ set_cfun (NULL);
572+ current_function_decl = NULL;
573+}
574+
575 static int pic_labels_used;
576
577 /* Fills in the label name that should be used for a pc thunk for
578@@ -10988,11 +11252,32 @@ ix86_code_end (void)
579 rtx xops[2];
580 int regno;
581
582+ if (indirect_thunk_needed)
583+ output_indirect_thunk_function (false, -1);
584+ if (indirect_thunk_bnd_needed)
585+ output_indirect_thunk_function (true, -1);
586+
587+ for (regno = FIRST_REX_INT_REG; regno <= LAST_REX_INT_REG; regno++)
588+ {
589+ int i = regno - FIRST_REX_INT_REG + LAST_INT_REG + 1;
590+ if ((indirect_thunks_used & (1 << i)))
591+ output_indirect_thunk_function (false, regno);
592+
593+ if ((indirect_thunks_bnd_used & (1 << i)))
594+ output_indirect_thunk_function (true, regno);
595+ }
596+
597 for (regno = AX_REG; regno <= SP_REG; regno++)
598 {
599 char name[32];
600 tree decl;
601
602+ if ((indirect_thunks_used & (1 << regno)))
603+ output_indirect_thunk_function (false, regno);
604+
605+ if ((indirect_thunks_bnd_used & (1 << regno)))
606+ output_indirect_thunk_function (true, regno);
607+
608 if (!(pic_labels_used & (1 << regno)))
609 continue;
610
611@@ -27369,12 +27654,292 @@ ix86_nopic_noplt_attribute_p (rtx call_op)
612 return false;
613 }
614
615+/* Output indirect branch via a call and return thunk. CALL_OP is a
616+ register which contains the branch target. XASM is the assembly
617+ template for CALL_OP. Branch is a tail call if SIBCALL_P is true.
618+ A normal call is converted to:
619+
620+ call __x86_indirect_thunk_reg
621+
622+ and a tail call is converted to:
623+
624+ jmp __x86_indirect_thunk_reg
625+ */
626+
627+static void
628+ix86_output_indirect_branch_via_reg (rtx call_op, bool sibcall_p)
629+{
630+ char thunk_name_buf[32];
631+ char *thunk_name;
632+ bool need_bnd_p = ix86_bnd_prefixed_insn_p (current_output_insn);
633+ int regno = REGNO (call_op);
634+
635+ if (cfun->machine->indirect_branch_type
636+ != indirect_branch_thunk_inline)
637+ {
638+ if (cfun->machine->indirect_branch_type == indirect_branch_thunk)
639+ {
640+ int i = regno;
641+ if (i >= FIRST_REX_INT_REG)
642+ i -= (FIRST_REX_INT_REG - LAST_INT_REG - 1);
643+ if (need_bnd_p)
644+ indirect_thunks_bnd_used |= 1 << i;
645+ else
646+ indirect_thunks_used |= 1 << i;
647+ }
648+ indirect_thunk_name (thunk_name_buf, regno, need_bnd_p);
649+ thunk_name = thunk_name_buf;
650+ }
651+ else
652+ thunk_name = NULL;
653+
654+ if (sibcall_p)
655+ {
656+ if (thunk_name != NULL)
657+ {
658+ if (need_bnd_p)
659+ fprintf (asm_out_file, "\tbnd jmp\t%s\n", thunk_name);
660+ else
661+ fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name);
662+ }
663+ else
664+ output_indirect_thunk (need_bnd_p, regno);
665+ }
666+ else
667+ {
668+ if (thunk_name != NULL)
669+ {
670+ if (need_bnd_p)
671+ fprintf (asm_out_file, "\tbnd call\t%s\n", thunk_name);
672+ else
673+ fprintf (asm_out_file, "\tcall\t%s\n", thunk_name);
674+ return;
675+ }
676+
677+ char indirectlabel1[32];
678+ char indirectlabel2[32];
679+
680+ ASM_GENERATE_INTERNAL_LABEL (indirectlabel1,
681+ INDIRECT_LABEL,
682+ indirectlabelno++);
683+ ASM_GENERATE_INTERNAL_LABEL (indirectlabel2,
684+ INDIRECT_LABEL,
685+ indirectlabelno++);
686+
687+ /* Jump. */
688+ if (need_bnd_p)
689+ fputs ("\tbnd jmp\t", asm_out_file);
690+ else
691+ fputs ("\tjmp\t", asm_out_file);
692+ assemble_name_raw (asm_out_file, indirectlabel2);
693+ fputc ('\n', asm_out_file);
694+
695+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel1);
696+
697+ if (thunk_name != NULL)
698+ {
699+ if (need_bnd_p)
700+ fprintf (asm_out_file, "\tbnd jmp\t%s\n", thunk_name);
701+ else
702+ fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name);
703+ }
704+ else
705+ output_indirect_thunk (need_bnd_p, regno);
706+
707+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel2);
708+
709+ /* Call. */
710+ if (need_bnd_p)
711+ fputs ("\tbnd call\t", asm_out_file);
712+ else
713+ fputs ("\tcall\t", asm_out_file);
714+ assemble_name_raw (asm_out_file, indirectlabel1);
715+ fputc ('\n', asm_out_file);
716+ }
717+}
718+
719+/* Output indirect branch via a call and return thunk. CALL_OP is
720+ the branch target. XASM is the assembly template for CALL_OP.
721+ Branch is a tail call if SIBCALL_P is true. A normal call is
722+ converted to:
723+
724+ jmp L2
725+ L1:
726+ push CALL_OP
727+ jmp __x86_indirect_thunk
728+ L2:
729+ call L1
730+
731+ and a tail call is converted to:
732+
733+ push CALL_OP
734+ jmp __x86_indirect_thunk
735+ */
736+
737+static void
738+ix86_output_indirect_branch_via_push (rtx call_op, const char *xasm,
739+ bool sibcall_p)
740+{
741+ char thunk_name_buf[32];
742+ char *thunk_name;
743+ char push_buf[64];
744+ bool need_bnd_p = ix86_bnd_prefixed_insn_p (current_output_insn);
745+ int regno = -1;
746+
747+ if (cfun->machine->indirect_branch_type
748+ != indirect_branch_thunk_inline)
749+ {
750+ if (cfun->machine->indirect_branch_type == indirect_branch_thunk)
751+ {
752+ if (need_bnd_p)
753+ indirect_thunk_bnd_needed = true;
754+ else
755+ indirect_thunk_needed = true;
756+ }
757+ indirect_thunk_name (thunk_name_buf, regno, need_bnd_p);
758+ thunk_name = thunk_name_buf;
759+ }
760+ else
761+ thunk_name = NULL;
762+
763+ snprintf (push_buf, sizeof (push_buf), "push{%c}\t%s",
764+ TARGET_64BIT ? 'q' : 'l', xasm);
765+
766+ if (sibcall_p)
767+ {
768+ output_asm_insn (push_buf, &call_op);
769+ if (thunk_name != NULL)
770+ {
771+ if (need_bnd_p)
772+ fprintf (asm_out_file, "\tbnd jmp\t%s\n", thunk_name);
773+ else
774+ fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name);
775+ }
776+ else
777+ output_indirect_thunk (need_bnd_p, regno);
778+ }
779+ else
780+ {
781+ char indirectlabel1[32];
782+ char indirectlabel2[32];
783+
784+ ASM_GENERATE_INTERNAL_LABEL (indirectlabel1,
785+ INDIRECT_LABEL,
786+ indirectlabelno++);
787+ ASM_GENERATE_INTERNAL_LABEL (indirectlabel2,
788+ INDIRECT_LABEL,
789+ indirectlabelno++);
790+
791+ /* Jump. */
792+ if (need_bnd_p)
793+ fputs ("\tbnd jmp\t", asm_out_file);
794+ else
795+ fputs ("\tjmp\t", asm_out_file);
796+ assemble_name_raw (asm_out_file, indirectlabel2);
797+ fputc ('\n', asm_out_file);
798+
799+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel1);
800+
801+ /* An external function may be called via GOT, instead of PLT. */
802+ if (MEM_P (call_op))
803+ {
804+ struct ix86_address parts;
805+ rtx addr = XEXP (call_op, 0);
806+ if (ix86_decompose_address (addr, &parts)
807+ && parts.base == stack_pointer_rtx)
808+ {
809+ /* Since call will adjust stack by -UNITS_PER_WORD,
810+ we must convert "disp(stack, index, scale)" to
811+ "disp+UNITS_PER_WORD(stack, index, scale)". */
812+ if (parts.index)
813+ {
814+ addr = gen_rtx_MULT (Pmode, parts.index,
815+ GEN_INT (parts.scale));
816+ addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
817+ addr);
818+ }
819+ else
820+ addr = stack_pointer_rtx;
821+
822+ rtx disp;
823+ if (parts.disp != NULL_RTX)
824+ disp = plus_constant (Pmode, parts.disp,
825+ UNITS_PER_WORD);
826+ else
827+ disp = GEN_INT (UNITS_PER_WORD);
828+
829+ addr = gen_rtx_PLUS (Pmode, addr, disp);
830+ call_op = gen_rtx_MEM (GET_MODE (call_op), addr);
831+ }
832+ }
833+
834+ output_asm_insn (push_buf, &call_op);
835+
836+ if (thunk_name != NULL)
837+ {
838+ if (need_bnd_p)
839+ fprintf (asm_out_file, "\tbnd jmp\t%s\n", thunk_name);
840+ else
841+ fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name);
842+ }
843+ else
844+ output_indirect_thunk (need_bnd_p, regno);
845+
846+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel2);
847+
848+ /* Call. */
849+ if (need_bnd_p)
850+ fputs ("\tbnd call\t", asm_out_file);
851+ else
852+ fputs ("\tcall\t", asm_out_file);
853+ assemble_name_raw (asm_out_file, indirectlabel1);
854+ fputc ('\n', asm_out_file);
855+ }
856+}
857+
858+/* Output indirect branch via a call and return thunk. CALL_OP is
859+ the branch target. XASM is the assembly template for CALL_OP.
860+ Branch is a tail call if SIBCALL_P is true. */
861+
862+static void
863+ix86_output_indirect_branch (rtx call_op, const char *xasm,
864+ bool sibcall_p)
865+{
866+ if (REG_P (call_op))
867+ ix86_output_indirect_branch_via_reg (call_op, sibcall_p);
868+ else
869+ ix86_output_indirect_branch_via_push (call_op, xasm, sibcall_p);
870+}
871+/* Output indirect jump. CALL_OP is the jump target. Jump is a
872+ function return if RET_P is true. */
873+
874+const char *
875+ix86_output_indirect_jmp (rtx call_op, bool ret_p)
876+{
877+ if (cfun->machine->indirect_branch_type != indirect_branch_keep)
878+ {
879+ /* We can't have red-zone if this isn't a function return since
880+ "call" in the indirect thunk pushes the return address onto
881+ stack, destroying red-zone. */
882+ if (!ret_p && ix86_red_zone_size != 0)
883+ gcc_unreachable ();
884+
885+ ix86_output_indirect_branch (call_op, "%0", true);
886+ return "";
887+ }
888+ else
889+ return "%!jmp\t%A0";
890+}
891+
892 /* Output the assembly for a call instruction. */
893
894 const char *
895 ix86_output_call_insn (rtx_insn *insn, rtx call_op)
896 {
897 bool direct_p = constant_call_address_operand (call_op, VOIDmode);
898+ bool output_indirect_p
899+ = (!TARGET_SEH
900+ && cfun->machine->indirect_branch_type != indirect_branch_keep);
901 bool seh_nop_p = false;
902 const char *xasm;
903
904@@ -27383,7 +27948,13 @@ ix86_output_call_insn (rtx_insn *insn, rtx call_op)
905 if (direct_p)
906 {
907 if (ix86_nopic_noplt_attribute_p (call_op))
908- xasm = "%!jmp\t{*%p0@GOTPCREL(%%rip)|[QWORD PTR %p0@GOTPCREL[rip]]}";
909+ {
910+ direct_p = false;
911+ if (output_indirect_p)
912+ xasm = "{%p0@GOTPCREL(%%rip)|[QWORD PTR %p0@GOTPCREL[rip]]}";
913+ else
914+ xasm = "%!jmp\t{*%p0@GOTPCREL(%%rip)|[QWORD PTR %p0@GOTPCREL[rip]]}";
915+ }
916 else
917 xasm = "%!jmp\t%P0";
918 }
919@@ -27392,9 +27963,17 @@ ix86_output_call_insn (rtx_insn *insn, rtx call_op)
920 else if (TARGET_SEH)
921 xasm = "%!rex.W jmp\t%A0";
922 else
923- xasm = "%!jmp\t%A0";
924+ {
925+ if (output_indirect_p)
926+ xasm = "%0";
927+ else
928+ xasm = "%!jmp\t%A0";
929+ }
930
931- output_asm_insn (xasm, &call_op);
932+ if (output_indirect_p && !direct_p)
933+ ix86_output_indirect_branch (call_op, xasm, true);
934+ else
935+ output_asm_insn (xasm, &call_op);
936 return "";
937 }
938
939@@ -27431,14 +28010,28 @@ ix86_output_call_insn (rtx_insn *insn, rtx call_op)
940 if (direct_p)
941 {
942 if (ix86_nopic_noplt_attribute_p (call_op))
943- xasm = "%!call\t{*%p0@GOTPCREL(%%rip)|[QWORD PTR %p0@GOTPCREL[rip]]}";
944+ {
945+ direct_p = false;
946+ if (output_indirect_p)
947+ xasm = "{%p0@GOTPCREL(%%rip)|[QWORD PTR %p0@GOTPCREL[rip]]}";
948+ else
949+ xasm = "%!call\t{*%p0@GOTPCREL(%%rip)|[QWORD PTR %p0@GOTPCREL[rip]]}";
950+ }
951 else
952 xasm = "%!call\t%P0";
953 }
954 else
955- xasm = "%!call\t%A0";
956+ {
957+ if (output_indirect_p)
958+ xasm = "%0";
959+ else
960+ xasm = "%!call\t%A0";
961+ }
962
963- output_asm_insn (xasm, &call_op);
964+ if (output_indirect_p && !direct_p)
965+ ix86_output_indirect_branch (call_op, xasm, false);
966+ else
967+ output_asm_insn (xasm, &call_op);
968
969 if (seh_nop_p)
970 return "nop";
971@@ -44836,7 +45429,7 @@ ix86_handle_struct_attribute (tree *node, tree name, tree, int,
972 }
973
974 static tree
975-ix86_handle_fndecl_attribute (tree *node, tree name, tree, int,
976+ix86_handle_fndecl_attribute (tree *node, tree name, tree args, int,
977 bool *no_add_attrs)
978 {
979 if (TREE_CODE (*node) != FUNCTION_DECL)
980@@ -44845,6 +45438,29 @@ ix86_handle_fndecl_attribute (tree *node, tree name, tree, int,
981 name);
982 *no_add_attrs = true;
983 }
984+
985+ if (is_attribute_p ("indirect_branch", name))
986+ {
987+ tree cst = TREE_VALUE (args);
988+ if (TREE_CODE (cst) != STRING_CST)
989+ {
990+ warning (OPT_Wattributes,
991+ "%qE attribute requires a string constant argument",
992+ name);
993+ *no_add_attrs = true;
994+ }
995+ else if (strcmp (TREE_STRING_POINTER (cst), "keep") != 0
996+ && strcmp (TREE_STRING_POINTER (cst), "thunk") != 0
997+ && strcmp (TREE_STRING_POINTER (cst), "thunk-inline") != 0
998+ && strcmp (TREE_STRING_POINTER (cst), "thunk-extern") != 0)
999+ {
1000+ warning (OPT_Wattributes,
1001+ "argument to %qE attribute is not "
1002+ "(keep|thunk|thunk-inline|thunk-extern)", name);
1003+ *no_add_attrs = true;
1004+ }
1005+ }
1006+
1007 return NULL_TREE;
1008 }
1009
1010@@ -49072,6 +49688,9 @@ static const struct attribute_spec ix86_attribute_table[] =
1011 false },
1012 { "callee_pop_aggregate_return", 1, 1, false, true, true,
1013 ix86_handle_callee_pop_aggregate_return, true },
1014+ { "indirect_branch", 1, 1, true, false, false,
1015+ ix86_handle_fndecl_attribute, false },
1016+
1017 /* End element. */
1018 { NULL, 0, 0, false, false, false, NULL, false }
1019 };
1020diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
1021index 5414416..9dccdb0 100644
1022--- a/gcc/config/i386/i386.h
1023+++ b/gcc/config/i386/i386.h
1024@@ -2572,6 +2572,13 @@ struct GTY(()) machine_function {
1025 /* If true, it is safe to not save/restore DRAP register. */
1026 BOOL_BITFIELD no_drap_save_restore : 1;
1027
1028+ /* How to generate indirec branch. */
1029+ ENUM_BITFIELD(indirect_branch) indirect_branch_type : 3;
1030+
1031+ /* If true, the current function has local indirect jumps, like
1032+ "indirect_jump" or "tablejump". */
1033+ BOOL_BITFIELD has_local_indirect_jump : 1;
1034+
1035 /* If true, there is register available for argument passing. This
1036 is used only in ix86_function_ok_for_sibcall by 32-bit to determine
1037 if there is scratch register available for indirect sibcall. In
1038diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
1039index d2bfe31..153e162 100644
1040--- a/gcc/config/i386/i386.md
1041+++ b/gcc/config/i386/i386.md
1042@@ -11807,13 +11807,18 @@
1043 {
1044 if (TARGET_X32)
1045 operands[0] = convert_memory_address (word_mode, operands[0]);
1046+ cfun->machine->has_local_indirect_jump = true;
1047 })
1048
1049 (define_insn "*indirect_jump"
1050 [(set (pc) (match_operand:W 0 "indirect_branch_operand" "rBw"))]
1051 ""
1052- "%!jmp\t%A0"
1053- [(set_attr "type" "ibr")
1054+ "* return ix86_output_indirect_jmp (operands[0], false);"
1055+ [(set (attr "type")
1056+ (if_then_else (match_test "(cfun->machine->indirect_branch_type
1057+ != indirect_branch_keep)")
1058+ (const_string "multi")
1059+ (const_string "ibr")))
1060 (set_attr "length_immediate" "0")
1061 (set_attr "maybe_prefix_bnd" "1")])
1062
1063@@ -11856,14 +11861,19 @@
1064
1065 if (TARGET_X32)
1066 operands[0] = convert_memory_address (word_mode, operands[0]);
1067+ cfun->machine->has_local_indirect_jump = true;
1068 })
1069
1070 (define_insn "*tablejump_1"
1071 [(set (pc) (match_operand:W 0 "indirect_branch_operand" "rBw"))
1072 (use (label_ref (match_operand 1)))]
1073 ""
1074- "%!jmp\t%A0"
1075- [(set_attr "type" "ibr")
1076+ "* return ix86_output_indirect_jmp (operands[0], false);"
1077+ [(set (attr "type")
1078+ (if_then_else (match_test "(cfun->machine->indirect_branch_type
1079+ != indirect_branch_keep)")
1080+ (const_string "multi")
1081+ (const_string "ibr")))
1082 (set_attr "length_immediate" "0")
1083 (set_attr "maybe_prefix_bnd" "1")])
1084
1085@@ -12520,8 +12530,12 @@
1086 [(simple_return)
1087 (use (match_operand:SI 0 "register_operand" "r"))]
1088 "reload_completed"
1089- "%!jmp\t%A0"
1090- [(set_attr "type" "ibr")
1091+ "* return ix86_output_indirect_jmp (operands[0], true);"
1092+ [(set (attr "type")
1093+ (if_then_else (match_test "(cfun->machine->indirect_branch_type
1094+ != indirect_branch_keep)")
1095+ (const_string "multi")
1096+ (const_string "ibr")))
1097 (set_attr "length_immediate" "0")
1098 (set_attr "maybe_prefix_bnd" "1")])
1099
1100diff --git a/gcc/config/i386/i386.opt b/gcc/config/i386/i386.opt
1101index f304b62..5ffa334 100644
1102--- a/gcc/config/i386/i386.opt
1103+++ b/gcc/config/i386/i386.opt
1104@@ -897,3 +897,23 @@ Enum(stack_protector_guard) String(global) Value(SSP_GLOBAL)
1105 mmitigate-rop
1106 Target Var(flag_mitigate_rop) Init(0)
1107 Attempt to avoid generating instruction sequences containing ret bytes.
1108+
1109+mindirect-branch=
1110+Target Report RejectNegative Joined Enum(indirect_branch) Var(ix86_indirect_branch) Init(indirect_branch_keep)
1111+Convert indirect call and jump to call and return thunks.
1112+
1113+Enum
1114+Name(indirect_branch) Type(enum indirect_branch)
1115+Known indirect branch choices (for use with the -mindirect-branch= option):
1116+
1117+EnumValue
1118+Enum(indirect_branch) String(keep) Value(indirect_branch_keep)
1119+
1120+EnumValue
1121+Enum(indirect_branch) String(thunk) Value(indirect_branch_thunk)
1122+
1123+EnumValue
1124+Enum(indirect_branch) String(thunk-inline) Value(indirect_branch_thunk_inline)
1125+
1126+EnumValue
1127+Enum(indirect_branch) String(thunk-extern) Value(indirect_branch_thunk_extern)
1128diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
1129index 8cc4f7e..8668dae 100644
1130--- a/gcc/doc/extend.texi
1131+++ b/gcc/doc/extend.texi
1132@@ -5419,6 +5419,16 @@ Specify which floating-point unit to use. You must specify the
1133 @code{target("fpmath=sse,387")} option as
1134 @code{target("fpmath=sse+387")} because the comma would separate
1135 different options.
1136+
1137+@item indirect_branch("@var{choice}")
1138+@cindex @code{indirect_branch} function attribute, x86
1139+On x86 targets, the @code{indirect_branch} attribute causes the compiler
1140+to convert indirect call and jump with @var{choice}. @samp{keep}
1141+keeps indirect call and jump unmodified. @samp{thunk} converts indirect
1142+call and jump to call and return thunk. @samp{thunk-inline} converts
1143+indirect call and jump to inlined call and return thunk.
1144+@samp{thunk-extern} converts indirect call and jump to external call
1145+and return thunk provided in a separate object file.
1146 @end table
1147
1148 On the x86, the inliner does not inline a
1149diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
1150index b066f7b..ff9a194 100644
1151--- a/gcc/doc/invoke.texi
1152+++ b/gcc/doc/invoke.texi
1153@@ -1169,7 +1169,7 @@ See RS/6000 and PowerPC Options.
1154 -msse2avx -mfentry -mrecord-mcount -mnop-mcount -m8bit-idiv @gol
1155 -mavx256-split-unaligned-load -mavx256-split-unaligned-store @gol
1156 -malign-data=@var{type} -mstack-protector-guard=@var{guard} @gol
1157--mmitigate-rop}
1158+-mmitigate-rop -mindirect-branch=@var{choice}}
1159
1160 @emph{x86 Windows Options}
1161 @gccoptlist{-mconsole -mcygwin -mno-cygwin -mdll @gol
1162@@ -24218,6 +24218,17 @@ opcodes, to mitigate against certain forms of attack. At the moment,
1163 this option is limited in what it can do and should not be relied
1164 on to provide serious protection.
1165
1166+@item -mindirect-branch=@var{choice}
1167+@opindex -mindirect-branch
1168+Convert indirect call and jump with @var{choice}. The default is
1169+@samp{keep}, which keeps indirect call and jump unmodified.
1170+@samp{thunk} converts indirect call and jump to call and return thunk.
1171+@samp{thunk-inline} converts indirect call and jump to inlined call
1172+and return thunk. @samp{thunk-extern} converts indirect call and jump
1173+to external call and return thunk provided in a separate object file.
1174+You can control this behavior for a specific function by using the
1175+function attribute @code{indirect_branch}. @xref{Function Attributes}.
1176+
1177 @end table
1178
1179 These @samp{-m} switches are supported in addition to the above
1180diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c
1181new file mode 100644
1182index 0000000..d983e1c
1183--- /dev/null
1184+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c
1185@@ -0,0 +1,20 @@
1186+/* { dg-do compile } */
1187+/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
1188+
1189+typedef void (*dispatch_t)(long offset);
1190+
1191+dispatch_t dispatch;
1192+
1193+void
1194+male_indirect_jump (long offset)
1195+{
1196+ dispatch(offset);
1197+}
1198+
1199+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1200+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1201+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1202+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1203+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1204+/* { dg-final { scan-assembler {\tpause} } } */
1205+/* { dg-final { scan-assembler {\tlfence} } } */
1206diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c
1207new file mode 100644
1208index 0000000..58f09b4
1209--- /dev/null
1210+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c
1211@@ -0,0 +1,20 @@
1212+/* { dg-do compile } */
1213+/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
1214+
1215+typedef void (*dispatch_t)(long offset);
1216+
1217+dispatch_t dispatch[256];
1218+
1219+void
1220+male_indirect_jump (long offset)
1221+{
1222+ dispatch[offset](offset);
1223+}
1224+
1225+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1226+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1227+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1228+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1229+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1230+/* { dg-final { scan-assembler {\tpause} } } */
1231+/* { dg-final { scan-assembler {\tlfence} } } */
1232diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c
1233new file mode 100644
1234index 0000000..f20d35c
1235--- /dev/null
1236+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c
1237@@ -0,0 +1,21 @@
1238+/* { dg-do compile } */
1239+/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
1240+
1241+typedef void (*dispatch_t)(long offset);
1242+
1243+dispatch_t dispatch;
1244+
1245+int
1246+male_indirect_jump (long offset)
1247+{
1248+ dispatch(offset);
1249+ return 0;
1250+}
1251+
1252+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1253+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1254+/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1255+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1256+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1257+/* { dg-final { scan-assembler {\tpause} } } */
1258+/* { dg-final { scan-assembler {\tlfence} } } */
1259diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c
1260new file mode 100644
1261index 0000000..0eff8fb
1262--- /dev/null
1263+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c
1264@@ -0,0 +1,21 @@
1265+/* { dg-do compile } */
1266+/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
1267+
1268+typedef void (*dispatch_t)(long offset);
1269+
1270+dispatch_t dispatch[256];
1271+
1272+int
1273+male_indirect_jump (long offset)
1274+{
1275+ dispatch[offset](offset);
1276+ return 0;
1277+}
1278+
1279+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1280+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1281+/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1282+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1283+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1284+/* { dg-final { scan-assembler {\tpause} } } */
1285+/* { dg-final { scan-assembler {\tlfence} } } */
1286diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c
1287new file mode 100644
1288index 0000000..a25b20d
1289--- /dev/null
1290+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c
1291@@ -0,0 +1,17 @@
1292+/* { dg-do compile { target *-*-linux* } } */
1293+/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk" } */
1294+
1295+extern void bar (void);
1296+
1297+void
1298+foo (void)
1299+{
1300+ bar ();
1301+}
1302+
1303+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */
1304+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" } } */
1305+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1306+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1307+/* { dg-final { scan-assembler {\tpause} } } */
1308+/* { dg-final { scan-assembler {\tlfence} } } */
1309diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c
1310new file mode 100644
1311index 0000000..cff114a
1312--- /dev/null
1313+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c
1314@@ -0,0 +1,18 @@
1315+/* { dg-do compile { target *-*-linux* } } */
1316+/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk" } */
1317+
1318+extern void bar (void);
1319+
1320+int
1321+foo (void)
1322+{
1323+ bar ();
1324+ return 0;
1325+}
1326+
1327+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */
1328+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" } } */
1329+/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */
1330+/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */
1331+/* { dg-final { scan-assembler {\tpause} } } */
1332+/* { dg-final { scan-assembler {\tlfence} } } */
1333diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c
1334new file mode 100644
1335index 0000000..afdb600
1336--- /dev/null
1337+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c
1338@@ -0,0 +1,44 @@
1339+/* { dg-do compile } */
1340+/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
1341+
1342+void func0 (void);
1343+void func1 (void);
1344+void func2 (void);
1345+void func3 (void);
1346+void func4 (void);
1347+void func4 (void);
1348+void func5 (void);
1349+
1350+void
1351+bar (int i)
1352+{
1353+ switch (i)
1354+ {
1355+ default:
1356+ func0 ();
1357+ break;
1358+ case 1:
1359+ func1 ();
1360+ break;
1361+ case 2:
1362+ func2 ();
1363+ break;
1364+ case 3:
1365+ func3 ();
1366+ break;
1367+ case 4:
1368+ func4 ();
1369+ break;
1370+ case 5:
1371+ func5 ();
1372+ break;
1373+ }
1374+}
1375+
1376+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { ! x32 } } } } */
1377+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1378+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1379+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1380+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1381+/* { dg-final { scan-assembler {\tpause} } } */
1382+/* { dg-final { scan-assembler {\tlfence} } } */
1383diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c
1384new file mode 100644
1385index 0000000..d64d978
1386--- /dev/null
1387+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c
1388@@ -0,0 +1,23 @@
1389+/* { dg-do compile } */
1390+/* { dg-options "-O2 -fno-pic" } */
1391+
1392+typedef void (*dispatch_t)(long offset);
1393+
1394+dispatch_t dispatch;
1395+
1396+extern void male_indirect_jump (long)
1397+ __attribute__ ((indirect_branch("thunk")));
1398+
1399+void
1400+male_indirect_jump (long offset)
1401+{
1402+ dispatch(offset);
1403+}
1404+
1405+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1406+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1407+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1408+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1409+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1410+/* { dg-final { scan-assembler {\tpause} } } */
1411+/* { dg-final { scan-assembler {\tlfence} } } */
1412diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c
1413new file mode 100644
1414index 0000000..9306745
1415--- /dev/null
1416+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c
1417@@ -0,0 +1,21 @@
1418+/* { dg-do compile } */
1419+/* { dg-options "-O2 -fno-pic" } */
1420+
1421+typedef void (*dispatch_t)(long offset);
1422+
1423+dispatch_t dispatch[256];
1424+
1425+__attribute__ ((indirect_branch("thunk")))
1426+void
1427+male_indirect_jump (long offset)
1428+{
1429+ dispatch[offset](offset);
1430+}
1431+
1432+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1433+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1434+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1435+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1436+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1437+/* { dg-final { scan-assembler {\tpause} } } */
1438+/* { dg-final { scan-assembler {\tlfence} } } */
1439diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c
1440new file mode 100644
1441index 0000000..97744d6
1442--- /dev/null
1443+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c
1444@@ -0,0 +1,23 @@
1445+/* { dg-do compile } */
1446+/* { dg-options "-O2 -fno-pic" } */
1447+
1448+typedef void (*dispatch_t)(long offset);
1449+
1450+dispatch_t dispatch;
1451+extern int male_indirect_jump (long)
1452+ __attribute__ ((indirect_branch("thunk-inline")));
1453+
1454+int
1455+male_indirect_jump (long offset)
1456+{
1457+ dispatch(offset);
1458+ return 0;
1459+}
1460+
1461+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1462+/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */
1463+/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */
1464+/* { dg-final { scan-assembler {\tpause} } } */
1465+/* { dg-final { scan-assembler {\tlfence} } } */
1466+/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
1467+/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
1468diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c
1469new file mode 100644
1470index 0000000..bfce3ea
1471--- /dev/null
1472+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c
1473@@ -0,0 +1,22 @@
1474+/* { dg-do compile } */
1475+/* { dg-options "-O2 -fno-pic" } */
1476+
1477+typedef void (*dispatch_t)(long offset);
1478+
1479+dispatch_t dispatch[256];
1480+
1481+__attribute__ ((indirect_branch("thunk-inline")))
1482+int
1483+male_indirect_jump (long offset)
1484+{
1485+ dispatch[offset](offset);
1486+ return 0;
1487+}
1488+
1489+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1490+/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */
1491+/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */
1492+/* { dg-final { scan-assembler {\tpause} } } */
1493+/* { dg-final { scan-assembler {\tlfence} } } */
1494+/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
1495+/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
1496diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c
1497new file mode 100644
1498index 0000000..0833606
1499--- /dev/null
1500+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c
1501@@ -0,0 +1,22 @@
1502+/* { dg-do compile } */
1503+/* { dg-options "-O2 -fno-pic" } */
1504+
1505+typedef void (*dispatch_t)(long offset);
1506+
1507+dispatch_t dispatch;
1508+extern int male_indirect_jump (long)
1509+ __attribute__ ((indirect_branch("thunk-extern")));
1510+
1511+int
1512+male_indirect_jump (long offset)
1513+{
1514+ dispatch(offset);
1515+ return 0;
1516+}
1517+
1518+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1519+/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
1520+/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
1521+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1522+/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1523+/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
1524diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c
1525new file mode 100644
1526index 0000000..2eba0fb
1527--- /dev/null
1528+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c
1529@@ -0,0 +1,21 @@
1530+/* { dg-do compile } */
1531+/* { dg-options "-O2 -fno-pic" } */
1532+
1533+typedef void (*dispatch_t)(long offset);
1534+
1535+dispatch_t dispatch[256];
1536+
1537+__attribute__ ((indirect_branch("thunk-extern")))
1538+int
1539+male_indirect_jump (long offset)
1540+{
1541+ dispatch[offset](offset);
1542+ return 0;
1543+}
1544+
1545+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1546+/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
1547+/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
1548+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1549+/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1550+/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
1551diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c
1552new file mode 100644
1553index 0000000..f58427e
1554--- /dev/null
1555+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c
1556@@ -0,0 +1,44 @@
1557+/* { dg-do compile } */
1558+/* { dg-options "-O2 -fno-pic" } */
1559+
1560+void func0 (void);
1561+void func1 (void);
1562+void func2 (void);
1563+void func3 (void);
1564+void func4 (void);
1565+void func4 (void);
1566+void func5 (void);
1567+
1568+__attribute__ ((indirect_branch("thunk-extern")))
1569+void
1570+bar (int i)
1571+{
1572+ switch (i)
1573+ {
1574+ default:
1575+ func0 ();
1576+ break;
1577+ case 1:
1578+ func1 ();
1579+ break;
1580+ case 2:
1581+ func2 ();
1582+ break;
1583+ case 3:
1584+ func3 ();
1585+ break;
1586+ case 4:
1587+ func4 ();
1588+ break;
1589+ case 5:
1590+ func5 ();
1591+ break;
1592+ }
1593+}
1594+
1595+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { ! x32 } } } } */
1596+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1597+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" } } */
1598+/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
1599+/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
1600+/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
1601diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c
1602new file mode 100644
1603index 0000000..564ed39
1604--- /dev/null
1605+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c
1606@@ -0,0 +1,42 @@
1607+/* { dg-do compile } */
1608+/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
1609+
1610+void func0 (void);
1611+void func1 (void);
1612+void func2 (void);
1613+void func3 (void);
1614+void func4 (void);
1615+void func4 (void);
1616+void func5 (void);
1617+
1618+__attribute__ ((indirect_branch("keep")))
1619+void
1620+bar (int i)
1621+{
1622+ switch (i)
1623+ {
1624+ default:
1625+ func0 ();
1626+ break;
1627+ case 1:
1628+ func1 ();
1629+ break;
1630+ case 2:
1631+ func2 ();
1632+ break;
1633+ case 3:
1634+ func3 ();
1635+ break;
1636+ case 4:
1637+ func4 ();
1638+ break;
1639+ case 5:
1640+ func5 ();
1641+ break;
1642+ }
1643+}
1644+
1645+/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
1646+/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
1647+/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
1648+/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
1649diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c
1650new file mode 100644
1651index 0000000..50fbee2
1652--- /dev/null
1653+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c
1654@@ -0,0 +1,20 @@
1655+/* { dg-do compile { target { ! x32 } } } */
1656+/* { dg-options "-O2 -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
1657+
1658+void (*dispatch) (char *);
1659+char buf[10];
1660+
1661+void
1662+foo (void)
1663+{
1664+ dispatch (buf);
1665+}
1666+
1667+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1668+/* { dg-final { scan-assembler "pushq\[ \t\]%rax" { target x32 } } } */
1669+/* { dg-final { scan-assembler "bnd jmp\[ \t\]*__x86_indirect_thunk_bnd" } } */
1670+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1671+/* { dg-final { scan-assembler "bnd call\[ \t\]*\.LIND" } } */
1672+/* { dg-final { scan-assembler "bnd ret" } } */
1673+/* { dg-final { scan-assembler {\tpause} } } */
1674+/* { dg-final { scan-assembler {\tlfence} } } */
1675diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c
1676new file mode 100644
1677index 0000000..2976e67
1678--- /dev/null
1679+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c
1680@@ -0,0 +1,21 @@
1681+/* { dg-do compile { target { ! x32 } } } */
1682+/* { dg-options "-O2 -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
1683+
1684+void (*dispatch) (char *);
1685+char buf[10];
1686+
1687+int
1688+foo (void)
1689+{
1690+ dispatch (buf);
1691+ return 0;
1692+}
1693+
1694+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1695+/* { dg-final { scan-assembler "pushq\[ \t\]%rax" { target x32 } } } */
1696+/* { dg-final { scan-assembler "bnd jmp\[ \t\]*__x86_indirect_thunk_bnd" } } */
1697+/* { dg-final { scan-assembler "bnd jmp\[ \t\]*\.LIND" } } */
1698+/* { dg-final { scan-assembler "bnd call\[ \t\]*\.LIND" } } */
1699+/* { dg-final { scan-assembler "bnd ret" } } */
1700+/* { dg-final { scan-assembler {\tpause} } } */
1701+/* { dg-final { scan-assembler {\tlfence} } } */
1702diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c
1703new file mode 100644
1704index 0000000..da4bc98
1705--- /dev/null
1706+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c
1707@@ -0,0 +1,19 @@
1708+/* { dg-do compile { target { *-*-linux* && { ! x32 } } } } */
1709+/* { dg-options "-O2 -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fpic -fno-plt" } */
1710+
1711+void bar (char *);
1712+char buf[10];
1713+
1714+void
1715+foo (void)
1716+{
1717+ bar (buf);
1718+}
1719+
1720+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */
1721+/* { dg-final { scan-assembler "bnd jmp\[ \t\]*__x86_indirect_thunk_bnd" } } */
1722+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1723+/* { dg-final { scan-assembler "bnd call\[ \t\]*\.LIND" } } */
1724+/* { dg-final { scan-assembler "bnd ret" } } */
1725+/* { dg-final { scan-assembler {\tpause} } } */
1726+/* { dg-final { scan-assembler {\tlfence} } } */
1727diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c
1728new file mode 100644
1729index 0000000..c64d12e
1730--- /dev/null
1731+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c
1732@@ -0,0 +1,20 @@
1733+/* { dg-do compile { target { *-*-linux* && { ! x32 } } } } */
1734+/* { dg-options "-O2 -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fpic -fno-plt" } */
1735+
1736+void bar (char *);
1737+char buf[10];
1738+
1739+int
1740+foo (void)
1741+{
1742+ bar (buf);
1743+ return 0;
1744+}
1745+
1746+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */
1747+/* { dg-final { scan-assembler "bnd jmp\[ \t\]*__x86_indirect_thunk" } } */
1748+/* { dg-final { scan-assembler "bnd jmp\[ \t\]*\.LIND" } } */
1749+/* { dg-final { scan-assembler-times "bnd call\[ \t\]*\.LIND" 2 } } */
1750+/* { dg-final { scan-assembler "bnd ret" } } */
1751+/* { dg-final { scan-assembler {\tpause} } } */
1752+/* { dg-final { scan-assembler {\tlfence} } } */
1753diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c
1754new file mode 100644
1755index 0000000..49f27b4
1756--- /dev/null
1757+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c
1758@@ -0,0 +1,19 @@
1759+/* { dg-do compile } */
1760+/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */
1761+
1762+typedef void (*dispatch_t)(long offset);
1763+
1764+dispatch_t dispatch;
1765+
1766+void
1767+male_indirect_jump (long offset)
1768+{
1769+ dispatch(offset);
1770+}
1771+
1772+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1773+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1774+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1775+/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
1776+/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
1777+/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
1778diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c
1779new file mode 100644
1780index 0000000..a1e3eb6
1781--- /dev/null
1782+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c
1783@@ -0,0 +1,19 @@
1784+/* { dg-do compile } */
1785+/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */
1786+
1787+typedef void (*dispatch_t)(long offset);
1788+
1789+dispatch_t dispatch[256];
1790+
1791+void
1792+male_indirect_jump (long offset)
1793+{
1794+ dispatch[offset](offset);
1795+}
1796+
1797+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1798+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1799+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1800+/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
1801+/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
1802+/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
1803diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c
1804new file mode 100644
1805index 0000000..395634e
1806--- /dev/null
1807+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c
1808@@ -0,0 +1,20 @@
1809+/* { dg-do compile } */
1810+/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */
1811+
1812+typedef void (*dispatch_t)(long offset);
1813+
1814+dispatch_t dispatch;
1815+
1816+int
1817+male_indirect_jump (long offset)
1818+{
1819+ dispatch(offset);
1820+ return 0;
1821+}
1822+
1823+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1824+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1825+/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
1826+/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
1827+/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1828+/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
1829diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c
1830new file mode 100644
1831index 0000000..fd3f633
1832--- /dev/null
1833+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c
1834@@ -0,0 +1,20 @@
1835+/* { dg-do compile } */
1836+/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */
1837+
1838+typedef void (*dispatch_t)(long offset);
1839+
1840+dispatch_t dispatch[256];
1841+
1842+int
1843+male_indirect_jump (long offset)
1844+{
1845+ dispatch[offset](offset);
1846+ return 0;
1847+}
1848+
1849+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1850+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1851+/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
1852+/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
1853+/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1854+/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
1855diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c
1856new file mode 100644
1857index 0000000..ba2f92b
1858--- /dev/null
1859+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c
1860@@ -0,0 +1,16 @@
1861+/* { dg-do compile { target *-*-linux* } } */
1862+/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk-extern" } */
1863+
1864+extern void bar (void);
1865+
1866+void
1867+foo (void)
1868+{
1869+ bar ();
1870+}
1871+
1872+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */
1873+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" } } */
1874+/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
1875+/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
1876+/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
1877diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c
1878new file mode 100644
1879index 0000000..0c5a2d4
1880--- /dev/null
1881+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c
1882@@ -0,0 +1,17 @@
1883+/* { dg-do compile { target *-*-linux* } } */
1884+/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk-extern" } */
1885+
1886+extern void bar (void);
1887+
1888+int
1889+foo (void)
1890+{
1891+ bar ();
1892+ return 0;
1893+}
1894+
1895+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */
1896+/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 } } */
1897+/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 } } */
1898+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" } } */
1899+/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
1900diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c
1901new file mode 100644
1902index 0000000..6652523
1903--- /dev/null
1904+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c
1905@@ -0,0 +1,43 @@
1906+/* { dg-do compile } */
1907+/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */
1908+
1909+void func0 (void);
1910+void func1 (void);
1911+void func2 (void);
1912+void func3 (void);
1913+void func4 (void);
1914+void func4 (void);
1915+void func5 (void);
1916+
1917+void
1918+bar (int i)
1919+{
1920+ switch (i)
1921+ {
1922+ default:
1923+ func0 ();
1924+ break;
1925+ case 1:
1926+ func1 ();
1927+ break;
1928+ case 2:
1929+ func2 ();
1930+ break;
1931+ case 3:
1932+ func3 ();
1933+ break;
1934+ case 4:
1935+ func4 ();
1936+ break;
1937+ case 5:
1938+ func5 ();
1939+ break;
1940+ }
1941+}
1942+
1943+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { ! x32 } } } } */
1944+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1945+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1946+/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
1947+/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
1948+/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
1949diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c
1950new file mode 100644
1951index 0000000..68c0ff7
1952--- /dev/null
1953+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c
1954@@ -0,0 +1,20 @@
1955+/* { dg-do compile } */
1956+/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */
1957+
1958+typedef void (*dispatch_t)(long offset);
1959+
1960+dispatch_t dispatch;
1961+
1962+void
1963+male_indirect_jump (long offset)
1964+{
1965+ dispatch(offset);
1966+}
1967+
1968+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1969+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1970+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1971+/* { dg-final { scan-assembler {\tpause} } } */
1972+/* { dg-final { scan-assembler {\tlfence} } } */
1973+/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
1974+/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
1975diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c
1976new file mode 100644
1977index 0000000..e2da1fc
1978--- /dev/null
1979+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c
1980@@ -0,0 +1,20 @@
1981+/* { dg-do compile } */
1982+/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */
1983+
1984+typedef void (*dispatch_t)(long offset);
1985+
1986+dispatch_t dispatch[256];
1987+
1988+void
1989+male_indirect_jump (long offset)
1990+{
1991+ dispatch[offset](offset);
1992+}
1993+
1994+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1995+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1996+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1997+/* { dg-final { scan-assembler {\tpause} } } */
1998+/* { dg-final { scan-assembler {\tlfence} } } */
1999+/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
2000+/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
2001diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c
2002new file mode 100644
2003index 0000000..244fec7
2004--- /dev/null
2005+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c
2006@@ -0,0 +1,21 @@
2007+/* { dg-do compile } */
2008+/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */
2009+
2010+typedef void (*dispatch_t)(long offset);
2011+
2012+dispatch_t dispatch;
2013+
2014+int
2015+male_indirect_jump (long offset)
2016+{
2017+ dispatch(offset);
2018+ return 0;
2019+}
2020+
2021+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
2022+/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */
2023+/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */
2024+/* { dg-final { scan-assembler-times {\tpause} 1 } } */
2025+/* { dg-final { scan-assembler-times {\tlfence} 1 } } */
2026+/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
2027+/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
2028diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c
2029new file mode 100644
2030index 0000000..107ebe3
2031--- /dev/null
2032+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c
2033@@ -0,0 +1,21 @@
2034+/* { dg-do compile } */
2035+/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */
2036+
2037+typedef void (*dispatch_t)(long offset);
2038+
2039+dispatch_t dispatch[256];
2040+
2041+int
2042+male_indirect_jump (long offset)
2043+{
2044+ dispatch[offset](offset);
2045+ return 0;
2046+}
2047+
2048+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
2049+/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */
2050+/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */
2051+/* { dg-final { scan-assembler-times {\tpause} 1 } } */
2052+/* { dg-final { scan-assembler-times {\tlfence} 1 } } */
2053+/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
2054+/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
2055diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c
2056new file mode 100644
2057index 0000000..17b04ef
2058--- /dev/null
2059+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c
2060@@ -0,0 +1,17 @@
2061+/* { dg-do compile { target *-*-linux* } } */
2062+/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk-inline" } */
2063+
2064+extern void bar (void);
2065+
2066+void
2067+foo (void)
2068+{
2069+ bar ();
2070+}
2071+
2072+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */
2073+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
2074+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
2075+/* { dg-final { scan-assembler {\tpause} } } */
2076+/* { dg-final { scan-assembler {\tlfence} } } */
2077+/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
2078diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c
2079new file mode 100644
2080index 0000000..d9eb112
2081--- /dev/null
2082+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c
2083@@ -0,0 +1,18 @@
2084+/* { dg-do compile { target *-*-linux* } } */
2085+/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk-inline" } */
2086+
2087+extern void bar (void);
2088+
2089+int
2090+foo (void)
2091+{
2092+ bar ();
2093+ return 0;
2094+}
2095+
2096+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */
2097+/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */
2098+/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */
2099+/* { dg-final { scan-assembler-times {\tpause} 1 } } */
2100+/* { dg-final { scan-assembler-times {\tlfence} 1 } } */
2101+/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
2102diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c
2103new file mode 100644
2104index 0000000..d02b1dc
2105--- /dev/null
2106+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c
2107@@ -0,0 +1,44 @@
2108+/* { dg-do compile } */
2109+/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */
2110+
2111+void func0 (void);
2112+void func1 (void);
2113+void func2 (void);
2114+void func3 (void);
2115+void func4 (void);
2116+void func4 (void);
2117+void func5 (void);
2118+
2119+void
2120+bar (int i)
2121+{
2122+ switch (i)
2123+ {
2124+ default:
2125+ func0 ();
2126+ break;
2127+ case 1:
2128+ func1 ();
2129+ break;
2130+ case 2:
2131+ func2 ();
2132+ break;
2133+ case 3:
2134+ func3 ();
2135+ break;
2136+ case 4:
2137+ func4 ();
2138+ break;
2139+ case 5:
2140+ func5 ();
2141+ break;
2142+ }
2143+}
2144+
2145+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { ! x32 } } } } */
2146+/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
2147+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
2148+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
2149+/* { dg-final { scan-assembler {\tpause} } } */
2150+/* { dg-final { scan-assembler {\tlfence} } } */
2151+/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
2152--
21532.7.4
2154