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