# back end breaks: array of ref Inst;conts: array of ref Inst;labels: array of ref Decl;bcscps: array of ref Node;labdep: int;nocont: ref Inst;nlabel: int; scp: int;scps:= array[MaxScope] of ref Node; curfn: ref Decl; pushscp(n : ref Node){ if (scp >= MaxScope) fatal("scope too deep"); scps[scp++] = n;} popscp(){ scp--;} curscp() : ref Node{ if (scp == 0) return nil; return scps[scp-1];} zeroscopes(stop : ref Node){ i : int; cs : ref Node; for (i = scp-1; i >= 0; i--) { cs = scps[i]; if (cs == stop) break; zcom(cs.left, nil); }} zeroallscopes(n: ref Node, nn: array of ref Node){ if(n == nil) return; for(; n != nil; n = n.right){ case(n.op){ Oscope => zeroallscopes(n.right, nn); zcom(n.left, nn); return; Olabel or Odo => zeroallscopes(n.right, nn); return; Oif or Ofor => zeroallscopes(n.right.left, nn); zeroallscopes(n.right.right, nn); return; Oalt or Ocase or Opick or Oexcept => for(n = n.right; n != nil; n = n.right) zeroallscopes(n.left.right, nn); return; Oseq => zeroallscopes(n.left, nn); break; Oexstmt => zeroallscopes(n.left, nn); zeroallscopes(n.right, nn); return; * => return; } }} excs: ref Except; installexc(en: ref Node, p1: ref Inst, p2: ref Inst, zn: ref Node){ e := ref Except; e.p1 = p1; e.p2 = p2; e.c = en.ty.cse; e.d = en.left.decl; e.zn = zn; e.next = excs; excs = e; ne := 0; c := e.c; for(i := 0; i < c.nlab; i++){ lab := c.labs[i]; if(lab.start.ty.kind == Texception) ne++; } e.ne = ne;} inlist(d: ref Decl, dd: ref Decl): int{ for( ; dd != nil; dd = dd.next) if(d == dd) return 1; return 0;} excdesc(){ dd, nd: ref Decl; for(e := excs; e != nil; e = e.next){ if(e.zn != nil){ dd = nil; maxo := 0; for(n := e.zn ; n != nil; n = n.right){ d := n.decl; d.locals = d.next; if(!inlist(d, dd)){ d.next = dd; dd = d; o := d.offset+d.ty.size; if(o > maxo) maxo = o; } } e.desc = gendesc(e.d, align(maxo, MaxAlign), dd); for(d := dd; d != nil; d = nd){ nd = d.next; d.next = d.locals; d.locals = nil; } e.zn = nil; } }} reve(e: ref Except): ref Except{ l, n: ref Except; l = nil; for( ; e != nil; e = n){ n = e.next; e.next = l; l = e; } return l;} ckinline0(n: ref Node, d: ref Decl): int{ dd: ref Decl; if(n == nil) return 1; if(n.op == Oname){ dd = n.decl; if(d == dd) return 0; if(int dd.inline == 1) return ckinline0(dd.init.right, d); return 1; } return ckinline0(n.left, d) && ckinline0(n.right, d);} ckinline(d: ref Decl){ d.inline = byte ckinline0(d.init.right, d);} modcom(entry: ref Decl){ d, m: ref Decl; if(errors) return; if(emitcode != "" || emitstub || emittab != "" || emitsbl != ""){ emit(curscope()); popscope(); return; } # # scom introduces global variables for case statements # and unaddressable constants, so it must be done before # popping the global scope # gent = sys->millisec(); nlabel = 0; maxstack = MaxTemp; nocont = ref Inst; genstart(); for(i := 0; i < nfns; i++) if(int fns[i].inline == 1) ckinline(fns[i]); ok := 0; for(i = 0; i < nfns; i++){ d = fns[i]; if(d.refs > 1 && !(int d.inline == 1 && local(d) && d.iface == nil)){ fns[ok++] = d; fncom(d); } } fns = fns[:ok]; nfns = ok; if(blocks != -1) fatal("blocks not nested correctly"); firstinst = firstinst.next; if(errors) return; globals := popscope(); checkrefs(globals); if(errors) return; globals = vars(globals); moddataref(); nils := popscope(); m = nil; for(d = nils; d != nil; d = d.next){ if(debug['n']) print("nil '%s' ref %d\n", d.sym.name, d.refs); if(d.refs && m == nil) m = dupdecl(d); d.offset = 0; } globals = appdecls(m, globals); globals = namesort(globals); globals = modglobals(impdecls.d, globals); vcom(globals); narrowmods(); ldts: ref Decl; if(LDT) (globals, ldts) = resolveldts(globals); offset := idoffsets(globals, 0, IBY2WD); if(LDT) ldtoff := idindices(ldts); # idoffsets(ldts, 0, IBY2WD); for(d = nils; d != nil; d = d.next){ if(debug['n']) print("nil '%s' ref %d\n", d.sym.name, d.refs); if(d.refs) d.offset = m.offset; } if(debug['g']){ print("globals:\n"); printdecls(globals); } ndata := 0; for(d = globals; d != nil; d = d.next) ndata++; ndesc := resolvedesc(impdecls.d, offset, globals); ninst := resolvepcs(firstinst); modresolve(); if(impdecls.next != nil) for(dl := impdecls; dl != nil; dl = dl.next) resolvemod(dl.d); nlink := resolvemod(impdecl); gent = sys->millisec() - gent; maxstack *= 10; if(fixss != 0) maxstack = fixss; if(debug['s']) print("%d instructions\n%d data elements\n%d type descriptors\n%d functions exported\n%d stack size\n", ninst, ndata, ndesc, nlink, maxstack); excs = reve(excs); writet = sys->millisec(); if(gendis){ discon(XMAGIC); hints := 0; if(mustcompile) hints |= MUSTCOMPILE; if(dontcompile) hints |= DONTCOMPILE; if(LDT) hints |= HASLDT; if(excs != nil) hints |= HASEXCEPT; discon(hints); # runtime hints discon(maxstack); # minimum stack extent size discon(ninst); discon(offset); discon(ndesc); discon(nlink); disentry(entry); disinst(firstinst); disdesc(descriptors); disvar(offset, globals); dismod(impdecl); if(LDT) disldt(ldtoff, ldts); if(excs != nil) disexc(excs); dispath(); }else{ asminst(firstinst); asmentry(entry); asmdesc(descriptors); asmvar(offset, globals); asmmod(impdecl); if(LDT) asmldt(ldtoff, ldts); if(excs != nil) asmexc(excs); asmpath(); } writet = sys->millisec() - writet; symt = sys->millisec(); if(bsym != nil){ sblmod(impdecl); sblfiles(); sblinst(firstinst, ninst); sblty(adts, nadts); sblfn(fns, nfns); sblvar(globals); } symt = sys->millisec() - symt; firstinst = nil; lastinst = nil; excs = nil;} fncom(decl: ref Decl){ curfn = decl; if(ispoly(decl)) addfnptrs(decl, 1); # # pick up the function body and compile it # this code tries to clean up the parse nodes as fast as possible # function is Ofunc(name, body) # decl.pc = nextinst(); tinit(); labdep = 0; scp = 0; breaks = array[maxlabdep] of ref Inst; conts = array[maxlabdep] of ref Inst; labels = array[maxlabdep] of ref Decl; bcscps = array[maxlabdep] of ref Node; n := decl.init; if(int decl.inline == 1) decl.init = dupn(0, nosrc, n); else decl.init = n.left; src := n.right.src; src.start = src.stop - 1; for(n = n.right; n != nil; n = n.right){ if(n.op != Oseq){ if(n.op == Ocall && trcom(n, nil, 1)) break; scom(n); break; } if(n.left.op == Ocall && trcom(n.left, n.right, 1)){ n = n.right; if(n == nil || n.op != Oseq) break; } else scom(n.left); } pushblock(); valued := decl.ty.tof != tnone; if(valued) in := genrawop(src, IRAISE, nil, nil, nil); else in = genrawop(src, IRET, nil, nil, nil); popblock(); reach(decl.pc); if(valued && in.reach != byte 0) error(src.start, "no return at end of function " + dotconv(decl)); # decl.endpc = lastinst; if(labdep != 0) fatal("unbalanced label stack"); breaks = nil; conts = nil; labels = nil; bcscps = nil; loc := declsort(appdecls(vars(decl.locals), tdecls())); decl.offset = idoffsets(loc, decl.offset, MaxAlign); for(last := decl.ty.ids; last != nil && last.next != nil; last = last.next) ; if(last != nil) last.next = loc; else decl.ty.ids = loc; if(debug['f']){ print("fn: %s\n", decl.sym.name); printdecls(decl.ty.ids); } decl.desc = gendesc(decl, decl.offset, decl.ty.ids); decl.locals = loc; excdesc(); if(decl.offset > maxstack) maxstack = decl.offset; if(optims) optim(decl.pc, decl); if(last != nil) last.next = nil; else decl.ty.ids = nil;} ## statement compiler#scom(n: ref Node){ b: int; p, pp: ref Inst; left: ref Node; for(; n != nil; n = n.right){ case n.op{ Ocondecl or Otypedecl or Ovardecl or Oimport or Oexdecl => return; Ovardecli => break; Oscope => pushscp(n); scom(n.right); popscp(); zcom(n.left, nil); return; Olabel => scom(n.right); return; Oif => pushblock(); left = simplify(n.left); if(left.op == Oconst && left.ty == tint){ if(left.c.val != big 0) scom(n.right.left); else scom(n.right.right); popblock(); return; } sumark(left); pushblock(); p = bcom(left, 1, nil); tfreenow(); popblock(); scom(n.right.left); if(n.right.right != nil){ pp = p; p = genrawop(lastinst.src, IJMP, nil, nil, nil); patch(pp, nextinst()); scom(n.right.right); } patch(p, nextinst()); popblock(); return; Ofor => n.left = left = simplify(n.left); if(left.op == Oconst && left.ty == tint){ if(left.c.val == big 0) return; left.op = Onothing; left.ty = tnone; left.decl = nil; } pp = nextinst(); b = pushblock();Lines 1–500 of 1402. Load more
# back end breaks: array of ref Inst; conts: array of ref Inst; labels: array of ref Decl; bcscps: array of ref Node; labdep: int; nocont: ref Inst; nlabel: int; scp: int; scps:= array[MaxScope] of ref Node; curfn: ref Decl; pushscp(n : ref Node) { if (scp >= MaxScope) fatal("scope too deep"); scps[scp++] = n; } popscp() { scp--; } curscp() : ref Node { if (scp == 0) return nil; return scps[scp-1]; } zeroscopes(stop : ref Node) { i : int; cs : ref Node; for (i = scp-1; i >= 0; i--) { cs = scps[i]; if (cs == stop) break; zcom(cs.left, nil); } } zeroallscopes(n: ref Node, nn: array of ref Node) { if(n == nil) return; for(; n != nil; n = n.right){ case(n.op){ Oscope => zeroallscopes(n.right, nn); zcom(n.left, nn); return; Olabel or Odo => zeroallscopes(n.right, nn); return; Oif or Ofor => zeroallscopes(n.right.left, nn); zeroallscopes(n.right.right, nn); return; Oalt or Ocase or Opick or Oexcept => for(n = n.right; n != nil; n = n.right) zeroallscopes(n.left.right, nn); return; Oseq => zeroallscopes(n.left, nn); break; Oexstmt => zeroallscopes(n.left, nn); zeroallscopes(n.right, nn); return; * => return; } } } excs: ref Except; installexc(en: ref Node, p1: ref Inst, p2: ref Inst, zn: ref Node) { e := ref Except; e.p1 = p1; e.p2 = p2; e.c = en.ty.cse; e.d = en.left.decl; e.zn = zn; e.next = excs; excs = e; ne := 0; c := e.c; for(i := 0; i < c.nlab; i++){ lab := c.labs[i]; if(lab.start.ty.kind == Texception) ne++; } e.ne = ne; } inlist(d: ref Decl, dd: ref Decl): int { for( ; dd != nil; dd = dd.next) if(d == dd) return 1; return 0; } excdesc() { dd, nd: ref Decl; for(e := excs; e != nil; e = e.next){ if(e.zn != nil){ dd = nil; maxo := 0; for(n := e.zn ; n != nil; n = n.right){ d := n.decl; d.locals = d.next; if(!inlist(d, dd)){ d.next = dd; dd = d; o := d.offset+d.ty.size; if(o > maxo) maxo = o; } } e.desc = gendesc(e.d, align(maxo, MaxAlign), dd); for(d := dd; d != nil; d = nd){ nd = d.next; d.next = d.locals; d.locals = nil; } e.zn = nil; } } } reve(e: ref Except): ref Except { l, n: ref Except; l = nil; for( ; e != nil; e = n){ n = e.next; e.next = l; l = e; } return l; } ckinline0(n: ref Node, d: ref Decl): int { dd: ref Decl; if(n == nil) return 1; if(n.op == Oname){ dd = n.decl; if(d == dd) return 0; if(int dd.inline == 1) return ckinline0(dd.init.right, d); return 1; } return ckinline0(n.left, d) && ckinline0(n.right, d); } ckinline(d: ref Decl) { d.inline = byte ckinline0(d.init.right, d); } modcom(entry: ref Decl) { d, m: ref Decl; if(errors) return; if(emitcode != "" || emitstub || emittab != "" || emitsbl != ""){ emit(curscope()); popscope(); return; } # # scom introduces global variables for case statements # and unaddressable constants, so it must be done before # popping the global scope # gent = sys->millisec(); nlabel = 0; maxstack = MaxTemp; nocont = ref Inst; genstart(); for(i := 0; i < nfns; i++) if(int fns[i].inline == 1) ckinline(fns[i]); ok := 0; for(i = 0; i < nfns; i++){ d = fns[i]; if(d.refs > 1 && !(int d.inline == 1 && local(d) && d.iface == nil)){ fns[ok++] = d; fncom(d); } } fns = fns[:ok]; nfns = ok; if(blocks != -1) fatal("blocks not nested correctly"); firstinst = firstinst.next; if(errors) return; globals := popscope(); checkrefs(globals); if(errors) return; globals = vars(globals); moddataref(); nils := popscope(); m = nil; for(d = nils; d != nil; d = d.next){ if(debug['n']) print("nil '%s' ref %d\n", d.sym.name, d.refs); if(d.refs && m == nil) m = dupdecl(d); d.offset = 0; } globals = appdecls(m, globals); globals = namesort(globals); globals = modglobals(impdecls.d, globals); vcom(globals); narrowmods(); ldts: ref Decl; if(LDT) (globals, ldts) = resolveldts(globals); offset := idoffsets(globals, 0, IBY2WD); if(LDT) ldtoff := idindices(ldts); # idoffsets(ldts, 0, IBY2WD); for(d = nils; d != nil; d = d.next){ if(debug['n']) print("nil '%s' ref %d\n", d.sym.name, d.refs); if(d.refs) d.offset = m.offset; } if(debug['g']){ print("globals:\n"); printdecls(globals); } ndata := 0; for(d = globals; d != nil; d = d.next) ndata++; ndesc := resolvedesc(impdecls.d, offset, globals); ninst := resolvepcs(firstinst); modresolve(); if(impdecls.next != nil) for(dl := impdecls; dl != nil; dl = dl.next) resolvemod(dl.d); nlink := resolvemod(impdecl); gent = sys->millisec() - gent; maxstack *= 10; if(fixss != 0) maxstack = fixss; if(debug['s']) print("%d instructions\n%d data elements\n%d type descriptors\n%d functions exported\n%d stack size\n", ninst, ndata, ndesc, nlink, maxstack); excs = reve(excs); writet = sys->millisec(); if(gendis){ discon(XMAGIC); hints := 0; if(mustcompile) hints |= MUSTCOMPILE; if(dontcompile) hints |= DONTCOMPILE; if(LDT) hints |= HASLDT; if(excs != nil) hints |= HASEXCEPT; discon(hints); # runtime hints discon(maxstack); # minimum stack extent size discon(ninst); discon(offset); discon(ndesc); discon(nlink); disentry(entry); disinst(firstinst); disdesc(descriptors); disvar(offset, globals); dismod(impdecl); if(LDT) disldt(ldtoff, ldts); if(excs != nil) disexc(excs); dispath(); }else{ asminst(firstinst); asmentry(entry); asmdesc(descriptors); asmvar(offset, globals); asmmod(impdecl); if(LDT) asmldt(ldtoff, ldts); if(excs != nil) asmexc(excs); asmpath(); } writet = sys->millisec() - writet; symt = sys->millisec(); if(bsym != nil){ sblmod(impdecl); sblfiles(); sblinst(firstinst, ninst); sblty(adts, nadts); sblfn(fns, nfns); sblvar(globals); } symt = sys->millisec() - symt; firstinst = nil; lastinst = nil; excs = nil; } fncom(decl: ref Decl) { curfn = decl; if(ispoly(decl)) addfnptrs(decl, 1); # # pick up the function body and compile it # this code tries to clean up the parse nodes as fast as possible # function is Ofunc(name, body) # decl.pc = nextinst(); tinit(); labdep = 0; scp = 0; breaks = array[maxlabdep] of ref Inst; conts = array[maxlabdep] of ref Inst; labels = array[maxlabdep] of ref Decl; bcscps = array[maxlabdep] of ref Node; n := decl.init; if(int decl.inline == 1) decl.init = dupn(0, nosrc, n); else decl.init = n.left; src := n.right.src; src.start = src.stop - 1; for(n = n.right; n != nil; n = n.right){ if(n.op != Oseq){ if(n.op == Ocall && trcom(n, nil, 1)) break; scom(n); break; } if(n.left.op == Ocall && trcom(n.left, n.right, 1)){ n = n.right; if(n == nil || n.op != Oseq) break; } else scom(n.left); } pushblock(); valued := decl.ty.tof != tnone; if(valued) in := genrawop(src, IRAISE, nil, nil, nil); else in = genrawop(src, IRET, nil, nil, nil); popblock(); reach(decl.pc); if(valued && in.reach != byte 0) error(src.start, "no return at end of function " + dotconv(decl)); # decl.endpc = lastinst; if(labdep != 0) fatal("unbalanced label stack"); breaks = nil; conts = nil; labels = nil; bcscps = nil; loc := declsort(appdecls(vars(decl.locals), tdecls())); decl.offset = idoffsets(loc, decl.offset, MaxAlign); for(last := decl.ty.ids; last != nil && last.next != nil; last = last.next) ; if(last != nil) last.next = loc; else decl.ty.ids = loc; if(debug['f']){ print("fn: %s\n", decl.sym.name); printdecls(decl.ty.ids); } decl.desc = gendesc(decl, decl.offset, decl.ty.ids); decl.locals = loc; excdesc(); if(decl.offset > maxstack) maxstack = decl.offset; if(optims) optim(decl.pc, decl); if(last != nil) last.next = nil; else decl.ty.ids = nil; } # # statement compiler # scom(n: ref Node) { b: int; p, pp: ref Inst; left: ref Node; for(; n != nil; n = n.right){ case n.op{ Ocondecl or Otypedecl or Ovardecl or Oimport or Oexdecl => return; Ovardecli => break; Oscope => pushscp(n); scom(n.right); popscp(); zcom(n.left, nil); return; Olabel => scom(n.right); return; Oif => pushblock(); left = simplify(n.left); if(left.op == Oconst && left.ty == tint){ if(left.c.val != big 0) scom(n.right.left); else scom(n.right.right); popblock(); return; } sumark(left); pushblock(); p = bcom(left, 1, nil); tfreenow(); popblock(); scom(n.right.left); if(n.right.right != nil){ pp = p; p = genrawop(lastinst.src, IJMP, nil, nil, nil); patch(pp, nextinst()); scom(n.right.right); } patch(p, nextinst()); popblock(); return; Ofor => n.left = left = simplify(n.left); if(left.op == Oconst && left.ty == tint){ if(left.c.val == big 0) return; left.op = Onothing; left.ty = tnone; left.decl = nil; } pp = nextinst(); b = pushblock();