* x86-tune-sched.c (ix86_adjust_cost): Fix Zen support.
[official-gcc.git] / gcc / config / i386 / x86-tune-sched-bd.c
blobc862fc156e218e44c6469e2cd136101c37351ccf
1 /* Scheduler hooks for IA-32 which implement bdver1-4 specific logic.
2 Copyright (C) 1988-2017 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 #include "config.h"
21 #include "system.h"
22 #include "coretypes.h"
23 #include "backend.h"
24 #include "rtl.h"
25 #include "tree.h"
26 #include "cfghooks.h"
27 #include "tm_p.h"
28 #include "insn-config.h"
29 #include "insn-attr.h"
30 #include "recog.h"
31 #include "target.h"
32 #include "rtl-iter.h"
33 #include "regset.h"
34 #include "sched-int.h"
36 /* The size of the dispatch window is the total number of bytes of
37 object code allowed in a window. */
38 #define DISPATCH_WINDOW_SIZE 16
40 /* Number of dispatch windows considered for scheduling. */
41 #define MAX_DISPATCH_WINDOWS 3
43 /* Maximum number of instructions in a window. */
44 #define MAX_INSN 4
46 /* Maximum number of immediate operands in a window. */
47 #define MAX_IMM 4
49 /* Maximum number of immediate bits allowed in a window. */
50 #define MAX_IMM_SIZE 128
52 /* Maximum number of 32 bit immediates allowed in a window. */
53 #define MAX_IMM_32 4
55 /* Maximum number of 64 bit immediates allowed in a window. */
56 #define MAX_IMM_64 2
58 /* Maximum total of loads or prefetches allowed in a window. */
59 #define MAX_LOAD 2
61 /* Maximum total of stores allowed in a window. */
62 #define MAX_STORE 1
64 #undef BIG
65 #define BIG 100
68 /* Dispatch groups. Istructions that affect the mix in a dispatch window. */
69 enum dispatch_group {
70 disp_no_group = 0,
71 disp_load,
72 disp_store,
73 disp_load_store,
74 disp_prefetch,
75 disp_imm,
76 disp_imm_32,
77 disp_imm_64,
78 disp_branch,
79 disp_cmp,
80 disp_jcc,
81 disp_last
84 /* Number of allowable groups in a dispatch window. It is an array
85 indexed by dispatch_group enum. 100 is used as a big number,
86 because the number of these kind of operations does not have any
87 effect in dispatch window, but we need them for other reasons in
88 the table. */
89 static unsigned int num_allowable_groups[disp_last] = {
90 0, 2, 1, 1, 2, 4, 4, 2, 1, BIG, BIG
93 char group_name[disp_last + 1][16] = {
94 "disp_no_group", "disp_load", "disp_store", "disp_load_store",
95 "disp_prefetch", "disp_imm", "disp_imm_32", "disp_imm_64",
96 "disp_branch", "disp_cmp", "disp_jcc", "disp_last"
99 /* Instruction path. */
100 enum insn_path {
101 no_path = 0,
102 path_single, /* Single micro op. */
103 path_double, /* Double micro op. */
104 path_multi, /* Instructions with more than 2 micro op.. */
105 last_path
108 /* sched_insn_info defines a window to the instructions scheduled in
109 the basic block. It contains a pointer to the insn_info table and
110 the instruction scheduled.
112 Windows are allocated for each basic block and are linked
113 together. */
114 typedef struct sched_insn_info_s {
115 rtx insn;
116 enum dispatch_group group;
117 enum insn_path path;
118 int byte_len;
119 int imm_bytes;
120 } sched_insn_info;
122 /* Linked list of dispatch windows. This is a two way list of
123 dispatch windows of a basic block. It contains information about
124 the number of uops in the window and the total number of
125 instructions and of bytes in the object code for this dispatch
126 window. */
127 typedef struct dispatch_windows_s {
128 int num_insn; /* Number of insn in the window. */
129 int num_uops; /* Number of uops in the window. */
130 int window_size; /* Number of bytes in the window. */
131 int window_num; /* Window number between 0 or 1. */
132 int num_imm; /* Number of immediates in an insn. */
133 int num_imm_32; /* Number of 32 bit immediates in an insn. */
134 int num_imm_64; /* Number of 64 bit immediates in an insn. */
135 int imm_size; /* Total immediates in the window. */
136 int num_loads; /* Total memory loads in the window. */
137 int num_stores; /* Total memory stores in the window. */
138 int violation; /* Violation exists in window. */
139 sched_insn_info *window; /* Pointer to the window. */
140 struct dispatch_windows_s *next;
141 struct dispatch_windows_s *prev;
142 } dispatch_windows;
144 /* Immediate valuse used in an insn. */
145 typedef struct imm_info_s
147 int imm;
148 int imm32;
149 int imm64;
150 } imm_info;
152 static dispatch_windows *dispatch_window_list;
153 static dispatch_windows *dispatch_window_list1;
155 /* Get dispatch group of insn. */
157 static enum dispatch_group
158 get_mem_group (rtx_insn *insn)
160 enum attr_memory memory;
162 if (INSN_CODE (insn) < 0)
163 return disp_no_group;
164 memory = get_attr_memory (insn);
165 if (memory == MEMORY_STORE)
166 return disp_store;
168 if (memory == MEMORY_LOAD)
169 return disp_load;
171 if (memory == MEMORY_BOTH)
172 return disp_load_store;
174 return disp_no_group;
177 /* Return true if insn is a compare instruction. */
179 static bool
180 is_cmp (rtx_insn *insn)
182 enum attr_type type;
184 type = get_attr_type (insn);
185 return (type == TYPE_TEST
186 || type == TYPE_ICMP
187 || type == TYPE_FCMP
188 || GET_CODE (PATTERN (insn)) == COMPARE);
191 /* Return true if a dispatch violation encountered. */
193 static bool
194 dispatch_violation (void)
196 if (dispatch_window_list->next)
197 return dispatch_window_list->next->violation;
198 return dispatch_window_list->violation;
201 /* Return true if insn is a branch instruction. */
203 static bool
204 is_branch (rtx_insn *insn)
206 return (CALL_P (insn) || JUMP_P (insn));
209 /* Return true if insn is a prefetch instruction. */
211 static bool
212 is_prefetch (rtx_insn *insn)
214 return NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == PREFETCH;
217 /* This function initializes a dispatch window and the list container holding a
218 pointer to the window. */
220 static void
221 init_window (int window_num)
223 int i;
224 dispatch_windows *new_list;
226 if (window_num == 0)
227 new_list = dispatch_window_list;
228 else
229 new_list = dispatch_window_list1;
231 new_list->num_insn = 0;
232 new_list->num_uops = 0;
233 new_list->window_size = 0;
234 new_list->next = NULL;
235 new_list->prev = NULL;
236 new_list->window_num = window_num;
237 new_list->num_imm = 0;
238 new_list->num_imm_32 = 0;
239 new_list->num_imm_64 = 0;
240 new_list->imm_size = 0;
241 new_list->num_loads = 0;
242 new_list->num_stores = 0;
243 new_list->violation = false;
245 for (i = 0; i < MAX_INSN; i++)
247 new_list->window[i].insn = NULL;
248 new_list->window[i].group = disp_no_group;
249 new_list->window[i].path = no_path;
250 new_list->window[i].byte_len = 0;
251 new_list->window[i].imm_bytes = 0;
253 return;
256 /* This function allocates and initializes a dispatch window and the
257 list container holding a pointer to the window. */
259 static dispatch_windows *
260 allocate_window (void)
262 dispatch_windows *new_list = XNEW (struct dispatch_windows_s);
263 new_list->window = XNEWVEC (struct sched_insn_info_s, MAX_INSN + 1);
265 return new_list;
268 /* This routine initializes the dispatch scheduling information. It
269 initiates building dispatch scheduler tables and constructs the
270 first dispatch window. */
272 static void
273 init_dispatch_sched (void)
275 /* Allocate a dispatch list and a window. */
276 dispatch_window_list = allocate_window ();
277 dispatch_window_list1 = allocate_window ();
278 init_window (0);
279 init_window (1);
282 /* This function returns true if a branch is detected. End of a basic block
283 does not have to be a branch, but here we assume only branches end a
284 window. */
286 static bool
287 is_end_basic_block (enum dispatch_group group)
289 return group == disp_branch;
292 /* This function is called when the end of a window processing is reached. */
294 static void
295 process_end_window (void)
297 gcc_assert (dispatch_window_list->num_insn <= MAX_INSN);
298 if (dispatch_window_list->next)
300 gcc_assert (dispatch_window_list1->num_insn <= MAX_INSN);
301 gcc_assert (dispatch_window_list->window_size
302 + dispatch_window_list1->window_size <= 48);
303 init_window (1);
305 init_window (0);
308 /* Allocates a new dispatch window and adds it to WINDOW_LIST.
309 WINDOW_NUM is either 0 or 1. A maximum of two windows are generated
310 for 48 bytes of instructions. Note that these windows are not dispatch
311 windows that their sizes are DISPATCH_WINDOW_SIZE. */
313 static dispatch_windows *
314 allocate_next_window (int window_num)
316 if (window_num == 0)
318 if (dispatch_window_list->next)
319 init_window (1);
320 init_window (0);
321 return dispatch_window_list;
324 dispatch_window_list->next = dispatch_window_list1;
325 dispatch_window_list1->prev = dispatch_window_list;
327 return dispatch_window_list1;
330 /* Compute number of immediate operands of an instruction. */
332 static void
333 find_constant (rtx in_rtx, imm_info *imm_values)
335 if (INSN_P (in_rtx))
336 in_rtx = PATTERN (in_rtx);
337 subrtx_iterator::array_type array;
338 FOR_EACH_SUBRTX (iter, array, in_rtx, ALL)
339 if (const_rtx x = *iter)
340 switch (GET_CODE (x))
342 case CONST:
343 case SYMBOL_REF:
344 case CONST_INT:
345 (imm_values->imm)++;
346 if (x86_64_immediate_operand (CONST_CAST_RTX (x), SImode))
347 (imm_values->imm32)++;
348 else
349 (imm_values->imm64)++;
350 break;
352 case CONST_DOUBLE:
353 case CONST_WIDE_INT:
354 (imm_values->imm)++;
355 (imm_values->imm64)++;
356 break;
358 case CODE_LABEL:
359 if (LABEL_KIND (x) == LABEL_NORMAL)
361 (imm_values->imm)++;
362 (imm_values->imm32)++;
364 break;
366 default:
367 break;
371 /* Return total size of immediate operands of an instruction along with number
372 of corresponding immediate-operands. It initializes its parameters to zero
373 befor calling FIND_CONSTANT.
374 INSN is the input instruction. IMM is the total of immediates.
375 IMM32 is the number of 32 bit immediates. IMM64 is the number of 64
376 bit immediates. */
378 static int
379 get_num_immediates (rtx_insn *insn, int *imm, int *imm32, int *imm64)
381 imm_info imm_values = {0, 0, 0};
383 find_constant (insn, &imm_values);
384 *imm = imm_values.imm;
385 *imm32 = imm_values.imm32;
386 *imm64 = imm_values.imm64;
387 return imm_values.imm32 * 4 + imm_values.imm64 * 8;
390 /* This function indicates if an operand of an instruction is an
391 immediate. */
393 static bool
394 has_immediate (rtx_insn *insn)
396 int num_imm_operand;
397 int num_imm32_operand;
398 int num_imm64_operand;
400 if (insn)
401 return get_num_immediates (insn, &num_imm_operand, &num_imm32_operand,
402 &num_imm64_operand);
403 return false;
406 /* Return single or double path for instructions. */
408 static enum insn_path
409 get_insn_path (rtx_insn *insn)
411 enum attr_amdfam10_decode path = get_attr_amdfam10_decode (insn);
413 if ((int)path == 0)
414 return path_single;
416 if ((int)path == 1)
417 return path_double;
419 return path_multi;
422 /* Return insn dispatch group. */
424 static enum dispatch_group
425 get_insn_group (rtx_insn *insn)
427 enum dispatch_group group = get_mem_group (insn);
428 if (group)
429 return group;
431 if (is_branch (insn))
432 return disp_branch;
434 if (is_cmp (insn))
435 return disp_cmp;
437 if (has_immediate (insn))
438 return disp_imm;
440 if (is_prefetch (insn))
441 return disp_prefetch;
443 return disp_no_group;
446 /* Count number of GROUP restricted instructions in a dispatch
447 window WINDOW_LIST. */
449 static int
450 count_num_restricted (rtx_insn *insn, dispatch_windows *window_list)
452 enum dispatch_group group = get_insn_group (insn);
453 int imm_size;
454 int num_imm_operand;
455 int num_imm32_operand;
456 int num_imm64_operand;
458 if (group == disp_no_group)
459 return 0;
461 if (group == disp_imm)
463 imm_size = get_num_immediates (insn, &num_imm_operand, &num_imm32_operand,
464 &num_imm64_operand);
465 if (window_list->imm_size + imm_size > MAX_IMM_SIZE
466 || num_imm_operand + window_list->num_imm > MAX_IMM
467 || (num_imm32_operand > 0
468 && (window_list->num_imm_32 + num_imm32_operand > MAX_IMM_32
469 || window_list->num_imm_64 * 2 + num_imm32_operand > MAX_IMM_32))
470 || (num_imm64_operand > 0
471 && (window_list->num_imm_64 + num_imm64_operand > MAX_IMM_64
472 || window_list->num_imm_32 + num_imm64_operand * 2 > MAX_IMM_32))
473 || (window_list->imm_size + imm_size == MAX_IMM_SIZE
474 && num_imm64_operand > 0
475 && ((window_list->num_imm_64 > 0
476 && window_list->num_insn >= 2)
477 || window_list->num_insn >= 3)))
478 return BIG;
480 return 1;
483 if ((group == disp_load_store
484 && (window_list->num_loads >= MAX_LOAD
485 || window_list->num_stores >= MAX_STORE))
486 || ((group == disp_load
487 || group == disp_prefetch)
488 && window_list->num_loads >= MAX_LOAD)
489 || (group == disp_store
490 && window_list->num_stores >= MAX_STORE))
491 return BIG;
493 return 1;
496 /* This function returns true if insn satisfies dispatch rules on the
497 last window scheduled. */
499 static bool
500 fits_dispatch_window (rtx_insn *insn)
502 dispatch_windows *window_list = dispatch_window_list;
503 dispatch_windows *window_list_next = dispatch_window_list->next;
504 unsigned int num_restrict;
505 enum dispatch_group group = get_insn_group (insn);
506 enum insn_path path = get_insn_path (insn);
507 int sum;
509 /* Make disp_cmp and disp_jcc get scheduled at the latest. These
510 instructions should be given the lowest priority in the
511 scheduling process in Haifa scheduler to make sure they will be
512 scheduled in the same dispatch window as the reference to them. */
513 if (group == disp_jcc || group == disp_cmp)
514 return false;
516 /* Check nonrestricted. */
517 if (group == disp_no_group || group == disp_branch)
518 return true;
520 /* Get last dispatch window. */
521 if (window_list_next)
522 window_list = window_list_next;
524 if (window_list->window_num == 1)
526 sum = window_list->prev->window_size + window_list->window_size;
528 if (sum == 32
529 || (ix86_min_insn_size (insn) + sum) >= 48)
530 /* Window 1 is full. Go for next window. */
531 return true;
534 num_restrict = count_num_restricted (insn, window_list);
536 if (num_restrict > num_allowable_groups[group])
537 return false;
539 /* See if it fits in the first window. */
540 if (window_list->window_num == 0)
542 /* The first widow should have only single and double path
543 uops. */
544 if (path == path_double
545 && (window_list->num_uops + 2) > MAX_INSN)
546 return false;
547 else if (path != path_single)
548 return false;
550 return true;
553 /* Add an instruction INSN with NUM_UOPS micro-operations to the
554 dispatch window WINDOW_LIST. */
556 static void
557 add_insn_window (rtx_insn *insn, dispatch_windows *window_list, int num_uops)
559 int byte_len = ix86_min_insn_size (insn);
560 int num_insn = window_list->num_insn;
561 int imm_size;
562 sched_insn_info *window = window_list->window;
563 enum dispatch_group group = get_insn_group (insn);
564 enum insn_path path = get_insn_path (insn);
565 int num_imm_operand;
566 int num_imm32_operand;
567 int num_imm64_operand;
569 if (!window_list->violation && group != disp_cmp
570 && !fits_dispatch_window (insn))
571 window_list->violation = true;
573 imm_size = get_num_immediates (insn, &num_imm_operand, &num_imm32_operand,
574 &num_imm64_operand);
576 /* Initialize window with new instruction. */
577 window[num_insn].insn = insn;
578 window[num_insn].byte_len = byte_len;
579 window[num_insn].group = group;
580 window[num_insn].path = path;
581 window[num_insn].imm_bytes = imm_size;
583 window_list->window_size += byte_len;
584 window_list->num_insn = num_insn + 1;
585 window_list->num_uops = window_list->num_uops + num_uops;
586 window_list->imm_size += imm_size;
587 window_list->num_imm += num_imm_operand;
588 window_list->num_imm_32 += num_imm32_operand;
589 window_list->num_imm_64 += num_imm64_operand;
591 if (group == disp_store)
592 window_list->num_stores += 1;
593 else if (group == disp_load
594 || group == disp_prefetch)
595 window_list->num_loads += 1;
596 else if (group == disp_load_store)
598 window_list->num_stores += 1;
599 window_list->num_loads += 1;
603 /* Adds a scheduled instruction, INSN, to the current dispatch window.
604 If the total bytes of instructions or the number of instructions in
605 the window exceed allowable, it allocates a new window. */
607 static void
608 add_to_dispatch_window (rtx_insn *insn)
610 int byte_len;
611 dispatch_windows *window_list;
612 dispatch_windows *next_list;
613 dispatch_windows *window0_list;
614 enum insn_path path;
615 enum dispatch_group insn_group;
616 bool insn_fits;
617 int num_insn;
618 int num_uops;
619 int window_num;
620 int insn_num_uops;
621 int sum;
623 if (INSN_CODE (insn) < 0)
624 return;
626 byte_len = ix86_min_insn_size (insn);
627 window_list = dispatch_window_list;
628 next_list = window_list->next;
629 path = get_insn_path (insn);
630 insn_group = get_insn_group (insn);
632 /* Get the last dispatch window. */
633 if (next_list)
634 window_list = dispatch_window_list->next;
636 if (path == path_single)
637 insn_num_uops = 1;
638 else if (path == path_double)
639 insn_num_uops = 2;
640 else
641 insn_num_uops = (int) path;
643 /* If current window is full, get a new window.
644 Window number zero is full, if MAX_INSN uops are scheduled in it.
645 Window number one is full, if window zero's bytes plus window
646 one's bytes is 32, or if the bytes of the new instruction added
647 to the total makes it greater than 48, or it has already MAX_INSN
648 instructions in it. */
649 num_insn = window_list->num_insn;
650 num_uops = window_list->num_uops;
651 window_num = window_list->window_num;
652 insn_fits = fits_dispatch_window (insn);
654 if (num_insn >= MAX_INSN
655 || num_uops + insn_num_uops > MAX_INSN
656 || !(insn_fits))
658 window_num = ~window_num & 1;
659 window_list = allocate_next_window (window_num);
662 if (window_num == 0)
664 add_insn_window (insn, window_list, insn_num_uops);
665 if (window_list->num_insn >= MAX_INSN
666 && insn_group == disp_branch)
668 process_end_window ();
669 return;
672 else if (window_num == 1)
674 window0_list = window_list->prev;
675 sum = window0_list->window_size + window_list->window_size;
676 if (sum == 32
677 || (byte_len + sum) >= 48)
679 process_end_window ();
680 window_list = dispatch_window_list;
683 add_insn_window (insn, window_list, insn_num_uops);
685 else
686 gcc_unreachable ();
688 if (is_end_basic_block (insn_group))
690 /* End of basic block is reached do end-basic-block process. */
691 process_end_window ();
692 return;
696 /* Print the dispatch window, WINDOW_NUM, to FILE. */
698 DEBUG_FUNCTION static void
699 debug_dispatch_window_file (FILE *file, int window_num)
701 dispatch_windows *list;
702 int i;
704 if (window_num == 0)
705 list = dispatch_window_list;
706 else
707 list = dispatch_window_list1;
709 fprintf (file, "Window #%d:\n", list->window_num);
710 fprintf (file, " num_insn = %d, num_uops = %d, window_size = %d\n",
711 list->num_insn, list->num_uops, list->window_size);
712 fprintf (file, " num_imm = %d, num_imm_32 = %d, num_imm_64 = %d, imm_size = %d\n",
713 list->num_imm, list->num_imm_32, list->num_imm_64, list->imm_size);
715 fprintf (file, " num_loads = %d, num_stores = %d\n", list->num_loads,
716 list->num_stores);
717 fprintf (file, " insn info:\n");
719 for (i = 0; i < MAX_INSN; i++)
721 if (!list->window[i].insn)
722 break;
723 fprintf (file, " group[%d] = %s, insn[%d] = %p, path[%d] = %d byte_len[%d] = %d, imm_bytes[%d] = %d\n",
724 i, group_name[list->window[i].group],
725 i, (void *)list->window[i].insn,
726 i, list->window[i].path,
727 i, list->window[i].byte_len,
728 i, list->window[i].imm_bytes);
732 /* Print to stdout a dispatch window. */
734 DEBUG_FUNCTION void
735 debug_dispatch_window (int window_num)
737 debug_dispatch_window_file (stdout, window_num);
740 /* Print INSN dispatch information to FILE. */
742 DEBUG_FUNCTION static void
743 debug_insn_dispatch_info_file (FILE *file, rtx_insn *insn)
745 int byte_len;
746 enum insn_path path;
747 enum dispatch_group group;
748 int imm_size;
749 int num_imm_operand;
750 int num_imm32_operand;
751 int num_imm64_operand;
753 if (INSN_CODE (insn) < 0)
754 return;
756 byte_len = ix86_min_insn_size (insn);
757 path = get_insn_path (insn);
758 group = get_insn_group (insn);
759 imm_size = get_num_immediates (insn, &num_imm_operand, &num_imm32_operand,
760 &num_imm64_operand);
762 fprintf (file, " insn info:\n");
763 fprintf (file, " group = %s, path = %d, byte_len = %d\n",
764 group_name[group], path, byte_len);
765 fprintf (file, " num_imm = %d, num_imm_32 = %d, num_imm_64 = %d, imm_size = %d\n",
766 num_imm_operand, num_imm32_operand, num_imm64_operand, imm_size);
769 /* Print to STDERR the status of the ready list with respect to
770 dispatch windows. */
772 DEBUG_FUNCTION void
773 debug_ready_dispatch (void)
775 int i;
776 int no_ready = number_in_ready ();
778 fprintf (stdout, "Number of ready: %d\n", no_ready);
780 for (i = 0; i < no_ready; i++)
781 debug_insn_dispatch_info_file (stdout, get_ready_element (i));
784 /* This routine is the driver of the dispatch scheduler. */
786 void
787 ix86_bd_do_dispatch (rtx_insn *insn, int mode)
789 if (mode == DISPATCH_INIT)
790 init_dispatch_sched ();
791 else if (mode == ADD_TO_DISPATCH_WINDOW)
792 add_to_dispatch_window (insn);
795 /* Return TRUE if Dispatch Scheduling is supported. */
797 bool
798 ix86_bd_has_dispatch (rtx_insn *insn, int action)
800 /* Current implementation of dispatch scheduler models buldozer only. */
801 if ((TARGET_BDVER1 || TARGET_BDVER2 || TARGET_BDVER3
802 || TARGET_BDVER4) && flag_dispatch_scheduler)
803 switch (action)
805 default:
806 return false;
808 case IS_DISPATCH_ON:
809 return true;
811 case IS_CMP:
812 return is_cmp (insn);
814 case DISPATCH_VIOLATION:
815 return dispatch_violation ();
817 case FITS_DISPATCH_WINDOW:
818 return fits_dispatch_window (insn);
821 return false;