]>
Commit | Line | Data |
---|---|---|
f2c5f623 BC |
1 | /* This file contains the definitions and documentation for the common |
2 | tree codes used in the GNU C and C++ compilers (see c-common.def | |
3 | for the standard codes). | |
4 | Copyright (C) 2000 Free Software Foundation, Inc. Written by | |
5 | Benjamin Chelf (chelf@codesourcery.com). | |
6 | ||
7 | This file is part of GNU CC. | |
8 | ||
9 | GNU CC is free software; you can redistribute it and/or modify | |
10 | it under the terms of the GNU General Public License as published by | |
11 | the Free Software Foundation; either version 2, or (at your option) | |
12 | any later version. | |
13 | ||
14 | GNU CC is distributed in the hope that it will be useful, | |
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | GNU General Public License for more details. | |
18 | ||
19 | You should have received a copy of the GNU General Public License | |
20 | along with GNU CC; see the file COPYING. If not, write to | |
21 | the Free Software Foundation, 59 Temple Place - Suite 330, | |
22 | Boston, MA 02111-1307, USA. */ | |
23 | ||
24 | #include "config.h" | |
25 | #include "system.h" | |
26 | #include "tree.h" | |
27 | #include "function.h" | |
28 | #include "splay-tree.h" | |
29 | #include "varray.h" | |
30 | #include "c-common.h" | |
31 | #include "except.h" | |
32 | #include "toplev.h" | |
33 | #include "flags.h" | |
34 | #include "ggc.h" | |
35 | #include "rtl.h" | |
36 | #include "output.h" | |
37 | #include "timevar.h" | |
38 | ||
54f7877c MM |
39 | /* If non-NULL, the address of a language-specific function for |
40 | expanding statements. */ | |
41 | void (*lang_expand_stmt) PARAMS ((tree)); | |
42 | ||
ae499cce MM |
43 | static tree prune_unused_decls PARAMS ((tree *, int *, void *)); |
44 | ||
45 | /* Create an empty statement tree rooted at T. */ | |
46 | ||
47 | void | |
48 | begin_stmt_tree (t) | |
49 | tree *t; | |
50 | { | |
51 | /* We create a trivial EXPR_STMT so that last_tree is never NULL in | |
52 | what follows. We remove the extraneous statement in | |
53 | finish_stmt_tree. */ | |
54 | *t = build_nt (EXPR_STMT, void_zero_node); | |
55 | last_tree = *t; | |
56 | last_expr_type = NULL_TREE; | |
57 | } | |
58 | ||
59 | /* T is a statement. Add it to the statement-tree. */ | |
60 | ||
61 | void | |
62 | add_stmt (t) | |
63 | tree t; | |
64 | { | |
65 | /* Add T to the statement-tree. */ | |
66 | TREE_CHAIN (last_tree) = t; | |
67 | last_tree = t; | |
68 | /* When we expand a statement-tree, we must know whether or not the | |
69 | statements are full-expresions. We record that fact here. */ | |
70 | STMT_IS_FULL_EXPR_P (last_tree) = stmts_are_full_exprs_p (); | |
71 | } | |
72 | ||
73 | /* Remove declarations of internal variables that are not used from a | |
74 | stmt tree. To qualify, the variable must have a name and must have | |
75 | a zero DECL_SOURCE_LINE. We tried to remove all variables for | |
76 | which TREE_USED was false, but it turns out that there's tons of | |
77 | variables for which TREE_USED is false but that are still in fact | |
78 | used. */ | |
79 | ||
80 | static tree | |
81 | prune_unused_decls (tp, walk_subtrees, data) | |
82 | tree *tp; | |
83 | int *walk_subtrees ATTRIBUTE_UNUSED; | |
84 | void *data ATTRIBUTE_UNUSED; | |
85 | { | |
86 | tree t = *tp; | |
87 | ||
88 | if (t == NULL_TREE) | |
89 | { | |
90 | *walk_subtrees = 0; | |
91 | return NULL_TREE; | |
92 | } | |
93 | ||
94 | if (TREE_CODE (t) == DECL_STMT) | |
95 | { | |
96 | tree d = DECL_STMT_DECL (t); | |
97 | if (!TREE_USED (d) && DECL_NAME (d) && DECL_SOURCE_LINE (d) == 0) | |
98 | { | |
99 | *tp = TREE_CHAIN (t); | |
100 | /* Recurse on the new value of tp, otherwise we will skip | |
101 | the next statement. */ | |
102 | return prune_unused_decls (tp, walk_subtrees, data); | |
103 | } | |
104 | } | |
105 | else if (TREE_CODE (t) == SCOPE_STMT) | |
106 | { | |
107 | /* Remove all unused decls from the BLOCK of this SCOPE_STMT. */ | |
108 | tree block = SCOPE_STMT_BLOCK (t); | |
109 | ||
110 | if (block) | |
111 | { | |
112 | tree *vp; | |
113 | ||
114 | for (vp = &BLOCK_VARS (block); *vp; ) | |
115 | { | |
116 | tree v = *vp; | |
117 | if (! TREE_USED (v) && DECL_NAME (v) && DECL_SOURCE_LINE (v) == 0) | |
118 | *vp = TREE_CHAIN (v); /* drop */ | |
119 | else | |
120 | vp = &TREE_CHAIN (v); /* advance */ | |
121 | } | |
122 | /* If there are now no variables, the entire BLOCK can be dropped. | |
123 | (This causes SCOPE_NULLIFIED_P (t) to be true.) */ | |
124 | if (BLOCK_VARS (block) == NULL_TREE) | |
125 | SCOPE_STMT_BLOCK (t) = NULL_TREE; | |
126 | } | |
127 | } | |
128 | return NULL_TREE; | |
129 | } | |
130 | ||
131 | /* Finish the statement tree rooted at T. */ | |
132 | ||
133 | void | |
134 | finish_stmt_tree (t) | |
135 | tree *t; | |
136 | { | |
137 | tree stmt; | |
138 | ||
139 | /* Remove the fake extra statement added in begin_stmt_tree. */ | |
140 | stmt = TREE_CHAIN (*t); | |
141 | *t = stmt; | |
142 | last_tree = NULL_TREE; | |
143 | ||
144 | /* Remove unused decls from the stmt tree. */ | |
145 | walk_stmt_tree (t, prune_unused_decls, NULL); | |
146 | ||
147 | if (cfun) | |
148 | { | |
149 | /* The line-number recorded in the outermost statement in a function | |
150 | is the line number of the end of the function. */ | |
151 | STMT_LINENO (stmt) = lineno; | |
152 | STMT_LINENO_FOR_FN_P (stmt) = 1; | |
153 | } | |
154 | } | |
155 | ||
0dfdeca6 BC |
156 | /* Build a generic statement based on the given type of node and |
157 | arguments. Similar to `build_nt', except that we set | |
158 | TREE_COMPLEXITY to be the current line number. */ | |
159 | ||
160 | tree | |
161 | build_stmt VPARAMS ((enum tree_code code, ...)) | |
162 | { | |
163 | #ifndef ANSI_PROTOTYPES | |
164 | enum tree_code code; | |
165 | #endif | |
166 | va_list p; | |
167 | register tree t; | |
168 | register int length; | |
169 | register int i; | |
170 | ||
171 | VA_START (p, code); | |
172 | ||
173 | #ifndef ANSI_PROTOTYPES | |
174 | code = va_arg (p, enum tree_code); | |
175 | #endif | |
176 | ||
177 | t = make_node (code); | |
178 | length = TREE_CODE_LENGTH (code); | |
179 | TREE_COMPLEXITY (t) = lineno; | |
180 | ||
181 | for (i = 0; i < length; i++) | |
182 | TREE_OPERAND (t, i) = va_arg (p, tree); | |
183 | ||
184 | va_end (p); | |
185 | return t; | |
186 | } | |
187 | ||
f2c5f623 BC |
188 | /* Some statements, like for-statements or if-statements, require a |
189 | condition. This condition can be a declaration. If T is such a | |
190 | declaration it is processed, and an expression appropriate to use | |
191 | as the condition is returned. Otherwise, T itself is returned. */ | |
192 | ||
193 | tree | |
194 | expand_cond (t) | |
195 | tree t; | |
196 | { | |
197 | if (t && TREE_CODE (t) == TREE_LIST) | |
198 | { | |
199 | expand_stmt (TREE_PURPOSE (t)); | |
200 | return TREE_VALUE (t); | |
201 | } | |
202 | else | |
203 | return t; | |
204 | } | |
205 | ||
206 | /* Create RTL for the local static variable DECL. */ | |
207 | ||
208 | void | |
209 | make_rtl_for_local_static (decl) | |
210 | tree decl; | |
211 | { | |
212 | const char *asmspec = NULL; | |
213 | ||
214 | /* If we inlined this variable, we could see it's declaration | |
215 | again. */ | |
95ee998c | 216 | if (TREE_ASM_WRITTEN (decl)) |
f2c5f623 BC |
217 | return; |
218 | ||
219 | if (DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl)) | |
220 | { | |
221 | /* The only way this situaton can occur is if the | |
222 | user specified a name for this DECL using the | |
223 | `attribute' syntax. */ | |
224 | asmspec = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); | |
225 | DECL_ASSEMBLER_NAME (decl) = DECL_NAME (decl); | |
226 | } | |
227 | ||
228 | rest_of_decl_compilation (decl, asmspec, /*top_level=*/0, /*at_end=*/0); | |
229 | } | |
230 | ||
231 | /* Let the back-end know about DECL. */ | |
232 | ||
233 | void | |
234 | emit_local_var (decl) | |
235 | tree decl; | |
236 | { | |
237 | /* Create RTL for this variable. */ | |
238 | if (!DECL_RTL (decl)) | |
239 | { | |
240 | if (DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl)) | |
241 | /* The user must have specified an assembler name for this | |
242 | variable. Set that up now. */ | |
243 | rest_of_decl_compilation | |
244 | (decl, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), | |
245 | /*top_level=*/0, /*at_end=*/0); | |
246 | else | |
247 | expand_decl (decl); | |
248 | } | |
249 | ||
250 | /* Actually do the initialization. */ | |
251 | if (stmts_are_full_exprs_p ()) | |
252 | expand_start_target_temps (); | |
253 | ||
254 | expand_decl_init (decl); | |
255 | ||
256 | if (stmts_are_full_exprs_p ()) | |
257 | expand_end_target_temps (); | |
258 | } | |
259 | ||
260 | /* Helper for generating the RTL at the beginning of a scope. */ | |
261 | ||
262 | void | |
263 | genrtl_do_pushlevel () | |
264 | { | |
265 | emit_line_note (input_filename, lineno); | |
266 | clear_last_expr (); | |
267 | } | |
268 | ||
269 | /* Helper for generating the RTL. */ | |
270 | ||
271 | void | |
272 | genrtl_clear_out_block () | |
273 | { | |
274 | /* If COND wasn't a declaration, clear out the | |
275 | block we made for it and start a new one here so the | |
276 | optimization in expand_end_loop will work. */ | |
277 | if (getdecls () == NULL_TREE) | |
278 | genrtl_do_pushlevel (); | |
279 | } | |
280 | ||
281 | /* Generate the RTL for DESTINATION, which is a GOTO_STMT. */ | |
282 | ||
283 | void | |
284 | genrtl_goto_stmt (destination) | |
285 | tree destination; | |
286 | { | |
287 | if (TREE_CODE (destination) == IDENTIFIER_NODE) | |
288 | abort (); | |
289 | ||
290 | /* We warn about unused labels with -Wunused. That means we have to | |
291 | mark the used labels as used. */ | |
292 | if (TREE_CODE (destination) == LABEL_DECL) | |
293 | TREE_USED (destination) = 1; | |
294 | ||
295 | emit_line_note (input_filename, lineno); | |
296 | ||
297 | if (TREE_CODE (destination) == LABEL_DECL) | |
298 | { | |
299 | label_rtx (destination); | |
300 | expand_goto (destination); | |
301 | } | |
302 | else | |
303 | expand_computed_goto (destination); | |
304 | } | |
305 | ||
306 | /* Generate the RTL for EXPR, which is an EXPR_STMT. */ | |
307 | ||
308 | void | |
309 | genrtl_expr_stmt (expr) | |
310 | tree expr; | |
311 | { | |
312 | if (expr != NULL_TREE) | |
313 | { | |
314 | emit_line_note (input_filename, lineno); | |
315 | ||
316 | if (stmts_are_full_exprs_p ()) | |
317 | expand_start_target_temps (); | |
318 | ||
319 | lang_expand_expr_stmt (expr); | |
320 | ||
321 | if (stmts_are_full_exprs_p ()) | |
322 | expand_end_target_temps (); | |
323 | } | |
324 | } | |
325 | ||
326 | /* Generate the RTL for T, which is a DECL_STMT. */ | |
327 | ||
328 | void | |
329 | genrtl_decl_stmt (t) | |
330 | tree t; | |
331 | { | |
332 | tree decl; | |
333 | emit_line_note (input_filename, lineno); | |
334 | decl = DECL_STMT_DECL (t); | |
335 | /* If this is a declaration for an automatic local | |
336 | variable, initialize it. Note that we might also see a | |
337 | declaration for a namespace-scope object (declared with | |
338 | `extern'). We don't have to handle the initialization | |
339 | of those objects here; they can only be declarations, | |
340 | rather than definitions. */ | |
341 | if (TREE_CODE (decl) == VAR_DECL | |
342 | && !TREE_STATIC (decl) | |
343 | && !DECL_EXTERNAL (decl)) | |
344 | { | |
345 | /* Let the back-end know about this variable. */ | |
346 | if (!anon_aggr_type_p (TREE_TYPE (decl))) | |
347 | emit_local_var (decl); | |
348 | else | |
349 | expand_anon_union_decl (decl, NULL_TREE, | |
350 | DECL_ANON_UNION_ELEMS (decl)); | |
351 | } | |
352 | else if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl)) | |
353 | { | |
354 | if (DECL_ARTIFICIAL (decl) && ! TREE_USED (decl)) | |
355 | /* Do not emit unused decls. This is not just an | |
356 | optimization. We really do not want to emit | |
357 | __PRETTY_FUNCTION__ etc, if they're never used. */ | |
358 | DECL_IGNORED_P (decl) = 1; | |
359 | else | |
360 | make_rtl_for_local_static (decl); | |
361 | } | |
362 | } | |
363 | ||
364 | /* Generate the RTL for T, which is an IF_STMT. */ | |
365 | ||
366 | void | |
367 | genrtl_if_stmt (t) | |
368 | tree t; | |
369 | { | |
370 | tree cond; | |
371 | genrtl_do_pushlevel (); | |
372 | cond = expand_cond (IF_COND (t)); | |
373 | emit_line_note (input_filename, lineno); | |
374 | expand_start_cond (cond, 0); | |
375 | if (THEN_CLAUSE (t)) | |
376 | expand_stmt (THEN_CLAUSE (t)); | |
377 | if (ELSE_CLAUSE (t)) | |
378 | { | |
379 | expand_start_else (); | |
380 | expand_stmt (ELSE_CLAUSE (t)); | |
381 | } | |
382 | expand_end_cond (); | |
383 | } | |
384 | ||
385 | /* Generate the RTL for T, which is a WHILE_STMT. */ | |
386 | ||
387 | void | |
388 | genrtl_while_stmt (t) | |
389 | tree t; | |
390 | { | |
391 | tree cond; | |
392 | emit_nop (); | |
393 | emit_line_note (input_filename, lineno); | |
394 | expand_start_loop (1); | |
395 | genrtl_do_pushlevel (); | |
396 | ||
397 | cond = expand_cond (WHILE_COND (t)); | |
398 | emit_line_note (input_filename, lineno); | |
399 | expand_exit_loop_if_false (0, cond); | |
400 | genrtl_clear_out_block (); | |
401 | ||
402 | expand_stmt (WHILE_BODY (t)); | |
403 | ||
404 | expand_end_loop (); | |
405 | } | |
406 | ||
407 | /* Generate the RTL for T, which is a DO_STMT. */ | |
408 | ||
409 | void | |
410 | genrtl_do_stmt (t) | |
411 | tree t; | |
412 | { | |
413 | tree cond; | |
414 | emit_nop (); | |
415 | emit_line_note (input_filename, lineno); | |
416 | expand_start_loop_continue_elsewhere (1); | |
417 | ||
418 | expand_stmt (DO_BODY (t)); | |
419 | ||
420 | expand_loop_continue_here (); | |
421 | ||
422 | cond = expand_cond (DO_COND (t)); | |
423 | emit_line_note (input_filename, lineno); | |
424 | expand_exit_loop_if_false (0, cond); | |
425 | expand_end_loop (); | |
426 | } | |
427 | ||
0dfdeca6 BC |
428 | /* Build the node for a return statement and return it. */ |
429 | ||
430 | tree | |
431 | build_return_stmt (expr) | |
432 | tree expr; | |
433 | { | |
434 | return (build_stmt (RETURN_STMT, expr)); | |
435 | } | |
436 | ||
f2c5f623 BC |
437 | /* Generate the RTL for EXPR, which is a RETURN_STMT. */ |
438 | ||
439 | void | |
440 | genrtl_return_stmt (expr) | |
441 | tree expr; | |
442 | { | |
443 | emit_line_note (input_filename, lineno); | |
444 | c_expand_return (expr); | |
445 | } | |
446 | ||
447 | /* Generate the RTL for T, which is a FOR_STMT. */ | |
448 | ||
449 | void | |
450 | genrtl_for_stmt (t) | |
451 | tree t; | |
452 | { | |
453 | tree tmp; | |
454 | tree cond; | |
455 | if (NEW_FOR_SCOPE_P (t)) | |
456 | genrtl_do_pushlevel (); | |
457 | ||
458 | expand_stmt (FOR_INIT_STMT (t)); | |
459 | ||
460 | emit_nop (); | |
461 | emit_line_note (input_filename, lineno); | |
462 | expand_start_loop_continue_elsewhere (1); | |
463 | genrtl_do_pushlevel (); | |
464 | cond = expand_cond (FOR_COND (t)); | |
465 | emit_line_note (input_filename, lineno); | |
466 | if (cond) | |
467 | expand_exit_loop_if_false (0, cond); | |
468 | genrtl_clear_out_block (); | |
469 | tmp = FOR_EXPR (t); | |
470 | ||
471 | expand_stmt (FOR_BODY (t)); | |
472 | ||
473 | emit_line_note (input_filename, lineno); | |
474 | expand_loop_continue_here (); | |
475 | if (tmp) | |
476 | genrtl_expr_stmt (tmp); | |
477 | expand_end_loop (); | |
478 | } | |
479 | ||
0dfdeca6 BC |
480 | /* Build a break statement node and return it. */ |
481 | ||
482 | tree | |
483 | build_break_stmt () | |
484 | { | |
485 | return (build_stmt (BREAK_STMT)); | |
486 | } | |
487 | ||
f2c5f623 BC |
488 | /* Generate the RTL for a BREAK_STMT. */ |
489 | ||
490 | void | |
491 | genrtl_break_stmt () | |
492 | { | |
493 | emit_line_note (input_filename, lineno); | |
494 | if ( ! expand_exit_something ()) | |
495 | error ("break statement not within loop or switch"); | |
496 | } | |
497 | ||
0dfdeca6 BC |
498 | /* Build a continue statement node and return it. */ |
499 | ||
500 | tree | |
501 | build_continue_stmt () | |
502 | { | |
503 | return (build_stmt (CONTINUE_STMT)); | |
504 | } | |
505 | ||
f2c5f623 BC |
506 | /* Generate the RTL for a CONTINUE_STMT. */ |
507 | ||
508 | void | |
509 | genrtl_continue_stmt () | |
510 | { | |
511 | emit_line_note (input_filename, lineno); | |
512 | if (! expand_continue_loop (0)) | |
513 | error ("continue statement not within a loop"); | |
514 | } | |
515 | ||
516 | /* Generate the RTL for T, which is a SCOPE_STMT. */ | |
517 | ||
518 | void | |
519 | genrtl_scope_stmt (t) | |
520 | tree t; | |
521 | { | |
522 | if (!SCOPE_NO_CLEANUPS_P (t)) | |
523 | { | |
524 | if (SCOPE_BEGIN_P (t)) | |
525 | expand_start_bindings_and_block (2 * SCOPE_NULLIFIED_P (t), | |
526 | SCOPE_STMT_BLOCK (t)); | |
527 | else if (SCOPE_END_P (t)) | |
528 | expand_end_bindings (NULL_TREE, !SCOPE_NULLIFIED_P (t), 0); | |
529 | } | |
530 | else if (!SCOPE_NULLIFIED_P (t)) | |
531 | { | |
532 | rtx note = emit_note (NULL, | |
533 | (SCOPE_BEGIN_P (t) | |
534 | ? NOTE_INSN_BLOCK_BEG | |
535 | : NOTE_INSN_BLOCK_END)); | |
536 | NOTE_BLOCK (note) = SCOPE_STMT_BLOCK (t); | |
537 | } | |
538 | } | |
539 | ||
540 | /* Generate the RTL for T, which is a SWITCH_STMT. */ | |
541 | ||
542 | void | |
543 | genrtl_switch_stmt (t) | |
544 | tree t; | |
545 | { | |
546 | tree cond; | |
547 | genrtl_do_pushlevel (); | |
548 | ||
549 | cond = expand_cond (SWITCH_COND (t)); | |
550 | if (cond != error_mark_node) | |
551 | { | |
552 | emit_line_note (input_filename, lineno); | |
553 | c_expand_start_case (cond); | |
554 | } | |
555 | else | |
556 | /* The code is in error, but we don't want expand_end_case to | |
557 | crash. */ | |
558 | c_expand_start_case (boolean_false_node); | |
559 | ||
560 | expand_stmt (SWITCH_BODY (t)); | |
561 | ||
562 | expand_end_case (cond); | |
563 | } | |
564 | ||
0dfdeca6 BC |
565 | /* Create a CASE_LABEL tree node and return it. */ |
566 | ||
567 | tree | |
568 | build_case_label (low_value, high_value) | |
569 | tree low_value; | |
570 | tree high_value; | |
571 | { | |
572 | return build_stmt (CASE_LABEL, low_value, high_value); | |
573 | } | |
574 | ||
575 | ||
f2c5f623 BC |
576 | /* Generate the RTL for a CASE_LABEL. */ |
577 | ||
578 | void | |
579 | genrtl_case_label (low_value, high_value) | |
580 | tree low_value; | |
581 | tree high_value; | |
582 | { | |
583 | do_case (low_value, high_value); | |
584 | } | |
585 | ||
4cf88f57 | 586 | /* Generate the RTL for T, which is a COMPOUND_STMT. */ |
f2c5f623 | 587 | |
4cf88f57 BC |
588 | void |
589 | genrtl_compound_stmt (t) | |
590 | tree t; | |
f2c5f623 BC |
591 | { |
592 | /* If this is the outermost block of the function, declare the | |
593 | variables __FUNCTION__, __PRETTY_FUNCTION__, and so forth. */ | |
594 | if (cfun | |
595 | && !current_function_name_declared () | |
4cf88f57 | 596 | && !COMPOUND_STMT_NO_SCOPE (t)) |
f2c5f623 BC |
597 | { |
598 | set_current_function_name_declared (1); | |
599 | declare_function_name (); | |
4cf88f57 | 600 | } |
f2c5f623 | 601 | |
f2c5f623 | 602 | expand_stmt (COMPOUND_BODY (t)); |
f2c5f623 BC |
603 | } |
604 | ||
605 | /* Generate the RTL for an ASM_STMT. */ | |
606 | ||
607 | void | |
608 | genrtl_asm_stmt (cv_qualifier, string, output_operands, | |
609 | input_operands, clobbers) | |
610 | tree cv_qualifier; | |
611 | tree string; | |
612 | tree output_operands; | |
613 | tree input_operands; | |
614 | tree clobbers; | |
615 | { | |
616 | if (TREE_CHAIN (string)) | |
617 | string = combine_strings (string); | |
618 | ||
619 | if (cv_qualifier != NULL_TREE | |
620 | && cv_qualifier != ridpointers[(int) RID_VOLATILE]) | |
621 | { | |
622 | warning ("%s qualifier ignored on asm", | |
623 | IDENTIFIER_POINTER (cv_qualifier)); | |
624 | cv_qualifier = NULL_TREE; | |
625 | } | |
626 | ||
627 | emit_line_note (input_filename, lineno); | |
628 | if (output_operands != NULL_TREE || input_operands != NULL_TREE | |
629 | || clobbers != NULL_TREE) | |
630 | c_expand_asm_operands (string, output_operands, | |
631 | input_operands, | |
632 | clobbers, | |
633 | cv_qualifier != NULL_TREE, | |
634 | input_filename, lineno); | |
635 | else | |
636 | expand_asm (string); | |
637 | } | |
638 | ||
639 | /* Generate the RTL for a DECL_CLEANUP. */ | |
640 | ||
641 | void | |
642 | genrtl_decl_cleanup (decl, cleanup) | |
643 | tree decl; | |
644 | tree cleanup; | |
645 | { | |
646 | if (!decl || (DECL_SIZE (decl) && TREE_TYPE (decl) != error_mark_node)) | |
647 | expand_decl_cleanup (decl, cleanup); | |
648 | } | |
649 | ||
54f7877c MM |
650 | /* We're about to expand T, a statement. Set up appropriate context |
651 | for the substitution. */ | |
652 | ||
653 | void | |
654 | prep_stmt (t) | |
655 | tree t; | |
656 | { | |
657 | if (!STMT_LINENO_FOR_FN_P (t)) | |
658 | lineno = STMT_LINENO (t); | |
659 | current_stmt_tree ()->stmts_are_full_exprs_p = STMT_IS_FULL_EXPR_P (t); | |
660 | } | |
661 | ||
4cf88f57 BC |
662 | /* Generate the RTL for the statement T, its substatements, and any |
663 | other statements at its nesting level. */ | |
664 | ||
54f7877c | 665 | void |
f2c5f623 BC |
666 | expand_stmt (t) |
667 | tree t; | |
668 | { | |
54f7877c MM |
669 | while (t && t != error_mark_node) |
670 | { | |
671 | int saved_stmts_are_full_exprs_p; | |
672 | ||
673 | /* Set up context appropriately for handling this statement. */ | |
674 | saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p (); | |
675 | prep_stmt (t); | |
676 | ||
677 | switch (TREE_CODE (t)) | |
678 | { | |
679 | case RETURN_STMT: | |
680 | genrtl_return_stmt (RETURN_EXPR (t)); | |
681 | break; | |
682 | ||
683 | case EXPR_STMT: | |
684 | genrtl_expr_stmt (EXPR_STMT_EXPR (t)); | |
685 | break; | |
686 | ||
687 | case DECL_STMT: | |
688 | genrtl_decl_stmt (t); | |
689 | break; | |
690 | ||
691 | case FOR_STMT: | |
692 | genrtl_for_stmt (t); | |
693 | break; | |
694 | ||
695 | case WHILE_STMT: | |
696 | genrtl_while_stmt (t); | |
697 | break; | |
698 | ||
699 | case DO_STMT: | |
700 | genrtl_do_stmt (t); | |
701 | break; | |
702 | ||
703 | case IF_STMT: | |
704 | genrtl_if_stmt (t); | |
705 | break; | |
706 | ||
707 | case COMPOUND_STMT: | |
708 | genrtl_compound_stmt (t); | |
709 | break; | |
710 | ||
711 | case BREAK_STMT: | |
712 | genrtl_break_stmt (); | |
713 | break; | |
714 | ||
715 | case CONTINUE_STMT: | |
716 | genrtl_continue_stmt (); | |
717 | break; | |
718 | ||
719 | case SWITCH_STMT: | |
720 | genrtl_switch_stmt (t); | |
721 | break; | |
722 | ||
723 | case CASE_LABEL: | |
724 | genrtl_case_label (CASE_LOW (t), CASE_HIGH (t)); | |
725 | break; | |
726 | ||
727 | case LABEL_STMT: | |
728 | expand_label (LABEL_STMT_LABEL (t)); | |
729 | break; | |
730 | ||
731 | case GOTO_STMT: | |
732 | genrtl_goto_stmt (GOTO_DESTINATION (t)); | |
733 | break; | |
734 | ||
735 | case ASM_STMT: | |
736 | genrtl_asm_stmt (ASM_CV_QUAL (t), ASM_STRING (t), | |
737 | ASM_OUTPUTS (t), ASM_INPUTS (t), ASM_CLOBBERS (t)); | |
738 | break; | |
739 | ||
740 | default: | |
741 | if (lang_expand_stmt) | |
742 | (*lang_expand_stmt) (t); | |
743 | else | |
744 | abort (); | |
745 | break; | |
746 | } | |
747 | ||
748 | /* Restore saved state. */ | |
749 | current_stmt_tree ()->stmts_are_full_exprs_p = | |
750 | saved_stmts_are_full_exprs_p; | |
751 | ||
752 | /* Go on to the next statement in this scope. */ | |
753 | t = TREE_CHAIN (t); | |
754 | } | |
f2c5f623 | 755 | } |
4cf88f57 | 756 |