root/src/cmd/5c/mul.c

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

DEFINITIONS

This source file includes following definitions.
  1. mulcon0
  2. docode
  3. gen1
  4. gen2
  5. gen3

// Inferno utils/5c/mul.c
// http://code.google.com/p/inferno-os/source/browse/utils/5c/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"

/*
 * code sequences for multiply by constant.
 * [a-l][0-3]
 *      lsl     $(A-'a'),r0,r1
 * [+][0-7]
 *      add     r0,r1,r2
 * [-][0-7]
 *      sub     r0,r1,r2
 */

static  int     maxmulops = 3;  /* max # of ops to replace mul with */
static  int     multabp;
static  int32   mulval;
static  char*   mulcp;
static  int32   valmax;
static  int     shmax;

static int      docode(char *hp, char *cp, int r0, int r1);
static int      gen1(int len);
static int      gen2(int len, int32 r1);
static int      gen3(int len, int32 r0, int32 r1, int flag);
enum
{
        SR1     = 1<<0,         /* r1 has been shifted */
        SR0     = 1<<1,         /* r0 has been shifted */
        UR1     = 1<<2,         /* r1 has not been used */
        UR0     = 1<<3,         /* r0 has not been used */
};

Multab*
mulcon0(int32 v)
{
        int a1, a2, g;
        Multab *m, *m1;
        char hint[10];

        if(v < 0)
                v = -v;

        /*
         * look in cache
         */
        m = multab;
        for(g=0; g<nelem(multab); g++) {
                if(m->val == v) {
                        if(m->code[0] == 0)
                                return 0;
                        return m;
                }
                m++;
        }

        /*
         * select a spot in cache to overwrite
         */
        multabp++;
        if(multabp < 0 || multabp >= nelem(multab))
                multabp = 0;
        m = multab+multabp;
        m->val = v;
        mulval = v;

        /*
         * look in execption hint table
         */
        a1 = 0;
        a2 = hintabsize;
        for(;;) {
                if(a1 >= a2)
                        goto no;
                g = (a2 + a1)/2;
                if(v < hintab[g].val) {
                        a2 = g;
                        continue;
                }
                if(v > hintab[g].val) {
                        a1 = g+1;
                        continue;
                }
                break;
        }

        if(docode(hintab[g].hint, m->code, 1, 0))
                return m;
        print("multiply table failure %d\n", v);
        m->code[0] = 0;
        return 0;

no:
        /*
         * try to search
         */
        hint[0] = 0;
        for(g=1; g<=maxmulops; g++) {
                if(g >= maxmulops && v >= 65535)
                        break;
                mulcp = hint+g;
                *mulcp = 0;
                if(gen1(g)) {
                        if(docode(hint, m->code, 1, 0))
                                return m;
                        print("multiply table failure %d\n", v);
                        break;
                }
        }

        /*
         * try a recur followed by a shift
         */
        g = 0;
        while(!(v & 1)) {
                g++;
                v >>= 1;
        }
        if(g) {
                m1 = mulcon0(v);
                if(m1) {
                        strcpy(m->code, m1->code);
                        sprint(strchr(m->code, 0), "%c0", g+'a');
                        return m;
                }
        }
        m->code[0] = 0;
        return 0;
}

