nkeynes@1006: /** nkeynes@1006: * $Id: xir.h 931 2008-10-31 02:57:59Z nkeynes $ nkeynes@1006: * nkeynes@1006: * This file provides support functions for the translation IR. nkeynes@1006: * nkeynes@1006: * Copyright (c) 2009 Nathan Keynes. nkeynes@1006: * nkeynes@1006: * This program is free software; you can redistribute it and/or modify nkeynes@1006: * it under the terms of the GNU General Public License as published by nkeynes@1006: * the Free Software Foundation; either version 2 of the License, or nkeynes@1006: * (at your option) any later version. nkeynes@1006: * nkeynes@1006: * This program is distributed in the hope that it will be useful, nkeynes@1006: * but WITHOUT ANY WARRANTY; without even the implied warranty of nkeynes@1006: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nkeynes@1006: * GNU General Public License for more details. nkeynes@1006: */ nkeynes@1006: nkeynes@1006: #include nkeynes@1006: #include nkeynes@1006: #include nkeynes@1006: #include "xlat/xir.h" nkeynes@1006: nkeynes@1006: static const char **xir_source_register_names = NULL; nkeynes@1006: static const char **xir_target_register_names = NULL; nkeynes@1006: static const struct xir_symbol_entry *xir_symbol_table = NULL; nkeynes@1006: nkeynes@1006: static const char *XIR_CC_NAMES[] = { nkeynes@1006: "ov", "no", "uge", "ult", "ule", "ugt", "eq", "ne", nkeynes@1006: "neg", "pos", "sge", "slt", "sle", "sgt" }; nkeynes@1006: static const int XIR_OPERAND_SIZE[] = { 4, 8, 4, 8, 16, 64, 0, 0 }; nkeynes@1006: nkeynes@1006: const struct xir_opcode_entry XIR_OPCODE_TABLE[] = { nkeynes@1006: { "NOP", OPM_NO }, nkeynes@1006: { "BARRIER", OPM_NO | OPM_CLB }, nkeynes@1006: { "DEC", OPM_RW_TW }, nkeynes@1006: { "LD", OPM_R | OPM_TW }, nkeynes@1006: { "ST", OPM_W | OPM_TR }, nkeynes@1006: { "RESTFLAGS", OPM_R | OPM_TW }, nkeynes@1006: { "SAVEFLAGS", OPM_W | OPM_TR }, nkeynes@1006: { "ENTER", OPM_R }, nkeynes@1006: { "BRREL", OPM_R | OPM_TERM }, nkeynes@1006: { "BR", OPM_R | OPM_TERM }, nkeynes@1006: { "CALL0", OPM_R | OPM_CLB }, nkeynes@1006: { "OCBI", OPM_R_EXC }, nkeynes@1006: { "OCBP", OPM_R_EXC }, nkeynes@1006: { "OCBWB", OPM_R_EXC }, nkeynes@1006: { "PREF", OPM_R_EXC }, nkeynes@1006: nkeynes@1006: { "MOV", OPM_R_W }, nkeynes@1006: { "MOVQ", OPM_R_W|OPM_Q_Q }, nkeynes@1006: { "MOVV", OPM_R_W|OPM_V_V }, nkeynes@1006: { "MOVM", OPM_R_W|OPM_M_M }, nkeynes@1006: { "MOVSX8", OPM_R_W }, nkeynes@1006: { "MOVSX16", OPM_R_W }, nkeynes@1006: { "MOVSX32", OPM_R_W|OPM_I_Q }, nkeynes@1006: { "MOVZX8", OPM_R_W }, nkeynes@1006: { "MOVZX16", OPM_R_W }, nkeynes@1006: { "MOVZX32", OPM_R_W|OPM_I_Q }, nkeynes@1006: nkeynes@1006: { "ADD", OPM_R_RW }, nkeynes@1006: { "ADDS", OPM_R_RW_TW }, nkeynes@1006: { "ADDC", OPM_R_RW_TR }, nkeynes@1006: { "ADDCS", OPM_R_RW_TRW }, nkeynes@1006: { "AND", OPM_R_RW }, nkeynes@1006: { "ANDS", OPM_R_RW_TW }, nkeynes@1006: { "CMP", OPM_R_R_TW }, nkeynes@1006: { "DIV", OPM_R_RW }, nkeynes@1006: { "DIVS", OPM_R_RW_TW }, nkeynes@1006: { "MUL", OPM_R_RW }, nkeynes@1006: { "MULS", OPM_R_RW_TW }, nkeynes@1006: { "MULQ", OPM_R_RW|OPM_Q_Q }, nkeynes@1006: { "MULQS", OPM_R_RW_TW|OPM_Q_Q }, nkeynes@1006: { "NEG", OPM_R_W }, nkeynes@1006: { "NEGS", OPM_R_W_TW }, nkeynes@1006: { "NOT", OPM_R_W }, nkeynes@1006: { "NOTS", OPM_R_W_TW }, nkeynes@1006: { "OR", OPM_R_RW }, nkeynes@1006: { "ORS", OPM_R_RW_TW }, nkeynes@1006: { "RCL", OPM_R_RW_TRW }, nkeynes@1006: { "RCR", OPM_R_RW_TRW }, nkeynes@1006: { "ROL", OPM_R_RW }, nkeynes@1006: { "ROLS", OPM_R_RW_TW }, nkeynes@1006: { "ROR", OPM_R_RW }, nkeynes@1006: { "RORS", OPM_R_RW_TW }, nkeynes@1006: { "SAR", OPM_R_RW }, nkeynes@1006: { "SARS", OPM_R_RW_TW }, nkeynes@1006: { "SDIV", OPM_R_RW }, nkeynes@1006: { "SDIVS", OPM_R_RW_TW }, nkeynes@1006: { "SLL", OPM_R_RW }, nkeynes@1006: { "SLLS", OPM_R_RW_TW }, nkeynes@1006: { "SLR", OPM_R_RW }, nkeynes@1006: { "SLRS", OPM_R_RW_TW }, nkeynes@1006: { "SUB", OPM_R_RW }, nkeynes@1006: { "SUBS", OPM_R_RW_TW }, nkeynes@1006: { "SUBB", OPM_R_RW }, nkeynes@1006: { "SUBBS", OPM_R_RW_TRW }, nkeynes@1006: { "SHUFFLE", OPM_R_RW }, nkeynes@1006: { "TST", OPM_R_R_TW }, nkeynes@1006: { "XOR", OPM_R_RW }, nkeynes@1006: { "XORS", OPM_R_RW_TW }, nkeynes@1006: { "XLAT", OPM_R_RW }, nkeynes@1006: nkeynes@1006: { "ABSD", OPM_DR_DW }, nkeynes@1006: { "ABSF", OPM_FR_FW }, nkeynes@1006: { "ABSV", OPM_VR_VW }, nkeynes@1006: { "ADDD", OPM_DR_DRW }, nkeynes@1006: { "ADDF", OPM_FR_FRW }, nkeynes@1006: { "ADDV", OPM_VR_VRW }, nkeynes@1006: { "CMPD", OPM_DR_DR_TW }, nkeynes@1006: { "CMPF", OPM_FR_FR_TW }, nkeynes@1006: { "DIVD", OPM_DR_DRW }, nkeynes@1006: { "DIVF", OPM_FR_FRW }, nkeynes@1006: { "DIVV", OPM_VR_VRW }, nkeynes@1006: { "MULD", OPM_DR_DRW }, nkeynes@1006: { "MULF", OPM_FR_FRW }, nkeynes@1006: { "MULV", OPM_VR_VRW }, nkeynes@1006: { "NEGD", OPM_DR_DW }, nkeynes@1006: { "NEGF", OPM_FR_FW }, nkeynes@1006: { "NEGV", OPM_VR_VW }, nkeynes@1006: { "SQRTD", OPM_DR_DW }, nkeynes@1006: { "SQRTF", OPM_FR_FW }, nkeynes@1006: { "SQRTV", OPM_VR_VW }, nkeynes@1006: { "RSQRTD", OPM_DR_DW }, nkeynes@1006: { "RSQRTF", OPM_FR_FW }, nkeynes@1006: { "RSQRTV", OPM_VR_VW }, nkeynes@1006: { "SUBD", OPM_DR_DRW }, nkeynes@1006: { "SUBF", OPM_FR_FRW }, nkeynes@1006: { "SUBV", OPM_VR_VRW }, nkeynes@1006: nkeynes@1006: { "DTOF", OPM_R_W|OPM_D_F }, /* Round according to rounding mode */ nkeynes@1006: { "DTOI", OPM_R_W|OPM_D_I }, /* Truncate + saturate to signed 32-bits */ nkeynes@1006: { "FTOD", OPM_R_W|OPM_F_D }, /* Exact */ nkeynes@1006: { "FTOI", OPM_R_W|OPM_F_I }, /* Truncate + saturate to signed 32-bits */ nkeynes@1006: { "ITOD", OPM_R_W|OPM_I_D }, /* Exact */ nkeynes@1006: { "ITOF", OPM_R_W|OPM_I_F }, /* Round according to rounding mode */ nkeynes@1006: nkeynes@1006: { "SINCOSF", OPM_FR_FRW }, nkeynes@1006: nkeynes@1006: /* Compute the dot product of two vectors - the result is nkeynes@1006: * stored in the last element of the target operand (and the nkeynes@1006: * other elements are unchanged) nkeynes@1006: */ nkeynes@1006: { "DOTPRODV", OPM_R_RW|OPM_V_V }, nkeynes@1006: /* Perform the matrix multiplication V * M and place the result nkeynes@1006: * in V. nkeynes@1006: */ nkeynes@1006: { "MATMULV", OPM_R_RW|OPM_V_M }, nkeynes@1006: nkeynes@1006: { "LOAD.B", OPM_R_W_EXC }, nkeynes@1006: { "LOAD.BFW", OPM_R_W_EXC }, nkeynes@1006: { "LOAD.W", OPM_R_W_EXC }, nkeynes@1006: { "LOAD.L", OPM_R_W_EXC }, nkeynes@1006: { "LOAD.Q", OPM_R_W_EXC|OPM_I_Q }, nkeynes@1006: { "STORE.B", OPM_R_R_EXC }, nkeynes@1006: { "STORE.W", OPM_R_R_EXC }, nkeynes@1006: { "STORE.L", OPM_R_R_EXC }, nkeynes@1006: { "STORE.Q", OPM_R_R_EXC|OPM_I_Q }, nkeynes@1006: { "STORE.LCA", OPM_R_R_EXC }, nkeynes@1006: nkeynes@1006: { "BRCOND", OPM_R_R|OPM_TR | OPM_TERM }, nkeynes@1006: { "BRCONDDEL", OPM_R_R|OPM_TR }, nkeynes@1006: { "RAISE/ME", OPM_R_R | OPM_EXC }, nkeynes@1006: { "RAISE/MNE", OPM_R_R | OPM_EXC }, nkeynes@1006: nkeynes@1006: { "CALL/LUT", OPM_R_R | OPM_EXC }, nkeynes@1006: { "CALL1", OPM_R_R | OPM_CLB }, nkeynes@1006: { "CALLR", OPM_R_W | OPM_CLB }, nkeynes@1006: nkeynes@1006: { "ADDQSAT32", OPM_R_R | OPM_CLBT|OPM_Q_Q }, nkeynes@1006: { "ADDQSAT48", OPM_R_R | OPM_CLBT|OPM_Q_Q }, nkeynes@1006: { "CMP/STR", OPM_R_R_TW | OPM_CLBT }, nkeynes@1006: { "DIV1", OPM_R_RW_TRW | OPM_CLBT }, nkeynes@1006: { "SHAD", OPM_R_RW | OPM_CLBT }, nkeynes@1006: { "SHLD", OPM_R_RW | OPM_CLBT }, nkeynes@1006: nkeynes@1006: }; nkeynes@1006: nkeynes@1006: void xir_set_register_names( const char **source_regs, const char **target_regs ) nkeynes@1006: { nkeynes@1006: xir_source_register_names = source_regs; nkeynes@1006: xir_target_register_names = target_regs; nkeynes@1006: } nkeynes@1006: nkeynes@1006: void xir_set_symbol_table( const struct xir_symbol_entry *symtab ) nkeynes@1006: { nkeynes@1006: xir_symbol_table = symtab; nkeynes@1006: } nkeynes@1006: nkeynes@1006: const char *xir_lookup_symbol( const void *ptr ) nkeynes@1006: { nkeynes@1006: if( xir_symbol_table != NULL ) { nkeynes@1006: const struct xir_symbol_entry *p; nkeynes@1006: for( p = xir_symbol_table; p->name != NULL; p++ ) { nkeynes@1006: if( p->ptr == ptr ) { nkeynes@1006: return p->name; nkeynes@1006: } nkeynes@1006: } nkeynes@1006: } nkeynes@1006: return NULL; nkeynes@1006: } nkeynes@1006: nkeynes@1006: int xir_snprint_operand( char *buf, int buflen, xir_operand_t op ) nkeynes@1006: { nkeynes@1006: const char *name; nkeynes@1006: switch( op->type ) { nkeynes@1006: case INT_IMM_OPERAND: nkeynes@1006: return snprintf( buf, buflen, "$0x%x", op->value.i ); nkeynes@1006: case FLOAT_IMM_OPERAND: nkeynes@1006: return snprintf( buf, buflen, "%f", op->value.f ); nkeynes@1006: case DOUBLE_IMM_OPERAND: nkeynes@1006: return snprintf( buf, buflen, "%f", op->value.f ); nkeynes@1006: case POINTER_OPERAND: nkeynes@1006: name = xir_lookup_symbol( op->value.p ); nkeynes@1006: if( name != NULL ) { nkeynes@1006: return snprintf( buf, buflen, "*%s", name ); nkeynes@1006: } else { nkeynes@1006: return snprintf( buf, buflen, "*%p", op->value.p ); nkeynes@1006: } nkeynes@1006: case SOURCE_REGISTER_OPERAND: nkeynes@1006: if( op->value.i >= MIN_SOURCE_REGISTER && op->value.i <= MAX_SOURCE_REGISTER ) { nkeynes@1006: if( xir_source_register_names ) { nkeynes@1006: return snprintf( buf, buflen, "%%%s", xir_source_register_names[(op->value.i-MIN_SOURCE_REGISTER)>>2] ); nkeynes@1006: } else { nkeynes@1006: return snprintf( buf, buflen, "%%src%d", op->value.i-MIN_SOURCE_REGISTER ); nkeynes@1006: } nkeynes@1006: } else { nkeynes@1006: return snprintf( buf, buflen, "%%tmp%d", op->value.i-MIN_TEMP_REGISTER ); nkeynes@1006: } nkeynes@1006: case TARGET_REGISTER_OPERAND: nkeynes@1006: if( xir_target_register_names ) { nkeynes@1006: return snprintf( buf, buflen, "%%%s", xir_target_register_names[op->value.i-MIN_TARGET_REGISTER] ); nkeynes@1006: } else { nkeynes@1006: return snprintf( buf, buflen, "%%dst%d", op->value.i-MIN_TARGET_REGISTER ); nkeynes@1006: } nkeynes@1006: default: nkeynes@1006: return snprintf( buf, buflen, "ILLOP" ); nkeynes@1006: } nkeynes@1006: } nkeynes@1006: nkeynes@1006: void xir_print_instruction( FILE *out, xir_op_t i ) nkeynes@1006: { nkeynes@1006: char operands[64] = ""; nkeynes@1006: nkeynes@1006: if( i->operand[0].type != NO_OPERAND ) { nkeynes@1006: int pos = xir_snprint_operand( operands, sizeof(operands), &i->operand[0] ); nkeynes@1006: if( i->operand[1].type != NO_OPERAND ) { nkeynes@1006: strncat( operands, ", ", sizeof(operands)-pos ); nkeynes@1006: pos += 2; nkeynes@1006: xir_snprint_operand( operands+pos, sizeof(operands)-pos, &i->operand[1] ); nkeynes@1006: } nkeynes@1006: } nkeynes@1006: if( i->cond == CC_TRUE ) { nkeynes@1006: fprintf( out, "%-9s %-30s", XIR_OPCODE_TABLE[i->opcode].name, operands ); nkeynes@1006: } else { nkeynes@1006: char buf[16]; nkeynes@1006: snprintf( buf, 16, "%s%s", XIR_OPCODE_TABLE[i->opcode].name, XIR_CC_NAMES[i->cond] ); nkeynes@1006: fprintf( out, "%-9s %-30s", buf, operands ); nkeynes@1006: } nkeynes@1006: } nkeynes@1006: nkeynes@1006: /** nkeynes@1006: * Sanity check a block of IR to make sure that nkeynes@1006: * operands match up with the expected values etc nkeynes@1006: */ nkeynes@1006: void xir_verify_block( xir_op_t start, xir_op_t end ) nkeynes@1006: { nkeynes@1006: xir_op_t it; nkeynes@1006: int flags_written = 0; nkeynes@1006: for( it = start; it != NULL; it = it->next ) { nkeynes@1006: assert( it != NULL && "Unexpected end of block" ); nkeynes@1006: assert( it->cond >= CC_TRUE && it->cond <= CC_SGT && "Invalid condition code" ); nkeynes@1006: if( XOP_HAS_0_OPERANDS(it) ) { nkeynes@1006: assert( it->operand[0].type == NO_OPERAND && it->operand[1].type == NO_OPERAND ); nkeynes@1006: } else if( XOP_HAS_1_OPERAND(it) ) { nkeynes@1006: assert( it->operand[0].type != NO_OPERAND && it->operand[1].type == NO_OPERAND ); nkeynes@1006: } else if( XOP_HAS_2_OPERANDS(it) ) { nkeynes@1006: assert( it->operand[0].type != NO_OPERAND && it->operand[1].type != NO_OPERAND ); nkeynes@1006: } nkeynes@1006: nkeynes@1006: if( it->opcode == OP_ENTER ) { nkeynes@1006: assert( it->prev == NULL && "Enter instruction must have no predecessors" ); nkeynes@1006: assert( it == start && "Enter instruction must occur at the start of the block" ); nkeynes@1006: assert( it->operand[0].type == INT_IMM_OPERAND && "Enter instruction must have an immediate operand" ); nkeynes@1006: } else if( it->opcode == OP_ST || it->opcode == OP_LD ) { nkeynes@1006: assert( it->cond != CC_TRUE && "Opcode not permitted with True condition code" ); nkeynes@1006: } nkeynes@1006: nkeynes@1006: if( XOP_WRITES_OP1(it) ) { nkeynes@1006: assert( (it->operand[0].type == SOURCE_REGISTER_OPERAND || nkeynes@1006: it->operand[0].type == TARGET_REGISTER_OPERAND) && "Writable operand 1 requires a register" ); nkeynes@1006: } nkeynes@1006: if( XOP_WRITES_OP2(it) ) { nkeynes@1006: assert( (it->operand[1].type == SOURCE_REGISTER_OPERAND || nkeynes@1006: it->operand[1].type == TARGET_REGISTER_OPERAND) && "Writable operand 2 requires a register" ); nkeynes@1006: } nkeynes@1006: nkeynes@1006: if( XOP_READS_FLAGS(it) ) { nkeynes@1006: assert( flags_written && "Flags used without prior definition in block" ); nkeynes@1006: } nkeynes@1006: if( XOP_WRITES_FLAGS(it) ) { nkeynes@1006: flags_written = 1; nkeynes@1006: } nkeynes@1006: nkeynes@1006: if( XOP_HAS_EXCEPTION(it) ) { nkeynes@1006: assert( it->exc != NULL && "Missing exception block" ); nkeynes@1006: assert( it->exc->prev == it && "Exception back-link broken" ); nkeynes@1006: xir_verify_block( it->exc, NULL ); // Verify exception sub-block nkeynes@1006: } else { nkeynes@1006: assert( it->exc == NULL && "Unexpected exception block" ); nkeynes@1006: } nkeynes@1006: if( XOP_IS_TERMINATOR(it) ) { nkeynes@1006: assert( it->next == NULL && "Unexpected next instruction on terminator" ); nkeynes@1006: } else { nkeynes@1006: assert( it->next != NULL && "Missing terminator instruction at end of block" ); nkeynes@1006: assert( it->next->prev == it && "Linked-list chain broken" ); nkeynes@1006: } nkeynes@1006: if( it == end ) nkeynes@1006: break; nkeynes@1006: } nkeynes@1006: } nkeynes@1006: nkeynes@1006: xir_op_t xir_append_op2( xir_basic_block_t xbb, int op, int arg0type, uint32_t arg0, int arg1type, uint32_t arg1 ) nkeynes@1006: { nkeynes@1006: xbb->ir_ptr->opcode = op; nkeynes@1006: xbb->ir_ptr->cond = CC_TRUE; nkeynes@1006: xbb->ir_ptr->operand[0].type = arg0type; nkeynes@1006: xbb->ir_ptr->operand[0].value.i = arg0; nkeynes@1006: xbb->ir_ptr->operand[1].type = arg1type; nkeynes@1006: xbb->ir_ptr->operand[1].value.i = arg1; nkeynes@1006: xbb->ir_ptr->exc = NULL; nkeynes@1006: xbb->ir_ptr->next = xbb->ir_ptr+1; nkeynes@1006: (xbb->ir_ptr+1)->prev = xbb->ir_ptr; nkeynes@1006: return xbb->ir_ptr++; nkeynes@1006: } nkeynes@1006: nkeynes@1006: xir_op_t xir_append_op2cc( xir_basic_block_t xbb, int op, xir_cc_t cc, int arg0type, uint32_t arg0, int arg1type, uint32_t arg1 ) nkeynes@1006: { nkeynes@1006: xbb->ir_ptr->opcode = op; nkeynes@1006: xbb->ir_ptr->cond = cc; nkeynes@1006: xbb->ir_ptr->operand[0].type = arg0type; nkeynes@1006: xbb->ir_ptr->operand[0].value.i = arg0; nkeynes@1006: xbb->ir_ptr->operand[1].type = arg1type; nkeynes@1006: xbb->ir_ptr->operand[1].value.i = arg1; nkeynes@1006: xbb->ir_ptr->exc = NULL; nkeynes@1006: xbb->ir_ptr->next = xbb->ir_ptr+1; nkeynes@1006: (xbb->ir_ptr+1)->prev = xbb->ir_ptr; nkeynes@1006: return xbb->ir_ptr++; nkeynes@1006: } nkeynes@1006: nkeynes@1006: xir_op_t xir_append_float_op2( xir_basic_block_t xbb, int op, float imm1, int arg1type, uint32_t arg1 ) nkeynes@1006: { nkeynes@1006: xbb->ir_ptr->opcode = op; nkeynes@1006: xbb->ir_ptr->cond = CC_TRUE; nkeynes@1006: xbb->ir_ptr->operand[0].type = FLOAT_IMM_OPERAND; nkeynes@1006: xbb->ir_ptr->operand[0].value.i = imm1; nkeynes@1006: xbb->ir_ptr->operand[1].type = arg1type; nkeynes@1006: xbb->ir_ptr->operand[1].value.i = arg1; nkeynes@1006: xbb->ir_ptr->exc = NULL; nkeynes@1006: xbb->ir_ptr->next = xbb->ir_ptr+1; nkeynes@1006: (xbb->ir_ptr+1)->prev = xbb->ir_ptr; nkeynes@1006: return xbb->ir_ptr++; nkeynes@1006: } nkeynes@1006: nkeynes@1006: xir_op_t xir_append_ptr_op2( xir_basic_block_t xbb, int op, void *arg0, int arg1type, uint32_t arg1 ) nkeynes@1006: { nkeynes@1006: xbb->ir_ptr->opcode = op; nkeynes@1006: xbb->ir_ptr->cond = CC_TRUE; nkeynes@1006: xbb->ir_ptr->operand[0].type = POINTER_OPERAND; nkeynes@1006: xbb->ir_ptr->operand[0].value.p = arg0; nkeynes@1006: xbb->ir_ptr->operand[1].type = arg1type; nkeynes@1006: xbb->ir_ptr->operand[1].value.i = arg1; nkeynes@1006: xbb->ir_ptr->exc = NULL; nkeynes@1006: xbb->ir_ptr->next = xbb->ir_ptr+1; nkeynes@1006: (xbb->ir_ptr+1)->prev = xbb->ir_ptr; nkeynes@1006: return xbb->ir_ptr++; nkeynes@1006: } nkeynes@1006: nkeynes@1006: void xir_insert_op( xir_op_t op, xir_op_t before ) nkeynes@1006: { nkeynes@1006: op->prev = before->prev; nkeynes@1006: op->next = before; nkeynes@1006: before->prev->next = op; nkeynes@1006: before->prev = op; nkeynes@1006: } nkeynes@1006: nkeynes@1006: void xir_insert_block( xir_op_t start, xir_op_t end, xir_op_t before ) nkeynes@1006: { nkeynes@1006: start->prev = before->prev; nkeynes@1006: end->next = before; nkeynes@1006: before->prev->next = start; nkeynes@1006: before->prev = end; nkeynes@1006: } nkeynes@1006: nkeynes@1006: void xir_remove_op( xir_op_t op ) nkeynes@1006: { nkeynes@1006: if( op->next != NULL ) { nkeynes@1006: op->next->prev = op->prev; nkeynes@1006: } nkeynes@1006: if( op->prev != NULL ) { nkeynes@1006: if( op->prev->next == op ) { nkeynes@1006: op->prev->next = op->next; nkeynes@1006: } else { nkeynes@1006: assert( op->prev->exc == op ); nkeynes@1006: op->prev->exc = op->next; nkeynes@1006: } nkeynes@1006: } nkeynes@1006: } nkeynes@1006: nkeynes@1006: int xir_get_operand_size( xir_op_t op, int operand ) nkeynes@1006: { nkeynes@1006: int mode = XIR_OPCODE_TABLE[op->opcode].mode; nkeynes@1006: if( operand == 0 ) { nkeynes@1006: mode >>= 4; nkeynes@1006: } else { nkeynes@1006: mode >>= 8; nkeynes@1006: } nkeynes@1006: mode &= 0x07; nkeynes@1006: return XIR_OPERAND_SIZE[mode]; nkeynes@1006: } nkeynes@1006: nkeynes@1006: void xir_print_block( FILE *out, xir_op_t start, xir_op_t end ) nkeynes@1006: { nkeynes@1006: xir_op_t it = start; nkeynes@1006: xir_op_t exc = NULL; nkeynes@1006: nkeynes@1006: while( it != NULL ) { nkeynes@1006: if( it->exc ) { nkeynes@1006: while( exc ) { nkeynes@1006: fprintf( out, "%40c ", ' ' ); nkeynes@1006: xir_print_instruction( out, exc ); nkeynes@1006: fprintf( out, "\n" ); nkeynes@1006: exc = exc->next; nkeynes@1006: } nkeynes@1006: exc = it->exc; nkeynes@1006: } nkeynes@1006: xir_print_instruction( out, it ); nkeynes@1006: if( exc ) { nkeynes@1006: if( it->exc ) { nkeynes@1006: fprintf( out, "=> " ); nkeynes@1006: } else { nkeynes@1006: fprintf( out, " " ); nkeynes@1006: } nkeynes@1006: xir_print_instruction( out, exc ); nkeynes@1006: exc = exc->next; nkeynes@1006: } nkeynes@1006: fprintf( out, "\n" ); nkeynes@1006: if( it == end ) nkeynes@1006: break; nkeynes@1006: it = it->next; nkeynes@1006: } nkeynes@1006: } nkeynes@1006: nkeynes@1006: void xir_dump_block( xir_op_t start, xir_op_t end ) nkeynes@1006: { nkeynes@1006: xir_print_block( stdout, start, end ); nkeynes@1006: xir_verify_block( start, end ); nkeynes@1006: }