treefold.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 1,648 行 · 第 1/4 页

C
1,648
字号
/****************************************************************************
*
*                            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:  Processor independent constant folding optimizations.
*
****************************************************************************/


#include "standard.h"
#include "model.h"
#include "coderep.h"
#include "cgdefs.h"
#include "addrname.h"
#include "tree.h"
#include "opcodes.h"
#include "cfloat.h"
#include "zoiks.h"
#include "i64.h"
#include "feprotos.h"
#include "types.h"

typedef union i32 {
    signed_32   s;
    unsigned_32 u;
} i32;

extern  type_def        *TypeInteger;
extern  type_def        *TypeBoolean;

#include "treefold.h"
#include "bldins.h"
extern  an              TreeGen(tn);
extern  name            *AllocIntConst(int);
extern  tn              TGCompare(cg_op,tn,tn,type_def*);
extern  unsigned_32     Mask(btn);
extern  unsigned_32     U32ModDiv(unsigned_32*,unsigned_32);
extern  tn              TGUnary(cg_op,tn,type_def*);
extern  tn              TGBinary(cg_op,tn,tn,type_def*);
extern  void            BurnTree(tn);
extern  tn              TGConst(cfloat *,type_def*);
extern  tn              TGConvert(tn,type_def*);
extern  uint            Length(char*);
extern  tn              TGTrash(tn);
extern  tn              TGNode( tn_class, cg_op, tn, tn, type_def * );
extern  bool            TGCanDuplicate( tn node );
extern  tn              TGDuplicate( tn node );

#define HasBigConst( t )       ( ( (t)->attr & TYPE_FLOAT ) || (t)->length == 8 )

static cg_op RevOpcode[] = {
    O_EQ,    /* O_EQ*/
    O_NE,    /* O_NE*/
    O_LT,    /* O_GT*/
    O_GE,    /* O_LE*/
    O_GT,    /* O_LT*/
    O_LE     /* O_GE*/
};

/* CheckCmpRange is based on code stolen from CheckMeaninglessCompare(),
 * used by the C++ front end. It is quite handy to be able to perform the
 * folding inside the cg, especially since the C++ front end doesn't do it!
 */

#define SIGN_BIT        (0x8000)
#define NumSign( a )    ((a) & SIGN_BIT)
#define NumBits( a )    ((a) & 0x7fff)

typedef enum {
    CMP_VOID    = 0,    /* comparison can't be folded */
    CMP_FALSE   = 1,
    CMP_TRUE    = 2,
} cmp_result;

typedef enum {
    REL_EQ,    // x == c
    REL_LT,    // x < c
    REL_LE,    // x <= c
    REL_SIZE
} rel_op;

//  a <= x <=  b   i.e range of x is between a and b
enum  case_range {
    CASE_LOW,         // c < a
    CASE_LOW_EQ,      // c == a
    CASE_HIGH,        // c > b
    CASE_HIGH_EQ,     // c == b
    CASE_SIZE
};

static char const CmpResult[REL_SIZE][CASE_SIZE] = {
//    c < a      c == a     c > b      c == b
    { CMP_FALSE, CMP_VOID , CMP_FALSE, CMP_VOID },  // x == c
    { CMP_FALSE, CMP_FALSE, CMP_TRUE , CMP_VOID },  // x < c
    { CMP_FALSE, CMP_VOID , CMP_TRUE , CMP_TRUE },  // x <= c
};

#define LOW_VAL         (0x80000000)
#define HIGH_VAL        (0xfffffffful)
#define MAXSIZE         32

static int CmpType( type_def *tipe )
/**********************************/
/* Convert cg type to a value used by CheckCmpRange */
{
    int     ret;

    ret =  tipe->length * 8;
    if( tipe->attr & TYPE_SIGNED )
        ret |= SIGN_BIT;
    return( ret );
}

