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, frame_t slot_1, frame_t slot_2, frame_t slot_r, uint32_t label_ovf)
23 if (ctx->registers[slot_1] >= 0)
24 g(spill(ctx, slot_1));
25 if (slot_2 != NO_FRAME_T && ctx->registers[slot_2] >= 0)
26 g(spill(ctx, slot_2));
27 g(gen_upcall_start(ctx, 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 (slot_2 != NO_FRAME_T) {
31 g(gen_frame_address(ctx, slot_2, 0, R_ARG1));
32 g(gen_upcall_argument(ctx, 1));
33 g(gen_frame_address(ctx, slot_r, 0, R_ARG2));
34 g(gen_upcall_argument(ctx, 2));
35 g(gen_upcall(ctx, upcall, 3));
37 g(gen_frame_address(ctx, slot_r, 0, R_ARG1));
38 g(gen_upcall_argument(ctx, 1));
39 g(gen_upcall(ctx, upcall, 2));
41 if (ctx->registers[slot_r] >= 0)
42 g(unspill(ctx, slot_r));
44 g(gen_jmp_on_zero(ctx, OP_SIZE_1, R_RET0, COND_E, label_ovf));
48 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)
50 upcall += op_size * sizeof(void (*)(void));
51 return gen_alu_upcall(ctx, upcall, slot_1, slot_2, slot_r, label_ovf);
58 #define MODE_ARRAY_LEN_GT 4
60 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)
64 unsigned reg1, reg2, reg3, target;
66 case MODE_FIXED: switch (op) {
67 case OPCODE_FIXED_OP_add: alu = ALU_ADD; goto do_alu;
68 case OPCODE_FIXED_OP_subtract: alu = ALU_SUB; goto do_alu;
69 case OPCODE_FIXED_OP_multiply: goto do_multiply;
70 case OPCODE_FIXED_OP_divide:
71 case OPCODE_FIXED_OP_divide_alt1: sgn = true; mod = false; goto do_divide;
72 case OPCODE_FIXED_OP_udivide:
73 case OPCODE_FIXED_OP_udivide_alt1: sgn = false; mod = false; goto do_divide;
74 case OPCODE_FIXED_OP_modulo:
75 case OPCODE_FIXED_OP_modulo_alt1: sgn = true; mod = true; goto do_divide;
76 case OPCODE_FIXED_OP_umodulo:
77 case OPCODE_FIXED_OP_umodulo_alt1: sgn = false; mod = true; goto do_divide;
78 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);
79 case OPCODE_FIXED_OP_and: alu = ALU_AND; goto do_alu;
80 case OPCODE_FIXED_OP_or: alu = ALU_OR; goto do_alu;
81 case OPCODE_FIXED_OP_xor: alu = ALU_XOR; goto do_alu;
82 case OPCODE_FIXED_OP_shl: alu = ROT_SHL; goto do_shift;
83 case OPCODE_FIXED_OP_shr: alu = ROT_SAR; goto do_shift;
84 case OPCODE_FIXED_OP_ushr: alu = ROT_SHR; goto do_shift;
85 case OPCODE_FIXED_OP_rol: alu = ROT_ROL; goto do_shift;
86 case OPCODE_FIXED_OP_ror: alu = ROT_ROR; goto do_shift;
87 case OPCODE_FIXED_OP_bts: alu = BTX_BTS; goto do_bt;
88 case OPCODE_FIXED_OP_btr: alu = BTX_BTR; goto do_bt;
89 case OPCODE_FIXED_OP_btc: alu = BTX_BTC; goto do_bt;
90 case OPCODE_FIXED_OP_equal: alu = COND_E; goto do_compare;
91 case OPCODE_FIXED_OP_not_equal: alu = COND_NE; goto do_compare;
92 case OPCODE_FIXED_OP_less: alu = COND_L; goto do_compare;
93 case OPCODE_FIXED_OP_less_equal: alu = COND_LE; goto do_compare;
94 case OPCODE_FIXED_OP_uless: alu = COND_B; goto do_compare;
95 case OPCODE_FIXED_OP_uless_equal: alu = COND_BE; goto do_compare;
96 case OPCODE_FIXED_OP_bt: alu = BTX_BT; goto do_bt;
97 default: internal(file_line, "gen_alu: unsupported fixed operation %u", op);
99 case MODE_INT: switch (op) {
100 case OPCODE_INT_OP_add: alu = ALU_ADD; goto do_alu;
101 case OPCODE_INT_OP_subtract: alu = ALU_SUB; goto do_alu;
102 case OPCODE_INT_OP_multiply: goto do_multiply;
103 case OPCODE_INT_OP_divide:
104 case OPCODE_INT_OP_divide_alt1: sgn = true; mod = false; goto do_divide;
105 case OPCODE_INT_OP_modulo:
106 case OPCODE_INT_OP_modulo_alt1: sgn = true; mod = true; goto do_divide;
107 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);
108 case OPCODE_INT_OP_and: alu = ALU_AND; mode = MODE_FIXED; goto do_alu;
109 case OPCODE_INT_OP_or: alu = ALU_OR; mode = MODE_FIXED; goto do_alu;
110 case OPCODE_INT_OP_xor: alu = ALU_XOR; mode = MODE_FIXED; goto do_alu;
111 case OPCODE_INT_OP_shl: alu = ROT_SHL; goto do_shift;
112 case OPCODE_INT_OP_shr: alu = ROT_SAR; goto do_shift;
113 case OPCODE_INT_OP_bts: alu = BTX_BTS; goto do_bt;
114 case OPCODE_INT_OP_btr: alu = BTX_BTR; goto do_bt;
115 case OPCODE_INT_OP_btc: alu = BTX_BTC; goto do_bt;
116 case OPCODE_INT_OP_equal: alu = COND_E; goto do_compare;
117 case OPCODE_INT_OP_not_equal: alu = COND_NE; goto do_compare;
118 case OPCODE_INT_OP_less: alu = COND_L; goto do_compare;
119 case OPCODE_INT_OP_less_equal: alu = COND_LE; goto do_compare;
120 case OPCODE_INT_OP_bt: alu = BTX_BT; goto do_bt;
121 default: internal(file_line, "gen_alu: unsupported int operation %u", op);
123 case MODE_BOOL: switch (op) {
124 case OPCODE_BOOL_OP_and: alu = ALU_AND; mode = MODE_FIXED; goto do_alu;
125 case OPCODE_BOOL_OP_or: alu = ALU_OR; mode = MODE_FIXED; goto do_alu;
126 case OPCODE_BOOL_OP_equal: alu = COND_E; goto do_compare;
127 case OPCODE_BOOL_OP_not_equal: alu = ALU_XOR; mode = MODE_FIXED; goto do_alu;
128 case OPCODE_BOOL_OP_less: alu = COND_L; goto do_compare;
129 case OPCODE_BOOL_OP_less_equal: alu = COND_LE; goto do_compare;
130 default: internal(file_line, "gen_alu: unsupported bool operation %u", op);
133 internal(file_line, "gen_alu: unsupported mode %u", mode);
139 size_t attr_unused offset;
140 uint8_t attr_unused long_imm;
141 unsigned first_flags;
142 unsigned second_flags;
144 unsigned attr_unused op_size_flags;
145 if (unlikely(op_size > OP_SIZE_NATIVE)) {
146 #if !defined(ARCH_X86) && !defined(ARCH_ARM) && !defined(ARCH_PARISC) && !defined(ARCH_POWER) && !defined(ARCH_SPARC32)
147 if (mode == MODE_FIXED) {
148 if (alu == ALU_ADD) {
149 g(gen_alu_upcall(ctx, offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_add_,TYPE_INT_MAX)), slot_1, slot_2, slot_r, 0));
151 } else if (alu == ALU_SUB) {
152 g(gen_alu_upcall(ctx, offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_subtract_,TYPE_INT_MAX)), slot_1, slot_2, slot_r, 0));
155 } else if (mode == MODE_INT) {
156 if (alu == ALU_ADD) {
157 g(gen_alu_upcall(ctx, offsetof(struct cg_upcall_vector_s, cat(INT_binary_add_,TYPE_INT_MAX)), slot_1, slot_2, slot_r, label_ovf));
159 } else if (alu == ALU_SUB) {
160 g(gen_alu_upcall(ctx, offsetof(struct cg_upcall_vector_s, cat(INT_binary_subtract_,TYPE_INT_MAX)), slot_1, slot_2, slot_r, label_ovf));
165 first_flags = alu == ALU_ADD || alu == ALU_SUB ? 2 : 0;
166 second_flags = mode == MODE_INT ? 1 : 0;
167 second_alu = alu == ALU_ADD ? ALU_ADC : alu == ALU_SUB ? ALU_SBB : alu;
168 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_1, 0, R_SCRATCH_1, R_SCRATCH_2));
169 #if defined(ARCH_X86)
170 g(gen_frame_load_op(ctx, OP_SIZE_NATIVE, garbage, alu, first_flags, slot_2, lo_word(OP_SIZE_NATIVE), R_SCRATCH_1));
171 g(gen_frame_load_op(ctx, OP_SIZE_NATIVE, garbage, second_alu, second_flags, slot_2, hi_word(OP_SIZE_NATIVE), R_SCRATCH_2));
173 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_2, 0, R_SCRATCH_3, R_SCRATCH_4));
174 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, alu, R_SCRATCH_1, R_SCRATCH_1, R_SCRATCH_3, first_flags));
175 #if defined(ARCH_PARISC)
176 if (mode == MODE_INT) {
177 gen_insn(INSN_ALU_FLAGS_TRAP, OP_SIZE_NATIVE, second_alu, ALU_WRITES_FLAGS(second_alu, false));
178 gen_one(R_SCRATCH_2);
179 gen_one(R_SCRATCH_2);
180 gen_one(R_SCRATCH_4);
185 gen_insn(first_flags ? INSN_ALU_FLAGS : INSN_ALU, OP_SIZE_NATIVE, second_alu, second_flags | ALU_WRITES_FLAGS(second_alu, false));
186 gen_one(R_SCRATCH_2);
187 gen_one(R_SCRATCH_2);
188 gen_one(R_SCRATCH_4);
191 #if !defined(ARCH_PARISC)
192 if (mode == MODE_INT) {
193 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_O, 0);
197 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, R_SCRATCH_1, R_SCRATCH_2));
201 if ((ARCH_HAS_FLAGS || ARCH_SUPPORTS_TRAPS) && slot_2 == slot_r && slot_1 != slot_2 && alu_is_commutative(alu)) {
206 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
207 #if defined(ARCH_POWER)
208 && op_size == OP_SIZE_NATIVE
212 unsigned undo_alu = alu == ALU_ADD ? ALU_SUB : ALU_ADD;
213 if (ctx->registers[slot_1] >= 0) {
214 unsigned reg1 = ctx->registers[slot_1];
215 if (ctx->registers[slot_2] >= 0) {
216 unsigned reg2 = ctx->registers[slot_2];
217 if (mode == MODE_INT && ARCH_SUPPORTS_TRAPS) {
218 gen_insn(INSN_ALU_TRAP, op_size, alu, ALU_WRITES_FLAGS(alu, false));
222 if (ARCH_TRAP_BEFORE) {
226 ce = alloc_undo_label(ctx);
229 gen_four(ce->undo_label);
233 g(gen_3address_alu(ctx, i_size(op_size), alu, reg1, reg1, reg2, mode == MODE_INT));
234 if (mode == MODE_INT) {
235 ce = alloc_undo_label(ctx);
238 gen_insn(INSN_JMP_COND, i_size_cmp(op_size), COND_O, 0);
239 gen_four(ce->undo_label);
241 ce->undo_opcode = INSN_ALU + ARCH_PARTIAL_ALU(op_size);
242 ce->undo_op_size = i_size(op_size);
243 ce->undo_aux = undo_alu;
244 ce->undo_writes_flags = ALU_WRITES_FLAGS(undo_alu, false);
245 ce->undo_parameters[0] = reg1;
246 ce->undo_parameters[1] = reg1;
247 ce->undo_parameters[2] = reg2;
248 ce->undo_parameters_len = 3;
252 #if defined(ARCH_S390) || defined(ARCH_X86)
255 int64_t offset = (size_t)slot_2 * slot_size;
256 g(gen_address(ctx, R_FRAME, offset, IMM_PURPOSE_LDR_OFFSET, i_size(op_size)));
257 gen_insn(INSN_ALU + ARCH_PARTIAL_ALU(op_size), i_size(op_size), alu, 1);
260 gen_address_offset();
261 if (mode == MODE_INT) {
262 ce = alloc_undo_label(ctx);
265 ce->undo_opcode = INSN_ALU + ARCH_PARTIAL_ALU(op_size);
266 ce->undo_op_size = i_size(op_size);
267 ce->undo_aux = undo_alu;
268 ce->undo_writes_flags = ARCH_HAS_FLAGS;
269 m = mark_params(ctx);
272 gen_address_offset();
273 copy_params(ctx, ce, m);
274 gen_insn(INSN_JMP_COND, i_size_cmp(op_size), COND_O, 0);
275 gen_four(ce->undo_label);
281 #if defined(ARCH_X86)
285 int64_t offset = (size_t)slot_1 * slot_size;
286 g(gen_frame_get(ctx, op_size, garbage, slot_2, 0, R_SCRATCH_1, ®2));
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);
289 gen_address_offset();
290 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);
301 gen_address_offset();
302 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);
313 #if defined(ARCH_X86)
315 #elif defined(ARCH_S390)
316 if (op_size >= OP_SIZE_4)
321 if (mode == MODE_INT) {
322 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
324 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, slot_2, R_SCRATCH_1);
326 g(gen_frame_load(ctx, op_size, garbage, slot_1, 0, target));
327 g(gen_frame_load_op(ctx, op_size, garbage, alu, mode == MODE_INT, slot_2, 0, target));
328 goto check_ovf_store;
330 op_size_flags = !ARCH_HAS_FLAGS && !ARCH_SUPPORTS_TRAPS ? OP_SIZE_NATIVE : OP_SIZE_4;
331 #if defined(ARCH_POWER)
332 op_size_flags = OP_SIZE_NATIVE;
334 g(gen_frame_get(ctx, op_size, mode == MODE_INT && (op_size < op_size_flags || ARCH_SUPPORTS_TRAPS) ? sign_x : garbage, slot_1, 0, R_SCRATCH_1, ®1));
335 g(gen_frame_get(ctx, op_size, mode == MODE_INT && (op_size < op_size_flags || ARCH_SUPPORTS_TRAPS) ? sign_x : garbage, slot_2, 0, R_SCRATCH_2, ®2));
337 if (mode == MODE_INT && op_size >= OP_SIZE_4) {
338 if (ARCH_SUPPORTS_TRAPS) {
339 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
340 gen_insn(INSN_ALU_TRAP, op_size, alu, ALU_WRITES_FLAGS(alu, false));
345 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
348 if (op_size >= OP_SIZE_NATIVE) {
349 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_3);
350 g(gen_3address_alu(ctx, i_size(op_size), alu, target, reg1, reg2, 0));
351 #if defined(ARCH_IA64)
352 g(gen_3address_alu(ctx, i_size(op_size), ALU_XOR, R_SCRATCH_1, reg1, reg2, 0));
353 g(gen_3address_alu(ctx, i_size(op_size), ALU_XOR, R_SCRATCH_2, reg2, target, 0));
354 if (alu == ALU_ADD) {
355 g(gen_3address_alu(ctx, i_size(op_size), ALU_ANDN, R_SCRATCH_1, R_SCRATCH_2, R_SCRATCH_1, 0));
357 g(gen_3address_alu(ctx, i_size(op_size), ALU_ANDN, R_SCRATCH_1, R_SCRATCH_1, R_SCRATCH_2, 0));
359 g(gen_cmp_test_jmp(ctx, INSN_TEST, i_size(op_size), R_SCRATCH_1, R_SCRATCH_1, COND_S, label_ovf));
361 gen_insn(INSN_CMP_DEST_REG, i_size(op_size), COND_L, 0);
362 gen_one(R_SCRATCH_1);
363 if (alu == ALU_ADD) {
371 g(gen_imm(ctx, 0, IMM_PURPOSE_CMP, i_size(op_size)));
372 gen_insn(INSN_CMP_DEST_REG, i_size(op_size), COND_L, 0);
373 gen_one(R_SCRATCH_2);
377 g(gen_cmp_test_jmp(ctx, INSN_CMP, i_size(op_size), R_SCRATCH_1, R_SCRATCH_2, COND_NE, label_ovf));
379 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
384 if (mode == MODE_INT) {
385 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
386 } else if (!ARCH_IS_3ADDRESS(alu, mode == MODE_INT && op_size >= op_size_flags) && !alu_is_commutative(alu)) {
387 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, slot_2, R_SCRATCH_1);
389 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
391 g(gen_3address_alu(ctx, i_size(op_size), alu, target, reg1, reg2, mode == MODE_INT && op_size >= op_size_flags));
393 if (mode == MODE_INT && unlikely(op_size < op_size_flags)) {
394 g(gen_cmp_extended(ctx, op_size_flags, op_size, target, R_SCRATCH_2, label_ovf));
397 if (mode == MODE_INT) {
398 gen_insn(INSN_JMP_COND, op_size, COND_O, 0);
401 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
409 size_t attr_unused offset;
410 uint8_t attr_unused long_imm;
411 if (unlikely(op_size > OP_SIZE_NATIVE) || unlikely(!ARCH_HAS_MUL)) {
412 if (mode == MODE_INT) {
413 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));
416 #if defined(ARCH_X86)
417 g(gen_frame_load(ctx, OP_SIZE_NATIVE, garbage, slot_1, hi_word(OP_SIZE_NATIVE), R_CX));
418 g(gen_frame_load(ctx, OP_SIZE_NATIVE, garbage, slot_2, hi_word(OP_SIZE_NATIVE), R_AX));
419 g(gen_frame_load_op(ctx, OP_SIZE_NATIVE, garbage, ALU_MUL, true, slot_2, lo_word(OP_SIZE_NATIVE), R_CX));
420 g(gen_frame_load_op(ctx, OP_SIZE_NATIVE, garbage, ALU_MUL, true, slot_1, lo_word(OP_SIZE_NATIVE), R_AX));
421 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_ADD, R_CX, R_CX, R_AX, 0));
422 g(gen_frame_load(ctx, OP_SIZE_NATIVE, garbage, slot_2, lo_word(OP_SIZE_NATIVE), R_AX));
424 offset = (size_t)slot_1 * slot_size + lo_word(OP_SIZE_NATIVE);
425 g(gen_address(ctx, R_FRAME, offset, IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
426 gen_insn(INSN_MUL_L, OP_SIZE_NATIVE, 0, 1);
430 gen_address_offset();
432 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_ADD, R_DX, R_DX, R_CX, 0));
434 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, R_AX, R_DX));
437 #elif defined(ARCH_ARM32)
438 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_1, 0, R_SCRATCH_1, R_SCRATCH_2));
439 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_2, 0, R_SCRATCH_3, R_SCRATCH_4));
441 g(gen_mov(ctx, OP_SIZE_NATIVE, R_SCRATCH_NA_1, R_SCRATCH_1));
443 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_MUL, R_SCRATCH_4, R_SCRATCH_1, R_SCRATCH_4, 0));
445 gen_insn(INSN_MADD, OP_SIZE_NATIVE, 0, 0);
446 gen_one(R_SCRATCH_2);
447 gen_one(R_SCRATCH_3);
448 gen_one(R_SCRATCH_2);
449 gen_one(R_SCRATCH_4);
451 gen_insn(INSN_MUL_L, OP_SIZE_NATIVE, 0, 0);
452 gen_one(R_SCRATCH_1);
453 gen_one(R_SCRATCH_4);
454 gen_one(R_SCRATCH_NA_1);
455 gen_one(R_SCRATCH_3);
457 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_ADD, R_SCRATCH_2, R_SCRATCH_2, R_SCRATCH_4, 0));
459 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, R_SCRATCH_1, R_SCRATCH_2));
462 #elif defined(ARCH_ARM64)
463 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_1, 0, R_SCRATCH_1, R_SCRATCH_2));
464 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_2, 0, R_SCRATCH_3, R_SCRATCH_4));
466 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_UMULH, R_SCRATCH_NA_1, R_SCRATCH_1, R_SCRATCH_3, 0));
468 gen_insn(INSN_MADD, OP_SIZE_NATIVE, 0, 0);
469 gen_one(R_SCRATCH_NA_1);
470 gen_one(R_SCRATCH_2);
471 gen_one(R_SCRATCH_3);
472 gen_one(R_SCRATCH_NA_1);
474 gen_insn(INSN_MADD, OP_SIZE_NATIVE, 0, 0);
475 gen_one(R_SCRATCH_2);
476 gen_one(R_SCRATCH_1);
477 gen_one(R_SCRATCH_4);
478 gen_one(R_SCRATCH_NA_1);
480 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_MUL, R_SCRATCH_1, R_SCRATCH_1, R_SCRATCH_3, 0));
482 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, R_SCRATCH_1, R_SCRATCH_2));
486 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));
491 #if defined(ARCH_X86)
492 if (mode == MODE_INT) {
493 if (op_size != OP_SIZE_1 && slot_r == slot_1 && ctx->registers[slot_1] >= 0) {
495 target = ctx->registers[slot_1];
496 g(gen_mov(ctx, op_size, R_SCRATCH_1, target));
497 g(gen_frame_load_op(ctx, op_size, garbage, ALU_MUL, mode == MODE_INT, slot_2, 0, target));
498 ce = alloc_undo_label(ctx);
501 ce->undo_opcode = INSN_MOV;
502 ce->undo_op_size = op_size;
504 ce->undo_writes_flags = 0;
505 ce->undo_parameters[0] = target;
506 ce->undo_parameters[1] = R_SCRATCH_1;
507 ce->undo_parameters_len = 2;
508 gen_insn(INSN_JMP_COND, op_size, COND_O, 0);
509 gen_four(ce->undo_label);
512 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
514 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, slot_2, R_SCRATCH_1);
516 if (op_size == OP_SIZE_1)
517 target = R_SCRATCH_1;
518 g(gen_frame_load(ctx, op_size, garbage, slot_1, 0, target));
519 g(gen_frame_load_op(ctx, op_size, garbage, ALU_MUL, mode == MODE_INT, slot_2, 0, target));
520 if (mode == MODE_INT) {
521 gen_insn(INSN_JMP_COND, op_size, COND_O, 0);
524 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
527 #if defined(ARCH_ALPHA)
528 if (mode == MODE_INT && op_size >= OP_SIZE_4 && ARCH_SUPPORTS_TRAPS) {
529 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
530 g(gen_frame_get(ctx, op_size, garbage, slot_1, 0, R_SCRATCH_1, ®1));
531 g(gen_frame_get(ctx, op_size, garbage, slot_2, 0, R_SCRATCH_2, ®2));
533 gen_insn(INSN_ALU_TRAP, op_size, ALU_MUL, ALU_WRITES_FLAGS(ALU_MUL, false));
538 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
543 #if defined(ARCH_ARM32)
544 if (mode == MODE_INT && op_size == OP_SIZE_4) {
545 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_3);
546 g(gen_frame_get(ctx, op_size, garbage, slot_1, 0, R_SCRATCH_1, ®1));
547 g(gen_frame_get(ctx, op_size, garbage, slot_2, 0, R_SCRATCH_2, ®2));
549 gen_insn(INSN_MUL_L, OP_SIZE_NATIVE, 0, 0);
551 gen_one(R_SCRATCH_4);
555 gen_insn(INSN_CMP, OP_SIZE_NATIVE, 0, 1);
556 gen_one(R_SCRATCH_4);
557 gen_one(ARG_SHIFTED_REGISTER);
558 gen_one(ARG_SHIFT_ASR | 0x1f);
561 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_NE, 0);
564 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
569 #if defined(ARCH_ARM64)
570 if (mode == MODE_INT && op_size == OP_SIZE_4) {
571 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
572 g(gen_frame_get(ctx, op_size, op_size < OP_SIZE_4 ? sign_x : garbage, slot_1, 0, R_SCRATCH_1, ®1));
573 g(gen_frame_get(ctx, op_size, op_size < OP_SIZE_4 ? sign_x : garbage, slot_2, 0, R_SCRATCH_2, ®2));
574 gen_insn(INSN_ALU, OP_SIZE_8, ALU_MUL, ALU_WRITES_FLAGS(ALU_MUL, false));
576 gen_one(ARG_EXTENDED_REGISTER);
577 gen_one(ARG_EXTEND_SXTW);
579 gen_one(ARG_EXTENDED_REGISTER);
580 gen_one(ARG_EXTEND_SXTW);
583 gen_insn(INSN_CMP, OP_SIZE_8, 0, 1);
585 gen_one(ARG_EXTENDED_REGISTER);
586 gen_one(ARG_EXTEND_SXTW);
589 gen_insn(INSN_JMP_COND, OP_SIZE_8, COND_NE, 0);
592 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
596 if (mode == MODE_INT && op_size == OP_SIZE_8) {
597 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
598 g(gen_frame_get(ctx, op_size, garbage, slot_1, 0, R_SCRATCH_1, ®1));
599 g(gen_frame_get(ctx, op_size, garbage, slot_2, 0, R_SCRATCH_2, ®2));
600 g(gen_3address_alu(ctx, OP_SIZE_8, ALU_SMULH, R_SCRATCH_3, reg1, reg2, 0));
602 g(gen_3address_alu(ctx, OP_SIZE_8, ALU_MUL, target, reg1, reg2, 0));
604 gen_insn(INSN_CMP, OP_SIZE_8, 0, 1);
605 gen_one(R_SCRATCH_3);
606 gen_one(ARG_SHIFTED_REGISTER);
607 gen_one(ARG_SHIFT_ASR | 0x3f);
610 gen_insn(INSN_JMP_COND, OP_SIZE_8, COND_NE, 0);
613 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
618 #if defined(ARCH_POWER)
619 if (mode == MODE_INT && op_size >= OP_SIZE_4) {
620 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
621 g(gen_frame_get(ctx, op_size, garbage, slot_1, 0, R_SCRATCH_1, ®1));
622 g(gen_frame_get(ctx, op_size, garbage, slot_2, 0, R_SCRATCH_2, ®2));
624 g(gen_3address_alu(ctx, op_size, ALU_MUL, target, reg1, reg2, 1));
626 gen_insn(INSN_JMP_COND, op_size, COND_O, 0);
629 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
634 #if defined(ARCH_LOONGARCH64) || (defined(ARCH_MIPS) && MIPS_R6) || defined(ARCH_RISCV64)
635 if (mode == MODE_INT && op_size == OP_SIZE_NATIVE) {
636 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
637 g(gen_frame_get(ctx, op_size, garbage, slot_1, 0, R_SCRATCH_1, ®1));
638 g(gen_frame_get(ctx, op_size, garbage, slot_2, 0, R_SCRATCH_2, ®2));
640 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_SMULH, R_SCRATCH_3, reg1, reg2, 0));
642 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_MUL, target, reg1, reg2, 0));
644 g(gen_3address_rot_imm(ctx, OP_SIZE_NATIVE, ROT_SAR, R_SCRATCH_4, target, (8U << OP_SIZE_NATIVE) - 1, 0));
646 g(gen_cmp_test_jmp(ctx, INSN_CMP, OP_SIZE_NATIVE, R_SCRATCH_3, R_SCRATCH_4, COND_NE, label_ovf));
648 g(gen_frame_store(ctx, OP_SIZE_NATIVE, slot_r, 0, target));
653 #if defined(ARCH_S390)
654 if (mode == MODE_INT && op_size >= OP_SIZE_4 && likely(cpu_test_feature(CPU_FEATURE_misc_insn_ext_2))) {
655 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
656 g(gen_frame_load(ctx, op_size, sign_x, slot_1, 0, target));
657 g(gen_frame_load_op(ctx, op_size, sign_x, ALU_MUL, 1, slot_2, 0, target));
659 gen_insn(INSN_JMP_COND, op_size, COND_O, 0);
662 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
666 #if (defined(ARCH_MIPS) && !MIPS_R6) || defined(ARCH_S390)
667 #if defined(ARCH_MIPS)
668 if (mode == MODE_INT && op_size >= OP_SIZE_4)
670 #if defined(ARCH_S390)
671 if (mode == MODE_INT && op_size == OP_SIZE_4)
674 #if defined(ARCH_S390)
675 target = R_SCRATCH_1;
677 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
679 g(gen_frame_get(ctx, op_size, sign_x, slot_1, 0, R_SCRATCH_1, ®1));
680 g(gen_frame_get(ctx, op_size, sign_x, slot_2, 0, R_SCRATCH_3, ®2));
682 gen_insn(INSN_MUL_L, op_size, 0, 0);
684 gen_one(R_SCRATCH_2);
688 g(gen_3address_rot_imm(ctx, op_size, ROT_SAR, R_SCRATCH_4, target, (8U << op_size) - 1, false));
690 g(gen_cmp_test_jmp(ctx, INSN_CMP, op_size, R_SCRATCH_2, R_SCRATCH_4, COND_NE, label_ovf));
692 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
696 if (mode == MODE_INT && op_size == OP_SIZE_NATIVE) {
697 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));
701 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
702 if (op_size < OP_SIZE_NATIVE && mode == MODE_INT) {
703 g(gen_frame_get(ctx, op_size, sign_x, slot_1, 0, R_SCRATCH_1, ®1));
704 g(gen_frame_get(ctx, op_size, sign_x, slot_2, 0, R_SCRATCH_2, ®2));
706 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_MUL, target, reg1, reg2, 0));
708 g(gen_frame_load(ctx, op_size, sign_x, slot_1, 0, target));
709 g(gen_frame_load_op(ctx, op_size, sign_x, ALU_MUL, 0, slot_2, 0, target));
712 if (mode == MODE_INT) {
713 g(gen_cmp_extended(ctx, OP_SIZE_NATIVE, op_size, target, R_SCRATCH_2, label_ovf));
716 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
725 uint32_t attr_unused label_skip = 0; /* avoid warning */
726 uint32_t attr_unused label_skip2 = 0; /* avoid warning */
727 uint32_t attr_unused label_end = 0; /* avoid warning */
728 uint32_t attr_unused label_div_0 = 0; /* avoid warning */
729 unsigned attr_unused divide_alu = 0; /* avoid warning */
730 bool attr_unused have_mod = false;
731 bool attr_unused force_sx = false;
732 unsigned attr_unused div_op_size = i_size(op_size);
733 if (unlikely(op_size > OP_SIZE_NATIVE) || unlikely(!ARCH_HAS_DIV)
734 #if defined(ARCH_S390)
735 || !(Z || (op_size <= OP_SIZE_4 && sgn))
739 if (mode == MODE_INT) {
740 upcall = !mod ? offsetof(struct cg_upcall_vector_s, INT_binary_divide_int8_t) : offsetof(struct cg_upcall_vector_s, INT_binary_modulo_int8_t);
742 upcall = !mod ? offsetof(struct cg_upcall_vector_s, FIXED_binary_divide_int8_t) : offsetof(struct cg_upcall_vector_s, FIXED_binary_modulo_int8_t);
744 upcall = !mod ? offsetof(struct cg_upcall_vector_s, FIXED_binary_udivide_int8_t) : offsetof(struct cg_upcall_vector_s, FIXED_binary_umodulo_int8_t);
746 g(gen_alu_typed_upcall(ctx, upcall, op_size, slot_1, slot_2, slot_r, mode == MODE_INT ? label_ovf : 0));
749 #if defined(ARCH_X86) || defined(ARCH_S390)
750 if (mode == MODE_FIXED) {
751 label_skip = alloc_label(ctx);
752 if (unlikely(!label_skip))
754 label_end = alloc_label(ctx);
755 if (unlikely(!label_end))
758 label_skip2 = alloc_label(ctx);
759 if (unlikely(!label_skip2))
763 #if defined(ARCH_X86)
764 if (R_SCRATCH_1 != R_AX || R_SCRATCH_2 != R_DX || R_SCRATCH_3 != R_CX)
765 internal(file_line, "gen_alu: bad scratch registers");
767 g(gen_frame_load(ctx, op_size, sgn ? sign_x : zero_x, slot_1, 0, R_SCRATCH_1));
768 g(gen_frame_load(ctx, op_size, sgn ? sign_x : zero_x, slot_2, 0, R_SCRATCH_3));
770 g(gen_jmp_on_zero(ctx, i_size(op_size), R_SCRATCH_3, COND_E, mode == MODE_INT ? label_ovf : label_skip));
774 uint32_t label_not_minus_1;
775 label_not_minus_1 = alloc_label(ctx);
776 if (unlikely(!label_not_minus_1))
779 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, op_size, R_SCRATCH_3, -1, COND_NE, label_not_minus_1));
781 val = -(uint64_t)0x80 << (((1 << op_size) - 1) * 8);
782 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, op_size, R_SCRATCH_1, val, COND_E, mode == MODE_INT ? label_ovf : label_skip2));
784 gen_label(label_not_minus_1);
787 #if defined(ARCH_X86)
788 if (op_size >= OP_SIZE_2) {
790 gen_insn(INSN_CWD + ARCH_PARTIAL_ALU(op_size), op_size, 0, 0);
791 gen_one(R_SCRATCH_2);
792 gen_one(R_SCRATCH_1);
793 if (op_size == OP_SIZE_2)
794 gen_one(R_SCRATCH_2);
796 g(gen_3address_alu(ctx, OP_SIZE_4, ALU_XOR, R_SCRATCH_2, R_SCRATCH_2, R_SCRATCH_2, 0));
799 gen_insn(INSN_DIV_L, op_size, sgn, 1);
800 gen_one(R_SCRATCH_1);
801 gen_one(i_size(op_size) == OP_SIZE_1 ? R_SCRATCH_1 : R_SCRATCH_2);
802 gen_one(R_SCRATCH_1);
803 gen_one(i_size(op_size) == OP_SIZE_1 ? R_SCRATCH_1 : R_SCRATCH_2);
804 gen_one(R_SCRATCH_3);
807 g(gen_load_constant(ctx, R_SCRATCH_2, 0));
808 } else if (op_size <= OP_SIZE_4) {
809 g(gen_3address_rot_imm(ctx, OP_SIZE_NATIVE, ROT_SAR, R_SCRATCH_2, R_SCRATCH_1, (1U << (OP_SIZE_NATIVE + 3)) - 1, false));
811 gen_insn(INSN_DIV_L, i_size(op_size), sgn, 1);
812 gen_one(R_SCRATCH_2);
813 gen_one(R_SCRATCH_1);
814 gen_one(R_SCRATCH_2);
815 gen_one(R_SCRATCH_1);
816 gen_one(R_SCRATCH_3);
818 if (mod && i_size(op_size) == OP_SIZE_1) {
819 g(gen_3address_rot_imm(ctx, OP_SIZE_2, ROT_SHR, R_SCRATCH_1, R_SCRATCH_1, 8, 0));
820 g(gen_frame_store(ctx, op_size, slot_r, 0, R_SCRATCH_1));
822 g(gen_frame_store(ctx, op_size, slot_r, 0, R_SCRATCH_2));
824 g(gen_frame_store(ctx, op_size, slot_r, 0, R_SCRATCH_1));
826 if (mode == MODE_FIXED) {
827 gen_insn(INSN_JMP, 0, 0, 0);
831 gen_label(label_skip2);
834 g(gen_frame_clear(ctx, op_size, slot_r));
836 g(gen_frame_store(ctx, op_size, slot_r, 0, R_SCRATCH_1));
838 gen_insn(INSN_JMP, 0, 0, 0);
842 gen_label(label_skip);
844 g(gen_frame_clear(ctx, op_size, slot_r));
846 g(gen_frame_store(ctx, op_size, slot_r, 0, R_SCRATCH_1));
847 gen_label(label_end);
851 #if defined(ARCH_MIPS)
853 div_op_size = maximum(op_size, OP_SIZE_4);
854 if (op_size == OP_SIZE_4)
857 #if defined(ARCH_POWER)
858 have_mod = cpu_test_feature(CPU_FEATURE_v30);
859 div_op_size = maximum(op_size, OP_SIZE_4);
861 #if defined(ARCH_LOONGARCH64) || defined(ARCH_RISCV64)
863 div_op_size = maximum(op_size, OP_SIZE_4);
865 label_end = alloc_label(ctx);
866 if (unlikely(!label_end))
869 g(gen_frame_get(ctx, op_size, (sgn && op_size < i_size(op_size)) || force_sx ? sign_x : zero_x, slot_1, 0, R_SCRATCH_1, ®1));
870 g(gen_frame_get(ctx, op_size, (sgn && op_size < i_size(op_size)) || force_sx ? sign_x : zero_x, slot_2, 0, R_SCRATCH_2, ®2));
871 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_3);
873 if (ARCH_PREFERS_SX(op_size) && !sgn && op_size < i_size(op_size)) {
874 g(gen_extend(ctx, op_size, zero_x, R_SCRATCH_1, reg1));
876 g(gen_extend(ctx, op_size, zero_x, R_SCRATCH_2, reg2));
880 if (mode == MODE_INT) {
881 g(gen_jmp_on_zero(ctx, i_size(op_size), reg2, COND_E, label_ovf));
884 uint32_t label_not_minus_1;
885 label_not_minus_1 = alloc_label(ctx);
886 if (unlikely(!label_not_minus_1))
889 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, i_size(op_size), reg2, -1, COND_NE, label_not_minus_1));
891 val = 0xFFFFFFFFFFFFFF80ULL << (((1 << op_size) - 1) * 8);
892 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, i_size(op_size), reg1, val, COND_E, label_ovf));
894 gen_label(label_not_minus_1);
897 #if !(defined(ARCH_ARM) && ARM_ASM_DIV_NO_TRAP)
899 g(gen_load_constant(ctx, target, 0));
901 g(gen_mov(ctx, OP_SIZE_NATIVE, target, reg1));
903 g(gen_jmp_on_zero(ctx, i_size(op_size), reg2, COND_E, label_end));
906 uint32_t label_not_minus_1;
907 label_not_minus_1 = alloc_label(ctx);
908 if (unlikely(!label_not_minus_1))
911 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, i_size(op_size), reg2, -1, COND_NE, label_not_minus_1));
914 g(gen_mov(ctx, OP_SIZE_NATIVE, target, reg1));
916 g(gen_load_constant(ctx, target, 0));
919 val = 0xFFFFFFFFFFFFFF80ULL << (((1 << op_size) - 1) * 8);
920 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, i_size(op_size), reg1, val, COND_E, label_end));
922 gen_label(label_not_minus_1);
926 if (mod && have_mod) {
927 g(gen_3address_alu(ctx, div_op_size, sgn ? ALU_SREM : ALU_UREM, target, reg1, reg2, 0));
929 g(gen_3address_alu(ctx, div_op_size, sgn ? ALU_SDIV : ALU_UDIV, target, reg1, reg2, 0));
932 if (mod && !have_mod) {
933 #if defined(ARCH_ARM)
934 gen_insn(INSN_MADD, i_size(op_size), 1, 0);
940 g(gen_3address_alu(ctx, i_size(op_size), ALU_MUL, R_SCRATCH_2, reg2, target, 0));
941 g(gen_3address_alu(ctx, i_size(op_size), ALU_SUB, target, reg1, R_SCRATCH_2, 0));
945 gen_label(label_end);
946 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
957 if (unlikely(op_size > OP_SIZE_NATIVE)) {
959 if (mode == MODE_FIXED) {
961 case ROT_SHL: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_shl_,TYPE_INT_MAX));
963 case ROT_SAR: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_shr_,TYPE_INT_MAX));
965 case ROT_SHR: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_ushr_,TYPE_INT_MAX));
967 case ROT_ROL: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_rol_,TYPE_INT_MAX));
969 case ROT_ROR: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_ror_,TYPE_INT_MAX));
971 default: internal(file_line, "do_alu: invalid shift %u", alu);
975 case ROT_SHL: upcall = offsetof(struct cg_upcall_vector_s, cat(INT_binary_shl_,TYPE_INT_MAX));
977 case ROT_SAR: upcall = offsetof(struct cg_upcall_vector_s, cat(INT_binary_shr_,TYPE_INT_MAX));
979 default: internal(file_line, "do_alu: invalid shift %u", alu);
982 g(gen_alu_upcall(ctx, upcall, slot_1, slot_2, slot_r, mode == MODE_INT ? label_ovf : 0));
985 op_s = i_size_rot(op_size);
986 #if defined(ARCH_X86)
987 if (slot_1 == slot_r && ctx->registers[slot_1] < 0 && !(mode == MODE_INT && alu == ROT_SHL)) {
989 g(gen_frame_load(ctx, op_size, garbage, slot_2, 0, R_SCRATCH_3));
990 if (mode == MODE_INT) {
991 int64_t imm = (8U << op_size) - 1;
992 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, op_size, R_SCRATCH_3, imm, COND_A, label_ovf));
993 } else if ((alu != ROT_ROL && alu != ROT_ROR) && op_size < OP_SIZE_4) {
994 g(gen_3address_alu_imm(ctx, OP_SIZE_1, ALU_AND, R_SCRATCH_3, R_SCRATCH_3, (8U << op_size) - 1, 0));
996 offset = (size_t)slot_1 * slot_size;
997 g(gen_address(ctx, R_FRAME, offset, IMM_PURPOSE_LDR_OFFSET, op_size));
998 gen_insn(INSN_ROT + ARCH_PARTIAL_ALU(op_size), op_size, alu, 1);
999 gen_address_offset();
1000 gen_address_offset();
1001 gen_one(R_SCRATCH_3);
1004 if (mode == MODE_INT && alu == ROT_SHL && op_size < OP_SIZE_NATIVE)
1007 must_mask = op_size < ARCH_SHIFT_SIZE;
1008 sx = (alu == ROT_SAR && op_size < op_s) || (alu == ROT_SHL && op_size < OP_SIZE_NATIVE && mode == MODE_INT);
1009 #if defined(ARCH_MIPS)
1010 sx |= op_size == OP_SIZE_4;
1012 g(gen_frame_get(ctx, op_size, sx ? sign_x : zero_x, slot_1, 0, R_SCRATCH_1, ®1));
1013 #if defined(ARCH_X86)
1014 if (!ARCH_IS_3ADDRESS_ROT(alu, op_size)) {
1015 g(gen_frame_load(ctx, op_size, garbage, slot_2, 0, R_SCRATCH_3));
1019 g(gen_frame_get(ctx, op_size, garbage, slot_2, 0, R_SCRATCH_3, ®3));
1020 if (ARCH_PREFERS_SX(op_size) && !sx && op_size < op_s) {
1021 g(gen_extend(ctx, op_size, zero_x, R_SCRATCH_1, reg1));
1025 if (mode == MODE_INT) {
1026 int64_t imm = (8U << op_size) - 1;
1027 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, i_size_cmp(op_size), reg3, imm, COND_A, label_ovf));
1029 #if defined(ARCH_ARM)
1030 if (alu == ROT_ROL) {
1031 g(gen_2address_alu1(ctx, OP_SIZE_4, ALU1_NEG, R_SCRATCH_3, reg3, 0));
1036 #if defined(ARCH_LOONGARCH64)
1037 if (alu == ROT_ROL && op_size >= OP_SIZE_4) {
1038 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_NEG, R_SCRATCH_3, reg3, 0));
1043 #if defined(ARCH_MIPS)
1044 if (MIPS_HAS_ROT && alu == ROT_ROL && op_size >= OP_SIZE_4) {
1045 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_NEG, R_SCRATCH_3, reg3, 0));
1050 #if defined(ARCH_POWER)
1051 if (alu == ROT_ROR && op_size >= OP_SIZE_4) {
1052 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_NEG, R_SCRATCH_3, reg3, 0));
1057 #if defined(ARCH_S390)
1058 if (Z && alu == ROT_ROR && op_size >= OP_SIZE_4) {
1059 g(gen_2address_alu1(ctx, OP_SIZE_4, ALU1_NEG, R_SCRATCH_3, reg3, 0));
1065 g(gen_3address_alu_imm(ctx, i_size(OP_SIZE_4), ALU_AND, R_SCRATCH_3, reg3, (8U << op_size) - 1, 0));
1070 #if defined(ARCH_X86)
1071 if (mode == MODE_INT && alu == ROT_SHL) {
1072 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_2);
1074 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, slot_2, R_SCRATCH_2);
1076 g(gen_3address_rot(ctx, op_s, alu, target, reg1, reg3));
1078 if (mode == MODE_INT && alu == ROT_SHL) {
1079 if (op_size < OP_SIZE_NATIVE) {
1080 gen_insn(INSN_MOVSX, op_size, 0, 0);
1081 gen_one(R_SCRATCH_4);
1084 g(gen_cmp_test_jmp(ctx, INSN_CMP, op_s, target, R_SCRATCH_4, COND_NE, label_ovf));
1086 g(gen_3address_rot(ctx, OP_SIZE_NATIVE, ROT_SAR, R_SCRATCH_4, target, reg3));
1088 g(gen_cmp_test_jmp(ctx, INSN_CMP, OP_SIZE_NATIVE, reg1, R_SCRATCH_4, COND_NE, label_ovf));
1091 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1094 #if defined(ARCH_ARM)
1095 if (op_size <= OP_SIZE_2 && alu == ROT_ROR) {
1096 gen_insn(INSN_ALU, OP_SIZE_4, ALU_OR, ALU_WRITES_FLAGS(ALU_OR, false));
1097 gen_one(R_SCRATCH_1);
1099 gen_one(ARG_SHIFTED_REGISTER);
1100 gen_one(ARG_SHIFT_LSL | (8U << op_size));
1102 if (op_size == OP_SIZE_1)
1106 goto do_generic_shift;
1108 #if defined(ARCH_LOONGARCH64)
1109 if (alu == ROT_ROR && op_size >= OP_SIZE_4)
1110 goto do_generic_shift;
1112 #if defined(ARCH_MIPS)
1113 if (MIPS_HAS_ROT && alu == ROT_ROR && op_size >= OP_SIZE_4)
1114 goto do_generic_shift;
1116 #if defined(ARCH_POWER)
1117 if (alu == ROT_ROL && op_size >= OP_SIZE_4)
1118 goto do_generic_shift;
1120 #if defined(ARCH_RISCV64)
1121 if ((alu == ROT_ROL || alu == ROT_ROR) && likely(cpu_test_feature(CPU_FEATURE_zbb))) {
1122 if (likely(op_size >= OP_SIZE_4)) {
1123 goto do_generic_shift;
1127 #if defined(ARCH_S390)
1128 if (Z && alu == ROT_ROL && op_size >= OP_SIZE_4)
1129 goto do_generic_shift;
1131 if (alu == ROT_ROL || alu == ROT_ROR) {
1132 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
1133 g(gen_3address_rot(ctx, op_s, alu == ROT_ROL ? ROT_SHL : ROT_SHR, R_SCRATCH_2, reg1, reg3));
1134 g(gen_2address_alu1(ctx, i_size(OP_SIZE_4), ALU1_NEG, R_SCRATCH_3, reg3, 0));
1136 g(gen_3address_alu_imm(ctx, i_size(OP_SIZE_4), ALU_AND, R_SCRATCH_3, R_SCRATCH_3, (8U << op_size) - 1, 0));
1138 g(gen_3address_rot(ctx, op_s, alu == ROT_ROL ? ROT_SHR : ROT_SHL, target, reg1, R_SCRATCH_3));
1139 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_OR, target, target, R_SCRATCH_2, 0));
1140 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1144 goto do_generic_shift;
1146 if (mode == MODE_INT && alu == ROT_SHL) {
1147 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
1148 #if defined(ARCH_S390)
1149 if (op_size >= OP_SIZE_4) {
1150 g(gen_3address_rot(ctx, op_size, ROT_SAL, target, reg1, reg3));
1152 gen_insn(INSN_JMP_COND, op_size, COND_O, 0);
1153 gen_four(label_ovf);
1156 if (op_size <= OP_SIZE_NATIVE - 1) {
1157 g(gen_3address_rot(ctx, OP_SIZE_NATIVE, alu, target, reg1, reg3));
1159 g(gen_cmp_extended(ctx, OP_SIZE_NATIVE, op_size, target, R_SCRATCH_2, label_ovf));
1161 g(gen_3address_rot(ctx, OP_SIZE_NATIVE, alu, R_SCRATCH_2, reg1, reg3));
1163 g(gen_3address_rot(ctx, OP_SIZE_NATIVE, ROT_SAR, R_SCRATCH_4, R_SCRATCH_2, reg3));
1165 g(gen_cmp_test_jmp(ctx, INSN_CMP, OP_SIZE_NATIVE, reg1, R_SCRATCH_4, COND_NE, label_ovf));
1167 g(gen_frame_store(ctx, op_size, slot_r, 0, R_SCRATCH_2));
1172 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, slot_2, R_SCRATCH_1);
1173 g(gen_3address_rot(ctx, op_s, alu, target, reg1, reg3));
1176 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1183 unsigned attr_unused op_s;
1185 #if defined(ARCH_X86)
1186 if ((alu == BTX_BT || slot_1 == slot_r) && ctx->registers[slot_1] < 0) {
1187 unsigned n_op_size = minimum(op_size, OP_SIZE_NATIVE);
1188 g(gen_frame_get(ctx, n_op_size, garbage, slot_2, 0, R_SCRATCH_1, ®2));
1189 if (mode == MODE_INT) {
1190 int64_t imm = (8U << op_size) - 1;
1191 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, n_op_size, reg2, imm, alu == BTX_BT ? COND_A : COND_AE, label_ovf));
1192 if (unlikely(op_size > OP_SIZE_NATIVE)) {
1193 g(gen_address(ctx, R_FRAME, (size_t)slot_2 * slot_size + hi_word(OP_SIZE_NATIVE), IMM_PURPOSE_STR_OFFSET, OP_SIZE_NATIVE));
1194 gen_insn(INSN_CMP, OP_SIZE_NATIVE, 0, 1);
1195 gen_address_offset();
1198 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_NE, 0);
1199 gen_four(label_ovf);
1202 g(gen_3address_alu_imm(ctx, OP_SIZE_4, ALU_AND, R_SCRATCH_1, reg2, (8U << op_size) - 1, 0));
1205 g(gen_address(ctx, R_FRAME, (size_t)slot_1 * slot_size, IMM_PURPOSE_STR_OFFSET, maximum(n_op_size, OP_SIZE_2)));
1206 if (alu == BTX_BT) {
1207 gen_insn(INSN_BT, maximum(n_op_size, OP_SIZE_2), 0, 1);
1208 gen_address_offset();
1210 g(gen_frame_set_cond(ctx, maximum(n_op_size, OP_SIZE_2), false, COND_B, slot_r));
1212 gen_insn(INSN_BTX, maximum(n_op_size, OP_SIZE_2), alu, 1);
1213 gen_address_offset();
1214 gen_address_offset();
1220 if (unlikely(op_size > OP_SIZE_NATIVE)) {
1222 if (mode == MODE_FIXED) {
1224 case BTX_BTS: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_bts_,TYPE_INT_MAX));
1226 case BTX_BTR: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_btr_,TYPE_INT_MAX));
1228 case BTX_BTC: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_btc_,TYPE_INT_MAX));
1230 case BTX_BT: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_bt_,TYPE_INT_MAX));
1232 default: internal(file_line, "do_alu: invalid bit test %u", alu);
1236 case BTX_BTS: upcall = offsetof(struct cg_upcall_vector_s, cat(INT_binary_bts_,TYPE_INT_MAX));
1238 case BTX_BTR: upcall = offsetof(struct cg_upcall_vector_s, cat(INT_binary_btr_,TYPE_INT_MAX));
1240 case BTX_BTC: upcall = offsetof(struct cg_upcall_vector_s, cat(INT_binary_btc_,TYPE_INT_MAX));
1242 case BTX_BT: upcall = offsetof(struct cg_upcall_vector_s, cat(INT_binary_bt_,TYPE_INT_MAX));
1244 default: internal(file_line, "do_alu: invalid bit test %u", alu);
1247 g(gen_alu_upcall(ctx, upcall, slot_1, slot_2, slot_r, label_ovf));
1250 op_s = minimum(OP_SIZE_NATIVE, ARCH_SHIFT_SIZE);
1251 op_s = maximum(op_s, op_size);
1252 g(gen_frame_get(ctx, op_size, zero_x, slot_1, 0, R_SCRATCH_1, ®1));
1253 g(gen_frame_get(ctx, op_size, garbage, slot_2, 0, R_SCRATCH_2, ®2));
1254 if (mode == MODE_INT) {
1255 int64_t imm = (8U << op_size) - 1;
1256 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, i_size_cmp(op_size), reg2, imm, alu == BTX_BT ? COND_A : COND_AE, label_ovf));
1258 if (alu != BTX_BT) {
1259 if (!ARCH_HAS_BTX(alu, OP_SIZE_NATIVE, false))
1261 need_mask = !ARCH_HAS_BTX(alu, op_size, false);
1263 #if defined(ARCH_X86)
1264 need_mask = op_size < OP_SIZE_2;
1266 if (!ARCH_HAS_BTX(BTX_BTEXT, OP_SIZE_NATIVE, false))
1268 need_mask = !ARCH_HAS_BTX(BTX_BTEXT, op_size, false);
1272 g(gen_3address_alu_imm(ctx, OP_SIZE_4, ALU_AND, R_SCRATCH_2, reg2, (8U << op_size) - 1, 0));
1275 if (alu == BTX_BT) {
1276 #if defined(ARCH_X86)
1277 gen_insn(INSN_BT, maximum(op_size, OP_SIZE_2), 0, 1);
1281 g(gen_frame_set_cond(ctx, maximum(op_size, OP_SIZE_2), false, COND_B, slot_r));
1283 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
1284 gen_insn(INSN_BTX, need_mask ? OP_SIZE_NATIVE : op_size, BTX_BTEXT, 0);
1289 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, target));
1292 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, slot_2, R_SCRATCH_1);
1293 #if defined(ARCH_X86)
1295 target = R_SCRATCH_1;
1296 if (target != reg1) {
1297 g(gen_mov(ctx, op_size, target, reg1));
1300 gen_insn(INSN_BTX, maximum(op_size, OP_SIZE_2), alu, 1);
1302 gen_insn(INSN_BTX, need_mask ? OP_SIZE_NATIVE : op_size, alu, 0);
1308 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1314 if (mode == MODE_FIXED && op_size < ARCH_SHIFT_SIZE) {
1315 g(gen_3address_alu_imm(ctx, i_size(OP_SIZE_4), ALU_AND, R_SCRATCH_2, reg2, (8U << op_size) - 1, 0));
1318 g(gen_load_constant(ctx, R_SCRATCH_3, 1));
1320 g(gen_3address_rot(ctx, op_s, ROT_SHL, R_SCRATCH_3, R_SCRATCH_3, reg2));
1325 #if defined(ARCH_S390) || defined(ARCH_POWER)
1326 g(gen_3address_alu(ctx, i_size(op_size), ALU_AND, R_SCRATCH_1, reg1, R_SCRATCH_3, 1));
1328 gen_insn(INSN_TEST, i_size(op_size), 0, 1);
1330 gen_one(R_SCRATCH_3);
1332 g(gen_frame_set_cond(ctx, i_size_cmp(op_size), false, COND_NE, slot_r));
1334 g(gen_3address_alu(ctx, i_size(op_size), ALU_AND, R_SCRATCH_1, reg1, R_SCRATCH_3, 0));
1335 g(gen_frame_cmp_imm_set_cond_reg(ctx, i_size(op_size), R_SCRATCH_1, 0, COND_NE, slot_r));
1339 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
1340 g(gen_3address_alu(ctx, i_size(op_size), ALU_OR, target, reg1, R_SCRATCH_3, 0));
1343 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
1344 if (!ARCH_HAS_ANDN) {
1345 g(gen_3address_alu_imm(ctx, i_size(op_size), ALU_XOR, R_SCRATCH_3, R_SCRATCH_3, -1, 0));
1347 g(gen_3address_alu(ctx, i_size(op_size), ALU_AND, target, reg1, R_SCRATCH_3, 0));
1350 g(gen_3address_alu(ctx, i_size(op_size), ALU_ANDN, target, reg1, R_SCRATCH_3, 0));
1353 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
1354 g(gen_3address_alu(ctx, i_size(op_size), ALU_XOR, target, reg1, R_SCRATCH_3, 0));
1357 internal(file_line, "gen_alu: unsupported bit test %u", alu);
1360 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1368 if (unlikely(op_size > OP_SIZE_NATIVE)) {
1369 size_t attr_unused upcall;
1373 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_1, 0, R_SCRATCH_1, R_SCRATCH_2));
1374 g(gen_frame_load_op(ctx, OP_SIZE_NATIVE, garbage, ALU_XOR, 0, slot_2, lo_word(OP_SIZE_NATIVE), R_SCRATCH_1));
1375 g(gen_frame_load_op(ctx, OP_SIZE_NATIVE, garbage, ALU_XOR, 0, slot_2, hi_word(OP_SIZE_NATIVE), R_SCRATCH_2));
1376 #if defined(ARCH_ARM64)
1377 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_OR, R_SCRATCH_1, R_SCRATCH_1, R_SCRATCH_2, 0));
1379 gen_insn(INSN_CMP, OP_SIZE_NATIVE, 0, 1);
1380 gen_one(R_SCRATCH_1);
1384 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_OR, R_SCRATCH_1, R_SCRATCH_1, R_SCRATCH_2, ARCH_HAS_FLAGS));
1387 g(gen_frame_set_cond(ctx, OP_SIZE_NATIVE, false, alu, slot_r));
1389 g(gen_frame_cmp_imm_set_cond_reg(ctx, OP_SIZE_NATIVE, R_SCRATCH_1, 0, alu, slot_r));
1392 #if defined(ARCH_X86) || defined(ARCH_ARM)
1395 g(gen_frame_load(ctx, OP_SIZE_NATIVE, garbage, slot_2, lo_word(OP_SIZE_NATIVE), R_SCRATCH_2));
1396 g(gen_frame_load(ctx, OP_SIZE_NATIVE, garbage, slot_1, hi_word(OP_SIZE_NATIVE), R_SCRATCH_1));
1397 g(gen_frame_load_cmp(ctx, OP_SIZE_NATIVE, false, garbage, true, slot_1, lo_word(OP_SIZE_NATIVE), R_SCRATCH_2));
1398 g(gen_frame_load_op(ctx, OP_SIZE_NATIVE, garbage, ALU_SBB, 1, slot_2, hi_word(OP_SIZE_NATIVE), R_SCRATCH_1));
1399 g(gen_frame_set_cond(ctx, OP_SIZE_NATIVE, false, alu, slot_r));
1403 g(gen_frame_load(ctx, OP_SIZE_NATIVE, garbage, slot_1, lo_word(OP_SIZE_NATIVE), R_SCRATCH_2));
1404 g(gen_frame_load(ctx, OP_SIZE_NATIVE, garbage, slot_2, hi_word(OP_SIZE_NATIVE), R_SCRATCH_1));
1405 g(gen_frame_load_cmp(ctx, OP_SIZE_NATIVE, false, garbage, true, slot_2, lo_word(OP_SIZE_NATIVE), R_SCRATCH_2));
1406 g(gen_frame_load_op(ctx, OP_SIZE_NATIVE, garbage, ALU_SBB, 1, slot_1, hi_word(OP_SIZE_NATIVE), R_SCRATCH_1));
1407 g(gen_frame_set_cond(ctx, OP_SIZE_NATIVE, false, alu == COND_LE ? COND_GE : COND_AE, slot_r));
1410 case COND_L: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_less_,TYPE_INT_MAX)); goto do_upcall;
1411 case COND_B: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_uless_,TYPE_INT_MAX)); goto do_upcall;
1412 case COND_LE: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_less_equal_,TYPE_INT_MAX)); goto do_upcall;
1413 case COND_BE: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_uless_equal_,TYPE_INT_MAX)); goto do_upcall;
1414 do_upcall: g(gen_alu_upcall(ctx, upcall, slot_1, slot_2, slot_r, 0));
1418 internal(file_line, "gen_alu: unsupported condition %u", alu);
1422 #if defined(ARCH_X86)
1423 g(gen_frame_get(ctx, op_size, garbage, slot_1, 0, R_SCRATCH_1, ®1));
1424 g(gen_frame_load_cmp_set_cond(ctx, op_size, garbage, slot_2, 0, reg1, alu, slot_r));
1426 g(gen_frame_get(ctx, op_size, op_size == i_size_cmp(op_size) + (unsigned)zero ? garbage : alu == COND_L || alu == COND_LE || ARCH_PREFERS_SX(op_size) ? sign_x : zero_x, slot_1, 0, R_SCRATCH_1, ®1));
1427 g(gen_frame_load_cmp_set_cond(ctx, op_size, alu == COND_L || alu == COND_LE || ARCH_PREFERS_SX(op_size) ? sign_x : zero_x, slot_2, 0, reg1, alu, slot_r));
1433 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)
1436 unsigned reg1, target;
1438 case MODE_FIXED: switch (op) {
1439 case OPCODE_FIXED_OP_not: alu = ALU1_NOT; goto do_alu;
1440 case OPCODE_FIXED_OP_neg: alu = ALU1_NEG; goto do_alu;
1441 case OPCODE_FIXED_OP_inc: alu = ALU1_INC; goto do_alu;
1442 case OPCODE_FIXED_OP_dec: alu = ALU1_DEC; goto do_alu;
1443 case OPCODE_FIXED_OP_bswap:
1444 case OPCODE_FIXED_OP_bswap_alt1: alu = ALU1_BSWAP; goto do_bswap;
1445 case OPCODE_FIXED_OP_brev:
1446 case OPCODE_FIXED_OP_brev_alt1: alu = ALU1_BREV; goto do_brev;
1447 case OPCODE_FIXED_OP_bsf:
1448 case OPCODE_FIXED_OP_bsf_alt1: alu = ALU1_BSF; goto do_bsf_bsr_popcnt;
1449 case OPCODE_FIXED_OP_bsr:
1450 case OPCODE_FIXED_OP_bsr_alt1: alu = ALU1_BSR; goto do_bsf_bsr_popcnt;
1451 case OPCODE_FIXED_OP_popcnt:
1452 case OPCODE_FIXED_OP_popcnt_alt1: alu = ALU1_POPCNT; goto do_bsf_bsr_popcnt;
1453 case OPCODE_FIXED_OP_to_int: goto do_fixed_conv;
1454 case OPCODE_FIXED_OP_from_int: goto do_fixed_conv;
1455 case OPCODE_FIXED_OP_uto_int: goto conv_uto_int;
1456 case OPCODE_FIXED_OP_ufrom_int: goto conv_ufrom_int;
1457 default: internal(file_line, "gen_alu1: unsupported fixed operation %u", op);
1459 case MODE_INT: switch (op) {
1460 case OPCODE_INT_OP_not: alu = ALU1_NOT; mode = MODE_FIXED; goto do_alu;
1461 case OPCODE_INT_OP_neg: alu = ALU1_NEG; goto do_alu;
1462 case OPCODE_INT_OP_inc: alu = ALU1_INC; goto do_alu;
1463 case OPCODE_INT_OP_dec: alu = ALU1_DEC; goto do_alu;
1464 case OPCODE_INT_OP_bsf: alu = ALU1_BSF; goto do_bsf_bsr_popcnt;
1465 case OPCODE_INT_OP_bsr: alu = ALU1_BSR; goto do_bsf_bsr_popcnt;
1466 case OPCODE_INT_OP_popcnt:
1467 case OPCODE_INT_OP_popcnt_alt1: alu = ALU1_POPCNT; goto do_bsf_bsr_popcnt;
1468 case OPCODE_INT_OP_to_int: goto do_conv;
1469 case OPCODE_INT_OP_from_int: goto do_conv;
1470 default: internal(file_line, "gen_alu1: unsupported int operation %u", op);
1472 case MODE_BOOL: switch (op) {
1473 case OPCODE_BOOL_OP_not: goto do_bool_not;
1474 default: internal(file_line, "gen_alu1: unsupported bool operation %u", op);
1477 internal(file_line, "gen_alu1: unsupported mode %u", mode);
1483 bool arch_use_flags = ARCH_HAS_FLAGS;
1485 #if defined(ARCH_POWER)
1486 arch_use_flags = false;
1488 if (op_size > OP_SIZE_NATIVE) {
1489 #if !defined(ARCH_X86) && !defined(ARCH_ARM) && !defined(ARCH_POWER)
1490 if (alu == ALU1_NEG) {
1491 if (mode == MODE_FIXED)
1492 g(gen_alu_upcall(ctx, offsetof(struct cg_upcall_vector_s, cat(FIXED_unary_neg_,TYPE_INT_MAX)), slot_1, NO_FRAME_T, slot_r, 0));
1494 g(gen_alu_upcall(ctx, offsetof(struct cg_upcall_vector_s, cat(INT_unary_neg_,TYPE_INT_MAX)), slot_1, NO_FRAME_T, slot_r, label_ovf));
1497 if (alu == ALU1_DEC) {
1498 if (mode == MODE_FIXED)
1499 g(gen_alu_upcall(ctx, offsetof(struct cg_upcall_vector_s, cat(FIXED_unary_dec_,TYPE_INT_MAX)), slot_1, NO_FRAME_T, slot_r, 0));
1501 g(gen_alu_upcall(ctx, offsetof(struct cg_upcall_vector_s, cat(INT_unary_dec_,TYPE_INT_MAX)), slot_1, NO_FRAME_T, slot_r, label_ovf));
1504 if (alu == ALU1_INC) {
1505 if (mode == MODE_FIXED)
1506 g(gen_alu_upcall(ctx, offsetof(struct cg_upcall_vector_s, cat(FIXED_unary_inc_,TYPE_INT_MAX)), slot_1, NO_FRAME_T, slot_r, 0));
1508 g(gen_alu_upcall(ctx, offsetof(struct cg_upcall_vector_s, cat(INT_unary_inc_,TYPE_INT_MAX)), slot_1, NO_FRAME_T, slot_r, label_ovf));
1512 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_1, 0, R_SCRATCH_1, R_SCRATCH_2));
1513 #if defined(ARCH_S390)
1514 if (alu == ALU1_NOT) {
1515 g(gen_load_constant(ctx, R_SCRATCH_3, -1));
1517 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_XOR, R_SCRATCH_1, R_SCRATCH_1, R_SCRATCH_3, 0));
1518 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_XOR, R_SCRATCH_2, R_SCRATCH_2, R_SCRATCH_3, 0));
1520 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, R_SCRATCH_1, R_SCRATCH_2));
1524 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));
1525 if (alu == ALU1_NOT) {
1526 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_NOT, R_SCRATCH_2, R_SCRATCH_2, 0));
1527 } else if (alu == ALU1_INC || alu == ALU1_DEC) {
1528 g(gen_imm(ctx, 0, alu == ALU1_INC ? IMM_PURPOSE_ADD : IMM_PURPOSE_SUB, OP_SIZE_NATIVE));
1529 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()));
1530 gen_one(R_SCRATCH_2);
1531 gen_one(R_SCRATCH_2);
1534 #if defined(ARCH_X86)
1535 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_NOT, R_SCRATCH_2, R_SCRATCH_2, 0));
1537 g(gen_imm(ctx, -1, IMM_PURPOSE_SUB, OP_SIZE_NATIVE));
1538 gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_SBB, ALU_WRITES_FLAGS(ALU_SBB, is_imm()));
1539 gen_one(R_SCRATCH_2);
1540 gen_one(R_SCRATCH_2);
1543 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_NGC, R_SCRATCH_2, R_SCRATCH_2, (mode == MODE_INT)));
1546 if (mode == MODE_INT) {
1547 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_O, 0);
1548 gen_four(label_ovf);
1550 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, R_SCRATCH_1, R_SCRATCH_2));
1553 if ((arch_use_flags || ARCH_SUPPORTS_TRAPS) && slot_1 == slot_r && i_size_cmp(op_size) == op_size + zero) {
1555 unsigned undo_alu = alu == ALU1_INC ? ALU1_DEC : alu == ALU1_DEC ? ALU1_INC : alu;
1556 if (ctx->registers[slot_1] >= 0) {
1557 unsigned reg = ctx->registers[slot_1];
1558 if (mode == MODE_INT && ARCH_SUPPORTS_TRAPS) {
1559 gen_insn(INSN_ALU1_TRAP, op_size, alu, ALU1_WRITES_FLAGS(alu));
1562 if (ARCH_TRAP_BEFORE || alu == undo_alu) {
1563 gen_four(label_ovf);
1566 ce = alloc_undo_label(ctx);
1569 gen_four(ce->undo_label);
1570 goto do_undo_opcode;
1573 g(gen_2address_alu1(ctx, i_size(op_size), alu, reg, reg, mode == MODE_INT));
1574 if (mode == MODE_INT) {
1575 if (alu != undo_alu) {
1576 ce = alloc_undo_label(ctx);
1579 gen_insn(INSN_JMP_COND, i_size_cmp(op_size), COND_O, 0);
1580 gen_four(ce->undo_label);
1582 ce->undo_opcode = INSN_ALU1 + ARCH_PARTIAL_ALU(op_size);
1583 ce->undo_op_size = i_size(op_size);
1584 ce->undo_aux = undo_alu;
1585 ce->undo_writes_flags = ALU1_WRITES_FLAGS(undo_alu);
1586 ce->undo_parameters[0] = reg;
1587 ce->undo_parameters[1] = reg;
1588 ce->undo_parameters_len = 2;
1590 gen_insn(INSN_JMP_COND, i_size_cmp(op_size), COND_O, 0);
1591 gen_four(label_ovf);
1596 #if defined(ARCH_X86)
1599 int64_t offset = (size_t)slot_1 * slot_size;
1600 g(gen_address(ctx, R_FRAME, offset, IMM_PURPOSE_LDR_OFFSET, i_size(op_size)));
1601 gen_insn(INSN_ALU1 + ARCH_PARTIAL_ALU(op_size), i_size(op_size), alu, ALU1_WRITES_FLAGS(alu) | (mode == MODE_INT));
1602 gen_address_offset();
1603 gen_address_offset();
1604 if (mode == MODE_INT) {
1605 if (alu != undo_alu) {
1606 ce = alloc_undo_label(ctx);
1609 ce->undo_opcode = INSN_ALU1 + ARCH_PARTIAL_ALU(op_size);
1610 ce->undo_op_size = i_size(op_size);
1611 ce->undo_aux = undo_alu;
1612 ce->undo_writes_flags = ALU1_WRITES_FLAGS(undo_alu);
1613 m = mark_params(ctx);
1614 gen_address_offset();
1615 gen_address_offset();
1616 copy_params(ctx, ce, m);
1617 gen_insn(INSN_JMP_COND, i_size_cmp(op_size), COND_O, 0);
1618 gen_four(ce->undo_label);
1620 gen_insn(INSN_JMP_COND, i_size_cmp(op_size), COND_O, 0);
1621 gen_four(label_ovf);
1628 target = gen_frame_target(ctx, slot_r, mode == MODE_INT ? slot_1 : NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
1629 if (mode == MODE_FIXED) {
1632 ex = ARCH_PREFERS_SX(op_size) ? sign_x : zero_x;
1633 if (ARCH_SUPPORTS_TRAPS && op_size >= OP_SIZE_4)
1635 if (op_size == i_size(op_size) + (unsigned)zero)
1638 g(gen_frame_get(ctx, op_size, ex, slot_1, 0, mode == MODE_INT ? R_SCRATCH_2 : target, ®1));
1639 #if defined(ARCH_S390)
1640 if (alu == ALU1_NOT) {
1641 g(gen_3address_alu_imm(ctx, i_size(op_size), ALU_XOR, target, reg1, -1, 0));
1643 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1647 #if defined(ARCH_X86)
1648 g(gen_2address_alu1(ctx, op_size, alu, target, reg1, mode == MODE_INT));
1650 if (mode == MODE_INT) {
1651 #if defined(ARCH_POWER)
1652 if (op_size == OP_SIZE_NATIVE) {
1653 g(gen_2address_alu1(ctx, i_size(op_size), alu, target, reg1, 0));
1654 if (alu == ALU1_NEG) {
1655 g(gen_3address_alu(ctx, i_size(op_size), ALU_AND, R_CG_SCRATCH, target, reg1, 1));
1656 } else if (alu == ALU1_INC) {
1657 g(gen_3address_alu(ctx, i_size(op_size), ALU_ANDN, R_CG_SCRATCH, target, reg1, 1));
1658 } else if (alu == ALU1_DEC) {
1659 g(gen_3address_alu(ctx, i_size(op_size), ALU_ANDN, R_CG_SCRATCH, reg1, target, 1));
1661 gen_insn(INSN_JMP_COND, op_size, COND_L, 0);
1662 gen_four(label_ovf);
1664 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1669 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) {
1670 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, alu, target, reg1, 0));
1672 g(gen_cmp_test_jmp(ctx, INSN_CMP, i_size_cmp(op_size), target, reg1, alu == ALU1_INC ? COND_L : COND_G, label_ovf));
1674 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1678 if (!arch_use_flags && !ARCH_SUPPORTS_TRAPS && ARCH_HAS_ANDN && op_size >= OP_SIZE_4) {
1679 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, alu, target, reg1, 0));
1681 if (alu == ALU1_NEG) {
1682 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_AND, R_SCRATCH_3, target, reg1, 0));
1683 } else if (alu == ALU1_INC) {
1684 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_ANDN, R_SCRATCH_3, target, reg1, 0));
1685 } else if (alu == ALU1_DEC) {
1686 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_ANDN, R_SCRATCH_3, reg1, target, 0));
1689 if (op_size < OP_SIZE_NATIVE)
1690 g(gen_extend(ctx, op_size, sign_x, R_SCRATCH_3, R_SCRATCH_3));
1692 g(gen_jmp_on_zero(ctx, OP_SIZE_NATIVE, R_SCRATCH_3, COND_S, label_ovf));
1694 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1698 if (op_size <= OP_SIZE_2 || (!arch_use_flags && !ARCH_SUPPORTS_TRAPS)) {
1699 int64_t imm = ((alu != ALU1_INC && ARCH_PREFERS_SX(op_size) ? -0x80ULL : 0x80ULL) << (((1 << op_size) - 1) * 8)) - (alu == ALU1_INC);
1701 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, i_size_cmp(op_size), reg1, imm, COND_E, label_ovf));
1705 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
1709 if (mode == MODE_INT) {
1710 gen_insn(INSN_ALU1_TRAP, op_size, alu, ALU1_WRITES_FLAGS(alu));
1713 gen_four(label_ovf);
1714 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1718 g(gen_2address_alu1(ctx, i_size(op_size), alu, target, reg1, mode == MODE_INT));
1720 if (mode == MODE_INT) {
1721 gen_insn(INSN_JMP_COND, i_size_cmp(op_size), COND_O, 0);
1722 gen_four(label_ovf);
1724 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1732 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
1733 g(gen_frame_get(ctx, op_size, garbage, slot_1, 0, target, ®1));
1735 g(gen_3address_alu_imm(ctx, i_size(op_size), ALU_XOR, target, reg1, 1, 0));
1737 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1745 bool attr_unused sx = false;
1746 #if defined(ARCH_X86) || defined(ARCH_ARM) || defined(ARCH_IA64) || defined(ARCH_LOONGARCH64) || defined(ARCH_MIPS) || defined(ARCH_RISCV64) || defined(ARCH_S390)
1747 #if defined(ARCH_ARM32)
1748 if (unlikely(!cpu_test_feature(CPU_FEATURE_armv6)))
1749 goto do_generic_bswap;
1751 #if defined(ARCH_MIPS)
1752 if (unlikely(!MIPS_HAS_ROT))
1753 goto do_generic_bswap;
1754 sx = op_size == OP_SIZE_4;
1756 #if defined(ARCH_RISCV64)
1757 if (unlikely(!cpu_test_feature(CPU_FEATURE_zbb)))
1758 goto do_generic_bswap;
1760 #if defined(ARCH_S390)
1761 if (op_size == OP_SIZE_2)
1762 goto do_generic_bswap;
1764 #if defined(ARCH_X86)
1765 if (op_size >= OP_SIZE_4 && !cpu_test_feature(CPU_FEATURE_bswap))
1766 goto do_generic_bswap;
1768 if (op_size > OP_SIZE_NATIVE) {
1769 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_1, 0, R_SCRATCH_1, R_SCRATCH_2));
1771 target = R_SCRATCH_1;
1773 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
1774 g(gen_frame_get(ctx, op_size, sx ? sign_x : garbage, slot_1, 0, target, ®1));
1777 if (op_size == OP_SIZE_1) {
1778 #if defined(ARCH_IA64) || defined(ARCH_RISCV64)
1779 } else if (op_size == OP_SIZE_2 || op_size == OP_SIZE_4) {
1780 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_BSWAP, target, reg1, 0));
1782 g(gen_3address_rot_imm(ctx, OP_SIZE_NATIVE, ROT_SAR, target, target, op_size == OP_SIZE_2 ? 48 : 32, 0));
1784 } else if (op_size == OP_SIZE_2) {
1785 #if defined(ARCH_X86)
1786 g(gen_3address_rot_imm(ctx, OP_SIZE_2, ROT_ROR, target, reg1, 8, 0));
1788 g(gen_2address_alu1(ctx, OP_SIZE_4, ALU1_BSWAP16, target, reg1, 0));
1791 g(gen_2address_alu1(ctx, minimum(op_size, OP_SIZE_NATIVE), ALU1_BSWAP, target, reg1, 0));
1793 if (op_size > OP_SIZE_NATIVE) {
1794 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_BSWAP, R_SCRATCH_2, R_SCRATCH_2, 0));
1797 if (op_size > OP_SIZE_NATIVE)
1798 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, R_SCRATCH_2, R_SCRATCH_1));
1800 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1803 goto do_generic_bswap;
1805 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);
1811 #if defined(ARCH_ARM) || defined(ARCH_LOONGARCH64) || (defined(ARCH_MIPS) && MIPS_R6)
1812 #if defined(ARCH_ARM32)
1813 if (unlikely(!cpu_test_feature(CPU_FEATURE_armv6t2)))
1814 goto do_generic_brev;
1816 if (op_size > OP_SIZE_NATIVE) {
1817 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_1, 0, R_SCRATCH_1, R_SCRATCH_2));
1819 target = R_SCRATCH_1;
1821 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
1822 g(gen_frame_get(ctx, op_size, garbage, slot_1, 0, target, ®1));
1825 g(gen_2address_alu1(ctx, minimum(maximum(OP_SIZE_4, op_size), OP_SIZE_NATIVE), ALU1_BREV, target, reg1, 0));
1826 if (op_size <= OP_SIZE_2) {
1827 g(gen_3address_rot_imm(ctx, OP_SIZE_4, ROT_SHR, target, target, op_size == OP_SIZE_1 ? 24 : 16, 0));
1829 if (op_size > OP_SIZE_NATIVE) {
1830 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_BREV, R_SCRATCH_2, R_SCRATCH_2, 0));
1833 if (op_size > OP_SIZE_NATIVE)
1834 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, R_SCRATCH_2, R_SCRATCH_1));
1836 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1839 goto do_generic_brev;
1841 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);
1846 do_bsf_bsr_popcnt: {
1847 if (op_size > OP_SIZE_NATIVE) {
1848 #if defined(ARCH_X86)
1849 uint32_t label_finish = 0; /* avoid warning */
1850 if (alu == ALU1_POPCNT && unlikely(!cpu_test_feature(CPU_FEATURE_popcnt)))
1851 goto do_generic_bsf_bsr_popcnt;
1852 if (alu == ALU1_BSR || alu == ALU1_POPCNT) {
1853 if (mode == MODE_INT) {
1854 g(gen_address(ctx, R_FRAME, (size_t)slot_1 * slot_size + hi_word(OP_SIZE_NATIVE), IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
1855 g(gen_imm(ctx, 0, IMM_PURPOSE_STORE_VALUE, OP_SIZE_NATIVE));
1856 gen_insn(INSN_CMP, OP_SIZE_NATIVE, 0, 1);
1857 gen_address_offset();
1860 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_S, 0);
1861 gen_four(label_ovf);
1864 if (alu == ALU1_BSF) {
1865 label_finish = alloc_label(ctx);
1866 if (unlikely(!label_finish))
1869 g(gen_address(ctx, R_FRAME, (size_t)slot_1 * slot_size + lo_word(OP_SIZE_NATIVE), IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
1870 gen_insn(INSN_ALU1, OP_SIZE_NATIVE, ALU1_BSF, ALU1_WRITES_FLAGS(ALU1_BSF));
1871 gen_one(R_SCRATCH_1);
1872 gen_address_offset();
1874 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_NE, 0);
1875 gen_four(label_finish);
1877 g(gen_address(ctx, R_FRAME, (size_t)slot_1 * slot_size + hi_word(OP_SIZE_NATIVE), IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
1878 gen_insn(INSN_ALU1, OP_SIZE_NATIVE, ALU1_BSF, ALU1_WRITES_FLAGS(ALU1_BSF));
1879 gen_one(R_SCRATCH_1);
1880 gen_address_offset();
1882 g(gen_3address_alu_imm(ctx, OP_SIZE_4, ALU_ADD, R_SCRATCH_1, R_SCRATCH_1, 8U << OP_SIZE_NATIVE, 0));
1884 if (alu == ALU1_BSR) {
1885 label_finish = alloc_label(ctx);
1886 if (unlikely(!label_finish))
1889 g(gen_address(ctx, R_FRAME, (size_t)slot_1 * slot_size + hi_word(OP_SIZE_NATIVE), IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
1890 gen_insn(INSN_ALU1, OP_SIZE_NATIVE, ALU1_BSR, ALU1_WRITES_FLAGS(ALU1_BSR));
1891 gen_one(R_SCRATCH_1);
1892 gen_address_offset();
1894 g(gen_3address_alu_imm(ctx, OP_SIZE_4, ALU_ADD, R_SCRATCH_1, R_SCRATCH_1, 8U << OP_SIZE_NATIVE, 0));
1896 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_NE, 0);
1897 gen_four(label_finish);
1899 g(gen_address(ctx, R_FRAME, (size_t)slot_1 * slot_size + lo_word(OP_SIZE_NATIVE), IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
1900 gen_insn(INSN_ALU1, OP_SIZE_NATIVE, ALU1_BSR, ALU1_WRITES_FLAGS(ALU1_BSR));
1901 gen_one(R_SCRATCH_1);
1902 gen_address_offset();
1904 if (alu == ALU1_BSF || alu == ALU1_BSR) {
1905 if (mode == MODE_INT) {
1906 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_E, 0);
1907 gen_four(label_ovf);
1909 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_NE, 0);
1910 gen_four(label_finish);
1912 g(gen_load_constant(ctx, R_SCRATCH_1, -1));
1915 gen_label(label_finish);
1917 if (mode == MODE_INT)
1920 if (R_SCRATCH_1 != R_AX || R_SCRATCH_2 != R_DX)
1921 internal(file_line, "gen_alu1: bad scratch registers");
1922 gen_insn(INSN_CWD, OP_SIZE_NATIVE, 0, 0);
1926 g(gen_address(ctx, R_FRAME, (size_t)slot_r * slot_size + lo_word(OP_SIZE_NATIVE), IMM_PURPOSE_STR_OFFSET, OP_SIZE_NATIVE));
1927 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
1928 gen_address_offset();
1929 gen_one(R_SCRATCH_1);
1931 g(gen_address(ctx, R_FRAME, (size_t)slot_r * slot_size + hi_word(OP_SIZE_NATIVE), IMM_PURPOSE_STR_OFFSET, OP_SIZE_NATIVE));
1932 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
1933 gen_address_offset();
1934 gen_one(R_SCRATCH_2);
1938 if (alu == ALU1_POPCNT) {
1939 g(gen_address(ctx, R_FRAME, (size_t)slot_1 * slot_size + lo_word(OP_SIZE_NATIVE), IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
1940 gen_insn(INSN_ALU1, OP_SIZE_NATIVE, ALU1_POPCNT, ALU1_WRITES_FLAGS(ALU1_POPCNT));
1941 gen_one(R_SCRATCH_1);
1942 gen_address_offset();
1944 g(gen_address(ctx, R_FRAME, (size_t)slot_1 * slot_size + hi_word(OP_SIZE_NATIVE), IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
1945 gen_insn(INSN_ALU1, OP_SIZE_NATIVE, ALU1_POPCNT, ALU1_WRITES_FLAGS(ALU1_POPCNT));
1946 gen_one(R_SCRATCH_2);
1947 gen_address_offset();
1949 g(gen_3address_alu(ctx, OP_SIZE_4, ALU_ADD, R_SCRATCH_1, R_SCRATCH_1, R_SCRATCH_2, 1));
1951 g(gen_address(ctx, R_FRAME, (size_t)slot_r * slot_size + lo_word(OP_SIZE_NATIVE), IMM_PURPOSE_STR_OFFSET, OP_SIZE_NATIVE));
1952 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
1953 gen_address_offset();
1954 gen_one(R_SCRATCH_1);
1956 g(gen_address(ctx, R_FRAME, (size_t)slot_r * slot_size + hi_word(OP_SIZE_NATIVE), IMM_PURPOSE_STR_OFFSET, OP_SIZE_NATIVE));
1957 g(gen_imm(ctx, 0, IMM_PURPOSE_STORE_VALUE, OP_SIZE_NATIVE));
1958 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
1959 gen_address_offset();
1965 goto do_generic_bsf_bsr_popcnt;
1967 #if defined(ARCH_X86)
1968 if (alu == ALU1_POPCNT && unlikely(!cpu_test_feature(CPU_FEATURE_popcnt)))
1969 goto do_generic_bsf_bsr_popcnt;
1970 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
1971 if (op_size == OP_SIZE_1 || ((alu == ALU1_BSR || alu == ALU1_POPCNT) && mode == MODE_INT)) {
1972 g(gen_frame_get(ctx, op_size, zero_x, slot_1, 0, target, ®1));
1973 if ((alu == ALU1_BSR || alu == ALU1_POPCNT) && mode == MODE_INT) {
1974 g(gen_cmp_test_jmp(ctx, INSN_TEST, op_size, reg1, reg1, alu == ALU1_BSR ? COND_LE : COND_S, label_ovf));
1976 g(gen_2address_alu1(ctx, maximum(op_size, OP_SIZE_2), alu, target, reg1, 1));
1977 if ((alu == ALU1_BSR || alu == ALU1_POPCNT) && mode == MODE_INT)
1978 goto x86_bsf_bsr_popcnt_finish;
1980 g(gen_frame_load_op1(ctx, op_size, alu, 1, slot_1, 0, target));
1982 if (alu == ALU1_POPCNT)
1983 goto x86_bsf_bsr_popcnt_finish;
1984 if (mode == MODE_FIXED) {
1985 uint32_t cmov_label;
1986 gen_insn(INSN_MOV, maximum(op_size, OP_SIZE_4), 0, 0);
1987 gen_one(R_SCRATCH_2);
1990 g(gen_cmov(ctx, maximum(op_size, OP_SIZE_4), COND_E, target, &cmov_label));
1991 gen_one(R_SCRATCH_2);
1993 gen_label(cmov_label);
1996 gen_insn(INSN_JMP_COND, maximum(op_size, OP_SIZE_2), COND_E, 0);
1997 gen_four(label_ovf);
1999 x86_bsf_bsr_popcnt_finish:
2000 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2003 #if defined(ARCH_ARM)
2004 #if defined(ARCH_ARM32)
2005 if (alu == ALU1_BSR && unlikely(!cpu_test_feature(CPU_FEATURE_armv6)))
2006 goto do_generic_bsf_bsr_popcnt;
2007 if (alu == ALU1_BSF && unlikely(!cpu_test_feature(CPU_FEATURE_armv6t2)))
2008 goto do_generic_bsf_bsr_popcnt;
2010 if (alu == ALU1_POPCNT && unlikely(!cpu_test_feature(CPU_FEATURE_neon)))
2011 goto do_generic_bsf_bsr_popcnt;
2012 g(gen_frame_get(ctx, op_size, mode == MODE_INT ? sign_x : zero_x, slot_1, 0, R_SCRATCH_1, ®1));
2013 if (mode == MODE_INT) {
2014 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));
2017 if (alu == ALU1_POPCNT) {
2018 g(gen_mov(ctx, OP_SIZE_NATIVE, FR_SCRATCH_1, reg1));
2019 gen_insn(INSN_FP_ALU1, OP_SIZE_NATIVE, FP_ALU1_VCNT8, 0);
2020 gen_one(FR_SCRATCH_1);
2021 gen_one(FR_SCRATCH_1);
2022 #if defined(ARCH_ARM32)
2023 if (op_size > OP_SIZE_1) {
2024 gen_insn(INSN_FP_ALU1, OP_SIZE_1, FP_ALU1_VPADDL, 0);
2025 gen_one(FR_SCRATCH_1);
2026 gen_one(FR_SCRATCH_1);
2028 if (op_size > OP_SIZE_2) {
2029 gen_insn(INSN_FP_ALU1, OP_SIZE_2, FP_ALU1_VPADDL, 0);
2030 gen_one(FR_SCRATCH_1);
2031 gen_one(FR_SCRATCH_1);
2034 if (op_size > OP_SIZE_1) {
2035 gen_insn(INSN_FP_ALU1, OP_SIZE_1, FP_ALU1_ADDV, 0);
2036 gen_one(FR_SCRATCH_1);
2037 gen_one(FR_SCRATCH_1);
2040 g(gen_frame_store(ctx, op_size, slot_r, 0, FR_SCRATCH_1));
2041 if (ctx->registers[slot_r] >= 0)
2042 g(unspill(ctx, slot_r));
2046 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
2047 if (mode == MODE_FIXED && alu == ALU1_BSF) {
2048 gen_insn(INSN_TEST, i_size(op_size), 0, 1);
2054 if (alu == ALU1_BSF) {
2055 g(gen_2address_alu1(ctx, i_size(op_size), ALU1_BREV, target, reg1, 0));
2059 g(gen_2address_alu1(ctx, i_size(op_size), ALU1_LZCNT, target, reg1, 0));
2061 if (alu == ALU1_BSR) {
2062 g(gen_load_constant(ctx, R_SCRATCH_2, op_size == OP_SIZE_8 ? 63 : 31));
2063 g(gen_3address_alu(ctx, i_size(op_size), ALU_SUB, target, R_SCRATCH_2, target, 0));
2066 if (mode == MODE_FIXED && alu == ALU1_BSF) {
2067 #if defined(ARCH_ARM32)
2068 g(gen_imm(ctx, -1, IMM_PURPOSE_CMOV, OP_SIZE_NATIVE));
2069 gen_insn(INSN_CMOV, OP_SIZE_NATIVE, COND_E, 0);
2074 gen_insn(INSN_CSEL_INV, i_size(op_size), COND_NE, 0);
2082 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2085 #if defined(ARCH_ALPHA)
2086 if (likely(cpu_test_feature(CPU_FEATURE_cix))) {
2087 g(gen_frame_get(ctx, op_size, mode == MODE_INT ? sign_x : zero_x, slot_1, 0, R_SCRATCH_1, ®1));
2088 target = gen_frame_target(ctx, slot_r, slot_1, NO_FRAME_T, R_SCRATCH_2);
2089 if (mode == MODE_INT) {
2090 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));
2092 if (alu == ALU1_POPCNT) {
2093 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_POPCNT, target, reg1, 0));
2095 if (alu == ALU1_BSF) {
2096 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_BSF, target, reg1, 0));
2098 if (mode == MODE_FIXED) {
2099 g(gen_imm(ctx, -1, IMM_PURPOSE_MOVR, OP_SIZE_INT));
2100 gen_insn(INSN_MOVR, OP_SIZE_NATIVE, COND_E, 0);
2107 if (alu == ALU1_BSR) {
2108 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_LZCNT, target, reg1, 0));
2110 g(gen_load_constant(ctx, R_SCRATCH_3, OP_SIZE_NATIVE == OP_SIZE_8 ? 63 : 31));
2112 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_SUB, target, R_SCRATCH_3, target, 0));
2114 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2118 #if defined(ARCH_MIPS)
2119 if (MIPS_HAS_CLZ && alu != ALU1_POPCNT) {
2120 g(gen_frame_get(ctx, op_size, mode == MODE_INT ? sign_x : zero_x, slot_1, 0, R_SCRATCH_1, ®1));
2121 target = gen_frame_target(ctx, slot_r, slot_1, NO_FRAME_T, R_SCRATCH_2);
2122 if (mode == MODE_INT) {
2123 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));
2125 if (alu == ALU1_BSF) {
2126 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_NEG, target, reg1, 0));
2128 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_AND, R_SCRATCH_1, reg1, target, 0));
2131 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_LZCNT, target, reg1, 0));
2133 g(gen_load_constant(ctx, R_SCRATCH_3, OP_SIZE_NATIVE == OP_SIZE_8 ? 63 : 31));
2135 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_SUB, target, R_SCRATCH_3, target, 0));
2137 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2141 #if defined(ARCH_POWER)
2142 if (alu == ALU1_BSF && (unlikely(!cpu_test_feature(CPU_FEATURE_v203)) || unlikely(!cpu_test_feature(CPU_FEATURE_v30))))
2143 goto do_generic_bsf_bsr_popcnt;
2144 if (alu == ALU1_POPCNT && unlikely(!cpu_test_feature(CPU_FEATURE_v206)))
2145 goto do_generic_bsf_bsr_popcnt;
2146 g(gen_frame_get(ctx, op_size, mode == MODE_INT ? sign_x : zero_x, slot_1, 0, R_SCRATCH_1, ®1));
2147 target = gen_frame_target(ctx, slot_r, slot_1, NO_FRAME_T, R_SCRATCH_2);
2148 if (mode == MODE_INT) {
2149 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));
2151 if (alu == ALU1_POPCNT) {
2152 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_POPCNT, target, reg1, 0));
2154 if (alu == ALU1_BSF) {
2155 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_BSF, target, reg1, 0));
2157 if (mode == MODE_FIXED) {
2158 g(gen_3address_alu(ctx, i_size(op_size), ALU_AND, R_SCRATCH_3, reg1, reg1, 1));
2160 g(gen_imm(ctx, -1, IMM_PURPOSE_CMOV, OP_SIZE_NATIVE));
2161 gen_insn(INSN_CMOV, OP_SIZE_NATIVE, COND_E, 0);
2167 if (alu == ALU1_BSR) {
2168 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_LZCNT, target, reg1, 0));
2170 g(gen_load_constant(ctx, R_SCRATCH_3, OP_SIZE_NATIVE == OP_SIZE_8 ? 63 : 31));
2172 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_SUB, target, R_SCRATCH_3, target, 0));
2174 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2177 #if defined(ARCH_LOONGARCH64) || defined(ARCH_RISCV64)
2178 #if defined(ARCH_LOONGARCH64)
2179 if (alu == ALU1_POPCNT)
2180 goto do_generic_bsf_bsr_popcnt;
2182 #if defined(ARCH_RISCV64)
2183 if (unlikely(!cpu_test_feature(CPU_FEATURE_zbb)))
2184 goto do_generic_bsf_bsr_popcnt;
2186 g(gen_frame_get(ctx, op_size, mode == MODE_INT ? sign_x : zero_x, slot_1, 0, R_SCRATCH_1, ®1));
2187 target = gen_frame_target(ctx, slot_r, slot_1, NO_FRAME_T, R_SCRATCH_2);
2188 if (mode == MODE_INT) {
2189 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));
2191 if (alu == ALU1_POPCNT) {
2192 g(gen_2address_alu1(ctx, maximum(OP_SIZE_4, op_size), ALU1_POPCNT, target, reg1, 0));
2194 if (alu == ALU1_BSF) {
2195 g(gen_2address_alu1(ctx, maximum(OP_SIZE_4, op_size), ALU1_BSF, target, reg1, 0));
2197 if (mode == MODE_FIXED) {
2198 g(gen_imm(ctx, 1, IMM_PURPOSE_CMP, OP_SIZE_NATIVE));
2199 gen_insn(INSN_CMP_DEST_REG, OP_SIZE_NATIVE, COND_B, 0);
2200 gen_one(R_SCRATCH_3);
2204 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_NEG, R_SCRATCH_3, R_SCRATCH_3, 0));
2206 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_OR, target, target, R_SCRATCH_3, 0));
2209 if (alu == ALU1_BSR) {
2210 g(gen_2address_alu1(ctx, maximum(OP_SIZE_4, op_size), ALU1_LZCNT, target, reg1, 0));
2212 g(gen_load_constant(ctx, R_SCRATCH_3, op_size <= OP_SIZE_4 ? 31 : 63));
2214 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_SUB, target, R_SCRATCH_3, target, 0));
2216 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2219 #if defined(ARCH_IA64) || defined(ARCH_S390) || defined(ARCH_SPARC)
2220 if (alu == ALU1_BSF && !ARCH_HAS_ANDN)
2221 goto do_generic_bsf_bsr_popcnt;
2222 #if defined(ARCH_S390)
2223 if (!cpu_test_feature(CPU_FEATURE_misc_45) || !cpu_test_feature(CPU_FEATURE_misc_insn_ext_3))
2224 goto do_generic_bsf_bsr_popcnt;
2226 #if defined(ARCH_SPARC)
2228 goto do_generic_bsf_bsr_popcnt;
2230 g(gen_frame_get(ctx, op_size, mode == MODE_INT ? sign_x : zero_x, slot_1, 0, R_SCRATCH_1, ®1));
2231 target = gen_frame_target(ctx, slot_r, slot_1, NO_FRAME_T, R_SCRATCH_2);
2232 if (mode == MODE_INT) {
2233 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));
2235 if (ARCH_PREFERS_SX(op_size) && alu == ALU1_POPCNT && op_size < OP_SIZE_NATIVE) {
2236 g(gen_extend(ctx, op_size, zero_x, R_SCRATCH_1, reg1));
2240 if (alu == ALU1_POPCNT) {
2241 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_POPCNT, R_SCRATCH_1, reg1, 0));
2242 g(gen_frame_store(ctx, op_size, slot_r, 0, R_SCRATCH_1));
2245 if (alu == ALU1_BSF) {
2246 g(gen_3address_alu_imm(ctx, OP_SIZE_NATIVE, ALU_SUB, target, reg1, 1, 0));
2248 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_ANDN, target, target, reg1, 0));
2250 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_POPCNT, target, target, 0));
2252 if (mode == MODE_FIXED) {
2253 unsigned attr_unused test_reg = R_SCRATCH_1;
2254 #if defined(ARCH_S390)
2255 g(gen_imm(ctx, 0, COND_IS_LOGICAL(COND_E) ? IMM_PURPOSE_CMP_LOGICAL : IMM_PURPOSE_CMP, OP_SIZE_NATIVE));
2256 gen_insn(INSN_CMP, OP_SIZE_NATIVE, 0, 1 + COND_IS_LOGICAL(COND_E));
2260 g(gen_imm(ctx, -1, IMM_PURPOSE_CMOV, OP_SIZE_NATIVE));
2261 gen_insn(INSN_CMOV, OP_SIZE_NATIVE, COND_E, 0);
2266 #if defined(ARCH_IA64)
2267 g(gen_cmp_dest_reg(ctx, OP_SIZE_NATIVE, reg1, (unsigned)-1, R_CMP_RESULT, 0, COND_NE));
2268 test_reg = R_CMP_RESULT;
2270 g(gen_imm(ctx, -1, IMM_PURPOSE_MOVR, OP_SIZE_NATIVE));
2271 gen_insn(INSN_MOVR, OP_SIZE_NATIVE, COND_E, 0);
2279 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2283 do_generic_bsf_bsr_popcnt:
2284 if (alu == ALU1_BSF) {
2285 if (mode == MODE_FIXED)
2286 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);
2288 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);
2290 if (alu == ALU1_BSR) {
2291 if (mode == MODE_FIXED)
2292 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);
2294 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);
2296 if (alu == ALU1_POPCNT) {
2297 if (mode == MODE_FIXED)
2298 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);
2300 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);
2308 unsigned src_op_size, dest_op_size;
2309 const struct type *src_type, *dest_type;
2310 src_type = get_type_of_local(ctx, slot_1);
2311 dest_type = get_type_of_local(ctx, slot_r);
2313 if (TYPE_TAG_IS_FIXED(src_type->tag)) {
2314 src_op_size = TYPE_TAG_IDX_FIXED(src_type->tag) >> 1;
2316 src_op_size = TYPE_TAG_IDX_INT(src_type->tag);
2319 if (TYPE_TAG_IS_FIXED(dest_type->tag)) {
2320 dest_op_size = TYPE_TAG_IDX_FIXED(dest_type->tag) >> 1;
2322 dest_op_size = TYPE_TAG_IDX_INT(dest_type->tag);
2325 if (src_op_size <= OP_SIZE_NATIVE) {
2326 g(gen_frame_get(ctx, src_op_size, sign_x, slot_1, 0, R_SCRATCH_1, ®1));
2328 #if defined(ARCH_X86)
2329 if (dest_op_size < src_op_size)
2330 g(gen_frame_load(ctx, OP_SIZE_NATIVE, garbage, slot_1, 0, R_SCRATCH_1));
2333 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_1, 0, R_SCRATCH_1, R_SCRATCH_3));
2337 if (dest_op_size >= src_op_size) {
2338 if (dest_op_size <= OP_SIZE_NATIVE) {
2339 g(gen_frame_store(ctx, dest_op_size, slot_r, 0, reg1));
2341 if (src_op_size <= OP_SIZE_NATIVE) {
2342 #if defined(ARCH_X86)
2343 if (R_SCRATCH_1 != R_AX || R_SCRATCH_2 != R_DX)
2344 internal(file_line, "gen_alu1: bad scratch registers");
2345 if (reg1 == R_SCRATCH_1) {
2346 gen_insn(INSN_CWD, OP_SIZE_NATIVE, 0, 0);
2351 g(gen_3address_rot_imm(ctx, OP_SIZE_NATIVE, ROT_SAR, R_SCRATCH_2, reg1, (1U << (OP_SIZE_NATIVE + 3)) - 1, false));
2352 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, reg1, R_SCRATCH_2));
2354 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, reg1, R_SCRATCH_3));
2359 if (src_op_size > OP_SIZE_NATIVE) {
2360 #if defined(ARCH_ARM)
2361 gen_insn(INSN_CMP, OP_SIZE_NATIVE, 0, 1);
2362 gen_one(R_SCRATCH_3);
2363 gen_one(ARG_SHIFTED_REGISTER);
2364 gen_one(ARG_SHIFT_ASR | ((1U << (OP_SIZE_NATIVE + 3)) - 1));
2365 gen_one(R_SCRATCH_1);
2367 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_NE, 0);
2368 gen_four(label_ovf);
2369 #elif defined(ARCH_X86)
2370 if (R_SCRATCH_1 != R_AX || R_SCRATCH_2 != R_DX)
2371 internal(file_line, "gen_alu1: bad scratch registers");
2372 gen_insn(INSN_CWD, OP_SIZE_NATIVE, 0, 0);
2376 g(gen_address(ctx, R_FRAME, (size_t)slot_1 * slot_size + hi_word(OP_SIZE_NATIVE), IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
2377 gen_insn(INSN_CMP, OP_SIZE_NATIVE, 0, 1);
2378 gen_one(R_SCRATCH_2);
2379 gen_address_offset();
2381 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_NE, 0);
2382 gen_four(label_ovf);
2384 g(gen_3address_rot_imm(ctx, OP_SIZE_NATIVE, ROT_SAR, R_SCRATCH_2, R_SCRATCH_1, (1U << (OP_SIZE_NATIVE + 3)) - 1, 0));
2386 g(gen_cmp_test_jmp(ctx, INSN_CMP, OP_SIZE_NATIVE, R_SCRATCH_3, R_SCRATCH_2, COND_NE, label_ovf));
2389 src_op_size = OP_SIZE_NATIVE;
2391 if (src_op_size > dest_op_size) {
2392 g(gen_cmp_extended(ctx, OP_SIZE_NATIVE, dest_op_size, reg1, R_SCRATCH_2, label_ovf));
2394 g(gen_frame_store(ctx, dest_op_size, slot_r, 0, reg1));
2400 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);
2404 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);
2408 static bool attr_w gen_constant(struct codegen_context *ctx, bool real, unsigned op_size, bool shrt, frame_t slot_r)
2412 c = (int16_t)get_unaligned_16(ctx->current_position);
2413 } else switch (op_size) {
2414 #define fx(n, type, utype, sz, bits) \
2416 c = (type)cat(get_unaligned_,bits)(ctx->current_position);\
2421 internal(file_line, "gen_constant: invalid type %u", op_size);
2423 if (op_size > OP_SIZE_NATIVE) {
2424 unsigned shift = (8U << OP_SIZE_NATIVE) - 1;
2425 g(gen_frame_store_imm_raw(ctx, OP_SIZE_NATIVE, slot_r, lo_word(OP_SIZE_NATIVE), c & ((2ULL << shift) - 1)));
2426 g(gen_frame_store_imm_raw(ctx, OP_SIZE_NATIVE, slot_r, hi_word(OP_SIZE_NATIVE), c >> 1 >> shift));
2427 if (real && ctx->registers[slot_r] >= 0)
2428 g(unspill(ctx, slot_r));
2430 } else if (real && ctx->registers[slot_r] >= 0) {
2431 if (ARCH_HAS_FP_GP_MOV) {
2432 g(gen_load_constant(ctx, R_SCRATCH_1, c));
2433 g(gen_mov(ctx, op_size, ctx->registers[slot_r], R_SCRATCH_1));
2435 g(gen_frame_store_imm_raw(ctx, op_size, slot_r, 0, c));
2436 g(unspill(ctx, slot_r));
2439 g(gen_frame_store_imm(ctx, op_size, slot_r, 0, c));
2444 static bool attr_w gen_real_constant(struct codegen_context *ctx, const struct type *t, frame_t slot_r)
2447 if (is_power_of_2(t->size) && t->size <= sizeof(uintbig_t))
2448 return gen_constant(ctx, true, log_2(t->size), false, slot_r);
2450 g(load_function_offset(ctx, R_SCRATCH_3, offsetof(struct data, u_.function.code)));
2452 offset = (ctx->current_position - da(ctx->fn,function)->code) * sizeof(code_t);
2454 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))));
2455 if (ctx->registers[slot_r] >= 0)
2456 g(unspill(ctx, slot_r));
2461 static bool attr_w gen_copy(struct codegen_context *ctx, unsigned op_size, frame_t slot_1, frame_t slot_r)
2464 if (unlikely(op_size > OP_SIZE_NATIVE)) {
2465 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_1, 0, R_SCRATCH_1, R_SCRATCH_2));
2466 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, R_SCRATCH_1, R_SCRATCH_2));
2469 unsigned target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
2470 g(gen_frame_get(ctx, op_size, garbage, slot_1, 0, target, ®1));
2471 g(gen_frame_store(ctx, op_size, slot_r, 0, reg1));
2476 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)
2478 unsigned attr_unused fp_alu;
2480 unsigned attr_unused op_size = real_type_to_op_size(real_type);
2481 unsigned reg1, reg2, target;
2483 case OPCODE_REAL_OP_add:
2484 case OPCODE_REAL_OP_add_alt1:
2485 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;
2486 case OPCODE_REAL_OP_subtract:
2487 case OPCODE_REAL_OP_subtract_alt1:
2488 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;
2489 case OPCODE_REAL_OP_multiply:
2490 case OPCODE_REAL_OP_multiply_alt1:
2491 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;
2492 case OPCODE_REAL_OP_divide:
2493 case OPCODE_REAL_OP_divide_alt1:
2494 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;
2495 case OPCODE_REAL_OP_modulo:
2496 case OPCODE_REAL_OP_power:
2497 case OPCODE_REAL_OP_ldexp:
2498 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;
2499 case OPCODE_REAL_OP_equal:
2500 case OPCODE_REAL_OP_equal_alt1:
2501 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;
2502 case OPCODE_REAL_OP_not_equal:
2503 case OPCODE_REAL_OP_not_equal_alt1:
2504 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;
2505 case OPCODE_REAL_OP_less:
2506 case OPCODE_REAL_OP_less_alt1:
2507 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;
2508 case OPCODE_REAL_OP_less_equal:
2509 case OPCODE_REAL_OP_less_equal_alt1:
2510 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;
2511 default: internal(file_line, "gen_fp_alu: unsupported operation %u", op);
2515 if ((SUPPORTED_FP >> real_type) & 1) {
2516 #if defined(ARCH_IA64)
2517 if (unlikely(fp_alu == FP_ALU_DIV))
2520 #if defined(ARCH_X86)
2522 #elif defined(ARCH_S390)
2523 if ((op_size <= OP_SIZE_8 && (size_t)slot_2 * slot_size < 4096) || ctx->registers[slot_2] >= 0)
2525 if (ctx->registers[slot_2] >= 0)
2528 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, slot_2, FR_SCRATCH_1);
2529 g(gen_frame_get(ctx, op_size, garbage, slot_1, 0, FR_SCRATCH_1, ®1));
2530 if (ctx->registers[slot_2] >= 0) {
2531 g(gen_3address_fp_alu(ctx, op_size, fp_alu, target, reg1, ctx->registers[slot_2]));
2533 if (target != reg1 && !ARCH_IS_3ADDRESS_FP) {
2534 g(gen_mov(ctx, op_size, target, reg1));
2537 g(gen_address(ctx, R_FRAME, (size_t)slot_2 * slot_size, IMM_PURPOSE_VLDR_VSTR_OFFSET, op_size));
2538 gen_insn(INSN_FP_ALU, op_size, fp_alu, 0);
2541 gen_address_offset();
2543 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2546 #if defined(ARCH_ALPHA)
2547 g(gen_frame_get(ctx, op_size, zero_x, slot_1, 0, FR_SCRATCH_1, ®1));
2548 g(gen_frame_get(ctx, op_size, zero_x, slot_2, 0, FR_SCRATCH_2, ®2));
2549 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, FR_SCRATCH_3);
2550 g(gen_3address_fp_alu(ctx, op_size, fp_alu, target, reg1, reg2));
2551 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2553 g(gen_frame_get(ctx, op_size, zero_x, slot_1, 0, FR_SCRATCH_1, ®1));
2554 g(gen_frame_get(ctx, op_size, zero_x, slot_2, 0, FR_SCRATCH_2, ®2));
2555 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, FR_SCRATCH_1);
2556 g(gen_3address_fp_alu(ctx, op_size, fp_alu, target, reg1, reg2));
2557 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2561 #ifdef SUPPORTED_FP_X87
2562 if ((SUPPORTED_FP_X87 >> real_type) & 1) {
2563 if (real_type != 3) {
2564 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_2));
2565 g(gen_frame_load_x87(ctx, INSN_X87_ALU, op_size, fp_alu, slot_1));
2567 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_1));
2568 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_2));
2569 gen_insn(INSN_X87_ALUP, op_size, fp_alu, 0);
2572 g(gen_frame_store_x87(ctx, INSN_X87_FSTP, op_size, slot_r));
2576 #ifdef SUPPORTED_FP_HALF_CVT
2577 if ((SUPPORTED_FP_HALF_CVT >> real_type) & 1) {
2578 g(gen_frame_get(ctx, op_size, zero_x, slot_1, 0, FR_SCRATCH_1, ®1));
2579 g(gen_frame_get(ctx, op_size, zero_x, slot_2, 0, FR_SCRATCH_2, ®2));
2580 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, FR_SCRATCH_1);
2581 gen_insn(INSN_FP_CVT, op_size, OP_SIZE_4, 0);
2582 gen_one(FR_SCRATCH_1);
2584 gen_insn(INSN_FP_CVT, op_size, OP_SIZE_4, 0);
2585 gen_one(FR_SCRATCH_2);
2587 gen_insn(INSN_FP_ALU, OP_SIZE_4, fp_alu, 0);
2588 gen_one(FR_SCRATCH_1);
2589 gen_one(FR_SCRATCH_1);
2590 gen_one(FR_SCRATCH_2);
2591 gen_insn(INSN_FP_CVT, OP_SIZE_4, op_size, 0);
2593 gen_one(FR_SCRATCH_1);
2594 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2601 if ((SUPPORTED_FP >> real_type) & 1
2602 #if defined(ARCH_ALPHA)
2603 && ARCH_SUPPORTS_TRAPS
2606 g(gen_frame_get(ctx, op_size, zero_x, slot_1, 0, FR_SCRATCH_1, ®1));
2607 g(gen_frame_get(ctx, op_size, zero_x, slot_2, 0, FR_SCRATCH_2, ®2));
2608 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
2609 #if defined(ARCH_ALPHA)
2610 gen_insn(INSN_FP_CMP_DEST_REG_TRAP, op_size, fp_alu == FP_COND_NE ? FP_COND_E : fp_alu, 0);
2611 gen_one(FR_SCRATCH_3);
2614 gen_four(label_ovf);
2616 if (!ARCH_HAS_FP_GP_MOV) {
2617 g(gen_frame_store_raw(ctx, OP_SIZE_4, slot_r, 0, FR_SCRATCH_3));
2618 g(gen_frame_load_raw(ctx, OP_SIZE_4, sign_x, slot_r, 0, target));
2620 g(gen_mov(ctx, OP_SIZE_4, target, FR_SCRATCH_3));
2623 if (fp_alu == FP_COND_NE) {
2624 g(gen_imm(ctx, 0, IMM_PURPOSE_CMP, OP_SIZE_NATIVE));
2625 gen_insn(INSN_CMP_DEST_REG, OP_SIZE_NATIVE, COND_E, 0);
2630 g(gen_3address_rot_imm(ctx, OP_SIZE_NATIVE, ROT_SHR, target, target, 30, 0));
2633 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, target));
2636 #elif defined(ARCH_IA64)
2637 gen_insn(INSN_FP_CMP_DEST_REG, op_size, FP_COND_P, 0);
2638 gen_one(R_CMP_RESULT);
2642 gen_insn(INSN_JMP_REG, OP_SIZE_NATIVE, COND_NE, 0);
2643 gen_one(R_CMP_RESULT);
2644 gen_four(label_ovf);
2646 gen_insn(INSN_FP_CMP_DEST_REG, op_size, fp_alu, 0);
2647 gen_one(R_CMP_RESULT);
2651 g(gen_mov(ctx, OP_SIZE_NATIVE, target, R_CMP_RESULT));
2653 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, target));
2656 #elif defined(ARCH_LOONGARCH64) || defined(ARCH_MIPS) || defined(ARCH_PARISC)
2657 gen_insn(INSN_FP_CMP_COND, op_size, FP_COND_P, 1);
2661 gen_insn(INSN_JMP_FP_TEST, 0, FP_COND_P, 0);
2662 gen_four(label_ovf);
2664 gen_insn(INSN_FP_CMP_COND, op_size, fp_alu, 1);
2668 gen_insn(INSN_FP_TEST_REG, OP_SIZE_NATIVE, fp_alu, 0);
2671 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, target));
2674 #elif defined(ARCH_RISCV64)
2675 gen_insn(INSN_FP_CMP_DEST_REG, op_size, FP_COND_E, 0);
2676 gen_one(R_SCRATCH_1);
2680 gen_insn(INSN_FP_CMP_DEST_REG, op_size, FP_COND_E, 0);
2681 gen_one(R_SCRATCH_2);
2685 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_AND, R_SCRATCH_1, R_SCRATCH_1, R_SCRATCH_2, 0));
2687 g(gen_jmp_on_zero(ctx, OP_SIZE_NATIVE, R_SCRATCH_1, COND_E, label_ovf));
2689 gen_insn(INSN_FP_CMP_DEST_REG, op_size, fp_alu == FP_COND_NE ? FP_COND_E : fp_alu, 0);
2694 if (fp_alu == FP_COND_NE) {
2695 g(gen_imm(ctx, 1, IMM_PURPOSE_XOR, OP_SIZE_NATIVE));
2696 gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_XOR, ALU_WRITES_FLAGS(ALU_AND, false));
2702 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, target));
2705 gen_insn(INSN_FP_CMP, op_size, 0, 1);
2708 #if defined(ARCH_ARM32)
2709 gen_insn(INSN_FP_TO_INT_FLAGS, 0, 0, 1);
2711 gen_insn(INSN_JMP_COND, op_size, FP_COND_P, 0);
2712 gen_four(label_ovf);
2713 g(gen_frame_set_cond(ctx, op_size, false, fp_alu, slot_r));
2717 #ifdef SUPPORTED_FP_X87
2718 if ((SUPPORTED_FP_X87 >> real_type) & 1) {
2719 if (likely(cpu_test_feature(CPU_FEATURE_cmov))) {
2720 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_2));
2721 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_1));
2722 gen_insn(INSN_X87_FCOMIP, op_size, 0, 0);
2724 gen_insn(INSN_X87_FSTP, op_size, 0, 0);
2726 gen_insn(INSN_JMP_COND, op_size, COND_P, 0);
2727 gen_four(label_ovf);
2728 g(gen_frame_set_cond(ctx, op_size, false, fp_alu & 0xf, slot_r));
2732 if (real_type != 3) {
2733 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_1));
2734 g(gen_frame_load_x87(ctx, INSN_X87_FCOMP, op_size, 0, slot_2));
2736 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_2));
2737 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_1));
2738 gen_insn(INSN_X87_FCOMPP, op_size, 0, 0);
2741 gen_insn(INSN_X87_FNSTSW, 0, 0, 0);
2745 gen_insn(INSN_TEST, OP_SIZE_2, 0, 1);
2750 gen_insn(INSN_JMP_COND, OP_SIZE_2, COND_NE, 0);
2751 gen_four(label_ovf);
2755 gen_insn(INSN_TEST, OP_SIZE_2, 0, 1);
2759 g(gen_frame_set_cond(ctx, OP_SIZE_2, false, COND_NE, slot_r));
2762 gen_insn(INSN_TEST, OP_SIZE_2, 0, 1);
2766 g(gen_frame_set_cond(ctx, OP_SIZE_2, false, COND_E, slot_r));
2769 gen_insn(INSN_TEST, OP_SIZE_2, 0, 1);
2773 g(gen_frame_set_cond(ctx, OP_SIZE_2, false, COND_NE, slot_r));
2776 gen_insn(INSN_TEST, OP_SIZE_2, 0, 1);
2780 g(gen_frame_set_cond(ctx, OP_SIZE_2, false, COND_NE, slot_r));
2783 internal(file_line, "gen_fp_alu: invalid condition %u", fp_alu);
2788 #ifdef SUPPORTED_FP_HALF_CVT
2789 if ((SUPPORTED_FP_HALF_CVT >> real_type) & 1) {
2790 g(gen_frame_get(ctx, op_size, zero_x, slot_1, 0, FR_SCRATCH_1, ®1));
2791 g(gen_frame_get(ctx, op_size, zero_x, slot_2, 0, FR_SCRATCH_2, ®2));
2792 gen_insn(INSN_FP_CVT, op_size, OP_SIZE_4, 0);
2793 gen_one(FR_SCRATCH_1);
2795 gen_insn(INSN_FP_CVT, op_size, OP_SIZE_4, 0);
2796 gen_one(FR_SCRATCH_2);
2798 gen_insn(INSN_FP_CMP, OP_SIZE_4, 0, 1);
2799 gen_one(FR_SCRATCH_1);
2800 gen_one(FR_SCRATCH_2);
2801 #if defined(ARCH_ARM32)
2802 gen_insn(INSN_FP_TO_INT_FLAGS, 0, 0, 1);
2804 gen_insn(INSN_JMP_COND, op_size, FP_COND_P, 0);
2805 gen_four(label_ovf);
2806 g(gen_frame_set_cond(ctx, op_size, false, fp_alu, slot_r));
2812 return gen_alu_typed_upcall(ctx, upc, real_type, slot_1, slot_2, slot_r, label_ovf);
2815 #define OP_IS_ROUND(alu) ((alu) == FP_ALU1_ROUND || (alu) == FP_ALU1_FLOOR || (alu) == FP_ALU1_CEIL || (alu) == FP_ALU1_TRUNC)
2817 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)
2819 unsigned attr_unused fp_alu;
2821 unsigned attr_unused op_size = real_type_to_op_size(real_type);
2822 unsigned reg1, target;
2824 case OPCODE_REAL_OP_neg:
2825 case OPCODE_REAL_OP_neg_alt1:
2826 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;
2827 case OPCODE_REAL_OP_sqrt:
2828 case OPCODE_REAL_OP_sqrt_alt1:
2829 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;
2830 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;
2831 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;
2832 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;
2833 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;
2834 case OPCODE_REAL_OP_to_int:
2835 case OPCODE_REAL_OP_to_int_alt1:
2836 case OPCODE_REAL_OP_to_int_alt2: upc = offsetof(struct cg_upcall_vector_s, REAL_unary_to_int_real16_t); goto do_to_int;
2837 case OPCODE_REAL_OP_from_int:
2838 case OPCODE_REAL_OP_from_int_alt1:
2839 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;
2840 case OPCODE_REAL_OP_is_exception:
2841 case OPCODE_REAL_OP_is_exception_alt1:
2842 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;
2843 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;
2847 if ((SUPPORTED_FP >> real_type) & 1 && (
2848 #if defined(ARCH_ALPHA)
2849 fp_alu == FP_ALU1_NEG ||
2850 (fp_alu == FP_ALU1_SQRT && cpu_test_feature(CPU_FEATURE_fix)) ||
2851 #elif defined(ARCH_ARM32)
2852 fp_alu == FP_ALU1_NEG ||
2853 fp_alu == FP_ALU1_SQRT ||
2854 #elif defined(ARCH_ARM64)
2856 #elif defined(ARCH_IA64)
2857 fp_alu == FP_ALU1_NEG ||
2858 #elif defined(ARCH_LOONGARCH64)
2859 fp_alu == FP_ALU1_NEG ||
2860 fp_alu == FP_ALU1_SQRT ||
2861 fp_alu == FP_ALU1_ROUND ||
2862 #elif defined(ARCH_MIPS)
2863 fp_alu == FP_ALU1_NEG ||
2864 (fp_alu == FP_ALU1_SQRT && MIPS_HAS_SQRT) ||
2865 #elif defined(ARCH_PARISC)
2866 (fp_alu == FP_ALU1_NEG && PA_20) ||
2867 fp_alu == FP_ALU1_SQRT ||
2868 #elif defined(ARCH_POWER)
2869 fp_alu == FP_ALU1_NEG ||
2870 (fp_alu == FP_ALU1_SQRT && cpu_test_feature(CPU_FEATURE_p2) && real_type != 4) ||
2871 #elif defined(ARCH_S390)
2873 #elif defined(ARCH_SPARC)
2874 fp_alu == FP_ALU1_NEG ||
2875 fp_alu == FP_ALU1_SQRT ||
2876 #elif defined(ARCH_RISCV64)
2877 fp_alu == FP_ALU1_NEG ||
2878 fp_alu == FP_ALU1_SQRT ||
2879 #elif defined(ARCH_X86)
2880 fp_alu == FP_ALU1_SQRT ||
2881 (OP_IS_ROUND(fp_alu) && cpu_test_feature(CPU_FEATURE_sse41)) ||
2884 #if defined(ARCH_S390)
2885 if (op_size <= OP_SIZE_8 && (size_t)slot_1 * slot_size < 4096 && fp_alu == FP_ALU1_SQRT) {
2886 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, FR_SCRATCH_1);
2887 if (ctx->registers[slot_1] >= 0) {
2888 gen_insn(INSN_FP_ALU1, op_size, fp_alu, 0);
2890 gen_one(ctx->registers[slot_1]);
2891 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2893 g(gen_address(ctx, R_FRAME, (size_t)slot_1 * slot_size, IMM_PURPOSE_VLDR_VSTR_OFFSET, op_size));
2894 gen_insn(INSN_FP_ALU1, op_size, fp_alu, 0);
2896 gen_address_offset();
2897 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2902 g(gen_frame_get(ctx, op_size, zero_x, slot_1, 0, FR_SCRATCH_1, ®1));
2903 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, FR_SCRATCH_2);
2904 gen_insn(INSN_FP_ALU1, op_size, fp_alu, 0);
2907 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2910 #ifdef SUPPORTED_FP_X87
2911 if ((SUPPORTED_FP_X87 >> real_type) & 1) {
2912 if (fp_alu == FP_ALU1_NEG) {
2913 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_1));
2914 gen_insn(INSN_X87_FCHS, op_size, 0, 0);
2915 g(gen_frame_store_x87(ctx, INSN_X87_FSTP, op_size, slot_r));
2917 } else if (fp_alu == FP_ALU1_SQRT) {
2918 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_1));
2919 gen_insn(INSN_X87_FSQRT, op_size, 0, 0);
2920 g(gen_frame_store_x87(ctx, INSN_X87_FSTP, op_size, slot_r));
2922 } else if (fp_alu == FP_ALU1_ROUND) {
2923 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_1));
2924 gen_insn(INSN_X87_FRNDINT, op_size, 0, 0);
2925 g(gen_frame_store_x87(ctx, INSN_X87_FSTP, op_size, slot_r));
2930 #ifdef SUPPORTED_FP_HALF_CVT
2931 if ((SUPPORTED_FP_HALF_CVT >> real_type) & 1 && (
2932 #if defined(ARCH_ARM32)
2933 fp_alu == FP_ALU1_NEG ||
2934 fp_alu == FP_ALU1_SQRT ||
2935 #elif defined(ARCH_ARM64)
2937 #elif defined(ARCH_X86)
2938 fp_alu == FP_ALU1_SQRT ||
2939 (OP_IS_ROUND(fp_alu) && cpu_test_feature(CPU_FEATURE_sse41)) ||
2942 g(gen_frame_get(ctx, op_size, zero_x, slot_1, 0, FR_SCRATCH_1, ®1));
2943 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, FR_SCRATCH_1);
2944 gen_insn(INSN_FP_CVT, op_size, OP_SIZE_4, 0);
2947 gen_insn(INSN_FP_ALU1, OP_SIZE_4, fp_alu, 0);
2950 gen_insn(INSN_FP_CVT, OP_SIZE_4, op_size, 0);
2953 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2960 if ((SUPPORTED_FP >> real_type) & 1
2961 #if defined(ARCH_ALPHA)
2962 && ARCH_SUPPORTS_TRAPS
2964 #if defined(ARCH_MIPS)
2968 g(gen_frame_get(ctx, op_size, zero_x, slot_1, 0, FR_SCRATCH_1, ®1));
2971 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
2972 #if defined(ARCH_X86)
2973 gen_insn(OP_SIZE_INT == OP_SIZE_4 ? INSN_FP_TO_INT32 : INSN_FP_TO_INT64, op_size, 0, 0);
2977 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, OP_SIZE_INT, target, sign_bit(uint_default_t), COND_E, label_ovf));
2979 g(gen_frame_store(ctx, OP_SIZE_INT, slot_r, 0, target));
2982 #if defined(ARCH_ARM) || defined(ARCH_LOONGARCH64) || defined(ARCH_MIPS)
2983 #if defined(ARCH_ARM)
2984 gen_insn(INSN_FP_CMP, op_size, 0, 1);
2987 #if defined(ARCH_ARM32)
2988 gen_insn(INSN_FP_TO_INT_FLAGS, 0, 0, 1);
2990 gen_insn(INSN_JMP_COND, op_size, FP_COND_P, 0);
2991 gen_four(label_ovf);
2993 gen_insn(INSN_FP_CMP_COND, op_size, FP_COND_P, 1);
2997 gen_insn(INSN_JMP_FP_TEST, 0, FP_COND_P, 0);
2998 gen_four(label_ovf);
3000 #if defined(ARCH_ARM32) || defined(ARCH_LOONGARCH64) || defined(ARCH_MIPS)
3001 gen_insn(OP_SIZE_INT == OP_SIZE_4 ? INSN_FP_TO_INT32 : INSN_FP_TO_INT64, op_size, 0, 0);
3002 gen_one(FR_SCRATCH_1);
3005 g(gen_mov(ctx, OP_SIZE_INT, target, FR_SCRATCH_1));
3007 gen_insn(OP_SIZE_INT == OP_SIZE_4 ? INSN_FP_TO_INT32 : INSN_FP_TO_INT64, op_size, 0, 0);
3011 g(gen_imm(ctx, (int_default_t)(sign_bit(uint_default_t) + 1), IMM_PURPOSE_ADD, OP_SIZE_INT));
3012 gen_insn(INSN_ALU, OP_SIZE_INT, ALU_ADD, ALU_WRITES_FLAGS(ALU_ADD, is_imm()));
3013 gen_one(R_SCRATCH_2);
3017 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, OP_SIZE_INT, R_SCRATCH_2, 1, COND_BE, label_ovf));
3019 g(gen_frame_store(ctx, OP_SIZE_INT, slot_r, 0, target));
3022 #if defined(ARCH_IA64)
3023 gen_insn(INSN_FP_TO_INT64, op_size, 0, 0);
3024 gen_one(FR_SCRATCH_1);
3027 g(gen_mov(ctx, OP_SIZE_NATIVE, target, FR_SCRATCH_1));
3029 if (OP_SIZE_INT == OP_SIZE_4) {
3030 g(gen_extend(ctx, OP_SIZE_4, sign_x, R_SCRATCH_2, target));
3031 g(gen_cmp_test_jmp(ctx, INSN_CMP, OP_SIZE_NATIVE, target, R_SCRATCH_2, COND_NE, label_ovf));
3033 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, OP_SIZE_NATIVE, target, sign_bit(uint64_t), COND_E, label_ovf));
3036 g(gen_frame_store(ctx, OP_SIZE_INT, slot_r, 0, target));
3039 #if defined(ARCH_PARISC) || defined(ARCH_POWER) || defined(ARCH_SPARC)
3040 #if defined(ARCH_POWER)
3041 if (!cpu_test_feature(CPU_FEATURE_ppc))
3043 if (OP_SIZE_INT == OP_SIZE_4)
3046 gen_insn(OP_SIZE_INT == OP_SIZE_4 ? INSN_FP_TO_INT32 : INSN_FP_TO_INT64, op_size, 0, 0);
3047 gen_one(FR_SCRATCH_1);
3050 g(gen_frame_store_raw(ctx, OP_SIZE_INT, slot_r, 0, FR_SCRATCH_1));
3051 if (ctx->registers[slot_r] >= 0)
3052 g(unspill(ctx, slot_r));
3053 g(gen_frame_load(ctx, OP_SIZE_INT, garbage, slot_r, 0, target));
3055 g(gen_imm(ctx, sign_bit(uint_default_t) + 1, IMM_PURPOSE_ADD, OP_SIZE_INT));
3056 gen_insn(INSN_ALU, i_size(OP_SIZE_INT), ALU_ADD, ALU_WRITES_FLAGS(ALU_ADD, is_imm()));
3057 gen_one(R_SCRATCH_2);
3061 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, OP_SIZE_INT, R_SCRATCH_2, 1, COND_BE, label_ovf));
3065 #if defined(ARCH_ALPHA)
3066 gen_insn(INSN_FP_TO_INT64_TRAP, op_size, 0, 0);
3067 gen_one(FR_SCRATCH_2);
3069 gen_four(label_ovf);
3071 if (OP_SIZE_INT == OP_SIZE_4) {
3072 gen_insn(INSN_FP_INT64_TO_INT32_TRAP, 0, 0, 0);
3073 gen_one(FR_SCRATCH_3);
3074 gen_one(FR_SCRATCH_2);
3075 gen_four(label_ovf);
3076 g(gen_frame_store_raw(ctx, OP_SIZE_INT, slot_r, 0, FR_SCRATCH_3));
3078 g(gen_frame_store_raw(ctx, OP_SIZE_INT, slot_r, 0, FR_SCRATCH_2));
3080 if (ctx->registers[slot_r] >= 0)
3081 g(unspill(ctx, slot_r));
3084 #if defined(ARCH_S390)
3085 gen_insn(OP_SIZE_INT == OP_SIZE_4 ? INSN_FP_TO_INT32 : INSN_FP_TO_INT64, op_size, 0, 1);
3089 gen_insn(INSN_JMP_COND, op_size, FP_COND_P, 0);
3090 gen_four(label_ovf);
3092 g(gen_frame_store(ctx, OP_SIZE_INT, slot_r, 0, target));
3095 #if defined(ARCH_RISCV64)
3096 gen_insn(OP_SIZE_INT == OP_SIZE_4 ? INSN_FP_TO_INT32 : INSN_FP_TO_INT64, op_size, 0, 0);
3100 g(gen_load_constant(ctx, R_SCRATCH_2, sign_bit(int_default_t)));
3102 g(gen_cmp_test_jmp(ctx, INSN_CMP, OP_SIZE_NATIVE, target, R_SCRATCH_2, COND_E, label_ovf));
3104 g(gen_imm(ctx, -1, IMM_PURPOSE_XOR, i_size(size)));
3105 gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_XOR, ALU_WRITES_FLAGS(ALU_XOR, is_imm()));
3106 gen_one(R_SCRATCH_2);
3107 gen_one(R_SCRATCH_2);
3110 g(gen_cmp_test_jmp(ctx, INSN_CMP, OP_SIZE_NATIVE, target, R_SCRATCH_2, COND_E, label_ovf));
3112 g(gen_frame_store(ctx, OP_SIZE_INT, slot_r, 0, target));
3116 #ifdef SUPPORTED_FP_X87
3117 if ((SUPPORTED_FP_X87 >> real_type) & 1) {
3118 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_1));
3120 if (likely(cpu_test_feature(CPU_FEATURE_sse3))) {
3121 g(gen_frame_store_x87(ctx, INSN_X87_FISTTP, OP_SIZE_INT, slot_r));
3123 gen_insn(INSN_PUSH, OP_SIZE_NATIVE, 0, 0);
3127 gen_insn(INSN_X87_FLDCW, 0, 0, 0);
3128 gen_one(ARG_ADDRESS_1);
3132 g(gen_frame_store_x87(ctx, INSN_X87_FISTP, OP_SIZE_INT, slot_r));
3134 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
3135 gen_one(ARG_ADDRESS_1);
3141 gen_insn(INSN_X87_FLDCW, 0, 0, 0);
3142 gen_one(ARG_ADDRESS_1);
3146 gen_insn(INSN_ALU, i_size(OP_SIZE_ADDRESS), ALU_ADD, 1);
3150 gen_eight(1 << OP_SIZE_NATIVE);
3152 if (ctx->registers[slot_r] >= 0)
3153 g(unspill(ctx, slot_r));
3154 g(gen_frame_load(ctx, OP_SIZE_INT, garbage, slot_r, 0, R_SCRATCH_1));
3156 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, OP_SIZE_INT, R_SCRATCH_1, sign_bit(int_default_t), COND_E, label_ovf));
3161 #ifdef SUPPORTED_FP_HALF_CVT
3162 if ((SUPPORTED_FP_HALF_CVT >> real_type) & 1) {
3163 g(gen_frame_get(ctx, op_size, zero_x, slot_1, 0, FR_SCRATCH_1, ®1));
3164 gen_insn(INSN_FP_CVT, op_size, OP_SIZE_4, 0);
3165 gen_one(FR_SCRATCH_1);
3167 reg1 = FR_SCRATCH_1;
3169 op_size = real_type_to_op_size(real_type);
3176 if ((SUPPORTED_FP >> real_type) & 1) {
3177 #if defined(ARCH_ALPHA) || defined(ARCH_ARM32) || defined(ARCH_LOONGARCH64) || defined(ARCH_MIPS) || defined(ARCH_PARISC) || defined(ARCH_POWER) || defined(ARCH_SPARC)
3178 int int_op_size = OP_SIZE_INT;
3179 #if defined(ARCH_POWER)
3180 if (int_op_size == OP_SIZE_4)
3182 if (op_size == OP_SIZE_4 && !cpu_test_feature(CPU_FEATURE_v206))
3184 if (op_size == OP_SIZE_8 && !cpu_test_feature(CPU_FEATURE_ppc))
3187 if (ctx->registers[slot_1] >= 0)
3188 g(spill(ctx, slot_1));
3189 g(gen_frame_load_raw(ctx, int_op_size, zero_x, slot_1, 0, FR_SCRATCH_1));
3190 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, FR_SCRATCH_2);
3191 #if defined(ARCH_ALPHA)
3192 if (OP_SIZE_INT == OP_SIZE_4) {
3193 gen_insn(INSN_MOVSX, OP_SIZE_4, 0, 0);
3194 gen_one(FR_SCRATCH_1);
3195 gen_one(FR_SCRATCH_1);
3197 int_op_size = OP_SIZE_8;
3200 gen_insn(int_op_size == OP_SIZE_4 ? INSN_FP_FROM_INT32 : INSN_FP_FROM_INT64, op_size, 0, 0);
3202 gen_one(FR_SCRATCH_1);
3204 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
3206 #elif defined(ARCH_IA64)
3207 g(gen_frame_get(ctx, OP_SIZE_INT, sign_x, slot_1, 0, R_SCRATCH_1, ®1));
3208 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, FR_SCRATCH_1);
3210 g(gen_mov(ctx, OP_SIZE_NATIVE, target, reg1));
3212 gen_insn(INSN_FP_FROM_INT64, op_size, 0, 0);
3216 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
3219 g(gen_frame_get(ctx, OP_SIZE_INT, garbage, slot_1, 0, R_SCRATCH_1, ®1));
3220 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, FR_SCRATCH_1);
3222 gen_insn(OP_SIZE_INT == OP_SIZE_4 ? INSN_FP_FROM_INT32 : INSN_FP_FROM_INT64, op_size, 0, 0);
3226 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
3230 #ifdef SUPPORTED_FP_X87
3231 if ((SUPPORTED_FP_X87 >> real_type) & 1) {
3232 if (ctx->registers[slot_1] >= 0)
3233 g(spill(ctx, slot_1));
3234 g(gen_frame_load_x87(ctx, INSN_X87_FILD, OP_SIZE_INT, 0, slot_1));
3235 g(gen_frame_store_x87(ctx, INSN_X87_FSTP, op_size, slot_r));
3239 #ifdef SUPPORTED_FP_HALF_CVT
3240 if ((SUPPORTED_FP_HALF_CVT >> real_type) & 1) {
3241 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, FR_SCRATCH_1);
3242 #if defined(ARCH_ARM32)
3243 g(gen_frame_get(ctx, OP_SIZE_INT, zero_x, slot_1, 0, FR_SCRATCH_1, ®1));
3245 gen_insn(INSN_FP_FROM_INT32, OP_SIZE_4, 0, 0);
3249 g(gen_frame_get(ctx, OP_SIZE_INT, garbage, slot_1, 0, R_SCRATCH_1, ®1));
3250 gen_insn(OP_SIZE_INT == OP_SIZE_4 ? INSN_FP_FROM_INT32 : INSN_FP_FROM_INT64, OP_SIZE_4, 0, 0);
3254 gen_insn(INSN_FP_CVT, OP_SIZE_4, op_size, 0);
3257 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
3264 if ((SUPPORTED_FP >> real_type) & 1) {
3265 g(gen_frame_get(ctx, op_size, zero_x, slot_1, 0, FR_SCRATCH_1, ®1));
3266 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
3267 #if defined(ARCH_ALPHA)
3268 gen_insn(INSN_FP_CMP_UNORDERED_DEST_REG, op_size, 0, 0);
3269 gen_one(FR_SCRATCH_2);
3270 gen_one(FR_SCRATCH_1);
3273 if (!cpu_test_feature(CPU_FEATURE_fix)) {
3274 g(gen_frame_store_raw(ctx, OP_SIZE_4, slot_r, 0, FR_SCRATCH_2));
3275 g(gen_frame_load_raw(ctx, OP_SIZE_4, sign_x, slot_r, 0, target));
3277 g(gen_mov(ctx, OP_SIZE_4, target, FR_SCRATCH_2));
3280 g(gen_3address_rot_imm(ctx, OP_SIZE_NATIVE, ROT_SHR, target, target, 30, 0));
3282 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, target));
3285 #elif defined(ARCH_IA64)
3286 gen_insn(INSN_FP_CMP_DEST_REG, op_size, FP_COND_P, 0);
3287 gen_one(R_CMP_RESULT);
3291 g(gen_mov(ctx, OP_SIZE_NATIVE, target, R_CMP_RESULT));
3293 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, target));
3294 #elif defined(ARCH_LOONGARCH64) || defined(ARCH_MIPS) || defined(ARCH_PARISC)
3295 gen_insn(INSN_FP_CMP_COND, op_size, FP_COND_P, 1);
3299 gen_insn(INSN_FP_TEST_REG, OP_SIZE_NATIVE, FP_COND_P, 0);
3302 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, target));
3303 #elif defined(ARCH_RISCV64)
3304 gen_insn(INSN_FP_CMP_DEST_REG, op_size, FP_COND_E, 0);
3309 g(gen_imm(ctx, 1, IMM_PURPOSE_XOR, OP_SIZE_NATIVE));
3310 gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_XOR, ALU_WRITES_FLAGS(ALU_XOR, is_imm()));
3315 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, target));
3317 gen_insn(INSN_FP_CMP, op_size, 0, 1);
3320 #if defined(ARCH_ARM32)
3321 gen_insn(INSN_FP_TO_INT_FLAGS, 0, 0, 1);
3323 g(gen_frame_set_cond(ctx, op_size, false, FP_COND_P, slot_r));
3327 #ifdef SUPPORTED_FP_X87
3328 if ((SUPPORTED_FP_X87 >> real_type) & 1) {
3329 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_1));
3330 if (likely(cpu_test_feature(CPU_FEATURE_cmov))) {
3331 gen_insn(INSN_X87_FCOMIP, op_size, 0, 0);
3334 g(gen_frame_set_cond(ctx, op_size, false, COND_P, slot_r));
3338 gen_insn(INSN_X87_FCOMP, op_size, 0, 0);
3341 gen_insn(INSN_X87_FNSTSW, 0, 0, 0);
3345 gen_insn(INSN_TEST, OP_SIZE_2, 0, 1);
3350 g(gen_frame_set_cond(ctx, op_size, false, COND_NE, slot_r));
3355 #ifdef SUPPORTED_FP_HALF_CVT
3356 if ((SUPPORTED_FP_HALF_CVT >> real_type) & 1) {
3357 g(gen_frame_get(ctx, op_size, zero_x, slot_1, 0, FR_SCRATCH_1, ®1));
3358 gen_insn(INSN_FP_CVT, op_size, OP_SIZE_4, 0);
3359 gen_one(FR_SCRATCH_1);
3361 gen_insn(INSN_FP_CMP, OP_SIZE_4, 0, 1);
3362 gen_one(FR_SCRATCH_1);
3363 gen_one(FR_SCRATCH_1);
3364 #if defined(ARCH_ARM32)
3365 gen_insn(INSN_FP_TO_INT_FLAGS, 0, 0, 1);
3367 g(gen_frame_set_cond(ctx, op_size, false, FP_COND_P, slot_r));
3373 g(gen_alu_typed_upcall(ctx, upc, real_type, slot_1, NO_FRAME_T, slot_r, label_ovf));
3377 static bool attr_w gen_is_exception(struct codegen_context *ctx, frame_t slot_1, frame_t slot_r)
3379 uint32_t no_ex_label, escape_label;
3380 const struct type *type = get_type_of_local(ctx, slot_1);
3382 no_ex_label = alloc_label(ctx);
3383 if (unlikely(!no_ex_label))
3385 escape_label = alloc_escape_label(ctx);
3386 if (unlikely(!escape_label))
3389 if (TYPE_IS_FLAT(type))
3390 g(gen_test_1_jz_cached(ctx, slot_1, no_ex_label));
3392 g(gen_frame_load(ctx, OP_SIZE_SLOT, zero_x, slot_1, 0, R_SCRATCH_1));
3393 g(gen_ptr_is_thunk(ctx, R_SCRATCH_1, slot_1, escape_label));
3395 if (!TYPE_IS_FLAT(type)) {
3396 g(gen_compare_da_tag(ctx, R_SCRATCH_1, DATA_TAG_flat, COND_E, escape_label, R_SCRATCH_1));
3399 gen_label(no_ex_label);
3400 g(gen_frame_clear(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r));
3402 flag_set(ctx, slot_r, false);
3407 static bool attr_w gen_system_property(struct codegen_context *ctx, frame_t slot_1, frame_t slot_r)
3409 uint32_t escape_label;
3411 escape_label = alloc_escape_label(ctx);
3412 if (unlikely(!escape_label))
3415 g(gen_test_1_cached(ctx, slot_1, escape_label));
3417 g(gen_upcall_start(ctx, 1));
3419 g(gen_frame_load(ctx, OP_SIZE_INT, garbage, slot_1, 0, R_ARG0));
3420 g(gen_upcall_argument(ctx, 0));
3422 g(gen_upcall(ctx, offsetof(struct cg_upcall_vector_s, ipret_system_property), 1));
3424 g(gen_frame_store(ctx, OP_SIZE_INT, slot_r, 0, R_RET0));
3426 flag_set(ctx, slot_1, false);
3427 flag_set(ctx, slot_r, false);
3432 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)
3437 unsigned attr_unused reg2;
3439 *failed = true; return true;
3442 case MODE_FIXED: switch (op) {
3443 case OPCODE_FIXED_OP_equal: alu = COND_E; goto do_compare;
3444 case OPCODE_FIXED_OP_not_equal: alu = COND_NE; goto do_compare;
3445 case OPCODE_FIXED_OP_less: alu = COND_L; goto do_compare;
3446 case OPCODE_FIXED_OP_less_equal: alu = COND_LE; goto do_compare;
3447 case OPCODE_FIXED_OP_uless: alu = COND_B; goto do_compare;
3448 case OPCODE_FIXED_OP_uless_equal: alu = COND_BE; goto do_compare;
3449 case OPCODE_FIXED_OP_bt: *failed = true; return true;
3450 default: internal(file_line, "gen_alu_jmp: unsupported fixed operation %u", op);
3452 case MODE_INT: switch (op) {
3453 case OPCODE_INT_OP_equal: alu = COND_E; goto do_compare;
3454 case OPCODE_INT_OP_not_equal: alu = COND_NE; goto do_compare;
3455 case OPCODE_INT_OP_less: alu = COND_L; goto do_compare;
3456 case OPCODE_INT_OP_less_equal: alu = COND_LE; goto do_compare;
3457 case OPCODE_INT_OP_bt: *failed = true; return true;
3458 default: internal(file_line, "gen_alu_jmp: unsupported int operation %u", op);
3460 case MODE_BOOL: switch (op) {
3461 case OPCODE_BOOL_OP_and: alu = ALU_AND; mode = MODE_FIXED; goto do_alu;
3462 case OPCODE_BOOL_OP_or: alu = ALU_OR; mode = MODE_FIXED; goto do_alu;
3463 case OPCODE_BOOL_OP_equal: alu = COND_E; mode = MODE_FIXED; goto do_compare;
3464 case OPCODE_BOOL_OP_not_equal: alu = COND_NE; mode = MODE_FIXED; goto do_compare;
3465 case OPCODE_BOOL_OP_less: alu = COND_L; mode = MODE_FIXED; goto do_compare;
3466 case OPCODE_BOOL_OP_less_equal: alu = COND_LE; mode = MODE_FIXED; goto do_compare;
3467 default: internal(file_line, "gen_alu_jmp: unsupported bool operation %u", op);
3470 internal(file_line, "gen_alu_jmp: unsupported mode %u", mode);
3472 bool attr_unused logical;
3473 if (unlikely(op_size > OP_SIZE_NATIVE)) {
3477 if (ctx->registers[slot_2] >= 0 && ctx->registers[slot_1] < 0) {
3482 case COND_L: alu = COND_G; break;
3483 case COND_LE: alu = COND_GE; break;
3484 case COND_B: alu = COND_A; break;
3485 case COND_BE: alu = COND_AE; break;
3488 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;
3489 g(gen_frame_get(ctx, op_size, ex, slot_1, 0, R_SCRATCH_1, ®1));
3490 if (ARCH_HAS_JMP_2REGS(alu)) {
3491 g(gen_frame_get(ctx, op_size, ex, slot_2, 0, R_SCRATCH_2, ®2));
3492 g(gen_jump(ctx, jmp_offset, i_size_cmp(op_size), alu ^ 1, reg1, reg2));
3496 logical = COND_IS_LOGICAL(alu ^ 1);
3497 g(gen_frame_load_cmp(ctx, op_size, logical, ex, false, slot_2, 0, reg1));
3498 g(gen_jump(ctx, jmp_offset, op_size, alu ^ 1, -1U, -1U));
3500 g(gen_frame_get(ctx, op_size, ex, slot_2, 0, R_SCRATCH_2, ®2));
3501 g(gen_cmp_dest_reg(ctx, op_size, reg1, reg2, R_CMP_RESULT, 0, alu));
3502 g(gen_jump(ctx, jmp_offset, OP_SIZE_NATIVE, COND_E, R_CMP_RESULT, -1U));
3507 if (ctx->registers[slot_2] >= 0 && ctx->registers[slot_1] < 0) {
3512 ex = op_size == i_size(op_size) + (unsigned)zero ? garbage : ARCH_PREFERS_SX(op_size) ? sign_x : zero_x;
3513 g(gen_frame_get(ctx, op_size, ex, slot_1, 0, R_SCRATCH_1, ®1));
3514 #if defined(ARCH_X86)
3515 if (alu == ALU_AND && ctx->registers[slot_2] < 0) {
3516 g(gen_address(ctx, R_FRAME, (size_t)slot_2 * slot_size, IMM_PURPOSE_LDR_OFFSET, op_size));
3517 gen_insn(INSN_TEST, i_size(op_size), 0, 1);
3519 gen_address_offset();
3520 g(gen_jump(ctx, jmp_offset, op_size, COND_E, -1U, -1U));
3524 g(gen_frame_get(ctx, op_size, ex, slot_2, 0, R_SCRATCH_2, ®2));
3525 #if ARCH_HAS_FLAGS && !defined(ARCH_S390)
3526 if (alu == ALU_AND) {
3527 gen_insn(INSN_TEST, i_size(op_size), 0, 1);
3530 g(gen_jump(ctx, jmp_offset, op_size, COND_E, -1U, -1U));
3534 #if defined(ARCH_ARM64)
3539 g(gen_3address_alu(ctx, i_size(op_size), alu, R_SCRATCH_1, reg1, reg2, 1));
3540 g(gen_jump(ctx, jmp_offset, i_size(op_size), COND_E, -1U, -1U));
3545 g(gen_3address_alu(ctx, i_size(op_size), alu, R_SCRATCH_1, reg1, reg2, 0));
3546 g(gen_jump(ctx, jmp_offset, i_size(op_size), COND_E, R_SCRATCH_1, -1U));
3551 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)
3553 unsigned attr_unused fp_alu;
3554 unsigned attr_unused op_size = real_type_to_op_size(real_type);
3555 unsigned reg1, reg2;
3556 unsigned attr_unused target;
3558 case OPCODE_REAL_OP_equal:
3559 case OPCODE_REAL_OP_equal_alt1:
3560 case OPCODE_REAL_OP_equal_alt2: fp_alu = FP_COND_E; goto do_cmp;
3561 case OPCODE_REAL_OP_not_equal:
3562 case OPCODE_REAL_OP_not_equal_alt1:
3563 case OPCODE_REAL_OP_not_equal_alt2: fp_alu = FP_COND_NE; goto do_cmp;
3564 case OPCODE_REAL_OP_less:
3565 case OPCODE_REAL_OP_less_alt1:
3566 case OPCODE_REAL_OP_less_alt2: fp_alu = FP_COND_B; goto do_cmp;
3567 case OPCODE_REAL_OP_less_equal:
3568 case OPCODE_REAL_OP_less_equal_alt1:
3569 case OPCODE_REAL_OP_less_equal_alt2: fp_alu = FP_COND_BE; goto do_cmp;
3570 default: internal(file_line, "gen_fp_alu_jmp: unsupported operation %u", op);
3574 if ((SUPPORTED_FP >> real_type) & 1
3575 #if defined(ARCH_ALPHA)
3576 && ARCH_SUPPORTS_TRAPS && cpu_test_feature(CPU_FEATURE_fix)
3579 g(gen_frame_get(ctx, op_size, zero_x, slot_1, 0, FR_SCRATCH_1, ®1));
3580 g(gen_frame_get(ctx, op_size, zero_x, slot_2, 0, FR_SCRATCH_2, ®2));
3581 target = R_SCRATCH_1;
3582 #if defined(ARCH_ALPHA)
3583 gen_insn(INSN_FP_CMP_DEST_REG_TRAP, op_size, fp_alu == FP_COND_NE ? FP_COND_E : fp_alu, 0);
3584 gen_one(FR_SCRATCH_3);
3587 gen_four(label_ovf);
3589 g(gen_mov(ctx, OP_SIZE_4, target, FR_SCRATCH_3));
3591 if (fp_alu == FP_COND_NE) {
3592 g(gen_jump(ctx, jmp_offset, OP_SIZE_NATIVE, COND_NE, target, -1U));
3594 g(gen_jump(ctx, jmp_offset, OP_SIZE_NATIVE, COND_E, target, -1U));
3598 #elif defined(ARCH_IA64)
3599 gen_insn(INSN_FP_CMP_DEST_REG, op_size, FP_COND_P, 0);
3600 gen_one(R_CMP_RESULT);
3604 gen_insn(INSN_JMP_REG, OP_SIZE_NATIVE, COND_NE, 0);
3605 gen_one(R_CMP_RESULT);
3606 gen_four(label_ovf);
3608 gen_insn(INSN_FP_CMP_DEST_REG, op_size, fp_alu, 0);
3609 gen_one(R_CMP_RESULT);
3613 g(gen_jump(ctx, jmp_offset, OP_SIZE_NATIVE, COND_E, R_CMP_RESULT, -1U);
3616 #elif defined(ARCH_LOONGARCH64) || defined(ARCH_MIPS) || defined(ARCH_PARISC)
3617 gen_insn(INSN_FP_CMP_COND, op_size, FP_COND_P, 1);
3621 gen_insn(INSN_JMP_FP_TEST, 0, FP_COND_P, 0);
3622 gen_four(label_ovf);
3624 gen_insn(INSN_FP_CMP_COND, op_size, fp_alu ^ 1, 1);
3628 g(gen_jump(ctx, jmp_offset, OP_SIZE_NATIVE, fp_alu ^ 1, -1U, -1U));
3631 #elif defined(ARCH_RISCV64)
3632 gen_insn(INSN_FP_CMP_DEST_REG, op_size, FP_COND_E, 0);
3633 gen_one(R_SCRATCH_1);
3637 gen_insn(INSN_FP_CMP_DEST_REG, op_size, FP_COND_E, 0);
3638 gen_one(R_SCRATCH_2);
3642 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_AND, R_SCRATCH_1, R_SCRATCH_1, R_SCRATCH_2, 0));
3644 g(gen_jmp_on_zero(ctx, OP_SIZE_NATIVE, R_SCRATCH_1, COND_E, label_ovf));
3646 gen_insn(INSN_FP_CMP_DEST_REG, op_size, fp_alu == FP_COND_NE ? FP_COND_E : fp_alu, 0);
3651 if (fp_alu == FP_COND_NE) {
3652 g(gen_jump(ctx, jmp_offset, OP_SIZE_NATIVE, COND_NE, target, -1U));
3654 g(gen_jump(ctx, jmp_offset, OP_SIZE_NATIVE, COND_E, target, -1U));
3658 gen_insn(INSN_FP_CMP, op_size, 0, 1);
3661 #if defined(ARCH_ARM32)
3662 gen_insn(INSN_FP_TO_INT_FLAGS, 0, 0, 1);
3664 gen_insn(INSN_JMP_COND, op_size, FP_COND_P, 0);
3665 gen_four(label_ovf);
3666 g(gen_jump(ctx, jmp_offset, op_size, fp_alu ^ 1, -1U, -1U));