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