foldins.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 444 行

C
444
字号
/****************************************************************************
*
*                            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:  Constant folding on instruction level.
*
****************************************************************************/


#include "standard.h"
#include "coderep.h"
#include "opcodes.h"
#include "zoiks.h"
#include "typedef.h"
#include "hostsys.h"
#include "model.h"
#include "cgdefs.h"
#include "tree.h"
#include "feprotos.h"
#include "cfloat.h"

extern void             ReplIns(instruction*,instruction*);
extern void             DupSeg(instruction*,instruction*);
extern instruction      *MakeMove(name*,name*,type_class_def);
extern void             DoNothing(instruction*);
extern name             *TGetName(tn);
extern tn               FoldCompare(opcode_defs,tn,tn,type_def*);
extern tn               FoldCnvRnd(cg_op,tn,type_def*);
extern tn               Fold1sComp(tn,type_def*);
extern tn               FoldUMinus(tn,type_def*);
extern tn               FoldLShift(tn,tn,type_def*);
extern tn               FoldRShift(tn,tn,type_def*);
extern tn               FoldXor(tn,tn,type_def*);
extern tn               FoldOr(tn,tn,type_def*);
extern tn               FoldAnd(tn,tn,type_def*);
extern tn               FoldMod(tn,tn,type_def*);
extern tn               FoldDiv(tn,tn,type_def*);
extern tn               FoldTimes(tn,tn,type_def*);
extern tn               FoldMinus(tn,tn,type_def*);
extern tn               FoldPlus(tn,tn,type_def*);
extern tn               TName(name*,type_def*);
extern type_def         *ClassType(type_class_def);
extern int              NumOperands(instruction*);
extern bool             DoesSomething(instruction*);
extern bool             NeedConvert(type_def*,type_def*);
extern  name            *AllocIntConst(int);
extern  bool            AskSegNear(segment_id);
extern  void            SetCSEBits(instruction *,instruction *);
extern  name            *AllocConst( cfloat * );
extern  cfloat          *OkToNegate( cfloat *, type_def * );
extern  instruction     *MakeBinary( opcode_defs, name *, name *, name *, type_class_def );

extern  type_length     TypeClassSize[];


extern  bool    IsTrickyPointerConv( instruction *ins )
/******************************************************
    Is "ins" a near (based) to far pointer conversion that has
    to be carefully converted with taking segments into account?
*/
{
#if _TARGET & ( _TARG_80386 | _TARG_IAPX86 )
    if( (ins->head.opcode == OP_CONVERT) && _IsPointer( ins->type_class ) ) {
        if( ins->base_type_class == U2 && TypeClassSize[ ins->type_class ] > WORD_SIZE )
            return( TRUE );
    }
#endif
    return( FALSE );
}

static  bool    RelocConst( name *op ) {
/***************************************
    Is "op" a relocatable constant?
*/

    bool        reloc_const;

    reloc_const = FALSE;
    if( op->n.class == N_CONSTANT ) {
        if( op->c.const_type != CONS_ABSOLUTE ) {
            reloc_const = TRUE;
        }
    }
    return( reloc_const );
}


static bool ActiveCompare( instruction *ins ) {
/*********************************************/

    if( _FalseIndex( ins ) == _TrueIndex( ins ) ) return( FALSE );
    /* if unexpanded OR expanded and not just placeholder conditional */
    if( ins->table == NULL ) return( TRUE );
    if( ins->u.gen_table == NULL ) return( FALSE );
    if( DoesSomething( ins ) ) return( TRUE );
    return( FALSE );
}


static  instruction *KillCompare( instruction *ins, name *result ) {
/******************************************************************/

    instruction *new_ins;

    if( ins->result != NULL ) {
        new_ins = MakeMove( result, ins->result, ins->result->n.name_class );
        DupSeg( ins, new_ins );
        SetCSEBits( ins, new_ins );
        ReplIns( ins, new_ins );
    } else {
        new_ins = ins;
        DoNothing( ins );
    }
    return( new_ins );
}


