From 812f06b3ca425d26ea18f02dd7392a72be4f3eda Mon Sep 17 00:00:00 2001 From: Ken Thompson Date: Sat, 8 Aug 2009 16:53:21 -0700 Subject: [PATCH] another plateau - almost done only need to fix up certain denominators R=rsc OCL=32928 CL=32928 --- src/cmd/6g/ggen.c | 71 ++++++-- test/ken/divconst.go | 376 ++++++++++++++++++++++++++++++++++++++++--- test/ken/modconst.go | 371 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 780 insertions(+), 38 deletions(-) create mode 100644 test/ken/modconst.go diff --git a/src/cmd/6g/ggen.c b/src/cmd/6g/ggen.c index 8bbd7ec4d6..a3723738f5 100644 --- a/src/cmd/6g/ggen.c +++ b/src/cmd/6g/ggen.c @@ -601,16 +601,14 @@ cgen_div(int op, Node *nl, Node *nr, Node *res) if(n < 0) goto divbymul; - if(op == OMOD) { - // todo - goto longdiv; - } - switch(n) { case 0: // divide by 1 regalloc(&n1, nl->type, res); cgen(nl, &n1); + if(op == OMOD) { + gins(optoas(OXOR, nl->type), &n1, &n1); + } else if(s) gins(optoas(OMINUS, nl->type), N, &n1); gmove(&n1, res); @@ -618,6 +616,17 @@ cgen_div(int op, Node *nl, Node *nr, Node *res) return; case 1: // divide by 2 + if(op == OMOD) { + if(issigned[nl->type->etype]) + goto longmod; + regalloc(&n1, nl->type, res); + cgen(nl, &n1); + nodconst(&n2, nl->type, 1); + gins(optoas(OAND, nl->type), &n2, &n1); + gmove(&n1, res); + regfree(&n1); + return; + } regalloc(&n1, nl->type, res); cgen(nl, &n1); if(!issigned[nl->type->etype]) @@ -632,6 +641,23 @@ cgen_div(int op, Node *nl, Node *nr, Node *res) regfree(&n2); break; default: + if(op == OMOD) { + if(issigned[nl->type->etype]) + goto longmod; + regalloc(&n1, nl->type, res); + cgen(nl, &n1); + nodconst(&n2, nl->type, mpgetfix(nr->val.u.xval)-1); + if(!smallintconst(&n2)) { + regalloc(&n3, nl->type, N); + gmove(&n2, &n3); + gins(optoas(OAND, nl->type), &n3, &n1); + regfree(&n3); + } else + gins(optoas(OAND, nl->type), &n2, &n1); + gmove(&n1, res); + regfree(&n1); + return; + } regalloc(&n1, nl->type, res); cgen(nl, &n1); if(!issigned[nl->type->etype]) @@ -657,6 +683,8 @@ cgen_div(int op, Node *nl, Node *nr, Node *res) return; divbymul: + // try to do division by multiply by (2^w)/d + // see hacker's delight chapter 10 switch(simtype[nl->type->etype]) { default: goto longdiv; @@ -669,14 +697,12 @@ divbymul: umagic(&m); if(m.bad) break; - if(op == OMOD) { - // todo - break; - } if(m.ua != 0) { // todo fixup break; } + if(op == OMOD) + goto longmod; savex(D_AX, &ax, &oldax, res, nl->type); savex(D_DX, &dx, &olddx, res, nl->type); @@ -709,14 +735,12 @@ divbymul: smagic(&m); if(m.bad) break; - if(op == OMOD) { - // todo - break; - } if(m.sm < 0) { // todo fixup break; } + if(op == OMOD) + goto longmod; savex(D_AX, &ax, &oldax, res, nl->type); savex(D_DX, &dx, &olddx, res, nl->type); @@ -751,11 +775,32 @@ divbymul: goto longdiv; longdiv: + // division and mod using (slow) hardware instruction savex(D_AX, &ax, &oldax, res, nl->type); savex(D_DX, &dx, &olddx, res, nl->type); dodiv(op, nl, nr, res, &ax, &dx); restx(&ax, &oldax); restx(&dx, &olddx); + return; + +longmod: + // mod using formula A%B = A-(A/B*B) but + // we know that there is a fast algorithm for A/B + regalloc(&n1, nl->type, res); + cgen(nl, &n1); + regalloc(&n2, nl->type, N); + cgen_div(ODIV, &n1, nr, &n2); + if(!smallintconst(nr)) { + regalloc(&n3, nl->type, N); + cgen(nr, &n3); + gins(optoas(OMUL, nl->type), &n3, &n2); + regfree(&n3); + } else + gins(optoas(OMUL, nl->type), nr, &n2); + gins(optoas(OSUB, nl->type), &n2, &n1); + gmove(&n1, res); + regfree(&n1); + regfree(&n2); } /* diff --git a/test/ken/divconst.go b/test/ken/divconst.go index 9042b1e962..d0cbbbedcd 100644 --- a/test/ken/divconst.go +++ b/test/ken/divconst.go @@ -9,37 +9,363 @@ package main import "rand" -func test(a,b,c int64); +const Count = 1e6 + +func +i64rand() int64 +{ + for { + a := int64(rand.Uint32()); + a = (a<<32) | int64(rand.Uint32()); + a >>= uint(rand.Intn(64)); + if -a != a { + return a; + } + } + return 0; // impossible +} + +func +i64test(a,b,c int64) +{ + d := a/c; + if d != b { + panicln("i64", a, b, c, d); + } +} + +func +i64run() +{ + var a, b int64; + + for i:=0; i>= uint(rand.Intn(64)); + return a; +} + +func +u64test(a,b,c uint64) +{ + d := a/c; + if d != b { + panicln("u64", a, b, c, d); + } +} + +func +u64run() +{ + var a, b uint64; + + for i:=0; i>= uint(rand.Intn(32)); + if -a != a { + return a; + } + } + return 0; // impossible +} + +func +i32test(a,b,c int32) +{ + d := a/c; + if d != b { + panicln("i32", a, b, c, d); + } +} + +func +i32run() +{ + var a, b int32; + + for i:=0; i>= uint(rand.Intn(32)); + return a; +} + +func +u32test(a,b,c uint32) +{ + d := a/c; + if d != b { + panicln("u32", a, b, c, d); + } +} + +func +u32run() +{ + var a, b uint32; + + for i:=0; i>= uint(rand.Intn(16)); + if -a != a { + return a; + } + } + return 0; // impossible +} + +func +i16test(a,b,c int16) +{ + d := a/c; + if d != b { + panicln("i16", a, b, c, d); + } +} + +func +i16run() +{ + var a, b int16; + + for i:=0; i>= uint(rand.Intn(16)); + return a; +} + +func +u16test(a,b,c uint16) +{ + d := a/c; + if d != b { + panicln("u16", a, b, c, d); + } +} + +func +u16run() +{ + var a, b uint16; + + for i:=0; i>= uint(rand.Intn(64)); + if -a != a { + return a; + } + } + return 0; // impossible +} + +func +i64test(a,b,c int64) +{ + d := a%c; + if d != b { + panicln("i64", a, b, c, d); + } +} + +func +i64run() +{ + var a, b int64; + + for i:=0; i>= uint(rand.Intn(64)); + return a; +} + +func +u64test(a,b,c uint64) +{ + d := a%c; + if d != b { + panicln("u64", a, b, c, d); + } +} + +func +u64run() +{ + var a, b uint64; + + for i:=0; i>= uint(rand.Intn(32)); + if -a != a { + return a; + } + } + return 0; // impossible +} + +func +i32test(a,b,c int32) +{ + d := a%c; + if d != b { + panicln("i32", a, b, c, d); + } +} + +func +i32run() +{ + var a, b int32; + + for i:=0; i>= uint(rand.Intn(32)); + return a; +} + +func +u32test(a,b,c uint32) +{ + d := a%c; + if d != b { + panicln("u32", a, b, c, d); + } +} + +func +u32run() +{ + var a, b uint32; + + for i:=0; i>= uint(rand.Intn(16)); + if -a != a { + return a; + } + } + return 0; // impossible +} + +func +i16test(a,b,c int16) +{ + d := a%c; + if d != b { + panicln("i16", a, b, c, d); + } +} + +func +i16run() +{ + var a, b int16; + + for i:=0; i>= uint(rand.Intn(16)); + return a; +} + +func +u16test(a,b,c uint16) +{ + d := a%c; + if d != b { + panicln("u16", a, b, c, d); + } +} + +func +u16run() +{ + var a, b uint16; + + for i:=0; i