Project import/gcc - Diff e1bb95cf02...6eac6210dc

... ... --- a/.abf.yml
... ... +++ b/.abf.yml
... ... @@ -1,3 +1,3 @@
1 1
sources:
2 2
  gcc-x32-seed.tar.xz: c656c8f0d0f17a94f0a21ec65ba6633b56e6ea47
3
  gcc-linaro-5.4-2017.05.tar.xz: 3376af91629331fc4c3344d5aa0301c124b964db
3
  gcc-linaro-5.5-2017.10.tar.xz: f31ffa46619262a227727eab5ae5d7569cd3989c
view file @ 6eac6210dc
... ... --- /dev/null
... ... +++ b/0001-i386-Move-struct-ix86_frame-to-machine_function.diff
... ... @@ -0,0 +1,239 @@
1
From 11a3b9034935080b9996caf07fca6353309006f1 Mon Sep 17 00:00:00 2001
2
From: hjl <hjl@138bc75d-0d04-0410-961f-82ee72b054a4>
3
Date: Mon, 15 Jan 2018 11:27:24 +0000
4
Subject: [PATCH 1/9] i386: Move struct ix86_frame to machine_function
5
6
Make ix86_frame available to i386 code generation.  This is needed to
7
backport the patch set of -mindirect-branch= to mitigate variant #2 of
8
the speculative execution vulnerabilities on x86 processors identified
9
by CVE-2017-5715, aka Spectre.
10
11
	Backport from mainline
12
	* config/i386/i386.c (ix86_frame): Moved to ...
13
	* config/i386/i386.h (ix86_frame): Here.
14
	(machine_function): Add frame.
15
	* config/i386/i386.c (ix86_compute_frame_layout): Repace the
16
	frame argument with &cfun->machine->frame.
17
	(ix86_can_use_return_insn_p): Don't pass &frame to
18
	ix86_compute_frame_layout.  Copy frame from cfun->machine->frame.
19
	(ix86_can_eliminate): Likewise.
20
	(ix86_expand_prologue): Likewise.
21
	(ix86_expand_epilogue): Likewise.
22
	(ix86_expand_split_stack_prologue): Likewise.
23
24
25
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gcc-7-branch@256691 138bc75d-0d04-0410-961f-82ee72b054a4
26
---
27
 src/gcc/config/i386/i386.c |   68 ++++++++-------------------------------------
28
 src/gcc/config/i386/i386.h |   53 ++++++++++++++++++++++++++++++++++-
29
 2 files changed, 65 insertions(+), 56 deletions(-)
30
31
Index: b/src/gcc/config/i386/i386.c
32
===================================================================
33
--- a/src/gcc/config/i386/i386.c
34
+++ b/src/gcc/config/i386/i386.c
35
@@ -2306,53 +2306,6 @@ struct GTY(()) stack_local_entry {
36
   struct stack_local_entry *next;
37
 };
38
 
39
-/* Structure describing stack frame layout.
40
-   Stack grows downward:
41
-
42
-   [arguments]
43
-					<- ARG_POINTER
44
-   saved pc
45
-
46
-   saved static chain			if ix86_static_chain_on_stack
47
-
48
-   saved frame pointer			if frame_pointer_needed
49
-					<- HARD_FRAME_POINTER
50
-   [saved regs]
51
-					<- regs_save_offset
52
-   [padding0]
53
-
54
-   [saved SSE regs]
55
-					<- sse_regs_save_offset
56
-   [padding1]          |
57
-		       |		<- FRAME_POINTER
58
-   [va_arg registers]  |
59
-		       |
60
-   [frame]	       |
61
-		       |
62
-   [padding2]	       | = to_allocate
63
-					<- STACK_POINTER
64
-  */
65
-struct ix86_frame
66
-{
67
-  int nsseregs;
68
-  int nregs;
69
-  int va_arg_size;
70
-  int red_zone_size;
71
-  int outgoing_arguments_size;
72
-
73
-  /* The offsets relative to ARG_POINTER.  */
74
-  HOST_WIDE_INT frame_pointer_offset;
75
-  HOST_WIDE_INT hard_frame_pointer_offset;
76
-  HOST_WIDE_INT stack_pointer_offset;
77
-  HOST_WIDE_INT hfp_save_offset;
78
-  HOST_WIDE_INT reg_save_offset;
79
-  HOST_WIDE_INT sse_reg_save_offset;
80
-
81
-  /* When save_regs_using_mov is set, emit prologue using
82
-     move instead of push instructions.  */
83
-  bool save_regs_using_mov;
84
-};
85
-
86
 /* Which cpu are we scheduling for.  */
87
 enum attr_cpu ix86_schedule;
88
 
89
@@ -2443,7 +2396,7 @@ static unsigned int ix86_function_arg_bo
90
 						const_tree);
91
 static rtx ix86_static_chain (const_tree, bool);
92
 static int ix86_function_regparm (const_tree, const_tree);
93
-static void ix86_compute_frame_layout (struct ix86_frame *);
94
+static void ix86_compute_frame_layout (void);
95
 static bool ix86_expand_vector_init_one_nonzero (bool, machine_mode,
96
 						 rtx, rtx, int);
97
 static void ix86_add_new_builtins (HOST_WIDE_INT);
98
@@ -9664,7 +9617,8 @@ ix86_can_use_return_insn_p (void)
99
   if (crtl->args.pops_args && crtl->args.size >= 32768)
100
     return 0;
101
 
102
-  ix86_compute_frame_layout (&frame);
103
+  ix86_compute_frame_layout ();
104
+  frame = cfun->machine->frame;
105
   return (frame.stack_pointer_offset == UNITS_PER_WORD
106
 	  && (frame.nregs + frame.nsseregs) == 0);
107
 }
