Branch data Line data Source code
1 : : /* Scheduler hooks for IA-32 which implement bdver1-4 specific logic.
2 : : Copyright (C) 1988-2024 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 : 267 : FOR_EACH_SUBRTX (iter, array, in_rtx, ALL)
341 : 220 : if (const_rtx x = *iter)
342 : 220 : 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 : 61339832 : ix86_bd_has_dispatch (rtx_insn *insn, int action)
801 : : {
802 : : /* Current implementation of dispatch scheduler models buldozer only. */
803 : 61339832 : if ((TARGET_CPU_P (BDVER1) || TARGET_CPU_P (BDVER2)
804 : 61339832 : || TARGET_CPU_P (BDVER3) || TARGET_CPU_P (BDVER4))
805 : 2204 : && 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 : : }
|