i86proc.c

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

C
1,286
字号
/****************************************************************************
*
*                            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:  Intel x86 procedure call generation.
*
****************************************************************************/


#include "standard.h"
#include "coderep.h"
#include "opcodes.h"
#include "procdef.h"
#include "model.h"
#include "rtclass.h"
#include "objrep.h"
#include "ocentry.h"
#include "gen8087.h"
#include "cgaux.h"
#include "stackok.h"
#include "zoiks.h"
#include "feprotos.h"

extern  void        OutDLLExport(uint,sym_handle);
extern  void        GenLeaSP(long);
extern  void        Gcld( void );
extern  void        GenReturn(int,bool,bool);
extern  void        GenLeave( void );
extern  void        GenWindowsProlog( void );
extern  void        GenCypWindowsProlog( void );
extern  void        GenWindowsEpilog( void );
extern  void        GenCypWindowsEpilog( void );
extern  void        EmitRtnEnd( void );
extern  abspatch_handle *NextFramePatch( void );
extern  void        EmitEpiBeg( void );
extern  void        PatchBigLabels(offset);
extern  void        GenEnter(int,int);
extern  void        GenUnkEnter(pointer,int);
extern  void        GenRegAnd(hw_reg_set,type_length);
extern  void        GenRegSub(hw_reg_set,type_length);
extern  void        GenUnkSub(hw_reg_set,pointer);
extern  void        AdjustPushLocal(name*);
extern  bool        DoesSomething(instruction*);
extern  void        GenRegAdd(hw_reg_set,type_length);
extern  void        GenRegMove(hw_reg_set,hw_reg_set);
extern  void        GenPushOffset(byte);
extern  void        EmitProEnd( void );
extern  void        DbgRetOffset(type_length);
extern  void        RelocParms( void );
extern  type_length AdjustBase( void );
extern  hw_reg_set  SaveRegs( void );
extern  void        DoCall(label_handle,bool,bool,oc_class);
extern  label_handle    RTLabel(int);
extern  void        GenUnkPush(pointer);
extern  void        GenPushC(signed_32);
extern  void        GenUnkMov(hw_reg_set,pointer);
extern  void        QuickSave(hw_reg_set,opcode_defs);
extern  sym_handle  AskForLblSym(label_handle);
extern  void        CodeLabel(label_handle,unsigned);
extern  void        EmitRtnBeg( void );
extern  void        CodeLineNum( cg_linenum,bool);
extern  seg_id      SetOP(seg_id);
extern  seg_id      AskCodeSeg( void );
extern  void        Gpusha( void );
extern  void        Gpopa( void );
extern  void        AbsPatch(abspatch_handle,offset);
extern  label_handle    AskForSymLabel(pointer ,cg_class );
extern  bool        AskIfRTLabel(label_handle);
extern  unsigned    DepthAlign( unsigned );
extern  char        *CopyStr(char*,char*);
extern  void        EyeCatchBytes(byte*,uint);
extern  void        GenSelEntry(bool);
extern  void        TellKeepLabel(label_handle);
extern  label_handle    AskForNewLabel(void);
extern  void        GenKillLabel(label_handle);
extern  void        GFstpM(pointer);
extern  void        GenTouchStack( bool );
extern  void        GenLoadDS(void);
extern  label_handle    GenFar16Thunk( label_handle, unsigned_16, bool );
extern  void        GenP5ProfilingProlog( label_handle );
extern  void        GenP5ProfilingEpilog( label_handle );
extern  bool        SymIsExported( sym_handle );
extern  void        FlowSave( hw_reg_set * );
extern  void        FlowRestore( hw_reg_set * );

/* forward declarations */
static  void        MoveParms( void );
static  int         PushAll( void );
static  void        CalcUsedRegs( void );
static  void        Enter( void );
static  void        AllocStack( void );
static  int         Push( hw_reg_set to_push );
static  void        DoEnter( int level );
static  void        DoEpilog( void );

extern  block       *HeadBlock;
extern  proc_def    *CurrProc;
extern  bool        BlockByBlock;
extern  type_length MaxStack;
extern  hw_reg_set  GivenRegisters;
extern  byte        OptForSize;
extern  pointer     Parm8087[ MAX_8087_REG+1 ];

#define WINDOWS_CHEAP  ( ( _IsModel( DLL_RESIDENT_CODE ) &&         \
               ( CurrProc->state.attr & ROUTINE_LOADS_DS ) )        \
            || ( _IsTargetModel( CHEAP_WINDOWS )                    \
               && !( CurrProc->prolog_state &                       \
                 ( GENERATE_EXPORT | GENERATE_FAT_PROLOG ) ) ) )

