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