fold.c

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

C
1,425
字号
    TYPE type_final;

    *happened = FALSE;
    if( notFoldable( expr ) ) {
        return( expr );
    }
    type_final = TypedefModifierRemoveOnly( type );
    type = TypedefModifierRemove( type_final );
    switch( expr->op ) {
    case PT_INT_CONSTANT:
        expr = CastIntConstant( expr, type, happened );
        expr->type = type_final;
        break;
    case PT_FLOATING_CONSTANT:
        expr = castFloatingConstant( expr, type, happened );
        expr->type = type_final;
        break;
    }
    return( expr );
}

static boolean soFarSoGood( PTREE expr, unsigned op, CGOP cgop )
{
    if( expr != NULL && expr->op == op && expr->cgop == cgop ) {
        return( TRUE );
    }
    return( FALSE );
}

static boolean referenceSymbol( PTREE expr )
{
    SYMBOL ref_sym;

    ref_sym = expr->u.symcg.symbol;
    if( ref_sym != NULL && TypeReference( ref_sym->sym_type ) != NULL ) {
        return( TRUE );
    }
    return( FALSE );
}

static boolean thisSymbol( PTREE expr )
{
    SYMBOL this_sym;

    this_sym = expr->u.symcg.symbol;
    if( this_sym == NULL ) {
        return( TRUE );
    }
    return( FALSE );
}

static boolean anachronismFound( PTREE expr )
{
    /* two anachronisms supported:

        (1) this != 0, this == 0
        (2) &r != 0, &r == 0    -- r is 'T & r;' (parm or auto)
    */
    if( ! CompFlags.extensions_enabled ) {
        /* ANSI C++ code cannot require these constructs */
        return( FALSE );
    }
    if( soFarSoGood( expr, PT_UNARY, CO_ADDR_OF ) ) {
        expr = expr->u.subtree[0];
        if( soFarSoGood( expr, PT_UNARY, CO_RARG_FETCH ) ) {
            /*
                int foo( X &r )
                {
                    return &r != NULL;
                }
            */
            expr = expr->u.subtree[0];
            if( soFarSoGood( expr, PT_SYMBOL, CO_NAME_PARM_REF ) ) {
                return( referenceSymbol( expr ) );
            }
        } else if( soFarSoGood( expr, PT_UNARY, CO_FETCH ) ) {
            /*
                int foo( X *p )
                {
                    X &r = *p;
                    return &r != NULL;
                }
            */
            expr = expr->u.subtree[0];
            if( soFarSoGood( expr, PT_SYMBOL, CO_NAME_NORMAL ) ) {
                return( referenceSymbol( expr ) );
            }
        }
    } else if( soFarSoGood( expr, PT_UNARY, CO_RARG_FETCH ) ) {
        /*
            int S::foo()
            {
                return this ? 0 : field;
            }
        */
        expr = expr->u.subtree[0];
        if( soFarSoGood( expr, PT_SYMBOL, CO_NAME_PARM_REF ) ) {
            return( thisSymbol( expr ) );
        }
    }
    return( FALSE );
}

static PTREE makeTrueFalse( PTREE expr, PTREE op, int value )
{
    PTREE node;

    if(( op->flags & PTF_SIDE_EFF ) != 0 ) {
        return( expr );
    }
    if( anachronismFound( op ) ) {
        return( expr );
    }
    node = NodeOffset( value );
    node = NodeSetBooleanType( node );
    node = PTreeCopySrcLocation( node, expr );
    NodeFreeDupedExpr( expr );
    return( node );
}

static PTREE makeBooleanConst( PTREE expr, int value )
{
    DbgVerify( ( value & 1 ) == value, "invalid boolean constant fold" );
    expr->u.int_constant = value;
    expr->op = PT_INT_CONSTANT;
    expr = NodeSetBooleanType( expr );
    return( expr );
}

