LCOV - code coverage report
Current view: top level - gcc/config/i386 - x86-tune-sched-bd.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 65.2 % 330 215
Test Date: 2026-02-28 14:20:25 Functions: 73.1 % 26 19
Legend: Lines:     hit not hit

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

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.