108
@@ -10073,8 +10027,8 @@ ix86_can_eliminate (const int from, cons
109
 HOST_WIDE_INT
110
 ix86_initial_elimination_offset (int from, int to)
111
 {
112
-  struct ix86_frame frame;
113
-  ix86_compute_frame_layout (&frame);
114
+  ix86_compute_frame_layout ();
115
+  struct ix86_frame frame = cfun->machine->frame;
116
 
117
   if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
118
     return frame.hard_frame_pointer_offset;
119
@@ -10113,8 +10067,9 @@ ix86_builtin_setjmp_frame_value (void)
120
 /* Fill structure ix86_frame about frame of currently computed function.  */
121
 
122
 static void
123
-ix86_compute_frame_layout (struct ix86_frame *frame)
124
+ix86_compute_frame_layout (void)
125
 {
126
+  struct ix86_frame *frame = &cfun->machine->frame;
127
   unsigned HOST_WIDE_INT stack_alignment_needed;
128
   HOST_WIDE_INT offset;
129
   unsigned HOST_WIDE_INT preferred_alignment;
130
@@ -11417,7 +11372,8 @@ ix86_expand_prologue (void)
131
   m->fs.sp_offset = INCOMING_FRAME_SP_OFFSET;
132
   m->fs.sp_valid = true;
133
 
134
-  ix86_compute_frame_layout (&frame);
135
+  ix86_compute_frame_layout ();
136
+  frame = m->frame;
137
 
138
   if (!TARGET_64BIT && ix86_function_ms_hook_prologue (current_function_decl))
139
     {
140
@@ -12083,7 +12039,8 @@ ix86_expand_epilogue (int style)
141
   bool using_drap;
142
 
143
   ix86_finalize_stack_realign_flags ();
144
-  ix86_compute_frame_layout (&frame);
145
+  ix86_compute_frame_layout ();
146
+  frame = m->frame;
147
 
148
   m->fs.sp_valid = (!frame_pointer_needed
149
 		    || (crtl->sp_is_unchanging
150
@@ -12546,7 +12503,8 @@ ix86_expand_split_stack_prologue (void)
151
   gcc_assert (flag_split_stack && reload_completed);
152
 
153
   ix86_finalize_stack_realign_flags ();
154
-  ix86_compute_frame_layout (&frame);
155
+  ix86_compute_frame_layout ();
156
+  frame = cfun->machine->frame;
157
   allocate = frame.stack_pointer_offset - INCOMING_FRAME_SP_OFFSET;
158
 
159
   /* This is the label we will branch to if we have enough stack
160
Index: b/src/gcc/config/i386/i386.h
161
===================================================================
162
--- a/src/gcc/config/i386/i386.h
163
+++ b/src/gcc/config/i386/i386.h
164
@@ -2409,9 +2409,56 @@ enum avx_u128_state
165
 
166
 #define FASTCALL_PREFIX '@'
167
 
168
+#ifndef USED_FOR_TARGET
169
+/* Structure describing stack frame layout.
170
+   Stack grows downward:
171
+
172
+   [arguments]
173
+					<- ARG_POINTER
174
+   saved pc
175
+
176
+   saved static chain			if ix86_static_chain_on_stack
177
+
178
+   saved frame pointer			if frame_pointer_needed
179
+					<- HARD_FRAME_POINTER
180
+   [saved regs]
181
+					<- regs_save_offset
182
+   [padding0]
183
+
184
+   [saved SSE regs]
185
+					<- sse_regs_save_offset
186
+   [padding1]          |
187
+		       |		<- FRAME_POINTER
188
+   [va_arg registers]  |
189
+		       |
190
+   [frame]	       |
191
+		       |
192
+   [padding2]	       | = to_allocate
193
+					<- STACK_POINTER
194
+  */
195
+struct GTY(()) ix86_frame
196
+{
197
+  int nsseregs;
198
+  int nregs;
199
+  int va_arg_size;
200
+  int red_zone_size;
201
+  int outgoing_arguments_size;
202
+
203
+  /* The offsets relative to ARG_POINTER.  */
204
+  HOST_WIDE_INT frame_pointer_offset;
205
+  HOST_WIDE_INT hard_frame_pointer_offset;
206
+  HOST_WIDE_INT stack_pointer_offset;
207
+  HOST_WIDE_INT hfp_save_offset;
208
+  HOST_WIDE_INT reg_save_offset;
209
+  HOST_WIDE_INT sse_reg_save_offset;
210
+
211
+  /* When save_regs_using_mov is set, emit prologue using
212
+     move instead of push instructions.  */
213
+  bool save_regs_using_mov;
214
+};
215
+
216
 /* Machine specific frame tracking during prologue/epilogue generation.  */
217
 
218
-#ifndef USED_FOR_TARGET
219
 struct GTY(()) machine_frame_state
220
 {
221
   /* This pair tracks the currently active CFA as reg+offset.  When reg
222
@@ -2457,6 +2504,9 @@ struct GTY(()) machine_function {
223
   int varargs_fpr_size;
224
   int optimize_mode_switching[MAX_386_ENTITIES];
225
 
226
+  /* Cached initial frame layout for the current function.  */
227
+  struct ix86_frame frame;
228
+
229
   /* Number of saved registers USE_FAST_PROLOGUE_EPILOGUE
230
      has been computed for.  */
231
   int use_fast_prologue_epilogue_nregs;
232
@@ -2524,6 +2574,7 @@ struct GTY(()) machine_function {
233
 #define ix86_current_function_calls_tls_descriptor \
234
   (ix86_tls_descriptor_calls_expanded_in_cfun && df_regs_ever_live_p (SP_REG))
235
 #define ix86_static_chain_on_stack (cfun->machine->static_chain_on_stack)
236
+#define ix86_red_zone_size (cfun->machine->frame.red_zone_size)
237
 
238
 /* Control behavior of x86_file_start.  */
239
 #define X86_FILE_START_VERSION_DIRECTIVE false
view file @ 6eac6210dc
... ... --- /dev/null
... ... +++ b/0002-i386-Use-reference-of-struct-ix86_frame-to-avoid-cop.diff
... ... @@ -0,0 +1,72 @@
1
From 18202ba32cb8de22fc43a5839235a751d0f5c4d9 Mon Sep 17 00:00:00 2001
2
From: hjl <hjl@138bc75d-0d04-0410-961f-82ee72b054a4>
3
Date: Mon, 15 Jan 2018 11:28:44 +0000
4
Subject: [PATCH 2/9] i386: Use reference of struct ix86_frame to avoid copy
5
6
When there is no need to make a copy of ix86_frame, we can use reference
7
of struct ix86_frame to avoid copy.
8
9
	Backport from mainline
10
	* config/i386/i386.c (ix86_can_use_return_insn_p): Use reference
11
	of struct ix86_frame.
12
	(ix86_initial_elimination_offset): Likewise.
13
	(ix86_expand_split_stack_prologue): Likewise.
14
15
16
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gcc-7-branch@256692 138bc75d-0d04-0410-961f-82ee72b054a4
17
---
18
 gcc/config/i386/i386.c  | 9 +++------
19
 gcc/testsuite/ChangeLog | 8 ++++++++
20
 2 files changed, 11 insertions(+), 6 deletions(-)
21
22
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
23
index 8133372..397ef7c 100644
24
--- a/src/gcc/config/i386/i386.c
25
+++ b/src/gcc/config/i386/i386.c
26
@@ -11843,8 +11843,6 @@ symbolic_reference_mentioned_p (rtx op)
27
 bool
28
 ix86_can_use_return_insn_p (void)
29
 {
30
-  struct ix86_frame frame;
31
-
32
   if (! reload_completed || frame_pointer_needed)
33
     return 0;
34
 
35
@@ -11857,7 +11855,7 @@ ix86_can_use_return_insn_p (void)
36
     return 0;
37
 
38
   ix86_compute_frame_layout ();
39
-  frame = cfun->machine->frame;
40
+  struct ix86_frame &frame = cfun->machine->frame;
41
   return (frame.stack_pointer_offset == UNITS_PER_WORD
42
 	  && (frame.nregs + frame.nsseregs) == 0);
43
 }
44
@@ -12344,7 +12342,7 @@ HOST_WIDE_INT
45
 ix86_initial_elimination_offset (int from, int to)
46
 {
47
   ix86_compute_frame_layout ();
48
-  struct ix86_frame frame = cfun->machine->frame;
49
+  struct ix86_frame &frame = cfun->machine->frame;
50
 
51
   if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
52
     return frame.hard_frame_pointer_offset;
53
@@ -14860,7 +14858,6 @@ static GTY(()) rtx split_stack_fn_large;
54
 void
55
 ix86_expand_split_stack_prologue (void)
56
 {
57
-  struct ix86_frame frame;
58
   HOST_WIDE_INT allocate;
59
   unsigned HOST_WIDE_INT args_size;
60
   rtx_code_label *label;
61
@@ -14873,7 +14870,7 @@ ix86_expand_split_stack_prologue (void)
62
 
63
   ix86_finalize_stack_realign_flags ();
64
   ix86_compute_frame_layout ();
65
-  frame = cfun->machine->frame;
66
+  struct ix86_frame &frame = cfun->machine->frame;
67
   allocate = frame.stack_pointer_offset - INCOMING_FRAME_SP_OFFSET;
68
 
69
   /* This is the label we will branch to if we have enough stack
70
-- 
71
2.7.4
72
view file @ 6eac6210dc
... ... --- /dev/null
... ... +++ b/0003-i386-More-use-reference-of-struct-ix86_frame-to-avoi.diff
... ... @@ -0,0 +1,59 @@
1
From 839ca2d69157ef03c8df0ab912dacdb991738694 Mon Sep 17 00:00:00 2001
2
From: hjl <hjl@138bc75d-0d04-0410-961f-82ee72b054a4>
3
Date: Mon, 15 Jan 2018 11:33:42 +0000
4
Subject: [PATCH 3/9] i386: More use reference of struct ix86_frame to avoid copy
5
6
When there is no need to make a copy of ix86_frame, we can use reference
7
of struct ix86_frame to avoid copy.
8
9
	Backport from mainline
10
	* config/i386/i386.c (ix86_expand_prologue): Use reference of
11
	struct ix86_frame.
12
	(ix86_expand_epilogue): Likewise.
13
14
15
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gcc-7-branch@256695 138bc75d-0d04-0410-961f-82ee72b054a4
16
---
17
 gcc/ChangeLog          | 7 +++++++
18
 gcc/config/i386/i386.c | 6 ++----
19
 2 files changed, 9 insertions(+), 4 deletions(-)
20
21
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
22
index 397ef7c..986e6d7 100644
23
--- a/src/gcc/config/i386/i386.c
24
+++ b/src/gcc/config/i386/i386.c
25
@@ -13667,7 +13667,6 @@ ix86_expand_prologue (void)
26
 {
27
   struct machine_function *m = cfun->machine;
28
   rtx insn, t;
29
-  struct ix86_frame frame;
30
   HOST_WIDE_INT allocate;
31
   bool int_registers_saved;
32
   bool sse_registers_saved;
33
@@ -13691,7 +13690,7 @@ ix86_expand_prologue (void)
34
   m->fs.sp_valid = true;
35
 
36
   ix86_compute_frame_layout ();
37
-  frame = m->frame;
38
+  struct ix86_frame &frame = cfun->machine->frame;
39
 
40
   if (!TARGET_64BIT && ix86_function_ms_hook_prologue (current_function_decl))
41
     {
42
@@ -14354,13 +14353,12 @@ ix86_expand_epilogue (int style)
43
 {
44
   struct machine_function *m = cfun->machine;
45
   struct machine_frame_state frame_state_save = m->fs;
46
-  struct ix86_frame frame;
47
   bool restore_regs_via_mov;
48
   bool using_drap;
49
 
50
   ix86_finalize_stack_realign_flags ();
51
   ix86_compute_frame_layout ();
52
-  frame = m->frame;
53
+  struct ix86_frame &frame = cfun->machine->frame;
54
 
55
   m->fs.sp_valid = (!frame_pointer_needed
56
 		    || (crtl->sp_is_unchanging
57
-- 
58
2.7.4
59
view file @ 6eac6210dc
... ... --- /dev/null
... ... +++ b/0004-i386-Don-t-use-reference-of-struct-ix86_frame.diff
... ... @@ -0,0 +1,63 @@
1
From c25b81ba01fa9ac0c1baa3aabd64190c47928f03 Mon Sep 17 00:00:00 2001
2
From: hjl <hjl@138bc75d-0d04-0410-961f-82ee72b054a4>
3
Date: Tue, 16 Jan 2018 12:49:29 +0000
4
Subject: [PATCH 4/9] i386: Don't use reference of struct ix86_frame
5
6
Use reference of struct ix86_frame in ix86_expand_prologue and
7
ix86_expand_epilogue caused:
8
9
raised STORAGE_ERROR : stack overflow or erroneous memory access
10
make[5]: *** [/export/gnu/import/git/sources/gcc/gcc/ada/Make-generated.in:45: ada/sinfo.h] Error 1
11
12
on trunk when bootstrapping GCC with ada on x86-64.
13
14
	* config/i386/i386.c (ix86_expand_prologue): Don't use reference
15
	of struct ix86_frame.
16
	(ix86_expand_epilogue): Likewise.
17
18
19
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gcc-7-branch@256742 138bc75d-0d04-0410-961f-82ee72b054a4
20
---
21
 gcc/ChangeLog          | 10 ++++++++++
22
 gcc/config/i386/i386.c |  6 ++++--
23
 2 files changed, 14 insertions(+), 2 deletions(-)
24
25
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
26
index e758387..ba2abc5 100644
27
--- a/src/gcc/config/i386/i386.c
28
+++ b/src/gcc/config/i386/i386.c
29
@@ -14061,6 +14061,7 @@ ix86_expand_prologue (void)
30
 {
31
   struct machine_function *m = cfun->machine;
32
   rtx insn, t;
33
+  struct ix86_frame frame;
34
   HOST_WIDE_INT allocate;
35
   bool int_registers_saved;
36
   bool sse_registers_saved;
37
@@ -14084,7 +14085,7 @@ ix86_expand_prologue (void)
38
   m->fs.sp_valid = true;
39
 
40
   ix86_compute_frame_layout ();
41
-  struct ix86_frame &frame = cfun->machine->frame;
42
+  frame = m->frame;
43
 
44
   if (!TARGET_64BIT && ix86_function_ms_hook_prologue (current_function_decl))
45
     {
46
@@ -14747,12 +14748,13 @@ ix86_expand_epilogue (int style)
47
 {
48
   struct machine_function *m = cfun->machine;
49
   struct machine_frame_state frame_state_save = m->fs;
50
+  struct ix86_frame frame;
51
   bool restore_regs_via_mov;
52
   bool using_drap;
53
 
54
   ix86_finalize_stack_realign_flags ();
55
   ix86_compute_frame_layout ();
56
-  struct ix86_frame &frame = cfun->machine->frame;
57
+  frame = m->frame;
58
 
59
   m->fs.sp_valid = (!frame_pointer_needed
60
 		    || (crtl->sp_is_unchanging
61
-- 
62
2.7.4
63
view file @ 6eac6210dc
... ... --- /dev/null
... ... +++ b/0005-x86-Add-mindirect-branch.diff
... ... @@ -0,0 +1,1923 @@
1
From c6b72be421ded17e0c156070ba6e90aa6c335ed6 Mon Sep 17 00:00:00 2001
2
From: hjl <hjl@138bc75d-0d04-0410-961f-82ee72b054a4>
3
Date: Tue, 16 Jan 2018 10:59:42 +0000
4
Subject: [PATCH 5/9] x86: Add -mindirect-branch=
5
6
Add -mindirect-branch= option to convert indirect call and jump to call
7
and return thunks.  The default is 'keep', which keeps indirect call and
8
jump unmodified.  'thunk' converts indirect call and jump to call and
9
return thunk.  'thunk-inline' converts indirect call and jump to inlined
10
call and return thunk.  'thunk-extern' converts indirect call and jump to
11
external call and return thunk provided in a separate object file.  You
12
can control this behavior for a specific function by using the function
13
attribute indirect_branch.
14
15
2 kinds of thunks are geneated.  Memory thunk where the function address
16
is at the top of the stack:
17
18
__x86_indirect_thunk:
19
	call L2
20
L1:
21
	pause
22
	lfence
23
	jmp L1
24
L2:
25
	lea 8(%rsp), %rsp|lea 4(%esp), %esp
26
	ret
27
28
Indirect jmp via memory, "jmp mem", is converted to
29
30
	push memory
31
	jmp __x86_indirect_thunk
32
33
Indirect call via memory, "call mem", is converted to
34
35
	jmp L2
36
L1:
37
	push [mem]
38
	jmp __x86_indirect_thunk
39
L2:
40
	call L1
41
42
Register thunk where the function address is in a register, reg:
43
44
__x86_indirect_thunk_reg:
45
	call	L2
46
L1:
47
	pause
48
	lfence
49
	jmp	L1
50
L2:
51
	movq	%reg, (%rsp)|movl    %reg, (%esp)
52
	ret
53
54
where 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
57
Indirect jmp via register, "jmp reg", is converted to
58
59
	jmp __x86_indirect_thunk_reg
60
61
Indirect call via register, "call reg", is converted to
62
63
	call __x86_indirect_thunk_reg
64
65
gcc/
66
67
	Backport from mainline
68
	* config/i386/i386-opts.h (indirect_branch): New.
69
	* config/i386/i386-protos.h (ix86_output_indirect_jmp): Likewise.
70
	* config/i386/i386.c (ix86_using_red_zone): Disallow red-zone
71
	with local indirect jump when converting indirect call and jump.
72
	(ix86_set_indirect_branch_type): New.
73
	(ix86_set_current_function): Call ix86_set_indirect_branch_type.
74
	(indirectlabelno): New.
75
	(indirect_thunk_needed): Likewise.
76
	(indirect_thunk_bnd_needed): Likewise.
77
	(indirect_thunks_used): Likewise.
78
	(indirect_thunks_bnd_used): Likewise.
79
	(INDIRECT_LABEL): Likewise.
80
	(indirect_thunk_name): Likewise.
81
	(output_indirect_thunk): Likewise.
82
	(output_indirect_thunk_function): Likewise.
83
	(ix86_output_indirect_branch_via_reg): Likewise.
84
	(ix86_output_indirect_branch_via_push): Likewise.
85
	(ix86_output_indirect_branch): Likewise.
86
	(ix86_output_indirect_jmp): Likewise.
87
	(ix86_code_end): Call output_indirect_thunk_function if needed.
88
	(ix86_output_call_insn): Call ix86_output_indirect_branch if
89
	needed.
90
	(ix86_handle_fndecl_attribute): Handle indirect_branch.
91
	(ix86_attribute_table): Add indirect_branch.
92
	* config/i386/i386.h (machine_function): Add indirect_branch_type
93
	and has_local_indirect_jump.
94
	* config/i386/i386.md (indirect_jump): Set has_local_indirect_jump
95
	to true.
96
	(tablejump): Likewise.
97
	(*indirect_jump): Use ix86_output_indirect_jmp.
98
	(*tablejump_1): Likewise.
99
	(simple_return_indirect_internal): Likewise.
100
	* config/i386/i386.opt (mindirect-branch=): New option.
101
	(indirect_branch): New.
102
	(keep): Likewise.
103
	(thunk): Likewise.
104
	(thunk-inline): Likewise.
105
	(thunk-extern): Likewise.
106
	* doc/extend.texi: Document indirect_branch function attribute.
107
	* doc/invoke.texi: Document -mindirect-branch= option.
108
109
gcc/testsuite/
110
111
	Backport from mainline
112
	* gcc.target/i386/indirect-thunk-1.c: New test.
113
	* gcc.target/i386/indirect-thunk-2.c: Likewise.
114
	* gcc.target/i386/indirect-thunk-3.c: Likewise.
115
	* gcc.target/i386/indirect-thunk-4.c: Likewise.
116
	* gcc.target/i386/indirect-thunk-5.c: Likewise.
117
	* gcc.target/i386/indirect-thunk-6.c: Likewise.
118
	* gcc.target/i386/indirect-thunk-7.c: Likewise.
119
	* gcc.target/i386/indirect-thunk-attr-1.c: Likewise.
120
	* gcc.target/i386/indirect-thunk-attr-2.c: Likewise.
121
	* gcc.target/i386/indirect-thunk-attr-3.c: Likewise.
122
	* gcc.target/i386/indirect-thunk-attr-4.c: Likewise.
123
	* gcc.target/i386/indirect-thunk-attr-5.c: Likewise.
124
	* gcc.target/i386/indirect-thunk-attr-6.c: Likewise.
125
	* gcc.target/i386/indirect-thunk-attr-7.c: Likewise.
126
	* gcc.target/i386/indirect-thunk-attr-8.c: Likewise.
127
	* gcc.target/i386/indirect-thunk-bnd-1.c: Likewise.
128
	* gcc.target/i386/indirect-thunk-bnd-2.c: Likewise.
129
	* gcc.target/i386/indirect-thunk-bnd-3.c: Likewise.
130
	* gcc.target/i386/indirect-thunk-bnd-4.c: Likewise.
131
	* gcc.target/i386/indirect-thunk-extern-1.c: Likewise.
132
	* gcc.target/i386/indirect-thunk-extern-2.c: Likewise.
133
	* gcc.target/i386/indirect-thunk-extern-3.c: Likewise.
134
	* gcc.target/i386/indirect-thunk-extern-4.c: Likewise.
135
	* gcc.target/i386/indirect-thunk-extern-5.c: Likewise.
136
	* gcc.target/i386/indirect-thunk-extern-6.c: Likewise.
137
	* gcc.target/i386/indirect-thunk-extern-7.c: Likewise.
138
	* gcc.target/i386/indirect-thunk-inline-1.c: Likewise.
139
	* gcc.target/i386/indirect-thunk-inline-2.c: Likewise.
140
	* gcc.target/i386/indirect-thunk-inline-3.c: Likewise.
141
	* gcc.target/i386/indirect-thunk-inline-4.c: Likewise.
142
	* gcc.target/i386/indirect-thunk-inline-5.c: Likewise.
143
	* gcc.target/i386/indirect-thunk-inline-6.c: Likewise.
144
	* gcc.target/i386/indirect-thunk-inline-7.c: Likewise.
145
146
147
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gcc-7-branch@256732 138bc75d-0d04-0410-961f-82ee72b054a4
148
149
[UBUNTU NOTES: Updated for gcc-5.4 to include defines for
150
 FIRST_INT_REG, LAST_INT_REG, and LEGACY_INT_REGNO_P as defined in
151
 https://gcc.gnu.org/viewcvs/gcc?view=revision&revision=222269.
152
 Dropped indirect-thunk-5.c, indirect-thunk-6.c,
153
 indirect-thunk-bnd-3.c, indirect-thunk-bnd-4.c,
154
 indirect-thunk-extern-5.c, indirect-thunk-extern-6.c,
155
 indirect-thunk-inline-5.c, and indirect-thunk-inline-6.c tests due
156
 to gcc 5.4 and earlier not supporting the -fno-plt option.
157
    --sbeattie, tyhicks]
158
---
159
 src/gcc/config/i386/i386-opts.h                             |   13 
160
 src/gcc/config/i386/i386-protos.h                           |    1 
161
 src/gcc/config/i386/i386.c                                  |  621 +++++++++++-
162
 src/gcc/config/i386/i386.h                                  |   12 
163
 src/gcc/config/i386/i386.md                                 |   26 
164
 src/gcc/config/i386/i386.opt                                |   20 
165
 src/gcc/doc/extend.texi                                     |   10 
166
 src/gcc/doc/invoke.texi                                     |   14 
167
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c        |   20 
168
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c        |   20 
169
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c        |   21 
170
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c        |   21 
171
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c        |   44 
172
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c   |   23 
173
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c   |   21 
174
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c   |   23 
175
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c   |   22 
176
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c   |   22 
177
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c   |   21 
178
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c   |   44 
179
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c   |   42 
180
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c    |   20 
181
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c    |   21 
182
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c |   19 
183
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c |   19 
184
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c |   20 
185
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c |   20 
186
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c |   43 
187
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c |   20 
188
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c |   20 
189
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c |   21 
190
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c |   21 
191
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c |   44 
192
 33 files changed, 1334 insertions(+), 15 deletions(-)
193
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-1.c
194
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-2.c
195
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-3.c
196
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-4.c
197
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-5.c
198
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-6.c
199
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-7.c
200
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c
201
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c
202
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c
203
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c
204
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c
205
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c
206
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c
207
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c
208
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c
209
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c
210
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-3.c
211
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-4.c
212
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c
213
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c
214
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c
215
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c
216
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-extern-5.c
217
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-extern-6.c
218
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c
219
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c
220
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c
221
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c
222
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c
223
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-inline-5.c
224
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-inline-6.c
225
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c
226
227
Index: b/src/gcc/config/i386/i386-opts.h
228
===================================================================
229
--- a/src/gcc/config/i386/i386-opts.h
230
+++ b/src/gcc/config/i386/i386-opts.h
231
@@ -99,4 +99,17 @@ enum stack_protector_guard {
232
   SSP_GLOBAL    /* global canary */
233
 };
234
 
235
+/* This is used to mitigate variant #2 of the speculative execution
236
+   vulnerabilities on x86 processors identified by CVE-2017-5715, aka
237
+   Spectre.  They convert indirect branches and function returns to
238
+   call and return thunks to avoid speculative execution via indirect
239
+   call, jmp and ret.  */
240
+enum indirect_branch {
241
+  indirect_branch_unset = 0,
242
+  indirect_branch_keep,
243
+  indirect_branch_thunk,
244
+  indirect_branch_thunk_inline,
245
+  indirect_branch_thunk_extern
246
+};
247
+
248
 #endif
249
Index: b/src/gcc/config/i386/i386-protos.h
250
===================================================================
251
--- a/src/gcc/config/i386/i386-protos.h
252
+++ b/src/gcc/config/i386/i386-protos.h
253
@@ -306,6 +306,7 @@ extern enum attr_cpu ix86_schedule;
254
 #endif
255
 
256
 extern const char * ix86_output_call_insn (rtx_insn *insn, rtx call_op);
257
+extern const char * ix86_output_indirect_jmp (rtx call_op, bool ret_p);
258
 
259
 #ifdef RTX_CODE
260
 /* Target data for multipass lookahead scheduling.
261
Index: b/src/gcc/config/i386/i386.c
262
===================================================================
263
--- a/src/gcc/config/i386/i386.c
264
+++ b/src/gcc/config/i386/i386.c
265
@@ -2554,12 +2554,23 @@ make_pass_insert_vzeroupper (gcc::contex
266
   return new pass_insert_vzeroupper (ctxt);
267
 }
268
 
269
-/* Return true if a red-zone is in use.  */
270
+/* Return true if a red-zone is in use.  We can't use red-zone when
271
+   there are local indirect jumps, like "indirect_jump" or "tablejump",
272
+   which jumps to another place in the function, since "call" in the
273
+   indirect thunk pushes the return address onto stack, destroying
274
+   red-zone.
275
+
276
+   TODO: If we can reserve the first 2 WORDs, for PUSH and, another
277
+   for CALL, in red-zone, we can allow local indirect jumps with
278
+   indirect thunk.  */
279
 
280
 static inline bool
281
 ix86_using_red_zone (void)
282
 {
283
-  return TARGET_RED_ZONE && !TARGET_64BIT_MS_ABI;
284
+  return (TARGET_RED_ZONE
285
+	  && !TARGET_64BIT_MS_ABI
286
+	  && (!cfun->machine->has_local_indirect_jump
287
+	      || cfun->machine->indirect_branch_type == indirect_branch_keep));
288
 }
289
 
290
 /* Return a string that documents the current -m options.  The caller is
291
@@ -5126,6 +5137,37 @@ ix86_reset_previous_fndecl (void)
292
   ix86_previous_fndecl = NULL_TREE;
293
 }
294
 
295
+/* Set the indirect_branch_type field from the function FNDECL.  */
296
+
297
+static void
298
+ix86_set_indirect_branch_type (tree fndecl)
299
+{
300
+  if (cfun->machine->indirect_branch_type == indirect_branch_unset)
301
+    {
302
+      tree attr = lookup_attribute ("indirect_branch",
303
+				    DECL_ATTRIBUTES (fndecl));
304
+      if (attr != NULL)
305
+	{
306
+	  tree args = TREE_VALUE (attr);
307
+	  if (args == NULL)
308
+	    gcc_unreachable ();
309
+	  tree cst = TREE_VALUE (args);
310
+	  if (strcmp (TREE_STRING_POINTER (cst), "keep") == 0)
311
+	    cfun->machine->indirect_branch_type = indirect_branch_keep;
312
+	  else if (strcmp (TREE_STRING_POINTER (cst), "thunk") == 0)
313
+	    cfun->machine->indirect_branch_type = indirect_branch_thunk;
314
+	  else if (strcmp (TREE_STRING_POINTER (cst), "thunk-inline") == 0)
315
+	    cfun->machine->indirect_branch_type = indirect_branch_thunk_inline;
316
+	  else if (strcmp (TREE_STRING_POINTER (cst), "thunk-extern") == 0)
317
+	    cfun->machine->indirect_branch_type = indirect_branch_thunk_extern;
318
+	  else
319
+	    gcc_unreachable ();
320
+	}
321
+      else
322
+	cfun->machine->indirect_branch_type = ix86_indirect_branch;
323
+    }
324
+}
325
+
326
 /* Establish appropriate back-end context for processing the function
327
    FNDECL.  The argument might be NULL to indicate processing at top
328
    level, outside of any function scope.  */
329
@@ -5136,7 +5178,11 @@ ix86_set_current_function (tree fndecl)
330
      several times in the course of compiling a function, and we don't want to
331
      slow things down too much or call target_reinit when it isn't safe.  */
332
   if (fndecl == ix86_previous_fndecl)
333
-    return;
334
+    {
335
+      if (fndecl != NULL_TREE)
336
+	  ix86_set_indirect_branch_type (fndecl);
337
+      return;
338
+    }
339
 
340
   tree old_tree;
341
   if (ix86_previous_fndecl == NULL_TREE)
342
@@ -5153,6 +5199,8 @@ ix86_set_current_function (tree fndecl)
343
       return;
344
     }
345
 
346
+  ix86_set_indirect_branch_type (fndecl);
347
+
348
   tree new_tree = DECL_FUNCTION_SPECIFIC_TARGET (fndecl);
349
   if (new_tree == NULL_TREE)
350
     new_tree = target_option_default_node;
351
@@ -9681,6 +9729,220 @@ ix86_setup_frame_addresses (void)
352
 # endif
353
 #endif
354
 
355
+/* Label count for call and return thunks.  It is used to make unique
356
+   labels in call and return thunks.  */
357
+static int indirectlabelno;
358
+
359
+/* True if call and return thunk functions are needed.  */
360
+static bool indirect_thunk_needed = false;
361
+/* True if call and return thunk functions with the BND prefix are
362
+   needed.  */
363
+static bool indirect_thunk_bnd_needed = false;
364
+
365
+/* Bit masks of integer registers, which contain branch target, used
366
+   by call and return thunks functions.  */
367
+static int indirect_thunks_used;
368
+/* Bit masks of integer registers, which contain branch target, used
369
+   by call and return thunks functions with the BND prefix.  */
370
+static int indirect_thunks_bnd_used;
371
+
372
+#ifndef INDIRECT_LABEL
373
+# define INDIRECT_LABEL "LIND"
374
+#endif
375
+
376
+/* Fills in the label name that should be used for the indirect thunk.  */
377
+
378
+static void
379
+indirect_thunk_name (char name[32], int regno, bool need_bnd_p)
380
+{
381
+  if (USE_HIDDEN_LINKONCE)
382
+    {
383
+      const char *bnd = need_bnd_p ? "_bnd" : "";
384
+      if (regno >= 0)
385
+	{
386
+	  const char *reg_prefix;
387
+	  if (LEGACY_INT_REGNO_P (regno))
388
+	    reg_prefix = TARGET_64BIT ? "r" : "e";
389
+	  else
390
+	    reg_prefix = "";
391
+	  sprintf (name, "__x86_indirect_thunk%s_%s%s",
392
+		   bnd, reg_prefix, reg_names[regno]);
393
+	}
394
+      else
395
+	sprintf (name, "__x86_indirect_thunk%s", bnd);
396
+    }
397
+  else
398
+    {
399
+      if (regno >= 0)
400
+	{
401
+	  if (need_bnd_p)
402
+	    ASM_GENERATE_INTERNAL_LABEL (name, "LITBR", regno);
403
+	  else
404
+	    ASM_GENERATE_INTERNAL_LABEL (name, "LITR", regno);
405
+	}
406
+      else
407
+	{
408
+	  if (need_bnd_p)
409
+	    ASM_GENERATE_INTERNAL_LABEL (name, "LITB", 0);
410
+	  else
411
+	    ASM_GENERATE_INTERNAL_LABEL (name, "LIT", 0);
412
+	}
413
+    }
414
+}
415
+
416
+/* Output a call and return thunk for indirect branch.  If BND_P is
417
+   true, the BND prefix is needed.   If REGNO != -1,  the function
418
+   address is in REGNO and the call and return thunk looks like:
419
+
420
+	call	L2
421
+   L1:
422
+	pause
423
+	jmp	L1
424
+   L2:
425
+	mov	%REG, (%sp)
426
+	ret
427
+
428
+   Otherwise, the function address is on the top of stack and the
429
+   call and return thunk looks like:
430
+
431
+	call L2
432
+  L1:
433
+	pause
434
+	jmp L1
435
+  L2:
436
+	lea WORD_SIZE(%sp), %sp
437
+	ret
438
+ */
439
+
440
+static void
441
+output_indirect_thunk (bool need_bnd_p, int regno)
442
+{
443
+  char indirectlabel1[32];
444
+  char indirectlabel2[32];
445
+
446
+  ASM_GENERATE_INTERNAL_LABEL (indirectlabel1, INDIRECT_LABEL,
447
+			       indirectlabelno++);
448
+  ASM_GENERATE_INTERNAL_LABEL (indirectlabel2, INDIRECT_LABEL,
449
+			       indirectlabelno++);
450
+
451
+  /* Call */
452
+  if (need_bnd_p)
453
+    fputs ("\tbnd call\t", asm_out_file);
454
+  else
455
+    fputs ("\tcall\t", asm_out_file);
456
+  assemble_name_raw (asm_out_file, indirectlabel2);
457
+  fputc ('\n', asm_out_file);
458
+
459
+  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel1);
460
+
461
+  /* Pause + lfence.  */
462
+  fprintf (asm_out_file, "\tpause\n\tlfence\n");
463
+
464
+  /* Jump.  */
465
+  fputs ("\tjmp\t", asm_out_file);
466
+  assemble_name_raw (asm_out_file, indirectlabel1);
467
+  fputc ('\n', asm_out_file);
468
+
469
+  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel2);
470
+
471
+  if (regno >= 0)
472
+    {
473
+      /* MOV.  */
474
+      rtx xops[2];
475
+      xops[0] = gen_rtx_MEM (word_mode, stack_pointer_rtx);
476
+      xops[1] = gen_rtx_REG (word_mode, regno);
477
+      output_asm_insn ("mov\t{%1, %0|%0, %1}", xops);
478
+    }
479
+  else
480
+    {
481
+      /* LEA.  */
482
+      rtx xops[2];
483
+      xops[0] = stack_pointer_rtx;
484
+      xops[1] = plus_constant (Pmode, stack_pointer_rtx, UNITS_PER_WORD);
485
+      output_asm_insn ("lea\t{%E1, %0|%0, %E1}", xops);
486
+    }
487
+
488
+  if (need_bnd_p)
489
+    fputs ("\tbnd ret\n", asm_out_file);
490
+  else
491
+    fputs ("\tret\n", asm_out_file);
492
+}
493
+
494
+/* Output a funtion with a call and return thunk for indirect branch.
495
+   If BND_P is true, the BND prefix is needed.   If REGNO != -1,  the
496
+   function address is in REGNO.  Otherwise, the function address is
497
+   on the top of stack.  */
498
+
499
+static void
500
+output_indirect_thunk_function (bool need_bnd_p, int regno)
501
+{
502
+  char name[32];
503
+  tree decl;
504
+
505
+  /* Create __x86_indirect_thunk/__x86_indirect_thunk_bnd.  */
506
+  indirect_thunk_name (name, regno, need_bnd_p);
507
+  decl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL,
508
+		     get_identifier (name),
509
+		     build_function_type_list (void_type_node, NULL_TREE));
510
+  DECL_RESULT (decl) = build_decl (BUILTINS_LOCATION, RESULT_DECL,
511
+				   NULL_TREE, void_type_node);
512
+  TREE_PUBLIC (decl) = 1;
513
+  TREE_STATIC (decl) = 1;
514
+  DECL_IGNORED_P (decl) = 1;
515
+
516
+#if TARGET_MACHO
517
+  if (TARGET_MACHO)
518
+    {
519
+      switch_to_section (darwin_sections[picbase_thunk_section]);
520
+      fputs ("\t.weak_definition\t", asm_out_file);
521
+      assemble_name (asm_out_file, name);
522
+      fputs ("\n\t.private_extern\t", asm_out_file);
523
+      assemble_name (asm_out_file, name);
524
+      putc ('\n', asm_out_file);
525
+      ASM_OUTPUT_LABEL (asm_out_file, name);
526
+      DECL_WEAK (decl) = 1;
527
+    }
528
+  else
529
+#endif
530
+    if (USE_HIDDEN_LINKONCE)
531
+      {
532
+	cgraph_node::create (decl)->set_comdat_group (DECL_ASSEMBLER_NAME (decl));
533
+
534
+	targetm.asm_out.unique_section (decl, 0);
535
+	switch_to_section (get_named_section (decl, NULL, 0));
536
+
537
+	targetm.asm_out.globalize_label (asm_out_file, name);
538
+	fputs ("\t.hidden\t", asm_out_file);
539
+	assemble_name (asm_out_file, name);
540
+	putc ('\n', asm_out_file);
541
+	ASM_DECLARE_FUNCTION_NAME (asm_out_file, name, decl);
542
+      }
543
+    else
544
+      {
545
+	switch_to_section (text_section);
546
+	ASM_OUTPUT_LABEL (asm_out_file, name);
547
+      }
548
+
549
+  DECL_INITIAL (decl) = make_node (BLOCK);
550
+  current_function_decl = decl;
551
+  allocate_struct_function (decl, false);
552
+  init_function_start (decl);
553
+  /* We're about to hide the function body from callees of final_* by
554
+     emitting it directly; tell them we're a thunk, if they care.  */
555
+  cfun->is_thunk = true;
556
+  first_function_block_is_cold = false;
557
+  /* Make sure unwind info is emitted for the thunk if needed.  */
558
+  final_start_function (emit_barrier (), asm_out_file, 1);
559
+
560
+  output_indirect_thunk (need_bnd_p, regno);
561
+
562
+  final_end_function ();
563
+  init_insn_lengths ();
564
+  free_after_compilation (cfun);
565
+  set_cfun (NULL);
566
+  current_function_decl = NULL;
567
+}
568
+
569
 static int pic_labels_used;
570
 
571
 /* Fills in the label name that should be used for a pc thunk for
572
@@ -9707,11 +9969,32 @@ ix86_code_end (void)
573
   rtx xops[2];
574
   int regno;
575
 
576
+  if (indirect_thunk_needed)
577
+    output_indirect_thunk_function (false, -1);
578
+  if (indirect_thunk_bnd_needed)
579
+    output_indirect_thunk_function (true, -1);
580
+
581
+  for (regno = FIRST_REX_INT_REG; regno <= LAST_REX_INT_REG; regno++)
582
+    {
583
+      int i = regno - FIRST_REX_INT_REG + LAST_INT_REG + 1;
584
+      if ((indirect_thunks_used & (1 << i)))
585
+	output_indirect_thunk_function (false, regno);
586
+
587
+      if ((indirect_thunks_bnd_used & (1 << i)))
588
+	output_indirect_thunk_function (true, regno);
589
+    }
590
+
591
   for (regno = AX_REG; regno <= SP_REG; regno++)
592
     {
593
       char name[32];
594
       tree decl;
595
 
596
+      if ((indirect_thunks_used & (1 << regno)))
597
+	output_indirect_thunk_function (false, regno);
598
+
599
+      if ((indirect_thunks_bnd_used & (1 << regno)))
600
+	output_indirect_thunk_function (true, regno);
601
+
602
       if (!(pic_labels_used & (1 << regno)))
603
 	continue;
604
 
605
@@ -25805,12 +26088,292 @@ ix86_expand_call (rtx retval, rtx fnaddr
606
   return call;
607
 }
608
 
609
+/* Output indirect branch via a call and return thunk.  CALL_OP is a
610
+   register which contains the branch target.  XASM is the assembly
611
+   template for CALL_OP.  Branch is a tail call if SIBCALL_P is true.
612
+   A normal call is converted to:
613
+
614
+	call __x86_indirect_thunk_reg
615
+
616
+   and a tail call is converted to:
617
+
618
+	jmp __x86_indirect_thunk_reg
619
+ */
620
+
621
+static void
622
+ix86_output_indirect_branch_via_reg (rtx call_op, bool sibcall_p)
623
+{
624
+  char thunk_name_buf[32];
625
+  char *thunk_name;
626
+  bool need_bnd_p = ix86_bnd_prefixed_insn_p (current_output_insn);
627
+  int regno = REGNO (call_op);
628
+
629
+  if (cfun->machine->indirect_branch_type
630
+      != indirect_branch_thunk_inline)
631
+    {
632
+      if (cfun->machine->indirect_branch_type == indirect_branch_thunk)
633
+	{
634
+	  int i = regno;
635
+	  if (i >= FIRST_REX_INT_REG)
636
+	    i -= (FIRST_REX_INT_REG - LAST_INT_REG - 1);
637
+	  if (need_bnd_p)
638
+	    indirect_thunks_bnd_used |= 1 << i;
639
+	  else
640
+	    indirect_thunks_used |= 1 << i;
641
+	}
642
+      indirect_thunk_name (thunk_name_buf, regno, need_bnd_p);
643
+      thunk_name = thunk_name_buf;
644
+    }
645
+  else
646
+    thunk_name = NULL;
647
+
648
+  if (sibcall_p)
649
+    {
650
+      if (thunk_name != NULL)
651
+	{
652
+	  if (need_bnd_p)
653
+	    fprintf (asm_out_file, "\tbnd jmp\t%s\n", thunk_name);
654
+	  else
655
+	    fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name);
656
+	}
657
+      else
658
+	output_indirect_thunk (need_bnd_p, regno);
659
+    }
660
+  else
661
+    {
662
+      if (thunk_name != NULL)
663
+	{
664
+	  if (need_bnd_p)
665
+	    fprintf (asm_out_file, "\tbnd call\t%s\n", thunk_name);
666
+	  else
667
+	    fprintf (asm_out_file, "\tcall\t%s\n", thunk_name);
668
+	  return;
669
+	}
670
+
671
+      char indirectlabel1[32];
672
+      char indirectlabel2[32];
673
+
674
+      ASM_GENERATE_INTERNAL_LABEL (indirectlabel1,
675
+				   INDIRECT_LABEL,
676
+				   indirectlabelno++);
677
+      ASM_GENERATE_INTERNAL_LABEL (indirectlabel2,
678
+				   INDIRECT_LABEL,
679
+				   indirectlabelno++);
680
+
681
+      /* Jump.  */
682
+      if (need_bnd_p)
683
+	fputs ("\tbnd jmp\t", asm_out_file);
684
+      else
685
+	fputs ("\tjmp\t", asm_out_file);
686
+      assemble_name_raw (asm_out_file, indirectlabel2);
687
+      fputc ('\n', asm_out_file);
688
+
689
+      ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel1);
690
+
691
+      if (thunk_name != NULL)
692
+	{
693
+	  if (need_bnd_p)
694
+	    fprintf (asm_out_file, "\tbnd jmp\t%s\n", thunk_name);
695
+	  else
696
+	    fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name);
697
+	}
698
+      else
699
+	output_indirect_thunk (need_bnd_p, regno);
700
+
701
+      ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel2);
702
+
703
+      /* Call.  */
704
+      if (need_bnd_p)
705
+	fputs ("\tbnd call\t", asm_out_file);
706
+      else
707
+	fputs ("\tcall\t", asm_out_file);
708
+      assemble_name_raw (asm_out_file, indirectlabel1);
709
+      fputc ('\n', asm_out_file);
710
+    }
711
+}
712
+
713
+/* Output indirect branch via a call and return thunk.  CALL_OP is
714
+   the branch target.  XASM is the assembly template for CALL_OP.
715
+   Branch is a tail call if SIBCALL_P is true.  A normal call is
716
+   converted to:
717
+
718
+	jmp L2
719
+   L1:
720
+	push CALL_OP
721
+	jmp __x86_indirect_thunk
722
+   L2:
723
+	call L1
724
+
725
+   and a tail call is converted to:
726
+
727
+	push CALL_OP
728
+	jmp __x86_indirect_thunk
729
+ */
730
+
731
+static void
732
+ix86_output_indirect_branch_via_push (rtx call_op, const char *xasm,
733
+				      bool sibcall_p)
734
+{
735
+  char thunk_name_buf[32];
736
+  char *thunk_name;
737
+  char push_buf[64];
738
+  bool need_bnd_p = ix86_bnd_prefixed_insn_p (current_output_insn);
739
+  int regno = -1;
740
+
741
+  if (cfun->machine->indirect_branch_type
742
+      != indirect_branch_thunk_inline)
743
+    {
744
+      if (cfun->machine->indirect_branch_type == indirect_branch_thunk)
745
+	{
746
+	  if (need_bnd_p)
747
+	    indirect_thunk_bnd_needed = true;
748
+	  else
749
+	    indirect_thunk_needed = true;
750
+	}
751
+      indirect_thunk_name (thunk_name_buf, regno, need_bnd_p);
752
+      thunk_name = thunk_name_buf;
753
+    }
754
+  else
755
+    thunk_name = NULL;
756
+
757
+  snprintf (push_buf, sizeof (push_buf), "push{%c}\t%s",
758
+	    TARGET_64BIT ? 'q' : 'l', xasm);
759
+
760
+  if (sibcall_p)
761
+    {
762
+      output_asm_insn (push_buf, &call_op);
763
+      if (thunk_name != NULL)
764
+	{
765
+	  if (need_bnd_p)
766
+	    fprintf (asm_out_file, "\tbnd jmp\t%s\n", thunk_name);
767
+	  else
768
+	    fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name);
769
+	}
770
+      else
771
+	output_indirect_thunk (need_bnd_p, regno);
772
+    }
773
+  else
774
+    {
775
+      char indirectlabel1[32];
776
+      char indirectlabel2[32];
777
+
778
+      ASM_GENERATE_INTERNAL_LABEL (indirectlabel1,
779
+				   INDIRECT_LABEL,
780
+				   indirectlabelno++);
781
+      ASM_GENERATE_INTERNAL_LABEL (indirectlabel2,
782
+				   INDIRECT_LABEL,
783
+				   indirectlabelno++);
784
+
785
+      /* Jump.  */
786
+      if (need_bnd_p)
787
+	fputs ("\tbnd jmp\t", asm_out_file);
788
+      else
789
+	fputs ("\tjmp\t", asm_out_file);
790
+      assemble_name_raw (asm_out_file, indirectlabel2);
791
+      fputc ('\n', asm_out_file);
792
+
793
+      ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel1);
794
+
795
+      /* An external function may be called via GOT, instead of PLT.  */
796
+      if (MEM_P (call_op))
797
+	{
798
+	  struct ix86_address parts;
799
+	  rtx addr = XEXP (call_op, 0);
800
+	  if (ix86_decompose_address (addr, &parts)
801
+	      && parts.base == stack_pointer_rtx)
802
+	    {
803
+	      /* Since call will adjust stack by -UNITS_PER_WORD,
804
+		 we must convert "disp(stack, index, scale)" to
805
+		 "disp+UNITS_PER_WORD(stack, index, scale)".  */
806
+	      if (parts.index)
807
+		{
808
+		  addr = gen_rtx_MULT (Pmode, parts.index,
809
+				       GEN_INT (parts.scale));
810
+		  addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
811
+				       addr);
812
+		}
813
+	      else
814
+		addr = stack_pointer_rtx;
815
+
816
+	      rtx disp;
817
+	      if (parts.disp != NULL_RTX)
818
+		disp = plus_constant (Pmode, parts.disp,
819
+				      UNITS_PER_WORD);
820
+	      else
821
+		disp = GEN_INT (UNITS_PER_WORD);
822
+
823
+	      addr = gen_rtx_PLUS (Pmode, addr, disp);
824
+	      call_op = gen_rtx_MEM (GET_MODE (call_op), addr);
825
+	    }
826
+	}
827
+
828
+      output_asm_insn (push_buf, &call_op);
829
+
830
+      if (thunk_name != NULL)
831
+	{
832
+	  if (need_bnd_p)
833
+	    fprintf (asm_out_file, "\tbnd jmp\t%s\n", thunk_name);
834
+	  else
835
+	    fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name);
836
+	}
837
+      else
838
+	output_indirect_thunk (need_bnd_p, regno);
839
+
840
+      ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel2);
841
+
842
+      /* Call.  */
843
+      if (need_bnd_p)
844
+	fputs ("\tbnd call\t", asm_out_file);
845
+      else
846
+	fputs ("\tcall\t", asm_out_file);
847
+      assemble_name_raw (asm_out_file, indirectlabel1);
848
+      fputc ('\n', asm_out_file);
849
+    }
850
+}
851
+
852
+/* Output indirect branch via a call and return thunk.  CALL_OP is
853
+   the branch target.  XASM is the assembly template for CALL_OP.
854
+   Branch is a tail call if SIBCALL_P is true.   */
855
+
856
+static void
857
+ix86_output_indirect_branch (rtx call_op, const char *xasm,
858
+			     bool sibcall_p)
859
+{
860
+  if (REG_P (call_op))
861
+    ix86_output_indirect_branch_via_reg (call_op, sibcall_p);
862
+  else
863
+    ix86_output_indirect_branch_via_push (call_op, xasm, sibcall_p);
864
+}
865
+/* Output indirect jump.  CALL_OP is the jump target.  Jump is a
866
+   function return if RET_P is true.  */
867
+
868
+const char *
869
+ix86_output_indirect_jmp (rtx call_op, bool ret_p)
870
+{
871
+  if (cfun->machine->indirect_branch_type != indirect_branch_keep)
872
+    {
873
+      /* We can't have red-zone if this isn't a function return since
874
+	 "call" in the indirect thunk pushes the return address onto
875
+	 stack, destroying red-zone.  */
876
+      if (!ret_p && ix86_red_zone_size != 0)
877
+	gcc_unreachable ();
878
+
879
+      ix86_output_indirect_branch (call_op, "%0", true);
880
+      return "";
881
+    }
882
+  else
883
+    return "%!jmp\t%A0";
884
+}
885
+
886
 /* Output the assembly for a call instruction.  */