static  instruction *CmpRelocZero( instruction *ins, int c, int r ) {
/*******************************************************************/

    name        *cons;
    name        *rel;
    bool        truth;

    if( NumOperands( ins ) != 2 ) return( NULL );
    cons = ins->operands[ c ];
    if( cons->n.class != N_CONSTANT ) return( NULL );
    if( cons->c.const_type != CONS_ABSOLUTE ) return( NULL );
    if( CFTest( cons->c.value ) != 0 ) return( NULL );
    rel = ins->operands[ r ];
    if( rel->c.const_type ==  CONS_OFFSET
     && !AskSegNear( rel->c.int_value ) ) return( NULL );
    switch( ins->head.opcode ) {
    case OP_BIT_TEST_FALSE:
    case OP_CMP_EQUAL:
    case OP_CMP_LESS:
    case OP_CMP_LESS_EQUAL:
        truth = FALSE;
        break;
    case OP_BIT_TEST_TRUE:
    case OP_CMP_GREATER:
    case OP_CMP_GREATER_EQUAL:
    case OP_CMP_NOT_EQUAL:
        truth = TRUE;
        break;
    default:
        return( FALSE );
    }
    if( !ActiveCompare( ins ) ) return( NULL );
    if( c != 1 ) truth = !truth;
    if( truth ) {
        _SetBlockIndex( ins, _TrueIndex(ins), _TrueIndex(ins) );
    } else {
        _SetBlockIndex( ins, _FalseIndex(ins), _FalseIndex(ins) );
    }
    return( KillCompare( ins, AllocIntConst( truth ? FETrue() : 0 ) ) );
}

static  instruction *StraightLine( instruction *ins, tn fold, bool is_true )
/***************************************************************************
    See if we can turn a comparison into a straight line piece of code.
*/
{
    name        *result;

    result = TGetName( fold );
    if( result == NULL ) return( NULL );
    if( result->n.class != N_CONSTANT ) return( NULL );
    if( result->c.const_type != CONS_ABSOLUTE ) return( NULL );
    if( result->c.int_value == 0 ) is_true = !is_true;
    if( is_true ) {
        _SetBlockIndex( ins, _TrueIndex(ins),
                             _TrueIndex(ins) );
    } else {
        _SetBlockIndex( ins, _FalseIndex(ins),
                             _FalseIndex(ins) );
    }
    return( KillCompare( ins, result ) );
}

static  instruction    *FoldAbsolute( instruction *ins ) {
/*********************************************************
    See below.
*/
    instruction *new_ins;
    int         i;
    name        *result;
    tn          fold;
    type_def    *tipe;
    type_def    *left_tipe;
    type_def    *rite_tipe;
    type_def    *fold_tipe;
    pointer     left;
    pointer     rite;
    name        *tmp;
    name        *new_const;
    cfloat      *value;

    tipe = ClassType( ins->type_class );
    left_tipe = ClassType( _OpClass( ins ) );
    i = NumOperands( ins );
    left = NULL;
    rite = NULL;
    if( i != 0 ) {
        left = TName( ins->operands[ 0 ], left_tipe );
        if( i > 1 ) {
            if( ins->operands[ 1 ]->n.name_class == XX ) {
                rite_tipe = tipe;
            } else {
                rite_tipe = ClassType( ins->operands[ 1 ]->n.name_class );
            }
            rite = TName( ins->operands[ 1 ], rite_tipe );
        }
    }
    fold = NULL;
    switch( ins->head.opcode ) {
    case OP_ADD:
        fold = FoldPlus( left, rite, tipe );
        break;
    case OP_SUB:
        fold = FoldMinus( left, rite, tipe );
        break;
    case OP_MUL:
        fold = FoldTimes( left, rite, tipe );
        break;
    case OP_DIV:
        fold = FoldDiv( left, rite, tipe );
        break;
    case OP_MOD:
        fold = FoldMod( left, rite, tipe );
        break;
    case OP_AND:
        fold = FoldAnd( left, rite, tipe );
        break;
    case OP_OR:
        fold = FoldOr( left, rite, tipe );
        break;
    case OP_XOR:
        fold = FoldXor( left, rite, tipe );
        break;
    case OP_RSHIFT:
        fold = FoldRShift( left, rite, tipe );
        break;
    case OP_LSHIFT:
        fold = FoldLShift( left, rite, tipe );
        break;
    case OP_NEGATE:
        fold = FoldUMinus( left, tipe );
        break;
    case OP_COMPLEMENT:
        fold = Fold1sComp( left, tipe );
        break;
    case OP_CONVERT:
        // look out for CNV PT U2 t1 type instructions; if sizeof( PT ) is greater
        // than sizeof( U2 ), we don't want to fold or we'll screw up based pointers
        if( IsTrickyPointerConv( ins ) ) return( NULL );
        // fall through!
    case OP_ROUND:
        fold = FoldCnvRnd( ins->head.opcode, left, tipe );
        break;
    case OP_CMP_EQUAL:
    case OP_CMP_NOT_EQUAL:
    case OP_CMP_GREATER:
    case OP_CMP_LESS_EQUAL:
    case OP_CMP_LESS:
    case OP_CMP_GREATER_EQUAL:
        if( ActiveCompare( ins ) ) {
            fold = FoldCompare( ins->head.opcode, left, rite, tipe );
            if( fold != NULL ) {
                return( StraightLine( ins, fold, TRUE ) );
            }
        }
        break;
    case OP_BIT_TEST_TRUE:
        if( ActiveCompare( ins ) ) {
            fold = FoldAnd( left, rite, tipe );
            if( fold != NULL ) {
                return( StraightLine( ins, fold, TRUE ) );
            }
        }
        break;
    case OP_BIT_TEST_FALSE:
        if( ActiveCompare( ins ) ) {
            fold = FoldAnd( left, rite, tipe );
            if( fold != NULL ) {
                return( StraightLine( ins, fold, FALSE ) );
            }
        }
        break;
    default:
        fold = NULL;
        break;
    }
    if( fold != NULL ) {
        fold_tipe = fold->tipe;
        result = TGetName( fold );
        if( result != NULL & !NeedConvert( fold_tipe, tipe ) ) {
            ins->table = NULL;
            // look out for scary DIV U4 EDX:EAX, c1 -> t1 type instructions
            if( result->n.class != N_CONSTANT &&
                result->n.size != TypeClassSize[ ins->type_class ] ) return( NULL );
            // look out for scary MUL U4 EDX:EAX, c1 -> t1 type instructions
            if( result->n.class != N_CONSTANT &&
                ins->result->n.size != TypeClassSize[ ins->type_class ] ) return( NULL );
            new_ins = MakeMove( result, ins->result, ins->type_class );
            SetCSEBits( ins, new_ins );
            DupSeg( ins, new_ins );
            ReplIns( ins, new_ins );
            return( new_ins );
        }
    } else {
        if( left != NULL ) {
            TGetName( left );
        }
        if( rite != NULL ) {
            TGetName( rite );
        }
    }
    switch( ins->head.opcode ) {
    case OP_SUB:
        // change sub t1, k -> add t1, -k
        if( ins->operands[ 1 ]->n.class == N_CONSTANT &&
            ins->operands[ 1 ]->c.const_type == CONS_ABSOLUTE ) {
            value = OkToNegate( ins->operands[ 1 ]->c.value, tipe );
            if( value != NULL ) {
                new_const = AllocConst( value );
                new_ins = MakeBinary( OP_ADD, ins->operands[ 0 ], new_const, ins->result, ins->type_class );
                SetCSEBits( ins, new_ins );
                DupSeg( ins, new_ins );
                ReplIns( ins, new_ins );
                return( new_ins );
            }
        }
        break;
    case OP_ADD:
    case OP_EXT_ADD:
    case OP_MUL:
    case OP_EXT_MUL:
    case OP_OR:
    case OP_AND:
    case OP_XOR:
        // for commutative op's prefer constant on right
        if( _IsPointer( ins->type_class ) ) break;
        tmp = ins->operands[ 0 ];
        if( tmp->n.class == N_CONSTANT && tmp->c.const_type == CONS_ABSOLUTE ) {
            ins->operands[ 0 ] = ins->operands[ 1 ];
            ins->operands[ 1 ] = tmp;
        }
        break;
    }
    return( NULL );
}

