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