multiply.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 250 行

C
250
字号
/****************************************************************************
*
*                            Open Watcom Project
*
*    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
*  ========================================================================
*
*    This file contains Original Code and/or Modifications of Original
*    Code as defined in and that are subject to the Sybase Open Watcom
*    Public License version 1.0 (the 'License'). You may not use this file
*    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
*    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
*    provided with the Original Code and Modifications, and is also
*    available at www.sybase.com/developer/opensource.
*
*    The Original Code and all software distributed under the License are
*    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
*    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
*    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
*    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
*    NON-INFRINGEMENT. Please see the License for the specific language
*    governing rights and limitations under the License.
*
*  ========================================================================
*
* Description:  Strength reduction of multiplication operations.
*
****************************************************************************/


#include "standard.h"
#include "coderep.h"
#include "opcodes.h"

extern  instruction     *MakeMove(name*,name*,type_class_def);
extern  instruction     *MakeBinary(opcode_defs,name*,name*,name*,type_class_def);
extern  instruction     *MakeUnary(opcode_defs,name*,name*,type_class_def);
extern  name            *AllocIntConst(int);
extern  name            *AllocTemp(type_class_def);
extern  void            PrefixIns(instruction*,instruction*);
extern  void            FreeIns(instruction*);
extern  int             SubCost(void);
extern  int             AddCost(void);
extern  int             MulCost(unsigned_32);
extern  int             ShiftCost(void);
extern  uint_32         CountBits( uint_32 );

extern  block           *HeadBlock;

#define MAXOPS  20

typedef enum {
    DO_SHL,
    DO_SUB,
    DO_ADD,
    DO_XFR
} op_type;

typedef struct op {
    op_type     op;
    char        cnt;
} op;

static  op      Ops[MAXOPS];


static  int     Factor( unsigned_32 num, int *cost )
/**************************************************/
{
    int         shlcnt;
    int         i;
    unsigned    num_oprs;
    unsigned_32 test;
    unsigned_32 pow2;

    *cost = 0;
    i = MAXOPS;
    if( num == 0 ) return( i );
    if( num == 0xFFFFFFFF ) return( i );

    num_oprs = 0;
    test = num >> 1;
    do {
        pow2 = 1;
        shlcnt = 0;
        while( test ) {
            pow2 <<= 1;
            shlcnt++;
            test >>= 1;
        }
        while( pow2 != 1 ) {
            if( ( num % ( pow2-1) ) == 0 ) {
                test = pow2-1;
            } else if( num % (pow2+1) == 0 ) {
                test = pow2+1;
            } else {
                test = 0;
            }
            if( test ) {
                if( CountBits( num / test )+2 <= CountBits( num ) ) {

                    num /= test;

                    if( --i < 0 ) return( MAXOPS );
                    Ops[i].op = test == pow2-1 ? DO_SUB : DO_ADD;

                    if( --i < 0 ) return( MAXOPS );
                    Ops[i].op = DO_SHL;
                    Ops[i].cnt= shlcnt;

                    if( --i < 0 ) return( MAXOPS );
                    Ops[i].op = DO_XFR;
                    break;
                }
            }
            pow2 >>= 1;
            shlcnt--;
        }
    } while( pow2 != 1 );

    shlcnt = 0;
    for( ;; ) {
        while( !( num & 1 ) ) {
            ++shlcnt;
            num >>= 1;
        }
        if( shlcnt != 0 ) {
            if( --i < 0 ) return( MAXOPS );
            Ops[i].op = DO_SHL;
            Ops[i].cnt= shlcnt;
            *cost += ShiftCost();
            ++num_oprs;
        }
        if( num == 1 ) break;
        if( --i < 0 ) return( MAXOPS );
        shlcnt = 0;
        if( ( num & 3 ) == 1 ) {
            *cost += AddCost();
            Ops[i].op = DO_ADD;
            num >>= 1;
            shlcnt = 1;
        } else {
            *cost += SubCost();
            Ops[i].op = DO_SUB;
            ++num;
        }
        ++num_oprs;
    }
    /*
        Bump up cost estimate to allow for the fact that we're going to have
        [a lot] more instructions with the shift and add method.
    */
    *cost += num_oprs;
    return( i );
}

static  instruction     *CheckMul( instruction *ins )
/***************************************************/
{
    signed_32           rhs;
    int                 i;
    bool                neg;
    instruction         *new_ins;
    name                *orig;
    name                *temp;
    type_class_def      class;
    int                 cost;

    rhs = ins->operands[1]->c.int_value;
    neg = FALSE;
    class = ins->type_class;
    if( class == SW && rhs < 0 ) {
        rhs = -rhs;
        neg = TRUE;
    }
    i = Factor( rhs, &cost );
    if( MulCost( rhs ) <= cost ) return( ins );
    if( i == MAXOPS ) return( ins );
    orig = AllocTemp( class );
    new_ins = MakeMove( ins->operands[0], orig, class );
    PrefixIns( ins, new_ins );
    temp = AllocTemp( class );
    new_ins = MakeMove( orig, temp, class );
    PrefixIns( ins, new_ins );
    for( ; i < MAXOPS; ++i ) {
        switch( Ops[i].op ) {
        case DO_XFR:
            new_ins = MakeUnary( OP_MOV, temp, orig, class );
            break;
        case DO_ADD:
            new_ins = MakeBinary( OP_ADD, temp, orig, temp, class );
            break;
        case DO_SUB:
            new_ins = MakeBinary( OP_SUB, temp, orig, temp, class );
            break;
        case DO_SHL:
            new_ins = MakeBinary( OP_LSHIFT, temp,
                                  AllocIntConst( Ops[i].cnt ), temp, class );
            break;
        }
        PrefixIns( ins, new_ins );
    }
    if( neg ) {
        new_ins = MakeUnary( OP_NEGATE, temp, ins->result, class );
    } else {
        new_ins = MakeMove( temp, ins->result, class );
    }
    PrefixIns( ins, new_ins );
    FreeIns( ins );
    return( new_ins );
}


extern  void    MulToShiftAdd( void )
/***********************************/
{
    block       *blk;
    instruction *ins;
    instruction *next;
    name        *op;

    for( blk = HeadBlock; blk != NULL; blk = blk->next_block ) {
        for( ins = blk->ins.hd.next;
            ins->head.opcode != OP_BLOCK; ins = ins->head.next ) {
            if( ins->head.opcode != OP_MUL ) continue;
            if( ins->operands[0]->n.class == N_CONSTANT ) {
                op = ins->operands[0];
                if( op->c.const_type == CONS_ABSOLUTE ) {
                    ins->operands[0] = ins->operands[1];
                    ins->operands[1] = op;
                }
            }
            op = ins->operands[1];
            switch( op->n.class ) {
            case N_TEMP:
                if( !(op->t.temp_flags & CONST_TEMP) ) continue;
                ins->operands[1] = op->v.symbol;
                /* fall through */
            case N_CONSTANT:
                if( ins->type_class != WD && ins->type_class != SW ) continue;
                if( op->c.const_type != CONS_ABSOLUTE ) continue;
                next = CheckMul( ins );
                if( next == ins ) ins->operands[1] = op; /*nothing happened*/
                ins = next;
            }
        }
    }
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?