mipsfmt.c

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

C
1,508
字号
}
#endif


static unsigned loadConst32( uint_32 *buffer, uint_8 d_reg, uint_8 s_reg, ins_operand *op, op_const c, asm_reloc *reloc, bool force_pair )
//****************************************************************************************************************************************
// load sequence for 32-bit constants
// Given: la $d_reg, foobar+c($s_reg)
//        info for foobar is stored in op
//        c should be passed in also
// Returns # of ins generated
{
    unsigned            ret = 1;
    int_16              low, high;

    if( force_pair ) {
        assert( reloc != NULL );
        if( op->reloc.type != ASM_RELOC_UNSPECIFIED ) {
            Error( INVALID_RELOC_MODIFIER );
            return( ret );
        }
    }
    low  = c & 0xffff;
    high = (c & 0xffff0000) >> 16;

    if( !force_pair && (c < 32768) && ((int_32)c > -32769) ) {
        // Only need sign extended low 16 bits - 'addiu rt,$zero,value'
        doOpcodeIType( buffer, OPCODE_ADDIU, d_reg, MIPS_ZERO_SINK, low );
        doReloc( reloc, op, OWL_RELOC_HALF_LO, buffer );
    } else if( !force_pair && !high ) {
        // Only need high 16 bits - 'lui rt,$zero,(value >> 16)'
        doOpcodeIType( buffer, OPCODE_LUI, d_reg, MIPS_ZERO_SINK, high );
        doReloc( reloc, op, OWL_RELOC_HALF_HI, buffer );
    } else {
        // Need two instructions: 'lui rt,$zero,(value >> 16)'
        doOpcodeIType( buffer, OPCODE_LUI, d_reg, MIPS_ZERO_SINK, high );
        doReloc( reloc, op, OWL_RELOC_HALF_HI, buffer );
        ++buffer;
        // followed by 'ori rt,rt,(value & 0xffff)'
        // or 'addiu' for the 'la' pseudo-ins
        if( force_pair )
            doOpcodeIType( buffer, OPCODE_ADDIU, d_reg, d_reg, low );
        else
            doOpcodeIType( buffer, OPCODE_ORI, d_reg, d_reg, low );
        doReloc( reloc, op, OWL_RELOC_HALF_LO, buffer );
        ++ret;
    }
    return( ret );
}


static unsigned load32BitLiteral( uint_32 *buffer, ins_operand *op0, ins_operand *op1, domov_option m_opt )
//*********************************************************************************************************
{
    op_const        val;

    if( m_opt == DOMOV_ABS ) {
        val = abs( op0->constant );
    } else {
        val = op0->constant;
    }
    return( loadConst32( buffer, RegIndex( op1->reg ), MIPS_ZERO_SINK,
                         op0, val, NULL, FALSE ) );
}


static void doMov( uint_32 *buffer, ins_operand *operands[], domov_option m_opt )
//*******************************************************************************
{
    ins_operand     *op0, *op1;
    uint_32         extra;
    uint_32         abs_val;
    bool            ready = TRUE;

    op0 = operands[0];
    op1 = operands[1];
    if( op0->type == OP_GPR ) {
        extra = _Rt( RegIndex( op0->reg ) );
    } else if( ( op0->constant & 0xff ) == op0->constant ) { // OP_IMMED implied
        extra = _LIT( op0->constant ); // this lit is between 0..255
        (void)ensureOpAbsolute( op0, 0 );
    } else if( m_opt == DOMOV_ABS &&
               ( ( ( abs_val = abs( op0->constant ) ) & 0xff ) == abs_val ) ) {
        extra = _LIT( abs_val ); // this lit is between 0..255
        // ensureOpAbsolute( op0, 0 );  should be done before calling doMov
    } else {
        ready = FALSE;
    }
    if( ready ) {
        doOpcodeFcRsRt( buffer, OPCODE_BIS, FUNCCODE_BIS,
                        MIPS_ZERO_SINK, RegIndex( op1->reg ), extra );
        return;
    }
    // Otherwise it's OP_IMMED with a greater than 8-bit literal.
    // We'll then use multiple LDA, LDAH instructions to load the literal.
    if( !ensureOpAbsolute( op0, 0 ) ) return;
    numExtendedIns += load32BitLiteral( buffer, op0, op1, m_opt ) - 1;
}


