1/* Scheduler hooks for IA-32 which implement atom+ specific logic.
2   Copyright (C) 1988-2020 Free Software Foundation, Inc.
3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 3, or (at your option)
9any later version.
10
11GCC is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along 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/* Try to reorder ready list to take advantage of Atom pipelined IMUL
39   execution. It is applied if
40   (1) IMUL instruction is on the top of list;
41   (2) There exists the only producer of independent IMUL instruction in
42       ready list.
43   Return index of IMUL producer if it was found and -1 otherwise.  */
44static int
45do_reorder_for_imul (rtx_insn **ready, int n_ready)
46{
47  rtx_insn *insn;
48  rtx set, insn1, insn2;
49  sd_iterator_def sd_it;
50  dep_t dep;
51  int index = -1;
52  int i;
53
54  if (!TARGET_BONNELL)
55    return index;
56
57  /* Check that IMUL instruction is on the top of ready list.  */
58  insn = ready[n_ready - 1];
59  set = single_set (insn);
60  if (!set)
61    return index;
62  if (!(GET_CODE (SET_SRC (set)) == MULT
63      && GET_MODE (SET_SRC (set)) == SImode))
64    return index;
65
66  /* Search for producer of independent IMUL instruction.  */
67  for (i = n_ready - 2; i >= 0; i--)
68    {
69      insn = ready[i];
70      if (!NONDEBUG_INSN_P (insn))
71	continue;
72      /* Skip IMUL instruction.  */
73      insn2 = PATTERN (insn);
74      if (GET_CODE (insn2) == PARALLEL)
75	insn2 = XVECEXP (insn2, 0, 0);
76      if (GET_CODE (insn2) == SET
77	  && GET_CODE (SET_SRC (insn2)) == MULT
78	  && GET_MODE (SET_SRC (insn2)) == SImode)
79	continue;
80
81      FOR_EACH_DEP (insn, SD_LIST_FORW, sd_it, dep)
82	{
83	  rtx con;
84	  con = DEP_CON (dep);
85	  if (!NONDEBUG_INSN_P (con))
86	    continue;
87	  insn1 = PATTERN (con);
88	  if (GET_CODE (insn1) == PARALLEL)
89	    insn1 = XVECEXP (insn1, 0, 0);
90
91	  if (GET_CODE (insn1) == SET
92	      && GET_CODE (SET_SRC (insn1)) == MULT
93	      && GET_MODE (SET_SRC (insn1)) == SImode)
94	    {
95	      sd_iterator_def sd_it1;
96	      dep_t dep1;
97	      /* Check if there is no other dependee for IMUL.  */
98	      index = i;
99	      FOR_EACH_DEP (con, SD_LIST_BACK, sd_it1, dep1)
100		{
101		  rtx pro;
102		  pro = DEP_PRO (dep1);
103		  if (!NONDEBUG_INSN_P (pro))
104		    continue;
105		  if (pro != insn)
106		    index = -1;
107		}
108	      if (index >= 0)
109		break;
110	    }
111	}
112      if (index >= 0)
113	break;
114    }
115  return index;
116}
117
118/* Try to find the best candidate on the top of ready list if two insns
119   have the same priority - candidate is best if its dependees were
120   scheduled earlier. Applied for Silvermont only.
121   Return true if top 2 insns must be interchanged.  */
122static bool
123swap_top_of_ready_list (rtx_insn **ready, int n_ready)
124{
125  rtx_insn *top = ready[n_ready - 1];
126  rtx_insn *next = ready[n_ready - 2];
127  rtx set;
128  sd_iterator_def sd_it;
129  dep_t dep;
130  int clock1 = -1;
131  int clock2 = -1;
132  #define INSN_TICK(INSN) (HID (INSN)->tick)
133
134  if (!TARGET_SILVERMONT && !TARGET_INTEL)
135    return false;
136
137  if (!NONDEBUG_INSN_P (top))
138    return false;
139  if (!NONJUMP_INSN_P (top))
140    return false;
141  if (!NONDEBUG_INSN_P (next))
142    return false;
143  if (!NONJUMP_INSN_P (next))
144    return false;
145  set = single_set (top);
146  if (!set)
147    return false;
148  set = single_set (next);
149  if (!set)
150    return false;
151
152  if (INSN_PRIORITY_KNOWN (top) && INSN_PRIORITY_KNOWN (next))
153    {
154      if (INSN_PRIORITY (top) != INSN_PRIORITY (next))
155	return false;
156      /* Determine winner more precise.  */
157      FOR_EACH_DEP (top, SD_LIST_RES_BACK, sd_it, dep)
158	{
159	  rtx pro;
160	  pro = DEP_PRO (dep);
161	  if (!NONDEBUG_INSN_P (pro))
162	    continue;
163	  if (INSN_TICK (pro) > clock1)
164	    clock1 = INSN_TICK (pro);
165	}
166      FOR_EACH_DEP (next, SD_LIST_RES_BACK, sd_it, dep)
167	{
168	  rtx pro;
169	  pro = DEP_PRO (dep);
170	  if (!NONDEBUG_INSN_P (pro))
171	    continue;
172	  if (INSN_TICK (pro) > clock2)
173	    clock2 = INSN_TICK (pro);
174	}
175
176      if (clock1 == clock2)
177	{
178	  /* Determine winner - load must win. */
179	  enum attr_memory memory1, memory2;
180	  memory1 = get_attr_memory (top);
181	  memory2 = get_attr_memory (next);
182	  if (memory2 == MEMORY_LOAD && memory1 != MEMORY_LOAD)
183	    return true;
184	}
185	return (bool) (clock2 < clock1);
186    }
187  return false;
188  #undef INSN_TICK
189}
190
191/* Perform possible reodering of ready list for Atom/Silvermont only.
192   Return issue rate.  */
193int
194ix86_atom_sched_reorder (FILE *dump, int sched_verbose, rtx_insn **ready,
195		         int *pn_ready, int clock_var)
196{
197  int issue_rate = -1;
198  int n_ready = *pn_ready;
199  int i;
200  rtx_insn *insn;
201  int index = -1;
202
203  /* Set up issue rate.  */
204  issue_rate = ix86_issue_rate ();
205
206  /* Do reodering for BONNELL/SILVERMONT only.  */
207  if (!TARGET_BONNELL && !TARGET_SILVERMONT && !TARGET_INTEL)
208    return issue_rate;
209
210  /* Nothing to do if ready list contains only 1 instruction.  */
211  if (n_ready <= 1)
212    return issue_rate;
213
214  /* Do reodering for post-reload scheduler only.  */
215  if (!reload_completed)
216    return issue_rate;
217
218  if ((index = do_reorder_for_imul (ready, n_ready)) >= 0)
219    {
220      if (sched_verbose > 1)
221	fprintf (dump, ";;\tatom sched_reorder: put %d insn on top\n",
222		 INSN_UID (ready[index]));
223
224      /* Put IMUL producer (ready[index]) at the top of ready list.  */
225      insn = ready[index];
226      for (i = index; i < n_ready - 1; i++)
227	ready[i] = ready[i + 1];
228      ready[n_ready - 1] = insn;
229      return issue_rate;
230    }
231
232  /* Skip selective scheduling since HID is not populated in it.  */
233  if (clock_var != 0
234      && !sel_sched_p ()
235      && swap_top_of_ready_list (ready, n_ready))
236    {
237      if (sched_verbose > 1)
238	fprintf (dump, ";;\tslm sched_reorder: swap %d and %d insns\n",
239		 INSN_UID (ready[n_ready - 1]), INSN_UID (ready[n_ready - 2]));
240      /* Swap 2 top elements of ready list.  */
241      insn = ready[n_ready - 1];
242      ready[n_ready - 1] = ready[n_ready - 2];
243      ready[n_ready - 2] = insn;
244    }
245  return issue_rate;
246}
247