2 * Copyright (C) 2024 Mikulas Patocka
4 * This file is part of Ajla.
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
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.
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/>.
21 #define X86_ALU_RM8_R8 0x00
22 #define X86_ALU_RM16_R16 0x01
23 #define X86_ALU_R8_RM8 0x02
24 #define X86_ALU_R16_RM16 0x03
25 #define X86_ALU_AL_IMM8 0x04
26 #define X86_ALU_AX_IMM16 0x05
33 #define X86_REX_B 0x01
34 #define X86_REX_X 0x02
35 #define X86_REX_R 0x04
36 #define X86_REX_W 0x08
37 #define X86_INC_R16 0x40
38 #define X86_DEC_R16 0x48
39 #define X86_PUSH_R16 0x50
40 #define X86_POP_R16 0x58
42 #define X86_MOVSXD 0x63
45 #define X86_OP_SIZE 0x66
46 #define X86_PUSH_IMM16 0x68
47 #define X86_IMUL_R16_RM16_IMM16 0x69
48 #define X86_PUSH_IMM8 0x6a
49 #define X86_IMUL_R16_RM16_IMM8 0x6b
50 #define X86_JCC_8 0x70
51 #define X86_ALU_RM8_IMM8 0x80
52 #define X86_ALU_RM16_IMM16 0x81
53 #define X86_ALU_RM16_IMM8 0x83
54 #define X86_TEST_RM8_R8 0x84
55 #define X86_TEST_RM16_R16 0x85
56 #define X86_MOV_RM8_R8 0x88
57 #define X86_MOV_RM16_R16 0x89
58 #define X86_MOV_R8_RM8 0x8a
59 #define X86_MOV_R16_RM16 0x8b
60 #define X86_LEA_R16_RM16 0x8d
62 #define X86_8F_POP 0x0
65 #define X86_MOV_AL_M16 0xa0
66 #define X86_MOV_AX_M16 0xa1
67 #define X86_MOV_M16_AL 0xa2
68 #define X86_MOV_M16_AX 0xa3
69 #define X86_MOVSB 0xa4
70 #define X86_TEST_AL_IMM8 0xa8
71 #define X86_TEST_AX_IMM16 0xa9
72 #define X86_STOSB 0xaa
73 #define X86_MOV_R16_IMM16 0xb8
74 #define X86_ROT_RM8_IMM8 0xc0
75 #define X86_ROT_RM16_IMM8 0xc1
76 #define X86_RET_IMM16 0xc2
78 #define X86_VEX_3 0xc4
79 #define X86_VEX_2 0xc5
80 #define X86_MOV_RM8_IMM8 0xc6
81 #define X86_MOV_RM16_IMM16 0xc7
82 #define X86_MOV_R16_IMM16_REG 0x0
83 #define X86_ROT_RM8_1 0xd0
84 #define X86_ROT_RM16_1 0xd1
85 #define X86_ROT_RM8_CL 0xd2
86 #define X86_ROT_RM16_CL 0xd3
88 #define X86_REX2_B3 0x01
89 #define X86_REX2_X3 0x02
90 #define X86_REX2_R3 0x04
91 #define X86_REX2_W 0x08
92 #define X86_REX2_B4 0x10
93 #define X86_REX2_X4 0x20
94 #define X86_REX2_R4 0x40
95 #define X86_REX2_M0 0x80
96 #define X86_JMP_16 0xe9
97 #define X86_JMP_8 0xeb
98 #define X86_REPNE 0xf2
101 #define X86_F6_TEST_RM8_IMM8 0x0
102 #define X86_F6_NOT_RM8 0x2
103 #define X86_F6_NEG_RM8 0x3
104 #define X86_F6_MUL_RM8 0x4
105 #define X86_F6_IMUL_RM8 0x5
106 #define X86_F6_DIV_RM8 0x6
107 #define X86_F6_IDIV_RM8 0x7
109 #define X86_F7_TEST_RM16_IMM16 0x0
110 #define X86_F7_NOT_RM16 0x2
111 #define X86_F7_NEG_RM16 0x3
112 #define X86_F7_MUL_RM16 0x4
113 #define X86_F7_IMUL_RM16 0x5
114 #define X86_F7_DIV_RM16 0x6
115 #define X86_F7_IDIV_RM16 0x7
117 #define X86_FE_INC_RM8 0x0
118 #define X86_FE_DEC_RM8 0x1
120 #define X86_FF_INC_RM16 0x0
121 #define X86_FF_DEC_RM16 0x1
122 #define X86_FF_CALL_INDIRECT 0x2
123 #define X86_FF_JMP_INDIRECT 0x4
124 #define X86_FF_PUSH 0x6
126 #define X86_0F_MOVSS_X128_M32 0x10
127 #define X86_0F_MOVSS_M32_X128 0x11
128 #define X86_0F_MOVAPS_X128_M128 0x28
129 #define X86_0F_MOVAPS_M128_X128 0x29
130 #define X86_0F_CVTSI2SS_X128_RM32 0x2a
131 #define X86_0F_CVTTSS2SI_X128_RM32 0x2c
132 #define X86_0F_UCOMISS_X128_RM32 0x2e
133 #define X86_0F_38 0x38
134 #define X86_0F_3A 0x3a
135 #define X86_0F_CMOVCC_R16_RM16 0x40
136 #define X86_0F_SQRTPS_X128_M32 0x51
137 #define X86_0F_ANDPS_X128_M128 0x54
138 #define X86_0F_ANDNPS_X128_M128 0x55
139 #define X86_0F_ORPS_X128_M128 0x56
140 #define X86_0F_XORPS_X128_M128 0x57
141 #define X86_0F_ADDPS_X128_M32 0x58
142 #define X86_0F_MULPS_X128_M32 0x59
143 #define X86_0F_SUBPS_X128_M32 0x5c
144 #define X86_0F_DIVPS_X128_M32 0x5e
145 #define X86_0F_MOVD_X128_RM32 0x6e
146 #define X86_0F_MOVD_RM32_X128 0x7e
147 #define X86_0F_JCC_16 0x80
148 #define X86_0F_SETCC_RM8 0x90
149 #define X86_0F_BT_RM16_R16 0xa3
150 #define X86_0F_BTS_RM16_R16 0xab
151 #define X86_0F_BTR_RM16_R16 0xb3
152 #define X86_0F_BTX_RM16_IMM8 0xba
153 #define X86_0F_BTX_BT_RM16_IMM8 0x4
154 #define X86_0F_BTX_BTS_RM16_IMM8 0x5
155 #define X86_0F_BTX_BTR_RM16_IMM8 0x6
156 #define X86_0F_BTX_BTC_RM16_IMM8 0x7
157 #define X86_0F_BSWAP 0xc8
158 #define X86_0F_BTC_RM16_R16 0xbb
159 #define X86_0F_IMUL_R16_RM16 0xaf
160 #define X86_0F_MOVZX_R16_RM8 0xb6
161 #define X86_0F_MOVZX_R16_RM16 0xb7
162 #define X86_0F_POPCNT_R16_RM16 0xb8
163 #define X86_0F_BSF_R16_RM16 0xbc
164 #define X86_0F_BSR_R16_RM16 0xbd
165 #define X86_0F_MOVSX_R16_RM8 0xbe
166 #define X86_0F_MOVSX_R16_RM16 0xbf
167 #define X86_0F_PINSRW_X128_RM16_IMM8 0xc4
169 #define X86_0F_38_CVTPH2PS_X128_RM64 0x13
170 #define X86_0F_38_ROTX 0xf7
172 #define X86_0F_3A_ROUNDSS_X128_M32 0x0a
173 #define X86_0F_3A_RNDSCALESH_X128_M16 0x0a
174 #define X86_0F_3A_ROUNDSD_X128_M64 0x0b
175 #define X86_0F_3A_PEXTRW_RM16_X128_IMM8 0x15
176 #define X86_0F_3A_CVTPS2PH_RM64_X128 0x1d
178 #define X86_LEGACY_EVEX_SETCC_R64 0x40
180 #define X86_MAP5_MOVSH_X128_M16 0x10
181 #define X86_MAP5_MOVSH_M16_X128 0x11
182 #define X86_MAP5_CVTSI2SH_X128_RM16 0x2a
183 #define X86_MAP5_UCOMISH_X128_RM16 0x2e
184 #define X86_MAP5_CVTTSH2SI_X128_RM16 0x2c
185 #define X86_MAP5_SQRTPH_X128_M16 0x51
186 #define X86_MAP5_ADDPH_X128_M16 0x58
187 #define X86_MAP5_MULPH_X128_M16 0x59
188 #define X86_MAP5_SUBPH_X128_M16 0x5c
189 #define X86_MAP5_DIVPH_X128_M16 0x5e
191 #define X87_FLD_RM32 0xd9
192 #define X87_FLD_RM32_X 0x0
193 #define X87_FLDCW 0xd9
194 #define X87_FLDCW_X 0x5
195 #define X87_FILD_M32 0xdb
196 #define X87_FILD_M32_X 0x0
197 #define X87_FISTTP_M32 0xdb
198 #define X87_FISTTP_M32_X 0x1
199 #define X87_FISTP_M32 0xdb
200 #define X87_FISTP_M32_X 0x3
201 #define X87_FLD_M80 0xdb
202 #define X87_FLD_M80_X 0x5
203 #define X87_FLD_M64 0xdd
204 #define X87_FLD_M64_X 0x0
205 #define X87_FSTP_M32 0xd9
206 #define X87_FSTP_M32_X 0x3
207 #define X87_FSTP_M80 0xdb
208 #define X87_FSTP_M80_X 0x7
209 #define X87_FSTP_RM64 0xdd
210 #define X87_FSTP_RM64_X 0x3
211 #define X87_FALU_ST_RM32 0xd8
212 #define X87_FCHS 0xd9
213 #define X87_FCHS_2 0xe0
214 #define X87_FSQRT 0xd9
215 #define X87_FSQRT_2 0xfa
216 #define X87_FRNDINT 0xd9
217 #define X87_FRNDINT_2 0xfc
218 #define X87_FALU_ST_M64 0xdc
219 #define X87_FALU_STi_ST 0xdc
220 #define X87_FISTTP_M64 0xdd
221 #define X87_FISTTP_M64_X 0x1
222 #define X87_FALUP_STi_ST0 0xde
223 #define X87_ALU_ADD 0x0
224 #define X87_ALU_MUL 0x1
225 #define X87_ALU_FCOM 0x2
226 #define X87_ALU_FCOMP 0x3
227 #define X87_ALU_SUBR 0x4
228 #define X87_ALU_SUB 0x5
229 #define X87_ALU_DIVR 0x6
230 #define X87_ALU_DIV 0x7
231 #define X87_FCOMPP 0xde
232 #define X87_FCOMPP_2 0xd9
233 #define X87_FILD_M16 0xdf
234 #define X87_FILD_M16_X 0x0
235 #define X87_FISTTP_M16 0xdf
236 #define X87_FISTTP_M16_X 0x1
237 #define X87_FISTP_M16 0xdf
238 #define X87_FISTP_M16_X 0x3
239 #define X87_FILD_M64 0xdf
240 #define X87_FILD_M64_X 0x5
241 #define X87_FISTP_M64 0xdf
242 #define X87_FISTP_M64_X 0x7
243 #define X87_FNSTSW 0xdf
244 #define X87_FNSTSW_2 0xe0
245 #define X87_FCOMIP 0xdf
246 #define X87_FCOMIP_2 0xf0
248 #define SSE_PREFIX_NONE 0
249 #define SSE_PREFIX_66 1
250 #define SSE_PREFIX_F3 2
251 #define SSE_PREFIX_F2 3
253 #define PREFIX_NONE 0
255 #define PREFIX_0F_38 2
256 #define PREFIX_0F_3A 3
257 #define PREFIX_LEGACY_EVEX 4
258 #define PREFIX_MAP5 5
260 static bool attr_w cgen_rex2(struct codegen_context attr_unused *ctx, uint8_t rex2)
263 internal(file_line, "cgen_rex: attempting to generate rex in 32-bit mode: %02x", rex2);
266 if (!(rex2 & 0xf0)) {
267 cgen_one(X86_REX | rex2);
269 if (unlikely(!cpu_test_feature(CPU_FEATURE_apx)))
270 internal(file_line, "cgen_rex2: attempting to generate rex2 without apx: %02x", rex2);
278 #define force_vex 0x10000
279 #define force_evex 0x20000
280 #define force_ndd 0x40000
281 #define SSE_PREFIX_W 0x80000
283 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)
285 uint8_t rex2, mod, rm;
287 int64_t imm = 0; /* avoid warning */
292 if (unlikely(R_IS_XMM(reg)))
294 if (unlikely(R_IS_XMM(arg[0]))) {
295 arg_reg = arg[0] - R_XMM0;
298 if (unlikely(!R_IS_GPR(reg)))
299 internal(file_line, "cgen_rm_insn: invalid register %02x", reg);
303 if (size == OP_SIZE_8)
318 uint8_t *imm_ptr = arg + arg_size(arg[0]) - 8;
319 imm = get_imm(imm_ptr);
320 if (unlikely(!imm_is_32bit(imm)))
321 internal(file_line, "cgen_rm_insn: immediate out of range: %"PRIxMAX"", (uintmax_t)imm);
322 if (arg[0] == ARG_ADDRESS_0) {
332 } else if (imm >= -0x80 && imm <= 0x7f) {
337 if ((arg[1] & 7) == 0x5 && addr_size == 0)
341 else if (addr_size == 1)
345 if (arg[0] == ARG_ADDRESS_1) {
346 if (reg_is_segment(arg[1])) {
347 static const uint8_t segments[6] = { X86_ES, X86_CS, X86_SS, X86_DS, X86_FS, X86_GS };
348 cgen_one(segments[arg[1] - R_ES]);
355 if ((arg[1] & 7) == 0x4) {
363 if (arg[0] >= ARG_ADDRESS_1_2 && arg[0] <= ARG_ADDRESS_1_8) {
364 if (unlikely(arg[1] == R_SP))
365 internal(file_line, "cgen_rm_insn: attemptint to scale SP");
373 sib = ((arg[0] - ARG_ADDRESS_1) << 6) | ((arg[1] & 7) << 3) | 0x5;
376 if (arg[0] >= ARG_ADDRESS_2 && arg[0] <= ARG_ADDRESS_2_8) {
377 if (unlikely(arg[2] == R_SP))
378 internal(file_line, "cgen_rm_insn: attemptint to scale SP");
388 sib = ((arg[0] - ARG_ADDRESS_2) << 6) | ((arg[2] & 7) << 3) | (arg[1] & 7);
391 internal(file_line, "cgen_rm_insn: invalid argument %02x", arg[0]);
395 if (unlikely(sse_prefix >= 0)) {
396 if (likely(cpu_test_feature(CPU_FEATURE_avx)) || (sse_prefix & (force_vex | force_evex | force_ndd))) {
397 if (rex2 & 0xf0 || sse_prefix & 0x1000 || sse_prefix & (force_evex | force_ndd) || test_evex) {
398 /*debug("evex: %02x, %02x, %02x", reg, (sse_prefix >> 8) & 0x1f, arg[0]);*/
399 if (!(sse_prefix & (force_vex | force_ndd))) {
400 if (sse_prefix & SSE_PREFIX_W)
402 if (addr_size == 1 && imm) {
404 mod = (mod & ~0xc0) | 0x80;
407 if (rex2 & X86_REX2_B4) {
408 rex2 &= ~X86_REX2_B4;
414 cgen_one(((~rex2 & (X86_REX2_R3 | X86_REX2_X3 | X86_REX2_B3)) << 5) | !(rex2 & X86_REX2_R4) << 4 | !!(rex2 & X86_REX2_B4) << 3 | prefix);
415 cgen_one((rex2 & X86_REX2_W) << 4 | (~(sse_prefix >> 8) & 0xf) << 3 | !(rex2 & X86_REX2_X4) << 2 | (sse_prefix & 3));
416 cgen_one(!!(sse_prefix & force_ndd) << 4 | !((sse_prefix >> 8) & 0x10) << 3);
417 } else if ((rex2 & (X86_REX2_X3 | X86_REX2_B3 | X86_REX2_W)) == 0 && prefix == PREFIX_0F) {
419 cgen_one((~rex2 & X86_REX2_R3) << 5 | (~(sse_prefix >> 8) & 0xf) << 3 | (sse_prefix & 3));
422 cgen_one((~rex2 & (X86_REX2_R3 | X86_REX2_X3 | X86_REX2_B3)) << 5 | prefix);
423 cgen_one((rex2 & X86_REX2_W) << 4 | (~(sse_prefix >> 8) & 0xf) << 3 | (sse_prefix & 3));
427 switch (sse_prefix & 3) {
428 case SSE_PREFIX_66: cgen_one(X86_OP_SIZE); break;
429 case SSE_PREFIX_F3: cgen_one(X86_REPE); break;
430 case SSE_PREFIX_F2: cgen_one(X86_REPNE); break;
433 if (size == OP_SIZE_2)
434 cgen_one(X86_OP_SIZE);
436 need_rex = rex2 != 0;
437 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));
438 if (prefix == PREFIX_0F && (opcode == X86_0F_MOVZX_R16_RM8 || opcode == X86_0F_MOVSX_R16_RM8)) {
439 need_rex |= mod == 0xc0 && arg[0] >= 4;
446 prefix = PREFIX_NONE;
450 internal(file_line, "cgen_rm_insn: invalid prefix %u", prefix);
454 g(cgen_rex2(ctx, rex2));
471 internal(file_line, "cgen_rm_insn: invalid prefix %u", prefix);
475 cgen_one(mod | ((reg & 7) << 3) | (rm & 7));
489 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)
491 g(cgen_rm_insn(ctx, sse_prefix + (reg2 << 8), sse_op_map, opcode, !wide ? OP_SIZE_4 : OP_SIZE_8, true, reg, arg));
495 static bool attr_w cgen_push(struct codegen_context *ctx, unsigned aux)
497 uint8_t *arg1 = ctx->code_position;
498 ctx->code_position += arg_size(*arg1);
499 if (likely(R_IS_GPR(arg1[0]))) {
511 g(cgen_rex2(ctx, rex2));
513 cgen_one(X86_PUSH_R16 + (arg1[0] & 7));
516 if (arg1[0] == ARG_IMM) {
518 imm = get_imm(&arg1[1]);
519 if (unlikely(!imm_is_32bit(imm)))
520 internal(file_line, "cgen_push: immediate out of range: %"PRIxMAX"", (uintmax_t)imm);
521 if (imm >= -0x80 && imm <= 0x7f) {
522 cgen_one(X86_PUSH_IMM8);
526 cgen_one(X86_PUSH_IMM16);
531 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, X86_FF, OP_SIZE_4, false, X86_FF_PUSH, arg1));
535 static bool attr_w cgen_pop(struct codegen_context *ctx, unsigned aux)
537 uint8_t *arg1 = ctx->code_position;
538 ctx->code_position += arg_size(*arg1);
539 if (likely(R_IS_GPR(arg1[0]))) {
551 g(cgen_rex2(ctx, rex2));
553 cgen_one(X86_POP_R16 + (arg1[0] & 7));
556 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, X86_8F, OP_SIZE_4, false, X86_8F_POP, arg1));
560 static bool attr_w cgen_push2(struct codegen_context *ctx, unsigned aux)
562 uint8_t *arg1 = ctx->code_position;
563 uint8_t *arg2 = arg1 + arg_size(*arg1);
564 ctx->code_position = arg2 + arg_size(*arg2);
565 g(cgen_rm_insn(ctx, (arg1[0] << 8) | force_ndd, PREFIX_LEGACY_EVEX, X86_FF, !aux ? OP_SIZE_4 : OP_SIZE_8, false, X86_FF_PUSH, arg2));
569 static bool attr_w cgen_pop2(struct codegen_context *ctx, unsigned aux)
571 uint8_t *arg1 = ctx->code_position;
572 uint8_t *arg2 = arg1 + arg_size(*arg1);
573 ctx->code_position = arg2 + arg_size(*arg2);
574 g(cgen_rm_insn(ctx, (arg1[0] << 8) | force_ndd, PREFIX_LEGACY_EVEX, X86_8F, !aux ? OP_SIZE_4 : OP_SIZE_8, false, X86_8F_POP, arg2));
578 static bool attr_w cgen_mov(struct codegen_context *ctx, unsigned size)
580 uint8_t *arg1 = ctx->code_position;
581 uint8_t *arg2 = arg1 + arg_size(*arg1);
582 ctx->code_position = arg2 + arg_size(*arg2);
583 if (arg2[0] == ARG_IMM) {
586 imm = get_imm(&arg2[1]);
587 if (R_IS_GPR(arg1[0])) {
593 if (imm >= 0 && imm < 0x100000000LL)
597 g(cgen_rex2(ctx, rex2));
598 cgen_one(X86_MOV_R16_IMM16 + (arg1[0] & 7));
602 if (imm >= ~(int64_t)0x7fffffff && imm < 0) {
606 g(cgen_rex2(ctx, rex2));
607 cgen_one(X86_MOV_R16_IMM16 + (arg1[0] & 7));
611 if (size < OP_SIZE_4) {
612 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));
613 if (size == OP_SIZE_1)
620 if (unlikely(!imm_is_32bit(imm)))
621 internal(file_line, "cgen_mov: immediate out of range: %"PRIxMAX"", (uintmax_t)imm);
622 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, X86_MOV_RM16_IMM16, maximum(size, OP_SIZE_4), false, X86_MOV_R16_IMM16_REG, arg1));
627 if (arg1[0] == R_AX && size >= OP_SIZE_4 && arg2[0] == ARG_ADDRESS_0) {
629 imm = get_imm(&arg2[1]);
630 if (size == OP_SIZE_8)
631 g(cgen_rex2(ctx, X86_REX2_W));
632 cgen_one(X86_MOV_AX_M16);
636 if (arg1[0] == ARG_ADDRESS_0 && arg2[0] == R_AX) {
637 uint8_t code = size == OP_SIZE_1 ? X86_MOV_M16_AL : X86_MOV_M16_AX;
639 imm = get_imm(&arg1[1]);
640 if (size == OP_SIZE_2)
641 cgen_one(X86_OP_SIZE);
642 if (size == OP_SIZE_8)
643 g(cgen_rex2(ctx, X86_REX2_W));
648 if (R_IS_XMM(arg1[0]) && ARG_IS_ADDRESS(arg2[0])) {
649 if (size == OP_SIZE_2) {
650 if (cpu_test_feature(CPU_FEATURE_fp16)) {
651 g(cgen_sse_insn(ctx, SSE_PREFIX_F3 | force_evex, PREFIX_MAP5, X86_MAP5_MOVSH_X128_M16, false, arg1[0], 0, arg2));
654 g(cgen_sse_insn(ctx, SSE_PREFIX_66, PREFIX_0F, X86_0F_PINSRW_X128_RM16_IMM8, false, arg1[0], R_XMM7, arg2));
659 if (size == OP_SIZE_16) {
660 g(cgen_sse_insn(ctx, SSE_PREFIX_NONE, PREFIX_0F, X86_0F_MOVAPS_X128_M128, false, arg1[0], 0, arg2));
663 g(cgen_sse_insn(ctx, size == OP_SIZE_4 ? SSE_PREFIX_F3 : SSE_PREFIX_F2 | SSE_PREFIX_W, PREFIX_0F, X86_0F_MOVSS_X128_M32, false, arg1[0], 0, arg2));
666 if (ARG_IS_ADDRESS(arg1[0]) && R_IS_XMM(arg2[0])) {
667 if (size == OP_SIZE_2) {
668 if (cpu_test_feature(CPU_FEATURE_fp16)) {
669 g(cgen_sse_insn(ctx, SSE_PREFIX_F3 | force_evex, PREFIX_MAP5, X86_MAP5_MOVSH_M16_X128, false, arg2[0], 0, arg1));
672 g(cgen_sse_insn(ctx, SSE_PREFIX_66, PREFIX_0F_3A, X86_0F_3A_PEXTRW_RM16_X128_IMM8, false, arg2[0], 0, arg1));
677 if (size == OP_SIZE_16) {
678 g(cgen_sse_insn(ctx, SSE_PREFIX_NONE, PREFIX_0F, X86_0F_MOVAPS_M128_X128, false, arg2[0], 0, arg1));
681 g(cgen_sse_insn(ctx, size == OP_SIZE_4 ? SSE_PREFIX_F3 : SSE_PREFIX_F2 | SSE_PREFIX_W, PREFIX_0F, X86_0F_MOVSS_M32_X128, false, arg2[0], 0, arg1));
684 if (R_IS_XMM(arg1[0]) && R_IS_XMM(arg2[0])) {
685 g(cgen_sse_insn(ctx, SSE_PREFIX_NONE, PREFIX_0F, X86_0F_MOVAPS_X128_M128, false, arg1[0], 0, arg2));
688 if (R_IS_XMM(arg1[0]) && R_IS_GPR(arg2[0])) {
689 g(cgen_sse_insn(ctx, SSE_PREFIX_66, PREFIX_0F, X86_0F_MOVD_X128_RM32, size == OP_SIZE_8, arg1[0], 0, arg2));
692 if (R_IS_GPR(arg1[0]) && R_IS_XMM(arg2[0])) {
693 g(cgen_sse_insn(ctx, SSE_PREFIX_66, PREFIX_0F, X86_0F_MOVD_RM32_X128, size == OP_SIZE_8, arg2[0], 0, arg1));
696 if (!R_IS_GPR(arg1[0]) && unlikely(!R_IS_GPR(arg2[0]))) {
697 /*debug("%s", da(ctx->fn,function)->function_name);*/
698 internal(file_line, "cgen_mov: two addresses not supported");
700 if (!R_IS_GPR(arg1[0])) {
701 uint8_t code = size == OP_SIZE_1 ? X86_MOV_RM8_R8 : X86_MOV_RM16_R16;
702 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, code, size, true, arg2[0], arg1));
704 } else if (size >= OP_SIZE_4) {
705 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, X86_MOV_R16_RM16, size, true, arg1[0], arg2));
708 uint8_t code = size == OP_SIZE_1 ? X86_0F_MOVZX_R16_RM8 : X86_0F_MOVZX_R16_RM16;
709 g(cgen_rm_insn(ctx, -1, PREFIX_0F, code, OP_SIZE_4, false, arg1[0], arg2));
714 static bool attr_w cgen_movsx(struct codegen_context *ctx, unsigned size)
716 uint8_t *arg1, *arg2;
717 if (unlikely(size == OP_SIZE_NATIVE)) {
718 g(cgen_mov(ctx, size));
721 arg1 = ctx->code_position;
722 arg2 = arg1 + arg_size(*arg1);
723 ctx->code_position = arg2 + arg_size(*arg2);
724 if (size <= OP_SIZE_2) {
725 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));
727 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, X86_MOVSXD, OP_SIZE_NATIVE, true, arg1[0], arg2));
732 static bool attr_w cgen_lea(struct codegen_context *ctx, unsigned size)
735 uint8_t *arg1, *arg2, *arg3;
737 arg1 = ctx->code_position;
738 arg2 = arg1 + arg_size(*arg1);
739 arg3 = arg2 + arg_size(*arg2);
740 ctx->code_position = arg3 + arg_size(*arg3);
742 if (arg3[0] == ARG_IMM) {
744 if (arg2[0] == ARG_SHIFTED_REGISTER) {
745 if (unlikely((arg2[1] & ARG_SHIFT_MODE) != ARG_SHIFT_LSL) ||
746 unlikely((arg2[1] & ARG_SHIFT_AMOUNT) > 3))
748 addr[0] = ARG_ADDRESS_1 + (arg2[1] & ARG_SHIFT_AMOUNT);
751 addr[0] = ARG_ADDRESS_1;
754 imm = get_imm(&arg3[1]);
755 memcpy(&addr[2], &imm, 8);
756 } else if (R_IS_GPR(arg3[0])) {
757 addr[0] = ARG_ADDRESS_2;
760 memset(&addr[3], 0, 8);
761 } else if (arg3[0] == ARG_SHIFTED_REGISTER) {
762 if (unlikely((arg3[1] & ARG_SHIFT_MODE) != ARG_SHIFT_LSL) ||
763 unlikely((arg3[1] & ARG_SHIFT_AMOUNT) > 3))
765 addr[0] = ARG_ADDRESS_2 + (arg3[1] & ARG_SHIFT_AMOUNT);
768 memset(&addr[3], 0, 8);
771 internal(file_line, "cgen_lea: invalid argument %u, %02x, %02x, %02x", size, arg1[0], arg2[0], arg3[0]);
773 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, X86_LEA_R16_RM16, size, true, arg1[0], addr));
777 static bool attr_w cgen_alu(struct codegen_context *ctx, unsigned size, unsigned alu, unsigned writes_flags)
779 uint8_t *arg1, *arg2, *arg3;
781 arg1 = ctx->code_position;
782 arg2 = arg1 + arg_size(*arg1);
783 arg3 = arg2 + arg_size(*arg2);
784 ctx->code_position = arg3 + arg_size(*arg3);
785 if (unlikely(arg_size(*arg1) != arg_size(*arg2)))
786 internal(file_line, "cgen_alu: three-operand mode not supported");
787 if (!cpu_test_feature(CPU_FEATURE_apx) && unlikely(memcmp(arg1, arg2, arg_size(*arg1))))
788 internal(file_line, "cgen_alu: three-operand mode not supported");
790 arg1 = ctx->code_position;
792 arg3 = arg2 + arg_size(*arg2);
793 ctx->code_position = arg3 + arg_size(*arg3);
796 if (unlikely(alu == ALU_MUL)) {
797 if (unlikely(arg3[0] == ARG_IMM)) {
800 imm = get_imm(&arg3[1]);
801 if (unlikely(!imm_is_32bit(imm)))
802 internal(file_line, "cgen_alu: immediate out of range: %"PRIxMAX"", (uintmax_t)imm);
803 if (unlikely(size == OP_SIZE_1))
804 internal(file_line, "cgen_alu: byte mul with imm not supported");
805 code = imm_is_8bit(imm) ? X86_IMUL_R16_RM16_IMM8 : X86_IMUL_R16_RM16_IMM16;
806 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, code, size, true, arg1[0], arg2));
807 if (code == X86_IMUL_R16_RM16_IMM8) {
809 } else if (size == OP_SIZE_2) {
816 if (unlikely(size == OP_SIZE_1)) {
817 if (unlikely(arg1[0] != R_AX))
818 internal(file_line, "cgen_alu: imul with unsupported register");
819 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, X86_F6, size, false, X86_F6_IMUL_RM8, arg3));
822 if (unlikely(!R_IS_GPR(arg1[0])))
823 internal(file_line, "cgen_alu: invalid multiply args");
824 if (arg1[0] == arg2[0] && !test_evex)
825 g(cgen_rm_insn(ctx, -1, PREFIX_0F, X86_0F_IMUL_R16_RM16, size, true, arg1[0], arg3));
827 g(cgen_rm_insn(ctx, (arg1[0] << 8) | force_ndd, PREFIX_LEGACY_EVEX, X86_0F_IMUL_R16_RM16, size, true, arg2[0], arg3));
832 if (arg3[0] == ARG_IMM) {
836 imm = get_imm(&arg3[1]);
837 if (unlikely(!imm_is_32bit(imm)))
838 internal(file_line, "cgen_alu: immediate out of range: %"PRIxMAX"", (uintmax_t)imm);
840 if (!(writes_flags & 2)) {
841 if ((alu == ALU_ADD && imm == 1) || (alu == ALU_SUB && imm == -1)) {
843 if (R_IS_GPR(arg1[0]) && size >= OP_SIZE_2) {
844 if (size == OP_SIZE_2)
845 cgen_one(X86_OP_SIZE);
846 cgen_one(X86_INC_R16 + arg1[0]);
850 if ((arg1[0] == arg2[0] && !test_evex) || !R_IS_GPR(arg1[0]))
851 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, size == OP_SIZE_1 ? X86_FE : X86_FF, size, false, X86_FE_INC_RM8, arg1));
853 g(cgen_rm_insn(ctx, (arg1[0] << 8) | force_ndd, PREFIX_LEGACY_EVEX, size == OP_SIZE_1 ? X86_FE : X86_FF, size, false, X86_FE_INC_RM8, arg2));
856 if ((alu == ALU_ADD && imm == -1) || (alu == ALU_SUB && imm == 1)) {
858 if (R_IS_GPR(arg1[0]) && size >= OP_SIZE_2) {
859 if (size == OP_SIZE_2)
860 cgen_one(X86_OP_SIZE);
861 cgen_one(X86_DEC_R16 + arg1[0]);
865 if ((arg1[0] == arg2[0] && !test_evex) || !R_IS_GPR(arg1[0]))
866 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, size == OP_SIZE_1 ? X86_FE : X86_FF, size, false, X86_FE_DEC_RM8, arg1));
868 g(cgen_rm_insn(ctx, (arg1[0] << 8) | force_ndd, PREFIX_LEGACY_EVEX, size == OP_SIZE_1 ? X86_FE : X86_FF, size, false, X86_FE_DEC_RM8, arg2));
873 if (arg1[0] == R_AX && arg1[0] == arg2[0]) {
874 if (imm_is_8bit(imm) && size >= OP_SIZE_4)
877 code = size == OP_SIZE_1 ? X86_ALU_AL_IMM8 : X86_ALU_AX_IMM16;
878 if (size == OP_SIZE_2)
879 cgen_one(X86_OP_SIZE);
880 if (size == OP_SIZE_8)
881 g(cgen_rex2(ctx, X86_REX2_W));
886 bit8 = imm_is_8bit(imm);
887 code = size == OP_SIZE_1 ? X86_ALU_RM8_IMM8 : bit8 ? X86_ALU_RM16_IMM8 : X86_ALU_RM16_IMM16;
888 if (alu == 7 || (arg1[0] == arg2[0] && !test_evex) || !R_IS_GPR(arg1[0]) || 0)
889 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, code, size, false, alu, arg1));
891 g(cgen_rm_insn(ctx, (arg1[0] << 8) | force_ndd, PREFIX_LEGACY_EVEX, code, size, false, alu, arg2));
893 if (bit8 || size == OP_SIZE_1) {
895 } else if (size == OP_SIZE_2) {
903 if (R_IS_XMM(arg1[0]) && size == OP_SIZE_16) {
906 case ALU_AND: code = X86_0F_ANDPS_X128_M128; break;
907 case ALU_ANDN: code = X86_0F_ANDNPS_X128_M128; break;
908 case ALU_OR: code = X86_0F_ORPS_X128_M128; break;
909 case ALU_XOR: code = X86_0F_XORPS_X128_M128; break;
910 default: internal(file_line, "invalid sse alu: %u", alu);
912 g(cgen_sse_insn(ctx, SSE_PREFIX_NONE, PREFIX_0F, code, false, arg1[0], arg2[0], arg3));
916 if (!R_IS_GPR(arg1[0]) && unlikely(!R_IS_GPR(arg3[0])))
917 internal(file_line, "cgen_alu: two addresses not supported");
919 if (!R_IS_GPR(arg1[0])) {
920 uint8_t code = size == OP_SIZE_1 ? X86_ALU_RM8_R8 : X86_ALU_RM16_R16;
922 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, code, size, true, arg3[0], arg1));
925 uint8_t code = size == OP_SIZE_1 ? X86_ALU_R8_RM8 : X86_ALU_R16_RM16;
927 if (alu == 7 || (arg1[0] == arg2[0] && !test_evex))
928 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, code, size, true, arg1[0], arg3));
930 g(cgen_rm_insn(ctx, (arg1[0] << 8) | force_ndd, PREFIX_LEGACY_EVEX, code, size, true, arg2[0], arg3));
935 static bool attr_w cgen_alu1(struct codegen_context *ctx, unsigned size, unsigned alu)
938 uint8_t *arg1 = ctx->code_position;
939 uint8_t *arg2 = arg1 + arg_size(*arg1);
940 ctx->code_position = arg2 + arg_size(*arg2);
941 if ((!cpu_test_feature(CPU_FEATURE_apx) && (alu == ALU1_NOT || alu == ALU1_NEG)) || alu == ALU1_BSWAP) {
942 if (unlikely(arg1[0] != arg2[0]))
943 internal(file_line, "cgen_alu1: arguments mismatch: %x, %x", arg1[0], arg2[0]);
947 if ((arg1[0] == arg2[0] && !test_evex) || !R_IS_GPR(arg1[0]))
948 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, size == OP_SIZE_1 ? X86_F6 : X86_F7, size, false, X86_F6_NOT_RM8, arg1));
950 g(cgen_rm_insn(ctx, (arg1[0] << 8) | force_ndd, PREFIX_LEGACY_EVEX, size == OP_SIZE_1 ? X86_F6 : X86_F7, size, false, X86_F6_NOT_RM8, arg2));
953 if ((arg1[0] == arg2[0] && !test_evex) || !R_IS_GPR(arg1[0]))
954 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, size == OP_SIZE_1 ? X86_F6 : X86_F7, size, false, X86_F6_NEG_RM8, arg1));
956 g(cgen_rm_insn(ctx, (arg1[0] << 8) | force_ndd, PREFIX_LEGACY_EVEX, size == OP_SIZE_1 ? X86_F6 : X86_F7, size, false, X86_F6_NEG_RM8, arg2));
959 if (unlikely(size <= OP_SIZE_2))
960 internal(file_line, "cgen_alu1: bytes or words not supported with this operation");
962 if (!R_IS_GPR(arg1[0]))
963 internal(file_line, "cgen_alu1: bswap needs a register");
968 if (size == OP_SIZE_8)
973 g(cgen_rex2(ctx, rex2));
974 if (!(rex2 & X86_REX2_M0))
976 cgen_one(X86_0F_BSWAP + (arg1[0] & 7));
982 if (unlikely(size == OP_SIZE_1))
983 internal(file_line, "cgen_alu1: bytes not supported with this operation");
984 if (alu == ALU1_POPCNT || alu == ALU1_LZCNT)
986 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));
989 internal(file_line, "cgen_alu1: invalid operation %u", alu);
994 static bool attr_w cgen_test(struct codegen_context *ctx, unsigned size)
996 uint8_t *arg1, *arg2;
997 arg1 = ctx->code_position;
998 arg2 = arg1 + arg_size(*arg1);
999 ctx->code_position = arg2 + arg_size(*arg2);
1001 if (arg2[0] == ARG_IMM) {
1003 imm = get_imm(&arg2[1]);
1004 if (arg1[0] == R_AX) {
1005 if (size == OP_SIZE_1) {
1006 cgen_one(X86_TEST_AL_IMM8);
1007 } else if (size == OP_SIZE_2) {
1008 cgen_one(X86_OP_SIZE);
1009 cgen_one(X86_TEST_AX_IMM16);
1010 } else if (size == OP_SIZE_4) {
1011 cgen_one(X86_TEST_AX_IMM16);
1013 if (unlikely(!imm_is_32bit(imm)))
1014 internal(file_line, "cgen_test: immediate out of range: %"PRIxMAX"", (uintmax_t)imm);
1015 g(cgen_rex2(ctx, X86_REX2_W));
1016 cgen_one(X86_TEST_AX_IMM16);
1019 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, size == OP_SIZE_1 ? X86_F6 : X86_F7, size, false, X86_F6_TEST_RM8_IMM8, arg1));
1021 if (size == OP_SIZE_1) {
1023 } else if (size == OP_SIZE_2) {
1025 } else if (size == OP_SIZE_4) {
1028 if (unlikely(!imm_is_32bit(imm)))
1029 internal(file_line, "cgen_test: immediate out of range: %"PRIxMAX"", (uintmax_t)imm);
1035 if (!R_IS_GPR(arg1[0]) && unlikely(!R_IS_GPR(arg2[0])))
1036 internal(file_line, "cgen_test: two addresses not supported");
1038 if (!R_IS_GPR(arg1[0])) {
1039 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));
1041 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));
1046 static bool attr_w cgen_lea3(struct codegen_context *ctx, unsigned size, unsigned shift)
1049 uint8_t *arg1, *arg2, *arg3, *arg4;
1051 arg1 = ctx->code_position;
1052 arg2 = arg1 + arg_size(*arg1);
1053 arg3 = arg2 + arg_size(*arg2);
1054 arg4 = arg3 + arg_size(*arg3);
1055 ctx->code_position = arg4 + arg_size(*arg4);
1057 if (unlikely(!R_IS_GPR(arg1[0])) || unlikely(!R_IS_GPR(arg2[0])) || unlikely(!R_IS_GPR(arg3[0])) || unlikely(arg4[0] != ARG_IMM))
1058 internal(file_line, "cgen_lea3: invalid arguments");
1060 addr[0] = ARG_ADDRESS_2 + shift;
1063 memcpy(&addr[3], &arg4[1], 8);
1065 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, X86_LEA_R16_RM16, size, true, arg1[0], addr));
1070 static bool attr_w cgen_rot(struct codegen_context *ctx, unsigned size, uint8_t rot, unsigned writes_flags)
1072 uint8_t *arg1 = ctx->code_position;
1073 uint8_t *arg2 = arg1 + arg_size(*arg1);
1074 uint8_t *arg3 = arg2 + arg_size(*arg2);
1075 ctx->code_position = arg3 + arg_size(*arg3);
1077 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)) {
1080 case ROT_SHL: sse_prefix = SSE_PREFIX_66; break;
1081 case ROT_SAR: sse_prefix = SSE_PREFIX_F3; break;
1082 case ROT_SHR: sse_prefix = SSE_PREFIX_F2; break;
1083 default: internal(file_line, "cgen_rot: invalid rotation %x", rot);
1085 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));
1089 if (arg1[0] != arg2[0])
1090 internal(file_line, "cgen_rot: invalid arguments: %x, %02x, %02x, %02x", rot, arg1[0], arg2[0], arg3[0]);
1092 if (arg3[0] == R_CX) {
1093 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, size == OP_SIZE_1 ? X86_ROT_RM8_CL : X86_ROT_RM16_CL, size, false, rot, arg1));
1094 } else if (likely(arg3[0] == ARG_IMM)) {
1096 imm = get_imm(&arg3[1]);
1098 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, size == OP_SIZE_1 ? X86_ROT_RM8_1 : X86_ROT_RM16_1, size, false, rot, arg1));
1100 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, size == OP_SIZE_1 ? X86_ROT_RM8_IMM8 : X86_ROT_RM16_IMM8, size, false, rot, arg1));
1104 internal(file_line, "cgen_rot: invalid argument %02x", arg3[0]);
1109 static bool attr_w cgen_btxt(struct codegen_context *ctx, unsigned size, uint8_t bt, uint8_t *arg1, uint8_t *arg2)
1111 if (arg2[0] == ARG_IMM) {
1112 g(cgen_rm_insn(ctx, -1, PREFIX_0F, X86_0F_BTX_RM16_IMM8, size, false, X86_0F_BTX_BT_RM16_IMM8 + bt, arg1));
1115 g(cgen_rm_insn(ctx, -1, PREFIX_0F, X86_0F_BT_RM16_R16 + bt * 8, size, true, arg2[0], arg1));
1120 static bool attr_w cgen_bt(struct codegen_context *ctx, unsigned size)
1122 uint8_t *arg1 = ctx->code_position;
1123 uint8_t *arg2 = arg1 + arg_size(*arg1);
1124 ctx->code_position = arg2 + arg_size(*arg2);
1126 return cgen_btxt(ctx, size, BTX_BT, arg1, arg2);
1129 static bool attr_w cgen_btx(struct codegen_context *ctx, unsigned size, uint8_t bt)
1131 uint8_t *arg1 = ctx->code_position;
1132 uint8_t *arg2 = arg1 + arg_size(*arg1);
1133 uint8_t *arg3 = arg2 + arg_size(*arg2);
1134 ctx->code_position = arg3 + arg_size(*arg3);
1136 if (arg1[0] != arg2[0])
1137 internal(file_line, "cgen_btx: invalid arguments");
1139 return cgen_btxt(ctx, size, bt, arg1, arg3);
1142 static bool attr_w cgen_mul_l(struct codegen_context *ctx, unsigned size, bool sgn)
1144 uint8_t *arg1, *arg2, *arg3, *arg4;
1146 arg1 = ctx->code_position;
1147 arg2 = arg1 + arg_size(*arg1);
1148 arg3 = arg2 + arg_size(*arg2);
1149 arg4 = arg3 + arg_size(*arg3);
1150 ctx->code_position = arg4 + arg_size(*arg4);
1151 reg_up = size == OP_SIZE_1 ? R_AX : R_DX;
1152 if (unlikely(arg1[0] != R_AX) || unlikely(arg2[0] != reg_up) || unlikely(arg3[0] != R_AX) || unlikely(arg4[0] == ARG_IMM))
1153 internal(file_line, "cgen_mul_l: invalid mul arguments");
1155 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));
1159 static bool attr_w cgen_div_l(struct codegen_context *ctx, unsigned size, bool sgn)
1161 uint8_t *arg1, *arg2, *arg3, *arg4, *arg5;
1163 arg1 = ctx->code_position;
1164 arg2 = arg1 + arg_size(*arg1);
1165 arg3 = arg2 + arg_size(*arg2);
1166 arg4 = arg3 + arg_size(*arg3);
1167 arg5 = arg4 + arg_size(*arg4);
1168 ctx->code_position = arg5 + arg_size(*arg5);
1169 reg_up = size == OP_SIZE_1 ? R_AX : R_DX;
1170 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))
1171 internal(file_line, "cgen_div_l: invalid div arguments");
1173 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));
1177 static bool attr_w cgen_cmov(struct codegen_context *ctx, unsigned size, unsigned cond)
1179 uint8_t *arg1 = ctx->code_position;
1180 uint8_t *arg2 = arg1 + arg_size(*arg1);
1181 uint8_t *arg3 = arg2 + arg_size(*arg2);
1182 ctx->code_position = arg3 + arg_size(*arg3);
1183 if (unlikely(arg1[0] != arg2[0]))
1184 internal(file_line, "cgen_cmov: invalid arguments");
1185 g(cgen_rm_insn(ctx, -1, PREFIX_0F, X86_0F_CMOVCC_R16_RM16 + cond, size, true, arg1[0], arg3));
1189 static bool attr_w cgen_memcpy(struct codegen_context *ctx)
1191 int64_t disp_dest, disp_src;
1192 uint8_t *arg1, *arg2, *arg3;
1193 arg1 = ctx->code_position;
1194 arg2 = arg1 + arg_size(*arg1);
1195 arg3 = arg2 + arg_size(*arg2);
1196 ctx->code_position = arg3 + arg_size(*arg3);
1197 if (unlikely(arg1[0] != ARG_ADDRESS_1_POST_I) || unlikely(arg2[0] != ARG_ADDRESS_1_POST_I) || unlikely(arg3[0] != R_CX))
1199 if (unlikely(arg1[1] != R_DI) || unlikely(arg2[1] != R_SI))
1201 disp_dest = get_imm(&arg1[2]);
1202 disp_src = get_imm(&arg2[2]);
1203 if (unlikely(disp_dest != 0) || unlikely(disp_src != 0))
1207 cgen_one(X86_MOVSB);
1211 internal(file_line, "cgen_memcpy: invalid arguments %02x, %02x, %02x", *arg1, *arg2, *arg3);
1215 static bool attr_w cgen_memset(struct codegen_context *ctx)
1218 uint8_t *arg1, *arg2, *arg3;
1219 arg1 = ctx->code_position;
1220 arg2 = arg1 + arg_size(*arg1);
1221 arg3 = arg2 + arg_size(*arg2);
1222 ctx->code_position = arg3 + arg_size(*arg3);
1223 if (unlikely(arg1[0] != ARG_ADDRESS_1_POST_I) || unlikely(arg2[0] != R_CX) || unlikely(arg3[0] != R_AX))
1225 if (unlikely(arg1[1] != R_DI))
1227 disp_dest = get_imm(&arg1[2]);
1228 if (unlikely(disp_dest != 0))
1232 cgen_one(X86_STOSB);
1236 internal(file_line, "cgen_memset: invalid arguments %02x, %02x, %02x", *arg1, *arg2, *arg3);
1240 static bool attr_w cgen_sse_cmp(struct codegen_context *ctx, unsigned size)
1242 uint8_t *arg1 = ctx->code_position;
1243 uint8_t *arg2 = arg1 + arg_size(*arg1);
1244 ctx->code_position = arg2 + arg_size(*arg2);
1245 if (size == OP_SIZE_2) {
1246 g(cgen_sse_insn(ctx, SSE_PREFIX_NONE | force_evex, PREFIX_MAP5, X86_MAP5_UCOMISH_X128_RM16, false, arg1[0], 0, arg2));
1248 g(cgen_sse_insn(ctx, size == OP_SIZE_4 ? SSE_PREFIX_NONE : SSE_PREFIX_66 | SSE_PREFIX_W, PREFIX_0F, X86_0F_UCOMISS_X128_RM32, false, arg1[0], 0, arg2));
1253 static bool attr_w cgen_sse_alu(struct codegen_context *ctx, unsigned size, unsigned alu)
1256 uint8_t *arg1 = ctx->code_position;
1257 uint8_t *arg2 = arg1 + arg_size(*arg1);
1258 uint8_t *arg3 = arg2 + arg_size(*arg2);
1259 ctx->code_position = arg3 + arg_size(*arg3);
1261 case FP_ALU_ADD: opcode = X86_0F_ADDPS_X128_M32; break;
1262 case FP_ALU_SUB: opcode = X86_0F_SUBPS_X128_M32; break;
1263 case FP_ALU_MUL: opcode = X86_0F_MULPS_X128_M32; break;
1264 case FP_ALU_DIV: opcode = X86_0F_DIVPS_X128_M32; break;
1265 default: internal(file_line, "cgen_sse_alu: invalid alu %u", alu);
1267 if (size == OP_SIZE_2) {
1268 g(cgen_sse_insn(ctx, SSE_PREFIX_F3 | force_evex, PREFIX_MAP5, opcode, false, arg1[0], arg2[0], arg3));
1270 g(cgen_sse_insn(ctx, size == OP_SIZE_4 ? SSE_PREFIX_F3 : SSE_PREFIX_F2 | SSE_PREFIX_W, PREFIX_0F, opcode, false, arg1[0], arg2[0], arg3));
1275 static bool attr_w cgen_sse_alu1(struct codegen_context *ctx, unsigned size, unsigned alu)
1278 unsigned sse_pfx, sse_op_map;
1279 uint8_t *arg1 = ctx->code_position;
1280 uint8_t *arg2 = arg1 + arg_size(*arg1);
1281 ctx->code_position = arg2 + arg_size(*arg2);
1283 case FP_ALU1_SQRT: if (size == OP_SIZE_2) {
1284 sse_pfx = SSE_PREFIX_F3 | force_evex;
1285 sse_op_map = PREFIX_MAP5;
1286 } else if (size == OP_SIZE_4) {
1287 sse_pfx = SSE_PREFIX_F3;
1288 sse_op_map = PREFIX_0F;
1289 } else if (size == OP_SIZE_8) {
1290 sse_pfx = SSE_PREFIX_F2 | SSE_PREFIX_W;
1291 sse_op_map = PREFIX_0F;
1295 opcode = X86_0F_SQRTPS_X128_M32;
1300 case FP_ALU1_TRUNC: sse_pfx = SSE_PREFIX_66;
1301 sse_op_map = PREFIX_0F_3A;
1302 if (size == OP_SIZE_2) {
1303 sse_pfx = SSE_PREFIX_NONE | force_evex;
1304 opcode = X86_0F_3A_RNDSCALESH_X128_M16;
1305 } else if (size == OP_SIZE_4) {
1306 opcode = X86_0F_3A_ROUNDSS_X128_M32;
1307 } else if (size == OP_SIZE_8) {
1308 opcode = X86_0F_3A_ROUNDSD_X128_M64;
1309 sse_pfx |= SSE_PREFIX_W;
1315 default: internal(file_line, "cgen_sse_alu1: invalid alu %u, %u", alu, size);
1317 g(cgen_sse_insn(ctx, sse_pfx, sse_op_map, opcode, false, arg1[0], arg1[0], arg2));
1318 if (OP_IS_ROUND(alu))
1319 cgen_one(alu - FP_ALU1_ROUND);
1323 static bool attr_w cgen_sse_from_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
1325 uint8_t *arg1 = ctx->code_position;
1326 uint8_t *arg2 = arg1 + arg_size(*arg1);
1327 ctx->code_position = arg2 + arg_size(*arg2);
1328 if (fp_op_size == OP_SIZE_2) {
1329 g(cgen_sse_insn(ctx, SSE_PREFIX_F3 | force_evex, PREFIX_MAP5, X86_MAP5_CVTSI2SH_X128_RM16, int_op_size == OP_SIZE_8, arg1[0], R_XMM7, arg2));
1331 g(cgen_sse_insn(ctx, fp_op_size == OP_SIZE_4 ? SSE_PREFIX_F3 : SSE_PREFIX_F2 | SSE_PREFIX_W, PREFIX_0F, X86_0F_CVTSI2SS_X128_RM32, int_op_size == OP_SIZE_8, arg1[0], R_XMM7, arg2));
1336 static bool attr_w cgen_sse_to_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
1338 uint8_t *arg1 = ctx->code_position;
1339 uint8_t *arg2 = arg1 + arg_size(*arg1);
1340 ctx->code_position = arg2 + arg_size(*arg2);
1341 if (fp_op_size == OP_SIZE_2) {
1342 g(cgen_sse_insn(ctx, SSE_PREFIX_F3 | force_evex, PREFIX_MAP5, X86_MAP5_CVTTSH2SI_X128_RM16, int_op_size == OP_SIZE_8, arg1[0], 0, arg2));
1344 g(cgen_sse_insn(ctx, fp_op_size == OP_SIZE_4 ? SSE_PREFIX_F3 : SSE_PREFIX_F2 | SSE_PREFIX_W, PREFIX_0F, X86_0F_CVTTSS2SI_X128_RM32, int_op_size == OP_SIZE_8, arg1[0], 0, arg2));
1349 static bool attr_w cgen_sse_cvt(struct codegen_context *ctx, unsigned from_op_size, unsigned to_op_size)
1351 uint8_t *arg1 = ctx->code_position;
1352 uint8_t *arg2 = arg1 + arg_size(*arg1);
1353 ctx->code_position = arg2 + arg_size(*arg2);
1354 if (from_op_size == OP_SIZE_2 && to_op_size == OP_SIZE_4) {
1355 g(cgen_sse_insn(ctx, SSE_PREFIX_66, PREFIX_0F_38, X86_0F_38_CVTPH2PS_X128_RM64, false, arg1[0], 0, arg2));
1357 } else if (from_op_size == OP_SIZE_4 && to_op_size == OP_SIZE_2) {
1358 g(cgen_sse_insn(ctx, SSE_PREFIX_66, PREFIX_0F_3A, X86_0F_3A_CVTPS2PH_RM64_X128, false, arg2[0], 0, arg1));
1362 internal(file_line, "cgen_sse_cvt: unsupported arguments %u, %u", from_op_size, to_op_size);
1366 static bool attr_w cgen_x87_fld(struct codegen_context *ctx, unsigned size)
1369 uint8_t *arg1 = ctx->code_position;
1370 ctx->code_position = arg1 + arg_size(*arg1);
1371 if (arg1[0] >= R_ST0 && arg1[0] <= R_ST7)
1375 c1 = X87_FLD_RM32; c2 = X87_FLD_RM32_X; break;
1377 c1 = X87_FLD_M64; c2 = X87_FLD_M64_X; break;
1379 c1 = X87_FLD_M80; c2 = X87_FLD_M80_X; break;
1381 internal(file_line, "cgen_x87_fld: invalid size %u", size);
1383 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, c1, OP_SIZE_4, false, c2, arg1));
1387 static bool attr_w cgen_x87_fild(struct codegen_context *ctx, unsigned size)
1390 uint8_t *arg1 = ctx->code_position;
1391 ctx->code_position = arg1 + arg_size(*arg1);
1394 c1 = X87_FILD_M16; c2 = X87_FILD_M16_X; break;
1396 c1 = X87_FILD_M32; c2 = X87_FILD_M32_X; break;
1398 c1 = X87_FILD_M64; c2 = X87_FILD_M64_X; break;
1400 internal(file_line, "cgen_x87_fild: invalid size %u", size);
1402 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, c1, OP_SIZE_4, false, c2, arg1));
1406 static bool attr_w cgen_x87_fstp(struct codegen_context *ctx, unsigned size)
1409 uint8_t *arg1 = ctx->code_position;
1410 ctx->code_position = arg1 + arg_size(*arg1);
1411 if (arg1[0] >= R_ST0 && arg1[0] <= R_ST7)
1415 c1 = X87_FSTP_M32; c2 = X87_FSTP_M32_X; break;
1417 c1 = X87_FSTP_RM64; c2 = X87_FSTP_RM64_X; break;
1419 c1 = X87_FSTP_M80; c2 = X87_FSTP_M80_X; break;
1421 internal(file_line, "cgen_x87_fstp: invalid size %u", size);
1423 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, c1, OP_SIZE_4, false, c2, arg1));
1427 static bool attr_w cgen_x87_fistp(struct codegen_context *ctx, unsigned size)
1430 uint8_t *arg1 = ctx->code_position;
1431 ctx->code_position = arg1 + arg_size(*arg1);
1434 c1 = X87_FISTP_M16; c2 = X87_FISTP_M16_X; break;
1436 c1 = X87_FISTP_M32; c2 = X87_FISTP_M32_X; break;
1438 c1 = X87_FISTP_M64; c2 = X87_FISTP_M64_X; break;
1440 internal(file_line, "cgen_x87_fistp: invalid size %u", size);
1442 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, c1, OP_SIZE_4, false, c2, arg1));
1446 static bool attr_w cgen_x87_fisttp(struct codegen_context *ctx, unsigned size)
1449 uint8_t *arg1 = ctx->code_position;
1450 ctx->code_position = arg1 + arg_size(*arg1);
1453 c1 = X87_FISTTP_M16; c2 = X87_FISTTP_M16_X; break;
1455 c1 = X87_FISTTP_M32; c2 = X87_FISTTP_M32_X; break;
1457 c1 = X87_FISTTP_M64; c2 = X87_FISTTP_M64_X; break;
1459 internal(file_line, "cgen_x87_fisttp: invalid size %u", size);
1461 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, c1, OP_SIZE_4, false, c2, arg1));
1465 static bool attr_w cgen_x87_fcomp(struct codegen_context *ctx, unsigned size)
1468 uint8_t *arg1 = ctx->code_position;
1469 ctx->code_position = arg1 + arg_size(*arg1);
1470 if (arg1[0] < ARG_REGS_MAX) {
1471 c1 = X87_FALU_ST_RM32;
1472 } else switch (size) {
1474 c1 = X87_FALU_ST_RM32; break;
1476 c1 = X87_FALU_ST_M64; break;
1478 internal(file_line, "cgen_x87_fcomp: invalid size %u", size);
1481 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, c1, OP_SIZE_4, false, c2, arg1));
1485 static bool attr_w cgen_x87_alu(struct codegen_context *ctx, unsigned size, unsigned aux)
1488 uint8_t *arg1 = ctx->code_position;
1489 ctx->code_position = arg1 + arg_size(*arg1);
1490 if (arg1[0] < ARG_REGS_MAX) {
1491 c1 = X87_FALU_ST_RM32;
1492 } else switch (size) {
1494 c1 = X87_FALU_ST_RM32; break;
1496 c1 = X87_FALU_ST_M64; break;
1498 internal(file_line, "cgen_x87_alu: invalid size %u", size);
1502 c2 = X87_ALU_ADD; break;
1504 c2 = X87_ALU_SUB; break;
1506 c2 = X87_ALU_MUL; break;
1508 c2 = X87_ALU_DIV; break;
1510 internal(file_line, "cgen_x87_fst: invalid operation %u", aux);
1512 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, c1, OP_SIZE_4, false, c2, arg1));
1516 static bool attr_w cgen_x87_alup(struct codegen_context *ctx, unsigned aux)
1519 uint8_t *arg1 = ctx->code_position;
1520 ctx->code_position = arg1 + arg_size(*arg1);
1523 c2 = X87_ALU_ADD; break;
1525 c2 = X87_ALU_SUB; break;
1527 c2 = X87_ALU_MUL; break;
1529 c2 = X87_ALU_DIV; break;
1531 internal(file_line, "cgen_x87_fstp: invalid operation %u", aux);
1533 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, X87_FALUP_STi_ST0, OP_SIZE_4, false, c2, arg1));
1537 static bool attr_w resolve_relocation(struct codegen_context *ctx, struct relocation *reloc)
1539 int64_t offs = (int64_t)ctx->label_to_pos[reloc->label_id] - (int64_t)(reloc->position + (reloc->length == JMP_SHORT ? 1 : 4));
1540 switch (reloc->length) {
1543 if (!imm_is_8bit(offs))
1546 memcpy(ctx->mcode + reloc->position, &i8, 1);
1551 if (!imm_is_32bit(offs))
1554 memcpy(ctx->mcode + reloc->position, &i32, 4);
1558 internal(file_line, "resolve_relocation: invalid relocation length %u", reloc->length);
1564 static bool attr_w cgen_insn(struct codegen_context *ctx, uint32_t insn)
1568 /*debug("insn: %08x", insn);*/
1569 switch (insn_opcode(insn)) {
1580 imm16 = cget_two(ctx);
1581 cgen_one(X86_RET_IMM16);
1585 g(cgen_push(ctx, insn_aux(insn)));
1588 g(cgen_pop(ctx, insn_aux(insn)));
1591 g(cgen_push2(ctx, insn_aux(insn)));
1594 g(cgen_pop2(ctx, insn_aux(insn)));
1596 case INSN_CALL_INDIRECT:
1597 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, X86_FF, OP_SIZE_4, false, X86_FF_CALL_INDIRECT, ctx->code_position));
1598 ctx->code_position += arg_size(*ctx->code_position);
1601 g(cgen_mov(ctx, insn_op_size(insn)));
1604 g(cgen_movsx(ctx, insn_op_size(insn)));
1607 g(cgen_alu(ctx, insn_op_size(insn), 7, insn_writes_flags(insn)));
1610 g(cgen_test(ctx, insn_op_size(insn)));
1613 case INSN_ALU_FLAGS:
1614 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1616 if (!insn_writes_flags(insn) && insn_op_size(insn) <= OP_SIZE_8) {
1617 if (unlikely(insn_aux(insn) != ALU_ADD))
1619 g(cgen_lea(ctx, insn_op_size(insn)));
1622 g(cgen_alu(ctx, insn_op_size(insn), insn_aux(insn), insn_writes_flags(insn)));
1624 case INSN_ALU_PARTIAL:
1625 case INSN_ALU_FLAGS_PARTIAL:
1626 if (unlikely(insn_op_size(insn) >= OP_SIZE_4))
1628 if (!insn_writes_flags(insn)) {
1629 if (unlikely(insn_aux(insn) != ALU_ADD) || insn_op_size(insn) != OP_SIZE_2)
1631 g(cgen_lea(ctx, insn_op_size(insn)));
1634 g(cgen_alu(ctx, insn_op_size(insn), insn_aux(insn), insn_writes_flags(insn)));
1637 case INSN_ALU1_FLAGS:
1638 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1640 g(cgen_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
1642 case INSN_ALU1_PARTIAL:
1643 case INSN_ALU1_FLAGS_PARTIAL:
1644 if (unlikely(insn_op_size(insn) >= OP_SIZE_4))
1646 g(cgen_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
1649 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1651 g(cgen_lea3(ctx, insn_op_size(insn), insn_aux(insn)));
1654 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
1656 g(cgen_rot(ctx, insn_op_size(insn), insn_aux(insn), insn_writes_flags(insn)));
1658 case INSN_ROT_PARTIAL:
1659 if (unlikely(insn_op_size(insn) >= OP_SIZE_4))
1661 g(cgen_rot(ctx, insn_op_size(insn), insn_aux(insn), insn_writes_flags(insn)));
1664 if (unlikely(insn_op_size(insn) == OP_SIZE_1) || unlikely(!insn_writes_flags(insn)))
1666 g(cgen_bt(ctx, insn_op_size(insn)));
1669 if (unlikely(insn_op_size(insn) == OP_SIZE_1) || unlikely(!insn_writes_flags(insn)))
1671 g(cgen_btx(ctx, insn_op_size(insn), insn_aux(insn)));
1674 g(cgen_mul_l(ctx, insn_op_size(insn), insn_aux(insn)));
1677 g(cgen_div_l(ctx, insn_op_size(insn), insn_aux(insn)));
1680 if (unlikely(insn_op_size(insn) <= OP_SIZE_2))
1682 if (insn_op_size(insn) == OP_SIZE_8)
1683 g(cgen_rex2(ctx, X86_REX2_W));
1684 if (unlikely(cget_one(ctx) != R_AX))
1686 if (unlikely(cget_one(ctx) != R_AX))
1690 case INSN_CBW_PARTIAL:
1691 if (unlikely(insn_op_size(insn) != OP_SIZE_2))
1693 if (unlikely(cget_one(ctx) != R_AX))
1695 if (unlikely(cget_one(ctx) != R_AX))
1697 cgen_one(X86_OP_SIZE);
1701 if (unlikely(insn_op_size(insn) <= OP_SIZE_2))
1703 if (unlikely(cget_one(ctx) != R_DX))
1705 if (unlikely(cget_one(ctx) != R_AX))
1707 if (insn_op_size(insn) == OP_SIZE_8)
1708 g(cgen_rex2(ctx, X86_REX2_W));
1711 case INSN_CWD_PARTIAL:
1712 if (unlikely(insn_op_size(insn) != OP_SIZE_2))
1714 if (unlikely(cget_one(ctx) != R_DX))
1716 if (unlikely(cget_one(ctx) != R_AX))
1718 if (unlikely(cget_one(ctx) != R_DX))
1720 cgen_one(X86_OP_SIZE);
1724 if (insn_op_size(insn) >= OP_SIZE_4) {
1725 g(cgen_rm_insn(ctx, SSE_PREFIX_F2 | force_ndd, PREFIX_LEGACY_EVEX, X86_LEGACY_EVEX_SETCC_R64 + (insn_aux(insn) & 0xf), OP_SIZE_8, false, 0, ctx->code_position));
1726 } else if (insn_op_size(insn) == OP_SIZE_1) {
1727 g(cgen_rm_insn(ctx, -1, PREFIX_0F, X86_0F_SETCC_RM8 + (insn_aux(insn) & 0xf), OP_SIZE_1, false, 0, ctx->code_position));
1731 ctx->code_position += arg_size(*ctx->code_position);
1733 case INSN_SET_COND_PARTIAL:
1734 if (unlikely(insn_op_size(insn) != OP_SIZE_1))
1736 g(cgen_rm_insn(ctx, -1, PREFIX_0F, X86_0F_SETCC_RM8 + (insn_aux(insn) & 0xf), OP_SIZE_1, false, 0, ctx->code_position));
1737 ctx->code_position += arg_size(*ctx->code_position);
1738 ctx->code_position += arg_size(*ctx->code_position);
1742 if (unlikely(insn_op_size(insn) == OP_SIZE_1))
1744 g(cgen_cmov(ctx, insn_op_size(insn), insn_aux(insn)));
1747 g(cgen_memcpy(ctx));
1750 g(cgen_memset(ctx));
1753 g(cgen_sse_cmp(ctx, insn_op_size(insn)));
1756 g(cgen_sse_alu(ctx, insn_op_size(insn), insn_aux(insn)));
1759 g(cgen_sse_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
1761 case INSN_FP_FROM_INT32:
1762 case INSN_FP_FROM_INT64:
1763 g(cgen_sse_from_int(ctx, insn_opcode(insn) == INSN_FP_FROM_INT32 ? OP_SIZE_4 : OP_SIZE_8, insn_op_size(insn)));
1765 case INSN_FP_TO_INT32:
1766 case INSN_FP_TO_INT64:
1767 g(cgen_sse_to_int(ctx, insn_opcode(insn) == INSN_FP_TO_INT32 ? OP_SIZE_4 : OP_SIZE_8, insn_op_size(insn)));
1770 g(cgen_sse_cvt(ctx, insn_op_size(insn), insn_aux(insn)));
1773 g(cgen_x87_fld(ctx, insn_op_size(insn)));
1776 g(cgen_x87_fild(ctx, insn_op_size(insn)));
1779 g(cgen_x87_fstp(ctx, insn_op_size(insn)));
1781 case INSN_X87_FISTP:
1782 g(cgen_x87_fistp(ctx, insn_op_size(insn)));
1784 case INSN_X87_FISTTP:
1785 g(cgen_x87_fisttp(ctx, insn_op_size(insn)));
1787 case INSN_X87_FCOMP:
1788 g(cgen_x87_fcomp(ctx, insn_op_size(insn)));
1790 case INSN_X87_FCOMPP:
1791 cgen_one(X87_FCOMPP);
1792 cgen_one(X87_FCOMPP_2);
1794 case INSN_X87_FCOMIP:
1795 imm8 = cget_one(ctx);
1796 cgen_one(X87_FCOMIP);
1797 cgen_one(X87_FCOMIP_2 + (imm8 & 7));
1800 g(cgen_x87_alu(ctx, insn_op_size(insn), insn_aux(insn)));
1803 g(cgen_x87_alup(ctx, insn_aux(insn)));
1807 cgen_one(X87_FCHS_2);
1809 case INSN_X87_FSQRT:
1810 cgen_one(X87_FSQRT);
1811 cgen_one(X87_FSQRT_2);
1813 case INSN_X87_FRNDINT:
1814 cgen_one(X87_FRNDINT);
1815 cgen_one(X87_FRNDINT_2);
1817 case INSN_X87_FNSTSW:
1818 if (unlikely(cget_one(ctx) != R_AX))
1820 if (unlikely(cget_one(ctx) != R_AX))
1822 cgen_one(X87_FNSTSW);
1823 cgen_one(X87_FNSTSW_2);
1825 case INSN_X87_FLDCW:
1826 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, X87_FLDCW, OP_SIZE_4, false, X87_FLDCW_X, ctx->code_position));
1827 ctx->code_position += arg_size(*ctx->code_position);
1830 if (insn_jump_size(insn) == JMP_SHORT || insn_jump_size(insn) == JMP_SHORTEST) {
1831 cgen_one(X86_JMP_8);
1832 g(add_relocation(ctx, JMP_SHORT, 0, NULL));
1834 } else if (likely(insn_jump_size(insn) == JMP_LONG)) {
1835 cgen_one(X86_JMP_16);
1836 g(add_relocation(ctx, JMP_LONG, 0, NULL));
1843 if (insn_jump_size(insn) == JMP_SHORT || insn_jump_size(insn) == JMP_SHORTEST) {
1844 cgen_one(X86_JCC_8 + (insn_aux(insn) & 0xf));
1845 g(add_relocation(ctx, JMP_SHORT, 0, NULL));
1847 } else if (likely(insn_jump_size(insn) == JMP_LONG)) {
1849 cgen_one(X86_0F_JCC_16 + (insn_aux(insn) & 0xf));
1850 g(add_relocation(ctx, JMP_LONG, 0, NULL));
1856 case INSN_JMP_INDIRECT:
1857 g(cgen_rm_insn(ctx, -1, PREFIX_NONE, X86_FF, OP_SIZE_4, false, X86_FF_JMP_INDIRECT, ctx->code_position));
1858 ctx->code_position += arg_size(*ctx->code_position);
1862 internal(file_line, "cgen_insn: invalid insn %08lx", (unsigned long)insn);