PTREE FoldUnary( PTREE expr )
/***************************/
{
    PTREE op1;
    TYPE result_type;
    boolean dont_care;

    op1 = expr->u.subtree[0];
    if( notFoldable( op1 ) ) {
        switch( expr->cgop ) {
        case CO_EXCLAMATION:
            if( nonZeroExpr( op1 ) ) {
                expr = makeTrueFalse( expr, op1, 0 );
            }
            break;
        }
        return( expr );
    }
    result_type = expr->type;
    if( op1->op == PT_FLOATING_CONSTANT ) {
        switch( expr->cgop ) {
        case CO_EXCLAMATION:
            op1->u.int64_constant.u._32[ I64HI32 ] = 0;
            op1->u.int64_constant.u._32[ I64LO32 ]
                = ( BFSign( op1->u.floating_constant ) == 0 );
            op1->op = PT_INT_CONSTANT;
            op1 = NodeSetBooleanType( op1 );
            break;
        case CO_UMINUS:
            BFNegate( op1->u.floating_constant );
            break;
        case CO_UPLUS:
            break;
        default:
            return( expr );
        }
        op1 = PTreeCopySrcLocation( op1, expr );
        PTreeFree( expr );
        return( castConstant( op1, result_type, &dont_care ) );
    }
    switch( expr->cgop ) {
    case CO_TILDE:
        op1->u.int64_constant.u._32[0] = ~ op1->u.int64_constant.u._32[0];
        op1->u.int64_constant.u._32[1] = ~ op1->u.int64_constant.u._32[1];
        break;
    case CO_EXCLAMATION:
        op1 = makeBooleanConst( op1, ! nonZeroExpr( op1 ) );
        break;
    case CO_UMINUS:
        U64Neg( &op1->u.int64_constant, &op1->u.int64_constant );
        break;
    case CO_UPLUS:
        break;
    default:
        return( expr );
    }
    op1 = PTreeCopySrcLocation( op1, expr );
    PTreeFree( expr );
    return( castConstant( op1, result_type, &dont_care ) );
}

static PTREE foldFloating( CGOP op, PTREE left, CPP_FLOAT *v2 )
{
    CPP_FLOAT *v1;
    CPP_FLOAT *tmp;

    v1 = left->u.floating_constant;
    switch( op ) {
    case CO_PLUS:
        tmp = BFAdd( v1, v2 );
        BFFree( v1 );
        v1 = tmp;
        break;
    case CO_MINUS:
        tmp = BFSub( v1, v2 );
        BFFree( v1 );
        v1 = tmp;
        break;
    case CO_TIMES:
        tmp = BFMul( v1, v2 );
        BFFree( v1 );
        v1 = tmp;
        break;
    case CO_DIVIDE:
        if( BFSign( v2 ) == 0 ) {
            CErr1( ERR_DIVISION_BY_ZERO );
        }
        tmp = BFDiv( v1, v2 );
        BFFree( v1 );
        v1 = tmp;
        break;
    case CO_EQ:
        left = makeBooleanConst( left, BFCmp( v1, v2 ) == 0 );
        BFFree( v1 );
        return( left );
    case CO_NE:
        left = makeBooleanConst( left, BFCmp( v1, v2 ) != 0 );
        BFFree( v1 );
        return( left );
    case CO_GT:
        left = makeBooleanConst( left, BFCmp( v1, v2 ) > 0 );
        BFFree( v1 );
        return( left );
    case CO_LE:
        left = makeBooleanConst( left, BFCmp( v1, v2 ) <= 0 );
        BFFree( v1 );
        return( left );
    case CO_LT:
        left = makeBooleanConst( left, BFCmp( v1, v2 ) < 0 );
        BFFree( v1 );
        return( left );
    case CO_GE:
        left = makeBooleanConst( left, BFCmp( v1, v2 ) >= 0 );
        BFFree( v1 );
        return( left );
    case CO_COMMA:
        BFFree( v1 );
        v1 = BFCopy( v2 );
        break;
    default:
        return( NULL );
    }

    left->u.floating_constant = v1;
    left->op = PT_FLOATING_CONSTANT;
    return( left );
}

static PTREE foldUInt( CGOP op, PTREE left, target_ulong v2 )
{
    double test;
    target_ulong v1;

    v1 = left->u.uint_constant;
    switch( op ) {
    case CO_PLUS:
        v1 += v2;
        break;
    case CO_MINUS:
        v1 -= v2;
        break;
    case CO_TIMES:
        test = (double) v1 * (double) v2;
        v1 *= v2;
        if( test != v1 ) {
            CErr1( ANSI_ARITHMETIC_OVERFLOW );
        }
        break;
    case CO_DIVIDE:
        if( v2 == 0 ) {
            CErr1( ERR_DIVISION_BY_ZERO );
            v1 = 1;
        } else {
            v1 /= v2;
        }
        break;
    case CO_PERCENT:
        if( v2 == 0 ) {
            CErr1( ERR_DIVISION_BY_ZERO );
            v1 = 1;
        } else {
            v1 %= v2;
        }
        break;
    case CO_AND:
        v1 &= v2;
        break;
    case CO_OR:
        v1 |= v2;
        break;
    case CO_XOR:
        v1 ^= v2;
        break;
    case CO_RSHIFT:
        if( ((target_ulong) v2) >= sizeof( target_long ) * CHAR_BIT ) {
            v1 = 0;
        } else {
            v1 >>= v2;
        }
        break;
    case CO_LSHIFT:
        if( ((target_ulong) v2) >= sizeof( target_long ) * CHAR_BIT ) {
            v1 = 0;
        } else {
            v1 <<= v2;
        }
        break;
    case CO_EQ:
        left = makeBooleanConst( left, v1 == v2 );
        return( left );
    case CO_NE:
        left = makeBooleanConst( left, v1 != v2 );
        return( left );
    case CO_GT:
        left = makeBooleanConst( left, v1 > v2 );
        return( left );
    case CO_LE:
        left = makeBooleanConst( left, v1 <= v2 );
        return( left );
    case CO_LT:
        left = makeBooleanConst( left, v1 < v2 );
        return( left );
    case CO_GE:
        left = makeBooleanConst( left, v1 >= v2 );
        return( left );
    case CO_AND_AND:
        left = makeBooleanConst( left, v1 && v2 );
        return( left );
    case CO_OR_OR:
        left = makeBooleanConst( left, v1 || v2 );
        return( left );
    case CO_COMMA:
        v1 = v2;
        break;
    default:
        return( NULL );
    }
    left->u.uint_constant = v1;
    left->op = PT_INT_CONSTANT;
    return( left );
}