static void doLoadImm( uint_32 *buffer, ins_operand *operands[] )
//***************************************************************
// 'li' pseudo-ins
{
    ins_operand     *op0, *op1;
    int_32          value;
    uint_32         reg;

    op0 = operands[0];
    op1 = operands[1];
    ensureOpAbsolute( op1, 1 );
    reg = RegIndex( op0->reg );
    value = op1->constant;

    if( (value < 32768) && (value > -32769) ) {
        // Only need sign extended low 16 bits - 'addiu rt,$zero,value'
        doOpcodeIType( buffer, OPCODE_ADDIU, reg, MIPS_ZERO_SINK,
            (unsigned_16)value );
    } else if( (value & 0xffff == 0) ) {
        // Only need high 16 bits - 'lui rt,$zero,(value >> 16)'
        doOpcodeIType( buffer, OPCODE_LUI, reg, MIPS_ZERO_SINK,
            (unsigned_16)(value >> 16) );
    } else {
        // Need two instructions: 'lui rt,$zero,(value >> 16)'
        doOpcodeIType( buffer, OPCODE_LUI, reg, MIPS_ZERO_SINK,
            (unsigned_16)(value >> 16) );
        // followed by 'ori rt,$zero,(value & 0xffff)'
        ++buffer;
        doOpcodeIType( buffer, OPCODE_ORI, reg, MIPS_ZERO_SINK,
            (unsigned_16)value );
        ++numExtendedIns;
    }
}


static void ITSysCode( ins_table *table, instruction *ins, uint_32 *buffer, asm_reloc *reloc )
//********************************************************************************************
{
    ins_operand     *op;
    op_const        constant;

    assert( ins->num_operands < 2 );
    reloc = reloc;
    if( ins->num_operands > 0 ) {
        op = ins->operands[0];
        ensureOpAbsolute( op, 0 );
        constant = op->constant;
    } else {
        constant = 0;
    }
    *buffer = _Opcode( table->opcode ) | _Code( constant ) | _Op_Func( table->funccode );
}


static void ITTrap( ins_table *table, instruction *ins, uint_32 *buffer, asm_reloc *reloc )
//*****************************************************************************************
{
    ins_operand     *op;
    op_const        code;

    reloc = reloc;
    if( ins->num_operands > 2 ) {
        op = ins->operands[2];
        ensureOpAbsolute( op, 2 );
        code = op->constant;
    } else {
        code = 0;
    }
    *buffer = _Opcode( table->opcode ) |
              _Rs( RegIndex( ins->operands[0]->reg ) ) |
              _Rt( RegIndex( ins->operands[1]->reg ) ) |
              _TrapCode( code ) | _Op_Func( table->funccode );
}


static void ITLoadUImm( ins_table *table, instruction *ins, uint_32 *buffer, asm_reloc *reloc )
//*********************************************************************************************
{
    ins_operand     *op;

    reloc = reloc;
    assert( ins->num_operands == 2 );
    op = ins->operands[1];
    ensureOpAbsolute( op, 1 );
    doOpcodeIType( buffer, table->opcode, RegIndex( ins->operands[0]->reg ),
                   0, op->constant );
}


static void ITTrapImm( ins_table *table, instruction *ins, uint_32 *buffer, asm_reloc *reloc )
//********************************************************************************************
{
    ins_operand     *op;

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


static void ITMemAll( ins_table *table, instruction *ins, uint_32 *buffer, asm_reloc *reloc )
//*******************************************************************************************
{
    ins_operand     *op;
    owl_reloc_type  type;
    ins_opcode      opcode;

    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 );
#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
    opcode = table->opcode;
    doOpcodeRsRt( buffer, opcode, RegIndex( op->reg ),
            RegIndex( ins->operands[0]->reg ), _Memory_disp( op->constant ) );
    type = ( opcode == OPCODE_LDAH ) ? OWL_RELOC_HALF_HI : OWL_RELOC_HALF_LO;
    doReloc( reloc, op, type, buffer );
}


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


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


