cfold.c

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

C
1,229
字号
#endif
        break;
    default:
        value = 0;
        break;
    }
    return( value );
}


void CastConstValue( TREEPTR leaf, DATA_TYPE newtyp )
{
    int_32      val32;
    int64       val64;
    DATA_TYPE   oldtyp;

    oldtyp = leaf->op.const_type;

    if( (newtyp == TYPE_DOUBLE || newtyp == TYPE_FLOAT)
     && (oldtyp == TYPE_DOUBLE || oldtyp == TYPE_FLOAT) ) {
        CastFloatValue( leaf, newtyp );  // float to float
        return;
    } else if( newtyp == TYPE_LONG64 || newtyp == TYPE_ULONG64 ) {
        val64 = LongValue64( leaf );
        leaf->op.ulong64_value = val64;
    } else if( newtyp == TYPE_BOOL ) {
        leaf->op.ulong_value = IsConstantZero( leaf ) ? 0 : 1;
        newtyp = TYPE_UCHAR;
    } else {
        val32 = LongValue( leaf );
        switch( newtyp ) {
        case TYPE_CHAR:
            leaf->op.ulong_value = (signed char)val32;
            break;
        case TYPE_UCHAR:
            leaf->op.ulong_value = (unsigned char)val32;
            break;
        case TYPE_SHORT:
            leaf->op.ulong_value = (target_short)val32;
            break;
        case TYPE_USHORT:
            leaf->op.ulong_value = (target_ushort)val32;
            break;
        case TYPE_INT:
            leaf->op.ulong_value = (target_int)val32;
            break;
        case TYPE_UINT:
            leaf->op.ulong_value = (target_uint)val32;
            break;
        case TYPE_LONG:
            leaf->op.ulong_value = (target_long)val32;
            break;
        case TYPE_ULONG:
            leaf->op.ulong_value = (target_ulong)val32;
            break;
        case TYPE_FLOAT:
        case TYPE_DOUBLE:
        case TYPE_LONG_DOUBLE:
            CastFloatValue( leaf, newtyp );
            return;
        default:
            return;
        }
    }
    leaf->op.opr = OPR_PUSHINT;
    leaf->op.const_type = newtyp;
}


static bool IsConstantZero( TREEPTR tree )
{
    if( tree->op.opr == OPR_PUSHINT ) {
        uint64      val64;

        val64 = LongValue64( tree );
        return( !U64Test( &val64 ) );
    } else {
        FLOATVAL    *flt;
        char        *endptr;
        long_double ld;
        long_double ldzero;

        assert( tree->op.opr == OPR_PUSHFLOAT );
        flt = tree->op.float_value;
        if( flt->len == 0 ) {           // if contains binary value
            ld = flt->ld;
        } else {
            __Strtold( flt->string, &ld, &endptr );
        }
#ifdef _LONG_DOUBLE_
        __I4LD( 0, (long_double near *)&ldzero );
#else
        ldzero.value = 0;
#endif
        return( !FltCmp( &ld, &ldzero ) );
    }
}


static void FoldQuestionTree( TREEPTR tree )
{
    TREEPTR     node;
    TREEPTR     true_part;
    TREEPTR     false_part;
    op_flags    ops;

    node = tree->right;                 // point to OPR_COLON node
    true_part  = node->left;
    false_part = node->right;
    FreeExprNode( node );
    if( IsConstantZero( tree->left ) ) {
        node = false_part;              // want false_part
        FreeExprTree( true_part );
    } else {
        node = true_part;               // want true_part
        FreeExprTree( false_part );
    }
    ops = tree->op.flags;
    FreeExprNode( tree->left );
    *tree = *node;
    node->op.opr = OPR_NOP;
    FreeExprNode( node );
    if( ops & OPFLAG_RVALUE ) {
        if( tree->op.opr == OPR_PUSHADDR ) {
          tree->op.opr = OPR_PUSHSYM;
          ops &= ~OPFLAG_RVALUE;
        }
    tree->op.flags = ops;
    }
}


static bool ConstantLeaf( TREEPTR opnd )
{
    if( opnd->op.opr == OPR_PUSHINT  || opnd->op.opr == OPR_PUSHFLOAT ) {
        return( TRUE );
    } else {
        return( FALSE );
    }
}


