Line data Source code
1 : /* Scheduler hooks for IA-32 which implement bdver1-4 specific logic.
2 : Copyright (C) 1988-2026 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 "insn-config.h"
31 : #include "insn-attr.h"
32 : #include "recog.h"
33 : #include "target.h"
34 : #include "rtl-iter.h"
35 : #include "regset.h"
36 : #include "sched-int.h"
37 :
38 : /* The size of the dispatch window is the total number of bytes of
39 : object code allowed in a window. */
40 : #define DISPATCH_WINDOW_SIZE 16
41 :
42 : /* Number of dispatch windows considered for scheduling. */
43 : #define MAX_DISPATCH_WINDOWS 3
44 :
45 : /* Maximum number of instructions in a window. */
46 : #define MAX_INSN 4
47 :
48 : /* Maximum number of immediate operands in a window. */
49 : #define MAX_IMM 4
50 :
51 : /* Maximum number of immediate bits allowed in a window. */
52 : #define MAX_IMM_SIZE 128
53 :
54 : /* Maximum number of 32 bit immediates allowed in a window. */
55 : #define MAX_IMM_32 4
56 :
57 : /* Maximum number of 64 bit immediates allowed in a window. */
58 : #define MAX_IMM_64 2
59 :
60 : /* Maximum total of loads or prefetches allowed in a window. */
61 : #define MAX_LOAD 2
62 :
63 : /* Maximum total of stores allowed in a window. */
64 : #define MAX_STORE 1
65 :
66 : #undef BIG
67 : #define BIG 100
68 :
69 :
70 : /* Dispatch groups. Instructions that affect the mix in a dispatch window. */
71 : enum dispatch_group {
72 : disp_no_group = 0,
73 : disp_load,
74 : disp_store,
75 : disp_load_store,
76 : disp_prefetch,
77 : disp_imm,
78 : disp_imm_32,
79 : disp_imm_64,
80 : disp_branch,
81 : disp_cmp,
82 : disp_jcc,
83 : disp_last
84 : };
85 :
86 : /* Number of allowable groups in a dispatch window. It is an array
87 : indexed by dispatch_group enum. 100 is used as a big number,
88 : because the number of these kind of operations does not have any
89 : effect in dispatch window, but we need them for other reasons in
90 : the table. */
91 : static unsigned int num_allowable_groups[disp_last] = {
92 : 0, 2, 1, 1, 2, 4, 4, 2, 1, BIG, BIG
93 : };
94 :
95 : char group_name[disp_last + 1][16] = {
96 : "disp_no_group", "disp_load", "disp_store", "disp_load_store",
97 : "disp_prefetch", "disp_imm", "disp_imm_32", "disp_imm_64",
98 : "disp_branch", "disp_cmp", "disp_jcc", "disp_last"
99 : };
100 :
101 : /* Instruction path. */
102 : enum insn_path {
103 : no_path = 0,
104 : path_single, /* Single micro op. */
105 : path_double, /* Double micro op. */
106 : path_multi, /* Instructions with more than 2 micro op.. */
107 : last_path
108 : };
109 :
110 : /* sched_insn_info defines a window to the instructions scheduled in
111 : the basic block. It contains a pointer to the insn_info table and
112 : the instruction scheduled.
113 :
114 : Windows are allocated for each basic block and are linked
115 : together. */
116 : typedef struct sched_insn_info_s {
117 : rtx insn;
118 : enum dispatch_group group;
119 : enum insn_path path;
120 : int byte_len;
121 : int imm_bytes;
122 : } sched_insn_info;
123 :
124 : /* Linked list of dispatch windows. This is a two way list of
125 : dispatch windows of a basic block. It contains information about
126 : the number of uops in the window and the total number of
127 : instructions and of bytes in the object code for this dispatch
128 : window. */
129 : typedef struct dispatch_windows_s {
130 : int num_insn; /* Number of insn in the window. */
131 : int num_uops; /* Number of uops in the window. */
132 : int window_size; /* Number of bytes in the window. */
133 : int window_num; /* Window number between 0 or 1. */
134 : int num_imm; /* Number of immediates in an insn. */
135 : int num_imm_32; /* Number of 32 bit immediates in an insn. */
136 : int num_imm_64; /* Number of 64 bit immediates in an insn. */
137 : int imm_size; /* Total immediates in the window. */
138 : int num_loads; /* Total memory loads in the window. */
139 : int num_stores; /* Total memory stores in the window. */
140 : int violation; /* Violation exists in window. */
141 : sched_insn_info *window; /* Pointer to the window. */
142 : struct dispatch_windows_s *next;
143 : struct dispatch_windows_s *prev;
144 : } dispatch_windows;
145 :
146 : /* Immediate values used in an insn. */
147 : typedef struct imm_info_s
148 : {
149 : int imm;
150 : int imm32;
151 : int imm64;
152 : } imm_info;
153 :
154 : static dispatch_windows *dispatch_window_list;
155 : static dispatch_windows *dispatch_window_list1;
156 :
157 : /* Get dispatch group of insn. */
158 :
159 : static enum dispatch_group
160 50 : get_mem_group (rtx_insn *insn)
161 : {
162 50 : enum attr_memory memory;
163 :
164 50 : if (INSN_CODE (insn) < 0)
165 : return disp_no_group;
166 50 : memory = get_attr_memory (insn);
167 50 : if (memory == MEMORY_STORE)
168 : return disp_store;
169 :
170 44 : if (memory == MEMORY_LOAD)
171 : return disp_load;
172 :
173 38 : if (memory == MEMORY_BOTH)
174 0 : return disp_load_store;
175 :
176 : return disp_no_group;
177 : }
178 :
179 : /* Return true if insn is a compare instruction. */
180 :
181 : static bool
182 34 : is_cmp (rtx_insn *insn)
183 : {
184 34 : enum attr_type type;
185 :
186 34 : type = get_attr_type (insn);
187 34 : return (type == TYPE_TEST
188 34 : || type == TYPE_ICMP
189 34 : || type == TYPE_FCMP
190 34 : || GET_CODE (PATTERN (insn)) == COMPARE);
191 : }
192 :
193 : /* Return true if a dispatch violation encountered. */
194 :
195 : static bool
196 0 : dispatch_violation (void)
197 : {
198 0 : if (dispatch_window_list->next)
199 0 : return dispatch_window_list->next->violation;
200 0 : return dispatch_window_list->violation;
201 : }
202 :
203 : /* Return true if insn is a branch instruction. */
204 :
205 : static bool
206 38 : is_branch (rtx_insn *insn)
207 : {
208 38 : return (CALL_P (insn) || JUMP_P (insn));
209 : }
210 :
211 : /* Return true if insn is a prefetch instruction. */
212 :
213 : static bool
214 28 : is_prefetch (rtx_insn *insn)
215 : {
216 28 : return NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == PREFETCH;
217 : }
218 :
219 : /* This function initializes a dispatch window and the list container holding a
220 : pointer to the window. */
221 :
222 : static void
223 7 : init_window (int window_num)
224 : {
225 7 : int i;
226 7 : dispatch_windows *new_list;
227 :
228 7 : if (window_num == 0)
229 4 : new_list = dispatch_window_list;
230 : else
231 3 : new_list = dispatch_window_list1;
232 :
233 7 : new_list->num_insn = 0;
234 7 : new_list->num_uops = 0;
235 7 : new_list->window_size = 0;
236 7 : new_list->next = NULL;
237 7 : new_list->prev = NULL;
238 7 : new_list->window_num = window_num;
239 7 : new_list->num_imm = 0;
240 7 : new_list->num_imm_32 = 0;
241 7 : new_list->num_imm_64 = 0;
242 7 : new_list->imm_size = 0;
243 7 : new_list->num_loads = 0;
244 7 : new_list->num_stores = 0;
245 7 : new_list->violation = false;
246 :
247 35 : for (i = 0; i < MAX_INSN; i++)
248 : {
249 28 : new_list->window[i].insn = NULL;
250 28 : new_list->window[i].group = disp_no_group;
251 28 : new_list->window[i].path = no_path;
252 28 : new_list->window[i].byte_len = 0;
253 28 : new_list->window[i].imm_bytes = 0;
254 : }
255 7 : return;
256 : }
257 :
258 : /* This function allocates and initializes a dispatch window and the
259 : list container holding a pointer to the window. */
260 :
261 : static dispatch_windows *
262 6 : allocate_window (void)
263 : {
264 6 : dispatch_windows *new_list = XNEW (struct dispatch_windows_s);
265 6 : new_list->window = XNEWVEC (struct sched_insn_info_s, MAX_INSN + 1);
266 :
267 6 : return new_list;
268 : }
269 :
270 : /* This routine initializes the dispatch scheduling information. It
271 : initiates building dispatch scheduler tables and constructs the
272 : first dispatch window. */
273 :
274 : static void
275 3 : init_dispatch_sched (void)
276 : {
277 : /* Allocate a dispatch list and a window. */
278 3 : dispatch_window_list = allocate_window ();
279 3 : dispatch_window_list1 = allocate_window ();
280 3 : init_window (0);
281 3 : init_window (1);
282 3 : }
283 :
284 : /* This function returns true if a branch is detected. End of a basic block
285 : does not have to be a branch, but here we assume only branches end a
286 : window. */
287 :
288 : static bool
289 0 : is_end_basic_block (enum dispatch_group group)
290 : {
291 0 : return group == disp_branch;
292 : }
293 :
294 : /* This function is called when the end of a window processing is reached. */
295 :
296 : static void
297 1 : process_end_window (void)
298 : {
299 1 : gcc_assert (dispatch_window_list->num_insn <= MAX_INSN);
300 1 : if (dispatch_window_list->next)
301 : {
302 0 : gcc_assert (dispatch_window_list1->num_insn <= MAX_INSN);
303 0 : gcc_assert (dispatch_window_list->window_size
304 : + dispatch_window_list1->window_size <= 48);
305 0 : init_window (1);
306 : }
307 1 : init_window (0);
308 1 : }
309 :
310 : /* Allocates a new dispatch window and adds it to WINDOW_LIST.
311 : WINDOW_NUM is either 0 or 1. A maximum of two windows are generated
312 : for 48 bytes of instructions. Note that these windows are not dispatch
313 : windows that their sizes are DISPATCH_WINDOW_SIZE. */
314 :
315 : static dispatch_windows *
316 0 : allocate_next_window (int window_num)
317 : {
318 0 : if (window_num == 0)
319 : {
320 0 : if (dispatch_window_list->next)
321 0 : init_window (1);
322 0 : init_window (0);
323 0 : return dispatch_window_list;
324 : }
325 :
326 0 : dispatch_window_list->next = dispatch_window_list1;
327 0 : dispatch_window_list1->prev = dispatch_window_list;
328 :
329 0 : return dispatch_window_list1;
330 : }
331 :
332 : /* Compute number of immediate operands of an instruction. */
333 :
334 : static void
335 47 : find_constant (rtx_insn *insn, imm_info *imm_values)
336 : {
337 47 : rtx in_rtx = INSN_P (insn) ? PATTERN (insn) : insn;
338 47 : subrtx_iterator::array_type array;
339 262 : FOR_EACH_SUBRTX (iter, array, in_rtx, ALL)
340 215 : if (const_rtx x = *iter)
341 215 : switch (GET_CODE (x))
342 : {
343 11 : case CONST:
344 11 : case SYMBOL_REF:
345 11 : case CONST_INT:
346 11 : (imm_values->imm)++;
347 11 : if (x86_64_immediate_operand (const_cast<rtx> (x), SImode))
348 11 : (imm_values->imm32)++;
349 : else
350 0 : (imm_values->imm64)++;
351 : break;
352 :
353 0 : case CONST_DOUBLE:
354 0 : case CONST_WIDE_INT:
355 0 : (imm_values->imm)++;
356 0 : (imm_values->imm64)++;
357 0 : break;
358 :
359 0 : case CODE_LABEL:
360 0 : if (LABEL_KIND (x) == LABEL_NORMAL)
361 : {
362 0 : (imm_values->imm)++;
363 0 : (imm_values->imm32)++;
364 : }
365 : break;
366 :
367 : default:
368 : break;
369 : }
370 47 : }
371 :
372 : /* Return total size of immediate operands of an instruction along with number
373 : of corresponding immediate-operands. It initializes its parameters to zero
374 : before calling FIND_CONSTANT.
375 : INSN is the input instruction. IMM is the total of immediates.
376 : IMM32 is the number of 32 bit immediates. IMM64 is the number of 64
377 : bit immediates. */
378 :
379 : static int
380 47 : get_num_immediates (rtx_insn *insn, int *imm, int *imm32, int *imm64)
381 : {
382 47 : imm_info imm_values = {0, 0, 0};
383 :
384 47 : find_constant (insn, &imm_values);
385 47 : *imm = imm_values.imm;
386 47 : *imm32 = imm_values.imm32;
387 47 : *imm64 = imm_values.imm64;
388 47 : return imm_values.imm32 * 4 + imm_values.imm64 * 8;
389 : }
390 :
391 : /* This function indicates if an operand of an instruction is an
392 : immediate. */
393 :
394 : static bool
395 34 : has_immediate (rtx_insn *insn)
396 : {
397 34 : int num_imm_operand;
398 34 : int num_imm32_operand;
399 34 : int num_imm64_operand;
400 :
401 34 : if (insn)
402 34 : return get_num_immediates (insn, &num_imm_operand, &num_imm32_operand,
403 34 : &num_imm64_operand);
404 : return false;
405 : }
406 :
407 : /* Return single or double path for instructions. */
408 :
409 : static enum insn_path
410 44 : get_insn_path (rtx_insn *insn)
411 : {
412 44 : enum attr_amdfam10_decode path = get_attr_amdfam10_decode (insn);
413 :
414 44 : if ((int)path == 0)
415 : return path_single;
416 :
417 0 : if ((int)path == 1)
418 0 : return path_double;
419 :
420 : return path_multi;
421 : }
422 :
423 : /* Return insn dispatch group. */
424 :
425 : static enum dispatch_group
426 50 : get_insn_group (rtx_insn *insn)
427 : {
428 50 : enum dispatch_group group = get_mem_group (insn);
429 50 : if (group)
430 : return group;
431 :
432 38 : if (is_branch (insn))
433 : return disp_branch;
434 :
435 34 : if (is_cmp (insn))
436 : return disp_cmp;
437 :
438 34 : if (has_immediate (insn))
439 : return disp_imm;
440 :
441 28 : if (is_prefetch (insn))
442 0 : return disp_prefetch;
443 :
444 : return disp_no_group;
445 : }
446 :
447 : /* Count number of GROUP restricted instructions in a dispatch
448 : window WINDOW_LIST. */
449 :
450 : static int
451 6 : count_num_restricted (rtx_insn *insn, dispatch_windows *window_list)
452 : {
453 6 : enum dispatch_group group = get_insn_group (insn);
454 6 : int imm_size;
455 6 : int num_imm_operand;
456 6 : int num_imm32_operand;
457 6 : int num_imm64_operand;
458 :
459 6 : if (group == disp_no_group)
460 : return 0;
461 :
462 6 : if (group == disp_imm)
463 : {
464 2 : imm_size = get_num_immediates (insn, &num_imm_operand, &num_imm32_operand,
465 : &num_imm64_operand);
466 2 : if (window_list->imm_size + imm_size > MAX_IMM_SIZE
467 2 : || num_imm_operand + window_list->num_imm > MAX_IMM
468 2 : || (num_imm32_operand > 0
469 2 : && (window_list->num_imm_32 + num_imm32_operand > MAX_IMM_32
470 2 : || window_list->num_imm_64 * 2 + num_imm32_operand > MAX_IMM_32))
471 2 : || (num_imm64_operand > 0
472 0 : && (window_list->num_imm_64 + num_imm64_operand > MAX_IMM_64
473 0 : || window_list->num_imm_32 + num_imm64_operand * 2 > MAX_IMM_32))
474 2 : || (window_list->imm_size + imm_size == MAX_IMM_SIZE
475 0 : && num_imm64_operand > 0
476 0 : && ((window_list->num_imm_64 > 0
477 0 : && window_list->num_insn >= 2)
478 0 : || window_list->num_insn >= 3)))
479 : return BIG;
480 :
481 2 : return 1;
482 : }
483 :
484 4 : if ((group == disp_load_store
485 0 : && (window_list->num_loads >= MAX_LOAD
486 0 : || window_list->num_stores >= MAX_STORE))
487 4 : || ((group == disp_load
488 4 : || group == disp_prefetch)
489 2 : && window_list->num_loads >= MAX_LOAD)
490 4 : || (group == disp_store
491 2 : && window_list->num_stores >= MAX_STORE))
492 0 : return BIG;
493 :
494 : return 1;
495 : }
496 :
497 : /* This function returns true if insn satisfies dispatch rules on the
498 : last window scheduled. */
499 :
500 : static bool
501 22 : fits_dispatch_window (rtx_insn *insn)
502 : {
503 22 : dispatch_windows *window_list = dispatch_window_list;
504 22 : dispatch_windows *window_list_next = dispatch_window_list->next;
505 22 : unsigned int num_restrict;
506 22 : enum dispatch_group group = get_insn_group (insn);
507 22 : enum insn_path path = get_insn_path (insn);
508 22 : int sum;
509 :
510 : /* Make disp_cmp and disp_jcc get scheduled at the latest. These
511 : instructions should be given the lowest priority in the
512 : scheduling process in Haifa scheduler to make sure they will be
513 : scheduled in the same dispatch window as the reference to them. */
514 22 : if (group == disp_jcc || group == disp_cmp)
515 : return false;
516 :
517 : /* Check nonrestricted. */
518 22 : if (group == disp_no_group || group == disp_branch)
519 : return true;
520 :
521 : /* Get last dispatch window. */
522 6 : if (window_list_next)
523 0 : window_list = window_list_next;
524 :
525 6 : if (window_list->window_num == 1)
526 : {
527 0 : sum = window_list->prev->window_size + window_list->window_size;
528 :
529 0 : if (sum == 32
530 0 : || (ix86_min_insn_size (insn) + sum) >= 48)
531 : /* Window 1 is full. Go for next window. */
532 : return true;
533 : }
534 :
535 6 : num_restrict = count_num_restricted (insn, window_list);
536 :
537 6 : if (num_restrict > num_allowable_groups[group])
538 : return false;
539 :
540 : /* See if it fits in the first window. */
541 6 : if (window_list->window_num == 0)
542 : {
543 : /* The first widow should have only single and double path
544 : uops. */
545 6 : if (path == path_double
546 0 : && (window_list->num_uops + 2) > MAX_INSN)
547 : return false;
548 6 : else if (path != path_single)
549 0 : return false;
550 : }
551 : return true;
552 : }
553 :
554 : /* Add an instruction INSN with NUM_UOPS micro-operations to the
555 : dispatch window WINDOW_LIST. */
556 :
557 : static void
558 11 : add_insn_window (rtx_insn *insn, dispatch_windows *window_list, int num_uops)
559 : {
560 11 : int byte_len = ix86_min_insn_size (insn);
561 11 : int num_insn = window_list->num_insn;
562 11 : int imm_size;
563 11 : sched_insn_info *window = window_list->window;
564 11 : enum dispatch_group group = get_insn_group (insn);
565 11 : enum insn_path path = get_insn_path (insn);
566 11 : int num_imm_operand;
567 11 : int num_imm32_operand;
568 11 : int num_imm64_operand;
569 :
570 11 : if (!window_list->violation && group != disp_cmp
571 22 : && !fits_dispatch_window (insn))
572 0 : window_list->violation = true;
573 :
574 11 : imm_size = get_num_immediates (insn, &num_imm_operand, &num_imm32_operand,
575 : &num_imm64_operand);
576 :
577 : /* Initialize window with new instruction. */
578 11 : window[num_insn].insn = insn;
579 11 : window[num_insn].byte_len = byte_len;
580 11 : window[num_insn].group = group;
581 11 : window[num_insn].path = path;
582 11 : window[num_insn].imm_bytes = imm_size;
583 :
584 11 : window_list->window_size += byte_len;
585 11 : window_list->num_insn = num_insn + 1;
586 11 : window_list->num_uops = window_list->num_uops + num_uops;
587 11 : window_list->imm_size += imm_size;
588 11 : window_list->num_imm += num_imm_operand;
589 11 : window_list->num_imm_32 += num_imm32_operand;
590 11 : window_list->num_imm_64 += num_imm64_operand;
591 :
592 11 : if (group == disp_store)
593 1 : window_list->num_stores += 1;
594 10 : else if (group == disp_load
595 10 : || group == disp_prefetch)
596 1 : window_list->num_loads += 1;
597 9 : else if (group == disp_load_store)
598 : {
599 0 : window_list->num_stores += 1;
600 0 : window_list->num_loads += 1;
601 : }
602 11 : }
603 :
604 : /* Adds a scheduled instruction, INSN, to the current dispatch window.
605 : If the total bytes of instructions or the number of instructions in
606 : the window exceed allowable, it allocates a new window. */
607 :
608 : static void
609 14 : add_to_dispatch_window (rtx_insn *insn)
610 : {
611 14 : int byte_len;
612 14 : dispatch_windows *window_list;
613 14 : dispatch_windows *next_list;
614 14 : dispatch_windows *window0_list;
615 14 : enum insn_path path;
616 14 : enum dispatch_group insn_group;
617 14 : bool insn_fits;
618 14 : int num_insn;
619 14 : int num_uops;
620 14 : int window_num;
621 14 : int insn_num_uops;
622 14 : int sum;
623 :
624 14 : if (INSN_CODE (insn) < 0)
625 : return;
626 :
627 11 : byte_len = ix86_min_insn_size (insn);
628 11 : window_list = dispatch_window_list;
629 11 : next_list = window_list->next;
630 11 : path = get_insn_path (insn);
631 11 : insn_group = get_insn_group (insn);
632 :
633 : /* Get the last dispatch window. */
634 11 : if (next_list)
635 0 : window_list = dispatch_window_list->next;
636 :
637 11 : if (path == path_single)
638 : insn_num_uops = 1;
639 0 : else if (path == path_double)
640 : insn_num_uops = 2;
641 : else
642 0 : insn_num_uops = (int) path;
643 :
644 : /* If current window is full, get a new window.
645 : Window number zero is full, if MAX_INSN uops are scheduled in it.
646 : Window number one is full, if window zero's bytes plus window
647 : one's bytes is 32, or if the bytes of the new instruction added
648 : to the total makes it greater than 48, or it has already MAX_INSN
649 : instructions in it. */
650 11 : num_insn = window_list->num_insn;
651 11 : num_uops = window_list->num_uops;
652 11 : window_num = window_list->window_num;
653 11 : insn_fits = fits_dispatch_window (insn);
654 :
655 11 : if (num_insn >= MAX_INSN
656 11 : || num_uops + insn_num_uops > MAX_INSN
657 11 : || !(insn_fits))
658 : {
659 0 : window_num = ~window_num & 1;
660 0 : window_list = allocate_next_window (window_num);
661 : }
662 :
663 11 : if (window_num == 0)
664 : {
665 11 : add_insn_window (insn, window_list, insn_num_uops);
666 11 : if (window_list->num_insn >= MAX_INSN
667 2 : && insn_group == disp_branch)
668 : {
669 1 : process_end_window ();
670 1 : return;
671 : }
672 : }
673 0 : else if (window_num == 1)
674 : {
675 0 : window0_list = window_list->prev;
676 0 : sum = window0_list->window_size + window_list->window_size;
677 0 : if (sum == 32
678 0 : || (byte_len + sum) >= 48)
679 : {
680 0 : process_end_window ();
681 0 : window_list = dispatch_window_list;
682 : }
683 :
684 0 : add_insn_window (insn, window_list, insn_num_uops);
685 : }
686 : else
687 0 : gcc_unreachable ();
688 :
689 9 : if (is_end_basic_block (insn_group))
690 : {
691 : /* End of basic block is reached do end-basic-block process. */
692 0 : process_end_window ();
693 0 : return;
694 : }
695 : }
696 :
697 : /* Print the dispatch window, WINDOW_NUM, to FILE. */
698 :
699 : DEBUG_FUNCTION static void
700 0 : debug_dispatch_window_file (FILE *file, int window_num)
701 : {
702 0 : dispatch_windows *list;
703 0 : int i;
704 :
705 0 : if (window_num == 0)
706 0 : list = dispatch_window_list;
707 : else
708 0 : list = dispatch_window_list1;
709 :
710 0 : fprintf (file, "Window #%d:\n", list->window_num);
711 0 : fprintf (file, " num_insn = %d, num_uops = %d, window_size = %d\n",
712 : list->num_insn, list->num_uops, list->window_size);
713 0 : fprintf (file, " num_imm = %d, num_imm_32 = %d, num_imm_64 = %d, imm_size = %d\n",
714 : list->num_imm, list->num_imm_32, list->num_imm_64, list->imm_size);
715 :
716 0 : fprintf (file, " num_loads = %d, num_stores = %d\n", list->num_loads,
717 : list->num_stores);
718 0 : fprintf (file, " insn info:\n");
719 :
720 0 : for (i = 0; i < MAX_INSN; i++)
721 : {
722 0 : if (!list->window[i].insn)
723 : break;
724 0 : fprintf (file, " group[%d] = %s, insn[%d] = %p, path[%d] = %d byte_len[%d] = %d, imm_bytes[%d] = %d\n",
725 0 : i, group_name[list->window[i].group],
726 : i, (void *)list->window[i].insn,
727 0 : i, list->window[i].path,
728 : i, list->window[i].byte_len,
729 : i, list->window[i].imm_bytes);
730 : }
731 0 : }
732 :
733 : /* Print to stdout a dispatch window. */
734 :
735 : DEBUG_FUNCTION void
736 0 : debug_dispatch_window (int window_num)
737 : {
738 0 : debug_dispatch_window_file (stdout, window_num);
739 0 : }
740 :
741 : /* Print INSN dispatch information to FILE. */
742 :
743 : DEBUG_FUNCTION static void
744 0 : debug_insn_dispatch_info_file (FILE *file, rtx_insn *insn)
745 : {
746 0 : int byte_len;
747 0 : enum insn_path path;
748 0 : enum dispatch_group group;
749 0 : int imm_size;
750 0 : int num_imm_operand;
751 0 : int num_imm32_operand;
752 0 : int num_imm64_operand;
753 :
754 0 : if (INSN_CODE (insn) < 0)
755 : return;
756 :
757 0 : byte_len = ix86_min_insn_size (insn);
758 0 : path = get_insn_path (insn);
759 0 : group = get_insn_group (insn);
760 0 : imm_size = get_num_immediates (insn, &num_imm_operand, &num_imm32_operand,
761 : &num_imm64_operand);
762 :
763 0 : fprintf (file, " insn info:\n");
764 0 : fprintf (file, " group = %s, path = %d, byte_len = %d\n",
765 0 : group_name[group], path, byte_len);
766 0 : fprintf (file, " num_imm = %d, num_imm_32 = %d, num_imm_64 = %d, imm_size = %d\n",
767 : num_imm_operand, num_imm32_operand, num_imm64_operand, imm_size);
768 : }
769 :
770 : /* Print to STDERR the status of the ready list with respect to
771 : dispatch windows. */
772 :
773 : DEBUG_FUNCTION void
774 0 : debug_ready_dispatch (void)
775 : {
776 0 : int i;
777 0 : int no_ready = number_in_ready ();
778 :
779 0 : fprintf (stdout, "Number of ready: %d\n", no_ready);
780 :
781 0 : for (i = 0; i < no_ready; i++)
782 0 : debug_insn_dispatch_info_file (stdout, get_ready_element (i));
783 0 : }
784 :
785 : /* This routine is the driver of the dispatch scheduler. */
786 :
787 : void
788 17 : ix86_bd_do_dispatch (rtx_insn *insn, int mode)
789 : {
790 17 : if (mode == DISPATCH_INIT)
791 3 : init_dispatch_sched ();
792 14 : else if (mode == ADD_TO_DISPATCH_WINDOW)
793 14 : add_to_dispatch_window (insn);
794 17 : }
795 :
796 : /* Return TRUE if Dispatch Scheduling is supported. */
797 :
798 : bool
799 62962452 : ix86_bd_has_dispatch (rtx_insn *insn, int action)
800 : {
801 : /* Current implementation of dispatch scheduler models buldozer only. */
802 62962452 : if ((TARGET_CPU_P (BDVER1) || TARGET_CPU_P (BDVER2)
803 62962452 : || TARGET_CPU_P (BDVER3) || TARGET_CPU_P (BDVER4))
804 2269 : && flag_dispatch_scheduler)
805 33 : switch (action)
806 : {
807 : default:
808 : return false;
809 :
810 33 : case IS_DISPATCH_ON:
811 33 : return true;
812 :
813 0 : case IS_CMP:
814 0 : return is_cmp (insn);
815 :
816 0 : case DISPATCH_VIOLATION:
817 0 : return dispatch_violation ();
818 :
819 0 : case FITS_DISPATCH_WINDOW:
820 0 : return fits_dispatch_window (insn);
821 : }
822 :
823 : return false;
824 : }
|