#define DO_WINDOWS_CRAP ( _IsTargetModel( WINDOWS )                 \
               && ( !WINDOWS_CHEAP || CurrProc->contains_call ) )

#define DO_BP_CHAIN ( ( (_IsTargetModel( NEED_STACK_FRAME ) || _IsModel( DBG_CV ) ) \
               && CurrProc->contains_call )                                         \
             || ( CurrProc->prolog_state & GENERATE_FAT_PROLOG ) )

#define CHAIN_FRAME ( DO_WINDOWS_CRAP || DO_BP_CHAIN )

#define CHEAP_FRAME ( _IsTargetModel( NEED_STACK_FRAME ) || \
              _IsntTargetModel( WINDOWS ) || WINDOWS_CHEAP )

#define FAR_RET_ON_STACK ( (_RoutineIsLong( CurrProc->state.attr ) ) \
             && !(CurrProc->state.attr & ROUTINE_NEVER_RETURNS))

type_length StackDepth;

hw_reg_set   PushRegs[] = {
#if _TARGET & _TARG_80386
#define ALL_REG_SIZE 12*WORD_SIZE
#define HW_STACK_CHECK HW_EAX
    HW_D( HW_EAX ),
    HW_D( HW_EBX ),
    HW_D( HW_ECX ),
    HW_D( HW_EDX ),
    HW_D( HW_ESI ),
    HW_D( HW_EDI ),
    HW_D( HW_DS ),
    HW_D( HW_ES ),
    HW_D( HW_FS ),
    HW_D( HW_GS ),
    HW_D( HW_SS ),
#else
#define ALL_REG_SIZE 8*WORD_SIZE+4*2
#define HW_STACK_CHECK HW_AX
    HW_D( HW_AX ),
    HW_D( HW_BX ),
    HW_D( HW_CX ),
    HW_D( HW_DX ),
    HW_D( HW_SI ),
    HW_D( HW_DI ),
    HW_D( HW_DS ),
    HW_D( HW_ES ),
    HW_D( HW_FS ),
    HW_D( HW_GS ),
    HW_D( HW_SS ),
#endif
    HW_D( HW_BP ),
    HW_D( HW_EMPTY )
};

extern  bool    CanZapBP( void ) {
/**************************/

    return( !CHAIN_FRAME );
}


static  bool    ScanInstructions( void )
/**********************************/
{
    block       *blk;
    instruction     *ins;
    name        *addr;
    bool        sp_constant;

    CurrProc->contains_call = TRUE;
    if( BlockByBlock )
        return( FALSE );
    CurrProc->contains_call = FALSE;
    blk = HeadBlock;
    sp_constant = TRUE;
    while( blk != NULL ) {
        ins = blk->ins.hd.next;
        while( ins->head.opcode != OP_BLOCK ) {
            if( _OpIsCall( ins->head.opcode ) ) {
                if( ins->head.opcode == OP_CALL_INDIRECT ) {
                    CurrProc->contains_call = TRUE;
                } else {
                    addr = ins->operands[ CALL_OP_ADDR ];
                    if( addr->n.class != N_MEMORY ||
                     addr->m.memory_type != CG_LBL ||
                     !AskIfRTLabel( addr->v.symbol ) ) {
                        CurrProc->contains_call = TRUE;
                    }
                }
                if( HW_COvlap( ins->zap->reg, HW_SP ) ) {
                    CurrProc->state.attr |= ROUTINE_NEEDS_PROLOG;
                    sp_constant = FALSE;
                }
            }
            ins = ins->head.next;
        }
        blk = blk->next_block;
    }
    return( sp_constant );
}


#if _TARGET & _TARG_80386
static  void    ChkFDOp( name *op, int depth ) {
/**********************************************/

    if( op->n.class != N_TEMP )
        return;
    if( !( op->v.usage & (USE_IN_ANOTHER_BLOCK|USE_ADDRESS) ) )
        return;
    if( op->t.temp_flags & STACK_PARM )
        return;
    if( op->t.location != NO_LOCATION ) {
        if( op->v.usage & (USE_ADDRESS|HAS_MEMORY) )
            return;
        if( op->t.alias != op )
            return;
        if( depth == 0 )
            return;
        op->t.location = NO_LOCATION;
    }
    op->t.temp_flags |= USED_AS_FD;
    CurrProc->targ.has_fd_temps = TRUE;
}
#endif