887
 
888
 const char *
889
 ix86_output_call_insn (rtx_insn *insn, rtx call_op)
890
 {
891
   bool direct_p = constant_call_address_operand (call_op, VOIDmode);
892
+  bool output_indirect_p
893
+    = (!TARGET_SEH
894
+       && cfun->machine->indirect_branch_type != indirect_branch_keep);
895
   bool seh_nop_p = false;
896
   const char *xasm;
897
 
898
@@ -25823,9 +26386,17 @@ ix86_output_call_insn (rtx_insn *insn, r
899
       else if (TARGET_SEH)
900
 	xasm = "%!rex.W jmp %A0";
901
       else
902
-	xasm = "%!jmp\t%A0";
903
+	{
904
+	  if (output_indirect_p)
905
+	    xasm = "%0";
906
+	  else
907
+	    xasm = "%!jmp\t%A0";
908
+	}
909
 
910
-      output_asm_insn (xasm, &call_op);
911
+      if (output_indirect_p && !direct_p)
912
+	ix86_output_indirect_branch (call_op, xasm, true);
913
+      else
914
+	output_asm_insn (xasm, &call_op);
915
       return "";
916
     }
917
 
918
@@ -25862,9 +26433,17 @@ ix86_output_call_insn (rtx_insn *insn, r
919
   if (direct_p)
920
     xasm = "%!call\t%P0";
921
   else
922
-    xasm = "%!call\t%A0";
923
+    {
924
+      if (output_indirect_p)
925
+	xasm = "%0";
926
+      else
927
+	xasm = "%!call\t%A0";
928
+    }
929
 
930
-  output_asm_insn (xasm, &call_op);
931
+  if (output_indirect_p && !direct_p)
932
+    ix86_output_indirect_branch (call_op, xasm, false);
933
+  else
934
+    output_asm_insn (xasm, &call_op);
935
 
936
   if (seh_nop_p)
937
     return "nop";
938
@@ -43014,7 +43593,7 @@ ix86_handle_struct_attribute (tree *node
939
 }
940
 
941
 static tree
942
-ix86_handle_fndecl_attribute (tree *node, tree name, tree, int,
943
+ix86_handle_fndecl_attribute (tree *node, tree name, tree args, int,
944
 			      bool *no_add_attrs)
945
 {
946
   if (TREE_CODE (*node) != FUNCTION_DECL)
947
@@ -43023,6 +43602,29 @@ ix86_handle_fndecl_attribute (tree *node
948
                name);
949
       *no_add_attrs = true;
950
     }
951
+
952
+  if (is_attribute_p ("indirect_branch", name))
953
+    {
954
+      tree cst = TREE_VALUE (args);
955
+      if (TREE_CODE (cst) != STRING_CST)
956
+	{
957
+	  warning (OPT_Wattributes,
958
+		   "%qE attribute requires a string constant argument",
959
+		   name);
960
+	  *no_add_attrs = true;
961
+	}
962
+      else if (strcmp (TREE_STRING_POINTER (cst), "keep") != 0
963
+	       && strcmp (TREE_STRING_POINTER (cst), "thunk") != 0
964
+	       && strcmp (TREE_STRING_POINTER (cst), "thunk-inline") != 0
965
+	       && strcmp (TREE_STRING_POINTER (cst), "thunk-extern") != 0)
966
+	{
967
+	  warning (OPT_Wattributes,
968
+		   "argument to %qE attribute is not "
969
+		   "(keep|thunk|thunk-inline|thunk-extern)", name);
970
+	  *no_add_attrs = true;
971
+	}
972
+    }
973
+
974
   return NULL_TREE;
975
 }
976
 
977
@@ -46915,6 +47517,9 @@ static const struct attribute_spec ix86_
978
     false },
979
   { "callee_pop_aggregate_return", 1, 1, false, true, true,
980
     ix86_handle_callee_pop_aggregate_return, true },
981
+  { "indirect_branch", 1, 1, true, false, false,
982
+    ix86_handle_fndecl_attribute, false },
983
+
984
   /* End element.  */
985
   { NULL,        0, 0, false, false, false, NULL, false }
986
 };