static cmp_result CheckCmpRange( opcode_defs op, int op_type, cfloat *val )
/*************************************************************************/
/* Check if comparison 'op' of operand of type 'op_type' against constant
 * 'val' can be folded, eg. '(unsigned char)x <= 255'. Integer only, can
 * be used for bitfields (op_type contains number of bits).
 */
{
    enum case_range     range;
    cmp_result          ret;
    signed_32           low;
    signed_32           high;
    signed_32           konst;
    rel_op              rel;
    bool                rev_ret = FALSE;

    /* Map cg rel ops to equivalent cases */
    switch( op ) {
    case O_NE:
        rev_ret = TRUE;
    case O_EQ:
        rel = REL_EQ;
        break;
    case O_GE:
        rev_ret = TRUE;
    case O_LT:
        rel = REL_LT;
        break;
    case O_GT:
        rev_ret = TRUE;
    case O_LE:
        rel = REL_LE;
        break;
    default:
        _Zoiks( ZOIKS_112 );
    }
    /* Determine type range */
    if( NumSign( op_type ) ) {
        low = (signed_32)(LOW_VAL) >> MAXSIZE-NumBits( op_type );
        high = ~low;
    } else {
        low = 0;
        high = HIGH_VAL >> MAXSIZE-NumBits( op_type );
    }
    /* Determine how to compare */
    konst = CFCnvF32( val );
    if( konst == low ) {
        range = CASE_LOW_EQ;
    } else if( konst == high ) {
        range = CASE_HIGH_EQ;
    } else if( NumBits( op_type ) < MAXSIZE ) { /* Can't be outside range */
        if( konst < low ) {                     /* Don't have to do unsigned compare */
            range = CASE_LOW;
        } else if( konst > high ) {
            range = CASE_HIGH;
        } else {
            range = CASE_SIZE;
        }
    } else {
        range = CASE_SIZE;
    }
    /* Figure out comparison result, if possible */
    if( range != CASE_SIZE ) {
        ret = CmpResult[rel][range];
        if( rev_ret && (ret != CMP_VOID) ) {
            /* Flip result */
            if( ret == CMP_FALSE ) {
                ret = CMP_TRUE;
            } else {
                ret = CMP_FALSE;
            }
        }
    } else {
        ret = CMP_VOID;
    }
    return( ret );
}

static signed_32 CFConvertByType( cfloat *cf, type_def *tipe )
/************************************************************/
{
    signed_32   data;

    data = CFCnvF32( cf );
    switch( tipe->length ) {
    case 1:
        if( tipe->attr & TYPE_SIGNED ) {
            data = (signed_8)data;
        } else {
            data = (unsigned_8)data;
        }
        break;
    case 2:
        if( tipe->attr & TYPE_SIGNED ) {
            data = (signed_16)data;
        } else {
            data = (unsigned_16)data;
        }
        break;
    }
    return( data );
}

static signed_64 CFGetInteger64Value( cfloat *cf )
/************************************************/
{
    signed_64   value;
    int         neg;
    cfloat      *trunc;

    trunc = CFTrunc( cf );
    neg = CFTest( trunc );
    if( neg < 0 ) CFNegate( trunc );
    value = CFCnvF64( trunc );
    if( neg < 0 ) U64Neg( &value, &value );
    CFFree( trunc );
    return( value );
}

static  cfloat  *IntToCF( signed_64 value, type_def *tipe )
/*********************************************************/
{
    signed_8    s8;
    unsigned_8  u8;
    signed_16   s16;
    unsigned_16 u16;
    signed_32   s32;
    unsigned_32 u32;

    if( tipe->attr & TYPE_SIGNED ) {
        switch( tipe->length ) {
        case 1:
            s8 = value.u._8[I64LO8];
            return( CFCnvI32F( s8 ) );
        case 2:
            s16 = value.u._16[I64LO16];
            return( CFCnvI32F( s16 ) );
        case 4:
        case 6:
            s32 = value.u._32[I64LO32];
            return( CFCnvI32F( s32 ) );
        case 8:
            return( CFCnvI64F( value.u._32[I64LO32], value.u._32[I64HI32] ) );
        default:
            _Zoiks( ZOIKS_112 );
            return( NULL );
        }
    } else {
        switch( tipe->length ) {
        case 1:
            u8 = value.u._8[I64LO8];
            return( CFCnvU32F( u8 ) );
        case 2:
            u16 = value.u._16[I64LO16];
            return( CFCnvU32F( u16 ) );
        case 4:
        case 6:
            u32 = value.u._32[I64LO32];
            return( CFCnvU32F( u32 ) );
        case 8:
            return( CFCnvU64F( value.u._32[I64LO32], value.u._32[I64HI32] ) );
        default:
            _Zoiks( ZOIKS_112 );
            return( NULL );
        }
    }
}

