]> gcc.gnu.org Git - gcc.git/blob - gcc/cp/expr.c
59th 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 if (TREE_PERMANENT (args))
111 args = tree_cons (0, build1 (ADDR_EXPR, type, slot),
112 TREE_CHAIN (args));
113 else
114 TREE_VALUE (args) = build1 (ADDR_EXPR, type, slot);
115 call_target = 0;
116 }
117 else if (TREE_CODE (return_type) == REFERENCE_TYPE)
118 {
119 type = return_type;
120 call_target = 0;
121 }
122 else
123 {
124 #ifdef PCC_STATIC_STRUCT_RETURN
125 pcc_struct_return = 1;
126 call_target = 0;
127 #else
128 call_target = target;
129 #endif
130 }
131 if (call_target)
132 {
133 preserve_temp_slots (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 preserve_temp_slots (DECL_RTL (slot));
143 call_exp = build (CALL_EXPR, type, func, args, 0);
144 TREE_SIDE_EFFECTS (call_exp) = 1;
145 return_target = expand_expr (call_exp, call_target, mode, 0);
146 free_temp_slots ();
147 if (call_target == 0)
148 {
149 if (pcc_struct_return)
150 {
151 extern int flag_access_control;
152 int old_ac = flag_access_control;
153
154 tree init = build (RTL_EXPR, type, 0, return_target);
155 TREE_ADDRESSABLE (init) = 1;
156
157 flag_access_control = 0;
158 expand_aggr_init (slot, init, 0, LOOKUP_ONLYCONVERTING);
159 flag_access_control = old_ac;
160
161 if (TYPE_NEEDS_DESTRUCTOR (type))
162 {
163 init = build (RTL_EXPR, build_reference_type (type), 0,
164 XEXP (return_target, 0));
165 init = maybe_build_cleanup (convert_from_reference (init));
166 if (init != NULL_TREE)
167 expand_expr (init, 0, 0, 0);
168 }
169 call_target = return_target = DECL_RTL (slot);
170 }
171 else
172 call_target = return_target;
173 }
174
175 if (call_target != return_target)
176 {
177 my_friendly_assert (! TYPE_NEEDS_CONSTRUCTING (type), 317);
178 if (GET_MODE (return_target) == BLKmode)
179 emit_block_move (call_target, return_target, expr_size (exp),
180 TYPE_ALIGN (type) / BITS_PER_UNIT);
181 else
182 emit_move_insn (call_target, return_target);
183 }
184
185 if (TREE_CODE (return_type) == REFERENCE_TYPE)
186 {
187 tree init;
188
189 if (GET_CODE (call_target) == REG
190 && REGNO (call_target) < FIRST_PSEUDO_REGISTER)
191 my_friendly_abort (39);
192
193 type = TREE_TYPE (exp);
194
195 init = build (RTL_EXPR, return_type, 0, call_target);
196 /* We got back a reference to the type we want. Now initialize
197 target with that. */
198 expand_aggr_init (slot, init, 0, LOOKUP_ONLYCONVERTING);
199 }
200
201 if (DECL_RTL (slot) != target)
202 emit_move_insn (DECL_RTL (slot), target);
203 return DECL_RTL (slot);
204 }
205
206 case OFFSET_REF:
207 {
208 #if 1
209 return expand_expr (default_conversion (resolve_offset_ref (exp)),
210 target, tmode, EXPAND_NORMAL);
211 #else
212 /* This is old crusty code, and does not handle all that the
213 resolve_offset_ref function does. (mrs) */
214 tree base = build_unary_op (ADDR_EXPR, TREE_OPERAND (exp, 0), 0);
215 tree offset = build_unary_op (ADDR_EXPR, TREE_OPERAND (exp, 1), 0);
216 return expand_expr (build (PLUS_EXPR, TREE_TYPE (exp), base, offset),
217 target, tmode, EXPAND_NORMAL);
218 #endif
219 }
220
221 case THUNK_DECL:
222 return DECL_RTL (exp);
223
224 case THROW_EXPR:
225 expand_throw (TREE_OPERAND (exp, 0));
226 return NULL;
227
228 default:
229 break;
230 }
231 my_friendly_abort (40);
232 /* NOTREACHED */
233 return NULL;
234 }
235
236 void
237 init_cplus_expand ()
238 {
239 lang_expand_expr = cplus_expand_expr;
240 }
241
242 /* If DECL had its rtl moved from where callers expect it
243 to be, fix it up. RESULT is the nominal rtl for the RESULT_DECL,
244 which may be a pseudo instead of a hard register. */
245
246 void
247 fixup_result_decl (decl, result)
248 tree decl;
249 rtx result;
250 {
251 if (REG_P (result))
252 {
253 if (REGNO (result) >= FIRST_PSEUDO_REGISTER)
254 {
255 rtx real_decl_result;
256
257 #ifdef FUNCTION_OUTGOING_VALUE
258 real_decl_result
259 = FUNCTION_OUTGOING_VALUE (TREE_TYPE (decl), current_function_decl);
260 #else
261 real_decl_result
262 = FUNCTION_VALUE (TREE_TYPE (decl), current_function_decl);
263 #endif
264 REG_FUNCTION_VALUE_P (real_decl_result) = 1;
265 result = real_decl_result;
266 }
267 store_expr (decl, result, 0);
268 emit_insn (gen_rtx (USE, VOIDmode, result));
269 }
270 }
271
272 /* Return nonzero iff DECL is memory-based. The DECL_RTL of
273 certain const variables might be a CONST_INT, or a REG
274 in some cases. We cannot use `memory_operand' as a test
275 here because on most RISC machines, a variable's address
276 is not, by itself, a legitimate address. */
277
278 int
279 decl_in_memory_p (decl)
280 tree decl;
281 {
282 return DECL_RTL (decl) != 0 && GET_CODE (DECL_RTL (decl)) == MEM;
283 }
284
285 /* Expand this initialization inline and see if it's simple enough that
286 it can be done at compile-time. */
287
288 static tree
289 extract_aggr_init (decl, init)
290 tree decl, init;
291 {
292 return 0;
293 }
294
295 static tree
296 extract_scalar_init (decl, init)
297 tree decl, init;
298 {
299 rtx value, insns, insn;
300 extern struct obstack temporary_obstack;
301 tree t = NULL_TREE;
302
303 push_obstacks (&temporary_obstack, &temporary_obstack);
304 start_sequence ();
305 value = expand_expr (init, NULL_RTX, VOIDmode, 0);
306 insns = get_insns ();
307 end_sequence ();
308 reg_scan (insns, max_reg_num (), 0);
309 jump_optimize (insns, 0, 0, 1);
310 pop_obstacks ();
311
312 for (insn = insns; insn; insn = NEXT_INSN (insn))
313 {
314 rtx r, to;
315
316 if (GET_CODE (insn) == NOTE)
317 continue;
318 else if (GET_CODE (insn) != INSN)
319 return 0;
320
321 r = PATTERN (insn);
322 if (GET_CODE (r) != SET)
323 return 0;
324
325 to = XEXP (r, 0);
326
327 if (! (to == value ||
328 (GET_CODE (to) == SUBREG && XEXP (to, 0) == value)))
329 return 0;
330
331 r = XEXP (r, 1);
332
333 switch (GET_CODE (r))
334 {
335 case CONST_INT:
336 t = build_int_2 (XEXP (r, 0), 0);
337 break;
338 default:
339 return 0;
340 }
341 }
342
343 return t;
344 }
345
346 int
347 extract_init (decl, init)
348 tree decl, init;
349 {
350 return 0;
351
352 if (IS_AGGR_TYPE (TREE_TYPE (decl))
353 || TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
354 init = extract_aggr_init (decl, init);
355 else
356 init = extract_scalar_init (decl, init);
357
358 if (init == NULL_TREE)
359 return 0;
360
361 DECL_INITIAL (decl) = init;
362 return 1;
363 }
This page took 0.052013 seconds and 5 git commands to generate.