Strength reduction of constant multipliers

cliffc@cs.rice.edu (Cliff Click)
Thu, 15 Oct 1992 16:37:51 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)
| List of all articles for this month |
Newsgroups: comp.compilers
From: cliffc@cs.rice.edu (Cliff Click)
Organization: Center for Research on Parallel Computations
Date: Thu, 15 Oct 1992 16:37:51 GMT
Keywords: arithmetic, optimize
References: 92-10-057 92-10-063

Due to the number of requests, here comes the C source code I mentioned
in an earlier post. I have cleaned it up some; most notably the code
for dealing with the intermediate representation has been abstracted alot.


As usual, no guarentees and your milage may vary.


Cliff


--------------------------CUT HERE-----------------------------------
/*****************************************************************************/
/* */
/* I N T E G E R M U L T I P L Y */
/* */
/*****************************************************************************/


/* Cost in cycles for integer add */
#define COST_add 1


/* Cost in cycles for integer multiply */
#define COST_mul 16


/* Cost in cycles for integer negation */
#define COST_neg 1


/* Barrel shifters pay a fixed cost for any shift. */
/* The old 68000 would pay 4 for the initial, plus 2 per each bit shifted */
/* Cost in cycles for an initial shift */
#define COST_shl1 1


/* Cost in cycles for a shift by 1 bit */
#define COST_shln 0




/*------------------------------prototypes-----------------------------------*/


/* Create a new intermediate-representation node creating the given constant */
extern Inst *constOp(int32 con);


/* Create a new intermediate-representation node doing "opnum" on the input */
extern Inst *unaryOp(Opnum opnum, Inst *ip);


/* Create a new intermediate-representation node doing "opnum" on the inputs */
extern Inst *binaryOp(Opnum opnum, Inst *ip0, Inst *ip1);


/*------------------------------mul_con_Op-----------------------------------*/
/* Convert an integer multiply by a constant to a series of shifts and adds. */
/* This code assumes that the target can do integer shifts & adds, and that */
/* he has a fixed-cost model for the shift and add/sub instructions. Extra */
/* registers are "free", in the sense that the register allocator yet-to-run */
/* will make spare registers available; i.e. spill costs due to increased */
/* register pressure because of this optimization are not taken into account.*/
/* I assume an optimizer will follow this code and clean up useless moves */
/* and adds-of-zero. */
void mul_con_Op(int32 con, Inst *ip1)
{
    Inst *ip0, *ip2; /* Input node guts */
    uint8 x[33]; /* Need 1 per 32-bits + extra high one */
    int16 i, k, l, m; /* Trash counter */
    uint32 j; /* Used as a mask */
    int16 C; /* Costs calculation */


/* Find cheapest set of shifts/adds that performs the same multiplication, */
/* and compare costs against the cost of a multiply. My heuristic is: If */
/* 2nd highest bit is clear, subtract by power-of-2 for high bit (power-of-2 */
/* computed by successive shifts/adds) and recurse. If 2nd highest bit is */
/* set, subtract next higher power-of-2 from number and recurse. Gather all */
/* the powers-of-2 desired, and determine if you want to shift or add to get */
/* each one of them (then add or sub to get product). */


    for( i=0; i<33; i++) /* Zero costs */
        x[i] = 0;
    i = 31;
    j = 1L<<31; /* Start at top bits */
    while( con ) { /* Still got bits to-do */
        if( con & j ) { /* Found a bit? */
            if( con & (j>>1) ) { /* 2 bits in a row? (11xxx pattern) */
x[i+1] = 1; /* Subtract reversed */
con = (j<<1)-con; /* Compute new, smaller constant */
            } else { /* Else just 1 bit in a row (10xxx pattern) */
x[i] = 2; /* Flag as add power-of-2 */
con -= j; /* Compute new, smaller constant */
            } /* End of either 1 or 2+ bits in a row... */
        } /* End of found bits... */
        j >>= 1; /* Figure next smaller power-of-2 */
        i--; /* Figure log of power-of-2 */
    } /* Repeat till got constant */
    C = 0; /* Cost */
    m = 0;
    for( i=0; i<32; i++) { /* Compute cost */
        if( x[i] ) { /* Need this power of 2? */
            m = i-m; /* Get delta since last power of 2 */
            k = m*COST_add; /* Cost for repeated adds */
            l = COST_shl1+(m-1)*COST_shln; /* Cost for shifting */
            C += ((k < l) ? k : l) +COST_add; /* Take min, plus cost to add res */
            m = i; /* Save for next delta computation */
        } /* Else don't need this power of 2 */
    }
    if( x[32] ) C += COST_neg; /* Need a final negation */


/* With costs in hand, determine to shift/add or multiply. */
    if( C < COST_mul ) { /* Cheaper to shift/add */
        ip0 = constOp(0); /* Start with 0 */
        ip2 = unaryOp(MOV_,ip1); /* Work in a temp */
        m = 0; /* Last power of 2 handy */
        for( i=0; i<32; i++ ) { /* For all shifts/adds */
            if( x[i] ) { /* Need this power of 2? */
m = i-m; /* Powers of 2 to gain */
if( m*COST_add < COST_shl1+(m-1)*COST_shln ) { /* Repeated add */
while( m++ < i ) /* Accumulate powers of 2 */
ip2 = binaryOp(ADD_,ip2,ip2);
} else { /* Else shift left */
ip2 = binaryOp(LSL_,ip2,constOp(m));
} /* End of shift or add... */
ip0 = binaryOp((x[i] == 2) ? ADD_ : SUB_,ip2,ip0);
            } /* End of if need this power of 2... */
        } /* End of for all shifts/adds... */
        if( x[32] ) /* Need final negation? */
            ip0 = unaryOp(NEGATE_,ip0);
    } else /* Else multiply */
        ip0 = binaryOp(MUL_,constOp(con),ip1);


    return ip0;
}
--


Post a followup to this message

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