mipsenc.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 1,073 行 · 第 1/3 页
C
1,073 行
/****************************************************************************
*
* 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: MIPS instruction encoding.
*
****************************************************************************/
#include "standard.h"
#include "coderep.h"
#include "opcodes.h"
#include "pattern.h"
#include "symdbg.h"
#include "vergen.h"
#include "ocentry.h"
#include "mipsenc.h"
#include "reloc.h"
#include "offset.h"
#include "optopts.h"
#include "optlbl.h"
#include "zoiks.h"
#include "model.h"
#include "coff.h"
#include "procdef.h"
#include "encode.h"
#include "cgaux.h"
#include "rtclass.h"
#include "feprotos.h"
#include <assert.h>
#include <stdio.h>
extern void DumpInsOnly( instruction * );
extern void DumpString( char * );
extern void DumpPtr( pointer );
extern void DumpInt( int );
extern void DumpNL( void );
extern void DumpGen( struct opcode_entry * );
extern void DumpPtr( void *ptr );
extern void ObjBytes( char *buffer, int size );
extern uint_8 RegTrans( hw_reg_set );
extern pointer AskForSymLabel( pointer, cg_class );
extern name *DeAlias( name * );
extern void TryScrapLabel( code_lbl * );
extern void EmitDbgInfo( instruction * );
extern void ObjEmitSeq( risc_byte_seq * );
extern bool AskIfRTLabel( code_lbl * );
extern void InputOC( any_oc * );
extern opcode_defs FlipOpcode( opcode_defs );
extern void FactorInt32( signed_32 val, signed_16 *, signed_16 *, signed_16 * );
extern label_handle RTLabel( int );
extern type_class_def Unsigned[];
extern type_length TypeClassSize[];
extern proc_def *CurrProc;
#define _NameReg( op ) ( (op)->r.arch_index )
#define _IsSigned( type ) ( Unsigned[type] != type )
#define _BinaryOpcode( a, b ) { { a, b }, { a, b } }
#define _SignedOpcode( a, b, c, d ) { { a, b }, { c, d } }
#define _BinaryImmOpcode( a ) { a, a }
#define _SignedImmOpcode( a, b ) { a, b }
// Our table for opcode values is really a list of pairs of
// primary opcode / function code pairs. There are two entries
// for each opcode in case the sign of the instruction matters;
// for example, for OP_RSHIFT we need to generate either srav or
// srlv. If the sign of the type of the instruction doesn't
// matter, we can just use the _BinaryOpcode macro to create
// identical cases, otherwise we give each pair explicitly.
static uint_8 BinaryOpcodes4[][2][2] = {
_BinaryOpcode( 0x00, 0x21 ), /* OP_ADD */
_BinaryOpcode( 0x00, 0x21 ), /* OP_EXT_ADD */
_BinaryOpcode( 0x00, 0x23 ), /* OP_SUB */
_BinaryOpcode( 0x00, 0x23 ), /* OP_EXT_SUB */
_SignedOpcode( 0x00, 0x19, 0x00, 0x18 ), /* OP_MUL */
_SignedOpcode( 0x00, 0x19, 0x00, 0x18 ), /* OP_EXT_MUL */
_SignedOpcode( 0x00, 0x1b, 0x00, 0x1a ), /* OP_DIV */
_SignedOpcode( 0x00, 0x1b, 0x00, 0x1a ), /* OP_MOD */
_BinaryOpcode( 0x00, 0x24 ), /* OP_AND */
_BinaryOpcode( 0x00, 0x25 ), /* OP_OR */
_BinaryOpcode( 0x00, 0x26 ), /* OP_XOR */
_SignedOpcode( 0x00, 0x06, 0x00, 0x07 ), /* OP_RSHIFT */
_BinaryOpcode( 0x00, 0x04 ), /* OP_LSHIFT */
_BinaryOpcode( 0x00, 0x00 ), /* OP_POW */
_BinaryOpcode( 0x00, 0x00 ), /* OP_ATAN2 */
_BinaryOpcode( 0x00, 0x00 ), /* OP_FMOD */
};
static uint_8 BinaryOpcodes8[][2][2] = {
_BinaryOpcode( 0x00, 0x21 ), /* OP_ADD */
_BinaryOpcode( 0x00, 0x21 ), /* OP_EXT_ADD */
_BinaryOpcode( 0x00, 0x23 ), /* OP_SUB */
_BinaryOpcode( 0x00, 0x23 ), /* OP_EXT_SUB */
_SignedOpcode( 0x00, 0x19, 0x00, 0x18 ), /* OP_MUL */
_SignedOpcode( 0x00, 0x19, 0x00, 0x18 ), /* OP_EXT_MUL */
_BinaryOpcode( 0x00, 0x00 ), /* OP_DIV */
_BinaryOpcode( 0x00, 0x00 ), /* OP_MOD */
_BinaryOpcode( 0x00, 0x24 ), /* OP_AND */
_BinaryOpcode( 0x00, 0x25 ), /* OP_OR */
_BinaryOpcode( 0x00, 0x26 ), /* OP_XOR */
_SignedOpcode( 0x00, 0x06, 0x00, 0x07 ), /* OP_RSHIFT */
_BinaryOpcode( 0x00, 0x04 ), /* OP_LSHIFT */
_BinaryOpcode( 0x00, 0x00 ), /* OP_POW */
_BinaryOpcode( 0x00, 0x00 ), /* OP_ATAN2 */
_BinaryOpcode( 0x00, 0x00 ), /* OP_FMOD */
};
/* MIPS only has slt/sltu - every other operation needs to be
* reduced to something else.
*/
static uint_8 SetOpcodes[][2][2] = {
_BinaryOpcode( 0x00, 0x00 ), /* OP_SET_EQUAL */
_BinaryOpcode( 0x00, 0x00 ), /* OP_SET_NOT_EQUAL */
_BinaryOpcode( 0x00, 0x00 ), /* OP_SET_GREATER */
_BinaryOpcode( 0x00, 0x00 ), /* OP_SET_LESS_EQUAL */
_SignedOpcode( 0x00, 0x2b, 0x00, 0x2a ), /* OP_SET_LESS */
_BinaryOpcode( 0x00, 0x00 ), /* OP_SET_GREATER_EQUAL */
};
static uint_8 BinaryImmedOpcodes[] = {
0x09, /* OP_ADD */
0x09, /* OP_EXT_ADD */
0x09, /* OP_SUB */
0x09, /* OP_EXT_SUB */
0, /* OP_MUL */
0, /* OP_EXT_MUL */
0, /* OP_DIV */
0, /* OP_MOD */
0x0c, /* OP_AND */
0x0d, /* OP_OR */
0x0e, /* OP_XOR */
0, /* OP_RSHIFT */
0, /* OP_LSHIFT */
0, /* OP_POW */
0, /* OP_ATAN2 */
0, /* OP_FMOD */
};
/* Note - 'reg SET_LESS_EQUAL imm' will be converted to 'reg SET_LESS (imm + 1)'
* inside FindImmedOpcode. That's why the opcodes are the same as for SET_LESS.
*/
static uint_8 SetImmedOpcodes[][2] = {
_BinaryImmOpcode( 0x00 ), /* OP_SET_EQUAL */
_BinaryImmOpcode( 0x00 ), /* OP_SET_NOT_EQUAL */
_BinaryImmOpcode( 0x00 ), /* OP_SET_GREATER */
_SignedImmOpcode( 0x0b, 0x0a ), /* OP_SET_LESS_EQUAL */
_SignedImmOpcode( 0x0b, 0x0a ), /* OP_SET_LESS */
_BinaryImmOpcode( 0x00 ), /* OP_SET_GREATER_EQUAL */
};
// For floating point operate format instructions. We don't need to store
// the primary opcode here since it is always 0x11 (ie. COP1) and we don't
// need the format type since it can be derived from the operand size easily
// enough. Function code is all we need here.
// Note that we are in for some minor discomfort if we need to start
// enabling different trap bits on instructions.
static uint_8 FloatingBinaryOpcodes[] = {
{ 0x00 }, /* OP_ADD */
{ 0x00 }, /* OP_EXT_ADD */
{ 0x01 }, /* OP_SUB */
{ 0x01 }, /* OP_EXT_SUB */
{ 0x02 }, /* OP_MUL */
{ 0x02 }, /* OP_EXT_MUL */
{ 0x03 }, /* OP_DIV */
};
static uint_8 FloatingSetOpcodes[] = {
{ 0x32 }, /* OP_SET_EQUAL */
{ 0x32 }, /* OP_SET_NOT_EQUAL */
{ 0x36 }, /* OP_SET_GREATER */
{ 0x36 }, /* OP_SET_LESS_EQUAL */
{ 0x34 }, /* OP_SET_LESS */
{ 0x34 }, /* OP_SET_GREATER_EQUAL */
};
extern void EmitInsReloc( mips_ins ins, pointer sym, owl_reloc_type type )
/*************************************************************************/
{
oc_riscins oc;
oc.op.objlen = 4;
oc.op.class = OC_RCODE;
oc.op.reclen = sizeof( oc_riscins );
oc.opcode = ins;
oc.sym = sym;
oc.reloc = type;
InputOC( (any_oc *)&oc );
}
static void EmitIns( mips_ins ins )
/**********************************/
{
EmitInsReloc( ins, NULL, 0 );
}
extern void GenLOADS32( signed_32 value, uint_8 reg )
/*****************************************************
* Load a signed 32-bit constant 'value' into register 'reg'
*/
{
if( (value < 32768) && (value > -32769) ) {
// Only need sign extended low 16 bits - 'addiu rt,$zero,value'
GenIType( 0x09, reg, MIPS_ZERO_SINK, (unsigned_16)value );
} else if( (value & 0xffff == 0) ) {
// Only need high 16 bits - 'lui rt,$zero,(value >> 16)'
GenIType( 0x0f, reg, MIPS_ZERO_SINK, (unsigned_16)(value >> 16) );
} else {
// Need two instructions - 'lui rt,$zero,(value >> 16)'
GenIType( 0x0f, reg, MIPS_ZERO_SINK, (unsigned_16)(value >> 16) );
// followed by 'ori rt,$zero,(value & 0xffff)'
GenIType( 0x0d, reg, MIPS_ZERO_SINK, (unsigned_16)value );
}
}
static uint_8 *FindOpcodes( instruction *ins )
/***********************************************
* Look up the opcodes for a binary operator
*/
{
uint_8 *opcodes;
if( _OpIsBinary( ins->head.opcode ) ) {
if( ins->type_class == U8 || ins->type_class == I8 ) {
opcodes = &BinaryOpcodes8[ins->head.opcode - FIRST_BINARY_OP][_IsSigned( ins->type_class )][0];
} else {
opcodes = &BinaryOpcodes4[ins->head.opcode - FIRST_BINARY_OP][_IsSigned( ins->type_class )][0];
}
} else if( _OpIsSet( ins->head.opcode ) ) {
opcodes = &SetOpcodes[ins->head.opcode - FIRST_SET_OP][_IsSigned( ins->type_class )][0];
} else {
assert( 0 );
}
assert( opcodes[0] || opcodes[1] );
return( opcodes );
}
static uint_8 FindImmedOpcode( instruction *ins )
/*************************************************
* Look up the opcode for a binary operator
* where right hand operand is an immediate
*/
{
uint_8 opcode;
if( _OpIsBinary( ins->head.opcode ) ) {
opcode = BinaryImmedOpcodes[ins->head.opcode - FIRST_BINARY_OP];
} else if( _OpIsSet( ins->head.opcode ) ) {
opcode = SetImmedOpcodes[ins->head.opcode - FIRST_SET_OP][_IsSigned( ins->type_class )];
if( ins->head.opcode == OP_SET_LESS_EQUAL ) {
// need to increment the immediate by one (since CPU can do
// 'less than' but not 'less than or equal')
ins->operands[1]->c.int_value++;
assert( ins->operands[1]->c.int_value <= MIPS_MAX_OFFSET );
}
} else {
assert( 0 );
}
assert( opcode );
return( opcode );
}
static uint_8 FindFloatingOpcodes( instruction *ins )
/*****************************************************
* Look up the opcodes for a binary operator with
* floating point operands
*/
{
uint_8 opcode;
assert( _IsFloating( ins->type_class ) );
if( _OpIsBinary( ins->head.opcode ) ) {
opcode = FloatingBinaryOpcodes[ins->head.opcode - FIRST_BINARY_OP];
/* NB: this opcode may legitimately be zero - that's 'add' */
} else if( _OpIsSet( ins->head.opcode ) ) {
opcode = FloatingSetOpcodes[ins->head.opcode - FIRST_SET_OP];
assert( opcode );
} else {
assert( 0 );
}
return( opcode );
}
extern void GenMEMINSRELOC( uint_8 opcode, uint_8 rt, uint_8 rs, signed_16 displacement, pointer lbl, owl_reloc_type type )
/**************************************************************************************************************************/
{
mips_ins encoding;
encoding = _Opcode( opcode ) | _Rt( rt ) | _Rs( rs ) | _SignedImmed( displacement );
EmitInsReloc( encoding, lbl, type );
}
extern void GenMEMINS( uint_8 opcode, uint_8 a, uint_8 b, signed_16 displacement )
/*********************************************************************************/
{
mips_ins encoding;
encoding = _Opcode( opcode ) | _Rt( a ) | _Rs( b ) | _SignedImmed( displacement );
EmitIns( encoding );
}
extern void GenIType( uint_8 opcode, uint_8 rt, uint_8 rs, signed_16 immed )
/***************************************************************************/
{
mips_ins encoding;
encoding = _Opcode( opcode ) | _Rs( rs ) | _Rt( rt ) | _Immed( immed );
EmitIns( encoding );
}
extern void GenRType( uint_8 opcode, uint_8 fc, uint_8 rd, uint_8 rs, uint_8 rt )
/********************************************************************************/
{
mips_ins encoding;
encoding = _Opcode( opcode ) | _Rs( rs ) | _Rt( rt ) | _Rd( rd ) | _Function( fc );
EmitIns( encoding );
}
extern void GenIShift( uint_8 fc, uint_8 rd, uint_8 rt, uint_8 sa )
/******************************************************************/
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?