static bool FoldableTree( TREEPTR tree )
{
    TREEPTR     opnd;
    TYPEPTR     typ;
    unsigned    offset;

    switch( tree->op.opr ) {
    case OPR_ADD:
    case OPR_SUB:
    case OPR_MUL:
    case OPR_DIV:
    case OPR_CMP:
    case OPR_MOD:
    case OPR_OR:
    case OPR_AND:
    case OPR_XOR:
    case OPR_RSHIFT:
    case OPR_LSHIFT:
    case OPR_OR_OR:
    case OPR_AND_AND:
        return( ConstantLeaf( tree->left ) && ConstantLeaf( tree->right ) );
    case OPR_NEG:
    case OPR_COM:
    case OPR_NOT:
        return( ConstantLeaf( tree->right ) );
    case OPR_CONVERT:
        opnd = tree->right;
        if( opnd->op.opr == OPR_PUSHINT || opnd->op.opr == OPR_PUSHFLOAT ) {
            typ = tree->expr_type;
            CastConstValue( opnd, typ->decl_type );
            *tree = *opnd;
            tree->expr_type = typ;
            opnd->op.opr = OPR_NOP;
            FreeExprNode( opnd );
        }
        break;
    case OPR_RETURN:
        opnd = tree->right;
        if( opnd->op.opr == OPR_PUSHINT || opnd->op.opr == OPR_PUSHFLOAT ) {
            typ = tree->expr_type;
            CastConstValue( opnd, typ->decl_type );
        }
        break;
    case OPR_COMMA:
        opnd = tree->left;
        if( opnd->op.opr == OPR_PUSHINT || opnd->op.opr == OPR_PUSHFLOAT ) {
            FreeExprNode( opnd );
            opnd = tree->right;
            *tree = *opnd;
            opnd->op.opr = OPR_NOP;
            FreeExprNode( opnd );
        }
        break;
    case OPR_QUESTION:
        opnd = tree->left;
        if( opnd->op.opr == OPR_ADDROF
          && (opnd->right->op.opr == OPR_PUSHADDR || opnd->right->op.opr == OPR_PUSHSYM) ) {
            SYM_ENTRY   sym;

            SymGet( &sym, opnd->right->op.sym_handle );
            if( sym.stg_class != SC_AUTO && sym.stg_class != SC_REGISTER ) {
                /* &(static object) is known to be non-zero */
                /* replace it by a 1 */
                FreeExprNode( opnd->right );
                FreeExprNode( opnd );
                tree->left = UIntLeaf( 1 );
                opnd = tree->left;
            }
        }
        if( opnd->op.opr == OPR_PUSHINT || opnd->op.opr == OPR_PUSHFLOAT ) {
            FoldQuestionTree( tree );
        }
        break;
    case OPR_ADDROF:                    // look for offsetof() pattern
        offset = 0;
        opnd = tree->right;
        while( opnd->op.opr == OPR_DOT ) {
            offset += opnd->right->op.long_value;
            opnd = opnd->left;
        }
        if( opnd->op.opr == OPR_ARROW ) {
            offset += opnd->right->op.long_value;
            opnd = opnd->left;
            if( opnd->op.opr == OPR_PUSHINT ) {
                offset += opnd->op.long_value;
                opnd = tree->right;
                tree->op.opr = OPR_PUSHINT;
                tree->op.long_value = offset;
                tree->op.const_type = TYPE_UINT;
                tree->expr_type = GetType( TYPE_UINT );
                tree->right = NULL;
                FreeExprTree( opnd );
            }
        }
        break;
    default:
        break;
    }
    return( FALSE );
}

typedef enum {
    SIGNED_INT,
    UNSIGNED_INT,
    SIGNED_INT64,
    UNSIGNED_INT64,
    FLOATING,
    NOT_A_NUMBER
} arithmetic_type;

static arithmetic_type ArithmeticType( DATA_TYPE decl_type )
{
    switch( decl_type ) {
    case TYPE_CHAR:
    case TYPE_SHORT:
    case TYPE_INT:
    case TYPE_LONG:
        return( SIGNED_INT );
    case TYPE_LONG64:
        return( SIGNED_INT64 );
    case TYPE_UCHAR:
    case TYPE_USHORT:
    case TYPE_UINT:
    case TYPE_ULONG:
    case TYPE_POINTER:
        return( UNSIGNED_INT );
    case TYPE_ULONG64:
        return( UNSIGNED_INT64 );
    case TYPE_FLOAT:
    case TYPE_DOUBLE:
        return( FLOATING );
    }
    return( NOT_A_NUMBER );
}


