diff options
Diffstat (limited to 'appl/cmd/limbo/ecom.b')
| -rw-r--r-- | appl/cmd/limbo/ecom.b | 2345 |
1 files changed, 2345 insertions, 0 deletions
diff --git a/appl/cmd/limbo/ecom.b b/appl/cmd/limbo/ecom.b new file mode 100644 index 00000000..978882ab --- /dev/null +++ b/appl/cmd/limbo/ecom.b @@ -0,0 +1,2345 @@ +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, true: 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, true, b); + tfree(tn); + return b; + } + + if(debug['b']) + print("bcom %s %d\n", nodeconv(n), true); + + left := n.left; + right := n.right; + op := n.op; + case op{ + Onothing => + return b; + Onot => + return bcom(n.left, !true, b); + Oandand => + if(!true) + return oror(n, true, b); + return andand(n, true, b); + Ooror => + if(!true) + return andand(n, true, b); + return oror(n, true, 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(true) + 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, true: int, b: ref Inst): ref Inst +{ + if(debug['b']) + print("andand %s\n", nodeconv(n)); + b = bcom(n.left, true, b); + b = bcom(n.right, true, b); + return b; +} + +oror(n: ref Node, true: int, b: ref Inst): ref Inst +{ + if(debug['b']) + print("oror %s\n", nodeconv(n)); + bb := bcom(n.left, !true, nil); + b = bcom(n.right, true, 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); +} |
