summaryrefslogtreecommitdiff
path: root/gcc/tree-ssa-opfinalize.h
blob: 3415cf46979999d9e8a384b070499b018781c856 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/* SSA operand allocation and finalizing.
   Copyright (C) 2005 Free Software Foundation, Inc.

This file is part of GCC.

GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.

GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING.  If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.  */


/* This file contains common code which is used by each of the 5 operand 
   types.  Macros are defined to specify the varying components.

   FINALIZE_FUNC - name of finalize function.
   FINALIZE_ALLOC - name of allocation routine.
   FINALIZE_FREE - name of free list.
   FINALIZE_TYPE - type of node.
   FINALIZE_OPS - Lead element in list.
   FINALIZE_USE_PTR - How to get the use_operand_p, if this is a use operand.
   FINALIZE_INITIALIZE - How to initialize an element.
   FINALIZE_ELEM - How to retrieve an element.
   FINALIZE_BASE - How to retrieve the base variable of an element.
   FINALIZE_BASE_TYPE - Type of the base variable.
   FINALIZE_OPBUILD - Opbuild array for these nodes.
   FINALIZE_OPBUILD_ELEM - How to get an element from the opbuild list.
   FINALIZE_OPBUILD_BASE - How to get an element base from the opbuild list.
   FINALIZE_BASE_ZERO - How to zero an element.  */


/* This routine will either pick up a node from the free list, or allocate a
   new one if need be.  */

static inline FINALIZE_TYPE *
FINALIZE_ALLOC (void)
{
  FINALIZE_TYPE *ret;
  if (FINALIZE_FREE)
    {
      ret = FINALIZE_FREE;
      FINALIZE_FREE = FINALIZE_FREE->next;
    }
  else
    ret = (FINALIZE_TYPE *)ssa_operand_alloc (sizeof (FINALIZE_TYPE));
  return ret;
}



/* This routine will take the new operands from FINALIZE_OPBUILD and turn them
   into the new operands for STMT.  All required linking and deleting is u
   performed here.  */
static inline void
FINALIZE_FUNC (tree stmt)
{
  int new_i;
  FINALIZE_TYPE *old_ops, *ptr, *last;
  FINALIZE_BASE_TYPE old_base;
  FINALIZE_TYPE new_list;

  new_list.next = NULL;
  last = &new_list;

  old_ops = FINALIZE_OPS (stmt);
  if (old_ops)
    old_base = FINALIZE_BASE (FINALIZE_ELEM (old_ops));
  else
    old_base = FINALIZE_BASE_ZERO;

  new_i = opbuild_first (&FINALIZE_OPBUILD);
  while (old_ops && new_i != OPBUILD_LAST)
    {
      FINALIZE_BASE_TYPE new_base = FINALIZE_OPBUILD_BASE (new_i);
      if (old_base == new_base)
        {
	  /* if variables are the same, reuse this node.  */
	  last->next = old_ops;
	  last = old_ops;
#ifdef FINALIZE_USE_PTR
	  correct_use_link (FINALIZE_USE_PTR (last), stmt);
#endif
	  old_ops = old_ops->next;
	  new_i = opbuild_next (&FINALIZE_OPBUILD, new_i);
	}
      else
        if (old_base < new_base)
	  {
	    /* if old is less than new, old goes to the free list.  */
#ifdef FINALIZE_USE_PTR
	    use_operand_p use_p = FINALIZE_USE_PTR (old_ops);
	    delink_imm_use (use_p);
#endif
	    ptr = old_ops;
	    old_ops = old_ops->next;
	    ptr->next = FINALIZE_FREE;
	    FINALIZE_FREE = ptr;
	  }
	else
	  {
	    /* This is a new operand.  */
	    ptr = FINALIZE_ALLOC ();
	    FINALIZE_INITIALIZE (ptr, FINALIZE_OPBUILD_ELEM (new_i), stmt);
	    last->next = ptr;
	    last = ptr;
	    new_i = opbuild_next (&FINALIZE_OPBUILD, new_i);
	  }
      if (old_ops)
        old_base = FINALIZE_BASE (FINALIZE_ELEM (old_ops));
    }

  /* If there is anything remaining in the opbuild list, simply emit them.  */
  for ( ; 
	new_i != OPBUILD_LAST; 
	new_i = opbuild_next (&FINALIZE_OPBUILD, new_i))
    {
      ptr = FINALIZE_ALLOC ();
      FINALIZE_INITIALIZE (ptr, FINALIZE_OPBUILD_ELEM (new_i), stmt);
      last->next = ptr;
      last = ptr;
    }

  last->next = NULL;

  /* If there is anything in the old list, free them.  */
  if (old_ops)
    {
#ifdef FINALIZE_USE_PTR
      for (ptr = old_ops; ptr; ptr = ptr->next)
	{
	  use_operand_p use_p = FINALIZE_USE_PTR (ptr);
	  delink_imm_use (use_p);
	}
#endif
      old_ops->next = FINALIZE_FREE;
      FINALIZE_FREE = old_ops;
    }

  /* NOw set the stmt's operands.  */
  FINALIZE_OPS (stmt) = new_list.next;

#ifdef ENABLE_CHECKING
  {
    unsigned x = 0;
    for (ptr = FINALIZE_OPS (stmt); ptr; ptr = ptr->next)
      x++;

    gcc_assert (x == opbuild_num_elems (&FINALIZE_OPBUILD));
  }
#endif
}

#undef FINALIZE_FUNC
#undef FINALIZE_ALLOC
#undef FINALIZE_FREE
#undef FINALIZE_TYPE
#undef FINALIZE_OPS
#undef FINALIZE_USE_PTR
#undef FINALIZE_INITIALIZE
#undef FINALIZE_ELEM
#undef FINALIZE_BASE
#undef FINALIZE_BASE_TYPE
#undef FINALIZE_OPBUILD
#undef FINALIZE_OPBUILD_ELEM
#undef FINALIZE_OPBUILD_BASE
#undef FINALIZE_BASE_ZERO