x86: use push and pop also on x32
[ajla.git] / c2-sparc.inc
blob99f0546c8ddb8c255e663c0c3361d7822c0308cb
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_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] = {
140         SPARC_ADD,
141         SPARC_OR,
142         SPARC_ADDC,
143         SPARC_SUBC,
144         SPARC_AND,
145         SPARC_SUB,
146         SPARC_XOR,
147         -1U,
148         SPARC_ORN,
149         SPARC_ANDN,
150         SPARC_XORN,
151         -1U,
152         -1U,
153         -1U,
154         -1U,
155         -1U,
156         SPARC_MULX,
157         -1U,
158         -1U,
159         SPARC_UDIVX,
160         SPARC_SDIVX,
161         -1U,
162         -1U,
163         SPARC_SAVE,
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)
173         int64_t imm;
174         if (address[0] == ARG_ADDRESS_2) {
175                 imm = get_imm(&address[3]);
176                 if (unlikely(imm != 0))
177                         goto invalid;
178                 cgen_sparc_3reg(mc, reg, address[1], address[2]);
179                 return true;
180         } else if (address[0] == ARG_ADDRESS_1) {
181                 imm = get_imm(&address[2]);
182                 if (unlikely(imm < -4096) || unlikely(imm >= 4096))
183                         goto invalid;
184                 cgen_sparc_imm(mc, reg, address[1], imm);
185                 return true;
186         }
188         imm = 0;
190 invalid:
191         internal(file_line, "cgen_ld_st: invalid address: %02x, %02x, %"PRIxMAX"", reg, address[0], (uintmax_t)imm);
192         return false;
195 static bool attr_w cgen_mov(struct codegen_context *ctx, unsigned size, bool sx)
197         int64_t imm;
198         uint8_t *arg1 = ctx->code_position;
199         uint8_t *arg2 = arg1 + arg_size(*arg1);
200         ctx->code_position = arg2 + arg_size(*arg2);
201         if (arg1[0] < 32) {
202                 if (arg2[0] < 32) {
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);
206                         return true;
207                 }
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);
212                         } else {
213                                 if (imm & ~0xfffffc00ULL)
214                                         internal(file_line, "cgen_mov: invalid imm");
215                                 cgen_four(SPARC_SETHI | ((uint32_t)arg1[0] << 25) | imm >> 10);
216                                 return true;
217                         }
218                 }
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);
222                         } else {
223                                 return cgen_ld_st(ctx, size == OP_SIZE_1 ? SPARC_LDSB : size == OP_SIZE_2 ? SPARC_LDSH : SPARC_LDSW, arg1[0], arg2);
224                         }
225                 }
226         }
227         if (arg1[0] < 64) {
228                 if (arg2[0] < 64)
229                         goto invalid;
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);
231         }
232         if (arg2[0] < 32) {
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);
234         }
235         if (arg2[0] < 64) {
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);
237         }
238         if (arg2[0] == ARG_IMM) {
239                 imm = get_imm(&arg2[1]);
240                 if (!imm)
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);
242         }
243 invalid:
244         internal(file_line, "cgen_mov: invalid arguments %02x, %02x", arg1[0], arg2[0]);
245         return false;
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)
250         int64_t imm;
252         if (unlikely(arg1[0] >= 32) || unlikely(arg2[0] >= 32))
253                 goto invalid;
255         if (writes_flags)
256                 mc |= SPARC_CC_BIT;
258         if (arg3[0] == ARG_IMM) {
259                 imm = get_imm(&arg3[1]);
260                 if (unlikely(imm < -4096) || unlikely(imm >= 4096))
261                         goto invalid;
262                 cgen_sparc_imm(mc, arg1[0], arg2[0], imm);
263                 return true;
264         } else if (likely(arg3[0] < 32)) {
265                 cgen_sparc_3reg(mc, arg1[0], arg2[0], arg3[0]);
266                 return true;
267         }
269 invalid:
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);
271         return false;
274 static bool attr_w cgen_cmp(struct codegen_context *ctx, uint32_t mc)
276         uint8_t z = R_ZERO;
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)
285         uint32_t mc;
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));
295         mc = alu_map[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)
304         uint8_t z = R_ZERO;
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);
309         switch (alu) {
310                 case ALU1_NOT:
311                         g(cgen_alu_args(ctx, writes_flags, SPARC_XORN, arg1, arg2, &z));
312                         return true;
313                 case ALU1_NEG:
314                         g(cgen_alu_args(ctx, writes_flags, SPARC_SUB, arg1, &z, arg2));
315                         return true;
316                 case ALU1_INC:
317                         g(cgen_alu_args(ctx, writes_flags, SPARC_ADD, arg1, arg2, one_imm));
318                         return true;
319                 case ALU1_DEC:
320                         g(cgen_alu_args(ctx, writes_flags, SPARC_SUB, arg1, arg2, one_imm));
321                         return true;
322                 case ALU1_POPCNT:
323                         g(cgen_alu_args(ctx, writes_flags, SPARC_POPC, arg1, &z, arg2));
324                         return true;
325                 default:
326                         internal(file_line, "cgen_alu1: invalid operation %u", alu);
327                         return false;
328         }
331 static bool attr_w cgen_rot(struct codegen_context *ctx, unsigned size, uint8_t rot)
333         uint32_t mc;
334         int64_t imm;
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))
341                 goto invalid;
343         switch (rot) {
344                 case ROT_SHL:   mc = SPARC_SLL; break;
345                 case ROT_SHR:   mc = SPARC_SRL; break;
346                 case ROT_SAR:   mc = SPARC_SRA; break;
347                 default:
348                         goto invalid;
349         }
351         if (size == OP_SIZE_8)
352                 mc |= SPARC_S_64;
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)))
357                         goto invalid;
358                 cgen_sparc_imm(mc, arg1[0], arg2[0], imm);
359                 return true;
360         } else {
361                 cgen_sparc_3reg(mc, arg1[0], arg2[0], arg3[0]);
362                 return true;
363         }
365 invalid:
366         internal(file_line, "cgen_rot: invalid arguments: %02x, %02x, %02x, %u, %u", arg1[0], arg2[0], arg3[0], size, rot);
367         return false;
370 static bool attr_w cgen_cmov(struct codegen_context *ctx, unsigned aux, bool xcc)
372         int8_t cond;
373         uint32_t mc;
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");
380         mc = SPARC_CMOV;
381         cond = jmp_cond[aux];
382         if (unlikely(cond < 0))
383                 internal(file_line, "cgen_cmov: invalid condition %u", aux);
384         if (aux & COND_FP) {
385                 mc |= SPARC_CMOV_FCC0;
386         } else {
387                 mc |= xcc ? SPARC_CMOV_XCC : SPARC_CMOV_ICC;
388         }
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]);
393                 mc |= SPARC_IMM_BIT;
394                 mc |= imm & 0x7FF;
395         } else {
396                 mc |= arg3[0];
397         }
398         cgen_four(mc);
399         return true;
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);
410         switch (aux) {
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);
418         }
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]);
425                 mc |= SPARC_IMM_BIT;
426                 mc |= imm & 0x3FF;
427         } else {
428                 mc |= arg4[0];
429         }
430         cgen_four(mc);
431         return true;
434 static bool attr_w cgen_ldp_stp(struct codegen_context *ctx, bool ldr)
436         uint8_t *arg1, *arg2, *arg3;
437         if (!ldr) {
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);
442         } else {
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);
447         }
448         if (unlikely(arg2[0] >= 32) || unlikely(arg3[0] >= 32))
449                 goto invalid;
450         if (unlikely((arg3[0] & 1) != 0) || unlikely(arg2[0] != arg3[0] + 1))
451                 goto invalid;
453         if (ldr)
454                 return cgen_ld_st(ctx, SPARC_LDD, arg3[0], arg1);
455         else
456                 return cgen_ld_st(ctx, SPARC_STD, arg3[0], arg1);
458 invalid:
459         internal(file_line, "cgen_ldp_stp: invalid arguments %02x, %02x, %02x", arg1[0], arg2[0], arg3[0]);
460         return false;
463 static bool attr_w cgen_fp_cmp(struct codegen_context *ctx, unsigned op_size)
465         uint32_t mc;
466         uint8_t *arg1 = ctx->code_position;
467         uint8_t *arg2 = arg1 + arg_size(*arg1);
468         ctx->code_position = arg2 + arg_size(*arg2);
469         mc = SPARC_FCMP;
470         switch (op_size) {
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);
475         }
476         cgen_sparc_3reg(mc, 0, arg1[0] & 31, arg2[0] & 31);
477         return true;
480 static bool attr_w cgen_fp_alu(struct codegen_context *ctx, unsigned op_size, unsigned aux)
482         uint32_t mc;
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);
487         switch (aux) {
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);
493         }
494         switch (op_size) {
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);
499         }
500         cgen_sparc_3reg(mc, arg1[0] & 31, arg2[0] & 31, arg3[0] & 31);
501         return true;
504 static bool attr_w cgen_fp_alu1(struct codegen_context *ctx, unsigned op_size, unsigned aux)
506         uint32_t mc;
507         uint8_t *arg1 = ctx->code_position;
508         uint8_t *arg2 = arg1 + arg_size(*arg1);
509         ctx->code_position = arg2 + arg_size(*arg2);
510         switch (aux) {
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);
514         }
515         switch (op_size) {
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);
520         }
521         cgen_sparc_3reg(mc, arg1[0] & 31, 0, arg2[0] & 31);
522         return true;
525 static bool attr_w cgen_fp_to_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
527         uint32_t mc;
528         uint8_t *arg1 = ctx->code_position;
529         uint8_t *arg2 = arg1 + arg_size(*arg1);
530         ctx->code_position = arg2 + arg_size(*arg2);
531         mc = SPARC_FTOI;
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);
536         }
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);
542         }
543         cgen_sparc_3reg(mc, arg1[0] & 31, 0, arg2[0] & 31);
544         return true;
547 static bool attr_w cgen_fp_from_int(struct codegen_context *ctx, unsigned int_op_size, unsigned fp_op_size)
549         uint32_t mc;
550         uint8_t *arg1 = ctx->code_position;
551         uint8_t *arg2 = arg1 + arg_size(*arg1);
552         ctx->code_position = arg2 + arg_size(*arg2);
553         mc = SPARC_ITOF;
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);
558         }
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);
564         }
565         cgen_sparc_3reg(mc, arg1[0] & 31, 0, arg2[0] & 31);
566         return true;
569 static bool attr_w cgen_jmp_cond(struct codegen_context *ctx, unsigned size, unsigned aux, unsigned length)
571         int8_t cond;
572         cond = jmp_cond[aux];
573         if (unlikely(cond < 0))
574                 internal(file_line, "cgen_jmp_cond: invalid condition %u", aux);
575         if (aux & COND_FP) {
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));
585                 } else {
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);
590                 }
591         } else {
592                 internal(file_line, "cgen_jmp_cond: invalid size %u", size);
593         }
594         cgen_four(SPARC_NOP);
595         return true;
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;
602         switch (aux) {
603                 case COND_E:    mc |= SPARC_BR_BRZ; break;
604                 case COND_LE:   mc |= SPARC_BR_BRLEZ; break;
605                 case COND_S:
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;
609                 case COND_NS:
610                 case COND_GE:   mc |= SPARC_BR_GEZ; break;
611                 default:
612                         internal(file_line, "cgen_jmp_reg: invalid condition %u", aux);
613         }
614         switch (length) {
615                 case JMP_SHORTEST:
616                         g(add_relocation(ctx, JMP_SHORTEST, 1, NULL));
617                         cgen_four(mc);
618                         cgen_four(SPARC_NOP);
619                         return true;
620                 case JMP_SHORT:
621                 case JMP_LONG:
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);
626                         return true;
627                 default:
628                         internal(file_line, "cgen_jmp_reg: invalid length %u", length);
629                         return false;
630         }
633 static bool attr_w resolve_relocation(struct codegen_context *ctx, struct relocation *reloc)
635         uint32_t mc;
636         int64_t offs = (int64_t)(ctx->label_to_pos[reloc->label_id] >> 2) - (int64_t)(reloc->position >> 2);
637         switch (reloc->length) {
638                 case JMP_SHORTEST:
639                         if (unlikely(offs < -0x00008000) || unlikely(offs >= 0x00008000))
640                                 return false;
641                         memcpy(&mc, ctx->mcode + reloc->position, 4);
642                         mc &= ~0x00303fffU;
643                         mc |= offs & 0x3fffU;
644                         mc |= (offs & 0xc000U) << 6;
645                         memcpy(ctx->mcode + reloc->position, &mc, 4);
646                         return true;
647                 case JMP_SHORT:
648                         if (unlikely(offs < -0x00040000) || unlikely(offs >= 0x00040000))
649                                 return false;
650                         memcpy(&mc, ctx->mcode + reloc->position, 4);
651                         mc &= ~0x0007ffffU;
652                         mc |= offs & 0x0007ffffU;
653                         memcpy(ctx->mcode + reloc->position, &mc, 4);
654                         return true;
655                 case JMP_LONG:
656                         if (unlikely(offs < -0x00200000) || unlikely(offs >= 0x00200000))
657                                 return false;
658                         memcpy(&mc, ctx->mcode + reloc->position, 4);
659                         mc &= ~0x003fffffU;
660                         mc |= offs & 0x003fffffU;
661                         memcpy(ctx->mcode + reloc->position, &mc, 4);
662                         return true;
663                 default:
664                         internal(file_line, "resolve_relocation: invalid relocation length %u", reloc->length);
665         }
666         return false;
669 static bool attr_w cgen_insn(struct codegen_context *ctx, uint32_t insn)
671         uint32_t reg;
672         /*debug("insn: %08x", insn);*/
673         switch (insn_opcode(insn)) {
674                 case INSN_ENTRY:
675                         g(cgen_entry(ctx));
676                         return true;
677                 case INSN_LABEL:
678                         g(cgen_label(ctx));
679                         return true;
680                 case INSN_RET:
681                         cgen_four(SPARC_RETURN | ((uint32_t)R_I7 << 14) | SPARC_IMM_BIT | 8);
682                         cgen_four(SPARC_NOP);
683                         return true;
684                 case INSN_CALL_INDIRECT:
685                         reg = cget_one(ctx);
686                         cgen_sparc_imm(SPARC_JMPL, R_O7, reg, R_ZERO);
687                         cgen_four(SPARC_NOP);
688                         return true;
689                 case INSN_MOV:
690                         g(cgen_mov(ctx, insn_op_size(insn), false));
691                         return true;
692                 case INSN_MOVSX:
693                         g(cgen_mov(ctx, insn_op_size(insn), true));
694                         return true;
695                 case INSN_CMP:
696                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
697                                 goto invalid_insn;
698                         g(cgen_cmp(ctx, SPARC_SUB));
699                         return true;
700                 case INSN_CMN:
701                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
702                                 goto invalid_insn;
703                         g(cgen_cmp(ctx, SPARC_ADD));
704                         return true;
705                 case INSN_TEST:
706                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
707                                 goto invalid_insn;
708                         g(cgen_cmp(ctx, SPARC_AND));
709                         return true;
710                 case INSN_ALU:
711                 case INSN_ALU_FLAGS:
712                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
713                                 goto invalid_insn;
714                         g(cgen_alu(ctx, insn_writes_flags(insn), insn_aux(insn)));
715                         return true;
716                 case INSN_ALU1:
717                 case INSN_ALU1_FLAGS:
718                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
719                                 goto invalid_insn;
720                         g(cgen_alu1(ctx, insn_writes_flags(insn), insn_aux(insn)));
721                         return true;
722                 case INSN_ROT:
723                         if (unlikely(insn_op_size(insn) < OP_SIZE_4))
724                                 goto invalid_insn;
725                         g(cgen_rot(ctx, insn_op_size(insn), insn_aux(insn)));
726                         return true;
727                 case INSN_CMOV:
728                         if (unlikely(!SPARC_9))
729                                 goto invalid_insn;
730                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
731                                 goto invalid_insn;
732                         g(cgen_cmov(ctx, insn_aux(insn), false));
733                         return true;
734                 case INSN_CMOV_XCC:
735                         if (unlikely(!SPARC_9))
736                                 goto invalid_insn;
737                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
738                                 goto invalid_insn;
739                         g(cgen_cmov(ctx, insn_aux(insn), true));
740                         return true;
741                 case INSN_MOVR:
742                         if (unlikely(!SPARC_9))
743                                 goto invalid_insn;
744                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
745                                 goto invalid_insn;
746                         g(cgen_movr(ctx, insn_aux(insn)));
747                         return true;
748                 case INSN_STP:
749                 case INSN_LDP:
750                         if (unlikely(insn_op_size(insn) != OP_SIZE_4))
751                                 goto invalid_insn;
752                         g(cgen_ldp_stp(ctx, insn_opcode(insn) == INSN_LDP));
753                         return true;
754                 case INSN_FP_CMP:
755                         g(cgen_fp_cmp(ctx, insn_op_size(insn)));
756                         return true;
757                 case INSN_FP_ALU:
758                         g(cgen_fp_alu(ctx, insn_op_size(insn), insn_aux(insn)));
759                         return true;
760                 case INSN_FP_ALU1:
761                         g(cgen_fp_alu1(ctx, insn_op_size(insn), insn_aux(insn)));
762                         return true;
763                 case INSN_FP_TO_INT64:
764 #ifdef ARCH_SPARC32
765                         goto invalid_insn;
766 #endif
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)));
769                         return true;
770                 case INSN_FP_FROM_INT64:
771 #ifdef ARCH_SPARC32
772                         goto invalid_insn;
773 #endif
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)));
776                         return true;
777                 case INSN_JMP:
778                         g(add_relocation(ctx, JMP_LONG, 0, NULL));
779                         cgen_four(SPARC_BCC | SPARC_BCC_A | 0x8 << 25);
780                         return true;
781                 case INSN_JMP_COND:
782                         g(cgen_jmp_cond(ctx, insn_op_size(insn), insn_aux(insn), insn_jump_size(insn)));
783                         return true;
784                 case INSN_JMP_REG:
785                         if (unlikely(!SPARC_9))
786                                 goto invalid_insn;
787                         if (unlikely(insn_op_size(insn) != OP_SIZE_NATIVE))
788                                 goto invalid_insn;
789                         g(cgen_jmp_reg(ctx, insn_aux(insn), insn_jump_size(insn)));
790                         return true;
791                 case INSN_JMP_INDIRECT:
792                         reg = cget_one(ctx);
793                         cgen_sparc_imm(SPARC_JMPL, R_ZERO, reg, R_ZERO);
794                         cgen_four(SPARC_NOP);
795                         return true;
796                 default:
797                 invalid_insn:
798                         internal(file_line, "cgen_insn: invalid insn %08x", insn);
799                         return false;
800         }