987
Index: b/src/gcc/config/i386/i386.h
988
===================================================================
989
--- a/src/gcc/config/i386/i386.h
990
+++ b/src/gcc/config/i386/i386.h
991
@@ -1229,6 +1229,9 @@ extern const char *host_detect_local_cpu
992
 /* Base register for access to local variables of the function.  */
993
 #define FRAME_POINTER_REGNUM 20
994
 
995
+#define FIRST_INT_REG  AX_REG
996
+#define LAST_INT_REG  SP_REG
997
+
998
 /* First floating point reg */
999
 #define FIRST_FLOAT_REG 8
1000
 
1001
@@ -1465,6 +1468,8 @@ enum reg_class
1002
    registers.  */
1003
 #define TARGET_SMALL_REGISTER_CLASSES_FOR_MODE_P hook_bool_mode_true
1004
 
1005
+#define LEGACY_INT_REGNO_P(N) (IN_RANGE ((N), FIRST_INT_REG, LAST_INT_REG))
1006
+
1007
 #define QI_REG_P(X) (REG_P (X) && QI_REGNO_P (REGNO (X)))
1008
 #define QI_REGNO_P(N) IN_RANGE ((N), AX_REG, BX_REG)
1009
 
1010
@@ -2550,6 +2555,13 @@ struct GTY(()) machine_function {
1011
   /* If true, it is safe to not save/restore DRAP register.  */
1012
   BOOL_BITFIELD no_drap_save_restore : 1;
1013
 
1014
+  /* How to generate indirec branch.  */
1015
+  ENUM_BITFIELD(indirect_branch) indirect_branch_type : 3;
1016
+
1017
+  /* If true, the current function has local indirect jumps, like
1018
+     "indirect_jump" or "tablejump".  */
1019
+  BOOL_BITFIELD has_local_indirect_jump : 1;
1020
+
1021
   /* During prologue/epilogue generation, the current frame state.
1022
      Otherwise, the frame state at the end of the prologue.  */
1023
   struct machine_frame_state fs;
1024
Index: b/src/gcc/config/i386/i386.md
1025
===================================================================
1026
--- a/src/gcc/config/i386/i386.md
1027
+++ b/src/gcc/config/i386/i386.md
1028
@@ -11556,13 +11556,18 @@
1029
 {
1030
   if (TARGET_X32)
1031
     operands[0] = convert_memory_address (word_mode, operands[0]);
1032
+  cfun->machine->has_local_indirect_jump = true;
1033
 })
