alphafmt.c

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

C
1,226
字号
/****************************************************************************
*
*                            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:  Alpha AXP instruction formats and encodings.
*
****************************************************************************/


#include "as.h"
#ifndef _STANDALONE_
#include "asinline.h"
#endif

typedef struct reloc_entry      *reloc_list;

struct reloc_entry {
    reloc_list          next;
    op_reloc_target     target;
    owl_reloc_type      type;
    unsigned            loc;            // offset of the reloc from &result[0].
    bool                is_named;       // does it have a corr. named symbol
};

typedef struct asm_reloc {
    reloc_list          first;
    reloc_list          last;
} asm_reloc;

typedef void (*fmt_func)( ins_table *, instruction *, uint_32 *, asm_reloc * );

typedef struct {
    fmt_func    func;
    op_type     ops[ MAX_OPERANDS ];
} alpha_format;

typedef enum {
    DOMOV_ORIGINAL,
    DOMOV_ABS,
} domov_option;

#define MAX_VARIETIES   3
typedef op_type ot_array[MAX_VARIETIES][3];

#define _FiveBits( x )          ( (x) & 0x001f )
#define _SixBits( x )           ( (x) & 0x003f )
#define _SevenBits( x )         ( (x) & 0x007f )
#define _EightBits( x )         ( (x) & 0x00ff )
#define _ElevenBits( x )        ( (x) & 0x07ff )
#define _FourteenBits( x )      ( (x) & 0x3fff )
#define _SixteenBits( x )       ( (x) & 0xffff )
#define _TwentyOneBits( x )     ( (x) & 0x001fffff )

#define _LIT_value( x )         ( _EightBits( x )     << 1  )
#define _LIT_bit                1
#define _LIT_unshifted( x )     ( _LIT_value( x ) | _LIT_bit )

#define _Opcode( x )            ( _SixBits( x )       << 26 )
#define _Ra( x )                ( _FiveBits( x )      << 21 )
#define _Rb( x )                ( _FiveBits( x )      << 16 )
#define _Rc( x )                ( _FiveBits( x )      << 0  )
#define _Memory_disp( x )       ( _SixteenBits( x )   << 0  )
#define _Mem_Func( x )          ( _SixteenBits( x )   << 0  )
#define _Branch_disp( x )       ( _TwentyOneBits( x ) << 0  )
#define _Op_Func( x )           ( _SevenBits( x )     << 5  )
#define _FP_Op_Func( x )        ( _ElevenBits( x )    << 5  )
#define _LIT( x )               ( _LIT_unshifted( x ) << 12 )

#define _Longword_offset( x )   ( (x) >> 2 )

#define MAX_EXTENDED_INS        20  // Including the default buffer, we have
                                    // 21 dwords for an ins that emits multiple
                                    // instructions. (eg. ldb)

#define RA_REG_IDX              26
#define SP_REG_IDX              30
#define FP_REG_IDX              15
#define ZERO_REG_IDX            31
// Check if ".set noat" is in effect before using this
#define AT_REG_IDX              RegIndex( AT_REG )

#define ZERO_REG                MakeReg( RC_GPR, ZERO_REG_IDX )

#define OPCODE_BIS      0x11
#define FUNCCODE_BIS    0x0020
#define OPCODE_LDA      0x8
#define OPCODE_LDAH     0x9

#define OP_HAS_RELOC( op )      ((op)->flags & (RELOC | UNNAMED_RELOC))
#define OP_RELOC_NAMED( op )    ((op)->flags & RELOC)

static unsigned numExtendedIns = 0;  // >= 1 when we use extendedIns
static uint_32 result[ MAX_EXTENDED_INS + 1 ];

static owl_reloc_type reloc_translate[] = {
    OWL_RELOC_ABSOLUTE,     // Corresponds to ASM_RELOC_UNSPECIFIED
    OWL_RELOC_WORD,
    OWL_RELOC_HALF_HI,
    OWL_RELOC_HALF_HA,
    OWL_RELOC_HALF_LO,
    OWL_RELOC_BRANCH_REL,   // j^ reloc
    OWL_RELOC_JUMP_REL,     // jump hint
};

static bool ensureOpAbsolute( ins_operand *op, uint_8 opIdx ) {
//*************************************************************

    if( OP_HAS_RELOC( op ) ) {
        Error( RELOC_NOT_ALLOWED, opIdx );
        return( FALSE );
    }
    return( TRUE );
}

static void addReloc( asm_reloc *reloc, op_reloc_target target, owl_reloc_type type, unsigned loc, bool is_named ) {
//******************************************************************************************************************

    reloc_list  new_entry;

    new_entry = MemAlloc( sizeof( struct reloc_entry ) );
    new_entry->next = NULL;
    new_entry->target = target;
    new_entry->type = type;
    new_entry->loc = loc;
    new_entry->target = target;
    new_entry->is_named = is_named;
    if( reloc->first == NULL ) {
        reloc->first = new_entry;
    } else {
        reloc->last->next = new_entry;
    }
    reloc->last = new_entry;
}

