filename | src/xlat/x86/x86gen.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 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@1011 | 108 | #define NONE NO_OPERAND |
nkeynes@1011 | 109 | #define SRC SOURCE_OPERAND |
nkeynes@1011 | 110 | #define DST DEST_OPERAND |
nkeynes@1011 | 111 | #define TMP TEMP_OPERAND |
nkeynes@1011 | 112 | #define IMM IMMEDIATE_OPERAND |
nkeynes@1006 | 113 | |
nkeynes@1011 | 114 | #define MAX_X86_GENERAL_REGISTER 7 |
nkeynes@1011 | 115 | #define MAX_AMD64_GENERAL_REGISTER 15 |
nkeynes@1011 | 116 | #define MIN_XMM_REGISTER 16 |
nkeynes@1011 | 117 | #define MAX_X86_XMM_REGISTER 23 |
nkeynes@1011 | 118 | #define MAX_AMD64_XMM_REGISTER 31 |
nkeynes@1006 | 119 | |
nkeynes@1011 | 120 | #define SRCADDR(op,n) (XOP_REG(op,n) - 128) |
nkeynes@1011 | 121 | #define TMPADDR(op,n) (XOP_REG(op,n)) /* FIXME */ |
nkeynes@1006 | 122 | |
nkeynes@1011 | 123 | #define ILLOP(op) FATAL("Illegal x86 opcode %s %d %d\n", XIR_OPCODE_TABLE[op->opcode], op->operand[0].form, op->operand[1].form) |
nkeynes@1006 | 124 | |
nkeynes@1006 | 125 | // Convenience macros |
nkeynes@1006 | 126 | #define X86L_IMMS_REG(opname, op) \ |
nkeynes@1011 | 127 | if( XOP_IS_FORM(op,IMM,DST) ) { opname##_imms_r32(XOP_INT(op,0),XOP_REG(op,1)); } \ |
nkeynes@1011 | 128 | else if( XOP_IS_FORM(op,IMM,SRC) ) { opname##_imms_r32disp(XOP_INT(op,0),REG_RBP,SRCADDR(op,1)); } \ |
nkeynes@1011 | 129 | else if( XOP_IS_FORM(op,IMM,TMP) ) { opname##_imms_r32disp(XOP_INT(op,0),REG_RSP,TMPADDR(op,1)); } \ |
nkeynes@1006 | 130 | else { ILLOP(op); } |
nkeynes@1006 | 131 | |
nkeynes@1011 | 132 | #define X86L_REG_DST(opname,op) \ |
nkeynes@1011 | 133 | if( XOP_IS_FORM(op,DST,DST) ) { opname##_r32_r32(XOP_REG(op,0),XOP_REG(op,1)); } \ |
nkeynes@1011 | 134 | else if( XOP_IS_FORM(op,SRC,DST) ) { opname##_r32disp_r32(REG_RBP, SRCADDR(op,0),XOP_REG(op,1)); } \ |
nkeynes@1011 | 135 | else if( XOP_IS_FORM(op,TMP,DST) ) { opname##_r32disp_r32(REG_RSP, TMPADDR(op,0),XOP_REG(op,1)); } \ |
nkeynes@1006 | 136 | else { ILLOP(op); } |
nkeynes@1006 | 137 | |
nkeynes@1011 | 138 | #define X86F_REG_DST(opname,op ) \ |
nkeynes@1011 | 139 | if( XOP_IS_FORM(op,DST,DST) ) { opname##_xmm_xmm(XOP_REG(op,0),XOP_REG(op,1)); } \ |
nkeynes@1011 | 140 | else if( XOP_IS_FORM(op,SRC,DST) ) { opname##_r32disp_xmm(REG_RBP, SRCADDR(op,0),XOP_REG(op,1)); } \ |
nkeynes@1011 | 141 | else if( XOP_IS_FORM(op,TMP,DST) ) { opname##_r32disp_xmm(REG_RSP, TMPADDR(op,0),XOP_REG(op,1)); } \ |
nkeynes@1006 | 142 | else { ILLOP(op); } |
nkeynes@1006 | 143 | |
nkeynes@1006 | 144 | #define X86L_REG_REG(opname,op) \ |
nkeynes@1011 | 145 | if( XOP_IS_FORM(op,DST,DST) ) { opname##_r32_r32(XOP_REG(op,0),XOP_REG(op,1)); } \ |
nkeynes@1011 | 146 | else if( XOP_IS_FORM(op,SRC,DST) ) { opname##_r32disp_r32(REG_RBP, SRCADDR(op,0),XOP_REG(op,1)); } \ |
nkeynes@1011 | 147 | else if( XOP_IS_FORM(op,DST,SRC) ) { opname##_r32_r32disp(XOP_REG(op,0),REG_RBP, SRCADDR(op,1)); } \ |
nkeynes@1011 | 148 | else if( XOP_IS_FORM(op,TMP,DST) ) { opname##_r32disp_r32(REG_RSP, TMPADDR(op,0),XOP_REG(op,1)); } \ |
nkeynes@1011 | 149 | else if( XOP_IS_FORM(op,DST,TMP) ) { opname##_r32_r32disp(XOP_REG(op,0),REG_RSP, TMPADDR(op,1)); } \ |
nkeynes@1006 | 150 | else { ILLOP(op); } |
nkeynes@1006 | 151 | |
nkeynes@1006 | 152 | #define X86L_REG(opname,op) \ |
nkeynes@1011 | 153 | if( XOP_IS_DST(op,0) ) { opname##_r32(XOP_REG(op,0)); } \ |
nkeynes@1011 | 154 | else if( XOP_IS_SRC(op,0) ) { opname##_r32disp(REG_RBP,SRCADDR(op,0)); } \ |
nkeynes@1011 | 155 | else if( XOP_IS_TMP(op,0) ) { opname##_r32disp(REG_RSP,TMPADDR(op,0)); } \ |
nkeynes@1006 | 156 | else { ILLOP(op); } |
nkeynes@1006 | 157 | |
nkeynes@1006 | 158 | #define X86L_CL_REG(opname,op) \ |
nkeynes@1011 | 159 | if( XOP_IS_FORM(op,DST,DST) && XOP_REG(op,0) == REG_CL ) { opname##_cl_r32(XOP_REG(op,1)); } \ |
nkeynes@1011 | 160 | else if( XOP_IS_FORM(op,DST,SRC) && XOP_REG(op,0) == REG_CL ) { opname##_cl_r32disp(REG_RBP, SRCADDR(op,1)); } \ |
nkeynes@1011 | 161 | else if( XOP_IS_FORM(op,DST,TMP) && XOP_REG(op,0) == REG_CL ) { opname##_cl_r32disp(REG_RSP, TMPADDR(op,1)); } \ |
nkeynes@1006 | 162 | else { ILLOP(op); } |
nkeynes@1006 | 163 | |
nkeynes@1006 | 164 | #define X86L_IMMCL_REG(opname,op) \ |
nkeynes@1011 | 165 | if( XOP_IS_FORM(op,IMM,DST) ) { opname##_imm_r32(XOP_INT(op,0),XOP_REG(op,1)); } \ |
nkeynes@1011 | 166 | else if( XOP_IS_FORM(op,IMM,SRC) ) { opname##_imm_r32disp(XOP_INT(op,0),REG_RBP, SRCADDR(op,1)); } \ |
nkeynes@1011 | 167 | else if( XOP_IS_FORM(op,IMM,TMP) ) { opname##_imm_r32disp(XOP_INT(op,0),REG_RSP, TMPADDR(op,1)); } \ |
nkeynes@1011 | 168 | else if( XOP_IS_FORM(op,DST,DST) && XOP_REG(op,0) == REG_CL ) { opname##_cl_r32(XOP_REG(op,1)); } \ |
nkeynes@1011 | 169 | else if( XOP_IS_FORM(op,DST,SRC) && XOP_REG(op,0) == REG_CL ) { opname##_cl_r32disp(REG_RBP, SRCADDR(op,1)); } \ |
nkeynes@1011 | 170 | else if( XOP_IS_FORM(op,DST,TMP) && XOP_REG(op,0) == REG_CL ) { opname##_cl_r32disp(REG_RSP, TMPADDR(op,1)); } \ |
nkeynes@1006 | 171 | else { ILLOP(op); } |
nkeynes@1006 | 172 | |
nkeynes@1006 | 173 | // Standard ALU forms - imms,reg or reg,reg |
nkeynes@1006 | 174 | #define X86L_ALU_REG(opname,op) \ |
nkeynes@1011 | 175 | if( XOP_IS_FORM(op,IMM,DST) ) { opname##_imms_r32(XOP_INT(op,0),XOP_REG(op,1)); } \ |
nkeynes@1011 | 176 | else if( XOP_IS_FORM(op,IMM,SRC) ) { opname##_imms_r32disp(XOP_INT(op,0),REG_RBP, SRCADDR(op,1)); } \ |
nkeynes@1011 | 177 | else if( XOP_IS_FORM(op,IMM,TMP) ) { opname##_imms_r32disp(XOP_INT(op,0),REG_RSP, TMPADDR(op,1)); } \ |
nkeynes@1011 | 178 | else if( XOP_IS_FORM(op,DST,DST) ) { opname##_r32_r32(XOP_REG(op,0),XOP_REG(op,1)); } \ |
nkeynes@1011 | 179 | else if( XOP_IS_FORM(op,SRC,DST) ) { opname##_r32disp_r32(REG_RBP, SRCADDR(op,0),XOP_REG(op,1)); } \ |
nkeynes@1011 | 180 | else if( XOP_IS_FORM(op,DST,SRC) ) { opname##_r32_r32disp(XOP_REG(op,0),REG_RBP, SRCADDR(op,1)); } \ |
nkeynes@1011 | 181 | else if( XOP_IS_FORM(op,TMP,DST) ) { opname##_r32disp_r32(REG_RSP, TMPADDR(op,0),XOP_REG(op,1)); } \ |
nkeynes@1011 | 182 | else if( XOP_IS_FORM(op,DST,TMP) ) { opname##_r32_r32disp(XOP_REG(op,0),REG_RSP, TMPADDR(op,1)); } \ |
nkeynes@1006 | 183 | else { ILLOP(op); } |
nkeynes@1006 | 184 | |
nkeynes@1006 | 185 | uint32_t x86_target_get_code_size( xir_op_t begin, xir_op_t end ) |
nkeynes@1006 | 186 | { |
nkeynes@1006 | 187 | return -1; |
nkeynes@1006 | 188 | } |
nkeynes@1006 | 189 | |
nkeynes@1006 | 190 | |
nkeynes@1006 | 191 | /** |
nkeynes@1006 | 192 | * Note: Assumes that the IR is x86-legal (ie doesn't contain any unencodeable instructions). |
nkeynes@1006 | 193 | */ |
nkeynes@1006 | 194 | uint32_t x86_target_codegen( target_data_t td, xir_op_t begin, xir_op_t end ) |
nkeynes@1006 | 195 | { |
nkeynes@1006 | 196 | int ss; |
nkeynes@1006 | 197 | xir_op_t it; |
nkeynes@1006 | 198 | |
nkeynes@1006 | 199 | /* Prologue */ |
nkeynes@1006 | 200 | |
nkeynes@1006 | 201 | for( it=begin; it != NULL; it = it->next ) { |
nkeynes@1006 | 202 | switch( it->opcode ) { |
nkeynes@1006 | 203 | case OP_ENTER: |
nkeynes@1006 | 204 | case OP_BARRIER: |
nkeynes@1006 | 205 | case OP_NOP: |
nkeynes@1006 | 206 | /* No code to generate */ |
nkeynes@1006 | 207 | break; |
nkeynes@1006 | 208 | case OP_MOV: |
nkeynes@1011 | 209 | if( XOP_IS_FORM(it, IMM, DST) ) { |
nkeynes@1006 | 210 | MOVL_imm32_r32( XOP_INT(it,0), XOP_REG2(it) ); |
nkeynes@1011 | 211 | } else if( XOP_IS_FORM(it, IMM, SRC) ) { |
nkeynes@1011 | 212 | MOVL_imm32_r32disp( XOP_INT(it,0), REG_RBP, SRCADDR(it,1) ); |
nkeynes@1011 | 213 | } else if( XOP_IS_FORM(it, IMM, TMP) ) { |
nkeynes@1011 | 214 | MOVL_imm32_r32disp( XOP_INT(it,0), REG_RSP, TMPADDR(it,1) ); |
nkeynes@1011 | 215 | } else if( XOP_IS_FORM(it, DST, SRC) ) { |
nkeynes@1006 | 216 | if( IS_XMM_REG(it,0) ) { |
nkeynes@1011 | 217 | MOVSS_xmm_r32disp( XOP_REG1(it), REG_RBP, SRCADDR(it,1) ); |
nkeynes@1006 | 218 | } else { |
nkeynes@1011 | 219 | MOVL_r32_r32disp( XOP_REG1(it), REG_RBP, SRCADDR(it,1) ); |
nkeynes@1006 | 220 | } |
nkeynes@1011 | 221 | } else if( XOP_IS_FORM(it, DST, DST) ) { |
nkeynes@1006 | 222 | if( IS_XMM_REG(it,0) ) { |
nkeynes@1006 | 223 | if( IS_XMM_REG(it,1) ) { |
nkeynes@1006 | 224 | MOVSS_xmm_xmm( XOP_REG1(it), XOP_REG2(it) ); |
nkeynes@1006 | 225 | } else { |
nkeynes@1006 | 226 | MOVL_xmm_r32( XOP_REG1(it), XOP_REG2(it) ); |
nkeynes@1006 | 227 | } |
nkeynes@1006 | 228 | } else if( IS_XMM_REG(it,1) ) { |
nkeynes@1006 | 229 | MOVL_r32_xmm( XOP_REG1(it), XOP_REG2(it) ); |
nkeynes@1006 | 230 | } else { |
nkeynes@1006 | 231 | MOVL_r32_r32( XOP_REG1(it), XOP_REG2(it) ); |
nkeynes@1006 | 232 | } |
nkeynes@1011 | 233 | } else if( XOP_IS_FORM(it, SRC, DST) ) { |
nkeynes@1006 | 234 | if( IS_XMM_REG(it,1) ) { |
nkeynes@1011 | 235 | MOVSS_r32disp_xmm( REG_RBP, SRCADDR(it,0), XOP_REG2(it) ); |
nkeynes@1006 | 236 | } else { |
nkeynes@1011 | 237 | MOVL_r32disp_r32( REG_RBP, SRCADDR(it,0), XOP_REG2(it) ); |
nkeynes@1006 | 238 | } |
nkeynes@1006 | 239 | } else { |
nkeynes@1006 | 240 | ILLOP(it); |
nkeynes@1006 | 241 | } |
nkeynes@1006 | 242 | break; |
nkeynes@1006 | 243 | case OP_MOVQ: |
nkeynes@1006 | 244 | if( XOP_IS_FORM(it, IMM, SRC) ) { |
nkeynes@1006 | 245 | ILLOP(it); |
nkeynes@1011 | 246 | } else if( XOP_IS_FORM(it, IMM, DST) ) { |
nkeynes@1006 | 247 | if( IS_XMM_REG(it,0) ) { |
nkeynes@1006 | 248 | if( XOP_INT(it,0) == 0 ) { |
nkeynes@1006 | 249 | XORPD_xmm_xmm( XOP_REG2(it), XOP_REG2(it) ); |
nkeynes@1006 | 250 | } |
nkeynes@1006 | 251 | } else { |
nkeynes@1006 | 252 | MOVQ_imm64_r64( XOP_INT(it,0), XOP_REG2(it) ); |
nkeynes@1006 | 253 | } |
nkeynes@1011 | 254 | } else if( XOP_IS_FORM(it, DST, SRC) ) { |
nkeynes@1006 | 255 | if( IS_XMM_REG(it,0) ) { |
nkeynes@1011 | 256 | MOVSD_xmm_r32disp( XOP_REG1(it), REG_RBP, SRCADDR(it,1) ); |
nkeynes@1006 | 257 | } else { |
nkeynes@1011 | 258 | MOVQ_r64_r64disp( XOP_REG1(it), REG_RBP, SRCADDR(it,1) ); |
nkeynes@1006 | 259 | } |
nkeynes@1011 | 260 | } else if( XOP_IS_FORM(it, DST, DST) ) { |
nkeynes@1006 | 261 | if( IS_XMM_REG(it,0) ) { |
nkeynes@1006 | 262 | if( IS_XMM_REG(it,1) ) { |
nkeynes@1006 | 263 | MOVSD_xmm_xmm( XOP_REG1(it), XOP_REG2(it) ); |
nkeynes@1006 | 264 | } else { |
nkeynes@1006 | 265 | MOVQ_xmm_r64( XOP_REG1(it), XOP_REG2(it) ); |
nkeynes@1006 | 266 | } |
nkeynes@1006 | 267 | } else if( IS_XMM_REG(it,1) ) { |
nkeynes@1006 | 268 | MOVQ_r64_xmm( XOP_REG1(it), XOP_REG2(it) ); |
nkeynes@1006 | 269 | } else { |
nkeynes@1006 | 270 | MOVQ_r64_r64( XOP_REG1(it), XOP_REG2(it) ); |
nkeynes@1006 | 271 | } |
nkeynes@1011 | 272 | } else if( XOP_IS_FORM(it, SRC, DST) ) { |
nkeynes@1006 | 273 | if( IS_XMM_REG(it,1) ) { |
nkeynes@1011 | 274 | MOVSD_r32disp_xmm( REG_RBP, SRCADDR(it,0), XOP_REG2(it) ); |
nkeynes@1006 | 275 | } else { |
nkeynes@1011 | 276 | MOVQ_r64disp_r64( REG_RBP, SRCADDR(it,0), XOP_REG2(it) ); |
nkeynes@1006 | 277 | } |
nkeynes@1006 | 278 | } else { |
nkeynes@1006 | 279 | ILLOP(it); |
nkeynes@1006 | 280 | } |
nkeynes@1006 | 281 | break; |
nkeynes@1006 | 282 | case OP_MOVSX8: |
nkeynes@1011 | 283 | if( XOP_IS_FORM(it, DST, DST) ) { |
nkeynes@1006 | 284 | MOVSXL_r8_r32( XOP_REG1(it), XOP_REG2(it) ); |
nkeynes@1011 | 285 | } else if( XOP_IS_FORM(it, SRC, DST) ) { |
nkeynes@1011 | 286 | MOVSXL_r32disp8_r32( REG_RBP, SRCADDR(it,0), XOP_REG2(it) ); |
nkeynes@1006 | 287 | } else { |
nkeynes@1006 | 288 | ILLOP(it); |
nkeynes@1006 | 289 | } |
nkeynes@1006 | 290 | break; |
nkeynes@1006 | 291 | case OP_MOVSX16: |
nkeynes@1011 | 292 | if( XOP_IS_FORM(it, DST, DST) ) { |
nkeynes@1006 | 293 | MOVSXL_r16_r32( XOP_REG1(it), XOP_REG2(it) ); |
nkeynes@1011 | 294 | } else if( XOP_IS_FORM(it, SRC, DST) ) { |
nkeynes@1011 | 295 | MOVSXL_r32disp16_r32( REG_RBP, SRCADDR(it,0), XOP_REG2(it) ); |
nkeynes@1006 | 296 | } else { |
nkeynes@1006 | 297 | ILLOP(it); |
nkeynes@1006 | 298 | } |
nkeynes@1006 | 299 | break; |
nkeynes@1006 | 300 | case OP_MOVZX8: |
nkeynes@1011 | 301 | if( XOP_IS_FORM(it, DST, DST) ) { |
nkeynes@1006 | 302 | MOVZXL_r8_r32( XOP_REG1(it), XOP_REG2(it) ); |
nkeynes@1011 | 303 | } else if( XOP_IS_FORM(it, SRC, DST) ) { |
nkeynes@1011 | 304 | MOVZXL_r32disp8_r32( REG_RBP, SRCADDR(it,0), XOP_REG2(it) ); |
nkeynes@1006 | 305 | } else { |
nkeynes@1006 | 306 | ILLOP(it); |
nkeynes@1006 | 307 | } |
nkeynes@1006 | 308 | break; |
nkeynes@1006 | 309 | case OP_MOVZX16: |
nkeynes@1011 | 310 | if( XOP_IS_FORM(it, DST, DST) ) { |
nkeynes@1006 | 311 | MOVZXL_r16_r32( XOP_REG1(it), XOP_REG2(it) ); |
nkeynes@1011 | 312 | } else if( XOP_IS_FORM(it, SRC, DST) ) { |
nkeynes@1011 | 313 | MOVZXL_r32disp16_r32( REG_RBP, SRCADDR(it,0), XOP_REG2(it) ); |
nkeynes@1006 | 314 | } else { |
nkeynes@1006 | 315 | ILLOP(it); |
nkeynes@1006 | 316 | } |
nkeynes@1006 | 317 | break; |
nkeynes@1006 | 318 | case OP_ADD: |
nkeynes@1006 | 319 | case OP_ADDS: X86L_ALU_REG(ADDL,it); break; |
nkeynes@1006 | 320 | case OP_ADDCS: X86L_ALU_REG(ADCL,it); break; |
nkeynes@1006 | 321 | case OP_AND: X86L_ALU_REG(ANDL,it); break; |
nkeynes@1006 | 322 | case OP_CMP: |
nkeynes@1006 | 323 | X86L_ALU_REG(CMPL,it); break; |
nkeynes@1006 | 324 | case OP_DEC: |
nkeynes@1011 | 325 | if( XOP_IS_FORM(it,DST,NONE) ) { |
nkeynes@1006 | 326 | DECL_r32(XOP_REG(it,0)); |
nkeynes@1006 | 327 | } else if( XOP_IS_FORM(it,SRC,NONE) ) { |
nkeynes@1011 | 328 | DECL_r32disp( REG_RBP, SRCADDR(it,0) ); |
nkeynes@1006 | 329 | } else { |
nkeynes@1006 | 330 | ILLOP(it); |
nkeynes@1006 | 331 | } |
nkeynes@1006 | 332 | break; |
nkeynes@1006 | 333 | case OP_MUL: |
nkeynes@1011 | 334 | X86L_REG_DST(IMULL,it); |
nkeynes@1006 | 335 | break; |
nkeynes@1006 | 336 | case OP_NEG: X86L_REG(NEGL,it); break; |
nkeynes@1006 | 337 | case OP_NOT: X86L_REG(NOTL,it); break; |
nkeynes@1006 | 338 | case OP_OR: X86L_ALU_REG(ORL,it); break; |
nkeynes@1006 | 339 | case OP_RCL: X86L_IMMCL_REG(RCLL,it); break; |
nkeynes@1006 | 340 | case OP_RCR: X86L_IMMCL_REG(RCRL,it); break; |
nkeynes@1006 | 341 | case OP_ROL: X86L_IMMCL_REG(ROLL,it); break; |
nkeynes@1006 | 342 | case OP_ROR: X86L_IMMCL_REG(RORL,it); break; |
nkeynes@1006 | 343 | case OP_SAR: |
nkeynes@1006 | 344 | case OP_SARS: X86L_IMMCL_REG(SARL,it); break; |
nkeynes@1006 | 345 | case OP_SUBBS: X86L_ALU_REG(SBBL,it); break; |
nkeynes@1006 | 346 | case OP_SLL: |
nkeynes@1006 | 347 | case OP_SLLS: X86L_IMMCL_REG(SHLL,it); break; |
nkeynes@1006 | 348 | case OP_SLR: |
nkeynes@1006 | 349 | case OP_SLRS: X86L_IMMCL_REG(SHRL,it); break; |
nkeynes@1006 | 350 | case OP_SUB: |
nkeynes@1006 | 351 | case OP_SUBS: X86L_ALU_REG(SUBL,it); break; |
nkeynes@1006 | 352 | case OP_SHUFFLE: |
nkeynes@1011 | 353 | if( XOP_IS_FORM(it,IMM,DST) ) { |
nkeynes@1006 | 354 | if( XOP_INT(it,0) == 0x4321 ) { |
nkeynes@1006 | 355 | BSWAPL_r32( XOP_REG(it,1) ); |
nkeynes@1006 | 356 | } else if( it->operand[1].value.i == 0x1243 ) { |
nkeynes@1006 | 357 | XCHGB_r8_r8( REG_AL, REG_AH ); |
nkeynes@1006 | 358 | /* XCHG al, ah */ |
nkeynes@1006 | 359 | } |
nkeynes@1006 | 360 | } |
nkeynes@1006 | 361 | break; |
nkeynes@1006 | 362 | case OP_TST: X86L_ALU_REG(TESTL,it); break; |
nkeynes@1006 | 363 | case OP_XOR: X86L_ALU_REG(XORL,it); break; |
nkeynes@1006 | 364 | |
nkeynes@1006 | 365 | // Float |
nkeynes@1006 | 366 | case OP_ABSF: |
nkeynes@1006 | 367 | case OP_ABSD: |
nkeynes@1006 | 368 | // Why is there no SSE FP ABS instruction? |
nkeynes@1006 | 369 | break; |
nkeynes@1011 | 370 | case OP_ADDF: X86F_REG_DST(ADDSS,it); break; |
nkeynes@1011 | 371 | case OP_ADDD: X86F_REG_DST(ADDSD,it); break; |
nkeynes@1006 | 372 | case OP_CMPF: |
nkeynes@1006 | 373 | break; |
nkeynes@1006 | 374 | case OP_CMPD: // UCOMISD |
nkeynes@1006 | 375 | break; |
nkeynes@1011 | 376 | case OP_DIVF: X86F_REG_DST(DIVSS,it); break; |
nkeynes@1011 | 377 | case OP_DIVD: X86F_REG_DST(DIVSD,it); break; |
nkeynes@1011 | 378 | case OP_MULF: X86F_REG_DST(MULSS,it); break; |
nkeynes@1011 | 379 | case OP_MULD: X86F_REG_DST(MULSD,it); break; |
nkeynes@1011 | 380 | case OP_RSQRTF:X86F_REG_DST(RSQRTSS,it); break; |
nkeynes@1011 | 381 | case OP_SQRTF: X86F_REG_DST(SQRTSS,it); break; |
nkeynes@1011 | 382 | case OP_SQRTD: X86F_REG_DST(SQRTSD,it); break; |
nkeynes@1011 | 383 | case OP_SUBF: X86F_REG_DST(SUBSS,it); break; |
nkeynes@1011 | 384 | case OP_SUBD: X86F_REG_DST(SUBSD,it); break; |
nkeynes@1006 | 385 | |
nkeynes@1006 | 386 | case OP_DOTPRODV: |
nkeynes@1011 | 387 | MULPS_r32disp_xmm( REG_RBP, SRCADDR(it,0), 4 ); |
nkeynes@1006 | 388 | HADDPS_xmm_xmm( 4, 4 ); |
nkeynes@1006 | 389 | HADDPS_xmm_xmm( 4, 4 ); |
nkeynes@1011 | 390 | MOVSS_xmm_r32disp( 4, REG_RBP, SRCADDR(it,0) ); |
nkeynes@1006 | 391 | break; |
nkeynes@1006 | 392 | case OP_SINCOSF: |
nkeynes@1006 | 393 | case OP_MATMULV: |
nkeynes@1006 | 394 | break; |
nkeynes@1006 | 395 | case OP_FTOD: |
nkeynes@1011 | 396 | if( XOP_IS_FORM(it,DST,DST) ) { |
nkeynes@1006 | 397 | CVTSS2SD_xmm_xmm( XOP_REG(it,0), XOP_REG(it,1) ); |
nkeynes@1011 | 398 | } else if( XOP_IS_FORM(it,SRC,DST) ) { |
nkeynes@1011 | 399 | CVTSS2SD_r32disp_xmm( REG_RBP, SRCADDR(it,0), XOP_REG(it,1) ); |
nkeynes@1006 | 400 | } else { |
nkeynes@1006 | 401 | ILLOP(it); |
nkeynes@1006 | 402 | } |
nkeynes@1006 | 403 | break; |
nkeynes@1006 | 404 | case OP_DTOF: |
nkeynes@1011 | 405 | if( XOP_IS_FORM(it,DST,DST) ) { |
nkeynes@1006 | 406 | CVTSS2SD_xmm_xmm( XOP_REG(it,0), XOP_REG(it,1) ); |
nkeynes@1011 | 407 | } else if( XOP_IS_FORM(it, SRC,DST) ) { |
nkeynes@1011 | 408 | CVTSS2SD_r32disp_xmm( REG_RBP, SRCADDR(it,0), XOP_REG(it,1) ); |
nkeynes@1006 | 409 | } else { |
nkeynes@1006 | 410 | ILLOP(it); |
nkeynes@1006 | 411 | } |
nkeynes@1006 | 412 | break; |
nkeynes@1006 | 413 | case OP_ITOD: |
nkeynes@1011 | 414 | if( XOP_IS_FORM(it,DST,DST) ) { |
nkeynes@1006 | 415 | CVTSI2SDL_r32_xmm( XOP_REG(it,0), XOP_REG(it,1) ); |
nkeynes@1011 | 416 | } else if( XOP_IS_FORM(it,SRC,DST) ) { |
nkeynes@1011 | 417 | CVTSI2SDL_r32disp_xmm( REG_RBP, SRCADDR(it,0), XOP_REG(it,1) ); |
nkeynes@1006 | 418 | } else { |
nkeynes@1006 | 419 | ILLOP(it); |
nkeynes@1006 | 420 | } |
nkeynes@1006 | 421 | break; |
nkeynes@1006 | 422 | case OP_DTOI: |
nkeynes@1011 | 423 | if( XOP_IS_FORM(it,DST,DST) ) { |
nkeynes@1006 | 424 | CVTSD2SIL_xmm_r32( XOP_REG(it,0), XOP_REG(it,1) ); |
nkeynes@1011 | 425 | } else if( XOP_IS_FORM(it,SRC,DST) ) { |
nkeynes@1011 | 426 | CVTSD2SIL_r32disp_r32( REG_RBP, SRCADDR(it,0), XOP_REG(it,1) ); |
nkeynes@1006 | 427 | } else { |
nkeynes@1006 | 428 | ILLOP(it); |
nkeynes@1006 | 429 | } |
nkeynes@1006 | 430 | break; |
nkeynes@1006 | 431 | case OP_ITOF: |
nkeynes@1006 | 432 | case OP_FTOI: |
nkeynes@1006 | 433 | |
nkeynes@1006 | 434 | case OP_BRCOND: |
nkeynes@1006 | 435 | case OP_BRREL: |
nkeynes@1006 | 436 | case OP_BR: |
nkeynes@1006 | 437 | case OP_BRCONDDEL: |
nkeynes@1006 | 438 | |
nkeynes@1006 | 439 | case OP_CALL0: |
nkeynes@1011 | 440 | if( XOP_IS_IMM(it,0) ) { |
nkeynes@1006 | 441 | CALL_imm32( XOP_INT(it,0) ); |
nkeynes@1011 | 442 | } else if( XOP_IS_SRC(it,0) ) { |
nkeynes@1006 | 443 | CALL_r32( XOP_INT(it,0) ); |
nkeynes@1006 | 444 | } else { |
nkeynes@1006 | 445 | ILLOP(it); |
nkeynes@1006 | 446 | } |
nkeynes@1006 | 447 | break; |
nkeynes@1006 | 448 | case OP_XLAT: |
nkeynes@1006 | 449 | if( IS_X86_64() ) { |
nkeynes@1006 | 450 | ss = 3; |
nkeynes@1006 | 451 | } else { |
nkeynes@1006 | 452 | ss = 2; |
nkeynes@1006 | 453 | } |
nkeynes@1011 | 454 | if( XOP_IS_FORM(it,IMM,DST) ) { |
nkeynes@1006 | 455 | MOVP_sib_rptr(ss, XOP_REG(it,1), -1, XOP_INT(it,0), XOP_REG(it,1)); |
nkeynes@1011 | 456 | } else if( XOP_IS_FORM(it,DST,DST) ) { |
nkeynes@1006 | 457 | MOVP_sib_rptr(ss, XOP_REG(it,1), XOP_REG(it,0), 0, XOP_REG(it,1)); |
nkeynes@1006 | 458 | } else { |
nkeynes@1006 | 459 | ILLOP(it); |
nkeynes@1006 | 460 | } |
nkeynes@1006 | 461 | break; |
nkeynes@1006 | 462 | case OP_CALLLUT: |
nkeynes@1011 | 463 | if( XOP_IS_FORM(it,DST,IMM) ) { |
nkeynes@1006 | 464 | CALL_r32disp(XOP_REG(it,0),XOP_INT(it,1)); |
nkeynes@1011 | 465 | } else if( XOP_IS_FORM(it,DST,DST) ) { |
nkeynes@1006 | 466 | CALL_sib(0,XOP_REG(it,0),XOP_REG(it,1),0); |
nkeynes@1011 | 467 | } else if( XOP_IS_FORM(it,IMM,DST) ) { |
nkeynes@1006 | 468 | CALL_r32disp(XOP_REG(it,1),XOP_INT(it,0)); |
nkeynes@1006 | 469 | } else { |
nkeynes@1006 | 470 | ILLOP(it); |
nkeynes@1006 | 471 | } |
nkeynes@1006 | 472 | break; |
nkeynes@1006 | 473 | |
nkeynes@1006 | 474 | // SH4-specific macro operations |
nkeynes@1006 | 475 | case OP_RAISEME: |
nkeynes@1006 | 476 | |
nkeynes@1006 | 477 | case OP_RAISEMNE: |
nkeynes@1006 | 478 | |
nkeynes@1006 | 479 | case OP_CMPSTR: |
nkeynes@1006 | 480 | break; |
nkeynes@1006 | 481 | case OP_DIV1: |
nkeynes@1006 | 482 | break; |
nkeynes@1006 | 483 | case OP_SHAD: |
nkeynes@1011 | 484 | assert( it->operand[0].form == DST && XOP_REG(it,0) == REG_ECX ); |
nkeynes@1006 | 485 | CMPL_imms_r32(0,REG_ECX); |
nkeynes@1006 | 486 | JNGE_label(shad_shr); |
nkeynes@1006 | 487 | X86L_CL_REG(SHLL,it); |
nkeynes@1006 | 488 | JMP_label(shad_end); |
nkeynes@1006 | 489 | |
nkeynes@1006 | 490 | JMP_TARGET(shad_shr); |
nkeynes@1011 | 491 | if( IS_X86_64() && it->operand[1].form == DST ) { |
nkeynes@1006 | 492 | /* We can do this a little more simply with a 64-bit shift */ |
nkeynes@1006 | 493 | ORL_imms_r32(0xFFFFFFE0,REG_ECX); |
nkeynes@1006 | 494 | NEGL_r32(REG_ECX); |
nkeynes@1006 | 495 | MOVSXQ_r32_r64(XOP_REG(it,1), XOP_REG(it,1)); // sign-extend |
nkeynes@1006 | 496 | SARQ_cl_r64(XOP_REG(it,1)); |
nkeynes@1006 | 497 | } else { |
nkeynes@1006 | 498 | NEGL_r32(REG_ECX); |
nkeynes@1006 | 499 | ANDB_imms_r8( 0x1F, REG_ECX ); |
nkeynes@1006 | 500 | JE_label(emptyshr ); |
nkeynes@1006 | 501 | X86L_CL_REG(SARL,it); |
nkeynes@1006 | 502 | JMP_label(shad_end2); |
nkeynes@1006 | 503 | |
nkeynes@1006 | 504 | JMP_TARGET(emptyshr); |
nkeynes@1011 | 505 | if( it->operand[1].form == DST ) { |
nkeynes@1006 | 506 | SARL_imm_r32( 31, XOP_REG(it,1) ); |
nkeynes@1011 | 507 | } else if( it->operand[1].form == SRC ) { |
nkeynes@1011 | 508 | SARL_imm_r32disp( 32, REG_RBP, SRCADDR(it,1) ); |
nkeynes@1006 | 509 | } else { |
nkeynes@1011 | 510 | SARL_imm_r32disp( 32, REG_RSP, TMPADDR(it,1) ); |
nkeynes@1006 | 511 | } |
nkeynes@1006 | 512 | JMP_TARGET(shad_end2); |
nkeynes@1006 | 513 | } |
nkeynes@1006 | 514 | JMP_TARGET(shad_end); |
nkeynes@1006 | 515 | break; |
nkeynes@1006 | 516 | |
nkeynes@1006 | 517 | case OP_SHLD: |
nkeynes@1011 | 518 | assert( it->operand[0].form == DST && XOP_REG(it,0) == REG_ECX ); |
nkeynes@1006 | 519 | CMPL_imms_r32(0,REG_ECX); |
nkeynes@1006 | 520 | JNGE_label(shld_shr); |
nkeynes@1006 | 521 | X86L_CL_REG(SHLL,it); |
nkeynes@1006 | 522 | JMP_label(shld_end); |
nkeynes@1006 | 523 | |
nkeynes@1006 | 524 | JMP_TARGET(shld_shr); |
nkeynes@1011 | 525 | if( IS_X86_64() && it->operand[1].form == DST ) { |
nkeynes@1006 | 526 | /* We can do this a little more simply with a 64-bit shift */ |
nkeynes@1006 | 527 | ORL_imms_r32(0xFFFFFFE0,REG_ECX); |
nkeynes@1006 | 528 | NEGL_r32(REG_ECX); |
nkeynes@1006 | 529 | MOVL_r32_r32(XOP_REG(it,1), XOP_REG(it,1)); // Ensure high bits are 0 |
nkeynes@1006 | 530 | SHRQ_cl_r64(XOP_REG(it,1)); |
nkeynes@1006 | 531 | } else { |
nkeynes@1006 | 532 | NEGL_r32(REG_ECX); |
nkeynes@1006 | 533 | ANDB_imms_r8( 0x1F, REG_ECX ); |
nkeynes@1006 | 534 | JE_label(emptyshr ); |
nkeynes@1006 | 535 | X86L_CL_REG(SHRL,it); |
nkeynes@1006 | 536 | JMP_label(shld_end2); |
nkeynes@1006 | 537 | |
nkeynes@1006 | 538 | JMP_TARGET(emptyshr); |
nkeynes@1006 | 539 | XORL_r32_r32( REG_EAX, REG_EAX ); |
nkeynes@1006 | 540 | JMP_TARGET(shld_end2); |
nkeynes@1006 | 541 | } |
nkeynes@1006 | 542 | JMP_TARGET(shld_end); |
nkeynes@1006 | 543 | break; |
nkeynes@1006 | 544 | |
nkeynes@1006 | 545 | case OP_MULQ: |
nkeynes@1006 | 546 | case OP_ADDQSAT32: |
nkeynes@1006 | 547 | case OP_ADDQSAT48: |
nkeynes@1006 | 548 | |
nkeynes@1006 | 549 | // Should not occur (should be have been lowered in target_lower) |
nkeynes@1006 | 550 | case OP_NEGF: |
nkeynes@1006 | 551 | case OP_NEGD: |
nkeynes@1006 | 552 | case OP_LOADB: |
nkeynes@1006 | 553 | case OP_LOADBFW: |
nkeynes@1006 | 554 | case OP_LOADW: |
nkeynes@1006 | 555 | case OP_LOADL: |
nkeynes@1006 | 556 | case OP_LOADQ: |
nkeynes@1006 | 557 | case OP_STOREB: |
nkeynes@1006 | 558 | case OP_STOREW: |
nkeynes@1006 | 559 | case OP_STOREL: |
nkeynes@1006 | 560 | case OP_STOREQ: |
nkeynes@1006 | 561 | case OP_STORELCA: |
nkeynes@1006 | 562 | case OP_OCBI: |
nkeynes@1006 | 563 | case OP_OCBP: |
nkeynes@1006 | 564 | case OP_OCBWB: |
nkeynes@1006 | 565 | case OP_PREF: |
nkeynes@1006 | 566 | default: |
nkeynes@1006 | 567 | ILLOP(it); |
nkeynes@1006 | 568 | } |
nkeynes@1006 | 569 | if( it == end ) |
nkeynes@1006 | 570 | break; |
nkeynes@1006 | 571 | /* Epilogue */ |
nkeynes@1006 | 572 | } |
nkeynes@1006 | 573 | } |
.