]>
Commit | Line | Data |
---|---|---|
8d08fdba MS |
1 | /* Convert language-specific tree expression to rtl instructions, |
2 | for GNU compiler. | |
8ecb1d92 | 3 | Copyright (C) 1988, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. |
8d08fdba MS |
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 | |
e9fa0c7c RK |
19 | the Free Software Foundation, 59 Temple Place - Suite 330, |
20 | Boston, MA 02111-1307, USA. */ | |
8d08fdba MS |
21 | |
22 | ||
23 | #include "config.h" | |
da20811c | 24 | #include <stdio.h> |
8d08fdba MS |
25 | #include "rtl.h" |
26 | #include "tree.h" | |
27 | #include "flags.h" | |
28 | #include "expr.h" | |
29 | #include "cp-tree.h" | |
30 | ||
49c249e1 JM |
31 | static tree extract_aggr_init PROTO((tree, tree)); |
32 | static tree extract_scalar_init PROTO((tree, tree)); | |
9f617717 L |
33 | static rtx cplus_expand_expr PROTO((tree, rtx, enum machine_mode, |
34 | enum expand_modifier)); | |
49c249e1 | 35 | |
8d08fdba MS |
36 | /* Hook used by expand_expr to expand language-specific tree codes. */ |
37 | ||
9f617717 | 38 | static rtx |
8d08fdba MS |
39 | cplus_expand_expr (exp, target, tmode, modifier) |
40 | tree exp; | |
41 | rtx target; | |
42 | enum machine_mode tmode; | |
43 | enum expand_modifier modifier; | |
44 | { | |
45 | tree type = TREE_TYPE (exp); | |
46 | register enum machine_mode mode = TYPE_MODE (type); | |
47 | register enum tree_code code = TREE_CODE (exp); | |
8d08fdba MS |
48 | int ignore = target == const0_rtx; |
49 | ||
50 | if (ignore) | |
de22184b | 51 | target = 0; |
8d08fdba MS |
52 | |
53 | /* No sense saving up arithmetic to be done | |
54 | if it's all in the wrong mode to form part of an address. | |
55 | And force_operand won't know whether to sign-extend or zero-extend. */ | |
56 | ||
57 | if (mode != Pmode && modifier == EXPAND_SUM) | |
58 | modifier = EXPAND_NORMAL; | |
59 | ||
60 | switch (code) | |
61 | { | |
62 | case NEW_EXPR: | |
63 | { | |
64 | /* Something needs to be initialized, but we didn't know | |
65 | where that thing was when building the tree. For example, | |
66 | it could be the return value of a function, or a parameter | |
67 | to a function which lays down in the stack, or a temporary | |
68 | variable which must be passed by reference. | |
69 | ||
70 | Cleanups are handled in a language-specific way: they | |
71 | might be run by the called function (true in GNU C++ | |
72 | for parameters with cleanups), or they might be | |
73 | run by the caller, after the call (true in GNU C++ | |
74 | for other cleanup needs). */ | |
75 | ||
76 | tree func = TREE_OPERAND (exp, 0); | |
77 | tree args = TREE_OPERAND (exp, 1); | |
78 | tree type = TREE_TYPE (exp), slot; | |
79 | tree fn_type = TREE_TYPE (TREE_TYPE (func)); | |
80 | tree return_type = TREE_TYPE (fn_type); | |
81 | tree call_exp; | |
82 | rtx call_target, return_target; | |
83 | int pcc_struct_return = 0; | |
84 | ||
85 | /* The expression `init' wants to initialize what | |
86 | `target' represents. SLOT holds the slot for TARGET. */ | |
87 | slot = TREE_OPERAND (exp, 2); | |
88 | ||
89 | if (target == 0) | |
90 | { | |
91 | /* Should always be called with a target in BLKmode case. */ | |
92 | my_friendly_assert (mode != BLKmode, 205); | |
93 | my_friendly_assert (DECL_RTL (slot) != 0, 206); | |
94 | ||
95 | target = gen_reg_rtx (mode); | |
96 | } | |
97 | ||
98 | /* The target the initializer will initialize (CALL_TARGET) | |
99 | must now be directed to initialize the target we are | |
100 | supposed to initialize (TARGET). The semantics for | |
101 | choosing what CALL_TARGET is is language-specific, | |
102 | as is building the call which will perform the | |
103 | initialization. It is left here to show the choices that | |
104 | exist for C++. */ | |
105 | ||
106 | if (TREE_CODE (func) == ADDR_EXPR | |
107 | && TREE_CODE (TREE_OPERAND (func, 0)) == FUNCTION_DECL | |
108 | && DECL_CONSTRUCTOR_P (TREE_OPERAND (func, 0))) | |
109 | { | |
f30432d7 | 110 | type = build_pointer_type (type); |
8d08fdba MS |
111 | /* Don't clobber a value that might be part of a default |
112 | parameter value. */ | |
c19a8067 | 113 | mark_addressable (slot); |
8d08fdba | 114 | if (TREE_PERMANENT (args)) |
e66d884e | 115 | args = expr_tree_cons (0, build1 (ADDR_EXPR, type, slot), |
8d08fdba MS |
116 | TREE_CHAIN (args)); |
117 | else | |
118 | TREE_VALUE (args) = build1 (ADDR_EXPR, type, slot); | |
119 | call_target = 0; | |
120 | } | |
121 | else if (TREE_CODE (return_type) == REFERENCE_TYPE) | |
122 | { | |
123 | type = return_type; | |
124 | call_target = 0; | |
125 | } | |
126 | else | |
127 | { | |
128 | #ifdef PCC_STATIC_STRUCT_RETURN | |
129 | pcc_struct_return = 1; | |
130 | call_target = 0; | |
131 | #else | |
132 | call_target = target; | |
133 | #endif | |
134 | } | |
135 | if (call_target) | |
136 | { | |
8d08fdba MS |
137 | /* Make this a valid memory address now. The code below assumes |
138 | that it can compare rtx and make assumptions based on the | |
139 | result. The assumptions are true only if the address was | |
140 | valid to begin with. */ | |
141 | call_target = validize_mem (call_target); | |
f49422da MS |
142 | |
143 | /* If this is a reference to a symbol, expand_inline_function | |
144 | will do this transformation and return a different target | |
145 | than the one we gave it, though functionally equivalent. Do | |
146 | the transformation here to avoid confusion. */ | |
147 | if (! cse_not_expected && GET_CODE (call_target) == MEM | |
148 | && GET_CODE (XEXP (call_target, 0)) == SYMBOL_REF) | |
149 | { | |
150 | call_target = gen_rtx | |
151 | (MEM, mode, memory_address (mode, XEXP (call_target, 0))); | |
152 | MEM_IN_STRUCT_P (call_target) = 1; | |
153 | } | |
8d08fdba MS |
154 | } |
155 | ||
4dabb379 | 156 | call_exp = build (CALL_EXPR, type, func, args, NULL_TREE); |
8d08fdba | 157 | TREE_SIDE_EFFECTS (call_exp) = 1; |
e8abc66f | 158 | return_target = expand_call (call_exp, call_target, ignore); |
8d08fdba MS |
159 | if (call_target == 0) |
160 | { | |
161 | if (pcc_struct_return) | |
162 | { | |
eae89e04 JM |
163 | extern int flag_access_control; |
164 | int old_ac = flag_access_control; | |
165 | ||
a5894242 | 166 | tree init = build_decl (VAR_DECL, 0, type); |
8d08fdba | 167 | TREE_ADDRESSABLE (init) = 1; |
a5894242 | 168 | DECL_RTL (init) = return_target; |
eae89e04 JM |
169 | |
170 | flag_access_control = 0; | |
6060a796 | 171 | expand_aggr_init (slot, init, 0, LOOKUP_ONLYCONVERTING); |
eae89e04 JM |
172 | flag_access_control = old_ac; |
173 | ||
8d08fdba MS |
174 | if (TYPE_NEEDS_DESTRUCTOR (type)) |
175 | { | |
a5894242 MS |
176 | init = build_decl (VAR_DECL, 0, |
177 | build_reference_type (type)); | |
178 | DECL_RTL (init) = XEXP (return_target, 0); | |
179 | ||
8d08fdba MS |
180 | init = maybe_build_cleanup (convert_from_reference (init)); |
181 | if (init != NULL_TREE) | |
a0128b67 | 182 | expand_expr (init, const0_rtx, VOIDmode, 0); |
8d08fdba MS |
183 | } |
184 | call_target = return_target = DECL_RTL (slot); | |
185 | } | |
186 | else | |
187 | call_target = return_target; | |
188 | } | |
189 | ||
190 | if (call_target != return_target) | |
191 | { | |
e8abc66f | 192 | my_friendly_assert (TYPE_HAS_TRIVIAL_INIT_REF (type), 317); |
8d08fdba MS |
193 | if (GET_MODE (return_target) == BLKmode) |
194 | emit_block_move (call_target, return_target, expr_size (exp), | |
195 | TYPE_ALIGN (type) / BITS_PER_UNIT); | |
196 | else | |
197 | emit_move_insn (call_target, return_target); | |
198 | } | |
199 | ||
200 | if (TREE_CODE (return_type) == REFERENCE_TYPE) | |
201 | { | |
202 | tree init; | |
203 | ||
204 | if (GET_CODE (call_target) == REG | |
205 | && REGNO (call_target) < FIRST_PSEUDO_REGISTER) | |
206 | my_friendly_abort (39); | |
207 | ||
208 | type = TREE_TYPE (exp); | |
209 | ||
210 | init = build (RTL_EXPR, return_type, 0, call_target); | |
211 | /* We got back a reference to the type we want. Now initialize | |
212 | target with that. */ | |
6060a796 | 213 | expand_aggr_init (slot, init, 0, LOOKUP_ONLYCONVERTING); |
8d08fdba MS |
214 | } |
215 | ||
216 | if (DECL_RTL (slot) != target) | |
217 | emit_move_insn (DECL_RTL (slot), target); | |
218 | return DECL_RTL (slot); | |
219 | } | |
220 | ||
221 | case OFFSET_REF: | |
222 | { | |
223 | #if 1 | |
224 | return expand_expr (default_conversion (resolve_offset_ref (exp)), | |
225 | target, tmode, EXPAND_NORMAL); | |
226 | #else | |
227 | /* This is old crusty code, and does not handle all that the | |
228 | resolve_offset_ref function does. (mrs) */ | |
229 | tree base = build_unary_op (ADDR_EXPR, TREE_OPERAND (exp, 0), 0); | |
230 | tree offset = build_unary_op (ADDR_EXPR, TREE_OPERAND (exp, 1), 0); | |
231 | return expand_expr (build (PLUS_EXPR, TREE_TYPE (exp), base, offset), | |
232 | target, tmode, EXPAND_NORMAL); | |
233 | #endif | |
234 | } | |
235 | ||
8926095f MS |
236 | case THUNK_DECL: |
237 | return DECL_RTL (exp); | |
238 | ||
8d2733ca MS |
239 | case THROW_EXPR: |
240 | expand_throw (TREE_OPERAND (exp, 0)); | |
241 | return NULL; | |
242 | ||
a80e4195 MS |
243 | case VEC_INIT_EXPR: |
244 | return expand_expr | |
245 | (expand_vec_init | |
246 | (NULL_TREE, TREE_OPERAND (exp, 0), | |
247 | build_binary_op (MINUS_EXPR, TREE_OPERAND (exp, 2), | |
248 | integer_one_node, 1), | |
249 | TREE_OPERAND (exp, 1), 0), target, tmode, modifier); | |
250 | ||
8d08fdba MS |
251 | default: |
252 | break; | |
253 | } | |
254 | my_friendly_abort (40); | |
255 | /* NOTREACHED */ | |
256 | return NULL; | |
257 | } | |
258 | ||
259 | void | |
260 | init_cplus_expand () | |
261 | { | |
262 | lang_expand_expr = cplus_expand_expr; | |
263 | } | |
264 | ||
265 | /* If DECL had its rtl moved from where callers expect it | |
266 | to be, fix it up. RESULT is the nominal rtl for the RESULT_DECL, | |
267 | which may be a pseudo instead of a hard register. */ | |
268 | ||
269 | void | |
270 | fixup_result_decl (decl, result) | |
271 | tree decl; | |
272 | rtx result; | |
273 | { | |
274 | if (REG_P (result)) | |
275 | { | |
276 | if (REGNO (result) >= FIRST_PSEUDO_REGISTER) | |
277 | { | |
278 | rtx real_decl_result; | |
279 | ||
280 | #ifdef FUNCTION_OUTGOING_VALUE | |
281 | real_decl_result | |
282 | = FUNCTION_OUTGOING_VALUE (TREE_TYPE (decl), current_function_decl); | |
283 | #else | |
284 | real_decl_result | |
285 | = FUNCTION_VALUE (TREE_TYPE (decl), current_function_decl); | |
286 | #endif | |
287 | REG_FUNCTION_VALUE_P (real_decl_result) = 1; | |
288 | result = real_decl_result; | |
289 | } | |
28cbf42c | 290 | store_expr (decl, result, 0); |
8d08fdba MS |
291 | emit_insn (gen_rtx (USE, VOIDmode, result)); |
292 | } | |
293 | } | |
294 | ||
28cbf42c MS |
295 | /* Expand this initialization inline and see if it's simple enough that |
296 | it can be done at compile-time. */ | |
297 | ||
298 | static tree | |
299 | extract_aggr_init (decl, init) | |
300 | tree decl, init; | |
301 | { | |
302 | return 0; | |
303 | } | |
304 | ||
305 | static tree | |
306 | extract_scalar_init (decl, init) | |
307 | tree decl, init; | |
308 | { | |
309 | rtx value, insns, insn; | |
310 | extern struct obstack temporary_obstack; | |
311 | tree t = NULL_TREE; | |
312 | ||
313 | push_obstacks (&temporary_obstack, &temporary_obstack); | |
314 | start_sequence (); | |
315 | value = expand_expr (init, NULL_RTX, VOIDmode, 0); | |
316 | insns = get_insns (); | |
317 | end_sequence (); | |
318 | reg_scan (insns, max_reg_num (), 0); | |
319 | jump_optimize (insns, 0, 0, 1); | |
320 | pop_obstacks (); | |
321 | ||
322 | for (insn = insns; insn; insn = NEXT_INSN (insn)) | |
323 | { | |
324 | rtx r, to; | |
325 | ||
326 | if (GET_CODE (insn) == NOTE) | |
327 | continue; | |
328 | else if (GET_CODE (insn) != INSN) | |
329 | return 0; | |
330 | ||
331 | r = PATTERN (insn); | |
332 | if (GET_CODE (r) != SET) | |
333 | return 0; | |
334 | ||
335 | to = XEXP (r, 0); | |
336 | ||
beb53fb8 JM |
337 | if (! (to == value |
338 | || (GET_CODE (to) == SUBREG && XEXP (to, 0) == value))) | |
28cbf42c MS |
339 | return 0; |
340 | ||
341 | r = XEXP (r, 1); | |
342 | ||
343 | switch (GET_CODE (r)) | |
344 | { | |
345 | case CONST_INT: | |
346 | t = build_int_2 (XEXP (r, 0), 0); | |
347 | break; | |
348 | default: | |
349 | return 0; | |
350 | } | |
351 | } | |
352 | ||
353 | return t; | |
354 | } | |
355 | ||
356 | int | |
357 | extract_init (decl, init) | |
358 | tree decl, init; | |
359 | { | |
360 | return 0; | |
361 | ||
9e9ff709 | 362 | #if 0 |
28cbf42c MS |
363 | if (IS_AGGR_TYPE (TREE_TYPE (decl)) |
364 | || TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE) | |
365 | init = extract_aggr_init (decl, init); | |
366 | else | |
367 | init = extract_scalar_init (decl, init); | |
368 | ||
369 | if (init == NULL_TREE) | |
370 | return 0; | |
371 | ||
372 | DECL_INITIAL (decl) = init; | |
373 | return 1; | |
9e9ff709 | 374 | #endif |
28cbf42c | 375 | } |
5566b478 MS |
376 | |
377 | void | |
378 | do_case (start, end) | |
379 | tree start, end; | |
380 | { | |
381 | tree value1 = NULL_TREE, value2 = NULL_TREE, label; | |
382 | ||
ce122a86 MS |
383 | if (start != NULL_TREE && TREE_TYPE (start) != NULL_TREE |
384 | && POINTER_TYPE_P (TREE_TYPE (start))) | |
fc378698 MS |
385 | error ("pointers are not permitted as case values"); |
386 | ||
5566b478 MS |
387 | if (end && pedantic) |
388 | pedwarn ("ANSI C++ forbids range expressions in switch statement"); | |
389 | ||
5156628f | 390 | if (processing_template_decl) |
5566b478 MS |
391 | { |
392 | add_tree (build_min_nt (CASE_LABEL, start, end)); | |
393 | return; | |
394 | } | |
395 | ||
396 | if (start) | |
397 | value1 = check_cp_case_value (start); | |
398 | if (end) | |
399 | value2 = check_cp_case_value (end); | |
400 | ||
401 | label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); | |
402 | ||
403 | if (value1 != error_mark_node | |
404 | && value2 != error_mark_node) | |
405 | { | |
406 | tree duplicate; | |
407 | int success; | |
408 | ||
409 | if (end) | |
410 | success = pushcase_range (value1, value2, convert_and_check, | |
411 | label, &duplicate); | |
412 | else if (start) | |
413 | success = pushcase (value1, convert_and_check, label, &duplicate); | |
414 | else | |
415 | success = pushcase (NULL_TREE, 0, label, &duplicate); | |
416 | ||
417 | if (success == 1) | |
418 | { | |
419 | if (end) | |
420 | error ("case label not within a switch statement"); | |
421 | else if (start) | |
422 | cp_error ("case label `%E' not within a switch statement", start); | |
423 | else | |
424 | error ("default label not within a switch statement"); | |
425 | } | |
426 | else if (success == 2) | |
427 | { | |
428 | if (end) | |
429 | { | |
430 | error ("duplicate (or overlapping) case value"); | |
431 | cp_error_at ("this is the first entry overlapping that value", | |
432 | duplicate); | |
433 | } | |
434 | else if (start) | |
435 | { | |
436 | cp_error ("duplicate case value `%E'", start); | |
437 | cp_error_at ("previously used here", duplicate); | |
438 | } | |
439 | else | |
440 | { | |
441 | error ("multiple default labels in one switch"); | |
442 | cp_error_at ("this is the first default label", duplicate); | |
443 | } | |
444 | } | |
445 | else if (success == 3) | |
446 | warning ("case value out of range"); | |
447 | else if (success == 4) | |
448 | warning ("empty range specified"); | |
449 | else if (success == 5) | |
450 | { | |
451 | if (end) | |
452 | error ("case label within scope of cleanup or variable array"); | |
eb448459 MS |
453 | else if (! start) |
454 | error ("`default' label within scope of cleanup or variable array"); | |
5566b478 MS |
455 | else |
456 | cp_error ("case label `%E' within scope of cleanup or variable array", start); | |
457 | } | |
458 | } | |
459 | if (start) | |
460 | define_case_label (label); | |
461 | else | |
462 | define_case_label (NULL_TREE); | |
463 | } |