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 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
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 : 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 in_rtx, imm_info *imm_values)
336 : {
337 47 : if (INSN_P (in_rtx))
338 47 : in_rtx = PATTERN (in_rtx);
339 47 : subrtx_iterator::array_type array;
340 262 : FOR_EACH_SUBRTX (iter, array, in_rtx, ALL)
341 215 : if (const_rtx x = *iter)
342 215 : switch (GET_CODE (x))
343 : {
344 11 : case CONST:
345 11 : case SYMBOL_REF:
346 11 : case CONST_INT:
347 11 : (imm_values->imm)++;
348 11 : if (x86_64_immediate_operand (const_cast<rtx> (x), SImode))
349 11 : (imm_values->imm32)++;
350 : else
351 0 : (imm_values->imm64)++;
352 : break;
353 :
354 0 : case CONST_DOUBLE:
355 0 : case CONST_WIDE_INT:
356 0 : (imm_values->imm)++;
357 0 : (imm_values->imm64)++;
358 0 : break;
359 :
360 0 : case CODE_LABEL:
361 0 : if (LABEL_KIND (x) == LABEL_NORMAL)
362 : {
363 0 : (imm_values->imm)++;
364 0 : (imm_values->imm32)++;
365 : }
366 : break;
367 :
368 : default:
369 : break;
370 : }
371 47 : }
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
381 47 : get_num_immediates (rtx_insn *insn, int *imm, int *imm32, int *imm64)
382 : {
383 47 : imm_info imm_values = {0, 0, 0};
384 :
385 47 : find_constant (insn, &imm_values);
386 47 : *imm = imm_values.imm;
387 47 : *imm32 = imm_values.imm32;
388 47 : *imm64 = imm_values.imm64;
389 47 : 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
396 34 : has_immediate (rtx_insn *insn)
397 : {
398 34 : int num_imm_operand;
399 34 : int num_imm32_operand;
400 34 : int num_imm64_operand;
401 :
402 34 : if (insn)
403 34 : return get_num_immediates (insn, &num_imm_operand, &num_imm32_operand,
404 34 : &num_imm64_operand);
405 : return false;
406 : }
407 :
408 : /* Return single or double path for instructions. */
409 :
410 : static enum insn_path
411 44 : get_insn_path (rtx_insn *insn)
412 : {
413 44 : enum attr_amdfam10_decode path = get_attr_amdfam10_decode (insn);
414 :
415 44 : if ((int)path == 0)
416 : return path_single;
417 :
418 0 : if ((int)path == 1)
419 0 : return path_double;
420 :
421 : return path_multi;
422 : }
423 :
424 : /* Return insn dispatch group. */
425 :
426 : static enum dispatch_group
427 50 : get_insn_group (rtx_insn *insn)
428 : {
429 50 : enum dispatch_group group = get_mem_group (insn);
430 50 : if (group)
431 : return group;
432 :
433 38 : if (is_branch (insn))
434 : return disp_branch;
435 :
436 34 : if (is_cmp (insn))
437 : return disp_cmp;
438 :
439 34 : if (has_immediate (insn))
440 : return disp_imm;
441 :
442 28 : if (is_prefetch (insn))
443 0 : 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
452 6 : count_num_restricted (rtx_insn *insn, dispatch_windows *window_list)
453 : {
454 6 : enum dispatch_group group = get_insn_group (insn);
455 6 : int imm_size;
456 6 : int num_imm_operand;
457 6 : int num_imm32_operand;
458 6 : int num_imm64_operand;
459 :
460 6 : if (group == disp_no_group)
461 : return 0;
462 :
463 6 : if (group == disp_imm)
464 : {
465 2 : imm_size = get_num_immediates (insn, &num_imm_operand, &num_imm32_operand,
466 : &num_imm64_operand);
467 2 : if (window_list->imm_size + imm_size > MAX_IMM_SIZE
468 2 : || num_imm_operand + window_list->num_imm > MAX_IMM
469 2 : || (num_imm32_operand > 0
470 2 : && (window_list->num_imm_32 + num_imm32_operand > MAX_IMM_32
471 2 : || window_list->num_imm_64 * 2 + num_imm32_operand > MAX_IMM_32))
472 2 : || (num_imm64_operand > 0
473 0 : && (window_list->num_imm_64 + num_imm64_operand > MAX_IMM_64
474 0 : || window_list->num_imm_32 + num_imm64_operand * 2 > MAX_IMM_32))
475 2 : || (window_list->imm_size + imm_size == MAX_IMM_SIZE
476 0 : && num_imm64_operand > 0
477 0 : && ((window_list->num_imm_64 > 0
478 0 : && window_list->num_insn >= 2)
479 0 : || window_list->num_insn >= 3)))
480 : return BIG;
481 :
482 : return 1;
483 : }
484 :
485 4 : if ((group == disp_load_store
486 0 : && (window_list->num_loads >= MAX_LOAD
487 0 : || window_list->num_stores >= MAX_STORE))
488 4 : || ((group == disp_load
489 4 : || group == disp_prefetch)
490 2 : && window_list->num_loads >= MAX_LOAD)
491 4 : || (group == disp_store
492 2 : && 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
502 22 : fits_dispatch_window (rtx_insn *insn)
503 : {
504 22 : dispatch_windows *window_list = dispatch_window_list;
505 22 : dispatch_windows *window_list_next = dispatch_window_list->next;
506 22 : unsigned int num_restrict;
507 22 : enum dispatch_group group = get_insn_group (insn);
508 22 : enum insn_path path = get_insn_path (insn);
509 22 : 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 22 : if (group == disp_jcc || group == disp_cmp)
516 : return false;
517 :
518 : /* Check nonrestricted. */
519 22 : if (group == disp_no_group || group == disp_branch)
520 : return true;
521 :
522 : /* Get last dispatch window. */
523 6 : if (window_list_next)
524 0 : window_list = window_list_next;
525 :
526 6 : if (window_list->window_num == 1)
527 : {
528 0 : sum = window_list->prev->window_size + window_list->window_size;
529 :
530 0 : if (sum == 32
531 0 : || (ix86_min_insn_size (insn) + sum) >= 48)
532 : /* Window 1 is full. Go for next window. */
533 0 : return true;
534 : }
535 :
536 6 : num_restrict = count_num_restricted (insn, window_list);
537 :
538 6 : if (num_restrict > num_allowable_groups[group])
539 : return false;
540 :
541 : /* See if it fits in the first window. */
542 6 : if (window_list->window_num == 0)
543 : {
544 : /* The first widow should have only single and double path
545 : uops. */
546 6 : if (path == path_double
547 0 : && (window_list->num_uops + 2) > MAX_INSN)
548 : return false;
549 6 : 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
559 11 : add_insn_window (rtx_insn *insn, dispatch_windows *window_list, int num_uops)
560 : {
561 11 : int byte_len = ix86_min_insn_size (insn);
562 11 : int num_insn = window_list->num_insn;
563 11 : int imm_size;
564 11 : sched_insn_info *window = window_list->window;
565 11 : enum dispatch_group group = get_insn_group (insn);
566 11 : enum insn_path path = get_insn_path (insn);
567 11 : int num_imm_operand;
568 11 : int num_imm32_operand;
569 11 : int num_imm64_operand;
570 :
571 11 : if (!window_list->violation && group != disp_cmp
572 22 : && !fits_dispatch_window (insn))
573 0 : window_list->violation = true;
574 :
575 11 : imm_size = get_num_immediates (insn, &num_imm_operand, &num_imm32_operand,
576 : &num_imm64_operand);
577 :
578 : /* Initialize window with new instruction. */
579 11 : window[num_insn].insn = insn;
580 11 : window[num_insn].byte_len = byte_len;
581 11 : window[num_insn].group = group;
582 11 : window[num_insn].path = path;
583 11 : window[num_insn].imm_bytes = imm_size;
584 :
585 11 : window_list->window_size += byte_len;
586 11 : window_list->num_insn = num_insn + 1;
587 11 : window_list->num_uops = window_list->num_uops + num_uops;
588 11 : window_list->imm_size += imm_size;
589 11 : window_list->num_imm += num_imm_operand;
590 11 : window_list->num_imm_32 += num_imm32_operand;
591 11 : window_list->num_imm_64 += num_imm64_operand;
592 :
593 11 : if (group == disp_store)
594 1 : window_list->num_stores += 1;
595 10 : else if (group == disp_load
596 10 : || group == disp_prefetch)
597 1 : window_list->num_loads += 1;
598 9 : else if (group == disp_load_store)
599 : {
600 0 : window_list->num_stores += 1;
601 0 : window_list->num_loads += 1;
602 : }
603 11 : }
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
610 14 : add_to_dispatch_window (rtx_insn *insn)
611 : {
612 14 : int byte_len;
613 14 : dispatch_windows *window_list;
614 14 : dispatch_windows *next_list;
615 14 : dispatch_windows *window0_list;
616 14 : enum insn_path path;
617 14 : enum dispatch_group insn_group;
618 14 : bool insn_fits;
619 14 : int num_insn;
620 14 : int num_uops;
621 14 : int window_num;
622 14 : int insn_num_uops;
623 14 : int sum;
624 :
625 14 : if (INSN_CODE (insn) < 0)
626 : return;
627 :
628 11 : byte_len = ix86_min_insn_size (insn);
629 11 : window_list = dispatch_window_list;
630 11 : next_list = window_list->next;
631 11 : path = get_insn_path (insn);
632 11 : insn_group = get_insn_group (insn);
633 :
634 : /* Get the last dispatch window. */
635 11 : if (next_list)
636 0 : window_list = dispatch_window_list->next;
637 :
638 11 : if (path == path_single)
639 : insn_num_uops = 1;
640 0 : else if (path == path_double)
641 : insn_num_uops = 2;
642 : else
643 0 : 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 11 : num_insn = window_list->num_insn;
652 11 : num_uops = window_list->num_uops;
653 11 : window_num = window_list->window_num;
654 11 : insn_fits = fits_dispatch_window (insn);
655 :
656 11 : if (num_insn >= MAX_INSN
657 11 : || num_uops + insn_num_uops > MAX_INSN
658 11 : || !(insn_fits))
659 : {
660 0 : window_num = ~window_num & 1;
661 0 : window_list = allocate_next_window (window_num);
662 : }
663 :
664 11 : if (window_num == 0)
665 : {
666 11 : add_insn_window (insn, window_list, insn_num_uops);
667 11 : if (window_list->num_insn >= MAX_INSN
668 2 : && insn_group == disp_branch)
669 : {
670 1 : process_end_window ();
671 1 : return;
672 : }
673 : }
674 0 : else if (window_num == 1)
675 : {
676 0 : window0_list = window_list->prev;
677 0 : sum = window0_list->window_size + window_list->window_size;
678 0 : if (sum == 32
679 0 : || (byte_len + sum) >= 48)
680 : {
681 0 : process_end_window ();
682 0 : window_list = dispatch_window_list;
683 : }
684 :
685 0 : add_insn_window (insn, window_list, insn_num_uops);
686 : }
687 : else
688 0 : gcc_unreachable ();
689 :
690 9 : if (is_end_basic_block (insn_group))
691 : {
692 : /* End of basic block is reached do end-basic-block process. */
693 0 : process_end_window ();
694 0 : return;
695 : }
696 : }
697 :
698 : /* Print the dispatch window, WINDOW_NUM, to FILE. */
699 :
700 : DEBUG_FUNCTION static void
701 0 : debug_dispatch_window_file (FILE *file, int window_num)
702 : {
703 0 : dispatch_windows *list;
704 0 : int i;
705 :
706 0 : if (window_num == 0)
707 0 : list = dispatch_window_list;
708 : else
709 0 : list = dispatch_window_list1;
710 :
711 0 : fprintf (file, "Window #%d:\n", list->window_num);
712 0 : fprintf (file, " num_insn = %d, num_uops = %d, window_size = %d\n",
713 : list->num_insn, list->num_uops, list->window_size);
714 0 : 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 0 : fprintf (file, " num_loads = %d, num_stores = %d\n", list->num_loads,
718 : list->num_stores);
719 0 : fprintf (file, " insn info:\n");
720 :
721 0 : for (i = 0; i < MAX_INSN; i++)
722 : {
723 0 : if (!list->window[i].insn)
724 : break;
725 0 : fprintf (file, " group[%d] = %s, insn[%d] = %p, path[%d] = %d byte_len[%d] = %d, imm_bytes[%d] = %d\n",
726 0 : i, group_name[list->window[i].group],
727 : i, (void *)list->window[i].insn,
728 0 : i, list->window[i].path,
729 : i, list->window[i].byte_len,
730 : i, list->window[i].imm_bytes);
731 : }
732 0 : }
733 :
734 : /* Print to stdout a dispatch window. */
735 :
736 : DEBUG_FUNCTION void
737 0 : debug_dispatch_window (int window_num)
738 : {
739 0 : debug_dispatch_window_file (stdout, window_num);
740 0 : }
741 :
742 : /* Print INSN dispatch information to FILE. */
743 :
744 : DEBUG_FUNCTION static void
745 0 : debug_insn_dispatch_info_file (FILE *file, rtx_insn *insn)
746 : {
747 0 : int byte_len;
748 0 : enum insn_path path;
749 0 : enum dispatch_group group;
750 0 : int imm_size;
751 0 : int num_imm_operand;
752 0 : int num_imm32_operand;
753 0 : int num_imm64_operand;
754 :
755 0 : if (INSN_CODE (insn) < 0)
756 0 : return;
757 :
758 0 : byte_len = ix86_min_insn_size (insn);
759 0 : path = get_insn_path (insn);
760 0 : group = get_insn_group (insn);
761 0 : imm_size = get_num_immediates (insn, &num_imm_operand, &num_imm32_operand,
762 : &num_imm64_operand);
763 :
764 0 : fprintf (file, " insn info:\n");
765 0 : fprintf (file, " group = %s, path = %d, byte_len = %d\n",
766 0 : group_name[group], path, byte_len);
767 0 : 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
775 0 : debug_ready_dispatch (void)
776 : {
777 0 : int i;
778 0 : int no_ready = number_in_ready ();
779 :
780 0 : fprintf (stdout, "Number of ready: %d\n", no_ready);
781 :
782 0 : for (i = 0; i < no_ready; i++)
783 0 : debug_insn_dispatch_info_file (stdout, get_ready_element (i));
784 0 : }
785 :
786 : /* This routine is the driver of the dispatch scheduler. */
787 :
788 : void
789 17 : ix86_bd_do_dispatch (rtx_insn *insn, int mode)
790 : {
791 17 : if (mode == DISPATCH_INIT)
792 3 : init_dispatch_sched ();
793 14 : else if (mode == ADD_TO_DISPATCH_WINDOW)
794 14 : add_to_dispatch_window (insn);
795 17 : }
796 :
797 : /* Return TRUE if Dispatch Scheduling is supported. */
798 :
799 : bool
800 61101499 : ix86_bd_has_dispatch (rtx_insn *insn, int action)
801 : {
802 : /* Current implementation of dispatch scheduler models buldozer only. */
803 61101499 : if ((TARGET_CPU_P (BDVER1) || TARGET_CPU_P (BDVER2)
804 61101499 : || TARGET_CPU_P (BDVER3) || TARGET_CPU_P (BDVER4))
805 2417 : && flag_dispatch_scheduler)
806 33 : switch (action)
807 : {
808 : default:
809 : return false;
810 :
811 33 : case IS_DISPATCH_ON:
812 33 : return true;
813 :
814 0 : case IS_CMP:
815 0 : return is_cmp (insn);
816 :
817 0 : case DISPATCH_VIOLATION:
818 0 : return dispatch_violation ();
819 :
820 0 : case FITS_DISPATCH_WINDOW:
821 0 : return fits_dispatch_window (insn);
822 : }
823 :
824 : return false;
825 : }
|