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/>.
19 static bool attr_w gen_jump(struct codegen_context *ctx, int32_t jmp_offset, unsigned op_size, unsigned cond, unsigned reg1, unsigned reg2);
21 static bool attr_w gen_alu_upcall(struct codegen_context *ctx, size_t upcall, unsigned op_size, frame_t slot_1, frame_t slot_2, frame_t slot_r, uint32_t label_ovf)
23 if (slot_is_register(ctx, slot_1))
24 g(spill(ctx, slot_1));
25 if (slot_2 != NO_FRAME_T && slot_is_register(ctx, slot_2))
26 g(spill(ctx, slot_2));
27 if (frame_t_is_const(slot_2)) {
28 size_t x_offs = offsetof(struct cg_upcall_vector_s, INT_binary_const_int8_t) + op_size * sizeof(void (*)(void));
29 g(gen_upcall_start(ctx, x_offs, 4));
30 g(gen_frame_address(ctx, slot_1, 0, R_ARG0));
31 g(gen_upcall_argument(ctx, 0));
32 g(gen_load_constant(ctx, R_ARG1, frame_t_get_const(slot_2)));
33 g(gen_upcall_argument(ctx, 1));
34 g(gen_frame_address(ctx, slot_r, 0, R_ARG2));
35 g(gen_upcall_argument(ctx, 2));
36 g(gen_get_upcall_pointer(ctx, upcall, R_ARG3));
37 g(gen_upcall_argument(ctx, 3));
38 g(gen_upcall(ctx, x_offs, 4));
39 } else if (slot_2 != NO_FRAME_T) {
40 g(gen_upcall_start(ctx, upcall, 3));
41 g(gen_frame_address(ctx, slot_1, 0, R_ARG0));
42 g(gen_upcall_argument(ctx, 0));
43 g(gen_frame_address(ctx, slot_2, 0, R_ARG1));
44 g(gen_upcall_argument(ctx, 1));
45 g(gen_frame_address(ctx, slot_r, 0, R_ARG2));
46 g(gen_upcall_argument(ctx, 2));
47 g(gen_upcall(ctx, upcall, 3));
49 g(gen_upcall_start(ctx, upcall, 2));
50 g(gen_frame_address(ctx, slot_1, 0, R_ARG0));
51 g(gen_upcall_argument(ctx, 0));
52 g(gen_frame_address(ctx, slot_r, 0, R_ARG1));
53 g(gen_upcall_argument(ctx, 1));
54 g(gen_upcall(ctx, upcall, 2));
56 if (slot_is_register(ctx, slot_r))
57 g(unspill(ctx, slot_r));
59 g(gen_jmp_on_zero(ctx, OP_SIZE_1, R_RET0, COND_E, label_ovf));
63 static bool attr_w gen_alu_typed_upcall(struct codegen_context *ctx, size_t upcall, unsigned op_size, frame_t slot_1, frame_t slot_2, frame_t slot_r, uint32_t label_ovf)
65 upcall += op_size * sizeof(void (*)(void));
66 return gen_alu_upcall(ctx, upcall, op_size, slot_1, slot_2, slot_r, label_ovf);
73 #define MODE_ARRAY_LEN_GT 4
75 static bool attr_w gen_alu(struct codegen_context *ctx, unsigned mode, unsigned op_size, unsigned op, uint32_t label_ovf, frame_t slot_1, frame_t slot_2, frame_t slot_r)
79 unsigned reg1, reg2, reg3, target;
81 case MODE_FIXED: switch (op) {
82 case OPCODE_FIXED_OP_add: alu = ALU_ADD; goto do_alu;
83 case OPCODE_FIXED_OP_subtract: alu = ALU_SUB; goto do_alu;
84 case OPCODE_FIXED_OP_multiply: goto do_multiply;
85 case OPCODE_FIXED_OP_divide:
86 case OPCODE_FIXED_OP_divide_alt1: sgn = true; mod = false; goto do_divide;
87 case OPCODE_FIXED_OP_udivide:
88 case OPCODE_FIXED_OP_udivide_alt1: sgn = false; mod = false; goto do_divide;
89 case OPCODE_FIXED_OP_modulo:
90 case OPCODE_FIXED_OP_modulo_alt1: sgn = true; mod = true; goto do_divide;
91 case OPCODE_FIXED_OP_umodulo:
92 case OPCODE_FIXED_OP_umodulo_alt1: sgn = false; mod = true; goto do_divide;
93 case OPCODE_FIXED_OP_power: return gen_alu_typed_upcall(ctx, offsetof(struct cg_upcall_vector_s, FIXED_binary_power_int8_t), op_size, slot_1, slot_2, slot_r, 0);
94 case OPCODE_FIXED_OP_and: alu = ALU_AND; goto do_alu;
95 case OPCODE_FIXED_OP_or: alu = ALU_OR; goto do_alu;
96 case OPCODE_FIXED_OP_xor: alu = ALU_XOR; goto do_alu;
97 case OPCODE_FIXED_OP_shl: alu = ROT_SHL; goto do_shift;
98 case OPCODE_FIXED_OP_shr: alu = ROT_SAR; goto do_shift;
99 case OPCODE_FIXED_OP_ushr: alu = ROT_SHR; goto do_shift;
100 case OPCODE_FIXED_OP_rol: alu = ROT_ROL; goto do_shift;
101 case OPCODE_FIXED_OP_ror: alu = ROT_ROR; goto do_shift;
102 case OPCODE_FIXED_OP_bts: alu = BTX_BTS; goto do_bt;
103 case OPCODE_FIXED_OP_btr: alu = BTX_BTR; goto do_bt;
104 case OPCODE_FIXED_OP_btc: alu = BTX_BTC; goto do_bt;
105 case OPCODE_FIXED_OP_equal: alu = COND_E; goto do_compare;
106 case OPCODE_FIXED_OP_not_equal: alu = COND_NE; goto do_compare;
107 case OPCODE_FIXED_OP_less: alu = COND_L; goto do_compare;
108 case OPCODE_FIXED_OP_less_equal: alu = COND_LE; goto do_compare;
109 case OPCODE_FIXED_OP_greater: alu = COND_G; goto do_compare;
110 case OPCODE_FIXED_OP_greater_equal: alu = COND_GE; goto do_compare;
111 case OPCODE_FIXED_OP_uless: alu = COND_B; goto do_compare;
112 case OPCODE_FIXED_OP_uless_equal: alu = COND_BE; goto do_compare;
113 case OPCODE_FIXED_OP_ugreater: alu = COND_A; goto do_compare;
114 case OPCODE_FIXED_OP_ugreater_equal: alu = COND_AE; goto do_compare;
115 case OPCODE_FIXED_OP_bt: alu = BTX_BT; goto do_bt;
116 default: internal(file_line, "gen_alu: unsupported fixed operation %u", op);
118 case MODE_INT: switch (op) {
119 case OPCODE_INT_OP_add: alu = ALU_ADD; goto do_alu;
120 case OPCODE_INT_OP_subtract: alu = ALU_SUB; goto do_alu;
121 case OPCODE_INT_OP_multiply: goto do_multiply;
122 case OPCODE_INT_OP_divide:
123 case OPCODE_INT_OP_divide_alt1: sgn = true; mod = false; goto do_divide;
124 case OPCODE_INT_OP_modulo:
125 case OPCODE_INT_OP_modulo_alt1: sgn = true; mod = true; goto do_divide;
126 case OPCODE_INT_OP_power: return gen_alu_typed_upcall(ctx, offsetof(struct cg_upcall_vector_s, INT_binary_power_int8_t), op_size, slot_1, slot_2, slot_r, label_ovf);
127 case OPCODE_INT_OP_and: alu = ALU_AND; mode = MODE_FIXED; goto do_alu;
128 case OPCODE_INT_OP_or: alu = ALU_OR; mode = MODE_FIXED; goto do_alu;
129 case OPCODE_INT_OP_xor: alu = ALU_XOR; mode = MODE_FIXED; goto do_alu;
130 case OPCODE_INT_OP_shl: alu = ROT_SHL; goto do_shift;
131 case OPCODE_INT_OP_shr: alu = ROT_SAR; goto do_shift;
132 case OPCODE_INT_OP_bts: alu = BTX_BTS; goto do_bt;
133 case OPCODE_INT_OP_btr: alu = BTX_BTR; goto do_bt;
134 case OPCODE_INT_OP_btc: alu = BTX_BTC; goto do_bt;
135 case OPCODE_INT_OP_equal: alu = COND_E; goto do_compare;
136 case OPCODE_INT_OP_not_equal: alu = COND_NE; goto do_compare;
137 case OPCODE_INT_OP_less: alu = COND_L; goto do_compare;
138 case OPCODE_INT_OP_less_equal: alu = COND_LE; goto do_compare;
139 case OPCODE_INT_OP_greater: alu = COND_G; goto do_compare;
140 case OPCODE_INT_OP_greater_equal: alu = COND_GE; goto do_compare;
141 case OPCODE_INT_OP_bt: alu = BTX_BT; goto do_bt;
142 default: internal(file_line, "gen_alu: unsupported int operation %u", op);
144 case MODE_BOOL: switch (op) {
145 case OPCODE_BOOL_OP_and: alu = ALU_AND; mode = MODE_FIXED; goto do_alu;
146 case OPCODE_BOOL_OP_or: alu = ALU_OR; mode = MODE_FIXED; goto do_alu;
147 case OPCODE_BOOL_OP_equal: alu = COND_E; goto do_compare;
148 case OPCODE_BOOL_OP_not_equal: alu = ALU_XOR; mode = MODE_FIXED; goto do_alu;
149 case OPCODE_BOOL_OP_less: alu = COND_L; goto do_compare;
150 case OPCODE_BOOL_OP_less_equal: alu = COND_LE; goto do_compare;
151 case OPCODE_BOOL_OP_greater: alu = COND_G; goto do_compare;
152 case OPCODE_BOOL_OP_greater_equal: alu = COND_GE; goto do_compare;
153 default: internal(file_line, "gen_alu: unsupported bool operation %u", op);
156 internal(file_line, "gen_alu: unsupported mode %u", mode);
162 size_t attr_unused offset;
163 uint8_t attr_unused long_imm;
164 unsigned first_flags;
165 unsigned second_flags;
167 unsigned attr_unused op_size_flags;
169 if (unlikely(op_size > OP_SIZE_NATIVE)) {
170 #if !defined(ARCH_X86) && !defined(ARCH_ARM) && !defined(ARCH_PARISC) && !defined(ARCH_POWER) && !defined(ARCH_SPARC32)
171 if (mode == MODE_FIXED) {
172 if (alu == ALU_ADD) {
173 g(gen_alu_upcall(ctx, offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_add_,TYPE_INT_MAX)), op_size, slot_1, slot_2, slot_r, 0));
175 } else if (alu == ALU_SUB) {
176 g(gen_alu_upcall(ctx, offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_subtract_,TYPE_INT_MAX)), op_size, slot_1, slot_2, slot_r, 0));
179 } else if (mode == MODE_INT) {
180 if (alu == ALU_ADD) {
181 g(gen_alu_upcall(ctx, offsetof(struct cg_upcall_vector_s, cat(INT_binary_add_,TYPE_INT_MAX)), op_size, slot_1, slot_2, slot_r, label_ovf));
183 } else if (alu == ALU_SUB) {
184 g(gen_alu_upcall(ctx, offsetof(struct cg_upcall_vector_s, cat(INT_binary_subtract_,TYPE_INT_MAX)), op_size, slot_1, slot_2, slot_r, label_ovf));
189 first_flags = alu == ALU_ADD || alu == ALU_SUB ? 2 : 0;
190 second_flags = mode == MODE_INT ? 1 : 0;
191 second_alu = alu == ALU_ADD ? ALU_ADC : alu == ALU_SUB ? ALU_SBB : alu;
192 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_1, 0, R_SCRATCH_1, R_SCRATCH_2));
193 #if defined(ARCH_X86)
194 g(gen_frame_load_op(ctx, OP_SIZE_NATIVE, garbage, alu, first_flags, slot_2, lo_word(OP_SIZE_NATIVE), true, R_SCRATCH_1));
195 g(gen_frame_load_op(ctx, OP_SIZE_NATIVE, garbage, second_alu, second_flags, slot_2, hi_word(OP_SIZE_NATIVE), true, R_SCRATCH_2));
197 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_2, 0, R_SCRATCH_3, R_SCRATCH_4));
198 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, alu, R_SCRATCH_1, R_SCRATCH_1, R_SCRATCH_3, first_flags));
199 #if defined(ARCH_PARISC)
200 if (mode == MODE_INT) {
201 gen_insn(INSN_ALU_FLAGS_TRAP, OP_SIZE_NATIVE, second_alu, ALU_WRITES_FLAGS(OP_SIZE_NATIVE, second_alu, false, false, 0));
202 gen_one(R_SCRATCH_2);
203 gen_one(R_SCRATCH_2);
204 gen_one(R_SCRATCH_4);
209 gen_insn(first_flags ? INSN_ALU_FLAGS : INSN_ALU, OP_SIZE_NATIVE, second_alu, second_flags | ALU_WRITES_FLAGS(OP_SIZE_NATIVE, second_alu, false, false, 0));
210 gen_one(R_SCRATCH_2);
211 gen_one(R_SCRATCH_2);
212 gen_one(R_SCRATCH_4);
215 #if !defined(ARCH_PARISC)
216 if (mode == MODE_INT) {
217 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_O, 0);
221 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, R_SCRATCH_1, R_SCRATCH_2));
225 if (((ARCH_HAS_FLAGS && i_size_cmp(op_size) == op_size + zero) || ARCH_SUPPORTS_TRAPS(op_size)) && slot_2 == slot_r && slot_1 != slot_2 && alu_is_commutative(alu)) {
230 if (((ARCH_HAS_FLAGS && i_size_cmp(op_size) == op_size + zero) || ARCH_SUPPORTS_TRAPS(op_size)) && slot_1 == slot_r && (slot_1 != slot_2 || mode != MODE_INT)
231 #if defined(ARCH_POWER)
232 && op_size == OP_SIZE_NATIVE
236 unsigned undo_alu = alu == ALU_ADD ? ALU_SUB : ALU_ADD;
237 if (slot_is_register(ctx, slot_1)) {
238 unsigned reg1 = ctx->registers[slot_1];
239 if (slot_is_register(ctx, slot_2)
240 #if !defined(ARCH_POWER)
241 || frame_t_is_const(slot_2)
244 unsigned reg2 = frame_t_is_const(slot_2) ? 0xff /* avoid warning */ : ctx->registers[slot_2];
245 if (mode == MODE_INT && ARCH_SUPPORTS_TRAPS(op_size)) {
246 if (frame_t_is_const(slot_2))
247 g(gen_imm(ctx, frame_t_get_const(slot_2), alu_trap_purpose(alu) | (alu_purpose(undo_alu) << 8), i_size(op_size)));
248 gen_insn(INSN_ALU_TRAP, op_size, alu, ALU_WRITES_FLAGS(op_size, alu, false, frame_t_is_const(slot_2) && is_imm(), ctx->const_imm));
251 if (frame_t_is_const(slot_2))
255 if (ARCH_TRAP_BEFORE) {
259 ce = alloc_undo_label(ctx);
262 gen_four(ce->undo_label);
266 if (frame_t_is_const(slot_2))
267 g(gen_imm(ctx, frame_t_get_const(slot_2), alu_purpose(alu) | (alu_purpose(undo_alu) << 8), i_size(op_size)));
268 gen_insn(INSN_ALU + ARCH_PARTIAL_ALU(i_size(op_size)), i_size(op_size), alu, ALU_WRITES_FLAGS(i_size(op_size), alu, false, frame_t_is_const(slot_2) && is_imm(), ctx->const_imm));
271 if (frame_t_is_const(slot_2))
275 if (mode == MODE_INT) {
277 ce = alloc_undo_label(ctx);
280 gen_insn(INSN_JMP_COND, i_size_cmp(op_size), COND_O, 0);
281 gen_four(ce->undo_label);
283 ce->undo_opcode = INSN_ALU + ARCH_PARTIAL_ALU(i_size(op_size));
284 ce->undo_op_size = i_size(op_size);
285 ce->undo_aux = undo_alu;
286 ce->undo_writes_flags = ALU_WRITES_FLAGS(i_size(op_size), undo_alu, false, frame_t_is_const(slot_2) && is_imm(), ctx->const_imm);
287 m = mark_params(ctx);
290 if (frame_t_is_const(slot_2))
294 copy_params(ctx, ce, m);
298 #if defined(ARCH_S390) || defined(ARCH_X86)
299 else if (!frame_t_is_const(slot_2)) {
301 int64_t offset = (size_t)slot_2 * slot_size;
302 g(gen_address(ctx, R_FRAME, offset, IMM_PURPOSE_LDR_OFFSET, i_size(op_size)));
303 gen_insn(INSN_ALU + ARCH_PARTIAL_ALU(i_size(op_size)), i_size(op_size), alu, ALU_WRITES_FLAGS(i_size(op_size), alu, true, false, 0) | 1);
306 gen_address_offset();
307 if (mode == MODE_INT) {
308 ce = alloc_undo_label(ctx);
311 ce->undo_opcode = INSN_ALU + ARCH_PARTIAL_ALU(i_size(op_size));
312 ce->undo_op_size = i_size(op_size);
313 ce->undo_aux = undo_alu;
314 ce->undo_writes_flags = ALU_WRITES_FLAGS(i_size(op_size), undo_alu, true, false, 0);
315 m = mark_params(ctx);
318 gen_address_offset();
319 copy_params(ctx, ce, m);
320 gen_insn(INSN_JMP_COND, i_size_cmp(op_size), COND_O, 0);
321 gen_four(ce->undo_label);
327 #if defined(ARCH_X86)
331 int64_t offset = (size_t)slot_1 * slot_size;
332 if (!frame_t_is_const(slot_2))
333 g(gen_frame_get(ctx, op_size, garbage, slot_2, R_SCRATCH_1, ®2));
334 g(gen_address(ctx, R_FRAME, offset, IMM_PURPOSE_LDR_OFFSET, i_size(op_size)));
335 if (frame_t_is_const(slot_2))
336 g(gen_imm(ctx, frame_t_get_const(slot_2), alu_purpose(alu) | (alu_purpose(undo_alu) << 8), i_size(op_size)));
337 gen_insn(INSN_ALU + ARCH_PARTIAL_ALU(op_size), i_size(op_size), alu, ALU_WRITES_FLAGS(i_size(op_size), undo_alu, true, frame_t_is_const(slot_2) && is_imm(), ctx->const_imm) | 1);
338 gen_address_offset();
339 gen_address_offset();
340 if (frame_t_is_const(slot_2))
344 if (mode == MODE_INT) {
345 ce = alloc_undo_label(ctx);
348 ce->undo_opcode = INSN_ALU + ARCH_PARTIAL_ALU(op_size);
349 ce->undo_op_size = i_size(op_size);
350 ce->undo_aux = undo_alu;
351 ce->undo_writes_flags = ALU_WRITES_FLAGS(i_size(op_size), undo_alu, true, false, 0);
352 m = mark_params(ctx);
353 gen_address_offset();
354 gen_address_offset();
355 if (frame_t_is_const(slot_2))
359 copy_params(ctx, ce, m);
360 gen_insn(INSN_JMP_COND, i_size_cmp(op_size), COND_O, 0);
361 gen_four(ce->undo_label);
368 #if defined(ARCH_X86)
370 #elif defined(ARCH_S390)
371 if (op_size >= OP_SIZE_4)
372 #elif ARCH_HAS_FLAGS && !defined(ARCH_POWER)
373 if (op_size == i_size(op_size) + (unsigned)zero && frame_t_is_const(slot_2))
375 if (mode != MODE_INT && op_size == i_size(op_size) + (unsigned)zero && frame_t_is_const(slot_2))
378 if (mode == MODE_INT) {
379 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
381 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, slot_2, R_SCRATCH_1);
383 g(gen_frame_load(ctx, op_size, garbage, slot_1, 0, false, target));
384 g(gen_frame_load_op(ctx, op_size, garbage, alu, mode == MODE_INT, slot_2, 0, false, target));
385 goto check_ovf_store;
387 op_size_flags = !ARCH_HAS_FLAGS && !ARCH_SUPPORTS_TRAPS(op_size) ? OP_SIZE_NATIVE : OP_SIZE_4;
388 #if defined(ARCH_POWER)
389 op_size_flags = OP_SIZE_NATIVE;
391 g(gen_frame_get(ctx, op_size, mode == MODE_INT && (op_size < op_size_flags || ARCH_SUPPORTS_TRAPS(op_size)) ? sign_x : garbage, slot_1, R_SCRATCH_1, ®1));
392 if (frame_t_is_const(slot_2)
393 #if defined(ARCH_POWER)
400 g(gen_frame_get(ctx, op_size, mode == MODE_INT && (op_size < op_size_flags || ARCH_SUPPORTS_TRAPS(op_size)) ? sign_x : garbage, slot_2, R_SCRATCH_2, ®2));
404 if (mode == MODE_INT && op_size >= OP_SIZE_4) {
405 if (ARCH_SUPPORTS_TRAPS(op_size)) {
406 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
408 g(gen_imm(ctx, frame_t_get_const(slot_2), alu_trap_purpose(alu), op_size));
409 gen_insn(INSN_ALU_TRAP, op_size, alu, ALU_WRITES_FLAGS(op_size, alu, false, c && is_imm(), ctx->const_imm));
417 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
420 if (op_size >= OP_SIZE_NATIVE) {
421 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_3);
423 g(gen_3address_alu_imm(ctx, i_size(op_size), alu, target, reg1, frame_t_get_const(slot_2), 0));
425 g(gen_3address_alu(ctx, i_size(op_size), alu, target, reg1, reg2, 0));
426 #if defined(ARCH_IA64)
428 g(gen_3address_alu_imm(ctx, i_size(op_size), ALU_XOR, R_SCRATCH_1, reg1, frame_t_get_const(slot_2), 0));
429 g(gen_3address_alu_imm(ctx, i_size(op_size), ALU_XOR, R_SCRATCH_2, target, frame_t_get_const(slot_2), 0));
431 g(gen_3address_alu(ctx, i_size(op_size), ALU_XOR, R_SCRATCH_1, reg1, reg2, 0));
432 g(gen_3address_alu(ctx, i_size(op_size), ALU_XOR, R_SCRATCH_2, target, reg2, 0));
434 if (alu == ALU_ADD) {
435 g(gen_3address_alu(ctx, i_size(op_size), ALU_ANDN, R_SCRATCH_1, R_SCRATCH_2, R_SCRATCH_1, 0));
437 g(gen_3address_alu(ctx, i_size(op_size), ALU_ANDN, R_SCRATCH_1, R_SCRATCH_1, R_SCRATCH_2, 0));
439 g(gen_cmp_test_jmp(ctx, INSN_TEST, i_size(op_size), R_SCRATCH_1, R_SCRATCH_1, COND_S, label_ovf));
442 g(gen_cmp_test_jmp(ctx, INSN_CMP, i_size(op_size), reg1, target, (frame_t_get_const(slot_2) >= 0) ^ (alu != ALU_ADD) ? COND_G : COND_L, label_ovf));
444 gen_insn(INSN_CMP_DEST_REG, i_size(op_size), COND_L, 0);
445 gen_one(R_SCRATCH_1);
446 if (alu == ALU_ADD) {
454 g(gen_imm(ctx, 0, IMM_PURPOSE_CMP, i_size(op_size)));
455 gen_insn(INSN_CMP_DEST_REG, i_size(op_size), COND_L, 0);
456 gen_one(R_SCRATCH_2);
460 g(gen_cmp_test_jmp(ctx, INSN_CMP, i_size(op_size), R_SCRATCH_1, R_SCRATCH_2, COND_NE, label_ovf));
463 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
468 if (mode == MODE_INT) {
469 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
470 } else if (!ARCH_IS_3ADDRESS(alu, mode == MODE_INT && op_size >= op_size_flags) && !alu_is_commutative(alu)) {
471 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, slot_2, R_SCRATCH_1);
473 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
476 g(gen_3address_alu_imm(ctx, i_size(op_size), alu, target, reg1, frame_t_get_const(slot_2), mode == MODE_INT && op_size >= op_size_flags));
478 g(gen_3address_alu(ctx, i_size(op_size), alu, target, reg1, reg2, mode == MODE_INT && op_size >= op_size_flags));
481 if (mode == MODE_INT && unlikely(op_size < op_size_flags)) {
482 g(gen_cmp_extended(ctx, op_size_flags, op_size, target, R_SCRATCH_2, label_ovf));
485 if (mode == MODE_INT) {
486 gen_insn(INSN_JMP_COND, op_size, COND_O, 0);
489 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
497 size_t attr_unused offset;
498 uint8_t attr_unused long_imm;
499 if (unlikely(op_size > OP_SIZE_NATIVE) || unlikely(!ARCH_HAS_MUL)) {
500 if (mode == MODE_INT) {
501 g(gen_alu_typed_upcall(ctx, offsetof(struct cg_upcall_vector_s, INT_binary_multiply_int8_t), op_size, slot_1, slot_2, slot_r, label_ovf));
504 #if defined(ARCH_X86)
505 g(gen_frame_load(ctx, OP_SIZE_NATIVE, garbage, slot_1, hi_word(OP_SIZE_NATIVE), true, R_CX));
506 g(gen_frame_load(ctx, OP_SIZE_NATIVE, garbage, slot_2, hi_word(OP_SIZE_NATIVE), true, R_AX));
507 g(gen_frame_load_op(ctx, OP_SIZE_NATIVE, garbage, ALU_MUL, true, slot_2, lo_word(OP_SIZE_NATIVE), true, R_CX));
508 g(gen_frame_load_op(ctx, OP_SIZE_NATIVE, garbage, ALU_MUL, true, slot_1, lo_word(OP_SIZE_NATIVE), true, R_AX));
509 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_ADD, R_CX, R_CX, R_AX, 0));
510 g(gen_frame_load(ctx, OP_SIZE_NATIVE, garbage, slot_2, lo_word(OP_SIZE_NATIVE), true, R_AX));
512 offset = (size_t)slot_1 * slot_size + lo_word(OP_SIZE_NATIVE);
513 g(gen_address(ctx, R_FRAME, offset, IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
514 gen_insn(INSN_MUL_L, OP_SIZE_NATIVE, 0, 1);
518 gen_address_offset();
520 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_ADD, R_DX, R_DX, R_CX, 0));
522 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, R_AX, R_DX));
525 #elif defined(ARCH_ARM32)
526 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_1, 0, R_SCRATCH_1, R_SCRATCH_2));
527 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_2, 0, R_SCRATCH_3, R_SCRATCH_4));
529 g(gen_mov(ctx, OP_SIZE_NATIVE, R_SCRATCH_NA_1, R_SCRATCH_1));
531 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_MUL, R_SCRATCH_4, R_SCRATCH_1, R_SCRATCH_4, 0));
533 gen_insn(INSN_MADD, OP_SIZE_NATIVE, 0, 0);
534 gen_one(R_SCRATCH_2);
535 gen_one(R_SCRATCH_3);
536 gen_one(R_SCRATCH_2);
537 gen_one(R_SCRATCH_4);
539 gen_insn(INSN_MUL_L, OP_SIZE_NATIVE, 0, 0);
540 gen_one(R_SCRATCH_1);
541 gen_one(R_SCRATCH_4);
542 gen_one(R_SCRATCH_NA_1);
543 gen_one(R_SCRATCH_3);
545 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_ADD, R_SCRATCH_2, R_SCRATCH_2, R_SCRATCH_4, 0));
547 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, R_SCRATCH_1, R_SCRATCH_2));
550 #elif defined(ARCH_ARM64)
551 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_1, 0, R_SCRATCH_1, R_SCRATCH_2));
552 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_2, 0, R_SCRATCH_3, R_SCRATCH_4));
554 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_UMULH, R_SCRATCH_NA_1, R_SCRATCH_1, R_SCRATCH_3, 0));
556 gen_insn(INSN_MADD, OP_SIZE_NATIVE, 0, 0);
557 gen_one(R_SCRATCH_NA_1);
558 gen_one(R_SCRATCH_2);
559 gen_one(R_SCRATCH_3);
560 gen_one(R_SCRATCH_NA_1);
562 gen_insn(INSN_MADD, OP_SIZE_NATIVE, 0, 0);
563 gen_one(R_SCRATCH_2);
564 gen_one(R_SCRATCH_1);
565 gen_one(R_SCRATCH_4);
566 gen_one(R_SCRATCH_NA_1);
568 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_MUL, R_SCRATCH_1, R_SCRATCH_1, R_SCRATCH_3, 0));
570 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, R_SCRATCH_1, R_SCRATCH_2));
574 g(gen_alu_typed_upcall(ctx, offsetof(struct cg_upcall_vector_s, FIXED_binary_multiply_int8_t), op_size, slot_1, slot_2, slot_r, 0));
579 #if defined(ARCH_X86)
580 if (mode == MODE_INT) {
581 if (op_size != OP_SIZE_1 && slot_r == slot_1 && slot_is_register(ctx, slot_1)) {
583 target = ctx->registers[slot_1];
584 g(gen_mov(ctx, op_size, R_SCRATCH_1, target));
585 g(gen_frame_load_op(ctx, op_size, garbage, ALU_MUL, mode == MODE_INT, slot_2, 0, false, target));
586 ce = alloc_undo_label(ctx);
589 ce->undo_opcode = INSN_MOV;
590 ce->undo_op_size = op_size;
592 ce->undo_writes_flags = 0;
593 ce->undo_parameters[0] = target;
594 ce->undo_parameters[1] = R_SCRATCH_1;
595 ce->undo_parameters_len = 2;
596 gen_insn(INSN_JMP_COND, op_size, COND_O, 0);
597 gen_four(ce->undo_label);
600 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
602 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, slot_2, R_SCRATCH_1);
604 if (op_size == OP_SIZE_1)
605 target = R_SCRATCH_1;
606 g(gen_frame_load(ctx, op_size, garbage, slot_1, 0, false, target));
607 if (op_size == OP_SIZE_1 && frame_t_is_const(slot_2)) {
608 g(gen_load_constant(ctx, R_SCRATCH_3, frame_t_get_const(slot_2)));
609 gen_insn(INSN_ALU + ARCH_PARTIAL_ALU(op_size), op_size, ALU_MUL, 1);
612 gen_one(R_SCRATCH_3);
614 g(gen_frame_load_op(ctx, op_size, garbage, ALU_MUL, mode == MODE_INT, slot_2, 0, false, target));
616 if (mode == MODE_INT) {
617 gen_insn(INSN_JMP_COND, op_size, COND_O, 0);
620 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
623 #if defined(ARCH_ALPHA)
624 if (mode == MODE_INT && ARCH_SUPPORTS_TRAPS(op_size)) {
625 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
626 g(gen_frame_get(ctx, op_size, garbage, slot_1, R_SCRATCH_1, ®1));
627 g(gen_frame_get(ctx, op_size, garbage, slot_2, R_SCRATCH_2, ®2));
629 gen_insn(INSN_ALU_TRAP, op_size, ALU_MUL, ALU_WRITES_FLAGS(op_size, ALU_MUL, false, false, 0));
634 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
639 #if defined(ARCH_ARM32)
640 if (mode == MODE_INT && op_size == OP_SIZE_4) {
641 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_3);
642 g(gen_frame_get(ctx, op_size, garbage, slot_1, R_SCRATCH_1, ®1));
643 g(gen_frame_get(ctx, op_size, garbage, slot_2, R_SCRATCH_2, ®2));
645 gen_insn(INSN_MUL_L, OP_SIZE_NATIVE, 0, 0);
647 gen_one(R_SCRATCH_4);
651 gen_insn(INSN_CMP, OP_SIZE_NATIVE, 0, 1);
652 gen_one(R_SCRATCH_4);
653 gen_one(ARG_SHIFTED_REGISTER);
654 gen_one(ARG_SHIFT_ASR | 0x1f);
657 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_NE, 0);
660 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
665 #if defined(ARCH_ARM64)
666 if (mode == MODE_INT && op_size == OP_SIZE_4) {
667 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
668 g(gen_frame_get(ctx, op_size, op_size < OP_SIZE_4 ? sign_x : garbage, slot_1, R_SCRATCH_1, ®1));
669 g(gen_frame_get(ctx, op_size, op_size < OP_SIZE_4 ? sign_x : garbage, slot_2, R_SCRATCH_2, ®2));
670 gen_insn(INSN_ALU, OP_SIZE_8, ALU_MUL, ALU_WRITES_FLAGS(OP_SIZE_8, ALU_MUL, false, false, 0));
672 gen_one(ARG_EXTENDED_REGISTER);
673 gen_one(ARG_EXTEND_SXTW);
675 gen_one(ARG_EXTENDED_REGISTER);
676 gen_one(ARG_EXTEND_SXTW);
679 gen_insn(INSN_CMP, OP_SIZE_8, 0, 1);
681 gen_one(ARG_EXTENDED_REGISTER);
682 gen_one(ARG_EXTEND_SXTW);
685 gen_insn(INSN_JMP_COND, OP_SIZE_8, COND_NE, 0);
688 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
692 if (mode == MODE_INT && op_size == OP_SIZE_8) {
693 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
694 g(gen_frame_get(ctx, op_size, garbage, slot_1, R_SCRATCH_1, ®1));
695 g(gen_frame_get(ctx, op_size, garbage, slot_2, R_SCRATCH_2, ®2));
696 g(gen_3address_alu(ctx, OP_SIZE_8, ALU_SMULH, R_SCRATCH_3, reg1, reg2, 0));
698 g(gen_3address_alu(ctx, OP_SIZE_8, ALU_MUL, target, reg1, reg2, 0));
700 gen_insn(INSN_CMP, OP_SIZE_8, 0, 1);
701 gen_one(R_SCRATCH_3);
702 gen_one(ARG_SHIFTED_REGISTER);
703 gen_one(ARG_SHIFT_ASR | 0x3f);
706 gen_insn(INSN_JMP_COND, OP_SIZE_8, COND_NE, 0);
709 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
714 #if defined(ARCH_POWER)
715 if (mode == MODE_INT && op_size >= OP_SIZE_4) {
716 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
717 g(gen_frame_get(ctx, op_size, garbage, slot_1, R_SCRATCH_1, ®1));
718 g(gen_frame_get(ctx, op_size, garbage, slot_2, R_SCRATCH_2, ®2));
720 g(gen_3address_alu(ctx, op_size, ALU_MUL, target, reg1, reg2, 1));
722 gen_insn(INSN_JMP_COND, op_size, COND_O, 0);
725 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
730 #if defined(ARCH_LOONGARCH64) || (defined(ARCH_MIPS) && MIPS_R6) || defined(ARCH_RISCV64)
731 if (mode == MODE_INT && op_size == OP_SIZE_NATIVE) {
732 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
733 g(gen_frame_get(ctx, op_size, garbage, slot_1, R_SCRATCH_1, ®1));
734 g(gen_frame_get(ctx, op_size, garbage, slot_2, R_SCRATCH_2, ®2));
736 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_SMULH, R_SCRATCH_3, reg1, reg2, 0));
738 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_MUL, target, reg1, reg2, 0));
740 g(gen_3address_rot_imm(ctx, OP_SIZE_NATIVE, ROT_SAR, R_SCRATCH_4, target, (8U << OP_SIZE_NATIVE) - 1, 0));
742 g(gen_cmp_test_jmp(ctx, INSN_CMP, OP_SIZE_NATIVE, R_SCRATCH_3, R_SCRATCH_4, COND_NE, label_ovf));
744 g(gen_frame_store(ctx, OP_SIZE_NATIVE, slot_r, 0, target));
749 #if defined(ARCH_S390)
750 if (mode == MODE_INT && op_size >= OP_SIZE_4 && likely(cpu_test_feature(CPU_FEATURE_misc_insn_ext_2))) {
751 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
752 g(gen_frame_load(ctx, op_size, sign_x, slot_1, 0, false, target));
753 g(gen_frame_load_op(ctx, op_size, sign_x, ALU_MUL, 1, slot_2, 0, false, target));
755 gen_insn(INSN_JMP_COND, op_size, COND_O, 0);
758 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
762 #if (defined(ARCH_MIPS) && !MIPS_R6) || defined(ARCH_S390)
763 #if defined(ARCH_MIPS)
764 if (mode == MODE_INT && op_size >= OP_SIZE_4)
766 #if defined(ARCH_S390)
767 if (mode == MODE_INT && op_size == OP_SIZE_4)
770 #if defined(ARCH_S390)
771 target = R_SCRATCH_1;
773 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
775 g(gen_frame_get(ctx, op_size, sign_x, slot_1, R_SCRATCH_1, ®1));
776 g(gen_frame_get(ctx, op_size, sign_x, slot_2, R_SCRATCH_3, ®2));
778 gen_insn(INSN_MUL_L, op_size, 0, 0);
780 gen_one(R_SCRATCH_2);
784 g(gen_3address_rot_imm(ctx, op_size, ROT_SAR, R_SCRATCH_4, target, (8U << op_size) - 1, false));
786 g(gen_cmp_test_jmp(ctx, INSN_CMP, op_size, R_SCRATCH_2, R_SCRATCH_4, COND_NE, label_ovf));
788 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
792 if (mode == MODE_INT && op_size == OP_SIZE_NATIVE) {
793 g(gen_alu_typed_upcall(ctx, offsetof(struct cg_upcall_vector_s, INT_binary_multiply_int8_t), op_size, slot_1, slot_2, slot_r, label_ovf));
797 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
798 if (op_size < OP_SIZE_NATIVE && mode == MODE_INT) {
799 g(gen_frame_get(ctx, op_size, sign_x, slot_1, R_SCRATCH_1, ®1));
800 g(gen_frame_get(ctx, op_size, sign_x, slot_2, R_SCRATCH_2, ®2));
802 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_MUL, target, reg1, reg2, 0));
804 g(gen_frame_load(ctx, op_size, sign_x, slot_1, 0, false, target));
805 g(gen_frame_load_op(ctx, op_size, sign_x, ALU_MUL, 0, slot_2, 0, false, target));
808 if (mode == MODE_INT) {
809 g(gen_cmp_extended(ctx, OP_SIZE_NATIVE, op_size, target, R_SCRATCH_2, label_ovf));
812 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
821 uint32_t attr_unused label_skip = 0; /* avoid warning */
822 uint32_t attr_unused label_skip2 = 0; /* avoid warning */
823 uint32_t attr_unused label_end = 0; /* avoid warning */
824 uint32_t attr_unused label_div_0 = 0; /* avoid warning */
825 unsigned attr_unused divide_alu = 0; /* avoid warning */
826 bool attr_unused have_mod = false;
827 bool attr_unused force_sx = false;
828 unsigned attr_unused div_op_size = i_size(op_size);
829 if (unlikely(op_size > OP_SIZE_NATIVE) || unlikely(!ARCH_HAS_DIV)
830 #if defined(ARCH_S390)
831 || !(Z || (op_size <= OP_SIZE_4 && sgn))
835 if (mode == MODE_INT) {
836 upcall = !mod ? offsetof(struct cg_upcall_vector_s, INT_binary_divide_int8_t) : offsetof(struct cg_upcall_vector_s, INT_binary_modulo_int8_t);
838 upcall = !mod ? offsetof(struct cg_upcall_vector_s, FIXED_binary_divide_int8_t) : offsetof(struct cg_upcall_vector_s, FIXED_binary_modulo_int8_t);
840 upcall = !mod ? offsetof(struct cg_upcall_vector_s, FIXED_binary_udivide_int8_t) : offsetof(struct cg_upcall_vector_s, FIXED_binary_umodulo_int8_t);
842 g(gen_alu_typed_upcall(ctx, upcall, op_size, slot_1, slot_2, slot_r, mode == MODE_INT ? label_ovf : 0));
845 #if defined(ARCH_X86) || defined(ARCH_S390)
846 if (mode == MODE_FIXED) {
847 label_skip = alloc_label(ctx);
848 if (unlikely(!label_skip))
850 label_end = alloc_label(ctx);
851 if (unlikely(!label_end))
854 label_skip2 = alloc_label(ctx);
855 if (unlikely(!label_skip2))
859 #if defined(ARCH_X86)
860 if (R_SCRATCH_1 != R_AX || R_SCRATCH_2 != R_DX || R_SCRATCH_3 != R_CX)
861 internal(file_line, "gen_alu: bad scratch registers");
863 g(gen_frame_load(ctx, op_size, sgn ? sign_x : zero_x, slot_1, 0, false, R_SCRATCH_1));
864 g(gen_frame_load(ctx, op_size, sgn ? sign_x : zero_x, slot_2, 0, false, R_SCRATCH_3));
866 g(gen_jmp_on_zero(ctx, i_size(op_size), R_SCRATCH_3, COND_E, mode == MODE_INT ? label_ovf : label_skip));
870 uint32_t label_not_minus_1;
871 label_not_minus_1 = alloc_label(ctx);
872 if (unlikely(!label_not_minus_1))
875 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, op_size, R_SCRATCH_3, -1, COND_NE, label_not_minus_1));
877 val = -(uint64_t)0x80 << (((1 << op_size) - 1) * 8);
878 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, op_size, R_SCRATCH_1, val, COND_E, mode == MODE_INT ? label_ovf : label_skip2));
880 gen_label(label_not_minus_1);
883 #if defined(ARCH_X86)
884 if (op_size >= OP_SIZE_2) {
886 gen_insn(INSN_CWD + ARCH_PARTIAL_ALU(op_size), op_size, 0, 0);
887 gen_one(R_SCRATCH_2);
888 gen_one(R_SCRATCH_1);
889 if (op_size == OP_SIZE_2)
890 gen_one(R_SCRATCH_2);
892 g(gen_3address_alu(ctx, OP_SIZE_4, ALU_XOR, R_SCRATCH_2, R_SCRATCH_2, R_SCRATCH_2, 0));
895 gen_insn(INSN_DIV_L, op_size, sgn, 1);
896 gen_one(R_SCRATCH_1);
897 gen_one(i_size(op_size) == OP_SIZE_1 ? R_SCRATCH_1 : R_SCRATCH_2);
898 gen_one(R_SCRATCH_1);
899 gen_one(i_size(op_size) == OP_SIZE_1 ? R_SCRATCH_1 : R_SCRATCH_2);
900 gen_one(R_SCRATCH_3);
903 g(gen_load_constant(ctx, R_SCRATCH_2, 0));
904 } else if (op_size <= OP_SIZE_4) {
905 g(gen_3address_rot_imm(ctx, OP_SIZE_NATIVE, ROT_SAR, R_SCRATCH_2, R_SCRATCH_1, (1U << (OP_SIZE_NATIVE + 3)) - 1, false));
907 gen_insn(INSN_DIV_L, i_size(op_size), sgn, 1);
908 gen_one(R_SCRATCH_2);
909 gen_one(R_SCRATCH_1);
910 gen_one(R_SCRATCH_2);
911 gen_one(R_SCRATCH_1);
912 gen_one(R_SCRATCH_3);
914 if (mod && i_size(op_size) == OP_SIZE_1) {
915 g(gen_3address_rot_imm(ctx, OP_SIZE_2, ROT_SHR, R_SCRATCH_1, R_SCRATCH_1, 8, 0));
916 g(gen_frame_store(ctx, op_size, slot_r, 0, R_SCRATCH_1));
918 g(gen_frame_store(ctx, op_size, slot_r, 0, R_SCRATCH_2));
920 g(gen_frame_store(ctx, op_size, slot_r, 0, R_SCRATCH_1));
922 if (mode == MODE_FIXED) {
923 gen_insn(INSN_JMP, 0, 0, 0);
927 gen_label(label_skip2);
930 g(gen_frame_clear(ctx, op_size, slot_r));
932 g(gen_frame_store(ctx, op_size, slot_r, 0, R_SCRATCH_1));
934 gen_insn(INSN_JMP, 0, 0, 0);
938 gen_label(label_skip);
940 g(gen_frame_clear(ctx, op_size, slot_r));
942 g(gen_frame_store(ctx, op_size, slot_r, 0, R_SCRATCH_1));
943 gen_label(label_end);
947 #if defined(ARCH_MIPS)
949 div_op_size = maximum(op_size, OP_SIZE_4);
950 if (op_size == OP_SIZE_4)
953 #if defined(ARCH_POWER)
954 have_mod = cpu_test_feature(CPU_FEATURE_v30);
955 div_op_size = maximum(op_size, OP_SIZE_4);
957 #if defined(ARCH_LOONGARCH64) || defined(ARCH_RISCV64)
959 div_op_size = maximum(op_size, OP_SIZE_4);
961 label_end = alloc_label(ctx);
962 if (unlikely(!label_end))
965 g(gen_frame_get(ctx, op_size, (sgn && op_size < i_size(op_size)) || force_sx ? sign_x : zero_x, slot_1, R_SCRATCH_1, ®1));
966 g(gen_frame_get(ctx, op_size, (sgn && op_size < i_size(op_size)) || force_sx ? sign_x : zero_x, slot_2, R_SCRATCH_2, ®2));
967 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_3);
969 if (ARCH_PREFERS_SX(op_size) && !sgn && op_size < i_size(op_size)) {
970 g(gen_extend(ctx, op_size, zero_x, R_SCRATCH_1, reg1));
972 g(gen_extend(ctx, op_size, zero_x, R_SCRATCH_2, reg2));
976 if (mode == MODE_INT) {
977 g(gen_jmp_on_zero(ctx, i_size(op_size), reg2, COND_E, label_ovf));
980 uint32_t label_not_minus_1;
981 label_not_minus_1 = alloc_label(ctx);
982 if (unlikely(!label_not_minus_1))
985 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, i_size(op_size), reg2, -1, COND_NE, label_not_minus_1));
987 val = 0xFFFFFFFFFFFFFF80ULL << (((1 << op_size) - 1) * 8);
988 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, i_size(op_size), reg1, val, COND_E, label_ovf));
990 gen_label(label_not_minus_1);
993 #if !(defined(ARCH_ARM) && ARM_ASM_DIV_NO_TRAP)
995 g(gen_load_constant(ctx, target, 0));
997 g(gen_mov(ctx, OP_SIZE_NATIVE, target, reg1));
999 g(gen_jmp_on_zero(ctx, i_size(op_size), reg2, COND_E, label_end));
1002 uint32_t label_not_minus_1;
1003 label_not_minus_1 = alloc_label(ctx);
1004 if (unlikely(!label_not_minus_1))
1007 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, i_size(op_size), reg2, -1, COND_NE, label_not_minus_1));
1010 g(gen_mov(ctx, OP_SIZE_NATIVE, target, reg1));
1012 g(gen_load_constant(ctx, target, 0));
1015 val = 0xFFFFFFFFFFFFFF80ULL << (((1 << op_size) - 1) * 8);
1016 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, i_size(op_size), reg1, val, COND_E, label_end));
1018 gen_label(label_not_minus_1);
1022 if (mod && have_mod) {
1023 g(gen_3address_alu(ctx, div_op_size, sgn ? ALU_SREM : ALU_UREM, target, reg1, reg2, 0));
1025 g(gen_3address_alu(ctx, div_op_size, sgn ? ALU_SDIV : ALU_UDIV, target, reg1, reg2, 0));
1028 if (mod && !have_mod) {
1029 #if defined(ARCH_ARM)
1030 gen_insn(INSN_MADD, i_size(op_size), 1, 0);
1036 g(gen_3address_alu(ctx, i_size(op_size), ALU_MUL, R_SCRATCH_2, reg2, target, 0));
1037 g(gen_3address_alu(ctx, i_size(op_size), ALU_SUB, target, reg1, R_SCRATCH_2, 0));
1041 gen_label(label_end);
1042 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1053 int64_t cnst = 0; /* avoid warning */
1054 bool c = frame_t_is_const(slot_2);
1055 if (unlikely(op_size > OP_SIZE_NATIVE)) {
1057 if (mode == MODE_FIXED) {
1059 case ROT_SHL: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_shl_,TYPE_INT_MAX));
1061 case ROT_SAR: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_shr_,TYPE_INT_MAX));
1063 case ROT_SHR: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_ushr_,TYPE_INT_MAX));
1065 case ROT_ROL: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_rol_,TYPE_INT_MAX));
1067 case ROT_ROR: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_ror_,TYPE_INT_MAX));
1069 default: internal(file_line, "do_alu: invalid shift %u", alu);
1073 case ROT_SHL: upcall = offsetof(struct cg_upcall_vector_s, cat(INT_binary_shl_,TYPE_INT_MAX));
1075 case ROT_SAR: upcall = offsetof(struct cg_upcall_vector_s, cat(INT_binary_shr_,TYPE_INT_MAX));
1077 default: internal(file_line, "do_alu: invalid shift %u", alu);
1080 g(gen_alu_upcall(ctx, upcall, op_size, slot_1, slot_2, slot_r, mode == MODE_INT ? label_ovf : 0));
1083 op_s = i_size_rot(op_size);
1084 #if defined(ARCH_X86)
1085 if (slot_1 == slot_r && !slot_is_register(ctx, slot_1) && !(mode == MODE_INT && alu == ROT_SHL)) {
1086 int64_t offset = (size_t)slot_1 * slot_size;
1088 cnst = frame_t_get_const(slot_2);
1089 if (mode == MODE_INT) {
1090 if ((uint64_t)cnst > (8U << op_size) - 1) {
1091 gen_insn(INSN_JMP, 0, 0, 0);
1092 gen_four(label_ovf);
1096 cnst &= (8U << op_size) - 1;
1098 g(gen_address(ctx, R_FRAME, offset, IMM_PURPOSE_LDR_OFFSET, op_size));
1099 gen_insn(INSN_ROT + ARCH_PARTIAL_ALU(op_size), op_size, alu, 1);
1100 gen_address_offset();
1101 gen_address_offset();
1105 g(gen_frame_load(ctx, op_size, garbage, slot_2, 0, false, R_SCRATCH_3));
1106 if (mode == MODE_INT) {
1107 int64_t imm = (8U << op_size) - 1;
1108 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, op_size, R_SCRATCH_3, imm, COND_A, label_ovf));
1109 } else if ((alu != ROT_ROL && alu != ROT_ROR) && op_size < OP_SIZE_4) {
1110 g(gen_3address_alu_imm(ctx, OP_SIZE_1, ALU_AND, R_SCRATCH_3, R_SCRATCH_3, (8U << op_size) - 1, 0));
1112 g(gen_address(ctx, R_FRAME, offset, IMM_PURPOSE_LDR_OFFSET, op_size));
1113 gen_insn(INSN_ROT + ARCH_PARTIAL_ALU(op_size), op_size, alu, 1);
1114 gen_address_offset();
1115 gen_address_offset();
1116 gen_one(R_SCRATCH_3);
1120 if (mode == MODE_INT && alu == ROT_SHL && op_size < OP_SIZE_NATIVE)
1123 must_mask = op_size < ARCH_SHIFT_SIZE;
1124 sx = (alu == ROT_SAR && op_size < op_s) || (alu == ROT_SHL && op_size < OP_SIZE_NATIVE && mode == MODE_INT);
1125 #if defined(ARCH_MIPS)
1126 sx |= op_size == OP_SIZE_4;
1128 g(gen_frame_get(ctx, op_size, sx ? sign_x : zero_x, slot_1, R_SCRATCH_1, ®1));
1130 reg3 = 0xff; /* avoid warning */
1131 cnst = frame_t_get_const(slot_2);
1133 #if defined(ARCH_X86)
1134 if (!ARCH_IS_3ADDRESS_ROT(alu, op_size)) {
1135 g(gen_frame_load(ctx, op_size, garbage, slot_2, 0, false, R_SCRATCH_3));
1139 g(gen_frame_get(ctx, op_size, garbage, slot_2, R_SCRATCH_3, ®3));
1141 if (ARCH_PREFERS_SX(op_size) && !sx && op_size < op_s) {
1142 g(gen_extend(ctx, op_size, zero_x, R_SCRATCH_1, reg1));
1146 if (mode == MODE_INT) {
1147 int64_t imm = (8U << op_size) - 1;
1149 if ((uint64_t)cnst > (uint64_t)imm) {
1150 gen_insn(INSN_JMP, 0, 0, 0);
1151 gen_four(label_ovf);
1155 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, i_size_cmp(op_size), reg3, imm, COND_A, label_ovf));
1158 #if defined(ARCH_ARM)
1159 if (alu == ROT_ROL) {
1161 cnst = -(uint64_t)cnst;
1163 g(gen_2address_alu1(ctx, OP_SIZE_4, ALU1_NEG, R_SCRATCH_3, reg3, 0));
1169 #if defined(ARCH_LOONGARCH64)
1170 if (alu == ROT_ROL && op_size >= OP_SIZE_4) {
1172 cnst = -(uint64_t)cnst;
1174 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_NEG, R_SCRATCH_3, reg3, 0));
1180 #if defined(ARCH_MIPS)
1181 if (MIPS_HAS_ROT && alu == ROT_ROL && op_size >= OP_SIZE_4) {
1183 cnst = -(uint64_t)cnst;
1185 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_NEG, R_SCRATCH_3, reg3, 0));
1191 #if defined(ARCH_POWER)
1192 if (alu == ROT_ROR && op_size >= OP_SIZE_4) {
1194 cnst = -(uint64_t)cnst;
1196 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_NEG, R_SCRATCH_3, reg3, 0));
1202 #if defined(ARCH_S390)
1203 if (Z && alu == ROT_ROR && op_size >= OP_SIZE_4) {
1205 cnst = -(uint64_t)cnst;
1207 g(gen_2address_alu1(ctx, OP_SIZE_4, ALU1_NEG, R_SCRATCH_3, reg3, 0));
1214 cnst &= (8U << op_size) - 1;
1215 } else if (must_mask) {
1216 g(gen_3address_alu_imm(ctx, i_size(OP_SIZE_4), ALU_AND, R_SCRATCH_3, reg3, (8U << op_size) - 1, 0));
1221 #if defined(ARCH_X86)
1222 if (mode == MODE_INT && alu == ROT_SHL) {
1223 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_2);
1225 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, slot_2, R_SCRATCH_2);
1228 g(gen_3address_rot_imm(ctx, op_s, alu, target, reg1, cnst, 0));
1230 g(gen_3address_rot(ctx, op_s, alu, target, reg1, reg3));
1233 if (mode == MODE_INT && alu == ROT_SHL) {
1234 if (op_size < OP_SIZE_NATIVE) {
1235 gen_insn(INSN_MOVSX, op_size, 0, 0);
1236 gen_one(R_SCRATCH_4);
1239 g(gen_cmp_test_jmp(ctx, INSN_CMP, op_s, target, R_SCRATCH_4, COND_NE, label_ovf));
1242 g(gen_3address_rot_imm(ctx, OP_SIZE_NATIVE, ROT_SAR, R_SCRATCH_4, target, cnst, 0));
1244 g(gen_3address_rot(ctx, OP_SIZE_NATIVE, ROT_SAR, R_SCRATCH_4, target, reg3));
1247 g(gen_cmp_test_jmp(ctx, INSN_CMP, OP_SIZE_NATIVE, reg1, R_SCRATCH_4, COND_NE, label_ovf));
1250 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1253 #if defined(ARCH_ARM)
1254 if (op_size <= OP_SIZE_2 && alu == ROT_ROR) {
1255 gen_insn(INSN_ALU, OP_SIZE_4, ALU_OR, ALU_WRITES_FLAGS(OP_SIZE_4, ALU_OR, false, false, 0));
1256 gen_one(R_SCRATCH_1);
1258 gen_one(ARG_SHIFTED_REGISTER);
1259 gen_one(ARG_SHIFT_LSL | (8U << op_size));
1261 if (op_size == OP_SIZE_1)
1265 goto do_generic_shift;
1267 #if defined(ARCH_LOONGARCH64)
1268 if (alu == ROT_ROR && op_size >= OP_SIZE_4)
1269 goto do_generic_shift;
1271 #if defined(ARCH_MIPS)
1272 if (MIPS_HAS_ROT && alu == ROT_ROR && op_size >= OP_SIZE_4)
1273 goto do_generic_shift;
1275 #if defined(ARCH_POWER)
1276 if (alu == ROT_ROL && op_size >= OP_SIZE_4)
1277 goto do_generic_shift;
1279 #if defined(ARCH_RISCV64)
1280 if ((alu == ROT_ROL || alu == ROT_ROR) && likely(cpu_test_feature(CPU_FEATURE_zbb))) {
1281 if (likely(op_size >= OP_SIZE_4)) {
1282 goto do_generic_shift;
1286 #if defined(ARCH_S390)
1287 if (Z && alu == ROT_ROL && op_size >= OP_SIZE_4)
1288 goto do_generic_shift;
1290 if (alu == ROT_ROL || alu == ROT_ROR) {
1291 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
1293 g(gen_3address_rot_imm(ctx, op_s, alu == ROT_ROL ? ROT_SHL : ROT_SHR, R_SCRATCH_2, reg1, cnst, 0));
1294 g(gen_3address_rot_imm(ctx, op_s, alu == ROT_ROL ? ROT_SHR : ROT_SHL, target, reg1, -(uint64_t)cnst & ((8U << op_size) - 1), 0));
1296 g(gen_3address_rot(ctx, op_s, alu == ROT_ROL ? ROT_SHL : ROT_SHR, R_SCRATCH_2, reg1, reg3));
1297 g(gen_2address_alu1(ctx, i_size(OP_SIZE_4), ALU1_NEG, R_SCRATCH_3, reg3, 0));
1299 g(gen_3address_alu_imm(ctx, i_size(OP_SIZE_4), ALU_AND, R_SCRATCH_3, R_SCRATCH_3, (8U << op_size) - 1, 0));
1301 g(gen_3address_rot(ctx, op_s, alu == ROT_ROL ? ROT_SHR : ROT_SHL, target, reg1, R_SCRATCH_3));
1303 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_OR, target, target, R_SCRATCH_2, 0));
1304 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1308 goto do_generic_shift;
1310 if (mode == MODE_INT && alu == ROT_SHL) {
1311 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
1312 #if defined(ARCH_S390)
1313 if (op_size >= OP_SIZE_4) {
1315 g(gen_3address_rot_imm(ctx, op_size, ROT_SAL, target, reg1, cnst, 0));
1317 g(gen_3address_rot(ctx, op_size, ROT_SAL, target, reg1, reg3));
1319 gen_insn(INSN_JMP_COND, op_size, COND_O, 0);
1320 gen_four(label_ovf);
1323 if (op_size <= OP_SIZE_NATIVE - 1) {
1325 g(gen_3address_rot_imm(ctx, OP_SIZE_NATIVE, alu, target, reg1, cnst, 0));
1327 g(gen_3address_rot(ctx, OP_SIZE_NATIVE, alu, target, reg1, reg3));
1329 g(gen_cmp_extended(ctx, OP_SIZE_NATIVE, op_size, target, R_SCRATCH_2, label_ovf));
1332 g(gen_3address_rot_imm(ctx, OP_SIZE_NATIVE, alu, R_SCRATCH_2, reg1, cnst, 0));
1333 g(gen_3address_rot_imm(ctx, OP_SIZE_NATIVE, ROT_SAR, R_SCRATCH_4, R_SCRATCH_2, cnst, 0));
1335 g(gen_3address_rot(ctx, OP_SIZE_NATIVE, alu, R_SCRATCH_2, reg1, reg3));
1336 g(gen_3address_rot(ctx, OP_SIZE_NATIVE, ROT_SAR, R_SCRATCH_4, R_SCRATCH_2, reg3));
1339 g(gen_cmp_test_jmp(ctx, INSN_CMP, OP_SIZE_NATIVE, reg1, R_SCRATCH_4, COND_NE, label_ovf));
1341 g(gen_frame_store(ctx, op_size, slot_r, 0, R_SCRATCH_2));
1346 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, slot_2, R_SCRATCH_1);
1348 g(gen_3address_rot_imm(ctx, op_s, alu, target, reg1, cnst, 0));
1350 g(gen_3address_rot(ctx, op_s, alu, target, reg1, reg3));
1353 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1360 unsigned attr_unused op_s;
1362 bool c = frame_t_is_const(slot_2);
1363 int64_t cnst = !c ? 0 : frame_t_get_const(slot_2);
1364 int64_t max_imm = (8U << op_size) - 1;
1366 if (mode == MODE_INT) {
1367 if (alu == BTX_BT ? (uint64_t)cnst > (uint64_t)max_imm : (uint64_t)cnst >= (uint64_t)max_imm) {
1368 gen_insn(INSN_JMP, 0, 0, 0);
1369 gen_four(label_ovf);
1375 #if defined(ARCH_X86)
1376 if ((alu == BTX_BT || slot_1 == slot_r) && !slot_is_register(ctx, slot_1)) {
1378 unsigned n_op_size = minimum(op_size, OP_SIZE_NATIVE);
1379 g(gen_frame_get(ctx, n_op_size, garbage, slot_2, R_SCRATCH_1, ®2));
1380 if (mode == MODE_INT) {
1382 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, n_op_size, reg2, max_imm, alu == BTX_BT ? COND_A : COND_AE, label_ovf));
1383 if (unlikely(op_size > OP_SIZE_NATIVE)) {
1384 g(gen_address(ctx, R_FRAME, (size_t)slot_2 * slot_size + hi_word(OP_SIZE_NATIVE), IMM_PURPOSE_STR_OFFSET, OP_SIZE_NATIVE));
1385 gen_insn(INSN_CMP, OP_SIZE_NATIVE, 0, 1);
1386 gen_address_offset();
1389 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_NE, 0);
1390 gen_four(label_ovf);
1395 g(gen_3address_alu_imm(ctx, OP_SIZE_4, ALU_AND, R_SCRATCH_1, reg2, (8U << op_size) - 1, 0));
1399 offset = (size_t)slot_1 * slot_size;
1400 if (c && cnst >= 8U << OP_SIZE_NATIVE) {
1401 offset += 1U << OP_SIZE_NATIVE;
1402 cnst -= 8U << OP_SIZE_NATIVE;
1404 g(gen_address(ctx, R_FRAME, offset, IMM_PURPOSE_STR_OFFSET, maximum(n_op_size, OP_SIZE_2)));
1405 if (alu == BTX_BT) {
1406 gen_insn(INSN_BT, maximum(n_op_size, OP_SIZE_2), 0, 1);
1407 gen_address_offset();
1414 g(gen_frame_set_cond(ctx, maximum(n_op_size, OP_SIZE_2), false, COND_B, slot_r));
1416 gen_insn(INSN_BTX, maximum(n_op_size, OP_SIZE_2), alu, 1);
1417 gen_address_offset();
1418 gen_address_offset();
1429 if (unlikely(op_size > OP_SIZE_NATIVE)) {
1431 if (mode == MODE_FIXED) {
1433 case BTX_BTS: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_bts_,TYPE_INT_MAX));
1435 case BTX_BTR: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_btr_,TYPE_INT_MAX));
1437 case BTX_BTC: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_btc_,TYPE_INT_MAX));
1439 case BTX_BT: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_bt_,TYPE_INT_MAX));
1441 default: internal(file_line, "do_alu: invalid bit test %u", alu);
1445 case BTX_BTS: upcall = offsetof(struct cg_upcall_vector_s, cat(INT_binary_bts_,TYPE_INT_MAX));
1447 case BTX_BTR: upcall = offsetof(struct cg_upcall_vector_s, cat(INT_binary_btr_,TYPE_INT_MAX));
1449 case BTX_BTC: upcall = offsetof(struct cg_upcall_vector_s, cat(INT_binary_btc_,TYPE_INT_MAX));
1451 case BTX_BT: upcall = offsetof(struct cg_upcall_vector_s, cat(INT_binary_bt_,TYPE_INT_MAX));
1453 default: internal(file_line, "do_alu: invalid bit test %u", alu);
1456 g(gen_alu_upcall(ctx, upcall, op_size, slot_1, slot_2, slot_r, label_ovf));
1459 op_s = minimum(OP_SIZE_NATIVE, ARCH_SHIFT_SIZE);
1460 op_s = maximum(op_s, op_size);
1461 g(gen_frame_get(ctx, op_size, zero_x, slot_1, R_SCRATCH_1, ®1));
1463 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
1464 if (ARCH_HAS_BTX(alu == BTX_BT ? BTX_BTEXT : alu, OP_SIZE_NATIVE, true)) {
1466 g(gen_mov(ctx, OP_SIZE_NATIVE, target, reg1));
1468 gen_insn(INSN_BTX, OP_SIZE_NATIVE, alu == BTX_BT ? BTX_BTEXT : alu, 1);
1470 gen_insn(INSN_BTX, OP_SIZE_NATIVE, alu == BTX_BT ? BTX_BTEXT : alu, 0);
1476 } else switch (alu) {
1478 g(gen_3address_alu_imm(ctx, i_size(op_size), ALU_OR, target, reg1, 1ULL << cnst, 0));
1481 g(gen_3address_alu_imm(ctx, i_size(op_size), ALU_AND, target, reg1, ~(1ULL << cnst), 0));
1484 g(gen_3address_alu_imm(ctx, i_size(op_size), ALU_XOR, target, reg1, 1ULL << cnst, 0));
1488 g(gen_3address_rot_imm(ctx, i_size(op_size), ROT_SHR, target, reg1, cnst, 0));
1490 g(gen_3address_alu_imm(ctx, i_size(op_size), ALU_AND, target, target, 1, 0));
1493 internal(file_line, "do_alu: invalid bit test %u", alu);
1496 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, target));
1498 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1501 g(gen_frame_get(ctx, op_size, garbage, slot_2, R_SCRATCH_2, ®2));
1502 if (mode == MODE_INT) {
1504 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, i_size_cmp(op_size), reg2, max_imm, alu == BTX_BT ? COND_A : COND_AE, label_ovf));
1506 if (alu != BTX_BT) {
1507 if (!ARCH_HAS_BTX(alu, OP_SIZE_NATIVE, false))
1509 need_mask = !ARCH_HAS_BTX(alu, op_size, false);
1511 #if defined(ARCH_X86)
1512 need_mask = op_size < OP_SIZE_2;
1514 if (!ARCH_HAS_BTX(BTX_BTEXT, OP_SIZE_NATIVE, false))
1516 need_mask = !ARCH_HAS_BTX(BTX_BTEXT, op_size, false);
1520 g(gen_3address_alu_imm(ctx, OP_SIZE_4, ALU_AND, R_SCRATCH_2, reg2, (8U << op_size) - 1, 0));
1523 if (alu == BTX_BT) {
1524 #if defined(ARCH_X86)
1525 gen_insn(INSN_BT, maximum(op_size, OP_SIZE_2), 0, 1);
1529 g(gen_frame_set_cond(ctx, maximum(op_size, OP_SIZE_2), false, COND_B, slot_r));
1531 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
1532 gen_insn(INSN_BTX, need_mask ? OP_SIZE_NATIVE : op_size, BTX_BTEXT, 0);
1537 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, target));
1540 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, slot_2, R_SCRATCH_1);
1541 #if defined(ARCH_X86)
1543 target = R_SCRATCH_1;
1544 if (target != reg1) {
1545 g(gen_mov(ctx, op_size, target, reg1));
1548 gen_insn(INSN_BTX, maximum(op_size, OP_SIZE_2), alu, 1);
1550 gen_insn(INSN_BTX, need_mask ? OP_SIZE_NATIVE : op_size, alu, 0);
1556 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1562 if (mode == MODE_FIXED && op_size < ARCH_SHIFT_SIZE) {
1563 g(gen_3address_alu_imm(ctx, i_size(OP_SIZE_4), ALU_AND, R_SCRATCH_2, reg2, (8U << op_size) - 1, 0));
1566 g(gen_load_constant(ctx, R_SCRATCH_3, 1));
1568 g(gen_3address_rot(ctx, op_s, ROT_SHL, R_SCRATCH_3, R_SCRATCH_3, reg2));
1573 #if defined(ARCH_S390) || defined(ARCH_POWER)
1574 g(gen_3address_alu(ctx, i_size(op_size), ALU_AND, R_SCRATCH_1, reg1, R_SCRATCH_3, 1));
1576 gen_insn(INSN_TEST, i_size(op_size), 0, 1);
1578 gen_one(R_SCRATCH_3);
1580 g(gen_frame_set_cond(ctx, i_size_cmp(op_size), false, COND_NE, slot_r));
1582 g(gen_3address_alu(ctx, i_size(op_size), ALU_AND, R_SCRATCH_1, reg1, R_SCRATCH_3, 0));
1583 g(gen_frame_cmp_imm_set_cond_reg(ctx, i_size(op_size), R_SCRATCH_1, 0, COND_NE, slot_r));
1587 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
1588 g(gen_3address_alu(ctx, i_size(op_size), ALU_OR, target, reg1, R_SCRATCH_3, 0));
1591 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
1592 if (!ARCH_HAS_ANDN) {
1593 g(gen_3address_alu_imm(ctx, i_size(op_size), ALU_XOR, R_SCRATCH_3, R_SCRATCH_3, -1, 0));
1595 g(gen_3address_alu(ctx, i_size(op_size), ALU_AND, target, reg1, R_SCRATCH_3, 0));
1598 g(gen_3address_alu(ctx, i_size(op_size), ALU_ANDN, target, reg1, R_SCRATCH_3, 0));
1601 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
1602 g(gen_3address_alu(ctx, i_size(op_size), ALU_XOR, target, reg1, R_SCRATCH_3, 0));
1605 internal(file_line, "gen_alu: unsupported bit test %u", alu);
1608 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1616 if (unlikely(op_size > OP_SIZE_NATIVE)) {
1617 size_t attr_unused upcall;
1618 frame_t attr_unused swap;
1622 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_1, 0, R_SCRATCH_1, R_SCRATCH_2));
1623 g(gen_frame_load_op(ctx, OP_SIZE_NATIVE, garbage, ALU_XOR, 0, slot_2, lo_word(OP_SIZE_NATIVE), true, R_SCRATCH_1));
1624 g(gen_frame_load_op(ctx, OP_SIZE_NATIVE, garbage, ALU_XOR, 0, slot_2, hi_word(OP_SIZE_NATIVE), true, R_SCRATCH_2));
1625 #if defined(ARCH_ARM64)
1626 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_OR, R_SCRATCH_1, R_SCRATCH_1, R_SCRATCH_2, 0));
1628 gen_insn(INSN_CMP, OP_SIZE_NATIVE, 0, 1);
1629 gen_one(R_SCRATCH_1);
1633 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_OR, R_SCRATCH_1, R_SCRATCH_1, R_SCRATCH_2, ARCH_HAS_FLAGS));
1636 g(gen_frame_set_cond(ctx, OP_SIZE_NATIVE, false, alu, slot_r));
1638 g(gen_frame_cmp_imm_set_cond_reg(ctx, OP_SIZE_NATIVE, R_SCRATCH_1, 0, alu, slot_r));
1641 #if defined(ARCH_X86_64) || defined(ARCH_X86_X32) || defined(ARCH_ARM)
1644 swap = slot_1; slot_1 = slot_2; slot_2 = swap;
1645 alu = alu == COND_G ? COND_L : COND_B;
1649 g(gen_frame_load(ctx, OP_SIZE_NATIVE, garbage, slot_2, lo_word(OP_SIZE_NATIVE), true, R_SCRATCH_2));
1650 g(gen_frame_load(ctx, OP_SIZE_NATIVE, garbage, slot_1, hi_word(OP_SIZE_NATIVE), true, R_SCRATCH_1));
1651 g(gen_frame_load_cmp(ctx, OP_SIZE_NATIVE, false, garbage, true, slot_1, lo_word(OP_SIZE_NATIVE), true, R_SCRATCH_2));
1652 g(gen_frame_load_op(ctx, OP_SIZE_NATIVE, garbage, ALU_SBB, 1, slot_2, hi_word(OP_SIZE_NATIVE), true, R_SCRATCH_1));
1653 g(gen_frame_set_cond(ctx, OP_SIZE_NATIVE, false, alu, slot_r));
1657 swap = slot_1; slot_1 = slot_2; slot_2 = swap;
1658 alu = alu == COND_GE ? COND_LE : COND_BE;
1662 g(gen_frame_load(ctx, OP_SIZE_NATIVE, garbage, slot_1, lo_word(OP_SIZE_NATIVE), true, R_SCRATCH_2));
1663 g(gen_frame_load(ctx, OP_SIZE_NATIVE, garbage, slot_2, hi_word(OP_SIZE_NATIVE), true, R_SCRATCH_1));
1664 g(gen_frame_load_cmp(ctx, OP_SIZE_NATIVE, false, garbage, true, slot_2, lo_word(OP_SIZE_NATIVE), true, R_SCRATCH_2));
1665 g(gen_frame_load_op(ctx, OP_SIZE_NATIVE, garbage, ALU_SBB, 1, slot_1, hi_word(OP_SIZE_NATIVE), true, R_SCRATCH_1));
1666 g(gen_frame_set_cond(ctx, OP_SIZE_NATIVE, false, alu == COND_LE ? COND_GE : COND_AE, slot_r));
1669 case COND_L: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_less_,TYPE_INT_MAX)); goto do_upcall;
1670 case COND_LE: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_less_equal_,TYPE_INT_MAX)); goto do_upcall;
1671 case COND_G: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_greater_,TYPE_INT_MAX)); goto do_upcall;
1672 case COND_GE: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_greater_equal_,TYPE_INT_MAX)); goto do_upcall;
1673 case COND_B: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_uless_,TYPE_INT_MAX)); goto do_upcall;
1674 case COND_BE: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_uless_equal_,TYPE_INT_MAX)); goto do_upcall;
1675 case COND_A: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_ugreater_,TYPE_INT_MAX)); goto do_upcall;
1676 case COND_AE: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_ugreater_equal_,TYPE_INT_MAX)); goto do_upcall;
1677 do_upcall: g(gen_alu_upcall(ctx, upcall, op_size, slot_1, slot_2, slot_r, 0));
1681 internal(file_line, "gen_alu: unsupported condition %u", alu);
1685 #if defined(ARCH_X86)
1686 g(gen_frame_get(ctx, op_size, garbage, slot_1, R_SCRATCH_1, ®1));
1687 g(gen_frame_load_cmp_set_cond(ctx, op_size, garbage, slot_2, reg1, alu, slot_r));
1689 g(gen_frame_get(ctx, op_size, op_size == i_size_cmp(op_size) + (unsigned)zero ? garbage : alu == COND_L || alu == COND_LE || alu == COND_G || alu == COND_GE || ARCH_PREFERS_SX(op_size) ? sign_x : zero_x, slot_1, R_SCRATCH_1, ®1));
1690 g(gen_frame_load_cmp_set_cond(ctx, op_size, alu == COND_L || alu == COND_LE || alu == COND_G || alu == COND_GE || ARCH_PREFERS_SX(op_size) ? sign_x : zero_x, slot_2, reg1, alu, slot_r));
1696 static bool attr_w gen_alu1(struct codegen_context *ctx, unsigned mode, unsigned op_size, unsigned op, uint32_t label_ovf, frame_t slot_1, frame_t slot_r)
1699 unsigned reg1, target;
1701 case MODE_FIXED: switch (op) {
1702 case OPCODE_FIXED_OP_not: alu = ALU1_NOT; goto do_alu;
1703 case OPCODE_FIXED_OP_neg: alu = ALU1_NEG; goto do_alu;
1704 case OPCODE_FIXED_OP_bswap:
1705 case OPCODE_FIXED_OP_bswap_alt1: alu = ALU1_BSWAP; goto do_bswap;
1706 case OPCODE_FIXED_OP_brev:
1707 case OPCODE_FIXED_OP_brev_alt1: alu = ALU1_BREV; goto do_brev;
1708 case OPCODE_FIXED_OP_bsf:
1709 case OPCODE_FIXED_OP_bsf_alt1: alu = ALU1_BSF; goto do_bsf_bsr_popcnt;
1710 case OPCODE_FIXED_OP_bsr:
1711 case OPCODE_FIXED_OP_bsr_alt1: alu = ALU1_BSR; goto do_bsf_bsr_popcnt;
1712 case OPCODE_FIXED_OP_popcnt:
1713 case OPCODE_FIXED_OP_popcnt_alt1: alu = ALU1_POPCNT; goto do_bsf_bsr_popcnt;
1714 case OPCODE_FIXED_OP_to_int: goto do_fixed_conv;
1715 case OPCODE_FIXED_OP_from_int: goto do_fixed_conv;
1716 case OPCODE_FIXED_OP_uto_int: goto conv_uto_int;
1717 case OPCODE_FIXED_OP_ufrom_int: goto conv_ufrom_int;
1718 default: internal(file_line, "gen_alu1: unsupported fixed operation %u", op);
1720 case MODE_INT: switch (op) {
1721 case OPCODE_INT_OP_not: alu = ALU1_NOT; mode = MODE_FIXED; goto do_alu;
1722 case OPCODE_INT_OP_neg: alu = ALU1_NEG; goto do_alu;
1723 case OPCODE_INT_OP_bsf: alu = ALU1_BSF; goto do_bsf_bsr_popcnt;
1724 case OPCODE_INT_OP_bsr: alu = ALU1_BSR; goto do_bsf_bsr_popcnt;
1725 case OPCODE_INT_OP_popcnt:
1726 case OPCODE_INT_OP_popcnt_alt1: alu = ALU1_POPCNT; goto do_bsf_bsr_popcnt;
1727 case OPCODE_INT_OP_to_int: goto do_conv;
1728 case OPCODE_INT_OP_from_int: goto do_conv;
1729 default: internal(file_line, "gen_alu1: unsupported int operation %u", op);
1731 case MODE_BOOL: switch (op) {
1732 case OPCODE_BOOL_OP_not: goto do_bool_not;
1733 default: internal(file_line, "gen_alu1: unsupported bool operation %u", op);
1736 internal(file_line, "gen_alu1: unsupported mode %u", mode);
1742 bool arch_use_flags = ARCH_HAS_FLAGS;
1744 #if defined(ARCH_POWER)
1745 arch_use_flags = false;
1747 if (op_size > OP_SIZE_NATIVE) {
1748 #if !defined(ARCH_X86) && !defined(ARCH_ARM) && !defined(ARCH_POWER)
1749 if (alu == ALU1_NEG) {
1750 if (mode == MODE_FIXED)
1751 g(gen_alu_upcall(ctx, offsetof(struct cg_upcall_vector_s, cat(FIXED_unary_neg_,TYPE_INT_MAX)), op_size, slot_1, NO_FRAME_T, slot_r, 0));
1753 g(gen_alu_upcall(ctx, offsetof(struct cg_upcall_vector_s, cat(INT_unary_neg_,TYPE_INT_MAX)), op_size, slot_1, NO_FRAME_T, slot_r, label_ovf));
1757 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_1, 0, R_SCRATCH_1, R_SCRATCH_2));
1758 #if defined(ARCH_S390)
1759 if (alu == ALU1_NOT) {
1760 g(gen_load_constant(ctx, R_SCRATCH_3, -1));
1762 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_XOR, R_SCRATCH_1, R_SCRATCH_1, R_SCRATCH_3, 0));
1763 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_XOR, R_SCRATCH_2, R_SCRATCH_2, R_SCRATCH_3, 0));
1765 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, R_SCRATCH_1, R_SCRATCH_2));
1769 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, alu, R_SCRATCH_1, R_SCRATCH_1, alu == ALU1_NEG ? 2 : 0));
1770 if (alu == ALU1_NOT) {
1771 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_NOT, R_SCRATCH_2, R_SCRATCH_2, 0));
1773 #if defined(ARCH_X86)
1774 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_NOT, R_SCRATCH_2, R_SCRATCH_2, 0));
1776 g(gen_imm(ctx, -1, IMM_PURPOSE_SUB, OP_SIZE_NATIVE));
1777 gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_SBB, ALU_WRITES_FLAGS(OP_SIZE_NATIVE, ALU_SBB, false, is_imm(), ctx->const_imm));
1778 gen_one(R_SCRATCH_2);
1779 gen_one(R_SCRATCH_2);
1782 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_NGC, R_SCRATCH_2, R_SCRATCH_2, (mode == MODE_INT)));
1785 if (mode == MODE_INT) {
1786 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_O, 0);
1787 gen_four(label_ovf);
1789 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, R_SCRATCH_1, R_SCRATCH_2));
1792 if ((arch_use_flags || ARCH_SUPPORTS_TRAPS(op_size)) && slot_1 == slot_r && i_size_cmp(op_size) == op_size + zero) {
1794 unsigned undo_alu = alu;
1795 if (slot_is_register(ctx, slot_1)) {
1796 unsigned reg = ctx->registers[slot_1];
1797 if (mode == MODE_INT && ARCH_SUPPORTS_TRAPS(op_size)) {
1798 gen_insn(INSN_ALU1_TRAP, op_size, alu, ALU1_WRITES_FLAGS(alu));
1801 if (ARCH_TRAP_BEFORE || alu == undo_alu) {
1802 gen_four(label_ovf);
1805 ce = alloc_undo_label(ctx);
1808 gen_four(ce->undo_label);
1809 goto do_undo_opcode;
1812 g(gen_2address_alu1(ctx, i_size(op_size), alu, reg, reg, mode == MODE_INT));
1813 if (mode == MODE_INT) {
1814 if (alu != undo_alu) {
1815 ce = alloc_undo_label(ctx);
1818 gen_insn(INSN_JMP_COND, i_size_cmp(op_size), COND_O, 0);
1819 gen_four(ce->undo_label);
1821 ce->undo_opcode = INSN_ALU1 + ARCH_PARTIAL_ALU(op_size);
1822 ce->undo_op_size = i_size(op_size);
1823 ce->undo_aux = undo_alu;
1824 ce->undo_writes_flags = ALU1_WRITES_FLAGS(undo_alu);
1825 ce->undo_parameters[0] = reg;
1826 ce->undo_parameters[1] = reg;
1827 ce->undo_parameters_len = 2;
1829 gen_insn(INSN_JMP_COND, i_size_cmp(op_size), COND_O, 0);
1830 gen_four(label_ovf);
1835 #if defined(ARCH_X86)
1838 int64_t offset = (size_t)slot_1 * slot_size;
1839 g(gen_address(ctx, R_FRAME, offset, IMM_PURPOSE_LDR_OFFSET, i_size(op_size)));
1840 gen_insn(INSN_ALU1 + ARCH_PARTIAL_ALU(op_size), i_size(op_size), alu, ALU1_WRITES_FLAGS(alu) | (mode == MODE_INT));
1841 gen_address_offset();
1842 gen_address_offset();
1843 if (mode == MODE_INT) {
1844 if (alu != undo_alu) {
1845 ce = alloc_undo_label(ctx);
1848 ce->undo_opcode = INSN_ALU1 + ARCH_PARTIAL_ALU(op_size);
1849 ce->undo_op_size = i_size(op_size);
1850 ce->undo_aux = undo_alu;
1851 ce->undo_writes_flags = ALU1_WRITES_FLAGS(undo_alu);
1852 m = mark_params(ctx);
1853 gen_address_offset();
1854 gen_address_offset();
1855 copy_params(ctx, ce, m);
1856 gen_insn(INSN_JMP_COND, i_size_cmp(op_size), COND_O, 0);
1857 gen_four(ce->undo_label);
1859 gen_insn(INSN_JMP_COND, i_size_cmp(op_size), COND_O, 0);
1860 gen_four(label_ovf);
1867 target = gen_frame_target(ctx, slot_r, mode == MODE_INT ? slot_1 : NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
1868 if (mode == MODE_FIXED) {
1871 ex = ARCH_PREFERS_SX(op_size) ? sign_x : zero_x;
1872 if (ARCH_SUPPORTS_TRAPS(op_size))
1874 if (op_size == i_size(op_size) + (unsigned)zero)
1877 g(gen_frame_get(ctx, op_size, ex, slot_1, mode == MODE_INT ? R_SCRATCH_2 : target, ®1));
1878 #if defined(ARCH_S390)
1879 if (alu == ALU1_NOT) {
1880 g(gen_3address_alu_imm(ctx, i_size(op_size), ALU_XOR, target, reg1, -1, 0));
1882 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1886 #if defined(ARCH_X86)
1887 g(gen_2address_alu1(ctx, op_size, alu, target, reg1, mode == MODE_INT));
1889 if (mode == MODE_INT) {
1890 #if defined(ARCH_POWER)
1891 if (op_size == OP_SIZE_NATIVE) {
1892 g(gen_2address_alu1(ctx, i_size(op_size), alu, target, reg1, 0));
1893 if (alu == ALU1_NEG) {
1894 g(gen_3address_alu(ctx, i_size(op_size), ALU_AND, R_CG_SCRATCH, target, reg1, 1));
1896 gen_insn(INSN_JMP_COND, op_size, COND_L, 0);
1897 gen_four(label_ovf);
1899 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1904 if (!arch_use_flags && !ARCH_SUPPORTS_TRAPS(op_size) && ARCH_HAS_ANDN && op_size >= OP_SIZE_4) {
1905 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, alu, target, reg1, 0));
1907 if (alu == ALU1_NEG) {
1908 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_AND, R_SCRATCH_3, target, reg1, 0));
1911 if (op_size < OP_SIZE_NATIVE)
1912 g(gen_extend(ctx, op_size, sign_x, R_SCRATCH_3, R_SCRATCH_3));
1914 g(gen_jmp_on_zero(ctx, OP_SIZE_NATIVE, R_SCRATCH_3, COND_S, label_ovf));
1916 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1920 if (op_size <= OP_SIZE_2 || (!arch_use_flags && !ARCH_SUPPORTS_TRAPS(op_size))) {
1921 int64_t imm = (ARCH_PREFERS_SX(op_size) ? -0x80ULL : 0x80ULL) << (((1 << op_size) - 1) * 8);
1923 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, i_size_cmp(op_size), reg1, imm, COND_E, label_ovf));
1927 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
1931 if (mode == MODE_INT) {
1932 gen_insn(INSN_ALU1_TRAP, op_size, alu, ALU1_WRITES_FLAGS(alu));
1935 gen_four(label_ovf);
1936 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1940 g(gen_2address_alu1(ctx, i_size(op_size), alu, target, reg1, mode == MODE_INT));
1942 if (mode == MODE_INT) {
1943 gen_insn(INSN_JMP_COND, i_size_cmp(op_size), COND_O, 0);
1944 gen_four(label_ovf);
1946 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1954 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
1955 g(gen_frame_get(ctx, op_size, garbage, slot_1, target, ®1));
1957 g(gen_3address_alu_imm(ctx, i_size(op_size), ALU_XOR, target, reg1, 1, 0));
1959 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1967 bool attr_unused sx = false;
1968 #if defined(ARCH_X86) || defined(ARCH_ARM) || defined(ARCH_IA64) || defined(ARCH_LOONGARCH64) || defined(ARCH_MIPS) || defined(ARCH_RISCV64) || defined(ARCH_S390)
1969 #if defined(ARCH_ARM32)
1970 if (unlikely(!cpu_test_feature(CPU_FEATURE_armv6)))
1971 goto do_generic_bswap;
1973 #if defined(ARCH_MIPS)
1974 if (unlikely(!MIPS_HAS_ROT))
1975 goto do_generic_bswap;
1976 sx = op_size == OP_SIZE_4;
1978 #if defined(ARCH_RISCV64)
1979 if (unlikely(!cpu_test_feature(CPU_FEATURE_zbb)))
1980 goto do_generic_bswap;
1982 #if defined(ARCH_S390)
1983 if (op_size == OP_SIZE_2)
1984 goto do_generic_bswap;
1986 #if defined(ARCH_X86)
1987 if (op_size >= OP_SIZE_4 && !cpu_test_feature(CPU_FEATURE_bswap))
1988 goto do_generic_bswap;
1990 if (op_size > OP_SIZE_NATIVE) {
1991 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_1, 0, R_SCRATCH_1, R_SCRATCH_2));
1993 target = R_SCRATCH_1;
1995 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
1996 g(gen_frame_get(ctx, op_size, sx ? sign_x : garbage, slot_1, target, ®1));
1999 if (op_size == OP_SIZE_1) {
2000 #if defined(ARCH_IA64) || defined(ARCH_RISCV64)
2001 } else if (op_size == OP_SIZE_2 || op_size == OP_SIZE_4) {
2002 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_BSWAP, target, reg1, 0));
2004 g(gen_3address_rot_imm(ctx, OP_SIZE_NATIVE, ROT_SAR, target, target, op_size == OP_SIZE_2 ? 48 : 32, 0));
2006 } else if (op_size == OP_SIZE_2) {
2007 #if defined(ARCH_X86)
2008 g(gen_3address_rot_imm(ctx, OP_SIZE_2, ROT_ROR, target, reg1, 8, 0));
2010 g(gen_2address_alu1(ctx, OP_SIZE_4, ALU1_BSWAP16, target, reg1, 0));
2013 g(gen_2address_alu1(ctx, minimum(op_size, OP_SIZE_NATIVE), ALU1_BSWAP, target, reg1, 0));
2015 if (op_size > OP_SIZE_NATIVE) {
2016 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_BSWAP, R_SCRATCH_2, R_SCRATCH_2, 0));
2019 if (op_size > OP_SIZE_NATIVE)
2020 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, R_SCRATCH_2, R_SCRATCH_1));
2022 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2025 goto do_generic_bswap;
2027 return gen_alu_typed_upcall(ctx, offsetof(struct cg_upcall_vector_s, FIXED_unary_bswap_int8_t), op_size, slot_1, NO_FRAME_T, slot_r, 0);
2033 #if defined(ARCH_ARM) || defined(ARCH_LOONGARCH64) || (defined(ARCH_MIPS) && MIPS_R6)
2034 #if defined(ARCH_ARM32)
2035 if (unlikely(!cpu_test_feature(CPU_FEATURE_armv6t2)))
2036 goto do_generic_brev;
2038 if (op_size > OP_SIZE_NATIVE) {
2039 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_1, 0, R_SCRATCH_1, R_SCRATCH_2));
2041 target = R_SCRATCH_1;
2043 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
2044 g(gen_frame_get(ctx, op_size, garbage, slot_1, target, ®1));
2047 g(gen_2address_alu1(ctx, minimum(maximum(OP_SIZE_4, op_size), OP_SIZE_NATIVE), ALU1_BREV, target, reg1, 0));
2048 if (op_size <= OP_SIZE_2) {
2049 g(gen_3address_rot_imm(ctx, OP_SIZE_4, ROT_SHR, target, target, op_size == OP_SIZE_1 ? 24 : 16, 0));
2051 if (op_size > OP_SIZE_NATIVE) {
2052 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_BREV, R_SCRATCH_2, R_SCRATCH_2, 0));
2055 if (op_size > OP_SIZE_NATIVE)
2056 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, R_SCRATCH_2, R_SCRATCH_1));
2058 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2061 goto do_generic_brev;
2063 return gen_alu_typed_upcall(ctx, offsetof(struct cg_upcall_vector_s, FIXED_unary_brev_int8_t), op_size, slot_1, NO_FRAME_T, slot_r, 0);
2068 do_bsf_bsr_popcnt: {
2069 if (op_size > OP_SIZE_NATIVE) {
2070 #if defined(ARCH_X86)
2071 uint32_t label_finish = 0; /* avoid warning */
2072 if (alu == ALU1_POPCNT && unlikely(!cpu_test_feature(CPU_FEATURE_popcnt)))
2073 goto do_generic_bsf_bsr_popcnt;
2074 if (alu == ALU1_BSR || alu == ALU1_POPCNT) {
2075 if (mode == MODE_INT) {
2076 g(gen_address(ctx, R_FRAME, (size_t)slot_1 * slot_size + hi_word(OP_SIZE_NATIVE), IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
2077 g(gen_imm(ctx, 0, IMM_PURPOSE_STORE_VALUE, OP_SIZE_NATIVE));
2078 gen_insn(INSN_CMP, OP_SIZE_NATIVE, 0, 1);
2079 gen_address_offset();
2082 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_S, 0);
2083 gen_four(label_ovf);
2086 if (alu == ALU1_BSF) {
2087 label_finish = alloc_label(ctx);
2088 if (unlikely(!label_finish))
2091 g(gen_address(ctx, R_FRAME, (size_t)slot_1 * slot_size + lo_word(OP_SIZE_NATIVE), IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
2092 gen_insn(INSN_ALU1, OP_SIZE_NATIVE, ALU1_BSF, ALU1_WRITES_FLAGS(ALU1_BSF));
2093 gen_one(R_SCRATCH_1);
2094 gen_address_offset();
2096 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_NE, 0);
2097 gen_four(label_finish);
2099 g(gen_address(ctx, R_FRAME, (size_t)slot_1 * slot_size + hi_word(OP_SIZE_NATIVE), IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
2100 gen_insn(INSN_ALU1, OP_SIZE_NATIVE, ALU1_BSF, ALU1_WRITES_FLAGS(ALU1_BSF));
2101 gen_one(R_SCRATCH_1);
2102 gen_address_offset();
2104 g(gen_3address_alu_imm(ctx, OP_SIZE_4, ALU_ADD, R_SCRATCH_1, R_SCRATCH_1, 8U << OP_SIZE_NATIVE, 0));
2106 if (alu == ALU1_BSR) {
2107 label_finish = alloc_label(ctx);
2108 if (unlikely(!label_finish))
2111 g(gen_address(ctx, R_FRAME, (size_t)slot_1 * slot_size + hi_word(OP_SIZE_NATIVE), IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
2112 gen_insn(INSN_ALU1, OP_SIZE_NATIVE, ALU1_BSR, ALU1_WRITES_FLAGS(ALU1_BSR));
2113 gen_one(R_SCRATCH_1);
2114 gen_address_offset();
2116 g(gen_3address_alu_imm(ctx, OP_SIZE_4, ALU_ADD, R_SCRATCH_1, R_SCRATCH_1, 8U << OP_SIZE_NATIVE, 0));
2118 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_NE, 0);
2119 gen_four(label_finish);
2121 g(gen_address(ctx, R_FRAME, (size_t)slot_1 * slot_size + lo_word(OP_SIZE_NATIVE), IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
2122 gen_insn(INSN_ALU1, OP_SIZE_NATIVE, ALU1_BSR, ALU1_WRITES_FLAGS(ALU1_BSR));
2123 gen_one(R_SCRATCH_1);
2124 gen_address_offset();
2126 if (alu == ALU1_BSF || alu == ALU1_BSR) {
2127 if (mode == MODE_INT) {
2128 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_E, 0);
2129 gen_four(label_ovf);
2131 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_NE, 0);
2132 gen_four(label_finish);
2134 g(gen_load_constant(ctx, R_SCRATCH_1, -1));
2137 gen_label(label_finish);
2139 if (mode == MODE_INT)
2142 if (R_SCRATCH_1 != R_AX || R_SCRATCH_2 != R_DX)
2143 internal(file_line, "gen_alu1: bad scratch registers");
2144 gen_insn(INSN_CWD, OP_SIZE_NATIVE, 0, 0);
2148 g(gen_address(ctx, R_FRAME, (size_t)slot_r * slot_size + lo_word(OP_SIZE_NATIVE), IMM_PURPOSE_STR_OFFSET, OP_SIZE_NATIVE));
2149 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
2150 gen_address_offset();
2151 gen_one(R_SCRATCH_1);
2153 g(gen_address(ctx, R_FRAME, (size_t)slot_r * slot_size + hi_word(OP_SIZE_NATIVE), IMM_PURPOSE_STR_OFFSET, OP_SIZE_NATIVE));
2154 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
2155 gen_address_offset();
2156 gen_one(R_SCRATCH_2);
2160 if (alu == ALU1_POPCNT) {
2161 g(gen_address(ctx, R_FRAME, (size_t)slot_1 * slot_size + lo_word(OP_SIZE_NATIVE), IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
2162 gen_insn(INSN_ALU1, OP_SIZE_NATIVE, ALU1_POPCNT, ALU1_WRITES_FLAGS(ALU1_POPCNT));
2163 gen_one(R_SCRATCH_1);
2164 gen_address_offset();
2166 g(gen_address(ctx, R_FRAME, (size_t)slot_1 * slot_size + hi_word(OP_SIZE_NATIVE), IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
2167 gen_insn(INSN_ALU1, OP_SIZE_NATIVE, ALU1_POPCNT, ALU1_WRITES_FLAGS(ALU1_POPCNT));
2168 gen_one(R_SCRATCH_2);
2169 gen_address_offset();
2171 g(gen_3address_alu(ctx, OP_SIZE_4, ALU_ADD, R_SCRATCH_1, R_SCRATCH_1, R_SCRATCH_2, 1));
2173 g(gen_address(ctx, R_FRAME, (size_t)slot_r * slot_size + lo_word(OP_SIZE_NATIVE), IMM_PURPOSE_STR_OFFSET, OP_SIZE_NATIVE));
2174 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
2175 gen_address_offset();
2176 gen_one(R_SCRATCH_1);
2178 g(gen_address(ctx, R_FRAME, (size_t)slot_r * slot_size + hi_word(OP_SIZE_NATIVE), IMM_PURPOSE_STR_OFFSET, OP_SIZE_NATIVE));
2179 g(gen_imm(ctx, 0, IMM_PURPOSE_STORE_VALUE, OP_SIZE_NATIVE));
2180 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
2181 gen_address_offset();
2187 goto do_generic_bsf_bsr_popcnt;
2189 #if defined(ARCH_X86)
2190 if (alu == ALU1_POPCNT && unlikely(!cpu_test_feature(CPU_FEATURE_popcnt)))
2191 goto do_generic_bsf_bsr_popcnt;
2192 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
2193 if (op_size == OP_SIZE_1 || ((alu == ALU1_BSR || alu == ALU1_POPCNT) && mode == MODE_INT)) {
2194 g(gen_frame_get(ctx, op_size, zero_x, slot_1, target, ®1));
2195 if ((alu == ALU1_BSR || alu == ALU1_POPCNT) && mode == MODE_INT) {
2196 g(gen_cmp_test_jmp(ctx, INSN_TEST, op_size, reg1, reg1, alu == ALU1_BSR ? COND_LE : COND_S, label_ovf));
2198 g(gen_2address_alu1(ctx, maximum(op_size, OP_SIZE_2), alu, target, reg1, 1));
2199 if ((alu == ALU1_BSR || alu == ALU1_POPCNT) && mode == MODE_INT)
2200 goto x86_bsf_bsr_popcnt_finish;
2202 g(gen_frame_load_op1(ctx, op_size, alu, 1, slot_1, target));
2204 if (alu == ALU1_POPCNT)
2205 goto x86_bsf_bsr_popcnt_finish;
2206 if (mode == MODE_FIXED) {
2207 uint32_t cmov_label;
2208 gen_insn(INSN_MOV, maximum(op_size, OP_SIZE_4), 0, 0);
2209 gen_one(R_SCRATCH_2);
2212 g(gen_cmov(ctx, maximum(op_size, OP_SIZE_4), COND_E, target, &cmov_label));
2213 gen_one(R_SCRATCH_2);
2215 gen_label(cmov_label);
2218 gen_insn(INSN_JMP_COND, maximum(op_size, OP_SIZE_2), COND_E, 0);
2219 gen_four(label_ovf);
2221 x86_bsf_bsr_popcnt_finish:
2222 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2225 #if defined(ARCH_ARM)
2226 #if defined(ARCH_ARM32)
2227 if (alu == ALU1_BSR && unlikely(!cpu_test_feature(CPU_FEATURE_armv6)))
2228 goto do_generic_bsf_bsr_popcnt;
2229 if (alu == ALU1_BSF && unlikely(!cpu_test_feature(CPU_FEATURE_armv6t2)))
2230 goto do_generic_bsf_bsr_popcnt;
2232 if (alu == ALU1_POPCNT && unlikely(!cpu_test_feature(CPU_FEATURE_neon)))
2233 goto do_generic_bsf_bsr_popcnt;
2234 g(gen_frame_get(ctx, op_size, mode == MODE_INT ? sign_x : zero_x, slot_1, R_SCRATCH_1, ®1));
2235 if (mode == MODE_INT) {
2236 g(gen_cmp_test_jmp(ctx, INSN_TEST, i_size(op_size), reg1, reg1, alu == ALU1_BSR ? COND_LE : alu == ALU1_BSF ? COND_E : COND_S, label_ovf));
2239 if (alu == ALU1_POPCNT) {
2240 g(gen_mov(ctx, OP_SIZE_NATIVE, FR_SCRATCH_1, reg1));
2241 gen_insn(INSN_FP_ALU1, OP_SIZE_NATIVE, FP_ALU1_VCNT8, 0);
2242 gen_one(FR_SCRATCH_1);
2243 gen_one(FR_SCRATCH_1);
2244 #if defined(ARCH_ARM32)
2245 if (op_size > OP_SIZE_1) {
2246 gen_insn(INSN_FP_ALU1, OP_SIZE_1, FP_ALU1_VPADDL, 0);
2247 gen_one(FR_SCRATCH_1);
2248 gen_one(FR_SCRATCH_1);
2250 if (op_size > OP_SIZE_2) {
2251 gen_insn(INSN_FP_ALU1, OP_SIZE_2, FP_ALU1_VPADDL, 0);
2252 gen_one(FR_SCRATCH_1);
2253 gen_one(FR_SCRATCH_1);
2256 if (op_size > OP_SIZE_1) {
2257 gen_insn(INSN_FP_ALU1, OP_SIZE_1, FP_ALU1_ADDV, 0);
2258 gen_one(FR_SCRATCH_1);
2259 gen_one(FR_SCRATCH_1);
2262 g(gen_frame_store(ctx, op_size, slot_r, 0, FR_SCRATCH_1));
2263 if (slot_is_register(ctx, slot_r))
2264 g(unspill(ctx, slot_r));
2268 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
2269 if (mode == MODE_FIXED && alu == ALU1_BSF) {
2270 gen_insn(INSN_TEST, i_size(op_size), 0, 1);
2276 if (alu == ALU1_BSF) {
2277 g(gen_2address_alu1(ctx, i_size(op_size), ALU1_BREV, target, reg1, 0));
2281 g(gen_2address_alu1(ctx, i_size(op_size), ALU1_LZCNT, target, reg1, 0));
2283 if (alu == ALU1_BSR) {
2284 g(gen_load_constant(ctx, R_SCRATCH_2, op_size == OP_SIZE_8 ? 63 : 31));
2285 g(gen_3address_alu(ctx, i_size(op_size), ALU_SUB, target, R_SCRATCH_2, target, 0));
2288 if (mode == MODE_FIXED && alu == ALU1_BSF) {
2289 #if defined(ARCH_ARM32)
2290 g(gen_imm(ctx, -1, IMM_PURPOSE_CMOV, OP_SIZE_NATIVE));
2291 gen_insn(INSN_CMOV, OP_SIZE_NATIVE, COND_E, 0);
2296 gen_insn(INSN_CSEL_INV, i_size(op_size), COND_NE, 0);
2304 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2307 #if defined(ARCH_ALPHA)
2308 if (likely(cpu_test_feature(CPU_FEATURE_cix))) {
2309 g(gen_frame_get(ctx, op_size, mode == MODE_INT ? sign_x : zero_x, slot_1, R_SCRATCH_1, ®1));
2310 target = gen_frame_target(ctx, slot_r, slot_1, NO_FRAME_T, R_SCRATCH_2);
2311 if (mode == MODE_INT) {
2312 g(gen_cmp_test_jmp(ctx, INSN_TEST, OP_SIZE_NATIVE, reg1, reg1, alu == ALU1_BSR ? COND_LE : alu == ALU1_BSF ? COND_E : COND_S, label_ovf));
2314 if (alu == ALU1_POPCNT) {
2315 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_POPCNT, target, reg1, 0));
2317 if (alu == ALU1_BSF) {
2318 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_BSF, target, reg1, 0));
2320 if (mode == MODE_FIXED) {
2321 g(gen_imm(ctx, -1, IMM_PURPOSE_MOVR, OP_SIZE_INT));
2322 gen_insn(INSN_MOVR, OP_SIZE_NATIVE, COND_E, 0);
2329 if (alu == ALU1_BSR) {
2330 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_LZCNT, target, reg1, 0));
2332 g(gen_load_constant(ctx, R_SCRATCH_3, OP_SIZE_NATIVE == OP_SIZE_8 ? 63 : 31));
2334 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_SUB, target, R_SCRATCH_3, target, 0));
2336 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2340 #if defined(ARCH_MIPS)
2341 if (MIPS_HAS_CLZ && alu != ALU1_POPCNT) {
2342 g(gen_frame_get(ctx, op_size, mode == MODE_INT ? sign_x : zero_x, slot_1, R_SCRATCH_1, ®1));
2343 target = gen_frame_target(ctx, slot_r, slot_1, NO_FRAME_T, R_SCRATCH_2);
2344 if (mode == MODE_INT) {
2345 g(gen_cmp_test_jmp(ctx, INSN_TEST, OP_SIZE_NATIVE, reg1, reg1, alu == ALU1_BSR ? COND_LE : alu == ALU1_BSF ? COND_E : COND_S, label_ovf));
2347 if (alu == ALU1_BSF) {
2348 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_NEG, target, reg1, 0));
2350 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_AND, R_SCRATCH_1, reg1, target, 0));
2353 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_LZCNT, target, reg1, 0));
2355 g(gen_load_constant(ctx, R_SCRATCH_3, OP_SIZE_NATIVE == OP_SIZE_8 ? 63 : 31));
2357 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_SUB, target, R_SCRATCH_3, target, 0));
2359 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2363 #if defined(ARCH_POWER)
2364 if (alu == ALU1_BSF && (unlikely(!cpu_test_feature(CPU_FEATURE_v203)) || unlikely(!cpu_test_feature(CPU_FEATURE_v30))))
2365 goto do_generic_bsf_bsr_popcnt;
2366 if (alu == ALU1_POPCNT && unlikely(!cpu_test_feature(CPU_FEATURE_v206)))
2367 goto do_generic_bsf_bsr_popcnt;
2368 g(gen_frame_get(ctx, op_size, mode == MODE_INT ? sign_x : zero_x, slot_1, R_SCRATCH_1, ®1));
2369 target = gen_frame_target(ctx, slot_r, slot_1, NO_FRAME_T, R_SCRATCH_2);
2370 if (mode == MODE_INT) {
2371 g(gen_cmp_test_jmp(ctx, INSN_TEST, i_size(op_size), reg1, reg1, alu == ALU1_BSR ? COND_LE : alu == ALU1_BSF ? COND_E : COND_S, label_ovf));
2373 if (alu == ALU1_POPCNT) {
2374 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_POPCNT, target, reg1, 0));
2376 if (alu == ALU1_BSF) {
2377 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_BSF, target, reg1, 0));
2379 if (mode == MODE_FIXED) {
2380 g(gen_3address_alu(ctx, i_size(op_size), ALU_AND, R_SCRATCH_3, reg1, reg1, 1));
2382 g(gen_imm(ctx, -1, IMM_PURPOSE_CMOV, OP_SIZE_NATIVE));
2383 gen_insn(INSN_CMOV, OP_SIZE_NATIVE, COND_E, 0);
2389 if (alu == ALU1_BSR) {
2390 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_LZCNT, target, reg1, 0));
2392 g(gen_load_constant(ctx, R_SCRATCH_3, OP_SIZE_NATIVE == OP_SIZE_8 ? 63 : 31));
2394 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_SUB, target, R_SCRATCH_3, target, 0));
2396 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2399 #if defined(ARCH_LOONGARCH64) || defined(ARCH_RISCV64)
2400 #if defined(ARCH_LOONGARCH64)
2401 if (alu == ALU1_POPCNT)
2402 goto do_generic_bsf_bsr_popcnt;
2404 #if defined(ARCH_RISCV64)
2405 if (unlikely(!cpu_test_feature(CPU_FEATURE_zbb)))
2406 goto do_generic_bsf_bsr_popcnt;
2408 g(gen_frame_get(ctx, op_size, mode == MODE_INT ? sign_x : zero_x, slot_1, R_SCRATCH_1, ®1));
2409 target = gen_frame_target(ctx, slot_r, slot_1, NO_FRAME_T, R_SCRATCH_2);
2410 if (mode == MODE_INT) {
2411 g(gen_cmp_test_jmp(ctx, INSN_TEST, OP_SIZE_NATIVE, reg1, reg1, alu == ALU1_BSR ? COND_LE : alu == ALU1_BSF ? COND_E : COND_S, label_ovf));
2413 if (alu == ALU1_POPCNT) {
2414 g(gen_2address_alu1(ctx, maximum(OP_SIZE_4, op_size), ALU1_POPCNT, target, reg1, 0));
2416 if (alu == ALU1_BSF) {
2417 g(gen_2address_alu1(ctx, maximum(OP_SIZE_4, op_size), ALU1_BSF, target, reg1, 0));
2419 if (mode == MODE_FIXED) {
2420 g(gen_imm(ctx, 1, IMM_PURPOSE_CMP, OP_SIZE_NATIVE));
2421 gen_insn(INSN_CMP_DEST_REG, OP_SIZE_NATIVE, COND_B, 0);
2422 gen_one(R_SCRATCH_3);
2426 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_NEG, R_SCRATCH_3, R_SCRATCH_3, 0));
2428 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_OR, target, target, R_SCRATCH_3, 0));
2431 if (alu == ALU1_BSR) {
2432 g(gen_2address_alu1(ctx, maximum(OP_SIZE_4, op_size), ALU1_LZCNT, target, reg1, 0));
2434 g(gen_load_constant(ctx, R_SCRATCH_3, op_size <= OP_SIZE_4 ? 31 : 63));
2436 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_SUB, target, R_SCRATCH_3, target, 0));
2438 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2441 #if defined(ARCH_IA64) || defined(ARCH_S390) || defined(ARCH_SPARC)
2442 if (alu == ALU1_BSF && !ARCH_HAS_ANDN)
2443 goto do_generic_bsf_bsr_popcnt;
2444 #if defined(ARCH_S390)
2445 if (!cpu_test_feature(CPU_FEATURE_misc_45) || !cpu_test_feature(CPU_FEATURE_misc_insn_ext_3))
2446 goto do_generic_bsf_bsr_popcnt;
2448 #if defined(ARCH_SPARC)
2450 goto do_generic_bsf_bsr_popcnt;
2452 g(gen_frame_get(ctx, op_size, mode == MODE_INT ? sign_x : zero_x, slot_1, R_SCRATCH_1, ®1));
2453 target = gen_frame_target(ctx, slot_r, slot_1, NO_FRAME_T, R_SCRATCH_2);
2454 if (mode == MODE_INT) {
2455 g(gen_cmp_test_jmp(ctx, INSN_TEST, maximum(op_size, OP_SIZE_4), reg1, reg1, alu == ALU1_BSR ? COND_LE : alu == ALU1_BSF ? COND_E : COND_S, label_ovf));
2457 if (ARCH_PREFERS_SX(op_size) && alu == ALU1_POPCNT && op_size < OP_SIZE_NATIVE) {
2458 g(gen_extend(ctx, op_size, zero_x, R_SCRATCH_1, reg1));
2462 if (alu == ALU1_POPCNT) {
2463 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_POPCNT, R_SCRATCH_1, reg1, 0));
2464 g(gen_frame_store(ctx, op_size, slot_r, 0, R_SCRATCH_1));
2467 if (alu == ALU1_BSF) {
2468 g(gen_3address_alu_imm(ctx, OP_SIZE_NATIVE, ALU_SUB, target, reg1, 1, 0));
2470 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_ANDN, target, target, reg1, 0));
2472 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_POPCNT, target, target, 0));
2474 if (mode == MODE_FIXED) {
2475 unsigned attr_unused test_reg = R_SCRATCH_1;
2476 #if defined(ARCH_S390)
2477 g(gen_imm(ctx, 0, COND_IS_LOGICAL(COND_E) ? IMM_PURPOSE_CMP_LOGICAL : IMM_PURPOSE_CMP, OP_SIZE_NATIVE));
2478 gen_insn(INSN_CMP, OP_SIZE_NATIVE, 0, 1 + COND_IS_LOGICAL(COND_E));
2482 g(gen_imm(ctx, -1, IMM_PURPOSE_CMOV, OP_SIZE_NATIVE));
2483 gen_insn(INSN_CMOV, OP_SIZE_NATIVE, COND_E, 0);
2488 #if defined(ARCH_IA64)
2489 g(gen_cmp_dest_reg(ctx, OP_SIZE_NATIVE, reg1, (unsigned)-1, R_CMP_RESULT, 0, COND_NE));
2490 test_reg = R_CMP_RESULT;
2492 g(gen_imm(ctx, -1, IMM_PURPOSE_MOVR, OP_SIZE_NATIVE));
2493 gen_insn(INSN_MOVR, OP_SIZE_NATIVE, COND_E, 0);
2501 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2505 do_generic_bsf_bsr_popcnt:
2506 if (alu == ALU1_BSF) {
2507 if (mode == MODE_FIXED)
2508 return gen_alu_typed_upcall(ctx, offsetof(struct cg_upcall_vector_s, FIXED_unary_bsf_int8_t), op_size, slot_1, NO_FRAME_T, slot_r, 0);
2510 return gen_alu_typed_upcall(ctx, offsetof(struct cg_upcall_vector_s, INT_unary_bsf_int8_t), op_size, slot_1, NO_FRAME_T, slot_r, label_ovf);
2512 if (alu == ALU1_BSR) {
2513 if (mode == MODE_FIXED)
2514 return gen_alu_typed_upcall(ctx, offsetof(struct cg_upcall_vector_s, FIXED_unary_bsr_int8_t), op_size, slot_1, NO_FRAME_T, slot_r, 0);
2516 return gen_alu_typed_upcall(ctx, offsetof(struct cg_upcall_vector_s, INT_unary_bsr_int8_t), op_size, slot_1, NO_FRAME_T, slot_r, label_ovf);
2518 if (alu == ALU1_POPCNT) {
2519 if (mode == MODE_FIXED)
2520 return gen_alu_typed_upcall(ctx, offsetof(struct cg_upcall_vector_s, FIXED_unary_popcnt_int8_t), op_size, slot_1, NO_FRAME_T, slot_r, 0);
2522 return gen_alu_typed_upcall(ctx, offsetof(struct cg_upcall_vector_s, INT_unary_popcnt_int8_t), op_size, slot_1, NO_FRAME_T, slot_r, label_ovf);
2530 unsigned src_op_size, dest_op_size;
2531 const struct type *src_type, *dest_type;
2532 src_type = get_type_of_local(ctx, slot_1);
2533 dest_type = get_type_of_local(ctx, slot_r);
2535 if (TYPE_TAG_IS_FIXED(src_type->tag)) {
2536 src_op_size = TYPE_TAG_IDX_FIXED(src_type->tag) >> 1;
2538 src_op_size = TYPE_TAG_IDX_INT(src_type->tag);
2541 if (TYPE_TAG_IS_FIXED(dest_type->tag)) {
2542 dest_op_size = TYPE_TAG_IDX_FIXED(dest_type->tag) >> 1;
2544 dest_op_size = TYPE_TAG_IDX_INT(dest_type->tag);
2547 if (src_op_size <= OP_SIZE_NATIVE) {
2548 g(gen_frame_get(ctx, src_op_size, sign_x, slot_1, R_SCRATCH_1, ®1));
2550 #if defined(ARCH_X86)
2551 if (dest_op_size < src_op_size)
2552 g(gen_frame_load(ctx, OP_SIZE_NATIVE, garbage, slot_1, 0, false, R_SCRATCH_1));
2555 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_1, 0, R_SCRATCH_1, R_SCRATCH_3));
2559 if (dest_op_size >= src_op_size) {
2560 if (dest_op_size <= OP_SIZE_NATIVE) {
2561 g(gen_frame_store(ctx, dest_op_size, slot_r, 0, reg1));
2563 if (src_op_size <= OP_SIZE_NATIVE) {
2564 #if defined(ARCH_X86)
2565 if (R_SCRATCH_1 != R_AX || R_SCRATCH_2 != R_DX)
2566 internal(file_line, "gen_alu1: bad scratch registers");
2567 if (reg1 == R_SCRATCH_1) {
2568 gen_insn(INSN_CWD, OP_SIZE_NATIVE, 0, 0);
2573 g(gen_3address_rot_imm(ctx, OP_SIZE_NATIVE, ROT_SAR, R_SCRATCH_2, reg1, (1U << (OP_SIZE_NATIVE + 3)) - 1, false));
2574 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, reg1, R_SCRATCH_2));
2576 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, reg1, R_SCRATCH_3));
2581 if (src_op_size > OP_SIZE_NATIVE) {
2582 #if defined(ARCH_ARM)
2583 gen_insn(INSN_CMP, OP_SIZE_NATIVE, 0, 1);
2584 gen_one(R_SCRATCH_3);
2585 gen_one(ARG_SHIFTED_REGISTER);
2586 gen_one(ARG_SHIFT_ASR | ((1U << (OP_SIZE_NATIVE + 3)) - 1));
2587 gen_one(R_SCRATCH_1);
2589 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_NE, 0);
2590 gen_four(label_ovf);
2591 #elif defined(ARCH_X86)
2592 if (R_SCRATCH_1 != R_AX || R_SCRATCH_2 != R_DX)
2593 internal(file_line, "gen_alu1: bad scratch registers");
2594 gen_insn(INSN_CWD, OP_SIZE_NATIVE, 0, 0);
2598 g(gen_address(ctx, R_FRAME, (size_t)slot_1 * slot_size + hi_word(OP_SIZE_NATIVE), IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
2599 gen_insn(INSN_CMP, OP_SIZE_NATIVE, 0, 1);
2600 gen_one(R_SCRATCH_2);
2601 gen_address_offset();
2603 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_NE, 0);
2604 gen_four(label_ovf);
2606 g(gen_3address_rot_imm(ctx, OP_SIZE_NATIVE, ROT_SAR, R_SCRATCH_2, R_SCRATCH_1, (1U << (OP_SIZE_NATIVE + 3)) - 1, 0));
2608 g(gen_cmp_test_jmp(ctx, INSN_CMP, OP_SIZE_NATIVE, R_SCRATCH_3, R_SCRATCH_2, COND_NE, label_ovf));
2611 src_op_size = OP_SIZE_NATIVE;
2613 if (src_op_size > dest_op_size) {
2614 g(gen_cmp_extended(ctx, OP_SIZE_NATIVE, dest_op_size, reg1, R_SCRATCH_2, label_ovf));
2616 g(gen_frame_store(ctx, dest_op_size, slot_r, 0, reg1));
2622 return gen_alu_typed_upcall(ctx, offsetof(struct cg_upcall_vector_s, FIXED_uto_int_int8_t), op_size, slot_1, NO_FRAME_T, slot_r, label_ovf);
2626 return gen_alu_typed_upcall(ctx, offsetof(struct cg_upcall_vector_s, FIXED_ufrom_int_int8_t), op_size, slot_1, NO_FRAME_T, slot_r, label_ovf);
2630 static bool attr_w gen_constant(struct codegen_context *ctx, bool real, unsigned op_size, bool shrt, frame_t slot_r)
2634 c = (int16_t)get_unaligned_16(ctx->current_position);
2635 } else switch (op_size) {
2636 #define fx(n, type, utype, sz, bits) \
2638 c = (type)cat(get_unaligned_,bits)(ctx->current_position);\
2643 internal(file_line, "gen_constant: invalid type %u", op_size);
2645 if (op_size > OP_SIZE_NATIVE) {
2646 unsigned shift = (8U << OP_SIZE_NATIVE) - 1;
2647 g(gen_frame_store_imm_raw(ctx, OP_SIZE_NATIVE, slot_r, lo_word(OP_SIZE_NATIVE), c & ((2ULL << shift) - 1)));
2648 g(gen_frame_store_imm_raw(ctx, OP_SIZE_NATIVE, slot_r, hi_word(OP_SIZE_NATIVE), c >> 1 >> shift));
2649 if (real && slot_is_register(ctx, slot_r))
2650 g(unspill(ctx, slot_r));
2652 } else if (real && slot_is_register(ctx, slot_r)) {
2653 if (ARCH_HAS_FP_GP_MOV) {
2654 g(gen_load_constant(ctx, R_SCRATCH_1, c));
2655 g(gen_mov(ctx, op_size, ctx->registers[slot_r], R_SCRATCH_1));
2657 g(gen_frame_store_imm_raw(ctx, op_size, slot_r, 0, c));
2658 g(unspill(ctx, slot_r));
2661 g(gen_frame_store_imm(ctx, op_size, slot_r, 0, c));
2666 static bool attr_w gen_real_constant(struct codegen_context *ctx, const struct type *t, frame_t slot_r)
2669 if (is_power_of_2(t->size) && t->size <= sizeof(uintbig_t))
2670 return gen_constant(ctx, true, log_2(t->size), false, slot_r);
2672 g(load_function_offset(ctx, R_SCRATCH_3, offsetof(struct data, u_.function.code)));
2674 offset = (ctx->current_position - da(ctx->fn,function)->code) * sizeof(code_t);
2676 g(gen_memcpy_raw(ctx, R_FRAME, (size_t)slot_r * slot_size, R_SCRATCH_3, offset, t->size, minimum(t->align, sizeof(code_t))));
2677 if (slot_is_register(ctx, slot_r))
2678 g(unspill(ctx, slot_r));
2683 static bool attr_w gen_copy(struct codegen_context *ctx, unsigned op_size, frame_t slot_1, frame_t slot_r)
2686 if (unlikely(op_size > OP_SIZE_NATIVE)) {
2687 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_1, 0, R_SCRATCH_1, R_SCRATCH_2));
2688 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, R_SCRATCH_1, R_SCRATCH_2));
2691 unsigned target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
2692 g(gen_frame_get(ctx, op_size, garbage, slot_1, target, ®1));
2693 g(gen_frame_store(ctx, op_size, slot_r, 0, reg1));
2698 static bool attr_w gen_fp_alu(struct codegen_context *ctx, unsigned real_type, unsigned op, uint32_t label_ovf, frame_t slot_1, frame_t slot_2, frame_t slot_r)
2700 unsigned attr_unused fp_alu;
2702 unsigned attr_unused op_size = real_type_to_op_size(real_type);
2703 unsigned reg1, reg2, target;
2705 case OPCODE_REAL_OP_add:
2706 case OPCODE_REAL_OP_add_alt1:
2707 case OPCODE_REAL_OP_add_alt2: fp_alu = FP_ALU_ADD; upc = offsetof(struct cg_upcall_vector_s, REAL_binary_add_real16_t); label_ovf = 0; goto do_alu;
2708 case OPCODE_REAL_OP_subtract:
2709 case OPCODE_REAL_OP_subtract_alt1:
2710 case OPCODE_REAL_OP_subtract_alt2: fp_alu = FP_ALU_SUB; upc = offsetof(struct cg_upcall_vector_s, REAL_binary_subtract_real16_t); label_ovf = 0; goto do_alu;
2711 case OPCODE_REAL_OP_multiply:
2712 case OPCODE_REAL_OP_multiply_alt1:
2713 case OPCODE_REAL_OP_multiply_alt2: fp_alu = FP_ALU_MUL; upc = offsetof(struct cg_upcall_vector_s, REAL_binary_multiply_real16_t); label_ovf = 0; goto do_alu;
2714 case OPCODE_REAL_OP_divide:
2715 case OPCODE_REAL_OP_divide_alt1:
2716 case OPCODE_REAL_OP_divide_alt2: fp_alu = FP_ALU_DIV; upc = offsetof(struct cg_upcall_vector_s, REAL_binary_divide_real16_t); label_ovf = 0; goto do_alu;
2717 case OPCODE_REAL_OP_modulo:
2718 case OPCODE_REAL_OP_power:
2719 case OPCODE_REAL_OP_ldexp:
2720 case OPCODE_REAL_OP_atan2: upc = offsetof(struct cg_upcall_vector_s, REAL_binary_modulo_real16_t) + (op - OPCODE_REAL_OP_modulo) * TYPE_REAL_N * sizeof(void (*)(void)); goto do_upcall;
2721 case OPCODE_REAL_OP_equal:
2722 case OPCODE_REAL_OP_equal_alt1:
2723 case OPCODE_REAL_OP_equal_alt2: fp_alu = FP_COND_E; upc = offsetof(struct cg_upcall_vector_s, REAL_binary_equal_real16_t); goto do_cmp;
2724 case OPCODE_REAL_OP_not_equal:
2725 case OPCODE_REAL_OP_not_equal_alt1:
2726 case OPCODE_REAL_OP_not_equal_alt2: fp_alu = FP_COND_NE; upc = offsetof(struct cg_upcall_vector_s, REAL_binary_not_equal_real16_t); goto do_cmp;
2727 case OPCODE_REAL_OP_less:
2728 case OPCODE_REAL_OP_less_alt1:
2729 case OPCODE_REAL_OP_less_alt2: fp_alu = FP_COND_B; upc = offsetof(struct cg_upcall_vector_s, REAL_binary_less_real16_t); goto do_cmp;
2730 case OPCODE_REAL_OP_less_equal:
2731 case OPCODE_REAL_OP_less_equal_alt1:
2732 case OPCODE_REAL_OP_less_equal_alt2: fp_alu = FP_COND_BE; upc = offsetof(struct cg_upcall_vector_s, REAL_binary_less_equal_real16_t); goto do_cmp;
2733 case OPCODE_REAL_OP_greater:
2734 case OPCODE_REAL_OP_greater_alt1:
2735 case OPCODE_REAL_OP_greater_alt2: fp_alu = FP_COND_A; upc = offsetof(struct cg_upcall_vector_s, REAL_binary_greater_real16_t); goto do_cmp;
2736 case OPCODE_REAL_OP_greater_equal:
2737 case OPCODE_REAL_OP_greater_equal_alt1:
2738 case OPCODE_REAL_OP_greater_equal_alt2: fp_alu = FP_COND_AE; upc = offsetof(struct cg_upcall_vector_s, REAL_binary_greater_equal_real16_t); goto do_cmp;
2739 default: internal(file_line, "gen_fp_alu: unsupported operation %u", op);
2743 if ((SUPPORTED_FP >> real_type) & 1) {
2744 #if defined(ARCH_IA64)
2745 if (unlikely(fp_alu == FP_ALU_DIV))
2748 #if defined(ARCH_X86)
2750 #elif defined(ARCH_S390)
2751 if ((op_size <= OP_SIZE_8 && (size_t)slot_2 * slot_size < 4096) || slot_is_register(ctx, slot_2))
2753 if (slot_is_register(ctx, slot_2))
2756 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, slot_2, FR_SCRATCH_1);
2757 g(gen_frame_get(ctx, op_size, garbage, slot_1, FR_SCRATCH_1, ®1));
2758 if (slot_is_register(ctx, slot_2)) {
2759 g(gen_3address_fp_alu(ctx, op_size, fp_alu, target, reg1, ctx->registers[slot_2]));
2761 if (target != reg1 && !ARCH_IS_3ADDRESS_FP) {
2762 g(gen_mov(ctx, op_size, target, reg1));
2765 g(gen_address(ctx, R_FRAME, (size_t)slot_2 * slot_size, IMM_PURPOSE_VLDR_VSTR_OFFSET, op_size));
2766 gen_insn(INSN_FP_ALU, op_size, fp_alu, 0);
2769 gen_address_offset();
2771 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2774 #if defined(ARCH_ALPHA)
2775 g(gen_frame_get(ctx, op_size, zero_x, slot_1, FR_SCRATCH_1, ®1));
2776 g(gen_frame_get(ctx, op_size, zero_x, slot_2, FR_SCRATCH_2, ®2));
2777 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, FR_SCRATCH_3);
2778 g(gen_3address_fp_alu(ctx, op_size, fp_alu, target, reg1, reg2));
2779 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2781 g(gen_frame_get(ctx, op_size, zero_x, slot_1, FR_SCRATCH_1, ®1));
2782 g(gen_frame_get(ctx, op_size, zero_x, slot_2, FR_SCRATCH_2, ®2));
2783 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, FR_SCRATCH_1);
2784 g(gen_3address_fp_alu(ctx, op_size, fp_alu, target, reg1, reg2));
2785 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2789 #ifdef SUPPORTED_FP_X87
2790 if ((SUPPORTED_FP_X87 >> real_type) & 1) {
2791 if (real_type != 3) {
2792 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_2));
2793 g(gen_frame_load_x87(ctx, INSN_X87_ALU, op_size, fp_alu, slot_1));
2795 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_1));
2796 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_2));
2797 gen_insn(INSN_X87_ALUP, op_size, fp_alu, 0);
2800 g(gen_frame_store_x87(ctx, INSN_X87_FSTP, op_size, slot_r));
2804 #ifdef SUPPORTED_FP_HALF_CVT
2805 if ((SUPPORTED_FP_HALF_CVT >> real_type) & 1) {
2806 g(gen_frame_get(ctx, op_size, zero_x, slot_1, FR_SCRATCH_1, ®1));
2807 g(gen_frame_get(ctx, op_size, zero_x, slot_2, FR_SCRATCH_2, ®2));
2808 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, FR_SCRATCH_1);
2809 gen_insn(INSN_FP_CVT, op_size, OP_SIZE_4, 0);
2810 gen_one(FR_SCRATCH_1);
2812 gen_insn(INSN_FP_CVT, op_size, OP_SIZE_4, 0);
2813 gen_one(FR_SCRATCH_2);
2815 gen_insn(INSN_FP_ALU, OP_SIZE_4, fp_alu, 0);
2816 gen_one(FR_SCRATCH_1);
2817 gen_one(FR_SCRATCH_1);
2818 gen_one(FR_SCRATCH_2);
2819 gen_insn(INSN_FP_CVT, OP_SIZE_4, op_size, 0);
2821 gen_one(FR_SCRATCH_1);
2822 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2829 if ((SUPPORTED_FP >> real_type) & 1
2830 #if defined(ARCH_ALPHA)
2831 && OS_SUPPORTS_TRAPS
2834 g(gen_frame_get(ctx, op_size, zero_x, slot_1, FR_SCRATCH_1, ®1));
2835 g(gen_frame_get(ctx, op_size, zero_x, slot_2, FR_SCRATCH_2, ®2));
2836 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
2837 #if defined(ARCH_ALPHA)
2838 gen_insn(INSN_FP_CMP_DEST_REG_TRAP, op_size, fp_alu == FP_COND_NE ? FP_COND_E : fp_alu, 0);
2839 gen_one(FR_SCRATCH_3);
2842 gen_four(label_ovf);
2844 if (!ARCH_HAS_FP_GP_MOV) {
2845 g(gen_frame_store_raw(ctx, OP_SIZE_4, slot_r, 0, FR_SCRATCH_3));
2846 g(gen_frame_load_raw(ctx, OP_SIZE_4, sign_x, slot_r, 0, false, target));
2848 g(gen_mov(ctx, OP_SIZE_4, target, FR_SCRATCH_3));
2851 if (fp_alu == FP_COND_NE) {
2852 g(gen_imm(ctx, 0, IMM_PURPOSE_CMP, OP_SIZE_NATIVE));
2853 gen_insn(INSN_CMP_DEST_REG, OP_SIZE_NATIVE, COND_E, 0);
2858 g(gen_3address_rot_imm(ctx, OP_SIZE_NATIVE, ROT_SHR, target, target, 30, 0));
2861 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, target));
2864 #elif defined(ARCH_IA64)
2865 gen_insn(INSN_FP_CMP_DEST_REG, op_size, FP_COND_P, 0);
2866 gen_one(R_CMP_RESULT);
2870 gen_insn(INSN_JMP_REG, OP_SIZE_NATIVE, COND_NE, 0);
2871 gen_one(R_CMP_RESULT);
2872 gen_four(label_ovf);
2874 gen_insn(INSN_FP_CMP_DEST_REG, op_size, fp_alu, 0);
2875 gen_one(R_CMP_RESULT);
2879 g(gen_mov(ctx, OP_SIZE_NATIVE, target, R_CMP_RESULT));
2881 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, target));
2884 #elif defined(ARCH_LOONGARCH64) || defined(ARCH_MIPS) || defined(ARCH_PARISC)
2885 gen_insn(INSN_FP_CMP_COND, op_size, FP_COND_P, 1);
2889 gen_insn(INSN_JMP_FP_TEST, 0, FP_COND_P, 0);
2890 gen_four(label_ovf);
2892 gen_insn(INSN_FP_CMP_COND, op_size, fp_alu, 1);
2896 gen_insn(INSN_FP_TEST_REG, OP_SIZE_NATIVE, fp_alu, 0);
2899 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, target));
2902 #elif defined(ARCH_RISCV64)
2903 gen_insn(INSN_FP_CMP_DEST_REG, op_size, FP_COND_E, 0);
2904 gen_one(R_SCRATCH_1);
2908 gen_insn(INSN_FP_CMP_DEST_REG, op_size, FP_COND_E, 0);
2909 gen_one(R_SCRATCH_2);
2913 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_AND, R_SCRATCH_1, R_SCRATCH_1, R_SCRATCH_2, 0));
2915 g(gen_jmp_on_zero(ctx, OP_SIZE_NATIVE, R_SCRATCH_1, COND_E, label_ovf));
2917 gen_insn(INSN_FP_CMP_DEST_REG, op_size, fp_alu == FP_COND_NE ? FP_COND_E : fp_alu, 0);
2922 if (fp_alu == FP_COND_NE) {
2923 g(gen_imm(ctx, 1, IMM_PURPOSE_XOR, OP_SIZE_NATIVE));
2924 gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_XOR, ALU_WRITES_FLAGS(OP_SIZE_NATIVE, ALU_XOR, false, is_imm(), ctx->const_imm));
2930 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, target));
2933 gen_insn(INSN_FP_CMP, op_size, 0, 1);
2936 #if defined(ARCH_ARM32)
2937 gen_insn(INSN_FP_TO_INT_FLAGS, 0, 0, 1);
2939 gen_insn(INSN_JMP_COND, op_size, FP_COND_P, 0);
2940 gen_four(label_ovf);
2941 g(gen_frame_set_cond(ctx, op_size, false, fp_alu, slot_r));
2945 #ifdef SUPPORTED_FP_X87
2946 if ((SUPPORTED_FP_X87 >> real_type) & 1) {
2947 if (likely(cpu_test_feature(CPU_FEATURE_cmov))) {
2948 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_2));
2949 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_1));
2950 gen_insn(INSN_X87_FCOMIP, op_size, 0, 0);
2952 gen_insn(INSN_X87_FSTP, op_size, 0, 0);
2954 gen_insn(INSN_JMP_COND, op_size, COND_P, 0);
2955 gen_four(label_ovf);
2956 g(gen_frame_set_cond(ctx, op_size, false, fp_alu & 0xf, slot_r));
2960 if (real_type != 3) {
2961 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_1));
2962 g(gen_frame_load_x87(ctx, INSN_X87_FCOMP, op_size, 0, slot_2));
2964 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_2));
2965 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_1));
2966 gen_insn(INSN_X87_FCOMPP, op_size, 0, 0);
2969 gen_insn(INSN_X87_FNSTSW, 0, 0, 0);
2973 gen_insn(INSN_TEST, OP_SIZE_2, 0, 1);
2978 gen_insn(INSN_JMP_COND, OP_SIZE_2, COND_NE, 0);
2979 gen_four(label_ovf);
2983 gen_insn(INSN_TEST, OP_SIZE_2, 0, 1);
2987 g(gen_frame_set_cond(ctx, OP_SIZE_2, false, COND_NE, slot_r));
2990 gen_insn(INSN_TEST, OP_SIZE_2, 0, 1);
2994 g(gen_frame_set_cond(ctx, OP_SIZE_2, false, COND_E, slot_r));
2997 gen_insn(INSN_TEST, OP_SIZE_2, 0, 1);
3001 g(gen_frame_set_cond(ctx, OP_SIZE_2, false, COND_NE, slot_r));
3004 gen_insn(INSN_TEST, OP_SIZE_2, 0, 1);
3008 g(gen_frame_set_cond(ctx, OP_SIZE_2, false, COND_NE, slot_r));
3011 internal(file_line, "gen_fp_alu: invalid condition %u", fp_alu);
3016 #ifdef SUPPORTED_FP_HALF_CVT
3017 if ((SUPPORTED_FP_HALF_CVT >> real_type) & 1) {
3018 g(gen_frame_get(ctx, op_size, zero_x, slot_1, FR_SCRATCH_1, ®1));
3019 g(gen_frame_get(ctx, op_size, zero_x, slot_2, FR_SCRATCH_2, ®2));
3020 gen_insn(INSN_FP_CVT, op_size, OP_SIZE_4, 0);
3021 gen_one(FR_SCRATCH_1);
3023 gen_insn(INSN_FP_CVT, op_size, OP_SIZE_4, 0);
3024 gen_one(FR_SCRATCH_2);
3026 gen_insn(INSN_FP_CMP, OP_SIZE_4, 0, 1);
3027 gen_one(FR_SCRATCH_1);
3028 gen_one(FR_SCRATCH_2);
3029 #if defined(ARCH_ARM32)
3030 gen_insn(INSN_FP_TO_INT_FLAGS, 0, 0, 1);
3032 gen_insn(INSN_JMP_COND, op_size, FP_COND_P, 0);
3033 gen_four(label_ovf);
3034 g(gen_frame_set_cond(ctx, op_size, false, fp_alu, slot_r));
3040 return gen_alu_typed_upcall(ctx, upc, real_type, slot_1, slot_2, slot_r, label_ovf);
3043 #define OP_IS_ROUND(alu) ((alu) == FP_ALU1_ROUND || (alu) == FP_ALU1_FLOOR || (alu) == FP_ALU1_CEIL || (alu) == FP_ALU1_TRUNC)
3045 static bool attr_w gen_fp_alu1(struct codegen_context *ctx, unsigned real_type, unsigned op, uint32_t label_ovf, frame_t slot_1, frame_t slot_r)
3047 unsigned attr_unused fp_alu;
3049 unsigned attr_unused op_size = real_type_to_op_size(real_type);
3050 unsigned reg1, target;
3052 case OPCODE_REAL_OP_neg:
3053 case OPCODE_REAL_OP_neg_alt1:
3054 case OPCODE_REAL_OP_neg_alt2: fp_alu = FP_ALU1_NEG; upc = offsetof(struct cg_upcall_vector_s, REAL_unary_neg_real16_t); label_ovf = 0; goto do_alu;
3055 case OPCODE_REAL_OP_sqrt:
3056 case OPCODE_REAL_OP_sqrt_alt1:
3057 case OPCODE_REAL_OP_sqrt_alt2: fp_alu = FP_ALU1_SQRT; upc = offsetof(struct cg_upcall_vector_s, REAL_unary_sqrt_real16_t); label_ovf = 0; goto do_alu;
3058 case OPCODE_REAL_OP_round: fp_alu = FP_ALU1_ROUND; upc = offsetof(struct cg_upcall_vector_s, REAL_unary_round_real16_t); label_ovf = 0; goto do_alu;
3059 case OPCODE_REAL_OP_floor: fp_alu = FP_ALU1_FLOOR; upc = offsetof(struct cg_upcall_vector_s, REAL_unary_floor_real16_t); label_ovf = 0; goto do_alu;
3060 case OPCODE_REAL_OP_ceil: fp_alu = FP_ALU1_CEIL; upc = offsetof(struct cg_upcall_vector_s, REAL_unary_ceil_real16_t); label_ovf = 0; goto do_alu;
3061 case OPCODE_REAL_OP_trunc: fp_alu = FP_ALU1_TRUNC; upc = offsetof(struct cg_upcall_vector_s, REAL_unary_trunc_real16_t); label_ovf = 0; goto do_alu;
3062 case OPCODE_REAL_OP_to_int:
3063 case OPCODE_REAL_OP_to_int_alt1:
3064 case OPCODE_REAL_OP_to_int_alt2: upc = offsetof(struct cg_upcall_vector_s, REAL_unary_to_int_real16_t); goto do_to_int;
3065 case OPCODE_REAL_OP_from_int:
3066 case OPCODE_REAL_OP_from_int_alt1:
3067 case OPCODE_REAL_OP_from_int_alt2: upc = offsetof(struct cg_upcall_vector_s, REAL_unary_from_int_real16_t); label_ovf = 0; goto do_from_int;
3068 case OPCODE_REAL_OP_is_exception:
3069 case OPCODE_REAL_OP_is_exception_alt1:
3070 case OPCODE_REAL_OP_is_exception_alt2: upc = offsetof(struct cg_upcall_vector_s, REAL_unary_is_exception_real16_t); label_ovf = 0; goto do_is_exception;
3071 default: upc = offsetof(struct cg_upcall_vector_s, REAL_unary_cbrt_real16_t) + (op - OPCODE_REAL_OP_cbrt) * TYPE_REAL_N * sizeof(void (*)(void)); label_ovf = 0; goto do_upcall;
3075 if ((SUPPORTED_FP >> real_type) & 1 && (
3076 #if defined(ARCH_ALPHA)
3077 fp_alu == FP_ALU1_NEG ||
3078 (fp_alu == FP_ALU1_SQRT && cpu_test_feature(CPU_FEATURE_fix)) ||
3079 #elif defined(ARCH_ARM32)
3080 fp_alu == FP_ALU1_NEG ||
3081 fp_alu == FP_ALU1_SQRT ||
3082 #elif defined(ARCH_ARM64)
3084 #elif defined(ARCH_IA64)
3085 fp_alu == FP_ALU1_NEG ||
3086 #elif defined(ARCH_LOONGARCH64)
3087 fp_alu == FP_ALU1_NEG ||
3088 fp_alu == FP_ALU1_SQRT ||
3089 fp_alu == FP_ALU1_ROUND ||
3090 #elif defined(ARCH_MIPS)
3091 fp_alu == FP_ALU1_NEG ||
3092 (fp_alu == FP_ALU1_SQRT && MIPS_HAS_SQRT) ||
3093 #elif defined(ARCH_PARISC)
3094 (fp_alu == FP_ALU1_NEG && PA_20) ||
3095 fp_alu == FP_ALU1_SQRT ||
3096 #elif defined(ARCH_POWER)
3097 fp_alu == FP_ALU1_NEG ||
3098 (fp_alu == FP_ALU1_SQRT && cpu_test_feature(CPU_FEATURE_p2) && real_type != 4) ||
3099 #elif defined(ARCH_S390)
3101 #elif defined(ARCH_SPARC)
3102 fp_alu == FP_ALU1_NEG ||
3103 fp_alu == FP_ALU1_SQRT ||
3104 #elif defined(ARCH_RISCV64)
3105 fp_alu == FP_ALU1_NEG ||
3106 fp_alu == FP_ALU1_SQRT ||
3107 #elif defined(ARCH_X86)
3108 fp_alu == FP_ALU1_SQRT ||
3109 (OP_IS_ROUND(fp_alu) && cpu_test_feature(CPU_FEATURE_sse41)) ||
3112 #if defined(ARCH_S390)
3113 if (op_size <= OP_SIZE_8 && (size_t)slot_1 * slot_size < 4096 && fp_alu == FP_ALU1_SQRT) {
3114 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, FR_SCRATCH_1);
3115 if (slot_is_register(ctx, slot_1)) {
3116 gen_insn(INSN_FP_ALU1, op_size, fp_alu, 0);
3118 gen_one(ctx->registers[slot_1]);
3119 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
3121 g(gen_address(ctx, R_FRAME, (size_t)slot_1 * slot_size, IMM_PURPOSE_VLDR_VSTR_OFFSET, op_size));
3122 gen_insn(INSN_FP_ALU1, op_size, fp_alu, 0);
3124 gen_address_offset();
3125 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
3130 g(gen_frame_get(ctx, op_size, zero_x, slot_1, FR_SCRATCH_1, ®1));
3131 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, FR_SCRATCH_2);
3132 gen_insn(INSN_FP_ALU1, op_size, fp_alu, 0);
3135 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
3138 #ifdef SUPPORTED_FP_X87
3139 if ((SUPPORTED_FP_X87 >> real_type) & 1) {
3140 if (fp_alu == FP_ALU1_NEG) {
3141 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_1));
3142 gen_insn(INSN_X87_FCHS, op_size, 0, 0);
3143 g(gen_frame_store_x87(ctx, INSN_X87_FSTP, op_size, slot_r));
3145 } else if (fp_alu == FP_ALU1_SQRT) {
3146 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_1));
3147 gen_insn(INSN_X87_FSQRT, op_size, 0, 0);
3148 g(gen_frame_store_x87(ctx, INSN_X87_FSTP, op_size, slot_r));
3150 } else if (fp_alu == FP_ALU1_ROUND) {
3151 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_1));
3152 gen_insn(INSN_X87_FRNDINT, op_size, 0, 0);
3153 g(gen_frame_store_x87(ctx, INSN_X87_FSTP, op_size, slot_r));
3158 #ifdef SUPPORTED_FP_HALF_CVT
3159 if ((SUPPORTED_FP_HALF_CVT >> real_type) & 1 && (
3160 #if defined(ARCH_ARM32)
3161 fp_alu == FP_ALU1_NEG ||
3162 fp_alu == FP_ALU1_SQRT ||
3163 #elif defined(ARCH_ARM64)
3165 #elif defined(ARCH_X86)
3166 fp_alu == FP_ALU1_SQRT ||
3167 (OP_IS_ROUND(fp_alu) && cpu_test_feature(CPU_FEATURE_sse41)) ||
3170 g(gen_frame_get(ctx, op_size, zero_x, slot_1, FR_SCRATCH_1, ®1));
3171 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, FR_SCRATCH_1);
3172 gen_insn(INSN_FP_CVT, op_size, OP_SIZE_4, 0);
3175 gen_insn(INSN_FP_ALU1, OP_SIZE_4, fp_alu, 0);
3178 gen_insn(INSN_FP_CVT, OP_SIZE_4, op_size, 0);
3181 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
3188 if ((SUPPORTED_FP >> real_type) & 1
3189 #if defined(ARCH_ALPHA)
3190 && OS_SUPPORTS_TRAPS
3192 #if defined(ARCH_MIPS)
3196 g(gen_frame_get(ctx, op_size, zero_x, slot_1, FR_SCRATCH_1, ®1));
3199 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
3200 #if defined(ARCH_X86)
3201 gen_insn(OP_SIZE_INT == OP_SIZE_4 ? INSN_FP_TO_INT32 : INSN_FP_TO_INT64, op_size, 0, 0);
3205 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, OP_SIZE_INT, target, sign_bit(uint_default_t), COND_E, label_ovf));
3207 g(gen_frame_store(ctx, OP_SIZE_INT, slot_r, 0, target));
3210 #if defined(ARCH_ARM) || defined(ARCH_LOONGARCH64) || defined(ARCH_MIPS)
3211 #if defined(ARCH_ARM)
3212 gen_insn(INSN_FP_CMP, op_size, 0, 1);
3215 #if defined(ARCH_ARM32)
3216 gen_insn(INSN_FP_TO_INT_FLAGS, 0, 0, 1);
3218 gen_insn(INSN_JMP_COND, op_size, FP_COND_P, 0);
3219 gen_four(label_ovf);
3221 gen_insn(INSN_FP_CMP_COND, op_size, FP_COND_P, 1);
3225 gen_insn(INSN_JMP_FP_TEST, 0, FP_COND_P, 0);
3226 gen_four(label_ovf);
3228 #if defined(ARCH_ARM32) || defined(ARCH_LOONGARCH64) || defined(ARCH_MIPS)
3229 gen_insn(OP_SIZE_INT == OP_SIZE_4 ? INSN_FP_TO_INT32 : INSN_FP_TO_INT64, op_size, 0, 0);
3230 gen_one(FR_SCRATCH_1);
3233 g(gen_mov(ctx, OP_SIZE_INT, target, FR_SCRATCH_1));
3235 gen_insn(OP_SIZE_INT == OP_SIZE_4 ? INSN_FP_TO_INT32 : INSN_FP_TO_INT64, op_size, 0, 0);
3239 g(gen_imm(ctx, (int_default_t)(sign_bit(uint_default_t) + 1), IMM_PURPOSE_ADD, OP_SIZE_INT));
3240 gen_insn(INSN_ALU, OP_SIZE_INT, ALU_ADD, ALU_WRITES_FLAGS(OP_SIZE_INT, ALU_ADD, false, is_imm(), ctx->const_imm));
3241 gen_one(R_SCRATCH_2);
3245 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, OP_SIZE_INT, R_SCRATCH_2, 1, COND_BE, label_ovf));
3247 g(gen_frame_store(ctx, OP_SIZE_INT, slot_r, 0, target));
3250 #if defined(ARCH_IA64)
3251 gen_insn(INSN_FP_TO_INT64, op_size, 0, 0);
3252 gen_one(FR_SCRATCH_1);
3255 g(gen_mov(ctx, OP_SIZE_NATIVE, target, FR_SCRATCH_1));
3257 if (OP_SIZE_INT == OP_SIZE_4) {
3258 g(gen_extend(ctx, OP_SIZE_4, sign_x, R_SCRATCH_2, target));
3259 g(gen_cmp_test_jmp(ctx, INSN_CMP, OP_SIZE_NATIVE, target, R_SCRATCH_2, COND_NE, label_ovf));
3261 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, OP_SIZE_NATIVE, target, sign_bit(uint64_t), COND_E, label_ovf));
3264 g(gen_frame_store(ctx, OP_SIZE_INT, slot_r, 0, target));
3267 #if defined(ARCH_PARISC) || defined(ARCH_POWER) || defined(ARCH_SPARC)
3268 #if defined(ARCH_POWER)
3269 if (!cpu_test_feature(CPU_FEATURE_ppc))
3271 if (OP_SIZE_INT == OP_SIZE_4)
3274 gen_insn(OP_SIZE_INT == OP_SIZE_4 ? INSN_FP_TO_INT32 : INSN_FP_TO_INT64, op_size, 0, 0);
3275 gen_one(FR_SCRATCH_1);
3278 g(gen_frame_store_raw(ctx, OP_SIZE_INT, slot_r, 0, FR_SCRATCH_1));
3279 if (slot_is_register(ctx, slot_r))
3280 g(unspill(ctx, slot_r));
3281 g(gen_frame_load(ctx, OP_SIZE_INT, garbage, slot_r, 0, false, target));
3283 g(gen_imm(ctx, sign_bit(uint_default_t) + 1, IMM_PURPOSE_ADD, OP_SIZE_INT));
3284 gen_insn(INSN_ALU, i_size(OP_SIZE_INT), ALU_ADD, ALU_WRITES_FLAGS(i_size(OP_SIZE_INT), ALU_ADD, false, is_imm(), ctx->const_imm));
3285 gen_one(R_SCRATCH_2);
3289 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, OP_SIZE_INT, R_SCRATCH_2, 1, COND_BE, label_ovf));
3293 #if defined(ARCH_ALPHA)
3294 gen_insn(INSN_FP_TO_INT64_TRAP, op_size, 0, 0);
3295 gen_one(FR_SCRATCH_2);
3297 gen_four(label_ovf);
3299 if (OP_SIZE_INT == OP_SIZE_4) {
3300 gen_insn(INSN_FP_INT64_TO_INT32_TRAP, 0, 0, 0);
3301 gen_one(FR_SCRATCH_3);
3302 gen_one(FR_SCRATCH_2);
3303 gen_four(label_ovf);
3304 g(gen_frame_store_raw(ctx, OP_SIZE_INT, slot_r, 0, FR_SCRATCH_3));
3306 g(gen_frame_store_raw(ctx, OP_SIZE_INT, slot_r, 0, FR_SCRATCH_2));
3308 if (slot_is_register(ctx, slot_r))
3309 g(unspill(ctx, slot_r));
3312 #if defined(ARCH_S390)
3313 gen_insn(OP_SIZE_INT == OP_SIZE_4 ? INSN_FP_TO_INT32 : INSN_FP_TO_INT64, op_size, 0, 1);
3317 gen_insn(INSN_JMP_COND, op_size, FP_COND_P, 0);
3318 gen_four(label_ovf);
3320 g(gen_frame_store(ctx, OP_SIZE_INT, slot_r, 0, target));
3323 #if defined(ARCH_RISCV64)
3324 gen_insn(OP_SIZE_INT == OP_SIZE_4 ? INSN_FP_TO_INT32 : INSN_FP_TO_INT64, op_size, 0, 0);
3328 g(gen_load_constant(ctx, R_SCRATCH_2, sign_bit(int_default_t)));
3330 g(gen_cmp_test_jmp(ctx, INSN_CMP, OP_SIZE_NATIVE, target, R_SCRATCH_2, COND_E, label_ovf));
3332 g(gen_imm(ctx, -1, IMM_PURPOSE_XOR, i_size(size)));
3333 gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_XOR, ALU_WRITES_FLAGS(OP_SIZE_NATIVE, ALU_XOR, false, is_imm(), ctx->const_imm));
3334 gen_one(R_SCRATCH_2);
3335 gen_one(R_SCRATCH_2);
3338 g(gen_cmp_test_jmp(ctx, INSN_CMP, OP_SIZE_NATIVE, target, R_SCRATCH_2, COND_E, label_ovf));
3340 g(gen_frame_store(ctx, OP_SIZE_INT, slot_r, 0, target));
3344 #ifdef SUPPORTED_FP_X87
3345 if ((SUPPORTED_FP_X87 >> real_type) & 1) {
3346 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_1));
3348 if (likely(cpu_test_feature(CPU_FEATURE_sse3))) {
3349 g(gen_frame_store_x87(ctx, INSN_X87_FISTTP, OP_SIZE_INT, slot_r));
3351 gen_insn(INSN_PUSH, OP_SIZE_NATIVE, 0, 0);
3355 gen_insn(INSN_X87_FLDCW, 0, 0, 0);
3356 gen_one(ARG_ADDRESS_1);
3360 g(gen_frame_store_x87(ctx, INSN_X87_FISTP, OP_SIZE_INT, slot_r));
3362 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
3363 gen_one(ARG_ADDRESS_1);
3369 gen_insn(INSN_X87_FLDCW, 0, 0, 0);
3370 gen_one(ARG_ADDRESS_1);
3374 gen_insn(INSN_ALU, i_size(OP_SIZE_ADDRESS), ALU_ADD, 1);
3378 gen_eight(1 << OP_SIZE_NATIVE);
3380 if (slot_is_register(ctx, slot_r))
3381 g(unspill(ctx, slot_r));
3382 g(gen_frame_load(ctx, OP_SIZE_INT, garbage, slot_r, 0, false, R_SCRATCH_1));
3384 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, OP_SIZE_INT, R_SCRATCH_1, sign_bit(int_default_t), COND_E, label_ovf));
3389 #ifdef SUPPORTED_FP_HALF_CVT
3390 if ((SUPPORTED_FP_HALF_CVT >> real_type) & 1) {
3391 g(gen_frame_get(ctx, op_size, zero_x, slot_1, FR_SCRATCH_1, ®1));
3392 gen_insn(INSN_FP_CVT, op_size, OP_SIZE_4, 0);
3393 gen_one(FR_SCRATCH_1);
3395 reg1 = FR_SCRATCH_1;
3397 op_size = real_type_to_op_size(real_type);
3404 if ((SUPPORTED_FP >> real_type) & 1) {
3405 #if defined(ARCH_ALPHA) || defined(ARCH_ARM32) || defined(ARCH_LOONGARCH64) || defined(ARCH_MIPS) || defined(ARCH_PARISC) || defined(ARCH_POWER) || defined(ARCH_SPARC)
3406 int int_op_size = OP_SIZE_INT;
3407 #if defined(ARCH_POWER)
3408 if (int_op_size == OP_SIZE_4)
3410 if (op_size == OP_SIZE_4 && !cpu_test_feature(CPU_FEATURE_v206))
3412 if (op_size == OP_SIZE_8 && !cpu_test_feature(CPU_FEATURE_ppc))
3415 if (slot_is_register(ctx, slot_1))
3416 g(spill(ctx, slot_1));
3417 g(gen_frame_load_raw(ctx, int_op_size, zero_x, slot_1, 0, false, FR_SCRATCH_1));
3418 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, FR_SCRATCH_2);
3419 #if defined(ARCH_ALPHA)
3420 if (OP_SIZE_INT == OP_SIZE_4) {
3421 gen_insn(INSN_MOVSX, OP_SIZE_4, 0, 0);
3422 gen_one(FR_SCRATCH_1);
3423 gen_one(FR_SCRATCH_1);
3425 int_op_size = OP_SIZE_8;
3428 gen_insn(int_op_size == OP_SIZE_4 ? INSN_FP_FROM_INT32 : INSN_FP_FROM_INT64, op_size, 0, 0);
3430 gen_one(FR_SCRATCH_1);
3432 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
3434 #elif defined(ARCH_IA64)
3435 g(gen_frame_get(ctx, OP_SIZE_INT, sign_x, slot_1, R_SCRATCH_1, ®1));
3436 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, FR_SCRATCH_1);
3438 g(gen_mov(ctx, OP_SIZE_NATIVE, target, reg1));
3440 gen_insn(INSN_FP_FROM_INT64, op_size, 0, 0);
3444 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
3447 g(gen_frame_get(ctx, OP_SIZE_INT, garbage, slot_1, R_SCRATCH_1, ®1));
3448 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, FR_SCRATCH_1);
3450 gen_insn(OP_SIZE_INT == OP_SIZE_4 ? INSN_FP_FROM_INT32 : INSN_FP_FROM_INT64, op_size, 0, 0);
3454 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
3458 #ifdef SUPPORTED_FP_X87
3459 if ((SUPPORTED_FP_X87 >> real_type) & 1) {
3460 if (slot_is_register(ctx, slot_1))
3461 g(spill(ctx, slot_1));
3462 g(gen_frame_load_x87(ctx, INSN_X87_FILD, OP_SIZE_INT, 0, slot_1));
3463 g(gen_frame_store_x87(ctx, INSN_X87_FSTP, op_size, slot_r));
3467 #ifdef SUPPORTED_FP_HALF_CVT
3468 if ((SUPPORTED_FP_HALF_CVT >> real_type) & 1) {
3469 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, FR_SCRATCH_1);
3470 #if defined(ARCH_ARM32)
3471 g(gen_frame_get(ctx, OP_SIZE_INT, zero_x, slot_1, FR_SCRATCH_1, ®1));
3473 gen_insn(INSN_FP_FROM_INT32, OP_SIZE_4, 0, 0);
3477 g(gen_frame_get(ctx, OP_SIZE_INT, garbage, slot_1, R_SCRATCH_1, ®1));
3478 gen_insn(OP_SIZE_INT == OP_SIZE_4 ? INSN_FP_FROM_INT32 : INSN_FP_FROM_INT64, OP_SIZE_4, 0, 0);
3482 gen_insn(INSN_FP_CVT, OP_SIZE_4, op_size, 0);
3485 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
3492 if ((SUPPORTED_FP >> real_type) & 1) {
3493 g(gen_frame_get(ctx, op_size, zero_x, slot_1, FR_SCRATCH_1, ®1));
3494 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
3495 #if defined(ARCH_ALPHA)
3496 gen_insn(INSN_FP_CMP_UNORDERED_DEST_REG, op_size, 0, 0);
3497 gen_one(FR_SCRATCH_2);
3498 gen_one(FR_SCRATCH_1);
3501 if (!cpu_test_feature(CPU_FEATURE_fix)) {
3502 g(gen_frame_store_raw(ctx, OP_SIZE_4, slot_r, 0, FR_SCRATCH_2));
3503 g(gen_frame_load_raw(ctx, OP_SIZE_4, sign_x, slot_r, 0, false, target));
3505 g(gen_mov(ctx, OP_SIZE_4, target, FR_SCRATCH_2));
3508 g(gen_3address_rot_imm(ctx, OP_SIZE_NATIVE, ROT_SHR, target, target, 30, 0));
3510 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, target));
3513 #elif defined(ARCH_IA64)
3514 gen_insn(INSN_FP_CMP_DEST_REG, op_size, FP_COND_P, 0);
3515 gen_one(R_CMP_RESULT);
3519 g(gen_mov(ctx, OP_SIZE_NATIVE, target, R_CMP_RESULT));
3521 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, target));
3522 #elif defined(ARCH_LOONGARCH64) || defined(ARCH_MIPS) || defined(ARCH_PARISC)
3523 gen_insn(INSN_FP_CMP_COND, op_size, FP_COND_P, 1);
3527 gen_insn(INSN_FP_TEST_REG, OP_SIZE_NATIVE, FP_COND_P, 0);
3530 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, target));
3531 #elif defined(ARCH_RISCV64)
3532 gen_insn(INSN_FP_CMP_DEST_REG, op_size, FP_COND_E, 0);
3537 g(gen_imm(ctx, 1, IMM_PURPOSE_XOR, OP_SIZE_NATIVE));
3538 gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_XOR, ALU_WRITES_FLAGS(OP_SIZE_NATIVE, ALU_XOR, false, is_imm(), ctx->const_imm));
3543 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, target));
3545 gen_insn(INSN_FP_CMP, op_size, 0, 1);
3548 #if defined(ARCH_ARM32)
3549 gen_insn(INSN_FP_TO_INT_FLAGS, 0, 0, 1);
3551 g(gen_frame_set_cond(ctx, op_size, false, FP_COND_P, slot_r));
3555 #ifdef SUPPORTED_FP_X87
3556 if ((SUPPORTED_FP_X87 >> real_type) & 1) {
3557 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_1));
3558 if (likely(cpu_test_feature(CPU_FEATURE_cmov))) {
3559 gen_insn(INSN_X87_FCOMIP, op_size, 0, 0);
3562 g(gen_frame_set_cond(ctx, op_size, false, COND_P, slot_r));
3566 gen_insn(INSN_X87_FCOMP, op_size, 0, 0);
3569 gen_insn(INSN_X87_FNSTSW, 0, 0, 0);
3573 gen_insn(INSN_TEST, OP_SIZE_2, 0, 1);
3578 g(gen_frame_set_cond(ctx, op_size, false, COND_NE, slot_r));
3583 #ifdef SUPPORTED_FP_HALF_CVT
3584 if ((SUPPORTED_FP_HALF_CVT >> real_type) & 1) {
3585 g(gen_frame_get(ctx, op_size, zero_x, slot_1, FR_SCRATCH_1, ®1));
3586 gen_insn(INSN_FP_CVT, op_size, OP_SIZE_4, 0);
3587 gen_one(FR_SCRATCH_1);
3589 gen_insn(INSN_FP_CMP, OP_SIZE_4, 0, 1);
3590 gen_one(FR_SCRATCH_1);
3591 gen_one(FR_SCRATCH_1);
3592 #if defined(ARCH_ARM32)
3593 gen_insn(INSN_FP_TO_INT_FLAGS, 0, 0, 1);
3595 g(gen_frame_set_cond(ctx, op_size, false, FP_COND_P, slot_r));
3601 g(gen_alu_typed_upcall(ctx, upc, real_type, slot_1, NO_FRAME_T, slot_r, label_ovf));
3605 static bool attr_w gen_is_exception(struct codegen_context *ctx, frame_t slot_1, frame_t slot_r)
3607 uint32_t no_ex_label, escape_label;
3608 const struct type *type = get_type_of_local(ctx, slot_1);
3610 no_ex_label = alloc_label(ctx);
3611 if (unlikely(!no_ex_label))
3613 escape_label = alloc_escape_label(ctx);
3614 if (unlikely(!escape_label))
3617 if (TYPE_IS_FLAT(type))
3618 g(gen_test_1_jz_cached(ctx, slot_1, no_ex_label));
3620 g(gen_frame_load(ctx, OP_SIZE_SLOT, zero_x, slot_1, 0, false, R_SCRATCH_1));
3621 g(gen_ptr_is_thunk(ctx, R_SCRATCH_1, slot_1, escape_label));
3623 if (!TYPE_IS_FLAT(type)) {
3624 g(gen_compare_da_tag(ctx, R_SCRATCH_1, DATA_TAG_flat, COND_E, escape_label, R_SCRATCH_1));
3627 gen_label(no_ex_label);
3628 g(gen_frame_clear(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r));
3630 flag_set(ctx, slot_r, false);
3635 static bool attr_w gen_system_property(struct codegen_context *ctx, frame_t slot_1, frame_t slot_r)
3637 uint32_t escape_label;
3639 escape_label = alloc_escape_label(ctx);
3640 if (unlikely(!escape_label))
3643 g(gen_test_1_cached(ctx, slot_1, escape_label));
3645 g(gen_upcall_start(ctx, offsetof(struct cg_upcall_vector_s, cg_upcall_ipret_system_property), 1));
3647 g(gen_frame_load(ctx, OP_SIZE_INT, garbage, slot_1, 0, false, R_ARG0));
3648 g(gen_upcall_argument(ctx, 0));
3650 g(gen_upcall(ctx, offsetof(struct cg_upcall_vector_s, cg_upcall_ipret_system_property), 1));
3652 g(gen_frame_store(ctx, OP_SIZE_INT, slot_r, 0, R_RET0));
3654 flag_set(ctx, slot_1, false);
3655 flag_set(ctx, slot_r, false);
3660 static bool attr_w gen_alu_jmp(struct codegen_context *ctx, unsigned mode, unsigned op_size, unsigned op, frame_t slot_1, frame_t slot_2, int32_t jmp_offset, bool *failed)
3665 unsigned attr_unused reg2;
3667 *failed = true; return true;
3670 case MODE_FIXED: switch (op) {
3671 case OPCODE_FIXED_OP_equal: alu = COND_E; goto do_compare;
3672 case OPCODE_FIXED_OP_not_equal: alu = COND_NE; goto do_compare;
3673 case OPCODE_FIXED_OP_less: alu = COND_L; goto do_compare;
3674 case OPCODE_FIXED_OP_less_equal: alu = COND_LE; goto do_compare;
3675 case OPCODE_FIXED_OP_greater: alu = COND_G; goto do_compare;
3676 case OPCODE_FIXED_OP_greater_equal: alu = COND_GE; goto do_compare;
3677 case OPCODE_FIXED_OP_uless: alu = COND_B; goto do_compare;
3678 case OPCODE_FIXED_OP_uless_equal: alu = COND_BE; goto do_compare;
3679 case OPCODE_FIXED_OP_ugreater: alu = COND_A; goto do_compare;
3680 case OPCODE_FIXED_OP_ugreater_equal: alu = COND_AE; goto do_compare;
3681 case OPCODE_FIXED_OP_bt: *failed = true; return true;
3682 default: internal(file_line, "gen_alu_jmp: unsupported fixed operation %u", op);
3684 case MODE_INT: switch (op) {
3685 case OPCODE_INT_OP_equal: alu = COND_E; goto do_compare;
3686 case OPCODE_INT_OP_not_equal: alu = COND_NE; goto do_compare;
3687 case OPCODE_INT_OP_less: alu = COND_L; goto do_compare;
3688 case OPCODE_INT_OP_less_equal: alu = COND_LE; goto do_compare;
3689 case OPCODE_INT_OP_greater: alu = COND_G; goto do_compare;
3690 case OPCODE_INT_OP_greater_equal: alu = COND_GE; goto do_compare;
3691 case OPCODE_INT_OP_bt: *failed = true; return true;
3692 default: internal(file_line, "gen_alu_jmp: unsupported int operation %u", op);
3694 case MODE_BOOL: switch (op) {
3695 case OPCODE_BOOL_OP_and: alu = ALU_AND; mode = MODE_FIXED; goto do_alu;
3696 case OPCODE_BOOL_OP_or: alu = ALU_OR; mode = MODE_FIXED; goto do_alu;
3697 case OPCODE_BOOL_OP_equal: alu = COND_E; mode = MODE_FIXED; goto do_compare;
3698 case OPCODE_BOOL_OP_not_equal: alu = COND_NE; mode = MODE_FIXED; goto do_compare;
3699 case OPCODE_BOOL_OP_less: alu = COND_L; mode = MODE_FIXED; goto do_compare;
3700 case OPCODE_BOOL_OP_less_equal: alu = COND_LE; mode = MODE_FIXED; goto do_compare;
3701 case OPCODE_BOOL_OP_greater: alu = COND_G; mode = MODE_FIXED; goto do_compare;
3702 case OPCODE_BOOL_OP_greater_equal: alu = COND_GE; mode = MODE_FIXED; goto do_compare;
3703 default: internal(file_line, "gen_alu_jmp: unsupported bool operation %u", op);
3706 internal(file_line, "gen_alu_jmp: unsupported mode %u", mode);
3708 bool attr_unused logical;
3709 if (unlikely(op_size > OP_SIZE_NATIVE)) {
3713 if (slot_is_register(ctx, slot_2) && !slot_is_register(ctx, slot_1)) {
3718 case COND_L: alu = COND_G; break;
3719 case COND_LE: alu = COND_GE; break;
3720 case COND_G: alu = COND_L; break;
3721 case COND_GE: alu = COND_LE; break;
3722 case COND_B: alu = COND_A; break;
3723 case COND_BE: alu = COND_AE; break;
3724 case COND_A: alu = COND_B; break;
3725 case COND_AE: alu = COND_BE; break;
3728 ex = op_size == i_size_cmp(op_size) + (unsigned)zero ? garbage : alu == COND_L || alu == COND_LE || alu == COND_G || alu == COND_GE || ARCH_PREFERS_SX(op_size) ? sign_x : zero_x;
3729 g(gen_frame_get(ctx, op_size, ex, slot_1, R_SCRATCH_1, ®1));
3730 if (ARCH_HAS_JMP_2REGS(alu)) {
3731 g(gen_frame_get(ctx, op_size, ex, slot_2, R_SCRATCH_2, ®2));
3732 g(gen_jump(ctx, jmp_offset, i_size_cmp(op_size), alu ^ 1, reg1, reg2));
3736 logical = COND_IS_LOGICAL(alu ^ 1);
3737 g(gen_frame_load_cmp(ctx, op_size, logical, ex, false, slot_2, 0, false, reg1));
3738 g(gen_jump(ctx, jmp_offset, op_size, alu ^ 1, -1U, -1U));
3740 g(gen_frame_get(ctx, op_size, ex, slot_2, R_SCRATCH_2, ®2));
3741 g(gen_cmp_dest_reg(ctx, op_size, reg1, reg2, R_CMP_RESULT, 0, alu));
3742 g(gen_jump(ctx, jmp_offset, OP_SIZE_NATIVE, COND_E, R_CMP_RESULT, -1U));
3747 if (slot_is_register(ctx, slot_2) && !slot_is_register(ctx, slot_1)) {
3752 ex = op_size == i_size(op_size) + (unsigned)zero ? garbage : ARCH_PREFERS_SX(op_size) ? sign_x : zero_x;
3753 g(gen_frame_get(ctx, op_size, ex, slot_1, R_SCRATCH_1, ®1));
3754 #if defined(ARCH_X86)
3755 if (alu == ALU_AND && !slot_is_register(ctx, slot_2)) {
3756 g(gen_address(ctx, R_FRAME, (size_t)slot_2 * slot_size, IMM_PURPOSE_LDR_OFFSET, op_size));
3757 gen_insn(INSN_TEST, i_size(op_size), 0, 1);
3759 gen_address_offset();
3760 g(gen_jump(ctx, jmp_offset, op_size, COND_E, -1U, -1U));
3764 g(gen_frame_get(ctx, op_size, ex, slot_2, R_SCRATCH_2, ®2));
3765 #if ARCH_HAS_FLAGS && !defined(ARCH_S390)
3766 if (alu == ALU_AND) {
3767 gen_insn(INSN_TEST, i_size(op_size), 0, 1);
3770 g(gen_jump(ctx, jmp_offset, op_size, COND_E, -1U, -1U));
3774 #if defined(ARCH_ARM64)
3779 g(gen_3address_alu(ctx, i_size(op_size), alu, R_SCRATCH_1, reg1, reg2, 1));
3780 g(gen_jump(ctx, jmp_offset, i_size(op_size), COND_E, -1U, -1U));
3785 g(gen_3address_alu(ctx, i_size(op_size), alu, R_SCRATCH_1, reg1, reg2, 0));
3786 g(gen_jump(ctx, jmp_offset, i_size(op_size), COND_E, R_SCRATCH_1, -1U));
3791 static bool attr_w gen_fp_alu_jmp(struct codegen_context *ctx, unsigned real_type, unsigned op, uint32_t label_ovf, frame_t slot_1, frame_t slot_2, int32_t jmp_offset, bool *failed)
3793 unsigned attr_unused fp_alu;
3794 unsigned attr_unused op_size = real_type_to_op_size(real_type);
3795 unsigned reg1, reg2;
3796 unsigned attr_unused target;
3798 case OPCODE_REAL_OP_equal:
3799 case OPCODE_REAL_OP_equal_alt1:
3800 case OPCODE_REAL_OP_equal_alt2: fp_alu = FP_COND_E; goto do_cmp;
3801 case OPCODE_REAL_OP_not_equal:
3802 case OPCODE_REAL_OP_not_equal_alt1:
3803 case OPCODE_REAL_OP_not_equal_alt2: fp_alu = FP_COND_NE; goto do_cmp;
3804 case OPCODE_REAL_OP_less:
3805 case OPCODE_REAL_OP_less_alt1:
3806 case OPCODE_REAL_OP_less_alt2: fp_alu = FP_COND_B; goto do_cmp;
3807 case OPCODE_REAL_OP_less_equal:
3808 case OPCODE_REAL_OP_less_equal_alt1:
3809 case OPCODE_REAL_OP_less_equal_alt2: fp_alu = FP_COND_BE; goto do_cmp;
3810 case OPCODE_REAL_OP_greater:
3811 case OPCODE_REAL_OP_greater_alt1:
3812 case OPCODE_REAL_OP_greater_alt2: fp_alu = FP_COND_A; goto do_cmp;
3813 case OPCODE_REAL_OP_greater_equal:
3814 case OPCODE_REAL_OP_greater_equal_alt1:
3815 case OPCODE_REAL_OP_greater_equal_alt2: fp_alu = FP_COND_AE; goto do_cmp;
3816 default: internal(file_line, "gen_fp_alu_jmp: unsupported operation %u", op);
3820 if ((SUPPORTED_FP >> real_type) & 1
3821 #if defined(ARCH_ALPHA)
3822 && OS_SUPPORTS_TRAPS && cpu_test_feature(CPU_FEATURE_fix)
3825 g(gen_frame_get(ctx, op_size, zero_x, slot_1, FR_SCRATCH_1, ®1));
3826 g(gen_frame_get(ctx, op_size, zero_x, slot_2, FR_SCRATCH_2, ®2));
3827 target = R_SCRATCH_1;
3828 #if defined(ARCH_ALPHA)
3829 gen_insn(INSN_FP_CMP_DEST_REG_TRAP, op_size, fp_alu == FP_COND_NE ? FP_COND_E : fp_alu, 0);
3830 gen_one(FR_SCRATCH_3);
3833 gen_four(label_ovf);
3835 g(gen_mov(ctx, OP_SIZE_4, target, FR_SCRATCH_3));
3837 if (fp_alu == FP_COND_NE) {
3838 g(gen_jump(ctx, jmp_offset, OP_SIZE_NATIVE, COND_NE, target, -1U));
3840 g(gen_jump(ctx, jmp_offset, OP_SIZE_NATIVE, COND_E, target, -1U));
3844 #elif defined(ARCH_IA64)
3845 gen_insn(INSN_FP_CMP_DEST_REG, op_size, FP_COND_P, 0);
3846 gen_one(R_CMP_RESULT);
3850 gen_insn(INSN_JMP_REG, OP_SIZE_NATIVE, COND_NE, 0);
3851 gen_one(R_CMP_RESULT);
3852 gen_four(label_ovf);
3854 gen_insn(INSN_FP_CMP_DEST_REG, op_size, fp_alu, 0);
3855 gen_one(R_CMP_RESULT);
3859 g(gen_jump(ctx, jmp_offset, OP_SIZE_NATIVE, COND_E, R_CMP_RESULT, -1U));
3862 #elif defined(ARCH_LOONGARCH64) || defined(ARCH_MIPS) || defined(ARCH_PARISC)
3863 gen_insn(INSN_FP_CMP_COND, op_size, FP_COND_P, 1);
3867 gen_insn(INSN_JMP_FP_TEST, 0, FP_COND_P, 0);
3868 gen_four(label_ovf);
3870 gen_insn(INSN_FP_CMP_COND, op_size, fp_alu ^ 1, 1);
3874 g(gen_jump(ctx, jmp_offset, OP_SIZE_NATIVE, fp_alu ^ 1, -1U, -1U));
3877 #elif defined(ARCH_RISCV64)
3878 gen_insn(INSN_FP_CMP_DEST_REG, op_size, FP_COND_E, 0);
3879 gen_one(R_SCRATCH_1);
3883 gen_insn(INSN_FP_CMP_DEST_REG, op_size, FP_COND_E, 0);
3884 gen_one(R_SCRATCH_2);
3888 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_AND, R_SCRATCH_1, R_SCRATCH_1, R_SCRATCH_2, 0));
3890 g(gen_jmp_on_zero(ctx, OP_SIZE_NATIVE, R_SCRATCH_1, COND_E, label_ovf));
3892 gen_insn(INSN_FP_CMP_DEST_REG, op_size, fp_alu == FP_COND_NE ? FP_COND_E : fp_alu, 0);
3897 if (fp_alu == FP_COND_NE) {
3898 g(gen_jump(ctx, jmp_offset, OP_SIZE_NATIVE, COND_NE, target, -1U));
3900 g(gen_jump(ctx, jmp_offset, OP_SIZE_NATIVE, COND_E, target, -1U));
3904 gen_insn(INSN_FP_CMP, op_size, 0, 1);
3907 #if defined(ARCH_ARM32)
3908 gen_insn(INSN_FP_TO_INT_FLAGS, 0, 0, 1);
3910 gen_insn(INSN_JMP_COND, op_size, FP_COND_P, 0);
3911 gen_four(label_ovf);
3912 g(gen_jump(ctx, jmp_offset, op_size, fp_alu ^ 1, -1U, -1U));