static PTREE foldInt( CGOP op, PTREE left, target_long v2 )
{
    double test;
    target_long v1;

    v1 = left->u.int_constant;
    switch( op ) {
    case CO_PLUS:
        v1 += v2;
        break;
    case CO_MINUS:
        v1 -= v2;
        break;
    case CO_TIMES:
        test = (double) v1 * (double) v2;
        v1 *= v2;
        if( test != v1 ) {
            CErr1( ANSI_ARITHMETIC_OVERFLOW );
        }
        break;
    case CO_DIVIDE:
        if( v2 == 0 ) {
            CErr1( ERR_DIVISION_BY_ZERO );
            v1 = 1;
        } else {
            v1 /= v2;
        }
        break;
    case CO_PERCENT:
        if( v2 == 0 ) {
            CErr1( ERR_DIVISION_BY_ZERO );
            v1 = 1;
        } else {
            v1 %= v2;
        }
        break;
    case CO_AND:
        v1 &= v2;
        break;
    case CO_OR:
        v1 |= v2;
        break;
    case CO_XOR:
        v1 ^= v2;
        break;
    case CO_RSHIFT:
        if( ((target_ulong) v2) >= sizeof( target_long ) * CHAR_BIT ) {
            v1 = FoldSignedRShiftMax( v1 );
        } else {
            v1 >>= v2;
        }
        break;
    case CO_LSHIFT:
        if( ((target_ulong) v2) >= sizeof( target_long ) * CHAR_BIT ) {
            v1 = 0;
        } else {
            v1 <<= v2;
        }
        break;
    case CO_EQ:
        left = makeBooleanConst( left, v1 == v2 );
        return( left );
    case CO_NE:
        left = makeBooleanConst( left, v1 != v2 );
        return( left );
    case CO_GT:
        left = makeBooleanConst( left, v1 > v2 );
        return( left );
    case CO_LE:
        left = makeBooleanConst( left, v1 <= v2 );
        return( left );
    case CO_LT:
        left = makeBooleanConst( left, v1 < v2 );
        return( left );
    case CO_GE:
        left = makeBooleanConst( left, v1 >= v2 );
        return( left );
    case CO_AND_AND:
        left = makeBooleanConst( left, v1 && v2 );
        return( left );
    case CO_OR_OR:
        left = makeBooleanConst( left, v1 || v2 );
        return( left );
    case CO_COMMA:
        v1 = v2;
        break;
    default:
        return( NULL );
    }
    left->u.int_constant = v1;
    left->op = PT_INT_CONSTANT;
    return( left );
}

static void idiv64              // DO 64-BIT SIGNED DIVISION
    ( signed_64 const * v1      // - top
    , signed_64 const * v2      // - divisor
    , signed_64* result         // - result
    , signed_64* rem )          // - remainder
{
    if( v2->u._32[0] == 0
     && v2->u._32[1] == 0 ) {
        CErr1( ERR_DIVISION_BY_ZERO );
        result->u._32[ I64HI32 ] = 0;
        result->u._32[ I64LO32 ] = 1;
        rem->u._32[ I64HI32 ] = 0;
        rem->u._32[ I64LO32 ] = 0;
    } else {
        I64Div( v1, v2, result, rem );
    }
}

static PTREE foldInt64( CGOP op, PTREE left, signed_64 v2 )
{
    signed_64 test;
    signed_64 v1;
    float_handle t0, t1, t2;

    v1 = left->u.int64_constant;
    switch( op ) {
    case CO_PLUS:
        U64Add( &v1, &v2, &left->u.int64_constant );
        break;
    case CO_MINUS:

⌨️ 快捷键说明

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