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