diff options
Diffstat (limited to 'src/cmd/5l/noop.c')
-rw-r--r-- | src/cmd/5l/noop.c | 671 |
1 files changed, 3 insertions, 668 deletions
diff --git a/src/cmd/5l/noop.c b/src/cmd/5l/noop.c index 305ed684e..d42c86289 100644 --- a/src/cmd/5l/noop.c +++ b/src/cmd/5l/noop.c @@ -32,677 +32,12 @@ #include "l.h" #include "../ld/lib.h" -#include "../../pkg/runtime/stack.h" - -static Sym* sym_div; -static Sym* sym_divu; -static Sym* sym_mod; -static Sym* sym_modu; -static Sym* symmorestack; -static Prog* pmorestack; - -static Prog* stacksplit(Prog*, int32); - -static void -linkcase(Prog *casep) -{ - Prog *p; - - for(p = casep; p != P; p = p->link){ - if(p->as == ABCASE) { - for(; p != P && p->as == ABCASE; p = p->link) - p->pcrel = casep; - break; - } - } -} void noops(void) { - Prog *p, *q, *q1, *q2; - int o; - Sym *tlsfallback, *gmsym; - - /* - * find leaf subroutines - * strip NOPs - * expand RET - * expand BECOME pseudo - * fixup TLS - */ - - if(debug['v']) - Bprint(&bso, "%5.2f noops\n", cputime()); - Bflush(&bso); - - symmorestack = lookup("runtime.morestack", 0); - if(symmorestack->type != STEXT) { - diag("runtime·morestack not defined"); - errorexit(); - } - pmorestack = symmorestack->text; - pmorestack->reg |= NOSPLIT; - - tlsfallback = lookup("runtime.read_tls_fallback", 0); - gmsym = S; - if(linkmode == LinkExternal) - gmsym = lookup("runtime.tlsgm", 0); - q = P; - for(cursym = textp; cursym != nil; cursym = cursym->next) { - for(p = cursym->text; p != P; p = p->link) { - switch(p->as) { - case ACASE: - if(flag_shared) - linkcase(p); - break; - - case ATEXT: - p->mark |= LEAF; - break; - - case ARET: - break; - - case ADIV: - case ADIVU: - case AMOD: - case AMODU: - q = p; - if(prog_div == P) - initdiv(); - cursym->text->mark &= ~LEAF; - continue; - - case ANOP: - q1 = p->link; - q->link = q1; /* q is non-nop */ - if(q1 != P) - q1->mark |= p->mark; - continue; - - case ABL: - case ABX: - cursym->text->mark &= ~LEAF; - - case ABCASE: - case AB: - - case ABEQ: - case ABNE: - case ABCS: - case ABHS: - case ABCC: - case ABLO: - case ABMI: - case ABPL: - case ABVS: - case ABVC: - case ABHI: - case ABLS: - case ABGE: - case ABLT: - case ABGT: - case ABLE: - q1 = p->cond; - if(q1 != P) { - while(q1->as == ANOP) { - q1 = q1->link; - p->cond = q1; - } - } - break; - case AWORD: - // Rewrite TLS register fetch: MRC 15, 0, <reg>, C13, C0, 3 - if((p->to.offset & 0xffff0fff) == 0xee1d0f70) { - if(HEADTYPE == Hopenbsd) { - p->as = ARET; - } else if(goarm < 7) { - if(tlsfallback->type != STEXT) { - diag("runtime·read_tls_fallback not defined"); - errorexit(); - } - // BL runtime.read_tls_fallback(SB) - p->as = ABL; - p->to.type = D_BRANCH; - p->to.sym = tlsfallback; - p->cond = tlsfallback->text; - p->to.offset = 0; - cursym->text->mark &= ~LEAF; - } - if(linkmode == LinkExternal) { - // runtime.tlsgm is relocated with R_ARM_TLS_LE32 - // and $runtime.tlsgm will contain the TLS offset. - // - // MOV $runtime.tlsgm+tlsoffset(SB), REGTMP - // ADD REGTMP, <reg> - // - // In shared mode, runtime.tlsgm is relocated with - // R_ARM_TLS_IE32 and runtime.tlsgm(SB) will point - // to the GOT entry containing the TLS offset. - // - // MOV runtime.tlsgm(SB), REGTMP - // ADD REGTMP, <reg> - // SUB -tlsoffset, <reg> - // - // The SUB compensates for tlsoffset - // used in runtime.save_gm and runtime.load_gm. - q = p; - p = appendp(p); - p->as = AMOVW; - p->scond = 14; - p->reg = NREG; - if(flag_shared) { - p->from.type = D_OREG; - p->from.offset = 0; - } else { - p->from.type = D_CONST; - p->from.offset = tlsoffset; - } - p->from.sym = gmsym; - p->from.name = D_EXTERN; - p->to.type = D_REG; - p->to.reg = REGTMP; - p->to.offset = 0; - - p = appendp(p); - p->as = AADD; - p->scond = 14; - p->reg = NREG; - p->from.type = D_REG; - p->from.reg = REGTMP; - p->to.type = D_REG; - p->to.reg = (q->to.offset & 0xf000) >> 12; - p->to.offset = 0; - - if(flag_shared) { - p = appendp(p); - p->as = ASUB; - p->scond = 14; - p->reg = NREG; - p->from.type = D_CONST; - p->from.offset = -tlsoffset; - p->to.type = D_REG; - p->to.reg = (q->to.offset & 0xf000) >> 12; - p->to.offset = 0; - } - } - } - } - q = p; - } - } - - for(cursym = textp; cursym != nil; cursym = cursym->next) { - for(p = cursym->text; p != P; p = p->link) { - o = p->as; - switch(o) { - case ATEXT: - autosize = p->to.offset + 4; - if(autosize <= 4) - if(cursym->text->mark & LEAF) { - p->to.offset = -4; - autosize = 0; - } - - if(!autosize && !(cursym->text->mark & LEAF)) { - if(debug['v']) - Bprint(&bso, "save suppressed in: %s\n", - cursym->name); - Bflush(&bso); - cursym->text->mark |= LEAF; - } - if(cursym->text->mark & LEAF) { - cursym->leaf = 1; - if(!autosize) - break; - } - - if(!(p->reg & NOSPLIT)) - p = stacksplit(p, autosize); // emit split check - - // MOVW.W R14,$-autosize(SP) - p = appendp(p); - p->as = AMOVW; - p->scond |= C_WBIT; - p->from.type = D_REG; - p->from.reg = REGLINK; - p->to.type = D_OREG; - p->to.offset = -autosize; - p->to.reg = REGSP; - p->spadj = autosize; - - if(cursym->text->reg & WRAPPER) { - // g->panicwrap += autosize; - // MOVW panicwrap_offset(g), R3 - // ADD $autosize, R3 - // MOVW R3 panicwrap_offset(g) - p = appendp(p); - p->as = AMOVW; - p->from.type = D_OREG; - p->from.reg = REGG; - p->from.offset = 2*PtrSize; - p->to.type = D_REG; - p->to.reg = 3; - - p = appendp(p); - p->as = AADD; - p->from.type = D_CONST; - p->from.offset = autosize; - p->to.type = D_REG; - p->to.reg = 3; - - p = appendp(p); - p->as = AMOVW; - p->from.type = D_REG; - p->from.reg = 3; - p->to.type = D_OREG; - p->to.reg = REGG; - p->to.offset = 2*PtrSize; - } - break; - - case ARET: - nocache(p); - if(cursym->text->mark & LEAF) { - if(!autosize) { - p->as = AB; - p->from = zprg.from; - if(p->to.sym) { // retjmp - p->to.type = D_BRANCH; - p->cond = p->to.sym->text; - } else { - p->to.type = D_OREG; - p->to.offset = 0; - p->to.reg = REGLINK; - } - break; - } - } - - if(cursym->text->reg & WRAPPER) { - int cond; - - // Preserve original RET's cond, to allow RET.EQ - // in the implementation of reflect.call. - cond = p->scond; - p->scond = C_SCOND_NONE; - - // g->panicwrap -= autosize; - // MOVW panicwrap_offset(g), R3 - // SUB $autosize, R3 - // MOVW R3 panicwrap_offset(g) - p->as = AMOVW; - p->from.type = D_OREG; - p->from.reg = REGG; - p->from.offset = 2*PtrSize; - p->to.type = D_REG; - p->to.reg = 3; - p = appendp(p); - - p->as = ASUB; - p->from.type = D_CONST; - p->from.offset = autosize; - p->to.type = D_REG; - p->to.reg = 3; - p = appendp(p); - - p->as = AMOVW; - p->from.type = D_REG; - p->from.reg = 3; - p->to.type = D_OREG; - p->to.reg = REGG; - p->to.offset = 2*PtrSize; - p = appendp(p); - - p->scond = cond; - } - - p->as = AMOVW; - p->scond |= C_PBIT; - p->from.type = D_OREG; - p->from.offset = autosize; - p->from.reg = REGSP; - p->to.type = D_REG; - p->to.reg = REGPC; - // If there are instructions following - // this ARET, they come from a branch - // with the same stackframe, so no spadj. - - if(p->to.sym) { // retjmp - p->to.reg = REGLINK; - q2 = appendp(p); - q2->as = AB; - q2->to.type = D_BRANCH; - q2->to.sym = p->to.sym; - q2->cond = p->to.sym->text; - p->to.sym = nil; - p = q2; - } - break; - - case AADD: - if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP) - p->spadj = -p->from.offset; - break; - - case ASUB: - if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP) - p->spadj = p->from.offset; - break; - - case ADIV: - case ADIVU: - case AMOD: - case AMODU: - if(debug['M']) - break; - if(p->from.type != D_REG) - break; - if(p->to.type != D_REG) - break; - q1 = p; - - /* MOV a,4(SP) */ - p = appendp(p); - p->as = AMOVW; - p->line = q1->line; - p->from.type = D_REG; - p->from.reg = q1->from.reg; - p->to.type = D_OREG; - p->to.reg = REGSP; - p->to.offset = 4; - - /* MOV b,REGTMP */ - p = appendp(p); - p->as = AMOVW; - p->line = q1->line; - p->from.type = D_REG; - p->from.reg = q1->reg; - if(q1->reg == NREG) - p->from.reg = q1->to.reg; - p->to.type = D_REG; - p->to.reg = REGTMP; - p->to.offset = 0; - - /* CALL appropriate */ - p = appendp(p); - p->as = ABL; - p->line = q1->line; - p->to.type = D_BRANCH; - p->cond = p; - switch(o) { - case ADIV: - p->cond = prog_div; - p->to.sym = sym_div; - break; - case ADIVU: - p->cond = prog_divu; - p->to.sym = sym_divu; - break; - case AMOD: - p->cond = prog_mod; - p->to.sym = sym_mod; - break; - case AMODU: - p->cond = prog_modu; - p->to.sym = sym_modu; - break; - } + LSym *s; - /* MOV REGTMP, b */ - p = appendp(p); - p->as = AMOVW; - p->line = q1->line; - p->from.type = D_REG; - p->from.reg = REGTMP; - p->from.offset = 0; - p->to.type = D_REG; - p->to.reg = q1->to.reg; - - /* ADD $8,SP */ - p = appendp(p); - p->as = AADD; - p->line = q1->line; - p->from.type = D_CONST; - p->from.reg = NREG; - p->from.offset = 8; - p->reg = NREG; - p->to.type = D_REG; - p->to.reg = REGSP; - p->spadj = -8; - - /* Keep saved LR at 0(SP) after SP change. */ - /* MOVW 0(SP), REGTMP; MOVW REGTMP, -8!(SP) */ - /* TODO: Remove SP adjustments; see issue 6699. */ - q1->as = AMOVW; - q1->from.type = D_OREG; - q1->from.reg = REGSP; - q1->from.offset = 0; - q1->reg = NREG; - q1->to.type = D_REG; - q1->to.reg = REGTMP; - - /* SUB $8,SP */ - q1 = appendp(q1); - q1->as = AMOVW; - q1->from.type = D_REG; - q1->from.reg = REGTMP; - q1->reg = NREG; - q1->to.type = D_OREG; - q1->to.reg = REGSP; - q1->to.offset = -8; - q1->scond |= C_WBIT; - q1->spadj = 8; - - break; - case AMOVW: - if((p->scond & C_WBIT) && p->to.type == D_OREG && p->to.reg == REGSP) - p->spadj = -p->to.offset; - if((p->scond & C_PBIT) && p->from.type == D_OREG && p->from.reg == REGSP && p->to.reg != REGPC) - p->spadj = -p->from.offset; - if(p->from.type == D_CONST && p->from.reg == REGSP && p->to.type == D_REG && p->to.reg == REGSP) - p->spadj = -p->from.offset; - break; - } - } - } -} - -static Prog* -stacksplit(Prog *p, int32 framesize) -{ - int32 arg; - - // MOVW g_stackguard(g), R1 - p = appendp(p); - p->as = AMOVW; - p->from.type = D_OREG; - p->from.reg = REGG; - p->to.type = D_REG; - p->to.reg = 1; - - if(framesize <= StackSmall) { - // small stack: SP < stackguard - // CMP stackguard, SP - p = appendp(p); - p->as = ACMP; - p->from.type = D_REG; - p->from.reg = 1; - p->reg = REGSP; - } else if(framesize <= StackBig) { - // large stack: SP-framesize < stackguard-StackSmall - // MOVW $-framesize(SP), R2 - // CMP stackguard, R2 - p = appendp(p); - p->as = AMOVW; - p->from.type = D_CONST; - p->from.reg = REGSP; - p->from.offset = -framesize; - p->to.type = D_REG; - p->to.reg = 2; - - p = appendp(p); - p->as = ACMP; - p->from.type = D_REG; - p->from.reg = 1; - p->reg = 2; - } else { - // Such a large stack we need to protect against wraparound - // if SP is close to zero. - // SP-stackguard+StackGuard < framesize + (StackGuard-StackSmall) - // The +StackGuard on both sides is required to keep the left side positive: - // SP is allowed to be slightly below stackguard. See stack.h. - // CMP $StackPreempt, R1 - // MOVW.NE $StackGuard(SP), R2 - // SUB.NE R1, R2 - // MOVW.NE $(framesize+(StackGuard-StackSmall)), R3 - // CMP.NE R3, R2 - p = appendp(p); - p->as = ACMP; - p->from.type = D_CONST; - p->from.offset = (uint32)StackPreempt; - p->reg = 1; - - p = appendp(p); - p->as = AMOVW; - p->from.type = D_CONST; - p->from.reg = REGSP; - p->from.offset = StackGuard; - p->to.type = D_REG; - p->to.reg = 2; - p->scond = C_SCOND_NE; - - p = appendp(p); - p->as = ASUB; - p->from.type = D_REG; - p->from.reg = 1; - p->to.type = D_REG; - p->to.reg = 2; - p->scond = C_SCOND_NE; - - p = appendp(p); - p->as = AMOVW; - p->from.type = D_CONST; - p->from.offset = framesize + (StackGuard - StackSmall); - p->to.type = D_REG; - p->to.reg = 3; - p->scond = C_SCOND_NE; - - p = appendp(p); - p->as = ACMP; - p->from.type = D_REG; - p->from.reg = 3; - p->reg = 2; - p->scond = C_SCOND_NE; - } - - // MOVW.LS $framesize, R1 - p = appendp(p); - p->as = AMOVW; - p->scond = C_SCOND_LS; - p->from.type = D_CONST; - p->from.offset = framesize; - p->to.type = D_REG; - p->to.reg = 1; - - // MOVW.LS $args, R2 - p = appendp(p); - p->as = AMOVW; - p->scond = C_SCOND_LS; - p->from.type = D_CONST; - arg = cursym->text->to.offset2; - if(arg == 1) // special marker for known 0 - arg = 0; - if(arg&3) - diag("misaligned argument size in stack split"); - p->from.offset = arg; - p->to.type = D_REG; - p->to.reg = 2; - - // MOVW.LS R14, R3 - p = appendp(p); - p->as = AMOVW; - p->scond = C_SCOND_LS; - p->from.type = D_REG; - p->from.reg = REGLINK; - p->to.type = D_REG; - p->to.reg = 3; - - // BL.LS runtime.morestack(SB) // modifies LR, returns with LO still asserted - p = appendp(p); - p->as = ABL; - p->scond = C_SCOND_LS; - p->to.type = D_BRANCH; - p->to.sym = symmorestack; - p->cond = pmorestack; - - // BLS start - p = appendp(p); - p->as = ABLS; - p->to.type = D_BRANCH; - p->cond = cursym->text->link; - - return p; -} - -static void -sigdiv(char *n) -{ - Sym *s; - - s = lookup(n, 0); - if(s->type == STEXT) - if(s->sig == 0) - s->sig = SIGNINTERN; -} - -void -divsig(void) -{ - sigdiv("_div"); - sigdiv("_divu"); - sigdiv("_mod"); - sigdiv("_modu"); -} - -void -initdiv(void) -{ - Sym *s2, *s3, *s4, *s5; - - if(prog_div != P) - return; - sym_div = s2 = lookup("_div", 0); - sym_divu = s3 = lookup("_divu", 0); - sym_mod = s4 = lookup("_mod", 0); - sym_modu = s5 = lookup("_modu", 0); - prog_div = s2->text; - prog_divu = s3->text; - prog_mod = s4->text; - prog_modu = s5->text; - if(prog_div == P) { - diag("undefined: %s", s2->name); - prog_div = cursym->text; - } - if(prog_divu == P) { - diag("undefined: %s", s3->name); - prog_divu = cursym->text; - } - if(prog_mod == P) { - diag("undefined: %s", s4->name); - prog_mod = cursym->text; - } - if(prog_modu == P) { - diag("undefined: %s", s5->name); - prog_modu = cursym->text; - } -} - -void -nocache(Prog *p) -{ - p->optab = 0; - p->from.class = 0; - p->to.class = 0; + for(s = ctxt->textp; s != nil; s = s->next) + ctxt->arch->addstacksplit(ctxt, s); } |