nkeynes@1006 | 1 | /**
|
nkeynes@1006 | 2 | * $Id: xir.h 931 2008-10-31 02:57:59Z nkeynes $
|
nkeynes@1006 | 3 | *
|
nkeynes@1006 | 4 | * This file provides support functions for the translation IR.
|
nkeynes@1006 | 5 | *
|
nkeynes@1006 | 6 | * Copyright (c) 2009 Nathan Keynes.
|
nkeynes@1006 | 7 | *
|
nkeynes@1006 | 8 | * This program is free software; you can redistribute it and/or modify
|
nkeynes@1006 | 9 | * it under the terms of the GNU General Public License as published by
|
nkeynes@1006 | 10 | * the Free Software Foundation; either version 2 of the License, or
|
nkeynes@1006 | 11 | * (at your option) any later version.
|
nkeynes@1006 | 12 | *
|
nkeynes@1006 | 13 | * This program is distributed in the hope that it will be useful,
|
nkeynes@1006 | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
nkeynes@1006 | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
nkeynes@1006 | 16 | * GNU General Public License for more details.
|
nkeynes@1006 | 17 | */
|
nkeynes@1006 | 18 |
|
nkeynes@1006 | 19 | #include <stdio.h>
|
nkeynes@1006 | 20 | #include <string.h>
|
nkeynes@1006 | 21 | #include <assert.h>
|
nkeynes@1006 | 22 | #include "xlat/xir.h"
|
nkeynes@1006 | 23 |
|
nkeynes@1006 | 24 | static const char **xir_source_register_names = NULL;
|
nkeynes@1006 | 25 | static const char **xir_target_register_names = NULL;
|
nkeynes@1006 | 26 | static const struct xir_symbol_entry *xir_symbol_table = NULL;
|
nkeynes@1006 | 27 |
|
nkeynes@1006 | 28 | static const char *XIR_CC_NAMES[] = {
|
nkeynes@1006 | 29 | "ov", "no", "uge", "ult", "ule", "ugt", "eq", "ne",
|
nkeynes@1006 | 30 | "neg", "pos", "sge", "slt", "sle", "sgt" };
|
nkeynes@1006 | 31 | static const int XIR_OPERAND_SIZE[] = { 4, 8, 4, 8, 16, 64, 0, 0 };
|
nkeynes@1006 | 32 |
|
nkeynes@1006 | 33 | const struct xir_opcode_entry XIR_OPCODE_TABLE[] = {
|
nkeynes@1006 | 34 | { "NOP", OPM_NO },
|
nkeynes@1006 | 35 | { "BARRIER", OPM_NO | OPM_CLB },
|
nkeynes@1006 | 36 | { "DEC", OPM_RW_TW },
|
nkeynes@1006 | 37 | { "LD", OPM_R | OPM_TW },
|
nkeynes@1006 | 38 | { "ST", OPM_W | OPM_TR },
|
nkeynes@1006 | 39 | { "RESTFLAGS", OPM_R | OPM_TW },
|
nkeynes@1006 | 40 | { "SAVEFLAGS", OPM_W | OPM_TR },
|
nkeynes@1006 | 41 | { "ENTER", OPM_R },
|
nkeynes@1006 | 42 | { "BRREL", OPM_R | OPM_TERM },
|
nkeynes@1006 | 43 | { "BR", OPM_R | OPM_TERM },
|
nkeynes@1006 | 44 | { "CALL0", OPM_R | OPM_CLB },
|
nkeynes@1006 | 45 | { "OCBI", OPM_R_EXC },
|
nkeynes@1006 | 46 | { "OCBP", OPM_R_EXC },
|
nkeynes@1006 | 47 | { "OCBWB", OPM_R_EXC },
|
nkeynes@1006 | 48 | { "PREF", OPM_R_EXC },
|
nkeynes@1006 | 49 |
|
nkeynes@1006 | 50 | { "MOV", OPM_R_W },
|
nkeynes@1006 | 51 | { "MOVQ", OPM_R_W|OPM_Q_Q },
|
nkeynes@1006 | 52 | { "MOVV", OPM_R_W|OPM_V_V },
|
nkeynes@1006 | 53 | { "MOVM", OPM_R_W|OPM_M_M },
|
nkeynes@1006 | 54 | { "MOVSX8", OPM_R_W },
|
nkeynes@1006 | 55 | { "MOVSX16", OPM_R_W },
|
nkeynes@1006 | 56 | { "MOVSX32", OPM_R_W|OPM_I_Q },
|
nkeynes@1006 | 57 | { "MOVZX8", OPM_R_W },
|
nkeynes@1006 | 58 | { "MOVZX16", OPM_R_W },
|
nkeynes@1006 | 59 | { "MOVZX32", OPM_R_W|OPM_I_Q },
|
nkeynes@1006 | 60 |
|
nkeynes@1006 | 61 | { "ADD", OPM_R_RW },
|
nkeynes@1006 | 62 | { "ADDS", OPM_R_RW_TW },
|
nkeynes@1006 | 63 | { "ADDC", OPM_R_RW_TR },
|
nkeynes@1006 | 64 | { "ADDCS", OPM_R_RW_TRW },
|
nkeynes@1006 | 65 | { "AND", OPM_R_RW },
|
nkeynes@1006 | 66 | { "ANDS", OPM_R_RW_TW },
|
nkeynes@1006 | 67 | { "CMP", OPM_R_R_TW },
|
nkeynes@1006 | 68 | { "DIV", OPM_R_RW },
|
nkeynes@1006 | 69 | { "DIVS", OPM_R_RW_TW },
|
nkeynes@1006 | 70 | { "MUL", OPM_R_RW },
|
nkeynes@1006 | 71 | { "MULS", OPM_R_RW_TW },
|
nkeynes@1006 | 72 | { "MULQ", OPM_R_RW|OPM_Q_Q },
|
nkeynes@1006 | 73 | { "MULQS", OPM_R_RW_TW|OPM_Q_Q },
|
nkeynes@1006 | 74 | { "NEG", OPM_R_W },
|
nkeynes@1006 | 75 | { "NEGS", OPM_R_W_TW },
|
nkeynes@1006 | 76 | { "NOT", OPM_R_W },
|
nkeynes@1006 | 77 | { "NOTS", OPM_R_W_TW },
|
nkeynes@1006 | 78 | { "OR", OPM_R_RW },
|
nkeynes@1006 | 79 | { "ORS", OPM_R_RW_TW },
|
nkeynes@1006 | 80 | { "RCL", OPM_R_RW_TRW },
|
nkeynes@1006 | 81 | { "RCR", OPM_R_RW_TRW },
|
nkeynes@1006 | 82 | { "ROL", OPM_R_RW },
|
nkeynes@1006 | 83 | { "ROLS", OPM_R_RW_TW },
|
nkeynes@1006 | 84 | { "ROR", OPM_R_RW },
|
nkeynes@1006 | 85 | { "RORS", OPM_R_RW_TW },
|
nkeynes@1006 | 86 | { "SAR", OPM_R_RW },
|
nkeynes@1006 | 87 | { "SARS", OPM_R_RW_TW },
|
nkeynes@1006 | 88 | { "SDIV", OPM_R_RW },
|
nkeynes@1006 | 89 | { "SDIVS", OPM_R_RW_TW },
|
nkeynes@1006 | 90 | { "SLL", OPM_R_RW },
|
nkeynes@1006 | 91 | { "SLLS", OPM_R_RW_TW },
|
nkeynes@1006 | 92 | { "SLR", OPM_R_RW },
|
nkeynes@1006 | 93 | { "SLRS", OPM_R_RW_TW },
|
nkeynes@1006 | 94 | { "SUB", OPM_R_RW },
|
nkeynes@1006 | 95 | { "SUBS", OPM_R_RW_TW },
|
nkeynes@1006 | 96 | { "SUBB", OPM_R_RW },
|
nkeynes@1006 | 97 | { "SUBBS", OPM_R_RW_TRW },
|
nkeynes@1006 | 98 | { "SHUFFLE", OPM_R_RW },
|
nkeynes@1006 | 99 | { "TST", OPM_R_R_TW },
|
nkeynes@1006 | 100 | { "XOR", OPM_R_RW },
|
nkeynes@1006 | 101 | { "XORS", OPM_R_RW_TW },
|
nkeynes@1006 | 102 | { "XLAT", OPM_R_RW },
|
nkeynes@1006 | 103 |
|
nkeynes@1006 | 104 | { "ABSD", OPM_DR_DW },
|
nkeynes@1006 | 105 | { "ABSF", OPM_FR_FW },
|
nkeynes@1006 | 106 | { "ABSV", OPM_VR_VW },
|
nkeynes@1006 | 107 | { "ADDD", OPM_DR_DRW },
|
nkeynes@1006 | 108 | { "ADDF", OPM_FR_FRW },
|
nkeynes@1006 | 109 | { "ADDV", OPM_VR_VRW },
|
nkeynes@1006 | 110 | { "CMPD", OPM_DR_DR_TW },
|
nkeynes@1006 | 111 | { "CMPF", OPM_FR_FR_TW },
|
nkeynes@1006 | 112 | { "DIVD", OPM_DR_DRW },
|
nkeynes@1006 | 113 | { "DIVF", OPM_FR_FRW },
|
nkeynes@1006 | 114 | { "DIVV", OPM_VR_VRW },
|
nkeynes@1006 | 115 | { "MULD", OPM_DR_DRW },
|
nkeynes@1006 | 116 | { "MULF", OPM_FR_FRW },
|
nkeynes@1006 | 117 | { "MULV", OPM_VR_VRW },
|
nkeynes@1006 | 118 | { "NEGD", OPM_DR_DW },
|
nkeynes@1006 | 119 | { "NEGF", OPM_FR_FW },
|
nkeynes@1006 | 120 | { "NEGV", OPM_VR_VW },
|
nkeynes@1006 | 121 | { "SQRTD", OPM_DR_DW },
|
nkeynes@1006 | 122 | { "SQRTF", OPM_FR_FW },
|
nkeynes@1006 | 123 | { "SQRTV", OPM_VR_VW },
|
nkeynes@1006 | 124 | { "RSQRTD", OPM_DR_DW },
|
nkeynes@1006 | 125 | { "RSQRTF", OPM_FR_FW },
|
nkeynes@1006 | 126 | { "RSQRTV", OPM_VR_VW },
|
nkeynes@1006 | 127 | { "SUBD", OPM_DR_DRW },
|
nkeynes@1006 | 128 | { "SUBF", OPM_FR_FRW },
|
nkeynes@1006 | 129 | { "SUBV", OPM_VR_VRW },
|
nkeynes@1006 | 130 |
|
nkeynes@1006 | 131 | { "DTOF", OPM_R_W|OPM_D_F }, /* Round according to rounding mode */
|
nkeynes@1006 | 132 | { "DTOI", OPM_R_W|OPM_D_I }, /* Truncate + saturate to signed 32-bits */
|
nkeynes@1006 | 133 | { "FTOD", OPM_R_W|OPM_F_D }, /* Exact */
|
nkeynes@1006 | 134 | { "FTOI", OPM_R_W|OPM_F_I }, /* Truncate + saturate to signed 32-bits */
|
nkeynes@1006 | 135 | { "ITOD", OPM_R_W|OPM_I_D }, /* Exact */
|
nkeynes@1006 | 136 | { "ITOF", OPM_R_W|OPM_I_F }, /* Round according to rounding mode */
|
nkeynes@1006 | 137 |
|
nkeynes@1006 | 138 | { "SINCOSF", OPM_FR_FRW },
|
nkeynes@1006 | 139 |
|
nkeynes@1006 | 140 | /* Compute the dot product of two vectors - the result is
|
nkeynes@1006 | 141 | * stored in the last element of the target operand (and the
|
nkeynes@1006 | 142 | * other elements are unchanged)
|
nkeynes@1006 | 143 | */
|
nkeynes@1006 | 144 | { "DOTPRODV", OPM_R_RW|OPM_V_V },
|
nkeynes@1006 | 145 | /* Perform the matrix multiplication V * M and place the result
|
nkeynes@1006 | 146 | * in V.
|
nkeynes@1006 | 147 | */
|
nkeynes@1006 | 148 | { "MATMULV", OPM_R_RW|OPM_V_M },
|
nkeynes@1006 | 149 |
|
nkeynes@1006 | 150 | { "LOAD.B", OPM_R_W_EXC },
|
nkeynes@1006 | 151 | { "LOAD.BFW", OPM_R_W_EXC },
|
nkeynes@1006 | 152 | { "LOAD.W", OPM_R_W_EXC },
|
nkeynes@1006 | 153 | { "LOAD.L", OPM_R_W_EXC },
|
nkeynes@1006 | 154 | { "LOAD.Q", OPM_R_W_EXC|OPM_I_Q },
|
nkeynes@1006 | 155 | { "STORE.B", OPM_R_R_EXC },
|
nkeynes@1006 | 156 | { "STORE.W", OPM_R_R_EXC },
|
nkeynes@1006 | 157 | { "STORE.L", OPM_R_R_EXC },
|
nkeynes@1006 | 158 | { "STORE.Q", OPM_R_R_EXC|OPM_I_Q },
|
nkeynes@1006 | 159 | { "STORE.LCA", OPM_R_R_EXC },
|
nkeynes@1006 | 160 |
|
nkeynes@1006 | 161 | { "BRCOND", OPM_R_R|OPM_TR | OPM_TERM },
|
nkeynes@1006 | 162 | { "BRCONDDEL", OPM_R_R|OPM_TR },
|
nkeynes@1006 | 163 | { "RAISE/ME", OPM_R_R | OPM_EXC },
|
nkeynes@1006 | 164 | { "RAISE/MNE", OPM_R_R | OPM_EXC },
|
nkeynes@1006 | 165 |
|
nkeynes@1006 | 166 | { "CALL/LUT", OPM_R_R | OPM_EXC },
|
nkeynes@1006 | 167 | { "CALL1", OPM_R_R | OPM_CLB },
|
nkeynes@1006 | 168 | { "CALLR", OPM_R_W | OPM_CLB },
|
nkeynes@1006 | 169 |
|
nkeynes@1006 | 170 | { "ADDQSAT32", OPM_R_R | OPM_CLBT|OPM_Q_Q },
|
nkeynes@1006 | 171 | { "ADDQSAT48", OPM_R_R | OPM_CLBT|OPM_Q_Q },
|
nkeynes@1006 | 172 | { "CMP/STR", OPM_R_R_TW | OPM_CLBT },
|
nkeynes@1006 | 173 | { "DIV1", OPM_R_RW_TRW | OPM_CLBT },
|
nkeynes@1006 | 174 | { "SHAD", OPM_R_RW | OPM_CLBT },
|
nkeynes@1006 | 175 | { "SHLD", OPM_R_RW | OPM_CLBT },
|
nkeynes@1006 | 176 |
|
nkeynes@1006 | 177 | };
|
nkeynes@1006 | 178 |
|
nkeynes@1006 | 179 | void xir_set_register_names( const char **source_regs, const char **target_regs )
|
nkeynes@1006 | 180 | {
|
nkeynes@1006 | 181 | xir_source_register_names = source_regs;
|
nkeynes@1006 | 182 | xir_target_register_names = target_regs;
|
nkeynes@1006 | 183 | }
|
nkeynes@1006 | 184 |
|
nkeynes@1006 | 185 | void xir_set_symbol_table( const struct xir_symbol_entry *symtab )
|
nkeynes@1006 | 186 | {
|
nkeynes@1006 | 187 | xir_symbol_table = symtab;
|
nkeynes@1006 | 188 | }
|
nkeynes@1006 | 189 |
|
nkeynes@1006 | 190 | const char *xir_lookup_symbol( const void *ptr )
|
nkeynes@1006 | 191 | {
|
nkeynes@1006 | 192 | if( xir_symbol_table != NULL ) {
|
nkeynes@1006 | 193 | const struct xir_symbol_entry *p;
|
nkeynes@1006 | 194 | for( p = xir_symbol_table; p->name != NULL; p++ ) {
|
nkeynes@1006 | 195 | if( p->ptr == ptr ) {
|
nkeynes@1006 | 196 | return p->name;
|
nkeynes@1006 | 197 | }
|
nkeynes@1006 | 198 | }
|
nkeynes@1006 | 199 | }
|
nkeynes@1006 | 200 | return NULL;
|
nkeynes@1006 | 201 | }
|
nkeynes@1006 | 202 |
|
nkeynes@1006 | 203 | int xir_snprint_operand( char *buf, int buflen, xir_operand_t op )
|
nkeynes@1006 | 204 | {
|
nkeynes@1006 | 205 | const char *name;
|
nkeynes@1006 | 206 | switch( op->type ) {
|
nkeynes@1006 | 207 | case INT_IMM_OPERAND:
|
nkeynes@1006 | 208 | return snprintf( buf, buflen, "$0x%x", op->value.i );
|
nkeynes@1006 | 209 | case FLOAT_IMM_OPERAND:
|
nkeynes@1006 | 210 | return snprintf( buf, buflen, "%f", op->value.f );
|
nkeynes@1006 | 211 | case DOUBLE_IMM_OPERAND:
|
nkeynes@1006 | 212 | return snprintf( buf, buflen, "%f", op->value.f );
|
nkeynes@1006 | 213 | case POINTER_OPERAND:
|
nkeynes@1006 | 214 | name = xir_lookup_symbol( op->value.p );
|
nkeynes@1006 | 215 | if( name != NULL ) {
|
nkeynes@1006 | 216 | return snprintf( buf, buflen, "*%s", name );
|
nkeynes@1006 | 217 | } else {
|
nkeynes@1006 | 218 | return snprintf( buf, buflen, "*%p", op->value.p );
|
nkeynes@1006 | 219 | }
|
nkeynes@1006 | 220 | case SOURCE_REGISTER_OPERAND:
|
nkeynes@1006 | 221 | if( op->value.i >= MIN_SOURCE_REGISTER && op->value.i <= MAX_SOURCE_REGISTER ) {
|
nkeynes@1006 | 222 | if( xir_source_register_names ) {
|
nkeynes@1006 | 223 | return snprintf( buf, buflen, "%%%s", xir_source_register_names[(op->value.i-MIN_SOURCE_REGISTER)>>2] );
|
nkeynes@1006 | 224 | } else {
|
nkeynes@1006 | 225 | return snprintf( buf, buflen, "%%src%d", op->value.i-MIN_SOURCE_REGISTER );
|
nkeynes@1006 | 226 | }
|
nkeynes@1006 | 227 | } else {
|
nkeynes@1006 | 228 | return snprintf( buf, buflen, "%%tmp%d", op->value.i-MIN_TEMP_REGISTER );
|
nkeynes@1006 | 229 | }
|
nkeynes@1006 | 230 | case TARGET_REGISTER_OPERAND:
|
nkeynes@1006 | 231 | if( xir_target_register_names ) {
|
nkeynes@1006 | 232 | return snprintf( buf, buflen, "%%%s", xir_target_register_names[op->value.i-MIN_TARGET_REGISTER] );
|
nkeynes@1006 | 233 | } else {
|
nkeynes@1006 | 234 | return snprintf( buf, buflen, "%%dst%d", op->value.i-MIN_TARGET_REGISTER );
|
nkeynes@1006 | 235 | }
|
nkeynes@1006 | 236 | default:
|
nkeynes@1006 | 237 | return snprintf( buf, buflen, "ILLOP" );
|
nkeynes@1006 | 238 | }
|
nkeynes@1006 | 239 | }
|
nkeynes@1006 | 240 |
|
nkeynes@1006 | 241 | void xir_print_instruction( FILE *out, xir_op_t i )
|
nkeynes@1006 | 242 | {
|
nkeynes@1006 | 243 | char operands[64] = "";
|
nkeynes@1006 | 244 |
|
nkeynes@1006 | 245 | if( i->operand[0].type != NO_OPERAND ) {
|
nkeynes@1006 | 246 | int pos = xir_snprint_operand( operands, sizeof(operands), &i->operand[0] );
|
nkeynes@1006 | 247 | if( i->operand[1].type != NO_OPERAND ) {
|
nkeynes@1006 | 248 | strncat( operands, ", ", sizeof(operands)-pos );
|
nkeynes@1006 | 249 | pos += 2;
|
nkeynes@1006 | 250 | xir_snprint_operand( operands+pos, sizeof(operands)-pos, &i->operand[1] );
|
nkeynes@1006 | 251 | }
|
nkeynes@1006 | 252 | }
|
nkeynes@1006 | 253 | if( i->cond == CC_TRUE ) {
|
nkeynes@1006 | 254 | fprintf( out, "%-9s %-30s", XIR_OPCODE_TABLE[i->opcode].name, operands );
|
nkeynes@1006 | 255 | } else {
|
nkeynes@1006 | 256 | char buf[16];
|
nkeynes@1006 | 257 | snprintf( buf, 16, "%s%s", XIR_OPCODE_TABLE[i->opcode].name, XIR_CC_NAMES[i->cond] );
|
nkeynes@1006 | 258 | fprintf( out, "%-9s %-30s", buf, operands );
|
nkeynes@1006 | 259 | }
|
nkeynes@1006 | 260 | }
|
nkeynes@1006 | 261 |
|
nkeynes@1006 | 262 | /**
|
nkeynes@1006 | 263 | * Sanity check a block of IR to make sure that
|
nkeynes@1006 | 264 | * operands match up with the expected values etc
|
nkeynes@1006 | 265 | */
|
nkeynes@1006 | 266 | void xir_verify_block( xir_op_t start, xir_op_t end )
|
nkeynes@1006 | 267 | {
|
nkeynes@1006 | 268 | xir_op_t it;
|
nkeynes@1006 | 269 | int flags_written = 0;
|
nkeynes@1006 | 270 | for( it = start; it != NULL; it = it->next ) {
|
nkeynes@1006 | 271 | assert( it != NULL && "Unexpected end of block" );
|
nkeynes@1006 | 272 | assert( it->cond >= CC_TRUE && it->cond <= CC_SGT && "Invalid condition code" );
|
nkeynes@1006 | 273 | if( XOP_HAS_0_OPERANDS(it) ) {
|
nkeynes@1006 | 274 | assert( it->operand[0].type == NO_OPERAND && it->operand[1].type == NO_OPERAND );
|
nkeynes@1006 | 275 | } else if( XOP_HAS_1_OPERAND(it) ) {
|
nkeynes@1006 | 276 | assert( it->operand[0].type != NO_OPERAND && it->operand[1].type == NO_OPERAND );
|
nkeynes@1006 | 277 | } else if( XOP_HAS_2_OPERANDS(it) ) {
|
nkeynes@1006 | 278 | assert( it->operand[0].type != NO_OPERAND && it->operand[1].type != NO_OPERAND );
|
nkeynes@1006 | 279 | }
|
nkeynes@1006 | 280 |
|
nkeynes@1006 | 281 | if( it->opcode == OP_ENTER ) {
|
nkeynes@1006 | 282 | assert( it->prev == NULL && "Enter instruction must have no predecessors" );
|
nkeynes@1006 | 283 | assert( it == start && "Enter instruction must occur at the start of the block" );
|
nkeynes@1006 | 284 | assert( it->operand[0].type == INT_IMM_OPERAND && "Enter instruction must have an immediate operand" );
|
nkeynes@1006 | 285 | } else if( it->opcode == OP_ST || it->opcode == OP_LD ) {
|
nkeynes@1006 | 286 | assert( it->cond != CC_TRUE && "Opcode not permitted with True condition code" );
|
nkeynes@1006 | 287 | }
|
nkeynes@1006 | 288 |
|
nkeynes@1006 | 289 | if( XOP_WRITES_OP1(it) ) {
|
nkeynes@1006 | 290 | assert( (it->operand[0].type == SOURCE_REGISTER_OPERAND ||
|
nkeynes@1006 | 291 | it->operand[0].type == TARGET_REGISTER_OPERAND) && "Writable operand 1 requires a register" );
|
nkeynes@1006 | 292 | }
|
nkeynes@1006 | 293 | if( XOP_WRITES_OP2(it) ) {
|
nkeynes@1006 | 294 | assert( (it->operand[1].type == SOURCE_REGISTER_OPERAND ||
|
nkeynes@1006 | 295 | it->operand[1].type == TARGET_REGISTER_OPERAND) && "Writable operand 2 requires a register" );
|
nkeynes@1006 | 296 | }
|
nkeynes@1006 | 297 |
|
nkeynes@1006 | 298 | if( XOP_READS_FLAGS(it) ) {
|
nkeynes@1006 | 299 | assert( flags_written && "Flags used without prior definition in block" );
|
nkeynes@1006 | 300 | }
|
nkeynes@1006 | 301 | if( XOP_WRITES_FLAGS(it) ) {
|
nkeynes@1006 | 302 | flags_written = 1;
|
nkeynes@1006 | 303 | }
|
nkeynes@1006 | 304 |
|
nkeynes@1006 | 305 | if( XOP_HAS_EXCEPTION(it) ) {
|
nkeynes@1006 | 306 | assert( it->exc != NULL && "Missing exception block" );
|
nkeynes@1006 | 307 | assert( it->exc->prev == it && "Exception back-link broken" );
|
nkeynes@1006 | 308 | xir_verify_block( it->exc, NULL ); // Verify exception sub-block
|
nkeynes@1006 | 309 | } else {
|
nkeynes@1006 | 310 | assert( it->exc == NULL && "Unexpected exception block" );
|
nkeynes@1006 | 311 | }
|
nkeynes@1006 | 312 | if( XOP_IS_TERMINATOR(it) ) {
|
nkeynes@1006 | 313 | assert( it->next == NULL && "Unexpected next instruction on terminator" );
|
nkeynes@1006 | 314 | } else {
|
nkeynes@1006 | 315 | assert( it->next != NULL && "Missing terminator instruction at end of block" );
|
nkeynes@1006 | 316 | assert( it->next->prev == it && "Linked-list chain broken" );
|
nkeynes@1006 | 317 | }
|
nkeynes@1006 | 318 | if( it == end )
|
nkeynes@1006 | 319 | break;
|
nkeynes@1006 | 320 | }
|
nkeynes@1006 | 321 | }
|
nkeynes@1006 | 322 |
|
nkeynes@1006 | 323 | 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 | 324 | {
|
nkeynes@1006 | 325 | xbb->ir_ptr->opcode = op;
|
nkeynes@1006 | 326 | xbb->ir_ptr->cond = CC_TRUE;
|
nkeynes@1006 | 327 | xbb->ir_ptr->operand[0].type = arg0type;
|
nkeynes@1006 | 328 | xbb->ir_ptr->operand[0].value.i = arg0;
|
nkeynes@1006 | 329 | xbb->ir_ptr->operand[1].type = arg1type;
|
nkeynes@1006 | 330 | xbb->ir_ptr->operand[1].value.i = arg1;
|
nkeynes@1006 | 331 | xbb->ir_ptr->exc = NULL;
|
nkeynes@1006 | 332 | xbb->ir_ptr->next = xbb->ir_ptr+1;
|
nkeynes@1006 | 333 | (xbb->ir_ptr+1)->prev = xbb->ir_ptr;
|
nkeynes@1006 | 334 | return xbb->ir_ptr++;
|
nkeynes@1006 | 335 | }
|
nkeynes@1006 | 336 |
|
nkeynes@1006 | 337 | 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 | 338 | {
|
nkeynes@1006 | 339 | xbb->ir_ptr->opcode = op;
|
nkeynes@1006 | 340 | xbb->ir_ptr->cond = cc;
|
nkeynes@1006 | 341 | xbb->ir_ptr->operand[0].type = arg0type;
|
nkeynes@1006 | 342 | xbb->ir_ptr->operand[0].value.i = arg0;
|
nkeynes@1006 | 343 | xbb->ir_ptr->operand[1].type = arg1type;
|
nkeynes@1006 | 344 | xbb->ir_ptr->operand[1].value.i = arg1;
|
nkeynes@1006 | 345 | xbb->ir_ptr->exc = NULL;
|
nkeynes@1006 | 346 | xbb->ir_ptr->next = xbb->ir_ptr+1;
|
nkeynes@1006 | 347 | (xbb->ir_ptr+1)->prev = xbb->ir_ptr;
|
nkeynes@1006 | 348 | return xbb->ir_ptr++;
|
nkeynes@1006 | 349 | }
|
nkeynes@1006 | 350 |
|
nkeynes@1006 | 351 | xir_op_t xir_append_float_op2( xir_basic_block_t xbb, int op, float imm1, int arg1type, uint32_t arg1 )
|
nkeynes@1006 | 352 | {
|
nkeynes@1006 | 353 | xbb->ir_ptr->opcode = op;
|
nkeynes@1006 | 354 | xbb->ir_ptr->cond = CC_TRUE;
|
nkeynes@1006 | 355 | xbb->ir_ptr->operand[0].type = FLOAT_IMM_OPERAND;
|
nkeynes@1006 | 356 | xbb->ir_ptr->operand[0].value.i = imm1;
|
nkeynes@1006 | 357 | xbb->ir_ptr->operand[1].type = arg1type;
|
nkeynes@1006 | 358 | xbb->ir_ptr->operand[1].value.i = arg1;
|
nkeynes@1006 | 359 | xbb->ir_ptr->exc = NULL;
|
nkeynes@1006 | 360 | xbb->ir_ptr->next = xbb->ir_ptr+1;
|
nkeynes@1006 | 361 | (xbb->ir_ptr+1)->prev = xbb->ir_ptr;
|
nkeynes@1006 | 362 | return xbb->ir_ptr++;
|
nkeynes@1006 | 363 | }
|
nkeynes@1006 | 364 |
|
nkeynes@1006 | 365 | xir_op_t xir_append_ptr_op2( xir_basic_block_t xbb, int op, void *arg0, int arg1type, uint32_t arg1 )
|
nkeynes@1006 | 366 | {
|
nkeynes@1006 | 367 | xbb->ir_ptr->opcode = op;
|
nkeynes@1006 | 368 | xbb->ir_ptr->cond = CC_TRUE;
|
nkeynes@1006 | 369 | xbb->ir_ptr->operand[0].type = POINTER_OPERAND;
|
nkeynes@1006 | 370 | xbb->ir_ptr->operand[0].value.p = arg0;
|
nkeynes@1006 | 371 | xbb->ir_ptr->operand[1].type = arg1type;
|
nkeynes@1006 | 372 | xbb->ir_ptr->operand[1].value.i = arg1;
|
nkeynes@1006 | 373 | xbb->ir_ptr->exc = NULL;
|
nkeynes@1006 | 374 | xbb->ir_ptr->next = xbb->ir_ptr+1;
|
nkeynes@1006 | 375 | (xbb->ir_ptr+1)->prev = xbb->ir_ptr;
|
nkeynes@1006 | 376 | return xbb->ir_ptr++;
|
nkeynes@1006 | 377 | }
|
nkeynes@1006 | 378 |
|
nkeynes@1006 | 379 | void xir_insert_op( xir_op_t op, xir_op_t before )
|
nkeynes@1006 | 380 | {
|
nkeynes@1006 | 381 | op->prev = before->prev;
|
nkeynes@1006 | 382 | op->next = before;
|
nkeynes@1006 | 383 | before->prev->next = op;
|
nkeynes@1006 | 384 | before->prev = op;
|
nkeynes@1006 | 385 | }
|
nkeynes@1006 | 386 |
|
nkeynes@1006 | 387 | void xir_insert_block( xir_op_t start, xir_op_t end, xir_op_t before )
|
nkeynes@1006 | 388 | {
|
nkeynes@1006 | 389 | start->prev = before->prev;
|
nkeynes@1006 | 390 | end->next = before;
|
nkeynes@1006 | 391 | before->prev->next = start;
|
nkeynes@1006 | 392 | before->prev = end;
|
nkeynes@1006 | 393 | }
|
nkeynes@1006 | 394 |
|
nkeynes@1006 | 395 | void xir_remove_op( xir_op_t op )
|
nkeynes@1006 | 396 | {
|
nkeynes@1006 | 397 | if( op->next != NULL ) {
|
nkeynes@1006 | 398 | op->next->prev = op->prev;
|
nkeynes@1006 | 399 | }
|
nkeynes@1006 | 400 | if( op->prev != NULL ) {
|
nkeynes@1006 | 401 | if( op->prev->next == op ) {
|
nkeynes@1006 | 402 | op->prev->next = op->next;
|
nkeynes@1006 | 403 | } else {
|
nkeynes@1006 | 404 | assert( op->prev->exc == op );
|
nkeynes@1006 | 405 | op->prev->exc = op->next;
|
nkeynes@1006 | 406 | }
|
nkeynes@1006 | 407 | }
|
nkeynes@1006 | 408 | }
|
nkeynes@1006 | 409 |
|
nkeynes@1006 | 410 | int xir_get_operand_size( xir_op_t op, int operand )
|
nkeynes@1006 | 411 | {
|
nkeynes@1006 | 412 | int mode = XIR_OPCODE_TABLE[op->opcode].mode;
|
nkeynes@1006 | 413 | if( operand == 0 ) {
|
nkeynes@1006 | 414 | mode >>= 4;
|
nkeynes@1006 | 415 | } else {
|
nkeynes@1006 | 416 | mode >>= 8;
|
nkeynes@1006 | 417 | }
|
nkeynes@1006 | 418 | mode &= 0x07;
|
nkeynes@1006 | 419 | return XIR_OPERAND_SIZE[mode];
|
nkeynes@1006 | 420 | }
|
nkeynes@1006 | 421 |
|
nkeynes@1006 | 422 | void xir_print_block( FILE *out, xir_op_t start, xir_op_t end )
|
nkeynes@1006 | 423 | {
|
nkeynes@1006 | 424 | xir_op_t it = start;
|
nkeynes@1006 | 425 | xir_op_t exc = NULL;
|
nkeynes@1006 | 426 |
|
nkeynes@1006 | 427 | while( it != NULL ) {
|
nkeynes@1006 | 428 | if( it->exc ) {
|
nkeynes@1006 | 429 | while( exc ) {
|
nkeynes@1006 | 430 | fprintf( out, "%40c ", ' ' );
|
nkeynes@1006 | 431 | xir_print_instruction( out, exc );
|
nkeynes@1006 | 432 | fprintf( out, "\n" );
|
nkeynes@1006 | 433 | exc = exc->next;
|
nkeynes@1006 | 434 | }
|
nkeynes@1006 | 435 | exc = it->exc;
|
nkeynes@1006 | 436 | }
|
nkeynes@1006 | 437 | xir_print_instruction( out, it );
|
nkeynes@1006 | 438 | if( exc ) {
|
nkeynes@1006 | 439 | if( it->exc ) {
|
nkeynes@1006 | 440 | fprintf( out, "=> " );
|
nkeynes@1006 | 441 | } else {
|
nkeynes@1006 | 442 | fprintf( out, " " );
|
nkeynes@1006 | 443 | }
|
nkeynes@1006 | 444 | xir_print_instruction( out, exc );
|
nkeynes@1006 | 445 | exc = exc->next;
|
nkeynes@1006 | 446 | }
|
nkeynes@1006 | 447 | fprintf( out, "\n" );
|
nkeynes@1006 | 448 | if( it == end )
|
nkeynes@1006 | 449 | break;
|
nkeynes@1006 | 450 | it = it->next;
|
nkeynes@1006 | 451 | }
|
nkeynes@1006 | 452 | }
|
nkeynes@1006 | 453 |
|
nkeynes@1006 | 454 | void xir_dump_block( xir_op_t start, xir_op_t end )
|
nkeynes@1006 | 455 | {
|
nkeynes@1006 | 456 | xir_print_block( stdout, start, end );
|
nkeynes@1006 | 457 | xir_verify_block( start, end );
|
nkeynes@1006 | 458 | }
|