📄 final.c
字号:
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 5); for ((ptr = bb_head), (i = 0); ptr != 0; (ptr = ptr->next), i++) assemble_integer (GEN_INT (ptr->line_num), UNITS_PER_WORD, 1); for ( ; i < count_basic_blocks; i++) assemble_integer (const0_rtx, UNITS_PER_WORD, 1); /* Output the table of file names. */ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 6); for ((ptr = bb_head), (i = 0); ptr != 0; (ptr = ptr->next), i++) { if (ptr->file_label_num >= 0) { ASM_GENERATE_INTERNAL_LABEL (name, "LPBC", ptr->file_label_num); assemble_integer (gen_rtx (SYMBOL_REF, Pmode, name), UNITS_PER_WORD, 1); } else assemble_integer (const0_rtx, UNITS_PER_WORD, 1); } for ( ; i < count_basic_blocks; i++) assemble_integer (const0_rtx, UNITS_PER_WORD, 1); } /* End with the address of the table of addresses, so we can find it easily, as the last word in the file's text. */ ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 3); assemble_integer (gen_rtx (SYMBOL_REF, Pmode, name), UNITS_PER_WORD, 1); }}/* Enable APP processing of subsequent output. Used before the output from an `asm' statement. */voidapp_enable (){ if (! app_on) { fprintf (asm_out_file, ASM_APP_ON); app_on = 1; }}/* Disable APP processing of subsequent output. Called from varasm.c before most kinds of output. */voidapp_disable (){ if (app_on) { fprintf (asm_out_file, ASM_APP_OFF); app_on = 0; }}/* Return the number of slots filled in the current delayed branch sequence (we don't count the insn needing the delay slot). Zero if not in a delayed branch sequence. */#ifdef DELAY_SLOTSintdbr_sequence_length (){ if (final_sequence != 0) return XVECLEN (final_sequence, 0) - 1; else return 0;}#endif/* The next two pages contain routines used to compute the length of an insn and to shorten branches. *//* Arrays for insn lengths, and addresses. The latter is referenced by `insn_current_length'. */static short *insn_lengths;int *insn_addresses;/* Address of insn being processed. Used by `insn_current_length'. */int insn_current_address;/* Indicate that branch shortening hasn't yet been done. */voidinit_insn_lengths (){ insn_lengths = 0;}/* Obtain the current length of an insn. If branch shortening has been done, get its actual length. Otherwise, get its maximum length. */intget_attr_length (insn) rtx insn;{#ifdef HAVE_ATTR_length rtx body; int i; int length = 0; if (insn_lengths) return insn_lengths[INSN_UID (insn)]; else switch (GET_CODE (insn)) { case NOTE: case BARRIER: case CODE_LABEL: return 0; case CALL_INSN: length = insn_default_length (insn); break; case JUMP_INSN: body = PATTERN (insn); if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC) { /* This only takes room if jump tables go into the text section. */#if !defined(READONLY_DATA_SECTION) || defined(JUMP_TABLES_IN_TEXT_SECTION) length = (XVECLEN (body, GET_CODE (body) == ADDR_DIFF_VEC) * GET_MODE_SIZE (GET_MODE (body))); /* Be pessimistic and assume worst-case alignment. */ length += (GET_MODE_SIZE (GET_MODE (body)) - 1);#else return 0;#endif } else length = insn_default_length (insn); break; case INSN: body = PATTERN (insn); if (GET_CODE (body) == USE || GET_CODE (body) == CLOBBER) return 0; else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0) length = asm_insn_count (body) * insn_default_length (insn); else if (GET_CODE (body) == SEQUENCE) for (i = 0; i < XVECLEN (body, 0); i++) length += get_attr_length (XVECEXP (body, 0, i)); else length = insn_default_length (insn); }#ifdef ADJUST_INSN_LENGTH ADJUST_INSN_LENGTH (insn, length);#endif return length;#else /* not HAVE_ATTR_length */ return 0;#endif /* not HAVE_ATTR_length */}/* Make a pass over all insns and compute their actual lengths by shortening any branches of variable length if possible. *//* Give a default value for the lowest address in a function. */#ifndef FIRST_INSN_ADDRESS#define FIRST_INSN_ADDRESS 0#endifvoidshorten_branches (first) rtx first;{#ifdef HAVE_ATTR_length rtx insn; int something_changed = 1; int max_uid = 0; char *varying_length; rtx body; int uid; /* Compute maximum UID and allocate arrays. */ for (insn = first; insn; insn = NEXT_INSN (insn)) if (INSN_UID (insn) > max_uid) 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; int tmp_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; /* insn_current_length returns 0 for insns with a non-varying length. */ if (! varying_length[inner_uid]) inner_length = insn_lengths[inner_uid]; else 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; }#ifdef SHORTEN_WITH_ADJUST_INSN_LENGTH#ifdef ADJUST_INSN_LENGTH /* If needed, do any adjustment. */ tmp_length = new_length; ADJUST_INSN_LENGTH (insn, new_length); insn_current_address += (new_length - tmp_length);#endif#endif if (new_length != insn_lengths[uid]) { insn_lengths[uid] = new_length; something_changed = 1; } } /* For a non-optimizing compile, do only a single pass. */ if (!optimize) break; }#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; if (GET_CODE (body) == ASM_INPUT) template = XSTR (body, 0); else template = decode_asm_operands (body, NULL_PTR, NULL_PTR, NULL_PTR, NULL_PTR); for ( ; *template; template++) if (IS_ASM_LOGICAL_LINE_SEPARATOR(*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) last_linenum = high_block_linenum = high_function_linenum = NOTE_LINE_NUMBER (first); /* For SDB and XCOFF, the function beginning must be marked between the function label and the prologue. We always need this, even when -g1 was used. Defer on MIPS systems so that parameter descriptions follow function entry. */#if defined(SDB_DEBUGGING_INFO) && !defined(MIPS_DEBUGGING_INFO) if (write_symbols == SDB_DEBUG) sdbout_begin_function (last_linenum); else#endif#ifdef XCOFF_DEBUGGING_INFO if (write_symbols == XCOFF_DEBUG) xcoffout_begin_function (file, last_linenum); else#endif /* But only output line number for other debug info types if -g2 or better. */ if (NOTE_LINE_NUMBER (first) != NOTE_INSN_DELETED) 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -