Re: Strength reduction of constant multipliers

preston@dawn.cs.rice.edu (Preston Briggs)
Tue, 20 Oct 1992 01:36:44 GMT

          From comp.compilers

Related articles
Strength reduction of constant multipliers cliffc@cs.rice.edu (1992-10-13)
Re: Strength reduction of constant multipliers sastdr@unx.sas.com (1992-10-14)
Re: Strength reduction of constant multipliers sastdr@unx.sas.com (1992-10-15)
Strength reduction of constant multipliers cliffc@cs.rice.edu (1992-10-15)
Re: Strength reduction of constant multipliers davidm@voltaire.rational.com (1992-10-14)
Re: Strength reduction of constant multipliers preston@dawn.cs.rice.edu (1992-10-20)
Constant divisions, remainders rutt@paradise.mti.sgi.com (1992-10-20)
Re: Constant divisions, remainders phillips@swanee.ee.uwa.oz.au (1992-10-23)
| List of all articles for this month |
Newsgroups: comp.compilers
From: preston@dawn.cs.rice.edu (Preston Briggs)
Organization: Rice University, Houston
Date: Tue, 20 Oct 1992 01:36:44 GMT
References: 92-10-057 92-10-069
Keywords: arithmetic, optimize

davidm@voltaire.rational.com (David Moore) writes:
>Although it is undoubtably obvious, no-one to my knowledge has remarked
>that you can use Booth's algorithm for run's of ones of length>2. This
>just uses the fact that 1...1 = 10...0 - 1 (Eg 111 = 1000-1) So you need
>an add and a subtract per run, rather than an add per bit.


The first paper I mentioned, includes the above trick plus Cliff
Click's approach, plus additional improvements. Again, the reference
is


    title="Multiplication by Integer Constants",
    author="Robert Bernstein",
    journal="Software -- Practice and Experience",
    volume=16,
    number=7,
    month=jul,
    year=1986,
    pages="641--652"


It even has code (unfortunately incorrect, due in part to typesetting
errors).


Preston Briggs
------------------------------------------------------------------------------
Here's a version in C that I built for illustration purposes.




/*
  *
  * See -- Multiplication by Integer Constants
  * Robert Bernstein
  * Software -- Practice and Experience
  * Volume 16(7), July 1986
  *
  * corrected and enhanced, supposedly, by Preston Briggs
  * October 7, 1991
  *
  */




#include <stdio.h>


typedef
    enum {
        ErrorOp, NegOp, OneOp,
        ShiftAdd, ShiftSub, ShiftRev,
        FactorAdd, FactorSub, FactorRev
        } OpType;




typedef
    struct node {
        struct node *next;
        struct node * parent;
        int value;
        OpType op;
        char cost;
        char valid;
    } Node, *Nodes;




/*
  * HASH should be prime.
  * Can be made fairly large if it turns out
  * that find() is consuming a lot of time.
  */


#define HASH 97


Nodes *mhash;


Nodes find(n)
          int n;
{
    int absn = n < 0 ? -n : n;
    int h = absn % HASH;
    Nodes p = mhash[h];
    while (p && p->value != n)
        p = p->next;
    if (!p) {
        p = (Nodes) malloc(sizeof(Node));
        p->next = mhash[h];
        mhash[h] = p;
        p->value = n;
        p->valid = 0;
        p->cost = 1;
    }
    return p;
}




int make_odd(n)
          int n;
{
    do {
        n >>= 1;
    } while (!(n & 1));
    return n;
}




void try(op, cost, n, lower, upper, p)
          OpType op;
          int *cost;
          int n;
          int lower;
          int *upper;
          Nodes p;
{
    Nodes parent = find(n);
    int k = odd_cost(parent, n, lower+2, *upper);
    if (k < *cost) { /* must beat a previous cost to go here */
        *cost = k; /* if < cost, then should be valid */
        *upper = k;
        p->parent = parent;
        p->op = op;
        p->cost = parent->cost + 2;
        p->valid = 1;
    }
    else if (!p->valid) {
        if (k < *upper) {
            p->parent = parent;
            p->op = op;
            p->cost = parent->cost + 2;
            p->valid = 1;
        }
        else if (!p->parent) { /* initialize */
            p->parent = parent;
            p->op = op;
            p->cost = parent->cost + 2;
        }
        *cost = k;
        *upper = k;
    }
}




int odd_cost(p, n, lower, upper)
          Nodes p;
          int n;
          int lower;
          int upper;
{
    int cost = p->cost + lower;
    if (cost >= upper)
        return cost;
    else if (p->valid)
        return cost;
    else {
        if (n > 0) {
            int i = 4;
            int nn = n >> 1;
            while (i < nn) {
if (n % (i-1) == 0) try(FactorSub, &cost, n/(i-1), lower, &upper, p);
if (n % (i+1) == 0) try(FactorAdd, &cost, n/(i+1), lower, &upper, p);
i <<= 1;
            }
            try(ShiftAdd, &cost, make_odd(n-1), lower, &upper, p);
        }
        else {
            int i = 4;
            int nn = (-n) >> 1;
            while (i < nn) {
if (n % (1-i) == 0) try(FactorRev, &cost, n/(1-i), lower, &upper, p);
if (n % (i+1) == 0) try(FactorAdd, &cost, n/(i+1), lower, &upper, p);
i <<= 1;
            }
            try(ShiftRev, &cost, make_odd(1-n), lower, &upper, p);
        }
        try(ShiftSub, &cost, make_odd(n+1), lower, &upper, p);
        return cost;
    }
}




