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 + -
显示快捷键?