source: trunk/third/gcc/cp/expr.c @ 8834

Revision 8834, 9.7 KB checked in by ghudson, 28 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r8833, which included commits to RCS files with non-trunk default branches.
Line 
1/* Convert language-specific tree expression to rtl instructions,
2   for GNU compiler.
3   Copyright (C) 1988, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
4
5This file is part of GNU CC.
6
7GNU CC is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2, or (at your option)
10any later version.
11
12GNU CC is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU CC; see the file COPYING.  If not, write to
19the Free Software Foundation, 59 Temple Place - Suite 330,
20Boston, MA 02111-1307, USA.  */
21
22
23#include "config.h"
24#include "rtl.h"
25#include "tree.h"
26#include "flags.h"
27#include "expr.h"
28#include "cp-tree.h"
29
30#undef NULL
31#define NULL 0
32
33/* Hook used by expand_expr to expand language-specific tree codes.  */
34
35rtx
36cplus_expand_expr (exp, target, tmode, modifier)
37     tree exp;
38     rtx target;
39     enum machine_mode tmode;
40     enum expand_modifier modifier;
41{
42  tree type = TREE_TYPE (exp);
43  register enum machine_mode mode = TYPE_MODE (type);
44  register enum tree_code code = TREE_CODE (exp);
45  rtx original_target = target;
46  int ignore = target == const0_rtx;
47
48  if (ignore)
49    target = 0, original_target = 0;
50
51  /* No sense saving up arithmetic to be done
52     if it's all in the wrong mode to form part of an address.
53     And force_operand won't know whether to sign-extend or zero-extend.  */
54
55  if (mode != Pmode && modifier == EXPAND_SUM)
56    modifier = EXPAND_NORMAL;
57
58  switch (code)
59    {
60    case NEW_EXPR:
61      {
62        /* Something needs to be initialized, but we didn't know
63           where that thing was when building the tree.  For example,
64           it could be the return value of a function, or a parameter
65           to a function which lays down in the stack, or a temporary
66           variable which must be passed by reference.
67
68           Cleanups are handled in a language-specific way: they
69           might be run by the called function (true in GNU C++
70           for parameters with cleanups), or they might be
71           run by the caller, after the call (true in GNU C++
72           for other cleanup needs).  */
73
74        tree func = TREE_OPERAND (exp, 0);
75        tree args = TREE_OPERAND (exp, 1);
76        tree type = TREE_TYPE (exp), slot;
77        tree fn_type = TREE_TYPE (TREE_TYPE (func));
78        tree return_type = TREE_TYPE (fn_type);
79        tree call_exp;
80        rtx call_target, return_target;
81        int pcc_struct_return = 0;
82
83        /* The expression `init' wants to initialize what
84           `target' represents.  SLOT holds the slot for TARGET.  */
85        slot = TREE_OPERAND (exp, 2);
86
87        if (target == 0)
88          {
89            /* Should always be called with a target in BLKmode case.  */
90            my_friendly_assert (mode != BLKmode, 205);
91            my_friendly_assert (DECL_RTL (slot) != 0, 206);
92
93            target = gen_reg_rtx (mode);
94          }
95
96        /* The target the initializer will initialize (CALL_TARGET)
97           must now be directed to initialize the target we are
98           supposed to initialize (TARGET).  The semantics for
99           choosing what CALL_TARGET is is language-specific,
100           as is building the call which will perform the
101           initialization.  It is left here to show the choices that
102           exist for C++.  */
103           
104        if (TREE_CODE (func) == ADDR_EXPR
105            && TREE_CODE (TREE_OPERAND (func, 0)) == FUNCTION_DECL
106            && DECL_CONSTRUCTOR_P (TREE_OPERAND (func, 0)))
107          {
108            type = build_pointer_type (type);
109            /* Don't clobber a value that might be part of a default
110               parameter value.  */
111            mark_addressable (slot);
112            if (TREE_PERMANENT (args))
113              args = tree_cons (0, build1 (ADDR_EXPR, type, slot),
114                                TREE_CHAIN (args));
115            else
116              TREE_VALUE (args) = build1 (ADDR_EXPR, type, slot);
117            call_target = 0;
118          }
119        else if (TREE_CODE (return_type) == REFERENCE_TYPE)
120          {
121            type = return_type;
122            call_target = 0;
123          }
124        else
125          {
126#ifdef PCC_STATIC_STRUCT_RETURN
127            pcc_struct_return = 1;
128            call_target = 0;
129#else
130            call_target = target;
131#endif
132          }
133        if (call_target)
134          {
135            /* Make this a valid memory address now.  The code below assumes
136               that it can compare rtx and make assumptions based on the
137               result.  The assumptions are true only if the address was
138               valid to begin with.  */
139            call_target = validize_mem (call_target);
140          }
141
142        call_exp = build (CALL_EXPR, type, func, args, 0);
143        TREE_SIDE_EFFECTS (call_exp) = 1;
144        return_target = expand_call (call_exp, call_target, ignore);
145        if (call_target == 0)
146          {
147            if (pcc_struct_return)
148              {
149                extern int flag_access_control;
150                int old_ac = flag_access_control;
151
152                tree init = build_decl (VAR_DECL, 0, type);
153                TREE_ADDRESSABLE (init) = 1;
154                DECL_RTL (init) = return_target;
155
156                flag_access_control = 0;
157                expand_aggr_init (slot, init, 0, LOOKUP_ONLYCONVERTING);
158                flag_access_control = old_ac;
159
160                if (TYPE_NEEDS_DESTRUCTOR (type))
161                  {
162                    init = build_decl (VAR_DECL, 0,
163                                       build_reference_type (type));
164                    DECL_RTL (init) = XEXP (return_target, 0);
165
166                    init = maybe_build_cleanup (convert_from_reference (init));
167                    if (init != NULL_TREE)
168                      expand_expr (init, 0, 0, 0);
169                  }
170                call_target = return_target = DECL_RTL (slot);
171              }
172            else
173              call_target = return_target;
174          }
175
176        if (call_target != return_target)
177          {
178            my_friendly_assert (TYPE_HAS_TRIVIAL_INIT_REF (type), 317);
179            if (GET_MODE (return_target) == BLKmode)
180              emit_block_move (call_target, return_target, expr_size (exp),
181                               TYPE_ALIGN (type) / BITS_PER_UNIT);
182            else
183              emit_move_insn (call_target, return_target);
184          }
185
186        if (TREE_CODE (return_type) == REFERENCE_TYPE)
187          {
188            tree init;
189
190            if (GET_CODE (call_target) == REG
191                && REGNO (call_target) < FIRST_PSEUDO_REGISTER)
192              my_friendly_abort (39);
193
194            type = TREE_TYPE (exp);
195
196            init = build (RTL_EXPR, return_type, 0, call_target);
197            /* We got back a reference to the type we want.  Now initialize
198               target with that.  */
199            expand_aggr_init (slot, init, 0, LOOKUP_ONLYCONVERTING);
200          }
201
202        if (DECL_RTL (slot) != target)
203          emit_move_insn (DECL_RTL (slot), target);
204        return DECL_RTL (slot);
205      }
206
207    case OFFSET_REF:
208      {
209#if 1
210        return expand_expr (default_conversion (resolve_offset_ref (exp)),
211                            target, tmode, EXPAND_NORMAL);
212#else
213        /* This is old crusty code, and does not handle all that the
214           resolve_offset_ref function does.  (mrs) */
215        tree base = build_unary_op (ADDR_EXPR, TREE_OPERAND (exp, 0), 0);
216        tree offset = build_unary_op (ADDR_EXPR, TREE_OPERAND (exp, 1), 0);
217        return expand_expr (build (PLUS_EXPR, TREE_TYPE (exp), base, offset),
218                            target, tmode, EXPAND_NORMAL);
219#endif
220      }
221
222    case THUNK_DECL:
223      return DECL_RTL (exp);
224
225    case THROW_EXPR:
226      expand_throw (TREE_OPERAND (exp, 0));
227      return NULL;
228
229    case UNSAVE_EXPR:
230      {
231        rtx temp;
232        temp = expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier);
233        TREE_OPERAND (exp, 0) = unsave_expr_now (TREE_OPERAND (exp, 0));
234        return temp;
235      }
236
237    default:
238      break;
239    }
240  my_friendly_abort (40);
241  /* NOTREACHED */
242  return NULL;
243}
244
245void
246init_cplus_expand ()
247{
248  lang_expand_expr = cplus_expand_expr;
249}
250
251/* If DECL had its rtl moved from where callers expect it
252   to be, fix it up.  RESULT is the nominal rtl for the RESULT_DECL,
253   which may be a pseudo instead of a hard register.  */
254
255void
256fixup_result_decl (decl, result)
257     tree decl;
258     rtx result;
259{
260  if (REG_P (result))
261    {
262      if (REGNO (result) >= FIRST_PSEUDO_REGISTER)
263        {
264          rtx real_decl_result;
265
266#ifdef FUNCTION_OUTGOING_VALUE
267          real_decl_result
268            = FUNCTION_OUTGOING_VALUE (TREE_TYPE (decl), current_function_decl);
269#else
270          real_decl_result
271            = FUNCTION_VALUE (TREE_TYPE (decl), current_function_decl);
272#endif
273          REG_FUNCTION_VALUE_P (real_decl_result) = 1;
274          result = real_decl_result;
275        }
276      store_expr (decl, result, 0);
277      emit_insn (gen_rtx (USE, VOIDmode, result));
278    }
279}
280
281/* Return nonzero iff DECL is memory-based.  The DECL_RTL of
282   certain const variables might be a CONST_INT, or a REG
283   in some cases.  We cannot use `memory_operand' as a test
284   here because on most RISC machines, a variable's address
285   is not, by itself, a legitimate address.  */
286
287int
288decl_in_memory_p (decl)
289     tree decl;
290{
291  return DECL_RTL (decl) != 0 && GET_CODE (DECL_RTL (decl)) == MEM;
292}
293
294/* Expand this initialization inline and see if it's simple enough that
295   it can be done at compile-time.  */
296
297static tree
298extract_aggr_init (decl, init)
299     tree decl, init;
300{
301  return 0;
302}
303
304static tree
305extract_scalar_init (decl, init)
306     tree decl, init;
307{
308  rtx value, insns, insn;
309  extern struct obstack temporary_obstack;
310  tree t = NULL_TREE;
311
312  push_obstacks (&temporary_obstack, &temporary_obstack);
313  start_sequence ();
314  value = expand_expr (init, NULL_RTX, VOIDmode, 0);
315  insns = get_insns ();
316  end_sequence ();
317  reg_scan (insns, max_reg_num (), 0);
318  jump_optimize (insns, 0, 0, 1);
319  pop_obstacks ();
320
321  for (insn = insns; insn; insn = NEXT_INSN (insn))
322    {
323      rtx r, to;
324
325      if (GET_CODE (insn) == NOTE)
326        continue;
327      else if (GET_CODE (insn) != INSN)
328        return 0;
329
330      r = PATTERN (insn);
331      if (GET_CODE (r) != SET)
332        return 0;
333
334      to = XEXP (r, 0);
335
336      if (! (to == value ||
337             (GET_CODE (to) == SUBREG && XEXP (to, 0) == value)))
338        return 0;
339
340      r = XEXP (r, 1);
341
342      switch (GET_CODE (r))
343        {
344        case CONST_INT:
345          t = build_int_2 (XEXP (r, 0), 0);
346          break;
347        default:
348          return 0;
349        }
350    }
351
352  return t;
353}
354
355int
356extract_init (decl, init)
357     tree decl, init;
358{
359  return 0;
360
361  if (IS_AGGR_TYPE (TREE_TYPE (decl))
362      || TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
363    init = extract_aggr_init (decl, init);
364  else
365    init = extract_scalar_init (decl, init);
366
367  if (init == NULL_TREE)
368    return 0;
369
370  DECL_INITIAL (decl) = init;
371  return 1;
372}
Note: See TracBrowser for help on using the repository browser.