i86enc.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 2,335 行 · 第 1/5 页
C
2,335 行
/****************************************************************************
*
* 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: Take the instruction stream from the code generator and
* writes the instructions into the object file.
*
****************************************************************************/
#include <stdio.h>
#include "standard.h"
#include "coderep.h"
#include "opcodes.h"
#include "pattern.h"
#include "ocentry.h"
#include "vergen.h"
#include "pccode.h"
#include "system.h"
#include "escape.h"
#include "model.h"
#include "pcencode.h"
#include "objrep.h"
#include "regset.h"
#include "rttable.h"
#include "rtclass.h"
#include "zoiks.h"
#include "zeropage.h"
#include "fppatch.h"
#include "cfloat.h"
#include "cgaux.h"
#include "feprotos.h"
#include "p5prof.h"
#include "procdef.h"
extern void DoAbsPatch(abspatch_handle*,int);
extern void DoFunnyRef(int);
extern hw_reg_set High32Reg(hw_reg_set);
extern hw_reg_set Low32Reg(hw_reg_set);
extern void DoSegRef(seg_id);
extern hw_reg_set CalcSegment(sym_handle,cg_class);
extern void EmitDbgInfo(instruction*);
extern void DoCall(label_handle,bool,bool,oc_class);
extern void RTCall( rt_class rtn, oc_class pop_bit );
extern label_handle RTLabel(int);
extern void GenMJmp(instruction*);
extern void GenRJmp(instruction*);
extern void GenICall(instruction*);
extern void GenRCall(instruction*);
extern void GenCall(instruction*);
extern abspatch_handle *NextFramePatch( void );
extern bool AskIsFrameIndex(name*);
extern void GenCondJump(instruction*);
extern int NumOperands(instruction*);
extern void InputOC(any_oc*);
extern void DoRepOp( instruction *ins );
extern void Do4CXShift(instruction *,void (*)(instruction*) );
extern void LayLeaOp(instruction*);
extern void LayModRM(name*);
extern byte DoMDisp(name*,bool);
extern void DoMAddr(name*);
extern void DoRelocConst(name*,type_class_def);
extern void Do4Shift(instruction*);
extern void Do4RShift(instruction*);
extern void Gen4RNeg(instruction*);
extern void Gen4Neg(instruction*);
extern void Pow2Div(instruction*);
extern void By2Div(instruction*);
extern void Pow2Div286(instruction*);
extern void LayLeaRegOp(instruction*);
extern pointer Copy(pointer,pointer,uint);
extern void GenUnkLea(pointer);
extern name *IntEquivalent(name*);
extern void LookupRoutine(instruction*);
extern void AdjustStackDepth(instruction*);
extern void AdjustStackDepthDirect(int adjust);
extern hw_reg_set FullReg(hw_reg_set);
extern bool BaseIsSP(name*);
extern type_length TmpLoc(name*,name*);
extern name *DeAlias(name*);
extern seg_id AskBackSeg( void );
extern seg_id AskCodeSeg( void );
extern void DoLblRef(label_handle,seg_id,offset,byte);
extern void AddWData(signed_32,type_class_def );
extern label_handle AskForNewLabel( void );
extern name *LowPart(name *,type_class_def);
extern name *HighPart(name *,type_class_def);
extern void CodeLabel(label_handle, unsigned);
extern int OptInsSize(oc_class,oc_dest_attr);
extern void DoFESymRef(sym_handle,cg_class,offset,int);
extern void GenJumpLabel( label_handle );
extern void GenKillLabel( label_handle );
extern segment_id GenP5ProfileData( char *fe_name, label_handle *data, label_handle *stack );
extern void EndBlockProfiling( void );
extern void LayOpbyte( opcode op );
extern void LayOpword( opcode op );
extern void LayW( type_class_def class );
extern void GenSeg( hw_reg_set regs );
extern void GenLoadDS(void);
extern void LayRMRegOp( name *r );
extern void AddWCons( name *op, type_class_def kind );
extern void LayReg( hw_reg_set r );
extern void GCondFwait(void);
extern void GFldz(void);
extern void AddSData( signed_32 value, type_class_def kind );
extern void GFwait(void);
extern void GCondFwait(void);
extern void GFldM( pointer what );
static void AddSWCons( opcode_defs op, name *opnd, type_class_def class );
static void TransferIns(void);
static void LayST( name *op );
static void LayMF( name *op );
static void AddSCons( name *op, type_class_def kind );
static void LayACRegOp( name *r );
static void LayRegOp( name *r );
static void LaySROp( name *r );
static void SetCC(void);
static void CallMathFunc( instruction *ins );
static void MathFunc( instruction *ins );
static void PopSeg( hw_reg_set reg );
static void PushSeg( hw_reg_set reg );
static void GFld1(void);
static int FPRegTrans( hw_reg_set reg );
extern pccode_def PCCodeTable[];
extern name *FPStatWord;
extern byte OptForSize;
extern bool Used87;
extern proc_def *CurrProc;
template Temp; /* template for oc_entries*/
byte Inst[INSSIZE]; /* template for instructions*/
static int ICur; /* cursor for writing into Inst*/
static int IEsc; /* number of initial bytes that must be*/
/* checked for escapes when copied into Temp*/
int ILen; /* length of object instruction*/
fp_patches FPPatchType;
static hw_reg_set RegTab[] = {
#define REGS 24
HW_D( HW_AL ), HW_D( HW_AX ), HW_D( HW_EAX ),
HW_D( HW_CL ), HW_D( HW_CX ), HW_D( HW_ECX ),
HW_D( HW_DL ), HW_D( HW_DX ), HW_D( HW_EDX ),
HW_D( HW_BL ), HW_D( HW_BX ), HW_D( HW_EBX ),
HW_D( HW_AH ), HW_D( HW_SP ), HW_D( HW_SP ),
HW_D( HW_CH ), HW_D( HW_BP ), HW_D( HW_BP ),
HW_D( HW_DH ), HW_D( HW_SI ), HW_D( HW_ESI ),
HW_D( HW_BH ), HW_D( HW_DI ), HW_D( HW_EDI ) };
static hw_reg_set SegTab[] = {
#define SEGS 6
HW_D( HW_ES ), HW_D( HW_CS ),
HW_D( HW_SS ), HW_D( HW_DS ),
HW_D( HW_FS ), HW_D( HW_GS ) };
static fp_patches SegPatchTab[] = {
FPP_ES, FPP_CS,
FPP_SS, FPP_DS,
FPP_FS, FPP_GS };
hw_reg_set FPRegs[] = {
HW_D( HW_ST0 ),
HW_D( HW_ST1 ),
HW_D( HW_ST2 ),
HW_D( HW_ST3 ),
HW_D( HW_ST4 ),
HW_D( HW_ST5 ),
HW_D( HW_ST6 ),
HW_D( HW_ST7 ) };
/* routines that maintain instruction buffers*/
extern void Format( oc_class class ) {
/*****************************************
Get Temp and Inst ready to accept instructions. Each instruction is
formatted into Inst, transferred into Temp (as an opcode_entry) and
then dumped into the peephole optimizer.
*/
FPPatchType = FPP_NONE;
Temp.oc.class = class;
Temp.oc.objlen = 0;
Temp.oc.reclen = sizeof( oc_header );
ICur = 0;
ILen = 0;
IEsc = 0;
}
extern void ReFormat( oc_class class ) {
/*******************************************
Change the class of Temp
*/
Temp.oc.class = class;
}
extern void AddByte( byte b ) {
/**********************************
Add a byte to Inst[]
*/
b &= 0xff;
if( b == ESC ) {
Inst[ ICur++ ] = ESC;
}
Inst[ ICur++ ] = b;
ILen++;
}
extern void AddToTemp( byte b ) {
/************************************
Add a byte to the end of Temp
*/
if( b == ESC ) {
Temp.data[ Temp.oc.reclen++ - sizeof( oc_header ) ] = ESC;
}
Temp.data[ Temp.oc.reclen++ - sizeof( oc_header ) ] = b;
Temp.oc.objlen++;
}
extern void InsertByte( byte b ) {
/*************************************
Insert a byte into the beginning of Temp. It may not be ESC!
*/
int i;
byte *src;
byte *dst;
i = Temp.oc.reclen - sizeof( oc_header );
dst = &Temp.data[ i ];
src = &Temp.data[ i - 1 ];
while( --i >= 0 ) {
*dst = *src;
--dst;
--src;
}
Temp.data[ 0 ] = b;
Temp.oc.reclen++;
}
extern void EmitByte( byte b ) {
/***********************************
Plop a byte into Inst[]
*/
Inst[ ICur++ ] = b;
}
extern void EmitPtr( pointer p ) {
/*************************************
Plop a pointer into Inst[]
*/
*(pointer *)(Inst+ICur) = p;
ICur += sizeof( pointer );
}
extern void EmitSegId( seg_id seg ) {
/****************************************
Plop a seg_id into Inst[]
*/
*(seg_id *)(Inst+ICur) = seg;
ICur += sizeof( seg_id );
}
extern void EmitOffset( offset i ) {
/***************************************
Plop an "offset" int Inst[] (a machine word)
*/
*(offset *)(Inst+ICur) = i;
ICur += sizeof( offset );
}
extern void EjectInst( void ) {
/**********************************
Dump the current instruction into the peephole optimizer
*/
TransferIns();
ICur = 0;
ILen = 0;
IEsc = 0;
}
static void TransferIns( void ) {
/************************************
Transfer an instruction from Inst[] to Temp
*/
int i;
int j;
i = 0;
j = Temp.oc.reclen - sizeof( oc_header );
while( i < IEsc ) {
if( Inst[ i ] == ESC ) {
Temp.data[ j++ ] = ESC;
Temp.oc.reclen++;
}
Temp.data[ j++ ] = Inst[ i++ ];
}
Copy( &Inst[ i ], &Temp.data[ j ], ICur - i );
Temp.oc.reclen += ICur;
Temp.oc.objlen += ILen;
}
extern void Finalize( void ) {
/*********************************
Invoked by macro _Emit. Spits Temp into the peephole optimizer
*/
EjectInst();
if( FPPatchType != FPP_NONE ) {
DoFunnyRef( FPPatchType );
FPPatchType = FPP_NONE;
}
if( Temp.oc.objlen != 0 ) {
InputOC( (any_oc *)&Temp.oc );
}
}
static void LayInitial( instruction *ins, gentype gen ) {
/************************************************************
Do some really magical jiggery pokery based on "gen" to get the
right opcode int Inst[]. See PCCodeTable if you want, but this is
not for the faint of heart!
*/
int index;
pccode_def *table;
table = PCCodeTable;
for(;;) {
if( gen < table->low_gen ) break;
if( table->width == 0 ) return;
++ table;
}
-- table;
index = 0;
for(;;) {
if( table->opcode_list[ index ] == ins->head.opcode ) break;
if( table->opcode_list[ index ] == OP_NOP ) break;
++ index;
}
index = index * table->width + gen - table->low_gen;
if( table->flags & NEED_WAIT ) {
Used87 = TRUE;
#if !( _TARGET & _TARG_80386 )
if( gen == G_FINIT || !_CPULevel( CPU_286 ) || _IsEmulation() ) {
if( _IsEmulation() ) {
FPPatchType = FPP_NORMAL;
}
LayOpbyte( 0x9b );
_Next;
}
#endif
}
if( table->flags & BYTE_OPCODE ) {
LayOpbyte( table->opcode_table[ index ] );
} else {
LayOpword( table->opcode_table[ index ] );
}
if( table->flags & BYTE_WORD ) {
LayW( ins->type_class );
}
if( table->flags & SIGN_UNSIGN ) {
if( ins->type_class == I1
|| ins->type_class == I2
|| ins->type_class == I4 ) {
if( ins->head.opcode >= OP_MUL && ins->head.opcode <= OP_MOD ) {
Inst[ RMR ] |= B_RMR_MUL_SGN;
} else if( ins->head.opcode == OP_RSHIFT ) {
Inst[ RMR ] |= B_RMR_SHR_SAR;
}
}
}
}
static byte SegTrans( hw_reg_set regs ) {
/********************************************
Return the encoding of a segment register name
*/
int i;
HW_COnlyOn( regs, HW_SEGS );
i = 0;
while( i < SEGS ) {
if( HW_Equal( regs, SegTab[ i ] ) ) break;
i++;
}
if( i >= SEGS ) {
_Zoiks( ZOIKS_032 );
}
return( i );
}
static byte RegTrans( hw_reg_set regs ) {
/********************************************
Return the encoding of a register name
*/
int i;
HW_CTurnOff( regs, HW_SEGS );
i = 0;
while( i < REGS ) {
if( HW_Equal( regs, RegTab[ i ] ) ) break;
i++;
}
if( i >= REGS ) {
_Zoiks( ZOIKS_031 );
}
i = i / 3;
return( i );
}
#if _TARGET & _TARG_80386
static bool NeedOpndSize( instruction *ins ) {
/*************************************************
Do we REALLY, REALLY need the operand size override.
*/
int i;
hw_reg_set result_reg;
hw_reg_set full_reg;
instruction *next;
switch( ins->head.opcode ) {
case OP_MOD:
case OP_DIV:
case OP_RSHIFT:
return( TRUE );
default:
break;
}
if( _OpIsCondition( ins->head.opcode ) ) return( TRUE );
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?