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 SPARC_IMM_BIT 0x00002000U
20 #define SPARC_CC_BIT 0x00800000U
22 #define SPARC_BPCC 0x00400000U
23 #define SPARC_BPCC_P 0x00080000U
24 #define SPARC_BPCC_64 0x00200000U
25 #define SPARC_BPCC_A 0x20000000U
26 #define SPARC_BCC 0x00800000U
27 #define SPARC_BCC_A 0x20000000U
28 #define SPARC_BR 0x00c00000U
29 #define SPARC_BR_BRZ 0x02000000U
30 #define SPARC_BR_BRLEZ 0x04000000U
31 #define SPARC_BR_BRLZ 0x06000000U
32 #define SPARC_BR_BRNZ 0x0a000000U
33 #define SPARC_BR_GZ 0x0c000000U
34 #define SPARC_BR_GEZ 0x0e000000U
35 #define SPARC_BR_A 0x20000000U
36 #define SPARC_NOP 0x01000000U
37 #define SPARC_SETHI 0x01000000U
38 #define SPARC_FBPCC 0x01400000U
39 #define SPARC_FBPCC_P 0x00080000U
40 #define SPARC_FBPCC_CC0 0x00100000U
41 #define SPARC_FBPCC_CC1 0x00200000U
42 #define SPARC_FBPCC_A 0x20000000U
43 #define SPARC_FBCC 0x01800000U
44 #define SPARC_FBCC_A 0x20000000U
46 #define SPARC_ADD 0x80000000U
47 #define SPARC_AND 0x80080000U
48 #define SPARC_OR 0x80100000U
49 #define SPARC_XOR 0x80180000U
50 #define SPARC_SUB 0x80200000U
51 #define SPARC_ANDN 0x80280000U
52 #define SPARC_ORN 0x80300000U
53 #define SPARC_XORN 0x80380000U
54 #define SPARC_ADDC 0x80400000U
55 #define SPARC_MULX 0x80480000U
56 #define SPARC_SUBC 0x80600000U
57 #define SPARC_UDIVX 0x80680000U
58 #define SPARC_SLL 0x81280000U
59 #define SPARC_SRL 0x81300000U
60 #define SPARC_SRA 0x81380000U
61 #define SPARC_S_64 0x00001000U
62 #define SPARC_CMOV 0x81600000U
63 #define SPARC_CMOV_FCC0 0x00000000U
64 #define SPARC_CMOV_FCC1 0x00000800U
65 #define SPARC_CMOV_FCC2 0x00001000U
66 #define SPARC_CMOV_FCC3 0x00001800U
67 #define SPARC_CMOV_ICC 0x00040000U
68 #define SPARC_CMOV_XCC 0x00041000U
69 #define SPARC_SDIVX 0x81680000U
70 #define SPARC_POPC 0x81700000U
71 #define SPARC_MOVR 0x81780000U
72 #define SPARC_MOVR_Z 0x00000400U
73 #define SPARC_MOVR_LEZ 0x00000800U
74 #define SPARC_MOVR_LZ 0x00000c00U
75 #define SPARC_MOVR_NZ 0x00001400U
76 #define SPARC_MOVR_GZ 0x00001800U
77 #define SPARC_MOVR_GEZ 0x00001c00U
78 #define SPARC_FMOV 0x81a00000U
79 #define SPARC_FNEG 0x81a00080U
80 #define SPARC_FSQRT 0x81a00500U
81 #define SPARC_FADD 0x81a00800U
82 #define SPARC_FSUB 0x81a00880U
83 #define SPARC_FMUL 0x81a00900U
84 #define SPARC_FDIV 0x81a00980U
85 #define SPARC_FP_SINGLE 0x00000020U
86 #define SPARC_FP_DOUBLE 0x00000040U
87 #define SPARC_FP_QUAD 0x00000060U
88 #define SPARC_FTOI 0x81a01000U
89 #define SPARC_FTOI_32 0x00000a00U
90 #define SPARC_FTOI_64 0x00000000U
91 #define SPARC_FTOI_SINGLE 0x00000020U
92 #define SPARC_FTOI_DOUBLE 0x00000040U
93 #define SPARC_FTOI_QUAD 0x00000060U
94 #define SPARC_ITOF 0x81a01000U
95 #define SPARC_ITOF_64 0x00000000U
96 #define SPARC_ITOF_32 0x00000800U
97 #define SPARC_ITOF_SINGLE 0x00000080U
98 #define SPARC_ITOF_DOUBLE 0x00000100U
99 #define SPARC_ITOF_QUAD 0x00000180U
100 #define SPARC_FCMP 0x81a80a00U
101 #define SPARC_FCMP_CC0 0x02000000U
102 #define SPARC_FCMP_CC1 0x04000000U
103 #define SPARC_FCMP_SINGLE 0x00000020U
104 #define SPARC_FCMP_DOUBLE 0x00000040U
105 #define SPARC_FCMP_QUAD 0x00000060U
106 #define SPARC_JMPL 0x81c00000U
107 #define SPARC_RETURN 0x81c80000U
108 #define SPARC_SAVE 0x81e00000U
109 #define SPARC_RESTORE 0x81e80000U
111 #define SPARC_LDUW 0xc0000000U
112 #define SPARC_LDUB 0xc0080000U
113 #define SPARC_LDUH 0xc0100000U
114 #define SPARC_LDD 0xc0180000U
115 #define SPARC_STW 0xc0200000U
116 #define SPARC_STB 0xc0280000U
117 #define SPARC_STH 0xc0300000U
118 #define SPARC_STD 0xc0380000U
119 #define SPARC_LDSW 0xc0400000U
120 #define SPARC_LDSB 0xc0480000U
121 #define SPARC_LDSH 0xc0500000U
122 #define SPARC_LDX 0xc0580000U
123 #define SPARC_STX 0xc0700000U
124 #define SPARC_LDF 0xc1000000U
125 #define SPARC_STF 0xc1200000U
126 #define SPARC_LDSTF_SINGLE 0x00000000U
127 #define SPARC_LDSTF_DOUBLE 0x00180000U
128 #define SPARC_LDSTF_QUAD 0x00100000U
131 static const int8_t jmp_cond[48] = {
132 0x7, 0xf, 0x5, 0xd, 0x1, 0x9, 0x4, 0xc,
133 0x6, 0xe, -1, -1, 0x3, 0xb, 0x2, 0xa,
134 -1, -1, -1, -1, -1, -1, -1, -1,
135 -1, -1, -1, -1, -1, -1, -1, -1,
136 -1, -1, 0x4, 0xb, 0x9, 0x2, 0xd, 0x6,
137 -1, -1, 0x7, 0xf, -1, -1, -1, -1,
140 static const uint32_t alu_map[24] = {
167 #define cgen_sparc_3reg(mc, rd, rs1, rs2) \
168 cgen_four((mc) | ((uint32_t)(rd) << 25) | ((uint32_t)((rs1) << 14)) | (rs2))
169 #define cgen_sparc_imm(mc, rd, rs1, imm) \
170 cgen_four((mc) | SPARC_IMM_BIT | ((uint32_t)(rd) << 25) | ((uint32_t)((rs1) << 14)) | ((imm) & 8191))
172 static bool attr_w cgen_ld_st(struct codegen_context *ctx, uint32_t mc, uint8_t reg, uint8_t *address)
175 if (address[0] == ARG_ADDRESS_2) {
176 imm = get_imm(&address[3]);
177 if (unlikely(imm != 0))
179 cgen_sparc_3reg(mc, reg, address[1], address[2]);
181 } else if (address[0] == ARG_ADDRESS_1) {
182 imm = get_imm(&address[2]);
183 if (unlikely(imm < -4096) || unlikely(imm >= 4096))
185 cgen_sparc_imm(mc, reg, address[1], imm);
192 internal(file_line, "cgen_ld_st: invalid address: %02x, %02x, %"PRIxMAX"", reg, address[0], (uintmax_t)imm);
196 static bool attr_w cgen_mov(struct codegen_context *ctx, unsigned size, bool sx)
199 uint8_t *arg1 = ctx->code_position;
200 uint8_t *arg2 = arg1 + arg_size(*arg1);
201 ctx->code_position = arg2 + arg_size(*arg2);
204 if (unlikely(size != OP_SIZE_NATIVE))
205 internal(file_line, "cgen_mov: unsupported size %u", size);
206 cgen_sparc_3reg(SPARC_OR, arg1[0], arg2[0], R_ZERO);
209 if (arg2[0] == ARG_IMM) {
210 imm = get_imm(&arg2[1]);
211 if (imm >= -4096 && imm < 4096) {
212 cgen_sparc_imm(SPARC_OR, arg1[0], R_ZERO, imm);
214 if (imm & ~0xfffffc00ULL)
215 internal(file_line, "cgen_mov: invalid imm");
216 cgen_four(SPARC_SETHI | ((uint32_t)arg1[0] << 25) | imm >> 10);
220 if (arg2[0] == ARG_ADDRESS_1 || arg2[0] == ARG_ADDRESS_2) {
221 if (!sx || size == OP_SIZE_NATIVE) {
222 return cgen_ld_st(ctx, size == OP_SIZE_1 ? SPARC_LDUB : size == OP_SIZE_2 ? SPARC_LDUH : size == OP_SIZE_4 ? SPARC_LDUW : SPARC_LDX, arg1[0], arg2);
224 return cgen_ld_st(ctx, size == OP_SIZE_1 ? SPARC_LDSB : size == OP_SIZE_2 ? SPARC_LDSH : SPARC_LDSW, arg1[0], arg2);
228 if (reg_is_fp(arg1[0])) {
229 if (reg_is_fp(arg2[0])) {
230 uint32_t mc = SPARC_FMOV;
232 case OP_SIZE_4: mc |= SPARC_FP_SINGLE; break;
233 case OP_SIZE_8: mc |= SPARC_FP_DOUBLE; break;
234 case OP_SIZE_16: mc |= SPARC_FP_QUAD; break;
235 default: internal(file_line, "cgen_mov: invalid size %u", size);
237 cgen_sparc_3reg(mc, arg1[0] & 31, 0, arg2[0] & 31);
240 return cgen_ld_st(ctx, SPARC_LDF | (size == OP_SIZE_4 ? SPARC_LDSTF_SINGLE : size == OP_SIZE_8 ? SPARC_LDSTF_DOUBLE : SPARC_LDSTF_QUAD), arg1[0] & 31, arg2);
243 return cgen_ld_st(ctx, size == OP_SIZE_1 ? SPARC_STB : size == OP_SIZE_2 ? SPARC_STH : size == OP_SIZE_4 ? SPARC_STW : SPARC_STX, arg2[0], arg1);
245 if (reg_is_fp(arg2[0])) {
246 return cgen_ld_st(ctx, SPARC_STF | (size == OP_SIZE_4 ? SPARC_LDSTF_SINGLE : size == OP_SIZE_8 ? SPARC_LDSTF_DOUBLE : SPARC_LDSTF_QUAD), arg2[0] & 31, arg1);
248 if (arg2[0] == ARG_IMM) {
249 imm = get_imm(&arg2[1]);
251 return cgen_ld_st(ctx, size == OP_SIZE_1 ? SPARC_STB : size == OP_SIZE_2 ? SPARC_STH : size == OP_SIZE_4 ? SPARC_STW : SPARC_STX, R_ZERO, arg1);
253 internal(file_line, "cgen_mov: invalid arguments %02x, %02x", arg1[0], arg2[0]);
257 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)
261 if (unlikely(arg1[0] >= 32) || unlikely(arg2[0] >= 32))
267 if (arg3[0] == ARG_IMM) {
268 imm = get_imm(&arg3[1]);
269 if (unlikely(imm < -4096) || unlikely(imm >= 4096))
271 cgen_sparc_imm(mc, arg1[0], arg2[0], imm);
273 } else if (likely(arg3[0] < 32)) {
274 cgen_sparc_3reg(mc, arg1[0], arg2[0], arg3[0]);
279 internal(file_line, "cgen_alu_args: invalid arguments %02x, %02x, %02x, %08x, %u", arg1[0], arg2[0], arg3[0], (uint32_t)mc, writes_flags);
283 static bool attr_w cgen_cmp(struct codegen_context *ctx, uint32_t mc)
286 uint8_t *arg1 = ctx->code_position;
287 uint8_t *arg2 = arg1 + arg_size(*arg1);
288 ctx->code_position = arg2 + arg_size(*arg2);
289 return cgen_alu_args(ctx, true, mc, &z, arg1, arg2);
292 static bool attr_w cgen_alu(struct codegen_context *ctx, unsigned writes_flags, unsigned alu)
295 uint8_t *arg1 = ctx->code_position;
296 uint8_t *arg2 = arg1 + arg_size(*arg1);
297 uint8_t *arg3 = arg2 + arg_size(*arg2);
298 ctx->code_position = arg3 + arg_size(*arg3);
300 if (unlikely(alu >= 16) && unlikely(writes_flags))
301 internal(file_line, "cgen_alu: alu %u can't write flags", alu);
303 ajla_assert_lo(alu < n_array_elements(alu_map), (file_line, "cgen_alu: invalid alu %u", alu));
305 if (unlikely(mc == (uint32_t)-1))
306 internal(file_line, "cgen_alu: invalid alu %u", alu);
308 return cgen_alu_args(ctx, writes_flags, mc, arg1, arg2, arg3);
311 static bool attr_w cgen_alu1(struct codegen_context *ctx, unsigned writes_flags, uint8_t alu)
314 uint8_t one_imm[9] = { ARG_IMM, 1, 0, 0, 0, 0, 0, 0, 0 };
315 uint8_t *arg1 = ctx->code_position;
316 uint8_t *arg2 = arg1 + arg_size(*arg1);
317 ctx->code_position = arg2 + arg_size(*arg2);
320 g(cgen_alu_args(ctx, writes_flags, SPARC_XORN, arg1, arg2, &z));
323 g(cgen_alu_args(ctx, writes_flags, SPARC_SUB, arg1, &z, arg2));
326 g(cgen_alu_args(ctx, writes_flags, SPARC_ADD, arg1, arg2, one_imm));
329 g(cgen_alu_args(ctx, writes_flags, SPARC_SUB, arg1, arg2, one_imm));
332 g(cgen_alu_args(ctx, writes_flags, SPARC_POPC, arg1, &z, arg2));
335 internal(file_line, "cgen_alu1: invalid operation %u", alu);
340 static bool attr_w cgen_rot(struct codegen_context *ctx, unsigned size, uint8_t rot)
344 uint8_t *arg1 = ctx->code_position;
345 uint8_t *arg2 = arg1 + arg_size(*arg1);
346 uint8_t *arg3 = arg2 + arg_size(*arg2);
347 ctx->code_position = arg3 + arg_size(*arg3);
349 if (unlikely(arg1[0] >= 32) || unlikely(arg2[0] >= 32) || unlikely(size < OP_SIZE_4) || unlikely(size > OP_SIZE_8))
353 case ROT_SHL: mc = SPARC_SLL; break;
354 case ROT_SHR: mc = SPARC_SRL; break;
355 case ROT_SAR: mc = SPARC_SRA; break;
360 if (size == OP_SIZE_8)
363 if (arg3[0] == ARG_IMM) {
364 imm = get_imm(&arg3[1]);
365 if (unlikely(imm < 0) || unlikely(imm >= (size == OP_SIZE_4 ? 32 : 64)))
367 cgen_sparc_imm(mc, arg1[0], arg2[0], imm);
370 cgen_sparc_3reg(mc, arg1[0], arg2[0], arg3[0]);
375 internal(file_line, "cgen_rot: invalid arguments: %02x, %02x, %02x, %u, %u", arg1[0], arg2[0], arg3[0], size, rot);
379 static bool attr_w cgen_cmov(struct codegen_context *ctx, unsigned aux, bool xcc)
383 uint8_t *arg1 = ctx->code_position;
384 uint8_t *arg2 = arg1 + arg_size(*arg1);
385 uint8_t *arg3 = arg2 + arg_size(*arg2);
386 ctx->code_position = arg3 + arg_size(*arg3);
387 if (unlikely(arg1[0] != arg2[0]))
388 internal(file_line, "cgen_cmov: invalid arguments");
390 cond = jmp_cond[aux];
391 if (unlikely(cond < 0))
392 internal(file_line, "cgen_cmov: invalid condition %u", aux);
394 mc |= SPARC_CMOV_FCC0;
396 mc |= xcc ? SPARC_CMOV_XCC : SPARC_CMOV_ICC;
398 mc |= (uint32_t)arg1[0] << 25;
399 mc |= (uint32_t)cond << 14;
400 if (arg3[0] == ARG_IMM) {
401 int64_t imm = get_imm(&arg3[1]);
411 static bool attr_w cgen_movr(struct codegen_context *ctx, unsigned aux)
413 uint32_t mc = SPARC_MOVR;
414 uint8_t *arg1 = ctx->code_position;
415 uint8_t *arg2 = arg1 + arg_size(*arg1);
416 uint8_t *arg3 = arg2 + arg_size(*arg2);
417 uint8_t *arg4 = arg3 + arg_size(*arg3);
418 ctx->code_position = arg4 + arg_size(*arg4);
420 case COND_E: mc |= SPARC_MOVR_Z; break;
421 case COND_LE: mc |= SPARC_MOVR_LEZ; break;
422 case COND_L: mc |= SPARC_MOVR_LZ; break;
423 case COND_NE: mc |= SPARC_MOVR_NZ; break;
424 case COND_G: mc |= SPARC_MOVR_GZ; break;
425 case COND_GE: mc |= SPARC_MOVR_GEZ; break;
426 default: internal(file_line, "cgen_movr: invalid condition %u", aux);
428 if (unlikely(arg1[0] != arg2[0]))
429 internal(file_line, "cgen_movr: invalid arguments");
430 mc |= (uint32_t)arg1[0] << 25;
431 mc |= (uint32_t)arg3[0] << 14;
432 if (arg4[0] == ARG_IMM) {
433 int64_t imm = get_imm(&arg4[1]);
443 static bool attr_w cgen_ldp_stp(struct codegen_context *ctx, bool ldr)
445 uint8_t *arg1, *arg2, *arg3;
447 arg1 = ctx->code_position;
448 arg2 = arg1 + arg_size(*arg1);
449 arg3 = arg2 + arg_size(*arg2);
450 ctx->code_position = arg3 + arg_size(*arg3);
452 arg2 = ctx->code_position;
453 arg3 = arg2 + arg_size(*arg2);
454 arg1 = arg3 + arg_size(*arg3);
455 ctx->code_position = arg1 + arg_size(*arg1);
457 if (unlikely(arg2[0] >= 32) || unlikely(arg3[0] >= 32))
459 if (unlikely((arg3[0] & 1) != 0) || unlikely(arg2[0] != arg3[0] + 1))
463 return cgen_ld_st(ctx, SPARC_LDD, arg3[0], arg1);
465 return cgen_ld_st(ctx, SPARC_STD, arg3[0], arg1);
468 internal(file_line, "cgen_ldp_stp: invalid arguments %02x, %02x, %02x", arg1[0], arg2[0], arg3[0]);
472 static bool attr_w cgen_fp_cmp(struct codegen_context *ctx, unsigned op_size)
475 uint8_t *arg1 = ctx->code_position;
476 uint8_t *arg2 = arg1 + arg_size(*arg1);
477 ctx->code_position = arg2 + arg_size(*arg2);
480 case OP_SIZE_4: mc |= SPARC_FCMP_SINGLE; break;
481 case OP_SIZE_8: mc |= SPARC_FCMP_DOUBLE; break;
482 case OP_SIZE_16: mc |= SPARC_FCMP_QUAD; break;
483 default: internal(file_line, "cgen_fp_cmp: invalid size %u", op_size);
485 cgen_sparc_3reg(mc, 0, arg1[0] & 31, arg2[0] & 31);
489 static bool attr_w cgen_fp_alu(struct codegen_context *ctx, unsigned op_size, unsigned aux)
492 uint8_t *arg1 = ctx->code_position;
493 uint8_t *arg2 = arg1 + arg_size(*arg1);
494 uint8_t *arg3 = arg2 + arg_size(*arg2);
495 ctx->code_position = arg3 + arg_size(*arg3);
497 case FP_ALU_ADD: mc = SPARC_FADD; break;
498 case FP_ALU_SUB: mc = SPARC_FSUB; break;
499 case FP_ALU_MUL: mc = SPARC_FMUL; break;
500 case FP_ALU_DIV: mc = SPARC_FDIV; break;
501 default: internal(file_line, "cgen_fp_alu: invalid alu %u", aux);
504 case OP_SIZE_4: mc |= SPARC_FP_SINGLE; break;
505 case OP_SIZE_8: mc |= SPARC_FP_DOUBLE; break;
506 case OP_SIZE_16: mc |= SPARC_FP_QUAD; break;
507 default: internal(file_line, "cgen_fp_alu: invalid size %u", op_size);
509 cgen_sparc_3reg(mc, arg1[0] & 31, arg2[0] & 31, arg3[0] & 31);
513 static bool attr_w cgen_fp_alu1(struct codegen_context *ctx, unsigned op_size, unsigned aux)
516 uint8_t *arg1 = ctx->code_position;
517 uint8_t *arg2 = arg1 + arg_size(*arg1);
518 ctx->code_position = arg2 + arg_size(*arg2);
520 case FP_ALU1_NEG: mc = SPARC_FNEG; break;
521 case FP_ALU1_SQRT: mc = SPARC_FSQRT; break;
522 default: internal(file_line, "cgen_fp_alu1: invalid alu %u", aux);
525 case OP_SIZE_4: mc |= SPARC_FP_SINGLE; break;
526 case OP_SIZE_8: mc |= SPARC_FP_DOUBLE; break;
527 case OP_SIZE_16: mc |= SPARC_FP_QUAD; break;
528 default: internal(file_line, "cgen_fp_alu1: invalid size %u", op_size);
530 cgen_sparc_3reg(mc, arg1[0] & 31, 0, arg2[0] & 31);
534 static bool attr_w cgen_fp_to_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
537 uint8_t *arg1 = ctx->code_position;
538 uint8_t *arg2 = arg1 + arg_size(*arg1);
539 ctx->code_position = arg2 + arg_size(*arg2);
541 switch (int_op_size) {
542 case OP_SIZE_4: mc |= SPARC_FTOI_32; break;
543 case OP_SIZE_8: mc |= SPARC_FTOI_64; break;
544 default: internal(file_line, "cgen_fp_to_int: invalid int size %u", int_op_size);
546 switch (fp_op_size) {
547 case OP_SIZE_4: mc |= SPARC_FTOI_SINGLE; break;
548 case OP_SIZE_8: mc |= SPARC_FTOI_DOUBLE; break;
549 case OP_SIZE_16: mc |= SPARC_FTOI_QUAD; break;
550 default: internal(file_line, "cgen_fp_to_int: invalid fp size %u", fp_op_size);
552 cgen_sparc_3reg(mc, arg1[0] & 31, 0, arg2[0] & 31);
556 static bool attr_w cgen_fp_from_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
559 uint8_t *arg1 = ctx->code_position;
560 uint8_t *arg2 = arg1 + arg_size(*arg1);
561 ctx->code_position = arg2 + arg_size(*arg2);
563 switch (int_op_size) {
564 case OP_SIZE_4: mc |= SPARC_ITOF_32; break;
565 case OP_SIZE_8: mc |= SPARC_ITOF_64; break;
566 default: internal(file_line, "cgen_fp_to_int: invalid int size %u", int_op_size);
568 switch (fp_op_size) {
569 case OP_SIZE_4: mc |= SPARC_ITOF_SINGLE; break;
570 case OP_SIZE_8: mc |= SPARC_ITOF_DOUBLE; break;
571 case OP_SIZE_16: mc |= SPARC_ITOF_QUAD; break;
572 default: internal(file_line, "cgen_fp_to_int: invalid fp size %u", fp_op_size);
574 cgen_sparc_3reg(mc, arg1[0] & 31, 0, arg2[0] & 31);
578 static bool attr_w cgen_jmp_cond(struct codegen_context *ctx, unsigned size, unsigned aux, unsigned length)
581 cond = jmp_cond[aux];
582 if (unlikely(cond < 0))
583 internal(file_line, "cgen_jmp_cond: invalid condition %u", aux);
585 g(add_relocation(ctx, JMP_LONG, 0, NULL));
586 cgen_four(SPARC_FBCC | ((uint32_t)cond << 25));
587 } else if (size == OP_SIZE_4) {
588 g(add_relocation(ctx, JMP_LONG, 0, NULL));
589 cgen_four(SPARC_BCC | ((uint32_t)cond << 25));
590 } else if (size == OP_SIZE_8) {
591 if (length <= JMP_SHORT) {
592 g(add_relocation(ctx, JMP_SHORT, 0, NULL));
593 cgen_four(SPARC_BPCC | SPARC_BPCC_64 | ((uint32_t)cond << 25));
595 cgen_four(SPARC_BPCC | SPARC_BPCC_64 | ((uint32_t)(cond ^ 0x8) << 25) | 3);
596 cgen_four(SPARC_NOP);
597 g(add_relocation(ctx, JMP_LONG, 0, NULL));
598 cgen_four(SPARC_BCC | SPARC_BCC_A | 0x8 << 25);
601 internal(file_line, "cgen_jmp_cond: invalid size %u", size);
603 cgen_four(SPARC_NOP);
607 static bool attr_w cgen_jmp_reg(struct codegen_context *ctx, unsigned aux, unsigned length)
609 uint32_t mc = SPARC_BR;
610 mc |= (uint32_t)cget_one(ctx) << 14;
612 case COND_E: mc |= SPARC_BR_BRZ; break;
613 case COND_LE: mc |= SPARC_BR_BRLEZ; break;
615 case COND_L: mc |= SPARC_BR_BRLZ; break;
616 case COND_NE: mc |= SPARC_BR_BRNZ; break;
617 case COND_G: mc |= SPARC_BR_GZ; break;
619 case COND_GE: mc |= SPARC_BR_GEZ; break;
621 internal(file_line, "cgen_jmp_reg: invalid condition %u", aux);
625 g(add_relocation(ctx, JMP_SHORTEST, 1, NULL));
627 cgen_four(SPARC_NOP);
631 cgen_four((mc ^ 0x08000000U) | 3);
632 cgen_four(SPARC_NOP);
633 g(add_relocation(ctx, JMP_LONG, 1, NULL));
634 cgen_four(SPARC_BCC | SPARC_BCC_A | 0x8 << 25);
637 internal(file_line, "cgen_jmp_reg: invalid length %u", length);
642 static bool attr_w resolve_relocation(struct codegen_context *ctx, struct relocation *reloc)
645 int64_t offs = (int64_t)(ctx->label_to_pos[reloc->label_id] >> 2) - (int64_t)(reloc->position >> 2);
646 switch (reloc->length) {
648 if (unlikely(offs < -0x00008000) || unlikely(offs >= 0x00008000))
650 memcpy(&mc, ctx->mcode + reloc->position, 4);
652 mc |= offs & 0x3fffU;
653 mc |= (offs & 0xc000U) << 6;
654 memcpy(ctx->mcode + reloc->position, &mc, 4);
657 if (unlikely(offs < -0x00040000) || unlikely(offs >= 0x00040000))
659 memcpy(&mc, ctx->mcode + reloc->position, 4);
661 mc |= offs & 0x0007ffffU;
662 memcpy(ctx->mcode + reloc->position, &mc, 4);
665 if (unlikely(offs < -0x00200000) || unlikely(offs >= 0x00200000))
667 memcpy(&mc, ctx->mcode + reloc->position, 4);
669 mc |= offs & 0x003fffffU;
670 memcpy(ctx->mcode + reloc->position, &mc, 4);
673 internal(file_line, "resolve_relocation: invalid relocation length %u", reloc->length);
678 static bool attr_w cgen_insn(struct codegen_context *ctx, uint32_t insn)
681 /*debug("insn: %08x", insn);*/
682 switch (insn_opcode(insn)) {
690 cgen_four(SPARC_RETURN | ((uint32_t)R_I7 << 14) | SPARC_IMM_BIT | 8);
691 cgen_four(SPARC_NOP);
693 case INSN_CALL_INDIRECT:
695 cgen_sparc_imm(SPARC_JMPL, R_O7, reg, R_ZERO);
696 cgen_four(SPARC_NOP);
699 g(cgen_mov(ctx, insn_op_size(insn), false));
702 g(cgen_mov(ctx, insn_op_size(insn), true));
705 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
707 g(cgen_cmp(ctx, SPARC_SUB));
710 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
712 g(cgen_cmp(ctx, SPARC_ADD));
715 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
717 g(cgen_cmp(ctx, SPARC_AND));
721 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
723 g(cgen_alu(ctx, insn_writes_flags(insn), insn_aux(insn)));
726 case INSN_ALU1_FLAGS:
727 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
729 g(cgen_alu1(ctx, insn_writes_flags(insn), insn_aux(insn)));
732 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
734 g(cgen_rot(ctx, insn_op_size(insn), insn_aux(insn)));
737 if (unlikely(!SPARC_9))
739 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
741 g(cgen_cmov(ctx, insn_aux(insn), false));
744 if (unlikely(!SPARC_9))
746 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
748 g(cgen_cmov(ctx, insn_aux(insn), true));
751 if (unlikely(!SPARC_9))
753 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
755 g(cgen_movr(ctx, insn_aux(insn)));
759 if (unlikely(insn_op_size(insn) != OP_SIZE_4))
761 g(cgen_ldp_stp(ctx, insn_opcode(insn) == INSN_LDP));
764 g(cgen_fp_cmp(ctx, insn_op_size(insn)));
767 g(cgen_fp_alu(ctx, insn_op_size(insn), insn_aux(insn)));
770 g(cgen_fp_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
772 case INSN_FP_TO_INT64:
776 case INSN_FP_TO_INT32:
777 g(cgen_fp_to_int(ctx, insn_opcode(insn) == INSN_FP_TO_INT32 ? OP_SIZE_4 : OP_SIZE_8, insn_op_size(insn)));
779 case INSN_FP_FROM_INT64:
783 case INSN_FP_FROM_INT32:
784 g(cgen_fp_from_int(ctx, insn_opcode(insn) == INSN_FP_FROM_INT32 ? OP_SIZE_4 : OP_SIZE_8, insn_op_size(insn)));
787 g(add_relocation(ctx, JMP_LONG, 0, NULL));
788 cgen_four(SPARC_BCC | SPARC_BCC_A | 0x8 << 25);
791 g(cgen_jmp_cond(ctx, insn_op_size(insn), insn_aux(insn), insn_jump_size(insn)));
794 if (unlikely(!SPARC_9))
796 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
798 g(cgen_jmp_reg(ctx, insn_aux(insn), insn_jump_size(insn)));
800 case INSN_JMP_INDIRECT:
802 cgen_sparc_imm(SPARC_JMPL, R_ZERO, reg, R_ZERO);
803 cgen_four(SPARC_NOP);
807 internal(file_line, "cgen_insn: invalid insn %08x", insn);