diff options
Diffstat (limited to 'src/cmd/gc/walk.c')
-rw-r--r-- | src/cmd/gc/walk.c | 185 |
1 files changed, 125 insertions, 60 deletions
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index de2105ed3..d9c6341b4 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -29,40 +29,6 @@ static void walkdiv(Node**, NodeList**); static int bounded(Node*, int64); static Mpint mpzero; -// can this code branch reach the end -// without an unconditional RETURN -// this is hard, so it is conservative -static int -walkret(NodeList *l) -{ - Node *n; - -loop: - while(l && l->next) - l = l->next; - if(l == nil) - return 1; - - // at this point, we have the last - // statement of the function - n = l->n; - switch(n->op) { - case OBLOCK: - l = n->list; - goto loop; - - case OGOTO: - case ORETURN: - case OPANIC: - return 0; - break; - } - - // all other statements - // will flow to the end - return 1; -} - void walk(Node *fn) { @@ -76,9 +42,6 @@ walk(Node *fn) snprint(s, sizeof(s), "\nbefore %S", curfn->nname->sym); dumplist(s, curfn->nbody); } - if(curfn->type->outtuple) - if(walkret(curfn->nbody)) - yyerror("function ends without a return statement"); lno = lineno; @@ -221,6 +184,7 @@ walkstmt(Node **np) case OLABEL: case ODCLCONST: case ODCLTYPE: + case OCHECKNOTNIL: break; case OBLOCK: @@ -433,13 +397,28 @@ walkexpr(Node **np, NodeList **init) case OIMAG: case ODOTMETH: case ODOTINTER: + walkexpr(&n->left, init); + goto ret; + case OIND: + if(n->left->type->type->width == 0) { + n->left = cheapexpr(n->left, init); + checknotnil(n->left, init); + } walkexpr(&n->left, init); goto ret; case ODOT: + usefield(n); + walkexpr(&n->left, init); + goto ret; + case ODOTPTR: usefield(n); + if(n->op == ODOTPTR && n->left->type->type->width == 0) { + n->left = cheapexpr(n->left, init); + checknotnil(n->left, init); + } walkexpr(&n->left, init); goto ret; @@ -561,13 +540,6 @@ walkexpr(Node **np, NodeList **init) if(n->list && n->list->n->op == OAS) goto ret; - /* - if(n->left->op == OCLOSURE) { - walkcallclosure(n, init); - t = n->left->type; - } - */ - walkexpr(&n->left, init); walkexprlist(n->list, init); @@ -673,8 +645,48 @@ walkexpr(Node **np, NodeList **init) r = n->rlist->n; walkexprlistsafe(n->list, init); walkexpr(&r->left, init); - fn = mapfn("mapaccess2", r->left->type); - r = mkcall1(fn, getoutargx(fn->type), init, typename(r->left->type), r->left, r->right); + t = r->left->type; + p = nil; + if(t->type->width <= 128) { // Check ../../pkg/runtime/hashmap.c:MAXVALUESIZE before changing. + switch(simsimtype(t->down)) { + case TINT32: + case TUINT32: + p = "mapaccess2_fast32"; + break; + case TINT64: + case TUINT64: + p = "mapaccess2_fast64"; + break; + case TSTRING: + p = "mapaccess2_faststr"; + break; + } + } + if(p != nil) { + // from: + // a,b = m[i] + // to: + // var,b = mapaccess2_fast*(t, m, i) + // a = *var + a = n->list->n; + var = temp(ptrto(t->type)); + var->typecheck = 1; + + fn = mapfn(p, t); + r = mkcall1(fn, getoutargx(fn->type), init, typename(t), r->left, r->right); + n->rlist = list1(r); + n->op = OAS2FUNC; + n->list->n = var; + walkexpr(&n, init); + *init = list(*init, n); + + n = nod(OAS, a, nod(OIND, var, N)); + typecheck(&n, Etop); + walkexpr(&n, init); + goto ret; + } + fn = mapfn("mapaccess2", t); + r = mkcall1(fn, getoutargx(fn->type), init, typename(t), r->left, r->right); n->rlist = list1(r); n->op = OAS2FUNC; goto as2func; @@ -1041,7 +1053,33 @@ walkexpr(Node **np, NodeList **init) goto ret; t = n->left->type; - n = mkcall1(mapfn("mapaccess1", t), t->type, init, typename(t), n->left, n->right); + p = nil; + if(t->type->width <= 128) { // Check ../../pkg/runtime/hashmap.c:MAXVALUESIZE before changing. + switch(simsimtype(t->down)) { + case TINT32: + case TUINT32: + p = "mapaccess1_fast32"; + break; + case TINT64: + case TUINT64: + p = "mapaccess1_fast64"; + break; + case TSTRING: + p = "mapaccess1_faststr"; + break; + } + } + if(p != nil) { + // use fast version. The fast versions return a pointer to the value - we need + // to dereference it to get the result. + n = mkcall1(mapfn(p, t), ptrto(t->type), init, typename(t), n->left, n->right); + n = nod(OIND, n, N); + n->type = t->type; + n->typecheck = 1; + } else { + // no fast version for this key + n = mkcall1(mapfn("mapaccess1", t), t->type, init, typename(t), n->left, n->right); + } goto ret; case ORECV: @@ -1292,6 +1330,10 @@ walkexpr(Node **np, NodeList **init) case OCLOSURE: n = walkclosure(n, init); goto ret; + + case OCALLPART: + n = walkpartialcall(n, init); + goto ret; } fatal("missing switch %O", n->op); @@ -2814,11 +2856,19 @@ walkcompare(Node **np, NodeList **init) typecheck(&call, Etop); walkstmt(&call); *init = list(*init, call); - - if(n->op == OEQ) - r = tempbool; - else - r = nod(ONOT, tempbool, N); + + // tempbool cannot be used directly as multiple comparison + // expressions may exist in the same statement. Create another + // temporary to hold the value (its address is not taken so it can + // be optimized away). + r = temp(types[TBOOL]); + a = nod(OAS, r, tempbool); + typecheck(&a, Etop); + walkstmt(&a); + *init = list(*init, a); + + if(n->op != OEQ) + r = nod(ONOT, r, N); typecheck(&r, Erv); walkexpr(&r, init); *np = r; @@ -2847,14 +2897,29 @@ hard: static int samecheap(Node *a, Node *b) { - if(a == N || b == N || a->op != b->op) - return 0; - - switch(a->op) { - case ONAME: - return a == b; - // TODO: Could do more here, but maybe this is enough. - // It's all cheapexpr does. + Node *ar, *br; + while(a != N && b != N && a->op == b->op) { + switch(a->op) { + default: + return 0; + case ONAME: + return a == b; + case ODOT: + case ODOTPTR: + ar = a->right; + br = b->right; + if(ar->op != ONAME || br->op != ONAME || ar->sym != br->sym) + return 0; + break; + case OINDEX: + ar = a->right; + br = b->right; + if(!isconst(ar, CTINT) || !isconst(br, CTINT) || mpcmpfixfix(ar->val.u.xval, br->val.u.xval) != 0) + return 0; + break; + } + a = a->left; + b = b->left; } return 0; } |