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