ssa: delete unused label skip_must_be_flat
[ajla.git] / c1-mips.inc
blobdf5364dac4759bc2bf06d530508a783a956a855b
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 #ifdef ARCH_MIPS_O32
20 #define OP_SIZE_NATIVE  OP_SIZE_4
21 #else
22 #define OP_SIZE_NATIVE  OP_SIZE_8
23 #endif
25 #ifdef ARCH_MIPS32
26 #define OP_SIZE_ADDRESS OP_SIZE_4
27 #else
28 #define OP_SIZE_ADDRESS OP_SIZE_8
29 #endif
31 #define JMP_LIMIT       JMP_EXTRA_LONG
33 #define UNALIGNED_TRAP                  (!MIPS_R6)
35 #define ALU_WRITES_FLAGS(alu, im)       0
36 #define ALU1_WRITES_FLAGS(alu)          0
37 #define ROT_WRITES_FLAGS(alu, size, im) 0
38 #define COND_IS_LOGICAL(cond)           0
40 #define ARCH_PARTIAL_ALU(size)          0
41 #define ARCH_IS_3ADDRESS(alu, f)        1
42 #define ARCH_IS_3ADDRESS_IMM(alu, f)    1
43 #define ARCH_IS_3ADDRESS_ROT(alu, size) 1
44 #define ARCH_IS_3ADDRESS_ROT_IMM(alu)   1
45 #define ARCH_IS_2ADDRESS(alu)           1
46 #define ARCH_IS_3ADDRESS_FP             1
47 #define ARCH_HAS_FLAGS                  0
48 #define ARCH_SUPPORTS_TRAPS             OS_SUPPORTS_TRAPS
49 #define ARCH_PREFERS_SX(size)           0
50 #define ARCH_HAS_BWX                    1
51 #define ARCH_HAS_MUL                    1
52 #define ARCH_HAS_DIV                    1
53 #define ARCH_HAS_ANDN                   0
54 #define ARCH_HAS_SHIFTED_ADD(bits)      (MIPS_R6 && (bits) >= 1 && (bits) <= 4)
55 #define ARCH_HAS_BTX(btx, size, cnst)   0
56 #define ARCH_SHIFT_SIZE                 OP_SIZE_4
57 #define ARCH_NEEDS_BARRIER              0
59 #define i_size(size)                    OP_SIZE_NATIVE
60 #define i_size_rot(size)                maximum(size, OP_SIZE_4)
61 #define i_size_cmp(size)                OP_SIZE_NATIVE
63 #if __mips < 2
64 #define MIPS_LOAD_DELAY_SLOTS           1
65 #define MIPS_HAS_LS_DOUBLE              0
66 #define MIPS_HAS_SQRT                   0
67 #define MIPS_HAS_TRUNC                  0
68 #else
69 #define MIPS_LOAD_DELAY_SLOTS           0
70 #define MIPS_HAS_LS_DOUBLE              1
71 #define MIPS_HAS_SQRT                   1
72 #define MIPS_HAS_TRUNC                  1
73 #endif
75 #if __mips < 4
76 #define MIPS_R4000_ERRATA               1
77 #define MIPS_FCMP_DELAY_SLOTS           1
78 #define MIPS_HAS_MOVT                   0
79 #else
80 #define MIPS_R4000_ERRATA               0
81 #define MIPS_FCMP_DELAY_SLOTS           0
82 #define MIPS_HAS_MOVT                   1
83 #endif
85 #if __mips < 32
86 #define MIPS_HAS_CLZ                    0
87 #define MIPS_HAS_MUL                    0
88 #else
89 #define MIPS_HAS_CLZ                    1
90 #define MIPS_HAS_MUL                    1
91 #endif
93 #if __mips < 32 || !defined(__mips_isa_rev) || __mips_isa_rev < 2
94 #define MIPS_HAS_ROT                    0
95 #else
96 #define MIPS_HAS_ROT                    1
97 #endif
99 #if __mips < 32 || !defined(__mips_isa_rev) || __mips_isa_rev < 6
100 #define MIPS_R6                         0
101 #else
102 #define MIPS_R6                         1
103 #endif
105 #define R_ZERO          0x00
106 #define R_AT            0x01
107 #define R_V0            0x02
108 #define R_V1            0x03
109 #define R_A0            0x04
110 #define R_A1            0x05
111 #define R_A2            0x06
112 #define R_A3            0x07
113 #define R_T0            0x08
114 #define R_T1            0x09
115 #define R_T2            0x0a
116 #define R_T3            0x0b
117 #define R_T4            0x0c
118 #define R_T5            0x0d
119 #define R_T6            0x0e
120 #define R_T7            0x0f
121 #define R_S0            0x10
122 #define R_S1            0x11
123 #define R_S2            0x12
124 #define R_S3            0x13
125 #define R_S4            0x14
126 #define R_S5            0x15
127 #define R_S6            0x16
128 #define R_S7            0x17
129 #define R_T8            0x18
130 #define R_T9            0x19
131 #define R_K0            0x1a
132 #define R_K1            0x1b
133 #define R_GP            0x1c
134 #define R_SP            0x1d
135 #define R_FP            0x1e
136 #define R_RA            0x1f
138 #define R_F0            0x20
139 #define R_F1            0x21
140 #define R_F2            0x22
141 #define R_F3            0x23
142 #define R_F4            0x24
143 #define R_F5            0x25
144 #define R_F6            0x26
145 #define R_F7            0x27
146 #define R_F8            0x28
147 #define R_F9            0x29
148 #define R_F10           0x2a
149 #define R_F11           0x2b
150 #define R_F12           0x2c
151 #define R_F13           0x2d
152 #define R_F14           0x2e
153 #define R_F15           0x2f
154 #define R_F16           0x30
155 #define R_F17           0x31
156 #define R_F18           0x32
157 #define R_F19           0x33
158 #define R_F20           0x34
159 #define R_F21           0x35
160 #define R_F22           0x36
161 #define R_F23           0x37
162 #define R_F24           0x38
163 #define R_F25           0x39
164 #define R_F26           0x3a
165 #define R_F27           0x3b
166 #define R_F28           0x3c
167 #define R_F29           0x3d
168 #define R_F30           0x3e
169 #define R_F31           0x3f
171 #define R_FRAME         R_S0
172 #define R_UPCALL        R_S1
174 #define R_SCRATCH_1     R_A0
175 #define R_SCRATCH_2     R_A1
176 #define R_SCRATCH_3     R_A2
177 #define R_SCRATCH_4     R_SAVED_2
178 #define R_SCRATCH_NA_1  R_T0
179 #define R_SCRATCH_NA_2  R_T1
180 #define R_SCRATCH_NA_3  R_T2
182 #define R_SAVED_1       R_S2
183 #define R_SAVED_2       R_S3
185 #define R_ARG0          R_A0
186 #define R_ARG1          R_A1
187 #define R_ARG2          R_A2
188 #define R_ARG3          R_A3
190 #define R_RET0          R_V0
191 #define R_RET1          R_V1
193 #define R_OFFSET_IMM    R_T3
194 #define R_CONST_IMM     R_T4
195 #define R_CMP_RESULT    R_T5
197 #define FR_SCRATCH_1    R_F0
198 #define FR_SCRATCH_2    R_F2
199 #define FR_SCRATCH_3    R_F4
200 #define FR_CMP_RESULT   R_F6
202 #define SUPPORTED_FP    0x6
204 #ifdef ARCH_MIPS_O32
205 #define FRAME_SIZE      64
206 #define SAVE_OFFSET     20
207 #else
208 #define FRAME_SIZE      96
209 #define SAVE_OFFSET     0
210 #endif
212 static bool reg_is_fp(unsigned reg)
214         return reg >= 0x20 && reg < 0x40;
217 static const uint8_t regs_saved[] = { R_S4, R_S5, R_S6, R_S7,
218 #ifndef ARCH_MIPS_O32
219         R_GP,
220 #endif
221         R_FP };
222 static const uint8_t regs_volatile[] = { R_A3, R_T6, R_T7, R_T8, R_T9, R_RA };
223 static const uint8_t fp_saved[] = { 0 };
224 #define n_fp_saved 0U
225 static const uint8_t fp_volatile[] = { R_F8, R_F10, R_F12, R_F14, R_F16, R_F18 };
226 #define reg_is_saved(r) (((r) >= R_S0 && (r) <= R_S7) || (r) == R_GP || (r) == R_FP)
228 static bool attr_w gen_load_constant(struct codegen_context *ctx, unsigned reg, uint64_t c)
230         if (OP_SIZE_NATIVE == OP_SIZE_4)
231                 c = (int32_t)c;
232         if ((int64_t)c != (int32_t)c) {
233                 if (MIPS_R6) {
234                         g(gen_load_constant(ctx, reg, (int32_t)c));
235                         if ((int32_t)c < 0) {
236                                 c += 0x100000000ULL;
237                         }
238                         c &= ~0xFFFFFFFFULL;
239                         c >>= 32;
240                         if (c & 0xFFFFULL) {
241                                 gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_ADD, 0);
242                                 gen_one(reg);
243                                 gen_one(reg);
244                                 gen_one(ARG_IMM);
245                                 gen_eight((uint64_t)(int16_t)c << 32);
246                         }
247                         if ((int16_t)c < 0) {
248                                 c += 0x10000ULL;
249                         }
250                         c &= ~0xFFFFULL;
251                         c >>= 16;
252                         if (c & 0xFFFFULL) {
253                                 gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_ADD, 0);
254                                 gen_one(reg);
255                                 gen_one(reg);
256                                 gen_one(ARG_IMM);
257                                 gen_eight(c << 48);
258                         }
259                         return true;
260                 }
261                 if (c && !(c & (c - 1))) {
262                         int bit = -1;
263                         uint64_t cc = c;
264                         do {
265                                 cc >>= 1;
266                                 bit++;
267                         } while (cc);
268                         gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_OR, 0);
269                         gen_one(reg);
270                         gen_one(R_ZERO);
271                         gen_one(ARG_IMM);
272                         gen_eight(1);
274                         gen_insn(INSN_ROT, OP_SIZE_NATIVE, ROT_SHL, 0);
275                         gen_one(reg);
276                         gen_one(reg);
277                         gen_one(ARG_IMM);
278                         gen_eight(bit);
280                         return true;
281                 }
282                 if (~c && !(~c & (~c - 1))) {
283                         g(gen_load_constant(ctx, reg, ~c));
285                         gen_insn(INSN_ALU1, OP_SIZE_NATIVE, ALU1_NOT, 0);
286                         gen_one(reg);
287                         gen_one(reg);
289                         return true;
290                 }
291                 g(gen_load_constant(ctx, reg, (int32_t)((c & 0xFFFFFFFF00000000ULL) >> 32)));
292                 c &= 0xFFFFFFFFULL;
293                 if (c & 0xFFFF0000ULL) {
294                         gen_insn(INSN_ROT, OP_SIZE_NATIVE, ROT_SHL, 0);
295                         gen_one(reg);
296                         gen_one(reg);
297                         gen_one(ARG_IMM);
298                         gen_eight(16);
300                         gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_OR, 0);
301                         gen_one(reg);
302                         gen_one(reg);
303                         gen_one(ARG_IMM);
304                         gen_eight(c >> 16);
306                         gen_insn(INSN_ROT, OP_SIZE_NATIVE, ROT_SHL, 0);
307                         gen_one(reg);
308                         gen_one(reg);
309                         gen_one(ARG_IMM);
310                         gen_eight(16);
311                 } else {
312                         gen_insn(INSN_ROT, OP_SIZE_NATIVE, ROT_SHL, 0);
313                         gen_one(reg);
314                         gen_one(reg);
315                         gen_one(ARG_IMM);
316                         gen_eight(32);
317                 }
318                 if (c & 0xFFFFULL) {
319                         gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_OR, 0);
320                         gen_one(reg);
321                         gen_one(reg);
322                         gen_one(ARG_IMM);
323                         gen_eight(c & 0xFFFFULL);
324                 }
325                 return true;
326         }
327         if (c == (uint16_t)c) {
328                 gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_OR, 0);
329                 gen_one(reg);
330                 gen_one(R_ZERO);
331                 gen_one(ARG_IMM);
332                 gen_eight(c);
333                 return true;
334         }
335         if ((int64_t)c == (int16_t)c) {
336                 gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_ADD, 0);
337                 gen_one(reg);
338                 gen_one(R_ZERO);
339                 gen_one(ARG_IMM);
340                 gen_eight(c);
341                 return true;
342         }
343         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
344         gen_one(reg);
345         gen_one(ARG_IMM);
346         gen_eight(c & ~0xffffULL);
347         if (c & 0xFFFFULL) {
348                 gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_OR, 0);
349                 gen_one(reg);
350                 gen_one(reg);
351                 gen_one(ARG_IMM);
352                 gen_eight(c & 0xFFFFULL);
353         }
354         return true;
357 static bool attr_w gen_address(struct codegen_context *ctx, unsigned base, int64_t imm, unsigned purpose, unsigned size)
359         ctx->base_reg = base;
360         ctx->offset_imm = imm;
361         ctx->offset_reg = false;
362         switch (purpose) {
363                 case IMM_PURPOSE_LDR_OFFSET:
364                 case IMM_PURPOSE_LDR_SX_OFFSET:
365                 case IMM_PURPOSE_STR_OFFSET:
366                 case IMM_PURPOSE_VLDR_VSTR_OFFSET:
367                 case IMM_PURPOSE_MVI_CLI_OFFSET:
368                         if (likely(imm == (int16_t)imm))
369                                 return true;
370                         break;
371                 default:
372                         internal(file_line, "gen_address: invalid purpose %u (imm %"PRIxMAX", size %u)", purpose, (uintmax_t)imm, size);
373         }
374         g(gen_load_constant(ctx, R_OFFSET_IMM, imm));
375         gen_insn(INSN_ALU, OP_SIZE_ADDRESS, ALU_ADD, 0);
376         gen_one(R_OFFSET_IMM);
377         gen_one(R_OFFSET_IMM);
378         gen_one(base);
379         ctx->base_reg = R_OFFSET_IMM;
380         ctx->offset_imm = 0;
381         return true;
384 static bool is_direct_const(int64_t imm, unsigned purpose, unsigned size)
386         if (MIPS_R4000_ERRATA && (purpose == IMM_PURPOSE_ADD || purpose == IMM_PURPOSE_SUB) && size == OP_SIZE_8)
387                 return false;
388         switch (purpose) {
389                 case IMM_PURPOSE_STORE_VALUE:
390                         if (!imm)
391                                 return true;
392                         break;
393                 case IMM_PURPOSE_ADD:
394                 case IMM_PURPOSE_CMP:
395                 case IMM_PURPOSE_CMP_LOGICAL:
396                         if (likely(imm == (int16_t)imm))
397                                 return true;
398                         break;
399                 case IMM_PURPOSE_SUB:
400                         if (likely(imm > -0x8000) && likely(imm <= 0x8000))
401                                 return true;
402                         break;
403                 case IMM_PURPOSE_AND:
404                 case IMM_PURPOSE_OR:
405                 case IMM_PURPOSE_XOR:
406                 case IMM_PURPOSE_TEST:
407                         if (likely((uint64_t)imm == (uint16_t)imm))
408                                 return true;
409                         break;
410                 case IMM_PURPOSE_MUL:
411                         break;
412                 default:
413                         internal(file_line, "is_direct_const: invalid purpose %u (imm %"PRIxMAX", size %u)", purpose, (uintmax_t)imm, size);
414         }
415         return false;
418 static bool attr_w gen_imm(struct codegen_context *ctx, int64_t imm, unsigned purpose, unsigned size)
420         if (is_direct_const(imm, purpose, size)) {
421                 ctx->const_imm = imm;
422                 ctx->const_reg = false;
423         } else {
424                 g(gen_load_constant(ctx, R_CONST_IMM, imm));
425                 ctx->const_reg = true;
426         }
427         return true;
430 static bool attr_w gen_entry(struct codegen_context *ctx)
432         int save_offset;
433         unsigned reg;
435         gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_SUB, 0);
436         gen_one(R_SP);
437         gen_one(R_SP);
438         gen_one(ARG_IMM);
439         gen_eight(FRAME_SIZE);
441         save_offset = SAVE_OFFSET;
443         g(gen_address(ctx, R_SP, save_offset, IMM_PURPOSE_STR_OFFSET, OP_SIZE_NATIVE));
444         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
445         gen_address_offset();
446         gen_one(R_ARG2);
447         save_offset += 1 << OP_SIZE_NATIVE;
449         for (reg = R_S0; reg <= R_S7; reg++) {
450                 g(gen_address(ctx, R_SP, save_offset, IMM_PURPOSE_STR_OFFSET, OP_SIZE_NATIVE));
451                 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
452                 gen_address_offset();
453                 gen_one(reg);
454                 save_offset += 1 << OP_SIZE_NATIVE;
455         }
456 #ifndef ARCH_MIPS_O32
457         g(gen_address(ctx, R_SP, save_offset, IMM_PURPOSE_STR_OFFSET, OP_SIZE_NATIVE));
458         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
459         gen_address_offset();
460         gen_one(R_GP);
461         save_offset += 1 << OP_SIZE_NATIVE;
462 #endif
463         g(gen_address(ctx, R_SP, save_offset, IMM_PURPOSE_STR_OFFSET, OP_SIZE_NATIVE));
464         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
465         gen_address_offset();
466         gen_one(R_FP);
467         save_offset += 1 << OP_SIZE_NATIVE;
469         g(gen_address(ctx, R_SP, save_offset, IMM_PURPOSE_STR_OFFSET, OP_SIZE_NATIVE));
470         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
471         gen_address_offset();
472         gen_one(R_RA);
474         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
475         gen_one(R_FRAME);
476         gen_one(R_ARG0);
478         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
479         gen_one(R_UPCALL);
480         gen_one(R_ARG1);
482         gen_insn(INSN_JMP_INDIRECT, 0, 0, 0);
483         gen_one(R_ARG3);
485         return true;
488 static bool attr_w gen_escape_arg(struct codegen_context *ctx, ip_t ip, uint32_t escape_label)
490         g(gen_load_constant(ctx, R_RET1, (int32_t)ip));
492         gen_insn(INSN_JMP, 0, 0, 0);
493         gen_four(escape_label);
495         return true;
498 static bool attr_w gen_escape(struct codegen_context *ctx)
500         int save_offset;
501         unsigned reg;
503 #if defined(ARCH_MIPS_N32)
504         gen_insn(INSN_ROT, OP_SIZE_NATIVE, ROT_SHL, 0);
505         gen_one(R_RET1);
506         gen_one(R_RET1);
507         gen_one(ARG_IMM);
508         gen_eight(32);
510         gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_OR, 0);
511         gen_one(R_RET0);
512         gen_one(R_FRAME);
513         gen_one(R_RET1);
514 #else
515         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
516         gen_one(R_RET0);
517         gen_one(R_FRAME);
518 #endif
520         save_offset = SAVE_OFFSET + (1 << OP_SIZE_NATIVE);
521         for (reg = R_S0; reg <= R_S7; reg++) {
522                 g(gen_address(ctx, R_SP, save_offset, IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
523                 gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
524                 gen_one(reg);
525                 gen_address_offset();
526                 save_offset += 1 << OP_SIZE_NATIVE;
527         }
528 #ifndef ARCH_MIPS_O32
529         g(gen_address(ctx, R_SP, save_offset, IMM_PURPOSE_STR_OFFSET, OP_SIZE_NATIVE));
530         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
531         gen_one(R_GP);
532         gen_address_offset();
533         save_offset += 1 << OP_SIZE_NATIVE;
534 #endif
535         g(gen_address(ctx, R_SP, save_offset, IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
536         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
537         gen_one(R_FP);
538         gen_address_offset();
539         save_offset += 1 << OP_SIZE_NATIVE;
541         g(gen_address(ctx, R_SP, save_offset, IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
542         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
543         gen_one(R_RA);
544         gen_address_offset();
546         gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_ADD, 0);
547         gen_one(R_SP);
548         gen_one(R_SP);
549         gen_one(ARG_IMM);
550         gen_eight(FRAME_SIZE);
552         gen_insn(INSN_RET, 0, 0, 0);
554         return true;
557 static bool attr_w gen_upcall_argument(struct codegen_context attr_unused *ctx, unsigned attr_unused arg)
559         return true;
562 static bool attr_w gen_upcall(struct codegen_context *ctx, unsigned offset, unsigned n_args)
564         g(gen_address(ctx, R_UPCALL, offset, IMM_PURPOSE_LDR_OFFSET, OP_SIZE_ADDRESS));
565         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
566         gen_one(R_T9);
567         gen_address_offset();
569         gen_insn(INSN_CALL_INDIRECT, OP_SIZE_ADDRESS, 0, 0);
570         gen_one(R_T9);
572         g(gen_upcall_end(ctx, n_args));
574         return true;
577 static bool attr_w gen_cmp_test_jmp(struct codegen_context *ctx, unsigned insn, unsigned op_size, unsigned reg1, unsigned reg2, unsigned cond, uint32_t label);
579 static bool attr_w gen_timestamp_test(struct codegen_context *ctx, uint32_t escape_label)
581         g(gen_address(ctx, R_UPCALL, offsetof(struct cg_upcall_vector_s, ts), IMM_PURPOSE_LDR_OFFSET, OP_SIZE_4));
582         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
583         gen_one(R_SCRATCH_1);
584         gen_address_offset();
586         g(gen_address(ctx, R_SP, SAVE_OFFSET, IMM_PURPOSE_STR_OFFSET, OP_SIZE_NATIVE));
587         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
588         gen_one(R_SCRATCH_2);
589         gen_address_offset();
591         g(gen_cmp_test_jmp(ctx, INSN_CMP, OP_SIZE_NATIVE, R_SCRATCH_1, R_SCRATCH_2, COND_NE, escape_label));
593         return true;