1/* Scheduler hooks for IA-32 which implement bdver1-4 specific logic.
2 Copyright (C) 1988-2023 Free Software Foundation, Inc.
3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 3, or (at your option)
9any later version.
10
11GCC is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along 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. */
71enum 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. */
91static unsigned int num_allowable_groups[disp_last] = {
92 0, 2, 1, 1, 2, 4, 4, 2, 1, BIG, BIG
93};
94
95char 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. */
102enum 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. */
116typedef 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. */
129typedef 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 valuse used in an insn. */
147typedef struct imm_info_s
148 {
149 int imm;
150 int imm32;
151 int imm64;
152 } imm_info;
153
154static dispatch_windows *dispatch_window_list;
155static dispatch_windows *dispatch_window_list1;
156
157/* Get dispatch group of insn. */
158
159static enum dispatch_group
160get_mem_group (rtx_insn *insn)
161{
162 enum attr_memory memory;
163
164 if (INSN_CODE (insn) < 0)
165 return disp_no_group;
166 memory = get_attr_memory (insn);
167 if (memory == MEMORY_STORE)
168 return disp_store;
169
170 if (memory == MEMORY_LOAD)
171 return disp_load;
172
173 if (memory == MEMORY_BOTH)
174 return disp_load_store;
175
176 return disp_no_group;
177}
178
179/* Return true if insn is a compare instruction. */
180
181static bool
182is_cmp (rtx_insn *insn)
183{
184 enum attr_type type;
185
186 type = get_attr_type (insn);
187 return (type == TYPE_TEST
188 || type == TYPE_ICMP
189 || type == TYPE_FCMP
190 || GET_CODE (PATTERN (insn)) == COMPARE);
191}
192
193/* Return true if a dispatch violation encountered. */
194
195static bool
196dispatch_violation (void)
197{
198 if (dispatch_window_list->next)
199 return dispatch_window_list->next->violation;
200 return dispatch_window_list->violation;
201}
202
203/* Return true if insn is a branch instruction. */
204
205static bool
206is_branch (rtx_insn *insn)
207{
208 return (CALL_P (insn) || JUMP_P (insn));
209}
210
211/* Return true if insn is a prefetch instruction. */
212
213static bool
214is_prefetch (rtx_insn *insn)
215{
216 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
222static void
223init_window (int window_num)
224{
225 int i;
226 dispatch_windows *new_list;
227
228 if (window_num == 0)
229 new_list = dispatch_window_list;
230 else
231 new_list = dispatch_window_list1;
232
233 new_list->num_insn = 0;
234 new_list->num_uops = 0;
235 new_list->window_size = 0;
236 new_list->next = NULL;
237 new_list->prev = NULL;
238 new_list->window_num = window_num;
239 new_list->num_imm = 0;
240 new_list->num_imm_32 = 0;
241 new_list->num_imm_64 = 0;
242 new_list->imm_size = 0;
243 new_list->num_loads = 0;
244 new_list->num_stores = 0;
245 new_list->violation = false;
246
247 for (i = 0; i < MAX_INSN; i++)
248 {
249 new_list->window[i].insn = NULL;
250 new_list->window[i].group = disp_no_group;
251 new_list->window[i].path = no_path;
252 new_list->window[i].byte_len = 0;
253 new_list->window[i].imm_bytes = 0;
254 }
255 return;
256}
257
258/* This function allocates and initializes a dispatch window and the
259 list container holding a pointer to the window. */
260
261static dispatch_windows *
262allocate_window (void)
263{
264 dispatch_windows *new_list = XNEW (struct dispatch_windows_s);
265 new_list->window = XNEWVEC (struct sched_insn_info_s, MAX_INSN + 1);
266
267 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
274static void
275init_dispatch_sched (void)
276{
277 /* Allocate a dispatch list and a window. */
278 dispatch_window_list = allocate_window ();
279 dispatch_window_list1 = allocate_window ();
280 init_window (window_num: 0);
281 init_window (window_num: 1);
282}
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
288static bool
289is_end_basic_block (enum dispatch_group group)
290{
291 return group == disp_branch;
292}
293
294/* This function is called when the end of a window processing is reached. */
295
296static void
297process_end_window (void)
298{
299 gcc_assert (dispatch_window_list->num_insn <= MAX_INSN);
300 if (dispatch_window_list->next)
301 {
302 gcc_assert (dispatch_window_list1->num_insn <= MAX_INSN);
303 gcc_assert (dispatch_window_list->window_size
304 + dispatch_window_list1->window_size <= 48);
305 init_window (window_num: 1);
306 }
307 init_window (window_num: 0);
308}
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
315static dispatch_windows *
316allocate_next_window (int window_num)
317{
318 if (window_num == 0)
319 {
320 if (dispatch_window_list->next)
321 init_window (window_num: 1);
322 init_window (window_num: 0);
323 return dispatch_window_list;
324 }
325
326 dispatch_window_list->next = dispatch_window_list1;
327 dispatch_window_list1->prev = dispatch_window_list;
328
329 return dispatch_window_list1;
330}
331
332/* Compute number of immediate operands of an instruction. */
333
334static void
335find_constant (rtx in_rtx, imm_info *imm_values)
336{
337 if (INSN_P (in_rtx))
338 in_rtx = PATTERN (insn: in_rtx);
339 subrtx_iterator::array_type array;
340 FOR_EACH_SUBRTX (iter, array, in_rtx, ALL)
341 if (const_rtx x = *iter)
342 switch (GET_CODE (x))
343 {
344 case CONST:
345 case SYMBOL_REF:
346 case CONST_INT:
347 (imm_values->imm)++;
348 if (x86_64_immediate_operand (CONST_CAST_RTX (x), SImode))
349 (imm_values->imm32)++;
350 else
351 (imm_values->imm64)++;
352 break;
353
354 case CONST_DOUBLE:
355 case CONST_WIDE_INT:
356 (imm_values->imm)++;
357 (imm_values->imm64)++;
358 break;
359
360 case CODE_LABEL:
361 if (LABEL_KIND (x) == LABEL_NORMAL)
362 {
363 (imm_values->imm)++;
364 (imm_values->imm32)++;
365 }
366 break;
367
368 default:
369 break;
370 }
371}
372
373/* Return total size of immediate operands of an instruction along with number
374 of corresponding immediate-operands. It initializes its parameters to zero
375 befor calling FIND_CONSTANT.
376 INSN is the input instruction. IMM is the total of immediates.
377 IMM32 is the number of 32 bit immediates. IMM64 is the number of 64
378 bit immediates. */
379
380static int
381get_num_immediates (rtx_insn *insn, int *imm, int *imm32, int *imm64)
382{
383 imm_info imm_values = {.imm: 0, .imm32: 0, .imm64: 0};
384
385 find_constant (in_rtx: insn, imm_values: &imm_values);
386 *imm = imm_values.imm;
387 *imm32 = imm_values.imm32;
388 *imm64 = imm_values.imm64;
389 return imm_values.imm32 * 4 + imm_values.imm64 * 8;
390}
391
392/* This function indicates if an operand of an instruction is an
393 immediate. */
394
395static bool
396has_immediate (rtx_insn *insn)
397{
398 int num_imm_operand;
399 int num_imm32_operand;
400 int num_imm64_operand;
401
402 if (insn)
403 return get_num_immediates (insn, imm: &num_imm_operand, imm32: &num_imm32_operand,
404 imm64: &num_imm64_operand);
405 return false;
406}
407
408/* Return single or double path for instructions. */
409
410static enum insn_path
411get_insn_path (rtx_insn *insn)
412{
413 enum attr_amdfam10_decode path = get_attr_amdfam10_decode (insn);
414
415 if ((int)path == 0)
416 return path_single;
417
418 if ((int)path == 1)
419 return path_double;
420
421 return path_multi;
422}
423
424/* Return insn dispatch group. */
425
426static enum dispatch_group
427get_insn_group (rtx_insn *insn)
428{
429 enum dispatch_group group = get_mem_group (insn);
430 if (group)
431 return group;
432
433 if (is_branch (insn))
434 return disp_branch;
435
436 if (is_cmp (insn))
437 return disp_cmp;
438
439 if (has_immediate (insn))
440 return disp_imm;
441
442 if (is_prefetch (insn))
443 return disp_prefetch;
444
445 return disp_no_group;
446}
447
448/* Count number of GROUP restricted instructions in a dispatch
449 window WINDOW_LIST. */
450
451static int
452count_num_restricted (rtx_insn *insn, dispatch_windows *window_list)
453{
454 enum dispatch_group group = get_insn_group (insn);
455 int imm_size;
456 int num_imm_operand;
457 int num_imm32_operand;
458 int num_imm64_operand;
459
460 if (group == disp_no_group)
461 return 0;
462
463 if (group == disp_imm)
464 {
465 imm_size = get_num_immediates (insn, imm: &num_imm_operand, imm32: &num_imm32_operand,
466 imm64: &num_imm64_operand);
467 if (window_list->imm_size + imm_size > MAX_IMM_SIZE
468 || num_imm_operand + window_list->num_imm > MAX_IMM
469 || (num_imm32_operand > 0
470 && (window_list->num_imm_32 + num_imm32_operand > MAX_IMM_32
471 || window_list->num_imm_64 * 2 + num_imm32_operand > MAX_IMM_32))
472 || (num_imm64_operand > 0
473 && (window_list->num_imm_64 + num_imm64_operand > MAX_IMM_64
474 || window_list->num_imm_32 + num_imm64_operand * 2 > MAX_IMM_32))
475 || (window_list->imm_size + imm_size == MAX_IMM_SIZE
476 && num_imm64_operand > 0
477 && ((window_list->num_imm_64 > 0
478 && window_list->num_insn >= 2)
479 || window_list->num_insn >= 3)))
480 return BIG;
481
482 return 1;
483 }
484
485 if ((group == disp_load_store
486 && (window_list->num_loads >= MAX_LOAD
487 || window_list->num_stores >= MAX_STORE))
488 || ((group == disp_load
489 || group == disp_prefetch)
490 && window_list->num_loads >= MAX_LOAD)
491 || (group == disp_store
492 && window_list->num_stores >= MAX_STORE))
493 return BIG;
494
495 return 1;
496}
497
498/* This function returns true if insn satisfies dispatch rules on the
499 last window scheduled. */
500
501static bool
502fits_dispatch_window (rtx_insn *insn)
503{
504 dispatch_windows *window_list = dispatch_window_list;
505 dispatch_windows *window_list_next = dispatch_window_list->next;
506 unsigned int num_restrict;
507 enum dispatch_group group = get_insn_group (insn);
508 enum insn_path path = get_insn_path (insn);
509 int sum;
510
511 /* Make disp_cmp and disp_jcc get scheduled at the latest. These
512 instructions should be given the lowest priority in the
513 scheduling process in Haifa scheduler to make sure they will be
514 scheduled in the same dispatch window as the reference to them. */
515 if (group == disp_jcc || group == disp_cmp)
516 return false;
517
518 /* Check nonrestricted. */
519 if (group == disp_no_group || group == disp_branch)
520 return true;
521
522 /* Get last dispatch window. */
523 if (window_list_next)
524 window_list = window_list_next;
525
526 if (window_list->window_num == 1)
527 {
528 sum = window_list->prev->window_size + window_list->window_size;
529
530 if (sum == 32
531 || (ix86_min_insn_size (insn) + sum) >= 48)
532 /* Window 1 is full. Go for next window. */
533 return true;
534 }
535
536 num_restrict = count_num_restricted (insn, window_list);
537
538 if (num_restrict > num_allowable_groups[group])
539 return false;
540
541 /* See if it fits in the first window. */
542 if (window_list->window_num == 0)
543 {
544 /* The first widow should have only single and double path
545 uops. */
546 if (path == path_double
547 && (window_list->num_uops + 2) > MAX_INSN)
548 return false;
549 else if (path != path_single)
550 return false;
551 }
552 return true;
553}
554
555/* Add an instruction INSN with NUM_UOPS micro-operations to the
556 dispatch window WINDOW_LIST. */
557
558static void
559add_insn_window (rtx_insn *insn, dispatch_windows *window_list, int num_uops)
560{
561 int byte_len = ix86_min_insn_size (insn);
562 int num_insn = window_list->num_insn;
563 int imm_size;
564 sched_insn_info *window = window_list->window;
565 enum dispatch_group group = get_insn_group (insn);
566 enum insn_path path = get_insn_path (insn);
567 int num_imm_operand;
568 int num_imm32_operand;
569 int num_imm64_operand;
570
571 if (!window_list->violation && group != disp_cmp
572 && !fits_dispatch_window (insn))
573 window_list->violation = true;
574
575 imm_size = get_num_immediates (insn, imm: &num_imm_operand, imm32: &num_imm32_operand,
576 imm64: &num_imm64_operand);
577
578 /* Initialize window with new instruction. */
579 window[num_insn].insn = insn;
580 window[num_insn].byte_len = byte_len;
581 window[num_insn].group = group;
582 window[num_insn].path = path;
583 window[num_insn].imm_bytes = imm_size;
584
585 window_list->window_size += byte_len;
586 window_list->num_insn = num_insn + 1;
587 window_list->num_uops = window_list->num_uops + num_uops;
588 window_list->imm_size += imm_size;
589 window_list->num_imm += num_imm_operand;
590 window_list->num_imm_32 += num_imm32_operand;
591 window_list->num_imm_64 += num_imm64_operand;
592
593 if (group == disp_store)
594 window_list->num_stores += 1;
595 else if (group == disp_load
596 || group == disp_prefetch)
597 window_list->num_loads += 1;
598 else if (group == disp_load_store)
599 {
600 window_list->num_stores += 1;
601 window_list->num_loads += 1;
602 }
603}
604
605/* Adds a scheduled instruction, INSN, to the current dispatch window.
606 If the total bytes of instructions or the number of instructions in
607 the window exceed allowable, it allocates a new window. */
608
609static void
610add_to_dispatch_window (rtx_insn *insn)
611{
612 int byte_len;
613 dispatch_windows *window_list;
614 dispatch_windows *next_list;
615 dispatch_windows *window0_list;
616 enum insn_path path;
617 enum dispatch_group insn_group;
618 bool insn_fits;
619 int num_insn;
620 int num_uops;
621 int window_num;
622 int insn_num_uops;
623 int sum;
624
625 if (INSN_CODE (insn) < 0)
626 return;
627
628 byte_len = ix86_min_insn_size (insn);
629 window_list = dispatch_window_list;
630 next_list = window_list->next;
631 path = get_insn_path (insn);
632 insn_group = get_insn_group (insn);
633
634 /* Get the last dispatch window. */
635 if (next_list)
636 window_list = dispatch_window_list->next;
637
638 if (path == path_single)
639 insn_num_uops = 1;
640 else if (path == path_double)
641 insn_num_uops = 2;
642 else
643 insn_num_uops = (int) path;
644
645 /* If current window is full, get a new window.
646 Window number zero is full, if MAX_INSN uops are scheduled in it.
647 Window number one is full, if window zero's bytes plus window
648 one's bytes is 32, or if the bytes of the new instruction added
649 to the total makes it greater than 48, or it has already MAX_INSN
650 instructions in it. */
651 num_insn = window_list->num_insn;
652 num_uops = window_list->num_uops;
653 window_num = window_list->window_num;
654 insn_fits = fits_dispatch_window (insn);
655
656 if (num_insn >= MAX_INSN
657 || num_uops + insn_num_uops > MAX_INSN
658 || !(insn_fits))
659 {
660 window_num = ~window_num & 1;
661 window_list = allocate_next_window (window_num);
662 }
663
664 if (window_num == 0)
665 {
666 add_insn_window (insn, window_list, num_uops: insn_num_uops);
667 if (window_list->num_insn >= MAX_INSN
668 && insn_group == disp_branch)
669 {
670 process_end_window ();
671 return;
672 }
673 }
674 else if (window_num == 1)
675 {
676 window0_list = window_list->prev;
677 sum = window0_list->window_size + window_list->window_size;
678 if (sum == 32
679 || (byte_len + sum) >= 48)
680 {
681 process_end_window ();
682 window_list = dispatch_window_list;
683 }
684
685 add_insn_window (insn, window_list, num_uops: insn_num_uops);
686 }
687 else
688 gcc_unreachable ();
689
690 if (is_end_basic_block (group: insn_group))
691 {
692 /* End of basic block is reached do end-basic-block process. */
693 process_end_window ();
694 return;
695 }
696}
697
698/* Print the dispatch window, WINDOW_NUM, to FILE. */
699
700DEBUG_FUNCTION static void
701debug_dispatch_window_file (FILE *file, int window_num)
702{
703 dispatch_windows *list;
704 int i;
705
706 if (window_num == 0)
707 list = dispatch_window_list;
708 else
709 list = dispatch_window_list1;
710
711 fprintf (stream: file, format: "Window #%d:\n", list->window_num);
712 fprintf (stream: file, format: " num_insn = %d, num_uops = %d, window_size = %d\n",
713 list->num_insn, list->num_uops, list->window_size);
714 fprintf (stream: file, format: " num_imm = %d, num_imm_32 = %d, num_imm_64 = %d, imm_size = %d\n",
715 list->num_imm, list->num_imm_32, list->num_imm_64, list->imm_size);
716
717 fprintf (stream: file, format: " num_loads = %d, num_stores = %d\n", list->num_loads,
718 list->num_stores);
719 fprintf (stream: file, format: " insn info:\n");
720
721 for (i = 0; i < MAX_INSN; i++)
722 {
723 if (!list->window[i].insn)
724 break;
725 fprintf (stream: file, format: " group[%d] = %s, insn[%d] = %p, path[%d] = %d byte_len[%d] = %d, imm_bytes[%d] = %d\n",
726 i, group_name[list->window[i].group],
727 i, (void *)list->window[i].insn,
728 i, list->window[i].path,
729 i, list->window[i].byte_len,
730 i, list->window[i].imm_bytes);
731 }
732}
733
734/* Print to stdout a dispatch window. */
735
736DEBUG_FUNCTION void
737debug_dispatch_window (int window_num)
738{
739 debug_dispatch_window_file (stdout, window_num);
740}
741
742/* Print INSN dispatch information to FILE. */
743
744DEBUG_FUNCTION static void
745debug_insn_dispatch_info_file (FILE *file, rtx_insn *insn)
746{
747 int byte_len;
748 enum insn_path path;
749 enum dispatch_group group;
750 int imm_size;
751 int num_imm_operand;
752 int num_imm32_operand;
753 int num_imm64_operand;
754
755 if (INSN_CODE (insn) < 0)
756 return;
757
758 byte_len = ix86_min_insn_size (insn);
759 path = get_insn_path (insn);
760 group = get_insn_group (insn);
761 imm_size = get_num_immediates (insn, imm: &num_imm_operand, imm32: &num_imm32_operand,
762 imm64: &num_imm64_operand);
763
764 fprintf (stream: file, format: " insn info:\n");
765 fprintf (stream: file, format: " group = %s, path = %d, byte_len = %d\n",
766 group_name[group], path, byte_len);
767 fprintf (stream: file, format: " num_imm = %d, num_imm_32 = %d, num_imm_64 = %d, imm_size = %d\n",
768 num_imm_operand, num_imm32_operand, num_imm64_operand, imm_size);
769}
770
771/* Print to STDERR the status of the ready list with respect to
772 dispatch windows. */
773
774DEBUG_FUNCTION void
775debug_ready_dispatch (void)
776{
777 int i;
778 int no_ready = number_in_ready ();
779
780 fprintf (stdout, format: "Number of ready: %d\n", no_ready);
781
782 for (i = 0; i < no_ready; i++)
783 debug_insn_dispatch_info_file (stdout, insn: get_ready_element (i));
784}
785
786/* This routine is the driver of the dispatch scheduler. */
787
788void
789ix86_bd_do_dispatch (rtx_insn *insn, int mode)
790{
791 if (mode == DISPATCH_INIT)
792 init_dispatch_sched ();
793 else if (mode == ADD_TO_DISPATCH_WINDOW)
794 add_to_dispatch_window (insn);
795}
796
797/* Return TRUE if Dispatch Scheduling is supported. */
798
799bool
800ix86_bd_has_dispatch (rtx_insn *insn, int action)
801{
802 /* Current implementation of dispatch scheduler models buldozer only. */
803 if ((TARGET_CPU_P (BDVER1) || TARGET_CPU_P (BDVER2)
804 || TARGET_CPU_P (BDVER3) || TARGET_CPU_P (BDVER4))
805 && flag_dispatch_scheduler)
806 switch (action)
807 {
808 default:
809 return false;
810
811 case IS_DISPATCH_ON:
812 return true;
813
814 case IS_CMP:
815 return is_cmp (insn);
816
817 case DISPATCH_VIOLATION:
818 return dispatch_violation ();
819
820 case FITS_DISPATCH_WINDOW:
821 return fits_dispatch_window (insn);
822 }
823
824 return false;
825}
826

source code of gcc/config/i386/x86-tune-sched-bd.cc