static int
docode(char *hp, char *cp, int r0, int r1)
{
        int c, i;

        c = *hp++;
        *cp = c;
        cp += 2;
        switch(c) {
        default:
                c -= 'a';
                if(c < 1 || c >= 30)
                        break;
                for(i=0; i<4; i++) {
                        switch(i) {
                        case 0:
                                if(docode(hp, cp, r0<<c, r1))
                                        goto out;
                                break;
                        case 1:
                                if(docode(hp, cp, r1<<c, r1))
                                        goto out;
                                break;
                        case 2:
                                if(docode(hp, cp, r0, r0<<c))
                                        goto out;
                                break;
                        case 3:
                                if(docode(hp, cp, r0, r1<<c))
                                        goto out;
                                break;
                        }
                }
                break;

        case '+':
                for(i=0; i<8; i++) {
                        cp[-1] = i+'0';
                        switch(i) {
                        case 1:
                                if(docode(hp, cp, r0+r1, r1))
                                        goto out;
                                break;
                        case 5:
                                if(docode(hp, cp, r0, r0+r1))
                                        goto out;
                                break;
                        }
                }
                break;

        case '-':
                for(i=0; i<8; i++) {
                        cp[-1] = i+'0';
                        switch(i) {
                        case 1:
                                if(docode(hp, cp, r0-r1, r1))
                                        goto out;
                                break;
                        case 2:
                                if(docode(hp, cp, r1-r0, r1))
                                        goto out;
                                break;
                        case 5:
                                if(docode(hp, cp, r0, r0-r1))
                                        goto out;
                                break;
                        case 6:
                                if(docode(hp, cp, r0, r1-r0))
                                        goto out;
                                break;
                        }
                }
                break;

        case 0:
                if(r0 == mulval)
                        return 1;
        }
        return 0;

out:
        cp[-1] = i+'0';
        return 1;
}

static int
gen1(int len)
{
        int i;

        for(shmax=1; shmax<30; shmax++) {
                valmax = 1<<shmax;
                if(valmax >= mulval)
                        break;
        }
        if(mulval == 1)
                return 1;

        len--;
        for(i=1; i<=shmax; i++)
                if(gen2(len, 1<<i)) {
                        *--mulcp = 'a'+i;
                        return 1;
                }
        return 0;
}

static int
gen2(int len, int32 r1)
{
        int i;

        if(len <= 0) {
                if(r1 == mulval)
                        return 1;
                return 0;
        }

        len--;
        if(len == 0)
                goto calcr0;

        if(gen3(len, r1, r1+1, UR1)) {
                i = '+';
                goto out;
        }
        if(gen3(len, r1-1, r1, UR0)) {
                i = '-';
                goto out;
        }
        if(gen3(len, 1, r1+1, UR1)) {
                i = '+';
                goto out;
        }
        if(gen3(len, 1, r1-1, UR1)) {
                i = '-';
                goto out;
        }

        return 0;

calcr0:
        if(mulval == r1+1) {
                i = '+';
                goto out;
        }
        if(mulval == r1-1) {
                i = '-';
                goto out;
        }
        return 0;

out:
        *--mulcp = i;
        return 1;
}

static int
gen3(int len, int32 r0, int32 r1, int flag)
{
        int i, f1, f2;
        int32 x;

        if(r0 <= 0 ||
           r0 >= r1 ||
           r1 > valmax)
                return 0;

        len--;
        if(len == 0)
                goto calcr0;

        if(!(flag & UR1)) {
                f1 = UR1|SR1;
                for(i=1; i<=shmax; i++) {
                        x = r0<<i;
                        if(x > valmax)
                                break;
                        if(gen3(len, r0, x, f1)) {
                                i += 'a';
                                goto out;
                        }
                }
        }

        if(!(flag & UR0)) {
                f1 = UR1|SR1;
                for(i=1; i<=shmax; i++) {
                        x = r1<<i;
                        if(x > valmax)
                                break;
                        if(gen3(len, r1, x, f1)) {
                                i += 'a';
                                goto out;
                        }
                }
        }

        if(!(flag & SR1)) {
                f1 = UR1|SR1|(flag&UR0);
                for(i=1; i<=shmax; i++) {
                        x = r1<<i;
                        if(x > valmax)
                                break;
                        if(gen3(len, r0, x, f1)) {
                                i += 'a';
                                goto out;
                        }
                }
        }

        if(!(flag & SR0)) {
                f1 = UR0|SR0|(flag&(SR1|UR1));

                f2 = UR1|SR1;
                if(flag & UR1)
                        f2 |= UR0;
                if(flag & SR1)
                        f2 |= SR0;

                for(i=1; i<=shmax; i++) {
                        x = r0<<i;
                        if(x > valmax)
                                break;
                        if(x > r1) {
                                if(gen3(len, r1, x, f2)) {
                                        i += 'a';
                                        goto out;
                                }
                        } else
                                if(gen3(len, x, r1, f1)) {
                                        i += 'a';
                                        goto out;
                                }
                }
        }

        x = r1+r0;
        if(gen3(len, r0, x, UR1)) {
                i = '+';
                goto out;
        }

        if(gen3(len, r1, x, UR1)) {
                i = '+';
                goto out;
        }

        x = r1-r0;
        if(gen3(len, x, r1, UR0)) {
                i = '-';
                goto out;
        }

        if(x > r0) {
                if(gen3(len, r0, x, UR1)) {
                        i = '-';
                        goto out;
                }
        } else
                if(gen3(len, x, r0, UR0)) {
                        i = '-';
                        goto out;
                }

        return 0;

calcr0:
        f1 = flag & (UR0|UR1);
        if(f1 == UR1) {
                for(i=1; i<=shmax; i++) {
                        x = r1<<i;
                        if(x >= mulval) {
                                if(x == mulval) {
                                        i += 'a';
                                        goto out;
                                }
                                break;
                        }
                }
        }

        if(mulval == r1+r0) {
                i = '+';
                goto out;
        }
        if(mulval == r1-r0) {
                i = '-';
                goto out;
        }

        return 0;

out:
        *--mulcp = i;
        return 1;
}

