2 * Copyright (C) 2024 Mikulas Patocka
4 * This file is part of Ajla.
6 * Ajla is free software: you can redistribute it and/or modify it under the
7 * terms of the GNU General Public License as published by the Free Software
8 * Foundation, either version 3 of the License, or (at your option) any later
11 * Ajla is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along with
16 * Ajla. If not, see <https://www.gnu.org/licenses/>.
19 static bool attr_w gen_jump(struct codegen_context *ctx, int32_t jmp_offset, unsigned op_size, unsigned cond, unsigned reg1, unsigned reg2);
21 static bool attr_w gen_alu_upcall(struct codegen_context *ctx, size_t upcall, unsigned op_size, frame_t slot_1, frame_t slot_2, frame_t slot_r, uint32_t label_ovf)
23 if (slot_is_register(ctx, slot_1))
24 g(spill(ctx, slot_1));
25 if (slot_2 != NO_FRAME_T && slot_is_register(ctx, slot_2))
26 g(spill(ctx, slot_2));
27 g(gen_upcall_start(ctx, frame_t_is_const(slot_2) ? 4 : slot_2 != NO_FRAME_T ? 3 : 2));
28 g(gen_frame_address(ctx, slot_1, 0, R_ARG0));
29 g(gen_upcall_argument(ctx, 0));
30 if (frame_t_is_const(slot_2)) {
32 g(gen_load_constant(ctx, R_ARG1, frame_t_get_const(slot_2)));
33 g(gen_upcall_argument(ctx, 1));
34 g(gen_frame_address(ctx, slot_r, 0, R_ARG2));
35 g(gen_upcall_argument(ctx, 2));
36 g(gen_get_upcall_pointer(ctx, upcall, R_ARG3));
37 g(gen_upcall_argument(ctx, 3));
38 x_offs = offsetof(struct cg_upcall_vector_s, INT_binary_const_int8_t) + op_size * sizeof(void (*)(void));
39 g(gen_upcall(ctx, x_offs, 4));
40 } else if (slot_2 != NO_FRAME_T) {
41 g(gen_frame_address(ctx, slot_2, 0, R_ARG1));
42 g(gen_upcall_argument(ctx, 1));
43 g(gen_frame_address(ctx, slot_r, 0, R_ARG2));
44 g(gen_upcall_argument(ctx, 2));
45 g(gen_upcall(ctx, upcall, 3));
47 g(gen_frame_address(ctx, slot_r, 0, R_ARG1));
48 g(gen_upcall_argument(ctx, 1));
49 g(gen_upcall(ctx, upcall, 2));
51 if (slot_is_register(ctx, slot_r))
52 g(unspill(ctx, slot_r));
54 g(gen_jmp_on_zero(ctx, OP_SIZE_1, R_RET0, COND_E, label_ovf));
58 static bool attr_w gen_alu_typed_upcall(struct codegen_context *ctx, size_t upcall, unsigned op_size, frame_t slot_1, frame_t slot_2, frame_t slot_r, uint32_t label_ovf)
60 upcall += op_size * sizeof(void (*)(void));
61 return gen_alu_upcall(ctx, upcall, op_size, slot_1, slot_2, slot_r, label_ovf);
68 #define MODE_ARRAY_LEN_GT 4
70 static bool attr_w gen_alu(struct codegen_context *ctx, unsigned mode, unsigned op_size, unsigned op, uint32_t label_ovf, frame_t slot_1, frame_t slot_2, frame_t slot_r)
74 unsigned reg1, reg2, reg3, target;
76 case MODE_FIXED: switch (op) {
77 case OPCODE_FIXED_OP_add: alu = ALU_ADD; goto do_alu;
78 case OPCODE_FIXED_OP_subtract: alu = ALU_SUB; goto do_alu;
79 case OPCODE_FIXED_OP_multiply: goto do_multiply;
80 case OPCODE_FIXED_OP_divide:
81 case OPCODE_FIXED_OP_divide_alt1: sgn = true; mod = false; goto do_divide;
82 case OPCODE_FIXED_OP_udivide:
83 case OPCODE_FIXED_OP_udivide_alt1: sgn = false; mod = false; goto do_divide;
84 case OPCODE_FIXED_OP_modulo:
85 case OPCODE_FIXED_OP_modulo_alt1: sgn = true; mod = true; goto do_divide;
86 case OPCODE_FIXED_OP_umodulo:
87 case OPCODE_FIXED_OP_umodulo_alt1: sgn = false; mod = true; goto do_divide;
88 case OPCODE_FIXED_OP_power: return gen_alu_typed_upcall(ctx, offsetof(struct cg_upcall_vector_s, FIXED_binary_power_int8_t), op_size, slot_1, slot_2, slot_r, 0);
89 case OPCODE_FIXED_OP_and: alu = ALU_AND; goto do_alu;
90 case OPCODE_FIXED_OP_or: alu = ALU_OR; goto do_alu;
91 case OPCODE_FIXED_OP_xor: alu = ALU_XOR; goto do_alu;
92 case OPCODE_FIXED_OP_shl: alu = ROT_SHL; goto do_shift;
93 case OPCODE_FIXED_OP_shr: alu = ROT_SAR; goto do_shift;
94 case OPCODE_FIXED_OP_ushr: alu = ROT_SHR; goto do_shift;
95 case OPCODE_FIXED_OP_rol: alu = ROT_ROL; goto do_shift;
96 case OPCODE_FIXED_OP_ror: alu = ROT_ROR; goto do_shift;
97 case OPCODE_FIXED_OP_bts: alu = BTX_BTS; goto do_bt;
98 case OPCODE_FIXED_OP_btr: alu = BTX_BTR; goto do_bt;
99 case OPCODE_FIXED_OP_btc: alu = BTX_BTC; goto do_bt;
100 case OPCODE_FIXED_OP_equal: alu = COND_E; goto do_compare;
101 case OPCODE_FIXED_OP_not_equal: alu = COND_NE; goto do_compare;
102 case OPCODE_FIXED_OP_less: alu = COND_L; goto do_compare;
103 case OPCODE_FIXED_OP_less_equal: alu = COND_LE; goto do_compare;
104 case OPCODE_FIXED_OP_greater: alu = COND_G; goto do_compare;
105 case OPCODE_FIXED_OP_greater_equal: alu = COND_GE; goto do_compare;
106 case OPCODE_FIXED_OP_uless: alu = COND_B; goto do_compare;
107 case OPCODE_FIXED_OP_uless_equal: alu = COND_BE; goto do_compare;
108 case OPCODE_FIXED_OP_ugreater: alu = COND_A; goto do_compare;
109 case OPCODE_FIXED_OP_ugreater_equal: alu = COND_AE; goto do_compare;
110 case OPCODE_FIXED_OP_bt: alu = BTX_BT; goto do_bt;
111 default: internal(file_line, "gen_alu: unsupported fixed operation %u", op);
113 case MODE_INT: switch (op) {
114 case OPCODE_INT_OP_add: alu = ALU_ADD; goto do_alu;
115 case OPCODE_INT_OP_subtract: alu = ALU_SUB; goto do_alu;
116 case OPCODE_INT_OP_multiply: goto do_multiply;
117 case OPCODE_INT_OP_divide:
118 case OPCODE_INT_OP_divide_alt1: sgn = true; mod = false; goto do_divide;
119 case OPCODE_INT_OP_modulo:
120 case OPCODE_INT_OP_modulo_alt1: sgn = true; mod = true; goto do_divide;
121 case OPCODE_INT_OP_power: return gen_alu_typed_upcall(ctx, offsetof(struct cg_upcall_vector_s, INT_binary_power_int8_t), op_size, slot_1, slot_2, slot_r, label_ovf);
122 case OPCODE_INT_OP_and: alu = ALU_AND; mode = MODE_FIXED; goto do_alu;
123 case OPCODE_INT_OP_or: alu = ALU_OR; mode = MODE_FIXED; goto do_alu;
124 case OPCODE_INT_OP_xor: alu = ALU_XOR; mode = MODE_FIXED; goto do_alu;
125 case OPCODE_INT_OP_shl: alu = ROT_SHL; goto do_shift;
126 case OPCODE_INT_OP_shr: alu = ROT_SAR; goto do_shift;
127 case OPCODE_INT_OP_bts: alu = BTX_BTS; goto do_bt;
128 case OPCODE_INT_OP_btr: alu = BTX_BTR; goto do_bt;
129 case OPCODE_INT_OP_btc: alu = BTX_BTC; goto do_bt;
130 case OPCODE_INT_OP_equal: alu = COND_E; goto do_compare;
131 case OPCODE_INT_OP_not_equal: alu = COND_NE; goto do_compare;
132 case OPCODE_INT_OP_less: alu = COND_L; goto do_compare;
133 case OPCODE_INT_OP_less_equal: alu = COND_LE; goto do_compare;
134 case OPCODE_INT_OP_greater: alu = COND_G; goto do_compare;
135 case OPCODE_INT_OP_greater_equal: alu = COND_GE; goto do_compare;
136 case OPCODE_INT_OP_bt: alu = BTX_BT; goto do_bt;
137 default: internal(file_line, "gen_alu: unsupported int operation %u", op);
139 case MODE_BOOL: switch (op) {
140 case OPCODE_BOOL_OP_and: alu = ALU_AND; mode = MODE_FIXED; goto do_alu;
141 case OPCODE_BOOL_OP_or: alu = ALU_OR; mode = MODE_FIXED; goto do_alu;
142 case OPCODE_BOOL_OP_equal: alu = COND_E; goto do_compare;
143 case OPCODE_BOOL_OP_not_equal: alu = ALU_XOR; mode = MODE_FIXED; goto do_alu;
144 case OPCODE_BOOL_OP_less: alu = COND_L; goto do_compare;
145 case OPCODE_BOOL_OP_less_equal: alu = COND_LE; goto do_compare;
146 case OPCODE_BOOL_OP_greater: alu = COND_G; goto do_compare;
147 case OPCODE_BOOL_OP_greater_equal: alu = COND_GE; goto do_compare;
148 default: internal(file_line, "gen_alu: unsupported bool operation %u", op);
151 internal(file_line, "gen_alu: unsupported mode %u", mode);
157 size_t attr_unused offset;
158 uint8_t attr_unused long_imm;
159 unsigned first_flags;
160 unsigned second_flags;
162 unsigned attr_unused op_size_flags;
164 if (unlikely(op_size > OP_SIZE_NATIVE)) {
165 #if !defined(ARCH_X86) && !defined(ARCH_ARM) && !defined(ARCH_PARISC) && !defined(ARCH_POWER) && !defined(ARCH_SPARC32)
166 if (mode == MODE_FIXED) {
167 if (alu == ALU_ADD) {
168 g(gen_alu_upcall(ctx, offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_add_,TYPE_INT_MAX)), op_size, slot_1, slot_2, slot_r, 0));
170 } else if (alu == ALU_SUB) {
171 g(gen_alu_upcall(ctx, offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_subtract_,TYPE_INT_MAX)), op_size, slot_1, slot_2, slot_r, 0));
174 } else if (mode == MODE_INT) {
175 if (alu == ALU_ADD) {
176 g(gen_alu_upcall(ctx, offsetof(struct cg_upcall_vector_s, cat(INT_binary_add_,TYPE_INT_MAX)), op_size, slot_1, slot_2, slot_r, label_ovf));
178 } else if (alu == ALU_SUB) {
179 g(gen_alu_upcall(ctx, offsetof(struct cg_upcall_vector_s, cat(INT_binary_subtract_,TYPE_INT_MAX)), op_size, slot_1, slot_2, slot_r, label_ovf));
184 first_flags = alu == ALU_ADD || alu == ALU_SUB ? 2 : 0;
185 second_flags = mode == MODE_INT ? 1 : 0;
186 second_alu = alu == ALU_ADD ? ALU_ADC : alu == ALU_SUB ? ALU_SBB : alu;
187 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_1, 0, R_SCRATCH_1, R_SCRATCH_2));
188 #if defined(ARCH_X86)
189 g(gen_frame_load_op(ctx, OP_SIZE_NATIVE, garbage, alu, first_flags, slot_2, lo_word(OP_SIZE_NATIVE), true, R_SCRATCH_1));
190 g(gen_frame_load_op(ctx, OP_SIZE_NATIVE, garbage, second_alu, second_flags, slot_2, hi_word(OP_SIZE_NATIVE), true, R_SCRATCH_2));
192 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_2, 0, R_SCRATCH_3, R_SCRATCH_4));
193 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, alu, R_SCRATCH_1, R_SCRATCH_1, R_SCRATCH_3, first_flags));
194 #if defined(ARCH_PARISC)
195 if (mode == MODE_INT) {
196 gen_insn(INSN_ALU_FLAGS_TRAP, OP_SIZE_NATIVE, second_alu, ALU_WRITES_FLAGS(OP_SIZE_NATIVE, second_alu, false, false, 0));
197 gen_one(R_SCRATCH_2);
198 gen_one(R_SCRATCH_2);
199 gen_one(R_SCRATCH_4);
204 gen_insn(first_flags ? INSN_ALU_FLAGS : INSN_ALU, OP_SIZE_NATIVE, second_alu, second_flags | ALU_WRITES_FLAGS(OP_SIZE_NATIVE, second_alu, false, false, 0));
205 gen_one(R_SCRATCH_2);
206 gen_one(R_SCRATCH_2);
207 gen_one(R_SCRATCH_4);
210 #if !defined(ARCH_PARISC)
211 if (mode == MODE_INT) {
212 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_O, 0);
216 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, R_SCRATCH_1, R_SCRATCH_2));
220 if (((ARCH_HAS_FLAGS && i_size_cmp(op_size) == op_size + zero) || ARCH_SUPPORTS_TRAPS(op_size)) && slot_2 == slot_r && slot_1 != slot_2 && alu_is_commutative(alu)) {
225 if (((ARCH_HAS_FLAGS && i_size_cmp(op_size) == op_size + zero) || ARCH_SUPPORTS_TRAPS(op_size)) && slot_1 == slot_r && (slot_1 != slot_2 || mode != MODE_INT)
226 #if defined(ARCH_POWER)
227 && op_size == OP_SIZE_NATIVE
231 unsigned undo_alu = alu == ALU_ADD ? ALU_SUB : ALU_ADD;
232 if (slot_is_register(ctx, slot_1)) {
233 unsigned reg1 = ctx->registers[slot_1];
234 if (slot_is_register(ctx, slot_2)
235 #if !defined(ARCH_POWER)
236 || frame_t_is_const(slot_2)
239 unsigned reg2 = frame_t_is_const(slot_2) ? 0xff /* avoid warning */ : ctx->registers[slot_2];
240 if (mode == MODE_INT && ARCH_SUPPORTS_TRAPS(op_size)) {
241 if (frame_t_is_const(slot_2))
242 g(gen_imm(ctx, frame_t_get_const(slot_2), alu_trap_purpose(alu) | (alu_purpose(undo_alu) << 8), i_size(op_size)));
243 gen_insn(INSN_ALU_TRAP, op_size, alu, ALU_WRITES_FLAGS(op_size, alu, false, frame_t_is_const(slot_2) && is_imm(), ctx->const_imm));
246 if (frame_t_is_const(slot_2))
250 if (ARCH_TRAP_BEFORE) {
254 ce = alloc_undo_label(ctx);
257 gen_four(ce->undo_label);
261 if (frame_t_is_const(slot_2))
262 g(gen_imm(ctx, frame_t_get_const(slot_2), alu_purpose(alu) | (alu_purpose(undo_alu) << 8), i_size(op_size)));
263 gen_insn(INSN_ALU + ARCH_PARTIAL_ALU(i_size(op_size)), i_size(op_size), alu, ALU_WRITES_FLAGS(i_size(op_size), alu, false, frame_t_is_const(slot_2) && is_imm(), ctx->const_imm));
266 if (frame_t_is_const(slot_2))
270 if (mode == MODE_INT) {
272 ce = alloc_undo_label(ctx);
275 gen_insn(INSN_JMP_COND, i_size_cmp(op_size), COND_O, 0);
276 gen_four(ce->undo_label);
278 ce->undo_opcode = INSN_ALU + ARCH_PARTIAL_ALU(i_size(op_size));
279 ce->undo_op_size = i_size(op_size);
280 ce->undo_aux = undo_alu;
281 ce->undo_writes_flags = ALU_WRITES_FLAGS(i_size(op_size), undo_alu, false, frame_t_is_const(slot_2) && is_imm(), ctx->const_imm);
282 m = mark_params(ctx);
285 if (frame_t_is_const(slot_2))
289 copy_params(ctx, ce, m);
293 #if defined(ARCH_S390) || defined(ARCH_X86)
294 else if (!frame_t_is_const(slot_2)) {
296 int64_t offset = (size_t)slot_2 * slot_size;
297 g(gen_address(ctx, R_FRAME, offset, IMM_PURPOSE_LDR_OFFSET, i_size(op_size)));
298 gen_insn(INSN_ALU + ARCH_PARTIAL_ALU(i_size(op_size)), i_size(op_size), alu, ALU_WRITES_FLAGS(i_size(op_size), alu, true, false, 0) | 1);
301 gen_address_offset();
302 if (mode == MODE_INT) {
303 ce = alloc_undo_label(ctx);
306 ce->undo_opcode = INSN_ALU + ARCH_PARTIAL_ALU(i_size(op_size));
307 ce->undo_op_size = i_size(op_size);
308 ce->undo_aux = undo_alu;
309 ce->undo_writes_flags = ALU_WRITES_FLAGS(i_size(op_size), undo_alu, true, false, 0);
310 m = mark_params(ctx);
313 gen_address_offset();
314 copy_params(ctx, ce, m);
315 gen_insn(INSN_JMP_COND, i_size_cmp(op_size), COND_O, 0);
316 gen_four(ce->undo_label);
322 #if defined(ARCH_X86)
326 int64_t offset = (size_t)slot_1 * slot_size;
327 if (!frame_t_is_const(slot_2))
328 g(gen_frame_get(ctx, op_size, garbage, slot_2, R_SCRATCH_1, ®2));
329 g(gen_address(ctx, R_FRAME, offset, IMM_PURPOSE_LDR_OFFSET, i_size(op_size)));
330 if (frame_t_is_const(slot_2))
331 g(gen_imm(ctx, frame_t_get_const(slot_2), alu_purpose(alu) | (alu_purpose(undo_alu) << 8), i_size(op_size)));
332 gen_insn(INSN_ALU + ARCH_PARTIAL_ALU(op_size), i_size(op_size), alu, ALU_WRITES_FLAGS(i_size(op_size), undo_alu, true, frame_t_is_const(slot_2) && is_imm(), ctx->const_imm) | 1);
333 gen_address_offset();
334 gen_address_offset();
335 if (frame_t_is_const(slot_2))
339 if (mode == MODE_INT) {
340 ce = alloc_undo_label(ctx);
343 ce->undo_opcode = INSN_ALU + ARCH_PARTIAL_ALU(op_size);
344 ce->undo_op_size = i_size(op_size);
345 ce->undo_aux = undo_alu;
346 ce->undo_writes_flags = ALU_WRITES_FLAGS(i_size(op_size), undo_alu, true, false, 0);
347 m = mark_params(ctx);
348 gen_address_offset();
349 gen_address_offset();
350 if (frame_t_is_const(slot_2))
354 copy_params(ctx, ce, m);
355 gen_insn(INSN_JMP_COND, i_size_cmp(op_size), COND_O, 0);
356 gen_four(ce->undo_label);
363 #if defined(ARCH_X86)
365 #elif defined(ARCH_S390)
366 if (op_size >= OP_SIZE_4)
367 #elif ARCH_HAS_FLAGS && !defined(ARCH_POWER)
368 if (op_size == i_size(op_size) + (unsigned)zero && frame_t_is_const(slot_2))
370 if (mode != MODE_INT && op_size == i_size(op_size) + (unsigned)zero && frame_t_is_const(slot_2))
373 if (mode == MODE_INT) {
374 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
376 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, slot_2, R_SCRATCH_1);
378 g(gen_frame_load(ctx, op_size, garbage, slot_1, 0, false, target));
379 g(gen_frame_load_op(ctx, op_size, garbage, alu, mode == MODE_INT, slot_2, 0, false, target));
380 goto check_ovf_store;
382 op_size_flags = !ARCH_HAS_FLAGS && !ARCH_SUPPORTS_TRAPS(op_size) ? OP_SIZE_NATIVE : OP_SIZE_4;
383 #if defined(ARCH_POWER)
384 op_size_flags = OP_SIZE_NATIVE;
386 g(gen_frame_get(ctx, op_size, mode == MODE_INT && (op_size < op_size_flags || ARCH_SUPPORTS_TRAPS(op_size)) ? sign_x : garbage, slot_1, R_SCRATCH_1, ®1));
387 if (frame_t_is_const(slot_2)
388 #if defined(ARCH_POWER)
395 g(gen_frame_get(ctx, op_size, mode == MODE_INT && (op_size < op_size_flags || ARCH_SUPPORTS_TRAPS(op_size)) ? sign_x : garbage, slot_2, R_SCRATCH_2, ®2));
399 if (mode == MODE_INT && op_size >= OP_SIZE_4) {
400 if (ARCH_SUPPORTS_TRAPS(op_size)) {
401 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
403 g(gen_imm(ctx, frame_t_get_const(slot_2), alu_trap_purpose(alu), op_size));
404 gen_insn(INSN_ALU_TRAP, op_size, alu, ALU_WRITES_FLAGS(op_size, alu, false, c && is_imm(), ctx->const_imm));
412 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
415 if (op_size >= OP_SIZE_NATIVE) {
416 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_3);
418 g(gen_3address_alu_imm(ctx, i_size(op_size), alu, target, reg1, frame_t_get_const(slot_2), 0));
420 g(gen_3address_alu(ctx, i_size(op_size), alu, target, reg1, reg2, 0));
421 #if defined(ARCH_IA64)
423 g(gen_3address_alu_imm(ctx, i_size(op_size), ALU_XOR, R_SCRATCH_1, reg1, frame_t_get_const(slot_2), 0));
424 g(gen_3address_alu_imm(ctx, i_size(op_size), ALU_XOR, R_SCRATCH_2, target, frame_t_get_const(slot_2), 0));
426 g(gen_3address_alu(ctx, i_size(op_size), ALU_XOR, R_SCRATCH_1, reg1, reg2, 0));
427 g(gen_3address_alu(ctx, i_size(op_size), ALU_XOR, R_SCRATCH_2, target, reg2, 0));
429 if (alu == ALU_ADD) {
430 g(gen_3address_alu(ctx, i_size(op_size), ALU_ANDN, R_SCRATCH_1, R_SCRATCH_2, R_SCRATCH_1, 0));
432 g(gen_3address_alu(ctx, i_size(op_size), ALU_ANDN, R_SCRATCH_1, R_SCRATCH_1, R_SCRATCH_2, 0));
434 g(gen_cmp_test_jmp(ctx, INSN_TEST, i_size(op_size), R_SCRATCH_1, R_SCRATCH_1, COND_S, label_ovf));
437 g(gen_cmp_test_jmp(ctx, INSN_CMP, i_size(op_size), reg1, target, (frame_t_get_const(slot_2) >= 0) ^ (alu != ALU_ADD) ? COND_G : COND_L, label_ovf));
439 gen_insn(INSN_CMP_DEST_REG, i_size(op_size), COND_L, 0);
440 gen_one(R_SCRATCH_1);
441 if (alu == ALU_ADD) {
449 g(gen_imm(ctx, 0, IMM_PURPOSE_CMP, i_size(op_size)));
450 gen_insn(INSN_CMP_DEST_REG, i_size(op_size), COND_L, 0);
451 gen_one(R_SCRATCH_2);
455 g(gen_cmp_test_jmp(ctx, INSN_CMP, i_size(op_size), R_SCRATCH_1, R_SCRATCH_2, COND_NE, label_ovf));
458 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
463 if (mode == MODE_INT) {
464 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
465 } else if (!ARCH_IS_3ADDRESS(alu, mode == MODE_INT && op_size >= op_size_flags) && !alu_is_commutative(alu)) {
466 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, slot_2, R_SCRATCH_1);
468 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
471 g(gen_3address_alu_imm(ctx, i_size(op_size), alu, target, reg1, frame_t_get_const(slot_2), mode == MODE_INT && op_size >= op_size_flags));
473 g(gen_3address_alu(ctx, i_size(op_size), alu, target, reg1, reg2, mode == MODE_INT && op_size >= op_size_flags));
476 if (mode == MODE_INT && unlikely(op_size < op_size_flags)) {
477 g(gen_cmp_extended(ctx, op_size_flags, op_size, target, R_SCRATCH_2, label_ovf));
480 if (mode == MODE_INT) {
481 gen_insn(INSN_JMP_COND, op_size, COND_O, 0);
484 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
492 size_t attr_unused offset;
493 uint8_t attr_unused long_imm;
494 if (unlikely(op_size > OP_SIZE_NATIVE) || unlikely(!ARCH_HAS_MUL)) {
495 if (mode == MODE_INT) {
496 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));
499 #if defined(ARCH_X86)
500 g(gen_frame_load(ctx, OP_SIZE_NATIVE, garbage, slot_1, hi_word(OP_SIZE_NATIVE), true, R_CX));
501 g(gen_frame_load(ctx, OP_SIZE_NATIVE, garbage, slot_2, hi_word(OP_SIZE_NATIVE), true, R_AX));
502 g(gen_frame_load_op(ctx, OP_SIZE_NATIVE, garbage, ALU_MUL, true, slot_2, lo_word(OP_SIZE_NATIVE), true, R_CX));
503 g(gen_frame_load_op(ctx, OP_SIZE_NATIVE, garbage, ALU_MUL, true, slot_1, lo_word(OP_SIZE_NATIVE), true, R_AX));
504 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_ADD, R_CX, R_CX, R_AX, 0));
505 g(gen_frame_load(ctx, OP_SIZE_NATIVE, garbage, slot_2, lo_word(OP_SIZE_NATIVE), true, R_AX));
507 offset = (size_t)slot_1 * slot_size + lo_word(OP_SIZE_NATIVE);
508 g(gen_address(ctx, R_FRAME, offset, IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
509 gen_insn(INSN_MUL_L, OP_SIZE_NATIVE, 0, 1);
513 gen_address_offset();
515 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_ADD, R_DX, R_DX, R_CX, 0));
517 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, R_AX, R_DX));
520 #elif defined(ARCH_ARM32)
521 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_1, 0, R_SCRATCH_1, R_SCRATCH_2));
522 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_2, 0, R_SCRATCH_3, R_SCRATCH_4));
524 g(gen_mov(ctx, OP_SIZE_NATIVE, R_SCRATCH_NA_1, R_SCRATCH_1));
526 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_MUL, R_SCRATCH_4, R_SCRATCH_1, R_SCRATCH_4, 0));
528 gen_insn(INSN_MADD, OP_SIZE_NATIVE, 0, 0);
529 gen_one(R_SCRATCH_2);
530 gen_one(R_SCRATCH_3);
531 gen_one(R_SCRATCH_2);
532 gen_one(R_SCRATCH_4);
534 gen_insn(INSN_MUL_L, OP_SIZE_NATIVE, 0, 0);
535 gen_one(R_SCRATCH_1);
536 gen_one(R_SCRATCH_4);
537 gen_one(R_SCRATCH_NA_1);
538 gen_one(R_SCRATCH_3);
540 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_ADD, R_SCRATCH_2, R_SCRATCH_2, R_SCRATCH_4, 0));
542 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, R_SCRATCH_1, R_SCRATCH_2));
545 #elif defined(ARCH_ARM64)
546 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_1, 0, R_SCRATCH_1, R_SCRATCH_2));
547 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_2, 0, R_SCRATCH_3, R_SCRATCH_4));
549 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_UMULH, R_SCRATCH_NA_1, R_SCRATCH_1, R_SCRATCH_3, 0));
551 gen_insn(INSN_MADD, OP_SIZE_NATIVE, 0, 0);
552 gen_one(R_SCRATCH_NA_1);
553 gen_one(R_SCRATCH_2);
554 gen_one(R_SCRATCH_3);
555 gen_one(R_SCRATCH_NA_1);
557 gen_insn(INSN_MADD, OP_SIZE_NATIVE, 0, 0);
558 gen_one(R_SCRATCH_2);
559 gen_one(R_SCRATCH_1);
560 gen_one(R_SCRATCH_4);
561 gen_one(R_SCRATCH_NA_1);
563 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_MUL, R_SCRATCH_1, R_SCRATCH_1, R_SCRATCH_3, 0));
565 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, R_SCRATCH_1, R_SCRATCH_2));
569 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));
574 #if defined(ARCH_X86)
575 if (mode == MODE_INT) {
576 if (op_size != OP_SIZE_1 && slot_r == slot_1 && slot_is_register(ctx, slot_1)) {
578 target = ctx->registers[slot_1];
579 g(gen_mov(ctx, op_size, R_SCRATCH_1, target));
580 g(gen_frame_load_op(ctx, op_size, garbage, ALU_MUL, mode == MODE_INT, slot_2, 0, false, target));
581 ce = alloc_undo_label(ctx);
584 ce->undo_opcode = INSN_MOV;
585 ce->undo_op_size = op_size;
587 ce->undo_writes_flags = 0;
588 ce->undo_parameters[0] = target;
589 ce->undo_parameters[1] = R_SCRATCH_1;
590 ce->undo_parameters_len = 2;
591 gen_insn(INSN_JMP_COND, op_size, COND_O, 0);
592 gen_four(ce->undo_label);
595 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
597 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, slot_2, R_SCRATCH_1);
599 if (op_size == OP_SIZE_1)
600 target = R_SCRATCH_1;
601 g(gen_frame_load(ctx, op_size, garbage, slot_1, 0, false, target));
602 if (op_size == OP_SIZE_1 && frame_t_is_const(slot_2)) {
603 g(gen_load_constant(ctx, R_SCRATCH_3, frame_t_get_const(slot_2)));
604 gen_insn(INSN_ALU + ARCH_PARTIAL_ALU(op_size), op_size, ALU_MUL, 1);
607 gen_one(R_SCRATCH_3);
609 g(gen_frame_load_op(ctx, op_size, garbage, ALU_MUL, mode == MODE_INT, slot_2, 0, false, target));
611 if (mode == MODE_INT) {
612 gen_insn(INSN_JMP_COND, op_size, COND_O, 0);
615 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
618 #if defined(ARCH_ALPHA)
619 if (mode == MODE_INT && ARCH_SUPPORTS_TRAPS(op_size)) {
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, R_SCRATCH_1, ®1));
622 g(gen_frame_get(ctx, op_size, garbage, slot_2, R_SCRATCH_2, ®2));
624 gen_insn(INSN_ALU_TRAP, op_size, ALU_MUL, ALU_WRITES_FLAGS(op_size, ALU_MUL, false, false, 0));
629 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
634 #if defined(ARCH_ARM32)
635 if (mode == MODE_INT && op_size == OP_SIZE_4) {
636 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_3);
637 g(gen_frame_get(ctx, op_size, garbage, slot_1, R_SCRATCH_1, ®1));
638 g(gen_frame_get(ctx, op_size, garbage, slot_2, R_SCRATCH_2, ®2));
640 gen_insn(INSN_MUL_L, OP_SIZE_NATIVE, 0, 0);
642 gen_one(R_SCRATCH_4);
646 gen_insn(INSN_CMP, OP_SIZE_NATIVE, 0, 1);
647 gen_one(R_SCRATCH_4);
648 gen_one(ARG_SHIFTED_REGISTER);
649 gen_one(ARG_SHIFT_ASR | 0x1f);
652 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_NE, 0);
655 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
660 #if defined(ARCH_ARM64)
661 if (mode == MODE_INT && op_size == OP_SIZE_4) {
662 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
663 g(gen_frame_get(ctx, op_size, op_size < OP_SIZE_4 ? sign_x : garbage, slot_1, R_SCRATCH_1, ®1));
664 g(gen_frame_get(ctx, op_size, op_size < OP_SIZE_4 ? sign_x : garbage, slot_2, R_SCRATCH_2, ®2));
665 gen_insn(INSN_ALU, OP_SIZE_8, ALU_MUL, ALU_WRITES_FLAGS(OP_SIZE_8, ALU_MUL, false, false, 0));
667 gen_one(ARG_EXTENDED_REGISTER);
668 gen_one(ARG_EXTEND_SXTW);
670 gen_one(ARG_EXTENDED_REGISTER);
671 gen_one(ARG_EXTEND_SXTW);
674 gen_insn(INSN_CMP, OP_SIZE_8, 0, 1);
676 gen_one(ARG_EXTENDED_REGISTER);
677 gen_one(ARG_EXTEND_SXTW);
680 gen_insn(INSN_JMP_COND, OP_SIZE_8, COND_NE, 0);
683 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
687 if (mode == MODE_INT && op_size == OP_SIZE_8) {
688 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
689 g(gen_frame_get(ctx, op_size, garbage, slot_1, R_SCRATCH_1, ®1));
690 g(gen_frame_get(ctx, op_size, garbage, slot_2, R_SCRATCH_2, ®2));
691 g(gen_3address_alu(ctx, OP_SIZE_8, ALU_SMULH, R_SCRATCH_3, reg1, reg2, 0));
693 g(gen_3address_alu(ctx, OP_SIZE_8, ALU_MUL, target, reg1, reg2, 0));
695 gen_insn(INSN_CMP, OP_SIZE_8, 0, 1);
696 gen_one(R_SCRATCH_3);
697 gen_one(ARG_SHIFTED_REGISTER);
698 gen_one(ARG_SHIFT_ASR | 0x3f);
701 gen_insn(INSN_JMP_COND, OP_SIZE_8, COND_NE, 0);
704 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
709 #if defined(ARCH_POWER)
710 if (mode == MODE_INT && op_size >= OP_SIZE_4) {
711 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
712 g(gen_frame_get(ctx, op_size, garbage, slot_1, R_SCRATCH_1, ®1));
713 g(gen_frame_get(ctx, op_size, garbage, slot_2, R_SCRATCH_2, ®2));
715 g(gen_3address_alu(ctx, op_size, ALU_MUL, target, reg1, reg2, 1));
717 gen_insn(INSN_JMP_COND, op_size, COND_O, 0);
720 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
725 #if defined(ARCH_LOONGARCH64) || (defined(ARCH_MIPS) && MIPS_R6) || defined(ARCH_RISCV64)
726 if (mode == MODE_INT && op_size == OP_SIZE_NATIVE) {
727 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
728 g(gen_frame_get(ctx, op_size, garbage, slot_1, R_SCRATCH_1, ®1));
729 g(gen_frame_get(ctx, op_size, garbage, slot_2, R_SCRATCH_2, ®2));
731 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_SMULH, R_SCRATCH_3, reg1, reg2, 0));
733 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_MUL, target, reg1, reg2, 0));
735 g(gen_3address_rot_imm(ctx, OP_SIZE_NATIVE, ROT_SAR, R_SCRATCH_4, target, (8U << OP_SIZE_NATIVE) - 1, 0));
737 g(gen_cmp_test_jmp(ctx, INSN_CMP, OP_SIZE_NATIVE, R_SCRATCH_3, R_SCRATCH_4, COND_NE, label_ovf));
739 g(gen_frame_store(ctx, OP_SIZE_NATIVE, slot_r, 0, target));
744 #if defined(ARCH_S390)
745 if (mode == MODE_INT && op_size >= OP_SIZE_4 && likely(cpu_test_feature(CPU_FEATURE_misc_insn_ext_2))) {
746 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
747 g(gen_frame_load(ctx, op_size, sign_x, slot_1, 0, false, target));
748 g(gen_frame_load_op(ctx, op_size, sign_x, ALU_MUL, 1, slot_2, 0, false, target));
750 gen_insn(INSN_JMP_COND, op_size, COND_O, 0);
753 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
757 #if (defined(ARCH_MIPS) && !MIPS_R6) || defined(ARCH_S390)
758 #if defined(ARCH_MIPS)
759 if (mode == MODE_INT && op_size >= OP_SIZE_4)
761 #if defined(ARCH_S390)
762 if (mode == MODE_INT && op_size == OP_SIZE_4)
765 #if defined(ARCH_S390)
766 target = R_SCRATCH_1;
768 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
770 g(gen_frame_get(ctx, op_size, sign_x, slot_1, R_SCRATCH_1, ®1));
771 g(gen_frame_get(ctx, op_size, sign_x, slot_2, R_SCRATCH_3, ®2));
773 gen_insn(INSN_MUL_L, op_size, 0, 0);
775 gen_one(R_SCRATCH_2);
779 g(gen_3address_rot_imm(ctx, op_size, ROT_SAR, R_SCRATCH_4, target, (8U << op_size) - 1, false));
781 g(gen_cmp_test_jmp(ctx, INSN_CMP, op_size, R_SCRATCH_2, R_SCRATCH_4, COND_NE, label_ovf));
783 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
787 if (mode == MODE_INT && op_size == OP_SIZE_NATIVE) {
788 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));
792 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
793 if (op_size < OP_SIZE_NATIVE && mode == MODE_INT) {
794 g(gen_frame_get(ctx, op_size, sign_x, slot_1, R_SCRATCH_1, ®1));
795 g(gen_frame_get(ctx, op_size, sign_x, slot_2, R_SCRATCH_2, ®2));
797 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_MUL, target, reg1, reg2, 0));
799 g(gen_frame_load(ctx, op_size, sign_x, slot_1, 0, false, target));
800 g(gen_frame_load_op(ctx, op_size, sign_x, ALU_MUL, 0, slot_2, 0, false, target));
803 if (mode == MODE_INT) {
804 g(gen_cmp_extended(ctx, OP_SIZE_NATIVE, op_size, target, R_SCRATCH_2, label_ovf));
807 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
816 uint32_t attr_unused label_skip = 0; /* avoid warning */
817 uint32_t attr_unused label_skip2 = 0; /* avoid warning */
818 uint32_t attr_unused label_end = 0; /* avoid warning */
819 uint32_t attr_unused label_div_0 = 0; /* avoid warning */
820 unsigned attr_unused divide_alu = 0; /* avoid warning */
821 bool attr_unused have_mod = false;
822 bool attr_unused force_sx = false;
823 unsigned attr_unused div_op_size = i_size(op_size);
824 if (unlikely(op_size > OP_SIZE_NATIVE) || unlikely(!ARCH_HAS_DIV)
825 #if defined(ARCH_S390)
826 || !(Z || (op_size <= OP_SIZE_4 && sgn))
830 if (mode == MODE_INT) {
831 upcall = !mod ? offsetof(struct cg_upcall_vector_s, INT_binary_divide_int8_t) : offsetof(struct cg_upcall_vector_s, INT_binary_modulo_int8_t);
833 upcall = !mod ? offsetof(struct cg_upcall_vector_s, FIXED_binary_divide_int8_t) : offsetof(struct cg_upcall_vector_s, FIXED_binary_modulo_int8_t);
835 upcall = !mod ? offsetof(struct cg_upcall_vector_s, FIXED_binary_udivide_int8_t) : offsetof(struct cg_upcall_vector_s, FIXED_binary_umodulo_int8_t);
837 g(gen_alu_typed_upcall(ctx, upcall, op_size, slot_1, slot_2, slot_r, mode == MODE_INT ? label_ovf : 0));
840 #if defined(ARCH_X86) || defined(ARCH_S390)
841 if (mode == MODE_FIXED) {
842 label_skip = alloc_label(ctx);
843 if (unlikely(!label_skip))
845 label_end = alloc_label(ctx);
846 if (unlikely(!label_end))
849 label_skip2 = alloc_label(ctx);
850 if (unlikely(!label_skip2))
854 #if defined(ARCH_X86)
855 if (R_SCRATCH_1 != R_AX || R_SCRATCH_2 != R_DX || R_SCRATCH_3 != R_CX)
856 internal(file_line, "gen_alu: bad scratch registers");
858 g(gen_frame_load(ctx, op_size, sgn ? sign_x : zero_x, slot_1, 0, false, R_SCRATCH_1));
859 g(gen_frame_load(ctx, op_size, sgn ? sign_x : zero_x, slot_2, 0, false, R_SCRATCH_3));
861 g(gen_jmp_on_zero(ctx, i_size(op_size), R_SCRATCH_3, COND_E, mode == MODE_INT ? label_ovf : label_skip));
865 uint32_t label_not_minus_1;
866 label_not_minus_1 = alloc_label(ctx);
867 if (unlikely(!label_not_minus_1))
870 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, op_size, R_SCRATCH_3, -1, COND_NE, label_not_minus_1));
872 val = -(uint64_t)0x80 << (((1 << op_size) - 1) * 8);
873 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, op_size, R_SCRATCH_1, val, COND_E, mode == MODE_INT ? label_ovf : label_skip2));
875 gen_label(label_not_minus_1);
878 #if defined(ARCH_X86)
879 if (op_size >= OP_SIZE_2) {
881 gen_insn(INSN_CWD + ARCH_PARTIAL_ALU(op_size), op_size, 0, 0);
882 gen_one(R_SCRATCH_2);
883 gen_one(R_SCRATCH_1);
884 if (op_size == OP_SIZE_2)
885 gen_one(R_SCRATCH_2);
887 g(gen_3address_alu(ctx, OP_SIZE_4, ALU_XOR, R_SCRATCH_2, R_SCRATCH_2, R_SCRATCH_2, 0));
890 gen_insn(INSN_DIV_L, op_size, sgn, 1);
891 gen_one(R_SCRATCH_1);
892 gen_one(i_size(op_size) == OP_SIZE_1 ? R_SCRATCH_1 : R_SCRATCH_2);
893 gen_one(R_SCRATCH_1);
894 gen_one(i_size(op_size) == OP_SIZE_1 ? R_SCRATCH_1 : R_SCRATCH_2);
895 gen_one(R_SCRATCH_3);
898 g(gen_load_constant(ctx, R_SCRATCH_2, 0));
899 } else if (op_size <= OP_SIZE_4) {
900 g(gen_3address_rot_imm(ctx, OP_SIZE_NATIVE, ROT_SAR, R_SCRATCH_2, R_SCRATCH_1, (1U << (OP_SIZE_NATIVE + 3)) - 1, false));
902 gen_insn(INSN_DIV_L, i_size(op_size), sgn, 1);
903 gen_one(R_SCRATCH_2);
904 gen_one(R_SCRATCH_1);
905 gen_one(R_SCRATCH_2);
906 gen_one(R_SCRATCH_1);
907 gen_one(R_SCRATCH_3);
909 if (mod && i_size(op_size) == OP_SIZE_1) {
910 g(gen_3address_rot_imm(ctx, OP_SIZE_2, ROT_SHR, R_SCRATCH_1, R_SCRATCH_1, 8, 0));
911 g(gen_frame_store(ctx, op_size, slot_r, 0, R_SCRATCH_1));
913 g(gen_frame_store(ctx, op_size, slot_r, 0, R_SCRATCH_2));
915 g(gen_frame_store(ctx, op_size, slot_r, 0, R_SCRATCH_1));
917 if (mode == MODE_FIXED) {
918 gen_insn(INSN_JMP, 0, 0, 0);
922 gen_label(label_skip2);
925 g(gen_frame_clear(ctx, op_size, slot_r));
927 g(gen_frame_store(ctx, op_size, slot_r, 0, R_SCRATCH_1));
929 gen_insn(INSN_JMP, 0, 0, 0);
933 gen_label(label_skip);
935 g(gen_frame_clear(ctx, op_size, slot_r));
937 g(gen_frame_store(ctx, op_size, slot_r, 0, R_SCRATCH_1));
938 gen_label(label_end);
942 #if defined(ARCH_MIPS)
944 div_op_size = maximum(op_size, OP_SIZE_4);
945 if (op_size == OP_SIZE_4)
948 #if defined(ARCH_POWER)
949 have_mod = cpu_test_feature(CPU_FEATURE_v30);
950 div_op_size = maximum(op_size, OP_SIZE_4);
952 #if defined(ARCH_LOONGARCH64) || defined(ARCH_RISCV64)
954 div_op_size = maximum(op_size, OP_SIZE_4);
956 label_end = alloc_label(ctx);
957 if (unlikely(!label_end))
960 g(gen_frame_get(ctx, op_size, (sgn && op_size < i_size(op_size)) || force_sx ? sign_x : zero_x, slot_1, R_SCRATCH_1, ®1));
961 g(gen_frame_get(ctx, op_size, (sgn && op_size < i_size(op_size)) || force_sx ? sign_x : zero_x, slot_2, R_SCRATCH_2, ®2));
962 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_3);
964 if (ARCH_PREFERS_SX(op_size) && !sgn && op_size < i_size(op_size)) {
965 g(gen_extend(ctx, op_size, zero_x, R_SCRATCH_1, reg1));
967 g(gen_extend(ctx, op_size, zero_x, R_SCRATCH_2, reg2));
971 if (mode == MODE_INT) {
972 g(gen_jmp_on_zero(ctx, i_size(op_size), reg2, COND_E, label_ovf));
975 uint32_t label_not_minus_1;
976 label_not_minus_1 = alloc_label(ctx);
977 if (unlikely(!label_not_minus_1))
980 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, i_size(op_size), reg2, -1, COND_NE, label_not_minus_1));
982 val = 0xFFFFFFFFFFFFFF80ULL << (((1 << op_size) - 1) * 8);
983 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, i_size(op_size), reg1, val, COND_E, label_ovf));
985 gen_label(label_not_minus_1);
988 #if !(defined(ARCH_ARM) && ARM_ASM_DIV_NO_TRAP)
990 g(gen_load_constant(ctx, target, 0));
992 g(gen_mov(ctx, OP_SIZE_NATIVE, target, reg1));
994 g(gen_jmp_on_zero(ctx, i_size(op_size), reg2, COND_E, label_end));
997 uint32_t label_not_minus_1;
998 label_not_minus_1 = alloc_label(ctx);
999 if (unlikely(!label_not_minus_1))
1002 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, i_size(op_size), reg2, -1, COND_NE, label_not_minus_1));
1005 g(gen_mov(ctx, OP_SIZE_NATIVE, target, reg1));
1007 g(gen_load_constant(ctx, target, 0));
1010 val = 0xFFFFFFFFFFFFFF80ULL << (((1 << op_size) - 1) * 8);
1011 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, i_size(op_size), reg1, val, COND_E, label_end));
1013 gen_label(label_not_minus_1);
1017 if (mod && have_mod) {
1018 g(gen_3address_alu(ctx, div_op_size, sgn ? ALU_SREM : ALU_UREM, target, reg1, reg2, 0));
1020 g(gen_3address_alu(ctx, div_op_size, sgn ? ALU_SDIV : ALU_UDIV, target, reg1, reg2, 0));
1023 if (mod && !have_mod) {
1024 #if defined(ARCH_ARM)
1025 gen_insn(INSN_MADD, i_size(op_size), 1, 0);
1031 g(gen_3address_alu(ctx, i_size(op_size), ALU_MUL, R_SCRATCH_2, reg2, target, 0));
1032 g(gen_3address_alu(ctx, i_size(op_size), ALU_SUB, target, reg1, R_SCRATCH_2, 0));
1036 gen_label(label_end);
1037 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1048 int64_t cnst = 0; /* avoid warning */
1049 bool c = frame_t_is_const(slot_2);
1050 if (unlikely(op_size > OP_SIZE_NATIVE)) {
1052 if (mode == MODE_FIXED) {
1054 case ROT_SHL: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_shl_,TYPE_INT_MAX));
1056 case ROT_SAR: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_shr_,TYPE_INT_MAX));
1058 case ROT_SHR: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_ushr_,TYPE_INT_MAX));
1060 case ROT_ROL: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_rol_,TYPE_INT_MAX));
1062 case ROT_ROR: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_ror_,TYPE_INT_MAX));
1064 default: internal(file_line, "do_alu: invalid shift %u", alu);
1068 case ROT_SHL: upcall = offsetof(struct cg_upcall_vector_s, cat(INT_binary_shl_,TYPE_INT_MAX));
1070 case ROT_SAR: upcall = offsetof(struct cg_upcall_vector_s, cat(INT_binary_shr_,TYPE_INT_MAX));
1072 default: internal(file_line, "do_alu: invalid shift %u", alu);
1075 g(gen_alu_upcall(ctx, upcall, op_size, slot_1, slot_2, slot_r, mode == MODE_INT ? label_ovf : 0));
1078 op_s = i_size_rot(op_size);
1079 #if defined(ARCH_X86)
1080 if (slot_1 == slot_r && !slot_is_register(ctx, slot_1) && !(mode == MODE_INT && alu == ROT_SHL)) {
1081 int64_t offset = (size_t)slot_1 * slot_size;
1083 cnst = frame_t_get_const(slot_2);
1084 if (mode == MODE_INT) {
1085 if ((uint64_t)cnst > (8U << op_size) - 1) {
1086 gen_insn(INSN_JMP, 0, 0, 0);
1087 gen_four(label_ovf);
1091 cnst &= (8U << op_size) - 1;
1093 g(gen_address(ctx, R_FRAME, offset, IMM_PURPOSE_LDR_OFFSET, op_size));
1094 gen_insn(INSN_ROT + ARCH_PARTIAL_ALU(op_size), op_size, alu, 1);
1095 gen_address_offset();
1096 gen_address_offset();
1100 g(gen_frame_load(ctx, op_size, garbage, slot_2, 0, false, R_SCRATCH_3));
1101 if (mode == MODE_INT) {
1102 int64_t imm = (8U << op_size) - 1;
1103 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, op_size, R_SCRATCH_3, imm, COND_A, label_ovf));
1104 } else if ((alu != ROT_ROL && alu != ROT_ROR) && op_size < OP_SIZE_4) {
1105 g(gen_3address_alu_imm(ctx, OP_SIZE_1, ALU_AND, R_SCRATCH_3, R_SCRATCH_3, (8U << op_size) - 1, 0));
1107 g(gen_address(ctx, R_FRAME, offset, IMM_PURPOSE_LDR_OFFSET, op_size));
1108 gen_insn(INSN_ROT + ARCH_PARTIAL_ALU(op_size), op_size, alu, 1);
1109 gen_address_offset();
1110 gen_address_offset();
1111 gen_one(R_SCRATCH_3);
1115 if (mode == MODE_INT && alu == ROT_SHL && op_size < OP_SIZE_NATIVE)
1118 must_mask = op_size < ARCH_SHIFT_SIZE;
1119 sx = (alu == ROT_SAR && op_size < op_s) || (alu == ROT_SHL && op_size < OP_SIZE_NATIVE && mode == MODE_INT);
1120 #if defined(ARCH_MIPS)
1121 sx |= op_size == OP_SIZE_4;
1123 g(gen_frame_get(ctx, op_size, sx ? sign_x : zero_x, slot_1, R_SCRATCH_1, ®1));
1125 reg3 = 0xff; /* avoid warning */
1126 cnst = frame_t_get_const(slot_2);
1128 #if defined(ARCH_X86)
1129 if (!ARCH_IS_3ADDRESS_ROT(alu, op_size)) {
1130 g(gen_frame_load(ctx, op_size, garbage, slot_2, 0, false, R_SCRATCH_3));
1134 g(gen_frame_get(ctx, op_size, garbage, slot_2, R_SCRATCH_3, ®3));
1136 if (ARCH_PREFERS_SX(op_size) && !sx && op_size < op_s) {
1137 g(gen_extend(ctx, op_size, zero_x, R_SCRATCH_1, reg1));
1141 if (mode == MODE_INT) {
1142 int64_t imm = (8U << op_size) - 1;
1144 if ((uint64_t)cnst > (uint64_t)imm) {
1145 gen_insn(INSN_JMP, 0, 0, 0);
1146 gen_four(label_ovf);
1150 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, i_size_cmp(op_size), reg3, imm, COND_A, label_ovf));
1153 #if defined(ARCH_ARM)
1154 if (alu == ROT_ROL) {
1156 cnst = -(uint64_t)cnst;
1158 g(gen_2address_alu1(ctx, OP_SIZE_4, ALU1_NEG, R_SCRATCH_3, reg3, 0));
1164 #if defined(ARCH_LOONGARCH64)
1165 if (alu == ROT_ROL && op_size >= OP_SIZE_4) {
1167 cnst = -(uint64_t)cnst;
1169 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_NEG, R_SCRATCH_3, reg3, 0));
1175 #if defined(ARCH_MIPS)
1176 if (MIPS_HAS_ROT && alu == ROT_ROL && op_size >= OP_SIZE_4) {
1178 cnst = -(uint64_t)cnst;
1180 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_NEG, R_SCRATCH_3, reg3, 0));
1186 #if defined(ARCH_POWER)
1187 if (alu == ROT_ROR && op_size >= OP_SIZE_4) {
1189 cnst = -(uint64_t)cnst;
1191 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_NEG, R_SCRATCH_3, reg3, 0));
1197 #if defined(ARCH_S390)
1198 if (Z && alu == ROT_ROR && op_size >= OP_SIZE_4) {
1200 cnst = -(uint64_t)cnst;
1202 g(gen_2address_alu1(ctx, OP_SIZE_4, ALU1_NEG, R_SCRATCH_3, reg3, 0));
1209 cnst &= (8U << op_size) - 1;
1210 } else if (must_mask) {
1211 g(gen_3address_alu_imm(ctx, i_size(OP_SIZE_4), ALU_AND, R_SCRATCH_3, reg3, (8U << op_size) - 1, 0));
1216 #if defined(ARCH_X86)
1217 if (mode == MODE_INT && alu == ROT_SHL) {
1218 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_2);
1220 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, slot_2, R_SCRATCH_2);
1223 g(gen_3address_rot_imm(ctx, op_s, alu, target, reg1, cnst, 0));
1225 g(gen_3address_rot(ctx, op_s, alu, target, reg1, reg3));
1228 if (mode == MODE_INT && alu == ROT_SHL) {
1229 if (op_size < OP_SIZE_NATIVE) {
1230 gen_insn(INSN_MOVSX, op_size, 0, 0);
1231 gen_one(R_SCRATCH_4);
1234 g(gen_cmp_test_jmp(ctx, INSN_CMP, op_s, target, R_SCRATCH_4, COND_NE, label_ovf));
1237 g(gen_3address_rot_imm(ctx, OP_SIZE_NATIVE, ROT_SAR, R_SCRATCH_4, target, cnst, 0));
1239 g(gen_3address_rot(ctx, OP_SIZE_NATIVE, ROT_SAR, R_SCRATCH_4, target, reg3));
1242 g(gen_cmp_test_jmp(ctx, INSN_CMP, OP_SIZE_NATIVE, reg1, R_SCRATCH_4, COND_NE, label_ovf));
1245 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1248 #if defined(ARCH_ARM)
1249 if (op_size <= OP_SIZE_2 && alu == ROT_ROR) {
1250 gen_insn(INSN_ALU, OP_SIZE_4, ALU_OR, ALU_WRITES_FLAGS(OP_SIZE_4, ALU_OR, false, false, 0));
1251 gen_one(R_SCRATCH_1);
1253 gen_one(ARG_SHIFTED_REGISTER);
1254 gen_one(ARG_SHIFT_LSL | (8U << op_size));
1256 if (op_size == OP_SIZE_1)
1260 goto do_generic_shift;
1262 #if defined(ARCH_LOONGARCH64)
1263 if (alu == ROT_ROR && op_size >= OP_SIZE_4)
1264 goto do_generic_shift;
1266 #if defined(ARCH_MIPS)
1267 if (MIPS_HAS_ROT && alu == ROT_ROR && op_size >= OP_SIZE_4)
1268 goto do_generic_shift;
1270 #if defined(ARCH_POWER)
1271 if (alu == ROT_ROL && op_size >= OP_SIZE_4)
1272 goto do_generic_shift;
1274 #if defined(ARCH_RISCV64)
1275 if ((alu == ROT_ROL || alu == ROT_ROR) && likely(cpu_test_feature(CPU_FEATURE_zbb))) {
1276 if (likely(op_size >= OP_SIZE_4)) {
1277 goto do_generic_shift;
1281 #if defined(ARCH_S390)
1282 if (Z && alu == ROT_ROL && op_size >= OP_SIZE_4)
1283 goto do_generic_shift;
1285 if (alu == ROT_ROL || alu == ROT_ROR) {
1286 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
1288 g(gen_3address_rot_imm(ctx, op_s, alu == ROT_ROL ? ROT_SHL : ROT_SHR, R_SCRATCH_2, reg1, cnst, 0));
1289 g(gen_3address_rot_imm(ctx, op_s, alu == ROT_ROL ? ROT_SHR : ROT_SHL, target, reg1, -(uint64_t)cnst & ((8U << op_size) - 1), 0));
1291 g(gen_3address_rot(ctx, op_s, alu == ROT_ROL ? ROT_SHL : ROT_SHR, R_SCRATCH_2, reg1, reg3));
1292 g(gen_2address_alu1(ctx, i_size(OP_SIZE_4), ALU1_NEG, R_SCRATCH_3, reg3, 0));
1294 g(gen_3address_alu_imm(ctx, i_size(OP_SIZE_4), ALU_AND, R_SCRATCH_3, R_SCRATCH_3, (8U << op_size) - 1, 0));
1296 g(gen_3address_rot(ctx, op_s, alu == ROT_ROL ? ROT_SHR : ROT_SHL, target, reg1, R_SCRATCH_3));
1298 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_OR, target, target, R_SCRATCH_2, 0));
1299 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1303 goto do_generic_shift;
1305 if (mode == MODE_INT && alu == ROT_SHL) {
1306 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, R_SCRATCH_1);
1307 #if defined(ARCH_S390)
1308 if (op_size >= OP_SIZE_4) {
1310 g(gen_3address_rot_imm(ctx, op_size, ROT_SAL, target, reg1, cnst, 0));
1312 g(gen_3address_rot(ctx, op_size, ROT_SAL, target, reg1, reg3));
1314 gen_insn(INSN_JMP_COND, op_size, COND_O, 0);
1315 gen_four(label_ovf);
1318 if (op_size <= OP_SIZE_NATIVE - 1) {
1320 g(gen_3address_rot_imm(ctx, OP_SIZE_NATIVE, alu, target, reg1, cnst, 0));
1322 g(gen_3address_rot(ctx, OP_SIZE_NATIVE, alu, target, reg1, reg3));
1324 g(gen_cmp_extended(ctx, OP_SIZE_NATIVE, op_size, target, R_SCRATCH_2, label_ovf));
1327 g(gen_3address_rot_imm(ctx, OP_SIZE_NATIVE, alu, R_SCRATCH_2, reg1, cnst, 0));
1328 g(gen_3address_rot_imm(ctx, OP_SIZE_NATIVE, ROT_SAR, R_SCRATCH_4, R_SCRATCH_2, cnst, 0));
1330 g(gen_3address_rot(ctx, OP_SIZE_NATIVE, alu, R_SCRATCH_2, reg1, reg3));
1331 g(gen_3address_rot(ctx, OP_SIZE_NATIVE, ROT_SAR, R_SCRATCH_4, R_SCRATCH_2, reg3));
1334 g(gen_cmp_test_jmp(ctx, INSN_CMP, OP_SIZE_NATIVE, reg1, R_SCRATCH_4, COND_NE, label_ovf));
1336 g(gen_frame_store(ctx, op_size, slot_r, 0, R_SCRATCH_2));
1341 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, slot_2, R_SCRATCH_1);
1343 g(gen_3address_rot_imm(ctx, op_s, alu, target, reg1, cnst, 0));
1345 g(gen_3address_rot(ctx, op_s, alu, target, reg1, reg3));
1348 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1355 unsigned attr_unused op_s;
1357 bool c = frame_t_is_const(slot_2);
1358 int64_t cnst = !c ? 0 : frame_t_get_const(slot_2);
1359 int64_t max_imm = (8U << op_size) - 1;
1361 if (mode == MODE_INT) {
1362 if (alu == BTX_BT ? (uint64_t)cnst > (uint64_t)max_imm : (uint64_t)cnst >= (uint64_t)max_imm) {
1363 gen_insn(INSN_JMP, 0, 0, 0);
1364 gen_four(label_ovf);
1370 #if defined(ARCH_X86)
1371 if ((alu == BTX_BT || slot_1 == slot_r) && !slot_is_register(ctx, slot_1)) {
1373 unsigned n_op_size = minimum(op_size, OP_SIZE_NATIVE);
1374 g(gen_frame_get(ctx, n_op_size, garbage, slot_2, R_SCRATCH_1, ®2));
1375 if (mode == MODE_INT) {
1377 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, n_op_size, reg2, max_imm, alu == BTX_BT ? COND_A : COND_AE, label_ovf));
1378 if (unlikely(op_size > OP_SIZE_NATIVE)) {
1379 g(gen_address(ctx, R_FRAME, (size_t)slot_2 * slot_size + hi_word(OP_SIZE_NATIVE), IMM_PURPOSE_STR_OFFSET, OP_SIZE_NATIVE));
1380 gen_insn(INSN_CMP, OP_SIZE_NATIVE, 0, 1);
1381 gen_address_offset();
1384 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_NE, 0);
1385 gen_four(label_ovf);
1390 g(gen_3address_alu_imm(ctx, OP_SIZE_4, ALU_AND, R_SCRATCH_1, reg2, (8U << op_size) - 1, 0));
1394 offset = (size_t)slot_1 * slot_size;
1395 if (c && cnst >= 8U << OP_SIZE_NATIVE) {
1396 offset += 1U << OP_SIZE_NATIVE;
1397 cnst -= 8U << OP_SIZE_NATIVE;
1399 g(gen_address(ctx, R_FRAME, offset, IMM_PURPOSE_STR_OFFSET, maximum(n_op_size, OP_SIZE_2)));
1400 if (alu == BTX_BT) {
1401 gen_insn(INSN_BT, maximum(n_op_size, OP_SIZE_2), 0, 1);
1402 gen_address_offset();
1409 g(gen_frame_set_cond(ctx, maximum(n_op_size, OP_SIZE_2), false, COND_B, slot_r));
1411 gen_insn(INSN_BTX, maximum(n_op_size, OP_SIZE_2), alu, 1);
1412 gen_address_offset();
1413 gen_address_offset();
1424 if (unlikely(op_size > OP_SIZE_NATIVE)) {
1426 if (mode == MODE_FIXED) {
1428 case BTX_BTS: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_bts_,TYPE_INT_MAX));
1430 case BTX_BTR: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_btr_,TYPE_INT_MAX));
1432 case BTX_BTC: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_btc_,TYPE_INT_MAX));
1434 case BTX_BT: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_bt_,TYPE_INT_MAX));
1436 default: internal(file_line, "do_alu: invalid bit test %u", alu);
1440 case BTX_BTS: upcall = offsetof(struct cg_upcall_vector_s, cat(INT_binary_bts_,TYPE_INT_MAX));
1442 case BTX_BTR: upcall = offsetof(struct cg_upcall_vector_s, cat(INT_binary_btr_,TYPE_INT_MAX));
1444 case BTX_BTC: upcall = offsetof(struct cg_upcall_vector_s, cat(INT_binary_btc_,TYPE_INT_MAX));
1446 case BTX_BT: upcall = offsetof(struct cg_upcall_vector_s, cat(INT_binary_bt_,TYPE_INT_MAX));
1448 default: internal(file_line, "do_alu: invalid bit test %u", alu);
1451 g(gen_alu_upcall(ctx, upcall, op_size, slot_1, slot_2, slot_r, label_ovf));
1454 op_s = minimum(OP_SIZE_NATIVE, ARCH_SHIFT_SIZE);
1455 op_s = maximum(op_s, op_size);
1456 g(gen_frame_get(ctx, op_size, zero_x, slot_1, R_SCRATCH_1, ®1));
1458 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
1459 if (ARCH_HAS_BTX(alu == BTX_BT ? BTX_BTEXT : alu, OP_SIZE_NATIVE, true)) {
1461 g(gen_mov(ctx, OP_SIZE_NATIVE, target, reg1));
1463 gen_insn(INSN_BTX, OP_SIZE_NATIVE, alu == BTX_BT ? BTX_BTEXT : alu, 1);
1465 gen_insn(INSN_BTX, OP_SIZE_NATIVE, alu == BTX_BT ? BTX_BTEXT : alu, 0);
1471 } else switch (alu) {
1473 g(gen_3address_alu_imm(ctx, i_size(op_size), ALU_OR, target, reg1, 1ULL << cnst, 0));
1476 g(gen_3address_alu_imm(ctx, i_size(op_size), ALU_AND, target, reg1, ~(1ULL << cnst), 0));
1479 g(gen_3address_alu_imm(ctx, i_size(op_size), ALU_XOR, target, reg1, 1ULL << cnst, 0));
1483 g(gen_3address_rot_imm(ctx, i_size(op_size), ROT_SHR, target, reg1, cnst, 0));
1485 g(gen_3address_alu_imm(ctx, i_size(op_size), ALU_AND, target, target, 1, 0));
1488 internal(file_line, "do_alu: invalid bit test %u", alu);
1491 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, target));
1493 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1496 g(gen_frame_get(ctx, op_size, garbage, slot_2, R_SCRATCH_2, ®2));
1497 if (mode == MODE_INT) {
1499 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, i_size_cmp(op_size), reg2, max_imm, alu == BTX_BT ? COND_A : COND_AE, label_ovf));
1501 if (alu != BTX_BT) {
1502 if (!ARCH_HAS_BTX(alu, OP_SIZE_NATIVE, false))
1504 need_mask = !ARCH_HAS_BTX(alu, op_size, false);
1506 #if defined(ARCH_X86)
1507 need_mask = op_size < OP_SIZE_2;
1509 if (!ARCH_HAS_BTX(BTX_BTEXT, OP_SIZE_NATIVE, false))
1511 need_mask = !ARCH_HAS_BTX(BTX_BTEXT, op_size, false);
1515 g(gen_3address_alu_imm(ctx, OP_SIZE_4, ALU_AND, R_SCRATCH_2, reg2, (8U << op_size) - 1, 0));
1518 if (alu == BTX_BT) {
1519 #if defined(ARCH_X86)
1520 gen_insn(INSN_BT, maximum(op_size, OP_SIZE_2), 0, 1);
1524 g(gen_frame_set_cond(ctx, maximum(op_size, OP_SIZE_2), false, COND_B, slot_r));
1526 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
1527 gen_insn(INSN_BTX, need_mask ? OP_SIZE_NATIVE : op_size, BTX_BTEXT, 0);
1532 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, target));
1535 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, slot_2, R_SCRATCH_1);
1536 #if defined(ARCH_X86)
1538 target = R_SCRATCH_1;
1539 if (target != reg1) {
1540 g(gen_mov(ctx, op_size, target, reg1));
1543 gen_insn(INSN_BTX, maximum(op_size, OP_SIZE_2), alu, 1);
1545 gen_insn(INSN_BTX, need_mask ? OP_SIZE_NATIVE : op_size, alu, 0);
1551 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1557 if (mode == MODE_FIXED && op_size < ARCH_SHIFT_SIZE) {
1558 g(gen_3address_alu_imm(ctx, i_size(OP_SIZE_4), ALU_AND, R_SCRATCH_2, reg2, (8U << op_size) - 1, 0));
1561 g(gen_load_constant(ctx, R_SCRATCH_3, 1));
1563 g(gen_3address_rot(ctx, op_s, ROT_SHL, R_SCRATCH_3, R_SCRATCH_3, reg2));
1568 #if defined(ARCH_S390) || defined(ARCH_POWER)
1569 g(gen_3address_alu(ctx, i_size(op_size), ALU_AND, R_SCRATCH_1, reg1, R_SCRATCH_3, 1));
1571 gen_insn(INSN_TEST, i_size(op_size), 0, 1);
1573 gen_one(R_SCRATCH_3);
1575 g(gen_frame_set_cond(ctx, i_size_cmp(op_size), false, COND_NE, slot_r));
1577 g(gen_3address_alu(ctx, i_size(op_size), ALU_AND, R_SCRATCH_1, reg1, R_SCRATCH_3, 0));
1578 g(gen_frame_cmp_imm_set_cond_reg(ctx, i_size(op_size), R_SCRATCH_1, 0, COND_NE, slot_r));
1582 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
1583 g(gen_3address_alu(ctx, i_size(op_size), ALU_OR, target, reg1, R_SCRATCH_3, 0));
1586 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
1587 if (!ARCH_HAS_ANDN) {
1588 g(gen_3address_alu_imm(ctx, i_size(op_size), ALU_XOR, R_SCRATCH_3, R_SCRATCH_3, -1, 0));
1590 g(gen_3address_alu(ctx, i_size(op_size), ALU_AND, target, reg1, R_SCRATCH_3, 0));
1593 g(gen_3address_alu(ctx, i_size(op_size), ALU_ANDN, target, reg1, R_SCRATCH_3, 0));
1596 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
1597 g(gen_3address_alu(ctx, i_size(op_size), ALU_XOR, target, reg1, R_SCRATCH_3, 0));
1600 internal(file_line, "gen_alu: unsupported bit test %u", alu);
1603 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1611 if (unlikely(op_size > OP_SIZE_NATIVE)) {
1612 size_t attr_unused upcall;
1613 frame_t attr_unused swap;
1617 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_1, 0, R_SCRATCH_1, R_SCRATCH_2));
1618 g(gen_frame_load_op(ctx, OP_SIZE_NATIVE, garbage, ALU_XOR, 0, slot_2, lo_word(OP_SIZE_NATIVE), true, R_SCRATCH_1));
1619 g(gen_frame_load_op(ctx, OP_SIZE_NATIVE, garbage, ALU_XOR, 0, slot_2, hi_word(OP_SIZE_NATIVE), true, R_SCRATCH_2));
1620 #if defined(ARCH_ARM64)
1621 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_OR, R_SCRATCH_1, R_SCRATCH_1, R_SCRATCH_2, 0));
1623 gen_insn(INSN_CMP, OP_SIZE_NATIVE, 0, 1);
1624 gen_one(R_SCRATCH_1);
1628 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_OR, R_SCRATCH_1, R_SCRATCH_1, R_SCRATCH_2, ARCH_HAS_FLAGS));
1631 g(gen_frame_set_cond(ctx, OP_SIZE_NATIVE, false, alu, slot_r));
1633 g(gen_frame_cmp_imm_set_cond_reg(ctx, OP_SIZE_NATIVE, R_SCRATCH_1, 0, alu, slot_r));
1636 #if defined(ARCH_X86_64) || defined(ARCH_X86_X32) || defined(ARCH_ARM)
1639 swap = slot_1; slot_1 = slot_2; slot_2 = swap;
1640 alu = alu == COND_G ? COND_L : COND_B;
1644 g(gen_frame_load(ctx, OP_SIZE_NATIVE, garbage, slot_2, lo_word(OP_SIZE_NATIVE), true, R_SCRATCH_2));
1645 g(gen_frame_load(ctx, OP_SIZE_NATIVE, garbage, slot_1, hi_word(OP_SIZE_NATIVE), true, R_SCRATCH_1));
1646 g(gen_frame_load_cmp(ctx, OP_SIZE_NATIVE, false, garbage, true, slot_1, lo_word(OP_SIZE_NATIVE), true, R_SCRATCH_2));
1647 g(gen_frame_load_op(ctx, OP_SIZE_NATIVE, garbage, ALU_SBB, 1, slot_2, hi_word(OP_SIZE_NATIVE), true, R_SCRATCH_1));
1648 g(gen_frame_set_cond(ctx, OP_SIZE_NATIVE, false, alu, slot_r));
1652 swap = slot_1; slot_1 = slot_2; slot_2 = swap;
1653 alu = alu == COND_GE ? COND_LE : COND_BE;
1657 g(gen_frame_load(ctx, OP_SIZE_NATIVE, garbage, slot_1, lo_word(OP_SIZE_NATIVE), true, R_SCRATCH_2));
1658 g(gen_frame_load(ctx, OP_SIZE_NATIVE, garbage, slot_2, hi_word(OP_SIZE_NATIVE), true, R_SCRATCH_1));
1659 g(gen_frame_load_cmp(ctx, OP_SIZE_NATIVE, false, garbage, true, slot_2, lo_word(OP_SIZE_NATIVE), true, R_SCRATCH_2));
1660 g(gen_frame_load_op(ctx, OP_SIZE_NATIVE, garbage, ALU_SBB, 1, slot_1, hi_word(OP_SIZE_NATIVE), true, R_SCRATCH_1));
1661 g(gen_frame_set_cond(ctx, OP_SIZE_NATIVE, false, alu == COND_LE ? COND_GE : COND_AE, slot_r));
1664 case COND_L: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_less_,TYPE_INT_MAX)); goto do_upcall;
1665 case COND_LE: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_less_equal_,TYPE_INT_MAX)); goto do_upcall;
1666 case COND_G: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_greater_,TYPE_INT_MAX)); goto do_upcall;
1667 case COND_GE: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_greater_equal_,TYPE_INT_MAX)); goto do_upcall;
1668 case COND_B: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_uless_,TYPE_INT_MAX)); goto do_upcall;
1669 case COND_BE: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_uless_equal_,TYPE_INT_MAX)); goto do_upcall;
1670 case COND_A: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_ugreater_,TYPE_INT_MAX)); goto do_upcall;
1671 case COND_AE: upcall = offsetof(struct cg_upcall_vector_s, cat(FIXED_binary_ugreater_equal_,TYPE_INT_MAX)); goto do_upcall;
1672 do_upcall: g(gen_alu_upcall(ctx, upcall, op_size, slot_1, slot_2, slot_r, 0));
1676 internal(file_line, "gen_alu: unsupported condition %u", alu);
1680 #if defined(ARCH_X86)
1681 g(gen_frame_get(ctx, op_size, garbage, slot_1, R_SCRATCH_1, ®1));
1682 g(gen_frame_load_cmp_set_cond(ctx, op_size, garbage, slot_2, reg1, alu, slot_r));
1684 g(gen_frame_get(ctx, op_size, op_size == i_size_cmp(op_size) + (unsigned)zero ? garbage : alu == COND_L || alu == COND_LE || alu == COND_G || alu == COND_GE || ARCH_PREFERS_SX(op_size) ? sign_x : zero_x, slot_1, R_SCRATCH_1, ®1));
1685 g(gen_frame_load_cmp_set_cond(ctx, op_size, alu == COND_L || alu == COND_LE || alu == COND_G || alu == COND_GE || ARCH_PREFERS_SX(op_size) ? sign_x : zero_x, slot_2, reg1, alu, slot_r));
1691 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)
1694 unsigned reg1, target;
1696 case MODE_FIXED: switch (op) {
1697 case OPCODE_FIXED_OP_not: alu = ALU1_NOT; goto do_alu;
1698 case OPCODE_FIXED_OP_neg: alu = ALU1_NEG; goto do_alu;
1699 case OPCODE_FIXED_OP_bswap:
1700 case OPCODE_FIXED_OP_bswap_alt1: alu = ALU1_BSWAP; goto do_bswap;
1701 case OPCODE_FIXED_OP_brev:
1702 case OPCODE_FIXED_OP_brev_alt1: alu = ALU1_BREV; goto do_brev;
1703 case OPCODE_FIXED_OP_bsf:
1704 case OPCODE_FIXED_OP_bsf_alt1: alu = ALU1_BSF; goto do_bsf_bsr_popcnt;
1705 case OPCODE_FIXED_OP_bsr:
1706 case OPCODE_FIXED_OP_bsr_alt1: alu = ALU1_BSR; goto do_bsf_bsr_popcnt;
1707 case OPCODE_FIXED_OP_popcnt:
1708 case OPCODE_FIXED_OP_popcnt_alt1: alu = ALU1_POPCNT; goto do_bsf_bsr_popcnt;
1709 case OPCODE_FIXED_OP_to_int: goto do_fixed_conv;
1710 case OPCODE_FIXED_OP_from_int: goto do_fixed_conv;
1711 case OPCODE_FIXED_OP_uto_int: goto conv_uto_int;
1712 case OPCODE_FIXED_OP_ufrom_int: goto conv_ufrom_int;
1713 default: internal(file_line, "gen_alu1: unsupported fixed operation %u", op);
1715 case MODE_INT: switch (op) {
1716 case OPCODE_INT_OP_not: alu = ALU1_NOT; mode = MODE_FIXED; goto do_alu;
1717 case OPCODE_INT_OP_neg: alu = ALU1_NEG; goto do_alu;
1718 case OPCODE_INT_OP_bsf: alu = ALU1_BSF; goto do_bsf_bsr_popcnt;
1719 case OPCODE_INT_OP_bsr: alu = ALU1_BSR; goto do_bsf_bsr_popcnt;
1720 case OPCODE_INT_OP_popcnt:
1721 case OPCODE_INT_OP_popcnt_alt1: alu = ALU1_POPCNT; goto do_bsf_bsr_popcnt;
1722 case OPCODE_INT_OP_to_int: goto do_conv;
1723 case OPCODE_INT_OP_from_int: goto do_conv;
1724 default: internal(file_line, "gen_alu1: unsupported int operation %u", op);
1726 case MODE_BOOL: switch (op) {
1727 case OPCODE_BOOL_OP_not: goto do_bool_not;
1728 default: internal(file_line, "gen_alu1: unsupported bool operation %u", op);
1731 internal(file_line, "gen_alu1: unsupported mode %u", mode);
1737 bool arch_use_flags = ARCH_HAS_FLAGS;
1739 #if defined(ARCH_POWER)
1740 arch_use_flags = false;
1742 if (op_size > OP_SIZE_NATIVE) {
1743 #if !defined(ARCH_X86) && !defined(ARCH_ARM) && !defined(ARCH_POWER)
1744 if (alu == ALU1_NEG) {
1745 if (mode == MODE_FIXED)
1746 g(gen_alu_upcall(ctx, offsetof(struct cg_upcall_vector_s, cat(FIXED_unary_neg_,TYPE_INT_MAX)), op_size, slot_1, NO_FRAME_T, slot_r, 0));
1748 g(gen_alu_upcall(ctx, offsetof(struct cg_upcall_vector_s, cat(INT_unary_neg_,TYPE_INT_MAX)), op_size, slot_1, NO_FRAME_T, slot_r, label_ovf));
1752 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_1, 0, R_SCRATCH_1, R_SCRATCH_2));
1753 #if defined(ARCH_S390)
1754 if (alu == ALU1_NOT) {
1755 g(gen_load_constant(ctx, R_SCRATCH_3, -1));
1757 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_XOR, R_SCRATCH_1, R_SCRATCH_1, R_SCRATCH_3, 0));
1758 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_XOR, R_SCRATCH_2, R_SCRATCH_2, R_SCRATCH_3, 0));
1760 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, R_SCRATCH_1, R_SCRATCH_2));
1764 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, alu, R_SCRATCH_1, R_SCRATCH_1, alu == ALU1_NEG ? 2 : 0));
1765 if (alu == ALU1_NOT) {
1766 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_NOT, R_SCRATCH_2, R_SCRATCH_2, 0));
1768 #if defined(ARCH_X86)
1769 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_NOT, R_SCRATCH_2, R_SCRATCH_2, 0));
1771 g(gen_imm(ctx, -1, IMM_PURPOSE_SUB, OP_SIZE_NATIVE));
1772 gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_SBB, ALU_WRITES_FLAGS(OP_SIZE_NATIVE, ALU_SBB, false, is_imm(), ctx->const_imm));
1773 gen_one(R_SCRATCH_2);
1774 gen_one(R_SCRATCH_2);
1777 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_NGC, R_SCRATCH_2, R_SCRATCH_2, (mode == MODE_INT)));
1780 if (mode == MODE_INT) {
1781 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_O, 0);
1782 gen_four(label_ovf);
1784 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, R_SCRATCH_1, R_SCRATCH_2));
1787 if ((arch_use_flags || ARCH_SUPPORTS_TRAPS(op_size)) && slot_1 == slot_r && i_size_cmp(op_size) == op_size + zero) {
1789 unsigned undo_alu = alu;
1790 if (slot_is_register(ctx, slot_1)) {
1791 unsigned reg = ctx->registers[slot_1];
1792 if (mode == MODE_INT && ARCH_SUPPORTS_TRAPS(op_size)) {
1793 gen_insn(INSN_ALU1_TRAP, op_size, alu, ALU1_WRITES_FLAGS(alu));
1796 if (ARCH_TRAP_BEFORE || alu == undo_alu) {
1797 gen_four(label_ovf);
1800 ce = alloc_undo_label(ctx);
1803 gen_four(ce->undo_label);
1804 goto do_undo_opcode;
1807 g(gen_2address_alu1(ctx, i_size(op_size), alu, reg, reg, mode == MODE_INT));
1808 if (mode == MODE_INT) {
1809 if (alu != undo_alu) {
1810 ce = alloc_undo_label(ctx);
1813 gen_insn(INSN_JMP_COND, i_size_cmp(op_size), COND_O, 0);
1814 gen_four(ce->undo_label);
1816 ce->undo_opcode = INSN_ALU1 + ARCH_PARTIAL_ALU(op_size);
1817 ce->undo_op_size = i_size(op_size);
1818 ce->undo_aux = undo_alu;
1819 ce->undo_writes_flags = ALU1_WRITES_FLAGS(undo_alu);
1820 ce->undo_parameters[0] = reg;
1821 ce->undo_parameters[1] = reg;
1822 ce->undo_parameters_len = 2;
1824 gen_insn(INSN_JMP_COND, i_size_cmp(op_size), COND_O, 0);
1825 gen_four(label_ovf);
1830 #if defined(ARCH_X86)
1833 int64_t offset = (size_t)slot_1 * slot_size;
1834 g(gen_address(ctx, R_FRAME, offset, IMM_PURPOSE_LDR_OFFSET, i_size(op_size)));
1835 gen_insn(INSN_ALU1 + ARCH_PARTIAL_ALU(op_size), i_size(op_size), alu, ALU1_WRITES_FLAGS(alu) | (mode == MODE_INT));
1836 gen_address_offset();
1837 gen_address_offset();
1838 if (mode == MODE_INT) {
1839 if (alu != undo_alu) {
1840 ce = alloc_undo_label(ctx);
1843 ce->undo_opcode = INSN_ALU1 + ARCH_PARTIAL_ALU(op_size);
1844 ce->undo_op_size = i_size(op_size);
1845 ce->undo_aux = undo_alu;
1846 ce->undo_writes_flags = ALU1_WRITES_FLAGS(undo_alu);
1847 m = mark_params(ctx);
1848 gen_address_offset();
1849 gen_address_offset();
1850 copy_params(ctx, ce, m);
1851 gen_insn(INSN_JMP_COND, i_size_cmp(op_size), COND_O, 0);
1852 gen_four(ce->undo_label);
1854 gen_insn(INSN_JMP_COND, i_size_cmp(op_size), COND_O, 0);
1855 gen_four(label_ovf);
1862 target = gen_frame_target(ctx, slot_r, mode == MODE_INT ? slot_1 : NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
1863 if (mode == MODE_FIXED) {
1866 ex = ARCH_PREFERS_SX(op_size) ? sign_x : zero_x;
1867 if (ARCH_SUPPORTS_TRAPS(op_size))
1869 if (op_size == i_size(op_size) + (unsigned)zero)
1872 g(gen_frame_get(ctx, op_size, ex, slot_1, mode == MODE_INT ? R_SCRATCH_2 : target, ®1));
1873 #if defined(ARCH_S390)
1874 if (alu == ALU1_NOT) {
1875 g(gen_3address_alu_imm(ctx, i_size(op_size), ALU_XOR, target, reg1, -1, 0));
1877 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1881 #if defined(ARCH_X86)
1882 g(gen_2address_alu1(ctx, op_size, alu, target, reg1, mode == MODE_INT));
1884 if (mode == MODE_INT) {
1885 #if defined(ARCH_POWER)
1886 if (op_size == OP_SIZE_NATIVE) {
1887 g(gen_2address_alu1(ctx, i_size(op_size), alu, target, reg1, 0));
1888 if (alu == ALU1_NEG) {
1889 g(gen_3address_alu(ctx, i_size(op_size), ALU_AND, R_CG_SCRATCH, target, reg1, 1));
1891 gen_insn(INSN_JMP_COND, op_size, COND_L, 0);
1892 gen_four(label_ovf);
1894 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1899 if (!arch_use_flags && !ARCH_SUPPORTS_TRAPS(op_size) && ARCH_HAS_ANDN && op_size >= OP_SIZE_4) {
1900 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, alu, target, reg1, 0));
1902 if (alu == ALU1_NEG) {
1903 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_AND, R_SCRATCH_3, target, reg1, 0));
1906 if (op_size < OP_SIZE_NATIVE)
1907 g(gen_extend(ctx, op_size, sign_x, R_SCRATCH_3, R_SCRATCH_3));
1909 g(gen_jmp_on_zero(ctx, OP_SIZE_NATIVE, R_SCRATCH_3, COND_S, label_ovf));
1911 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1915 if (op_size <= OP_SIZE_2 || (!arch_use_flags && !ARCH_SUPPORTS_TRAPS(op_size))) {
1916 int64_t imm = (ARCH_PREFERS_SX(op_size) ? -0x80ULL : 0x80ULL) << (((1 << op_size) - 1) * 8);
1918 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, i_size_cmp(op_size), reg1, imm, COND_E, label_ovf));
1922 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
1926 if (mode == MODE_INT) {
1927 gen_insn(INSN_ALU1_TRAP, op_size, alu, ALU1_WRITES_FLAGS(alu));
1930 gen_four(label_ovf);
1931 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1935 g(gen_2address_alu1(ctx, i_size(op_size), alu, target, reg1, mode == MODE_INT));
1937 if (mode == MODE_INT) {
1938 gen_insn(INSN_JMP_COND, i_size_cmp(op_size), COND_O, 0);
1939 gen_four(label_ovf);
1941 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1949 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
1950 g(gen_frame_get(ctx, op_size, garbage, slot_1, target, ®1));
1952 g(gen_3address_alu_imm(ctx, i_size(op_size), ALU_XOR, target, reg1, 1, 0));
1954 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
1962 bool attr_unused sx = false;
1963 #if defined(ARCH_X86) || defined(ARCH_ARM) || defined(ARCH_IA64) || defined(ARCH_LOONGARCH64) || defined(ARCH_MIPS) || defined(ARCH_RISCV64) || defined(ARCH_S390)
1964 #if defined(ARCH_ARM32)
1965 if (unlikely(!cpu_test_feature(CPU_FEATURE_armv6)))
1966 goto do_generic_bswap;
1968 #if defined(ARCH_MIPS)
1969 if (unlikely(!MIPS_HAS_ROT))
1970 goto do_generic_bswap;
1971 sx = op_size == OP_SIZE_4;
1973 #if defined(ARCH_RISCV64)
1974 if (unlikely(!cpu_test_feature(CPU_FEATURE_zbb)))
1975 goto do_generic_bswap;
1977 #if defined(ARCH_S390)
1978 if (op_size == OP_SIZE_2)
1979 goto do_generic_bswap;
1981 #if defined(ARCH_X86)
1982 if (op_size >= OP_SIZE_4 && !cpu_test_feature(CPU_FEATURE_bswap))
1983 goto do_generic_bswap;
1985 if (op_size > OP_SIZE_NATIVE) {
1986 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_1, 0, R_SCRATCH_1, R_SCRATCH_2));
1988 target = R_SCRATCH_1;
1990 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
1991 g(gen_frame_get(ctx, op_size, sx ? sign_x : garbage, slot_1, target, ®1));
1994 if (op_size == OP_SIZE_1) {
1995 #if defined(ARCH_IA64) || defined(ARCH_RISCV64)
1996 } else if (op_size == OP_SIZE_2 || op_size == OP_SIZE_4) {
1997 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_BSWAP, target, reg1, 0));
1999 g(gen_3address_rot_imm(ctx, OP_SIZE_NATIVE, ROT_SAR, target, target, op_size == OP_SIZE_2 ? 48 : 32, 0));
2001 } else if (op_size == OP_SIZE_2) {
2002 #if defined(ARCH_X86)
2003 g(gen_3address_rot_imm(ctx, OP_SIZE_2, ROT_ROR, target, reg1, 8, 0));
2005 g(gen_2address_alu1(ctx, OP_SIZE_4, ALU1_BSWAP16, target, reg1, 0));
2008 g(gen_2address_alu1(ctx, minimum(op_size, OP_SIZE_NATIVE), ALU1_BSWAP, target, reg1, 0));
2010 if (op_size > OP_SIZE_NATIVE) {
2011 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_BSWAP, R_SCRATCH_2, R_SCRATCH_2, 0));
2014 if (op_size > OP_SIZE_NATIVE)
2015 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, R_SCRATCH_2, R_SCRATCH_1));
2017 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2020 goto do_generic_bswap;
2022 return gen_alu_typed_upcall(ctx, offsetof(struct cg_upcall_vector_s, FIXED_unary_bswap_int8_t), op_size, slot_1, NO_FRAME_T, slot_r, 0);
2028 #if defined(ARCH_ARM) || defined(ARCH_LOONGARCH64) || (defined(ARCH_MIPS) && MIPS_R6)
2029 #if defined(ARCH_ARM32)
2030 if (unlikely(!cpu_test_feature(CPU_FEATURE_armv6t2)))
2031 goto do_generic_brev;
2033 if (op_size > OP_SIZE_NATIVE) {
2034 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_1, 0, R_SCRATCH_1, R_SCRATCH_2));
2036 target = R_SCRATCH_1;
2038 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
2039 g(gen_frame_get(ctx, op_size, garbage, slot_1, target, ®1));
2042 g(gen_2address_alu1(ctx, minimum(maximum(OP_SIZE_4, op_size), OP_SIZE_NATIVE), ALU1_BREV, target, reg1, 0));
2043 if (op_size <= OP_SIZE_2) {
2044 g(gen_3address_rot_imm(ctx, OP_SIZE_4, ROT_SHR, target, target, op_size == OP_SIZE_1 ? 24 : 16, 0));
2046 if (op_size > OP_SIZE_NATIVE) {
2047 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_BREV, R_SCRATCH_2, R_SCRATCH_2, 0));
2050 if (op_size > OP_SIZE_NATIVE)
2051 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, R_SCRATCH_2, R_SCRATCH_1));
2053 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2056 goto do_generic_brev;
2058 return gen_alu_typed_upcall(ctx, offsetof(struct cg_upcall_vector_s, FIXED_unary_brev_int8_t), op_size, slot_1, NO_FRAME_T, slot_r, 0);
2063 do_bsf_bsr_popcnt: {
2064 if (op_size > OP_SIZE_NATIVE) {
2065 #if defined(ARCH_X86)
2066 uint32_t label_finish = 0; /* avoid warning */
2067 if (alu == ALU1_POPCNT && unlikely(!cpu_test_feature(CPU_FEATURE_popcnt)))
2068 goto do_generic_bsf_bsr_popcnt;
2069 if (alu == ALU1_BSR || alu == ALU1_POPCNT) {
2070 if (mode == MODE_INT) {
2071 g(gen_address(ctx, R_FRAME, (size_t)slot_1 * slot_size + hi_word(OP_SIZE_NATIVE), IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
2072 g(gen_imm(ctx, 0, IMM_PURPOSE_STORE_VALUE, OP_SIZE_NATIVE));
2073 gen_insn(INSN_CMP, OP_SIZE_NATIVE, 0, 1);
2074 gen_address_offset();
2077 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_S, 0);
2078 gen_four(label_ovf);
2081 if (alu == ALU1_BSF) {
2082 label_finish = alloc_label(ctx);
2083 if (unlikely(!label_finish))
2086 g(gen_address(ctx, R_FRAME, (size_t)slot_1 * slot_size + lo_word(OP_SIZE_NATIVE), IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
2087 gen_insn(INSN_ALU1, OP_SIZE_NATIVE, ALU1_BSF, ALU1_WRITES_FLAGS(ALU1_BSF));
2088 gen_one(R_SCRATCH_1);
2089 gen_address_offset();
2091 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_NE, 0);
2092 gen_four(label_finish);
2094 g(gen_address(ctx, R_FRAME, (size_t)slot_1 * slot_size + hi_word(OP_SIZE_NATIVE), IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
2095 gen_insn(INSN_ALU1, OP_SIZE_NATIVE, ALU1_BSF, ALU1_WRITES_FLAGS(ALU1_BSF));
2096 gen_one(R_SCRATCH_1);
2097 gen_address_offset();
2099 g(gen_3address_alu_imm(ctx, OP_SIZE_4, ALU_ADD, R_SCRATCH_1, R_SCRATCH_1, 8U << OP_SIZE_NATIVE, 0));
2101 if (alu == ALU1_BSR) {
2102 label_finish = alloc_label(ctx);
2103 if (unlikely(!label_finish))
2106 g(gen_address(ctx, R_FRAME, (size_t)slot_1 * slot_size + hi_word(OP_SIZE_NATIVE), IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
2107 gen_insn(INSN_ALU1, OP_SIZE_NATIVE, ALU1_BSR, ALU1_WRITES_FLAGS(ALU1_BSR));
2108 gen_one(R_SCRATCH_1);
2109 gen_address_offset();
2111 g(gen_3address_alu_imm(ctx, OP_SIZE_4, ALU_ADD, R_SCRATCH_1, R_SCRATCH_1, 8U << OP_SIZE_NATIVE, 0));
2113 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_NE, 0);
2114 gen_four(label_finish);
2116 g(gen_address(ctx, R_FRAME, (size_t)slot_1 * slot_size + lo_word(OP_SIZE_NATIVE), IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
2117 gen_insn(INSN_ALU1, OP_SIZE_NATIVE, ALU1_BSR, ALU1_WRITES_FLAGS(ALU1_BSR));
2118 gen_one(R_SCRATCH_1);
2119 gen_address_offset();
2121 if (alu == ALU1_BSF || alu == ALU1_BSR) {
2122 if (mode == MODE_INT) {
2123 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_E, 0);
2124 gen_four(label_ovf);
2126 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_NE, 0);
2127 gen_four(label_finish);
2129 g(gen_load_constant(ctx, R_SCRATCH_1, -1));
2132 gen_label(label_finish);
2134 if (mode == MODE_INT)
2137 if (R_SCRATCH_1 != R_AX || R_SCRATCH_2 != R_DX)
2138 internal(file_line, "gen_alu1: bad scratch registers");
2139 gen_insn(INSN_CWD, OP_SIZE_NATIVE, 0, 0);
2143 g(gen_address(ctx, R_FRAME, (size_t)slot_r * slot_size + lo_word(OP_SIZE_NATIVE), IMM_PURPOSE_STR_OFFSET, OP_SIZE_NATIVE));
2144 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
2145 gen_address_offset();
2146 gen_one(R_SCRATCH_1);
2148 g(gen_address(ctx, R_FRAME, (size_t)slot_r * slot_size + hi_word(OP_SIZE_NATIVE), IMM_PURPOSE_STR_OFFSET, OP_SIZE_NATIVE));
2149 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
2150 gen_address_offset();
2151 gen_one(R_SCRATCH_2);
2155 if (alu == ALU1_POPCNT) {
2156 g(gen_address(ctx, R_FRAME, (size_t)slot_1 * slot_size + lo_word(OP_SIZE_NATIVE), IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
2157 gen_insn(INSN_ALU1, OP_SIZE_NATIVE, ALU1_POPCNT, ALU1_WRITES_FLAGS(ALU1_POPCNT));
2158 gen_one(R_SCRATCH_1);
2159 gen_address_offset();
2161 g(gen_address(ctx, R_FRAME, (size_t)slot_1 * slot_size + hi_word(OP_SIZE_NATIVE), IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
2162 gen_insn(INSN_ALU1, OP_SIZE_NATIVE, ALU1_POPCNT, ALU1_WRITES_FLAGS(ALU1_POPCNT));
2163 gen_one(R_SCRATCH_2);
2164 gen_address_offset();
2166 g(gen_3address_alu(ctx, OP_SIZE_4, ALU_ADD, R_SCRATCH_1, R_SCRATCH_1, R_SCRATCH_2, 1));
2168 g(gen_address(ctx, R_FRAME, (size_t)slot_r * slot_size + lo_word(OP_SIZE_NATIVE), IMM_PURPOSE_STR_OFFSET, OP_SIZE_NATIVE));
2169 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
2170 gen_address_offset();
2171 gen_one(R_SCRATCH_1);
2173 g(gen_address(ctx, R_FRAME, (size_t)slot_r * slot_size + hi_word(OP_SIZE_NATIVE), IMM_PURPOSE_STR_OFFSET, OP_SIZE_NATIVE));
2174 g(gen_imm(ctx, 0, IMM_PURPOSE_STORE_VALUE, OP_SIZE_NATIVE));
2175 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
2176 gen_address_offset();
2182 goto do_generic_bsf_bsr_popcnt;
2184 #if defined(ARCH_X86)
2185 if (alu == ALU1_POPCNT && unlikely(!cpu_test_feature(CPU_FEATURE_popcnt)))
2186 goto do_generic_bsf_bsr_popcnt;
2187 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
2188 if (op_size == OP_SIZE_1 || ((alu == ALU1_BSR || alu == ALU1_POPCNT) && mode == MODE_INT)) {
2189 g(gen_frame_get(ctx, op_size, zero_x, slot_1, target, ®1));
2190 if ((alu == ALU1_BSR || alu == ALU1_POPCNT) && mode == MODE_INT) {
2191 g(gen_cmp_test_jmp(ctx, INSN_TEST, op_size, reg1, reg1, alu == ALU1_BSR ? COND_LE : COND_S, label_ovf));
2193 g(gen_2address_alu1(ctx, maximum(op_size, OP_SIZE_2), alu, target, reg1, 1));
2194 if ((alu == ALU1_BSR || alu == ALU1_POPCNT) && mode == MODE_INT)
2195 goto x86_bsf_bsr_popcnt_finish;
2197 g(gen_frame_load_op1(ctx, op_size, alu, 1, slot_1, target));
2199 if (alu == ALU1_POPCNT)
2200 goto x86_bsf_bsr_popcnt_finish;
2201 if (mode == MODE_FIXED) {
2202 uint32_t cmov_label;
2203 gen_insn(INSN_MOV, maximum(op_size, OP_SIZE_4), 0, 0);
2204 gen_one(R_SCRATCH_2);
2207 g(gen_cmov(ctx, maximum(op_size, OP_SIZE_4), COND_E, target, &cmov_label));
2208 gen_one(R_SCRATCH_2);
2210 gen_label(cmov_label);
2213 gen_insn(INSN_JMP_COND, maximum(op_size, OP_SIZE_2), COND_E, 0);
2214 gen_four(label_ovf);
2216 x86_bsf_bsr_popcnt_finish:
2217 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2220 #if defined(ARCH_ARM)
2221 #if defined(ARCH_ARM32)
2222 if (alu == ALU1_BSR && unlikely(!cpu_test_feature(CPU_FEATURE_armv6)))
2223 goto do_generic_bsf_bsr_popcnt;
2224 if (alu == ALU1_BSF && unlikely(!cpu_test_feature(CPU_FEATURE_armv6t2)))
2225 goto do_generic_bsf_bsr_popcnt;
2227 if (alu == ALU1_POPCNT && unlikely(!cpu_test_feature(CPU_FEATURE_neon)))
2228 goto do_generic_bsf_bsr_popcnt;
2229 g(gen_frame_get(ctx, op_size, mode == MODE_INT ? sign_x : zero_x, slot_1, R_SCRATCH_1, ®1));
2230 if (mode == MODE_INT) {
2231 g(gen_cmp_test_jmp(ctx, INSN_TEST, i_size(op_size), reg1, reg1, alu == ALU1_BSR ? COND_LE : alu == ALU1_BSF ? COND_E : COND_S, label_ovf));
2234 if (alu == ALU1_POPCNT) {
2235 g(gen_mov(ctx, OP_SIZE_NATIVE, FR_SCRATCH_1, reg1));
2236 gen_insn(INSN_FP_ALU1, OP_SIZE_NATIVE, FP_ALU1_VCNT8, 0);
2237 gen_one(FR_SCRATCH_1);
2238 gen_one(FR_SCRATCH_1);
2239 #if defined(ARCH_ARM32)
2240 if (op_size > OP_SIZE_1) {
2241 gen_insn(INSN_FP_ALU1, OP_SIZE_1, FP_ALU1_VPADDL, 0);
2242 gen_one(FR_SCRATCH_1);
2243 gen_one(FR_SCRATCH_1);
2245 if (op_size > OP_SIZE_2) {
2246 gen_insn(INSN_FP_ALU1, OP_SIZE_2, FP_ALU1_VPADDL, 0);
2247 gen_one(FR_SCRATCH_1);
2248 gen_one(FR_SCRATCH_1);
2251 if (op_size > OP_SIZE_1) {
2252 gen_insn(INSN_FP_ALU1, OP_SIZE_1, FP_ALU1_ADDV, 0);
2253 gen_one(FR_SCRATCH_1);
2254 gen_one(FR_SCRATCH_1);
2257 g(gen_frame_store(ctx, op_size, slot_r, 0, FR_SCRATCH_1));
2258 if (slot_is_register(ctx, slot_r))
2259 g(unspill(ctx, slot_r));
2263 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
2264 if (mode == MODE_FIXED && alu == ALU1_BSF) {
2265 gen_insn(INSN_TEST, i_size(op_size), 0, 1);
2271 if (alu == ALU1_BSF) {
2272 g(gen_2address_alu1(ctx, i_size(op_size), ALU1_BREV, target, reg1, 0));
2276 g(gen_2address_alu1(ctx, i_size(op_size), ALU1_LZCNT, target, reg1, 0));
2278 if (alu == ALU1_BSR) {
2279 g(gen_load_constant(ctx, R_SCRATCH_2, op_size == OP_SIZE_8 ? 63 : 31));
2280 g(gen_3address_alu(ctx, i_size(op_size), ALU_SUB, target, R_SCRATCH_2, target, 0));
2283 if (mode == MODE_FIXED && alu == ALU1_BSF) {
2284 #if defined(ARCH_ARM32)
2285 g(gen_imm(ctx, -1, IMM_PURPOSE_CMOV, OP_SIZE_NATIVE));
2286 gen_insn(INSN_CMOV, OP_SIZE_NATIVE, COND_E, 0);
2291 gen_insn(INSN_CSEL_INV, i_size(op_size), COND_NE, 0);
2299 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2302 #if defined(ARCH_ALPHA)
2303 if (likely(cpu_test_feature(CPU_FEATURE_cix))) {
2304 g(gen_frame_get(ctx, op_size, mode == MODE_INT ? sign_x : zero_x, slot_1, R_SCRATCH_1, ®1));
2305 target = gen_frame_target(ctx, slot_r, slot_1, NO_FRAME_T, R_SCRATCH_2);
2306 if (mode == MODE_INT) {
2307 g(gen_cmp_test_jmp(ctx, INSN_TEST, OP_SIZE_NATIVE, reg1, reg1, alu == ALU1_BSR ? COND_LE : alu == ALU1_BSF ? COND_E : COND_S, label_ovf));
2309 if (alu == ALU1_POPCNT) {
2310 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_POPCNT, target, reg1, 0));
2312 if (alu == ALU1_BSF) {
2313 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_BSF, target, reg1, 0));
2315 if (mode == MODE_FIXED) {
2316 g(gen_imm(ctx, -1, IMM_PURPOSE_MOVR, OP_SIZE_INT));
2317 gen_insn(INSN_MOVR, OP_SIZE_NATIVE, COND_E, 0);
2324 if (alu == ALU1_BSR) {
2325 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_LZCNT, target, reg1, 0));
2327 g(gen_load_constant(ctx, R_SCRATCH_3, OP_SIZE_NATIVE == OP_SIZE_8 ? 63 : 31));
2329 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_SUB, target, R_SCRATCH_3, target, 0));
2331 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2335 #if defined(ARCH_MIPS)
2336 if (MIPS_HAS_CLZ && alu != ALU1_POPCNT) {
2337 g(gen_frame_get(ctx, op_size, mode == MODE_INT ? sign_x : zero_x, slot_1, R_SCRATCH_1, ®1));
2338 target = gen_frame_target(ctx, slot_r, slot_1, NO_FRAME_T, R_SCRATCH_2);
2339 if (mode == MODE_INT) {
2340 g(gen_cmp_test_jmp(ctx, INSN_TEST, OP_SIZE_NATIVE, reg1, reg1, alu == ALU1_BSR ? COND_LE : alu == ALU1_BSF ? COND_E : COND_S, label_ovf));
2342 if (alu == ALU1_BSF) {
2343 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_NEG, target, reg1, 0));
2345 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_AND, R_SCRATCH_1, reg1, target, 0));
2348 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_LZCNT, target, reg1, 0));
2350 g(gen_load_constant(ctx, R_SCRATCH_3, OP_SIZE_NATIVE == OP_SIZE_8 ? 63 : 31));
2352 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_SUB, target, R_SCRATCH_3, target, 0));
2354 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2358 #if defined(ARCH_POWER)
2359 if (alu == ALU1_BSF && (unlikely(!cpu_test_feature(CPU_FEATURE_v203)) || unlikely(!cpu_test_feature(CPU_FEATURE_v30))))
2360 goto do_generic_bsf_bsr_popcnt;
2361 if (alu == ALU1_POPCNT && unlikely(!cpu_test_feature(CPU_FEATURE_v206)))
2362 goto do_generic_bsf_bsr_popcnt;
2363 g(gen_frame_get(ctx, op_size, mode == MODE_INT ? sign_x : zero_x, slot_1, R_SCRATCH_1, ®1));
2364 target = gen_frame_target(ctx, slot_r, slot_1, NO_FRAME_T, R_SCRATCH_2);
2365 if (mode == MODE_INT) {
2366 g(gen_cmp_test_jmp(ctx, INSN_TEST, i_size(op_size), reg1, reg1, alu == ALU1_BSR ? COND_LE : alu == ALU1_BSF ? COND_E : COND_S, label_ovf));
2368 if (alu == ALU1_POPCNT) {
2369 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_POPCNT, target, reg1, 0));
2371 if (alu == ALU1_BSF) {
2372 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_BSF, target, reg1, 0));
2374 if (mode == MODE_FIXED) {
2375 g(gen_3address_alu(ctx, i_size(op_size), ALU_AND, R_SCRATCH_3, reg1, reg1, 1));
2377 g(gen_imm(ctx, -1, IMM_PURPOSE_CMOV, OP_SIZE_NATIVE));
2378 gen_insn(INSN_CMOV, OP_SIZE_NATIVE, COND_E, 0);
2384 if (alu == ALU1_BSR) {
2385 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_LZCNT, target, reg1, 0));
2387 g(gen_load_constant(ctx, R_SCRATCH_3, OP_SIZE_NATIVE == OP_SIZE_8 ? 63 : 31));
2389 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_SUB, target, R_SCRATCH_3, target, 0));
2391 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2394 #if defined(ARCH_LOONGARCH64) || defined(ARCH_RISCV64)
2395 #if defined(ARCH_LOONGARCH64)
2396 if (alu == ALU1_POPCNT)
2397 goto do_generic_bsf_bsr_popcnt;
2399 #if defined(ARCH_RISCV64)
2400 if (unlikely(!cpu_test_feature(CPU_FEATURE_zbb)))
2401 goto do_generic_bsf_bsr_popcnt;
2403 g(gen_frame_get(ctx, op_size, mode == MODE_INT ? sign_x : zero_x, slot_1, R_SCRATCH_1, ®1));
2404 target = gen_frame_target(ctx, slot_r, slot_1, NO_FRAME_T, R_SCRATCH_2);
2405 if (mode == MODE_INT) {
2406 g(gen_cmp_test_jmp(ctx, INSN_TEST, OP_SIZE_NATIVE, reg1, reg1, alu == ALU1_BSR ? COND_LE : alu == ALU1_BSF ? COND_E : COND_S, label_ovf));
2408 if (alu == ALU1_POPCNT) {
2409 g(gen_2address_alu1(ctx, maximum(OP_SIZE_4, op_size), ALU1_POPCNT, target, reg1, 0));
2411 if (alu == ALU1_BSF) {
2412 g(gen_2address_alu1(ctx, maximum(OP_SIZE_4, op_size), ALU1_BSF, target, reg1, 0));
2414 if (mode == MODE_FIXED) {
2415 g(gen_imm(ctx, 1, IMM_PURPOSE_CMP, OP_SIZE_NATIVE));
2416 gen_insn(INSN_CMP_DEST_REG, OP_SIZE_NATIVE, COND_B, 0);
2417 gen_one(R_SCRATCH_3);
2421 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_NEG, R_SCRATCH_3, R_SCRATCH_3, 0));
2423 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_OR, target, target, R_SCRATCH_3, 0));
2426 if (alu == ALU1_BSR) {
2427 g(gen_2address_alu1(ctx, maximum(OP_SIZE_4, op_size), ALU1_LZCNT, target, reg1, 0));
2429 g(gen_load_constant(ctx, R_SCRATCH_3, op_size <= OP_SIZE_4 ? 31 : 63));
2431 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_SUB, target, R_SCRATCH_3, target, 0));
2433 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2436 #if defined(ARCH_IA64) || defined(ARCH_S390) || defined(ARCH_SPARC)
2437 if (alu == ALU1_BSF && !ARCH_HAS_ANDN)
2438 goto do_generic_bsf_bsr_popcnt;
2439 #if defined(ARCH_S390)
2440 if (!cpu_test_feature(CPU_FEATURE_misc_45) || !cpu_test_feature(CPU_FEATURE_misc_insn_ext_3))
2441 goto do_generic_bsf_bsr_popcnt;
2443 #if defined(ARCH_SPARC)
2445 goto do_generic_bsf_bsr_popcnt;
2447 g(gen_frame_get(ctx, op_size, mode == MODE_INT ? sign_x : zero_x, slot_1, R_SCRATCH_1, ®1));
2448 target = gen_frame_target(ctx, slot_r, slot_1, NO_FRAME_T, R_SCRATCH_2);
2449 if (mode == MODE_INT) {
2450 g(gen_cmp_test_jmp(ctx, INSN_TEST, maximum(op_size, OP_SIZE_4), reg1, reg1, alu == ALU1_BSR ? COND_LE : alu == ALU1_BSF ? COND_E : COND_S, label_ovf));
2452 if (ARCH_PREFERS_SX(op_size) && alu == ALU1_POPCNT && op_size < OP_SIZE_NATIVE) {
2453 g(gen_extend(ctx, op_size, zero_x, R_SCRATCH_1, reg1));
2457 if (alu == ALU1_POPCNT) {
2458 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_POPCNT, R_SCRATCH_1, reg1, 0));
2459 g(gen_frame_store(ctx, op_size, slot_r, 0, R_SCRATCH_1));
2462 if (alu == ALU1_BSF) {
2463 g(gen_3address_alu_imm(ctx, OP_SIZE_NATIVE, ALU_SUB, target, reg1, 1, 0));
2465 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_ANDN, target, target, reg1, 0));
2467 g(gen_2address_alu1(ctx, OP_SIZE_NATIVE, ALU1_POPCNT, target, target, 0));
2469 if (mode == MODE_FIXED) {
2470 unsigned attr_unused test_reg = R_SCRATCH_1;
2471 #if defined(ARCH_S390)
2472 g(gen_imm(ctx, 0, COND_IS_LOGICAL(COND_E) ? IMM_PURPOSE_CMP_LOGICAL : IMM_PURPOSE_CMP, OP_SIZE_NATIVE));
2473 gen_insn(INSN_CMP, OP_SIZE_NATIVE, 0, 1 + COND_IS_LOGICAL(COND_E));
2477 g(gen_imm(ctx, -1, IMM_PURPOSE_CMOV, OP_SIZE_NATIVE));
2478 gen_insn(INSN_CMOV, OP_SIZE_NATIVE, COND_E, 0);
2483 #if defined(ARCH_IA64)
2484 g(gen_cmp_dest_reg(ctx, OP_SIZE_NATIVE, reg1, (unsigned)-1, R_CMP_RESULT, 0, COND_NE));
2485 test_reg = R_CMP_RESULT;
2487 g(gen_imm(ctx, -1, IMM_PURPOSE_MOVR, OP_SIZE_NATIVE));
2488 gen_insn(INSN_MOVR, OP_SIZE_NATIVE, COND_E, 0);
2496 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2500 do_generic_bsf_bsr_popcnt:
2501 if (alu == ALU1_BSF) {
2502 if (mode == MODE_FIXED)
2503 return gen_alu_typed_upcall(ctx, offsetof(struct cg_upcall_vector_s, FIXED_unary_bsf_int8_t), op_size, slot_1, NO_FRAME_T, slot_r, 0);
2505 return gen_alu_typed_upcall(ctx, offsetof(struct cg_upcall_vector_s, INT_unary_bsf_int8_t), op_size, slot_1, NO_FRAME_T, slot_r, label_ovf);
2507 if (alu == ALU1_BSR) {
2508 if (mode == MODE_FIXED)
2509 return gen_alu_typed_upcall(ctx, offsetof(struct cg_upcall_vector_s, FIXED_unary_bsr_int8_t), op_size, slot_1, NO_FRAME_T, slot_r, 0);
2511 return gen_alu_typed_upcall(ctx, offsetof(struct cg_upcall_vector_s, INT_unary_bsr_int8_t), op_size, slot_1, NO_FRAME_T, slot_r, label_ovf);
2513 if (alu == ALU1_POPCNT) {
2514 if (mode == MODE_FIXED)
2515 return gen_alu_typed_upcall(ctx, offsetof(struct cg_upcall_vector_s, FIXED_unary_popcnt_int8_t), op_size, slot_1, NO_FRAME_T, slot_r, 0);
2517 return gen_alu_typed_upcall(ctx, offsetof(struct cg_upcall_vector_s, INT_unary_popcnt_int8_t), op_size, slot_1, NO_FRAME_T, slot_r, label_ovf);
2525 unsigned src_op_size, dest_op_size;
2526 const struct type *src_type, *dest_type;
2527 src_type = get_type_of_local(ctx, slot_1);
2528 dest_type = get_type_of_local(ctx, slot_r);
2530 if (TYPE_TAG_IS_FIXED(src_type->tag)) {
2531 src_op_size = TYPE_TAG_IDX_FIXED(src_type->tag) >> 1;
2533 src_op_size = TYPE_TAG_IDX_INT(src_type->tag);
2536 if (TYPE_TAG_IS_FIXED(dest_type->tag)) {
2537 dest_op_size = TYPE_TAG_IDX_FIXED(dest_type->tag) >> 1;
2539 dest_op_size = TYPE_TAG_IDX_INT(dest_type->tag);
2542 if (src_op_size <= OP_SIZE_NATIVE) {
2543 g(gen_frame_get(ctx, src_op_size, sign_x, slot_1, R_SCRATCH_1, ®1));
2545 #if defined(ARCH_X86)
2546 if (dest_op_size < src_op_size)
2547 g(gen_frame_load(ctx, OP_SIZE_NATIVE, garbage, slot_1, 0, false, R_SCRATCH_1));
2550 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_1, 0, R_SCRATCH_1, R_SCRATCH_3));
2554 if (dest_op_size >= src_op_size) {
2555 if (dest_op_size <= OP_SIZE_NATIVE) {
2556 g(gen_frame_store(ctx, dest_op_size, slot_r, 0, reg1));
2558 if (src_op_size <= OP_SIZE_NATIVE) {
2559 #if defined(ARCH_X86)
2560 if (R_SCRATCH_1 != R_AX || R_SCRATCH_2 != R_DX)
2561 internal(file_line, "gen_alu1: bad scratch registers");
2562 if (reg1 == R_SCRATCH_1) {
2563 gen_insn(INSN_CWD, OP_SIZE_NATIVE, 0, 0);
2568 g(gen_3address_rot_imm(ctx, OP_SIZE_NATIVE, ROT_SAR, R_SCRATCH_2, reg1, (1U << (OP_SIZE_NATIVE + 3)) - 1, false));
2569 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, reg1, R_SCRATCH_2));
2571 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, reg1, R_SCRATCH_3));
2576 if (src_op_size > OP_SIZE_NATIVE) {
2577 #if defined(ARCH_ARM)
2578 gen_insn(INSN_CMP, OP_SIZE_NATIVE, 0, 1);
2579 gen_one(R_SCRATCH_3);
2580 gen_one(ARG_SHIFTED_REGISTER);
2581 gen_one(ARG_SHIFT_ASR | ((1U << (OP_SIZE_NATIVE + 3)) - 1));
2582 gen_one(R_SCRATCH_1);
2584 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_NE, 0);
2585 gen_four(label_ovf);
2586 #elif defined(ARCH_X86)
2587 if (R_SCRATCH_1 != R_AX || R_SCRATCH_2 != R_DX)
2588 internal(file_line, "gen_alu1: bad scratch registers");
2589 gen_insn(INSN_CWD, OP_SIZE_NATIVE, 0, 0);
2593 g(gen_address(ctx, R_FRAME, (size_t)slot_1 * slot_size + hi_word(OP_SIZE_NATIVE), IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
2594 gen_insn(INSN_CMP, OP_SIZE_NATIVE, 0, 1);
2595 gen_one(R_SCRATCH_2);
2596 gen_address_offset();
2598 gen_insn(INSN_JMP_COND, OP_SIZE_NATIVE, COND_NE, 0);
2599 gen_four(label_ovf);
2601 g(gen_3address_rot_imm(ctx, OP_SIZE_NATIVE, ROT_SAR, R_SCRATCH_2, R_SCRATCH_1, (1U << (OP_SIZE_NATIVE + 3)) - 1, 0));
2603 g(gen_cmp_test_jmp(ctx, INSN_CMP, OP_SIZE_NATIVE, R_SCRATCH_3, R_SCRATCH_2, COND_NE, label_ovf));
2606 src_op_size = OP_SIZE_NATIVE;
2608 if (src_op_size > dest_op_size) {
2609 g(gen_cmp_extended(ctx, OP_SIZE_NATIVE, dest_op_size, reg1, R_SCRATCH_2, label_ovf));
2611 g(gen_frame_store(ctx, dest_op_size, slot_r, 0, reg1));
2617 return gen_alu_typed_upcall(ctx, offsetof(struct cg_upcall_vector_s, FIXED_uto_int_int8_t), op_size, slot_1, NO_FRAME_T, slot_r, label_ovf);
2621 return gen_alu_typed_upcall(ctx, offsetof(struct cg_upcall_vector_s, FIXED_ufrom_int_int8_t), op_size, slot_1, NO_FRAME_T, slot_r, label_ovf);
2625 static bool attr_w gen_constant(struct codegen_context *ctx, bool real, unsigned op_size, bool shrt, frame_t slot_r)
2629 c = (int16_t)get_unaligned_16(ctx->current_position);
2630 } else switch (op_size) {
2631 #define fx(n, type, utype, sz, bits) \
2633 c = (type)cat(get_unaligned_,bits)(ctx->current_position);\
2638 internal(file_line, "gen_constant: invalid type %u", op_size);
2640 if (op_size > OP_SIZE_NATIVE) {
2641 unsigned shift = (8U << OP_SIZE_NATIVE) - 1;
2642 g(gen_frame_store_imm_raw(ctx, OP_SIZE_NATIVE, slot_r, lo_word(OP_SIZE_NATIVE), c & ((2ULL << shift) - 1)));
2643 g(gen_frame_store_imm_raw(ctx, OP_SIZE_NATIVE, slot_r, hi_word(OP_SIZE_NATIVE), c >> 1 >> shift));
2644 if (real && slot_is_register(ctx, slot_r))
2645 g(unspill(ctx, slot_r));
2647 } else if (real && slot_is_register(ctx, slot_r)) {
2648 if (ARCH_HAS_FP_GP_MOV) {
2649 g(gen_load_constant(ctx, R_SCRATCH_1, c));
2650 g(gen_mov(ctx, op_size, ctx->registers[slot_r], R_SCRATCH_1));
2652 g(gen_frame_store_imm_raw(ctx, op_size, slot_r, 0, c));
2653 g(unspill(ctx, slot_r));
2656 g(gen_frame_store_imm(ctx, op_size, slot_r, 0, c));
2661 static bool attr_w gen_real_constant(struct codegen_context *ctx, const struct type *t, frame_t slot_r)
2664 if (is_power_of_2(t->size) && t->size <= sizeof(uintbig_t))
2665 return gen_constant(ctx, true, log_2(t->size), false, slot_r);
2667 g(load_function_offset(ctx, R_SCRATCH_3, offsetof(struct data, u_.function.code)));
2669 offset = (ctx->current_position - da(ctx->fn,function)->code) * sizeof(code_t);
2671 g(gen_memcpy_raw(ctx, R_FRAME, (size_t)slot_r * slot_size, R_SCRATCH_3, offset, t->size, minimum(t->align, sizeof(code_t))));
2672 if (slot_is_register(ctx, slot_r))
2673 g(unspill(ctx, slot_r));
2678 static bool attr_w gen_copy(struct codegen_context *ctx, unsigned op_size, frame_t slot_1, frame_t slot_r)
2681 if (unlikely(op_size > OP_SIZE_NATIVE)) {
2682 g(gen_frame_load_2(ctx, OP_SIZE_NATIVE, slot_1, 0, R_SCRATCH_1, R_SCRATCH_2));
2683 g(gen_frame_store_2(ctx, OP_SIZE_NATIVE, slot_r, 0, R_SCRATCH_1, R_SCRATCH_2));
2686 unsigned target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
2687 g(gen_frame_get(ctx, op_size, garbage, slot_1, target, ®1));
2688 g(gen_frame_store(ctx, op_size, slot_r, 0, reg1));
2693 static bool attr_w gen_fp_alu(struct codegen_context *ctx, unsigned real_type, unsigned op, uint32_t label_ovf, frame_t slot_1, frame_t slot_2, frame_t slot_r)
2695 unsigned attr_unused fp_alu;
2697 unsigned attr_unused op_size = real_type_to_op_size(real_type);
2698 unsigned reg1, reg2, target;
2700 case OPCODE_REAL_OP_add:
2701 case OPCODE_REAL_OP_add_alt1:
2702 case OPCODE_REAL_OP_add_alt2: fp_alu = FP_ALU_ADD; upc = offsetof(struct cg_upcall_vector_s, REAL_binary_add_real16_t); label_ovf = 0; goto do_alu;
2703 case OPCODE_REAL_OP_subtract:
2704 case OPCODE_REAL_OP_subtract_alt1:
2705 case OPCODE_REAL_OP_subtract_alt2: fp_alu = FP_ALU_SUB; upc = offsetof(struct cg_upcall_vector_s, REAL_binary_subtract_real16_t); label_ovf = 0; goto do_alu;
2706 case OPCODE_REAL_OP_multiply:
2707 case OPCODE_REAL_OP_multiply_alt1:
2708 case OPCODE_REAL_OP_multiply_alt2: fp_alu = FP_ALU_MUL; upc = offsetof(struct cg_upcall_vector_s, REAL_binary_multiply_real16_t); label_ovf = 0; goto do_alu;
2709 case OPCODE_REAL_OP_divide:
2710 case OPCODE_REAL_OP_divide_alt1:
2711 case OPCODE_REAL_OP_divide_alt2: fp_alu = FP_ALU_DIV; upc = offsetof(struct cg_upcall_vector_s, REAL_binary_divide_real16_t); label_ovf = 0; goto do_alu;
2712 case OPCODE_REAL_OP_modulo:
2713 case OPCODE_REAL_OP_power:
2714 case OPCODE_REAL_OP_ldexp:
2715 case OPCODE_REAL_OP_atan2: upc = offsetof(struct cg_upcall_vector_s, REAL_binary_modulo_real16_t) + (op - OPCODE_REAL_OP_modulo) * TYPE_REAL_N * sizeof(void (*)(void)); goto do_upcall;
2716 case OPCODE_REAL_OP_equal:
2717 case OPCODE_REAL_OP_equal_alt1:
2718 case OPCODE_REAL_OP_equal_alt2: fp_alu = FP_COND_E; upc = offsetof(struct cg_upcall_vector_s, REAL_binary_equal_real16_t); goto do_cmp;
2719 case OPCODE_REAL_OP_not_equal:
2720 case OPCODE_REAL_OP_not_equal_alt1:
2721 case OPCODE_REAL_OP_not_equal_alt2: fp_alu = FP_COND_NE; upc = offsetof(struct cg_upcall_vector_s, REAL_binary_not_equal_real16_t); goto do_cmp;
2722 case OPCODE_REAL_OP_less:
2723 case OPCODE_REAL_OP_less_alt1:
2724 case OPCODE_REAL_OP_less_alt2: fp_alu = FP_COND_B; upc = offsetof(struct cg_upcall_vector_s, REAL_binary_less_real16_t); goto do_cmp;
2725 case OPCODE_REAL_OP_less_equal:
2726 case OPCODE_REAL_OP_less_equal_alt1:
2727 case OPCODE_REAL_OP_less_equal_alt2: fp_alu = FP_COND_BE; upc = offsetof(struct cg_upcall_vector_s, REAL_binary_less_equal_real16_t); goto do_cmp;
2728 case OPCODE_REAL_OP_greater:
2729 case OPCODE_REAL_OP_greater_alt1:
2730 case OPCODE_REAL_OP_greater_alt2: fp_alu = FP_COND_A; upc = offsetof(struct cg_upcall_vector_s, REAL_binary_greater_real16_t); goto do_cmp;
2731 case OPCODE_REAL_OP_greater_equal:
2732 case OPCODE_REAL_OP_greater_equal_alt1:
2733 case OPCODE_REAL_OP_greater_equal_alt2: fp_alu = FP_COND_AE; upc = offsetof(struct cg_upcall_vector_s, REAL_binary_greater_equal_real16_t); goto do_cmp;
2734 default: internal(file_line, "gen_fp_alu: unsupported operation %u", op);
2738 if ((SUPPORTED_FP >> real_type) & 1) {
2739 #if defined(ARCH_IA64)
2740 if (unlikely(fp_alu == FP_ALU_DIV))
2743 #if defined(ARCH_X86)
2745 #elif defined(ARCH_S390)
2746 if ((op_size <= OP_SIZE_8 && (size_t)slot_2 * slot_size < 4096) || slot_is_register(ctx, slot_2))
2748 if (slot_is_register(ctx, slot_2))
2751 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, slot_2, FR_SCRATCH_1);
2752 g(gen_frame_get(ctx, op_size, garbage, slot_1, FR_SCRATCH_1, ®1));
2753 if (slot_is_register(ctx, slot_2)) {
2754 g(gen_3address_fp_alu(ctx, op_size, fp_alu, target, reg1, ctx->registers[slot_2]));
2756 if (target != reg1 && !ARCH_IS_3ADDRESS_FP) {
2757 g(gen_mov(ctx, op_size, target, reg1));
2760 g(gen_address(ctx, R_FRAME, (size_t)slot_2 * slot_size, IMM_PURPOSE_VLDR_VSTR_OFFSET, op_size));
2761 gen_insn(INSN_FP_ALU, op_size, fp_alu, 0);
2764 gen_address_offset();
2766 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2769 #if defined(ARCH_ALPHA)
2770 g(gen_frame_get(ctx, op_size, zero_x, slot_1, FR_SCRATCH_1, ®1));
2771 g(gen_frame_get(ctx, op_size, zero_x, slot_2, FR_SCRATCH_2, ®2));
2772 target = gen_frame_target(ctx, slot_r, slot_1, slot_2, FR_SCRATCH_3);
2773 g(gen_3address_fp_alu(ctx, op_size, fp_alu, target, reg1, reg2));
2774 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2776 g(gen_frame_get(ctx, op_size, zero_x, slot_1, FR_SCRATCH_1, ®1));
2777 g(gen_frame_get(ctx, op_size, zero_x, slot_2, FR_SCRATCH_2, ®2));
2778 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, FR_SCRATCH_1);
2779 g(gen_3address_fp_alu(ctx, op_size, fp_alu, target, reg1, reg2));
2780 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2784 #ifdef SUPPORTED_FP_X87
2785 if ((SUPPORTED_FP_X87 >> real_type) & 1) {
2786 if (real_type != 3) {
2787 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_2));
2788 g(gen_frame_load_x87(ctx, INSN_X87_ALU, op_size, fp_alu, slot_1));
2790 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_1));
2791 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_2));
2792 gen_insn(INSN_X87_ALUP, op_size, fp_alu, 0);
2795 g(gen_frame_store_x87(ctx, INSN_X87_FSTP, op_size, slot_r));
2799 #ifdef SUPPORTED_FP_HALF_CVT
2800 if ((SUPPORTED_FP_HALF_CVT >> real_type) & 1) {
2801 g(gen_frame_get(ctx, op_size, zero_x, slot_1, FR_SCRATCH_1, ®1));
2802 g(gen_frame_get(ctx, op_size, zero_x, slot_2, FR_SCRATCH_2, ®2));
2803 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, FR_SCRATCH_1);
2804 gen_insn(INSN_FP_CVT, op_size, OP_SIZE_4, 0);
2805 gen_one(FR_SCRATCH_1);
2807 gen_insn(INSN_FP_CVT, op_size, OP_SIZE_4, 0);
2808 gen_one(FR_SCRATCH_2);
2810 gen_insn(INSN_FP_ALU, OP_SIZE_4, fp_alu, 0);
2811 gen_one(FR_SCRATCH_1);
2812 gen_one(FR_SCRATCH_1);
2813 gen_one(FR_SCRATCH_2);
2814 gen_insn(INSN_FP_CVT, OP_SIZE_4, op_size, 0);
2816 gen_one(FR_SCRATCH_1);
2817 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
2824 if ((SUPPORTED_FP >> real_type) & 1
2825 #if defined(ARCH_ALPHA)
2826 && OS_SUPPORTS_TRAPS
2829 g(gen_frame_get(ctx, op_size, zero_x, slot_1, FR_SCRATCH_1, ®1));
2830 g(gen_frame_get(ctx, op_size, zero_x, slot_2, FR_SCRATCH_2, ®2));
2831 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
2832 #if defined(ARCH_ALPHA)
2833 gen_insn(INSN_FP_CMP_DEST_REG_TRAP, op_size, fp_alu == FP_COND_NE ? FP_COND_E : fp_alu, 0);
2834 gen_one(FR_SCRATCH_3);
2837 gen_four(label_ovf);
2839 if (!ARCH_HAS_FP_GP_MOV) {
2840 g(gen_frame_store_raw(ctx, OP_SIZE_4, slot_r, 0, FR_SCRATCH_3));
2841 g(gen_frame_load_raw(ctx, OP_SIZE_4, sign_x, slot_r, 0, false, target));
2843 g(gen_mov(ctx, OP_SIZE_4, target, FR_SCRATCH_3));
2846 if (fp_alu == FP_COND_NE) {
2847 g(gen_imm(ctx, 0, IMM_PURPOSE_CMP, OP_SIZE_NATIVE));
2848 gen_insn(INSN_CMP_DEST_REG, OP_SIZE_NATIVE, COND_E, 0);
2853 g(gen_3address_rot_imm(ctx, OP_SIZE_NATIVE, ROT_SHR, target, target, 30, 0));
2856 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, target));
2859 #elif defined(ARCH_IA64)
2860 gen_insn(INSN_FP_CMP_DEST_REG, op_size, FP_COND_P, 0);
2861 gen_one(R_CMP_RESULT);
2865 gen_insn(INSN_JMP_REG, OP_SIZE_NATIVE, COND_NE, 0);
2866 gen_one(R_CMP_RESULT);
2867 gen_four(label_ovf);
2869 gen_insn(INSN_FP_CMP_DEST_REG, op_size, fp_alu, 0);
2870 gen_one(R_CMP_RESULT);
2874 g(gen_mov(ctx, OP_SIZE_NATIVE, target, R_CMP_RESULT));
2876 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, target));
2879 #elif defined(ARCH_LOONGARCH64) || defined(ARCH_MIPS) || defined(ARCH_PARISC)
2880 gen_insn(INSN_FP_CMP_COND, op_size, FP_COND_P, 1);
2884 gen_insn(INSN_JMP_FP_TEST, 0, FP_COND_P, 0);
2885 gen_four(label_ovf);
2887 gen_insn(INSN_FP_CMP_COND, op_size, fp_alu, 1);
2891 gen_insn(INSN_FP_TEST_REG, OP_SIZE_NATIVE, fp_alu, 0);
2894 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, target));
2897 #elif defined(ARCH_RISCV64)
2898 gen_insn(INSN_FP_CMP_DEST_REG, op_size, FP_COND_E, 0);
2899 gen_one(R_SCRATCH_1);
2903 gen_insn(INSN_FP_CMP_DEST_REG, op_size, FP_COND_E, 0);
2904 gen_one(R_SCRATCH_2);
2908 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_AND, R_SCRATCH_1, R_SCRATCH_1, R_SCRATCH_2, 0));
2910 g(gen_jmp_on_zero(ctx, OP_SIZE_NATIVE, R_SCRATCH_1, COND_E, label_ovf));
2912 gen_insn(INSN_FP_CMP_DEST_REG, op_size, fp_alu == FP_COND_NE ? FP_COND_E : fp_alu, 0);
2917 if (fp_alu == FP_COND_NE) {
2918 g(gen_imm(ctx, 1, IMM_PURPOSE_XOR, OP_SIZE_NATIVE));
2919 gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_XOR, ALU_WRITES_FLAGS(OP_SIZE_NATIVE, ALU_XOR, false, is_imm(), ctx->const_imm));
2925 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, target));
2928 gen_insn(INSN_FP_CMP, op_size, 0, 1);
2931 #if defined(ARCH_ARM32)
2932 gen_insn(INSN_FP_TO_INT_FLAGS, 0, 0, 1);
2934 gen_insn(INSN_JMP_COND, op_size, FP_COND_P, 0);
2935 gen_four(label_ovf);
2936 g(gen_frame_set_cond(ctx, op_size, false, fp_alu, slot_r));
2940 #ifdef SUPPORTED_FP_X87
2941 if ((SUPPORTED_FP_X87 >> real_type) & 1) {
2942 if (likely(cpu_test_feature(CPU_FEATURE_cmov))) {
2943 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_2));
2944 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_1));
2945 gen_insn(INSN_X87_FCOMIP, op_size, 0, 0);
2947 gen_insn(INSN_X87_FSTP, op_size, 0, 0);
2949 gen_insn(INSN_JMP_COND, op_size, COND_P, 0);
2950 gen_four(label_ovf);
2951 g(gen_frame_set_cond(ctx, op_size, false, fp_alu & 0xf, slot_r));
2955 if (real_type != 3) {
2956 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_1));
2957 g(gen_frame_load_x87(ctx, INSN_X87_FCOMP, op_size, 0, slot_2));
2959 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_2));
2960 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_1));
2961 gen_insn(INSN_X87_FCOMPP, op_size, 0, 0);
2964 gen_insn(INSN_X87_FNSTSW, 0, 0, 0);
2968 gen_insn(INSN_TEST, OP_SIZE_2, 0, 1);
2973 gen_insn(INSN_JMP_COND, OP_SIZE_2, COND_NE, 0);
2974 gen_four(label_ovf);
2978 gen_insn(INSN_TEST, OP_SIZE_2, 0, 1);
2982 g(gen_frame_set_cond(ctx, OP_SIZE_2, false, COND_NE, slot_r));
2985 gen_insn(INSN_TEST, OP_SIZE_2, 0, 1);
2989 g(gen_frame_set_cond(ctx, OP_SIZE_2, false, COND_E, slot_r));
2992 gen_insn(INSN_TEST, OP_SIZE_2, 0, 1);
2996 g(gen_frame_set_cond(ctx, OP_SIZE_2, false, COND_NE, slot_r));
2999 gen_insn(INSN_TEST, OP_SIZE_2, 0, 1);
3003 g(gen_frame_set_cond(ctx, OP_SIZE_2, false, COND_NE, slot_r));
3006 internal(file_line, "gen_fp_alu: invalid condition %u", fp_alu);
3011 #ifdef SUPPORTED_FP_HALF_CVT
3012 if ((SUPPORTED_FP_HALF_CVT >> real_type) & 1) {
3013 g(gen_frame_get(ctx, op_size, zero_x, slot_1, FR_SCRATCH_1, ®1));
3014 g(gen_frame_get(ctx, op_size, zero_x, slot_2, FR_SCRATCH_2, ®2));
3015 gen_insn(INSN_FP_CVT, op_size, OP_SIZE_4, 0);
3016 gen_one(FR_SCRATCH_1);
3018 gen_insn(INSN_FP_CVT, op_size, OP_SIZE_4, 0);
3019 gen_one(FR_SCRATCH_2);
3021 gen_insn(INSN_FP_CMP, OP_SIZE_4, 0, 1);
3022 gen_one(FR_SCRATCH_1);
3023 gen_one(FR_SCRATCH_2);
3024 #if defined(ARCH_ARM32)
3025 gen_insn(INSN_FP_TO_INT_FLAGS, 0, 0, 1);
3027 gen_insn(INSN_JMP_COND, op_size, FP_COND_P, 0);
3028 gen_four(label_ovf);
3029 g(gen_frame_set_cond(ctx, op_size, false, fp_alu, slot_r));
3035 return gen_alu_typed_upcall(ctx, upc, real_type, slot_1, slot_2, slot_r, label_ovf);
3038 #define OP_IS_ROUND(alu) ((alu) == FP_ALU1_ROUND || (alu) == FP_ALU1_FLOOR || (alu) == FP_ALU1_CEIL || (alu) == FP_ALU1_TRUNC)
3040 static bool attr_w gen_fp_alu1(struct codegen_context *ctx, unsigned real_type, unsigned op, uint32_t label_ovf, frame_t slot_1, frame_t slot_r)
3042 unsigned attr_unused fp_alu;
3044 unsigned attr_unused op_size = real_type_to_op_size(real_type);
3045 unsigned reg1, target;
3047 case OPCODE_REAL_OP_neg:
3048 case OPCODE_REAL_OP_neg_alt1:
3049 case OPCODE_REAL_OP_neg_alt2: fp_alu = FP_ALU1_NEG; upc = offsetof(struct cg_upcall_vector_s, REAL_unary_neg_real16_t); label_ovf = 0; goto do_alu;
3050 case OPCODE_REAL_OP_sqrt:
3051 case OPCODE_REAL_OP_sqrt_alt1:
3052 case OPCODE_REAL_OP_sqrt_alt2: fp_alu = FP_ALU1_SQRT; upc = offsetof(struct cg_upcall_vector_s, REAL_unary_sqrt_real16_t); label_ovf = 0; goto do_alu;
3053 case OPCODE_REAL_OP_round: fp_alu = FP_ALU1_ROUND; upc = offsetof(struct cg_upcall_vector_s, REAL_unary_round_real16_t); label_ovf = 0; goto do_alu;
3054 case OPCODE_REAL_OP_floor: fp_alu = FP_ALU1_FLOOR; upc = offsetof(struct cg_upcall_vector_s, REAL_unary_floor_real16_t); label_ovf = 0; goto do_alu;
3055 case OPCODE_REAL_OP_ceil: fp_alu = FP_ALU1_CEIL; upc = offsetof(struct cg_upcall_vector_s, REAL_unary_ceil_real16_t); label_ovf = 0; goto do_alu;
3056 case OPCODE_REAL_OP_trunc: fp_alu = FP_ALU1_TRUNC; upc = offsetof(struct cg_upcall_vector_s, REAL_unary_trunc_real16_t); label_ovf = 0; goto do_alu;
3057 case OPCODE_REAL_OP_to_int:
3058 case OPCODE_REAL_OP_to_int_alt1:
3059 case OPCODE_REAL_OP_to_int_alt2: upc = offsetof(struct cg_upcall_vector_s, REAL_unary_to_int_real16_t); goto do_to_int;
3060 case OPCODE_REAL_OP_from_int:
3061 case OPCODE_REAL_OP_from_int_alt1:
3062 case OPCODE_REAL_OP_from_int_alt2: upc = offsetof(struct cg_upcall_vector_s, REAL_unary_from_int_real16_t); label_ovf = 0; goto do_from_int;
3063 case OPCODE_REAL_OP_is_exception:
3064 case OPCODE_REAL_OP_is_exception_alt1:
3065 case OPCODE_REAL_OP_is_exception_alt2: upc = offsetof(struct cg_upcall_vector_s, REAL_unary_is_exception_real16_t); label_ovf = 0; goto do_is_exception;
3066 default: upc = offsetof(struct cg_upcall_vector_s, REAL_unary_cbrt_real16_t) + (op - OPCODE_REAL_OP_cbrt) * TYPE_REAL_N * sizeof(void (*)(void)); label_ovf = 0; goto do_upcall;
3070 if ((SUPPORTED_FP >> real_type) & 1 && (
3071 #if defined(ARCH_ALPHA)
3072 fp_alu == FP_ALU1_NEG ||
3073 (fp_alu == FP_ALU1_SQRT && cpu_test_feature(CPU_FEATURE_fix)) ||
3074 #elif defined(ARCH_ARM32)
3075 fp_alu == FP_ALU1_NEG ||
3076 fp_alu == FP_ALU1_SQRT ||
3077 #elif defined(ARCH_ARM64)
3079 #elif defined(ARCH_IA64)
3080 fp_alu == FP_ALU1_NEG ||
3081 #elif defined(ARCH_LOONGARCH64)
3082 fp_alu == FP_ALU1_NEG ||
3083 fp_alu == FP_ALU1_SQRT ||
3084 fp_alu == FP_ALU1_ROUND ||
3085 #elif defined(ARCH_MIPS)
3086 fp_alu == FP_ALU1_NEG ||
3087 (fp_alu == FP_ALU1_SQRT && MIPS_HAS_SQRT) ||
3088 #elif defined(ARCH_PARISC)
3089 (fp_alu == FP_ALU1_NEG && PA_20) ||
3090 fp_alu == FP_ALU1_SQRT ||
3091 #elif defined(ARCH_POWER)
3092 fp_alu == FP_ALU1_NEG ||
3093 (fp_alu == FP_ALU1_SQRT && cpu_test_feature(CPU_FEATURE_p2) && real_type != 4) ||
3094 #elif defined(ARCH_S390)
3096 #elif defined(ARCH_SPARC)
3097 fp_alu == FP_ALU1_NEG ||
3098 fp_alu == FP_ALU1_SQRT ||
3099 #elif defined(ARCH_RISCV64)
3100 fp_alu == FP_ALU1_NEG ||
3101 fp_alu == FP_ALU1_SQRT ||
3102 #elif defined(ARCH_X86)
3103 fp_alu == FP_ALU1_SQRT ||
3104 (OP_IS_ROUND(fp_alu) && cpu_test_feature(CPU_FEATURE_sse41)) ||
3107 #if defined(ARCH_S390)
3108 if (op_size <= OP_SIZE_8 && (size_t)slot_1 * slot_size < 4096 && fp_alu == FP_ALU1_SQRT) {
3109 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, FR_SCRATCH_1);
3110 if (slot_is_register(ctx, slot_1)) {
3111 gen_insn(INSN_FP_ALU1, op_size, fp_alu, 0);
3113 gen_one(ctx->registers[slot_1]);
3114 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
3116 g(gen_address(ctx, R_FRAME, (size_t)slot_1 * slot_size, IMM_PURPOSE_VLDR_VSTR_OFFSET, op_size));
3117 gen_insn(INSN_FP_ALU1, op_size, fp_alu, 0);
3119 gen_address_offset();
3120 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
3125 g(gen_frame_get(ctx, op_size, zero_x, slot_1, FR_SCRATCH_1, ®1));
3126 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, FR_SCRATCH_2);
3127 gen_insn(INSN_FP_ALU1, op_size, fp_alu, 0);
3130 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
3133 #ifdef SUPPORTED_FP_X87
3134 if ((SUPPORTED_FP_X87 >> real_type) & 1) {
3135 if (fp_alu == FP_ALU1_NEG) {
3136 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_1));
3137 gen_insn(INSN_X87_FCHS, op_size, 0, 0);
3138 g(gen_frame_store_x87(ctx, INSN_X87_FSTP, op_size, slot_r));
3140 } else if (fp_alu == FP_ALU1_SQRT) {
3141 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_1));
3142 gen_insn(INSN_X87_FSQRT, op_size, 0, 0);
3143 g(gen_frame_store_x87(ctx, INSN_X87_FSTP, op_size, slot_r));
3145 } else if (fp_alu == FP_ALU1_ROUND) {
3146 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_1));
3147 gen_insn(INSN_X87_FRNDINT, op_size, 0, 0);
3148 g(gen_frame_store_x87(ctx, INSN_X87_FSTP, op_size, slot_r));
3153 #ifdef SUPPORTED_FP_HALF_CVT
3154 if ((SUPPORTED_FP_HALF_CVT >> real_type) & 1 && (
3155 #if defined(ARCH_ARM32)
3156 fp_alu == FP_ALU1_NEG ||
3157 fp_alu == FP_ALU1_SQRT ||
3158 #elif defined(ARCH_ARM64)
3160 #elif defined(ARCH_X86)
3161 fp_alu == FP_ALU1_SQRT ||
3162 (OP_IS_ROUND(fp_alu) && cpu_test_feature(CPU_FEATURE_sse41)) ||
3165 g(gen_frame_get(ctx, op_size, zero_x, slot_1, FR_SCRATCH_1, ®1));
3166 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, FR_SCRATCH_1);
3167 gen_insn(INSN_FP_CVT, op_size, OP_SIZE_4, 0);
3170 gen_insn(INSN_FP_ALU1, OP_SIZE_4, fp_alu, 0);
3173 gen_insn(INSN_FP_CVT, OP_SIZE_4, op_size, 0);
3176 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
3183 if ((SUPPORTED_FP >> real_type) & 1
3184 #if defined(ARCH_ALPHA)
3185 && OS_SUPPORTS_TRAPS
3187 #if defined(ARCH_MIPS)
3191 g(gen_frame_get(ctx, op_size, zero_x, slot_1, FR_SCRATCH_1, ®1));
3194 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
3195 #if defined(ARCH_X86)
3196 gen_insn(OP_SIZE_INT == OP_SIZE_4 ? INSN_FP_TO_INT32 : INSN_FP_TO_INT64, op_size, 0, 0);
3200 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, OP_SIZE_INT, target, sign_bit(uint_default_t), COND_E, label_ovf));
3202 g(gen_frame_store(ctx, OP_SIZE_INT, slot_r, 0, target));
3205 #if defined(ARCH_ARM) || defined(ARCH_LOONGARCH64) || defined(ARCH_MIPS)
3206 #if defined(ARCH_ARM)
3207 gen_insn(INSN_FP_CMP, op_size, 0, 1);
3210 #if defined(ARCH_ARM32)
3211 gen_insn(INSN_FP_TO_INT_FLAGS, 0, 0, 1);
3213 gen_insn(INSN_JMP_COND, op_size, FP_COND_P, 0);
3214 gen_four(label_ovf);
3216 gen_insn(INSN_FP_CMP_COND, op_size, FP_COND_P, 1);
3220 gen_insn(INSN_JMP_FP_TEST, 0, FP_COND_P, 0);
3221 gen_four(label_ovf);
3223 #if defined(ARCH_ARM32) || defined(ARCH_LOONGARCH64) || defined(ARCH_MIPS)
3224 gen_insn(OP_SIZE_INT == OP_SIZE_4 ? INSN_FP_TO_INT32 : INSN_FP_TO_INT64, op_size, 0, 0);
3225 gen_one(FR_SCRATCH_1);
3228 g(gen_mov(ctx, OP_SIZE_INT, target, FR_SCRATCH_1));
3230 gen_insn(OP_SIZE_INT == OP_SIZE_4 ? INSN_FP_TO_INT32 : INSN_FP_TO_INT64, op_size, 0, 0);
3234 g(gen_imm(ctx, (int_default_t)(sign_bit(uint_default_t) + 1), IMM_PURPOSE_ADD, OP_SIZE_INT));
3235 gen_insn(INSN_ALU, OP_SIZE_INT, ALU_ADD, ALU_WRITES_FLAGS(OP_SIZE_INT, ALU_ADD, false, is_imm(), ctx->const_imm));
3236 gen_one(R_SCRATCH_2);
3240 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, OP_SIZE_INT, R_SCRATCH_2, 1, COND_BE, label_ovf));
3242 g(gen_frame_store(ctx, OP_SIZE_INT, slot_r, 0, target));
3245 #if defined(ARCH_IA64)
3246 gen_insn(INSN_FP_TO_INT64, op_size, 0, 0);
3247 gen_one(FR_SCRATCH_1);
3250 g(gen_mov(ctx, OP_SIZE_NATIVE, target, FR_SCRATCH_1));
3252 if (OP_SIZE_INT == OP_SIZE_4) {
3253 g(gen_extend(ctx, OP_SIZE_4, sign_x, R_SCRATCH_2, target));
3254 g(gen_cmp_test_jmp(ctx, INSN_CMP, OP_SIZE_NATIVE, target, R_SCRATCH_2, COND_NE, label_ovf));
3256 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, OP_SIZE_NATIVE, target, sign_bit(uint64_t), COND_E, label_ovf));
3259 g(gen_frame_store(ctx, OP_SIZE_INT, slot_r, 0, target));
3262 #if defined(ARCH_PARISC) || defined(ARCH_POWER) || defined(ARCH_SPARC)
3263 #if defined(ARCH_POWER)
3264 if (!cpu_test_feature(CPU_FEATURE_ppc))
3266 if (OP_SIZE_INT == OP_SIZE_4)
3269 gen_insn(OP_SIZE_INT == OP_SIZE_4 ? INSN_FP_TO_INT32 : INSN_FP_TO_INT64, op_size, 0, 0);
3270 gen_one(FR_SCRATCH_1);
3273 g(gen_frame_store_raw(ctx, OP_SIZE_INT, slot_r, 0, FR_SCRATCH_1));
3274 if (slot_is_register(ctx, slot_r))
3275 g(unspill(ctx, slot_r));
3276 g(gen_frame_load(ctx, OP_SIZE_INT, garbage, slot_r, 0, false, target));
3278 g(gen_imm(ctx, sign_bit(uint_default_t) + 1, IMM_PURPOSE_ADD, OP_SIZE_INT));
3279 gen_insn(INSN_ALU, i_size(OP_SIZE_INT), ALU_ADD, ALU_WRITES_FLAGS(i_size(OP_SIZE_INT), ALU_ADD, false, is_imm(), ctx->const_imm));
3280 gen_one(R_SCRATCH_2);
3284 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, OP_SIZE_INT, R_SCRATCH_2, 1, COND_BE, label_ovf));
3288 #if defined(ARCH_ALPHA)
3289 gen_insn(INSN_FP_TO_INT64_TRAP, op_size, 0, 0);
3290 gen_one(FR_SCRATCH_2);
3292 gen_four(label_ovf);
3294 if (OP_SIZE_INT == OP_SIZE_4) {
3295 gen_insn(INSN_FP_INT64_TO_INT32_TRAP, 0, 0, 0);
3296 gen_one(FR_SCRATCH_3);
3297 gen_one(FR_SCRATCH_2);
3298 gen_four(label_ovf);
3299 g(gen_frame_store_raw(ctx, OP_SIZE_INT, slot_r, 0, FR_SCRATCH_3));
3301 g(gen_frame_store_raw(ctx, OP_SIZE_INT, slot_r, 0, FR_SCRATCH_2));
3303 if (slot_is_register(ctx, slot_r))
3304 g(unspill(ctx, slot_r));
3307 #if defined(ARCH_S390)
3308 gen_insn(OP_SIZE_INT == OP_SIZE_4 ? INSN_FP_TO_INT32 : INSN_FP_TO_INT64, op_size, 0, 1);
3312 gen_insn(INSN_JMP_COND, op_size, FP_COND_P, 0);
3313 gen_four(label_ovf);
3315 g(gen_frame_store(ctx, OP_SIZE_INT, slot_r, 0, target));
3318 #if defined(ARCH_RISCV64)
3319 gen_insn(OP_SIZE_INT == OP_SIZE_4 ? INSN_FP_TO_INT32 : INSN_FP_TO_INT64, op_size, 0, 0);
3323 g(gen_load_constant(ctx, R_SCRATCH_2, sign_bit(int_default_t)));
3325 g(gen_cmp_test_jmp(ctx, INSN_CMP, OP_SIZE_NATIVE, target, R_SCRATCH_2, COND_E, label_ovf));
3327 g(gen_imm(ctx, -1, IMM_PURPOSE_XOR, i_size(size)));
3328 gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_XOR, ALU_WRITES_FLAGS(OP_SIZE_NATIVE, ALU_XOR, false, is_imm(), ctx->const_imm));
3329 gen_one(R_SCRATCH_2);
3330 gen_one(R_SCRATCH_2);
3333 g(gen_cmp_test_jmp(ctx, INSN_CMP, OP_SIZE_NATIVE, target, R_SCRATCH_2, COND_E, label_ovf));
3335 g(gen_frame_store(ctx, OP_SIZE_INT, slot_r, 0, target));
3339 #ifdef SUPPORTED_FP_X87
3340 if ((SUPPORTED_FP_X87 >> real_type) & 1) {
3341 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_1));
3343 if (likely(cpu_test_feature(CPU_FEATURE_sse3))) {
3344 g(gen_frame_store_x87(ctx, INSN_X87_FISTTP, OP_SIZE_INT, slot_r));
3346 gen_insn(INSN_PUSH, OP_SIZE_NATIVE, 0, 0);
3350 gen_insn(INSN_X87_FLDCW, 0, 0, 0);
3351 gen_one(ARG_ADDRESS_1);
3355 g(gen_frame_store_x87(ctx, INSN_X87_FISTP, OP_SIZE_INT, slot_r));
3357 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
3358 gen_one(ARG_ADDRESS_1);
3364 gen_insn(INSN_X87_FLDCW, 0, 0, 0);
3365 gen_one(ARG_ADDRESS_1);
3369 gen_insn(INSN_ALU, i_size(OP_SIZE_ADDRESS), ALU_ADD, 1);
3373 gen_eight(1 << OP_SIZE_NATIVE);
3375 if (slot_is_register(ctx, slot_r))
3376 g(unspill(ctx, slot_r));
3377 g(gen_frame_load(ctx, OP_SIZE_INT, garbage, slot_r, 0, false, R_SCRATCH_1));
3379 g(gen_cmp_test_imm_jmp(ctx, INSN_CMP, OP_SIZE_INT, R_SCRATCH_1, sign_bit(int_default_t), COND_E, label_ovf));
3384 #ifdef SUPPORTED_FP_HALF_CVT
3385 if ((SUPPORTED_FP_HALF_CVT >> real_type) & 1) {
3386 g(gen_frame_get(ctx, op_size, zero_x, slot_1, FR_SCRATCH_1, ®1));
3387 gen_insn(INSN_FP_CVT, op_size, OP_SIZE_4, 0);
3388 gen_one(FR_SCRATCH_1);
3390 reg1 = FR_SCRATCH_1;
3392 op_size = real_type_to_op_size(real_type);
3399 if ((SUPPORTED_FP >> real_type) & 1) {
3400 #if defined(ARCH_ALPHA) || defined(ARCH_ARM32) || defined(ARCH_LOONGARCH64) || defined(ARCH_MIPS) || defined(ARCH_PARISC) || defined(ARCH_POWER) || defined(ARCH_SPARC)
3401 int int_op_size = OP_SIZE_INT;
3402 #if defined(ARCH_POWER)
3403 if (int_op_size == OP_SIZE_4)
3405 if (op_size == OP_SIZE_4 && !cpu_test_feature(CPU_FEATURE_v206))
3407 if (op_size == OP_SIZE_8 && !cpu_test_feature(CPU_FEATURE_ppc))
3410 if (slot_is_register(ctx, slot_1))
3411 g(spill(ctx, slot_1));
3412 g(gen_frame_load_raw(ctx, int_op_size, zero_x, slot_1, 0, false, FR_SCRATCH_1));
3413 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, FR_SCRATCH_2);
3414 #if defined(ARCH_ALPHA)
3415 if (OP_SIZE_INT == OP_SIZE_4) {
3416 gen_insn(INSN_MOVSX, OP_SIZE_4, 0, 0);
3417 gen_one(FR_SCRATCH_1);
3418 gen_one(FR_SCRATCH_1);
3420 int_op_size = OP_SIZE_8;
3423 gen_insn(int_op_size == OP_SIZE_4 ? INSN_FP_FROM_INT32 : INSN_FP_FROM_INT64, op_size, 0, 0);
3425 gen_one(FR_SCRATCH_1);
3427 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
3429 #elif defined(ARCH_IA64)
3430 g(gen_frame_get(ctx, OP_SIZE_INT, sign_x, slot_1, R_SCRATCH_1, ®1));
3431 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, FR_SCRATCH_1);
3433 g(gen_mov(ctx, OP_SIZE_NATIVE, target, reg1));
3435 gen_insn(INSN_FP_FROM_INT64, op_size, 0, 0);
3439 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
3442 g(gen_frame_get(ctx, OP_SIZE_INT, garbage, slot_1, R_SCRATCH_1, ®1));
3443 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, FR_SCRATCH_1);
3445 gen_insn(OP_SIZE_INT == OP_SIZE_4 ? INSN_FP_FROM_INT32 : INSN_FP_FROM_INT64, op_size, 0, 0);
3449 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
3453 #ifdef SUPPORTED_FP_X87
3454 if ((SUPPORTED_FP_X87 >> real_type) & 1) {
3455 if (slot_is_register(ctx, slot_1))
3456 g(spill(ctx, slot_1));
3457 g(gen_frame_load_x87(ctx, INSN_X87_FILD, OP_SIZE_INT, 0, slot_1));
3458 g(gen_frame_store_x87(ctx, INSN_X87_FSTP, op_size, slot_r));
3462 #ifdef SUPPORTED_FP_HALF_CVT
3463 if ((SUPPORTED_FP_HALF_CVT >> real_type) & 1) {
3464 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, FR_SCRATCH_1);
3465 #if defined(ARCH_ARM32)
3466 g(gen_frame_get(ctx, OP_SIZE_INT, zero_x, slot_1, FR_SCRATCH_1, ®1));
3468 gen_insn(INSN_FP_FROM_INT32, OP_SIZE_4, 0, 0);
3472 g(gen_frame_get(ctx, OP_SIZE_INT, garbage, slot_1, R_SCRATCH_1, ®1));
3473 gen_insn(OP_SIZE_INT == OP_SIZE_4 ? INSN_FP_FROM_INT32 : INSN_FP_FROM_INT64, OP_SIZE_4, 0, 0);
3477 gen_insn(INSN_FP_CVT, OP_SIZE_4, op_size, 0);
3480 g(gen_frame_store(ctx, op_size, slot_r, 0, target));
3487 if ((SUPPORTED_FP >> real_type) & 1) {
3488 g(gen_frame_get(ctx, op_size, zero_x, slot_1, FR_SCRATCH_1, ®1));
3489 target = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
3490 #if defined(ARCH_ALPHA)
3491 gen_insn(INSN_FP_CMP_UNORDERED_DEST_REG, op_size, 0, 0);
3492 gen_one(FR_SCRATCH_2);
3493 gen_one(FR_SCRATCH_1);
3496 if (!cpu_test_feature(CPU_FEATURE_fix)) {
3497 g(gen_frame_store_raw(ctx, OP_SIZE_4, slot_r, 0, FR_SCRATCH_2));
3498 g(gen_frame_load_raw(ctx, OP_SIZE_4, sign_x, slot_r, 0, false, target));
3500 g(gen_mov(ctx, OP_SIZE_4, target, FR_SCRATCH_2));
3503 g(gen_3address_rot_imm(ctx, OP_SIZE_NATIVE, ROT_SHR, target, target, 30, 0));
3505 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, target));
3508 #elif defined(ARCH_IA64)
3509 gen_insn(INSN_FP_CMP_DEST_REG, op_size, FP_COND_P, 0);
3510 gen_one(R_CMP_RESULT);
3514 g(gen_mov(ctx, OP_SIZE_NATIVE, target, R_CMP_RESULT));
3516 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, target));
3517 #elif defined(ARCH_LOONGARCH64) || defined(ARCH_MIPS) || defined(ARCH_PARISC)
3518 gen_insn(INSN_FP_CMP_COND, op_size, FP_COND_P, 1);
3522 gen_insn(INSN_FP_TEST_REG, OP_SIZE_NATIVE, FP_COND_P, 0);
3525 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, target));
3526 #elif defined(ARCH_RISCV64)
3527 gen_insn(INSN_FP_CMP_DEST_REG, op_size, FP_COND_E, 0);
3532 g(gen_imm(ctx, 1, IMM_PURPOSE_XOR, OP_SIZE_NATIVE));
3533 gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_XOR, ALU_WRITES_FLAGS(OP_SIZE_NATIVE, ALU_XOR, false, is_imm(), ctx->const_imm));
3538 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, target));
3540 gen_insn(INSN_FP_CMP, op_size, 0, 1);
3543 #if defined(ARCH_ARM32)
3544 gen_insn(INSN_FP_TO_INT_FLAGS, 0, 0, 1);
3546 g(gen_frame_set_cond(ctx, op_size, false, FP_COND_P, slot_r));
3550 #ifdef SUPPORTED_FP_X87
3551 if ((SUPPORTED_FP_X87 >> real_type) & 1) {
3552 g(gen_frame_load_x87(ctx, INSN_X87_FLD, op_size, 0, slot_1));
3553 if (likely(cpu_test_feature(CPU_FEATURE_cmov))) {
3554 gen_insn(INSN_X87_FCOMIP, op_size, 0, 0);
3557 g(gen_frame_set_cond(ctx, op_size, false, COND_P, slot_r));
3561 gen_insn(INSN_X87_FCOMP, op_size, 0, 0);
3564 gen_insn(INSN_X87_FNSTSW, 0, 0, 0);
3568 gen_insn(INSN_TEST, OP_SIZE_2, 0, 1);
3573 g(gen_frame_set_cond(ctx, op_size, false, COND_NE, slot_r));
3578 #ifdef SUPPORTED_FP_HALF_CVT
3579 if ((SUPPORTED_FP_HALF_CVT >> real_type) & 1) {
3580 g(gen_frame_get(ctx, op_size, zero_x, slot_1, FR_SCRATCH_1, ®1));
3581 gen_insn(INSN_FP_CVT, op_size, OP_SIZE_4, 0);
3582 gen_one(FR_SCRATCH_1);
3584 gen_insn(INSN_FP_CMP, OP_SIZE_4, 0, 1);
3585 gen_one(FR_SCRATCH_1);
3586 gen_one(FR_SCRATCH_1);
3587 #if defined(ARCH_ARM32)
3588 gen_insn(INSN_FP_TO_INT_FLAGS, 0, 0, 1);
3590 g(gen_frame_set_cond(ctx, op_size, false, FP_COND_P, slot_r));
3596 g(gen_alu_typed_upcall(ctx, upc, real_type, slot_1, NO_FRAME_T, slot_r, label_ovf));
3600 static bool attr_w gen_is_exception(struct codegen_context *ctx, frame_t slot_1, frame_t slot_r)
3602 uint32_t no_ex_label, escape_label;
3603 const struct type *type = get_type_of_local(ctx, slot_1);
3605 no_ex_label = alloc_label(ctx);
3606 if (unlikely(!no_ex_label))
3608 escape_label = alloc_escape_label(ctx);
3609 if (unlikely(!escape_label))
3612 if (TYPE_IS_FLAT(type))
3613 g(gen_test_1_jz_cached(ctx, slot_1, no_ex_label));
3615 g(gen_frame_load(ctx, OP_SIZE_SLOT, zero_x, slot_1, 0, false, R_SCRATCH_1));
3616 g(gen_ptr_is_thunk(ctx, R_SCRATCH_1, slot_1, escape_label));
3618 if (!TYPE_IS_FLAT(type)) {
3619 g(gen_compare_da_tag(ctx, R_SCRATCH_1, DATA_TAG_flat, COND_E, escape_label, R_SCRATCH_1));
3622 gen_label(no_ex_label);
3623 g(gen_frame_clear(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r));
3625 flag_set(ctx, slot_r, false);
3630 static bool attr_w gen_system_property(struct codegen_context *ctx, frame_t slot_1, frame_t slot_r)
3632 uint32_t escape_label;
3634 escape_label = alloc_escape_label(ctx);
3635 if (unlikely(!escape_label))
3638 g(gen_test_1_cached(ctx, slot_1, escape_label));
3640 g(gen_upcall_start(ctx, 1));
3642 g(gen_frame_load(ctx, OP_SIZE_INT, garbage, slot_1, 0, false, R_ARG0));
3643 g(gen_upcall_argument(ctx, 0));
3645 g(gen_upcall(ctx, offsetof(struct cg_upcall_vector_s, cg_upcall_ipret_system_property), 1));
3647 g(gen_frame_store(ctx, OP_SIZE_INT, slot_r, 0, R_RET0));
3649 flag_set(ctx, slot_1, false);
3650 flag_set(ctx, slot_r, false);
3655 static bool attr_w gen_alu_jmp(struct codegen_context *ctx, unsigned mode, unsigned op_size, unsigned op, frame_t slot_1, frame_t slot_2, int32_t jmp_offset, bool *failed)
3660 unsigned attr_unused reg2;
3662 *failed = true; return true;
3665 case MODE_FIXED: switch (op) {
3666 case OPCODE_FIXED_OP_equal: alu = COND_E; goto do_compare;
3667 case OPCODE_FIXED_OP_not_equal: alu = COND_NE; goto do_compare;
3668 case OPCODE_FIXED_OP_less: alu = COND_L; goto do_compare;
3669 case OPCODE_FIXED_OP_less_equal: alu = COND_LE; goto do_compare;
3670 case OPCODE_FIXED_OP_greater: alu = COND_G; goto do_compare;
3671 case OPCODE_FIXED_OP_greater_equal: alu = COND_GE; goto do_compare;
3672 case OPCODE_FIXED_OP_uless: alu = COND_B; goto do_compare;
3673 case OPCODE_FIXED_OP_uless_equal: alu = COND_BE; goto do_compare;
3674 case OPCODE_FIXED_OP_ugreater: alu = COND_A; goto do_compare;
3675 case OPCODE_FIXED_OP_ugreater_equal: alu = COND_AE; goto do_compare;
3676 case OPCODE_FIXED_OP_bt: *failed = true; return true;
3677 default: internal(file_line, "gen_alu_jmp: unsupported fixed operation %u", op);
3679 case MODE_INT: switch (op) {
3680 case OPCODE_INT_OP_equal: alu = COND_E; goto do_compare;
3681 case OPCODE_INT_OP_not_equal: alu = COND_NE; goto do_compare;
3682 case OPCODE_INT_OP_less: alu = COND_L; goto do_compare;
3683 case OPCODE_INT_OP_less_equal: alu = COND_LE; goto do_compare;
3684 case OPCODE_INT_OP_greater: alu = COND_G; goto do_compare;
3685 case OPCODE_INT_OP_greater_equal: alu = COND_GE; goto do_compare;
3686 case OPCODE_INT_OP_bt: *failed = true; return true;
3687 default: internal(file_line, "gen_alu_jmp: unsupported int operation %u", op);
3689 case MODE_BOOL: switch (op) {
3690 case OPCODE_BOOL_OP_and: alu = ALU_AND; mode = MODE_FIXED; goto do_alu;
3691 case OPCODE_BOOL_OP_or: alu = ALU_OR; mode = MODE_FIXED; goto do_alu;
3692 case OPCODE_BOOL_OP_equal: alu = COND_E; mode = MODE_FIXED; goto do_compare;
3693 case OPCODE_BOOL_OP_not_equal: alu = COND_NE; mode = MODE_FIXED; goto do_compare;
3694 case OPCODE_BOOL_OP_less: alu = COND_L; mode = MODE_FIXED; goto do_compare;
3695 case OPCODE_BOOL_OP_less_equal: alu = COND_LE; mode = MODE_FIXED; goto do_compare;
3696 case OPCODE_BOOL_OP_greater: alu = COND_G; mode = MODE_FIXED; goto do_compare;
3697 case OPCODE_BOOL_OP_greater_equal: alu = COND_GE; mode = MODE_FIXED; goto do_compare;
3698 default: internal(file_line, "gen_alu_jmp: unsupported bool operation %u", op);
3701 internal(file_line, "gen_alu_jmp: unsupported mode %u", mode);
3703 bool attr_unused logical;
3704 if (unlikely(op_size > OP_SIZE_NATIVE)) {
3708 if (slot_is_register(ctx, slot_2) && !slot_is_register(ctx, slot_1)) {
3713 case COND_L: alu = COND_G; break;
3714 case COND_LE: alu = COND_GE; break;
3715 case COND_G: alu = COND_L; break;
3716 case COND_GE: alu = COND_LE; break;
3717 case COND_B: alu = COND_A; break;
3718 case COND_BE: alu = COND_AE; break;
3719 case COND_A: alu = COND_B; break;
3720 case COND_AE: alu = COND_BE; break;
3723 ex = op_size == i_size_cmp(op_size) + (unsigned)zero ? garbage : alu == COND_L || alu == COND_LE || alu == COND_G || alu == COND_GE || ARCH_PREFERS_SX(op_size) ? sign_x : zero_x;
3724 g(gen_frame_get(ctx, op_size, ex, slot_1, R_SCRATCH_1, ®1));
3725 if (ARCH_HAS_JMP_2REGS(alu)) {
3726 g(gen_frame_get(ctx, op_size, ex, slot_2, R_SCRATCH_2, ®2));
3727 g(gen_jump(ctx, jmp_offset, i_size_cmp(op_size), alu ^ 1, reg1, reg2));
3731 logical = COND_IS_LOGICAL(alu ^ 1);
3732 g(gen_frame_load_cmp(ctx, op_size, logical, ex, false, slot_2, 0, false, reg1));
3733 g(gen_jump(ctx, jmp_offset, op_size, alu ^ 1, -1U, -1U));
3735 g(gen_frame_get(ctx, op_size, ex, slot_2, R_SCRATCH_2, ®2));
3736 g(gen_cmp_dest_reg(ctx, op_size, reg1, reg2, R_CMP_RESULT, 0, alu));
3737 g(gen_jump(ctx, jmp_offset, OP_SIZE_NATIVE, COND_E, R_CMP_RESULT, -1U));
3742 if (slot_is_register(ctx, slot_2) && !slot_is_register(ctx, slot_1)) {
3747 ex = op_size == i_size(op_size) + (unsigned)zero ? garbage : ARCH_PREFERS_SX(op_size) ? sign_x : zero_x;
3748 g(gen_frame_get(ctx, op_size, ex, slot_1, R_SCRATCH_1, ®1));
3749 #if defined(ARCH_X86)
3750 if (alu == ALU_AND && !slot_is_register(ctx, slot_2)) {
3751 g(gen_address(ctx, R_FRAME, (size_t)slot_2 * slot_size, IMM_PURPOSE_LDR_OFFSET, op_size));
3752 gen_insn(INSN_TEST, i_size(op_size), 0, 1);
3754 gen_address_offset();
3755 g(gen_jump(ctx, jmp_offset, op_size, COND_E, -1U, -1U));
3759 g(gen_frame_get(ctx, op_size, ex, slot_2, R_SCRATCH_2, ®2));
3760 #if ARCH_HAS_FLAGS && !defined(ARCH_S390)
3761 if (alu == ALU_AND) {
3762 gen_insn(INSN_TEST, i_size(op_size), 0, 1);
3765 g(gen_jump(ctx, jmp_offset, op_size, COND_E, -1U, -1U));
3769 #if defined(ARCH_ARM64)
3774 g(gen_3address_alu(ctx, i_size(op_size), alu, R_SCRATCH_1, reg1, reg2, 1));
3775 g(gen_jump(ctx, jmp_offset, i_size(op_size), COND_E, -1U, -1U));
3780 g(gen_3address_alu(ctx, i_size(op_size), alu, R_SCRATCH_1, reg1, reg2, 0));
3781 g(gen_jump(ctx, jmp_offset, i_size(op_size), COND_E, R_SCRATCH_1, -1U));
3786 static bool attr_w gen_fp_alu_jmp(struct codegen_context *ctx, unsigned real_type, unsigned op, uint32_t label_ovf, frame_t slot_1, frame_t slot_2, int32_t jmp_offset, bool *failed)
3788 unsigned attr_unused fp_alu;
3789 unsigned attr_unused op_size = real_type_to_op_size(real_type);
3790 unsigned reg1, reg2;
3791 unsigned attr_unused target;
3793 case OPCODE_REAL_OP_equal:
3794 case OPCODE_REAL_OP_equal_alt1:
3795 case OPCODE_REAL_OP_equal_alt2: fp_alu = FP_COND_E; goto do_cmp;
3796 case OPCODE_REAL_OP_not_equal:
3797 case OPCODE_REAL_OP_not_equal_alt1:
3798 case OPCODE_REAL_OP_not_equal_alt2: fp_alu = FP_COND_NE; goto do_cmp;
3799 case OPCODE_REAL_OP_less:
3800 case OPCODE_REAL_OP_less_alt1:
3801 case OPCODE_REAL_OP_less_alt2: fp_alu = FP_COND_B; goto do_cmp;
3802 case OPCODE_REAL_OP_less_equal:
3803 case OPCODE_REAL_OP_less_equal_alt1:
3804 case OPCODE_REAL_OP_less_equal_alt2: fp_alu = FP_COND_BE; goto do_cmp;
3805 case OPCODE_REAL_OP_greater:
3806 case OPCODE_REAL_OP_greater_alt1:
3807 case OPCODE_REAL_OP_greater_alt2: fp_alu = FP_COND_A; goto do_cmp;
3808 case OPCODE_REAL_OP_greater_equal:
3809 case OPCODE_REAL_OP_greater_equal_alt1:
3810 case OPCODE_REAL_OP_greater_equal_alt2: fp_alu = FP_COND_AE; goto do_cmp;
3811 default: internal(file_line, "gen_fp_alu_jmp: unsupported operation %u", op);
3815 if ((SUPPORTED_FP >> real_type) & 1
3816 #if defined(ARCH_ALPHA)
3817 && OS_SUPPORTS_TRAPS && cpu_test_feature(CPU_FEATURE_fix)
3820 g(gen_frame_get(ctx, op_size, zero_x, slot_1, FR_SCRATCH_1, ®1));
3821 g(gen_frame_get(ctx, op_size, zero_x, slot_2, FR_SCRATCH_2, ®2));
3822 target = R_SCRATCH_1;
3823 #if defined(ARCH_ALPHA)
3824 gen_insn(INSN_FP_CMP_DEST_REG_TRAP, op_size, fp_alu == FP_COND_NE ? FP_COND_E : fp_alu, 0);
3825 gen_one(FR_SCRATCH_3);
3828 gen_four(label_ovf);
3830 g(gen_mov(ctx, OP_SIZE_4, target, FR_SCRATCH_3));
3832 if (fp_alu == FP_COND_NE) {
3833 g(gen_jump(ctx, jmp_offset, OP_SIZE_NATIVE, COND_NE, target, -1U));
3835 g(gen_jump(ctx, jmp_offset, OP_SIZE_NATIVE, COND_E, target, -1U));
3839 #elif defined(ARCH_IA64)
3840 gen_insn(INSN_FP_CMP_DEST_REG, op_size, FP_COND_P, 0);
3841 gen_one(R_CMP_RESULT);
3845 gen_insn(INSN_JMP_REG, OP_SIZE_NATIVE, COND_NE, 0);
3846 gen_one(R_CMP_RESULT);
3847 gen_four(label_ovf);
3849 gen_insn(INSN_FP_CMP_DEST_REG, op_size, fp_alu, 0);
3850 gen_one(R_CMP_RESULT);
3854 g(gen_jump(ctx, jmp_offset, OP_SIZE_NATIVE, COND_E, R_CMP_RESULT, -1U));
3857 #elif defined(ARCH_LOONGARCH64) || defined(ARCH_MIPS) || defined(ARCH_PARISC)
3858 gen_insn(INSN_FP_CMP_COND, op_size, FP_COND_P, 1);
3862 gen_insn(INSN_JMP_FP_TEST, 0, FP_COND_P, 0);
3863 gen_four(label_ovf);
3865 gen_insn(INSN_FP_CMP_COND, op_size, fp_alu ^ 1, 1);
3869 g(gen_jump(ctx, jmp_offset, OP_SIZE_NATIVE, fp_alu ^ 1, -1U, -1U));
3872 #elif defined(ARCH_RISCV64)
3873 gen_insn(INSN_FP_CMP_DEST_REG, op_size, FP_COND_E, 0);
3874 gen_one(R_SCRATCH_1);
3878 gen_insn(INSN_FP_CMP_DEST_REG, op_size, FP_COND_E, 0);
3879 gen_one(R_SCRATCH_2);
3883 g(gen_3address_alu(ctx, OP_SIZE_NATIVE, ALU_AND, R_SCRATCH_1, R_SCRATCH_1, R_SCRATCH_2, 0));
3885 g(gen_jmp_on_zero(ctx, OP_SIZE_NATIVE, R_SCRATCH_1, COND_E, label_ovf));
3887 gen_insn(INSN_FP_CMP_DEST_REG, op_size, fp_alu == FP_COND_NE ? FP_COND_E : fp_alu, 0);
3892 if (fp_alu == FP_COND_NE) {
3893 g(gen_jump(ctx, jmp_offset, OP_SIZE_NATIVE, COND_NE, target, -1U));
3895 g(gen_jump(ctx, jmp_offset, OP_SIZE_NATIVE, COND_E, target, -1U));
3899 gen_insn(INSN_FP_CMP, op_size, 0, 1);
3902 #if defined(ARCH_ARM32)
3903 gen_insn(INSN_FP_TO_INT_FLAGS, 0, 0, 1);
3905 gen_insn(INSN_JMP_COND, op_size, FP_COND_P, 0);
3906 gen_four(label_ovf);
3907 g(gen_jump(ctx, jmp_offset, op_size, fp_alu ^ 1, -1U, -1U));