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 ARM_ALWAYS 0xe0000000U
20 #define ARM_WRITE_FLAGS 0x00100000U
22 #define ARM_LDR_STR_LD 0x00100000U
23 #define ARM_LDR_STR_W 0x00200000U
24 #define ARM_LDR_STR_U 0x00800000U
25 #define ARM_LDR_STR_P 0x01000000U
26 #define ARM_STRH_REG 0x000000b0U
27 #define ARM_LDRD_REG 0x000000d0U
28 #define ARM_STRD_REG 0x000000f0U
29 #define ARM_LDRSB_REG 0x001000d0U
30 #define ARM_LDRSH_REG 0x001000f0U
31 #define ARM_STRH_IMM 0x004000b0U
32 #define ARM_LDRD_IMM 0x004000d0U
33 #define ARM_STRD_IMM 0x004000f0U
34 #define ARM_LDRSB_IMM 0x005000d0U
35 #define ARM_LDRSH_IMM 0x005000f0U
36 #define ARM_STR_IMM 0x04000000U
37 #define ARM_STRB_IMM 0x04400000U
38 #define ARM_STR_REG 0x06000000U
39 #define ARM_STRB_REG 0x06400000U
41 #define ARM_ALU_IMM 0x02000000U
42 #define ARM_ALU_REG_SHIFTED 0x00000010U
43 #define ARM_ROT_LSL 0x00000000U
44 #define ARM_ROT_LSR 0x00000020U
45 #define ARM_ROT_ASR 0x00000040U
46 #define ARM_ROT_ROR 0x00000060U
47 #define ARM_AND 0x00000000U
48 #define ARM_EOR 0x00200000U
49 #define ARM_SUB 0x00400000U
50 #define ARM_RSB 0x00600000U
51 #define ARM_ADD 0x00800000U
52 #define ARM_ADC 0x00a00000U
53 #define ARM_SBC 0x00c00000U
54 #define ARM_RSC 0x00e00000U
55 #define ARM_TST 0x01100000U
56 #define ARM_TEQ 0x01300000U
57 #define ARM_CMP 0x01500000U
58 #define ARM_CMN 0x01700000U
59 #define ARM_ORR 0x01800000U
60 #define ARM_MOV 0x01a00000U
61 #define ARM_BIC 0x01c00000U
62 #define ARM_MVN 0x01e00000U
64 #define ARM_MUL 0x00000090U
65 #define ARM_MLA 0x00200090U
66 #define ARM_MLS 0x00600090U
67 #define ARM_UMULL 0x00800090U
68 #define ARM_SMULL 0x00c00090U
69 #define ARM_BX 0x012fff10U
70 #define ARM_BLX_REG 0x012fff30U
71 #define ARM_CLZ 0x016f0f10U
72 #define ARM_MOV_IMM16 0x03000000U
73 #define ARM_MOVT 0x03400000U
74 #define ARM_REV 0x06bf0f30U
75 #define ARM_REV16 0x06bf0fb0U
76 #define ARM_RBIT 0x06ff0f30U
77 #define ARM_SDIV 0x0710f010U
78 #define ARM_UDIV 0x0730f010U
79 #define ARM_POP 0x08bd0000U
80 #define ARM_PUSH 0x092d0000U
81 #define ARM_B 0x0a000000U
83 #define ARM_V_D 0x00000100U
84 #define ARM_VSTR 0x0d000a00U
85 #define ARM_VLDR 0x0d100a00U
86 #define ARM_VMOV_S32_R 0x0e000a10U
87 #define ARM_VMOV_R_S32 0x0e100a10U
88 #define ARM_VMUL 0x0e200a00U
89 #define ARM_VADD 0x0e300a00U
90 #define ARM_VSUB 0x0e300a40U
91 #define ARM_VDIV 0x0e800a00U
92 #define ARM_VNEG 0x0eb10a40U
93 #define ARM_VSQRT 0x0eb10ac0U
94 #define ARM_VCVT_F32_F16 0x0eb20a40U
95 #define ARM_VCVT_F16_F32 0x0eb30a40U
96 #define ARM_VCMP 0x0eb40a40U
97 #define ARM_VCVT_F_S32 0x0eb80ac0U
98 #define ARM_VCVT_S32_F 0x0ebd0ac0U
99 #define ARM_VMRS_NZCV_FPSCR 0x0ef1fa10U
101 #define ARM_V_BYTE 0x00000000U
102 #define ARM_V_HALF 0x00000400U
103 #define ARM_VST1 0xf480000fU
104 #define ARM_VLD1 0xf4a0000fU
105 #define ARM_VCNT_8_Q 0x00000040U
106 #define ARM_VCNT_8 0xf3b00500U
107 #define ARM_VPADDL_U8 0xf3b00280U
108 #define ARM_VPADDL_U16 0xf3b40280U
109 #define ARM_VPADDL_U32 0xf3b80280U
111 static const uint32_t alu_codes[7] = {
121 static const int8_t jmp_cond[48] = {
122 0x6, 0x7, 0x3, 0x2, 0x0, 0x1, 0x9, 0x8,
123 0x4, 0x5, -1, -1, 0xb, 0xa, 0xd, 0xc,
124 -1, -1, -1, -1, -1, -1, -1, -1,
125 -1, -1, -1, -1, -1, -1, -1, -1,
126 -1, -1, 0x3, 0x2, 0x0, 0x1, 0x9, 0x8,
127 -1, -1, 0x6, 0x7, -1, -1, -1, -1,
130 static const int8_t rot_codes[8] = {
141 static bool attr_w cgen_arm_push_pop(struct codegen_context *ctx, bool pop)
143 bool need_bx = false;
144 uint32_t mc = ARM_ALWAYS;
145 mc |= pop ? ARM_POP : ARM_PUSH;
146 #if defined(__thumb__) || defined(__thumb2__)
148 if (unlikely(!cpu_test_feature(CPU_FEATURE_armv5)))
161 mc |= 1U << (pop && !need_bx ? R_PC : R_LR);
164 mc = ARM_ALWAYS | ARM_BX;
171 static bool attr_w cgen_call_indirect(struct codegen_context *ctx)
175 uint8_t reg = cget_one(ctx);
177 #if defined(__thumb__) || defined(__thumb2__)
180 if (likely(cpu_test_feature(CPU_FEATURE_armv6)))
185 mc = ARM_ALWAYS | ARM_BLX_REG;
189 mc = ARM_ALWAYS | ARM_MOV;
190 mc |= (uint32_t)R_LR << 12;
194 mc = ARM_ALWAYS | ARM_MOV;
195 mc |= (uint32_t)R_PC << 12;
203 static bool attr_w cgen_ldr_str(struct codegen_context *ctx, bool ld, uint32_t cond, unsigned size, bool sx, uint8_t reg, uint8_t *address)
208 mc |= ARM_LDR_STR_LD;
209 if (size == OP_SIZE_NATIVE)
211 if (address[0] >= ARG_ADDRESS_2 && address[0] <= ARG_ADDRESS_2_8) {
212 imm = get_imm(&address[3]);
213 if (unlikely(imm != 0))
215 if (sx || size == OP_SIZE_2) {
216 if (unlikely(address[0] != ARG_ADDRESS_2))
219 mc |= size == OP_SIZE_2 ? ARM_LDRSH_REG : ARM_LDRSB_REG;
223 mc |= size == OP_SIZE_1 ? ARM_STRB_REG : ARM_STR_REG;
227 mc |= (uint32_t)address[1] << 16;
229 mc |= (uint32_t)reg << 12;
230 mc |= (uint32_t)(address[0] - ARG_ADDRESS_2) << 7;
234 if (address[0] == ARG_ADDRESS_1 || address[0] == ARG_ADDRESS_1_PRE_I || address[0] == ARG_ADDRESS_1_POST_I) {
235 imm = get_imm(&address[2]);
236 if (!(imm >= -4095 && imm <= 4095))
243 if (sx || size == OP_SIZE_2) {
244 if (unlikely(imm >= 256))
247 mc |= size == OP_SIZE_2 ? ARM_LDRSH_IMM : ARM_LDRSB_IMM;
251 mc |= (imm & 0xf0) << 4;
253 mc |= size == OP_SIZE_1 ? ARM_STRB_IMM : ARM_STR_IMM;
256 if (address[0] == ARG_ADDRESS_1) {
258 } else if (address[0] == ARG_ADDRESS_1_PRE_I) {
262 mc |= (uint32_t)address[1] << 16;
263 mc |= (uint32_t)reg << 12;
270 internal(file_line, "cgen_ldr_str: invalid address: %02x, %02x, %"PRIxMAX"", reg, address[0], (uintmax_t)imm);
274 static bool attr_w cgen_vldr_vstr(struct codegen_context *ctx, bool ld, uint32_t cond, unsigned size, uint8_t reg, uint8_t *address)
279 if (size < OP_SIZE_4) {
280 mc = ld ? ARM_VLD1 : ARM_VST1;
281 mc |= size == OP_SIZE_1 ? ARM_V_BYTE : ARM_V_HALF;
282 mc |= (uint32_t)address[1] << 16;
283 mc |= (uint32_t)(reg & 0x1e) << 11;
284 mc |= (uint32_t)(reg & 1) << 22;
290 mc |= ld ? ARM_VLDR : ARM_VSTR;
292 if (unlikely(address[0] != ARG_ADDRESS_1))
295 imm = get_imm(&address[2]);
296 if (!(imm >= -1023 && imm <= 1023))
305 mc |= (uint32_t)address[1] << 16;
306 mc |= (uint32_t)(reg & 0x1e) << 11;
307 mc |= (uint32_t)(reg & 1) << 22;
308 mc |= (imm >> 2) & 0xff;
309 if (size == OP_SIZE_8)
315 internal(file_line, "cgen_vldr_vstr: invalid address: %02x, %02x, %"PRIxMAX"", reg, address[0], (uintmax_t)imm);
319 static bool attr_w cgen_mov_args(struct codegen_context *ctx, uint32_t cond, unsigned size, bool sx, uint8_t *arg1, uint8_t *arg2)
326 internal(file_line, "cgen_mov_args: unsupported sign extension");
327 if (unlikely(size != OP_SIZE_NATIVE))
328 internal(file_line, "cgen_mov_args: unsupported size %u", size);
331 mc |= (uint32_t)arg1[0] << 12;
337 internal(file_line, "cgen_mov_args: unsupported sign extension");
338 if (unlikely(size != OP_SIZE_NATIVE))
339 internal(file_line, "cgen_mov_args: unsupported size %u", size);
340 mc = cond | ARM_VMOV_R_S32;
341 mc |= (uint32_t)(arg2[0] & 0x1e) << 15;
342 mc |= (uint32_t)(arg2[0] & 1) << 7;
343 mc |= (uint32_t)arg1[0] << 12;
347 if (arg2[0] == ARG_IMM) {
349 imm = get_imm(&arg2[1]);
350 imm12 = gen_imm12(imm);
352 mc = cond | ARM_MOV | ARM_ALU_IMM;
353 mc |= (uint32_t)arg1[0] << 12;
358 imm12 = gen_imm12(~imm);
360 mc = cond | ARM_MVN | ARM_ALU_IMM;
361 mc |= (uint32_t)arg1[0] << 12;
366 if ((uint32_t)imm >= 0x10000)
368 mc = cond | ARM_MOV_IMM16;
369 mc |= (uint32_t)arg1[0] << 12;
371 mc |= (imm & 0xf000) << 4;
375 return cgen_ldr_str(ctx, true, cond, size, sx, arg1[0], arg2);
380 internal(file_line, "cgen_mov_args: unsupported sign extension");
381 if (unlikely(size != OP_SIZE_NATIVE))
382 internal(file_line, "cgen_mov_args: unsupported size %u", size);
383 mc = cond | ARM_VMOV_S32_R;
384 mc |= (uint32_t)(arg1[0] & 0x1e) << 15;
385 mc |= (uint32_t)(arg1[0] & 1) << 7;
386 mc |= (uint32_t)arg2[0] << 12;
392 return cgen_vldr_vstr(ctx, true, cond, size, arg1[0] & 31, arg2);
395 return cgen_ldr_str(ctx, false, cond, size, false, arg2[0], arg1);
398 return cgen_vldr_vstr(ctx, false, cond, size, arg2[0] & 31, arg1);
401 internal(file_line, "cgen_mov_args: invalid arguments %02x, %02x", arg1[0], arg2[0]);
405 static bool attr_w cgen_mov(struct codegen_context *ctx, unsigned size, bool sx)
407 uint8_t *arg1 = ctx->code_position;
408 uint8_t *arg2 = arg1 + arg_size(*arg1);
409 ctx->code_position = arg2 + arg_size(*arg2);
410 g(cgen_mov_args(ctx, ARM_ALWAYS, size, sx, arg1, arg2));
414 static bool attr_w cgen_alu_args(struct codegen_context *ctx, unsigned writes_flags, uint32_t mc, uint8_t *arg1, uint8_t *arg2, uint8_t *arg3)
418 if (unlikely(arg1[0] >= 16))
420 if (unlikely(arg2[0] >= 16))
424 mc |= ARM_WRITE_FLAGS;
425 mc |= (uint32_t)arg1[0] << 12;
426 mc |= (uint32_t)arg2[0] << 16;
427 if (arg3[0] == ARG_IMM) {
428 imm = get_imm(&arg3[1]);
429 imm12 = gen_imm12(imm);
430 if (unlikely(imm12 < 0))
437 if (likely(arg3[0] < 16)) {
442 if (arg3[0] == ARG_SHIFTED_REGISTER) {
443 unsigned mode = arg3[1] >> 6;
444 unsigned amount = arg3[1] & ARG_SHIFT_AMOUNT;
448 mc |= (uint32_t)mode << 5;
449 mc |= ((uint32_t)amount & 0x1f) << 7;
455 internal(file_line, "cgen_alu_args: invalid arguments %02x, %02x, %02x, %08x, %u", arg1[0], arg2[0], arg3[0], (unsigned)mc, writes_flags);
459 static bool attr_w cgen_cmp(struct codegen_context *ctx, bool cmn)
462 uint8_t *arg1 = ctx->code_position;
463 uint8_t *arg2 = arg1 + arg_size(*arg1);
464 ctx->code_position = arg2 + arg_size(*arg2);
465 return cgen_alu_args(ctx, true, cmn ? ARM_CMN : ARM_CMP, &z, arg1, arg2);
468 static bool attr_w cgen_test(struct codegen_context *ctx)
471 uint8_t *arg1 = ctx->code_position;
472 uint8_t *arg2 = arg1 + arg_size(*arg1);
473 ctx->code_position = arg2 + arg_size(*arg2);
474 return cgen_alu_args(ctx, true, ARM_TST, &z, arg1, arg2);
477 static bool attr_w cgen_alu(struct codegen_context *ctx, unsigned writes_flags, unsigned alu)
479 uint8_t *arg1 = ctx->code_position;
480 uint8_t *arg2 = arg1 + arg_size(*arg1);
481 uint8_t *arg3 = arg2 + arg_size(*arg2);
482 ctx->code_position = arg3 + arg_size(*arg3);
483 if (unlikely(alu >= 7)) {
484 uint32_t mc = ARM_ALWAYS;
485 if (alu == ALU_ANDN) {
486 return cgen_alu_args(ctx, writes_flags, ARM_BIC, arg1, arg2, arg3);
487 } else if (alu == ALU_MUL) {
489 } else if (alu == ALU_UDIV) {
491 } else if (alu == ALU_SDIV) {
494 internal(file_line, "cgen_alu: invalid alu %u", alu);
496 mc |= (uint32_t)arg1[0] << 16;
498 mc |= (uint32_t)arg3[0] << 8;
502 return cgen_alu_args(ctx, writes_flags, alu_codes[alu], arg1, arg2, arg3);
505 static bool attr_w cgen_alu1(struct codegen_context *ctx, unsigned writes_flags, unsigned alu)
509 uint8_t z_imm[9] = { ARG_IMM, 0, 0, 0, 0, 0, 0, 0, 0 };
510 uint8_t one_imm[9] = { ARG_IMM, 1, 0, 0, 0, 0, 0, 0, 0 };
511 uint8_t *arg1 = ctx->code_position;
512 uint8_t *arg2 = arg1 + arg_size(*arg1);
513 ctx->code_position = arg2 + arg_size(*arg2);
516 return cgen_alu_args(ctx, writes_flags, ARM_MVN, arg1, &z, arg2);
518 return cgen_alu_args(ctx, writes_flags, ARM_RSB, arg1, arg2, z_imm);
520 return cgen_alu_args(ctx, writes_flags, ARM_RSC, arg1, arg2, z_imm);
522 return cgen_alu_args(ctx, writes_flags, ARM_ADD, arg1, arg2, one_imm);
524 return cgen_alu_args(ctx, writes_flags, ARM_SUB, arg1, arg2, one_imm);
526 mc = ARM_ALWAYS | ARM_REV;
529 mc = ARM_ALWAYS | ARM_REV16;
532 mc = ARM_ALWAYS | ARM_RBIT;
535 mc = ARM_ALWAYS | ARM_CLZ;
538 internal(file_line, "cgen_alu1: invalid alu %u", alu);
541 mc |= (uint32_t)arg1[0] << 12;
547 static bool attr_w cgen_rot(struct codegen_context *ctx, unsigned writes_flags, unsigned rot)
551 uint8_t *arg1 = ctx->code_position;
552 uint8_t *arg2 = arg1 + arg_size(*arg1);
553 uint8_t *arg3 = arg2 + arg_size(*arg2);
554 ctx->code_position = arg3 + arg_size(*arg3);
555 mc = ARM_ALWAYS | ARM_MOV;
557 mc |= ARM_WRITE_FLAGS;
558 arm_rot = rot_codes[rot];
559 if (unlikely(arm_rot < 0))
560 internal(file_line, "cgen_rot: invalid rotation %u", rot);
561 if (arg3[0] == ARG_IMM) {
562 uint8_t imm = arg3[1];
564 arm_rot = ARM_ROT_LSL;
565 mc |= (uint32_t)imm << 7;
567 mc |= ARM_ALU_REG_SHIFTED;
568 mc |= (uint32_t)arg3[0] << 8;
571 mc |= (uint32_t)arg1[0] << 12;
577 static bool attr_w cgen_mul_l(struct codegen_context *ctx, bool sgn)
580 uint8_t *arg1 = ctx->code_position;
581 uint8_t *arg2 = arg1 + arg_size(*arg1);
582 uint8_t *arg3 = arg2 + arg_size(*arg2);
583 uint8_t *arg4 = arg3 + arg_size(*arg3);
584 ctx->code_position = arg4 + arg_size(*arg4);
585 if (unlikely(arg1[0] >= 16) || unlikely(arg2[0] >= 16) || unlikely(arg3[0] >= 16) || unlikely(arg4[0] >= 16))
586 internal(file_line, "cgen_madd: invalid arguments");
588 mc |= sgn ? ARM_SMULL : ARM_UMULL;
589 mc |= (uint32_t)arg1[0] << 12;
590 mc |= (uint32_t)arg2[0] << 16;
592 mc |= (uint32_t)arg4[0] << 8;
597 static bool attr_w cgen_madd(struct codegen_context *ctx, bool sub)
600 uint8_t *arg1 = ctx->code_position;
601 uint8_t *arg2 = arg1 + arg_size(*arg1);
602 uint8_t *arg3 = arg2 + arg_size(*arg2);
603 uint8_t *arg4 = arg3 + arg_size(*arg3);
604 ctx->code_position = arg4 + arg_size(*arg4);
605 if (unlikely(arg1[0] >= 16) || unlikely(arg2[0] >= 16) || unlikely(arg3[0] >= 16) || unlikely(arg4[0] >= 16))
606 internal(file_line, "cgen_madd: invalid arguments");
608 mc |= sub ? ARM_MLS : ARM_MLA;
609 mc |= (uint32_t)arg1[0] << 16;
611 mc |= (uint32_t)arg3[0] << 8;
612 mc |= (uint32_t)arg4[0] << 12;
617 static bool attr_w cgen_cmov(struct codegen_context *ctx, unsigned size, unsigned aux)
620 uint8_t *arg1 = ctx->code_position;
621 uint8_t *arg2 = arg1 + arg_size(*arg1);
622 uint8_t *arg3 = arg2 + arg_size(*arg2);
623 ctx->code_position = arg3 + arg_size(*arg3);
624 if (unlikely(arg1[0] != arg2[0]))
625 internal(file_line, "cgen_cmov: invalid arguments");
626 cond = jmp_cond[aux];
627 if (unlikely(cond < 0))
628 internal(file_line, "cgen_cmov: invalid condition %u", aux);
629 g(cgen_mov_args(ctx, (uint32_t)cond << 28, size, false, arg1, arg3));
633 static bool attr_w cgen_ldp_stp(struct codegen_context *ctx, bool ldr)
635 uint8_t *arg1, *arg2, *arg3;
637 uint32_t mc = ARM_ALWAYS;
639 arg1 = ctx->code_position;
640 arg2 = arg1 + arg_size(*arg1);
641 arg3 = arg2 + arg_size(*arg2);
642 ctx->code_position = arg3 + arg_size(*arg3);
644 arg2 = ctx->code_position;
645 arg3 = arg2 + arg_size(*arg2);
646 arg1 = arg3 + arg_size(*arg3);
647 ctx->code_position = arg1 + arg_size(*arg1);
649 if (unlikely(arg2[0] >= 16) || unlikely(arg3[0] >= 16))
651 if (unlikely((arg2[0] & 1) != 0) || unlikely(arg3[0] != arg2[0] + 1))
653 if (arg1[0] == ARG_ADDRESS_1 || arg1[0] == ARG_ADDRESS_1_PRE_I || arg1[0] == ARG_ADDRESS_1_POST_I) {
654 mc |= !ldr ? ARM_STRD_IMM : ARM_LDRD_IMM;
655 if (arg1[0] == ARG_ADDRESS_1) {
657 } else if (arg1[0] == ARG_ADDRESS_1_PRE_I) {
661 imm = get_imm(&arg1[2]);
662 if (!(imm >= -255 && imm <= 255))
670 mc |= (imm & 0xf0) << 4;
671 } else if (arg1[0] == ARG_ADDRESS_2) {
672 imm = get_imm(&arg1[3]);
673 if (unlikely(imm != 0))
675 mc |= !ldr ? ARM_STRD_REG : ARM_LDRD_REG;
682 mc |= (uint32_t)arg1[1] << 16;
683 mc |= (uint32_t)arg2[0] << 12;
688 internal(file_line, "cgen_ldp_stp: invalid arguments %02x, %02x, %02x", arg1[0], arg2[0], arg3[0]);
692 static bool attr_w cgen_mov_mask(struct codegen_context *ctx, unsigned aux)
696 uint8_t *arg1 = ctx->code_position;
697 uint8_t *arg2 = arg1 + arg_size(*arg1);
698 uint8_t *arg3 = arg2 + arg_size(*arg2);
699 ctx->code_position = arg3 + arg_size(*arg3);
700 if (unlikely(arg1[0] >= 16) || unlikely(arg2[0] >= 16) || unlikely(arg3[0] != ARG_IMM) || unlikely(aux != MOV_MASK_16_32))
701 internal(file_line, "cgen_mov_mask: bad arguments");
702 imm = get_imm(&arg3[1]);
703 if (unlikely(imm >= 0x10000))
704 internal(file_line, "cgen_mov_mask: bad number");
705 mc = ARM_ALWAYS | ARM_MOVT;
706 mc |= (uint32_t)arg1[0] << 12;
708 mc |= (imm & 0xf000) << 4;
713 static bool attr_w cgen_fp_cmp(struct codegen_context *ctx, unsigned op_size)
716 uint8_t *arg1 = ctx->code_position;
717 uint8_t *arg2 = arg1 + arg_size(*arg1);
718 ctx->code_position = arg2 + arg_size(*arg2);
722 case OP_SIZE_4: break;
723 case OP_SIZE_8: mc |= ARM_V_D; break;
724 default: internal(file_line, "cgen_fp_cmp: invalid size %u", op_size);
726 mc |= (uint32_t)(arg1[0] & 0x1e) << 11;
727 mc |= (uint32_t)(arg1[0] & 1) << 22;
728 mc |= (uint32_t)(arg2[0] & 0x1e) >> 1;
729 mc |= (uint32_t)(arg2[0] & 1) << 5;
734 static bool attr_w cgen_fp_alu(struct codegen_context *ctx, unsigned op_size, unsigned aux)
737 uint8_t *arg1 = ctx->code_position;
738 uint8_t *arg2 = arg1 + arg_size(*arg1);
739 uint8_t *arg3 = arg2 + arg_size(*arg2);
740 ctx->code_position = arg3 + arg_size(*arg3);
743 case FP_ALU_ADD: mc |= ARM_VADD; break;
744 case FP_ALU_SUB: mc |= ARM_VSUB; break;
745 case FP_ALU_MUL: mc |= ARM_VMUL; break;
746 case FP_ALU_DIV: mc |= ARM_VDIV; break;
747 default: internal(file_line, "cgen_fp_alu: invalid alu %u", aux);
750 case OP_SIZE_4: break;
751 case OP_SIZE_8: mc |= ARM_V_D; break;
752 default: internal(file_line, "cgen_fp_alu: invalid size %u", op_size);
754 mc |= (uint32_t)(arg1[0] & 0x1e) << 11;
755 mc |= (uint32_t)(arg1[0] & 1) << 22;
756 mc |= (uint32_t)(arg2[0] & 0x1e) << 15;
757 mc |= (uint32_t)(arg2[0] & 1) << 7;
758 mc |= (uint32_t)(arg3[0] & 0x1e) >> 1;
759 mc |= (uint32_t)(arg3[0] & 1) << 5;
764 static bool attr_w cgen_fp_alu1(struct codegen_context *ctx, unsigned op_size, unsigned aux)
767 uint8_t *arg1 = ctx->code_position;
768 uint8_t *arg2 = arg1 + arg_size(*arg1);
769 ctx->code_position = arg2 + arg_size(*arg2);
771 case FP_ALU1_NEG: mc = ARM_ALWAYS | ARM_VNEG; break;
772 case FP_ALU1_SQRT: mc = ARM_ALWAYS | ARM_VSQRT; break;
773 case FP_ALU1_VCNT8: mc = ARM_VCNT_8; goto do_regs;
774 case FP_ALU1_VPADDL: mc = op_size == OP_SIZE_1 ? ARM_VPADDL_U8 : op_size == OP_SIZE_2 ? ARM_VPADDL_U16 : op_size == OP_SIZE_4 ? ARM_VPADDL_U32 : 0;
778 default: internal(file_line, "cgen_fp_alu1: invalid alu %u", aux);
781 case OP_SIZE_4: break;
782 case OP_SIZE_8: mc |= ARM_V_D; break;
784 default: internal(file_line, "cgen_fp_alu1: invalid size %u", op_size);
787 mc |= (uint32_t)(arg1[0] & 0x1e) << 11;
788 mc |= (uint32_t)(arg1[0] & 1) << 22;
789 mc |= (uint32_t)(arg2[0] & 0x1e) >> 1;
790 mc |= (uint32_t)(arg2[0] & 1) << 5;
795 static bool attr_w cgen_fp_to_int(struct codegen_context *ctx, unsigned fp_op_size)
798 uint8_t *arg1 = ctx->code_position;
799 uint8_t *arg2 = arg1 + arg_size(*arg1);
800 ctx->code_position = arg2 + arg_size(*arg2);
802 mc |= ARM_VCVT_S32_F;
803 switch (fp_op_size) {
804 case OP_SIZE_4: break;
805 case OP_SIZE_8: mc |= ARM_V_D; break;
806 default: internal(file_line, "cgen_fp_to_int: invalid size %u", fp_op_size);
808 mc |= (uint32_t)(arg1[0] & 0x1e) << 11;
809 mc |= (uint32_t)(arg1[0] & 1) << 22;
810 mc |= (uint32_t)(arg2[0] & 0x1e) >> 1;
811 mc |= (uint32_t)(arg2[0] & 1) << 5;
816 static bool attr_w cgen_fp_from_int(struct codegen_context *ctx, unsigned fp_op_size)
819 uint8_t *arg1 = ctx->code_position;
820 uint8_t *arg2 = arg1 + arg_size(*arg1);
821 ctx->code_position = arg2 + arg_size(*arg2);
823 mc |= ARM_VCVT_F_S32;
824 switch (fp_op_size) {
825 case OP_SIZE_4: break;
826 case OP_SIZE_8: mc |= ARM_V_D; break;
827 default: internal(file_line, "cgen_fp_from_int: invalid size %u", fp_op_size);
829 mc |= (uint32_t)(arg1[0] & 0x1e) << 11;
830 mc |= (uint32_t)(arg1[0] & 1) << 22;
831 mc |= (uint32_t)(arg2[0] & 0x1e) >> 1;
832 mc |= (uint32_t)(arg2[0] & 1) << 5;
837 static bool attr_w cgen_fp_cvt(struct codegen_context *ctx, unsigned from_op_size, unsigned to_op_size)
840 uint8_t *arg1 = ctx->code_position;
841 uint8_t *arg2 = arg1 + arg_size(*arg1);
842 ctx->code_position = arg2 + arg_size(*arg2);
844 if (from_op_size == OP_SIZE_2 && to_op_size == OP_SIZE_4) {
845 mc |= ARM_VCVT_F32_F16;
846 } else if (from_op_size == OP_SIZE_4 && to_op_size == OP_SIZE_2) {
847 mc |= ARM_VCVT_F16_F32;
849 internal(file_line, "cgen_fp_cvt: invalid types %u, %u", from_op_size, to_op_size);
851 mc |= (uint32_t)(arg1[0] & 0x1e) << 11;
852 mc |= (uint32_t)(arg1[0] & 1) << 22;
853 mc |= (uint32_t)(arg2[0] & 0x1e) >> 1;
854 mc |= (uint32_t)(arg2[0] & 1) << 5;
859 static bool attr_w cgen_jmp_cond(struct codegen_context *ctx, unsigned aux, unsigned length)
863 if (unlikely(length != JMP_SHORTEST))
864 internal(file_line, "cgen_jmp_cond: invalid length %u", length);
865 cond = jmp_cond[aux];
866 if (unlikely(cond < 0))
867 internal(file_line, "cgen_jmp_cond: invalid condition %u", aux);
868 g(add_relocation(ctx, JMP_SHORTEST, 0, NULL));
869 mc = (uint32_t)cond << 28;
875 static bool attr_w cgen_jmp_indirect(struct codegen_context *ctx)
878 uint8_t *arg1 = ctx->code_position;
879 ctx->code_position = arg1 + arg_size(*arg1);
880 g(cgen_mov_args(ctx, ARM_ALWAYS, OP_SIZE_ADDRESS, false, &pc, arg1));
884 static bool attr_w resolve_relocation(struct codegen_context *ctx, struct relocation *reloc)
887 int64_t offs = (int64_t)(ctx->label_to_pos[reloc->label_id] >> 2) - (int64_t)(reloc->position >> 2) - 2;
888 switch (reloc->length) {
890 if (unlikely(offs < -0x00800000) || unlikely(offs >= 0x00800000))
892 memcpy(&mc, ctx->mcode + reloc->position, 4);
894 mc |= offs & 0x00ffffffU;
895 memcpy(ctx->mcode + reloc->position, &mc, 4);
898 internal(file_line, "resolve_relocation: invalid relocation length %u", reloc->length);
903 static bool attr_w cgen_insn(struct codegen_context *ctx, uint32_t insn)
905 /*debug("insn: %08x (%s)", insn, da(ctx->fn,function)->function_name);*/
906 switch (insn_opcode(insn)) {
915 g(cgen_arm_push_pop(ctx, insn_opcode(insn) == INSN_ARM_POP));
917 case INSN_CALL_INDIRECT:
918 g(cgen_call_indirect(ctx));
921 g(cgen_mov(ctx, insn_op_size(insn), false));
924 g(cgen_mov(ctx, insn_op_size(insn), true));
927 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
929 g(cgen_cmp(ctx, false));
932 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
934 g(cgen_cmp(ctx, true));
937 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
943 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
945 g(cgen_alu(ctx, insn_writes_flags(insn), insn_aux(insn)));
948 case INSN_ALU1_FLAGS:
949 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
951 g(cgen_alu1(ctx, insn_writes_flags(insn), insn_aux(insn)));
954 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
956 g(cgen_rot(ctx, insn_writes_flags(insn), insn_aux(insn)));
959 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
961 g(cgen_mul_l(ctx, insn_aux(insn)));
964 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
966 g(cgen_madd(ctx, insn_aux(insn)));
969 g(cgen_cmov(ctx, insn_op_size(insn), insn_aux(insn)));
973 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
975 g(cgen_ldp_stp(ctx, insn_opcode(insn) == INSN_LDP));
978 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
980 g(cgen_mov_mask(ctx, insn_aux(insn)));
983 g(cgen_fp_cmp(ctx, insn_op_size(insn)));
985 case INSN_FP_TO_INT_FLAGS:
986 cgen_four(ARM_ALWAYS | ARM_VMRS_NZCV_FPSCR);
989 g(cgen_fp_alu(ctx, insn_op_size(insn), insn_aux(insn)));
992 g(cgen_fp_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
994 case INSN_FP_TO_INT32:
995 g(cgen_fp_to_int(ctx, insn_op_size(insn)));
997 case INSN_FP_FROM_INT32:
998 g(cgen_fp_from_int(ctx, insn_op_size(insn)));
1001 g(cgen_fp_cvt(ctx, insn_op_size(insn), insn_aux(insn)));
1004 g(add_relocation(ctx, JMP_SHORTEST, 0, NULL));
1005 cgen_four(ARM_ALWAYS | ARM_B);
1008 g(cgen_jmp_cond(ctx, insn_aux(insn), insn_jump_size(insn)));
1010 case INSN_JMP_INDIRECT:
1011 g(cgen_jmp_indirect(ctx));
1015 internal(file_line, "cgen_insn: invalid insn %08x", insn);