|
|
1.1 root 1: /* Convert language-specific tree expression to rtl instructions,
2: for GNU compiler.
1.1.1.2 ! root 3: Copyright (C) 1988, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
1.1 root 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
1.1.1.2 ! root 19: the Free Software Foundation, 59 Temple Place - Suite 330,
! 20: Boston, MA 02111-1307, USA. */
1.1 root 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: {
1.1.1.2 ! root 108: type = build_pointer_type (type);
1.1 root 109: /* Don't clobber a value that might be part of a default
110: parameter value. */
1.1.1.2 ! root 111: mark_addressable (slot);
1.1 root 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;
1.1.1.2 ! root 144: return_target = expand_call (call_exp, call_target, ignore);
1.1 root 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:
1.1.1.2 ! root 152: tree init = build_decl (VAR_DECL, 0, type);
1.1 root 153: TREE_ADDRESSABLE (init) = 1;
1.1.1.2 ! root 154: DECL_RTL (init) = return_target;
1.1 root 155:
156: flag_access_control = 0;
1.1.1.2 ! root 157: expand_aggr_init (slot, init, 0, LOOKUP_ONLYCONVERTING);
1.1 root 158: flag_access_control = old_ac;
159:
160: if (TYPE_NEEDS_DESTRUCTOR (type))
161: {
1.1.1.2 ! root 162: init = build_decl (VAR_DECL, 0,
! 163: build_reference_type (type));
! 164: DECL_RTL (init) = XEXP (return_target, 0);
! 165:
1.1 root 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: {
1.1.1.2 ! root 178: my_friendly_assert (TYPE_HAS_TRIVIAL_INIT_REF (type), 317);
1.1 root 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. */
1.1.1.2 ! root 199: expand_aggr_init (slot, init, 0, LOOKUP_ONLYCONVERTING);
1.1 root 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:
1.1.1.2 ! root 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:
1.1 root 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: }
1.1.1.2 ! root 276: store_expr (decl, result, 0);
1.1 root 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. */
1.1.1.2 ! root 286:
1.1 root 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: }
1.1.1.2 ! root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.