static owl_reloc_type relocType( asm_reloc_type type, owl_reloc_type default_type ) {
//***********************************************************************************

    owl_reloc_type  ret;

    if( type == ASM_RELOC_UNSPECIFIED ) {
        return( default_type );
    }
    switch( default_type ) {
    case OWL_RELOC_HALF_HI:
    case OWL_RELOC_HALF_LO:
        if( ( ret = reloc_translate[type] ) != OWL_RELOC_HALF_HI &&
            ret != OWL_RELOC_HALF_LO ) {
            Error( INVALID_RELOC_MODIFIER );
        }
        break;
    case OWL_RELOC_BRANCH_REL:  // j^ reloc
        if( ( ret = reloc_translate[type] ) != default_type ) {
            Error( INVALID_RELOC_MODIFIER );
        }
        break;
    case OWL_RELOC_JUMP_REL:    // jump hint
        // we accept j^ to be specified for jump hint for now.
        if( ( ret = reloc_translate[type] ) != OWL_RELOC_JUMP_REL &&
            ret != OWL_RELOC_BRANCH_REL ) {
            Error( INVALID_RELOC_MODIFIER );
        }
        ret = OWL_RELOC_JUMP_REL;
        break;
    default:
        //Error( "internal - unexpected default type" );
        assert( FALSE );
        ret = OWL_RELOC_ABSOLUTE;
    }
    return( ret );
}

static void doReloc( asm_reloc *reloc, ins_operand *op, owl_reloc_type rtype, uint_32 *offset ) {
//***********************************************************************************************

    if( op == NULL ) return;
    if( !( OP_HAS_RELOC( op ) ) ) return;
    addReloc( reloc, op->reloc.target, relocType( op->reloc.type, rtype ),
              (unsigned)offset - (unsigned)result, ( op->flags & RELOC ) );
}

/*
    IT_OPERATE:
        QF_V..........+0x40
    IT_FP_xxxx:
        QF_S..........+0x400
        QF_U..........+0x100
        QF_V..........+0x100
        QF_I..........+0x200
        QF_C..........-0x080
        QF_M..........-0x040
        QF_D..........+0x040
*/
static ins_funccode getFuncCode( ins_table *table, instruction *ins ) {
//*********************************************************************

    ins_funccode fc;

    fc = table->funccode;
    switch( table->template ) {
    case IT_OPERATE:
    case IT_PSEUDO_NOT:
        if( ins->format->flags & QF_V ) {
            fc += 0x40;
        } else {
            assert( ins->format->flags == 0 ); // No other valid flags
        }
        break;
    case IT_FP_OPERATE:
    case IT_FP_CONVERT:
    case IT_PSEUDO_NEGF:
        if( ins->format->flags & QF_S ) fc += 0x400;
        if( ins->format->flags & QF_U ) fc += 0x100;
        if( ins->format->flags & QF_V ) fc += 0x100;
        if( ins->format->flags & QF_I ) fc += 0x200;
        if( ins->format->flags & QF_C ) fc -= 0x080;
        if( ins->format->flags & QF_M ) fc -= 0x040;
        if( ins->format->flags & QF_D ) fc += 0x040;
        break;
    default:
        assert( FALSE ); // Others should have no need to call this.
    }
    return( fc );
}

static void doOpcodeRaRb( uint_32 *buffer, ins_opcode opcode, uint_8 ra, uint_8 rb, uint_32 remain ) {
//****************************************************************************************************

    *buffer = _Opcode( opcode ) | _Ra( ra ) | _Rb( rb ) | remain;
}

static void doOpcodeFcRaRc( uint_32 *buffer, ins_opcode opcode, ins_funccode fc, uint_8 ra, uint_8 rc, uint_32 extra ) {
//**********************************************************************************************************************
// This procedure doesn't fill in all the bits (missing bits 20-12).
// But we can fill it in using extra.

    *buffer = _Opcode( opcode ) | _Op_Func( fc ) | _Ra( ra ) | _Rc( rc ) |
              extra;
}

static void doFPInst( uint_32 *buffer, ins_opcode opcode, uint_8 ra, uint_8 rb, uint_8 rc, uint_32 remain ) {
//***********************************************************************************************************

    *buffer = _Opcode( opcode ) | _Ra( ra ) | _Rb( rb ) |
              _FP_Op_Func( remain ) | _Rc( rc );
}

#ifndef _STANDALONE_
static void doAutoVar( asm_reloc *reloc, op_reloc_target targ, uint_32 *buffer, ins_table *table, instruction *ins ) {
//********************************************************************************************************************

    ins_operand *op;

    op = ins->operands[1];
    if( op->reg != ZERO_REG ) {
        Error( BAD_BASE_REG_FOR_STACKVAR );
        return;
    }
    addReloc( reloc, targ, OWL_RELOC_FP_OFFSET, (unsigned)buffer - (unsigned)&result[ 0 ], TRUE );
    doOpcodeRaRb( buffer, table->opcode, RegIndex( ins->operands[0]->reg ),
                  FP_REG_IDX, 0 );
}
#endif

static unsigned ldaConst32( uint_32 *buffer, uint_8 d_reg, uint_8 s_reg, ins_operand *op, op_const c, asm_reloc *reloc, bool force_pair ) {
//*****************************************************************************************************************************************
// LDA-LDAH sequence for 32-bit constants
// Given: lda $d_reg, foobar+c($s_reg)
//        info for foobar is stored in op
//        c should be passed in also
// Returns # of ins generated

    int_32              tmp;
    int                 ctr;
    unsigned            ret = 1;
    int_16              low, high[2];
    uint_8              base_reg;
    owl_reloc_type      type;
    bool                hi_reloc_emitted = FALSE;

    if( force_pair ) {
        assert( reloc != NULL );
        if( op->reloc.type != ASM_RELOC_UNSPECIFIED ) {
            Error( INVALID_RELOC_MODIFIER );
            return( ret );
        }

⌨️ 快捷键说明

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