summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJuro Bystricky <juro.bystricky@intel.com>2018-03-01 10:32:43 -0800
committerRichard Purdie <richard.purdie@linuxfoundation.org>2018-03-14 07:55:54 -0700
commit1d3634423ccc69e06587ca7d06a2408d652df151 (patch)
tree0ee7ba98aeb83f057553c4889266793570409c37
parent12b68d0fc72d7ced68ef9b181adcb844457d94be (diff)
downloadpoky-1d3634423ccc69e06587ca7d06a2408d652df151.tar.gz
gcc6: Backport few more patches
Backported series of patches from https://github.com/hjl-tools/gcc.git branch /hjl/indirect/gcc-6-branch/master which contains an IA patch series for security related issues (From OE-Core rev: 155936a8e5d29d26ef80333920a056f7c3211657) Signed-off-by: Juro Bystricky <juro.bystricky@intel.com> Signed-off-by: Martin Jansa <Martin.Jansa@gmail.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r--meta/recipes-devtools/gcc/gcc-6.4.inc13
-rw-r--r--meta/recipes-devtools/gcc/gcc-6.4/backport/0001-i386-Move-struct-ix86_frame-to-machine_function.patch247
-rw-r--r--meta/recipes-devtools/gcc/gcc-6.4/backport/0002-i386-Use-reference-of-struct-ix86_frame-to-avoid-cop.patch74
-rw-r--r--meta/recipes-devtools/gcc/gcc-6.4/backport/0003-i386-Use-const-reference-of-struct-ix86_frame-to-avo.patch131
-rw-r--r--meta/recipes-devtools/gcc/gcc-6.4/backport/0004-x86-Add-mindirect-branch.patch2154
-rw-r--r--meta/recipes-devtools/gcc/gcc-6.4/backport/0005-x86-Add-mfunction-return.patch1570
-rw-r--r--meta/recipes-devtools/gcc/gcc-6.4/backport/0006-x86-Add-mindirect-branch-register.patch946
-rw-r--r--meta/recipes-devtools/gcc/gcc-6.4/backport/0007-x86-Add-V-register-operand-modifier.patch139
-rw-r--r--meta/recipes-devtools/gcc/gcc-6.4/backport/0008-x86-Disallow-mindirect-branch-mfunction-return-with-.patch304
-rw-r--r--meta/recipes-devtools/gcc/gcc-6.4/backport/0009-Use-INVALID_REGNUM-in-indirect-thunk-processing.patch126
-rw-r--r--meta/recipes-devtools/gcc/gcc-6.4/backport/0010-i386-Pass-INVALID_REGNUM-as-invalid-register-number.patch46
-rw-r--r--meta/recipes-devtools/gcc/gcc-6.4/backport/0011-i386-Update-mfunction-return-for-return-with-pop.patch453
-rw-r--r--meta/recipes-devtools/gcc/gcc-6.4/backport/0012-i386-Add-TARGET_INDIRECT_BRANCH_REGISTER.patch1004
13 files changed, 7207 insertions, 0 deletions
diff --git a/meta/recipes-devtools/gcc/gcc-6.4.inc b/meta/recipes-devtools/gcc/gcc-6.4.inc
index 66654e62a9..1803917f01 100644
--- a/meta/recipes-devtools/gcc/gcc-6.4.inc
+++ b/meta/recipes-devtools/gcc/gcc-6.4.inc
@@ -88,7 +88,20 @@ BACKPORTS = "\
88 file://CVE-2016-6131.patch \ 88 file://CVE-2016-6131.patch \
89 file://0057-ARM-PR-82445-suppress-32-bit-aligned-ldrd-strd-peeph.patch \ 89 file://0057-ARM-PR-82445-suppress-32-bit-aligned-ldrd-strd-peeph.patch \
90 file://0001-enable-FL_LPAE-flag-for-armv7ve-cores.patch \ 90 file://0001-enable-FL_LPAE-flag-for-armv7ve-cores.patch \
91 file://0001-i386-Move-struct-ix86_frame-to-machine_function.patch \
92 file://0002-i386-Use-reference-of-struct-ix86_frame-to-avoid-cop.patch \
93 file://0003-i386-Use-const-reference-of-struct-ix86_frame-to-avo.patch \
94 file://0004-x86-Add-mindirect-branch.patch \
95 file://0005-x86-Add-mfunction-return.patch \
96 file://0006-x86-Add-mindirect-branch-register.patch \
97 file://0007-x86-Add-V-register-operand-modifier.patch \
98 file://0008-x86-Disallow-mindirect-branch-mfunction-return-with-.patch \
99 file://0009-Use-INVALID_REGNUM-in-indirect-thunk-processing.patch \
100 file://0010-i386-Pass-INVALID_REGNUM-as-invalid-register-number.patch \
101 file://0011-i386-Update-mfunction-return-for-return-with-pop.patch \
102 file://0012-i386-Add-TARGET_INDIRECT_BRANCH_REGISTER.patch \
91" 103"
104
92SRC_URI[md5sum] = "11ba51a0cfb8471927f387c8895fe232" 105SRC_URI[md5sum] = "11ba51a0cfb8471927f387c8895fe232"
93SRC_URI[sha256sum] = "850bf21eafdfe5cd5f6827148184c08c4a0852a37ccf36ce69855334d2c914d4" 106SRC_URI[sha256sum] = "850bf21eafdfe5cd5f6827148184c08c4a0852a37ccf36ce69855334d2c914d4"
94 107
diff --git a/meta/recipes-devtools/gcc/gcc-6.4/backport/0001-i386-Move-struct-ix86_frame-to-machine_function.patch b/meta/recipes-devtools/gcc/gcc-6.4/backport/0001-i386-Move-struct-ix86_frame-to-machine_function.patch
new file mode 100644
index 0000000000..00b0ffd156
--- /dev/null
+++ b/meta/recipes-devtools/gcc/gcc-6.4/backport/0001-i386-Move-struct-ix86_frame-to-machine_function.patch
@@ -0,0 +1,247 @@
1From c2c7775c5587dc59b6756162d390d89d60971a16 Mon Sep 17 00:00:00 2001
2From: hjl <hjl@138bc75d-0d04-0410-961f-82ee72b054a4>
3Date: Mon, 15 Jan 2018 11:27:24 +0000
4Subject: [PATCH 01/12] i386: Move struct ix86_frame to machine_function
5
6Make ix86_frame available to i386 code generation. This is needed to
7backport the patch set of -mindirect-branch= to mitigate variant #2 of
8the speculative execution vulnerabilities on x86 processors identified
9by CVE-2017-5715, aka Spectre.
10
11 Backport from mainline
12 2017-06-01 Bernd Edlinger <bernd.edlinger@hotmail.de>
13
14 * config/i386/i386.c (ix86_frame): Moved to ...
15 * config/i386/i386.h (ix86_frame): Here.
16 (machine_function): Add frame.
17 * config/i386/i386.c (ix86_compute_frame_layout): Repace the
18 frame argument with &cfun->machine->frame.
19 (ix86_can_use_return_insn_p): Don't pass &frame to
20 ix86_compute_frame_layout. Copy frame from cfun->machine->frame.
21 (ix86_can_eliminate): Likewise.
22 (ix86_expand_prologue): Likewise.
23 (ix86_expand_epilogue): Likewise.
24 (ix86_expand_split_stack_prologue): Likewise.
25
26
27Upstream-Status: Pending
28
29Signed-off-by: Juro Bystricky <juro.bystricky@intel.com>
30
31---
32 gcc/config/i386/i386.c | 68 ++++++++++----------------------------------------
33 gcc/config/i386/i386.h | 53 ++++++++++++++++++++++++++++++++++++++-
34 2 files changed, 65 insertions(+), 56 deletions(-)
35
36diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
37index 8b5faac..a1ff32b 100644
38--- a/gcc/config/i386/i386.c
39+++ b/gcc/config/i386/i386.c
40@@ -2434,53 +2434,6 @@ struct GTY(()) stack_local_entry {
41 struct stack_local_entry *next;
42 };
43
44-/* Structure describing stack frame layout.
45- Stack grows downward:
46-
47- [arguments]
48- <- ARG_POINTER
49- saved pc
50-
51- saved static chain if ix86_static_chain_on_stack
52-
53- saved frame pointer if frame_pointer_needed
54- <- HARD_FRAME_POINTER
55- [saved regs]
56- <- regs_save_offset
57- [padding0]
58-
59- [saved SSE regs]
60- <- sse_regs_save_offset
61- [padding1] |
62- | <- FRAME_POINTER
63- [va_arg registers] |
64- |
65- [frame] |
66- |
67- [padding2] | = to_allocate
68- <- STACK_POINTER
69- */
70-struct ix86_frame
71-{
72- int nsseregs;
73- int nregs;
74- int va_arg_size;
75- int red_zone_size;
76- int outgoing_arguments_size;
77-
78- /* The offsets relative to ARG_POINTER. */
79- HOST_WIDE_INT frame_pointer_offset;
80- HOST_WIDE_INT hard_frame_pointer_offset;
81- HOST_WIDE_INT stack_pointer_offset;
82- HOST_WIDE_INT hfp_save_offset;
83- HOST_WIDE_INT reg_save_offset;
84- HOST_WIDE_INT sse_reg_save_offset;
85-
86- /* When save_regs_using_mov is set, emit prologue using
87- move instead of push instructions. */
88- bool save_regs_using_mov;
89-};
90-
91 /* Which cpu are we scheduling for. */
92 enum attr_cpu ix86_schedule;
93
94@@ -2572,7 +2525,7 @@ static unsigned int ix86_function_arg_boundary (machine_mode,
95 const_tree);
96 static rtx ix86_static_chain (const_tree, bool);
97 static int ix86_function_regparm (const_tree, const_tree);
98-static void ix86_compute_frame_layout (struct ix86_frame *);
99+static void ix86_compute_frame_layout (void);
100 static bool ix86_expand_vector_init_one_nonzero (bool, machine_mode,
101 rtx, rtx, int);
102 static void ix86_add_new_builtins (HOST_WIDE_INT);
103@@ -10944,7 +10897,8 @@ ix86_can_use_return_insn_p (void)
104 if (crtl->args.pops_args && crtl->args.size >= 32768)
105 return 0;
106
107- ix86_compute_frame_layout (&frame);
108+ ix86_compute_frame_layout ();
109+ frame = cfun->machine->frame;
110 return (frame.stack_pointer_offset == UNITS_PER_WORD
111 && (frame.nregs + frame.nsseregs) == 0);
112 }
113@@ -11355,8 +11309,8 @@ ix86_can_eliminate (const int from, const int to)
114 HOST_WIDE_INT
115 ix86_initial_elimination_offset (int from, int to)
116 {
117- struct ix86_frame frame;
118- ix86_compute_frame_layout (&frame);
119+ ix86_compute_frame_layout ();
120+ struct ix86_frame frame = cfun->machine->frame;
121
122 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
123 return frame.hard_frame_pointer_offset;
124@@ -11395,8 +11349,9 @@ ix86_builtin_setjmp_frame_value (void)
125 /* Fill structure ix86_frame about frame of currently computed function. */
126
127 static void
128-ix86_compute_frame_layout (struct ix86_frame *frame)
129+ix86_compute_frame_layout (void)
130 {
131+ struct ix86_frame *frame = &cfun->machine->frame;
132 unsigned HOST_WIDE_INT stack_alignment_needed;
133 HOST_WIDE_INT offset;
134 unsigned HOST_WIDE_INT preferred_alignment;
135@@ -12702,7 +12657,8 @@ ix86_expand_prologue (void)
136 m->fs.sp_offset = INCOMING_FRAME_SP_OFFSET;
137 m->fs.sp_valid = true;
138
139- ix86_compute_frame_layout (&frame);
140+ ix86_compute_frame_layout ();
141+ frame = m->frame;
142
143 if (!TARGET_64BIT && ix86_function_ms_hook_prologue (current_function_decl))
144 {
145@@ -13379,7 +13335,8 @@ ix86_expand_epilogue (int style)
146 bool using_drap;
147
148 ix86_finalize_stack_realign_flags ();
149- ix86_compute_frame_layout (&frame);
150+ ix86_compute_frame_layout ();
151+ frame = m->frame;
152
153 m->fs.sp_valid = (!frame_pointer_needed
154 || (crtl->sp_is_unchanging
155@@ -13876,7 +13833,8 @@ ix86_expand_split_stack_prologue (void)
156 gcc_assert (flag_split_stack && reload_completed);
157
158 ix86_finalize_stack_realign_flags ();
159- ix86_compute_frame_layout (&frame);
160+ ix86_compute_frame_layout ();
161+ frame = cfun->machine->frame;
162 allocate = frame.stack_pointer_offset - INCOMING_FRAME_SP_OFFSET;
163
164 /* This is the label we will branch to if we have enough stack
165diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
166index 8113f83..5414416 100644
167--- a/gcc/config/i386/i386.h
168+++ b/gcc/config/i386/i386.h
169@@ -2427,9 +2427,56 @@ enum avx_u128_state
170
171 #define FASTCALL_PREFIX '@'
172
173+#ifndef USED_FOR_TARGET
174+/* Structure describing stack frame layout.
175+ Stack grows downward:
176+
177+ [arguments]
178+ <- ARG_POINTER
179+ saved pc
180+
181+ saved static chain if ix86_static_chain_on_stack
182+
183+ saved frame pointer if frame_pointer_needed
184+ <- HARD_FRAME_POINTER
185+ [saved regs]
186+ <- regs_save_offset
187+ [padding0]
188+
189+ [saved SSE regs]
190+ <- sse_regs_save_offset
191+ [padding1] |
192+ | <- FRAME_POINTER
193+ [va_arg registers] |
194+ |
195+ [frame] |
196+ |
197+ [padding2] | = to_allocate
198+ <- STACK_POINTER
199+ */
200+struct GTY(()) ix86_frame
201+{
202+ int nsseregs;
203+ int nregs;
204+ int va_arg_size;
205+ int red_zone_size;
206+ int outgoing_arguments_size;
207+
208+ /* The offsets relative to ARG_POINTER. */
209+ HOST_WIDE_INT frame_pointer_offset;
210+ HOST_WIDE_INT hard_frame_pointer_offset;
211+ HOST_WIDE_INT stack_pointer_offset;
212+ HOST_WIDE_INT hfp_save_offset;
213+ HOST_WIDE_INT reg_save_offset;
214+ HOST_WIDE_INT sse_reg_save_offset;
215+
216+ /* When save_regs_using_mov is set, emit prologue using
217+ move instead of push instructions. */
218+ bool save_regs_using_mov;
219+};
220+
221 /* Machine specific frame tracking during prologue/epilogue generation. */
222
223-#ifndef USED_FOR_TARGET
224 struct GTY(()) machine_frame_state
225 {
226 /* This pair tracks the currently active CFA as reg+offset. When reg
227@@ -2475,6 +2522,9 @@ struct GTY(()) machine_function {
228 int varargs_fpr_size;
229 int optimize_mode_switching[MAX_386_ENTITIES];
230
231+ /* Cached initial frame layout for the current function. */
232+ struct ix86_frame frame;
233+
234 /* Number of saved registers USE_FAST_PROLOGUE_EPILOGUE
235 has been computed for. */
236 int use_fast_prologue_epilogue_nregs;
237@@ -2554,6 +2604,7 @@ struct GTY(()) machine_function {
238 #define ix86_current_function_calls_tls_descriptor \
239 (ix86_tls_descriptor_calls_expanded_in_cfun && df_regs_ever_live_p (SP_REG))
240 #define ix86_static_chain_on_stack (cfun->machine->static_chain_on_stack)
241+#define ix86_red_zone_size (cfun->machine->frame.red_zone_size)
242
243 /* Control behavior of x86_file_start. */
244 #define X86_FILE_START_VERSION_DIRECTIVE false
245--
2462.7.4
247
diff --git a/meta/recipes-devtools/gcc/gcc-6.4/backport/0002-i386-Use-reference-of-struct-ix86_frame-to-avoid-cop.patch b/meta/recipes-devtools/gcc/gcc-6.4/backport/0002-i386-Use-reference-of-struct-ix86_frame-to-avoid-cop.patch
new file mode 100644
index 0000000000..df65b08f93
--- /dev/null
+++ b/meta/recipes-devtools/gcc/gcc-6.4/backport/0002-i386-Use-reference-of-struct-ix86_frame-to-avoid-cop.patch
@@ -0,0 +1,74 @@
1From fe2b3be3f4b6ec6b3a6f89c26016a3983b7cb351 Mon Sep 17 00:00:00 2001
2From: hjl <hjl@138bc75d-0d04-0410-961f-82ee72b054a4>
3Date: Mon, 15 Jan 2018 11:28:44 +0000
4Subject: [PATCH 02/12] i386: Use reference of struct ix86_frame to avoid copy
5
6When there is no need to make a copy of ix86_frame, we can use reference
7of struct ix86_frame to avoid copy.
8
9 Backport from mainline
10 2017-11-06 H.J. Lu <hongjiu.lu@intel.com>
11
12 * config/i386/i386.c (ix86_can_use_return_insn_p): Use reference
13 of struct ix86_frame.
14 (ix86_initial_elimination_offset): Likewise.
15 (ix86_expand_split_stack_prologue): Likewise.
16
17Upstream-Status: Pending
18
19Signed-off-by: Juro Bystricky <juro.bystricky@intel.com>
20
21---
22 gcc/config/i386/i386.c | 8 +++-----
23 1 file changed, 3 insertions(+), 5 deletions(-)
24
25diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
26index a1ff32b..13ebf10 100644
27--- a/gcc/config/i386/i386.c
28+++ b/gcc/config/i386/i386.c
29@@ -10887,7 +10887,6 @@ symbolic_reference_mentioned_p (rtx op)
30 bool
31 ix86_can_use_return_insn_p (void)
32 {
33- struct ix86_frame frame;
34
35 if (! reload_completed || frame_pointer_needed)
36 return 0;
37@@ -10898,7 +10897,7 @@ ix86_can_use_return_insn_p (void)
38 return 0;
39
40 ix86_compute_frame_layout ();
41- frame = cfun->machine->frame;
42+ struct ix86_frame &frame = cfun->machine->frame;
43 return (frame.stack_pointer_offset == UNITS_PER_WORD
44 && (frame.nregs + frame.nsseregs) == 0);
45 }
46@@ -11310,7 +11309,7 @@ HOST_WIDE_INT
47 ix86_initial_elimination_offset (int from, int to)
48 {
49 ix86_compute_frame_layout ();
50- struct ix86_frame frame = cfun->machine->frame;
51+ struct ix86_frame &frame = cfun->machine->frame;
52
53 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
54 return frame.hard_frame_pointer_offset;
55@@ -13821,7 +13820,6 @@ static GTY(()) rtx split_stack_fn_large;
56 void
57 ix86_expand_split_stack_prologue (void)
58 {
59- struct ix86_frame frame;
60 HOST_WIDE_INT allocate;
61 unsigned HOST_WIDE_INT args_size;
62 rtx_code_label *label;
63@@ -13834,7 +13832,7 @@ ix86_expand_split_stack_prologue (void)
64
65 ix86_finalize_stack_realign_flags ();
66 ix86_compute_frame_layout ();
67- frame = cfun->machine->frame;
68+ struct ix86_frame &frame = cfun->machine->frame;
69 allocate = frame.stack_pointer_offset - INCOMING_FRAME_SP_OFFSET;
70
71 /* This is the label we will branch to if we have enough stack
72--
732.7.4
74
diff --git a/meta/recipes-devtools/gcc/gcc-6.4/backport/0003-i386-Use-const-reference-of-struct-ix86_frame-to-avo.patch b/meta/recipes-devtools/gcc/gcc-6.4/backport/0003-i386-Use-const-reference-of-struct-ix86_frame-to-avo.patch
new file mode 100644
index 0000000000..a5ffd85d6f
--- /dev/null
+++ b/meta/recipes-devtools/gcc/gcc-6.4/backport/0003-i386-Use-const-reference-of-struct-ix86_frame-to-avo.patch
@@ -0,0 +1,131 @@
1From 82243732dc63e9b90396a5ae4ad99ca36af81355 Mon Sep 17 00:00:00 2001
2From: hjl <hjl@138bc75d-0d04-0410-961f-82ee72b054a4>
3Date: Sat, 27 Jan 2018 13:10:24 +0000
4Subject: [PATCH 03/12] i386: Use const reference of struct ix86_frame to avoid
5 copy
6
7We can use const reference of struct ix86_frame to avoid making a local
8copy of ix86_frame. ix86_expand_epilogue makes a local copy of struct
9ix86_frame and uses the reg_save_offset field as a local variable. This
10patch uses a separate local variable for reg_save_offset.
11
12Tested on x86-64 with ada.
13
14 Backport from mainline
15 PR target/83905
16 * config/i386/i386.c (ix86_expand_prologue): Use cost reference
17 of struct ix86_frame.
18 (ix86_expand_epilogue): Likewise. Add a local variable for
19 the reg_save_offset field in struct ix86_frame.
20
21git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gcc-7-branch@257123 138bc75d-0d04-0410-961f-82ee72b054a4
22
23Upstream-Status: Pending
24
25Signed-off-by: Juro Bystricky <juro.bystricky@intel.com>
26
27---
28 gcc/config/i386/i386.c | 24 ++++++++++++------------
29 1 file changed, 12 insertions(+), 12 deletions(-)
30
31diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
32index 13ebf10..6c98f75 100644
33--- a/gcc/config/i386/i386.c
34+++ b/gcc/config/i386/i386.c
35@@ -12633,7 +12633,6 @@ ix86_expand_prologue (void)
36 {
37 struct machine_function *m = cfun->machine;
38 rtx insn, t;
39- struct ix86_frame frame;
40 HOST_WIDE_INT allocate;
41 bool int_registers_saved;
42 bool sse_registers_saved;
43@@ -12657,7 +12656,7 @@ ix86_expand_prologue (void)
44 m->fs.sp_valid = true;
45
46 ix86_compute_frame_layout ();
47- frame = m->frame;
48+ const struct ix86_frame &frame = cfun->machine->frame;
49
50 if (!TARGET_64BIT && ix86_function_ms_hook_prologue (current_function_decl))
51 {
52@@ -13329,13 +13328,12 @@ ix86_expand_epilogue (int style)
53 {
54 struct machine_function *m = cfun->machine;
55 struct machine_frame_state frame_state_save = m->fs;
56- struct ix86_frame frame;
57 bool restore_regs_via_mov;
58 bool using_drap;
59
60 ix86_finalize_stack_realign_flags ();
61 ix86_compute_frame_layout ();
62- frame = m->frame;
63+ const struct ix86_frame &frame = cfun->machine->frame;
64
65 m->fs.sp_valid = (!frame_pointer_needed
66 || (crtl->sp_is_unchanging
67@@ -13377,11 +13375,13 @@ ix86_expand_epilogue (int style)
68 + UNITS_PER_WORD);
69 }
70
71+ HOST_WIDE_INT reg_save_offset = frame.reg_save_offset;
72+
73 /* Special care must be taken for the normal return case of a function
74 using eh_return: the eax and edx registers are marked as saved, but
75 not restored along this path. Adjust the save location to match. */
76 if (crtl->calls_eh_return && style != 2)
77- frame.reg_save_offset -= 2 * UNITS_PER_WORD;
78+ reg_save_offset -= 2 * UNITS_PER_WORD;
79
80 /* EH_RETURN requires the use of moves to function properly. */
81 if (crtl->calls_eh_return)
82@@ -13397,11 +13397,11 @@ ix86_expand_epilogue (int style)
83 else if (TARGET_EPILOGUE_USING_MOVE
84 && cfun->machine->use_fast_prologue_epilogue
85 && (frame.nregs > 1
86- || m->fs.sp_offset != frame.reg_save_offset))
87+ || m->fs.sp_offset != reg_save_offset))
88 restore_regs_via_mov = true;
89 else if (frame_pointer_needed
90 && !frame.nregs
91- && m->fs.sp_offset != frame.reg_save_offset)
92+ && m->fs.sp_offset != reg_save_offset)
93 restore_regs_via_mov = true;
94 else if (frame_pointer_needed
95 && TARGET_USE_LEAVE
96@@ -13439,7 +13439,7 @@ ix86_expand_epilogue (int style)
97 rtx t;
98
99 if (frame.nregs)
100- ix86_emit_restore_regs_using_mov (frame.reg_save_offset, style == 2);
101+ ix86_emit_restore_regs_using_mov (reg_save_offset, style == 2);
102
103 /* eh_return epilogues need %ecx added to the stack pointer. */
104 if (style == 2)
105@@ -13529,19 +13529,19 @@ ix86_expand_epilogue (int style)
106 epilogues. */
107 if (!m->fs.sp_valid
108 || (TARGET_SEH
109- && (m->fs.sp_offset - frame.reg_save_offset
110+ && (m->fs.sp_offset - reg_save_offset
111 >= SEH_MAX_FRAME_SIZE)))
112 {
113 pro_epilogue_adjust_stack (stack_pointer_rtx, hard_frame_pointer_rtx,
114 GEN_INT (m->fs.fp_offset
115- - frame.reg_save_offset),
116+ - reg_save_offset),
117 style, false);
118 }
119- else if (m->fs.sp_offset != frame.reg_save_offset)
120+ else if (m->fs.sp_offset != reg_save_offset)
121 {
122 pro_epilogue_adjust_stack (stack_pointer_rtx, stack_pointer_rtx,
123 GEN_INT (m->fs.sp_offset
124- - frame.reg_save_offset),
125+ - reg_save_offset),
126 style,
127 m->fs.cfa_reg == stack_pointer_rtx);
128 }
129--
1302.7.4
131
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
diff --git a/meta/recipes-devtools/gcc/gcc-6.4/backport/0005-x86-Add-mfunction-return.patch b/meta/recipes-devtools/gcc/gcc-6.4/backport/0005-x86-Add-mfunction-return.patch
new file mode 100644
index 0000000000..5354c77d6f
--- /dev/null
+++ b/meta/recipes-devtools/gcc/gcc-6.4/backport/0005-x86-Add-mfunction-return.patch
@@ -0,0 +1,1570 @@
1From e3270814b9e0caad63fbcdfd7ae9da2d52c97497 Mon Sep 17 00:00:00 2001
2From: "H.J. Lu" <hjl.tools@gmail.com>
3Date: Sat, 6 Jan 2018 22:29:56 -0800
4Subject: [PATCH 05/12] x86: Add -mfunction-return=
5
6Add -mfunction-return= option to convert function return to call and
7return thunks. The default is 'keep', which keeps function return
8unmodified. 'thunk' converts function return to call and return thunk.
9'thunk-inline' converts function return to inlined call and return thunk.
10'thunk-extern' converts function return to external call and return
11thunk provided in a separate object file. You can control this behavior
12for a specific function by using the function attribute function_return.
13
14Function return thunk is the same as memory thunk for -mindirect-branch=
15where the return address is at the top of the stack:
16
17__x86_return_thunk:
18 call L2
19L1:
20 pause
21 lfence
22 jmp L1
23L2:
24 lea 8(%rsp), %rsp|lea 4(%esp), %esp
25 ret
26
27and function return becomes
28
29 jmp __x86_return_thunk
30
31-mindirect-branch= tests are updated with -mfunction-return=keep to
32avoid false test failures when -mfunction-return=thunk is added to
33RUNTESTFLAGS for "make check".
34
35gcc/
36
37 Backport from mainline
38 2018-01-14 H.J. Lu <hongjiu.lu@intel.com>
39
40 * config/i386/i386-protos.h (ix86_output_function_return): New.
41 * config/i386/i386.c (ix86_set_indirect_branch_type): Also
42 set function_return_type.
43 (indirect_thunk_name): Add ret_p to indicate thunk for function
44 return.
45 (output_indirect_thunk_function): Pass false to
46 indirect_thunk_name.
47 (ix86_output_indirect_branch_via_reg): Likewise.
48 (ix86_output_indirect_branch_via_push): Likewise.
49 (output_indirect_thunk_function): Create alias for function
50 return thunk if regno < 0.
51 (ix86_output_function_return): New function.
52 (ix86_handle_fndecl_attribute): Handle function_return.
53 (ix86_attribute_table): Add function_return.
54 * config/i386/i386.h (machine_function): Add
55 function_return_type.
56 * config/i386/i386.md (simple_return_internal): Use
57 ix86_output_function_return.
58 (simple_return_internal_long): Likewise.
59 * config/i386/i386.opt (mfunction-return=): New option.
60 (indirect_branch): Mention -mfunction-return=.
61 * doc/extend.texi: Document function_return function attribute.
62 * doc/invoke.texi: Document -mfunction-return= option.
63
64gcc/testsuite/
65
66 Backport from mainline
67 2018-01-14 H.J. Lu <hongjiu.lu@intel.com>
68
69 * gcc.target/i386/indirect-thunk-1.c (dg-options): Add
70 -mfunction-return=keep.
71 * gcc.target/i386/indirect-thunk-2.c: Likewise.
72 * gcc.target/i386/indirect-thunk-3.c: Likewise.
73 * gcc.target/i386/indirect-thunk-4.c: Likewise.
74 * gcc.target/i386/indirect-thunk-5.c: Likewise.
75 * gcc.target/i386/indirect-thunk-6.c: Likewise.
76 * gcc.target/i386/indirect-thunk-7.c: Likewise.
77 * gcc.target/i386/indirect-thunk-attr-1.c: Likewise.
78 * gcc.target/i386/indirect-thunk-attr-2.c: Likewise.
79 * gcc.target/i386/indirect-thunk-attr-3.c: Likewise.
80 * gcc.target/i386/indirect-thunk-attr-4.c: Likewise.
81 * gcc.target/i386/indirect-thunk-attr-5.c: Likewise.
82 * gcc.target/i386/indirect-thunk-attr-6.c: Likewise.
83 * gcc.target/i386/indirect-thunk-attr-7.c: Likewise.
84 * gcc.target/i386/indirect-thunk-attr-8.c: Likewise.
85 * gcc.target/i386/indirect-thunk-bnd-1.c: Likewise.
86 * gcc.target/i386/indirect-thunk-bnd-2.c: Likewise.
87 * gcc.target/i386/indirect-thunk-bnd-3.c: Likewise.
88 * gcc.target/i386/indirect-thunk-bnd-4.c: Likewise.
89 * gcc.target/i386/indirect-thunk-extern-1.c: Likewise.
90 * gcc.target/i386/indirect-thunk-extern-2.c: Likewise.
91 * gcc.target/i386/indirect-thunk-extern-3.c: Likewise.
92 * gcc.target/i386/indirect-thunk-extern-4.c: Likewise.
93 * gcc.target/i386/indirect-thunk-extern-5.c: Likewise.
94 * gcc.target/i386/indirect-thunk-extern-6.c: Likewise.
95 * gcc.target/i386/indirect-thunk-extern-7.c: Likewise.
96 * gcc.target/i386/indirect-thunk-inline-1.c: Likewise.
97 * gcc.target/i386/indirect-thunk-inline-2.c: Likewise.
98 * gcc.target/i386/indirect-thunk-inline-3.c: Likewise.
99 * gcc.target/i386/indirect-thunk-inline-4.c: Likewise.
100 * gcc.target/i386/indirect-thunk-inline-5.c: Likewise.
101 * gcc.target/i386/indirect-thunk-inline-6.c: Likewise.
102 * gcc.target/i386/indirect-thunk-inline-7.c: Likewise.
103 * gcc.target/i386/ret-thunk-1.c: New test.
104 * gcc.target/i386/ret-thunk-10.c: Likewise.
105 * gcc.target/i386/ret-thunk-11.c: Likewise.
106 * gcc.target/i386/ret-thunk-12.c: Likewise.
107 * gcc.target/i386/ret-thunk-13.c: Likewise.
108 * gcc.target/i386/ret-thunk-14.c: Likewise.
109 * gcc.target/i386/ret-thunk-15.c: Likewise.
110 * gcc.target/i386/ret-thunk-16.c: Likewise.
111 * gcc.target/i386/ret-thunk-2.c: Likewise.
112 * gcc.target/i386/ret-thunk-3.c: Likewise.
113 * gcc.target/i386/ret-thunk-4.c: Likewise.
114 * gcc.target/i386/ret-thunk-5.c: Likewise.
115 * gcc.target/i386/ret-thunk-6.c: Likewise.
116 * gcc.target/i386/ret-thunk-7.c: Likewise.
117 * gcc.target/i386/ret-thunk-8.c: Likewise.
118 * gcc.target/i386/ret-thunk-9.c: Likewise.
119
120i386: Don't use ASM_OUTPUT_DEF for TARGET_MACHO
121
122ASM_OUTPUT_DEF isn't defined for TARGET_MACHO. Use ASM_OUTPUT_LABEL to
123generate the __x86_return_thunk label, instead of the set directive.
124Update testcase to remove the __x86_return_thunk label check. Since
125-fno-pic is ignored on Darwin, update testcases to sscan or "push"
126only on Linux.
127
128gcc/
129
130 Backport from mainline
131 2018-01-15 H.J. Lu <hongjiu.lu@intel.com>
132
133 PR target/83839
134 * config/i386/i386.c (output_indirect_thunk_function): Use
135 ASM_OUTPUT_LABEL, instead of ASM_OUTPUT_DEF, for TARGET_MACHO
136 for __x86.return_thunk.
137
138gcc/testsuite/
139
140 Backport from mainline
141 2018-01-15 H.J. Lu <hongjiu.lu@intel.com>
142
143 PR target/83839
144 * gcc.target/i386/indirect-thunk-1.c: Scan for "push" only on
145 Linux.
146 * gcc.target/i386/indirect-thunk-2.c: Likewise.
147 * gcc.target/i386/indirect-thunk-3.c: Likewise.
148 * gcc.target/i386/indirect-thunk-4.c: Likewise.
149 * gcc.target/i386/indirect-thunk-7.c: Likewise.
150 * gcc.target/i386/indirect-thunk-attr-1.c: Likewise.
151 * gcc.target/i386/indirect-thunk-attr-2.c: Likewise.
152 * gcc.target/i386/indirect-thunk-attr-5.c: Likewise.
153 * gcc.target/i386/indirect-thunk-attr-6.c: Likewise.
154 * gcc.target/i386/indirect-thunk-attr-7.c: Likewise.
155 * gcc.target/i386/indirect-thunk-extern-1.c: Likewise.
156 * gcc.target/i386/indirect-thunk-extern-2.c: Likewise.
157 * gcc.target/i386/indirect-thunk-extern-3.c: Likewise.
158 * gcc.target/i386/indirect-thunk-extern-4.c: Likewise.
159 * gcc.target/i386/indirect-thunk-extern-7.c: Likewise.
160 * gcc.target/i386/indirect-thunk-register-1.c: Likewise.
161 * gcc.target/i386/indirect-thunk-register-3.c: Likewise.
162 * gcc.target/i386/indirect-thunk-register-4.c: Likewise.
163 * gcc.target/i386/ret-thunk-10.c: Likewise.
164 * gcc.target/i386/ret-thunk-11.c: Likewise.
165 * gcc.target/i386/ret-thunk-12.c: Likewise.
166 * gcc.target/i386/ret-thunk-13.c: Likewise.
167 * gcc.target/i386/ret-thunk-14.c: Likewise.
168 * gcc.target/i386/ret-thunk-15.c: Likewise.
169 * gcc.target/i386/ret-thunk-9.c: Don't check the
170 __x86_return_thunk label.
171 Scan for "push" only for Linux.
172
173Upstream-Status: Pending
174
175Signed-off-by: Juro Bystricky <juro.bystricky@intel.com>
176
177---
178 gcc/config/i386/i386-protos.h | 1 +
179 gcc/config/i386/i386.c | 152 +++++++++++++++++++--
180 gcc/config/i386/i386.h | 3 +
181 gcc/config/i386/i386.md | 9 +-
182 gcc/config/i386/i386.opt | 6 +-
183 gcc/doc/extend.texi | 9 ++
184 gcc/doc/invoke.texi | 14 +-
185 gcc/testsuite/gcc.target/i386/indirect-thunk-1.c | 4 +-
186 gcc/testsuite/gcc.target/i386/indirect-thunk-2.c | 4 +-
187 gcc/testsuite/gcc.target/i386/indirect-thunk-3.c | 4 +-
188 gcc/testsuite/gcc.target/i386/indirect-thunk-4.c | 4 +-
189 gcc/testsuite/gcc.target/i386/indirect-thunk-5.c | 2 +-
190 gcc/testsuite/gcc.target/i386/indirect-thunk-6.c | 2 +-
191 gcc/testsuite/gcc.target/i386/indirect-thunk-7.c | 4 +-
192 .../gcc.target/i386/indirect-thunk-attr-1.c | 4 +-
193 .../gcc.target/i386/indirect-thunk-attr-2.c | 4 +-
194 .../gcc.target/i386/indirect-thunk-attr-3.c | 4 +-
195 .../gcc.target/i386/indirect-thunk-attr-4.c | 4 +-
196 .../gcc.target/i386/indirect-thunk-attr-5.c | 4 +-
197 .../gcc.target/i386/indirect-thunk-attr-6.c | 4 +-
198 .../gcc.target/i386/indirect-thunk-attr-7.c | 4 +-
199 .../gcc.target/i386/indirect-thunk-attr-8.c | 2 +-
200 .../gcc.target/i386/indirect-thunk-bnd-1.c | 4 +-
201 .../gcc.target/i386/indirect-thunk-bnd-2.c | 4 +-
202 .../gcc.target/i386/indirect-thunk-bnd-3.c | 2 +-
203 .../gcc.target/i386/indirect-thunk-bnd-4.c | 2 +-
204 .../gcc.target/i386/indirect-thunk-extern-1.c | 4 +-
205 .../gcc.target/i386/indirect-thunk-extern-2.c | 4 +-
206 .../gcc.target/i386/indirect-thunk-extern-3.c | 4 +-
207 .../gcc.target/i386/indirect-thunk-extern-4.c | 4 +-
208 .../gcc.target/i386/indirect-thunk-extern-5.c | 2 +-
209 .../gcc.target/i386/indirect-thunk-extern-6.c | 2 +-
210 .../gcc.target/i386/indirect-thunk-extern-7.c | 4 +-
211 .../gcc.target/i386/indirect-thunk-inline-1.c | 4 +-
212 .../gcc.target/i386/indirect-thunk-inline-2.c | 4 +-
213 .../gcc.target/i386/indirect-thunk-inline-3.c | 4 +-
214 .../gcc.target/i386/indirect-thunk-inline-4.c | 4 +-
215 .../gcc.target/i386/indirect-thunk-inline-5.c | 2 +-
216 .../gcc.target/i386/indirect-thunk-inline-6.c | 2 +-
217 .../gcc.target/i386/indirect-thunk-inline-7.c | 4 +-
218 gcc/testsuite/gcc.target/i386/ret-thunk-1.c | 13 ++
219 gcc/testsuite/gcc.target/i386/ret-thunk-10.c | 23 ++++
220 gcc/testsuite/gcc.target/i386/ret-thunk-11.c | 23 ++++
221 gcc/testsuite/gcc.target/i386/ret-thunk-12.c | 22 +++
222 gcc/testsuite/gcc.target/i386/ret-thunk-13.c | 22 +++
223 gcc/testsuite/gcc.target/i386/ret-thunk-14.c | 22 +++
224 gcc/testsuite/gcc.target/i386/ret-thunk-15.c | 22 +++
225 gcc/testsuite/gcc.target/i386/ret-thunk-16.c | 18 +++
226 gcc/testsuite/gcc.target/i386/ret-thunk-2.c | 13 ++
227 gcc/testsuite/gcc.target/i386/ret-thunk-3.c | 12 ++
228 gcc/testsuite/gcc.target/i386/ret-thunk-4.c | 12 ++
229 gcc/testsuite/gcc.target/i386/ret-thunk-5.c | 15 ++
230 gcc/testsuite/gcc.target/i386/ret-thunk-6.c | 14 ++
231 gcc/testsuite/gcc.target/i386/ret-thunk-7.c | 13 ++
232 gcc/testsuite/gcc.target/i386/ret-thunk-8.c | 14 ++
233 gcc/testsuite/gcc.target/i386/ret-thunk-9.c | 24 ++++
234 56 files changed, 516 insertions(+), 74 deletions(-)
235 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-1.c
236 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-10.c
237 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-11.c
238 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-12.c
239 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-13.c
240 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-14.c
241 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-15.c
242 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-16.c
243 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-2.c
244 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-3.c
245 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-4.c
246 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-5.c
247 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-6.c
248 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-7.c
249 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-8.c
250 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-9.c
251
252diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h
253index eca4cbf..620d70e 100644
254--- a/gcc/config/i386/i386-protos.h
255+++ b/gcc/config/i386/i386-protos.h
256@@ -312,6 +312,7 @@ extern enum attr_cpu ix86_schedule;
257
258 extern const char * ix86_output_call_insn (rtx_insn *insn, rtx call_op);
259 extern const char * ix86_output_indirect_jmp (rtx call_op, bool ret_p);
260+extern const char * ix86_output_function_return (bool long_p);
261 extern bool ix86_operands_ok_for_move_multiple (rtx *operands, bool load,
262 enum machine_mode mode);
263
264diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
265index 0b9fc4d..34e26a3 100644
266--- a/gcc/config/i386/i386.c
267+++ b/gcc/config/i386/i386.c
268@@ -6390,6 +6390,31 @@ ix86_set_indirect_branch_type (tree fndecl)
269 else
270 cfun->machine->indirect_branch_type = ix86_indirect_branch;
271 }
272+
273+ if (cfun->machine->function_return_type == indirect_branch_unset)
274+ {
275+ tree attr = lookup_attribute ("function_return",
276+ DECL_ATTRIBUTES (fndecl));
277+ if (attr != NULL)
278+ {
279+ tree args = TREE_VALUE (attr);
280+ if (args == NULL)
281+ gcc_unreachable ();
282+ tree cst = TREE_VALUE (args);
283+ if (strcmp (TREE_STRING_POINTER (cst), "keep") == 0)
284+ cfun->machine->function_return_type = indirect_branch_keep;
285+ else if (strcmp (TREE_STRING_POINTER (cst), "thunk") == 0)
286+ cfun->machine->function_return_type = indirect_branch_thunk;
287+ else if (strcmp (TREE_STRING_POINTER (cst), "thunk-inline") == 0)
288+ cfun->machine->function_return_type = indirect_branch_thunk_inline;
289+ else if (strcmp (TREE_STRING_POINTER (cst), "thunk-extern") == 0)
290+ cfun->machine->function_return_type = indirect_branch_thunk_extern;
291+ else
292+ gcc_unreachable ();
293+ }
294+ else
295+ cfun->machine->function_return_type = ix86_function_return;
296+ }
297 }
298
299 /* Establish appropriate back-end context for processing the function
300@@ -11036,8 +11061,12 @@ static int indirect_thunks_bnd_used;
301 /* Fills in the label name that should be used for the indirect thunk. */
302
303 static void
304-indirect_thunk_name (char name[32], int regno, bool need_bnd_p)
305+indirect_thunk_name (char name[32], int regno, bool need_bnd_p,
306+ bool ret_p)
307 {
308+ if (regno >= 0 && ret_p)
309+ gcc_unreachable ();
310+
311 if (USE_HIDDEN_LINKONCE)
312 {
313 const char *bnd = need_bnd_p ? "_bnd" : "";
314@@ -11052,7 +11081,10 @@ indirect_thunk_name (char name[32], int regno, bool need_bnd_p)
315 bnd, reg_prefix, reg_names[regno]);
316 }
317 else
318- sprintf (name, "__x86_indirect_thunk%s", bnd);
319+ {
320+ const char *ret = ret_p ? "return" : "indirect";
321+ sprintf (name, "__x86_%s_thunk%s", ret, bnd);
322+ }
323 }
324 else
325 {
326@@ -11065,10 +11097,20 @@ indirect_thunk_name (char name[32], int regno, bool need_bnd_p)
327 }
328 else
329 {
330- if (need_bnd_p)
331- ASM_GENERATE_INTERNAL_LABEL (name, "LITB", 0);
332+ if (ret_p)
333+ {
334+ if (need_bnd_p)
335+ ASM_GENERATE_INTERNAL_LABEL (name, "LRTB", 0);
336+ else
337+ ASM_GENERATE_INTERNAL_LABEL (name, "LRT", 0);
338+ }
339 else
340- ASM_GENERATE_INTERNAL_LABEL (name, "LIT", 0);
341+ {
342+ if (need_bnd_p)
343+ ASM_GENERATE_INTERNAL_LABEL (name, "LITB", 0);
344+ else
345+ ASM_GENERATE_INTERNAL_LABEL (name, "LIT", 0);
346+ }
347 }
348 }
349 }
350@@ -11163,7 +11205,7 @@ output_indirect_thunk_function (bool need_bnd_p, int regno)
351 tree decl;
352
353 /* Create __x86_indirect_thunk/__x86_indirect_thunk_bnd. */
354- indirect_thunk_name (name, regno, need_bnd_p);
355+ indirect_thunk_name (name, regno, need_bnd_p, false);
356 decl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL,
357 get_identifier (name),
358 build_function_type_list (void_type_node, NULL_TREE));
359@@ -11206,6 +11248,36 @@ output_indirect_thunk_function (bool need_bnd_p, int regno)
360 ASM_OUTPUT_LABEL (asm_out_file, name);
361 }
362
363+ if (regno < 0)
364+ {
365+ /* Create alias for __x86.return_thunk/__x86.return_thunk_bnd. */
366+ char alias[32];
367+
368+ indirect_thunk_name (alias, regno, need_bnd_p, true);
369+#if TARGET_MACHO
370+ if (TARGET_MACHO)
371+ {
372+ fputs ("\t.weak_definition\t", asm_out_file);
373+ assemble_name (asm_out_file, alias);
374+ fputs ("\n\t.private_extern\t", asm_out_file);
375+ assemble_name (asm_out_file, alias);
376+ putc ('\n', asm_out_file);
377+ ASM_OUTPUT_LABEL (asm_out_file, alias);
378+ }
379+#else
380+ ASM_OUTPUT_DEF (asm_out_file, alias, name);
381+ if (USE_HIDDEN_LINKONCE)
382+ {
383+ fputs ("\t.globl\t", asm_out_file);
384+ assemble_name (asm_out_file, alias);
385+ putc ('\n', asm_out_file);
386+ fputs ("\t.hidden\t", asm_out_file);
387+ assemble_name (asm_out_file, alias);
388+ putc ('\n', asm_out_file);
389+ }
390+#endif
391+ }
392+
393 DECL_INITIAL (decl) = make_node (BLOCK);
394 current_function_decl = decl;
395 allocate_struct_function (decl, false);
396@@ -27687,7 +27759,7 @@ ix86_output_indirect_branch_via_reg (rtx call_op, bool sibcall_p)
397 else
398 indirect_thunks_used |= 1 << i;
399 }
400- indirect_thunk_name (thunk_name_buf, regno, need_bnd_p);
401+ indirect_thunk_name (thunk_name_buf, regno, need_bnd_p, false);
402 thunk_name = thunk_name_buf;
403 }
404 else
405@@ -27796,7 +27868,7 @@ ix86_output_indirect_branch_via_push (rtx call_op, const char *xasm,
406 else
407 indirect_thunk_needed = true;
408 }
409- indirect_thunk_name (thunk_name_buf, regno, need_bnd_p);
410+ indirect_thunk_name (thunk_name_buf, regno, need_bnd_p, false);
411 thunk_name = thunk_name_buf;
412 }
413 else
414@@ -27931,6 +28003,46 @@ ix86_output_indirect_jmp (rtx call_op, bool ret_p)
415 return "%!jmp\t%A0";
416 }
417
418+/* Output function return. CALL_OP is the jump target. Add a REP
419+ prefix to RET if LONG_P is true and function return is kept. */
420+
421+const char *
422+ix86_output_function_return (bool long_p)
423+{
424+ if (cfun->machine->function_return_type != indirect_branch_keep)
425+ {
426+ char thunk_name[32];
427+ bool need_bnd_p = ix86_bnd_prefixed_insn_p (current_output_insn);
428+
429+ if (cfun->machine->function_return_type
430+ != indirect_branch_thunk_inline)
431+ {
432+ bool need_thunk = (cfun->machine->function_return_type
433+ == indirect_branch_thunk);
434+ indirect_thunk_name (thunk_name, -1, need_bnd_p, true);
435+ if (need_bnd_p)
436+ {
437+ indirect_thunk_bnd_needed |= need_thunk;
438+ fprintf (asm_out_file, "\tbnd jmp\t%s\n", thunk_name);
439+ }
440+ else
441+ {
442+ indirect_thunk_needed |= need_thunk;
443+ fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name);
444+ }
445+ }
446+ else
447+ output_indirect_thunk (need_bnd_p, -1);
448+
449+ return "";
450+ }
451+
452+ if (!long_p || ix86_bnd_prefixed_insn_p (current_output_insn))
453+ return "%!ret";
454+
455+ return "rep%; ret";
456+}
457+
458 /* Output the assembly for a call instruction. */
459
460 const char *
461@@ -45461,6 +45573,28 @@ ix86_handle_fndecl_attribute (tree *node, tree name, tree args, int,
462 }
463 }
464
465+ if (is_attribute_p ("function_return", name))
466+ {
467+ tree cst = TREE_VALUE (args);
468+ if (TREE_CODE (cst) != STRING_CST)
469+ {
470+ warning (OPT_Wattributes,
471+ "%qE attribute requires a string constant argument",
472+ name);
473+ *no_add_attrs = true;
474+ }
475+ else if (strcmp (TREE_STRING_POINTER (cst), "keep") != 0
476+ && strcmp (TREE_STRING_POINTER (cst), "thunk") != 0
477+ && strcmp (TREE_STRING_POINTER (cst), "thunk-inline") != 0
478+ && strcmp (TREE_STRING_POINTER (cst), "thunk-extern") != 0)
479+ {
480+ warning (OPT_Wattributes,
481+ "argument to %qE attribute is not "
482+ "(keep|thunk|thunk-inline|thunk-extern)", name);
483+ *no_add_attrs = true;
484+ }
485+ }
486+
487 return NULL_TREE;
488 }
489
490@@ -49690,6 +49824,8 @@ static const struct attribute_spec ix86_attribute_table[] =
491 ix86_handle_callee_pop_aggregate_return, true },
492 { "indirect_branch", 1, 1, true, false, false,
493 ix86_handle_fndecl_attribute, false },
494+ { "function_return", 1, 1, true, false, false,
495+ ix86_handle_fndecl_attribute, false },
496
497 /* End element. */
498 { NULL, 0, 0, false, false, false, NULL, false }
499diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
500index 9dccdb0..b34bc11 100644
501--- a/gcc/config/i386/i386.h
502+++ b/gcc/config/i386/i386.h
503@@ -2579,6 +2579,9 @@ struct GTY(()) machine_function {
504 "indirect_jump" or "tablejump". */
505 BOOL_BITFIELD has_local_indirect_jump : 1;
506
507+ /* How to generate function return. */
508+ ENUM_BITFIELD(indirect_branch) function_return_type : 3;
509+
510 /* If true, there is register available for argument passing. This
511 is used only in ix86_function_ok_for_sibcall by 32-bit to determine
512 if there is scratch register available for indirect sibcall. In
513diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
514index 153e162..2da671e 100644
515--- a/gcc/config/i386/i386.md
516+++ b/gcc/config/i386/i386.md
517@@ -12489,7 +12489,7 @@
518 (define_insn "simple_return_internal"
519 [(simple_return)]
520 "reload_completed"
521- "%!ret"
522+ "* return ix86_output_function_return (false);"
523 [(set_attr "length" "1")
524 (set_attr "atom_unit" "jeu")
525 (set_attr "length_immediate" "0")
526@@ -12503,12 +12503,7 @@
527 [(simple_return)
528 (unspec [(const_int 0)] UNSPEC_REP)]
529 "reload_completed"
530-{
531- if (ix86_bnd_prefixed_insn_p (insn))
532- return "%!ret";
533-
534- return "rep%; ret";
535-}
536+ "* return ix86_output_function_return (true);"
537 [(set_attr "length" "2")
538 (set_attr "atom_unit" "jeu")
539 (set_attr "length_immediate" "0")
540diff --git a/gcc/config/i386/i386.opt b/gcc/config/i386/i386.opt
541index 5ffa334..ad5916f 100644
542--- a/gcc/config/i386/i386.opt
543+++ b/gcc/config/i386/i386.opt
544@@ -902,9 +902,13 @@ mindirect-branch=
545 Target Report RejectNegative Joined Enum(indirect_branch) Var(ix86_indirect_branch) Init(indirect_branch_keep)
546 Convert indirect call and jump to call and return thunks.
547
548+mfunction-return=
549+Target Report RejectNegative Joined Enum(indirect_branch) Var(ix86_function_return) Init(indirect_branch_keep)
550+Convert function return to call and return thunk.
551+
552 Enum
553 Name(indirect_branch) Type(enum indirect_branch)
554-Known indirect branch choices (for use with the -mindirect-branch= option):
555+Known indirect branch choices (for use with the -mindirect-branch=/-mfunction-return= options):
556
557 EnumValue
558 Enum(indirect_branch) String(keep) Value(indirect_branch_keep)
559diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
560index 8668dae..2cb6bd1 100644
561--- a/gcc/doc/extend.texi
562+++ b/gcc/doc/extend.texi
563@@ -5429,6 +5429,15 @@ call and jump to call and return thunk. @samp{thunk-inline} converts
564 indirect call and jump to inlined call and return thunk.
565 @samp{thunk-extern} converts indirect call and jump to external call
566 and return thunk provided in a separate object file.
567+
568+@item function_return("@var{choice}")
569+@cindex @code{function_return} function attribute, x86
570+On x86 targets, the @code{function_return} attribute causes the compiler
571+to convert function return with @var{choice}. @samp{keep} keeps function
572+return unmodified. @samp{thunk} converts function return to call and
573+return thunk. @samp{thunk-inline} converts function return to inlined
574+call and return thunk. @samp{thunk-extern} converts function return to
575+external call and return thunk provided in a separate object file.
576 @end table
577
578 On the x86, the inliner does not inline a
579diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
580index ff9a194..fa63dc5 100644
581--- a/gcc/doc/invoke.texi
582+++ b/gcc/doc/invoke.texi
583@@ -1169,7 +1169,8 @@ See RS/6000 and PowerPC Options.
584 -msse2avx -mfentry -mrecord-mcount -mnop-mcount -m8bit-idiv @gol
585 -mavx256-split-unaligned-load -mavx256-split-unaligned-store @gol
586 -malign-data=@var{type} -mstack-protector-guard=@var{guard} @gol
587--mmitigate-rop -mindirect-branch=@var{choice}}
588+-mmitigate-rop -mindirect-branch=@var{choice} @gol
589+-mfunction-return=@var{choice}}
590
591 @emph{x86 Windows Options}
592 @gccoptlist{-mconsole -mcygwin -mno-cygwin -mdll @gol
593@@ -24229,6 +24230,17 @@ to external call and return thunk provided in a separate object file.
594 You can control this behavior for a specific function by using the
595 function attribute @code{indirect_branch}. @xref{Function Attributes}.
596
597+@item -mfunction-return=@var{choice}
598+@opindex -mfunction-return
599+Convert function return with @var{choice}. The default is @samp{keep},
600+which keeps function return unmodified. @samp{thunk} converts function
601+return to call and return thunk. @samp{thunk-inline} converts function
602+return to inlined call and return thunk. @samp{thunk-extern} converts
603+function return to external call and return thunk provided in a separate
604+object file. You can control this behavior for a specific function by
605+using the function attribute @code{function_return}.
606+@xref{Function Attributes}.
607+
608 @end table
609
610 These @samp{-m} switches are supported in addition to the above
611diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c
612index d983e1c..e365ef5 100644
613--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c
614+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c
615@@ -1,5 +1,5 @@
616 /* { dg-do compile } */
617-/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
618+/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
619
620 typedef void (*dispatch_t)(long offset);
621
622@@ -11,7 +11,7 @@ male_indirect_jump (long offset)
623 dispatch(offset);
624 }
625
626-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
627+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
628 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
629 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
630 /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
631diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c
632index 58f09b4..05a51ad 100644
633--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c
634+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c
635@@ -1,5 +1,5 @@
636 /* { dg-do compile } */
637-/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
638+/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
639
640 typedef void (*dispatch_t)(long offset);
641
642@@ -11,7 +11,7 @@ male_indirect_jump (long offset)
643 dispatch[offset](offset);
644 }
645
646-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
647+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
648 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
649 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
650 /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
651diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c
652index f20d35c..3c0d4c3 100644
653--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c
654+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c
655@@ -1,5 +1,5 @@
656 /* { dg-do compile } */
657-/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
658+/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
659
660 typedef void (*dispatch_t)(long offset);
661
662@@ -12,7 +12,7 @@ male_indirect_jump (long offset)
663 return 0;
664 }
665
666-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
667+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
668 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
669 /* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
670 /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
671diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c
672index 0eff8fb..14d4ef6 100644
673--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c
674+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c
675@@ -1,5 +1,5 @@
676 /* { dg-do compile } */
677-/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
678+/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
679
680 typedef void (*dispatch_t)(long offset);
681
682@@ -12,7 +12,7 @@ male_indirect_jump (long offset)
683 return 0;
684 }
685
686-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
687+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
688 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
689 /* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
690 /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
691diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c
692index a25b20d..b4836c3 100644
693--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c
694+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c
695@@ -1,5 +1,5 @@
696 /* { dg-do compile { target *-*-linux* } } */
697-/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk" } */
698+/* { dg-options "-O2 -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk" } */
699
700 extern void bar (void);
701
702diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c
703index cff114a..1f06bd1 100644
704--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c
705+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c
706@@ -1,5 +1,5 @@
707 /* { dg-do compile { target *-*-linux* } } */
708-/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk" } */
709+/* { dg-options "-O2 -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk" } */
710
711 extern void bar (void);
712
713diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c
714index afdb600..bc6b47a 100644
715--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c
716+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c
717@@ -1,5 +1,5 @@
718 /* { dg-do compile } */
719-/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
720+/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
721
722 void func0 (void);
723 void func1 (void);
724@@ -35,7 +35,7 @@ bar (int i)
725 }
726 }
727
728-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { ! x32 } } } } */
729+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { { ! x32 } && *-*-linux* } } } } */
730 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
731 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
732 /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
733diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c
734index d64d978..2257be3 100644
735--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c
736+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c
737@@ -1,5 +1,5 @@
738 /* { dg-do compile } */
739-/* { dg-options "-O2 -fno-pic" } */
740+/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
741
742 typedef void (*dispatch_t)(long offset);
743
744@@ -14,7 +14,7 @@ male_indirect_jump (long offset)
745 dispatch(offset);
746 }
747
748-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
749+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
750 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
751 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
752 /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
753diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c
754index 9306745..e9cfdc5 100644
755--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c
756+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c
757@@ -1,5 +1,5 @@
758 /* { dg-do compile } */
759-/* { dg-options "-O2 -fno-pic" } */
760+/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
761
762 typedef void (*dispatch_t)(long offset);
763
764@@ -12,7 +12,7 @@ male_indirect_jump (long offset)
765 dispatch[offset](offset);
766 }
767
768-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
769+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
770 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
771 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
772 /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
773diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c
774index 97744d6..f938db0 100644
775--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c
776+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c
777@@ -1,5 +1,5 @@
778 /* { dg-do compile } */
779-/* { dg-options "-O2 -fno-pic" } */
780+/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
781
782 typedef void (*dispatch_t)(long offset);
783
784@@ -14,7 +14,7 @@ male_indirect_jump (long offset)
785 return 0;
786 }
787
788-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
789+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
790 /* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */
791 /* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */
792 /* { dg-final { scan-assembler {\tpause} } } */
793diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c
794index bfce3ea..4e58599 100644
795--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c
796+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c
797@@ -1,5 +1,5 @@
798 /* { dg-do compile } */
799-/* { dg-options "-O2 -fno-pic" } */
800+/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
801
802 typedef void (*dispatch_t)(long offset);
803
804@@ -13,7 +13,7 @@ male_indirect_jump (long offset)
805 return 0;
806 }
807
808-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
809+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
810 /* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */
811 /* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */
812 /* { dg-final { scan-assembler {\tpause} } } */
813diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c
814index 0833606..b8d5024 100644
815--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c
816+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c
817@@ -1,5 +1,5 @@
818 /* { dg-do compile } */
819-/* { dg-options "-O2 -fno-pic" } */
820+/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
821
822 typedef void (*dispatch_t)(long offset);
823
824@@ -14,7 +14,7 @@ male_indirect_jump (long offset)
825 return 0;
826 }
827
828-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
829+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
830 /* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
831 /* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
832 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
833diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c
834index 2eba0fb..455adab 100644
835--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c
836+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c
837@@ -1,5 +1,5 @@
838 /* { dg-do compile } */
839-/* { dg-options "-O2 -fno-pic" } */
840+/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
841
842 typedef void (*dispatch_t)(long offset);
843
844@@ -13,7 +13,7 @@ male_indirect_jump (long offset)
845 return 0;
846 }
847
848-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
849+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
850 /* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
851 /* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
852 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
853diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c
854index f58427e..4595b84 100644
855--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c
856+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c
857@@ -1,5 +1,5 @@
858 /* { dg-do compile } */
859-/* { dg-options "-O2 -fno-pic" } */
860+/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
861
862 void func0 (void);
863 void func1 (void);
864@@ -36,7 +36,7 @@ bar (int i)
865 }
866 }
867
868-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { ! x32 } } } } */
869+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { { ! x32 } && *-*-linux* } } } } */
870 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
871 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" } } */
872 /* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
873diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c
874index 564ed39..d730d31 100644
875--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c
876+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c
877@@ -1,5 +1,5 @@
878 /* { dg-do compile } */
879-/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
880+/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
881
882 void func0 (void);
883 void func1 (void);
884diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c
885index 50fbee2..5e3e118 100644
886--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c
887+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c
888@@ -1,5 +1,5 @@
889 /* { dg-do compile { target { ! x32 } } } */
890-/* { dg-options "-O2 -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
891+/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
892
893 void (*dispatch) (char *);
894 char buf[10];
895@@ -10,7 +10,7 @@ foo (void)
896 dispatch (buf);
897 }
898
899-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
900+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
901 /* { dg-final { scan-assembler "pushq\[ \t\]%rax" { target x32 } } } */
902 /* { dg-final { scan-assembler "bnd jmp\[ \t\]*__x86_indirect_thunk_bnd" } } */
903 /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
904diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c
905index 2976e67..2801aa4 100644
906--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c
907+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c
908@@ -1,5 +1,5 @@
909 /* { dg-do compile { target { ! x32 } } } */
910-/* { dg-options "-O2 -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
911+/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
912
913 void (*dispatch) (char *);
914 char buf[10];
915@@ -11,7 +11,7 @@ foo (void)
916 return 0;
917 }
918
919-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
920+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
921 /* { dg-final { scan-assembler "pushq\[ \t\]%rax" { target x32 } } } */
922 /* { dg-final { scan-assembler "bnd jmp\[ \t\]*__x86_indirect_thunk_bnd" } } */
923 /* { dg-final { scan-assembler "bnd jmp\[ \t\]*\.LIND" } } */
924diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c
925index da4bc98..70b4fb3 100644
926--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c
927+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c
928@@ -1,5 +1,5 @@
929 /* { dg-do compile { target { *-*-linux* && { ! x32 } } } } */
930-/* { dg-options "-O2 -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fpic -fno-plt" } */
931+/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fpic -fno-plt" } */
932
933 void bar (char *);
934 char buf[10];
935diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c
936index c64d12e..3baf03e 100644
937--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c
938+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c
939@@ -1,5 +1,5 @@
940 /* { dg-do compile { target { *-*-linux* && { ! x32 } } } } */
941-/* { dg-options "-O2 -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fpic -fno-plt" } */
942+/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fpic -fno-plt" } */
943
944 void bar (char *);
945 char buf[10];
946diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c
947index 49f27b4..edeb264 100644
948--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c
949+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c
950@@ -1,5 +1,5 @@
951 /* { dg-do compile } */
952-/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */
953+/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
954
955 typedef void (*dispatch_t)(long offset);
956
957@@ -11,7 +11,7 @@ male_indirect_jump (long offset)
958 dispatch(offset);
959 }
960
961-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
962+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
963 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
964 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
965 /* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
966diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c
967index a1e3eb6..1d00413 100644
968--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c
969+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c
970@@ -1,5 +1,5 @@
971 /* { dg-do compile } */
972-/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */
973+/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
974
975 typedef void (*dispatch_t)(long offset);
976
977@@ -11,7 +11,7 @@ male_indirect_jump (long offset)
978 dispatch[offset](offset);
979 }
980
981-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
982+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
983 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
984 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
985 /* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
986diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c
987index 395634e..06ebf1c 100644
988--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c
989+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c
990@@ -1,5 +1,5 @@
991 /* { dg-do compile } */
992-/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */
993+/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
994
995 typedef void (*dispatch_t)(long offset);
996
997@@ -12,7 +12,7 @@ male_indirect_jump (long offset)
998 return 0;
999 }
1000
1001-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1002+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
1003 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1004 /* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
1005 /* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
1006diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c
1007index fd3f633..1c8f944 100644
1008--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c
1009+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c
1010@@ -1,5 +1,5 @@
1011 /* { dg-do compile } */
1012-/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */
1013+/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
1014
1015 typedef void (*dispatch_t)(long offset);
1016
1017@@ -12,7 +12,7 @@ male_indirect_jump (long offset)
1018 return 0;
1019 }
1020
1021-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1022+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
1023 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1024 /* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
1025 /* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
1026diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c
1027index ba2f92b..21740ac 100644
1028--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c
1029+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c
1030@@ -1,5 +1,5 @@
1031 /* { dg-do compile { target *-*-linux* } } */
1032-/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk-extern" } */
1033+/* { dg-options "-O2 -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk-extern" } */
1034
1035 extern void bar (void);
1036
1037diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c
1038index 0c5a2d4..a77c1f4 100644
1039--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c
1040+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c
1041@@ -1,5 +1,5 @@
1042 /* { dg-do compile { target *-*-linux* } } */
1043-/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk-extern" } */
1044+/* { dg-options "-O2 -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk-extern" } */
1045
1046 extern void bar (void);
1047
1048diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c
1049index 6652523..86e9fd1 100644
1050--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c
1051+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c
1052@@ -1,5 +1,5 @@
1053 /* { dg-do compile } */
1054-/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */
1055+/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
1056
1057 void func0 (void);
1058 void func1 (void);
1059@@ -35,7 +35,7 @@ bar (int i)
1060 }
1061 }
1062
1063-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { ! x32 } } } } */
1064+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { { ! x32 } && *-*-linux* } } } } */
1065 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1066 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1067 /* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
1068diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c
1069index 68c0ff7..3ecde87 100644
1070--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c
1071+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c
1072@@ -1,5 +1,5 @@
1073 /* { dg-do compile } */
1074-/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */
1075+/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
1076
1077 typedef void (*dispatch_t)(long offset);
1078
1079@@ -11,7 +11,7 @@ male_indirect_jump (long offset)
1080 dispatch(offset);
1081 }
1082
1083-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1084+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
1085 /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1086 /* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1087 /* { dg-final { scan-assembler {\tpause} } } */
1088diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c
1089index e2da1fc..df32a19 100644
1090--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c
1091+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c
1092@@ -1,5 +1,5 @@
1093 /* { dg-do compile } */
1094-/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */
1095+/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
1096
1097 typedef void (*dispatch_t)(long offset);
1098
1099@@ -11,7 +11,7 @@ male_indirect_jump (long offset)
1100 dispatch[offset](offset);
1101 }
1102
1103-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1104+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
1105 /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1106 /* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1107 /* { dg-final { scan-assembler {\tpause} } } */
1108diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c
1109index 244fec7..9540996 100644
1110--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c
1111+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c
1112@@ -1,5 +1,5 @@
1113 /* { dg-do compile } */
1114-/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */
1115+/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
1116
1117 typedef void (*dispatch_t)(long offset);
1118
1119@@ -12,7 +12,7 @@ male_indirect_jump (long offset)
1120 return 0;
1121 }
1122
1123-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1124+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
1125 /* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */
1126 /* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */
1127 /* { dg-final { scan-assembler-times {\tpause} 1 } } */
1128diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c
1129index 107ebe3..f3db6e2 100644
1130--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c
1131+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c
1132@@ -1,5 +1,5 @@
1133 /* { dg-do compile } */
1134-/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */
1135+/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
1136
1137 typedef void (*dispatch_t)(long offset);
1138
1139@@ -12,7 +12,7 @@ male_indirect_jump (long offset)
1140 return 0;
1141 }
1142
1143-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1144+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
1145 /* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */
1146 /* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */
1147 /* { dg-final { scan-assembler-times {\tpause} 1 } } */
1148diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c
1149index 17b04ef..0f687c3 100644
1150--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c
1151+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c
1152@@ -1,5 +1,5 @@
1153 /* { dg-do compile { target *-*-linux* } } */
1154-/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk-inline" } */
1155+/* { dg-options "-O2 -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk-inline" } */
1156
1157 extern void bar (void);
1158
1159diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c
1160index d9eb112..b27c6fc 100644
1161--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c
1162+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c
1163@@ -1,5 +1,5 @@
1164 /* { dg-do compile { target *-*-linux* } } */
1165-/* { dg-options "-O2 -fpic -fno-plt -mindirect-branch=thunk-inline" } */
1166+/* { dg-options "-O2 -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk-inline" } */
1167
1168 extern void bar (void);
1169
1170diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c
1171index d02b1dc..764a375 100644
1172--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c
1173+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c
1174@@ -1,5 +1,5 @@
1175 /* { dg-do compile } */
1176-/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */
1177+/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
1178
1179 void func0 (void);
1180 void func1 (void);
1181@@ -35,7 +35,7 @@ bar (int i)
1182 }
1183 }
1184
1185-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { ! x32 } } } } */
1186+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { { ! x32 } && *-*-linux* } } } } */
1187 /* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
1188 /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1189 /* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1190diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-1.c b/gcc/testsuite/gcc.target/i386/ret-thunk-1.c
1191new file mode 100644
1192index 0000000..7223f67
1193--- /dev/null
1194+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-1.c
1195@@ -0,0 +1,13 @@
1196+/* { dg-do compile } */
1197+/* { dg-options "-O2 -mfunction-return=thunk" } */
1198+
1199+void
1200+foo (void)
1201+{
1202+}
1203+
1204+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk" } } */
1205+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1206+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1207+/* { dg-final { scan-assembler {\tpause} } } */
1208+/* { dg-final { scan-assembler {\tlfence} } } */
1209diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-10.c b/gcc/testsuite/gcc.target/i386/ret-thunk-10.c
1210new file mode 100644
1211index 0000000..3a6727b
1212--- /dev/null
1213+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-10.c
1214@@ -0,0 +1,23 @@
1215+/* { dg-do compile } */
1216+/* { dg-options "-O2 -mfunction-return=thunk-inline -mindirect-branch=thunk -fno-pic" } */
1217+
1218+extern void (*bar) (void);
1219+
1220+int
1221+foo (void)
1222+{
1223+ bar ();
1224+ return 0;
1225+}
1226+
1227+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1228+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1229+/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_return_thunk" } } */
1230+/* { dg-final { scan-assembler-times {\tpause} 2 } } */
1231+/* { dg-final { scan-assembler-times {\tlfence} 2 } } */
1232+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { { ! x32 } && *-*-linux* } } } } */
1233+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1234+/* { dg-final { scan-assembler "__x86_indirect_thunk:" { target { ! x32 } } } } */
1235+/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target { x32 } } } } */
1236+/* { dg-final { scan-assembler "__x86_indirect_thunk_(r|e)ax:" { target { x32 } } } } */
1237+/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
1238diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-11.c b/gcc/testsuite/gcc.target/i386/ret-thunk-11.c
1239new file mode 100644
1240index 0000000..b8f6818
1241--- /dev/null
1242+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-11.c
1243@@ -0,0 +1,23 @@
1244+/* { dg-do compile } */
1245+/* { dg-options "-O2 -mfunction-return=thunk-extern -mindirect-branch=thunk -fno-pic" } */
1246+
1247+extern void (*bar) (void);
1248+
1249+int
1250+foo (void)
1251+{
1252+ bar ();
1253+ return 0;
1254+}
1255+
1256+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk" } } */
1257+/* { dg-final { scan-assembler-times {\tpause} 1 } } */
1258+/* { dg-final { scan-assembler-times {\tlfence} 1 } } */
1259+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1260+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1261+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { { ! x32 } && *-*-linux* } } } } */
1262+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1263+/* { dg-final { scan-assembler "__x86_indirect_thunk:" { target { ! x32 } } } } */
1264+/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target { x32 } } } } */
1265+/* { dg-final { scan-assembler "__x86_indirect_thunk_(r|e)ax:" { target { x32 } } } } */
1266+/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
1267diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-12.c b/gcc/testsuite/gcc.target/i386/ret-thunk-12.c
1268new file mode 100644
1269index 0000000..01b0a02
1270--- /dev/null
1271+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-12.c
1272@@ -0,0 +1,22 @@
1273+/* { dg-do compile } */
1274+/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
1275+
1276+extern void (*bar) (void);
1277+
1278+int
1279+foo (void)
1280+{
1281+ bar ();
1282+ return 0;
1283+}
1284+
1285+/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_return_thunk" } } */
1286+/* { dg-final { scan-assembler-times {\tpause} 1 } } */
1287+/* { dg-final { scan-assembler-times {\tlfence} 1 } } */
1288+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1289+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1290+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1291+/* { dg-final { scan-assembler "__x86_indirect_thunk:" { target { ! x32 } } } } */
1292+/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target { x32 } } } } */
1293+/* { dg-final { scan-assembler "__x86_indirect_thunk_(r|e)ax:" { target { x32 } } } } */
1294+/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
1295diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-13.c b/gcc/testsuite/gcc.target/i386/ret-thunk-13.c
1296new file mode 100644
1297index 0000000..4b497b5
1298--- /dev/null
1299+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-13.c
1300@@ -0,0 +1,22 @@
1301+/* { dg-do compile } */
1302+/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
1303+
1304+extern void (*bar) (void);
1305+extern int foo (void) __attribute__ ((function_return("thunk")));
1306+
1307+int
1308+foo (void)
1309+{
1310+ bar ();
1311+ return 0;
1312+}
1313+
1314+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk" } } */
1315+/* { dg-final { scan-assembler-times {\tpause} 2 } } */
1316+/* { dg-final { scan-assembler-times {\tlfence} 2 } } */
1317+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { { ! x32 } && *-*-linux* } } } } */
1318+/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 3 } } */
1319+/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 3 } } */
1320+/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_indirect_thunk" } } */
1321+/* { dg-final { scan-assembler-not "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target { x32 } } } } */
1322+/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
1323diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-14.c b/gcc/testsuite/gcc.target/i386/ret-thunk-14.c
1324new file mode 100644
1325index 0000000..4ae4c44
1326--- /dev/null
1327+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-14.c
1328@@ -0,0 +1,22 @@
1329+/* { dg-do compile } */
1330+/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
1331+
1332+extern void (*bar) (void);
1333+
1334+__attribute__ ((function_return("thunk-inline")))
1335+int
1336+foo (void)
1337+{
1338+ bar ();
1339+ return 0;
1340+}
1341+
1342+/* { dg-final { scan-assembler-times {\tpause} 1 } } */
1343+/* { dg-final { scan-assembler-times {\tlfence} 1 } } */
1344+/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_return_thunk" } } */
1345+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1346+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1347+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { { ! x32 } && *-*-linux* } } } } */
1348+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1349+/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target { x32 } } } } */
1350+/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
1351diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-15.c b/gcc/testsuite/gcc.target/i386/ret-thunk-15.c
1352new file mode 100644
1353index 0000000..5b5bc76
1354--- /dev/null
1355+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-15.c
1356@@ -0,0 +1,22 @@
1357+/* { dg-do compile } */
1358+/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=keep -fno-pic" } */
1359+
1360+extern void (*bar) (void);
1361+
1362+__attribute__ ((function_return("thunk-extern"), indirect_branch("thunk")))
1363+int
1364+foo (void)
1365+{
1366+ bar ();
1367+ return 0;
1368+}
1369+
1370+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk" } } */
1371+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1372+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1373+/* { dg-final { scan-assembler-times {\tpause} 1 } } */
1374+/* { dg-final { scan-assembler-times {\tlfence} 1 } } */
1375+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { { ! x32 } && *-*-linux* } } } } */
1376+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1377+/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1378+/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
1379diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-16.c b/gcc/testsuite/gcc.target/i386/ret-thunk-16.c
1380new file mode 100644
1381index 0000000..a16cad1
1382--- /dev/null
1383+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-16.c
1384@@ -0,0 +1,18 @@
1385+/* { dg-do compile } */
1386+/* { dg-options "-O2 -mfunction-return=thunk-inline -mindirect-branch=thunk-extern -fno-pic" } */
1387+
1388+extern void (*bar) (void);
1389+
1390+__attribute__ ((function_return("keep"), indirect_branch("keep")))
1391+int
1392+foo (void)
1393+{
1394+ bar ();
1395+ return 0;
1396+}
1397+
1398+/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
1399+/* { dg-final { scan-assembler-not "__x86_return_thunk" } } */
1400+/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
1401+/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
1402+/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
1403diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-2.c b/gcc/testsuite/gcc.target/i386/ret-thunk-2.c
1404new file mode 100644
1405index 0000000..c6659e3
1406--- /dev/null
1407+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-2.c
1408@@ -0,0 +1,13 @@
1409+/* { dg-do compile } */
1410+/* { dg-options "-O2 -mfunction-return=thunk-inline" } */
1411+
1412+void
1413+foo (void)
1414+{
1415+}
1416+
1417+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1418+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1419+/* { dg-final { scan-assembler {\tpause} } } */
1420+/* { dg-final { scan-assembler {\tlfence} } } */
1421+/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_return_thunk" } } */
1422diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-3.c b/gcc/testsuite/gcc.target/i386/ret-thunk-3.c
1423new file mode 100644
1424index 0000000..0f7f388
1425--- /dev/null
1426+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-3.c
1427@@ -0,0 +1,12 @@
1428+/* { dg-do compile } */
1429+/* { dg-options "-O2 -mfunction-return=thunk-extern" } */
1430+
1431+void
1432+foo (void)
1433+{
1434+}
1435+
1436+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk" } } */
1437+/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
1438+/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
1439+/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
1440diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-4.c b/gcc/testsuite/gcc.target/i386/ret-thunk-4.c
1441new file mode 100644
1442index 0000000..9ae37e8
1443--- /dev/null
1444+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-4.c
1445@@ -0,0 +1,12 @@
1446+/* { dg-do compile } */
1447+/* { dg-options "-O2 -mfunction-return=keep" } */
1448+
1449+void
1450+foo (void)
1451+{
1452+}
1453+
1454+/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_return_thunk" } } */
1455+/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
1456+/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
1457+/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
1458diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-5.c b/gcc/testsuite/gcc.target/i386/ret-thunk-5.c
1459new file mode 100644
1460index 0000000..4bd0d2a
1461--- /dev/null
1462+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-5.c
1463@@ -0,0 +1,15 @@
1464+/* { dg-do compile } */
1465+/* { dg-options "-O2 -mfunction-return=keep" } */
1466+
1467+extern void foo (void) __attribute__ ((function_return("thunk")));
1468+
1469+void
1470+foo (void)
1471+{
1472+}
1473+
1474+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk" } } */
1475+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1476+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1477+/* { dg-final { scan-assembler {\tpause} } } */
1478+/* { dg-final { scan-assembler {\tlfence} } } */
1479diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-6.c b/gcc/testsuite/gcc.target/i386/ret-thunk-6.c
1480new file mode 100644
1481index 0000000..053841f
1482--- /dev/null
1483+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-6.c
1484@@ -0,0 +1,14 @@
1485+/* { dg-do compile } */
1486+/* { dg-options "-O2 -mfunction-return=keep" } */
1487+
1488+__attribute__ ((function_return("thunk-inline")))
1489+void
1490+foo (void)
1491+{
1492+}
1493+
1494+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1495+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1496+/* { dg-final { scan-assembler {\tpause} } } */
1497+/* { dg-final { scan-assembler {\tlfence} } } */
1498+/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_return_thunk" } } */
1499diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-7.c b/gcc/testsuite/gcc.target/i386/ret-thunk-7.c
1500new file mode 100644
1501index 0000000..262e678
1502--- /dev/null
1503+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-7.c
1504@@ -0,0 +1,13 @@
1505+/* { dg-do compile } */
1506+/* { dg-options "-O2 -mfunction-return=keep" } */
1507+
1508+__attribute__ ((function_return("thunk-extern")))
1509+void
1510+foo (void)
1511+{
1512+}
1513+
1514+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk" } } */
1515+/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
1516+/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
1517+/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
1518diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-8.c b/gcc/testsuite/gcc.target/i386/ret-thunk-8.c
1519new file mode 100644
1520index 0000000..c1658e9
1521--- /dev/null
1522+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-8.c
1523@@ -0,0 +1,14 @@
1524+/* { dg-do compile } */
1525+/* { dg-options "-O2 -mfunction-return=thunk-inline" } */
1526+
1527+extern void foo (void) __attribute__ ((function_return("keep")));
1528+
1529+void
1530+foo (void)
1531+{
1532+}
1533+
1534+/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_return_thunk" } } */
1535+/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
1536+/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
1537+/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
1538diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-9.c b/gcc/testsuite/gcc.target/i386/ret-thunk-9.c
1539new file mode 100644
1540index 0000000..fa24a1f
1541--- /dev/null
1542+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-9.c
1543@@ -0,0 +1,24 @@
1544+/* { dg-do compile } */
1545+/* { dg-options "-O2 -mfunction-return=thunk -mindirect-branch=thunk -fno-pic" } */
1546+
1547+extern void (*bar) (void);
1548+
1549+int
1550+foo (void)
1551+{
1552+ bar ();
1553+ return 0;
1554+}
1555+
1556+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk" } } */
1557+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1558+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1559+/* { dg-final { scan-assembler "__x86_indirect_thunk:" } } */
1560+/* { dg-final { scan-assembler-times {\tpause} 1 { target { ! x32 } } } } */
1561+/* { dg-final { scan-assembler-times {\tlfence} 1 { target { ! x32 } } } } */
1562+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { { ! x32 } && *-*-linux* } } } } */
1563+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1564+/* { dg-final { scan-assembler-times {\tpause} 2 { target { x32 } } } } */
1565+/* { dg-final { scan-assembler-times {\tlfence} 2 { target { x32 } } } } */
1566+/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target { x32 } } } } */
1567+/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
1568--
15692.7.4
1570
diff --git a/meta/recipes-devtools/gcc/gcc-6.4/backport/0006-x86-Add-mindirect-branch-register.patch b/meta/recipes-devtools/gcc/gcc-6.4/backport/0006-x86-Add-mindirect-branch-register.patch
new file mode 100644
index 0000000000..ad736913cd
--- /dev/null
+++ b/meta/recipes-devtools/gcc/gcc-6.4/backport/0006-x86-Add-mindirect-branch-register.patch
@@ -0,0 +1,946 @@
1From 3f1c39fb543884d36e759a6dc196a8e914eb4f73 Mon Sep 17 00:00:00 2001
2From: "H.J. Lu" <hjl.tools@gmail.com>
3Date: Sat, 6 Jan 2018 22:29:56 -0800
4Subject: [PATCH 06/12] x86: Add -mindirect-branch-register
5
6Add -mindirect-branch-register to force indirect branch via register.
7This is implemented by disabling patterns of indirect branch via memory,
8similar to TARGET_X32.
9
10-mindirect-branch= and -mfunction-return= tests are updated with
11-mno-indirect-branch-register to avoid false test failures when
12-mindirect-branch-register is added to RUNTESTFLAGS for "make check".
13
14gcc/
15
16 Backport from mainline
17 2018-01-14 H.J. Lu <hongjiu.lu@intel.com>
18
19 * config/i386/constraints.md (Bs): Disallow memory operand for
20 -mindirect-branch-register.
21 (Bw): Likewise.
22 * config/i386/predicates.md (indirect_branch_operand): Likewise.
23 (GOT_memory_operand): Likewise.
24 (call_insn_operand): Likewise.
25 (sibcall_insn_operand): Likewise.
26 (GOT32_symbol_operand): Likewise.
27 * config/i386/i386.md (indirect_jump): Call convert_memory_address
28 for -mindirect-branch-register.
29 (tablejump): Likewise.
30 (*sibcall_memory): Likewise.
31 (*sibcall_value_memory): Likewise.
32 Disallow peepholes of indirect call and jump via memory for
33 -mindirect-branch-register.
34 (*call_pop): Replace m with Bw.
35 (*call_value_pop): Likewise.
36 (*sibcall_pop_memory): Replace m with Bs.
37 * config/i386/i386.opt (mindirect-branch-register): New option.
38 * doc/invoke.texi: Document -mindirect-branch-register option.
39
40gcc/testsuite/
41
42 Backport from mainline
43 2018-01-14 H.J. Lu <hongjiu.lu@intel.com>
44
45 * gcc.target/i386/indirect-thunk-1.c (dg-options): Add
46 -mno-indirect-branch-register.
47 * gcc.target/i386/indirect-thunk-2.c: Likewise.
48 * gcc.target/i386/indirect-thunk-3.c: Likewise.
49 * gcc.target/i386/indirect-thunk-4.c: Likewise.
50 * gcc.target/i386/indirect-thunk-5.c: Likewise.
51 * gcc.target/i386/indirect-thunk-6.c: Likewise.
52 * gcc.target/i386/indirect-thunk-7.c: Likewise.
53 * gcc.target/i386/indirect-thunk-attr-1.c: Likewise.
54 * gcc.target/i386/indirect-thunk-attr-2.c: Likewise.
55 * gcc.target/i386/indirect-thunk-attr-3.c: Likewise.
56 * gcc.target/i386/indirect-thunk-attr-4.c: Likewise.
57 * gcc.target/i386/indirect-thunk-attr-5.c: Likewise.
58 * gcc.target/i386/indirect-thunk-attr-6.c: Likewise.
59 * gcc.target/i386/indirect-thunk-attr-7.c: Likewise.
60 * gcc.target/i386/indirect-thunk-bnd-1.c: Likewise.
61 * gcc.target/i386/indirect-thunk-bnd-2.c: Likewise.
62 * gcc.target/i386/indirect-thunk-bnd-3.c: Likewise.
63 * gcc.target/i386/indirect-thunk-bnd-4.c: Likewise.
64 * gcc.target/i386/indirect-thunk-extern-1.c: Likewise.
65 * gcc.target/i386/indirect-thunk-extern-2.c: Likewise.
66 * gcc.target/i386/indirect-thunk-extern-3.c: Likewise.
67 * gcc.target/i386/indirect-thunk-extern-4.c: Likewise.
68 * gcc.target/i386/indirect-thunk-extern-5.c: Likewise.
69 * gcc.target/i386/indirect-thunk-extern-6.c: Likewise.
70 * gcc.target/i386/indirect-thunk-extern-7.c: Likewise.
71 * gcc.target/i386/indirect-thunk-inline-1.c: Likewise.
72 * gcc.target/i386/indirect-thunk-inline-2.c: Likewise.
73 * gcc.target/i386/indirect-thunk-inline-3.c: Likewise.
74 * gcc.target/i386/indirect-thunk-inline-4.c: Likewise.
75 * gcc.target/i386/indirect-thunk-inline-5.c: Likewise.
76 * gcc.target/i386/indirect-thunk-inline-6.c: Likewise.
77 * gcc.target/i386/indirect-thunk-inline-7.c: Likewise.
78 * gcc.target/i386/ret-thunk-10.c: Likewise.
79 * gcc.target/i386/ret-thunk-11.c: Likewise.
80 * gcc.target/i386/ret-thunk-12.c: Likewise.
81 * gcc.target/i386/ret-thunk-13.c: Likewise.
82 * gcc.target/i386/ret-thunk-14.c: Likewise.
83 * gcc.target/i386/ret-thunk-15.c: Likewise.
84 * gcc.target/i386/ret-thunk-9.c: Likewise.
85 * gcc.target/i386/indirect-thunk-register-1.c: New test.
86 * gcc.target/i386/indirect-thunk-register-2.c: Likewise.
87 * gcc.target/i386/indirect-thunk-register-3.c: Likewise.
88
89i386: Rename to ix86_indirect_branch_register
90
91Rename the variable for -mindirect-branch-register to
92ix86_indirect_branch_register to match the command-line option name.
93
94 Backport from mainline
95 2018-01-15 H.J. Lu <hongjiu.lu@intel.com>
96
97 * config/i386/constraints.md (Bs): Replace
98 ix86_indirect_branch_thunk_register with
99 ix86_indirect_branch_register.
100 (Bw): Likewise.
101 * config/i386/i386.md (indirect_jump): Likewise.
102 (tablejump): Likewise.
103 (*sibcall_memory): Likewise.
104 (*sibcall_value_memory): Likewise.
105 Peepholes of indirect call and jump via memory: Likewise.
106 * config/i386/i386.opt: Likewise.
107 * config/i386/predicates.md (indirect_branch_operand): Likewise.
108 (GOT_memory_operand): Likewise.
109 (call_insn_operand): Likewise.
110 (sibcall_insn_operand): Likewise.
111 (GOT32_symbol_operand): Likewise.
112
113x86: Rewrite ix86_indirect_branch_register logic
114
115Rewrite ix86_indirect_branch_register logic with
116
117(and (not (match_test "ix86_indirect_branch_register"))
118 (original condition before r256662))
119
120 Backport from mainline
121 2018-01-15 H.J. Lu <hongjiu.lu@intel.com>
122
123 * config/i386/predicates.md (constant_call_address_operand):
124 Rewrite ix86_indirect_branch_register logic.
125 (sibcall_insn_operand): Likewise.
126
127Don't check ix86_indirect_branch_register for GOT operand
128
129Since GOT_memory_operand and GOT32_symbol_operand are simple pattern
130matches, don't check ix86_indirect_branch_register here. If needed,
131-mindirect-branch= will convert indirect branch via GOT slot to a call
132and return thunk.
133
134 Backport from mainline
135 2018-01-15 H.J. Lu <hongjiu.lu@intel.com>
136
137 * config/i386/constraints.md (Bs): Update
138 ix86_indirect_branch_register check. Don't check
139 ix86_indirect_branch_register with GOT_memory_operand.
140 (Bw): Likewise.
141 * config/i386/predicates.md (GOT_memory_operand): Don't check
142 ix86_indirect_branch_register here.
143 (GOT32_symbol_operand): Likewise.
144
145i386: Rewrite indirect_branch_operand logic
146
147 Backport from mainline
148 2018-01-15 H.J. Lu <hongjiu.lu@intel.com>
149
150 * config/i386/predicates.md (indirect_branch_operand): Rewrite
151 ix86_indirect_branch_register logic.
152
153Upstream-Status: Pending
154
155Signed-off-by: Juro Bystricky <juro.bystricky@intel.com>
156
157---
158 gcc/config/i386/constraints.md | 6 ++--
159 gcc/config/i386/i386.md | 34 ++++++++++++++--------
160 gcc/config/i386/i386.opt | 4 +++
161 gcc/config/i386/predicates.md | 21 +++++++------
162 gcc/doc/invoke.texi | 6 +++-
163 gcc/testsuite/gcc.target/i386/indirect-thunk-1.c | 2 +-
164 gcc/testsuite/gcc.target/i386/indirect-thunk-2.c | 2 +-
165 gcc/testsuite/gcc.target/i386/indirect-thunk-3.c | 2 +-
166 gcc/testsuite/gcc.target/i386/indirect-thunk-4.c | 2 +-
167 gcc/testsuite/gcc.target/i386/indirect-thunk-5.c | 2 +-
168 gcc/testsuite/gcc.target/i386/indirect-thunk-6.c | 2 +-
169 gcc/testsuite/gcc.target/i386/indirect-thunk-7.c | 2 +-
170 .../gcc.target/i386/indirect-thunk-attr-1.c | 2 +-
171 .../gcc.target/i386/indirect-thunk-attr-2.c | 2 +-
172 .../gcc.target/i386/indirect-thunk-attr-3.c | 2 +-
173 .../gcc.target/i386/indirect-thunk-attr-4.c | 2 +-
174 .../gcc.target/i386/indirect-thunk-attr-5.c | 2 +-
175 .../gcc.target/i386/indirect-thunk-attr-6.c | 2 +-
176 .../gcc.target/i386/indirect-thunk-attr-7.c | 2 +-
177 .../gcc.target/i386/indirect-thunk-bnd-1.c | 2 +-
178 .../gcc.target/i386/indirect-thunk-bnd-2.c | 2 +-
179 .../gcc.target/i386/indirect-thunk-bnd-3.c | 2 +-
180 .../gcc.target/i386/indirect-thunk-bnd-4.c | 2 +-
181 .../gcc.target/i386/indirect-thunk-extern-1.c | 2 +-
182 .../gcc.target/i386/indirect-thunk-extern-2.c | 2 +-
183 .../gcc.target/i386/indirect-thunk-extern-3.c | 2 +-
184 .../gcc.target/i386/indirect-thunk-extern-4.c | 2 +-
185 .../gcc.target/i386/indirect-thunk-extern-5.c | 2 +-
186 .../gcc.target/i386/indirect-thunk-extern-6.c | 2 +-
187 .../gcc.target/i386/indirect-thunk-extern-7.c | 2 +-
188 .../gcc.target/i386/indirect-thunk-inline-1.c | 2 +-
189 .../gcc.target/i386/indirect-thunk-inline-2.c | 2 +-
190 .../gcc.target/i386/indirect-thunk-inline-3.c | 2 +-
191 .../gcc.target/i386/indirect-thunk-inline-4.c | 2 +-
192 .../gcc.target/i386/indirect-thunk-inline-5.c | 2 +-
193 .../gcc.target/i386/indirect-thunk-inline-6.c | 2 +-
194 .../gcc.target/i386/indirect-thunk-inline-7.c | 2 +-
195 .../gcc.target/i386/indirect-thunk-register-1.c | 22 ++++++++++++++
196 .../gcc.target/i386/indirect-thunk-register-2.c | 20 +++++++++++++
197 .../gcc.target/i386/indirect-thunk-register-3.c | 19 ++++++++++++
198 gcc/testsuite/gcc.target/i386/ret-thunk-10.c | 2 +-
199 gcc/testsuite/gcc.target/i386/ret-thunk-11.c | 2 +-
200 gcc/testsuite/gcc.target/i386/ret-thunk-12.c | 2 +-
201 gcc/testsuite/gcc.target/i386/ret-thunk-13.c | 2 +-
202 gcc/testsuite/gcc.target/i386/ret-thunk-14.c | 2 +-
203 gcc/testsuite/gcc.target/i386/ret-thunk-15.c | 2 +-
204 gcc/testsuite/gcc.target/i386/ret-thunk-9.c | 2 +-
205 47 files changed, 147 insertions(+), 63 deletions(-)
206 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-register-1.c
207 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-register-2.c
208 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-register-3.c
209
210diff --git a/gcc/config/i386/constraints.md b/gcc/config/i386/constraints.md
211index 1a4c701..9204c8e 100644
212--- a/gcc/config/i386/constraints.md
213+++ b/gcc/config/i386/constraints.md
214@@ -172,14 +172,16 @@
215
216 (define_constraint "Bs"
217 "@internal Sibcall memory operand."
218- (ior (and (not (match_test "TARGET_X32"))
219+ (ior (and (not (match_test "ix86_indirect_branch_register"))
220+ (not (match_test "TARGET_X32"))
221 (match_operand 0 "sibcall_memory_operand"))
222 (and (match_test "TARGET_X32 && Pmode == DImode")
223 (match_operand 0 "GOT_memory_operand"))))
224
225 (define_constraint "Bw"
226 "@internal Call memory operand."
227- (ior (and (not (match_test "TARGET_X32"))
228+ (ior (and (not (match_test "ix86_indirect_branch_register"))
229+ (not (match_test "TARGET_X32"))
230 (match_operand 0 "memory_operand"))
231 (and (match_test "TARGET_X32 && Pmode == DImode")
232 (match_operand 0 "GOT_memory_operand"))))
233diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
234index 2da671e..05a88ff 100644
235--- a/gcc/config/i386/i386.md
236+++ b/gcc/config/i386/i386.md
237@@ -11805,7 +11805,7 @@
238 [(set (pc) (match_operand 0 "indirect_branch_operand"))]
239 ""
240 {
241- if (TARGET_X32)
242+ if (TARGET_X32 || ix86_indirect_branch_register)
243 operands[0] = convert_memory_address (word_mode, operands[0]);
244 cfun->machine->has_local_indirect_jump = true;
245 })
246@@ -11859,7 +11859,7 @@
247 OPTAB_DIRECT);
248 }
249
250- if (TARGET_X32)
251+ if (TARGET_X32 || ix86_indirect_branch_register)
252 operands[0] = convert_memory_address (word_mode, operands[0]);
253 cfun->machine->has_local_indirect_jump = true;
254 })
255@@ -12048,7 +12048,7 @@
256 [(call (mem:QI (match_operand:W 0 "memory_operand" "m"))
257 (match_operand 1))
258 (unspec [(const_int 0)] UNSPEC_PEEPSIB)]
259- "!TARGET_X32"
260+ "!TARGET_X32 && !ix86_indirect_branch_register"
261 "* return ix86_output_call_insn (insn, operands[0]);"
262 [(set_attr "type" "call")])
263
264@@ -12057,7 +12057,9 @@
265 (match_operand:W 1 "memory_operand"))
266 (call (mem:QI (match_dup 0))
267 (match_operand 3))]
268- "!TARGET_X32 && SIBLING_CALL_P (peep2_next_insn (1))
269+ "!TARGET_X32
270+ && !ix86_indirect_branch_register
271+ && SIBLING_CALL_P (peep2_next_insn (1))
272 && !reg_mentioned_p (operands[0],
273 CALL_INSN_FUNCTION_USAGE (peep2_next_insn (1)))"
274 [(parallel [(call (mem:QI (match_dup 1))
275@@ -12070,7 +12072,9 @@
276 (unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)
277 (call (mem:QI (match_dup 0))
278 (match_operand 3))]
279- "!TARGET_X32 && SIBLING_CALL_P (peep2_next_insn (2))
280+ "!TARGET_X32
281+ && !ix86_indirect_branch_register
282+ && SIBLING_CALL_P (peep2_next_insn (2))
283 && !reg_mentioned_p (operands[0],
284 CALL_INSN_FUNCTION_USAGE (peep2_next_insn (2)))"
285 [(unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)
286@@ -12092,7 +12096,7 @@
287 })
288
289 (define_insn "*call_pop"
290- [(call (mem:QI (match_operand:SI 0 "call_insn_operand" "lmBz"))
291+ [(call (mem:QI (match_operand:SI 0 "call_insn_operand" "lBwBz"))
292 (match_operand 1))
293 (set (reg:SI SP_REG)
294 (plus:SI (reg:SI SP_REG)
295@@ -12112,7 +12116,7 @@
296 [(set_attr "type" "call")])
297
298 (define_insn "*sibcall_pop_memory"
299- [(call (mem:QI (match_operand:SI 0 "memory_operand" "m"))
300+ [(call (mem:QI (match_operand:SI 0 "memory_operand" "Bs"))
301 (match_operand 1))
302 (set (reg:SI SP_REG)
303 (plus:SI (reg:SI SP_REG)
304@@ -12166,7 +12170,9 @@
305 [(set (match_operand:W 0 "register_operand")
306 (match_operand:W 1 "memory_operand"))
307 (set (pc) (match_dup 0))]
308- "!TARGET_X32 && peep2_reg_dead_p (2, operands[0])"
309+ "!TARGET_X32
310+ && !ix86_indirect_branch_register
311+ && peep2_reg_dead_p (2, operands[0])"
312 [(set (pc) (match_dup 1))])
313
314 ;; Call subroutine, returning value in operand 0
315@@ -12244,7 +12250,7 @@
316 (call (mem:QI (match_operand:W 1 "memory_operand" "m"))
317 (match_operand 2)))
318 (unspec [(const_int 0)] UNSPEC_PEEPSIB)]
319- "!TARGET_X32"
320+ "!TARGET_X32 && !ix86_indirect_branch_register"
321 "* return ix86_output_call_insn (insn, operands[1]);"
322 [(set_attr "type" "callv")])
323
324@@ -12254,7 +12260,9 @@
325 (set (match_operand 2)
326 (call (mem:QI (match_dup 0))
327 (match_operand 3)))]
328- "!TARGET_X32 && SIBLING_CALL_P (peep2_next_insn (1))
329+ "!TARGET_X32
330+ && !ix86_indirect_branch_register
331+ && SIBLING_CALL_P (peep2_next_insn (1))
332 && !reg_mentioned_p (operands[0],
333 CALL_INSN_FUNCTION_USAGE (peep2_next_insn (1)))"
334 [(parallel [(set (match_dup 2)
335@@ -12269,7 +12277,9 @@
336 (set (match_operand 2)
337 (call (mem:QI (match_dup 0))
338 (match_operand 3)))]
339- "!TARGET_X32 && SIBLING_CALL_P (peep2_next_insn (2))
340+ "!TARGET_X32
341+ && !ix86_indirect_branch_register
342+ && SIBLING_CALL_P (peep2_next_insn (2))
343 && !reg_mentioned_p (operands[0],
344 CALL_INSN_FUNCTION_USAGE (peep2_next_insn (2)))"
345 [(unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)
346@@ -12294,7 +12304,7 @@
347
348 (define_insn "*call_value_pop"
349 [(set (match_operand 0)
350- (call (mem:QI (match_operand:SI 1 "call_insn_operand" "lmBz"))
351+ (call (mem:QI (match_operand:SI 1 "call_insn_operand" "lBwBz"))
352 (match_operand 2)))
353 (set (reg:SI SP_REG)
354 (plus:SI (reg:SI SP_REG)
355diff --git a/gcc/config/i386/i386.opt b/gcc/config/i386/i386.opt
356index ad5916f..a97f84f 100644
357--- a/gcc/config/i386/i386.opt
358+++ b/gcc/config/i386/i386.opt
359@@ -921,3 +921,7 @@ Enum(indirect_branch) String(thunk-inline) Value(indirect_branch_thunk_inline)
360
361 EnumValue
362 Enum(indirect_branch) String(thunk-extern) Value(indirect_branch_thunk_extern)
363+
364+mindirect-branch-register
365+Target Report Var(ix86_indirect_branch_register) Init(0)
366+Force indirect call and jump via register.
367diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md
368index 93dda7b..d1f0a7d 100644
369--- a/gcc/config/i386/predicates.md
370+++ b/gcc/config/i386/predicates.md
371@@ -593,7 +593,8 @@
372 ;; Test for a valid operand for indirect branch.
373 (define_predicate "indirect_branch_operand"
374 (ior (match_operand 0 "register_operand")
375- (and (not (match_test "TARGET_X32"))
376+ (and (not (match_test "ix86_indirect_branch_register"))
377+ (not (match_test "TARGET_X32"))
378 (match_operand 0 "memory_operand"))))
379
380 ;; Return true if OP is a memory operands that can be used in sibcalls.
381@@ -636,20 +637,22 @@
382 (ior (match_test "constant_call_address_operand
383 (op, mode == VOIDmode ? mode : Pmode)")
384 (match_operand 0 "call_register_no_elim_operand")
385- (ior (and (not (match_test "TARGET_X32"))
386- (match_operand 0 "memory_operand"))
387- (and (match_test "TARGET_X32 && Pmode == DImode")
388- (match_operand 0 "GOT_memory_operand")))))
389+ (and (not (match_test "ix86_indirect_branch_register"))
390+ (ior (and (not (match_test "TARGET_X32"))
391+ (match_operand 0 "memory_operand"))
392+ (and (match_test "TARGET_X32 && Pmode == DImode")
393+ (match_operand 0 "GOT_memory_operand"))))))
394
395 ;; Similarly, but for tail calls, in which we cannot allow memory references.
396 (define_special_predicate "sibcall_insn_operand"
397 (ior (match_test "constant_call_address_operand
398 (op, mode == VOIDmode ? mode : Pmode)")
399 (match_operand 0 "register_no_elim_operand")
400- (ior (and (not (match_test "TARGET_X32"))
401- (match_operand 0 "sibcall_memory_operand"))
402- (and (match_test "TARGET_X32 && Pmode == DImode")
403- (match_operand 0 "GOT_memory_operand")))))
404+ (and (not (match_test "ix86_indirect_branch_register"))
405+ (ior (and (not (match_test "TARGET_X32"))
406+ (match_operand 0 "sibcall_memory_operand"))
407+ (and (match_test "TARGET_X32 && Pmode == DImode")
408+ (match_operand 0 "GOT_memory_operand"))))))
409
410 ;; Return true if OP is a 32-bit GOT symbol operand.
411 (define_predicate "GOT32_symbol_operand"
412diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
413index fa63dc5..ad9f295 100644
414--- a/gcc/doc/invoke.texi
415+++ b/gcc/doc/invoke.texi
416@@ -1170,7 +1170,7 @@ See RS/6000 and PowerPC Options.
417 -mavx256-split-unaligned-load -mavx256-split-unaligned-store @gol
418 -malign-data=@var{type} -mstack-protector-guard=@var{guard} @gol
419 -mmitigate-rop -mindirect-branch=@var{choice} @gol
420--mfunction-return=@var{choice}}
421+-mfunction-return=@var{choice} -mindirect-branch-register}
422
423 @emph{x86 Windows Options}
424 @gccoptlist{-mconsole -mcygwin -mno-cygwin -mdll @gol
425@@ -24241,6 +24241,10 @@ object file. You can control this behavior for a specific function by
426 using the function attribute @code{function_return}.
427 @xref{Function Attributes}.
428
429+@item -mindirect-branch-register
430+@opindex -mindirect-branch-register
431+Force indirect call and jump via register.
432+
433 @end table
434
435 These @samp{-m} switches are supported in addition to the above
436diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c
437index e365ef5..60d0988 100644
438--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c
439+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c
440@@ -1,5 +1,5 @@
441 /* { dg-do compile } */
442-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
443+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
444
445 typedef void (*dispatch_t)(long offset);
446
447diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c
448index 05a51ad..aac7516 100644
449--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c
450+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c
451@@ -1,5 +1,5 @@
452 /* { dg-do compile } */
453-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
454+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
455
456 typedef void (*dispatch_t)(long offset);
457
458diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c
459index 3c0d4c3..9e24a38 100644
460--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c
461+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c
462@@ -1,5 +1,5 @@
463 /* { dg-do compile } */
464-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
465+/* { dg-options "-O2 -mno-indirect-branch-register -mno-indirect-branch-register -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
466
467 typedef void (*dispatch_t)(long offset);
468
469diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c
470index 14d4ef6..127b5d9 100644
471--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c
472+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c
473@@ -1,5 +1,5 @@
474 /* { dg-do compile } */
475-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
476+/* { dg-options "-O2 -mno-indirect-branch-register -mno-indirect-branch-register -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
477
478 typedef void (*dispatch_t)(long offset);
479
480diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c
481index b4836c3..fcaa18d 100644
482--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c
483+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c
484@@ -1,5 +1,5 @@
485 /* { dg-do compile { target *-*-linux* } } */
486-/* { dg-options "-O2 -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk" } */
487+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk" } */
488
489 extern void bar (void);
490
491diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c
492index 1f06bd1..e464928 100644
493--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c
494+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c
495@@ -1,5 +1,5 @@
496 /* { dg-do compile { target *-*-linux* } } */
497-/* { dg-options "-O2 -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk" } */
498+/* { dg-options "-O2 -mno-indirect-branch-register -mno-indirect-branch-register -mno-indirect-branch-register -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk" } */
499
500 extern void bar (void);
501
502diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c
503index bc6b47a..17c2d0f 100644
504--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c
505+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c
506@@ -1,5 +1,5 @@
507 /* { dg-do compile } */
508-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
509+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
510
511 void func0 (void);
512 void func1 (void);
513diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c
514index 2257be3..9194ccf 100644
515--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c
516+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c
517@@ -1,5 +1,5 @@
518 /* { dg-do compile } */
519-/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
520+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic" } */
521
522 typedef void (*dispatch_t)(long offset);
523
524diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c
525index e9cfdc5..e51f261 100644
526--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c
527+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c
528@@ -1,5 +1,5 @@
529 /* { dg-do compile } */
530-/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
531+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic" } */
532
533 typedef void (*dispatch_t)(long offset);
534
535diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c
536index f938db0..4aeec18 100644
537--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c
538+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c
539@@ -1,5 +1,5 @@
540 /* { dg-do compile } */
541-/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
542+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic" } */
543
544 typedef void (*dispatch_t)(long offset);
545
546diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c
547index 4e58599..ac0e599 100644
548--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c
549+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c
550@@ -1,5 +1,5 @@
551 /* { dg-do compile } */
552-/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
553+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic" } */
554
555 typedef void (*dispatch_t)(long offset);
556
557diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c
558index b8d5024..573cf1e 100644
559--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c
560+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c
561@@ -1,5 +1,5 @@
562 /* { dg-do compile } */
563-/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
564+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic" } */
565
566 typedef void (*dispatch_t)(long offset);
567
568diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c
569index 455adab..b2b37fc 100644
570--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c
571+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c
572@@ -1,5 +1,5 @@
573 /* { dg-do compile } */
574-/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
575+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic" } */
576
577 typedef void (*dispatch_t)(long offset);
578
579diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c
580index 4595b84..4a43e19 100644
581--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c
582+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c
583@@ -1,5 +1,5 @@
584 /* { dg-do compile } */
585-/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
586+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic" } */
587
588 void func0 (void);
589 void func1 (void);
590diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c
591index 5e3e118..ac84ab6 100644
592--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c
593+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c
594@@ -1,5 +1,5 @@
595 /* { dg-do compile { target { ! x32 } } } */
596-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
597+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
598
599 void (*dispatch) (char *);
600 char buf[10];
601diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c
602index 2801aa4..ce655e8 100644
603--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c
604+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c
605@@ -1,5 +1,5 @@
606 /* { dg-do compile { target { ! x32 } } } */
607-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
608+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
609
610 void (*dispatch) (char *);
611 char buf[10];
612diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c
613index 70b4fb3..d34485a 100644
614--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c
615+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c
616@@ -1,5 +1,5 @@
617 /* { dg-do compile { target { *-*-linux* && { ! x32 } } } } */
618-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fpic -fno-plt" } */
619+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fpic -fno-plt" } */
620
621 void bar (char *);
622 char buf[10];
623diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c
624index 3baf03e..0e19830 100644
625--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c
626+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c
627@@ -1,5 +1,5 @@
628 /* { dg-do compile { target { *-*-linux* && { ! x32 } } } } */
629-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fpic -fno-plt" } */
630+/* { dg-options "-O2 -mno-indirect-branch-register -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fpic -fno-plt" } */
631
632 void bar (char *);
633 char buf[10];
634diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c
635index edeb264..579441f 100644
636--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c
637+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c
638@@ -1,5 +1,5 @@
639 /* { dg-do compile } */
640-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
641+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
642
643 typedef void (*dispatch_t)(long offset);
644
645diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c
646index 1d00413..c92e6f2 100644
647--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c
648+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c
649@@ -1,5 +1,5 @@
650 /* { dg-do compile } */
651-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
652+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
653
654 typedef void (*dispatch_t)(long offset);
655
656diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c
657index 06ebf1c..d9964c2 100644
658--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c
659+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c
660@@ -1,5 +1,5 @@
661 /* { dg-do compile } */
662-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
663+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
664
665 typedef void (*dispatch_t)(long offset);
666
667diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c
668index 1c8f944..d4dca4d 100644
669--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c
670+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c
671@@ -1,5 +1,5 @@
672 /* { dg-do compile } */
673-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
674+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
675
676 typedef void (*dispatch_t)(long offset);
677
678diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c
679index 21740ac..5c07e02 100644
680--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c
681+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c
682@@ -1,5 +1,5 @@
683 /* { dg-do compile { target *-*-linux* } } */
684-/* { dg-options "-O2 -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk-extern" } */
685+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk-extern" } */
686
687 extern void bar (void);
688
689diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c
690index a77c1f4..3eb4406 100644
691--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c
692+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c
693@@ -1,5 +1,5 @@
694 /* { dg-do compile { target *-*-linux* } } */
695-/* { dg-options "-O2 -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk-extern" } */
696+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk-extern" } */
697
698 extern void bar (void);
699
700diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c
701index 86e9fd1..aece938 100644
702--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c
703+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c
704@@ -1,5 +1,5 @@
705 /* { dg-do compile } */
706-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
707+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
708
709 void func0 (void);
710 void func1 (void);
711diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c
712index 3ecde87..3aba5e8 100644
713--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c
714+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c
715@@ -1,5 +1,5 @@
716 /* { dg-do compile } */
717-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
718+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
719
720 typedef void (*dispatch_t)(long offset);
721
722diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c
723index df32a19..0f0181d 100644
724--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c
725+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c
726@@ -1,5 +1,5 @@
727 /* { dg-do compile } */
728-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
729+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
730
731 typedef void (*dispatch_t)(long offset);
732
733diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c
734index 9540996..2eef6f3 100644
735--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c
736+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c
737@@ -1,5 +1,5 @@
738 /* { dg-do compile } */
739-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
740+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
741
742 typedef void (*dispatch_t)(long offset);
743
744diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c
745index f3db6e2..e825a10 100644
746--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c
747+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c
748@@ -1,5 +1,5 @@
749 /* { dg-do compile } */
750-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
751+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
752
753 typedef void (*dispatch_t)(long offset);
754
755diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c
756index 0f687c3..c6d77e1 100644
757--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c
758+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c
759@@ -1,5 +1,5 @@
760 /* { dg-do compile { target *-*-linux* } } */
761-/* { dg-options "-O2 -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk-inline" } */
762+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk-inline" } */
763
764 extern void bar (void);
765
766diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c
767index b27c6fc..6454827 100644
768--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c
769+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c
770@@ -1,5 +1,5 @@
771 /* { dg-do compile { target *-*-linux* } } */
772-/* { dg-options "-O2 -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk-inline" } */
773+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fpic -fno-plt -mindirect-branch=thunk-inline" } */
774
775 extern void bar (void);
776
777diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c
778index 764a375..c67066c 100644
779--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c
780+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c
781@@ -1,5 +1,5 @@
782 /* { dg-do compile } */
783-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
784+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
785
786 void func0 (void);
787 void func1 (void);
788diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-register-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-register-1.c
789new file mode 100644
790index 0000000..7d396a3
791--- /dev/null
792+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-register-1.c
793@@ -0,0 +1,22 @@
794+/* { dg-do compile } */
795+/* { dg-options "-O2 -mindirect-branch=thunk -mindirect-branch-register -fno-pic" } */
796+
797+typedef void (*dispatch_t)(long offset);
798+
799+dispatch_t dispatch;
800+
801+void
802+male_indirect_jump (long offset)
803+{
804+ dispatch(offset);
805+}
806+
807+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" } } */
808+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
809+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
810+/* { dg-final { scan-assembler "mov\[ \t\](%eax|%rax), \\((%esp|%rsp)\\)" } } */
811+/* { dg-final { scan-assembler {\tpause} } } */
812+/* { dg-final { scan-assembler-not "push(?:l|q)\[ \t\]*_?dispatch" } } */
813+/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" } } */
814+/* { dg-final { scan-assembler-not "__x86_indirect_thunk\n" } } */
815+/* { dg-final { scan-assembler-not "__x86_indirect_thunk_bnd\n" } } */
816diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-register-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-register-2.c
817new file mode 100644
818index 0000000..e7e616b
819--- /dev/null
820+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-register-2.c
821@@ -0,0 +1,20 @@
822+/* { dg-do compile } */
823+/* { dg-options "-O2 -mindirect-branch=thunk-inline -mindirect-branch-register -fno-pic" } */
824+
825+typedef void (*dispatch_t)(long offset);
826+
827+dispatch_t dispatch;
828+
829+void
830+male_indirect_jump (long offset)
831+{
832+ dispatch(offset);
833+}
834+
835+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
836+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
837+/* { dg-final { scan-assembler "mov\[ \t\](%eax|%rax), \\((%esp|%rsp)\\)" } } */
838+/* { dg-final { scan-assembler {\tpause} } } */
839+/* { dg-final { scan-assembler-not "push(?:l|q)\[ \t\]*_?dispatch" } } */
840+/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" } } */
841+/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
842diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-register-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-register-3.c
843new file mode 100644
844index 0000000..5320e92
845--- /dev/null
846+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-register-3.c
847@@ -0,0 +1,19 @@
848+/* { dg-do compile } */
849+/* { dg-options "-O2 -mindirect-branch=thunk-extern -mindirect-branch-register -fno-pic" } */
850+
851+typedef void (*dispatch_t)(long offset);
852+
853+dispatch_t dispatch;
854+
855+void
856+male_indirect_jump (long offset)
857+{
858+ dispatch(offset);
859+}
860+
861+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" } } */
862+/* { dg-final { scan-assembler-not "push(?:l|q)\[ \t\]*_?dispatch" } } */
863+/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" } } */
864+/* { dg-final { scan-assembler-not {\t(pause|pause|nop)} } } */
865+/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
866+/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
867diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-10.c b/gcc/testsuite/gcc.target/i386/ret-thunk-10.c
868index 3a6727b..e6fea84 100644
869--- a/gcc/testsuite/gcc.target/i386/ret-thunk-10.c
870+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-10.c
871@@ -1,5 +1,5 @@
872 /* { dg-do compile } */
873-/* { dg-options "-O2 -mfunction-return=thunk-inline -mindirect-branch=thunk -fno-pic" } */
874+/* { dg-options "-O2 -mno-indirect-branch-register -mno-indirect-branch-register -mfunction-return=thunk-inline -mindirect-branch=thunk -fno-pic" } */
875
876 extern void (*bar) (void);
877
878diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-11.c b/gcc/testsuite/gcc.target/i386/ret-thunk-11.c
879index b8f6818..e239ec4 100644
880--- a/gcc/testsuite/gcc.target/i386/ret-thunk-11.c
881+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-11.c
882@@ -1,5 +1,5 @@
883 /* { dg-do compile } */
884-/* { dg-options "-O2 -mfunction-return=thunk-extern -mindirect-branch=thunk -fno-pic" } */
885+/* { 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" } */
886
887 extern void (*bar) (void);
888
889diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-12.c b/gcc/testsuite/gcc.target/i386/ret-thunk-12.c
890index 01b0a02..fa31813 100644
891--- a/gcc/testsuite/gcc.target/i386/ret-thunk-12.c
892+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-12.c
893@@ -1,5 +1,5 @@
894 /* { dg-do compile } */
895-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
896+/* { 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" } */
897
898 extern void (*bar) (void);
899
900diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-13.c b/gcc/testsuite/gcc.target/i386/ret-thunk-13.c
901index 4b497b5..fd5b41f 100644
902--- a/gcc/testsuite/gcc.target/i386/ret-thunk-13.c
903+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-13.c
904@@ -1,5 +1,5 @@
905 /* { dg-do compile } */
906-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
907+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
908
909 extern void (*bar) (void);
910 extern int foo (void) __attribute__ ((function_return("thunk")));
911diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-14.c b/gcc/testsuite/gcc.target/i386/ret-thunk-14.c
912index 4ae4c44..d606373 100644
913--- a/gcc/testsuite/gcc.target/i386/ret-thunk-14.c
914+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-14.c
915@@ -1,5 +1,5 @@
916 /* { dg-do compile } */
917-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
918+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
919
920 extern void (*bar) (void);
921
922diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-15.c b/gcc/testsuite/gcc.target/i386/ret-thunk-15.c
923index 5b5bc76..75e45e2 100644
924--- a/gcc/testsuite/gcc.target/i386/ret-thunk-15.c
925+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-15.c
926@@ -1,5 +1,5 @@
927 /* { dg-do compile } */
928-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=keep -fno-pic" } */
929+/* { 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" } */
930
931 extern void (*bar) (void);
932
933diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-9.c b/gcc/testsuite/gcc.target/i386/ret-thunk-9.c
934index fa24a1f..d1db41c 100644
935--- a/gcc/testsuite/gcc.target/i386/ret-thunk-9.c
936+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-9.c
937@@ -1,5 +1,5 @@
938 /* { dg-do compile } */
939-/* { dg-options "-O2 -mfunction-return=thunk -mindirect-branch=thunk -fno-pic" } */
940+/* { dg-options "-O2 -mno-indirect-branch-register -mno-indirect-branch-register -mfunction-return=thunk -mindirect-branch=thunk -fno-pic" } */
941
942 extern void (*bar) (void);
943
944--
9452.7.4
946
diff --git a/meta/recipes-devtools/gcc/gcc-6.4/backport/0007-x86-Add-V-register-operand-modifier.patch b/meta/recipes-devtools/gcc/gcc-6.4/backport/0007-x86-Add-V-register-operand-modifier.patch
new file mode 100644
index 0000000000..cec84fefb2
--- /dev/null
+++ b/meta/recipes-devtools/gcc/gcc-6.4/backport/0007-x86-Add-V-register-operand-modifier.patch
@@ -0,0 +1,139 @@
1From 8f0efd692eb8db06d6c00b759c872bd2170b7f7b Mon Sep 17 00:00:00 2001
2From: "H.J. Lu" <hjl.tools@gmail.com>
3Date: Sat, 6 Jan 2018 22:29:56 -0800
4Subject: [PATCH 07/12] x86: Add 'V' register operand modifier
5
6Add 'V', a special modifier which prints the name of the full integer
7register without '%'. For
8
9extern void (*func_p) (void);
10
11void
12foo (void)
13{
14 asm ("call __x86_indirect_thunk_%V0" : : "a" (func_p));
15}
16
17it generates:
18
19foo:
20 movq func_p(%rip), %rax
21 call __x86_indirect_thunk_rax
22 ret
23
24gcc/
25
26 Backport from mainline
27 2018-01-14 H.J. Lu <hongjiu.lu@intel.com>
28
29 * config/i386/i386.c (print_reg): Print the name of the full
30 integer register without '%'.
31 (ix86_print_operand): Handle 'V'.
32 * doc/extend.texi: Document 'V' modifier.
33
34gcc/testsuite/
35
36 Backport from mainline
37 2018-01-14 H.J. Lu <hongjiu.lu@intel.com>
38
39 * gcc.target/i386/indirect-thunk-register-4.c: New test.
40
41Upstream-Status: Pending
42
43Signed-off-by: Juro Bystricky <juro.bystricky@intel.com>
44
45---
46 gcc/config/i386/i386.c | 13 ++++++++++++-
47 gcc/doc/extend.texi | 3 +++
48 gcc/testsuite/gcc.target/i386/indirect-thunk-register-4.c | 13 +++++++++++++
49 3 files changed, 28 insertions(+), 1 deletion(-)
50 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-register-4.c
51
52diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
53index 34e26a3..eeca7e5 100644
54--- a/gcc/config/i386/i386.c
55+++ b/gcc/config/i386/i386.c
56@@ -16869,6 +16869,7 @@ put_condition_code (enum rtx_code code, machine_mode mode, bool reverse,
57 If CODE is 'h', pretend the reg is the 'high' byte register.
58 If CODE is 'y', print "st(0)" instead of "st", if the reg is stack op.
59 If CODE is 'd', duplicate the operand for AVX instruction.
60+ If CODE is 'V', print naked full integer register name without %.
61 */
62
63 void
64@@ -16879,7 +16880,7 @@ print_reg (rtx x, int code, FILE *file)
65 unsigned int regno;
66 bool duplicated;
67
68- if (ASSEMBLER_DIALECT == ASM_ATT)
69+ if (ASSEMBLER_DIALECT == ASM_ATT && code != 'V')
70 putc ('%', file);
71
72 if (x == pc_rtx)
73@@ -16922,6 +16923,14 @@ print_reg (rtx x, int code, FILE *file)
74 && regno != FPSR_REG
75 && regno != FPCR_REG);
76
77+ if (code == 'V')
78+ {
79+ if (GENERAL_REGNO_P (regno))
80+ msize = GET_MODE_SIZE (word_mode);
81+ else
82+ error ("'V' modifier on non-integer register");
83+ }
84+
85 duplicated = code == 'd' && TARGET_AVX;
86
87 switch (msize)
88@@ -17035,6 +17044,7 @@ print_reg (rtx x, int code, FILE *file)
89 & -- print some in-use local-dynamic symbol name.
90 H -- print a memory address offset by 8; used for sse high-parts
91 Y -- print condition for XOP pcom* instruction.
92+ V -- print naked full integer register name without %.
93 + -- print a branch hint as 'cs' or 'ds' prefix
94 ; -- print a semicolon (after prefixes due to bug in older gas).
95 ~ -- print "i" if TARGET_AVX2, "f" otherwise.
96@@ -17259,6 +17269,7 @@ ix86_print_operand (FILE *file, rtx x, int code)
97 case 'X':
98 case 'P':
99 case 'p':
100+ case 'V':
101 break;
102
103 case 's':
104diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
105index 2cb6bd1..76ba1d4 100644
106--- a/gcc/doc/extend.texi
107+++ b/gcc/doc/extend.texi
108@@ -8511,6 +8511,9 @@ The table below shows the list of supported modifiers and their effects.
109 @tab @code{2}
110 @end multitable
111
112+@code{V} is a special modifier which prints the name of the full integer
113+register without @code{%}.
114+
115 @anchor{x86floatingpointasmoperands}
116 @subsubsection x86 Floating-Point @code{asm} Operands
117
118diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-register-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-register-4.c
119new file mode 100644
120index 0000000..f0cd9b7
121--- /dev/null
122+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-register-4.c
123@@ -0,0 +1,13 @@
124+/* { dg-do compile } */
125+/* { dg-options "-O2 -mindirect-branch=keep -fno-pic" } */
126+
127+extern void (*func_p) (void);
128+
129+void
130+foo (void)
131+{
132+ asm("call __x86_indirect_thunk_%V0" : : "a" (func_p));
133+}
134+
135+/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_eax" { target ia32 } } } */
136+/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_rax" { target { ! ia32 } } } } */
137--
1382.7.4
139
diff --git a/meta/recipes-devtools/gcc/gcc-6.4/backport/0008-x86-Disallow-mindirect-branch-mfunction-return-with-.patch b/meta/recipes-devtools/gcc/gcc-6.4/backport/0008-x86-Disallow-mindirect-branch-mfunction-return-with-.patch
new file mode 100644
index 0000000000..d8a581013a
--- /dev/null
+++ b/meta/recipes-devtools/gcc/gcc-6.4/backport/0008-x86-Disallow-mindirect-branch-mfunction-return-with-.patch
@@ -0,0 +1,304 @@
1From 8e0d9bf93e2e2ec03c544572aef4b03a8e7090f3 Mon Sep 17 00:00:00 2001
2From: "H.J. Lu" <hjl.tools@gmail.com>
3Date: Sat, 13 Jan 2018 18:01:54 -0800
4Subject: [PATCH 08/12] x86: Disallow -mindirect-branch=/-mfunction-return=
5 with -mcmodel=large
6
7Since the thunk function may not be reachable in large code model,
8-mcmodel=large is incompatible with -mindirect-branch=thunk,
9-mindirect-branch=thunk-extern, -mfunction-return=thunk and
10-mfunction-return=thunk-extern. Issue an error when they are used with
11-mcmodel=large.
12
13gcc/
14
15 Backport from mainline
16 2018-01-14 H.J. Lu <hongjiu.lu@intel.com>
17
18 * config/i386/i386.c (ix86_set_indirect_branch_type): Disallow
19 -mcmodel=large with -mindirect-branch=thunk,
20 -mindirect-branch=thunk-extern, -mfunction-return=thunk and
21 -mfunction-return=thunk-extern.
22 * doc/invoke.texi: Document -mcmodel=large is incompatible with
23 -mindirect-branch=thunk, -mindirect-branch=thunk-extern,
24 -mfunction-return=thunk and -mfunction-return=thunk-extern.
25
26gcc/testsuite/
27
28 Backport from mainline
29 2018-01-14 H.J. Lu <hongjiu.lu@intel.com>
30
31 * gcc.target/i386/indirect-thunk-10.c: New test.
32 * gcc.target/i386/indirect-thunk-8.c: Likewise.
33 * gcc.target/i386/indirect-thunk-9.c: Likewise.
34 * gcc.target/i386/indirect-thunk-attr-10.c: Likewise.
35 * gcc.target/i386/indirect-thunk-attr-11.c: Likewise.
36 * gcc.target/i386/indirect-thunk-attr-9.c: Likewise.
37 * gcc.target/i386/ret-thunk-17.c: Likewise.
38 * gcc.target/i386/ret-thunk-18.c: Likewise.
39 * gcc.target/i386/ret-thunk-19.c: Likewise.
40 * gcc.target/i386/ret-thunk-20.c: Likewise.
41 * gcc.target/i386/ret-thunk-21.c: Likewise.
42
43Upstream-Status: Pending
44
45Signed-off-by: Juro Bystricky <juro.bystricky@intel.com>
46
47---
48 gcc/config/i386/i386.c | 26 ++++++++++++++++++++++
49 gcc/doc/invoke.texi | 11 +++++++++
50 gcc/testsuite/gcc.target/i386/indirect-thunk-10.c | 7 ++++++
51 gcc/testsuite/gcc.target/i386/indirect-thunk-8.c | 7 ++++++
52 gcc/testsuite/gcc.target/i386/indirect-thunk-9.c | 7 ++++++
53 .../gcc.target/i386/indirect-thunk-attr-10.c | 9 ++++++++
54 .../gcc.target/i386/indirect-thunk-attr-11.c | 9 ++++++++
55 .../gcc.target/i386/indirect-thunk-attr-9.c | 9 ++++++++
56 gcc/testsuite/gcc.target/i386/ret-thunk-17.c | 7 ++++++
57 gcc/testsuite/gcc.target/i386/ret-thunk-18.c | 8 +++++++
58 gcc/testsuite/gcc.target/i386/ret-thunk-19.c | 8 +++++++
59 gcc/testsuite/gcc.target/i386/ret-thunk-20.c | 9 ++++++++
60 gcc/testsuite/gcc.target/i386/ret-thunk-21.c | 9 ++++++++
61 13 files changed, 126 insertions(+)
62 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-10.c
63 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-8.c
64 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-9.c
65 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-10.c
66 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-11.c
67 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-9.c
68 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-17.c
69 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-18.c
70 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-19.c
71 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-20.c
72 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-21.c
73
74diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
75index eeca7e5..9c038be 100644
76--- a/gcc/config/i386/i386.c
77+++ b/gcc/config/i386/i386.c
78@@ -6389,6 +6389,19 @@ ix86_set_indirect_branch_type (tree fndecl)
79 }
80 else
81 cfun->machine->indirect_branch_type = ix86_indirect_branch;
82+
83+ /* -mcmodel=large is not compatible with -mindirect-branch=thunk
84+ nor -mindirect-branch=thunk-extern. */
85+ if ((ix86_cmodel == CM_LARGE || ix86_cmodel == CM_LARGE_PIC)
86+ && ((cfun->machine->indirect_branch_type
87+ == indirect_branch_thunk_extern)
88+ || (cfun->machine->indirect_branch_type
89+ == indirect_branch_thunk)))
90+ error ("%<-mindirect-branch=%s%> and %<-mcmodel=large%> are not "
91+ "compatible",
92+ ((cfun->machine->indirect_branch_type
93+ == indirect_branch_thunk_extern)
94+ ? "thunk-extern" : "thunk"));
95 }
96
97 if (cfun->machine->function_return_type == indirect_branch_unset)
98@@ -6414,6 +6427,19 @@ ix86_set_indirect_branch_type (tree fndecl)
99 }
100 else
101 cfun->machine->function_return_type = ix86_function_return;
102+
103+ /* -mcmodel=large is not compatible with -mfunction-return=thunk
104+ nor -mfunction-return=thunk-extern. */
105+ if ((ix86_cmodel == CM_LARGE || ix86_cmodel == CM_LARGE_PIC)
106+ && ((cfun->machine->function_return_type
107+ == indirect_branch_thunk_extern)
108+ || (cfun->machine->function_return_type
109+ == indirect_branch_thunk)))
110+ error ("%<-mfunction-return=%s%> and %<-mcmodel=large%> are not "
111+ "compatible",
112+ ((cfun->machine->function_return_type
113+ == indirect_branch_thunk_extern)
114+ ? "thunk-extern" : "thunk"));
115 }
116 }
117
118diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
119index ad9f295..48e827f 100644
120--- a/gcc/doc/invoke.texi
121+++ b/gcc/doc/invoke.texi
122@@ -24230,6 +24230,11 @@ to external call and return thunk provided in a separate object file.
123 You can control this behavior for a specific function by using the
124 function attribute @code{indirect_branch}. @xref{Function Attributes}.
125
126+Note that @option{-mcmodel=large} is incompatible with
127+@option{-mindirect-branch=thunk} nor
128+@option{-mindirect-branch=thunk-extern} since the thunk function may
129+not be reachable in large code model.
130+
131 @item -mfunction-return=@var{choice}
132 @opindex -mfunction-return
133 Convert function return with @var{choice}. The default is @samp{keep},
134@@ -24241,6 +24246,12 @@ object file. You can control this behavior for a specific function by
135 using the function attribute @code{function_return}.
136 @xref{Function Attributes}.
137
138+Note that @option{-mcmodel=large} is incompatible with
139+@option{-mfunction-return=thunk} nor
140+@option{-mfunction-return=thunk-extern} since the thunk function may
141+not be reachable in large code model.
142+
143+
144 @item -mindirect-branch-register
145 @opindex -mindirect-branch-register
146 Force indirect call and jump via register.
147diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-10.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-10.c
148new file mode 100644
149index 0000000..a0674bd
150--- /dev/null
151+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-10.c
152@@ -0,0 +1,7 @@
153+/* { dg-do compile { target { lp64 } } } */
154+/* { dg-options "-O2 -mindirect-branch=thunk-inline -mfunction-return=keep -mcmodel=large" } */
155+
156+void
157+bar (void)
158+{
159+}
160diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-8.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-8.c
161new file mode 100644
162index 0000000..7a80a89
163--- /dev/null
164+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-8.c
165@@ -0,0 +1,7 @@
166+/* { dg-do compile { target { lp64 } } } */
167+/* { dg-options "-O2 -mindirect-branch=thunk -mfunction-return=keep -mcmodel=large" } */
168+
169+void
170+bar (void)
171+{ /* { dg-error "'-mindirect-branch=thunk' and '-mcmodel=large' are not compatible" } */
172+}
173diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-9.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-9.c
174new file mode 100644
175index 0000000..d4d45c5
176--- /dev/null
177+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-9.c
178@@ -0,0 +1,7 @@
179+/* { dg-do compile { target { lp64 } } } */
180+/* { dg-options "-O2 -mindirect-branch=thunk-extern -mfunction-return=keep -mcmodel=large" } */
181+
182+void
183+bar (void)
184+{ /* { dg-error "'-mindirect-branch=thunk-extern' and '-mcmodel=large' are not compatible" } */
185+}
186diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-10.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-10.c
187new file mode 100644
188index 0000000..3a2aead
189--- /dev/null
190+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-10.c
191@@ -0,0 +1,9 @@
192+/* { dg-do compile { target { lp64 } } } */
193+/* { dg-options "-O2 -mindirect-branch=keep -mfunction-return=keep -mcmodel=large" } */
194+/* { dg-additional-options "-fPIC" { target fpic } } */
195+
196+__attribute__ ((indirect_branch("thunk-extern")))
197+void
198+bar (void)
199+{ /* { dg-error "'-mindirect-branch=thunk-extern' and '-mcmodel=large' are not compatible" } */
200+}
201diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-11.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-11.c
202new file mode 100644
203index 0000000..8e52f03
204--- /dev/null
205+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-11.c
206@@ -0,0 +1,9 @@
207+/* { dg-do compile { target { lp64 } } } */
208+/* { dg-options "-O2 -mindirect-branch=keep -mfunction-return=keep -mcmodel=large" } */
209+/* { dg-additional-options "-fPIC" { target fpic } } */
210+
211+__attribute__ ((indirect_branch("thunk-inline")))
212+void
213+bar (void)
214+{
215+}
216diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-9.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-9.c
217new file mode 100644
218index 0000000..bdaa4f6
219--- /dev/null
220+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-9.c
221@@ -0,0 +1,9 @@
222+/* { dg-do compile { target { lp64 } } } */
223+/* { dg-options "-O2 -mindirect-branch=keep -mfunction-return=keep -mcmodel=large" } */
224+/* { dg-additional-options "-fPIC" { target fpic } } */
225+
226+__attribute__ ((indirect_branch("thunk")))
227+void
228+bar (void)
229+{ /* { dg-error "'-mindirect-branch=thunk' and '-mcmodel=large' are not compatible" } */
230+}
231diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-17.c b/gcc/testsuite/gcc.target/i386/ret-thunk-17.c
232new file mode 100644
233index 0000000..0605e2c
234--- /dev/null
235+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-17.c
236@@ -0,0 +1,7 @@
237+/* { dg-do compile { target { lp64 } } } */
238+/* { dg-options "-O2 -mfunction-return=thunk -mindirect-branch=keep -mcmodel=large" } */
239+
240+void
241+bar (void)
242+{ /* { dg-error "'-mfunction-return=thunk' and '-mcmodel=large' are not compatible" } */
243+}
244diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-18.c b/gcc/testsuite/gcc.target/i386/ret-thunk-18.c
245new file mode 100644
246index 0000000..307019d
247--- /dev/null
248+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-18.c
249@@ -0,0 +1,8 @@
250+/* { dg-do compile { target { lp64 } } } */
251+/* { dg-options "-O2 -mfunction-return=thunk-extern -mindirect-branch=keep -mcmodel=large" } */
252+/* { dg-additional-options "-fPIC" { target fpic } } */
253+
254+void
255+bar (void)
256+{ /* { dg-error "'-mfunction-return=thunk-extern' and '-mcmodel=large' are not compatible" } */
257+}
258diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-19.c b/gcc/testsuite/gcc.target/i386/ret-thunk-19.c
259new file mode 100644
260index 0000000..772617f
261--- /dev/null
262+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-19.c
263@@ -0,0 +1,8 @@
264+/* { dg-do compile { target { lp64 } } } */
265+/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=keep -mcmodel=large" } */
266+
267+__attribute__ ((function_return("thunk")))
268+void
269+bar (void)
270+{ /* { dg-error "'-mfunction-return=thunk' and '-mcmodel=large' are not compatible" } */
271+}
272diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-20.c b/gcc/testsuite/gcc.target/i386/ret-thunk-20.c
273new file mode 100644
274index 0000000..1e9f9bd
275--- /dev/null
276+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-20.c
277@@ -0,0 +1,9 @@
278+/* { dg-do compile { target { lp64 } } } */
279+/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=keep -mcmodel=large" } */
280+/* { dg-additional-options "-fPIC" { target fpic } } */
281+
282+__attribute__ ((function_return("thunk-extern")))
283+void
284+bar (void)
285+{ /* { dg-error "'-mfunction-return=thunk-extern' and '-mcmodel=large' are not compatible" } */
286+}
287diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-21.c b/gcc/testsuite/gcc.target/i386/ret-thunk-21.c
288new file mode 100644
289index 0000000..eea07f7
290--- /dev/null
291+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-21.c
292@@ -0,0 +1,9 @@
293+/* { dg-do compile { target { lp64 } } } */
294+/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=keep -mcmodel=large" } */
295+/* { dg-additional-options "-fPIC" { target fpic } } */
296+
297+__attribute__ ((function_return("thunk-inline")))
298+void
299+bar (void)
300+{
301+}
302--
3032.7.4
304
diff --git a/meta/recipes-devtools/gcc/gcc-6.4/backport/0009-Use-INVALID_REGNUM-in-indirect-thunk-processing.patch b/meta/recipes-devtools/gcc/gcc-6.4/backport/0009-Use-INVALID_REGNUM-in-indirect-thunk-processing.patch
new file mode 100644
index 0000000000..7364a2c36a
--- /dev/null
+++ b/meta/recipes-devtools/gcc/gcc-6.4/backport/0009-Use-INVALID_REGNUM-in-indirect-thunk-processing.patch
@@ -0,0 +1,126 @@
1From 3eff2adada2b1667b0e76496fa559e0c248ecd84 Mon Sep 17 00:00:00 2001
2From: uros <uros@138bc75d-0d04-0410-961f-82ee72b054a4>
3Date: Thu, 25 Jan 2018 19:39:01 +0000
4Subject: [PATCH 09/12] Use INVALID_REGNUM in indirect thunk processing
5
6 Backport from mainline
7 2018-01-17 Uros Bizjak <ubizjak@gmail.com>
8
9 * config/i386/i386.c (indirect_thunk_name): Declare regno
10 as unsigned int. Compare regno with INVALID_REGNUM.
11 (output_indirect_thunk): Ditto.
12 (output_indirect_thunk_function): Ditto.
13 (ix86_code_end): Declare regno as unsigned int. Use INVALID_REGNUM
14 in the call to output_indirect_thunk_function.
15
16git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gcc-7-branch@257067 138bc75d-0d04-0410-961f-82ee72b054a4
17
18Upstream-Status: Pending
19
20Signed-off-by: Juro Bystricky <juro.bystricky@intel.com>
21
22---
23 gcc/config/i386/i386.c | 30 +++++++++++++++---------------
24 1 file changed, 15 insertions(+), 15 deletions(-)
25
26diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
27index 9c038be..4012657 100644
28--- a/gcc/config/i386/i386.c
29+++ b/gcc/config/i386/i386.c
30@@ -11087,16 +11087,16 @@ static int indirect_thunks_bnd_used;
31 /* Fills in the label name that should be used for the indirect thunk. */
32
33 static void
34-indirect_thunk_name (char name[32], int regno, bool need_bnd_p,
35- bool ret_p)
36+indirect_thunk_name (char name[32], unsigned int regno,
37+ bool need_bnd_p, bool ret_p)
38 {
39- if (regno >= 0 && ret_p)
40+ if (regno != INVALID_REGNUM && ret_p)
41 gcc_unreachable ();
42
43 if (USE_HIDDEN_LINKONCE)
44 {
45 const char *bnd = need_bnd_p ? "_bnd" : "";
46- if (regno >= 0)
47+ if (regno != INVALID_REGNUM)
48 {
49 const char *reg_prefix;
50 if (LEGACY_INT_REGNO_P (regno))
51@@ -11114,7 +11114,7 @@ indirect_thunk_name (char name[32], int regno, bool need_bnd_p,
52 }
53 else
54 {
55- if (regno >= 0)
56+ if (regno != INVALID_REGNUM)
57 {
58 if (need_bnd_p)
59 ASM_GENERATE_INTERNAL_LABEL (name, "LITBR", regno);
60@@ -11166,7 +11166,7 @@ indirect_thunk_name (char name[32], int regno, bool need_bnd_p,
61 */
62
63 static void
64-output_indirect_thunk (bool need_bnd_p, int regno)
65+output_indirect_thunk (bool need_bnd_p, unsigned int regno)
66 {
67 char indirectlabel1[32];
68 char indirectlabel2[32];
69@@ -11196,7 +11196,7 @@ output_indirect_thunk (bool need_bnd_p, int regno)
70
71 ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel2);
72
73- if (regno >= 0)
74+ if (regno != INVALID_REGNUM)
75 {
76 /* MOV. */
77 rtx xops[2];
78@@ -11220,12 +11220,12 @@ output_indirect_thunk (bool need_bnd_p, int regno)
79 }
80
81 /* Output a funtion with a call and return thunk for indirect branch.
82- If BND_P is true, the BND prefix is needed. If REGNO != -1, the
83- function address is in REGNO. Otherwise, the function address is
84+ If BND_P is true, the BND prefix is needed. If REGNO != INVALID_REGNUM,
85+ the function address is in REGNO. Otherwise, the function address is
86 on the top of stack. */
87
88 static void
89-output_indirect_thunk_function (bool need_bnd_p, int regno)
90+output_indirect_thunk_function (bool need_bnd_p, unsigned int regno)
91 {
92 char name[32];
93 tree decl;
94@@ -11274,7 +11274,7 @@ output_indirect_thunk_function (bool need_bnd_p, int regno)
95 ASM_OUTPUT_LABEL (asm_out_file, name);
96 }
97
98- if (regno < 0)
99+ if (regno == INVALID_REGNUM)
100 {
101 /* Create alias for __x86.return_thunk/__x86.return_thunk_bnd. */
102 char alias[32];
103@@ -11348,16 +11348,16 @@ static void
104 ix86_code_end (void)
105 {
106 rtx xops[2];
107- int regno;
108+ unsigned int regno;
109
110 if (indirect_thunk_needed)
111- output_indirect_thunk_function (false, -1);
112+ output_indirect_thunk_function (false, INVALID_REGNUM);
113 if (indirect_thunk_bnd_needed)
114- output_indirect_thunk_function (true, -1);
115+ output_indirect_thunk_function (true, INVALID_REGNUM);
116
117 for (regno = FIRST_REX_INT_REG; regno <= LAST_REX_INT_REG; regno++)
118 {
119- int i = regno - FIRST_REX_INT_REG + LAST_INT_REG + 1;
120+ unsigned int i = regno - FIRST_REX_INT_REG + LAST_INT_REG + 1;
121 if ((indirect_thunks_used & (1 << i)))
122 output_indirect_thunk_function (false, regno);
123
124--
1252.7.4
126
diff --git a/meta/recipes-devtools/gcc/gcc-6.4/backport/0010-i386-Pass-INVALID_REGNUM-as-invalid-register-number.patch b/meta/recipes-devtools/gcc/gcc-6.4/backport/0010-i386-Pass-INVALID_REGNUM-as-invalid-register-number.patch
new file mode 100644
index 0000000000..080d741983
--- /dev/null
+++ b/meta/recipes-devtools/gcc/gcc-6.4/backport/0010-i386-Pass-INVALID_REGNUM-as-invalid-register-number.patch
@@ -0,0 +1,46 @@
1From c4300d9ad683e693c90d02d4f1b13183bf2d4acc Mon Sep 17 00:00:00 2001
2From: hjl <hjl@138bc75d-0d04-0410-961f-82ee72b054a4>
3Date: Fri, 2 Feb 2018 16:47:02 +0000
4Subject: [PATCH 10/12] i386: Pass INVALID_REGNUM as invalid register number
5
6 Backport from mainline
7 * config/i386/i386.c (ix86_output_function_return): Pass
8 INVALID_REGNUM, instead of -1, as invalid register number to
9 indirect_thunk_name and output_indirect_thunk.
10
11git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gcc-7-branch@257341 138bc75d-0d04-0410-961f-82ee72b054a4
12
13Upstream-Status: Pending
14
15Signed-off-by: Juro Bystricky <juro.bystricky@intel.com>
16
17---
18 gcc/config/i386/i386.c | 5 +++--
19 1 file changed, 3 insertions(+), 2 deletions(-)
20
21diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
22index 4012657..66502ee 100644
23--- a/gcc/config/i386/i386.c
24+++ b/gcc/config/i386/i386.c
25@@ -28056,7 +28056,8 @@ ix86_output_function_return (bool long_p)
26 {
27 bool need_thunk = (cfun->machine->function_return_type
28 == indirect_branch_thunk);
29- indirect_thunk_name (thunk_name, -1, need_bnd_p, true);
30+ indirect_thunk_name (thunk_name, INVALID_REGNUM, need_bnd_p,
31+ true);
32 if (need_bnd_p)
33 {
34 indirect_thunk_bnd_needed |= need_thunk;
35@@ -28069,7 +28070,7 @@ ix86_output_function_return (bool long_p)
36 }
37 }
38 else
39- output_indirect_thunk (need_bnd_p, -1);
40+ output_indirect_thunk (need_bnd_p, INVALID_REGNUM);
41
42 return "";
43 }
44--
452.7.4
46
diff --git a/meta/recipes-devtools/gcc/gcc-6.4/backport/0011-i386-Update-mfunction-return-for-return-with-pop.patch b/meta/recipes-devtools/gcc/gcc-6.4/backport/0011-i386-Update-mfunction-return-for-return-with-pop.patch
new file mode 100644
index 0000000000..3b036fbe18
--- /dev/null
+++ b/meta/recipes-devtools/gcc/gcc-6.4/backport/0011-i386-Update-mfunction-return-for-return-with-pop.patch
@@ -0,0 +1,453 @@
1From b3a2269c7884378a9afd394ac7e669aab0443b57 Mon Sep 17 00:00:00 2001
2From: hjl <hjl@138bc75d-0d04-0410-961f-82ee72b054a4>
3Date: Mon, 26 Feb 2018 15:29:30 +0000
4Subject: [PATCH 11/12] i386: Update -mfunction-return= for return with pop
5
6When -mfunction-return= is used, simple_return_pop_internal should pop
7return address into ECX register, adjust stack by bytes to pop from stack
8and jump to the return thunk via ECX register.
9
10Revision 257992 removed the bool argument from ix86_output_indirect_jmp.
11Update comments to reflect it.
12
13Tested on i686 and x86-64.
14
15 Backport from mainline
16 * config/i386/i386.c (ix86_output_indirect_jmp): Update comments.
17
18 PR target/84530
19 * config/i386/i386-protos.h (ix86_output_indirect_jmp): Remove
20 the bool argument.
21 (ix86_output_indirect_function_return): New prototype.
22 (ix86_split_simple_return_pop_internal): Likewise.
23 * config/i386/i386.c (indirect_return_via_cx): New.
24 (indirect_return_via_cx_bnd): Likewise.
25 (indirect_thunk_name): Handle return va CX_REG.
26 (output_indirect_thunk_function): Create alias for
27 __x86_return_thunk_[re]cx and __x86_return_thunk_[re]cx_bnd.
28 (ix86_output_indirect_jmp): Remove the bool argument.
29 (ix86_output_indirect_function_return): New function.
30 (ix86_split_simple_return_pop_internal): Likewise.
31 * config/i386/i386.md (*indirect_jump): Don't pass false
32 to ix86_output_indirect_jmp.
33 (*tablejump_1): Likewise.
34 (simple_return_pop_internal): Change it to define_insn_and_split.
35 Call ix86_split_simple_return_pop_internal to split it for
36 -mfunction-return=.
37 (simple_return_indirect_internal): Call
38 ix86_output_indirect_function_return instead of
39 ix86_output_indirect_jmp.
40
41gcc/testsuite/
42
43 Backport from mainline
44 PR target/84530
45 * gcc.target/i386/ret-thunk-22.c: New test.
46 * gcc.target/i386/ret-thunk-23.c: Likewise.
47 * gcc.target/i386/ret-thunk-24.c: Likewise.
48 * gcc.target/i386/ret-thunk-25.c: Likewise.
49 * gcc.target/i386/ret-thunk-26.c: Likewise.
50
51Upstream-Status: Pending
52
53Signed-off-by: Juro Bystricky <juro.bystricky@intel.com>
54
55---
56 gcc/config/i386/i386-protos.h | 4 +-
57 gcc/config/i386/i386.c | 127 +++++++++++++++++++++++----
58 gcc/config/i386/i386.md | 11 ++-
59 gcc/testsuite/gcc.target/i386/ret-thunk-22.c | 15 ++++
60 gcc/testsuite/gcc.target/i386/ret-thunk-23.c | 15 ++++
61 gcc/testsuite/gcc.target/i386/ret-thunk-24.c | 15 ++++
62 gcc/testsuite/gcc.target/i386/ret-thunk-25.c | 15 ++++
63 gcc/testsuite/gcc.target/i386/ret-thunk-26.c | 40 +++++++++
64 8 files changed, 222 insertions(+), 20 deletions(-)
65 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-22.c
66 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-23.c
67 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-24.c
68 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-25.c
69 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-26.c
70
71diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h
72index 620d70e..c7a0ccb5 100644
73--- a/gcc/config/i386/i386-protos.h
74+++ b/gcc/config/i386/i386-protos.h
75@@ -311,8 +311,10 @@ extern enum attr_cpu ix86_schedule;
76 #endif
77
78 extern const char * ix86_output_call_insn (rtx_insn *insn, rtx call_op);
79-extern const char * ix86_output_indirect_jmp (rtx call_op, bool ret_p);
80+extern const char * ix86_output_indirect_jmp (rtx call_op);
81 extern const char * ix86_output_function_return (bool long_p);
82+extern const char * ix86_output_indirect_function_return (rtx ret_op);
83+extern void ix86_split_simple_return_pop_internal (rtx);
84 extern bool ix86_operands_ok_for_move_multiple (rtx *operands, bool load,
85 enum machine_mode mode);
86
87diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
88index 66502ee..21c3c18 100644
89--- a/gcc/config/i386/i386.c
90+++ b/gcc/config/i386/i386.c
91@@ -11080,6 +11080,12 @@ static int indirect_thunks_used;
92 by call and return thunks functions with the BND prefix. */
93 static int indirect_thunks_bnd_used;
94
95+/* True if return thunk function via CX is needed. */
96+static bool indirect_return_via_cx;
97+/* True if return thunk function via CX with the BND prefix is
98+ needed. */
99+static bool indirect_return_via_cx_bnd;
100+
101 #ifndef INDIRECT_LABEL
102 # define INDIRECT_LABEL "LIND"
103 #endif
104@@ -11090,12 +11096,13 @@ static void
105 indirect_thunk_name (char name[32], unsigned int regno,
106 bool need_bnd_p, bool ret_p)
107 {
108- if (regno != INVALID_REGNUM && ret_p)
109+ if (regno != INVALID_REGNUM && regno != CX_REG && ret_p)
110 gcc_unreachable ();
111
112 if (USE_HIDDEN_LINKONCE)
113 {
114 const char *bnd = need_bnd_p ? "_bnd" : "";
115+ const char *ret = ret_p ? "return" : "indirect";
116 if (regno != INVALID_REGNUM)
117 {
118 const char *reg_prefix;
119@@ -11103,14 +11110,11 @@ indirect_thunk_name (char name[32], unsigned int regno,
120 reg_prefix = TARGET_64BIT ? "r" : "e";
121 else
122 reg_prefix = "";
123- sprintf (name, "__x86_indirect_thunk%s_%s%s",
124- bnd, reg_prefix, reg_names[regno]);
125+ sprintf (name, "__x86_%s_thunk%s_%s%s",
126+ ret, bnd, reg_prefix, reg_names[regno]);
127 }
128 else
129- {
130- const char *ret = ret_p ? "return" : "indirect";
131- sprintf (name, "__x86_%s_thunk%s", ret, bnd);
132- }
133+ sprintf (name, "__x86_%s_thunk%s", ret, bnd);
134 }
135 else
136 {
137@@ -11274,9 +11278,23 @@ output_indirect_thunk_function (bool need_bnd_p, unsigned int regno)
138 ASM_OUTPUT_LABEL (asm_out_file, name);
139 }
140
141+ /* Create alias for __x86_return_thunk/__x86_return_thunk_bnd or
142+ __x86_return_thunk_ecx/__x86_return_thunk_ecx_bnd. */
143+ bool need_alias;
144 if (regno == INVALID_REGNUM)
145+ need_alias = true;
146+ else if (regno == CX_REG)
147+ {
148+ if (need_bnd_p)
149+ need_alias = indirect_return_via_cx_bnd;
150+ else
151+ need_alias = indirect_return_via_cx;
152+ }
153+ else
154+ need_alias = false;
155+
156+ if (need_alias)
157 {
158- /* Create alias for __x86.return_thunk/__x86.return_thunk_bnd. */
159 char alias[32];
160
161 indirect_thunk_name (alias, regno, need_bnd_p, true);
162@@ -28019,18 +28037,17 @@ ix86_output_indirect_branch (rtx call_op, const char *xasm,
163 else
164 ix86_output_indirect_branch_via_push (call_op, xasm, sibcall_p);
165 }
166-/* Output indirect jump. CALL_OP is the jump target. Jump is a
167- function return if RET_P is true. */
168+
169+/* Output indirect jump. CALL_OP is the jump target. */
170
171 const char *
172-ix86_output_indirect_jmp (rtx call_op, bool ret_p)
173+ix86_output_indirect_jmp (rtx call_op)
174 {
175 if (cfun->machine->indirect_branch_type != indirect_branch_keep)
176 {
177- /* We can't have red-zone if this isn't a function return since
178- "call" in the indirect thunk pushes the return address onto
179- stack, destroying red-zone. */
180- if (!ret_p && ix86_red_zone_size != 0)
181+ /* We can't have red-zone since "call" in the indirect thunk
182+ pushes the return address onto stack, destroying red-zone. */
183+ if (ix86_red_zone_size != 0)
184 gcc_unreachable ();
185
186 ix86_output_indirect_branch (call_op, "%0", true);
187@@ -28081,6 +28098,86 @@ ix86_output_function_return (bool long_p)
188 return "rep%; ret";
189 }
190
191+/* Output indirect function return. RET_OP is the function return
192+ target. */
193+
194+const char *
195+ix86_output_indirect_function_return (rtx ret_op)
196+{
197+ if (cfun->machine->function_return_type != indirect_branch_keep)
198+ {
199+ char thunk_name[32];
200+ bool need_bnd_p = ix86_bnd_prefixed_insn_p (current_output_insn);
201+ unsigned int regno = REGNO (ret_op);
202+ gcc_assert (regno == CX_REG);
203+
204+ if (cfun->machine->function_return_type
205+ != indirect_branch_thunk_inline)
206+ {
207+ bool need_thunk = (cfun->machine->function_return_type
208+ == indirect_branch_thunk);
209+ indirect_thunk_name (thunk_name, regno, need_bnd_p, true);
210+ if (need_bnd_p)
211+ {
212+ if (need_thunk)
213+ {
214+ indirect_return_via_cx_bnd = true;
215+ indirect_thunks_bnd_used |= 1 << CX_REG;
216+ }
217+ fprintf (asm_out_file, "\tbnd jmp\t%s\n", thunk_name);
218+ }
219+ else
220+ {
221+ if (need_thunk)
222+ {
223+ indirect_return_via_cx = true;
224+ indirect_thunks_used |= 1 << CX_REG;
225+ }
226+ fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name);
227+ }
228+ }
229+ else
230+ output_indirect_thunk (need_bnd_p, regno);
231+
232+ return "";
233+ }
234+ else
235+ return "%!jmp\t%A0";
236+}
237+
238+/* Split simple return with popping POPC bytes from stack to indirect
239+ branch with stack adjustment . */
240+
241+void
242+ix86_split_simple_return_pop_internal (rtx popc)
243+{
244+ struct machine_function *m = cfun->machine;
245+ rtx ecx = gen_rtx_REG (SImode, CX_REG);
246+ rtx_insn *insn;
247+
248+ /* There is no "pascal" calling convention in any 64bit ABI. */
249+ gcc_assert (!TARGET_64BIT);
250+
251+ insn = emit_insn (gen_pop (ecx));
252+ m->fs.cfa_offset -= UNITS_PER_WORD;
253+ m->fs.sp_offset -= UNITS_PER_WORD;
254+
255+ rtx x = plus_constant (Pmode, stack_pointer_rtx, UNITS_PER_WORD);
256+ x = gen_rtx_SET (stack_pointer_rtx, x);
257+ add_reg_note (insn, REG_CFA_ADJUST_CFA, x);
258+ add_reg_note (insn, REG_CFA_REGISTER, gen_rtx_SET (ecx, pc_rtx));
259+ RTX_FRAME_RELATED_P (insn) = 1;
260+
261+ x = gen_rtx_PLUS (Pmode, stack_pointer_rtx, popc);
262+ x = gen_rtx_SET (stack_pointer_rtx, x);
263+ insn = emit_insn (x);
264+ add_reg_note (insn, REG_CFA_ADJUST_CFA, x);
265+ RTX_FRAME_RELATED_P (insn) = 1;
266+
267+ /* Now return address is in ECX. */
268+ emit_jump_insn (gen_simple_return_indirect_internal (ecx));
269+}
270+
271 /* Output the assembly for a call instruction. */
272
273 const char *
274diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
275index 05a88ff..857466a 100644
276--- a/gcc/config/i386/i386.md
277+++ b/gcc/config/i386/i386.md
278@@ -11813,7 +11813,7 @@
279 (define_insn "*indirect_jump"
280 [(set (pc) (match_operand:W 0 "indirect_branch_operand" "rBw"))]
281 ""
282- "* return ix86_output_indirect_jmp (operands[0], false);"
283+ "* return ix86_output_indirect_jmp (operands[0]);"
284 [(set (attr "type")
285 (if_then_else (match_test "(cfun->machine->indirect_branch_type
286 != indirect_branch_keep)")
287@@ -11868,7 +11868,7 @@
288 [(set (pc) (match_operand:W 0 "indirect_branch_operand" "rBw"))
289 (use (label_ref (match_operand 1)))]
290 ""
291- "* return ix86_output_indirect_jmp (operands[0], false);"
292+ "* return ix86_output_indirect_jmp (operands[0]);"
293 [(set (attr "type")
294 (if_then_else (match_test "(cfun->machine->indirect_branch_type
295 != indirect_branch_keep)")
296@@ -12520,11 +12520,14 @@
297 (set_attr "prefix_rep" "1")
298 (set_attr "modrm" "0")])
299
300-(define_insn "simple_return_pop_internal"
301+(define_insn_and_split "simple_return_pop_internal"
302 [(simple_return)
303 (use (match_operand:SI 0 "const_int_operand"))]
304 "reload_completed"
305 "%!ret\t%0"
306+ "&& cfun->machine->function_return_type != indirect_branch_keep"
307+ [(const_int 0)]
308+ "ix86_split_simple_return_pop_internal (operands[0]); DONE;"
309 [(set_attr "length" "3")
310 (set_attr "atom_unit" "jeu")
311 (set_attr "length_immediate" "2")
312@@ -12535,7 +12538,7 @@
313 [(simple_return)
314 (use (match_operand:SI 0 "register_operand" "r"))]
315 "reload_completed"
316- "* return ix86_output_indirect_jmp (operands[0], true);"
317+ "* return ix86_output_indirect_function_return (operands[0]);"
318 [(set (attr "type")
319 (if_then_else (match_test "(cfun->machine->indirect_branch_type
320 != indirect_branch_keep)")
321diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-22.c b/gcc/testsuite/gcc.target/i386/ret-thunk-22.c
322new file mode 100644
323index 0000000..89e086d
324--- /dev/null
325+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-22.c
326@@ -0,0 +1,15 @@
327+/* PR target/r84530 */
328+/* { dg-do compile { target ia32 } } */
329+/* { dg-options "-O2 -mfunction-return=thunk" } */
330+
331+struct s { _Complex unsigned short x; };
332+struct s gs = { 100 + 200i };
333+struct s __attribute__((noinline)) foo (void) { return gs; }
334+
335+/* { dg-final { scan-assembler-times "popl\[\\t \]*%ecx" 1 } } */
336+/* { dg-final { scan-assembler "lea\[l\]?\[\\t \]*4\\(%esp\\), %esp" } } */
337+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk_ecx" } } */
338+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
339+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
340+/* { dg-final { scan-assembler {\tpause} } } */
341+/* { dg-final { scan-assembler {\tlfence} } } */
342diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-23.c b/gcc/testsuite/gcc.target/i386/ret-thunk-23.c
343new file mode 100644
344index 0000000..43f0cca
345--- /dev/null
346+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-23.c
347@@ -0,0 +1,15 @@
348+/* PR target/r84530 */
349+/* { dg-do compile { target ia32 } } */
350+/* { dg-options "-O2 -mfunction-return=thunk-extern" } */
351+
352+struct s { _Complex unsigned short x; };
353+struct s gs = { 100 + 200i };
354+struct s __attribute__((noinline)) foo (void) { return gs; }
355+
356+/* { dg-final { scan-assembler-times "popl\[\\t \]*%ecx" 1 } } */
357+/* { dg-final { scan-assembler "lea\[l\]?\[\\t \]*4\\(%esp\\), %esp" } } */
358+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk_ecx" } } */
359+/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
360+/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
361+/* { dg-final { scan-assembler-not {\tpause} } } */
362+/* { dg-final { scan-assembler-not {\tlfence} } } */
363diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-24.c b/gcc/testsuite/gcc.target/i386/ret-thunk-24.c
364new file mode 100644
365index 0000000..8729e35
366--- /dev/null
367+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-24.c
368@@ -0,0 +1,15 @@
369+/* PR target/r84530 */
370+/* { dg-do compile { target ia32 } } */
371+/* { dg-options "-O2 -mfunction-return=thunk-inline" } */
372+
373+struct s { _Complex unsigned short x; };
374+struct s gs = { 100 + 200i };
375+struct s __attribute__((noinline)) foo (void) { return gs; }
376+
377+/* { dg-final { scan-assembler-times "popl\[\\t \]*%ecx" 1 } } */
378+/* { dg-final { scan-assembler "lea\[l\]?\[\\t \]*4\\(%esp\\), %esp" } } */
379+/* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_return_thunk_ecx" } } */
380+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
381+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
382+/* { dg-final { scan-assembler {\tpause} } } */
383+/* { dg-final { scan-assembler {\tlfence} } } */
384diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-25.c b/gcc/testsuite/gcc.target/i386/ret-thunk-25.c
385new file mode 100644
386index 0000000..f73553c
387--- /dev/null
388+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-25.c
389@@ -0,0 +1,15 @@
390+/* PR target/r84530 */
391+/* { dg-do compile { target ia32 } } */
392+/* { dg-options "-O2 -mfunction-return=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
393+
394+struct s { _Complex unsigned short x; };
395+struct s gs = { 100 + 200i };
396+struct s __attribute__((noinline)) foo (void) { return gs; }
397+
398+/* { dg-final { scan-assembler-times "popl\[\\t \]*%ecx" 1 } } */
399+/* { dg-final { scan-assembler "lea\[l\]?\[\\t \]*4\\(%esp\\), %esp" } } */
400+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk_bnd_ecx" } } */
401+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
402+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
403+/* { dg-final { scan-assembler {\tpause} } } */
404+/* { dg-final { scan-assembler {\tlfence} } } */
405diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-26.c b/gcc/testsuite/gcc.target/i386/ret-thunk-26.c
406new file mode 100644
407index 0000000..9144e98
408--- /dev/null
409+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-26.c
410@@ -0,0 +1,40 @@
411+/* PR target/r84530 */
412+/* { dg-do run } */
413+/* { dg-options "-Os -mfunction-return=thunk" } */
414+
415+struct S { int i; };
416+__attribute__((const, noinline, noclone))
417+struct S foo (int x)
418+{
419+ struct S s;
420+ s.i = x;
421+ return s;
422+}
423+
424+int a[2048], b[2048], c[2048], d[2048];
425+struct S e[2048];
426+
427+__attribute__((noinline, noclone)) void
428+bar (void)
429+{
430+ int i;
431+ for (i = 0; i < 1024; i++)
432+ {
433+ e[i] = foo (i);
434+ a[i+2] = a[i] + a[i+1];
435+ b[10] = b[10] + i;
436+ c[i] = c[2047 - i];
437+ d[i] = d[i + 1];
438+ }
439+}
440+
441+int
442+main ()
443+{
444+ int i;
445+ bar ();
446+ for (i = 0; i < 1024; i++)
447+ if (e[i].i != i)
448+ __builtin_abort ();
449+ return 0;
450+}
451--
4522.7.4
453
diff --git a/meta/recipes-devtools/gcc/gcc-6.4/backport/0012-i386-Add-TARGET_INDIRECT_BRANCH_REGISTER.patch b/meta/recipes-devtools/gcc/gcc-6.4/backport/0012-i386-Add-TARGET_INDIRECT_BRANCH_REGISTER.patch
new file mode 100644
index 0000000000..b50ac5cb02
--- /dev/null
+++ b/meta/recipes-devtools/gcc/gcc-6.4/backport/0012-i386-Add-TARGET_INDIRECT_BRANCH_REGISTER.patch
@@ -0,0 +1,1004 @@
1From 7ba192d11a43d24ce427a3dfce0ad0592bd52830 Mon Sep 17 00:00:00 2001
2From: hjl <hjl@138bc75d-0d04-0410-961f-82ee72b054a4>
3Date: Mon, 26 Feb 2018 17:00:46 +0000
4Subject: [PATCH 12/12] i386: Add TARGET_INDIRECT_BRANCH_REGISTER
5
6For
7
8---
9struct C {
10 virtual ~C();
11 virtual void f();
12};
13
14void
15f (C *p)
16{
17 p->f();
18 p->f();
19}
20---
21
22-mindirect-branch=thunk-extern -O2 on x86-64 GNU/Linux generates:
23
24_Z1fP1C:
25.LFB0:
26 .cfi_startproc
27 pushq %rbx
28 .cfi_def_cfa_offset 16
29 .cfi_offset 3, -16
30 movq (%rdi), %rax
31 movq %rdi, %rbx
32 jmp .LIND1
33.LIND0:
34 pushq 16(%rax)
35 jmp __x86_indirect_thunk
36.LIND1:
37 call .LIND0
38 movq (%rbx), %rax
39 movq %rbx, %rdi
40 popq %rbx
41 .cfi_def_cfa_offset 8
42 movq 16(%rax), %rax
43 jmp __x86_indirect_thunk_rax
44 .cfi_endproc
45
46x86-64 is supposed to have asynchronous unwind tables by default, but
47there is nothing that reflects the change in the (relative) frame
48address after .LIND0. That region really has to be moved outside of
49the .cfi_startproc/.cfi_endproc bracket.
50
51This patch adds TARGET_INDIRECT_BRANCH_REGISTER to force indirect
52branch via register whenever -mindirect-branch= is used. Now,
53-mindirect-branch=thunk-extern -O2 on x86-64 GNU/Linux generates:
54
55_Z1fP1C:
56.LFB0:
57 .cfi_startproc
58 pushq %rbx
59 .cfi_def_cfa_offset 16
60 .cfi_offset 3, -16
61 movq (%rdi), %rax
62 movq %rdi, %rbx
63 movq 16(%rax), %rax
64 call __x86_indirect_thunk_rax
65 movq (%rbx), %rax
66 movq %rbx, %rdi
67 popq %rbx
68 .cfi_def_cfa_offset 8
69 movq 16(%rax), %rax
70 jmp __x86_indirect_thunk_rax
71 .cfi_endproc
72
73so that "-mindirect-branch=thunk-extern" is equivalent to
74"-mindirect-branch=thunk-extern -mindirect-branch-register", which is
75used by Linux kernel.
76
77gcc/
78
79 Backport from mainline
80 PR target/84039
81 * config/i386/constraints.md (Bs): Replace
82 ix86_indirect_branch_register with
83 TARGET_INDIRECT_BRANCH_REGISTER.
84 (Bw): Likewise.
85 * config/i386/i386.md (indirect_jump): Likewise.
86 (tablejump): Likewise.
87 (*sibcall_memory): Likewise.
88 (*sibcall_value_memory): Likewise.
89 Peepholes of indirect call and jump via memory: Likewise.
90 (*sibcall_GOT_32): Disallowed for TARGET_INDIRECT_BRANCH_REGISTER.
91 (*sibcall_value_GOT_32): Likewise.
92 * config/i386/predicates.md (indirect_branch_operand): Likewise.
93 (GOT_memory_operand): Likewise.
94 (call_insn_operand): Likewise.
95 (sibcall_insn_operand): Likewise.
96 (GOT32_symbol_operand): Likewise.
97 * config/i386/i386.h (TARGET_INDIRECT_BRANCH_REGISTER): New.
98
99gcc/testsuite/
100
101 Backport from mainline
102 PR target/84039
103 * gcc.target/i386/indirect-thunk-1.c: Updated.
104 * gcc.target/i386/indirect-thunk-2.c: Likewise.
105 * gcc.target/i386/indirect-thunk-3.c: Likewise.
106 * gcc.target/i386/indirect-thunk-4.c: Likewise.
107 * gcc.target/i386/indirect-thunk-5.c: Likewise.
108 * gcc.target/i386/indirect-thunk-6.c: Likewise.
109 * gcc.target/i386/indirect-thunk-7.c: Likewise.
110 * gcc.target/i386/indirect-thunk-attr-1.c: Likewise.
111 * gcc.target/i386/indirect-thunk-attr-2.c: Likewise.
112 * gcc.target/i386/indirect-thunk-attr-3.c: Likewise.
113 * gcc.target/i386/indirect-thunk-attr-4.c: Likewise.
114 * gcc.target/i386/indirect-thunk-attr-5.c: Likewise.
115 * gcc.target/i386/indirect-thunk-attr-6.c: Likewise.
116 * gcc.target/i386/indirect-thunk-attr-7.c: Likewise.
117 * gcc.target/i386/indirect-thunk-bnd-1.c: Likewise.
118 * gcc.target/i386/indirect-thunk-bnd-2.c: Likewise.
119 * gcc.target/i386/indirect-thunk-bnd-3.c: Likewise.
120 * gcc.target/i386/indirect-thunk-bnd-4.c: Likewise.
121 * gcc.target/i386/indirect-thunk-extern-1.c: Likewise.
122 * gcc.target/i386/indirect-thunk-extern-2.c: Likewise.
123 * gcc.target/i386/indirect-thunk-extern-3.c: Likewise.
124 * gcc.target/i386/indirect-thunk-extern-4.c: Likewise.
125 * gcc.target/i386/indirect-thunk-extern-5.c: Likewise.
126 * gcc.target/i386/indirect-thunk-extern-6.c: Likewise.
127 * gcc.target/i386/indirect-thunk-extern-7.c: Likewise.
128 * gcc.target/i386/indirect-thunk-inline-1.c: Likewise.
129 * gcc.target/i386/indirect-thunk-inline-2.c: Likewise.
130 * gcc.target/i386/indirect-thunk-inline-3.c: Likewise.
131 * gcc.target/i386/indirect-thunk-inline-4.c: Likewise.
132 * gcc.target/i386/indirect-thunk-inline-5.c: Likewise.
133 * gcc.target/i386/indirect-thunk-inline-6.c: Likewise.
134 * gcc.target/i386/indirect-thunk-inline-7.c: Likewise.
135 * gcc.target/i386/ret-thunk-9.c: Likewise.
136 * gcc.target/i386/ret-thunk-10.c: Likewise.
137 * gcc.target/i386/ret-thunk-11.c: Likewise.
138 * gcc.target/i386/ret-thunk-12.c: Likewise.
139 * gcc.target/i386/ret-thunk-13.c: Likewise.
140 * gcc.target/i386/ret-thunk-14.c: Likewise.
141 * gcc.target/i386/ret-thunk-15.c: Likewise.
142
143Upstream-Status: Pending
144
145Signed-off-by: Juro Bystricky <juro.bystricky@intel.com>
146
147---
148 gcc/config/i386/constraints.md | 4 ++--
149 gcc/config/i386/i386.h | 5 ++++
150 gcc/config/i386/i386.md | 28 +++++++++++++---------
151 gcc/config/i386/predicates.md | 6 ++---
152 gcc/testsuite/gcc.target/i386/indirect-thunk-1.c | 5 ++--
153 gcc/testsuite/gcc.target/i386/indirect-thunk-2.c | 5 ++--
154 gcc/testsuite/gcc.target/i386/indirect-thunk-3.c | 5 ++--
155 gcc/testsuite/gcc.target/i386/indirect-thunk-4.c | 5 ++--
156 gcc/testsuite/gcc.target/i386/indirect-thunk-5.c | 6 +++--
157 gcc/testsuite/gcc.target/i386/indirect-thunk-6.c | 12 ++++++----
158 gcc/testsuite/gcc.target/i386/indirect-thunk-7.c | 5 ++--
159 .../gcc.target/i386/indirect-thunk-attr-1.c | 5 ++--
160 .../gcc.target/i386/indirect-thunk-attr-2.c | 5 ++--
161 .../gcc.target/i386/indirect-thunk-attr-3.c | 3 +--
162 .../gcc.target/i386/indirect-thunk-attr-4.c | 3 +--
163 .../gcc.target/i386/indirect-thunk-attr-5.c | 9 ++++---
164 .../gcc.target/i386/indirect-thunk-attr-6.c | 9 ++++---
165 .../gcc.target/i386/indirect-thunk-attr-7.c | 5 ++--
166 .../gcc.target/i386/indirect-thunk-bnd-1.c | 6 ++---
167 .../gcc.target/i386/indirect-thunk-bnd-2.c | 6 ++---
168 .../gcc.target/i386/indirect-thunk-bnd-3.c | 5 ++--
169 .../gcc.target/i386/indirect-thunk-bnd-4.c | 7 +++---
170 .../gcc.target/i386/indirect-thunk-extern-1.c | 5 ++--
171 .../gcc.target/i386/indirect-thunk-extern-2.c | 5 ++--
172 .../gcc.target/i386/indirect-thunk-extern-3.c | 9 ++++---
173 .../gcc.target/i386/indirect-thunk-extern-4.c | 6 ++---
174 .../gcc.target/i386/indirect-thunk-extern-5.c | 6 +++--
175 .../gcc.target/i386/indirect-thunk-extern-6.c | 8 +++----
176 .../gcc.target/i386/indirect-thunk-extern-7.c | 5 ++--
177 .../gcc.target/i386/indirect-thunk-inline-1.c | 2 +-
178 .../gcc.target/i386/indirect-thunk-inline-2.c | 2 +-
179 .../gcc.target/i386/indirect-thunk-inline-3.c | 2 +-
180 .../gcc.target/i386/indirect-thunk-inline-4.c | 2 +-
181 .../gcc.target/i386/indirect-thunk-inline-5.c | 3 ++-
182 .../gcc.target/i386/indirect-thunk-inline-6.c | 3 ++-
183 .../gcc.target/i386/indirect-thunk-inline-7.c | 4 ++--
184 gcc/testsuite/gcc.target/i386/ret-thunk-10.c | 9 +++----
185 gcc/testsuite/gcc.target/i386/ret-thunk-11.c | 9 +++----
186 gcc/testsuite/gcc.target/i386/ret-thunk-12.c | 8 +++----
187 gcc/testsuite/gcc.target/i386/ret-thunk-13.c | 5 ++--
188 gcc/testsuite/gcc.target/i386/ret-thunk-14.c | 7 +++---
189 gcc/testsuite/gcc.target/i386/ret-thunk-15.c | 7 +++---
190 gcc/testsuite/gcc.target/i386/ret-thunk-9.c | 13 ++++------
191 43 files changed, 128 insertions(+), 141 deletions(-)
192
193diff --git a/gcc/config/i386/constraints.md b/gcc/config/i386/constraints.md
194index 9204c8e..ef684a9 100644
195--- a/gcc/config/i386/constraints.md
196+++ b/gcc/config/i386/constraints.md
197@@ -172,7 +172,7 @@
198
199 (define_constraint "Bs"
200 "@internal Sibcall memory operand."
201- (ior (and (not (match_test "ix86_indirect_branch_register"))
202+ (ior (and (not (match_test "TARGET_INDIRECT_BRANCH_REGISTER"))
203 (not (match_test "TARGET_X32"))
204 (match_operand 0 "sibcall_memory_operand"))
205 (and (match_test "TARGET_X32 && Pmode == DImode")
206@@ -180,7 +180,7 @@
207
208 (define_constraint "Bw"
209 "@internal Call memory operand."
210- (ior (and (not (match_test "ix86_indirect_branch_register"))
211+ (ior (and (not (match_test "TARGET_INDIRECT_BRANCH_REGISTER"))
212 (not (match_test "TARGET_X32"))
213 (match_operand 0 "memory_operand"))
214 (and (match_test "TARGET_X32 && Pmode == DImode")
215diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
216index b34bc11..1816d71 100644
217--- a/gcc/config/i386/i386.h
218+++ b/gcc/config/i386/i386.h
219@@ -2676,6 +2676,11 @@ extern void debug_dispatch_window (int);
220 #define TARGET_RECIP_VEC_DIV ((recip_mask & RECIP_MASK_VEC_DIV) != 0)
221 #define TARGET_RECIP_VEC_SQRT ((recip_mask & RECIP_MASK_VEC_SQRT) != 0)
222
223+
224+#define TARGET_INDIRECT_BRANCH_REGISTER \
225+ (ix86_indirect_branch_register \
226+ || cfun->machine->indirect_branch_type != indirect_branch_keep)
227+
228 #define IX86_HLE_ACQUIRE (1 << 16)
229 #define IX86_HLE_RELEASE (1 << 17)
230
231diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
232index 857466a..6a6dc26 100644
233--- a/gcc/config/i386/i386.md
234+++ b/gcc/config/i386/i386.md
235@@ -11805,7 +11805,7 @@
236 [(set (pc) (match_operand 0 "indirect_branch_operand"))]
237 ""
238 {
239- if (TARGET_X32 || ix86_indirect_branch_register)
240+ if (TARGET_X32 || TARGET_INDIRECT_BRANCH_REGISTER)
241 operands[0] = convert_memory_address (word_mode, operands[0]);
242 cfun->machine->has_local_indirect_jump = true;
243 })
244@@ -11859,7 +11859,7 @@
245 OPTAB_DIRECT);
246 }
247
248- if (TARGET_X32 || ix86_indirect_branch_register)
249+ if (TARGET_X32 || TARGET_INDIRECT_BRANCH_REGISTER)
250 operands[0] = convert_memory_address (word_mode, operands[0]);
251 cfun->machine->has_local_indirect_jump = true;
252 })
253@@ -12029,7 +12029,10 @@
254 (match_operand:SI 0 "register_no_elim_operand" "U")
255 (match_operand:SI 1 "GOT32_symbol_operand"))))
256 (match_operand 2))]
257- "!TARGET_MACHO && !TARGET_64BIT && SIBLING_CALL_P (insn)"
258+ "!TARGET_MACHO
259+ && !TARGET_64BIT
260+ && !TARGET_INDIRECT_BRANCH_REGISTER
261+ && SIBLING_CALL_P (insn)"
262 {
263 rtx fnaddr = gen_rtx_PLUS (Pmode, operands[0], operands[1]);
264 fnaddr = gen_const_mem (Pmode, fnaddr);
265@@ -12048,7 +12051,7 @@
266 [(call (mem:QI (match_operand:W 0 "memory_operand" "m"))
267 (match_operand 1))
268 (unspec [(const_int 0)] UNSPEC_PEEPSIB)]
269- "!TARGET_X32 && !ix86_indirect_branch_register"
270+ "!TARGET_X32 && !TARGET_INDIRECT_BRANCH_REGISTER"
271 "* return ix86_output_call_insn (insn, operands[0]);"
272 [(set_attr "type" "call")])
273
274@@ -12058,7 +12061,7 @@
275 (call (mem:QI (match_dup 0))
276 (match_operand 3))]
277 "!TARGET_X32
278- && !ix86_indirect_branch_register
279+ && !TARGET_INDIRECT_BRANCH_REGISTER
280 && SIBLING_CALL_P (peep2_next_insn (1))
281 && !reg_mentioned_p (operands[0],
282 CALL_INSN_FUNCTION_USAGE (peep2_next_insn (1)))"
283@@ -12073,7 +12076,7 @@
284 (call (mem:QI (match_dup 0))
285 (match_operand 3))]
286 "!TARGET_X32
287- && !ix86_indirect_branch_register
288+ && !TARGET_INDIRECT_BRANCH_REGISTER
289 && SIBLING_CALL_P (peep2_next_insn (2))
290 && !reg_mentioned_p (operands[0],
291 CALL_INSN_FUNCTION_USAGE (peep2_next_insn (2)))"
292@@ -12171,7 +12174,7 @@
293 (match_operand:W 1 "memory_operand"))
294 (set (pc) (match_dup 0))]
295 "!TARGET_X32
296- && !ix86_indirect_branch_register
297+ && !TARGET_INDIRECT_BRANCH_REGISTER
298 && peep2_reg_dead_p (2, operands[0])"
299 [(set (pc) (match_dup 1))])
300
301@@ -12229,7 +12232,10 @@
302 (match_operand:SI 1 "register_no_elim_operand" "U")
303 (match_operand:SI 2 "GOT32_symbol_operand"))))
304 (match_operand 3)))]
305- "!TARGET_MACHO && !TARGET_64BIT && SIBLING_CALL_P (insn)"
306+ "!TARGET_MACHO
307+ && !TARGET_64BIT
308+ && !TARGET_INDIRECT_BRANCH_REGISTER
309+ && SIBLING_CALL_P (insn)"
310 {
311 rtx fnaddr = gen_rtx_PLUS (Pmode, operands[1], operands[2]);
312 fnaddr = gen_const_mem (Pmode, fnaddr);
313@@ -12250,7 +12256,7 @@
314 (call (mem:QI (match_operand:W 1 "memory_operand" "m"))
315 (match_operand 2)))
316 (unspec [(const_int 0)] UNSPEC_PEEPSIB)]
317- "!TARGET_X32 && !ix86_indirect_branch_register"
318+ "!TARGET_X32 && !TARGET_INDIRECT_BRANCH_REGISTER"
319 "* return ix86_output_call_insn (insn, operands[1]);"
320 [(set_attr "type" "callv")])
321
322@@ -12261,7 +12267,7 @@
323 (call (mem:QI (match_dup 0))
324 (match_operand 3)))]
325 "!TARGET_X32
326- && !ix86_indirect_branch_register
327+ && !TARGET_INDIRECT_BRANCH_REGISTER
328 && SIBLING_CALL_P (peep2_next_insn (1))
329 && !reg_mentioned_p (operands[0],
330 CALL_INSN_FUNCTION_USAGE (peep2_next_insn (1)))"
331@@ -12278,7 +12284,7 @@
332 (call (mem:QI (match_dup 0))
333 (match_operand 3)))]
334 "!TARGET_X32
335- && !ix86_indirect_branch_register
336+ && !TARGET_INDIRECT_BRANCH_REGISTER
337 && SIBLING_CALL_P (peep2_next_insn (2))
338 && !reg_mentioned_p (operands[0],
339 CALL_INSN_FUNCTION_USAGE (peep2_next_insn (2)))"
340diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md
341index d1f0a7d..5f8a98f 100644
342--- a/gcc/config/i386/predicates.md
343+++ b/gcc/config/i386/predicates.md
344@@ -593,7 +593,7 @@
345 ;; Test for a valid operand for indirect branch.
346 (define_predicate "indirect_branch_operand"
347 (ior (match_operand 0 "register_operand")
348- (and (not (match_test "ix86_indirect_branch_register"))
349+ (and (not (match_test "TARGET_INDIRECT_BRANCH_REGISTER"))
350 (not (match_test "TARGET_X32"))
351 (match_operand 0 "memory_operand"))))
352
353@@ -637,7 +637,7 @@
354 (ior (match_test "constant_call_address_operand
355 (op, mode == VOIDmode ? mode : Pmode)")
356 (match_operand 0 "call_register_no_elim_operand")
357- (and (not (match_test "ix86_indirect_branch_register"))
358+ (and (not (match_test "TARGET_INDIRECT_BRANCH_REGISTER"))
359 (ior (and (not (match_test "TARGET_X32"))
360 (match_operand 0 "memory_operand"))
361 (and (match_test "TARGET_X32 && Pmode == DImode")
362@@ -648,7 +648,7 @@
363 (ior (match_test "constant_call_address_operand
364 (op, mode == VOIDmode ? mode : Pmode)")
365 (match_operand 0 "register_no_elim_operand")
366- (and (not (match_test "ix86_indirect_branch_register"))
367+ (and (not (match_test "TARGET_INDIRECT_BRANCH_REGISTER"))
368 (ior (and (not (match_test "TARGET_X32"))
369 (match_operand 0 "sibcall_memory_operand"))
370 (and (match_test "TARGET_X32 && Pmode == DImode")
371diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c
372index 60d0988..6e94d2c 100644
373--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c
374+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c
375@@ -11,9 +11,8 @@ male_indirect_jump (long offset)
376 dispatch(offset);
377 }
378
379-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
380-/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
381-/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
382+/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*_?dispatch" { target *-*-linux* } } } */
383+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" } } */
384 /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
385 /* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
386 /* { dg-final { scan-assembler {\tpause} } } */
387diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c
388index aac7516..3c46707 100644
389--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c
390+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c
391@@ -11,9 +11,8 @@ male_indirect_jump (long offset)
392 dispatch[offset](offset);
393 }
394
395-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
396-/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
397-/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
398+/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*_?dispatch" { target *-*-linux* } } } */
399+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" } } */
400 /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
401 /* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
402 /* { dg-final { scan-assembler {\tpause} } } */
403diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c
404index 9e24a38..2c7fb52 100644
405--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c
406+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c
407@@ -12,9 +12,8 @@ male_indirect_jump (long offset)
408 return 0;
409 }
410
411-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
412-/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
413-/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
414+/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*_?dispatch" { target *-*-linux* } } } */
415+/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" } } */
416 /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
417 /* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
418 /* { dg-final { scan-assembler {\tpause} } } */
419diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c
420index 127b5d9..0d3f895 100644
421--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c
422+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c
423@@ -12,9 +12,8 @@ male_indirect_jump (long offset)
424 return 0;
425 }
426
427-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
428-/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
429-/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
430+/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*_?dispatch" { target *-*-linux* } } } */
431+/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" } } */
432 /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
433 /* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
434 /* { dg-final { scan-assembler {\tpause} } } */
435diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c
436index fcaa18d..fb26c00 100644
437--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c
438+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-5.c
439@@ -9,8 +9,10 @@ foo (void)
440 bar ();
441 }
442
443-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */
444-/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" } } */
445+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" { target x32 } } } */
446+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target x32 } } } */
447+/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*bar@GOT" { target { ! x32 } } } } */
448+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target { ! x32 } } } } */
449 /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
450 /* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
451 /* { dg-final { scan-assembler {\tpause} } } */
452diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c
453index e464928..aa03fbd 100644
454--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c
455+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-6.c
456@@ -10,9 +10,13 @@ foo (void)
457 return 0;
458 }
459
460-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */
461-/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" } } */
462-/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */
463-/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */
464+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" { target x32 } } } */
465+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target x32 } } } */
466+/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 { target x32 } } } */
467+/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 { target x32 } } } */
468+/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*bar@GOT" { target { ! x32 } } } } */
469+/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target { ! x32 } } } } */
470+/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
471+/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
472 /* { dg-final { scan-assembler {\tpause} } } */
473 /* { dg-final { scan-assembler {\tlfence} } } */
474diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c
475index 17c2d0f..3c72036 100644
476--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c
477+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c
478@@ -35,9 +35,8 @@ bar (int i)
479 }
480 }
481
482-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { { ! x32 } && *-*-linux* } } } } */
483-/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
484-/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
485+/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target *-*-linux* } } } */
486+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" } } */
487 /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
488 /* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
489 /* { dg-final { scan-assembler {\tpause} } } */
490diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c
491index 9194ccf..7106407 100644
492--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c
493+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c
494@@ -14,9 +14,8 @@ male_indirect_jump (long offset)
495 dispatch(offset);
496 }
497
498-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
499-/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
500-/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
501+/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*_?dispatch" { target *-*-linux* } } } */
502+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" } } */
503 /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
504 /* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
505 /* { dg-final { scan-assembler {\tpause} } } */
506diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c
507index e51f261..27c7e5b 100644
508--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c
509+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c
510@@ -12,9 +12,8 @@ male_indirect_jump (long offset)
511 dispatch[offset](offset);
512 }
513
514-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
515-/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
516-/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
517+/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*_?dispatch" { target *-*-linux* } } } */
518+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" } } */
519 /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
520 /* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
521 /* { dg-final { scan-assembler {\tpause} } } */
522diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c
523index 4aeec18..89a2bac 100644
524--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c
525+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c
526@@ -14,10 +14,9 @@ male_indirect_jump (long offset)
527 return 0;
528 }
529
530-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
531+/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*_?dispatch" { target *-*-linux* } } } */
532 /* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */
533 /* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */
534 /* { dg-final { scan-assembler {\tpause} } } */
535 /* { dg-final { scan-assembler {\tlfence} } } */
536 /* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
537-/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
538diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c
539index ac0e599..3eb83c3 100644
540--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c
541+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c
542@@ -13,10 +13,9 @@ male_indirect_jump (long offset)
543 return 0;
544 }
545
546-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
547+/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*_?dispatch" { target *-*-linux* } } } */
548 /* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */
549 /* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */
550 /* { dg-final { scan-assembler {\tpause} } } */
551 /* { dg-final { scan-assembler {\tlfence} } } */
552 /* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
553-/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
554diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c
555index 573cf1e..0098dd1 100644
556--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c
557+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c
558@@ -14,9 +14,8 @@ male_indirect_jump (long offset)
559 return 0;
560 }
561
562-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
563-/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
564-/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
565-/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
566-/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
567+/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*_?dispatch" { target *-*-linux* } } } */
568+/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" } } */
569 /* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
570+/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
571+/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
572diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c
573index b2b37fc..ece8de1 100644
574--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c
575+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c
576@@ -13,9 +13,8 @@ male_indirect_jump (long offset)
577 return 0;
578 }
579
580-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
581-/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
582-/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
583-/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
584-/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
585+/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*_?dispatch" { target *-*-linux* } } } */
586+/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" } } */
587 /* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
588+/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
589+/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
590diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c
591index 4a43e19..d53fc88 100644
592--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c
593+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c
594@@ -36,9 +36,8 @@ bar (int i)
595 }
596 }
597
598-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { { ! x32 } && *-*-linux* } } } } */
599-/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
600-/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" } } */
601+/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target *-*-linux* } } } */
602+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" } } */
603 /* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
604 /* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
605 /* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
606diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c
607index ac84ab6..73d16ba 100644
608--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c
609+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c
610@@ -10,9 +10,9 @@ foo (void)
611 dispatch (buf);
612 }
613
614-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
615-/* { dg-final { scan-assembler "pushq\[ \t\]%rax" { target x32 } } } */
616-/* { dg-final { scan-assembler "bnd jmp\[ \t\]*__x86_indirect_thunk_bnd" } } */
617+/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*_?dispatch" { target *-*-linux* } } } */
618+/* { dg-final { scan-assembler "bnd jmp\[ \t\]*__x86_indirect_thunk_bnd_rax" { target lp64 } } } */
619+/* { dg-final { scan-assembler "bnd call\[ \t\]*__x86_indirect_thunk_bnd_eax" { target ia32 } } } */
620 /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
621 /* { dg-final { scan-assembler "bnd call\[ \t\]*\.LIND" } } */
622 /* { dg-final { scan-assembler "bnd ret" } } */
623diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c
624index ce655e8..856751a 100644
625--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c
626+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c
627@@ -11,10 +11,8 @@ foo (void)
628 return 0;
629 }
630
631-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
632-/* { dg-final { scan-assembler "pushq\[ \t\]%rax" { target x32 } } } */
633-/* { dg-final { scan-assembler "bnd jmp\[ \t\]*__x86_indirect_thunk_bnd" } } */
634-/* { dg-final { scan-assembler "bnd jmp\[ \t\]*\.LIND" } } */
635+/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*_?dispatch" { target *-*-linux* } } } */
636+/* { dg-final { scan-assembler "bnd call\[ \t\]*__x86_indirect_thunk_bnd_(r|e)ax" } } */
637 /* { dg-final { scan-assembler "bnd call\[ \t\]*\.LIND" } } */
638 /* { dg-final { scan-assembler "bnd ret" } } */
639 /* { dg-final { scan-assembler {\tpause} } } */
640diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c
641index d34485a..42312f6 100644
642--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c
643+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c
644@@ -10,8 +10,9 @@ foo (void)
645 bar (buf);
646 }
647
648-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */
649-/* { dg-final { scan-assembler "bnd jmp\[ \t\]*__x86_indirect_thunk_bnd" } } */
650+/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*bar@GOT" } } */
651+/* { dg-final { scan-assembler "bnd jmp\[ \t\]*__x86_indirect_thunk_bnd_rax" { target lp64 } } } */
652+/* { dg-final { scan-assembler "bnd call\[ \t\]*__x86_indirect_thunk_bnd_eax" { target ia32 } } } */
653 /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
654 /* { dg-final { scan-assembler "bnd call\[ \t\]*\.LIND" } } */
655 /* { dg-final { scan-assembler "bnd ret" } } */
656diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c
657index 0e19830..c8ca102 100644
658--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c
659+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c
660@@ -11,10 +11,9 @@ foo (void)
661 return 0;
662 }
663
664-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */
665-/* { dg-final { scan-assembler "bnd jmp\[ \t\]*__x86_indirect_thunk" } } */
666-/* { dg-final { scan-assembler "bnd jmp\[ \t\]*\.LIND" } } */
667-/* { dg-final { scan-assembler-times "bnd call\[ \t\]*\.LIND" 2 } } */
668+/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*bar@GOT" } } */
669+/* { dg-final { scan-assembler "bnd call\[ \t\]*__x86_indirect_thunk_bnd_(r|e)ax" } } */
670+/* { dg-final { scan-assembler-times "bnd call\[ \t\]*\.LIND" 1 } } */
671 /* { dg-final { scan-assembler "bnd ret" } } */
672 /* { dg-final { scan-assembler {\tpause} } } */
673 /* { dg-final { scan-assembler {\tlfence} } } */
674diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c
675index 579441f..c09dd0a 100644
676--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c
677+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c
678@@ -11,9 +11,8 @@ male_indirect_jump (long offset)
679 dispatch(offset);
680 }
681
682-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
683-/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
684-/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
685+/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*_?dispatch" { target *-*-linux* } } } */
686+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" } } */
687 /* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
688 /* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
689 /* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
690diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c
691index c92e6f2..826425a 100644
692--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c
693+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c
694@@ -11,9 +11,8 @@ male_indirect_jump (long offset)
695 dispatch[offset](offset);
696 }
697
698-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
699-/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
700-/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
701+/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*_?dispatch" { target *-*-linux* } } } */
702+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" } } */
703 /* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
704 /* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
705 /* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
706diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c
707index d9964c2..3856268 100644
708--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c
709+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c
710@@ -12,9 +12,8 @@ male_indirect_jump (long offset)
711 return 0;
712 }
713
714-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
715-/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
716-/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
717-/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
718-/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
719+/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*_?dispatch" { target *-*-linux* } } } */
720+/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" } } */
721 /* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
722+/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
723+/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
724diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c
725index d4dca4d..1ae49b1 100644
726--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c
727+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c
728@@ -12,9 +12,7 @@ male_indirect_jump (long offset)
729 return 0;
730 }
731
732-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
733-/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
734-/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
735-/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
736 /* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
737+/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*_?dispatch" { target *-*-linux* } } } */
738+/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" } } */
739 /* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
740diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c
741index 5c07e02..5328239 100644
742--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c
743+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c
744@@ -9,8 +9,10 @@ foo (void)
745 bar ();
746 }
747
748-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */
749-/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" } } */
750+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" { target x32 } } } */
751+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target x32 } } } */
752+/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*bar@GOT" { target { ! x32 } } } } */
753+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target { ! x32 } } } } */
754 /* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
755 /* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
756 /* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
757diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c
758index 3eb4406..8ae4348 100644
759--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c
760+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c
761@@ -10,8 +10,8 @@ foo (void)
762 return 0;
763 }
764
765-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */
766-/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 } } */
767-/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 } } */
768-/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" } } */
769+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" { target x32 } } } */
770+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target x32 } } } */
771+/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*bar@GOT" { target { ! x32 } } } } */
772+/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target { ! x32 } } } } */
773 /* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
774diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c
775index aece938..2b9a33e 100644
776--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c
777+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c
778@@ -35,9 +35,8 @@ bar (int i)
779 }
780 }
781
782-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { { ! x32 } && *-*-linux* } } } } */
783-/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
784-/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
785+/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target *-*-linux* } } } */
786+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" } } */
787 /* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
788 /* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
789 /* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
790diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c
791index 3aba5e8..869d904 100644
792--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c
793+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c
794@@ -11,7 +11,7 @@ male_indirect_jump (long offset)
795 dispatch(offset);
796 }
797
798-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
799+/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*_?dispatch" { target *-*-linux* } } } */
800 /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
801 /* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
802 /* { dg-final { scan-assembler {\tpause} } } */
803diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c
804index 0f0181d..c5c16ed 100644
805--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c
806+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c
807@@ -11,7 +11,7 @@ male_indirect_jump (long offset)
808 dispatch[offset](offset);
809 }
810
811-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
812+/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*_?dispatch" { target *-*-linux* } } } */
813 /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
814 /* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
815 /* { dg-final { scan-assembler {\tpause} } } */
816diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c
817index 2eef6f3..4a63ebe 100644
818--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c
819+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c
820@@ -12,7 +12,7 @@ male_indirect_jump (long offset)
821 return 0;
822 }
823
824-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
825+/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*_?dispatch" { target *-*-linux* } } } */
826 /* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */
827 /* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */
828 /* { dg-final { scan-assembler-times {\tpause} 1 } } */
829diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c
830index e825a10..a395ffc 100644
831--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c
832+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c
833@@ -12,7 +12,7 @@ male_indirect_jump (long offset)
834 return 0;
835 }
836
837-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
838+/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*_?dispatch" { target *-*-linux* } } } */
839 /* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */
840 /* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */
841 /* { dg-final { scan-assembler-times {\tpause} 1 } } */
842diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c
843index c6d77e1..21cbfd3 100644
844--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c
845+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c
846@@ -9,7 +9,8 @@ foo (void)
847 bar ();
848 }
849
850-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */
851+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" { target x32 } } } */
852+/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*bar@GOT" { target { ! x32 } } } } */
853 /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
854 /* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
855 /* { dg-final { scan-assembler {\tpause} } } */
856diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c
857index 6454827..d1300f1 100644
858--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c
859+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c
860@@ -10,7 +10,8 @@ foo (void)
861 return 0;
862 }
863
864-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" } } */
865+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*bar@GOT" { target x32 } } } */
866+/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*bar@GOT" { target { ! x32 } } } } */
867 /* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */
868 /* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */
869 /* { dg-final { scan-assembler-times {\tpause} 1 } } */
870diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c
871index c67066c..ea00924 100644
872--- a/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c
873+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c
874@@ -35,8 +35,8 @@ bar (int i)
875 }
876 }
877
878-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { { ! x32 } && *-*-linux* } } } } */
879-/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
880+/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target *-*-linux* } } } */
881+/* { dg-final { scan-assembler-not "pushq\[ \t\]%(r|e)ax" } } */
882 /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
883 /* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
884 /* { dg-final { scan-assembler {\tpause} } } */
885diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-10.c b/gcc/testsuite/gcc.target/i386/ret-thunk-10.c
886index e6fea84..af9023a 100644
887--- a/gcc/testsuite/gcc.target/i386/ret-thunk-10.c
888+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-10.c
889@@ -15,9 +15,6 @@ foo (void)
890 /* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_return_thunk" } } */
891 /* { dg-final { scan-assembler-times {\tpause} 2 } } */
892 /* { dg-final { scan-assembler-times {\tlfence} 2 } } */
893-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { { ! x32 } && *-*-linux* } } } } */
894-/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
895-/* { dg-final { scan-assembler "__x86_indirect_thunk:" { target { ! x32 } } } } */
896-/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target { x32 } } } } */
897-/* { dg-final { scan-assembler "__x86_indirect_thunk_(r|e)ax:" { target { x32 } } } } */
898-/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
899+/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" } } */
900+/* { dg-final { scan-assembler "__x86_indirect_thunk_(r|e)ax:" } } */
901+/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" } } */
902diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-11.c b/gcc/testsuite/gcc.target/i386/ret-thunk-11.c
903index e239ec4..ba467c5 100644
904--- a/gcc/testsuite/gcc.target/i386/ret-thunk-11.c
905+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-11.c
906@@ -15,9 +15,6 @@ foo (void)
907 /* { dg-final { scan-assembler-times {\tlfence} 1 } } */
908 /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
909 /* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
910-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { { ! x32 } && *-*-linux* } } } } */
911-/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
912-/* { dg-final { scan-assembler "__x86_indirect_thunk:" { target { ! x32 } } } } */
913-/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target { x32 } } } } */
914-/* { dg-final { scan-assembler "__x86_indirect_thunk_(r|e)ax:" { target { x32 } } } } */
915-/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
916+/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" } } */
917+/* { dg-final { scan-assembler "__x86_indirect_thunk_(r|e)ax:" } } */
918+/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" } } */
919diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-12.c b/gcc/testsuite/gcc.target/i386/ret-thunk-12.c
920index fa31813..43e57ca 100644
921--- a/gcc/testsuite/gcc.target/i386/ret-thunk-12.c
922+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-12.c
923@@ -15,8 +15,6 @@ foo (void)
924 /* { dg-final { scan-assembler-times {\tlfence} 1 } } */
925 /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
926 /* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
927-/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
928-/* { dg-final { scan-assembler "__x86_indirect_thunk:" { target { ! x32 } } } } */
929-/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target { x32 } } } } */
930-/* { dg-final { scan-assembler "__x86_indirect_thunk_(r|e)ax:" { target { x32 } } } } */
931-/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
932+/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" } } */
933+/* { dg-final { scan-assembler "__x86_indirect_thunk_(r|e)ax:" } } */
934+/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" } } */
935diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-13.c b/gcc/testsuite/gcc.target/i386/ret-thunk-13.c
936index fd5b41f..55f156c 100644
937--- a/gcc/testsuite/gcc.target/i386/ret-thunk-13.c
938+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-13.c
939@@ -14,9 +14,8 @@ foo (void)
940 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_return_thunk" } } */
941 /* { dg-final { scan-assembler-times {\tpause} 2 } } */
942 /* { dg-final { scan-assembler-times {\tlfence} 2 } } */
943-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { { ! x32 } && *-*-linux* } } } } */
944 /* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 3 } } */
945 /* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 3 } } */
946 /* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_indirect_thunk" } } */
947-/* { dg-final { scan-assembler-not "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target { x32 } } } } */
948-/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
949+/* { dg-final { scan-assembler-not "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" } } */
950+/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" } } */
951diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-14.c b/gcc/testsuite/gcc.target/i386/ret-thunk-14.c
952index d606373..1c79043 100644
953--- a/gcc/testsuite/gcc.target/i386/ret-thunk-14.c
954+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-14.c
955@@ -16,7 +16,6 @@ foo (void)
956 /* { dg-final { scan-assembler-not "jmp\[ \t\]*__x86_return_thunk" } } */
957 /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
958 /* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
959-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { { ! x32 } && *-*-linux* } } } } */
960-/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
961-/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target { x32 } } } } */
962-/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
963+/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*_?bar" { target *-*-linux* } } } */
964+/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" } } */
965+/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" } } */
966diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-15.c b/gcc/testsuite/gcc.target/i386/ret-thunk-15.c
967index 75e45e2..58aba31 100644
968--- a/gcc/testsuite/gcc.target/i386/ret-thunk-15.c
969+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-15.c
970@@ -16,7 +16,6 @@ foo (void)
971 /* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
972 /* { dg-final { scan-assembler-times {\tpause} 1 } } */
973 /* { dg-final { scan-assembler-times {\tlfence} 1 } } */
974-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { { ! x32 } && *-*-linux* } } } } */
975-/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
976-/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
977-/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
978+/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*_?bar" { target *-*-linux* } } } */
979+/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" } } */
980+/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" } } */
981diff --git a/gcc/testsuite/gcc.target/i386/ret-thunk-9.c b/gcc/testsuite/gcc.target/i386/ret-thunk-9.c
982index d1db41c..d2df8b8 100644
983--- a/gcc/testsuite/gcc.target/i386/ret-thunk-9.c
984+++ b/gcc/testsuite/gcc.target/i386/ret-thunk-9.c
985@@ -14,11 +14,8 @@ foo (void)
986 /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
987 /* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
988 /* { dg-final { scan-assembler "__x86_indirect_thunk:" } } */
989-/* { dg-final { scan-assembler-times {\tpause} 1 { target { ! x32 } } } } */
990-/* { dg-final { scan-assembler-times {\tlfence} 1 { target { ! x32 } } } } */
991-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?bar" { target { { ! x32 } && *-*-linux* } } } } */
992-/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
993-/* { dg-final { scan-assembler-times {\tpause} 2 { target { x32 } } } } */
994-/* { dg-final { scan-assembler-times {\tlfence} 2 { target { x32 } } } } */
995-/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target { x32 } } } } */
996-/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
997+/* { dg-final { scan-assembler "mov(?:l|q)\[ \t\]*_?bar" { target *-*-linux* } } } */
998+/* { dg-final { scan-assembler-times {\tpause} 2 } } */
999+/* { dg-final { scan-assembler-times {\tlfence} 2 } } */
1000+/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" } } */
1001+/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" } } */
1002--
10032.7.4
1004