annotate gcc/config/rs6000/rs6000-p8swap.c @ 111:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents
children 84e7813d76e9
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
111
kono
parents:
diff changeset
1 /* Subroutines used to remove unnecessary doubleword swaps
kono
parents:
diff changeset
2 for p8 little-endian VSX code.
kono
parents:
diff changeset
3 Copyright (C) 1991-2017 Free Software Foundation, Inc.
kono
parents:
diff changeset
4
kono
parents:
diff changeset
5 This file is part of GCC.
kono
parents:
diff changeset
6
kono
parents:
diff changeset
7 GCC is free software; you can redistribute it and/or modify it
kono
parents:
diff changeset
8 under the terms of the GNU General Public License as published
kono
parents:
diff changeset
9 by the Free Software Foundation; either version 3, or (at your
kono
parents:
diff changeset
10 option) any later version.
kono
parents:
diff changeset
11
kono
parents:
diff changeset
12 GCC is distributed in the hope that it will be useful, but WITHOUT
kono
parents:
diff changeset
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
kono
parents:
diff changeset
14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
kono
parents:
diff changeset
15 License for more details.
kono
parents:
diff changeset
16
kono
parents:
diff changeset
17 You should have received a copy of the GNU General Public License
kono
parents:
diff changeset
18 along with GCC; see the file COPYING3. If not see
kono
parents:
diff changeset
19 <http://www.gnu.org/licenses/>. */
kono
parents:
diff changeset
20
kono
parents:
diff changeset
21 #include "config.h"
kono
parents:
diff changeset
22 #include "system.h"
kono
parents:
diff changeset
23 #include "coretypes.h"
kono
parents:
diff changeset
24 #include "backend.h"
kono
parents:
diff changeset
25 #include "rtl.h"
kono
parents:
diff changeset
26 #include "tree.h"
kono
parents:
diff changeset
27 #include "memmodel.h"
kono
parents:
diff changeset
28 #include "df.h"
kono
parents:
diff changeset
29 #include "tm_p.h"
kono
parents:
diff changeset
30 #include "ira.h"
kono
parents:
diff changeset
31 #include "print-tree.h"
kono
parents:
diff changeset
32 #include "varasm.h"
kono
parents:
diff changeset
33 #include "explow.h"
kono
parents:
diff changeset
34 #include "expr.h"
kono
parents:
diff changeset
35 #include "output.h"
kono
parents:
diff changeset
36 #include "tree-pass.h"
kono
parents:
diff changeset
37
kono
parents:
diff changeset
38 /* Analyze vector computations and remove unnecessary doubleword
kono
parents:
diff changeset
39 swaps (xxswapdi instructions). This pass is performed only
kono
parents:
diff changeset
40 for little-endian VSX code generation.
kono
parents:
diff changeset
41
kono
parents:
diff changeset
42 For this specific case, loads and stores of 4x32 and 2x64 vectors
kono
parents:
diff changeset
43 are inefficient. These are implemented using the lvx2dx and
kono
parents:
diff changeset
44 stvx2dx instructions, which invert the order of doublewords in
kono
parents:
diff changeset
45 a vector register. Thus the code generation inserts an xxswapdi
kono
parents:
diff changeset
46 after each such load, and prior to each such store. (For spill
kono
parents:
diff changeset
47 code after register assignment, an additional xxswapdi is inserted
kono
parents:
diff changeset
48 following each store in order to return a hard register to its
kono
parents:
diff changeset
49 unpermuted value.)
kono
parents:
diff changeset
50
kono
parents:
diff changeset
51 The extra xxswapdi instructions reduce performance. This can be
kono
parents:
diff changeset
52 particularly bad for vectorized code. The purpose of this pass
kono
parents:
diff changeset
53 is to reduce the number of xxswapdi instructions required for
kono
parents:
diff changeset
54 correctness.
kono
parents:
diff changeset
55
kono
parents:
diff changeset
56 The primary insight is that much code that operates on vectors
kono
parents:
diff changeset
57 does not care about the relative order of elements in a register,
kono
parents:
diff changeset
58 so long as the correct memory order is preserved. If we have
kono
parents:
diff changeset
59 a computation where all input values are provided by lvxd2x/xxswapdi
kono
parents:
diff changeset
60 sequences, all outputs are stored using xxswapdi/stvxd2x sequences,
kono
parents:
diff changeset
61 and all intermediate computations are pure SIMD (independent of
kono
parents:
diff changeset
62 element order), then all the xxswapdi's associated with the loads
kono
parents:
diff changeset
63 and stores may be removed.
kono
parents:
diff changeset
64
kono
parents:
diff changeset
65 This pass uses some of the infrastructure and logical ideas from
kono
parents:
diff changeset
66 the "web" pass in web.c. We create maximal webs of computations
kono
parents:
diff changeset
67 fitting the description above using union-find. Each such web is
kono
parents:
diff changeset
68 then optimized by removing its unnecessary xxswapdi instructions.
kono
parents:
diff changeset
69
kono
parents:
diff changeset
70 The pass is placed prior to global optimization so that we can
kono
parents:
diff changeset
71 perform the optimization in the safest and simplest way possible;
kono
parents:
diff changeset
72 that is, by replacing each xxswapdi insn with a register copy insn.
kono
parents:
diff changeset
73 Subsequent forward propagation will remove copies where possible.
kono
parents:
diff changeset
74
kono
parents:
diff changeset
75 There are some operations sensitive to element order for which we
kono
parents:
diff changeset
76 can still allow the operation, provided we modify those operations.
kono
parents:
diff changeset
77 These include CONST_VECTORs, for which we must swap the first and
kono
parents:
diff changeset
78 second halves of the constant vector; and SUBREGs, for which we
kono
parents:
diff changeset
79 must adjust the byte offset to account for the swapped doublewords.
kono
parents:
diff changeset
80 A remaining opportunity would be non-immediate-form splats, for
kono
parents:
diff changeset
81 which we should adjust the selected lane of the input. We should
kono
parents:
diff changeset
82 also make code generation adjustments for sum-across operations,
kono
parents:
diff changeset
83 since this is a common vectorizer reduction.
kono
parents:
diff changeset
84
kono
parents:
diff changeset
85 Because we run prior to the first split, we can see loads and stores
kono
parents:
diff changeset
86 here that match *vsx_le_perm_{load,store}_<mode>. These are vanilla
kono
parents:
diff changeset
87 vector loads and stores that have not yet been split into a permuting
kono
parents:
diff changeset
88 load/store and a swap. (One way this can happen is with a builtin
kono
parents:
diff changeset
89 call to vec_vsx_{ld,st}.) We can handle these as well, but rather
kono
parents:
diff changeset
90 than deleting a swap, we convert the load/store into a permuting
kono
parents:
diff changeset
91 load/store (which effectively removes the swap). */
kono
parents:
diff changeset
92
kono
parents:
diff changeset
93 /* Notes on Permutes
kono
parents:
diff changeset
94
kono
parents:
diff changeset
95 We do not currently handle computations that contain permutes. There
kono
parents:
diff changeset
96 is a general transformation that can be performed correctly, but it
kono
parents:
diff changeset
97 may introduce more expensive code than it replaces. To handle these
kono
parents:
diff changeset
98 would require a cost model to determine when to perform the optimization.
kono
parents:
diff changeset
99 This commentary records how this could be done if desired.
kono
parents:
diff changeset
100
kono
parents:
diff changeset
101 The most general permute is something like this (example for V16QI):
kono
parents:
diff changeset
102
kono
parents:
diff changeset
103 (vec_select:V16QI (vec_concat:V32QI (op1:V16QI) (op2:V16QI))
kono
parents:
diff changeset
104 (parallel [(const_int a0) (const_int a1)
kono
parents:
diff changeset
105 ...
kono
parents:
diff changeset
106 (const_int a14) (const_int a15)]))
kono
parents:
diff changeset
107
kono
parents:
diff changeset
108 where a0,...,a15 are in [0,31] and select elements from op1 and op2
kono
parents:
diff changeset
109 to produce in the result.
kono
parents:
diff changeset
110
kono
parents:
diff changeset
111 Regardless of mode, we can convert the PARALLEL to a mask of 16
kono
parents:
diff changeset
112 byte-element selectors. Let's call this M, with M[i] representing
kono
parents:
diff changeset
113 the ith byte-element selector value. Then if we swap doublewords
kono
parents:
diff changeset
114 throughout the computation, we can get correct behavior by replacing
kono
parents:
diff changeset
115 M with M' as follows:
kono
parents:
diff changeset
116
kono
parents:
diff changeset
117 M'[i] = { (M[i]+8)%16 : M[i] in [0,15]
kono
parents:
diff changeset
118 { ((M[i]+8)%16)+16 : M[i] in [16,31]
kono
parents:
diff changeset
119
kono
parents:
diff changeset
120 This seems promising at first, since we are just replacing one mask
kono
parents:
diff changeset
121 with another. But certain masks are preferable to others. If M
kono
parents:
diff changeset
122 is a mask that matches a vmrghh pattern, for example, M' certainly
kono
parents:
diff changeset
123 will not. Instead of a single vmrghh, we would generate a load of
kono
parents:
diff changeset
124 M' and a vperm. So we would need to know how many xxswapd's we can
kono
parents:
diff changeset
125 remove as a result of this transformation to determine if it's
kono
parents:
diff changeset
126 profitable; and preferably the logic would need to be aware of all
kono
parents:
diff changeset
127 the special preferable masks.
kono
parents:
diff changeset
128
kono
parents:
diff changeset
129 Another form of permute is an UNSPEC_VPERM, in which the mask is
kono
parents:
diff changeset
130 already in a register. In some cases, this mask may be a constant
kono
parents:
diff changeset
131 that we can discover with ud-chains, in which case the above
kono
parents:
diff changeset
132 transformation is ok. However, the common usage here is for the
kono
parents:
diff changeset
133 mask to be produced by an UNSPEC_LVSL, in which case the mask
kono
parents:
diff changeset
134 cannot be known at compile time. In such a case we would have to
kono
parents:
diff changeset
135 generate several instructions to compute M' as above at run time,
kono
parents:
diff changeset
136 and a cost model is needed again.
kono
parents:
diff changeset
137
kono
parents:
diff changeset
138 However, when the mask M for an UNSPEC_VPERM is loaded from the
kono
parents:
diff changeset
139 constant pool, we can replace M with M' as above at no cost
kono
parents:
diff changeset
140 beyond adding a constant pool entry. */
kono
parents:
diff changeset
141
kono
parents:
diff changeset
142 /* This is based on the union-find logic in web.c. web_entry_base is
kono
parents:
diff changeset
143 defined in df.h. */
kono
parents:
diff changeset
144 class swap_web_entry : public web_entry_base
kono
parents:
diff changeset
145 {
kono
parents:
diff changeset
146 public:
kono
parents:
diff changeset
147 /* Pointer to the insn. */
kono
parents:
diff changeset
148 rtx_insn *insn;
kono
parents:
diff changeset
149 /* Set if insn contains a mention of a vector register. All other
kono
parents:
diff changeset
150 fields are undefined if this field is unset. */
kono
parents:
diff changeset
151 unsigned int is_relevant : 1;
kono
parents:
diff changeset
152 /* Set if insn is a load. */
kono
parents:
diff changeset
153 unsigned int is_load : 1;
kono
parents:
diff changeset
154 /* Set if insn is a store. */
kono
parents:
diff changeset
155 unsigned int is_store : 1;
kono
parents:
diff changeset
156 /* Set if insn is a doubleword swap. This can either be a register swap
kono
parents:
diff changeset
157 or a permuting load or store (test is_load and is_store for this). */
kono
parents:
diff changeset
158 unsigned int is_swap : 1;
kono
parents:
diff changeset
159 /* Set if the insn has a live-in use of a parameter register. */
kono
parents:
diff changeset
160 unsigned int is_live_in : 1;
kono
parents:
diff changeset
161 /* Set if the insn has a live-out def of a return register. */
kono
parents:
diff changeset
162 unsigned int is_live_out : 1;
kono
parents:
diff changeset
163 /* Set if the insn contains a subreg reference of a vector register. */
kono
parents:
diff changeset
164 unsigned int contains_subreg : 1;
kono
parents:
diff changeset
165 /* Set if the insn contains a 128-bit integer operand. */
kono
parents:
diff changeset
166 unsigned int is_128_int : 1;
kono
parents:
diff changeset
167 /* Set if this is a call-insn. */
kono
parents:
diff changeset
168 unsigned int is_call : 1;
kono
parents:
diff changeset
169 /* Set if this insn does not perform a vector operation for which
kono
parents:
diff changeset
170 element order matters, or if we know how to fix it up if it does.
kono
parents:
diff changeset
171 Undefined if is_swap is set. */
kono
parents:
diff changeset
172 unsigned int is_swappable : 1;
kono
parents:
diff changeset
173 /* A nonzero value indicates what kind of special handling for this
kono
parents:
diff changeset
174 insn is required if doublewords are swapped. Undefined if
kono
parents:
diff changeset
175 is_swappable is not set. */
kono
parents:
diff changeset
176 unsigned int special_handling : 4;
kono
parents:
diff changeset
177 /* Set if the web represented by this entry cannot be optimized. */
kono
parents:
diff changeset
178 unsigned int web_not_optimizable : 1;
kono
parents:
diff changeset
179 /* Set if this insn should be deleted. */
kono
parents:
diff changeset
180 unsigned int will_delete : 1;
kono
parents:
diff changeset
181 };
kono
parents:
diff changeset
182
kono
parents:
diff changeset
183 enum special_handling_values {
kono
parents:
diff changeset
184 SH_NONE = 0,
kono
parents:
diff changeset
185 SH_CONST_VECTOR,
kono
parents:
diff changeset
186 SH_SUBREG,
kono
parents:
diff changeset
187 SH_NOSWAP_LD,
kono
parents:
diff changeset
188 SH_NOSWAP_ST,
kono
parents:
diff changeset
189 SH_EXTRACT,
kono
parents:
diff changeset
190 SH_SPLAT,
kono
parents:
diff changeset
191 SH_XXPERMDI,
kono
parents:
diff changeset
192 SH_CONCAT,
kono
parents:
diff changeset
193 SH_VPERM
kono
parents:
diff changeset
194 };
kono
parents:
diff changeset
195
kono
parents:
diff changeset
196 /* Union INSN with all insns containing definitions that reach USE.
kono
parents:
diff changeset
197 Detect whether USE is live-in to the current function. */
kono
parents:
diff changeset
198 static void
kono
parents:
diff changeset
199 union_defs (swap_web_entry *insn_entry, rtx insn, df_ref use)
kono
parents:
diff changeset
200 {
kono
parents:
diff changeset
201 struct df_link *link = DF_REF_CHAIN (use);
kono
parents:
diff changeset
202
kono
parents:
diff changeset
203 if (!link)
kono
parents:
diff changeset
204 insn_entry[INSN_UID (insn)].is_live_in = 1;
kono
parents:
diff changeset
205
kono
parents:
diff changeset
206 while (link)
kono
parents:
diff changeset
207 {
kono
parents:
diff changeset
208 if (DF_REF_IS_ARTIFICIAL (link->ref))
kono
parents:
diff changeset
209 insn_entry[INSN_UID (insn)].is_live_in = 1;
kono
parents:
diff changeset
210
kono
parents:
diff changeset
211 if (DF_REF_INSN_INFO (link->ref))
kono
parents:
diff changeset
212 {
kono
parents:
diff changeset
213 rtx def_insn = DF_REF_INSN (link->ref);
kono
parents:
diff changeset
214 (void)unionfind_union (insn_entry + INSN_UID (insn),
kono
parents:
diff changeset
215 insn_entry + INSN_UID (def_insn));
kono
parents:
diff changeset
216 }
kono
parents:
diff changeset
217
kono
parents:
diff changeset
218 link = link->next;
kono
parents:
diff changeset
219 }
kono
parents:
diff changeset
220 }
kono
parents:
diff changeset
221
kono
parents:
diff changeset
222 /* Union INSN with all insns containing uses reached from DEF.
kono
parents:
diff changeset
223 Detect whether DEF is live-out from the current function. */
kono
parents:
diff changeset
224 static void
kono
parents:
diff changeset
225 union_uses (swap_web_entry *insn_entry, rtx insn, df_ref def)
kono
parents:
diff changeset
226 {
kono
parents:
diff changeset
227 struct df_link *link = DF_REF_CHAIN (def);
kono
parents:
diff changeset
228
kono
parents:
diff changeset
229 if (!link)
kono
parents:
diff changeset
230 insn_entry[INSN_UID (insn)].is_live_out = 1;
kono
parents:
diff changeset
231
kono
parents:
diff changeset
232 while (link)
kono
parents:
diff changeset
233 {
kono
parents:
diff changeset
234 /* This could be an eh use or some other artificial use;
kono
parents:
diff changeset
235 we treat these all the same (killing the optimization). */
kono
parents:
diff changeset
236 if (DF_REF_IS_ARTIFICIAL (link->ref))
kono
parents:
diff changeset
237 insn_entry[INSN_UID (insn)].is_live_out = 1;
kono
parents:
diff changeset
238
kono
parents:
diff changeset
239 if (DF_REF_INSN_INFO (link->ref))
kono
parents:
diff changeset
240 {
kono
parents:
diff changeset
241 rtx use_insn = DF_REF_INSN (link->ref);
kono
parents:
diff changeset
242 (void)unionfind_union (insn_entry + INSN_UID (insn),
kono
parents:
diff changeset
243 insn_entry + INSN_UID (use_insn));
kono
parents:
diff changeset
244 }
kono
parents:
diff changeset
245
kono
parents:
diff changeset
246 link = link->next;
kono
parents:
diff changeset
247 }
kono
parents:
diff changeset
248 }
kono
parents:
diff changeset
249
kono
parents:
diff changeset
250 /* Return 1 iff INSN is a load insn, including permuting loads that
kono
parents:
diff changeset
251 represent an lvxd2x instruction; else return 0. */
kono
parents:
diff changeset
252 static unsigned int
kono
parents:
diff changeset
253 insn_is_load_p (rtx insn)
kono
parents:
diff changeset
254 {
kono
parents:
diff changeset
255 rtx body = PATTERN (insn);
kono
parents:
diff changeset
256
kono
parents:
diff changeset
257 if (GET_CODE (body) == SET)
kono
parents:
diff changeset
258 {
kono
parents:
diff changeset
259 if (GET_CODE (SET_SRC (body)) == MEM)
kono
parents:
diff changeset
260 return 1;
kono
parents:
diff changeset
261
kono
parents:
diff changeset
262 if (GET_CODE (SET_SRC (body)) == VEC_SELECT
kono
parents:
diff changeset
263 && GET_CODE (XEXP (SET_SRC (body), 0)) == MEM)
kono
parents:
diff changeset
264 return 1;
kono
parents:
diff changeset
265
kono
parents:
diff changeset
266 return 0;
kono
parents:
diff changeset
267 }
kono
parents:
diff changeset
268
kono
parents:
diff changeset
269 if (GET_CODE (body) != PARALLEL)
kono
parents:
diff changeset
270 return 0;
kono
parents:
diff changeset
271
kono
parents:
diff changeset
272 rtx set = XVECEXP (body, 0, 0);
kono
parents:
diff changeset
273
kono
parents:
diff changeset
274 if (GET_CODE (set) == SET && GET_CODE (SET_SRC (set)) == MEM)
kono
parents:
diff changeset
275 return 1;
kono
parents:
diff changeset
276
kono
parents:
diff changeset
277 return 0;
kono
parents:
diff changeset
278 }
kono
parents:
diff changeset
279
kono
parents:
diff changeset
280 /* Return 1 iff INSN is a store insn, including permuting stores that
kono
parents:
diff changeset
281 represent an stvxd2x instruction; else return 0. */
kono
parents:
diff changeset
282 static unsigned int
kono
parents:
diff changeset
283 insn_is_store_p (rtx insn)
kono
parents:
diff changeset
284 {
kono
parents:
diff changeset
285 rtx body = PATTERN (insn);
kono
parents:
diff changeset
286 if (GET_CODE (body) == SET && GET_CODE (SET_DEST (body)) == MEM)
kono
parents:
diff changeset
287 return 1;
kono
parents:
diff changeset
288 if (GET_CODE (body) != PARALLEL)
kono
parents:
diff changeset
289 return 0;
kono
parents:
diff changeset
290 rtx set = XVECEXP (body, 0, 0);
kono
parents:
diff changeset
291 if (GET_CODE (set) == SET && GET_CODE (SET_DEST (set)) == MEM)
kono
parents:
diff changeset
292 return 1;
kono
parents:
diff changeset
293 return 0;
kono
parents:
diff changeset
294 }
kono
parents:
diff changeset
295
kono
parents:
diff changeset
296 /* Return 1 iff INSN swaps doublewords. This may be a reg-reg swap,
kono
parents:
diff changeset
297 a permuting load, or a permuting store. */
kono
parents:
diff changeset
298 static unsigned int
kono
parents:
diff changeset
299 insn_is_swap_p (rtx insn)
kono
parents:
diff changeset
300 {
kono
parents:
diff changeset
301 rtx body = PATTERN (insn);
kono
parents:
diff changeset
302 if (GET_CODE (body) != SET)
kono
parents:
diff changeset
303 return 0;
kono
parents:
diff changeset
304 rtx rhs = SET_SRC (body);
kono
parents:
diff changeset
305 if (GET_CODE (rhs) != VEC_SELECT)
kono
parents:
diff changeset
306 return 0;
kono
parents:
diff changeset
307 rtx parallel = XEXP (rhs, 1);
kono
parents:
diff changeset
308 if (GET_CODE (parallel) != PARALLEL)
kono
parents:
diff changeset
309 return 0;
kono
parents:
diff changeset
310 unsigned int len = XVECLEN (parallel, 0);
kono
parents:
diff changeset
311 if (len != 2 && len != 4 && len != 8 && len != 16)
kono
parents:
diff changeset
312 return 0;
kono
parents:
diff changeset
313 for (unsigned int i = 0; i < len / 2; ++i)
kono
parents:
diff changeset
314 {
kono
parents:
diff changeset
315 rtx op = XVECEXP (parallel, 0, i);
kono
parents:
diff changeset
316 if (GET_CODE (op) != CONST_INT || INTVAL (op) != len / 2 + i)
kono
parents:
diff changeset
317 return 0;
kono
parents:
diff changeset
318 }
kono
parents:
diff changeset
319 for (unsigned int i = len / 2; i < len; ++i)
kono
parents:
diff changeset
320 {
kono
parents:
diff changeset
321 rtx op = XVECEXP (parallel, 0, i);
kono
parents:
diff changeset
322 if (GET_CODE (op) != CONST_INT || INTVAL (op) != i - len / 2)
kono
parents:
diff changeset
323 return 0;
kono
parents:
diff changeset
324 }
kono
parents:
diff changeset
325 return 1;
kono
parents:
diff changeset
326 }
kono
parents:
diff changeset
327
kono
parents:
diff changeset
328 /* Return TRUE if insn is a swap fed by a load from the constant pool. */
kono
parents:
diff changeset
329 static bool
kono
parents:
diff changeset
330 const_load_sequence_p (swap_web_entry *insn_entry, rtx insn)
kono
parents:
diff changeset
331 {
kono
parents:
diff changeset
332 unsigned uid = INSN_UID (insn);
kono
parents:
diff changeset
333 if (!insn_entry[uid].is_swap || insn_entry[uid].is_load)
kono
parents:
diff changeset
334 return false;
kono
parents:
diff changeset
335
kono
parents:
diff changeset
336 const_rtx tocrel_base;
kono
parents:
diff changeset
337
kono
parents:
diff changeset
338 struct df_insn_info *insn_info = DF_INSN_INFO_GET (insn);
kono
parents:
diff changeset
339 df_ref use;
kono
parents:
diff changeset
340 FOR_EACH_INSN_INFO_USE (use, insn_info)
kono
parents:
diff changeset
341 {
kono
parents:
diff changeset
342 struct df_link *def_link = DF_REF_CHAIN (use);
kono
parents:
diff changeset
343
kono
parents:
diff changeset
344 /* If there is no def or the def is artificial or there are
kono
parents:
diff changeset
345 multiple defs, punt. */
kono
parents:
diff changeset
346 if (!def_link || !def_link->ref || DF_REF_IS_ARTIFICIAL (def_link->ref)
kono
parents:
diff changeset
347 || def_link->next)
kono
parents:
diff changeset
348 return false;
kono
parents:
diff changeset
349
kono
parents:
diff changeset
350 rtx def_insn = DF_REF_INSN (def_link->ref);
kono
parents:
diff changeset
351 unsigned uid2 = INSN_UID (def_insn);
kono
parents:
diff changeset
352 /* If this is not a load or is not a swap, return false. */
kono
parents:
diff changeset
353 if (!insn_entry[uid2].is_load || !insn_entry[uid2].is_swap)
kono
parents:
diff changeset
354 return false;
kono
parents:
diff changeset
355
kono
parents:
diff changeset
356 /* If the source of the rtl def is not a set from memory, return
kono
parents:
diff changeset
357 false. */
kono
parents:
diff changeset
358 rtx body = PATTERN (def_insn);
kono
parents:
diff changeset
359 if (GET_CODE (body) != SET
kono
parents:
diff changeset
360 || GET_CODE (SET_SRC (body)) != VEC_SELECT
kono
parents:
diff changeset
361 || GET_CODE (XEXP (SET_SRC (body), 0)) != MEM)
kono
parents:
diff changeset
362 return false;
kono
parents:
diff changeset
363
kono
parents:
diff changeset
364 rtx mem = XEXP (SET_SRC (body), 0);
kono
parents:
diff changeset
365 rtx base_reg = XEXP (mem, 0);
kono
parents:
diff changeset
366 /* If the base address for the memory expression is not
kono
parents:
diff changeset
367 represented by a register, punt. */
kono
parents:
diff changeset
368 if (!REG_P (base_reg))
kono
parents:
diff changeset
369 return false;
kono
parents:
diff changeset
370
kono
parents:
diff changeset
371 df_ref base_use;
kono
parents:
diff changeset
372 insn_info = DF_INSN_INFO_GET (def_insn);
kono
parents:
diff changeset
373 FOR_EACH_INSN_INFO_USE (base_use, insn_info)
kono
parents:
diff changeset
374 {
kono
parents:
diff changeset
375 /* If base_use does not represent base_reg, look for another
kono
parents:
diff changeset
376 use. */
kono
parents:
diff changeset
377 if (!rtx_equal_p (DF_REF_REG (base_use), base_reg))
kono
parents:
diff changeset
378 continue;
kono
parents:
diff changeset
379
kono
parents:
diff changeset
380 struct df_link *base_def_link = DF_REF_CHAIN (base_use);
kono
parents:
diff changeset
381 if (!base_def_link || base_def_link->next)
kono
parents:
diff changeset
382 return false;
kono
parents:
diff changeset
383
kono
parents:
diff changeset
384 /* Constants held on the stack are not "true" constants
kono
parents:
diff changeset
385 because their values are not part of the static load
kono
parents:
diff changeset
386 image. If this constant's base reference is a stack
kono
parents:
diff changeset
387 or frame pointer, it is seen as an artificial
kono
parents:
diff changeset
388 reference. */
kono
parents:
diff changeset
389 if (DF_REF_IS_ARTIFICIAL (base_def_link->ref))
kono
parents:
diff changeset
390 return false;
kono
parents:
diff changeset
391
kono
parents:
diff changeset
392 rtx tocrel_insn = DF_REF_INSN (base_def_link->ref);
kono
parents:
diff changeset
393 rtx tocrel_body = PATTERN (tocrel_insn);
kono
parents:
diff changeset
394 rtx base, offset;
kono
parents:
diff changeset
395 if (GET_CODE (tocrel_body) != SET)
kono
parents:
diff changeset
396 return false;
kono
parents:
diff changeset
397 /* There is an extra level of indirection for small/large
kono
parents:
diff changeset
398 code models. */
kono
parents:
diff changeset
399 rtx tocrel_expr = SET_SRC (tocrel_body);
kono
parents:
diff changeset
400 if (GET_CODE (tocrel_expr) == MEM)
kono
parents:
diff changeset
401 tocrel_expr = XEXP (tocrel_expr, 0);
kono
parents:
diff changeset
402 if (!toc_relative_expr_p (tocrel_expr, false, &tocrel_base, NULL))
kono
parents:
diff changeset
403 return false;
kono
parents:
diff changeset
404 split_const (XVECEXP (tocrel_base, 0, 0), &base, &offset);
kono
parents:
diff changeset
405
kono
parents:
diff changeset
406 if (GET_CODE (base) != SYMBOL_REF || !CONSTANT_POOL_ADDRESS_P (base))
kono
parents:
diff changeset
407 return false;
kono
parents:
diff changeset
408 else
kono
parents:
diff changeset
409 {
kono
parents:
diff changeset
410 /* FIXME: The conditions under which
kono
parents:
diff changeset
411 ((GET_CODE (const_vector) == SYMBOL_REF) &&
kono
parents:
diff changeset
412 !CONSTANT_POOL_ADDRESS_P (const_vector))
kono
parents:
diff changeset
413 are not well understood. This code prevents
kono
parents:
diff changeset
414 an internal compiler error which will occur in
kono
parents:
diff changeset
415 replace_swapped_load_constant () if we were to return
kono
parents:
diff changeset
416 true. Some day, we should figure out how to properly
kono
parents:
diff changeset
417 handle this condition in
kono
parents:
diff changeset
418 replace_swapped_load_constant () and then we can
kono
parents:
diff changeset
419 remove this special test. */
kono
parents:
diff changeset
420 rtx const_vector = get_pool_constant (base);
kono
parents:
diff changeset
421 if (GET_CODE (const_vector) == SYMBOL_REF
kono
parents:
diff changeset
422 && !CONSTANT_POOL_ADDRESS_P (const_vector))
kono
parents:
diff changeset
423 return false;
kono
parents:
diff changeset
424 }
kono
parents:
diff changeset
425 }
kono
parents:
diff changeset
426 }
kono
parents:
diff changeset
427 return true;
kono
parents:
diff changeset
428 }
kono
parents:
diff changeset
429
kono
parents:
diff changeset
430 /* Return TRUE iff OP matches a V2DF reduction pattern. See the
kono
parents:
diff changeset
431 definition of vsx_reduc_<VEC_reduc_name>_v2df in vsx.md. */
kono
parents:
diff changeset
432 static bool
kono
parents:
diff changeset
433 v2df_reduction_p (rtx op)
kono
parents:
diff changeset
434 {
kono
parents:
diff changeset
435 if (GET_MODE (op) != V2DFmode)
kono
parents:
diff changeset
436 return false;
kono
parents:
diff changeset
437
kono
parents:
diff changeset
438 enum rtx_code code = GET_CODE (op);
kono
parents:
diff changeset
439 if (code != PLUS && code != SMIN && code != SMAX)
kono
parents:
diff changeset
440 return false;
kono
parents:
diff changeset
441
kono
parents:
diff changeset
442 rtx concat = XEXP (op, 0);
kono
parents:
diff changeset
443 if (GET_CODE (concat) != VEC_CONCAT)
kono
parents:
diff changeset
444 return false;
kono
parents:
diff changeset
445
kono
parents:
diff changeset
446 rtx select0 = XEXP (concat, 0);
kono
parents:
diff changeset
447 rtx select1 = XEXP (concat, 1);
kono
parents:
diff changeset
448 if (GET_CODE (select0) != VEC_SELECT || GET_CODE (select1) != VEC_SELECT)
kono
parents:
diff changeset
449 return false;
kono
parents:
diff changeset
450
kono
parents:
diff changeset
451 rtx reg0 = XEXP (select0, 0);
kono
parents:
diff changeset
452 rtx reg1 = XEXP (select1, 0);
kono
parents:
diff changeset
453 if (!rtx_equal_p (reg0, reg1) || !REG_P (reg0))
kono
parents:
diff changeset
454 return false;
kono
parents:
diff changeset
455
kono
parents:
diff changeset
456 rtx parallel0 = XEXP (select0, 1);
kono
parents:
diff changeset
457 rtx parallel1 = XEXP (select1, 1);
kono
parents:
diff changeset
458 if (GET_CODE (parallel0) != PARALLEL || GET_CODE (parallel1) != PARALLEL)
kono
parents:
diff changeset
459 return false;
kono
parents:
diff changeset
460
kono
parents:
diff changeset
461 if (!rtx_equal_p (XVECEXP (parallel0, 0, 0), const1_rtx)
kono
parents:
diff changeset
462 || !rtx_equal_p (XVECEXP (parallel1, 0, 0), const0_rtx))
kono
parents:
diff changeset
463 return false;
kono
parents:
diff changeset
464
kono
parents:
diff changeset
465 return true;
kono
parents:
diff changeset
466 }
kono
parents:
diff changeset
467
kono
parents:
diff changeset
468 /* Return 1 iff OP is an operand that will not be affected by having
kono
parents:
diff changeset
469 vector doublewords swapped in memory. */
kono
parents:
diff changeset
470 static unsigned int
kono
parents:
diff changeset
471 rtx_is_swappable_p (rtx op, unsigned int *special)
kono
parents:
diff changeset
472 {
kono
parents:
diff changeset
473 enum rtx_code code = GET_CODE (op);
kono
parents:
diff changeset
474 int i, j;
kono
parents:
diff changeset
475 rtx parallel;
kono
parents:
diff changeset
476
kono
parents:
diff changeset
477 switch (code)
kono
parents:
diff changeset
478 {
kono
parents:
diff changeset
479 case LABEL_REF:
kono
parents:
diff changeset
480 case SYMBOL_REF:
kono
parents:
diff changeset
481 case CLOBBER:
kono
parents:
diff changeset
482 case REG:
kono
parents:
diff changeset
483 return 1;
kono
parents:
diff changeset
484
kono
parents:
diff changeset
485 case VEC_CONCAT:
kono
parents:
diff changeset
486 case ASM_INPUT:
kono
parents:
diff changeset
487 case ASM_OPERANDS:
kono
parents:
diff changeset
488 return 0;
kono
parents:
diff changeset
489
kono
parents:
diff changeset
490 case CONST_VECTOR:
kono
parents:
diff changeset
491 {
kono
parents:
diff changeset
492 *special = SH_CONST_VECTOR;
kono
parents:
diff changeset
493 return 1;
kono
parents:
diff changeset
494 }
kono
parents:
diff changeset
495
kono
parents:
diff changeset
496 case VEC_DUPLICATE:
kono
parents:
diff changeset
497 /* Opportunity: If XEXP (op, 0) has the same mode as the result,
kono
parents:
diff changeset
498 and XEXP (op, 1) is a PARALLEL with a single QImode const int,
kono
parents:
diff changeset
499 it represents a vector splat for which we can do special
kono
parents:
diff changeset
500 handling. */
kono
parents:
diff changeset
501 if (GET_CODE (XEXP (op, 0)) == CONST_INT)
kono
parents:
diff changeset
502 return 1;
kono
parents:
diff changeset
503 else if (REG_P (XEXP (op, 0))
kono
parents:
diff changeset
504 && GET_MODE_INNER (GET_MODE (op)) == GET_MODE (XEXP (op, 0)))
kono
parents:
diff changeset
505 /* This catches V2DF and V2DI splat, at a minimum. */
kono
parents:
diff changeset
506 return 1;
kono
parents:
diff changeset
507 else if (GET_CODE (XEXP (op, 0)) == TRUNCATE
kono
parents:
diff changeset
508 && REG_P (XEXP (XEXP (op, 0), 0))
kono
parents:
diff changeset
509 && GET_MODE_INNER (GET_MODE (op)) == GET_MODE (XEXP (op, 0)))
kono
parents:
diff changeset
510 /* This catches splat of a truncated value. */
kono
parents:
diff changeset
511 return 1;
kono
parents:
diff changeset
512 else if (GET_CODE (XEXP (op, 0)) == VEC_SELECT)
kono
parents:
diff changeset
513 /* If the duplicated item is from a select, defer to the select
kono
parents:
diff changeset
514 processing to see if we can change the lane for the splat. */
kono
parents:
diff changeset
515 return rtx_is_swappable_p (XEXP (op, 0), special);
kono
parents:
diff changeset
516 else
kono
parents:
diff changeset
517 return 0;
kono
parents:
diff changeset
518
kono
parents:
diff changeset
519 case VEC_SELECT:
kono
parents:
diff changeset
520 /* A vec_extract operation is ok if we change the lane. */
kono
parents:
diff changeset
521 if (GET_CODE (XEXP (op, 0)) == REG
kono
parents:
diff changeset
522 && GET_MODE_INNER (GET_MODE (XEXP (op, 0))) == GET_MODE (op)
kono
parents:
diff changeset
523 && GET_CODE ((parallel = XEXP (op, 1))) == PARALLEL
kono
parents:
diff changeset
524 && XVECLEN (parallel, 0) == 1
kono
parents:
diff changeset
525 && GET_CODE (XVECEXP (parallel, 0, 0)) == CONST_INT)
kono
parents:
diff changeset
526 {
kono
parents:
diff changeset
527 *special = SH_EXTRACT;
kono
parents:
diff changeset
528 return 1;
kono
parents:
diff changeset
529 }
kono
parents:
diff changeset
530 /* An XXPERMDI is ok if we adjust the lanes. Note that if the
kono
parents:
diff changeset
531 XXPERMDI is a swap operation, it will be identified by
kono
parents:
diff changeset
532 insn_is_swap_p and therefore we won't get here. */
kono
parents:
diff changeset
533 else if (GET_CODE (XEXP (op, 0)) == VEC_CONCAT
kono
parents:
diff changeset
534 && (GET_MODE (XEXP (op, 0)) == V4DFmode
kono
parents:
diff changeset
535 || GET_MODE (XEXP (op, 0)) == V4DImode)
kono
parents:
diff changeset
536 && GET_CODE ((parallel = XEXP (op, 1))) == PARALLEL
kono
parents:
diff changeset
537 && XVECLEN (parallel, 0) == 2
kono
parents:
diff changeset
538 && GET_CODE (XVECEXP (parallel, 0, 0)) == CONST_INT
kono
parents:
diff changeset
539 && GET_CODE (XVECEXP (parallel, 0, 1)) == CONST_INT)
kono
parents:
diff changeset
540 {
kono
parents:
diff changeset
541 *special = SH_XXPERMDI;
kono
parents:
diff changeset
542 return 1;
kono
parents:
diff changeset
543 }
kono
parents:
diff changeset
544 else if (v2df_reduction_p (op))
kono
parents:
diff changeset
545 return 1;
kono
parents:
diff changeset
546 else
kono
parents:
diff changeset
547 return 0;
kono
parents:
diff changeset
548
kono
parents:
diff changeset
549 case UNSPEC:
kono
parents:
diff changeset
550 {
kono
parents:
diff changeset
551 /* Various operations are unsafe for this optimization, at least
kono
parents:
diff changeset
552 without significant additional work. Permutes are obviously
kono
parents:
diff changeset
553 problematic, as both the permute control vector and the ordering
kono
parents:
diff changeset
554 of the target values are invalidated by doubleword swapping.
kono
parents:
diff changeset
555 Vector pack and unpack modify the number of vector lanes.
kono
parents:
diff changeset
556 Merge-high/low will not operate correctly on swapped operands.
kono
parents:
diff changeset
557 Vector shifts across element boundaries are clearly uncool,
kono
parents:
diff changeset
558 as are vector select and concatenate operations. Vector
kono
parents:
diff changeset
559 sum-across instructions define one operand with a specific
kono
parents:
diff changeset
560 order-dependent element, so additional fixup code would be
kono
parents:
diff changeset
561 needed to make those work. Vector set and non-immediate-form
kono
parents:
diff changeset
562 vector splat are element-order sensitive. A few of these
kono
parents:
diff changeset
563 cases might be workable with special handling if required.
kono
parents:
diff changeset
564 Adding cost modeling would be appropriate in some cases. */
kono
parents:
diff changeset
565 int val = XINT (op, 1);
kono
parents:
diff changeset
566 switch (val)
kono
parents:
diff changeset
567 {
kono
parents:
diff changeset
568 default:
kono
parents:
diff changeset
569 break;
kono
parents:
diff changeset
570 case UNSPEC_VMRGH_DIRECT:
kono
parents:
diff changeset
571 case UNSPEC_VMRGL_DIRECT:
kono
parents:
diff changeset
572 case UNSPEC_VPACK_SIGN_SIGN_SAT:
kono
parents:
diff changeset
573 case UNSPEC_VPACK_SIGN_UNS_SAT:
kono
parents:
diff changeset
574 case UNSPEC_VPACK_UNS_UNS_MOD:
kono
parents:
diff changeset
575 case UNSPEC_VPACK_UNS_UNS_MOD_DIRECT:
kono
parents:
diff changeset
576 case UNSPEC_VPACK_UNS_UNS_SAT:
kono
parents:
diff changeset
577 case UNSPEC_VPERM:
kono
parents:
diff changeset
578 case UNSPEC_VPERM_UNS:
kono
parents:
diff changeset
579 case UNSPEC_VPERMHI:
kono
parents:
diff changeset
580 case UNSPEC_VPERMSI:
kono
parents:
diff changeset
581 case UNSPEC_VPKPX:
kono
parents:
diff changeset
582 case UNSPEC_VSLDOI:
kono
parents:
diff changeset
583 case UNSPEC_VSLO:
kono
parents:
diff changeset
584 case UNSPEC_VSRO:
kono
parents:
diff changeset
585 case UNSPEC_VSUM2SWS:
kono
parents:
diff changeset
586 case UNSPEC_VSUM4S:
kono
parents:
diff changeset
587 case UNSPEC_VSUM4UBS:
kono
parents:
diff changeset
588 case UNSPEC_VSUMSWS:
kono
parents:
diff changeset
589 case UNSPEC_VSUMSWS_DIRECT:
kono
parents:
diff changeset
590 case UNSPEC_VSX_CONCAT:
kono
parents:
diff changeset
591 case UNSPEC_VSX_SET:
kono
parents:
diff changeset
592 case UNSPEC_VSX_SLDWI:
kono
parents:
diff changeset
593 case UNSPEC_VUNPACK_HI_SIGN:
kono
parents:
diff changeset
594 case UNSPEC_VUNPACK_HI_SIGN_DIRECT:
kono
parents:
diff changeset
595 case UNSPEC_VUNPACK_LO_SIGN:
kono
parents:
diff changeset
596 case UNSPEC_VUNPACK_LO_SIGN_DIRECT:
kono
parents:
diff changeset
597 case UNSPEC_VUPKHPX:
kono
parents:
diff changeset
598 case UNSPEC_VUPKHS_V4SF:
kono
parents:
diff changeset
599 case UNSPEC_VUPKHU_V4SF:
kono
parents:
diff changeset
600 case UNSPEC_VUPKLPX:
kono
parents:
diff changeset
601 case UNSPEC_VUPKLS_V4SF:
kono
parents:
diff changeset
602 case UNSPEC_VUPKLU_V4SF:
kono
parents:
diff changeset
603 case UNSPEC_VSX_CVDPSPN:
kono
parents:
diff changeset
604 case UNSPEC_VSX_CVSPDP:
kono
parents:
diff changeset
605 case UNSPEC_VSX_CVSPDPN:
kono
parents:
diff changeset
606 case UNSPEC_VSX_EXTRACT:
kono
parents:
diff changeset
607 case UNSPEC_VSX_VSLO:
kono
parents:
diff changeset
608 case UNSPEC_VSX_VEC_INIT:
kono
parents:
diff changeset
609 return 0;
kono
parents:
diff changeset
610 case UNSPEC_VSPLT_DIRECT:
kono
parents:
diff changeset
611 case UNSPEC_VSX_XXSPLTD:
kono
parents:
diff changeset
612 *special = SH_SPLAT;
kono
parents:
diff changeset
613 return 1;
kono
parents:
diff changeset
614 case UNSPEC_REDUC_PLUS:
kono
parents:
diff changeset
615 case UNSPEC_REDUC:
kono
parents:
diff changeset
616 return 1;
kono
parents:
diff changeset
617 }
kono
parents:
diff changeset
618 }
kono
parents:
diff changeset
619
kono
parents:
diff changeset
620 default:
kono
parents:
diff changeset
621 break;
kono
parents:
diff changeset
622 }
kono
parents:
diff changeset
623
kono
parents:
diff changeset
624 const char *fmt = GET_RTX_FORMAT (code);
kono
parents:
diff changeset
625 int ok = 1;
kono
parents:
diff changeset
626
kono
parents:
diff changeset
627 for (i = 0; i < GET_RTX_LENGTH (code); ++i)
kono
parents:
diff changeset
628 if (fmt[i] == 'e' || fmt[i] == 'u')
kono
parents:
diff changeset
629 {
kono
parents:
diff changeset
630 unsigned int special_op = SH_NONE;
kono
parents:
diff changeset
631 ok &= rtx_is_swappable_p (XEXP (op, i), &special_op);
kono
parents:
diff changeset
632 if (special_op == SH_NONE)
kono
parents:
diff changeset
633 continue;
kono
parents:
diff changeset
634 /* Ensure we never have two kinds of special handling
kono
parents:
diff changeset
635 for the same insn. */
kono
parents:
diff changeset
636 if (*special != SH_NONE && *special != special_op)
kono
parents:
diff changeset
637 return 0;
kono
parents:
diff changeset
638 *special = special_op;
kono
parents:
diff changeset
639 }
kono
parents:
diff changeset
640 else if (fmt[i] == 'E')
kono
parents:
diff changeset
641 for (j = 0; j < XVECLEN (op, i); ++j)
kono
parents:
diff changeset
642 {
kono
parents:
diff changeset
643 unsigned int special_op = SH_NONE;
kono
parents:
diff changeset
644 ok &= rtx_is_swappable_p (XVECEXP (op, i, j), &special_op);
kono
parents:
diff changeset
645 if (special_op == SH_NONE)
kono
parents:
diff changeset
646 continue;
kono
parents:
diff changeset
647 /* Ensure we never have two kinds of special handling
kono
parents:
diff changeset
648 for the same insn. */
kono
parents:
diff changeset
649 if (*special != SH_NONE && *special != special_op)
kono
parents:
diff changeset
650 return 0;
kono
parents:
diff changeset
651 *special = special_op;
kono
parents:
diff changeset
652 }
kono
parents:
diff changeset
653
kono
parents:
diff changeset
654 return ok;
kono
parents:
diff changeset
655 }
kono
parents:
diff changeset
656
kono
parents:
diff changeset
657 /* Return 1 iff INSN is an operand that will not be affected by
kono
parents:
diff changeset
658 having vector doublewords swapped in memory (in which case
kono
parents:
diff changeset
659 *SPECIAL is unchanged), or that can be modified to be correct
kono
parents:
diff changeset
660 if vector doublewords are swapped in memory (in which case
kono
parents:
diff changeset
661 *SPECIAL is changed to a value indicating how). */
kono
parents:
diff changeset
662 static unsigned int
kono
parents:
diff changeset
663 insn_is_swappable_p (swap_web_entry *insn_entry, rtx insn,
kono
parents:
diff changeset
664 unsigned int *special)
kono
parents:
diff changeset
665 {
kono
parents:
diff changeset
666 /* Calls are always bad. */
kono
parents:
diff changeset
667 if (GET_CODE (insn) == CALL_INSN)
kono
parents:
diff changeset
668 return 0;
kono
parents:
diff changeset
669
kono
parents:
diff changeset
670 /* Loads and stores seen here are not permuting, but we can still
kono
parents:
diff changeset
671 fix them up by converting them to permuting ones. Exceptions:
kono
parents:
diff changeset
672 UNSPEC_LVE, UNSPEC_LVX, and UNSPEC_STVX, which have a PARALLEL
kono
parents:
diff changeset
673 body instead of a SET; and UNSPEC_STVE, which has an UNSPEC
kono
parents:
diff changeset
674 for the SET source. Also we must now make an exception for lvx
kono
parents:
diff changeset
675 and stvx when they are not in the UNSPEC_LVX/STVX form (with the
kono
parents:
diff changeset
676 explicit "& -16") since this leads to unrecognizable insns. */
kono
parents:
diff changeset
677 rtx body = PATTERN (insn);
kono
parents:
diff changeset
678 int i = INSN_UID (insn);
kono
parents:
diff changeset
679
kono
parents:
diff changeset
680 if (insn_entry[i].is_load)
kono
parents:
diff changeset
681 {
kono
parents:
diff changeset
682 if (GET_CODE (body) == SET)
kono
parents:
diff changeset
683 {
kono
parents:
diff changeset
684 rtx rhs = SET_SRC (body);
kono
parents:
diff changeset
685 /* Even without a swap, the RHS might be a vec_select for, say,
kono
parents:
diff changeset
686 a byte-reversing load. */
kono
parents:
diff changeset
687 if (GET_CODE (rhs) != MEM)
kono
parents:
diff changeset
688 return 0;
kono
parents:
diff changeset
689 if (GET_CODE (XEXP (rhs, 0)) == AND)
kono
parents:
diff changeset
690 return 0;
kono
parents:
diff changeset
691
kono
parents:
diff changeset
692 *special = SH_NOSWAP_LD;
kono
parents:
diff changeset
693 return 1;
kono
parents:
diff changeset
694 }
kono
parents:
diff changeset
695 else
kono
parents:
diff changeset
696 return 0;
kono
parents:
diff changeset
697 }
kono
parents:
diff changeset
698
kono
parents:
diff changeset
699 if (insn_entry[i].is_store)
kono
parents:
diff changeset
700 {
kono
parents:
diff changeset
701 if (GET_CODE (body) == SET
kono
parents:
diff changeset
702 && GET_CODE (SET_SRC (body)) != UNSPEC)
kono
parents:
diff changeset
703 {
kono
parents:
diff changeset
704 rtx lhs = SET_DEST (body);
kono
parents:
diff changeset
705 /* Even without a swap, the LHS might be a vec_select for, say,
kono
parents:
diff changeset
706 a byte-reversing store. */
kono
parents:
diff changeset
707 if (GET_CODE (lhs) != MEM)
kono
parents:
diff changeset
708 return 0;
kono
parents:
diff changeset
709 if (GET_CODE (XEXP (lhs, 0)) == AND)
kono
parents:
diff changeset
710 return 0;
kono
parents:
diff changeset
711
kono
parents:
diff changeset
712 *special = SH_NOSWAP_ST;
kono
parents:
diff changeset
713 return 1;
kono
parents:
diff changeset
714 }
kono
parents:
diff changeset
715 else
kono
parents:
diff changeset
716 return 0;
kono
parents:
diff changeset
717 }
kono
parents:
diff changeset
718
kono
parents:
diff changeset
719 /* A convert to single precision can be left as is provided that
kono
parents:
diff changeset
720 all of its uses are in xxspltw instructions that splat BE element
kono
parents:
diff changeset
721 zero. */
kono
parents:
diff changeset
722 if (GET_CODE (body) == SET
kono
parents:
diff changeset
723 && GET_CODE (SET_SRC (body)) == UNSPEC
kono
parents:
diff changeset
724 && XINT (SET_SRC (body), 1) == UNSPEC_VSX_CVDPSPN)
kono
parents:
diff changeset
725 {
kono
parents:
diff changeset
726 df_ref def;
kono
parents:
diff changeset
727 struct df_insn_info *insn_info = DF_INSN_INFO_GET (insn);
kono
parents:
diff changeset
728
kono
parents:
diff changeset
729 FOR_EACH_INSN_INFO_DEF (def, insn_info)
kono
parents:
diff changeset
730 {
kono
parents:
diff changeset
731 struct df_link *link = DF_REF_CHAIN (def);
kono
parents:
diff changeset
732 if (!link)
kono
parents:
diff changeset
733 return 0;
kono
parents:
diff changeset
734
kono
parents:
diff changeset
735 for (; link; link = link->next) {
kono
parents:
diff changeset
736 rtx use_insn = DF_REF_INSN (link->ref);
kono
parents:
diff changeset
737 rtx use_body = PATTERN (use_insn);
kono
parents:
diff changeset
738 if (GET_CODE (use_body) != SET
kono
parents:
diff changeset
739 || GET_CODE (SET_SRC (use_body)) != UNSPEC
kono
parents:
diff changeset
740 || XINT (SET_SRC (use_body), 1) != UNSPEC_VSX_XXSPLTW
kono
parents:
diff changeset
741 || XVECEXP (SET_SRC (use_body), 0, 1) != const0_rtx)
kono
parents:
diff changeset
742 return 0;
kono
parents:
diff changeset
743 }
kono
parents:
diff changeset
744 }
kono
parents:
diff changeset
745
kono
parents:
diff changeset
746 return 1;
kono
parents:
diff changeset
747 }
kono
parents:
diff changeset
748
kono
parents:
diff changeset
749 /* A concatenation of two doublewords is ok if we reverse the
kono
parents:
diff changeset
750 order of the inputs. */
kono
parents:
diff changeset
751 if (GET_CODE (body) == SET
kono
parents:
diff changeset
752 && GET_CODE (SET_SRC (body)) == VEC_CONCAT
kono
parents:
diff changeset
753 && (GET_MODE (SET_SRC (body)) == V2DFmode
kono
parents:
diff changeset
754 || GET_MODE (SET_SRC (body)) == V2DImode))
kono
parents:
diff changeset
755 {
kono
parents:
diff changeset
756 *special = SH_CONCAT;
kono
parents:
diff changeset
757 return 1;
kono
parents:
diff changeset
758 }
kono
parents:
diff changeset
759
kono
parents:
diff changeset
760 /* V2DF reductions are always swappable. */
kono
parents:
diff changeset
761 if (GET_CODE (body) == PARALLEL)
kono
parents:
diff changeset
762 {
kono
parents:
diff changeset
763 rtx expr = XVECEXP (body, 0, 0);
kono
parents:
diff changeset
764 if (GET_CODE (expr) == SET
kono
parents:
diff changeset
765 && v2df_reduction_p (SET_SRC (expr)))
kono
parents:
diff changeset
766 return 1;
kono
parents:
diff changeset
767 }
kono
parents:
diff changeset
768
kono
parents:
diff changeset
769 /* An UNSPEC_VPERM is ok if the mask operand is loaded from the
kono
parents:
diff changeset
770 constant pool. */
kono
parents:
diff changeset
771 if (GET_CODE (body) == SET
kono
parents:
diff changeset
772 && GET_CODE (SET_SRC (body)) == UNSPEC
kono
parents:
diff changeset
773 && XINT (SET_SRC (body), 1) == UNSPEC_VPERM
kono
parents:
diff changeset
774 && XVECLEN (SET_SRC (body), 0) == 3
kono
parents:
diff changeset
775 && GET_CODE (XVECEXP (SET_SRC (body), 0, 2)) == REG)
kono
parents:
diff changeset
776 {
kono
parents:
diff changeset
777 rtx mask_reg = XVECEXP (SET_SRC (body), 0, 2);
kono
parents:
diff changeset
778 struct df_insn_info *insn_info = DF_INSN_INFO_GET (insn);
kono
parents:
diff changeset
779 df_ref use;
kono
parents:
diff changeset
780 FOR_EACH_INSN_INFO_USE (use, insn_info)
kono
parents:
diff changeset
781 if (rtx_equal_p (DF_REF_REG (use), mask_reg))
kono
parents:
diff changeset
782 {
kono
parents:
diff changeset
783 struct df_link *def_link = DF_REF_CHAIN (use);
kono
parents:
diff changeset
784 /* Punt if multiple definitions for this reg. */
kono
parents:
diff changeset
785 if (def_link && !def_link->next &&
kono
parents:
diff changeset
786 const_load_sequence_p (insn_entry,
kono
parents:
diff changeset
787 DF_REF_INSN (def_link->ref)))
kono
parents:
diff changeset
788 {
kono
parents:
diff changeset
789 *special = SH_VPERM;
kono
parents:
diff changeset
790 return 1;
kono
parents:
diff changeset
791 }
kono
parents:
diff changeset
792 }
kono
parents:
diff changeset
793 }
kono
parents:
diff changeset
794
kono
parents:
diff changeset
795 /* Otherwise check the operands for vector lane violations. */
kono
parents:
diff changeset
796 return rtx_is_swappable_p (body, special);
kono
parents:
diff changeset
797 }
kono
parents:
diff changeset
798
kono
parents:
diff changeset
799 enum chain_purpose { FOR_LOADS, FOR_STORES };
kono
parents:
diff changeset
800
kono
parents:
diff changeset
801 /* Return true if the UD or DU chain headed by LINK is non-empty,
kono
parents:
diff changeset
802 and every entry on the chain references an insn that is a
kono
parents:
diff changeset
803 register swap. Furthermore, if PURPOSE is FOR_LOADS, each such
kono
parents:
diff changeset
804 register swap must have only permuting loads as reaching defs.
kono
parents:
diff changeset
805 If PURPOSE is FOR_STORES, each such register swap must have only
kono
parents:
diff changeset
806 register swaps or permuting stores as reached uses. */
kono
parents:
diff changeset
807 static bool
kono
parents:
diff changeset
808 chain_contains_only_swaps (swap_web_entry *insn_entry, struct df_link *link,
kono
parents:
diff changeset
809 enum chain_purpose purpose)
kono
parents:
diff changeset
810 {
kono
parents:
diff changeset
811 if (!link)
kono
parents:
diff changeset
812 return false;
kono
parents:
diff changeset
813
kono
parents:
diff changeset
814 for (; link; link = link->next)
kono
parents:
diff changeset
815 {
kono
parents:
diff changeset
816 if (!ALTIVEC_OR_VSX_VECTOR_MODE (GET_MODE (DF_REF_REG (link->ref))))
kono
parents:
diff changeset
817 continue;
kono
parents:
diff changeset
818
kono
parents:
diff changeset
819 if (DF_REF_IS_ARTIFICIAL (link->ref))
kono
parents:
diff changeset
820 return false;
kono
parents:
diff changeset
821
kono
parents:
diff changeset
822 rtx reached_insn = DF_REF_INSN (link->ref);
kono
parents:
diff changeset
823 unsigned uid = INSN_UID (reached_insn);
kono
parents:
diff changeset
824 struct df_insn_info *insn_info = DF_INSN_INFO_GET (reached_insn);
kono
parents:
diff changeset
825
kono
parents:
diff changeset
826 if (!insn_entry[uid].is_swap || insn_entry[uid].is_load
kono
parents:
diff changeset
827 || insn_entry[uid].is_store)
kono
parents:
diff changeset
828 return false;
kono
parents:
diff changeset
829
kono
parents:
diff changeset
830 if (purpose == FOR_LOADS)
kono
parents:
diff changeset
831 {
kono
parents:
diff changeset
832 df_ref use;
kono
parents:
diff changeset
833 FOR_EACH_INSN_INFO_USE (use, insn_info)
kono
parents:
diff changeset
834 {
kono
parents:
diff changeset
835 struct df_link *swap_link = DF_REF_CHAIN (use);
kono
parents:
diff changeset
836
kono
parents:
diff changeset
837 while (swap_link)
kono
parents:
diff changeset
838 {
kono
parents:
diff changeset
839 if (DF_REF_IS_ARTIFICIAL (link->ref))
kono
parents:
diff changeset
840 return false;
kono
parents:
diff changeset
841
kono
parents:
diff changeset
842 rtx swap_def_insn = DF_REF_INSN (swap_link->ref);
kono
parents:
diff changeset
843 unsigned uid2 = INSN_UID (swap_def_insn);
kono
parents:
diff changeset
844
kono
parents:
diff changeset
845 /* Only permuting loads are allowed. */
kono
parents:
diff changeset
846 if (!insn_entry[uid2].is_swap || !insn_entry[uid2].is_load)
kono
parents:
diff changeset
847 return false;
kono
parents:
diff changeset
848
kono
parents:
diff changeset
849 swap_link = swap_link->next;
kono
parents:
diff changeset
850 }
kono
parents:
diff changeset
851 }
kono
parents:
diff changeset
852 }
kono
parents:
diff changeset
853 else if (purpose == FOR_STORES)
kono
parents:
diff changeset
854 {
kono
parents:
diff changeset
855 df_ref def;
kono
parents:
diff changeset
856 FOR_EACH_INSN_INFO_DEF (def, insn_info)
kono
parents:
diff changeset
857 {
kono
parents:
diff changeset
858 struct df_link *swap_link = DF_REF_CHAIN (def);
kono
parents:
diff changeset
859
kono
parents:
diff changeset
860 while (swap_link)
kono
parents:
diff changeset
861 {
kono
parents:
diff changeset
862 if (DF_REF_IS_ARTIFICIAL (link->ref))
kono
parents:
diff changeset
863 return false;
kono
parents:
diff changeset
864
kono
parents:
diff changeset
865 rtx swap_use_insn = DF_REF_INSN (swap_link->ref);
kono
parents:
diff changeset
866 unsigned uid2 = INSN_UID (swap_use_insn);
kono
parents:
diff changeset
867
kono
parents:
diff changeset
868 /* Permuting stores or register swaps are allowed. */
kono
parents:
diff changeset
869 if (!insn_entry[uid2].is_swap || insn_entry[uid2].is_load)
kono
parents:
diff changeset
870 return false;
kono
parents:
diff changeset
871
kono
parents:
diff changeset
872 swap_link = swap_link->next;
kono
parents:
diff changeset
873 }
kono
parents:
diff changeset
874 }
kono
parents:
diff changeset
875 }
kono
parents:
diff changeset
876 }
kono
parents:
diff changeset
877
kono
parents:
diff changeset
878 return true;
kono
parents:
diff changeset
879 }
kono
parents:
diff changeset
880
kono
parents:
diff changeset
881 /* Mark the xxswapdi instructions associated with permuting loads and
kono
parents:
diff changeset
882 stores for removal. Note that we only flag them for deletion here,
kono
parents:
diff changeset
883 as there is a possibility of a swap being reached from multiple
kono
parents:
diff changeset
884 loads, etc. */
kono
parents:
diff changeset
885 static void
kono
parents:
diff changeset
886 mark_swaps_for_removal (swap_web_entry *insn_entry, unsigned int i)
kono
parents:
diff changeset
887 {
kono
parents:
diff changeset
888 rtx insn = insn_entry[i].insn;
kono
parents:
diff changeset
889 struct df_insn_info *insn_info = DF_INSN_INFO_GET (insn);
kono
parents:
diff changeset
890
kono
parents:
diff changeset
891 if (insn_entry[i].is_load)
kono
parents:
diff changeset
892 {
kono
parents:
diff changeset
893 df_ref def;
kono
parents:
diff changeset
894 FOR_EACH_INSN_INFO_DEF (def, insn_info)
kono
parents:
diff changeset
895 {
kono
parents:
diff changeset
896 struct df_link *link = DF_REF_CHAIN (def);
kono
parents:
diff changeset
897
kono
parents:
diff changeset
898 /* We know by now that these are swaps, so we can delete
kono
parents:
diff changeset
899 them confidently. */
kono
parents:
diff changeset
900 while (link)
kono
parents:
diff changeset
901 {
kono
parents:
diff changeset
902 rtx use_insn = DF_REF_INSN (link->ref);
kono
parents:
diff changeset
903 insn_entry[INSN_UID (use_insn)].will_delete = 1;
kono
parents:
diff changeset
904 link = link->next;
kono
parents:
diff changeset
905 }
kono
parents:
diff changeset
906 }
kono
parents:
diff changeset
907 }
kono
parents:
diff changeset
908 else if (insn_entry[i].is_store)
kono
parents:
diff changeset
909 {
kono
parents:
diff changeset
910 df_ref use;
kono
parents:
diff changeset
911 FOR_EACH_INSN_INFO_USE (use, insn_info)
kono
parents:
diff changeset
912 {
kono
parents:
diff changeset
913 /* Ignore uses for addressability. */
kono
parents:
diff changeset
914 machine_mode mode = GET_MODE (DF_REF_REG (use));
kono
parents:
diff changeset
915 if (!ALTIVEC_OR_VSX_VECTOR_MODE (mode))
kono
parents:
diff changeset
916 continue;
kono
parents:
diff changeset
917
kono
parents:
diff changeset
918 struct df_link *link = DF_REF_CHAIN (use);
kono
parents:
diff changeset
919
kono
parents:
diff changeset
920 /* We know by now that these are swaps, so we can delete
kono
parents:
diff changeset
921 them confidently. */
kono
parents:
diff changeset
922 while (link)
kono
parents:
diff changeset
923 {
kono
parents:
diff changeset
924 rtx def_insn = DF_REF_INSN (link->ref);
kono
parents:
diff changeset
925 insn_entry[INSN_UID (def_insn)].will_delete = 1;
kono
parents:
diff changeset
926 link = link->next;
kono
parents:
diff changeset
927 }
kono
parents:
diff changeset
928 }
kono
parents:
diff changeset
929 }
kono
parents:
diff changeset
930 }
kono
parents:
diff changeset
931
kono
parents:
diff changeset
932 /* OP is either a CONST_VECTOR or an expression containing one.
kono
parents:
diff changeset
933 Swap the first half of the vector with the second in the first
kono
parents:
diff changeset
934 case. Recurse to find it in the second. */
kono
parents:
diff changeset
935 static void
kono
parents:
diff changeset
936 swap_const_vector_halves (rtx op)
kono
parents:
diff changeset
937 {
kono
parents:
diff changeset
938 int i;
kono
parents:
diff changeset
939 enum rtx_code code = GET_CODE (op);
kono
parents:
diff changeset
940 if (GET_CODE (op) == CONST_VECTOR)
kono
parents:
diff changeset
941 {
kono
parents:
diff changeset
942 int half_units = GET_MODE_NUNITS (GET_MODE (op)) / 2;
kono
parents:
diff changeset
943 for (i = 0; i < half_units; ++i)
kono
parents:
diff changeset
944 {
kono
parents:
diff changeset
945 rtx temp = CONST_VECTOR_ELT (op, i);
kono
parents:
diff changeset
946 CONST_VECTOR_ELT (op, i) = CONST_VECTOR_ELT (op, i + half_units);
kono
parents:
diff changeset
947 CONST_VECTOR_ELT (op, i + half_units) = temp;
kono
parents:
diff changeset
948 }
kono
parents:
diff changeset
949 }
kono
parents:
diff changeset
950 else
kono
parents:
diff changeset
951 {
kono
parents:
diff changeset
952 int j;
kono
parents:
diff changeset
953 const char *fmt = GET_RTX_FORMAT (code);
kono
parents:
diff changeset
954 for (i = 0; i < GET_RTX_LENGTH (code); ++i)
kono
parents:
diff changeset
955 if (fmt[i] == 'e' || fmt[i] == 'u')
kono
parents:
diff changeset
956 swap_const_vector_halves (XEXP (op, i));
kono
parents:
diff changeset
957 else if (fmt[i] == 'E')
kono
parents:
diff changeset
958 for (j = 0; j < XVECLEN (op, i); ++j)
kono
parents:
diff changeset
959 swap_const_vector_halves (XVECEXP (op, i, j));
kono
parents:
diff changeset
960 }
kono
parents:
diff changeset
961 }
kono
parents:
diff changeset
962
kono
parents:
diff changeset
963 /* Find all subregs of a vector expression that perform a narrowing,
kono
parents:
diff changeset
964 and adjust the subreg index to account for doubleword swapping. */
kono
parents:
diff changeset
965 static void
kono
parents:
diff changeset
966 adjust_subreg_index (rtx op)
kono
parents:
diff changeset
967 {
kono
parents:
diff changeset
968 enum rtx_code code = GET_CODE (op);
kono
parents:
diff changeset
969 if (code == SUBREG
kono
parents:
diff changeset
970 && (GET_MODE_SIZE (GET_MODE (op))
kono
parents:
diff changeset
971 < GET_MODE_SIZE (GET_MODE (XEXP (op, 0)))))
kono
parents:
diff changeset
972 {
kono
parents:
diff changeset
973 unsigned int index = SUBREG_BYTE (op);
kono
parents:
diff changeset
974 if (index < 8)
kono
parents:
diff changeset
975 index += 8;
kono
parents:
diff changeset
976 else
kono
parents:
diff changeset
977 index -= 8;
kono
parents:
diff changeset
978 SUBREG_BYTE (op) = index;
kono
parents:
diff changeset
979 }
kono
parents:
diff changeset
980
kono
parents:
diff changeset
981 const char *fmt = GET_RTX_FORMAT (code);
kono
parents:
diff changeset
982 int i,j;
kono
parents:
diff changeset
983 for (i = 0; i < GET_RTX_LENGTH (code); ++i)
kono
parents:
diff changeset
984 if (fmt[i] == 'e' || fmt[i] == 'u')
kono
parents:
diff changeset
985 adjust_subreg_index (XEXP (op, i));
kono
parents:
diff changeset
986 else if (fmt[i] == 'E')
kono
parents:
diff changeset
987 for (j = 0; j < XVECLEN (op, i); ++j)
kono
parents:
diff changeset
988 adjust_subreg_index (XVECEXP (op, i, j));
kono
parents:
diff changeset
989 }
kono
parents:
diff changeset
990
kono
parents:
diff changeset
991 /* Convert the non-permuting load INSN to a permuting one. */
kono
parents:
diff changeset
992 static void
kono
parents:
diff changeset
993 permute_load (rtx_insn *insn)
kono
parents:
diff changeset
994 {
kono
parents:
diff changeset
995 rtx body = PATTERN (insn);
kono
parents:
diff changeset
996 rtx mem_op = SET_SRC (body);
kono
parents:
diff changeset
997 rtx tgt_reg = SET_DEST (body);
kono
parents:
diff changeset
998 machine_mode mode = GET_MODE (tgt_reg);
kono
parents:
diff changeset
999 int n_elts = GET_MODE_NUNITS (mode);
kono
parents:
diff changeset
1000 int half_elts = n_elts / 2;
kono
parents:
diff changeset
1001 rtx par = gen_rtx_PARALLEL (mode, rtvec_alloc (n_elts));
kono
parents:
diff changeset
1002 int i, j;
kono
parents:
diff changeset
1003 for (i = 0, j = half_elts; i < half_elts; ++i, ++j)
kono
parents:
diff changeset
1004 XVECEXP (par, 0, i) = GEN_INT (j);
kono
parents:
diff changeset
1005 for (i = half_elts, j = 0; j < half_elts; ++i, ++j)
kono
parents:
diff changeset
1006 XVECEXP (par, 0, i) = GEN_INT (j);
kono
parents:
diff changeset
1007 rtx sel = gen_rtx_VEC_SELECT (mode, mem_op, par);
kono
parents:
diff changeset
1008 SET_SRC (body) = sel;
kono
parents:
diff changeset
1009 INSN_CODE (insn) = -1; /* Force re-recognition. */
kono
parents:
diff changeset
1010 df_insn_rescan (insn);
kono
parents:
diff changeset
1011
kono
parents:
diff changeset
1012 if (dump_file)
kono
parents:
diff changeset
1013 fprintf (dump_file, "Replacing load %d with permuted load\n",
kono
parents:
diff changeset
1014 INSN_UID (insn));
kono
parents:
diff changeset
1015 }
kono
parents:
diff changeset
1016
kono
parents:
diff changeset
1017 /* Convert the non-permuting store INSN to a permuting one. */
kono
parents:
diff changeset
1018 static void
kono
parents:
diff changeset
1019 permute_store (rtx_insn *insn)
kono
parents:
diff changeset
1020 {
kono
parents:
diff changeset
1021 rtx body = PATTERN (insn);
kono
parents:
diff changeset
1022 rtx src_reg = SET_SRC (body);
kono
parents:
diff changeset
1023 machine_mode mode = GET_MODE (src_reg);
kono
parents:
diff changeset
1024 int n_elts = GET_MODE_NUNITS (mode);
kono
parents:
diff changeset
1025 int half_elts = n_elts / 2;
kono
parents:
diff changeset
1026 rtx par = gen_rtx_PARALLEL (mode, rtvec_alloc (n_elts));
kono
parents:
diff changeset
1027 int i, j;
kono
parents:
diff changeset
1028 for (i = 0, j = half_elts; i < half_elts; ++i, ++j)
kono
parents:
diff changeset
1029 XVECEXP (par, 0, i) = GEN_INT (j);
kono
parents:
diff changeset
1030 for (i = half_elts, j = 0; j < half_elts; ++i, ++j)
kono
parents:
diff changeset
1031 XVECEXP (par, 0, i) = GEN_INT (j);
kono
parents:
diff changeset
1032 rtx sel = gen_rtx_VEC_SELECT (mode, src_reg, par);
kono
parents:
diff changeset
1033 SET_SRC (body) = sel;
kono
parents:
diff changeset
1034 INSN_CODE (insn) = -1; /* Force re-recognition. */
kono
parents:
diff changeset
1035 df_insn_rescan (insn);
kono
parents:
diff changeset
1036
kono
parents:
diff changeset
1037 if (dump_file)
kono
parents:
diff changeset
1038 fprintf (dump_file, "Replacing store %d with permuted store\n",
kono
parents:
diff changeset
1039 INSN_UID (insn));
kono
parents:
diff changeset
1040 }
kono
parents:
diff changeset
1041
kono
parents:
diff changeset
1042 /* Given OP that contains a vector extract operation, adjust the index
kono
parents:
diff changeset
1043 of the extracted lane to account for the doubleword swap. */
kono
parents:
diff changeset
1044 static void
kono
parents:
diff changeset
1045 adjust_extract (rtx_insn *insn)
kono
parents:
diff changeset
1046 {
kono
parents:
diff changeset
1047 rtx pattern = PATTERN (insn);
kono
parents:
diff changeset
1048 if (GET_CODE (pattern) == PARALLEL)
kono
parents:
diff changeset
1049 pattern = XVECEXP (pattern, 0, 0);
kono
parents:
diff changeset
1050 rtx src = SET_SRC (pattern);
kono
parents:
diff changeset
1051 /* The vec_select may be wrapped in a vec_duplicate for a splat, so
kono
parents:
diff changeset
1052 account for that. */
kono
parents:
diff changeset
1053 rtx sel = GET_CODE (src) == VEC_DUPLICATE ? XEXP (src, 0) : src;
kono
parents:
diff changeset
1054 rtx par = XEXP (sel, 1);
kono
parents:
diff changeset
1055 int half_elts = GET_MODE_NUNITS (GET_MODE (XEXP (sel, 0))) >> 1;
kono
parents:
diff changeset
1056 int lane = INTVAL (XVECEXP (par, 0, 0));
kono
parents:
diff changeset
1057 lane = lane >= half_elts ? lane - half_elts : lane + half_elts;
kono
parents:
diff changeset
1058 XVECEXP (par, 0, 0) = GEN_INT (lane);
kono
parents:
diff changeset
1059 INSN_CODE (insn) = -1; /* Force re-recognition. */
kono
parents:
diff changeset
1060 df_insn_rescan (insn);
kono
parents:
diff changeset
1061
kono
parents:
diff changeset
1062 if (dump_file)
kono
parents:
diff changeset
1063 fprintf (dump_file, "Changing lane for extract %d\n", INSN_UID (insn));
kono
parents:
diff changeset
1064 }
kono
parents:
diff changeset
1065
kono
parents:
diff changeset
1066 /* Given OP that contains a vector direct-splat operation, adjust the index
kono
parents:
diff changeset
1067 of the source lane to account for the doubleword swap. */
kono
parents:
diff changeset
1068 static void
kono
parents:
diff changeset
1069 adjust_splat (rtx_insn *insn)
kono
parents:
diff changeset
1070 {
kono
parents:
diff changeset
1071 rtx body = PATTERN (insn);
kono
parents:
diff changeset
1072 rtx unspec = XEXP (body, 1);
kono
parents:
diff changeset
1073 int half_elts = GET_MODE_NUNITS (GET_MODE (unspec)) >> 1;
kono
parents:
diff changeset
1074 int lane = INTVAL (XVECEXP (unspec, 0, 1));
kono
parents:
diff changeset
1075 lane = lane >= half_elts ? lane - half_elts : lane + half_elts;
kono
parents:
diff changeset
1076 XVECEXP (unspec, 0, 1) = GEN_INT (lane);
kono
parents:
diff changeset
1077 INSN_CODE (insn) = -1; /* Force re-recognition. */
kono
parents:
diff changeset
1078 df_insn_rescan (insn);
kono
parents:
diff changeset
1079
kono
parents:
diff changeset
1080 if (dump_file)
kono
parents:
diff changeset
1081 fprintf (dump_file, "Changing lane for splat %d\n", INSN_UID (insn));
kono
parents:
diff changeset
1082 }
kono
parents:
diff changeset
1083
kono
parents:
diff changeset
1084 /* Given OP that contains an XXPERMDI operation (that is not a doubleword
kono
parents:
diff changeset
1085 swap), reverse the order of the source operands and adjust the indices
kono
parents:
diff changeset
1086 of the source lanes to account for doubleword reversal. */
kono
parents:
diff changeset
1087 static void
kono
parents:
diff changeset
1088 adjust_xxpermdi (rtx_insn *insn)
kono
parents:
diff changeset
1089 {
kono
parents:
diff changeset
1090 rtx set = PATTERN (insn);
kono
parents:
diff changeset
1091 rtx select = XEXP (set, 1);
kono
parents:
diff changeset
1092 rtx concat = XEXP (select, 0);
kono
parents:
diff changeset
1093 rtx src0 = XEXP (concat, 0);
kono
parents:
diff changeset
1094 XEXP (concat, 0) = XEXP (concat, 1);
kono
parents:
diff changeset
1095 XEXP (concat, 1) = src0;
kono
parents:
diff changeset
1096 rtx parallel = XEXP (select, 1);
kono
parents:
diff changeset
1097 int lane0 = INTVAL (XVECEXP (parallel, 0, 0));
kono
parents:
diff changeset
1098 int lane1 = INTVAL (XVECEXP (parallel, 0, 1));
kono
parents:
diff changeset
1099 int new_lane0 = 3 - lane1;
kono
parents:
diff changeset
1100 int new_lane1 = 3 - lane0;
kono
parents:
diff changeset
1101 XVECEXP (parallel, 0, 0) = GEN_INT (new_lane0);
kono
parents:
diff changeset
1102 XVECEXP (parallel, 0, 1) = GEN_INT (new_lane1);
kono
parents:
diff changeset
1103 INSN_CODE (insn) = -1; /* Force re-recognition. */
kono
parents:
diff changeset
1104 df_insn_rescan (insn);
kono
parents:
diff changeset
1105
kono
parents:
diff changeset
1106 if (dump_file)
kono
parents:
diff changeset
1107 fprintf (dump_file, "Changing lanes for xxpermdi %d\n", INSN_UID (insn));
kono
parents:
diff changeset
1108 }
kono
parents:
diff changeset
1109
kono
parents:
diff changeset
1110 /* Given OP that contains a VEC_CONCAT operation of two doublewords,
kono
parents:
diff changeset
1111 reverse the order of those inputs. */
kono
parents:
diff changeset
1112 static void
kono
parents:
diff changeset
1113 adjust_concat (rtx_insn *insn)
kono
parents:
diff changeset
1114 {
kono
parents:
diff changeset
1115 rtx set = PATTERN (insn);
kono
parents:
diff changeset
1116 rtx concat = XEXP (set, 1);
kono
parents:
diff changeset
1117 rtx src0 = XEXP (concat, 0);
kono
parents:
diff changeset
1118 XEXP (concat, 0) = XEXP (concat, 1);
kono
parents:
diff changeset
1119 XEXP (concat, 1) = src0;
kono
parents:
diff changeset
1120 INSN_CODE (insn) = -1; /* Force re-recognition. */
kono
parents:
diff changeset
1121 df_insn_rescan (insn);
kono
parents:
diff changeset
1122
kono
parents:
diff changeset
1123 if (dump_file)
kono
parents:
diff changeset
1124 fprintf (dump_file, "Reversing inputs for concat %d\n", INSN_UID (insn));
kono
parents:
diff changeset
1125 }
kono
parents:
diff changeset
1126
kono
parents:
diff changeset
1127 /* Given an UNSPEC_VPERM insn, modify the mask loaded from the
kono
parents:
diff changeset
1128 constant pool to reflect swapped doublewords. */
kono
parents:
diff changeset
1129 static void
kono
parents:
diff changeset
1130 adjust_vperm (rtx_insn *insn)
kono
parents:
diff changeset
1131 {
kono
parents:
diff changeset
1132 /* We previously determined that the UNSPEC_VPERM was fed by a
kono
parents:
diff changeset
1133 swap of a swapping load of a TOC-relative constant pool symbol.
kono
parents:
diff changeset
1134 Find the MEM in the swapping load and replace it with a MEM for
kono
parents:
diff changeset
1135 the adjusted mask constant. */
kono
parents:
diff changeset
1136 rtx set = PATTERN (insn);
kono
parents:
diff changeset
1137 rtx mask_reg = XVECEXP (SET_SRC (set), 0, 2);
kono
parents:
diff changeset
1138
kono
parents:
diff changeset
1139 /* Find the swap. */
kono
parents:
diff changeset
1140 struct df_insn_info *insn_info = DF_INSN_INFO_GET (insn);
kono
parents:
diff changeset
1141 df_ref use;
kono
parents:
diff changeset
1142 rtx_insn *swap_insn = 0;
kono
parents:
diff changeset
1143 FOR_EACH_INSN_INFO_USE (use, insn_info)
kono
parents:
diff changeset
1144 if (rtx_equal_p (DF_REF_REG (use), mask_reg))
kono
parents:
diff changeset
1145 {
kono
parents:
diff changeset
1146 struct df_link *def_link = DF_REF_CHAIN (use);
kono
parents:
diff changeset
1147 gcc_assert (def_link && !def_link->next);
kono
parents:
diff changeset
1148 swap_insn = DF_REF_INSN (def_link->ref);
kono
parents:
diff changeset
1149 break;
kono
parents:
diff changeset
1150 }
kono
parents:
diff changeset
1151 gcc_assert (swap_insn);
kono
parents:
diff changeset
1152
kono
parents:
diff changeset
1153 /* Find the load. */
kono
parents:
diff changeset
1154 insn_info = DF_INSN_INFO_GET (swap_insn);
kono
parents:
diff changeset
1155 rtx_insn *load_insn = 0;
kono
parents:
diff changeset
1156 FOR_EACH_INSN_INFO_USE (use, insn_info)
kono
parents:
diff changeset
1157 {
kono
parents:
diff changeset
1158 struct df_link *def_link = DF_REF_CHAIN (use);
kono
parents:
diff changeset
1159 gcc_assert (def_link && !def_link->next);
kono
parents:
diff changeset
1160 load_insn = DF_REF_INSN (def_link->ref);
kono
parents:
diff changeset
1161 break;
kono
parents:
diff changeset
1162 }
kono
parents:
diff changeset
1163 gcc_assert (load_insn);
kono
parents:
diff changeset
1164
kono
parents:
diff changeset
1165 /* Find the TOC-relative symbol access. */
kono
parents:
diff changeset
1166 insn_info = DF_INSN_INFO_GET (load_insn);
kono
parents:
diff changeset
1167 rtx_insn *tocrel_insn = 0;
kono
parents:
diff changeset
1168 FOR_EACH_INSN_INFO_USE (use, insn_info)
kono
parents:
diff changeset
1169 {
kono
parents:
diff changeset
1170 struct df_link *def_link = DF_REF_CHAIN (use);
kono
parents:
diff changeset
1171 gcc_assert (def_link && !def_link->next);
kono
parents:
diff changeset
1172 tocrel_insn = DF_REF_INSN (def_link->ref);
kono
parents:
diff changeset
1173 break;
kono
parents:
diff changeset
1174 }
kono
parents:
diff changeset
1175 gcc_assert (tocrel_insn);
kono
parents:
diff changeset
1176
kono
parents:
diff changeset
1177 /* Find the embedded CONST_VECTOR. We have to call toc_relative_expr_p
kono
parents:
diff changeset
1178 to set tocrel_base; otherwise it would be unnecessary as we've
kono
parents:
diff changeset
1179 already established it will return true. */
kono
parents:
diff changeset
1180 rtx base, offset;
kono
parents:
diff changeset
1181 const_rtx tocrel_base;
kono
parents:
diff changeset
1182 rtx tocrel_expr = SET_SRC (PATTERN (tocrel_insn));
kono
parents:
diff changeset
1183 /* There is an extra level of indirection for small/large code models. */
kono
parents:
diff changeset
1184 if (GET_CODE (tocrel_expr) == MEM)
kono
parents:
diff changeset
1185 tocrel_expr = XEXP (tocrel_expr, 0);
kono
parents:
diff changeset
1186 if (!toc_relative_expr_p (tocrel_expr, false, &tocrel_base, NULL))
kono
parents:
diff changeset
1187 gcc_unreachable ();
kono
parents:
diff changeset
1188 split_const (XVECEXP (tocrel_base, 0, 0), &base, &offset);
kono
parents:
diff changeset
1189 rtx const_vector = get_pool_constant (base);
kono
parents:
diff changeset
1190 /* With the extra indirection, get_pool_constant will produce the
kono
parents:
diff changeset
1191 real constant from the reg_equal expression, so get the real
kono
parents:
diff changeset
1192 constant. */
kono
parents:
diff changeset
1193 if (GET_CODE (const_vector) == SYMBOL_REF)
kono
parents:
diff changeset
1194 const_vector = get_pool_constant (const_vector);
kono
parents:
diff changeset
1195 gcc_assert (GET_CODE (const_vector) == CONST_VECTOR);
kono
parents:
diff changeset
1196
kono
parents:
diff changeset
1197 /* Create an adjusted mask from the initial mask. */
kono
parents:
diff changeset
1198 unsigned int new_mask[16], i, val;
kono
parents:
diff changeset
1199 for (i = 0; i < 16; ++i) {
kono
parents:
diff changeset
1200 val = INTVAL (XVECEXP (const_vector, 0, i));
kono
parents:
diff changeset
1201 if (val < 16)
kono
parents:
diff changeset
1202 new_mask[i] = (val + 8) % 16;
kono
parents:
diff changeset
1203 else
kono
parents:
diff changeset
1204 new_mask[i] = ((val + 8) % 16) + 16;
kono
parents:
diff changeset
1205 }
kono
parents:
diff changeset
1206
kono
parents:
diff changeset
1207 /* Create a new CONST_VECTOR and a MEM that references it. */
kono
parents:
diff changeset
1208 rtx vals = gen_rtx_PARALLEL (V16QImode, rtvec_alloc (16));
kono
parents:
diff changeset
1209 for (i = 0; i < 16; ++i)
kono
parents:
diff changeset
1210 XVECEXP (vals, 0, i) = GEN_INT (new_mask[i]);
kono
parents:
diff changeset
1211 rtx new_const_vector = gen_rtx_CONST_VECTOR (V16QImode, XVEC (vals, 0));
kono
parents:
diff changeset
1212 rtx new_mem = force_const_mem (V16QImode, new_const_vector);
kono
parents:
diff changeset
1213 /* This gives us a MEM whose base operand is a SYMBOL_REF, which we
kono
parents:
diff changeset
1214 can't recognize. Force the SYMBOL_REF into a register. */
kono
parents:
diff changeset
1215 if (!REG_P (XEXP (new_mem, 0))) {
kono
parents:
diff changeset
1216 rtx base_reg = force_reg (Pmode, XEXP (new_mem, 0));
kono
parents:
diff changeset
1217 XEXP (new_mem, 0) = base_reg;
kono
parents:
diff changeset
1218 /* Move the newly created insn ahead of the load insn. */
kono
parents:
diff changeset
1219 rtx_insn *force_insn = get_last_insn ();
kono
parents:
diff changeset
1220 remove_insn (force_insn);
kono
parents:
diff changeset
1221 rtx_insn *before_load_insn = PREV_INSN (load_insn);
kono
parents:
diff changeset
1222 add_insn_after (force_insn, before_load_insn, BLOCK_FOR_INSN (load_insn));
kono
parents:
diff changeset
1223 df_insn_rescan (before_load_insn);
kono
parents:
diff changeset
1224 df_insn_rescan (force_insn);
kono
parents:
diff changeset
1225 }
kono
parents:
diff changeset
1226
kono
parents:
diff changeset
1227 /* Replace the MEM in the load instruction and rescan it. */
kono
parents:
diff changeset
1228 XEXP (SET_SRC (PATTERN (load_insn)), 0) = new_mem;
kono
parents:
diff changeset
1229 INSN_CODE (load_insn) = -1; /* Force re-recognition. */
kono
parents:
diff changeset
1230 df_insn_rescan (load_insn);
kono
parents:
diff changeset
1231
kono
parents:
diff changeset
1232 if (dump_file)
kono
parents:
diff changeset
1233 fprintf (dump_file, "Adjusting mask for vperm %d\n", INSN_UID (insn));
kono
parents:
diff changeset
1234 }
kono
parents:
diff changeset
1235
kono
parents:
diff changeset
1236 /* The insn described by INSN_ENTRY[I] can be swapped, but only
kono
parents:
diff changeset
1237 with special handling. Take care of that here. */
kono
parents:
diff changeset
1238 static void
kono
parents:
diff changeset
1239 handle_special_swappables (swap_web_entry *insn_entry, unsigned i)
kono
parents:
diff changeset
1240 {
kono
parents:
diff changeset
1241 rtx_insn *insn = insn_entry[i].insn;
kono
parents:
diff changeset
1242 rtx body = PATTERN (insn);
kono
parents:
diff changeset
1243
kono
parents:
diff changeset
1244 switch (insn_entry[i].special_handling)
kono
parents:
diff changeset
1245 {
kono
parents:
diff changeset
1246 default:
kono
parents:
diff changeset
1247 gcc_unreachable ();
kono
parents:
diff changeset
1248 case SH_CONST_VECTOR:
kono
parents:
diff changeset
1249 {
kono
parents:
diff changeset
1250 /* A CONST_VECTOR will only show up somewhere in the RHS of a SET. */
kono
parents:
diff changeset
1251 gcc_assert (GET_CODE (body) == SET);
kono
parents:
diff changeset
1252 rtx rhs = SET_SRC (body);
kono
parents:
diff changeset
1253 swap_const_vector_halves (rhs);
kono
parents:
diff changeset
1254 if (dump_file)
kono
parents:
diff changeset
1255 fprintf (dump_file, "Swapping constant halves in insn %d\n", i);
kono
parents:
diff changeset
1256 break;
kono
parents:
diff changeset
1257 }
kono
parents:
diff changeset
1258 case SH_SUBREG:
kono
parents:
diff changeset
1259 /* A subreg of the same size is already safe. For subregs that
kono
parents:
diff changeset
1260 select a smaller portion of a reg, adjust the index for
kono
parents:
diff changeset
1261 swapped doublewords. */
kono
parents:
diff changeset
1262 adjust_subreg_index (body);
kono
parents:
diff changeset
1263 if (dump_file)
kono
parents:
diff changeset
1264 fprintf (dump_file, "Adjusting subreg in insn %d\n", i);
kono
parents:
diff changeset
1265 break;
kono
parents:
diff changeset
1266 case SH_NOSWAP_LD:
kono
parents:
diff changeset
1267 /* Convert a non-permuting load to a permuting one. */
kono
parents:
diff changeset
1268 permute_load (insn);
kono
parents:
diff changeset
1269 break;
kono
parents:
diff changeset
1270 case SH_NOSWAP_ST:
kono
parents:
diff changeset
1271 /* Convert a non-permuting store to a permuting one. */
kono
parents:
diff changeset
1272 permute_store (insn);
kono
parents:
diff changeset
1273 break;
kono
parents:
diff changeset
1274 case SH_EXTRACT:
kono
parents:
diff changeset
1275 /* Change the lane on an extract operation. */
kono
parents:
diff changeset
1276 adjust_extract (insn);
kono
parents:
diff changeset
1277 break;
kono
parents:
diff changeset
1278 case SH_SPLAT:
kono
parents:
diff changeset
1279 /* Change the lane on a direct-splat operation. */
kono
parents:
diff changeset
1280 adjust_splat (insn);
kono
parents:
diff changeset
1281 break;
kono
parents:
diff changeset
1282 case SH_XXPERMDI:
kono
parents:
diff changeset
1283 /* Change the lanes on an XXPERMDI operation. */
kono
parents:
diff changeset
1284 adjust_xxpermdi (insn);
kono
parents:
diff changeset
1285 break;
kono
parents:
diff changeset
1286 case SH_CONCAT:
kono
parents:
diff changeset
1287 /* Reverse the order of a concatenation operation. */
kono
parents:
diff changeset
1288 adjust_concat (insn);
kono
parents:
diff changeset
1289 break;
kono
parents:
diff changeset
1290 case SH_VPERM:
kono
parents:
diff changeset
1291 /* Change the mask loaded from the constant pool for a VPERM. */
kono
parents:
diff changeset
1292 adjust_vperm (insn);
kono
parents:
diff changeset
1293 break;
kono
parents:
diff changeset
1294 }
kono
parents:
diff changeset
1295 }
kono
parents:
diff changeset
1296
kono
parents:
diff changeset
1297 /* Find the insn from the Ith table entry, which is known to be a
kono
parents:
diff changeset
1298 register swap Y = SWAP(X). Replace it with a copy Y = X. */
kono
parents:
diff changeset
1299 static void
kono
parents:
diff changeset
1300 replace_swap_with_copy (swap_web_entry *insn_entry, unsigned i)
kono
parents:
diff changeset
1301 {
kono
parents:
diff changeset
1302 rtx_insn *insn = insn_entry[i].insn;
kono
parents:
diff changeset
1303 rtx body = PATTERN (insn);
kono
parents:
diff changeset
1304 rtx src_reg = XEXP (SET_SRC (body), 0);
kono
parents:
diff changeset
1305 rtx copy = gen_rtx_SET (SET_DEST (body), src_reg);
kono
parents:
diff changeset
1306 rtx_insn *new_insn = emit_insn_before (copy, insn);
kono
parents:
diff changeset
1307 set_block_for_insn (new_insn, BLOCK_FOR_INSN (insn));
kono
parents:
diff changeset
1308 df_insn_rescan (new_insn);
kono
parents:
diff changeset
1309
kono
parents:
diff changeset
1310 if (dump_file)
kono
parents:
diff changeset
1311 {
kono
parents:
diff changeset
1312 unsigned int new_uid = INSN_UID (new_insn);
kono
parents:
diff changeset
1313 fprintf (dump_file, "Replacing swap %d with copy %d\n", i, new_uid);
kono
parents:
diff changeset
1314 }
kono
parents:
diff changeset
1315
kono
parents:
diff changeset
1316 df_insn_delete (insn);
kono
parents:
diff changeset
1317 remove_insn (insn);
kono
parents:
diff changeset
1318 insn->set_deleted ();
kono
parents:
diff changeset
1319 }
kono
parents:
diff changeset
1320
kono
parents:
diff changeset
1321 /* Given that swap_insn represents a swap of a load of a constant
kono
parents:
diff changeset
1322 vector value, replace with a single instruction that loads a
kono
parents:
diff changeset
1323 swapped variant of the original constant.
kono
parents:
diff changeset
1324
kono
parents:
diff changeset
1325 The "natural" representation of a byte array in memory is the same
kono
parents:
diff changeset
1326 for big endian and little endian.
kono
parents:
diff changeset
1327
kono
parents:
diff changeset
1328 unsigned char byte_array[] =
kono
parents:
diff changeset
1329 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f };
kono
parents:
diff changeset
1330
kono
parents:
diff changeset
1331 However, when loaded into a vector register, the representation
kono
parents:
diff changeset
1332 depends on endian conventions.
kono
parents:
diff changeset
1333
kono
parents:
diff changeset
1334 In big-endian mode, the register holds:
kono
parents:
diff changeset
1335
kono
parents:
diff changeset
1336 MSB LSB
kono
parents:
diff changeset
1337 [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f ]
kono
parents:
diff changeset
1338
kono
parents:
diff changeset
1339 In little-endian mode, the register holds:
kono
parents:
diff changeset
1340
kono
parents:
diff changeset
1341 MSB LSB
kono
parents:
diff changeset
1342 [ f, e, d, c, b, a, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 ]
kono
parents:
diff changeset
1343
kono
parents:
diff changeset
1344 Word arrays require different handling. Consider the word array:
kono
parents:
diff changeset
1345
kono
parents:
diff changeset
1346 unsigned int word_array[] =
kono
parents:
diff changeset
1347 { 0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f };
kono
parents:
diff changeset
1348
kono
parents:
diff changeset
1349 The in-memory representation depends on endian configuration. The
kono
parents:
diff changeset
1350 equivalent array, declared as a byte array, in memory would be:
kono
parents:
diff changeset
1351
kono
parents:
diff changeset
1352 unsigned char big_endian_word_array_data[] =
kono
parents:
diff changeset
1353 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f }
kono
parents:
diff changeset
1354
kono
parents:
diff changeset
1355 unsigned char little_endian_word_array_data[] =
kono
parents:
diff changeset
1356 { 3, 2, 1, 0, 7, 6, 5, 4, b, a, 9, 8, f, e, d, c }
kono
parents:
diff changeset
1357
kono
parents:
diff changeset
1358 In big-endian mode, the register holds:
kono
parents:
diff changeset
1359
kono
parents:
diff changeset
1360 MSB LSB
kono
parents:
diff changeset
1361 [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f ]
kono
parents:
diff changeset
1362
kono
parents:
diff changeset
1363 In little-endian mode, the register holds:
kono
parents:
diff changeset
1364
kono
parents:
diff changeset
1365 MSB LSB
kono
parents:
diff changeset
1366 [ c, d, e, f, 8, 9, a, b, 4, 5, 6, 7, 0, 1, 2, 3 ]
kono
parents:
diff changeset
1367
kono
parents:
diff changeset
1368
kono
parents:
diff changeset
1369 Similar transformations apply to the vector of half-word and vector
kono
parents:
diff changeset
1370 of double-word representations.
kono
parents:
diff changeset
1371
kono
parents:
diff changeset
1372 For now, don't handle vectors of quad-precision values. Just return.
kono
parents:
diff changeset
1373 A better solution is to fix the code generator to emit lvx/stvx for
kono
parents:
diff changeset
1374 those. */
kono
parents:
diff changeset
1375 static void
kono
parents:
diff changeset
1376 replace_swapped_load_constant (swap_web_entry *insn_entry, rtx swap_insn)
kono
parents:
diff changeset
1377 {
kono
parents:
diff changeset
1378 /* Find the load. */
kono
parents:
diff changeset
1379 struct df_insn_info *insn_info = DF_INSN_INFO_GET (swap_insn);
kono
parents:
diff changeset
1380 rtx_insn *load_insn;
kono
parents:
diff changeset
1381 df_ref use = DF_INSN_INFO_USES (insn_info);
kono
parents:
diff changeset
1382 struct df_link *def_link = DF_REF_CHAIN (use);
kono
parents:
diff changeset
1383 gcc_assert (def_link && !def_link->next);
kono
parents:
diff changeset
1384
kono
parents:
diff changeset
1385 load_insn = DF_REF_INSN (def_link->ref);
kono
parents:
diff changeset
1386 gcc_assert (load_insn);
kono
parents:
diff changeset
1387
kono
parents:
diff changeset
1388 /* Find the TOC-relative symbol access. */
kono
parents:
diff changeset
1389 insn_info = DF_INSN_INFO_GET (load_insn);
kono
parents:
diff changeset
1390 use = DF_INSN_INFO_USES (insn_info);
kono
parents:
diff changeset
1391
kono
parents:
diff changeset
1392 def_link = DF_REF_CHAIN (use);
kono
parents:
diff changeset
1393 gcc_assert (def_link && !def_link->next);
kono
parents:
diff changeset
1394
kono
parents:
diff changeset
1395 rtx_insn *tocrel_insn = DF_REF_INSN (def_link->ref);
kono
parents:
diff changeset
1396 gcc_assert (tocrel_insn);
kono
parents:
diff changeset
1397
kono
parents:
diff changeset
1398 /* Find the embedded CONST_VECTOR. We have to call toc_relative_expr_p
kono
parents:
diff changeset
1399 to set tocrel_base; otherwise it would be unnecessary as we've
kono
parents:
diff changeset
1400 already established it will return true. */
kono
parents:
diff changeset
1401 rtx base, offset;
kono
parents:
diff changeset
1402 rtx tocrel_expr = SET_SRC (PATTERN (tocrel_insn));
kono
parents:
diff changeset
1403 const_rtx tocrel_base;
kono
parents:
diff changeset
1404
kono
parents:
diff changeset
1405 /* There is an extra level of indirection for small/large code models. */
kono
parents:
diff changeset
1406 if (GET_CODE (tocrel_expr) == MEM)
kono
parents:
diff changeset
1407 tocrel_expr = XEXP (tocrel_expr, 0);
kono
parents:
diff changeset
1408
kono
parents:
diff changeset
1409 if (!toc_relative_expr_p (tocrel_expr, false, &tocrel_base, NULL))
kono
parents:
diff changeset
1410 gcc_unreachable ();
kono
parents:
diff changeset
1411
kono
parents:
diff changeset
1412 split_const (XVECEXP (tocrel_base, 0, 0), &base, &offset);
kono
parents:
diff changeset
1413 rtx const_vector = get_pool_constant (base);
kono
parents:
diff changeset
1414
kono
parents:
diff changeset
1415 /* With the extra indirection, get_pool_constant will produce the
kono
parents:
diff changeset
1416 real constant from the reg_equal expression, so get the real
kono
parents:
diff changeset
1417 constant. */
kono
parents:
diff changeset
1418 if (GET_CODE (const_vector) == SYMBOL_REF)
kono
parents:
diff changeset
1419 const_vector = get_pool_constant (const_vector);
kono
parents:
diff changeset
1420 gcc_assert (GET_CODE (const_vector) == CONST_VECTOR);
kono
parents:
diff changeset
1421
kono
parents:
diff changeset
1422 rtx new_mem;
kono
parents:
diff changeset
1423 enum machine_mode mode = GET_MODE (const_vector);
kono
parents:
diff changeset
1424
kono
parents:
diff changeset
1425 /* Create an adjusted constant from the original constant. */
kono
parents:
diff changeset
1426 if (mode == V1TImode)
kono
parents:
diff changeset
1427 /* Leave this code as is. */
kono
parents:
diff changeset
1428 return;
kono
parents:
diff changeset
1429 else if (mode == V16QImode)
kono
parents:
diff changeset
1430 {
kono
parents:
diff changeset
1431 rtx vals = gen_rtx_PARALLEL (mode, rtvec_alloc (16));
kono
parents:
diff changeset
1432 int i;
kono
parents:
diff changeset
1433
kono
parents:
diff changeset
1434 for (i = 0; i < 16; i++)
kono
parents:
diff changeset
1435 XVECEXP (vals, 0, ((i+8) % 16)) = XVECEXP (const_vector, 0, i);
kono
parents:
diff changeset
1436 rtx new_const_vector = gen_rtx_CONST_VECTOR (mode, XVEC (vals, 0));
kono
parents:
diff changeset
1437 new_mem = force_const_mem (mode, new_const_vector);
kono
parents:
diff changeset
1438 }
kono
parents:
diff changeset
1439 else if ((mode == V8HImode)
kono
parents:
diff changeset
1440 #ifdef HAVE_V8HFmode
kono
parents:
diff changeset
1441 || (mode == V8HFmode)
kono
parents:
diff changeset
1442 #endif
kono
parents:
diff changeset
1443 )
kono
parents:
diff changeset
1444 {
kono
parents:
diff changeset
1445 rtx vals = gen_rtx_PARALLEL (mode, rtvec_alloc (8));
kono
parents:
diff changeset
1446 int i;
kono
parents:
diff changeset
1447
kono
parents:
diff changeset
1448 for (i = 0; i < 8; i++)
kono
parents:
diff changeset
1449 XVECEXP (vals, 0, ((i+4) % 8)) = XVECEXP (const_vector, 0, i);
kono
parents:
diff changeset
1450 rtx new_const_vector = gen_rtx_CONST_VECTOR (mode, XVEC (vals, 0));
kono
parents:
diff changeset
1451 new_mem = force_const_mem (mode, new_const_vector);
kono
parents:
diff changeset
1452 }
kono
parents:
diff changeset
1453 else if ((mode == V4SImode) || (mode == V4SFmode))
kono
parents:
diff changeset
1454 {
kono
parents:
diff changeset
1455 rtx vals = gen_rtx_PARALLEL (mode, rtvec_alloc (4));
kono
parents:
diff changeset
1456 int i;
kono
parents:
diff changeset
1457
kono
parents:
diff changeset
1458 for (i = 0; i < 4; i++)
kono
parents:
diff changeset
1459 XVECEXP (vals, 0, ((i+2) % 4)) = XVECEXP (const_vector, 0, i);
kono
parents:
diff changeset
1460 rtx new_const_vector = gen_rtx_CONST_VECTOR (mode, XVEC (vals, 0));
kono
parents:
diff changeset
1461 new_mem = force_const_mem (mode, new_const_vector);
kono
parents:
diff changeset
1462 }
kono
parents:
diff changeset
1463 else if ((mode == V2DImode) || (mode == V2DFmode))
kono
parents:
diff changeset
1464 {
kono
parents:
diff changeset
1465 rtx vals = gen_rtx_PARALLEL (mode, rtvec_alloc (2));
kono
parents:
diff changeset
1466 int i;
kono
parents:
diff changeset
1467
kono
parents:
diff changeset
1468 for (i = 0; i < 2; i++)
kono
parents:
diff changeset
1469 XVECEXP (vals, 0, ((i+1) % 2)) = XVECEXP (const_vector, 0, i);
kono
parents:
diff changeset
1470 rtx new_const_vector = gen_rtx_CONST_VECTOR (mode, XVEC (vals, 0));
kono
parents:
diff changeset
1471 new_mem = force_const_mem (mode, new_const_vector);
kono
parents:
diff changeset
1472 }
kono
parents:
diff changeset
1473 else
kono
parents:
diff changeset
1474 {
kono
parents:
diff changeset
1475 /* We do not expect other modes to be constant-load-swapped. */
kono
parents:
diff changeset
1476 gcc_unreachable ();
kono
parents:
diff changeset
1477 }
kono
parents:
diff changeset
1478
kono
parents:
diff changeset
1479 /* This gives us a MEM whose base operand is a SYMBOL_REF, which we
kono
parents:
diff changeset
1480 can't recognize. Force the SYMBOL_REF into a register. */
kono
parents:
diff changeset
1481 if (!REG_P (XEXP (new_mem, 0))) {
kono
parents:
diff changeset
1482 rtx base_reg = force_reg (Pmode, XEXP (new_mem, 0));
kono
parents:
diff changeset
1483 XEXP (new_mem, 0) = base_reg;
kono
parents:
diff changeset
1484
kono
parents:
diff changeset
1485 /* Move the newly created insn ahead of the load insn. */
kono
parents:
diff changeset
1486 /* The last insn is the the insn that forced new_mem into a register. */
kono
parents:
diff changeset
1487 rtx_insn *force_insn = get_last_insn ();
kono
parents:
diff changeset
1488 /* Remove this insn from the end of the instruction sequence. */
kono
parents:
diff changeset
1489 remove_insn (force_insn);
kono
parents:
diff changeset
1490 rtx_insn *before_load_insn = PREV_INSN (load_insn);
kono
parents:
diff changeset
1491
kono
parents:
diff changeset
1492 /* And insert this insn back into the sequence before the previous
kono
parents:
diff changeset
1493 load insn so this new expression will be available when the
kono
parents:
diff changeset
1494 existing load is modified to load the swapped constant. */
kono
parents:
diff changeset
1495 add_insn_after (force_insn, before_load_insn, BLOCK_FOR_INSN (load_insn));
kono
parents:
diff changeset
1496 df_insn_rescan (before_load_insn);
kono
parents:
diff changeset
1497 df_insn_rescan (force_insn);
kono
parents:
diff changeset
1498 }
kono
parents:
diff changeset
1499
kono
parents:
diff changeset
1500 /* Replace the MEM in the load instruction and rescan it. */
kono
parents:
diff changeset
1501 XEXP (SET_SRC (PATTERN (load_insn)), 0) = new_mem;
kono
parents:
diff changeset
1502 INSN_CODE (load_insn) = -1; /* Force re-recognition. */
kono
parents:
diff changeset
1503 df_insn_rescan (load_insn);
kono
parents:
diff changeset
1504
kono
parents:
diff changeset
1505 unsigned int uid = INSN_UID (swap_insn);
kono
parents:
diff changeset
1506 mark_swaps_for_removal (insn_entry, uid);
kono
parents:
diff changeset
1507 replace_swap_with_copy (insn_entry, uid);
kono
parents:
diff changeset
1508 }
kono
parents:
diff changeset
1509
kono
parents:
diff changeset
1510 /* Dump the swap table to DUMP_FILE. */
kono
parents:
diff changeset
1511 static void
kono
parents:
diff changeset
1512 dump_swap_insn_table (swap_web_entry *insn_entry)
kono
parents:
diff changeset
1513 {
kono
parents:
diff changeset
1514 int e = get_max_uid ();
kono
parents:
diff changeset
1515 fprintf (dump_file, "\nRelevant insns with their flag settings\n\n");
kono
parents:
diff changeset
1516
kono
parents:
diff changeset
1517 for (int i = 0; i < e; ++i)
kono
parents:
diff changeset
1518 if (insn_entry[i].is_relevant)
kono
parents:
diff changeset
1519 {
kono
parents:
diff changeset
1520 swap_web_entry *pred_entry = (swap_web_entry *)insn_entry[i].pred ();
kono
parents:
diff changeset
1521 fprintf (dump_file, "%6d %6d ", i,
kono
parents:
diff changeset
1522 pred_entry && pred_entry->insn
kono
parents:
diff changeset
1523 ? INSN_UID (pred_entry->insn) : 0);
kono
parents:
diff changeset
1524 if (insn_entry[i].is_load)
kono
parents:
diff changeset
1525 fputs ("load ", dump_file);
kono
parents:
diff changeset
1526 if (insn_entry[i].is_store)
kono
parents:
diff changeset
1527 fputs ("store ", dump_file);
kono
parents:
diff changeset
1528 if (insn_entry[i].is_swap)
kono
parents:
diff changeset
1529 fputs ("swap ", dump_file);
kono
parents:
diff changeset
1530 if (insn_entry[i].is_live_in)
kono
parents:
diff changeset
1531 fputs ("live-in ", dump_file);
kono
parents:
diff changeset
1532 if (insn_entry[i].is_live_out)
kono
parents:
diff changeset
1533 fputs ("live-out ", dump_file);
kono
parents:
diff changeset
1534 if (insn_entry[i].contains_subreg)
kono
parents:
diff changeset
1535 fputs ("subreg ", dump_file);
kono
parents:
diff changeset
1536 if (insn_entry[i].is_128_int)
kono
parents:
diff changeset
1537 fputs ("int128 ", dump_file);
kono
parents:
diff changeset
1538 if (insn_entry[i].is_call)
kono
parents:
diff changeset
1539 fputs ("call ", dump_file);
kono
parents:
diff changeset
1540 if (insn_entry[i].is_swappable)
kono
parents:
diff changeset
1541 {
kono
parents:
diff changeset
1542 fputs ("swappable ", dump_file);
kono
parents:
diff changeset
1543 if (insn_entry[i].special_handling == SH_CONST_VECTOR)
kono
parents:
diff changeset
1544 fputs ("special:constvec ", dump_file);
kono
parents:
diff changeset
1545 else if (insn_entry[i].special_handling == SH_SUBREG)
kono
parents:
diff changeset
1546 fputs ("special:subreg ", dump_file);
kono
parents:
diff changeset
1547 else if (insn_entry[i].special_handling == SH_NOSWAP_LD)
kono
parents:
diff changeset
1548 fputs ("special:load ", dump_file);
kono
parents:
diff changeset
1549 else if (insn_entry[i].special_handling == SH_NOSWAP_ST)
kono
parents:
diff changeset
1550 fputs ("special:store ", dump_file);
kono
parents:
diff changeset
1551 else if (insn_entry[i].special_handling == SH_EXTRACT)
kono
parents:
diff changeset
1552 fputs ("special:extract ", dump_file);
kono
parents:
diff changeset
1553 else if (insn_entry[i].special_handling == SH_SPLAT)
kono
parents:
diff changeset
1554 fputs ("special:splat ", dump_file);
kono
parents:
diff changeset
1555 else if (insn_entry[i].special_handling == SH_XXPERMDI)
kono
parents:
diff changeset
1556 fputs ("special:xxpermdi ", dump_file);
kono
parents:
diff changeset
1557 else if (insn_entry[i].special_handling == SH_CONCAT)
kono
parents:
diff changeset
1558 fputs ("special:concat ", dump_file);
kono
parents:
diff changeset
1559 else if (insn_entry[i].special_handling == SH_VPERM)
kono
parents:
diff changeset
1560 fputs ("special:vperm ", dump_file);
kono
parents:
diff changeset
1561 }
kono
parents:
diff changeset
1562 if (insn_entry[i].web_not_optimizable)
kono
parents:
diff changeset
1563 fputs ("unoptimizable ", dump_file);
kono
parents:
diff changeset
1564 if (insn_entry[i].will_delete)
kono
parents:
diff changeset
1565 fputs ("delete ", dump_file);
kono
parents:
diff changeset
1566 fputs ("\n", dump_file);
kono
parents:
diff changeset
1567 }
kono
parents:
diff changeset
1568 fputs ("\n", dump_file);
kono
parents:
diff changeset
1569 }
kono
parents:
diff changeset
1570
kono
parents:
diff changeset
1571 /* Return RTX with its address canonicalized to (reg) or (+ reg reg).
kono
parents:
diff changeset
1572 Here RTX is an (& addr (const_int -16)). Always return a new copy
kono
parents:
diff changeset
1573 to avoid problems with combine. */
kono
parents:
diff changeset
1574 static rtx
kono
parents:
diff changeset
1575 alignment_with_canonical_addr (rtx align)
kono
parents:
diff changeset
1576 {
kono
parents:
diff changeset
1577 rtx canon;
kono
parents:
diff changeset
1578 rtx addr = XEXP (align, 0);
kono
parents:
diff changeset
1579
kono
parents:
diff changeset
1580 if (REG_P (addr))
kono
parents:
diff changeset
1581 canon = addr;
kono
parents:
diff changeset
1582
kono
parents:
diff changeset
1583 else if (GET_CODE (addr) == PLUS)
kono
parents:
diff changeset
1584 {
kono
parents:
diff changeset
1585 rtx addrop0 = XEXP (addr, 0);
kono
parents:
diff changeset
1586 rtx addrop1 = XEXP (addr, 1);
kono
parents:
diff changeset
1587
kono
parents:
diff changeset
1588 if (!REG_P (addrop0))
kono
parents:
diff changeset
1589 addrop0 = force_reg (GET_MODE (addrop0), addrop0);
kono
parents:
diff changeset
1590
kono
parents:
diff changeset
1591 if (!REG_P (addrop1))
kono
parents:
diff changeset
1592 addrop1 = force_reg (GET_MODE (addrop1), addrop1);
kono
parents:
diff changeset
1593
kono
parents:
diff changeset
1594 canon = gen_rtx_PLUS (GET_MODE (addr), addrop0, addrop1);
kono
parents:
diff changeset
1595 }
kono
parents:
diff changeset
1596
kono
parents:
diff changeset
1597 else
kono
parents:
diff changeset
1598 canon = force_reg (GET_MODE (addr), addr);
kono
parents:
diff changeset
1599
kono
parents:
diff changeset
1600 return gen_rtx_AND (GET_MODE (align), canon, GEN_INT (-16));
kono
parents:
diff changeset
1601 }
kono
parents:
diff changeset
1602
kono
parents:
diff changeset
1603 /* Check whether an rtx is an alignment mask, and if so, return
kono
parents:
diff changeset
1604 a fully-expanded rtx for the masking operation. */
kono
parents:
diff changeset
1605 static rtx
kono
parents:
diff changeset
1606 alignment_mask (rtx_insn *insn)
kono
parents:
diff changeset
1607 {
kono
parents:
diff changeset
1608 rtx body = PATTERN (insn);
kono
parents:
diff changeset
1609
kono
parents:
diff changeset
1610 if (GET_CODE (body) != SET
kono
parents:
diff changeset
1611 || GET_CODE (SET_SRC (body)) != AND
kono
parents:
diff changeset
1612 || !REG_P (XEXP (SET_SRC (body), 0)))
kono
parents:
diff changeset
1613 return 0;
kono
parents:
diff changeset
1614
kono
parents:
diff changeset
1615 rtx mask = XEXP (SET_SRC (body), 1);
kono
parents:
diff changeset
1616
kono
parents:
diff changeset
1617 if (GET_CODE (mask) == CONST_INT)
kono
parents:
diff changeset
1618 {
kono
parents:
diff changeset
1619 if (INTVAL (mask) == -16)
kono
parents:
diff changeset
1620 return alignment_with_canonical_addr (SET_SRC (body));
kono
parents:
diff changeset
1621 else
kono
parents:
diff changeset
1622 return 0;
kono
parents:
diff changeset
1623 }
kono
parents:
diff changeset
1624
kono
parents:
diff changeset
1625 if (!REG_P (mask))
kono
parents:
diff changeset
1626 return 0;
kono
parents:
diff changeset
1627
kono
parents:
diff changeset
1628 struct df_insn_info *insn_info = DF_INSN_INFO_GET (insn);
kono
parents:
diff changeset
1629 df_ref use;
kono
parents:
diff changeset
1630 rtx real_mask = 0;
kono
parents:
diff changeset
1631
kono
parents:
diff changeset
1632 FOR_EACH_INSN_INFO_USE (use, insn_info)
kono
parents:
diff changeset
1633 {
kono
parents:
diff changeset
1634 if (!rtx_equal_p (DF_REF_REG (use), mask))
kono
parents:
diff changeset
1635 continue;
kono
parents:
diff changeset
1636
kono
parents:
diff changeset
1637 struct df_link *def_link = DF_REF_CHAIN (use);
kono
parents:
diff changeset
1638 if (!def_link || def_link->next)
kono
parents:
diff changeset
1639 return 0;
kono
parents:
diff changeset
1640
kono
parents:
diff changeset
1641 rtx_insn *const_insn = DF_REF_INSN (def_link->ref);
kono
parents:
diff changeset
1642 rtx const_body = PATTERN (const_insn);
kono
parents:
diff changeset
1643 if (GET_CODE (const_body) != SET)
kono
parents:
diff changeset
1644 return 0;
kono
parents:
diff changeset
1645
kono
parents:
diff changeset
1646 real_mask = SET_SRC (const_body);
kono
parents:
diff changeset
1647
kono
parents:
diff changeset
1648 if (GET_CODE (real_mask) != CONST_INT
kono
parents:
diff changeset
1649 || INTVAL (real_mask) != -16)
kono
parents:
diff changeset
1650 return 0;
kono
parents:
diff changeset
1651 }
kono
parents:
diff changeset
1652
kono
parents:
diff changeset
1653 if (real_mask == 0)
kono
parents:
diff changeset
1654 return 0;
kono
parents:
diff changeset
1655
kono
parents:
diff changeset
1656 return alignment_with_canonical_addr (SET_SRC (body));
kono
parents:
diff changeset
1657 }
kono
parents:
diff changeset
1658
kono
parents:
diff changeset
1659 /* Given INSN that's a load or store based at BASE_REG, look for a
kono
parents:
diff changeset
1660 feeding computation that aligns its address on a 16-byte boundary.
kono
parents:
diff changeset
1661 Return the rtx and its containing AND_INSN. */
kono
parents:
diff changeset
1662 static rtx
kono
parents:
diff changeset
1663 find_alignment_op (rtx_insn *insn, rtx base_reg, rtx_insn **and_insn)
kono
parents:
diff changeset
1664 {
kono
parents:
diff changeset
1665 df_ref base_use;
kono
parents:
diff changeset
1666 struct df_insn_info *insn_info = DF_INSN_INFO_GET (insn);
kono
parents:
diff changeset
1667 rtx and_operation = 0;
kono
parents:
diff changeset
1668
kono
parents:
diff changeset
1669 FOR_EACH_INSN_INFO_USE (base_use, insn_info)
kono
parents:
diff changeset
1670 {
kono
parents:
diff changeset
1671 if (!rtx_equal_p (DF_REF_REG (base_use), base_reg))
kono
parents:
diff changeset
1672 continue;
kono
parents:
diff changeset
1673
kono
parents:
diff changeset
1674 struct df_link *base_def_link = DF_REF_CHAIN (base_use);
kono
parents:
diff changeset
1675 if (!base_def_link || base_def_link->next)
kono
parents:
diff changeset
1676 break;
kono
parents:
diff changeset
1677
kono
parents:
diff changeset
1678 /* With stack-protector code enabled, and possibly in other
kono
parents:
diff changeset
1679 circumstances, there may not be an associated insn for
kono
parents:
diff changeset
1680 the def. */
kono
parents:
diff changeset
1681 if (DF_REF_IS_ARTIFICIAL (base_def_link->ref))
kono
parents:
diff changeset
1682 break;
kono
parents:
diff changeset
1683
kono
parents:
diff changeset
1684 *and_insn = DF_REF_INSN (base_def_link->ref);
kono
parents:
diff changeset
1685 and_operation = alignment_mask (*and_insn);
kono
parents:
diff changeset
1686 if (and_operation != 0)
kono
parents:
diff changeset
1687 break;
kono
parents:
diff changeset
1688 }
kono
parents:
diff changeset
1689
kono
parents:
diff changeset
1690 return and_operation;
kono
parents:
diff changeset
1691 }
kono
parents:
diff changeset
1692
kono
parents:
diff changeset
1693 struct del_info { bool replace; rtx_insn *replace_insn; };
kono
parents:
diff changeset
1694
kono
parents:
diff changeset
1695 /* If INSN is the load for an lvx pattern, put it in canonical form. */
kono
parents:
diff changeset
1696 static void
kono
parents:
diff changeset
1697 recombine_lvx_pattern (rtx_insn *insn, del_info *to_delete)
kono
parents:
diff changeset
1698 {
kono
parents:
diff changeset
1699 rtx body = PATTERN (insn);
kono
parents:
diff changeset
1700 gcc_assert (GET_CODE (body) == SET
kono
parents:
diff changeset
1701 && GET_CODE (SET_SRC (body)) == VEC_SELECT
kono
parents:
diff changeset
1702 && GET_CODE (XEXP (SET_SRC (body), 0)) == MEM);
kono
parents:
diff changeset
1703
kono
parents:
diff changeset
1704 rtx mem = XEXP (SET_SRC (body), 0);
kono
parents:
diff changeset
1705 rtx base_reg = XEXP (mem, 0);
kono
parents:
diff changeset
1706
kono
parents:
diff changeset
1707 rtx_insn *and_insn;
kono
parents:
diff changeset
1708 rtx and_operation = find_alignment_op (insn, base_reg, &and_insn);
kono
parents:
diff changeset
1709
kono
parents:
diff changeset
1710 if (and_operation != 0)
kono
parents:
diff changeset
1711 {
kono
parents:
diff changeset
1712 df_ref def;
kono
parents:
diff changeset
1713 struct df_insn_info *insn_info = DF_INSN_INFO_GET (insn);
kono
parents:
diff changeset
1714 FOR_EACH_INSN_INFO_DEF (def, insn_info)
kono
parents:
diff changeset
1715 {
kono
parents:
diff changeset
1716 struct df_link *link = DF_REF_CHAIN (def);
kono
parents:
diff changeset
1717 if (!link || link->next)
kono
parents:
diff changeset
1718 break;
kono
parents:
diff changeset
1719
kono
parents:
diff changeset
1720 rtx_insn *swap_insn = DF_REF_INSN (link->ref);
kono
parents:
diff changeset
1721 if (!insn_is_swap_p (swap_insn)
kono
parents:
diff changeset
1722 || insn_is_load_p (swap_insn)
kono
parents:
diff changeset
1723 || insn_is_store_p (swap_insn))
kono
parents:
diff changeset
1724 break;
kono
parents:
diff changeset
1725
kono
parents:
diff changeset
1726 /* Expected lvx pattern found. Change the swap to
kono
parents:
diff changeset
1727 a copy, and propagate the AND operation into the
kono
parents:
diff changeset
1728 load. */
kono
parents:
diff changeset
1729 to_delete[INSN_UID (swap_insn)].replace = true;
kono
parents:
diff changeset
1730 to_delete[INSN_UID (swap_insn)].replace_insn = swap_insn;
kono
parents:
diff changeset
1731
kono
parents:
diff changeset
1732 /* However, first we must be sure that we make the
kono
parents:
diff changeset
1733 base register from the AND operation available
kono
parents:
diff changeset
1734 in case the register has been overwritten. Copy
kono
parents:
diff changeset
1735 the base register to a new pseudo and use that
kono
parents:
diff changeset
1736 as the base register of the AND operation in
kono
parents:
diff changeset
1737 the new LVX instruction. */
kono
parents:
diff changeset
1738 rtx and_base = XEXP (and_operation, 0);
kono
parents:
diff changeset
1739 rtx new_reg = gen_reg_rtx (GET_MODE (and_base));
kono
parents:
diff changeset
1740 rtx copy = gen_rtx_SET (new_reg, and_base);
kono
parents:
diff changeset
1741 rtx_insn *new_insn = emit_insn_after (copy, and_insn);
kono
parents:
diff changeset
1742 set_block_for_insn (new_insn, BLOCK_FOR_INSN (and_insn));
kono
parents:
diff changeset
1743 df_insn_rescan (new_insn);
kono
parents:
diff changeset
1744
kono
parents:
diff changeset
1745 XEXP (mem, 0) = gen_rtx_AND (GET_MODE (and_base), new_reg,
kono
parents:
diff changeset
1746 XEXP (and_operation, 1));
kono
parents:
diff changeset
1747 SET_SRC (body) = mem;
kono
parents:
diff changeset
1748 INSN_CODE (insn) = -1; /* Force re-recognition. */
kono
parents:
diff changeset
1749 df_insn_rescan (insn);
kono
parents:
diff changeset
1750
kono
parents:
diff changeset
1751 if (dump_file)
kono
parents:
diff changeset
1752 fprintf (dump_file, "lvx opportunity found at %d\n",
kono
parents:
diff changeset
1753 INSN_UID (insn));
kono
parents:
diff changeset
1754 }
kono
parents:
diff changeset
1755 }
kono
parents:
diff changeset
1756 }
kono
parents:
diff changeset
1757
kono
parents:
diff changeset
1758 /* If INSN is the store for an stvx pattern, put it in canonical form. */
kono
parents:
diff changeset
1759 static void
kono
parents:
diff changeset
1760 recombine_stvx_pattern (rtx_insn *insn, del_info *to_delete)
kono
parents:
diff changeset
1761 {
kono
parents:
diff changeset
1762 rtx body = PATTERN (insn);
kono
parents:
diff changeset
1763 gcc_assert (GET_CODE (body) == SET
kono
parents:
diff changeset
1764 && GET_CODE (SET_DEST (body)) == MEM
kono
parents:
diff changeset
1765 && GET_CODE (SET_SRC (body)) == VEC_SELECT);
kono
parents:
diff changeset
1766 rtx mem = SET_DEST (body);
kono
parents:
diff changeset
1767 rtx base_reg = XEXP (mem, 0);
kono
parents:
diff changeset
1768
kono
parents:
diff changeset
1769 rtx_insn *and_insn;
kono
parents:
diff changeset
1770 rtx and_operation = find_alignment_op (insn, base_reg, &and_insn);
kono
parents:
diff changeset
1771
kono
parents:
diff changeset
1772 if (and_operation != 0)
kono
parents:
diff changeset
1773 {
kono
parents:
diff changeset
1774 rtx src_reg = XEXP (SET_SRC (body), 0);
kono
parents:
diff changeset
1775 df_ref src_use;
kono
parents:
diff changeset
1776 struct df_insn_info *insn_info = DF_INSN_INFO_GET (insn);
kono
parents:
diff changeset
1777 FOR_EACH_INSN_INFO_USE (src_use, insn_info)
kono
parents:
diff changeset
1778 {
kono
parents:
diff changeset
1779 if (!rtx_equal_p (DF_REF_REG (src_use), src_reg))
kono
parents:
diff changeset
1780 continue;
kono
parents:
diff changeset
1781
kono
parents:
diff changeset
1782 struct df_link *link = DF_REF_CHAIN (src_use);
kono
parents:
diff changeset
1783 if (!link || link->next)
kono
parents:
diff changeset
1784 break;
kono
parents:
diff changeset
1785
kono
parents:
diff changeset
1786 rtx_insn *swap_insn = DF_REF_INSN (link->ref);
kono
parents:
diff changeset
1787 if (!insn_is_swap_p (swap_insn)
kono
parents:
diff changeset
1788 || insn_is_load_p (swap_insn)
kono
parents:
diff changeset
1789 || insn_is_store_p (swap_insn))
kono
parents:
diff changeset
1790 break;
kono
parents:
diff changeset
1791
kono
parents:
diff changeset
1792 /* Expected stvx pattern found. Change the swap to
kono
parents:
diff changeset
1793 a copy, and propagate the AND operation into the
kono
parents:
diff changeset
1794 store. */
kono
parents:
diff changeset
1795 to_delete[INSN_UID (swap_insn)].replace = true;
kono
parents:
diff changeset
1796 to_delete[INSN_UID (swap_insn)].replace_insn = swap_insn;
kono
parents:
diff changeset
1797
kono
parents:
diff changeset
1798 /* However, first we must be sure that we make the
kono
parents:
diff changeset
1799 base register from the AND operation available
kono
parents:
diff changeset
1800 in case the register has been overwritten. Copy
kono
parents:
diff changeset
1801 the base register to a new pseudo and use that
kono
parents:
diff changeset
1802 as the base register of the AND operation in
kono
parents:
diff changeset
1803 the new STVX instruction. */
kono
parents:
diff changeset
1804 rtx and_base = XEXP (and_operation, 0);
kono
parents:
diff changeset
1805 rtx new_reg = gen_reg_rtx (GET_MODE (and_base));
kono
parents:
diff changeset
1806 rtx copy = gen_rtx_SET (new_reg, and_base);
kono
parents:
diff changeset
1807 rtx_insn *new_insn = emit_insn_after (copy, and_insn);
kono
parents:
diff changeset
1808 set_block_for_insn (new_insn, BLOCK_FOR_INSN (and_insn));
kono
parents:
diff changeset
1809 df_insn_rescan (new_insn);
kono
parents:
diff changeset
1810
kono
parents:
diff changeset
1811 XEXP (mem, 0) = gen_rtx_AND (GET_MODE (and_base), new_reg,
kono
parents:
diff changeset
1812 XEXP (and_operation, 1));
kono
parents:
diff changeset
1813 SET_SRC (body) = src_reg;
kono
parents:
diff changeset
1814 INSN_CODE (insn) = -1; /* Force re-recognition. */
kono
parents:
diff changeset
1815 df_insn_rescan (insn);
kono
parents:
diff changeset
1816
kono
parents:
diff changeset
1817 if (dump_file)
kono
parents:
diff changeset
1818 fprintf (dump_file, "stvx opportunity found at %d\n",
kono
parents:
diff changeset
1819 INSN_UID (insn));
kono
parents:
diff changeset
1820 }
kono
parents:
diff changeset
1821 }
kono
parents:
diff changeset
1822 }
kono
parents:
diff changeset
1823
kono
parents:
diff changeset
1824 /* Look for patterns created from builtin lvx and stvx calls, and
kono
parents:
diff changeset
1825 canonicalize them to be properly recognized as such. */
kono
parents:
diff changeset
1826 static void
kono
parents:
diff changeset
1827 recombine_lvx_stvx_patterns (function *fun)
kono
parents:
diff changeset
1828 {
kono
parents:
diff changeset
1829 int i;
kono
parents:
diff changeset
1830 basic_block bb;
kono
parents:
diff changeset
1831 rtx_insn *insn;
kono
parents:
diff changeset
1832
kono
parents:
diff changeset
1833 int num_insns = get_max_uid ();
kono
parents:
diff changeset
1834 del_info *to_delete = XCNEWVEC (del_info, num_insns);
kono
parents:
diff changeset
1835
kono
parents:
diff changeset
1836 FOR_ALL_BB_FN (bb, fun)
kono
parents:
diff changeset
1837 FOR_BB_INSNS (bb, insn)
kono
parents:
diff changeset
1838 {
kono
parents:
diff changeset
1839 if (!NONDEBUG_INSN_P (insn))
kono
parents:
diff changeset
1840 continue;
kono
parents:
diff changeset
1841
kono
parents:
diff changeset
1842 if (insn_is_load_p (insn) && insn_is_swap_p (insn))
kono
parents:
diff changeset
1843 recombine_lvx_pattern (insn, to_delete);
kono
parents:
diff changeset
1844 else if (insn_is_store_p (insn) && insn_is_swap_p (insn))
kono
parents:
diff changeset
1845 recombine_stvx_pattern (insn, to_delete);
kono
parents:
diff changeset
1846 }
kono
parents:
diff changeset
1847
kono
parents:
diff changeset
1848 /* Turning swaps into copies is delayed until now, to avoid problems
kono
parents:
diff changeset
1849 with deleting instructions during the insn walk. */
kono
parents:
diff changeset
1850 for (i = 0; i < num_insns; i++)
kono
parents:
diff changeset
1851 if (to_delete[i].replace)
kono
parents:
diff changeset
1852 {
kono
parents:
diff changeset
1853 rtx swap_body = PATTERN (to_delete[i].replace_insn);
kono
parents:
diff changeset
1854 rtx src_reg = XEXP (SET_SRC (swap_body), 0);
kono
parents:
diff changeset
1855 rtx copy = gen_rtx_SET (SET_DEST (swap_body), src_reg);
kono
parents:
diff changeset
1856 rtx_insn *new_insn = emit_insn_before (copy,
kono
parents:
diff changeset
1857 to_delete[i].replace_insn);
kono
parents:
diff changeset
1858 set_block_for_insn (new_insn,
kono
parents:
diff changeset
1859 BLOCK_FOR_INSN (to_delete[i].replace_insn));
kono
parents:
diff changeset
1860 df_insn_rescan (new_insn);
kono
parents:
diff changeset
1861 df_insn_delete (to_delete[i].replace_insn);
kono
parents:
diff changeset
1862 remove_insn (to_delete[i].replace_insn);
kono
parents:
diff changeset
1863 to_delete[i].replace_insn->set_deleted ();
kono
parents:
diff changeset
1864 }
kono
parents:
diff changeset
1865
kono
parents:
diff changeset
1866 free (to_delete);
kono
parents:
diff changeset
1867 }
kono
parents:
diff changeset
1868
kono
parents:
diff changeset
1869 /* Main entry point for this pass. */
kono
parents:
diff changeset
1870 unsigned int
kono
parents:
diff changeset
1871 rs6000_analyze_swaps (function *fun)
kono
parents:
diff changeset
1872 {
kono
parents:
diff changeset
1873 swap_web_entry *insn_entry;
kono
parents:
diff changeset
1874 basic_block bb;
kono
parents:
diff changeset
1875 rtx_insn *insn, *curr_insn = 0;
kono
parents:
diff changeset
1876
kono
parents:
diff changeset
1877 /* Dataflow analysis for use-def chains. */
kono
parents:
diff changeset
1878 df_set_flags (DF_RD_PRUNE_DEAD_DEFS);
kono
parents:
diff changeset
1879 df_chain_add_problem (DF_DU_CHAIN | DF_UD_CHAIN);
kono
parents:
diff changeset
1880 df_analyze ();
kono
parents:
diff changeset
1881 df_set_flags (DF_DEFER_INSN_RESCAN);
kono
parents:
diff changeset
1882
kono
parents:
diff changeset
1883 /* Pre-pass to recombine lvx and stvx patterns so we don't lose info. */
kono
parents:
diff changeset
1884 recombine_lvx_stvx_patterns (fun);
kono
parents:
diff changeset
1885 df_process_deferred_rescans ();
kono
parents:
diff changeset
1886
kono
parents:
diff changeset
1887 /* Allocate structure to represent webs of insns. */
kono
parents:
diff changeset
1888 insn_entry = XCNEWVEC (swap_web_entry, get_max_uid ());
kono
parents:
diff changeset
1889
kono
parents:
diff changeset
1890 /* Walk the insns to gather basic data. */
kono
parents:
diff changeset
1891 FOR_ALL_BB_FN (bb, fun)
kono
parents:
diff changeset
1892 FOR_BB_INSNS_SAFE (bb, insn, curr_insn)
kono
parents:
diff changeset
1893 {
kono
parents:
diff changeset
1894 unsigned int uid = INSN_UID (insn);
kono
parents:
diff changeset
1895 if (NONDEBUG_INSN_P (insn))
kono
parents:
diff changeset
1896 {
kono
parents:
diff changeset
1897 insn_entry[uid].insn = insn;
kono
parents:
diff changeset
1898
kono
parents:
diff changeset
1899 if (GET_CODE (insn) == CALL_INSN)
kono
parents:
diff changeset
1900 insn_entry[uid].is_call = 1;
kono
parents:
diff changeset
1901
kono
parents:
diff changeset
1902 /* Walk the uses and defs to see if we mention vector regs.
kono
parents:
diff changeset
1903 Record any constraints on optimization of such mentions. */
kono
parents:
diff changeset
1904 struct df_insn_info *insn_info = DF_INSN_INFO_GET (insn);
kono
parents:
diff changeset
1905 df_ref mention;
kono
parents:
diff changeset
1906 FOR_EACH_INSN_INFO_USE (mention, insn_info)
kono
parents:
diff changeset
1907 {
kono
parents:
diff changeset
1908 /* We use DF_REF_REAL_REG here to get inside any subregs. */
kono
parents:
diff changeset
1909 machine_mode mode = GET_MODE (DF_REF_REAL_REG (mention));
kono
parents:
diff changeset
1910
kono
parents:
diff changeset
1911 /* If a use gets its value from a call insn, it will be
kono
parents:
diff changeset
1912 a hard register and will look like (reg:V4SI 3 3).
kono
parents:
diff changeset
1913 The df analysis creates two mentions for GPR3 and GPR4,
kono
parents:
diff changeset
1914 both DImode. We must recognize this and treat it as a
kono
parents:
diff changeset
1915 vector mention to ensure the call is unioned with this
kono
parents:
diff changeset
1916 use. */
kono
parents:
diff changeset
1917 if (mode == DImode && DF_REF_INSN_INFO (mention))
kono
parents:
diff changeset
1918 {
kono
parents:
diff changeset
1919 rtx feeder = DF_REF_INSN (mention);
kono
parents:
diff changeset
1920 /* FIXME: It is pretty hard to get from the df mention
kono
parents:
diff changeset
1921 to the mode of the use in the insn. We arbitrarily
kono
parents:
diff changeset
1922 pick a vector mode here, even though the use might
kono
parents:
diff changeset
1923 be a real DImode. We can be too conservative
kono
parents:
diff changeset
1924 (create a web larger than necessary) because of
kono
parents:
diff changeset
1925 this, so consider eventually fixing this. */
kono
parents:
diff changeset
1926 if (GET_CODE (feeder) == CALL_INSN)
kono
parents:
diff changeset
1927 mode = V4SImode;
kono
parents:
diff changeset
1928 }
kono
parents:
diff changeset
1929
kono
parents:
diff changeset
1930 if (ALTIVEC_OR_VSX_VECTOR_MODE (mode) || mode == TImode)
kono
parents:
diff changeset
1931 {
kono
parents:
diff changeset
1932 insn_entry[uid].is_relevant = 1;
kono
parents:
diff changeset
1933 if (mode == TImode || mode == V1TImode
kono
parents:
diff changeset
1934 || FLOAT128_VECTOR_P (mode))
kono
parents:
diff changeset
1935 insn_entry[uid].is_128_int = 1;
kono
parents:
diff changeset
1936 if (DF_REF_INSN_INFO (mention))
kono
parents:
diff changeset
1937 insn_entry[uid].contains_subreg
kono
parents:
diff changeset
1938 = !rtx_equal_p (DF_REF_REG (mention),
kono
parents:
diff changeset
1939 DF_REF_REAL_REG (mention));
kono
parents:
diff changeset
1940 union_defs (insn_entry, insn, mention);
kono
parents:
diff changeset
1941 }
kono
parents:
diff changeset
1942 }
kono
parents:
diff changeset
1943 FOR_EACH_INSN_INFO_DEF (mention, insn_info)
kono
parents:
diff changeset
1944 {
kono
parents:
diff changeset
1945 /* We use DF_REF_REAL_REG here to get inside any subregs. */
kono
parents:
diff changeset
1946 machine_mode mode = GET_MODE (DF_REF_REAL_REG (mention));
kono
parents:
diff changeset
1947
kono
parents:
diff changeset
1948 /* If we're loading up a hard vector register for a call,
kono
parents:
diff changeset
1949 it looks like (set (reg:V4SI 9 9) (...)). The df
kono
parents:
diff changeset
1950 analysis creates two mentions for GPR9 and GPR10, both
kono
parents:
diff changeset
1951 DImode. So relying on the mode from the mentions
kono
parents:
diff changeset
1952 isn't sufficient to ensure we union the call into the
kono
parents:
diff changeset
1953 web with the parameter setup code. */
kono
parents:
diff changeset
1954 if (mode == DImode && GET_CODE (insn) == SET
kono
parents:
diff changeset
1955 && ALTIVEC_OR_VSX_VECTOR_MODE (GET_MODE (SET_DEST (insn))))
kono
parents:
diff changeset
1956 mode = GET_MODE (SET_DEST (insn));
kono
parents:
diff changeset
1957
kono
parents:
diff changeset
1958 if (ALTIVEC_OR_VSX_VECTOR_MODE (mode) || mode == TImode)
kono
parents:
diff changeset
1959 {
kono
parents:
diff changeset
1960 insn_entry[uid].is_relevant = 1;
kono
parents:
diff changeset
1961 if (mode == TImode || mode == V1TImode
kono
parents:
diff changeset
1962 || FLOAT128_VECTOR_P (mode))
kono
parents:
diff changeset
1963 insn_entry[uid].is_128_int = 1;
kono
parents:
diff changeset
1964 if (DF_REF_INSN_INFO (mention))
kono
parents:
diff changeset
1965 insn_entry[uid].contains_subreg
kono
parents:
diff changeset
1966 = !rtx_equal_p (DF_REF_REG (mention),
kono
parents:
diff changeset
1967 DF_REF_REAL_REG (mention));
kono
parents:
diff changeset
1968 /* REG_FUNCTION_VALUE_P is not valid for subregs. */
kono
parents:
diff changeset
1969 else if (REG_FUNCTION_VALUE_P (DF_REF_REG (mention)))
kono
parents:
diff changeset
1970 insn_entry[uid].is_live_out = 1;
kono
parents:
diff changeset
1971 union_uses (insn_entry, insn, mention);
kono
parents:
diff changeset
1972 }
kono
parents:
diff changeset
1973 }
kono
parents:
diff changeset
1974
kono
parents:
diff changeset
1975 if (insn_entry[uid].is_relevant)
kono
parents:
diff changeset
1976 {
kono
parents:
diff changeset
1977 /* Determine if this is a load or store. */
kono
parents:
diff changeset
1978 insn_entry[uid].is_load = insn_is_load_p (insn);
kono
parents:
diff changeset
1979 insn_entry[uid].is_store = insn_is_store_p (insn);
kono
parents:
diff changeset
1980
kono
parents:
diff changeset
1981 /* Determine if this is a doubleword swap. If not,
kono
parents:
diff changeset
1982 determine whether it can legally be swapped. */
kono
parents:
diff changeset
1983 if (insn_is_swap_p (insn))
kono
parents:
diff changeset
1984 insn_entry[uid].is_swap = 1;
kono
parents:
diff changeset
1985 else
kono
parents:
diff changeset
1986 {
kono
parents:
diff changeset
1987 unsigned int special = SH_NONE;
kono
parents:
diff changeset
1988 insn_entry[uid].is_swappable
kono
parents:
diff changeset
1989 = insn_is_swappable_p (insn_entry, insn, &special);
kono
parents:
diff changeset
1990 if (special != SH_NONE && insn_entry[uid].contains_subreg)
kono
parents:
diff changeset
1991 insn_entry[uid].is_swappable = 0;
kono
parents:
diff changeset
1992 else if (special != SH_NONE)
kono
parents:
diff changeset
1993 insn_entry[uid].special_handling = special;
kono
parents:
diff changeset
1994 else if (insn_entry[uid].contains_subreg)
kono
parents:
diff changeset
1995 insn_entry[uid].special_handling = SH_SUBREG;
kono
parents:
diff changeset
1996 }
kono
parents:
diff changeset
1997 }
kono
parents:
diff changeset
1998 }
kono
parents:
diff changeset
1999 }
kono
parents:
diff changeset
2000
kono
parents:
diff changeset
2001 if (dump_file)
kono
parents:
diff changeset
2002 {
kono
parents:
diff changeset
2003 fprintf (dump_file, "\nSwap insn entry table when first built\n");
kono
parents:
diff changeset
2004 dump_swap_insn_table (insn_entry);
kono
parents:
diff changeset
2005 }
kono
parents:
diff changeset
2006
kono
parents:
diff changeset
2007 /* Record unoptimizable webs. */
kono
parents:
diff changeset
2008 unsigned e = get_max_uid (), i;
kono
parents:
diff changeset
2009 for (i = 0; i < e; ++i)
kono
parents:
diff changeset
2010 {
kono
parents:
diff changeset
2011 if (!insn_entry[i].is_relevant)
kono
parents:
diff changeset
2012 continue;
kono
parents:
diff changeset
2013
kono
parents:
diff changeset
2014 swap_web_entry *root
kono
parents:
diff changeset
2015 = (swap_web_entry*)(&insn_entry[i])->unionfind_root ();
kono
parents:
diff changeset
2016
kono
parents:
diff changeset
2017 if (insn_entry[i].is_live_in || insn_entry[i].is_live_out
kono
parents:
diff changeset
2018 || (insn_entry[i].contains_subreg
kono
parents:
diff changeset
2019 && insn_entry[i].special_handling != SH_SUBREG)
kono
parents:
diff changeset
2020 || insn_entry[i].is_128_int || insn_entry[i].is_call
kono
parents:
diff changeset
2021 || !(insn_entry[i].is_swappable || insn_entry[i].is_swap))
kono
parents:
diff changeset
2022 root->web_not_optimizable = 1;
kono
parents:
diff changeset
2023
kono
parents:
diff changeset
2024 /* If we have loads or stores that aren't permuting then the
kono
parents:
diff changeset
2025 optimization isn't appropriate. */
kono
parents:
diff changeset
2026 else if ((insn_entry[i].is_load || insn_entry[i].is_store)
kono
parents:
diff changeset
2027 && !insn_entry[i].is_swap && !insn_entry[i].is_swappable)
kono
parents:
diff changeset
2028 root->web_not_optimizable = 1;
kono
parents:
diff changeset
2029
kono
parents:
diff changeset
2030 /* If we have permuting loads or stores that are not accompanied
kono
parents:
diff changeset
2031 by a register swap, the optimization isn't appropriate. */
kono
parents:
diff changeset
2032 else if (insn_entry[i].is_load && insn_entry[i].is_swap)
kono
parents:
diff changeset
2033 {
kono
parents:
diff changeset
2034 rtx insn = insn_entry[i].insn;
kono
parents:
diff changeset
2035 struct df_insn_info *insn_info = DF_INSN_INFO_GET (insn);
kono
parents:
diff changeset
2036 df_ref def;
kono
parents:
diff changeset
2037
kono
parents:
diff changeset
2038 FOR_EACH_INSN_INFO_DEF (def, insn_info)
kono
parents:
diff changeset
2039 {
kono
parents:
diff changeset
2040 struct df_link *link = DF_REF_CHAIN (def);
kono
parents:
diff changeset
2041
kono
parents:
diff changeset
2042 if (!chain_contains_only_swaps (insn_entry, link, FOR_LOADS))
kono
parents:
diff changeset
2043 {
kono
parents:
diff changeset
2044 root->web_not_optimizable = 1;
kono
parents:
diff changeset
2045 break;
kono
parents:
diff changeset
2046 }
kono
parents:
diff changeset
2047 }
kono
parents:
diff changeset
2048 }
kono
parents:
diff changeset
2049 else if (insn_entry[i].is_store && insn_entry[i].is_swap)
kono
parents:
diff changeset
2050 {
kono
parents:
diff changeset
2051 rtx insn = insn_entry[i].insn;
kono
parents:
diff changeset
2052 struct df_insn_info *insn_info = DF_INSN_INFO_GET (insn);
kono
parents:
diff changeset
2053 df_ref use;
kono
parents:
diff changeset
2054
kono
parents:
diff changeset
2055 FOR_EACH_INSN_INFO_USE (use, insn_info)
kono
parents:
diff changeset
2056 {
kono
parents:
diff changeset
2057 struct df_link *link = DF_REF_CHAIN (use);
kono
parents:
diff changeset
2058
kono
parents:
diff changeset
2059 if (!chain_contains_only_swaps (insn_entry, link, FOR_STORES))
kono
parents:
diff changeset
2060 {
kono
parents:
diff changeset
2061 root->web_not_optimizable = 1;
kono
parents:
diff changeset
2062 break;
kono
parents:
diff changeset
2063 }
kono
parents:
diff changeset
2064 }
kono
parents:
diff changeset
2065 }
kono
parents:
diff changeset
2066 }
kono
parents:
diff changeset
2067
kono
parents:
diff changeset
2068 if (dump_file)
kono
parents:
diff changeset
2069 {
kono
parents:
diff changeset
2070 fprintf (dump_file, "\nSwap insn entry table after web analysis\n");
kono
parents:
diff changeset
2071 dump_swap_insn_table (insn_entry);
kono
parents:
diff changeset
2072 }
kono
parents:
diff changeset
2073
kono
parents:
diff changeset
2074 /* For each load and store in an optimizable web (which implies
kono
parents:
diff changeset
2075 the loads and stores are permuting), find the associated
kono
parents:
diff changeset
2076 register swaps and mark them for removal. Due to various
kono
parents:
diff changeset
2077 optimizations we may mark the same swap more than once. Also
kono
parents:
diff changeset
2078 perform special handling for swappable insns that require it. */
kono
parents:
diff changeset
2079 for (i = 0; i < e; ++i)
kono
parents:
diff changeset
2080 if ((insn_entry[i].is_load || insn_entry[i].is_store)
kono
parents:
diff changeset
2081 && insn_entry[i].is_swap)
kono
parents:
diff changeset
2082 {
kono
parents:
diff changeset
2083 swap_web_entry* root_entry
kono
parents:
diff changeset
2084 = (swap_web_entry*)((&insn_entry[i])->unionfind_root ());
kono
parents:
diff changeset
2085 if (!root_entry->web_not_optimizable)
kono
parents:
diff changeset
2086 mark_swaps_for_removal (insn_entry, i);
kono
parents:
diff changeset
2087 }
kono
parents:
diff changeset
2088 else if (insn_entry[i].is_swappable && insn_entry[i].special_handling)
kono
parents:
diff changeset
2089 {
kono
parents:
diff changeset
2090 swap_web_entry* root_entry
kono
parents:
diff changeset
2091 = (swap_web_entry*)((&insn_entry[i])->unionfind_root ());
kono
parents:
diff changeset
2092 if (!root_entry->web_not_optimizable)
kono
parents:
diff changeset
2093 handle_special_swappables (insn_entry, i);
kono
parents:
diff changeset
2094 }
kono
parents:
diff changeset
2095
kono
parents:
diff changeset
2096 /* Now delete the swaps marked for removal. */
kono
parents:
diff changeset
2097 for (i = 0; i < e; ++i)
kono
parents:
diff changeset
2098 if (insn_entry[i].will_delete)
kono
parents:
diff changeset
2099 replace_swap_with_copy (insn_entry, i);
kono
parents:
diff changeset
2100
kono
parents:
diff changeset
2101 /* Clean up. */
kono
parents:
diff changeset
2102 free (insn_entry);
kono
parents:
diff changeset
2103
kono
parents:
diff changeset
2104 /* Use additional pass over rtl to replace swap(load(vector constant))
kono
parents:
diff changeset
2105 with load(swapped vector constant). */
kono
parents:
diff changeset
2106 swap_web_entry *pass2_insn_entry;
kono
parents:
diff changeset
2107 pass2_insn_entry = XCNEWVEC (swap_web_entry, get_max_uid ());
kono
parents:
diff changeset
2108
kono
parents:
diff changeset
2109 /* Walk the insns to gather basic data. */
kono
parents:
diff changeset
2110 FOR_ALL_BB_FN (bb, fun)
kono
parents:
diff changeset
2111 FOR_BB_INSNS_SAFE (bb, insn, curr_insn)
kono
parents:
diff changeset
2112 {
kono
parents:
diff changeset
2113 unsigned int uid = INSN_UID (insn);
kono
parents:
diff changeset
2114 if (NONDEBUG_INSN_P (insn))
kono
parents:
diff changeset
2115 {
kono
parents:
diff changeset
2116 pass2_insn_entry[uid].insn = insn;
kono
parents:
diff changeset
2117
kono
parents:
diff changeset
2118 pass2_insn_entry[uid].is_relevant = 1;
kono
parents:
diff changeset
2119 pass2_insn_entry[uid].is_load = insn_is_load_p (insn);
kono
parents:
diff changeset
2120 pass2_insn_entry[uid].is_store = insn_is_store_p (insn);
kono
parents:
diff changeset
2121
kono
parents:
diff changeset
2122 /* Determine if this is a doubleword swap. If not,
kono
parents:
diff changeset
2123 determine whether it can legally be swapped. */
kono
parents:
diff changeset
2124 if (insn_is_swap_p (insn))
kono
parents:
diff changeset
2125 pass2_insn_entry[uid].is_swap = 1;
kono
parents:
diff changeset
2126 }
kono
parents:
diff changeset
2127 }
kono
parents:
diff changeset
2128
kono
parents:
diff changeset
2129 e = get_max_uid ();
kono
parents:
diff changeset
2130 for (unsigned i = 0; i < e; ++i)
kono
parents:
diff changeset
2131 if (pass2_insn_entry[i].is_swap && !pass2_insn_entry[i].is_load
kono
parents:
diff changeset
2132 && !pass2_insn_entry[i].is_store)
kono
parents:
diff changeset
2133 {
kono
parents:
diff changeset
2134 insn = pass2_insn_entry[i].insn;
kono
parents:
diff changeset
2135 if (const_load_sequence_p (pass2_insn_entry, insn))
kono
parents:
diff changeset
2136 replace_swapped_load_constant (pass2_insn_entry, insn);
kono
parents:
diff changeset
2137 }
kono
parents:
diff changeset
2138
kono
parents:
diff changeset
2139 /* Clean up. */
kono
parents:
diff changeset
2140 free (pass2_insn_entry);
kono
parents:
diff changeset
2141 return 0;
kono
parents:
diff changeset
2142 }
kono
parents:
diff changeset
2143
kono
parents:
diff changeset
2144 const pass_data pass_data_analyze_swaps =
kono
parents:
diff changeset
2145 {
kono
parents:
diff changeset
2146 RTL_PASS, /* type */
kono
parents:
diff changeset
2147 "swaps", /* name */
kono
parents:
diff changeset
2148 OPTGROUP_NONE, /* optinfo_flags */
kono
parents:
diff changeset
2149 TV_NONE, /* tv_id */
kono
parents:
diff changeset
2150 0, /* properties_required */
kono
parents:
diff changeset
2151 0, /* properties_provided */
kono
parents:
diff changeset
2152 0, /* properties_destroyed */
kono
parents:
diff changeset
2153 0, /* todo_flags_start */
kono
parents:
diff changeset
2154 TODO_df_finish, /* todo_flags_finish */
kono
parents:
diff changeset
2155 };
kono
parents:
diff changeset
2156
kono
parents:
diff changeset
2157 class pass_analyze_swaps : public rtl_opt_pass
kono
parents:
diff changeset
2158 {
kono
parents:
diff changeset
2159 public:
kono
parents:
diff changeset
2160 pass_analyze_swaps(gcc::context *ctxt)
kono
parents:
diff changeset
2161 : rtl_opt_pass(pass_data_analyze_swaps, ctxt)
kono
parents:
diff changeset
2162 {}
kono
parents:
diff changeset
2163
kono
parents:
diff changeset
2164 /* opt_pass methods: */
kono
parents:
diff changeset
2165 virtual bool gate (function *)
kono
parents:
diff changeset
2166 {
kono
parents:
diff changeset
2167 return (optimize > 0 && !BYTES_BIG_ENDIAN && TARGET_VSX
kono
parents:
diff changeset
2168 && !TARGET_P9_VECTOR && rs6000_optimize_swaps);
kono
parents:
diff changeset
2169 }
kono
parents:
diff changeset
2170
kono
parents:
diff changeset
2171 virtual unsigned int execute (function *fun)
kono
parents:
diff changeset
2172 {
kono
parents:
diff changeset
2173 return rs6000_analyze_swaps (fun);
kono
parents:
diff changeset
2174 }
kono
parents:
diff changeset
2175
kono
parents:
diff changeset
2176 opt_pass *clone ()
kono
parents:
diff changeset
2177 {
kono
parents:
diff changeset
2178 return new pass_analyze_swaps (m_ctxt);
kono
parents:
diff changeset
2179 }
kono
parents:
diff changeset
2180
kono
parents:
diff changeset
2181 }; // class pass_analyze_swaps
kono
parents:
diff changeset
2182
kono
parents:
diff changeset
2183 rtl_opt_pass *
kono
parents:
diff changeset
2184 make_pass_analyze_swaps (gcc::context *ctxt)
kono
parents:
diff changeset
2185 {
kono
parents:
diff changeset
2186 return new pass_analyze_swaps (ctxt);
kono
parents:
diff changeset
2187 }
kono
parents:
diff changeset
2188