📄 i370.c
字号:
inti370_short_branch (insn) rtx insn;{ int base_offset; base_offset = i370_branch_length(insn); if (0 > base_offset) { base_offset += mvs_page_code; } else { /* avoid bumping into lit pool; use 2x to estimate max possible lits */ base_offset *= 2; base_offset += mvs_page_code + mvs_page_lit; } /* make a conservative estimate of room left on page */ if ((4060 >base_offset) && ( 0 < base_offset)) return 1; return 0;}/* The i370_label_scan() routine is supposed to loop over all labels and label references in a compilation unit, and determine whether all label refs appear on the same code page as the label. If they do, then we can avoid a reload of the base register for that label. Note that the instruction addresses used here are only approximate, and make the sizes of the jumps appear farther apart then they will actually be. This makes this code far more conservative than it needs to be. */#define I370_RECORD_LABEL_REF(label,addr) { \ label_node_t *lp; \ int labelno = CODE_LABEL_NUMBER (label); \ lp = mvs_get_label (labelno); \ if (addr < lp -> label_first_ref) lp->label_first_ref = addr; \ if (addr > lp -> label_last_ref) lp->label_last_ref = addr; \}static void i370_label_scan () { rtx insn; label_node_t *lp; int tablejump_offset = 0; for (insn = get_insns(); insn; insn = NEXT_INSN(insn)) { int here = INSN_ADDRESSES (INSN_UID (insn)); enum rtx_code code = GET_CODE(insn); /* ??? adjust for tables embedded in the .text section that * the compiler didn't take into account */ here += tablejump_offset; INSN_ADDRESSES (INSN_UID (insn)) = here; /* check to see if this insn is a label ... */ if (CODE_LABEL == code) { int labelno = CODE_LABEL_NUMBER (insn); lp = mvs_get_label (labelno); lp -> label_addr = here;#if 0 /* Supposedly, labels are supposed to have circular lists of label-refs that reference them, setup in flow.c, but this does not appear to be the case. */ rtx labelref = LABEL_REFS (insn); rtx ref = labelref; do { rtx linsn = CONTAINING_INSN(ref); ref = LABEL_NEXTREF(ref); } while (ref && (ref != labelref));#endif } else if (JUMP_INSN == code) { rtx label = JUMP_LABEL (insn); /* If there is no label for this jump, then this had better be a ADDR_VEC or an ADDR_DIFF_VEC and there had better be a vector of labels. */ if (!label) { int j; rtx body = PATTERN (insn); if (ADDR_VEC == GET_CODE(body)) { for (j=0; j < XVECLEN (body, 0); j++) { rtx lref = XVECEXP (body, 0, j); if (LABEL_REF != GET_CODE (lref)) abort (); label = XEXP (lref,0); if (CODE_LABEL != GET_CODE (label)) abort (); tablejump_offset += 4; here += 4; I370_RECORD_LABEL_REF(label,here); } /* finished with the vector go do next insn */ continue; } else if (ADDR_DIFF_VEC == GET_CODE(body)) {/* XXX hack alert. Right now, we leave this as a no-op, but strictly speaking, this is incorrect. It is possible that a table-jump driven off of a relative address could take us off-page, to a place where we need to reload the base reg. So really, we need to examing both labels, and compare thier values to the current basereg value. More generally, this brings up a troubling issue overall: what happens if a tablejump is split across two pages? I do not beleive that this case is handled correctly at all, and can only lead to horrible results if this were to occur. However, the current situation is not any worse than it was last week, and so we punt for now. */ debug_rtx (insn); for (j=0; j < XVECLEN (body, 0); j++) { } /* finished with the vector go do next insn */ continue; } else {/* XXX hack alert. Compiling the exception handling (L_eh) in libgcc2.a will trip up right here, with something that looks like (set (pc) (mem:SI (plus:SI (reg/v:SI 1 r1) (const_int 4)))) {indirect_jump} I'm not sure of what leads up to this, but it looks like the makings of a long jump which will surely get us into trouble because the base & page registers don't get reloaded. For now I'm not sure of what to do ... again we punt ... we are not worse off than yesterday. */ /* print_rtl_single (stdout, insn); */ debug_rtx (insn); /* abort(); */ continue; } } else { /* At this point, this jump_insn had better be a plain-old ordinary one, grap the label id and go */ if (CODE_LABEL != GET_CODE (label)) abort (); I370_RECORD_LABEL_REF(label,here); } } /* Sometimes, we take addresses of labels and use them as instruction operands ... these show up as REG_NOTES */ else if (INSN == code) { if ('i' == GET_RTX_CLASS (code)) { rtx note; for (note = REG_NOTES (insn); note; note = XEXP(note,1)) { if (REG_LABEL == REG_NOTE_KIND(note)) { rtx label = XEXP (note,0); if (!label || CODE_LABEL != GET_CODE (label)) abort (); I370_RECORD_LABEL_REF(label,here); } } } } }}/* ===================================================== *//* Emit reload of base register if indicated. This is to eliminate multiple reloads when several labels are generated pointing to the same place in the code. The page table is written at the end of the function. The entries in the page table look like .LPGT0: // PGT0 EQU * .long .LPG0 // DC A(PG0) .long .LPG1 // DC A(PG1) while the prologue generates L r4,=A(.LPGT0) Note that this paging scheme breaks down if a single subroutine has more than about 10MB of code in it ... as long as humans write code, this shouldn't be a problem ... */voidcheck_label_emit (){ if (mvs_need_base_reload) { mvs_need_base_reload = 0; mvs_page_code += 4; fprintf (assembler_source, "\tL\t%d,%d(,%d)\n", BASE_REGISTER, (mvs_page_num - function_base_page) * 4, PAGE_REGISTER); }}/* Add the label to the current page label list. If a free element is available it will be used for the new label. Otherwise, a label element will be allocated from memory. ID is the label number of the label being added to the list. */static label_node_t *mvs_get_label (id) int id;{ label_node_t *lp; /* first, lets see if we already go one, if so, use that. */ for (lp = label_anchor; lp; lp = lp->label_next) { if (lp->label_id == id) return lp; } /* not found, get a new one */ if (free_anchor) { lp = free_anchor; free_anchor = lp->label_next; } else { lp = (label_node_t *) xmalloc (sizeof (label_node_t)); } /* initialize for new label */ lp->label_id = id; lp->label_page = -1; lp->label_next = label_anchor; lp->label_first_ref = 2000123123; lp->label_last_ref = -1; lp->label_addr = -1; lp->first_ref_page = -1; label_anchor = lp; return lp;}voidmvs_add_label (id) int id;{ label_node_t *lp; int fwd_distance; lp = mvs_get_label (id); lp->label_page = mvs_page_num; /* OK, we just saw the label. Determine if this label * needs a reload of the base register */ if ((-1 != lp->first_ref_page) && (lp->first_ref_page != mvs_page_num)) { /* Yep; the first label_ref was on a different page. */ mvs_need_base_reload ++; return; } /* Hmm. Try to see if the estimated address of the last label_ref is on the current page. If it is, then we don't need a base reg reload. Note that this estimate is very conservatively handled; we'll tend to have a good bit more reloads than actually needed. Someday, we should tighten the estimates (which are driven by the (set_att "length") insn attibute. Currently, we estimate that number of page literals same as number of insns, which is a vast overestimate, esp that the estimate of each insn size is its max size. */ /* if latest ref comes before label, we are clear */ if (lp->label_last_ref < lp->label_addr) return; fwd_distance = lp->label_last_ref - lp->label_addr; if (mvs_page_code + 2 * fwd_distance + mvs_page_lit < 4060) return; mvs_need_base_reload ++;}/* Check to see if the label is in the list and in the current page. If not found, we have to make worst case assumption that label will be on a different page, and thus will have to generate a load and branch on register. This is rather ugly for forward-jumps, but what can we do? For backward jumps on the same page we can branch directly to address. ID is the label number of the label being checked. */intmvs_check_label (id) int id;{ label_node_t *lp; for (lp = label_anchor; lp; lp = lp->label_next) { if (lp->label_id == id) { if (lp->label_page == mvs_page_num) { return 1; } else { return 0; } } } return 0;}/* Get the page on which the label sits. This will be used to determine is a register reload is really needed. */#if 0intmvs_get_label_page(int id){ label_node_t *lp; for (lp = label_anchor; lp; lp = lp->label_next) { if (lp->label_id == id) return lp->label_page; } return -1;}#endif/* The label list for the current page freed by linking the list onto the free label element chain. */voidmvs_free_label_list (){ if (label_anchor) { label_node_t *last_lp = label_anchor; while (last_lp->label_next) last_lp = last_lp->label_next; last_lp->label_next = free_anchor; free_anchor = label_anchor; } label_anchor = 0;}/* ====================================================================== *//* If the page size limit is reached a new code page is started, and the base register is set to it. This page break point is counted conservatively, most literals that have the same value are collapsed by the assembler. True is returned when a new page is started. FILE is the assembler output file descriptor. CODE is the length, in bytes, of the instruction to be emitted. LIT is the length of the literal to be emitted. */#ifdef TARGET_HLASMintmvs_check_page (file, code, lit) FILE *file; int code, lit;{ if (file) assembler_source = file; if (mvs_page_code + code + mvs_page_lit + lit > MAX_MVS_PAGE_LENGTH) { fprintf (assembler_source, "\tB\tPGE%d\n", mvs_page_num); fprintf (assembler_source, "\tDS\t0F\n"); fprintf (assembler_source, "\tLTORG\n"); fprintf (assembler_source, "\tDS\t0F\n"); fprintf (assembler_source, "PGE%d\tEQU\t*\n", mvs_page_num); fprintf (assembler_source, "\tDROP\t%d\n", BASE_REGISTER); mvs_page_num++; /* Safe to use BASR not BALR, since we are * not switching addressing mode here ... */ fprintf (assembler_source, "\tBASR\t%d,0\n", BASE_REGISTER); fprintf (assembler_source, "PG%d\tEQU\t*\n", mvs_page_num); fprintf (assembler_source, "\tUSING\t*,%d\n", BASE_REGISTER);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -