📄 final.c
字号:
max_uid = INSN_UID (insn); max_uid++; insn_lengths = (short *) oballoc (max_uid * sizeof (short)); insn_addresses = (int *) oballoc (max_uid * sizeof (int)); varying_length = (char *) oballoc (max_uid * sizeof (char)); /* Compute initial lengths, addresses, and varying flags for each insn. */ for (insn_current_address = FIRST_INSN_ADDRESS, insn = first; insn != 0; insn_current_address += insn_lengths[uid], insn = NEXT_INSN (insn)) { uid = INSN_UID (insn); insn_addresses[uid] = insn_current_address; insn_lengths[uid] = 0; varying_length[uid] = 0; if (GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER || GET_CODE (insn) == CODE_LABEL) continue; body = PATTERN (insn); if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC) { /* This only takes room if read-only data goes into the text section. */#if !defined(READONLY_DATA_SECTION) || defined(JUMP_TABLES_IN_TEXT_SECTION) int unitsize = GET_MODE_SIZE (GET_MODE (body)); insn_lengths[uid] = (XVECLEN (body, GET_CODE (body) == ADDR_DIFF_VEC) * GET_MODE_SIZE (GET_MODE (body))); /* Account for possible alignment. */ insn_lengths[uid] += unitsize - (insn_current_address & (unitsize - 1));#else ;#endif } else if (asm_noperands (body) >= 0) insn_lengths[uid] = asm_insn_count (body) * insn_default_length (insn); else if (GET_CODE (body) == SEQUENCE) { int i; int const_delay_slots;#ifdef DELAY_SLOTS const_delay_slots = const_num_delay_slots (XVECEXP (body, 0, 0));#else const_delay_slots = 0;#endif /* Inside a delay slot sequence, we do not do any branch shortening if the shortening could change the number of delay slots of the branch. */ for (i = 0; i < XVECLEN (body, 0); i++) { rtx inner_insn = XVECEXP (body, 0, i); int inner_uid = INSN_UID (inner_insn); int inner_length; if (asm_noperands (PATTERN (XVECEXP (body, 0, i))) >= 0) inner_length = (asm_insn_count (PATTERN (inner_insn)) * insn_default_length (inner_insn)); else inner_length = insn_default_length (inner_insn); insn_lengths[inner_uid] = inner_length; if (const_delay_slots) { if ((varying_length[inner_uid] = insn_variable_length_p (inner_insn)) != 0) varying_length[uid] = 1; insn_addresses[inner_uid] = (insn_current_address + insn_lengths[uid]); } else varying_length[inner_uid] = 0; insn_lengths[uid] += inner_length; } } else if (GET_CODE (body) != USE && GET_CODE (body) != CLOBBER) { insn_lengths[uid] = insn_default_length (insn); varying_length[uid] = insn_variable_length_p (insn); } /* If needed, do any adjustment. */#ifdef ADJUST_INSN_LENGTH ADJUST_INSN_LENGTH (insn, insn_lengths[uid]);#endif } /* Now loop over all the insns finding varying length insns. For each, get the current insn length. If it has changed, reflect the change. When nothing changes for a full pass, we are done. */ while (something_changed) { something_changed = 0; for (insn_current_address = FIRST_INSN_ADDRESS, insn = first; insn != 0; insn = NEXT_INSN (insn)) { int new_length; uid = INSN_UID (insn); insn_addresses[uid] = insn_current_address; if (! varying_length[uid]) { insn_current_address += insn_lengths[uid]; continue; } if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE) { int i; body = PATTERN (insn); new_length = 0; for (i = 0; i < XVECLEN (body, 0); i++) { rtx inner_insn = XVECEXP (body, 0, i); int inner_uid = INSN_UID (inner_insn); int inner_length; insn_addresses[inner_uid] = insn_current_address; inner_length = insn_current_length (inner_insn); if (inner_length != insn_lengths[inner_uid]) { insn_lengths[inner_uid] = inner_length; something_changed = 1; } insn_current_address += insn_lengths[inner_uid]; new_length += inner_length; } } else { new_length = insn_current_length (insn); insn_current_address += new_length; } if (new_length != insn_lengths[uid]) { insn_lengths[uid] = new_length; something_changed = 1; } } }#endif /* HAVE_ATTR_length */}#ifdef HAVE_ATTR_length/* Given the body of an INSN known to be generated by an ASM statement, return the number of machine instructions likely to be generated for this insn. This is used to compute its length. */static intasm_insn_count (body) rtx body;{ char *template; int count = 1; for (template = decode_asm_operands (body, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR); *template; template++) if (*template == ';' || *template == '\n') count++; return count;}#endif/* Output assembler code for the start of a function, and initialize some of the variables in this file for the new function. The label for the function and associated assembler pseudo-ops have already been output in `assemble_start_function'. FIRST is the first insn of the rtl for the function being compiled. FILE is the file to write assembler code to. OPTIMIZE is nonzero if we should eliminate redundant test and compare insns. */voidfinal_start_function (first, file, optimize) rtx first; FILE *file; int optimize;{ block_depth = 0; this_is_asm_operands = 0;#ifdef NON_SAVING_SETJMP /* A function that calls setjmp should save and restore all the call-saved registers on a system where longjmp clobbers them. */ if (NON_SAVING_SETJMP && current_function_calls_setjmp) { int i; for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) if (!call_used_regs[i] && !call_fixed_regs[i]) regs_ever_live[i] = 1; }#endif /* Initial line number is supposed to be output before the function's prologue and label so that the function's address will not appear to be in the last statement of the preceding function. */ if (NOTE_LINE_NUMBER (first) != NOTE_INSN_DELETED) { if (write_symbols == SDB_DEBUG) /* For sdb, let's not, but say we did. We need to set last_linenum for sdbout_function_begin, but we can't have an actual line number before the .bf symbol. (sdb_begin_function_line is not set, and other compilers don't do it.) */ last_linenum = NOTE_LINE_NUMBER (first);#ifdef XCOFF_DEBUGGING_INFO else if (write_symbols == XCOFF_DEBUG) { last_linenum = NOTE_LINE_NUMBER (first); xcoffout_output_first_source_line (file, last_linenum); }#endif else output_source_line (file, first); }#ifdef LEAF_REG_REMAP if (leaf_function) leaf_renumber_regs (first);#endif /* The Sun386i and perhaps other machines don't work right if the profiling code comes after the prologue. */#ifdef PROFILE_BEFORE_PROLOGUE if (profile_flag) profile_function (file);#endif /* PROFILE_BEFORE_PROLOGUE */#ifdef FUNCTION_PROLOGUE /* First output the function prologue: code to set up the stack frame. */ FUNCTION_PROLOGUE (file, get_frame_size ());#endif#if defined (SDB_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO) if (write_symbols == SDB_DEBUG || write_symbols == XCOFF_DEBUG) next_block_index = 1;#endif /* If the machine represents the prologue as RTL, the profiling code must be emitted when NOTE_INSN_PROLOGUE_END is scanned. */#ifdef HAVE_prologue if (! HAVE_prologue)#endif profile_after_prologue (file); profile_label_no++;}static voidprofile_after_prologue (file) FILE *file;{#ifdef FUNCTION_BLOCK_PROFILER if (profile_block_flag) { FUNCTION_BLOCK_PROFILER (file, profile_label_no); }#endif /* FUNCTION_BLOCK_PROFILER */#ifndef PROFILE_BEFORE_PROLOGUE if (profile_flag) profile_function (file);#endif /* not PROFILE_BEFORE_PROLOGUE */}voidprofile_function (file) FILE *file;{ int align = MIN (BIGGEST_ALIGNMENT, INT_TYPE_SIZE); int sval = current_function_returns_struct; int cxt = current_function_needs_context; data_section (); ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT)); ASM_OUTPUT_INTERNAL_LABEL (file, "LP", profile_label_no); assemble_integer (const0_rtx, UNITS_PER_WORD, 1); text_section ();#ifdef STRUCT_VALUE_INCOMING_REGNUM if (sval) ASM_OUTPUT_REG_PUSH (file, STRUCT_VALUE_INCOMING_REGNUM);#else#ifdef STRUCT_VALUE_REGNUM if (sval) ASM_OUTPUT_REG_PUSH (file, STRUCT_VALUE_REGNUM);#endif#endif#if 0#ifdef STATIC_CHAIN_INCOMING_REGNUM if (cxt) ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_INCOMING_REGNUM);#else#ifdef STATIC_CHAIN_REGNUM if (cxt) ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_REGNUM);#endif#endif#endif /* 0 */ FUNCTION_PROFILER (file, profile_label_no);#if 0#ifdef STATIC_CHAIN_INCOMING_REGNUM if (cxt) ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_INCOMING_REGNUM);#else#ifdef STATIC_CHAIN_REGNUM if (cxt) ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_REGNUM);#endif#endif#endif /* 0 */#ifdef STRUCT_VALUE_INCOMING_REGNUM if (sval) ASM_OUTPUT_REG_POP (file, STRUCT_VALUE_INCOMING_REGNUM);#else#ifdef STRUCT_VALUE_REGNUM if (sval) ASM_OUTPUT_REG_POP (file, STRUCT_VALUE_REGNUM);#endif#endif}/* Output assembler code for the end of a function. For clarity, args are same as those of `final_start_function' even though not all of them are needed. */voidfinal_end_function (first, file, optimize) rtx first; FILE *file; int optimize;{ if (app_on) { fprintf (file, ASM_APP_OFF); app_on = 0; }#ifdef SDB_DEBUGGING_INFO if (write_symbols == SDB_DEBUG) sdbout_end_function (last_linenum);#endif#ifdef DWARF_DEBUGGING_INFO if (write_symbols == DWARF_DEBUG) dwarfout_end_function ();#endif#ifdef XCOFF_DEBUGGING_INFO if (write_symbols == XCOFF_DEBUG) xcoffout_end_function (file, last_linenum);#endif#ifdef FUNCTION_EPILOGUE /* Finally, output the function epilogue: code to restore the stack frame and return to the caller. */ FUNCTION_EPILOGUE (file, get_frame_size ());#endif#ifdef SDB_DEBUGGING_INFO if (write_symbols == SDB_DEBUG) sdbout_end_epilogue ();#endif#ifdef DWARF_DEBUGGING_INFO if (write_symbols == DWARF_DEBUG) dwarfout_end_epilogue ();#endif#ifdef XCOFF_DEBUGGING_INFO if (write_symbols == XCOFF_DEBUG) xcoffout_end_epilogue (file);#endif /* If FUNCTION_EPILOGUE is not defined, then the function body itself contains return instructions wherever needed. */}/* Output assembler code for some insns: all or part of a function. For description of args, see `final_start_function', above. PRESCAN is 1 if we are not really outputting, just scanning as if we were outputting. Prescanning deletes and rearranges insns just like ordinary output. PRESCAN is -2 if we are outputting after having prescanned. In this case, don't try to delete or rearrange insns because that has already been done. Prescanning is done only on certain machines. */voidfinal (first, file, optimize, prescan) rtx first; FILE *file; int optimize; int prescan;{ register rtx insn; int max_line = 0; last_ignored_compare = 0; new_block = 1; /* Make a map indicating which line numbers appear in this function. When producing SDB debugging info, delete troublesome line number notes from inlined functions in other files as well as duplicate line number notes. */#ifdef SDB_DEBUGGING_INFO if (write_symbols == SDB_DEBUG) { rtx last = 0; for (insn = first; insn; insn = NEXT_INSN (insn)) if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0) { if ((RTX_INTEGRATED_P (insn) && strcmp (NOTE_SOURCE_FILE (insn), main_input_filename) != 0) || (last != 0 && NOTE_LINE_NUMBER (insn) == NOTE_LINE_NUMBER (last) && NOTE_SOURCE_FILE (insn) == NOTE_SOURCE_FILE (last))) { NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; NOTE_SOURCE_FILE (insn) = 0; continue; } last = insn; if (NOTE_LINE_NUMBER (insn) > max_line) max_line = NOTE_LINE_NUMBER (insn); } } else#endif { for (insn = first; insn; insn = NEXT_INSN (insn)) if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > max_line) max_line = NOTE_LINE_NUMBER (insn); } line_note_exists = (char *) oballoc (max_line + 1); bzero (line_note_exists, max_line + 1); for (insn = first; insn; insn = NEXT_INSN (insn)) if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0) line_note_exists[NOTE_LINE_NUMBER (insn)] = 1; init_recog (); CC_STATUS_INIT; /* Output the insns. */ for (insn = NEXT_INSN (first); insn;) insn = final_scan_insn (insn, file, optimize, prescan, 0); /* Do basic-block profiling here if the last insn was a conditional branch. */ if (profile_block_flag && new_block) { new_block = 0; /* Enable the table of basic-block use counts to point at the code it applies to. */ ASM_OUTPUT_INTERNAL_LABEL (file, "LPB", count_basic_blocks); /* Before first insn of this basic block, increment the count of times it was entered. */#ifdef BLOCK_PROFILER BLOCK_PROFILER (file, count_basic_blocks); CC_STATUS_INIT;#endif count_basic_blocks++; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -