]>
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 | { | |
02531345 | 62 | case AGGR_INIT_EXPR: |
8d08fdba MS |
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; | |
8d08fdba MS |
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 | ||
02531345 JM |
87 | /* Should always be called with a target. */ |
88 | my_friendly_assert (target != NULL_RTX, 205); | |
8d08fdba MS |
89 | |
90 | /* The target the initializer will initialize (CALL_TARGET) | |
91 | must now be directed to initialize the target we are | |
92 | supposed to initialize (TARGET). The semantics for | |
93 | choosing what CALL_TARGET is is language-specific, | |
94 | as is building the call which will perform the | |
95 | initialization. It is left here to show the choices that | |
96 | exist for C++. */ | |
97 | ||
98 | if (TREE_CODE (func) == ADDR_EXPR | |
99 | && TREE_CODE (TREE_OPERAND (func, 0)) == FUNCTION_DECL | |
100 | && DECL_CONSTRUCTOR_P (TREE_OPERAND (func, 0))) | |
101 | { | |
f30432d7 | 102 | type = build_pointer_type (type); |
8d08fdba MS |
103 | /* Don't clobber a value that might be part of a default |
104 | parameter value. */ | |
c19a8067 | 105 | mark_addressable (slot); |
8d08fdba | 106 | if (TREE_PERMANENT (args)) |
e66d884e | 107 | args = expr_tree_cons (0, build1 (ADDR_EXPR, type, slot), |
8d08fdba MS |
108 | TREE_CHAIN (args)); |
109 | else | |
110 | TREE_VALUE (args) = build1 (ADDR_EXPR, type, slot); | |
111 | call_target = 0; | |
112 | } | |
8d08fdba MS |
113 | else |
114 | { | |
115 | #ifdef PCC_STATIC_STRUCT_RETURN | |
116 | pcc_struct_return = 1; | |
117 | call_target = 0; | |
118 | #else | |
119 | call_target = target; | |
120 | #endif | |
121 | } | |
8d08fdba | 122 | |
4dabb379 | 123 | call_exp = build (CALL_EXPR, type, func, args, NULL_TREE); |
8d08fdba | 124 | TREE_SIDE_EFFECTS (call_exp) = 1; |
e8abc66f | 125 | return_target = expand_call (call_exp, call_target, ignore); |
8d08fdba | 126 | |
02531345 | 127 | if (call_target) |
8d08fdba | 128 | { |
02531345 JM |
129 | my_friendly_assert (rtx_equal_p (call_target, return_target) |
130 | || TYPE_HAS_TRIVIAL_INIT_REF (type), 317); | |
131 | return return_target; | |
8d08fdba MS |
132 | } |
133 | ||
02531345 JM |
134 | /* If we're suffering under the ancient PCC_STATIC_STRUCT_RETURN |
135 | calling convention, we need to copy the return value out of | |
136 | the static return buffer into slot. */ | |
137 | if (pcc_struct_return) | |
8d08fdba | 138 | { |
02531345 JM |
139 | extern int flag_access_control; |
140 | int old_ac = flag_access_control; | |
8d08fdba | 141 | |
02531345 JM |
142 | tree init = build_decl (VAR_DECL, NULL_TREE, |
143 | build_reference_type (type)); | |
144 | DECL_RTL (init) = XEXP (return_target, 0); | |
8d08fdba | 145 | |
02531345 | 146 | flag_access_control = 0; |
6060a796 | 147 | expand_aggr_init (slot, init, 0, LOOKUP_ONLYCONVERTING); |
02531345 JM |
148 | flag_access_control = old_ac; |
149 | ||
150 | if (TYPE_NEEDS_DESTRUCTOR (type)) | |
151 | { | |
152 | init = maybe_build_cleanup (convert_from_reference (init)); | |
153 | if (init != NULL_TREE) | |
154 | expand_expr (init, const0_rtx, VOIDmode, 0); | |
155 | } | |
8d08fdba MS |
156 | } |
157 | ||
8d08fdba MS |
158 | return DECL_RTL (slot); |
159 | } | |
160 | ||
161 | case OFFSET_REF: | |
162 | { | |
163 | #if 1 | |
164 | return expand_expr (default_conversion (resolve_offset_ref (exp)), | |
165 | target, tmode, EXPAND_NORMAL); | |
166 | #else | |
167 | /* This is old crusty code, and does not handle all that the | |
168 | resolve_offset_ref function does. (mrs) */ | |
169 | tree base = build_unary_op (ADDR_EXPR, TREE_OPERAND (exp, 0), 0); | |
170 | tree offset = build_unary_op (ADDR_EXPR, TREE_OPERAND (exp, 1), 0); | |
171 | return expand_expr (build (PLUS_EXPR, TREE_TYPE (exp), base, offset), | |
172 | target, tmode, EXPAND_NORMAL); | |
173 | #endif | |
174 | } | |
175 | ||
8926095f MS |
176 | case THUNK_DECL: |
177 | return DECL_RTL (exp); | |
178 | ||
8d2733ca MS |
179 | case THROW_EXPR: |
180 | expand_throw (TREE_OPERAND (exp, 0)); | |
181 | return NULL; | |
182 | ||
a80e4195 MS |
183 | case VEC_INIT_EXPR: |
184 | return expand_expr | |
185 | (expand_vec_init | |
186 | (NULL_TREE, TREE_OPERAND (exp, 0), | |
187 | build_binary_op (MINUS_EXPR, TREE_OPERAND (exp, 2), | |
188 | integer_one_node, 1), | |
189 | TREE_OPERAND (exp, 1), 0), target, tmode, modifier); | |
190 | ||
8d08fdba MS |
191 | default: |
192 | break; | |
193 | } | |
194 | my_friendly_abort (40); | |
195 | /* NOTREACHED */ | |
196 | return NULL; | |
197 | } | |
198 | ||
199 | void | |
200 | init_cplus_expand () | |
201 | { | |
202 | lang_expand_expr = cplus_expand_expr; | |
203 | } | |
204 | ||
205 | /* If DECL had its rtl moved from where callers expect it | |
206 | to be, fix it up. RESULT is the nominal rtl for the RESULT_DECL, | |
207 | which may be a pseudo instead of a hard register. */ | |
208 | ||
209 | void | |
210 | fixup_result_decl (decl, result) | |
211 | tree decl; | |
212 | rtx result; | |
213 | { | |
214 | if (REG_P (result)) | |
215 | { | |
216 | if (REGNO (result) >= FIRST_PSEUDO_REGISTER) | |
217 | { | |
218 | rtx real_decl_result; | |
219 | ||
220 | #ifdef FUNCTION_OUTGOING_VALUE | |
221 | real_decl_result | |
222 | = FUNCTION_OUTGOING_VALUE (TREE_TYPE (decl), current_function_decl); | |
223 | #else | |
224 | real_decl_result | |
225 | = FUNCTION_VALUE (TREE_TYPE (decl), current_function_decl); | |
226 | #endif | |
227 | REG_FUNCTION_VALUE_P (real_decl_result) = 1; | |
228 | result = real_decl_result; | |
229 | } | |
28cbf42c | 230 | store_expr (decl, result, 0); |
8d08fdba MS |
231 | emit_insn (gen_rtx (USE, VOIDmode, result)); |
232 | } | |
233 | } | |
234 | ||
28cbf42c MS |
235 | /* Expand this initialization inline and see if it's simple enough that |
236 | it can be done at compile-time. */ | |
237 | ||
238 | static tree | |
239 | extract_aggr_init (decl, init) | |
240 | tree decl, init; | |
241 | { | |
242 | return 0; | |
243 | } | |
244 | ||
245 | static tree | |
246 | extract_scalar_init (decl, init) | |
247 | tree decl, init; | |
248 | { | |
249 | rtx value, insns, insn; | |
250 | extern struct obstack temporary_obstack; | |
251 | tree t = NULL_TREE; | |
252 | ||
253 | push_obstacks (&temporary_obstack, &temporary_obstack); | |
254 | start_sequence (); | |
255 | value = expand_expr (init, NULL_RTX, VOIDmode, 0); | |
256 | insns = get_insns (); | |
257 | end_sequence (); | |
258 | reg_scan (insns, max_reg_num (), 0); | |
259 | jump_optimize (insns, 0, 0, 1); | |
260 | pop_obstacks (); | |
261 | ||
262 | for (insn = insns; insn; insn = NEXT_INSN (insn)) | |
263 | { | |
264 | rtx r, to; | |
265 | ||
266 | if (GET_CODE (insn) == NOTE) | |
267 | continue; | |
268 | else if (GET_CODE (insn) != INSN) | |
269 | return 0; | |
270 | ||
271 | r = PATTERN (insn); | |
272 | if (GET_CODE (r) != SET) | |
273 | return 0; | |
274 | ||
275 | to = XEXP (r, 0); | |
276 | ||
beb53fb8 JM |
277 | if (! (to == value |
278 | || (GET_CODE (to) == SUBREG && XEXP (to, 0) == value))) | |
28cbf42c MS |
279 | return 0; |
280 | ||
281 | r = XEXP (r, 1); | |
282 | ||
283 | switch (GET_CODE (r)) | |
284 | { | |
285 | case CONST_INT: | |
286 | t = build_int_2 (XEXP (r, 0), 0); | |
287 | break; | |
288 | default: | |
289 | return 0; | |
290 | } | |
291 | } | |
292 | ||
293 | return t; | |
294 | } | |
295 | ||
296 | int | |
297 | extract_init (decl, init) | |
298 | tree decl, init; | |
299 | { | |
300 | return 0; | |
301 | ||
9e9ff709 | 302 | #if 0 |
28cbf42c MS |
303 | if (IS_AGGR_TYPE (TREE_TYPE (decl)) |
304 | || TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE) | |
305 | init = extract_aggr_init (decl, init); | |
306 | else | |
307 | init = extract_scalar_init (decl, init); | |
308 | ||
309 | if (init == NULL_TREE) | |
310 | return 0; | |
311 | ||
312 | DECL_INITIAL (decl) = init; | |
313 | return 1; | |
9e9ff709 | 314 | #endif |
28cbf42c | 315 | } |
5566b478 MS |
316 | |
317 | void | |
318 | do_case (start, end) | |
319 | tree start, end; | |
320 | { | |
321 | tree value1 = NULL_TREE, value2 = NULL_TREE, label; | |
322 | ||
ce122a86 MS |
323 | if (start != NULL_TREE && TREE_TYPE (start) != NULL_TREE |
324 | && POINTER_TYPE_P (TREE_TYPE (start))) | |
fc378698 MS |
325 | error ("pointers are not permitted as case values"); |
326 | ||
5566b478 MS |
327 | if (end && pedantic) |
328 | pedwarn ("ANSI C++ forbids range expressions in switch statement"); | |
329 | ||
5156628f | 330 | if (processing_template_decl) |
5566b478 MS |
331 | { |
332 | add_tree (build_min_nt (CASE_LABEL, start, end)); | |
333 | return; | |
334 | } | |
335 | ||
336 | if (start) | |
337 | value1 = check_cp_case_value (start); | |
338 | if (end) | |
339 | value2 = check_cp_case_value (end); | |
340 | ||
341 | label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); | |
342 | ||
343 | if (value1 != error_mark_node | |
344 | && value2 != error_mark_node) | |
345 | { | |
346 | tree duplicate; | |
347 | int success; | |
348 | ||
349 | if (end) | |
350 | success = pushcase_range (value1, value2, convert_and_check, | |
351 | label, &duplicate); | |
352 | else if (start) | |
353 | success = pushcase (value1, convert_and_check, label, &duplicate); | |
354 | else | |
355 | success = pushcase (NULL_TREE, 0, label, &duplicate); | |
356 | ||
357 | if (success == 1) | |
358 | { | |
359 | if (end) | |
360 | error ("case label not within a switch statement"); | |
361 | else if (start) | |
362 | cp_error ("case label `%E' not within a switch statement", start); | |
363 | else | |
364 | error ("default label not within a switch statement"); | |
365 | } | |
366 | else if (success == 2) | |
367 | { | |
368 | if (end) | |
369 | { | |
370 | error ("duplicate (or overlapping) case value"); | |
371 | cp_error_at ("this is the first entry overlapping that value", | |
372 | duplicate); | |
373 | } | |
374 | else if (start) | |
375 | { | |
376 | cp_error ("duplicate case value `%E'", start); | |
377 | cp_error_at ("previously used here", duplicate); | |
378 | } | |
379 | else | |
380 | { | |
381 | error ("multiple default labels in one switch"); | |
382 | cp_error_at ("this is the first default label", duplicate); | |
383 | } | |
384 | } | |
385 | else if (success == 3) | |
386 | warning ("case value out of range"); | |
387 | else if (success == 4) | |
388 | warning ("empty range specified"); | |
389 | else if (success == 5) | |
390 | { | |
391 | if (end) | |
392 | error ("case label within scope of cleanup or variable array"); | |
eb448459 MS |
393 | else if (! start) |
394 | error ("`default' label within scope of cleanup or variable array"); | |
5566b478 MS |
395 | else |
396 | cp_error ("case label `%E' within scope of cleanup or variable array", start); | |
397 | } | |
398 | } | |
399 | if (start) | |
400 | define_case_label (label); | |
401 | else | |
402 | define_case_label (NULL_TREE); | |
403 | } |