/*
 * hint table has numbers that
 * the search algorithm fails on.
 * <1000:
 *      all numbers
 * <5000:
 *      ÷ by 5
 * <10000:
 *      ÷ by 50
 * <65536:
 *      ÷ by 250
 */
Hintab  hintab[] =
{
        683,    "b++d+e+",
        687,    "b+e++e-",
        691,    "b++d+e+",
        731,    "b++d+e+",
        811,    "b++d+i+",
        821,    "b++e+e+",
        843,    "b+d++e+",
        851,    "b+f-+e-",
        853,    "b++e+e+",
        877,    "c++++g-",
        933,    "b+c++g-",
        981,    "c-+e-d+",
        1375,   "b+c+b+h-",
        1675,   "d+b++h+",
        2425,   "c++f-e+",
        2675,   "c+d++f-",
        2750,   "b+d-b+h-",
        2775,   "c-+g-e-",
        3125,   "b++e+g+",
        3275,   "b+c+g+e+",
        3350,   "c++++i+",
        3475,   "c-+e-f-",
        3525,   "c-+d+g-",
        3625,   "c-+e-j+",
        3675,   "b+d+d+e+",
        3725,   "b+d-+h+",
        3925,   "b+d+f-d-",
        4275,   "b+g++e+",
        4325,   "b+h-+d+",
        4425,   "b+b+g-j-",
        4525,   "b+d-d+f+",
        4675,   "c++d-g+",
        4775,   "b+d+b+g-",
        4825,   "c+c-+i-",
        4850,   "c++++i-",
        4925,   "b++e-g-",
        4975,   "c+f++e-",
        5500,   "b+g-c+d+",
        6700,   "d+b++i+",
        9700,   "d++++j-",
        11000,  "b+f-c-h-",
        11750,  "b+d+g+j-",
        12500,  "b+c+e-k+",
        13250,  "b+d+e-f+",
        13750,  "b+h-c-d+",
        14250,  "b+g-c+e-",
        14500,  "c+f+j-d-",
        14750,  "d-g--f+",
        16750,  "b+e-d-n+",
        17750,  "c+h-b+e+",
        18250,  "d+b+h-d+",
        18750,  "b+g-++f+",
        19250,  "b+e+b+h+",
        19750,  "b++h--f-",
        20250,  "b+e-l-c+",
        20750,  "c++bi+e-",
        21250,  "b+i+l+c+",
        22000,  "b+e+d-g-",
        22250,  "b+d-h+k-",
        22750,  "b+d-e-g+",
        23250,  "b+c+h+e-",
        23500,  "b+g-c-g-",
        23750,  "b+g-b+h-",
        24250,  "c++g+m-",
        24750,  "b+e+e+j-",
        25000,  "b++dh+g+",
        25250,  "b+e+d-g-",
        25750,  "b+e+b+j+",
        26250,  "b+h+c+e+",
        26500,  "b+h+c+g+",
        26750,  "b+d+e+g-",
        27250,  "b+e+e+f+",
        27500,  "c-i-c-d+",
        27750,  "b+bd++j+",
        28250,  "d-d-++i-",
        28500,  "c+c-h-e-",
        29000,  "b+g-d-f+",
        29500,  "c+h+++e-",
        29750,  "b+g+f-c+",
        30250,  "b+f-g-c+",
        33500,  "c-f-d-n+",
        33750,  "b+d-b+j-",
        34250,  "c+e+++i+",
        35250,  "e+b+d+k+",
        35500,  "c+e+d-g-",
        35750,  "c+i-++e+",
        36250,  "b+bh-d+e+",
        36500,  "c+c-h-e-",
        36750,  "d+e--i+",
        37250,  "b+g+g+b+",
        37500,  "b+h-b+f+",
        37750,  "c+be++j-",
        38500,  "b+e+b+i+",
        38750,  "d+i-b+d+",
        39250,  "b+g-l-+d+",
        39500,  "b+g-c+g-",
        39750,  "b+bh-c+f-",
        40250,  "b+bf+d+g-",
        40500,  "b+g-c+g+",
        40750,  "c+b+i-e+",
        41250,  "d++bf+h+",
        41500,  "b+j+c+d-",
        41750,  "c+f+b+h-",
        42500,  "c+h++g+",
        42750,  "b+g+d-f-",
        43250,  "b+l-e+d-",
        43750,  "c+bd+h+f-",
        44000,  "b+f+g-d-",
        44250,  "b+d-g--f+",
        44500,  "c+e+c+h+",
        44750,  "b+e+d-h-",
        45250,  "b++g+j-g+",
        45500,  "c+d+e-g+",
        45750,  "b+d-h-e-",
        46250,  "c+bd++j+",
        46500,  "b+d-c-j-",
        46750,  "e-e-b+g-",
        47000,  "b+c+d-j-",
        47250,  "b+e+e-g-",
        47500,  "b+g-c-h-",
        47750,  "b+f-c+h-",
        48250,  "d--h+n-",
        48500,  "b+c-g+m-",
        48750,  "b+e+e-g+",
        49500,  "c-f+e+j-",
        49750,  "c+c+g++f-",
        50000,  "b+e+e+k+",
        50250,  "b++i++g+",
        50500,  "c+g+f-i+",
        50750,  "b+e+d+k-",
        51500,  "b+i+c-f+",
        51750,  "b+bd+g-e-",
        52250,  "b+d+g-j+",
        52500,  "c+c+f+g+",
        52750,  "b+c+e+i+",
        53000,  "b+i+c+g+",
        53500,  "c+g+g-n+",
        53750,  "b+j+d-c+",
        54250,  "b+d-g-j-",
        54500,  "c-f+e+f+",
        54750,  "b+f-+c+g+",
        55000,  "b+g-d-g-",
        55250,  "b+e+e+g+",
        55500,  "b+cd++j+",
        55750,  "b+bh-d-f-",
        56250,  "c+d-b+j-",
        56500,  "c+d+c+i+",
        56750,  "b+e+d++h-",
        57000,  "b+d+g-f+",
        57250,  "b+f-m+d-",
        57750,  "b+i+c+e-",
        58000,  "b+e+d+h+",
        58250,  "c+b+g+g+",
        58750,  "d-e-j--e+",
        59000,  "d-i-+e+",
        59250,  "e--h-m+",
        59500,  "c+c-h+f-",
        59750,  "b+bh-e+i-",
        60250,  "b+bh-e-e-",
        60500,  "c+c-g-g-",
        60750,  "b+e-l-e-",
        61250,  "b+g-g-c+",
        61750,  "b+g-c+g+",
        62250,  "f--+c-i-",
        62750,  "e+f--+g+",
        64750,  "b+f+d+p-",
};
int     hintabsize      = nelem(hintab);

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