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 g(gen_upcall_start(ctx, frame_t_is_const(slot_2) ? 4 : slot_2 != NO_FRAME_T ? 3 : 2));
28 g(gen_frame_address(ctx, slot_1, 0, R_ARG0));
29 g(gen_upcall_argument(ctx, 0));
30 if (frame_t_is_const(slot_2)) {
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 x_offs = offsetof(struct cg_upcall_vector_s, INT_binary_const_int8_t) + op_size * sizeof(void (*)(void));
39 g(gen_upcall(ctx, x_offs, 4));
40 } else if (slot_2 != NO_FRAME_T) {
41 g(gen_frame_address(ctx, slot_2, 0, R_ARG1));
42 g(gen_upcall_argument(ctx, 1));
43 g(gen_frame_address(ctx, slot_r, 0, R_ARG2));
44 g(gen_upcall_argument(ctx, 2));
45 g(gen_upcall(ctx, upcall, 3));
47 g(gen_frame_address(ctx, slot_r, 0, R_ARG1));
48 g(gen_upcall_argument(ctx, 1));
49 g(gen_upcall(ctx, upcall, 2));
51 if (slot_is_register(ctx, slot_r))
52 g(unspill(ctx, slot_r));
54 g(gen_jmp_on_zero(ctx, OP_SIZE_1, R_RET0, COND_E, label_ovf));
58 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)
60 upcall += op_size * sizeof(void (*)(void));
61 return gen_alu_upcall(ctx, upcall, op_size, slot_1, slot_2, slot_r, label_ovf);
68 #define MODE_ARRAY_LEN_GT 4
70 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)
74 unsigned reg1, reg2, reg3, target;
76 case MODE_FIXED: switch (op) {
77 case OPCODE_FIXED_OP_add: alu = ALU_ADD; goto do_alu;
78 case OPCODE_FIXED_OP_subtract: alu = ALU_SUB; goto do_alu;
79 case OPCODE_FIXED_OP_multiply: goto do_multiply;
80 case OPCODE_FIXED_OP_divide:
81 case OPCODE_FIXED_OP_divide_alt1: sgn = true; mod = false; goto do_divide;
82 case OPCODE_FIXED_OP_udivide:
83 case OPCODE_FIXED_OP_udivide_alt1: sgn = false; mod = false; goto do_divide;
84 case OPCODE_FIXED_OP_modulo:
85 case OPCODE_FIXED_OP_modulo_alt1: sgn = true; mod = true; goto do_divide;
86 case OPCODE_FIXED_OP_umodulo:
87 case OPCODE_FIXED_OP_umodulo_alt1: sgn = false; mod = true; goto do_divide;
88 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);
89 case OPCODE_FIXED_OP_and: alu = ALU_AND; goto do_alu;
90 case OPCODE_FIXED_OP_or: alu = ALU_OR; goto do_alu;
91 case OPCODE_FIXED_OP_xor: alu = ALU_XOR; goto do_alu;
92 case OPCODE_FIXED_OP_shl: alu = ROT_SHL; goto do_shift;
93 case OPCODE_FIXED_OP_shr: alu = ROT_SAR; goto do_shift;
94 case OPCODE_FIXED_OP_ushr: alu = ROT_SHR; goto do_shift;
95 case OPCODE_FIXED_OP_rol: alu = ROT_ROL; goto do_shift;
96 case OPCODE_FIXED_OP_ror: alu = ROT_ROR; goto do_shift;
97 case OPCODE_FIXED_OP_bts: alu = BTX_BTS; goto do_bt;
98 case OPCODE_FIXED_OP_btr: alu = BTX_BTR; goto do_bt;
99 case OPCODE_FIXED_OP_btc: alu = BTX_BTC; goto do_bt;
100 case OPCODE_FIXED_OP_equal: alu = COND_E; goto do_compare;
101 case OPCODE_FIXED_OP_not_equal: alu = COND_NE; goto do_compare;
102 case OPCODE_FIXED_OP_less: alu = COND_L; goto do_compare;
103 case OPCODE_FIXED_OP_less_equal: alu = COND_LE; goto do_compare;
104 case OPCODE_FIXED_OP_greater: alu = COND_G; goto do_compare;
105 case OPCODE_FIXED_OP_greater_equal: alu = COND_GE; goto do_compare;
106 case OPCODE_FIXED_OP_uless: alu = COND_B; goto do_compare;
107 case OPCODE_FIXED_OP_uless_equal: alu = COND_BE; goto do_compare;
108 case OPCODE_FIXED_OP_ugreater: alu = COND_A; goto do_compare;
109 case OPCODE_FIXED_OP_ugreater_equal: alu = COND_AE; goto do_compare;
110 case OPCODE_FIXED_OP_bt: alu = BTX_BT; goto do_bt;
111 default: internal(file_line, "gen_alu: unsupported fixed operation %u", op);
113 case MODE_INT: switch (op) {
114 case OPCODE_INT_OP_add: alu = ALU_ADD; goto do_alu;
115 case OPCODE_INT_OP_subtract: alu = ALU_SUB; goto do_alu;
116 case OPCODE_INT_OP_multiply: goto do_multiply;
117 case OPCODE_INT_OP_divide:
118 case OPCODE_INT_OP_divide_alt1: sgn = true; mod = false; goto do_divide;
119 case OPCODE_INT_OP_modulo:
120 case OPCODE_INT_OP_modulo_alt1: sgn = true; mod = true; goto do_divide;
121 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);
122 case OPCODE_INT_OP_and: alu = ALU_AND; mode = MODE_FIXED; goto do_alu;
123 case OPCODE_INT_OP_or: alu = ALU_OR; mode = MODE_FIXED; goto do_alu;
124 case OPCODE_INT_OP_xor: alu = ALU_XOR; mode = MODE_FIXED; goto do_alu;
125 case OPCODE_INT_OP_shl: alu = ROT_SHL; goto do_shift;
126 case OPCODE_INT_OP_shr: alu = ROT_SAR; goto do_shift;
127 case OPCODE_INT_OP_bts: alu = BTX_BTS; goto do_bt;
128 case OPCODE_INT_OP_btr: alu = BTX_BTR; goto do_bt;
129 case OPCODE_INT_OP_btc: alu = BTX_BTC; goto do_bt;
130 case OPCODE_INT_OP_equal: alu = COND_E; goto do_compare;
131 case OPCODE_INT_OP_not_equal: alu = COND_NE; goto do_compare;
132 case OPCODE_INT_OP_less: alu = COND_L; goto do_compare;
133 case OPCODE_INT_OP_less_equal: alu = COND_LE; goto do_compare;
134 case OPCODE_INT_OP_greater: alu = COND_G; goto do_compare;
135 case OPCODE_INT_OP_greater_equal: alu = COND_GE; goto do_compare;
136 case OPCODE_INT_OP_bt: alu = BTX_BT; goto do_bt;
137 default: internal(file_line, "gen_alu: unsupported int operation %u", op);
139 case MODE_BOOL: switch (op) {
140 case OPCODE_BOOL_OP_and: alu = ALU_AND; mode = MODE_FIXED; goto do_alu;
141 case OPCODE_BOOL_OP_or: alu = ALU_OR; mode = MODE_FIXED; goto do_alu;
142 case OPCODE_BOOL_OP_equal: alu = COND_E; goto do_compare;
143 case OPCODE_BOOL_OP_not_equal: alu = ALU_XOR; mode = MODE_FIXED; goto do_alu;
144 case OPCODE_BOOL_OP_less: alu = COND_L; goto do_compare;
145 case OPCODE_BOOL_OP_less_equal: alu = COND_LE; goto do_compare;
146 case OPCODE_BOOL_OP_greater: alu = COND_G; goto do_compare;
147 case OPCODE_BOOL_OP_greater_equal: alu = COND_GE; goto do_compare;
148 default: internal(file_line, "gen_alu: unsupported bool operation %u", op);
151 internal(file_line, "gen_alu: unsupported mode %u", mode);
157 size_t attr_unused offset;
158 uint8_t attr_unused long_imm;
159 unsigned first_flags;
160 unsigned second_flags;
162 unsigned attr_unused op_size_flags;
163 if (unlikely(op_size > OP_SIZE_NATIVE)) {
164 #if !defined(ARCH_X86) && !defined(ARCH_ARM) && !defined(ARCH_PARISC) && !defined(ARCH_POWER) && !defined(ARCH_SPARC32)
165 if (mode == MODE_FIXED) {
166 if (alu == ALU_ADD) {
167 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));
169 } else if (alu == ALU_SUB) {
170 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));
173 } else if (mode == MODE_INT) {
174 if (alu == ALU_ADD) {
175 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));
177 } else if (alu == ALU_SUB) {
178 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));
183 first_flags = alu == ALU_ADD || alu == ALU_SUB ? 2 : 0;
184 second_flags = mode == MODE_INT ? 1 : 0;
185 second_alu = alu == ALU_ADD ? ALU_ADC : alu == ALU_SUB ? ALU_SBB : alu;
186 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_1, 0, R_SCRATCH_1, R_SCRATCH_2));
187 #if defined(ARCH_X86)
188 g(gen_frame_load_op(ctx, OP_SIZE_NATIVE, garbage, alu, first_flags, slot_2, lo_word(OP_SIZE_NATIVE), true, R_SCRATCH_1));
189 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));
191 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_2, 0, R_SCRATCH_3, R_SCRATCH_4));
192 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, alu, R_SCRATCH_1, R_SCRATCH_1, R_SCRATCH_3, first_flags));
193 #if defined(ARCH_PARISC)
194 if (mode == MODE_INT) {
195 gen_insn(INSN_ALU_FLAGS_TRAP, OP_SIZE_NATIVE, second_alu, ALU_WRITES_FLAGS(second_alu, false));
196 gen_one(R_SCRATCH_2);
197 gen_one(R_SCRATCH_2);
198 gen_one(R_SCRATCH_4);
203 gen_insn(first_flags ? INSN_ALU_FLAGS : INSN_ALU, OP_SIZE_NATIVE, second_alu, second_flags | ALU_WRITES_FLAGS(second_alu, false));
204 gen_one(R_SCRATCH_2);
205 gen_one(R_SCRATCH_2);
206 gen_one(R_SCRATCH_4);
209 #if !defined(ARCH_PARISC)
210 if (mode == MODE_INT) {
211 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_O, 0);
215 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, R_SCRATCH_1, R_SCRATCH_2));
219 if ((ARCH_HAS_FLAGS || ARCH_SUPPORTS_TRAPS) && slot_2 == slot_r && slot_1 != slot_2 && alu_is_commutative(alu)) {
224 if ((ARCH_HAS_FLAGS || ARCH_SUPPORTS_TRAPS) && slot_1 == slot_r && (slot_1 != slot_2 || mode != MODE_INT) && i_size_cmp(op_size) == op_size + zero
225 #if defined(ARCH_POWER)
226 && op_size == OP_SIZE_NATIVE
230 unsigned undo_alu = alu == ALU_ADD ? ALU_SUB : ALU_ADD;
231 if (slot_is_register(ctx, slot_1)) {
232 unsigned reg1 = ctx->registers[slot_1];
233 if (slot_is_register(ctx, slot_2) || frame_t_is_const(slot_2)) {
234 unsigned reg2 = frame_t_is_const(slot_2) ? 0xff /* avoid warning */ : ctx->registers[slot_2];
235 if (mode == MODE_INT && ARCH_SUPPORTS_TRAPS) {
236 if (frame_t_is_const(slot_2))
237 g(gen_imm(ctx, frame_t_get_const(slot_2), alu_trap_purpose(alu), i_size(op_size)));
238 gen_insn(INSN_ALU_TRAP, op_size, alu, ALU_WRITES_FLAGS(alu, frame_t_is_const(slot_2) && is_imm()));
241 if (frame_t_is_const(slot_2))
245 if (ARCH_TRAP_BEFORE) {
249 ce = alloc_undo_label(ctx);
252 gen_four(ce->undo_label);
256 if (frame_t_is_const(slot_2))
257 g(gen_3address_alu_imm(ctx, i_size(op_size), alu, reg1, reg1, frame_t_get_const(slot_2), mode == MODE_INT));
259 g(gen_3address_alu(ctx, i_size(op_size), alu, reg1, reg1, reg2, mode == MODE_INT));
260 if (mode == MODE_INT) {
262 ce = alloc_undo_label(ctx);
265 gen_insn(INSN_JMP_COND, i_size_cmp(op_size), COND_O, 0);
266 gen_four(ce->undo_label);
268 ce->undo_opcode = INSN_ALU + ARCH_PARTIAL_ALU(op_size);
269 ce->undo_op_size = i_size(op_size);
270 ce->undo_aux = undo_alu;
271 ce->undo_writes_flags = ALU_WRITES_FLAGS(undo_alu, frame_t_is_const(slot_2) && is_imm());
272 m = mark_params(ctx);
275 if (frame_t_is_const(slot_2))
279 copy_params(ctx, ce, m);
283 #if defined(ARCH_S390) || defined(ARCH_X86)
284 else if (!frame_t_is_const(slot_2)) {
286 int64_t offset = (size_t)slot_2 * slot_size;
287 g(gen_address(ctx, R_FRAME, offset, IMM_PURPOSE_LDR_OFFSET, i_size(op_size)));
288 gen_insn(INSN_ALU + ARCH_PARTIAL_ALU(op_size), i_size(op_size), alu, 1);
291 gen_address_offset();
292 if (mode == MODE_INT) {
293 ce = alloc_undo_label(ctx);
296 ce->undo_opcode = INSN_ALU + ARCH_PARTIAL_ALU(op_size);
297 ce->undo_op_size = i_size(op_size);
298 ce->undo_aux = undo_alu;
299 ce->undo_writes_flags = ARCH_HAS_FLAGS;
300 m = mark_params(ctx);
303 gen_address_offset();
304 copy_params(ctx, ce, m);
305 gen_insn(INSN_JMP_COND, i_size_cmp(op_size), COND_O, 0);
306 gen_four(ce->undo_label);
312 #if defined(ARCH_X86)
316 int64_t offset = (size_t)slot_1 * slot_size;
317 if (!frame_t_is_const(slot_2))
318 g(gen_frame_get(ctx, op_size, garbage, slot_2, R_SCRATCH_1, ®2));
319 g(gen_address(ctx, R_FRAME, offset, IMM_PURPOSE_LDR_OFFSET, i_size(op_size)));
320 if (frame_t_is_const(slot_2))
321 g(gen_imm(ctx, frame_t_get_const(slot_2), alu_purpose(alu), i_size(op_size)));
322 gen_insn(INSN_ALU + ARCH_PARTIAL_ALU(op_size), i_size(op_size), alu, 1);
323 gen_address_offset();
324 gen_address_offset();
325 if (frame_t_is_const(slot_2))
329 if (mode == MODE_INT) {
330 ce = alloc_undo_label(ctx);
333 ce->undo_opcode = INSN_ALU + ARCH_PARTIAL_ALU(op_size);
334 ce->undo_op_size = i_size(op_size);
335 ce->undo_aux = undo_alu;
336 ce->undo_writes_flags = ARCH_HAS_FLAGS;
337 m = mark_params(ctx);
338 gen_address_offset();
339 gen_address_offset();
340 if (frame_t_is_const(slot_2))
344 copy_params(ctx, ce, m);
345 gen_insn(INSN_JMP_COND, i_size_cmp(op_size), COND_O, 0);
346 gen_four(ce->undo_label);
353 #if defined(ARCH_X86)
355 #elif defined(ARCH_S390)
356 if (op_size >= OP_SIZE_4)
357 #elif ARCH_HAS_FLAGS && !defined(ARCH_POWER)
358 if (op_size == i_size(op_size) + (unsigned)zero && frame_t_is_const(slot_2))
360 if (mode != MODE_INT && op_size == i_size(op_size) + (unsigned)zero && frame_t_is_const(slot_2))
363 if (mode == MODE_INT) {
364 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
366 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, slot_2, R_SCRATCH_1);
368 g(gen_frame_load(ctx, op_size, garbage, slot_1, 0, false, target));
369 g(gen_frame_load_op(ctx, op_size, garbage, alu, mode == MODE_INT, slot_2, 0, false, target));
370 goto check_ovf_store;
372 op_size_flags = !ARCH_HAS_FLAGS && !ARCH_SUPPORTS_TRAPS ? OP_SIZE_NATIVE : OP_SIZE_4;
373 #if defined(ARCH_POWER)
374 op_size_flags = OP_SIZE_NATIVE;
376 g(gen_frame_get(ctx, op_size, mode == MODE_INT && (op_size < op_size_flags || ARCH_SUPPORTS_TRAPS) ? sign_x : garbage, slot_1, R_SCRATCH_1, ®1));
377 g(gen_frame_get(ctx, op_size, mode == MODE_INT && (op_size < op_size_flags || ARCH_SUPPORTS_TRAPS) ? sign_x : garbage, slot_2, R_SCRATCH_2, ®2));
379 if (mode == MODE_INT && op_size >= OP_SIZE_4) {
380 if (ARCH_SUPPORTS_TRAPS) {
381 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
382 gen_insn(INSN_ALU_TRAP, op_size, alu, ALU_WRITES_FLAGS(alu, false));
387 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
390 if (op_size >= OP_SIZE_NATIVE) {
391 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_3);
392 g(gen_3address_alu(ctx, i_size(op_size), alu, target, reg1, reg2, 0));
393 #if defined(ARCH_IA64)
394 g(gen_3address_alu(ctx, i_size(op_size), ALU_XOR, R_SCRATCH_1, reg1, reg2, 0));
395 g(gen_3address_alu(ctx, i_size(op_size), ALU_XOR, R_SCRATCH_2, reg2, target, 0));
396 if (alu == ALU_ADD) {
397 g(gen_3address_alu(ctx, i_size(op_size), ALU_ANDN, R_SCRATCH_1, R_SCRATCH_2, R_SCRATCH_1, 0));
399 g(gen_3address_alu(ctx, i_size(op_size), ALU_ANDN, R_SCRATCH_1, R_SCRATCH_1, R_SCRATCH_2, 0));
401 g(gen_cmp_test_jmp(ctx, INSN_TEST, i_size(op_size), R_SCRATCH_1, R_SCRATCH_1, COND_S, label_ovf));
403 gen_insn(INSN_CMP_DEST_REG, i_size(op_size), COND_L, 0);
404 gen_one(R_SCRATCH_1);
405 if (alu == ALU_ADD) {
413 g(gen_imm(ctx, 0, IMM_PURPOSE_CMP, i_size(op_size)));
414 gen_insn(INSN_CMP_DEST_REG, i_size(op_size), COND_L, 0);
415 gen_one(R_SCRATCH_2);
419 g(gen_cmp_test_jmp(ctx, INSN_CMP, i_size(op_size), R_SCRATCH_1, R_SCRATCH_2, COND_NE, label_ovf));
421 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
426 if (mode == MODE_INT) {
427 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
428 } else if (!ARCH_IS_3ADDRESS(alu, mode == MODE_INT && op_size >= op_size_flags) && !alu_is_commutative(alu)) {
429 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, slot_2, R_SCRATCH_1);
431 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
433 g(gen_3address_alu(ctx, i_size(op_size), alu, target, reg1, reg2, mode == MODE_INT && op_size >= op_size_flags));
435 if (mode == MODE_INT && unlikely(op_size < op_size_flags)) {
436 g(gen_cmp_extended(ctx, op_size_flags, op_size, target, R_SCRATCH_2, label_ovf));
439 if (mode == MODE_INT) {
440 gen_insn(INSN_JMP_COND, op_size, COND_O, 0);
443 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
451 size_t attr_unused offset;
452 uint8_t attr_unused long_imm;
453 if (unlikely(op_size > OP_SIZE_NATIVE) || unlikely(!ARCH_HAS_MUL)) {
454 if (mode == MODE_INT) {
455 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));
458 #if defined(ARCH_X86)
459 g(gen_frame_load(ctx, OP_SIZE_NATIVE, garbage, slot_1, hi_word(OP_SIZE_NATIVE), true, R_CX));
460 g(gen_frame_load(ctx, OP_SIZE_NATIVE, garbage, slot_2, hi_word(OP_SIZE_NATIVE), true, R_AX));
461 g(gen_frame_load_op(ctx, OP_SIZE_NATIVE, garbage, ALU_MUL, true, slot_2, lo_word(OP_SIZE_NATIVE), true, R_CX));
462 g(gen_frame_load_op(ctx, OP_SIZE_NATIVE, garbage, ALU_MUL, true, slot_1, lo_word(OP_SIZE_NATIVE), true, R_AX));
463 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_ADD, R_CX, R_CX, R_AX, 0));
464 g(gen_frame_load(ctx, OP_SIZE_NATIVE, garbage, slot_2, lo_word(OP_SIZE_NATIVE), true, R_AX));
466 offset = (size_t)slot_1 * slot_size + lo_word(OP_SIZE_NATIVE);
467 g(gen_address(ctx, R_FRAME, offset, IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
468 gen_insn(INSN_MUL_L, OP_SIZE_NATIVE, 0, 1);
472 gen_address_offset();
474 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_ADD, R_DX, R_DX, R_CX, 0));
476 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, R_AX, R_DX));
479 #elif defined(ARCH_ARM32)
480 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_1, 0, R_SCRATCH_1, R_SCRATCH_2));
481 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_2, 0, R_SCRATCH_3, R_SCRATCH_4));
483 g(gen_mov(ctx, OP_SIZE_NATIVE, R_SCRATCH_NA_1, R_SCRATCH_1));
485 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_MUL, R_SCRATCH_4, R_SCRATCH_1, R_SCRATCH_4, 0));
487 gen_insn(INSN_MADD, OP_SIZE_NATIVE, 0, 0);
488 gen_one(R_SCRATCH_2);
489 gen_one(R_SCRATCH_3);
490 gen_one(R_SCRATCH_2);
491 gen_one(R_SCRATCH_4);
493 gen_insn(INSN_MUL_L, OP_SIZE_NATIVE, 0, 0);
494 gen_one(R_SCRATCH_1);
495 gen_one(R_SCRATCH_4);
496 gen_one(R_SCRATCH_NA_1);
497 gen_one(R_SCRATCH_3);
499 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_ADD, R_SCRATCH_2, R_SCRATCH_2, R_SCRATCH_4, 0));
501 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, R_SCRATCH_1, R_SCRATCH_2));
504 #elif defined(ARCH_ARM64)
505 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_1, 0, R_SCRATCH_1, R_SCRATCH_2));
506 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_2, 0, R_SCRATCH_3, R_SCRATCH_4));
508 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_UMULH, R_SCRATCH_NA_1, R_SCRATCH_1, R_SCRATCH_3, 0));
510 gen_insn(INSN_MADD, OP_SIZE_NATIVE, 0, 0);
511 gen_one(R_SCRATCH_NA_1);
512 gen_one(R_SCRATCH_2);
513 gen_one(R_SCRATCH_3);
514 gen_one(R_SCRATCH_NA_1);
516 gen_insn(INSN_MADD, OP_SIZE_NATIVE, 0, 0);
517 gen_one(R_SCRATCH_2);
518 gen_one(R_SCRATCH_1);
519 gen_one(R_SCRATCH_4);
520 gen_one(R_SCRATCH_NA_1);
522 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_MUL, R_SCRATCH_1, R_SCRATCH_1, R_SCRATCH_3, 0));
524 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, R_SCRATCH_1, R_SCRATCH_2));
528 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));
533 #if defined(ARCH_X86)
534 if (mode == MODE_INT) {
535 if (op_size != OP_SIZE_1 && slot_r == slot_1 && slot_is_register(ctx, slot_1)) {
537 target = ctx->registers[slot_1];
538 g(gen_mov(ctx, op_size, R_SCRATCH_1, target));
539 g(gen_frame_load_op(ctx, op_size, garbage, ALU_MUL, mode == MODE_INT, slot_2, 0, false, target));
540 ce = alloc_undo_label(ctx);
543 ce->undo_opcode = INSN_MOV;
544 ce->undo_op_size = op_size;
546 ce->undo_writes_flags = 0;
547 ce->undo_parameters[0] = target;
548 ce->undo_parameters[1] = R_SCRATCH_1;
549 ce->undo_parameters_len = 2;
550 gen_insn(INSN_JMP_COND, op_size, COND_O, 0);
551 gen_four(ce->undo_label);
554 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
556 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, slot_2, R_SCRATCH_1);
558 if (op_size == OP_SIZE_1)
559 target = R_SCRATCH_1;
560 g(gen_frame_load(ctx, op_size, garbage, slot_1, 0, false, target));
561 if (op_size == OP_SIZE_1 && frame_t_is_const(slot_2)) {
562 g(gen_load_constant(ctx, R_SCRATCH_3, frame_t_get_const(slot_2)));
563 gen_insn(INSN_ALU + ARCH_PARTIAL_ALU(op_size), op_size, ALU_MUL, 1);
566 gen_one(R_SCRATCH_3);
568 g(gen_frame_load_op(ctx, op_size, garbage, ALU_MUL, mode == MODE_INT, slot_2, 0, false, target));
570 if (mode == MODE_INT) {
571 gen_insn(INSN_JMP_COND, op_size, COND_O, 0);
574 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
577 #if defined(ARCH_ALPHA)
578 if (mode == MODE_INT && op_size >= OP_SIZE_4 && ARCH_SUPPORTS_TRAPS) {
579 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
580 g(gen_frame_get(ctx, op_size, garbage, slot_1, R_SCRATCH_1, ®1));
581 g(gen_frame_get(ctx, op_size, garbage, slot_2, R_SCRATCH_2, ®2));
583 gen_insn(INSN_ALU_TRAP, op_size, ALU_MUL, ALU_WRITES_FLAGS(ALU_MUL, false));
588 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
593 #if defined(ARCH_ARM32)
594 if (mode == MODE_INT && op_size == OP_SIZE_4) {
595 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_3);
596 g(gen_frame_get(ctx, op_size, garbage, slot_1, R_SCRATCH_1, ®1));
597 g(gen_frame_get(ctx, op_size, garbage, slot_2, R_SCRATCH_2, ®2));
599 gen_insn(INSN_MUL_L, OP_SIZE_NATIVE, 0, 0);
601 gen_one(R_SCRATCH_4);
605 gen_insn(INSN_CMP, OP_SIZE_NATIVE, 0, 1);
606 gen_one(R_SCRATCH_4);
607 gen_one(ARG_SHIFTED_REGISTER);
608 gen_one(ARG_SHIFT_ASR | 0x1f);
611 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_NE, 0);
614 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
619 #if defined(ARCH_ARM64)
620 if (mode == MODE_INT && op_size == OP_SIZE_4) {
621 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
622 g(gen_frame_get(ctx, op_size, op_size < OP_SIZE_4 ? sign_x : garbage, slot_1, R_SCRATCH_1, ®1));
623 g(gen_frame_get(ctx, op_size, op_size < OP_SIZE_4 ? sign_x : garbage, slot_2, R_SCRATCH_2, ®2));
624 gen_insn(INSN_ALU, OP_SIZE_8, ALU_MUL, ALU_WRITES_FLAGS(ALU_MUL, false));
626 gen_one(ARG_EXTENDED_REGISTER);
627 gen_one(ARG_EXTEND_SXTW);
629 gen_one(ARG_EXTENDED_REGISTER);
630 gen_one(ARG_EXTEND_SXTW);
633 gen_insn(INSN_CMP, OP_SIZE_8, 0, 1);
635 gen_one(ARG_EXTENDED_REGISTER);
636 gen_one(ARG_EXTEND_SXTW);
639 gen_insn(INSN_JMP_COND, OP_SIZE_8, COND_NE, 0);
642 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
646 if (mode == MODE_INT && op_size == OP_SIZE_8) {
647 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
648 g(gen_frame_get(ctx, op_size, garbage, slot_1, R_SCRATCH_1, ®1));
649 g(gen_frame_get(ctx, op_size, garbage, slot_2, R_SCRATCH_2, ®2));
650 g(gen_3address_alu(ctx, OP_SIZE_8, ALU_SMULH, R_SCRATCH_3, reg1, reg2, 0));
652 g(gen_3address_alu(ctx, OP_SIZE_8, ALU_MUL, target, reg1, reg2, 0));
654 gen_insn(INSN_CMP, OP_SIZE_8, 0, 1);
655 gen_one(R_SCRATCH_3);
656 gen_one(ARG_SHIFTED_REGISTER);
657 gen_one(ARG_SHIFT_ASR | 0x3f);
660 gen_insn(INSN_JMP_COND, OP_SIZE_8, COND_NE, 0);
663 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
668 #if defined(ARCH_POWER)
669 if (mode == MODE_INT && op_size >= OP_SIZE_4) {
670 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
671 g(gen_frame_get(ctx, op_size, garbage, slot_1, R_SCRATCH_1, ®1));
672 g(gen_frame_get(ctx, op_size, garbage, slot_2, R_SCRATCH_2, ®2));
674 g(gen_3address_alu(ctx, op_size, ALU_MUL, target, reg1, reg2, 1));
676 gen_insn(INSN_JMP_COND, op_size, COND_O, 0);
679 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
684 #if defined(ARCH_LOONGARCH64) || (defined(ARCH_MIPS) && MIPS_R6) || defined(ARCH_RISCV64)
685 if (mode == MODE_INT && op_size == OP_SIZE_NATIVE) {
686 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
687 g(gen_frame_get(ctx, op_size, garbage, slot_1, R_SCRATCH_1, ®1));
688 g(gen_frame_get(ctx, op_size, garbage, slot_2, R_SCRATCH_2, ®2));
690 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_SMULH, R_SCRATCH_3, reg1, reg2, 0));
692 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_MUL, target, reg1, reg2, 0));
694 g(gen_3address_rot_imm(ctx, OP_SIZE_NATIVE, ROT_SAR, R_SCRATCH_4, target, (8U << OP_SIZE_NATIVE) - 1, 0));
696 g(gen_cmp_test_jmp(ctx, INSN_CMP, OP_SIZE_NATIVE, R_SCRATCH_3, R_SCRATCH_4, COND_NE, label_ovf));
698 g(gen_frame_store(ctx, OP_SIZE_NATIVE, slot_r, 0, target));
703 #if defined(ARCH_S390)
704 if (mode == MODE_INT && op_size >= OP_SIZE_4 && likely(cpu_test_feature(CPU_FEATURE_misc_insn_ext_2))) {
705 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
706 g(gen_frame_load(ctx, op_size, sign_x, slot_1, 0, false, target));
707 g(gen_frame_load_op(ctx, op_size, sign_x, ALU_MUL, 1, slot_2, 0, false, target));
709 gen_insn(INSN_JMP_COND, op_size, COND_O, 0);
712 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
716 #if (defined(ARCH_MIPS) && !MIPS_R6) || defined(ARCH_S390)
717 #if defined(ARCH_MIPS)
718 if (mode == MODE_INT && op_size >= OP_SIZE_4)
720 #if defined(ARCH_S390)
721 if (mode == MODE_INT && op_size == OP_SIZE_4)
724 #if defined(ARCH_S390)
725 target = R_SCRATCH_1;
727 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
729 g(gen_frame_get(ctx, op_size, sign_x, slot_1, R_SCRATCH_1, ®1));
730 g(gen_frame_get(ctx, op_size, sign_x, slot_2, R_SCRATCH_3, ®2));
732 gen_insn(INSN_MUL_L, op_size, 0, 0);
734 gen_one(R_SCRATCH_2);
738 g(gen_3address_rot_imm(ctx, op_size, ROT_SAR, R_SCRATCH_4, target, (8U << op_size) - 1, false));
740 g(gen_cmp_test_jmp(ctx, INSN_CMP, op_size, R_SCRATCH_2, R_SCRATCH_4, COND_NE, label_ovf));
742 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
746 if (mode == MODE_INT && op_size == OP_SIZE_NATIVE) {
747 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));
751 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
752 if (op_size < OP_SIZE_NATIVE && mode == MODE_INT) {
753 g(gen_frame_get(ctx, op_size, sign_x, slot_1, R_SCRATCH_1, ®1));
754 g(gen_frame_get(ctx, op_size, sign_x, slot_2, R_SCRATCH_2, ®2));
756 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_MUL, target, reg1, reg2, 0));
758 g(gen_frame_load(ctx, op_size, sign_x, slot_1, 0, false, target));
759 g(gen_frame_load_op(ctx, op_size, sign_x, ALU_MUL, 0, slot_2, 0, false, target));
762 if (mode == MODE_INT) {
763 g(gen_cmp_extended(ctx, OP_SIZE_NATIVE, op_size, target, R_SCRATCH_2, label_ovf));
766 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
775 uint32_t attr_unused label_skip = 0; /* avoid warning */
776 uint32_t attr_unused label_skip2 = 0; /* avoid warning */
777 uint32_t attr_unused label_end = 0; /* avoid warning */
778 uint32_t attr_unused label_div_0 = 0; /* avoid warning */
779 unsigned attr_unused divide_alu = 0; /* avoid warning */
780 bool attr_unused have_mod = false;
781 bool attr_unused force_sx = false;
782 unsigned attr_unused div_op_size = i_size(op_size);
783 if (unlikely(op_size > OP_SIZE_NATIVE) || unlikely(!ARCH_HAS_DIV)
784 #if defined(ARCH_S390)
785 || !(Z || (op_size <= OP_SIZE_4 && sgn))
789 if (mode == MODE_INT) {
790 upcall = !mod ? offsetof(struct cg_upcall_vector_s, INT_binary_divide_int8_t) : offsetof(struct cg_upcall_vector_s, INT_binary_modulo_int8_t);
792 upcall = !mod ? offsetof(struct cg_upcall_vector_s, FIXED_binary_divide_int8_t) : offsetof(struct cg_upcall_vector_s, FIXED_binary_modulo_int8_t);
794 upcall = !mod ? offsetof(struct cg_upcall_vector_s, FIXED_binary_udivide_int8_t) : offsetof(struct cg_upcall_vector_s, FIXED_binary_umodulo_int8_t);
796 g(gen_alu_typed_upcall(ctx, upcall, op_size, slot_1, slot_2, slot_r, mode == MODE_INT ? label_ovf : 0));
799 #if defined(ARCH_X86) || defined(ARCH_S390)
800 if (mode == MODE_FIXED) {
801 label_skip = alloc_label(ctx);
802 if (unlikely(!label_skip))
804 label_end = alloc_label(ctx);
805 if (unlikely(!label_end))
808 label_skip2 = alloc_label(ctx);
809 if (unlikely(!label_skip2))
813 #if defined(ARCH_X86)
814 if (R_SCRATCH_1 != R_AX || R_SCRATCH_2 != R_DX || R_SCRATCH_3 != R_CX)
815 internal(file_line, "gen_alu: bad scratch registers");
817 g(gen_frame_load(ctx, op_size, sgn ? sign_x : zero_x, slot_1, 0, false, R_SCRATCH_1));
818 g(gen_frame_load(ctx, op_size, sgn ? sign_x : zero_x, slot_2, 0, false, R_SCRATCH_3));
820 g(gen_jmp_on_zero(ctx, i_size(op_size), R_SCRATCH_3, COND_E, mode == MODE_INT ? label_ovf : label_skip));
824 uint32_t label_not_minus_1;
825 label_not_minus_1 = alloc_label(ctx);
826 if (unlikely(!label_not_minus_1))
829 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, op_size, R_SCRATCH_3, -1, COND_NE, label_not_minus_1));
831 val = -(uint64_t)0x80 << (((1 << op_size) - 1) * 8);
832 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, op_size, R_SCRATCH_1, val, COND_E, mode == MODE_INT ? label_ovf : label_skip2));
834 gen_label(label_not_minus_1);
837 #if defined(ARCH_X86)
838 if (op_size >= OP_SIZE_2) {
840 gen_insn(INSN_CWD + ARCH_PARTIAL_ALU(op_size), op_size, 0, 0);
841 gen_one(R_SCRATCH_2);
842 gen_one(R_SCRATCH_1);
843 if (op_size == OP_SIZE_2)
844 gen_one(R_SCRATCH_2);
846 g(gen_3address_alu(ctx, OP_SIZE_4, ALU_XOR, R_SCRATCH_2, R_SCRATCH_2, R_SCRATCH_2, 0));
849 gen_insn(INSN_DIV_L, op_size, sgn, 1);
850 gen_one(R_SCRATCH_1);
851 gen_one(i_size(op_size) == OP_SIZE_1 ? R_SCRATCH_1 : R_SCRATCH_2);
852 gen_one(R_SCRATCH_1);
853 gen_one(i_size(op_size) == OP_SIZE_1 ? R_SCRATCH_1 : R_SCRATCH_2);
854 gen_one(R_SCRATCH_3);
857 g(gen_load_constant(ctx, R_SCRATCH_2, 0));
858 } else if (op_size <= OP_SIZE_4) {
859 g(gen_3address_rot_imm(ctx, OP_SIZE_NATIVE, ROT_SAR, R_SCRATCH_2, R_SCRATCH_1, (1U << (OP_SIZE_NATIVE + 3)) - 1, false));
861 gen_insn(INSN_DIV_L, i_size(op_size), sgn, 1);
862 gen_one(R_SCRATCH_2);
863 gen_one(R_SCRATCH_1);
864 gen_one(R_SCRATCH_2);
865 gen_one(R_SCRATCH_1);
866 gen_one(R_SCRATCH_3);
868 if (mod && i_size(op_size) == OP_SIZE_1) {
869 g(gen_3address_rot_imm(ctx, OP_SIZE_2, ROT_SHR, R_SCRATCH_1, R_SCRATCH_1, 8, 0));
870 g(gen_frame_store(ctx, op_size, slot_r, 0, R_SCRATCH_1));
872 g(gen_frame_store(ctx, op_size, slot_r, 0, R_SCRATCH_2));
874 g(gen_frame_store(ctx, op_size, slot_r, 0, R_SCRATCH_1));
876 if (mode == MODE_FIXED) {
877 gen_insn(INSN_JMP, 0, 0, 0);
881 gen_label(label_skip2);
884 g(gen_frame_clear(ctx, op_size, slot_r));
886 g(gen_frame_store(ctx, op_size, slot_r, 0, R_SCRATCH_1));
888 gen_insn(INSN_JMP, 0, 0, 0);
892 gen_label(label_skip);
894 g(gen_frame_clear(ctx, op_size, slot_r));
896 g(gen_frame_store(ctx, op_size, slot_r, 0, R_SCRATCH_1));
897 gen_label(label_end);
901 #if defined(ARCH_MIPS)
903 div_op_size = maximum(op_size, OP_SIZE_4);
904 if (op_size == OP_SIZE_4)
907 #if defined(ARCH_POWER)
908 have_mod = cpu_test_feature(CPU_FEATURE_v30);
909 div_op_size = maximum(op_size, OP_SIZE_4);
911 #if defined(ARCH_LOONGARCH64) || defined(ARCH_RISCV64)
913 div_op_size = maximum(op_size, OP_SIZE_4);
915 label_end = alloc_label(ctx);
916 if (unlikely(!label_end))
919 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));
920 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));
921 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_3);
923 if (ARCH_PREFERS_SX(op_size) && !sgn && op_size < i_size(op_size)) {
924 g(gen_extend(ctx, op_size, zero_x, R_SCRATCH_1, reg1));
926 g(gen_extend(ctx, op_size, zero_x, R_SCRATCH_2, reg2));
930 if (mode == MODE_INT) {
931 g(gen_jmp_on_zero(ctx, i_size(op_size), reg2, COND_E, label_ovf));
934 uint32_t label_not_minus_1;
935 label_not_minus_1 = alloc_label(ctx);
936 if (unlikely(!label_not_minus_1))
939 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, i_size(op_size), reg2, -1, COND_NE, label_not_minus_1));
941 val = 0xFFFFFFFFFFFFFF80ULL << (((1 << op_size) - 1) * 8);
942 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, i_size(op_size), reg1, val, COND_E, label_ovf));
944 gen_label(label_not_minus_1);
947 #if !(defined(ARCH_ARM) && ARM_ASM_DIV_NO_TRAP)
949 g(gen_load_constant(ctx, target, 0));
951 g(gen_mov(ctx, OP_SIZE_NATIVE, target, reg1));
953 g(gen_jmp_on_zero(ctx, i_size(op_size), reg2, COND_E, label_end));
956 uint32_t label_not_minus_1;
957 label_not_minus_1 = alloc_label(ctx);
958 if (unlikely(!label_not_minus_1))
961 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, i_size(op_size), reg2, -1, COND_NE, label_not_minus_1));
964 g(gen_mov(ctx, OP_SIZE_NATIVE, target, reg1));
966 g(gen_load_constant(ctx, target, 0));
969 val = 0xFFFFFFFFFFFFFF80ULL << (((1 << op_size) - 1) * 8);
970 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, i_size(op_size), reg1, val, COND_E, label_end));
972 gen_label(label_not_minus_1);
976 if (mod && have_mod) {
977 g(gen_3address_alu(ctx, div_op_size, sgn ? ALU_SREM : ALU_UREM, target, reg1, reg2, 0));
979 g(gen_3address_alu(ctx, div_op_size, sgn ? ALU_SDIV : ALU_UDIV, target, reg1, reg2, 0));
982 if (mod && !have_mod) {
983 #if defined(ARCH_ARM)
984 gen_insn(INSN_MADD, i_size(op_size), 1, 0);
990 g(gen_3address_alu(ctx, i_size(op_size), ALU_MUL, R_SCRATCH_2, reg2, target, 0));
991 g(gen_3address_alu(ctx, i_size(op_size), ALU_SUB, target, reg1, R_SCRATCH_2, 0));
995 gen_label(label_end);
996 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1007 int64_t cnst = 0; /* avoid warning */
1008 bool c = frame_t_is_const(slot_2);
1009 if (unlikely(op_size > OP_SIZE_NATIVE)) {
1011 if (mode == MODE_FIXED) {
1013 case ROT_SHL: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_shl_,TYPE_INT_MAX));
1015 case ROT_SAR: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_shr_,TYPE_INT_MAX));
1017 case ROT_SHR: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_ushr_,TYPE_INT_MAX));
1019 case ROT_ROL: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_rol_,TYPE_INT_MAX));
1021 case ROT_ROR: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_ror_,TYPE_INT_MAX));
1023 default: internal(file_line, "do_alu: invalid shift %u", alu);
1027 case ROT_SHL: upcall = offsetof(struct cg_upcall_vector_s, cat(INT_binary_shl_,TYPE_INT_MAX));
1029 case ROT_SAR: upcall = offsetof(struct cg_upcall_vector_s, cat(INT_binary_shr_,TYPE_INT_MAX));
1031 default: internal(file_line, "do_alu: invalid shift %u", alu);
1034 g(gen_alu_upcall(ctx, upcall, op_size, slot_1, slot_2, slot_r, mode == MODE_INT ? label_ovf : 0));
1037 op_s = i_size_rot(op_size);
1038 #if defined(ARCH_X86)
1039 if (slot_1 == slot_r && !slot_is_register(ctx, slot_1) && !(mode == MODE_INT && alu == ROT_SHL)) {
1040 int64_t offset = (size_t)slot_1 * slot_size;
1042 cnst = frame_t_get_const(slot_2);
1043 if (mode == MODE_INT) {
1044 if ((uint64_t)cnst > (8U << op_size) - 1) {
1045 gen_insn(INSN_JMP, 0, 0, 0);
1046 gen_four(label_ovf);
1050 cnst &= (8U << op_size) - 1;
1052 g(gen_address(ctx, R_FRAME, offset, IMM_PURPOSE_LDR_OFFSET, op_size));
1053 gen_insn(INSN_ROT + ARCH_PARTIAL_ALU(op_size), op_size, alu, 1);
1054 gen_address_offset();
1055 gen_address_offset();
1059 g(gen_frame_load(ctx, op_size, garbage, slot_2, 0, false, R_SCRATCH_3));
1060 if (mode == MODE_INT) {
1061 int64_t imm = (8U << op_size) - 1;
1062 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, op_size, R_SCRATCH_3, imm, COND_A, label_ovf));
1063 } else if ((alu != ROT_ROL && alu != ROT_ROR) && op_size < OP_SIZE_4) {
1064 g(gen_3address_alu_imm(ctx, OP_SIZE_1, ALU_AND, R_SCRATCH_3, R_SCRATCH_3, (8U << op_size) - 1, 0));
1066 g(gen_address(ctx, R_FRAME, offset, IMM_PURPOSE_LDR_OFFSET, op_size));
1067 gen_insn(INSN_ROT + ARCH_PARTIAL_ALU(op_size), op_size, alu, 1);
1068 gen_address_offset();
1069 gen_address_offset();
1070 gen_one(R_SCRATCH_3);
1074 if (mode == MODE_INT && alu == ROT_SHL && op_size < OP_SIZE_NATIVE)
1077 must_mask = op_size < ARCH_SHIFT_SIZE;
1078 sx = (alu == ROT_SAR && op_size < op_s) || (alu == ROT_SHL && op_size < OP_SIZE_NATIVE && mode == MODE_INT);
1079 #if defined(ARCH_MIPS)
1080 sx |= op_size == OP_SIZE_4;
1082 g(gen_frame_get(ctx, op_size, sx ? sign_x : zero_x, slot_1, R_SCRATCH_1, ®1));
1084 reg3 = 0xff; /* avoid warning */
1085 cnst = frame_t_get_const(slot_2);
1087 #if defined(ARCH_X86)
1088 if (!ARCH_IS_3ADDRESS_ROT(alu, op_size)) {
1089 g(gen_frame_load(ctx, op_size, garbage, slot_2, 0, false, R_SCRATCH_3));
1093 g(gen_frame_get(ctx, op_size, garbage, slot_2, R_SCRATCH_3, ®3));
1095 if (ARCH_PREFERS_SX(op_size) && !sx && op_size < op_s) {
1096 g(gen_extend(ctx, op_size, zero_x, R_SCRATCH_1, reg1));
1100 if (mode == MODE_INT) {
1101 int64_t imm = (8U << op_size) - 1;
1103 if ((uint64_t)cnst > (uint64_t)imm) {
1104 gen_insn(INSN_JMP, 0, 0, 0);
1105 gen_four(label_ovf);
1109 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, i_size_cmp(op_size), reg3, imm, COND_A, label_ovf));
1112 #if defined(ARCH_ARM)
1113 if (alu == ROT_ROL) {
1115 cnst = -(uint64_t)cnst;
1117 g(gen_2address_alu1(ctx, OP_SIZE_4, ALU1_NEG, R_SCRATCH_3, reg3, 0));
1123 #if defined(ARCH_LOONGARCH64)
1124 if (alu == ROT_ROL && op_size >= OP_SIZE_4) {
1126 cnst = -(uint64_t)cnst;
1128 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_NEG, R_SCRATCH_3, reg3, 0));
1134 #if defined(ARCH_MIPS)
1135 if (MIPS_HAS_ROT && alu == ROT_ROL && op_size >= OP_SIZE_4) {
1137 cnst = -(uint64_t)cnst;
1139 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_NEG, R_SCRATCH_3, reg3, 0));
1145 #if defined(ARCH_POWER)
1146 if (alu == ROT_ROR && op_size >= OP_SIZE_4) {
1148 cnst = -(uint64_t)cnst;
1150 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_NEG, R_SCRATCH_3, reg3, 0));
1156 #if defined(ARCH_S390)
1157 if (Z && alu == ROT_ROR && op_size >= OP_SIZE_4) {
1159 cnst = -(uint64_t)cnst;
1161 g(gen_2address_alu1(ctx, OP_SIZE_4, ALU1_NEG, R_SCRATCH_3, reg3, 0));
1168 cnst &= (8U << op_size) - 1;
1169 } else if (must_mask) {
1170 g(gen_3address_alu_imm(ctx, i_size(OP_SIZE_4), ALU_AND, R_SCRATCH_3, reg3, (8U << op_size) - 1, 0));
1175 #if defined(ARCH_X86)
1176 if (mode == MODE_INT && alu == ROT_SHL) {
1177 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_2);
1179 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, slot_2, R_SCRATCH_2);
1182 g(gen_3address_rot_imm(ctx, op_s, alu, target, reg1, cnst, 0));
1184 g(gen_3address_rot(ctx, op_s, alu, target, reg1, reg3));
1187 if (mode == MODE_INT && alu == ROT_SHL) {
1188 if (op_size < OP_SIZE_NATIVE) {
1189 gen_insn(INSN_MOVSX, op_size, 0, 0);
1190 gen_one(R_SCRATCH_4);
1193 g(gen_cmp_test_jmp(ctx, INSN_CMP, op_s, target, R_SCRATCH_4, COND_NE, label_ovf));
1196 g(gen_3address_rot_imm(ctx, OP_SIZE_NATIVE, ROT_SAR, R_SCRATCH_4, target, cnst, 0));
1198 g(gen_3address_rot(ctx, OP_SIZE_NATIVE, ROT_SAR, R_SCRATCH_4, target, reg3));
1201 g(gen_cmp_test_jmp(ctx, INSN_CMP, OP_SIZE_NATIVE, reg1, R_SCRATCH_4, COND_NE, label_ovf));
1204 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1207 #if defined(ARCH_ARM)
1208 if (op_size <= OP_SIZE_2 && alu == ROT_ROR) {
1209 gen_insn(INSN_ALU, OP_SIZE_4, ALU_OR, ALU_WRITES_FLAGS(ALU_OR, false));
1210 gen_one(R_SCRATCH_1);
1212 gen_one(ARG_SHIFTED_REGISTER);
1213 gen_one(ARG_SHIFT_LSL | (8U << op_size));
1215 if (op_size == OP_SIZE_1)
1219 goto do_generic_shift;
1221 #if defined(ARCH_LOONGARCH64)
1222 if (alu == ROT_ROR && op_size >= OP_SIZE_4)
1223 goto do_generic_shift;
1225 #if defined(ARCH_MIPS)
1226 if (MIPS_HAS_ROT && alu == ROT_ROR && op_size >= OP_SIZE_4)
1227 goto do_generic_shift;
1229 #if defined(ARCH_POWER)
1230 if (alu == ROT_ROL && op_size >= OP_SIZE_4)
1231 goto do_generic_shift;
1233 #if defined(ARCH_RISCV64)
1234 if ((alu == ROT_ROL || alu == ROT_ROR) && likely(cpu_test_feature(CPU_FEATURE_zbb))) {
1235 if (likely(op_size >= OP_SIZE_4)) {
1236 goto do_generic_shift;
1240 #if defined(ARCH_S390)
1241 if (Z && alu == ROT_ROL && op_size >= OP_SIZE_4)
1242 goto do_generic_shift;
1244 if (alu == ROT_ROL || alu == ROT_ROR) {
1245 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
1247 g(gen_3address_rot_imm(ctx, op_s, alu == ROT_ROL ? ROT_SHL : ROT_SHR, R_SCRATCH_2, reg1, cnst, 0));
1248 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));
1250 g(gen_3address_rot(ctx, op_s, alu == ROT_ROL ? ROT_SHL : ROT_SHR, R_SCRATCH_2, reg1, reg3));
1251 g(gen_2address_alu1(ctx, i_size(OP_SIZE_4), ALU1_NEG, R_SCRATCH_3, reg3, 0));
1253 g(gen_3address_alu_imm(ctx, i_size(OP_SIZE_4), ALU_AND, R_SCRATCH_3, R_SCRATCH_3, (8U << op_size) - 1, 0));
1255 g(gen_3address_rot(ctx, op_s, alu == ROT_ROL ? ROT_SHR : ROT_SHL, target, reg1, R_SCRATCH_3));
1257 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_OR, target, target, R_SCRATCH_2, 0));
1258 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1262 goto do_generic_shift;
1264 if (mode == MODE_INT && alu == ROT_SHL) {
1265 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
1266 #if defined(ARCH_S390)
1267 if (op_size >= OP_SIZE_4) {
1269 g(gen_3address_rot_imm(ctx, op_size, ROT_SAL, target, reg1, cnst, 0));
1271 g(gen_3address_rot(ctx, op_size, ROT_SAL, target, reg1, reg3));
1273 gen_insn(INSN_JMP_COND, op_size, COND_O, 0);
1274 gen_four(label_ovf);
1277 if (op_size <= OP_SIZE_NATIVE - 1) {
1279 g(gen_3address_rot_imm(ctx, OP_SIZE_NATIVE, alu, target, reg1, cnst, 0));
1281 g(gen_3address_rot(ctx, OP_SIZE_NATIVE, alu, target, reg1, reg3));
1283 g(gen_cmp_extended(ctx, OP_SIZE_NATIVE, op_size, target, R_SCRATCH_2, label_ovf));
1286 g(gen_3address_rot_imm(ctx, OP_SIZE_NATIVE, alu, R_SCRATCH_2, reg1, cnst, 0));
1287 g(gen_3address_rot_imm(ctx, OP_SIZE_NATIVE, ROT_SAR, R_SCRATCH_4, R_SCRATCH_2, cnst, 0));
1289 g(gen_3address_rot(ctx, OP_SIZE_NATIVE, alu, R_SCRATCH_2, reg1, reg3));
1290 g(gen_3address_rot(ctx, OP_SIZE_NATIVE, ROT_SAR, R_SCRATCH_4, R_SCRATCH_2, reg3));
1293 g(gen_cmp_test_jmp(ctx, INSN_CMP, OP_SIZE_NATIVE, reg1, R_SCRATCH_4, COND_NE, label_ovf));
1295 g(gen_frame_store(ctx, op_size, slot_r, 0, R_SCRATCH_2));
1300 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, slot_2, R_SCRATCH_1);
1302 g(gen_3address_rot_imm(ctx, op_s, alu, target, reg1, cnst, 0));
1304 g(gen_3address_rot(ctx, op_s, alu, target, reg1, reg3));
1307 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1314 unsigned attr_unused op_s;
1316 bool c = frame_t_is_const(slot_2);
1317 int64_t cnst = !c ? 0 : frame_t_get_const(slot_2);
1318 int64_t max_imm = (8U << op_size) - 1;
1320 if (mode == MODE_INT) {
1321 if (alu == BTX_BT ? (uint64_t)cnst > (uint64_t)max_imm : (uint64_t)cnst >= (uint64_t)max_imm) {
1322 gen_insn(INSN_JMP, 0, 0, 0);
1323 gen_four(label_ovf);
1329 #if defined(ARCH_X86)
1330 if ((alu == BTX_BT || slot_1 == slot_r) && !slot_is_register(ctx, slot_1)) {
1332 unsigned n_op_size = minimum(op_size, OP_SIZE_NATIVE);
1333 g(gen_frame_get(ctx, n_op_size, garbage, slot_2, R_SCRATCH_1, ®2));
1334 if (mode == MODE_INT) {
1336 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, n_op_size, reg2, max_imm, alu == BTX_BT ? COND_A : COND_AE, label_ovf));
1337 if (unlikely(op_size > OP_SIZE_NATIVE)) {
1338 g(gen_address(ctx, R_FRAME, (size_t)slot_2 * slot_size + hi_word(OP_SIZE_NATIVE), IMM_PURPOSE_STR_OFFSET, OP_SIZE_NATIVE));
1339 gen_insn(INSN_CMP, OP_SIZE_NATIVE, 0, 1);
1340 gen_address_offset();
1343 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_NE, 0);
1344 gen_four(label_ovf);
1349 g(gen_3address_alu_imm(ctx, OP_SIZE_4, ALU_AND, R_SCRATCH_1, reg2, (8U << op_size) - 1, 0));
1353 offset = (size_t)slot_1 * slot_size;
1354 if (c && cnst >= 8U << OP_SIZE_NATIVE) {
1355 offset += 1U << OP_SIZE_NATIVE;
1356 cnst -= 8U << OP_SIZE_NATIVE;
1358 g(gen_address(ctx, R_FRAME, offset, IMM_PURPOSE_STR_OFFSET, maximum(n_op_size, OP_SIZE_2)));
1359 if (alu == BTX_BT) {
1360 gen_insn(INSN_BT, maximum(n_op_size, OP_SIZE_2), 0, 1);
1361 gen_address_offset();
1368 g(gen_frame_set_cond(ctx, maximum(n_op_size, OP_SIZE_2), false, COND_B, slot_r));
1370 gen_insn(INSN_BTX, maximum(n_op_size, OP_SIZE_2), alu, 1);
1371 gen_address_offset();
1372 gen_address_offset();
1383 if (unlikely(op_size > OP_SIZE_NATIVE)) {
1385 if (mode == MODE_FIXED) {
1387 case BTX_BTS: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_bts_,TYPE_INT_MAX));
1389 case BTX_BTR: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_btr_,TYPE_INT_MAX));
1391 case BTX_BTC: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_btc_,TYPE_INT_MAX));
1393 case BTX_BT: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_bt_,TYPE_INT_MAX));
1395 default: internal(file_line, "do_alu: invalid bit test %u", alu);
1399 case BTX_BTS: upcall = offsetof(struct cg_upcall_vector_s, cat(INT_binary_bts_,TYPE_INT_MAX));
1401 case BTX_BTR: upcall = offsetof(struct cg_upcall_vector_s, cat(INT_binary_btr_,TYPE_INT_MAX));
1403 case BTX_BTC: upcall = offsetof(struct cg_upcall_vector_s, cat(INT_binary_btc_,TYPE_INT_MAX));
1405 case BTX_BT: upcall = offsetof(struct cg_upcall_vector_s, cat(INT_binary_bt_,TYPE_INT_MAX));
1407 default: internal(file_line, "do_alu: invalid bit test %u", alu);
1410 g(gen_alu_upcall(ctx, upcall, op_size, slot_1, slot_2, slot_r, label_ovf));
1413 op_s = minimum(OP_SIZE_NATIVE, ARCH_SHIFT_SIZE);
1414 op_s = maximum(op_s, op_size);
1415 g(gen_frame_get(ctx, op_size, zero_x, slot_1, R_SCRATCH_1, ®1));
1417 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
1418 if (ARCH_HAS_BTX(alu == BTX_BT ? BTX_BTEXT : alu, OP_SIZE_NATIVE, true)) {
1420 g(gen_mov(ctx, OP_SIZE_NATIVE, target, reg1));
1422 gen_insn(INSN_BTX, OP_SIZE_NATIVE, alu == BTX_BT ? BTX_BTEXT : alu, 1);
1424 gen_insn(INSN_BTX, OP_SIZE_NATIVE, alu == BTX_BT ? BTX_BTEXT : alu, 0);
1430 } else switch (alu) {
1432 g(gen_3address_alu_imm(ctx, i_size(op_size), ALU_OR, target, reg1, 1ULL << cnst, 0));
1435 g(gen_3address_alu_imm(ctx, i_size(op_size), ALU_AND, target, reg1, ~(1ULL << cnst), 0));
1438 g(gen_3address_alu_imm(ctx, i_size(op_size), ALU_XOR, target, reg1, 1ULL << cnst, 0));
1442 g(gen_3address_rot_imm(ctx, i_size(op_size), ROT_SHR, target, reg1, cnst, 0));
1444 g(gen_3address_alu_imm(ctx, i_size(op_size), ALU_AND, target, target, 1, 0));
1447 internal(file_line, "do_alu: invalid bit test %u", alu);
1450 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, target));
1452 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1455 g(gen_frame_get(ctx, op_size, garbage, slot_2, R_SCRATCH_2, ®2));
1456 if (mode == MODE_INT) {
1458 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));
1460 if (alu != BTX_BT) {
1461 if (!ARCH_HAS_BTX(alu, OP_SIZE_NATIVE, false))
1463 need_mask = !ARCH_HAS_BTX(alu, op_size, false);
1465 #if defined(ARCH_X86)
1466 need_mask = op_size < OP_SIZE_2;
1468 if (!ARCH_HAS_BTX(BTX_BTEXT, OP_SIZE_NATIVE, false))
1470 need_mask = !ARCH_HAS_BTX(BTX_BTEXT, op_size, false);
1474 g(gen_3address_alu_imm(ctx, OP_SIZE_4, ALU_AND, R_SCRATCH_2, reg2, (8U << op_size) - 1, 0));
1477 if (alu == BTX_BT) {
1478 #if defined(ARCH_X86)
1479 gen_insn(INSN_BT, maximum(op_size, OP_SIZE_2), 0, 1);
1483 g(gen_frame_set_cond(ctx, maximum(op_size, OP_SIZE_2), false, COND_B, slot_r));
1485 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
1486 gen_insn(INSN_BTX, need_mask ? OP_SIZE_NATIVE : op_size, BTX_BTEXT, 0);
1491 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, target));
1494 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, slot_2, R_SCRATCH_1);
1495 #if defined(ARCH_X86)
1497 target = R_SCRATCH_1;
1498 if (target != reg1) {
1499 g(gen_mov(ctx, op_size, target, reg1));
1502 gen_insn(INSN_BTX, maximum(op_size, OP_SIZE_2), alu, 1);
1504 gen_insn(INSN_BTX, need_mask ? OP_SIZE_NATIVE : op_size, alu, 0);
1510 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1516 if (mode == MODE_FIXED && op_size < ARCH_SHIFT_SIZE) {
1517 g(gen_3address_alu_imm(ctx, i_size(OP_SIZE_4), ALU_AND, R_SCRATCH_2, reg2, (8U << op_size) - 1, 0));
1520 g(gen_load_constant(ctx, R_SCRATCH_3, 1));
1522 g(gen_3address_rot(ctx, op_s, ROT_SHL, R_SCRATCH_3, R_SCRATCH_3, reg2));
1527 #if defined(ARCH_S390) || defined(ARCH_POWER)
1528 g(gen_3address_alu(ctx, i_size(op_size), ALU_AND, R_SCRATCH_1, reg1, R_SCRATCH_3, 1));
1530 gen_insn(INSN_TEST, i_size(op_size), 0, 1);
1532 gen_one(R_SCRATCH_3);
1534 g(gen_frame_set_cond(ctx, i_size_cmp(op_size), false, COND_NE, slot_r));
1536 g(gen_3address_alu(ctx, i_size(op_size), ALU_AND, R_SCRATCH_1, reg1, R_SCRATCH_3, 0));
1537 g(gen_frame_cmp_imm_set_cond_reg(ctx, i_size(op_size), R_SCRATCH_1, 0, COND_NE, slot_r));
1541 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
1542 g(gen_3address_alu(ctx, i_size(op_size), ALU_OR, target, reg1, R_SCRATCH_3, 0));
1545 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
1546 if (!ARCH_HAS_ANDN) {
1547 g(gen_3address_alu_imm(ctx, i_size(op_size), ALU_XOR, R_SCRATCH_3, R_SCRATCH_3, -1, 0));
1549 g(gen_3address_alu(ctx, i_size(op_size), ALU_AND, target, reg1, R_SCRATCH_3, 0));
1552 g(gen_3address_alu(ctx, i_size(op_size), ALU_ANDN, target, reg1, R_SCRATCH_3, 0));
1555 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
1556 g(gen_3address_alu(ctx, i_size(op_size), ALU_XOR, target, reg1, R_SCRATCH_3, 0));
1559 internal(file_line, "gen_alu: unsupported bit test %u", alu);
1562 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1570 if (unlikely(op_size > OP_SIZE_NATIVE)) {
1571 size_t attr_unused upcall;
1572 frame_t attr_unused swap;
1576 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_1, 0, R_SCRATCH_1, R_SCRATCH_2));
1577 g(gen_frame_load_op(ctx, OP_SIZE_NATIVE, garbage, ALU_XOR, 0, slot_2, lo_word(OP_SIZE_NATIVE), true, R_SCRATCH_1));
1578 g(gen_frame_load_op(ctx, OP_SIZE_NATIVE, garbage, ALU_XOR, 0, slot_2, hi_word(OP_SIZE_NATIVE), true, R_SCRATCH_2));
1579 #if defined(ARCH_ARM64)
1580 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_OR, R_SCRATCH_1, R_SCRATCH_1, R_SCRATCH_2, 0));
1582 gen_insn(INSN_CMP, OP_SIZE_NATIVE, 0, 1);
1583 gen_one(R_SCRATCH_1);
1587 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_OR, R_SCRATCH_1, R_SCRATCH_1, R_SCRATCH_2, ARCH_HAS_FLAGS));
1590 g(gen_frame_set_cond(ctx, OP_SIZE_NATIVE, false, alu, slot_r));
1592 g(gen_frame_cmp_imm_set_cond_reg(ctx, OP_SIZE_NATIVE, R_SCRATCH_1, 0, alu, slot_r));
1595 #if defined(ARCH_X86_64) || defined(ARCH_X86_X32) || defined(ARCH_ARM)
1598 swap = slot_1; slot_1 = slot_2; slot_2 = swap;
1599 alu = alu == COND_G ? COND_L : COND_B;
1603 g(gen_frame_load(ctx, OP_SIZE_NATIVE, garbage, slot_2, lo_word(OP_SIZE_NATIVE), true, R_SCRATCH_2));
1604 g(gen_frame_load(ctx, OP_SIZE_NATIVE, garbage, slot_1, hi_word(OP_SIZE_NATIVE), true, R_SCRATCH_1));
1605 g(gen_frame_load_cmp(ctx, OP_SIZE_NATIVE, false, garbage, true, slot_1, lo_word(OP_SIZE_NATIVE), true, R_SCRATCH_2));
1606 g(gen_frame_load_op(ctx, OP_SIZE_NATIVE, garbage, ALU_SBB, 1, slot_2, hi_word(OP_SIZE_NATIVE), true, R_SCRATCH_1));
1607 g(gen_frame_set_cond(ctx, OP_SIZE_NATIVE, false, alu, slot_r));
1611 swap = slot_1; slot_1 = slot_2; slot_2 = swap;
1612 alu = alu == COND_GE ? COND_LE : COND_BE;
1616 g(gen_frame_load(ctx, OP_SIZE_NATIVE, garbage, slot_1, lo_word(OP_SIZE_NATIVE), true, R_SCRATCH_2));
1617 g(gen_frame_load(ctx, OP_SIZE_NATIVE, garbage, slot_2, hi_word(OP_SIZE_NATIVE), true, R_SCRATCH_1));
1618 g(gen_frame_load_cmp(ctx, OP_SIZE_NATIVE, false, garbage, true, slot_2, lo_word(OP_SIZE_NATIVE), true, R_SCRATCH_2));
1619 g(gen_frame_load_op(ctx, OP_SIZE_NATIVE, garbage, ALU_SBB, 1, slot_1, hi_word(OP_SIZE_NATIVE), true, R_SCRATCH_1));
1620 g(gen_frame_set_cond(ctx, OP_SIZE_NATIVE, false, alu == COND_LE ? COND_GE : COND_AE, slot_r));
1623 case COND_L: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_less_,TYPE_INT_MAX)); goto do_upcall;
1624 case COND_LE: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_less_equal_,TYPE_INT_MAX)); goto do_upcall;
1625 case COND_G: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_greater_,TYPE_INT_MAX)); goto do_upcall;
1626 case COND_GE: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_greater_equal_,TYPE_INT_MAX)); goto do_upcall;
1627 case COND_B: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_uless_,TYPE_INT_MAX)); goto do_upcall;
1628 case COND_BE: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_uless_equal_,TYPE_INT_MAX)); goto do_upcall;
1629 case COND_A: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_ugreater_,TYPE_INT_MAX)); goto do_upcall;
1630 case COND_AE: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_ugreater_equal_,TYPE_INT_MAX)); goto do_upcall;
1631 do_upcall: g(gen_alu_upcall(ctx, upcall, op_size, slot_1, slot_2, slot_r, 0));
1635 internal(file_line, "gen_alu: unsupported condition %u", alu);
1639 #if defined(ARCH_X86)
1640 g(gen_frame_get(ctx, op_size, garbage, slot_1, R_SCRATCH_1, ®1));
1641 g(gen_frame_load_cmp_set_cond(ctx, op_size, garbage, slot_2, reg1, alu, slot_r));
1643 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));
1644 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));
1650 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)
1653 unsigned reg1, target;
1655 case MODE_FIXED: switch (op) {
1656 case OPCODE_FIXED_OP_not: alu = ALU1_NOT; goto do_alu;
1657 case OPCODE_FIXED_OP_neg: alu = ALU1_NEG; goto do_alu;
1658 case OPCODE_FIXED_OP_inc: alu = ALU1_INC; goto do_alu;
1659 case OPCODE_FIXED_OP_dec: alu = ALU1_DEC; goto do_alu;
1660 case OPCODE_FIXED_OP_bswap:
1661 case OPCODE_FIXED_OP_bswap_alt1: alu = ALU1_BSWAP; goto do_bswap;
1662 case OPCODE_FIXED_OP_brev:
1663 case OPCODE_FIXED_OP_brev_alt1: alu = ALU1_BREV; goto do_brev;
1664 case OPCODE_FIXED_OP_bsf:
1665 case OPCODE_FIXED_OP_bsf_alt1: alu = ALU1_BSF; goto do_bsf_bsr_popcnt;
1666 case OPCODE_FIXED_OP_bsr:
1667 case OPCODE_FIXED_OP_bsr_alt1: alu = ALU1_BSR; goto do_bsf_bsr_popcnt;
1668 case OPCODE_FIXED_OP_popcnt:
1669 case OPCODE_FIXED_OP_popcnt_alt1: alu = ALU1_POPCNT; goto do_bsf_bsr_popcnt;
1670 case OPCODE_FIXED_OP_to_int: goto do_fixed_conv;
1671 case OPCODE_FIXED_OP_from_int: goto do_fixed_conv;
1672 case OPCODE_FIXED_OP_uto_int: goto conv_uto_int;
1673 case OPCODE_FIXED_OP_ufrom_int: goto conv_ufrom_int;
1674 default: internal(file_line, "gen_alu1: unsupported fixed operation %u", op);
1676 case MODE_INT: switch (op) {
1677 case OPCODE_INT_OP_not: alu = ALU1_NOT; mode = MODE_FIXED; goto do_alu;
1678 case OPCODE_INT_OP_neg: alu = ALU1_NEG; goto do_alu;
1679 case OPCODE_INT_OP_inc: alu = ALU1_INC; goto do_alu;
1680 case OPCODE_INT_OP_dec: alu = ALU1_DEC; goto do_alu;
1681 case OPCODE_INT_OP_bsf: alu = ALU1_BSF; goto do_bsf_bsr_popcnt;
1682 case OPCODE_INT_OP_bsr: alu = ALU1_BSR; goto do_bsf_bsr_popcnt;
1683 case OPCODE_INT_OP_popcnt:
1684 case OPCODE_INT_OP_popcnt_alt1: alu = ALU1_POPCNT; goto do_bsf_bsr_popcnt;
1685 case OPCODE_INT_OP_to_int: goto do_conv;
1686 case OPCODE_INT_OP_from_int: goto do_conv;
1687 default: internal(file_line, "gen_alu1: unsupported int operation %u", op);
1689 case MODE_BOOL: switch (op) {
1690 case OPCODE_BOOL_OP_not: goto do_bool_not;
1691 default: internal(file_line, "gen_alu1: unsupported bool operation %u", op);
1694 internal(file_line, "gen_alu1: unsupported mode %u", mode);
1700 bool arch_use_flags = ARCH_HAS_FLAGS;
1702 #if defined(ARCH_POWER)
1703 arch_use_flags = false;
1705 if (op_size > OP_SIZE_NATIVE) {
1706 #if !defined(ARCH_X86) && !defined(ARCH_ARM) && !defined(ARCH_POWER)
1707 if (alu == ALU1_NEG) {
1708 if (mode == MODE_FIXED)
1709 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));
1711 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));
1714 if (alu == ALU1_DEC) {
1715 if (mode == MODE_FIXED)
1716 g(gen_alu_upcall(ctx, offsetof(struct cg_upcall_vector_s, cat(FIXED_unary_dec_,TYPE_INT_MAX)), op_size, slot_1, NO_FRAME_T, slot_r, 0));
1718 g(gen_alu_upcall(ctx, offsetof(struct cg_upcall_vector_s, cat(INT_unary_dec_,TYPE_INT_MAX)), op_size, slot_1, NO_FRAME_T, slot_r, label_ovf));
1721 if (alu == ALU1_INC) {
1722 if (mode == MODE_FIXED)
1723 g(gen_alu_upcall(ctx, offsetof(struct cg_upcall_vector_s, cat(FIXED_unary_inc_,TYPE_INT_MAX)), op_size, slot_1, NO_FRAME_T, slot_r, 0));
1725 g(gen_alu_upcall(ctx, offsetof(struct cg_upcall_vector_s, cat(INT_unary_inc_,TYPE_INT_MAX)), op_size, slot_1, NO_FRAME_T, slot_r, label_ovf));
1729 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_1, 0, R_SCRATCH_1, R_SCRATCH_2));
1730 #if defined(ARCH_S390)
1731 if (alu == ALU1_NOT) {
1732 g(gen_load_constant(ctx, R_SCRATCH_3, -1));
1734 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_XOR, R_SCRATCH_1, R_SCRATCH_1, R_SCRATCH_3, 0));
1735 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_XOR, R_SCRATCH_2, R_SCRATCH_2, R_SCRATCH_3, 0));
1737 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, R_SCRATCH_1, R_SCRATCH_2));
1741 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, alu, R_SCRATCH_1, R_SCRATCH_1, alu == ALU1_INC || alu == ALU1_DEC || alu == ALU1_NEG ? 2 : 0));
1742 if (alu == ALU1_NOT) {
1743 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_NOT, R_SCRATCH_2, R_SCRATCH_2, 0));
1744 } else if (alu == ALU1_INC || alu == ALU1_DEC) {
1745 g(gen_imm(ctx, 0, alu == ALU1_INC ? IMM_PURPOSE_ADD : IMM_PURPOSE_SUB, OP_SIZE_NATIVE));
1746 gen_insn(INSN_ALU, OP_SIZE_NATIVE, alu == ALU1_INC ? ALU_ADC : ALU_SBB, (mode == MODE_INT) | ALU_WRITES_FLAGS(alu == ALU1_INC ? ALU_ADC : ALU_SBB, is_imm()));
1747 gen_one(R_SCRATCH_2);
1748 gen_one(R_SCRATCH_2);
1751 #if defined(ARCH_X86)
1752 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_NOT, R_SCRATCH_2, R_SCRATCH_2, 0));
1754 g(gen_imm(ctx, -1, IMM_PURPOSE_SUB, OP_SIZE_NATIVE));
1755 gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_SBB, ALU_WRITES_FLAGS(ALU_SBB, is_imm()));
1756 gen_one(R_SCRATCH_2);
1757 gen_one(R_SCRATCH_2);
1760 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_NGC, R_SCRATCH_2, R_SCRATCH_2, (mode == MODE_INT)));
1763 if (mode == MODE_INT) {
1764 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_O, 0);
1765 gen_four(label_ovf);
1767 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, R_SCRATCH_1, R_SCRATCH_2));
1770 if ((arch_use_flags || ARCH_SUPPORTS_TRAPS) && slot_1 == slot_r && i_size_cmp(op_size) == op_size + zero) {
1772 unsigned undo_alu = alu == ALU1_INC ? ALU1_DEC : alu == ALU1_DEC ? ALU1_INC : alu;
1773 if (slot_is_register(ctx, slot_1)) {
1774 unsigned reg = ctx->registers[slot_1];
1775 if (mode == MODE_INT && ARCH_SUPPORTS_TRAPS) {
1776 gen_insn(INSN_ALU1_TRAP, op_size, alu, ALU1_WRITES_FLAGS(alu));
1779 if (ARCH_TRAP_BEFORE || alu == undo_alu) {
1780 gen_four(label_ovf);
1783 ce = alloc_undo_label(ctx);
1786 gen_four(ce->undo_label);
1787 goto do_undo_opcode;
1790 g(gen_2address_alu1(ctx, i_size(op_size), alu, reg, reg, mode == MODE_INT));
1791 if (mode == MODE_INT) {
1792 if (alu != undo_alu) {
1793 ce = alloc_undo_label(ctx);
1796 gen_insn(INSN_JMP_COND, i_size_cmp(op_size), COND_O, 0);
1797 gen_four(ce->undo_label);
1799 ce->undo_opcode = INSN_ALU1 + ARCH_PARTIAL_ALU(op_size);
1800 ce->undo_op_size = i_size(op_size);
1801 ce->undo_aux = undo_alu;
1802 ce->undo_writes_flags = ALU1_WRITES_FLAGS(undo_alu);
1803 ce->undo_parameters[0] = reg;
1804 ce->undo_parameters[1] = reg;
1805 ce->undo_parameters_len = 2;
1807 gen_insn(INSN_JMP_COND, i_size_cmp(op_size), COND_O, 0);
1808 gen_four(label_ovf);
1813 #if defined(ARCH_X86)
1816 int64_t offset = (size_t)slot_1 * slot_size;
1817 g(gen_address(ctx, R_FRAME, offset, IMM_PURPOSE_LDR_OFFSET, i_size(op_size)));
1818 gen_insn(INSN_ALU1 + ARCH_PARTIAL_ALU(op_size), i_size(op_size), alu, ALU1_WRITES_FLAGS(alu) | (mode == MODE_INT));
1819 gen_address_offset();
1820 gen_address_offset();
1821 if (mode == MODE_INT) {
1822 if (alu != undo_alu) {
1823 ce = alloc_undo_label(ctx);
1826 ce->undo_opcode = INSN_ALU1 + ARCH_PARTIAL_ALU(op_size);
1827 ce->undo_op_size = i_size(op_size);
1828 ce->undo_aux = undo_alu;
1829 ce->undo_writes_flags = ALU1_WRITES_FLAGS(undo_alu);
1830 m = mark_params(ctx);
1831 gen_address_offset();
1832 gen_address_offset();
1833 copy_params(ctx, ce, m);
1834 gen_insn(INSN_JMP_COND, i_size_cmp(op_size), COND_O, 0);
1835 gen_four(ce->undo_label);
1837 gen_insn(INSN_JMP_COND, i_size_cmp(op_size), COND_O, 0);
1838 gen_four(label_ovf);
1845 target = gen_frame_target(ctx, slot_r, mode == MODE_INT ? slot_1 : NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
1846 if (mode == MODE_FIXED) {
1849 ex = ARCH_PREFERS_SX(op_size) ? sign_x : zero_x;
1850 if (ARCH_SUPPORTS_TRAPS && op_size >= OP_SIZE_4)
1852 if (op_size == i_size(op_size) + (unsigned)zero)
1855 g(gen_frame_get(ctx, op_size, ex, slot_1, mode == MODE_INT ? R_SCRATCH_2 : target, ®1));
1856 #if defined(ARCH_S390)
1857 if (alu == ALU1_NOT) {
1858 g(gen_3address_alu_imm(ctx, i_size(op_size), ALU_XOR, target, reg1, -1, 0));
1860 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1864 #if defined(ARCH_X86)
1865 g(gen_2address_alu1(ctx, op_size, alu, target, reg1, mode == MODE_INT));
1867 if (mode == MODE_INT) {
1868 #if defined(ARCH_POWER)
1869 if (op_size == OP_SIZE_NATIVE) {
1870 g(gen_2address_alu1(ctx, i_size(op_size), alu, target, reg1, 0));
1871 if (alu == ALU1_NEG) {
1872 g(gen_3address_alu(ctx, i_size(op_size), ALU_AND, R_CG_SCRATCH, target, reg1, 1));
1873 } else if (alu == ALU1_INC) {
1874 g(gen_3address_alu(ctx, i_size(op_size), ALU_ANDN, R_CG_SCRATCH, target, reg1, 1));
1875 } else if (alu == ALU1_DEC) {
1876 g(gen_3address_alu(ctx, i_size(op_size), ALU_ANDN, R_CG_SCRATCH, reg1, target, 1));
1878 gen_insn(INSN_JMP_COND, op_size, COND_L, 0);
1879 gen_four(label_ovf);
1881 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1886 if (ARCH_HAS_JMP_2REGS(COND_L) && ARCH_HAS_JMP_2REGS(COND_G) && (alu == ALU1_INC || alu == ALU1_DEC) && op_size == i_size_cmp(op_size) + (unsigned)zero) {
1887 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, alu, target, reg1, 0));
1889 g(gen_cmp_test_jmp(ctx, INSN_CMP, i_size_cmp(op_size), target, reg1, alu == ALU1_INC ? COND_L : COND_G, label_ovf));
1891 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1895 if (!arch_use_flags && !ARCH_SUPPORTS_TRAPS && ARCH_HAS_ANDN && op_size >= OP_SIZE_4) {
1896 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, alu, target, reg1, 0));
1898 if (alu == ALU1_NEG) {
1899 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_AND, R_SCRATCH_3, target, reg1, 0));
1900 } else if (alu == ALU1_INC) {
1901 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_ANDN, R_SCRATCH_3, target, reg1, 0));
1902 } else if (alu == ALU1_DEC) {
1903 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_ANDN, R_SCRATCH_3, reg1, target, 0));
1906 if (op_size < OP_SIZE_NATIVE)
1907 g(gen_extend(ctx, op_size, sign_x, R_SCRATCH_3, R_SCRATCH_3));
1909 g(gen_jmp_on_zero(ctx, OP_SIZE_NATIVE, R_SCRATCH_3, COND_S, label_ovf));
1911 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1915 if (op_size <= OP_SIZE_2 || (!arch_use_flags && !ARCH_SUPPORTS_TRAPS)) {
1916 int64_t imm = ((alu != ALU1_INC && ARCH_PREFERS_SX(op_size) ? -0x80ULL : 0x80ULL) << (((1 << op_size) - 1) * 8)) - (alu == ALU1_INC);
1918 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, i_size_cmp(op_size), reg1, imm, COND_E, label_ovf));
1922 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
1926 if (mode == MODE_INT) {
1927 gen_insn(INSN_ALU1_TRAP, op_size, alu, ALU1_WRITES_FLAGS(alu));
1930 gen_four(label_ovf);
1931 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1935 g(gen_2address_alu1(ctx, i_size(op_size), alu, target, reg1, mode == MODE_INT));
1937 if (mode == MODE_INT) {
1938 gen_insn(INSN_JMP_COND, i_size_cmp(op_size), COND_O, 0);
1939 gen_four(label_ovf);
1941 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1949 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
1950 g(gen_frame_get(ctx, op_size, garbage, slot_1, target, ®1));
1952 g(gen_3address_alu_imm(ctx, i_size(op_size), ALU_XOR, target, reg1, 1, 0));
1954 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1962 bool attr_unused sx = false;
1963 #if defined(ARCH_X86) || defined(ARCH_ARM) || defined(ARCH_IA64) || defined(ARCH_LOONGARCH64) || defined(ARCH_MIPS) || defined(ARCH_RISCV64) || defined(ARCH_S390)
1964 #if defined(ARCH_ARM32)
1965 if (unlikely(!cpu_test_feature(CPU_FEATURE_armv6)))
1966 goto do_generic_bswap;
1968 #if defined(ARCH_MIPS)
1969 if (unlikely(!MIPS_HAS_ROT))
1970 goto do_generic_bswap;
1971 sx = op_size == OP_SIZE_4;
1973 #if defined(ARCH_RISCV64)
1974 if (unlikely(!cpu_test_feature(CPU_FEATURE_zbb)))
1975 goto do_generic_bswap;
1977 #if defined(ARCH_S390)
1978 if (op_size == OP_SIZE_2)
1979 goto do_generic_bswap;
1981 #if defined(ARCH_X86)
1982 if (op_size >= OP_SIZE_4 && !cpu_test_feature(CPU_FEATURE_bswap))
1983 goto do_generic_bswap;
1985 if (op_size > OP_SIZE_NATIVE) {
1986 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_1, 0, R_SCRATCH_1, R_SCRATCH_2));
1988 target = R_SCRATCH_1;
1990 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
1991 g(gen_frame_get(ctx, op_size, sx ? sign_x : garbage, slot_1, target, ®1));
1994 if (op_size == OP_SIZE_1) {
1995 #if defined(ARCH_IA64) || defined(ARCH_RISCV64)
1996 } else if (op_size == OP_SIZE_2 || op_size == OP_SIZE_4) {
1997 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_BSWAP, target, reg1, 0));
1999 g(gen_3address_rot_imm(ctx, OP_SIZE_NATIVE, ROT_SAR, target, target, op_size == OP_SIZE_2 ? 48 : 32, 0));
2001 } else if (op_size == OP_SIZE_2) {
2002 #if defined(ARCH_X86)
2003 g(gen_3address_rot_imm(ctx, OP_SIZE_2, ROT_ROR, target, reg1, 8, 0));
2005 g(gen_2address_alu1(ctx, OP_SIZE_4, ALU1_BSWAP16, target, reg1, 0));
2008 g(gen_2address_alu1(ctx, minimum(op_size, OP_SIZE_NATIVE), ALU1_BSWAP, target, reg1, 0));
2010 if (op_size > OP_SIZE_NATIVE) {
2011 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_BSWAP, R_SCRATCH_2, R_SCRATCH_2, 0));
2014 if (op_size > OP_SIZE_NATIVE)
2015 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, R_SCRATCH_2, R_SCRATCH_1));
2017 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2020 goto do_generic_bswap;
2022 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);
2028 #if defined(ARCH_ARM) || defined(ARCH_LOONGARCH64) || (defined(ARCH_MIPS) && MIPS_R6)
2029 #if defined(ARCH_ARM32)
2030 if (unlikely(!cpu_test_feature(CPU_FEATURE_armv6t2)))
2031 goto do_generic_brev;
2033 if (op_size > OP_SIZE_NATIVE) {
2034 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_1, 0, R_SCRATCH_1, R_SCRATCH_2));
2036 target = R_SCRATCH_1;
2038 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
2039 g(gen_frame_get(ctx, op_size, garbage, slot_1, target, ®1));
2042 g(gen_2address_alu1(ctx, minimum(maximum(OP_SIZE_4, op_size), OP_SIZE_NATIVE), ALU1_BREV, target, reg1, 0));
2043 if (op_size <= OP_SIZE_2) {
2044 g(gen_3address_rot_imm(ctx, OP_SIZE_4, ROT_SHR, target, target, op_size == OP_SIZE_1 ? 24 : 16, 0));
2046 if (op_size > OP_SIZE_NATIVE) {
2047 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_BREV, R_SCRATCH_2, R_SCRATCH_2, 0));
2050 if (op_size > OP_SIZE_NATIVE)
2051 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, R_SCRATCH_2, R_SCRATCH_1));
2053 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2056 goto do_generic_brev;
2058 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);
2063 do_bsf_bsr_popcnt: {
2064 if (op_size > OP_SIZE_NATIVE) {
2065 #if defined(ARCH_X86)
2066 uint32_t label_finish = 0; /* avoid warning */
2067 if (alu == ALU1_POPCNT && unlikely(!cpu_test_feature(CPU_FEATURE_popcnt)))
2068 goto do_generic_bsf_bsr_popcnt;
2069 if (alu == ALU1_BSR || alu == ALU1_POPCNT) {
2070 if (mode == MODE_INT) {
2071 g(gen_address(ctx, R_FRAME, (size_t)slot_1 * slot_size + hi_word(OP_SIZE_NATIVE), IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
2072 g(gen_imm(ctx, 0, IMM_PURPOSE_STORE_VALUE, OP_SIZE_NATIVE));
2073 gen_insn(INSN_CMP, OP_SIZE_NATIVE, 0, 1);
2074 gen_address_offset();
2077 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_S, 0);
2078 gen_four(label_ovf);
2081 if (alu == ALU1_BSF) {
2082 label_finish = alloc_label(ctx);
2083 if (unlikely(!label_finish))
2086 g(gen_address(ctx, R_FRAME, (size_t)slot_1 * slot_size + lo_word(OP_SIZE_NATIVE), IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
2087 gen_insn(INSN_ALU1, OP_SIZE_NATIVE, ALU1_BSF, ALU1_WRITES_FLAGS(ALU1_BSF));
2088 gen_one(R_SCRATCH_1);
2089 gen_address_offset();
2091 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_NE, 0);
2092 gen_four(label_finish);
2094 g(gen_address(ctx, R_FRAME, (size_t)slot_1 * slot_size + hi_word(OP_SIZE_NATIVE), IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
2095 gen_insn(INSN_ALU1, OP_SIZE_NATIVE, ALU1_BSF, ALU1_WRITES_FLAGS(ALU1_BSF));
2096 gen_one(R_SCRATCH_1);
2097 gen_address_offset();
2099 g(gen_3address_alu_imm(ctx, OP_SIZE_4, ALU_ADD, R_SCRATCH_1, R_SCRATCH_1, 8U << OP_SIZE_NATIVE, 0));
2101 if (alu == ALU1_BSR) {
2102 label_finish = alloc_label(ctx);
2103 if (unlikely(!label_finish))
2106 g(gen_address(ctx, R_FRAME, (size_t)slot_1 * slot_size + hi_word(OP_SIZE_NATIVE), IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
2107 gen_insn(INSN_ALU1, OP_SIZE_NATIVE, ALU1_BSR, ALU1_WRITES_FLAGS(ALU1_BSR));
2108 gen_one(R_SCRATCH_1);
2109 gen_address_offset();
2111 g(gen_3address_alu_imm(ctx, OP_SIZE_4, ALU_ADD, R_SCRATCH_1, R_SCRATCH_1, 8U << OP_SIZE_NATIVE, 0));
2113 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_NE, 0);
2114 gen_four(label_finish);
2116 g(gen_address(ctx, R_FRAME, (size_t)slot_1 * slot_size + lo_word(OP_SIZE_NATIVE), IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
2117 gen_insn(INSN_ALU1, OP_SIZE_NATIVE, ALU1_BSR, ALU1_WRITES_FLAGS(ALU1_BSR));
2118 gen_one(R_SCRATCH_1);
2119 gen_address_offset();
2121 if (alu == ALU1_BSF || alu == ALU1_BSR) {
2122 if (mode == MODE_INT) {
2123 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_E, 0);
2124 gen_four(label_ovf);
2126 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_NE, 0);
2127 gen_four(label_finish);
2129 g(gen_load_constant(ctx, R_SCRATCH_1, -1));
2132 gen_label(label_finish);
2134 if (mode == MODE_INT)
2137 if (R_SCRATCH_1 != R_AX || R_SCRATCH_2 != R_DX)
2138 internal(file_line, "gen_alu1: bad scratch registers");
2139 gen_insn(INSN_CWD, OP_SIZE_NATIVE, 0, 0);
2143 g(gen_address(ctx, R_FRAME, (size_t)slot_r * slot_size + lo_word(OP_SIZE_NATIVE), IMM_PURPOSE_STR_OFFSET, OP_SIZE_NATIVE));
2144 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
2145 gen_address_offset();
2146 gen_one(R_SCRATCH_1);
2148 g(gen_address(ctx, R_FRAME, (size_t)slot_r * slot_size + hi_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_2);
2155 if (alu == ALU1_POPCNT) {
2156 g(gen_address(ctx, R_FRAME, (size_t)slot_1 * slot_size + lo_word(OP_SIZE_NATIVE), IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
2157 gen_insn(INSN_ALU1, OP_SIZE_NATIVE, ALU1_POPCNT, ALU1_WRITES_FLAGS(ALU1_POPCNT));
2158 gen_one(R_SCRATCH_1);
2159 gen_address_offset();
2161 g(gen_address(ctx, R_FRAME, (size_t)slot_1 * slot_size + hi_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_2);
2164 gen_address_offset();
2166 g(gen_3address_alu(ctx, OP_SIZE_4, ALU_ADD, R_SCRATCH_1, R_SCRATCH_1, R_SCRATCH_2, 1));
2168 g(gen_address(ctx, R_FRAME, (size_t)slot_r * slot_size + lo_word(OP_SIZE_NATIVE), IMM_PURPOSE_STR_OFFSET, OP_SIZE_NATIVE));
2169 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
2170 gen_address_offset();
2171 gen_one(R_SCRATCH_1);
2173 g(gen_address(ctx, R_FRAME, (size_t)slot_r * slot_size + hi_word(OP_SIZE_NATIVE), IMM_PURPOSE_STR_OFFSET, OP_SIZE_NATIVE));
2174 g(gen_imm(ctx, 0, IMM_PURPOSE_STORE_VALUE, OP_SIZE_NATIVE));
2175 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
2176 gen_address_offset();
2182 goto do_generic_bsf_bsr_popcnt;
2184 #if defined(ARCH_X86)
2185 if (alu == ALU1_POPCNT && unlikely(!cpu_test_feature(CPU_FEATURE_popcnt)))
2186 goto do_generic_bsf_bsr_popcnt;
2187 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
2188 if (op_size == OP_SIZE_1 || ((alu == ALU1_BSR || alu == ALU1_POPCNT) && mode == MODE_INT)) {
2189 g(gen_frame_get(ctx, op_size, zero_x, slot_1, target, ®1));
2190 if ((alu == ALU1_BSR || alu == ALU1_POPCNT) && mode == MODE_INT) {
2191 g(gen_cmp_test_jmp(ctx, INSN_TEST, op_size, reg1, reg1, alu == ALU1_BSR ? COND_LE : COND_S, label_ovf));
2193 g(gen_2address_alu1(ctx, maximum(op_size, OP_SIZE_2), alu, target, reg1, 1));
2194 if ((alu == ALU1_BSR || alu == ALU1_POPCNT) && mode == MODE_INT)
2195 goto x86_bsf_bsr_popcnt_finish;
2197 g(gen_frame_load_op1(ctx, op_size, alu, 1, slot_1, target));
2199 if (alu == ALU1_POPCNT)
2200 goto x86_bsf_bsr_popcnt_finish;
2201 if (mode == MODE_FIXED) {
2202 uint32_t cmov_label;
2203 gen_insn(INSN_MOV, maximum(op_size, OP_SIZE_4), 0, 0);
2204 gen_one(R_SCRATCH_2);
2207 g(gen_cmov(ctx, maximum(op_size, OP_SIZE_4), COND_E, target, &cmov_label));
2208 gen_one(R_SCRATCH_2);
2210 gen_label(cmov_label);
2213 gen_insn(INSN_JMP_COND, maximum(op_size, OP_SIZE_2), COND_E, 0);
2214 gen_four(label_ovf);
2216 x86_bsf_bsr_popcnt_finish:
2217 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2220 #if defined(ARCH_ARM)
2221 #if defined(ARCH_ARM32)
2222 if (alu == ALU1_BSR && unlikely(!cpu_test_feature(CPU_FEATURE_armv6)))
2223 goto do_generic_bsf_bsr_popcnt;
2224 if (alu == ALU1_BSF && unlikely(!cpu_test_feature(CPU_FEATURE_armv6t2)))
2225 goto do_generic_bsf_bsr_popcnt;
2227 if (alu == ALU1_POPCNT && unlikely(!cpu_test_feature(CPU_FEATURE_neon)))
2228 goto do_generic_bsf_bsr_popcnt;
2229 g(gen_frame_get(ctx, op_size, mode == MODE_INT ? sign_x : zero_x, slot_1, R_SCRATCH_1, ®1));
2230 if (mode == MODE_INT) {
2231 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));
2234 if (alu == ALU1_POPCNT) {
2235 g(gen_mov(ctx, OP_SIZE_NATIVE, FR_SCRATCH_1, reg1));
2236 gen_insn(INSN_FP_ALU1, OP_SIZE_NATIVE, FP_ALU1_VCNT8, 0);
2237 gen_one(FR_SCRATCH_1);
2238 gen_one(FR_SCRATCH_1);
2239 #if defined(ARCH_ARM32)
2240 if (op_size > OP_SIZE_1) {
2241 gen_insn(INSN_FP_ALU1, OP_SIZE_1, FP_ALU1_VPADDL, 0);
2242 gen_one(FR_SCRATCH_1);
2243 gen_one(FR_SCRATCH_1);
2245 if (op_size > OP_SIZE_2) {
2246 gen_insn(INSN_FP_ALU1, OP_SIZE_2, FP_ALU1_VPADDL, 0);
2247 gen_one(FR_SCRATCH_1);
2248 gen_one(FR_SCRATCH_1);
2251 if (op_size > OP_SIZE_1) {
2252 gen_insn(INSN_FP_ALU1, OP_SIZE_1, FP_ALU1_ADDV, 0);
2253 gen_one(FR_SCRATCH_1);
2254 gen_one(FR_SCRATCH_1);
2257 g(gen_frame_store(ctx, op_size, slot_r, 0, FR_SCRATCH_1));
2258 if (slot_is_register(ctx, slot_r))
2259 g(unspill(ctx, slot_r));
2263 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
2264 if (mode == MODE_FIXED && alu == ALU1_BSF) {
2265 gen_insn(INSN_TEST, i_size(op_size), 0, 1);
2271 if (alu == ALU1_BSF) {
2272 g(gen_2address_alu1(ctx, i_size(op_size), ALU1_BREV, target, reg1, 0));
2276 g(gen_2address_alu1(ctx, i_size(op_size), ALU1_LZCNT, target, reg1, 0));
2278 if (alu == ALU1_BSR) {
2279 g(gen_load_constant(ctx, R_SCRATCH_2, op_size == OP_SIZE_8 ? 63 : 31));
2280 g(gen_3address_alu(ctx, i_size(op_size), ALU_SUB, target, R_SCRATCH_2, target, 0));
2283 if (mode == MODE_FIXED && alu == ALU1_BSF) {
2284 #if defined(ARCH_ARM32)
2285 g(gen_imm(ctx, -1, IMM_PURPOSE_CMOV, OP_SIZE_NATIVE));
2286 gen_insn(INSN_CMOV, OP_SIZE_NATIVE, COND_E, 0);
2291 gen_insn(INSN_CSEL_INV, i_size(op_size), COND_NE, 0);
2299 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2302 #if defined(ARCH_ALPHA)
2303 if (likely(cpu_test_feature(CPU_FEATURE_cix))) {
2304 g(gen_frame_get(ctx, op_size, mode == MODE_INT ? sign_x : zero_x, slot_1, R_SCRATCH_1, ®1));
2305 target = gen_frame_target(ctx, slot_r, slot_1, NO_FRAME_T, R_SCRATCH_2);
2306 if (mode == MODE_INT) {
2307 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));
2309 if (alu == ALU1_POPCNT) {
2310 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_POPCNT, target, reg1, 0));
2312 if (alu == ALU1_BSF) {
2313 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_BSF, target, reg1, 0));
2315 if (mode == MODE_FIXED) {
2316 g(gen_imm(ctx, -1, IMM_PURPOSE_MOVR, OP_SIZE_INT));
2317 gen_insn(INSN_MOVR, OP_SIZE_NATIVE, COND_E, 0);
2324 if (alu == ALU1_BSR) {
2325 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_LZCNT, target, reg1, 0));
2327 g(gen_load_constant(ctx, R_SCRATCH_3, OP_SIZE_NATIVE == OP_SIZE_8 ? 63 : 31));
2329 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_SUB, target, R_SCRATCH_3, target, 0));
2331 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2335 #if defined(ARCH_MIPS)
2336 if (MIPS_HAS_CLZ && alu != ALU1_POPCNT) {
2337 g(gen_frame_get(ctx, op_size, mode == MODE_INT ? sign_x : zero_x, slot_1, R_SCRATCH_1, ®1));
2338 target = gen_frame_target(ctx, slot_r, slot_1, NO_FRAME_T, R_SCRATCH_2);
2339 if (mode == MODE_INT) {
2340 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));
2342 if (alu == ALU1_BSF) {
2343 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_NEG, target, reg1, 0));
2345 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_AND, R_SCRATCH_1, reg1, target, 0));
2348 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_LZCNT, target, reg1, 0));
2350 g(gen_load_constant(ctx, R_SCRATCH_3, OP_SIZE_NATIVE == OP_SIZE_8 ? 63 : 31));
2352 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_SUB, target, R_SCRATCH_3, target, 0));
2354 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2358 #if defined(ARCH_POWER)
2359 if (alu == ALU1_BSF && (unlikely(!cpu_test_feature(CPU_FEATURE_v203)) || unlikely(!cpu_test_feature(CPU_FEATURE_v30))))
2360 goto do_generic_bsf_bsr_popcnt;
2361 if (alu == ALU1_POPCNT && unlikely(!cpu_test_feature(CPU_FEATURE_v206)))
2362 goto do_generic_bsf_bsr_popcnt;
2363 g(gen_frame_get(ctx, op_size, mode == MODE_INT ? sign_x : zero_x, slot_1, R_SCRATCH_1, ®1));
2364 target = gen_frame_target(ctx, slot_r, slot_1, NO_FRAME_T, R_SCRATCH_2);
2365 if (mode == MODE_INT) {
2366 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));
2368 if (alu == ALU1_POPCNT) {
2369 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_POPCNT, target, reg1, 0));
2371 if (alu == ALU1_BSF) {
2372 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_BSF, target, reg1, 0));
2374 if (mode == MODE_FIXED) {
2375 g(gen_3address_alu(ctx, i_size(op_size), ALU_AND, R_SCRATCH_3, reg1, reg1, 1));
2377 g(gen_imm(ctx, -1, IMM_PURPOSE_CMOV, OP_SIZE_NATIVE));
2378 gen_insn(INSN_CMOV, OP_SIZE_NATIVE, COND_E, 0);
2384 if (alu == ALU1_BSR) {
2385 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_LZCNT, target, reg1, 0));
2387 g(gen_load_constant(ctx, R_SCRATCH_3, OP_SIZE_NATIVE == OP_SIZE_8 ? 63 : 31));
2389 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_SUB, target, R_SCRATCH_3, target, 0));
2391 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2394 #if defined(ARCH_LOONGARCH64) || defined(ARCH_RISCV64)
2395 #if defined(ARCH_LOONGARCH64)
2396 if (alu == ALU1_POPCNT)
2397 goto do_generic_bsf_bsr_popcnt;
2399 #if defined(ARCH_RISCV64)
2400 if (unlikely(!cpu_test_feature(CPU_FEATURE_zbb)))
2401 goto do_generic_bsf_bsr_popcnt;
2403 g(gen_frame_get(ctx, op_size, mode == MODE_INT ? sign_x : zero_x, slot_1, R_SCRATCH_1, ®1));
2404 target = gen_frame_target(ctx, slot_r, slot_1, NO_FRAME_T, R_SCRATCH_2);
2405 if (mode == MODE_INT) {
2406 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));
2408 if (alu == ALU1_POPCNT) {
2409 g(gen_2address_alu1(ctx, maximum(OP_SIZE_4, op_size), ALU1_POPCNT, target, reg1, 0));
2411 if (alu == ALU1_BSF) {
2412 g(gen_2address_alu1(ctx, maximum(OP_SIZE_4, op_size), ALU1_BSF, target, reg1, 0));
2414 if (mode == MODE_FIXED) {
2415 g(gen_imm(ctx, 1, IMM_PURPOSE_CMP, OP_SIZE_NATIVE));
2416 gen_insn(INSN_CMP_DEST_REG, OP_SIZE_NATIVE, COND_B, 0);
2417 gen_one(R_SCRATCH_3);
2421 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_NEG, R_SCRATCH_3, R_SCRATCH_3, 0));
2423 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_OR, target, target, R_SCRATCH_3, 0));
2426 if (alu == ALU1_BSR) {
2427 g(gen_2address_alu1(ctx, maximum(OP_SIZE_4, op_size), ALU1_LZCNT, target, reg1, 0));
2429 g(gen_load_constant(ctx, R_SCRATCH_3, op_size <= OP_SIZE_4 ? 31 : 63));
2431 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_SUB, target, R_SCRATCH_3, target, 0));
2433 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2436 #if defined(ARCH_IA64) || defined(ARCH_S390) || defined(ARCH_SPARC)
2437 if (alu == ALU1_BSF && !ARCH_HAS_ANDN)
2438 goto do_generic_bsf_bsr_popcnt;
2439 #if defined(ARCH_S390)
2440 if (!cpu_test_feature(CPU_FEATURE_misc_45) || !cpu_test_feature(CPU_FEATURE_misc_insn_ext_3))
2441 goto do_generic_bsf_bsr_popcnt;
2443 #if defined(ARCH_SPARC)
2445 goto do_generic_bsf_bsr_popcnt;
2447 g(gen_frame_get(ctx, op_size, mode == MODE_INT ? sign_x : zero_x, slot_1, R_SCRATCH_1, ®1));
2448 target = gen_frame_target(ctx, slot_r, slot_1, NO_FRAME_T, R_SCRATCH_2);
2449 if (mode == MODE_INT) {
2450 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));
2452 if (ARCH_PREFERS_SX(op_size) && alu == ALU1_POPCNT && op_size < OP_SIZE_NATIVE) {
2453 g(gen_extend(ctx, op_size, zero_x, R_SCRATCH_1, reg1));
2457 if (alu == ALU1_POPCNT) {
2458 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_POPCNT, R_SCRATCH_1, reg1, 0));
2459 g(gen_frame_store(ctx, op_size, slot_r, 0, R_SCRATCH_1));
2462 if (alu == ALU1_BSF) {
2463 g(gen_3address_alu_imm(ctx, OP_SIZE_NATIVE, ALU_SUB, target, reg1, 1, 0));
2465 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_ANDN, target, target, reg1, 0));
2467 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_POPCNT, target, target, 0));
2469 if (mode == MODE_FIXED) {
2470 unsigned attr_unused test_reg = R_SCRATCH_1;
2471 #if defined(ARCH_S390)
2472 g(gen_imm(ctx, 0, COND_IS_LOGICAL(COND_E) ? IMM_PURPOSE_CMP_LOGICAL : IMM_PURPOSE_CMP, OP_SIZE_NATIVE));
2473 gen_insn(INSN_CMP, OP_SIZE_NATIVE, 0, 1 + COND_IS_LOGICAL(COND_E));
2477 g(gen_imm(ctx, -1, IMM_PURPOSE_CMOV, OP_SIZE_NATIVE));
2478 gen_insn(INSN_CMOV, OP_SIZE_NATIVE, COND_E, 0);
2483 #if defined(ARCH_IA64)
2484 g(gen_cmp_dest_reg(ctx, OP_SIZE_NATIVE, reg1, (unsigned)-1, R_CMP_RESULT, 0, COND_NE));
2485 test_reg = R_CMP_RESULT;
2487 g(gen_imm(ctx, -1, IMM_PURPOSE_MOVR, OP_SIZE_NATIVE));
2488 gen_insn(INSN_MOVR, OP_SIZE_NATIVE, COND_E, 0);
2496 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2500 do_generic_bsf_bsr_popcnt:
2501 if (alu == ALU1_BSF) {
2502 if (mode == MODE_FIXED)
2503 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);
2505 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);
2507 if (alu == ALU1_BSR) {
2508 if (mode == MODE_FIXED)
2509 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);
2511 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);
2513 if (alu == ALU1_POPCNT) {
2514 if (mode == MODE_FIXED)
2515 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);
2517 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);
2525 unsigned src_op_size, dest_op_size;
2526 const struct type *src_type, *dest_type;
2527 src_type = get_type_of_local(ctx, slot_1);
2528 dest_type = get_type_of_local(ctx, slot_r);
2530 if (TYPE_TAG_IS_FIXED(src_type->tag)) {
2531 src_op_size = TYPE_TAG_IDX_FIXED(src_type->tag) >> 1;
2533 src_op_size = TYPE_TAG_IDX_INT(src_type->tag);
2536 if (TYPE_TAG_IS_FIXED(dest_type->tag)) {
2537 dest_op_size = TYPE_TAG_IDX_FIXED(dest_type->tag) >> 1;
2539 dest_op_size = TYPE_TAG_IDX_INT(dest_type->tag);
2542 if (src_op_size <= OP_SIZE_NATIVE) {
2543 g(gen_frame_get(ctx, src_op_size, sign_x, slot_1, R_SCRATCH_1, ®1));
2545 #if defined(ARCH_X86)
2546 if (dest_op_size < src_op_size)
2547 g(gen_frame_load(ctx, OP_SIZE_NATIVE, garbage, slot_1, 0, false, R_SCRATCH_1));
2550 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_1, 0, R_SCRATCH_1, R_SCRATCH_3));
2554 if (dest_op_size >= src_op_size) {
2555 if (dest_op_size <= OP_SIZE_NATIVE) {
2556 g(gen_frame_store(ctx, dest_op_size, slot_r, 0, reg1));
2558 if (src_op_size <= OP_SIZE_NATIVE) {
2559 #if defined(ARCH_X86)
2560 if (R_SCRATCH_1 != R_AX || R_SCRATCH_2 != R_DX)
2561 internal(file_line, "gen_alu1: bad scratch registers");
2562 if (reg1 == R_SCRATCH_1) {
2563 gen_insn(INSN_CWD, OP_SIZE_NATIVE, 0, 0);
2568 g(gen_3address_rot_imm(ctx, OP_SIZE_NATIVE, ROT_SAR, R_SCRATCH_2, reg1, (1U << (OP_SIZE_NATIVE + 3)) - 1, false));
2569 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, reg1, R_SCRATCH_2));
2571 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, reg1, R_SCRATCH_3));
2576 if (src_op_size > OP_SIZE_NATIVE) {
2577 #if defined(ARCH_ARM)
2578 gen_insn(INSN_CMP, OP_SIZE_NATIVE, 0, 1);
2579 gen_one(R_SCRATCH_3);
2580 gen_one(ARG_SHIFTED_REGISTER);
2581 gen_one(ARG_SHIFT_ASR | ((1U << (OP_SIZE_NATIVE + 3)) - 1));
2582 gen_one(R_SCRATCH_1);
2584 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_NE, 0);
2585 gen_four(label_ovf);
2586 #elif defined(ARCH_X86)
2587 if (R_SCRATCH_1 != R_AX || R_SCRATCH_2 != R_DX)
2588 internal(file_line, "gen_alu1: bad scratch registers");
2589 gen_insn(INSN_CWD, OP_SIZE_NATIVE, 0, 0);
2593 g(gen_address(ctx, R_FRAME, (size_t)slot_1 * slot_size + hi_word(OP_SIZE_NATIVE), IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
2594 gen_insn(INSN_CMP, OP_SIZE_NATIVE, 0, 1);
2595 gen_one(R_SCRATCH_2);
2596 gen_address_offset();
2598 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_NE, 0);
2599 gen_four(label_ovf);
2601 g(gen_3address_rot_imm(ctx, OP_SIZE_NATIVE, ROT_SAR, R_SCRATCH_2, R_SCRATCH_1, (1U << (OP_SIZE_NATIVE + 3)) - 1, 0));
2603 g(gen_cmp_test_jmp(ctx, INSN_CMP, OP_SIZE_NATIVE, R_SCRATCH_3, R_SCRATCH_2, COND_NE, label_ovf));
2606 src_op_size = OP_SIZE_NATIVE;
2608 if (src_op_size > dest_op_size) {
2609 g(gen_cmp_extended(ctx, OP_SIZE_NATIVE, dest_op_size, reg1, R_SCRATCH_2, label_ovf));
2611 g(gen_frame_store(ctx, dest_op_size, slot_r, 0, reg1));
2617 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);
2621 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);
2625 static bool attr_w gen_constant(struct codegen_context *ctx, bool real, unsigned op_size, bool shrt, frame_t slot_r)
2629 c = (int16_t)get_unaligned_16(ctx->current_position);
2630 } else switch (op_size) {
2631 #define fx(n, type, utype, sz, bits) \
2633 c = (type)cat(get_unaligned_,bits)(ctx->current_position);\
2638 internal(file_line, "gen_constant: invalid type %u", op_size);
2640 if (op_size > OP_SIZE_NATIVE) {
2641 unsigned shift = (8U << OP_SIZE_NATIVE) - 1;
2642 g(gen_frame_store_imm_raw(ctx, OP_SIZE_NATIVE, slot_r, lo_word(OP_SIZE_NATIVE), c & ((2ULL << shift) - 1)));
2643 g(gen_frame_store_imm_raw(ctx, OP_SIZE_NATIVE, slot_r, hi_word(OP_SIZE_NATIVE), c >> 1 >> shift));
2644 if (real && slot_is_register(ctx, slot_r))
2645 g(unspill(ctx, slot_r));
2647 } else if (real && slot_is_register(ctx, slot_r)) {
2648 if (ARCH_HAS_FP_GP_MOV) {
2649 g(gen_load_constant(ctx, R_SCRATCH_1, c));
2650 g(gen_mov(ctx, op_size, ctx->registers[slot_r], R_SCRATCH_1));
2652 g(gen_frame_store_imm_raw(ctx, op_size, slot_r, 0, c));
2653 g(unspill(ctx, slot_r));
2656 g(gen_frame_store_imm(ctx, op_size, slot_r, 0, c));
2661 static bool attr_w gen_real_constant(struct codegen_context *ctx, const struct type *t, frame_t slot_r)
2664 if (is_power_of_2(t->size) && t->size <= sizeof(uintbig_t))
2665 return gen_constant(ctx, true, log_2(t->size), false, slot_r);
2667 g(load_function_offset(ctx, R_SCRATCH_3, offsetof(struct data, u_.function.code)));
2669 offset = (ctx->current_position - da(ctx->fn,function)->code) * sizeof(code_t);
2671 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))));
2672 if (slot_is_register(ctx, slot_r))
2673 g(unspill(ctx, slot_r));
2678 static bool attr_w gen_copy(struct codegen_context *ctx, unsigned op_size, frame_t slot_1, frame_t slot_r)
2681 if (unlikely(op_size > OP_SIZE_NATIVE)) {
2682 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_1, 0, R_SCRATCH_1, R_SCRATCH_2));
2683 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, R_SCRATCH_1, R_SCRATCH_2));
2686 unsigned target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
2687 g(gen_frame_get(ctx, op_size, garbage, slot_1, target, ®1));
2688 g(gen_frame_store(ctx, op_size, slot_r, 0, reg1));
2693 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)
2695 unsigned attr_unused fp_alu;
2697 unsigned attr_unused op_size = real_type_to_op_size(real_type);
2698 unsigned reg1, reg2, target;
2700 case OPCODE_REAL_OP_add:
2701 case OPCODE_REAL_OP_add_alt1:
2702 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;
2703 case OPCODE_REAL_OP_subtract:
2704 case OPCODE_REAL_OP_subtract_alt1:
2705 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;
2706 case OPCODE_REAL_OP_multiply:
2707 case OPCODE_REAL_OP_multiply_alt1:
2708 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;
2709 case OPCODE_REAL_OP_divide:
2710 case OPCODE_REAL_OP_divide_alt1:
2711 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;
2712 case OPCODE_REAL_OP_modulo:
2713 case OPCODE_REAL_OP_power:
2714 case OPCODE_REAL_OP_ldexp:
2715 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;
2716 case OPCODE_REAL_OP_equal:
2717 case OPCODE_REAL_OP_equal_alt1:
2718 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;
2719 case OPCODE_REAL_OP_not_equal:
2720 case OPCODE_REAL_OP_not_equal_alt1:
2721 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;
2722 case OPCODE_REAL_OP_less:
2723 case OPCODE_REAL_OP_less_alt1:
2724 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;
2725 case OPCODE_REAL_OP_less_equal:
2726 case OPCODE_REAL_OP_less_equal_alt1:
2727 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;
2728 case OPCODE_REAL_OP_greater:
2729 case OPCODE_REAL_OP_greater_alt1:
2730 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;
2731 case OPCODE_REAL_OP_greater_equal:
2732 case OPCODE_REAL_OP_greater_equal_alt1:
2733 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;
2734 default: internal(file_line, "gen_fp_alu: unsupported operation %u", op);
2738 if ((SUPPORTED_FP >> real_type) & 1) {
2739 #if defined(ARCH_IA64)
2740 if (unlikely(fp_alu == FP_ALU_DIV))
2743 #if defined(ARCH_X86)
2745 #elif defined(ARCH_S390)
2746 if ((op_size <= OP_SIZE_8 && (size_t)slot_2 * slot_size < 4096) || slot_is_register(ctx, slot_2))
2748 if (slot_is_register(ctx, slot_2))
2751 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, slot_2, FR_SCRATCH_1);
2752 g(gen_frame_get(ctx, op_size, garbage, slot_1, FR_SCRATCH_1, ®1));
2753 if (slot_is_register(ctx, slot_2)) {
2754 g(gen_3address_fp_alu(ctx, op_size, fp_alu, target, reg1, ctx->registers[slot_2]));
2756 if (target != reg1 && !ARCH_IS_3ADDRESS_FP) {
2757 g(gen_mov(ctx, op_size, target, reg1));
2760 g(gen_address(ctx, R_FRAME, (size_t)slot_2 * slot_size, IMM_PURPOSE_VLDR_VSTR_OFFSET, op_size));
2761 gen_insn(INSN_FP_ALU, op_size, fp_alu, 0);
2764 gen_address_offset();
2766 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2769 #if defined(ARCH_ALPHA)
2770 g(gen_frame_get(ctx, op_size, zero_x, slot_1, FR_SCRATCH_1, ®1));
2771 g(gen_frame_get(ctx, op_size, zero_x, slot_2, FR_SCRATCH_2, ®2));
2772 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, FR_SCRATCH_3);
2773 g(gen_3address_fp_alu(ctx, op_size, fp_alu, target, reg1, reg2));
2774 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2776 g(gen_frame_get(ctx, op_size, zero_x, slot_1, FR_SCRATCH_1, ®1));
2777 g(gen_frame_get(ctx, op_size, zero_x, slot_2, FR_SCRATCH_2, ®2));
2778 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, FR_SCRATCH_1);
2779 g(gen_3address_fp_alu(ctx, op_size, fp_alu, target, reg1, reg2));
2780 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2784 #ifdef SUPPORTED_FP_X87
2785 if ((SUPPORTED_FP_X87 >> real_type) & 1) {
2786 if (real_type != 3) {
2787 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_2));
2788 g(gen_frame_load_x87(ctx, INSN_X87_ALU, op_size, fp_alu, slot_1));
2790 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_1));
2791 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_2));
2792 gen_insn(INSN_X87_ALUP, op_size, fp_alu, 0);
2795 g(gen_frame_store_x87(ctx, INSN_X87_FSTP, op_size, slot_r));
2799 #ifdef SUPPORTED_FP_HALF_CVT
2800 if ((SUPPORTED_FP_HALF_CVT >> real_type) & 1) {
2801 g(gen_frame_get(ctx, op_size, zero_x, slot_1, FR_SCRATCH_1, ®1));
2802 g(gen_frame_get(ctx, op_size, zero_x, slot_2, FR_SCRATCH_2, ®2));
2803 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, FR_SCRATCH_1);
2804 gen_insn(INSN_FP_CVT, op_size, OP_SIZE_4, 0);
2805 gen_one(FR_SCRATCH_1);
2807 gen_insn(INSN_FP_CVT, op_size, OP_SIZE_4, 0);
2808 gen_one(FR_SCRATCH_2);
2810 gen_insn(INSN_FP_ALU, OP_SIZE_4, fp_alu, 0);
2811 gen_one(FR_SCRATCH_1);
2812 gen_one(FR_SCRATCH_1);
2813 gen_one(FR_SCRATCH_2);
2814 gen_insn(INSN_FP_CVT, OP_SIZE_4, op_size, 0);
2816 gen_one(FR_SCRATCH_1);
2817 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2824 if ((SUPPORTED_FP >> real_type) & 1
2825 #if defined(ARCH_ALPHA)
2826 && ARCH_SUPPORTS_TRAPS
2829 g(gen_frame_get(ctx, op_size, zero_x, slot_1, FR_SCRATCH_1, ®1));
2830 g(gen_frame_get(ctx, op_size, zero_x, slot_2, FR_SCRATCH_2, ®2));
2831 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
2832 #if defined(ARCH_ALPHA)
2833 gen_insn(INSN_FP_CMP_DEST_REG_TRAP, op_size, fp_alu == FP_COND_NE ? FP_COND_E : fp_alu, 0);
2834 gen_one(FR_SCRATCH_3);
2837 gen_four(label_ovf);
2839 if (!ARCH_HAS_FP_GP_MOV) {
2840 g(gen_frame_store_raw(ctx, OP_SIZE_4, slot_r, 0, FR_SCRATCH_3));
2841 g(gen_frame_load_raw(ctx, OP_SIZE_4, sign_x, slot_r, 0, false, target));
2843 g(gen_mov(ctx, OP_SIZE_4, target, FR_SCRATCH_3));
2846 if (fp_alu == FP_COND_NE) {
2847 g(gen_imm(ctx, 0, IMM_PURPOSE_CMP, OP_SIZE_NATIVE));
2848 gen_insn(INSN_CMP_DEST_REG, OP_SIZE_NATIVE, COND_E, 0);
2853 g(gen_3address_rot_imm(ctx, OP_SIZE_NATIVE, ROT_SHR, target, target, 30, 0));
2856 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, target));
2859 #elif defined(ARCH_IA64)
2860 gen_insn(INSN_FP_CMP_DEST_REG, op_size, FP_COND_P, 0);
2861 gen_one(R_CMP_RESULT);
2865 gen_insn(INSN_JMP_REG, OP_SIZE_NATIVE, COND_NE, 0);
2866 gen_one(R_CMP_RESULT);
2867 gen_four(label_ovf);
2869 gen_insn(INSN_FP_CMP_DEST_REG, op_size, fp_alu, 0);
2870 gen_one(R_CMP_RESULT);
2874 g(gen_mov(ctx, OP_SIZE_NATIVE, target, R_CMP_RESULT));
2876 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, target));
2879 #elif defined(ARCH_LOONGARCH64) || defined(ARCH_MIPS) || defined(ARCH_PARISC)
2880 gen_insn(INSN_FP_CMP_COND, op_size, FP_COND_P, 1);
2884 gen_insn(INSN_JMP_FP_TEST, 0, FP_COND_P, 0);
2885 gen_four(label_ovf);
2887 gen_insn(INSN_FP_CMP_COND, op_size, fp_alu, 1);
2891 gen_insn(INSN_FP_TEST_REG, OP_SIZE_NATIVE, fp_alu, 0);
2894 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, target));
2897 #elif defined(ARCH_RISCV64)
2898 gen_insn(INSN_FP_CMP_DEST_REG, op_size, FP_COND_E, 0);
2899 gen_one(R_SCRATCH_1);
2903 gen_insn(INSN_FP_CMP_DEST_REG, op_size, FP_COND_E, 0);
2904 gen_one(R_SCRATCH_2);
2908 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_AND, R_SCRATCH_1, R_SCRATCH_1, R_SCRATCH_2, 0));
2910 g(gen_jmp_on_zero(ctx, OP_SIZE_NATIVE, R_SCRATCH_1, COND_E, label_ovf));
2912 gen_insn(INSN_FP_CMP_DEST_REG, op_size, fp_alu == FP_COND_NE ? FP_COND_E : fp_alu, 0);
2917 if (fp_alu == FP_COND_NE) {
2918 g(gen_imm(ctx, 1, IMM_PURPOSE_XOR, OP_SIZE_NATIVE));
2919 gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_XOR, ALU_WRITES_FLAGS(ALU_AND, false));
2925 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, target));
2928 gen_insn(INSN_FP_CMP, op_size, 0, 1);
2931 #if defined(ARCH_ARM32)
2932 gen_insn(INSN_FP_TO_INT_FLAGS, 0, 0, 1);
2934 gen_insn(INSN_JMP_COND, op_size, FP_COND_P, 0);
2935 gen_four(label_ovf);
2936 g(gen_frame_set_cond(ctx, op_size, false, fp_alu, slot_r));
2940 #ifdef SUPPORTED_FP_X87
2941 if ((SUPPORTED_FP_X87 >> real_type) & 1) {
2942 if (likely(cpu_test_feature(CPU_FEATURE_cmov))) {
2943 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_2));
2944 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_1));
2945 gen_insn(INSN_X87_FCOMIP, op_size, 0, 0);
2947 gen_insn(INSN_X87_FSTP, op_size, 0, 0);
2949 gen_insn(INSN_JMP_COND, op_size, COND_P, 0);
2950 gen_four(label_ovf);
2951 g(gen_frame_set_cond(ctx, op_size, false, fp_alu & 0xf, slot_r));
2955 if (real_type != 3) {
2956 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_1));
2957 g(gen_frame_load_x87(ctx, INSN_X87_FCOMP, op_size, 0, slot_2));
2959 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_2));
2960 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_1));
2961 gen_insn(INSN_X87_FCOMPP, op_size, 0, 0);
2964 gen_insn(INSN_X87_FNSTSW, 0, 0, 0);
2968 gen_insn(INSN_TEST, OP_SIZE_2, 0, 1);
2973 gen_insn(INSN_JMP_COND, OP_SIZE_2, COND_NE, 0);
2974 gen_four(label_ovf);
2978 gen_insn(INSN_TEST, OP_SIZE_2, 0, 1);
2982 g(gen_frame_set_cond(ctx, OP_SIZE_2, false, COND_NE, slot_r));
2985 gen_insn(INSN_TEST, OP_SIZE_2, 0, 1);
2989 g(gen_frame_set_cond(ctx, OP_SIZE_2, false, COND_E, slot_r));
2992 gen_insn(INSN_TEST, OP_SIZE_2, 0, 1);
2996 g(gen_frame_set_cond(ctx, OP_SIZE_2, false, COND_NE, slot_r));
2999 gen_insn(INSN_TEST, OP_SIZE_2, 0, 1);
3003 g(gen_frame_set_cond(ctx, OP_SIZE_2, false, COND_NE, slot_r));
3006 internal(file_line, "gen_fp_alu: invalid condition %u", fp_alu);
3011 #ifdef SUPPORTED_FP_HALF_CVT
3012 if ((SUPPORTED_FP_HALF_CVT >> real_type) & 1) {
3013 g(gen_frame_get(ctx, op_size, zero_x, slot_1, FR_SCRATCH_1, ®1));
3014 g(gen_frame_get(ctx, op_size, zero_x, slot_2, FR_SCRATCH_2, ®2));
3015 gen_insn(INSN_FP_CVT, op_size, OP_SIZE_4, 0);
3016 gen_one(FR_SCRATCH_1);
3018 gen_insn(INSN_FP_CVT, op_size, OP_SIZE_4, 0);
3019 gen_one(FR_SCRATCH_2);
3021 gen_insn(INSN_FP_CMP, OP_SIZE_4, 0, 1);
3022 gen_one(FR_SCRATCH_1);
3023 gen_one(FR_SCRATCH_2);
3024 #if defined(ARCH_ARM32)
3025 gen_insn(INSN_FP_TO_INT_FLAGS, 0, 0, 1);
3027 gen_insn(INSN_JMP_COND, op_size, FP_COND_P, 0);
3028 gen_four(label_ovf);
3029 g(gen_frame_set_cond(ctx, op_size, false, fp_alu, slot_r));
3035 return gen_alu_typed_upcall(ctx, upc, real_type, slot_1, slot_2, slot_r, label_ovf);
3038 #define OP_IS_ROUND(alu) ((alu) == FP_ALU1_ROUND || (alu) == FP_ALU1_FLOOR || (alu) == FP_ALU1_CEIL || (alu) == FP_ALU1_TRUNC)
3040 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)
3042 unsigned attr_unused fp_alu;
3044 unsigned attr_unused op_size = real_type_to_op_size(real_type);
3045 unsigned reg1, target;
3047 case OPCODE_REAL_OP_neg:
3048 case OPCODE_REAL_OP_neg_alt1:
3049 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;
3050 case OPCODE_REAL_OP_sqrt:
3051 case OPCODE_REAL_OP_sqrt_alt1:
3052 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;
3053 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;
3054 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;
3055 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;
3056 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;
3057 case OPCODE_REAL_OP_to_int:
3058 case OPCODE_REAL_OP_to_int_alt1:
3059 case OPCODE_REAL_OP_to_int_alt2: upc = offsetof(struct cg_upcall_vector_s, REAL_unary_to_int_real16_t); goto do_to_int;
3060 case OPCODE_REAL_OP_from_int:
3061 case OPCODE_REAL_OP_from_int_alt1:
3062 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;
3063 case OPCODE_REAL_OP_is_exception:
3064 case OPCODE_REAL_OP_is_exception_alt1:
3065 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;
3066 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;
3070 if ((SUPPORTED_FP >> real_type) & 1 && (
3071 #if defined(ARCH_ALPHA)
3072 fp_alu == FP_ALU1_NEG ||
3073 (fp_alu == FP_ALU1_SQRT && cpu_test_feature(CPU_FEATURE_fix)) ||
3074 #elif defined(ARCH_ARM32)
3075 fp_alu == FP_ALU1_NEG ||
3076 fp_alu == FP_ALU1_SQRT ||
3077 #elif defined(ARCH_ARM64)
3079 #elif defined(ARCH_IA64)
3080 fp_alu == FP_ALU1_NEG ||
3081 #elif defined(ARCH_LOONGARCH64)
3082 fp_alu == FP_ALU1_NEG ||
3083 fp_alu == FP_ALU1_SQRT ||
3084 fp_alu == FP_ALU1_ROUND ||
3085 #elif defined(ARCH_MIPS)
3086 fp_alu == FP_ALU1_NEG ||
3087 (fp_alu == FP_ALU1_SQRT && MIPS_HAS_SQRT) ||
3088 #elif defined(ARCH_PARISC)
3089 (fp_alu == FP_ALU1_NEG && PA_20) ||
3090 fp_alu == FP_ALU1_SQRT ||
3091 #elif defined(ARCH_POWER)
3092 fp_alu == FP_ALU1_NEG ||
3093 (fp_alu == FP_ALU1_SQRT && cpu_test_feature(CPU_FEATURE_p2) && real_type != 4) ||
3094 #elif defined(ARCH_S390)
3096 #elif defined(ARCH_SPARC)
3097 fp_alu == FP_ALU1_NEG ||
3098 fp_alu == FP_ALU1_SQRT ||
3099 #elif defined(ARCH_RISCV64)
3100 fp_alu == FP_ALU1_NEG ||
3101 fp_alu == FP_ALU1_SQRT ||
3102 #elif defined(ARCH_X86)
3103 fp_alu == FP_ALU1_SQRT ||
3104 (OP_IS_ROUND(fp_alu) && cpu_test_feature(CPU_FEATURE_sse41)) ||
3107 #if defined(ARCH_S390)
3108 if (op_size <= OP_SIZE_8 && (size_t)slot_1 * slot_size < 4096 && fp_alu == FP_ALU1_SQRT) {
3109 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, FR_SCRATCH_1);
3110 if (slot_is_register(ctx, slot_1)) {
3111 gen_insn(INSN_FP_ALU1, op_size, fp_alu, 0);
3113 gen_one(ctx->registers[slot_1]);
3114 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
3116 g(gen_address(ctx, R_FRAME, (size_t)slot_1 * slot_size, IMM_PURPOSE_VLDR_VSTR_OFFSET, op_size));
3117 gen_insn(INSN_FP_ALU1, op_size, fp_alu, 0);
3119 gen_address_offset();
3120 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
3125 g(gen_frame_get(ctx, op_size, zero_x, slot_1, FR_SCRATCH_1, ®1));
3126 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, FR_SCRATCH_2);
3127 gen_insn(INSN_FP_ALU1, op_size, fp_alu, 0);
3130 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
3133 #ifdef SUPPORTED_FP_X87
3134 if ((SUPPORTED_FP_X87 >> real_type) & 1) {
3135 if (fp_alu == FP_ALU1_NEG) {
3136 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_1));
3137 gen_insn(INSN_X87_FCHS, op_size, 0, 0);
3138 g(gen_frame_store_x87(ctx, INSN_X87_FSTP, op_size, slot_r));
3140 } else if (fp_alu == FP_ALU1_SQRT) {
3141 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_1));
3142 gen_insn(INSN_X87_FSQRT, 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_ROUND) {
3146 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_1));
3147 gen_insn(INSN_X87_FRNDINT, op_size, 0, 0);
3148 g(gen_frame_store_x87(ctx, INSN_X87_FSTP, op_size, slot_r));
3153 #ifdef SUPPORTED_FP_HALF_CVT
3154 if ((SUPPORTED_FP_HALF_CVT >> real_type) & 1 && (
3155 #if defined(ARCH_ARM32)
3156 fp_alu == FP_ALU1_NEG ||
3157 fp_alu == FP_ALU1_SQRT ||
3158 #elif defined(ARCH_ARM64)
3160 #elif defined(ARCH_X86)
3161 fp_alu == FP_ALU1_SQRT ||
3162 (OP_IS_ROUND(fp_alu) && cpu_test_feature(CPU_FEATURE_sse41)) ||
3165 g(gen_frame_get(ctx, op_size, zero_x, slot_1, FR_SCRATCH_1, ®1));
3166 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, FR_SCRATCH_1);
3167 gen_insn(INSN_FP_CVT, op_size, OP_SIZE_4, 0);
3170 gen_insn(INSN_FP_ALU1, OP_SIZE_4, fp_alu, 0);
3173 gen_insn(INSN_FP_CVT, OP_SIZE_4, op_size, 0);
3176 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
3183 if ((SUPPORTED_FP >> real_type) & 1
3184 #if defined(ARCH_ALPHA)
3185 && ARCH_SUPPORTS_TRAPS
3187 #if defined(ARCH_MIPS)
3191 g(gen_frame_get(ctx, op_size, zero_x, slot_1, FR_SCRATCH_1, ®1));
3194 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
3195 #if defined(ARCH_X86)
3196 gen_insn(OP_SIZE_INT == OP_SIZE_4 ? INSN_FP_TO_INT32 : INSN_FP_TO_INT64, op_size, 0, 0);
3200 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, OP_SIZE_INT, target, sign_bit(uint_default_t), COND_E, label_ovf));
3202 g(gen_frame_store(ctx, OP_SIZE_INT, slot_r, 0, target));
3205 #if defined(ARCH_ARM) || defined(ARCH_LOONGARCH64) || defined(ARCH_MIPS)
3206 #if defined(ARCH_ARM)
3207 gen_insn(INSN_FP_CMP, op_size, 0, 1);
3210 #if defined(ARCH_ARM32)
3211 gen_insn(INSN_FP_TO_INT_FLAGS, 0, 0, 1);
3213 gen_insn(INSN_JMP_COND, op_size, FP_COND_P, 0);
3214 gen_four(label_ovf);
3216 gen_insn(INSN_FP_CMP_COND, op_size, FP_COND_P, 1);
3220 gen_insn(INSN_JMP_FP_TEST, 0, FP_COND_P, 0);
3221 gen_four(label_ovf);
3223 #if defined(ARCH_ARM32) || defined(ARCH_LOONGARCH64) || defined(ARCH_MIPS)
3224 gen_insn(OP_SIZE_INT == OP_SIZE_4 ? INSN_FP_TO_INT32 : INSN_FP_TO_INT64, op_size, 0, 0);
3225 gen_one(FR_SCRATCH_1);
3228 g(gen_mov(ctx, OP_SIZE_INT, target, FR_SCRATCH_1));
3230 gen_insn(OP_SIZE_INT == OP_SIZE_4 ? INSN_FP_TO_INT32 : INSN_FP_TO_INT64, op_size, 0, 0);
3234 g(gen_imm(ctx, (int_default_t)(sign_bit(uint_default_t) + 1), IMM_PURPOSE_ADD, OP_SIZE_INT));
3235 gen_insn(INSN_ALU, OP_SIZE_INT, ALU_ADD, ALU_WRITES_FLAGS(ALU_ADD, is_imm()));
3236 gen_one(R_SCRATCH_2);
3240 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, OP_SIZE_INT, R_SCRATCH_2, 1, COND_BE, label_ovf));
3242 g(gen_frame_store(ctx, OP_SIZE_INT, slot_r, 0, target));
3245 #if defined(ARCH_IA64)
3246 gen_insn(INSN_FP_TO_INT64, op_size, 0, 0);
3247 gen_one(FR_SCRATCH_1);
3250 g(gen_mov(ctx, OP_SIZE_NATIVE, target, FR_SCRATCH_1));
3252 if (OP_SIZE_INT == OP_SIZE_4) {
3253 g(gen_extend(ctx, OP_SIZE_4, sign_x, R_SCRATCH_2, target));
3254 g(gen_cmp_test_jmp(ctx, INSN_CMP, OP_SIZE_NATIVE, target, R_SCRATCH_2, COND_NE, label_ovf));
3256 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, OP_SIZE_NATIVE, target, sign_bit(uint64_t), COND_E, label_ovf));
3259 g(gen_frame_store(ctx, OP_SIZE_INT, slot_r, 0, target));
3262 #if defined(ARCH_PARISC) || defined(ARCH_POWER) || defined(ARCH_SPARC)
3263 #if defined(ARCH_POWER)
3264 if (!cpu_test_feature(CPU_FEATURE_ppc))
3266 if (OP_SIZE_INT == OP_SIZE_4)
3269 gen_insn(OP_SIZE_INT == OP_SIZE_4 ? INSN_FP_TO_INT32 : INSN_FP_TO_INT64, op_size, 0, 0);
3270 gen_one(FR_SCRATCH_1);
3273 g(gen_frame_store_raw(ctx, OP_SIZE_INT, slot_r, 0, FR_SCRATCH_1));
3274 if (slot_is_register(ctx, slot_r))
3275 g(unspill(ctx, slot_r));
3276 g(gen_frame_load(ctx, OP_SIZE_INT, garbage, slot_r, 0, false, target));
3278 g(gen_imm(ctx, sign_bit(uint_default_t) + 1, IMM_PURPOSE_ADD, OP_SIZE_INT));
3279 gen_insn(INSN_ALU, i_size(OP_SIZE_INT), ALU_ADD, ALU_WRITES_FLAGS(ALU_ADD, is_imm()));
3280 gen_one(R_SCRATCH_2);
3284 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, OP_SIZE_INT, R_SCRATCH_2, 1, COND_BE, label_ovf));
3288 #if defined(ARCH_ALPHA)
3289 gen_insn(INSN_FP_TO_INT64_TRAP, op_size, 0, 0);
3290 gen_one(FR_SCRATCH_2);
3292 gen_four(label_ovf);
3294 if (OP_SIZE_INT == OP_SIZE_4) {
3295 gen_insn(INSN_FP_INT64_TO_INT32_TRAP, 0, 0, 0);
3296 gen_one(FR_SCRATCH_3);
3297 gen_one(FR_SCRATCH_2);
3298 gen_four(label_ovf);
3299 g(gen_frame_store_raw(ctx, OP_SIZE_INT, slot_r, 0, FR_SCRATCH_3));
3301 g(gen_frame_store_raw(ctx, OP_SIZE_INT, slot_r, 0, FR_SCRATCH_2));
3303 if (slot_is_register(ctx, slot_r))
3304 g(unspill(ctx, slot_r));
3307 #if defined(ARCH_S390)
3308 gen_insn(OP_SIZE_INT == OP_SIZE_4 ? INSN_FP_TO_INT32 : INSN_FP_TO_INT64, op_size, 0, 1);
3312 gen_insn(INSN_JMP_COND, op_size, FP_COND_P, 0);
3313 gen_four(label_ovf);
3315 g(gen_frame_store(ctx, OP_SIZE_INT, slot_r, 0, target));
3318 #if defined(ARCH_RISCV64)
3319 gen_insn(OP_SIZE_INT == OP_SIZE_4 ? INSN_FP_TO_INT32 : INSN_FP_TO_INT64, op_size, 0, 0);
3323 g(gen_load_constant(ctx, R_SCRATCH_2, sign_bit(int_default_t)));
3325 g(gen_cmp_test_jmp(ctx, INSN_CMP, OP_SIZE_NATIVE, target, R_SCRATCH_2, COND_E, label_ovf));
3327 g(gen_imm(ctx, -1, IMM_PURPOSE_XOR, i_size(size)));
3328 gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_XOR, ALU_WRITES_FLAGS(ALU_XOR, is_imm()));
3329 gen_one(R_SCRATCH_2);
3330 gen_one(R_SCRATCH_2);
3333 g(gen_cmp_test_jmp(ctx, INSN_CMP, OP_SIZE_NATIVE, target, R_SCRATCH_2, COND_E, label_ovf));
3335 g(gen_frame_store(ctx, OP_SIZE_INT, slot_r, 0, target));
3339 #ifdef SUPPORTED_FP_X87
3340 if ((SUPPORTED_FP_X87 >> real_type) & 1) {
3341 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_1));
3343 if (likely(cpu_test_feature(CPU_FEATURE_sse3))) {
3344 g(gen_frame_store_x87(ctx, INSN_X87_FISTTP, OP_SIZE_INT, slot_r));
3346 gen_insn(INSN_PUSH, OP_SIZE_NATIVE, 0, 0);
3350 gen_insn(INSN_X87_FLDCW, 0, 0, 0);
3351 gen_one(ARG_ADDRESS_1);
3355 g(gen_frame_store_x87(ctx, INSN_X87_FISTP, OP_SIZE_INT, slot_r));
3357 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
3358 gen_one(ARG_ADDRESS_1);
3364 gen_insn(INSN_X87_FLDCW, 0, 0, 0);
3365 gen_one(ARG_ADDRESS_1);
3369 gen_insn(INSN_ALU, i_size(OP_SIZE_ADDRESS), ALU_ADD, 1);
3373 gen_eight(1 << OP_SIZE_NATIVE);
3375 if (slot_is_register(ctx, slot_r))
3376 g(unspill(ctx, slot_r));
3377 g(gen_frame_load(ctx, OP_SIZE_INT, garbage, slot_r, 0, false, R_SCRATCH_1));
3379 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, OP_SIZE_INT, R_SCRATCH_1, sign_bit(int_default_t), COND_E, label_ovf));
3384 #ifdef SUPPORTED_FP_HALF_CVT
3385 if ((SUPPORTED_FP_HALF_CVT >> real_type) & 1) {
3386 g(gen_frame_get(ctx, op_size, zero_x, slot_1, FR_SCRATCH_1, ®1));
3387 gen_insn(INSN_FP_CVT, op_size, OP_SIZE_4, 0);
3388 gen_one(FR_SCRATCH_1);
3390 reg1 = FR_SCRATCH_1;
3392 op_size = real_type_to_op_size(real_type);
3399 if ((SUPPORTED_FP >> real_type) & 1) {
3400 #if defined(ARCH_ALPHA) || defined(ARCH_ARM32) || defined(ARCH_LOONGARCH64) || defined(ARCH_MIPS) || defined(ARCH_PARISC) || defined(ARCH_POWER) || defined(ARCH_SPARC)
3401 int int_op_size = OP_SIZE_INT;
3402 #if defined(ARCH_POWER)
3403 if (int_op_size == OP_SIZE_4)
3405 if (op_size == OP_SIZE_4 && !cpu_test_feature(CPU_FEATURE_v206))
3407 if (op_size == OP_SIZE_8 && !cpu_test_feature(CPU_FEATURE_ppc))
3410 if (slot_is_register(ctx, slot_1))
3411 g(spill(ctx, slot_1));
3412 g(gen_frame_load_raw(ctx, int_op_size, zero_x, slot_1, 0, false, FR_SCRATCH_1));
3413 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, FR_SCRATCH_2);
3414 #if defined(ARCH_ALPHA)
3415 if (OP_SIZE_INT == OP_SIZE_4) {
3416 gen_insn(INSN_MOVSX, OP_SIZE_4, 0, 0);
3417 gen_one(FR_SCRATCH_1);
3418 gen_one(FR_SCRATCH_1);
3420 int_op_size = OP_SIZE_8;
3423 gen_insn(int_op_size == OP_SIZE_4 ? INSN_FP_FROM_INT32 : INSN_FP_FROM_INT64, op_size, 0, 0);
3425 gen_one(FR_SCRATCH_1);
3427 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
3429 #elif defined(ARCH_IA64)
3430 g(gen_frame_get(ctx, OP_SIZE_INT, sign_x, slot_1, R_SCRATCH_1, ®1));
3431 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, FR_SCRATCH_1);
3433 g(gen_mov(ctx, OP_SIZE_NATIVE, target, reg1));
3435 gen_insn(INSN_FP_FROM_INT64, op_size, 0, 0);
3439 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
3442 g(gen_frame_get(ctx, OP_SIZE_INT, garbage, slot_1, R_SCRATCH_1, ®1));
3443 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, FR_SCRATCH_1);
3445 gen_insn(OP_SIZE_INT == OP_SIZE_4 ? INSN_FP_FROM_INT32 : INSN_FP_FROM_INT64, op_size, 0, 0);
3449 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
3453 #ifdef SUPPORTED_FP_X87
3454 if ((SUPPORTED_FP_X87 >> real_type) & 1) {
3455 if (slot_is_register(ctx, slot_1))
3456 g(spill(ctx, slot_1));
3457 g(gen_frame_load_x87(ctx, INSN_X87_FILD, OP_SIZE_INT, 0, slot_1));
3458 g(gen_frame_store_x87(ctx, INSN_X87_FSTP, op_size, slot_r));
3462 #ifdef SUPPORTED_FP_HALF_CVT
3463 if ((SUPPORTED_FP_HALF_CVT >> real_type) & 1) {
3464 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, FR_SCRATCH_1);
3465 #if defined(ARCH_ARM32)
3466 g(gen_frame_get(ctx, OP_SIZE_INT, zero_x, slot_1, FR_SCRATCH_1, ®1));
3468 gen_insn(INSN_FP_FROM_INT32, OP_SIZE_4, 0, 0);
3472 g(gen_frame_get(ctx, OP_SIZE_INT, garbage, slot_1, R_SCRATCH_1, ®1));
3473 gen_insn(OP_SIZE_INT == OP_SIZE_4 ? INSN_FP_FROM_INT32 : INSN_FP_FROM_INT64, OP_SIZE_4, 0, 0);
3477 gen_insn(INSN_FP_CVT, OP_SIZE_4, op_size, 0);
3480 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
3487 if ((SUPPORTED_FP >> real_type) & 1) {
3488 g(gen_frame_get(ctx, op_size, zero_x, slot_1, FR_SCRATCH_1, ®1));
3489 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
3490 #if defined(ARCH_ALPHA)
3491 gen_insn(INSN_FP_CMP_UNORDERED_DEST_REG, op_size, 0, 0);
3492 gen_one(FR_SCRATCH_2);
3493 gen_one(FR_SCRATCH_1);
3496 if (!cpu_test_feature(CPU_FEATURE_fix)) {
3497 g(gen_frame_store_raw(ctx, OP_SIZE_4, slot_r, 0, FR_SCRATCH_2));
3498 g(gen_frame_load_raw(ctx, OP_SIZE_4, sign_x, slot_r, 0, false, target));
3500 g(gen_mov(ctx, OP_SIZE_4, target, FR_SCRATCH_2));
3503 g(gen_3address_rot_imm(ctx, OP_SIZE_NATIVE, ROT_SHR, target, target, 30, 0));
3505 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, target));
3508 #elif defined(ARCH_IA64)
3509 gen_insn(INSN_FP_CMP_DEST_REG, op_size, FP_COND_P, 0);
3510 gen_one(R_CMP_RESULT);
3514 g(gen_mov(ctx, OP_SIZE_NATIVE, target, R_CMP_RESULT));
3516 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, target));
3517 #elif defined(ARCH_LOONGARCH64) || defined(ARCH_MIPS) || defined(ARCH_PARISC)
3518 gen_insn(INSN_FP_CMP_COND, op_size, FP_COND_P, 1);
3522 gen_insn(INSN_FP_TEST_REG, OP_SIZE_NATIVE, FP_COND_P, 0);
3525 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, target));
3526 #elif defined(ARCH_RISCV64)
3527 gen_insn(INSN_FP_CMP_DEST_REG, op_size, FP_COND_E, 0);
3532 g(gen_imm(ctx, 1, IMM_PURPOSE_XOR, OP_SIZE_NATIVE));
3533 gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_XOR, ALU_WRITES_FLAGS(ALU_XOR, is_imm()));
3538 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, target));
3540 gen_insn(INSN_FP_CMP, op_size, 0, 1);
3543 #if defined(ARCH_ARM32)
3544 gen_insn(INSN_FP_TO_INT_FLAGS, 0, 0, 1);
3546 g(gen_frame_set_cond(ctx, op_size, false, FP_COND_P, slot_r));
3550 #ifdef SUPPORTED_FP_X87
3551 if ((SUPPORTED_FP_X87 >> real_type) & 1) {
3552 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_1));
3553 if (likely(cpu_test_feature(CPU_FEATURE_cmov))) {
3554 gen_insn(INSN_X87_FCOMIP, op_size, 0, 0);
3557 g(gen_frame_set_cond(ctx, op_size, false, COND_P, slot_r));
3561 gen_insn(INSN_X87_FCOMP, op_size, 0, 0);
3564 gen_insn(INSN_X87_FNSTSW, 0, 0, 0);
3568 gen_insn(INSN_TEST, OP_SIZE_2, 0, 1);
3573 g(gen_frame_set_cond(ctx, op_size, false, COND_NE, slot_r));
3578 #ifdef SUPPORTED_FP_HALF_CVT
3579 if ((SUPPORTED_FP_HALF_CVT >> real_type) & 1) {
3580 g(gen_frame_get(ctx, op_size, zero_x, slot_1, FR_SCRATCH_1, ®1));
3581 gen_insn(INSN_FP_CVT, op_size, OP_SIZE_4, 0);
3582 gen_one(FR_SCRATCH_1);
3584 gen_insn(INSN_FP_CMP, OP_SIZE_4, 0, 1);
3585 gen_one(FR_SCRATCH_1);
3586 gen_one(FR_SCRATCH_1);
3587 #if defined(ARCH_ARM32)
3588 gen_insn(INSN_FP_TO_INT_FLAGS, 0, 0, 1);
3590 g(gen_frame_set_cond(ctx, op_size, false, FP_COND_P, slot_r));
3596 g(gen_alu_typed_upcall(ctx, upc, real_type, slot_1, NO_FRAME_T, slot_r, label_ovf));
3600 static bool attr_w gen_is_exception(struct codegen_context *ctx, frame_t slot_1, frame_t slot_r)
3602 uint32_t no_ex_label, escape_label;
3603 const struct type *type = get_type_of_local(ctx, slot_1);
3605 no_ex_label = alloc_label(ctx);
3606 if (unlikely(!no_ex_label))
3608 escape_label = alloc_escape_label(ctx);
3609 if (unlikely(!escape_label))
3612 if (TYPE_IS_FLAT(type))
3613 g(gen_test_1_jz_cached(ctx, slot_1, no_ex_label));
3615 g(gen_frame_load(ctx, OP_SIZE_SLOT, zero_x, slot_1, 0, false, R_SCRATCH_1));
3616 g(gen_ptr_is_thunk(ctx, R_SCRATCH_1, slot_1, escape_label));
3618 if (!TYPE_IS_FLAT(type)) {
3619 g(gen_compare_da_tag(ctx, R_SCRATCH_1, DATA_TAG_flat, COND_E, escape_label, R_SCRATCH_1));
3622 gen_label(no_ex_label);
3623 g(gen_frame_clear(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r));
3625 flag_set(ctx, slot_r, false);
3630 static bool attr_w gen_system_property(struct codegen_context *ctx, frame_t slot_1, frame_t slot_r)
3632 uint32_t escape_label;
3634 escape_label = alloc_escape_label(ctx);
3635 if (unlikely(!escape_label))
3638 g(gen_test_1_cached(ctx, slot_1, escape_label));
3640 g(gen_upcall_start(ctx, 1));
3642 g(gen_frame_load(ctx, OP_SIZE_INT, garbage, slot_1, 0, false, R_ARG0));
3643 g(gen_upcall_argument(ctx, 0));
3645 g(gen_upcall(ctx, offsetof(struct cg_upcall_vector_s, cg_upcall_ipret_system_property), 1));
3647 g(gen_frame_store(ctx, OP_SIZE_INT, slot_r, 0, R_RET0));
3649 flag_set(ctx, slot_1, false);
3650 flag_set(ctx, slot_r, false);
3655 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)
3660 unsigned attr_unused reg2;
3662 *failed = true; return true;
3665 case MODE_FIXED: switch (op) {
3666 case OPCODE_FIXED_OP_equal: alu = COND_E; goto do_compare;
3667 case OPCODE_FIXED_OP_not_equal: alu = COND_NE; goto do_compare;
3668 case OPCODE_FIXED_OP_less: alu = COND_L; goto do_compare;
3669 case OPCODE_FIXED_OP_less_equal: alu = COND_LE; goto do_compare;
3670 case OPCODE_FIXED_OP_greater: alu = COND_G; goto do_compare;
3671 case OPCODE_FIXED_OP_greater_equal: alu = COND_GE; goto do_compare;
3672 case OPCODE_FIXED_OP_uless: alu = COND_B; goto do_compare;
3673 case OPCODE_FIXED_OP_uless_equal: alu = COND_BE; goto do_compare;
3674 case OPCODE_FIXED_OP_ugreater: alu = COND_A; goto do_compare;
3675 case OPCODE_FIXED_OP_ugreater_equal: alu = COND_AE; goto do_compare;
3676 case OPCODE_FIXED_OP_bt: *failed = true; return true;
3677 default: internal(file_line, "gen_alu_jmp: unsupported fixed operation %u", op);
3679 case MODE_INT: switch (op) {
3680 case OPCODE_INT_OP_equal: alu = COND_E; goto do_compare;
3681 case OPCODE_INT_OP_not_equal: alu = COND_NE; goto do_compare;
3682 case OPCODE_INT_OP_less: alu = COND_L; goto do_compare;
3683 case OPCODE_INT_OP_less_equal: alu = COND_LE; goto do_compare;
3684 case OPCODE_INT_OP_greater: alu = COND_G; goto do_compare;
3685 case OPCODE_INT_OP_greater_equal: alu = COND_GE; goto do_compare;
3686 case OPCODE_INT_OP_bt: *failed = true; return true;
3687 default: internal(file_line, "gen_alu_jmp: unsupported int operation %u", op);
3689 case MODE_BOOL: switch (op) {
3690 case OPCODE_BOOL_OP_and: alu = ALU_AND; mode = MODE_FIXED; goto do_alu;
3691 case OPCODE_BOOL_OP_or: alu = ALU_OR; mode = MODE_FIXED; goto do_alu;
3692 case OPCODE_BOOL_OP_equal: alu = COND_E; mode = MODE_FIXED; goto do_compare;
3693 case OPCODE_BOOL_OP_not_equal: alu = COND_NE; mode = MODE_FIXED; goto do_compare;
3694 case OPCODE_BOOL_OP_less: alu = COND_L; mode = MODE_FIXED; goto do_compare;
3695 case OPCODE_BOOL_OP_less_equal: alu = COND_LE; mode = MODE_FIXED; goto do_compare;
3696 case OPCODE_BOOL_OP_greater: alu = COND_G; mode = MODE_FIXED; goto do_compare;
3697 case OPCODE_BOOL_OP_greater_equal: alu = COND_GE; mode = MODE_FIXED; goto do_compare;
3698 default: internal(file_line, "gen_alu_jmp: unsupported bool operation %u", op);
3701 internal(file_line, "gen_alu_jmp: unsupported mode %u", mode);
3703 bool attr_unused logical;
3704 if (unlikely(op_size > OP_SIZE_NATIVE)) {
3708 if (slot_is_register(ctx, slot_2) && !slot_is_register(ctx, slot_1)) {
3713 case COND_L: alu = COND_G; break;
3714 case COND_LE: alu = COND_GE; break;
3715 case COND_G: alu = COND_L; break;
3716 case COND_GE: alu = COND_LE; break;
3717 case COND_B: alu = COND_A; break;
3718 case COND_BE: alu = COND_AE; break;
3719 case COND_A: alu = COND_B; break;
3720 case COND_AE: alu = COND_BE; break;
3723 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;
3724 g(gen_frame_get(ctx, op_size, ex, slot_1, R_SCRATCH_1, ®1));
3725 if (ARCH_HAS_JMP_2REGS(alu)) {
3726 g(gen_frame_get(ctx, op_size, ex, slot_2, R_SCRATCH_2, ®2));
3727 g(gen_jump(ctx, jmp_offset, i_size_cmp(op_size), alu ^ 1, reg1, reg2));
3731 logical = COND_IS_LOGICAL(alu ^ 1);
3732 g(gen_frame_load_cmp(ctx, op_size, logical, ex, false, slot_2, 0, false, reg1));
3733 g(gen_jump(ctx, jmp_offset, op_size, alu ^ 1, -1U, -1U));
3735 g(gen_frame_get(ctx, op_size, ex, slot_2, R_SCRATCH_2, ®2));
3736 g(gen_cmp_dest_reg(ctx, op_size, reg1, reg2, R_CMP_RESULT, 0, alu));
3737 g(gen_jump(ctx, jmp_offset, OP_SIZE_NATIVE, COND_E, R_CMP_RESULT, -1U));
3742 if (slot_is_register(ctx, slot_2) && !slot_is_register(ctx, slot_1)) {
3747 ex = op_size == i_size(op_size) + (unsigned)zero ? garbage : ARCH_PREFERS_SX(op_size) ? sign_x : zero_x;
3748 g(gen_frame_get(ctx, op_size, ex, slot_1, R_SCRATCH_1, ®1));
3749 #if defined(ARCH_X86)
3750 if (alu == ALU_AND && !slot_is_register(ctx, slot_2)) {
3751 g(gen_address(ctx, R_FRAME, (size_t)slot_2 * slot_size, IMM_PURPOSE_LDR_OFFSET, op_size));
3752 gen_insn(INSN_TEST, i_size(op_size), 0, 1);
3754 gen_address_offset();
3755 g(gen_jump(ctx, jmp_offset, op_size, COND_E, -1U, -1U));
3759 g(gen_frame_get(ctx, op_size, ex, slot_2, R_SCRATCH_2, ®2));
3760 #if ARCH_HAS_FLAGS && !defined(ARCH_S390)
3761 if (alu == ALU_AND) {
3762 gen_insn(INSN_TEST, i_size(op_size), 0, 1);
3765 g(gen_jump(ctx, jmp_offset, op_size, COND_E, -1U, -1U));
3769 #if defined(ARCH_ARM64)
3774 g(gen_3address_alu(ctx, i_size(op_size), alu, R_SCRATCH_1, reg1, reg2, 1));
3775 g(gen_jump(ctx, jmp_offset, i_size(op_size), COND_E, -1U, -1U));
3780 g(gen_3address_alu(ctx, i_size(op_size), alu, R_SCRATCH_1, reg1, reg2, 0));
3781 g(gen_jump(ctx, jmp_offset, i_size(op_size), COND_E, R_SCRATCH_1, -1U));
3786 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)
3788 unsigned attr_unused fp_alu;
3789 unsigned attr_unused op_size = real_type_to_op_size(real_type);
3790 unsigned reg1, reg2;
3791 unsigned attr_unused target;
3793 case OPCODE_REAL_OP_equal:
3794 case OPCODE_REAL_OP_equal_alt1:
3795 case OPCODE_REAL_OP_equal_alt2: fp_alu = FP_COND_E; goto do_cmp;
3796 case OPCODE_REAL_OP_not_equal:
3797 case OPCODE_REAL_OP_not_equal_alt1:
3798 case OPCODE_REAL_OP_not_equal_alt2: fp_alu = FP_COND_NE; goto do_cmp;
3799 case OPCODE_REAL_OP_less:
3800 case OPCODE_REAL_OP_less_alt1:
3801 case OPCODE_REAL_OP_less_alt2: fp_alu = FP_COND_B; goto do_cmp;
3802 case OPCODE_REAL_OP_less_equal:
3803 case OPCODE_REAL_OP_less_equal_alt1:
3804 case OPCODE_REAL_OP_less_equal_alt2: fp_alu = FP_COND_BE; goto do_cmp;
3805 case OPCODE_REAL_OP_greater:
3806 case OPCODE_REAL_OP_greater_alt1:
3807 case OPCODE_REAL_OP_greater_alt2: fp_alu = FP_COND_A; goto do_cmp;
3808 case OPCODE_REAL_OP_greater_equal:
3809 case OPCODE_REAL_OP_greater_equal_alt1:
3810 case OPCODE_REAL_OP_greater_equal_alt2: fp_alu = FP_COND_AE; goto do_cmp;
3811 default: internal(file_line, "gen_fp_alu_jmp: unsupported operation %u", op);
3815 if ((SUPPORTED_FP >> real_type) & 1
3816 #if defined(ARCH_ALPHA)
3817 && ARCH_SUPPORTS_TRAPS && cpu_test_feature(CPU_FEATURE_fix)
3820 g(gen_frame_get(ctx, op_size, zero_x, slot_1, FR_SCRATCH_1, ®1));
3821 g(gen_frame_get(ctx, op_size, zero_x, slot_2, FR_SCRATCH_2, ®2));
3822 target = R_SCRATCH_1;
3823 #if defined(ARCH_ALPHA)
3824 gen_insn(INSN_FP_CMP_DEST_REG_TRAP, op_size, fp_alu == FP_COND_NE ? FP_COND_E : fp_alu, 0);
3825 gen_one(FR_SCRATCH_3);
3828 gen_four(label_ovf);
3830 g(gen_mov(ctx, OP_SIZE_4, target, FR_SCRATCH_3));
3832 if (fp_alu == FP_COND_NE) {
3833 g(gen_jump(ctx, jmp_offset, OP_SIZE_NATIVE, COND_NE, target, -1U));
3835 g(gen_jump(ctx, jmp_offset, OP_SIZE_NATIVE, COND_E, target, -1U));
3839 #elif defined(ARCH_IA64)
3840 gen_insn(INSN_FP_CMP_DEST_REG, op_size, FP_COND_P, 0);
3841 gen_one(R_CMP_RESULT);
3845 gen_insn(INSN_JMP_REG, OP_SIZE_NATIVE, COND_NE, 0);
3846 gen_one(R_CMP_RESULT);
3847 gen_four(label_ovf);
3849 gen_insn(INSN_FP_CMP_DEST_REG, op_size, fp_alu, 0);
3850 gen_one(R_CMP_RESULT);
3854 g(gen_jump(ctx, jmp_offset, OP_SIZE_NATIVE, COND_E, R_CMP_RESULT, -1U);
3857 #elif defined(ARCH_LOONGARCH64) || defined(ARCH_MIPS) || defined(ARCH_PARISC)
3858 gen_insn(INSN_FP_CMP_COND, op_size, FP_COND_P, 1);
3862 gen_insn(INSN_JMP_FP_TEST, 0, FP_COND_P, 0);
3863 gen_four(label_ovf);
3865 gen_insn(INSN_FP_CMP_COND, op_size, fp_alu ^ 1, 1);
3869 g(gen_jump(ctx, jmp_offset, OP_SIZE_NATIVE, fp_alu ^ 1, -1U, -1U));
3872 #elif defined(ARCH_RISCV64)
3873 gen_insn(INSN_FP_CMP_DEST_REG, op_size, FP_COND_E, 0);
3874 gen_one(R_SCRATCH_1);
3878 gen_insn(INSN_FP_CMP_DEST_REG, op_size, FP_COND_E, 0);
3879 gen_one(R_SCRATCH_2);
3883 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_AND, R_SCRATCH_1, R_SCRATCH_1, R_SCRATCH_2, 0));
3885 g(gen_jmp_on_zero(ctx, OP_SIZE_NATIVE, R_SCRATCH_1, COND_E, label_ovf));
3887 gen_insn(INSN_FP_CMP_DEST_REG, op_size, fp_alu == FP_COND_NE ? FP_COND_E : fp_alu, 0);
3892 if (fp_alu == FP_COND_NE) {
3893 g(gen_jump(ctx, jmp_offset, OP_SIZE_NATIVE, COND_NE, target, -1U));
3895 g(gen_jump(ctx, jmp_offset, OP_SIZE_NATIVE, COND_E, target, -1U));
3899 gen_insn(INSN_FP_CMP, op_size, 0, 1);
3902 #if defined(ARCH_ARM32)
3903 gen_insn(INSN_FP_TO_INT_FLAGS, 0, 0, 1);
3905 gen_insn(INSN_JMP_COND, op_size, FP_COND_P, 0);
3906 gen_four(label_ovf);
3907 g(gen_jump(ctx, jmp_offset, op_size, fp_alu ^ 1, -1U, -1U));