i86ldstr.c

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

C
622
字号
/****************************************************************************
*
*                            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:  RISCify complex instructions into load/store model.
*
****************************************************************************/


#include "standard.h"
#include "coderep.h"
#include "opcodes.h"
#include "pattern.h"
#include "regset.h"
#include "procdef.h"
#include "cfloat.h"
#include "model.h"
#include "vergen.h"
#include "zoiks.h"
#include "score.h"

extern  hw_reg_set      *RegSets[];
extern  proc_def        *CurrProc;
extern  block           *HeadBlock;
extern  byte            OptForSize;

extern  type_class_def  RegClass(hw_reg_set);
extern  opcode_entry    *FindGenEntry(instruction*,bool*);
extern  instruction     *PostExpandIns(instruction*);
extern  void            PrefixIns(instruction*,instruction*);
extern  void            SuffixIns(instruction*,instruction*);
extern  name            *AllocRegName(hw_reg_set);
extern  name            *AllocIntConst(int);
extern  void            UpdateLive(instruction*,instruction*);
extern  instruction     *MakeMove(name*,name*,type_class_def);
extern  void            DupSeg(instruction*,instruction*);
extern  void            DelSeg(instruction*);
extern  void            DeadInstructions(void);
extern  bool            ChangeIns(instruction*,name*,name**,change_type);
extern  void            FreeIns(instruction*);
extern  bool            DoesSomething( instruction* );
extern  name            *HighPart( name *, type_class_def );
extern  name            *LowPart( name *, type_class_def );
extern  void            FreeIns( instruction * );
extern  hw_reg_set      FullReg( hw_reg_set );
extern  bool            ReDefinedBy( instruction *, name * );
extern  void            MoveSegRes( instruction *, instruction * );
extern  void            MoveSegOp( instruction *, instruction *, int );
extern  int             NumOperands( instruction * );
extern  bool            InsOrderDependant( instruction *, instruction * );

extern  type_length     TypeClassSize[];

static  bool            PreferSize;

static  name    **Enregister( instruction *ins )
/***********************************************

    Try to find an operand that's useful to enregister. For MOV's this
    is a constant whose result is a N_MEMORY, N_INDEXED, or N_TEMP with a
    base (486 has a 1 cycle stall in those cases). For other instructions,
    a N_MEMORY, N_INDEXED, or N_TEMP as an operand or result.
*/
{
    int         i;

    switch( ins->head.opcode ) {
    case OP_MOV:
        if( ins->operands[0]->n.class != N_CONSTANT ) return( NULL );
        switch( ins->result->n.class ) {
        case N_INDEXED:
            if( ins->result->i.base == NULL ) break;
            /* fall through */
        case N_MEMORY:
        case N_TEMP:
            return( &ins->operands[0] );
        default:
            break;
        }
        return( NULL );
    case OP_LA:
    case OP_CAREFUL_LA:
    case OP_CONVERT:
    case OP_ROUND:
    case OP_CALL:
    case OP_CALL_INDIRECT:
    case OP_SELECT:
        return( NULL );
    default:
        break;
    }
    /* only RISCify CMPs, TESTs, and MOVs when optimizing for size */
    if( PreferSize && !_OpIsCondition( ins->head.opcode ) ) return( FALSE );
    for( i = ins->num_operands-1; i >= 0; --i ) {
        switch( ins->operands[i]->n.class ) {
        case N_INDEXED:
        case N_MEMORY:
        case N_TEMP:
            return( &ins->operands[i] );
        default:
            break;
        }
    }
    if( ins->result != NULL && !_OpIsCondition( ins->head.opcode ) ) {
        switch( ins->result->n.class ) {
        case N_INDEXED:
        case N_MEMORY:
        case N_TEMP:
            return( &ins->result );
        default:
            break;
        }
    }
    return( NULL );
}

static  hw_reg_set      *RoverByte;
static  hw_reg_set      *RoverWord;
static  hw_reg_set      *RoverDouble;

static hw_reg_set       *FindRegister( instruction *ins )
/********************************************************

    Find a register of the appropriate type for the instruction.
    Note we use rover pointers for each of the classes so that the
    scheduler will have a better chance to intermix instructions.
*/
{
    hw_reg_set  except;
    hw_reg_set  *regs;
    hw_reg_set  *curregs;
    hw_reg_set  *start;
    hw_reg_set  *first;
    hw_reg_set  **rover_ptr;

    switch( ins->type_class ) {
    case U1:
    case I1:
        start = RegSets[ RL_BYTE ];
        rover_ptr = &RoverByte;
        break;
    case U2:
    case I2:
        start = RegSets[ RL_WORD ];
        rover_ptr = &RoverWord;
        break;
#if _TARGET & _TARG_80386
    case U4:
    case I4:
        start = RegSets[ RL_DOUBLE ];
        rover_ptr = &RoverDouble;
        break;
#endif
    default:
        return( NULL );
    }
    except = ins->head.live.regs;
    HW_TurnOn( except, ins->zap->reg );
    if( ins->result != NULL && ins->result->n.class == N_REGISTER ) {
        HW_TurnOn( except, ins->result->r.reg );
    }
    regs = *rover_ptr;
    if( regs == NULL ) {
        regs = start;
        *rover_ptr = start;
    }
    /* 2006-04-25 RomanT
       When optimizing for size, disable rover pointers and
       reuse registers to decrease number of push'es in function prologue
    */
    if( PreferSize ) {
        regs = start;
    }
    first = regs;
    /* NOTE: assumes at least one register in the set */
    /* 2006-04-25 RomanT
       Code rewriten because first and best reg in list (_AX) was used last
    */
    for( ;; ) {
        curregs = regs;
        ++regs;
        if( HW_CEqual( *regs, HW_EMPTY ) ) {
            regs = start;
        }
        if( !HW_Ovlap( *curregs, except ) ) {
            *rover_ptr = regs;  /* next run will use next register */
            break;
        }
        if( regs == first ) return( NULL );
        /* only use _AX when optimizing for size */
        if( PreferSize ) return ( NULL );
    }
    return( curregs );
}


static  instruction     *MakeGeneratable( instruction *ins )
/***********************************************************

    Make sure the instruction is generatable. We might have a couple of
    optmization reductions to work through.
*/
{
    opcode_entry        *tbl;
    instruction         *next;
    instruction         *prev;

    for( ;; ) {
        next = ins->head.next;
        prev = ins->head.prev;
        ins = PostExpandIns( ins );
        if( next != ins->head.next || prev != ins->head.prev ) {
            _Zoiks( ZOIKS_073 );
        }
        tbl = ins->u.gen_table;
        if( tbl != NULL && tbl->generate < FIRST_REDUCT ) break;
    }
    return( ins );
}


static  bool    LoadStoreIns( instruction *ins )
/***********************************************

    RISCify one instruction. See LdStAlloc for details.
*/
{
    name        **op_ptr;
    name        *op;
    hw_reg_set  *hw_reg;
    instruction *new_ins;
    name        *reg;

    if( !DoesSomething( ins ) ) return( FALSE );
    op_ptr = Enregister( ins );
    if( op_ptr == NULL ) return( FALSE );
    hw_reg = FindRegister( ins );
    if( hw_reg == NULL ) return( FALSE );
    reg = AllocRegName( *hw_reg );
    op = *op_ptr;
    if( op == ins->result ) {
        new_ins = MakeMove( reg, op, ins->type_class );
        MoveSegRes( ins, new_ins );
        ins->result = reg;
        SuffixIns( ins, new_ins );
        MakeGeneratable( new_ins );
    }
    if( op_ptr != &ins->result ) {
        new_ins = MakeMove( op, reg, ins->type_class );
        MoveSegOp( ins, new_ins, 0 );
        *op_ptr = reg;
        PrefixIns( ins, new_ins );
        MakeGeneratable( new_ins );
    }
    ins = MakeGeneratable( ins );
    ins->ins_flags |= INS_RISCIFIED;
    return( TRUE );
}

#if _TARGET & _TARG_80386
static  bool    SplitMem16Move( instruction *ins )
/*************************************************
    Return TRUE if we can split the 16-bit move
    instruction given into two one-byte moves.
*/
{
    instruction *new_h;
    instruction *new_l;
    hw_reg_set  reg;

    if( ins->result->n.class == N_REGISTER ) {
        /* make sure we can tear this thing apart */
        reg = ins->result->r.reg;
        HW_COnlyOn( reg, HW_ABCD );
        if( HW_CEqual( reg, HW_EMPTY ) ) {
            return( FALSE );
        }
        if( ReDefinedBy( ins, ins->operands[ 0 ] ) ) {
            return( FALSE );
        }
    }
    new_h = MakeMove( HighPart( ins->operands[ 0 ], U1 ), HighPart( ins->result, U1 ), U1 );
    new_l = MakeMove( LowPart( ins->operands[ 0 ], U1 ), LowPart( ins->result, U1 ), U1 );

    /* this is cheesy - so that we can recover in case we were unable to
       schedule, we stuff a pointer to the second instruction in one of the
       unused operands of the first move instruction, and the original ins
       in another unused operand.
    */

⌨️ 快捷键说明

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