Branch data Line data Source code
1 : : /* Scheduler hooks for IA-32 which implement CPU specific logic.
2 : : Copyright (C) 1988-2025 Free Software Foundation, Inc.
3 : :
4 : : This file is part of GCC.
5 : :
6 : : GCC is free software; you can redistribute it and/or modify
7 : : it under the terms of the GNU General Public License as published by
8 : : the Free Software Foundation; either version 3, or (at your option)
9 : : any later version.
10 : :
11 : : GCC is distributed in the hope that it will be useful,
12 : : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : : GNU General Public License for more details.
15 : :
16 : : You should have received a copy of the GNU General Public License
17 : : along with GCC; see the file COPYING3. If not see
18 : : <http://www.gnu.org/licenses/>. */
19 : :
20 : : #define IN_TARGET_CODE 1
21 : :
22 : : #include "config.h"
23 : : #include "system.h"
24 : : #include "coretypes.h"
25 : : #include "backend.h"
26 : : #include "rtl.h"
27 : : #include "tree.h"
28 : : #include "cfghooks.h"
29 : : #include "tm_p.h"
30 : : #include "target.h"
31 : : #include "insn-config.h"
32 : : #include "insn-attr.h"
33 : : #include "insn-opinit.h"
34 : : #include "recog.h"
35 : : #include "tm-constrs.h"
36 : :
37 : : /* Return the maximum number of instructions a cpu can issue. */
38 : :
39 : : int
40 : 34923654 : ix86_issue_rate (void)
41 : : {
42 : 34923654 : switch (ix86_tune)
43 : : {
44 : : case PROCESSOR_PENTIUM:
45 : : case PROCESSOR_LAKEMONT:
46 : : case PROCESSOR_BONNELL:
47 : : case PROCESSOR_SILVERMONT:
48 : : case PROCESSOR_INTEL:
49 : : case PROCESSOR_K6:
50 : : case PROCESSOR_BTVER2:
51 : : case PROCESSOR_PENTIUM4:
52 : : case PROCESSOR_NOCONA:
53 : : return 2;
54 : :
55 : : case PROCESSOR_PENTIUMPRO:
56 : : case PROCESSOR_ATHLON:
57 : : case PROCESSOR_K8:
58 : : case PROCESSOR_AMDFAM10:
59 : : case PROCESSOR_BTVER1:
60 : : case PROCESSOR_LUJIAZUI:
61 : : return 3;
62 : :
63 : : case PROCESSOR_BDVER1:
64 : : case PROCESSOR_BDVER2:
65 : : case PROCESSOR_BDVER3:
66 : : case PROCESSOR_BDVER4:
67 : : case PROCESSOR_ZNVER1:
68 : : case PROCESSOR_ZNVER2:
69 : : case PROCESSOR_ZNVER3:
70 : : case PROCESSOR_ZNVER4:
71 : : case PROCESSOR_CORE2:
72 : : case PROCESSOR_NEHALEM:
73 : : case PROCESSOR_SANDYBRIDGE:
74 : : case PROCESSOR_HASWELL:
75 : : case PROCESSOR_TREMONT:
76 : : case PROCESSOR_SKYLAKE:
77 : : case PROCESSOR_SKYLAKE_AVX512:
78 : : case PROCESSOR_CASCADELAKE:
79 : : case PROCESSOR_CANNONLAKE:
80 : : case PROCESSOR_ALDERLAKE:
81 : : case PROCESSOR_YONGFENG:
82 : : case PROCESSOR_SHIJIDADAO:
83 : : case PROCESSOR_GENERIC:
84 : : return 4;
85 : :
86 : : case PROCESSOR_ICELAKE_CLIENT:
87 : : case PROCESSOR_ICELAKE_SERVER:
88 : : case PROCESSOR_TIGERLAKE:
89 : : case PROCESSOR_COOPERLAKE:
90 : : case PROCESSOR_ROCKETLAKE:
91 : : return 5;
92 : :
93 : : case PROCESSOR_SAPPHIRERAPIDS:
94 : : /* For znver5 decoder can handle 4 or 8 instructions per cycle,
95 : : op cache 12 instruction/cycle, dispatch 8 instructions
96 : : integer rename 8 instructions and Fp 6 instructions.
97 : :
98 : : The scheduler, without understanding out of order nature of the CPU
99 : : is unlikely going to be able to fill all of these. */
100 : : case PROCESSOR_ZNVER5:
101 : : return 6;
102 : :
103 : : default:
104 : : return 1;
105 : : }
106 : : }
107 : :
108 : : /* Return true iff USE_INSN has a memory address with operands set by
109 : : SET_INSN. */
110 : :
111 : : bool
112 : 9976492 : ix86_agi_dependent (rtx_insn *set_insn, rtx_insn *use_insn)
113 : : {
114 : 9976492 : int i;
115 : 9976492 : extract_insn_cached (use_insn);
116 : 12287340 : for (i = recog_data.n_operands - 1; i >= 0; --i)
117 : 11921075 : if (MEM_P (recog_data.operand[i]))
118 : : {
119 : 9610227 : rtx addr = XEXP (recog_data.operand[i], 0);
120 : 9610227 : if (modified_in_p (addr, set_insn) != 0)
121 : : {
122 : : /* No AGI stall if SET_INSN is a push or pop and USE_INSN
123 : : has SP based memory (unless index reg is modified in a pop). */
124 : 4393094 : rtx set = single_set (set_insn);
125 : 4393094 : if (set
126 : 4393094 : && (push_operand (SET_DEST (set), GET_MODE (SET_DEST (set)))
127 : 3595788 : || pop_operand (SET_SRC (set), GET_MODE (SET_SRC (set)))))
128 : : {
129 : 595773 : struct ix86_address parts;
130 : 595773 : if (ix86_decompose_address (addr, &parts)
131 : 595773 : && parts.base == stack_pointer_rtx
132 : 1191332 : && (parts.index == NULL_RTX
133 : 583 : || MEM_P (SET_DEST (set))
134 : 14 : || !modified_in_p (parts.index, set_insn)))
135 : 595556 : return false;
136 : : }
137 : 3797538 : return true;
138 : : }
139 : : return false;
140 : : }
141 : : return false;
142 : : }
143 : :
144 : : /* A subroutine of ix86_adjust_cost -- return TRUE iff INSN reads flags set
145 : : by DEP_INSN and nothing set by DEP_INSN. */
146 : :
147 : : static bool
148 : 0 : ix86_flags_dependent (rtx_insn *insn, rtx_insn *dep_insn, enum attr_type insn_type)
149 : : {
150 : 0 : rtx set, set2;
151 : :
152 : : /* Simplify the test for uninteresting insns. */
153 : 0 : if (insn_type != TYPE_SETCC
154 : 0 : && insn_type != TYPE_ICMOV
155 : 0 : && insn_type != TYPE_FCMOV
156 : 0 : && insn_type != TYPE_IBR)
157 : : return false;
158 : :
159 : 0 : if ((set = single_set (dep_insn)) != 0)
160 : : {
161 : 0 : set = SET_DEST (set);
162 : 0 : set2 = NULL_RTX;
163 : : }
164 : 0 : else if (GET_CODE (PATTERN (dep_insn)) == PARALLEL
165 : 0 : && XVECLEN (PATTERN (dep_insn), 0) == 2
166 : 0 : && GET_CODE (XVECEXP (PATTERN (dep_insn), 0, 0)) == SET
167 : 0 : && GET_CODE (XVECEXP (PATTERN (dep_insn), 0, 1)) == SET)
168 : : {
169 : 0 : set = SET_DEST (XVECEXP (PATTERN (dep_insn), 0, 0));
170 : 0 : set2 = SET_DEST (XVECEXP (PATTERN (dep_insn), 0, 0));
171 : : }
172 : : else
173 : : return false;
174 : :
175 : 0 : if (!REG_P (set) || REGNO (set) != FLAGS_REG)
176 : : return false;
177 : :
178 : : /* This test is true if the dependent insn reads the flags but
179 : : not any other potentially set register. */
180 : 0 : if (!reg_overlap_mentioned_p (set, PATTERN (insn)))
181 : : return false;
182 : :
183 : 0 : if (set2 && reg_overlap_mentioned_p (set2, PATTERN (insn)))
184 : : return false;
185 : :
186 : : return true;
187 : : }
188 : :
189 : : /* Helper function for exact_store_load_dependency.
190 : : Return true if addr is found in insn. */
191 : : static bool
192 : 0 : exact_dependency_1 (rtx addr, rtx insn)
193 : : {
194 : 0 : enum rtx_code code;
195 : 0 : const char *format_ptr;
196 : 0 : int i, j;
197 : :
198 : 0 : code = GET_CODE (insn);
199 : 0 : switch (code)
200 : : {
201 : 0 : case MEM:
202 : 0 : if (rtx_equal_p (addr, insn))
203 : : return true;
204 : : break;
205 : : case REG:
206 : : CASE_CONST_ANY:
207 : : case SYMBOL_REF:
208 : : case CODE_LABEL:
209 : : case PC:
210 : : case EXPR_LIST:
211 : : return false;
212 : : default:
213 : : break;
214 : : }
215 : :
216 : 0 : format_ptr = GET_RTX_FORMAT (code);
217 : 0 : for (i = 0; i < GET_RTX_LENGTH (code); i++)
218 : : {
219 : 0 : switch (*format_ptr++)
220 : : {
221 : 0 : case 'e':
222 : 0 : if (exact_dependency_1 (addr, XEXP (insn, i)))
223 : : return true;
224 : : break;
225 : : case 'E':
226 : 0 : for (j = 0; j < XVECLEN (insn, i); j++)
227 : 0 : if (exact_dependency_1 (addr, XVECEXP (insn, i, j)))
228 : : return true;
229 : : break;
230 : : }
231 : : }
232 : : return false;
233 : : }
234 : :
235 : : /* Return true if there exists exact dependency for store & load, i.e.
236 : : the same memory address is used in them. */
237 : : static bool
238 : 0 : exact_store_load_dependency (rtx_insn *store, rtx_insn *load)
239 : : {
240 : 0 : rtx set1, set2;
241 : :
242 : 0 : set1 = single_set (store);
243 : 0 : if (!set1)
244 : : return false;
245 : 0 : if (!MEM_P (SET_DEST (set1)))
246 : : return false;
247 : 0 : set2 = single_set (load);
248 : 0 : if (!set2)
249 : : return false;
250 : 0 : if (exact_dependency_1 (SET_DEST (set1), SET_SRC (set2)))
251 : : return true;
252 : : return false;
253 : : }
254 : :
255 : :
256 : : /* This function corrects the value of COST (latency) based on the relationship
257 : : between INSN and DEP_INSN through a dependence of type DEP_TYPE, and strength
258 : : DW. It should return the new value.
259 : :
260 : : On x86 CPUs this is most commonly used to model the fact that valus of
261 : : registers used to compute address of memory operand needs to be ready
262 : : earlier than values of registers used in the actual operation. */
263 : :
264 : : int
265 : 146624028 : ix86_adjust_cost (rtx_insn *insn, int dep_type, rtx_insn *dep_insn, int cost,
266 : : unsigned int)
267 : : {
268 : 146624028 : enum attr_type insn_type, dep_insn_type;
269 : 146624028 : enum attr_memory memory;
270 : 146624028 : rtx set, set2;
271 : 146624028 : int dep_insn_code_number;
272 : :
273 : : /* Anti and output dependencies have zero cost on all CPUs. */
274 : 146624028 : if (dep_type != 0)
275 : : return 0;
276 : :
277 : 52087602 : dep_insn_code_number = recog_memoized (dep_insn);
278 : :
279 : : /* If we can't recognize the insns, we can't really do anything. */
280 : 52087602 : if (dep_insn_code_number < 0 || recog_memoized (insn) < 0)
281 : 341178 : return cost;
282 : :
283 : 51746424 : insn_type = get_attr_type (insn);
284 : 51746424 : dep_insn_type = get_attr_type (dep_insn);
285 : :
286 : 51746424 : switch (ix86_tune)
287 : : {
288 : 0 : case PROCESSOR_PENTIUM:
289 : 0 : case PROCESSOR_LAKEMONT:
290 : : /* Address Generation Interlock adds a cycle of latency. */
291 : 0 : if (insn_type == TYPE_LEA)
292 : : {
293 : 0 : rtx addr = PATTERN (insn);
294 : :
295 : 0 : if (GET_CODE (addr) == PARALLEL)
296 : 0 : addr = XVECEXP (addr, 0, 0);
297 : :
298 : 0 : gcc_assert (GET_CODE (addr) == SET);
299 : :
300 : 0 : addr = SET_SRC (addr);
301 : 0 : if (modified_in_p (addr, dep_insn))
302 : 0 : cost += 1;
303 : : }
304 : 0 : else if (ix86_agi_dependent (dep_insn, insn))
305 : 0 : cost += 1;
306 : :
307 : : /* ??? Compares pair with jump/setcc. */
308 : 0 : if (ix86_flags_dependent (insn, dep_insn, insn_type))
309 : 0 : cost = 0;
310 : :
311 : : /* Floating point stores require value to be ready one cycle earlier. */
312 : 0 : if (insn_type == TYPE_FMOV
313 : 0 : && get_attr_memory (insn) == MEMORY_STORE
314 : 0 : && !ix86_agi_dependent (dep_insn, insn))
315 : 0 : cost += 1;
316 : : break;
317 : :
318 : 0 : case PROCESSOR_PENTIUMPRO:
319 : : /* INT->FP conversion is expensive. */
320 : 0 : if (get_attr_fp_int_src (dep_insn))
321 : 0 : cost += 5;
322 : :
323 : : /* There is one cycle extra latency between an FP op and a store. */
324 : 0 : if (insn_type == TYPE_FMOV
325 : 0 : && (set = single_set (dep_insn)) != NULL_RTX
326 : 0 : && (set2 = single_set (insn)) != NULL_RTX
327 : 0 : && rtx_equal_p (SET_DEST (set), SET_SRC (set2))
328 : 0 : && MEM_P (SET_DEST (set2)))
329 : 0 : cost += 1;
330 : :
331 : 0 : memory = get_attr_memory (insn);
332 : :
333 : : /* Show ability of reorder buffer to hide latency of load by executing
334 : : in parallel with previous instruction in case
335 : : previous instruction is not needed to compute the address. */
336 : 0 : if ((memory == MEMORY_LOAD || memory == MEMORY_BOTH)
337 : 0 : && !ix86_agi_dependent (dep_insn, insn))
338 : : {
339 : : /* Claim moves to take one cycle, as core can issue one load
340 : : at time and the next load can start cycle later. */
341 : 0 : if (dep_insn_type == TYPE_IMOV
342 : 0 : || dep_insn_type == TYPE_FMOV)
343 : : cost = 1;
344 : 0 : else if (cost > 1)
345 : 0 : cost--;
346 : : }
347 : : break;
348 : :
349 : 0 : case PROCESSOR_K6:
350 : : /* The esp dependency is resolved before
351 : : the instruction is really finished. */
352 : 0 : if ((insn_type == TYPE_PUSH || insn_type == TYPE_POP)
353 : 0 : && (dep_insn_type == TYPE_PUSH || dep_insn_type == TYPE_POP))
354 : : return 1;
355 : :
356 : : /* INT->FP conversion is expensive. */
357 : 0 : if (get_attr_fp_int_src (dep_insn))
358 : 0 : cost += 5;
359 : :
360 : 0 : memory = get_attr_memory (insn);
361 : :
362 : : /* Show ability of reorder buffer to hide latency of load by executing
363 : : in parallel with previous instruction in case
364 : : previous instruction is not needed to compute the address. */
365 : 0 : if ((memory == MEMORY_LOAD || memory == MEMORY_BOTH)
366 : 0 : && !ix86_agi_dependent (dep_insn, insn))
367 : : {
368 : : /* Claim moves to take one cycle, as core can issue one load
369 : : at time and the next load can start cycle later. */
370 : 0 : if (dep_insn_type == TYPE_IMOV
371 : 0 : || dep_insn_type == TYPE_FMOV)
372 : : cost = 1;
373 : 0 : else if (cost > 2)
374 : 0 : cost -= 2;
375 : : else
376 : : cost = 1;
377 : : }
378 : : break;
379 : :
380 : 9930 : case PROCESSOR_AMDFAM10:
381 : 9930 : case PROCESSOR_BDVER1:
382 : 9930 : case PROCESSOR_BDVER2:
383 : 9930 : case PROCESSOR_BDVER3:
384 : 9930 : case PROCESSOR_BDVER4:
385 : 9930 : case PROCESSOR_BTVER1:
386 : 9930 : case PROCESSOR_BTVER2:
387 : : /* Stack engine allows to execute push&pop instructions in parall. */
388 : 9930 : if ((insn_type == TYPE_PUSH || insn_type == TYPE_POP)
389 : 322 : && (dep_insn_type == TYPE_PUSH || dep_insn_type == TYPE_POP))
390 : : return 0;
391 : : /* FALLTHRU */
392 : :
393 : 75197 : case PROCESSOR_ATHLON:
394 : 75197 : case PROCESSOR_K8:
395 : 75197 : memory = get_attr_memory (insn);
396 : :
397 : : /* Show ability of reorder buffer to hide latency of load by executing
398 : : in parallel with previous instruction in case
399 : : previous instruction is not needed to compute the address. */
400 : 75197 : if ((memory == MEMORY_LOAD || memory == MEMORY_BOTH)
401 : 75197 : && !ix86_agi_dependent (dep_insn, insn))
402 : : {
403 : 11808 : enum attr_unit unit = get_attr_unit (insn);
404 : 11808 : int loadcost = 3;
405 : :
406 : : /* Because of the difference between the length of integer and
407 : : floating unit pipeline preparation stages, the memory operands
408 : : for floating point are cheaper.
409 : :
410 : : ??? For Athlon it the difference is most probably 2. */
411 : 11808 : if (unit == UNIT_INTEGER || unit == UNIT_UNKNOWN)
412 : : loadcost = 3;
413 : : else
414 : 6951 : loadcost = TARGET_CPU_P (ATHLON) ? 2 : 0;
415 : :
416 : 11808 : if (cost >= loadcost)
417 : 7723 : cost -= loadcost;
418 : : else
419 : : cost = 0;
420 : : }
421 : : break;
422 : :
423 : 3002 : case PROCESSOR_ZNVER1:
424 : 3002 : case PROCESSOR_ZNVER2:
425 : 3002 : case PROCESSOR_ZNVER3:
426 : 3002 : case PROCESSOR_ZNVER4:
427 : 3002 : case PROCESSOR_ZNVER5:
428 : : /* Stack engine allows to execute push&pop instructions in parall. */
429 : 3002 : if ((insn_type == TYPE_PUSH || insn_type == TYPE_POP)
430 : 452 : && (dep_insn_type == TYPE_PUSH || dep_insn_type == TYPE_POP))
431 : : return 0;
432 : :
433 : 2815 : memory = get_attr_memory (insn);
434 : :
435 : : /* Show ability of reorder buffer to hide latency of load by executing
436 : : in parallel with previous instruction in case
437 : : previous instruction is not needed to compute the address. */
438 : 2815 : if ((memory == MEMORY_LOAD || memory == MEMORY_BOTH)
439 : 2815 : && !ix86_agi_dependent (dep_insn, insn))
440 : : {
441 : 489 : enum attr_unit unit = get_attr_unit (insn);
442 : 489 : int loadcost;
443 : :
444 : : /* TODO: On znver5 complex addressing modes have
445 : : greater latency. */
446 : 489 : if (unit == UNIT_INTEGER || unit == UNIT_UNKNOWN)
447 : : loadcost = 4;
448 : : else
449 : 352 : loadcost = 7;
450 : :
451 : 489 : if (cost >= loadcost)
452 : 44 : cost -= loadcost;
453 : : else
454 : : cost = 0;
455 : : }
456 : : break;
457 : :
458 : 0 : case PROCESSOR_YONGFENG:
459 : 0 : case PROCESSOR_SHIJIDADAO:
460 : : /* Stack engine allows to execute push&pop instructions in parallel. */
461 : 0 : if ((insn_type == TYPE_PUSH || insn_type == TYPE_POP)
462 : 0 : && (dep_insn_type == TYPE_PUSH || dep_insn_type == TYPE_POP))
463 : : return 0;
464 : : /* FALLTHRU */
465 : :
466 : 0 : case PROCESSOR_LUJIAZUI:
467 : 0 : memory = get_attr_memory (insn);
468 : :
469 : : /* Show ability of reorder buffer to hide latency of load by executing
470 : : in parallel with previous instruction in case
471 : : previous instruction is not needed to compute the address. */
472 : 0 : if ((memory == MEMORY_LOAD || memory == MEMORY_BOTH)
473 : 0 : && !ix86_agi_dependent (dep_insn, insn))
474 : : {
475 : 0 : int loadcost = 4;
476 : :
477 : 0 : if (cost >= loadcost)
478 : 0 : cost -= loadcost;
479 : : else
480 : : cost = 0;
481 : : }
482 : : break;
483 : :
484 : 51634048 : case PROCESSOR_CORE2:
485 : 51634048 : case PROCESSOR_NEHALEM:
486 : 51634048 : case PROCESSOR_SANDYBRIDGE:
487 : 51634048 : case PROCESSOR_HASWELL:
488 : 51634048 : case PROCESSOR_TREMONT:
489 : 51634048 : case PROCESSOR_ALDERLAKE:
490 : 51634048 : case PROCESSOR_GENERIC:
491 : : /* Stack engine allows to execute push&pop instructions in parall. */
492 : 51634048 : if ((insn_type == TYPE_PUSH || insn_type == TYPE_POP)
493 : 9587297 : && (dep_insn_type == TYPE_PUSH || dep_insn_type == TYPE_POP))
494 : : return 0;
495 : :
496 : 45423535 : memory = get_attr_memory (insn);
497 : :
498 : : /* Show ability of reorder buffer to hide latency of load by executing
499 : : in parallel with previous instruction in case
500 : : previous instruction is not needed to compute the address. */
501 : 45423535 : if ((memory == MEMORY_LOAD || memory == MEMORY_BOTH)
502 : 45423535 : && !ix86_agi_dependent (dep_insn, insn))
503 : : {
504 : 6166600 : if (cost >= 4)
505 : 213979 : cost -= 4;
506 : : else
507 : : cost = 0;
508 : : }
509 : : break;
510 : :
511 : 2903 : case PROCESSOR_SILVERMONT:
512 : 2903 : case PROCESSOR_INTEL:
513 : 2903 : if (!reload_completed)
514 : : return cost;
515 : :
516 : : /* Increase cost of integer loads. */
517 : 2903 : memory = get_attr_memory (dep_insn);
518 : 2903 : if (memory == MEMORY_LOAD || memory == MEMORY_BOTH)
519 : : {
520 : 620 : enum attr_unit unit = get_attr_unit (dep_insn);
521 : 620 : if (unit == UNIT_INTEGER && cost == 1)
522 : : {
523 : 424 : if (memory == MEMORY_LOAD)
524 : : cost = 3;
525 : : else
526 : : {
527 : : /* Increase cost of ld/st for short int types only
528 : : because of store forwarding issue. */
529 : 0 : rtx set = single_set (dep_insn);
530 : 0 : if (set && (GET_MODE (SET_DEST (set)) == QImode
531 : 0 : || GET_MODE (SET_DEST (set)) == HImode))
532 : : {
533 : : /* Increase cost of store/load insn if exact
534 : : dependence exists and it is load insn. */
535 : 0 : enum attr_memory insn_memory = get_attr_memory (insn);
536 : 0 : if (insn_memory == MEMORY_LOAD
537 : 0 : && exact_store_load_dependency (dep_insn, insn))
538 : : cost = 3;
539 : : }
540 : : }
541 : : }
542 : : }
543 : :
544 : : default:
545 : : break;
546 : : }
547 : :
548 : : return cost;
549 : : }
550 : :
551 : : /* How many alternative schedules to try. This should be as wide as the
552 : : scheduling freedom in the DFA, but no wider. Making this value too
553 : : large results extra work for the scheduler. */
554 : :
555 : : int
556 : 929840 : ia32_multipass_dfa_lookahead (void)
557 : : {
558 : : /* Generally, we want haifa-sched:max_issue() to look ahead as far
559 : : as many instructions can be executed on a cycle, i.e.,
560 : : issue_rate. */
561 : 929840 : if (reload_completed)
562 : 929587 : return ix86_issue_rate ();
563 : : /* Don't use lookahead for pre-reload schedule to save compile time. */
564 : : return 0;
565 : : }
566 : :
567 : : /* Return true if target platform supports macro-fusion. */
568 : :
569 : : bool
570 : 96485265 : ix86_macro_fusion_p ()
571 : : {
572 : 96485265 : return TARGET_FUSE_CMP_AND_BRANCH;
573 : : }
574 : :
575 : : /* Check whether MOV is a reg-reg move and ALU is an
576 : : ALU operation that allows macro-op fusion. */
577 : :
578 : : static bool
579 : 772 : ix86_fuse_mov_alu_p (rtx_insn *mov, rtx_insn *alu)
580 : : {
581 : : /* Validate mov:
582 : : - It should be reg-reg move with opcode 0x89 or 0x8B. */
583 : 772 : rtx set1 = PATTERN (mov);
584 : 772 : if (GET_CODE (set1) != SET
585 : 629 : || !GENERAL_REG_P (SET_SRC (set1))
586 : 919 : || !GENERAL_REG_P (SET_DEST (set1)))
587 : : return false;
588 : 48 : rtx reg = SET_DEST (set1);
589 : : /* - it should have 0x89 or 0x8B opcode. */
590 : 48 : if (!INTEGRAL_MODE_P (GET_MODE (reg))
591 : 96 : || GET_MODE_SIZE (GET_MODE (reg)) < 2
592 : 96 : || GET_MODE_SIZE (GET_MODE (reg)) > 8)
593 : : return false;
594 : : /* Validate ALU. */
595 : 48 : if (GET_CODE (PATTERN (alu)) != PARALLEL)
596 : : return false;
597 : 1 : rtx set2 = XVECEXP (PATTERN (alu), 0, 0);
598 : 1 : if (GET_CODE (set2) != SET)
599 : : return false;
600 : : /* If this is instruction setting both compare and normal
601 : : register, the first set always sets flags, while
602 : : second set writes to the output operan. Pick
603 : : the second set. */
604 : 1 : if (GET_CODE (SET_SRC (set2)) == COMPARE)
605 : : {
606 : 0 : set2 = XVECEXP (PATTERN (alu), 0, 1);
607 : 0 : if (GET_CODE (set2) != SET)
608 : : return false;
609 : : }
610 : : /* Match one of:
611 : : ADD ADC AND XOR OR SUB SBB INC DEC NOT SAL SHL SHR SAR
612 : : We also may add insn attribute to handle some of sporadic
613 : : case we output those with different RTX expressions. */
614 : :
615 : 1 : if (GET_CODE (SET_SRC (set2)) != PLUS
616 : 1 : && GET_CODE (SET_SRC (set2)) != MINUS
617 : : && GET_CODE (SET_SRC (set2)) != XOR
618 : : && GET_CODE (SET_SRC (set2)) != AND
619 : : && GET_CODE (SET_SRC (set2)) != IOR
620 : : && GET_CODE (SET_SRC (set2)) != NOT
621 : : && GET_CODE (SET_SRC (set2)) != ASHIFT
622 : : && GET_CODE (SET_SRC (set2)) != ASHIFTRT
623 : : && GET_CODE (SET_SRC (set2)) != LSHIFTRT)
624 : : return false;
625 : 1 : rtx op0 = XEXP (SET_SRC (set2), 0);
626 : 1 : rtx op1 = GET_CODE (SET_SRC (set2)) != NOT ? XEXP (SET_SRC (set2), 1) : NULL;
627 : : /* One of operands should be register. */
628 : 1 : if (op1 && (!REG_P (op0) || REGNO (op0) != REGNO (reg)))
629 : : std::swap (op0, op1);
630 : 1 : if (!REG_P (op0) || REGNO (op0) != REGNO (reg))
631 : : return false;
632 : 0 : if (op1
633 : 0 : && !REG_P (op1)
634 : 0 : && !x86_64_immediate_operand (op1, VOIDmode))
635 : : return false;
636 : : /* Only one of two parameters must be move destination. */
637 : 0 : if (op1 && REG_P (op1) && REGNO (op1) == REGNO (reg))
638 : : return false;
639 : : return true;
640 : : }
641 : :
642 : : /* Check whether current microarchitecture support macro fusion
643 : : for insn pair "CONDGEN + CONDJMP". Refer to
644 : : "Intel Architectures Optimization Reference Manual". */
645 : :
646 : : bool
647 : 40015499 : ix86_macro_fusion_pair_p (rtx_insn *condgen, rtx_insn *condjmp)
648 : : {
649 : 40015499 : if (TARGET_FUSE_MOV_AND_ALU
650 : 40015499 : && ix86_fuse_mov_alu_p (condgen, condjmp))
651 : : return true;
652 : 40015499 : rtx src, imm = NULL_RTX;
653 : 40015499 : enum rtx_code ccode;
654 : 40015499 : rtx compare_set = NULL_RTX, test_if, cond;
655 : 40015499 : rtx alu_set = NULL_RTX, addr = NULL_RTX;
656 : 40015499 : rtx alu_clobber = NULL_RTX;
657 : 40015499 : enum attr_type condgen_type;
658 : :
659 : 40015499 : if (!any_condjump_p (condjmp))
660 : : return false;
661 : :
662 : 4330579 : unsigned int condreg1, condreg2;
663 : 4330579 : rtx cc_reg_1;
664 : 4330579 : targetm.fixed_condition_code_regs (&condreg1, &condreg2);
665 : 4330579 : cc_reg_1 = gen_rtx_REG (CCmode, condreg1);
666 : 4330579 : if (!reg_referenced_p (cc_reg_1, PATTERN (condjmp))
667 : 4330579 : || !condgen
668 : 8661158 : || !modified_in_p (cc_reg_1, condgen))
669 : 113643 : return false;
670 : :
671 : 4216936 : condgen_type = get_attr_type (condgen);
672 : 4216936 : if (condgen_type == TYPE_MULTI
673 : 161 : && INSN_CODE (condgen) == code_for_stack_protect_test_1 (ptr_mode)
674 : 4217097 : && TARGET_FUSE_ALU_AND_BRANCH)
675 : : {
676 : : /* stack_protect_test_<mode> ends with a sub, which subtracts
677 : : a non-rip special memory operand from a GPR. */
678 : 161 : src = NULL_RTX;
679 : 161 : alu_set = XVECEXP (PATTERN (condgen), 0, 1);
680 : 161 : goto handle_stack_protect_test;
681 : : }
682 : : /* ??? zen5 can fuse cmp, test, sub, add, inc, dec, or, and xor.
683 : : Cores can not fuse or and xor which will pass the test below
684 : : since type is ALU. */
685 : 4216775 : else if (condgen_type != TYPE_TEST
686 : 4216775 : && condgen_type != TYPE_ICMP
687 : 4216775 : && condgen_type != TYPE_INCDEC
688 : 370196 : && condgen_type != TYPE_ALU)
689 : : return false;
690 : :
691 : 4008433 : compare_set = single_set (condgen);
692 : 4008433 : if (compare_set == NULL_RTX && !TARGET_FUSE_ALU_AND_BRANCH)
693 : : return false;
694 : :
695 : 64585 : if (compare_set == NULL_RTX)
696 : : {
697 : 64585 : int i;
698 : 64585 : rtx pat = PATTERN (condgen);
699 : 193755 : for (i = 0; i < XVECLEN (pat, 0); i++)
700 : 129170 : if (GET_CODE (XVECEXP (pat, 0, i)) == SET)
701 : : {
702 : 129170 : rtx set_src = SET_SRC (XVECEXP (pat, 0, i));
703 : 129170 : if (GET_CODE (set_src) == COMPARE)
704 : : compare_set = XVECEXP (pat, 0, i);
705 : : else
706 : 68986 : alu_set = XVECEXP (pat, 0, i);
707 : : }
708 : : /* We also possibly generated ALU instruction only to set
709 : : flags. In this case there will be clobber. */
710 : 0 : else if (GET_CODE (XVECEXP (pat, 0, i)) == CLOBBER
711 : 0 : && GENERAL_REG_P (XEXP (XVECEXP (pat, 0, i), 0)))
712 : : alu_clobber = XVECEXP (pat, 0, i);
713 : : }
714 : 64585 : if (compare_set == NULL_RTX)
715 : : return false;
716 : 4004010 : src = SET_SRC (compare_set);
717 : 4004010 : if (GET_CODE (src) != COMPARE)
718 : : return false;
719 : :
720 : : /* Check for memory operand. */
721 : 3998190 : if (MEM_P (XEXP (src, 0)))
722 : 534600 : addr = XEXP (XEXP (src, 0), 0);
723 : 3463590 : else if (MEM_P (XEXP (src, 1)))
724 : 351031 : addr = XEXP (XEXP (src, 1), 0);
725 : : /* Some CPUs, i.e. tigerlake and cooperlake does not fuse
726 : : ALU with memory operand. */
727 : 885631 : if (addr && !TARGET_FUSE_ALU_AND_BRANCH_MEM)
728 : : return false;
729 : 3998181 : if (CONST_INT_P (XEXP (src, 0)))
730 : : imm = XEXP (src, 0);
731 : 3998181 : else if (CONST_INT_P (XEXP (src, 1)))
732 : : imm = XEXP (src, 1);
733 : : /* Check that the instruction really has immediate.
734 : : In particular compare with 0 is done using test with no immediate. */
735 : 2629106 : if (imm && !get_attr_length_immediate (condgen))
736 : : imm = NULL;
737 : : /* Macro-fusion for cmp/test MEM-IMM + conditional jmp is not
738 : : supported. */
739 : 3998181 : if (addr && imm && !TARGET_FUSE_ALU_AND_BRANCH_MEM_IMM)
740 : : return false;
741 : :
742 : : /* No fusion for RIP-relative address. */
743 : 3998057 : if (addr && !TARGET_FUSE_ALU_AND_BRANCH_RIP_RELATIVE)
744 : : {
745 : 885498 : ix86_address parts;
746 : 885498 : int ok = ix86_decompose_address (addr, &parts);
747 : 885498 : gcc_assert (ok);
748 : :
749 : 885498 : if (ix86_rip_relative_addr_p (&parts))
750 : 66525 : return false;
751 : : }
752 : : /* Znver5 supports fussion fusion with their reg/reg, reg/imm and
753 : : reg/mem forms. They are also supported when the instruction has an
754 : : immediate and displacement that meets the criteria of 4 byte displacement
755 : : and 2 byte immediate or the case of 2 byte displacement and 4 byte
756 : : immediate. We do not know the displacement size, so we ignore this
757 : : limitation. */
758 : :
759 : 3112559 : handle_stack_protect_test:
760 : 3931693 : test_if = SET_SRC (pc_set (condjmp));
761 : 3931693 : cond = XEXP (test_if, 0);
762 : 3931693 : ccode = GET_CODE (cond);
763 : : /* Check whether conditional jump use Sign or Overflow Flags. */
764 : 3931693 : if (!TARGET_FUSE_CMP_AND_BRANCH_SOFLAGS
765 : 0 : && (ccode == GE || ccode == GT || ccode == LE || ccode == LT))
766 : : return false;
767 : :
768 : : /* Return true for TYPE_TEST and TYPE_ICMP. */
769 : 3931693 : if (condgen_type == TYPE_TEST || condgen_type == TYPE_ICMP)
770 : : return true;
771 : :
772 : : /* The following is the case that macro-fusion for alu + jmp. */
773 : 157211 : if (!TARGET_FUSE_ALU_AND_BRANCH || (!alu_set && !alu_clobber))
774 : : return false;
775 : :
776 : : /* No fusion for alu op with memory destination operand. */
777 : 60345 : if (alu_set && MEM_P (SET_DEST (alu_set)))
778 : : return false;
779 : :
780 : :
781 : : /* Macro-fusion for inc/dec + unsigned conditional jump is not
782 : : supported on some CPUs while supported on others (znver5 and core_avx512).
783 : : We however never generate it, so we do not need a specific tune for it. */
784 : 58870 : gcc_checking_assert (!(condgen_type == TYPE_INCDEC
785 : : && (ccode == GEU || ccode == GTU || ccode == LEU || ccode == LTU)));
786 : :
787 : : return true;
788 : : }
|