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 *arg1 = ctx->code_position;
315 uint8_t *arg2 = arg1 + arg_size(*arg1);
316 ctx->code_position = arg2 + arg_size(*arg2);
319 g(cgen_alu_args(ctx, writes_flags, SPARC_XORN, arg1, arg2, &z));
322 g(cgen_alu_args(ctx, writes_flags, SPARC_SUB, arg1, &z, arg2));
325 g(cgen_alu_args(ctx, writes_flags, SPARC_POPC, arg1, &z, arg2));
328 internal(file_line, "cgen_alu1: invalid operation %u", alu);
333 static bool attr_w cgen_rot(struct codegen_context *ctx, unsigned size, uint8_t rot)
337 uint8_t *arg1 = ctx->code_position;
338 uint8_t *arg2 = arg1 + arg_size(*arg1);
339 uint8_t *arg3 = arg2 + arg_size(*arg2);
340 ctx->code_position = arg3 + arg_size(*arg3);
342 if (unlikely(arg1[0] >= 32) || unlikely(arg2[0] >= 32) || unlikely(size < OP_SIZE_4) || unlikely(size > OP_SIZE_8))
346 case ROT_SHL: mc = SPARC_SLL; break;
347 case ROT_SHR: mc = SPARC_SRL; break;
348 case ROT_SAR: mc = SPARC_SRA; break;
353 if (size == OP_SIZE_8)
356 if (arg3[0] == ARG_IMM) {
357 imm = get_imm(&arg3[1]);
358 if (unlikely(imm < 0) || unlikely(imm >= (size == OP_SIZE_4 ? 32 : 64)))
360 cgen_sparc_imm(mc, arg1[0], arg2[0], imm);
363 cgen_sparc_3reg(mc, arg1[0], arg2[0], arg3[0]);
368 internal(file_line, "cgen_rot: invalid arguments: %02x, %02x, %02x, %u, %u", arg1[0], arg2[0], arg3[0], size, rot);
372 static bool attr_w cgen_cmov(struct codegen_context *ctx, unsigned aux, bool xcc)
376 uint8_t *arg1 = ctx->code_position;
377 uint8_t *arg2 = arg1 + arg_size(*arg1);
378 uint8_t *arg3 = arg2 + arg_size(*arg2);
379 ctx->code_position = arg3 + arg_size(*arg3);
380 if (unlikely(arg1[0] != arg2[0]))
381 internal(file_line, "cgen_cmov: invalid arguments");
383 cond = jmp_cond[aux];
384 if (unlikely(cond < 0))
385 internal(file_line, "cgen_cmov: invalid condition %u", aux);
387 mc |= SPARC_CMOV_FCC0;
389 mc |= xcc ? SPARC_CMOV_XCC : SPARC_CMOV_ICC;
391 mc |= (uint32_t)arg1[0] << 25;
392 mc |= (uint32_t)cond << 14;
393 if (arg3[0] == ARG_IMM) {
394 int64_t imm = get_imm(&arg3[1]);
404 static bool attr_w cgen_movr(struct codegen_context *ctx, unsigned aux)
406 uint32_t mc = SPARC_MOVR;
407 uint8_t *arg1 = ctx->code_position;
408 uint8_t *arg2 = arg1 + arg_size(*arg1);
409 uint8_t *arg3 = arg2 + arg_size(*arg2);
410 uint8_t *arg4 = arg3 + arg_size(*arg3);
411 ctx->code_position = arg4 + arg_size(*arg4);
413 case COND_E: mc |= SPARC_MOVR_Z; break;
414 case COND_LE: mc |= SPARC_MOVR_LEZ; break;
415 case COND_L: mc |= SPARC_MOVR_LZ; break;
416 case COND_NE: mc |= SPARC_MOVR_NZ; break;
417 case COND_G: mc |= SPARC_MOVR_GZ; break;
418 case COND_GE: mc |= SPARC_MOVR_GEZ; break;
419 default: internal(file_line, "cgen_movr: invalid condition %u", aux);
421 if (unlikely(arg1[0] != arg2[0]))
422 internal(file_line, "cgen_movr: invalid arguments");
423 mc |= (uint32_t)arg1[0] << 25;
424 mc |= (uint32_t)arg3[0] << 14;
425 if (arg4[0] == ARG_IMM) {
426 int64_t imm = get_imm(&arg4[1]);
436 static bool attr_w cgen_ldp_stp(struct codegen_context *ctx, bool ldr)
438 uint8_t *arg1, *arg2, *arg3;
440 arg1 = ctx->code_position;
441 arg2 = arg1 + arg_size(*arg1);
442 arg3 = arg2 + arg_size(*arg2);
443 ctx->code_position = arg3 + arg_size(*arg3);
445 arg2 = ctx->code_position;
446 arg3 = arg2 + arg_size(*arg2);
447 arg1 = arg3 + arg_size(*arg3);
448 ctx->code_position = arg1 + arg_size(*arg1);
450 if (unlikely(arg2[0] >= 32) || unlikely(arg3[0] >= 32))
452 if (unlikely((arg3[0] & 1) != 0) || unlikely(arg2[0] != arg3[0] + 1))
456 return cgen_ld_st(ctx, SPARC_LDD, arg3[0], arg1);
458 return cgen_ld_st(ctx, SPARC_STD, arg3[0], arg1);
461 internal(file_line, "cgen_ldp_stp: invalid arguments %02x, %02x, %02x", arg1[0], arg2[0], arg3[0]);
465 static bool attr_w cgen_fp_cmp(struct codegen_context *ctx, unsigned op_size)
468 uint8_t *arg1 = ctx->code_position;
469 uint8_t *arg2 = arg1 + arg_size(*arg1);
470 ctx->code_position = arg2 + arg_size(*arg2);
473 case OP_SIZE_4: mc |= SPARC_FCMP_SINGLE; break;
474 case OP_SIZE_8: mc |= SPARC_FCMP_DOUBLE; break;
475 case OP_SIZE_16: mc |= SPARC_FCMP_QUAD; break;
476 default: internal(file_line, "cgen_fp_cmp: invalid size %u", op_size);
478 cgen_sparc_3reg(mc, 0, arg1[0] & 31, arg2[0] & 31);
482 static bool attr_w cgen_fp_alu(struct codegen_context *ctx, unsigned op_size, unsigned aux)
485 uint8_t *arg1 = ctx->code_position;
486 uint8_t *arg2 = arg1 + arg_size(*arg1);
487 uint8_t *arg3 = arg2 + arg_size(*arg2);
488 ctx->code_position = arg3 + arg_size(*arg3);
490 case FP_ALU_ADD: mc = SPARC_FADD; break;
491 case FP_ALU_SUB: mc = SPARC_FSUB; break;
492 case FP_ALU_MUL: mc = SPARC_FMUL; break;
493 case FP_ALU_DIV: mc = SPARC_FDIV; break;
494 default: internal(file_line, "cgen_fp_alu: invalid alu %u", aux);
497 case OP_SIZE_4: mc |= SPARC_FP_SINGLE; break;
498 case OP_SIZE_8: mc |= SPARC_FP_DOUBLE; break;
499 case OP_SIZE_16: mc |= SPARC_FP_QUAD; break;
500 default: internal(file_line, "cgen_fp_alu: invalid size %u", op_size);
502 cgen_sparc_3reg(mc, arg1[0] & 31, arg2[0] & 31, arg3[0] & 31);
506 static bool attr_w cgen_fp_alu1(struct codegen_context *ctx, unsigned op_size, unsigned aux)
509 uint8_t *arg1 = ctx->code_position;
510 uint8_t *arg2 = arg1 + arg_size(*arg1);
511 ctx->code_position = arg2 + arg_size(*arg2);
513 case FP_ALU1_NEG: mc = SPARC_FNEG; break;
514 case FP_ALU1_SQRT: mc = SPARC_FSQRT; break;
515 default: internal(file_line, "cgen_fp_alu1: invalid alu %u", aux);
518 case OP_SIZE_4: mc |= SPARC_FP_SINGLE; break;
519 case OP_SIZE_8: mc |= SPARC_FP_DOUBLE; break;
520 case OP_SIZE_16: mc |= SPARC_FP_QUAD; break;
521 default: internal(file_line, "cgen_fp_alu1: invalid size %u", op_size);
523 cgen_sparc_3reg(mc, arg1[0] & 31, 0, arg2[0] & 31);
527 static bool attr_w cgen_fp_to_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
530 uint8_t *arg1 = ctx->code_position;
531 uint8_t *arg2 = arg1 + arg_size(*arg1);
532 ctx->code_position = arg2 + arg_size(*arg2);
534 switch (int_op_size) {
535 case OP_SIZE_4: mc |= SPARC_FTOI_32; break;
536 case OP_SIZE_8: mc |= SPARC_FTOI_64; break;
537 default: internal(file_line, "cgen_fp_to_int: invalid int size %u", int_op_size);
539 switch (fp_op_size) {
540 case OP_SIZE_4: mc |= SPARC_FTOI_SINGLE; break;
541 case OP_SIZE_8: mc |= SPARC_FTOI_DOUBLE; break;
542 case OP_SIZE_16: mc |= SPARC_FTOI_QUAD; break;
543 default: internal(file_line, "cgen_fp_to_int: invalid fp size %u", fp_op_size);
545 cgen_sparc_3reg(mc, arg1[0] & 31, 0, arg2[0] & 31);
549 static bool attr_w cgen_fp_from_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
552 uint8_t *arg1 = ctx->code_position;
553 uint8_t *arg2 = arg1 + arg_size(*arg1);
554 ctx->code_position = arg2 + arg_size(*arg2);
556 switch (int_op_size) {
557 case OP_SIZE_4: mc |= SPARC_ITOF_32; break;
558 case OP_SIZE_8: mc |= SPARC_ITOF_64; break;
559 default: internal(file_line, "cgen_fp_to_int: invalid int size %u", int_op_size);
561 switch (fp_op_size) {
562 case OP_SIZE_4: mc |= SPARC_ITOF_SINGLE; break;
563 case OP_SIZE_8: mc |= SPARC_ITOF_DOUBLE; break;
564 case OP_SIZE_16: mc |= SPARC_ITOF_QUAD; break;
565 default: internal(file_line, "cgen_fp_to_int: invalid fp size %u", fp_op_size);
567 cgen_sparc_3reg(mc, arg1[0] & 31, 0, arg2[0] & 31);
571 static bool attr_w cgen_jmp_cond(struct codegen_context *ctx, unsigned size, unsigned aux, unsigned length)
574 cond = jmp_cond[aux];
575 if (unlikely(cond < 0))
576 internal(file_line, "cgen_jmp_cond: invalid condition %u", aux);
578 g(add_relocation(ctx, JMP_LONG, 0, NULL));
579 cgen_four(SPARC_FBCC | ((uint32_t)cond << 25));
580 } else if (size == OP_SIZE_4) {
581 g(add_relocation(ctx, JMP_LONG, 0, NULL));
582 cgen_four(SPARC_BCC | ((uint32_t)cond << 25));
583 } else if (size == OP_SIZE_8) {
584 if (length <= JMP_SHORT) {
585 g(add_relocation(ctx, JMP_SHORT, 0, NULL));
586 cgen_four(SPARC_BPCC | SPARC_BPCC_64 | ((uint32_t)cond << 25));
588 cgen_four(SPARC_BPCC | SPARC_BPCC_64 | ((uint32_t)(cond ^ 0x8) << 25) | 3);
589 cgen_four(SPARC_NOP);
590 g(add_relocation(ctx, JMP_LONG, 0, NULL));
591 cgen_four(SPARC_BCC | SPARC_BCC_A | 0x8 << 25);
594 internal(file_line, "cgen_jmp_cond: invalid size %u", size);
596 cgen_four(SPARC_NOP);
600 static bool attr_w cgen_jmp_reg(struct codegen_context *ctx, unsigned aux, unsigned length)
602 uint32_t mc = SPARC_BR;
603 mc |= (uint32_t)cget_one(ctx) << 14;
605 case COND_E: mc |= SPARC_BR_BRZ; break;
606 case COND_LE: mc |= SPARC_BR_BRLEZ; break;
608 case COND_L: mc |= SPARC_BR_BRLZ; break;
609 case COND_NE: mc |= SPARC_BR_BRNZ; break;
610 case COND_G: mc |= SPARC_BR_GZ; break;
612 case COND_GE: mc |= SPARC_BR_GEZ; break;
614 internal(file_line, "cgen_jmp_reg: invalid condition %u", aux);
618 g(add_relocation(ctx, JMP_SHORTEST, 1, NULL));
620 cgen_four(SPARC_NOP);
624 cgen_four((mc ^ 0x08000000U) | 3);
625 cgen_four(SPARC_NOP);
626 g(add_relocation(ctx, JMP_LONG, 1, NULL));
627 cgen_four(SPARC_BCC | SPARC_BCC_A | 0x8 << 25);
630 internal(file_line, "cgen_jmp_reg: invalid length %u", length);
635 static bool attr_w resolve_relocation(struct codegen_context *ctx, struct relocation *reloc)
638 int64_t offs = (int64_t)(ctx->label_to_pos[reloc->label_id] >> 2) - (int64_t)(reloc->position >> 2);
639 switch (reloc->length) {
641 if (unlikely(offs < -0x00008000) || unlikely(offs >= 0x00008000))
643 memcpy(&mc, ctx->mcode + reloc->position, 4);
645 mc |= offs & 0x3fffU;
646 mc |= (offs & 0xc000U) << 6;
647 memcpy(ctx->mcode + reloc->position, &mc, 4);
650 if (unlikely(offs < -0x00040000) || unlikely(offs >= 0x00040000))
652 memcpy(&mc, ctx->mcode + reloc->position, 4);
654 mc |= offs & 0x0007ffffU;
655 memcpy(ctx->mcode + reloc->position, &mc, 4);
658 if (unlikely(offs < -0x00200000) || unlikely(offs >= 0x00200000))
660 memcpy(&mc, ctx->mcode + reloc->position, 4);
662 mc |= offs & 0x003fffffU;
663 memcpy(ctx->mcode + reloc->position, &mc, 4);
666 internal(file_line, "resolve_relocation: invalid relocation length %u", reloc->length);
671 static bool attr_w cgen_insn(struct codegen_context *ctx, uint32_t insn)
674 /*debug("insn: %08x", insn);*/
675 switch (insn_opcode(insn)) {
683 cgen_four(SPARC_RETURN | ((uint32_t)R_I7 << 14) | SPARC_IMM_BIT | 8);
684 cgen_four(SPARC_NOP);
686 case INSN_CALL_INDIRECT:
688 cgen_sparc_imm(SPARC_JMPL, R_O7, reg, R_ZERO);
689 cgen_four(SPARC_NOP);
692 g(cgen_mov(ctx, insn_op_size(insn), false));
695 g(cgen_mov(ctx, insn_op_size(insn), true));
698 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
700 g(cgen_cmp(ctx, SPARC_SUB));
703 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
705 g(cgen_cmp(ctx, SPARC_ADD));
708 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
710 g(cgen_cmp(ctx, SPARC_AND));
714 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
716 g(cgen_alu(ctx, insn_writes_flags(insn), insn_aux(insn)));
719 case INSN_ALU1_FLAGS:
720 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
722 g(cgen_alu1(ctx, insn_writes_flags(insn), insn_aux(insn)));
725 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
727 g(cgen_rot(ctx, insn_op_size(insn), insn_aux(insn)));
730 if (unlikely(!SPARC_9))
732 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
734 g(cgen_cmov(ctx, insn_aux(insn), false));
737 if (unlikely(!SPARC_9))
739 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
741 g(cgen_cmov(ctx, insn_aux(insn), true));
744 if (unlikely(!SPARC_9))
746 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
748 g(cgen_movr(ctx, insn_aux(insn)));
752 if (unlikely(insn_op_size(insn) != OP_SIZE_4))
754 g(cgen_ldp_stp(ctx, insn_opcode(insn) == INSN_LDP));
757 g(cgen_fp_cmp(ctx, insn_op_size(insn)));
760 g(cgen_fp_alu(ctx, insn_op_size(insn), insn_aux(insn)));
763 g(cgen_fp_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
765 case INSN_FP_TO_INT64:
769 case INSN_FP_TO_INT32:
770 g(cgen_fp_to_int(ctx, insn_opcode(insn) == INSN_FP_TO_INT32 ? OP_SIZE_4 : OP_SIZE_8, insn_op_size(insn)));
772 case INSN_FP_FROM_INT64:
776 case INSN_FP_FROM_INT32:
777 g(cgen_fp_from_int(ctx, insn_opcode(insn) == INSN_FP_FROM_INT32 ? OP_SIZE_4 : OP_SIZE_8, insn_op_size(insn)));
780 g(add_relocation(ctx, JMP_LONG, 0, NULL));
781 cgen_four(SPARC_BCC | SPARC_BCC_A | 0x8 << 25);
784 g(cgen_jmp_cond(ctx, insn_op_size(insn), insn_aux(insn), insn_jump_size(insn)));
787 if (unlikely(!SPARC_9))
789 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
791 g(cgen_jmp_reg(ctx, insn_aux(insn), insn_jump_size(insn)));
793 case INSN_JMP_INDIRECT:
795 cgen_sparc_imm(SPARC_JMPL, R_ZERO, reg, R_ZERO);
796 cgen_four(SPARC_NOP);
800 internal(file_line, "cgen_insn: invalid insn %08x", insn);