Add GCC support to ENQCMD.
[official-gcc.git] / gcc / config / i386 / x86-tune-sched-bd.c
blobe417484d17c2db74e8ab7d8bedb0984b4626ecef
1 /* Scheduler hooks for IA-32 which implement bdver1-4 specific logic.
2 Copyright (C) 1988-2019 Free Software Foundation, Inc.
4 This file is part of GCC.
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.
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.
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/>. */
20 #define IN_TARGET_CODE 1
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"
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
42 /* Number of dispatch windows considered for scheduling. */
43 #define MAX_DISPATCH_WINDOWS 3
45 /* Maximum number of instructions in a window. */
46 #define MAX_INSN 4
48 /* Maximum number of immediate operands in a window. */
49 #define MAX_IMM 4
51 /* Maximum number of immediate bits allowed in a window. */
52 #define MAX_IMM_SIZE 128
54 /* Maximum number of 32 bit immediates allowed in a window. */
55 #define MAX_IMM_32 4
57 /* Maximum number of 64 bit immediates allowed in a window. */
58 #define MAX_IMM_64 2
60 /* Maximum total of loads or prefetches allowed in a window. */
61 #define MAX_LOAD 2
63 /* Maximum total of stores allowed in a window. */
64 #define MAX_STORE 1
66 #undef BIG
67 #define BIG 100
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
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
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"
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
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.
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;
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;
146 /* Immediate valuse used in an insn. */
147 typedef struct imm_info_s
149 int imm;
150 int imm32;
151 int imm64;
152 } imm_info;
154 static dispatch_windows *dispatch_window_list;
155 static dispatch_windows *dispatch_window_list1;
157 /* Get dispatch group of insn. */
159 static enum dispatch_group
160 get_mem_group (rtx_insn *insn)
162 enum attr_memory memory;
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;
170 if (memory == MEMORY_LOAD)
171 return disp_load;
173 if (memory == MEMORY_BOTH)
174 return disp_load_store;
176 return disp_no_group;
179 /* Return true if insn is a compare instruction. */
181 static bool
182 is_cmp (rtx_insn *insn)
184 enum attr_type type;
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);
193 /* Return true if a dispatch violation encountered. */
195 static bool
196 dispatch_violation (void)
198 if (dispatch_window_list->next)
199 return dispatch_window_list->next->violation;
200 return dispatch_window_list->violation;
203 /* Return true if insn is a branch instruction. */
205 static bool
206 is_branch (rtx_insn *insn)
208 return (CALL_P (insn) || JUMP_P (insn));
211 /* Return true if insn is a prefetch instruction. */
213 static bool
214 is_prefetch (rtx_insn *insn)
216 return NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == PREFETCH;
219 /* This function initializes a dispatch window and the list container holding a
220 pointer to the window. */
222 static void
223 init_window (int window_num)
225 int i;
226 dispatch_windows *new_list;
228 if (window_num == 0)
229 new_list = dispatch_window_list;
230 else
231 new_list = dispatch_window_list1;
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;
247 for (i = 0; i < MAX_INSN; i++)
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;
255 return;
258 /* This function allocates and initializes a dispatch window and the
259 list container holding a pointer to the window. */
261 static dispatch_windows *
262 allocate_window (void)
264 dispatch_windows *new_list = XNEW (struct dispatch_windows_s);
265 new_list->window = XNEWVEC (struct sched_insn_info_s, MAX_INSN + 1);
267 return new_list;
270 /* This routine initializes the dispatch scheduling information. It
271 initiates building dispatch scheduler tables and constructs the
272 first dispatch window. */
274 static void
275 init_dispatch_sched (void)
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);
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. */
288 static bool
289 is_end_basic_block (enum dispatch_group group)
291 return group == disp_branch;
294 /* This function is called when the end of a window processing is reached. */
296 static void
297 process_end_window (void)
299 gcc_assert (dispatch_window_list->num_insn <= MAX_INSN);
300 if (dispatch_window_list->next)
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);
307 init_window (0);
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. */
315 static dispatch_windows *
316 allocate_next_window (int window_num)
318 if (window_num == 0)
320 if (dispatch_window_list->next)
321 init_window (1);
322 init_window (0);
323 return dispatch_window_list;
326 dispatch_window_list->next = dispatch_window_list1;
327 dispatch_window_list1->prev = dispatch_window_list;
329 return dispatch_window_list1;
332 /* Compute number of immediate operands of an instruction. */
334 static void
335 find_constant (rtx in_rtx, imm_info *imm_values)
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))
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;
354 case CONST_DOUBLE:
355 case CONST_WIDE_INT:
356 (imm_values->imm)++;
357 (imm_values->imm64)++;
358 break;
360 case CODE_LABEL:
361 if (LABEL_KIND (x) == LABEL_NORMAL)
363 (imm_values->imm)++;
364 (imm_values->imm32)++;
366 break;
368 default:
369 break;
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. */
380 static int
381 get_num_immediates (rtx_insn *insn, int *imm, int *imm32, int *imm64)
383 imm_info imm_values = {0, 0, 0};
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;
392 /* This function indicates if an operand of an instruction is an
393 immediate. */
395 static bool
396 has_immediate (rtx_insn *insn)
398 int num_imm_operand;
399 int num_imm32_operand;
400 int num_imm64_operand;
402 if (insn)
403 return get_num_immediates (insn, &num_imm_operand, &num_imm32_operand,
404 &num_imm64_operand);
405 return false;
408 /* Return single or double path for instructions. */
410 static enum insn_path
411 get_insn_path (rtx_insn *insn)
413 enum attr_amdfam10_decode path = get_attr_amdfam10_decode (insn);
415 if ((int)path == 0)
416 return path_single;
418 if ((int)path == 1)
419 return path_double;
421 return path_multi;
424 /* Return insn dispatch group. */
426 static enum dispatch_group
427 get_insn_group (rtx_insn *insn)
429 enum dispatch_group group = get_mem_group (insn);
430 if (group)
431 return group;
433 if (is_branch (insn))
434 return disp_branch;
436 if (is_cmp (insn))
437 return disp_cmp;
439 if (has_immediate (insn))
440 return disp_imm;
442 if (is_prefetch (insn))
443 return disp_prefetch;
445 return disp_no_group;
448 /* Count number of GROUP restricted instructions in a dispatch
449 window WINDOW_LIST. */
451 static int
452 count_num_restricted (rtx_insn *insn, dispatch_windows *window_list)
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;
460 if (group == disp_no_group)
461 return 0;
463 if (group == disp_imm)
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;
482 return 1;
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;
495 return 1;
498 /* This function returns true if insn satisfies dispatch rules on the
499 last window scheduled. */
501 static bool
502 fits_dispatch_window (rtx_insn *insn)
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;
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;
518 /* Check nonrestricted. */
519 if (group == disp_no_group || group == disp_branch)
520 return true;
522 /* Get last dispatch window. */
523 if (window_list_next)
524 window_list = window_list_next;
526 if (window_list->window_num == 1)
528 sum = window_list->prev->window_size + window_list->window_size;
530 if (sum == 32
531 || (ix86_min_insn_size (insn) + sum) >= 48)
532 /* Window 1 is full. Go for next window. */
533 return true;
536 num_restrict = count_num_restricted (insn, window_list);
538 if (num_restrict > num_allowable_groups[group])
539 return false;
541 /* See if it fits in the first window. */
542 if (window_list->window_num == 0)
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;
552 return true;
555 /* Add an instruction INSN with NUM_UOPS micro-operations to the
556 dispatch window WINDOW_LIST. */
558 static void
559 add_insn_window (rtx_insn *insn, dispatch_windows *window_list, int num_uops)
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;
571 if (!window_list->violation && group != disp_cmp
572 && !fits_dispatch_window (insn))
573 window_list->violation = true;
575 imm_size = get_num_immediates (insn, &num_imm_operand, &num_imm32_operand,
576 &num_imm64_operand);
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;
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;
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)
600 window_list->num_stores += 1;
601 window_list->num_loads += 1;
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. */
609 static void
610 add_to_dispatch_window (rtx_insn *insn)
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;
625 if (INSN_CODE (insn) < 0)
626 return;
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);
634 /* Get the last dispatch window. */
635 if (next_list)
636 window_list = dispatch_window_list->next;
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;
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);
656 if (num_insn >= MAX_INSN
657 || num_uops + insn_num_uops > MAX_INSN
658 || !(insn_fits))
660 window_num = ~window_num & 1;
661 window_list = allocate_next_window (window_num);
664 if (window_num == 0)
666 add_insn_window (insn, window_list, insn_num_uops);
667 if (window_list->num_insn >= MAX_INSN
668 && insn_group == disp_branch)
670 process_end_window ();
671 return;
674 else if (window_num == 1)
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)
681 process_end_window ();
682 window_list = dispatch_window_list;
685 add_insn_window (insn, window_list, insn_num_uops);
687 else
688 gcc_unreachable ();
690 if (is_end_basic_block (insn_group))
692 /* End of basic block is reached do end-basic-block process. */
693 process_end_window ();
694 return;
698 /* Print the dispatch window, WINDOW_NUM, to FILE. */
700 DEBUG_FUNCTION static void
701 debug_dispatch_window_file (FILE *file, int window_num)
703 dispatch_windows *list;
704 int i;
706 if (window_num == 0)
707 list = dispatch_window_list;
708 else
709 list = dispatch_window_list1;
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);
717 fprintf (file, " num_loads = %d, num_stores = %d\n", list->num_loads,
718 list->num_stores);
719 fprintf (file, " insn info:\n");
721 for (i = 0; i < MAX_INSN; i++)
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);
734 /* Print to stdout a dispatch window. */
736 DEBUG_FUNCTION void
737 debug_dispatch_window (int window_num)
739 debug_dispatch_window_file (stdout, window_num);
742 /* Print INSN dispatch information to FILE. */
744 DEBUG_FUNCTION static void
745 debug_insn_dispatch_info_file (FILE *file, rtx_insn *insn)
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;
755 if (INSN_CODE (insn) < 0)
756 return;
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);
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);
771 /* Print to STDERR the status of the ready list with respect to
772 dispatch windows. */
774 DEBUG_FUNCTION void
775 debug_ready_dispatch (void)
777 int i;
778 int no_ready = number_in_ready ();
780 fprintf (stdout, "Number of ready: %d\n", no_ready);
782 for (i = 0; i < no_ready; i++)
783 debug_insn_dispatch_info_file (stdout, get_ready_element (i));
786 /* This routine is the driver of the dispatch scheduler. */
788 void
789 ix86_bd_do_dispatch (rtx_insn *insn, int mode)
791 if (mode == DISPATCH_INIT)
792 init_dispatch_sched ();
793 else if (mode == ADD_TO_DISPATCH_WINDOW)
794 add_to_dispatch_window (insn);
797 /* Return TRUE if Dispatch Scheduling is supported. */
799 bool
800 ix86_bd_has_dispatch (rtx_insn *insn, int action)
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)
807 default:
808 return false;
810 case IS_DISPATCH_ON:
811 return true;
813 case IS_CMP:
814 return is_cmp (insn);
816 case DISPATCH_VIOLATION:
817 return dispatch_violation ();
819 case FITS_DISPATCH_WINDOW:
820 return fits_dispatch_window (insn);
823 return false;