From: Russ Cox Date: Thu, 14 Feb 2013 19:54:00 +0000 (-0500) Subject: cmd/gc: replace x*8 by x<<3 etc X-Git-Tag: go1.1rc2~1027 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=31072e41f4e2ed0a135c46816cb2a65daba12540;p=gostls13.git cmd/gc: replace x*8 by x<<3 etc Fixes #4199. R=ken2 CC=golang-dev https://golang.org/cl/7322081 --- diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index a781ed20c4..4e751cbce7 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -24,6 +24,7 @@ static Node* append(Node*, NodeList**); static Node* sliceany(Node*, NodeList**); static void walkcompare(Node**, NodeList**); static void walkrotate(Node**); +static void walkmul(Node**, NodeList**); static void walkdiv(Node**, NodeList**); static int bounded(Node*, int64); static Mpint mpzero; @@ -481,7 +482,6 @@ walkexpr(Node **np, NodeList **init) case OAND: case OSUB: - case OMUL: case OHMUL: case OLT: case OLE: @@ -932,6 +932,12 @@ walkexpr(Node **np, NodeList **init) walkexpr(&n->right, init); goto ret; + case OMUL: + walkexpr(&n->left, init); + walkexpr(&n->right, init); + walkmul(&n, init); + goto ret; + case ODIV: case OMOD: walkexpr(&n->left, init); @@ -2897,6 +2903,70 @@ yes: return; } +/* + * walkmul rewrites integer multiplication by powers of two as shifts. + */ +static void +walkmul(Node **np, NodeList **init) +{ + Node *n, *nl, *nr; + int pow, neg, w; + + n = *np; + if(!isint[n->type->etype]) + return; + + if(n->right->op == OLITERAL) { + nl = n->left; + nr = n->right; + } else if(n->left->op == OLITERAL) { + nl = n->right; + nr = n->left; + } else + return; + + neg = 0; + + // x*0 is 0 (and side effects of x). + if(mpgetfix(nr->val.u.xval) == 0) { + cheapexpr(nl, init); + nodconst(n, n->type, 0); + goto ret; + } + + // nr is a constant. + pow = powtwo(nr); + if(pow < 0) + return; + if(pow >= 1000) { + // negative power of 2, like -16 + neg = 1; + pow -= 1000; + } + + w = nl->type->width*8; + if(pow+1 >= w)// too big, shouldn't happen + return; + + nl = cheapexpr(nl, init); + + if(pow == 0) { + // x*1 is x + n = nl; + goto ret; + } + + n = nod(OLSH, nl, nodintconst(pow)); + +ret: + if(neg) + n = nod(OMINUS, n, N); + + typecheck(&n, Erv); + walkexpr(&n, init); + *np = n; +} + /* * walkdiv rewrites division by a constant as less expensive * operations.