static void doMemJump( uint_32 *buffer, ins_table *table, uint_8 ra, uint_8 rb, ins_operand *addr_op, uint_32 hint, asm_reloc *reloc )
//************************************************************************************************************************************
{
    // Note that addr_op maybe NULL. If not, addr_op->constant == hint.
    assert( addr_op == NULL || addr_op->constant == hint );
    assert( addr_op == NULL || addr_op->type == OP_IMMED );
    doOpcodeRsRt( buffer, table->opcode, ra, rb,
                  (table->funccode << 14) | _FourteenBits(hint) );
    doReloc( reloc, addr_op, OWL_RELOC_JUMP_REL, buffer );
}


static int doDelaySlotNOP( uint_32 *buffer )
//******************************************
{
    int     inc = 0;

    if( _DirIsSet( REORDER ) ) {
        buffer += sizeof( uint_32 );
        *buffer = OPCODE_NOP;
        inc = 1;
    }
    return( inc );
}


static void doAbsJump( uint_32 *buffer, ins_table *table, ins_operand *addr_op, asm_reloc *reloc )
//************************************************************************************************
{
    assert( addr_op == NULL || addr_op->type == OP_IMMED );
    doOpcodeJType( buffer, table->opcode );
    doReloc( reloc, addr_op, OWL_RELOC_JUMP_ABS, buffer );
}


static void opError( instruction *ins, op_type actual, op_type wanted, int i )
//****************************************************************************
// Stuff out an error message.
{
    ins = ins;
    actual = actual;
    wanted = wanted;    // it's a set of flags
    if( ( wanted & OP_NOTHING ) != OP_NOTHING ) {
        Error( OPERAND_INCORRECT, i );
    } else {
        Error( OPERAND_UNEXPECTED, i );
    }
}


static bool opValidate( ot_array *verify, instruction *ins, ins_opcount num_op, unsigned num_var )
//************************************************************************************************
{
    int             ctr, var, lasterr;
    op_type         actual, wanted;

    for( var = 0; var < num_var; var++ ) {
        lasterr = -1;
        for( ctr = 0; ctr < num_op; ctr++ ) {
            if( ins->operands[ctr]->type != (*verify)[var][ctr] ) {
                lasterr = ctr;
                actual = ins->operands[ctr]->type;
                wanted = (*verify)[var][ctr];
                break;
            }
        }
        if( lasterr == -1 ) {   // passed
            break;
        }
    }
    if( lasterr != -1 ) {
        opError( ins, actual, wanted, lasterr );
        return( FALSE );
    }
    return( TRUE );
}


static bool jmpOperandsValidate( instruction *ins, ins_opcount num_op, bool link )
//********************************************************************************
// Used by j, jal
{
    static op_type  verify1[][3] = { { OP_REG_INDIRECT, OP_NOTHING, OP_NOTHING },
                                     { OP_GPR, OP_NOTHING, OP_NOTHING },
                                     { OP_IMMED, OP_NOTHING, OP_NOTHING } };
    static op_type  verify2[][3] = { { OP_GPR, OP_REG_INDIRECT, OP_NOTHING },
                                     { OP_GPR, OP_GPR, OP_NOTHING },
                                     { OP_GPR, OP_IMMED, OP_NOTHING }};
    ot_array        *verify;
    ot_array        *verify_table[2] = { &verify1, &verify2 };
    unsigned        num_var;

    if( num_op == 0 )
        return( FALSE );
    assert( num_op <= 2 );
    verify = verify_table[num_op - 1];
    if( num_op == 1 ) {
        num_var = sizeof( verify1 ) / sizeof( **verify1 ) / 3;
    } else {
        if( !link ) // two-operand from only valid for 'jal', not 'j'
            return( FALSE );
        num_var = sizeof( verify2 ) / sizeof( **verify2 ) / 3;
    }
    assert( num_var <= MAX_VARIETIES );
    return( opValidate( verify, ins, num_op, num_var ) );
}


static void stdMemJump( ins_table *table, instruction *ins, uint_32 *buffer, asm_reloc *reloc )
//*********************************************************************************************
{
    ins_operand *op1, *op2;

    op1 = ins->operands[1];
    if( op1->constant != 0 ) {
        Error( IMPROPER_OPERAND, 1 );
        return;
    }
    op2 = ins->operands[2];
    doMemJump( buffer, table, RegIndex( ins->operands[0]->reg ),

⌨️ 快捷键说明

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