]> Cypherpunks repositories - gostls13.git/commitdiff
divide by a constant power of 2
authorKen Thompson <ken@golang.org>
Fri, 7 Aug 2009 05:33:12 +0000 (22:33 -0700)
committerKen Thompson <ken@golang.org>
Fri, 7 Aug 2009 05:33:12 +0000 (22:33 -0700)
R=rsc
OCL=32858
CL=32858

src/cmd/6g/gg.h
src/cmd/6g/ggen.c
src/cmd/6g/gsubr.c
test/ken/divconst.go [new file with mode: 0644]

index ce5f6c86cd7fce3f3563ffcdfc10cf9300e29889..f9f50cc9d421899389ac04bd89e191854099b8a1 100644 (file)
@@ -125,6 +125,8 @@ void        sudoclean(void);
 int    sudoaddable(int, Node*, Addr*);
 void   afunclit(Addr*);
 void   datagostring(Strlit*, Addr*);
+int    powtwo(Node*);
+Type*  tounsigned(Type*);
 
 /*
  * obj.c
index 64220bc841e1f78b27904153ee03ce6c9730a10f..4e71f75e5cbd7c8787e97d1ba56ad92018d2fd17 100644 (file)
@@ -533,8 +533,8 @@ dodiv(int op, Node *nl, Node *nr, Node *res, Node *ax, Node *dx)
 void
 cgen_div(int op, Node *nl, Node *nr, Node *res)
 {
-       Node ax, dx, oldax, olddx, n1, n2;
-       int rax, rdx;
+       Node ax, dx, oldax, olddx, n1, n2, n3;
+       int rax, rdx, n, w;
 
        if(nl->ullman >= UINF) {
                tempname(&n1, nl->type);
@@ -547,6 +547,86 @@ cgen_div(int op, Node *nl, Node *nr, Node *res)
                nr = &n2;
        }
 
+       if(nr->op != OLITERAL)
+               goto longdiv;
+
+       // special cases of mod/div
+       // by a constant
+       n = powtwo(nr);
+       w = nl->type->width*8;
+
+       if(n+1 >= w) {
+               // just sign bit
+               goto longdiv;
+       }
+
+       if(n < 0)
+               goto divbymul;
+
+       if(op == OMOD) {
+               // todo
+               goto longdiv;
+       }
+
+       switch(n) {
+       case 0:
+               // divide by 1
+               cgen(nl, res);
+               return;
+       case 1:
+               // divide by 2
+               regalloc(&n1, nl->type, res);
+               cgen(nl, &n1);
+               if(issigned[nl->type->etype]) {
+                       // develop -1 iff nl is negative
+                       regalloc(&n2, nl->type, N);
+                       gmove(&n1, &n2);
+                       nodconst(&n3, nl->type, w-1);
+                       gins(optoas(ORSH, nl->type), &n3, &n2);
+                       gins(optoas(OSUB, nl->type), &n2, &n1);
+                       regfree(&n2);
+               }
+               nodconst(&n2, nl->type, n);
+               gins(optoas(ORSH, nl->type), &n2, &n1);
+               gmove(&n1, res);
+               regfree(&n1);
+               return;
+       default:
+               regalloc(&n1, nl->type, res);
+               cgen(nl, &n1);
+               if(issigned[nl->type->etype]) {
+                       // develop (2^k)-1 iff nl is negative
+                       regalloc(&n2, nl->type, N);
+                       gmove(&n1, &n2);
+                       nodconst(&n3, nl->type, w-1);
+                       gins(optoas(ORSH, nl->type), &n3, &n2);
+                       nodconst(&n3, nl->type, w-n);
+                       gins(optoas(ORSH, tounsigned(nl->type)), &n3, &n2);
+                       gins(optoas(OADD, nl->type), &n2, &n1);
+                       regfree(&n2);
+               }
+               nodconst(&n2, nl->type, n);
+               gins(optoas(ORSH, nl->type), &n2, &n1);
+               gmove(&n1, res);
+               regfree(&n1);
+       }
+       return;
+
+divbymul:
+       switch(simtype[nl->type->etype]) {
+       default:
+               goto longdiv;
+
+       case TINT32:
+       case TUINT32:
+       case TINT64:
+       case TUINT64:
+               break;
+       }
+       // todo
+       goto longdiv;
+
+longdiv:
        rax = reg[D_AX];
        rdx = reg[D_DX];
 
index 5ed0a8105917db7b5906a60bb764c831c31e0794..136a8d5efe3d2d5d3972a0b88a3a094b8900bfeb 100644 (file)
@@ -1861,3 +1861,55 @@ no:
        sudoclean();
        return 0;
 }
+
+int
+powtwo(Node *n)
+{
+       uvlong v, b;
+       int i;
+
+       if(n == N || n->op != OLITERAL || n->type == T)
+               goto no;
+       if(!isint[n->type->etype])
+               goto no;
+
+       v = mpgetfix(n->val.u.xval);
+       b = 1ULL;
+       for(i=0; i<64; i++) {
+               if(b == v)
+                       return i;
+               b = b<<1;
+       }
+
+no:
+       return -1;
+}
+
+Type*
+tounsigned(Type *t)
+{
+
+       // this is types[et+1], but not sure
+       // that this relation is immutable
+       switch(t->etype) {
+       default:
+               print("tounsigned: unknown type %T\n", t);
+               break;
+       case TINT:
+               t = types[TUINT];
+               break;
+       case TINT8:
+               t = types[TUINT8];
+               break;
+       case TINT16:
+               t = types[TUINT16];
+               break;
+       case TINT32:
+               t = types[TUINT32];
+               break;
+       case TINT64:
+               t = types[TUINT64];
+               break;
+       }
+       return t;
+}
diff --git a/test/ken/divconst.go b/test/ken/divconst.go
new file mode 100644 (file)
index 0000000..9042b1e
--- /dev/null
@@ -0,0 +1,45 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+
+package main
+
+import "rand"
+
+func   test(a,b,c int64);
+
+func
+main()
+{
+       var a, b int64;
+
+       for i:=0; i<1e6; i++ {
+               a := rand.Int63() - 1<<62;
+               b = a/1;        test(a,b,1);
+               b = a/2;        test(a,b,2);
+               b = a/3;        test(a,b,3);
+               b = a/4;        test(a,b,4);
+               b = a/5;        test(a,b,5);
+               b = a/6;        test(a,b,6);
+               b = a/7;        test(a,b,7);
+               b = a/8;        test(a,b,8);
+               b = a/16;       test(a,b,16);
+               b = a/32;       test(a,b,32);
+               b = a/64;       test(a,b,64);
+               b = a/128;      test(a,b,128);
+               b = a/256;      test(a,b,256);
+               b = a/16384;    test(a,b,16384);
+       }
+}
+
+func
+test(a,b,c int64)
+{
+       d := a/c;
+       if d != b {
+               panicln(a, b, c, d);
+       }
+}