extern  instruction    *FoldIns( instruction *ins ) {
/****************************************************
    See if we can do any constant folding on instruction "ins". This is
    done by building an expression tree to represent "ins", and then
    calling the constant folder used at tree building time. If a folded
    result comes back (non-NULL), turn that result into an instruction
    to replace the original "ins".
*/

    int         i;
    bool        have_const;

    if( ins->ins_flags & INS_CC_USED ) return( NULL );
    i = ins->num_operands;
    have_const = FALSE;
    while( --i >= 0 ) {
        if( ins->operands[ i ]->n.class == N_CONSTANT ) {
            if( ins->operands[ i ]->c.const_type == CONS_ABSOLUTE ) {
                return( FoldAbsolute( ins ) );
            }
            have_const = TRUE;
        }
    }
    if( have_const ) {
        i = NumOperands( ins );
        if( i > 1 ) {
            if( RelocConst( ins->operands[ 1 ] ) ) {
                return( CmpRelocZero( ins, 0, 1 ) );
            }
        }
        if( i != 0 ) {
            if( RelocConst( ins->operands[ 0 ] ) ) {
                return( CmpRelocZero( ins, 1, 0 ) );
            }
        }
    }
    return( NULL );
}



extern  bool    ConstFold( block *root ) {
/****************************************
    For each instruction in the program, see if we can do some constant
    folding that wasn't caught in the tree phase. This will come from
    copy/constant propagation causing an operand to be replaced with
    a constant.
*/

    instruction *ins;
    instruction *next;
    bool        change;
    block       *blk;

    change = FALSE;
    blk = root;
    for( ;; ) {
        ins = blk->ins.hd.next;
        while( ins->head.opcode != OP_BLOCK ) {
            next = ins->head.next;
            if( FoldIns( ins ) != NULL ) change = TRUE;
            ins = next;
        }
        blk = blk->u.partition;
        if( blk == root ) break;
    }
    return( change );
}

⌨️ 快捷键说明

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