|
|
1.1 root 1: /* Convert language-specific tree expression to rtl instructions,
2: for GNU compiler.
3: Copyright (C) 1988, 1992 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: #define NULL 0
30:
31: /* Hook used by expand_expr to expand language-specific tree codes. */
32:
33: rtx
34: cplus_expand_expr (exp, target, tmode, modifier)
35: tree exp;
36: rtx target;
37: enum machine_mode tmode;
38: enum expand_modifier modifier;
39: {
40: tree type = TREE_TYPE (exp);
41: register enum machine_mode mode = TYPE_MODE (type);
42: register enum tree_code code = TREE_CODE (exp);
43: rtx original_target = target;
44: int ignore = target == const0_rtx;
45:
46: if (ignore) target = 0, original_target = 0;
47:
48: /* No sense saving up arithmetic to be done
49: if it's all in the wrong mode to form part of an address.
50: And force_operand won't know whether to sign-extend or zero-extend. */
51:
52: if (mode != Pmode && modifier == EXPAND_SUM)
53: modifier = EXPAND_NORMAL;
54:
55: switch (code)
56: {
57: case NEW_EXPR:
58: {
59: /* Something needs to be initialized, but we didn't know
60: where that thing was when building the tree. For example,
61: it could be the return value of a function, or a parameter
62: to a function which lays down in the stack, or a temporary
63: variable which must be passed by reference.
64:
65: Cleanups are handled in a language-specific way: they
66: might be run by the called function (true in GNU C++
67: for parameters with cleanups), or they might be
68: run by the caller, after the call (true in GNU C++
69: for other cleanup needs). */
70:
71: tree func = TREE_OPERAND (exp, 0);
72: tree args = TREE_OPERAND (exp, 1);
73: tree type = TREE_TYPE (exp), slot;
74: tree fn_type = TREE_TYPE (TREE_TYPE (func));
75: tree return_type = TREE_TYPE (fn_type);
76: rtx call_target, return_target;
77:
78: /* The expression `init' wants to initialize what
79: `target' represents. SLOT holds the slot for TARGET. */
80: slot = TREE_OPERAND (exp, 2);
81:
82: if (target == 0)
83: {
84: /* Should always be called with a target in BLKmode case. */
1.1.1.4 ! root 85: my_friendly_assert (mode != BLKmode, 205);
! 86: my_friendly_assert (DECL_RTL (slot) != 0, 206);
1.1 root 87:
88: target = gen_reg_rtx (mode);
89: }
90:
91: /* The target the initializer will initialize (CALL_TARGET)
92: must now be directed to initialize the target we are
93: supposed to initialize (TARGET). The semantics for
94: choosing what CALL_TARGET is is language-specific,
95: as is building the call which will perform the
96: initialization. It is left here to show the choices that
97: exist for C++. */
98:
99: if (TREE_CODE (func) == ADDR_EXPR
100: && TREE_CODE (TREE_OPERAND (func, 0)) == FUNCTION_DECL
101: && DECL_CONSTRUCTOR_P (TREE_OPERAND (func, 0)))
102: {
103: type = TYPE_POINTER_TO (type);
104: /* Don't clobber a value that might be part of a default
105: parameter value. */
106: if (TREE_PERMANENT (args))
107: args = tree_cons (0, build1 (ADDR_EXPR, type, slot),
108: TREE_CHAIN (args));
109: else
110: TREE_VALUE (args) = build1 (ADDR_EXPR, type, slot);
111: call_target = 0;
112: }
113: else if (TREE_CODE (return_type) == REFERENCE_TYPE)
114: {
115: type = return_type;
116: call_target = 0;
117: }
118: else
119: {
120: call_target = target;
121: }
122: if (call_target)
123: preserve_temp_slots (call_target);
124: preserve_temp_slots (DECL_RTL (slot));
125: return_target = expand_expr (build (CALL_EXPR, type, func, args, 0), call_target, mode, 0);
126: free_temp_slots ();
127: if (call_target == 0)
128: call_target = return_target;
129: else if (call_target != return_target)
130: {
131: if (GET_MODE (return_target) == BLKmode)
132: emit_block_move (call_target, return_target, expr_size (exp),
133: TYPE_ALIGN (type) / BITS_PER_UNIT);
134: else
135: emit_move_insn (call_target, return_target);
136: }
137:
138: if (TREE_CODE (return_type) == REFERENCE_TYPE)
139: {
140: tree init;
141:
142: if (GET_CODE (call_target) == REG
143: && REGNO (call_target) < FIRST_PSEUDO_REGISTER)
1.1.1.3 root 144: my_friendly_abort (39);
1.1 root 145:
146: type = TREE_TYPE (exp);
147:
148: init = build (RTL_EXPR, return_type, 0, call_target);
1.1.1.2 root 149: /* We got back a reference to the type we want. Now initialize
1.1 root 150: target with that. */
151: expand_aggr_init (slot, init, 0);
152: }
153:
154: if (DECL_RTL (slot) != target)
155: emit_move_insn (DECL_RTL (slot), target);
156: return DECL_RTL (slot);
157: }
158:
159: case OFFSET_REF:
160: {
161: tree base = build_unary_op (ADDR_EXPR, TREE_OPERAND (exp, 0), 0);
162: tree offset = build_unary_op (ADDR_EXPR, TREE_OPERAND (exp, 1), 0);
163: return expand_expr (build (PLUS_EXPR, TREE_TYPE (exp), base, offset),
164: target, tmode, EXPAND_NORMAL);
165: }
166:
167: default:
168: break;
169: }
1.1.1.3 root 170: my_friendly_abort (40);
1.1 root 171: /* NOTREACHED */
172: return NULL;
173: }
174:
175: void
176: init_cplus_expand ()
177: {
178: lang_expand_expr = cplus_expand_expr;
179: }
180:
181: /* If DECL had its rtl moved from where callers expect it
182: to be, fix it up. RESULT is the nominal rtl for the RESULT_DECL,
183: which may be a pseudo instead of a hard register. */
184:
185: void
186: fixup_result_decl (decl, result)
187: tree decl;
188: rtx result;
189: {
190: if (REG_P (result))
191: {
192: if (REGNO (result) >= FIRST_PSEUDO_REGISTER)
193: {
194: rtx real_decl_result;
195:
196: #ifdef FUNCTION_OUTGOING_VALUE
197: real_decl_result
198: = FUNCTION_OUTGOING_VALUE (TREE_TYPE (decl), current_function_decl);
199: #else
200: real_decl_result
201: = FUNCTION_VALUE (TREE_TYPE (decl), current_function_decl);
202: #endif
203: REG_FUNCTION_VALUE_P (real_decl_result) = 1;
204: result = real_decl_result;
205: }
206: emit_move_insn (result, DECL_RTL (decl));
207: emit_insn (gen_rtx (USE, VOIDmode, result));
208: }
209: }
210:
211: /* Return nonzero iff DECL is memory-based. The DECL_RTL of
212: certain const variables might be a CONST_INT, or a REG
213: in some cases. We cannot use `memory_operand' as a test
214: here because on most RISC machines, a variable's address
215: is not, by itself, a legitimate address. */
216: int
217: decl_in_memory_p (decl)
218: tree decl;
219: {
220: return DECL_RTL (decl) != 0 && GET_CODE (DECL_RTL (decl)) == MEM;
221: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.