/* Check values of constant operands of certain operators. Needs to be done
 * after all sub-trees are folded (the checked operands may be result of
 * constant folding) but before potentially constant folding the examined
 * operator.
 */
static void CheckOpndValues( TREEPTR tree )
{
    TYPEPTR             r_type;
    TREEPTR             opnd;
    arithmetic_type     con;

    switch( tree->op.opr ) {
    case OPR_LSHIFT:
    case OPR_RSHIFT:
    case OPR_LSHIFT_EQUAL:
    case OPR_RSHIFT_EQUAL:
        if( ConstantLeaf( tree->right ) ) {
            bool    shift_too_big = FALSE;
            bool    shift_negative = FALSE;
            int     max_shift;

            opnd = tree->right;
            r_type = opnd->expr_type;
            con = ArithmeticType( r_type->decl_type );
            // shift arguments undergo integral promotion; 'char c = 1 << 10;'
            // is not undefined, though it will overflow
            max_shift = max( SizeOfArg( tree->left->expr_type ),
                        SizeOfArg( GetType( TYPE_INT ) ) ) * 8;
            switch( con ) {
            case SIGNED_INT: {
                int_32      right;

                right = opnd->op.long_value;
                if( right < 0 )
                    shift_negative = TRUE;
                else if( right >= max_shift )
                    shift_too_big = TRUE;
                break;
                }
            case SIGNED_INT64: {
                int64       right;
                int64       big_shift;

                right = LongValue64( opnd );
                I32ToI64( max_shift, &big_shift );
                if( I64Test( &right ) < 0 )
                    shift_negative = TRUE;
                else if( I64Cmp( &right, &big_shift ) >= 0 )
                    shift_too_big = TRUE;
                break;
                }
            case UNSIGNED_INT:
                if( (uint_32)opnd->op.long_value >= max_shift )
                    shift_too_big = TRUE;
                break;
            case UNSIGNED_INT64: {
                uint64      right;
                uint64      big_shift;

                right = LongValue64( opnd );
                U32ToU64( max_shift, &big_shift );
                if( U64Cmp( &right, &big_shift ) >= 0 )
                    shift_too_big = TRUE;
                break;
                }
            default:
                // Not supposed to happen!
                break;
            }
            if( shift_negative ) {
                CWarn1( WARN_SHIFT_AMOUNT_NEGATIVE, ERR_SHIFT_AMOUNT_NEGATIVE );
            } else if( shift_too_big ) {
                CWarn1( WARN_SHIFT_AMOUNT_TOO_BIG, ERR_SHIFT_AMOUNT_TOO_BIG );
            }
        }
        break;
    default:
        break;
    }
}


void DoConstFold( TREEPTR tree )
{
    DATA_TYPE   decl_type;

    CheckOpndValues( tree );
    if( FoldableTree( tree ) ) {
        arithmetic_type     con;

        if( tree->op.opr == OPR_CMP ) {
            decl_type = tree->op.compare_type->decl_type;
        } else {
            decl_type = tree->expr_type->decl_type;
        }
        con = ArithmeticType( decl_type );
        switch( con ) {
        case SIGNED_INT:
            DoSignedOp( tree->left, tree, tree->right );
            break;
        case SIGNED_INT64:
            DoSignedOp64( tree->left, tree, tree->right );
            break;
        case UNSIGNED_INT:
            DoUnSignedOp( tree->left, tree, tree->right );
            break;
        case UNSIGNED_INT64:
            DoUnSignedOp64( tree->left, tree, tree->right );
            break;
        case FLOATING:
            DoFloatOp( tree->left, tree, tree->right );
            break;
        }
    }
}


void FoldExprTree( TREEPTR tree )
{
    WalkExprTree( tree, NoOp, NoOp, NoOp, DoConstFold );
}


bool BoolConstExpr( void )
{
    const_val   val;

    ConstExprAndType( &val );
    return( U64Test( &val.value ) );
}

⌨️ 快捷键说明

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