diff options
author | Martin Jansa <martin.jansa@gmail.com> | 2016-02-18 10:41:14 +0100 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2016-02-19 15:33:02 +0000 |
commit | 51fc30472f5e3438e1e892e5a6dd3de4b80427a4 (patch) | |
tree | 328043027b951cca75d180c97a11b5ab35940abf /meta | |
parent | ed20c6ca446a8788615e497bd4452195537deab5 (diff) | |
download | poky-51fc30472f5e3438e1e892e5a6dd3de4b80427a4.tar.gz |
gcc-5.3: backport fix for PR-target-65358
(From OE-Core rev: f8616c30870670992c00be349bedf64b35833c34)
Signed-off-by: Martin Jansa <Martin.Jansa@gmail.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'meta')
-rw-r--r-- | meta/recipes-devtools/gcc/gcc-5.3.inc | 3 | ||||
-rw-r--r-- | meta/recipes-devtools/gcc/gcc-5.3/0053-expr.c-PR-target-65358-Avoid-clobbering-partial-argu.patch | 307 |
2 files changed, 309 insertions, 1 deletions
diff --git a/meta/recipes-devtools/gcc/gcc-5.3.inc b/meta/recipes-devtools/gcc/gcc-5.3.inc index a522bc40c2..a2e347adfe 100644 --- a/meta/recipes-devtools/gcc/gcc-5.3.inc +++ b/meta/recipes-devtools/gcc/gcc-5.3.inc | |||
@@ -82,7 +82,8 @@ SRC_URI = "\ | |||
82 | file://0050-powerpc-pass-secure-plt-to-the-linker.patch \ | 82 | file://0050-powerpc-pass-secure-plt-to-the-linker.patch \ |
83 | file://0051-Ignore-fdebug-prefix-map-in-producer-string-by-Danie.patch \ | 83 | file://0051-Ignore-fdebug-prefix-map-in-producer-string-by-Danie.patch \ |
84 | file://0052-nios2-use-ret-with-r31.patch \ | 84 | file://0052-nios2-use-ret-with-r31.patch \ |
85 | " | 85 | file://0053-expr.c-PR-target-65358-Avoid-clobbering-partial-argu.patch \ |
86 | " | ||
86 | 87 | ||
87 | BACKPORTS = "" | 88 | BACKPORTS = "" |
88 | 89 | ||
diff --git a/meta/recipes-devtools/gcc/gcc-5.3/0053-expr.c-PR-target-65358-Avoid-clobbering-partial-argu.patch b/meta/recipes-devtools/gcc/gcc-5.3/0053-expr.c-PR-target-65358-Avoid-clobbering-partial-argu.patch new file mode 100644 index 0000000000..c18f40e740 --- /dev/null +++ b/meta/recipes-devtools/gcc/gcc-5.3/0053-expr.c-PR-target-65358-Avoid-clobbering-partial-argu.patch | |||
@@ -0,0 +1,307 @@ | |||
1 | From 536b8318974495cde2b42c3c2742748e2b271be0 Mon Sep 17 00:00:00 2001 | ||
2 | From: ktkachov <ktkachov@138bc75d-0d04-0410-961f-82ee72b054a4> | ||
3 | Date: Wed, 27 May 2015 13:25:01 +0000 | ||
4 | Subject: [PATCH] PR target/65358 Avoid clobbering partial argument during | ||
5 | sibcall | ||
6 | |||
7 | PR target/65358 | ||
8 | * expr.c (memory_load_overlap): New function. | ||
9 | (emit_push_insn): When pushing partial args to the stack would | ||
10 | clobber the register part load the overlapping part into a pseudo | ||
11 | and put it into the hard reg after pushing. Change return type | ||
12 | to bool. Add bool argument. | ||
13 | * expr.h (emit_push_insn): Change return type to bool. | ||
14 | Add bool argument. | ||
15 | * calls.c (expand_call): Cancel sibcall optimization when encountering | ||
16 | partial argument on targets with ARGS_GROW_DOWNWARD and | ||
17 | !STACK_GROWS_DOWNWARD. | ||
18 | (emit_library_call_value_1): Update callsite of emit_push_insn. | ||
19 | (store_one_arg): Likewise. | ||
20 | |||
21 | PR target/65358 | ||
22 | * gcc.dg/pr65358.c: New test. | ||
23 | |||
24 | git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@223753 138bc75d-0d04-0410-961f-82ee72b054a4 | ||
25 | |||
26 | Upstream-Status: Backport from 6.0 | ||
27 | Signed-off-by: Martin Jansa <Martin.Jansa@gmail.com> | ||
28 | --- | ||
29 | gcc/calls.c | 17 ++++++-- | ||
30 | gcc/expr.c | 90 +++++++++++++++++++++++++++++++++++++----- | ||
31 | gcc/expr.h | 4 +- | ||
32 | gcc/testsuite/gcc.dg/pr65358.c | 33 ++++++++++++++++ | ||
33 | 4 files changed, 129 insertions(+), 15 deletions(-) | ||
34 | create mode 100644 gcc/testsuite/gcc.dg/pr65358.c | ||
35 | |||
36 | diff --git a/gcc/calls.c b/gcc/calls.c | ||
37 | index ee8ea5f..2334381 100644 | ||
38 | --- a/gcc/calls.c | ||
39 | +++ b/gcc/calls.c | ||
40 | @@ -3236,6 +3236,14 @@ expand_call (tree exp, rtx target, int ignore) | ||
41 | { | ||
42 | rtx_insn *before_arg = get_last_insn (); | ||
43 | |||
44 | + /* On targets with weird calling conventions (e.g. PA) it's | ||
45 | + hard to ensure that all cases of argument overlap between | ||
46 | + stack and registers work. Play it safe and bail out. */ | ||
47 | +#if defined(ARGS_GROW_DOWNWARD) && !defined(STACK_GROWS_DOWNWARD) | ||
48 | + sibcall_failure = 1; | ||
49 | + break; | ||
50 | +#endif | ||
51 | + | ||
52 | if (store_one_arg (&args[i], argblock, flags, | ||
53 | adjusted_args_size.var != 0, | ||
54 | reg_parm_stack_space) | ||
55 | @@ -4279,7 +4287,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, | ||
56 | partial, reg, 0, argblock, | ||
57 | GEN_INT (argvec[argnum].locate.offset.constant), | ||
58 | reg_parm_stack_space, | ||
59 | - ARGS_SIZE_RTX (argvec[argnum].locate.alignment_pad)); | ||
60 | + ARGS_SIZE_RTX (argvec[argnum].locate.alignment_pad), false); | ||
61 | |||
62 | /* Now mark the segment we just used. */ | ||
63 | if (ACCUMULATE_OUTGOING_ARGS) | ||
64 | @@ -4886,10 +4894,11 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags, | ||
65 | |||
66 | /* This isn't already where we want it on the stack, so put it there. | ||
67 | This can either be done with push or copy insns. */ | ||
68 | - emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), NULL_RTX, | ||
69 | + if (!emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), NULL_RTX, | ||
70 | parm_align, partial, reg, used - size, argblock, | ||
71 | ARGS_SIZE_RTX (arg->locate.offset), reg_parm_stack_space, | ||
72 | - ARGS_SIZE_RTX (arg->locate.alignment_pad)); | ||
73 | + ARGS_SIZE_RTX (arg->locate.alignment_pad), true)) | ||
74 | + sibcall_failure = 1; | ||
75 | |||
76 | /* Unless this is a partially-in-register argument, the argument is now | ||
77 | in the stack. */ | ||
78 | @@ -5001,7 +5010,7 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags, | ||
79 | emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), size_rtx, | ||
80 | parm_align, partial, reg, excess, argblock, | ||
81 | ARGS_SIZE_RTX (arg->locate.offset), reg_parm_stack_space, | ||
82 | - ARGS_SIZE_RTX (arg->locate.alignment_pad)); | ||
83 | + ARGS_SIZE_RTX (arg->locate.alignment_pad), false); | ||
84 | |||
85 | /* Unless this is a partially-in-register argument, the argument is now | ||
86 | in the stack. | ||
87 | diff --git a/gcc/expr.c b/gcc/expr.c | ||
88 | index 5c09550..24a6293 100644 | ||
89 | --- a/gcc/expr.c | ||
90 | +++ b/gcc/expr.c | ||
91 | @@ -4121,12 +4121,35 @@ emit_single_push_insn (machine_mode mode, rtx x, tree type) | ||
92 | } | ||
93 | #endif | ||
94 | |||
95 | +/* If reading SIZE bytes from X will end up reading from | ||
96 | + Y return the number of bytes that overlap. Return -1 | ||
97 | + if there is no overlap or -2 if we can't determine | ||
98 | + (for example when X and Y have different base registers). */ | ||
99 | + | ||
100 | +static int | ||
101 | +memory_load_overlap (rtx x, rtx y, HOST_WIDE_INT size) | ||
102 | +{ | ||
103 | + rtx tmp = plus_constant (Pmode, x, size); | ||
104 | + rtx sub = simplify_gen_binary (MINUS, Pmode, tmp, y); | ||
105 | + | ||
106 | + if (!CONST_INT_P (sub)) | ||
107 | + return -2; | ||
108 | + | ||
109 | + HOST_WIDE_INT val = INTVAL (sub); | ||
110 | + | ||
111 | + return IN_RANGE (val, 1, size) ? val : -1; | ||
112 | +} | ||
113 | + | ||
114 | /* Generate code to push X onto the stack, assuming it has mode MODE and | ||
115 | type TYPE. | ||
116 | MODE is redundant except when X is a CONST_INT (since they don't | ||
117 | carry mode info). | ||
118 | SIZE is an rtx for the size of data to be copied (in bytes), | ||
119 | needed only if X is BLKmode. | ||
120 | + Return true if successful. May return false if asked to push a | ||
121 | + partial argument during a sibcall optimization (as specified by | ||
122 | + SIBCALL_P) and the incoming and outgoing pointers cannot be shown | ||
123 | + to not overlap. | ||
124 | |||
125 | ALIGN (in bits) is maximum alignment we can assume. | ||
126 | |||
127 | @@ -4152,11 +4175,11 @@ emit_single_push_insn (machine_mode mode, rtx x, tree type) | ||
128 | for arguments passed in registers. If nonzero, it will be the number | ||
129 | of bytes required. */ | ||
130 | |||
131 | -void | ||
132 | +bool | ||
133 | emit_push_insn (rtx x, machine_mode mode, tree type, rtx size, | ||
134 | unsigned int align, int partial, rtx reg, int extra, | ||
135 | rtx args_addr, rtx args_so_far, int reg_parm_stack_space, | ||
136 | - rtx alignment_pad) | ||
137 | + rtx alignment_pad, bool sibcall_p) | ||
138 | { | ||
139 | rtx xinner; | ||
140 | enum direction stack_direction | ||
141 | @@ -4179,6 +4202,10 @@ emit_push_insn (rtx x, machine_mode mode, tree type, rtx size, | ||
142 | |||
143 | xinner = x; | ||
144 | |||
145 | + int nregs = partial / UNITS_PER_WORD; | ||
146 | + rtx *tmp_regs = NULL; | ||
147 | + int overlapping = 0; | ||
148 | + | ||
149 | if (mode == BLKmode | ||
150 | || (STRICT_ALIGNMENT && align < GET_MODE_ALIGNMENT (mode))) | ||
151 | { | ||
152 | @@ -4309,6 +4336,43 @@ emit_push_insn (rtx x, machine_mode mode, tree type, rtx size, | ||
153 | PARM_BOUNDARY. Assume the caller isn't lying. */ | ||
154 | set_mem_align (target, align); | ||
155 | |||
156 | + /* If part should go in registers and pushing to that part would | ||
157 | + overwrite some of the values that need to go into regs, load the | ||
158 | + overlapping values into temporary pseudos to be moved into the hard | ||
159 | + regs at the end after the stack pushing has completed. | ||
160 | + We cannot load them directly into the hard regs here because | ||
161 | + they can be clobbered by the block move expansions. | ||
162 | + See PR 65358. */ | ||
163 | + | ||
164 | + if (partial > 0 && reg != 0 && mode == BLKmode | ||
165 | + && GET_CODE (reg) != PARALLEL) | ||
166 | + { | ||
167 | + overlapping = memory_load_overlap (XEXP (x, 0), temp, partial); | ||
168 | + if (overlapping > 0) | ||
169 | + { | ||
170 | + gcc_assert (overlapping % UNITS_PER_WORD == 0); | ||
171 | + overlapping /= UNITS_PER_WORD; | ||
172 | + | ||
173 | + tmp_regs = XALLOCAVEC (rtx, overlapping); | ||
174 | + | ||
175 | + for (int i = 0; i < overlapping; i++) | ||
176 | + tmp_regs[i] = gen_reg_rtx (word_mode); | ||
177 | + | ||
178 | + for (int i = 0; i < overlapping; i++) | ||
179 | + emit_move_insn (tmp_regs[i], | ||
180 | + operand_subword_force (target, i, mode)); | ||
181 | + } | ||
182 | + else if (overlapping == -1) | ||
183 | + overlapping = 0; | ||
184 | + /* Could not determine whether there is overlap. | ||
185 | + Fail the sibcall. */ | ||
186 | + else | ||
187 | + { | ||
188 | + overlapping = 0; | ||
189 | + if (sibcall_p) | ||
190 | + return false; | ||
191 | + } | ||
192 | + } | ||
193 | emit_block_move (target, xinner, size, BLOCK_OP_CALL_PARM); | ||
194 | } | ||
195 | } | ||
196 | @@ -4363,12 +4427,13 @@ emit_push_insn (rtx x, machine_mode mode, tree type, rtx size, | ||
197 | has a size a multiple of a word. */ | ||
198 | for (i = size - 1; i >= not_stack; i--) | ||
199 | if (i >= not_stack + offset) | ||
200 | - emit_push_insn (operand_subword_force (x, i, mode), | ||
201 | + if (!emit_push_insn (operand_subword_force (x, i, mode), | ||
202 | word_mode, NULL_TREE, NULL_RTX, align, 0, NULL_RTX, | ||
203 | 0, args_addr, | ||
204 | GEN_INT (args_offset + ((i - not_stack + skip) | ||
205 | * UNITS_PER_WORD)), | ||
206 | - reg_parm_stack_space, alignment_pad); | ||
207 | + reg_parm_stack_space, alignment_pad, sibcall_p)) | ||
208 | + return false; | ||
209 | } | ||
210 | else | ||
211 | { | ||
212 | @@ -4411,9 +4476,8 @@ emit_push_insn (rtx x, machine_mode mode, tree type, rtx size, | ||
213 | } | ||
214 | } | ||
215 | |||
216 | - /* If part should go in registers, copy that part | ||
217 | - into the appropriate registers. Do this now, at the end, | ||
218 | - since mem-to-mem copies above may do function calls. */ | ||
219 | + /* Move the partial arguments into the registers and any overlapping | ||
220 | + values that we moved into the pseudos in tmp_regs. */ | ||
221 | if (partial > 0 && reg != 0) | ||
222 | { | ||
223 | /* Handle calls that pass values in multiple non-contiguous locations. | ||
224 | @@ -4421,9 +4485,15 @@ emit_push_insn (rtx x, machine_mode mode, tree type, rtx size, | ||
225 | if (GET_CODE (reg) == PARALLEL) | ||
226 | emit_group_load (reg, x, type, -1); | ||
227 | else | ||
228 | - { | ||
229 | + { | ||
230 | gcc_assert (partial % UNITS_PER_WORD == 0); | ||
231 | - move_block_to_reg (REGNO (reg), x, partial / UNITS_PER_WORD, mode); | ||
232 | + move_block_to_reg (REGNO (reg), x, nregs - overlapping, mode); | ||
233 | + | ||
234 | + for (int i = 0; i < overlapping; i++) | ||
235 | + emit_move_insn (gen_rtx_REG (word_mode, REGNO (reg) | ||
236 | + + nregs - overlapping + i), | ||
237 | + tmp_regs[i]); | ||
238 | + | ||
239 | } | ||
240 | } | ||
241 | |||
242 | @@ -4432,6 +4502,8 @@ emit_push_insn (rtx x, machine_mode mode, tree type, rtx size, | ||
243 | |||
244 | if (alignment_pad && args_addr == 0) | ||
245 | anti_adjust_stack (alignment_pad); | ||
246 | + | ||
247 | + return true; | ||
248 | } | ||
249 | |||
250 | /* Return X if X can be used as a subtarget in a sequence of arithmetic | ||
251 | diff --git a/gcc/expr.h b/gcc/expr.h | ||
252 | index 867852e..5fcc13f 100644 | ||
253 | --- a/gcc/expr.h | ||
254 | +++ b/gcc/expr.h | ||
255 | @@ -218,8 +218,8 @@ extern rtx emit_move_resolve_push (machine_mode, rtx); | ||
256 | extern rtx push_block (rtx, int, int); | ||
257 | |||
258 | /* Generate code to push something onto the stack, given its mode and type. */ | ||
259 | -extern void emit_push_insn (rtx, machine_mode, tree, rtx, unsigned int, | ||
260 | - int, rtx, int, rtx, rtx, int, rtx); | ||
261 | +extern bool emit_push_insn (rtx, machine_mode, tree, rtx, unsigned int, | ||
262 | + int, rtx, int, rtx, rtx, int, rtx, bool); | ||
263 | |||
264 | /* Expand an assignment that stores the value of FROM into TO. */ | ||
265 | extern void expand_assignment (tree, tree, bool); | ||
266 | diff --git a/gcc/testsuite/gcc.dg/pr65358.c b/gcc/testsuite/gcc.dg/pr65358.c | ||
267 | new file mode 100644 | ||
268 | index 0000000..ba89fd4 | ||
269 | --- /dev/null | ||
270 | +++ b/gcc/testsuite/gcc.dg/pr65358.c | ||
271 | @@ -0,0 +1,33 @@ | ||
272 | +/* { dg-do run } */ | ||
273 | +/* { dg-options "-O2" } */ | ||
274 | + | ||
275 | +struct pack | ||
276 | +{ | ||
277 | + int fine; | ||
278 | + int victim; | ||
279 | + int killer; | ||
280 | +}; | ||
281 | + | ||
282 | +int __attribute__ ((__noinline__, __noclone__)) | ||
283 | +bar (int a, int b, struct pack p) | ||
284 | +{ | ||
285 | + if (a != 20 || b != 30) | ||
286 | + __builtin_abort (); | ||
287 | + if (p.fine != 40 || p.victim != 50 || p.killer != 60) | ||
288 | + __builtin_abort (); | ||
289 | + return 0; | ||
290 | +} | ||
291 | + | ||
292 | +int __attribute__ ((__noinline__, __noclone__)) | ||
293 | +foo (int arg1, int arg2, int arg3, struct pack p) | ||
294 | +{ | ||
295 | + return bar (arg2, arg3, p); | ||
296 | +} | ||
297 | + | ||
298 | +int main (void) | ||
299 | +{ | ||
300 | + struct pack p = { 40, 50, 60 }; | ||
301 | + | ||
302 | + (void) foo (10, 20, 30, p); | ||
303 | + return 0; | ||
304 | +} | ||
305 | -- | ||
306 | 2.7.0 | ||
307 | |||