📄 toplev.c
字号:
/* If stack_reg dump desired, open the output file. */ if (stack_reg_dump) stack_reg_dump_file = open_dump_file (dump_base_name, ".stack");#endif /* Open assembler code output file. */ if (! name_specified && asm_file_name == 0) asm_out_file = stdout; else { int len = strlen (dump_base_name); register char *dumpname = (char *) xmalloc (len + 6); strcpy (dumpname, dump_base_name); strip_off_ending (dumpname, len); strcat (dumpname, ".s"); if (asm_file_name == 0) { asm_file_name = (char *) xmalloc (strlen (dumpname) + 1); strcpy (asm_file_name, dumpname); } if (!strcmp (asm_file_name, "-")) asm_out_file = stdout; else asm_out_file = fopen (asm_file_name, "w"); if (asm_out_file == 0) pfatal_with_name (asm_file_name); }#ifdef IO_BUFFER_SIZE setvbuf (asm_out_file, (char *) xmalloc (IO_BUFFER_SIZE), _IOFBF, IO_BUFFER_SIZE);#endif input_filename = name; /* Put an entry on the input file stack for the main input file. */ input_file_stack = (struct file_stack *) xmalloc (sizeof (struct file_stack)); input_file_stack->next = 0; input_file_stack->name = input_filename; /* Perform language-specific initialization. This may set main_input_filename. */ lang_init (); /* If the input doesn't start with a #line, use the input name as the official input file name. */ if (main_input_filename == 0) main_input_filename = name; if (!output_bytecode) { ASM_FILE_START (asm_out_file); } /* Output something to inform GDB that this compilation was by GCC. Also serves to tell GDB file consists of bytecodes. */ if (output_bytecode) fprintf (asm_out_file, "bc_gcc2_compiled.:\n"); else {#ifndef ASM_IDENTIFY_GCC fprintf (asm_out_file, "gcc2_compiled.:\n");#else ASM_IDENTIFY_GCC (asm_out_file);#endif } /* Output something to identify which front-end produced this file. */#ifdef ASM_IDENTIFY_LANGUAGE ASM_IDENTIFY_LANGUAGE (asm_out_file);#endif if (output_bytecode) { if (profile_flag || profile_block_flag) error ("profiling not supported in bytecode compilation"); } else { /* ??? Note: There used to be a conditional here to call assemble_zeros without fail if DBX_DEBUGGING_INFO is defined. This was to guarantee separation between gcc_compiled. and the first function, for the sake of dbx on Suns. However, having the extra zero here confused the Emacs code for unexec, and might confuse other programs too. Therefore, I took out that change. In future versions we should find another way to solve that dbx problem. -- rms, 23 May 93. */ /* Don't let the first function fall at the same address as gcc_compiled., if profiling. */ if (profile_flag || profile_block_flag) assemble_zeros (UNITS_PER_WORD); } /* If dbx symbol table desired, initialize writing it and output the predefined types. */#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO) if (write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG) TIMEVAR (symout_time, dbxout_init (asm_out_file, main_input_filename, getdecls ()));#endif#ifdef SDB_DEBUGGING_INFO if (write_symbols == SDB_DEBUG) TIMEVAR (symout_time, sdbout_init (asm_out_file, main_input_filename, getdecls ()));#endif#ifdef DWARF_DEBUGGING_INFO if (write_symbols == DWARF_DEBUG) TIMEVAR (symout_time, dwarfout_init (asm_out_file, main_input_filename));#endif /* Initialize yet another pass. */ if (!output_bytecode) init_final (main_input_filename); start_time = get_run_time (); /* Call the parser, which parses the entire file (calling rest_of_compilation for each function). */ if (yyparse () != 0) { if (errorcount == 0) fprintf (stderr, "Errors detected in input file (your bison.simple is out of date)"); /* In case there were missing closebraces, get us back to the global binding level. */ while (! global_bindings_p ()) poplevel (0, 0, 0); } /* Compilation is now finished except for writing what's left of the symbol table output. */ parse_time += get_run_time () - start_time; parse_time -= integration_time; parse_time -= varconst_time; globals = getdecls (); /* Really define vars that have had only a tentative definition. Really output inline functions that must actually be callable and have not been output so far. */ { int len = list_length (globals); tree *vec = (tree *) alloca (sizeof (tree) * len); int i; tree decl; int reconsider = 1; /* Process the decls in reverse order--earliest first. Put them into VEC from back to front, then take out from front. */ for (i = 0, decl = globals; i < len; i++, decl = TREE_CHAIN (decl)) vec[len - i - 1] = decl; for (i = 0; i < len; i++) { decl = vec[i]; /* We're not deferring this any longer. */ DECL_DEFER_OUTPUT (decl) = 0; if (TREE_CODE (decl) == VAR_DECL && DECL_SIZE (decl) == 0 && incomplete_decl_finalize_hook != 0) (*incomplete_decl_finalize_hook) (decl); } /* Now emit any global variables or functions that we have been putting off. We need to loop in case one of the things emitted here references another one which comes earlier in the list. */ while (reconsider) { reconsider = 0; for (i = 0; i < len; i++) { decl = vec[i]; if (TREE_ASM_WRITTEN (decl) || DECL_EXTERNAL (decl)) continue; /* Don't write out static consts, unless we still need them. We also keep static consts if not optimizing (for debugging). ??? They might be better written into the debug information. This is possible when using DWARF. A language processor that wants static constants to be always written out (even if it is not used) is responsible for calling rest_of_decl_compilation itself. E.g. the C front-end calls rest_of_decl_compilation from finish_decl. One motivation for this is that is conventional in some environments to write things like: static const char rcsid[] = "... version string ..."; intending to force the string to be in the executable. A language processor that would prefer to have unneeded static constants "optimized away" would just defer writing them out until here. E.g. C++ does this, because static constants are often defined in header files. ??? A tempting alternative (for both C and C++) would be to force a constant to be written if and only if it is defined in a main file, as opposed to an include file. */ if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl) && (! TREE_READONLY (decl) || TREE_PUBLIC (decl) || !optimize || TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))) { reconsider = 1; rest_of_decl_compilation (decl, NULL_PTR, 1, 1); } if (TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl) != 0 && DECL_SAVED_INSNS (decl) != 0 && (flag_keep_inline_functions || TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))) { reconsider = 1; temporary_allocation (); output_inline_function (decl); permanent_allocation (1); } } } for (i = 0; i < len; i++) { decl = vec[i]; if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl) && ! TREE_ASM_WRITTEN (decl)) /* Cancel the RTL for this decl so that, if debugging info output for global variables is still to come, this one will be omitted. */ DECL_RTL (decl) = NULL; /* Warn about any function declared static but not defined. We don't warn about variables, because many programs have static variables that exist only to get some text into the object file. */ if (TREE_CODE (decl) == FUNCTION_DECL && (warn_unused || TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))) && DECL_INITIAL (decl) == 0 && DECL_EXTERNAL (decl) && ! TREE_PUBLIC (decl)) { pedwarn_with_decl (decl, "`%s' declared `static' but never defined"); /* This symbol is effectively an "extern" declaration now. */ TREE_PUBLIC (decl) = 1; assemble_external (decl); } /* Warn about static fns or vars defined but not used, but not about inline functions or static consts since defining those in header files is normal practice. */ if (warn_unused && ((TREE_CODE (decl) == FUNCTION_DECL && ! DECL_INLINE (decl)) || (TREE_CODE (decl) == VAR_DECL && ! TREE_READONLY (decl))) && ! DECL_IN_SYSTEM_HEADER (decl) && ! DECL_EXTERNAL (decl) && ! TREE_PUBLIC (decl) && ! TREE_USED (decl) && ! DECL_REGISTER (decl) /* The TREE_USED bit for file-scope decls is kept in the identifier, to handle multiple external decls in different scopes. */ && ! TREE_USED (DECL_NAME (decl))) warning_with_decl (decl, "`%s' defined but not used");#ifdef SDB_DEBUGGING_INFO /* The COFF linker can move initialized global vars to the end. And that can screw up the symbol ordering. By putting the symbols in that order to begin with, we avoid a problem. mcsun!unido!fauern!tumuc!pes@uunet.uu.net. */ if (write_symbols == SDB_DEBUG && TREE_CODE (decl) == VAR_DECL && TREE_PUBLIC (decl) && DECL_INITIAL (decl) && ! DECL_EXTERNAL (decl) && DECL_RTL (decl) != 0) TIMEVAR (symout_time, sdbout_symbol (decl, 0)); /* Output COFF information for non-global file-scope initialized variables. */ if (write_symbols == SDB_DEBUG && TREE_CODE (decl) == VAR_DECL && DECL_INITIAL (decl) && ! DECL_EXTERNAL (decl) && DECL_RTL (decl) != 0 && GET_CODE (DECL_RTL (decl)) == MEM) TIMEVAR (symout_time, sdbout_toplevel_data (decl));#endif /* SDB_DEBUGGING_INFO */#ifdef DWARF_DEBUGGING_INFO /* Output DWARF information for file-scope tentative data object declarations, file-scope (extern) function declarations (which had no corresponding body) and file-scope tagged type declarations and definitions which have not yet been forced out. */ if (write_symbols == DWARF_DEBUG && (TREE_CODE (decl) != FUNCTION_DECL || !DECL_INITIAL (decl))) TIMEVAR (symout_time, dwarfout_file_scope_decl (decl, 1));#endif } } /* Write out any pending weak symbol declarations. */ weak_finish (); /* Do dbx symbols */#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO) if (write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG) TIMEVAR (symout_time, { dbxout_finish (asm_out_file, main_input_filename); });#endif#ifdef DWARF_DEBUGGING_INFO if (write_symbols == DWARF_DEBUG) TIMEVAR (symout_time, { dwarfout_finish (); });#endif /* Output some stuff at end of file if nec. */ if (!output_bytecode) { end_final (main_input_filename);#ifdef ASM_FILE_END ASM_FILE_END (asm_out_file);#endif } /* Language-specific end of compilation actions. */ lang_finish (); if (output_bytecode) bc_write_file (asm_out_file); /* Close the dump files. */ if (flag_gen_aux_info) { fclose (aux_info_file); if (errorcount) unlink (aux_info_file_name); } if (rtl_dump) fclose (rtl_dump_file); if (jump_opt_dump) fclose (jump_opt_dump_file); if (cse_dump) fclose (cse_dump_file); if (loop_dump) fclose (loop_dump_file); if (cse2_dump) fclose (cse2_dump_file); if (flow_dump) fclose (flow_dump_file); if (combine_dump) { dump_combine_total_stats (combine_dump_file); fclose (combine_dump_file); } if (sched_dump) fclose (sched_dump_file); if (local_reg_dump) fclose (local_reg_dump_file); if (global_reg_dump) fclose (global_reg_dump_file); if (sched2_dump) fclose (sched2_dump_file); if (jump2_opt_dump) fclose (jump2_opt_dump_file); if (dbr_sched_dump) fclose (dbr_sched_dump_file);#ifdef STACK_REGS if (stack_reg_dump) fclose (stack_reg_dump_file);#endif /* Close non-debugging input and output files. Take special care to note whether fclose returns an error, since the pages might still be on the buffer chain while the file is open. */ fclose (finput); if (ferror (asm_out_file) != 0 || fclose (asm_out_file) != 0) fatal_io_error (asm_file_name); /* Print the times. */ if (! quiet_flag) { fprintf (stderr,"\n"); print_time ("parse", parse_time); if (!output_bytecode) { print_time ("integration", integration_time); print_time ("jump", jump_time); print_time ("cse", cse_time); print_time ("loop", loop_time); print_time ("cse2", cse2_time); print_time ("flow", flow_time); print_time ("combine", combine_time); print_time ("sched", sched_time); print_time ("local-alloc", local_alloc_time); print_time ("global-alloc", global_alloc_time); print_time ("sched2", sched2_time); print_time ("dbranch", dbr_sched_time); print_time ("shorten-branch", shorten_branch_time); print_time ("stack-reg", stack_reg_time); print_time ("final", final_time); print_time ("varconst", varconst_time); print_time ("symout", symout_time); print_time ("dump", dump_time); } }}/* This is called from various places for FUNCTION_DECL, VAR_DECL, and TYPE_DECL nodes. This does nothing for local (non-static) variables. Otherwise, it sets up the RTL and outputs any assembler code (label definition, storage allocation and initialization). DECL is the declaration. If ASMSPEC is nonzero, it specifies the assembler symbol name to be used. TOP_LEVEL is nonzero if this declaration is not within a function. */voidrest_of_decl_compilation (decl, asmspec, top_level, at_end) tree decl; char *asmspec; int top_level; int at_end;{ /* Declarations of variables, and of functions defined elsewhere. *//* The most obvious approach, to put an #ifndef around where this macro is used, doesn't work since it's inside a macro call. */#ifndef ASM_FINISH_DECLARE_OBJECT#define ASM_FINISH_DECLARE_OBJECT(FILE, DECL, TOP, END)#endif /* Forward declarations for nested functions are not "external", but we need to treat them as if they were. */ if (TREE_STATIC (decl) || DECL_EXTERNAL (decl) || TREE_CODE (decl) == FUNCTION_DECL) TIMEVAR (varconst_time, { make_decl_rtl (decl, asmspec, top_level); /* Initialized extern variable exists to be replaced with its value, or represents something that will be output in another file. */ if (! (TREE_CODE (decl) == VAR_DECL && DECL_EXTERNAL (decl) && TREE_READONLY (decl) && DECL_INITIAL (decl) != 0 && DECL_INITIAL (decl) != error_mark_node)) /* Don't output anything when a tentative file-scope definition is seen. But at end of compilation, do output code for them. */ if (! (! at_end && top_level && (DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node))) assemble_variable (decl, top_level, at_end, 0); if (decl == last_assemble_variable_decl) { ASM_FINISH_DECLARE_OBJECT (asm_out_file, decl, top_level, at_end); } }); else if (DECL_REGISTER (decl) && asmspec != 0) { if (decode_reg_name (asmspec) >= 0) { DECL_RTL (decl) = 0; make_decl_rtl (decl, asmspec, top_level); } else error ("invalid register name `%s' for register variable", asmspec); }#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO) else if ((write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG) && TREE_CODE (decl) == TYPE_DECL) TIMEVAR (symout_time, dbxout_symbol (decl, 0));#endif#ifdef SDB_DEBUGGING_INFO else if (write_symbols == SDB_
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -