root/src/cmd/6c/mul.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. lowbit
  2. genmuladd
  3. mulparam
  4. m0
  5. m1
  6. m2
  7. shiftit
  8. mulgen1
  9. mulgen

// Inferno utils/6c/mul.c
// http://code.google.com/p/inferno-os/source/browse/utils/6c/mul.c
//
//      Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
//      Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
//      Portions Copyright © 1997-1999 Vita Nuova Limited
//      Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
//      Portions Copyright © 2004,2006 Bruce Ellis
//      Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
//      Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
//      Portions Copyright © 2009 The Go Authors.  All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include "gc.h"

typedef struct  Malg    Malg;
typedef struct  Mparam  Mparam;

struct  Malg
{
        schar   vals[10];
};

struct  Mparam
{
        uint32  value;
        schar   alg;
        char    neg;
        char    shift;
        char    arg;
        schar   off;
};

static  Mparam  multab[32];
static  int     mulptr;

static  Malg    malgs[] =
{
        {0, 100},
        {-1, 1, 100},
        {-9, -5, -3, 3, 5, 9, 100},
        {6, 10, 12, 18, 20, 24, 36, 40, 72, 100},
        {-8, -4, -2, 2, 4, 8, 100},
};

/*
 * return position of lowest 1
 */
int
lowbit(uint32 v)
{
        int s, i;
        uint32 m;

        s = 0;
        m = 0xFFFFFFFFUL;
        for(i = 16; i > 0; i >>= 1) {
                m >>= i;
                if((v & m) == 0) {
                        v >>= i;
                        s += i;
                }
        }
        return s;
}

void
genmuladd(Node *d, Node *s, int m, Node *a)
{
        Node nod;

        nod.op = OINDEX;
        nod.left = a;
        nod.right = s;
        nod.scale = m;
        nod.type = types[TIND];
        nod.xoffset = 0;
        xcom(&nod);
        gopcode(OADDR, d->type, &nod, d);
}

void
mulparam(uint32 m, Mparam *mp)
{
        int c, i, j, n, o, q, s;
        int bc, bi, bn, bo, bq, bs, bt;
        schar *p;
        int32 u;
        uint32 t;

        bc = bq = 10;
        bi = bn = bo = bs = bt = 0;
        for(i = 0; i < nelem(malgs); i++) {
                for(p = malgs[i].vals, j = 0; (o = p[j]) < 100; j++)
                for(s = 0; s < 2; s++) {
                        c = 10;
                        q = 10;
                        u = m - o;
                        if(u == 0)
                                continue;
                        if(s) {
                                o = -o;
                                if(o > 0)
                                        continue;
                                u = -u;
                        }
                        n = lowbit(u);
                        t = (uint32)u >> n;
                        switch(i) {
                        case 0:
                                if(t == 1) {
                                        c = s + 1;
                                        q = 0;
                                        break;
                                }
                                switch(t) {
                                case 3:
                                case 5:
                                case 9:
                                        c = s + 1;
                                        if(n)
                                                c++;
                                        q = 0;
                                        break;
                                }
                                if(s)
                                        break;
                                switch(t) {
                                case 15:
                                case 25:
                                case 27:
                                case 45:
                                case 81:
                                        c = 2;
                                        if(n)
                                                c++;
                                        q = 1;
                                        break;
                                }
                                break;
                        case 1:
                                if(t == 1) {
                                        c = 3;
                                        q = 3;
                                        break;
                                }
                                switch(t) {
                                case 3:
                                case 5:
                                case 9:
                                        c = 3;
                                        q = 2;
                                        break;
                                }
                                break;
                        case 2:
                                if(t == 1) {
                                        c = 3;
                                        q = 2;
                                        break;
                                }
                                break;
                        case 3:
                                if(s)
                                        break;
                                if(t == 1) {
                                        c = 3;
                                        q = 1;
                                        break;
                                }
                                break;
                        case 4:
                                if(t == 1) {
                                        c = 3;
                                        q = 0;
                                        break;
                                }
                                break;
                        }
                        if(c < bc || (c == bc && q > bq)) {
                                bc = c;
                                bi = i;
                                bn = n;
                                bo = o;
                                bq = q;
                                bs = s;
                                bt = t;
                        }
                }
        }
        mp->value = m;
        if(bc <= 3) {
                mp->alg = bi;
                mp->shift = bn;
                mp->off = bo;
                mp->neg = bs;
                mp->arg = bt;
        }
        else
                mp->alg = -1;
}

int
m0(int a)
{
        switch(a) {
        case -2:
        case 2:
                return 2;
        case -3:
        case 3:
                return 2;
        case -4:
        case 4:
                return 4;
        case -5:
        case 5:
                return 4;
        case 6:
                return 2;
        case -8:
        case 8:
                return 8;
        case -9:
        case 9:
                return 8;
        case 10:
                return 4;
        case 12:
                return 2;
        case 15:
                return 2;
        case 18:
                return 8;
        case 20:
                return 4;
        case 24:
                return 2;
        case 25:
                return 4;
        case 27:
                return 2;
        case 36:
                return 8;
        case 40:
                return 4;
        case 45:
                return 4;
        case 72:
                return 8;
        case 81:
                return 8;
        }
        diag(Z, "bad m0");
        return 0;
}

int
m1(int a)
{
        switch(a) {
        case 15:
                return 4;
        case 25:
                return 4;
        case 27:
                return 8;
        case 45:
                return 8;
        case 81:
                return 8;
        }
        diag(Z, "bad m1");
        return 0;
}

int
m2(int a)
{
        switch(a) {
        case 6:
                return 2;
        case 10:
                return 2;
        case 12:
                return 4;
        case 18:
                return 2;
        case 20:
                return 4;
        case 24:
                return 8;
        case 36:
                return 4;
        case 40:
                return 8;
        case 72:
                return 8;
        }
        diag(Z, "bad m2");
        return 0;
}

void
shiftit(Type *t, Node *s, Node *d)
{
        int32 c;

        c = (int32)s->vconst & 31;
        switch(c) {
        case 0:
                break;
        case 1:
                gopcode(OADD, t, d, d);
                break;
        default:
                gopcode(OASHL, t, s, d);
        }
}

static int
mulgen1(uint32 v, Node *n)
{
        int i, o;
        Mparam *p;
        Node nod, nods;

        for(i = 0; i < nelem(multab); i++) {
                p = &multab[i];
                if(p->value == v)
                        goto found;
        }

        p = &multab[mulptr];
        if(++mulptr == nelem(multab))
                mulptr = 0;

        mulparam(v, p);

found:
//      print("v=%.x a=%d n=%d s=%d g=%d o=%d \n", p->value, p->alg, p->neg, p->shift, p->arg, p->off);
        if(p->alg < 0)
                return 0;

        nods = *nodconst(p->shift);

        o = OADD;
        if(p->alg > 0) {
                regalloc(&nod, n, Z);
                if(p->off < 0)
                        o = OSUB;
        }

        switch(p->alg) {
        case 0:
                switch(p->arg) {
                case 1:
                        shiftit(n->type, &nods, n);
                        break;
                case 15:
                case 25:
                case 27:
                case 45:
                case 81:
                        genmuladd(n, n, m1(p->arg), n);
                        /* fall thru */
                case 3:
                case 5:
                case 9:
                        genmuladd(n, n, m0(p->arg), n);
                        shiftit(n->type, &nods, n);
                        break;
                default:
                        goto bad;
                }
                if(p->neg == 1)
                        gins(ANEGL, Z, n);
                break;
        case 1:
                switch(p->arg) {
                case 1:
                        gmove(n, &nod);
                        shiftit(n->type, &nods, &nod);
                        break;
                case 3:
                case 5:
                case 9:
                        genmuladd(&nod, n, m0(p->arg), n);
                        shiftit(n->type, &nods, &nod);
                        break;
                default:
                        goto bad;
                }
                if(p->neg)
                        gopcode(o, n->type, &nod, n);
                else {
                        gopcode(o, n->type, n, &nod);
                        gmove(&nod, n);
                }
                break;
        case 2:
                genmuladd(&nod, n, m0(p->off), n);
                shiftit(n->type, &nods, n);
                goto comop;
        case 3:
                genmuladd(&nod, n, m0(p->off), n);
                shiftit(n->type, &nods, n);
                genmuladd(n, &nod, m2(p->off), n);
                break;
        case 4:
                genmuladd(&nod, n, m0(p->off), nodconst(0));
                shiftit(n->type, &nods, n);
                goto comop;
        default:
                diag(Z, "bad mul alg");
                break;
        comop:
                if(p->neg) {
                        gopcode(o, n->type, n, &nod);
                        gmove(&nod, n);
                }
                else
                        gopcode(o, n->type, &nod, n);
        }

        if(p->alg > 0)
                regfree(&nod);

        return 1;

bad:
        diag(Z, "mulgen botch");
        return 1;
}

void
mulgen(Type *t, Node *r, Node *n)
{
        if(!mulgen1(r->vconst, n))
                gopcode(OMUL, t, r, n);
}

/* [<][>][^][v][top][bottom][index][help] */