mipsfmt.c

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

C
1,508
字号
//*********************************************************************************************
{
    assert( ins->num_operands == 1 || ins->num_operands == 3 );
    if( ins->num_operands == 1 ) {
        uint_8          reg_num;

        reg_num = RegIndex( ins->operands[0]->reg );
        doFPInst( buffer, table->opcode, reg_num, reg_num, reg_num,
                  table->funccode );
        return;
    }
    ITFPOperate( table, ins, buffer, reloc );
}


static void ITPseudoClr( ins_table *table, instruction *ins, uint_32 *buffer, asm_reloc *reloc )
//**********************************************************************************************
{
    assert( ins->num_operands == 1 );
    reloc = reloc;
    doOpcodeFcRsRt( buffer, table->opcode, table->funccode, 31,
                    RegIndex( ins->operands[0]->reg ), _Rd( 31 ) );
}


static void ITPseudoFclr( ins_table *table, instruction *ins, uint_32 *buffer, asm_reloc *reloc )
//***********************************************************************************************
{
    assert( ins->num_operands == 1 );
    reloc = reloc;
    doFPInst( buffer, table->opcode, 31, 31,
              RegIndex( ins->operands[0]->reg ), table->funccode );
}


static void ITPseudoLImm( ins_table *table, instruction *ins, uint_32 *buffer, asm_reloc *reloc )
//***********************************************************************************************
{
    assert( ins->num_operands == 2 );
    table = table;
    reloc = reloc;
    doLoadImm( buffer, ins->operands );
}


static void ITPseudoLAddr( ins_table *table, instruction *ins, uint_32 *buffer, asm_reloc *reloc )
//************************************************************************************************
{
    ins_operand         *op;
    ins_operand         *ops[2];
    unsigned            inc;
    op_const            val;
    uint_8              s_reg;

    assert( ins->num_operands == 2 );
    op = ins->operands[1];
    // If op is IMMED foo, it's actually REG_INDIRECT that we want: foo($zero)
    if( op->type == OP_IMMED ) {
        op->type = OP_REG_INDIRECT;
        op->reg = ZERO_REG;
    }
    assert( op->type == OP_REG_INDIRECT );
    val = op->constant;
    s_reg = RegIndex( op->reg );
    if( !OP_HAS_RELOC( op ) && s_reg == MIPS_ZERO_SINK ) {
        // doMov() can only be called when op->reg is ZERO_REG and no reloc
        ops[0] = op;
        ops[1] = ins->operands[0];
        doMov( buffer, ops, DOMOV_ORIGINAL );
        return;
    }
    if( OP_HAS_RELOC( op ) ) {
#ifndef _STANDALONE_
        if( OP_RELOC_NAMED( op ) ) {
            char        *name;

            name = SymName( op->reloc.target.ptr );
            if( AsmQueryExternal( name ) == SYM_STACK ) {
                doAutoVar( reloc, op->reloc.target, buffer, table, ins );
                return;
            }
        }
#endif
        if( op->reloc.type == ASM_RELOC_UNSPECIFIED ) {
            // We should emit lui/addiu pair.
            inc = loadConst32( buffer, RegIndex( ins->operands[0]->reg ),
                               s_reg, op, op->constant, reloc, TRUE );
            numExtendedIns += inc - 1;
            return;
        }
    }
    inc = loadConst32( buffer, RegIndex( ins->operands[0]->reg ), s_reg, op,
                       op->constant, reloc, FALSE );
    numExtendedIns += inc - 1;
}


static void ITPseudoMov( ins_table *table, instruction *ins, uint_32 *buffer, asm_reloc *reloc )
//**********************************************************************************************
{
    assert( ins->num_operands == 2 );
    reloc = reloc;

    doOpcodeRType( buffer, 0, FNCCODE_OR, RegIndex( ins->operands[0]->reg ),
        RegIndex( ins->operands[1]->reg ), MIPS_ZERO_SINK );
}


static void ITPseudoFmov( ins_table *table, instruction *ins, uint_32 *buffer, asm_reloc *reloc )
//***********************************************************************************************
{
    uint_8          reg_idx0;

    assert( ins->num_operands == 2 );
    reloc = reloc;
    reg_idx0 = RegIndex( ins->operands[0]->reg );
    doFPInst( buffer, table->opcode, reg_idx0, reg_idx0,
              RegIndex( ins->operands[1]->reg ), table->funccode );
}