1034
 
1035
 (define_insn "*indirect_jump"
1036
   [(set (pc) (match_operand:W 0 "indirect_branch_operand" "rBw"))]
1037
   ""
1038
-  "%!jmp\t%A0"
1039
-  [(set_attr "type" "ibr")
1040
+  "* return ix86_output_indirect_jmp (operands[0], false);"
1041
+  [(set (attr "type")
1042
+     (if_then_else (match_test "(cfun->machine->indirect_branch_type
1043
+				 != indirect_branch_keep)")
1044
+	(const_string "multi")
1045
+	(const_string "ibr")))
1046
    (set_attr "length_immediate" "0")])
1047
 
1048
 (define_expand "tablejump"
1049
@@ -11604,14 +11609,19 @@
1050
 
1051
   if (TARGET_X32)
1052
     operands[0] = convert_memory_address (word_mode, operands[0]);
1053
+  cfun->machine->has_local_indirect_jump = true;
1054
 })
1055
 
1056
 (define_insn "*tablejump_1"
1057
   [(set (pc) (match_operand:W 0 "indirect_branch_operand" "rBw"))
1058
    (use (label_ref (match_operand 1)))]
1059
   ""
1060
-  "%!jmp\t%A0"
1061
-  [(set_attr "type" "ibr")
1062
+  "* return ix86_output_indirect_jmp (operands[0], false);"
1063
+  [(set (attr "type")
1064
+     (if_then_else (match_test "(cfun->machine->indirect_branch_type
1065
+				 != indirect_branch_keep)")
1066
+	(const_string "multi")
1067
+	(const_string "ibr")))
1068
    (set_attr "length_immediate" "0")])
1069
 
1070
 ;; Convert setcc + movzbl to xor + setcc if operands don't overlap.
1071
@@ -12198,8 +12208,12 @@
1072
   [(simple_return)
1073
    (use (match_operand:SI 0 "register_operand" "r"))]
1074
   "reload_completed"
1075
-  "%!jmp\t%A0"
1076
-  [(set_attr "type" "ibr")
1077
+  "* return ix86_output_indirect_jmp (operands[0], true);"
1078
+  [(set (attr "type")
1079
+     (if_then_else (match_test "(cfun->machine->indirect_branch_type
1080
+				 != indirect_branch_keep)")
1081
+	(const_string "multi")
1082
+	(const_string "ibr")))
1083
    (set_attr "length_immediate" "0")])
1084
 
1085
 (define_insn "nop"
1086
Index: b/src/gcc/config/i386/i386.opt
1087
===================================================================
1088
--- a/src/gcc/config/i386/i386.opt
1089
+++ b/src/gcc/config/i386/i386.opt
1090
@@ -876,3 +876,23 @@ Enum(stack_protector_guard) String(tls)
1091
 
1092
 EnumValue
1093
 Enum(stack_protector_guard) String(global) Value(SSP_GLOBAL)
1094
+
1095
+mindirect-branch=
1096
+Target Report RejectNegative Joined Enum(indirect_branch) Var(ix86_indirect_branch) Init(indirect_branch_keep)
1097
+Convert indirect call and jump to call and return thunks.
1098
+
1099
+Enum
1100
+Name(indirect_branch) Type(enum indirect_branch)
1101
+Known indirect branch choices (for use with the -mindirect-branch= option):
1102
+
1103
+EnumValue
1104
+Enum(indirect_branch) String(keep) Value(indirect_branch_keep)
1105
+
1106
+EnumValue
1107
+Enum(indirect_branch) String(thunk) Value(indirect_branch_thunk)
1108
+
1109
+EnumValue
1110
+Enum(indirect_branch) String(thunk-inline) Value(indirect_branch_thunk_inline)
1111
+
1112
+EnumValue
1113
+Enum(indirect_branch) String(thunk-extern) Value(indirect_branch_thunk_extern)
1114
Index: b/src/gcc/doc/extend.texi
1115
===================================================================
1116
--- a/src/gcc/doc/extend.texi
1117
+++ b/src/gcc/doc/extend.texi
1118
@@ -4119,6 +4119,16 @@ Specify which floating-point unit to use
1119
 @code{target("fpmath=sse,387")} option must be specified as
1120
 @code{target("fpmath=sse+387")} because the comma would separate
1121
 different options.
1122
+
1123
+@item indirect_branch("@var{choice}")
1124
+@cindex @code{indirect_branch} function attribute, x86
1125
+On x86 targets, the @code{indirect_branch} attribute causes the compiler
1126
+to convert indirect call and jump with @var{choice}.  @samp{keep}
1127
+keeps indirect call and jump unmodified.  @samp{thunk} converts indirect
1128
+call and jump to call and return thunk.  @samp{thunk-inline} converts
1129
+indirect call and jump to inlined call and return thunk.
1130
+@samp{thunk-extern} converts indirect call and jump to external call
1131
+and return thunk provided in a separate object file.
1132
 @end table
1133
 
1134
 On the PowerPC, the following options are allowed:
1135
Index: b/src/gcc/doc/invoke.texi
1136
===================================================================
1137
--- a/src/gcc/doc/invoke.texi
1138
+++ b/src/gcc/doc/invoke.texi
1139
@@ -1090,7 +1090,8 @@ See RS/6000 and PowerPC Options.
1140
 -m32 -m64 -mx32 -m16 -mlarge-data-threshold=@var{num} @gol
1141
 -msse2avx -mfentry -mrecord-mcount -mnop-mcount -m8bit-idiv @gol
1142
 -mavx256-split-unaligned-load -mavx256-split-unaligned-store @gol
1143
--malign-data=@var{type} -mstack-protector-guard=@var{guard}}
1144
+-malign-data=@var{type} -mstack-protector-guard=@var{guard} @gol
1145
+-mindirect-branch=@var{choice}}
1146
 
1147
 @emph{x86 Windows Options}
