Ajla 0.1.0
[ajla.git] / c1-x86.inc
blobfc64a963563c50bd3dec22f4855a14873f066b49
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_X86_32
20 #define OP_SIZE_NATIVE                  OP_SIZE_4
21 #else
22 #define OP_SIZE_NATIVE                  OP_SIZE_8
23 #endif
25 #ifndef ARCH_X86_64
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_LONG
33 #define UNALIGNED_TRAP                  0
35 #define ALU_WRITES_FLAGS(alu, im)       ((alu) != ALU_ADD ? 3 : 0)
36 #define ALU1_WRITES_FLAGS(alu)          ((alu) == ALU1_INC || (alu) == ALU1_DEC ? 1 : (alu) == ALU1_NOT || (alu) == ALU1_BSWAP ? 0 : 3)
37 #define ROT_WRITES_FLAGS(alu)           1
38 #define COND_IS_LOGICAL(cond)           0
40 #define ARCH_PARTIAL_ALU(size)          ((size) <= OP_SIZE_2)
41 #define ARCH_IS_3ADDRESS                0
42 #define ARCH_HAS_FLAGS                  1
43 #define ARCH_PREFERS_SX(size)           0
44 #define ARCH_HAS_BWX                    1
45 #define ARCH_HAS_MUL                    1
46 #define ARCH_HAS_DIV                    1
47 #define ARCH_HAS_ANDN                   0
48 #define ARCH_HAS_BTX(btx, size, cnst)   ((btx) != BTX_BTEXT && (size) >= OP_SIZE_2)
49 #define ARCH_HAS_SHIFTED_ADD(bits)      ((bits) <= 3)
50 #define ARCH_SHIFT_SIZE                 OP_SIZE_4
51 #define ARCH_NEEDS_BARRIER              0
53 #define i_size(size)                    (size)
54 #define i_size_rot(size)                (size)
56 #define R_AX            0x0
57 #define R_CX            0x1
58 #define R_DX            0x2
59 #define R_BX            0x3
60 #define R_SP            0x4
61 #define R_BP            0x5
62 #define R_SI            0x6
63 #define R_DI            0x7
64 #define R_R8            0x8
65 #define R_R9            0x9
66 #define R_R10           0xa
67 #define R_R11           0xb
68 #define R_R12           0xc
69 #define R_R13           0xd
70 #define R_R14           0xe
71 #define R_R15           0xf
73 #define R_ST0           0x10
74 #define R_ST1           0x11
75 #define R_ST2           0x12
76 #define R_ST3           0x13
77 #define R_ST4           0x14
78 #define R_ST5           0x15
79 #define R_ST6           0x16
80 #define R_ST7           0x17
82 #define R_XMM0          0x20
83 #define R_XMM1          0x21
84 #define R_XMM2          0x22
85 #define R_XMM3          0x23
86 #define R_XMM4          0x24
87 #define R_XMM5          0x25
88 #define R_XMM6          0x26
89 #define R_XMM7          0x27
90 #define R_XMM8          0x28
91 #define R_XMM9          0x29
92 #define R_XMM10         0x2a
93 #define R_XMM11         0x2b
94 #define R_XMM12         0x2c
95 #define R_XMM13         0x2d
96 #define R_XMM14         0x2e
97 #define R_XMM15         0x2f
98 #define R_XMM16         0x30
99 #define R_XMM17         0x31
100 #define R_XMM18         0x32
101 #define R_XMM19         0x33
102 #define R_XMM20         0x34
103 #define R_XMM21         0x35
104 #define R_XMM22         0x36
105 #define R_XMM23         0x37
106 #define R_XMM24         0x38
107 #define R_XMM25         0x39
108 #define R_XMM26         0x3a
109 #define R_XMM27         0x3b
110 #define R_XMM28         0x3c
111 #define R_XMM29         0x3d
112 #define R_XMM30         0x3e
113 #define R_XMM31         0x3f
115 #define R_IS_GPR(r)     ((r) < 16)
116 #define R_IS_XMM(r)     ((r) >= R_XMM0 && (r) <= R_XMM31)
118 #define R_FRAME         R_BX
119 #ifndef ARCH_X86_32
120 #define R_UPCALL        R_R15
121 #define R_TIMESTAMP     R_R14
122 #define R_OFFSET_IMM    R_R10
123 #define R_CONST_IMM     R_R11
124 #else
125 #define R_OFFSET_IMM    255     /* this should not be used */
126 #define R_CONST_IMM     255
127 #endif
129 #if defined(ARCH_X86_64) && defined(ARCH_X86_WIN_ABI)
130 #define R_SCRATCH_1     R_AX
131 #define R_SCRATCH_2     R_DX
132 #define R_SCRATCH_3     R_CX
133 #define R_SCRATCH_4     R_R8
134 #define R_SAVED_1       R_SI
135 #define R_SAVED_2       R_DI
136 #elif defined(ARCH_X86_32)
137 #define R_SCRATCH_1     R_AX
138 #define R_SCRATCH_2     R_DX
139 #define R_SCRATCH_3     R_CX
140 #define R_SCRATCH_4     R_SI
141 #define R_SAVED_1       R_BP
142 #define R_SAVED_2       R_DI
143 #else
144 #define R_SCRATCH_1     R_AX
145 #define R_SCRATCH_2     R_DX
146 #define R_SCRATCH_3     R_CX
147 #define R_SCRATCH_4     R_SI
148 #define R_SAVED_1       R_BP
149 #define R_SAVED_2       R_R12
150 #endif
152 #define FR_SCRATCH_1    R_XMM0
153 #define FR_SCRATCH_2    R_XMM1
155 #if defined(ARCH_X86_32)
156 #define R_ARG0          R_AX
157 #define R_ARG1          R_AX
158 #define R_ARG2          R_AX
159 #define R_ARG3          R_AX
160 #elif defined(ARCH_X86_WIN_ABI)
161 #define R_ARG0          R_CX
162 #define R_ARG1          R_DX
163 #define R_ARG2          R_R8
164 #define R_ARG3          R_R9
165 #else
166 #define R_ARG0          R_DI
167 #define R_ARG1          R_SI
168 #define R_ARG2          R_DX
169 #define R_ARG3          R_CX
170 #endif
171 #define R_RET0          R_AX
173 #if defined(ARCH_X86_32)
174 #define ARG_SPACE       0x1c            /* must be 0xc modulo 0x10 */
175 #define ARG_OFFSET      0x14
176 #elif defined(ARCH_X86_WIN_ABI)
177 #define ARG_SPACE       0x28
178 #endif
180 #define SUPPORTED_FP            (cpu_test_feature(CPU_FEATURE_sse) * 0x2 + cpu_test_feature(CPU_FEATURE_sse2) * 0x4)
181 #define SUPPORTED_FP_X87        0xe
182 #define SUPPORTED_FP_HALF_CVT   (cpu_test_feature(CPU_FEATURE_f16c) * 0x1)
184 static bool reg_is_fp(unsigned reg)
186         return reg >= 0x20 && reg < 0x40;
189 static bool attr_w imm_is_8bit(int64_t imm)
191         return imm >= -0x80 && imm < 0x80;
194 static bool attr_w imm_is_32bit(int64_t attr_unused imm)
196 #ifdef ARCH_X86_32
197         return true;
198 #else
199         return imm >= -0x80000000LL && imm < 0x80000000LL;
200 #endif
203 static bool attr_w gen_load_constant(struct codegen_context *ctx, unsigned reg, uint64_t c)
205         if (OP_SIZE_NATIVE == OP_SIZE_4)
206                 c = (int32_t)c;
207         gen_insn(INSN_MOV, OP_SIZE_NATIVE, 0, 0);
208         gen_one(reg);
209         gen_one(ARG_IMM);
210         gen_eight(c);
211         return true;
214 static bool attr_w gen_address(struct codegen_context *ctx, unsigned base, int64_t imm, unsigned purpose, unsigned attr_unused size)
216         ctx->offset_imm = imm;
217         ctx->offset_reg = false;
218         ctx->base_reg = base;
219         switch (purpose) {
220                 case IMM_PURPOSE_LDR_OFFSET:
221                 case IMM_PURPOSE_LDR_SX_OFFSET:
222                 case IMM_PURPOSE_STR_OFFSET:
223                 case IMM_PURPOSE_VLDR_VSTR_OFFSET:
224                 case IMM_PURPOSE_MVI_CLI_OFFSET:
225                         break;
226                 default:
227                         internal(file_line, "gen_address: invalid purpose %d", purpose);
228         }
229 #ifndef ARCH_X86_32
230         if (likely(imm_is_32bit(imm)))
231                 return true;
232         gen_insn(INSN_MOV, OP_SIZE_8, 0, 0);
233         gen_one(R_OFFSET_IMM);
234         gen_one(ARG_IMM);
235         gen_eight(imm);
236         ctx->offset_reg = true;
237 #endif
238         return true;
241 static bool is_direct_const(int64_t attr_unused imm, unsigned attr_unused purpose, unsigned attr_unused size)
243 #ifdef ARCH_X86_32
244         return true;
245 #else
246         return imm_is_32bit(imm);
247 #endif
250 static bool attr_w gen_imm(struct codegen_context *ctx, int64_t imm, unsigned purpose, unsigned size)
252 #if 0
253         if (size == OP_SIZE_1 && (unlikely(imm < -0x80LL) || unlikely(imm >= 0x80LL)))
254                 internal(file_line, "invalid imm for size 1: %016llx", (long long)imm);
255         if (size == OP_SIZE_2 && (unlikely(imm < -0x8000LL) || unlikely(imm >= 0x8000LL)))
256                 internal(file_line, "invalid imm for size 2 : %016llx", (long long)imm);
257         if (size == OP_SIZE_4 && (unlikely(imm < -0x80000000LL) || unlikely(imm >= 0x80000000LL)))
258                 internal(file_line, "invalid imm for size 3: %016llx", (long long)imm);
259 #endif
260         if (is_direct_const(imm, purpose, size)) {
261                 ctx->const_imm = imm;
262                 ctx->const_reg = false;
263         } else {
264                 gen_insn(INSN_MOV, OP_SIZE_8, 0, 0);
265                 gen_one(R_CONST_IMM);
266                 gen_one(ARG_IMM);
267                 gen_eight(imm);
268                 ctx->const_reg = true;
269         }
270         return true;
273 static bool attr_w gen_entry(struct codegen_context *ctx)
275 #if defined(ARCH_X86_32)
276         gen_insn(INSN_PUSH, OP_SIZE_4, 0, 0);
277         gen_one(R_BX);
279         gen_insn(INSN_PUSH, OP_SIZE_4, 0, 0);
280         gen_one(R_BP);
282         gen_insn(INSN_PUSH, OP_SIZE_4, 0, 0);
283         gen_one(R_SI);
285         gen_insn(INSN_PUSH, OP_SIZE_4, 0, 0);
286         gen_one(R_DI);
288         gen_insn(INSN_ALU, OP_SIZE_4, ALU_SUB, 1);
289         gen_one(R_SP);
290         gen_one(R_SP);
291         gen_one(ARG_IMM);
292         gen_eight(ARG_SPACE);
294         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
295         gen_one(R_FRAME);
296         gen_one(ARG_ADDRESS_1);
297         gen_one(R_SP);
298         gen_eight(ARG_SPACE + ARG_OFFSET);
299 #else
300         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
301         gen_one(R_FRAME);
303         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
304         gen_one(R_SAVED_1);
306         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
307         gen_one(R_SAVED_2);
309         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
310         gen_one(R_TIMESTAMP);
312         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
313         gen_one(R_UPCALL);
314 #if defined(ARCH_X86_WIN_ABI)
315         gen_insn(INSN_PUSH, OP_SIZE_8, 0, 0);
316         gen_one(R_ARG0);
318         gen_insn(INSN_ALU, OP_SIZE_8, ALU_SUB, 1);
319         gen_one(R_SP);
320         gen_one(R_SP);
321         gen_one(ARG_IMM);
322         gen_eight(ARG_SPACE);
324         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
325         gen_one(R_FRAME);
326         gen_one(R_ARG1);
328         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
329         gen_one(R_TIMESTAMP);
330         gen_one(R_ARG3);
332         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
333         gen_one(R_UPCALL);
334         gen_one(R_ARG2);
335 #else
336         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
337         gen_one(R_FRAME);
338         gen_one(R_ARG0);
340         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
341         gen_one(R_UPCALL);
342         gen_one(R_ARG1);
344         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
345         gen_one(R_TIMESTAMP);
346         gen_one(R_ARG2);
347 #endif
348 #endif
349         return true;
352 static bool attr_w gen_escape_arg(struct codegen_context *ctx, ip_t ip, uint32_t escape_label)
354 #if defined(ARCH_X86_32) || defined(ARCH_X86_64)
355         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
356         gen_one(R_DX);
357         gen_one(ARG_IMM);
358         gen_eight(ip);
359 #else
360         gen_insn(INSN_MOV, OP_SIZE_8, 0, 0);
361         gen_one(R_AX);
362         gen_one(ARG_IMM);
363         gen_eight((uint64_t)ip << 32);
364 #endif
365         gen_insn(INSN_JMP, 0, 0, 0);
366         gen_four(escape_label);
368         return true;
371 static bool attr_w gen_escape(struct codegen_context *ctx)
373 #if defined(ARCH_X86_32)
374         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
375         gen_one(R_AX);
376         gen_one(R_FRAME);
378         gen_insn(INSN_ALU, OP_SIZE_4, ALU_ADD, 1);
379         gen_one(R_SP);
380         gen_one(R_SP);
381         gen_one(ARG_IMM);
382         gen_eight(ARG_SPACE);
384         gen_insn(INSN_POP, OP_SIZE_4, 0, 0);
385         gen_one(R_DI);
387         gen_insn(INSN_POP, OP_SIZE_4, 0, 0);
388         gen_one(R_SI);
390         gen_insn(INSN_POP, OP_SIZE_4, 0, 0);
391         gen_one(R_BP);
393         gen_insn(INSN_POP, OP_SIZE_4, 0, 0);
394         gen_one(R_BX);
396         gen_insn(INSN_RET, 0, 0, 0);
397 #elif defined(ARCH_X86_WIN_ABI)
398         gen_insn(INSN_ALU, OP_SIZE_8, ALU_ADD, 1);
399         gen_one(R_SP);
400         gen_one(R_SP);
401         gen_one(ARG_IMM);
402         gen_eight(ARG_SPACE);
404         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
405         gen_one(R_AX);
407         gen_insn(INSN_MOV, OP_SIZE_8, 0, 0);
408         gen_one(ARG_ADDRESS_1);
409         gen_one(R_AX);
410         gen_eight(0);
411         gen_one(R_FRAME);
413         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
414         gen_one(ARG_ADDRESS_1);
415         gen_one(R_AX);
416         gen_eight(8);
417         gen_one(R_DX);
419         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
420         gen_one(R_UPCALL);
422         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
423         gen_one(R_TIMESTAMP);
425         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
426         gen_one(R_SAVED_2);
428         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
429         gen_one(R_SAVED_1);
431         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
432         gen_one(R_FRAME);
434         gen_insn(INSN_RET, 0, 0, 0);
435 #else
436 #if defined(ARCH_X86_X32)
437         gen_insn(INSN_ALU, OP_SIZE_8, ALU_ADD, 1);
438         gen_one(R_AX);
439         gen_one(R_AX);
440         gen_one(R_FRAME);
441 #else
442         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
443         gen_one(R_AX);
444         gen_one(R_FRAME);
445 #endif
446         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
447         gen_one(R_UPCALL);
449         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
450         gen_one(R_TIMESTAMP);
452         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
453         gen_one(R_SAVED_2);
455         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
456         gen_one(R_SAVED_1);
458         gen_insn(INSN_POP, OP_SIZE_8, 0, 0);
459         gen_one(R_FRAME);
461         gen_insn(INSN_RET, 0, 0, 0);
462 #endif
463         return true;
466 static bool attr_w gen_upcall_argument(struct codegen_context attr_unused *ctx, unsigned attr_unused arg)
468 #if defined(ARCH_X86_32)
469         ajla_assert_lo(arg * 4 < ARG_SPACE, (file_line, "gen_upcall_argument: argument %u", arg));
470         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
471         gen_one(ARG_ADDRESS_1);
472         gen_one(R_SP);
473         gen_eight(arg * 4);
474         gen_one(R_ARG0);
475 #endif
476         return true;
479 static bool attr_w gen_upcall(struct codegen_context *ctx, unsigned offset, unsigned attr_unused n_args)
481 #if defined(ARCH_X86_32)
482         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
483         gen_one(R_AX);
484         gen_one(ARG_ADDRESS_1);
485         gen_one(R_SP);
486         gen_eight(ARG_SPACE + ARG_OFFSET + 4);
488         gen_insn(INSN_CALL_INDIRECT, OP_SIZE_4, 0, 0);
489         gen_one(ARG_ADDRESS_1);
490         gen_one(R_AX);
491         gen_eight(offset);
492 #elif defined(ARCH_X86_X32)
493         gen_insn(INSN_MOV, OP_SIZE_ADDRESS, 0, 0);
494         gen_one(R_AX);
495         gen_one(ARG_ADDRESS_1);
496         gen_one(R_UPCALL);
497         gen_eight(offset);
499         gen_insn(INSN_CALL_INDIRECT, OP_SIZE_8, 0, 0);
500         gen_one(R_AX);
501 #else
502         gen_insn(INSN_CALL_INDIRECT, OP_SIZE_8, 0, 0);
503         gen_one(ARG_ADDRESS_1);
504         gen_one(R_UPCALL);
505         gen_eight(offset);
506 #endif
507         return true;
510 static bool attr_w gen_timestamp_test(struct codegen_context *ctx, uint32_t label_id)
512 #if defined(ARCH_X86_32)
513         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
514         gen_one(R_AX);
515         gen_one(ARG_ADDRESS_1);
516         gen_one(R_SP);
517         gen_eight(ARG_SPACE + ARG_OFFSET + 4);
519         gen_insn(INSN_MOV, OP_SIZE_4, 0, 0);
520         gen_one(R_DX);
521         gen_one(ARG_ADDRESS_1);
522         gen_one(R_SP);
523         gen_eight(ARG_SPACE + ARG_OFFSET + 8);
525         gen_insn(INSN_CMP, OP_SIZE_4, 0, 1);
526         gen_one(R_DX);
527         gen_one(ARG_ADDRESS_1);
528         gen_one(R_AX);
529         gen_eight(offsetof(struct cg_upcall_vector_s, ts));
530 #else
531         gen_insn(INSN_CMP, OP_SIZE_4, 0, 1);
532         gen_one(R_TIMESTAMP);
533         gen_one(ARG_ADDRESS_1);
534         gen_one(R_UPCALL);
535         gen_eight(offsetof(struct cg_upcall_vector_s, ts));
536 #endif
537         gen_insn(INSN_JMP_COND, OP_SIZE_4, COND_E, 0);
538         gen_four(label_id);
540         return true;