nkeynes@1006 | 1 | /**
|
nkeynes@1006 | 2 | * $Id: xir.h 931 2008-10-31 02:57:59Z nkeynes $
|
nkeynes@1006 | 3 | *
|
nkeynes@1006 | 4 | * x86/x86-64 target support
|
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 | #include <assert.h>
|
nkeynes@1006 | 19 |
|
nkeynes@1006 | 20 | #include "xlat/xir.h"
|
nkeynes@1006 | 21 | #include "xlat/xlat.h"
|
nkeynes@1006 | 22 | #include "xlat/x86/x86op.h"
|
nkeynes@1006 | 23 |
|
nkeynes@1006 | 24 | static char *x86_reg_names[] = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi",
|
nkeynes@1006 | 25 | "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
|
nkeynes@1006 | 26 | "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
|
nkeynes@1006 | 27 | "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15" };
|
nkeynes@1006 | 28 |
|
nkeynes@1006 | 29 | void x86_target_lower( xir_basic_block_t xbb, xir_op_t begin, xir_op_t end );
|
nkeynes@1006 | 30 | uint32_t x86_target_get_code_size( xir_op_t begin, xir_op_t end );
|
nkeynes@1006 | 31 | uint32_t x86_target_codegen( target_data_t td, xir_op_t begin, xir_op_t end );
|
nkeynes@1006 | 32 |
|
nkeynes@1006 | 33 | struct xlat_target_machine x86_target_machine = { "x86", x86_reg_names,
|
nkeynes@1006 | 34 | NULL, x86_target_lower, x86_target_get_code_size, x86_target_codegen
|
nkeynes@1006 | 35 | };
|
nkeynes@1006 | 36 |
|
nkeynes@1006 | 37 |
|
nkeynes@1006 | 38 |
|
nkeynes@1006 | 39 | /******************************************************************************
|
nkeynes@1006 | 40 | * Target lowering - Replace higher level/unsupported operations *
|
nkeynes@1006 | 41 | * with equivalent x86 sequences. Note that we don't lower conditional ops *
|
nkeynes@1006 | 42 | * here - that's left to final codegen as we can't represent local branches *
|
nkeynes@1006 | 43 | * in XIR *
|
nkeynes@1006 | 44 | *****************************************************************************/
|
nkeynes@1006 | 45 |
|
nkeynes@1006 | 46 | #define MEM_FUNC_OFFSET(name) offsetof( struct mem_region_fn, name )
|
nkeynes@1006 | 47 |
|
nkeynes@1006 | 48 | /**
|
nkeynes@1006 | 49 | * Construct an XLAT operation and append it to the code block. For 64-bit
|
nkeynes@1006 | 50 | * code this may need to be a load/xlat sequence as we can't encode a 64-bit
|
nkeynes@1006 | 51 | * displacement.
|
nkeynes@1006 | 52 | */
|
nkeynes@1006 | 53 | static inline void xir_append_xlat( xir_basic_block_t xbb, void *address_space,
|
nkeynes@1006 | 54 | int opertype, int operval )
|
nkeynes@1006 | 55 | {
|
nkeynes@1006 | 56 | if( sizeof(void *) == 8 ) {
|
nkeynes@1006 | 57 | xir_append_ptr_op2( xbb, OP_MOVQ, address_space, SOURCE_REGISTER_OPERAND, REG_TMP4 );
|
nkeynes@1006 | 58 | xir_append_op2( xbb, OP_XLAT, SOURCE_REGISTER_OPERAND, REG_TMP4, opertype, operval );
|
nkeynes@1006 | 59 | } else {
|
nkeynes@1006 | 60 | xir_append_ptr_op2( xbb, OP_XLAT, address_space, opertype, operval );
|
nkeynes@1006 | 61 | }
|
nkeynes@1006 | 62 | }
|
nkeynes@1006 | 63 |
|
nkeynes@1006 | 64 |
|
nkeynes@1006 | 65 | /* Replace LOAD/STORE with low-level calling sequence eg:
|
nkeynes@1006 | 66 | * mov addr, %eax
|
nkeynes@1006 | 67 | * mov addr, %tmp3
|
nkeynes@1006 | 68 | * slr 12, %tmp3
|
nkeynes@1006 | 69 | * xlat $sh4_address_space, %tmp3
|
nkeynes@1006 | 70 | * call/lut %tmp3, $operation_offset
|
nkeynes@1006 | 71 | * mov %eax, result
|
nkeynes@1006 | 72 | */
|
nkeynes@1006 | 73 | static void lower_mem_load( xir_basic_block_t xbb, xir_op_t it, void *addr_space, int offset )
|
nkeynes@1006 | 74 | {
|
nkeynes@1006 | 75 | xir_op_t start =
|
nkeynes@1006 | 76 | xir_append_op2( xbb, OP_MOV, it->operand[0].type, it->operand[0].value.i, TARGET_REGISTER_OPERAND, REG_ARG1 );
|
nkeynes@1006 | 77 | xir_append_op2( xbb, OP_MOV, it->operand[0].type, it->operand[0].value.i, SOURCE_REGISTER_OPERAND, REG_TMP3 );
|
nkeynes@1006 | 78 | xir_append_op2( xbb, OP_SLR, INT_IMM_OPERAND, 12, SOURCE_REGISTER_OPERAND, REG_TMP3 );
|
nkeynes@1006 | 79 | xir_append_xlat( xbb, addr_space, SOURCE_REGISTER_OPERAND, REG_TMP3 );
|
nkeynes@1006 | 80 | xir_insert_block(start,xbb->ir_ptr-1, it);
|
nkeynes@1006 | 81 | if( XOP_WRITES_OP2(it) ) {
|
nkeynes@1006 | 82 | xir_insert_op( xir_append_op2( xbb, OP_MOV, TARGET_REGISTER_OPERAND, REG_RESULT1, it->operand[1].type, it->operand[1].value.i ), it->next );
|
nkeynes@1006 | 83 | }
|
nkeynes@1006 | 84 | /* Replace original op with CALLLUT */
|
nkeynes@1006 | 85 | it->opcode = OP_CALLLUT;
|
nkeynes@1006 | 86 | it->operand[0].type = SOURCE_REGISTER_OPERAND;
|
nkeynes@1006 | 87 | it->operand[0].value.i = REG_TMP3;
|
nkeynes@1006 | 88 | it->operand[1].type = INT_IMM_OPERAND;
|
nkeynes@1006 | 89 | it->operand[1].value.i = offset;
|
nkeynes@1006 | 90 | }
|
nkeynes@1006 | 91 |
|
nkeynes@1006 | 92 | static void lower_mem_store( xir_basic_block_t xbb, xir_op_t it, void *addr_space, int offset )
|
nkeynes@1006 | 93 | {
|
nkeynes@1006 | 94 | xir_op_t start =
|
nkeynes@1006 | 95 | xir_append_op2( xbb, OP_MOV, it->operand[0].type, it->operand[0].value.i, TARGET_REGISTER_OPERAND, REG_ARG1 );
|
nkeynes@1006 | 96 | xir_append_op2( xbb, OP_MOV, it->operand[1].type, it->operand[1].value.i, TARGET_REGISTER_OPERAND, REG_ARG2 );
|
nkeynes@1006 | 97 | xir_append_op2( xbb, OP_MOV, it->operand[0].type, it->operand[0].value.i, SOURCE_REGISTER_OPERAND, REG_TMP3 );
|
nkeynes@1006 | 98 | xir_append_op2( xbb, OP_SLR, INT_IMM_OPERAND, 12, SOURCE_REGISTER_OPERAND, REG_TMP3 );
|
nkeynes@1006 | 99 | xir_append_xlat( xbb, addr_space, SOURCE_REGISTER_OPERAND, REG_TMP3 );
|
nkeynes@1006 | 100 | xir_insert_block(start,xbb->ir_ptr-1, it);
|
nkeynes@1006 | 101 | /* Replace original op with CALLLUT */
|
nkeynes@1006 | 102 | it->opcode = OP_CALLLUT;
|
nkeynes@1006 | 103 | it->operand[0].type = SOURCE_REGISTER_OPERAND;
|
nkeynes@1006 | 104 | it->operand[0].value.i = REG_TMP3;
|
nkeynes@1006 | 105 | it->operand[1].type = INT_IMM_OPERAND;
|
nkeynes@1006 | 106 | it->operand[1].value.i = offset;
|
nkeynes@1006 | 107 | }
|
nkeynes@1006 | 108 |
|
nkeynes@1006 | 109 | static void lower_mem_loadq( xir_basic_block_t xbb, xir_op_t it, void *addr_space )
|
nkeynes@1006 | 110 | {
|
nkeynes@1006 | 111 | int resulttype = it->operand[1].type;
|
nkeynes@1006 | 112 | uint32_t resultval = it->operand[1].value.i;
|
nkeynes@1006 | 113 |
|
nkeynes@1006 | 114 | /* First block */
|
nkeynes@1006 | 115 | xir_op_t start =
|
nkeynes@1006 | 116 | xir_append_op2( xbb, OP_MOV, it->operand[0].type, it->operand[0].value.i, TARGET_REGISTER_OPERAND, REG_ARG1 );
|
nkeynes@1006 | 117 | xir_append_op2( xbb, OP_MOV, it->operand[0].type, it->operand[0].value.i, SOURCE_REGISTER_OPERAND, REG_TMP3 );
|
nkeynes@1006 | 118 | xir_append_op2( xbb, OP_SLR, INT_IMM_OPERAND, 12, SOURCE_REGISTER_OPERAND, REG_TMP3 );
|
nkeynes@1006 | 119 | xir_append_xlat( xbb, addr_space, SOURCE_REGISTER_OPERAND, REG_TMP3 );
|
nkeynes@1006 | 120 | xir_insert_block(start,xbb->ir_ptr-1, it);
|
nkeynes@1006 | 121 | /* Replace original op with CALLLUT */
|
nkeynes@1006 | 122 | it->opcode = OP_CALLLUT;
|
nkeynes@1006 | 123 | it->operand[0].type = SOURCE_REGISTER_OPERAND;
|
nkeynes@1006 | 124 | it->operand[0].value.i = REG_TMP3;
|
nkeynes@1006 | 125 | it->operand[1].type = INT_IMM_OPERAND;
|
nkeynes@1006 | 126 | it->operand[1].value.i = MEM_FUNC_OFFSET(read_long);
|
nkeynes@1006 | 127 |
|
nkeynes@1006 | 128 | /* Second block */
|
nkeynes@1006 | 129 | start = xir_append_op2( xbb, OP_MOV, TARGET_REGISTER_OPERAND, REG_RESULT1, resulttype, resultval+1 );
|
nkeynes@1006 | 130 | xir_append_op2( xbb, OP_ADD, INT_IMM_OPERAND, 4, SOURCE_REGISTER_OPERAND, REG_ARG1 );
|
nkeynes@1006 | 131 | xir_op_t fin = xir_append_op2( xbb, OP_CALLLUT, SOURCE_REGISTER_OPERAND, REG_TMP3, INT_IMM_OPERAND, MEM_FUNC_OFFSET(read_long) );
|
nkeynes@1006 | 132 | xir_append_op2( xbb, OP_MOV, TARGET_REGISTER_OPERAND, REG_RESULT1, resulttype, resultval );
|
nkeynes@1006 | 133 | fin->exc = it->exc;
|
nkeynes@1006 | 134 | xir_insert_block(start, xbb->ir_ptr-1, it->next);
|
nkeynes@1006 | 135 | }
|
nkeynes@1006 | 136 |
|
nkeynes@1006 | 137 | static void lower_mem_storeq( xir_basic_block_t xbb, xir_op_t it, void *addr_space )
|
nkeynes@1006 | 138 | {
|
nkeynes@1006 | 139 | int argtype = it->operand[1].type;
|
nkeynes@1006 | 140 | uint32_t argval = it->operand[1].value.i;
|
nkeynes@1006 | 141 |
|
nkeynes@1006 | 142 | /* First block */
|
nkeynes@1006 | 143 | xir_op_t start =
|
nkeynes@1006 | 144 | xir_append_op2( xbb, OP_MOV, it->operand[0].type, it->operand[0].value.i, TARGET_REGISTER_OPERAND, REG_ARG1 );
|
nkeynes@1006 | 145 | xir_append_op2( xbb, OP_MOV, argtype, argval+1, TARGET_REGISTER_OPERAND, REG_ARG2 );
|
nkeynes@1006 | 146 | xir_append_op2( xbb, OP_MOV, it->operand[0].type, it->operand[0].value.i, SOURCE_REGISTER_OPERAND, REG_TMP3 );
|
nkeynes@1006 | 147 | xir_append_op2( xbb, OP_SLR, INT_IMM_OPERAND, 12, SOURCE_REGISTER_OPERAND, REG_TMP3 );
|
nkeynes@1006 | 148 | xir_append_xlat( xbb, addr_space, SOURCE_REGISTER_OPERAND, REG_TMP3 );
|
nkeynes@1006 | 149 | xir_insert_block(start,xbb->ir_ptr-1, it);
|
nkeynes@1006 | 150 | /* Replace original op with CALLLUT */
|
nkeynes@1006 | 151 | it->opcode = OP_CALLLUT;
|
nkeynes@1006 | 152 | it->operand[0].type = SOURCE_REGISTER_OPERAND;
|
nkeynes@1006 | 153 | it->operand[0].value.i = REG_TMP3;
|
nkeynes@1006 | 154 | it->operand[1].type = INT_IMM_OPERAND;
|
nkeynes@1006 | 155 | it->operand[1].value.i = MEM_FUNC_OFFSET(read_long);
|
nkeynes@1006 | 156 |
|
nkeynes@1006 | 157 | /* Second block */
|
nkeynes@1006 | 158 | xir_append_op2( xbb, OP_MOV, argtype, argval, TARGET_REGISTER_OPERAND, REG_ARG2 );
|
nkeynes@1006 | 159 | xir_append_op2( xbb, OP_ADD, INT_IMM_OPERAND, 4, SOURCE_REGISTER_OPERAND, REG_ARG1 );
|
nkeynes@1006 | 160 | xir_op_t fin = xir_append_op2( xbb, OP_CALLLUT, SOURCE_REGISTER_OPERAND, REG_TMP3, INT_IMM_OPERAND, MEM_FUNC_OFFSET(read_long) );
|
nkeynes@1006 | 161 | fin->exc = it->exc;
|
nkeynes@1006 | 162 | xir_insert_block(start, xbb->ir_ptr-1, it->next);
|
nkeynes@1006 | 163 | }
|
nkeynes@1006 | 164 |
|
nkeynes@1006 | 165 |
|
nkeynes@1006 | 166 | /**
|
nkeynes@1006 | 167 | * Runs a single pass over the block, performing the following transformations:
|
nkeynes@1006 | 168 | * Load/Store ops -> Mov/call sequences
|
nkeynes@1006 | 169 | * Flags -> explicit SETcc/loadcc ops where necessary (doesn't try to reorder
|
nkeynes@1006 | 170 | * at the moment)
|
nkeynes@1006 | 171 | * Mov operands into target specific registers where the ISA requires it. (eg SAR)
|
nkeynes@1006 | 172 | * Run in reverse order so we can track liveness of the flags as we go (for ALU
|
nkeynes@1006 | 173 | * lowering to flags-modifying instructions)
|
nkeynes@1006 | 174 | */
|
nkeynes@1006 | 175 | void x86_target_lower( xir_basic_block_t xbb, xir_op_t start, xir_op_t end )
|
nkeynes@1006 | 176 | {
|
nkeynes@1006 | 177 | gboolean flags_live = FALSE;
|
nkeynes@1006 | 178 | xir_op_t it;
|
nkeynes@1006 | 179 | for( it=end; it != NULL; it = it->prev ) {
|
nkeynes@1006 | 180 | switch( it->opcode ) {
|
nkeynes@1006 | 181 |
|
nkeynes@1006 | 182 | /* Promote non-flag versions to flag versions where there's no flag-free version
|
nkeynes@1006 | 183 | * (in other words, all ALU ops except ADD, since we can use LEA for a flag-free
|
nkeynes@1006 | 184 | * ADD
|
nkeynes@1006 | 185 | */
|
nkeynes@1006 | 186 | case OP_ADDC: case OP_AND: case OP_DIV: case OP_MUL: case OP_MULQ:
|
nkeynes@1006 | 187 | case OP_NEG: case OP_NOT: case OP_OR: case OP_XOR: case OP_SUB:
|
nkeynes@1006 | 188 | case OP_SUBB: case OP_SDIV:
|
nkeynes@1006 | 189 | it->opcode++;
|
nkeynes@1006 | 190 | if( flags_live ) {
|
nkeynes@1006 | 191 | xir_insert_op( XOP1( OP_SAVEFLAGS, REG_TMP5 ), it );
|
nkeynes@1006 | 192 | xir_insert_op( XOP1( OP_RESTFLAGS, REG_TMP5 ), it->next );
|
nkeynes@1006 | 193 | }
|
nkeynes@1006 | 194 | break;
|
nkeynes@1006 | 195 |
|
nkeynes@1006 | 196 | case OP_SAR: case OP_SLL: case OP_SLR: case OP_ROL: case OP_ROR:
|
nkeynes@1006 | 197 | /* Promote to *S form since we don't have a non-flag version */
|
nkeynes@1006 | 198 | it->opcode++;
|
nkeynes@1006 | 199 | if( flags_live ) {
|
nkeynes@1006 | 200 | xir_insert_op( XOP1( OP_SAVEFLAGS, REG_TMP5 ), it );
|
nkeynes@1006 | 201 | xir_insert_op( XOP1( OP_RESTFLAGS, REG_TMP5 ), it->next );
|
nkeynes@1006 | 202 | }
|
nkeynes@1006 | 203 |
|
nkeynes@1006 | 204 | case OP_SARS: case OP_SLLS: case OP_SLRS:
|
nkeynes@1006 | 205 | case OP_RCL: case OP_RCR: case OP_ROLS: case OP_RORS:
|
nkeynes@1006 | 206 | /* Insert mov %reg, %ecx */
|
nkeynes@1006 | 207 | if( it->operand[0].type == SOURCE_REGISTER_OPERAND ) {
|
nkeynes@1006 | 208 | xir_insert_op( xir_append_op2( xbb, OP_MOV, SOURCE_REGISTER_OPERAND, it->operand[0].value.i, TARGET_REGISTER_OPERAND, REG_ECX ), it );
|
nkeynes@1006 | 209 | it->operand[0].type = TARGET_REGISTER_OPERAND;
|
nkeynes@1006 | 210 | it->operand[0].value.i = REG_ECX;
|
nkeynes@1006 | 211 | }
|
nkeynes@1006 | 212 | break;
|
nkeynes@1006 | 213 | case OP_SHLD: case OP_SHAD:
|
nkeynes@1006 | 214 | /* Insert mov %reg, %ecx */
|
nkeynes@1006 | 215 | if( it->operand[0].type == SOURCE_REGISTER_OPERAND ) {
|
nkeynes@1006 | 216 | xir_insert_op( xir_append_op2( xbb, OP_MOV, SOURCE_REGISTER_OPERAND, it->operand[0].value.i, TARGET_REGISTER_OPERAND, REG_ECX ), it );
|
nkeynes@1006 | 217 | it->operand[0].type = TARGET_REGISTER_OPERAND;
|
nkeynes@1006 | 218 | it->operand[0].value.i = REG_ECX;
|
nkeynes@1006 | 219 | } else if( it->operand[0].type == INT_IMM_OPERAND ) {
|
nkeynes@1006 | 220 | /* Simplify down to SAR/SLL/SLR where we have a constant shift */
|
nkeynes@1006 | 221 | if( it->operand[0].value.i == 0 ) {
|
nkeynes@1006 | 222 | /* No-op */
|
nkeynes@1006 | 223 | it->opcode = OP_NOP;
|
nkeynes@1006 | 224 | it->operand[1].type = it->operand[0].type = NO_OPERAND;
|
nkeynes@1006 | 225 | } else if( it->operand[0].value.i > 0 ) {
|
nkeynes@1006 | 226 | it->opcode = OP_SLL;
|
nkeynes@1006 | 227 | } else if( (it->operand[0].value.i & 0x1F) == 0 ) {
|
nkeynes@1006 | 228 | if( it->opcode == OP_SHLD ) {
|
nkeynes@1006 | 229 | it->opcode = OP_MOV;
|
nkeynes@1006 | 230 | it->operand[0].value.i = 0;
|
nkeynes@1006 | 231 | } else {
|
nkeynes@1006 | 232 | it->opcode = OP_SAR;
|
nkeynes@1006 | 233 | it->operand[0].value.i = 31;
|
nkeynes@1006 | 234 | }
|
nkeynes@1006 | 235 | } else {
|
nkeynes@1006 | 236 | if( it->opcode == OP_SHLD ) {
|
nkeynes@1006 | 237 | it->opcode = OP_SLR;
|
nkeynes@1006 | 238 | } else {
|
nkeynes@1006 | 239 | it->opcode = OP_SAR;
|
nkeynes@1006 | 240 | }
|
nkeynes@1006 | 241 | }
|
nkeynes@1006 | 242 | }
|
nkeynes@1006 | 243 | break;
|
nkeynes@1006 | 244 |
|
nkeynes@1006 | 245 | case OP_CALL1: /* Reduce to mov reg, %eax; call0 ptr */
|
nkeynes@1006 | 246 | xir_insert_op( xir_append_op2( xbb, OP_MOV, it->operand[1].type, it->operand[1].value.i, TARGET_REGISTER_OPERAND, REG_ARG1 ), it );
|
nkeynes@1006 | 247 | it->opcode = OP_CALL0;
|
nkeynes@1006 | 248 | it->operand[1].type = NO_OPERAND;
|
nkeynes@1006 | 249 | break;
|
nkeynes@1006 | 250 | case OP_CALLR: /* reduce to call0 ptr, mov result, reg */
|
nkeynes@1006 | 251 | xir_insert_op( xir_append_op2( xbb, OP_MOV, TARGET_REGISTER_OPERAND, REG_RESULT1, it->operand[1].type, it->operand[1].value.i), it->next );
|
nkeynes@1006 | 252 | it->opcode = OP_CALL0;
|
nkeynes@1006 | 253 | it->operand[1].type = NO_OPERAND;
|
nkeynes@1006 | 254 | break;
|
nkeynes@1006 | 255 | case OP_LOADB:
|
nkeynes@1006 | 256 | lower_mem_load( xbb, it, xbb->address_space, MEM_FUNC_OFFSET(read_byte) );
|
nkeynes@1006 | 257 | break;
|
nkeynes@1006 | 258 | case OP_LOADW:
|
nkeynes@1006 | 259 | lower_mem_load( xbb, it, xbb->address_space, MEM_FUNC_OFFSET(read_word) );
|
nkeynes@1006 | 260 | break;
|
nkeynes@1006 | 261 | case OP_LOADL:
|
nkeynes@1006 | 262 | lower_mem_load( xbb, it, xbb->address_space, MEM_FUNC_OFFSET(read_long) );
|
nkeynes@1006 | 263 | break;
|
nkeynes@1006 | 264 | case OP_LOADBFW:
|
nkeynes@1006 | 265 | lower_mem_load( xbb, it, xbb->address_space, MEM_FUNC_OFFSET(read_byte_for_write) );
|
nkeynes@1006 | 266 | break;
|
nkeynes@1006 | 267 | case OP_LOADQ:
|
nkeynes@1006 | 268 | lower_mem_loadq( xbb, it, xbb->address_space );
|
nkeynes@1006 | 269 | break;
|
nkeynes@1006 | 270 | case OP_PREF:
|
nkeynes@1006 | 271 | lower_mem_load( xbb, it, xbb->address_space, MEM_FUNC_OFFSET(prefetch) );
|
nkeynes@1006 | 272 | break;
|
nkeynes@1006 | 273 | case OP_OCBI:
|
nkeynes@1006 | 274 | case OP_OCBP:
|
nkeynes@1006 | 275 | case OP_OCBWB:
|
nkeynes@1006 | 276 | break;
|
nkeynes@1006 | 277 | case OP_STOREB:
|
nkeynes@1006 | 278 | lower_mem_store( xbb, it, xbb->address_space, MEM_FUNC_OFFSET(write_byte) );
|
nkeynes@1006 | 279 | break;
|
nkeynes@1006 | 280 | case OP_STOREW:
|
nkeynes@1006 | 281 | lower_mem_store( xbb, it, xbb->address_space, MEM_FUNC_OFFSET(write_word) );
|
nkeynes@1006 | 282 | break;
|
nkeynes@1006 | 283 | case OP_STOREL:
|
nkeynes@1006 | 284 | lower_mem_store( xbb, it, xbb->address_space, MEM_FUNC_OFFSET(write_long) );
|
nkeynes@1006 | 285 | break;
|
nkeynes@1006 | 286 | case OP_STORELCA:
|
nkeynes@1006 | 287 | lower_mem_store( xbb, it, xbb->address_space, MEM_FUNC_OFFSET(write_long) );
|
nkeynes@1006 | 288 | break;
|
nkeynes@1006 | 289 | case OP_STOREQ:
|
nkeynes@1006 | 290 | lower_mem_storeq( xbb, it, xbb->address_space );
|
nkeynes@1006 | 291 | break;
|
nkeynes@1006 | 292 |
|
nkeynes@1006 | 293 | case OP_SHUFFLE:
|
nkeynes@1006 | 294 | assert( it->operand[0].type == INT_IMM_OPERAND );
|
nkeynes@1006 | 295 | if( it->operand[0].value.i = 0x2134 ) { /* Swap low bytes */
|
nkeynes@1006 | 296 | /* This is an xchg al,ah, but we need to force the operand into one of the bottom 4 registers */
|
nkeynes@1006 | 297 | xir_insert_op( xir_append_op2( xbb, OP_MOV, it->operand[1].type, it->operand[1].value.i, TARGET_REGISTER_OPERAND, REG_EAX ), it);
|
nkeynes@1006 | 298 | it->operand[1].type = TARGET_REGISTER_OPERAND;
|
nkeynes@1006 | 299 | it->operand[1].value.i = REG_EAX;
|
nkeynes@1006 | 300 | } else if( it->operand[0].value.i != 0x4321 ) {
|
nkeynes@1006 | 301 | /* 4321 is a full byteswap (directly supported) - use shift/mask/or
|
nkeynes@1006 | 302 | * sequence for anything else. Although we could use PSHUF...
|
nkeynes@1006 | 303 | */
|
nkeynes@1006 | 304 | it = xir_shuffle_lower( xbb, it, REG_TMP3, REG_TMP4 );
|
nkeynes@1006 | 305 | }
|
nkeynes@1006 | 306 | break;
|
nkeynes@1006 | 307 | case OP_NEGF:
|
nkeynes@1006 | 308 | xir_insert_op( xir_append_op2( xbb, OP_MOV, INT_IMM_OPERAND, 0, SOURCE_REGISTER_OPERAND, REG_TMP4 ), it);
|
nkeynes@1006 | 309 | xir_insert_op( xir_append_op2( xbb, OP_MOV, SOURCE_REGISTER_OPERAND, REG_TMP4,it->operand[0].type, it->operand[0].value.i), it->next );
|
nkeynes@1006 | 310 | it->opcode = OP_SUBF;
|
nkeynes@1006 | 311 | it->operand[1].type = SOURCE_REGISTER_OPERAND;
|
nkeynes@1006 | 312 | it->operand[1].value.i = REG_TMP4;
|
nkeynes@1006 | 313 | break;
|
nkeynes@1006 | 314 | case OP_NEGD:
|
nkeynes@1006 | 315 | xir_insert_op( xir_append_op2( xbb, OP_MOVQ, INT_IMM_OPERAND, 0, SOURCE_REGISTER_OPERAND, REG_TMPQ0 ), it);
|
nkeynes@1006 | 316 | xir_insert_op( xir_append_op2( xbb, OP_MOVQ, SOURCE_REGISTER_OPERAND, REG_TMPQ0,it->operand[0].type, it->operand[0].value.i), it->next );
|
nkeynes@1006 | 317 | it->opcode = OP_SUBD;
|
nkeynes@1006 | 318 | it->operand[1].type = SOURCE_REGISTER_OPERAND;
|
nkeynes@1006 | 319 | it->operand[1].value.i = REG_TMPQ0;
|
nkeynes@1006 | 320 | break;
|
nkeynes@1006 | 321 | case OP_XLAT:
|
nkeynes@1006 | 322 | /* Insert temp register if translating through a 64-bit pointer */
|
nkeynes@1006 | 323 | if( XOP_IS_PTRIMM(it, 0) && sizeof(void *) == 8 && it->operand[0].value.q >= 0x100000000LL ) {
|
nkeynes@1006 | 324 | xir_insert_op( XOP2P( OP_MOVQ, it->operand[0].value.p, REG_TMP4 ), it );
|
nkeynes@1006 | 325 | it->operand[0].type = SOURCE_REGISTER_OPERAND;
|
nkeynes@1006 | 326 | it->operand[0].value.i = REG_TMP4;
|
nkeynes@1006 | 327 | }
|
nkeynes@1006 | 328 | break;
|
nkeynes@1006 | 329 | }
|
nkeynes@1006 | 330 |
|
nkeynes@1006 | 331 | if( XOP_READS_FLAGS(it) ) {
|
nkeynes@1006 | 332 | flags_live = TRUE;
|
nkeynes@1006 | 333 | } else if( XOP_WRITES_FLAGS(it) ) {
|
nkeynes@1006 | 334 | flags_live = FALSE;
|
nkeynes@1006 | 335 | }
|
nkeynes@1006 | 336 |
|
nkeynes@1006 | 337 | /* Lower pointer operands to INT or QUAD according to address and value size. */
|
nkeynes@1006 | 338 | if( it->operand[0].type == POINTER_OPERAND ) {
|
nkeynes@1006 | 339 | if( sizeof(void *) == 8 && it->operand[0].value.q >= 0x100000000LL ) {
|
nkeynes@1006 | 340 | if( it->opcode == OP_MOV ) {
|
nkeynes@1006 | 341 | // Promote MOV ptr, reg to MOVQ ptr, reg
|
nkeynes@1006 | 342 | it->opcode = OP_MOVQ;
|
nkeynes@1006 | 343 | } else if( it->opcode != OP_MOVQ ) {
|
nkeynes@1006 | 344 | /* 64-bit pointers can't be used as immediate values - break up into
|
nkeynes@1006 | 345 | * an immediate load to temporary, followed by the original instruction.
|
nkeynes@1006 | 346 | * (We only check the first operand as there are no instructions that
|
nkeynes@1006 | 347 | * permit the second operand to be an immediate pointer.
|
nkeynes@1006 | 348 | */
|
nkeynes@1006 | 349 | xir_insert_op( xir_append_op2( xbb, OP_MOVQ, POINTER_OPERAND, it->operand[0].value.q, SOURCE_REGISTER_OPERAND, REG_TMP4 ), it );
|
nkeynes@1006 | 350 | it->operand[0].type = SOURCE_REGISTER_OPERAND;
|
nkeynes@1006 | 351 | it->operand[1].value.i = REG_TMP4;
|
nkeynes@1006 | 352 | }
|
nkeynes@1006 | 353 | it->operand[0].type = QUAD_IMM_OPERAND;
|
nkeynes@1006 | 354 | } else {
|
nkeynes@1006 | 355 | if( it->opcode == OP_MOVQ ) {
|
nkeynes@1006 | 356 | /* Lower a MOVQ of a 32-bit quantity to a MOV, and save the 5 bytes */
|
nkeynes@1006 | 357 | it->opcode = OP_MOV;
|
nkeynes@1006 | 358 | }
|
nkeynes@1006 | 359 | it->operand[0].type = INT_IMM_OPERAND;
|
nkeynes@1006 | 360 | }
|
nkeynes@1006 | 361 | }
|
nkeynes@1006 | 362 |
|
nkeynes@1006 | 363 | if( it == start )
|
nkeynes@1006 | 364 | break;
|
nkeynes@1006 | 365 | }
|
nkeynes@1006 | 366 |
|
nkeynes@1006 | 367 | }
|