1148
 @gccoptlist{-mconsole -mcygwin -mno-cygwin -mdll @gol
1149
@@ -24017,6 +24018,17 @@ The default value of this option is enab
1150
 of the option is @option{-fno-sync-libcalls}.  This option is used in
1151
 the implementation of the @file{libatomic} runtime library.
1152
 
1153
+@item -mindirect-branch=@var{choice}
1154
+@opindex -mindirect-branch
1155
+Convert indirect call and jump with @var{choice}.  The default is
1156
+@samp{keep}, which keeps indirect call and jump unmodified.
1157
+@samp{thunk} converts indirect call and jump to call and return thunk.
1158
+@samp{thunk-inline} converts indirect call and jump to inlined call
1159
+and return thunk.  @samp{thunk-extern} converts indirect call and jump
1160
+to external call and return thunk provided in a separate object file.
1161
+You can control this behavior for a specific function by using the
1162
+function attribute @code{indirect_branch}.  @xref{Function Attributes}.
1163
+
1164
 @end table
1165
 
1166
 @c man end
1167
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c
1168
===================================================================
1169
--- /dev/null
1170
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c
1171
@@ -0,0 +1,20 @@
1172
+/* { dg-do compile } */
1173
+/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
1174
+
1175
+typedef void (*dispatch_t)(long offset);
1176
+
1177
+dispatch_t dispatch;
1178
+
1179
+void
1180
+male_indirect_jump (long offset)
1181
+{
1182
+  dispatch(offset);
1183
+}
1184
+
1185
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1186
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1187
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1188
+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1189
+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1190
+/* { dg-final { scan-assembler {\tpause} } } */
1191
+/* { dg-final { scan-assembler {\tlfence} } } */
1192
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c
1193
===================================================================
1194
--- /dev/null
1195
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c
1196
@@ -0,0 +1,20 @@
1197
+/* { dg-do compile } */
1198
+/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
1199
+
1200
+typedef void (*dispatch_t)(long offset);
1201
+
1202
+dispatch_t dispatch[256];
1203
+
1204
+void
1205
+male_indirect_jump (long offset)
1206
+{
1207
+  dispatch[offset](offset);
1208
+}
1209
+
1210
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1211
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1212
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1213
+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1214
+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1215
+/* { dg-final { scan-assembler {\tpause} } } */
1216
+/* { dg-final { scan-assembler {\tlfence} } } */
1217
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c
1218
===================================================================
1219
--- /dev/null
1220
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c
1221
@@ -0,0 +1,21 @@
1222
+/* { dg-do compile } */
1223
+/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
1224
+
1225
+typedef void (*dispatch_t)(long offset);
1226
+
1227
+dispatch_t dispatch;
1228
+
1229
+int
1230
+male_indirect_jump (long offset)
1231
+{
1232
+  dispatch(offset);
1233
+  return 0;
1234
+}
1235
+
1236
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1237
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1238
+/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1239
+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1240
+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1241
+/* { dg-final { scan-assembler {\tpause} } } */
1242
+/* { dg-final { scan-assembler {\tlfence} } } */
1243
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c
1244
===================================================================
1245
--- /dev/null
1246
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c
1247
@@ -0,0 +1,21 @@
1248
+/* { dg-do compile } */
1249
+/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
1250
+
1251
+typedef void (*dispatch_t)(long offset);
1252
+
1253
+dispatch_t dispatch[256];
1254
+
1255
+int
1256
+male_indirect_jump (long offset)
1257
+{
1258
+  dispatch[offset](offset);
1259
+  return 0;
1260
+}
1261
+
1262
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1263
+/* { dg-final { scan-assembler "jmp\[ \t\]*__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 "jmp\[ \t\]*\.LIND" } } */
1266
+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1267
+/* { dg-final { scan-assembler {\tpause} } } */
1268
+/* { dg-final { scan-assembler {\tlfence} } } */
1269
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c
1270
===================================================================
1271
--- /dev/null
1272
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c
1273
@@ -0,0 +1,44 @@
1274
+/* { dg-do compile } */
1275
+/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
1276
+
1277
+void func0 (void);
1278
+void func1 (void);
1279
+void func2 (void);
1280
+void func3 (void);
1281
+void func4 (void);
1282
+void func4 (void);
1283
+void func5 (void);
1284
+
1285
+void
1286
+bar (int i)
1287
+{
1288
+  switch (i)
1289
+    {
1290
+    default:
1291
+      func0 ();
1292
+      break;
1293
+    case 1:
1294
+      func1 ();
1295
+      break;
1296
+    case 2:
1297
+      func2 ();
1298
+      break;
1299
+    case 3:
1300
+      func3 ();
1301
+      break;
1302
+    case 4:
1303
+      func4 ();
1304
+      break;
1305
+    case 5:
1306
+      func5 ();
1307
+      break;
1308
+    }
1309
+}
1310
+
1311
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { ! x32 } } } } */
1312
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1313
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1314
+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1315
+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1316
+/* { dg-final { scan-assembler {\tpause} } } */
1317
+/* { dg-final { scan-assembler {\tlfence} } } */
1318
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c
1319
===================================================================
1320
--- /dev/null
1321
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c
1322
@@ -0,0 +1,23 @@
1323
+/* { dg-do compile } */
1324
+/* { dg-options "-O2 -fno-pic" } */
1325
+
1326
+typedef void (*dispatch_t)(long offset);
1327
+
1328
+dispatch_t dispatch;
1329
+
1330
+extern void male_indirect_jump (long)
1331
+  __attribute__ ((indirect_branch("thunk")));
1332
+
1333
+void
1334
+male_indirect_jump (long offset)
1335
+{
1336
+  dispatch(offset);
1337
+}
1338
+
1339
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1340
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1341
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1342
+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1343
+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1344
+/* { dg-final { scan-assembler {\tpause} } } */
1345
+/* { dg-final { scan-assembler {\tlfence} } } */
1346
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c
1347
===================================================================
1348
--- /dev/null
1349
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c
1350
@@ -0,0 +1,21 @@
1351
+/* { dg-do compile } */
1352
+/* { dg-options "-O2 -fno-pic" } */
1353
+
1354
+typedef void (*dispatch_t)(long offset);
1355
+
1356
+dispatch_t dispatch[256];
1357
+
1358
+__attribute__ ((indirect_branch("thunk")))
1359
+void
1360
+male_indirect_jump (long offset)
1361
+{
1362
+  dispatch[offset](offset);
1363
+}
1364
+
1365
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1366
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1367
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1368
+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1369
+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1370
+/* { dg-final { scan-assembler {\tpause} } } */
1371
+/* { dg-final { scan-assembler {\tlfence} } } */
1372
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c
1373
===================================================================
1374
--- /dev/null
1375
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c
1376
@@ -0,0 +1,23 @@
1377
+/* { dg-do compile } */
1378
+/* { dg-options "-O2 -fno-pic" } */
1379
+
1380
+typedef void (*dispatch_t)(long offset);
1381
+
1382
+dispatch_t dispatch;
1383
+extern int male_indirect_jump (long)
1384
+  __attribute__ ((indirect_branch("thunk-inline")));
1385
+
1386
+int
1387
+male_indirect_jump (long offset)
1388
+{
1389
+  dispatch(offset);
1390
+  return 0;
1391
+}
1392
+
1393
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1394
+/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */
1395
+/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */
1396
+/* { dg-final { scan-assembler {\tpause} } } */
1397
+/* { dg-final { scan-assembler {\tlfence} } } */
1398
+/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
1399
+/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
1400
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c
1401
===================================================================
1402
--- /dev/null
1403
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c
1404
@@ -0,0 +1,22 @@
1405
+/* { dg-do compile } */
1406
+/* { dg-options "-O2 -fno-pic" } */
1407
+
1408
+typedef void (*dispatch_t)(long offset);
1409
+
1410
+dispatch_t dispatch[256];
1411
+
1412
+__attribute__ ((indirect_branch("thunk-inline")))
1413
+int
1414
+male_indirect_jump (long offset)
1415
+{
1416
+  dispatch[offset](offset);
1417
+  return 0;
1418
+}
1419
+
1420
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1421
+/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */
1422
+/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */
1423
+/* { dg-final { scan-assembler {\tpause} } } */
1424
+/* { dg-final { scan-assembler {\tlfence} } } */
1425
+/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
1426
+/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
1427
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c
1428
===================================================================
1429
--- /dev/null
1430
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c
1431
@@ -0,0 +1,22 @@
1432
+/* { dg-do compile } */
1433
+/* { dg-options "-O2 -fno-pic" } */
1434
+
1435
+typedef void (*dispatch_t)(long offset);
1436
+
1437
+dispatch_t dispatch;
1438
+extern int male_indirect_jump (long)
1439
+  __attribute__ ((indirect_branch("thunk-extern")));
1440
+
1441
+int
1442
+male_indirect_jump (long offset)
1443
+{
1444
+  dispatch(offset);
1445
+  return 0;
1446
+}
1447
+
1448
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1449
+/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
1450
+/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
1451
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1452
+/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1453
+/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
1454
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c
1455
===================================================================
1456
--- /dev/null
1457
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c
1458
@@ -0,0 +1,21 @@
1459
+/* { dg-do compile } */
1460
+/* { dg-options "-O2 -fno-pic" } */
1461
+
1462
+typedef void (*dispatch_t)(long offset);
1463
+
1464
+dispatch_t dispatch[256];
1465
+
1466
+__attribute__ ((indirect_branch("thunk-extern")))
1467
+int
1468
+male_indirect_jump (long offset)
1469
+{
1470
+  dispatch[offset](offset);
1471
+  return 0;
1472
+}
1473
+
1474
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1475
+/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
1476
+/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
1477
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1478
+/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1479
+/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
1480
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c
1481
===================================================================
1482
--- /dev/null
1483
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c
1484
@@ -0,0 +1,44 @@
1485
+/* { dg-do compile } */
1486
+/* { dg-options "-O2 -fno-pic" } */
1487
+
1488
+void func0 (void);
1489
+void func1 (void);
1490
+void func2 (void);
1491
+void func3 (void);
1492
+void func4 (void);
1493
+void func4 (void);
1494
+void func5 (void);
1495
+
1496
+__attribute__ ((indirect_branch("thunk-extern")))
1497
+void
1498
+bar (int i)
1499
+{
1500
+  switch (i)
1501
+    {
1502
+    default:
1503
+      func0 ();
1504
+      break;
1505
+    case 1:
1506
+      func1 ();
1507
+      break;
1508
+    case 2:
1509
+      func2 ();
1510
+      break;
1511
+    case 3:
1512
+      func3 ();
1513
+      break;
1514
+    case 4:
1515
+      func4 ();
1516
+      break;
1517
+    case 5:
1518
+      func5 ();
1519
+      break;
1520
+    }
1521
+}
1522
+
1523
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { ! x32 } } } } */
1524
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1525
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" } } */
1526
+/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
1527
+/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
1528
+/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
1529
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c
1530
===================================================================
1531
--- /dev/null
1532
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c
1533
@@ -0,0 +1,42 @@
1534
+/* { dg-do compile } */
1535
+/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
1536
+
1537
+void func0 (void);
1538
+void func1 (void);
1539
+void func2 (void);
1540
+void func3 (void);
1541
+void func4 (void);
1542
+void func4 (void);
1543
+void func5 (void);
1544
+
1545
+__attribute__ ((indirect_branch("keep")))
1546
+void
1547
+bar (int i)
1548
+{
1549
+  switch (i)
1550
+    {
1551
+    default:
1552
+      func0 ();
1553
+      break;
1554
+    case 1:
1555
+      func1 ();
1556
+      break;
1557
+    case 2:
1558
+      func2 ();
1559
+      break;
1560
+    case 3:
1561
+      func3 ();
1562
+      break;
1563
+    case 4:
1564
+      func4 ();
1565
+      break;
1566
+    case 5:
1567
+      func5 ();
1568
+      break;
1569
+    }
1570
+}
1571
+
1572
+/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
1573
+/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
1574
+/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
1575
+/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
1576
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c
1577
===================================================================
1578
--- /dev/null
1579
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c
1580
@@ -0,0 +1,20 @@
1581
+/* { dg-do compile { target { ! x32 } } } */
1582
+/* { dg-options "-O2 -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
1583
+
1584
+void (*dispatch) (char *);
1585
+char buf[10];
1586
+
1587
+void
1588
+foo (void)
1589
+{
1590
+  dispatch (buf);
1591
+}
1592
+
1593
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1594
+/* { dg-final { scan-assembler "pushq\[ \t\]%rax" { target x32 } } } */
1595
+/* { dg-final { scan-assembler "bnd jmp\[ \t\]*__x86_indirect_thunk_bnd" } } */
1596
+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1597
+/* { dg-final { scan-assembler "bnd call\[ \t\]*\.LIND" } } */
1598
+/* { dg-final { scan-assembler "bnd ret" } } */
1599
+/* { dg-final { scan-assembler {\tpause} } } */
1600
+/* { dg-final { scan-assembler {\tlfence} } } */
1601
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c
1602
===================================================================
1603
--- /dev/null
1604
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c
1605
@@ -0,0 +1,21 @@
1606
+/* { dg-do compile { target { ! x32 } } } */
1607
+/* { dg-options "-O2 -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
1608
+
1609
+void (*dispatch) (char *);
1610
+char buf[10];
1611
+
1612
+int
1613
+foo (void)
1614
+{
1615
+  dispatch (buf);
1616
+  return 0;
1617
+}
1618
+
1619
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1620
+/* { dg-final { scan-assembler "pushq\[ \t\]%rax" { target x32 } } } */
1621
+/* { dg-final { scan-assembler "bnd jmp\[ \t\]*__x86_indirect_thunk_bnd" } } */
1622
+/* { dg-final { scan-assembler "bnd jmp\[ \t\]*\.LIND" } } */
1623
+/* { dg-final { scan-assembler "bnd call\[ \t\]*\.LIND" } } */
1624
+/* { dg-final { scan-assembler "bnd ret" } } */
1625
+/* { dg-final { scan-assembler {\tpause} } } */
1626
+/* { dg-final { scan-assembler {\tlfence} } } */
1627
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c
1628
===================================================================
1629
--- /dev/null
1630
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c
1631
@@ -0,0 +1,19 @@
1632
+/* { dg-do compile } */
1633
+/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */
1634
+
1635
+typedef void (*dispatch_t)(long offset);
1636
+
1637
+dispatch_t dispatch;
1638
+
1639
+void
1640
+male_indirect_jump (long offset)
1641
+{
1642
+  dispatch(offset);
1643
+}
1644
+
1645
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1646
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1647
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1648
+/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
1649
+/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
1650
+/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
1651
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c
1652
===================================================================
1653
--- /dev/null
1654
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c
1655
@@ -0,0 +1,19 @@
1656
+/* { dg-do compile } */
1657
+/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */
1658
+
1659
+typedef void (*dispatch_t)(long offset);
1660
+
1661
+dispatch_t dispatch[256];
1662
+
1663
+void
1664
+male_indirect_jump (long offset)
1665
+{
1666
+  dispatch[offset](offset);
1667
+}
1668
+
1669
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1670
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1671
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1672
+/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
1673
+/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
1674
+/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
1675
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c
1676
===================================================================
1677
--- /dev/null
1678
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c
1679
@@ -0,0 +1,20 @@
1680
+/* { dg-do compile } */
1681
+/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */
1682
+
1683
+typedef void (*dispatch_t)(long offset);
1684
+
1685
+dispatch_t dispatch;
1686
+
1687
+int
1688
+male_indirect_jump (long offset)
1689
+{
1690
+  dispatch(offset);
1691
+  return 0;
1692
+}
1693
+
1694
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1695
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1696
+/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
1697
+/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
1698
+/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1699
+/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
1700
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c
1701
===================================================================
1702
--- /dev/null
1703
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c
1704
@@ -0,0 +1,20 @@
1705
+/* { dg-do compile } */
1706
+/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */
1707
+
1708
+typedef void (*dispatch_t)(long offset);
1709
+
1710
+dispatch_t dispatch[256];
1711
+
1712
+int
1713
+male_indirect_jump (long offset)
1714
+{
1715
+  dispatch[offset](offset);
1716
+  return 0;
1717
+}
1718
+
1719
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1720
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1721
+/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
1722
+/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
1723
+/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1724
+/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
1725
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c
1726
===================================================================
1727
--- /dev/null
1728
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c
1729
@@ -0,0 +1,43 @@
1730
+/* { dg-do compile } */
1731
+/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */
1732
+
1733
+void func0 (void);
1734
+void func1 (void);
1735
+void func2 (void);
1736
+void func3 (void);
1737
+void func4 (void);
1738
+void func4 (void);
1739
+void func5 (void);
1740
+
1741
+void
1742
+bar (int i)
1743
+{
1744
+  switch (i)
1745
+    {
1746
+    default:
1747
+      func0 ();
1748
+      break;
1749
+    case 1:
1750
+      func1 ();
1751
+      break;
1752
+    case 2:
1753
+      func2 ();
1754
+      break;
1755
+    case 3:
1756
+      func3 ();
1757
+      break;
1758
+    case 4:
1759
+      func4 ();
1760
+      break;
1761
+    case 5:
1762
+      func5 ();
1763
+      break;
1764
+    }
1765
+}
1766
+
1767
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { ! x32 } } } } */
1768
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
1769
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
1770
+/* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
1771
+/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
1772
+/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
1773
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c
1774
===================================================================
1775
--- /dev/null
1776
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c
1777
@@ -0,0 +1,20 @@
1778
+/* { dg-do compile } */
1779
+/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */
1780
+
1781
+typedef void (*dispatch_t)(long offset);
1782
+
1783
+dispatch_t dispatch;
1784
+
1785
+void
1786
+male_indirect_jump (long offset)
1787
+{
1788
+  dispatch(offset);
1789
+}
1790
+
1791
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1792
+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1793
+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1794
+/* { dg-final { scan-assembler {\tpause} } } */
1795
+/* { dg-final { scan-assembler {\tlfence} } } */
1796
+/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
1797
+/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
1798
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c
1799
===================================================================
1800
--- /dev/null
1801
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c
1802
@@ -0,0 +1,20 @@
1803
+/* { dg-do compile } */
1804
+/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */
1805
+
1806
+typedef void (*dispatch_t)(long offset);
1807
+
1808
+dispatch_t dispatch[256];
1809
+
1810
+void
1811
+male_indirect_jump (long offset)
1812
+{
1813
+  dispatch[offset](offset);
1814
+}
1815
+
1816
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1817
+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1818
+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1819
+/* { dg-final { scan-assembler {\tpause} } } */
1820
+/* { dg-final { scan-assembler {\tlfence} } } */
1821
+/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
1822
+/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
1823
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c
1824
===================================================================
1825
--- /dev/null
1826
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c
1827
@@ -0,0 +1,21 @@
1828
+/* { dg-do compile } */
1829
+/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */
1830
+
1831
+typedef void (*dispatch_t)(long offset);
1832
+
1833
+dispatch_t dispatch;
1834
+
1835
+int
1836
+male_indirect_jump (long offset)
1837
+{
1838
+  dispatch(offset);
1839
+  return 0;
1840
+}
1841
+
1842
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1843
+/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */
1844
+/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */
1845
+/* { dg-final { scan-assembler-times {\tpause} 1 } } */
1846
+/* { dg-final { scan-assembler-times {\tlfence} 1 } } */
1847
+/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
1848
+/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
1849
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c
1850
===================================================================
1851
--- /dev/null
1852
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c
1853
@@ -0,0 +1,21 @@
1854
+/* { dg-do compile } */
1855
+/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */
1856
+
1857
+typedef void (*dispatch_t)(long offset);
1858
+
1859
+dispatch_t dispatch[256];
1860
+
1861
+int
1862
+male_indirect_jump (long offset)
1863
+{
1864
+  dispatch[offset](offset);
1865
+  return 0;
1866
+}
1867
+
1868
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
1869
+/* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */
1870
+/* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */
1871
+/* { dg-final { scan-assembler-times {\tpause} 1 } } */
1872
+/* { dg-final { scan-assembler-times {\tlfence} 1 } } */
1873
+/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
1874
+/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
1875
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c
1876
===================================================================
1877
--- /dev/null
1878
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c
1879
@@ -0,0 +1,44 @@
1880
+/* { dg-do compile } */
1881
+/* { dg-options "-O2 -mindirect-branch=thunk-inline -fno-pic" } */
1882
+
1883
+void func0 (void);
1884
+void func1 (void);
1885
+void func2 (void);
1886
+void func3 (void);
1887
+void func4 (void);
1888
+void func4 (void);
1889
+void func5 (void);
1890
+
1891
+void
1892
+bar (int i)
1893
+{
1894
+  switch (i)
1895
+    {
1896
+    default:
1897
+      func0 ();
1898
+      break;
1899
+    case 1:
1900
+      func1 ();
1901
+      break;
1902
+    case 2:
1903
+      func2 ();
1904
+      break;
1905
+    case 3:
1906
+      func3 ();
1907
+      break;
1908
+    case 4:
1909
+      func4 ();
1910
+      break;
1911
+    case 5:
1912
+      func5 ();
1913
+      break;
1914
+    }
1915
+}
1916
+
1917
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { ! x32 } } } } */
1918
+/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" { target x32 } } } */
1919
+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
1920
+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
1921
+/* { dg-final { scan-assembler {\tpause} } } */
1922
+/* { dg-final { scan-assembler {\tlfence} } } */
1923
+/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
view file @ 6eac6210dc
... ... --- /dev/null
... ... +++ b/0006-x86-Add-mfunction-return.diff
... ... @@ -0,0 +1,1460 @@
1
From 357311dd400f7f72d2132f2f94161ece39bf08c6 Mon Sep 17 00:00:00 2001
2
From: hjl <hjl@138bc75d-0d04-0410-961f-82ee72b054a4>
3
Date: Tue, 16 Jan 2018 11:10:44 +0000
4
Subject: [PATCH 6/9] x86: Add -mfunction-return=
5
6
Add -mfunction-return= option to convert function return to call and
7
return thunks.  The default is 'keep', which keeps function return
8
unmodified.  '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
11
thunk provided in a separate object file.  You can control this behavior
12
for a specific function by using the function attribute function_return.
13
14
Function return thunk is the same as memory thunk for -mindirect-branch=
15
where the return address is at the top of the stack:
16
17
__x86_return_thunk:
18
	call L2
