x86: implement 128-bit popcnt
[ajla.git] / c2-sparc.inc
blob6bdbc8db56ce90dcb1cc4bae210efe49eac289e5
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 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);
318         switch (alu) {
319                 case ALU1_NOT:
320                         g(cgen_alu_args(ctx, writes_flags, SPARC_XORN, arg1, arg2, &z));
321                         return true;
322                 case ALU1_NEG:
323                         g(cgen_alu_args(ctx, writes_flags, SPARC_SUB, arg1, &z, arg2));
324                         return true;
325                 case ALU1_INC:
326                         g(cgen_alu_args(ctx, writes_flags, SPARC_ADD, arg1, arg2, one_imm));
327                         return true;
328                 case ALU1_DEC:
329                         g(cgen_alu_args(ctx, writes_flags, SPARC_SUB, arg1, arg2, one_imm));
330                         return true;
331                 case ALU1_POPCNT:
332                         g(cgen_alu_args(ctx, writes_flags, SPARC_POPC, arg1, &z, arg2));
333                         return true;
334                 default:
335                         internal(file_line, "cgen_alu1: invalid operation %u", alu);
336                         return false;
337         }
340 static bool attr_w cgen_rot(struct codegen_context *ctx, unsigned size, uint8_t rot)
342         uint32_t mc;
343         int64_t imm;
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))
350                 goto invalid;
352         switch (rot) {
353                 case ROT_SHL:   mc = SPARC_SLL; break;
354                 case ROT_SHR:   mc = SPARC_SRL; break;
355                 case ROT_SAR:   mc = SPARC_SRA; break;
356                 default:
357                         goto invalid;
358         }
360         if (size == OP_SIZE_8)
361                 mc |= SPARC_S_64;
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)))
366                         goto invalid;
367                 cgen_sparc_imm(mc, arg1[0], arg2[0], imm);
368                 return true;
369         } else {
370                 cgen_sparc_3reg(mc, arg1[0], arg2[0], arg3[0]);
371                 return true;
372         }
374 invalid:
375         internal(file_line, "cgen_rot: invalid arguments: %02x, %02x, %02x, %u, %u", arg1[0], arg2[0], arg3[0], size, rot);
376         return false;
379 static bool attr_w cgen_cmov(struct codegen_context *ctx, unsigned aux, bool xcc)
381         int8_t cond;
382         uint32_t mc;
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");
389         mc = SPARC_CMOV;
390         cond = jmp_cond[aux];
391         if (unlikely(cond < 0))
392                 internal(file_line, "cgen_cmov: invalid condition %u", aux);
393         if (aux & COND_FP) {
394                 mc |= SPARC_CMOV_FCC0;
395         } else {
396                 mc |= xcc ? SPARC_CMOV_XCC : SPARC_CMOV_ICC;
397         }
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]);
402                 mc |= SPARC_IMM_BIT;
403                 mc |= imm & 0x7FF;
404         } else {
405                 mc |= arg3[0];
406         }
407         cgen_four(mc);
408         return true;
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);
419         switch (aux) {
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);
427         }
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]);
434                 mc |= SPARC_IMM_BIT;
435                 mc |= imm & 0x3FF;
436         } else {
437                 mc |= arg4[0];
438         }
439         cgen_four(mc);
440         return true;
443 static bool attr_w cgen_ldp_stp(struct codegen_context *ctx, bool ldr)
445         uint8_t *arg1, *arg2, *arg3;
446         if (!ldr) {
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);
451         } else {
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);
456         }
457         if (unlikely(arg2[0] >= 32) || unlikely(arg3[0] >= 32))
458                 goto invalid;
459         if (unlikely((arg3[0] & 1) != 0) || unlikely(arg2[0] != arg3[0] + 1))
460                 goto invalid;
462         if (ldr)
463                 return cgen_ld_st(ctx, SPARC_LDD, arg3[0], arg1);
464         else
465                 return cgen_ld_st(ctx, SPARC_STD, arg3[0], arg1);
467 invalid:
468         internal(file_line, "cgen_ldp_stp: invalid arguments %02x, %02x, %02x", arg1[0], arg2[0], arg3[0]);
469         return false;
472 static bool attr_w cgen_fp_cmp(struct codegen_context *ctx, unsigned op_size)
474         uint32_t mc;
475         uint8_t *arg1 = ctx->code_position;
476         uint8_t *arg2 = arg1 + arg_size(*arg1);
477         ctx->code_position = arg2 + arg_size(*arg2);
478         mc = SPARC_FCMP;
479         switch (op_size) {
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);
484         }
485         cgen_sparc_3reg(mc, 0, arg1[0] & 31, arg2[0] & 31);
486         return true;
489 static bool attr_w cgen_fp_alu(struct codegen_context *ctx, unsigned op_size, unsigned aux)
491         uint32_t mc;
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);
496         switch (aux) {
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);
502         }
503         switch (op_size) {
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);
508         }
509         cgen_sparc_3reg(mc, arg1[0] & 31, arg2[0] & 31, arg3[0] & 31);
510         return true;
513 static bool attr_w cgen_fp_alu1(struct codegen_context *ctx, unsigned op_size, unsigned aux)
515         uint32_t mc;
516         uint8_t *arg1 = ctx->code_position;
517         uint8_t *arg2 = arg1 + arg_size(*arg1);
518         ctx->code_position = arg2 + arg_size(*arg2);
519         switch (aux) {
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);
523         }
524         switch (op_size) {
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);
529         }
530         cgen_sparc_3reg(mc, arg1[0] & 31, 0, arg2[0] & 31);
531         return true;
534 static bool attr_w cgen_fp_to_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
536         uint32_t mc;
537         uint8_t *arg1 = ctx->code_position;
538         uint8_t *arg2 = arg1 + arg_size(*arg1);
539         ctx->code_position = arg2 + arg_size(*arg2);
540         mc = SPARC_FTOI;
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);
545         }
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);
551         }
552         cgen_sparc_3reg(mc, arg1[0] & 31, 0, arg2[0] & 31);
553         return true;
556 static bool attr_w cgen_fp_from_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
558         uint32_t mc;
559         uint8_t *arg1 = ctx->code_position;
560         uint8_t *arg2 = arg1 + arg_size(*arg1);
561         ctx->code_position = arg2 + arg_size(*arg2);
562         mc = SPARC_ITOF;
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);
567         }
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);
573         }
574         cgen_sparc_3reg(mc, arg1[0] & 31, 0, arg2[0] & 31);
575         return true;
578 static bool attr_w cgen_jmp_cond(struct codegen_context *ctx, unsigned size, unsigned aux, unsigned length)
580         int8_t cond;
581         cond = jmp_cond[aux];
582         if (unlikely(cond < 0))
583                 internal(file_line, "cgen_jmp_cond: invalid condition %u", aux);
584         if (aux & COND_FP) {
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));
594                 } else {
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);
599                 }
600         } else {
601                 internal(file_line, "cgen_jmp_cond: invalid size %u", size);
602         }
603         cgen_four(SPARC_NOP);
604         return true;
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;
611         switch (aux) {
612                 case COND_E:    mc |= SPARC_BR_BRZ; break;
613                 case COND_LE:   mc |= SPARC_BR_BRLEZ; break;
614                 case COND_S:
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;
618                 case COND_NS:
619                 case COND_GE:   mc |= SPARC_BR_GEZ; break;
620                 default:
621                         internal(file_line, "cgen_jmp_reg: invalid condition %u", aux);
622         }
623         switch (length) {
624                 case JMP_SHORTEST:
625                         g(add_relocation(ctx, JMP_SHORTEST, 1, NULL));
626                         cgen_four(mc);
627                         cgen_four(SPARC_NOP);
628                         return true;
629                 case JMP_SHORT:
630                 case JMP_LONG:
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);
635                         return true;
636                 default:
637                         internal(file_line, "cgen_jmp_reg: invalid length %u", length);
638                         return false;
639         }
642 static bool attr_w resolve_relocation(struct codegen_context *ctx, struct relocation *reloc)
644         uint32_t mc;
645         int64_t offs = (int64_t)(ctx->label_to_pos[reloc->label_id] >> 2) - (int64_t)(reloc->position >> 2);
646         switch (reloc->length) {
647                 case JMP_SHORTEST:
648                         if (unlikely(offs < -0x00008000) || unlikely(offs >= 0x00008000))
649                                 return false;
650                         memcpy(&mc, ctx->mcode + reloc->position, 4);
651                         mc &= ~0x00303fffU;
652                         mc |= offs & 0x3fffU;
653                         mc |= (offs & 0xc000U) << 6;
654                         memcpy(ctx->mcode + reloc->position, &mc, 4);
655                         return true;
656                 case JMP_SHORT:
657                         if (unlikely(offs < -0x00040000) || unlikely(offs >= 0x00040000))
658                                 return false;
659                         memcpy(&mc, ctx->mcode + reloc->position, 4);
660                         mc &= ~0x0007ffffU;
661                         mc |= offs & 0x0007ffffU;
662                         memcpy(ctx->mcode + reloc->position, &mc, 4);
663                         return true;
664                 case JMP_LONG:
665                         if (unlikely(offs < -0x00200000) || unlikely(offs >= 0x00200000))
666                                 return false;
667                         memcpy(&mc, ctx->mcode + reloc->position, 4);
668                         mc &= ~0x003fffffU;
669                         mc |= offs & 0x003fffffU;
670                         memcpy(ctx->mcode + reloc->position, &mc, 4);
671                         return true;
672                 default:
673                         internal(file_line, "resolve_relocation: invalid relocation length %u", reloc->length);
674         }
675         return false;
678 static bool attr_w cgen_insn(struct codegen_context *ctx, uint32_t insn)
680         uint32_t reg;
681         /*debug("insn: %08x", insn);*/
682         switch (insn_opcode(insn)) {
683                 case INSN_ENTRY:
684                         g(cgen_entry(ctx));
685                         return true;
686                 case INSN_LABEL:
687                         g(cgen_label(ctx));
688                         return true;
689                 case INSN_RET:
690                         cgen_four(SPARC_RETURN | ((uint32_t)R_I7 << 14) | SPARC_IMM_BIT | 8);
691                         cgen_four(SPARC_NOP);
692                         return true;
693                 case INSN_CALL_INDIRECT:
694                         reg = cget_one(ctx);
695                         cgen_sparc_imm(SPARC_JMPL, R_O7, reg, R_ZERO);
696                         cgen_four(SPARC_NOP);
697                         return true;
698                 case INSN_MOV:
699                         g(cgen_mov(ctx, insn_op_size(insn), false));
700                         return true;
701                 case INSN_MOVSX:
702                         g(cgen_mov(ctx, insn_op_size(insn), true));
703                         return true;
704                 case INSN_CMP:
705                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
706                                 goto invalid_insn;
707                         g(cgen_cmp(ctx, SPARC_SUB));
708                         return true;
709                 case INSN_CMN:
710                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
711                                 goto invalid_insn;
712                         g(cgen_cmp(ctx, SPARC_ADD));
713                         return true;
714                 case INSN_TEST:
715                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
716                                 goto invalid_insn;
717                         g(cgen_cmp(ctx, SPARC_AND));
718                         return true;
719                 case INSN_ALU:
720                 case INSN_ALU_FLAGS:
721                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
722                                 goto invalid_insn;
723                         g(cgen_alu(ctx, insn_writes_flags(insn), insn_aux(insn)));
724                         return true;
725                 case INSN_ALU1:
726                 case INSN_ALU1_FLAGS:
727                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
728                                 goto invalid_insn;
729                         g(cgen_alu1(ctx, insn_writes_flags(insn), insn_aux(insn)));
730                         return true;
731                 case INSN_ROT:
732                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
733                                 goto invalid_insn;
734                         g(cgen_rot(ctx, insn_op_size(insn), insn_aux(insn)));
735                         return true;
736                 case INSN_CMOV:
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), false));
742                         return true;
743                 case INSN_CMOV_XCC:
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_cmov(ctx, insn_aux(insn), true));
749                         return true;
750                 case INSN_MOVR:
751                         if (unlikely(!SPARC_9))
752                                 goto invalid_insn;
753                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
754                                 goto invalid_insn;
755                         g(cgen_movr(ctx, insn_aux(insn)));
756                         return true;
757                 case INSN_STP:
758                 case INSN_LDP:
759                         if (unlikely(insn_op_size(insn) != OP_SIZE_4))
760                                 goto invalid_insn;
761                         g(cgen_ldp_stp(ctx, insn_opcode(insn) == INSN_LDP));
762                         return true;
763                 case INSN_FP_CMP:
764                         g(cgen_fp_cmp(ctx, insn_op_size(insn)));
765                         return true;
766                 case INSN_FP_ALU:
767                         g(cgen_fp_alu(ctx, insn_op_size(insn), insn_aux(insn)));
768                         return true;
769                 case INSN_FP_ALU1:
770                         g(cgen_fp_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
771                         return true;
772                 case INSN_FP_TO_INT64:
773 #ifdef ARCH_SPARC32
774                         goto invalid_insn;
775 #endif
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)));
778                         return true;
779                 case INSN_FP_FROM_INT64:
780 #ifdef ARCH_SPARC32
781                         goto invalid_insn;
782 #endif
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)));
785                         return true;
786                 case INSN_JMP:
787                         g(add_relocation(ctx, JMP_LONG, 0, NULL));
788                         cgen_four(SPARC_BCC | SPARC_BCC_A | 0x8 << 25);
789                         return true;
790                 case INSN_JMP_COND:
791                         g(cgen_jmp_cond(ctx, insn_op_size(insn), insn_aux(insn), insn_jump_size(insn)));
792                         return true;
793                 case INSN_JMP_REG:
794                         if (unlikely(!SPARC_9))
795                                 goto invalid_insn;
796                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
797                                 goto invalid_insn;
798                         g(cgen_jmp_reg(ctx, insn_aux(insn), insn_jump_size(insn)));
799                         return true;
800                 case INSN_JMP_INDIRECT:
801                         reg = cget_one(ctx);
802                         cgen_sparc_imm(SPARC_JMPL, R_ZERO, reg, R_ZERO);
803                         cgen_four(SPARC_NOP);
804                         return true;
805                 default:
806                 invalid_insn:
807                         internal(file_line, "cgen_insn: invalid insn %08x", insn);
808                         return false;
809         }