diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1f19a8099ba..6eca585b107 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,20 @@ +2000-12-20 Richard Henderson + + * c-typeck.c (build_asm_stmt): New, broken out from ... + (c_expand_asm_operands): ... here. Just do rtl expansion. + (c_expand_return): Return the new stmt node. + (c_start_case, do_case): Likewise. + * c-common.c (c_expand_expr_stmt): Likewise. + * c-common.h: Update declarations. + * c-tree.h: Likewise. + * c-semantics.c (build_stmt): Use STMT_LINENO not TREE_COMPLEXITY. + * c-parse.in (fndef): Set DECL_SOURCE_LINE to the open brace. + (nested_function, notype_nested_function): Likewise. + (compstmt): Return the compound statement not the binding level. + (lineno_labeled_stmt): Simplify. + (lineno_stmt, lineno_label): Set STMT_LINENO. + (stmt, label): Return the new stmt node. + 2000-12-20 Bernd Schmidt * Makefile.in (OBJS): Add sched-ebb.o. diff --git a/gcc/c-common.c b/gcc/c-common.c index a1970e2cd0c..5d13345eda0 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -3950,7 +3950,7 @@ verify_sequence_points (expr) obstack_free (&tlist_obstack, tlist_firstobj); } -void +tree c_expand_expr_stmt (expr) tree expr; { @@ -3969,7 +3969,7 @@ c_expand_expr_stmt (expr) error ("expression statement has incomplete type"); last_expr_type = TREE_TYPE (expr); - add_stmt (build_stmt (EXPR_STMT, expr)); + return add_stmt (build_stmt (EXPR_STMT, expr)); } /* Validate the expression after `case' and apply default promotions. */ diff --git a/gcc/c-common.h b/gcc/c-common.h index b31499ff7ea..a23b8715b35 100644 --- a/gcc/c-common.h +++ b/gcc/c-common.h @@ -467,7 +467,7 @@ extern void c_apply_type_quals_to_decl PARAMS ((int, tree)); /* Print an error message for invalid operands to arith operation CODE. NOP_EXPR is used as a special case (see truthvalue_conversion). */ extern void binary_op_error PARAMS ((enum tree_code)); -extern void c_expand_expr_stmt PARAMS ((tree)); +extern tree c_expand_expr_stmt PARAMS ((tree)); extern void c_expand_start_cond PARAMS ((tree, int)); extern void c_finish_then PARAMS ((void)); extern void c_expand_start_else PARAMS ((void)); @@ -713,8 +713,8 @@ extern int anon_aggr_type_p PARAMS ((tree)); extern void emit_local_var PARAMS ((tree)); extern void make_rtl_for_local_static PARAMS ((tree)); extern tree expand_cond PARAMS ((tree)); -extern void c_expand_return PARAMS ((tree)); -extern void do_case PARAMS ((tree, tree)); +extern tree c_expand_return PARAMS ((tree)); +extern tree do_case PARAMS ((tree, tree)); extern tree build_stmt PARAMS ((enum tree_code, ...)); extern tree build_case_label PARAMS ((tree, tree, tree)); extern tree build_continue_stmt PARAMS ((void)); diff --git a/gcc/c-parse.in b/gcc/c-parse.in index cf010e6a091..8b211d1384b 100644 --- a/gcc/c-parse.in +++ b/gcc/c-parse.in @@ -177,7 +177,7 @@ end ifc %type any_word extension %type compstmt compstmt_start compstmt_nostart compstmt_primary_start -%type do_stmt_start poplevel +%type do_stmt_start poplevel stmt label %type c99_block_start c99_block_end %type declarator @@ -365,8 +365,10 @@ fndef: } old_style_parm_decls { store_parm_decls (); } - compstmt_or_error - { finish_function (0); + save_filename save_lineno compstmt_or_error + { DECL_SOURCE_FILE (current_function_decl) = $7; + DECL_SOURCE_LINE (current_function_decl) = $8; + finish_function (0); current_declspecs = TREE_VALUE (declspec_stack); prefix_attributes = TREE_PURPOSE (declspec_stack); declspec_stack = TREE_CHAIN (declspec_stack); } @@ -381,8 +383,10 @@ fndef: } old_style_parm_decls { store_parm_decls (); } - compstmt_or_error - { finish_function (0); + save_filename save_lineno compstmt_or_error + { DECL_SOURCE_FILE (current_function_decl) = $7; + DECL_SOURCE_LINE (current_function_decl) = $8; + finish_function (0); current_declspecs = TREE_VALUE (declspec_stack); prefix_attributes = TREE_PURPOSE (declspec_stack); declspec_stack = TREE_CHAIN (declspec_stack); } @@ -397,8 +401,10 @@ fndef: } old_style_parm_decls { store_parm_decls (); } - compstmt_or_error - { finish_function (0); + save_filename save_lineno compstmt_or_error + { DECL_SOURCE_FILE (current_function_decl) = $6; + DECL_SOURCE_LINE (current_function_decl) = $7; + finish_function (0); current_declspecs = TREE_VALUE (declspec_stack); prefix_attributes = TREE_PURPOSE (declspec_stack); declspec_stack = TREE_CHAIN (declspec_stack); } @@ -1192,8 +1198,10 @@ nested_function: which then was handled by compstmt_or_error. There followed a repeated execution of that same rule, which called YYERROR1 again, and so on. */ - compstmt + save_filename save_lineno compstmt { tree decl = current_function_decl; + DECL_SOURCE_FILE (decl) = $5; + DECL_SOURCE_LINE (decl) = $6; finish_function (1); pop_function_context (); add_decl_stmt (decl); } @@ -1220,8 +1228,10 @@ notype_nested_function: which then was handled by compstmt_or_error. There followed a repeated execution of that same rule, which called YYERROR1 again, and so on. */ - compstmt + save_filename save_lineno compstmt { tree decl = current_function_decl; + DECL_SOURCE_FILE (decl) = $5; + DECL_SOURCE_LINE (decl) = $6; finish_function (1); pop_function_context (); add_decl_stmt (decl); } @@ -1750,7 +1760,7 @@ compstmt_primary_start: compstmt: compstmt_start compstmt_nostart { RECHAIN_STMTS ($1, COMPOUND_BODY ($1)); - $$ = $2; } + $$ = $1; } ; /* Value is number of statements counted as of the closeparen. */ @@ -1808,13 +1818,8 @@ save_lineno: ; lineno_labeled_stmt: - save_filename save_lineno stmt - { } -/* | save_filename save_lineno error - { } -*/ - | save_filename save_lineno label lineno_labeled_stmt - { } + lineno_stmt + | lineno_label lineno_labeled_stmt ; /* Like lineno_labeled_stmt, but a block in C99. */ @@ -1826,12 +1831,25 @@ c99_block_lineno_labeled_stmt: lineno_stmt: save_filename save_lineno stmt - { } + { if ($3) + { + STMT_LINENO ($3) = $2; + /* ??? We currently have no way of recording + the filename for a statement. This probably + matters little in practice at the moment, + but I suspect that problems will ocurr when + doing inlining at the tree level. */ + } + } ; lineno_label: save_filename save_lineno label - { } + { if ($3) + { + STMT_LINENO ($3) = $2; + } + } ; select_or_iter_stmt: @@ -1900,25 +1918,26 @@ for_init_stmt: /* Parse a single real statement, not including any labels. */ stmt: compstmt - { stmt_count++; } + { stmt_count++; $$ = $1; } | expr ';' { stmt_count++; - c_expand_expr_stmt ($1); } + $$ = c_expand_expr_stmt ($1); } | c99_block_start select_or_iter_stmt c99_block_end { if (flag_isoc99) - RECHAIN_STMTS ($1, COMPOUND_BODY ($1)); } + RECHAIN_STMTS ($1, COMPOUND_BODY ($1)); + $$ = NULL_TREE; } | BREAK ';' { stmt_count++; - add_stmt (build_break_stmt ()); } + $$ = add_stmt (build_break_stmt ()); } | CONTINUE ';' { stmt_count++; - add_stmt (build_continue_stmt ()); } + $$ = add_stmt (build_continue_stmt ()); } | RETURN ';' { stmt_count++; - c_expand_return (NULL_TREE); } + $$ = c_expand_return (NULL_TREE); } | RETURN expr ';' { stmt_count++; - c_expand_return ($2); } + $$ = c_expand_return ($2); } | ASM_KEYWORD maybe_type_qual '(' expr ')' ';' { stmt_count++; STRIP_NOPS ($4); @@ -1930,30 +1949,30 @@ stmt: $4 = TREE_OPERAND ($4, 0); if (TREE_CHAIN ($4)) $4 = combine_strings ($4); - add_stmt (build_stmt (ASM_STMT, NULL_TREE, $4, - NULL_TREE, NULL_TREE, NULL_TREE)); + $$ = add_stmt (build_stmt (ASM_STMT, NULL_TREE, $4, + NULL_TREE, NULL_TREE, + NULL_TREE)); } else - error ("argument of `asm' is not a constant string"); } + { + error ("argument of `asm' is not a constant string"); + $$ = NULL_TREE; + } + } /* This is the case with just output operands. */ | ASM_KEYWORD maybe_type_qual '(' expr ':' asm_operands ')' ';' { stmt_count++; - c_expand_asm_operands ($4, $6, NULL_TREE, NULL_TREE, - $2 == ridpointers[(int)RID_VOLATILE], - input_filename, lineno); } + $$ = build_asm_stmt ($2, $4, $6, NULL_TREE, NULL_TREE); } /* This is the case with input operands as well. */ - | ASM_KEYWORD maybe_type_qual '(' expr ':' asm_operands ':' asm_operands ')' ';' + | ASM_KEYWORD maybe_type_qual '(' expr ':' asm_operands ':' + asm_operands ')' ';' { stmt_count++; - c_expand_asm_operands ($4, $6, $8, NULL_TREE, - $2 == ridpointers[(int)RID_VOLATILE], - input_filename, lineno); } + $$ = build_asm_stmt ($2, $4, $6, $8, NULL_TREE); } /* This is the case with clobbered registers as well. */ | ASM_KEYWORD maybe_type_qual '(' expr ':' asm_operands ':' asm_operands ':' asm_clobbers ')' ';' { stmt_count++; - c_expand_asm_operands ($4, $6, $8, $10, - $2 == ridpointers[(int)RID_VOLATILE], - input_filename, lineno); } + $$ = build_asm_stmt ($2, $4, $6, $8, $10); } | GOTO identifier ';' { tree decl; stmt_count++; @@ -1961,16 +1980,19 @@ stmt: if (decl != 0) { TREE_USED (decl) = 1; - add_stmt (build_stmt (GOTO_STMT, decl)); + $$ = add_stmt (build_stmt (GOTO_STMT, decl)); } + else + $$ = NULL_TREE; } | GOTO '*' expr ';' { if (pedantic) pedwarn ("ISO C forbids `goto *expr;'"); stmt_count++; $3 = convert (ptr_type_node, $3); - add_stmt (build_stmt (GOTO_STMT, $3)); } + $$ = add_stmt (build_stmt (GOTO_STMT, $3)); } | ';' + { $$ = NULL_TREE; } ; /* Any kind of label, including jump labels and case labels. @@ -1979,21 +2001,23 @@ stmt: label: CASE expr_no_commas ':' { stmt_count++; - do_case ($2, NULL_TREE); } + $$ = do_case ($2, NULL_TREE); } | CASE expr_no_commas ELLIPSIS expr_no_commas ':' { stmt_count++; - do_case ($2, $4); } + $$ = do_case ($2, $4); } | DEFAULT ':' { stmt_count++; - do_case (NULL_TREE, NULL_TREE); } + $$ = do_case (NULL_TREE, NULL_TREE); } | identifier save_filename save_lineno ':' maybe_attribute { tree label = define_label ($2, $3, $1); stmt_count++; if (label) { decl_attributes (label, $5, NULL_TREE); - add_stmt (build_stmt (LABEL_STMT, label)); + $$ = add_stmt (build_stmt (LABEL_STMT, label)); } + else + $$ = NULL_TREE; } ; diff --git a/gcc/c-semantics.c b/gcc/c-semantics.c index d5150ba45f4..4cf457279de 100644 --- a/gcc/c-semantics.c +++ b/gcc/c-semantics.c @@ -220,7 +220,9 @@ finish_stmt_tree (t) /* Build a generic statement based on the given type of node and arguments. Similar to `build_nt', except that we set - TREE_COMPLEXITY to be the current line number. */ + STMT_LINENO to be the current line number. */ +/* ??? This should be obsolete with the lineno_stmt productions + in the grammar. */ tree build_stmt VPARAMS ((enum tree_code code, ...)) @@ -241,7 +243,7 @@ build_stmt VPARAMS ((enum tree_code code, ...)) t = make_node (code); length = TREE_CODE_LENGTH (code); - TREE_COMPLEXITY (t) = lineno; + STMT_LINENO (t) = lineno; for (i = 0; i < length; i++) TREE_OPERAND (t, i) = va_arg (p, tree); diff --git a/gcc/c-tree.h b/gcc/c-tree.h index ee769e7a6ca..939ca3fafed 100644 --- a/gcc/c-tree.h +++ b/gcc/c-tree.h @@ -275,6 +275,8 @@ extern void pedwarn_c99 PARAMS ((const char *, ...)) ATTRIBUTE_PRINTF_1; extern tree c_start_case PARAMS ((tree)); extern void c_finish_case PARAMS ((void)); +extern tree build_asm_stmt PARAMS ((tree, tree, tree, + tree, tree)); /* Set to 0 at beginning of a function definition, set to 1 if a return statement that specifies a return value is seen. */ diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index 9122a756c83..d7efc2d56f7 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -6303,6 +6303,78 @@ process_init_element (value) } } +/* Build an asm-statement, whose components are a CV_QUALIFIER, a + STRING, some OUTPUTS, some INPUTS, and some CLOBBERS. */ + +tree +build_asm_stmt (cv_qualifier, string, outputs, inputs, clobbers) + tree cv_qualifier; + tree string; + tree outputs; + tree inputs; + tree clobbers; +{ + tree tail; + + if (TREE_CHAIN (string)) + string = combine_strings (string); + if (TREE_CODE (string) != STRING_CST) + { + error ("asm template is not a string constant"); + return NULL_TREE; + } + + if (cv_qualifier != NULL_TREE + && cv_qualifier != ridpointers[(int) RID_VOLATILE]) + { + warning ("%s qualifier ignored on asm", + IDENTIFIER_POINTER (cv_qualifier)); + cv_qualifier = NULL_TREE; + } + + /* We can remove output conversions that change the type, + but not the mode. */ + for (tail = outputs; tail; tail = TREE_CHAIN (tail)) + { + tree output = TREE_VALUE (tail); + + STRIP_NOPS (output); + TREE_VALUE (tail) = output; + + /* Allow conversions as LHS here. build_modify_expr as called below + will do the right thing with them. */ + while (TREE_CODE (output) == NOP_EXPR + || TREE_CODE (output) == CONVERT_EXPR + || TREE_CODE (output) == FLOAT_EXPR + || TREE_CODE (output) == FIX_TRUNC_EXPR + || TREE_CODE (output) == FIX_FLOOR_EXPR + || TREE_CODE (output) == FIX_ROUND_EXPR + || TREE_CODE (output) == FIX_CEIL_EXPR) + output = TREE_OPERAND (output, 0); + + lvalue_or_else (TREE_VALUE (tail), "invalid lvalue in asm statement"); + } + + /* Remove output conversions that change the type but not the mode. */ + for (tail = outputs; tail; tail = TREE_CHAIN (tail)) + { + tree output = TREE_VALUE (tail); + STRIP_NOPS (output); + TREE_VALUE (tail) = output; + } + + /* Perform default conversions on array and function inputs. + Don't do this for other types as it would screw up operands + expected to be in memory. */ + for (tail = inputs; tail; tail = TREE_CHAIN (tail)) + if (TREE_CODE (TREE_TYPE (TREE_VALUE (tail))) == ARRAY_TYPE + || TREE_CODE (TREE_TYPE (TREE_VALUE (tail))) == FUNCTION_TYPE) + TREE_VALUE (tail) = default_conversion (TREE_VALUE (tail)); + + return add_stmt (build_stmt (ASM_STMT, cv_qualifier, string, + outputs, inputs, clobbers)); +} + /* Expand an ASM statement with operands, handling output operands that are not variables or INDIRECT_REFS by transforming such cases into cases that expand_asm_operands can handle. @@ -6322,57 +6394,12 @@ c_expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line) register tree *o = (tree *) alloca (noutputs * sizeof (tree)); register tree tail; - if (TREE_CODE (string) == ADDR_EXPR) - string = TREE_OPERAND (string, 0); - if (last_tree && TREE_CODE (string) != STRING_CST) - { - error ("asm template is not a string constant"); - return; - } - /* Record the contents of OUTPUTS before it is modified. */ for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++) - { - tree output = TREE_VALUE (tail); + o[i] = TREE_VALUE (tail); - /* We can remove conversions that just change the type, not the mode. */ - STRIP_NOPS (output); - o[i] = output; - - /* Allow conversions as LHS here. build_modify_expr as called below - will do the right thing with them. */ - while (TREE_CODE (output) == NOP_EXPR - || TREE_CODE (output) == CONVERT_EXPR - || TREE_CODE (output) == FLOAT_EXPR - || TREE_CODE (output) == FIX_TRUNC_EXPR - || TREE_CODE (output) == FIX_FLOOR_EXPR - || TREE_CODE (output) == FIX_ROUND_EXPR - || TREE_CODE (output) == FIX_CEIL_EXPR) - output = TREE_OPERAND (output, 0); - - if (last_tree) - lvalue_or_else (o[i], "invalid lvalue in asm statement"); - } - - /* Perform default conversions on array and function inputs. */ - /* Don't do this for other types-- - it would screw up operands expected to be in memory. */ - for (i = 0, tail = inputs; tail; tail = TREE_CHAIN (tail), i++) - if (TREE_CODE (TREE_TYPE (TREE_VALUE (tail))) == ARRAY_TYPE - || TREE_CODE (TREE_TYPE (TREE_VALUE (tail))) == FUNCTION_TYPE) - TREE_VALUE (tail) = default_conversion (TREE_VALUE (tail)); - - if (last_tree) - { - add_stmt (build_stmt (ASM_STMT, - vol ? ridpointers[(int) RID_VOLATILE] : NULL_TREE, - string, outputs, inputs, clobbers)); - return; - } - - /* Generate the ASM_OPERANDS insn; - store into the TREE_VALUEs of OUTPUTS some trees for - where the values were actually stored. */ + /* Generate the ASM_OPERANDS insn; store into the TREE_VALUEs of + OUTPUTS some trees for where the values were actually stored. */ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line); /* Copy all the intermediate outputs into the specified outputs. */ @@ -6410,7 +6437,7 @@ c_expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line) RETVAL is the expression for what to return, or a null pointer for `return;' with no value. */ -void +tree c_expand_return (retval) tree retval; { @@ -6440,7 +6467,7 @@ c_expand_return (retval) tree inner; if (t == error_mark_node) - return; + return NULL_TREE; inner = t = convert (TREE_TYPE (res), t); @@ -6499,7 +6526,7 @@ c_expand_return (retval) current_function_returns_value = 1; } - add_stmt (build_return_stmt (retval)); + return add_stmt (build_return_stmt (retval)); } struct c_switch { @@ -6581,20 +6608,27 @@ c_start_case (exp) /* Process a case label. */ -void +tree do_case (low_value, high_value) tree low_value; tree high_value; { + tree label = NULL_TREE; + if (switch_stack) - c_add_case_label (switch_stack->cases, - SWITCH_COND (switch_stack->switch_stmt), - low_value, - high_value); + { + label = c_add_case_label (switch_stack->cases, + SWITCH_COND (switch_stack->switch_stmt), + low_value, high_value); + if (label == error_mark_node) + label = NULL_TREE; + } else if (low_value) error ("case label not within a switch statement"); else error ("`default' label not within a switch statement"); + + return label; } /* Finish the switch statement. */