📄 toplev.c
字号:
else { register char *dumpname = (char *) xmalloc (dump_base_name_length + 6); int len = strlen (dump_base_name); strcpy (dumpname, dump_base_name); if (len > 2 && ! strcmp (".c", dumpname + len - 2)) dumpname[len - 2] = 0; else if (len > 2 && ! strcmp (".i", dumpname + len - 2)) dumpname[len - 2] = 0; else if (len > 3 && ! strcmp (".co", dumpname + len - 3)) dumpname[len - 3] = 0; strcat (dumpname, ".s"); if (asm_file_name == 0) { asm_file_name = (char *) malloc (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); } input_filename = name; /* the beginning of the file is a new line; check for # */ /* With luck, we discover the real source file's name from that and put it in input_filename. */ ungetc (check_newline (), finput); /* 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; /* 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; ASM_FILE_START (asm_out_file); /* Output something to inform GDB that this compilation was by GCC. */#ifndef ASM_IDENTIFY_GCC fprintf (asm_out_file, "gcc_compiled.:\n");#else ASM_IDENTIFY_GCC (asm_out_file);#endif /* If GDB symbol table desired, open the GDB symbol output file. */ if (write_symbols == GDB_DEBUG) { register char *dumpname = (char *) xmalloc (dump_base_name_length + 6); int len = strlen (dump_base_name); strcpy (dumpname, dump_base_name); if (len > 2 && ! strcmp (".c", dumpname + len - 2)) dumpname[len - 2] = 0; else if (len > 2 && ! strcmp (".i", dumpname + len - 2)) dumpname[len - 2] = 0; else if (len > 3 && ! strcmp (".co", dumpname + len - 3)) dumpname[len - 3] = 0; strcat (dumpname, ".sym"); if (sym_file_name == 0) sym_file_name = dumpname; symout_init (sym_file_name, asm_out_file, main_input_filename); } /* If dbx symbol table desired, initialize writing it and output the predefined types. */#ifdef DBX_DEBUGGING_INFO if (write_symbols == DBX_DEBUG) dbxout_init (asm_out_file, main_input_filename);#endif#ifdef SDB_DEBUGGING_INFO if (write_symbols == SDB_DEBUG) sdbout_init (asm_out_file, main_input_filename);#endif /* Initialize yet another pass. */ init_final (main_input_filename); start_time = gettime (); /* Call the parser, which parses the entire file (calling rest_of_compilation for each function). */ yyparse (); /* Compilation is now finished except for writing what's left of the symbol table output. */ parse_time += gettime () - 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. */ { tree decl; for (decl = globals; decl; decl = TREE_CHAIN (decl)) { if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl) && ! TREE_ASM_WRITTEN (decl)) { /* Don't write out static consts, unless we used them. (This used to write them out only if the address was taken, but that was wrong; if the variable was simply referred to, it still needs to exist or else it will be undefined in the linker.) */ if (! TREE_READONLY (decl) || TREE_USED (decl) || TREE_PUBLIC (decl) || TREE_ADDRESSABLE (decl)) rest_of_decl_compilation (decl, 0, 1, 1); /* Otherwise maybe mention them just for the debugger. */#ifdef DBX_DEBUGGING_INFO else if (DECL_INITIAL (decl) && write_symbols == DBX_DEBUG) TIMEVAR (varconst_time, dbxout_symbol (decl, 0));#endif#ifdef SDB_DEBUGGING_INFO else if (DECL_INITIAL (decl) && write_symbols == SDB_DEBUG) TIMEVAR (varconst_time, sdbout_symbol (decl, 0));#endif } if (TREE_CODE (decl) == FUNCTION_DECL && ! TREE_ASM_WRITTEN (decl) && DECL_INITIAL (decl) != 0 && TREE_ADDRESSABLE (decl) && ! TREE_EXTERNAL (decl)) output_inline_function (decl); /* Warn about any function declared static but not defined. */ if (warn_unused && TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl) == 0 && TREE_EXTERNAL (decl) && ! TREE_PUBLIC (decl)) warning_with_decl (decl, "`%s' declared but never defined"); /* Warn about statics fns or vars defined but not used, but not about inline functions since unused inline statics is normal practice. */ if (warn_unused && (TREE_CODE (decl) == FUNCTION_DECL || TREE_CODE (decl) == VAR_DECL) && ! TREE_EXTERNAL (decl) && ! TREE_PUBLIC (decl) && ! TREE_USED (decl) && ! TREE_INLINE (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"); } } /* Do dbx symbols */#ifdef DBX_DEBUGGING_INFO if (write_symbols == DBX_DEBUG) TIMEVAR (symout_time, { dbxout_tags (gettags ()); dbxout_types (get_permanent_types ()); });#endif#ifdef SDB_DEBUGGING_INFO if (write_symbols == SDB_DEBUG) TIMEVAR (symout_time, { tree decl; sdbout_tags (gettags ()); sdbout_types (get_permanent_types ()); /* Output first static file-scope vars, then global ones. */ for (decl = globals; decl; decl = TREE_CHAIN (decl)) if (TREE_CODE (decl) == VAR_DECL && !TREE_PUBLIC (decl)) sdbout_symbol (decl, 1); for (decl = globals; decl; decl = TREE_CHAIN (decl)) if (TREE_CODE (decl) == VAR_DECL && TREE_PUBLIC (decl)) sdbout_symbol (decl, 1); });#endif /* Do gdb symbols */ if (write_symbols == GDB_DEBUG) TIMEVAR (symout_time, { struct stat statbuf; fstat (fileno (finput), &statbuf); symout_types (get_permanent_types ()); symout_top_blocks (globals, gettags ()); symout_finish (name, statbuf.st_ctime); }); /* Output some stuff at end of file if nec. */ end_final (main_input_filename);#ifdef ASM_FILE_END ASM_FILE_END (asm_out_file);#endif /* Close the dump files. */ 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 (flow_dump) fclose (flow_dump_file); if (combine_dump) { dump_combine_total_stats (combine_dump_file); fclose (combine_dump_file); } if (local_reg_dump) fclose (local_reg_dump_file); if (global_reg_dump) fclose (global_reg_dump_file); if (jump2_opt_dump) fclose (jump2_opt_dump_file); if (dbr_sched_dump) fclose (dbr_sched_dump_file); /* 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); print_time ("integration", integration_time); print_time ("jump", jump_time); print_time ("cse", cse_time); print_time ("loop", loop_time); print_time ("flow", flow_time); print_time ("combine", combine_time); print_time ("local-alloc", local_alloc_time); print_time ("global-alloc", global_alloc_time); print_time ("dbranch", dbr_sched_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 finish_decl (within yyparse) for each declaration of a function or variable. This does nothing for automatic 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. */ if (TREE_STATIC (decl) || TREE_EXTERNAL (decl)) TIMEVAR (varconst_time, { make_decl_rtl (decl, asmspec, top_level); /* 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, write_symbols, at_end); }); else if (TREE_REGDECL (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); }#ifdef DBX_DEBUGGING_INFO else if (write_symbols == DBX_DEBUG && TREE_CODE (decl) == TYPE_DECL) TIMEVAR (varconst_time, dbxout_symbol (decl, 0));#endif#ifdef SDB_DEBUGGING_INFO else if (write_symbols == SDB_DEBUG && top_level && TREE_CODE (decl) == TYPE_DECL) TIMEVAR (varconst_time, sdbout_symbol (decl, 0));#endif if (top_level) { if (write_symbols == GDB_DEBUG) { TIMEVAR (symout_time, { /* The initizations make types when they contain string constants. The types are on the temporary obstack, so output them now before they go away. */ symout_types (get_temporary_types ()); }); } else /* Clean out the temporary type list, since the types will go away. */ get_temporary_types (); }}/* This is called from finish_function (within yyparse) after each top-level definition is parsed. It is supposed to compile that function or variable and output the assembler code for it. After we return, the tree storage is freed. */voidrest_of_compilation (decl) tree decl;{ register rtx insns; int start_time = gettime (); int tem; /* If we are reconsidering an inline function at the end of compilation, skip the stuff for making it inline. */ if (DECL_SAVED_INSNS (decl) == 0) { /* If requested, consider whether to make this function inline. */ if (flag_inline_functions || TREE_INLINE (decl)) { TIMEVAR (integration_time, { int specd = TREE_INLINE (decl); char *lose = function_cannot_inline_p (decl); if (lose != 0 && specd) warning_with_decl (decl, lose); if (lose == 0) save_for_inline (decl); else TREE_INLINE (decl) = 0; }); } insns = get_insns (); /* Dump the rtl code if we are dumping rtl. */ if (rtl_dump) TIMEVAR (dump_time, { fprintf (rtl_dump_file, "\n;; Function %s\n\n", IDENTIFIER_POINTER (DECL_NAME (decl))); if (DECL_SAVED_INSNS (decl)) fprintf (rtl_dump_file, ";; (integrable)\n\n"); print_rtl (rtl_dump_file, insns); fflush (rtl_dump_file); }); /* If function is inline, and we don't yet know whether to compile it by itself, defer decision till end of compilation. finish_compilation will call rest_of_compilation again for those functions that need to be output. */ if (((! TREE_PUBLIC (decl) && ! TREE_ADDRESSABLE (decl) && ! flag_keep_inline_functions) || TREE_EXTERNAL (decl)) && TREE_INLINE (decl)) goto exit_rest_of_compilation; } if (rtl_dump_and_exit || flag_syntax_only) { get_temporary_types (); goto exit_rest_of_compilation; } TREE_ASM_WRITTEN (decl) = 1; insns = get_insns (); /* Copy any shared structure that should not be shared. */ unshare_all_rtl (insns); /* See if we have allocated stack slots that are not directly addressable. If so, scan all the insns and create explicit address computation for all references to such slots. *//* fixup_stack_slots (); */ /* Do jump optimization the first time, if -opt. Also do it if -W, but in that case it doesn't change the rtl code, it only computes whether control can drop off the end of the function. */ if (optimize || extra_warnings || warn_return_type /* If function is `volatile', we should warn if it tries to return. */ || TREE_THIS_VOLATILE (decl)) TIMEVAR (jump_time, jump_optimize (insns, 0, 0)); /* Dump rtl code after jump, if we are doing that. */ if (jump_opt_dump) TIMEVAR (dump_time, { fprintf (jump_opt_dump_file, "\n;; Function %s\n\n", IDENTIFIER_POINTER (DECL_NAME (decl))); print_rtl (jump_opt_dump_file, insns); fflush (jump_opt_dump_file); }); /* Perform common subexpression elimination. Nonzero value from `cse_main' means that jumps were simplified and some code may now be unreachable, so do jump optimization again. */ if (optimize) { TIMEVAR (cse_time, reg_scan (insns, max_reg_num (), 0)); TIMEVAR (cse_time, tem = cse_main (insns, max_reg_num ())); if (tem) TIMEVAR (jump_time, jump_optimize (insns, 0, 0)); } /* Dump rtl code after cse, if we are doing that. */ if (cse_dump) TIMEVAR (dump_time, { fprintf (cse_dump_file, "\n;; Function %s\n\n", IDENTIFIER_POINTER (DECL_NAME (decl))); print_rtl (cse_dump_file, insns); fflush (cse_dump_file); }); if (loop_dump) TIMEVAR (dump_time, { fprintf (loop_dump_file, "\n;; Function %s\n\n", IDENTIFIER_POINTER (DECL_NAME (decl))); }); /* Move constant computations out of loops. */ if (optimize) { TIMEVAR (loop_time, { reg_scan (insns, max_reg_num (), 1); loop_optimize (insns, loop_dump ? loop_dump_file : 0); }); } /* Dump rtl code after loop opt, if we are doing that. */ if (loop_dump) TIMEVAR (dump_time, { print_rtl (loop_dump_file, insns); fflush (loop_dump_file); }); /* Now we choose between stupid (pcc-like) register allocation (if we got the -noreg switch and not -opt) and smart register allocation. */ if (optimize) /* Stupid allocation probably won't work */ obey_regdecls = 0; /* if optimizations being done. */ regclass_init (); /* Print function header into flow dump now because doing the flow analysis makes some of the dump. */ if (flow_dump) TIMEVAR (dump_time, { fprintf (flow_dump_file, "\n;; Function %s\n\n", IDENTIFIER_POINTER (DECL_NAME (decl))); }); if (obey_regdecls) { TIMEVAR (flow_time, { regclass (insns, max_reg_num ()); stupid_life_analysis (insns, max_reg_num (), flow_dump_file); }); } else { /* Do control and data flow analysis,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -