// Inferno utils/5l/pass.c // http://code.google.com/p/inferno-os/source/browse/utils/5l/pass.c // // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) // Portions Copyright © 1997-1999 Vita Nuova Limited // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) // Portions Copyright © 2004,2006 Bruce Ellis // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others // Portions Copyright © 2009 The Go Authors. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // Code and data passes. #include "l.h" #include "../ld/lib.h" static void xfol(Prog*, Prog**); Prog* brchain(Prog *p) { int i; for(i=0; i<20; i++) { if(p == P || p->as != AB) return p; p = p->cond; } return P; } int relinv(int a) { switch(a) { case ABEQ: return ABNE; case ABNE: return ABEQ; case ABCS: return ABCC; case ABHS: return ABLO; case ABCC: return ABCS; case ABLO: return ABHS; case ABMI: return ABPL; case ABPL: return ABMI; case ABVS: return ABVC; case ABVC: return ABVS; case ABHI: return ABLS; case ABLS: return ABHI; case ABGE: return ABLT; case ABLT: return ABGE; case ABGT: return ABLE; case ABLE: return ABGT; } diag("unknown relation: %s", anames[a]); return a; } void follow(void) { Prog *firstp, *lastp; if(debug['v']) Bprint(&bso, "%5.2f follow\n", cputime()); Bflush(&bso); for(cursym = textp; cursym != nil; cursym = cursym->next) { firstp = prg(); lastp = firstp; xfol(cursym->text, &lastp); lastp->link = nil; cursym->text = firstp->link; } } static void xfol(Prog *p, Prog **last) { Prog *q, *r; int a, i; loop: if(p == P) return; a = p->as; if(a == AB) { q = p->cond; if(q != P && q->as != ATEXT) { p->mark |= FOLL; p = q; if(!(p->mark & FOLL)) goto loop; } } if(p->mark & FOLL) { for(i=0,q=p; i<4; i++,q=q->link) { if(q == *last || q == nil) break; a = q->as; if(a == ANOP) { i--; continue; } if(a == AB || (a == ARET && q->scond == 14) || a == ARFE) goto copy; if(q->cond == P || (q->cond->mark&FOLL)) continue; if(a != ABEQ && a != ABNE) continue; copy: for(;;) { r = prg(); *r = *p; if(!(r->mark&FOLL)) print("cant happen 1\n"); r->mark |= FOLL; if(p != q) { p = p->link; (*last)->link = r; *last = r; continue; } (*last)->link = r; *last = r; if(a == AB || (a == ARET && q->scond == 14) || a == ARFE) return; r->as = ABNE; if(a == ABNE) r->as = ABEQ; r->cond = p->link; r->link = p->cond; if(!(r->link->mark&FOLL)) xfol(r->link, last); if(!(r->cond->mark&FOLL)) print("cant happen 2\n"); return; } } a = AB; q = prg(); q->as = a; q->line = p->line; q->to.type = D_BRANCH; q->to.offset = p->pc; q->cond = p; p = q; } p->mark |= FOLL; (*last)->link = p; *last = p; if(a == AB || (a == ARET && p->scond == 14) || a == ARFE){ return; } if(p->cond != P) if(a != ABL && a != ABX && p->link != P) { q = brchain(p->link); if(a != ATEXT && a != ABCASE) if(q != P && (q->mark&FOLL)) { p->as = relinv(a); p->link = p->cond; p->cond = q; } xfol(p->link, last); q = brchain(p->cond); if(q == P) q = p->cond; if(q->mark&FOLL) { p->cond = q; return; } p = q; goto loop; } p = p->link; goto loop; } void patch(void) { int32 c, vexit; Prog *p, *q; Sym *s; int a; if(debug['v']) Bprint(&bso, "%5.2f patch\n", cputime()); Bflush(&bso); mkfwd(); s = lookup("exit", 0); vexit = s->value; for(cursym = textp; cursym != nil; cursym = cursym->next) { for(p = cursym->text; p != P; p = p->link) { a = p->as; if((a == ABL || a == ABX || a == AB || a == ARET) && p->to.type != D_BRANCH && p->to.sym != S) { s = p->to.sym; if(s->text == nil) continue; switch(s->type) { default: diag("undefined: %s", s->name); s->type = STEXT; s->value = vexit; continue; // avoid more error messages case STEXT: p->to.offset = s->value; p->to.type = D_BRANCH; p->cond = s->text; continue; } } if(p->to.type != D_BRANCH) continue; c = p->to.offset; for(q = textp->text; q != P;) { if(c == q->pc) break; if(q->forwd != P && c >= q->forwd->pc) q = q->forwd; else q = q->link; } if(q == P) { diag("branch out of range %d\n%P", c, p); p->to.type = D_NONE; } p->cond = q; } } for(cursym = textp; cursym != nil; cursym = cursym->next) { for(p = cursym->text; p != P; p = p->link) { if(p->cond != P) { p->cond = brloop(p->cond); if(p->cond != P) if(p->to.type == D_BRANCH) p->to.offset = p->cond->pc; } } } } Prog* brloop(Prog *p) { Prog *q; int c; for(c=0; p!=P;) { if(p->as != AB) return p; q = p->cond; if(q <= p) { c++; if(q == p || c > 5000) break; } p = q; } return P; } int32 atolwhex(char *s) { int32 n; int f; n = 0; f = 0; while(*s == ' ' || *s == '\t') s++; if(*s == '-' || *s == '+') { if(*s++ == '-') f = 1; while(*s == ' ' || *s == '\t') s++; } if(s[0]=='0' && s[1]){ if(s[1]=='x' || s[1]=='X'){ s += 2; for(;;){ if(*s >= '0' && *s <= '9') n = n*16 + *s++ - '0'; else if(*s >= 'a' && *s <= 'f') n = n*16 + *s++ - 'a' + 10; else if(*s >= 'A' && *s <= 'F') n = n*16 + *s++ - 'A' + 10; else break; } } else while(*s >= '0' && *s <= '7') n = n*8 + *s++ - '0'; } else while(*s >= '0' && *s <= '9') n = n*10 + *s++ - '0'; if(f) n = -n; return n; } int32 rnd(int32 v, int32 r) { int32 c; if(r <= 0) return v; v += r - 1; c = v % r; if(c < 0) c += r; v -= c; return v; }