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 #define frame_offs(x) ((ssize_t)offsetof(struct frame_struct, x) - (ssize_t)frame_offset)
21 #if defined(C_LITTLE_ENDIAN)
22 #define lo_word(size) (0)
23 #define hi_word(size) ((size_t)1 << (size))
24 #elif defined(C_BIG_ENDIAN)
25 #define lo_word(size) ((size_t)1 << (size))
26 #define hi_word(size) (0)
32 static bool attr_w gen_frame_load_raw(struct codegen_context *ctx, unsigned size, enum extend ex, frame_t slot, int64_t offset, bool dual, unsigned reg);
33 static bool attr_w gen_frame_store_raw(struct codegen_context *ctx, unsigned size, frame_t slot, int64_t offset, unsigned reg);
36 static const struct type *get_type_of_local(struct codegen_context *ctx, frame_t pos)
39 const struct data *function = ctx->fn;
40 t = da(function,function)->local_variables[pos].type;
42 TYPE_TAG_VALIDATE(t->tag);
46 static unsigned real_type_to_op_size(unsigned real_type)
49 case 0: return OP_SIZE_2;
50 case 1: return OP_SIZE_4;
51 case 2: return OP_SIZE_8;
52 case 3: return OP_SIZE_10;
53 case 4: return OP_SIZE_16;
55 internal(file_line, "real_type_to_op_size: invalid type %u", real_type);
60 static unsigned spill_size(const struct type *t)
62 if (!TYPE_TAG_IS_BUILTIN(t->tag)) {
64 } else if (TYPE_TAG_IS_REAL(t->tag)) {
65 return real_type_to_op_size(TYPE_TAG_IDX_REAL(t->tag));
67 return log_2(t->size);
71 static bool attr_w spill(struct codegen_context *ctx, frame_t v)
73 const struct type *t = get_type_of_local(ctx, v);
74 g(gen_frame_store_raw(ctx, spill_size(t), v, 0, ctx->registers[v]));
78 static bool attr_w unspill(struct codegen_context *ctx, frame_t v)
80 const struct type *t = get_type_of_local(ctx, v);
81 enum extend ex = garbage;
82 if (t->tag == TYPE_TAG_flat_option)
84 else if (!TYPE_IS_FLAT(t))
86 g(gen_frame_load_raw(ctx, spill_size(t), ex, v, 0, false, ctx->registers[v]));
91 static bool attr_w gen_frame_address(struct codegen_context *ctx, frame_t slot, int64_t offset, unsigned reg)
93 offset += (size_t)slot * slot_size;
94 g(gen_3address_alu_imm(ctx, i_size(OP_SIZE_ADDRESS), ALU_ADD, reg, R_FRAME, offset, 0));
98 static int64_t get_constant(unsigned size, enum extend ex, frame_t slot, int64_t offset, bool dual)
103 ex = ARCH_PREFERS_SX(size) ? sign_x : zero_x;
106 if (unlikely(offset != 0))
108 c = frame_t_get_const(slot);
110 if (size == OP_SIZE_1) c &= 0xFFUL;
111 if (size == OP_SIZE_2) c &= 0xFFFFUL;
112 if (size == OP_SIZE_4) c &= 0xFFFFFFFFUL;
116 if (offset == (int64_t)lo_word(size))
117 return frame_t_get_const(slot);
118 if (offset == (int64_t)hi_word(size))
119 return frame_t_get_const(slot) < 0 ? -1 : 0;
121 internal(file_line, "get_constant: invalid offset %"PRIdMAX"", (intmax_t)offset);
125 static bool attr_w gen_frame_load_raw(struct codegen_context *ctx, unsigned size, enum extend ex, frame_t slot, int64_t offset, bool dual, unsigned reg)
128 if (frame_t_is_const(slot)) {
129 g(gen_load_constant(ctx, reg, get_constant(size, ex, slot, offset, dual)));
132 if (ex == garbage || ex == native) {
134 ex = ARCH_PREFERS_SX(size) ? sign_x : zero_x;
138 x_offset = offset + (size_t)slot * slot_size;
139 if (!ARCH_HAS_BWX && size < OP_SIZE_4) {
140 g(gen_address(ctx, R_FRAME, x_offset, reg_is_fp(reg) ? IMM_PURPOSE_VLDR_VSTR_OFFSET : IMM_PURPOSE_LDR_SX_OFFSET, OP_SIZE_4));
141 gen_insn(INSN_MOVSX, OP_SIZE_4, 0, 0);
143 gen_address_offset();
145 g(gen_extend(ctx, size, ex, reg, reg));
149 #if defined(ARCH_ALPHA)
150 if (size < OP_SIZE_4) {
151 g(gen_address(ctx, R_FRAME, x_offset, reg_is_fp(reg) ? IMM_PURPOSE_VLDR_VSTR_OFFSET : IMM_PURPOSE_LDR_OFFSET, size));
152 gen_insn(INSN_MOV, size, 0, 0);
154 gen_address_offset();
157 g(gen_extend(ctx, size, ex, reg, reg));
161 if (size == OP_SIZE_4 && !reg_is_fp(reg) && ex == zero_x) {
162 g(gen_frame_load_raw(ctx, size, sign_x, slot, offset, false, reg));
163 g(gen_extend(ctx, size, ex, reg, reg));
168 #if defined(ARCH_MIPS)
169 if (reg_is_fp(reg) && size == OP_SIZE_8 && !MIPS_HAS_LS_DOUBLE) {
170 #if defined(C_LITTLE_ENDIAN)
171 g(gen_frame_load_raw(ctx, OP_SIZE_4, zero_x, slot, offset, true, reg));
172 g(gen_frame_load_raw(ctx, OP_SIZE_4, zero_x, slot, offset + 4, true, reg + 1));
174 g(gen_frame_load_raw(ctx, OP_SIZE_4, zero_x, slot, offset, true, reg + 1));
175 g(gen_frame_load_raw(ctx, OP_SIZE_4, zero_x, slot, offset + 4, true, reg));
180 #if defined(ARCH_IA64) || defined(ARCH_PARISC)
182 g(gen_address(ctx, R_FRAME, x_offset, IMM_PURPOSE_LDR_OFFSET, size));
183 gen_insn(INSN_MOV, size, 0, 0);
185 gen_address_offset();
187 g(gen_extend(ctx, size, ex, reg, reg));
192 #if defined(ARCH_POWER)
193 if (size == OP_SIZE_1 && ex == sign_x) {
194 g(gen_address(ctx, R_FRAME, x_offset, IMM_PURPOSE_LDR_OFFSET, size));
195 gen_insn(INSN_MOV, size, 0, 0);
197 gen_address_offset();
199 g(gen_extend(ctx, size, ex, reg, reg));
204 #if defined(ARCH_S390)
205 if (size == OP_SIZE_1 && !cpu_test_feature(CPU_FEATURE_long_displacement)) {
206 g(gen_address(ctx, R_FRAME, x_offset, IMM_PURPOSE_LDR_OFFSET, size));
207 gen_insn(INSN_MOV_MASK, OP_SIZE_NATIVE, MOV_MASK_0_8, 0);
210 gen_address_offset();
212 g(gen_extend(ctx, size, ex, reg, reg));
216 if (size == OP_SIZE_16 && reg_is_fp(reg)) {
217 g(gen_frame_load_raw(ctx, OP_SIZE_8, zero_x, 0, x_offset, true, reg));
218 g(gen_frame_load_raw(ctx, OP_SIZE_8, zero_x, 0, x_offset + 8, true, reg + 2));
223 g(gen_address(ctx, R_FRAME, x_offset, reg_is_fp(reg) ? IMM_PURPOSE_VLDR_VSTR_OFFSET : ex ? IMM_PURPOSE_LDR_SX_OFFSET : IMM_PURPOSE_LDR_OFFSET, size));
224 gen_insn(unlikely(ex == sign_x) ? INSN_MOVSX : INSN_MOV, size, 0, 0);
226 gen_address_offset();
231 static bool attr_w gen_frame_load(struct codegen_context *ctx, unsigned size, enum extend ex, frame_t slot, int64_t offset, bool dual, unsigned reg)
233 ajla_assert_lo((slot >= MIN_USEABLE_SLOT && slot < function_n_variables(ctx->fn)) || frame_t_is_const(slot), (file_line, "gen_frame_load: invalid slot: %lu >= %lu", (unsigned long)slot, (unsigned long)function_n_variables(ctx->fn)));
234 if (slot_is_register(ctx, slot)) {
235 if (unlikely(offset != 0))
236 internal(file_line, "gen_frame_load: offset is non-zero: %"PRIdMAX"", (intmax_t)offset);
237 if (ex != garbage && size < OP_SIZE_NATIVE && !reg_is_fp(reg)) {
238 g(gen_extend(ctx, size, ex, reg, ctx->registers[slot]));
241 g(gen_mov(ctx, !reg_is_fp(reg) ? OP_SIZE_NATIVE : size, reg, ctx->registers[slot]));
245 g(gen_frame_load_raw(ctx, size, ex, slot, offset, dual, reg));
248 if (size < OP_SIZE_NATIVE && ex == garbage) {
250 g(gen_extend(ctx, size, zero_x, reg, reg));
251 mask = (rand()) | ((uint64_t)rand() << 31) | ((uint64_t)rand() << 62);
252 mask <<= 8ULL << size;
253 g(gen_imm(ctx, mask, IMM_PURPOSE_OR, OP_SIZE_NATIVE));
254 gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_OR, ALU_WRITES_FLAGS(OP_SIZE_NATIVE, ALU_OR, false, is_imm(), ctx->const_imm));
263 static bool attr_w gen_frame_get(struct codegen_context *ctx, unsigned size, enum extend ex, frame_t slot, unsigned reg, unsigned *dest)
265 const struct type *t;
266 if (frame_t_is_const(slot)) {
267 g(gen_frame_load(ctx, size, ex, slot, 0, false, reg));
271 t = get_type_of_local(ctx, slot);
272 ajla_assert_lo(slot >= MIN_USEABLE_SLOT && slot < function_n_variables(ctx->fn), (file_line, "gen_frame_get: invalid slot: %lu >= %lu", (unsigned long)slot, (unsigned long)function_n_variables(ctx->fn)));
273 if (slot_is_register(ctx, slot)) {
274 unsigned reg = ctx->registers[slot];
275 if (ex != garbage && size < OP_SIZE_NATIVE && !reg_is_fp(reg)) {
276 if (t->tag == TYPE_TAG_flat_option && size <= ARCH_BOOL_SIZE)
278 g(gen_extend(ctx, size, ex, reg, reg));
285 g(gen_frame_load(ctx, size, ex, slot, 0, false, reg));
288 if (size < OP_SIZE_NATIVE && ex == garbage && t->tag != TYPE_TAG_flat_option) {
290 g(gen_extend(ctx, size, zero_x, *dest, *dest));
291 mask = (rand()) | ((uint64_t)rand() << 31) | ((uint64_t)rand() << 62);
292 mask <<= 8ULL << size;
293 g(gen_imm(ctx, mask, IMM_PURPOSE_OR, OP_SIZE_NATIVE));
294 gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_OR, ALU_WRITES_FLAGS(OP_SIZE_NATIVE, ALU_OR, false, is_imm(), ctx->const_imm));
303 #if defined(ARCH_X86)
304 static bool attr_w gen_frame_load_x87(struct codegen_context *ctx, unsigned insn, unsigned size, unsigned alu, frame_t slot)
306 if (slot_is_register(ctx, slot))
308 g(gen_address(ctx, R_FRAME, (size_t)slot * slot_size, IMM_PURPOSE_LDR_OFFSET, size));
309 gen_insn(insn, size, alu, 0);
310 gen_address_offset();
314 static bool attr_w gen_frame_store_x87(struct codegen_context *ctx, unsigned insn, unsigned size, frame_t slot)
316 g(gen_address(ctx, R_FRAME, (size_t)slot * slot_size, IMM_PURPOSE_STR_OFFSET, size));
317 gen_insn(insn, size, 0, 0);
318 gen_address_offset();
319 if (slot_is_register(ctx, slot))
320 g(unspill(ctx,slot));
325 static bool attr_w gen_frame_load_op(struct codegen_context *ctx, unsigned size, enum extend ex, unsigned alu, unsigned writes_flags, frame_t slot, int64_t offset, bool dual, unsigned reg)
327 ajla_assert_lo((slot >= MIN_USEABLE_SLOT && slot < function_n_variables(ctx->fn)) || frame_t_is_const(slot), (file_line, "gen_frame_load_op: invalid slot: %lu >= %lu", (unsigned long)slot, (unsigned long)function_n_variables(ctx->fn)));
328 if (slot_is_register(ctx, slot)) {
329 if (size != i_size(size) + (unsigned)zero && ex != garbage)
331 g(gen_3address_alu(ctx, i_size(size), alu, reg, reg, ctx->registers[slot], writes_flags));
334 if (frame_t_is_const(slot)) {
335 g(gen_imm(ctx, get_constant(size, ex, slot, offset, dual), alu_purpose(alu), i_size(size)));
336 gen_insn(INSN_ALU + ARCH_PARTIAL_ALU(size), i_size(size), alu, ALU_WRITES_FLAGS(i_size(size), alu, false, is_imm(), ctx->const_imm) | writes_flags);
342 #if defined(ARCH_X86) || defined(ARCH_S390)
343 #if defined(ARCH_S390)
344 if (size >= OP_SIZE_4)
347 offset += (size_t)slot * slot_size;
348 g(gen_address(ctx, R_FRAME, offset, IMM_PURPOSE_LDR_OFFSET, size));
349 gen_insn(INSN_ALU + ARCH_PARTIAL_ALU(size), size, alu, ALU_WRITES_FLAGS(size, alu, true, false, 0) | writes_flags);
352 gen_address_offset();
357 #if defined(R_SCRATCH_NA_1)
358 g(gen_frame_load(ctx, size, ex, slot, offset, dual, R_SCRATCH_NA_1));
359 g(gen_3address_alu(ctx, i_size(size), alu, reg, reg, R_SCRATCH_NA_1, writes_flags));
364 static bool attr_w attr_unused gen_frame_load_op1(struct codegen_context *ctx, unsigned size, unsigned alu, unsigned writes_flags, frame_t slot, unsigned reg)
366 ajla_assert_lo(slot >= MIN_USEABLE_SLOT && slot < function_n_variables(ctx->fn), (file_line, "gen_frame_load_op1: invalid slot: %lu >= %lu", (unsigned long)slot, (unsigned long)function_n_variables(ctx->fn)));
367 if (slot_is_register(ctx, slot)) {
368 g(gen_2address_alu1(ctx, size, alu, reg, ctx->registers[slot], writes_flags));
371 #if defined(ARCH_X86)
373 int64_t offset = (size_t)slot * slot_size;
374 g(gen_address(ctx, R_FRAME, offset, IMM_PURPOSE_LDR_OFFSET, size));
375 gen_insn(INSN_ALU1 + ARCH_PARTIAL_ALU(size), size, alu, ALU1_WRITES_FLAGS(alu) | writes_flags);
377 gen_address_offset();
381 #if !defined(ARCH_X86)
382 g(gen_frame_load(ctx, size, garbage, slot, 0, false, reg));
383 g(gen_2address_alu1(ctx, size, alu, reg, reg, writes_flags));
389 static bool attr_w gen_frame_load_cmp(struct codegen_context *ctx, unsigned size, bool logical, enum extend attr_unused ex, bool swap, frame_t slot, int64_t offset, bool dual, unsigned reg)
391 if (slot_is_register(ctx, slot)) {
392 if (size != i_size_cmp(size) + (unsigned)zero && ex != garbage)
394 gen_insn(INSN_CMP, i_size_cmp(size), 0, 1 + logical);
397 gen_one(ctx->registers[slot]);
399 gen_one(ctx->registers[slot]);
404 if (frame_t_is_const(slot)) {
406 g(gen_imm(ctx, get_constant(size, ex, slot, offset, dual), !logical ? IMM_PURPOSE_CMP : IMM_PURPOSE_CMP_LOGICAL, size));
407 gen_insn(INSN_CMP, i_size_cmp(size), 0, 1 + logical);
411 g(gen_load_constant(ctx, R_CONST_IMM, get_constant(size, ex, slot, offset, dual)));
412 gen_insn(INSN_CMP, i_size_cmp(size), 0, 1 + logical);
413 gen_one(R_CONST_IMM);
418 #if defined(ARCH_S390) || defined(ARCH_X86)
419 #if defined(ARCH_S390)
420 if (size < OP_SIZE_4)
423 offset += (size_t)slot * slot_size;
424 g(gen_address(ctx, R_FRAME, offset, IMM_PURPOSE_LDR_OFFSET, size));
425 gen_insn(INSN_CMP, size, 0, 1 + logical);
428 gen_address_offset();
430 gen_address_offset();
436 #if defined(R_SCRATCH_NA_1)
437 g(gen_frame_load(ctx, size, ex, slot, offset, false, R_SCRATCH_NA_1));
438 gen_insn(INSN_CMP, i_size_cmp(size), 0, 1 + logical);
441 gen_one(R_SCRATCH_NA_1);
443 gen_one(R_SCRATCH_NA_1);
450 static bool attr_w gen_frame_load_cmp_imm(struct codegen_context *ctx, unsigned size, bool logical, enum extend attr_unused ex, frame_t slot, int64_t offset, int64_t value)
452 if (slot_is_register(ctx, slot)) {
453 #if defined(ARCH_X86)
454 g(gen_imm(ctx, value, logical ? IMM_PURPOSE_CMP_LOGICAL : IMM_PURPOSE_CMP, size));
455 gen_insn(INSN_CMP, size, 0, 1 + logical);
456 gen_one(ctx->registers[slot]);
459 if (size != i_size(size) + (unsigned)zero && size < OP_SIZE_4 && ex != garbage)
461 g(gen_imm(ctx, value, logical ? IMM_PURPOSE_CMP_LOGICAL : IMM_PURPOSE_CMP, size));
462 gen_insn(INSN_CMP, i_size_cmp(size), 0, 1 + logical);
463 gen_one(ctx->registers[slot]);
468 #if defined(ARCH_X86)
469 offset += (size_t)slot * slot_size;
470 g(gen_address(ctx, R_FRAME, offset, IMM_PURPOSE_MVI_CLI_OFFSET, size));
471 g(gen_imm(ctx, value, logical ? IMM_PURPOSE_CMP_LOGICAL : IMM_PURPOSE_CMP, size));
472 gen_insn(INSN_CMP, size, 0, 1 + logical);
473 gen_address_offset();
477 #if defined(ARCH_S390)
478 if (size != OP_SIZE_1 || !logical)
480 offset += (size_t)slot * slot_size;
481 g(gen_address(ctx, R_FRAME, offset, IMM_PURPOSE_MVI_CLI_OFFSET, size));
482 gen_insn(INSN_CMP, size, 0, 1 + logical);
483 gen_address_offset();
485 gen_eight((int8_t)value);
488 #if defined(R_SCRATCH_NA_1)
491 g(gen_frame_load(ctx, size, ex, slot, offset, false, R_SCRATCH_NA_1));
492 g(gen_imm(ctx, value, logical ? IMM_PURPOSE_CMP_LOGICAL : IMM_PURPOSE_CMP, size));
493 gen_insn(INSN_CMP, i_size(size), 0, 1 + logical);
494 gen_one(R_SCRATCH_NA_1);
501 static bool attr_w gen_frame_load_2(struct codegen_context *ctx, unsigned size, frame_t slot, int64_t offset, unsigned reg1, unsigned reg2)
503 if (frame_t_is_const(slot))
505 #if defined(ARCH_ARM64)
506 offset += (size_t)slot * slot_size;
507 g(gen_address(ctx, R_FRAME, offset, IMM_PURPOSE_LDP_STP_OFFSET, size));
508 gen_insn(INSN_LDP, size, 0, 0);
511 gen_address_offset();
514 #if defined(ARCH_ARM32)
515 if (likely(!(reg1 & 1)) && likely(reg2 == reg1 + 1) && likely(cpu_test_feature(CPU_FEATURE_armv6)))
516 #elif defined(ARCH_SPARC32)
517 if (likely(!(reg2 & 1)) && likely(reg1 == reg2 + 1))
518 #elif defined(ARCH_S390)
519 if (likely(reg1 == reg2 + 1))
524 offset += (size_t)slot * slot_size;
525 if (UNALIGNED_TRAP) {
526 if (unlikely((offset & ((2U << size) - 1)) != 0)) {
527 offset -= (size_t)slot * slot_size;
531 g(gen_address(ctx, R_FRAME, offset, IMM_PURPOSE_LDP_STP_OFFSET, size));
532 gen_insn(INSN_LDP, size, 0, 0);
535 gen_address_offset();
540 g(gen_frame_load(ctx, size, garbage, slot, offset + lo_word(size), true, reg1));
541 g(gen_frame_load(ctx, size, garbage, slot, offset + hi_word(size), true, reg2));
545 static bool attr_w gen_frame_store_raw(struct codegen_context *ctx, unsigned size, frame_t slot, int64_t offset, unsigned reg)
547 offset += (size_t)slot * slot_size;
549 size = maximum(OP_SIZE_4, size);
550 #if defined(ARCH_MIPS)
551 if (reg_is_fp(reg) && size == OP_SIZE_8 && !MIPS_HAS_LS_DOUBLE) {
552 #if defined(C_LITTLE_ENDIAN)
553 g(gen_frame_store_raw(ctx, OP_SIZE_4, 0, offset, reg));
554 g(gen_frame_store_raw(ctx, OP_SIZE_4, 0, offset + 4, reg + 1));
556 g(gen_frame_store_raw(ctx, OP_SIZE_4, 0, offset, reg + 1));
557 g(gen_frame_store_raw(ctx, OP_SIZE_4, 0, offset + 4, reg));
562 #if defined(ARCH_S390)
563 if (size == OP_SIZE_16 && reg_is_fp(reg)) {
564 g(gen_frame_store_raw(ctx, OP_SIZE_8, 0, offset, reg));
565 g(gen_frame_store_raw(ctx, OP_SIZE_8, 0, offset + 8, reg + 2));
569 g(gen_address(ctx, R_FRAME, offset, reg_is_fp(reg) ? IMM_PURPOSE_VLDR_VSTR_OFFSET : IMM_PURPOSE_STR_OFFSET, size));
570 gen_insn(INSN_MOV, size, 0, 0);
571 gen_address_offset();
576 static bool attr_w gen_frame_store(struct codegen_context *ctx, unsigned size, frame_t slot, int64_t offset, unsigned reg)
578 ajla_assert_lo(slot >= MIN_USEABLE_SLOT && slot < function_n_variables(ctx->fn), (file_line, "gen_frame_store: invalid slot: %lu >= %lu", (unsigned long)slot, (unsigned long)function_n_variables(ctx->fn)));
579 if (slot_is_register(ctx, slot)) {
580 if (unlikely(offset != 0))
581 internal(file_line, "gen_frame_store: offset is non-zero: %"PRIdMAX"", (intmax_t)offset);
582 g(gen_mov(ctx, !reg_is_fp(reg) ? OP_SIZE_NATIVE : size, ctx->registers[slot], reg));
585 return gen_frame_store_raw(ctx, size, slot, offset, reg);
588 static unsigned gen_frame_target(struct codegen_context *ctx, frame_t slot_r, frame_t slot_na_1, frame_t slot_na_2, unsigned reg)
590 if (slot_is_register(ctx, slot_r)) {
591 short d = ctx->registers[slot_r];
592 if (slot_na_1 != NO_FRAME_T && slot_is_register(ctx, slot_na_1) && ctx->registers[slot_na_1] == d)
594 if (slot_na_2 != NO_FRAME_T && slot_is_register(ctx, slot_na_2) && ctx->registers[slot_na_2] == d)
601 static bool attr_w gen_frame_store_2(struct codegen_context *ctx, unsigned size, frame_t slot, int64_t offset, unsigned reg1, unsigned reg2)
603 #if defined(ARCH_ARM64)
604 offset += (size_t)slot * slot_size;
605 g(gen_address(ctx, R_FRAME, offset, IMM_PURPOSE_LDP_STP_OFFSET, size));
606 gen_insn(INSN_STP, size, 0, 0);
607 gen_address_offset();
612 #if defined(ARCH_ARM32)
613 if (likely(!(reg1 & 1)) && likely(reg2 == reg1 + 1) && likely(cpu_test_feature(CPU_FEATURE_armv6)))
614 #elif defined(ARCH_SPARC32)
615 if (likely(!(reg2 & 1)) && likely(reg1 == reg2 + 1))
616 #elif defined(ARCH_S390)
617 if (likely(reg1 == reg2 + 1))
622 offset += (size_t)slot * slot_size;
623 if (UNALIGNED_TRAP) {
624 if (unlikely((offset & ((2U << size) - 1)) != 0)) {
625 offset -= (size_t)slot * slot_size;
629 g(gen_address(ctx, R_FRAME, offset, IMM_PURPOSE_LDP_STP_OFFSET, size));
630 gen_insn(INSN_STP, size, 0, 0);
631 gen_address_offset();
638 g(gen_frame_store(ctx, size, slot, offset + lo_word(size), reg1));
639 g(gen_frame_store(ctx, size, slot, offset + hi_word(size), reg2));
643 static bool attr_w gen_frame_store_imm_raw(struct codegen_context *ctx, unsigned size, frame_t slot, int64_t offset, int64_t imm)
645 offset += (size_t)slot * slot_size;
647 size = maximum(OP_SIZE_4, size);
648 g(gen_address(ctx, R_FRAME, offset, size == OP_SIZE_1 ? IMM_PURPOSE_MVI_CLI_OFFSET : IMM_PURPOSE_STR_OFFSET, size));
649 g(gen_imm(ctx, imm, IMM_PURPOSE_STORE_VALUE, size));
650 gen_insn(INSN_MOV, size, 0, 0);
651 gen_address_offset();
656 static bool attr_w gen_frame_store_imm(struct codegen_context *ctx, unsigned size, frame_t slot, int64_t offset, int64_t imm)
658 ajla_assert_lo(slot >= MIN_USEABLE_SLOT && slot < function_n_variables(ctx->fn), (file_line, "gen_frame_store_imm: invalid slot: %lu >= %lu", (unsigned long)slot, (unsigned long)function_n_variables(ctx->fn)));
659 if (slot_is_register(ctx, slot)) {
660 if (unlikely(offset != 0))
661 internal(file_line, "gen_frame_store_imm: offset is non-zero: %"PRIdMAX"", (intmax_t)offset);
662 if (size == OP_SIZE_1)
663 imm = ARCH_PREFERS_SX(size) ? (int64_t)(int8_t)imm : (int64_t)(uint8_t)imm;
664 if (size == OP_SIZE_2)
665 imm = ARCH_PREFERS_SX(size) ? (int64_t)(int16_t)imm : (int64_t)(uint16_t)imm;
666 if (size == OP_SIZE_4)
667 imm = ARCH_PREFERS_SX(size) ? (int64_t)(int32_t)imm : (int64_t)(uint32_t)imm;
668 g(gen_load_constant(ctx, ctx->registers[slot], imm));
671 return gen_frame_store_imm_raw(ctx, size, slot, offset, imm);
674 static bool attr_w gen_frame_clear_raw(struct codegen_context *ctx, unsigned size, frame_t slot)
676 g(gen_frame_store_imm_raw(ctx, size, slot, 0, 0));
680 static bool attr_w gen_frame_clear(struct codegen_context *ctx, unsigned size, frame_t slot)
682 g(gen_frame_store_imm(ctx, size, slot, 0, 0));
683 if (slot_is_register(ctx, slot))
688 #if defined(ARCH_X86)
689 static bool attr_w gen_frame_set_cond(struct codegen_context *ctx, unsigned attr_unused size, bool attr_unused logical, unsigned cond, frame_t slot)
692 if (slot_is_register(ctx, slot)) {
693 unsigned reg = ctx->registers[slot];
694 #if defined(ARCH_X86_32)
696 gen_insn(INSN_SET_COND_PARTIAL, OP_SIZE_1, cond, 0);
697 gen_one(R_SCRATCH_1);
698 gen_one(R_SCRATCH_1);
700 g(gen_mov(ctx, OP_SIZE_1, reg, R_SCRATCH_1));
704 if (cpu_test_feature(CPU_FEATURE_apx)) {
705 gen_insn(INSN_SET_COND, OP_SIZE_8, cond, 0);
708 gen_insn(INSN_SET_COND_PARTIAL, OP_SIZE_1, cond, 0);
711 if (sizeof(ajla_flat_option_t) > 1)
712 g(gen_mov(ctx, OP_SIZE_1, reg, reg));
716 offset = (size_t)slot * slot_size;
717 if (sizeof(ajla_flat_option_t) > 1) {
718 gen_insn(INSN_SET_COND_PARTIAL, OP_SIZE_1, cond, 0);
719 gen_one(R_SCRATCH_1);
720 gen_one(R_SCRATCH_1);
722 g(gen_mov(ctx, OP_SIZE_1, R_SCRATCH_1, R_SCRATCH_1));
724 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot, 0, R_SCRATCH_1));
726 g(gen_address(ctx, R_FRAME, offset, IMM_PURPOSE_STR_OFFSET, OP_SIZE_1));
727 gen_insn(INSN_SET_COND, OP_SIZE_1, cond, 0);
728 gen_address_offset();
732 #elif defined(ARCH_ARM64)
733 static bool attr_w gen_frame_set_cond(struct codegen_context *ctx, unsigned attr_unused size, bool attr_unused logical, unsigned cond, frame_t slot)
735 if (slot_is_register(ctx, slot)) {
736 gen_insn(INSN_SET_COND, OP_SIZE_4, cond, 0);
737 gen_one(ctx->registers[slot]);
739 gen_insn(INSN_SET_COND, OP_SIZE_4, cond, 0);
740 gen_one(R_SCRATCH_1);
741 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot, 0, R_SCRATCH_1));
746 static bool attr_w gen_frame_set_cond(struct codegen_context *ctx, unsigned size, bool logical, unsigned cond, frame_t slot)
748 unsigned target = gen_frame_target(ctx, slot, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_1);
749 #if defined(ARCH_POWER)
750 if (!cpu_test_feature(CPU_FEATURE_v203))
751 #elif defined(ARCH_S390)
752 if (!cpu_test_feature(CPU_FEATURE_misc_45))
753 #elif defined(ARCH_SPARC32)
760 g(gen_load_constant(ctx, target, 1));
761 label = alloc_label(ctx);
762 if (unlikely(!label))
764 gen_insn(!logical ? INSN_JMP_COND : INSN_JMP_COND_LOGICAL, i_size_cmp(size), cond, 0);
766 g(gen_load_constant(ctx, target, 0));
770 g(gen_load_constant(ctx, target, 1));
771 g(gen_imm(ctx, 0, IMM_PURPOSE_CMOV, OP_SIZE_NATIVE));
772 if (cond & COND_FP) {
773 gen_insn(INSN_CMOV, OP_SIZE_NATIVE, cond ^ 1, 0);
775 #if defined(ARCH_S390)
776 gen_insn(logical ? INSN_CMOV_XCC : INSN_CMOV, OP_SIZE_NATIVE, cond ^ 1, 0);
778 gen_insn(size == OP_SIZE_8 ? INSN_CMOV_XCC : INSN_CMOV, OP_SIZE_NATIVE, cond ^ 1, 0);
785 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot, 0, target));
791 static bool attr_w gen_frame_cmp_imm_set_cond_reg(struct codegen_context *ctx, unsigned size, unsigned reg, int64_t imm, unsigned cond, frame_t slot_r)
794 dest_reg = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_CMP_RESULT);
795 g(gen_cmp_dest_reg(ctx, size, reg, (unsigned)-1, dest_reg, imm, cond));
796 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, dest_reg));
802 static bool attr_w gen_frame_load_cmp_set_cond(struct codegen_context *ctx, unsigned size, enum extend ex, frame_t slot, unsigned reg, unsigned cond, frame_t slot_r)
805 bool logical = COND_IS_LOGICAL(cond);
806 g(gen_frame_load_cmp(ctx, size, logical, ex, false, slot, 0, false, reg));
807 g(gen_frame_set_cond(ctx, size, logical, cond, slot_r));
809 unsigned src_reg, dest_reg;
810 g(gen_frame_get(ctx, size, ex, slot, R_SCRATCH_NA_1, &src_reg));
811 dest_reg = gen_frame_target(ctx, slot_r, NO_FRAME_T, NO_FRAME_T, R_SCRATCH_NA_1);
812 g(gen_cmp_dest_reg(ctx, size, reg, src_reg, dest_reg, 0, cond));
813 g(gen_frame_store(ctx, log_2(sizeof(ajla_flat_option_t)), slot_r, 0, dest_reg));
818 static bool attr_w gen_frame_load_cmp_imm_set_cond(struct codegen_context *ctx, unsigned size, enum extend ex, frame_t slot, int64_t value, unsigned cond, frame_t slot_r)
821 bool logical = COND_IS_LOGICAL(cond);
822 #if defined(ARCH_S390)
826 g(gen_frame_load_cmp_imm(ctx, size, logical, ex, slot, 0, value));
827 g(gen_frame_set_cond(ctx, size, false, cond, slot_r));
830 g(gen_frame_get(ctx, size, ex, slot, R_SCRATCH_NA_1, &src_reg));
831 g(gen_frame_cmp_imm_set_cond_reg(ctx, size, src_reg, value, cond, slot_r));
836 static bool attr_w gen_upcall_start(struct codegen_context *ctx, unsigned offset, unsigned args)
840 int attr_unused reg_to_push = -1;
841 ajla_assert_lo(ctx->upcall_args == -1, (file_line, "gen_upcall_start: gen_upcall_end not called"));
842 ajla_assert_lo(ctx->upcall_offset == -1, (file_line, "gen_upcall_start: gen_upcall_end not called"));
843 ctx->upcall_args = (int)args;
844 ctx->upcall_offset = (int)offset;
845 idx = offset / sizeof(void *);
846 ctx->upcall_hacked_abi = false;
847 if (idx < 32 && (hacked_upcall_map >> idx) & 1)
848 ctx->upcall_hacked_abi = true;
850 #if (defined(ARCH_X86_64) || defined(ARCH_X86_X32)) && !defined(ARCH_X86_WIN_ABI)
851 for (i = 0; i < ctx->need_spill_l; i++) {
852 unsigned reg = ctx->registers[ctx->need_spill[i]];
854 g(spill(ctx, ctx->need_spill[i]));
857 for (i = 0; i < ctx->need_spill_l; i++) {
858 unsigned reg = ctx->registers[ctx->need_spill[i]];
859 if (!reg_is_fp(reg)) {
860 if (ctx->upcall_hacked_abi && !reg_is_saved(reg))
862 if (reg_to_push < 0) {
865 g(gen_x86_push2(ctx, reg_to_push, reg, true));
871 if (ctx->n_pushes & 1) {
872 g(gen_x86_push2(ctx, reg_to_push, R_CX, true));
875 for (i = 0; i < ctx->need_spill_l; i++)
876 g(spill(ctx, ctx->need_spill[i]));
881 static bool attr_w gen_upcall_end(struct codegen_context *ctx, unsigned attr_unused offset, unsigned attr_unused args)
884 int attr_unused reg_to_pop = -1;
885 ajla_assert_lo(ctx->upcall_args == (int)args, (file_line, "gen_upcall_end: gen_upcall_start args mismatch: %d != %d", ctx->upcall_args, (int)args));
886 ajla_assert_lo(ctx->upcall_offset == (int)offset, (file_line, "gen_upcall_end: gen_upcall_start offset mismatch: %d != %d", ctx->upcall_offset, (int)offset));
888 #if (defined(ARCH_X86_64) || defined(ARCH_X86_X32)) && !defined(ARCH_X86_WIN_ABI)
889 if (ctx->n_pushes & 1) {
892 for (i = ctx->need_spill_l; i;) {
895 reg = ctx->registers[ctx->need_spill[i]];
896 if (!reg_is_fp(reg)) {
897 if (ctx->upcall_hacked_abi && !reg_is_saved(reg))
899 if (reg_to_pop < 0) {
902 g(gen_x86_pop2(ctx, reg_to_pop, reg, true));
907 ajla_assert_lo(reg_to_pop == -1, (file_line, "gen_upcall_end: reg_to_pop mismatch"));
908 for (i = 0; i < ctx->need_spill_l; i++) {
909 unsigned reg = ctx->registers[ctx->need_spill[i]];
911 g(unspill(ctx, ctx->need_spill[i]));
914 for (i = 0; i < ctx->need_spill_l; i++)
915 g(unspill(ctx, ctx->need_spill[i]));
918 ctx->upcall_args = -1;
919 ctx->upcall_offset = -1;
920 ctx->upcall_hacked_abi = false;
924 static bool attr_w gen_memcpy_raw(struct codegen_context *ctx, unsigned dest_base, int64_t dest_offset, unsigned src_base, int64_t src_offset, size_t size, size_t attr_unused align)
929 if (align < 4 || (size & 3))
932 #if defined(ARCH_S390)
934 if (!(size & 3) || (cpu_test_feature(CPU_FEATURE_long_displacement) && cpu_test_feature(CPU_FEATURE_extended_imm)))
935 goto do_explicit_copy;
937 if (size <= 0x100 && dest_offset >= 0 && dest_offset < 0x1000 && src_offset >= 0 && src_offset < 0x1000) {
938 gen_insn(INSN_MEMCPY, 0, 0, 0);
939 gen_one(ARG_ADDRESS_1);
941 gen_eight(dest_offset);
942 gen_one(ARG_ADDRESS_1);
944 gen_eight(src_offset);
952 if (size <= INLINE_COPY_SIZE) {
955 unsigned this_op_size;
956 #if defined(ARCH_ARM)
957 if (size >= 2U << OP_SIZE_NATIVE
958 #if defined(ARCH_ARM32)
959 && align >= 1U << OP_SIZE_NATIVE
962 g(gen_address(ctx, src_base, src_offset, IMM_PURPOSE_LDP_STP_OFFSET, OP_SIZE_NATIVE));
963 gen_insn(INSN_LDP, OP_SIZE_NATIVE, 0, 0);
964 gen_one(R_SCRATCH_NA_1);
965 gen_one(R_SCRATCH_NA_2);
966 gen_address_offset();
968 g(gen_address(ctx, dest_base, dest_offset, IMM_PURPOSE_LDP_STP_OFFSET, OP_SIZE_NATIVE));
969 gen_insn(INSN_STP, OP_SIZE_NATIVE, 0, 0);
970 gen_address_offset();
971 gen_one(R_SCRATCH_NA_1);
972 gen_one(R_SCRATCH_NA_2);
974 size -= 2U << OP_SIZE_NATIVE;
975 src_offset += 2U << OP_SIZE_NATIVE;
976 dest_offset += 2U << OP_SIZE_NATIVE;
981 if (size >= 8 && OP_SIZE_NATIVE >= OP_SIZE_8)
990 this_step = minimum(this_step, align);
991 this_op_size = log_2(this_step);
993 g(gen_address(ctx, src_base, src_offset, ARCH_PREFERS_SX(this_op_size) ? IMM_PURPOSE_LDR_SX_OFFSET : IMM_PURPOSE_LDR_OFFSET, this_op_size));
994 gen_insn(ARCH_PREFERS_SX(this_op_size) ? INSN_MOVSX : INSN_MOV, this_op_size, 0, 0);
995 gen_one(R_SCRATCH_1);
996 gen_address_offset();
998 g(gen_address(ctx, dest_base, dest_offset, IMM_PURPOSE_STR_OFFSET, this_op_size));
999 gen_insn(INSN_MOV, this_op_size, 0, 0);
1000 gen_address_offset();
1001 gen_one(R_SCRATCH_1);
1004 src_offset += this_step;
1005 dest_offset += this_step;
1011 g(gen_upcall_start(ctx, offsetof(struct cg_upcall_vector_s, mem_copy), 3));
1012 if (unlikely(R_ARG0 == src_base)) {
1013 if (unlikely(R_ARG1 == dest_base))
1014 internal(file_line, "gen_memcpy_raw: swapped registers: %u, %u", src_base, dest_base);
1015 g(gen_3address_alu_imm(ctx, i_size(OP_SIZE_ADDRESS), ALU_ADD, R_ARG1, src_base, src_offset, 0));
1016 g(gen_upcall_argument(ctx, 1));
1019 g(gen_3address_alu_imm(ctx, i_size(OP_SIZE_ADDRESS), ALU_ADD, R_ARG0, dest_base, dest_offset, 0));
1020 g(gen_upcall_argument(ctx, 0));
1022 if (R_ARG0 != src_base) {
1023 g(gen_3address_alu_imm(ctx, i_size(OP_SIZE_ADDRESS), ALU_ADD, R_ARG1, src_base, src_offset, 0));
1024 g(gen_upcall_argument(ctx, 1));
1027 #if (defined(ARCH_X86_64) || defined(ARCH_X86_X32)) && !defined(ARCH_X86_WIN_ABI)
1028 if (cpu_test_feature(CPU_FEATURE_erms)) {
1029 g(gen_load_constant(ctx, R_CX, size));
1031 gen_insn(INSN_MEMCPY, 0, 0, 0);
1032 gen_one(ARG_ADDRESS_1_POST_I);
1035 gen_one(ARG_ADDRESS_1_POST_I);
1039 g(gen_upcall_end(ctx, offsetof(struct cg_upcall_vector_s, mem_copy), 3));
1044 g(gen_load_constant(ctx, R_ARG2, size));
1045 g(gen_upcall_argument(ctx, 2));
1047 g(gen_upcall(ctx, offsetof(struct cg_upcall_vector_s, mem_copy), 3));
1052 static bool attr_w gen_memcpy_to_slot(struct codegen_context *ctx, frame_t dest_slot, unsigned src_base, int64_t src_offset)
1054 const struct type *t = get_type_of_local(ctx, dest_slot);
1055 unsigned size = spill_size(t);
1056 short dest_reg = ctx->registers[dest_slot];
1057 if (dest_reg >= 0) {
1058 if (ARCH_PREFERS_SX(size) && !reg_is_fp(dest_reg)) {
1059 #if defined(ARCH_S390)
1060 if (size == OP_SIZE_1 && !cpu_test_feature(CPU_FEATURE_long_displacement)) {
1061 g(gen_address(ctx, src_base, src_offset, IMM_PURPOSE_LDR_OFFSET, size));
1062 gen_insn(INSN_MOV_MASK, OP_SIZE_NATIVE, MOV_MASK_0_8, 0);
1065 gen_address_offset();
1066 g(gen_extend(ctx, size, sign_x, dest_reg, dest_reg));
1070 g(gen_address(ctx, src_base, src_offset, IMM_PURPOSE_LDR_SX_OFFSET, size));
1071 gen_insn(INSN_MOVSX, size, 0, 0);
1073 g(gen_address(ctx, src_base, src_offset, reg_is_fp(dest_reg) ? IMM_PURPOSE_VLDR_VSTR_OFFSET : IMM_PURPOSE_LDR_OFFSET, size));
1074 gen_insn(INSN_MOV, size, 0, 0);
1077 gen_address_offset();
1080 g(gen_memcpy_raw(ctx, R_FRAME, (size_t)dest_slot * slot_size, src_base, src_offset, t->size, t->align));
1084 static bool attr_w gen_memcpy_from_slot(struct codegen_context *ctx, unsigned dest_base, int64_t dest_offset, frame_t src_slot)
1086 const struct type *t = get_type_of_local(ctx, src_slot);
1087 short src_reg = ctx->registers[src_slot];
1089 unsigned size = spill_size(t);
1090 g(gen_address(ctx, dest_base, dest_offset, reg_is_fp(src_reg) ? IMM_PURPOSE_VLDR_VSTR_OFFSET : IMM_PURPOSE_STR_OFFSET, size));
1091 gen_insn(INSN_MOV, size, 0, 0);
1092 gen_address_offset();
1096 g(gen_memcpy_raw(ctx, dest_base, dest_offset, R_FRAME, (size_t)src_slot * slot_size, t->size, t->align));
1100 static bool attr_w gen_memcpy_slots(struct codegen_context *ctx, frame_t dest_slot, frame_t src_slot)
1102 const struct type *t = get_type_of_local(ctx, src_slot);
1103 short dest_reg = ctx->registers[dest_slot];
1104 short src_reg = ctx->registers[src_slot];
1105 if (dest_reg >= 0 && src_reg >= 0) {
1106 unsigned size = spill_size(t);
1107 g(gen_mov(ctx, reg_is_fp(src_reg) ? size : OP_SIZE_NATIVE, dest_reg, src_reg));
1110 if (dest_reg >= 0) {
1111 unsigned size = spill_size(t);
1112 g(gen_frame_load(ctx, size, garbage, src_slot, 0, false, dest_reg));
1116 unsigned size = spill_size(t);
1117 g(gen_frame_store(ctx, size, dest_slot, 0, src_reg));
1120 g(gen_memcpy_raw(ctx, R_FRAME, (size_t)dest_slot * slot_size, R_FRAME, (size_t)src_slot * slot_size, t->size, maximum(slot_size, t->align)));
1124 static bool attr_w gen_clear_bitmap(struct codegen_context *ctx, unsigned additional_offset, unsigned dest_base, int64_t dest_offset, frame_t bitmap_slots)
1126 if (bitmap_slots <= INLINE_BITMAP_SLOTS) {
1127 bool attr_unused scratch_2_zeroed = false;
1128 size_t bitmap_length = (size_t)bitmap_slots * slot_size;
1129 size_t clear_offset = 0;
1130 additional_offset += (unsigned)dest_offset;
1131 #if defined(ARCH_X86)
1132 g(gen_3address_alu(ctx, OP_SIZE_4, ALU_XOR, R_SCRATCH_1, R_SCRATCH_1, R_SCRATCH_1, 0));
1134 #if defined(ARCH_ARM32) || defined(ARCH_S390)
1135 g(gen_load_constant(ctx, R_SCRATCH_1, 0));
1137 while (clear_offset < bitmap_length) {
1138 size_t len = bitmap_length - clear_offset;
1139 if (len > frame_align)
1141 if (additional_offset)
1142 len = minimum(len, additional_offset & -additional_offset);
1143 #if defined(ARCH_ARM32) || defined(ARCH_S390)
1144 len = minimum(len, 2U << OP_SIZE_NATIVE);
1145 if (len == 2U << OP_SIZE_NATIVE) {
1146 if (!scratch_2_zeroed) {
1147 g(gen_load_constant(ctx, R_SCRATCH_2, 0));
1148 scratch_2_zeroed = true;
1150 g(gen_address(ctx, dest_base, dest_offset + clear_offset, IMM_PURPOSE_LDP_STP_OFFSET, OP_SIZE_NATIVE));
1151 gen_insn(INSN_STP, OP_SIZE_NATIVE, 0, 0);
1152 gen_address_offset();
1153 gen_one(R_SCRATCH_1);
1154 gen_one(R_SCRATCH_2);
1157 #elif defined(ARCH_ARM64)
1158 len = minimum(len, 1U << OP_SIZE_16);
1159 if (len == 1U << OP_SIZE_16) {
1160 g(gen_address(ctx, dest_base, dest_offset + clear_offset, IMM_PURPOSE_LDP_STP_OFFSET, OP_SIZE_8));
1161 g(gen_imm(ctx, 0, IMM_PURPOSE_STORE_VALUE, OP_SIZE_8));
1162 gen_insn(INSN_STP, OP_SIZE_NATIVE, 0, 0);
1163 gen_address_offset();
1168 #elif defined(ARCH_X86)
1169 len = minimum(len, 1U << OP_SIZE_16);
1170 if (len == 1U << OP_SIZE_16 && cpu_test_feature(CPU_FEATURE_sse)) {
1171 if (!scratch_2_zeroed) {
1172 g(gen_3address_alu(ctx, OP_SIZE_16, ALU_XOR, FR_SCRATCH_1, FR_SCRATCH_1, FR_SCRATCH_1, 0));
1173 scratch_2_zeroed = true;
1175 g(gen_address(ctx, dest_base, dest_offset + clear_offset, IMM_PURPOSE_VLDR_VSTR_OFFSET, OP_SIZE_16));
1176 gen_insn(INSN_MOV, OP_SIZE_16, 0, 0);
1177 gen_address_offset();
1178 gen_one(FR_SCRATCH_1);
1182 len = minimum(len, 1U << OP_SIZE_NATIVE);
1183 len = (size_t)1 << high_bit(len);
1184 #if defined(ARCH_X86) || defined(ARCH_ARM32) || defined(ARCH_S390)
1185 g(gen_address(ctx, dest_base, dest_offset + clear_offset, IMM_PURPOSE_STR_OFFSET, log_2(len)));
1186 gen_insn(INSN_MOV, log_2(len), 0, 0);
1187 gen_address_offset();
1188 gen_one(R_SCRATCH_1);
1190 g(gen_address(ctx, dest_base, dest_offset + clear_offset, IMM_PURPOSE_STR_OFFSET, log_2(len)));
1191 g(gen_imm(ctx, 0, IMM_PURPOSE_STORE_VALUE, log_2(len)));
1192 gen_insn(INSN_MOV, log_2(len), 0, 0);
1193 gen_address_offset();
1198 clear_offset += len;
1199 additional_offset += len;
1203 #if (defined(ARCH_X86_64) || defined(ARCH_X86_X32)) && !defined(ARCH_X86_WIN_ABI)
1204 if (cpu_test_feature(CPU_FEATURE_erms)) {
1205 g(gen_x86_push(ctx, R_DI, true));
1207 g(gen_3address_alu_imm(ctx, i_size(OP_SIZE_ADDRESS), ALU_ADD, R_DI, dest_base, dest_offset, 0));
1209 g(gen_load_constant(ctx, R_CX, (size_t)bitmap_slots * slot_size));
1211 g(gen_3address_alu(ctx, OP_SIZE_4, ALU_XOR, R_AX, R_AX, R_AX, 0));
1213 gen_insn(INSN_MEMSET, 0, 0, 0);
1214 gen_one(ARG_ADDRESS_1_POST_I);
1220 g(gen_x86_pop(ctx, R_DI, true));
1225 g(gen_upcall_start(ctx, offsetof(struct cg_upcall_vector_s, mem_clear), 2));
1227 g(gen_3address_alu_imm(ctx, i_size(OP_SIZE_ADDRESS), ALU_ADD, R_ARG0, dest_base, dest_offset, 0));
1228 g(gen_upcall_argument(ctx, 0));
1230 g(gen_load_constant(ctx, R_ARG1, (size_t)bitmap_slots * slot_size));
1231 g(gen_upcall_argument(ctx, 1));
1233 g(gen_upcall(ctx, offsetof(struct cg_upcall_vector_s, mem_clear), 2));
1238 static bool attr_w load_function_offset(struct codegen_context *ctx, unsigned dest, size_t fn_offset)
1240 g(gen_frame_load_raw(ctx, OP_SIZE_ADDRESS, zero_x, 0, frame_offs(function), false, dest));
1242 g(gen_address(ctx, dest, fn_offset, IMM_PURPOSE_LDR_OFFSET, OP_SIZE_ADDRESS));
1243 gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
1245 gen_address_offset();