filename | src/xlat/xir.c |
changeset | 1011:fdd58619b760 |
prev | 1006:3a169c224c12 |
next | 1012:0b8cc74ac83a |
author | nkeynes |
date | Sun Apr 12 07:24:45 2009 +0000 (14 years ago) |
branch | xlat-refactor |
permissions | -rw-r--r-- |
last change | Restructure operand types - rename to forms to avoid conflict for actual data types temporary operands are now a first class form remove explicit types for immediates - now implied by opcode Initial work on promote-source-reg pass |
file | annotate | diff | log | raw |
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@1011 | 23 | #include "xlat/xlat.h" |
nkeynes@1006 | 24 | |
nkeynes@1006 | 25 | static const struct xir_symbol_entry *xir_symbol_table = NULL; |
nkeynes@1006 | 26 | |
nkeynes@1006 | 27 | static const char *XIR_CC_NAMES[] = { |
nkeynes@1006 | 28 | "ov", "no", "uge", "ult", "ule", "ugt", "eq", "ne", |
nkeynes@1006 | 29 | "neg", "pos", "sge", "slt", "sle", "sgt" }; |
nkeynes@1011 | 30 | static const char XIR_TYPE_CODES[] = { 'l', 'q', 'f', 'd', 'v', 'm' }; |
nkeynes@1011 | 31 | |
nkeynes@1011 | 32 | const int XIR_OPERAND_SIZE[] = { 4, 8, 4, 8, 16, 64, (sizeof(void *)), 0 }; |
nkeynes@1011 | 33 | |
nkeynes@1006 | 34 | |
nkeynes@1006 | 35 | const struct xir_opcode_entry XIR_OPCODE_TABLE[] = { |
nkeynes@1006 | 36 | { "NOP", OPM_NO }, |
nkeynes@1006 | 37 | { "BARRIER", OPM_NO | OPM_CLB }, |
nkeynes@1006 | 38 | { "DEC", OPM_RW_TW }, |
nkeynes@1006 | 39 | { "LD", OPM_R | OPM_TW }, |
nkeynes@1006 | 40 | { "ST", OPM_W | OPM_TR }, |
nkeynes@1006 | 41 | { "RESTFLAGS", OPM_R | OPM_TW }, |
nkeynes@1006 | 42 | { "SAVEFLAGS", OPM_W | OPM_TR }, |
nkeynes@1006 | 43 | { "ENTER", OPM_R }, |
nkeynes@1006 | 44 | { "BRREL", OPM_R | OPM_TERM }, |
nkeynes@1006 | 45 | { "BR", OPM_R | OPM_TERM }, |
nkeynes@1006 | 46 | { "CALL0", OPM_R | OPM_CLB }, |
nkeynes@1006 | 47 | { "OCBI", OPM_R_EXC }, |
nkeynes@1006 | 48 | { "OCBP", OPM_R_EXC }, |
nkeynes@1006 | 49 | { "OCBWB", OPM_R_EXC }, |
nkeynes@1006 | 50 | { "PREF", OPM_R_EXC }, |
nkeynes@1006 | 51 | |
nkeynes@1006 | 52 | { "MOV", OPM_R_W }, |
nkeynes@1006 | 53 | { "MOVQ", OPM_R_W|OPM_Q_Q }, |
nkeynes@1006 | 54 | { "MOVV", OPM_R_W|OPM_V_V }, |
nkeynes@1006 | 55 | { "MOVM", OPM_R_W|OPM_M_M }, |
nkeynes@1006 | 56 | { "MOVSX8", OPM_R_W }, |
nkeynes@1006 | 57 | { "MOVSX16", OPM_R_W }, |
nkeynes@1006 | 58 | { "MOVSX32", OPM_R_W|OPM_I_Q }, |
nkeynes@1006 | 59 | { "MOVZX8", OPM_R_W }, |
nkeynes@1006 | 60 | { "MOVZX16", OPM_R_W }, |
nkeynes@1006 | 61 | { "MOVZX32", OPM_R_W|OPM_I_Q }, |
nkeynes@1006 | 62 | |
nkeynes@1006 | 63 | { "ADD", OPM_R_RW }, |
nkeynes@1006 | 64 | { "ADDS", OPM_R_RW_TW }, |
nkeynes@1006 | 65 | { "ADDC", OPM_R_RW_TR }, |
nkeynes@1006 | 66 | { "ADDCS", OPM_R_RW_TRW }, |
nkeynes@1006 | 67 | { "AND", OPM_R_RW }, |
nkeynes@1006 | 68 | { "ANDS", OPM_R_RW_TW }, |
nkeynes@1006 | 69 | { "CMP", OPM_R_R_TW }, |
nkeynes@1006 | 70 | { "DIV", OPM_R_RW }, |
nkeynes@1006 | 71 | { "DIVS", OPM_R_RW_TW }, |
nkeynes@1006 | 72 | { "MUL", OPM_R_RW }, |
nkeynes@1006 | 73 | { "MULS", OPM_R_RW_TW }, |
nkeynes@1006 | 74 | { "MULQ", OPM_R_RW|OPM_Q_Q }, |
nkeynes@1006 | 75 | { "MULQS", OPM_R_RW_TW|OPM_Q_Q }, |
nkeynes@1006 | 76 | { "NEG", OPM_R_W }, |
nkeynes@1006 | 77 | { "NEGS", OPM_R_W_TW }, |
nkeynes@1006 | 78 | { "NOT", OPM_R_W }, |
nkeynes@1006 | 79 | { "NOTS", OPM_R_W_TW }, |
nkeynes@1006 | 80 | { "OR", OPM_R_RW }, |
nkeynes@1006 | 81 | { "ORS", OPM_R_RW_TW }, |
nkeynes@1006 | 82 | { "RCL", OPM_R_RW_TRW }, |
nkeynes@1006 | 83 | { "RCR", OPM_R_RW_TRW }, |
nkeynes@1006 | 84 | { "ROL", OPM_R_RW }, |
nkeynes@1006 | 85 | { "ROLS", OPM_R_RW_TW }, |
nkeynes@1006 | 86 | { "ROR", OPM_R_RW }, |
nkeynes@1006 | 87 | { "RORS", OPM_R_RW_TW }, |
nkeynes@1006 | 88 | { "SAR", OPM_R_RW }, |
nkeynes@1006 | 89 | { "SARS", OPM_R_RW_TW }, |
nkeynes@1006 | 90 | { "SDIV", OPM_R_RW }, |
nkeynes@1006 | 91 | { "SDIVS", OPM_R_RW_TW }, |
nkeynes@1006 | 92 | { "SLL", OPM_R_RW }, |
nkeynes@1006 | 93 | { "SLLS", OPM_R_RW_TW }, |
nkeynes@1006 | 94 | { "SLR", OPM_R_RW }, |
nkeynes@1006 | 95 | { "SLRS", OPM_R_RW_TW }, |
nkeynes@1006 | 96 | { "SUB", OPM_R_RW }, |
nkeynes@1006 | 97 | { "SUBS", OPM_R_RW_TW }, |
nkeynes@1006 | 98 | { "SUBB", OPM_R_RW }, |
nkeynes@1006 | 99 | { "SUBBS", OPM_R_RW_TRW }, |
nkeynes@1006 | 100 | { "SHUFFLE", OPM_R_RW }, |
nkeynes@1006 | 101 | { "TST", OPM_R_R_TW }, |
nkeynes@1006 | 102 | { "XOR", OPM_R_RW }, |
nkeynes@1006 | 103 | { "XORS", OPM_R_RW_TW }, |
nkeynes@1006 | 104 | |
nkeynes@1006 | 105 | { "ABSD", OPM_DR_DW }, |
nkeynes@1006 | 106 | { "ABSF", OPM_FR_FW }, |
nkeynes@1006 | 107 | { "ABSV", OPM_VR_VW }, |
nkeynes@1006 | 108 | { "ADDD", OPM_DR_DRW }, |
nkeynes@1006 | 109 | { "ADDF", OPM_FR_FRW }, |
nkeynes@1006 | 110 | { "ADDV", OPM_VR_VRW }, |
nkeynes@1006 | 111 | { "CMPD", OPM_DR_DR_TW }, |
nkeynes@1006 | 112 | { "CMPF", OPM_FR_FR_TW }, |
nkeynes@1006 | 113 | { "DIVD", OPM_DR_DRW }, |
nkeynes@1006 | 114 | { "DIVF", OPM_FR_FRW }, |
nkeynes@1006 | 115 | { "DIVV", OPM_VR_VRW }, |
nkeynes@1006 | 116 | { "MULD", OPM_DR_DRW }, |
nkeynes@1006 | 117 | { "MULF", OPM_FR_FRW }, |
nkeynes@1006 | 118 | { "MULV", OPM_VR_VRW }, |
nkeynes@1006 | 119 | { "NEGD", OPM_DR_DW }, |
nkeynes@1006 | 120 | { "NEGF", OPM_FR_FW }, |
nkeynes@1006 | 121 | { "NEGV", OPM_VR_VW }, |
nkeynes@1006 | 122 | { "SQRTD", OPM_DR_DW }, |
nkeynes@1006 | 123 | { "SQRTF", OPM_FR_FW }, |
nkeynes@1006 | 124 | { "SQRTV", OPM_VR_VW }, |
nkeynes@1006 | 125 | { "RSQRTD", OPM_DR_DW }, |
nkeynes@1006 | 126 | { "RSQRTF", OPM_FR_FW }, |
nkeynes@1006 | 127 | { "RSQRTV", OPM_VR_VW }, |
nkeynes@1006 | 128 | { "SUBD", OPM_DR_DRW }, |
nkeynes@1006 | 129 | { "SUBF", OPM_FR_FRW }, |
nkeynes@1006 | 130 | { "SUBV", OPM_VR_VRW }, |
nkeynes@1006 | 131 | |
nkeynes@1006 | 132 | { "DTOF", OPM_R_W|OPM_D_F }, /* Round according to rounding mode */ |
nkeynes@1006 | 133 | { "DTOI", OPM_R_W|OPM_D_I }, /* Truncate + saturate to signed 32-bits */ |
nkeynes@1006 | 134 | { "FTOD", OPM_R_W|OPM_F_D }, /* Exact */ |
nkeynes@1006 | 135 | { "FTOI", OPM_R_W|OPM_F_I }, /* Truncate + saturate to signed 32-bits */ |
nkeynes@1006 | 136 | { "ITOD", OPM_R_W|OPM_I_D }, /* Exact */ |
nkeynes@1006 | 137 | { "ITOF", OPM_R_W|OPM_I_F }, /* Round according to rounding mode */ |
nkeynes@1006 | 138 | |
nkeynes@1006 | 139 | { "SINCOSF", OPM_FR_FRW }, |
nkeynes@1006 | 140 | |
nkeynes@1006 | 141 | /* Compute the dot product of two vectors - the result is |
nkeynes@1006 | 142 | * stored in the last element of the target operand (and the |
nkeynes@1006 | 143 | * other elements are unchanged) |
nkeynes@1006 | 144 | */ |
nkeynes@1006 | 145 | { "DOTPRODV", OPM_R_RW|OPM_V_V }, |
nkeynes@1006 | 146 | /* Perform the matrix multiplication V * M and place the result |
nkeynes@1006 | 147 | * in V. |
nkeynes@1006 | 148 | */ |
nkeynes@1006 | 149 | { "MATMULV", OPM_R_RW|OPM_V_M }, |
nkeynes@1006 | 150 | |
nkeynes@1006 | 151 | { "LOAD.B", OPM_R_W_EXC }, |
nkeynes@1006 | 152 | { "LOAD.BFW", OPM_R_W_EXC }, |
nkeynes@1006 | 153 | { "LOAD.W", OPM_R_W_EXC }, |
nkeynes@1006 | 154 | { "LOAD.L", OPM_R_W_EXC }, |
nkeynes@1006 | 155 | { "LOAD.Q", OPM_R_W_EXC|OPM_I_Q }, |
nkeynes@1006 | 156 | { "STORE.B", OPM_R_R_EXC }, |
nkeynes@1006 | 157 | { "STORE.W", OPM_R_R_EXC }, |
nkeynes@1006 | 158 | { "STORE.L", OPM_R_R_EXC }, |
nkeynes@1006 | 159 | { "STORE.Q", OPM_R_R_EXC|OPM_I_Q }, |
nkeynes@1006 | 160 | { "STORE.LCA", OPM_R_R_EXC }, |
nkeynes@1006 | 161 | |
nkeynes@1006 | 162 | { "BRCOND", OPM_R_R|OPM_TR | OPM_TERM }, |
nkeynes@1006 | 163 | { "BRCONDDEL", OPM_R_R|OPM_TR }, |
nkeynes@1006 | 164 | { "RAISE/ME", OPM_R_R | OPM_EXC }, |
nkeynes@1006 | 165 | { "RAISE/MNE", OPM_R_R | OPM_EXC }, |
nkeynes@1006 | 166 | |
nkeynes@1011 | 167 | /* Native/pointer operations */ |
nkeynes@1006 | 168 | { "CALL/LUT", OPM_R_R | OPM_EXC }, |
nkeynes@1006 | 169 | { "CALL1", OPM_R_R | OPM_CLB }, |
nkeynes@1006 | 170 | { "CALLR", OPM_R_W | OPM_CLB }, |
nkeynes@1011 | 171 | { "LOADPTRL", OPM_R_W | 0x060 }, |
nkeynes@1011 | 172 | { "LOADPTRQ", OPM_R_W | 0x160 }, |
nkeynes@1011 | 173 | { "XLAT", OPM_R_RW | 0x600 }, /* Xlat Rm, Rn - Read native [Rm+Rn] and store in Rn */ |
nkeynes@1006 | 174 | |
nkeynes@1006 | 175 | { "ADDQSAT32", OPM_R_R | OPM_CLBT|OPM_Q_Q }, |
nkeynes@1006 | 176 | { "ADDQSAT48", OPM_R_R | OPM_CLBT|OPM_Q_Q }, |
nkeynes@1006 | 177 | { "CMP/STR", OPM_R_R_TW | OPM_CLBT }, |
nkeynes@1006 | 178 | { "DIV1", OPM_R_RW_TRW | OPM_CLBT }, |
nkeynes@1006 | 179 | { "SHAD", OPM_R_RW | OPM_CLBT }, |
nkeynes@1006 | 180 | { "SHLD", OPM_R_RW | OPM_CLBT }, |
nkeynes@1006 | 181 | |
nkeynes@1006 | 182 | }; |
nkeynes@1006 | 183 | |
nkeynes@1011 | 184 | void xir_clear_basic_block( xir_basic_block_t xbb ) |
nkeynes@1006 | 185 | { |
nkeynes@1011 | 186 | xbb->next_temp_reg = 0; |
nkeynes@1011 | 187 | xir_alloc_temp_reg( xbb, XTY_LONG, -1 ); |
nkeynes@1011 | 188 | xir_alloc_temp_reg( xbb, XTY_LONG, -1 ); |
nkeynes@1011 | 189 | xir_alloc_temp_reg( xbb, XTY_LONG, -1 ); |
nkeynes@1011 | 190 | xir_alloc_temp_reg( xbb, XTY_QUAD, -1 ); |
nkeynes@1011 | 191 | xir_alloc_temp_reg( xbb, XTY_QUAD, -1 ); |
nkeynes@1011 | 192 | } |
nkeynes@1011 | 193 | |
nkeynes@1011 | 194 | uint32_t xir_alloc_temp_reg( xir_basic_block_t xbb, xir_type_t type, int home ) |
nkeynes@1011 | 195 | { |
nkeynes@1011 | 196 | assert( xbb->next_temp_reg <= MAX_TEMP_REGISTER ); |
nkeynes@1011 | 197 | int reg = xbb->next_temp_reg++; |
nkeynes@1011 | 198 | xbb->temp_regs[reg].type = type; |
nkeynes@1011 | 199 | xbb->temp_regs[reg].home_register = home; |
nkeynes@1011 | 200 | return reg; |
nkeynes@1006 | 201 | } |
nkeynes@1006 | 202 | |
nkeynes@1006 | 203 | void xir_set_symbol_table( const struct xir_symbol_entry *symtab ) |
nkeynes@1006 | 204 | { |
nkeynes@1006 | 205 | xir_symbol_table = symtab; |
nkeynes@1006 | 206 | } |
nkeynes@1006 | 207 | |
nkeynes@1006 | 208 | const char *xir_lookup_symbol( const void *ptr ) |
nkeynes@1006 | 209 | { |
nkeynes@1006 | 210 | if( xir_symbol_table != NULL ) { |
nkeynes@1006 | 211 | const struct xir_symbol_entry *p; |
nkeynes@1006 | 212 | for( p = xir_symbol_table; p->name != NULL; p++ ) { |
nkeynes@1006 | 213 | if( p->ptr == ptr ) { |
nkeynes@1006 | 214 | return p->name; |
nkeynes@1006 | 215 | } |
nkeynes@1006 | 216 | } |
nkeynes@1006 | 217 | } |
nkeynes@1006 | 218 | return NULL; |
nkeynes@1006 | 219 | } |
nkeynes@1006 | 220 | |
nkeynes@1011 | 221 | static int xir_snprint_operand( char *buf, int buflen, xir_basic_block_t xbb, xir_operand_t op, xir_type_t ty ) |
nkeynes@1006 | 222 | { |
nkeynes@1006 | 223 | const char *name; |
nkeynes@1011 | 224 | xir_temp_register_t tmp; |
nkeynes@1011 | 225 | |
nkeynes@1011 | 226 | switch( op->form ) { |
nkeynes@1011 | 227 | case IMMEDIATE_OPERAND: |
nkeynes@1011 | 228 | switch( ty ) { |
nkeynes@1011 | 229 | case XTY_LONG: |
nkeynes@1011 | 230 | return snprintf( buf, buflen, "$0x%x", op->value.i ); |
nkeynes@1011 | 231 | case XTY_QUAD: |
nkeynes@1011 | 232 | return snprintf( buf, buflen, "$0x%lld", op->value.q ); |
nkeynes@1011 | 233 | case XTY_FLOAT: |
nkeynes@1011 | 234 | return snprintf( buf, buflen, "%f", op->value.f ); |
nkeynes@1011 | 235 | case XTY_DOUBLE: |
nkeynes@1011 | 236 | return snprintf( buf, buflen, "%f", op->value.f ); |
nkeynes@1011 | 237 | case XTY_PTR: |
nkeynes@1011 | 238 | name = xir_lookup_symbol( op->value.p ); |
nkeynes@1011 | 239 | if( name != NULL ) { |
nkeynes@1011 | 240 | return snprintf( buf, buflen, "*%s", name ); |
nkeynes@1011 | 241 | } else { |
nkeynes@1011 | 242 | return snprintf( buf, buflen, "*%p", op->value.p ); |
nkeynes@1011 | 243 | } |
nkeynes@1011 | 244 | default: |
nkeynes@1011 | 245 | return snprintf( buf, buflen, "ILLOP" ); |
nkeynes@1011 | 246 | } |
nkeynes@1011 | 247 | break; |
nkeynes@1011 | 248 | case SOURCE_OPERAND: |
nkeynes@1011 | 249 | name = xbb->source->get_register_name(op->value.i, ty); |
nkeynes@1006 | 250 | if( name != NULL ) { |
nkeynes@1011 | 251 | return snprintf( buf, buflen, "%%%s", name ); |
nkeynes@1006 | 252 | } else { |
nkeynes@1011 | 253 | return snprintf( buf, buflen, "%%src%d", op->value.i ); |
nkeynes@1006 | 254 | } |
nkeynes@1011 | 255 | break; |
nkeynes@1011 | 256 | case TEMP_OPERAND: |
nkeynes@1011 | 257 | tmp = &xbb->temp_regs[op->value.i]; |
nkeynes@1011 | 258 | if( tmp->home_register != -1 && |
nkeynes@1011 | 259 | (name = xbb->source->get_register_name(tmp->home_register,ty)) != NULL ) { |
nkeynes@1011 | 260 | return snprintf( buf, buflen, "%%%s.%c%d", name, |
nkeynes@1011 | 261 | XIR_TYPE_CODES[tmp->type], op->value.i ); |
nkeynes@1006 | 262 | } else { |
nkeynes@1011 | 263 | return snprintf( buf, buflen, "%%tmp%c%d", |
nkeynes@1011 | 264 | XIR_TYPE_CODES[tmp->type], op->value.i ); |
nkeynes@1006 | 265 | } |
nkeynes@1011 | 266 | case DEST_OPERAND: |
nkeynes@1011 | 267 | name = xbb->target->get_register_name(op->value.i, ty); |
nkeynes@1011 | 268 | if( name != NULL ) { |
nkeynes@1011 | 269 | return snprintf( buf, buflen, "%%%s", name ); |
nkeynes@1006 | 270 | } else { |
nkeynes@1011 | 271 | return snprintf( buf, buflen, "%%dst%d", op->value.i ); |
nkeynes@1006 | 272 | } |
nkeynes@1006 | 273 | default: |
nkeynes@1006 | 274 | return snprintf( buf, buflen, "ILLOP" ); |
nkeynes@1006 | 275 | } |
nkeynes@1006 | 276 | } |
nkeynes@1006 | 277 | |
nkeynes@1011 | 278 | static void xir_print_instruction( FILE *out, xir_basic_block_t xbb, xir_op_t i ) |
nkeynes@1006 | 279 | { |
nkeynes@1006 | 280 | char operands[64] = ""; |
nkeynes@1006 | 281 | |
nkeynes@1011 | 282 | if( i->operand[0].form != NO_OPERAND ) { |
nkeynes@1011 | 283 | int pos = xir_snprint_operand( operands, sizeof(operands), xbb, &i->operand[0], |
nkeynes@1011 | 284 | XOP_OPTYPE(i,0)); |
nkeynes@1011 | 285 | if( i->operand[1].form != NO_OPERAND ) { |
nkeynes@1006 | 286 | strncat( operands, ", ", sizeof(operands)-pos ); |
nkeynes@1006 | 287 | pos += 2; |
nkeynes@1011 | 288 | xir_snprint_operand( operands+pos, sizeof(operands)-pos, xbb, &i->operand[1], |
nkeynes@1011 | 289 | XOP_OPTYPE(i,1) ); |
nkeynes@1006 | 290 | } |
nkeynes@1006 | 291 | } |
nkeynes@1006 | 292 | if( i->cond == CC_TRUE ) { |
nkeynes@1006 | 293 | fprintf( out, "%-9s %-30s", XIR_OPCODE_TABLE[i->opcode].name, operands ); |
nkeynes@1006 | 294 | } else { |
nkeynes@1006 | 295 | char buf[16]; |
nkeynes@1006 | 296 | snprintf( buf, 16, "%s%s", XIR_OPCODE_TABLE[i->opcode].name, XIR_CC_NAMES[i->cond] ); |
nkeynes@1006 | 297 | fprintf( out, "%-9s %-30s", buf, operands ); |
nkeynes@1006 | 298 | } |
nkeynes@1006 | 299 | } |
nkeynes@1006 | 300 | |
nkeynes@1006 | 301 | /** |
nkeynes@1006 | 302 | * Sanity check a block of IR to make sure that |
nkeynes@1006 | 303 | * operands match up with the expected values etc |
nkeynes@1006 | 304 | */ |
nkeynes@1011 | 305 | void xir_verify_block( xir_basic_block_t xbb, xir_op_t start, xir_op_t end ) |
nkeynes@1006 | 306 | { |
nkeynes@1006 | 307 | xir_op_t it; |
nkeynes@1006 | 308 | int flags_written = 0; |
nkeynes@1006 | 309 | for( it = start; it != NULL; it = it->next ) { |
nkeynes@1006 | 310 | assert( it != NULL && "Unexpected end of block" ); |
nkeynes@1006 | 311 | assert( it->cond >= CC_TRUE && it->cond <= CC_SGT && "Invalid condition code" ); |
nkeynes@1006 | 312 | if( XOP_HAS_0_OPERANDS(it) ) { |
nkeynes@1011 | 313 | assert( it->operand[0].form == NO_OPERAND && it->operand[1].form == NO_OPERAND ); |
nkeynes@1006 | 314 | } else if( XOP_HAS_1_OPERAND(it) ) { |
nkeynes@1011 | 315 | assert( it->operand[0].form != NO_OPERAND && it->operand[1].form == NO_OPERAND ); |
nkeynes@1006 | 316 | } else if( XOP_HAS_2_OPERANDS(it) ) { |
nkeynes@1011 | 317 | assert( it->operand[0].form != NO_OPERAND && it->operand[1].form != NO_OPERAND ); |
nkeynes@1006 | 318 | } |
nkeynes@1006 | 319 | |
nkeynes@1006 | 320 | if( it->opcode == OP_ENTER ) { |
nkeynes@1006 | 321 | assert( it->prev == NULL && "Enter instruction must have no predecessors" ); |
nkeynes@1006 | 322 | assert( it == start && "Enter instruction must occur at the start of the block" ); |
nkeynes@1011 | 323 | assert( it->operand[0].form == IMMEDIATE_OPERAND && "Enter instruction must have an immediate operand" ); |
nkeynes@1006 | 324 | } else if( it->opcode == OP_ST || it->opcode == OP_LD ) { |
nkeynes@1006 | 325 | assert( it->cond != CC_TRUE && "Opcode not permitted with True condition code" ); |
nkeynes@1006 | 326 | } |
nkeynes@1006 | 327 | |
nkeynes@1006 | 328 | if( XOP_WRITES_OP1(it) ) { |
nkeynes@1011 | 329 | assert( XOP_IS_REG(it,0) && "Writable operand 1 requires a register" ); |
nkeynes@1006 | 330 | } |
nkeynes@1006 | 331 | if( XOP_WRITES_OP2(it) ) { |
nkeynes@1011 | 332 | assert( XOP_IS_REG(it,1) && "Writable operand 2 requires a register" ); |
nkeynes@1006 | 333 | } |
nkeynes@1011 | 334 | |
nkeynes@1011 | 335 | if( XOP_IS_SRC(it,0) ) { |
nkeynes@1011 | 336 | assert( XOP_REG(it,0) <= MAX_SOURCE_REGISTER && "Undefined source register" ); |
nkeynes@1011 | 337 | } else if( XOP_IS_TMP(it,0) ) { |
nkeynes@1011 | 338 | assert( XOP_REG(it,0) < xbb->next_temp_reg && "Undefined temporary register" ); |
nkeynes@1011 | 339 | } else if( XOP_IS_DST(it,0) ) { |
nkeynes@1011 | 340 | assert( XOP_REG(it,0) <= MAX_DEST_REGISTER && "Undefined target register" ); |
nkeynes@1011 | 341 | } |
nkeynes@1011 | 342 | if( XOP_IS_SRC(it,1) ) { |
nkeynes@1011 | 343 | assert( XOP_REG(it,1) <= MAX_SOURCE_REGISTER && "Undefined source register" ); |
nkeynes@1011 | 344 | } else if( XOP_IS_TMP(it,1) ) { |
nkeynes@1011 | 345 | assert( XOP_REG(it,1) < xbb->next_temp_reg && "Undefined temporary register" ); |
nkeynes@1011 | 346 | } else if( XOP_IS_DST(it,1) ) { |
nkeynes@1011 | 347 | assert( XOP_REG(it,1) <= MAX_DEST_REGISTER && "Undefined target register" ); |
nkeynes@1011 | 348 | } |
nkeynes@1011 | 349 | |
nkeynes@1006 | 350 | if( XOP_READS_FLAGS(it) ) { |
nkeynes@1006 | 351 | assert( flags_written && "Flags used without prior definition in block" ); |
nkeynes@1006 | 352 | } |
nkeynes@1006 | 353 | if( XOP_WRITES_FLAGS(it) ) { |
nkeynes@1006 | 354 | flags_written = 1; |
nkeynes@1006 | 355 | } |
nkeynes@1006 | 356 | |
nkeynes@1006 | 357 | if( XOP_HAS_EXCEPTION(it) ) { |
nkeynes@1006 | 358 | assert( it->exc != NULL && "Missing exception block" ); |
nkeynes@1006 | 359 | assert( it->exc->prev == it && "Exception back-link broken" ); |
nkeynes@1011 | 360 | xir_verify_block( xbb, it->exc, NULL ); // Verify exception sub-block |
nkeynes@1006 | 361 | } else { |
nkeynes@1006 | 362 | assert( it->exc == NULL && "Unexpected exception block" ); |
nkeynes@1006 | 363 | } |
nkeynes@1006 | 364 | if( XOP_IS_TERMINATOR(it) ) { |
nkeynes@1006 | 365 | assert( it->next == NULL && "Unexpected next instruction on terminator" ); |
nkeynes@1006 | 366 | } else { |
nkeynes@1006 | 367 | assert( it->next != NULL && "Missing terminator instruction at end of block" ); |
nkeynes@1006 | 368 | assert( it->next->prev == it && "Linked-list chain broken" ); |
nkeynes@1006 | 369 | } |
nkeynes@1006 | 370 | if( it == end ) |
nkeynes@1006 | 371 | break; |
nkeynes@1006 | 372 | } |
nkeynes@1006 | 373 | } |
nkeynes@1006 | 374 | |
nkeynes@1011 | 375 | xir_op_t xir_append_op2( xir_basic_block_t xbb, int op, int arg0form, uint32_t arg0, int arg1form, uint32_t arg1 ) |
nkeynes@1006 | 376 | { |
nkeynes@1006 | 377 | xbb->ir_ptr->opcode = op; |
nkeynes@1006 | 378 | xbb->ir_ptr->cond = CC_TRUE; |
nkeynes@1011 | 379 | xbb->ir_ptr->operand[0].form = arg0form; |
nkeynes@1006 | 380 | xbb->ir_ptr->operand[0].value.i = arg0; |
nkeynes@1011 | 381 | xbb->ir_ptr->operand[1].form = arg1form; |
nkeynes@1006 | 382 | xbb->ir_ptr->operand[1].value.i = arg1; |
nkeynes@1006 | 383 | xbb->ir_ptr->exc = NULL; |
nkeynes@1006 | 384 | xbb->ir_ptr->next = xbb->ir_ptr+1; |
nkeynes@1006 | 385 | (xbb->ir_ptr+1)->prev = xbb->ir_ptr; |
nkeynes@1006 | 386 | return xbb->ir_ptr++; |
nkeynes@1006 | 387 | } |
nkeynes@1006 | 388 | |
nkeynes@1011 | 389 | xir_op_t xir_append_op2cc( xir_basic_block_t xbb, int op, xir_cc_t cc, int arg0form, uint32_t arg0, int arg1form, uint32_t arg1 ) |
nkeynes@1006 | 390 | { |
nkeynes@1006 | 391 | xbb->ir_ptr->opcode = op; |
nkeynes@1006 | 392 | xbb->ir_ptr->cond = cc; |
nkeynes@1011 | 393 | xbb->ir_ptr->operand[0].form = arg0form; |
nkeynes@1006 | 394 | xbb->ir_ptr->operand[0].value.i = arg0; |
nkeynes@1011 | 395 | xbb->ir_ptr->operand[1].form = arg1form; |
nkeynes@1006 | 396 | xbb->ir_ptr->operand[1].value.i = arg1; |
nkeynes@1006 | 397 | xbb->ir_ptr->exc = NULL; |
nkeynes@1006 | 398 | xbb->ir_ptr->next = xbb->ir_ptr+1; |
nkeynes@1006 | 399 | (xbb->ir_ptr+1)->prev = xbb->ir_ptr; |
nkeynes@1006 | 400 | return xbb->ir_ptr++; |
nkeynes@1006 | 401 | } |
nkeynes@1006 | 402 | |
nkeynes@1011 | 403 | xir_op_t xir_append_float_op2( xir_basic_block_t xbb, int op, float imm1, int arg1form, uint32_t arg1 ) |
nkeynes@1006 | 404 | { |
nkeynes@1006 | 405 | xbb->ir_ptr->opcode = op; |
nkeynes@1006 | 406 | xbb->ir_ptr->cond = CC_TRUE; |
nkeynes@1011 | 407 | xbb->ir_ptr->operand[0].form = IMMEDIATE_OPERAND; |
nkeynes@1006 | 408 | xbb->ir_ptr->operand[0].value.i = imm1; |
nkeynes@1011 | 409 | xbb->ir_ptr->operand[1].form = arg1form; |
nkeynes@1006 | 410 | xbb->ir_ptr->operand[1].value.i = arg1; |
nkeynes@1006 | 411 | xbb->ir_ptr->exc = NULL; |
nkeynes@1006 | 412 | xbb->ir_ptr->next = xbb->ir_ptr+1; |
nkeynes@1006 | 413 | (xbb->ir_ptr+1)->prev = xbb->ir_ptr; |
nkeynes@1006 | 414 | return xbb->ir_ptr++; |
nkeynes@1006 | 415 | } |
nkeynes@1006 | 416 | |
nkeynes@1011 | 417 | xir_op_t xir_append_ptr_op2( xir_basic_block_t xbb, int op, void *arg0, int arg1form, uint32_t arg1 ) |
nkeynes@1006 | 418 | { |
nkeynes@1006 | 419 | xbb->ir_ptr->opcode = op; |
nkeynes@1006 | 420 | xbb->ir_ptr->cond = CC_TRUE; |
nkeynes@1011 | 421 | xbb->ir_ptr->operand[0].form = IMMEDIATE_OPERAND; |
nkeynes@1006 | 422 | xbb->ir_ptr->operand[0].value.p = arg0; |
nkeynes@1011 | 423 | xbb->ir_ptr->operand[1].form = arg1form; |
nkeynes@1006 | 424 | xbb->ir_ptr->operand[1].value.i = arg1; |
nkeynes@1006 | 425 | xbb->ir_ptr->exc = NULL; |
nkeynes@1006 | 426 | xbb->ir_ptr->next = xbb->ir_ptr+1; |
nkeynes@1006 | 427 | (xbb->ir_ptr+1)->prev = xbb->ir_ptr; |
nkeynes@1006 | 428 | return xbb->ir_ptr++; |
nkeynes@1006 | 429 | } |
nkeynes@1006 | 430 | |
nkeynes@1006 | 431 | void xir_insert_op( xir_op_t op, xir_op_t before ) |
nkeynes@1006 | 432 | { |
nkeynes@1006 | 433 | op->prev = before->prev; |
nkeynes@1006 | 434 | op->next = before; |
nkeynes@1006 | 435 | before->prev->next = op; |
nkeynes@1006 | 436 | before->prev = op; |
nkeynes@1006 | 437 | } |
nkeynes@1006 | 438 | |
nkeynes@1006 | 439 | void xir_insert_block( xir_op_t start, xir_op_t end, xir_op_t before ) |
nkeynes@1006 | 440 | { |
nkeynes@1006 | 441 | start->prev = before->prev; |
nkeynes@1006 | 442 | end->next = before; |
nkeynes@1006 | 443 | before->prev->next = start; |
nkeynes@1006 | 444 | before->prev = end; |
nkeynes@1006 | 445 | } |
nkeynes@1006 | 446 | |
nkeynes@1006 | 447 | void xir_remove_op( xir_op_t op ) |
nkeynes@1006 | 448 | { |
nkeynes@1006 | 449 | if( op->next != NULL ) { |
nkeynes@1006 | 450 | op->next->prev = op->prev; |
nkeynes@1006 | 451 | } |
nkeynes@1006 | 452 | if( op->prev != NULL ) { |
nkeynes@1006 | 453 | if( op->prev->next == op ) { |
nkeynes@1006 | 454 | op->prev->next = op->next; |
nkeynes@1006 | 455 | } else { |
nkeynes@1006 | 456 | assert( op->prev->exc == op ); |
nkeynes@1006 | 457 | op->prev->exc = op->next; |
nkeynes@1006 | 458 | } |
nkeynes@1006 | 459 | } |
nkeynes@1006 | 460 | } |
nkeynes@1006 | 461 | |
nkeynes@1011 | 462 | void xir_print_block( FILE *out, xir_basic_block_t xbb, xir_op_t start, xir_op_t end ) |
nkeynes@1006 | 463 | { |
nkeynes@1006 | 464 | xir_op_t it = start; |
nkeynes@1006 | 465 | xir_op_t exc = NULL; |
nkeynes@1006 | 466 | |
nkeynes@1006 | 467 | while( it != NULL ) { |
nkeynes@1006 | 468 | if( it->exc ) { |
nkeynes@1006 | 469 | while( exc ) { |
nkeynes@1006 | 470 | fprintf( out, "%40c ", ' ' ); |
nkeynes@1011 | 471 | xir_print_instruction( out, xbb, exc ); |
nkeynes@1006 | 472 | fprintf( out, "\n" ); |
nkeynes@1006 | 473 | exc = exc->next; |
nkeynes@1006 | 474 | } |
nkeynes@1006 | 475 | exc = it->exc; |
nkeynes@1006 | 476 | } |
nkeynes@1011 | 477 | xir_print_instruction( out, xbb, it ); |
nkeynes@1006 | 478 | if( exc ) { |
nkeynes@1006 | 479 | if( it->exc ) { |
nkeynes@1006 | 480 | fprintf( out, "=> " ); |
nkeynes@1006 | 481 | } else { |
nkeynes@1006 | 482 | fprintf( out, " " ); |
nkeynes@1006 | 483 | } |
nkeynes@1011 | 484 | xir_print_instruction( out, xbb, exc ); |
nkeynes@1006 | 485 | exc = exc->next; |
nkeynes@1006 | 486 | } |
nkeynes@1006 | 487 | fprintf( out, "\n" ); |
nkeynes@1006 | 488 | if( it == end ) |
nkeynes@1006 | 489 | break; |
nkeynes@1006 | 490 | it = it->next; |
nkeynes@1006 | 491 | } |
nkeynes@1006 | 492 | } |
nkeynes@1006 | 493 | |
nkeynes@1011 | 494 | void xir_dump_block( xir_basic_block_t xbb ) |
nkeynes@1006 | 495 | { |
nkeynes@1011 | 496 | xir_print_block( stdout, xbb, xbb->ir_begin, xbb->ir_end ); |
nkeynes@1006 | 497 | } |
.