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