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 1011:fdd58619b760
prev1006:3a169c224c12
next1012:0b8cc74ac83a
author nkeynes
date Sun Apr 12 07:24:45 2009 +0000 (15 years ago)
branchxlat-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
}
.