optrel.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 253 行
C
253 行
/****************************************************************************
*
* 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: Relative branch optimizations.
*
****************************************************************************/
#include "optwif.h"
extern ins_entry *FirstIns;
extern byte OptForSize;
extern void TryScrapLabel(code_lbl*);
extern byte ReverseCondition(byte);
extern void AddNewJump(ins_entry*,code_lbl*);
extern code_lbl *AddNewLabel(ins_entry*,int);
extern ins_entry *PrevIns(ins_entry*);
extern void ChgLblRef(ins_entry*,code_lbl*);
extern ins_entry *NextIns(ins_entry*);
extern offset AskLocation(void);
extern int OptInsSize(oc_class,oc_dest_attr);
static code_lbl *Handle;
static bool Jmp_to_lbl( ins_entry *instr )
/********************************************/
{
optbegin
if( _Class( instr ) != OC_JMP ) optreturn( FALSE );
if( _Label( instr ) != Handle ) optreturn( FALSE );
optreturn( TRUE );
}
static bool CanReach( code_lbl *lbl, ins_entry **add_ptr,
ins_entry **jmp_ptr )
/************************************************************
Can a short branch at instruction 'FirstIns' reach label 'lbl'?
*/
{
ins_entry *add;
ins_entry *jmp;
ins_entry *instr;
ins_entry *lbl_ins;
offset obj_len;
add = NULL;
jmp = NULL;
if( _TstStatus( lbl, UNREACHABLE ) ) {
/* can't do anything with it */
} else if( lbl->lbl.address == ADDR_UNKNOWN ) {
if( _TstStatus( lbl, SHORTREACH ) ) return( TRUE );
obj_len = OptInsSize( OC_JMP, OC_DEST_SHORT );
lbl_ins = Handle->ins;
instr = FirstIns;
for(;;) {
instr = NextIns( instr );
if( instr == NULL ) break;
obj_len += _ObjLen( instr );
if( obj_len > MAX_SHORT_FWD ) break;
if( Jmp_to_lbl( instr ) ) {
jmp = instr;
} else if( _TransferClass( _Class( instr ) ) ) {
add = instr;
}
if( instr == lbl_ins ) return( TRUE );
}
} else if( (AskLocation() - lbl->lbl.address) <= MAX_SHORT_BWD ) {
return( TRUE );
}
if( add_ptr != NULL ) *add_ptr = add;
if( jmp_ptr != NULL ) *jmp_ptr = jmp;
return( FALSE );
}
static void HndlRedirect( code_lbl *new )
/*******************************************/
{
code_lbl *redir;
optbegin
redir = Handle->redirect;
if( redir != NULL && redir != new ) {
_ClrStatus( redir, REDIRECTION );
TryScrapLabel( redir );
}
Handle->redirect = new;
if( new != NULL ) {
_SetStatus( new, REDIRECTION );
}
optend
static bool InRange( void )
/*****************************/
/* Check if redirection is still within range*/
{
code_lbl *jmp_lbl;
optbegin
if( _IsModel( NO_OPTIMIZATION ) ) optreturn( FALSE );
jmp_lbl = Handle->redirect;
/* we don't have a redirection for this label*/
if( jmp_lbl == NULL ) optreturn( FALSE );
/* forward jump: must still be in range*/
if( jmp_lbl->lbl.address == ADDR_UNKNOWN ) optreturn( TRUE );
/* can't redirect the redirection jump to itself*/
if( jmp_lbl->lbl.address == AskLocation() ) optreturn( FALSE );
/* can still reach old redirection with short backward jump*/
if( (AskLocation()-jmp_lbl->lbl.address)<=MAX_SHORT_BWD ) optreturn( TRUE );
/* can't get at old redirection any more*/
HndlRedirect( NULL );
optreturn( FALSE );
}
static void BigBranch( ins_entry *add, ins_entry *jmp )
/**********************************************************
We can't get to where we want to go, have to redirect
*/
{
optbegin
if( jmp != NULL && _IsntModel( NO_OPTIMIZATION ) ) {
/* jump to a jump that's going where we want*/
HndlRedirect( AddNewLabel( PrevIns( jmp ), 0 ) );
ChgLblRef( FirstIns, Handle->redirect );
} else if( InRange() ) {
/* use old redirection label*/
ChgLblRef( FirstIns, Handle->redirect );
} else if( add != NULL && _IsntModel( NO_OPTIMIZATION ) ) {
/* add a jump that's in range*/
AddNewJump( add, Handle );
_Savings( OPT_JUMPS, -_ObjLen( NextIns( add ) ) );
HndlRedirect( AddNewLabel( add, 0 ) );
ChgLblRef( FirstIns, Handle->redirect );
} else {
/* reverse the branch*/
_JmpCond( FirstIns ) = ReverseCondition( _JmpCond( FirstIns ) );
AddNewJump( FirstIns, Handle );
ChgLblRef( FirstIns, AddNewLabel( NextIns( FirstIns ), 0 ) );
HndlRedirect( AddNewLabel( FirstIns, 0 ) );
}
optend
static void SetShort( void )
/******************************/
{
ins_entry *l_ins;
int size;
bool floating;
optbegin
floating = FALSE;
if( _Attr( FirstIns ) & ATTR_FLOAT ) {
floating = TRUE;
}
size = OptInsSize( _Class( FirstIns ), OC_DEST_SHORT );
if( _Class( FirstIns ) == OC_JMP ) {
_Savings( OPT_JUMPS, _ObjLen( FirstIns ) - size );
_ObjLen( FirstIns ) = size;
_SetClass( FirstIns, OC_JMP );
if( floating ) {
_SetAttr( FirstIns, ATTR_FLOAT );
}
} else {
_Savings( OPT_JCONDS, _ObjLen( FirstIns ) - size );
_ObjLen( FirstIns ) = size;
_SetClass( FirstIns, OC_JCOND );
if( floating ) {
_SetAttr( FirstIns, ATTR_FLOAT );
}
}
l_ins = _Label( FirstIns )->ins;
if( l_ins != NULL ) {
_SetAttr( l_ins, ATTR_SHORT );
}
optend
extern void SetBranches( void )
/*********************************/
/* Check whether the actual label itself can be targeted*/
{
ins_entry *add;
ins_entry *jmp;
ins_entry *next;
bool was_keep;
optbegin
Handle = _Label( FirstIns );
if( CanReach( Handle, &add, &jmp ) ) {
_SetStatus( Handle, SHORTREACH );
HndlRedirect( NULL );
SetShort();
} else {
if( _Attr( FirstIns ) & ATTR_SHORT ) {
/* HAS to be a short branch */
next = NextIns( FirstIns );
if( _Class(next) == OC_JMP && CanReach(_Label(next), NULL, NULL) ) {
/* we have:
Jcond L1
JMP L2
and L2 is reachable, but L1 is not.
Turn it into:
J~cond L2
JMP L1
*/
_JmpCond( FirstIns ) =
ReverseCondition( _JmpCond( FirstIns ) );
was_keep = ( _TstStatus( Handle, KEEPLABEL ) != 0 );
_SetStatus( Handle, KEEPLABEL );
ChgLblRef( FirstIns, _Label( next ) );
ChgLblRef( next, Handle );
if( !was_keep ) _ClrStatus( Handle, KEEPLABEL );
} else {
BigBranch( add, jmp );
}
SetShort();
} else if( OptForSize > 50 && InRange() ) {
/* use an old redirection label*/
ChgLblRef( FirstIns, Handle->redirect );
SetShort();
}
}
optend
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?