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 | /* Registers 0..127 belong to the source machine, all higher numbers are temporaries */
|
nkeynes@1006 | 52 | #define MIN_SOURCE_REGISTER 0
|
nkeynes@1006 | 53 | #define MAX_SOURCE_REGISTER 1023
|
nkeynes@1006 | 54 | #define MIN_TEMP_REGISTER 1024
|
nkeynes@1006 | 55 | #define MAX_TEMP_REGISTER 1535
|
nkeynes@1006 | 56 |
|
nkeynes@1006 | 57 | /* Target registers have a separate 'address' space. */
|
nkeynes@1006 | 58 | #define MIN_TARGET_REGISTER 0
|
nkeynes@1006 | 59 | #define MAX_TARGET_REGISTER 127
|
nkeynes@1006 | 60 |
|
nkeynes@1006 | 61 | /* Convenience defines */
|
nkeynes@1006 | 62 | #define REG_TMP0 (MIN_TEMP_REGISTER)
|
nkeynes@1006 | 63 | #define REG_TMP1 (MIN_TEMP_REGISTER+1)
|
nkeynes@1006 | 64 | #define REG_TMP2 (MIN_TEMP_REGISTER+2)
|
nkeynes@1006 | 65 | #define REG_TMP3 (MIN_TEMP_REGISTER+3)
|
nkeynes@1006 | 66 | #define REG_TMP4 (MIN_TEMP_REGISTER+4)
|
nkeynes@1006 | 67 | #define REG_TMP5 (MIN_TEMP_REGISTER+5)
|
nkeynes@1006 | 68 |
|
nkeynes@1006 | 69 | #define REG_TMPQ0 (MIN_TEMP_REGISTER+128)
|
nkeynes@1006 | 70 | #define REG_TMPQ1 (MIN_TEMP_REGISTER+129)
|
nkeynes@1006 | 71 |
|
nkeynes@1006 | 72 | /**
|
nkeynes@1006 | 73 | * Operands are either integer, float, or double, and are either immediate or
|
nkeynes@1006 | 74 | * assigned to a source-machine register, destination-machine register, or a
|
nkeynes@1006 | 75 | * temporary register. (All temporaries have to be resolved to a dest-reg before
|
nkeynes@1006 | 76 | * code generation)
|
nkeynes@1006 | 77 | */
|
nkeynes@1006 | 78 | typedef enum {
|
nkeynes@1006 | 79 | NO_OPERAND = 0,
|
nkeynes@1006 | 80 | SOURCE_REGISTER_OPERAND =1, // Source (or temp) register
|
nkeynes@1006 | 81 | TARGET_REGISTER_OPERAND =2,
|
nkeynes@1006 | 82 | INT_IMM_OPERAND = 3,
|
nkeynes@1006 | 83 | QUAD_IMM_OPERAND = 4,
|
nkeynes@1006 | 84 | FLOAT_IMM_OPERAND = 5,
|
nkeynes@1006 | 85 | DOUBLE_IMM_OPERAND = 6,
|
nkeynes@1006 | 86 | POINTER_OPERAND = 7, // Native target pointer, eg direct memory access
|
nkeynes@1006 | 87 | } xir_operand_type_t;
|
nkeynes@1006 | 88 |
|
nkeynes@1006 | 89 | typedef struct xir_operand {
|
nkeynes@1006 | 90 | xir_operand_type_t type;
|
nkeynes@1006 | 91 | union {
|
nkeynes@1006 | 92 | uint32_t i;
|
nkeynes@1006 | 93 | uint64_t q;
|
nkeynes@1006 | 94 | float f;
|
nkeynes@1006 | 95 | double d;
|
nkeynes@1006 | 96 | void *p;
|
nkeynes@1006 | 97 | } value;
|
nkeynes@1006 | 98 | } *xir_operand_t;
|
nkeynes@1006 | 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@1006 | 125 | OP_BARRIER, // Direction to register allocator - Ensure all state is committed
|
nkeynes@1006 | 126 |
|
nkeynes@1006 | 127 | // One operand
|
nkeynes@1006 | 128 | OP_DEC, /* Decrement and set Z if result == 0 */
|
nkeynes@1006 | 129 | OP_LD, /* Load flags from reg/imm (1 = condition, 0 = !condition) */
|
nkeynes@1006 | 130 | OP_ST, /* Set reg to 1 on condition, 0 on !condition */
|
nkeynes@1006 | 131 | OP_RESTFLAGS, /* Restore flags from register */
|
nkeynes@1006 | 132 | OP_SAVEFLAGS, /* Save flags into register */
|
nkeynes@1006 | 133 | OP_ENTER, // Block start - immediate operand is a bitmask of target registers used
|
nkeynes@1006 | 134 | OP_BRREL,
|
nkeynes@1006 | 135 | OP_BR,
|
nkeynes@1006 | 136 | OP_CALL0, // Call function with no arguments or return value
|
nkeynes@1006 | 137 | OP_OCBI,
|
nkeynes@1006 | 138 | OP_OCBP,
|
nkeynes@1006 | 139 | OP_OCBWB,
|
nkeynes@1006 | 140 | OP_PREF,
|
nkeynes@1006 | 141 |
|
nkeynes@1006 | 142 | // Register moves */
|
nkeynes@1006 | 143 | OP_MOV,
|
nkeynes@1006 | 144 | OP_MOVQ,
|
nkeynes@1006 | 145 | OP_MOVV,
|
nkeynes@1006 | 146 | OP_MOVM,
|
nkeynes@1006 | 147 | OP_MOVSX8,
|
nkeynes@1006 | 148 | OP_MOVSX16,
|
nkeynes@1006 | 149 | OP_MOVSX32,
|
nkeynes@1006 | 150 | OP_MOVZX8,
|
nkeynes@1006 | 151 | OP_MOVZX16,
|
nkeynes@1006 | 152 | OP_MOVZX32,
|
nkeynes@1006 | 153 |
|
nkeynes@1006 | 154 | /* ALU */
|
nkeynes@1006 | 155 | OP_ADD,
|
nkeynes@1006 | 156 | OP_ADDS,
|
nkeynes@1006 | 157 | OP_ADDC,
|
nkeynes@1006 | 158 | OP_ADDCS,
|
nkeynes@1006 | 159 | OP_AND,
|
nkeynes@1006 | 160 | OP_ANDS,
|
nkeynes@1006 | 161 | OP_CMP,
|
nkeynes@1006 | 162 | OP_DIV, /* Unsigned division */
|
nkeynes@1006 | 163 | OP_DIVS, /* Unsigned divison and update flags */
|
nkeynes@1006 | 164 | OP_MUL,
|
nkeynes@1006 | 165 | OP_MULS,
|
nkeynes@1006 | 166 | OP_MULQ,
|
nkeynes@1006 | 167 | OP_MULQS,
|
nkeynes@1006 | 168 | OP_NEG,
|
nkeynes@1006 | 169 | OP_NEGS,
|
nkeynes@1006 | 170 | OP_NOT,
|
nkeynes@1006 | 171 | OP_NOTS,
|
nkeynes@1006 | 172 | OP_OR,
|
nkeynes@1006 | 173 | OP_ORS,
|
nkeynes@1006 | 174 | OP_RCL,
|
nkeynes@1006 | 175 | OP_RCR,
|
nkeynes@1006 | 176 | OP_ROL, /* Rotate left w/o updating flags */
|
nkeynes@1006 | 177 | OP_ROLS, /* Rotate left, and set carry */
|
nkeynes@1006 | 178 | OP_ROR, /* Rotate right */
|
nkeynes@1006 | 179 | OP_RORS, /* Rotate right and set carry */
|
nkeynes@1006 | 180 | OP_SAR, /* Shift arithmetic right */
|
nkeynes@1006 | 181 | OP_SARS, /* Shift arithmetic right and set carry */
|
nkeynes@1006 | 182 | OP_SDIV, /* Signed division */
|
nkeynes@1006 | 183 | OP_SDIVS, /* Signed division and update flags */
|
nkeynes@1006 | 184 | OP_SLL, /* Shift logical left */
|
nkeynes@1006 | 185 | OP_SLLS, /* Shift logical left and set carry */
|
nkeynes@1006 | 186 | OP_SLR, /* Shift logical right */
|
nkeynes@1006 | 187 | OP_SLRS, /* Shift logical right and set carry */
|
nkeynes@1006 | 188 | OP_SUB, /* Subtract, no flags changed/used */
|
nkeynes@1006 | 189 | OP_SUBS, /* Subtract, flag set on overflow */
|
nkeynes@1006 | 190 | OP_SUBB, /* Subtract with borrow */
|
nkeynes@1006 | 191 | OP_SUBBS, /* Subtract with borrow and set carry */
|
nkeynes@1006 | 192 | OP_SHUFFLE, /* Rearrange bytes according to immediate pattern */
|
nkeynes@1006 | 193 | OP_TST,
|
nkeynes@1006 | 194 | OP_XOR,
|
nkeynes@1006 | 195 | OP_XORS,
|
nkeynes@1006 | 196 | OP_XLAT,
|
nkeynes@1006 | 197 |
|
nkeynes@1006 | 198 | /* FPU */
|
nkeynes@1006 | 199 | OP_ABSD,
|
nkeynes@1006 | 200 | OP_ABSF,
|
nkeynes@1006 | 201 | OP_ABSV,
|
nkeynes@1006 | 202 | OP_ADDD,
|
nkeynes@1006 | 203 | OP_ADDF,
|
nkeynes@1006 | 204 | OP_ADDV,
|
nkeynes@1006 | 205 | OP_CMPD,
|
nkeynes@1006 | 206 | OP_CMPF,
|
nkeynes@1006 | 207 | OP_DIVD,
|
nkeynes@1006 | 208 | OP_DIVF,
|
nkeynes@1006 | 209 | OP_DIVV,
|
nkeynes@1006 | 210 | OP_MULD,
|
nkeynes@1006 | 211 | OP_MULF,
|
nkeynes@1006 | 212 | OP_MULV,
|
nkeynes@1006 | 213 | OP_NEGD,
|
nkeynes@1006 | 214 | OP_NEGF,
|
nkeynes@1006 | 215 | OP_NEGV,
|
nkeynes@1006 | 216 | OP_SQRTD,
|
nkeynes@1006 | 217 | OP_SQRTF,
|
nkeynes@1006 | 218 | OP_SQRTV,
|
nkeynes@1006 | 219 | OP_RSQRTD,
|
nkeynes@1006 | 220 | OP_RSQRTF,
|
nkeynes@1006 | 221 | OP_RSQRTV,
|
nkeynes@1006 | 222 | OP_SUBD,
|
nkeynes@1006 | 223 | OP_SUBF,
|
nkeynes@1006 | 224 | OP_SUBV,
|
nkeynes@1006 | 225 | OP_DTOF,
|
nkeynes@1006 | 226 | OP_DTOI,
|
nkeynes@1006 | 227 | OP_FTOD,
|
nkeynes@1006 | 228 | OP_FTOI,
|
nkeynes@1006 | 229 | OP_ITOD,
|
nkeynes@1006 | 230 | OP_ITOF,
|
nkeynes@1006 | 231 | OP_SINCOSF,
|
nkeynes@1006 | 232 | OP_DOTPRODV,
|
nkeynes@1006 | 233 | OP_MATMULV,
|
nkeynes@1006 | 234 |
|
nkeynes@1006 | 235 | // Memory operations - these all indirect through the memory tables.
|
nkeynes@1006 | 236 | OP_LOADB,
|
nkeynes@1006 | 237 | OP_LOADBFW,
|
nkeynes@1006 | 238 | OP_LOADW,
|
nkeynes@1006 | 239 | OP_LOADL,
|
nkeynes@1006 | 240 | OP_LOADQ,
|
nkeynes@1006 | 241 | OP_STOREB,
|
nkeynes@1006 | 242 | OP_STOREW,
|
nkeynes@1006 | 243 | OP_STOREL,
|
nkeynes@1006 | 244 | OP_STOREQ,
|
nkeynes@1006 | 245 | OP_STORELCA,
|
nkeynes@1006 | 246 |
|
nkeynes@1006 | 247 | OP_BRCOND,
|
nkeynes@1006 | 248 | OP_BRCONDDEL, // Delayed branch - sets newpc rather than pc (and is not a terminator)
|
nkeynes@1006 | 249 | OP_RAISEME, // imm mask in, reg in - branch to exception if (reg & mask) == 0
|
nkeynes@1006 | 250 | OP_RAISEMNE, // imm mask in, reg in - branch to exception if (reg & mask) != 0
|
nkeynes@1006 | 251 |
|
nkeynes@1006 | 252 |
|
nkeynes@1006 | 253 | // Native calls (not source machine calls)
|
nkeynes@1006 | 254 | OP_CALLLUT, // Call indirect through base pointer (reg) + displacement
|
nkeynes@1006 | 255 | OP_CALL1, // Call function with single argument and no return value
|
nkeynes@1006 | 256 | OP_CALLR, // Call function with no arguments and a single return value
|
nkeynes@1006 | 257 |
|
nkeynes@1006 | 258 | /********************** SH4-specific macro operations *************************/
|
nkeynes@1006 | 259 | /* TODO: These need to be broken down into smaller operations eventually,
|
nkeynes@1006 | 260 | * especially as some are likely to be partially optimizable. But in the
|
nkeynes@1006 | 261 | * meantime this at least gets things working
|
nkeynes@1006 | 262 | */
|
nkeynes@1006 | 263 |
|
nkeynes@1006 | 264 | /**
|
nkeynes@1006 | 265 | * ADDQSAT32 Rm, Rn - 64-bit Add Rm to Rn, saturating to 32-bits if S==1 (per SH4 MAC.W)
|
nkeynes@1006 | 266 | *
|
nkeynes@1006 | 267 | * if R_S == 0 ->
|
nkeynes@1006 | 268 | * Rn += Rm
|
nkeynes@1006 | 269 | * else ->
|
nkeynes@1006 | 270 | * if overflow32( Rn + Rm ) ->
|
nkeynes@1006 | 271 | * Rn = saturate32( Rn + Rm ) | 0x100000000
|
nkeynes@1006 | 272 | * else ->
|
nkeynes@1006 | 273 | * Rn += Rm
|
nkeynes@1006 | 274 | */
|
nkeynes@1006 | 275 | OP_ADDQSAT32,
|
nkeynes@1006 | 276 |
|
nkeynes@1006 | 277 | /**
|
nkeynes@1006 | 278 | * ADDSAT48 Rm, Rn - 64-bit Add Rm to Rn, saturating to 48-bits if S==1 (per SH4 MAC.L)
|
nkeynes@1006 | 279 | *
|
nkeynes@1006 | 280 | * if R_S == 0 ->
|
nkeynes@1006 | 281 | * Rn += Rm
|
nkeynes@1006 | 282 | * else ->
|
nkeynes@1006 | 283 | * if( Rm + Rn > 0x00007FFFFFFFFFFF ) ->
|
nkeynes@1006 | 284 | * Rn = 0x00007FFFFFFFFFFF
|
nkeynes@1006 | 285 | * else if( Rm + Rn < 0x0000800000000000 ) ->
|
nkeynes@1006 | 286 | * Rn = 0x0000800000000000
|
nkeynes@1006 | 287 | * else ->
|
nkeynes@1006 | 288 | * Rn += Rm
|
nkeynes@1006 | 289 | */
|
nkeynes@1006 | 290 | OP_ADDQSAT48,
|
nkeynes@1006 | 291 |
|
nkeynes@1006 | 292 | /**
|
nkeynes@1006 | 293 | * CMP/STR Rm, Rn - Set T if any byte is the same between Rm and Rn
|
nkeynes@1006 | 294 | *
|
nkeynes@1006 | 295 | * Macro expansion:
|
nkeynes@1006 | 296 | * MOV Rm, %tmp
|
nkeynes@1006 | 297 | * XOR Rn, %tmp
|
nkeynes@1006 | 298 | * TEST 0x000000FF, %tmp
|
nkeynes@1006 | 299 | * TESTne 0x0000FF00, %tmp
|
nkeynes@1006 | 300 | * TESTne 0x00FF0000, %tmp
|
nkeynes@1006 | 301 | * TESTne 0xFF000000, %tmp
|
nkeynes@1006 | 302 | * SETe T
|
nkeynes@1006 | 303 | *
|
nkeynes@1006 | 304 | */
|
nkeynes@1006 | 305 | OP_CMPSTR,
|
nkeynes@1006 | 306 |
|
nkeynes@1006 | 307 | /**
|
nkeynes@1006 | 308 | * DIV1 Rm,Rn performs a single-step division of Rm/Rn, modifying flags
|
nkeynes@1006 | 309 | * as it goes.
|
nkeynes@1006 | 310 | *
|
nkeynes@1006 | 311 | * sign = Rn >> 31
|
nkeynes@1006 | 312 | * Rn = (Rn << 1) | R_T
|
nkeynes@1006 | 313 | * If R_Q == R_M -> Rn = Rn - Rm
|
nkeynes@1006 | 314 | * Else -> Rn = Rn + Rm
|
nkeynes@1006 | 315 | * R_Q = sign ^ R_M ^ (Rn>>31)
|
nkeynes@1006 | 316 | * R_T = (R_Q == R_M) ; or newq == (rn>>31)
|
nkeynes@1006 | 317 | *
|
nkeynes@1006 | 318 | * Macro expansion:
|
nkeynes@1006 | 319 | * LDc R_T
|
nkeynes@1006 | 320 | * RCL 1, Rn
|
nkeynes@1006 | 321 | * SETc temp
|
nkeynes@1006 | 322 | * CMP R_Q, R_M
|
nkeynes@1006 | 323 | * ADDne Rm, Rn
|
nkeynes@1006 | 324 | * SUBeq Rm, Rn
|
nkeynes@1006 | 325 | * MOV Rn, R_Q
|
nkeynes@1006 | 326 | * SHR 31, Rn
|
nkeynes@1006 | 327 | * XOR temp, R_Q
|
nkeynes@1006 | 328 | * XOR R_M, R_Q
|
nkeynes@1006 | 329 | * CMP R_M, R_Q
|
nkeynes@1006 | 330 | * SETe R_T
|
nkeynes@1006 | 331 | */
|
nkeynes@1006 | 332 | OP_DIV1,
|
nkeynes@1006 | 333 |
|
nkeynes@1006 | 334 | /**
|
nkeynes@1006 | 335 | * SHAD Rm, Rn performs an arithmetic shift of Rn as follows:
|
nkeynes@1006 | 336 | * If Rm >= 0 -> Rn = Rn << (Rm&0x1F)
|
nkeynes@1006 | 337 | * If Rm < 0 ->
|
nkeynes@1006 | 338 | * If Rm&0x1F == 0 -> Rn = Rn >> 31
|
nkeynes@1006 | 339 | * Else -> Rn = Rn >> 32 - (Rm&0x1F)
|
nkeynes@1006 | 340 | *
|
nkeynes@1006 | 341 | * CMP 0, Rm
|
nkeynes@1006 | 342 | * ANDuge 0x1F, Rm
|
nkeynes@1006 | 343 | * SLLuge Rm, Rn
|
nkeynes@1006 | 344 | * ORult 0xFFFFFFE0, Rm
|
nkeynes@1006 | 345 | * NEGult Rm
|
nkeynes@1006 | 346 | * SARult Rm, Rn ; unmasked shift
|
nkeynes@1006 | 347 | *
|
nkeynes@1006 | 348 | */
|
nkeynes@1006 | 349 | OP_SHAD, // Shift dynamic arithmetic (left or right)
|
nkeynes@1006 | 350 |
|
nkeynes@1006 | 351 | /**
|
nkeynes@1006 | 352 | * SHLD Rm, Rn performs a logical shift of Rn as follows:
|
nkeynes@1006 | 353 | * If Rm >= 0 -> Rn = Rn << (Rm&0x1F)
|
nkeynes@1006 | 354 | * If Rm < 0 ->
|
nkeynes@1006 | 355 | * If Rm&0x1F == 0 -> Rn = 0
|
nkeynes@1006 | 356 | * Else -> Rn = Rn >> 32 - (Rm&0x1F)
|
nkeynes@1006 | 357 | */
|
nkeynes@1006 | 358 | OP_SHLD, // Shift dynamic logical (left or right)
|
nkeynes@1006 | 359 | } xir_opcode_t;
|
nkeynes@1006 | 360 |
|
nkeynes@1006 | 361 | #define MAX_OP0_OPCODE OP_BARRIER
|
nkeynes@1006 | 362 | #define MAX_OP1_OPCODE OP_PREF
|
nkeynes@1006 | 363 | #define MAX_OP2_OPCODE OP_SHLD
|
nkeynes@1006 | 364 | #define NUM_OP0_OPCODES (MAX_OP0_OPCODE+1)
|
nkeynes@1006 | 365 | #define NUM_OP1_OPCODES (MAX_OP1_OPCODE-MAX_OP0_OPCODE)
|
nkeynes@1006 | 366 | #define NUM_OP2_OPCODES (MAX_OP2_OPCODE-MAX_OP1_OPCODE)
|
nkeynes@1006 | 367 | #define MAX_OPCODE (MAX_OP2_OPCODE)
|
nkeynes@1006 | 368 | #define NUM_OPCODES (MAX_OP2_OPCODE+1)
|
nkeynes@1006 | 369 |
|
nkeynes@1006 | 370 | typedef struct xir_op {
|
nkeynes@1006 | 371 | xir_opcode_t opcode;
|
nkeynes@1006 | 372 | xir_cc_t cond;
|
nkeynes@1006 | 373 | struct xir_operand operand[2];
|
nkeynes@1006 | 374 | struct xir_op *next; /* Next instruction (normal path) - NULL in the case of the last instruction */
|
nkeynes@1006 | 375 | struct xir_op *prev; /* Previous instruction (normal path) - NULL in the case of the first instruction */
|
nkeynes@1006 | 376 | struct xir_op *exc; /* Next instruction if the opcode takes an exception - NULL if no exception is possible */
|
nkeynes@1006 | 377 | } *xir_op_t;
|
nkeynes@1006 | 378 |
|
nkeynes@1006 | 379 | /* Defined in xlat/xlat.h */
|
nkeynes@1006 | 380 | typedef struct xlat_source_machine *xlat_source_machine_t;
|
nkeynes@1006 | 381 | typedef struct xlat_target_machine *xlat_target_machine_t;
|
nkeynes@1006 | 382 |
|
nkeynes@1006 | 383 | /**
|
nkeynes@1006 | 384 | * Source data structure. This mainly exists to manage memory for XIR operations
|
nkeynes@1006 | 385 | */
|
nkeynes@1006 | 386 | typedef struct xir_basic_block {
|
nkeynes@1006 | 387 | xir_op_t ir_begin; /* Beginning of code block */
|
nkeynes@1006 | 388 | xir_op_t ir_end; /* End of code block (Last instruction in code block) */
|
nkeynes@1006 | 389 | xir_op_t ir_ptr; /* First unallocated instruction in allocation block */
|
nkeynes@1006 | 390 | xir_op_t ir_alloc_begin; /* Beginning of memory allocation */
|
nkeynes@1006 | 391 | xir_op_t ir_alloc_end; /* End of allocation */
|
nkeynes@1006 | 392 | uint32_t pc_begin; /* first instruction */
|
nkeynes@1006 | 393 | uint32_t pc_end; /* next instruction after end */
|
nkeynes@1006 | 394 | xlat_source_machine_t source;
|
nkeynes@1006 | 395 | struct mem_region_fn **address_space; /* source machine memory access table */
|
nkeynes@1006 | 396 | } *xir_basic_block_t;
|
nkeynes@1006 | 397 |
|
nkeynes@1006 | 398 | typedef int xir_offset_t;
|
nkeynes@1006 | 399 |
|
nkeynes@1006 | 400 | /**************************** OP Information ******************************/
|
nkeynes@1006 | 401 |
|
nkeynes@1006 | 402 | /* Instruction operand modes */
|
nkeynes@1006 | 403 | #define OPM_NO 0x000000 /* No operands */
|
nkeynes@1006 | 404 | #define OPM_R 0x000001 /* Single operand, read-only */
|
nkeynes@1006 | 405 | #define OPM_W 0x000002 /* Single operand, write-only */
|
nkeynes@1006 | 406 | #define OPM_RW 0x000003 /* Single operand, read-write */
|
nkeynes@1006 | 407 | #define OPM_R_R 0x000005 /* Two operands, both read-only */
|
nkeynes@1006 | 408 | #define OPM_R_W 0x000009 /* Two operands, first read-only, second write-only */
|
nkeynes@1006 | 409 | #define OPM_R_RW 0x00000D /* Two operands, first read-only, second read-write */
|
nkeynes@1006 | 410 | #define OPM_I_I 0x000000 /* Both operands i32 */
|
nkeynes@1006 | 411 | #define OPM_Q_Q 0x000110 /* Both operands i64 */
|
nkeynes@1006 | 412 | #define OPM_I_Q 0x000100 /* i32,i64 operands */
|
nkeynes@1006 | 413 | #define OPM_Q_I 0x000010 /* i64,i32 operands */
|
nkeynes@1006 | 414 | #define OPM_F_F 0x000220 /* Both operands float */
|
nkeynes@1006 | 415 | #define OPM_D_D 0x000330 /* Both operands double */
|
nkeynes@1006 | 416 | #define OPM_I_F 0x000200 /* i32,float operands */
|
nkeynes@1006 | 417 | #define OPM_I_D 0x000300 /* i32,double operands */
|
nkeynes@1006 | 418 | #define OPM_F_I 0x000020 /* float,i32 operands */
|
nkeynes@1006 | 419 | #define OPM_D_I 0x000030 /* double,i32 operands */
|
nkeynes@1006 | 420 | #define OPM_F_D 0x000320 /* float,double operands */
|
nkeynes@1006 | 421 | #define OPM_D_F 0x000230 /* double,float operands */
|
nkeynes@1006 | 422 | #define OPM_V_V 0x000440 /* vec4,vec4 operands */
|
nkeynes@1006 | 423 | #define OPM_V_M 0x000540 /* vec4,matrix16 operands */
|
nkeynes@1006 | 424 | #define OPM_M_M 0x000550 /* mat16,mat16 operands */
|
nkeynes@1006 | 425 | #define OPM_TR 0x001000 /* Use T */
|
nkeynes@1006 | 426 | #define OPM_TW 0x002000 /* Set T */
|
nkeynes@1006 | 427 | #define OPM_TRW 0x003000 /* Use+Set T */
|
nkeynes@1006 | 428 | #define OPM_EXC 0x004000 /* May raise an exception, clobbers volatiles */
|
nkeynes@1006 | 429 | #define OPM_CLB 0x008000 /* Clobbers volatile registers */
|
nkeynes@1006 | 430 | #define OPM_CLBT 0x00C000 /* Clobbers 'temporary regs' but not the full volatile set */
|
nkeynes@1006 | 431 | #define OPM_TERM 0x010000 /* Terminates block. (Must be final instruction in block) */
|
nkeynes@1006 | 432 |
|
nkeynes@1006 | 433 | #define OPM_R_R_TW (OPM_R_R|OPM_TW) /* Read two ops + set flags */
|
nkeynes@1006 | 434 | #define OPM_R_RW_TR (OPM_R_RW|OPM_TR) /* Read/write + use flags */
|
nkeynes@1006 | 435 | #define OPM_R_RW_TW (OPM_R_RW|OPM_TW) /* Read/write + set flags */
|
nkeynes@1006 | 436 | #define OPM_R_RW_TRW (OPM_R_RW|OPM_TRW) /* Read/write + use/set flags */
|
nkeynes@1006 | 437 | #define OPM_R_W_TW (OPM_R_W|OPM_TW) /* Read/write + set flags */
|
nkeynes@1006 | 438 | #define OPM_RW_TW (OPM_RW|OPM_TW) /* Read/write single op + set flags */
|
nkeynes@1006 | 439 | #define OPM_RW_TRW (OPM_RW|OPM_TRW) /* Read/write single op + use/set flags */
|
nkeynes@1006 | 440 | #define OPM_FRW (OPM_RW|OPM_F_F) /* Read/write single float op */
|
nkeynes@1006 | 441 | #define OPM_FR_FRW (OPM_R_RW|OPM_F_F) /* Read/write float op pair */
|
nkeynes@1006 | 442 | #define OPM_FR_FW (OPM_R_W|OPM_F_F) /* Read/write float op pair */
|
nkeynes@1006 | 443 | #define OPM_FR_FR_TW (OPM_R_R_TW|OPM_F_F) /* Read two float ops + set flags */
|
nkeynes@1006 | 444 | #define OPM_DRW (OPM_RW|OPM_D_D) /* Read/write single double op */
|
nkeynes@1006 | 445 | #define OPM_DR_DRW (OPM_R_RW|OPM_D_D) /* Read/write double op pair */
|
nkeynes@1006 | 446 | #define OPM_DR_DW (OPM_R_W|OPM_D_D) /* Read/write double op pair */
|
nkeynes@1006 | 447 | #define OPM_VR_VRW (OPM_R_RW|OPM_V_V) /* Vector Read/write double op pair */
|
nkeynes@1006 | 448 | #define OPM_VR_VW (OPM_R_W|OPM_V_V) /* Vector Read/write double op pair */
|
nkeynes@1006 | 449 | #define OPM_DR_DR_TW (OPM_R_R_TW|OPM_D_D) /* Read two double ops + set flags */
|
nkeynes@1006 | 450 |
|
nkeynes@1006 | 451 | #define OPM_R_W_EXC (OPM_R_W|OPM_EXC) /* Read first, write second, possible exc (typical load) */
|
nkeynes@1006 | 452 | #define OPM_R_R_EXC (OPM_R_R|OPM_EXC) /* Read first, write second, possible exc (typical store) */
|
nkeynes@1006 | 453 | #define OPM_R_EXC (OPM_R|OPM_EXC) /* Read-only single op, possible exc (eg pref) */
|
nkeynes@1006 | 454 |
|
nkeynes@1006 | 455 | struct xir_opcode_entry {
|
nkeynes@1006 | 456 | char *name;
|
nkeynes@1006 | 457 | int mode;
|
nkeynes@1006 | 458 | };
|
nkeynes@1006 | 459 |
|
nkeynes@1006 | 460 | struct xir_symbol_entry {
|
nkeynes@1006 | 461 | const char *name;
|
nkeynes@1006 | 462 | void *ptr;
|
nkeynes@1006 | 463 | };
|
nkeynes@1006 | 464 |
|
nkeynes@1006 | 465 | extern const struct xir_opcode_entry XIR_OPCODE_TABLE[];
|
nkeynes@1006 | 466 | #define XOP_IS_SRCREG(op,n) (op->operand[n].type == SOURCE_REGISTER_OPERAND)
|
nkeynes@1006 | 467 | #define XOP_IS_TGTREG(op,n) (op->operand[n].type == TARGET_REGISTER_OPERAND)
|
nkeynes@1006 | 468 | #define XOP_IS_INTIMM(op,n) (op->operand[n].type == INT_IMM_OPERAND)
|
nkeynes@1006 | 469 | #define XOP_IS_FLOATIMM(op,n) (op->operand[n].type == FLOAT_IMM_OPERAND)
|
nkeynes@1006 | 470 | #define XOP_IS_DOUBLEIMM(op,n) (op->operand[n].type == DOUBLE_IMM_OPERAND)
|
nkeynes@1006 | 471 | #define XOP_IS_QUADIMM(op,n) (op->operand[n].type == QUAD_IMM_OPERAND)
|
nkeynes@1006 | 472 | #define XOP_IS_PTRIMM(op,n) (op->operand[n].type == POINTER_OPERAND)
|
nkeynes@1006 | 473 | #define XOP_IS_IMM(op,n) (op->operand[n].type > TARGET_REGISTER_OPERAND)
|
nkeynes@1006 | 474 | #define XOP_IS_REG(op,n) (XOP_IS_SRCREG(op,n)||XOP_IS_TGTREG(op,n)
|
nkeynes@1006 | 475 | #define XOP_IS_FORM(op,t1,t2) (op->operand[0].type == t1 && op->operand[1].type == t2)
|
nkeynes@1006 | 476 |
|
nkeynes@1006 | 477 | #define XOP_REG(op,n) (op->operand[n].value.i)
|
nkeynes@1006 | 478 | #define XOP_REG1(op) XOP_REG(op,0)
|
nkeynes@1006 | 479 | #define XOP_REG2(op) XOP_REG(op,1)
|
nkeynes@1006 | 480 | #define XOP_INT(op,n) (op->operand[n].value.i)
|
nkeynes@1006 | 481 | #define XOP_QUAD(op,n) (op->operand[n].value.q)
|
nkeynes@1006 | 482 | #define XOP_FLOAT(op,n) (op->operand[n].value.f)
|
nkeynes@1006 | 483 | #define XOP_DOUBLE(op,n) (op->operand[n].value.d)
|
nkeynes@1006 | 484 | #define XOP_PTR(op,n) (op->operand[n].value.p)
|
nkeynes@1006 | 485 |
|
nkeynes@1006 | 486 | #define XOP_IS_TERMINATOR(op) (XIR_OPCODE_TABLE[op->opcode].mode & OPM_TERM)
|
nkeynes@1006 | 487 | #define XOP_HAS_0_OPERANDS(op) ((XIR_OPCODE_TABLE[op->opcode].mode & 0x0F) == 0)
|
nkeynes@1006 | 488 | #define XOP_HAS_1_OPERAND(op) ((XIR_OPCODE_TABLE[op->opcode].mode & 0x0F) < 4)
|
nkeynes@1006 | 489 | #define XOP_HAS_2_OPERANDS(op) ((XIR_OPCODE_TABLE[op->opcode].mode & 0x0C) != 0)
|
nkeynes@1006 | 490 | #define XOP_HAS_EXCEPTION(op) ((XIR_OPCODE_TABLE[op->opcode].mode & 0xC000) == OPM_EXC)
|
nkeynes@1006 | 491 |
|
nkeynes@1006 | 492 | #define XOP_READS_OP1(op) (XIR_OPCODE_TABLE[op->opcode].mode & 0x01)
|
nkeynes@1006 | 493 | #define XOP_WRITES_OP1(op) (XIR_OPCODE_TABLE[op->opcode].mode & 0x02)
|
nkeynes@1006 | 494 | #define XOP_READS_OP2(op) (XIR_OPCODE_TABLE[op->opcode].mode & 0x04)
|
nkeynes@1006 | 495 | #define XOP_WRITES_OP2(op) (XIR_OPCODE_TABLE[op->opcode].mode & 0x08)
|
nkeynes@1006 | 496 | #define XOP_READS_FLAGS(op) ((XIR_OPCODE_TABLE[op->opcode].mode & OPM_TR) || (op->cond != CC_TRUE && op->opcode != OP_LD))
|
nkeynes@1006 | 497 | #define XOP_WRITES_FLAGS(op) (XIR_OPCODE_TABLE[op->opcode].mode & OPM_TW)
|
nkeynes@1006 | 498 |
|
nkeynes@1006 | 499 | #define XOP_READS_REG1(op) (XOP_READS_OP1(op) && XOP_IS_REG(op,0))
|
nkeynes@1006 | 500 | #define XOP_WRITES_REG1(op) (XOP_WRITES_OP1(op) && XOP_IS_REG(op,0))
|
nkeynes@1006 | 501 | #define XOP_READS_REG2(op) (XOP_READS_OP2(op) && XOP_IS_REG(op,1))
|
nkeynes@1006 | 502 | #define XOP_WRITES_REG2(op) (XOP_WRITES_OP2(op) && XOP_IS_REG(op,1))
|
nkeynes@1006 | 503 |
|
nkeynes@1006 | 504 | #define XOP_TYPE1(op) (op->operand[0].type)
|
nkeynes@1006 | 505 | #define XOP_TYPE2(op) (op->operand[1].type)
|
nkeynes@1006 | 506 | #define XOP_OPERAND(op,i) (&op->operand[i])
|
nkeynes@1006 | 507 |
|
nkeynes@1006 | 508 | /******************************* OP Constructors ******************************/
|
nkeynes@1006 | 509 |
|
nkeynes@1006 | 510 | 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 | 511 | xir_op_t xir_append_op2cc( xir_basic_block_t xbb, int op, int cc, int arg0type, uint32_t arg0, int arg1type, uint32_t arg1 );
|
nkeynes@1006 | 512 | xir_op_t xir_append_float_op2( xir_basic_block_t xbb, int op, float imm1, int arg1type, uint32_t arg1 );
|
nkeynes@1006 | 513 | xir_op_t xir_append_ptr_op2( xir_basic_block_t xbb, int op, void *arg0, int arg1type, uint32_t arg1 );
|
nkeynes@1006 | 514 |
|
nkeynes@1006 | 515 |
|
nkeynes@1006 | 516 | #define XOP1( op, arg0 ) xir_append_op2(xbb, op, SOURCE_REGISTER_OPERAND, arg0, NO_OPERAND, 0)
|
nkeynes@1006 | 517 | #define XOP1CC( op, cc, arg0 ) xir_append_op2cc(xbb, op, cc, SOURCE_REGISTER_OPERAND, arg0, NO_OPERAND, 0)
|
nkeynes@1006 | 518 | #define XOP1I( op, arg0 ) xir_append_op2(xbb, op, INT_IMM_OPERAND, arg0, NO_OPERAND, 0)
|
nkeynes@1006 | 519 | #define XOP2I( op, arg0, arg1 ) xir_append_op2(xbb, op, INT_IMM_OPERAND, arg0, SOURCE_REGISTER_OPERAND, arg1)
|
nkeynes@1006 | 520 | #define XOP2II( op, arg0, arg1 ) xir_append_op2(xbb, op, INT_IMM_OPERAND, arg0, INT_IMM_OPERAND, arg1)
|
nkeynes@1006 | 521 | #define XOP2IICC( op, cc, arg0, arg1 ) xir_append_op2cc(xbb, op, cc, INT_IMM_OPERAND, arg0, INT_IMM_OPERAND, arg1)
|
nkeynes@1006 | 522 | #define XOP2( op, arg0, arg1 ) xir_append_op2(xbb, op, SOURCE_REGISTER_OPERAND, arg0, SOURCE_REGISTER_OPERAND, arg1)
|
nkeynes@1006 | 523 | #define XOP2CC( op, cc, arg0, arg1 ) xir_append_op2cc(xbb, op, cc, SOURCE_REGISTER_OPERAND, arg0, SOURCE_REGISTER_OPERAND, arg1)
|
nkeynes@1006 | 524 | #define XOP2F( op, arg0, arg1 ) xir_append_float_op2(xbb, op, arg0, SOURCE_REGISTER_OPERAND, arg1)
|
nkeynes@1006 | 525 | #define XOP2P( op, arg0, arg1 ) xir_append_ptr_op2(xbb, op, arg0, SOURCE_REGISTER_OPERAND, arg1)
|
nkeynes@1006 | 526 | #define XOP0( op ) xir_append_op2(xbb, op, NO_OPERAND, 0, NO_OPERAND, 0)
|
nkeynes@1006 | 527 | #define XOPCALL0( arg0 ) xir_append_ptr_op2(xbb, OP_CALL0, arg0, NO_OPERAND, 0)
|
nkeynes@1006 | 528 | #define XOPCALL1( arg0, arg1 ) xir_append_ptr_op2(xbb, OP_CALL1, arg0, SOURCE_REGISTER_OPERAND, arg1)
|
nkeynes@1006 | 529 | #define XOPCALL1I( arg0, arg1 ) xir_append_ptr_op2(xbb, OP_CALL1, arg0, INT_IMM_OPERAND, arg1)
|
nkeynes@1006 | 530 | #define XOPCALLR( arg0, arg1 ) xir_append_ptr_op2(xbb, OP_CALLR, arg0, SOURCE_REGISTER_OPERAND, arg1)
|
nkeynes@1006 | 531 |
|
nkeynes@1006 | 532 | /**************************** IR Modification ******************************/
|
nkeynes@1006 | 533 |
|
nkeynes@1006 | 534 | /**
|
nkeynes@1006 | 535 | * Insert a new instruction immediately before the given existing inst.
|
nkeynes@1006 | 536 | */
|
nkeynes@1006 | 537 | void xir_insert_op( xir_op_t op, xir_op_t before );
|
nkeynes@1006 | 538 |
|
nkeynes@1006 | 539 | /**
|
nkeynes@1006 | 540 | * Insert the block start..end immediately before the given instruction
|
nkeynes@1006 | 541 | */
|
nkeynes@1006 | 542 | void xir_insert_block( xir_op_t start, xir_op_t end, xir_op_t before );
|
nkeynes@1006 | 543 |
|
nkeynes@1006 | 544 | /**
|
nkeynes@1006 | 545 | * Remove the specified instruction completely from the block in which it appears.
|
nkeynes@1006 | 546 | * Note: removing terminators with this method may break the representation.
|
nkeynes@1006 | 547 | * Op itself is not modified.
|
nkeynes@1006 | 548 | */
|
nkeynes@1006 | 549 | void xir_remove_op( xir_op_t op );
|
nkeynes@1006 | 550 |
|
nkeynes@1006 | 551 | /**
|
nkeynes@1006 | 552 | * Apply a shuffle directly to the given operand, and return the result
|
nkeynes@1006 | 553 | */
|
nkeynes@1006 | 554 | uint32_t xir_shuffle_imm32( uint32_t shuffle, uint32_t operand );
|
nkeynes@1006 | 555 |
|
nkeynes@1006 | 556 | /**
|
nkeynes@1006 | 557 | * Apply a shuffle transitively to the operation (which must also be a shuffle).
|
nkeynes@1006 | 558 | * For example, given the sequence
|
nkeynes@1006 | 559 | * op1: shuffle 0x2134, r12
|
nkeynes@1006 | 560 | * op2: shuffle 0x3412, r12
|
nkeynes@1006 | 561 | * xir_trans_shuffle( 0x2134, op2 ) can be used to replace op2 wih
|
nkeynes@1006 | 562 | * shuffle 0x3421, r12
|
nkeynes@1006 | 563 | */
|
nkeynes@1006 | 564 | void xir_shuffle_op( uint32_t shuffle, xir_op_t it );
|
nkeynes@1006 | 565 |
|
nkeynes@1006 | 566 | /**
|
nkeynes@1006 | 567 | * Return the number of instructions that would be emitted by xir_shuffle_lower
|
nkeynes@1006 | 568 | * for the given instruction (not including the leading nop, if there is one)
|
nkeynes@1006 | 569 | */
|
nkeynes@1006 | 570 | int xir_shuffle_lower_size( xir_op_t it );
|
nkeynes@1006 | 571 |
|
nkeynes@1006 | 572 | /**
|
nkeynes@1006 | 573 | * Transform a shuffle instruction into an equivalent sequence of shifts, and
|
nkeynes@1006 | 574 | * logical operations.
|
nkeynes@1006 | 575 | * @return the last instruction in the resultant sequence (which may be the
|
nkeynes@1006 | 576 | * original instruction pointer).
|
nkeynes@1006 | 577 | */
|
nkeynes@1006 | 578 | xir_op_t xir_shuffle_lower( xir_basic_block_t xbb, xir_op_t it, int tmp1, int tmp2 );
|
nkeynes@1006 | 579 |
|
nkeynes@1006 | 580 |
|
nkeynes@1006 | 581 | /**************************** Debugging ******************************/
|
nkeynes@1006 | 582 |
|
nkeynes@1006 | 583 | /**
|
nkeynes@1006 | 584 | * Verify the integrity of an IR block - abort with assertion failure on any
|
nkeynes@1006 | 585 | * errors.
|
nkeynes@1006 | 586 | */
|
nkeynes@1006 | 587 | void xir_verify_block( xir_op_t start, xir_op_t end );
|
nkeynes@1006 | 588 |
|
nkeynes@1006 | 589 | /**
|
nkeynes@1006 | 590 | * Set the register name mappings for source and target registers - only really
|
nkeynes@1006 | 591 | * used for debug output
|
nkeynes@1006 | 592 | */
|
nkeynes@1006 | 593 | void xir_set_register_names( const char **source_regs, const char **target_regs );
|
nkeynes@1006 | 594 |
|
nkeynes@1006 | 595 | /**
|
nkeynes@1006 | 596 | * Set the symbol table mappings for target points - also only really for
|
nkeynes@1006 | 597 | * debugging output.
|
nkeynes@1006 | 598 | */
|
nkeynes@1006 | 599 | void xir_set_symbol_table( const struct xir_symbol_entry *symtab );
|
nkeynes@1006 | 600 |
|
nkeynes@1006 | 601 | /**
|
nkeynes@1006 | 602 | * Dump the specified block of IR to stdout
|
nkeynes@1006 | 603 | */
|
nkeynes@1006 | 604 | void xir_dump_block( xir_op_t start, xir_op_t end );
|
nkeynes@1006 | 605 |
|
nkeynes@1006 | 606 |
|
nkeynes@1006 | 607 | #endif /* !lxdream_xir_H */
|