static void ITPseudoNot( ins_table *table, instruction *ins, uint_32 *buffer, asm_reloc *reloc )
//**********************************************************************************************
{
    ins_funccode    fc;
    ins_operand     *op;
    uint_32         extra;

    assert( ins->num_operands == 2 );
    reloc = reloc;

    op = ins->operands[0];
    if( op->type == OP_GPR ) {
        extra = _Rt( RegIndex( op->reg ) );
    } else {    // OP_IMMED
        assert( op->type == OP_IMMED );
        extra = _LIT( op->constant );
        (void)ensureOpAbsolute( op, 0 );
    }
    fc = getFuncCode( table, ins );
    doOpcodeFcRsRt( buffer, table->opcode, fc, 31,
                    RegIndex( ins->operands[1]->reg ), extra );
}


static void ITPseudoNegf( ins_table *table, instruction *ins, uint_32 *buffer, asm_reloc *reloc )
//***********************************************************************************************
{
    ins_funccode    fc;

    assert( ins->num_operands == 2 );
    reloc = reloc;
    fc = getFuncCode( table, ins );
    doFPInst( buffer, table->opcode, 31, RegIndex( ins->operands[0]->reg ),
              RegIndex( ins->operands[1]->reg ), fc );
}


static void ITPseudoFneg( ins_table *table, instruction *ins, uint_32 *buffer, asm_reloc *reloc )
//***********************************************************************************************
{
    uint_8          reg_idx0;

    assert( ins->num_operands == 2 );
    reloc = reloc;
    reg_idx0 = RegIndex( ins->operands[0]->reg );
    doFPInst( buffer, table->opcode, reg_idx0, reg_idx0,
              RegIndex( ins->operands[1]->reg ), table->funccode );
}


static void ITPseudoAbs( ins_table *table, instruction *ins, uint_32 *buffer, asm_reloc *reloc )
//**********************************************************************************************
{
    uint_8          s_reg_idx, d_reg_idx, rc_reg_idx;
    ins_operand     *src_op;
    bool            same_reg;

    assert( ins->num_operands == 2 );
    reloc = reloc;
    src_op = ins->operands[0];
    if( src_op->type == OP_IMMED ) {
        // Then just evaluate it and do a mov instead.
        // mov  abs(src_op->constant), d_reg
        if( ensureOpAbsolute( src_op, 0 ) ) {
            doMov( buffer, ins->operands, DOMOV_ABS );
        }
        return;
    }
    assert( src_op->type == OP_GPR );
    /* Emit an instruction sequence like:
       1. subq/v  $zero, $s_reg, $at    // if( $s_reg == $d_reg )
       2. cmovlt  $s_reg, $at, $s_reg
       ---or---
       1. subq/v  $zero, $s_reg, $d_reg // if( $s_reg != $d_reg )
       2. cmovgt  $s_reg, $s_reg, $d_reg
    */
    s_reg_idx = RegIndex( src_op->reg );
    d_reg_idx = RegIndex( ins->operands[1]->reg );
    if( same_reg = ( s_reg_idx == d_reg_idx ) ) {
        // Then $at reg will be needed.
        if( !_DirIsSet( AT ) ) {
            Warning( INS_USES_AT_REG );
        }
        rc_reg_idx = AT_REG_IDX;
    } else {
        rc_reg_idx = d_reg_idx;
    }
    doOpcodeFcRsRt( buffer, table->opcode, table->funccode, 31,
                    rc_reg_idx, _Rt( s_reg_idx ) );
    // So buffer gets ins #1. Now do ins #2.
    ++buffer;
#define OPCODE_CMOVGT           0x11
#define OPCODE_CMOVLT           0x11
#define FUNCCODE_CMOVGT         0x0066
#define FUNCCODE_CMOVLT         0x0044
    if( same_reg ) {
        doOpcodeFcRsRt( buffer, OPCODE_CMOVLT,
                        FUNCCODE_CMOVLT, s_reg_idx, s_reg_idx,
                        _Rt( AT_REG_IDX ) );
    } else {
        doOpcodeFcRsRt( buffer, OPCODE_CMOVGT,
                        FUNCCODE_CMOVGT, s_reg_idx, d_reg_idx,
                        _Rt( s_reg_idx ) );
    }
    ++numExtendedIns;
}


mips_format MIPSFormatTable[] = {
    #define PICK( a, b, c, d, e )       { b, { c, d, e } },
    #include "mipsfmt.inc"
    #undef PICK
};


