diff options
Diffstat (limited to 'src/cmd/gc/gen.c')
-rw-r--r-- | src/cmd/gc/gen.c | 228 |
1 files changed, 159 insertions, 69 deletions
diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c index 96e7b526c..5f03d9476 100644 --- a/src/cmd/gc/gen.c +++ b/src/cmd/gc/gen.c @@ -266,6 +266,8 @@ gen(Node *n) Label *lab; int32 wasregalloc; +//dump("gen", n); + lno = setlineno(n); wasregalloc = anyregalloc(); @@ -279,7 +281,7 @@ gen(Node *n) switch(n->op) { default: - fatal("gen: unknown op %N", n); + fatal("gen: unknown op %+hN", n); break; case OCASE: @@ -394,7 +396,7 @@ gen(Node *n) } gen(n->nincr); // contin: incr patch(p1, pc); // test: - bgen(n->ntest, 0, breakpc); // if(!test) goto break + bgen(n->ntest, 0, -1, breakpc); // if(!test) goto break genlist(n->nbody); // body gjmp(continpc); patch(breakpc, pc); // done: @@ -410,7 +412,7 @@ gen(Node *n) p1 = gjmp(P); // goto test p2 = gjmp(P); // p2: goto else patch(p1, pc); // test: - bgen(n->ntest, 0, p2); // if(!test) goto p2 + bgen(n->ntest, 0, -n->likely, p2); // if(!test) goto p2 genlist(n->nbody); // then p3 = gjmp(P); // goto done patch(p2, pc); // else: @@ -509,22 +511,24 @@ ret: void cgen_callmeth(Node *n, int proc) { + Node n2; Node *l; - // generate a rewrite for method call + // generate a rewrite in n2 for the method call // (p.f)(...) goes to (f)(p,...) l = n->left; if(l->op != ODOTMETH) fatal("cgen_callmeth: not dotmethod: %N"); - n->op = OCALLFUNC; - n->left = n->left->right; - n->left->type = l->type; + n2 = *n; + n2.op = OCALLFUNC; + n2.left = l->right; + n2.left->type = l->type; - if(n->left->op == ONAME) - n->left->class = PFUNC; - cgen_call(n, proc); + if(n2.left->op == ONAME) + n2.left->class = PFUNC; + cgen_call(&n2, proc); } /* @@ -631,6 +635,67 @@ cgen_discard(Node *nr) } /* + * clearslim generates code to zero a slim node. + */ +void +clearslim(Node *n) +{ + Node z; + Mpflt zero; + + memset(&z, 0, sizeof(z)); + z.op = OLITERAL; + z.type = n->type; + z.addable = 1; + + switch(simtype[n->type->etype]) { + case TCOMPLEX64: + case TCOMPLEX128: + z.val.u.cval = mal(sizeof(*z.val.u.cval)); + mpmovecflt(&z.val.u.cval->real, 0.0); + mpmovecflt(&z.val.u.cval->imag, 0.0); + break; + + case TFLOAT32: + case TFLOAT64: + mpmovecflt(&zero, 0.0); + z.val.ctype = CTFLT; + z.val.u.fval = &zero; + break; + + case TPTR32: + case TPTR64: + case TCHAN: + case TMAP: + z.val.ctype = CTNIL; + break; + + case TBOOL: + z.val.ctype = CTBOOL; + break; + + case TINT8: + case TINT16: + case TINT32: + case TINT64: + case TUINT8: + case TUINT16: + case TUINT32: + case TUINT64: + z.val.ctype = CTINT; + z.val.u.xval = mal(sizeof(*z.val.u.xval)); + mpmovecfix(z.val.u.xval, 0); + break; + + default: + fatal("clearslim called on type %T", n->type); + } + + ullmancalc(&z); + cgen(&z, n); +} + +/* * generate assignment: * nl = nr * nr == N means zero nl. @@ -638,9 +703,7 @@ cgen_discard(Node *nr) void cgen_as(Node *nl, Node *nr) { - Node nc; Type *tl; - int iszer; if(debug['g']) { dump("cgen_as", nl); @@ -655,7 +718,6 @@ cgen_as(Node *nl, Node *nr) return; } - iszer = 0; if(nr == N || isnil(nr)) { // externals and heaps should already be clear if(nr == N) { @@ -670,59 +732,10 @@ cgen_as(Node *nl, Node *nr) return; if(isfat(tl)) { clearfat(nl); - goto ret; - } - - /* invent a "zero" for the rhs */ - iszer = 1; - nr = &nc; - memset(nr, 0, sizeof(*nr)); - switch(simtype[tl->etype]) { - default: - fatal("cgen_as: tl %T", tl); - break; - - case TINT8: - case TUINT8: - case TINT16: - case TUINT16: - case TINT32: - case TUINT32: - case TINT64: - case TUINT64: - nr->val.u.xval = mal(sizeof(*nr->val.u.xval)); - mpmovecfix(nr->val.u.xval, 0); - nr->val.ctype = CTINT; - break; - - case TFLOAT32: - case TFLOAT64: - nr->val.u.fval = mal(sizeof(*nr->val.u.fval)); - mpmovecflt(nr->val.u.fval, 0.0); - nr->val.ctype = CTFLT; - break; - - case TBOOL: - nr->val.u.bval = 0; - nr->val.ctype = CTBOOL; - break; - - case TPTR32: - case TPTR64: - nr->val.ctype = CTNIL; - break; - - case TCOMPLEX64: - case TCOMPLEX128: - nr->val.u.cval = mal(sizeof(*nr->val.u.cval)); - mpmovecflt(&nr->val.u.cval->real, 0.0); - mpmovecflt(&nr->val.u.cval->imag, 0.0); - break; + return; } - nr->op = OLITERAL; - nr->type = tl; - nr->addable = 1; - ullmancalc(nr); + clearslim(nl); + return; } tl = nl->type; @@ -730,11 +743,88 @@ cgen_as(Node *nl, Node *nr) return; cgen(nr, nl); - if(iszer && nl->addable) - gused(nl); +} -ret: - ; +/* + * generate: + * res = iface{typ, data} + * n->left is typ + * n->right is data + */ +void +cgen_eface(Node *n, Node *res) +{ + /* + * the right node of an eface may contain function calls that uses res as an argument, + * so it's important that it is done first + */ + Node dst; + dst = *res; + dst.type = types[tptr]; + dst.xoffset += widthptr; + cgen(n->right, &dst); + dst.xoffset -= widthptr; + cgen(n->left, &dst); +} + +/* + * generate: + * res = s[lo, hi]; + * n->left is s + * n->list is (cap(s)-lo(TUINT), hi-lo(TUINT)[, lo*width(TUINTPTR)]) + * caller (cgen) guarantees res is an addable ONAME. + */ +void +cgen_slice(Node *n, Node *res) +{ + Node src, dst, *cap, *len, *offs, *add; + + cap = n->list->n; + len = n->list->next->n; + offs = N; + if(n->list->next->next) + offs = n->list->next->next->n; + + // dst.len = hi [ - lo ] + dst = *res; + dst.xoffset += Array_nel; + dst.type = types[simtype[TUINT]]; + cgen(len, &dst); + + if(n->op != OSLICESTR) { + // dst.cap = cap [ - lo ] + dst = *res; + dst.xoffset += Array_cap; + dst.type = types[simtype[TUINT]]; + cgen(cap, &dst); + } + + // dst.array = src.array [ + lo *width ] + dst = *res; + dst.xoffset += Array_array; + dst.type = types[TUINTPTR]; + + if(n->op == OSLICEARR) { + if(!isptr[n->left->type->etype]) + fatal("slicearr is supposed to work on pointer: %+N\n", n); + checkref(n->left); + } + + if(isnil(n->left)) { + tempname(&src, n->left->type); + cgen(n->left, &src); + } else + src = *n->left; + src.xoffset += Array_array; + src.type = types[TUINTPTR]; + + if(offs == N) { + cgen(&src, &dst); + } else { + add = nod(OADD, &src, offs); + typecheck(&add, Erv); + cgen(add, &dst); + } } /* |