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