x86: generate shlx sarx shrx
[ajla.git] / c2-x86.inc
blobf577a276f59cec2d9fbd6edfd09898a75262fa4f
1 /*
2  * Copyright (C) 2024 Mikulas Patocka
3  *
4  * This file is part of Ajla.
5  *
6  * Ajla is free software: you can redistribute it and/or modify it under the
7  * terms of the GNU General Public License as published by the Free Software
8  * Foundation, either version 3 of the License, or (at your option) any later
9  * version.
10  *
11  * Ajla is distributed in the hope that it will be useful, but WITHOUT ANY
12  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * Ajla. If not, see <https://www.gnu.org/licenses/>.
17  */
19 #define X86_ALU_RM8_R8                  0x00
20 #define X86_ALU_RM16_R16                0x01
21 #define X86_ALU_R8_RM8                  0x02
22 #define X86_ALU_R16_RM16                0x03
23 #define X86_ALU_AL_IMM8                 0x04
24 #define X86_ALU_AX_IMM16                0x05
25 #define X86_0F                          0x0f
26 #define X86_ES                          0x26
27 #define X86_CS                          0x2e
28 #define X86_SS                          0x36
29 #define X86_DS                          0x3e
30 #define X86_REX                         0x40
31 #define  X86_REX_B                              0x01
32 #define  X86_REX_X                              0x02
33 #define  X86_REX_R                              0x04
34 #define  X86_REX_W                              0x08
35 #define X86_INC_R16                     0x40
36 #define X86_DEC_R16                     0x48
37 #define X86_PUSH_R16                    0x50
38 #define X86_POP_R16                     0x58
39 #define X86_MOVSXD                      0x63
40 #define X86_FS                          0x64
41 #define X86_GS                          0x65
42 #define X86_OP_SIZE                     0x66
43 #define X86_PUSH_IMM16                  0x68
44 #define X86_IMUL_R16_RM16_IMM16         0x69
45 #define X86_PUSH_IMM8                   0x6a
46 #define X86_IMUL_R16_RM16_IMM8          0x6b
47 #define X86_JCC_8                       0x70
48 #define X86_ALU_RM8_IMM8                0x80
49 #define X86_ALU_RM16_IMM16              0x81
50 #define X86_ALU_RM16_IMM8               0x83
51 #define X86_TEST_RM8_R8                 0x84
52 #define X86_TEST_RM16_R16               0x85
53 #define X86_MOV_RM8_R8                  0x88
54 #define X86_MOV_RM16_R16                0x89
55 #define X86_MOV_R8_RM8                  0x8a
56 #define X86_MOV_R16_RM16                0x8b
57 #define X86_LEA_R16_RM16                0x8d
58 #define X86_CBW                         0x98
59 #define X86_CWD                         0x99
60 #define X86_MOV_AL_M16                  0xa0
61 #define X86_MOV_AX_M16                  0xa1
62 #define X86_MOV_M16_AL                  0xa2
63 #define X86_MOV_M16_AX                  0xa3
64 #define X86_MOVSB                       0xa4
65 #define X86_TEST_AL_IMM8                0xa8
66 #define X86_TEST_AX_IMM16               0xa9
67 #define X86_STOSB                       0xaa
68 #define X86_MOV_R16_IMM16               0xb8
69 #define X86_ROT_RM8_IMM8                0xc0
70 #define X86_ROT_RM16_IMM8               0xc1
71 #define X86_RET_IMM16                   0xc2
72 #define X86_RET                         0xc3
73 #define X86_VEX_3                       0xc4
74 #define X86_VEX_2                       0xc5
75 #define X86_MOV_RM8_IMM8                0xc6
76 #define X86_MOV_RM16_IMM16              0xc7
77 #define  X86_MOV_R16_IMM16_REG                  0x0
78 #define X86_8F                          0x8f
79 #define  X86_8F_POP                             0x0
80 #define X86_ROT_RM8_1                   0xd0
81 #define X86_ROT_RM16_1                  0xd1
82 #define X86_ROT_RM8_CL                  0xd2
83 #define X86_ROT_RM16_CL                 0xd3
84 #define X86_JMP_16                      0xe9
85 #define X86_JMP_8                       0xeb
86 #define X86_REPNE                       0xf2
87 #define X86_REPE                        0xf3
88 #define X86_F6                          0xf6
89 #define  X86_F6_TEST_RM8_IMM8                   0x0
90 #define  X86_F6_NOT_RM8                         0x2
91 #define  X86_F6_NEG_RM8                         0x3
92 #define  X86_F6_MUL_RM8                         0x4
93 #define  X86_F6_IMUL_RM8                        0x5
94 #define  X86_F6_DIV_RM8                         0x6
95 #define  X86_F6_IDIV_RM8                        0x7
96 #define X86_F7                          0xf7
97 #define  X86_F7_TEST_RM16_IMM16                 0x0
98 #define  X86_F7_NOT_RM16                        0x2
99 #define  X86_F7_NEG_RM16                        0x3
100 #define  X86_F7_MUL_RM16                        0x4
101 #define  X86_F7_IMUL_RM16                       0x5
102 #define  X86_F7_DIV_RM16                        0x6
103 #define  X86_F7_IDIV_RM16                       0x7
104 #define X86_FE                          0xfe
105 #define  X86_FE_INC_RM8                         0x0
106 #define  X86_FE_DEC_RM8                         0x1
107 #define X86_FF                          0xff
108 #define  X86_FF_INC_RM16                        0x0
109 #define  X86_FF_DEC_RM16                        0x1
110 #define  X86_FF_CALL_INDIRECT                   0x2
111 #define  X86_FF_JMP_INDIRECT                    0x4
112 #define  X86_FF_PUSH                            0x6
114 #define X86_0F_MOVSS_X128_M32           0x10
115 #define X86_0F_MOVSS_M32_X128           0x11
116 #define X86_0F_MOVAPS_X128_M128         0x28
117 #define X86_0F_MOVAPS_M128_X128         0x29
118 #define X86_0F_CVTSI2SS_X128_RM32       0x2a
119 #define X86_0F_CVTTSS2SI_X128_RM32      0x2c
120 #define X86_0F_UCOMISS_X128_RM32        0x2e
121 #define X86_0F_38                       0x38
122 #define X86_0F_3A                       0x3a
123 #define X86_0F_CMOVCC_R16_RM16          0x40
124 #define X86_0F_SQRTPS_X128_M32          0x51
125 #define X86_0F_ANDPS_X128_M128          0x54
126 #define X86_0F_ANDNPS_X128_M128         0x55
127 #define X86_0F_ORPS_X128_M128           0x56
128 #define X86_0F_XORPS_X128_M128          0x57
129 #define X86_0F_ADDPS_X128_M32           0x58
130 #define X86_0F_MULPS_X128_M32           0x59
131 #define X86_0F_SUBPS_X128_M32           0x5c
132 #define X86_0F_DIVPS_X128_M32           0x5e
133 #define X86_0F_JCC_16                   0x80
134 #define X86_0F_SETCC_RM8                0x90
135 #define X86_0F_BT_RM16_R16              0xa3
136 #define X86_0F_BTS_RM16_R16             0xab
137 #define X86_0F_BTR_RM16_R16             0xb3
138 #define X86_0F_BTX_RM16_IMM8            0xba
139 #define  X86_0F_BTX_BT_RM16_IMM8                0x4
140 #define  X86_0F_BTX_BTS_RM16_IMM8               0x5
141 #define  X86_0F_BTX_BTR_RM16_IMM8               0x6
142 #define  X86_0F_BTX_BTC_RM16_IMM8               0x7
143 #define X86_0F_BSWAP                    0xc8
144 #define X86_0F_BTC_RM16_R16             0xbb
145 #define X86_0F_IMUL_R16_RM16            0xaf
146 #define X86_0F_MOVZX_R16_RM8            0xb6
147 #define X86_0F_MOVZX_R16_RM16           0xb7
148 #define X86_0F_POPCNT_R16_RM16          0xb8
149 #define X86_0F_BSF_R16_RM16             0xbc
150 #define X86_0F_BSR_R16_RM16             0xbd
151 #define X86_0F_MOVSX_R16_RM8            0xbe
152 #define X86_0F_MOVSX_R16_RM16           0xbf
153 #define X86_0F_PINSRW_X128_RM16_IMM8    0xc4
155 #define X86_0F_38_CVTPH2PS_X128_RM64    0x13
156 #define X86_0F_38_ROTX                  0xf7
158 #define X86_0F_3A_ROUNDSS_X128_M32      0x0a
159 #define X86_0F_3A_ROUNDSD_X128_M64      0x0b
160 #define X86_0F_3A_PEXTRW_RM16_X128_IMM8 0x15
161 #define X86_0F_3A_CVTPS2PH_RM64_X128    0x1d
163 #define X87_FLD_RM32                    0xd9
164 #define  X87_FLD_RM32_X                         0x0
165 #define X87_FLDCW                       0xd9
166 #define  X87_FLDCW_X                            0x5
167 #define X87_FILD_M32                    0xdb
168 #define  X87_FILD_M32_X                         0x0
169 #define X87_FISTTP_M32                  0xdb
170 #define  X87_FISTTP_M32_X                       0x1
171 #define X87_FISTP_M32                   0xdb
172 #define  X87_FISTP_M32_X                        0x3
173 #define X87_FLD_M80                     0xdb
174 #define  X87_FLD_M80_X                          0x5
175 #define X87_FLD_M64                     0xdd
176 #define  X87_FLD_M64_X                          0x0
177 #define X87_FSTP_M32                    0xd9
178 #define  X87_FSTP_M32_X                         0x3
179 #define X87_FSTP_M80                    0xdb
180 #define  X87_FSTP_M80_X                         0x7
181 #define X87_FSTP_RM64                   0xdd
182 #define  X87_FSTP_RM64_X                        0x3
183 #define X87_FALU_ST_RM32                0xd8
184 #define X87_FCHS                        0xd9
185 #define  X87_FCHS_2                             0xe0
186 #define X87_FSQRT                       0xd9
187 #define  X87_FSQRT_2                            0xfa
188 #define X87_FRNDINT                     0xd9
189 #define  X87_FRNDINT_2                          0xfc
190 #define X87_FALU_ST_M64                 0xdc
191 #define X87_FALU_STi_ST                 0xdc
192 #define X87_FISTTP_M64                  0xdd
193 #define  X87_FISTTP_M64_X                       0x1
194 #define X87_FALUP_STi_ST0               0xde
195 #define  X87_ALU_ADD                            0x0
196 #define  X87_ALU_MUL                            0x1
197 #define  X87_ALU_FCOM                           0x2
198 #define  X87_ALU_FCOMP                          0x3
199 #define  X87_ALU_SUBR                           0x4
200 #define  X87_ALU_SUB                            0x5
201 #define  X87_ALU_DIVR                           0x6
202 #define  X87_ALU_DIV                            0x7
203 #define X87_FCOMPP                      0xde
204 #define  X87_FCOMPP_2                           0xd9
205 #define X87_FILD_M16                    0xdf
206 #define  X87_FILD_M16_X                         0x0
207 #define X87_FISTTP_M16                  0xdf
208 #define  X87_FISTTP_M16_X                       0x1
209 #define X87_FISTP_M16                   0xdf
210 #define  X87_FISTP_M16_X                        0x3
211 #define X87_FILD_M64                    0xdf
212 #define  X87_FILD_M64_X                         0x5
213 #define X87_FISTP_M64                   0xdf
214 #define  X87_FISTP_M64_X                        0x7
215 #define X87_FNSTSW                      0xdf
216 #define  X87_FNSTSW_2                           0xe0
217 #define X87_FCOMIP                      0xdf
218 #define  X87_FCOMIP_2                           0xf0
220 #define SSE_PREFIX_NONE                 0
221 #define SSE_PREFIX_66                   1
222 #define SSE_PREFIX_F3                   2
223 #define SSE_PREFIX_F2                   3
225 #define PREFIX_NONE                     0
226 #define PREFIX_0F                       1
227 #define PREFIX_0F_38                    2
228 #define PREFIX_0F_3A                    3
230 #ifdef ARCH_X86_32
231 #define cgen_rex(rex)           internal(file_line, "cgen_rex: attempting to generate rex in 32-bit mode: %02x", rex)
232 #else
233 #define cgen_rex(rex)           cgen_one(rex)
234 #endif
236 static bool attr_w cgen_rm_insn(struct codegen_context *ctx, int16_t sse_prefix, uint8_t prefix, uint8_t opcode, unsigned size, bool reg_is_reg, uint8_t reg, uint8_t *arg)
238         uint8_t rex, mod, rm;
239         int16_t sib;
240         int64_t imm = 0;        /* avoid warning */
241         uint8_t addr_size;
242         uint8_t arg_reg;
244         if (unlikely(R_IS_XMM(reg)))
245                 reg -= R_XMM0;
246         if (unlikely(R_IS_XMM(arg[0]))) {
247                 arg_reg = arg[0] - R_XMM0;
248                 arg = &arg_reg;
249         }
250         if (unlikely(!R_IS_GPR(reg)))
251                 internal(file_line, "cgen_rm_insn: invalid register %02x", reg);
253         sib = -1;
254         rex = X86_REX;
255         if (size == OP_SIZE_8)
256                 rex |= X86_REX_W;
257         if (reg & 8)
258                 rex |= X86_REX_R;
259         if (arg[0] < 0x40) {
260                 if (arg[0] & 8)
261                         rex |= X86_REX_B;
262                 mod = 0xc0;
263                 rm = arg[0] & 7;
264                 addr_size = 0;
265         } else {
266                 uint8_t *imm_ptr = arg + arg_size(arg[0]) - 8;
267                 imm = get_imm(imm_ptr);
268                 if (unlikely(!imm_is_32bit(imm)))
269                         internal(file_line, "cgen_rm_insn: immediate out of range: %"PRIxMAX"", (uintmax_t)imm);
270                 if (arg[0] == ARG_ADDRESS_0) {
271 address_0:
272                         addr_size = 4;
273                         mod = 0x00;
274                         rm = 0x4;
275                         sib = 0x25;
276                         goto gen;
277                 }
278                 if (!imm) {
279                         addr_size = 0;
280                 } else if (imm >= -0x80 && imm <= 0x7f) {
281                         addr_size = 1;
282                 } else {
283                         addr_size = 4;
284                 }
285                 if ((arg[1] & 7) == 0x5 && addr_size == 0)
286                         addr_size = 1;
287                 if (addr_size == 0)
288                         mod = 0x00;
289                 else if (addr_size == 1)
290                         mod = 0x40;
291                 else
292                         mod = 0x80;
293                 if (arg[0] == ARG_ADDRESS_1) {
294                         if (reg_is_segment(arg[1])) {
295                                 static const uint8_t segments[6] = { X86_ES, X86_CS, X86_SS, X86_DS, X86_FS, X86_GS };
296                                 cgen_one(segments[arg[1] - R_ES]);
297                                 goto address_0;
298                         }
299                         if (arg[1] & 8)
300                                 rex |= X86_REX_B;
301                         if ((arg[1] & 7) == 0x4) {
302                                 rm = 0x4;
303                                 sib = 0x24;
304                                 goto gen;
305                         }
306                         rm = arg[1] & 7;
307                         goto gen;
308                 }
309                 if (arg[0] >= ARG_ADDRESS_1_2 && arg[0] <= ARG_ADDRESS_1_8) {
310                         if (unlikely(arg[1] == R_SP))
311                                 internal(file_line, "cgen_rm_insn: attemptint to scale SP");
312                         if (arg[1] & 8)
313                                 rex |= X86_REX_X;
314                         addr_size = 4;
315                         mod = 0x00;
316                         rm = 0x4;
317                         sib = ((arg[0] - ARG_ADDRESS_1) << 6) | ((arg[1] & 7) << 3) | 0x5;
318                         goto gen;
319                 }
320                 if (arg[0] >= ARG_ADDRESS_2 && arg[0] <= ARG_ADDRESS_2_8) {
321                         if (unlikely(arg[2] == R_SP))
322                                 internal(file_line, "cgen_rm_insn: attemptint to scale SP");
323                         if (arg[1] & 8)
324                                 rex |= X86_REX_B;
325                         if (arg[2] & 8)
326                                 rex |= X86_REX_X;
327                         rm = 0x4;
328                         sib = ((arg[0] - ARG_ADDRESS_2) << 6) | ((arg[2] & 7) << 3) | (arg[1] & 7);
329                         goto gen;
330                 }
331                 internal(file_line, "cgen_rm_insn: invalid argument %02x", arg[0]);
332         }
334 gen:
335         if (unlikely(sse_prefix >= 0)) {
336                 if (likely(cpu_test_feature(CPU_FEATURE_avx)) || (sse_prefix & 0x4000)) {
337                         if ((rex & (X86_REX_X | X86_REX_B | X86_REX_W)) == 0 && prefix == PREFIX_0F) {
338                                 cgen_one(X86_VEX_2);
339                                 cgen_one((~rex & X86_REX_R) << 5 | (~(sse_prefix >> 8) & 0xf) << 3 | (sse_prefix & 3));
340                         } else {
341                                 cgen_one(X86_VEX_3);
342                                 cgen_one((~rex & (X86_REX_R | X86_REX_X | X86_REX_B)) << 5 | prefix);
343                                 cgen_one((rex & X86_REX_W) << 4 | (~(sse_prefix >> 8) & 0xf) << 3 | (sse_prefix & 3));
344                         }
345                         goto avx_done;
346                 }
347                 switch (sse_prefix & 3) {
348                         case SSE_PREFIX_66:     cgen_one(X86_OP_SIZE); break;
349                         case SSE_PREFIX_F3:     cgen_one(X86_REPE); break;
350                         case SSE_PREFIX_F2:     cgen_one(X86_REPNE); break;
351                 }
352         } else {
353                 if (size == OP_SIZE_2)
354                         cgen_one(X86_OP_SIZE);
355         }
356         if (rex != X86_REX || (size == OP_SIZE_1 && ((reg_is_reg && !reg_is_fp(reg) && reg >= 4) || (mod == 0xc0 && !reg_is_fp(arg[0]) && arg[0] >= 4))))
357                 cgen_rex(rex);
359         switch (prefix) {
360                 case PREFIX_NONE:
361                         break;
362                 case PREFIX_0F:
363                         cgen_one(X86_0F);
364                         break;
365                 case PREFIX_0F_38:
366                         cgen_one(X86_0F);
367                         cgen_one(X86_0F_38);
368                         break;
369                 case PREFIX_0F_3A:
370                         cgen_one(X86_0F);
371                         cgen_one(X86_0F_3A);
372                         break;
373                 default:
374                         internal(file_line, "cgen_rm_insn: invalid prefix %u", prefix);
375         }
376 avx_done:
377         cgen_one(opcode);
378         cgen_one(mod | ((reg & 7) << 3) | (rm & 7));
379         if (sib >= 0)
380                 cgen_one(sib);
381         switch (addr_size) {
382                 case 1:
383                         cgen_one(imm);
384                         break;
385                 case 4:
386                         cgen_four(imm);
387                         break;
388         }
389         return true;
392 static bool attr_w cgen_sse_insn(struct codegen_context *ctx, unsigned sse_prefix, unsigned sse_op_map, uint8_t opcode, bool wide, uint8_t reg, uint8_t reg2, uint8_t *arg)
394         g(cgen_rm_insn(ctx, sse_prefix + (reg2 << 8), sse_op_map, opcode, !wide ? OP_SIZE_4 : OP_SIZE_8, true, reg, arg));
395         return true;
398 static bool attr_w cgen_push(struct codegen_context *ctx)
400         uint8_t *arg1 = ctx->code_position;
401         ctx->code_position += arg_size(*arg1);
402         if (likely(R_IS_GPR(arg1[0]))) {
403                 if (arg1[0] & 8)
404                         cgen_rex(X86_REX | X86_REX_B);
405                 cgen_one(X86_PUSH_R16 + (arg1[0] & 7));
406                 return true;
407         }
408         if (arg1[0] == ARG_IMM) {
409                 int64_t imm;
410                 imm = get_imm(&arg1[1]);
411                 if (unlikely(!imm_is_32bit(imm)))
412                         internal(file_line, "cgen_push: immediate out of range: %"PRIxMAX"", (uintmax_t)imm);
413                 if (imm >= -0x80 && imm <= 0x7f) {
414                         cgen_one(X86_PUSH_IMM8);
415                         cgen_one(imm);
416                         return true;
417                 } else {
418                         cgen_one(X86_PUSH_IMM16);
419                         cgen_four(imm);
420                         return true;
421                 }
422         }
423         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, X86_FF, OP_SIZE_4, false, X86_FF_PUSH, arg1));
424         return true;
427 static bool attr_w cgen_pop(struct codegen_context *ctx)
429         uint8_t *arg1 = ctx->code_position;
430         ctx->code_position += arg_size(*arg1);
431         if (likely(R_IS_GPR(arg1[0]))) {
432                 if (arg1[0] & 8)
433                         cgen_rex(X86_REX | X86_REX_B);
434                 cgen_one(X86_POP_R16 + (arg1[0] & 7));
435                 return true;
436         }
437         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, X86_8F, OP_SIZE_4, false, X86_8F_POP, arg1));
438         return true;
441 static bool attr_w cgen_mov(struct codegen_context *ctx, unsigned size)
443         uint8_t *arg1 = ctx->code_position;
444         uint8_t *arg2 = arg1 + arg_size(*arg1);
445         ctx->code_position = arg2 + arg_size(*arg2);
446         if (arg2[0] == ARG_IMM) {
447                 int rex = X86_REX;
448                 int64_t imm;
449                 imm = get_imm(&arg2[1]);
450                 if (R_IS_GPR(arg1[0])) {
451                         if (arg1[0] & 8)
452                                 rex |= X86_REX_B;
453 #ifndef ARCH_X86_32
454                         if (imm >= 0 && imm < 0x100000000LL)
455 #endif
456                         {
457                                 if (rex != X86_REX)
458                                         cgen_rex(rex);
459                                 cgen_one(X86_MOV_R16_IMM16 + (arg1[0] & 7));
460                                 cgen_four(imm);
461                                 return true;
462                         }
463                         if (imm >= ~(int64_t)0x7fffffff && imm < 0) {
464                                 goto mov_rm;
465                         }
466                         rex |= X86_REX_W;
467                         cgen_rex(rex);
468                         cgen_one(X86_MOV_R16_IMM16 + (arg1[0] & 7));
469                         cgen_eight(imm);
470                         return true;
471                 } else {
472                         if (size < OP_SIZE_4) {
473                                 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, size == OP_SIZE_1 ? X86_MOV_RM8_IMM8 : X86_MOV_RM16_IMM16, size, false, X86_MOV_R16_IMM16_REG, arg1));
474                                 if (size == OP_SIZE_1)
475                                         cgen_one(imm);
476                                 else
477                                         cgen_two(imm);
478                                 return true;
479                         }
480 mov_rm:
481                         if (unlikely(!imm_is_32bit(imm)))
482                                 internal(file_line, "cgen_mov: immediate out of range: %"PRIxMAX"", (uintmax_t)imm);
483                         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, X86_MOV_RM16_IMM16, maximum(size, OP_SIZE_4), false, X86_MOV_R16_IMM16_REG, arg1));
484                         cgen_four(imm);
485                         return true;
486                 }
487         }
488         if (arg1[0] == R_AX && size >= OP_SIZE_4 && arg2[0] == ARG_ADDRESS_0) {
489                 int64_t imm;
490                 imm = get_imm(&arg2[1]);
491                 if (size == OP_SIZE_8)
492                         cgen_rex(X86_REX | X86_REX_W);
493                 cgen_one(X86_MOV_AX_M16);
494                 cgen_eight(imm);
495                 return true;
496         }
497         if (arg1[0] == ARG_ADDRESS_0 && arg2[0] == R_AX) {
498                 uint8_t code = size == OP_SIZE_1 ? X86_MOV_M16_AL : X86_MOV_M16_AX;
499                 int64_t imm;
500                 imm = get_imm(&arg1[1]);
501                 if (size == OP_SIZE_2)
502                         cgen_one(X86_OP_SIZE);
503                 if (size == OP_SIZE_8)
504                         cgen_rex(X86_REX | X86_REX_W);
505                 cgen_one(code);
506                 cgen_eight(imm);
507                 return true;
508         }
509         if (R_IS_XMM(arg1[0]) && ARG_IS_ADDRESS(arg2[0])) {
510                 if (size == OP_SIZE_2) {
511                         g(cgen_sse_insn(ctx, SSE_PREFIX_66, PREFIX_0F, X86_0F_PINSRW_X128_RM16_IMM8, false, arg1[0], R_XMM7, arg2));
512                         cgen_one(0x00);
513                         return true;
514                 }
515                 if (size == OP_SIZE_16) {
516                         g(cgen_sse_insn(ctx, SSE_PREFIX_NONE, PREFIX_0F, X86_0F_MOVAPS_X128_M128, false, arg1[0], 0, arg2));
517                         return true;
518                 }
519                 g(cgen_sse_insn(ctx, size == OP_SIZE_4 ? SSE_PREFIX_F3 : SSE_PREFIX_F2, PREFIX_0F, X86_0F_MOVSS_X128_M32, false, arg1[0], 0, arg2));
520                 return true;
521         }
522         if (ARG_IS_ADDRESS(arg1[0]) && R_IS_XMM(arg2[0])) {
523                 if (size == OP_SIZE_2) {
524                         g(cgen_sse_insn(ctx, SSE_PREFIX_66, PREFIX_0F_3A, X86_0F_3A_PEXTRW_RM16_X128_IMM8, false, arg2[0], 0, arg1));
525                         cgen_one(0x00);
526                         return true;
527                 }
528                 if (size == OP_SIZE_16) {
529                         g(cgen_sse_insn(ctx, SSE_PREFIX_NONE, PREFIX_0F, X86_0F_MOVAPS_M128_X128, false, arg2[0], 0, arg1));
530                         return true;
531                 }
532                 g(cgen_sse_insn(ctx, size == OP_SIZE_4 ? SSE_PREFIX_F3 : SSE_PREFIX_F2, PREFIX_0F, X86_0F_MOVSS_M32_X128, false, arg2[0], 0, arg1));
533                 return true;
534         }
535         if (R_IS_XMM(arg1[0]) && R_IS_XMM(arg2[0])) {
536                 g(cgen_sse_insn(ctx, SSE_PREFIX_NONE, PREFIX_0F, X86_0F_MOVAPS_X128_M128, false, arg1[0], 0, arg2));
537                 return true;
538         }
539         if (!R_IS_GPR(arg1[0]) && unlikely(!R_IS_GPR(arg2[0]))) {
540                 /*debug("%s", da(ctx->fn,function)->function_name);*/
541                 internal(file_line, "cgen_mov: two addresses not supported");
542         }
543         if (!R_IS_GPR(arg1[0])) {
544                 uint8_t code = size == OP_SIZE_1 ? X86_MOV_RM8_R8 : X86_MOV_RM16_R16;
545                 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, code, size, true, arg2[0], arg1));
546                 return true;
547         } else if (size >= OP_SIZE_4) {
548                 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, X86_MOV_R16_RM16, size, true, arg1[0], arg2));
549                 return true;
550         } else {
551                 uint8_t code = size == OP_SIZE_1 ? X86_0F_MOVZX_R16_RM8 : X86_0F_MOVZX_R16_RM16;
552                 g(cgen_rm_insn(ctx, -1, PREFIX_0F, code, size, false, arg1[0], arg2));
553                 return true;
554         }
557 static bool attr_w cgen_movsx(struct codegen_context *ctx, unsigned size)
559         uint8_t *arg1, *arg2;
560         if (unlikely(size == OP_SIZE_NATIVE)) {
561                 g(cgen_mov(ctx, size));
562                 return true;
563         }
564         arg1 = ctx->code_position;
565         arg2 = arg1 + arg_size(*arg1);
566         ctx->code_position = arg2 + arg_size(*arg2);
567         if (size <= OP_SIZE_2) {
568                 g(cgen_rm_insn(ctx, -1, PREFIX_0F, size == OP_SIZE_1 ? X86_0F_MOVSX_R16_RM8 : X86_0F_MOVSX_R16_RM16, OP_SIZE_NATIVE, true, arg1[0], arg2));
569         } else {
570                 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, X86_MOVSXD, OP_SIZE_NATIVE, true, arg1[0], arg2));
571         }
572         return true;
575 static bool attr_w cgen_lea(struct codegen_context *ctx, unsigned size)
577         uint8_t addr[11];
578         uint8_t *arg1, *arg2, *arg3;
580         arg1 = ctx->code_position;
581         arg2 = arg1 + arg_size(*arg1);
582         arg3 = arg2 + arg_size(*arg2);
583         ctx->code_position = arg3 + arg_size(*arg3);
585         if (arg3[0] == ARG_IMM) {
586                 if (arg2[0] == ARG_SHIFTED_REGISTER) {
587                         if (unlikely((arg2[1] & ARG_SHIFT_MODE) != ARG_SHIFT_LSL) ||
588                             unlikely((arg2[1] & ARG_SHIFT_AMOUNT) > 3))
589                                 goto invalid;
590                         addr[0] = ARG_ADDRESS_1 + (arg2[1] & ARG_SHIFT_AMOUNT);
591                         addr[1] = arg2[2];
592                         memcpy(&addr[2], &arg3[1], 8);
593                 } else {
594                         addr[0] = ARG_ADDRESS_1;
595                         addr[1] = arg2[0];
596                         memcpy(&addr[2], &arg3[1], 8);
597                 }
598         } else if (R_IS_GPR(arg3[0])) {
599                 addr[0] = ARG_ADDRESS_2;
600                 addr[1] = arg2[0];
601                 addr[2] = arg3[0];
602                 memset(&addr[3], 0, 8);
603         } else if (arg3[0] == ARG_SHIFTED_REGISTER) {
604                 if (unlikely((arg3[1] & ARG_SHIFT_MODE) != ARG_SHIFT_LSL) ||
605                     unlikely((arg3[1] & ARG_SHIFT_AMOUNT) > 3))
606                         goto invalid;
607                 addr[0] = ARG_ADDRESS_2 + (arg3[1] & ARG_SHIFT_AMOUNT);
608                 addr[1] = arg2[0];
609                 addr[2] = arg3[2];
610                 memset(&addr[3], 0, 8);
611         } else {
612 invalid:
613                 internal(file_line, "cgen_lea: invalid argument %02x, %02x, %02x", arg1[0], arg2[0], arg3[0]);
614         }
615         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, X86_LEA_R16_RM16, size, true, arg1[0], addr));
616         return true;
619 static bool attr_w cgen_alu(struct codegen_context *ctx, unsigned size, unsigned alu)
621         uint8_t *arg1, *arg2, *arg3;
622         if (alu != 7) {
623                 arg1 = ctx->code_position;
624                 arg2 = arg1 + arg_size(*arg1);
625                 arg3 = arg2 + arg_size(*arg2);
626                 ctx->code_position = arg3 + arg_size(*arg3);
627                 if (unlikely(arg_size(*arg1) != arg_size(*arg2)))
628                         internal(file_line, "cgen_alu: three-operand mode not supported");
629                 if (unlikely(memcmp(arg1, arg2, arg_size(*arg1))))
630                         internal(file_line, "cgen_alu: three-operand mode not supported");
631         } else {
632                 arg1 = ctx->code_position;
633                 arg2 = arg1;
634                 arg3 = arg2 + arg_size(*arg2);
635                 ctx->code_position = arg3 + arg_size(*arg3);
636         }
638         if (unlikely(alu == ALU_MUL)) {
639                 if (unlikely(arg3[0] == ARG_IMM)) {
640                         uint8_t code;
641                         int64_t imm;
642                         imm = get_imm(&arg3[1]);
643                         if (unlikely(!imm_is_32bit(imm)))
644                                 internal(file_line, "cgen_alu: immediate out of range: %"PRIxMAX"", (uintmax_t)imm);
645                         code = imm_is_8bit(imm) ? X86_IMUL_R16_RM16_IMM8 : X86_IMUL_R16_RM16_IMM16;
646                         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, code, size, true, arg1[0], arg2));
647                         if (code == X86_IMUL_R16_RM16_IMM8) {
648                                 cgen_one(imm);
649                         } else if (size == OP_SIZE_2) {
650                                 cgen_two(imm);
651                         } else {
652                                 cgen_four(imm);
653                         }
654                         return true;
655                 }
656                 if (unlikely(size == OP_SIZE_1)) {
657                         if (unlikely(arg1[0] != R_AX))
658                                 internal(file_line, "cgen_alu: imul with unsupported register");
659                         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, X86_F6, size, false, X86_F6_IMUL_RM8, arg3));
660                         return true;
661                 } else {
662                         if (unlikely(!R_IS_GPR(arg1[0])))
663                                 internal(file_line, "cgen_alu: invalid multiply args");
664                         g(cgen_rm_insn(ctx, -1, PREFIX_0F, X86_0F_IMUL_R16_RM16, size, true, arg1[0], arg3));
665                         return true;
666                 }
667         }
669         if (arg3[0] == ARG_IMM) {
670                 uint8_t code;
671                 bool bit8;
672                 int64_t imm;
673                 imm = get_imm(&arg3[1]);
674                 if (unlikely(!imm_is_32bit(imm)))
675                         internal(file_line, "cgen_alu: immediate out of range: %"PRIxMAX"", (uintmax_t)imm);
677                 if (arg1[0] == R_AX) {
678                         if (imm_is_8bit(imm) && size >= OP_SIZE_4)
679                                 goto use_shorter;
680                         bit8 = false;
681                         code = size == OP_SIZE_1 ? X86_ALU_AL_IMM8 : X86_ALU_AX_IMM16;
682                         if (size == OP_SIZE_2)
683                                 cgen_one(X86_OP_SIZE);
684                         if (size == OP_SIZE_8)
685                                 cgen_rex(X86_REX | X86_REX_W);
686                         code += alu * 8;
687                         cgen_one(code);
688                 } else {
689 use_shorter:
690                         bit8 = imm_is_8bit(imm);
691                         code = size == OP_SIZE_1 ? X86_ALU_RM8_IMM8 : bit8 ? X86_ALU_RM16_IMM8 : X86_ALU_RM16_IMM16;
692                         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, code, size, false, alu, arg1));
693                 }
694                 if (bit8 || size == OP_SIZE_1) {
695                         cgen_one(imm);
696                 } else if (size == OP_SIZE_2) {
697                         cgen_two(imm);
698                 } else {
699                         cgen_four(imm);
700                 }
701                 return true;
702         }
704         if (R_IS_XMM(arg1[0]) && size == OP_SIZE_16) {
705                 uint8_t code;
706                 switch (alu) {
707                         case ALU_AND:   code = X86_0F_ANDPS_X128_M128; break;
708                         case ALU_ANDN:  code = X86_0F_ANDNPS_X128_M128; break;
709                         case ALU_OR:    code = X86_0F_ORPS_X128_M128; break;
710                         case ALU_XOR:   code = X86_0F_XORPS_X128_M128; break;
711                         default:        internal(file_line, "invalid sse alu: %u", alu);
712                 }
713                 g(cgen_sse_insn(ctx, SSE_PREFIX_NONE, PREFIX_0F, code, false, arg1[0], arg2[0], arg3));
714                 return true;
715         }
717         if (!R_IS_GPR(arg1[0]) && unlikely(!R_IS_GPR(arg3[0])))
718                 internal(file_line, "cgen_alu: two addresses not supported");
720         if (!R_IS_GPR(arg1[0])) {
721                 uint8_t code = size == OP_SIZE_1 ? X86_ALU_RM8_R8 : X86_ALU_RM16_R16;
722                 code += alu * 8;
723                 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, code, size, true, arg3[0], arg1));
724                 return true;
725         } else {
726                 uint8_t code = size == OP_SIZE_1 ? X86_ALU_R8_RM8 : X86_ALU_R16_RM16;
727                 code += alu * 8;
728                 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, code, size, true, arg1[0], arg3));
729                 return true;
730         }
733 static bool attr_w cgen_alu1(struct codegen_context *ctx, unsigned size, unsigned alu, unsigned writes_flags)
735         uint8_t rex;
736         uint8_t *arg1 = ctx->code_position;
737         uint8_t *arg2 = arg1 + arg_size(*arg1);
738         ctx->code_position = arg2 + arg_size(*arg2);
739         if (alu == ALU1_NOT || alu == ALU1_NEG || alu == ALU1_INC || alu == ALU1_DEC || alu == ALU1_BSWAP) {
740                 if (unlikely(arg1[0] != arg2[0]))
741                         internal(file_line, "cgen_alu1: arguments mismatch");
742         }
743         switch (alu) {
744                 case ALU1_NOT:
745                         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, size == OP_SIZE_1 ? X86_F6 : X86_F7, size, false, X86_F6_NOT_RM8, arg1));
746                         return true;
747                 case ALU1_NEG:
748                         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, size == OP_SIZE_1 ? X86_F6 : X86_F7, size, false, X86_F6_NEG_RM8, arg1));
749                         return true;
750                 case ALU1_INC:
751                         if (writes_flags & 2) {
752                                 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, size == OP_SIZE_1 ? X86_ALU_RM8_IMM8 : X86_ALU_RM16_IMM8, size, false, ALU_ADD, arg1));
753                                 cgen_one(1);
754                                 return true;
755                         }
756 #ifdef ARCH_X86_32
757                         if (R_IS_GPR(arg1[0]) && size >= OP_SIZE_2) {
758                                 if (size == OP_SIZE_2)
759                                         cgen_one(X86_OP_SIZE);
760                                 cgen_one(X86_INC_R16 + arg1[0]);
761                                 return true;
762                         }
763 #endif
764                         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, size == OP_SIZE_1 ? X86_FE : X86_FF, size, false, X86_FE_INC_RM8, arg1));
765                         return true;
766                 case ALU1_DEC:
767                         if (writes_flags & 2) {
768                                 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, size == OP_SIZE_1 ? X86_ALU_RM8_IMM8 : X86_ALU_RM16_IMM8, size, false, ALU_SUB, arg1));
769                                 cgen_one(1);
770                                 return true;
771                         }
772 #ifdef ARCH_X86_32
773                         if (R_IS_GPR(arg1[0]) && size >= OP_SIZE_2) {
774                                 if (size == OP_SIZE_2)
775                                         cgen_one(X86_OP_SIZE);
776                                 cgen_one(X86_DEC_R16 + arg1[0]);
777                                 return true;
778                         }
779 #endif
780                         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, size == OP_SIZE_1 ? X86_FE : X86_FF, size, false, X86_FE_DEC_RM8, arg1));
781                         return true;
782                 case ALU1_BSWAP:
783                         if (unlikely(size <= OP_SIZE_2))
784                                 internal(file_line, "cgen_alu1: bytes or words not supported with this operation");
785                         rex = X86_REX;
786                         if (!R_IS_GPR(arg1[0]))
787                                 internal(file_line, "cgen_alu1: bswap needs a register");
788                         if (arg1[0] & 8)
789                                 rex |= X86_REX_B;
790                         if (size == OP_SIZE_8)
791                                 rex |= X86_REX_W;
792                         if (rex != X86_REX)
793                                 cgen_rex(rex);
794                         cgen_one(X86_0F);
795                         cgen_one(X86_0F_BSWAP + (arg1[0] & 7));
796                         return true;
797                 case ALU1_BSF:
798                 case ALU1_BSR:
799                 case ALU1_LZCNT:
800                 case ALU1_POPCNT:
801                         if (unlikely(size == OP_SIZE_1))
802                                 internal(file_line, "cgen_alu1: bytes not supported with this operation");
803                         if (alu == ALU1_POPCNT || alu == ALU1_LZCNT)
804                                 cgen_one(X86_REPE);
805                         g(cgen_rm_insn(ctx, -1, PREFIX_0F, alu == ALU1_BSF ? X86_0F_BSF_R16_RM16 : alu == ALU1_BSR || alu == ALU1_LZCNT ? X86_0F_BSR_R16_RM16 : X86_0F_POPCNT_R16_RM16, size, true, arg1[0], arg2));
806                         return true;
807                 default:
808                         internal(file_line, "cgen_alu1: invalid operation %u", alu);
809                         return false;
810         }
813 static bool attr_w cgen_test(struct codegen_context *ctx, unsigned size)
815         uint8_t *arg1, *arg2;
816         arg1 = ctx->code_position;
817         arg2 = arg1 + arg_size(*arg1);
818         ctx->code_position = arg2 + arg_size(*arg2);
820         if (arg2[0] == ARG_IMM) {
821                 int64_t imm;
822                 imm = get_imm(&arg2[1]);
823                 if (arg1[0] == R_AX) {
824                         if (size == OP_SIZE_1) {
825                                 cgen_one(X86_TEST_AL_IMM8);
826                         } else if (size == OP_SIZE_2) {
827                                 cgen_one(X86_OP_SIZE);
828                                 cgen_one(X86_TEST_AX_IMM16);
829                         } else if (size == OP_SIZE_4) {
830                                 cgen_one(X86_TEST_AX_IMM16);
831                         } else {
832                                 if (unlikely(!imm_is_32bit(imm)))
833                                         internal(file_line, "cgen_Test: immediate out of range: %"PRIxMAX"", (uintmax_t)imm);
834                                 cgen_rex(X86_REX | X86_REX_W);
835                                 cgen_one(X86_TEST_AX_IMM16);
836                         }
837                 } else {
838                         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, size == OP_SIZE_1 ? X86_F6 : X86_F7, size, false, X86_F6_TEST_RM8_IMM8, arg1));
839                 }
840                 if (size == OP_SIZE_1) {
841                         cgen_one(imm);
842                 } else if (size == OP_SIZE_2) {
843                         cgen_two(imm);
844                 } else if (size == OP_SIZE_4) {
845                         cgen_four(imm);
846                 } else {
847                         if (unlikely(!imm_is_32bit(imm)))
848                                 internal(file_line, "cgen_Test: immediate out of range: %"PRIxMAX"", (uintmax_t)imm);
849                         cgen_four(imm);
850                 }
851                 return true;
852         }
854         if (!R_IS_GPR(arg1[0]) && unlikely(!R_IS_GPR(arg2[0])))
855                 internal(file_line, "cgen_test: two addresses not supported");
857         if (!R_IS_GPR(arg1[0])) {
858                 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, size == OP_SIZE_1 ? X86_TEST_RM8_R8 : X86_TEST_RM16_R16, size, true, arg2[0], arg1));
859         } else {
860                 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, size == OP_SIZE_1 ? X86_TEST_RM8_R8 : X86_TEST_RM16_R16, size, true, arg1[0], arg2));
861         }
862         return true;
865 static bool attr_w cgen_lea3(struct codegen_context *ctx, unsigned size, unsigned shift)
867         uint8_t addr[11];
868         uint8_t *arg1, *arg2, *arg3, *arg4;
870         arg1 = ctx->code_position;
871         arg2 = arg1 + arg_size(*arg1);
872         arg3 = arg2 + arg_size(*arg2);
873         arg4 = arg3 + arg_size(*arg3);
874         ctx->code_position = arg4 + arg_size(*arg4);
876         if (unlikely(!R_IS_GPR(arg1[0])) || unlikely(!R_IS_GPR(arg2[0])) || unlikely(!R_IS_GPR(arg3[0])) || unlikely(arg4[0] != ARG_IMM))
877                 internal(file_line, "cgen_lea3: invalid arguments");
879         addr[0] = ARG_ADDRESS_2 + shift;
880         addr[1] = arg2[0];
881         addr[2] = arg3[0];
882         memcpy(&addr[3], &arg4[1], 8);
884         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, X86_LEA_R16_RM16, size, true, arg1[0], addr));
886         return true;
889 static bool attr_w cgen_rot(struct codegen_context *ctx, unsigned size, uint8_t rot, unsigned writes_flags)
891         uint8_t *arg1 = ctx->code_position;
892         uint8_t *arg2 = arg1 + arg_size(*arg1);
893         uint8_t *arg3 = arg2 + arg_size(*arg2);
894         ctx->code_position = arg3 + arg_size(*arg3);
896         if (cpu_test_feature(CPU_FEATURE_bmi2) && size >= OP_SIZE_4 && arg3[0] != ARG_IMM && !writes_flags && (rot == ROT_SHL || rot == ROT_SHR || rot == ROT_SAR)) {
897                 int16_t sse_prefix;
898                 switch (rot) {
899                         case ROT_SHL:   sse_prefix = SSE_PREFIX_66; break;
900                         case ROT_SAR:   sse_prefix = SSE_PREFIX_F3; break;
901                         case ROT_SHR:   sse_prefix = SSE_PREFIX_F2; break;
902                         default:        internal(file_line, "cgen_rot: invalid rotation %x", rot);
903                 }
904                 g(cgen_sse_insn(ctx, sse_prefix + 0x4000, PREFIX_0F_38, X86_0F_38_ROTX, size == OP_SIZE_8, arg1[0], arg3[0], arg2));
905                 return true;
906         }
908         if (arg1[0] != arg2[0])
909                 internal(file_line, "cgen_rot: invalid arguments: %x, %02x, %02x, %02x", rot, arg1[0], arg2[0], arg3[0]);
911         if (arg3[0] == R_CX) {
912                 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, size == OP_SIZE_1 ? X86_ROT_RM8_CL : X86_ROT_RM16_CL, size, false, rot, arg1));
913         } else if (likely(arg3[0] == ARG_IMM)) {
914                 int64_t imm;
915                 imm = get_imm(&arg1[3]);
916                 if (imm == 1) {
917                         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, size == OP_SIZE_1 ? X86_ROT_RM8_1 : X86_ROT_RM16_1, size, false, rot, arg1));
918                 } else {
919                         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, size == OP_SIZE_1 ? X86_ROT_RM8_IMM8 : X86_ROT_RM16_IMM8, size, false, rot, arg1));
920                         cgen_one(imm);
921                 }
922         } else {
923                 internal(file_line, "cgen_rot: invalid argument %02x", arg3[0]);
924         }
925         return true;
928 static bool attr_w cgen_btxt(struct codegen_context *ctx, unsigned size, uint8_t bt, uint8_t *arg1, uint8_t *arg2)
930         if (arg2[0] == ARG_IMM) {
931                 g(cgen_rm_insn(ctx, -1, PREFIX_0F, X86_0F_BTX_RM16_IMM8, size, false, X86_0F_BTX_BT_RM16_IMM8 + bt, arg1));
932                 cgen_one(arg2[1]);
933         } else {
934                 g(cgen_rm_insn(ctx, -1, PREFIX_0F, X86_0F_BT_RM16_R16 + bt * 8, size, true, arg2[0], arg1));
935         }
936         return true;
939 static bool attr_w cgen_bt(struct codegen_context *ctx, unsigned size)
941         uint8_t *arg1 = ctx->code_position;
942         uint8_t *arg2 = arg1 + arg_size(*arg1);
943         ctx->code_position = arg2 + arg_size(*arg2);
945         return cgen_btxt(ctx, size, BTX_BT, arg1, arg2);
948 static bool attr_w cgen_btx(struct codegen_context *ctx, unsigned size, uint8_t bt)
950         uint8_t *arg1 = ctx->code_position;
951         uint8_t *arg2 = arg1 + arg_size(*arg1);
952         uint8_t *arg3 = arg2 + arg_size(*arg2);
953         ctx->code_position = arg3 + arg_size(*arg3);
955         if (arg1[0] != arg2[0])
956                 internal(file_line, "cgen_btx: invalid arguments");
958         return cgen_btxt(ctx, size, bt, arg1, arg3);
961 static bool attr_w cgen_mul_l(struct codegen_context *ctx, unsigned size, bool sgn)
963         uint8_t *arg1, *arg2, *arg3, *arg4;
964         uint32_t reg_up;
965         arg1 = ctx->code_position;
966         arg2 = arg1 + arg_size(*arg1);
967         arg3 = arg2 + arg_size(*arg2);
968         arg4 = arg3 + arg_size(*arg3);
969         ctx->code_position = arg4 + arg_size(*arg4);
970         reg_up = size == OP_SIZE_1 ? R_AX : R_DX;
971         if (unlikely(arg1[0] != R_AX) || unlikely(arg2[0] != reg_up) || unlikely(arg3[0] != R_AX) || unlikely(arg4[0] == ARG_IMM))
972                 internal(file_line, "cgen_mul_l: invalid mul arguments");
974         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, size == OP_SIZE_1 ? X86_F6 : X86_F7, size, false, !sgn ? X86_F6_MUL_RM8 : X86_F6_IMUL_RM8, arg4));
975         return true;
978 static bool attr_w cgen_div_l(struct codegen_context *ctx, unsigned size, bool sgn)
980         uint8_t *arg1, *arg2, *arg3, *arg4, *arg5;
981         uint32_t reg_up;
982         arg1 = ctx->code_position;
983         arg2 = arg1 + arg_size(*arg1);
984         arg3 = arg2 + arg_size(*arg2);
985         arg4 = arg3 + arg_size(*arg3);
986         arg5 = arg4 + arg_size(*arg4);
987         ctx->code_position = arg5 + arg_size(*arg5);
988         reg_up = size == OP_SIZE_1 ? R_AX : R_DX;
989         if (unlikely(arg1[0] != R_AX) || unlikely(arg2[0] != reg_up) || unlikely(arg3[0] != R_AX) || unlikely(arg4[0] != reg_up) || unlikely(arg5[0] == ARG_IMM))
990                 internal(file_line, "cgen_div_l: invalid div arguments");
992         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, size == OP_SIZE_1 ? X86_F6 : X86_F7, size, false, !sgn ? X86_F6_DIV_RM8 : X86_F6_IDIV_RM8, arg5));
993         return true;
996 static bool attr_w cgen_cmov(struct codegen_context *ctx, unsigned size, unsigned cond)
998         uint8_t *arg1 = ctx->code_position;
999         uint8_t *arg2 = arg1 + arg_size(*arg1);
1000         uint8_t *arg3 = arg2 + arg_size(*arg2);
1001         ctx->code_position = arg3 + arg_size(*arg3);
1002         if (unlikely(arg1[0] != arg2[0]))
1003                 internal(file_line, "cgen_cmov: invalid arguments");
1004         g(cgen_rm_insn(ctx, -1, PREFIX_0F, X86_0F_CMOVCC_R16_RM16 + cond, size, true, arg1[0], arg3));
1005         return true;
1008 static bool attr_w cgen_memcpy(struct codegen_context *ctx)
1010         int64_t disp_dest, disp_src;
1011         uint8_t *arg1, *arg2, *arg3;
1012         arg1 = ctx->code_position;
1013         arg2 = arg1 + arg_size(*arg1);
1014         arg3 = arg2 + arg_size(*arg2);
1015         ctx->code_position = arg3 + arg_size(*arg3);
1016         if (unlikely(arg1[0] != ARG_ADDRESS_1_POST_I) || unlikely(arg2[0] != ARG_ADDRESS_1_POST_I) || unlikely(arg3[0] != R_CX))
1017                 goto invl;
1018         if (unlikely(arg1[1] != R_DI) || unlikely(arg2[1] != R_SI))
1019                 goto invl;
1020         disp_dest = get_imm(&arg1[2]);
1021         disp_src = get_imm(&arg2[2]);
1022         if (unlikely(disp_dest != 0) || unlikely(disp_src != 0))
1023                 goto invl;
1025         cgen_one(X86_REPE);
1026         cgen_one(X86_MOVSB);
1027         return true;
1029 invl:
1030         internal(file_line, "cgen_memcpy: invalid arguments %02x, %02x, %02x", *arg1, *arg2, *arg3);
1031         return false;
1034 static bool attr_w cgen_memset(struct codegen_context *ctx)
1036         int64_t disp_dest;
1037         uint8_t *arg1, *arg2, *arg3;
1038         arg1 = ctx->code_position;
1039         arg2 = arg1 + arg_size(*arg1);
1040         arg3 = arg2 + arg_size(*arg2);
1041         ctx->code_position = arg3 + arg_size(*arg3);
1042         if (unlikely(arg1[0] != ARG_ADDRESS_1_POST_I) || unlikely(arg2[0] != R_CX) || unlikely(arg3[0] != R_AX))
1043                 goto invl;
1044         if (unlikely(arg1[1] != R_DI))
1045                 goto invl;
1046         disp_dest = get_imm(&arg1[2]);
1047         if (unlikely(disp_dest != 0))
1048                 goto invl;
1050         cgen_one(X86_REPE);
1051         cgen_one(X86_STOSB);
1052         return true;
1054 invl:
1055         internal(file_line, "cgen_memset: invalid arguments %02x, %02x, %02x", *arg1, *arg2, *arg3);
1056         return false;
1059 static bool attr_w cgen_sse_cmp(struct codegen_context *ctx, unsigned size)
1061         uint8_t *arg1 = ctx->code_position;
1062         uint8_t *arg2 = arg1 + arg_size(*arg1);
1063         ctx->code_position = arg2 + arg_size(*arg2);
1064         g(cgen_sse_insn(ctx, size == OP_SIZE_4 ? SSE_PREFIX_NONE: SSE_PREFIX_66, PREFIX_0F, X86_0F_UCOMISS_X128_RM32, false, arg1[0], 0, arg2));
1065         return true;
1068 static bool attr_w cgen_sse_alu(struct codegen_context *ctx, unsigned size, unsigned alu)
1070         uint8_t opcode;
1071         uint8_t *arg1 = ctx->code_position;
1072         uint8_t *arg2 = arg1 + arg_size(*arg1);
1073         uint8_t *arg3 = arg2 + arg_size(*arg2);
1074         ctx->code_position = arg3 + arg_size(*arg3);
1075         switch (alu) {
1076                 case FP_ALU_ADD:        opcode = X86_0F_ADDPS_X128_M32; break;
1077                 case FP_ALU_SUB:        opcode = X86_0F_SUBPS_X128_M32; break;
1078                 case FP_ALU_MUL:        opcode = X86_0F_MULPS_X128_M32; break;
1079                 case FP_ALU_DIV:        opcode = X86_0F_DIVPS_X128_M32; break;
1080                 default:                internal(file_line, "cgen_sse_alu: invalid alu %u", alu);
1081         }
1082         g(cgen_sse_insn(ctx, size == OP_SIZE_4 ? SSE_PREFIX_F3 : SSE_PREFIX_F2, PREFIX_0F, opcode, false, arg1[0], arg2[0], arg3));
1083         return true;
1086 static bool attr_w cgen_sse_alu1(struct codegen_context *ctx, unsigned size, unsigned alu)
1088         uint8_t opcode;
1089         unsigned sse_pfx, sse_op_map;
1090         uint8_t *arg1 = ctx->code_position;
1091         uint8_t *arg2 = arg1 + arg_size(*arg1);
1092         ctx->code_position = arg2 + arg_size(*arg2);
1093         switch (alu) {
1094                 case FP_ALU1_SQRT:      if (size == OP_SIZE_4) {
1095                                                 sse_pfx = SSE_PREFIX_F3;
1096                                         } else if (size == OP_SIZE_8) {
1097                                                 sse_pfx = SSE_PREFIX_F2;
1098                                         } else {
1099                                                 goto fail;
1100                                         }
1101                                         sse_op_map = PREFIX_0F;
1102                                         opcode = X86_0F_SQRTPS_X128_M32;
1103                                         break;
1104                 case FP_ALU1_ROUND:
1105                 case FP_ALU1_FLOOR:
1106                 case FP_ALU1_CEIL:
1107                 case FP_ALU1_TRUNC:     sse_pfx = SSE_PREFIX_66;
1108                                         sse_op_map = PREFIX_0F_3A;
1109                                         if (size == OP_SIZE_4) {
1110                                                 opcode = X86_0F_3A_ROUNDSS_X128_M32;
1111                                         } else if (size == OP_SIZE_8) {
1112                                                 opcode = X86_0F_3A_ROUNDSD_X128_M64;
1113                                         } else {
1114                                                 goto fail;
1115                                         }
1116                                         break;
1117                 fail:
1118                 default:                internal(file_line, "cgen_sse_alu1: invalid alu %u, %u", alu, size);
1119         }
1120         g(cgen_sse_insn(ctx, sse_pfx, sse_op_map, opcode, false, arg1[0], arg1[0], arg2));
1121         if (OP_IS_ROUND(alu))
1122                 cgen_one(alu - FP_ALU1_ROUND);
1123         return true;
1126 static bool attr_w cgen_sse_from_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
1128         uint8_t *arg1 = ctx->code_position;
1129         uint8_t *arg2 = arg1 + arg_size(*arg1);
1130         ctx->code_position = arg2 + arg_size(*arg2);
1131         g(cgen_sse_insn(ctx, fp_op_size == OP_SIZE_4 ? SSE_PREFIX_F3 : SSE_PREFIX_F2, PREFIX_0F, X86_0F_CVTSI2SS_X128_RM32, int_op_size == OP_SIZE_8, arg1[0], R_XMM7, arg2));
1132         return true;
1135 static bool attr_w cgen_sse_to_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
1137         uint8_t *arg1 = ctx->code_position;
1138         uint8_t *arg2 = arg1 + arg_size(*arg1);
1139         ctx->code_position = arg2 + arg_size(*arg2);
1140         g(cgen_sse_insn(ctx, fp_op_size == OP_SIZE_4 ? SSE_PREFIX_F3 : SSE_PREFIX_F2, PREFIX_0F, X86_0F_CVTTSS2SI_X128_RM32, int_op_size == OP_SIZE_8, arg1[0], 0, arg2));
1141         return true;
1144 static bool attr_w cgen_sse_cvt(struct codegen_context *ctx, unsigned from_op_size, unsigned to_op_size)
1146         uint8_t *arg1 = ctx->code_position;
1147         uint8_t *arg2 = arg1 + arg_size(*arg1);
1148         ctx->code_position = arg2 + arg_size(*arg2);
1149         if (from_op_size == OP_SIZE_2 && to_op_size == OP_SIZE_4) {
1150                 g(cgen_sse_insn(ctx, SSE_PREFIX_66, PREFIX_0F_38, X86_0F_38_CVTPH2PS_X128_RM64, false, arg1[0], 0, arg2));
1151                 return true;
1152         } else if (from_op_size == OP_SIZE_4 && to_op_size == OP_SIZE_2) {
1153                 g(cgen_sse_insn(ctx, SSE_PREFIX_66, PREFIX_0F_3A, X86_0F_3A_CVTPS2PH_RM64_X128, false, arg2[0], 0, arg1));
1154                 cgen_one(0x04);
1155                 return true;
1156         }
1157         internal(file_line, "cgen_sse_cvt: unsupported arguments %u, %u", from_op_size, to_op_size);
1158         return false;
1161 static bool attr_w cgen_x87_fld(struct codegen_context *ctx, unsigned size)
1163         unsigned c1, c2;
1164         uint8_t *arg1 = ctx->code_position;
1165         ctx->code_position = arg1 + arg_size(*arg1);
1166         if (arg1[0] >= R_ST0 && arg1[0] <= R_ST7)
1167                 size = OP_SIZE_4;
1168         switch (size) {
1169                 case OP_SIZE_4:
1170                         c1 = X87_FLD_RM32; c2 = X87_FLD_RM32_X; break;
1171                 case OP_SIZE_8:
1172                         c1 = X87_FLD_M64; c2 = X87_FLD_M64_X; break;
1173                 case OP_SIZE_10:
1174                         c1 = X87_FLD_M80; c2 = X87_FLD_M80_X; break;
1175                 default:
1176                         internal(file_line, "cgen_x87_fld: invalid size %u", size);
1177         }
1178         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, c1, OP_SIZE_4, false, c2, arg1));
1179         return true;
1182 static bool attr_w cgen_x87_fild(struct codegen_context *ctx, unsigned size)
1184         unsigned c1, c2;
1185         uint8_t *arg1 = ctx->code_position;
1186         ctx->code_position = arg1 + arg_size(*arg1);
1187         switch (size) {
1188                 case OP_SIZE_2:
1189                         c1 = X87_FILD_M16; c2 = X87_FILD_M16_X; break;
1190                 case OP_SIZE_4:
1191                         c1 = X87_FILD_M32; c2 = X87_FILD_M32_X; break;
1192                 case OP_SIZE_8:
1193                         c1 = X87_FILD_M64; c2 = X87_FILD_M64_X; break;
1194                 default:
1195                         internal(file_line, "cgen_x87_fild: invalid size %u", size);
1196         }
1197         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, c1, OP_SIZE_4, false, c2, arg1));
1198         return true;
1201 static bool attr_w cgen_x87_fstp(struct codegen_context *ctx, unsigned size)
1203         unsigned c1, c2;
1204         uint8_t *arg1 = ctx->code_position;
1205         ctx->code_position = arg1 + arg_size(*arg1);
1206         if (arg1[0] >= R_ST0 && arg1[0] <= R_ST7)
1207                 size = OP_SIZE_8;
1208         switch (size) {
1209                 case OP_SIZE_4:
1210                         c1 = X87_FSTP_M32; c2 = X87_FSTP_M32_X; break;
1211                 case OP_SIZE_8:
1212                         c1 = X87_FSTP_RM64; c2 = X87_FSTP_RM64_X; break;
1213                 case OP_SIZE_10:
1214                         c1 = X87_FSTP_M80; c2 = X87_FSTP_M80_X; break;
1215                 default:
1216                         internal(file_line, "cgen_x87_fstp: invalid size %u", size);
1217         }
1218         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, c1, OP_SIZE_4, false, c2, arg1));
1219         return true;
1222 static bool attr_w cgen_x87_fistp(struct codegen_context *ctx, unsigned size)
1224         unsigned c1, c2;
1225         uint8_t *arg1 = ctx->code_position;
1226         ctx->code_position = arg1 + arg_size(*arg1);
1227         switch (size) {
1228                 case OP_SIZE_2:
1229                         c1 = X87_FISTP_M16; c2 = X87_FISTP_M16_X; break;
1230                 case OP_SIZE_4:
1231                         c1 = X87_FISTP_M32; c2 = X87_FISTP_M32_X; break;
1232                 case OP_SIZE_8:
1233                         c1 = X87_FISTP_M64; c2 = X87_FISTP_M64_X; break;
1234                 default:
1235                         internal(file_line, "cgen_x87_fistp: invalid size %u", size);
1236         }
1237         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, c1, OP_SIZE_4, false, c2, arg1));
1238         return true;
1241 static bool attr_w cgen_x87_fisttp(struct codegen_context *ctx, unsigned size)
1243         unsigned c1, c2;
1244         uint8_t *arg1 = ctx->code_position;
1245         ctx->code_position = arg1 + arg_size(*arg1);
1246         switch (size) {
1247                 case OP_SIZE_2:
1248                         c1 = X87_FISTTP_M16; c2 = X87_FISTTP_M16_X; break;
1249                 case OP_SIZE_4:
1250                         c1 = X87_FISTTP_M32; c2 = X87_FISTTP_M32_X; break;
1251                 case OP_SIZE_8:
1252                         c1 = X87_FISTTP_M64; c2 = X87_FISTTP_M64_X; break;
1253                 default:
1254                         internal(file_line, "cgen_x87_fisttp: invalid size %u", size);
1255         }
1256         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, c1, OP_SIZE_4, false, c2, arg1));
1257         return true;
1260 static bool attr_w cgen_x87_fcomp(struct codegen_context *ctx, unsigned size)
1262         unsigned c1, c2;
1263         uint8_t *arg1 = ctx->code_position;
1264         ctx->code_position = arg1 + arg_size(*arg1);
1265         if (arg1[0] < ARG_REGS_MAX) {
1266                 c1 = X87_FALU_ST_RM32;
1267         } else switch (size) {
1268                 case OP_SIZE_4:
1269                         c1 = X87_FALU_ST_RM32; break;
1270                 case OP_SIZE_8:
1271                         c1 = X87_FALU_ST_M64; break;
1272                 default:
1273                         internal(file_line, "cgen_x87_fcomp: invalid size %u", size);
1274         }
1275         c2 = X87_ALU_FCOMP;
1276         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, c1, OP_SIZE_4, false, c2, arg1));
1277         return true;
1280 static bool attr_w cgen_x87_alu(struct codegen_context *ctx, unsigned size, unsigned aux)
1282         unsigned c1, c2;
1283         uint8_t *arg1 = ctx->code_position;
1284         ctx->code_position = arg1 + arg_size(*arg1);
1285         if (arg1[0] < ARG_REGS_MAX) {
1286                 c1 = X87_FALU_ST_RM32;
1287         } else switch (size) {
1288                 case OP_SIZE_4:
1289                         c1 = X87_FALU_ST_RM32; break;
1290                 case OP_SIZE_8:
1291                         c1 = X87_FALU_ST_M64; break;
1292                 default:
1293                         internal(file_line, "cgen_x87_alu: invalid size %u", size);
1294         }
1295         switch (aux) {
1296                 case FP_ALU_ADD:
1297                         c2 = X87_ALU_ADD; break;
1298                 case FP_ALU_SUB:
1299                         c2 = X87_ALU_SUB; break;
1300                 case FP_ALU_MUL:
1301                         c2 = X87_ALU_MUL; break;
1302                 case FP_ALU_DIV:
1303                         c2 = X87_ALU_DIV; break;
1304                 default:
1305                         internal(file_line, "cgen_x87_fst: invalid operation %u", aux);
1306         }
1307         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, c1, OP_SIZE_4, false, c2, arg1));
1308         return true;
1311 static bool attr_w cgen_x87_alup(struct codegen_context *ctx, unsigned aux)
1313         unsigned c2;
1314         uint8_t *arg1 = ctx->code_position;
1315         ctx->code_position = arg1 + arg_size(*arg1);
1316         switch (aux) {
1317                 case FP_ALU_ADD:
1318                         c2 = X87_ALU_ADD; break;
1319                 case FP_ALU_SUB:
1320                         c2 = X87_ALU_SUB; break;
1321                 case FP_ALU_MUL:
1322                         c2 = X87_ALU_MUL; break;
1323                 case FP_ALU_DIV:
1324                         c2 = X87_ALU_DIV; break;
1325                 default:
1326                         internal(file_line, "cgen_x87_fstp: invalid operation %u", aux);
1327         }
1328         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, X87_FALUP_STi_ST0, OP_SIZE_4, false, c2, arg1));
1329         return true;
1332 static bool attr_w resolve_relocation(struct codegen_context *ctx, struct relocation *reloc)
1334         int64_t offs = (int64_t)ctx->label_to_pos[reloc->label_id] - (int64_t)(reloc->position + (reloc->length == JMP_SHORT ? 1 : 4));
1335         switch (reloc->length) {
1336                 case JMP_SHORT: {
1337                         int8_t i8;
1338                         if (!imm_is_8bit(offs))
1339                                 return false;
1340                         i8 = offs;
1341                         memcpy(ctx->mcode + reloc->position, &i8, 1);
1342                         return true;
1343                 }
1344                 case JMP_LONG: {
1345                         int32_t i32;
1346                         if (!imm_is_32bit(offs))
1347                                 return false;
1348                         i32 = offs;
1349                         memcpy(ctx->mcode + reloc->position, &i32, 4);
1350                         return true;
1351                 }
1352                 default: {
1353                         internal(file_line, "resolve_relocation: invalid relocation length %u", reloc->length);
1354                         return false;
1355                 }
1356         }
1359 static bool attr_w cgen_insn(struct codegen_context *ctx, uint32_t insn)
1361         uint8_t imm8;
1362         uint16_t imm16;
1363         /*debug("insn: %08x", insn);*/
1364         switch (insn_opcode(insn)) {
1365                 case INSN_ENTRY:
1366                         g(cgen_entry(ctx));
1367                         return true;
1368                 case INSN_LABEL:
1369                         g(cgen_label(ctx));
1370                         return true;
1371                 case INSN_RET:
1372                         cgen_one(X86_RET);
1373                         return true;
1374                 case INSN_RET_IMM:
1375                         imm16 = cget_two(ctx);
1376                         cgen_one(X86_RET_IMM16);
1377                         cgen_two(imm16);
1378                         return true;
1379                 case INSN_PUSH:
1380                         g(cgen_push(ctx));
1381                         return true;
1382                 case INSN_POP:
1383                         g(cgen_pop(ctx));
1384                         return true;
1385                 case INSN_CALL_INDIRECT:
1386                         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, X86_FF, OP_SIZE_4, false, X86_FF_CALL_INDIRECT, ctx->code_position));
1387                         ctx->code_position += arg_size(*ctx->code_position);
1388                         return true;
1389                 case INSN_MOV:
1390                         g(cgen_mov(ctx, insn_op_size(insn)));
1391                         return true;
1392                 case INSN_MOVSX:
1393                         g(cgen_movsx(ctx, insn_op_size(insn)));
1394                         return true;
1395                 case INSN_CMP:
1396                         g(cgen_alu(ctx, insn_op_size(insn), 7));
1397                         return true;
1398                 case INSN_TEST:
1399                         g(cgen_test(ctx, insn_op_size(insn)));
1400                         return true;
1401                 case INSN_ALU:
1402                 case INSN_ALU_FLAGS:
1403                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1404                                 goto invalid_insn;
1405                         if (!insn_writes_flags(insn) && insn_op_size(insn) <= OP_SIZE_8) {
1406                                 if (unlikely(insn_aux(insn) != ALU_ADD))
1407                                         goto invalid_insn;
1408                                 g(cgen_lea(ctx, insn_op_size(insn)));
1409                                 return true;
1410                         }
1411                         g(cgen_alu(ctx, insn_op_size(insn), insn_aux(insn)));
1412                         return true;
1413                 case INSN_ALU_PARTIAL:
1414                 case INSN_ALU_FLAGS_PARTIAL:
1415                         if (unlikely(insn_op_size(insn) >= OP_SIZE_4))
1416                                 goto invalid_insn;
1417                         g(cgen_alu(ctx, insn_op_size(insn), insn_aux(insn)));
1418                         return true;
1419                 case INSN_ALU1:
1420                 case INSN_ALU1_FLAGS:
1421                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1422                                 goto invalid_insn;
1423                         g(cgen_alu1(ctx, insn_op_size(insn), insn_aux(insn), insn_writes_flags(insn)));
1424                         return true;
1425                 case INSN_ALU1_PARTIAL:
1426                 case INSN_ALU1_FLAGS_PARTIAL:
1427                         if (unlikely(insn_op_size(insn) >= OP_SIZE_4))
1428                                 goto invalid_insn;
1429                         g(cgen_alu1(ctx, insn_op_size(insn), insn_aux(insn), insn_writes_flags(insn)));
1430                         return true;
1431                 case INSN_LEA3:
1432                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1433                                 goto invalid_insn;
1434                         g(cgen_lea3(ctx, insn_op_size(insn), insn_aux(insn)));
1435                         return true;
1436                 case INSN_ROT:
1437                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1438                                 goto invalid_insn;
1439                         g(cgen_rot(ctx, insn_op_size(insn), insn_aux(insn), insn_writes_flags(insn)));
1440                         return true;
1441                 case INSN_ROT_PARTIAL:
1442                         if (unlikely(insn_op_size(insn) >= OP_SIZE_4))
1443                                 goto invalid_insn;
1444                         g(cgen_rot(ctx, insn_op_size(insn), insn_aux(insn), insn_writes_flags(insn)));
1445                         return true;
1446                 case INSN_BT:
1447                         if (unlikely(insn_op_size(insn) == OP_SIZE_1) || unlikely(!insn_writes_flags(insn)))
1448                                 goto invalid_insn;
1449                         g(cgen_bt(ctx, insn_op_size(insn)));
1450                         return true;
1451                 case INSN_BTX:
1452                         if (unlikely(insn_op_size(insn) == OP_SIZE_1) || unlikely(!insn_writes_flags(insn)))
1453                                 goto invalid_insn;
1454                         g(cgen_btx(ctx, insn_op_size(insn), insn_aux(insn)));
1455                         return true;
1456                 case INSN_MUL_L:
1457                         g(cgen_mul_l(ctx, insn_op_size(insn), insn_aux(insn)));
1458                         return true;
1459                 case INSN_DIV_L:
1460                         g(cgen_div_l(ctx, insn_op_size(insn), insn_aux(insn)));
1461                         return true;
1462                 case INSN_CBW:
1463                         if (unlikely(insn_op_size(insn) <= OP_SIZE_2))
1464                                 goto invalid_insn;
1465                         if (insn_op_size(insn) == OP_SIZE_8)
1466                                 cgen_rex(X86_REX | X86_REX_W);
1467                         if (unlikely(cget_one(ctx) != R_AX))
1468                                 goto invalid_insn;
1469                         if (unlikely(cget_one(ctx) != R_AX))
1470                                 goto invalid_insn;
1471                         cgen_one(X86_CBW);
1472                         return true;
1473                 case INSN_CBW_PARTIAL:
1474                         if (unlikely(insn_op_size(insn) != OP_SIZE_2))
1475                                 goto invalid_insn;
1476                         if (unlikely(cget_one(ctx) != R_AX))
1477                                 goto invalid_insn;
1478                         if (unlikely(cget_one(ctx) != R_AX))
1479                                 goto invalid_insn;
1480                         cgen_one(X86_OP_SIZE);
1481                         cgen_one(X86_CBW);
1482                         return true;
1483                 case INSN_CWD:
1484                         if (unlikely(insn_op_size(insn) <= OP_SIZE_2))
1485                                 goto invalid_insn;
1486                         if (unlikely(cget_one(ctx) != R_DX))
1487                                 goto invalid_insn;
1488                         if (unlikely(cget_one(ctx) != R_AX))
1489                                 goto invalid_insn;
1490                         if (insn_op_size(insn) == OP_SIZE_8)
1491                                 cgen_rex(X86_REX | X86_REX_W);
1492                         cgen_one(X86_CWD);
1493                         return true;
1494                 case INSN_CWD_PARTIAL:
1495                         if (unlikely(insn_op_size(insn) != OP_SIZE_2))
1496                                 goto invalid_insn;
1497                         if (unlikely(cget_one(ctx) != R_DX))
1498                                 goto invalid_insn;
1499                         if (unlikely(cget_one(ctx) != R_AX))
1500                                 goto invalid_insn;
1501                         if (unlikely(cget_one(ctx) != R_DX))
1502                                 goto invalid_insn;
1503                         cgen_one(X86_OP_SIZE);
1504                         cgen_one(X86_CWD);
1505                         return true;
1506                 case INSN_SET_COND:
1507                         if (unlikely(insn_op_size(insn) != OP_SIZE_1))
1508                                 goto invalid_insn;
1509                         g(cgen_rm_insn(ctx, -1, PREFIX_0F, X86_0F_SETCC_RM8 + (insn_aux(insn) & 0xf), OP_SIZE_1, false, 0, ctx->code_position));
1510                         ctx->code_position += arg_size(*ctx->code_position);
1511                         return true;
1512                 case INSN_SET_COND_PARTIAL:
1513                         if (unlikely(insn_op_size(insn) != OP_SIZE_1))
1514                                 goto invalid_insn;
1515                         g(cgen_rm_insn(ctx, -1, PREFIX_0F, X86_0F_SETCC_RM8 + (insn_aux(insn) & 0xf), OP_SIZE_1, false, 0, ctx->code_position));
1516                         ctx->code_position += arg_size(*ctx->code_position);
1517                         ctx->code_position += arg_size(*ctx->code_position);
1518                         return true;
1519                 case INSN_CMOV:
1520                 case INSN_CMOV_XCC:
1521                         if (unlikely(insn_op_size(insn) == OP_SIZE_1))
1522                                 goto invalid_insn;
1523                         g(cgen_cmov(ctx, insn_op_size(insn), insn_aux(insn)));
1524                         return true;
1525                 case INSN_MEMCPY:
1526                         g(cgen_memcpy(ctx));
1527                         return true;
1528                 case INSN_MEMSET:
1529                         g(cgen_memset(ctx));
1530                         return true;
1531                 case INSN_FP_CMP:
1532                         g(cgen_sse_cmp(ctx, insn_op_size(insn)));
1533                         return true;
1534                 case INSN_FP_ALU:
1535                         g(cgen_sse_alu(ctx, insn_op_size(insn), insn_aux(insn)));
1536                         return true;
1537                 case INSN_FP_ALU1:
1538                         g(cgen_sse_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
1539                         return true;
1540                 case INSN_FP_FROM_INT32:
1541                 case INSN_FP_FROM_INT64:
1542                         g(cgen_sse_from_int(ctx, insn_opcode(insn) == INSN_FP_FROM_INT32 ? OP_SIZE_4 : OP_SIZE_8, insn_op_size(insn)));
1543                         return true;
1544                 case INSN_FP_TO_INT32:
1545                 case INSN_FP_TO_INT64:
1546                         g(cgen_sse_to_int(ctx, insn_opcode(insn) == INSN_FP_TO_INT32 ? OP_SIZE_4 : OP_SIZE_8, insn_op_size(insn)));
1547                         return true;
1548                 case INSN_FP_CVT:
1549                         g(cgen_sse_cvt(ctx, insn_op_size(insn), insn_aux(insn)));
1550                         return true;
1551                 case INSN_X87_FLD:
1552                         g(cgen_x87_fld(ctx, insn_op_size(insn)));
1553                         return true;
1554                 case INSN_X87_FILD:
1555                         g(cgen_x87_fild(ctx, insn_op_size(insn)));
1556                         return true;
1557                 case INSN_X87_FSTP:
1558                         g(cgen_x87_fstp(ctx, insn_op_size(insn)));
1559                         return true;
1560                 case INSN_X87_FISTP:
1561                         g(cgen_x87_fistp(ctx, insn_op_size(insn)));
1562                         return true;
1563                 case INSN_X87_FISTTP:
1564                         g(cgen_x87_fisttp(ctx, insn_op_size(insn)));
1565                         return true;
1566                 case INSN_X87_FCOMP:
1567                         g(cgen_x87_fcomp(ctx, insn_op_size(insn)));
1568                         return true;
1569                 case INSN_X87_FCOMPP:
1570                         cgen_one(X87_FCOMPP);
1571                         cgen_one(X87_FCOMPP_2);
1572                         return true;
1573                 case INSN_X87_FCOMIP:
1574                         imm8 = cget_one(ctx);
1575                         cgen_one(X87_FCOMIP);
1576                         cgen_one(X87_FCOMIP_2 + (imm8 & 7));
1577                         return true;
1578                 case INSN_X87_ALU:
1579                         g(cgen_x87_alu(ctx, insn_op_size(insn), insn_aux(insn)));
1580                         return true;
1581                 case INSN_X87_ALUP:
1582                         g(cgen_x87_alup(ctx, insn_aux(insn)));
1583                         return true;
1584                 case INSN_X87_FCHS:
1585                         cgen_one(X87_FCHS);
1586                         cgen_one(X87_FCHS_2);
1587                         return true;
1588                 case INSN_X87_FSQRT:
1589                         cgen_one(X87_FSQRT);
1590                         cgen_one(X87_FSQRT_2);
1591                         return true;
1592                 case INSN_X87_FRNDINT:
1593                         cgen_one(X87_FRNDINT);
1594                         cgen_one(X87_FRNDINT_2);
1595                         return true;
1596                 case INSN_X87_FNSTSW:
1597                         if (unlikely(cget_one(ctx) != R_AX))
1598                                 goto invalid_insn;
1599                         if (unlikely(cget_one(ctx) != R_AX))
1600                                 goto invalid_insn;
1601                         cgen_one(X87_FNSTSW);
1602                         cgen_one(X87_FNSTSW_2);
1603                         return true;
1604                 case INSN_X87_FLDCW:
1605                         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, X87_FLDCW, OP_SIZE_4, false, X87_FLDCW_X, ctx->code_position));
1606                         ctx->code_position += arg_size(*ctx->code_position);
1607                         return true;
1608                 case INSN_JMP:
1609                         if (insn_jump_size(insn) == JMP_SHORT || insn_jump_size(insn) == JMP_SHORTEST) {
1610                                 cgen_one(X86_JMP_8);
1611                                 g(add_relocation(ctx, JMP_SHORT, 0, NULL));
1612                                 cgen_one(0);
1613                         } else if (likely(insn_jump_size(insn) == JMP_LONG)) {
1614                                 cgen_one(X86_JMP_16);
1615                                 g(add_relocation(ctx, JMP_LONG, 0, NULL));
1616                                 cgen_four(0);
1617                         } else {
1618                                 goto invalid_insn;
1619                         }
1620                         return true;
1621                 case INSN_JMP_COND:
1622                         if (insn_jump_size(insn) == JMP_SHORT || insn_jump_size(insn) == JMP_SHORTEST) {
1623                                 cgen_one(X86_JCC_8 + (insn_aux(insn) & 0xf));
1624                                 g(add_relocation(ctx, JMP_SHORT, 0, NULL));
1625                                 cgen_one(0);
1626                         } else if (likely(insn_jump_size(insn) == JMP_LONG)) {
1627                                 cgen_one(X86_0F);
1628                                 cgen_one(X86_0F_JCC_16 + (insn_aux(insn) & 0xf));
1629                                 g(add_relocation(ctx, JMP_LONG, 0, NULL));
1630                                 cgen_four(0);
1631                         } else {
1632                                 goto invalid_insn;
1633                         }
1634                         return true;
1635                 case INSN_JMP_INDIRECT:
1636                         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, X86_FF, OP_SIZE_4, false, X86_FF_JMP_INDIRECT, ctx->code_position));
1637                         ctx->code_position += arg_size(*ctx->code_position);
1638                         return true;
1639                 default:
1640                 invalid_insn:
1641                         internal(file_line, "cgen_insn: invalid insn %08lx", (unsigned long)insn);
1642                         return false;
1643         }