codegen: add a 'size' argument to ALU_WRITES_FLAGS
[ajla.git] / c2-sparc.inc
blob735995ed212445fd75cbd3cdf9deddae8111bfb4
1 /*
2  * Copyright (C) 2024 Mikulas Patocka
3  *
4  * This file is part of Ajla.
5  *
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
9  * version.
10  *
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.
14  *
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/>.
17  */
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] = {
141         SPARC_ADD,
142         SPARC_OR,
143         SPARC_ADDC,
144         SPARC_SUBC,
145         SPARC_AND,
146         SPARC_SUB,
147         SPARC_XOR,
148         -1U,
149         SPARC_ORN,
150         SPARC_ANDN,
151         SPARC_XORN,
152         -1U,
153         -1U,
154         -1U,
155         -1U,
156         -1U,
157         SPARC_MULX,
158         -1U,
159         -1U,
160         SPARC_UDIVX,
161         SPARC_SDIVX,
162         -1U,
163         -1U,
164         SPARC_SAVE,
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)
174         int64_t imm;
175         if (address[0] == ARG_ADDRESS_2) {
176                 imm = get_imm(&address[3]);
177                 if (unlikely(imm != 0))
178                         goto invalid;
179                 cgen_sparc_3reg(mc, reg, address[1], address[2]);
180                 return true;
181         } else if (address[0] == ARG_ADDRESS_1) {
182                 imm = get_imm(&address[2]);
183                 if (unlikely(imm < -4096) || unlikely(imm >= 4096))
184                         goto invalid;
185                 cgen_sparc_imm(mc, reg, address[1], imm);
186                 return true;
187         }
189         imm = 0;
191 invalid:
192         internal(file_line, "cgen_ld_st: invalid address: %02x, %02x, %"PRIxMAX"", reg, address[0], (uintmax_t)imm);
193         return false;
196 static bool attr_w cgen_mov(struct codegen_context *ctx, unsigned size, bool sx)
198         int64_t imm;
199         uint8_t *arg1 = ctx->code_position;
200         uint8_t *arg2 = arg1 + arg_size(*arg1);
201         ctx->code_position = arg2 + arg_size(*arg2);
202         if (arg1[0] < 32) {
203                 if (arg2[0] < 32) {
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);
207                         return true;
208                 }
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);
213                         } else {
214                                 if (imm & ~0xfffffc00ULL)
215                                         internal(file_line, "cgen_mov: invalid imm");
216                                 cgen_four(SPARC_SETHI | ((uint32_t)arg1[0] << 25) | imm >> 10);
217                                 return true;
218                         }
219                 }
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);
223                         } else {
224                                 return cgen_ld_st(ctx, size == OP_SIZE_1 ? SPARC_LDSB : size == OP_SIZE_2 ? SPARC_LDSH : SPARC_LDSW, arg1[0], arg2);
225                         }
226                 }
227         }
228         if (reg_is_fp(arg1[0])) {
229                 if (reg_is_fp(arg2[0])) {
230                         uint32_t mc = SPARC_FMOV;
231                         switch (size) {
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);
236                         }
237                         cgen_sparc_3reg(mc, arg1[0] & 31, 0, arg2[0] & 31);
238                         return true;
239                 }
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);
241         }
242         if (arg2[0] < 32) {
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);
244         }
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);
247         }
248         if (arg2[0] == ARG_IMM) {
249                 imm = get_imm(&arg2[1]);
250                 if (!imm)
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);
252         }
253         internal(file_line, "cgen_mov: invalid arguments %02x, %02x", arg1[0], arg2[0]);
254         return false;
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)
259         int64_t imm;
261         if (unlikely(arg1[0] >= 32) || unlikely(arg2[0] >= 32))
262                 goto invalid;
264         if (writes_flags)
265                 mc |= SPARC_CC_BIT;
267         if (arg3[0] == ARG_IMM) {
268                 imm = get_imm(&arg3[1]);
269                 if (unlikely(imm < -4096) || unlikely(imm >= 4096))
270                         goto invalid;
271                 cgen_sparc_imm(mc, arg1[0], arg2[0], imm);
272                 return true;
273         } else if (likely(arg3[0] < 32)) {
274                 cgen_sparc_3reg(mc, arg1[0], arg2[0], arg3[0]);
275                 return true;
276         }
278 invalid:
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);
280         return false;
283 static bool attr_w cgen_cmp(struct codegen_context *ctx, uint32_t mc)
285         uint8_t z = R_ZERO;
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)
294         uint32_t mc;
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));
304         mc = alu_map[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)
313         uint8_t z = R_ZERO;
314         uint8_t *arg1 = ctx->code_position;
315         uint8_t *arg2 = arg1 + arg_size(*arg1);
316         ctx->code_position = arg2 + arg_size(*arg2);
317         switch (alu) {
318                 case ALU1_NOT:
319                         g(cgen_alu_args(ctx, writes_flags, SPARC_XORN, arg1, arg2, &z));
320                         return true;
321                 case ALU1_NEG:
322                         g(cgen_alu_args(ctx, writes_flags, SPARC_SUB, arg1, &z, arg2));
323                         return true;
324                 case ALU1_POPCNT:
325                         g(cgen_alu_args(ctx, writes_flags, SPARC_POPC, arg1, &z, arg2));
326                         return true;
327                 default:
328                         internal(file_line, "cgen_alu1: invalid operation %u", alu);
329                         return false;
330         }
333 static bool attr_w cgen_rot(struct codegen_context *ctx, unsigned size, uint8_t rot)
335         uint32_t mc;
336         int64_t imm;
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))
343                 goto invalid;
345         switch (rot) {
346                 case ROT_SHL:   mc = SPARC_SLL; break;
347                 case ROT_SHR:   mc = SPARC_SRL; break;
348                 case ROT_SAR:   mc = SPARC_SRA; break;
349                 default:
350                         goto invalid;
351         }
353         if (size == OP_SIZE_8)
354                 mc |= SPARC_S_64;
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)))
359                         goto invalid;
360                 cgen_sparc_imm(mc, arg1[0], arg2[0], imm);
361                 return true;
362         } else {
363                 cgen_sparc_3reg(mc, arg1[0], arg2[0], arg3[0]);
364                 return true;
365         }
367 invalid:
368         internal(file_line, "cgen_rot: invalid arguments: %02x, %02x, %02x, %u, %u", arg1[0], arg2[0], arg3[0], size, rot);
369         return false;
372 static bool attr_w cgen_cmov(struct codegen_context *ctx, unsigned aux, bool xcc)
374         int8_t cond;
375         uint32_t mc;
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");
382         mc = SPARC_CMOV;
383         cond = jmp_cond[aux];
384         if (unlikely(cond < 0))
385                 internal(file_line, "cgen_cmov: invalid condition %u", aux);
386         if (aux & COND_FP) {
387                 mc |= SPARC_CMOV_FCC0;
388         } else {
389                 mc |= xcc ? SPARC_CMOV_XCC : SPARC_CMOV_ICC;
390         }
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]);
395                 mc |= SPARC_IMM_BIT;
396                 mc |= imm & 0x7FF;
397         } else {
398                 mc |= arg3[0];
399         }
400         cgen_four(mc);
401         return true;
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);
412         switch (aux) {
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);
420         }
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]);
427                 mc |= SPARC_IMM_BIT;
428                 mc |= imm & 0x3FF;
429         } else {
430                 mc |= arg4[0];
431         }
432         cgen_four(mc);
433         return true;
436 static bool attr_w cgen_ldp_stp(struct codegen_context *ctx, bool ldr)
438         uint8_t *arg1, *arg2, *arg3;
439         if (!ldr) {
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);
444         } else {
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);
449         }
450         if (unlikely(arg2[0] >= 32) || unlikely(arg3[0] >= 32))
451                 goto invalid;
452         if (unlikely((arg3[0] & 1) != 0) || unlikely(arg2[0] != arg3[0] + 1))
453                 goto invalid;
455         if (ldr)
456                 return cgen_ld_st(ctx, SPARC_LDD, arg3[0], arg1);
457         else
458                 return cgen_ld_st(ctx, SPARC_STD, arg3[0], arg1);
460 invalid:
461         internal(file_line, "cgen_ldp_stp: invalid arguments %02x, %02x, %02x", arg1[0], arg2[0], arg3[0]);
462         return false;
465 static bool attr_w cgen_fp_cmp(struct codegen_context *ctx, unsigned op_size)
467         uint32_t mc;
468         uint8_t *arg1 = ctx->code_position;
469         uint8_t *arg2 = arg1 + arg_size(*arg1);
470         ctx->code_position = arg2 + arg_size(*arg2);
471         mc = SPARC_FCMP;
472         switch (op_size) {
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);
477         }
478         cgen_sparc_3reg(mc, 0, arg1[0] & 31, arg2[0] & 31);
479         return true;
482 static bool attr_w cgen_fp_alu(struct codegen_context *ctx, unsigned op_size, unsigned aux)
484         uint32_t mc;
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);
489         switch (aux) {
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);
495         }
496         switch (op_size) {
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);
501         }
502         cgen_sparc_3reg(mc, arg1[0] & 31, arg2[0] & 31, arg3[0] & 31);
503         return true;
506 static bool attr_w cgen_fp_alu1(struct codegen_context *ctx, unsigned op_size, unsigned aux)
508         uint32_t mc;
509         uint8_t *arg1 = ctx->code_position;
510         uint8_t *arg2 = arg1 + arg_size(*arg1);
511         ctx->code_position = arg2 + arg_size(*arg2);
512         switch (aux) {
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);
516         }
517         switch (op_size) {
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);
522         }
523         cgen_sparc_3reg(mc, arg1[0] & 31, 0, arg2[0] & 31);
524         return true;
527 static bool attr_w cgen_fp_to_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
529         uint32_t mc;
530         uint8_t *arg1 = ctx->code_position;
531         uint8_t *arg2 = arg1 + arg_size(*arg1);
532         ctx->code_position = arg2 + arg_size(*arg2);
533         mc = SPARC_FTOI;
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);
538         }
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);
544         }
545         cgen_sparc_3reg(mc, arg1[0] & 31, 0, arg2[0] & 31);
546         return true;
549 static bool attr_w cgen_fp_from_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
551         uint32_t mc;
552         uint8_t *arg1 = ctx->code_position;
553         uint8_t *arg2 = arg1 + arg_size(*arg1);
554         ctx->code_position = arg2 + arg_size(*arg2);
555         mc = SPARC_ITOF;
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);
560         }
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);
566         }
567         cgen_sparc_3reg(mc, arg1[0] & 31, 0, arg2[0] & 31);
568         return true;
571 static bool attr_w cgen_jmp_cond(struct codegen_context *ctx, unsigned size, unsigned aux, unsigned length)
573         int8_t cond;
574         cond = jmp_cond[aux];
575         if (unlikely(cond < 0))
576                 internal(file_line, "cgen_jmp_cond: invalid condition %u", aux);
577         if (aux & COND_FP) {
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));
587                 } else {
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);
592                 }
593         } else {
594                 internal(file_line, "cgen_jmp_cond: invalid size %u", size);
595         }
596         cgen_four(SPARC_NOP);
597         return true;
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;
604         switch (aux) {
605                 case COND_E:    mc |= SPARC_BR_BRZ; break;
606                 case COND_LE:   mc |= SPARC_BR_BRLEZ; break;
607                 case COND_S:
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;
611                 case COND_NS:
612                 case COND_GE:   mc |= SPARC_BR_GEZ; break;
613                 default:
614                         internal(file_line, "cgen_jmp_reg: invalid condition %u", aux);
615         }
616         switch (length) {
617                 case JMP_SHORTEST:
618                         g(add_relocation(ctx, JMP_SHORTEST, 1, NULL));
619                         cgen_four(mc);
620                         cgen_four(SPARC_NOP);
621                         return true;
622                 case JMP_SHORT:
623                 case JMP_LONG:
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);
628                         return true;
629                 default:
630                         internal(file_line, "cgen_jmp_reg: invalid length %u", length);
631                         return false;
632         }
635 static bool attr_w resolve_relocation(struct codegen_context *ctx, struct relocation *reloc)
637         uint32_t mc;
638         int64_t offs = (int64_t)(ctx->label_to_pos[reloc->label_id] >> 2) - (int64_t)(reloc->position >> 2);
639         switch (reloc->length) {
640                 case JMP_SHORTEST:
641                         if (unlikely(offs < -0x00008000) || unlikely(offs >= 0x00008000))
642                                 return false;
643                         memcpy(&mc, ctx->mcode + reloc->position, 4);
644                         mc &= ~0x00303fffU;
645                         mc |= offs & 0x3fffU;
646                         mc |= (offs & 0xc000U) << 6;
647                         memcpy(ctx->mcode + reloc->position, &mc, 4);
648                         return true;
649                 case JMP_SHORT:
650                         if (unlikely(offs < -0x00040000) || unlikely(offs >= 0x00040000))
651                                 return false;
652                         memcpy(&mc, ctx->mcode + reloc->position, 4);
653                         mc &= ~0x0007ffffU;
654                         mc |= offs & 0x0007ffffU;
655                         memcpy(ctx->mcode + reloc->position, &mc, 4);
656                         return true;
657                 case JMP_LONG:
658                         if (unlikely(offs < -0x00200000) || unlikely(offs >= 0x00200000))
659                                 return false;
660                         memcpy(&mc, ctx->mcode + reloc->position, 4);
661                         mc &= ~0x003fffffU;
662                         mc |= offs & 0x003fffffU;
663                         memcpy(ctx->mcode + reloc->position, &mc, 4);
664                         return true;
665                 default:
666                         internal(file_line, "resolve_relocation: invalid relocation length %u", reloc->length);
667         }
668         return false;
671 static bool attr_w cgen_insn(struct codegen_context *ctx, uint32_t insn)
673         uint32_t reg;
674         /*debug("insn: %08x", insn);*/
675         switch (insn_opcode(insn)) {
676                 case INSN_ENTRY:
677                         g(cgen_entry(ctx));
678                         return true;
679                 case INSN_LABEL:
680                         g(cgen_label(ctx));
681                         return true;
682                 case INSN_RET:
683                         cgen_four(SPARC_RETURN | ((uint32_t)R_I7 << 14) | SPARC_IMM_BIT | 8);
684                         cgen_four(SPARC_NOP);
685                         return true;
686                 case INSN_CALL_INDIRECT:
687                         reg = cget_one(ctx);
688                         cgen_sparc_imm(SPARC_JMPL, R_O7, reg, R_ZERO);
689                         cgen_four(SPARC_NOP);
690                         return true;
691                 case INSN_MOV:
692                         g(cgen_mov(ctx, insn_op_size(insn), false));
693                         return true;
694                 case INSN_MOVSX:
695                         g(cgen_mov(ctx, insn_op_size(insn), true));
696                         return true;
697                 case INSN_CMP:
698                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
699                                 goto invalid_insn;
700                         g(cgen_cmp(ctx, SPARC_SUB));
701                         return true;
702                 case INSN_CMN:
703                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
704                                 goto invalid_insn;
705                         g(cgen_cmp(ctx, SPARC_ADD));
706                         return true;
707                 case INSN_TEST:
708                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
709                                 goto invalid_insn;
710                         g(cgen_cmp(ctx, SPARC_AND));
711                         return true;
712                 case INSN_ALU:
713                 case INSN_ALU_FLAGS:
714                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
715                                 goto invalid_insn;
716                         g(cgen_alu(ctx, insn_writes_flags(insn), insn_aux(insn)));
717                         return true;
718                 case INSN_ALU1:
719                 case INSN_ALU1_FLAGS:
720                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
721                                 goto invalid_insn;
722                         g(cgen_alu1(ctx, insn_writes_flags(insn), insn_aux(insn)));
723                         return true;
724                 case INSN_ROT:
725                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
726                                 goto invalid_insn;
727                         g(cgen_rot(ctx, insn_op_size(insn), insn_aux(insn)));
728                         return true;
729                 case INSN_CMOV:
730                         if (unlikely(!SPARC_9))
731                                 goto invalid_insn;
732                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
733                                 goto invalid_insn;
734                         g(cgen_cmov(ctx, insn_aux(insn), false));
735                         return true;
736                 case INSN_CMOV_XCC:
737                         if (unlikely(!SPARC_9))
738                                 goto invalid_insn;
739                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
740                                 goto invalid_insn;
741                         g(cgen_cmov(ctx, insn_aux(insn), true));
742                         return true;
743                 case INSN_MOVR:
744                         if (unlikely(!SPARC_9))
745                                 goto invalid_insn;
746                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
747                                 goto invalid_insn;
748                         g(cgen_movr(ctx, insn_aux(insn)));
749                         return true;
750                 case INSN_STP:
751                 case INSN_LDP:
752                         if (unlikely(insn_op_size(insn) != OP_SIZE_4))
753                                 goto invalid_insn;
754                         g(cgen_ldp_stp(ctx, insn_opcode(insn) == INSN_LDP));
755                         return true;
756                 case INSN_FP_CMP:
757                         g(cgen_fp_cmp(ctx, insn_op_size(insn)));
758                         return true;
759                 case INSN_FP_ALU:
760                         g(cgen_fp_alu(ctx, insn_op_size(insn), insn_aux(insn)));
761                         return true;
762                 case INSN_FP_ALU1:
763                         g(cgen_fp_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
764                         return true;
765                 case INSN_FP_TO_INT64:
766 #ifdef ARCH_SPARC32
767                         goto invalid_insn;
768 #endif
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)));
771                         return true;
772                 case INSN_FP_FROM_INT64:
773 #ifdef ARCH_SPARC32
774                         goto invalid_insn;
775 #endif
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)));
778                         return true;
779                 case INSN_JMP:
780                         g(add_relocation(ctx, JMP_LONG, 0, NULL));
781                         cgen_four(SPARC_BCC | SPARC_BCC_A | 0x8 << 25);
782                         return true;
783                 case INSN_JMP_COND:
784                         g(cgen_jmp_cond(ctx, insn_op_size(insn), insn_aux(insn), insn_jump_size(insn)));
785                         return true;
786                 case INSN_JMP_REG:
787                         if (unlikely(!SPARC_9))
788                                 goto invalid_insn;
789                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
790                                 goto invalid_insn;
791                         g(cgen_jmp_reg(ctx, insn_aux(insn), insn_jump_size(insn)));
792                         return true;
793                 case INSN_JMP_INDIRECT:
794                         reg = cget_one(ctx);
795                         cgen_sparc_imm(SPARC_JMPL, R_ZERO, reg, R_ZERO);
796                         cgen_four(SPARC_NOP);
797                         return true;
798                 default:
799                 invalid_insn:
800                         internal(file_line, "cgen_insn: invalid insn %08x", insn);
801                         return false;
802         }