Search
lxdream.org :: lxdream/src/xlat/x86/x86target.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/xlat/x86/x86target.c
changeset 1006:3a169c224c12
next1011:fdd58619b760
author nkeynes
date Tue Apr 07 10:55:03 2009 +0000 (15 years ago)
branchxlat-refactor
permissions -rw-r--r--
last change Commit current work-in-progress to xlat-refactor branch
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@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
}
.