static  tn      IntToType( signed_32 value, type_def *tipe )
/**********************************************************/
{
    signed_64   temp;

    I32ToI64( value, &temp );
    return( TGConst( IntToCF( temp, tipe ), tipe ) );
}


static  tn      Int64ToType( signed_64 value, type_def *tipe )
/************************************************************/
{
    return( TGConst( IntToCF( value, tipe ), tipe ) );
}


static  tn      CFToType( cfloat *cf, type_def *tipe )
/****************************************************/
{
    tn          result;

    if( ( tipe->attr & TYPE_FLOAT ) == EMPTY ) {
        result = TGConst( IntToCF( CFGetInteger64Value( cf ), tipe ), tipe );
        CFFree( cf );
    } else {
        result = TGConst( cf, tipe );
    }
    return( result );
}



extern  int     GetLog2( unsigned_32 value )
/******************************************/
{
    unsigned_32     count;
    int             log;

    if( _IsPowerOfTwo( value ) && value != 0 ) {
        log = 0;
        count = 1;
        for( ;; ) {
            if( count == value ) return( log );
            count += count;
            ++log;
        }
    }
    return( -1 );
}


extern  tn      FoldTimes( tn left, tn rite, type_def *tipe )
/***********************************************************/
{
    tn          temp;
    tn          fold;
    int         test;
    int         log;
    cfloat      *lv;
    cfloat      *rv;
    unsigned_32 li;
    unsigned_32 ri;

    if( left->class == TN_CONS ) {
        temp = left;
        left = rite;
        rite = temp;
    }
    if( rite->class != TN_CONS ) return( NULL );
    if( left->class == TN_BINARY && left->op == O_TIMES &&
        tipe == left->tipe && !HasBigConst( tipe ) ) {
        if( left->u.left->class == TN_CONS ) {
            left->u.left = FoldTimes( left->u.left, rite, tipe );
            return( left );
        }
        if( left->rite->class == TN_CONS ) {
            left->rite = FoldTimes( left->rite, rite, tipe );
            return( left );
        }
    }
    if( left->class==TN_BINARY && left->op==O_LSHIFT && tipe==left->tipe ) {
        if( !HasBigConst( tipe ) && left->rite->class == TN_CONS ) {
            log = left->rite->u.name->c.int_value;
            li = 1;
            while( --log >= 0 ) {
                li <<= 1;
            }
            BurnTree( left->rite );
            left->rite = CFToType( CFCnvU32F( li ), tipe );
            left->op = O_TIMES;
            left->rite = FoldTimes( left->rite, rite, tipe );
            return( left );
        }
    }
    rv = rite->u.name->c.value;
    if( left->class == TN_CONS ) {
        lv = left->u.name->c.value;
        if( !HasBigConst( tipe ) && CFIs32( lv ) && CFIs32( rv ) ) {
            li = CFConvertByType( lv, tipe );
            ri = CFConvertByType( rv, tipe );
            ri = li * ri;
            fold = IntToType( ri, tipe );
        } else {
            fold = CFToType( CFMul( left->u.name->c.value, rv ), tipe );
        }
        BurnTree( left );
        BurnTree( rite );
        return( fold );
    }

⌨️ 快捷键说明

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