final.c
来自「GCC编译器源代码」· C语言 代码 · 共 2,287 行 · 第 1/5 页
C
2,287 行
ASM_OUTPUT_SHARED_LOCAL (asm_out_file, name, size, rounded); else#endif#ifdef ASM_OUTPUT_ALIGNED_DECL_LOCAL ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, NULL_TREE, name, size, BIGGEST_ALIGNMENT);#else#ifdef ASM_OUTPUT_ALIGNED_LOCAL ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, BIGGEST_ALIGNMENT);#else ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);#endif#endif } /* Output any basic block strings */ if (profile_block_flag) { readonly_data_section (); if (sbb_head) { ASM_OUTPUT_ALIGN (asm_out_file, align); for (sptr = sbb_head; sptr != 0; sptr = sptr->next) { ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBC", sptr->label_num); assemble_string (sptr->string, sptr->length); } } } /* Output the table of addresses. */ if (profile_block_flag) { /* Realign in new section */ ASM_OUTPUT_ALIGN (asm_out_file, align); ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 3); for (i = 0; i < count_basic_blocks; i++) { ASM_GENERATE_INTERNAL_LABEL (name, "LPB", i); assemble_integer (gen_rtx (SYMBOL_REF, Pmode, name), pointer_bytes, 1); } } /* Output the table of function names. */ if (profile_block_flag) { ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 4); for ((ptr = bb_head), (i = 0); ptr != 0; (ptr = ptr->next), i++) { if (ptr->func_label_num >= 0) { ASM_GENERATE_INTERNAL_LABEL (name, "LPBC", ptr->func_label_num); assemble_integer (gen_rtx (SYMBOL_REF, Pmode, name), pointer_bytes, 1); } else assemble_integer (const0_rtx, pointer_bytes, 1); } for ( ; i < count_basic_blocks; i++) assemble_integer (const0_rtx, pointer_bytes, 1); } if (write_symbols != NO_DEBUG && profile_block_flag) { /* Output the table of line numbers. */ 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), long_bytes, 1); for ( ; i < count_basic_blocks; i++) assemble_integer (const0_rtx, long_bytes, 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), pointer_bytes, 1); } else assemble_integer (const0_rtx, pointer_bytes, 1); } for ( ; i < count_basic_blocks; i++) assemble_integer (const0_rtx, pointer_bytes, 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. */ if (profile_block_flag) { ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 3); assemble_integer (gen_rtx (SYMBOL_REF, Pmode, name), pointer_bytes, 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); break; default: break; }#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; /* In order to make sure that all instructions have valid length info, we must split them before we compute the address/length info. */ for (insn = NEXT_INSN (first); insn; insn = NEXT_INSN (insn)) if (GET_RTX_CLASS (GET_CODE (insn)) == 'i') insn = try_split (PATTERN (insn), insn, 1); /* 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; if (INSN_DELETED_P (insn)) 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))); /* We don't know what address the ADDR_VEC/ADDR_DIFF_VEC will end up at after branch shortening. As a result, it is impossible to determine how much padding we need at this point. Therefore, assume worst possible alignment. */ insn_lengths[uid] += 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;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?