📄 asjxxx.c
字号:
} } /* Didn't find a tunnel. */ return((struct symtab *)0);}/* find_tunnel * * Routine to find a tunnel for a conditional branch so that it * won't have to be exploded into a branch of the opposite condition * followed by a branch word. A tunnel is an unconditional branch * to the same location as the original conditional branch. */static voidfind_tunnel(segno,starthint,jumpfrom) int segno; struct symtab **starthint; register struct symtab *jumpfrom;{ register struct symtab *tunnel; if (jxxxJUMP || UNCONDITIONAL(jumpfrom)) { /* * Don't attempt to find a tunnel. */ tunnel = 0; } else if ((jumpfrom->s_dest->s_value - jumpfrom->s_value) >= 0) { /* * The destination is ahead of us. Assume that the * most likely tunnel is ahead of us. */ tunnel = search_forward(segno,starthint,jumpfrom); if (tunnel == 0) { /* * That didn't work so search backwards. */ tunnel = search_backward(segno,starthint,jumpfrom); } } else { /* Reverse the search order. */ tunnel = search_backward(segno,starthint,jumpfrom); if (tunnel == 0) { tunnel = search_forward(segno,starthint,jumpfrom); } } if (tunnel) { /* Indicate that a tunnel was found. */ jumpfrom->s_dest = tunnel; jumpfrom->s_tag = JXTUNNEL; } else { jumpfrom->s_tag = JXNOTYET ; }#ifdef DEBUG if (debug) printf("%cBRANCH(%#8x) to %10s %10s, disp = %4d, value %8d\n", UNCONDITIONAL(jumpfrom) ? 'U' : 'C', jumpfrom , FETCHNAME( (tunnel ? tunnel : jumpfrom)->s_dest ), tunnel ? "TUNNEL" : "BUMPED" , jumpfrom->s_dest->s_value - jumpfrom->s_value , jumpfrom->s_value);#endif}/* CALC_FEAR * * Macro to calculate the amount to be feared from intervening aligns, * jbrs and jxxxs. Loops backward or forward through the current segment * from the current jbr or jxxx to its destination. For each questionable * item (JXACTIVE, JXNOTYET, JXALIGN, or JXINACTIVE) it calls jxxxfear() * to see how many more bytes the item might add to the instruction stream. * * The arguments are: * * current This is the current value of the copointer used * in the enclosing SEGITERATE loop. It is used to * determine where in the loop to start. * * end This is the destination of the jbr or jxxx and * determines when the loop terminates. * * disp Variable containing the initial displacement or * distance between the branch and its destination. * * op Either + or -. This is used to constuct the correct * operators for traversing the segment forwards or * backwards, and to add or subtract the fear to / from * the displacement. * * This is used in jxxxfix(), look there for more details. */#define CALC_FEAR(current, end, disp, op) \ { \ register struct symtab *ptr, **co_ptr; \ \ for (co_ptr = (current op 1), ptr = *co_ptr; \ ptr != end ; \ ptr = * op/**/op co_ptr \ ) { \ if (ptr->s_tag > JXQUESTIONABLE) { \ disp op= jxxxfear(ptr); \ } \ } \ } /* * Pass 1.5, resolve jxxx instructions and .align in .text */jxxxfix() { register struct symtab *jumpfrom, *dest, **cojumpfrom; struct symtab *ubjumpfrom; int segno; /* current segment number */ /* * consider each segment in turn... */ for (segno = 0; segno < NLOC + NLOC; segno++){ /* * Do a lazy topological sort. */ register int displ; /* estimated displacement */ unsigned n_changed; /* # of jxxx's changed in iteration */ unsigned n_still_active; /* # of jxxx's still active */ struct symtab **co_active; /* Saved value of cojumpfrom for * jumpfrom which is still active. */#ifdef DEBUG int n_iterations=0; /* # for current segment */ #endif /* Iterate through the segment, fixing the jbr/jxxx's. * Contiune to do this as long as the previous iteration * found something to bump, or some were deactivated, * but there are still active ones. */ do {#ifdef DEBUG if (debug) { printf("\nSegment %d, iteration %d\n", segno, ++n_iterations); }#endif /* Nothing changed or active yet. */ n_changed = 0; n_still_active = 0; co_active = NULL; SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom, ubjumpfrom, ++){ /* Ignore if not an active jbr/jxxx */ if (jumpfrom->s_tag != JXACTIVE) { continue; } /* Find the destination of the jbr/jxxx, and make * sure that it is in the same segment. */ dest = jumpfrom->s_dest; if (jumpfrom->s_index != dest->s_index){ yyerror("Intersegment jxxx"); continue; } /* Do an intial estimate of the displacement * needed for the destination address. */ displ = dest->s_value - jumpfrom->s_value; if ( ! ISBYTE(displ) ) { /* It is not a byte displacement, so try to * prevent the expansion of a jxxx by * finding a tunnel, but if this doesn't * doesn't work, mark it for expansion. */ find_tunnel(segno,cojumpfrom,jumpfrom) ; /* In either case make note that something * has changed. */ n_changed++; } else { if (displ >= 0) { /* An unconditional forward branch * also needs to take the alignment * following it into account. */ if (UNCONDITIONAL(jumpfrom)) { displ += ALIGN_FEAR; } /* It is a forward branch. Do a * forward search for any intervening * jbr's, jxxx's, or align's, as these * may affect the actual displacement. */ CALC_FEAR(cojumpfrom,dest,displ,+) ; } else { /* Do a backward search as above, for * a backward branch. */ CALC_FEAR(cojumpfrom,dest,displ,-) ; } if (ISBYTE(displ)){ /* * The displacement will still fit in * a byte so this jbr/jxx can be * deactivated. Note that a jxxx * has changed state. */ jumpfrom->s_tag = JXINACTIVE; jumpfrom->s_jxneedalign = UNCONDITIONAL(jumpfrom); DEBUG_DEACT(jumpfrom,dest,displ) ; n_changed++; } else if (n_changed > 0) { /* Keep track that a jxxx/jbr is * still active. */ n_still_active++; } else if (co_active == NULL) { /* Remember the first still active * jxxx so that we can use it later. */ co_active = cojumpfrom; n_still_active++; } else if (! UNCONDITIONAL(*co_active) && UNCONDITIONAL(jumpfrom)) { /* Better to bump an unconditional * branch than a conditional branch. */ co_active = cojumpfrom; n_still_active++; } else { n_still_active++; } } } if (co_active && n_changed == 0 ) { /* * Nothing changed in this iteration, so force * an active jxxx to change into a tunnel or a * bumped jxxx. This may allow us to deactivate * some other still active jxxx's. */#ifdef DEBUG if (debug) fputs("*** Forcing BUMP or TUNNEL ***\n", stdout);#endif find_tunnel(segno,co_active,*co_active); /* * Decrement the number still active, so that we * won't do another iteration if that was the only * one. */ n_still_active--; } /* Now go through the segment bumping what needs to be * bumped and aligning what can and needs to be aligned. * This is done regardless of whether anything changed * or is still active, so that the case all aligns will * be handled, even if there were no branches. */ jxxxbump(segno); /* End of iterating through all symbols in this * segment. Keep doing it as long as there is anything * still active. */ } while (n_still_active > 0) ;#ifdef DEBUG if (debug) jxxxcheck(segno);#endif }}#ifdef DEBUG/* * Debugging routine to check JXXX's and print out debugging info. */jxxxcheck(segno) int segno;{ register struct symtab **cosp, *sp; register struct symtab *ub; /* Iterate through the whole segment. */ SEGITERATE(segno, 0, 0, cosp, sp, ub, ++){ switch(sp->s_tag) { case LABELID: fprintf(stdout, "%s, value = %8d\n", FETCHNAME(sp), sp->s_value); break; case JXTUNNEL: fprintf(stdout, "TUNNEL(%#8x) to %#10x, disp = %4d, value = %8d\n", sp, sp->s_dest, TUNNEL_ADDR(sp->s_dest) - sp->s_value, sp->s_value); break ; case JXINACTIVE: if (sp->s_dest == 0) { fprintf(stdout, "\tALIGN(%#8x), value = %8d\n", sp, sp->s_value); break; } fprintf(stdout, "\t%cBRANCH(%#8x) to %10s, disp = %4d, value = %8d %s\n", UNCONDITIONAL(sp)?'U':'C', sp, FETCHNAME(sp->s_dest), sp->s_dest->s_value - sp->s_value, sp->s_value, sp->s_jxbump ? "BUMPED":""); if (sp->s_jxneedalign) fputs(" ERROR needs alignment \n",stdout); break ; case JXACTIVE: case JXNOTYET: fprintf(stdout, "BRANCH(%#8x) to %#10x, disp = %4d, value = %8d ERROR tag = %s\n", sp, sp->s_dest, sp->s_dest->s_value - sp->s_value, sp->s_value, sp->s_tag==JXACTIVE?"JXACTIVE":"JXNOTYET"); break ; } }}#endif/* * Go through the symbols in a given segment number, * and see which entries are jxxx entries that have * been logically "exploded" (expanded), but for which * the value of textually following symbols has not been * increased. Attempt to align as much as we can so that * that we can (possibly) deactivate jbr/jxxx's in fewer * iterations. This may also prevent some jbr/jxxx's * from being exploded unnecessarily. */jxxxbump(segno) int segno;{ register struct symtab **cosp, *sp; register struct symtab *ub; register int cum_bump; register int align_ok;#ifdef DEBUG if (debug) fputs("Bumping\n",stdout);#endif cum_bump = 0; /* No cumulative bump yet. */ align_ok = 1; /* No active jbr/jxxx's yet, so ok to align. */ /* Iterate through the whole segment. */ SEGITERATE(segno, 0, 0, cosp, sp, ub, ++){ switch(sp->s_tag) { case JXACTIVE: /* * Once an active jbr/jxxx has been seen we can * no longer do alignment, since it may later be * exploded. */ align_ok = 0; /* FALLTHROUGH */ case OKTOBUMP: case LABELID: case FLOATINGSTAB: case IGNOREBOUND: case OBSOLETE: case JXQUESTIONABLE: case JXTUNNEL: /* * Simply add the cumulative bump to these. */ sp->s_value += cum_bump; break; case JXINACTIVE: /* * Add the cumulative bump then see if we can * (align_ok) or need to (s_jxneedalign) align * the instruction following this one. */ sp->s_value += cum_bump; if (align_ok && sp->s_jxneedalign) { /* * Add the amount needed to align the next * instruction, but don't change s_value * for this instruction, since this will * be needed later if this instruction * provides a tunnel. This also make sense * because the alignment actually inserts * HALT instructions between this and the * next. */ cum_bump += ALIGN(sp->s_value) - sp->s_value; /* Indicate that this no longer needs * alignment. */ sp->s_jxneedalign = 0; } break; case JXNOTYET: /* * This one needs to be bumped, so do it and mark it * inactive. It's s_jxfear is used to bump the * cumulative bump which is then used to bump it's * own s_value. */ sp->s_tag = JXINACTIVE; sp->s_jxbump = 1; cum_bump += sp->s_jxfear; sp->s_value += cum_bump; /* We want to align the instruction following the * brw or bxxx/brw that this is turning into. Can * it be done now. */ if (align_ok) { /* * Yes, so add the alignment factor into * the cumulative bump and clear s_jxneedalign * to indicate that this has been done. */ cum_bump += ALIGN(sp->s_value) - sp->s_value; sp->s_jxneedalign = 0; } else { /* Can't calculate how much alignment needs * to be done, so indicate that it should be * done in a later call. */ sp->s_jxneedalign = 1; } break ; case JXALIGN: /* * Add any cumulative bump and calculate the alignment * needed, if posssible. If not, it will be done in * a later call. */ sp->s_value += cum_bump; if (align_ok) { /* How many extra bytes are there over the * required alignment? This is caluclated * on (sp->s_value - 1) rather than just * sp->s_value. See jalign() for detatils. */ int extra = (sp->s_value - 1) & ((unsigned)sp->s_jxfear); if (extra == 0) { /* * We over estimated, back off to * do the alignment. */ sp->s_value--; cum_bump--; } else { sp->s_jxfear -= extra ; sp->s_value += sp->s_jxfear; cum_bump += sp->s_jxfear; } /* Now mark it inactive and indicate that * it no longer needs alignment. */ sp->s_jxneedalign = 0; sp->s_tag = JXINACTIVE; } break; } } /* Finally bump the location value for the segment. */ usedot[segno].e_xvalue += cum_bump;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -