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