int shift(x, y)
          int x, y;
{
    int i = 0;
    do {
        y <<= 1;
        i++;
    } while (x != y);
    return i;
}




int emit(p, r)
          Nodes p;
          int r;
{
    switch (p->op) {
    case OneOp:
        return r;
    case NegOp:
        printf("r%d = r0 - r%d\n", -r, r);
        return -r;
    case ShiftAdd:
        {
            int i = emit(p->parent, r);
            int s = shift(p->value - 1, p->parent->value);
            int t = i << s;
            printf("r%d = r%d << %d\n", t, i, s);
            printf("r%d = r%d + r%d\n", t + r, t, r);
            return t + r;
        }
    case ShiftRev:
        {
            int i = emit(p->parent, r);
            int s = shift(1 - p->value, p->parent->value);
            int t = i << s;
            printf("r%d = r%d << %d\n", t, i, s);
            printf("r%d = r%d - r%d\n", r - t, r, t);
            return r - t;
        }
    case ShiftSub:
        {
            int i = emit(p->parent, r);
            int s = shift(p->value + 1, p->parent->value);
            int t = i << s;
            printf("r%d = r%d << %d\n", t, i, s);
            printf("r%d = r%d - r%d\n", t - r, t, r);
            return t - r;
        }
    case FactorAdd:
        {
            int i = emit(p->parent, r);
            int s = shift(p->value - p->parent->value, p->parent->value);
            int t = i << s;
            printf("r%d = r%d << %d\n", t, i, s);
            printf("r%d = r%d + r%d\n", t + i, t, i);
            return t + i;
        }
    case FactorSub:
        {
            int i = emit(p->parent, r);
            int s = shift(p->value + p->parent->value, p->parent->value);
            int t = i << s;
            printf("r%d = r%d << %d\n", t, i, s);
            printf("r%d = r%d - r%d\n", t-i, t, i);
            return t - i;
        }
    case FactorRev:
        {
            int i = emit(p->parent, r);
            int s = shift(p->parent->value - p->value, p->parent->value);
            int t = i << s;
            printf("r%d = r%d << %d\n", t, i, s);
            printf("r%d = r%d - r%d\n", i-t, i, t);
            return i - t;
        }
    case ErrorOp:
        fprintf(stderr, "ErrorOp encountered\n");
        exit(-1);
    }
}




int estimate(n)
          int n;
{
    int i = -1;
    if (n < 0) {
        n = -n;
        i++;
    }
    do {
        if (n & 1) i += 2;
        n >>= 1;
    } while (n);
    return i;
}




int multiply_even(r, i)
          int r;
          int i;
{
    Nodes p1 = find(i+1);
    int c1 = odd_cost(p1, i+1, 0, estimate(i+1));
    int n = make_odd(i);
    Nodes p2 = find(n);
    int c2 = odd_cost(p2, n, 0, c1);
    int delta = i > 0 ? i - 1 : 1 - i;
    Nodes p3 = find(delta);
    int c3 = odd_cost(p3, delta, 0, c2);
    int c23 = c3 < c2 ? c3 : c2;
    if (c1 <= c23) {
        int t = emit(p1, r);
        printf("r%d = r%d - r%d\n", t-r, t, r);
        return t-r;
    }
    else if (c2 <= c3) {
        int s = shift(i, n);
        int res = emit(p2, r);
        int final = res << s;
        printf("r%d = r%d << %d\n", final, res, s);
        return final;
    }
    else {
        int t = emit(p3, r);
        if (i > 0) {
            printf("r%d = r%d + r%d\n", t+r, t, r);
            return t+r;
        }
        else {
            printf("r%d = r%d - r%d\n", r-t, r, t);
            return r-t;
        }
    }
}






/*
  * Multiply 'r' by the immediate value 'i'
  *
  */


int multiply(r, i)
          int r;
          int i;
{
    if (i) {
        if (i & 1) {
            Nodes p = find(i);
            odd_cost(p, i, 0, estimate(i));
            return emit(p, r);
        }
        else return multiply_even(r, i);
    }
    return i;
}




void init_multiply()
{
    Nodes p;
    mhash = (Nodes *) calloc(HASH, sizeof(Nodes));


    p = find(-1);
    p->valid = 1;
    p->op = NegOp;
    p->cost = 1;
    p->parent = 0;


    p = find(1);
    p->valid = 1;
    p->op = OneOp;
    p->cost = 0;
    p->parent = 0;
}




void main()
{
    int i;
    init_multiply();
    while (EOF != scanf("%d", &i))
        multiply(1, i);
}
--


Post a followup to this message

Return to the comp.compilers page.
Search the comp.compilers archives again.