c-semantics.c revision 90075
190075Sobrien/* This file contains the definitions and documentation for the common 290075Sobrien tree codes used in the GNU C and C++ compilers (see c-common.def 390075Sobrien for the standard codes). 490075Sobrien Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. 590075Sobrien Written by Benjamin Chelf (chelf@codesourcery.com). 690075Sobrien 790075SobrienThis file is part of GCC. 890075Sobrien 990075SobrienGCC is free software; you can redistribute it and/or modify it under 1090075Sobrienthe terms of the GNU General Public License as published by the Free 1190075SobrienSoftware Foundation; either version 2, or (at your option) any later 1290075Sobrienversion. 1390075Sobrien 1490075SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY 1590075SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or 1690075SobrienFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1790075Sobrienfor more details. 1890075Sobrien 1990075SobrienYou should have received a copy of the GNU General Public License 2090075Sobrienalong with GCC; see the file COPYING. If not, write to the Free 2190075SobrienSoftware Foundation, 59 Temple Place - Suite 330, Boston, MA 2290075Sobrien02111-1307, USA. */ 2390075Sobrien 2490075Sobrien#include "config.h" 2590075Sobrien#include "system.h" 2690075Sobrien#include "tree.h" 2790075Sobrien#include "function.h" 2890075Sobrien#include "splay-tree.h" 2990075Sobrien#include "varray.h" 3090075Sobrien#include "c-common.h" 3190075Sobrien#include "except.h" 3290075Sobrien#include "toplev.h" 3390075Sobrien#include "flags.h" 3490075Sobrien#include "ggc.h" 3590075Sobrien#include "rtl.h" 3690075Sobrien#include "expr.h" 3790075Sobrien#include "output.h" 3890075Sobrien#include "timevar.h" 3990075Sobrien 4090075Sobrien/* If non-NULL, the address of a language-specific function for 4190075Sobrien expanding statements. */ 4290075Sobrienvoid (*lang_expand_stmt) PARAMS ((tree)); 4390075Sobrien 4490075Sobrien/* If non-NULL, the address of a language-specific function for 4590075Sobrien expanding a DECL_STMT. After the language-independent cases are 4690075Sobrien handled, this function will be called. If this function is not 4790075Sobrien defined, it is assumed that declarations other than those for 4890075Sobrien variables and labels do not require any RTL generation. */ 4990075Sobrienvoid (*lang_expand_decl_stmt) PARAMS ((tree)); 5090075Sobrien 5190075Sobrien/* Create an empty statement tree rooted at T. */ 5290075Sobrien 5390075Sobrienvoid 5490075Sobrienbegin_stmt_tree (t) 5590075Sobrien tree *t; 5690075Sobrien{ 5790075Sobrien /* We create a trivial EXPR_STMT so that last_tree is never NULL in 5890075Sobrien what follows. We remove the extraneous statement in 5990075Sobrien finish_stmt_tree. */ 6090075Sobrien *t = build_nt (EXPR_STMT, void_zero_node); 6190075Sobrien last_tree = *t; 6290075Sobrien last_expr_type = NULL_TREE; 6390075Sobrien last_expr_filename = input_filename; 6490075Sobrien} 6590075Sobrien 6690075Sobrien/* T is a statement. Add it to the statement-tree. */ 6790075Sobrien 6890075Sobrientree 6990075Sobrienadd_stmt (t) 7090075Sobrien tree t; 7190075Sobrien{ 7290075Sobrien if (input_filename != last_expr_filename) 7390075Sobrien { 7490075Sobrien /* If the filename has changed, also add in a FILE_STMT. Do a string 7590075Sobrien compare first, though, as it might be an equivalent string. */ 7690075Sobrien int add = (strcmp (input_filename, last_expr_filename) != 0); 7790075Sobrien last_expr_filename = input_filename; 7890075Sobrien if (add) 7990075Sobrien { 8090075Sobrien tree pos = build_nt (FILE_STMT, get_identifier (input_filename)); 8190075Sobrien add_stmt (pos); 8290075Sobrien } 8390075Sobrien } 8490075Sobrien 8590075Sobrien /* Add T to the statement-tree. */ 8690075Sobrien TREE_CHAIN (last_tree) = t; 8790075Sobrien last_tree = t; 8890075Sobrien 8990075Sobrien /* When we expand a statement-tree, we must know whether or not the 9090075Sobrien statements are full-expressions. We record that fact here. */ 9190075Sobrien STMT_IS_FULL_EXPR_P (last_tree) = stmts_are_full_exprs_p (); 9290075Sobrien 9390075Sobrien /* Keep track of the number of statements in this function. */ 9490075Sobrien if (current_function_decl) 9590075Sobrien ++DECL_NUM_STMTS (current_function_decl); 9690075Sobrien 9790075Sobrien return t; 9890075Sobrien} 9990075Sobrien 10090075Sobrien/* Create a declaration statement for the declaration given by the 10190075Sobrien DECL. */ 10290075Sobrien 10390075Sobrienvoid 10490075Sobrienadd_decl_stmt (decl) 10590075Sobrien tree decl; 10690075Sobrien{ 10790075Sobrien tree decl_stmt; 10890075Sobrien 10990075Sobrien /* We need the type to last until instantiation time. */ 11090075Sobrien decl_stmt = build_stmt (DECL_STMT, decl); 11190075Sobrien add_stmt (decl_stmt); 11290075Sobrien} 11390075Sobrien 11490075Sobrien/* Add a scope-statement to the statement-tree. BEGIN_P indicates 11590075Sobrien whether this statements opens or closes a scope. PARTIAL_P is true 11690075Sobrien for a partial scope, i.e, the scope that begins after a label when 11790075Sobrien an object that needs a cleanup is created. If BEGIN_P is nonzero, 11890075Sobrien returns a new TREE_LIST representing the top of the SCOPE_STMT 11990075Sobrien stack. The TREE_PURPOSE is the new SCOPE_STMT. If BEGIN_P is 12090075Sobrien zero, returns a TREE_LIST whose TREE_VALUE is the new SCOPE_STMT, 12190075Sobrien and whose TREE_PURPOSE is the matching SCOPE_STMT with 12290075Sobrien SCOPE_BEGIN_P set. */ 12390075Sobrien 12490075Sobrientree 12590075Sobrienadd_scope_stmt (begin_p, partial_p) 12690075Sobrien int begin_p; 12790075Sobrien int partial_p; 12890075Sobrien{ 12990075Sobrien tree *stack_ptr = current_scope_stmt_stack (); 13090075Sobrien tree ss; 13190075Sobrien tree top = *stack_ptr; 13290075Sobrien 13390075Sobrien /* Build the statement. */ 13490075Sobrien ss = build_stmt (SCOPE_STMT, NULL_TREE); 13590075Sobrien SCOPE_BEGIN_P (ss) = begin_p; 13690075Sobrien SCOPE_PARTIAL_P (ss) = partial_p; 13790075Sobrien 13890075Sobrien /* Keep the scope stack up to date. */ 13990075Sobrien if (begin_p) 14090075Sobrien { 14190075Sobrien top = tree_cons (ss, NULL_TREE, top); 14290075Sobrien *stack_ptr = top; 14390075Sobrien } 14490075Sobrien else 14590075Sobrien { 14690075Sobrien TREE_VALUE (top) = ss; 14790075Sobrien *stack_ptr = TREE_CHAIN (top); 14890075Sobrien } 14990075Sobrien 15090075Sobrien /* Add the new statement to the statement-tree. */ 15190075Sobrien add_stmt (ss); 15290075Sobrien 15390075Sobrien return top; 15490075Sobrien} 15590075Sobrien 15690075Sobrien/* Finish the statement tree rooted at T. */ 15790075Sobrien 15890075Sobrienvoid 15990075Sobrienfinish_stmt_tree (t) 16090075Sobrien tree *t; 16190075Sobrien{ 16290075Sobrien tree stmt; 16390075Sobrien 16490075Sobrien /* Remove the fake extra statement added in begin_stmt_tree. */ 16590075Sobrien stmt = TREE_CHAIN (*t); 16690075Sobrien *t = stmt; 16790075Sobrien last_tree = NULL_TREE; 16890075Sobrien 16990075Sobrien if (cfun && stmt) 17090075Sobrien { 17190075Sobrien /* The line-number recorded in the outermost statement in a function 17290075Sobrien is the line number of the end of the function. */ 17390075Sobrien STMT_LINENO (stmt) = lineno; 17490075Sobrien STMT_LINENO_FOR_FN_P (stmt) = 1; 17590075Sobrien } 17690075Sobrien} 17790075Sobrien 17890075Sobrien/* Build a generic statement based on the given type of node and 17990075Sobrien arguments. Similar to `build_nt', except that we set 18090075Sobrien STMT_LINENO to be the current line number. */ 18190075Sobrien/* ??? This should be obsolete with the lineno_stmt productions 18290075Sobrien in the grammar. */ 18390075Sobrien 18490075Sobrientree 18590075Sobrienbuild_stmt VPARAMS ((enum tree_code code, ...)) 18690075Sobrien{ 18790075Sobrien tree t; 18890075Sobrien int length; 18990075Sobrien int i; 19090075Sobrien 19190075Sobrien VA_OPEN (p, code); 19290075Sobrien VA_FIXEDARG (p, enum tree_code, code); 19390075Sobrien 19490075Sobrien t = make_node (code); 19590075Sobrien length = TREE_CODE_LENGTH (code); 19690075Sobrien STMT_LINENO (t) = lineno; 19790075Sobrien 19890075Sobrien for (i = 0; i < length; i++) 19990075Sobrien TREE_OPERAND (t, i) = va_arg (p, tree); 20090075Sobrien 20190075Sobrien VA_CLOSE (p); 20290075Sobrien return t; 20390075Sobrien} 20490075Sobrien 20590075Sobrien/* Some statements, like for-statements or if-statements, require a 20690075Sobrien condition. This condition can be a declaration. If T is such a 20790075Sobrien declaration it is processed, and an expression appropriate to use 20890075Sobrien as the condition is returned. Otherwise, T itself is returned. */ 20990075Sobrien 21090075Sobrientree 21190075Sobrienexpand_cond (t) 21290075Sobrien tree t; 21390075Sobrien{ 21490075Sobrien if (t && TREE_CODE (t) == TREE_LIST) 21590075Sobrien { 21690075Sobrien expand_stmt (TREE_PURPOSE (t)); 21790075Sobrien return TREE_VALUE (t); 21890075Sobrien } 21990075Sobrien else 22090075Sobrien return t; 22190075Sobrien} 22290075Sobrien 22390075Sobrien/* Create RTL for the local static variable DECL. */ 22490075Sobrien 22590075Sobrienvoid 22690075Sobrienmake_rtl_for_local_static (decl) 22790075Sobrien tree decl; 22890075Sobrien{ 22990075Sobrien const char *asmspec = NULL; 23090075Sobrien 23190075Sobrien /* If we inlined this variable, we could see it's declaration 23290075Sobrien again. */ 23390075Sobrien if (TREE_ASM_WRITTEN (decl)) 23490075Sobrien return; 23590075Sobrien 23690075Sobrien /* If the DECL_ASSEMBLER_NAME is not the same as the DECL_NAME, then 23790075Sobrien either we already created RTL for this DECL (and since it was a 23890075Sobrien local variable, its DECL_ASSEMBLER_NAME got hacked up to prevent 23990075Sobrien clashes with other local statics with the same name by a previous 24090075Sobrien call to make_decl_rtl), or the user explicitly requested a 24190075Sobrien particular assembly name for this variable, using the GNU 24290075Sobrien extension for this purpose: 24390075Sobrien 24490075Sobrien int i asm ("j"); 24590075Sobrien 24690075Sobrien There's no way to know which case we're in, here. But, it turns 24790075Sobrien out we're safe. If there's already RTL, then 24890075Sobrien rest_of_decl_compilation ignores the ASMSPEC parameter, so we 24990075Sobrien may as well not pass it in. If there isn't RTL, then we didn't 25090075Sobrien already create RTL, which means that the modification to 25190075Sobrien DECL_ASSEMBLER_NAME came only via the explicit extension. */ 25290075Sobrien if (DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl) 25390075Sobrien && !DECL_RTL_SET_P (decl)) 25490075Sobrien asmspec = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); 25590075Sobrien 25690075Sobrien rest_of_decl_compilation (decl, asmspec, /*top_level=*/0, /*at_end=*/0); 25790075Sobrien} 25890075Sobrien 25990075Sobrien/* Let the back-end know about DECL. */ 26090075Sobrien 26190075Sobrienvoid 26290075Sobrienemit_local_var (decl) 26390075Sobrien tree decl; 26490075Sobrien{ 26590075Sobrien /* Create RTL for this variable. */ 26690075Sobrien if (!DECL_RTL_SET_P (decl)) 26790075Sobrien { 26890075Sobrien if (DECL_C_HARD_REGISTER (decl)) 26990075Sobrien /* The user specified an assembler name for this variable. 27090075Sobrien Set that up now. */ 27190075Sobrien rest_of_decl_compilation 27290075Sobrien (decl, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), 27390075Sobrien /*top_level=*/0, /*at_end=*/0); 27490075Sobrien else 27590075Sobrien expand_decl (decl); 27690075Sobrien } 27790075Sobrien 27890075Sobrien /* Actually do the initialization. */ 27990075Sobrien if (stmts_are_full_exprs_p ()) 28090075Sobrien expand_start_target_temps (); 28190075Sobrien 28290075Sobrien expand_decl_init (decl); 28390075Sobrien 28490075Sobrien if (stmts_are_full_exprs_p ()) 28590075Sobrien expand_end_target_temps (); 28690075Sobrien} 28790075Sobrien 28890075Sobrien/* Helper for generating the RTL at the beginning of a scope. */ 28990075Sobrien 29090075Sobrienvoid 29190075Sobriengenrtl_do_pushlevel () 29290075Sobrien{ 29390075Sobrien emit_line_note (input_filename, lineno); 29490075Sobrien clear_last_expr (); 29590075Sobrien} 29690075Sobrien 29790075Sobrien/* Generate the RTL for DESTINATION, which is a GOTO_STMT. */ 29890075Sobrien 29990075Sobrienvoid 30090075Sobriengenrtl_goto_stmt (destination) 30190075Sobrien tree destination; 30290075Sobrien{ 30390075Sobrien if (TREE_CODE (destination) == IDENTIFIER_NODE) 30490075Sobrien abort (); 30590075Sobrien 30690075Sobrien /* We warn about unused labels with -Wunused. That means we have to 30790075Sobrien mark the used labels as used. */ 30890075Sobrien if (TREE_CODE (destination) == LABEL_DECL) 30990075Sobrien TREE_USED (destination) = 1; 31090075Sobrien 31190075Sobrien emit_line_note (input_filename, lineno); 31290075Sobrien 31390075Sobrien if (TREE_CODE (destination) == LABEL_DECL) 31490075Sobrien { 31590075Sobrien label_rtx (destination); 31690075Sobrien expand_goto (destination); 31790075Sobrien } 31890075Sobrien else 31990075Sobrien expand_computed_goto (destination); 32090075Sobrien} 32190075Sobrien 32290075Sobrien/* Generate the RTL for EXPR, which is an EXPR_STMT. Provided just 32390075Sobrien for backward compatibility. genrtl_expr_stmt_value() should be 32490075Sobrien used for new code. */ 32590075Sobrien 32690075Sobrienvoid 32790075Sobriengenrtl_expr_stmt (expr) 32890075Sobrien tree expr; 32990075Sobrien{ 33090075Sobrien genrtl_expr_stmt_value (expr, -1, 1); 33190075Sobrien} 33290075Sobrien 33390075Sobrien/* Generate the RTL for EXPR, which is an EXPR_STMT. WANT_VALUE tells 33490075Sobrien whether to (1) save the value of the expression, (0) discard it or 33590075Sobrien (-1) use expr_stmts_for_value to tell. The use of -1 is 33690075Sobrien deprecated, and retained only for backward compatibility. 33790075Sobrien MAYBE_LAST is non-zero if this EXPR_STMT might be the last statement 33890075Sobrien in expression statement. */ 33990075Sobrien 34090075Sobrienvoid 34190075Sobriengenrtl_expr_stmt_value (expr, want_value, maybe_last) 34290075Sobrien tree expr; 34390075Sobrien int want_value, maybe_last; 34490075Sobrien{ 34590075Sobrien if (expr != NULL_TREE) 34690075Sobrien { 34790075Sobrien emit_line_note (input_filename, lineno); 34890075Sobrien 34990075Sobrien if (stmts_are_full_exprs_p ()) 35090075Sobrien expand_start_target_temps (); 35190075Sobrien 35290075Sobrien if (expr != error_mark_node) 35390075Sobrien expand_expr_stmt_value (expr, want_value, maybe_last); 35490075Sobrien 35590075Sobrien if (stmts_are_full_exprs_p ()) 35690075Sobrien expand_end_target_temps (); 35790075Sobrien } 35890075Sobrien} 35990075Sobrien 36090075Sobrien/* Generate the RTL for T, which is a DECL_STMT. */ 36190075Sobrien 36290075Sobrienvoid 36390075Sobriengenrtl_decl_stmt (t) 36490075Sobrien tree t; 36590075Sobrien{ 36690075Sobrien tree decl; 36790075Sobrien emit_line_note (input_filename, lineno); 36890075Sobrien decl = DECL_STMT_DECL (t); 36990075Sobrien /* If this is a declaration for an automatic local 37090075Sobrien variable, initialize it. Note that we might also see a 37190075Sobrien declaration for a namespace-scope object (declared with 37290075Sobrien `extern'). We don't have to handle the initialization 37390075Sobrien of those objects here; they can only be declarations, 37490075Sobrien rather than definitions. */ 37590075Sobrien if (TREE_CODE (decl) == VAR_DECL 37690075Sobrien && !TREE_STATIC (decl) 37790075Sobrien && !DECL_EXTERNAL (decl)) 37890075Sobrien { 37990075Sobrien /* Let the back-end know about this variable. */ 38090075Sobrien if (!anon_aggr_type_p (TREE_TYPE (decl))) 38190075Sobrien emit_local_var (decl); 38290075Sobrien else 38390075Sobrien expand_anon_union_decl (decl, NULL_TREE, 38490075Sobrien DECL_ANON_UNION_ELEMS (decl)); 38590075Sobrien } 38690075Sobrien else if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl)) 38790075Sobrien make_rtl_for_local_static (decl); 38890075Sobrien else if (TREE_CODE (decl) == LABEL_DECL 38990075Sobrien && C_DECLARED_LABEL_FLAG (decl)) 39090075Sobrien declare_nonlocal_label (decl); 39190075Sobrien else if (lang_expand_decl_stmt) 39290075Sobrien (*lang_expand_decl_stmt) (t); 39390075Sobrien} 39490075Sobrien 39590075Sobrien/* Generate the RTL for T, which is an IF_STMT. */ 39690075Sobrien 39790075Sobrienvoid 39890075Sobriengenrtl_if_stmt (t) 39990075Sobrien tree t; 40090075Sobrien{ 40190075Sobrien tree cond; 40290075Sobrien genrtl_do_pushlevel (); 40390075Sobrien cond = expand_cond (IF_COND (t)); 40490075Sobrien emit_line_note (input_filename, lineno); 40590075Sobrien expand_start_cond (cond, 0); 40690075Sobrien if (THEN_CLAUSE (t)) 40790075Sobrien expand_stmt (THEN_CLAUSE (t)); 40890075Sobrien if (ELSE_CLAUSE (t)) 40990075Sobrien { 41090075Sobrien expand_start_else (); 41190075Sobrien expand_stmt (ELSE_CLAUSE (t)); 41290075Sobrien } 41390075Sobrien expand_end_cond (); 41490075Sobrien} 41590075Sobrien 41690075Sobrien/* Generate the RTL for T, which is a WHILE_STMT. */ 41790075Sobrien 41890075Sobrienvoid 41990075Sobriengenrtl_while_stmt (t) 42090075Sobrien tree t; 42190075Sobrien{ 42290075Sobrien tree cond; 42390075Sobrien emit_nop (); 42490075Sobrien emit_line_note (input_filename, lineno); 42590075Sobrien expand_start_loop (1); 42690075Sobrien genrtl_do_pushlevel (); 42790075Sobrien 42890075Sobrien cond = expand_cond (WHILE_COND (t)); 42990075Sobrien emit_line_note (input_filename, lineno); 43090075Sobrien expand_exit_loop_top_cond (0, cond); 43190075Sobrien genrtl_do_pushlevel (); 43290075Sobrien 43390075Sobrien expand_stmt (WHILE_BODY (t)); 43490075Sobrien 43590075Sobrien expand_end_loop (); 43690075Sobrien} 43790075Sobrien 43890075Sobrien/* Generate the RTL for T, which is a DO_STMT. */ 43990075Sobrien 44090075Sobrienvoid 44190075Sobriengenrtl_do_stmt (t) 44290075Sobrien tree t; 44390075Sobrien{ 44490075Sobrien tree cond = DO_COND (t); 44590075Sobrien 44690075Sobrien /* Recognize the common special-case of do { ... } while (0) and do 44790075Sobrien not emit the loop widgetry in this case. In particular this 44890075Sobrien avoids cluttering the rtl with dummy loop notes, which can affect 44990075Sobrien alignment of adjacent labels. */ 45090075Sobrien if (integer_zerop (cond)) 45190075Sobrien { 45290075Sobrien expand_start_null_loop (); 45390075Sobrien expand_stmt (DO_BODY (t)); 45490075Sobrien expand_end_null_loop (); 45590075Sobrien } 45690075Sobrien else 45790075Sobrien { 45890075Sobrien emit_nop (); 45990075Sobrien emit_line_note (input_filename, lineno); 46090075Sobrien expand_start_loop_continue_elsewhere (1); 46190075Sobrien 46290075Sobrien expand_stmt (DO_BODY (t)); 46390075Sobrien 46490075Sobrien expand_loop_continue_here (); 46590075Sobrien cond = expand_cond (cond); 46690075Sobrien emit_line_note (input_filename, lineno); 46790075Sobrien expand_exit_loop_if_false (0, cond); 46890075Sobrien expand_end_loop (); 46990075Sobrien } 47090075Sobrien} 47190075Sobrien 47290075Sobrien/* Build the node for a return statement and return it. */ 47390075Sobrien 47490075Sobrientree 47590075Sobrienbuild_return_stmt (expr) 47690075Sobrien tree expr; 47790075Sobrien{ 47890075Sobrien return (build_stmt (RETURN_STMT, expr)); 47990075Sobrien} 48090075Sobrien 48190075Sobrien/* Generate the RTL for STMT, which is a RETURN_STMT. */ 48290075Sobrien 48390075Sobrienvoid 48490075Sobriengenrtl_return_stmt (stmt) 48590075Sobrien tree stmt; 48690075Sobrien{ 48790075Sobrien tree expr; 48890075Sobrien 48990075Sobrien expr = RETURN_EXPR (stmt); 49090075Sobrien 49190075Sobrien emit_line_note (input_filename, lineno); 49290075Sobrien if (!expr) 49390075Sobrien expand_null_return (); 49490075Sobrien else 49590075Sobrien { 49690075Sobrien expand_start_target_temps (); 49790075Sobrien expand_return (expr); 49890075Sobrien expand_end_target_temps (); 49990075Sobrien } 50090075Sobrien} 50190075Sobrien 50290075Sobrien/* Generate the RTL for T, which is a FOR_STMT. */ 50390075Sobrien 50490075Sobrienvoid 50590075Sobriengenrtl_for_stmt (t) 50690075Sobrien tree t; 50790075Sobrien{ 50890075Sobrien tree cond; 50990075Sobrien const char *saved_filename; 51090075Sobrien int saved_lineno; 51190075Sobrien 51290075Sobrien if (NEW_FOR_SCOPE_P (t)) 51390075Sobrien genrtl_do_pushlevel (); 51490075Sobrien 51590075Sobrien expand_stmt (FOR_INIT_STMT (t)); 51690075Sobrien 51790075Sobrien /* Expand the initialization. */ 51890075Sobrien emit_nop (); 51990075Sobrien emit_line_note (input_filename, lineno); 52090075Sobrien expand_start_loop_continue_elsewhere (1); 52190075Sobrien genrtl_do_pushlevel (); 52290075Sobrien cond = expand_cond (FOR_COND (t)); 52390075Sobrien 52490075Sobrien /* Save the filename and line number so that we expand the FOR_EXPR 52590075Sobrien we can reset them back to the saved values. */ 52690075Sobrien saved_filename = input_filename; 52790075Sobrien saved_lineno = lineno; 52890075Sobrien 52990075Sobrien /* Expand the condition. */ 53090075Sobrien emit_line_note (input_filename, lineno); 53190075Sobrien if (cond) 53290075Sobrien expand_exit_loop_top_cond (0, cond); 53390075Sobrien 53490075Sobrien /* Expand the body. */ 53590075Sobrien genrtl_do_pushlevel (); 53690075Sobrien expand_stmt (FOR_BODY (t)); 53790075Sobrien 53890075Sobrien /* Expand the increment expression. */ 53990075Sobrien input_filename = saved_filename; 54090075Sobrien lineno = saved_lineno; 54190075Sobrien emit_line_note (input_filename, lineno); 54290075Sobrien expand_loop_continue_here (); 54390075Sobrien if (FOR_EXPR (t)) 54490075Sobrien genrtl_expr_stmt (FOR_EXPR (t)); 54590075Sobrien expand_end_loop (); 54690075Sobrien} 54790075Sobrien 54890075Sobrien/* Build a break statement node and return it. */ 54990075Sobrien 55090075Sobrientree 55190075Sobrienbuild_break_stmt () 55290075Sobrien{ 55390075Sobrien return (build_stmt (BREAK_STMT)); 55490075Sobrien} 55590075Sobrien 55690075Sobrien/* Generate the RTL for a BREAK_STMT. */ 55790075Sobrien 55890075Sobrienvoid 55990075Sobriengenrtl_break_stmt () 56090075Sobrien{ 56190075Sobrien emit_line_note (input_filename, lineno); 56290075Sobrien if ( ! expand_exit_something ()) 56390075Sobrien error ("break statement not within loop or switch"); 56490075Sobrien} 56590075Sobrien 56690075Sobrien/* Build a continue statement node and return it. */ 56790075Sobrien 56890075Sobrientree 56990075Sobrienbuild_continue_stmt () 57090075Sobrien{ 57190075Sobrien return (build_stmt (CONTINUE_STMT)); 57290075Sobrien} 57390075Sobrien 57490075Sobrien/* Generate the RTL for a CONTINUE_STMT. */ 57590075Sobrien 57690075Sobrienvoid 57790075Sobriengenrtl_continue_stmt () 57890075Sobrien{ 57990075Sobrien emit_line_note (input_filename, lineno); 58090075Sobrien if (! expand_continue_loop (0)) 58190075Sobrien error ("continue statement not within a loop"); 58290075Sobrien} 58390075Sobrien 58490075Sobrien/* Generate the RTL for T, which is a SCOPE_STMT. */ 58590075Sobrien 58690075Sobrienvoid 58790075Sobriengenrtl_scope_stmt (t) 58890075Sobrien tree t; 58990075Sobrien{ 59090075Sobrien tree block = SCOPE_STMT_BLOCK (t); 59190075Sobrien 59290075Sobrien if (!SCOPE_NO_CLEANUPS_P (t)) 59390075Sobrien { 59490075Sobrien if (SCOPE_BEGIN_P (t)) 59590075Sobrien expand_start_bindings_and_block (2 * SCOPE_NULLIFIED_P (t), block); 59690075Sobrien else if (SCOPE_END_P (t)) 59790075Sobrien expand_end_bindings (NULL_TREE, !SCOPE_NULLIFIED_P (t), 0); 59890075Sobrien } 59990075Sobrien else if (!SCOPE_NULLIFIED_P (t)) 60090075Sobrien { 60190075Sobrien rtx note = emit_note (NULL, 60290075Sobrien (SCOPE_BEGIN_P (t) 60390075Sobrien ? NOTE_INSN_BLOCK_BEG 60490075Sobrien : NOTE_INSN_BLOCK_END)); 60590075Sobrien NOTE_BLOCK (note) = block; 60690075Sobrien } 60790075Sobrien 60890075Sobrien /* If we're at the end of a scope that contains inlined nested 60990075Sobrien functions, we have to decide whether or not to write them out. */ 61090075Sobrien if (block && SCOPE_END_P (t)) 61190075Sobrien { 61290075Sobrien tree fn; 61390075Sobrien 61490075Sobrien for (fn = BLOCK_VARS (block); fn; fn = TREE_CHAIN (fn)) 61590075Sobrien { 61690075Sobrien if (TREE_CODE (fn) == FUNCTION_DECL 61790075Sobrien && DECL_CONTEXT (fn) == current_function_decl 61890075Sobrien && !TREE_ASM_WRITTEN (fn) 61990075Sobrien && TREE_ADDRESSABLE (fn)) 62090075Sobrien { 62190075Sobrien push_function_context (); 62290075Sobrien output_inline_function (fn); 62390075Sobrien pop_function_context (); 62490075Sobrien } 62590075Sobrien } 62690075Sobrien } 62790075Sobrien} 62890075Sobrien 62990075Sobrien/* Generate the RTL for T, which is a SWITCH_STMT. */ 63090075Sobrien 63190075Sobrienvoid 63290075Sobriengenrtl_switch_stmt (t) 63390075Sobrien tree t; 63490075Sobrien{ 63590075Sobrien tree cond; 63690075Sobrien genrtl_do_pushlevel (); 63790075Sobrien 63890075Sobrien cond = expand_cond (SWITCH_COND (t)); 63990075Sobrien if (cond == error_mark_node) 64090075Sobrien /* The code is in error, but we don't want expand_end_case to 64190075Sobrien crash. */ 64290075Sobrien cond = boolean_false_node; 64390075Sobrien 64490075Sobrien emit_line_note (input_filename, lineno); 64590075Sobrien expand_start_case (1, cond, TREE_TYPE (cond), "switch statement"); 64690075Sobrien expand_stmt (SWITCH_BODY (t)); 64790075Sobrien expand_end_case (cond); 64890075Sobrien} 64990075Sobrien 65090075Sobrien/* Create a CASE_LABEL tree node and return it. */ 65190075Sobrien 65290075Sobrientree 65390075Sobrienbuild_case_label (low_value, high_value, label_decl) 65490075Sobrien tree low_value; 65590075Sobrien tree high_value; 65690075Sobrien tree label_decl; 65790075Sobrien{ 65890075Sobrien return build_stmt (CASE_LABEL, low_value, high_value, label_decl); 65990075Sobrien} 66090075Sobrien 66190075Sobrien 66290075Sobrien/* Generate the RTL for a CASE_LABEL. */ 66390075Sobrien 66490075Sobrienvoid 66590075Sobriengenrtl_case_label (case_label) 66690075Sobrien tree case_label; 66790075Sobrien{ 66890075Sobrien tree duplicate; 66990075Sobrien tree cleanup; 67090075Sobrien 67190075Sobrien cleanup = last_cleanup_this_contour (); 67290075Sobrien if (cleanup) 67390075Sobrien { 67490075Sobrien static int explained = 0; 67590075Sobrien warning_with_decl (TREE_PURPOSE (cleanup), 67690075Sobrien "destructor needed for `%#D'"); 67790075Sobrien warning ("where case label appears here"); 67890075Sobrien if (!explained) 67990075Sobrien { 68090075Sobrien warning ("(enclose actions of previous case statements requiring destructors in their own scope.)"); 68190075Sobrien explained = 1; 68290075Sobrien } 68390075Sobrien } 68490075Sobrien 68590075Sobrien add_case_node (CASE_LOW (case_label), CASE_HIGH (case_label), 68690075Sobrien CASE_LABEL_DECL (case_label), &duplicate); 68790075Sobrien} 68890075Sobrien 68990075Sobrien/* Generate the RTL for T, which is a COMPOUND_STMT. */ 69090075Sobrien 69190075Sobrienvoid 69290075Sobriengenrtl_compound_stmt (t) 69390075Sobrien tree t; 69490075Sobrien{ 69590075Sobrien#ifdef ENABLE_CHECKING 69690075Sobrien struct nesting *n = current_nesting_level (); 69790075Sobrien#endif 69890075Sobrien 69990075Sobrien expand_stmt (COMPOUND_BODY (t)); 70090075Sobrien 70190075Sobrien#ifdef ENABLE_CHECKING 70290075Sobrien /* Make sure that we've pushed and popped the same number of levels. */ 70390075Sobrien if (!COMPOUND_STMT_NO_SCOPE (t) && n != current_nesting_level ()) 70490075Sobrien abort (); 70590075Sobrien#endif 70690075Sobrien} 70790075Sobrien 70890075Sobrien/* Generate the RTL for an ASM_STMT. */ 70990075Sobrien 71090075Sobrienvoid 71190075Sobriengenrtl_asm_stmt (cv_qualifier, string, output_operands, 71290075Sobrien input_operands, clobbers, asm_input_p) 71390075Sobrien tree cv_qualifier; 71490075Sobrien tree string; 71590075Sobrien tree output_operands; 71690075Sobrien tree input_operands; 71790075Sobrien tree clobbers; 71890075Sobrien int asm_input_p; 71990075Sobrien{ 72090075Sobrien if (cv_qualifier != NULL_TREE 72190075Sobrien && cv_qualifier != ridpointers[(int) RID_VOLATILE]) 72290075Sobrien { 72390075Sobrien warning ("%s qualifier ignored on asm", 72490075Sobrien IDENTIFIER_POINTER (cv_qualifier)); 72590075Sobrien cv_qualifier = NULL_TREE; 72690075Sobrien } 72790075Sobrien 72890075Sobrien emit_line_note (input_filename, lineno); 72990075Sobrien if (asm_input_p) 73090075Sobrien expand_asm (string); 73190075Sobrien else 73290075Sobrien c_expand_asm_operands (string, output_operands, input_operands, 73390075Sobrien clobbers, cv_qualifier != NULL_TREE, 73490075Sobrien input_filename, lineno); 73590075Sobrien} 73690075Sobrien 73790075Sobrien/* Generate the RTL for a DECL_CLEANUP. */ 73890075Sobrien 73990075Sobrienvoid 74090075Sobriengenrtl_decl_cleanup (decl, cleanup) 74190075Sobrien tree decl; 74290075Sobrien tree cleanup; 74390075Sobrien{ 74490075Sobrien if (!decl || (DECL_SIZE (decl) && TREE_TYPE (decl) != error_mark_node)) 74590075Sobrien expand_decl_cleanup (decl, cleanup); 74690075Sobrien} 74790075Sobrien 74890075Sobrien/* We're about to expand T, a statement. Set up appropriate context 74990075Sobrien for the substitution. */ 75090075Sobrien 75190075Sobrienvoid 75290075Sobrienprep_stmt (t) 75390075Sobrien tree t; 75490075Sobrien{ 75590075Sobrien if (!STMT_LINENO_FOR_FN_P (t)) 75690075Sobrien lineno = STMT_LINENO (t); 75790075Sobrien current_stmt_tree ()->stmts_are_full_exprs_p = STMT_IS_FULL_EXPR_P (t); 75890075Sobrien} 75990075Sobrien 76090075Sobrien/* Generate the RTL for the statement T, its substatements, and any 76190075Sobrien other statements at its nesting level. */ 76290075Sobrien 76390075Sobrienvoid 76490075Sobrienexpand_stmt (t) 76590075Sobrien tree t; 76690075Sobrien{ 76790075Sobrien while (t && t != error_mark_node) 76890075Sobrien { 76990075Sobrien int saved_stmts_are_full_exprs_p; 77090075Sobrien 77190075Sobrien /* Set up context appropriately for handling this statement. */ 77290075Sobrien saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p (); 77390075Sobrien prep_stmt (t); 77490075Sobrien 77590075Sobrien switch (TREE_CODE (t)) 77690075Sobrien { 77790075Sobrien case FILE_STMT: 77890075Sobrien input_filename = FILE_STMT_FILENAME (t); 77990075Sobrien break; 78090075Sobrien 78190075Sobrien case RETURN_STMT: 78290075Sobrien genrtl_return_stmt (t); 78390075Sobrien break; 78490075Sobrien 78590075Sobrien case EXPR_STMT: 78690075Sobrien genrtl_expr_stmt_value (EXPR_STMT_EXPR (t), TREE_ADDRESSABLE (t), 78790075Sobrien TREE_CHAIN (t) == NULL 78890075Sobrien || (TREE_CODE (TREE_CHAIN (t)) == SCOPE_STMT 78990075Sobrien && TREE_CHAIN (TREE_CHAIN (t)) == NULL)); 79090075Sobrien break; 79190075Sobrien 79290075Sobrien case DECL_STMT: 79390075Sobrien genrtl_decl_stmt (t); 79490075Sobrien break; 79590075Sobrien 79690075Sobrien case FOR_STMT: 79790075Sobrien genrtl_for_stmt (t); 79890075Sobrien break; 79990075Sobrien 80090075Sobrien case WHILE_STMT: 80190075Sobrien genrtl_while_stmt (t); 80290075Sobrien break; 80390075Sobrien 80490075Sobrien case DO_STMT: 80590075Sobrien genrtl_do_stmt (t); 80690075Sobrien break; 80790075Sobrien 80890075Sobrien case IF_STMT: 80990075Sobrien genrtl_if_stmt (t); 81090075Sobrien break; 81190075Sobrien 81290075Sobrien case COMPOUND_STMT: 81390075Sobrien genrtl_compound_stmt (t); 81490075Sobrien break; 81590075Sobrien 81690075Sobrien case BREAK_STMT: 81790075Sobrien genrtl_break_stmt (); 81890075Sobrien break; 81990075Sobrien 82090075Sobrien case CONTINUE_STMT: 82190075Sobrien genrtl_continue_stmt (); 82290075Sobrien break; 82390075Sobrien 82490075Sobrien case SWITCH_STMT: 82590075Sobrien genrtl_switch_stmt (t); 82690075Sobrien break; 82790075Sobrien 82890075Sobrien case CASE_LABEL: 82990075Sobrien genrtl_case_label (t); 83090075Sobrien break; 83190075Sobrien 83290075Sobrien case LABEL_STMT: 83390075Sobrien expand_label (LABEL_STMT_LABEL (t)); 83490075Sobrien break; 83590075Sobrien 83690075Sobrien case GOTO_STMT: 83790075Sobrien genrtl_goto_stmt (GOTO_DESTINATION (t)); 83890075Sobrien break; 83990075Sobrien 84090075Sobrien case ASM_STMT: 84190075Sobrien genrtl_asm_stmt (ASM_CV_QUAL (t), ASM_STRING (t), 84290075Sobrien ASM_OUTPUTS (t), ASM_INPUTS (t), 84390075Sobrien ASM_CLOBBERS (t), ASM_INPUT_P (t)); 84490075Sobrien break; 84590075Sobrien 84690075Sobrien case SCOPE_STMT: 84790075Sobrien genrtl_scope_stmt (t); 84890075Sobrien break; 84990075Sobrien 85090075Sobrien default: 85190075Sobrien if (lang_expand_stmt) 85290075Sobrien (*lang_expand_stmt) (t); 85390075Sobrien else 85490075Sobrien abort (); 85590075Sobrien break; 85690075Sobrien } 85790075Sobrien 85890075Sobrien /* Restore saved state. */ 85990075Sobrien current_stmt_tree ()->stmts_are_full_exprs_p 86090075Sobrien = saved_stmts_are_full_exprs_p; 86190075Sobrien 86290075Sobrien /* Go on to the next statement in this scope. */ 86390075Sobrien t = TREE_CHAIN (t); 86490075Sobrien } 86590075Sobrien} 866