ref: ee695eff4329234e20abb68ff3100d3b15929418
dir: /appl/cmd/limbo/ecom.b/
maxstack: int; # max size of a stack frame called precasttab := array[Tend] of array of ref Type; optabinit() { ct := array[Tend] of ref Type; for(i := 0; i < Tend; i++) precasttab[i] = ct; precasttab[Tstring] = array[Tend] of { Tbyte => tint, Tfix => treal, }; precasttab[Tbig] = array[Tend] of { Tbyte => tint, Tfix => treal, }; precasttab[Treal] = array[Tend] of { Tbyte => tint, }; precasttab[Tfix] = array[Tend] of { Tbyte => tint, Tstring => treal, Tbig => treal, }; precasttab[Tbyte] = array[Tend] of { Tstring => tint, Tbig => tint, Treal => tint, Tfix => tint, }; casttab = array[Tend] of { * => array[Tend] of {* => 0}}; casttab[Tint][Tint] = IMOVW; casttab[Tbig][Tbig] = IMOVL; casttab[Treal][Treal] = IMOVF; casttab[Tbyte][Tbyte] = IMOVB; casttab[Tstring][Tstring] = IMOVP; casttab[Tfix][Tfix] = ICVTXX; # never same type casttab[Tint][Tbyte] = ICVTWB; casttab[Tint][Treal] = ICVTWF; casttab[Tint][Tstring] = ICVTWC; casttab[Tint][Tfix] = ICVTXX; casttab[Tbyte][Tint] = ICVTBW; casttab[Treal][Tint] = ICVTFW; casttab[Tstring][Tint] = ICVTCW; casttab[Tfix][Tint] = ICVTXX; casttab[Tint][Tbig] = ICVTWL; casttab[Treal][Tbig] = ICVTFL; casttab[Tstring][Tbig] = ICVTCL; casttab[Tbig][Tint] = ICVTLW; casttab[Tbig][Treal] = ICVTLF; casttab[Tbig][Tstring] = ICVTLC; casttab[Treal][Tstring] = ICVTFC; casttab[Tstring][Treal] = ICVTCF; casttab[Treal][Tfix] = ICVTFX; casttab[Tfix][Treal] = ICVTXF; casttab[Tstring][Tarray] = ICVTCA; casttab[Tarray][Tstring] = ICVTAC; # # placeholders; fixed in precasttab # casttab[Tbyte][Tstring] = 16rff; casttab[Tstring][Tbyte] = 16rff; casttab[Tbyte][Treal] = 16rff; casttab[Treal][Tbyte] = 16rff; casttab[Tbyte][Tbig] = 16rff; casttab[Tbig][Tbyte] = 16rff; casttab[Tfix][Tbyte] = 16rff; casttab[Tbyte][Tfix] = 16rff; casttab[Tfix][Tbig] = 16rff; casttab[Tbig][Tfix] = 16rff; casttab[Tfix][Tstring] = 16rff; casttab[Tstring][Tfix] = 16rff; } # # global variable and constant initialization checking # vcom(ids: ref Decl): int { ok := 1; for(v := ids; v != nil; v = v.next) ok &= varcom(v); for(v = ids; v != nil; v = v.next) v.init = simplify(v.init); return ok; } simplify(n: ref Node): ref Node { if(n == nil) return nil; if(debug['F']) print("simplify %s\n", nodeconv(n)); n = efold(rewrite(n)); if(debug['F']) print("simplified %s\n", nodeconv(n)); return n; } isfix(n: ref Node): int { if(n.ty.kind == Tint || n.ty.kind == Tfix){ if(n.op == Ocast) return n.left.ty.kind == Tint || n.left.ty.kind == Tfix; return 1; } return 0; } # # rewrite an expression to make it easiser to compile, # or give the correct results # rewrite(n: ref Node): ref Node { v: big; t: ref Type; d: ref Decl; nn: ref Node; if(n == nil) return nil; left := n.left; right := n.right; # # rewrites # case n.op{ Oname => d = n.decl; if(d.importid != nil){ left = mkbin(Omdot, dupn(1, n.src, d.eimport), mkdeclname(n.src, d.importid)); left.ty = n.ty; return rewrite(left); } if((t = n.ty).kind == Texception){ if(int t.cons) fatal("cons in rewrite Oname"); n = mkbin(Oadd, n, mkconst(n.src, big(2*IBY2WD))); n = mkunary(Oind, n); n.ty = t; n.left.ty = n.left.left.ty = tint; return rewrite(n); } Odas => n.op = Oas; return rewrite(n); Oneg => n.left = rewrite(left); if(n.ty == treal) break; left = n.left; n.right = left; n.left = mkconst(n.src, big 0); n.left.ty = n.ty; n.op = Osub; Ocomp => v = big 0; v = ~v; n.right = mkconst(n.src, v); n.right.ty = n.ty; n.left = rewrite(left); n.op = Oxor; Oinc or Odec or Opreinc or Opredec => n.left = rewrite(left); case n.ty.kind{ Treal => n.right = mkrconst(n.src, 1.0); Tint or Tbig or Tbyte or Tfix => n.right = mkconst(n.src, big 1); n.right.ty = n.ty; * => fatal("can't rewrite inc/dec "+nodeconv(n)); } if(n.op == Opreinc) n.op = Oaddas; else if(n.op == Opredec) n.op = Osubas; Oslice => if(right.left.op == Onothing) right.left = mkconst(right.left.src, big 0); n.left = rewrite(left); n.right = rewrite(right); Oindex => n.op = Oindx; n.left = rewrite(left); n.right = rewrite(right); n = mkunary(Oind, n); n.ty = n.left.ty; n.left.ty = tint; Oload => n.right = mkn(Oname, nil, nil); n.right.src = n.left.src; n.right.decl = n.ty.tof.decl; n.right.ty = n.ty; n.left = rewrite(left); Ocast => if(left.ty.kind == Texception){ n = rewrite(left); break; } n.op = Ocast; t = precasttab[left.ty.kind][n.ty.kind]; if(t != nil){ n.left = mkunary(Ocast, left); n.left.ty = t; return rewrite(n); } n.left = rewrite(left); Oraise => if(left.ty == tstring) ; else if(left.ty.cons == byte 0) break; else if(left.op != Ocall || left.left.ty.kind == Tfn){ left = mkunary(Ocall, left); left.ty = left.left.ty; } n.left = rewrite(left); Ocall => t = left.ty; if(t.kind == Tref) t = t.tof; if(t.kind == Tfn){ if(left.ty.kind == Tref){ # call by function reference n.left = mkunary(Oind, left); n.left.ty = t; return rewrite(n); } d = nil; if(left.op == Oname) d = left.decl; else if(left.op == Omdot && left.right.op == Odot) d = left.right.right.decl; else if(left.op == Omdot || left.op == Odot) d = left.right.decl; else if(left.op != Oind) fatal("cannot deal with call " + nodeconv(n) + " in rewrite"); if(ispoly(d)) addfnptrs(d, 0); n.left = rewrite(left); if(right != nil) n.right = rewrite(right); if(d != nil && int d.inline == 1) n = simplify(inline(n)); break; } case n.ty.kind{ Tref => n = mkunary(Oref, n); n.ty = n.left.ty; n.left.ty = n.left.ty.tof; n.left.left.ty = n.left.ty; return rewrite(n); Tadt => n.op = Otuple; n.right = nil; if(n.ty.tags != nil){ n.left = nn = mkunary(Oseq, mkconst(n.src, big left.right.decl.tag)); if(right != nil){ nn.right = right; nn.src.stop = right.src.stop; } n.ty = left.right.decl.ty.tof; }else n.left = right; return rewrite(n); Tadtpick => n.op = Otuple; n.right = nil; n.left = nn = mkunary(Oseq, mkconst(n.src, big left.right.decl.tag)); if(right != nil){ nn.right = right; nn.src.stop = right.src.stop; } n.ty = left.right.decl.ty.tof; return rewrite(n); Texception => if(n.ty.cons == byte 0) return n.left; if(left.op == Omdot){ left.right.ty = left.ty; left = left.right; } n.op = Otuple; n.right = nil; n.left = nn = mkunary(Oseq, left.decl.init); nn.right = mkunary(Oseq, mkconst(n.src, big 0)); nn.right.right = right; n.ty = mkexbasetype(n.ty); n = mkunary(Oref, n); n.ty = internaltype(mktype(n.src.start, n.src.stop, Tref, t, nil)); return rewrite(n); * => fatal("can't deal with "+nodeconv(n)+" in rewrite/Ocall"); } Omdot => # # what about side effects from left? # d = right.decl; case d.store{ Dfn => n.left = rewrite(left); if(right.op == Odot){ n.right = dupn(1, left.src, right.right); n.right.ty = d.ty; } Dconst or Dtag or Dtype => # handled by fold return n; Dglobal => right.op = Oconst; right.c = ref Const(big d.offset, 0.); right.ty = tint; n.left = left = mkunary(Oind, left); left.ty = tint; n.op = Oadd; n = mkunary(Oind, n); n.ty = n.left.ty; n.left.ty = tint; n.left = rewrite(n.left); return n; Darg => return n; * => fatal("can't deal with "+nodeconv(n)+" in rewrite/Omdot"); } Odot => # # what about side effects from left? # d = right.decl; case d.store{ Dfn => if(right.left != nil){ n = mkbin(Omdot, dupn(1, left.src, right.left), right); right.left = nil; n.ty = d.ty; return rewrite(n); } if(left.ty.kind == Tpoly){ n = mkbin(Omdot, mkdeclname(left.src, d.link), mkdeclname(left.src, d.link.next)); n.ty = d.ty; return rewrite(n); } n.op = Oname; n.decl = d; n.right = nil; n.left = nil; return n; Dconst or Dtag or Dtype => # handled by fold return n; } if(istuple(left)) return n; # handled by fold right.op = Oconst; right.c = ref Const(big d.offset, 0.); right.ty = tint; if(left.ty.kind != Tref){ n.left = mkunary(Oadr, left); n.left.ty = tint; } n.op = Oadd; n = mkunary(Oind, n); n.ty = n.left.ty; n.left.ty = tint; n.left = rewrite(n.left); return n; Oadr => left = rewrite(left); n.left = left; if(left.op == Oind) return left.left; Otagof => if(n.decl == nil){ n.op = Oind; return rewrite(n); } return n; Omul or Odiv => left = n.left = rewrite(left); right = n.right = rewrite(right); if(n.ty.kind == Tfix && isfix(left) && isfix(right)){ if(left.op == Ocast && tequal(left.ty, n.ty)) n.left = left.left; if(right.op == Ocast && tequal(right.ty, n.ty)) n.right = right.left; } Oself => if(newfnptr) return n; if(selfdecl == nil){ d = selfdecl = mkids(n.src, enter(".self", 5), tany, nil); installids(Dglobal, d); d.refs++; } nn = mkn(Oload, nil, nil); nn.src = n.src; nn.left = mksconst(n.src, enterstring("$self")); nn.ty = impdecl.ty; usetype(nn.ty); usetype(nn.ty.tof); nn = rewrite(nn); nn.op = Oself; return nn; Ofnptr => if(n.flags == byte 0){ # module if(left == nil) left = mkn(Oself, nil, nil); return rewrite(left); } right.flags = n.flags; n = right; d = n.decl; if(int n.flags == FNPTR2){ if(left != nil && left.op != Oname) fatal("not Oname for addiface"); if(left == nil){ addiface(nil, d); if(newfnptr) n.flags |= byte FNPTRN; } else addiface(left.decl, d); n.ty = tint; return n; } if(int n.flags == FNPTRA){ n = mkdeclname(n.src, d.link); n.ty = tany; return n; } if(int n.flags == (FNPTRA|FNPTR2)){ n = mkdeclname(n.src, d.link.next); n.ty = tint; return n; } Ochan => if(left == nil) left = n.left = mkconst(n.src, big 0); n.left = rewrite(left); * => n.left = rewrite(left); n.right = rewrite(right); } return n; } # # label a node with sethi-ullman numbers and addressablity # genaddr interprets addable to generate operands, # so a change here mandates a change there. # # addressable: # const Rconst $value may also be Roff or Rdesc or Rnoff # Asmall(local) Rreg value(FP) # Asmall(global) Rmreg value(MP) # ind(Rareg) Rreg value(FP) # ind(Ramreg) Rmreg value(MP) # ind(Rreg) Radr *value(FP) # ind(Rmreg) Rmadr *value(MP) # ind(Raadr) Radr value(value(FP)) # ind(Ramadr) Rmadr value(value(MP)) # # almost addressable: # adr(Rreg) Rareg # adr(Rmreg) Ramreg # add(const, Rareg) Rareg # add(const, Ramreg) Ramreg # add(const, Rreg) Raadr # add(const, Rmreg) Ramadr # add(const, Raadr) Raadr # add(const, Ramadr) Ramadr # adr(Radr) Raadr # adr(Rmadr) Ramadr # # strangely addressable: # fn Rpc # mdot(module,exp) Rmpc # sumark(n: ref Node): ref Node { if(n == nil) return nil; n.temps = byte 0; n.addable = Rcant; left := n.left; right := n.right; if(left != nil){ sumark(left); n.temps = left.temps; } if(right != nil){ sumark(right); if(right.temps == n.temps) n.temps++; else if(right.temps > n.temps) n.temps = right.temps; } case n.op{ Oadr => case int left.addable{ int Rreg => n.addable = Rareg; int Rmreg => n.addable = Ramreg; int Radr => n.addable = Raadr; int Rmadr => n.addable = Ramadr; } Oind => case int left.addable{ int Rreg => n.addable = Radr; int Rmreg => n.addable = Rmadr; int Rareg => n.addable = Rreg; int Ramreg => n.addable = Rmreg; int Raadr => n.addable = Radr; int Ramadr => n.addable = Rmadr; } Oname => case n.decl.store{ Darg or Dlocal => n.addable = Rreg; Dglobal => n.addable = Rmreg; if(LDT && n.decl.ty.kind == Tiface) n.addable = Rldt; Dtype => # # check for inferface to load # if(n.decl.ty.kind == Tmodule) n.addable = Rmreg; Dfn => if(int n.flags & FNPTR){ if(int n.flags == FNPTR2) n.addable = Roff; else if(int n.flags == (FNPTR2|FNPTRN)) n.addable = Rnoff; } else n.addable = Rpc; * => fatal("cannot deal with "+declconv(n.decl)+" in Oname in "+nodeconv(n)); } Omdot => n.addable = Rmpc; Oconst => case n.ty.kind{ Tint or Tfix => v := int n.c.val; if(v < 0 && ((v >> 29) & 7) != 7 || v > 0 && (v >> 29) != 0){ n.decl = globalconst(n); n.addable = Rmreg; }else n.addable = Rconst; Tbig => n.decl = globalBconst(n); n.addable = Rmreg; Tbyte => n.decl = globalbconst(n); n.addable = Rmreg; Treal => n.decl = globalfconst(n); n.addable = Rmreg; Tstring => n.decl = globalsconst(n); n.addable = Rmreg; * => fatal("cannot const in sumark "+typeconv(n.ty)); } Oadd => if(right.addable == Rconst){ case int left.addable{ int Rareg => n.addable = Rareg; int Ramreg => n.addable = Ramreg; int Rreg or int Raadr => n.addable = Raadr; int Rmreg or int Ramadr => n.addable = Ramadr; } } } if(n.addable < Rcant) n.temps = byte 0; else if(n.temps == byte 0) n.temps = byte 1; return n; } mktn(t: ref Type): ref Node { n := mkn(Oname, nil, nil); usedesc(mktdesc(t)); n.ty = t; if(t.decl == nil) fatal("mktn nil decl t "+typeconv(t)); n.decl = t.decl; n.addable = Rdesc; return n; } # does a tuple of the form (a, b, ...) form a contiguous block # of memory on the stack when offsets are assigned later # - only when (a, b, ...) := rhs and none of the names nil # can we guarantee this # tupblk0(n: ref Node, d: ref Decl): (int, ref Decl) { ok, nid: int; case(n.op){ Otuple => for(n = n.left; n != nil; n = n.right){ (ok, d) = tupblk0(n.left, d); if(!ok) return (0, nil); } return (1, d); Oname => if(n.decl == nildecl) return (0, nil); if(d != nil && d.next != n.decl) return (0, nil); nid = int n.decl.nid; if(d == nil && nid == 1) return (0, nil); if(d != nil && nid != 0) return (0, nil); return (1, n.decl); } return (0, nil); } # could force locals to be next to each other # - need to shuffle locals list # - later # tupblk(n: ref Node): ref Node { ok: int; d: ref Decl; if(n.op != Otuple) return nil; d = nil; (ok, d) = tupblk0(n, d); if(!ok) return nil; while(n.op == Otuple) n = n.left.left; if(n.op != Oname || n.decl.nid == byte 1) fatal("bad tupblk"); return n; } # for cprof esrc(src: Src, osrc: Src, nto: ref Node): Src { if(nto != nil && src.start != 0 && src.stop != 0) return src; return osrc; } # # compile an expression with an implicit assignment # note: you are not allowed to use nto.src # # need to think carefully about the types used in moves # ecom(src: Src, nto, n: ref Node): ref Node { tleft, tright, tto, ttn: ref Node; t: ref Type; p: ref Inst; if(debug['e']){ print("ecom: %s\n", nodeconv(n)); if(nto != nil) print("ecom nto: %s\n", nodeconv(nto)); } if(n.addable < Rcant){ # # think carefully about the type used here # if(nto != nil) genmove(src, Mas, n.ty, n, nto); return nto; } left := n.left; right := n.right; op := n.op; case op{ * => fatal("can't ecom "+nodeconv(n)); return nto; Oif => p = bcom(left, 1, nil); ecom(right.left.src, nto, right.left); if(right.right != nil){ pp := p; p = genrawop(right.left.src, IJMP, nil, nil, nil); patch(pp, nextinst()); ecom(right.right.src, nto, right.right); } patch(p, nextinst()); Ocomma => ttn = left.left; ecom(left.src, nil, left); ecom(right.src, nto, right); tfree(ttn); Oname => if(n.addable == Rpc){ if(nto != nil) genmove(src, Mas, n.ty, n, nto); return nto; } fatal("can't ecom "+nodeconv(n)); Onothing => break; Oused => if(nto != nil) fatal("superflous used "+nodeconv(left)+" nto "+nodeconv(nto)); tto = talloc(left.ty, nil); ecom(left.src, tto, left); tfree(tto); Oas => if(right.ty == tany) right.ty = n.ty; if(left.op == Oname && left.decl.ty == tany){ if(nto == nil) nto = tto = talloc(right.ty, nil); left = nto; nto = nil; } if(left.op == Oinds){ indsascom(src, nto, n); tfree(tto); break; } if(left.op == Oslice){ slicelcom(src, nto, n); tfree(tto); break; } if(left.op == Otuple){ if(!tupsaliased(right, left)){ if((tn := tupblk(left)) != nil){ tn.ty = n.ty; ecom(n.right.src, tn, right); if(nto != nil) genmove(src, Mas, n.ty, tn, nto); tfree(tto); break; } if((tn = tupblk(right)) != nil){ tn.ty = n.ty; tuplcom(tn, left); if(nto != nil) genmove(src, Mas, n.ty, tn, nto); tfree(tto); break; } if(nto == nil && right.op == Otuple && left.ty.kind != Tadtpick){ tuplrcom(right, left); tfree(tto); break; } } if(right.addable >= Ralways || right.op != Oname || tupaliased(right, left)){ tright = talloc(n.ty, nil); ecom(n.right.src, tright, right); right = tright; } tuplcom(right, n.left); if(nto != nil) genmove(src, Mas, n.ty, right, nto); tfree(tright); tfree(tto); break; } # # check for left/right aliasing and build right into temporary # if(right.op == Otuple){ if(!tupsaliased(left, right) && (tn := tupblk(right)) != nil){ tn.ty = n.ty; right = tn; } else if(left.op != Oname || tupaliased(left, right)) right = ecom(right.src, tright = talloc(right.ty, nil), right); } # # think carefully about types here # if(left.addable >= Rcant) (left, tleft) = eacom(left, nto); ecom(n.src, left, right); if(nto != nil) genmove(src, Mas, nto.ty, left, nto); tfree(tleft); tfree(tright); tfree(tto); Ochan => if(left != nil && left.addable >= Rcant) (left, tleft) = eacom(left, nto); genchan(src, left, n.ty.tof, nto); tfree(tleft); Oinds => if(right.addable < Ralways){ if(left.addable >= Rcant) (left, tleft) = eacom(left, nil); }else if(left.temps <= right.temps){ right = ecom(right.src, tright = talloc(right.ty, nil), right); if(left.addable >= Rcant) (left, tleft) = eacom(left, nil); }else{ (left, tleft) = eacom(left, nil); right = ecom(right.src, tright = talloc(right.ty, nil), right); } genop(n.src, op, left, right, nto); tfree(tleft); tfree(tright); Osnd => if(right.addable < Rcant){ if(left.addable >= Rcant) (left, tleft) = eacom(left, nto); }else if(left.temps < right.temps){ (right, tright) = eacom(right, nto); if(left.addable >= Rcant) (left, tleft) = eacom(left, nil); }else{ (left, tleft) = eacom(left, nto); (right, tright) = eacom(right, nil); } p = genrawop(n.src, ISEND, right, nil, left); p.m.offset = n.ty.size; # for optimizer if(nto != nil) genmove(src, Mas, right.ty, right, nto); tfree(tleft); tfree(tright); Orcv => if(nto == nil){ ecom(n.src, tto = talloc(n.ty, nil), n); tfree(tto); return nil; } if(left.addable >= Rcant) (left, tleft) = eacom(left, nto); if(left.ty.kind == Tchan){ p = genrawop(src, IRECV, left, nil, nto); p.m.offset = n.ty.size; # for optimizer }else{ recvacom(src, nto, n); } tfree(tleft); Ocons => # # another temp which can go with analysis # if(left.addable >= Rcant) (left, tleft) = eacom(left, nil); if(!sameaddr(right, nto)){ ecom(right.src, tto = talloc(n.ty, nto), right); genmove(src, Mcons, left.ty, left, tto); if(!sameaddr(tto, nto)) genmove(src, Mas, nto.ty, tto, nto); }else genmove(src, Mcons, left.ty, left, nto); tfree(tleft); tfree(tto); Ohd => if(left.addable >= Rcant) (left, tleft) = eacom(left, nto); genmove(src, Mhd, nto.ty, left, nto); tfree(tleft); Otl => if(left.addable >= Rcant) (left, tleft) = eacom(left, nto); genmove(src, Mtl, left.ty, left, nto); tfree(tleft); Otuple => if((tn := tupblk(n)) != nil){ tn.ty = n.ty; genmove(src, Mas, n.ty, tn, nto); break; } tupcom(nto, n); Oadd or Osub or Omul or Odiv or Omod or Oand or Oor or Oxor or Olsh or Orsh or Oexp => # # check for 2 operand forms # if(sameaddr(nto, left)){ if(right.addable >= Rcant) (right, tright) = eacom(right, nto); genop(src, op, right, nil, nto); tfree(tright); break; } if(opcommute[op] && sameaddr(nto, right) && n.ty != tstring){ if(left.addable >= Rcant) (left, tleft) = eacom(left, nto); genop(src, opcommute[op], left, nil, nto); tfree(tleft); break; } if(right.addable < left.addable && opcommute[op] && n.ty != tstring){ op = opcommute[op]; left = right; right = n.left; } if(left.addable < Ralways){ if(right.addable >= Rcant) (right, tright) = eacom(right, nto); }else if(right.temps <= left.temps){ left = ecom(left.src, tleft = talloc(left.ty, nto), left); if(right.addable >= Rcant) (right, tright) = eacom(right, nil); }else{ (right, tright) = eacom(right, nto); left = ecom(left.src, tleft = talloc(left.ty, nil), left); } # # check for 2 operand forms # if(sameaddr(nto, left)) genop(src, op, right, nil, nto); else if(opcommute[op] && sameaddr(nto, right) && n.ty != tstring) genop(src, opcommute[op], left, nil, nto); else genop(src, op, right, left, nto); tfree(tleft); tfree(tright); Oaddas or Osubas or Omulas or Odivas or Omodas or Oexpas or Oandas or Ooras or Oxoras or Olshas or Orshas => if(left.op == Oinds){ indsascom(src, nto, n); break; } if(right.addable < Rcant){ if(left.addable >= Rcant) (left, tleft) = eacom(left, nto); }else if(left.temps < right.temps){ (right, tright) = eacom(right, nto); if(left.addable >= Rcant) (left, tleft) = eacom(left, nil); }else{ (left, tleft) = eacom(left, nto); (right, tright) = eacom(right, nil); } genop(n.src, op, right, nil, left); if(nto != nil) genmove(src, Mas, left.ty, left, nto); tfree(tleft); tfree(tright); Olen => if(left.addable >= Rcant) (left, tleft) = eacom(left, nto); op = -1; t = left.ty; if(t == tstring) op = ILENC; else if(t.kind == Tarray) op = ILENA; else if(t.kind == Tlist) op = ILENL; else fatal("can't len "+nodeconv(n)); genrawop(src, op, left, nil, nto); tfree(tleft); Oneg => if(left.addable >= Rcant) (left, tleft) = eacom(left, nto); genop(n.src, op, left, nil, nto); tfree(tleft); Oinc or Odec => if(left.op == Oinds){ indsascom(src, nto, n); break; } if(left.addable >= Rcant) (left, tleft) = eacom(left, nil); if(nto != nil) genmove(src, Mas, left.ty, left, nto); if(right.addable >= Rcant) fatal("inc/dec amount not addressable: "+nodeconv(n)); genop(n.src, op, right, nil, left); tfree(tleft); Ospawn => if(left.left.op == Oind) fpcall(n.src, op, left, nto); else callcom(n.src, op, left, nto); Oraise => if(left.addable >= Rcant) (left, tleft) = eacom(left, nil); genrawop(n.src, IRAISE, left, nil, nil); tfree(tleft); Ocall => if(left.op == Oind) fpcall(esrc(src, n.src, nto), op, n, nto); else callcom(esrc(src, n.src, nto), op, n, nto); Oref => t = left.ty; if(left.op == Oname && left.decl.store == Dfn || left.op == Omdot && left.right.op == Oname && left.right.decl.store == Dfn){ # create a function reference mod, ind: ref Node; d := left.decl; if(left.op == Omdot){ d = left.right.decl; mod = left.left; } else if(d.eimport != nil) mod = d.eimport; else{ mod = rewrite(mkn(Oself, nil, nil)); addiface(nil, d); } sumark(mod); tto = talloc(n.ty, nto); genrawop(src, INEW, mktn(usetype(tfnptr)), nil, tto); tright = ref znode; tright.src = src; tright.op = Oind; tright.left = tto; tright.right = nil; tright.ty = tany; sumark(tright); ecom(src, tright, mod); ind = mkunary(Oind, mkbin(Oadd, dupn(0, src, tto), mkconst(src, big IBY2WD))); ind.ty = ind.left.ty = ind.left.right.ty = tint; tright.op = Oas; tright.left = ind; tright.right = mkdeclname(src, d); tright.ty = tright.right.ty = tint; sumark(tright); if(mod.op == Oself && newfnptr) tright.right.addable = Rnoff; else tright.right.addable = Roff; ecom(src, nil, tright); if(!sameaddr(tto, nto)) genmove(src, Mas, n.ty, tto, nto); tfree(tto); break; } if(left.op == Oname && left.decl.store == Dtype){ genrawop(src, INEW, mktn(t), nil, nto); break; } if(t.kind == Tadt && t.tags != nil){ pickdupcom(src, nto, left); break; } tt := t; if(left.op == Oconst && left.decl.store == Dtag) t = left.decl.ty.tof; # # could eliminate temp if nto does not occur # in tuple initializer # tto = talloc(n.ty, nto); genrawop(src, INEW, mktn(t), nil, tto); tright = ref znode; tright.op = Oind; tright.left = tto; tright.right = nil; tright.ty = tt; sumark(tright); ecom(src, tright, left); if(!sameaddr(tto, nto)) genmove(src, Mas, n.ty, tto, nto); tfree(tto); Oload => if(left.addable >= Rcant) (left, tleft) = eacom(left, nto); tright = talloc(tint, nil); if(LDT) genrawop(src, ILOAD, left, right, nto); else{ genrawop(src, ILEA, right, nil, tright); genrawop(src, ILOAD, left, tright, nto); } tfree(tleft); tfree(tright); Ocast => if(left.addable >= Rcant) (left, tleft) = eacom(left, nto); t = left.ty; if(t.kind == Tfix || n.ty.kind == Tfix){ op = casttab[t.kind][n.ty.kind]; if(op == ICVTXX) genfixcastop(src, op, left, nto); else{ ttn = sumark(mkrconst(src, scale2(t, n.ty))); genrawop(src, op, left, ttn, nto); } } else genrawop(src, casttab[t.kind][n.ty.kind], left, nil, nto); tfree(tleft); Oarray => if(left.addable >= Rcant) (left, tleft) = eacom(left, nto); if(arrayz) genrawop(esrc(src, left.src, nto), INEWAZ, left, mktn(n.ty.tof), nto); else genrawop(esrc(src, left.src, nto), INEWA, left, mktn(n.ty.tof), nto); if(right != nil) arraycom(nto, right); tfree(tleft); Oslice => tn := right.right; right = right.left; # # make the left node of the slice directly addressable # therefore, if it's len is taken (via tn), # left's tree won't be rewritten # if(left.addable >= Rcant) (left, tleft) = eacom(left, nil); if(tn.op == Onothing){ tn = mkn(Olen, left, nil); tn.src = src; tn.ty = tint; sumark(tn); } if(tn.addable < Ralways){ if(right.addable >= Rcant) (right, tright) = eacom(right, nil); }else if(right.temps <= tn.temps){ tn = ecom(tn.src, ttn = talloc(tn.ty, nil), tn); if(right.addable >= Rcant) (right, tright) = eacom(right, nil); }else{ (right, tright) = eacom(right, nil); tn = ecom(tn.src, ttn = talloc(tn.ty, nil), tn); } op = ISLICEA; if(nto.ty == tstring) op = ISLICEC; # # overwrite the destination last, # since it might be used in computing the slice bounds # if(!sameaddr(left, nto)) ecom(left.src, nto, left); genrawop(src, op, right, tn, nto); tfree(tleft); tfree(tright); tfree(ttn); Oindx => if(right.addable < Rcant){ if(left.addable >= Rcant) (left, tleft) = eacom(left, nto); }else if(left.temps < right.temps){ (right, tright) = eacom(right, nto); if(left.addable >= Rcant) (left, tleft) = eacom(left, nil); }else{ (left, tleft) = eacom(left, nto); (right, tright) = eacom(right, nil); } if(nto.addable >= Ralways) nto = ecom(src, tto = talloc(nto.ty, nil), nto); op = IINDX; case left.ty.tof.size{ IBY2LG => op = IINDL; if(left.ty.tof == treal) op = IINDF; IBY2WD => op = IINDW; 1 => op = IINDB; } genrawop(src, op, left, nto, right); if(tleft != nil && tleft.decl != nil) tfreelater(tleft); else tfree(tleft); tfree(tright); tfree(tto); Oind => (n, tleft) = eacom(n, nto); genmove(src, Mas, n.ty, n, nto); tfree(tleft); Onot or Oandand or Ooror or Oeq or Oneq or Olt or Oleq or Ogt or Ogeq => p = bcom(n, 1, nil); genmove(src, Mas, tint, sumark(mkconst(src, big 1)), nto); pp := genrawop(src, IJMP, nil, nil, nil); patch(p, nextinst()); genmove(src, Mas, tint, sumark(mkconst(src, big 0)), nto); patch(pp, nextinst()); Oself => if(newfnptr){ if(nto != nil) genrawop(src, ISELF, nil, nil, nto); break; } tn := sumark(mkdeclname(src, selfdecl)); p = genbra(src, Oneq, tn, sumark(mkdeclname(src, nildecl))); n.op = Oload; ecom(src, tn, n); patch(p, nextinst()); genmove(src, Mas, n.ty, tn, nto); } return nto; } # # compile exp n to yield an addressable expression # use reg to build a temporary; if t is a temp, it is usable # # note that 0adr's are strange as they are only used # for calculating the addresses of fields within adt's. # therefore an Oind is the parent or grandparent of the Oadr, # and we pick off all of the cases where Oadr's argument is not # addressable by looking from the Oind. # eacom(n, t: ref Node): (ref Node, ref Node) { reg: ref Node; if(n.op == Ocomma){ tn := n.left.left; ecom(n.left.src, nil, n.left); nn := eacom(n.right, t); tfree(tn); return nn; } if(debug['e'] || debug['E']) print("eacom: %s\n", nodeconv(n)); left := n.left; if(n.op != Oind){ ecom(n.src, reg = talloc(n.ty, t), n); reg.src = n.src; return (reg, reg); } if(left.op == Oadd && left.right.op == Oconst){ if(left.left.op == Oadr){ (left.left.left, reg) = eacom(left.left.left, t); sumark(n); if(n.addable >= Rcant) fatal("eacom can't make node addressable: "+nodeconv(n)); return (n, reg); } reg = talloc(left.left.ty, t); ecom(left.left.src, reg, left.left); left.left.decl = reg.decl; left.left.addable = Rreg; left.left = reg; left.addable = Raadr; n.addable = Radr; }else if(left.op == Oadr){ reg = talloc(left.left.ty, t); ecom(left.left.src, reg, left.left); # # sleaze: treat the temp as the type of the field, not the enclosing structure # reg.ty = n.ty; reg.src = n.src; return (reg, reg); }else{ reg = talloc(left.ty, t); ecom(left.src, reg, left); n.left = reg; n.addable = Radr; } return (n, reg); } # # compile an assignment to an array slice # slicelcom(src: Src, nto, n: ref Node): ref Node { tleft, tright, tv: ref Node; left := n.left.left; right := n.left.right.left; v := n.right; if(right.addable < Ralways){ if(left.addable >= Rcant) (left, tleft) = eacom(left, nto); }else if(left.temps <= right.temps){ right = ecom(right.src, tright = talloc(right.ty, nto), right); if(left.addable >= Rcant) (left, tleft) = eacom(left, nil); }else{ (left, tleft) = eacom(left, nil); # dangle on right and v right = ecom(right.src, tright = talloc(right.ty, nil), right); } case n.op{ Oas => if(v.addable >= Rcant) (v, tv) = eacom(v, nil); } genrawop(n.src, ISLICELA, v, right, left); if(nto != nil) genmove(src, Mas, n.ty, left, nto); tfree(tleft); tfree(tv); tfree(tright); return nto; } # # compile an assignment to a string location # indsascom(src: Src, nto, n: ref Node): ref Node { tleft, tright, tv, tu, u: ref Node; left := n.left.left; right := n.left.right; v := n.right; if(right.addable < Ralways){ if(left.addable >= Rcant) (left, tleft) = eacom(left, nto); }else if(left.temps <= right.temps){ right = ecom(right.src, tright = talloc(right.ty, nto), right); if(left.addable >= Rcant) (left, tleft) = eacom(left, nil); }else{ (left, tleft) = eacom(left, nil); # dangle on right and v right = ecom(right.src, tright = talloc(right.ty, nil), right); } case n.op{ Oas => if(v.addable >= Rcant) (v, tv) = eacom(v, nil); Oinc or Odec => if(v.addable >= Rcant) fatal("inc/dec amount not addable"); u = tu = talloc(tint, nil); genop(n.left.src, Oinds, left, right, u); if(nto != nil) genmove(src, Mas, n.ty, u, nto); nto = nil; genop(n.src, n.op, v, nil, u); v = u; Oaddas or Osubas or Omulas or Odivas or Omodas or Oexpas or Oandas or Ooras or Oxoras or Olshas or Orshas => if(v.addable >= Rcant) (v, tv) = eacom(v, nil); u = tu = talloc(tint, nil); genop(n.left.src, Oinds, left, right, u); genop(n.src, n.op, v, nil, u); v = u; } genrawop(n.src, IINSC, v, right, left); tfree(tleft); tfree(tv); tfree(tright); tfree(tu); if(nto != nil) genmove(src, Mas, n.ty, v, nto); return nto; } callcom(src: Src, op: int, n, ret: ref Node) { tmod, tind: ref Node; callee: ref Decl; args := n.right; nfn := n.left; case(nfn.op){ Odot => callee = nfn.right.decl; nfn.addable = Rpc; Omdot => callee = nfn.right.decl; Oname => callee = nfn.decl; * => callee = nil; fatal("bad call op in callcom"); } if(nfn.addable != Rpc && nfn.addable != Rmpc) fatal("can't gen call addresses"); if(nfn.ty.tof != tnone && ret == nil){ ecom(src, tmod = talloc(nfn.ty.tof, nil), n); tfree(tmod); return; } if(ispoly(callee)) addfnptrs(callee, 0); if(nfn.ty.varargs != byte 0){ d := dupdecl(nfn.right.decl); nfn.decl = d; d.desc = gendesc(d, idoffsets(nfn.ty.ids, MaxTemp, MaxAlign), nfn.ty.ids); } frame := talloc(tint, nil); mod := nfn.left; ind := nfn.right; if(nfn.addable == Rmpc){ if(mod.addable >= Rcant) (mod, tmod) = eacom(mod, nil); # dangle always if(ind.op != Oname && ind.addable >= Ralways){ tind = talloc(ind.ty, nil); ecom(ind.src, tind, ind); ind = tind; } else if(ind.decl != nil && ind.decl.store != Darg) ind.addable = Roff; } # # stop nested uncalled frames # otherwise exception handling very complicated # for(a := args; a != nil; a = a.right){ if(hascall(a.left)){ tn := talloc(a.left.ty, nil); ecom(a.left.src, tn, a.left); a.left = tn; tn.flags |= byte TEMP; } } # # allocate the frame # if(nfn.addable == Rmpc && nfn.ty.varargs == byte 0){ genrawop(src, IMFRAME, mod, ind, frame); }else if(nfn.op == Odot){ genrawop(src, IFRAME, nfn.left, nil, frame); }else{ in := genrawop(src, IFRAME, nil, nil, frame); in.sm = Adesc; in.s.decl = nfn.decl; } # # build a fake node for the argument area # toff := ref znode; tadd := ref znode; pass := ref znode; toff.op = Oconst; toff.c = ref Const(big 0, 0.0); # jrf - added initialization toff.addable = Rconst; toff.ty = tint; tadd.op = Oadd; tadd.addable = Raadr; tadd.left = frame; tadd.right = toff; tadd.ty = tint; pass.op = Oind; pass.addable = Radr; pass.left = tadd; # # compile all the args # d := nfn.ty.ids; off := 0; for(a = args; a != nil; a = a.right){ off = d.offset; toff.c.val = big off; if(d.ty.kind == Tpoly) pass.ty = a.left.ty; else pass.ty = d.ty; ecom(a.left.src, pass, a.left); d = d.next; if(int a.left.flags & TEMP) tfree(a.left); } if(off > maxstack) maxstack = off; # # pass return value # if(ret != nil){ toff.c.val = big(REGRET*IBY2WD); pass.ty = nfn.ty.tof; p := genrawop(src, ILEA, ret, nil, pass); p.m.offset = ret.ty.size; # for optimizer } # # call it # iop: int; if(nfn.addable == Rmpc){ iop = IMCALL; if(op == Ospawn) iop = IMSPAWN; genrawop(src, iop, frame, ind, mod); tfree(tmod); tfree(tind); }else if(nfn.op == Odot){ iop = ICALL; if(op == Ospawn) iop = ISPAWN; genrawop(src, iop, frame, nil, nfn.right); }else{ iop = ICALL; if(op == Ospawn) iop = ISPAWN; in := genrawop(src, iop, frame, nil, nil); in.d.decl = nfn.decl; in.dm = Apc; } tfree(frame); } # # initialization code for arrays # a must be addressable (< Rcant) # arraycom(a, elems: ref Node) { top, out: ref Inst; ri, n, wild: ref Node; if(debug['A']) print("arraycom: %s %s\n", nodeconv(a), nodeconv(elems)); # c := elems.ty.cse; # don't use c.wild in case we've been inlined wild = nil; for(e := elems; e != nil; e = e.right) for(q := e.left.left; q != nil; q = q.right) if(q.left.op == Owild) wild = e.left; if(wild != nil) arraydefault(a, wild.right); tindex := ref znode; fake := ref znode; tmp := talloc(tint, nil); tindex.op = Oindx; tindex.addable = Rcant; tindex.left = a; tindex.right = nil; tindex.ty = tint; fake.op = Oind; fake.addable = Radr; fake.left = tmp; fake.ty = a.ty.tof; for(e = elems; e != nil; e = e.right){ # # just duplicate the initializer for Oor # for(q = e.left.left; q != nil; q = q.right){ if(q.left.op == Owild) continue; body := e.left.right; if(q.right != nil) body = dupn(0, nosrc, body); top = nil; out = nil; ri = nil; if(q.left.op == Orange){ # # for(i := q.left.left; i <= q.left.right; i++) # ri = talloc(tint, nil); ri.src = q.left.src; ecom(q.left.src, ri, q.left.left); # i <= q.left.right; n = mkn(Oleq, ri, q.left.right); n.src = q.left.src; n.ty = tint; top = nextinst(); out = bcom(n, 1, nil); tindex.right = ri; }else{ tindex.right = q.left; } tindex.addable = Rcant; tindex.src = q.left.src; ecom(tindex.src, tmp, tindex); ecom(body.src, fake, body); if(q.left.op == Orange){ # i++ n = mkbin(Oinc, ri, sumark(mkconst(ri.src, big 1))); n.ty = tint; n.addable = Rcant; ecom(n.src, nil, n); # jump to test patch(genrawop(q.left.src, IJMP, nil, nil, nil), top); patch(out, nextinst()); tfree(ri); } } } tfree(tmp); } # # default initialization code for arrays. # compiles to # n = len a; # while(n){ # n--; # a[n] = elem; # } # arraydefault(a, elem: ref Node) { e: ref Node; if(debug['A']) print("arraydefault: %s %s\n", nodeconv(a), nodeconv(elem)); t := mkn(Olen, a, nil); t.src = elem.src; t.ty = tint; t.addable = Rcant; n := talloc(tint, nil); n.src = elem.src; ecom(t.src, n, t); top := nextinst(); out := bcom(n, 1, nil); t = mkbin(Odec, n, sumark(mkconst(elem.src, big 1))); t.ty = tint; t.addable = Rcant; ecom(t.src, nil, t); if(elem.addable >= Rcant) (elem, e) = eacom(elem, nil); t = mkn(Oindx, a, n); t.src = elem.src; t = mkbin(Oas, mkunary(Oind, t), elem); t.ty = elem.ty; t.left.ty = elem.ty; t.left.left.ty = tint; sumark(t); ecom(t.src, nil, t); patch(genrawop(t.src, IJMP, nil, nil, nil), top); tfree(n); tfree(e); patch(out, nextinst()); } tupcom(nto, n: ref Node) { if(debug['Y']) print("tupcom %s\nto %s\n", nodeconv(n), nodeconv(nto)); # # build a fake node for the tuple # toff := ref znode; tadd := ref znode; fake := ref znode; tadr := ref znode; toff.op = Oconst; toff.c = ref Const(big 0, 0.0); # no val => may get fatal error below (jrf) toff.ty = tint; tadr.op = Oadr; tadr.left = nto; tadr.ty = tint; tadd.op = Oadd; tadd.left = tadr; tadd.right = toff; tadd.ty = tint; fake.op = Oind; fake.left = tadd; sumark(fake); if(fake.addable >= Rcant) fatal("tupcom: bad value exp "+nodeconv(fake)); # # compile all the exps # d := n.ty.ids; for(e := n.left; e != nil; e = e.right){ toff.c.val = big d.offset; fake.ty = d.ty; ecom(e.left.src, fake, e.left); d = d.next; } } tuplcom(n, nto: ref Node) { if(debug['Y']) print("tuplcom %s\nto %s\n", nodeconv(n), nodeconv(nto)); # # build a fake node for the tuple # toff := ref znode; tadd := ref znode; fake := ref znode; tadr := ref znode; toff.op = Oconst; toff.c = ref Const(big 0, 0.0); # no val => may get fatal error below (jrf) toff.ty = tint; tadr.op = Oadr; tadr.left = n; tadr.ty = tint; tadd.op = Oadd; tadd.left = tadr; tadd.right = toff; tadd.ty = tint; fake.op = Oind; fake.left = tadd; sumark(fake); if(fake.addable >= Rcant) fatal("tuplcom: bad value exp for "+nodeconv(fake)); # # compile all the exps # tas := ref znode; d := nto.ty.ids; if(nto.ty.kind == Tadtpick) d = nto.ty.tof.ids.next; for(e := nto.left; e != nil; e = e.right){ as := e.left; if(as.op != Oname || as.decl != nildecl){ toff.c.val = big d.offset; fake.ty = d.ty; fake.src = as.src; if(as.addable < Rcant) genmove(as.src, Mas, d.ty, fake, as); else{ tas.op = Oas; tas.ty = d.ty; tas.src = as.src; tas.left = as; tas.right = fake; tas.addable = Rcant; ecom(as.src, nil, tas); } } d = d.next; } } tuplrcom(n: ref Node, nto: ref Node) { s, d, tas: ref Node; de: ref Decl; tas = ref znode; de = nto.ty.ids; for((s, d) = (n.left, nto.left); s != nil && d != nil; (s, d) = (s.right, d.right)){ if(d.left.op != Oname || d.left.decl != nildecl){ tas.op = Oas; tas.ty = de.ty; tas.src = s.left.src; tas.left = d.left; tas.right = s.left; sumark(tas); ecom(tas.src, nil, tas); } de = de.next; } if(s != nil || d != nil) fatal("tuplrcom"); } # # boolean compiler # fall through when condition == true # bcom(n: ref Node, iftrue: int, b: ref Inst): ref Inst { tleft, tright: ref Node; if(n.op == Ocomma){ tn := n.left.left; ecom(n.left.src, nil, n.left); b = bcom(n.right, iftrue, b); tfree(tn); return b; } if(debug['b']) print("bcom %s %d\n", nodeconv(n), iftrue); left := n.left; right := n.right; op := n.op; case op{ Onothing => return b; Onot => return bcom(n.left, !iftrue, b); Oandand => if(!iftrue) return oror(n, iftrue, b); return andand(n, iftrue, b); Ooror => if(!iftrue) return andand(n, iftrue, b); return oror(n, iftrue, b); Ogt or Ogeq or Oneq or Oeq or Olt or Oleq => break; * => if(n.ty.kind == Tint){ right = mkconst(n.src, big 0); right.addable = Rconst; left = n; op = Oneq; break; } fatal("can't bcom "+nodeconv(n)); return b; } if(iftrue) op = oprelinvert[op]; if(left.addable < right.addable){ t := left; left = right; right = t; op = opcommute[op]; } if(right.addable < Ralways){ if(left.addable >= Rcant) (left, tleft) = eacom(left, nil); }else if(left.temps <= right.temps){ right = ecom(right.src, tright = talloc(right.ty, nil), right); if(left.addable >= Rcant) (left, tleft) = eacom(left, nil); }else{ (left, tleft) = eacom(left, nil); right = ecom(right.src, tright = talloc(right.ty, nil), right); } bb := genbra(n.src, op, left, right); bb.branch = b; tfree(tleft); tfree(tright); return bb; } andand(n: ref Node, iftrue: int, b: ref Inst): ref Inst { if(debug['b']) print("andand %s\n", nodeconv(n)); b = bcom(n.left, iftrue, b); b = bcom(n.right, iftrue, b); return b; } oror(n: ref Node, iftrue: int, b: ref Inst): ref Inst { if(debug['b']) print("oror %s\n", nodeconv(n)); bb := bcom(n.left, !iftrue, nil); b = bcom(n.right, iftrue, b); patch(bb, nextinst()); return b; } # # generate code for a recva expression # this is just a hacked up small alt # recvacom(src: Src, nto, n: ref Node) { p: ref Inst; left := n.left; labs := array[1] of Label; labs[0].isptr = left.addable >= Rcant; c := ref Case; c.nlab = 1; c.nsnd = 0; c.offset = 0; c.labs = labs; talt := mktalt(c); which := talloc(tint, nil); tab := talloc(talt, nil); # # build the node for the address of each channel, # the values to send, and the storage for values received # off := ref znode; adr := ref znode; add := ref znode; slot := ref znode; off.op = Oconst; off.c = ref Const(big 0, 0.0); # jrf - added initialization off.ty = tint; off.addable = Rconst; adr.op = Oadr; adr.left = tab; adr.ty = tint; add.op = Oadd; add.left = adr; add.right = off; add.ty = tint; slot.op = Oind; slot.left = add; sumark(slot); # # gen the channel # this sleaze is lying to the garbage collector # off.c.val = big(2*IBY2WD); if(left.addable < Rcant) genmove(src, Mas, tint, left, slot); else{ slot.ty = left.ty; ecom(src, slot, left); slot.ty = nil; } # # gen the value # off.c.val += big IBY2WD; p = genrawop(left.src, ILEA, nto, nil, slot); p.m.offset = nto.ty.size; # for optimizer # # number of senders and receivers # off.c.val = big 0; genmove(src, Mas, tint, sumark(mkconst(src, big 0)), slot); off.c.val += big IBY2WD; genmove(src, Mas, tint, sumark(mkconst(src, big 1)), slot); off.c.val += big IBY2WD; p = genrawop(src, IALT, tab, nil, which); p.m.offset = talt.size; # for optimizer tfree(which); tfree(tab); } # # generate code to duplicate an adt with pick fields # this is just a hacked up small pick # n is Oind(exp) # pickdupcom(src: Src, nto, n: ref Node) { jmps: ref Inst; if(n.op != Oind) fatal("pickdupcom not Oind: " + nodeconv(n)); t := n.ty; nlab := t.decl.tag; # # generate global which has case labels # d := mkids(src, enter(".c"+string nlabel++, 0), mktype(src.start, src.stop, Tcase, nil, nil), nil); d.init = mkdeclname(src, d); clab := ref znode; clab.addable = Rmreg; clab.left = nil; clab.right = nil; clab.op = Oname; clab.ty = d.ty; clab.decl = d; # # generate a temp to hold the real value # then generate a case on the tag # orig := n.left; tmp := talloc(orig.ty, nil); ecom(src, tmp, orig); orig = mkunary(Oind, tmp); orig.ty = tint; sumark(orig); dest := mkunary(Oind, nto); dest.ty = nto.ty.tof; sumark(dest); genrawop(src, ICASE, orig, nil, clab); labs := array[nlab] of Label; i := 0; jmps = nil; for(tg := t.tags; tg != nil; tg = tg.next){ stg := tg; for(; tg.next != nil; tg = tg.next) if(stg.ty != tg.next.ty) break; start := sumark(simplify(mkdeclname(src, stg))); stop := start; node := start; if(stg != tg){ stop = sumark(simplify(mkdeclname(src, tg))); node = mkbin(Orange, start, stop); } labs[i].start = start; labs[i].stop = stop; labs[i].node = node; labs[i++].inst = nextinst(); genrawop(src, INEW, mktn(tg.ty.tof), nil, nto); genmove(src, Mas, tg.ty.tof, orig, dest); j := genrawop(src, IJMP, nil, nil, nil); j.branch = jmps; jmps = j; } # # this should really be a runtime error # wild := genrawop(src, IJMP, nil, nil, nil); patch(wild, wild); patch(jmps, nextinst()); tfree(tmp); if(i > nlab) fatal("overflowed label tab for pickdupcom"); c := ref Case; c.nlab = i; c.nsnd = 0; c.labs = labs; c.iwild = wild; d.ty.cse = c; usetype(d.ty); installids(Dglobal, d); } # # see if name n occurs anywhere in e # tupaliased(n, e: ref Node): int { for(;;){ if(e == nil) return 0; if(e.op == Oname && e.decl == n.decl) return 1; if(tupaliased(n, e.left)) return 1; e = e.right; } return 0; } # # see if any name in n occurs anywere in e # tupsaliased(n, e: ref Node): int { for(;;){ if(n == nil) return 0; if(n.op == Oname && tupaliased(n, e)) return 1; if(tupsaliased(n.left, e)) return 1; n = n.right; } return 0; } # # put unaddressable constants in the global data area # globalconst(n: ref Node): ref Decl { s := enter(".i." + hex(int n.c.val, 8), 0); d := s.decl; if(d == nil){ d = mkids(n.src, s, tint, nil); installids(Dglobal, d); d.init = n; d.refs++; } return d; } globalBconst(n: ref Node): ref Decl { s := enter(".B." + bhex(n.c.val, 16), 0); d := s.decl; if(d == nil){ d = mkids(n.src, s, tbig, nil); installids(Dglobal, d); d.init = n; d.refs++; } return d; } globalbconst(n: ref Node): ref Decl { s := enter(".b." + hex(int n.c.val & 16rff, 2), 0); d := s.decl; if(d == nil){ d = mkids(n.src, s, tbyte, nil); installids(Dglobal, d); d.init = n; d.refs++; } return d; } globalfconst(n: ref Node): ref Decl { ba := array[8] of byte; export_real(ba, array[] of {n.c.rval}); fs := ".f."; for(i := 0; i < 8; i++) fs += hex(int ba[i], 2); if(fs != ".f." + bhex(math->realbits64(n.c.rval), 16)) fatal("bad globalfconst number"); s := enter(fs, 0); d := s.decl; if(d == nil){ d = mkids(n.src, s, treal, nil); installids(Dglobal, d); d.init = n; d.refs++; } return d; } globalsconst(n: ref Node): ref Decl { s := n.decl.sym; n.decl = nil; d := s.decl; if(d == nil){ d = mkids(n.src, s, tstring, nil); installids(Dglobal, d); d.init = n; } d.refs++; n.decl = d; return d; } # # make a global of type t # used to make initialized data # globalztup(t: ref Type): ref Decl { z := ".z." + string t.size + "."; desc := t.decl.desc; for(i := 0; i < desc.nmap; i++) z += hex(int desc.map[i], 2); s := enter(z, 0); d := s.decl; if(d == nil){ d = mkids(t.src, s, t, nil); installids(Dglobal, d); d.init = nil; } d.refs++; return d; } subst(d: ref Decl, e: ref Node, n: ref Node): ref Node { if(n == nil) return nil; if(n.op == Oname){ if(d == n.decl){ n = dupn(0, nosrc, e); n.ty = d.ty; } return n; } n.left = subst(d, e, n.left); n.right = subst(d, e, n.right); return n; } inline(n: ref Node): ref Node { e, tn: ref Node; t: ref Type; d: ref Decl; if(debug['z']) sys->print("inline1: %s\n", nodeconv(n)); if(n.left.op == Oname) d = n.left.decl; else d = n.left.right.decl; e = d.init; t = e.ty; e = dupn(1, n.src, e.right.left.left); n = n.right; for(d = t.ids; d != nil && n != nil; d = d.next){ if(hasside(n.left, 0) && occurs(d, e) != 1){ tn = talloc(d.ty, nil); e = mkbin(Ocomma, mkbin(Oas, tn, n.left), subst(d, tn, e)); e.ty = e.right.ty; e.left.ty = d.ty; } else e = subst(d, n.left, e); n = n.right; } if(d != nil || n != nil) fatal("bad arg match in inline()"); if(debug['z']) sys->print("inline2: %s\n", nodeconv(e)); return e; } fpcall(src: Src, op: int, n: ref Node, ret: ref Node) { tp, e, mod, ind: ref Node; e = n.left.left; if(e.addable >= Rcant) (e, tp) = eacom(e, nil); mod = mkunary(Oind, e); ind = mkunary(Oind, mkbin(Oadd, dupn(0, src, e), mkconst(src, big IBY2WD))); n.left = mkbin(Omdot, mod, ind); n.left.ty = e.ty.tof; mod.ty = ind.ty = ind.left.ty = ind.left.right.ty = tint; sumark(n); callcom(src, op, n, ret); tfree(tp); }