19
L1:
20
	pause
21
	lfence
22
	jmp L1
23
L2:
24
	lea 8(%rsp), %rsp|lea 4(%esp), %esp
25
	ret
26
27
and function return becomes
28
29
	jmp __x86_return_thunk
30
31
-mindirect-branch= tests are updated with -mfunction-return=keep to
32
avoid false test failures when -mfunction-return=thunk is added to
33
RUNTESTFLAGS for "make check".
34
35
gcc/
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
64
gcc/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
120
i386: Don't use ASM_OUTPUT_DEF for TARGET_MACHO
121
122
ASM_OUTPUT_DEF isn't defined for TARGET_MACHO.  Use ASM_OUTPUT_LABEL to
123
generate the __x86_return_thunk label, instead of the set directive.
124
Update testcase to remove the __x86_return_thunk label check.  Since
125
-fno-pic is ignored on Darwin, update testcases to sscan or "push"
126
only on Linux.
127
128
gcc/
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
138
gcc/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
173
174
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gcc-7-branch@256734 138bc75d-0d04-0410-961f-82ee72b054a4
175
176
[Ubuntu note: Dropped indirect-thunk-5.c, indirect-thunk-6.c,
177
 indirect-thunk-bnd-3.c, indirect-thunk-bnd-4.c,
178
 indirect-thunk-extern-5.c, indirect-thunk-extern-6.c,
179
 indirect-thunk-inline-5.c, and indirect-thunk-inline-6.c tests due
180
 to gcc 5.4 and earlier not supporting the -fno-plt option.
181
	--sbeattie,]
182
183
---
184
 src/gcc/config/i386/i386-protos.h                           |    1 
185
 src/gcc/config/i386/i386.c                                  |  152 +++++++++++-
186
 src/gcc/config/i386/i386.h                                  |    3 
187
 src/gcc/config/i386/i386.md                                 |    9 
188
 src/gcc/config/i386/i386.opt                                |    6 
189
 src/gcc/doc/extend.texi                                     |    9 
190
 src/gcc/doc/invoke.texi                                     |   13 -
191
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c        |    4 
192
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c        |    4 
193
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c        |    4 
194
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c        |    4 
195
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c        |    4 
196
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c   |    4 
197
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c   |    4 
198
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c   |    4 
199
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c   |    4 
200
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c   |    4 
201
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c   |    4 
202
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c   |    4 
203
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c   |    2 
204
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c    |    4 
205
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c    |    4 
206
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c |    4 
207
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c |    4 
208
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c |    4 
209
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c |    4 
210
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c |    4 
211
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c |    4 
212
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c |    4 
213
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c |    4 
214
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c |    4 
215
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c |    4 
216
 src/gcc/testsuite/gcc.target/i386/ret-thunk-1.c             |   13 +
217
 src/gcc/testsuite/gcc.target/i386/ret-thunk-10.c            |   23 +
218
 src/gcc/testsuite/gcc.target/i386/ret-thunk-11.c            |   23 +
219
 src/gcc/testsuite/gcc.target/i386/ret-thunk-12.c            |   22 +
220
 src/gcc/testsuite/gcc.target/i386/ret-thunk-13.c            |   22 +
221
 src/gcc/testsuite/gcc.target/i386/ret-thunk-14.c            |   22 +
222
 src/gcc/testsuite/gcc.target/i386/ret-thunk-15.c            |   22 +
223
 src/gcc/testsuite/gcc.target/i386/ret-thunk-16.c            |   18 +
224
 src/gcc/testsuite/gcc.target/i386/ret-thunk-2.c             |   13 +
225
 src/gcc/testsuite/gcc.target/i386/ret-thunk-3.c             |   12 
226
 src/gcc/testsuite/gcc.target/i386/ret-thunk-4.c             |   12 
227
 src/gcc/testsuite/gcc.target/i386/ret-thunk-5.c             |   15 +
228
 src/gcc/testsuite/gcc.target/i386/ret-thunk-6.c             |   14 +
229
 src/gcc/testsuite/gcc.target/i386/ret-thunk-7.c             |   13 +
230
 src/gcc/testsuite/gcc.target/i386/ret-thunk-8.c             |   14 +
231
 src/gcc/testsuite/gcc.target/i386/ret-thunk-9.c             |   24 +
232
 48 files changed, 507 insertions(+), 66 deletions(-)
233
 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-1.c
234
 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-10.c
235
 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-11.c
236
 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-12.c
237
 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-13.c
238
 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-14.c
239
 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-15.c
240
 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-16.c
241
 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-2.c
242
 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-3.c
243
 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-4.c
244
 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-5.c
245
 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-6.c
246
 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-7.c
247
 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-8.c
248
 create mode 100644 gcc/testsuite/gcc.target/i386/ret-thunk-9.c
249
250
Index: b/src/gcc/config/i386/i386-protos.h
251
===================================================================
252
--- a/src/gcc/config/i386/i386-protos.h
253
+++ b/src/gcc/config/i386/i386-protos.h
254
@@ -307,6 +307,7 @@ extern enum attr_cpu ix86_schedule;
255
 
256
 extern const char * ix86_output_call_insn (rtx_insn *insn, rtx call_op);
257
 extern const char * ix86_output_indirect_jmp (rtx call_op, bool ret_p);
258
+extern const char * ix86_output_function_return (bool long_p);
259
 
260
 #ifdef RTX_CODE
261
 /* Target data for multipass lookahead scheduling.
262
Index: b/src/gcc/config/i386/i386.c
263
===================================================================
264
--- a/src/gcc/config/i386/i386.c
265
+++ b/src/gcc/config/i386/i386.c
266
@@ -5166,6 +5166,31 @@ ix86_set_indirect_branch_type (tree fnde
267
       else
268
 	cfun->machine->indirect_branch_type = ix86_indirect_branch;
269
     }
270
+
271
+  if (cfun->machine->function_return_type == indirect_branch_unset)
272
+    {
273
+      tree attr = lookup_attribute ("function_return",
274
+				    DECL_ATTRIBUTES (fndecl));
275
+      if (attr != NULL)
276
+	{
277
+	  tree args = TREE_VALUE (attr);
278
+	  if (args == NULL)
279
+	    gcc_unreachable ();
280
+	  tree cst = TREE_VALUE (args);
281
+	  if (strcmp (TREE_STRING_POINTER (cst), "keep") == 0)
282
+	    cfun->machine->function_return_type = indirect_branch_keep;
283
+	  else if (strcmp (TREE_STRING_POINTER (cst), "thunk") == 0)
284
+	    cfun->machine->function_return_type = indirect_branch_thunk;
285
+	  else if (strcmp (TREE_STRING_POINTER (cst), "thunk-inline") == 0)
286
+	    cfun->machine->function_return_type = indirect_branch_thunk_inline;
287
+	  else if (strcmp (TREE_STRING_POINTER (cst), "thunk-extern") == 0)
288
+	    cfun->machine->function_return_type = indirect_branch_thunk_extern;
289
+	  else
290
+	    gcc_unreachable ();
291
+	}
292
+      else
293
+	cfun->machine->function_return_type = ix86_function_return;
294
+    }
295
 }
296
 
297
 /* Establish appropriate back-end context for processing the function
298
@@ -9753,8 +9778,12 @@ static int indirect_thunks_bnd_used;
299
 /* Fills in the label name that should be used for the indirect thunk.  */
300
 
301
 static void
302
-indirect_thunk_name (char name[32], int regno, bool need_bnd_p)
303
+indirect_thunk_name (char name[32], int regno, bool need_bnd_p,
304
+		     bool ret_p)
305
 {
306
+  if (regno >= 0 && ret_p)
307
+    gcc_unreachable ();
308
+
309
   if (USE_HIDDEN_LINKONCE)
310
     {
311
       const char *bnd = need_bnd_p ? "_bnd" : "";
312
@@ -9769,7 +9798,10 @@ indirect_thunk_name (char name[32], int
313
 		   bnd, reg_prefix, reg_names[regno]);
314
 	}
315
       else
316
-	sprintf (name, "__x86_indirect_thunk%s", bnd);
317
+	{
318
+	  const char *ret = ret_p ? "return" : "indirect";
319
+	  sprintf (name, "__x86_%s_thunk%s", ret, bnd);
320
+	}
321
     }
322
   else
323
     {
324
@@ -9782,10 +9814,20 @@ indirect_thunk_name (char name[32], int
325
 	}
326
       else
327
 	{
328
-	  if (need_bnd_p)
329
-	    ASM_GENERATE_INTERNAL_LABEL (name, "LITB", 0);
330
+	  if (ret_p)
331
+	    {
332
+	      if (need_bnd_p)
333
+		ASM_GENERATE_INTERNAL_LABEL (name, "LRTB", 0);
334
+	      else
335
+		ASM_GENERATE_INTERNAL_LABEL (name, "LRT", 0);
336
+	    }
337
 	  else
338
-	    ASM_GENERATE_INTERNAL_LABEL (name, "LIT", 0);
339
+	    {
340
+	      if (need_bnd_p)
341
+		ASM_GENERATE_INTERNAL_LABEL (name, "LITB", 0);
342
+	      else
343
+		ASM_GENERATE_INTERNAL_LABEL (name, "LIT", 0);
344
+	    }
345
 	}
346
     }
347
 }
348
@@ -9880,7 +9922,7 @@ output_indirect_thunk_function (bool nee
349
   tree decl;
350
 
351
   /* Create __x86_indirect_thunk/__x86_indirect_thunk_bnd.  */
352
-  indirect_thunk_name (name, regno, need_bnd_p);
353
+  indirect_thunk_name (name, regno, need_bnd_p, false);
354
   decl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL,
355
 		     get_identifier (name),
356
 		     build_function_type_list (void_type_node, NULL_TREE));
357
@@ -9923,6 +9965,36 @@ output_indirect_thunk_function (bool nee
358
 	ASM_OUTPUT_LABEL (asm_out_file, name);
359
       }
360
 
361
+  if (regno < 0)
362
+    {
363
+      /* Create alias for __x86.return_thunk/__x86.return_thunk_bnd.  */
364
+      char alias[32];
365
+
366
+      indirect_thunk_name (alias, regno, need_bnd_p, true);
367
+#if TARGET_MACHO
368
+      if (TARGET_MACHO)
369
+	{
370
+	  fputs ("\t.weak_definition\t", asm_out_file);
371
+	  assemble_name (asm_out_file, alias);
372
+	  fputs ("\n\t.private_extern\t", asm_out_file);
373
+	  assemble_name (asm_out_file, alias);
374
+	  putc ('\n', asm_out_file);
375
+	  ASM_OUTPUT_LABEL (asm_out_file, alias);
376
+	}
377
+#else
378
+      ASM_OUTPUT_DEF (asm_out_file, alias, name);
379
+      if (USE_HIDDEN_LINKONCE)
380
+	{
381
+	  fputs ("\t.globl\t", asm_out_file);
382
+	  assemble_name (asm_out_file, alias);
383
+	  putc ('\n', asm_out_file);
384
+	  fputs ("\t.hidden\t", asm_out_file);
385
+	  assemble_name (asm_out_file, alias);
386
+	  putc ('\n', asm_out_file);
387
+	}
388
+#endif
389
+    }
390
+
391
   DECL_INITIAL (decl) = make_node (BLOCK);
392
   current_function_decl = decl;
393
   allocate_struct_function (decl, false);
394
@@ -26121,7 +26193,7 @@ ix86_output_indirect_branch_via_reg (rtx
395
 	  else
396
 	    indirect_thunks_used |= 1 << i;
397
 	}
398
-      indirect_thunk_name (thunk_name_buf, regno, need_bnd_p);
399
+      indirect_thunk_name (thunk_name_buf, regno, need_bnd_p, false);
400
       thunk_name = thunk_name_buf;
401
     }
402
   else
403
@@ -26230,7 +26302,7 @@ ix86_output_indirect_branch_via_push (rt
404
 	  else
405
 	    indirect_thunk_needed = true;
406
 	}
407
-      indirect_thunk_name (thunk_name_buf, regno, need_bnd_p);
408
+      indirect_thunk_name (thunk_name_buf, regno, need_bnd_p, false);
409
       thunk_name = thunk_name_buf;
410
     }
411
   else
412
@@ -26365,6 +26437,46 @@ ix86_output_indirect_jmp (rtx call_op, b
413
     return "%!jmp\t%A0";
414
 }
415
 
416
+/* Output function return.  CALL_OP is the jump target.  Add a REP
417
+   prefix to RET if LONG_P is true and function return is kept.  */
418
+
419
+const char *
420
+ix86_output_function_return (bool long_p)
421
+{
422
+  if (cfun->machine->function_return_type != indirect_branch_keep)
423
+    {
424
+      char thunk_name[32];
425
+      bool need_bnd_p = ix86_bnd_prefixed_insn_p (current_output_insn);
426
+
427
+      if (cfun->machine->function_return_type
428
+	  != indirect_branch_thunk_inline)
429
+	{
430
+	  bool need_thunk = (cfun->machine->function_return_type
431
+			     == indirect_branch_thunk);
432
+	  indirect_thunk_name (thunk_name, -1, need_bnd_p, true);
433
+	  if (need_bnd_p)
434
+	    {
435
+	      indirect_thunk_bnd_needed |= need_thunk;
436
+	      fprintf (asm_out_file, "\tbnd jmp\t%s\n", thunk_name);
437
+	    }
438
+	  else
439
+	    {
440
+	      indirect_thunk_needed |= need_thunk;
441
+	      fprintf (asm_out_file, "\tjmp\t%s\n", thunk_name);
442
+	    }
443
+	}
444
+      else
445
+	output_indirect_thunk (need_bnd_p, -1);
446
+
447
+      return "";
448
+    }
449
+
450
+  if (!long_p || ix86_bnd_prefixed_insn_p (current_output_insn))
451
+    return "%!ret";
452
+
453
+  return "rep%; ret";
454
+}
455
+
456
 /* Output the assembly for a call instruction.  */
457
 
458
 const char *
459
@@ -43625,6 +43737,28 @@ ix86_handle_fndecl_attribute (tree *node
460
 	}
461
     }
462
 
