]>
Commit | Line | Data |
---|---|---|
8d08fdba MS |
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 | { | |
eae89e04 JM |
151 | extern int flag_access_control; |
152 | int old_ac = flag_access_control; | |
153 | ||
8d08fdba MS |
154 | tree init = build (RTL_EXPR, type, 0, return_target); |
155 | TREE_ADDRESSABLE (init) = 1; | |
eae89e04 JM |
156 | |
157 | flag_access_control = 0; | |
6060a796 | 158 | expand_aggr_init (slot, init, 0, LOOKUP_ONLYCONVERTING); |
eae89e04 JM |
159 | flag_access_control = old_ac; |
160 | ||
8d08fdba MS |
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. */ | |
6060a796 | 198 | expand_aggr_init (slot, init, 0, LOOKUP_ONLYCONVERTING); |
8d08fdba MS |
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 | ||
8926095f MS |
221 | case THUNK_DECL: |
222 | return DECL_RTL (exp); | |
223 | ||
8d2733ca MS |
224 | case THROW_EXPR: |
225 | expand_throw (TREE_OPERAND (exp, 0)); | |
226 | return NULL; | |
227 | ||
8d08fdba MS |
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 | } | |
28cbf42c | 267 | store_expr (decl, result, 0); |
8d08fdba MS |
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. */ | |
28cbf42c | 277 | |
8d08fdba MS |
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 | } | |
28cbf42c MS |
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 | } |