bool MIPSValidate( instruction *ins )
//***********************************
// Make sure that all operands of the given instruction
// are of the type we are expecting. If not, we print
// out an error message.
{
    int                 i;
    mips_format         *fmt;
    ins_operand         *op;

    fmt = &MIPSFormatTable[ins->format->table_entry->template];
    for( i = 0; i < ins->num_operands; i++ ) {
        op = ins->operands[i];
        if( ( op->type & fmt->ops[i] ) != op->type ) {
            opError( ins, op->type, fmt->ops[i], i );
            return( FALSE );
        }
    }
    if( i < MAX_OPERANDS ) {
        if( ( fmt->ops[i] & OP_NOTHING ) != OP_NOTHING ) {
            Error( NOT_ENOUGH_INSOP );
            return( FALSE );
        }
    }   // NOTE: It might not catch all improper operand combinations
        // because we're using flags here
    return( TRUE );
}


#ifdef _STANDALONE_
static void emitIns( owl_section_handle hdl, char *inscode, int size )
//********************************************************************
{
    ObjEmitData( hdl, inscode, size, TRUE );
}
#else
static void emitIns( char *inscode, int size )
//********************************************
{
    ObjEmitData( inscode, size, TRUE );
}
#endif


#ifdef _STANDALONE_
void MIPSEmit( owl_section_handle hdl, instruction *ins )
//*******************************************************
#else
void MIPSEmit( instruction *ins )
//*******************************
#endif
// Encode the given instruction (including emitting any
// relocs to the appropriate places), and emit the code
// to the given section.
{
    int             ctr;
    ins_table       *table;
    asm_reloc       reloc = { NULL, NULL };
    reloc_list      curr_reloc;
#ifdef _STANDALONE_
    uint_8          old_alignment;

    if( OWLTellSectionType( hdl ) & OWL_SEC_ATTR_BSS ) {
        Error( INVALID_BSS_STATEMENT );
        return;
    }
    old_alignment = CurrAlignment;
    if( CurrAlignment < 2 ) { // Instructions should at least be dword aligned
        CurrAlignment = 2;
    }
#endif
    table = ins->format->table_entry;
    MIPSFormatTable[table->template].func( table, ins, result, &reloc );
    for( ctr = 0; ctr <= numExtendedIns; ctr++ ) {
        if( ( curr_reloc = reloc.first ) != NULL ) {
            assert( curr_reloc->loc >= ctr * sizeof( *result ) );
            if( curr_reloc->loc == ctr * sizeof( *result ) ) {
                reloc.first = curr_reloc->next;
                if( curr_reloc->is_named ) {
#ifdef _STANDALONE_
                    ObjEmitReloc( hdl, SymName( curr_reloc->target.ptr ),
                                  curr_reloc->type, TRUE, TRUE );
#else
                    ObjEmitReloc( SymName( curr_reloc->target.ptr ),
                                  curr_reloc->type, TRUE, TRUE );
#endif
                } else {
#ifdef _STANDALONE_
                    ObjEmitReloc( hdl, &curr_reloc->target.label,
                                  curr_reloc->type, TRUE, FALSE );
#else
                    ObjEmitReloc( &curr_reloc->target.label,
                                  curr_reloc->type, TRUE, FALSE );
#endif
                }
#ifndef NDEBUG
                switch( curr_reloc->type ) {
                case OWL_RELOC_WORD:
                    _DBGMSG1( "word" ); break;
                case OWL_RELOC_HALF_LO:
                    _DBGMSG1( "l^" ); break;
                case OWL_RELOC_HALF_HI:
                    _DBGMSG1( "h^" ); break;
                case OWL_RELOC_BRANCH_REL:
                    _DBGMSG1( "j^" ); break;
                case OWL_RELOC_JUMP_REL:
                    _DBGMSG1( "jump hint" ); break;
                default:
                    _DBGMSG1( "absolute (shouldn't use)" ); break;
                }
                _DBGMSG1( " reloc emitted for the instruction.\n" );
#endif
                MemFree( curr_reloc );
            }
        }
#ifdef _STANDALONE_
        emitIns( hdl, (char *)&result[ctr], sizeof( uint_32 ) );
#else
        emitIns( (char *)&result[ctr], sizeof( uint_32 ) );
#endif
#ifndef NDEBUG
    #ifdef _STANDALONE_
        if( _IsOption( DUMP_INSTRUCTIONS ) ) {
            printf( " [%#010x]\n", result[ctr] );
        }
    #endif
#endif
    }
    assert( reloc.first == NULL ); // Should all be emitted already!
    reloc.last = NULL;
    if( numExtendedIns != 0 ) {
        if( !_DirIsSet( MACRO ) ) {
            Warning( MACRO_INSTRUCTION );
        }
        numExtendedIns = 0;
    }
#ifdef _STANDALONE_
    CurrAlignment = old_alignment;
#endif
}

⌨️ 快捷键说明

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