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_FNEG 0x81a00080U
79 #define SPARC_FSQRT 0x81a00500U
80 #define SPARC_FADD 0x81a00800U
81 #define SPARC_FSUB 0x81a00880U
82 #define SPARC_FMUL 0x81a00900U
83 #define SPARC_FDIV 0x81a00980U
84 #define SPARC_FP_SINGLE 0x00000020U
85 #define SPARC_FP_DOUBLE 0x00000040U
86 #define SPARC_FP_QUAD 0x00000060U
87 #define SPARC_FTOI 0x81a01000U
88 #define SPARC_FTOI_32 0x00000a00U
89 #define SPARC_FTOI_64 0x00000000U
90 #define SPARC_FTOI_SINGLE 0x00000020U
91 #define SPARC_FTOI_DOUBLE 0x00000040U
92 #define SPARC_FTOI_QUAD 0x00000060U
93 #define SPARC_ITOF 0x81a01000U
94 #define SPARC_ITOF_64 0x00000000U
95 #define SPARC_ITOF_32 0x00000800U
96 #define SPARC_ITOF_SINGLE 0x00000080U
97 #define SPARC_ITOF_DOUBLE 0x00000100U
98 #define SPARC_ITOF_QUAD 0x00000180U
99 #define SPARC_FCMP 0x81a80a00U
100 #define SPARC_FCMP_CC0 0x02000000U
101 #define SPARC_FCMP_CC1 0x04000000U
102 #define SPARC_FCMP_SINGLE 0x00000020U
103 #define SPARC_FCMP_DOUBLE 0x00000040U
104 #define SPARC_FCMP_QUAD 0x00000060U
105 #define SPARC_JMPL 0x81c00000U
106 #define SPARC_RETURN 0x81c80000U
107 #define SPARC_SAVE 0x81e00000U
108 #define SPARC_RESTORE 0x81e80000U
110 #define SPARC_LDUW 0xc0000000U
111 #define SPARC_LDUB 0xc0080000U
112 #define SPARC_LDUH 0xc0100000U
113 #define SPARC_LDD 0xc0180000U
114 #define SPARC_STW 0xc0200000U
115 #define SPARC_STB 0xc0280000U
116 #define SPARC_STH 0xc0300000U
117 #define SPARC_STD 0xc0380000U
118 #define SPARC_LDSW 0xc0400000U
119 #define SPARC_LDSB 0xc0480000U
120 #define SPARC_LDSH 0xc0500000U
121 #define SPARC_LDX 0xc0580000U
122 #define SPARC_STX 0xc0700000U
123 #define SPARC_LDF 0xc1000000U
124 #define SPARC_STF 0xc1200000U
125 #define SPARC_LDSTF_SINGLE 0x00000000U
126 #define SPARC_LDSTF_DOUBLE 0x00180000U
127 #define SPARC_LDSTF_QUAD 0x00100000U
130 static const int8_t jmp_cond[48] = {
131 0x7, 0xf, 0x5, 0xd, 0x1, 0x9, 0x4, 0xc,
132 0x6, 0xe, -1, -1, 0x3, 0xb, 0x2, 0xa,
133 -1, -1, -1, -1, -1, -1, -1, -1,
134 -1, -1, -1, -1, -1, -1, -1, -1,
135 -1, -1, 0x4, 0xb, 0x9, 0x2, 0xd, 0x6,
136 -1, -1, 0x7, 0xf, -1, -1, -1, -1,
139 static const uint32_t alu_map[24] = {
166 #define cgen_sparc_3reg(mc, rd, rs1, rs2) \
167 cgen_four((mc) | ((uint32_t)(rd) << 25) | ((uint32_t)((rs1) << 14)) | (rs2))
168 #define cgen_sparc_imm(mc, rd, rs1, imm) \
169 cgen_four((mc) | SPARC_IMM_BIT | ((uint32_t)(rd) << 25) | ((uint32_t)((rs1) << 14)) | ((imm) & 8191))
171 static bool attr_w cgen_ld_st(struct codegen_context *ctx, uint32_t mc, uint8_t reg, uint8_t *address)
174 if (address[0] == ARG_ADDRESS_2) {
175 imm = get_imm(&address[3]);
176 if (unlikely(imm != 0))
178 cgen_sparc_3reg(mc, reg, address[1], address[2]);
180 } else if (address[0] == ARG_ADDRESS_1) {
181 imm = get_imm(&address[2]);
182 if (unlikely(imm < -4096) || unlikely(imm >= 4096))
184 cgen_sparc_imm(mc, reg, address[1], imm);
191 internal(file_line, "cgen_ld_st: invalid address: %02x, %02x, %"PRIxMAX"", reg, address[0], (uintmax_t)imm);
195 static bool attr_w cgen_mov(struct codegen_context *ctx, unsigned size, bool sx)
198 uint8_t *arg1 = ctx->code_position;
199 uint8_t *arg2 = arg1 + arg_size(*arg1);
200 ctx->code_position = arg2 + arg_size(*arg2);
203 if (unlikely(size != OP_SIZE_NATIVE))
204 internal(file_line, "cgen_mov: unsupported size %u", size);
205 cgen_sparc_3reg(SPARC_OR, arg1[0], arg2[0], R_ZERO);
208 if (arg2[0] == ARG_IMM) {
209 imm = get_imm(&arg2[1]);
210 if (imm >= -4096 && imm < 4096) {
211 cgen_sparc_imm(SPARC_OR, arg1[0], R_ZERO, imm);
213 if (imm & ~0xfffffc00ULL)
214 internal(file_line, "cgen_mov: invalid imm");
215 cgen_four(SPARC_SETHI | ((uint32_t)arg1[0] << 25) | imm >> 10);
219 if (arg2[0] == ARG_ADDRESS_1 || arg2[0] == ARG_ADDRESS_2) {
220 if (!sx || size == OP_SIZE_NATIVE) {
221 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);
223 return cgen_ld_st(ctx, size == OP_SIZE_1 ? SPARC_LDSB : size == OP_SIZE_2 ? SPARC_LDSH : SPARC_LDSW, arg1[0], arg2);
230 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);
233 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);
236 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);
238 if (arg2[0] == ARG_IMM) {
239 imm = get_imm(&arg2[1]);
241 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);
244 internal(file_line, "cgen_mov: invalid arguments %02x, %02x", arg1[0], arg2[0]);
248 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)
252 if (unlikely(arg1[0] >= 32) || unlikely(arg2[0] >= 32))
258 if (arg3[0] == ARG_IMM) {
259 imm = get_imm(&arg3[1]);
260 if (unlikely(imm < -4096) || unlikely(imm >= 4096))
262 cgen_sparc_imm(mc, arg1[0], arg2[0], imm);
264 } else if (likely(arg3[0] < 32)) {
265 cgen_sparc_3reg(mc, arg1[0], arg2[0], arg3[0]);
270 internal(file_line, "cgen_alu_args: invalid arguments %02x, %02x, %02x, %08x, %u", arg1[0], arg2[0], arg3[0], (uint32_t)mc, writes_flags);
274 static bool attr_w cgen_cmp(struct codegen_context *ctx, uint32_t mc)
277 uint8_t *arg1 = ctx->code_position;
278 uint8_t *arg2 = arg1 + arg_size(*arg1);
279 ctx->code_position = arg2 + arg_size(*arg2);
280 return cgen_alu_args(ctx, true, mc, &z, arg1, arg2);
283 static bool attr_w cgen_alu(struct codegen_context *ctx, unsigned writes_flags, unsigned alu)
286 uint8_t *arg1 = ctx->code_position;
287 uint8_t *arg2 = arg1 + arg_size(*arg1);
288 uint8_t *arg3 = arg2 + arg_size(*arg2);
289 ctx->code_position = arg3 + arg_size(*arg3);
291 if (unlikely(alu >= 16) && unlikely(writes_flags))
292 internal(file_line, "cgen_alu: alu %u can't write flags", alu);
294 ajla_assert_lo(alu < n_array_elements(alu_map), (file_line, "cgen_alu: invalid alu %u", alu));
296 if (unlikely(mc == (uint32_t)-1))
297 internal(file_line, "cgen_alu: invalid alu %u", alu);
299 return cgen_alu_args(ctx, writes_flags, mc, arg1, arg2, arg3);
302 static bool attr_w cgen_alu1(struct codegen_context *ctx, unsigned writes_flags, uint8_t alu)
305 uint8_t one_imm[9] = { ARG_IMM, 1, 0, 0, 0, 0, 0, 0, 0 };
306 uint8_t *arg1 = ctx->code_position;
307 uint8_t *arg2 = arg1 + arg_size(*arg1);
308 ctx->code_position = arg2 + arg_size(*arg2);
311 g(cgen_alu_args(ctx, writes_flags, SPARC_XORN, arg1, arg2, &z));
314 g(cgen_alu_args(ctx, writes_flags, SPARC_SUB, arg1, &z, arg2));
317 g(cgen_alu_args(ctx, writes_flags, SPARC_ADD, arg1, arg2, one_imm));
320 g(cgen_alu_args(ctx, writes_flags, SPARC_SUB, arg1, arg2, one_imm));
323 g(cgen_alu_args(ctx, writes_flags, SPARC_POPC, arg1, &z, arg2));
326 internal(file_line, "cgen_alu1: invalid operation %u", alu);
331 static bool attr_w cgen_rot(struct codegen_context *ctx, unsigned size, uint8_t rot)
335 uint8_t *arg1 = ctx->code_position;
336 uint8_t *arg2 = arg1 + arg_size(*arg1);
337 uint8_t *arg3 = arg2 + arg_size(*arg2);
338 ctx->code_position = arg3 + arg_size(*arg3);
340 if (unlikely(arg1[0] >= 32) || unlikely(arg2[0] >= 32) || unlikely(size < OP_SIZE_4) || unlikely(size > OP_SIZE_8))
344 case ROT_SHL: mc = SPARC_SLL; break;
345 case ROT_SHR: mc = SPARC_SRL; break;
346 case ROT_SAR: mc = SPARC_SRA; break;
351 if (size == OP_SIZE_8)
354 if (arg3[0] == ARG_IMM) {
355 imm = get_imm(&arg3[1]);
356 if (unlikely(imm < 0) || unlikely(imm >= (size == OP_SIZE_4 ? 32 : 64)))
358 cgen_sparc_imm(mc, arg1[0], arg2[0], imm);
361 cgen_sparc_3reg(mc, arg1[0], arg2[0], arg3[0]);
366 internal(file_line, "cgen_rot: invalid arguments: %02x, %02x, %02x, %u, %u", arg1[0], arg2[0], arg3[0], size, rot);
370 static bool attr_w cgen_cmov(struct codegen_context *ctx, unsigned aux, bool xcc)
374 uint8_t *arg1 = ctx->code_position;
375 uint8_t *arg2 = arg1 + arg_size(*arg1);
376 uint8_t *arg3 = arg2 + arg_size(*arg2);
377 ctx->code_position = arg3 + arg_size(*arg3);
378 if (unlikely(arg1[0] != arg2[0]))
379 internal(file_line, "cgen_cmov: invalid arguments");
381 cond = jmp_cond[aux];
382 if (unlikely(cond < 0))
383 internal(file_line, "cgen_cmov: invalid condition %u", aux);
385 mc |= SPARC_CMOV_FCC0;
387 mc |= xcc ? SPARC_CMOV_XCC : SPARC_CMOV_ICC;
389 mc |= (uint32_t)arg1[0] << 25;
390 mc |= (uint32_t)cond << 14;
391 if (arg3[0] == ARG_IMM) {
392 int64_t imm = get_imm(&arg3[1]);
402 static bool attr_w cgen_movr(struct codegen_context *ctx, unsigned aux)
404 uint32_t mc = SPARC_MOVR;
405 uint8_t *arg1 = ctx->code_position;
406 uint8_t *arg2 = arg1 + arg_size(*arg1);
407 uint8_t *arg3 = arg2 + arg_size(*arg2);
408 uint8_t *arg4 = arg3 + arg_size(*arg3);
409 ctx->code_position = arg4 + arg_size(*arg4);
411 case COND_E: mc |= SPARC_MOVR_Z; break;
412 case COND_LE: mc |= SPARC_MOVR_LEZ; break;
413 case COND_L: mc |= SPARC_MOVR_LZ; break;
414 case COND_NE: mc |= SPARC_MOVR_NZ; break;
415 case COND_G: mc |= SPARC_MOVR_GZ; break;
416 case COND_GE: mc |= SPARC_MOVR_GEZ; break;
417 default: internal(file_line, "cgen_movr: invalid condition %u", aux);
419 if (unlikely(arg1[0] != arg2[0]))
420 internal(file_line, "cgen_movr: invalid arguments");
421 mc |= (uint32_t)arg1[0] << 25;
422 mc |= (uint32_t)arg3[0] << 14;
423 if (arg4[0] == ARG_IMM) {
424 int64_t imm = get_imm(&arg4[1]);
434 static bool attr_w cgen_ldp_stp(struct codegen_context *ctx, bool ldr)
436 uint8_t *arg1, *arg2, *arg3;
438 arg1 = ctx->code_position;
439 arg2 = arg1 + arg_size(*arg1);
440 arg3 = arg2 + arg_size(*arg2);
441 ctx->code_position = arg3 + arg_size(*arg3);
443 arg2 = ctx->code_position;
444 arg3 = arg2 + arg_size(*arg2);
445 arg1 = arg3 + arg_size(*arg3);
446 ctx->code_position = arg1 + arg_size(*arg1);
448 if (unlikely(arg2[0] >= 32) || unlikely(arg3[0] >= 32))
450 if (unlikely((arg3[0] & 1) != 0) || unlikely(arg2[0] != arg3[0] + 1))
454 return cgen_ld_st(ctx, SPARC_LDD, arg3[0], arg1);
456 return cgen_ld_st(ctx, SPARC_STD, arg3[0], arg1);
459 internal(file_line, "cgen_ldp_stp: invalid arguments %02x, %02x, %02x", arg1[0], arg2[0], arg3[0]);
463 static bool attr_w cgen_fp_cmp(struct codegen_context *ctx, unsigned op_size)
466 uint8_t *arg1 = ctx->code_position;
467 uint8_t *arg2 = arg1 + arg_size(*arg1);
468 ctx->code_position = arg2 + arg_size(*arg2);
471 case OP_SIZE_4: mc |= SPARC_FCMP_SINGLE; break;
472 case OP_SIZE_8: mc |= SPARC_FCMP_DOUBLE; break;
473 case OP_SIZE_16: mc |= SPARC_FCMP_QUAD; break;
474 default: internal(file_line, "cgen_fp_cmp: invalid size %u", op_size);
476 cgen_sparc_3reg(mc, 0, arg1[0] & 31, arg2[0] & 31);
480 static bool attr_w cgen_fp_alu(struct codegen_context *ctx, unsigned op_size, unsigned aux)
483 uint8_t *arg1 = ctx->code_position;
484 uint8_t *arg2 = arg1 + arg_size(*arg1);
485 uint8_t *arg3 = arg2 + arg_size(*arg2);
486 ctx->code_position = arg3 + arg_size(*arg3);
488 case FP_ALU_ADD: mc = SPARC_FADD; break;
489 case FP_ALU_SUB: mc = SPARC_FSUB; break;
490 case FP_ALU_MUL: mc = SPARC_FMUL; break;
491 case FP_ALU_DIV: mc = SPARC_FDIV; break;
492 default: internal(file_line, "cgen_fp_alu: invalid alu %u", aux);
495 case OP_SIZE_4: mc |= SPARC_FP_SINGLE; break;
496 case OP_SIZE_8: mc |= SPARC_FP_DOUBLE; break;
497 case OP_SIZE_16: mc |= SPARC_FP_QUAD; break;
498 default: internal(file_line, "cgen_fp_alu: invalid size %u", op_size);
500 cgen_sparc_3reg(mc, arg1[0] & 31, arg2[0] & 31, arg3[0] & 31);
504 static bool attr_w cgen_fp_alu1(struct codegen_context *ctx, unsigned op_size, unsigned aux)
507 uint8_t *arg1 = ctx->code_position;
508 uint8_t *arg2 = arg1 + arg_size(*arg1);
509 ctx->code_position = arg2 + arg_size(*arg2);
511 case FP_ALU1_NEG: mc = SPARC_FNEG; break;
512 case FP_ALU1_SQRT: mc = SPARC_FSQRT; break;
513 default: internal(file_line, "cgen_fp_alu1: invalid alu %u", aux);
516 case OP_SIZE_4: mc |= SPARC_FP_SINGLE; break;
517 case OP_SIZE_8: mc |= SPARC_FP_DOUBLE; break;
518 case OP_SIZE_16: mc |= SPARC_FP_QUAD; break;
519 default: internal(file_line, "cgen_fp_alu1: invalid size %u", op_size);
521 cgen_sparc_3reg(mc, arg1[0] & 31, 0, arg2[0] & 31);
525 static bool attr_w cgen_fp_to_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
528 uint8_t *arg1 = ctx->code_position;
529 uint8_t *arg2 = arg1 + arg_size(*arg1);
530 ctx->code_position = arg2 + arg_size(*arg2);
532 switch (int_op_size) {
533 case OP_SIZE_4: mc |= SPARC_FTOI_32; break;
534 case OP_SIZE_8: mc |= SPARC_FTOI_64; break;
535 default: internal(file_line, "cgen_fp_to_int: invalid int size %u", int_op_size);
537 switch (fp_op_size) {
538 case OP_SIZE_4: mc |= SPARC_FTOI_SINGLE; break;
539 case OP_SIZE_8: mc |= SPARC_FTOI_DOUBLE; break;
540 case OP_SIZE_16: mc |= SPARC_FTOI_QUAD; break;
541 default: internal(file_line, "cgen_fp_to_int: invalid fp size %u", fp_op_size);
543 cgen_sparc_3reg(mc, arg1[0] & 31, 0, arg2[0] & 31);
547 static bool attr_w cgen_fp_from_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
550 uint8_t *arg1 = ctx->code_position;
551 uint8_t *arg2 = arg1 + arg_size(*arg1);
552 ctx->code_position = arg2 + arg_size(*arg2);
554 switch (int_op_size) {
555 case OP_SIZE_4: mc |= SPARC_ITOF_32; break;
556 case OP_SIZE_8: mc |= SPARC_ITOF_64; break;
557 default: internal(file_line, "cgen_fp_to_int: invalid int size %u", int_op_size);
559 switch (fp_op_size) {
560 case OP_SIZE_4: mc |= SPARC_ITOF_SINGLE; break;
561 case OP_SIZE_8: mc |= SPARC_ITOF_DOUBLE; break;
562 case OP_SIZE_16: mc |= SPARC_ITOF_QUAD; break;
563 default: internal(file_line, "cgen_fp_to_int: invalid fp size %u", fp_op_size);
565 cgen_sparc_3reg(mc, arg1[0] & 31, 0, arg2[0] & 31);
569 static bool attr_w cgen_jmp_cond(struct codegen_context *ctx, unsigned size, unsigned aux, unsigned length)
572 cond = jmp_cond[aux];
573 if (unlikely(cond < 0))
574 internal(file_line, "cgen_jmp_cond: invalid condition %u", aux);
576 g(add_relocation(ctx, JMP_LONG, 0, NULL));
577 cgen_four(SPARC_FBCC | ((uint32_t)cond << 25));
578 } else if (size == OP_SIZE_4) {
579 g(add_relocation(ctx, JMP_LONG, 0, NULL));
580 cgen_four(SPARC_BCC | ((uint32_t)cond << 25));
581 } else if (size == OP_SIZE_8) {
582 if (length <= JMP_SHORT) {
583 g(add_relocation(ctx, JMP_SHORT, 0, NULL));
584 cgen_four(SPARC_BPCC | SPARC_BPCC_64 | ((uint32_t)cond << 25));
586 cgen_four(SPARC_BPCC | SPARC_BPCC_64 | ((uint32_t)(cond ^ 0x8) << 25) | 3);
587 cgen_four(SPARC_NOP);
588 g(add_relocation(ctx, JMP_LONG, 0, NULL));
589 cgen_four(SPARC_BCC | SPARC_BCC_A | 0x8 << 25);
592 internal(file_line, "cgen_jmp_cond: invalid size %u", size);
594 cgen_four(SPARC_NOP);
598 static bool attr_w cgen_jmp_reg(struct codegen_context *ctx, unsigned aux, unsigned length)
600 uint32_t mc = SPARC_BR;
601 mc |= (uint32_t)cget_one(ctx) << 14;
603 case COND_E: mc |= SPARC_BR_BRZ; break;
604 case COND_LE: mc |= SPARC_BR_BRLEZ; break;
606 case COND_L: mc |= SPARC_BR_BRLZ; break;
607 case COND_NE: mc |= SPARC_BR_BRNZ; break;
608 case COND_G: mc |= SPARC_BR_GZ; break;
610 case COND_GE: mc |= SPARC_BR_GEZ; break;
612 internal(file_line, "cgen_jmp_reg: invalid condition %u", aux);
616 g(add_relocation(ctx, JMP_SHORTEST, 1, NULL));
618 cgen_four(SPARC_NOP);
622 cgen_four((mc ^ 0x08000000U) | 3);
623 cgen_four(SPARC_NOP);
624 g(add_relocation(ctx, JMP_LONG, 1, NULL));
625 cgen_four(SPARC_BCC | SPARC_BCC_A | 0x8 << 25);
628 internal(file_line, "cgen_jmp_reg: invalid length %u", length);
633 static bool attr_w resolve_relocation(struct codegen_context *ctx, struct relocation *reloc)
636 int64_t offs = (int64_t)(ctx->label_to_pos[reloc->label_id] >> 2) - (int64_t)(reloc->position >> 2);
637 switch (reloc->length) {
639 if (unlikely(offs < -0x00008000) || unlikely(offs >= 0x00008000))
641 memcpy(&mc, ctx->mcode + reloc->position, 4);
643 mc |= offs & 0x3fffU;
644 mc |= (offs & 0xc000U) << 6;
645 memcpy(ctx->mcode + reloc->position, &mc, 4);
648 if (unlikely(offs < -0x00040000) || unlikely(offs >= 0x00040000))
650 memcpy(&mc, ctx->mcode + reloc->position, 4);
652 mc |= offs & 0x0007ffffU;
653 memcpy(ctx->mcode + reloc->position, &mc, 4);
656 if (unlikely(offs < -0x00200000) || unlikely(offs >= 0x00200000))
658 memcpy(&mc, ctx->mcode + reloc->position, 4);
660 mc |= offs & 0x003fffffU;
661 memcpy(ctx->mcode + reloc->position, &mc, 4);
664 internal(file_line, "resolve_relocation: invalid relocation length %u", reloc->length);
669 static bool attr_w cgen_insn(struct codegen_context *ctx, uint32_t insn)
672 /*debug("insn: %08x", insn);*/
673 switch (insn_opcode(insn)) {
681 cgen_four(SPARC_RETURN | ((uint32_t)R_I7 << 14) | SPARC_IMM_BIT | 8);
682 cgen_four(SPARC_NOP);
684 case INSN_CALL_INDIRECT:
686 cgen_sparc_imm(SPARC_JMPL, R_O7, reg, R_ZERO);
687 cgen_four(SPARC_NOP);
690 g(cgen_mov(ctx, insn_op_size(insn), false));
693 g(cgen_mov(ctx, insn_op_size(insn), true));
696 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
698 g(cgen_cmp(ctx, SPARC_SUB));
701 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
703 g(cgen_cmp(ctx, SPARC_ADD));
706 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
708 g(cgen_cmp(ctx, SPARC_AND));
712 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
714 g(cgen_alu(ctx, insn_writes_flags(insn), insn_aux(insn)));
717 case INSN_ALU1_FLAGS:
718 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
720 g(cgen_alu1(ctx, insn_writes_flags(insn), insn_aux(insn)));
723 if (unlikely(insn_op_size(insn) < OP_SIZE_4))
725 g(cgen_rot(ctx, insn_op_size(insn), insn_aux(insn)));
728 if (unlikely(!SPARC_9))
730 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
732 g(cgen_cmov(ctx, insn_aux(insn), false));
735 if (unlikely(!SPARC_9))
737 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
739 g(cgen_cmov(ctx, insn_aux(insn), true));
742 if (unlikely(!SPARC_9))
744 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
746 g(cgen_movr(ctx, insn_aux(insn)));
750 if (unlikely(insn_op_size(insn) != OP_SIZE_4))
752 g(cgen_ldp_stp(ctx, insn_opcode(insn) == INSN_LDP));
755 g(cgen_fp_cmp(ctx, insn_op_size(insn)));
758 g(cgen_fp_alu(ctx, insn_op_size(insn), insn_aux(insn)));
761 g(cgen_fp_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
763 case INSN_FP_TO_INT64:
767 case INSN_FP_TO_INT32:
768 g(cgen_fp_to_int(ctx, insn_opcode(insn) == INSN_FP_TO_INT32 ? OP_SIZE_4 : OP_SIZE_8, insn_op_size(insn)));
770 case INSN_FP_FROM_INT64:
774 case INSN_FP_FROM_INT32:
775 g(cgen_fp_from_int(ctx, insn_opcode(insn) == INSN_FP_FROM_INT32 ? OP_SIZE_4 : OP_SIZE_8, insn_op_size(insn)));
778 g(add_relocation(ctx, JMP_LONG, 0, NULL));
779 cgen_four(SPARC_BCC | SPARC_BCC_A | 0x8 << 25);
782 g(cgen_jmp_cond(ctx, insn_op_size(insn), insn_aux(insn), insn_jump_size(insn)));
785 if (unlikely(!SPARC_9))
787 if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
789 g(cgen_jmp_reg(ctx, insn_aux(insn), insn_jump_size(insn)));
791 case INSN_JMP_INDIRECT:
793 cgen_sparc_imm(SPARC_JMPL, R_ZERO, reg, R_ZERO);
794 cgen_four(SPARC_NOP);
798 internal(file_line, "cgen_insn: invalid insn %08x", insn);