1/* List management for the GCC expander.
2   Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
3   1999, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 2, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING.  If not, write to the Free
19Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
2002110-1301, USA.  */
21
22#include "config.h"
23#include "system.h"
24#include "coretypes.h"
25#include "tm.h"
26#include "toplev.h"
27#include "rtl.h"
28#include "ggc.h"
29
30static void free_list (rtx *, rtx *);
31static void free_DEPS_LIST_node (rtx);
32
33/* Functions for maintaining cache-able lists of EXPR_LIST and INSN_LISTs.  */
34
35/* An INSN_LIST containing all INSN_LISTs allocated but currently unused.  */
36static GTY ((deletable)) rtx unused_insn_list;
37
38/* An EXPR_LIST containing all EXPR_LISTs allocated but currently unused.  */
39static GTY ((deletable)) rtx unused_expr_list;
40
41/* An DEPS_LIST containing all DEPS_LISTs allocated but currently unused.  */
42static GTY ((deletable)) rtx unused_deps_list;
43
44
45/* This function will free an entire list of either EXPR_LIST, INSN_LIST
46   or DEPS_LIST nodes.  This is to be used only on lists that consist
47   exclusively of nodes of one type only.  This is only called by
48   free_EXPR_LIST_list, free_INSN_LIST_list and free_DEPS_LIST_list.  */
49static void
50free_list (rtx *listp, rtx *unused_listp)
51{
52  rtx link, prev_link;
53
54  prev_link = *listp;
55  link = XEXP (prev_link, 1);
56
57  gcc_assert ((unused_listp != &unused_insn_list
58	       || GET_CODE (prev_link) == INSN_LIST)
59	      && (unused_listp != &unused_deps_list
60		  || GET_CODE (prev_link) == DEPS_LIST));
61
62  while (link)
63    {
64      gcc_assert ((unused_listp != &unused_insn_list
65		   || GET_CODE (prev_link) == INSN_LIST)
66		  && (unused_listp != &unused_deps_list
67		      || GET_CODE (prev_link) == DEPS_LIST));
68
69      prev_link = link;
70      link = XEXP (link, 1);
71    }
72
73  XEXP (prev_link, 1) = *unused_listp;
74  *unused_listp = *listp;
75  *listp = 0;
76}
77
78/* Find corresponding to ELEM node in the list pointed to by LISTP.
79   This node must exist in the list.  Returns pointer to that node.  */
80static rtx *
81find_list_elem (rtx elem, rtx *listp)
82{
83  while (XEXP (*listp, 0) != elem)
84    listp = &XEXP (*listp, 1);
85  return listp;
86}
87
88/* Remove the node pointed to by LISTP from the list.  */
89static void
90remove_list_node (rtx *listp)
91{
92  rtx node;
93
94  node = *listp;
95  *listp = XEXP (node, 1);
96  XEXP (node, 1) = 0;
97}
98
99/* Removes corresponding to ELEM node from the list pointed to by LISTP.
100   Returns that node.  */
101rtx
102remove_list_elem (rtx elem, rtx *listp)
103{
104  rtx node;
105
106  listp = find_list_elem (elem, listp);
107  node = *listp;
108  remove_list_node (listp);
109  return node;
110}
111
112/* This call is used in place of a gen_rtx_INSN_LIST. If there is a cached
113   node available, we'll use it, otherwise a call to gen_rtx_INSN_LIST
114   is made.  */
115rtx
116alloc_INSN_LIST (rtx val, rtx next)
117{
118  rtx r;
119
120  if (unused_insn_list)
121    {
122      r = unused_insn_list;
123      unused_insn_list = XEXP (r, 1);
124      XEXP (r, 0) = val;
125      XEXP (r, 1) = next;
126      PUT_REG_NOTE_KIND (r, VOIDmode);
127
128      gcc_assert (GET_CODE (r) == INSN_LIST);
129    }
130  else
131    r = gen_rtx_INSN_LIST (VOIDmode, val, next);
132
133  return r;
134}
135
136/* This call is used in place of a gen_rtx_EXPR_LIST. If there is a cached
137   node available, we'll use it, otherwise a call to gen_rtx_EXPR_LIST
138   is made.  */
139rtx
140alloc_EXPR_LIST (int kind, rtx val, rtx next)
141{
142  rtx r;
143
144  if (unused_expr_list)
145    {
146      r = unused_expr_list;
147      unused_expr_list = XEXP (r, 1);
148      XEXP (r, 0) = val;
149      XEXP (r, 1) = next;
150      PUT_REG_NOTE_KIND (r, kind);
151    }
152  else
153    r = gen_rtx_EXPR_LIST (kind, val, next);
154
155  return r;
156}
157
158/* This call is used in place of a gen_rtx_DEPS_LIST.  If there is a cached
159   node available, we'll use it, otherwise a call to gen_rtx_DEPS_LIST
160   is made.  */
161rtx
162alloc_DEPS_LIST (rtx val, rtx next, int ds)
163{
164  rtx r;
165
166  if (unused_deps_list)
167    {
168      r = unused_deps_list;
169      unused_deps_list = XEXP (r, 1);
170      XEXP (r, 0) = val;
171      XEXP (r, 1) = next;
172      XINT (r, 2) = ds;
173      PUT_REG_NOTE_KIND (r, VOIDmode);
174
175      gcc_assert (GET_CODE (r) == DEPS_LIST);
176    }
177  else
178    r = gen_rtx_DEPS_LIST (VOIDmode, val, next, ds);
179
180  return r;
181}
182
183/* This function will free up an entire list of EXPR_LIST nodes.  */
184void
185free_EXPR_LIST_list (rtx *listp)
186{
187  if (*listp == 0)
188    return;
189  free_list (listp, &unused_expr_list);
190}
191
192/* This function will free up an entire list of INSN_LIST nodes.  */
193void
194free_INSN_LIST_list (rtx *listp)
195{
196  if (*listp == 0)
197    return;
198  free_list (listp, &unused_insn_list);
199}
200
201/* This function will free up an entire list of DEPS_LIST nodes.  */
202void
203free_DEPS_LIST_list (rtx *listp)
204{
205  if (*listp == 0)
206    return;
207  free_list (listp, &unused_deps_list);
208}
209
210/* This function will free up an individual EXPR_LIST node.  */
211void
212free_EXPR_LIST_node (rtx ptr)
213{
214  XEXP (ptr, 1) = unused_expr_list;
215  unused_expr_list = ptr;
216}
217
218/* This function will free up an individual INSN_LIST node.  */
219void
220free_INSN_LIST_node (rtx ptr)
221{
222  gcc_assert (GET_CODE (ptr) == INSN_LIST);
223  XEXP (ptr, 1) = unused_insn_list;
224  unused_insn_list = ptr;
225}
226
227/* This function will free up an individual DEPS_LIST node.  */
228static void
229free_DEPS_LIST_node (rtx ptr)
230{
231  gcc_assert (GET_CODE (ptr) == DEPS_LIST);
232  XEXP (ptr, 1) = unused_deps_list;
233  unused_deps_list = ptr;
234}
235
236/* Remove and free corresponding to ELEM node in the DEPS_LIST pointed to
237   by LISTP.  */
238void
239remove_free_DEPS_LIST_elem (rtx elem, rtx *listp)
240{
241  free_DEPS_LIST_node (remove_list_elem (elem, listp));
242}
243
244/* Remove and free corresponding to ELEM node in the INSN_LIST pointed to
245   by LISTP.  */
246void
247remove_free_INSN_LIST_elem (rtx elem, rtx *listp)
248{
249  free_INSN_LIST_node (remove_list_elem (elem, listp));
250}
251
252/* Create and return a copy of the DEPS_LIST LIST.  */
253rtx
254copy_DEPS_LIST_list (rtx list)
255{
256  rtx res = NULL_RTX, *resp = &res;
257
258  while (list)
259    {
260      *resp = alloc_DEPS_LIST (XEXP (list, 0), 0, XINT (list, 2));
261      PUT_REG_NOTE_KIND (*resp, REG_NOTE_KIND (list));
262      resp = &XEXP (*resp, 1);
263      list = XEXP (list, 1);
264    }
265  return res;
266}
267
268#include "gt-lists.h"
269