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