1 /* Scheduler hooks for IA-32 which implement bdver1-4 specific logic.
2    Copyright (C) 1988-2020 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.  Istructions 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 valuse 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
get_mem_group(rtx_insn * insn)160 get_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 
181 static bool
is_cmp(rtx_insn * insn)182 is_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 
195 static bool
dispatch_violation(void)196 dispatch_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 
205 static bool
is_branch(rtx_insn * insn)206 is_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 
213 static bool
is_prefetch(rtx_insn * insn)214 is_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 
222 static void
init_window(int window_num)223 init_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 
261 static dispatch_windows *
allocate_window(void)262 allocate_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 
274 static void
init_dispatch_sched(void)275 init_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 (0);
281   init_window (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 
288 static bool
is_end_basic_block(enum dispatch_group group)289 is_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 
296 static void
process_end_window(void)297 process_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 (1);
306     }
307   init_window (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 
315 static dispatch_windows *
allocate_next_window(int window_num)316 allocate_next_window (int window_num)
317 {
318   if (window_num == 0)
319     {
320       if (dispatch_window_list->next)
321 	  init_window (1);
322       init_window (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 
334 static void
find_constant(rtx in_rtx,imm_info * imm_values)335 find_constant (rtx in_rtx, imm_info *imm_values)
336 {
337   if (INSN_P (in_rtx))
338     in_rtx = PATTERN (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 
380 static int
get_num_immediates(rtx_insn * insn,int * imm,int * imm32,int * imm64)381 get_num_immediates (rtx_insn *insn, int *imm, int *imm32, int *imm64)
382 {
383   imm_info imm_values = {0, 0, 0};
384 
385   find_constant (insn, &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 
395 static bool
has_immediate(rtx_insn * insn)396 has_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, &num_imm_operand, &num_imm32_operand,
404 			       &num_imm64_operand);
405   return false;
406 }
407 
408 /* Return single or double path for instructions.  */
409 
410 static enum insn_path
get_insn_path(rtx_insn * insn)411 get_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 
426 static enum dispatch_group
get_insn_group(rtx_insn * insn)427 get_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 
451 static int
count_num_restricted(rtx_insn * insn,dispatch_windows * window_list)452 count_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, &num_imm_operand, &num_imm32_operand,
466 			      &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 
501 static bool
fits_dispatch_window(rtx_insn * insn)502 fits_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 
558 static void
add_insn_window(rtx_insn * insn,dispatch_windows * window_list,int num_uops)559 add_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, &num_imm_operand, &num_imm32_operand,
576 				 &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 
609 static void
add_to_dispatch_window(rtx_insn * insn)610 add_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, 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, insn_num_uops);
686     }
687   else
688     gcc_unreachable ();
689 
690   if (is_end_basic_block (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 
700 DEBUG_FUNCTION static void
debug_dispatch_window_file(FILE * file,int window_num)701 debug_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 (file, "Window #%d:\n", list->window_num);
712   fprintf (file, "  num_insn = %d, num_uops = %d, window_size = %d\n",
713 	  list->num_insn, list->num_uops, list->window_size);
714   fprintf (file, "  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 (file, "  num_loads = %d, num_stores = %d\n", list->num_loads,
718 	  list->num_stores);
719   fprintf (file, " insn info:\n");
720 
721   for (i = 0; i < MAX_INSN; i++)
722     {
723       if (!list->window[i].insn)
724 	break;
725       fprintf (file, "    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 
736 DEBUG_FUNCTION void
debug_dispatch_window(int window_num)737 debug_dispatch_window (int window_num)
738 {
739   debug_dispatch_window_file (stdout, window_num);
740 }
741 
742 /* Print INSN dispatch information to FILE.  */
743 
744 DEBUG_FUNCTION static void
debug_insn_dispatch_info_file(FILE * file,rtx_insn * insn)745 debug_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, &num_imm_operand, &num_imm32_operand,
762 				 &num_imm64_operand);
763 
764   fprintf (file, " insn info:\n");
765   fprintf (file, "  group = %s, path = %d, byte_len = %d\n",
766 	   group_name[group], path, byte_len);
767   fprintf (file, "  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 
774 DEBUG_FUNCTION void
debug_ready_dispatch(void)775 debug_ready_dispatch (void)
776 {
777   int i;
778   int no_ready = number_in_ready ();
779 
780   fprintf (stdout, "Number of ready: %d\n", no_ready);
781 
782   for (i = 0; i < no_ready; i++)
783     debug_insn_dispatch_info_file (stdout, get_ready_element (i));
784 }
785 
786 /* This routine is the driver of the dispatch scheduler.  */
787 
788 void
ix86_bd_do_dispatch(rtx_insn * insn,int mode)789 ix86_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 
799 bool
ix86_bd_has_dispatch(rtx_insn * insn,int action)800 ix86_bd_has_dispatch (rtx_insn *insn, int action)
801 {
802   /* Current implementation of dispatch scheduler models buldozer only.  */
803   if ((TARGET_BDVER1 || TARGET_BDVER2 || TARGET_BDVER3
804       || TARGET_BDVER4) && flag_dispatch_scheduler)
805     switch (action)
806       {
807       default:
808 	return false;
809 
810       case IS_DISPATCH_ON:
811 	return true;
812 
813       case IS_CMP:
814 	return is_cmp (insn);
815 
816       case DISPATCH_VIOLATION:
817 	return dispatch_violation ();
818 
819       case FITS_DISPATCH_WINDOW:
820 	return fits_dispatch_window (insn);
821       }
822 
823   return false;
824 }
825