Ajla 0.1.0
[ajla.git] / c1-ia64.inc
blob94e15ac192fe8ff43aa0db028bde272da0b1be53
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 OP_SIZE_NATIVE                  OP_SIZE_8
20 #define OP_SIZE_ADDRESS                 OP_SIZE_NATIVE
22 #define JMP_LIMIT                       (cpu_test_feature(CPU_FEATURE_brl) ? JMP_SHORT : JMP_SHORTEST)
24 #define UNALIGNED_TRAP                  1
26 #define ALU_WRITES_FLAGS(alu, im)       0
27 #define ALU1_WRITES_FLAGS(alu)          0
28 #define ROT_WRITES_FLAGS(alu)           0
29 #define COND_IS_LOGICAL(cond)           0
31 #define ARCH_PARTIAL_ALU(size)          0
32 #define ARCH_IS_3ADDRESS                1
33 #define ARCH_HAS_FLAGS                  0
34 #define ARCH_PREFERS_SX(size)           0
35 #define ARCH_HAS_BWX                    1
36 #define ARCH_HAS_MUL                    0
37 #define ARCH_HAS_DIV                    0
38 #define ARCH_HAS_ANDN                   1
39 #define ARCH_HAS_SHIFTED_ADD(bits)      ((bits) <= 4)
40 #define ARCH_HAS_BTX(btx, size, cnst)   (((btx) == BTX_BTS || (btx) == BTX_BTR) && (cnst))
41 #define ARCH_SHIFT_SIZE                 32
42 #define ARCH_NEEDS_BARRIER              0
44 #define i_size(size)                    OP_SIZE_NATIVE
45 #define i_size_rot(size)                OP_SIZE_NATIVE
47 #define R_ZERO          0x00
48 #define R_GP            0x01
49 #define R_2             0x02
50 #define R_3             0x03
51 #define R_4             0x04
52 #define R_5             0x05
53 #define R_6             0x06
54 #define R_7             0x07
55 #define R_8             0x08
56 #define R_9             0x09
57 #define R_10            0x0a
58 #define R_11            0x0b
59 #define R_SP            0x0c
60 #define R_TP            0x0d
61 #define R_14            0x0e
62 #define R_15            0x0f
63 #define R_16            0x10
64 #define R_17            0x11
65 #define R_18            0x12
66 #define R_19            0x13
67 #define R_20            0x14
68 #define R_21            0x15
69 #define R_22            0x16
70 #define R_23            0x17
71 #define R_24            0x18
72 #define R_25            0x19
73 #define R_26            0x1a
74 #define R_27            0x1b
75 #define R_28            0x1c
76 #define R_29            0x1d
77 #define R_30            0x1e
78 #define R_31            0x1f
79 #define R_32            0x20
80 #define R_33            0x21
81 #define R_34            0x22
82 #define R_35            0x23
83 #define R_36            0x24
84 #define R_37            0x25
85 #define R_38            0x26
86 #define R_39            0x27
87 #define R_40            0x28
88 #define R_41            0x29
89 #define R_42            0x2a
90 #define R_43            0x2b
91 #define R_44            0x2c
92 #define R_45            0x2d
93 #define R_46            0x2e
94 #define R_47            0x2f
95 #define R_48            0x30
96 #define R_49            0x31
97 #define R_50            0x32
98 #define R_51            0x33
99 #define R_52            0x34
100 #define R_53            0x35
101 #define R_54            0x36
102 #define R_55            0x37
103 #define R_56            0x38
104 #define R_57            0x39
105 #define R_58            0x3a
106 #define R_59            0x3b
107 #define R_60            0x3c
108 #define R_61            0x3d
109 #define R_62            0x3e
110 #define R_63            0x3f
112 #define FR_ZERO         0x80
113 #define FR_ONE          0x81
114 #define FR_2            0x82
115 #define FR_3            0x83
116 #define FR_4            0x84
117 #define FR_5            0x85
118 #define FR_6            0x86
119 #define FR_7            0x87
120 #define FR_8            0x88
121 #define FR_9            0x89
122 #define FR_10           0x8a
123 #define FR_11           0x8b
124 #define FR_12           0x8c
125 #define FR_13           0x8d
126 #define FR_14           0x8e
127 #define FR_15           0x8f
129 #define P_0             0xa0
130 #define P_1             0xa1
131 #define P_2             0xa2
132 #define P_3             0xa3
133 #define P_4             0xa4
134 #define P_5             0xa5
135 #define P_6             0xa6
136 #define P_7             0xa7
138 #define B_0             0xb0
139 #define B_1             0xb1
140 #define B_2             0xb2
141 #define B_3             0xb3
142 #define B_4             0xb4
143 #define B_5             0xb5
144 #define B_6             0xb6
145 #define B_7             0xb7
147 #define R_FRAME         R_32
148 #define R_UPCALL        R_33
149 #define R_TIMESTAMP     R_34
150 #define R_SAVED_B0      R_35
151 #define R_SAVED_AR_PFS  R_36
152 #define R_SAVED_1       R_37
153 #define R_SAVED_2       R_38
154 #define R_ARG0          R_39
155 #define R_ARG1          R_40
156 #define R_ARG2          R_41
157 #define R_ARG3          R_42
159 #define R_RET0          R_8
160 #define R_RET1          R_9
161 #define R_SCRATCH_NA_1  R_14
162 #define R_SCRATCH_NA_2  R_15
163 #define R_SCRATCH_NA_3  R_16
164 #define R_SCRATCH_1     R_17
165 #define R_SCRATCH_2     R_18
166 #define R_SCRATCH_3     R_19
167 #define R_SCRATCH_4     R_20
169 #define R_OFFSET_IMM    R_2
170 #define R_CONST_IMM     R_3
171 #define R_CMP_RESULT    P_6
173 #define R_SCRATCH_B     B_6
175 #define FR_SCRATCH_1    FR_6
176 #define FR_SCRATCH_2    FR_7
178 #define SUPPORTED_FP    0xe
180 static inline bool reg_is_gr(unsigned reg)
182         return reg < 0x40;
185 static inline bool reg_is_fp(unsigned reg)
187         return reg >= 0x80 && reg < 0x90;
190 static inline bool reg_is_p(unsigned reg)
192         return reg >= 0xa0 && reg < 0xa8;
195 static inline bool reg_is_b(unsigned reg)
197         return reg >= 0xb0 && reg < 0xb8;
200 static inline uint64_t bits_gr(unsigned reg)
202         ajla_assert_lo(reg_is_gr(reg), (file_line, "bits_gr: register %x", reg));
203         return reg;
206 static inline uint64_t bits_fp(unsigned reg)
208         ajla_assert_lo(reg_is_fp(reg), (file_line, "bits_fp: register %x", reg));
209         return reg - 0x80;
212 static inline uint64_t bits_p(unsigned reg)
214         ajla_assert_lo(reg_is_p(reg), (file_line, "bits_p: register %x", reg));
215         return reg - 0xa0;
218 static inline uint64_t bits_b(unsigned reg)
220         ajla_assert_lo(reg_is_b(reg), (file_line, "bits_b: register %x", reg));
221         return reg - 0xb0;
224 static char *codegen_stub_alloc(struct codegen_context *ctx, char *code)
226         uintptr_t *stub = mem_alloc_mayfail(uintptr_t *, sizeof(uintptr_t) * 2, &ctx->err);
227         if (unlikely(!stub))
228                 return NULL;
229         stub[0] = ptr_to_num(code);
230         stub[1] = 0;
231         return cast_ptr(char *, stub);
233 #define codegen_stub_alloc              codegen_stub_alloc
234 #define codegen_stub_free(stub)         mem_free(stub)
236 static bool attr_w gen_load_constant(struct codegen_context *ctx, unsigned reg, uint64_t c)
238         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
239         gen_one(reg);
240         gen_one(ARG_IMM);
241         gen_eight(c);
242         return true;
245 /*static bool attr_w gen_upcall(struct codegen_context *ctx, unsigned offset, unsigned attr_unused n_args);*/
246 static bool attr_w gen_imm(struct codegen_context *ctx, int64_t imm, unsigned purpose, unsigned size);
248 static bool attr_w gen_address(struct codegen_context *ctx, unsigned base, int64_t imm, unsigned attr_unused purpose, unsigned attr_unused size)
250         if (!imm) {
251                 ctx->offset_imm = imm;
252                 ctx->offset_reg = false;
253                 ctx->base_reg = base;
254         } else {
255                 g(gen_imm(ctx, imm, IMM_PURPOSE_ADD, OP_SIZE_NATIVE));
256                 gen_insn(INSN_ALU, OP_SIZE_NATIVE, ALU_ADD, 0);
257                 gen_one(R_OFFSET_IMM);
258                 gen_one(base);
259                 gen_imm_offset();
260                 ctx->offset_imm = 0;
261                 ctx->offset_reg = false;
262                 ctx->base_reg = R_OFFSET_IMM;
263         }
264         return true;
267 static bool is_direct_const(int64_t imm, unsigned purpose, unsigned size)
269         switch (purpose) {
270                 case IMM_PURPOSE_STORE_VALUE:
271                         if (!imm)
272                                 return true;
273                         break;
274                 case IMM_PURPOSE_ADD:
275                 case IMM_PURPOSE_MOVR:
276                         if (imm >= -0x2000 && imm < 0x2000)
277                                 return true;
278                         break;
279                 case IMM_PURPOSE_SUB:
280                         if (imm > -0x2000 && imm <= 0x2000)
281                                 return true;
282                         break;
283                 case IMM_PURPOSE_AND:
284                 case IMM_PURPOSE_OR:
285                 case IMM_PURPOSE_XOR:
286                         if (imm >= -0x80 && imm < 0x80)
287                                 return true;
288                         break;
289                 case IMM_PURPOSE_CMP:
290                         if (imm > -0x80 && imm < 0x80)
291                                 return true;
292                         break;
293                 case IMM_PURPOSE_ANDN:
294                         break;
295                 case IMM_PURPOSE_TEST:
296                         break;
297                 case IMM_PURPOSE_BITWISE:
298                         return true;
299                 default:
300                         internal(file_line, "is_direct_const: invalid purpose %u (imm %"PRIxMAX", size %u)", purpose, (uintmax_t)imm, size);
301         }
302         return false;
305 static bool attr_w gen_imm(struct codegen_context *ctx, int64_t imm, unsigned purpose, unsigned size)
307         if (is_direct_const(imm, purpose, size)) {
308                 ctx->const_imm = imm;
309                 ctx->const_reg = false;
310         } else {
311                 g(gen_load_constant(ctx, R_CONST_IMM, imm));
312                 ctx->const_reg = true;
313         }
314         return true;
317 static bool attr_w gen_entry(struct codegen_context *ctx)
319         gen_insn(INSN_IA64_ALLOC, OP_SIZE_NATIVE, 0, 0);
320         gen_one(R_SAVED_AR_PFS);
321         gen_one(ARG_IMM);
322         gen_eight(11);
323         gen_one(ARG_IMM);
324         gen_eight(7);
326         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
327         gen_one(R_SAVED_B0);
328         gen_one(B_0);
330         /*gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
331         gen_one(R_ARG0);
332         gen_one(R_FRAME);
333         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
334         gen_one(R_ARG1);
335         gen_one(R_UPCALL);
336         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
337         gen_one(R_ARG2);
338         gen_one(R_TIMESTAMP);
339         g(gen_load_constant(ctx, R_ARG3, 0x123));
340         g(gen_upcall(ctx, offsetof(struct cg_upcall_vector_s, cg_upcall_debug), 4));*/
342         return true;
345 static bool attr_w gen_escape_arg(struct codegen_context *ctx, ip_t ip, uint32_t escape_label)
347         g(gen_load_constant(ctx, R_RET1, ip));
349         gen_insn(INSN_JMP, 0, 0, 0);
350         gen_four(escape_label);
352         return true;
355 static bool attr_w gen_escape(struct codegen_context *ctx)
357         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
358         gen_one(R_RET0);
359         gen_one(R_FRAME);
361         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
362         gen_one(B_0);
363         gen_one(R_SAVED_B0);
365         gen_insn(INSN_IA64_DEALLOC, OP_SIZE_NATIVE, 0, 0);
366         gen_one(R_SAVED_AR_PFS);
368         gen_insn(INSN_RET, 0, 0, 0);
370         return true;
373 static bool attr_w gen_upcall_argument(struct codegen_context attr_unused *ctx, unsigned attr_unused arg)
375         return true;
378 static bool attr_w gen_upcall(struct codegen_context *ctx, unsigned offset, unsigned attr_unused n_args)
380         g(gen_address(ctx, R_UPCALL, offset, IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
381         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
382         gen_one(R_SCRATCH_NA_1);
383         gen_address_offset();
385         g(gen_address(ctx, R_SCRATCH_NA_1, 0, IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
386         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
387         gen_one(R_SCRATCH_NA_2);
388         gen_address_offset();
390         g(gen_address(ctx, R_SCRATCH_NA_1, 8, IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
391         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
392         gen_one(R_GP);
393         gen_address_offset();
395         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
396         gen_one(R_SCRATCH_B);
397         gen_one(R_SCRATCH_NA_2);
399         gen_insn(INSN_CALL_INDIRECT, OP_SIZE_8, 0, 0);
400         gen_one(R_SCRATCH_B);
402         return true;
405 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);
407 static bool attr_w gen_timestamp_test(struct codegen_context *ctx, uint32_t label_id)
409         g(gen_address(ctx, R_UPCALL, offsetof(struct cg_upcall_vector_s, ts), IMM_PURPOSE_LDR_OFFSET, OP_SIZE_NATIVE));
410         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
411         gen_one(R_SCRATCH_1);
412         gen_address_offset();
414         g(gen_cmp_test_jmp(ctx, INSN_CMP, OP_SIZE_4, R_SCRATCH_1, R_TIMESTAMP, COND_E, label_id));
416         return true;