]>
Commit | Line | Data |
---|---|---|
8d08fdba MS |
1 | /* Convert language-specific tree expression to rtl instructions, |
2 | for GNU compiler. | |
d6a8bdff JL |
3 | Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, |
4 | 2000 Free Software Foundation, Inc. | |
8d08fdba MS |
5 | |
6 | This file is part of GNU CC. | |
7 | ||
8 | GNU CC is free software; you can redistribute it and/or modify | |
9 | it under the terms of the GNU General Public License as published by | |
10 | the Free Software Foundation; either version 2, or (at your option) | |
11 | any later version. | |
12 | ||
13 | GNU CC is distributed in the hope that it will be useful, | |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | GNU General Public License for more details. | |
17 | ||
18 | You should have received a copy of the GNU General Public License | |
19 | along with GNU CC; see the file COPYING. If not, write to | |
e9fa0c7c RK |
20 | the Free Software Foundation, 59 Temple Place - Suite 330, |
21 | Boston, MA 02111-1307, USA. */ | |
8d08fdba MS |
22 | |
23 | ||
24 | #include "config.h" | |
8d052bc7 | 25 | #include "system.h" |
8d08fdba MS |
26 | #include "rtl.h" |
27 | #include "tree.h" | |
28 | #include "flags.h" | |
29 | #include "expr.h" | |
30 | #include "cp-tree.h" | |
54f92bfb | 31 | #include "toplev.h" |
59ccf49d | 32 | #include "except.h" |
b1474bb7 | 33 | #include "tm_p.h" |
8d08fdba | 34 | |
1bbe34be | 35 | #if 0 |
158991b7 KG |
36 | static tree extract_aggr_init PARAMS ((tree, tree)); |
37 | static tree extract_scalar_init PARAMS ((tree, tree)); | |
1bbe34be | 38 | #endif |
158991b7 | 39 | static rtx cplus_expand_expr PARAMS ((tree, rtx, enum machine_mode, |
9f617717 | 40 | enum expand_modifier)); |
49c249e1 | 41 | |
87533b37 MM |
42 | /* Hook used by output_constant to expand language-specific |
43 | constants. */ | |
44 | ||
b928a651 | 45 | tree |
87533b37 MM |
46 | cplus_expand_constant (cst) |
47 | tree cst; | |
48 | { | |
49 | switch (TREE_CODE (cst)) | |
50 | { | |
51 | case PTRMEM_CST: | |
52 | { | |
53 | tree type = TREE_TYPE (cst); | |
54 | tree member; | |
55 | tree offset; | |
56 | ||
57 | /* Find the member. */ | |
58 | member = PTRMEM_CST_MEMBER (cst); | |
59 | ||
60 | if (TREE_CODE (member) == FIELD_DECL) | |
61 | { | |
62 | /* Find the offset for the field. */ | |
63 | offset = convert (sizetype, | |
64 | size_binop (EASY_DIV_EXPR, | |
665f2503 | 65 | bit_position (member), |
fed3cef0 | 66 | bitsize_int (BITS_PER_UNIT))); |
87533b37 MM |
67 | |
68 | /* We offset all pointer to data members by 1 so that we | |
69 | can distinguish between a null pointer to data member | |
70 | and the first data member of a structure. */ | |
fed3cef0 | 71 | offset = size_binop (PLUS_EXPR, offset, size_one_node); |
87533b37 MM |
72 | cst = cp_convert (type, offset); |
73 | } | |
74 | else | |
75 | { | |
76 | tree delta; | |
77 | tree idx; | |
78 | tree pfn; | |
79 | tree delta2; | |
80 | ||
81 | expand_ptrmemfunc_cst (cst, &delta, &idx, &pfn, &delta2); | |
82 | ||
83 | cst = build_ptrmemfunc1 (type, delta, idx, | |
84 | pfn, delta2); | |
85 | } | |
86 | } | |
87 | break; | |
88 | ||
89 | default: | |
90 | /* There's nothing to do. */ | |
91 | break; | |
92 | } | |
93 | ||
94 | return cst; | |
95 | } | |
96 | ||
8d08fdba MS |
97 | /* Hook used by expand_expr to expand language-specific tree codes. */ |
98 | ||
9f617717 | 99 | static rtx |
8d08fdba MS |
100 | cplus_expand_expr (exp, target, tmode, modifier) |
101 | tree exp; | |
102 | rtx target; | |
103 | enum machine_mode tmode; | |
104 | enum expand_modifier modifier; | |
105 | { | |
106 | tree type = TREE_TYPE (exp); | |
107 | register enum machine_mode mode = TYPE_MODE (type); | |
108 | register enum tree_code code = TREE_CODE (exp); | |
8d08fdba MS |
109 | int ignore = target == const0_rtx; |
110 | ||
111 | if (ignore) | |
de22184b | 112 | target = 0; |
8d08fdba MS |
113 | |
114 | /* No sense saving up arithmetic to be done | |
115 | if it's all in the wrong mode to form part of an address. | |
116 | And force_operand won't know whether to sign-extend or zero-extend. */ | |
117 | ||
118 | if (mode != Pmode && modifier == EXPAND_SUM) | |
119 | modifier = EXPAND_NORMAL; | |
120 | ||
121 | switch (code) | |
122 | { | |
61a127b3 | 123 | case PTRMEM_CST: |
87533b37 MM |
124 | return expand_expr (cplus_expand_constant (exp), |
125 | target, tmode, modifier); | |
61a127b3 | 126 | |
8d08fdba MS |
127 | case OFFSET_REF: |
128 | { | |
8d08fdba MS |
129 | return expand_expr (default_conversion (resolve_offset_ref (exp)), |
130 | target, tmode, EXPAND_NORMAL); | |
8d08fdba MS |
131 | } |
132 | ||
8926095f | 133 | case THUNK_DECL: |
70ae3201 | 134 | my_friendly_assert (DECL_RTL (exp) != NULL_RTX, 20000115); |
8926095f MS |
135 | return DECL_RTL (exp); |
136 | ||
8d2733ca | 137 | case THROW_EXPR: |
59ccf49d MM |
138 | expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0); |
139 | expand_internal_throw (); | |
8d2733ca MS |
140 | return NULL; |
141 | ||
5f7cbe4e MM |
142 | case EMPTY_CLASS_EXPR: |
143 | /* We don't need to generate any code for an empty class. */ | |
144 | return const0_rtx; | |
145 | ||
558475f0 MM |
146 | case STMT_EXPR: |
147 | { | |
971cbc14 | 148 | tree rtl_expr = expand_start_stmt_expr (); |
447cfcb9 | 149 | expand_stmt (STMT_EXPR_STMT (exp)); |
971cbc14 | 150 | expand_end_stmt_expr (rtl_expr); |
558475f0 MM |
151 | return expand_expr (rtl_expr, target, tmode, modifier); |
152 | } | |
153 | break; | |
154 | ||
8d08fdba MS |
155 | default: |
156 | break; | |
157 | } | |
158 | my_friendly_abort (40); | |
159 | /* NOTREACHED */ | |
160 | return NULL; | |
161 | } | |
162 | ||
163 | void | |
164 | init_cplus_expand () | |
165 | { | |
166 | lang_expand_expr = cplus_expand_expr; | |
87533b37 | 167 | lang_expand_constant = cplus_expand_constant; |
8d08fdba MS |
168 | } |
169 | ||
170 | /* If DECL had its rtl moved from where callers expect it | |
171 | to be, fix it up. RESULT is the nominal rtl for the RESULT_DECL, | |
172 | which may be a pseudo instead of a hard register. */ | |
173 | ||
174 | void | |
175 | fixup_result_decl (decl, result) | |
176 | tree decl; | |
177 | rtx result; | |
178 | { | |
179 | if (REG_P (result)) | |
180 | { | |
181 | if (REGNO (result) >= FIRST_PSEUDO_REGISTER) | |
182 | { | |
183 | rtx real_decl_result; | |
184 | ||
185 | #ifdef FUNCTION_OUTGOING_VALUE | |
186 | real_decl_result | |
187 | = FUNCTION_OUTGOING_VALUE (TREE_TYPE (decl), current_function_decl); | |
188 | #else | |
189 | real_decl_result | |
190 | = FUNCTION_VALUE (TREE_TYPE (decl), current_function_decl); | |
191 | #endif | |
192 | REG_FUNCTION_VALUE_P (real_decl_result) = 1; | |
193 | result = real_decl_result; | |
194 | } | |
28cbf42c | 195 | store_expr (decl, result, 0); |
8d08fdba MS |
196 | emit_insn (gen_rtx (USE, VOIDmode, result)); |
197 | } | |
198 | } | |
199 | ||
994ac65b | 200 | #if 0 |
28cbf42c MS |
201 | /* Expand this initialization inline and see if it's simple enough that |
202 | it can be done at compile-time. */ | |
203 | ||
204 | static tree | |
205 | extract_aggr_init (decl, init) | |
206 | tree decl, init; | |
207 | { | |
208 | return 0; | |
209 | } | |
210 | ||
211 | static tree | |
212 | extract_scalar_init (decl, init) | |
213 | tree decl, init; | |
214 | { | |
215 | rtx value, insns, insn; | |
216 | extern struct obstack temporary_obstack; | |
217 | tree t = NULL_TREE; | |
218 | ||
28cbf42c MS |
219 | start_sequence (); |
220 | value = expand_expr (init, NULL_RTX, VOIDmode, 0); | |
221 | insns = get_insns (); | |
222 | end_sequence (); | |
223 | reg_scan (insns, max_reg_num (), 0); | |
224 | jump_optimize (insns, 0, 0, 1); | |
28cbf42c MS |
225 | |
226 | for (insn = insns; insn; insn = NEXT_INSN (insn)) | |
227 | { | |
228 | rtx r, to; | |
229 | ||
230 | if (GET_CODE (insn) == NOTE) | |
231 | continue; | |
232 | else if (GET_CODE (insn) != INSN) | |
233 | return 0; | |
234 | ||
235 | r = PATTERN (insn); | |
236 | if (GET_CODE (r) != SET) | |
237 | return 0; | |
238 | ||
239 | to = XEXP (r, 0); | |
240 | ||
beb53fb8 JM |
241 | if (! (to == value |
242 | || (GET_CODE (to) == SUBREG && XEXP (to, 0) == value))) | |
28cbf42c MS |
243 | return 0; |
244 | ||
245 | r = XEXP (r, 1); | |
246 | ||
247 | switch (GET_CODE (r)) | |
248 | { | |
249 | case CONST_INT: | |
250 | t = build_int_2 (XEXP (r, 0), 0); | |
251 | break; | |
252 | default: | |
253 | return 0; | |
254 | } | |
255 | } | |
256 | ||
257 | return t; | |
258 | } | |
1bbe34be | 259 | #endif |
28cbf42c MS |
260 | |
261 | int | |
262 | extract_init (decl, init) | |
b370501f | 263 | tree decl ATTRIBUTE_UNUSED, init ATTRIBUTE_UNUSED; |
28cbf42c MS |
264 | { |
265 | return 0; | |
266 | ||
9e9ff709 | 267 | #if 0 |
28cbf42c MS |
268 | if (IS_AGGR_TYPE (TREE_TYPE (decl)) |
269 | || TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE) | |
270 | init = extract_aggr_init (decl, init); | |
271 | else | |
272 | init = extract_scalar_init (decl, init); | |
273 | ||
274 | if (init == NULL_TREE) | |
275 | return 0; | |
276 | ||
277 | DECL_INITIAL (decl) = init; | |
278 | return 1; | |
9e9ff709 | 279 | #endif |
28cbf42c | 280 | } |
5566b478 MS |
281 | |
282 | void | |
283 | do_case (start, end) | |
284 | tree start, end; | |
285 | { | |
286 | tree value1 = NULL_TREE, value2 = NULL_TREE, label; | |
287 | ||
ce122a86 MS |
288 | if (start != NULL_TREE && TREE_TYPE (start) != NULL_TREE |
289 | && POINTER_TYPE_P (TREE_TYPE (start))) | |
8251199e | 290 | error ("pointers are not permitted as case values"); |
fc378698 | 291 | |
5566b478 | 292 | if (end && pedantic) |
cb9a3ff8 | 293 | pedwarn ("ISO C++ forbids range expressions in switch statement"); |
5566b478 | 294 | |
5566b478 MS |
295 | if (start) |
296 | value1 = check_cp_case_value (start); | |
297 | if (end) | |
298 | value2 = check_cp_case_value (end); | |
299 | ||
300 | label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); | |
301 | ||
302 | if (value1 != error_mark_node | |
303 | && value2 != error_mark_node) | |
304 | { | |
305 | tree duplicate; | |
306 | int success; | |
307 | ||
308 | if (end) | |
309 | success = pushcase_range (value1, value2, convert_and_check, | |
310 | label, &duplicate); | |
311 | else if (start) | |
312 | success = pushcase (value1, convert_and_check, label, &duplicate); | |
313 | else | |
314 | success = pushcase (NULL_TREE, 0, label, &duplicate); | |
315 | ||
316 | if (success == 1) | |
317 | { | |
318 | if (end) | |
8251199e | 319 | error ("case label not within a switch statement"); |
5566b478 | 320 | else if (start) |
8251199e | 321 | cp_error ("case label `%E' not within a switch statement", start); |
5566b478 | 322 | else |
8251199e | 323 | error ("default label not within a switch statement"); |
5566b478 MS |
324 | } |
325 | else if (success == 2) | |
326 | { | |
327 | if (end) | |
328 | { | |
8251199e JM |
329 | error ("duplicate (or overlapping) case value"); |
330 | cp_error_at ("this is the first entry overlapping that value", | |
5566b478 MS |
331 | duplicate); |
332 | } | |
333 | else if (start) | |
334 | { | |
8251199e JM |
335 | cp_error ("duplicate case value `%E'", start); |
336 | cp_error_at ("previously used here", duplicate); | |
5566b478 MS |
337 | } |
338 | else | |
339 | { | |
8251199e JM |
340 | error ("multiple default labels in one switch"); |
341 | cp_error_at ("this is the first default label", duplicate); | |
5566b478 MS |
342 | } |
343 | } | |
344 | else if (success == 3) | |
8251199e | 345 | warning ("case value out of range"); |
5566b478 | 346 | else if (success == 4) |
8251199e | 347 | warning ("empty range specified"); |
5566b478 MS |
348 | else if (success == 5) |
349 | { | |
350 | if (end) | |
8251199e | 351 | error ("case label within scope of cleanup or variable array"); |
eb448459 | 352 | else if (! start) |
8251199e | 353 | error ("`default' label within scope of cleanup or variable array"); |
5566b478 | 354 | else |
8251199e | 355 | cp_error ("case label `%E' within scope of cleanup or variable array", start); |
5566b478 MS |
356 | } |
357 | } | |
b35d4555 MM |
358 | |
359 | current_function_return_value = NULL_TREE; | |
5566b478 | 360 | } |