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 final code generation
|
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 | typedef enum {
|
nkeynes@1006 | 25 | SSE_NONE = 0,
|
nkeynes@1006 | 26 | SSE_1,
|
nkeynes@1006 | 27 | SSE_2,
|
nkeynes@1006 | 28 | SSE_3,
|
nkeynes@1006 | 29 | SSE_3_1, /* AKA SSSE3 */
|
nkeynes@1006 | 30 | SSE_4_1,
|
nkeynes@1006 | 31 | SSE_4_2
|
nkeynes@1006 | 32 | } sse_version_t;
|
nkeynes@1006 | 33 |
|
nkeynes@1006 | 34 | /* 32-bit register groups:
|
nkeynes@1006 | 35 | * General regs 0..7
|
nkeynes@1006 | 36 | * - EAX, EDX - arguments, volatile
|
nkeynes@1006 | 37 | * - ECX - volatile
|
nkeynes@1006 | 38 | * - EBX, ESI, EDI - non-volatile
|
nkeynes@1006 | 39 | * - ESP, EBP - blocked out for system use.
|
nkeynes@1006 | 40 | * XMM regs 16..23
|
nkeynes@1006 | 41 | * - Floating or integer, all volatile
|
nkeynes@1006 | 42 | * MMX regs 32..39
|
nkeynes@1006 | 43 | * - integer, all volatile
|
nkeynes@1006 | 44 | * OR (if SSE is unsupported)
|
nkeynes@1006 | 45 | * x87 regs 32..39
|
nkeynes@1006 | 46 | * - floating point, all volatile, stack allocator
|
nkeynes@1006 | 47 | */
|
nkeynes@1006 | 48 |
|
nkeynes@1006 | 49 | /*
|
nkeynes@1006 | 50 | * 64-bit register groups:
|
nkeynes@1006 | 51 | * General regs 0..15
|
nkeynes@1006 | 52 | * - EDI, ESI - arguments, volatile
|
nkeynes@1006 | 53 | * - EAX, ECX, EDX, ... - volatile
|
nkeynes@1006 | 54 | * - EBX, ... non-volatile
|
nkeynes@1006 | 55 | * - ESP, EBP - blocked for system use (r13?)
|
nkeynes@1006 | 56 | * XMM regs 16..31
|
nkeynes@1006 | 57 | * - Floating or integer, all volatile
|
nkeynes@1006 | 58 | * MMX regs 32..39
|
nkeynes@1006 | 59 | * - integer, all volatile
|
nkeynes@1006 | 60 | * OR
|
nkeynes@1006 | 61 | * x87 regs 32..39
|
nkeynes@1006 | 62 | * - floating point, all volatile, stack allocator
|
nkeynes@1006 | 63 | */
|
nkeynes@1006 | 64 |
|
nkeynes@1006 | 65 |
|
nkeynes@1006 | 66 |
|
nkeynes@1006 | 67 |
|
nkeynes@1006 | 68 | struct x86_target_info_struct {
|
nkeynes@1006 | 69 | sse_version_t sse_version;
|
nkeynes@1006 | 70 | } x86_target_info;
|
nkeynes@1006 | 71 |
|
nkeynes@1006 | 72 |
|
nkeynes@1006 | 73 | /**
|
nkeynes@1006 | 74 | * Initialize x86_target_info - detect supported features from cpuid
|
nkeynes@1006 | 75 | */
|
nkeynes@1006 | 76 | void x86_target_init()
|
nkeynes@1006 | 77 | {
|
nkeynes@1006 | 78 | uint32_t feature1, feature2;
|
nkeynes@1006 | 79 |
|
nkeynes@1006 | 80 | __asm__ __volatile__(
|
nkeynes@1006 | 81 | "mov $0x01, %%eax\n\t"
|
nkeynes@1006 | 82 | "cpuid\n\t" : "=c" (feature1), "=d" (feature2) : : "eax", "ebx");
|
nkeynes@1006 | 83 |
|
nkeynes@1006 | 84 | /* Walk through from oldest to newest - while it's normally the case
|
nkeynes@1006 | 85 | * that all older extensions are supported, you're not supposed to
|
nkeynes@1006 | 86 | * depend on that assumption. So instead we stop as soon as we find
|
nkeynes@1006 | 87 | * a missing feature bit. */
|
nkeynes@1006 | 88 | if( (feature2 & 0x02000000) == 0 ) {
|
nkeynes@1006 | 89 | x86_target_info.sse_version = SSE_NONE;
|
nkeynes@1006 | 90 | } else if( (feature2 & 0x04000000) == 0 ) {
|
nkeynes@1006 | 91 | x86_target_info.sse_version = SSE_1;
|
nkeynes@1006 | 92 | } else if( (feature1 & 0x00000001) == 0 ) { /* SSE3 bit */
|
nkeynes@1006 | 93 | x86_target_info.sse_version = SSE_2;
|
nkeynes@1006 | 94 | } else if( (feature1 & 0x00000100) == 0 ) { /* SSSE3 bit */
|
nkeynes@1006 | 95 | x86_target_info.sse_version = SSE_3;
|
nkeynes@1006 | 96 | } else if( (feature1 & 0x00080000) == 0 ) { /* SSE4.1 bit */
|
nkeynes@1006 | 97 | x86_target_info.sse_version = SSE_3_1;
|
nkeynes@1006 | 98 | } else if( (feature1 & 0x00100000) == 0 ) { /* SSE4.2 bit */
|
nkeynes@1006 | 99 | x86_target_info.sse_version = SSE_4_1;
|
nkeynes@1006 | 100 | } else {
|
nkeynes@1006 | 101 | x86_target_info.sse_version = SSE_4_2;
|
nkeynes@1006 | 102 | }
|
nkeynes@1006 | 103 | }
|
nkeynes@1006 | 104 |
|
nkeynes@1006 | 105 | #define IS_X86_64() (sizeof(void *)==8)
|
nkeynes@1006 | 106 | #define IS_XMM_REG(op,n) (XOP_REG(op,n) >= MIN_XMM_REGISTER && XOP_REG(op,n) <= MAX_AMD64_XMM_REGISTER)
|
nkeynes@1006 | 107 |
|
nkeynes@1006 | 108 | #define RBP_OFFSET (-128)
|
nkeynes@1006 | 109 |
|
nkeynes@1006 | 110 | #define NONE NO_OPERAND
|
nkeynes@1006 | 111 | #define SRC SOURCE_REGISTER_OPERAND
|
nkeynes@1006 | 112 | #define TGT TARGET_REGISTER_OPERAND
|
nkeynes@1006 | 113 | #define IMM INT_IMM_OPERAND
|
nkeynes@1006 | 114 | #define FLT FLOAT_IMM_OPERAND
|
nkeynes@1006 | 115 | #define DBL DOUBLE_IMM_OPERAND
|
nkeynes@1006 | 116 |
|
nkeynes@1006 | 117 | #define MAX_X86_GENERAL_REGISTER (MIN_TARGET_REGISTER+7)
|
nkeynes@1006 | 118 | #define MAX_AMD64_GENERAL_REGISTER (MIN_TARGET_REGISTER+15)
|
nkeynes@1006 | 119 | #define MIN_XMM_REGISTER (MIN_TARGET_REGISTER+16)
|
nkeynes@1006 | 120 | #define MAX_X86_XMM_REGISTER (MIN_TARGET_REGISTER+23)
|
nkeynes@1006 | 121 | #define MAX_AMD64_XMM_REGISTER (MIN_TARGET_REGISTER+31)
|
nkeynes@1006 | 122 |
|
nkeynes@1006 | 123 | #define ILLOP(op) FATAL("Illegal x86 opcode %s %d %d\n", XIR_OPCODE_TABLE[op->opcode], op->operand[0].type, op->operand[1].type)
|
nkeynes@1006 | 124 |
|
nkeynes@1006 | 125 | // Convenience macros
|
nkeynes@1006 | 126 | #define X86L_IMMS_REG(opname, op) \
|
nkeynes@1006 | 127 | if( XOP_IS_FORM(op,IMM,TGT) ) { opname##_imms_r32(XOP_INT(op,0),XOP_REG(op,1)); } \
|
nkeynes@1006 | 128 | else if( XOP_IS_FORM(op,IMM,SRC) ) { opname##_imms_rbpdisp(XOP_INT(op,0),XOP_REG(op,1)+RBP_OFFSET); } \
|
nkeynes@1006 | 129 | else { ILLOP(op); }
|
nkeynes@1006 | 130 |
|
nkeynes@1006 | 131 | #define X86L_REG_TGT(opname,op) \
|
nkeynes@1006 | 132 | if( XOP_IS_FORM(op,TGT,TGT) ) { opname##_r32_r32(XOP_REG(op,0),XOP_REG(op,1)); } \
|
nkeynes@1006 | 133 | else if( XOP_IS_FORM(op,SRC,TGT) ) { opname##_rbpdisp_r32(XOP_REG(op,0)+RBP_OFFSET,XOP_REG(op,1)); } \
|
nkeynes@1006 | 134 | else { ILLOP(op); }
|
nkeynes@1006 | 135 |
|
nkeynes@1006 | 136 | #define X86F_REG_TGT(opname,op ) \
|
nkeynes@1006 | 137 | if( XOP_IS_FORM(op,TGT,TGT) ) { opname##_xmm_xmm(XOP_REG(op,0),XOP_REG(op,1)); } \
|
nkeynes@1006 | 138 | else if( XOP_IS_FORM(op,SRC,TGT) ) { opname##_rbpdisp_xmm(XOP_REG(op,0)+RBP_OFFSET,XOP_REG(op,1)); } \
|
nkeynes@1006 | 139 | else { ILLOP(op); }
|
nkeynes@1006 | 140 |
|
nkeynes@1006 | 141 | #define X86L_REG_REG(opname,op) \
|
nkeynes@1006 | 142 | if( XOP_IS_FORM(op,TGT,TGT) ) { opname##_r32_r32(XOP_REG(op,0),XOP_REG(op,1)); } \
|
nkeynes@1006 | 143 | else if( XOP_IS_FORM(op,SRC,TGT) ) { opname##_rbpdisp_r32(XOP_REG(op,0)+RBP_OFFSET,XOP_REG(op,1)); } \
|
nkeynes@1006 | 144 | else if( XOP_IS_FORM(op,TGT,SRC) ) { opname##_r32_rbpdisp(XOP_REG(op,0),XOP_REG(op,1)+RBP_OFFSET); } \
|
nkeynes@1006 | 145 | else { ILLOP(op); }
|
nkeynes@1006 | 146 |
|
nkeynes@1006 | 147 | #define X86L_REG(opname,op) \
|
nkeynes@1006 | 148 | if( XOP_IS_TGTREG(op,0) ) { opname##_r32(XOP_REG(op,0)); } \
|
nkeynes@1006 | 149 | else if( XOP_IS_SRCREG(op,0) ) { opname##_rbpdisp(XOP_REG(op,0)+RBP_OFFSET); } \
|
nkeynes@1006 | 150 | else { ILLOP(op); }
|
nkeynes@1006 | 151 |
|
nkeynes@1006 | 152 | #define X86L_CL_REG(opname,op) \
|
nkeynes@1006 | 153 | if( XOP_IS_FORM(op,TGT,TGT) && XOP_REG(op,0) == REG_CL ) { opname##_cl_r32(XOP_REG(op,1)); } \
|
nkeynes@1006 | 154 | else if( XOP_IS_FORM(op,TGT,SRC) && XOP_REG(op,0) == REG_CL ) { opname##_cl_rbpdisp(XOP_REG(op,1)+RBP_OFFSET); } \
|
nkeynes@1006 | 155 | else { ILLOP(op); }
|
nkeynes@1006 | 156 |
|
nkeynes@1006 | 157 | #define X86L_IMMCL_REG(opname,op) \
|
nkeynes@1006 | 158 | if( XOP_IS_FORM(op,IMM,TGT) ) { opname##_imm_r32(XOP_INT(op,0),XOP_REG(op,1)); } \
|
nkeynes@1006 | 159 | else if( XOP_IS_FORM(op,IMM,SRC) ) { opname##_imm_rbpdisp(XOP_INT(op,0),XOP_REG(op,1)+RBP_OFFSET); } \
|
nkeynes@1006 | 160 | else if( XOP_IS_FORM(op,TGT,TGT) && XOP_REG(op,0) == REG_CL ) { opname##_cl_r32(XOP_REG(op,1)); } \
|
nkeynes@1006 | 161 | else if( XOP_IS_FORM(op,TGT,SRC) && XOP_REG(op,0) == REG_CL ) { opname##_cl_rbpdisp(XOP_REG(op,1)+RBP_OFFSET); } \
|
nkeynes@1006 | 162 | else { ILLOP(op); }
|
nkeynes@1006 | 163 |
|
nkeynes@1006 | 164 | // Standard ALU forms - imms,reg or reg,reg
|
nkeynes@1006 | 165 | #define X86L_ALU_REG(opname,op) \
|
nkeynes@1006 | 166 | if( XOP_IS_FORM(op,IMM,TGT) ) { opname##_imms_r32(XOP_INT(op,0),XOP_REG(op,1)); } \
|
nkeynes@1006 | 167 | else if( XOP_IS_FORM(op,IMM,SRC) ) { opname##_imms_rbpdisp(XOP_INT(op,0),XOP_REG(op,1)+RBP_OFFSET); } \
|
nkeynes@1006 | 168 | else if( XOP_IS_FORM(op,TGT,TGT) ) { opname##_r32_r32(XOP_REG(op,0),XOP_REG(op,1)); } \
|
nkeynes@1006 | 169 | else if( XOP_IS_FORM(op,SRC,TGT) ) { opname##_rbpdisp_r32(XOP_REG(op,0)+RBP_OFFSET,XOP_REG(op,1)); } \
|
nkeynes@1006 | 170 | else if( XOP_IS_FORM(op,TGT,SRC) ) { opname##_r32_rbpdisp(XOP_REG(op,0),XOP_REG(op,1)+RBP_OFFSET); } \
|
nkeynes@1006 | 171 | else { ILLOP(op); }
|
nkeynes@1006 | 172 |
|
nkeynes@1006 | 173 | uint32_t x86_target_get_code_size( xir_op_t begin, xir_op_t end )
|
nkeynes@1006 | 174 | {
|
nkeynes@1006 | 175 | return -1;
|
nkeynes@1006 | 176 | }
|
nkeynes@1006 | 177 |
|
nkeynes@1006 | 178 |
|
nkeynes@1006 | 179 | /**
|
nkeynes@1006 | 180 | * Note: Assumes that the IR is x86-legal (ie doesn't contain any unencodeable instructions).
|
nkeynes@1006 | 181 | */
|
nkeynes@1006 | 182 | uint32_t x86_target_codegen( target_data_t td, xir_op_t begin, xir_op_t end )
|
nkeynes@1006 | 183 | {
|
nkeynes@1006 | 184 | int ss;
|
nkeynes@1006 | 185 | xir_op_t it;
|
nkeynes@1006 | 186 |
|
nkeynes@1006 | 187 | /* Prologue */
|
nkeynes@1006 | 188 |
|
nkeynes@1006 | 189 | for( it=begin; it != NULL; it = it->next ) {
|
nkeynes@1006 | 190 | switch( it->opcode ) {
|
nkeynes@1006 | 191 | case OP_ENTER:
|
nkeynes@1006 | 192 | case OP_BARRIER:
|
nkeynes@1006 | 193 | case OP_NOP:
|
nkeynes@1006 | 194 | /* No code to generate */
|
nkeynes@1006 | 195 | break;
|
nkeynes@1006 | 196 | case OP_MOV:
|
nkeynes@1006 | 197 | if( XOP_IS_FORM(it, IMM, SRC) ) {
|
nkeynes@1006 | 198 | MOVL_imm32_rbpdisp( XOP_INT(it,0), XOP_REG2(it)+RBP_OFFSET );
|
nkeynes@1006 | 199 | } else if( XOP_IS_FORM(it, IMM, TGT) ) {
|
nkeynes@1006 | 200 | MOVL_imm32_r32( XOP_INT(it,0), XOP_REG2(it) );
|
nkeynes@1006 | 201 | } else if( XOP_IS_FORM(it, TGT, SRC) ) {
|
nkeynes@1006 | 202 | if( IS_XMM_REG(it,0) ) {
|
nkeynes@1006 | 203 | MOVSS_xmm_rbpdisp( XOP_REG1(it), XOP_REG2(it)+RBP_OFFSET );
|
nkeynes@1006 | 204 | } else {
|
nkeynes@1006 | 205 | MOVL_r32_rbpdisp( XOP_REG1(it), XOP_REG2(it)+RBP_OFFSET );
|
nkeynes@1006 | 206 | }
|
nkeynes@1006 | 207 | } else if( XOP_IS_FORM(it, TGT, TGT) ) {
|
nkeynes@1006 | 208 | if( IS_XMM_REG(it,0) ) {
|
nkeynes@1006 | 209 | if( IS_XMM_REG(it,1) ) {
|
nkeynes@1006 | 210 | MOVSS_xmm_xmm( XOP_REG1(it), XOP_REG2(it) );
|
nkeynes@1006 | 211 | } else {
|
nkeynes@1006 | 212 | MOVL_xmm_r32( XOP_REG1(it), XOP_REG2(it) );
|
nkeynes@1006 | 213 | }
|
nkeynes@1006 | 214 | } else if( IS_XMM_REG(it,1) ) {
|
nkeynes@1006 | 215 | MOVL_r32_xmm( XOP_REG1(it), XOP_REG2(it) );
|
nkeynes@1006 | 216 | } else {
|
nkeynes@1006 | 217 | MOVL_r32_r32( XOP_REG1(it), XOP_REG2(it) );
|
nkeynes@1006 | 218 | }
|
nkeynes@1006 | 219 | } else if( XOP_IS_FORM(it, SRC, TGT) ) {
|
nkeynes@1006 | 220 | if( IS_XMM_REG(it,1) ) {
|
nkeynes@1006 | 221 | MOVSS_rbpdisp_xmm( XOP_REG1(it)+RBP_OFFSET, XOP_REG2(it) );
|
nkeynes@1006 | 222 | } else {
|
nkeynes@1006 | 223 | MOVL_rbpdisp_r32( XOP_REG1(it)+RBP_OFFSET, XOP_REG2(it) );
|
nkeynes@1006 | 224 | }
|
nkeynes@1006 | 225 | } else {
|
nkeynes@1006 | 226 | ILLOP(it);
|
nkeynes@1006 | 227 | }
|
nkeynes@1006 | 228 | break;
|
nkeynes@1006 | 229 | case OP_MOVQ:
|
nkeynes@1006 | 230 | if( XOP_IS_FORM(it, IMM, SRC) ) {
|
nkeynes@1006 | 231 | ILLOP(it);
|
nkeynes@1006 | 232 | } else if( XOP_IS_FORM(it, IMM, TGT) ) {
|
nkeynes@1006 | 233 | if( IS_XMM_REG(it,0) ) {
|
nkeynes@1006 | 234 | if( XOP_INT(it,0) == 0 ) {
|
nkeynes@1006 | 235 | XORPD_xmm_xmm( XOP_REG2(it), XOP_REG2(it) );
|
nkeynes@1006 | 236 | }
|
nkeynes@1006 | 237 | } else {
|
nkeynes@1006 | 238 | MOVQ_imm64_r64( XOP_INT(it,0), XOP_REG2(it) );
|
nkeynes@1006 | 239 | }
|
nkeynes@1006 | 240 | } else if( XOP_IS_FORM(it, TGT, SRC) ) {
|
nkeynes@1006 | 241 | if( IS_XMM_REG(it,0) ) {
|
nkeynes@1006 | 242 | MOVSD_xmm_rbpdisp( XOP_REG1(it), XOP_REG2(it)+RBP_OFFSET );
|
nkeynes@1006 | 243 | } else {
|
nkeynes@1006 | 244 | MOVQ_r64_rbpdisp( XOP_REG1(it), XOP_REG2(it)+RBP_OFFSET );
|
nkeynes@1006 | 245 | }
|
nkeynes@1006 | 246 | } else if( XOP_IS_FORM(it, TGT, TGT) ) {
|
nkeynes@1006 | 247 | if( IS_XMM_REG(it,0) ) {
|
nkeynes@1006 | 248 | if( IS_XMM_REG(it,1) ) {
|
nkeynes@1006 | 249 | MOVSD_xmm_xmm( XOP_REG1(it), XOP_REG2(it) );
|
nkeynes@1006 | 250 | } else {
|
nkeynes@1006 | 251 | MOVQ_xmm_r64( XOP_REG1(it), XOP_REG2(it) );
|
nkeynes@1006 | 252 | }
|
nkeynes@1006 | 253 | } else if( IS_XMM_REG(it,1) ) {
|
nkeynes@1006 | 254 | MOVQ_r64_xmm( XOP_REG1(it), XOP_REG2(it) );
|
nkeynes@1006 | 255 | } else {
|
nkeynes@1006 | 256 | MOVQ_r64_r64( XOP_REG1(it), XOP_REG2(it) );
|
nkeynes@1006 | 257 | }
|
nkeynes@1006 | 258 | } else if( XOP_IS_FORM(it, SRC, TGT) ) {
|
nkeynes@1006 | 259 | if( IS_XMM_REG(it,1) ) {
|
nkeynes@1006 | 260 | MOVSD_rbpdisp_xmm( XOP_REG1(it)+RBP_OFFSET, XOP_REG2(it) );
|
nkeynes@1006 | 261 | } else {
|
nkeynes@1006 | 262 | MOVQ_rbpdisp_r64( XOP_REG1(it)+RBP_OFFSET, XOP_REG2(it) );
|
nkeynes@1006 | 263 | }
|
nkeynes@1006 | 264 | } else {
|
nkeynes@1006 | 265 | ILLOP(it);
|
nkeynes@1006 | 266 | }
|
nkeynes@1006 | 267 | break;
|
nkeynes@1006 | 268 | case OP_MOVSX8:
|
nkeynes@1006 | 269 | if( XOP_IS_FORM(it, TGT, TGT) ) {
|
nkeynes@1006 | 270 | MOVSXL_r8_r32( XOP_REG1(it), XOP_REG2(it) );
|
nkeynes@1006 | 271 | } else if( XOP_IS_FORM(it, SRC, TGT) ) {
|
nkeynes@1006 | 272 | MOVSXL_rbpdisp8_r32( XOP_REG1(it)+RBP_OFFSET, XOP_REG2(it) );
|
nkeynes@1006 | 273 | } else {
|
nkeynes@1006 | 274 | ILLOP(it);
|
nkeynes@1006 | 275 | }
|
nkeynes@1006 | 276 | break;
|
nkeynes@1006 | 277 | case OP_MOVSX16:
|
nkeynes@1006 | 278 | if( XOP_IS_FORM(it, TGT, TGT) ) {
|
nkeynes@1006 | 279 | MOVSXL_r16_r32( XOP_REG1(it), XOP_REG2(it) );
|
nkeynes@1006 | 280 | } else if( XOP_IS_FORM(it, SRC, TGT) ) {
|
nkeynes@1006 | 281 | MOVSXL_rbpdisp16_r32( XOP_REG1(it)+RBP_OFFSET, XOP_REG2(it) );
|
nkeynes@1006 | 282 | } else {
|
nkeynes@1006 | 283 | ILLOP(it);
|
nkeynes@1006 | 284 | }
|
nkeynes@1006 | 285 | break;
|
nkeynes@1006 | 286 | case OP_MOVZX8:
|
nkeynes@1006 | 287 | if( XOP_IS_FORM(it, TGT, TGT) ) {
|
nkeynes@1006 | 288 | MOVZXL_r8_r32( XOP_REG1(it), XOP_REG2(it) );
|
nkeynes@1006 | 289 | } else if( XOP_IS_FORM(it, SRC, TGT) ) {
|
nkeynes@1006 | 290 | MOVZXL_rbpdisp8_r32( XOP_REG1(it)+RBP_OFFSET, XOP_REG2(it) );
|
nkeynes@1006 | 291 | } else {
|
nkeynes@1006 | 292 | ILLOP(it);
|
nkeynes@1006 | 293 | }
|
nkeynes@1006 | 294 | break;
|
nkeynes@1006 | 295 | case OP_MOVZX16:
|
nkeynes@1006 | 296 | if( XOP_IS_FORM(it, TGT, TGT) ) {
|
nkeynes@1006 | 297 | MOVZXL_r16_r32( XOP_REG1(it), XOP_REG2(it) );
|
nkeynes@1006 | 298 | } else if( XOP_IS_FORM(it, SRC, TGT) ) {
|
nkeynes@1006 | 299 | MOVZXL_rbpdisp16_r32( XOP_REG1(it)+RBP_OFFSET, XOP_REG2(it) );
|
nkeynes@1006 | 300 | } else {
|
nkeynes@1006 | 301 | ILLOP(it);
|
nkeynes@1006 | 302 | }
|
nkeynes@1006 | 303 | break;
|
nkeynes@1006 | 304 | case OP_ADD:
|
nkeynes@1006 | 305 | case OP_ADDS: X86L_ALU_REG(ADDL,it); break;
|
nkeynes@1006 | 306 | case OP_ADDCS: X86L_ALU_REG(ADCL,it); break;
|
nkeynes@1006 | 307 | case OP_AND: X86L_ALU_REG(ANDL,it); break;
|
nkeynes@1006 | 308 | case OP_CMP:
|
nkeynes@1006 | 309 | X86L_ALU_REG(CMPL,it); break;
|
nkeynes@1006 | 310 | case OP_DEC:
|
nkeynes@1006 | 311 | if( XOP_IS_FORM(it,TGT,NONE) ) {
|
nkeynes@1006 | 312 | DECL_r32(XOP_REG(it,0));
|
nkeynes@1006 | 313 | } else if( XOP_IS_FORM(it,SRC,NONE) ) {
|
nkeynes@1006 | 314 | DECL_rbpdisp(XOP_REG(it,0)+RBP_OFFSET);
|
nkeynes@1006 | 315 | } else {
|
nkeynes@1006 | 316 | ILLOP(it);
|
nkeynes@1006 | 317 | }
|
nkeynes@1006 | 318 | break;
|
nkeynes@1006 | 319 | case OP_MUL:
|
nkeynes@1006 | 320 | X86L_REG_TGT(IMULL,it);
|
nkeynes@1006 | 321 | break;
|
nkeynes@1006 | 322 | case OP_NEG: X86L_REG(NEGL,it); break;
|
nkeynes@1006 | 323 | case OP_NOT: X86L_REG(NOTL,it); break;
|
nkeynes@1006 | 324 | case OP_OR: X86L_ALU_REG(ORL,it); break;
|
nkeynes@1006 | 325 | case OP_RCL: X86L_IMMCL_REG(RCLL,it); break;
|
nkeynes@1006 | 326 | case OP_RCR: X86L_IMMCL_REG(RCRL,it); break;
|
nkeynes@1006 | 327 | case OP_ROL: X86L_IMMCL_REG(ROLL,it); break;
|
nkeynes@1006 | 328 | case OP_ROR: X86L_IMMCL_REG(RORL,it); break;
|
nkeynes@1006 | 329 | case OP_SAR:
|
nkeynes@1006 | 330 | case OP_SARS: X86L_IMMCL_REG(SARL,it); break;
|
nkeynes@1006 | 331 | case OP_SUBBS: X86L_ALU_REG(SBBL,it); break;
|
nkeynes@1006 | 332 | case OP_SLL:
|
nkeynes@1006 | 333 | case OP_SLLS: X86L_IMMCL_REG(SHLL,it); break;
|
nkeynes@1006 | 334 | case OP_SLR:
|
nkeynes@1006 | 335 | case OP_SLRS: X86L_IMMCL_REG(SHRL,it); break;
|
nkeynes@1006 | 336 | case OP_SUB:
|
nkeynes@1006 | 337 | case OP_SUBS: X86L_ALU_REG(SUBL,it); break;
|
nkeynes@1006 | 338 | case OP_SHUFFLE:
|
nkeynes@1006 | 339 | if( XOP_IS_FORM(it,IMM,TGT) ) {
|
nkeynes@1006 | 340 | if( XOP_INT(it,0) == 0x4321 ) {
|
nkeynes@1006 | 341 | BSWAPL_r32( XOP_REG(it,1) );
|
nkeynes@1006 | 342 | } else if( it->operand[1].value.i == 0x1243 ) {
|
nkeynes@1006 | 343 | XCHGB_r8_r8( REG_AL, REG_AH );
|
nkeynes@1006 | 344 | /* XCHG al, ah */
|
nkeynes@1006 | 345 | }
|
nkeynes@1006 | 346 | }
|
nkeynes@1006 | 347 | break;
|
nkeynes@1006 | 348 | case OP_TST: X86L_ALU_REG(TESTL,it); break;
|
nkeynes@1006 | 349 | case OP_XOR: X86L_ALU_REG(XORL,it); break;
|
nkeynes@1006 | 350 |
|
nkeynes@1006 | 351 | // Float
|
nkeynes@1006 | 352 | case OP_ABSF:
|
nkeynes@1006 | 353 | case OP_ABSD:
|
nkeynes@1006 | 354 | // Why is there no SSE FP ABS instruction?
|
nkeynes@1006 | 355 | break;
|
nkeynes@1006 | 356 | case OP_ADDF: X86F_REG_TGT(ADDSS,it); break;
|
nkeynes@1006 | 357 | case OP_ADDD: X86F_REG_TGT(ADDSD,it); break;
|
nkeynes@1006 | 358 | case OP_CMPF:
|
nkeynes@1006 | 359 | break;
|
nkeynes@1006 | 360 | case OP_CMPD: // UCOMISD
|
nkeynes@1006 | 361 | break;
|
nkeynes@1006 | 362 | case OP_DIVF: X86F_REG_TGT(DIVSS,it); break;
|
nkeynes@1006 | 363 | case OP_DIVD: X86F_REG_TGT(DIVSD,it); break;
|
nkeynes@1006 | 364 | case OP_MULF: X86F_REG_TGT(MULSS,it); break;
|
nkeynes@1006 | 365 | case OP_MULD: X86F_REG_TGT(MULSD,it); break;
|
nkeynes@1006 | 366 | case OP_RSQRTF:X86F_REG_TGT(RSQRTSS,it); break;
|
nkeynes@1006 | 367 | case OP_SQRTF: X86F_REG_TGT(SQRTSS,it); break;
|
nkeynes@1006 | 368 | case OP_SQRTD: X86F_REG_TGT(SQRTSD,it); break;
|
nkeynes@1006 | 369 | case OP_SUBF: X86F_REG_TGT(SUBSS,it); break;
|
nkeynes@1006 | 370 | case OP_SUBD: X86F_REG_TGT(SUBSD,it); break;
|
nkeynes@1006 | 371 |
|
nkeynes@1006 | 372 | case OP_DOTPRODV:
|
nkeynes@1006 | 373 | MULPS_rbpdisp_xmm( XOP_REG1(it), 4 );
|
nkeynes@1006 | 374 | HADDPS_xmm_xmm( 4, 4 );
|
nkeynes@1006 | 375 | HADDPS_xmm_xmm( 4, 4 );
|
nkeynes@1006 | 376 | MOVSS_xmm_rbpdisp( 4, XOP_REG1(it) );
|
nkeynes@1006 | 377 | break;
|
nkeynes@1006 | 378 | case OP_SINCOSF:
|
nkeynes@1006 | 379 | case OP_MATMULV:
|
nkeynes@1006 | 380 | break;
|
nkeynes@1006 | 381 | case OP_FTOD:
|
nkeynes@1006 | 382 | if( XOP_IS_FORM(it,TGT,TGT) ) {
|
nkeynes@1006 | 383 | CVTSS2SD_xmm_xmm( XOP_REG(it,0), XOP_REG(it,1) );
|
nkeynes@1006 | 384 | } else if( XOP_IS_FORM(it,SRC,TGT) ) {
|
nkeynes@1006 | 385 | CVTSS2SD_rbpdisp_xmm( XOP_REG(it,0)+RBP_OFFSET, XOP_REG(it,1) );
|
nkeynes@1006 | 386 | } else {
|
nkeynes@1006 | 387 | ILLOP(it);
|
nkeynes@1006 | 388 | }
|
nkeynes@1006 | 389 | break;
|
nkeynes@1006 | 390 | case OP_DTOF:
|
nkeynes@1006 | 391 | if( XOP_IS_FORM(it,TGT,TGT) ) {
|
nkeynes@1006 | 392 | CVTSS2SD_xmm_xmm( XOP_REG(it,0), XOP_REG(it,1) );
|
nkeynes@1006 | 393 | } else if( XOP_IS_FORM(it, SRC,TGT) ) {
|
nkeynes@1006 | 394 | CVTSS2SD_rbpdisp_xmm( XOP_REG(it,0)+RBP_OFFSET, XOP_REG(it,1) );
|
nkeynes@1006 | 395 | } else {
|
nkeynes@1006 | 396 | ILLOP(it);
|
nkeynes@1006 | 397 | }
|
nkeynes@1006 | 398 | break;
|
nkeynes@1006 | 399 | case OP_ITOD:
|
nkeynes@1006 | 400 | if( XOP_IS_FORM(it,TGT,TGT) ) {
|
nkeynes@1006 | 401 | CVTSI2SDL_r32_xmm( XOP_REG(it,0), XOP_REG(it,1) );
|
nkeynes@1006 | 402 | } else if( XOP_IS_FORM(it,SRC,TGT) ) {
|
nkeynes@1006 | 403 | CVTSI2SDL_rbpdisp_xmm( XOP_REG(it,0)+RBP_OFFSET, XOP_REG(it,1) );
|
nkeynes@1006 | 404 | } else {
|
nkeynes@1006 | 405 | ILLOP(it);
|
nkeynes@1006 | 406 | }
|
nkeynes@1006 | 407 | break;
|
nkeynes@1006 | 408 | case OP_DTOI:
|
nkeynes@1006 | 409 | if( XOP_IS_FORM(it,TGT,TGT) ) {
|
nkeynes@1006 | 410 | CVTSD2SIL_xmm_r32( XOP_REG(it,0), XOP_REG(it,1) );
|
nkeynes@1006 | 411 | } else if( XOP_IS_FORM(it,SRC,TGT) ) {
|
nkeynes@1006 | 412 | CVTSD2SIL_rbpdisp_r32( XOP_REG(it,0)+RBP_OFFSET, XOP_REG(it,1) );
|
nkeynes@1006 | 413 | } else {
|
nkeynes@1006 | 414 | ILLOP(it);
|
nkeynes@1006 | 415 | }
|
nkeynes@1006 | 416 | break;
|
nkeynes@1006 | 417 | case OP_ITOF:
|
nkeynes@1006 | 418 | case OP_FTOI:
|
nkeynes@1006 | 419 |
|
nkeynes@1006 | 420 | case OP_BRCOND:
|
nkeynes@1006 | 421 | case OP_BRREL:
|
nkeynes@1006 | 422 | case OP_BR:
|
nkeynes@1006 | 423 | case OP_BRCONDDEL:
|
nkeynes@1006 | 424 |
|
nkeynes@1006 | 425 | case OP_CALL0:
|
nkeynes@1006 | 426 | if( XOP_IS_INTIMM(it,0) ) {
|
nkeynes@1006 | 427 | CALL_imm32( XOP_INT(it,0) );
|
nkeynes@1006 | 428 | } else if( XOP_IS_SRCREG(it,0) ) {
|
nkeynes@1006 | 429 | CALL_r32( XOP_INT(it,0) );
|
nkeynes@1006 | 430 | } else {
|
nkeynes@1006 | 431 | ILLOP(it);
|
nkeynes@1006 | 432 | }
|
nkeynes@1006 | 433 | break;
|
nkeynes@1006 | 434 | case OP_XLAT:
|
nkeynes@1006 | 435 | if( IS_X86_64() ) {
|
nkeynes@1006 | 436 | ss = 3;
|
nkeynes@1006 | 437 | } else {
|
nkeynes@1006 | 438 | ss = 2;
|
nkeynes@1006 | 439 | }
|
nkeynes@1006 | 440 | if( XOP_IS_FORM(it,IMM,TGT) ) {
|
nkeynes@1006 | 441 | MOVP_sib_rptr(ss, XOP_REG(it,1), -1, XOP_INT(it,0), XOP_REG(it,1));
|
nkeynes@1006 | 442 | } else if( XOP_IS_FORM(it,TGT,TGT) ) {
|
nkeynes@1006 | 443 | MOVP_sib_rptr(ss, XOP_REG(it,1), XOP_REG(it,0), 0, XOP_REG(it,1));
|
nkeynes@1006 | 444 | } else {
|
nkeynes@1006 | 445 | ILLOP(it);
|
nkeynes@1006 | 446 | }
|
nkeynes@1006 | 447 | break;
|
nkeynes@1006 | 448 | case OP_CALLLUT:
|
nkeynes@1006 | 449 | if( XOP_IS_FORM(it,TGT,IMM) ) {
|
nkeynes@1006 | 450 | CALL_r32disp(XOP_REG(it,0),XOP_INT(it,1));
|
nkeynes@1006 | 451 | } else if( XOP_IS_FORM(it,TGT,TGT) ) {
|
nkeynes@1006 | 452 | CALL_sib(0,XOP_REG(it,0),XOP_REG(it,1),0);
|
nkeynes@1006 | 453 | } else if( XOP_IS_FORM(it,IMM,TGT) ) {
|
nkeynes@1006 | 454 | CALL_r32disp(XOP_REG(it,1),XOP_INT(it,0));
|
nkeynes@1006 | 455 | } else {
|
nkeynes@1006 | 456 | ILLOP(it);
|
nkeynes@1006 | 457 | }
|
nkeynes@1006 | 458 | break;
|
nkeynes@1006 | 459 |
|
nkeynes@1006 | 460 | // SH4-specific macro operations
|
nkeynes@1006 | 461 | case OP_RAISEME:
|
nkeynes@1006 | 462 |
|
nkeynes@1006 | 463 | case OP_RAISEMNE:
|
nkeynes@1006 | 464 |
|
nkeynes@1006 | 465 | case OP_CMPSTR:
|
nkeynes@1006 | 466 | break;
|
nkeynes@1006 | 467 | case OP_DIV1:
|
nkeynes@1006 | 468 | break;
|
nkeynes@1006 | 469 | case OP_SHAD:
|
nkeynes@1006 | 470 | assert( it->operand[0].type == TGT && XOP_REG(it,0) == REG_ECX );
|
nkeynes@1006 | 471 | CMPL_imms_r32(0,REG_ECX);
|
nkeynes@1006 | 472 | JNGE_label(shad_shr);
|
nkeynes@1006 | 473 | X86L_CL_REG(SHLL,it);
|
nkeynes@1006 | 474 | JMP_label(shad_end);
|
nkeynes@1006 | 475 |
|
nkeynes@1006 | 476 | JMP_TARGET(shad_shr);
|
nkeynes@1006 | 477 | if( IS_X86_64() && it->operand[1].type == TGT ) {
|
nkeynes@1006 | 478 | /* We can do this a little more simply with a 64-bit shift */
|
nkeynes@1006 | 479 | ORL_imms_r32(0xFFFFFFE0,REG_ECX);
|
nkeynes@1006 | 480 | NEGL_r32(REG_ECX);
|
nkeynes@1006 | 481 | MOVSXQ_r32_r64(XOP_REG(it,1), XOP_REG(it,1)); // sign-extend
|
nkeynes@1006 | 482 | SARQ_cl_r64(XOP_REG(it,1));
|
nkeynes@1006 | 483 | } else {
|
nkeynes@1006 | 484 | NEGL_r32(REG_ECX);
|
nkeynes@1006 | 485 | ANDB_imms_r8( 0x1F, REG_ECX );
|
nkeynes@1006 | 486 | JE_label(emptyshr );
|
nkeynes@1006 | 487 | X86L_CL_REG(SARL,it);
|
nkeynes@1006 | 488 | JMP_label(shad_end2);
|
nkeynes@1006 | 489 |
|
nkeynes@1006 | 490 | JMP_TARGET(emptyshr);
|
nkeynes@1006 | 491 | if( it->operand[1].type == TGT ) {
|
nkeynes@1006 | 492 | SARL_imm_r32( 31, XOP_REG(it,1) );
|
nkeynes@1006 | 493 | } else {
|
nkeynes@1006 | 494 | SARL_imm_rbpdisp( 32, XOP_REG(it,1)+RBP_OFFSET );
|
nkeynes@1006 | 495 | }
|
nkeynes@1006 | 496 | JMP_TARGET(shad_end2);
|
nkeynes@1006 | 497 | }
|
nkeynes@1006 | 498 | JMP_TARGET(shad_end);
|
nkeynes@1006 | 499 | break;
|
nkeynes@1006 | 500 |
|
nkeynes@1006 | 501 | case OP_SHLD:
|
nkeynes@1006 | 502 | assert( it->operand[0].type == TGT && XOP_REG(it,0) == REG_ECX );
|
nkeynes@1006 | 503 | CMPL_imms_r32(0,REG_ECX);
|
nkeynes@1006 | 504 | JNGE_label(shld_shr);
|
nkeynes@1006 | 505 | X86L_CL_REG(SHLL,it);
|
nkeynes@1006 | 506 | JMP_label(shld_end);
|
nkeynes@1006 | 507 |
|
nkeynes@1006 | 508 | JMP_TARGET(shld_shr);
|
nkeynes@1006 | 509 | if( IS_X86_64() && it->operand[1].type == TGT ) {
|
nkeynes@1006 | 510 | /* We can do this a little more simply with a 64-bit shift */
|
nkeynes@1006 | 511 | ORL_imms_r32(0xFFFFFFE0,REG_ECX);
|
nkeynes@1006 | 512 | NEGL_r32(REG_ECX);
|
nkeynes@1006 | 513 | MOVL_r32_r32(XOP_REG(it,1), XOP_REG(it,1)); // Ensure high bits are 0
|
nkeynes@1006 | 514 | SHRQ_cl_r64(XOP_REG(it,1));
|
nkeynes@1006 | 515 | } else {
|
nkeynes@1006 | 516 | NEGL_r32(REG_ECX);
|
nkeynes@1006 | 517 | ANDB_imms_r8( 0x1F, REG_ECX );
|
nkeynes@1006 | 518 | JE_label(emptyshr );
|
nkeynes@1006 | 519 | X86L_CL_REG(SHRL,it);
|
nkeynes@1006 | 520 | JMP_label(shld_end2);
|
nkeynes@1006 | 521 |
|
nkeynes@1006 | 522 | JMP_TARGET(emptyshr);
|
nkeynes@1006 | 523 | XORL_r32_r32( REG_EAX, REG_EAX );
|
nkeynes@1006 | 524 | JMP_TARGET(shld_end2);
|
nkeynes@1006 | 525 | }
|
nkeynes@1006 | 526 | JMP_TARGET(shld_end);
|
nkeynes@1006 | 527 | break;
|
nkeynes@1006 | 528 |
|
nkeynes@1006 | 529 | case OP_MULQ:
|
nkeynes@1006 | 530 | case OP_ADDQSAT32:
|
nkeynes@1006 | 531 | case OP_ADDQSAT48:
|
nkeynes@1006 | 532 |
|
nkeynes@1006 | 533 | // Should not occur (should be have been lowered in target_lower)
|
nkeynes@1006 | 534 | case OP_NEGF:
|
nkeynes@1006 | 535 | case OP_NEGD:
|
nkeynes@1006 | 536 | case OP_LOADB:
|
nkeynes@1006 | 537 | case OP_LOADBFW:
|
nkeynes@1006 | 538 | case OP_LOADW:
|
nkeynes@1006 | 539 | case OP_LOADL:
|
nkeynes@1006 | 540 | case OP_LOADQ:
|
nkeynes@1006 | 541 | case OP_STOREB:
|
nkeynes@1006 | 542 | case OP_STOREW:
|
nkeynes@1006 | 543 | case OP_STOREL:
|
nkeynes@1006 | 544 | case OP_STOREQ:
|
nkeynes@1006 | 545 | case OP_STORELCA:
|
nkeynes@1006 | 546 | case OP_OCBI:
|
nkeynes@1006 | 547 | case OP_OCBP:
|
nkeynes@1006 | 548 | case OP_OCBWB:
|
nkeynes@1006 | 549 | case OP_PREF:
|
nkeynes@1006 | 550 | default:
|
nkeynes@1006 | 551 | ILLOP(it);
|
nkeynes@1006 | 552 | }
|
nkeynes@1006 | 553 | if( it == end )
|
nkeynes@1006 | 554 | break;
|
nkeynes@1006 | 555 | /* Epilogue */
|
nkeynes@1006 | 556 | }
|
nkeynes@1006 | 557 | }
|