Branch data Line data Source code
1 : : /* Copyright (C) 1988-2025 Free Software Foundation, Inc.
2 : :
3 : : This file is part of GCC.
4 : :
5 : : GCC is free software; you can redistribute it and/or modify
6 : : it under the terms of the GNU General Public License as published by
7 : : the Free Software Foundation; either version 3, or (at your option)
8 : : any later version.
9 : :
10 : : GCC is distributed in the hope that it will be useful,
11 : : but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : : GNU General Public License for more details.
14 : :
15 : : You should have received a copy of the GNU General Public License
16 : : along with GCC; see the file COPYING3. If not see
17 : : <http://www.gnu.org/licenses/>. */
18 : :
19 : : #define IN_TARGET_CODE 1
20 : :
21 : : #include "config.h"
22 : : #include "system.h"
23 : : #include "coretypes.h"
24 : : #include "backend.h"
25 : : #include "rtl.h"
26 : : #include "tree.h"
27 : : #include "memmodel.h"
28 : : #include "gimple.h"
29 : : #include "cfghooks.h"
30 : : #include "cfgloop.h"
31 : : #include "df.h"
32 : : #include "tm_p.h"
33 : : #include "stringpool.h"
34 : : #include "expmed.h"
35 : : #include "optabs.h"
36 : : #include "regs.h"
37 : : #include "emit-rtl.h"
38 : : #include "recog.h"
39 : : #include "cgraph.h"
40 : : #include "diagnostic.h"
41 : : #include "cfgbuild.h"
42 : : #include "alias.h"
43 : : #include "fold-const.h"
44 : : #include "attribs.h"
45 : : #include "calls.h"
46 : : #include "stor-layout.h"
47 : : #include "varasm.h"
48 : : #include "output.h"
49 : : #include "insn-attr.h"
50 : : #include "flags.h"
51 : : #include "except.h"
52 : : #include "explow.h"
53 : : #include "expr.h"
54 : : #include "cfgrtl.h"
55 : : #include "common/common-target.h"
56 : : #include "langhooks.h"
57 : : #include "reload.h"
58 : : #include "gimplify.h"
59 : : #include "dwarf2.h"
60 : : #include "tm-constrs.h"
61 : : #include "cselib.h"
62 : : #include "sched-int.h"
63 : : #include "opts.h"
64 : : #include "tree-pass.h"
65 : : #include "context.h"
66 : : #include "pass_manager.h"
67 : : #include "target-globals.h"
68 : : #include "gimple-iterator.h"
69 : : #include "shrink-wrap.h"
70 : : #include "builtins.h"
71 : : #include "rtl-iter.h"
72 : : #include "tree-iterator.h"
73 : : #include "dbgcnt.h"
74 : : #include "case-cfn-macros.h"
75 : : #include "dojump.h"
76 : : #include "fold-const-call.h"
77 : : #include "tree-vrp.h"
78 : : #include "tree-ssanames.h"
79 : : #include "selftest.h"
80 : : #include "selftest-rtl.h"
81 : : #include "print-rtl.h"
82 : : #include "intl.h"
83 : : #include "ifcvt.h"
84 : : #include "symbol-summary.h"
85 : : #include "sreal.h"
86 : : #include "ipa-cp.h"
87 : : #include "ipa-prop.h"
88 : : #include "ipa-fnsummary.h"
89 : : #include "wide-int-bitmask.h"
90 : : #include "tree-vector-builder.h"
91 : : #include "debug.h"
92 : : #include "dwarf2out.h"
93 : : #include "i386-builtins.h"
94 : : #include "i386-features.h"
95 : : #include "i386-expand.h"
96 : :
97 : : const char * const xlogue_layout::STUB_BASE_NAMES[XLOGUE_STUB_COUNT] = {
98 : : "savms64",
99 : : "resms64",
100 : : "resms64x",
101 : : "savms64f",
102 : : "resms64f",
103 : : "resms64fx"
104 : : };
105 : :
106 : : const unsigned xlogue_layout::REG_ORDER[xlogue_layout::MAX_REGS] = {
107 : : /* The below offset values are where each register is stored for the layout
108 : : relative to incoming stack pointer. The value of each m_regs[].offset will
109 : : be relative to the incoming base pointer (rax or rsi) used by the stub.
110 : :
111 : : s_instances: 0 1 2 3
112 : : Offset: realigned or aligned + 8
113 : : Register aligned aligned + 8 aligned w/HFP w/HFP */
114 : : XMM15_REG, /* 0x10 0x18 0x10 0x18 */
115 : : XMM14_REG, /* 0x20 0x28 0x20 0x28 */
116 : : XMM13_REG, /* 0x30 0x38 0x30 0x38 */
117 : : XMM12_REG, /* 0x40 0x48 0x40 0x48 */
118 : : XMM11_REG, /* 0x50 0x58 0x50 0x58 */
119 : : XMM10_REG, /* 0x60 0x68 0x60 0x68 */
120 : : XMM9_REG, /* 0x70 0x78 0x70 0x78 */
121 : : XMM8_REG, /* 0x80 0x88 0x80 0x88 */
122 : : XMM7_REG, /* 0x90 0x98 0x90 0x98 */
123 : : XMM6_REG, /* 0xa0 0xa8 0xa0 0xa8 */
124 : : SI_REG, /* 0xa8 0xb0 0xa8 0xb0 */
125 : : DI_REG, /* 0xb0 0xb8 0xb0 0xb8 */
126 : : BX_REG, /* 0xb8 0xc0 0xb8 0xc0 */
127 : : BP_REG, /* 0xc0 0xc8 N/A N/A */
128 : : R12_REG, /* 0xc8 0xd0 0xc0 0xc8 */
129 : : R13_REG, /* 0xd0 0xd8 0xc8 0xd0 */
130 : : R14_REG, /* 0xd8 0xe0 0xd0 0xd8 */
131 : : R15_REG, /* 0xe0 0xe8 0xd8 0xe0 */
132 : : };
133 : :
134 : : /* Instantiate static const values. */
135 : : const HOST_WIDE_INT xlogue_layout::STUB_INDEX_OFFSET;
136 : : const unsigned xlogue_layout::MIN_REGS;
137 : : const unsigned xlogue_layout::MAX_REGS;
138 : : const unsigned xlogue_layout::MAX_EXTRA_REGS;
139 : : const unsigned xlogue_layout::VARIANT_COUNT;
140 : : const unsigned xlogue_layout::STUB_NAME_MAX_LEN;
141 : :
142 : : /* Initialize xlogue_layout::s_stub_names to zero. */
143 : : char xlogue_layout::s_stub_names[2][XLOGUE_STUB_COUNT][VARIANT_COUNT]
144 : : [STUB_NAME_MAX_LEN];
145 : :
146 : : /* Instantiates all xlogue_layout instances. */
147 : : const xlogue_layout xlogue_layout::s_instances[XLOGUE_SET_COUNT] = {
148 : : xlogue_layout (0, false),
149 : : xlogue_layout (8, false),
150 : : xlogue_layout (0, true),
151 : : xlogue_layout (8, true)
152 : : };
153 : :
154 : : /* Return an appropriate const instance of xlogue_layout based upon values
155 : : in cfun->machine and crtl. */
156 : : const class xlogue_layout &
157 : 49891 : xlogue_layout::get_instance ()
158 : : {
159 : 49891 : enum xlogue_stub_sets stub_set;
160 : 49891 : bool aligned_plus_8 = cfun->machine->call_ms2sysv_pad_in;
161 : :
162 : 49891 : if (stack_realign_fp)
163 : : stub_set = XLOGUE_SET_HFP_ALIGNED_OR_REALIGN;
164 : 40910 : else if (frame_pointer_needed)
165 : 25246 : stub_set = aligned_plus_8
166 : 31552 : ? XLOGUE_SET_HFP_ALIGNED_PLUS_8
167 : : : XLOGUE_SET_HFP_ALIGNED_OR_REALIGN;
168 : : else
169 : 9358 : stub_set = aligned_plus_8 ? XLOGUE_SET_ALIGNED_PLUS_8 : XLOGUE_SET_ALIGNED;
170 : :
171 : 49891 : return s_instances[stub_set];
172 : : }
173 : :
174 : : /* Determine how many clobbered registers can be saved by the stub.
175 : : Returns the count of registers the stub will save and restore. */
176 : : unsigned
177 : 35225 : xlogue_layout::count_stub_managed_regs ()
178 : : {
179 : 35225 : bool hfp = frame_pointer_needed || stack_realign_fp;
180 : 35225 : unsigned i, count;
181 : 35225 : unsigned regno;
182 : :
183 : 94890 : for (count = i = MIN_REGS; i < MAX_REGS; ++i)
184 : : {
185 : 93670 : regno = REG_ORDER[i];
186 : 93670 : if (regno == BP_REG && hfp)
187 : 18200 : continue;
188 : 75470 : if (!ix86_save_reg (regno, false, false))
189 : : break;
190 : 41465 : ++count;
191 : : }
192 : 35225 : return count;
193 : : }
194 : :
195 : : /* Determine if register REGNO is a stub managed register given the
196 : : total COUNT of stub managed registers. */
197 : : bool
198 : 2650688 : xlogue_layout::is_stub_managed_reg (unsigned regno, unsigned count)
199 : : {
200 : 2650688 : bool hfp = frame_pointer_needed || stack_realign_fp;
201 : 2650688 : unsigned i;
202 : :
203 : 34587805 : for (i = 0; i < count; ++i)
204 : : {
205 : 32436986 : gcc_assert (i < MAX_REGS);
206 : 32436986 : if (REG_ORDER[i] == BP_REG && hfp)
207 : 522627 : ++count;
208 : 31914359 : else if (REG_ORDER[i] == regno)
209 : : return true;
210 : : }
211 : : return false;
212 : : }
213 : :
214 : : /* Constructor for xlogue_layout. */
215 : 1138480 : xlogue_layout::xlogue_layout (HOST_WIDE_INT stack_align_off_in, bool hfp)
216 : 1138480 : : m_hfp (hfp) , m_nregs (hfp ? 17 : 18),
217 : 1138480 : m_stack_align_off_in (stack_align_off_in)
218 : : {
219 : 1138480 : HOST_WIDE_INT offset = stack_align_off_in;
220 : 1138480 : unsigned i, j;
221 : :
222 : 21631120 : for (i = j = 0; i < MAX_REGS; ++i)
223 : : {
224 : 20492640 : unsigned regno = REG_ORDER[i];
225 : :
226 : 20492640 : if (regno == BP_REG && hfp)
227 : 569240 : continue;
228 : 19923400 : if (SSE_REGNO_P (regno))
229 : : {
230 : 11384800 : offset += 16;
231 : : /* Verify that SSE regs are always aligned. */
232 : 11384800 : gcc_assert (!((stack_align_off_in + offset) & 15));
233 : : }
234 : : else
235 : 8538600 : offset += 8;
236 : :
237 : 19923400 : m_regs[j].regno = regno;
238 : 19923400 : m_regs[j++].offset = offset - STUB_INDEX_OFFSET;
239 : : }
240 : 1138480 : gcc_assert (j == m_nregs);
241 : 1138480 : }
242 : :
243 : : const char *
244 : 14666 : xlogue_layout::get_stub_name (enum xlogue_stub stub,
245 : : unsigned n_extra_regs)
246 : : {
247 : 14666 : const int have_avx = TARGET_AVX;
248 : 14666 : char *name = s_stub_names[!!have_avx][stub][n_extra_regs];
249 : :
250 : : /* Lazy init */
251 : 14666 : if (!*name)
252 : : {
253 : 362 : int res = snprintf (name, STUB_NAME_MAX_LEN, "__%s_%s_%u",
254 : : (have_avx ? "avx" : "sse"),
255 : 181 : STUB_BASE_NAMES[stub],
256 : : MIN_REGS + n_extra_regs);
257 : 181 : gcc_checking_assert (res < (int)STUB_NAME_MAX_LEN);
258 : : }
259 : :
260 : 14666 : return name;
261 : : }
262 : :
263 : : /* Return rtx of a symbol ref for the entry point (based upon
264 : : cfun->machine->call_ms2sysv_extra_regs) of the specified stub. */
265 : : rtx
266 : 14666 : xlogue_layout::get_stub_rtx (enum xlogue_stub stub)
267 : : {
268 : 14666 : const unsigned n_extra_regs = cfun->machine->call_ms2sysv_extra_regs;
269 : 14666 : gcc_checking_assert (n_extra_regs <= MAX_EXTRA_REGS);
270 : 14666 : gcc_assert (stub < XLOGUE_STUB_COUNT);
271 : 14666 : gcc_assert (crtl->stack_realign_finalized);
272 : :
273 : 14666 : return gen_rtx_SYMBOL_REF (Pmode, get_stub_name (stub, n_extra_regs));
274 : : }
275 : :
276 : : unsigned scalar_chain::max_id = 0;
277 : :
278 : : namespace {
279 : :
280 : : /* Initialize new chain. */
281 : :
282 : 6501309 : scalar_chain::scalar_chain (enum machine_mode smode_, enum machine_mode vmode_)
283 : : {
284 : 6501309 : smode = smode_;
285 : 6501309 : vmode = vmode_;
286 : :
287 : 6501309 : chain_id = ++max_id;
288 : :
289 : 6501309 : if (dump_file)
290 : 136 : fprintf (dump_file, "Created a new instruction chain #%d\n", chain_id);
291 : :
292 : 6501309 : bitmap_obstack_initialize (NULL);
293 : 6501309 : insns = BITMAP_ALLOC (NULL);
294 : 6501309 : defs = BITMAP_ALLOC (NULL);
295 : 6501309 : defs_conv = BITMAP_ALLOC (NULL);
296 : 6501309 : insns_conv = BITMAP_ALLOC (NULL);
297 : 6501309 : queue = NULL;
298 : :
299 : 6501309 : cost_sse_integer = 0;
300 : 6501309 : weighted_cost_sse_integer = 0 ;
301 : 6501309 : max_visits = x86_stv_max_visits;
302 : 6501309 : }
303 : :
304 : : /* Free chain's data. */
305 : :
306 : 6501309 : scalar_chain::~scalar_chain ()
307 : : {
308 : 6501309 : BITMAP_FREE (insns);
309 : 6501309 : BITMAP_FREE (defs);
310 : 6501309 : BITMAP_FREE (defs_conv);
311 : 6501309 : BITMAP_FREE (insns_conv);
312 : 6501309 : bitmap_obstack_release (NULL);
313 : 6501309 : }
314 : :
315 : : /* Add instruction into chains' queue. */
316 : :
317 : : void
318 : 8084646 : scalar_chain::add_to_queue (unsigned insn_uid)
319 : : {
320 : 8084646 : if (!bitmap_set_bit (queue, insn_uid))
321 : : return;
322 : :
323 : 6238298 : if (dump_file)
324 : 141 : fprintf (dump_file, " Adding insn %d into chain's #%d queue\n",
325 : : insn_uid, chain_id);
326 : : }
327 : :
328 : : /* For DImode conversion, mark register defined by DEF as requiring
329 : : conversion. */
330 : :
331 : : void
332 : 9569359 : scalar_chain::mark_dual_mode_def (df_ref def)
333 : : {
334 : 9569359 : gcc_assert (DF_REF_REG_DEF_P (def));
335 : :
336 : : /* Record the def/insn pair so we can later efficiently iterate over
337 : : the defs to convert on insns not in the chain. */
338 : 9569359 : bool reg_new = bitmap_set_bit (defs_conv, DF_REF_REGNO (def));
339 : 9569359 : basic_block bb = BLOCK_FOR_INSN (DF_REF_INSN (def));
340 : 9569359 : profile_count entry_count = ENTRY_BLOCK_PTR_FOR_FN (cfun)->count;
341 : 9569359 : bool speed_p = optimize_bb_for_speed_p (bb);
342 : 9569359 : int cost = 0;
343 : :
344 : 9569359 : if (!bitmap_bit_p (insns, DF_REF_INSN_UID (def)))
345 : : {
346 : 2771975 : if (!bitmap_set_bit (insns_conv, DF_REF_INSN_UID (def))
347 : 2771975 : && !reg_new)
348 : 1400459 : return;
349 : :
350 : : /* Cost integer to sse moves. */
351 : 2523719 : if (speed_p)
352 : 2235205 : cost = COSTS_N_INSNS (ix86_cost->integer_to_sse) / 2;
353 : 288514 : else if (TARGET_64BIT || smode == SImode)
354 : : cost = COSTS_N_BYTES (4);
355 : : /* vmovd (4 bytes) + vpinsrd (6 bytes). */
356 : 18503 : else if (TARGET_SSE4_1)
357 : : cost = COSTS_N_BYTES (10);
358 : : /* movd (4 bytes) + movd (4 bytes) + unpckldq (4 bytes). */
359 : : else
360 : 8168900 : cost = COSTS_N_BYTES (12);
361 : : }
362 : : else
363 : : {
364 : 6797384 : if (!reg_new)
365 : : return;
366 : :
367 : : /* Cost sse to integer moves. */
368 : 5645181 : if (speed_p)
369 : 5087457 : cost = COSTS_N_INSNS (ix86_cost->sse_to_integer) / 2;
370 : 557724 : else if (TARGET_64BIT || smode == SImode)
371 : : cost = COSTS_N_BYTES (4);
372 : : /* vmovd (4 bytes) + vpextrd (6 bytes). */
373 : 2987 : else if (TARGET_SSE4_1)
374 : : cost = COSTS_N_BYTES (10);
375 : : /* movd (4 bytes) + psrlq (5 bytes) + movd (4 bytes). */
376 : : else
377 : 8168900 : cost = COSTS_N_BYTES (13);
378 : : }
379 : :
380 : 8168900 : if (speed_p)
381 : 7322662 : weighted_cost_sse_integer += bb->count.to_sreal_scale (entry_count) * cost;
382 : :
383 : 8168900 : cost_sse_integer += cost;
384 : :
385 : 8168900 : if (dump_file)
386 : 240 : fprintf (dump_file,
387 : : " Mark r%d def in insn %d as requiring both modes in chain #%d\n",
388 : 240 : DF_REF_REGNO (def), DF_REF_INSN_UID (def), chain_id);
389 : : }
390 : :
391 : : /* Check REF's chain to add new insns into a queue
392 : : and find registers requiring conversion. Return true if OK, false
393 : : if the analysis was aborted. */
394 : :
395 : : bool
396 : 17953318 : scalar_chain::analyze_register_chain (bitmap candidates, df_ref ref,
397 : : bitmap disallowed)
398 : : {
399 : 17953318 : df_link *chain;
400 : 17953318 : bool mark_def = false;
401 : :
402 : 17953318 : gcc_checking_assert (bitmap_bit_p (insns, DF_REF_INSN_UID (ref)));
403 : :
404 : 61457387 : for (chain = DF_REF_CHAIN (ref); chain; chain = chain->next)
405 : : {
406 : 43504586 : unsigned uid = DF_REF_INSN_UID (chain->ref);
407 : :
408 : 43504586 : if (!NONDEBUG_INSN_P (DF_REF_INSN (chain->ref)))
409 : 7618510 : continue;
410 : :
411 : 35886076 : if (--max_visits == 0)
412 : : return false;
413 : :
414 : 35885559 : if (!DF_REF_REG_MEM_P (chain->ref))
415 : : {
416 : 29986380 : if (bitmap_bit_p (insns, uid))
417 : 9450558 : continue;
418 : :
419 : 20535822 : if (bitmap_bit_p (candidates, uid))
420 : : {
421 : 8084646 : add_to_queue (uid);
422 : 8084646 : continue;
423 : : }
424 : :
425 : : /* If we run into parts of an aborted chain discovery abort. */
426 : 12451176 : if (bitmap_bit_p (disallowed, uid))
427 : : return false;
428 : : }
429 : :
430 : 18350355 : if (DF_REF_REG_DEF_P (chain->ref))
431 : : {
432 : 2771975 : if (dump_file)
433 : 125 : fprintf (dump_file, " r%d def in insn %d isn't convertible\n",
434 : : DF_REF_REGNO (chain->ref), uid);
435 : 2771975 : mark_dual_mode_def (chain->ref);
436 : : }
437 : : else
438 : : {
439 : 15578380 : if (dump_file)
440 : 524 : fprintf (dump_file, " r%d use in insn %d isn't convertible\n",
441 : : DF_REF_REGNO (chain->ref), uid);
442 : : mark_def = true;
443 : : }
444 : : }
445 : :
446 : 17952801 : if (mark_def)
447 : 6797384 : mark_dual_mode_def (ref);
448 : :
449 : : return true;
450 : : }
451 : :
452 : : /* Add instruction into a chain. Return true if OK, false if the search
453 : : was aborted. */
454 : :
455 : : bool
456 : 12739607 : scalar_chain::add_insn (bitmap candidates, unsigned int insn_uid,
457 : : bitmap disallowed)
458 : : {
459 : 12739607 : if (!bitmap_set_bit (insns, insn_uid))
460 : : return true;
461 : :
462 : 12739607 : if (dump_file)
463 : 277 : fprintf (dump_file, " Adding insn %d to chain #%d\n", insn_uid, chain_id);
464 : :
465 : 12739607 : rtx_insn *insn = DF_INSN_UID_GET (insn_uid)->insn;
466 : 12739607 : rtx def_set = single_set (insn);
467 : 12739607 : if (def_set && REG_P (SET_DEST (def_set))
468 : 22622157 : && !HARD_REGISTER_P (SET_DEST (def_set)))
469 : 9882542 : bitmap_set_bit (defs, REGNO (SET_DEST (def_set)));
470 : :
471 : : /* ??? The following is quadratic since analyze_register_chain
472 : : iterates over all refs to look for dual-mode regs. Instead this
473 : : should be done separately for all regs mentioned in the chain once. */
474 : 12739607 : df_ref ref;
475 : 26053120 : for (ref = DF_INSN_UID_DEFS (insn_uid); ref; ref = DF_REF_NEXT_LOC (ref))
476 : 13313963 : if (!HARD_REGISTER_P (DF_REF_REG (ref)))
477 : 9882542 : if (!analyze_register_chain (candidates, ref, disallowed))
478 : : return false;
479 : :
480 : : /* The operand(s) of VEC_SELECT don't need to be converted/convertible. */
481 : 12739157 : if (def_set && GET_CODE (SET_SRC (def_set)) == VEC_SELECT)
482 : : return true;
483 : :
484 : 27770282 : for (ref = DF_INSN_UID_USES (insn_uid); ref; ref = DF_REF_NEXT_LOC (ref))
485 : 15065749 : if (!DF_REF_REG_MEM_P (ref))
486 : 8070776 : if (!analyze_register_chain (candidates, ref, disallowed))
487 : : return false;
488 : :
489 : : return true;
490 : : }
491 : :
492 : : /* Build new chain starting from insn INSN_UID recursively
493 : : adding all dependent uses and definitions. Return true if OK, false
494 : : if the chain discovery was aborted. */
495 : :
496 : : bool
497 : 6501309 : scalar_chain::build (bitmap candidates, unsigned insn_uid, bitmap disallowed)
498 : : {
499 : 6501309 : queue = BITMAP_ALLOC (NULL);
500 : 6501309 : bitmap_set_bit (queue, insn_uid);
501 : :
502 : 6501309 : if (dump_file)
503 : 136 : fprintf (dump_file, "Building chain #%d...\n", chain_id);
504 : :
505 : 19240399 : while (!bitmap_empty_p (queue))
506 : : {
507 : 12739607 : insn_uid = bitmap_first_set_bit (queue);
508 : 12739607 : bitmap_clear_bit (queue, insn_uid);
509 : 12739607 : bitmap_clear_bit (candidates, insn_uid);
510 : 12739607 : if (!add_insn (candidates, insn_uid, disallowed))
511 : : {
512 : : /* If we aborted the search put sofar found insn on the set of
513 : : disallowed insns so that further searches reaching them also
514 : : abort and thus we abort the whole but yet undiscovered chain. */
515 : 517 : bitmap_ior_into (disallowed, insns);
516 : 517 : if (dump_file)
517 : 0 : fprintf (dump_file, "Aborted chain #%d discovery\n", chain_id);
518 : 517 : BITMAP_FREE (queue);
519 : 517 : return false;
520 : : }
521 : : }
522 : :
523 : 6500792 : if (dump_file)
524 : : {
525 : 136 : fprintf (dump_file, "Collected chain #%d...\n", chain_id);
526 : 136 : fprintf (dump_file, " insns: ");
527 : 136 : dump_bitmap (dump_file, insns);
528 : 136 : if (!bitmap_empty_p (defs_conv))
529 : : {
530 : 136 : bitmap_iterator bi;
531 : 136 : unsigned id;
532 : 136 : const char *comma = "";
533 : 136 : fprintf (dump_file, " defs to convert: ");
534 : 366 : EXECUTE_IF_SET_IN_BITMAP (defs_conv, 0, id, bi)
535 : : {
536 : 230 : fprintf (dump_file, "%sr%d", comma, id);
537 : 230 : comma = ", ";
538 : : }
539 : 136 : fprintf (dump_file, "\n");
540 : : }
541 : : }
542 : :
543 : 6500792 : BITMAP_FREE (queue);
544 : :
545 : 6500792 : return true;
546 : : }
547 : :
548 : : /* Return a cost of building a vector costant
549 : : instead of using a scalar one. */
550 : :
551 : : int
552 : 2686722 : general_scalar_chain::vector_const_cost (rtx exp, basic_block bb)
553 : : {
554 : 2686722 : gcc_assert (CONST_INT_P (exp));
555 : :
556 : 2686722 : if (standard_sse_constant_p (exp, vmode))
557 : 620642 : return ix86_cost->sse_op;
558 : 2066080 : if (optimize_bb_for_size_p (bb))
559 : : return COSTS_N_BYTES (8);
560 : : /* We have separate costs for SImode and DImode, use SImode costs
561 : : for smaller modes. */
562 : 2479888 : return COSTS_N_INSNS (ix86_cost->sse_load[smode == DImode ? 1 : 0]) / 2;
563 : : }
564 : :
565 : : /* Return true if it's cost profitable for chain conversion. */
566 : :
567 : : bool
568 : 6061377 : general_scalar_chain::compute_convert_gain ()
569 : : {
570 : 6061377 : bitmap_iterator bi;
571 : 6061377 : unsigned insn_uid;
572 : 6061377 : int gain = 0;
573 : 6061377 : sreal weighted_gain = 0;
574 : :
575 : 6061377 : if (dump_file)
576 : 136 : fprintf (dump_file, "Computing gain for chain #%d...\n", chain_id);
577 : :
578 : : /* SSE costs distinguish between SImode and DImode loads/stores, for
579 : : int costs factor in the number of GPRs involved. When supporting
580 : : smaller modes than SImode the int load/store costs need to be
581 : : adjusted as well. */
582 : 6061377 : unsigned sse_cost_idx = smode == DImode ? 1 : 0;
583 : 6061377 : int m = smode == DImode ? (TARGET_64BIT ? 1 : 2) : 1;
584 : :
585 : 17944727 : EXECUTE_IF_SET_IN_BITMAP (insns, 0, insn_uid, bi)
586 : : {
587 : 11883350 : rtx_insn *insn = DF_INSN_UID_GET (insn_uid)->insn;
588 : 11883350 : rtx def_set = single_set (insn);
589 : 11883350 : rtx src = SET_SRC (def_set);
590 : 11883350 : rtx dst = SET_DEST (def_set);
591 : 11883350 : basic_block bb = BLOCK_FOR_INSN (insn);
592 : 11883350 : int igain = 0;
593 : 11883350 : profile_count entry_count = ENTRY_BLOCK_PTR_FOR_FN (cfun)->count;
594 : 11883350 : bool speed_p = optimize_bb_for_speed_p (bb);
595 : 11883350 : sreal bb_freq = bb->count.to_sreal_scale (entry_count);
596 : :
597 : 11883350 : if (REG_P (src) && REG_P (dst))
598 : : {
599 : 965711 : if (!speed_p)
600 : : /* reg-reg move is 2 bytes, while SSE 3. */
601 : 212247 : igain += COSTS_N_BYTES (2 * m - 3);
602 : : else
603 : : /* Move costs are normalized to reg-reg move having cost 2. */
604 : 753464 : igain += COSTS_N_INSNS (2 * m - ix86_cost->xmm_move) / 2;
605 : : }
606 : 10917639 : else if (REG_P (src) && MEM_P (dst))
607 : : {
608 : 2325802 : if (!speed_p)
609 : : /* Integer load/store is 3+ bytes and SSE 4+. */
610 : 183722 : igain += COSTS_N_BYTES (3 * m - 4);
611 : : else
612 : 2142080 : igain
613 : 2142080 : += COSTS_N_INSNS (m * ix86_cost->int_store[2]
614 : : - ix86_cost->sse_store[sse_cost_idx]) / 2;
615 : : }
616 : 8591837 : else if (MEM_P (src) && REG_P (dst))
617 : : {
618 : 3932420 : if (!speed_p)
619 : 359812 : igain += COSTS_N_BYTES (3 * m - 4);
620 : : else
621 : 3572608 : igain += COSTS_N_INSNS (m * ix86_cost->int_load[2]
622 : : - ix86_cost->sse_load[sse_cost_idx]) / 2;
623 : : }
624 : : else
625 : : {
626 : : /* For operations on memory operands, include the overhead
627 : : of explicit load and store instructions. */
628 : 4659417 : if (MEM_P (dst))
629 : : {
630 : 65250 : if (!speed_p)
631 : : /* ??? This probably should account size difference
632 : : of SSE and integer load rather than full SSE load. */
633 : : igain -= COSTS_N_BYTES (8);
634 : : else
635 : : {
636 : 55850 : int cost = (m * (ix86_cost->int_load[2]
637 : 55850 : + ix86_cost->int_store[2])
638 : 55850 : - (ix86_cost->sse_load[sse_cost_idx] +
639 : 55850 : ix86_cost->sse_store[sse_cost_idx]));
640 : 55850 : igain += COSTS_N_INSNS (cost) / 2;
641 : : }
642 : : }
643 : :
644 : 4659417 : switch (GET_CODE (src))
645 : : {
646 : 483349 : case ASHIFT:
647 : 483349 : case ASHIFTRT:
648 : 483349 : case LSHIFTRT:
649 : 483349 : if (m == 2)
650 : : {
651 : 16981 : if (INTVAL (XEXP (src, 1)) >= 32)
652 : 11563 : igain += ix86_cost->add;
653 : : /* Gain for extend highpart case. */
654 : 5418 : else if (GET_CODE (XEXP (src, 0)) == ASHIFT)
655 : 0 : igain += ix86_cost->shift_const - ix86_cost->sse_op;
656 : : else
657 : 5418 : igain += ix86_cost->shift_const;
658 : : }
659 : :
660 : 483349 : igain += ix86_cost->shift_const - ix86_cost->sse_op;
661 : :
662 : 483349 : if (CONST_INT_P (XEXP (src, 0)))
663 : 0 : igain -= vector_const_cost (XEXP (src, 0), bb);
664 : : break;
665 : :
666 : 3790 : case ROTATE:
667 : 3790 : case ROTATERT:
668 : 3790 : igain += m * ix86_cost->shift_const;
669 : 3790 : if (TARGET_AVX512VL)
670 : 192 : igain -= ix86_cost->sse_op;
671 : 3598 : else if (smode == DImode)
672 : : {
673 : 604 : int bits = INTVAL (XEXP (src, 1));
674 : 604 : if ((bits & 0x0f) == 0)
675 : 122 : igain -= ix86_cost->sse_op;
676 : 482 : else if ((bits & 0x07) == 0)
677 : 27 : igain -= 2 * ix86_cost->sse_op;
678 : : else
679 : 455 : igain -= 3 * ix86_cost->sse_op;
680 : : }
681 : 2994 : else if (INTVAL (XEXP (src, 1)) == 16)
682 : 239 : igain -= ix86_cost->sse_op;
683 : : else
684 : 2755 : igain -= 2 * ix86_cost->sse_op;
685 : : break;
686 : :
687 : 2864353 : case AND:
688 : 2864353 : case IOR:
689 : 2864353 : case XOR:
690 : 2864353 : case PLUS:
691 : 2864353 : case MINUS:
692 : 2864353 : igain += m * ix86_cost->add - ix86_cost->sse_op;
693 : : /* Additional gain for andnot for targets without BMI. */
694 : 2864353 : if (GET_CODE (XEXP (src, 0)) == NOT
695 : 3599 : && !TARGET_BMI)
696 : 3590 : igain += m * ix86_cost->add;
697 : :
698 : 2864353 : if (CONST_INT_P (XEXP (src, 0)))
699 : 0 : igain -= vector_const_cost (XEXP (src, 0), bb);
700 : 2864353 : if (CONST_INT_P (XEXP (src, 1)))
701 : 1709562 : igain -= vector_const_cost (XEXP (src, 1), bb);
702 : 2864353 : if (MEM_P (XEXP (src, 1)))
703 : : {
704 : 100475 : if (!speed_p)
705 : 19629 : igain -= COSTS_N_BYTES (m == 2 ? 3 : 5);
706 : : else
707 : 90656 : igain += COSTS_N_INSNS
708 : : (m * ix86_cost->int_load[2]
709 : : - ix86_cost->sse_load[sse_cost_idx]) / 2;
710 : : }
711 : : break;
712 : :
713 : 50317 : case NEG:
714 : 50317 : case NOT:
715 : 50317 : igain -= ix86_cost->sse_op + COSTS_N_INSNS (1);
716 : :
717 : 50317 : if (GET_CODE (XEXP (src, 0)) != ABS)
718 : : {
719 : 50317 : igain += m * ix86_cost->add;
720 : 50317 : break;
721 : : }
722 : : /* FALLTHRU */
723 : :
724 : 990 : case ABS:
725 : 990 : case SMAX:
726 : 990 : case SMIN:
727 : 990 : case UMAX:
728 : 990 : case UMIN:
729 : : /* We do not have any conditional move cost, estimate it as a
730 : : reg-reg move. Comparisons are costed as adds. */
731 : 990 : igain += m * (COSTS_N_INSNS (2) + ix86_cost->add);
732 : : /* Integer SSE ops are all costed the same. */
733 : 990 : igain -= ix86_cost->sse_op;
734 : 990 : break;
735 : :
736 : 0 : case COMPARE:
737 : 0 : if (XEXP (src, 1) != const0_rtx)
738 : : {
739 : : /* cmp vs. pxor;pshufd;ptest. */
740 : 0 : igain += COSTS_N_INSNS (m - 3);
741 : : }
742 : 0 : else if (GET_CODE (XEXP (src, 0)) != AND)
743 : : {
744 : : /* test vs. pshufd;ptest. */
745 : 0 : igain += COSTS_N_INSNS (m - 2);
746 : : }
747 : 0 : else if (GET_CODE (XEXP (XEXP (src, 0), 0)) != NOT)
748 : : {
749 : : /* and;test vs. pshufd;ptest. */
750 : 0 : igain += COSTS_N_INSNS (2 * m - 2);
751 : : }
752 : 0 : else if (TARGET_BMI)
753 : : {
754 : : /* andn;test vs. pandn;pshufd;ptest. */
755 : 0 : igain += COSTS_N_INSNS (2 * m - 3);
756 : : }
757 : : else
758 : : {
759 : : /* not;and;test vs. pandn;pshufd;ptest. */
760 : 0 : igain += COSTS_N_INSNS (3 * m - 3);
761 : : }
762 : : break;
763 : :
764 : 1222061 : case CONST_INT:
765 : 1222061 : if (REG_P (dst))
766 : : {
767 : 1222061 : if (!speed_p)
768 : : {
769 : : /* xor (2 bytes) vs. xorps (3 bytes). */
770 : 244901 : if (src == const0_rtx)
771 : 142197 : igain -= COSTS_N_BYTES (1);
772 : : /* movdi_internal vs. movv2di_internal. */
773 : : /* => mov (5 bytes) vs. movaps (7 bytes). */
774 : 102704 : else if (x86_64_immediate_operand (src, SImode))
775 : 90131 : igain -= COSTS_N_BYTES (2);
776 : : else
777 : : /* ??? Larger immediate constants are placed in the
778 : : constant pool, where the size benefit/impact of
779 : : STV conversion is affected by whether and how
780 : : often each constant pool entry is shared/reused.
781 : : The value below is empirically derived from the
782 : : CSiBE benchmark (and the optimal value may drift
783 : : over time). */
784 : : igain += COSTS_N_BYTES (0);
785 : : }
786 : : else
787 : : {
788 : : /* DImode can be immediate for TARGET_64BIT
789 : : and SImode always. */
790 : 977160 : igain += m * COSTS_N_INSNS (1);
791 : 977160 : igain -= vector_const_cost (src, bb);
792 : : }
793 : : }
794 : 0 : else if (MEM_P (dst))
795 : : {
796 : 0 : igain += (m * ix86_cost->int_store[2]
797 : 0 : - ix86_cost->sse_store[sse_cost_idx]);
798 : 0 : igain -= vector_const_cost (src, bb);
799 : : }
800 : : break;
801 : :
802 : 34557 : case VEC_SELECT:
803 : 34557 : if (XVECEXP (XEXP (src, 1), 0, 0) == const0_rtx)
804 : : {
805 : : // movd (4 bytes) replaced with movdqa (4 bytes).
806 : 26535 : if (!!speed_p)
807 : 23872 : igain += COSTS_N_INSNS (ix86_cost->sse_to_integer
808 : : - ix86_cost->xmm_move) / 2;
809 : : }
810 : : else
811 : : {
812 : : // pshufd; movd replaced with pshufd.
813 : 8022 : if (!speed_p)
814 : 557 : igain += COSTS_N_BYTES (4);
815 : : else
816 : 7465 : igain += ix86_cost->sse_to_integer;
817 : : }
818 : : break;
819 : :
820 : 0 : default:
821 : 0 : gcc_unreachable ();
822 : : }
823 : : }
824 : :
825 : 11880687 : if (speed_p)
826 : 10599477 : weighted_gain += bb_freq * igain;
827 : 11883350 : gain += igain;
828 : :
829 : 11883350 : if (igain != 0 && dump_file)
830 : : {
831 : 93 : fprintf (dump_file, " Instruction gain %d with bb_freq %.2f for",
832 : : igain, bb_freq.to_double ());
833 : 93 : dump_insn_slim (dump_file, insn);
834 : : }
835 : : }
836 : :
837 : 6061377 : if (dump_file)
838 : : {
839 : 136 : fprintf (dump_file, " Instruction conversion gain: %d, \n",
840 : : gain);
841 : 136 : fprintf (dump_file, " Registers conversion cost: %d\n",
842 : : cost_sse_integer);
843 : 136 : fprintf (dump_file, " Weighted instruction conversion gain: %.2f, \n",
844 : : weighted_gain.to_double ());
845 : 136 : fprintf (dump_file, " Weighted registers conversion cost: %.2f\n",
846 : : weighted_cost_sse_integer.to_double ());
847 : : }
848 : :
849 : 6061377 : if (weighted_gain != weighted_cost_sse_integer)
850 : 4932720 : return weighted_gain > weighted_cost_sse_integer;
851 : : else
852 : 1128657 : return gain > cost_sse_integer;;
853 : : }
854 : :
855 : : /* Insert generated conversion instruction sequence INSNS
856 : : after instruction AFTER. New BB may be required in case
857 : : instruction has EH region attached. */
858 : :
859 : : void
860 : 30394 : scalar_chain::emit_conversion_insns (rtx insns, rtx_insn *after)
861 : : {
862 : 30394 : if (!control_flow_insn_p (after))
863 : : {
864 : 30171 : emit_insn_after (insns, after);
865 : 30171 : return;
866 : : }
867 : :
868 : 223 : basic_block bb = BLOCK_FOR_INSN (after);
869 : 223 : edge e = find_fallthru_edge (bb->succs);
870 : 223 : gcc_assert (e);
871 : :
872 : 223 : basic_block new_bb = split_edge (e);
873 : 223 : emit_insn_after (insns, BB_HEAD (new_bb));
874 : : }
875 : :
876 : : } // anon namespace
877 : :
878 : : /* Generate the canonical SET_SRC to move GPR to a VMODE vector register,
879 : : zeroing the upper parts. */
880 : :
881 : : static rtx
882 : 173052 : gen_gpr_to_xmm_move_src (enum machine_mode vmode, rtx gpr)
883 : : {
884 : 346104 : switch (GET_MODE_NUNITS (vmode))
885 : : {
886 : 13 : case 1:
887 : 13 : return gen_rtx_SUBREG (vmode, gpr, 0);
888 : 172564 : case 2:
889 : 345128 : return gen_rtx_VEC_CONCAT (vmode, gpr,
890 : : CONST0_RTX (GET_MODE_INNER (vmode)));
891 : 475 : default:
892 : 475 : return gen_rtx_VEC_MERGE (vmode, gen_rtx_VEC_DUPLICATE (vmode, gpr),
893 : : CONST0_RTX (vmode), GEN_INT (HOST_WIDE_INT_1U));
894 : : }
895 : : }
896 : :
897 : : /* Make vector copies for all register REGNO definitions
898 : : and replace its uses in a chain. */
899 : :
900 : : void
901 : 7978 : scalar_chain::make_vector_copies (rtx_insn *insn, rtx reg)
902 : : {
903 : 7978 : rtx vreg = *defs_map.get (reg);
904 : :
905 : 7978 : start_sequence ();
906 : 7978 : if (!TARGET_INTER_UNIT_MOVES_TO_VEC)
907 : : {
908 : 0 : rtx tmp = assign_386_stack_local (smode, SLOT_STV_TEMP);
909 : 0 : if (smode == DImode && !TARGET_64BIT)
910 : : {
911 : 0 : emit_move_insn (adjust_address (tmp, SImode, 0),
912 : : gen_rtx_SUBREG (SImode, reg, 0));
913 : 0 : emit_move_insn (adjust_address (tmp, SImode, 4),
914 : : gen_rtx_SUBREG (SImode, reg, 4));
915 : : }
916 : : else
917 : 0 : emit_move_insn (copy_rtx (tmp), reg);
918 : 0 : emit_insn (gen_rtx_SET (gen_rtx_SUBREG (vmode, vreg, 0),
919 : : gen_gpr_to_xmm_move_src (vmode, tmp)));
920 : : }
921 : 7978 : else if (!TARGET_64BIT && smode == DImode)
922 : : {
923 : 7943 : if (TARGET_SSE4_1)
924 : : {
925 : 356 : emit_insn (gen_sse2_loadld (gen_rtx_SUBREG (V4SImode, vreg, 0),
926 : : CONST0_RTX (V4SImode),
927 : : gen_rtx_SUBREG (SImode, reg, 0)));
928 : 356 : emit_insn (gen_sse4_1_pinsrd (gen_rtx_SUBREG (V4SImode, vreg, 0),
929 : : gen_rtx_SUBREG (V4SImode, vreg, 0),
930 : : gen_rtx_SUBREG (SImode, reg, 4),
931 : : GEN_INT (2)));
932 : : }
933 : : else
934 : : {
935 : 7587 : rtx tmp = gen_reg_rtx (DImode);
936 : 7587 : emit_insn (gen_sse2_loadld (gen_rtx_SUBREG (V4SImode, vreg, 0),
937 : : CONST0_RTX (V4SImode),
938 : : gen_rtx_SUBREG (SImode, reg, 0)));
939 : 7587 : emit_insn (gen_sse2_loadld (gen_rtx_SUBREG (V4SImode, tmp, 0),
940 : : CONST0_RTX (V4SImode),
941 : : gen_rtx_SUBREG (SImode, reg, 4)));
942 : 7587 : emit_insn (gen_vec_interleave_lowv4si
943 : : (gen_rtx_SUBREG (V4SImode, vreg, 0),
944 : : gen_rtx_SUBREG (V4SImode, vreg, 0),
945 : : gen_rtx_SUBREG (V4SImode, tmp, 0)));
946 : : }
947 : : }
948 : : else
949 : 35 : emit_insn (gen_rtx_SET (gen_rtx_SUBREG (vmode, vreg, 0),
950 : : gen_gpr_to_xmm_move_src (vmode, reg)));
951 : 7978 : rtx_insn *seq = end_sequence ();
952 : 7978 : emit_conversion_insns (seq, insn);
953 : :
954 : 7978 : if (dump_file)
955 : 0 : fprintf (dump_file,
956 : : " Copied r%d to a vector register r%d for insn %d\n",
957 : 0 : REGNO (reg), REGNO (vreg), INSN_UID (insn));
958 : 7978 : }
959 : :
960 : : /* Copy the definition SRC of INSN inside the chain to DST for
961 : : scalar uses outside of the chain. */
962 : :
963 : : void
964 : 21660 : scalar_chain::convert_reg (rtx_insn *insn, rtx dst, rtx src)
965 : : {
966 : 21660 : start_sequence ();
967 : 21660 : if (!TARGET_INTER_UNIT_MOVES_FROM_VEC)
968 : : {
969 : 0 : rtx tmp = assign_386_stack_local (smode, SLOT_STV_TEMP);
970 : 0 : emit_move_insn (tmp, src);
971 : 0 : if (!TARGET_64BIT && smode == DImode)
972 : : {
973 : 0 : emit_move_insn (gen_rtx_SUBREG (SImode, dst, 0),
974 : : adjust_address (tmp, SImode, 0));
975 : 0 : emit_move_insn (gen_rtx_SUBREG (SImode, dst, 4),
976 : : adjust_address (tmp, SImode, 4));
977 : : }
978 : : else
979 : 0 : emit_move_insn (dst, copy_rtx (tmp));
980 : : }
981 : 21660 : else if (!TARGET_64BIT && smode == DImode)
982 : : {
983 : 21298 : if (TARGET_SSE4_1)
984 : : {
985 : 0 : rtx tmp = gen_rtx_PARALLEL (VOIDmode,
986 : : gen_rtvec (1, const0_rtx));
987 : 0 : emit_insn
988 : 0 : (gen_rtx_SET
989 : : (gen_rtx_SUBREG (SImode, dst, 0),
990 : : gen_rtx_VEC_SELECT (SImode,
991 : : gen_rtx_SUBREG (V4SImode, src, 0),
992 : : tmp)));
993 : :
994 : 0 : tmp = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (1, const1_rtx));
995 : 0 : emit_insn
996 : 0 : (gen_rtx_SET
997 : : (gen_rtx_SUBREG (SImode, dst, 4),
998 : : gen_rtx_VEC_SELECT (SImode,
999 : : gen_rtx_SUBREG (V4SImode, src, 0),
1000 : : tmp)));
1001 : : }
1002 : : else
1003 : : {
1004 : 21298 : rtx vcopy = gen_reg_rtx (V2DImode);
1005 : 21298 : emit_move_insn (vcopy, gen_rtx_SUBREG (V2DImode, src, 0));
1006 : 21298 : emit_move_insn (gen_rtx_SUBREG (SImode, dst, 0),
1007 : : gen_rtx_SUBREG (SImode, vcopy, 0));
1008 : 21298 : emit_move_insn (vcopy,
1009 : : gen_rtx_LSHIFTRT (V2DImode,
1010 : : vcopy, GEN_INT (32)));
1011 : 21298 : emit_move_insn (gen_rtx_SUBREG (SImode, dst, 4),
1012 : : gen_rtx_SUBREG (SImode, vcopy, 0));
1013 : : }
1014 : : }
1015 : : else
1016 : 362 : emit_move_insn (dst, src);
1017 : :
1018 : 21660 : rtx_insn *seq = end_sequence ();
1019 : 21660 : emit_conversion_insns (seq, insn);
1020 : :
1021 : 21660 : if (dump_file)
1022 : 0 : fprintf (dump_file,
1023 : : " Copied r%d to a scalar register r%d for insn %d\n",
1024 : 0 : REGNO (src), REGNO (dst), INSN_UID (insn));
1025 : 21660 : }
1026 : :
1027 : : /* Helper function to convert immediate constant X to vmode. */
1028 : : static rtx
1029 : 45891 : smode_convert_cst (rtx x, enum machine_mode vmode)
1030 : : {
1031 : : /* Prefer all ones vector in case of -1. */
1032 : 45891 : if (constm1_operand (x, GET_MODE (x)))
1033 : 900 : return CONSTM1_RTX (vmode);
1034 : :
1035 : 44991 : unsigned n = GET_MODE_NUNITS (vmode);
1036 : 44991 : rtx *v = XALLOCAVEC (rtx, n);
1037 : 44991 : v[0] = x;
1038 : 50656 : for (unsigned i = 1; i < n; ++i)
1039 : 5665 : v[i] = const0_rtx;
1040 : 44991 : return gen_rtx_CONST_VECTOR (vmode, gen_rtvec_v (n, v));
1041 : : }
1042 : :
1043 : : /* Convert operand OP in INSN. We should handle
1044 : : memory operands and uninitialized registers.
1045 : : All other register uses are converted during
1046 : : registers conversion. */
1047 : :
1048 : : void
1049 : 245961 : scalar_chain::convert_op (rtx *op, rtx_insn *insn)
1050 : : {
1051 : 245961 : rtx tmp;
1052 : :
1053 : 245961 : if (GET_MODE (*op) == V1TImode)
1054 : : return;
1055 : :
1056 : 245938 : *op = copy_rtx_if_shared (*op);
1057 : :
1058 : 245938 : if (GET_CODE (*op) == NOT
1059 : 245938 : || GET_CODE (*op) == ASHIFT)
1060 : : {
1061 : 3490 : convert_op (&XEXP (*op, 0), insn);
1062 : 3490 : PUT_MODE (*op, vmode);
1063 : : }
1064 : : else if (MEM_P (*op))
1065 : : {
1066 : 173017 : rtx_insn *movabs = NULL;
1067 : :
1068 : : /* Emit MOVABS to load from a 64-bit absolute address to a GPR. */
1069 : 173017 : if (!memory_operand (*op, GET_MODE (*op)))
1070 : : {
1071 : 0 : tmp = gen_reg_rtx (GET_MODE (*op));
1072 : 0 : movabs = emit_insn_before (gen_rtx_SET (tmp, *op), insn);
1073 : :
1074 : 0 : *op = tmp;
1075 : : }
1076 : :
1077 : 173017 : tmp = gen_rtx_SUBREG (vmode, gen_reg_rtx (GET_MODE (*op)), 0);
1078 : :
1079 : 173017 : rtx_insn *eh_insn
1080 : 173017 : = emit_insn_before (gen_rtx_SET (copy_rtx (tmp),
1081 : : gen_gpr_to_xmm_move_src (vmode, *op)),
1082 : 173017 : insn);
1083 : :
1084 : 173017 : if (cfun->can_throw_non_call_exceptions)
1085 : : {
1086 : : /* Handle REG_EH_REGION note. */
1087 : 169015 : rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
1088 : 169015 : if (note)
1089 : : {
1090 : 3757 : if (movabs)
1091 : 0 : eh_insn = movabs;
1092 : 3757 : control_flow_insns.safe_push (eh_insn);
1093 : 3757 : add_reg_note (eh_insn, REG_EH_REGION, XEXP (note, 0));
1094 : : }
1095 : : }
1096 : :
1097 : 173017 : *op = tmp;
1098 : :
1099 : 173017 : if (dump_file)
1100 : 0 : fprintf (dump_file, " Preloading operand for insn %d into r%d\n",
1101 : 0 : INSN_UID (insn), reg_or_subregno (tmp));
1102 : : }
1103 : : else if (REG_P (*op))
1104 : 63088 : *op = gen_rtx_SUBREG (vmode, *op, 0);
1105 : : else if (CONST_SCALAR_INT_P (*op))
1106 : : {
1107 : 6343 : rtx vec_cst = smode_convert_cst (*op, vmode);
1108 : :
1109 : 6343 : if (!standard_sse_constant_p (vec_cst, vmode))
1110 : : {
1111 : 2709 : start_sequence ();
1112 : 2709 : vec_cst = validize_mem (force_const_mem (vmode, vec_cst));
1113 : 2709 : rtx_insn *seq = end_sequence ();
1114 : 2709 : emit_insn_before (seq, insn);
1115 : : }
1116 : :
1117 : 6343 : tmp = gen_rtx_SUBREG (vmode, gen_reg_rtx (smode), 0);
1118 : :
1119 : 6343 : emit_insn_before (gen_move_insn (copy_rtx (tmp), vec_cst), insn);
1120 : 6343 : *op = tmp;
1121 : : }
1122 : : else
1123 : : {
1124 : 0 : gcc_assert (SUBREG_P (*op));
1125 : 0 : gcc_assert (GET_MODE (*op) == vmode);
1126 : : }
1127 : : }
1128 : :
1129 : : /* Convert CCZmode COMPARE to vector mode. */
1130 : :
1131 : : rtx
1132 : 6 : scalar_chain::convert_compare (rtx op1, rtx op2, rtx_insn *insn)
1133 : : {
1134 : 6 : rtx src, tmp;
1135 : :
1136 : : /* Handle any REG_EQUAL notes. */
1137 : 6 : tmp = find_reg_equal_equiv_note (insn);
1138 : 6 : if (tmp)
1139 : : {
1140 : 1 : if (GET_CODE (XEXP (tmp, 0)) == COMPARE
1141 : 1 : && GET_MODE (XEXP (tmp, 0)) == CCZmode
1142 : 1 : && REG_P (XEXP (XEXP (tmp, 0), 0)))
1143 : : {
1144 : 1 : rtx *op = &XEXP (XEXP (tmp, 0), 1);
1145 : 1 : if (CONST_SCALAR_INT_P (*op))
1146 : : {
1147 : 1 : if (constm1_operand (*op, GET_MODE (*op)))
1148 : 0 : *op = CONSTM1_RTX (vmode);
1149 : : else
1150 : : {
1151 : 1 : unsigned n = GET_MODE_NUNITS (vmode);
1152 : 1 : rtx *v = XALLOCAVEC (rtx, n);
1153 : 1 : v[0] = *op;
1154 : 1 : for (unsigned i = 1; i < n; ++i)
1155 : 0 : v[i] = const0_rtx;
1156 : 1 : *op = gen_rtx_CONST_VECTOR (vmode, gen_rtvec_v (n, v));
1157 : : }
1158 : : tmp = NULL_RTX;
1159 : : }
1160 : 0 : else if (REG_P (*op))
1161 : : tmp = NULL_RTX;
1162 : : }
1163 : :
1164 : : if (tmp)
1165 : 0 : remove_note (insn, tmp);
1166 : : }
1167 : :
1168 : : /* Comparison against anything other than zero, requires an XOR. */
1169 : 6 : if (op2 != const0_rtx)
1170 : : {
1171 : 4 : convert_op (&op1, insn);
1172 : 4 : convert_op (&op2, insn);
1173 : : /* If both operands are MEMs, explicitly load the OP1 into TMP. */
1174 : 4 : if (MEM_P (op1) && MEM_P (op2))
1175 : : {
1176 : 0 : tmp = gen_reg_rtx (vmode);
1177 : 0 : emit_insn_before (gen_rtx_SET (tmp, op1), insn);
1178 : 0 : src = tmp;
1179 : : }
1180 : : else
1181 : : src = op1;
1182 : 4 : src = gen_rtx_XOR (vmode, src, op2);
1183 : : }
1184 : 2 : else if (GET_CODE (op1) == AND
1185 : 0 : && GET_CODE (XEXP (op1, 0)) == NOT)
1186 : : {
1187 : 0 : rtx op11 = XEXP (XEXP (op1, 0), 0);
1188 : 0 : rtx op12 = XEXP (op1, 1);
1189 : 0 : convert_op (&op11, insn);
1190 : 0 : convert_op (&op12, insn);
1191 : 0 : if (!REG_P (op11))
1192 : : {
1193 : 0 : tmp = gen_reg_rtx (vmode);
1194 : 0 : emit_insn_before (gen_rtx_SET (tmp, op11), insn);
1195 : 0 : op11 = tmp;
1196 : : }
1197 : 0 : src = gen_rtx_AND (vmode, gen_rtx_NOT (vmode, op11), op12);
1198 : 0 : }
1199 : 2 : else if (GET_CODE (op1) == AND)
1200 : : {
1201 : 0 : rtx op11 = XEXP (op1, 0);
1202 : 0 : rtx op12 = XEXP (op1, 1);
1203 : 0 : convert_op (&op11, insn);
1204 : 0 : convert_op (&op12, insn);
1205 : 0 : if (!REG_P (op11))
1206 : : {
1207 : 0 : tmp = gen_reg_rtx (vmode);
1208 : 0 : emit_insn_before (gen_rtx_SET (tmp, op11), insn);
1209 : 0 : op11 = tmp;
1210 : : }
1211 : 0 : return gen_rtx_UNSPEC (CCZmode, gen_rtvec (2, op11, op12),
1212 : : UNSPEC_PTEST);
1213 : : }
1214 : : else
1215 : : {
1216 : 2 : convert_op (&op1, insn);
1217 : 2 : src = op1;
1218 : : }
1219 : :
1220 : 6 : if (!REG_P (src))
1221 : : {
1222 : 4 : tmp = gen_reg_rtx (vmode);
1223 : 4 : emit_insn_before (gen_rtx_SET (tmp, src), insn);
1224 : 4 : src = tmp;
1225 : : }
1226 : :
1227 : 6 : if (vmode == V2DImode)
1228 : : {
1229 : 0 : tmp = gen_reg_rtx (vmode);
1230 : 0 : emit_insn_before (gen_vec_interleave_lowv2di (tmp, src, src), insn);
1231 : 0 : src = tmp;
1232 : : }
1233 : 6 : else if (vmode == V4SImode)
1234 : : {
1235 : 0 : tmp = gen_reg_rtx (vmode);
1236 : 0 : emit_insn_before (gen_sse2_pshufd (tmp, src, const0_rtx), insn);
1237 : 0 : src = tmp;
1238 : : }
1239 : :
1240 : 6 : return gen_rtx_UNSPEC (CCZmode, gen_rtvec (2, src, src), UNSPEC_PTEST);
1241 : : }
1242 : :
1243 : : /* Helper function for converting INSN to vector mode. */
1244 : :
1245 : : void
1246 : 1265675 : scalar_chain::convert_insn_common (rtx_insn *insn)
1247 : : {
1248 : : /* Generate copies for out-of-chain uses of defs and adjust debug uses. */
1249 : 1933408 : for (df_ref ref = DF_INSN_DEFS (insn); ref; ref = DF_REF_NEXT_LOC (ref))
1250 : 667733 : if (bitmap_bit_p (defs_conv, DF_REF_REGNO (ref)))
1251 : : {
1252 : 23120 : df_link *use;
1253 : 44692 : for (use = DF_REF_CHAIN (ref); use; use = use->next)
1254 : 43232 : if (NONDEBUG_INSN_P (DF_REF_INSN (use->ref))
1255 : 43232 : && (DF_REF_REG_MEM_P (use->ref)
1256 : 38617 : || !bitmap_bit_p (insns, DF_REF_INSN_UID (use->ref))))
1257 : : break;
1258 : 23120 : if (use)
1259 : 21660 : convert_reg (insn, DF_REF_REG (ref),
1260 : 21660 : *defs_map.get (regno_reg_rtx [DF_REF_REGNO (ref)]));
1261 : 1460 : else if (MAY_HAVE_DEBUG_BIND_INSNS)
1262 : : {
1263 : : /* If we generated a scalar copy we can leave debug-insns
1264 : : as-is, if not, we have to adjust them. */
1265 : 1368 : auto_vec<rtx_insn *, 5> to_reset_debug_insns;
1266 : 4168 : for (use = DF_REF_CHAIN (ref); use; use = use->next)
1267 : 2800 : if (DEBUG_INSN_P (DF_REF_INSN (use->ref)))
1268 : : {
1269 : 900 : rtx_insn *debug_insn = DF_REF_INSN (use->ref);
1270 : : /* If there's a reaching definition outside of the
1271 : : chain we have to reset. */
1272 : 900 : df_link *def;
1273 : 3788 : for (def = DF_REF_CHAIN (use->ref); def; def = def->next)
1274 : 3099 : if (!bitmap_bit_p (insns, DF_REF_INSN_UID (def->ref)))
1275 : : break;
1276 : 900 : if (def)
1277 : 211 : to_reset_debug_insns.safe_push (debug_insn);
1278 : : else
1279 : : {
1280 : 689 : *DF_REF_REAL_LOC (use->ref)
1281 : 689 : = *defs_map.get (regno_reg_rtx [DF_REF_REGNO (ref)]);
1282 : 689 : df_insn_rescan (debug_insn);
1283 : : }
1284 : : }
1285 : : /* Have to do the reset outside of the DF_CHAIN walk to not
1286 : : disrupt it. */
1287 : 2947 : while (!to_reset_debug_insns.is_empty ())
1288 : : {
1289 : 211 : rtx_insn *debug_insn = to_reset_debug_insns.pop ();
1290 : 211 : INSN_VAR_LOCATION_LOC (debug_insn) = gen_rtx_UNKNOWN_VAR_LOC ();
1291 : 211 : df_insn_rescan_debug_internal (debug_insn);
1292 : : }
1293 : 1368 : }
1294 : : }
1295 : :
1296 : : /* Replace uses in this insn with the defs we use in the chain. */
1297 : 3135898 : for (df_ref ref = DF_INSN_USES (insn); ref; ref = DF_REF_NEXT_LOC (ref))
1298 : 1870223 : if (!DF_REF_REG_MEM_P (ref))
1299 : 676386 : if (rtx *vreg = defs_map.get (regno_reg_rtx[DF_REF_REGNO (ref)]))
1300 : : {
1301 : : /* Also update a corresponding REG_DEAD note. */
1302 : 35242 : rtx note = find_reg_note (insn, REG_DEAD, DF_REF_REG (ref));
1303 : 35242 : if (note)
1304 : 23355 : XEXP (note, 0) = *vreg;
1305 : 35242 : *DF_REF_REAL_LOC (ref) = *vreg;
1306 : : }
1307 : 1265675 : }
1308 : :
1309 : : /* Convert INSN which is an SImode or DImode rotation by a constant
1310 : : to vector mode. CODE is either ROTATE or ROTATERT with operands
1311 : : OP0 and OP1. Returns the SET_SRC of the last instruction in the
1312 : : resulting sequence, which is emitted before INSN. */
1313 : :
1314 : : rtx
1315 : 92 : general_scalar_chain::convert_rotate (enum rtx_code code, rtx op0, rtx op1,
1316 : : rtx_insn *insn)
1317 : : {
1318 : 92 : int bits = INTVAL (op1);
1319 : 92 : rtx pat, result;
1320 : :
1321 : 92 : convert_op (&op0, insn);
1322 : 92 : if (bits == 0)
1323 : 0 : return op0;
1324 : :
1325 : 92 : if (smode == DImode)
1326 : : {
1327 : 92 : if (code == ROTATE)
1328 : 45 : bits = 64 - bits;
1329 : 92 : if (bits == 32)
1330 : : {
1331 : 0 : rtx tmp1 = gen_reg_rtx (V4SImode);
1332 : 0 : pat = gen_sse2_pshufd (tmp1, gen_lowpart (V4SImode, op0),
1333 : : GEN_INT (225));
1334 : 0 : emit_insn_before (pat, insn);
1335 : 0 : result = gen_lowpart (V2DImode, tmp1);
1336 : : }
1337 : 92 : else if (TARGET_AVX512VL)
1338 : 0 : result = simplify_gen_binary (code, V2DImode, op0, op1);
1339 : 92 : else if (bits == 16 || bits == 48)
1340 : : {
1341 : 0 : rtx tmp1 = gen_reg_rtx (V8HImode);
1342 : 0 : pat = gen_sse2_pshuflw (tmp1, gen_lowpart (V8HImode, op0),
1343 : : GEN_INT (bits == 16 ? 57 : 147));
1344 : 0 : emit_insn_before (pat, insn);
1345 : 0 : result = gen_lowpart (V2DImode, tmp1);
1346 : : }
1347 : 92 : else if ((bits & 0x07) == 0)
1348 : : {
1349 : 0 : rtx tmp1 = gen_reg_rtx (V4SImode);
1350 : 0 : pat = gen_sse2_pshufd (tmp1, gen_lowpart (V4SImode, op0),
1351 : : GEN_INT (68));
1352 : 0 : emit_insn_before (pat, insn);
1353 : 0 : rtx tmp2 = gen_reg_rtx (V1TImode);
1354 : 0 : pat = gen_sse2_lshrv1ti3 (tmp2, gen_lowpart (V1TImode, tmp1),
1355 : : GEN_INT (bits));
1356 : 0 : emit_insn_before (pat, insn);
1357 : 0 : result = gen_lowpart (V2DImode, tmp2);
1358 : : }
1359 : : else
1360 : : {
1361 : 92 : rtx tmp1 = gen_reg_rtx (V4SImode);
1362 : 92 : pat = gen_sse2_pshufd (tmp1, gen_lowpart (V4SImode, op0),
1363 : : GEN_INT (20));
1364 : 92 : emit_insn_before (pat, insn);
1365 : 92 : rtx tmp2 = gen_reg_rtx (V2DImode);
1366 : 92 : pat = gen_lshrv2di3 (tmp2, gen_lowpart (V2DImode, tmp1),
1367 : : GEN_INT (bits & 31));
1368 : 92 : emit_insn_before (pat, insn);
1369 : 92 : rtx tmp3 = gen_reg_rtx (V4SImode);
1370 : 139 : pat = gen_sse2_pshufd (tmp3, gen_lowpart (V4SImode, tmp2),
1371 : : GEN_INT (bits > 32 ? 34 : 136));
1372 : 92 : emit_insn_before (pat, insn);
1373 : 92 : result = gen_lowpart (V2DImode, tmp3);
1374 : : }
1375 : : }
1376 : 0 : else if (bits == 16)
1377 : : {
1378 : 0 : rtx tmp1 = gen_reg_rtx (V8HImode);
1379 : 0 : pat = gen_sse2_pshuflw (tmp1, gen_lowpart (V8HImode, op0), GEN_INT (225));
1380 : 0 : emit_insn_before (pat, insn);
1381 : 0 : result = gen_lowpart (V4SImode, tmp1);
1382 : : }
1383 : 0 : else if (TARGET_AVX512VL)
1384 : 0 : result = simplify_gen_binary (code, V4SImode, op0, op1);
1385 : : else
1386 : : {
1387 : 0 : if (code == ROTATE)
1388 : 0 : bits = 32 - bits;
1389 : :
1390 : 0 : rtx tmp1 = gen_reg_rtx (V4SImode);
1391 : 0 : emit_insn_before (gen_sse2_pshufd (tmp1, op0, GEN_INT (224)), insn);
1392 : 0 : rtx tmp2 = gen_reg_rtx (V2DImode);
1393 : 0 : pat = gen_lshrv2di3 (tmp2, gen_lowpart (V2DImode, tmp1),
1394 : : GEN_INT (bits));
1395 : 0 : emit_insn_before (pat, insn);
1396 : 0 : result = gen_lowpart (V4SImode, tmp2);
1397 : : }
1398 : :
1399 : : return result;
1400 : : }
1401 : :
1402 : : /* Convert INSN to vector mode. */
1403 : :
1404 : : void
1405 : 410273 : general_scalar_chain::convert_insn (rtx_insn *insn)
1406 : : {
1407 : 410273 : rtx def_set = single_set (insn);
1408 : 410273 : rtx src = SET_SRC (def_set);
1409 : 410273 : rtx dst = SET_DEST (def_set);
1410 : 410273 : rtx subreg;
1411 : :
1412 : 410273 : if (MEM_P (dst) && !REG_P (src))
1413 : : {
1414 : : /* There are no scalar integer instructions and therefore
1415 : : temporary register usage is required. */
1416 : 756 : rtx tmp = gen_reg_rtx (smode);
1417 : 756 : emit_conversion_insns (gen_move_insn (dst, tmp), insn);
1418 : 756 : dst = gen_rtx_SUBREG (vmode, tmp, 0);
1419 : 756 : }
1420 : 409517 : else if (REG_P (dst) && GET_MODE (dst) == smode)
1421 : : {
1422 : : /* Replace the definition with a SUBREG to the definition we
1423 : : use inside the chain. */
1424 : 213861 : rtx *vdef = defs_map.get (dst);
1425 : 213861 : if (vdef)
1426 : 23120 : dst = *vdef;
1427 : 213861 : dst = gen_rtx_SUBREG (vmode, dst, 0);
1428 : : /* IRA doesn't like to have REG_EQUAL/EQUIV notes when the SET_DEST
1429 : : is a non-REG_P. So kill those off. */
1430 : 213861 : rtx note = find_reg_equal_equiv_note (insn);
1431 : 213861 : if (note)
1432 : 9520 : remove_note (insn, note);
1433 : : }
1434 : :
1435 : 410273 : switch (GET_CODE (src))
1436 : : {
1437 : 29401 : case PLUS:
1438 : 29401 : case MINUS:
1439 : 29401 : case IOR:
1440 : 29401 : case XOR:
1441 : 29401 : case AND:
1442 : 29401 : case SMAX:
1443 : 29401 : case SMIN:
1444 : 29401 : case UMAX:
1445 : 29401 : case UMIN:
1446 : 29401 : convert_op (&XEXP (src, 1), insn);
1447 : : /* FALLTHRU */
1448 : :
1449 : 36667 : case ABS:
1450 : 36667 : case ASHIFT:
1451 : 36667 : case ASHIFTRT:
1452 : 36667 : case LSHIFTRT:
1453 : 36667 : convert_op (&XEXP (src, 0), insn);
1454 : 36667 : PUT_MODE (src, vmode);
1455 : 36667 : break;
1456 : :
1457 : 92 : case ROTATE:
1458 : 92 : case ROTATERT:
1459 : 92 : src = convert_rotate (GET_CODE (src), XEXP (src, 0), XEXP (src, 1),
1460 : : insn);
1461 : 92 : break;
1462 : :
1463 : 399 : case NEG:
1464 : 399 : src = XEXP (src, 0);
1465 : :
1466 : 399 : if (GET_CODE (src) == ABS)
1467 : : {
1468 : 0 : src = XEXP (src, 0);
1469 : 0 : convert_op (&src, insn);
1470 : 0 : subreg = gen_reg_rtx (vmode);
1471 : 0 : emit_insn_before (gen_rtx_SET (subreg,
1472 : : gen_rtx_ABS (vmode, src)), insn);
1473 : 0 : src = subreg;
1474 : : }
1475 : : else
1476 : 399 : convert_op (&src, insn);
1477 : :
1478 : 399 : subreg = gen_reg_rtx (vmode);
1479 : 399 : emit_insn_before (gen_move_insn (subreg, CONST0_RTX (vmode)), insn);
1480 : 399 : src = gen_rtx_MINUS (vmode, subreg, src);
1481 : 399 : break;
1482 : :
1483 : 251 : case NOT:
1484 : 251 : src = XEXP (src, 0);
1485 : 251 : convert_op (&src, insn);
1486 : 251 : subreg = gen_reg_rtx (vmode);
1487 : 251 : emit_insn_before (gen_move_insn (subreg, CONSTM1_RTX (vmode)), insn);
1488 : 251 : src = gen_rtx_XOR (vmode, src, subreg);
1489 : 251 : break;
1490 : :
1491 : 170895 : case MEM:
1492 : 170895 : if (!REG_P (dst))
1493 : 170895 : convert_op (&src, insn);
1494 : : break;
1495 : :
1496 : 197037 : case REG:
1497 : 197037 : if (!MEM_P (dst))
1498 : 1381 : convert_op (&src, insn);
1499 : : break;
1500 : :
1501 : 0 : case SUBREG:
1502 : 0 : gcc_assert (GET_MODE (src) == vmode);
1503 : : break;
1504 : :
1505 : 0 : case COMPARE:
1506 : 0 : dst = gen_rtx_REG (CCZmode, FLAGS_REG);
1507 : 0 : src = convert_compare (XEXP (src, 0), XEXP (src, 1), insn);
1508 : 0 : break;
1509 : :
1510 : 3343 : case CONST_INT:
1511 : 3343 : convert_op (&src, insn);
1512 : 3343 : break;
1513 : :
1514 : 1589 : case VEC_SELECT:
1515 : 1589 : if (XVECEXP (XEXP (src, 1), 0, 0) == const0_rtx)
1516 : 1289 : src = XEXP (src, 0);
1517 : 300 : else if (smode == DImode)
1518 : : {
1519 : 129 : rtx tmp = gen_lowpart (V1TImode, XEXP (src, 0));
1520 : 129 : dst = gen_lowpart (V1TImode, dst);
1521 : 129 : src = gen_rtx_LSHIFTRT (V1TImode, tmp, GEN_INT (64));
1522 : : }
1523 : : else
1524 : : {
1525 : 171 : rtx tmp = XVECEXP (XEXP (src, 1), 0, 0);
1526 : 171 : rtvec vec = gen_rtvec (4, tmp, tmp, tmp, tmp);
1527 : 171 : rtx par = gen_rtx_PARALLEL (VOIDmode, vec);
1528 : 171 : src = gen_rtx_VEC_SELECT (vmode, XEXP (src, 0), par);
1529 : : }
1530 : : break;
1531 : :
1532 : 0 : default:
1533 : 0 : gcc_unreachable ();
1534 : : }
1535 : :
1536 : 410273 : SET_SRC (def_set) = src;
1537 : 410273 : SET_DEST (def_set) = dst;
1538 : :
1539 : : /* Drop possible dead definitions. */
1540 : 410273 : PATTERN (insn) = def_set;
1541 : :
1542 : 410273 : INSN_CODE (insn) = -1;
1543 : 410273 : int patt = recog_memoized (insn);
1544 : 410273 : if (patt == -1)
1545 : 0 : fatal_insn_not_found (insn);
1546 : 410273 : df_insn_rescan (insn);
1547 : 410273 : }
1548 : :
1549 : : /* Helper function to compute gain for loading an immediate constant.
1550 : : Typically, two movabsq for TImode vs. vmovdqa for V1TImode, but
1551 : : with numerous special cases. */
1552 : :
1553 : : static int
1554 : 6 : timode_immed_const_gain (rtx cst, basic_block bb)
1555 : : {
1556 : : /* movabsq vs. movabsq+vmovq+vunpacklqdq. */
1557 : 6 : if (CONST_WIDE_INT_P (cst)
1558 : 5 : && CONST_WIDE_INT_NUNITS (cst) == 2
1559 : 11 : && CONST_WIDE_INT_ELT (cst, 0) == CONST_WIDE_INT_ELT (cst, 1))
1560 : 0 : return optimize_bb_for_size_p (bb) ? -COSTS_N_BYTES (9)
1561 : : : -COSTS_N_INSNS (2);
1562 : : /* 2x movabsq ~ vmovdqa. */
1563 : : return 0;
1564 : : }
1565 : :
1566 : : /* Return true it's cost profitable for for chain conversion. */
1567 : :
1568 : : bool
1569 : 439415 : timode_scalar_chain::compute_convert_gain ()
1570 : : {
1571 : : /* Assume that if we have to move TImode values between units,
1572 : : then transforming this chain isn't worth it. */
1573 : 439415 : if (cost_sse_integer)
1574 : : return false;
1575 : :
1576 : 439415 : bitmap_iterator bi;
1577 : 439415 : unsigned insn_uid;
1578 : :
1579 : : /* Split ties to prefer V1TImode when not optimizing for size. */
1580 : 439415 : int gain = optimize_size ? 0 : 1;
1581 : 439415 : sreal weighted_gain = 0;
1582 : :
1583 : 439415 : if (dump_file)
1584 : 0 : fprintf (dump_file, "Computing gain for chain #%d...\n", chain_id);
1585 : :
1586 : 1295155 : EXECUTE_IF_SET_IN_BITMAP (insns, 0, insn_uid, bi)
1587 : : {
1588 : 855740 : rtx_insn *insn = DF_INSN_UID_GET (insn_uid)->insn;
1589 : 855740 : rtx def_set = single_set (insn);
1590 : 855740 : rtx src = SET_SRC (def_set);
1591 : 855740 : rtx dst = SET_DEST (def_set);
1592 : 855740 : HOST_WIDE_INT op1val;
1593 : 855740 : basic_block bb = BLOCK_FOR_INSN (insn);
1594 : 855740 : int scost, vcost;
1595 : 855740 : int igain = 0;
1596 : 855740 : profile_count entry_count = ENTRY_BLOCK_PTR_FOR_FN (cfun)->count;
1597 : 855740 : bool speed_p = optimize_bb_for_speed_p (bb);
1598 : 855740 : sreal bb_freq = bb->count.to_sreal_scale (entry_count);
1599 : :
1600 : 855740 : switch (GET_CODE (src))
1601 : : {
1602 : 416076 : case REG:
1603 : 416076 : if (!speed_p)
1604 : 10614 : igain = MEM_P (dst) ? COSTS_N_BYTES (6) : COSTS_N_BYTES (3);
1605 : : else
1606 : : igain = COSTS_N_INSNS (1);
1607 : : break;
1608 : :
1609 : 388725 : case MEM:
1610 : 388725 : igain = !speed_p ? COSTS_N_BYTES (7) : COSTS_N_INSNS (1);
1611 : : break;
1612 : :
1613 : 10928 : case CONST_INT:
1614 : 10928 : if (MEM_P (dst)
1615 : 10928 : && standard_sse_constant_p (src, V1TImode))
1616 : 10395 : igain = !speed_p ? COSTS_N_BYTES (11) : 1;
1617 : : break;
1618 : :
1619 : 39743 : case CONST_WIDE_INT:
1620 : : /* 2 x mov vs. vmovdqa. */
1621 : 39743 : if (MEM_P (dst))
1622 : 39570 : igain = !speed_p ? COSTS_N_BYTES (3) : COSTS_N_INSNS (1);
1623 : : break;
1624 : :
1625 : 17 : case NOT:
1626 : 17 : if (MEM_P (dst))
1627 : 11584 : igain = -COSTS_N_INSNS (1);
1628 : : break;
1629 : :
1630 : 13 : case AND:
1631 : 13 : case XOR:
1632 : 13 : case IOR:
1633 : 13 : if (!MEM_P (dst))
1634 : 6 : igain = COSTS_N_INSNS (1);
1635 : 13 : if (CONST_SCALAR_INT_P (XEXP (src, 1)))
1636 : 6 : igain += timode_immed_const_gain (XEXP (src, 1), bb);
1637 : : break;
1638 : :
1639 : 122 : case ASHIFT:
1640 : 122 : case LSHIFTRT:
1641 : : /* See ix86_expand_v1ti_shift. */
1642 : 122 : op1val = INTVAL (XEXP (src, 1));
1643 : 122 : if (!speed_p)
1644 : : {
1645 : 10 : if (op1val == 64 || op1val == 65)
1646 : : scost = COSTS_N_BYTES (5);
1647 : 10 : else if (op1val >= 66)
1648 : : scost = COSTS_N_BYTES (6);
1649 : 10 : else if (op1val == 1)
1650 : : scost = COSTS_N_BYTES (8);
1651 : : else
1652 : : scost = COSTS_N_BYTES (9);
1653 : :
1654 : 9 : if ((op1val & 7) == 0)
1655 : : vcost = COSTS_N_BYTES (5);
1656 : 10 : else if (op1val > 64)
1657 : : vcost = COSTS_N_BYTES (10);
1658 : : else
1659 : 10 : vcost = TARGET_AVX ? COSTS_N_BYTES (19) : COSTS_N_BYTES (23);
1660 : : }
1661 : : else
1662 : : {
1663 : 112 : scost = COSTS_N_INSNS (2);
1664 : 112 : if ((op1val & 7) == 0)
1665 : : vcost = COSTS_N_INSNS (1);
1666 : 110 : else if (op1val > 64)
1667 : : vcost = COSTS_N_INSNS (2);
1668 : : else
1669 : 110 : vcost = TARGET_AVX ? COSTS_N_INSNS (4) : COSTS_N_INSNS (5);
1670 : : }
1671 : 122 : igain = scost - vcost;
1672 : 122 : break;
1673 : :
1674 : 103 : case ASHIFTRT:
1675 : : /* See ix86_expand_v1ti_ashiftrt. */
1676 : 103 : op1val = INTVAL (XEXP (src, 1));
1677 : 103 : if (!speed_p)
1678 : : {
1679 : 7 : if (op1val == 64 || op1val == 127)
1680 : : scost = COSTS_N_BYTES (7);
1681 : 7 : else if (op1val == 1)
1682 : : scost = COSTS_N_BYTES (8);
1683 : 7 : else if (op1val == 65)
1684 : : scost = COSTS_N_BYTES (10);
1685 : 7 : else if (op1val >= 66)
1686 : : scost = COSTS_N_BYTES (11);
1687 : : else
1688 : : scost = COSTS_N_BYTES (9);
1689 : :
1690 : 0 : if (op1val == 127)
1691 : : vcost = COSTS_N_BYTES (10);
1692 : 7 : else if (op1val == 64)
1693 : : vcost = COSTS_N_BYTES (14);
1694 : 7 : else if (op1val == 96)
1695 : : vcost = COSTS_N_BYTES (18);
1696 : 7 : else if (op1val >= 111)
1697 : : vcost = COSTS_N_BYTES (15);
1698 : 7 : else if (TARGET_AVX2 && op1val == 32)
1699 : : vcost = COSTS_N_BYTES (16);
1700 : 7 : else if (TARGET_SSE4_1 && op1val == 32)
1701 : : vcost = COSTS_N_BYTES (20);
1702 : 7 : else if (op1val >= 96)
1703 : : vcost = COSTS_N_BYTES (23);
1704 : 7 : else if ((op1val & 7) == 0)
1705 : : vcost = COSTS_N_BYTES (28);
1706 : 7 : else if (TARGET_AVX2 && op1val < 32)
1707 : : vcost = COSTS_N_BYTES (30);
1708 : 7 : else if (op1val == 1 || op1val >= 64)
1709 : : vcost = COSTS_N_BYTES (42);
1710 : : else
1711 : 7 : vcost = COSTS_N_BYTES (47);
1712 : : }
1713 : : else
1714 : : {
1715 : 96 : if (op1val >= 65 && op1val <= 126)
1716 : : scost = COSTS_N_INSNS (3);
1717 : : else
1718 : 96 : scost = COSTS_N_INSNS (2);
1719 : :
1720 : 96 : if (op1val == 127)
1721 : : vcost = COSTS_N_INSNS (2);
1722 : 96 : else if (op1val == 64)
1723 : : vcost = COSTS_N_INSNS (3);
1724 : 96 : else if (op1val == 96)
1725 : : vcost = COSTS_N_INSNS (3);
1726 : 96 : else if (op1val >= 111)
1727 : : vcost = COSTS_N_INSNS (3);
1728 : 96 : else if (TARGET_SSE4_1 && op1val == 32)
1729 : : vcost = COSTS_N_INSNS (3);
1730 : 96 : else if (TARGET_SSE4_1
1731 : 0 : && (op1val == 8 || op1val == 16 || op1val == 24))
1732 : : vcost = COSTS_N_INSNS (3);
1733 : 96 : else if (op1val >= 96)
1734 : : vcost = COSTS_N_INSNS (4);
1735 : 96 : else if (TARGET_SSE4_1 && (op1val == 28 || op1val == 80))
1736 : : vcost = COSTS_N_INSNS (4);
1737 : 96 : else if ((op1val & 7) == 0)
1738 : : vcost = COSTS_N_INSNS (5);
1739 : 96 : else if (TARGET_AVX2 && op1val < 32)
1740 : : vcost = COSTS_N_INSNS (6);
1741 : 96 : else if (TARGET_SSE4_1 && op1val < 15)
1742 : : vcost = COSTS_N_INSNS (6);
1743 : 96 : else if (op1val == 1 || op1val >= 64)
1744 : : vcost = COSTS_N_INSNS (8);
1745 : : else
1746 : 0 : vcost = COSTS_N_INSNS (9);
1747 : : }
1748 : 103 : igain = scost - vcost;
1749 : 103 : break;
1750 : :
1751 : 5 : case ROTATE:
1752 : 5 : case ROTATERT:
1753 : : /* See ix86_expand_v1ti_rotate. */
1754 : 5 : op1val = INTVAL (XEXP (src, 1));
1755 : 5 : if (!speed_p)
1756 : : {
1757 : 0 : scost = COSTS_N_BYTES (13);
1758 : 0 : if ((op1val & 31) == 0)
1759 : : vcost = COSTS_N_BYTES (5);
1760 : 0 : else if ((op1val & 7) == 0)
1761 : 0 : vcost = TARGET_AVX ? COSTS_N_BYTES (13) : COSTS_N_BYTES (18);
1762 : 0 : else if (op1val > 32 && op1val < 96)
1763 : : vcost = COSTS_N_BYTES (24);
1764 : : else
1765 : 0 : vcost = COSTS_N_BYTES (19);
1766 : : }
1767 : : else
1768 : : {
1769 : 5 : scost = COSTS_N_INSNS (3);
1770 : 5 : if ((op1val & 31) == 0)
1771 : : vcost = COSTS_N_INSNS (1);
1772 : 3 : else if ((op1val & 7) == 0)
1773 : 1 : vcost = TARGET_AVX ? COSTS_N_INSNS (3) : COSTS_N_INSNS (4);
1774 : 2 : else if (op1val > 32 && op1val < 96)
1775 : : vcost = COSTS_N_INSNS (5);
1776 : : else
1777 : 2 : vcost = COSTS_N_INSNS (1);
1778 : : }
1779 : 5 : igain = scost - vcost;
1780 : 5 : break;
1781 : :
1782 : 8 : case COMPARE:
1783 : 8 : if (XEXP (src, 1) == const0_rtx)
1784 : : {
1785 : 4 : if (GET_CODE (XEXP (src, 0)) == AND)
1786 : : /* and;and;or (9 bytes) vs. ptest (5 bytes). */
1787 : : igain = !speed_p ? COSTS_N_BYTES (4) : COSTS_N_INSNS (2);
1788 : : /* or (3 bytes) vs. ptest (5 bytes). */
1789 : 4 : else if (!speed_p)
1790 : 0 : igain = -COSTS_N_BYTES (2);
1791 : : }
1792 : 4 : else if (XEXP (src, 1) == const1_rtx)
1793 : : /* and;cmp -1 (7 bytes) vs. pcmpeqd;pxor;ptest (13 bytes). */
1794 : 0 : igain = !speed_p ? -COSTS_N_BYTES (6) : -COSTS_N_INSNS (1);
1795 : : break;
1796 : :
1797 : : default:
1798 : : break;
1799 : : }
1800 : :
1801 : 1688541 : gain += igain;
1802 : 855736 : if (speed_p)
1803 : 832805 : weighted_gain += bb_freq * igain;
1804 : :
1805 : 855740 : if (igain != 0 && dump_file)
1806 : : {
1807 : 0 : fprintf (dump_file, " Instruction gain %d with bb_freq %.2f for ",
1808 : : igain, bb_freq.to_double ());
1809 : 0 : dump_insn_slim (dump_file, insn);
1810 : : }
1811 : : }
1812 : :
1813 : 439415 : if (dump_file)
1814 : 0 : fprintf (dump_file, " Total gain: %d, weighted gain %.2f\n",
1815 : : gain, weighted_gain.to_double ());
1816 : :
1817 : 439415 : if (weighted_gain > (sreal) 0)
1818 : : return true;
1819 : : else
1820 : 12878 : return gain > 0;
1821 : : }
1822 : :
1823 : : /* Fix uses of converted REG in debug insns. */
1824 : :
1825 : : void
1826 : 389521 : timode_scalar_chain::fix_debug_reg_uses (rtx reg)
1827 : : {
1828 : 389521 : if (!flag_var_tracking)
1829 : : return;
1830 : :
1831 : 342329 : df_ref ref, next;
1832 : 702187 : for (ref = DF_REG_USE_CHAIN (REGNO (reg)); ref; ref = next)
1833 : : {
1834 : 359858 : rtx_insn *insn = DF_REF_INSN (ref);
1835 : : /* Make sure the next ref is for a different instruction,
1836 : : so that we're not affected by the rescan. */
1837 : 359858 : next = DF_REF_NEXT_REG (ref);
1838 : 359858 : while (next && DF_REF_INSN (next) == insn)
1839 : 0 : next = DF_REF_NEXT_REG (next);
1840 : :
1841 : 359858 : if (DEBUG_INSN_P (insn))
1842 : : {
1843 : : /* It may be a debug insn with a TImode variable in
1844 : : register. */
1845 : : bool changed = false;
1846 : 42 : for (; ref != next; ref = DF_REF_NEXT_REG (ref))
1847 : : {
1848 : 21 : rtx *loc = DF_REF_LOC (ref);
1849 : 21 : if (REG_P (*loc) && GET_MODE (*loc) == V1TImode)
1850 : : {
1851 : 17 : *loc = gen_rtx_SUBREG (TImode, *loc, 0);
1852 : 17 : changed = true;
1853 : : }
1854 : : }
1855 : 21 : if (changed)
1856 : 17 : df_insn_rescan (insn);
1857 : : }
1858 : : }
1859 : : }
1860 : :
1861 : : /* Convert INSN from TImode to V1T1mode. */
1862 : :
1863 : : void
1864 : 855402 : timode_scalar_chain::convert_insn (rtx_insn *insn)
1865 : : {
1866 : 855402 : rtx def_set = single_set (insn);
1867 : 855402 : rtx src = SET_SRC (def_set);
1868 : 855402 : rtx dst = SET_DEST (def_set);
1869 : 855402 : rtx tmp;
1870 : :
1871 : 855402 : switch (GET_CODE (dst))
1872 : : {
1873 : 389527 : case REG:
1874 : 389527 : if (GET_MODE (dst) == TImode)
1875 : : {
1876 : 388957 : PUT_MODE (dst, V1TImode);
1877 : 388957 : fix_debug_reg_uses (dst);
1878 : : }
1879 : 389527 : if (GET_MODE (dst) == V1TImode)
1880 : : {
1881 : : /* It might potentially be helpful to convert REG_EQUAL notes,
1882 : : but for now we just remove them. */
1883 : 389521 : rtx note = find_reg_equal_equiv_note (insn);
1884 : 389521 : if (note)
1885 : 436 : remove_note (insn, note);
1886 : : }
1887 : : break;
1888 : 465875 : case MEM:
1889 : 465875 : PUT_MODE (dst, V1TImode);
1890 : 465875 : break;
1891 : :
1892 : 0 : default:
1893 : 0 : gcc_unreachable ();
1894 : : }
1895 : :
1896 : 855402 : switch (GET_CODE (src))
1897 : : {
1898 : 416030 : case REG:
1899 : 416030 : if (GET_MODE (src) == TImode)
1900 : : {
1901 : 564 : PUT_MODE (src, V1TImode);
1902 : 564 : fix_debug_reg_uses (src);
1903 : : }
1904 : : break;
1905 : :
1906 : 388677 : case MEM:
1907 : 388677 : PUT_MODE (src, V1TImode);
1908 : 388677 : break;
1909 : :
1910 : 39742 : case CONST_WIDE_INT:
1911 : 39742 : if (NONDEBUG_INSN_P (insn))
1912 : : {
1913 : : /* Since there are no instructions to store 128-bit constant,
1914 : : temporary register usage is required. */
1915 : 39742 : bool use_move;
1916 : 39742 : start_sequence ();
1917 : 39742 : tmp = ix86_convert_const_wide_int_to_broadcast (TImode, src);
1918 : 39742 : if (tmp)
1919 : : {
1920 : 194 : src = lowpart_subreg (V1TImode, tmp, TImode);
1921 : 194 : use_move = true;
1922 : : }
1923 : : else
1924 : : {
1925 : 39548 : src = smode_convert_cst (src, V1TImode);
1926 : 39548 : src = validize_mem (force_const_mem (V1TImode, src));
1927 : 39548 : use_move = MEM_P (dst);
1928 : : }
1929 : 39742 : rtx_insn *seq = end_sequence ();
1930 : 39742 : if (seq)
1931 : 195 : emit_insn_before (seq, insn);
1932 : 39742 : if (use_move)
1933 : : {
1934 : 39571 : tmp = gen_reg_rtx (V1TImode);
1935 : 39571 : emit_insn_before (gen_rtx_SET (tmp, src), insn);
1936 : 39571 : src = tmp;
1937 : : }
1938 : : }
1939 : : break;
1940 : :
1941 : 10927 : case CONST_INT:
1942 : 10927 : switch (standard_sse_constant_p (src, TImode))
1943 : : {
1944 : 10698 : case 1:
1945 : 10698 : src = CONST0_RTX (GET_MODE (dst));
1946 : 10698 : break;
1947 : 229 : case 2:
1948 : 229 : src = CONSTM1_RTX (GET_MODE (dst));
1949 : 229 : break;
1950 : 0 : default:
1951 : 0 : gcc_unreachable ();
1952 : : }
1953 : 10927 : if (MEM_P (dst))
1954 : : {
1955 : 10395 : tmp = gen_reg_rtx (V1TImode);
1956 : 10395 : emit_insn_before (gen_rtx_SET (tmp, src), insn);
1957 : 10395 : src = tmp;
1958 : : }
1959 : : break;
1960 : :
1961 : 9 : case AND:
1962 : 9 : if (GET_CODE (XEXP (src, 0)) == NOT)
1963 : : {
1964 : 0 : convert_op (&XEXP (XEXP (src, 0), 0), insn);
1965 : 0 : convert_op (&XEXP (src, 1), insn);
1966 : 0 : PUT_MODE (XEXP (src, 0), V1TImode);
1967 : 0 : PUT_MODE (src, V1TImode);
1968 : 0 : break;
1969 : : }
1970 : : /* FALLTHRU */
1971 : :
1972 : 12 : case XOR:
1973 : 12 : case IOR:
1974 : 12 : convert_op (&XEXP (src, 0), insn);
1975 : 12 : convert_op (&XEXP (src, 1), insn);
1976 : 12 : PUT_MODE (src, V1TImode);
1977 : 12 : if (MEM_P (dst))
1978 : : {
1979 : 6 : tmp = gen_reg_rtx (V1TImode);
1980 : 6 : emit_insn_before (gen_rtx_SET (tmp, src), insn);
1981 : 6 : src = tmp;
1982 : : }
1983 : : break;
1984 : :
1985 : 1 : case NOT:
1986 : 1 : src = XEXP (src, 0);
1987 : 1 : convert_op (&src, insn);
1988 : 1 : tmp = gen_reg_rtx (V1TImode);
1989 : 1 : emit_insn_before (gen_move_insn (tmp, CONSTM1_RTX (V1TImode)), insn);
1990 : 1 : src = gen_rtx_XOR (V1TImode, src, tmp);
1991 : 1 : if (MEM_P (dst))
1992 : : {
1993 : 0 : tmp = gen_reg_rtx (V1TImode);
1994 : 0 : emit_insn_before (gen_rtx_SET (tmp, src), insn);
1995 : 0 : src = tmp;
1996 : : }
1997 : : break;
1998 : :
1999 : 6 : case COMPARE:
2000 : 6 : dst = gen_rtx_REG (CCZmode, FLAGS_REG);
2001 : 6 : src = convert_compare (XEXP (src, 0), XEXP (src, 1), insn);
2002 : 6 : break;
2003 : :
2004 : 7 : case ASHIFT:
2005 : 7 : case LSHIFTRT:
2006 : 7 : case ASHIFTRT:
2007 : 7 : case ROTATERT:
2008 : 7 : case ROTATE:
2009 : 7 : convert_op (&XEXP (src, 0), insn);
2010 : 7 : PUT_MODE (src, V1TImode);
2011 : 7 : break;
2012 : :
2013 : 0 : default:
2014 : 0 : gcc_unreachable ();
2015 : : }
2016 : :
2017 : 855402 : SET_SRC (def_set) = src;
2018 : 855402 : SET_DEST (def_set) = dst;
2019 : :
2020 : : /* Drop possible dead definitions. */
2021 : 855402 : PATTERN (insn) = def_set;
2022 : :
2023 : 855402 : INSN_CODE (insn) = -1;
2024 : 855402 : recog_memoized (insn);
2025 : 855402 : df_insn_rescan (insn);
2026 : 855402 : }
2027 : :
2028 : : /* Generate copies from defs used by the chain but not defined therein.
2029 : : Also populates defs_map which is used later by convert_insn. */
2030 : :
2031 : : void
2032 : 612100 : scalar_chain::convert_registers ()
2033 : : {
2034 : 612100 : bitmap_iterator bi;
2035 : 612100 : unsigned id;
2036 : 637713 : EXECUTE_IF_SET_IN_BITMAP (defs_conv, 0, id, bi)
2037 : : {
2038 : 25613 : rtx chain_reg = gen_reg_rtx (smode);
2039 : 25613 : defs_map.put (regno_reg_rtx[id], chain_reg);
2040 : : }
2041 : 620078 : EXECUTE_IF_SET_IN_BITMAP (insns_conv, 0, id, bi)
2042 : 20038 : for (df_ref ref = DF_INSN_UID_DEFS (id); ref; ref = DF_REF_NEXT_LOC (ref))
2043 : 12060 : if (bitmap_bit_p (defs_conv, DF_REF_REGNO (ref)))
2044 : 7978 : make_vector_copies (DF_REF_INSN (ref), DF_REF_REAL_REG (ref));
2045 : 612100 : }
2046 : :
2047 : : /* Convert whole chain creating required register
2048 : : conversions and copies. */
2049 : :
2050 : : int
2051 : 612100 : scalar_chain::convert ()
2052 : : {
2053 : 612100 : bitmap_iterator bi;
2054 : 612100 : unsigned id;
2055 : 612100 : int converted_insns = 0;
2056 : :
2057 : 612100 : if (!dbg_cnt (stv_conversion))
2058 : : return 0;
2059 : :
2060 : 612100 : if (dump_file)
2061 : 0 : fprintf (dump_file, "Converting chain #%d...\n", chain_id);
2062 : :
2063 : 612100 : convert_registers ();
2064 : :
2065 : 1877775 : EXECUTE_IF_SET_IN_BITMAP (insns, 0, id, bi)
2066 : : {
2067 : 1265675 : rtx_insn *insn = DF_INSN_UID_GET (id)->insn;
2068 : 1265675 : convert_insn_common (insn);
2069 : 1265675 : convert_insn (insn);
2070 : 1265675 : converted_insns++;
2071 : : }
2072 : :
2073 : : return converted_insns;
2074 : : }
2075 : :
2076 : : /* Return the SET expression if INSN doesn't reference hard register.
2077 : : Return NULL if INSN uses or defines a hard register, excluding
2078 : : pseudo register pushes, hard register uses in a memory address,
2079 : : clobbers and flags definitions. */
2080 : :
2081 : : static rtx
2082 : 343540728 : pseudo_reg_set (rtx_insn *insn)
2083 : : {
2084 : 343540728 : rtx set = single_set (insn);
2085 : 343540728 : if (!set)
2086 : : return NULL;
2087 : :
2088 : : /* Check pseudo register push first. */
2089 : 137338180 : machine_mode mode = TARGET_64BIT ? TImode : DImode;
2090 : 137338180 : if (REG_P (SET_SRC (set))
2091 : 38842054 : && !HARD_REGISTER_P (SET_SRC (set))
2092 : 167636652 : && push_operand (SET_DEST (set), mode))
2093 : : return set;
2094 : :
2095 : 137086070 : df_ref ref;
2096 : 222318890 : FOR_EACH_INSN_DEF (ref, insn)
2097 : 122776496 : if (HARD_REGISTER_P (DF_REF_REAL_REG (ref))
2098 : 65782718 : && !DF_REF_FLAGS_IS_SET (ref, DF_REF_MUST_CLOBBER)
2099 : 173878485 : && DF_REF_REGNO (ref) != FLAGS_REG)
2100 : : return NULL;
2101 : :
2102 : 189981266 : FOR_EACH_INSN_USE (ref, insn)
2103 : 116224799 : if (!DF_REF_REG_MEM_P (ref) && HARD_REGISTER_P (DF_REF_REAL_REG (ref)))
2104 : : return NULL;
2105 : :
2106 : : return set;
2107 : : }
2108 : :
2109 : : /* Return true if the register REG is defined in a single DEF chain.
2110 : : If it is defined in more than one DEF chains, we may not be able
2111 : : to convert it in all chains. */
2112 : :
2113 : : static bool
2114 : 1097579 : single_def_chain_p (rtx reg)
2115 : : {
2116 : 1097579 : df_ref ref = DF_REG_DEF_CHAIN (REGNO (reg));
2117 : 1097579 : if (!ref)
2118 : : return false;
2119 : 1097564 : return DF_REF_NEXT_REG (ref) == nullptr;
2120 : : }
2121 : :
2122 : : /* Check if comparison INSN may be transformed into vector comparison.
2123 : : Currently we transform equality/inequality checks which look like:
2124 : : (set (reg:CCZ 17 flags) (compare:CCZ (reg:TI x) (reg:TI y))) */
2125 : :
2126 : : static bool
2127 : 12918095 : convertible_comparison_p (rtx_insn *insn, enum machine_mode mode)
2128 : : {
2129 : 14311365 : if (mode != (TARGET_64BIT ? TImode : DImode))
2130 : : return false;
2131 : :
2132 : 4724712 : if (!TARGET_SSE4_1)
2133 : : return false;
2134 : :
2135 : 160046 : rtx def_set = single_set (insn);
2136 : :
2137 : 160046 : gcc_assert (def_set);
2138 : :
2139 : 160046 : rtx src = SET_SRC (def_set);
2140 : 160046 : rtx dst = SET_DEST (def_set);
2141 : :
2142 : 160046 : gcc_assert (GET_CODE (src) == COMPARE);
2143 : :
2144 : 160046 : if (!REG_P (dst)
2145 : 160046 : || REGNO (dst) != FLAGS_REG
2146 : 320092 : || GET_MODE (dst) != CCZmode)
2147 : : return false;
2148 : :
2149 : 116144 : rtx op1 = XEXP (src, 0);
2150 : 116144 : rtx op2 = XEXP (src, 1);
2151 : :
2152 : : /* *cmp<dwi>_doubleword. */
2153 : 116144 : if ((CONST_SCALAR_INT_P (op1)
2154 : 116144 : || ((REG_P (op1) || MEM_P (op1))
2155 : 114427 : && GET_MODE (op1) == mode))
2156 : 49 : && (CONST_SCALAR_INT_P (op2)
2157 : 6 : || ((REG_P (op2) || MEM_P (op2))
2158 : 4 : && GET_MODE (op2) == mode)))
2159 : : return true;
2160 : :
2161 : : /* *testti_doubleword. */
2162 : 116097 : if (op2 == const0_rtx
2163 : 37005 : && GET_CODE (op1) == AND
2164 : 150 : && REG_P (XEXP (op1, 0)))
2165 : : {
2166 : 150 : rtx op12 = XEXP (op1, 1);
2167 : 150 : return GET_MODE (XEXP (op1, 0)) == TImode
2168 : 150 : && (CONST_SCALAR_INT_P (op12)
2169 : 0 : || ((REG_P (op12) || MEM_P (op12))
2170 : 0 : && GET_MODE (op12) == TImode));
2171 : : }
2172 : :
2173 : : /* *test<dwi>_not_doubleword. */
2174 : 115947 : if (op2 == const0_rtx
2175 : 36855 : && GET_CODE (op1) == AND
2176 : 0 : && GET_CODE (XEXP (op1, 0)) == NOT)
2177 : : {
2178 : 0 : rtx op11 = XEXP (XEXP (op1, 0), 0);
2179 : 0 : rtx op12 = XEXP (op1, 1);
2180 : 0 : return (REG_P (op11) || MEM_P (op11))
2181 : 0 : && (REG_P (op12) || MEM_P (op12))
2182 : 0 : && GET_MODE (op11) == mode
2183 : 0 : && GET_MODE (op12) == mode;
2184 : : }
2185 : :
2186 : : return false;
2187 : : }
2188 : :
2189 : : /* The general version of scalar_to_vector_candidate_p. */
2190 : :
2191 : : static bool
2192 : 239971100 : general_scalar_to_vector_candidate_p (rtx_insn *insn, enum machine_mode mode)
2193 : : {
2194 : 239971100 : rtx def_set = pseudo_reg_set (insn);
2195 : :
2196 : 239971100 : if (!def_set)
2197 : : return false;
2198 : :
2199 : 50044582 : rtx src = SET_SRC (def_set);
2200 : 50044582 : rtx dst = SET_DEST (def_set);
2201 : :
2202 : 50044582 : if (GET_CODE (src) == COMPARE)
2203 : 8890018 : return convertible_comparison_p (insn, mode);
2204 : :
2205 : : /* We are interested in "mode" only. */
2206 : 41154564 : if ((GET_MODE (src) != mode
2207 : 28054919 : && !CONST_INT_P (src))
2208 : 18384105 : || GET_MODE (dst) != mode)
2209 : : return false;
2210 : :
2211 : 15382949 : if (!REG_P (dst) && !MEM_P (dst))
2212 : : return false;
2213 : :
2214 : 15152350 : switch (GET_CODE (src))
2215 : : {
2216 : 532866 : case ASHIFT:
2217 : 532866 : case LSHIFTRT:
2218 : 532866 : case ASHIFTRT:
2219 : 532866 : case ROTATE:
2220 : 532866 : case ROTATERT:
2221 : 532866 : if (!CONST_INT_P (XEXP (src, 1))
2222 : 1029700 : || !IN_RANGE (INTVAL (XEXP (src, 1)), 0, GET_MODE_BITSIZE (mode)-1))
2223 : : return false;
2224 : :
2225 : : /* Check for extend highpart case. */
2226 : 496830 : if (mode != DImode
2227 : 351529 : || GET_CODE (src) != ASHIFTRT
2228 : 79515 : || GET_CODE (XEXP (src, 0)) != ASHIFT)
2229 : : break;
2230 : :
2231 : 3705447 : src = XEXP (src, 0);
2232 : : break;
2233 : :
2234 : 70023 : case SMAX:
2235 : 70023 : case SMIN:
2236 : 70023 : case UMAX:
2237 : 70023 : case UMIN:
2238 : 70023 : if ((mode == DImode && !TARGET_AVX512VL)
2239 : 17382 : || (mode == SImode && !TARGET_SSE4_1))
2240 : : return false;
2241 : : /* Fallthru. */
2242 : :
2243 : 3255736 : case AND:
2244 : 3255736 : case IOR:
2245 : 3255736 : case XOR:
2246 : 3255736 : case PLUS:
2247 : 3255736 : case MINUS:
2248 : 3255736 : if (!REG_P (XEXP (src, 1))
2249 : : && !MEM_P (XEXP (src, 1))
2250 : : && !CONST_INT_P (XEXP (src, 1)))
2251 : : return false;
2252 : :
2253 : 3156555 : if (GET_MODE (XEXP (src, 1)) != mode
2254 : 1849956 : && !CONST_INT_P (XEXP (src, 1)))
2255 : : return false;
2256 : :
2257 : : /* Check for andnot case. */
2258 : 3156555 : if (GET_CODE (src) != AND
2259 : 191132 : || GET_CODE (XEXP (src, 0)) != NOT)
2260 : : break;
2261 : :
2262 : 3705447 : src = XEXP (src, 0);
2263 : : /* FALLTHRU */
2264 : :
2265 : : case NOT:
2266 : : break;
2267 : :
2268 : 25010 : case NEG:
2269 : : /* Check for nabs case. */
2270 : 25010 : if (GET_CODE (XEXP (src, 0)) != ABS)
2271 : : break;
2272 : :
2273 : : src = XEXP (src, 0);
2274 : : /* FALLTHRU */
2275 : :
2276 : 2757 : case ABS:
2277 : 2757 : if ((mode == DImode && !TARGET_AVX512VL)
2278 : 1086 : || (mode == SImode && !TARGET_SSSE3))
2279 : : return false;
2280 : : break;
2281 : :
2282 : : case REG:
2283 : : return true;
2284 : :
2285 : 6168547 : case MEM:
2286 : 6168547 : case CONST_INT:
2287 : 6168547 : return REG_P (dst);
2288 : :
2289 : 53502 : case VEC_SELECT:
2290 : : /* Excluding MEM_P (dst) avoids intefering with vpextr[dq]. */
2291 : 53502 : return REG_P (dst)
2292 : 43175 : && REG_P (XEXP (src, 0))
2293 : 50518 : && GET_MODE (XEXP (src, 0)) == (mode == DImode ? V2DImode
2294 : : : V4SImode)
2295 : 34557 : && GET_CODE (XEXP (src, 1)) == PARALLEL
2296 : 34557 : && XVECLEN (XEXP (src, 1), 0) == 1
2297 : 88059 : && CONST_INT_P (XVECEXP (XEXP (src, 1), 0, 0));
2298 : :
2299 : : default:
2300 : : return false;
2301 : : }
2302 : :
2303 : 3705447 : if (!REG_P (XEXP (src, 0))
2304 : : && !MEM_P (XEXP (src, 0))
2305 : : && !CONST_INT_P (XEXP (src, 0)))
2306 : : return false;
2307 : :
2308 : 3403052 : if (GET_MODE (XEXP (src, 0)) != mode
2309 : 0 : && !CONST_INT_P (XEXP (src, 0)))
2310 : : return false;
2311 : :
2312 : : return true;
2313 : : }
2314 : :
2315 : : /* Check for a suitable TImode memory operand. */
2316 : :
2317 : : static bool
2318 : 12795 : timode_mem_p (rtx x)
2319 : : {
2320 : 12795 : return MEM_P (x)
2321 : 12795 : && (TARGET_SSE_UNALIGNED_LOAD_OPTIMAL
2322 : 0 : || !misaligned_operand (x, TImode));
2323 : : }
2324 : :
2325 : : /* The TImode version of scalar_to_vector_candidate_p. */
2326 : :
2327 : : static bool
2328 : 103569628 : timode_scalar_to_vector_candidate_p (rtx_insn *insn)
2329 : : {
2330 : 103569628 : rtx def_set = pseudo_reg_set (insn);
2331 : :
2332 : 103569628 : if (!def_set)
2333 : : return false;
2334 : :
2335 : 23963995 : rtx src = SET_SRC (def_set);
2336 : 23963995 : rtx dst = SET_DEST (def_set);
2337 : :
2338 : 23963995 : if (GET_CODE (src) == COMPARE)
2339 : 4028077 : return convertible_comparison_p (insn, TImode);
2340 : :
2341 : 19935918 : if (GET_MODE (dst) != TImode
2342 : 1150573 : || (GET_MODE (src) != TImode
2343 : 67834 : && !CONST_SCALAR_INT_P (src)))
2344 : : return false;
2345 : :
2346 : 1150573 : if (!REG_P (dst) && !MEM_P (dst))
2347 : : return false;
2348 : :
2349 : 1149122 : if (MEM_P (dst)
2350 : 504996 : && misaligned_operand (dst, TImode)
2351 : 1421155 : && !TARGET_SSE_UNALIGNED_STORE_OPTIMAL)
2352 : : return false;
2353 : :
2354 : 1149117 : if (REG_P (dst) && !single_def_chain_p (dst))
2355 : : return false;
2356 : :
2357 : 986870 : switch (GET_CODE (src))
2358 : : {
2359 : 453453 : case REG:
2360 : 453453 : return single_def_chain_p (src);
2361 : :
2362 : : case CONST_WIDE_INT:
2363 : : return true;
2364 : :
2365 : 12870 : case CONST_INT:
2366 : : /* ??? Verify performance impact before enabling CONST_INT for
2367 : : __int128 store. */
2368 : 12870 : return standard_sse_constant_p (src, TImode);
2369 : :
2370 : 411440 : case MEM:
2371 : : /* Memory must be aligned or unaligned load is optimal. */
2372 : 411440 : return (REG_P (dst)
2373 : 411440 : && (!misaligned_operand (src, TImode)
2374 : 105716 : || TARGET_SSE_UNALIGNED_LOAD_OPTIMAL));
2375 : :
2376 : 4826 : case AND:
2377 : 4826 : if (!MEM_P (dst)
2378 : 4789 : && GET_CODE (XEXP (src, 0)) == NOT
2379 : 0 : && REG_P (XEXP (XEXP (src, 0), 0))
2380 : 4826 : && (REG_P (XEXP (src, 1))
2381 : 0 : || CONST_SCALAR_INT_P (XEXP (src, 1))
2382 : 0 : || timode_mem_p (XEXP (src, 1))))
2383 : 0 : return true;
2384 : 4826 : return (REG_P (XEXP (src, 0))
2385 : 42 : || timode_mem_p (XEXP (src, 0)))
2386 : 4868 : && (REG_P (XEXP (src, 1))
2387 : 2979 : || CONST_SCALAR_INT_P (XEXP (src, 1))
2388 : 35 : || timode_mem_p (XEXP (src, 1)));
2389 : :
2390 : 13946 : case IOR:
2391 : 13946 : case XOR:
2392 : 13946 : return (REG_P (XEXP (src, 0))
2393 : 12671 : || timode_mem_p (XEXP (src, 0)))
2394 : 13954 : && (REG_P (XEXP (src, 1))
2395 : 267 : || CONST_SCALAR_INT_P (XEXP (src, 1))
2396 : 31 : || timode_mem_p (XEXP (src, 1)));
2397 : :
2398 : 653 : case NOT:
2399 : 653 : return REG_P (XEXP (src, 0)) || timode_mem_p (XEXP (src, 0));
2400 : :
2401 : 13127 : case ASHIFT:
2402 : 13127 : case LSHIFTRT:
2403 : 13127 : case ASHIFTRT:
2404 : 13127 : case ROTATERT:
2405 : 13127 : case ROTATE:
2406 : : /* Handle shifts/rotates by integer constants between 0 and 127. */
2407 : 13127 : return REG_P (XEXP (src, 0))
2408 : 13091 : && CONST_INT_P (XEXP (src, 1))
2409 : 25871 : && (INTVAL (XEXP (src, 1)) & ~0x7f) == 0;
2410 : :
2411 : : default:
2412 : : return false;
2413 : : }
2414 : : }
2415 : :
2416 : : /* For a register REGNO, scan instructions for its defs and uses.
2417 : : Put REGNO in REGS if a def or use isn't in CANDIDATES. */
2418 : :
2419 : : static void
2420 : 1194279 : timode_check_non_convertible_regs (bitmap candidates, bitmap regs,
2421 : : unsigned int regno)
2422 : : {
2423 : : /* Do nothing if REGNO is already in REGS or is a hard reg. */
2424 : 1194279 : if (bitmap_bit_p (regs, regno)
2425 : 1194279 : || HARD_REGISTER_NUM_P (regno))
2426 : : return;
2427 : :
2428 : 1180476 : for (df_ref def = DF_REG_DEF_CHAIN (regno);
2429 : 2329398 : def;
2430 : 1148922 : def = DF_REF_NEXT_REG (def))
2431 : : {
2432 : 1180456 : if (!bitmap_bit_p (candidates, DF_REF_INSN_UID (def)))
2433 : : {
2434 : 31534 : if (dump_file)
2435 : 0 : fprintf (dump_file,
2436 : : "r%d has non convertible def in insn %d\n",
2437 : 0 : regno, DF_REF_INSN_UID (def));
2438 : :
2439 : 31534 : bitmap_set_bit (regs, regno);
2440 : 31534 : break;
2441 : : }
2442 : : }
2443 : :
2444 : 1180476 : for (df_ref ref = DF_REG_USE_CHAIN (regno);
2445 : 2610089 : ref;
2446 : 1429613 : ref = DF_REF_NEXT_REG (ref))
2447 : : {
2448 : : /* Debug instructions are skipped. */
2449 : 1486780 : if (NONDEBUG_INSN_P (DF_REF_INSN (ref))
2450 : 1486780 : && !bitmap_bit_p (candidates, DF_REF_INSN_UID (ref)))
2451 : : {
2452 : 57167 : if (dump_file)
2453 : 0 : fprintf (dump_file,
2454 : : "r%d has non convertible use in insn %d\n",
2455 : 0 : regno, DF_REF_INSN_UID (ref));
2456 : :
2457 : 57167 : bitmap_set_bit (regs, regno);
2458 : 57167 : break;
2459 : : }
2460 : : }
2461 : : }
2462 : :
2463 : : /* For a given bitmap of insn UIDs scans all instructions and
2464 : : remove insn from CANDIDATES in case it has both convertible
2465 : : and not convertible definitions.
2466 : :
2467 : : All insns in a bitmap are conversion candidates according to
2468 : : scalar_to_vector_candidate_p. Currently it implies all insns
2469 : : are single_set. */
2470 : :
2471 : : static void
2472 : 834983 : timode_remove_non_convertible_regs (bitmap candidates)
2473 : : {
2474 : 834983 : bitmap_iterator bi;
2475 : 834983 : unsigned id;
2476 : 834983 : bitmap regs = BITMAP_ALLOC (NULL);
2477 : 859011 : bool changed;
2478 : :
2479 : 859011 : do {
2480 : 859011 : changed = false;
2481 : 2087999 : EXECUTE_IF_SET_IN_BITMAP (candidates, 0, id, bi)
2482 : : {
2483 : 1228988 : rtx_insn *insn = DF_INSN_UID_GET (id)->insn;
2484 : 1228988 : df_ref ref;
2485 : :
2486 : 1834272 : FOR_EACH_INSN_DEF (ref, insn)
2487 : 605284 : if (!DF_REF_REG_MEM_P (ref)
2488 : 605284 : && GET_MODE (DF_REF_REG (ref)) == TImode)
2489 : 581802 : timode_check_non_convertible_regs (candidates, regs,
2490 : : DF_REF_REGNO (ref));
2491 : :
2492 : 2988510 : FOR_EACH_INSN_USE (ref, insn)
2493 : 1759522 : if (!DF_REF_REG_MEM_P (ref)
2494 : 612477 : && GET_MODE (DF_REF_REG (ref)) == TImode)
2495 : 612477 : timode_check_non_convertible_regs (candidates, regs,
2496 : : DF_REF_REGNO (ref));
2497 : : }
2498 : :
2499 : 1035469 : EXECUTE_IF_SET_IN_BITMAP (regs, 0, id, bi)
2500 : : {
2501 : 176458 : for (df_ref def = DF_REG_DEF_CHAIN (id);
2502 : 360234 : def;
2503 : 183776 : def = DF_REF_NEXT_REG (def))
2504 : 183776 : if (bitmap_bit_p (candidates, DF_REF_INSN_UID (def)))
2505 : : {
2506 : 37790 : if (dump_file)
2507 : 0 : fprintf (dump_file, "Removing insn %d from candidates list\n",
2508 : 0 : DF_REF_INSN_UID (def));
2509 : :
2510 : 37790 : bitmap_clear_bit (candidates, DF_REF_INSN_UID (def));
2511 : 37790 : changed = true;
2512 : : }
2513 : :
2514 : 176458 : for (df_ref ref = DF_REG_USE_CHAIN (id);
2515 : 493226 : ref;
2516 : 316768 : ref = DF_REF_NEXT_REG (ref))
2517 : 316768 : if (bitmap_bit_p (candidates, DF_REF_INSN_UID (ref)))
2518 : : {
2519 : 43166 : if (dump_file)
2520 : 0 : fprintf (dump_file, "Removing insn %d from candidates list\n",
2521 : 0 : DF_REF_INSN_UID (ref));
2522 : :
2523 : 43166 : bitmap_clear_bit (candidates, DF_REF_INSN_UID (ref));
2524 : 43166 : changed = true;
2525 : : }
2526 : : }
2527 : : } while (changed);
2528 : :
2529 : 834983 : BITMAP_FREE (regs);
2530 : 834983 : }
2531 : :
2532 : : /* Main STV pass function. Find and convert scalar
2533 : : instructions into vector mode when profitable. */
2534 : :
2535 : : static unsigned int
2536 : 1795368 : convert_scalars_to_vector (bool timode_p)
2537 : : {
2538 : 1795368 : basic_block bb;
2539 : 1795368 : int converted_insns = 0;
2540 : 1795368 : auto_vec<rtx_insn *> control_flow_insns;
2541 : :
2542 : 1795368 : bitmap_obstack_initialize (NULL);
2543 : 1795368 : const machine_mode cand_mode[3] = { SImode, DImode, TImode };
2544 : 1795368 : const machine_mode cand_vmode[3] = { V4SImode, V2DImode, V1TImode };
2545 : 5386104 : bitmap_head candidates[3]; /* { SImode, DImode, TImode } */
2546 : 7181472 : for (unsigned i = 0; i < 3; ++i)
2547 : 5386104 : bitmap_initialize (&candidates[i], &bitmap_default_obstack);
2548 : :
2549 : 1795368 : calculate_dominance_info (CDI_DOMINATORS);
2550 : 1795368 : df_set_flags (DF_DEFER_INSN_RESCAN | DF_RD_PRUNE_DEAD_DEFS);
2551 : 1795368 : df_chain_add_problem (DF_DU_CHAIN | DF_UD_CHAIN);
2552 : 1795368 : df_analyze ();
2553 : :
2554 : : /* Find all instructions we want to convert into vector mode. */
2555 : 1795368 : if (dump_file)
2556 : 44 : fprintf (dump_file, "Searching for mode conversion candidates...\n");
2557 : :
2558 : 20062311 : FOR_EACH_BB_FN (bb, cfun)
2559 : : {
2560 : 18266943 : rtx_insn *insn;
2561 : 243627168 : FOR_BB_INSNS (bb, insn)
2562 : 225360225 : if (timode_p
2563 : 225360225 : && timode_scalar_to_vector_candidate_p (insn))
2564 : : {
2565 : 936696 : if (dump_file)
2566 : 0 : fprintf (dump_file, " insn %d is marked as a TImode candidate\n",
2567 : 0 : INSN_UID (insn));
2568 : :
2569 : 936696 : bitmap_set_bit (&candidates[2], INSN_UID (insn));
2570 : : }
2571 : 224423529 : else if (!timode_p)
2572 : : {
2573 : : /* Check {SI,DI}mode. */
2574 : 349877830 : for (unsigned i = 0; i <= 1; ++i)
2575 : 239971100 : if (general_scalar_to_vector_candidate_p (insn, cand_mode[i]))
2576 : : {
2577 : 11883867 : if (dump_file)
2578 : 554 : fprintf (dump_file, " insn %d is marked as a %s candidate\n",
2579 : 277 : INSN_UID (insn), i == 0 ? "SImode" : "DImode");
2580 : :
2581 : 11883867 : bitmap_set_bit (&candidates[i], INSN_UID (insn));
2582 : 11883867 : break;
2583 : : }
2584 : : }
2585 : : }
2586 : :
2587 : 1795368 : if (timode_p)
2588 : 834983 : timode_remove_non_convertible_regs (&candidates[2]);
2589 : :
2590 : 5683180 : for (unsigned i = 0; i <= 2; ++i)
2591 : 4525870 : if (!bitmap_empty_p (&candidates[i]))
2592 : : break;
2593 : 3887812 : else if (i == 2 && dump_file)
2594 : 23 : fprintf (dump_file, "There are no candidates for optimization.\n");
2595 : :
2596 : 7181472 : for (unsigned i = 0; i <= 2; ++i)
2597 : : {
2598 : 5386104 : auto_bitmap disallowed;
2599 : 5386104 : bitmap_tree_view (&candidates[i]);
2600 : 17273517 : while (!bitmap_empty_p (&candidates[i]))
2601 : : {
2602 : 6501309 : unsigned uid = bitmap_first_set_bit (&candidates[i]);
2603 : 6501309 : scalar_chain *chain;
2604 : :
2605 : 6501309 : if (cand_mode[i] == TImode)
2606 : 439415 : chain = new timode_scalar_chain;
2607 : : else
2608 : 6061894 : chain = new general_scalar_chain (cand_mode[i], cand_vmode[i]);
2609 : :
2610 : : /* Find instructions chain we want to convert to vector mode.
2611 : : Check all uses and definitions to estimate all required
2612 : : conversions. */
2613 : 6501309 : if (chain->build (&candidates[i], uid, disallowed))
2614 : : {
2615 : 6500792 : if (chain->compute_convert_gain ())
2616 : 612100 : converted_insns += chain->convert ();
2617 : 5888692 : else if (dump_file)
2618 : 136 : fprintf (dump_file, "Chain #%d conversion is not profitable\n",
2619 : : chain->chain_id);
2620 : : }
2621 : :
2622 : 6501309 : rtx_insn* iter_insn;
2623 : 6501309 : unsigned int ii;
2624 : 6505066 : FOR_EACH_VEC_ELT (chain->control_flow_insns, ii, iter_insn)
2625 : 3757 : control_flow_insns.safe_push (iter_insn);
2626 : :
2627 : 6501309 : delete chain;
2628 : : }
2629 : 5386104 : }
2630 : :
2631 : 1795368 : if (dump_file)
2632 : 44 : fprintf (dump_file, "Total insns converted: %d\n", converted_insns);
2633 : :
2634 : 7181472 : for (unsigned i = 0; i <= 2; ++i)
2635 : 5386104 : bitmap_release (&candidates[i]);
2636 : 1795368 : bitmap_obstack_release (NULL);
2637 : 1795368 : df_process_deferred_rescans ();
2638 : :
2639 : : /* Conversion means we may have 128bit register spills/fills
2640 : : which require aligned stack. */
2641 : 1795368 : if (converted_insns)
2642 : : {
2643 : 105627 : if (crtl->stack_alignment_needed < 128)
2644 : 2229 : crtl->stack_alignment_needed = 128;
2645 : 105627 : if (crtl->stack_alignment_estimated < 128)
2646 : 194 : crtl->stack_alignment_estimated = 128;
2647 : :
2648 : 105627 : crtl->stack_realign_needed
2649 : 105627 : = INCOMING_STACK_BOUNDARY < crtl->stack_alignment_estimated;
2650 : 105627 : crtl->stack_realign_tried = crtl->stack_realign_needed;
2651 : :
2652 : 105627 : crtl->stack_realign_processed = true;
2653 : :
2654 : 105627 : if (!crtl->drap_reg)
2655 : : {
2656 : 105481 : rtx drap_rtx = targetm.calls.get_drap_rtx ();
2657 : :
2658 : : /* stack_realign_drap and drap_rtx must match. */
2659 : 105481 : gcc_assert ((stack_realign_drap != 0) == (drap_rtx != NULL));
2660 : :
2661 : : /* Do nothing if NULL is returned,
2662 : : which means DRAP is not needed. */
2663 : 105481 : if (drap_rtx != NULL)
2664 : : {
2665 : 0 : crtl->args.internal_arg_pointer = drap_rtx;
2666 : :
2667 : : /* Call fixup_tail_calls to clean up
2668 : : REG_EQUIV note if DRAP is needed. */
2669 : 0 : fixup_tail_calls ();
2670 : : }
2671 : : }
2672 : :
2673 : : /* Fix up DECL_RTL/DECL_INCOMING_RTL of arguments. */
2674 : 105627 : if (TARGET_64BIT)
2675 : 67233 : for (tree parm = DECL_ARGUMENTS (current_function_decl);
2676 : 186531 : parm; parm = DECL_CHAIN (parm))
2677 : : {
2678 : 119298 : if (TYPE_MODE (TREE_TYPE (parm)) != TImode)
2679 : 102918 : continue;
2680 : 16380 : if (DECL_RTL_SET_P (parm)
2681 : 32760 : && GET_MODE (DECL_RTL (parm)) == V1TImode)
2682 : : {
2683 : 324 : rtx r = DECL_RTL (parm);
2684 : 324 : if (REG_P (r))
2685 : 324 : SET_DECL_RTL (parm, gen_rtx_SUBREG (TImode, r, 0));
2686 : : }
2687 : 16380 : if (DECL_INCOMING_RTL (parm)
2688 : 16380 : && GET_MODE (DECL_INCOMING_RTL (parm)) == V1TImode)
2689 : : {
2690 : 0 : rtx r = DECL_INCOMING_RTL (parm);
2691 : 0 : if (REG_P (r))
2692 : 0 : DECL_INCOMING_RTL (parm) = gen_rtx_SUBREG (TImode, r, 0);
2693 : : }
2694 : : }
2695 : :
2696 : 105627 : if (!control_flow_insns.is_empty ())
2697 : : {
2698 : 1170 : free_dominance_info (CDI_DOMINATORS);
2699 : :
2700 : 1170 : unsigned int i;
2701 : 1170 : rtx_insn* insn;
2702 : 6097 : FOR_EACH_VEC_ELT (control_flow_insns, i, insn)
2703 : 3757 : if (control_flow_insn_p (insn))
2704 : : {
2705 : : /* Split the block after insn. There will be a fallthru
2706 : : edge, which is OK so we keep it. We have to create
2707 : : the exception edges ourselves. */
2708 : 3757 : bb = BLOCK_FOR_INSN (insn);
2709 : 3757 : split_block (bb, insn);
2710 : 3757 : rtl_make_eh_edge (NULL, bb, BB_END (bb));
2711 : : }
2712 : : }
2713 : : }
2714 : :
2715 : 1795368 : return 0;
2716 : 1795368 : }
2717 : :
2718 : : static unsigned int
2719 : 72727 : rest_of_handle_insert_vzeroupper (void)
2720 : : {
2721 : : /* vzeroupper instructions are inserted immediately after reload and
2722 : : postreload_cse to clean up after it a little bit to account for possible
2723 : : spills from 256bit or 512bit registers. The pass reuses mode switching
2724 : : infrastructure by re-running mode insertion pass, so disable entities
2725 : : that have already been processed. */
2726 : 509089 : for (int i = 0; i < MAX_386_ENTITIES; i++)
2727 : 436362 : ix86_optimize_mode_switching[i] = 0;
2728 : :
2729 : 72727 : ix86_optimize_mode_switching[AVX_U128] = 1;
2730 : :
2731 : : /* Call optimize_mode_switching. */
2732 : 72727 : g->get_passes ()->execute_pass_mode_switching ();
2733 : :
2734 : : /* LRA removes all REG_DEAD/REG_UNUSED notes and normally they
2735 : : reappear in the IL only at the start of pass_rtl_dse2, which does
2736 : : df_note_add_problem (); df_analyze ();
2737 : : The vzeroupper is scheduled after postreload_cse pass and mode
2738 : : switching computes the notes as well, the problem is that e.g.
2739 : : pass_gcse2 doesn't maintain the notes, see PR113059 and
2740 : : PR112760. Remove the notes now to restore status quo ante
2741 : : until we figure out how to maintain the notes or what else
2742 : : to do. */
2743 : 72727 : basic_block bb;
2744 : 72727 : rtx_insn *insn;
2745 : 396332 : FOR_EACH_BB_FN (bb, cfun)
2746 : 4245809 : FOR_BB_INSNS (bb, insn)
2747 : 3922204 : if (NONDEBUG_INSN_P (insn))
2748 : : {
2749 : 2050257 : rtx *pnote = ®_NOTES (insn);
2750 : 3788051 : while (*pnote != 0)
2751 : : {
2752 : 1737794 : if (REG_NOTE_KIND (*pnote) == REG_DEAD
2753 : 792302 : || REG_NOTE_KIND (*pnote) == REG_UNUSED)
2754 : 1252760 : *pnote = XEXP (*pnote, 1);
2755 : : else
2756 : 485034 : pnote = &XEXP (*pnote, 1);
2757 : : }
2758 : : }
2759 : :
2760 : 72727 : df_remove_problem (df_note);
2761 : 72727 : df_analyze ();
2762 : 72727 : return 0;
2763 : : }
2764 : :
2765 : : namespace {
2766 : :
2767 : : const pass_data pass_data_insert_vzeroupper =
2768 : : {
2769 : : RTL_PASS, /* type */
2770 : : "vzeroupper", /* name */
2771 : : OPTGROUP_NONE, /* optinfo_flags */
2772 : : TV_MACH_DEP, /* tv_id */
2773 : : 0, /* properties_required */
2774 : : 0, /* properties_provided */
2775 : : 0, /* properties_destroyed */
2776 : : 0, /* todo_flags_start */
2777 : : TODO_df_finish, /* todo_flags_finish */
2778 : : };
2779 : :
2780 : : class pass_insert_vzeroupper : public rtl_opt_pass
2781 : : {
2782 : : public:
2783 : 285689 : pass_insert_vzeroupper(gcc::context *ctxt)
2784 : 571378 : : rtl_opt_pass(pass_data_insert_vzeroupper, ctxt)
2785 : : {}
2786 : :
2787 : : /* opt_pass methods: */
2788 : 1481340 : bool gate (function *) final override
2789 : : {
2790 : 1481340 : return TARGET_AVX && TARGET_VZEROUPPER;
2791 : : }
2792 : :
2793 : 72727 : unsigned int execute (function *) final override
2794 : : {
2795 : 72727 : return rest_of_handle_insert_vzeroupper ();
2796 : : }
2797 : :
2798 : : }; // class pass_insert_vzeroupper
2799 : :
2800 : : const pass_data pass_data_stv =
2801 : : {
2802 : : RTL_PASS, /* type */
2803 : : "stv", /* name */
2804 : : OPTGROUP_NONE, /* optinfo_flags */
2805 : : TV_MACH_DEP, /* tv_id */
2806 : : 0, /* properties_required */
2807 : : 0, /* properties_provided */
2808 : : 0, /* properties_destroyed */
2809 : : 0, /* todo_flags_start */
2810 : : TODO_df_finish, /* todo_flags_finish */
2811 : : };
2812 : :
2813 : : class pass_stv : public rtl_opt_pass
2814 : : {
2815 : : public:
2816 : 571378 : pass_stv (gcc::context *ctxt)
2817 : 571378 : : rtl_opt_pass (pass_data_stv, ctxt),
2818 : 1142756 : timode_p (false)
2819 : : {}
2820 : :
2821 : : /* opt_pass methods: */
2822 : 2962680 : bool gate (function *) final override
2823 : : {
2824 : 1481340 : return ((!timode_p || TARGET_64BIT)
2825 : 4318299 : && TARGET_STV && TARGET_SSE2 && optimize > 1);
2826 : : }
2827 : :
2828 : 1795368 : unsigned int execute (function *) final override
2829 : : {
2830 : 1795368 : return convert_scalars_to_vector (timode_p);
2831 : : }
2832 : :
2833 : 285689 : opt_pass *clone () final override
2834 : : {
2835 : 285689 : return new pass_stv (m_ctxt);
2836 : : }
2837 : :
2838 : 571378 : void set_pass_param (unsigned int n, bool param) final override
2839 : : {
2840 : 571378 : gcc_assert (n == 0);
2841 : 571378 : timode_p = param;
2842 : 571378 : }
2843 : :
2844 : : private:
2845 : : bool timode_p;
2846 : : }; // class pass_stv
2847 : :
2848 : : } // anon namespace
2849 : :
2850 : : rtl_opt_pass *
2851 : 285689 : make_pass_insert_vzeroupper (gcc::context *ctxt)
2852 : : {
2853 : 285689 : return new pass_insert_vzeroupper (ctxt);
2854 : : }
2855 : :
2856 : : rtl_opt_pass *
2857 : 285689 : make_pass_stv (gcc::context *ctxt)
2858 : : {
2859 : 285689 : return new pass_stv (ctxt);
2860 : : }
2861 : :
2862 : : /* Inserting ENDBR and pseudo patchable-area instructions. */
2863 : :
2864 : : static void
2865 : 210846 : rest_of_insert_endbr_and_patchable_area (bool need_endbr,
2866 : : unsigned int patchable_area_size)
2867 : : {
2868 : 210846 : rtx endbr;
2869 : 210846 : rtx_insn *insn;
2870 : 210846 : rtx_insn *endbr_insn = NULL;
2871 : 210846 : basic_block bb;
2872 : :
2873 : 210846 : if (need_endbr)
2874 : : {
2875 : : /* Currently emit EB if it's a tracking function, i.e. 'nocf_check'
2876 : : is absent among function attributes. Later an optimization will
2877 : : be introduced to make analysis if an address of a static function
2878 : : is taken. A static function whose address is not taken will get
2879 : : a nocf_check attribute. This will allow to reduce the number of
2880 : : EB. */
2881 : 210801 : if (!lookup_attribute ("nocf_check",
2882 : 210801 : TYPE_ATTRIBUTES (TREE_TYPE (cfun->decl)))
2883 : 210791 : && (!flag_manual_endbr
2884 : 8 : || lookup_attribute ("cf_check",
2885 : 8 : DECL_ATTRIBUTES (cfun->decl)))
2886 : 421591 : && (!cgraph_node::get (cfun->decl)->only_called_directly_p ()
2887 : 30199 : || ix86_cmodel == CM_LARGE
2888 : 30198 : || ix86_cmodel == CM_LARGE_PIC
2889 : 30197 : || flag_force_indirect_call
2890 : 30197 : || (TARGET_DLLIMPORT_DECL_ATTRIBUTES
2891 : : && DECL_DLLIMPORT_P (cfun->decl))))
2892 : : {
2893 : 180594 : if (crtl->profile && flag_fentry)
2894 : : {
2895 : : /* Queue ENDBR insertion to x86_function_profiler.
2896 : : NB: Any patchable-area insn will be inserted after
2897 : : ENDBR. */
2898 : 6 : cfun->machine->insn_queued_at_entrance = TYPE_ENDBR;
2899 : : }
2900 : : else
2901 : : {
2902 : 180588 : endbr = gen_nop_endbr ();
2903 : 180588 : bb = ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb;
2904 : 180588 : rtx_insn *insn = BB_HEAD (bb);
2905 : 180588 : endbr_insn = emit_insn_before (endbr, insn);
2906 : : }
2907 : : }
2908 : : }
2909 : :
2910 : 210846 : if (patchable_area_size)
2911 : : {
2912 : 51 : if (crtl->profile && flag_fentry)
2913 : : {
2914 : : /* Queue patchable-area insertion to x86_function_profiler.
2915 : : NB: If there is a queued ENDBR, x86_function_profiler
2916 : : will also handle patchable-area. */
2917 : 2 : if (!cfun->machine->insn_queued_at_entrance)
2918 : 1 : cfun->machine->insn_queued_at_entrance = TYPE_PATCHABLE_AREA;
2919 : : }
2920 : : else
2921 : : {
2922 : 49 : rtx patchable_area
2923 : 49 : = gen_patchable_area (GEN_INT (patchable_area_size),
2924 : 49 : GEN_INT (crtl->patch_area_entry == 0));
2925 : 49 : if (endbr_insn)
2926 : 3 : emit_insn_after (patchable_area, endbr_insn);
2927 : : else
2928 : : {
2929 : 46 : bb = ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb;
2930 : 46 : insn = BB_HEAD (bb);
2931 : 46 : emit_insn_before (patchable_area, insn);
2932 : : }
2933 : : }
2934 : : }
2935 : :
2936 : 210846 : if (!need_endbr)
2937 : : return;
2938 : :
2939 : 210801 : bb = 0;
2940 : 4312106 : FOR_EACH_BB_FN (bb, cfun)
2941 : : {
2942 : 76836369 : for (insn = BB_HEAD (bb); insn != NEXT_INSN (BB_END (bb));
2943 : 72735064 : insn = NEXT_INSN (insn))
2944 : : {
2945 : 72735064 : if (CALL_P (insn))
2946 : : {
2947 : 1474478 : need_endbr = find_reg_note (insn, REG_SETJMP, NULL) != NULL;
2948 : 1474478 : if (!need_endbr && !SIBLING_CALL_P (insn))
2949 : : {
2950 : 1421815 : rtx call = get_call_rtx_from (insn);
2951 : 1421815 : rtx fnaddr = XEXP (call, 0);
2952 : 1421815 : tree fndecl = NULL_TREE;
2953 : :
2954 : : /* Also generate ENDBRANCH for non-tail call which
2955 : : may return via indirect branch. */
2956 : 1421815 : if (SYMBOL_REF_P (XEXP (fnaddr, 0)))
2957 : 1352090 : fndecl = SYMBOL_REF_DECL (XEXP (fnaddr, 0));
2958 : 1352090 : if (fndecl == NULL_TREE)
2959 : 70113 : fndecl = MEM_EXPR (fnaddr);
2960 : 70113 : if (fndecl
2961 : 1419618 : && TREE_CODE (TREE_TYPE (fndecl)) != FUNCTION_TYPE
2962 : 665844 : && TREE_CODE (TREE_TYPE (fndecl)) != METHOD_TYPE)
2963 : : fndecl = NULL_TREE;
2964 : 1421815 : if (fndecl && TYPE_ARG_TYPES (TREE_TYPE (fndecl)))
2965 : : {
2966 : 1378983 : tree fntype = TREE_TYPE (fndecl);
2967 : 1378983 : if (lookup_attribute ("indirect_return",
2968 : 1378983 : TYPE_ATTRIBUTES (fntype)))
2969 : : need_endbr = true;
2970 : : }
2971 : : }
2972 : 1474466 : if (!need_endbr)
2973 : 1474460 : continue;
2974 : : /* Generate ENDBRANCH after CALL, which can return more than
2975 : : twice, setjmp-like functions. */
2976 : :
2977 : 18 : endbr = gen_nop_endbr ();
2978 : 18 : emit_insn_after_setloc (endbr, insn, INSN_LOCATION (insn));
2979 : 18 : continue;
2980 : 18 : }
2981 : :
2982 : 71260586 : if (JUMP_P (insn) && flag_cet_switch)
2983 : : {
2984 : 9 : rtx target = JUMP_LABEL (insn);
2985 : 9 : if (target == NULL_RTX || ANY_RETURN_P (target))
2986 : 5 : continue;
2987 : :
2988 : : /* Check the jump is a switch table. */
2989 : 4 : rtx_insn *label = as_a<rtx_insn *> (target);
2990 : 4 : rtx_insn *table = next_insn (label);
2991 : 4 : if (table == NULL_RTX || !JUMP_TABLE_DATA_P (table))
2992 : 2 : continue;
2993 : :
2994 : : /* For the indirect jump find out all places it jumps and insert
2995 : : ENDBRANCH there. It should be done under a special flag to
2996 : : control ENDBRANCH generation for switch stmts. */
2997 : 2 : edge_iterator ei;
2998 : 2 : edge e;
2999 : 2 : basic_block dest_blk;
3000 : :
3001 : 24 : FOR_EACH_EDGE (e, ei, bb->succs)
3002 : : {
3003 : 22 : rtx_insn *insn;
3004 : :
3005 : 22 : dest_blk = e->dest;
3006 : 22 : insn = BB_HEAD (dest_blk);
3007 : 22 : gcc_assert (LABEL_P (insn));
3008 : 22 : endbr = gen_nop_endbr ();
3009 : 22 : emit_insn_after (endbr, insn);
3010 : : }
3011 : 2 : continue;
3012 : 2 : }
3013 : :
3014 : 71260577 : if (LABEL_P (insn) && LABEL_PRESERVE_P (insn))
3015 : : {
3016 : 157108 : endbr = gen_nop_endbr ();
3017 : 157108 : emit_insn_after (endbr, insn);
3018 : 157108 : continue;
3019 : : }
3020 : : }
3021 : : }
3022 : :
3023 : : return;
3024 : : }
3025 : :
3026 : : namespace {
3027 : :
3028 : : const pass_data pass_data_insert_endbr_and_patchable_area =
3029 : : {
3030 : : RTL_PASS, /* type. */
3031 : : "endbr_and_patchable_area", /* name. */
3032 : : OPTGROUP_NONE, /* optinfo_flags. */
3033 : : TV_MACH_DEP, /* tv_id. */
3034 : : 0, /* properties_required. */
3035 : : 0, /* properties_provided. */
3036 : : 0, /* properties_destroyed. */
3037 : : 0, /* todo_flags_start. */
3038 : : 0, /* todo_flags_finish. */
3039 : : };
3040 : :
3041 : : class pass_insert_endbr_and_patchable_area : public rtl_opt_pass
3042 : : {
3043 : : public:
3044 : 285689 : pass_insert_endbr_and_patchable_area (gcc::context *ctxt)
3045 : 571378 : : rtl_opt_pass (pass_data_insert_endbr_and_patchable_area, ctxt)
3046 : : {}
3047 : :
3048 : : /* opt_pass methods: */
3049 : 1481340 : bool gate (function *) final override
3050 : : {
3051 : 1481340 : need_endbr = (flag_cf_protection & CF_BRANCH) != 0;
3052 : 1481340 : patchable_area_size = crtl->patch_area_size - crtl->patch_area_entry;
3053 : 1481340 : return need_endbr || patchable_area_size;
3054 : : }
3055 : :
3056 : 210846 : unsigned int execute (function *) final override
3057 : : {
3058 : 210846 : timevar_push (TV_MACH_DEP);
3059 : 210846 : rest_of_insert_endbr_and_patchable_area (need_endbr,
3060 : : patchable_area_size);
3061 : 210846 : timevar_pop (TV_MACH_DEP);
3062 : 210846 : return 0;
3063 : : }
3064 : :
3065 : : private:
3066 : : bool need_endbr;
3067 : : unsigned int patchable_area_size;
3068 : : }; // class pass_insert_endbr_and_patchable_area
3069 : :
3070 : : } // anon namespace
3071 : :
3072 : : rtl_opt_pass *
3073 : 285689 : make_pass_insert_endbr_and_patchable_area (gcc::context *ctxt)
3074 : : {
3075 : 285689 : return new pass_insert_endbr_and_patchable_area (ctxt);
3076 : : }
3077 : :
3078 : : bool
3079 : 6045048 : ix86_rpad_gate ()
3080 : : {
3081 : 6045048 : return (TARGET_AVX
3082 : 402856 : && TARGET_SSE_PARTIAL_REG_DEPENDENCY
3083 : 308205 : && TARGET_SSE_MATH
3084 : 307983 : && optimize
3085 : 6348031 : && optimize_function_for_speed_p (cfun));
3086 : : }
3087 : :
3088 : : enum x86_cse_kind
3089 : : {
3090 : : X86_CSE_CONST0_VECTOR,
3091 : : X86_CSE_CONSTM1_VECTOR,
3092 : : X86_CSE_VEC_DUP,
3093 : : X86_CSE_TLS_GD,
3094 : : X86_CSE_TLS_LD_BASE,
3095 : : X86_CSE_TLSDESC
3096 : : };
3097 : :
3098 : 117818 : struct redundant_pattern
3099 : : {
3100 : : /* Bitmap of basic blocks with broadcast instructions. */
3101 : : auto_bitmap bbs;
3102 : : /* Bitmap of broadcast instructions. */
3103 : : auto_bitmap insns;
3104 : : /* The broadcast inner scalar. */
3105 : : rtx val;
3106 : : /* The actual redundant source value for UNSPEC_TLSDESC. */
3107 : : rtx tlsdesc_val;
3108 : : /* The inner scalar mode. */
3109 : : machine_mode mode;
3110 : : /* The instruction which sets the inner scalar. Nullptr if the inner
3111 : : scalar is applied to the whole function, instead of within the same
3112 : : block. */
3113 : : rtx_insn *def_insn;
3114 : : /* The widest broadcast source. */
3115 : : rtx broadcast_source;
3116 : : /* The widest broadcast register. */
3117 : : rtx broadcast_reg;
3118 : : /* The basic block of the broadcast instruction. */
3119 : : basic_block bb;
3120 : : /* The number of broadcast instructions with the same inner scalar. */
3121 : : unsigned HOST_WIDE_INT count;
3122 : : /* The threshold of broadcast instructions with the same inner
3123 : : scalar. */
3124 : : unsigned int threshold;
3125 : : /* The widest broadcast size in bytes. */
3126 : : unsigned int size;
3127 : : /* Load kind. */
3128 : : x86_cse_kind kind;
3129 : : };
3130 : :
3131 : : /* Generate a vector set, DEST = SRC, at entry of the nearest dominator
3132 : : for basic block map BBS, which is in the fake loop that contains the
3133 : : whole function, so that there is only a single vector set in the
3134 : : whole function. If not nullptr, LOAD is a pointer to the load. */
3135 : :
3136 : : static void
3137 : 30681 : ix86_place_single_vector_set (rtx dest, rtx src, bitmap bbs,
3138 : : redundant_pattern *load = nullptr)
3139 : : {
3140 : 30681 : basic_block bb = nearest_common_dominator_for_set (CDI_DOMINATORS, bbs);
3141 : : /* For X86_CSE_VEC_DUP, don't place the vector set outside of the loop
3142 : : to avoid extra spills. */
3143 : 30681 : if (!load || load->kind != X86_CSE_VEC_DUP)
3144 : : {
3145 : 22130 : while (bb->loop_father->latch
3146 : 22130 : != EXIT_BLOCK_PTR_FOR_FN (cfun))
3147 : 1366 : bb = get_immediate_dominator (CDI_DOMINATORS,
3148 : : bb->loop_father->header);
3149 : : }
3150 : :
3151 : 30681 : rtx set = gen_rtx_SET (dest, src);
3152 : :
3153 : 30681 : rtx_insn *insn = BB_HEAD (bb);
3154 : 131389 : while (insn && !NONDEBUG_INSN_P (insn))
3155 : : {
3156 : 100712 : if (insn == BB_END (bb))
3157 : : {
3158 : : insn = NULL;
3159 : : break;
3160 : : }
3161 : 100708 : insn = NEXT_INSN (insn);
3162 : : }
3163 : :
3164 : 30681 : rtx_insn *set_insn;
3165 : 30681 : if (insn == BB_HEAD (bb))
3166 : : {
3167 : 0 : set_insn = emit_insn_before (set, insn);
3168 : 0 : if (dump_file)
3169 : : {
3170 : 0 : fprintf (dump_file, "\nPlace:\n\n");
3171 : 0 : print_rtl_single (dump_file, set_insn);
3172 : 0 : fprintf (dump_file, "\nbefore:\n\n");
3173 : 0 : print_rtl_single (dump_file, insn);
3174 : 0 : fprintf (dump_file, "\n");
3175 : : }
3176 : : }
3177 : : else
3178 : : {
3179 : 30681 : rtx_insn *after = insn ? PREV_INSN (insn) : BB_END (bb);
3180 : 30681 : set_insn = emit_insn_after (set, after);
3181 : 30681 : if (dump_file)
3182 : : {
3183 : 0 : fprintf (dump_file, "\nPlace:\n\n");
3184 : 0 : print_rtl_single (dump_file, set_insn);
3185 : 0 : fprintf (dump_file, "\nafter:\n\n");
3186 : 0 : print_rtl_single (dump_file, after);
3187 : 0 : fprintf (dump_file, "\n");
3188 : : }
3189 : : }
3190 : :
3191 : 30681 : if (load && load->kind == X86_CSE_VEC_DUP)
3192 : : {
3193 : : /* Get the source from LOAD as (reg:SI 99) in
3194 : :
3195 : : (vec_duplicate:V4SI (reg:SI 99))
3196 : :
3197 : : */
3198 : 9917 : rtx inner_scalar = load->val;
3199 : : /* Set the source in (vec_duplicate:V4SI (reg:SI 99)). */
3200 : 9917 : rtx reg = XEXP (src, 0);
3201 : 9917 : if ((REG_P (inner_scalar) || MEM_P (inner_scalar))
3202 : 254 : && GET_MODE (reg) != GET_MODE (inner_scalar))
3203 : 0 : inner_scalar = gen_rtx_SUBREG (GET_MODE (reg), inner_scalar, 0);
3204 : 9917 : rtx set = gen_rtx_SET (reg, inner_scalar);
3205 : 9917 : insn = emit_insn_before (set, set_insn);
3206 : 9917 : if (dump_file)
3207 : : {
3208 : 0 : fprintf (dump_file, "\nAdd:\n\n");
3209 : 0 : print_rtl_single (dump_file, insn);
3210 : 0 : fprintf (dump_file, "\nbefore:\n\n");
3211 : 0 : print_rtl_single (dump_file, set_insn);
3212 : 0 : fprintf (dump_file, "\n");
3213 : : }
3214 : : }
3215 : 30681 : }
3216 : :
3217 : : /* At entry of the nearest common dominator for basic blocks with
3218 : : conversions/rcp/sqrt/rsqrt/round, generate a single
3219 : : vxorps %xmmN, %xmmN, %xmmN
3220 : : for all
3221 : : vcvtss2sd op, %xmmN, %xmmX
3222 : : vcvtsd2ss op, %xmmN, %xmmX
3223 : : vcvtsi2ss op, %xmmN, %xmmX
3224 : : vcvtsi2sd op, %xmmN, %xmmX
3225 : :
3226 : : NB: We want to generate only a single vxorps to cover the whole
3227 : : function. The LCM algorithm isn't appropriate here since it may
3228 : : place a vxorps inside the loop. */
3229 : :
3230 : : static unsigned int
3231 : 31637 : remove_partial_avx_dependency (void)
3232 : : {
3233 : 31637 : timevar_push (TV_MACH_DEP);
3234 : :
3235 : 31637 : bitmap_obstack_initialize (NULL);
3236 : 31637 : bitmap convert_bbs = BITMAP_ALLOC (NULL);
3237 : :
3238 : 31637 : basic_block bb;
3239 : 31637 : rtx_insn *insn, *set_insn;
3240 : 31637 : rtx set;
3241 : 31637 : rtx v4sf_const0 = NULL_RTX;
3242 : :
3243 : 31637 : auto_vec<rtx_insn *> control_flow_insns;
3244 : :
3245 : : /* We create invalid RTL initially so defer rescans. */
3246 : 31637 : df_set_flags (DF_DEFER_INSN_RESCAN);
3247 : :
3248 : 299518 : FOR_EACH_BB_FN (bb, cfun)
3249 : : {
3250 : 3485267 : FOR_BB_INSNS (bb, insn)
3251 : : {
3252 : 3217386 : if (!NONDEBUG_INSN_P (insn))
3253 : 1471356 : continue;
3254 : :
3255 : 1746030 : set = single_set (insn);
3256 : 1746030 : if (!set)
3257 : 65372 : continue;
3258 : :
3259 : 1680658 : if (get_attr_avx_partial_xmm_update (insn)
3260 : : != AVX_PARTIAL_XMM_UPDATE_TRUE)
3261 : 1677676 : continue;
3262 : :
3263 : : /* Convert PARTIAL_XMM_UPDATE_TRUE insns, DF -> SF, SF -> DF,
3264 : : SI -> SF, SI -> DF, DI -> SF, DI -> DF, sqrt, rsqrt, rcp,
3265 : : round, to vec_dup and vec_merge with subreg. */
3266 : 2982 : rtx src = SET_SRC (set);
3267 : 2982 : rtx dest = SET_DEST (set);
3268 : 2982 : machine_mode dest_mode = GET_MODE (dest);
3269 : 2982 : bool convert_p = false;
3270 : 2982 : switch (GET_CODE (src))
3271 : : {
3272 : 2877 : case FLOAT:
3273 : 2877 : case FLOAT_EXTEND:
3274 : 2877 : case FLOAT_TRUNCATE:
3275 : 2877 : case UNSIGNED_FLOAT:
3276 : 2877 : convert_p = true;
3277 : 2877 : break;
3278 : : default:
3279 : : break;
3280 : : }
3281 : :
3282 : : /* Only handle conversion here. */
3283 : 2877 : machine_mode src_mode
3284 : 2877 : = convert_p ? GET_MODE (XEXP (src, 0)) : VOIDmode;
3285 : 2877 : switch (src_mode)
3286 : : {
3287 : 172 : case E_SFmode:
3288 : 172 : case E_DFmode:
3289 : 172 : if (TARGET_USE_VECTOR_FP_CONVERTS
3290 : 166 : || !TARGET_SSE_PARTIAL_REG_FP_CONVERTS_DEPENDENCY)
3291 : 8 : continue;
3292 : : break;
3293 : 2705 : case E_SImode:
3294 : 2705 : case E_DImode:
3295 : 2705 : if (TARGET_USE_VECTOR_CONVERTS
3296 : 2693 : || !TARGET_SSE_PARTIAL_REG_CONVERTS_DEPENDENCY)
3297 : 14 : continue;
3298 : : break;
3299 : 105 : case E_VOIDmode:
3300 : 105 : gcc_assert (!convert_p);
3301 : : break;
3302 : 0 : default:
3303 : 0 : gcc_unreachable ();
3304 : : }
3305 : :
3306 : 2960 : if (!v4sf_const0)
3307 : 961 : v4sf_const0 = gen_reg_rtx (V4SFmode);
3308 : :
3309 : 2960 : rtx zero;
3310 : 2960 : machine_mode dest_vecmode;
3311 : 2960 : switch (dest_mode)
3312 : : {
3313 : 90 : case E_HFmode:
3314 : 90 : dest_vecmode = V8HFmode;
3315 : 90 : zero = gen_rtx_SUBREG (V8HFmode, v4sf_const0, 0);
3316 : 90 : break;
3317 : : case E_SFmode:
3318 : : dest_vecmode = V4SFmode;
3319 : : zero = v4sf_const0;
3320 : : break;
3321 : 1011 : case E_DFmode:
3322 : 1011 : dest_vecmode = V2DFmode;
3323 : 1011 : zero = gen_rtx_SUBREG (V2DFmode, v4sf_const0, 0);
3324 : 1011 : break;
3325 : 0 : default:
3326 : 0 : gcc_unreachable ();
3327 : : }
3328 : :
3329 : : /* Change source to vector mode. */
3330 : 2960 : src = gen_rtx_VEC_DUPLICATE (dest_vecmode, src);
3331 : 2960 : src = gen_rtx_VEC_MERGE (dest_vecmode, src, zero,
3332 : : GEN_INT (HOST_WIDE_INT_1U));
3333 : : /* Change destination to vector mode. */
3334 : 2960 : rtx vec = gen_reg_rtx (dest_vecmode);
3335 : : /* Generate an XMM vector SET. */
3336 : 2960 : set = gen_rtx_SET (vec, src);
3337 : 2960 : set_insn = emit_insn_before (set, insn);
3338 : :
3339 : 2960 : if (cfun->can_throw_non_call_exceptions)
3340 : : {
3341 : : /* Handle REG_EH_REGION note. */
3342 : 0 : rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
3343 : 0 : if (note)
3344 : : {
3345 : 0 : control_flow_insns.safe_push (set_insn);
3346 : 0 : add_reg_note (set_insn, REG_EH_REGION, XEXP (note, 0));
3347 : : }
3348 : : }
3349 : :
3350 : 2960 : src = gen_rtx_SUBREG (dest_mode, vec, 0);
3351 : 2960 : set = gen_rtx_SET (dest, src);
3352 : :
3353 : : /* Drop possible dead definitions. */
3354 : 2960 : PATTERN (insn) = set;
3355 : :
3356 : 2960 : INSN_CODE (insn) = -1;
3357 : 2960 : recog_memoized (insn);
3358 : 2960 : df_insn_rescan (insn);
3359 : 2960 : bitmap_set_bit (convert_bbs, bb->index);
3360 : : }
3361 : : }
3362 : :
3363 : 31637 : if (v4sf_const0)
3364 : : {
3365 : : /* (Re-)discover loops so that bb->loop_father can be used in the
3366 : : analysis below. */
3367 : 961 : calculate_dominance_info (CDI_DOMINATORS);
3368 : 961 : loop_optimizer_init (AVOID_CFG_MODIFICATIONS);
3369 : :
3370 : 961 : ix86_place_single_vector_set (v4sf_const0,
3371 : : CONST0_RTX (V4SFmode),
3372 : : convert_bbs);
3373 : :
3374 : 961 : loop_optimizer_finalize ();
3375 : :
3376 : 961 : if (!control_flow_insns.is_empty ())
3377 : : {
3378 : 0 : free_dominance_info (CDI_DOMINATORS);
3379 : :
3380 : 0 : unsigned int i;
3381 : 0 : FOR_EACH_VEC_ELT (control_flow_insns, i, insn)
3382 : 0 : if (control_flow_insn_p (insn))
3383 : : {
3384 : : /* Split the block after insn. There will be a fallthru
3385 : : edge, which is OK so we keep it. We have to create
3386 : : the exception edges ourselves. */
3387 : 0 : bb = BLOCK_FOR_INSN (insn);
3388 : 0 : split_block (bb, insn);
3389 : 0 : rtl_make_eh_edge (NULL, bb, BB_END (bb));
3390 : : }
3391 : : }
3392 : : }
3393 : :
3394 : 31637 : df_process_deferred_rescans ();
3395 : 31637 : df_clear_flags (DF_DEFER_INSN_RESCAN);
3396 : 31637 : bitmap_obstack_release (NULL);
3397 : 31637 : BITMAP_FREE (convert_bbs);
3398 : :
3399 : 31637 : timevar_pop (TV_MACH_DEP);
3400 : 31637 : return 0;
3401 : 31637 : }
3402 : :
3403 : : namespace {
3404 : :
3405 : : const pass_data pass_data_remove_partial_avx_dependency =
3406 : : {
3407 : : RTL_PASS, /* type */
3408 : : "rpad", /* name */
3409 : : OPTGROUP_NONE, /* optinfo_flags */
3410 : : TV_MACH_DEP, /* tv_id */
3411 : : 0, /* properties_required */
3412 : : 0, /* properties_provided */
3413 : : 0, /* properties_destroyed */
3414 : : 0, /* todo_flags_start */
3415 : : 0, /* todo_flags_finish */
3416 : : };
3417 : :
3418 : : class pass_remove_partial_avx_dependency : public rtl_opt_pass
3419 : : {
3420 : : public:
3421 : 285689 : pass_remove_partial_avx_dependency (gcc::context *ctxt)
3422 : 571378 : : rtl_opt_pass (pass_data_remove_partial_avx_dependency, ctxt)
3423 : : {}
3424 : :
3425 : : /* opt_pass methods: */
3426 : 1481340 : bool gate (function *) final override
3427 : : {
3428 : 1481340 : return ix86_rpad_gate ();
3429 : : }
3430 : :
3431 : 31637 : unsigned int execute (function *) final override
3432 : : {
3433 : 31637 : return remove_partial_avx_dependency ();
3434 : : }
3435 : : }; // class pass_rpad
3436 : :
3437 : : } // anon namespace
3438 : :
3439 : : rtl_opt_pass *
3440 : 285689 : make_pass_remove_partial_avx_dependency (gcc::context *ctxt)
3441 : : {
3442 : 285689 : return new pass_remove_partial_avx_dependency (ctxt);
3443 : : }
3444 : :
3445 : : /* Return a machine mode suitable for vector SIZE with SMODE inner
3446 : : mode. */
3447 : :
3448 : : static machine_mode
3449 : 30907 : ix86_get_vector_cse_mode (unsigned int size, machine_mode smode)
3450 : : {
3451 : : /* Use the inner scalar mode of vector broadcast source in:
3452 : :
3453 : : (set (reg:V8DF 394)
3454 : : (vec_duplicate:V8DF (reg:V2DF 190 [ alpha ])))
3455 : :
3456 : : to compute the vector mode for broadcast from vector source.
3457 : : */
3458 : 30907 : if (VECTOR_MODE_P (smode))
3459 : 1 : smode = GET_MODE_INNER (smode);
3460 : 30907 : scalar_mode s_mode = as_a <scalar_mode> (smode);
3461 : 61814 : poly_uint64 nunits = size / GET_MODE_SIZE (smode);
3462 : 30907 : machine_mode mode = mode_for_vector (s_mode, nunits).require ();
3463 : 30907 : return mode;
3464 : : }
3465 : :
3466 : : /* Replace the source operand of instructions in VECTOR_INSNS with
3467 : : VECTOR_CONST in VECTOR_MODE. */
3468 : :
3469 : : static void
3470 : 30493 : replace_vector_const (machine_mode vector_mode, rtx vector_const,
3471 : : auto_bitmap &vector_insns,
3472 : : machine_mode scalar_mode)
3473 : : {
3474 : 30493 : bitmap_iterator bi;
3475 : 30493 : unsigned int id;
3476 : :
3477 : 147233 : EXECUTE_IF_SET_IN_BITMAP (vector_insns, 0, id, bi)
3478 : : {
3479 : 116740 : rtx_insn *insn = DF_INSN_UID_GET (id)->insn;
3480 : :
3481 : : /* Get the single SET instruction. */
3482 : 116740 : rtx set = single_set (insn);
3483 : 116740 : rtx src = SET_SRC (set);
3484 : 116740 : rtx dest = SET_DEST (set);
3485 : 116740 : machine_mode mode = GET_MODE (dest);
3486 : :
3487 : 116740 : rtx replace;
3488 : : /* Replace the source operand with VECTOR_CONST. */
3489 : 116740 : if (SUBREG_P (src) || mode == vector_mode)
3490 : : replace = vector_const;
3491 : : else
3492 : : {
3493 : 60807 : unsigned int size = GET_MODE_SIZE (mode);
3494 : 60807 : if (size < ix86_regmode_natural_size (mode))
3495 : : {
3496 : : /* If the mode size is smaller than its natural size,
3497 : : first insert an extra move with a QI vector SUBREG
3498 : : of the same size to avoid validate_subreg failure. */
3499 : 414 : machine_mode vmode
3500 : 414 : = ix86_get_vector_cse_mode (size, scalar_mode);
3501 : 414 : rtx vreg;
3502 : 414 : if (mode == vmode)
3503 : : vreg = vector_const;
3504 : : else
3505 : : {
3506 : 37 : vreg = gen_reg_rtx (vmode);
3507 : 37 : rtx vsubreg = gen_rtx_SUBREG (vmode, vector_const, 0);
3508 : 37 : rtx pat = gen_rtx_SET (vreg, vsubreg);
3509 : 37 : rtx_insn *vinsn = emit_insn_before (pat, insn);
3510 : 37 : if (dump_file)
3511 : : {
3512 : 0 : fprintf (dump_file, "\nInsert an extra move:\n\n");
3513 : 0 : print_rtl_single (dump_file, vinsn);
3514 : 0 : fprintf (dump_file, "\nbefore:\n\n");
3515 : 0 : print_rtl_single (dump_file, insn);
3516 : 0 : fprintf (dump_file, "\n");
3517 : : }
3518 : : }
3519 : 414 : replace = gen_rtx_SUBREG (mode, vreg, 0);
3520 : : }
3521 : : else
3522 : 60393 : replace = gen_rtx_SUBREG (mode, vector_const, 0);
3523 : : }
3524 : :
3525 : 116740 : if (dump_file)
3526 : : {
3527 : 0 : fprintf (dump_file, "\nReplace:\n\n");
3528 : 0 : print_rtl_single (dump_file, insn);
3529 : : }
3530 : 116740 : SET_SRC (set) = replace;
3531 : : /* Drop possible dead definitions. */
3532 : 116740 : PATTERN (insn) = set;
3533 : 116740 : INSN_CODE (insn) = -1;
3534 : 116740 : recog_memoized (insn);
3535 : 116740 : if (dump_file)
3536 : : {
3537 : 0 : fprintf (dump_file, "\nwith:\n\n");
3538 : 0 : print_rtl_single (dump_file, insn);
3539 : 0 : fprintf (dump_file, "\n");
3540 : : }
3541 : 116740 : df_insn_rescan (insn);
3542 : : }
3543 : 30493 : }
3544 : :
3545 : : /* Return the inner scalar if OP is a broadcast, else return nullptr. */
3546 : :
3547 : : static rtx
3548 : 2125433 : ix86_broadcast_inner (rtx op, machine_mode mode,
3549 : : machine_mode *scalar_mode_p,
3550 : : x86_cse_kind *kind_p, rtx_insn **insn_p)
3551 : : {
3552 : 2125433 : switch (standard_sse_constant_p (op, mode))
3553 : : {
3554 : 107354 : case 1:
3555 : 107354 : *scalar_mode_p = QImode;
3556 : 107354 : *kind_p = X86_CSE_CONST0_VECTOR;
3557 : 107354 : *insn_p = nullptr;
3558 : 107354 : return const0_rtx;
3559 : 10697 : case 2:
3560 : 10697 : *scalar_mode_p = QImode;
3561 : 10697 : *kind_p = X86_CSE_CONSTM1_VECTOR;
3562 : 10697 : *insn_p = nullptr;
3563 : 10697 : return constm1_rtx;
3564 : 2007382 : default:
3565 : 2007382 : break;
3566 : : }
3567 : :
3568 : 2007382 : mode = GET_MODE (op);
3569 : 2007382 : int nunits = GET_MODE_NUNITS (mode);
3570 : 2007382 : if (nunits < 2)
3571 : : return nullptr;
3572 : :
3573 : 1553759 : *kind_p = X86_CSE_VEC_DUP;
3574 : :
3575 : 1553759 : rtx reg;
3576 : 1553759 : if (GET_CODE (op) == VEC_DUPLICATE)
3577 : : {
3578 : : /* Only
3579 : : (vec_duplicate:V4SI (reg:SI 99))
3580 : : (vec_duplicate:V2DF (mem/u/c:DF (symbol_ref/u:DI ("*.LC1") [flags 0x2]) [0 S8 A64]))
3581 : : are supported. Set OP to the broadcast source by default. */
3582 : 92830 : op = XEXP (op, 0);
3583 : 92830 : reg = op;
3584 : 92830 : if (SUBREG_P (op)
3585 : 391 : && SUBREG_BYTE (op) == 0
3586 : 93221 : && !paradoxical_subreg_p (op))
3587 : 391 : reg = SUBREG_REG (op);
3588 : 92830 : if (!REG_P (reg))
3589 : : {
3590 : 7233 : if (MEM_P (op)
3591 : 6966 : && SYMBOL_REF_P (XEXP (op, 0))
3592 : 12428 : && CONSTANT_POOL_ADDRESS_P (XEXP (op, 0)))
3593 : : {
3594 : : /* Handle constant broadcast from memory. */
3595 : 4994 : *scalar_mode_p = GET_MODE_INNER (mode);
3596 : 4994 : *insn_p = nullptr;
3597 : 4994 : return op;
3598 : : }
3599 : : return nullptr;
3600 : : }
3601 : : }
3602 : 1460929 : else if (CONST_VECTOR_P (op))
3603 : : {
3604 : 20 : rtx first = XVECEXP (op, 0, 0);
3605 : 48 : for (int i = 1; i < nunits; ++i)
3606 : : {
3607 : 48 : rtx tmp = XVECEXP (op, 0, i);
3608 : : /* Vector duplicate value. */
3609 : 48 : if (!rtx_equal_p (tmp, first))
3610 : : return nullptr;
3611 : : }
3612 : 0 : *scalar_mode_p = GET_MODE (first);
3613 : 0 : *insn_p = nullptr;
3614 : 0 : return first;
3615 : : }
3616 : : else
3617 : : return nullptr;
3618 : :
3619 : 85597 : mode = GET_MODE (op);
3620 : :
3621 : : /* Only single def chain is supported. */
3622 : 85597 : df_ref ref = DF_REG_DEF_CHAIN (REGNO (reg));
3623 : 85597 : if (!ref
3624 : 85596 : || DF_REF_IS_ARTIFICIAL (ref)
3625 : 85596 : || DF_REF_NEXT_REG (ref) != nullptr)
3626 : : return nullptr;
3627 : :
3628 : 80114 : rtx_insn *insn = DF_REF_INSN (ref);
3629 : 80114 : rtx set = single_set (insn);
3630 : 80114 : if (!set)
3631 : : return nullptr;
3632 : :
3633 : 80070 : rtx src = SET_SRC (set);
3634 : :
3635 : 80070 : if (CONST_INT_P (src))
3636 : : {
3637 : : /* Handle sequences like
3638 : :
3639 : : (set (reg:SI 99)
3640 : : (const_int 34 [0x22]))
3641 : : (set (reg:V4SI 98)
3642 : : (vec_duplicate:V4SI (reg:SI 99)))
3643 : :
3644 : : Set *INSN_P to nullptr and return SET_SRC if SET_SRC is an
3645 : : integer constant. */
3646 : 65998 : op = src;
3647 : 65998 : if (mode != GET_MODE (reg))
3648 : 0 : op = gen_int_mode (INTVAL (src), mode);
3649 : 65998 : *insn_p = nullptr;
3650 : : }
3651 : : else
3652 : : {
3653 : : /* Handle sequences like
3654 : :
3655 : : (set (reg:QI 105 [ c ])
3656 : : (reg:QI 5 di [ c ]))
3657 : : (set (reg:V64QI 102 [ _1 ])
3658 : : (vec_duplicate:V64QI (reg:QI 105 [ c ])))
3659 : :
3660 : : (set (reg/v:SI 116 [ argc ])
3661 : : (mem/c:SI (reg:SI 135) [2 argc+0 S4 A32]))
3662 : : (set (reg:V4SI 119 [ _45 ])
3663 : : (vec_duplicate:V4SI (reg/v:SI 116 [ argc ])))
3664 : :
3665 : : (set (reg:SI 98 [ _1 ])
3666 : : (sign_extend:SI (reg:QI 106 [ c ])))
3667 : : (set (reg:V16SI 103 [ _2 ])
3668 : : (vec_duplicate:V16SI (reg:SI 98 [ _1 ])))
3669 : :
3670 : : (set (reg:SI 102 [ cost ])
3671 : : (mem/c:SI (symbol_ref:DI ("cost") [flags 0x40])))
3672 : : (set (reg:V4HI 103 [ _16 ])
3673 : : (vec_duplicate:V4HI (subreg:HI (reg:SI 102 [ cost ]) 0)))
3674 : :
3675 : : (set (subreg:SI (reg/v:HI 107 [ cr_val ]) 0)
3676 : : (ashift:SI (reg:SI 158)
3677 : : (subreg:QI (reg:SI 156 [ _2 ]) 0)))
3678 : : (set (reg:V16HI 183 [ _61 ])
3679 : : (vec_duplicate:V16HI (reg/v:HI 107 [ cr_val ])))
3680 : :
3681 : : Set *INSN_P to INSN and return the broadcast source otherwise. */
3682 : 14072 : *insn_p = insn;
3683 : : }
3684 : :
3685 : 80070 : *scalar_mode_p = mode;
3686 : 80070 : return op;
3687 : : }
3688 : :
3689 : : /* Replace CALL instruction in TLS_CALL_INSNS with SET from SRC and
3690 : : put the updated instruction in UPDATED_TLS_INSNS. */
3691 : :
3692 : : static void
3693 : 301 : replace_tls_call (rtx src, auto_bitmap &tls_call_insns,
3694 : : auto_bitmap &updated_tls_insns)
3695 : : {
3696 : 301 : bitmap_iterator bi;
3697 : 301 : unsigned int id;
3698 : :
3699 : 1700 : EXECUTE_IF_SET_IN_BITMAP (tls_call_insns, 0, id, bi)
3700 : : {
3701 : 1399 : rtx_insn *insn = DF_INSN_UID_GET (id)->insn;
3702 : :
3703 : : /* If this isn't a CALL, only GNU2 TLS implicit CALL patterns are
3704 : : allowed. */
3705 : 1399 : if (!CALL_P (insn))
3706 : : {
3707 : 41 : attr_tls64 tls64 = get_attr_tls64 (insn);
3708 : 41 : if (tls64 != TLS64_CALL && tls64 != TLS64_COMBINE)
3709 : 0 : gcc_unreachable ();
3710 : : }
3711 : :
3712 : 1399 : rtx pat = PATTERN (insn);
3713 : 1399 : gcc_assert (GET_CODE (pat) == PARALLEL);
3714 : 1399 : rtx set = XVECEXP (pat, 0, 0);
3715 : 1399 : gcc_assert (GET_CODE (set) == SET);
3716 : 1399 : rtx dest = SET_DEST (set);
3717 : :
3718 : 1399 : set = gen_rtx_SET (dest, src);
3719 : 1399 : rtx_insn *set_insn = emit_insn_after (set, insn);
3720 : 1399 : if (recog_memoized (set_insn) < 0)
3721 : 0 : gcc_unreachable ();
3722 : :
3723 : : /* Put SET_INSN in UPDATED_TLS_INSNS. */
3724 : 1399 : bitmap_set_bit (updated_tls_insns, INSN_UID (set_insn));
3725 : :
3726 : 1399 : if (dump_file)
3727 : : {
3728 : 0 : fprintf (dump_file, "\nReplace:\n\n");
3729 : 0 : print_rtl_single (dump_file, insn);
3730 : 0 : fprintf (dump_file, "\nwith:\n\n");
3731 : 0 : print_rtl_single (dump_file, set_insn);
3732 : 0 : fprintf (dump_file, "\n");
3733 : : }
3734 : :
3735 : : /* Delete the CALL insn. */
3736 : 1399 : delete_insn (insn);
3737 : :
3738 : 1399 : df_insn_rescan (set_insn);
3739 : : }
3740 : 301 : }
3741 : :
3742 : : /* Return the basic block which dominates all basic blocks which set
3743 : : hard register REGNO used in basic block BB. */
3744 : :
3745 : : static basic_block
3746 : 2 : ix86_get_dominator_for_reg (unsigned int regno, basic_block bb)
3747 : : {
3748 : 2 : basic_block set_bb;
3749 : 2 : auto_bitmap set_bbs;
3750 : :
3751 : : /* Get all BBs which set REGNO and dominate the current BB from all
3752 : : DEFs of REGNO. */
3753 : 2 : for (df_ref def = DF_REG_DEF_CHAIN (regno);
3754 : 18 : def;
3755 : 16 : def = DF_REF_NEXT_REG (def))
3756 : 16 : if (!DF_REF_IS_ARTIFICIAL (def)
3757 : 16 : && !DF_REF_FLAGS_IS_SET (def, DF_REF_MAY_CLOBBER)
3758 : 6 : && !DF_REF_FLAGS_IS_SET (def, DF_REF_MUST_CLOBBER))
3759 : : {
3760 : 4 : set_bb = DF_REF_BB (def);
3761 : 4 : if (dominated_by_p (CDI_DOMINATORS, bb, set_bb))
3762 : 2 : bitmap_set_bit (set_bbs, set_bb->index);
3763 : : }
3764 : :
3765 : 2 : bb = nearest_common_dominator_for_set (CDI_DOMINATORS, set_bbs);
3766 : 2 : return bb;
3767 : 2 : }
3768 : :
3769 : : /* Mark FLAGS register as live in DATA, a bitmap of live caller-saved
3770 : : registers, if DEST is FLAGS register. */
3771 : :
3772 : : static void
3773 : 355 : ix86_check_flags_reg (rtx dest, const_rtx, void *data)
3774 : : {
3775 : 355 : auto_bitmap *live_caller_saved_regs = (auto_bitmap *) data;
3776 : 355 : if (REG_P (dest) && REGNO (dest) == FLAGS_REG)
3777 : 0 : bitmap_set_bit (*live_caller_saved_regs, FLAGS_REG);
3778 : 355 : }
3779 : :
3780 : : /* Emit a TLS_SET instruction of KIND in basic block BB. Store the
3781 : : insertion point in *BEFORE_P for emit_insn_before or in *AFTER_P
3782 : : for emit_insn_after. UPDATED_GNU_TLS_INSNS contains instructions
3783 : : which replace the GNU TLS instructions. UPDATED_GNU2_TLS_INSNS
3784 : : contains instructions which replace the GNU2 TLS instructions. */
3785 : :
3786 : : static rtx_insn *
3787 : 301 : ix86_emit_tls_call (rtx tls_set, x86_cse_kind kind, basic_block bb,
3788 : : rtx_insn **before_p, rtx_insn **after_p,
3789 : : auto_bitmap &updated_gnu_tls_insns,
3790 : : auto_bitmap &updated_gnu2_tls_insns)
3791 : : {
3792 : 303 : rtx_insn *tls_insn;
3793 : :
3794 : 303 : do
3795 : : {
3796 : 303 : rtx_insn *insn = BB_HEAD (bb);
3797 : 1237 : while (insn && !NONDEBUG_INSN_P (insn))
3798 : : {
3799 : 938 : if (insn == BB_END (bb))
3800 : : {
3801 : : /* This must be the beginning basic block:
3802 : :
3803 : : (note 4 0 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
3804 : : (note 2 4 26 2 NOTE_INSN_FUNCTION_BEG)
3805 : :
3806 : : or a basic block with only a label:
3807 : :
3808 : : (code_label 78 11 77 3 14 (nil) [1 uses])
3809 : : (note 77 78 54 3 [bb 3] NOTE_INSN_BASIC_BLOCK)
3810 : :
3811 : : or a basic block with only a debug marker:
3812 : :
3813 : : (note 3 0 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
3814 : : (note 2 3 5 2 NOTE_INSN_FUNCTION_BEG)
3815 : : (debug_insn 5 2 16 2 (debug_marker) "x.c":6:3 -1 (nil))
3816 : :
3817 : : */
3818 : 4 : gcc_assert (DEBUG_INSN_P (insn)
3819 : : || (NOTE_P (insn)
3820 : : && ((NOTE_KIND (insn)
3821 : : == NOTE_INSN_FUNCTION_BEG)
3822 : : || (NOTE_KIND (insn)
3823 : : == NOTE_INSN_BASIC_BLOCK))));
3824 : : insn = NULL;
3825 : : break;
3826 : : }
3827 : 934 : insn = NEXT_INSN (insn);
3828 : : }
3829 : :
3830 : : /* TLS_GD and TLS_LD_BASE instructions are normal functions which
3831 : : clobber caller-saved registers. TLSDESC instructions only
3832 : : clobber FLAGS. If any registers clobbered by TLS instructions
3833 : : are live in this basic block, we must insert TLS instructions
3834 : : after all live registers clobbered are dead. */
3835 : :
3836 : 303 : auto_bitmap live_caller_saved_regs;
3837 : 606 : bitmap in = df_live ? DF_LIVE_IN (bb) : DF_LR_IN (bb);
3838 : :
3839 : 303 : if (bitmap_bit_p (in, FLAGS_REG))
3840 : 4 : bitmap_set_bit (live_caller_saved_regs, FLAGS_REG);
3841 : :
3842 : 303 : unsigned int i;
3843 : :
3844 : : /* Get all live caller-saved registers for TLS_GD and TLS_LD_BASE
3845 : : instructions. */
3846 : 303 : if (kind != X86_CSE_TLSDESC)
3847 : 26412 : for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
3848 : 26128 : if (call_used_regs[i]
3849 : 24424 : && !fixed_regs[i]
3850 : 37796 : && bitmap_bit_p (in, i))
3851 : 339 : bitmap_set_bit (live_caller_saved_regs, i);
3852 : :
3853 : 303 : if (bitmap_empty_p (live_caller_saved_regs))
3854 : : {
3855 : 76 : if (insn == BB_HEAD (bb))
3856 : : {
3857 : 0 : *before_p = insn;
3858 : 0 : tls_insn = emit_insn_before (tls_set, insn);
3859 : : }
3860 : : else
3861 : : {
3862 : : /* Emit the TLS call after NOTE_INSN_FUNCTION_BEG in the
3863 : : beginning basic block:
3864 : :
3865 : : (note 4 0 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
3866 : : (note 2 4 26 2 NOTE_INSN_FUNCTION_BEG)
3867 : :
3868 : : or after NOTE_INSN_BASIC_BLOCK in a basic block with
3869 : : only a label:
3870 : :
3871 : : (code_label 78 11 77 3 14 (nil) [1 uses])
3872 : : (note 77 78 54 3 [bb 3] NOTE_INSN_BASIC_BLOCK)
3873 : :
3874 : : or after debug marker in a basic block with only a
3875 : : debug marker:
3876 : :
3877 : : (note 3 0 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
3878 : : (note 2 3 5 2 NOTE_INSN_FUNCTION_BEG)
3879 : : (debug_insn 5 2 16 2 (debug_marker) "x.c":6:3 -1 (nil))
3880 : :
3881 : : */
3882 : 76 : insn = insn ? PREV_INSN (insn) : BB_END (bb);
3883 : 76 : *after_p = insn;
3884 : 76 : tls_insn = emit_insn_after (tls_set, insn);
3885 : : }
3886 : 76 : return tls_insn;
3887 : : }
3888 : :
3889 : 227 : bool repeat = false;
3890 : :
3891 : : /* Search for REG_DEAD notes in this basic block. */
3892 : 626 : FOR_BB_INSNS (bb, insn)
3893 : : {
3894 : 626 : if (!NONDEBUG_INSN_P (insn))
3895 : 267 : continue;
3896 : :
3897 : : /* NB: Conditional jump is the only instruction which reads
3898 : : flags register and changes control flow. We can never
3899 : : place the TLS call after unconditional jump. */
3900 : 359 : if (JUMP_P (insn))
3901 : : {
3902 : : /* This must be a conditional jump. */
3903 : 2 : rtx label = JUMP_LABEL (insn);
3904 : 2 : if (label == nullptr
3905 : 2 : || ANY_RETURN_P (label)
3906 : 2 : || !(LABEL_P (label) || SYMBOL_REF_P (label)))
3907 : 0 : gcc_unreachable ();
3908 : :
3909 : : /* Place the call before all FLAGS_REG setting BBs since
3910 : : we can't place a call before nor after a conditional
3911 : : jump. */
3912 : 2 : bb = ix86_get_dominator_for_reg (FLAGS_REG, bb);
3913 : :
3914 : : /* Start over again. */
3915 : 2 : repeat = true;
3916 : 2 : break;
3917 : : }
3918 : :
3919 : 357 : if (bitmap_bit_p (updated_gnu_tls_insns, INSN_UID (insn)))
3920 : : {
3921 : : /* Insert the __tls_get_addr call before INSN which
3922 : : replaces a __tls_get_addr call. */
3923 : 1 : *before_p = insn;
3924 : 1 : tls_insn = emit_insn_before (tls_set, insn);
3925 : 1 : return tls_insn;
3926 : : }
3927 : :
3928 : 356 : if (bitmap_bit_p (updated_gnu2_tls_insns, INSN_UID (insn)))
3929 : : {
3930 : : /* Mark FLAGS register as dead since FLAGS register
3931 : : would be clobbered by the GNU2 TLS instruction. */
3932 : 1 : bitmap_clear_bit (live_caller_saved_regs, FLAGS_REG);
3933 : 1 : continue;
3934 : : }
3935 : :
3936 : : /* Check if FLAGS register is live. */
3937 : 355 : note_stores (insn, ix86_check_flags_reg,
3938 : : &live_caller_saved_regs);
3939 : :
3940 : 355 : rtx link;
3941 : 483 : for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
3942 : 352 : if (REG_NOTE_KIND (link) == REG_DEAD
3943 : 350 : && REG_P (XEXP (link, 0)))
3944 : : {
3945 : : /* Mark the live caller-saved register as dead. */
3946 : 705 : for (i = REGNO (XEXP (link, 0));
3947 : 705 : i < END_REGNO (XEXP (link, 0));
3948 : : i++)
3949 : 355 : if (i < FIRST_PSEUDO_REGISTER)
3950 : 339 : bitmap_clear_bit (live_caller_saved_regs, i);
3951 : :
3952 : 350 : if (bitmap_empty_p (live_caller_saved_regs))
3953 : : {
3954 : 224 : *after_p = insn;
3955 : 224 : tls_insn = emit_insn_after (tls_set, insn);
3956 : 224 : return tls_insn;
3957 : : }
3958 : : }
3959 : : }
3960 : :
3961 : : /* NB: Start over again for conditional jump. */
3962 : 2 : if (repeat)
3963 : 2 : continue;
3964 : :
3965 : 0 : gcc_assert (!bitmap_empty_p (live_caller_saved_regs));
3966 : :
3967 : : /* If any live caller-saved registers aren't dead at the end of
3968 : : this basic block, get the basic block which dominates all
3969 : : basic blocks which set the remaining live registers. */
3970 : 0 : auto_bitmap set_bbs;
3971 : 0 : bitmap_iterator bi;
3972 : 0 : unsigned int id;
3973 : 0 : EXECUTE_IF_SET_IN_BITMAP (live_caller_saved_regs, 0, id, bi)
3974 : : {
3975 : 0 : basic_block set_bb = ix86_get_dominator_for_reg (id, bb);
3976 : 0 : bitmap_set_bit (set_bbs, set_bb->index);
3977 : : }
3978 : 0 : bb = nearest_common_dominator_for_set (CDI_DOMINATORS, set_bbs);
3979 : 2 : }
3980 : : while (true);
3981 : : }
3982 : :
3983 : : /* Generate a TLS call of KIND with VAL and copy the call result to DEST,
3984 : : at entry of the nearest dominator for basic block map BBS, which is in
3985 : : the fake loop that contains the whole function, so that there is only
3986 : : a single TLS CALL of KIND with VAL in the whole function.
3987 : : UPDATED_GNU_TLS_INSNS contains instructions which replace the GNU TLS
3988 : : instructions. UPDATED_GNU2_TLS_INSNS contains instructions which
3989 : : replace the GNU2 TLS instructions. If TLSDESC_SET isn't nullptr,
3990 : : insert it before the TLS call. */
3991 : :
3992 : : static void
3993 : 301 : ix86_place_single_tls_call (rtx dest, rtx val, x86_cse_kind kind,
3994 : : auto_bitmap &bbs,
3995 : : auto_bitmap &updated_gnu_tls_insns,
3996 : : auto_bitmap &updated_gnu2_tls_insns,
3997 : : rtx tlsdesc_set = nullptr)
3998 : : {
3999 : 301 : basic_block bb = nearest_common_dominator_for_set (CDI_DOMINATORS, bbs);
4000 : 301 : while (bb->loop_father->latch
4001 : 307 : != EXIT_BLOCK_PTR_FOR_FN (cfun))
4002 : 6 : bb = get_immediate_dominator (CDI_DOMINATORS,
4003 : : bb->loop_father->header);
4004 : :
4005 : 301 : rtx rax = nullptr, rdi;
4006 : 301 : rtx eqv = nullptr;
4007 : 301 : rtx caddr;
4008 : 301 : rtx set;
4009 : 301 : rtx clob;
4010 : 301 : rtx symbol;
4011 : 301 : rtx tls;
4012 : :
4013 : 301 : switch (kind)
4014 : : {
4015 : 258 : case X86_CSE_TLS_GD:
4016 : 258 : rax = gen_rtx_REG (Pmode, AX_REG);
4017 : 258 : rdi = gen_rtx_REG (Pmode, DI_REG);
4018 : 258 : caddr = ix86_tls_get_addr ();
4019 : :
4020 : 258 : symbol = XVECEXP (val, 0, 0);
4021 : 258 : tls = gen_tls_global_dynamic_64 (Pmode, rax, symbol, caddr, rdi);
4022 : :
4023 : 258 : if (GET_MODE (symbol) != Pmode)
4024 : 0 : symbol = gen_rtx_ZERO_EXTEND (Pmode, symbol);
4025 : : eqv = symbol;
4026 : : break;
4027 : :
4028 : 25 : case X86_CSE_TLS_LD_BASE:
4029 : 25 : rax = gen_rtx_REG (Pmode, AX_REG);
4030 : 25 : rdi = gen_rtx_REG (Pmode, DI_REG);
4031 : 25 : caddr = ix86_tls_get_addr ();
4032 : :
4033 : 25 : tls = gen_tls_local_dynamic_base_64 (Pmode, rax, caddr, rdi);
4034 : :
4035 : : /* Attach a unique REG_EQUAL to DEST, to allow the RTL optimizers
4036 : : to share the LD_BASE result with other LD model accesses. */
4037 : 25 : eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
4038 : : UNSPEC_TLS_LD_BASE);
4039 : :
4040 : 25 : break;
4041 : :
4042 : 18 : case X86_CSE_TLSDESC:
4043 : 18 : set = gen_rtx_SET (dest, val);
4044 : 18 : clob = gen_rtx_CLOBBER (VOIDmode,
4045 : : gen_rtx_REG (CCmode, FLAGS_REG));
4046 : 18 : tls = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, set, clob));
4047 : 18 : break;
4048 : :
4049 : 0 : default:
4050 : 0 : gcc_unreachable ();
4051 : : }
4052 : :
4053 : : /* Emit the TLS CALL insn. */
4054 : 301 : rtx_insn *before = nullptr;
4055 : 301 : rtx_insn *after = nullptr;
4056 : 301 : rtx_insn *tls_insn = ix86_emit_tls_call (tls, kind, bb, &before,
4057 : : &after,
4058 : : updated_gnu_tls_insns,
4059 : : updated_gnu2_tls_insns);
4060 : :
4061 : 301 : rtx_insn *tlsdesc_insn = nullptr;
4062 : 301 : if (tlsdesc_set)
4063 : : {
4064 : 14 : rtx dest = copy_rtx (SET_DEST (tlsdesc_set));
4065 : 14 : rtx src = copy_rtx (SET_SRC (tlsdesc_set));
4066 : 14 : tlsdesc_set = gen_rtx_SET (dest, src);
4067 : 14 : tlsdesc_insn = emit_insn_before (tlsdesc_set, tls_insn);
4068 : : }
4069 : :
4070 : 301 : if (kind != X86_CSE_TLSDESC)
4071 : : {
4072 : 283 : RTL_CONST_CALL_P (tls_insn) = 1;
4073 : :
4074 : : /* Indicate that this function can't jump to non-local gotos. */
4075 : 283 : make_reg_eh_region_note_nothrow_nononlocal (tls_insn);
4076 : : }
4077 : :
4078 : 301 : if (recog_memoized (tls_insn) < 0)
4079 : 0 : gcc_unreachable ();
4080 : :
4081 : 301 : if (dump_file)
4082 : : {
4083 : 0 : if (after)
4084 : : {
4085 : 0 : fprintf (dump_file, "\nPlace:\n\n");
4086 : 0 : if (tlsdesc_insn)
4087 : 0 : print_rtl_single (dump_file, tlsdesc_insn);
4088 : 0 : print_rtl_single (dump_file, tls_insn);
4089 : 0 : fprintf (dump_file, "\nafter:\n\n");
4090 : 0 : print_rtl_single (dump_file, after);
4091 : 0 : fprintf (dump_file, "\n");
4092 : : }
4093 : : else
4094 : : {
4095 : 0 : fprintf (dump_file, "\nPlace:\n\n");
4096 : 0 : if (tlsdesc_insn)
4097 : 0 : print_rtl_single (dump_file, tlsdesc_insn);
4098 : 0 : print_rtl_single (dump_file, tls_insn);
4099 : 0 : fprintf (dump_file, "\nbefore:\n\n");
4100 : 0 : print_rtl_single (dump_file, before);
4101 : 0 : fprintf (dump_file, "\n");
4102 : : }
4103 : : }
4104 : :
4105 : 301 : if (kind != X86_CSE_TLSDESC)
4106 : : {
4107 : : /* Copy RAX to DEST. */
4108 : 283 : set = gen_rtx_SET (dest, rax);
4109 : 283 : rtx_insn *set_insn = emit_insn_after (set, tls_insn);
4110 : 283 : set_dst_reg_note (set_insn, REG_EQUAL, copy_rtx (eqv), dest);
4111 : 283 : if (dump_file)
4112 : : {
4113 : 0 : fprintf (dump_file, "\nPlace:\n\n");
4114 : 0 : print_rtl_single (dump_file, set_insn);
4115 : 0 : fprintf (dump_file, "\nafter:\n\n");
4116 : 0 : print_rtl_single (dump_file, tls_insn);
4117 : 0 : fprintf (dump_file, "\n");
4118 : : }
4119 : : }
4120 : 301 : }
4121 : :
4122 : : namespace {
4123 : :
4124 : : const pass_data pass_data_x86_cse =
4125 : : {
4126 : : RTL_PASS, /* type */
4127 : : "x86_cse", /* name */
4128 : : OPTGROUP_NONE, /* optinfo_flags */
4129 : : TV_MACH_DEP, /* tv_id */
4130 : : 0, /* properties_required */
4131 : : 0, /* properties_provided */
4132 : : 0, /* properties_destroyed */
4133 : : 0, /* todo_flags_start */
4134 : : 0, /* todo_flags_finish */
4135 : : };
4136 : :
4137 : : class pass_x86_cse : public rtl_opt_pass
4138 : : {
4139 : : public:
4140 : 285689 : pass_x86_cse (gcc::context *ctxt)
4141 : 571378 : : rtl_opt_pass (pass_data_x86_cse, ctxt)
4142 : : {}
4143 : :
4144 : : /* opt_pass methods: */
4145 : 1481340 : bool gate (function *fun) final override
4146 : : {
4147 : 1481340 : return (TARGET_SSE2
4148 : 1477128 : && optimize
4149 : 2523977 : && optimize_function_for_speed_p (fun));
4150 : : }
4151 : :
4152 : 978833 : unsigned int execute (function *) final override
4153 : : {
4154 : 978833 : return x86_cse ();
4155 : : }
4156 : :
4157 : : private:
4158 : : /* The redundant source value. */
4159 : : rtx val;
4160 : : /* The actual redundant source value for UNSPEC_TLSDESC. */
4161 : : rtx tlsdesc_val;
4162 : : /* The instruction which defines the redundant value. */
4163 : : rtx_insn *def_insn;
4164 : : /* Mode of the destination of the candidate redundant instruction. */
4165 : : machine_mode mode;
4166 : : /* Mode of the source of the candidate redundant instruction. */
4167 : : machine_mode scalar_mode;
4168 : : /* The classification of the candidate redundant instruction. */
4169 : : x86_cse_kind kind;
4170 : :
4171 : : unsigned int x86_cse (void);
4172 : : bool candidate_gnu_tls_p (rtx_insn *, attr_tls64);
4173 : : bool candidate_gnu2_tls_p (rtx, attr_tls64);
4174 : : bool candidate_vector_p (rtx);
4175 : : rtx_insn *tls_set_insn_from_symbol (const_rtx, const_rtx);
4176 : : }; // class pass_x86_cse
4177 : :
4178 : : /* Return the instruction which sets REG from TLS_SYMBOL. */
4179 : :
4180 : : rtx_insn *
4181 : 38 : pass_x86_cse::tls_set_insn_from_symbol (const_rtx reg,
4182 : : const_rtx tls_symbol)
4183 : : {
4184 : 38 : rtx_insn *set_insn = nullptr;
4185 : 38 : for (df_ref ref = DF_REG_DEF_CHAIN (REGNO (reg));
4186 : 103 : ref;
4187 : 65 : ref = DF_REF_NEXT_REG (ref))
4188 : : {
4189 : 65 : if (DF_REF_IS_ARTIFICIAL (ref))
4190 : : return nullptr;
4191 : :
4192 : 65 : set_insn = DF_REF_INSN (ref);
4193 : 65 : if (get_attr_tls64 (set_insn) != TLS64_LEA)
4194 : : return nullptr;
4195 : :
4196 : 65 : rtx tls_set = PATTERN (set_insn);
4197 : 65 : rtx tls_src = XVECEXP (SET_SRC (tls_set), 0, 0);
4198 : 65 : if (!rtx_equal_p (tls_symbol, tls_src))
4199 : : return nullptr;
4200 : : }
4201 : :
4202 : : return set_insn;
4203 : : }
4204 : :
4205 : : /* Return true and output def_insn, val, mode, scalar_mode and kind if
4206 : : INSN is UNSPEC_TLS_GD or UNSPEC_TLS_LD_BASE. */
4207 : :
4208 : : bool
4209 : 2185 : pass_x86_cse::candidate_gnu_tls_p (rtx_insn *insn, attr_tls64 tls64)
4210 : : {
4211 : 2185 : if (!TARGET_64BIT || !cfun->machine->tls_descriptor_call_multiple_p)
4212 : : return false;
4213 : :
4214 : : /* Record the redundant TLS CALLs for 64-bit:
4215 : :
4216 : : (parallel [
4217 : : (set (reg:DI 0 ax)
4218 : : (call:DI (mem:QI (symbol_ref:DI ("__tls_get_addr")))
4219 : : (const_int 0 [0])))
4220 : : (unspec:DI [(symbol_ref:DI ("foo") [flags 0x50])
4221 : : (reg/f:DI 7 sp)] UNSPEC_TLS_GD)
4222 : : (clobber (reg:DI 5 di))])
4223 : :
4224 : :
4225 : : and
4226 : :
4227 : : (parallel [
4228 : : (set (reg:DI 0 ax)
4229 : : (call:DI (mem:QI (symbol_ref:DI ("__tls_get_addr")))
4230 : : (const_int 0 [0])))
4231 : : (unspec:DI [(reg/f:DI 7 sp)] UNSPEC_TLS_LD_BASE)])
4232 : :
4233 : : */
4234 : :
4235 : 2000 : rtx pat = PATTERN (insn);
4236 : 2000 : rtx set = XVECEXP (pat, 0, 0);
4237 : 2000 : gcc_assert (GET_CODE (set) == SET);
4238 : 2000 : rtx dest = SET_DEST (set);
4239 : 2000 : scalar_mode = mode = GET_MODE (dest);
4240 : 2000 : val = XVECEXP (pat, 0, 1);
4241 : 2000 : gcc_assert (GET_CODE (val) == UNSPEC);
4242 : :
4243 : 2000 : if (tls64 == TLS64_GD)
4244 : 1909 : kind = X86_CSE_TLS_GD;
4245 : : else
4246 : 91 : kind = X86_CSE_TLS_LD_BASE;
4247 : :
4248 : 2000 : def_insn = nullptr;
4249 : 2000 : return true;
4250 : : }
4251 : :
4252 : : /* Return true and output def_insn, val, mode, scalar_mode and kind if
4253 : : SET is UNSPEC_TLSDESC. */
4254 : :
4255 : : bool
4256 : 50 : pass_x86_cse::candidate_gnu2_tls_p (rtx set, attr_tls64 tls64)
4257 : : {
4258 : 50 : if (!TARGET_64BIT || !cfun->machine->tls_descriptor_call_multiple_p)
4259 : : return false;
4260 : :
4261 : 48 : rtx tls_symbol;
4262 : 48 : rtx_insn *set_insn;
4263 : 48 : rtx src = SET_SRC (set);
4264 : 48 : val = src;
4265 : 48 : tlsdesc_val = src;
4266 : 48 : kind = X86_CSE_TLSDESC;
4267 : :
4268 : 48 : if (tls64 == TLS64_COMBINE)
4269 : : {
4270 : : /* Record 64-bit TLS64_COMBINE:
4271 : :
4272 : : (set (reg/f:DI 104)
4273 : : (plus:DI (unspec:DI [
4274 : : (symbol_ref:DI ("_TLS_MODULE_BASE_") [flags 0x10])
4275 : : (reg:DI 114)
4276 : : (reg/f:DI 7 sp)] UNSPEC_TLSDESC)
4277 : : (const:DI (unspec:DI [
4278 : : (symbol_ref:DI ("e") [flags 0x1a])
4279 : : ] UNSPEC_DTPOFF))))
4280 : :
4281 : : (set (reg/f:DI 104)
4282 : : (plus:DI (unspec:DI [
4283 : : (symbol_ref:DI ("_TLS_MODULE_BASE_") [flags 0x10])
4284 : : (unspec:DI [
4285 : : (symbol_ref:DI ("_TLS_MODULE_BASE_") [flags 0x10])
4286 : : ] UNSPEC_TLSDESC)
4287 : : (reg/f:DI 7 sp)] UNSPEC_TLSDESC)
4288 : : (const:DI (unspec:DI [
4289 : : (symbol_ref:DI ("e") [flags 0x1a])
4290 : : ] UNSPEC_DTPOFF))))
4291 : : */
4292 : :
4293 : 10 : scalar_mode = mode = GET_MODE (src);
4294 : :
4295 : : /* Since the first operand of PLUS in the source TLS_COMBINE
4296 : : pattern is unused, use the second operand of PLUS:
4297 : :
4298 : : (const:DI (unspec:DI [
4299 : : (symbol_ref:DI ("e") [flags 0x1a])
4300 : : ] UNSPEC_DTPOFF))
4301 : :
4302 : : as VAL to check if 2 TLS_COMBINE patterns have the same
4303 : : source. */
4304 : 10 : val = XEXP (src, 1);
4305 : 10 : gcc_assert (GET_CODE (val) == CONST
4306 : : && GET_CODE (XEXP (val, 0)) == UNSPEC
4307 : : && XINT (XEXP (val, 0), 1) == UNSPEC_DTPOFF
4308 : : && SYMBOL_REF_P (XVECEXP (XEXP (val, 0), 0, 0)));
4309 : 10 : def_insn = nullptr;
4310 : 10 : return true;
4311 : : }
4312 : :
4313 : : /* Record 64-bit TLS_CALL:
4314 : :
4315 : : (set (reg:DI 101)
4316 : : (unspec:DI [(symbol_ref:DI ("foo") [flags 0x50])
4317 : : (reg:DI 112)
4318 : : (reg/f:DI 7 sp)] UNSPEC_TLSDESC))
4319 : :
4320 : : */
4321 : :
4322 : 38 : gcc_assert (GET_CODE (src) == UNSPEC);
4323 : 38 : tls_symbol = XVECEXP (src, 0, 0);
4324 : 38 : src = XVECEXP (src, 0, 1);
4325 : 38 : scalar_mode = mode = GET_MODE (src);
4326 : 38 : gcc_assert (REG_P (src));
4327 : :
4328 : : /* All definitions of reg:DI 129 in
4329 : :
4330 : : (set (reg:DI 110)
4331 : : (unspec:DI [(symbol_ref:DI ("foo"))
4332 : : (reg:DI 129)
4333 : : (reg/f:DI 7 sp)] UNSPEC_TLSDESC))
4334 : :
4335 : : should have the same source as in
4336 : :
4337 : : (set (reg:DI 129)
4338 : : (unspec:DI [(symbol_ref:DI ("foo"))] UNSPEC_TLSDESC))
4339 : :
4340 : : */
4341 : :
4342 : 38 : set_insn = tls_set_insn_from_symbol (src, tls_symbol);
4343 : 38 : if (!set_insn)
4344 : : return false;
4345 : :
4346 : : /* Use TLS_SYMBOL as VAL to check if 2 patterns have the same source. */
4347 : 38 : val = tls_symbol;
4348 : 38 : def_insn = set_insn;
4349 : 38 : return true;
4350 : : }
4351 : :
4352 : : /* Return true and output def_insn, val, mode, scalar_mode and kind if
4353 : : INSN is a vector broadcast instruction. */
4354 : :
4355 : : bool
4356 : 50819250 : pass_x86_cse::candidate_vector_p (rtx set)
4357 : : {
4358 : 50819250 : rtx src = SET_SRC (set);
4359 : 50819250 : rtx dest = SET_DEST (set);
4360 : 50819250 : mode = GET_MODE (dest);
4361 : : /* Skip non-vector instruction. */
4362 : 50819250 : if (!VECTOR_MODE_P (mode))
4363 : : return false;
4364 : :
4365 : : /* Skip non-vector load instruction. */
4366 : 3581114 : if (!REG_P (dest) && !SUBREG_P (dest))
4367 : : return false;
4368 : :
4369 : 2125433 : val = ix86_broadcast_inner (src, mode, &scalar_mode, &kind,
4370 : : &def_insn);
4371 : 2125433 : return val ? true : false;
4372 : : }
4373 : :
4374 : : /* At entry of the nearest common dominator for basic blocks with
4375 : :
4376 : : 1. Vector CONST0_RTX patterns.
4377 : : 2. Vector CONSTM1_RTX patterns.
4378 : : 3. Vector broadcast patterns.
4379 : : 4. UNSPEC_TLS_GD patterns.
4380 : : 5. UNSPEC_TLS_LD_BASE patterns.
4381 : : 6. UNSPEC_TLSDESC patterns.
4382 : :
4383 : : generate a single pattern whose destination is used to replace the
4384 : : source in all identical patterns.
4385 : :
4386 : : NB: We want to generate a pattern, which is executed only once, to
4387 : : cover the whole function. The LCM algorithm isn't appropriate here
4388 : : since it may place a pattern inside the loop. */
4389 : :
4390 : : unsigned int
4391 : 978833 : pass_x86_cse::x86_cse (void)
4392 : : {
4393 : 978833 : timevar_push (TV_MACH_DEP);
4394 : :
4395 : 978833 : auto_vec<redundant_pattern *> loads;
4396 : 978833 : redundant_pattern *load;
4397 : 978833 : basic_block bb;
4398 : 978833 : rtx_insn *insn;
4399 : 978833 : unsigned int i;
4400 : 978833 : auto_bitmap updated_gnu_tls_insns;
4401 : 978833 : auto_bitmap updated_gnu2_tls_insns;
4402 : :
4403 : 978833 : df_set_flags (DF_DEFER_INSN_RESCAN);
4404 : :
4405 : 978833 : bool recursive_call_p = cfun->machine->recursive_function;
4406 : :
4407 : 11113135 : FOR_EACH_BB_FN (bb, cfun)
4408 : : {
4409 : 133991409 : FOR_BB_INSNS (bb, insn)
4410 : : {
4411 : 123857107 : if (!NONDEBUG_INSN_P (insn))
4412 : 69335354 : continue;
4413 : :
4414 : 54521753 : bool matched = false;
4415 : : /* Remove redundant pattens if there are more than 2 of
4416 : : them. */
4417 : 54521753 : unsigned int threshold = 2;
4418 : :
4419 : 54521753 : rtx set = single_set (insn);
4420 : 54521753 : if (!set && !CALL_P (insn))
4421 : 1094391 : continue;
4422 : :
4423 : 53427362 : tlsdesc_val = nullptr;
4424 : :
4425 : 53427362 : attr_tls64 tls64 = get_attr_tls64 (insn);
4426 : 53427362 : switch (tls64)
4427 : : {
4428 : 2185 : case TLS64_GD:
4429 : 2185 : case TLS64_LD_BASE:
4430 : : /* Verify UNSPEC_TLS_GD and UNSPEC_TLS_LD_BASE. */
4431 : 2185 : if (candidate_gnu_tls_p (insn, tls64))
4432 : : break;
4433 : 185 : continue;
4434 : :
4435 : 50 : case TLS64_CALL:
4436 : 50 : case TLS64_COMBINE:
4437 : : /* Verify UNSPEC_TLSDESC. */
4438 : 50 : if (candidate_gnu2_tls_p (set, tls64))
4439 : : break;
4440 : 2 : continue;
4441 : :
4442 : 35 : case TLS64_LEA:
4443 : : /* Skip TLS64_LEA. */
4444 : 35 : continue;
4445 : :
4446 : 53425092 : case TLS64_NONE:
4447 : 53425092 : if (!set)
4448 : 2605842 : continue;
4449 : :
4450 : : /* Check for vector broadcast. */
4451 : 50819250 : if (candidate_vector_p (set))
4452 : : break;
4453 : 50616135 : continue;
4454 : : }
4455 : :
4456 : : /* Check if there is a matching redundant load. */
4457 : 371132 : FOR_EACH_VEC_ELT (loads, i, load)
4458 : 253314 : if (load->val
4459 : 253314 : && load->kind == kind
4460 : 197412 : && load->mode == scalar_mode
4461 : 187489 : && (load->bb == bb
4462 : 152516 : || kind != X86_CSE_VEC_DUP
4463 : : /* Non all 0s/1s vector load must be in the same
4464 : : basic block if it is in a recursive call. */
4465 : 97269 : || !recursive_call_p)
4466 : 438828 : && rtx_equal_p (load->val, val))
4467 : : {
4468 : : /* Record instruction. */
4469 : 87345 : bitmap_set_bit (load->insns, INSN_UID (insn));
4470 : :
4471 : : /* Record the maximum vector size. */
4472 : 87345 : if (kind <= X86_CSE_VEC_DUP
4473 : 173592 : && load->size < GET_MODE_SIZE (mode))
4474 : 926 : load->size = GET_MODE_SIZE (mode);
4475 : :
4476 : : /* Record the basic block. */
4477 : 87345 : bitmap_set_bit (load->bbs, bb->index);
4478 : :
4479 : : /* Increment the count. */
4480 : 87345 : load->count++;
4481 : :
4482 : 87345 : matched = true;
4483 : 87345 : break;
4484 : : }
4485 : :
4486 : 205163 : if (matched)
4487 : 87345 : continue;
4488 : :
4489 : : /* We see this instruction the first time. Record the
4490 : : redundant source value, its mode, the destination size,
4491 : : instruction which defines the redundant source value,
4492 : : instruction basic block and the instruction kind. */
4493 : 117818 : load = new redundant_pattern;
4494 : :
4495 : 117818 : load->val = copy_rtx (val);
4496 : 117818 : if (tlsdesc_val)
4497 : 25 : load->tlsdesc_val = copy_rtx (tlsdesc_val);
4498 : : else
4499 : 117793 : load->tlsdesc_val = nullptr;
4500 : 117818 : load->mode = scalar_mode;
4501 : 117818 : load->size = GET_MODE_SIZE (mode);
4502 : 117818 : load->def_insn = def_insn;
4503 : 117818 : load->count = 1;
4504 : 117818 : load->threshold = threshold;
4505 : 117818 : load->bb = BLOCK_FOR_INSN (insn);
4506 : 117818 : load->kind = kind;
4507 : :
4508 : 117818 : bitmap_set_bit (load->insns, INSN_UID (insn));
4509 : 117818 : bitmap_set_bit (load->bbs, bb->index);
4510 : :
4511 : 117818 : loads.safe_push (load);
4512 : : }
4513 : : }
4514 : :
4515 : : bool replaced = false;
4516 : 1096651 : FOR_EACH_VEC_ELT (loads, i, load)
4517 : 117818 : if (load->count >= load->threshold)
4518 : : {
4519 : 30794 : machine_mode mode;
4520 : 30794 : rtx reg, broadcast_source, broadcast_reg;
4521 : 30794 : replaced = true;
4522 : 30794 : switch (load->kind)
4523 : : {
4524 : 301 : case X86_CSE_TLS_GD:
4525 : 301 : case X86_CSE_TLS_LD_BASE:
4526 : 301 : case X86_CSE_TLSDESC:
4527 : 301 : broadcast_reg = gen_reg_rtx (load->mode);
4528 : 301 : replace_tls_call (broadcast_reg, load->insns,
4529 : 301 : (load->kind == X86_CSE_TLSDESC
4530 : : ? updated_gnu2_tls_insns
4531 : : : updated_gnu_tls_insns));
4532 : 301 : load->broadcast_reg = broadcast_reg;
4533 : 301 : break;
4534 : :
4535 : 30493 : case X86_CSE_CONST0_VECTOR:
4536 : 30493 : case X86_CSE_CONSTM1_VECTOR:
4537 : 30493 : case X86_CSE_VEC_DUP:
4538 : 30493 : mode = ix86_get_vector_cse_mode (load->size, load->mode);
4539 : 30493 : broadcast_reg = gen_reg_rtx (mode);
4540 : 30493 : if (load->def_insn)
4541 : : {
4542 : : /* Replace redundant vector loads with a single vector
4543 : : load in the same basic block. */
4544 : 773 : reg = load->val;
4545 : 773 : if (load->mode != GET_MODE (reg))
4546 : 0 : reg = gen_rtx_SUBREG (load->mode, reg, 0);
4547 : 773 : broadcast_source = gen_rtx_VEC_DUPLICATE (mode, reg);
4548 : : }
4549 : : else
4550 : : /* This is a constant integer/double vector. If the
4551 : : inner scalar is 0 or -1, set vector to CONST0_RTX
4552 : : or CONSTM1_RTX directly. */
4553 : 29720 : switch (load->kind)
4554 : : {
4555 : 18608 : case X86_CSE_CONST0_VECTOR:
4556 : 18608 : broadcast_source = CONST0_RTX (mode);
4557 : 18608 : break;
4558 : 1195 : case X86_CSE_CONSTM1_VECTOR:
4559 : 1195 : broadcast_source = CONSTM1_RTX (mode);
4560 : 1195 : break;
4561 : 9917 : case X86_CSE_VEC_DUP:
4562 : 9917 : reg = gen_reg_rtx (load->mode);
4563 : 9917 : broadcast_source = gen_rtx_VEC_DUPLICATE (mode, reg);
4564 : 9917 : break;
4565 : 0 : default:
4566 : 0 : gcc_unreachable ();
4567 : : }
4568 : 30493 : replace_vector_const (mode, broadcast_reg, load->insns,
4569 : : load->mode);
4570 : 30493 : load->broadcast_source = broadcast_source;
4571 : 30493 : load->broadcast_reg = broadcast_reg;
4572 : 30493 : break;
4573 : : }
4574 : : }
4575 : :
4576 : 978833 : if (replaced)
4577 : : {
4578 : 24778 : auto_vec<rtx_insn *> control_flow_insns;
4579 : :
4580 : : /* (Re-)discover loops so that bb->loop_father can be used in the
4581 : : analysis below. */
4582 : 24778 : calculate_dominance_info (CDI_DOMINATORS);
4583 : 24778 : loop_optimizer_init (AVOID_CFG_MODIFICATIONS);
4584 : :
4585 : 68150 : FOR_EACH_VEC_ELT (loads, i, load)
4586 : 43372 : if (load->count >= load->threshold)
4587 : : {
4588 : 30794 : rtx set;
4589 : 30794 : if (load->def_insn)
4590 : 787 : switch (load->kind)
4591 : : {
4592 : 14 : case X86_CSE_TLSDESC:
4593 : 14 : ix86_place_single_tls_call (load->broadcast_reg,
4594 : : load->tlsdesc_val,
4595 : : load->kind,
4596 : 14 : load->bbs,
4597 : : updated_gnu_tls_insns,
4598 : : updated_gnu2_tls_insns,
4599 : 14 : PATTERN (load->def_insn));
4600 : 14 : break;
4601 : 773 : case X86_CSE_VEC_DUP:
4602 : : /* Insert a broadcast after the original scalar
4603 : : definition. */
4604 : 773 : set = gen_rtx_SET (load->broadcast_reg,
4605 : : load->broadcast_source);
4606 : 773 : insn = emit_insn_after (set, load->def_insn);
4607 : :
4608 : 773 : if (cfun->can_throw_non_call_exceptions)
4609 : : {
4610 : : /* Handle REG_EH_REGION note in DEF_INSN. */
4611 : 5 : rtx note = find_reg_note (load->def_insn,
4612 : : REG_EH_REGION, nullptr);
4613 : 5 : if (note)
4614 : : {
4615 : 1 : control_flow_insns.safe_push (load->def_insn);
4616 : 1 : add_reg_note (insn, REG_EH_REGION,
4617 : : XEXP (note, 0));
4618 : : }
4619 : : }
4620 : :
4621 : 773 : if (dump_file)
4622 : : {
4623 : 0 : fprintf (dump_file, "\nAdd:\n\n");
4624 : 0 : print_rtl_single (dump_file, insn);
4625 : 0 : fprintf (dump_file, "\nafter:\n\n");
4626 : 0 : print_rtl_single (dump_file, load->def_insn);
4627 : 0 : fprintf (dump_file, "\n");
4628 : : }
4629 : : break;
4630 : 0 : default:
4631 : 0 : gcc_unreachable ();
4632 : : }
4633 : : else
4634 : 30007 : switch (load->kind)
4635 : : {
4636 : 287 : case X86_CSE_TLS_GD:
4637 : 287 : case X86_CSE_TLS_LD_BASE:
4638 : 287 : case X86_CSE_TLSDESC:
4639 : 287 : ix86_place_single_tls_call (load->broadcast_reg,
4640 : : (load->kind == X86_CSE_TLSDESC
4641 : : ? load->tlsdesc_val
4642 : : : load->val),
4643 : : load->kind,
4644 : 287 : load->bbs,
4645 : : updated_gnu_tls_insns,
4646 : : updated_gnu2_tls_insns);
4647 : 287 : break;
4648 : 29720 : case X86_CSE_CONST0_VECTOR:
4649 : 29720 : case X86_CSE_CONSTM1_VECTOR:
4650 : 29720 : case X86_CSE_VEC_DUP:
4651 : 29720 : ix86_place_single_vector_set (load->broadcast_reg,
4652 : : load->broadcast_source,
4653 : : load->bbs,
4654 : : load);
4655 : 29720 : break;
4656 : : }
4657 : : }
4658 : :
4659 : 24778 : loop_optimizer_finalize ();
4660 : :
4661 : 24778 : if (!control_flow_insns.is_empty ())
4662 : : {
4663 : 1 : free_dominance_info (CDI_DOMINATORS);
4664 : :
4665 : 3 : FOR_EACH_VEC_ELT (control_flow_insns, i, insn)
4666 : 1 : if (control_flow_insn_p (insn))
4667 : : {
4668 : : /* Split the block after insn. There will be a fallthru
4669 : : edge, which is OK so we keep it. We have to create
4670 : : the exception edges ourselves. */
4671 : 1 : bb = BLOCK_FOR_INSN (insn);
4672 : 1 : split_block (bb, insn);
4673 : 1 : rtl_make_eh_edge (NULL, bb, BB_END (bb));
4674 : : }
4675 : : }
4676 : :
4677 : 24778 : df_process_deferred_rescans ();
4678 : 24778 : }
4679 : :
4680 : 978833 : df_clear_flags (DF_DEFER_INSN_RESCAN);
4681 : :
4682 : 978833 : timevar_pop (TV_MACH_DEP);
4683 : 978833 : return 0;
4684 : 978833 : }
4685 : :
4686 : : } // anon namespace
4687 : :
4688 : : rtl_opt_pass *
4689 : 285689 : make_pass_x86_cse (gcc::context *ctxt)
4690 : : {
4691 : 285689 : return new pass_x86_cse (ctxt);
4692 : : }
4693 : :
4694 : : /* Convert legacy instructions that clobbers EFLAGS to APX_NF
4695 : : instructions when there are no flag set between a flag
4696 : : producer and user. */
4697 : :
4698 : : static unsigned int
4699 : 357 : ix86_apx_nf_convert (void)
4700 : : {
4701 : 357 : timevar_push (TV_MACH_DEP);
4702 : :
4703 : 357 : basic_block bb;
4704 : 357 : rtx_insn *insn;
4705 : 357 : hash_map <rtx_insn *, rtx> converting_map;
4706 : 357 : auto_vec <rtx_insn *> current_convert_list;
4707 : :
4708 : 357 : bool converting_seq = false;
4709 : 357 : rtx cc = gen_rtx_REG (CCmode, FLAGS_REG);
4710 : :
4711 : 758 : FOR_EACH_BB_FN (bb, cfun)
4712 : : {
4713 : : /* Reset conversion for each bb. */
4714 : 401 : converting_seq = false;
4715 : 4538 : FOR_BB_INSNS (bb, insn)
4716 : : {
4717 : 4137 : if (!NONDEBUG_INSN_P (insn))
4718 : 4505 : continue;
4719 : :
4720 : 3350 : if (recog_memoized (insn) < 0)
4721 : 330 : continue;
4722 : :
4723 : : /* Convert candidate insns after cstore, which should
4724 : : satisify the two conditions:
4725 : : 1. Is not flag user or producer, only clobbers
4726 : : FLAGS_REG.
4727 : : 2. Have corresponding nf pattern. */
4728 : :
4729 : 3020 : rtx pat = PATTERN (insn);
4730 : :
4731 : : /* Starting convertion at first cstorecc. */
4732 : 3020 : rtx set = NULL_RTX;
4733 : 3020 : if (!converting_seq
4734 : 2617 : && (set = single_set (insn))
4735 : 2558 : && ix86_comparison_operator (SET_SRC (set), VOIDmode)
4736 : 63 : && reg_overlap_mentioned_p (cc, SET_SRC (set))
4737 : 3080 : && !reg_overlap_mentioned_p (cc, SET_DEST (set)))
4738 : : {
4739 : 60 : converting_seq = true;
4740 : 60 : current_convert_list.truncate (0);
4741 : : }
4742 : : /* Terminate at the next explicit flag set. */
4743 : 2960 : else if (reg_set_p (cc, pat)
4744 : 2960 : && GET_CODE (set_of (cc, pat)) != CLOBBER)
4745 : : converting_seq = false;
4746 : :
4747 : 2868 : if (!converting_seq)
4748 : 2601 : continue;
4749 : :
4750 : 419 : if (get_attr_has_nf (insn)
4751 : 419 : && GET_CODE (pat) == PARALLEL)
4752 : : {
4753 : : /* Record the insn to candidate map. */
4754 : 17 : current_convert_list.safe_push (insn);
4755 : 17 : converting_map.put (insn, pat);
4756 : : }
4757 : : /* If the insn clobbers flags but has no nf_attr,
4758 : : revoke all previous candidates. */
4759 : 402 : else if (!get_attr_has_nf (insn)
4760 : 401 : && reg_set_p (cc, pat)
4761 : 402 : && GET_CODE (set_of (cc, pat)) == CLOBBER)
4762 : : {
4763 : 0 : for (auto item : current_convert_list)
4764 : 0 : converting_map.remove (item);
4765 : 0 : converting_seq = false;
4766 : : }
4767 : : }
4768 : : }
4769 : :
4770 : 357 : if (!converting_map.is_empty ())
4771 : : {
4772 : 25 : for (auto iter = converting_map.begin ();
4773 : 50 : iter != converting_map.end (); ++iter)
4774 : : {
4775 : 17 : rtx_insn *replace = (*iter).first;
4776 : 17 : rtx pat = (*iter).second;
4777 : 17 : int i, n = 0, len = XVECLEN (pat, 0);
4778 : 17 : rtx *new_elems = XALLOCAVEC (rtx, len);
4779 : 17 : rtx new_pat;
4780 : 51 : for (i = 0; i < len; i++)
4781 : : {
4782 : 34 : rtx temp = XVECEXP (pat, 0, i);
4783 : 51 : if (! (GET_CODE (temp) == CLOBBER
4784 : 17 : && reg_overlap_mentioned_p (cc,
4785 : 17 : XEXP (temp, 0))))
4786 : : {
4787 : 17 : new_elems[n] = temp;
4788 : 17 : n++;
4789 : : }
4790 : : }
4791 : :
4792 : 17 : if (n == 1)
4793 : 17 : new_pat = new_elems[0];
4794 : : else
4795 : 0 : new_pat =
4796 : 0 : gen_rtx_PARALLEL (VOIDmode,
4797 : : gen_rtvec_v (n,
4798 : : new_elems));
4799 : :
4800 : 17 : PATTERN (replace) = new_pat;
4801 : 17 : INSN_CODE (replace) = -1;
4802 : 17 : recog_memoized (replace);
4803 : 17 : df_insn_rescan (replace);
4804 : : }
4805 : : }
4806 : :
4807 : 357 : timevar_pop (TV_MACH_DEP);
4808 : 357 : return 0;
4809 : 357 : }
4810 : :
4811 : :
4812 : : namespace {
4813 : :
4814 : : const pass_data pass_data_apx_nf_convert =
4815 : : {
4816 : : RTL_PASS, /* type */
4817 : : "apx_nfcvt", /* name */
4818 : : OPTGROUP_NONE, /* optinfo_flags */
4819 : : TV_MACH_DEP, /* tv_id */
4820 : : 0, /* properties_required */
4821 : : 0, /* properties_provided */
4822 : : 0, /* properties_destroyed */
4823 : : 0, /* todo_flags_start */
4824 : : 0, /* todo_flags_finish */
4825 : : };
4826 : :
4827 : : class pass_apx_nf_convert : public rtl_opt_pass
4828 : : {
4829 : : public:
4830 : 285689 : pass_apx_nf_convert (gcc::context *ctxt)
4831 : 571378 : : rtl_opt_pass (pass_data_apx_nf_convert, ctxt)
4832 : : {}
4833 : :
4834 : : /* opt_pass methods: */
4835 : 1481340 : bool gate (function *) final override
4836 : : {
4837 : 1481340 : return (TARGET_APX_NF
4838 : 448 : && optimize
4839 : 1481780 : && optimize_function_for_speed_p (cfun));
4840 : : }
4841 : :
4842 : 357 : unsigned int execute (function *) final override
4843 : : {
4844 : 357 : return ix86_apx_nf_convert ();
4845 : : }
4846 : : }; // class pass_apx_nf_convert
4847 : :
4848 : : } // anon namespace
4849 : :
4850 : : rtl_opt_pass *
4851 : 285689 : make_pass_apx_nf_convert (gcc::context *ctxt)
4852 : : {
4853 : 285689 : return new pass_apx_nf_convert (ctxt);
4854 : : }
4855 : :
4856 : : /* When a hot loop can be fit into one cacheline,
4857 : : force align the loop without considering the max skip. */
4858 : : static void
4859 : 980661 : ix86_align_loops ()
4860 : : {
4861 : 980661 : basic_block bb;
4862 : :
4863 : : /* Don't do this when we don't know cache line size. */
4864 : 980661 : if (ix86_cost->prefetch_block == 0)
4865 : 9 : return;
4866 : :
4867 : 980652 : loop_optimizer_init (AVOID_CFG_MODIFICATIONS);
4868 : 980652 : profile_count count_threshold = cfun->cfg->count_max / param_align_threshold;
4869 : 11579515 : FOR_EACH_BB_FN (bb, cfun)
4870 : : {
4871 : 10598863 : rtx_insn *label = BB_HEAD (bb);
4872 : 10598863 : bool has_fallthru = 0;
4873 : 10598863 : edge e;
4874 : 10598863 : edge_iterator ei;
4875 : :
4876 : 10598863 : if (!LABEL_P (label))
4877 : 5356616 : continue;
4878 : :
4879 : 5247538 : profile_count fallthru_count = profile_count::zero ();
4880 : 5247538 : profile_count branch_count = profile_count::zero ();
4881 : :
4882 : 15213899 : FOR_EACH_EDGE (e, ei, bb->preds)
4883 : : {
4884 : 9966361 : if (e->flags & EDGE_FALLTHRU)
4885 : 2546342 : has_fallthru = 1, fallthru_count += e->count ();
4886 : : else
4887 : 7420019 : branch_count += e->count ();
4888 : : }
4889 : :
4890 : 5247538 : if (!fallthru_count.initialized_p () || !branch_count.initialized_p ())
4891 : 5291 : continue;
4892 : :
4893 : 5242247 : if (bb->loop_father
4894 : 5242247 : && bb->loop_father->latch != EXIT_BLOCK_PTR_FOR_FN (cfun)
4895 : 6589943 : && (has_fallthru
4896 : 1347696 : ? (!(single_succ_p (bb)
4897 : 145670 : && single_succ (bb) == EXIT_BLOCK_PTR_FOR_FN (cfun))
4898 : 938906 : && optimize_bb_for_speed_p (bb)
4899 : 853731 : && branch_count + fallthru_count > count_threshold
4900 : 732712 : && (branch_count > fallthru_count * param_align_loop_iterations))
4901 : : /* In case there'no fallthru for the loop.
4902 : : Nops inserted won't be executed. */
4903 : 408790 : : (branch_count > count_threshold
4904 : 139959 : || (bb->count > bb->prev_bb->count * 10
4905 : 12699 : && (bb->prev_bb->count
4906 : 4707776 : <= ENTRY_BLOCK_PTR_FOR_FN (cfun)->count / 2)))))
4907 : : {
4908 : 547170 : rtx_insn* insn, *end_insn;
4909 : 547170 : HOST_WIDE_INT size = 0;
4910 : 547170 : bool padding_p = true;
4911 : 547170 : basic_block tbb = bb;
4912 : 547170 : unsigned cond_branch_num = 0;
4913 : 547170 : bool detect_tight_loop_p = false;
4914 : :
4915 : 866360 : for (unsigned int i = 0; i != bb->loop_father->num_nodes;
4916 : 319190 : i++, tbb = tbb->next_bb)
4917 : : {
4918 : : /* Only handle continuous cfg layout. */
4919 : 866360 : if (bb->loop_father != tbb->loop_father)
4920 : : {
4921 : : padding_p = false;
4922 : : break;
4923 : : }
4924 : :
4925 : 10118202 : FOR_BB_INSNS (tbb, insn)
4926 : : {
4927 : 9457132 : if (!NONDEBUG_INSN_P (insn))
4928 : 5372816 : continue;
4929 : 4084316 : size += ix86_min_insn_size (insn);
4930 : :
4931 : : /* We don't know size of inline asm.
4932 : : Don't align loop for call. */
4933 : 4084316 : if (asm_noperands (PATTERN (insn)) >= 0
4934 : 4084316 : || CALL_P (insn))
4935 : : {
4936 : : size = -1;
4937 : : break;
4938 : : }
4939 : : }
4940 : :
4941 : 823654 : if (size == -1 || size > ix86_cost->prefetch_block)
4942 : : {
4943 : : padding_p = false;
4944 : : break;
4945 : : }
4946 : :
4947 : 1463833 : FOR_EACH_EDGE (e, ei, tbb->succs)
4948 : : {
4949 : : /* It could be part of the loop. */
4950 : 1007035 : if (e->dest == bb)
4951 : : {
4952 : : detect_tight_loop_p = true;
4953 : : break;
4954 : : }
4955 : : }
4956 : :
4957 : 635092 : if (detect_tight_loop_p)
4958 : : break;
4959 : :
4960 : 456798 : end_insn = BB_END (tbb);
4961 : 456798 : if (JUMP_P (end_insn))
4962 : : {
4963 : : /* For decoded icache:
4964 : : 1. Up to two branches are allowed per Way.
4965 : : 2. A non-conditional branch is the last micro-op in a Way.
4966 : : */
4967 : 367415 : if (onlyjump_p (end_insn)
4968 : 367415 : && (any_uncondjump_p (end_insn)
4969 : 311547 : || single_succ_p (tbb)))
4970 : : {
4971 : : padding_p = false;
4972 : : break;
4973 : : }
4974 : 311547 : else if (++cond_branch_num >= 2)
4975 : : {
4976 : : padding_p = false;
4977 : : break;
4978 : : }
4979 : : }
4980 : :
4981 : : }
4982 : :
4983 : 547170 : if (padding_p && detect_tight_loop_p)
4984 : : {
4985 : 356588 : emit_insn_before (gen_max_skip_align (GEN_INT (ceil_log2 (size)),
4986 : : GEN_INT (0)), label);
4987 : : /* End of function. */
4988 : 178294 : if (!tbb || tbb == EXIT_BLOCK_PTR_FOR_FN (cfun))
4989 : : break;
4990 : : /* Skip bb which already fits into one cacheline. */
4991 : : bb = tbb;
4992 : : }
4993 : : }
4994 : : }
4995 : :
4996 : 980652 : loop_optimizer_finalize ();
4997 : 980652 : free_dominance_info (CDI_DOMINATORS);
4998 : : }
4999 : :
5000 : : namespace {
5001 : :
5002 : : const pass_data pass_data_align_tight_loops =
5003 : : {
5004 : : RTL_PASS, /* type */
5005 : : "align_tight_loops", /* name */
5006 : : OPTGROUP_NONE, /* optinfo_flags */
5007 : : TV_MACH_DEP, /* tv_id */
5008 : : 0, /* properties_required */
5009 : : 0, /* properties_provided */
5010 : : 0, /* properties_destroyed */
5011 : : 0, /* todo_flags_start */
5012 : : 0, /* todo_flags_finish */
5013 : : };
5014 : :
5015 : : class pass_align_tight_loops : public rtl_opt_pass
5016 : : {
5017 : : public:
5018 : 285689 : pass_align_tight_loops (gcc::context *ctxt)
5019 : 571378 : : rtl_opt_pass (pass_data_align_tight_loops, ctxt)
5020 : : {}
5021 : :
5022 : : /* opt_pass methods: */
5023 : 1481340 : bool gate (function *) final override
5024 : : {
5025 : 1481340 : return TARGET_ALIGN_TIGHT_LOOPS
5026 : 1480871 : && optimize
5027 : 2525851 : && optimize_function_for_speed_p (cfun);
5028 : : }
5029 : :
5030 : 980661 : unsigned int execute (function *) final override
5031 : : {
5032 : 980661 : timevar_push (TV_MACH_DEP);
5033 : : #ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
5034 : 980661 : ix86_align_loops ();
5035 : : #endif
5036 : 980661 : timevar_pop (TV_MACH_DEP);
5037 : 980661 : return 0;
5038 : : }
5039 : : }; // class pass_align_tight_loops
5040 : :
5041 : : } // anon namespace
5042 : :
5043 : : rtl_opt_pass *
5044 : 285689 : make_pass_align_tight_loops (gcc::context *ctxt)
5045 : : {
5046 : 285689 : return new pass_align_tight_loops (ctxt);
5047 : : }
5048 : :
5049 : : /* This compares the priority of target features in function DECL1
5050 : : and DECL2. It returns positive value if DECL1 is higher priority,
5051 : : negative value if DECL2 is higher priority and 0 if they are the
5052 : : same. */
5053 : :
5054 : : int
5055 : 5384 : ix86_compare_version_priority (tree decl1, tree decl2)
5056 : : {
5057 : 5384 : unsigned int priority1 = get_builtin_code_for_version (decl1, NULL);
5058 : 5384 : unsigned int priority2 = get_builtin_code_for_version (decl2, NULL);
5059 : :
5060 : 5384 : return (int)priority1 - (int)priority2;
5061 : : }
5062 : :
5063 : : /* V1 and V2 point to function versions with different priorities
5064 : : based on the target ISA. This function compares their priorities. */
5065 : :
5066 : : static int
5067 : 6647 : feature_compare (const void *v1, const void *v2)
5068 : : {
5069 : 6647 : typedef struct _function_version_info
5070 : : {
5071 : : tree version_decl;
5072 : : tree predicate_chain;
5073 : : unsigned int dispatch_priority;
5074 : : } function_version_info;
5075 : :
5076 : 6647 : const function_version_info c1 = *(const function_version_info *)v1;
5077 : 6647 : const function_version_info c2 = *(const function_version_info *)v2;
5078 : 6647 : return (c2.dispatch_priority - c1.dispatch_priority);
5079 : : }
5080 : :
5081 : : /* This adds a condition to the basic_block NEW_BB in function FUNCTION_DECL
5082 : : to return a pointer to VERSION_DECL if the outcome of the expression
5083 : : formed by PREDICATE_CHAIN is true. This function will be called during
5084 : : version dispatch to decide which function version to execute. It returns
5085 : : the basic block at the end, to which more conditions can be added. */
5086 : :
5087 : : static basic_block
5088 : 812 : add_condition_to_bb (tree function_decl, tree version_decl,
5089 : : tree predicate_chain, basic_block new_bb)
5090 : : {
5091 : 812 : gimple *return_stmt;
5092 : 812 : tree convert_expr, result_var;
5093 : 812 : gimple *convert_stmt;
5094 : 812 : gimple *call_cond_stmt;
5095 : 812 : gimple *if_else_stmt;
5096 : :
5097 : 812 : basic_block bb1, bb2, bb3;
5098 : 812 : edge e12, e23;
5099 : :
5100 : 812 : tree cond_var, and_expr_var = NULL_TREE;
5101 : 812 : gimple_seq gseq;
5102 : :
5103 : 812 : tree predicate_decl, predicate_arg;
5104 : :
5105 : 812 : push_cfun (DECL_STRUCT_FUNCTION (function_decl));
5106 : :
5107 : 812 : gcc_assert (new_bb != NULL);
5108 : 812 : gseq = bb_seq (new_bb);
5109 : :
5110 : :
5111 : 812 : convert_expr = build1 (CONVERT_EXPR, ptr_type_node,
5112 : : build_fold_addr_expr (version_decl));
5113 : 812 : result_var = create_tmp_var (ptr_type_node);
5114 : 812 : convert_stmt = gimple_build_assign (result_var, convert_expr);
5115 : 812 : return_stmt = gimple_build_return (result_var);
5116 : :
5117 : 812 : if (predicate_chain == NULL_TREE)
5118 : : {
5119 : 195 : gimple_seq_add_stmt (&gseq, convert_stmt);
5120 : 195 : gimple_seq_add_stmt (&gseq, return_stmt);
5121 : 195 : set_bb_seq (new_bb, gseq);
5122 : 195 : gimple_set_bb (convert_stmt, new_bb);
5123 : 195 : gimple_set_bb (return_stmt, new_bb);
5124 : 195 : pop_cfun ();
5125 : 195 : return new_bb;
5126 : : }
5127 : :
5128 : 1273 : while (predicate_chain != NULL)
5129 : : {
5130 : 656 : cond_var = create_tmp_var (integer_type_node);
5131 : 656 : predicate_decl = TREE_PURPOSE (predicate_chain);
5132 : 656 : predicate_arg = TREE_VALUE (predicate_chain);
5133 : 656 : call_cond_stmt = gimple_build_call (predicate_decl, 1, predicate_arg);
5134 : 656 : gimple_call_set_lhs (call_cond_stmt, cond_var);
5135 : :
5136 : 656 : gimple_set_block (call_cond_stmt, DECL_INITIAL (function_decl));
5137 : 656 : gimple_set_bb (call_cond_stmt, new_bb);
5138 : 656 : gimple_seq_add_stmt (&gseq, call_cond_stmt);
5139 : :
5140 : 656 : predicate_chain = TREE_CHAIN (predicate_chain);
5141 : :
5142 : 656 : if (and_expr_var == NULL)
5143 : : and_expr_var = cond_var;
5144 : : else
5145 : : {
5146 : 39 : gimple *assign_stmt;
5147 : : /* Use MIN_EXPR to check if any integer is zero?.
5148 : : and_expr_var = min_expr <cond_var, and_expr_var> */
5149 : 39 : assign_stmt = gimple_build_assign (and_expr_var,
5150 : : build2 (MIN_EXPR, integer_type_node,
5151 : : cond_var, and_expr_var));
5152 : :
5153 : 39 : gimple_set_block (assign_stmt, DECL_INITIAL (function_decl));
5154 : 39 : gimple_set_bb (assign_stmt, new_bb);
5155 : 39 : gimple_seq_add_stmt (&gseq, assign_stmt);
5156 : : }
5157 : : }
5158 : :
5159 : 617 : if_else_stmt = gimple_build_cond (GT_EXPR, and_expr_var,
5160 : : integer_zero_node,
5161 : : NULL_TREE, NULL_TREE);
5162 : 617 : gimple_set_block (if_else_stmt, DECL_INITIAL (function_decl));
5163 : 617 : gimple_set_bb (if_else_stmt, new_bb);
5164 : 617 : gimple_seq_add_stmt (&gseq, if_else_stmt);
5165 : :
5166 : 617 : gimple_seq_add_stmt (&gseq, convert_stmt);
5167 : 617 : gimple_seq_add_stmt (&gseq, return_stmt);
5168 : 617 : set_bb_seq (new_bb, gseq);
5169 : :
5170 : 617 : bb1 = new_bb;
5171 : 617 : e12 = split_block (bb1, if_else_stmt);
5172 : 617 : bb2 = e12->dest;
5173 : 617 : e12->flags &= ~EDGE_FALLTHRU;
5174 : 617 : e12->flags |= EDGE_TRUE_VALUE;
5175 : :
5176 : 617 : e23 = split_block (bb2, return_stmt);
5177 : :
5178 : 617 : gimple_set_bb (convert_stmt, bb2);
5179 : 617 : gimple_set_bb (return_stmt, bb2);
5180 : :
5181 : 617 : bb3 = e23->dest;
5182 : 617 : make_edge (bb1, bb3, EDGE_FALSE_VALUE);
5183 : :
5184 : 617 : remove_edge (e23);
5185 : 617 : make_edge (bb2, EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
5186 : :
5187 : 617 : pop_cfun ();
5188 : :
5189 : 617 : return bb3;
5190 : : }
5191 : :
5192 : : /* This function generates the dispatch function for
5193 : : multi-versioned functions. DISPATCH_DECL is the function which will
5194 : : contain the dispatch logic. FNDECLS are the function choices for
5195 : : dispatch, and is a tree chain. EMPTY_BB is the basic block pointer
5196 : : in DISPATCH_DECL in which the dispatch code is generated. */
5197 : :
5198 : : static int
5199 : 195 : dispatch_function_versions (tree dispatch_decl,
5200 : : void *fndecls_p,
5201 : : basic_block *empty_bb)
5202 : : {
5203 : 195 : tree default_decl;
5204 : 195 : gimple *ifunc_cpu_init_stmt;
5205 : 195 : gimple_seq gseq;
5206 : 195 : int ix;
5207 : 195 : tree ele;
5208 : 195 : vec<tree> *fndecls;
5209 : 195 : unsigned int num_versions = 0;
5210 : 195 : unsigned int actual_versions = 0;
5211 : 195 : unsigned int i;
5212 : :
5213 : 195 : struct _function_version_info
5214 : : {
5215 : : tree version_decl;
5216 : : tree predicate_chain;
5217 : : unsigned int dispatch_priority;
5218 : : }*function_version_info;
5219 : :
5220 : 195 : gcc_assert (dispatch_decl != NULL
5221 : : && fndecls_p != NULL
5222 : : && empty_bb != NULL);
5223 : :
5224 : : /*fndecls_p is actually a vector. */
5225 : 195 : fndecls = static_cast<vec<tree> *> (fndecls_p);
5226 : :
5227 : : /* At least one more version other than the default. */
5228 : 195 : num_versions = fndecls->length ();
5229 : 195 : gcc_assert (num_versions >= 2);
5230 : :
5231 : 195 : function_version_info = (struct _function_version_info *)
5232 : 195 : XNEWVEC (struct _function_version_info, (num_versions - 1));
5233 : :
5234 : : /* The first version in the vector is the default decl. */
5235 : 195 : default_decl = (*fndecls)[0];
5236 : :
5237 : 195 : push_cfun (DECL_STRUCT_FUNCTION (dispatch_decl));
5238 : :
5239 : 195 : gseq = bb_seq (*empty_bb);
5240 : : /* Function version dispatch is via IFUNC. IFUNC resolvers fire before
5241 : : constructors, so explicity call __builtin_cpu_init here. */
5242 : 195 : ifunc_cpu_init_stmt
5243 : 195 : = gimple_build_call_vec (get_ix86_builtin (IX86_BUILTIN_CPU_INIT), vNULL);
5244 : 195 : gimple_seq_add_stmt (&gseq, ifunc_cpu_init_stmt);
5245 : 195 : gimple_set_bb (ifunc_cpu_init_stmt, *empty_bb);
5246 : 195 : set_bb_seq (*empty_bb, gseq);
5247 : :
5248 : 195 : pop_cfun ();
5249 : :
5250 : :
5251 : 969 : for (ix = 1; fndecls->iterate (ix, &ele); ++ix)
5252 : : {
5253 : 774 : tree version_decl = ele;
5254 : 774 : tree predicate_chain = NULL_TREE;
5255 : 774 : unsigned int priority;
5256 : : /* Get attribute string, parse it and find the right predicate decl.
5257 : : The predicate function could be a lengthy combination of many
5258 : : features, like arch-type and various isa-variants. */
5259 : 774 : priority = get_builtin_code_for_version (version_decl,
5260 : : &predicate_chain);
5261 : :
5262 : 774 : if (predicate_chain == NULL_TREE)
5263 : 157 : continue;
5264 : :
5265 : 617 : function_version_info [actual_versions].version_decl = version_decl;
5266 : 617 : function_version_info [actual_versions].predicate_chain
5267 : 617 : = predicate_chain;
5268 : 617 : function_version_info [actual_versions].dispatch_priority = priority;
5269 : 617 : actual_versions++;
5270 : : }
5271 : :
5272 : : /* Sort the versions according to descending order of dispatch priority. The
5273 : : priority is based on the ISA. This is not a perfect solution. There
5274 : : could still be ambiguity. If more than one function version is suitable
5275 : : to execute, which one should be dispatched? In future, allow the user
5276 : : to specify a dispatch priority next to the version. */
5277 : 195 : qsort (function_version_info, actual_versions,
5278 : : sizeof (struct _function_version_info), feature_compare);
5279 : :
5280 : 1007 : for (i = 0; i < actual_versions; ++i)
5281 : 617 : *empty_bb = add_condition_to_bb (dispatch_decl,
5282 : : function_version_info[i].version_decl,
5283 : 617 : function_version_info[i].predicate_chain,
5284 : : *empty_bb);
5285 : :
5286 : : /* dispatch default version at the end. */
5287 : 195 : *empty_bb = add_condition_to_bb (dispatch_decl, default_decl,
5288 : : NULL, *empty_bb);
5289 : :
5290 : 195 : free (function_version_info);
5291 : 195 : return 0;
5292 : : }
5293 : :
5294 : : /* This function changes the assembler name for functions that are
5295 : : versions. If DECL is a function version and has a "target"
5296 : : attribute, it appends the attribute string to its assembler name. */
5297 : :
5298 : : static tree
5299 : 828 : ix86_mangle_function_version_assembler_name (tree decl, tree id)
5300 : : {
5301 : 828 : tree version_attr;
5302 : 828 : const char *orig_name, *version_string;
5303 : 828 : char *attr_str, *assembler_name;
5304 : :
5305 : 828 : if (DECL_DECLARED_INLINE_P (decl)
5306 : 882 : && lookup_attribute ("gnu_inline",
5307 : 54 : DECL_ATTRIBUTES (decl)))
5308 : 0 : error_at (DECL_SOURCE_LOCATION (decl),
5309 : : "function versions cannot be marked as %<gnu_inline%>,"
5310 : : " bodies have to be generated");
5311 : :
5312 : 828 : if (DECL_VIRTUAL_P (decl)
5313 : 1656 : || DECL_VINDEX (decl))
5314 : 0 : sorry ("virtual function multiversioning not supported");
5315 : :
5316 : 828 : version_attr = lookup_attribute ("target", DECL_ATTRIBUTES (decl));
5317 : :
5318 : : /* target attribute string cannot be NULL. */
5319 : 828 : gcc_assert (version_attr != NULL_TREE);
5320 : :
5321 : 828 : orig_name = IDENTIFIER_POINTER (id);
5322 : 828 : version_string
5323 : 828 : = TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (version_attr)));
5324 : :
5325 : 828 : if (strcmp (version_string, "default") == 0)
5326 : : return id;
5327 : :
5328 : 681 : attr_str = sorted_attr_string (TREE_VALUE (version_attr));
5329 : 681 : assembler_name = XNEWVEC (char, strlen (orig_name) + strlen (attr_str) + 2);
5330 : :
5331 : 681 : sprintf (assembler_name, "%s.%s", orig_name, attr_str);
5332 : :
5333 : : /* Allow assembler name to be modified if already set. */
5334 : 681 : if (DECL_ASSEMBLER_NAME_SET_P (decl))
5335 : 12 : SET_DECL_RTL (decl, NULL);
5336 : :
5337 : 681 : tree ret = get_identifier (assembler_name);
5338 : 681 : XDELETEVEC (attr_str);
5339 : 681 : XDELETEVEC (assembler_name);
5340 : 681 : return ret;
5341 : : }
5342 : :
5343 : : tree
5344 : 445756247 : ix86_mangle_decl_assembler_name (tree decl, tree id)
5345 : : {
5346 : : /* For function version, add the target suffix to the assembler name. */
5347 : 445756247 : if (TREE_CODE (decl) == FUNCTION_DECL
5348 : 445756247 : && DECL_FUNCTION_VERSIONED (decl))
5349 : 828 : id = ix86_mangle_function_version_assembler_name (decl, id);
5350 : : #ifdef SUBTARGET_MANGLE_DECL_ASSEMBLER_NAME
5351 : : id = SUBTARGET_MANGLE_DECL_ASSEMBLER_NAME (decl, id);
5352 : : #endif
5353 : :
5354 : 445756247 : return id;
5355 : : }
5356 : :
5357 : : /* Make a dispatcher declaration for the multi-versioned function DECL.
5358 : : Calls to DECL function will be replaced with calls to the dispatcher
5359 : : by the front-end. Returns the decl of the dispatcher function. */
5360 : :
5361 : : tree
5362 : 321 : ix86_get_function_versions_dispatcher (void *decl)
5363 : : {
5364 : 321 : tree fn = (tree) decl;
5365 : 321 : struct cgraph_node *node = NULL;
5366 : 321 : struct cgraph_node *default_node = NULL;
5367 : 321 : struct cgraph_function_version_info *node_v = NULL;
5368 : :
5369 : 321 : tree dispatch_decl = NULL;
5370 : :
5371 : 321 : struct cgraph_function_version_info *default_version_info = NULL;
5372 : :
5373 : 642 : gcc_assert (fn != NULL && DECL_FUNCTION_VERSIONED (fn));
5374 : :
5375 : 321 : node = cgraph_node::get (fn);
5376 : 321 : gcc_assert (node != NULL);
5377 : :
5378 : 321 : node_v = node->function_version ();
5379 : 321 : gcc_assert (node_v != NULL);
5380 : :
5381 : 321 : if (node_v->dispatcher_resolver != NULL)
5382 : : return node_v->dispatcher_resolver;
5383 : :
5384 : : /* The default node is always the beginning of the chain. */
5385 : : default_version_info = node_v;
5386 : 654 : while (default_version_info->prev != NULL)
5387 : : default_version_info = default_version_info->prev;
5388 : 207 : default_node = default_version_info->this_node;
5389 : :
5390 : : /* If there is no default node, just return NULL. */
5391 : 207 : if (!is_function_default_version (default_node->decl))
5392 : : return NULL;
5393 : :
5394 : : #if defined (ASM_OUTPUT_TYPE_DIRECTIVE)
5395 : 198 : if (targetm.has_ifunc_p ())
5396 : : {
5397 : 198 : struct cgraph_function_version_info *it_v = NULL;
5398 : 198 : struct cgraph_node *dispatcher_node = NULL;
5399 : 198 : struct cgraph_function_version_info *dispatcher_version_info = NULL;
5400 : :
5401 : : /* Right now, the dispatching is done via ifunc. */
5402 : 198 : dispatch_decl = make_dispatcher_decl (default_node->decl);
5403 : 198 : TREE_NOTHROW (dispatch_decl) = TREE_NOTHROW (fn);
5404 : :
5405 : 198 : dispatcher_node = cgraph_node::get_create (dispatch_decl);
5406 : 198 : gcc_assert (dispatcher_node != NULL);
5407 : 198 : dispatcher_node->dispatcher_function = 1;
5408 : 198 : dispatcher_version_info
5409 : 198 : = dispatcher_node->insert_new_function_version ();
5410 : 198 : dispatcher_version_info->next = default_version_info;
5411 : 198 : dispatcher_node->definition = 1;
5412 : :
5413 : : /* Set the dispatcher for all the versions. */
5414 : 198 : it_v = default_version_info;
5415 : 1173 : while (it_v != NULL)
5416 : : {
5417 : 975 : it_v->dispatcher_resolver = dispatch_decl;
5418 : 975 : it_v = it_v->next;
5419 : : }
5420 : : }
5421 : : else
5422 : : #endif
5423 : : {
5424 : 0 : error_at (DECL_SOURCE_LOCATION (default_node->decl),
5425 : : "multiversioning needs %<ifunc%> which is not supported "
5426 : : "on this target");
5427 : : }
5428 : :
5429 : : return dispatch_decl;
5430 : : }
5431 : :
5432 : : /* Make the resolver function decl to dispatch the versions of
5433 : : a multi-versioned function, DEFAULT_DECL. IFUNC_ALIAS_DECL is
5434 : : ifunc alias that will point to the created resolver. Create an
5435 : : empty basic block in the resolver and store the pointer in
5436 : : EMPTY_BB. Return the decl of the resolver function. */
5437 : :
5438 : : static tree
5439 : 195 : make_resolver_func (const tree default_decl,
5440 : : const tree ifunc_alias_decl,
5441 : : basic_block *empty_bb)
5442 : : {
5443 : 195 : tree decl, type, t;
5444 : :
5445 : : /* Create resolver function name based on default_decl. */
5446 : 195 : tree decl_name = clone_function_name (default_decl, "resolver");
5447 : 195 : const char *resolver_name = IDENTIFIER_POINTER (decl_name);
5448 : :
5449 : : /* The resolver function should return a (void *). */
5450 : 195 : type = build_function_type_list (ptr_type_node, NULL_TREE);
5451 : :
5452 : 195 : decl = build_fn_decl (resolver_name, type);
5453 : 195 : SET_DECL_ASSEMBLER_NAME (decl, decl_name);
5454 : :
5455 : 195 : DECL_NAME (decl) = decl_name;
5456 : 195 : TREE_USED (decl) = 1;
5457 : 195 : DECL_ARTIFICIAL (decl) = 1;
5458 : 195 : DECL_IGNORED_P (decl) = 1;
5459 : 195 : TREE_PUBLIC (decl) = 0;
5460 : 195 : DECL_UNINLINABLE (decl) = 1;
5461 : :
5462 : : /* Resolver is not external, body is generated. */
5463 : 195 : DECL_EXTERNAL (decl) = 0;
5464 : 195 : DECL_EXTERNAL (ifunc_alias_decl) = 0;
5465 : :
5466 : 195 : DECL_CONTEXT (decl) = NULL_TREE;
5467 : 195 : DECL_INITIAL (decl) = make_node (BLOCK);
5468 : 195 : DECL_STATIC_CONSTRUCTOR (decl) = 0;
5469 : :
5470 : 195 : if (DECL_COMDAT_GROUP (default_decl)
5471 : 195 : || TREE_PUBLIC (default_decl))
5472 : : {
5473 : : /* In this case, each translation unit with a call to this
5474 : : versioned function will put out a resolver. Ensure it
5475 : : is comdat to keep just one copy. */
5476 : 171 : DECL_COMDAT (decl) = 1;
5477 : 171 : make_decl_one_only (decl, DECL_ASSEMBLER_NAME (decl));
5478 : : }
5479 : : else
5480 : 24 : TREE_PUBLIC (ifunc_alias_decl) = 0;
5481 : :
5482 : : /* Build result decl and add to function_decl. */
5483 : 195 : t = build_decl (UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE, ptr_type_node);
5484 : 195 : DECL_CONTEXT (t) = decl;
5485 : 195 : DECL_ARTIFICIAL (t) = 1;
5486 : 195 : DECL_IGNORED_P (t) = 1;
5487 : 195 : DECL_RESULT (decl) = t;
5488 : :
5489 : 195 : gimplify_function_tree (decl);
5490 : 195 : push_cfun (DECL_STRUCT_FUNCTION (decl));
5491 : 195 : *empty_bb = init_lowered_empty_function (decl, false,
5492 : : profile_count::uninitialized ());
5493 : :
5494 : 195 : cgraph_node::add_new_function (decl, true);
5495 : 195 : symtab->call_cgraph_insertion_hooks (cgraph_node::get_create (decl));
5496 : :
5497 : 195 : pop_cfun ();
5498 : :
5499 : 195 : gcc_assert (ifunc_alias_decl != NULL);
5500 : : /* Mark ifunc_alias_decl as "ifunc" with resolver as resolver_name. */
5501 : 195 : DECL_ATTRIBUTES (ifunc_alias_decl)
5502 : 195 : = make_attribute ("ifunc", resolver_name,
5503 : 195 : DECL_ATTRIBUTES (ifunc_alias_decl));
5504 : :
5505 : : /* Create the alias for dispatch to resolver here. */
5506 : 195 : cgraph_node::create_same_body_alias (ifunc_alias_decl, decl);
5507 : 195 : return decl;
5508 : : }
5509 : :
5510 : : /* Generate the dispatching code body to dispatch multi-versioned function
5511 : : DECL. The target hook is called to process the "target" attributes and
5512 : : provide the code to dispatch the right function at run-time. NODE points
5513 : : to the dispatcher decl whose body will be created. */
5514 : :
5515 : : tree
5516 : 195 : ix86_generate_version_dispatcher_body (void *node_p)
5517 : : {
5518 : 195 : tree resolver_decl;
5519 : 195 : basic_block empty_bb;
5520 : 195 : tree default_ver_decl;
5521 : 195 : struct cgraph_node *versn;
5522 : 195 : struct cgraph_node *node;
5523 : :
5524 : 195 : struct cgraph_function_version_info *node_version_info = NULL;
5525 : 195 : struct cgraph_function_version_info *versn_info = NULL;
5526 : :
5527 : 195 : node = (cgraph_node *)node_p;
5528 : :
5529 : 195 : node_version_info = node->function_version ();
5530 : 195 : gcc_assert (node->dispatcher_function
5531 : : && node_version_info != NULL);
5532 : :
5533 : 195 : if (node_version_info->dispatcher_resolver)
5534 : : return node_version_info->dispatcher_resolver;
5535 : :
5536 : : /* The first version in the chain corresponds to the default version. */
5537 : 195 : default_ver_decl = node_version_info->next->this_node->decl;
5538 : :
5539 : : /* node is going to be an alias, so remove the finalized bit. */
5540 : 195 : node->definition = false;
5541 : :
5542 : 195 : resolver_decl = make_resolver_func (default_ver_decl,
5543 : : node->decl, &empty_bb);
5544 : :
5545 : 195 : node_version_info->dispatcher_resolver = resolver_decl;
5546 : :
5547 : 195 : push_cfun (DECL_STRUCT_FUNCTION (resolver_decl));
5548 : :
5549 : 195 : auto_vec<tree, 2> fn_ver_vec;
5550 : :
5551 : 1164 : for (versn_info = node_version_info->next; versn_info;
5552 : 969 : versn_info = versn_info->next)
5553 : : {
5554 : 969 : versn = versn_info->this_node;
5555 : : /* Check for virtual functions here again, as by this time it should
5556 : : have been determined if this function needs a vtable index or
5557 : : not. This happens for methods in derived classes that override
5558 : : virtual methods in base classes but are not explicitly marked as
5559 : : virtual. */
5560 : 969 : if (DECL_VINDEX (versn->decl))
5561 : 0 : sorry ("virtual function multiversioning not supported");
5562 : :
5563 : 969 : fn_ver_vec.safe_push (versn->decl);
5564 : : }
5565 : :
5566 : 195 : dispatch_function_versions (resolver_decl, &fn_ver_vec, &empty_bb);
5567 : 195 : cgraph_edge::rebuild_edges ();
5568 : 195 : pop_cfun ();
5569 : 195 : return resolver_decl;
5570 : 195 : }
5571 : :
5572 : :
|