463
+  if (is_attribute_p ("function_return", name))
464
+    {
465
+      tree cst = TREE_VALUE (args);
466
+      if (TREE_CODE (cst) != STRING_CST)
467
+	{
468
+	  warning (OPT_Wattributes,
469
+		   "%qE attribute requires a string constant argument",
470
+		   name);
471
+	  *no_add_attrs = true;
472
+	}
473
+      else if (strcmp (TREE_STRING_POINTER (cst), "keep") != 0
474
+	       && strcmp (TREE_STRING_POINTER (cst), "thunk") != 0
475
+	       && strcmp (TREE_STRING_POINTER (cst), "thunk-inline") != 0
476
+	       && strcmp (TREE_STRING_POINTER (cst), "thunk-extern") != 0)
477
+	{
478
+	  warning (OPT_Wattributes,
479
+		   "argument to %qE attribute is not "
480
+		   "(keep|thunk|thunk-inline|thunk-extern)", name);
481
+	  *no_add_attrs = true;
482
+	}
483
+    }
484
+
485
   return NULL_TREE;
486
 }
487
 
488
@@ -47519,6 +47653,8 @@ static const struct attribute_spec ix86_
489
     ix86_handle_callee_pop_aggregate_return, true },
490
   { "indirect_branch", 1, 1, true, false, false,
491
     ix86_handle_fndecl_attribute, false },
492
+  { "function_return", 1, 1, true, false, false,
493
+    ix86_handle_fndecl_attribute, false },
494
 
495
   /* End element.  */
496
   { NULL,        0, 0, false, false, false, NULL, false }
497
Index: b/src/gcc/config/i386/i386.h
498
===================================================================
499
--- a/src/gcc/config/i386/i386.h
500
+++ b/src/gcc/config/i386/i386.h
501
@@ -2562,6 +2562,9 @@ struct GTY(()) machine_function {
502
      "indirect_jump" or "tablejump".  */
503
   BOOL_BITFIELD has_local_indirect_jump : 1;
504
 
505
+  /* How to generate function return.  */
506
+  ENUM_BITFIELD(indirect_branch) function_return_type : 3;
507
+
508
   /* During prologue/epilogue generation, the current frame state.
509
      Otherwise, the frame state at the end of the prologue.  */
510
   struct machine_frame_state fs;
511
Index: b/src/gcc/config/i386/i386.md
512
===================================================================
513
--- a/src/gcc/config/i386/i386.md
514
+++ b/src/gcc/config/i386/i386.md
515
@@ -12169,7 +12169,7 @@
516
 (define_insn "simple_return_internal"
517
   [(simple_return)]
518
   "reload_completed"
519
-  "%!ret"
520
+  "* return ix86_output_function_return (false);"
521
   [(set_attr "length_nobnd" "1")
522
    (set_attr "atom_unit" "jeu")
523
    (set_attr "length_immediate" "0")
524
@@ -12182,12 +12182,7 @@
525
   [(simple_return)
526
    (unspec [(const_int 0)] UNSPEC_REP)]
527
   "reload_completed"
528
-{
529
-  if (ix86_bnd_prefixed_insn_p (insn))
530
-    return "%!ret";
531
-
532
-  return "rep%; ret";
533
-}
534
+  "* return ix86_output_function_return (true);"
535
   [(set_attr "length" "2")
536
    (set_attr "atom_unit" "jeu")
537
    (set_attr "length_immediate" "0")
538
Index: b/src/gcc/config/i386/i386.opt
539
===================================================================
540
--- a/src/gcc/config/i386/i386.opt
541
+++ b/src/gcc/config/i386/i386.opt
542
@@ -881,9 +881,13 @@ mindirect-branch=
543
 Target Report RejectNegative Joined Enum(indirect_branch) Var(ix86_indirect_branch) Init(indirect_branch_keep)
544
 Convert indirect call and jump to call and return thunks.
545
 
546
+mfunction-return=
547
+Target Report RejectNegative Joined Enum(indirect_branch) Var(ix86_function_return) Init(indirect_branch_keep)
548
+Convert function return to call and return thunk.
549
+
550
 Enum
551
 Name(indirect_branch) Type(enum indirect_branch)
552
-Known indirect branch choices (for use with the -mindirect-branch= option):
553
+Known indirect branch choices (for use with the -mindirect-branch=/-mfunction-return= options):
554
 
555
 EnumValue
556
 Enum(indirect_branch) String(keep) Value(indirect_branch_keep)
557
Index: b/src/gcc/doc/extend.texi
558
===================================================================
559
--- a/src/gcc/doc/extend.texi
560
+++ b/src/gcc/doc/extend.texi
561
@@ -4129,6 +4129,15 @@ call and jump to call and return thunk.
562
 indirect call and jump to inlined call and return thunk.
563
 @samp{thunk-extern} converts indirect call and jump to external call
564
 and return thunk provided in a separate object file.
565
+
566
+@item function_return("@var{choice}")
567
+@cindex @code{function_return} function attribute, x86
568
+On x86 targets, the @code{function_return} attribute causes the compiler
569
+to convert function return with @var{choice}.  @samp{keep} keeps function
570
+return unmodified.  @samp{thunk} converts function return to call and
571
+return thunk.  @samp{thunk-inline} converts function return to inlined
572
+call and return thunk.  @samp{thunk-extern} converts function return to
573
+external call and return thunk provided in a separate object file.
574
 @end table
575
 
576
 On the PowerPC, the following options are allowed:
577
Index: b/src/gcc/doc/invoke.texi
578
===================================================================
579
--- a/src/gcc/doc/invoke.texi
580
+++ b/src/gcc/doc/invoke.texi
581
@@ -1091,7 +1091,7 @@ See RS/6000 and PowerPC Options.
582
 -msse2avx -mfentry -mrecord-mcount -mnop-mcount -m8bit-idiv @gol
583
 -mavx256-split-unaligned-load -mavx256-split-unaligned-store @gol
584
 -malign-data=@var{type} -mstack-protector-guard=@var{guard} @gol
585
--mindirect-branch=@var{choice}}
586
+-mindirect-branch=@var{choice} -mfunction-return=@var{choice}}
587
 
588
 @emph{x86 Windows Options}
589
 @gccoptlist{-mconsole -mcygwin -mno-cygwin -mdll @gol
590
@@ -24029,6 +24029,17 @@ to external call and return thunk provid
591
 You can control this behavior for a specific function by using the
592
 function attribute @code{indirect_branch}.  @xref{Function Attributes}.
593
 
594
+@item -mfunction-return=@var{choice}
595
+@opindex -mfunction-return
596
+Convert function return with @var{choice}.  The default is @samp{keep},
597
+which keeps function return unmodified.  @samp{thunk} converts function
598
+return to call and return thunk.  @samp{thunk-inline} converts function
599
+return to inlined call and return thunk.  @samp{thunk-extern} converts
600
+function return to external call and return thunk provided in a separate
601
+object file.  You can control this behavior for a specific function by
602
+using the function attribute @code{function_return}.
603
+@xref{Function Attributes}.
604
+
605
 @end table
606
 
607
 @c man end
608
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c
609
===================================================================
610
--- a/src/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c
611
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c
612
@@ -1,5 +1,5 @@
613
 /* { dg-do compile } */
614
-/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
615
+/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
616
 
617
 typedef void (*dispatch_t)(long offset);
618
 
619
@@ -11,7 +11,7 @@ male_indirect_jump (long offset)
620
   dispatch(offset);
621
 }
622
 
623
-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
624
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
625
 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
626
 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
627
 /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
628
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c
629
===================================================================
630
--- a/src/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c
631
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c
632
@@ -1,5 +1,5 @@
633
 /* { dg-do compile } */
634
-/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
635
+/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
636
 
637
 typedef void (*dispatch_t)(long offset);
638
 
639
@@ -11,7 +11,7 @@ male_indirect_jump (long offset)
640
   dispatch[offset](offset);
641
 }
642
 
643
-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
644
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
645
 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
646
 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
647
 /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
648
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c
649
===================================================================
650
--- a/src/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c
651
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c
652
@@ -1,5 +1,5 @@
653
 /* { dg-do compile } */
654
-/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
655
+/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
656
 
657
 typedef void (*dispatch_t)(long offset);
658
 
659
@@ -12,7 +12,7 @@ male_indirect_jump (long offset)
660
   return 0;
661
 }
662
 
663
-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
664
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
665
 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
666
 /* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
667
 /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
668
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c
669
===================================================================
670
--- a/src/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c
671
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c
672
@@ -1,5 +1,5 @@
673
 /* { dg-do compile } */
674
-/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
675
+/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
676
 
677
 typedef void (*dispatch_t)(long offset);
678
 
679
@@ -12,7 +12,7 @@ male_indirect_jump (long offset)
680
   return 0;
681
 }
682
 
683
-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
684
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
685
 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
686
 /* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
687
 /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
688
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c
689
===================================================================
690
--- a/src/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c
691
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c
692
@@ -1,5 +1,5 @@
693
 /* { dg-do compile } */
694
-/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
695
+/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
696
 
697
 void func0 (void);
698
 void func1 (void);
699
@@ -35,7 +35,7 @@ bar (int i)
700
     }
701
 }
702
 
703
-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { ! x32 } } } } */
704
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { { ! x32 } && *-*-linux* } } } } */
705
 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
706
 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
707
 /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
708
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c
709
===================================================================
710
--- a/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c
711
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c
712
@@ -1,5 +1,5 @@
713
 /* { dg-do compile } */
714
-/* { dg-options "-O2 -fno-pic" } */
715
+/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
716
 
717
 typedef void (*dispatch_t)(long offset);
718
 
719
@@ -14,7 +14,7 @@ male_indirect_jump (long offset)
720
   dispatch(offset);
721
 }
722
 
723
-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
724
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
725
 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
726
 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
727
 /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
728
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c
729
===================================================================
730
--- a/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c
731
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c
732
@@ -1,5 +1,5 @@
733
 /* { dg-do compile } */
734
-/* { dg-options "-O2 -fno-pic" } */
735
+/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
736
 
737
 typedef void (*dispatch_t)(long offset);
738
 
739
@@ -12,7 +12,7 @@ male_indirect_jump (long offset)
740
   dispatch[offset](offset);
741
 }
742
 
743
-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
744
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
745
 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
746
 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
747
 /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
748
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c
749
===================================================================
750
--- a/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c
751
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c
752
@@ -1,5 +1,5 @@
753
 /* { dg-do compile } */
754
-/* { dg-options "-O2 -fno-pic" } */
755
+/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
756
 
757
 typedef void (*dispatch_t)(long offset);
758
 
759
@@ -14,7 +14,7 @@ male_indirect_jump (long offset)
760
   return 0;
761
 }
762
 
763
-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
764
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
765
 /* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */
766
 /* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */
767
 /* { dg-final { scan-assembler {\tpause} } } */
768
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c
769
===================================================================
770
--- a/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c
771
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c
772
@@ -1,5 +1,5 @@
773
 /* { dg-do compile } */
774
-/* { dg-options "-O2 -fno-pic" } */
775
+/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
776
 
777
 typedef void (*dispatch_t)(long offset);
778
 
779
@@ -13,7 +13,7 @@ male_indirect_jump (long offset)
780
   return 0;
781
 }
782
 
783
-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
784
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
785
 /* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 2 } } */
786
 /* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 2 } } */
787
 /* { dg-final { scan-assembler {\tpause} } } */
788
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c
789
===================================================================
790
--- a/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c
791
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c
792
@@ -1,5 +1,5 @@
793
 /* { dg-do compile } */
794
-/* { dg-options "-O2 -fno-pic" } */
795
+/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
796
 
797
 typedef void (*dispatch_t)(long offset);
798
 
799
@@ -14,7 +14,7 @@ male_indirect_jump (long offset)
800
   return 0;
801
 }
802
 
803
-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
804
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
805
 /* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
806
 /* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
807
 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
808
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c
809
===================================================================
810
--- a/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c
811
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c
812
@@ -1,5 +1,5 @@
813
 /* { dg-do compile } */
814
-/* { dg-options "-O2 -fno-pic" } */
815
+/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
816
 
817
 typedef void (*dispatch_t)(long offset);
818
 
819
@@ -13,7 +13,7 @@ male_indirect_jump (long offset)
820
   return 0;
821
 }
822
 
823
-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
824
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
825
 /* { dg-final { scan-assembler-times "jmp\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
826
 /* { dg-final { scan-assembler-times "call\[ \t\]*\.LIND" 1 { target { ! x32 } } } } */
827
 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" { target { ! x32 } } } } */
828
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c
829
===================================================================
830
--- a/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c
831
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c
832
@@ -1,5 +1,5 @@
833
 /* { dg-do compile } */
834
-/* { dg-options "-O2 -fno-pic" } */
835
+/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
836
 
837
 void func0 (void);
838
 void func1 (void);
839
@@ -36,7 +36,7 @@ bar (int i)
840
     }
841
 }
842
 
843
-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { ! x32 } } } } */
844
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*\.L\[0-9\]+\\(,%" { target { { ! x32 } && *-*-linux* } } } } */
845
 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" { target x32 } } } */
846
 /* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk" } } */
847
 /* { dg-final { scan-assembler-not {\t(lfence|pause)} } } */
848
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c
849
===================================================================
850
--- a/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c
851
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-8.c
852
@@ -1,5 +1,5 @@
853
 /* { dg-do compile } */
854
-/* { dg-options "-O2 -mindirect-branch=thunk -fno-pic" } */
855
+/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
856
 
857
 void func0 (void);
858
 void func1 (void);
859
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c
860
===================================================================
861
--- a/src/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c
862
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c
863
@@ -1,5 +1,5 @@
864
 /* { dg-do compile { target { ! x32 } } } */
865
-/* { dg-options "-O2 -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
866
+/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
867
 
868
 void (*dispatch) (char *);
869
 char buf[10];
870
@@ -10,7 +10,7 @@ foo (void)
871
   dispatch (buf);
872
 }
873
 
874
-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
875
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
876
 /* { dg-final { scan-assembler "pushq\[ \t\]%rax" { target x32 } } } */
877
 /* { dg-final { scan-assembler "bnd jmp\[ \t\]*__x86_indirect_thunk_bnd" } } */
878
 /* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
879
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c
880
===================================================================
881
--- a/src/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c
882
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c
883
@@ -1,5 +1,5 @@
884
 /* { dg-do compile { target { ! x32 } } } */
885
-/* { dg-options "-O2 -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
886
+/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
887
 
888
 void (*dispatch) (char *);
889
 char buf[10];
890
@@ -11,7 +11,7 @@ foo (void)
891
   return 0;
892
 }
893
 
894
-/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { ! x32 } } } } */
895
+/* { dg-final { scan-assembler "push(?:l|q)\[ \t\]*_?dispatch" { target { { ! x32 } && *-*-linux* } } } } */
896
 /* { dg-final { scan-assembler "pushq\[ \t\]%rax" { target x32 } } } */
897
 /* { dg-final { scan-assembler "bnd jmp\[ \t\]*__x86_indirect_thunk_bnd" } } */
898
 /* { dg-final { scan-assembler "bnd jmp\[ \t\]*\.LIND" } } */
899
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c
900
===================================================================
901
--- a/src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c
902
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c
903
@@ -1,5 +1,5 @@
904
 /* { dg-do compile } */
905
-/* { dg-options "-O2 -mindirect-branch=thunk-extern -fno-pic" } */
906
+/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
907
 
908
 typedef void (*dispatch_t)(long offset);
909