#if _TARGET & _TARG_80386
static  void    ScanForFDOps( void )
/****************************/
{
    block       *blk;
    instruction     *ins;
    int         i;
    int         depth;

    CurrProc->contains_call = FALSE;
    if( BlockByBlock )
        return;
    blk = HeadBlock;
    while( blk != NULL ) {
        ins = blk->ins.hd.next;
        depth = blk->depth;
        while( ins->head.opcode != OP_BLOCK ) {
            if( ins->type_class == FD || ins->type_class == FL ) {
                i = ins->num_operands;
                while( --i >= 0 ) {
                    ChkFDOp( ins->operands[i], depth );
                }
                if( ins->result != NULL ) {
                    ChkFDOp( ins->result, depth );
                }
            }
            ins = ins->head.next;
        }
        blk = blk->next_block;
    }
}
#endif


#if _TARGET & _TARG_80386
static  block   *ScanForLabelReturn( block *blk ) {
/*********************************************/

    block   *son;
    int     i;

    if( blk->class & (RETURN|CALL_LABEL) )
        return( NULL );
    blk->edge[0].flags |= DOWN_ONE_CALL;
    if( blk->class & LABEL_RETURN )
        return( blk );
    for( i = 0; i < blk->targets; ++i ) {
        son = blk->edge[i].destination;
        if( son->edge[0].flags & DOWN_ONE_CALL )
            continue;
        if( SafeRecurse( (void *(*)(void *))ScanForLabelReturn, son ) == NULL )
            return( NULL );
    }
    return( blk );
}
#endif


#if _TARGET & _TARG_80386
static  bool    ScanLabelCalls( void ) {
/*********************************

    Make sure that all blocks that are called are only called
    one level deep. Mark output edges of all such blocks as
    DOWN_ONE_CALL. This is so we can adjust our x[esp] offsets
    accordingly.
*/

    block   *blk;

    for( blk = HeadBlock; blk != NULL; blk = blk->next_block ) {
        if( !( blk->class & CALL_LABEL ) )
            continue;
        if( ScanForLabelReturn( blk->edge[0].destination ) == NULL ) {
            return( FALSE );
        }
    }
    return( TRUE );
}
#endif


extern  void    AddCacheRegs( void ) {
/******************************/

    #if _TARGET & _TARG_80386
    if( CurrProc->targ.never_sp_frame )
        return;
    if( _IsntModel( MEMORY_LOW_FAILS ) )
        return;
    if( OptForSize > 50 )
        return;
    if( _IsTargetModel( FLOATING_DS | FLOATING_SS ) )
        return;
    if( !ScanInstructions() )
        return;
    if( !CanZapBP() )
        return;
    if( !ScanLabelCalls() )
        return;
    if( CurrProc->state.attr & ROUTINE_WANTS_DEBUGGING )
        return;
    if( CurrProc->lex_level != 0 )
        return;
    if( _FPULevel( FPU_586 ) ) {
        ScanForFDOps();
    }
    if( CurrProc->targ.has_fd_temps ) {
        CurrProc->targ.sp_frame = TRUE;
        CurrProc->targ.sp_align = TRUE;
    } else if( !DO_BP_CHAIN && _IsntTargetModel( WINDOWS ) &&
            !_RoutineIsInterrupt( CurrProc->state.attr ) ) {
        /*
         * We cannot make EBP available under Windows because the SS
         * selector might not cover the data segment and so we cannot use
         * it as an index. Puke - BBB Feb 18, 1994
         */
        CurrProc->targ.sp_frame = TRUE;
        HW_CTurnOff( CurrProc->state.unalterable, HW_BP );
    }
    #endif
}


static  void    AdjustPushLocals( void ) {
/**********************************/

    instruction *ins;

    ins = HeadBlock->ins.hd.next;
    for(;;) {
        if( DoesSomething( ins ) )
            break;
        if( ins->head.opcode == OP_MOV
         && ins->head.state == OPERANDS_NEED_WORK ) {
            QuickSave( ins->operands[ 0 ]->r.reg, OP_PUSH );
            AdjustPushLocal( ins->result );
        }
        ins = ins->head.next;
    }
}

static  bool    NeedBPProlog( void ) {
/******************************/

    if( CurrProc->parms.size != 0 )
        return( TRUE );
    if( CurrProc->locals.size != 0 )
        return( TRUE );
    if( CurrProc->targ.push_local_size != 0 )
        return( TRUE );
    if( CurrProc->lex_level != 0 )
        return( TRUE );
    if( CurrProc->targ.sp_align )
        return( TRUE );
    if( BlockByBlock != 0 )
        return( TRUE );
    if( ( CurrProc->state.attr & ROUTINE_NEEDS_PROLOG ) != 0 )
        return( TRUE );
    if( FAR_RET_ON_STACK ) {
        if( CHAIN_FRAME )
            return( TRUE );
    }
    return( FALSE );
}


static void FindIfExported( void ) {
/****************************/

    sym_handle  sym;

    sym = AskForLblSym( CurrProc->label );
    if( sym == NULL )

⌨️ 快捷键说明

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