filename | src/xlat/xir.h |
changeset | 1012:0b8cc74ac83a |
prev | 1011:fdd58619b760 |
author | nkeynes |
date | Sun Apr 19 05:14:19 2009 +0000 (15 years ago) |
branch | xlat-refactor |
permissions | -rw-r--r-- |
last change | Remove branch instructions and replace with direct modification of PC + EXIT Add MIN/MAX instructions (for bound checks) Implement x86_target_is_legal Correct a few sh4 instructions |
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 defines the translation IR and associated functions. |
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 | #ifndef lxdream_xir_H |
nkeynes@1006 | 20 | #define lxdream_xir_H 1 |
nkeynes@1006 | 21 | |
nkeynes@1006 | 22 | #include <stdint.h> |
nkeynes@1006 | 23 | |
nkeynes@1006 | 24 | /***************************************************************************** |
nkeynes@1006 | 25 | * |
nkeynes@1006 | 26 | * We use a very simple low-level 2-op instruction form, largely intended to |
nkeynes@1006 | 27 | * closely match the x86 ISA to simplify final code generation. Complex |
nkeynes@1006 | 28 | * instructions are either broken up into simpler ops, or inserted as |
nkeynes@1006 | 29 | * opaque macros. First operand is source, second operand is destination. |
nkeynes@1006 | 30 | * |
nkeynes@1006 | 31 | * Data types are encoded in the instruction: |
nkeynes@1006 | 32 | * Byte (B) 8-bit integer |
nkeynes@1006 | 33 | * Word (W) 16-bit integer |
nkeynes@1006 | 34 | * Long (L) 32-bit integer |
nkeynes@1006 | 35 | * Quad (Q) 64-bit integer |
nkeynes@1006 | 36 | * Float (F) 32-bit floating point |
nkeynes@1006 | 37 | * Double (D) 64-bit floating point |
nkeynes@1006 | 38 | * Vec4 (V) 4x32-bit floating point |
nkeynes@1006 | 39 | * Matrix (M) 4x4x32-bit floating point in column-major order |
nkeynes@1006 | 40 | * This is not an exhaustive list, but it is sufficient to cover all operations |
nkeynes@1006 | 41 | * required for the SH4. |
nkeynes@1006 | 42 | * |
nkeynes@1006 | 43 | * ALU instructions come in two variants, xxxS which modifies the condition |
nkeynes@1006 | 44 | * flags, and the regular xxx version that does not. Implementations are assumed |
nkeynes@1006 | 45 | * to have at least the standard NZVC flags available (or will have to fake it) |
nkeynes@1006 | 46 | * |
nkeynes@1006 | 47 | * Variations in flag behaviour between implementations need to be accounted for |
nkeynes@1006 | 48 | * somehow. |
nkeynes@1006 | 49 | ****************************************************************************/ |
nkeynes@1006 | 50 | |
nkeynes@1006 | 51 | #define MAX_SOURCE_REGISTER 1023 |
nkeynes@1011 | 52 | #define MAX_TEMP_REGISTER 511 |
nkeynes@1011 | 53 | #define MAX_DEST_REGISTER 127 |
nkeynes@1006 | 54 | |
nkeynes@1011 | 55 | /* Preallocated temporaries for convenience */ |
nkeynes@1011 | 56 | #define REG_TMP0 0 |
nkeynes@1011 | 57 | #define REG_TMP1 1 |
nkeynes@1011 | 58 | #define REG_TMP2 2 |
nkeynes@1011 | 59 | #define REG_TMPQ0 3 |
nkeynes@1011 | 60 | #define REG_TMPQ1 4 |
nkeynes@1012 | 61 | #define REG_TMPF0 5 |
nkeynes@1012 | 62 | #define REG_TMPD0 6 |
nkeynes@1006 | 63 | |
nkeynes@1006 | 64 | |
nkeynes@1006 | 65 | /** |
nkeynes@1006 | 66 | * Operands are either integer, float, or double, and are either immediate or |
nkeynes@1006 | 67 | * assigned to a source-machine register, destination-machine register, or a |
nkeynes@1006 | 68 | * temporary register. (All temporaries have to be resolved to a dest-reg before |
nkeynes@1006 | 69 | * code generation) |
nkeynes@1006 | 70 | */ |
nkeynes@1006 | 71 | typedef enum { |
nkeynes@1006 | 72 | NO_OPERAND = 0, |
nkeynes@1011 | 73 | SOURCE_OPERAND =1, // Source (or temp) register |
nkeynes@1011 | 74 | DEST_OPERAND =2, |
nkeynes@1011 | 75 | TEMP_OPERAND=3, |
nkeynes@1011 | 76 | IMMEDIATE_OPERAND=4 |
nkeynes@1011 | 77 | } xir_operand_form_t; |
nkeynes@1006 | 78 | |
nkeynes@1006 | 79 | typedef struct xir_operand { |
nkeynes@1011 | 80 | xir_operand_form_t form; |
nkeynes@1006 | 81 | union { |
nkeynes@1006 | 82 | uint32_t i; |
nkeynes@1006 | 83 | uint64_t q; |
nkeynes@1006 | 84 | float f; |
nkeynes@1006 | 85 | double d; |
nkeynes@1006 | 86 | void *p; |
nkeynes@1006 | 87 | } value; |
nkeynes@1006 | 88 | } *xir_operand_t; |
nkeynes@1006 | 89 | |
nkeynes@1011 | 90 | typedef enum { |
nkeynes@1011 | 91 | XTY_LONG = 0, /* 32-bit integer */ |
nkeynes@1011 | 92 | XTY_QUAD = 1, /* 64-bit integer */ |
nkeynes@1011 | 93 | XTY_FLOAT = 2, /* 32-bit float */ |
nkeynes@1011 | 94 | XTY_DOUBLE = 3,/* 64-bit float */ |
nkeynes@1011 | 95 | XTY_VEC4F = 4,/* 4x 32-bit floats (16 bytes) */ |
nkeynes@1011 | 96 | XTY_MAT16F = 5,/* 4x4x 32-bit floats (64 bytes) */ |
nkeynes@1011 | 97 | XTY_PTR = 6, /* Native pointer (of appropriate size) */ |
nkeynes@1011 | 98 | } xir_type_t; |
nkeynes@1011 | 99 | |
nkeynes@1006 | 100 | /* Condition codes */ |
nkeynes@1006 | 101 | typedef enum { |
nkeynes@1006 | 102 | CC_TRUE = -1, /* Always */ |
nkeynes@1006 | 103 | CC_OV = 0, /* Overflow */ |
nkeynes@1006 | 104 | CC_NO = 1, /* !Overflow */ |
nkeynes@1006 | 105 | CC_UGE = 2, /* Unsigned greater or equal */ |
nkeynes@1006 | 106 | CC_ULT = 3, /* Unsigned less than */ |
nkeynes@1006 | 107 | CC_ULE = 4, /* Unsigned less or equal */ |
nkeynes@1006 | 108 | CC_UGT = 5, /* Unsigned greater than */ |
nkeynes@1006 | 109 | CC_EQ = 6, /* Equal */ |
nkeynes@1006 | 110 | CC_NE = 7, /* !Equal */ |
nkeynes@1006 | 111 | CC_NEG = 8, /* Negative */ |
nkeynes@1006 | 112 | CC_POS = 9, /* Not-negative (positive or zero) */ |
nkeynes@1006 | 113 | CC_SGE = 10, |
nkeynes@1006 | 114 | CC_SLT = 11, |
nkeynes@1006 | 115 | CC_SLE = 12, |
nkeynes@1006 | 116 | CC_SGT = 13 |
nkeynes@1006 | 117 | } xir_cc_t; |
nkeynes@1006 | 118 | |
nkeynes@1006 | 119 | #define CC_C CC_ULT |
nkeynes@1006 | 120 | #define CC_NC CC_UGE |
nkeynes@1006 | 121 | |
nkeynes@1006 | 122 | typedef enum { |
nkeynes@1006 | 123 | // No operands |
nkeynes@1006 | 124 | OP_NOP = 0, |
nkeynes@1012 | 125 | OP_EXIT, |
nkeynes@1006 | 126 | OP_BARRIER, // Direction to register allocator - Ensure all state is committed |
nkeynes@1006 | 127 | |
nkeynes@1006 | 128 | // One operand |
nkeynes@1006 | 129 | OP_DEC, /* Decrement and set Z if result == 0 */ |
nkeynes@1006 | 130 | OP_LD, /* Load flags from reg/imm (1 = condition, 0 = !condition) */ |
nkeynes@1006 | 131 | OP_ST, /* Set reg to 1 on condition, 0 on !condition */ |
nkeynes@1006 | 132 | OP_RESTFLAGS, /* Restore flags from register */ |
nkeynes@1006 | 133 | OP_SAVEFLAGS, /* Save flags into register */ |
nkeynes@1006 | 134 | OP_ENTER, // Block start - immediate operand is a bitmask of target registers used |
nkeynes@1006 | 135 | OP_CALL0, // Call function with no arguments or return value |
nkeynes@1006 | 136 | OP_OCBI, |
nkeynes@1006 | 137 | OP_OCBP, |
nkeynes@1006 | 138 | OP_OCBWB, |
nkeynes@1006 | 139 | OP_PREF, |
nkeynes@1006 | 140 | |
nkeynes@1006 | 141 | // Register moves */ |
nkeynes@1006 | 142 | OP_MOV, |
nkeynes@1006 | 143 | OP_MOVQ, |
nkeynes@1006 | 144 | OP_MOVV, |
nkeynes@1006 | 145 | OP_MOVM, |
nkeynes@1006 | 146 | OP_MOVSX8, |
nkeynes@1006 | 147 | OP_MOVSX16, |
nkeynes@1006 | 148 | OP_MOVSX32, |
nkeynes@1006 | 149 | OP_MOVZX8, |
nkeynes@1006 | 150 | OP_MOVZX16, |
nkeynes@1006 | 151 | OP_MOVZX32, |
nkeynes@1006 | 152 | |
nkeynes@1006 | 153 | /* ALU */ |
nkeynes@1006 | 154 | OP_ADD, |
nkeynes@1006 | 155 | OP_ADDS, |
nkeynes@1006 | 156 | OP_ADDC, |
nkeynes@1006 | 157 | OP_ADDCS, |
nkeynes@1006 | 158 | OP_AND, |
nkeynes@1006 | 159 | OP_ANDS, |
nkeynes@1006 | 160 | OP_CMP, |
nkeynes@1006 | 161 | OP_DIV, /* Unsigned division */ |
nkeynes@1006 | 162 | OP_DIVS, /* Unsigned divison and update flags */ |
nkeynes@1012 | 163 | OP_MAX, |
nkeynes@1012 | 164 | OP_MAXQ, |
nkeynes@1012 | 165 | OP_MIN, |
nkeynes@1012 | 166 | OP_MINQ, |
nkeynes@1006 | 167 | OP_MUL, |
nkeynes@1006 | 168 | OP_MULS, |
nkeynes@1006 | 169 | OP_MULQ, |
nkeynes@1006 | 170 | OP_MULQS, |
nkeynes@1006 | 171 | OP_NEG, |
nkeynes@1006 | 172 | OP_NEGS, |
nkeynes@1006 | 173 | OP_NOT, |
nkeynes@1006 | 174 | OP_NOTS, |
nkeynes@1006 | 175 | OP_OR, |
nkeynes@1006 | 176 | OP_ORS, |
nkeynes@1006 | 177 | OP_RCL, |
nkeynes@1006 | 178 | OP_RCR, |
nkeynes@1006 | 179 | OP_ROL, /* Rotate left w/o updating flags */ |
nkeynes@1006 | 180 | OP_ROLS, /* Rotate left, and set carry */ |
nkeynes@1006 | 181 | OP_ROR, /* Rotate right */ |
nkeynes@1006 | 182 | OP_RORS, /* Rotate right and set carry */ |
nkeynes@1006 | 183 | OP_SAR, /* Shift arithmetic right */ |
nkeynes@1006 | 184 | OP_SARS, /* Shift arithmetic right and set carry */ |
nkeynes@1006 | 185 | OP_SDIV, /* Signed division */ |
nkeynes@1006 | 186 | OP_SDIVS, /* Signed division and update flags */ |
nkeynes@1006 | 187 | OP_SLL, /* Shift logical left */ |
nkeynes@1006 | 188 | OP_SLLS, /* Shift logical left and set carry */ |
nkeynes@1006 | 189 | OP_SLR, /* Shift logical right */ |
nkeynes@1006 | 190 | OP_SLRS, /* Shift logical right and set carry */ |
nkeynes@1006 | 191 | OP_SUB, /* Subtract, no flags changed/used */ |
nkeynes@1006 | 192 | OP_SUBS, /* Subtract, flag set on overflow */ |
nkeynes@1006 | 193 | OP_SUBB, /* Subtract with borrow */ |
nkeynes@1006 | 194 | OP_SUBBS, /* Subtract with borrow and set carry */ |
nkeynes@1006 | 195 | OP_SHUFFLE, /* Rearrange bytes according to immediate pattern */ |
nkeynes@1006 | 196 | OP_TST, |
nkeynes@1006 | 197 | OP_XOR, |
nkeynes@1006 | 198 | OP_XORS, |
nkeynes@1006 | 199 | |
nkeynes@1006 | 200 | /* FPU */ |
nkeynes@1006 | 201 | OP_ABSD, |
nkeynes@1006 | 202 | OP_ABSF, |
nkeynes@1006 | 203 | OP_ABSV, |
nkeynes@1006 | 204 | OP_ADDD, |
nkeynes@1006 | 205 | OP_ADDF, |
nkeynes@1006 | 206 | OP_ADDV, |
nkeynes@1006 | 207 | OP_CMPD, |
nkeynes@1006 | 208 | OP_CMPF, |
nkeynes@1006 | 209 | OP_DIVD, |
nkeynes@1006 | 210 | OP_DIVF, |
nkeynes@1006 | 211 | OP_DIVV, |
nkeynes@1012 | 212 | OP_MAXD, |
nkeynes@1012 | 213 | OP_MAXF, |
nkeynes@1012 | 214 | OP_MAXV, |
nkeynes@1012 | 215 | OP_MIND, |
nkeynes@1012 | 216 | OP_MINF, |
nkeynes@1012 | 217 | OP_MINV, |
nkeynes@1006 | 218 | OP_MULD, |
nkeynes@1006 | 219 | OP_MULF, |
nkeynes@1006 | 220 | OP_MULV, |
nkeynes@1006 | 221 | OP_NEGD, |
nkeynes@1006 | 222 | OP_NEGF, |
nkeynes@1006 | 223 | OP_NEGV, |
nkeynes@1006 | 224 | OP_SQRTD, |
nkeynes@1006 | 225 | OP_SQRTF, |
nkeynes@1006 | 226 | OP_SQRTV, |
nkeynes@1006 | 227 | OP_RSQRTD, |
nkeynes@1006 | 228 | OP_RSQRTF, |
nkeynes@1006 | 229 | OP_RSQRTV, |
nkeynes@1006 | 230 | OP_SUBD, |
nkeynes@1006 | 231 | OP_SUBF, |
nkeynes@1006 | 232 | OP_SUBV, |
nkeynes@1006 | 233 | OP_DTOF, |
nkeynes@1006 | 234 | OP_DTOI, |
nkeynes@1006 | 235 | OP_FTOD, |
nkeynes@1006 | 236 | OP_FTOI, |
nkeynes@1006 | 237 | OP_ITOD, |
nkeynes@1006 | 238 | OP_ITOF, |
nkeynes@1006 | 239 | OP_SINCOSF, |
nkeynes@1006 | 240 | OP_DOTPRODV, |
nkeynes@1006 | 241 | OP_MATMULV, |
nkeynes@1006 | 242 | |
nkeynes@1006 | 243 | // Memory operations - these all indirect through the memory tables. |
nkeynes@1006 | 244 | OP_LOADB, |
nkeynes@1006 | 245 | OP_LOADBFW, |
nkeynes@1006 | 246 | OP_LOADW, |
nkeynes@1006 | 247 | OP_LOADL, |
nkeynes@1006 | 248 | OP_LOADQ, |
nkeynes@1006 | 249 | OP_STOREB, |
nkeynes@1006 | 250 | OP_STOREW, |
nkeynes@1006 | 251 | OP_STOREL, |
nkeynes@1006 | 252 | OP_STOREQ, |
nkeynes@1006 | 253 | OP_STORELCA, |
nkeynes@1006 | 254 | |
nkeynes@1006 | 255 | OP_RAISEME, // imm mask in, reg in - branch to exception if (reg & mask) == 0 |
nkeynes@1006 | 256 | OP_RAISEMNE, // imm mask in, reg in - branch to exception if (reg & mask) != 0 |
nkeynes@1006 | 257 | |
nkeynes@1006 | 258 | |
nkeynes@1011 | 259 | // Native operations |
nkeynes@1006 | 260 | OP_CALLLUT, // Call indirect through base pointer (reg) + displacement |
nkeynes@1006 | 261 | OP_CALL1, // Call function with single argument and no return value |
nkeynes@1006 | 262 | OP_CALLR, // Call function with no arguments and a single return value |
nkeynes@1012 | 263 | OP_LOADPTRW, // Load 16-bit word from pointer and sign extend to 32-bits |
nkeynes@1011 | 264 | OP_LOADPTRL, |
nkeynes@1011 | 265 | OP_LOADPTRQ, |
nkeynes@1011 | 266 | OP_XLAT, |
nkeynes@1006 | 267 | |
nkeynes@1006 | 268 | /********************** SH4-specific macro operations *************************/ |
nkeynes@1006 | 269 | /* TODO: These need to be broken down into smaller operations eventually, |
nkeynes@1006 | 270 | * especially as some are likely to be partially optimizable. But in the |
nkeynes@1006 | 271 | * meantime this at least gets things working |
nkeynes@1006 | 272 | */ |
nkeynes@1006 | 273 | |
nkeynes@1006 | 274 | /** |
nkeynes@1006 | 275 | * ADDQSAT32 Rm, Rn - 64-bit Add Rm to Rn, saturating to 32-bits if S==1 (per SH4 MAC.W) |
nkeynes@1006 | 276 | * |
nkeynes@1006 | 277 | * if R_S == 0 -> |
nkeynes@1006 | 278 | * Rn += Rm |
nkeynes@1006 | 279 | * else -> |
nkeynes@1006 | 280 | * if overflow32( Rn + Rm ) -> |
nkeynes@1006 | 281 | * Rn = saturate32( Rn + Rm ) | 0x100000000 |
nkeynes@1006 | 282 | * else -> |
nkeynes@1006 | 283 | * Rn += Rm |
nkeynes@1006 | 284 | */ |
nkeynes@1006 | 285 | OP_ADDQSAT32, |
nkeynes@1006 | 286 | |
nkeynes@1006 | 287 | /** |
nkeynes@1006 | 288 | * ADDSAT48 Rm, Rn - 64-bit Add Rm to Rn, saturating to 48-bits if S==1 (per SH4 MAC.L) |
nkeynes@1006 | 289 | * |
nkeynes@1006 | 290 | * if R_S == 0 -> |
nkeynes@1012 | 291 | * ADDQ Rm, Rn |
nkeynes@1006 | 292 | * else -> |
nkeynes@1012 | 293 | * ADDQ Rm, Rn |
nkeynes@1012 | 294 | * if overflow -> |
nkeynes@1006 | 295 | * else -> |
nkeynes@1012 | 296 | * MINQ 0x00007FFFFFFFFFFF, Rn |
nkeynes@1012 | 297 | * MAXQ 0xFFFF800000000000, Rn |
nkeynes@1006 | 298 | */ |
nkeynes@1006 | 299 | OP_ADDQSAT48, |
nkeynes@1006 | 300 | |
nkeynes@1006 | 301 | /** |
nkeynes@1006 | 302 | * CMP/STR Rm, Rn - Set T if any byte is the same between Rm and Rn |
nkeynes@1006 | 303 | * |
nkeynes@1006 | 304 | * Macro expansion: |
nkeynes@1006 | 305 | * MOV Rm, %tmp |
nkeynes@1006 | 306 | * XOR Rn, %tmp |
nkeynes@1006 | 307 | * TEST 0x000000FF, %tmp |
nkeynes@1006 | 308 | * TESTne 0x0000FF00, %tmp |
nkeynes@1006 | 309 | * TESTne 0x00FF0000, %tmp |
nkeynes@1006 | 310 | * TESTne 0xFF000000, %tmp |
nkeynes@1006 | 311 | * SETe T |
nkeynes@1006 | 312 | * |
nkeynes@1006 | 313 | */ |
nkeynes@1006 | 314 | OP_CMPSTR, |
nkeynes@1006 | 315 | |
nkeynes@1006 | 316 | /** |
nkeynes@1006 | 317 | * DIV1 Rm,Rn performs a single-step division of Rm/Rn, modifying flags |
nkeynes@1006 | 318 | * as it goes. |
nkeynes@1006 | 319 | * |
nkeynes@1006 | 320 | * sign = Rn >> 31 |
nkeynes@1006 | 321 | * Rn = (Rn << 1) | R_T |
nkeynes@1006 | 322 | * If R_Q == R_M -> Rn = Rn - Rm |
nkeynes@1006 | 323 | * Else -> Rn = Rn + Rm |
nkeynes@1006 | 324 | * R_Q = sign ^ R_M ^ (Rn>>31) |
nkeynes@1006 | 325 | * R_T = (R_Q == R_M) ; or newq == (rn>>31) |
nkeynes@1006 | 326 | * |
nkeynes@1006 | 327 | * Macro expansion: |
nkeynes@1006 | 328 | * LDc R_T |
nkeynes@1006 | 329 | * RCL 1, Rn |
nkeynes@1006 | 330 | * SETc temp |
nkeynes@1006 | 331 | * CMP R_Q, R_M |
nkeynes@1006 | 332 | * ADDne Rm, Rn |
nkeynes@1006 | 333 | * SUBeq Rm, Rn |
nkeynes@1006 | 334 | * MOV Rn, R_Q |
nkeynes@1006 | 335 | * SHR 31, Rn |
nkeynes@1006 | 336 | * XOR temp, R_Q |
nkeynes@1006 | 337 | * XOR R_M, R_Q |
nkeynes@1006 | 338 | * CMP R_M, R_Q |
nkeynes@1006 | 339 | * SETe R_T |
nkeynes@1006 | 340 | */ |
nkeynes@1006 | 341 | OP_DIV1, |
nkeynes@1006 | 342 | |
nkeynes@1006 | 343 | /** |
nkeynes@1006 | 344 | * SHAD Rm, Rn performs an arithmetic shift of Rn as follows: |
nkeynes@1006 | 345 | * If Rm >= 0 -> Rn = Rn << (Rm&0x1F) |
nkeynes@1006 | 346 | * If Rm < 0 -> |
nkeynes@1006 | 347 | * If Rm&0x1F == 0 -> Rn = Rn >> 31 |
nkeynes@1006 | 348 | * Else -> Rn = Rn >> 32 - (Rm&0x1F) |
nkeynes@1006 | 349 | * |
nkeynes@1006 | 350 | * CMP 0, Rm |
nkeynes@1006 | 351 | * ANDuge 0x1F, Rm |
nkeynes@1006 | 352 | * SLLuge Rm, Rn |
nkeynes@1006 | 353 | * ORult 0xFFFFFFE0, Rm |
nkeynes@1006 | 354 | * NEGult Rm |
nkeynes@1006 | 355 | * SARult Rm, Rn ; unmasked shift |
nkeynes@1006 | 356 | * |
nkeynes@1006 | 357 | */ |
nkeynes@1006 | 358 | OP_SHAD, // Shift dynamic arithmetic (left or right) |
nkeynes@1006 | 359 | |
nkeynes@1006 | 360 | /** |
nkeynes@1006 | 361 | * SHLD Rm, Rn performs a logical shift of Rn as follows: |
nkeynes@1006 | 362 | * If Rm >= 0 -> Rn = Rn << (Rm&0x1F) |
nkeynes@1006 | 363 | * If Rm < 0 -> |
nkeynes@1006 | 364 | * If Rm&0x1F == 0 -> Rn = 0 |
nkeynes@1006 | 365 | * Else -> Rn = Rn >> 32 - (Rm&0x1F) |
nkeynes@1006 | 366 | */ |
nkeynes@1006 | 367 | OP_SHLD, // Shift dynamic logical (left or right) |
nkeynes@1006 | 368 | } xir_opcode_t; |
nkeynes@1006 | 369 | |
nkeynes@1006 | 370 | #define MAX_OP0_OPCODE OP_BARRIER |
nkeynes@1006 | 371 | #define MAX_OP1_OPCODE OP_PREF |
nkeynes@1006 | 372 | #define MAX_OP2_OPCODE OP_SHLD |
nkeynes@1006 | 373 | #define NUM_OP0_OPCODES (MAX_OP0_OPCODE+1) |
nkeynes@1006 | 374 | #define NUM_OP1_OPCODES (MAX_OP1_OPCODE-MAX_OP0_OPCODE) |
nkeynes@1006 | 375 | #define NUM_OP2_OPCODES (MAX_OP2_OPCODE-MAX_OP1_OPCODE) |
nkeynes@1006 | 376 | #define MAX_OPCODE (MAX_OP2_OPCODE) |
nkeynes@1006 | 377 | #define NUM_OPCODES (MAX_OP2_OPCODE+1) |
nkeynes@1006 | 378 | |
nkeynes@1006 | 379 | typedef struct xir_op { |
nkeynes@1006 | 380 | xir_opcode_t opcode; |
nkeynes@1006 | 381 | xir_cc_t cond; |
nkeynes@1006 | 382 | struct xir_operand operand[2]; |
nkeynes@1006 | 383 | struct xir_op *next; /* Next instruction (normal path) - NULL in the case of the last instruction */ |
nkeynes@1006 | 384 | struct xir_op *prev; /* Previous instruction (normal path) - NULL in the case of the first instruction */ |
nkeynes@1006 | 385 | struct xir_op *exc; /* Next instruction if the opcode takes an exception - NULL if no exception is possible */ |
nkeynes@1006 | 386 | } *xir_op_t; |
nkeynes@1006 | 387 | |
nkeynes@1006 | 388 | /* Defined in xlat/xlat.h */ |
nkeynes@1006 | 389 | typedef struct xlat_source_machine *xlat_source_machine_t; |
nkeynes@1006 | 390 | typedef struct xlat_target_machine *xlat_target_machine_t; |
nkeynes@1006 | 391 | |
nkeynes@1011 | 392 | typedef struct xir_temp_register { |
nkeynes@1011 | 393 | xir_type_t type; |
nkeynes@1011 | 394 | uint32_t home_register; /* corresponding source register, or -1 for none */ |
nkeynes@1011 | 395 | } *xir_temp_register_t; |
nkeynes@1011 | 396 | |
nkeynes@1006 | 397 | /** |
nkeynes@1006 | 398 | * Source data structure. This mainly exists to manage memory for XIR operations |
nkeynes@1006 | 399 | */ |
nkeynes@1006 | 400 | typedef struct xir_basic_block { |
nkeynes@1006 | 401 | xir_op_t ir_begin; /* Beginning of code block */ |
nkeynes@1006 | 402 | xir_op_t ir_end; /* End of code block (Last instruction in code block) */ |
nkeynes@1006 | 403 | xir_op_t ir_ptr; /* First unallocated instruction in allocation block */ |
nkeynes@1006 | 404 | xir_op_t ir_alloc_begin; /* Beginning of memory allocation */ |
nkeynes@1006 | 405 | xir_op_t ir_alloc_end; /* End of allocation */ |
nkeynes@1006 | 406 | uint32_t pc_begin; /* first instruction */ |
nkeynes@1006 | 407 | uint32_t pc_end; /* next instruction after end */ |
nkeynes@1011 | 408 | struct xir_temp_register temp_regs[MAX_TEMP_REGISTER+1]; /* temporary register table */ |
nkeynes@1011 | 409 | uint32_t next_temp_reg; |
nkeynes@1006 | 410 | xlat_source_machine_t source; |
nkeynes@1011 | 411 | xlat_target_machine_t target; |
nkeynes@1006 | 412 | struct mem_region_fn **address_space; /* source machine memory access table */ |
nkeynes@1006 | 413 | } *xir_basic_block_t; |
nkeynes@1006 | 414 | |
nkeynes@1006 | 415 | typedef int xir_offset_t; |
nkeynes@1006 | 416 | |
nkeynes@1006 | 417 | /**************************** OP Information ******************************/ |
nkeynes@1006 | 418 | |
nkeynes@1006 | 419 | /* Instruction operand modes */ |
nkeynes@1006 | 420 | #define OPM_NO 0x000000 /* No operands */ |
nkeynes@1006 | 421 | #define OPM_R 0x000001 /* Single operand, read-only */ |
nkeynes@1006 | 422 | #define OPM_W 0x000002 /* Single operand, write-only */ |
nkeynes@1006 | 423 | #define OPM_RW 0x000003 /* Single operand, read-write */ |
nkeynes@1006 | 424 | #define OPM_R_R 0x000005 /* Two operands, both read-only */ |
nkeynes@1006 | 425 | #define OPM_R_W 0x000009 /* Two operands, first read-only, second write-only */ |
nkeynes@1006 | 426 | #define OPM_R_RW 0x00000D /* Two operands, first read-only, second read-write */ |
nkeynes@1006 | 427 | #define OPM_I_I 0x000000 /* Both operands i32 */ |
nkeynes@1006 | 428 | #define OPM_Q_Q 0x000110 /* Both operands i64 */ |
nkeynes@1006 | 429 | #define OPM_I_Q 0x000100 /* i32,i64 operands */ |
nkeynes@1006 | 430 | #define OPM_Q_I 0x000010 /* i64,i32 operands */ |
nkeynes@1006 | 431 | #define OPM_F_F 0x000220 /* Both operands float */ |
nkeynes@1006 | 432 | #define OPM_D_D 0x000330 /* Both operands double */ |
nkeynes@1006 | 433 | #define OPM_I_F 0x000200 /* i32,float operands */ |
nkeynes@1006 | 434 | #define OPM_I_D 0x000300 /* i32,double operands */ |
nkeynes@1006 | 435 | #define OPM_F_I 0x000020 /* float,i32 operands */ |
nkeynes@1006 | 436 | #define OPM_D_I 0x000030 /* double,i32 operands */ |
nkeynes@1006 | 437 | #define OPM_F_D 0x000320 /* float,double operands */ |
nkeynes@1006 | 438 | #define OPM_D_F 0x000230 /* double,float operands */ |
nkeynes@1006 | 439 | #define OPM_V_V 0x000440 /* vec4,vec4 operands */ |
nkeynes@1006 | 440 | #define OPM_V_M 0x000540 /* vec4,matrix16 operands */ |
nkeynes@1006 | 441 | #define OPM_M_M 0x000550 /* mat16,mat16 operands */ |
nkeynes@1006 | 442 | #define OPM_TR 0x001000 /* Use T */ |
nkeynes@1006 | 443 | #define OPM_TW 0x002000 /* Set T */ |
nkeynes@1006 | 444 | #define OPM_TRW 0x003000 /* Use+Set T */ |
nkeynes@1006 | 445 | #define OPM_EXC 0x004000 /* May raise an exception, clobbers volatiles */ |
nkeynes@1006 | 446 | #define OPM_CLB 0x008000 /* Clobbers volatile registers */ |
nkeynes@1006 | 447 | #define OPM_CLBT 0x00C000 /* Clobbers 'temporary regs' but not the full volatile set */ |
nkeynes@1006 | 448 | #define OPM_TERM 0x010000 /* Terminates block. (Must be final instruction in block) */ |
nkeynes@1006 | 449 | |
nkeynes@1006 | 450 | #define OPM_R_R_TW (OPM_R_R|OPM_TW) /* Read two ops + set flags */ |
nkeynes@1006 | 451 | #define OPM_R_RW_TR (OPM_R_RW|OPM_TR) /* Read/write + use flags */ |
nkeynes@1006 | 452 | #define OPM_R_RW_TW (OPM_R_RW|OPM_TW) /* Read/write + set flags */ |
nkeynes@1006 | 453 | #define OPM_R_RW_TRW (OPM_R_RW|OPM_TRW) /* Read/write + use/set flags */ |
nkeynes@1006 | 454 | #define OPM_R_W_TW (OPM_R_W|OPM_TW) /* Read/write + set flags */ |
nkeynes@1006 | 455 | #define OPM_RW_TW (OPM_RW|OPM_TW) /* Read/write single op + set flags */ |
nkeynes@1006 | 456 | #define OPM_RW_TRW (OPM_RW|OPM_TRW) /* Read/write single op + use/set flags */ |
nkeynes@1006 | 457 | #define OPM_FRW (OPM_RW|OPM_F_F) /* Read/write single float op */ |
nkeynes@1006 | 458 | #define OPM_FR_FRW (OPM_R_RW|OPM_F_F) /* Read/write float op pair */ |
nkeynes@1006 | 459 | #define OPM_FR_FW (OPM_R_W|OPM_F_F) /* Read/write float op pair */ |
nkeynes@1006 | 460 | #define OPM_FR_FR_TW (OPM_R_R_TW|OPM_F_F) /* Read two float ops + set flags */ |
nkeynes@1006 | 461 | #define OPM_DRW (OPM_RW|OPM_D_D) /* Read/write single double op */ |
nkeynes@1006 | 462 | #define OPM_DR_DRW (OPM_R_RW|OPM_D_D) /* Read/write double op pair */ |
nkeynes@1006 | 463 | #define OPM_DR_DW (OPM_R_W|OPM_D_D) /* Read/write double op pair */ |
nkeynes@1006 | 464 | #define OPM_VR_VRW (OPM_R_RW|OPM_V_V) /* Vector Read/write double op pair */ |
nkeynes@1006 | 465 | #define OPM_VR_VW (OPM_R_W|OPM_V_V) /* Vector Read/write double op pair */ |
nkeynes@1006 | 466 | #define OPM_DR_DR_TW (OPM_R_R_TW|OPM_D_D) /* Read two double ops + set flags */ |
nkeynes@1006 | 467 | |
nkeynes@1006 | 468 | #define OPM_R_W_EXC (OPM_R_W|OPM_EXC) /* Read first, write second, possible exc (typical load) */ |
nkeynes@1006 | 469 | #define OPM_R_R_EXC (OPM_R_R|OPM_EXC) /* Read first, write second, possible exc (typical store) */ |
nkeynes@1006 | 470 | #define OPM_R_EXC (OPM_R|OPM_EXC) /* Read-only single op, possible exc (eg pref) */ |
nkeynes@1006 | 471 | |
nkeynes@1006 | 472 | struct xir_opcode_entry { |
nkeynes@1006 | 473 | char *name; |
nkeynes@1006 | 474 | int mode; |
nkeynes@1006 | 475 | }; |
nkeynes@1006 | 476 | |
nkeynes@1006 | 477 | struct xir_symbol_entry { |
nkeynes@1006 | 478 | const char *name; |
nkeynes@1006 | 479 | void *ptr; |
nkeynes@1006 | 480 | }; |
nkeynes@1006 | 481 | |
nkeynes@1011 | 482 | extern const struct xir_opcode_entry XIR_OPCODE_TABLE[]; |
nkeynes@1011 | 483 | extern const int XIR_OPERAND_SIZE[]; |
nkeynes@1006 | 484 | |
nkeynes@1006 | 485 | #define XOP_REG(op,n) (op->operand[n].value.i) |
nkeynes@1006 | 486 | #define XOP_REG1(op) XOP_REG(op,0) |
nkeynes@1006 | 487 | #define XOP_REG2(op) XOP_REG(op,1) |
nkeynes@1006 | 488 | #define XOP_INT(op,n) (op->operand[n].value.i) |
nkeynes@1006 | 489 | #define XOP_QUAD(op,n) (op->operand[n].value.q) |
nkeynes@1006 | 490 | #define XOP_FLOAT(op,n) (op->operand[n].value.f) |
nkeynes@1006 | 491 | #define XOP_DOUBLE(op,n) (op->operand[n].value.d) |
nkeynes@1006 | 492 | #define XOP_PTR(op,n) (op->operand[n].value.p) |
nkeynes@1006 | 493 | |
nkeynes@1006 | 494 | #define XOP_IS_TERMINATOR(op) (XIR_OPCODE_TABLE[op->opcode].mode & OPM_TERM) |
nkeynes@1006 | 495 | #define XOP_HAS_0_OPERANDS(op) ((XIR_OPCODE_TABLE[op->opcode].mode & 0x0F) == 0) |
nkeynes@1006 | 496 | #define XOP_HAS_1_OPERAND(op) ((XIR_OPCODE_TABLE[op->opcode].mode & 0x0F) < 4) |
nkeynes@1006 | 497 | #define XOP_HAS_2_OPERANDS(op) ((XIR_OPCODE_TABLE[op->opcode].mode & 0x0C) != 0) |
nkeynes@1006 | 498 | #define XOP_HAS_EXCEPTION(op) ((XIR_OPCODE_TABLE[op->opcode].mode & 0xC000) == OPM_EXC) |
nkeynes@1006 | 499 | |
nkeynes@1006 | 500 | #define XOP_READS_OP1(op) (XIR_OPCODE_TABLE[op->opcode].mode & 0x01) |
nkeynes@1006 | 501 | #define XOP_WRITES_OP1(op) (XIR_OPCODE_TABLE[op->opcode].mode & 0x02) |
nkeynes@1006 | 502 | #define XOP_READS_OP2(op) (XIR_OPCODE_TABLE[op->opcode].mode & 0x04) |
nkeynes@1006 | 503 | #define XOP_WRITES_OP2(op) (XIR_OPCODE_TABLE[op->opcode].mode & 0x08) |
nkeynes@1006 | 504 | #define XOP_READS_FLAGS(op) ((XIR_OPCODE_TABLE[op->opcode].mode & OPM_TR) || (op->cond != CC_TRUE && op->opcode != OP_LD)) |
nkeynes@1006 | 505 | #define XOP_WRITES_FLAGS(op) (XIR_OPCODE_TABLE[op->opcode].mode & OPM_TW) |
nkeynes@1006 | 506 | |
nkeynes@1006 | 507 | #define XOP_READS_REG1(op) (XOP_READS_OP1(op) && XOP_IS_REG(op,0)) |
nkeynes@1006 | 508 | #define XOP_WRITES_REG1(op) (XOP_WRITES_OP1(op) && XOP_IS_REG(op,0)) |
nkeynes@1006 | 509 | #define XOP_READS_REG2(op) (XOP_READS_OP2(op) && XOP_IS_REG(op,1)) |
nkeynes@1006 | 510 | #define XOP_WRITES_REG2(op) (XOP_WRITES_OP2(op) && XOP_IS_REG(op,1)) |
nkeynes@1006 | 511 | |
nkeynes@1011 | 512 | #define XOP_TYPE1(op) ((XIR_OPCODE_TABLE[op->opcode].mode >> 4) & 0x0F) |
nkeynes@1011 | 513 | #define XOP_TYPE2(op) ((XIR_OPCODE_TABLE[op->opcode].mode >> 8) & 0x0F) |
nkeynes@1011 | 514 | #define XOP_FORM1(op) (op->operand[0].form) |
nkeynes@1011 | 515 | #define XOP_FORM2(op) (op->operand[1].form) |
nkeynes@1006 | 516 | #define XOP_OPERAND(op,i) (&op->operand[i]) |
nkeynes@1011 | 517 | #define XOP_OPTYPE(op,n) (n == 0 ? XOP_TYPE1(op) : XOP_TYPE2(op)) |
nkeynes@1011 | 518 | #define XOP_OPSIZE(op,n) (XIR_OPERAND_SIZE[XOP_OPTYPE(op,n)]) |
nkeynes@1006 | 519 | |
nkeynes@1011 | 520 | #define XOP_IS_SRC(op,n) (op->operand[n].form == SOURCE_OPERAND) |
nkeynes@1011 | 521 | #define XOP_IS_DST(op,n) (op->operand[n].form == DEST_OPERAND) |
nkeynes@1011 | 522 | #define XOP_IS_TMP(op,n) (op->operand[n].form == TEMP_OPERAND) |
nkeynes@1011 | 523 | #define XOP_IS_IMM(op,n) (op->operand[n].form == IMMEDIATE_OPERAND) |
nkeynes@1011 | 524 | #define XOP_IS_IMMF(op,n) (XOP_IS_IMM(op,n) && XOP_OPTYPE(op,n) == XTY_FLOAT) |
nkeynes@1011 | 525 | #define XOP_IS_IMMD(op,n) (XOP_IS_IMM(op,n) && XOP_OPTYPE(op,n) == XTY_DOUBLE) |
nkeynes@1011 | 526 | #define XOP_IS_IMML(op,n) (XOP_IS_IMM(op,n) && XOP_OPTYPE(op,n) == XTY_LONG) |
nkeynes@1011 | 527 | #define XOP_IS_IMMQ(op,n) (XOP_IS_IMM(op,n) && XOP_OPTYPE(op,n) == XTY_QUAD) |
nkeynes@1011 | 528 | #define XOP_IS_IMMP(op,n) (XOP_IS_IMM(op,n) && XOP_OPTYPE(op,n) == XTY_PTR) |
nkeynes@1011 | 529 | #define XOP_IS_REG(op,n) (op->operand[n].form >= SOURCE_OPERAND && op->operand[n].form <= TEMP_OPERAND) |
nkeynes@1011 | 530 | #define XOP_IS_FORM(op,t1,t2) (op->operand[0].form == t1 && op->operand[1].form == t2) |
nkeynes@1006 | 531 | |
nkeynes@1011 | 532 | /******************************* IR Construction ******************************/ |
nkeynes@1006 | 533 | |
nkeynes@1011 | 534 | /** |
nkeynes@1011 | 535 | * Clear out a basic block structure, ready for reuse |
nkeynes@1011 | 536 | */ |
nkeynes@1011 | 537 | void xir_clear_basic_block( xir_basic_block_t xbb ); |
nkeynes@1006 | 538 | |
nkeynes@1011 | 539 | /** |
nkeynes@1011 | 540 | * Allocate a temporary register of the given type, with given home position |
nkeynes@1011 | 541 | * (-1 for a pure temporary) |
nkeynes@1011 | 542 | */ |
nkeynes@1011 | 543 | uint32_t xir_alloc_temp_reg( xir_basic_block_t xbb, xir_type_t type, int home ); |
nkeynes@1011 | 544 | |
nkeynes@1011 | 545 | xir_op_t xir_append_op2( xir_basic_block_t xbb, int op, int arg0form, uint32_t arg0, int arg1form, uint32_t arg1 ); |
nkeynes@1011 | 546 | xir_op_t xir_append_op2cc( xir_basic_block_t xbb, int op, int cc, int arg0form, uint32_t arg0, int arg1form, uint32_t arg1 ); |
nkeynes@1011 | 547 | xir_op_t xir_append_float_op2( xir_basic_block_t xbb, int op, float imm1, int arg1form, uint32_t arg1 ); |
nkeynes@1011 | 548 | xir_op_t xir_append_ptr_op2( xir_basic_block_t xbb, int op, void *arg0, int arg1form, uint32_t arg1 ); |
nkeynes@1011 | 549 | |
nkeynes@1011 | 550 | |
nkeynes@1011 | 551 | #define XOP1I( op, arg0 ) xir_append_op2(xbb, op, IMMEDIATE_OPERAND, arg0, NO_OPERAND, 0) |
nkeynes@1011 | 552 | #define XOP1S( op, arg0 ) xir_append_op2(xbb, op, SOURCE_OPERAND, arg0, NO_OPERAND, 0) |
nkeynes@1011 | 553 | #define XOP1SCC( op, cc, arg0 ) xir_append_op2cc(xbb, op, cc, SOURCE_OPERAND, arg0, NO_OPERAND, 0) |
nkeynes@1011 | 554 | #define XOP1T( op, arg0 ) xir_append_op2(xbb, op, TEMP_OPERAND, arg0, NO_OPERAND, 0) |
nkeynes@1011 | 555 | #define XOP1TCC( op, cc, arg0 ) xir_append_op2cc(xbb, op, cc, TEMP_OPERAND, arg0, NO_OPERAND, 0) |
nkeynes@1011 | 556 | #define XOP2IS( op, arg0, arg1 ) xir_append_op2(xbb, op, IMMEDIATE_OPERAND, arg0, SOURCE_OPERAND, arg1) |
nkeynes@1012 | 557 | #define XOP2ISCC( op, cc, arg0, arg1 ) xir_append_op2cc(xbb, op, cc, IMMEDIATE_OPERAND, arg0, SOURCE_OPERAND, arg1) |
nkeynes@1011 | 558 | #define XOP2IT( op, arg0, arg1 ) xir_append_op2(xbb, op, IMMEDIATE_OPERAND, arg0, TEMP_OPERAND, arg1) |
nkeynes@1011 | 559 | #define XOP2II( op, arg0, arg1 ) xir_append_op2(xbb, op, IMMEDIATE_OPERAND, arg0, IMMEDIATE_OPERAND, arg1) |
nkeynes@1011 | 560 | #define XOP2IICC( op, cc, arg0, arg1 ) xir_append_op2cc(xbb, op, cc, IMMEDIATE_OPERAND, arg0, IMMEDIATE_OPERAND, arg1) |
nkeynes@1011 | 561 | #define XOP2SS( op, arg0, arg1 ) xir_append_op2(xbb, op, SOURCE_OPERAND, arg0, SOURCE_OPERAND, arg1) |
nkeynes@1011 | 562 | #define XOP2ST( op, arg0, arg1 ) xir_append_op2(xbb, op, SOURCE_OPERAND, arg0, TEMP_OPERAND, arg1) |
nkeynes@1011 | 563 | #define XOP2TS( op, arg0, arg1 ) xir_append_op2(xbb, op, TEMP_OPERAND, arg0, SOURCE_OPERAND, arg1) |
nkeynes@1011 | 564 | #define XOP2TT( op, arg0, arg1 ) xir_append_op2(xbb, op, TEMP_OPERAND, arg0, TEMP_OPERAND, arg1) |
nkeynes@1011 | 565 | #define XOP2CC( op, cc, arg0, arg1 ) xir_append_op2cc(xbb, op, cc, SOURCE_OPERAND, arg0, SOURCE_OPERAND, arg1) |
nkeynes@1011 | 566 | #define XOP2FS( op, arg0, arg1 ) xir_append_float_op2(xbb, op, arg0, SOURCE_OPERAND, arg1) |
nkeynes@1011 | 567 | #define XOP2PS( op, arg0, arg1 ) xir_append_ptr_op2(xbb, op, arg0, SOURCE_OPERAND, arg1) |
nkeynes@1011 | 568 | #define XOP2PT( op, arg0, arg1 ) xir_append_ptr_op2(xbb, op, arg0, TEMP_OPERAND, arg1) |
nkeynes@1006 | 569 | #define XOP0( op ) xir_append_op2(xbb, op, NO_OPERAND, 0, NO_OPERAND, 0) |
nkeynes@1006 | 570 | #define XOPCALL0( arg0 ) xir_append_ptr_op2(xbb, OP_CALL0, arg0, NO_OPERAND, 0) |
nkeynes@1011 | 571 | #define XOPCALL1I( arg0, arg1 ) xir_append_ptr_op2(xbb, OP_CALL1, arg0, IMMEDIATE_OPERAND, arg1) |
nkeynes@1011 | 572 | #define XOPCALL1S( arg0, arg1 ) xir_append_ptr_op2(xbb, OP_CALL1, arg0, SOURCE_OPERAND, arg1) |
nkeynes@1011 | 573 | #define XOPCALL1T( arg0, arg1 ) xir_append_ptr_op2(xbb, OP_CALL1, arg0, TEMP_OPERAND, arg1) |
nkeynes@1011 | 574 | #define XOPCALLRS( arg0, arg1 ) xir_append_ptr_op2(xbb, OP_CALLR, arg0, SOURCE_OPERAND, arg1) |
nkeynes@1011 | 575 | #define XOPCALLRT( arg0, arg1 ) xir_append_ptr_op2(xbb, OP_CALLR, arg0, TEMP_OPERAND, arg1) |
nkeynes@1006 | 576 | |
nkeynes@1006 | 577 | /**************************** IR Modification ******************************/ |
nkeynes@1006 | 578 | |
nkeynes@1006 | 579 | /** |
nkeynes@1006 | 580 | * Insert a new instruction immediately before the given existing inst. |
nkeynes@1006 | 581 | */ |
nkeynes@1006 | 582 | void xir_insert_op( xir_op_t op, xir_op_t before ); |
nkeynes@1006 | 583 | |
nkeynes@1006 | 584 | /** |
nkeynes@1006 | 585 | * Insert the block start..end immediately before the given instruction |
nkeynes@1006 | 586 | */ |
nkeynes@1006 | 587 | void xir_insert_block( xir_op_t start, xir_op_t end, xir_op_t before ); |
nkeynes@1006 | 588 | |
nkeynes@1006 | 589 | /** |
nkeynes@1006 | 590 | * Remove the specified instruction completely from the block in which it appears. |
nkeynes@1006 | 591 | * Note: removing terminators with this method may break the representation. |
nkeynes@1006 | 592 | * Op itself is not modified. |
nkeynes@1006 | 593 | */ |
nkeynes@1006 | 594 | void xir_remove_op( xir_op_t op ); |
nkeynes@1006 | 595 | |
nkeynes@1006 | 596 | /** |
nkeynes@1006 | 597 | * Apply a shuffle directly to the given operand, and return the result |
nkeynes@1006 | 598 | */ |
nkeynes@1006 | 599 | uint32_t xir_shuffle_imm32( uint32_t shuffle, uint32_t operand ); |
nkeynes@1006 | 600 | |
nkeynes@1006 | 601 | /** |
nkeynes@1006 | 602 | * Apply a shuffle transitively to the operation (which must also be a shuffle). |
nkeynes@1006 | 603 | * For example, given the sequence |
nkeynes@1006 | 604 | * op1: shuffle 0x2134, r12 |
nkeynes@1006 | 605 | * op2: shuffle 0x3412, r12 |
nkeynes@1006 | 606 | * xir_trans_shuffle( 0x2134, op2 ) can be used to replace op2 wih |
nkeynes@1006 | 607 | * shuffle 0x3421, r12 |
nkeynes@1006 | 608 | */ |
nkeynes@1006 | 609 | void xir_shuffle_op( uint32_t shuffle, xir_op_t it ); |
nkeynes@1006 | 610 | |
nkeynes@1006 | 611 | /** |
nkeynes@1006 | 612 | * Return the number of instructions that would be emitted by xir_shuffle_lower |
nkeynes@1006 | 613 | * for the given instruction (not including the leading nop, if there is one) |
nkeynes@1006 | 614 | */ |
nkeynes@1006 | 615 | int xir_shuffle_lower_size( xir_op_t it ); |
nkeynes@1006 | 616 | |
nkeynes@1006 | 617 | /** |
nkeynes@1006 | 618 | * Transform a shuffle instruction into an equivalent sequence of shifts, and |
nkeynes@1006 | 619 | * logical operations. |
nkeynes@1006 | 620 | * @return the last instruction in the resultant sequence (which may be the |
nkeynes@1006 | 621 | * original instruction pointer). |
nkeynes@1006 | 622 | */ |
nkeynes@1006 | 623 | xir_op_t xir_shuffle_lower( xir_basic_block_t xbb, xir_op_t it, int tmp1, int tmp2 ); |
nkeynes@1006 | 624 | |
nkeynes@1006 | 625 | |
nkeynes@1006 | 626 | /**************************** Debugging ******************************/ |
nkeynes@1006 | 627 | |
nkeynes@1006 | 628 | /** |
nkeynes@1006 | 629 | * Verify the integrity of an IR block - abort with assertion failure on any |
nkeynes@1006 | 630 | * errors. |
nkeynes@1006 | 631 | */ |
nkeynes@1011 | 632 | void xir_verify_block( xir_basic_block_t xbb, xir_op_t begin, xir_op_t end ); |
nkeynes@1006 | 633 | |
nkeynes@1006 | 634 | /** |
nkeynes@1006 | 635 | * Set the symbol table mappings for target points - also only really for |
nkeynes@1006 | 636 | * debugging output. |
nkeynes@1006 | 637 | */ |
nkeynes@1006 | 638 | void xir_set_symbol_table( const struct xir_symbol_entry *symtab ); |
nkeynes@1006 | 639 | |
nkeynes@1006 | 640 | /** |
nkeynes@1006 | 641 | * Dump the specified block of IR to stdout |
nkeynes@1006 | 642 | */ |
nkeynes@1011 | 643 | void xir_dump_block( xir_basic_block_t xbb ); |
nkeynes@1006 | 644 | |
nkeynes@1006 | 645 | |
nkeynes@1006 | 646 | #endif /* !lxdream_xir_H */ |
.