x86: make lea support negative numbers - we can change ALU_WRITES_FLAGS
[ajla.git] / c2-x86.inc
blobf2d6f1282f18b4941c0f4ecaffee5d3f85a78aa8
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_MOVD_X128_RM32           0x6e
134 #define X86_0F_MOVD_RM32_X128           0x7e
135 #define X86_0F_JCC_16                   0x80
136 #define X86_0F_SETCC_RM8                0x90
137 #define X86_0F_BT_RM16_R16              0xa3
138 #define X86_0F_BTS_RM16_R16             0xab
139 #define X86_0F_BTR_RM16_R16             0xb3
140 #define X86_0F_BTX_RM16_IMM8            0xba
141 #define  X86_0F_BTX_BT_RM16_IMM8                0x4
142 #define  X86_0F_BTX_BTS_RM16_IMM8               0x5
143 #define  X86_0F_BTX_BTR_RM16_IMM8               0x6
144 #define  X86_0F_BTX_BTC_RM16_IMM8               0x7
145 #define X86_0F_BSWAP                    0xc8
146 #define X86_0F_BTC_RM16_R16             0xbb
147 #define X86_0F_IMUL_R16_RM16            0xaf
148 #define X86_0F_MOVZX_R16_RM8            0xb6
149 #define X86_0F_MOVZX_R16_RM16           0xb7
150 #define X86_0F_POPCNT_R16_RM16          0xb8
151 #define X86_0F_BSF_R16_RM16             0xbc
152 #define X86_0F_BSR_R16_RM16             0xbd
153 #define X86_0F_MOVSX_R16_RM8            0xbe
154 #define X86_0F_MOVSX_R16_RM16           0xbf
155 #define X86_0F_PINSRW_X128_RM16_IMM8    0xc4
157 #define X86_0F_38_CVTPH2PS_X128_RM64    0x13
158 #define X86_0F_38_ROTX                  0xf7
160 #define X86_0F_3A_ROUNDSS_X128_M32      0x0a
161 #define X86_0F_3A_ROUNDSD_X128_M64      0x0b
162 #define X86_0F_3A_PEXTRW_RM16_X128_IMM8 0x15
163 #define X86_0F_3A_CVTPS2PH_RM64_X128    0x1d
165 #define X87_FLD_RM32                    0xd9
166 #define  X87_FLD_RM32_X                         0x0
167 #define X87_FLDCW                       0xd9
168 #define  X87_FLDCW_X                            0x5
169 #define X87_FILD_M32                    0xdb
170 #define  X87_FILD_M32_X                         0x0
171 #define X87_FISTTP_M32                  0xdb
172 #define  X87_FISTTP_M32_X                       0x1
173 #define X87_FISTP_M32                   0xdb
174 #define  X87_FISTP_M32_X                        0x3
175 #define X87_FLD_M80                     0xdb
176 #define  X87_FLD_M80_X                          0x5
177 #define X87_FLD_M64                     0xdd
178 #define  X87_FLD_M64_X                          0x0
179 #define X87_FSTP_M32                    0xd9
180 #define  X87_FSTP_M32_X                         0x3
181 #define X87_FSTP_M80                    0xdb
182 #define  X87_FSTP_M80_X                         0x7
183 #define X87_FSTP_RM64                   0xdd
184 #define  X87_FSTP_RM64_X                        0x3
185 #define X87_FALU_ST_RM32                0xd8
186 #define X87_FCHS                        0xd9
187 #define  X87_FCHS_2                             0xe0
188 #define X87_FSQRT                       0xd9
189 #define  X87_FSQRT_2                            0xfa
190 #define X87_FRNDINT                     0xd9
191 #define  X87_FRNDINT_2                          0xfc
192 #define X87_FALU_ST_M64                 0xdc
193 #define X87_FALU_STi_ST                 0xdc
194 #define X87_FISTTP_M64                  0xdd
195 #define  X87_FISTTP_M64_X                       0x1
196 #define X87_FALUP_STi_ST0               0xde
197 #define  X87_ALU_ADD                            0x0
198 #define  X87_ALU_MUL                            0x1
199 #define  X87_ALU_FCOM                           0x2
200 #define  X87_ALU_FCOMP                          0x3
201 #define  X87_ALU_SUBR                           0x4
202 #define  X87_ALU_SUB                            0x5
203 #define  X87_ALU_DIVR                           0x6
204 #define  X87_ALU_DIV                            0x7
205 #define X87_FCOMPP                      0xde
206 #define  X87_FCOMPP_2                           0xd9
207 #define X87_FILD_M16                    0xdf
208 #define  X87_FILD_M16_X                         0x0
209 #define X87_FISTTP_M16                  0xdf
210 #define  X87_FISTTP_M16_X                       0x1
211 #define X87_FISTP_M16                   0xdf
212 #define  X87_FISTP_M16_X                        0x3
213 #define X87_FILD_M64                    0xdf
214 #define  X87_FILD_M64_X                         0x5
215 #define X87_FISTP_M64                   0xdf
216 #define  X87_FISTP_M64_X                        0x7
217 #define X87_FNSTSW                      0xdf
218 #define  X87_FNSTSW_2                           0xe0
219 #define X87_FCOMIP                      0xdf
220 #define  X87_FCOMIP_2                           0xf0
222 #define SSE_PREFIX_NONE                 0
223 #define SSE_PREFIX_66                   1
224 #define SSE_PREFIX_F3                   2
225 #define SSE_PREFIX_F2                   3
227 #define PREFIX_NONE                     0
228 #define PREFIX_0F                       1
229 #define PREFIX_0F_38                    2
230 #define PREFIX_0F_3A                    3
232 #ifdef ARCH_X86_32
233 #define cgen_rex(rex)           internal(file_line, "cgen_rex: attempting to generate rex in 32-bit mode: %02x", rex)
234 #else
235 #define cgen_rex(rex)           cgen_one(rex)
236 #endif
238 #define force_vex                       0x10000
240 static bool attr_w cgen_rm_insn(struct codegen_context *ctx, int32_t sse_prefix, uint8_t prefix, uint8_t opcode, unsigned size, bool reg_is_reg, uint8_t reg, uint8_t *arg)
242         uint8_t rex, mod, rm;
243         int16_t sib;
244         int64_t imm = 0;        /* avoid warning */
245         uint8_t addr_size;
246         uint8_t arg_reg;
247         bool need_rex;
249         if (unlikely(R_IS_XMM(reg)))
250                 reg -= R_XMM0;
251         if (unlikely(R_IS_XMM(arg[0]))) {
252                 arg_reg = arg[0] - R_XMM0;
253                 arg = &arg_reg;
254         }
255         if (unlikely(!R_IS_GPR(reg)))
256                 internal(file_line, "cgen_rm_insn: invalid register %02x", reg);
258         sib = -1;
259         rex = X86_REX;
260         if (size == OP_SIZE_8)
261                 rex |= X86_REX_W;
262         if (reg & 8)
263                 rex |= X86_REX_R;
264         if (arg[0] < 0x40) {
265                 if (arg[0] & 8)
266                         rex |= X86_REX_B;
267                 mod = 0xc0;
268                 rm = arg[0] & 7;
269                 addr_size = 0;
270         } else {
271                 uint8_t *imm_ptr = arg + arg_size(arg[0]) - 8;
272                 imm = get_imm(imm_ptr);
273                 if (unlikely(!imm_is_32bit(imm)))
274                         internal(file_line, "cgen_rm_insn: immediate out of range: %"PRIxMAX"", (uintmax_t)imm);
275                 if (arg[0] == ARG_ADDRESS_0) {
276 address_0:
277                         addr_size = 4;
278                         mod = 0x00;
279                         rm = 0x4;
280                         sib = 0x25;
281                         goto gen;
282                 }
283                 if (!imm) {
284                         addr_size = 0;
285                 } else if (imm >= -0x80 && imm <= 0x7f) {
286                         addr_size = 1;
287                 } else {
288                         addr_size = 4;
289                 }
290                 if ((arg[1] & 7) == 0x5 && addr_size == 0)
291                         addr_size = 1;
292                 if (addr_size == 0)
293                         mod = 0x00;
294                 else if (addr_size == 1)
295                         mod = 0x40;
296                 else
297                         mod = 0x80;
298                 if (arg[0] == ARG_ADDRESS_1) {
299                         if (reg_is_segment(arg[1])) {
300                                 static const uint8_t segments[6] = { X86_ES, X86_CS, X86_SS, X86_DS, X86_FS, X86_GS };
301                                 cgen_one(segments[arg[1] - R_ES]);
302                                 goto address_0;
303                         }
304                         if (arg[1] & 8)
305                                 rex |= X86_REX_B;
306                         if ((arg[1] & 7) == 0x4) {
307                                 rm = 0x4;
308                                 sib = 0x24;
309                                 goto gen;
310                         }
311                         rm = arg[1] & 7;
312                         goto gen;
313                 }
314                 if (arg[0] >= ARG_ADDRESS_1_2 && arg[0] <= ARG_ADDRESS_1_8) {
315                         if (unlikely(arg[1] == R_SP))
316                                 internal(file_line, "cgen_rm_insn: attemptint to scale SP");
317                         if (arg[1] & 8)
318                                 rex |= X86_REX_X;
319                         addr_size = 4;
320                         mod = 0x00;
321                         rm = 0x4;
322                         sib = ((arg[0] - ARG_ADDRESS_1) << 6) | ((arg[1] & 7) << 3) | 0x5;
323                         goto gen;
324                 }
325                 if (arg[0] >= ARG_ADDRESS_2 && arg[0] <= ARG_ADDRESS_2_8) {
326                         if (unlikely(arg[2] == R_SP))
327                                 internal(file_line, "cgen_rm_insn: attemptint to scale SP");
328                         if (arg[1] & 8)
329                                 rex |= X86_REX_B;
330                         if (arg[2] & 8)
331                                 rex |= X86_REX_X;
332                         rm = 0x4;
333                         sib = ((arg[0] - ARG_ADDRESS_2) << 6) | ((arg[2] & 7) << 3) | (arg[1] & 7);
334                         goto gen;
335                 }
336                 internal(file_line, "cgen_rm_insn: invalid argument %02x", arg[0]);
337         }
339 gen:
340         if (unlikely(sse_prefix >= 0)) {
341                 if (likely(cpu_test_feature(CPU_FEATURE_avx)) || (sse_prefix & force_vex)) {
342                         if ((rex & (X86_REX_X | X86_REX_B | X86_REX_W)) == 0 && prefix == PREFIX_0F) {
343                                 cgen_one(X86_VEX_2);
344                                 cgen_one((~rex & X86_REX_R) << 5 | (~(sse_prefix >> 8) & 0xf) << 3 | (sse_prefix & 3));
345                         } else {
346                                 cgen_one(X86_VEX_3);
347                                 cgen_one((~rex & (X86_REX_R | X86_REX_X | X86_REX_B)) << 5 | prefix);
348                                 cgen_one((rex & X86_REX_W) << 4 | (~(sse_prefix >> 8) & 0xf) << 3 | (sse_prefix & 3));
349                         }
350                         goto avx_done;
351                 }
352                 switch (sse_prefix & 3) {
353                         case SSE_PREFIX_66:     cgen_one(X86_OP_SIZE); break;
354                         case SSE_PREFIX_F3:     cgen_one(X86_REPE); break;
355                         case SSE_PREFIX_F2:     cgen_one(X86_REPNE); break;
356                 }
357         } else {
358                 if (size == OP_SIZE_2)
359                         cgen_one(X86_OP_SIZE);
360         }
361         need_rex = rex != X86_REX;
362         need_rex |= size == OP_SIZE_1 && ((reg_is_reg && !reg_is_fp(reg) && reg >= 4) || (mod == 0xc0 && !reg_is_fp(arg[0]) && arg[0] >= 4));
363         if (prefix == PREFIX_0F && (opcode == X86_0F_MOVZX_R16_RM8 || opcode == X86_0F_MOVSX_R16_RM8)) {
364                 need_rex |= mod == 0xc0 && arg[0] >= 4;
365         }
366         if (need_rex)
367                 cgen_rex(rex);
369         switch (prefix) {
370                 case PREFIX_NONE:
371                         break;
372                 case PREFIX_0F:
373                         cgen_one(X86_0F);
374                         break;
375                 case PREFIX_0F_38:
376                         cgen_one(X86_0F);
377                         cgen_one(X86_0F_38);
378                         break;
379                 case PREFIX_0F_3A:
380                         cgen_one(X86_0F);
381                         cgen_one(X86_0F_3A);
382                         break;
383                 default:
384                         internal(file_line, "cgen_rm_insn: invalid prefix %u", prefix);
385         }
386 avx_done:
387         cgen_one(opcode);
388         cgen_one(mod | ((reg & 7) << 3) | (rm & 7));
389         if (sib >= 0)
390                 cgen_one(sib);
391         switch (addr_size) {
392                 case 1:
393                         cgen_one(imm);
394                         break;
395                 case 4:
396                         cgen_four(imm);
397                         break;
398         }
399         return true;
402 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)
404         g(cgen_rm_insn(ctx, sse_prefix + (reg2 << 8), sse_op_map, opcode, !wide ? OP_SIZE_4 : OP_SIZE_8, true, reg, arg));
405         return true;
408 static bool attr_w cgen_push(struct codegen_context *ctx)
410         uint8_t *arg1 = ctx->code_position;
411         ctx->code_position += arg_size(*arg1);
412         if (likely(R_IS_GPR(arg1[0]))) {
413                 if (arg1[0] & 8)
414                         cgen_rex(X86_REX | X86_REX_B);
415                 cgen_one(X86_PUSH_R16 + (arg1[0] & 7));
416                 return true;
417         }
418         if (arg1[0] == ARG_IMM) {
419                 int64_t imm;
420                 imm = get_imm(&arg1[1]);
421                 if (unlikely(!imm_is_32bit(imm)))
422                         internal(file_line, "cgen_push: immediate out of range: %"PRIxMAX"", (uintmax_t)imm);
423                 if (imm >= -0x80 && imm <= 0x7f) {
424                         cgen_one(X86_PUSH_IMM8);
425                         cgen_one(imm);
426                         return true;
427                 } else {
428                         cgen_one(X86_PUSH_IMM16);
429                         cgen_four(imm);
430                         return true;
431                 }
432         }
433         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, X86_FF, OP_SIZE_4, false, X86_FF_PUSH, arg1));
434         return true;
437 static bool attr_w cgen_pop(struct codegen_context *ctx)
439         uint8_t *arg1 = ctx->code_position;
440         ctx->code_position += arg_size(*arg1);
441         if (likely(R_IS_GPR(arg1[0]))) {
442                 if (arg1[0] & 8)
443                         cgen_rex(X86_REX | X86_REX_B);
444                 cgen_one(X86_POP_R16 + (arg1[0] & 7));
445                 return true;
446         }
447         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, X86_8F, OP_SIZE_4, false, X86_8F_POP, arg1));
448         return true;
451 static bool attr_w cgen_mov(struct codegen_context *ctx, unsigned size)
453         uint8_t *arg1 = ctx->code_position;
454         uint8_t *arg2 = arg1 + arg_size(*arg1);
455         ctx->code_position = arg2 + arg_size(*arg2);
456         if (arg2[0] == ARG_IMM) {
457                 int rex = X86_REX;
458                 int64_t imm;
459                 imm = get_imm(&arg2[1]);
460                 if (R_IS_GPR(arg1[0])) {
461                         if (arg1[0] & 8)
462                                 rex |= X86_REX_B;
463 #ifndef ARCH_X86_32
464                         if (imm >= 0 && imm < 0x100000000LL)
465 #endif
466                         {
467                                 if (rex != X86_REX)
468                                         cgen_rex(rex);
469                                 cgen_one(X86_MOV_R16_IMM16 + (arg1[0] & 7));
470                                 cgen_four(imm);
471                                 return true;
472                         }
473                         if (imm >= ~(int64_t)0x7fffffff && imm < 0) {
474                                 goto mov_rm;
475                         }
476                         rex |= X86_REX_W;
477                         cgen_rex(rex);
478                         cgen_one(X86_MOV_R16_IMM16 + (arg1[0] & 7));
479                         cgen_eight(imm);
480                         return true;
481                 } else {
482                         if (size < OP_SIZE_4) {
483                                 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));
484                                 if (size == OP_SIZE_1)
485                                         cgen_one(imm);
486                                 else
487                                         cgen_two(imm);
488                                 return true;
489                         }
490 mov_rm:
491                         if (unlikely(!imm_is_32bit(imm)))
492                                 internal(file_line, "cgen_mov: immediate out of range: %"PRIxMAX"", (uintmax_t)imm);
493                         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, X86_MOV_RM16_IMM16, maximum(size, OP_SIZE_4), false, X86_MOV_R16_IMM16_REG, arg1));
494                         cgen_four(imm);
495                         return true;
496                 }
497         }
498         if (arg1[0] == R_AX && size >= OP_SIZE_4 && arg2[0] == ARG_ADDRESS_0) {
499                 int64_t imm;
500                 imm = get_imm(&arg2[1]);
501                 if (size == OP_SIZE_8)
502                         cgen_rex(X86_REX | X86_REX_W);
503                 cgen_one(X86_MOV_AX_M16);
504                 cgen_eight(imm);
505                 return true;
506         }
507         if (arg1[0] == ARG_ADDRESS_0 && arg2[0] == R_AX) {
508                 uint8_t code = size == OP_SIZE_1 ? X86_MOV_M16_AL : X86_MOV_M16_AX;
509                 int64_t imm;
510                 imm = get_imm(&arg1[1]);
511                 if (size == OP_SIZE_2)
512                         cgen_one(X86_OP_SIZE);
513                 if (size == OP_SIZE_8)
514                         cgen_rex(X86_REX | X86_REX_W);
515                 cgen_one(code);
516                 cgen_eight(imm);
517                 return true;
518         }
519         if (R_IS_XMM(arg1[0]) && ARG_IS_ADDRESS(arg2[0])) {
520                 if (size == OP_SIZE_2) {
521                         g(cgen_sse_insn(ctx, SSE_PREFIX_66, PREFIX_0F, X86_0F_PINSRW_X128_RM16_IMM8, false, arg1[0], R_XMM7, arg2));
522                         cgen_one(0x00);
523                         return true;
524                 }
525                 if (size == OP_SIZE_16) {
526                         g(cgen_sse_insn(ctx, SSE_PREFIX_NONE, PREFIX_0F, X86_0F_MOVAPS_X128_M128, false, arg1[0], 0, arg2));
527                         return true;
528                 }
529                 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));
530                 return true;
531         }
532         if (ARG_IS_ADDRESS(arg1[0]) && R_IS_XMM(arg2[0])) {
533                 if (size == OP_SIZE_2) {
534                         g(cgen_sse_insn(ctx, SSE_PREFIX_66, PREFIX_0F_3A, X86_0F_3A_PEXTRW_RM16_X128_IMM8, false, arg2[0], 0, arg1));
535                         cgen_one(0x00);
536                         return true;
537                 }
538                 if (size == OP_SIZE_16) {
539                         g(cgen_sse_insn(ctx, SSE_PREFIX_NONE, PREFIX_0F, X86_0F_MOVAPS_M128_X128, false, arg2[0], 0, arg1));
540                         return true;
541                 }
542                 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));
543                 return true;
544         }
545         if (R_IS_XMM(arg1[0]) && R_IS_XMM(arg2[0])) {
546                 g(cgen_sse_insn(ctx, SSE_PREFIX_NONE, PREFIX_0F, X86_0F_MOVAPS_X128_M128, false, arg1[0], 0, arg2));
547                 return true;
548         }
549         if (R_IS_XMM(arg1[0]) && R_IS_GPR(arg2[0])) {
550                 g(cgen_sse_insn(ctx, SSE_PREFIX_66, PREFIX_0F, X86_0F_MOVD_X128_RM32, size == OP_SIZE_8, arg1[0], 0, arg2));
551                 return true;
552         }
553         if (R_IS_GPR(arg1[0]) && R_IS_XMM(arg2[0])) {
554                 g(cgen_sse_insn(ctx, SSE_PREFIX_66, PREFIX_0F, X86_0F_MOVD_RM32_X128, size == OP_SIZE_8, arg2[0], 0, arg1));
555                 return true;
556         }
557         if (!R_IS_GPR(arg1[0]) && unlikely(!R_IS_GPR(arg2[0]))) {
558                 /*debug("%s", da(ctx->fn,function)->function_name);*/
559                 internal(file_line, "cgen_mov: two addresses not supported");
560         }
561         if (!R_IS_GPR(arg1[0])) {
562                 uint8_t code = size == OP_SIZE_1 ? X86_MOV_RM8_R8 : X86_MOV_RM16_R16;
563                 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, code, size, true, arg2[0], arg1));
564                 return true;
565         } else if (size >= OP_SIZE_4) {
566                 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, X86_MOV_R16_RM16, size, true, arg1[0], arg2));
567                 return true;
568         } else {
569                 uint8_t code = size == OP_SIZE_1 ? X86_0F_MOVZX_R16_RM8 : X86_0F_MOVZX_R16_RM16;
570                 g(cgen_rm_insn(ctx, -1, PREFIX_0F, code, OP_SIZE_4, false, arg1[0], arg2));
571                 return true;
572         }
575 static bool attr_w cgen_movsx(struct codegen_context *ctx, unsigned size)
577         uint8_t *arg1, *arg2;
578         if (unlikely(size == OP_SIZE_NATIVE)) {
579                 g(cgen_mov(ctx, size));
580                 return true;
581         }
582         arg1 = ctx->code_position;
583         arg2 = arg1 + arg_size(*arg1);
584         ctx->code_position = arg2 + arg_size(*arg2);
585         if (size <= OP_SIZE_2) {
586                 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));
587         } else {
588                 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, X86_MOVSXD, OP_SIZE_NATIVE, true, arg1[0], arg2));
589         }
590         return true;
593 static bool attr_w cgen_lea(struct codegen_context *ctx, unsigned size, bool neg)
595         uint8_t addr[11];
596         uint8_t *arg1, *arg2, *arg3;
598         arg1 = ctx->code_position;
599         arg2 = arg1 + arg_size(*arg1);
600         arg3 = arg2 + arg_size(*arg2);
601         ctx->code_position = arg3 + arg_size(*arg3);
603         if (arg3[0] == ARG_IMM) {
604                 int64_t imm;
605                 if (arg2[0] == ARG_SHIFTED_REGISTER) {
606                         if (unlikely((arg2[1] & ARG_SHIFT_MODE) != ARG_SHIFT_LSL) ||
607                             unlikely((arg2[1] & ARG_SHIFT_AMOUNT) > 3))
608                                 goto invalid;
609                         addr[0] = ARG_ADDRESS_1 + (arg2[1] & ARG_SHIFT_AMOUNT);
610                         addr[1] = arg2[2];
611                 } else {
612                         addr[0] = ARG_ADDRESS_1;
613                         addr[1] = arg2[0];
614                 }
615                 imm = get_imm(&arg3[1]);
616                 if (neg) {
617                         if (unlikely(imm == -(int64_t)0x80000000))
618                                 goto invalid;
619                         imm = -(uint64_t)imm;
620                 }
621                 memcpy(&addr[2], &imm, 8);
622         } else if (R_IS_GPR(arg3[0])) {
623                 if (unlikely(neg))
624                         goto invalid;
625                 addr[0] = ARG_ADDRESS_2;
626                 addr[1] = arg2[0];
627                 addr[2] = arg3[0];
628                 memset(&addr[3], 0, 8);
629         } else if (arg3[0] == ARG_SHIFTED_REGISTER) {
630                 if (unlikely(neg))
631                         goto invalid;
632                 if (unlikely((arg3[1] & ARG_SHIFT_MODE) != ARG_SHIFT_LSL) ||
633                     unlikely((arg3[1] & ARG_SHIFT_AMOUNT) > 3))
634                         goto invalid;
635                 addr[0] = ARG_ADDRESS_2 + (arg3[1] & ARG_SHIFT_AMOUNT);
636                 addr[1] = arg2[0];
637                 addr[2] = arg3[2];
638                 memset(&addr[3], 0, 8);
639         } else {
640 invalid:
641                 internal(file_line, "cgen_lea: invalid argument %u, %02x, %02x, %02x, %u", size, arg1[0], arg2[0], arg3[0], (unsigned)neg);
642         }
643         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, X86_LEA_R16_RM16, size, true, arg1[0], addr));
644         return true;
647 static bool attr_w cgen_alu(struct codegen_context *ctx, unsigned size, unsigned alu, unsigned writes_flags)
649         uint8_t *arg1, *arg2, *arg3;
650         if (alu != 7) {
651                 arg1 = ctx->code_position;
652                 arg2 = arg1 + arg_size(*arg1);
653                 arg3 = arg2 + arg_size(*arg2);
654                 ctx->code_position = arg3 + arg_size(*arg3);
655                 if (unlikely(arg_size(*arg1) != arg_size(*arg2)))
656                         internal(file_line, "cgen_alu: three-operand mode not supported");
657                 if (unlikely(memcmp(arg1, arg2, arg_size(*arg1))))
658                         internal(file_line, "cgen_alu: three-operand mode not supported");
659         } else {
660                 arg1 = ctx->code_position;
661                 arg2 = arg1;
662                 arg3 = arg2 + arg_size(*arg2);
663                 ctx->code_position = arg3 + arg_size(*arg3);
664         }
666         if (unlikely(alu == ALU_MUL)) {
667                 if (unlikely(arg3[0] == ARG_IMM)) {
668                         uint8_t code;
669                         int64_t imm;
670                         imm = get_imm(&arg3[1]);
671                         if (unlikely(!imm_is_32bit(imm)))
672                                 internal(file_line, "cgen_alu: immediate out of range: %"PRIxMAX"", (uintmax_t)imm);
673                         code = imm_is_8bit(imm) ? X86_IMUL_R16_RM16_IMM8 : X86_IMUL_R16_RM16_IMM16;
674                         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, code, size, true, arg1[0], arg2));
675                         if (code == X86_IMUL_R16_RM16_IMM8) {
676                                 cgen_one(imm);
677                         } else if (size == OP_SIZE_2) {
678                                 cgen_two(imm);
679                         } else {
680                                 cgen_four(imm);
681                         }
682                         return true;
683                 }
684                 if (unlikely(size == OP_SIZE_1)) {
685                         if (unlikely(arg1[0] != R_AX))
686                                 internal(file_line, "cgen_alu: imul with unsupported register");
687                         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, X86_F6, size, false, X86_F6_IMUL_RM8, arg3));
688                         return true;
689                 } else {
690                         if (unlikely(!R_IS_GPR(arg1[0])))
691                                 internal(file_line, "cgen_alu: invalid multiply args");
692                         g(cgen_rm_insn(ctx, -1, PREFIX_0F, X86_0F_IMUL_R16_RM16, size, true, arg1[0], arg3));
693                         return true;
694                 }
695         }
697         if (arg3[0] == ARG_IMM) {
698                 uint8_t code;
699                 bool bit8;
700                 int64_t imm;
701                 imm = get_imm(&arg3[1]);
702                 if (unlikely(!imm_is_32bit(imm)))
703                         internal(file_line, "cgen_alu: immediate out of range: %"PRIxMAX"", (uintmax_t)imm);
705                 if (!(writes_flags & 2)) {
706                         if ((alu == ALU_ADD && imm == 1) || (alu == ALU_SUB && imm == -1)) {
707 #ifdef ARCH_X86_32
708                                 if (R_IS_GPR(arg1[0]) && size >= OP_SIZE_2) {
709                                         if (size == OP_SIZE_2)
710                                                 cgen_one(X86_OP_SIZE);
711                                         cgen_one(X86_INC_R16 + arg1[0]);
712                                         return true;
713                                 }
714 #endif
715                                 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, size == OP_SIZE_1 ? X86_FE : X86_FF, size, false, X86_FE_INC_RM8, arg1));
716                                 return true;
717                         }
718                         if ((alu == ALU_ADD && imm == -1) || (alu == ALU_SUB && imm == 1)) {
719 #ifdef ARCH_X86_32
720                                 if (R_IS_GPR(arg1[0]) && size >= OP_SIZE_2) {
721                                         if (size == OP_SIZE_2)
722                                                 cgen_one(X86_OP_SIZE);
723                                         cgen_one(X86_INC_R16 + arg1[0]);
724                                         return true;
725                                 }
726 #endif
727                                 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, size == OP_SIZE_1 ? X86_FE : X86_FF, size, false, X86_FE_DEC_RM8, arg1));
728                                 return true;
729                         }
730                 }
732                 if (arg1[0] == R_AX) {
733                         if (imm_is_8bit(imm) && size >= OP_SIZE_4)
734                                 goto use_shorter;
735                         bit8 = false;
736                         code = size == OP_SIZE_1 ? X86_ALU_AL_IMM8 : X86_ALU_AX_IMM16;
737                         if (size == OP_SIZE_2)
738                                 cgen_one(X86_OP_SIZE);
739                         if (size == OP_SIZE_8)
740                                 cgen_rex(X86_REX | X86_REX_W);
741                         code += alu * 8;
742                         cgen_one(code);
743                 } else {
744 use_shorter:
745                         bit8 = imm_is_8bit(imm);
746                         code = size == OP_SIZE_1 ? X86_ALU_RM8_IMM8 : bit8 ? X86_ALU_RM16_IMM8 : X86_ALU_RM16_IMM16;
747                         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, code, size, false, alu, arg1));
748                 }
749                 if (bit8 || size == OP_SIZE_1) {
750                         cgen_one(imm);
751                 } else if (size == OP_SIZE_2) {
752                         cgen_two(imm);
753                 } else {
754                         cgen_four(imm);
755                 }
756                 return true;
757         }
759         if (R_IS_XMM(arg1[0]) && size == OP_SIZE_16) {
760                 uint8_t code;
761                 switch (alu) {
762                         case ALU_AND:   code = X86_0F_ANDPS_X128_M128; break;
763                         case ALU_ANDN:  code = X86_0F_ANDNPS_X128_M128; break;
764                         case ALU_OR:    code = X86_0F_ORPS_X128_M128; break;
765                         case ALU_XOR:   code = X86_0F_XORPS_X128_M128; break;
766                         default:        internal(file_line, "invalid sse alu: %u", alu);
767                 }
768                 g(cgen_sse_insn(ctx, SSE_PREFIX_NONE, PREFIX_0F, code, false, arg1[0], arg2[0], arg3));
769                 return true;
770         }
772         if (!R_IS_GPR(arg1[0]) && unlikely(!R_IS_GPR(arg3[0])))
773                 internal(file_line, "cgen_alu: two addresses not supported");
775         if (!R_IS_GPR(arg1[0])) {
776                 uint8_t code = size == OP_SIZE_1 ? X86_ALU_RM8_R8 : X86_ALU_RM16_R16;
777                 code += alu * 8;
778                 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, code, size, true, arg3[0], arg1));
779                 return true;
780         } else {
781                 uint8_t code = size == OP_SIZE_1 ? X86_ALU_R8_RM8 : X86_ALU_R16_RM16;
782                 code += alu * 8;
783                 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, code, size, true, arg1[0], arg3));
784                 return true;
785         }
788 static bool attr_w cgen_alu1(struct codegen_context *ctx, unsigned size, unsigned alu)
790         uint8_t rex;
791         uint8_t *arg1 = ctx->code_position;
792         uint8_t *arg2 = arg1 + arg_size(*arg1);
793         ctx->code_position = arg2 + arg_size(*arg2);
794         if (alu == ALU1_NOT || alu == ALU1_NEG || alu == ALU1_BSWAP) {
795                 if (unlikely(arg1[0] != arg2[0]))
796                         internal(file_line, "cgen_alu1: arguments mismatch: %x, %x", arg1[0], arg2[0]);
797         }
798         switch (alu) {
799                 case ALU1_NOT:
800                         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, size == OP_SIZE_1 ? X86_F6 : X86_F7, size, false, X86_F6_NOT_RM8, arg1));
801                         return true;
802                 case ALU1_NEG:
803                         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, size == OP_SIZE_1 ? X86_F6 : X86_F7, size, false, X86_F6_NEG_RM8, arg1));
804                         return true;
805                 case ALU1_BSWAP:
806                         if (unlikely(size <= OP_SIZE_2))
807                                 internal(file_line, "cgen_alu1: bytes or words not supported with this operation");
808                         rex = X86_REX;
809                         if (!R_IS_GPR(arg1[0]))
810                                 internal(file_line, "cgen_alu1: bswap needs a register");
811                         if (arg1[0] & 8)
812                                 rex |= X86_REX_B;
813                         if (size == OP_SIZE_8)
814                                 rex |= X86_REX_W;
815                         if (rex != X86_REX)
816                                 cgen_rex(rex);
817                         cgen_one(X86_0F);
818                         cgen_one(X86_0F_BSWAP + (arg1[0] & 7));
819                         return true;
820                 case ALU1_BSF:
821                 case ALU1_BSR:
822                 case ALU1_LZCNT:
823                 case ALU1_POPCNT:
824                         if (unlikely(size == OP_SIZE_1))
825                                 internal(file_line, "cgen_alu1: bytes not supported with this operation");
826                         if (alu == ALU1_POPCNT || alu == ALU1_LZCNT)
827                                 cgen_one(X86_REPE);
828                         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));
829                         return true;
830                 default:
831                         internal(file_line, "cgen_alu1: invalid operation %u", alu);
832                         return false;
833         }
836 static bool attr_w cgen_test(struct codegen_context *ctx, unsigned size)
838         uint8_t *arg1, *arg2;
839         arg1 = ctx->code_position;
840         arg2 = arg1 + arg_size(*arg1);
841         ctx->code_position = arg2 + arg_size(*arg2);
843         if (arg2[0] == ARG_IMM) {
844                 int64_t imm;
845                 imm = get_imm(&arg2[1]);
846                 if (arg1[0] == R_AX) {
847                         if (size == OP_SIZE_1) {
848                                 cgen_one(X86_TEST_AL_IMM8);
849                         } else if (size == OP_SIZE_2) {
850                                 cgen_one(X86_OP_SIZE);
851                                 cgen_one(X86_TEST_AX_IMM16);
852                         } else if (size == OP_SIZE_4) {
853                                 cgen_one(X86_TEST_AX_IMM16);
854                         } else {
855                                 if (unlikely(!imm_is_32bit(imm)))
856                                         internal(file_line, "cgen_Test: immediate out of range: %"PRIxMAX"", (uintmax_t)imm);
857                                 cgen_rex(X86_REX | X86_REX_W);
858                                 cgen_one(X86_TEST_AX_IMM16);
859                         }
860                 } else {
861                         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, size == OP_SIZE_1 ? X86_F6 : X86_F7, size, false, X86_F6_TEST_RM8_IMM8, arg1));
862                 }
863                 if (size == OP_SIZE_1) {
864                         cgen_one(imm);
865                 } else if (size == OP_SIZE_2) {
866                         cgen_two(imm);
867                 } else if (size == OP_SIZE_4) {
868                         cgen_four(imm);
869                 } else {
870                         if (unlikely(!imm_is_32bit(imm)))
871                                 internal(file_line, "cgen_Test: immediate out of range: %"PRIxMAX"", (uintmax_t)imm);
872                         cgen_four(imm);
873                 }
874                 return true;
875         }
877         if (!R_IS_GPR(arg1[0]) && unlikely(!R_IS_GPR(arg2[0])))
878                 internal(file_line, "cgen_test: two addresses not supported");
880         if (!R_IS_GPR(arg1[0])) {
881                 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));
882         } else {
883                 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));
884         }
885         return true;
888 static bool attr_w cgen_lea3(struct codegen_context *ctx, unsigned size, unsigned shift)
890         uint8_t addr[11];
891         uint8_t *arg1, *arg2, *arg3, *arg4;
893         arg1 = ctx->code_position;
894         arg2 = arg1 + arg_size(*arg1);
895         arg3 = arg2 + arg_size(*arg2);
896         arg4 = arg3 + arg_size(*arg3);
897         ctx->code_position = arg4 + arg_size(*arg4);
899         if (unlikely(!R_IS_GPR(arg1[0])) || unlikely(!R_IS_GPR(arg2[0])) || unlikely(!R_IS_GPR(arg3[0])) || unlikely(arg4[0] != ARG_IMM))
900                 internal(file_line, "cgen_lea3: invalid arguments");
902         addr[0] = ARG_ADDRESS_2 + shift;
903         addr[1] = arg2[0];
904         addr[2] = arg3[0];
905         memcpy(&addr[3], &arg4[1], 8);
907         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, X86_LEA_R16_RM16, size, true, arg1[0], addr));
909         return true;
912 static bool attr_w cgen_rot(struct codegen_context *ctx, unsigned size, uint8_t rot, unsigned writes_flags)
914         uint8_t *arg1 = ctx->code_position;
915         uint8_t *arg2 = arg1 + arg_size(*arg1);
916         uint8_t *arg3 = arg2 + arg_size(*arg2);
917         ctx->code_position = arg3 + arg_size(*arg3);
919         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)) {
920                 int32_t sse_prefix;
921                 switch (rot) {
922                         case ROT_SHL:   sse_prefix = SSE_PREFIX_66; break;
923                         case ROT_SAR:   sse_prefix = SSE_PREFIX_F3; break;
924                         case ROT_SHR:   sse_prefix = SSE_PREFIX_F2; break;
925                         default:        internal(file_line, "cgen_rot: invalid rotation %x", rot);
926                 }
927                 g(cgen_sse_insn(ctx, sse_prefix + force_vex, PREFIX_0F_38, X86_0F_38_ROTX, size == OP_SIZE_8, arg1[0], arg3[0], arg2));
928                 return true;
929         }
931         if (arg1[0] != arg2[0])
932                 internal(file_line, "cgen_rot: invalid arguments: %x, %02x, %02x, %02x", rot, arg1[0], arg2[0], arg3[0]);
934         if (arg3[0] == R_CX) {
935                 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, size == OP_SIZE_1 ? X86_ROT_RM8_CL : X86_ROT_RM16_CL, size, false, rot, arg1));
936         } else if (likely(arg3[0] == ARG_IMM)) {
937                 int64_t imm;
938                 imm = get_imm(&arg3[1]);
939                 if (imm == 1) {
940                         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, size == OP_SIZE_1 ? X86_ROT_RM8_1 : X86_ROT_RM16_1, size, false, rot, arg1));
941                 } else {
942                         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, size == OP_SIZE_1 ? X86_ROT_RM8_IMM8 : X86_ROT_RM16_IMM8, size, false, rot, arg1));
943                         cgen_one(imm);
944                 }
945         } else {
946                 internal(file_line, "cgen_rot: invalid argument %02x", arg3[0]);
947         }
948         return true;
951 static bool attr_w cgen_btxt(struct codegen_context *ctx, unsigned size, uint8_t bt, uint8_t *arg1, uint8_t *arg2)
953         if (arg2[0] == ARG_IMM) {
954                 g(cgen_rm_insn(ctx, -1, PREFIX_0F, X86_0F_BTX_RM16_IMM8, size, false, X86_0F_BTX_BT_RM16_IMM8 + bt, arg1));
955                 cgen_one(arg2[1]);
956         } else {
957                 g(cgen_rm_insn(ctx, -1, PREFIX_0F, X86_0F_BT_RM16_R16 + bt * 8, size, true, arg2[0], arg1));
958         }
959         return true;
962 static bool attr_w cgen_bt(struct codegen_context *ctx, unsigned size)
964         uint8_t *arg1 = ctx->code_position;
965         uint8_t *arg2 = arg1 + arg_size(*arg1);
966         ctx->code_position = arg2 + arg_size(*arg2);
968         return cgen_btxt(ctx, size, BTX_BT, arg1, arg2);
971 static bool attr_w cgen_btx(struct codegen_context *ctx, unsigned size, uint8_t bt)
973         uint8_t *arg1 = ctx->code_position;
974         uint8_t *arg2 = arg1 + arg_size(*arg1);
975         uint8_t *arg3 = arg2 + arg_size(*arg2);
976         ctx->code_position = arg3 + arg_size(*arg3);
978         if (arg1[0] != arg2[0])
979                 internal(file_line, "cgen_btx: invalid arguments");
981         return cgen_btxt(ctx, size, bt, arg1, arg3);
984 static bool attr_w cgen_mul_l(struct codegen_context *ctx, unsigned size, bool sgn)
986         uint8_t *arg1, *arg2, *arg3, *arg4;
987         uint32_t reg_up;
988         arg1 = ctx->code_position;
989         arg2 = arg1 + arg_size(*arg1);
990         arg3 = arg2 + arg_size(*arg2);
991         arg4 = arg3 + arg_size(*arg3);
992         ctx->code_position = arg4 + arg_size(*arg4);
993         reg_up = size == OP_SIZE_1 ? R_AX : R_DX;
994         if (unlikely(arg1[0] != R_AX) || unlikely(arg2[0] != reg_up) || unlikely(arg3[0] != R_AX) || unlikely(arg4[0] == ARG_IMM))
995                 internal(file_line, "cgen_mul_l: invalid mul arguments");
997         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));
998         return true;
1001 static bool attr_w cgen_div_l(struct codegen_context *ctx, unsigned size, bool sgn)
1003         uint8_t *arg1, *arg2, *arg3, *arg4, *arg5;
1004         uint32_t reg_up;
1005         arg1 = ctx->code_position;
1006         arg2 = arg1 + arg_size(*arg1);
1007         arg3 = arg2 + arg_size(*arg2);
1008         arg4 = arg3 + arg_size(*arg3);
1009         arg5 = arg4 + arg_size(*arg4);
1010         ctx->code_position = arg5 + arg_size(*arg5);
1011         reg_up = size == OP_SIZE_1 ? R_AX : R_DX;
1012         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))
1013                 internal(file_line, "cgen_div_l: invalid div arguments");
1015         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));
1016         return true;
1019 static bool attr_w cgen_cmov(struct codegen_context *ctx, unsigned size, unsigned cond)
1021         uint8_t *arg1 = ctx->code_position;
1022         uint8_t *arg2 = arg1 + arg_size(*arg1);
1023         uint8_t *arg3 = arg2 + arg_size(*arg2);
1024         ctx->code_position = arg3 + arg_size(*arg3);
1025         if (unlikely(arg1[0] != arg2[0]))
1026                 internal(file_line, "cgen_cmov: invalid arguments");
1027         g(cgen_rm_insn(ctx, -1, PREFIX_0F, X86_0F_CMOVCC_R16_RM16 + cond, size, true, arg1[0], arg3));
1028         return true;
1031 static bool attr_w cgen_memcpy(struct codegen_context *ctx)
1033         int64_t disp_dest, disp_src;
1034         uint8_t *arg1, *arg2, *arg3;
1035         arg1 = ctx->code_position;
1036         arg2 = arg1 + arg_size(*arg1);
1037         arg3 = arg2 + arg_size(*arg2);
1038         ctx->code_position = arg3 + arg_size(*arg3);
1039         if (unlikely(arg1[0] != ARG_ADDRESS_1_POST_I) || unlikely(arg2[0] != ARG_ADDRESS_1_POST_I) || unlikely(arg3[0] != R_CX))
1040                 goto invl;
1041         if (unlikely(arg1[1] != R_DI) || unlikely(arg2[1] != R_SI))
1042                 goto invl;
1043         disp_dest = get_imm(&arg1[2]);
1044         disp_src = get_imm(&arg2[2]);
1045         if (unlikely(disp_dest != 0) || unlikely(disp_src != 0))
1046                 goto invl;
1048         cgen_one(X86_REPE);
1049         cgen_one(X86_MOVSB);
1050         return true;
1052 invl:
1053         internal(file_line, "cgen_memcpy: invalid arguments %02x, %02x, %02x", *arg1, *arg2, *arg3);
1054         return false;
1057 static bool attr_w cgen_memset(struct codegen_context *ctx)
1059         int64_t disp_dest;
1060         uint8_t *arg1, *arg2, *arg3;
1061         arg1 = ctx->code_position;
1062         arg2 = arg1 + arg_size(*arg1);
1063         arg3 = arg2 + arg_size(*arg2);
1064         ctx->code_position = arg3 + arg_size(*arg3);
1065         if (unlikely(arg1[0] != ARG_ADDRESS_1_POST_I) || unlikely(arg2[0] != R_CX) || unlikely(arg3[0] != R_AX))
1066                 goto invl;
1067         if (unlikely(arg1[1] != R_DI))
1068                 goto invl;
1069         disp_dest = get_imm(&arg1[2]);
1070         if (unlikely(disp_dest != 0))
1071                 goto invl;
1073         cgen_one(X86_REPE);
1074         cgen_one(X86_STOSB);
1075         return true;
1077 invl:
1078         internal(file_line, "cgen_memset: invalid arguments %02x, %02x, %02x", *arg1, *arg2, *arg3);
1079         return false;
1082 static bool attr_w cgen_sse_cmp(struct codegen_context *ctx, unsigned size)
1084         uint8_t *arg1 = ctx->code_position;
1085         uint8_t *arg2 = arg1 + arg_size(*arg1);
1086         ctx->code_position = arg2 + arg_size(*arg2);
1087         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));
1088         return true;
1091 static bool attr_w cgen_sse_alu(struct codegen_context *ctx, unsigned size, unsigned alu)
1093         uint8_t opcode;
1094         uint8_t *arg1 = ctx->code_position;
1095         uint8_t *arg2 = arg1 + arg_size(*arg1);
1096         uint8_t *arg3 = arg2 + arg_size(*arg2);
1097         ctx->code_position = arg3 + arg_size(*arg3);
1098         switch (alu) {
1099                 case FP_ALU_ADD:        opcode = X86_0F_ADDPS_X128_M32; break;
1100                 case FP_ALU_SUB:        opcode = X86_0F_SUBPS_X128_M32; break;
1101                 case FP_ALU_MUL:        opcode = X86_0F_MULPS_X128_M32; break;
1102                 case FP_ALU_DIV:        opcode = X86_0F_DIVPS_X128_M32; break;
1103                 default:                internal(file_line, "cgen_sse_alu: invalid alu %u", alu);
1104         }
1105         g(cgen_sse_insn(ctx, size == OP_SIZE_4 ? SSE_PREFIX_F3 : SSE_PREFIX_F2, PREFIX_0F, opcode, false, arg1[0], arg2[0], arg3));
1106         return true;
1109 static bool attr_w cgen_sse_alu1(struct codegen_context *ctx, unsigned size, unsigned alu)
1111         uint8_t opcode;
1112         unsigned sse_pfx, sse_op_map;
1113         uint8_t *arg1 = ctx->code_position;
1114         uint8_t *arg2 = arg1 + arg_size(*arg1);
1115         ctx->code_position = arg2 + arg_size(*arg2);
1116         switch (alu) {
1117                 case FP_ALU1_SQRT:      if (size == OP_SIZE_4) {
1118                                                 sse_pfx = SSE_PREFIX_F3;
1119                                         } else if (size == OP_SIZE_8) {
1120                                                 sse_pfx = SSE_PREFIX_F2;
1121                                         } else {
1122                                                 goto fail;
1123                                         }
1124                                         sse_op_map = PREFIX_0F;
1125                                         opcode = X86_0F_SQRTPS_X128_M32;
1126                                         break;
1127                 case FP_ALU1_ROUND:
1128                 case FP_ALU1_FLOOR:
1129                 case FP_ALU1_CEIL:
1130                 case FP_ALU1_TRUNC:     sse_pfx = SSE_PREFIX_66;
1131                                         sse_op_map = PREFIX_0F_3A;
1132                                         if (size == OP_SIZE_4) {
1133                                                 opcode = X86_0F_3A_ROUNDSS_X128_M32;
1134                                         } else if (size == OP_SIZE_8) {
1135                                                 opcode = X86_0F_3A_ROUNDSD_X128_M64;
1136                                         } else {
1137                                                 goto fail;
1138                                         }
1139                                         break;
1140                 fail:
1141                 default:                internal(file_line, "cgen_sse_alu1: invalid alu %u, %u", alu, size);
1142         }
1143         g(cgen_sse_insn(ctx, sse_pfx, sse_op_map, opcode, false, arg1[0], arg1[0], arg2));
1144         if (OP_IS_ROUND(alu))
1145                 cgen_one(alu - FP_ALU1_ROUND);
1146         return true;
1149 static bool attr_w cgen_sse_from_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
1151         uint8_t *arg1 = ctx->code_position;
1152         uint8_t *arg2 = arg1 + arg_size(*arg1);
1153         ctx->code_position = arg2 + arg_size(*arg2);
1154         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));
1155         return true;
1158 static bool attr_w cgen_sse_to_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
1160         uint8_t *arg1 = ctx->code_position;
1161         uint8_t *arg2 = arg1 + arg_size(*arg1);
1162         ctx->code_position = arg2 + arg_size(*arg2);
1163         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));
1164         return true;
1167 static bool attr_w cgen_sse_cvt(struct codegen_context *ctx, unsigned from_op_size, unsigned to_op_size)
1169         uint8_t *arg1 = ctx->code_position;
1170         uint8_t *arg2 = arg1 + arg_size(*arg1);
1171         ctx->code_position = arg2 + arg_size(*arg2);
1172         if (from_op_size == OP_SIZE_2 && to_op_size == OP_SIZE_4) {
1173                 g(cgen_sse_insn(ctx, SSE_PREFIX_66, PREFIX_0F_38, X86_0F_38_CVTPH2PS_X128_RM64, false, arg1[0], 0, arg2));
1174                 return true;
1175         } else if (from_op_size == OP_SIZE_4 && to_op_size == OP_SIZE_2) {
1176                 g(cgen_sse_insn(ctx, SSE_PREFIX_66, PREFIX_0F_3A, X86_0F_3A_CVTPS2PH_RM64_X128, false, arg2[0], 0, arg1));
1177                 cgen_one(0x04);
1178                 return true;
1179         }
1180         internal(file_line, "cgen_sse_cvt: unsupported arguments %u, %u", from_op_size, to_op_size);
1181         return false;
1184 static bool attr_w cgen_x87_fld(struct codegen_context *ctx, unsigned size)
1186         unsigned c1, c2;
1187         uint8_t *arg1 = ctx->code_position;
1188         ctx->code_position = arg1 + arg_size(*arg1);
1189         if (arg1[0] >= R_ST0 && arg1[0] <= R_ST7)
1190                 size = OP_SIZE_4;
1191         switch (size) {
1192                 case OP_SIZE_4:
1193                         c1 = X87_FLD_RM32; c2 = X87_FLD_RM32_X; break;
1194                 case OP_SIZE_8:
1195                         c1 = X87_FLD_M64; c2 = X87_FLD_M64_X; break;
1196                 case OP_SIZE_10:
1197                         c1 = X87_FLD_M80; c2 = X87_FLD_M80_X; break;
1198                 default:
1199                         internal(file_line, "cgen_x87_fld: invalid size %u", size);
1200         }
1201         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, c1, OP_SIZE_4, false, c2, arg1));
1202         return true;
1205 static bool attr_w cgen_x87_fild(struct codegen_context *ctx, unsigned size)
1207         unsigned c1, c2;
1208         uint8_t *arg1 = ctx->code_position;
1209         ctx->code_position = arg1 + arg_size(*arg1);
1210         switch (size) {
1211                 case OP_SIZE_2:
1212                         c1 = X87_FILD_M16; c2 = X87_FILD_M16_X; break;
1213                 case OP_SIZE_4:
1214                         c1 = X87_FILD_M32; c2 = X87_FILD_M32_X; break;
1215                 case OP_SIZE_8:
1216                         c1 = X87_FILD_M64; c2 = X87_FILD_M64_X; break;
1217                 default:
1218                         internal(file_line, "cgen_x87_fild: invalid size %u", size);
1219         }
1220         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, c1, OP_SIZE_4, false, c2, arg1));
1221         return true;
1224 static bool attr_w cgen_x87_fstp(struct codegen_context *ctx, unsigned size)
1226         unsigned c1, c2;
1227         uint8_t *arg1 = ctx->code_position;
1228         ctx->code_position = arg1 + arg_size(*arg1);
1229         if (arg1[0] >= R_ST0 && arg1[0] <= R_ST7)
1230                 size = OP_SIZE_8;
1231         switch (size) {
1232                 case OP_SIZE_4:
1233                         c1 = X87_FSTP_M32; c2 = X87_FSTP_M32_X; break;
1234                 case OP_SIZE_8:
1235                         c1 = X87_FSTP_RM64; c2 = X87_FSTP_RM64_X; break;
1236                 case OP_SIZE_10:
1237                         c1 = X87_FSTP_M80; c2 = X87_FSTP_M80_X; break;
1238                 default:
1239                         internal(file_line, "cgen_x87_fstp: invalid size %u", size);
1240         }
1241         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, c1, OP_SIZE_4, false, c2, arg1));
1242         return true;
1245 static bool attr_w cgen_x87_fistp(struct codegen_context *ctx, unsigned size)
1247         unsigned c1, c2;
1248         uint8_t *arg1 = ctx->code_position;
1249         ctx->code_position = arg1 + arg_size(*arg1);
1250         switch (size) {
1251                 case OP_SIZE_2:
1252                         c1 = X87_FISTP_M16; c2 = X87_FISTP_M16_X; break;
1253                 case OP_SIZE_4:
1254                         c1 = X87_FISTP_M32; c2 = X87_FISTP_M32_X; break;
1255                 case OP_SIZE_8:
1256                         c1 = X87_FISTP_M64; c2 = X87_FISTP_M64_X; break;
1257                 default:
1258                         internal(file_line, "cgen_x87_fistp: invalid size %u", size);
1259         }
1260         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, c1, OP_SIZE_4, false, c2, arg1));
1261         return true;
1264 static bool attr_w cgen_x87_fisttp(struct codegen_context *ctx, unsigned size)
1266         unsigned c1, c2;
1267         uint8_t *arg1 = ctx->code_position;
1268         ctx->code_position = arg1 + arg_size(*arg1);
1269         switch (size) {
1270                 case OP_SIZE_2:
1271                         c1 = X87_FISTTP_M16; c2 = X87_FISTTP_M16_X; break;
1272                 case OP_SIZE_4:
1273                         c1 = X87_FISTTP_M32; c2 = X87_FISTTP_M32_X; break;
1274                 case OP_SIZE_8:
1275                         c1 = X87_FISTTP_M64; c2 = X87_FISTTP_M64_X; break;
1276                 default:
1277                         internal(file_line, "cgen_x87_fisttp: invalid size %u", size);
1278         }
1279         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, c1, OP_SIZE_4, false, c2, arg1));
1280         return true;
1283 static bool attr_w cgen_x87_fcomp(struct codegen_context *ctx, unsigned size)
1285         unsigned c1, c2;
1286         uint8_t *arg1 = ctx->code_position;
1287         ctx->code_position = arg1 + arg_size(*arg1);
1288         if (arg1[0] < ARG_REGS_MAX) {
1289                 c1 = X87_FALU_ST_RM32;
1290         } else switch (size) {
1291                 case OP_SIZE_4:
1292                         c1 = X87_FALU_ST_RM32; break;
1293                 case OP_SIZE_8:
1294                         c1 = X87_FALU_ST_M64; break;
1295                 default:
1296                         internal(file_line, "cgen_x87_fcomp: invalid size %u", size);
1297         }
1298         c2 = X87_ALU_FCOMP;
1299         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, c1, OP_SIZE_4, false, c2, arg1));
1300         return true;
1303 static bool attr_w cgen_x87_alu(struct codegen_context *ctx, unsigned size, unsigned aux)
1305         unsigned c1, c2;
1306         uint8_t *arg1 = ctx->code_position;
1307         ctx->code_position = arg1 + arg_size(*arg1);
1308         if (arg1[0] < ARG_REGS_MAX) {
1309                 c1 = X87_FALU_ST_RM32;
1310         } else switch (size) {
1311                 case OP_SIZE_4:
1312                         c1 = X87_FALU_ST_RM32; break;
1313                 case OP_SIZE_8:
1314                         c1 = X87_FALU_ST_M64; break;
1315                 default:
1316                         internal(file_line, "cgen_x87_alu: invalid size %u", size);
1317         }
1318         switch (aux) {
1319                 case FP_ALU_ADD:
1320                         c2 = X87_ALU_ADD; break;
1321                 case FP_ALU_SUB:
1322                         c2 = X87_ALU_SUB; break;
1323                 case FP_ALU_MUL:
1324                         c2 = X87_ALU_MUL; break;
1325                 case FP_ALU_DIV:
1326                         c2 = X87_ALU_DIV; break;
1327                 default:
1328                         internal(file_line, "cgen_x87_fst: invalid operation %u", aux);
1329         }
1330         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, c1, OP_SIZE_4, false, c2, arg1));
1331         return true;
1334 static bool attr_w cgen_x87_alup(struct codegen_context *ctx, unsigned aux)
1336         unsigned c2;
1337         uint8_t *arg1 = ctx->code_position;
1338         ctx->code_position = arg1 + arg_size(*arg1);
1339         switch (aux) {
1340                 case FP_ALU_ADD:
1341                         c2 = X87_ALU_ADD; break;
1342                 case FP_ALU_SUB:
1343                         c2 = X87_ALU_SUB; break;
1344                 case FP_ALU_MUL:
1345                         c2 = X87_ALU_MUL; break;
1346                 case FP_ALU_DIV:
1347                         c2 = X87_ALU_DIV; break;
1348                 default:
1349                         internal(file_line, "cgen_x87_fstp: invalid operation %u", aux);
1350         }
1351         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, X87_FALUP_STi_ST0, OP_SIZE_4, false, c2, arg1));
1352         return true;
1355 static bool attr_w resolve_relocation(struct codegen_context *ctx, struct relocation *reloc)
1357         int64_t offs = (int64_t)ctx->label_to_pos[reloc->label_id] - (int64_t)(reloc->position + (reloc->length == JMP_SHORT ? 1 : 4));
1358         switch (reloc->length) {
1359                 case JMP_SHORT: {
1360                         int8_t i8;
1361                         if (!imm_is_8bit(offs))
1362                                 return false;
1363                         i8 = offs;
1364                         memcpy(ctx->mcode + reloc->position, &i8, 1);
1365                         return true;
1366                 }
1367                 case JMP_LONG: {
1368                         int32_t i32;
1369                         if (!imm_is_32bit(offs))
1370                                 return false;
1371                         i32 = offs;
1372                         memcpy(ctx->mcode + reloc->position, &i32, 4);
1373                         return true;
1374                 }
1375                 default: {
1376                         internal(file_line, "resolve_relocation: invalid relocation length %u", reloc->length);
1377                         return false;
1378                 }
1379         }
1382 static bool attr_w cgen_insn(struct codegen_context *ctx, uint32_t insn)
1384         uint8_t imm8;
1385         uint16_t imm16;
1386         /*debug("insn: %08x", insn);*/
1387         switch (insn_opcode(insn)) {
1388                 case INSN_ENTRY:
1389                         g(cgen_entry(ctx));
1390                         return true;
1391                 case INSN_LABEL:
1392                         g(cgen_label(ctx));
1393                         return true;
1394                 case INSN_RET:
1395                         cgen_one(X86_RET);
1396                         return true;
1397                 case INSN_RET_IMM:
1398                         imm16 = cget_two(ctx);
1399                         cgen_one(X86_RET_IMM16);
1400                         cgen_two(imm16);
1401                         return true;
1402                 case INSN_PUSH:
1403                         g(cgen_push(ctx));
1404                         return true;
1405                 case INSN_POP:
1406                         g(cgen_pop(ctx));
1407                         return true;
1408                 case INSN_CALL_INDIRECT:
1409                         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, X86_FF, OP_SIZE_4, false, X86_FF_CALL_INDIRECT, ctx->code_position));
1410                         ctx->code_position += arg_size(*ctx->code_position);
1411                         return true;
1412                 case INSN_MOV:
1413                         g(cgen_mov(ctx, insn_op_size(insn)));
1414                         return true;
1415                 case INSN_MOVSX:
1416                         g(cgen_movsx(ctx, insn_op_size(insn)));
1417                         return true;
1418                 case INSN_CMP:
1419                         g(cgen_alu(ctx, insn_op_size(insn), 7, insn_writes_flags(insn)));
1420                         return true;
1421                 case INSN_TEST:
1422                         g(cgen_test(ctx, insn_op_size(insn)));
1423                         return true;
1424                 case INSN_ALU:
1425                 case INSN_ALU_FLAGS:
1426                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1427                                 goto invalid_insn;
1428                         if (!insn_writes_flags(insn) && insn_op_size(insn) <= OP_SIZE_8) {
1429                                 if (unlikely(insn_aux(insn) != ALU_ADD) && unlikely(insn_aux(insn) != ALU_SUB))
1430                                         goto invalid_insn;
1431                                 g(cgen_lea(ctx, insn_op_size(insn), insn_aux(insn) == ALU_SUB));
1432                                 return true;
1433                         }
1434                         g(cgen_alu(ctx, insn_op_size(insn), insn_aux(insn), insn_writes_flags(insn)));
1435                         return true;
1436                 case INSN_ALU_PARTIAL:
1437                 case INSN_ALU_FLAGS_PARTIAL:
1438                         if (unlikely(insn_op_size(insn) >= OP_SIZE_4))
1439                                 goto invalid_insn;
1440                         g(cgen_alu(ctx, insn_op_size(insn), insn_aux(insn), insn_writes_flags(insn)));
1441                         return true;
1442                 case INSN_ALU1:
1443                 case INSN_ALU1_FLAGS:
1444                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1445                                 goto invalid_insn;
1446                         g(cgen_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
1447                         return true;
1448                 case INSN_ALU1_PARTIAL:
1449                 case INSN_ALU1_FLAGS_PARTIAL:
1450                         if (unlikely(insn_op_size(insn) >= OP_SIZE_4))
1451                                 goto invalid_insn;
1452                         g(cgen_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
1453                         return true;
1454                 case INSN_LEA3:
1455                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1456                                 goto invalid_insn;
1457                         g(cgen_lea3(ctx, insn_op_size(insn), insn_aux(insn)));
1458                         return true;
1459                 case INSN_ROT:
1460                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1461                                 goto invalid_insn;
1462                         g(cgen_rot(ctx, insn_op_size(insn), insn_aux(insn), insn_writes_flags(insn)));
1463                         return true;
1464                 case INSN_ROT_PARTIAL:
1465                         if (unlikely(insn_op_size(insn) >= OP_SIZE_4))
1466                                 goto invalid_insn;
1467                         g(cgen_rot(ctx, insn_op_size(insn), insn_aux(insn), insn_writes_flags(insn)));
1468                         return true;
1469                 case INSN_BT:
1470                         if (unlikely(insn_op_size(insn) == OP_SIZE_1) || unlikely(!insn_writes_flags(insn)))
1471                                 goto invalid_insn;
1472                         g(cgen_bt(ctx, insn_op_size(insn)));
1473                         return true;
1474                 case INSN_BTX:
1475                         if (unlikely(insn_op_size(insn) == OP_SIZE_1) || unlikely(!insn_writes_flags(insn)))
1476                                 goto invalid_insn;
1477                         g(cgen_btx(ctx, insn_op_size(insn), insn_aux(insn)));
1478                         return true;
1479                 case INSN_MUL_L:
1480                         g(cgen_mul_l(ctx, insn_op_size(insn), insn_aux(insn)));
1481                         return true;
1482                 case INSN_DIV_L:
1483                         g(cgen_div_l(ctx, insn_op_size(insn), insn_aux(insn)));
1484                         return true;
1485                 case INSN_CBW:
1486                         if (unlikely(insn_op_size(insn) <= OP_SIZE_2))
1487                                 goto invalid_insn;
1488                         if (insn_op_size(insn) == OP_SIZE_8)
1489                                 cgen_rex(X86_REX | X86_REX_W);
1490                         if (unlikely(cget_one(ctx) != R_AX))
1491                                 goto invalid_insn;
1492                         if (unlikely(cget_one(ctx) != R_AX))
1493                                 goto invalid_insn;
1494                         cgen_one(X86_CBW);
1495                         return true;
1496                 case INSN_CBW_PARTIAL:
1497                         if (unlikely(insn_op_size(insn) != OP_SIZE_2))
1498                                 goto invalid_insn;
1499                         if (unlikely(cget_one(ctx) != R_AX))
1500                                 goto invalid_insn;
1501                         if (unlikely(cget_one(ctx) != R_AX))
1502                                 goto invalid_insn;
1503                         cgen_one(X86_OP_SIZE);
1504                         cgen_one(X86_CBW);
1505                         return true;
1506                 case INSN_CWD:
1507                         if (unlikely(insn_op_size(insn) <= OP_SIZE_2))
1508                                 goto invalid_insn;
1509                         if (unlikely(cget_one(ctx) != R_DX))
1510                                 goto invalid_insn;
1511                         if (unlikely(cget_one(ctx) != R_AX))
1512                                 goto invalid_insn;
1513                         if (insn_op_size(insn) == OP_SIZE_8)
1514                                 cgen_rex(X86_REX | X86_REX_W);
1515                         cgen_one(X86_CWD);
1516                         return true;
1517                 case INSN_CWD_PARTIAL:
1518                         if (unlikely(insn_op_size(insn) != OP_SIZE_2))
1519                                 goto invalid_insn;
1520                         if (unlikely(cget_one(ctx) != R_DX))
1521                                 goto invalid_insn;
1522                         if (unlikely(cget_one(ctx) != R_AX))
1523                                 goto invalid_insn;
1524                         if (unlikely(cget_one(ctx) != R_DX))
1525                                 goto invalid_insn;
1526                         cgen_one(X86_OP_SIZE);
1527                         cgen_one(X86_CWD);
1528                         return true;
1529                 case INSN_SET_COND:
1530                         if (unlikely(insn_op_size(insn) != OP_SIZE_1))
1531                                 goto invalid_insn;
1532                         g(cgen_rm_insn(ctx, -1, PREFIX_0F, X86_0F_SETCC_RM8 + (insn_aux(insn) & 0xf), OP_SIZE_1, false, 0, ctx->code_position));
1533                         ctx->code_position += arg_size(*ctx->code_position);
1534                         return true;
1535                 case INSN_SET_COND_PARTIAL:
1536                         if (unlikely(insn_op_size(insn) != OP_SIZE_1))
1537                                 goto invalid_insn;
1538                         g(cgen_rm_insn(ctx, -1, PREFIX_0F, X86_0F_SETCC_RM8 + (insn_aux(insn) & 0xf), OP_SIZE_1, false, 0, ctx->code_position));
1539                         ctx->code_position += arg_size(*ctx->code_position);
1540                         ctx->code_position += arg_size(*ctx->code_position);
1541                         return true;
1542                 case INSN_CMOV:
1543                 case INSN_CMOV_XCC:
1544                         if (unlikely(insn_op_size(insn) == OP_SIZE_1))
1545                                 goto invalid_insn;
1546                         g(cgen_cmov(ctx, insn_op_size(insn), insn_aux(insn)));
1547                         return true;
1548                 case INSN_MEMCPY:
1549                         g(cgen_memcpy(ctx));
1550                         return true;
1551                 case INSN_MEMSET:
1552                         g(cgen_memset(ctx));
1553                         return true;
1554                 case INSN_FP_CMP:
1555                         g(cgen_sse_cmp(ctx, insn_op_size(insn)));
1556                         return true;
1557                 case INSN_FP_ALU:
1558                         g(cgen_sse_alu(ctx, insn_op_size(insn), insn_aux(insn)));
1559                         return true;
1560                 case INSN_FP_ALU1:
1561                         g(cgen_sse_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
1562                         return true;
1563                 case INSN_FP_FROM_INT32:
1564                 case INSN_FP_FROM_INT64:
1565                         g(cgen_sse_from_int(ctx, insn_opcode(insn) == INSN_FP_FROM_INT32 ? OP_SIZE_4 : OP_SIZE_8, insn_op_size(insn)));
1566                         return true;
1567                 case INSN_FP_TO_INT32:
1568                 case INSN_FP_TO_INT64:
1569                         g(cgen_sse_to_int(ctx, insn_opcode(insn) == INSN_FP_TO_INT32 ? OP_SIZE_4 : OP_SIZE_8, insn_op_size(insn)));
1570                         return true;
1571                 case INSN_FP_CVT:
1572                         g(cgen_sse_cvt(ctx, insn_op_size(insn), insn_aux(insn)));
1573                         return true;
1574                 case INSN_X87_FLD:
1575                         g(cgen_x87_fld(ctx, insn_op_size(insn)));
1576                         return true;
1577                 case INSN_X87_FILD:
1578                         g(cgen_x87_fild(ctx, insn_op_size(insn)));
1579                         return true;
1580                 case INSN_X87_FSTP:
1581                         g(cgen_x87_fstp(ctx, insn_op_size(insn)));
1582                         return true;
1583                 case INSN_X87_FISTP:
1584                         g(cgen_x87_fistp(ctx, insn_op_size(insn)));
1585                         return true;
1586                 case INSN_X87_FISTTP:
1587                         g(cgen_x87_fisttp(ctx, insn_op_size(insn)));
1588                         return true;
1589                 case INSN_X87_FCOMP:
1590                         g(cgen_x87_fcomp(ctx, insn_op_size(insn)));
1591                         return true;
1592                 case INSN_X87_FCOMPP:
1593                         cgen_one(X87_FCOMPP);
1594                         cgen_one(X87_FCOMPP_2);
1595                         return true;
1596                 case INSN_X87_FCOMIP:
1597                         imm8 = cget_one(ctx);
1598                         cgen_one(X87_FCOMIP);
1599                         cgen_one(X87_FCOMIP_2 + (imm8 & 7));
1600                         return true;
1601                 case INSN_X87_ALU:
1602                         g(cgen_x87_alu(ctx, insn_op_size(insn), insn_aux(insn)));
1603                         return true;
1604                 case INSN_X87_ALUP:
1605                         g(cgen_x87_alup(ctx, insn_aux(insn)));
1606                         return true;
1607                 case INSN_X87_FCHS:
1608                         cgen_one(X87_FCHS);
1609                         cgen_one(X87_FCHS_2);
1610                         return true;
1611                 case INSN_X87_FSQRT:
1612                         cgen_one(X87_FSQRT);
1613                         cgen_one(X87_FSQRT_2);
1614                         return true;
1615                 case INSN_X87_FRNDINT:
1616                         cgen_one(X87_FRNDINT);
1617                         cgen_one(X87_FRNDINT_2);
1618                         return true;
1619                 case INSN_X87_FNSTSW:
1620                         if (unlikely(cget_one(ctx) != R_AX))
1621                                 goto invalid_insn;
1622                         if (unlikely(cget_one(ctx) != R_AX))
1623                                 goto invalid_insn;
1624                         cgen_one(X87_FNSTSW);
1625                         cgen_one(X87_FNSTSW_2);
1626                         return true;
1627                 case INSN_X87_FLDCW:
1628                         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, X87_FLDCW, OP_SIZE_4, false, X87_FLDCW_X, ctx->code_position));
1629                         ctx->code_position += arg_size(*ctx->code_position);
1630                         return true;
1631                 case INSN_JMP:
1632                         if (insn_jump_size(insn) == JMP_SHORT || insn_jump_size(insn) == JMP_SHORTEST) {
1633                                 cgen_one(X86_JMP_8);
1634                                 g(add_relocation(ctx, JMP_SHORT, 0, NULL));
1635                                 cgen_one(0);
1636                         } else if (likely(insn_jump_size(insn) == JMP_LONG)) {
1637                                 cgen_one(X86_JMP_16);
1638                                 g(add_relocation(ctx, JMP_LONG, 0, NULL));
1639                                 cgen_four(0);
1640                         } else {
1641                                 goto invalid_insn;
1642                         }
1643                         return true;
1644                 case INSN_JMP_COND:
1645                         if (insn_jump_size(insn) == JMP_SHORT || insn_jump_size(insn) == JMP_SHORTEST) {
1646                                 cgen_one(X86_JCC_8 + (insn_aux(insn) & 0xf));
1647                                 g(add_relocation(ctx, JMP_SHORT, 0, NULL));
1648                                 cgen_one(0);
1649                         } else if (likely(insn_jump_size(insn) == JMP_LONG)) {
1650                                 cgen_one(X86_0F);
1651                                 cgen_one(X86_0F_JCC_16 + (insn_aux(insn) & 0xf));
1652                                 g(add_relocation(ctx, JMP_LONG, 0, NULL));
1653                                 cgen_four(0);
1654                         } else {
1655                                 goto invalid_insn;
1656                         }
1657                         return true;
1658                 case INSN_JMP_INDIRECT:
1659                         g(cgen_rm_insn(ctx, -1, PREFIX_NONE, X86_FF, OP_SIZE_4, false, X86_FF_JMP_INDIRECT, ctx->code_position));
1660                         ctx->code_position += arg_size(*ctx->code_position);
1661                         return true;
1662                 default:
1663                 invalid_insn:
1664                         internal(file_line, "cgen_insn: invalid insn %08lx", (unsigned long)insn);
1665                         return false;
1666         }