static void fixjmp(Prog *firstp) { int jmploop; Prog *p, *last; if(debug['R'] && debug['v']) print("\nfixjmp\n"); // pass 1: resolve jump to AJMP, mark all code as dead. jmploop = 0; for(p=firstp; p; p=p->link) { if(debug['R'] && debug['v']) print("%P\n", p); if(p->as != ACALL && p->to.type == D_BRANCH && p->to.branch && p->to.branch->as == AJMP) { p->to.branch = chasejmp(p->to.branch, &jmploop); if(debug['R'] && debug['v']) print("->%P\n", p); } p->reg = dead; } if(debug['R'] && debug['v']) print("\n"); // pass 2: mark all reachable code alive mark(firstp); // pass 3: delete dead code (mostly JMPs). last = nil; for(p=firstp; p; p=p->link) { if(p->reg == dead) { if(p->link == P && p->as == ARET && last && last->as != ARET) { // This is the final ARET, and the code so far doesn't have one. // Let it stay. } else { if(debug['R'] && debug['v']) print("del %P\n", p); continue; } } if(last) last->link = p; last = p; } last->link = P; // pass 4: elide JMP to next instruction. // only safe if there are no jumps to JMPs anymore. if(!jmploop) { last = nil; for(p=firstp; p; p=p->link) { if(p->as == AJMP && p->to.type == D_BRANCH && p->to.branch == p->link) { if(debug['R'] && debug['v']) print("del %P\n", p); continue; } if(last) last->link = p; last = p; } last->link = P; } if(debug['R'] && debug['v']) { print("\n"); for(p=firstp; p; p=p->link) print("%P\n", p); print("\n"); } }
/* * the code generator depends on being able to write out JMP * instructions that it can jump to now but fill in later. * the linker will resolve them nicely, but they make the code * longer and more difficult to follow during debugging. * remove them. */ static void fixjmp(Reg *firstr) { int jmploop; Reg *r; Prog *p; if(debug['R'] && debug['v']) print("\nfixjmp\n"); // pass 1: resolve jump to AJMP, mark all code as dead. jmploop = 0; for(r=firstr; r; r=r->link) { p = r->prog; if(debug['R'] && debug['v']) print("%04d %P\n", (int)r->pc, p); if(p->as != ACALL && p->to.type == D_BRANCH && r->s2 && r->s2->prog->as == AJMP) { r->s2 = chasejmp(r->s2, &jmploop); p->to.offset = r->s2->pc; p->to.u.branch = r->s2->prog; if(debug['R'] && debug['v']) print("->%P\n", p); } r->active = 0; } if(debug['R'] && debug['v']) print("\n"); // pass 2: mark all reachable code alive mark(firstr); // pass 3: delete dead code (mostly JMPs). for(r=firstr; r; r=r->link) { if(!r->active) { p = r->prog; if(p->link == P && p->as == ARET && r->p1 && r->p1->prog->as != ARET) { // This is the final ARET, and the code so far doesn't have one. // Let it stay. } else { if(debug['R'] && debug['v']) print("del %04d %P\n", (int)r->pc, p); p->as = ANOP; } } } // pass 4: elide JMP to next instruction. // only safe if there are no jumps to JMPs anymore. if(!jmploop) { for(r=firstr; r; r=r->link) { p = r->prog; if(p->as == AJMP && p->to.type == D_BRANCH && r->s2 == r->link) { if(debug['R'] && debug['v']) print("del %04d %P\n", (int)r->pc, p); p->as = ANOP; } } } // fix back pointers. for(r=firstr; r; r=r->link) { r->p2 = R; r->p2link = R; } for(r=firstr; r; r=r->link) { if(r->s2) { r->p2link = r->s2->p2; r->s2->p2 = r; } } if(debug['R'] && debug['v']) { print("\n"); for(r=firstr; r; r=r->link) print("%04d %P\n", (int)r->pc, r->prog); print("\n"); } }
void fixjmp(Prog *firstp) { int jmploop; Prog *p, *last; if(debug['R'] && debug['v']) print("\nfixjmp\n"); // pass 1: resolve jump to jump, mark all code as dead. jmploop = 0; for(p=firstp; p; p=p->link) { if(debug['R'] && debug['v']) print("%P\n", p); if(p->as != ACALL && p->to.type == D_BRANCH && p->to.u.branch && p->to.u.branch->as == AJMP) { p->to.u.branch = chasejmp(p->to.u.branch, &jmploop); if(debug['R'] && debug['v']) print("->%P\n", p); } p->opt = dead; } if(debug['R'] && debug['v']) print("\n"); // pass 2: mark all reachable code alive mark(firstp); // pass 3: delete dead code (mostly JMPs). last = nil; for(p=firstp; p; p=p->link) { if(p->opt == dead) { if(p->link == P && p->as == ARET && last && last->as != ARET) { // This is the final ARET, and the code so far doesn't have one. // Let it stay. The register allocator assumes that all live code in // the function can be traversed by starting at all the RET instructions // and following predecessor links. If we remove the final RET, // this assumption will not hold in the case of an infinite loop // at the end of a function. // Keep the RET but mark it dead for the liveness analysis. p->mode = 1; } else { if(debug['R'] && debug['v']) print("del %P\n", p); continue; } } if(last) last->link = p; last = p; } last->link = P; // pass 4: elide JMP to next instruction. // only safe if there are no jumps to JMPs anymore. if(!jmploop) { last = nil; for(p=firstp; p; p=p->link) { if(p->as == AJMP && p->to.type == D_BRANCH && p->to.u.branch == p->link) { if(debug['R'] && debug['v']) print("del %P\n", p); continue; } if(last) last->link = p; last = p; } last->link = P; } if(debug['R'] && debug['v']) { print("\n"); for(p=firstp; p; p=p->link) print("%P\n", p); print("\n"); } }