History

Add arm64 (AArch64) as a target architecture.

Edmund Grimley Evans committed 11 years ago

Commit b14ef0e1 parent 738606d16 files · +3265 −40Browse files

Unified · Split

16 files
  1. Makefile +15 −5
  2. arm64-gen.c +1621 −0
  3. configure +6 −0
  4. conftest.c +2 −0
  5. elf.h +112 −0
  6. include/stdarg.h +13 −0
  7. lib/Makefile +12 −0
  8. lib/lib-arm64.c +652 −0
  9. lib/testfp.c +510 −0
  10. libtcc.c +6 −1
  11. tcc.c +2 −0
  12. tcc.h +25 −5
  13. tccelf.c +133 −4
  14. tccgen.c +102 −25
  15. tccrun.c +21 −0
  16. tcctok.h +33 −0
Makefile+15−5
@@ -70,6 +70,7 @@ NATIVE_DEFINES_$(CONFIG_arm) += -DTCC_TARGET_ARM · 69 unmodified lines
7070 NATIVE_DEFINES_$(CONFIG_arm_eabihf) += -DTCC_ARM_EABI -DTCC_ARM_HARDFLOAT
7171 NATIVE_DEFINES_$(CONFIG_arm_eabi) += -DTCC_ARM_EABI
7272 NATIVE_DEFINES_$(CONFIG_arm_vfp) += -DTCC_ARM_VFP
73+NATIVE_DEFINES_$(CONFIG_arm64) += -DTCC_TARGET_ARM64
7374 NATIVE_DEFINES += $(NATIVE_DEFINES_yes)
7475
7576 ifeq ($(TOP),.)
@@ -86,6 +87,7 @@ ARM_VFP_CROSS = arm-linux-gnu-tcc$(EXESUF) · 10 unmodified lines
8687 ARM_EABI_CROSS = arm-linux-gnueabi-tcc$(EXESUF)
8788 ARM_EABIHF_CROSS = arm-linux-gnueabihf-tcc$(EXESUF)
8889 ARM_CROSS = $(ARM_FPA_CROSS) $(ARM_FPA_LD_CROSS) $(ARM_VFP_CROSS) $(ARM_EABI_CROSS)
90+ARM64_CROSS = arm64-tcc$(EXESUF)
8991 C67_CROSS = c67-tcc$(EXESUF)
9092
9193 # Legacy symlinks for cross compilers
@@ -107,33 +109,39 @@ WIN64_FILES = $(CORE_FILES) x86_64-gen.c i386-asm.c x86_64-asm.h tccpe.c · 15 unmodified lines
107109 WINCE_FILES = $(CORE_FILES) arm-gen.c tccpe.c
108110 X86_64_FILES = $(CORE_FILES) x86_64-gen.c i386-asm.c x86_64-asm.h
109111 ARM_FILES = $(CORE_FILES) arm-gen.c
112+ARM64_FILES = $(CORE_FILES) arm64-gen.c
110113 C67_FILES = $(CORE_FILES) c67-gen.c tcccoff.c
111114
112115 ifdef CONFIG_WIN64
113116 PROGS+=tiny_impdef$(EXESUF) tiny_libmaker$(EXESUF)
114117 NATIVE_FILES=$(WIN64_FILES)
115−PROGS_CROSS=$(WIN32_CROSS) $(I386_CROSS) $(X64_CROSS) $(ARM_CROSS) $(C67_CROSS) $(WINCE_CROSS)
118+PROGS_CROSS=$(WIN32_CROSS) $(I386_CROSS) $(X64_CROSS) $(ARM_CROSS) $(ARM64_CROSS) $(C67_CROSS) $(WINCE_CROSS)
116119 LIBTCC1_CROSS=lib/i386-win32/libtcc1.a
117120 LIBTCC1=libtcc1.a
118121 else ifdef CONFIG_WIN32
119122 PROGS+=tiny_impdef$(EXESUF) tiny_libmaker$(EXESUF)
120123 NATIVE_FILES=$(WIN32_FILES)
121−PROGS_CROSS=$(WIN64_CROSS) $(I386_CROSS) $(X64_CROSS) $(ARM_CROSS) $(C67_CROSS) $(WINCE_CROSS)
124+PROGS_CROSS=$(WIN64_CROSS) $(I386_CROSS) $(X64_CROSS) $(ARM_CROSS) $(ARM64_CROSS) $(C67_CROSS) $(WINCE_CROSS)
122125 LIBTCC1_CROSS=lib/x86_64-win32/libtcc1.a
123126 LIBTCC1=libtcc1.a
124127 else ifeq ($(ARCH),i386)
125128 NATIVE_FILES=$(I386_FILES)
126−PROGS_CROSS=$(X64_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(ARM_CROSS) $(C67_CROSS) $(WINCE_CROSS)
129+PROGS_CROSS=$(X64_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(ARM_CROSS) $(ARM64_CROSS) $(C67_CROSS) $(WINCE_CROSS)
127130 LIBTCC1_CROSS=lib/i386-win32/libtcc1.a lib/x86_64-win32/libtcc1.a
128131 LIBTCC1=libtcc1.a
129132 else ifeq ($(ARCH),x86-64)
130133 NATIVE_FILES=$(X86_64_FILES)
131−PROGS_CROSS=$(I386_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(ARM_CROSS) $(C67_CROSS) $(WINCE_CROSS)
134+PROGS_CROSS=$(I386_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(ARM_CROSS) $(ARM64_CROSS) $(C67_CROSS) $(WINCE_CROSS)
132135 LIBTCC1_CROSS=lib/i386-win32/libtcc1.a lib/x86_64-win32/libtcc1.a lib/i386/libtcc1.a
133136 LIBTCC1=libtcc1.a
134137 else ifeq ($(ARCH),arm)
135138 NATIVE_FILES=$(ARM_FILES)
136−PROGS_CROSS=$(I386_CROSS) $(X64_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(C67_CROSS) $(WINCE_CROSS)
139+PROGS_CROSS=$(I386_CROSS) $(X64_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(ARM64_CROSS) $(C67_CROSS) $(WINCE_CROSS)
140+LIBTCC1=libtcc1.a
141+LIBTCC1_CROSS=lib/i386-win32/libtcc1.a lib/x86_64-win32/libtcc1.a lib/i386/libtcc1.a
142+else ifeq ($(ARCH),arm64)
143+NATIVE_FILES=$(ARM64_FILES)
144+PROGS_CROSS=$(I386_CROSS) $(X64_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(ARM_CROSS) $(C67_CROSS) $(WINCE_CROSS)
137145 LIBTCC1=libtcc1.a
138146 LIBTCC1_CROSS=lib/i386-win32/libtcc1.a lib/x86_64-win32/libtcc1.a lib/i386/libtcc1.a
139147 endif
@@ -181,6 +189,7 @@ $(ARM_FPA_CROSS): DEFINES = -DTCC_TARGET_ARM · 41 unmodified lines
181189 $(ARM_FPA_LD_CROSS)$(EXESUF): DEFINES = -DTCC_TARGET_ARM -DLDOUBLE_SIZE=12
182190 $(ARM_VFP_CROSS): DEFINES = -DTCC_TARGET_ARM -DTCC_ARM_VFP -DCONFIG_MULTIARCHDIR="\"arm-linux-gnu\""
183191 $(ARM_EABI_CROSS): DEFINES = -DTCC_TARGET_ARM -DTCC_ARM_EABI -DTCC_ARM_VFP -DCONFIG_MULTIARCHDIR="\"arm-linux-gnueabi\""
192+$(ARM64_CROSS): DEFINES = -DTCC_TARGET_ARM64
184193
185194 $(I386_CROSS): $(I386_FILES)
186195 $(X64_CROSS): $(X86_64_FILES)
@@ -189,6 +198,7 @@ $(WIN64_CROSS): $(WIN64_FILES) · 2 unmodified lines
189198 $(WINCE_CROSS): $(WINCE_FILES)
190199 $(C67_CROSS): $(C67_FILES)
191200 $(ARM_FPA_CROSS) $(ARM_FPA_LD_CROSS) $(ARM_VFP_CROSS) $(ARM_EABI_CROSS): $(ARM_FILES)
201+$(ARM64_CROSS): $(ARM64_FILES)
192202
193203 # libtcc generation and test
194204 ifndef ONE_SOURCE
arm64-gen.c+1621−0
@@ -0,0 +1,1621 @@
1+/*
2+ * A64 code generator for TCC
3+ *
4+ * Copyright (c) 2014-2015 Edmund Grimley Evans
5+ *
6+ * Copying and distribution of this file, with or without modification,
7+ * are permitted in any medium without royalty provided the copyright
8+ * notice and this notice are preserved. This file is offered as-is,
9+ * without any warranty.
10+ */
11+
12+#ifdef TARGET_DEFS_ONLY
13+
14+// Number of registers available to allocator:
15+#define NB_REGS 28 // x0-x18, x30, v0-v7
16+
17+#define TREG_R(x) (x) // x = 0..18
18+#define TREG_R30 19
19+#define TREG_F(x) (x + 20) // x = 0..7
20+
21+// Register classes sorted from more general to more precise:
22+#define RC_INT (1 << 0)
23+#define RC_FLOAT (1 << 1)
24+#define RC_R(x) (1 << (2 + (x))) // x = 0..18
25+#define RC_R30 (1 << 21)
26+#define RC_F(x) (1 << (22 + (x))) // x = 0..7
27+
28+#define RC_IRET (RC_R(0)) // int return register class
29+#define RC_FRET (RC_F(0)) // float return register class
30+
31+#define REG_IRET (TREG_R(0)) // int return register number
32+#define REG_FRET (TREG_F(0)) // float return register number
33+
34+#define PTR_SIZE 8
35+
36+#define LDOUBLE_SIZE 16
37+#define LDOUBLE_ALIGN 16
38+
39+#define MAX_ALIGN 16
40+
41+#define CHAR_IS_UNSIGNED
42+
43+/******************************************************/
44+/* ELF defines */
45+
46+#define EM_TCC_TARGET EM_AARCH64
47+
48+#define R_DATA_32 R_AARCH64_ABS32
49+#define R_DATA_PTR R_AARCH64_ABS64
50+#define R_JMP_SLOT R_AARCH64_JUMP_SLOT
51+#define R_COPY R_AARCH64_COPY
52+
53+#define ELF_START_ADDR 0x00400000
54+#define ELF_PAGE_SIZE 0x1000
55+
56+/******************************************************/
57+#else /* ! TARGET_DEFS_ONLY */
58+/******************************************************/
59+#include "tcc.h"
60+#include <assert.h>
61+
62+ST_DATA const int reg_classes[NB_REGS] = {
63+ RC_INT | RC_R(0),
64+ RC_INT | RC_R(1),
65+ RC_INT | RC_R(2),
66+ RC_INT | RC_R(3),
67+ RC_INT | RC_R(4),
68+ RC_INT | RC_R(5),
69+ RC_INT | RC_R(6),
70+ RC_INT | RC_R(7),
71+ RC_INT | RC_R(8),
72+ RC_INT | RC_R(9),
73+ RC_INT | RC_R(10),
74+ RC_INT | RC_R(11),
75+ RC_INT | RC_R(12),
76+ RC_INT | RC_R(13),
77+ RC_INT | RC_R(14),
78+ RC_INT | RC_R(15),
79+ RC_INT | RC_R(16),
80+ RC_INT | RC_R(17),
81+ RC_INT | RC_R(18),
82+ RC_R30, // not in RC_INT as we make special use of x30
83+ RC_FLOAT | RC_F(0),
84+ RC_FLOAT | RC_F(1),
85+ RC_FLOAT | RC_F(2),
86+ RC_FLOAT | RC_F(3),
87+ RC_FLOAT | RC_F(4),
88+ RC_FLOAT | RC_F(5),
89+ RC_FLOAT | RC_F(6),
90+ RC_FLOAT | RC_F(7)
91+};
92+
93+#define IS_FREG(x) ((x) >= TREG_F(0))
94+
95+static uint32_t intr(int r)
96+{
97+ assert(TREG_R(0) <= r && r <= TREG_R30);
98+ return r < TREG_R30 ? r : 30;
99+}
100+
101+static uint32_t fltr(int r)
102+{
103+ assert(TREG_F(0) <= r && r <= TREG_F(7));
104+ return r - TREG_F(0);
105+}
106+
107+// Add an instruction to text section:
108+ST_FUNC void o(unsigned int c)
109+{
110+ int ind1 = ind + 4;
111+ if (ind1 > cur_text_section->data_allocated)
112+ section_realloc(cur_text_section, ind1);
113+ *(uint32_t *)(cur_text_section->data + ind) = c;
114+ ind = ind1;
115+}
116+
117+static int arm64_encode_bimm64(uint64_t x)
118+{
119+ int neg = x & 1;
120+ int rep, pos, len;
121+
122+ if (neg)
123+ x = ~x;
124+ if (!x)
125+ return -1;
126+
127+ if (x >> 2 == (x & (((uint64_t)1 << (64 - 2)) - 1)))
128+ rep = 2, x &= ((uint64_t)1 << 2) - 1;
129+ else if (x >> 4 == (x & (((uint64_t)1 << (64 - 4)) - 1)))
130+ rep = 4, x &= ((uint64_t)1 << 4) - 1;
131+ else if (x >> 8 == (x & (((uint64_t)1 << (64 - 8)) - 1)))
132+ rep = 8, x &= ((uint64_t)1 << 8) - 1;
133+ else if (x >> 16 == (x & (((uint64_t)1 << (64 - 16)) - 1)))
134+ rep = 16, x &= ((uint64_t)1 << 16) - 1;
135+ else if (x >> 32 == (x & (((uint64_t)1 << (64 - 32)) - 1)))
136+ rep = 32, x &= ((uint64_t)1 << 32) - 1;
137+ else
138+ rep = 64;
139+
140+ pos = 0;
141+ if (!(x & (((uint64_t)1 << 32) - 1))) x >>= 32, pos += 32;
142+ if (!(x & (((uint64_t)1 << 16) - 1))) x >>= 16, pos += 16;
143+ if (!(x & (((uint64_t)1 << 8) - 1))) x >>= 8, pos += 8;
144+ if (!(x & (((uint64_t)1 << 4) - 1))) x >>= 4, pos += 4;
145+ if (!(x & (((uint64_t)1 << 2) - 1))) x >>= 2, pos += 2;
146+ if (!(x & (((uint64_t)1 << 1) - 1))) x >>= 1, pos += 1;
147+
148+ len = 0;
149+ if (!(~x & (((uint64_t)1 << 32) - 1))) x >>= 32, len += 32;
150+ if (!(~x & (((uint64_t)1 << 16) - 1))) x >>= 16, len += 16;
151+ if (!(~x & (((uint64_t)1 << 8) - 1))) x >>= 8, len += 8;
152+ if (!(~x & (((uint64_t)1 << 4) - 1))) x >>= 4, len += 4;
153+ if (!(~x & (((uint64_t)1 << 2) - 1))) x >>= 2, len += 2;
154+ if (!(~x & (((uint64_t)1 << 1) - 1))) x >>= 1, len += 1;
155+
156+ if (x)
157+ return -1;
158+ if (neg) {
159+ pos = (pos + len) & (rep - 1);
160+ len = rep - len;
161+ }
162+ return ((0x1000 & rep << 6) | (((rep - 1) ^ 31) << 1 & 63) |
163+ ((rep - pos) & (rep - 1)) << 6 | (len - 1));
164+}
165+
166+static uint32_t arm64_movi(int r, uint64_t x)
167+{
168+ uint64_t m = 0xffff;
169+ int e;
170+ if (!(x & ~m))
171+ return 0x52800000 | r | x << 5; // movz w(r),#(x)
172+ if (!(x & ~(m << 16)))
173+ return 0x52a00000 | r | x >> 11; // movz w(r),#(x >> 16),lsl #16
174+ if (!(x & ~(m << 32)))
175+ return 0xd2c00000 | r | x >> 27; // movz x(r),#(x >> 32),lsl #32
176+ if (!(x & ~(m << 48)))
177+ return 0xd2e00000 | r | x >> 43; // movz x(r),#(x >> 48),lsl #48
178+ if ((x & ~m) == m << 16)
179+ return (0x12800000 | r |
180+ (~x << 5 & 0x1fffe0)); // movn w(r),#(~x)
181+ if ((x & ~(m << 16)) == m)
182+ return (0x12a00000 | r |
183+ (~x >> 11 & 0x1fffe0)); // movn w(r),#(~x >> 16),lsl #16
184+ if (!~(x | m))
185+ return (0x92800000 | r |
186+ (~x << 5 & 0x1fffe0)); // movn x(r),#(~x)
187+ if (!~(x | m << 16))
188+ return (0x92a00000 | r |
189+ (~x >> 11 & 0x1fffe0)); // movn x(r),#(~x >> 16),lsl #16
190+ if (!~(x | m << 32))
191+ return (0x92c00000 | r |
192+ (~x >> 27 & 0x1fffe0)); // movn x(r),#(~x >> 32),lsl #32
193+ if (!~(x | m << 48))
194+ return (0x92e00000 | r |
195+ (~x >> 43 & 0x1fffe0)); // movn x(r),#(~x >> 32),lsl #32
196+ if (!(x >> 32) && (e = arm64_encode_bimm64(x | x << 32)) >= 0)
197+ return 0x320003e0 | r | (uint32_t)e << 10; // movi w(r),#(x)
198+ if ((e = arm64_encode_bimm64(x)) >= 0)
199+ return 0xb20003e0 | r | (uint32_t)e << 10; // movi x(r),#(x)
200+ return 0;
201+}
202+
203+static void arm64_movimm(int r, uint64_t x)
204+{
205+ uint32_t i;
206+ if ((i = arm64_movi(r, x)))
207+ o(i);
208+ else {
209+ // This could be improved:
210+ o(0x52800000 | r | (x & 0xffff) << 5); // movz w(r),#(x & 0xffff)
211+ for (i = 1; i < 4; i++)
212+ if (x >> 16 * i & 0xffff) {
213+ o(0xf2800000 | r | (x >> 16 * i & 0xffff) << 5 | i << 21);
214+ // movk w(r),#(*),lsl #(*)
215+ }
216+
217+ }
218+}
219+
220+// Patch all branches in list pointed to by t to branch to a:
221+ST_FUNC void gsym_addr(int t_, int a_)
222+{
223+ uint32_t t = t_;
224+ uint32_t a = a_;
225+ while (t) {
226+ uint32_t *ptr = (uint32_t *)(cur_text_section->data + t);
227+ uint32_t next = *ptr;
228+ if (a - t + 0x8000000 >= 0x10000000)
229+ tcc_error("branch out of range");
230+ *ptr = (a - t == 4 ? 0xd503201f : // nop
231+ 0x14000000 | ((a - t) >> 2 & 0x3ffffff)); // b
232+ t = next;
233+ }
234+}
235+
236+// Patch all branches in list pointed to by t to branch to current location:
237+ST_FUNC void gsym(int t)
238+{
239+ gsym_addr(t, ind);
240+}
241+
242+static int arm64_type_size(int t)
243+{
244+ switch (t & VT_BTYPE) {
245+ case VT_INT: return 2;
246+ case VT_BYTE: return 0;
247+ case VT_SHORT: return 1;
248+ case VT_PTR: return 3;
249+ case VT_ENUM: return 2;
250+ case VT_FUNC: return 3;
251+ case VT_FLOAT: return 2;
252+ case VT_DOUBLE: return 3;
253+ case VT_LDOUBLE: return 4;
254+ case VT_BOOL: return 0;
255+ case VT_LLONG: return 3;
256+ }
257+ assert(0);
258+ return 0;
259+}
260+
261+static void gen_stack_addr(int reg, uint64_t off)
262+{
263+ arm64_movimm(30, off); // use x30 for offset
264+ o(0x8b3e63e0 | reg);
265+}
266+
267+static void gen_load(int sg, int sz, int dst, int bas, uint64_t off)
268+{
269+ if (sz >= 2)
270+ sg = 0;
271+ if (!(off & ~(0xfff << sz)))
272+ o(0x39400000 | dst | bas << 5 | off << (10 - sz) |
273+ !!sg << 23 | sz << 30);
274+ else if (off < 256 || -off <= 256)
275+ o(0x38400000 | dst | bas << 5 | (off & 511) << 12 |
276+ !!sg << 23 | sz << 30);
277+ else {
278+ arm64_movimm(30, off); // use x30 for offset
279+ o(0x38206800 | dst | bas << 5 | 30 << 16 |
280+ (!!sg + 1) << 22 | sz << 30);
281+ }
282+}
283+
284+static void gen_fload(int sz, int dst, int bas, uint64_t off)
285+{
286+ if (!(off & ~(0xfff << sz)))
287+ o(0x3d400000 | dst | bas << 5 | off << (10 - sz) |
288+ (sz & 4) << 21 | (sz & 3) << 30);
289+ else if (off < 256 || -off <= 256)
290+ o(0x3c400000 | dst | bas << 5 | (off & 511) << 12 |
291+ (sz & 4) << 21 | (sz & 3) << 30);
292+ else {
293+ arm64_movimm(30, off); // use x30 for offset
294+ o(0x3c606800 | dst | bas << 5 | 30 << 16 | sz << 30 | (sz & 4) << 21);
295+ }
296+}
297+
298+static void gen_sload(int reg, int size)
299+{
300+ // Use x30 for intermediate value in some cases.
301+ switch (size) {
302+ default: assert(0); break;
303+ case 1:
304+ gen_load(0, 0, reg, reg, 0);
305+ break;
306+ case 2:
307+ gen_load(0, 1, reg, reg, 0);
308+ break;
309+ case 3:
310+ gen_load(0, 1, 30, reg, 0);
311+ gen_load(0, 0, reg, reg, 2);
312+ o(0x2a0043c0 | reg | reg << 16); // orr x(reg),x30,x(reg),lsl #16
313+ break;
314+ case 4:
315+ gen_load(0, 2, reg, reg, 0);
316+ break;
317+ case 5:
318+ gen_load(0, 2, 30, reg, 0);
319+ gen_load(0, 0, reg, reg, 4);
320+ o(0xaa0083c0 | reg | reg << 16); // orr x(reg),x30,x(reg),lsl #32
321+ break;
322+ case 6:
323+ gen_load(0, 2, 30, reg, 0);
324+ gen_load(0, 1, reg, reg, 4);
325+ o(0xaa0083c0 | reg | reg << 16); // orr x(reg),x30,x(reg),lsl #32
326+ break;
327+ case 7:
328+ gen_load(0, 2, 30, reg, 0);
329+ gen_load(0, 2, reg, reg, 3);
330+ o(0x53087c00 | reg | reg << 5); // lsr w(reg), w(reg), #8
331+ o(0xaa0083c0 | reg | reg << 16); // orr x(reg),x30,x(reg),lsl #32
332+ break;
333+ case 8:
334+ gen_load(0, 3, reg, reg, 0);
335+ break;
336+ case 9:
337+ gen_load(0, 0, reg + 1, reg, 8);
338+ gen_load(0, 3, reg, reg, 0);
339+ break;
340+ case 10:
341+ gen_load(0, 1, reg + 1, reg, 8);
342+ gen_load(0, 3, reg, reg, 0);
343+ break;
344+ case 11:
345+ gen_load(0, 2, reg + 1, reg, 7);
346+ o(0x53087c00 | (reg+1) | (reg+1) << 5); // lsr w(reg+1), w(reg+1), #8
347+ gen_load(0, 3, reg, reg, 0);
348+ break;
349+ case 12:
350+ gen_load(0, 2, reg + 1, reg, 8);
351+ gen_load(0, 3, reg, reg, 0);
352+ break;
353+ case 13:
354+ gen_load(0, 3, reg + 1, reg, 5);
355+ o(0xd358fc00 | (reg+1) | (reg+1) << 5); // lsr x(reg+1), x(reg+1), #24
356+ gen_load(0, 3, reg, reg, 0);
357+ break;
358+ case 14:
359+ gen_load(0, 3, reg + 1, reg, 6);
360+ o(0xd350fc00 | (reg+1) | (reg+1) << 5); // lsr x(reg+1), x(reg+1), #16
361+ gen_load(0, 3, reg, reg, 0);
362+ break;
363+ case 15:
364+ gen_load(0, 3, reg + 1, reg, 7);
365+ o(0xd348fc00 | (reg+1) | (reg+1) << 5); // lsr x(reg+1), x(reg+1), #8
366+ gen_load(0, 3, reg, reg, 0);
367+ break;
368+ case 16:
369+ o(0xa9400000 | reg | (reg+1) << 10 | reg << 5);
370+ // ldp x(reg),x(reg+1),[x(reg)]
371+ break;
372+ }
373+}
374+
375+static void gen_store(int sz, int dst, int bas, uint64_t off)
376+{
377+ if (!(off & ~(0xfff << sz)))
378+ o(0x39000000 | dst | bas << 5 | off << (10 - sz) | sz << 30);
379+ else if (off < 256 || -off <= 256)
380+ o(0x38000000 | dst | bas << 5 | (off & 511) << 12 | sz << 30);
381+ else {
382+ arm64_movimm(30, off); // use x30 for offset
383+ o(0x38206800 | dst | bas << 5 | 30 << 16 | sz << 30);
384+ }
385+}
386+
387+static void gen_fstore(int sz, int dst, int bas, uint64_t off)
388+{
389+ if (!(off & ~(0xfff << sz)))
390+ o(0x3d000000 | dst | bas << 5 | off << (10 - sz) |
391+ (sz & 4) << 21 | (sz & 3) << 30);
392+ else if (off < 256 || -off <= 256)
393+ o(0x3c000000 | dst | bas << 5 | (off & 511) << 12 |
394+ (sz & 4) << 21 | (sz & 3) << 30);
395+ else {
396+ arm64_movimm(30, off); // use x30 for offset
397+ o(0x3c206800 | dst | bas << 5 | 30 << 16 | sz << 30 | (sz & 4) << 21);
398+ }
399+}
400+
401+static void gen_addr(int r, Sym *sym, unsigned long addend)
402+{
403+#if 0
404+ // This is normally the right way to do it, I think,
405+ // but it does not work with "-run" when stdin or stderr is
406+ // used by the program: "R_AARCH64_ADR_PREL_PG_HI21 relocation failed".
407+ greloca(cur_text_section, sym, ind, R_AARCH64_ADR_PREL_PG_HI21, addend);
408+ o(0x90000000 | r);
409+ greloca(cur_text_section, sym, ind, R_AARCH64_ADD_ABS_LO12_NC, addend);
410+ o(0x91000000 | r | r << 5);
411+#else
412+ // This seems to work in all cases, unless you try to use an old buggy
413+ // GCC for linking, which says: "unresolvable R_AARCH64_MOVW_UABS_G0_NC
414+ // relocation against symbol `stderr@@GLIBC_2.17'".
415+ greloca(cur_text_section, sym, ind, R_AARCH64_MOVW_UABS_G0_NC, addend);
416+ o(0xf2800000 | r); // movk x(rt),#...,lsl #0
417+ greloca(cur_text_section, sym, ind, R_AARCH64_MOVW_UABS_G1_NC, addend);
418+ o(0xf2a00000 | r); // movk x(rt),#...,lsl #16
419+ greloca(cur_text_section, sym, ind, R_AARCH64_MOVW_UABS_G2_NC, addend);
420+ o(0xf2c00000 | r); // movk x(rt),#...,lsl #32
421+ greloca(cur_text_section, sym, ind, R_AARCH64_MOVW_UABS_G3, addend);
422+ o(0xf2e00000 | r); // movk x(rt),#...,lsl #48
423+#endif
424+}
425+
426+ST_FUNC void load(int r, SValue *sv)
427+{
428+ int svtt = sv->type.t;
429+ int svr = sv->r & ~VT_LVAL_TYPE;
430+ int svrv = svr & VT_VALMASK;
431+ uint64_t svcul = (int32_t)sv->c.ul;
432+
433+ if (svr == (VT_LOCAL | VT_LVAL)) {
434+ if (IS_FREG(r))
435+ gen_fload(arm64_type_size(svtt), fltr(r), 29, svcul);
436+ else
437+ gen_load(!(svtt & VT_UNSIGNED), arm64_type_size(svtt),
438+ intr(r), 29, svcul);
439+ return;
440+ }
441+
442+ if ((svr & ~VT_VALMASK) == VT_LVAL && svrv < VT_CONST) {
443+ if (IS_FREG(r))
444+ gen_fload(arm64_type_size(svtt),
445+ fltr(r), intr(svrv), 0);
446+ else
447+ gen_load(!(svtt & VT_UNSIGNED), arm64_type_size(svtt),
448+ intr(r), intr(svrv), 0);
449+ return;
450+ }
451+
452+ if (svr == (VT_CONST | VT_LVAL | VT_SYM)) {
453+ gen_addr(30, sv->sym, svcul); // use x30 for address
454+ if (IS_FREG(r))
455+ gen_fload(arm64_type_size(svtt), fltr(r), 30, 0);
456+ else
457+ gen_load(!(svtt & VT_UNSIGNED), arm64_type_size(svtt),
458+ intr(r), 30, 0);
459+ return;
460+ }
461+
462+ if (svr == (VT_CONST | VT_SYM)) {
463+ gen_addr(intr(r), sv->sym, svcul);
464+ return;
465+ }
466+
467+ if (svr == VT_CONST) {
468+ if ((svtt & VT_BTYPE) != VT_VOID)
469+ arm64_movimm(intr(r),
470+ arm64_type_size(svtt) == 3 ? sv->c.ull : svcul);
471+ return;
472+ }
473+
474+ if (svr < VT_CONST) {
475+ if (IS_FREG(r) && IS_FREG(svr))
476+ if (svtt == VT_LDOUBLE)
477+ o(0x4ea01c00 | fltr(r) | fltr(svr) << 5);
478+ // mov v(r).16b,v(svr).16b
479+ else
480+ o(0x1e604000 | fltr(r) | fltr(svr) << 5); // fmov d(r),d(svr)
481+ else if (!IS_FREG(r) && !IS_FREG(svr))
482+ o(0xaa0003e0 | intr(r) | intr(svr) << 16); // mov x(r),x(svr)
483+ else
484+ assert(0);
485+ return;
486+ }
487+
488+ if (svr == VT_LOCAL) {
489+ if (-svcul < 0x1000)
490+ o(0xd10003a0 | intr(r) | -svcul << 10); // sub x(r),x29,#...
491+ else {
492+ arm64_movimm(30, -svcul); // use x30 for offset
493+ o(0xcb0003a0 | intr(r) | 30 << 16); // sub x(r),x29,x30
494+ }
495+ return;
496+ }
497+
498+ if (svr == VT_JMP || svr == VT_JMPI) {
499+ int t = (svr == VT_JMPI);
500+ arm64_movimm(intr(r), t);
501+ o(0x14000002); // b .+8
502+ gsym(svcul);
503+ arm64_movimm(intr(r), t ^ 1);
504+ return;
505+ }
506+
507+ if (svr == (VT_LLOCAL | VT_LVAL)) {
508+ gen_load(0, 3, 30, 29, svcul); // use x30 for offset
509+ if (IS_FREG(r))
510+ gen_fload(arm64_type_size(svtt), fltr(r), 30, 0);
511+ else
512+ gen_load(!(svtt & VT_UNSIGNED), arm64_type_size(svtt),
513+ intr(r), 30, 0);
514+ return;
515+ }
516+
517+ printf("load(%x, (%x, %x, %llx))\n", r, svtt, sv->r, (long long)svcul);
518+ assert(0);
519+}
520+
521+ST_FUNC void store(int r, SValue *sv)
522+{
523+ int svtt = sv->type.t;
524+ int svr = sv->r & ~VT_LVAL_TYPE;
525+ int svrv = svr & VT_VALMASK;
526+ uint64_t svcul = (int32_t)sv->c.ul;
527+
528+ if (svr == (VT_LOCAL | VT_LVAL)) {
529+ if (IS_FREG(r))
530+ gen_fstore(arm64_type_size(svtt), fltr(r), 29, svcul);
531+ else
532+ gen_store(arm64_type_size(svtt), intr(r), 29, svcul);
533+ return;
534+ }
535+
536+ if ((svr & ~VT_VALMASK) == VT_LVAL && svrv < VT_CONST) {
537+ if (IS_FREG(r))
538+ gen_fstore(arm64_type_size(svtt), fltr(r), intr(svrv), 0);
539+ else
540+ gen_store(arm64_type_size(svtt), intr(r), intr(svrv), 0);
541+ return;
542+ }
543+
544+ if (svr == (VT_CONST | VT_LVAL | VT_SYM)) {
545+ gen_addr(30, sv->sym, svcul); // use x30 for address
546+ if (IS_FREG(r))
547+ gen_fstore(arm64_type_size(svtt), fltr(r), 30, 0);
548+ else
549+ gen_store(arm64_type_size(svtt), intr(r), 30, 0);
550+ return;
551+ }
552+
553+ printf("store(%x, (%x, %x, %llx))\n", r, svtt, sv->r, (long long)svcul);
554+ assert(0);
555+}
556+
557+static void arm64_gen_bl_or_b(int b)
558+{
559+ if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
560+ assert(!b);
561+ if (vtop->r & VT_SYM)
562+ greloc(cur_text_section, vtop->sym, ind, R_AARCH64_CALL26);
563+ else
564+ assert(0);
565+ o(0x94000000); // bl .
566+ }
567+ else
568+ o(0xd61f0000 | !b << 21 | intr(gv(RC_R30)) << 5); // br/blr
569+}
570+
571+static int arm64_hfa_aux(CType *type, int *fsize, int num)
572+{
573+ if (is_float(type->t)) {
574+ int a, n = type_size(type, &a);
575+ if (num >= 4 || (*fsize && *fsize != n))
576+ return -1;
577+ *fsize = n;
578+ return num + 1;
579+ }
580+ else if ((type->t & VT_BTYPE) == VT_STRUCT) {
581+ int is_struct = 0; // rather than union
582+ Sym *field;
583+ for (field = type->ref->next; field; field = field->next)
584+ if (field->c) {
585+ is_struct = 1;
586+ break;
587+ }
588+ if (is_struct) {
589+ int num0 = num;
590+ for (field = type->ref->next; field; field = field->next) {
591+ if (field->c != (num - num0) * *fsize)
592+ return -1;
593+ num = arm64_hfa_aux(&field->type, fsize, num);
594+ if (num == -1)
595+ return -1;
596+ }
597+ if (type->ref->c != (num - num0) * *fsize)
598+ return -1;
599+ return num;
600+ }
601+ else { // union
602+ int num0 = num;
603+ for (field = type->ref->next; field; field = field->next) {
604+ int num1 = arm64_hfa_aux(&field->type, fsize, num0);
605+ if (num1 == -1)
606+ return -1;
607+ num = num1 < num ? num : num1;
608+ }
609+ if (type->ref->c != (num - num0) * *fsize)
610+ return -1;
611+ return num;
612+ }
613+ }
614+ else if (type->t & VT_ARRAY) {
615+ int num1;
616+ if (!type->ref->c)
617+ return num;
618+ num1 = arm64_hfa_aux(&type->ref->type, fsize, num);
619+ if (num1 == -1 || (num1 != num && type->ref->c > 4))
620+ return -1;
621+ num1 = num + type->ref->c * (num1 - num);
622+ if (num1 > 4)
623+ return -1;
624+ return num1;
625+ }
626+ return -1;
627+}
628+
629+static int arm64_hfa(CType *type, int *fsize)
630+{
631+ if ((type->t & VT_BTYPE) == VT_STRUCT || (type->t & VT_ARRAY)) {
632+ int sz = 0;
633+ int n = arm64_hfa_aux(type, &sz, 0);
634+ if (0 < n && n <= 4) {
635+ if (fsize)
636+ *fsize = sz;
637+ return n;
638+ }
639+ }
640+ return 0;
641+}
642+
643+static unsigned long arm64_pcs_aux(int n, CType **type, unsigned long *a)
644+{
645+ int nx = 0; // next integer register
646+ int nv = 0; // next vector register
647+ unsigned long ns = 32; // next stack offset
648+ int i;
649+
650+ for (i = 0; i < n; i++) {
651+ int hfa = arm64_hfa(type[i], 0);
652+ int size, align;
653+
654+ if ((type[i]->t & VT_ARRAY) ||
655+ (type[i]->t & VT_BTYPE) == VT_FUNC)
656+ size = align = 8;
657+ else
658+ size = type_size(type[i], &align);
659+
660+ if (hfa)
661+ // B.2
662+ ;
663+ else if (size > 16) {
664+ // B.3: replace with pointer
665+ if (nx < 8)
666+ a[i] = nx++ << 1 | 1;
667+ else {
668+ ns = (ns + 7) & ~7;
669+ a[i] = ns | 1;
670+ ns += 8;
671+ }
672+ continue;
673+ }
674+ else if ((type[i]->t & VT_BTYPE) == VT_STRUCT)
675+ // B.4
676+ size = (size + 7) & ~7;
677+
678+ // C.1
679+ if (is_float(type[i]->t) && nv < 8) {
680+ a[i] = 16 + (nv++ << 1);
681+ continue;
682+ }
683+
684+ // C.2
685+ if (hfa && nv + hfa <= 8) {
686+ a[i] = 16 + (nv << 1);
687+ nv += hfa;
688+ continue;
689+ }
690+
691+ // C.3
692+ if (hfa) {
693+ nv = 8;
694+ size = (size + 7) & ~7;
695+ }
696+
697+ // C.4
698+ if (hfa || (type[i]->t & VT_BTYPE) == VT_LDOUBLE) {
699+ ns = (ns + 7) & ~7;
700+ ns = (ns + align - 1) & -align;
701+ }
702+
703+ // C.5
704+ if ((type[i]->t & VT_BTYPE) == VT_FLOAT)
705+ size = 8;
706+
707+ // C.6
708+ if (hfa || is_float(type[i]->t)) {
709+ a[i] = ns;
710+ ns += size;
711+ continue;
712+ }
713+
714+ // C.7
715+ if ((type[i]->t & VT_BTYPE) != VT_STRUCT && size <= 8 && nx < 8) {
716+ a[i] = nx++ << 1;
717+ continue;
718+ }
719+
720+ // C.8
721+ if (align == 16)
722+ nx = (nx + 1) & ~1;
723+
724+ // C.9
725+ if ((type[i]->t & VT_BTYPE) != VT_STRUCT && size == 16 && nx < 7) {
726+ a[i] = nx << 1;
727+ nx += 2;
728+ continue;
729+ }
730+
731+ // C.10
732+ if ((type[i]->t & VT_BTYPE) == VT_STRUCT && size <= (8 - nx) * 8) {
733+ a[i] = nx << 1;
734+ nx += (size + 7) >> 3;
735+ continue;
736+ }
737+
738+ // C.11
739+ nx = 8;
740+
741+ // C.12
742+ ns = (ns + 7) & ~7;
743+ ns = (ns + align - 1) & -align;
744+
745+ // C.13
746+ if ((type[i]->t & VT_BTYPE) == VT_STRUCT) {
747+ a[i] = ns;
748+ ns += size;
749+ continue;
750+ }
751+
752+ // C.14
753+ if (size < 8)
754+ size = 8;
755+
756+ // C.15
757+ a[i] = ns;
758+ ns += size;
759+ }
760+
761+ return ns - 32;
762+}
763+
764+static unsigned long arm64_pcs(int n, CType **type, unsigned long *a)
765+{
766+ unsigned long stack;
767+
768+ // Return type:
769+ if ((type[0]->t & VT_BTYPE) == VT_VOID)
770+ a[0] = -1;
771+ else {
772+ arm64_pcs_aux(1, type, a);
773+ assert(a[0] == 0 || a[0] == 1 || a[0] == 16);
774+ }
775+
776+ // Argument types:
777+ stack = arm64_pcs_aux(n, type + 1, a + 1);
778+
779+ if (0) {
780+ int i;
781+ for (i = 0; i <= n; i++) {
782+ if (!i)
783+ printf("arm64_pcs return: ");
784+ else
785+ printf("arm64_pcs arg %d: ", i);
786+ if (a[i] == (unsigned long)-1)
787+ printf("void\n");
788+ else if (a[i] == 1 && !i)
789+ printf("X8 pointer\n");
790+ else if (a[i] < 16)
791+ printf("X%lu%s\n", a[i] / 2, a[i] & 1 ? " pointer" : "");
792+ else if (a[i] < 32)
793+ printf("V%lu\n", a[i] / 2 - 8);
794+ else
795+ printf("stack %lu%s\n",
796+ (a[i] - 32) & ~1, a[i] & 1 ? " pointer" : "");
797+ }
798+ }
799+
800+ return stack;
801+}
802+
803+ST_FUNC void gfunc_call(int nb_args)
804+{
805+ CType *return_type;
806+ CType **t;
807+ unsigned long *a, *a1;
808+ unsigned long stack;
809+ int i;
810+
811+ return_type = &vtop[-nb_args].type.ref->type;
812+ if ((return_type->t & VT_BTYPE) == VT_STRUCT)
813+ --nb_args;
814+
815+ t = tcc_malloc((nb_args + 1) * sizeof(*t));
816+ a = tcc_malloc((nb_args + 1) * sizeof(*a));
817+ a1 = tcc_malloc((nb_args + 1) * sizeof(*a1));
818+
819+ t[0] = return_type;
820+ for (i = 0; i < nb_args; i++)
821+ t[nb_args - i] = &vtop[-i].type;
822+
823+ stack = arm64_pcs(nb_args, t, a);
824+
825+ // Allocate space for structs replaced by pointer:
826+ for (i = nb_args; i; i--)
827+ if (a[i] & 1) {
828+ SValue *arg = &vtop[i - nb_args];
829+ int align, size = type_size(&arg->type, &align);
830+ assert((arg->type.t & VT_BTYPE) == VT_STRUCT);
831+ stack = (stack + align - 1) & -align;
832+ a1[i] = stack;
833+ stack += size;
834+ }
835+
836+ stack = (stack + 15) >> 4 << 4;
837+
838+ assert(stack < 0x1000);
839+ if (stack)
840+ o(0xd10003ff | stack << 10); // sub sp,sp,#(n)
841+
842+ // First pass: set all values on stack
843+ for (i = nb_args; i; i--) {
844+ vpushv(vtop - nb_args + i);
845+
846+ if (a[i] & 1) {
847+ // struct replaced by pointer
848+ int r = get_reg(RC_INT);
849+ gen_stack_addr(intr(r), a1[i]);
850+ vset(&vtop->type, r | VT_LVAL, 0);
851+ vswap();
852+ vstore();
853+ if (a[i] >= 32) {
854+ // pointer on stack
855+ r = get_reg(RC_INT);
856+ gen_stack_addr(intr(r), a1[i]);
857+ gen_store(3, intr(r), 31, (a[i] - 32) >> 1 << 1);
858+ }
859+ }
860+ else if (a[i] >= 32) {
861+ // value on stack
862+ if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
863+ int r = get_reg(RC_INT);
864+ gen_stack_addr(intr(r), a[i] - 32);
865+ vset(&vtop->type, r | VT_LVAL, 0);
866+ vswap();
867+ vstore();
868+ }
869+ else if (is_float(vtop->type.t)) {
870+ gv(RC_FLOAT);
871+ gen_fstore(arm64_type_size(vtop[0].type.t),
872+ fltr(vtop[0].r), 31, a[i] - 32);
873+ }
874+ else {
875+ gv(RC_INT);
876+ gen_store(arm64_type_size(vtop[0].type.t),
877+ intr(vtop[0].r), 31, a[i] - 32);
878+ }
879+ }
880+
881+ --vtop;
882+ }
883+
884+ // Second pass: assign values to registers
885+ for (i = nb_args; i; i--, vtop--) {
886+ if (a[i] < 16 && !(a[i] & 1)) {
887+ // value in general-purpose registers
888+ if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
889+ int align, size = type_size(&vtop->type, &align);
890+ vtop->type.t = VT_PTR;
891+ gaddrof();
892+ gv(RC_R(a[i] / 2));
893+ gen_sload(a[i] / 2, size);
894+ }
895+ else
896+ gv(RC_R(a[i] / 2));
897+ }
898+ else if (a[i] < 16)
899+ // struct replaced by pointer in register
900+ gen_stack_addr(a[i] / 2, a1[i]);
901+ else if (a[i] < 32) {
902+ // value in floating-point registers
903+ if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
904+ int j, sz, n = arm64_hfa(&vtop->type, &sz);
905+ vtop->type.t = VT_PTR;
906+ gaddrof();
907+ gv(RC_R30);
908+ for (j = 0; j < n; j++)
909+ o(0x3d4003c0 |
910+ (sz & 16) << 19 | -(sz & 8) << 27 | (sz & 4) << 29 |
911+ (a[i] / 2 - 8 + j) |
912+ j << 10); // ldr ([sdq])(*),[x30,#(j * sz)]
913+ }
914+ else
915+ gv(RC_F(a[i] / 2 - 8));
916+ }
917+ }
918+
919+ if ((return_type->t & VT_BTYPE) == VT_STRUCT) {
920+ if (a[0] == 1) {
921+ // indirect return: set x8 and discard the stack value
922+ gv(RC_R(8));
923+ --vtop;
924+ }
925+ else
926+ // return in registers: keep the address for after the call
927+ vswap();
928+ }
929+
930+ save_regs(0);
931+ arm64_gen_bl_or_b(0);
932+ --vtop;
933+ if (stack)
934+ o(0x910003ff | stack << 10); // add sp,sp,#(n)
935+
936+ {
937+ int rt = return_type->t;
938+ int bt = rt & VT_BTYPE;
939+ if (bt == VT_BYTE || bt == VT_SHORT)
940+ // Promote small integers:
941+ o(0x13001c00 | (bt == VT_SHORT) << 13 |
942+ !!(rt & VT_UNSIGNED) << 30); // [su]xt[bh] w0,w0
943+ else if (bt == VT_STRUCT && !(a[0] & 1)) {
944+ // A struct was returned in registers, so write it out:
945+ gv(RC_R(8));
946+ --vtop;
947+ if (a[0] == 0) {
948+ int align, size = type_size(return_type, &align);
949+ assert(size <= 16);
950+ if (size > 8)
951+ o(0xa9000500); // stp x0,x1,[x8]
952+ else if (size)
953+ gen_store(size > 4 ? 3 : size > 2 ? 2 : size > 1,
954+ 0, 8, 0);
955+
956+ }
957+ else if (a[0] == 16) {
958+ int j, sz, n = arm64_hfa(return_type, &sz);
959+ for (j = 0; j < n; j++)
960+ o(0x3d000100 |
961+ (sz & 16) << 19 | -(sz & 8) << 27 | (sz & 4) << 29 |
962+ (a[i] / 2 - 8 + j) |
963+ j << 10); // str ([sdq])(*),[x8,#(j * sz)]
964+ }
965+ }
966+ }
967+
968+ tcc_free(a1);
969+ tcc_free(a);
970+ tcc_free(t);
971+}
972+
973+static unsigned long arm64_func_va_list_stack;
974+static int arm64_func_va_list_gr_offs;
975+static int arm64_func_va_list_vr_offs;
976+static int arm64_func_sub_sp_offset;
977+
978+ST_FUNC void gfunc_prolog(CType *func_type)
979+{
980+ int n = 0;
981+ int i = 0;
982+ Sym *sym;
983+ CType **t;
984+ unsigned long *a;
985+
986+ // Why doesn't the caller (gen_function) set func_vt?
987+ func_vt = func_type->ref->type;
988+ func_vc = 144; // offset of where x8 is stored
989+
990+ for (sym = func_type->ref; sym; sym = sym->next)
991+ ++n;
992+ t = tcc_malloc(n * sizeof(*t));
993+ a = tcc_malloc(n * sizeof(*a));
994+
995+ for (sym = func_type->ref; sym; sym = sym->next)
996+ t[i++] = &sym->type;
997+
998+ arm64_func_va_list_stack = arm64_pcs(n - 1, t, a);
999+
1000+ o(0xa9b27bfd); // stp x29,x30,[sp,#-224]!
1001+ o(0xad0087e0); // stp q0,q1,[sp,#16]
1002+ o(0xad018fe2); // stp q2,q3,[sp,#48]
1003+ o(0xad0297e4); // stp q4,q5,[sp,#80]
1004+ o(0xad039fe6); // stp q6,q7,[sp,#112]
1005+ o(0xa90923e8); // stp x8,x8,[sp,#144]
1006+ o(0xa90a07e0); // stp x0,x1,[sp,#160]
1007+ o(0xa90b0fe2); // stp x2,x3,[sp,#176]
1008+ o(0xa90c17e4); // stp x4,x5,[sp,#192]
1009+ o(0xa90d1fe6); // stp x6,x7,[sp,#208]
1010+
1011+ arm64_func_va_list_gr_offs = -64;
1012+ arm64_func_va_list_vr_offs = -128;
1013+
1014+ for (i = 1, sym = func_type->ref->next; sym; i++, sym = sym->next) {
1015+ int off = (a[i] < 16 ? 160 + a[i] / 2 * 8 :
1016+ a[i] < 32 ? 16 + (a[i] - 16) / 2 * 16 :
1017+ 224 + ((a[i] - 32) >> 1 << 1));
1018+ sym_push(sym->v & ~SYM_FIELD, &sym->type,
1019+ (a[i] & 1 ? VT_LLOCAL : VT_LOCAL) | lvalue_type(sym->type.t),
1020+ off);
1021+
1022+ if (a[i] < 16) {
1023+ int align, size = type_size(&sym->type, &align);
1024+ arm64_func_va_list_gr_offs = (a[i] / 2 - 7 +
1025+ (!(a[i] & 1) && size > 8)) * 8;
1026+ }
1027+ else if (a[i] < 32) {
1028+ int hfa = arm64_hfa(&sym->type, 0);
1029+ arm64_func_va_list_vr_offs = (a[i] / 2 - 16 +
1030+ (hfa ? hfa : 1)) * 16;
1031+ }
1032+
1033+ // HFAs of float and double need to be written differently:
1034+ if (16 <= a[i] && a[i] < 32 && (sym->type.t & VT_BTYPE) == VT_STRUCT) {
1035+ int j, sz, k = arm64_hfa(&sym->type, &sz);
1036+ if (sz < 16)
1037+ for (j = 0; j < k; j++) {
1038+ o(0x3d0003e0 | -(sz & 8) << 27 | (sz & 4) << 29 |
1039+ ((a[i] - 16) / 2 + j) | (off / sz + j) << 10);
1040+ // str ([sdq])(*),[sp,#(j * sz)]
1041+ }
1042+ }
1043+ }
1044+
1045+ tcc_free(a);
1046+ tcc_free(t);
1047+
1048+ o(0x910003fd); // mov x29,sp
1049+ arm64_func_sub_sp_offset = ind;
1050+ // In gfunc_epilog these will be replaced with code to decrement SP:
1051+ o(0xd503201f); // nop
1052+ o(0xd503201f); // nop
1053+ loc = 0;
1054+}
1055+
1056+ST_FUNC void gen_va_start(void)
1057+{
1058+ int r;
1059+ --vtop; // we don't need the "arg"
1060+ gaddrof();
1061+ r = intr(gv(RC_INT));
1062+
1063+ if (arm64_func_va_list_stack) {
1064+ //xx could use add (immediate) here
1065+ arm64_movimm(30, arm64_func_va_list_stack + 224);
1066+ o(0x8b1e03be); // add x30,x29,x30
1067+ }
1068+ else
1069+ o(0x910383be); // add x30,x29,#224
1070+ o(0xf900001e | r << 5); // str x30,[x(r)]
1071+
1072+ if (arm64_func_va_list_gr_offs) {
1073+ if (arm64_func_va_list_stack)
1074+ o(0x910383be); // add x30,x29,#224
1075+ o(0xf900041e | r << 5); // str x30,[x(r),#8]
1076+ }
1077+
1078+ if (arm64_func_va_list_vr_offs) {
1079+ o(0x910243be); // add x30,x29,#144
1080+ o(0xf900081e | r << 5); // str x30,[x(r),#16]
1081+ }
1082+
1083+ arm64_movimm(30, arm64_func_va_list_gr_offs);
1084+ o(0xb900181e | r << 5); // str w30,[x(r),#24]
1085+
1086+ arm64_movimm(30, arm64_func_va_list_vr_offs);
1087+ o(0xb9001c1e | r << 5); // str w30,[x(r),#28]
1088+
1089+ --vtop;
1090+}
1091+
1092+ST_FUNC void gen_va_arg(CType *t)
1093+{
1094+ int align, size = type_size(t, &align);
1095+ int fsize, hfa = arm64_hfa(t, &fsize);
1096+ int r0, r1;
1097+
1098+ if (is_float(t->t)) {
1099+ hfa = 1;
1100+ fsize = size;
1101+ }
1102+
1103+ gaddrof();
1104+ r0 = intr(gv(RC_INT));
1105+ r1 = get_reg(RC_INT);
1106+ vtop[0].r = r1 | lvalue_type(t->t);
1107+ r1 = intr(r1);
1108+
1109+ if (!hfa) {
1110+ uint32_t n = size > 16 ? 8 : (size + 7) & -8;
1111+ if (size == 16 && align == 16)
1112+ tcc_error("va_arg(ap, __uint128_t) unimplemented");
1113+ o(0xb940181e | r0 << 5); // ldr w30,[x(r0),#24] // __gr_offs
1114+ o(0x310003c0 | r1 | n << 10); // adds w(r1),w30,#(n)
1115+ o(0x540000ad); // b.le .+20
1116+ o(0xf9400000 | r1 | r0 << 5); // ldr x(r1),[x(r0)] // __stack
1117+ o(0x9100001e | r1 << 5 | n << 10); // add x30,x(r1),#(n)
1118+ o(0xf900001e | r0 << 5); // str x30,[x(r0)] // __stack
1119+ o(0x14000004); // b .+16
1120+ o(0xb9001800 | r1 | r0 << 5); // str w(r1),[x(r0),#24] // __gr_offs
1121+ o(0xf9400400 | r1 | r0 << 5); // ldr x(r1),[x(r0),#8] // __gr_top
1122+ o(0x8b3ec000 | r1 | r1 << 5); // add x(r1),x(r1),w30,sxtw
1123+ if (size > 16)
1124+ o(0xf9400000 | r1 | r1 << 5); // ldr x(r1),[x(r1)]
1125+ }
1126+ else {
1127+ uint32_t rsz = hfa << 4;
1128+ uint32_t ssz = (size + 7) & -(uint32_t)8;
1129+ uint32_t b1;
1130+ if (hfa > 1 && fsize < 16)
1131+ // We may need to change the layout of this HFA
1132+ tcc_error("va_arg(ap, HFA) unimplemented");
1133+ o(0xb9401c1e | r0 << 5); // ldr w30,[x(r0),#28] // __vr_offs
1134+ o(0x310003c0 | r1 | rsz << 10); // adds w(r1),w30,#(rsz)
1135+ b1 = ind; o(0x5400000d); // b.le lab1
1136+ o(0xf9400000 | r1 | r0 << 5); // ldr x(r1),[x(r0)] // __stack
1137+ if (fsize == 16) {
1138+ o(0x91003c00 | r1 | r1 << 5); // add x(r1),x(r1),#15
1139+ o(0x927cec00 | r1 | r1 << 5); // and x(r1),x(r1),#-16
1140+ }
1141+ o(0x9100001e | r1 << 5 | ssz << 10); // add x30,x(r1),#(ssz)
1142+ o(0xf900001e | r0 << 5); // str x30,[x(r0)] // __stack
1143+ o(0x14000004); // b .+16
1144+ // lab1:
1145+ *(uint32_t *)(cur_text_section->data + b1) =
1146+ (0x5400000d | (ind - b1) << 3);
1147+ o(0xb9001c00 | r1 | r0 << 5); // str w(r1),[x(r0),#28] // __vr_offs
1148+ o(0xf9400800 | r1 | r0 << 5); // ldr x(r1),[x(r0),#16] // __vr_top
1149+ o(0x8b3ec000 | r1 | r1 << 5); // add x(r1),x(r1),w30,sxtw
1150+ }
1151+}
1152+
1153+ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align)
1154+{
1155+ return 0;
1156+}
1157+
1158+ST_FUNC void greturn(void)
1159+{
1160+ CType *t = &func_vt;
1161+ unsigned long a;
1162+
1163+ arm64_pcs(0, &t, &a);
1164+ switch (a) {
1165+ case -1:
1166+ break;
1167+ case 0:
1168+ if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
1169+ int align, size = type_size(&func_vt, &align);
1170+ gaddrof();
1171+ gv(RC_R(0));
1172+ gen_sload(0, size);
1173+ }
1174+ else
1175+ gv(RC_IRET);
1176+ break;
1177+ case 1: {
1178+ CType type = func_vt;
1179+ mk_pointer(&type);
1180+ vset(&type, VT_LOCAL | VT_LVAL, func_vc);
1181+ indir();
1182+ vswap();
1183+ vstore();
1184+ break;
1185+ }
1186+ case 16:
1187+ if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
1188+ int j, sz, n = arm64_hfa(&vtop->type, &sz);
1189+ gaddrof();
1190+ gv(RC_R(0));
1191+ for (j = 0; j < n; j++)
1192+ o(0x3d400000 |
1193+ (sz & 16) << 19 | -(sz & 8) << 27 | (sz & 4) << 29 |
1194+ j | j << 10); // ldr ([sdq])(*),[x0,#(j * sz)]
1195+ }
1196+ else
1197+ gv(RC_FRET);
1198+ break;
1199+ default:
1200+ assert(0);
1201+ }
1202+}
1203+
1204+ST_FUNC void gfunc_epilog(void)
1205+{
1206+ if (loc) {
1207+ // Insert instructions to subtract size of stack frame from SP.
1208+ uint32_t *ptr =
1209+ (uint32_t *)(cur_text_section->data + arm64_func_sub_sp_offset);
1210+ uint64_t diff = (-loc + 15) & ~15;
1211+ if (!(diff >> 24)) {
1212+ if (diff & 0xfff) // sub sp,sp,#(diff & 0xfff)
1213+ ptr[0] = 0xd10003ff | (diff & 0xfff) << 10;
1214+ if (diff >> 12) // sub sp,sp,#(diff >> 12),lsl #12
1215+ ptr[1] = 0xd14003ff | (diff >> 12) << 10;
1216+ }
1217+ else {
1218+ // In this case we may subtract more than necessary,
1219+ // but always less than 17/16 of what we were aiming for.
1220+ int i = 0;
1221+ int j = 0;
1222+ while (diff >> 20) {
1223+ diff = (diff + 0xffff) >> 16;
1224+ ++i;
1225+ }
1226+ while (diff >> 16) {
1227+ diff = (diff + 1) >> 1;
1228+ ++j;
1229+ }
1230+ ptr[0] = 0xd2800010 | diff << 5 | i << 21;
1231+ // mov x16,#(diff),lsl #(16 * i)
1232+ ptr[1] = 0xcb3063ff | j << 10;
1233+ // sub sp,sp,x16,lsl #(j)
1234+ }
1235+ }
1236+ o(0x910003bf); // mov sp,x29
1237+ o(0xa8ce7bfd); // ldp x29,x30,[sp],#224
1238+
1239+ o(0xd65f03c0); // ret
1240+}
1241+
1242+// Generate forward branch to label:
1243+ST_FUNC int gjmp(int t)
1244+{
1245+ int r = ind;
1246+ o(t);
1247+ return r;
1248+}
1249+
1250+// Generate branch to known address:
1251+ST_FUNC void gjmp_addr(int a)
1252+{
1253+ assert(a - ind + 0x8000000 < 0x10000000);
1254+ o(0x14000000 | ((a - ind) >> 2 & 0x3ffffff));
1255+}
1256+
1257+ST_FUNC int gtst(int inv, int t)
1258+{
1259+ int bt = vtop->type.t & VT_BTYPE;
1260+ if (bt == VT_LDOUBLE) {
1261+ int a, b, f = fltr(gv(RC_FLOAT));
1262+ a = get_reg(RC_INT);
1263+ vpushi(0);
1264+ vtop[0].r = a;
1265+ b = get_reg(RC_INT);
1266+ a = intr(a);
1267+ b = intr(b);
1268+ o(0x4e083c00 | a | f << 5); // mov x(a),v(f).d[0]
1269+ o(0x4e183c00 | b | f << 5); // mov x(b),v(f).d[1]
1270+ o(0xaa000400 | a | a << 5 | b << 16); // orr x(a),x(a),x(b),lsl #1
1271+ o(0xb4000040 | a | !!inv << 24); // cbz/cbnz x(a),.+8
1272+ --vtop;
1273+ }
1274+ else if (bt == VT_FLOAT || bt == VT_DOUBLE) {
1275+ int a = fltr(gv(RC_FLOAT));
1276+ o(0x1e202008 | a << 5 | (bt != VT_FLOAT) << 22); // fcmp
1277+ o(0x54000040 | !!inv); // b.eq/b.ne .+8
1278+ }
1279+ else {
1280+ int ll = (bt == VT_PTR || bt == VT_LLONG);
1281+ int a = intr(gv(RC_INT));
1282+ o(0x34000040 | a | !!inv << 24 | ll << 31); // cbz/cbnz wA,.+8
1283+ }
1284+ --vtop;
1285+ return gjmp(t);
1286+}
1287+
1288+static void arm64_gen_opil(int op, int l)
1289+{
1290+ int x, a, b;
1291+ gv2(RC_INT, RC_INT);
1292+ assert(vtop[-1].r < VT_CONST && vtop[0].r < VT_CONST);
1293+ a = intr(vtop[-1].r);
1294+ b = intr(vtop[0].r);
1295+ vtop -= 2;
1296+ x = get_reg(RC_INT);
1297+ ++vtop;
1298+ vtop[0].r = x;
1299+ x = intr(x);
1300+
1301+ switch (op) {
1302+ case '%':
1303+ // Use x30 for quotient:
1304+ o(0x1ac00c00 | l << 31 | 30 | a << 5 | b << 16); // sdiv
1305+ o(0x1b008000 | l << 31 | x | 30 << 5 | b << 16 | a << 10); // msub
1306+ break;
1307+ case '&':
1308+ o(0x0a000000 | l << 31 | x | a << 5 | b << 16); // and
1309+ break;
1310+ case '*':
1311+ o(0x1b007c00 | l << 31 | x | a << 5 | b << 16); // mul
1312+ break;
1313+ case '+':
1314+ o(0x0b000000 | l << 31 | x | a << 5 | b << 16); // add
1315+ break;
1316+ case '-':
1317+ o(0x4b000000 | l << 31 | x | a << 5 | b << 16); // sub
1318+ break;
1319+ case '/':
1320+ o(0x1ac00c00 | l << 31 | x | a << 5 | b << 16); // sdiv
1321+ break;
1322+ case '^':
1323+ o(0x4a000000 | l << 31 | x | a << 5 | b << 16); // eor
1324+ break;
1325+ case '|':
1326+ o(0x2a000000 | l << 31 | x | a << 5 | b << 16); // orr
1327+ break;
1328+ case TOK_EQ:
1329+ o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp
1330+ o(0x1a9f17e0 | x); // cset wA,eq
1331+ break;
1332+ case TOK_GE:
1333+ o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp
1334+ o(0x1a9fb7e0 | x); // cset wA,ge
1335+ break;
1336+ case TOK_GT:
1337+ o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp
1338+ o(0x1a9fd7e0 | x); // cset wA,gt
1339+ break;
1340+ case TOK_LE:
1341+ o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp
1342+ o(0x1a9fc7e0 | x); // cset wA,le
1343+ break;
1344+ case TOK_LT:
1345+ o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp
1346+ o(0x1a9fa7e0 | x); // cset wA,lt
1347+ break;
1348+ case TOK_NE:
1349+ o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp
1350+ o(0x1a9f07e0 | x); // cset wA,ne
1351+ break;
1352+ case TOK_SAR:
1353+ o(0x1ac02800 | l << 31 | x | a << 5 | b << 16); // asr
1354+ break;
1355+ case TOK_SHL:
1356+ o(0x1ac02000 | l << 31 | x | a << 5 | b << 16); // lsl
1357+ break;
1358+ case TOK_SHR:
1359+ o(0x1ac02400 | l << 31 | x | a << 5 | b << 16); // lsr
1360+ break;
1361+ case TOK_UDIV:
1362+ case TOK_PDIV:
1363+ o(0x1ac00800 | l << 31 | x | a << 5 | b << 16); // udiv
1364+ break;
1365+ case TOK_UGE:
1366+ o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp
1367+ o(0x1a9f37e0 | x); // cset wA,cs
1368+ break;
1369+ case TOK_UGT:
1370+ o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp
1371+ o(0x1a9f97e0 | x); // cset wA,hi
1372+ break;
1373+ case TOK_ULT:
1374+ o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp
1375+ o(0x1a9f27e0 | x); // cset wA,cc
1376+ break;
1377+ case TOK_ULE:
1378+ o(0x6b00001f | l << 31 | a << 5 | b << 16); // cmp
1379+ o(0x1a9f87e0 | x); // cset wA,ls
1380+ break;
1381+ case TOK_UMOD:
1382+ // Use x30 for quotient:
1383+ o(0x1ac00800 | l << 31 | 30 | a << 5 | b << 16); // udiv
1384+ o(0x1b008000 | l << 31 | x | 30 << 5 | b << 16 | a << 10); // msub
1385+ break;
1386+ default:
1387+ assert(0);
1388+ }
1389+}
1390+
1391+ST_FUNC void gen_opi(int op)
1392+{
1393+ arm64_gen_opil(op, 0);
1394+}
1395+
1396+ST_FUNC void gen_opl(int op)
1397+{
1398+ arm64_gen_opil(op, 1);
1399+}
1400+
1401+ST_FUNC void gen_opf(int op)
1402+{
1403+ int x, a, b, dbl;
1404+
1405+ if (vtop[0].type.t == VT_LDOUBLE) {
1406+ CType type = vtop[0].type;
1407+ int func = 0;
1408+ int cond = -1;
1409+ switch (op) {
1410+ case '*': func = TOK___multf3; break;
1411+ case '+': func = TOK___addtf3; break;
1412+ case '-': func = TOK___subtf3; break;
1413+ case '/': func = TOK___divtf3; break;
1414+ case TOK_EQ: func = TOK___eqtf2; cond = 1; break;
1415+ case TOK_NE: func = TOK___netf2; cond = 0; break;
1416+ case TOK_LT: func = TOK___lttf2; cond = 10; break;
1417+ case TOK_GE: func = TOK___getf2; cond = 11; break;
1418+ case TOK_LE: func = TOK___letf2; cond = 12; break;
1419+ case TOK_GT: func = TOK___gttf2; cond = 13; break;
1420+ default: assert(0); break;
1421+ }
1422+ vpush_global_sym(&func_old_type, func);
1423+ vrott(3);
1424+ gfunc_call(2);
1425+ vpushi(0);
1426+ vtop->r = cond < 0 ? REG_FRET : REG_IRET;
1427+ if (cond < 0)
1428+ vtop->type = type;
1429+ else {
1430+ o(0x7100001f); // cmp w0,#0
1431+ o(0x1a9f07e0 | cond << 12); // cset w0,(cond)
1432+ }
1433+ return;
1434+ }
1435+
1436+ dbl = vtop[0].type.t != VT_FLOAT;
1437+ gv2(RC_FLOAT, RC_FLOAT);
1438+ assert(vtop[-1].r < VT_CONST && vtop[0].r < VT_CONST);
1439+ a = fltr(vtop[-1].r);
1440+ b = fltr(vtop[0].r);
1441+ vtop -= 2;
1442+ switch (op) {
1443+ case TOK_EQ: case TOK_NE:
1444+ case TOK_LT: case TOK_GE: case TOK_LE: case TOK_GT:
1445+ x = get_reg(RC_INT);
1446+ ++vtop;
1447+ vtop[0].r = x;
1448+ x = intr(x);
1449+ break;
1450+ default:
1451+ x = get_reg(RC_FLOAT);
1452+ ++vtop;
1453+ vtop[0].r = x;
1454+ x = fltr(x);
1455+ break;
1456+ }
1457+
1458+ switch (op) {
1459+ case '*':
1460+ o(0x1e200800 | dbl << 22 | x | a << 5 | b << 16); // fmul
1461+ break;
1462+ case '+':
1463+ o(0x1e202800 | dbl << 22 | x | a << 5 | b << 16); // fadd
1464+ break;
1465+ case '-':
1466+ o(0x1e203800 | dbl << 22 | x | a << 5 | b << 16); // fsub
1467+ break;
1468+ case '/':
1469+ o(0x1e201800 | dbl << 22 | x | a << 5 | b << 16); // fdiv
1470+ break;
1471+ case TOK_EQ:
1472+ o(0x1e202000 | dbl << 22 | a << 5 | b << 16); // fcmp
1473+ o(0x1a9f17e0 | x); // cset w(x),eq
1474+ break;
1475+ case TOK_GE:
1476+ o(0x1e202000 | dbl << 22 | a << 5 | b << 16); // fcmp
1477+ o(0x1a9fb7e0 | x); // cset w(x),ge
1478+ break;
1479+ case TOK_GT:
1480+ o(0x1e202000 | dbl << 22 | a << 5 | b << 16); // fcmp
1481+ o(0x1a9fd7e0 | x); // cset w(x),gt
1482+ break;
1483+ case TOK_LE:
1484+ o(0x1e202000 | dbl << 22 | a << 5 | b << 16); // fcmp
1485+ o(0x1a9f87e0 | x); // cset w(x),ls
1486+ break;
1487+ case TOK_LT:
1488+ o(0x1e202000 | dbl << 22 | a << 5 | b << 16); // fcmp
1489+ o(0x1a9f57e0 | x); // cset w(x),mi
1490+ break;
1491+ case TOK_NE:
1492+ o(0x1e202000 | dbl << 22 | a << 5 | b << 16); // fcmp
1493+ o(0x1a9f07e0 | x); // cset w(x),ne
1494+ break;
1495+ default:
1496+ assert(0);
1497+ }
1498+}
1499+
1500+// Generate sign extension from 32 to 64 bits:
1501+ST_FUNC void gen_cvt_sxtw(void)
1502+{
1503+ int r = intr(gv(RC_INT));
1504+ o(0x93407c00 | r | r << 5); // sxtw x(r),w(r)
1505+}
1506+
1507+ST_FUNC void gen_cvt_itof(int t)
1508+{
1509+ if (t == VT_LDOUBLE) {
1510+ int f = vtop->type.t;
1511+ int func = (f & VT_BTYPE) == VT_LLONG ?
1512+ (f & VT_UNSIGNED ? TOK___floatunditf : TOK___floatditf) :
1513+ (f & VT_UNSIGNED ? TOK___floatunsitf : TOK___floatsitf);
1514+ vpush_global_sym(&func_old_type, func);
1515+ vrott(2);
1516+ gfunc_call(1);
1517+ vpushi(0);
1518+ vtop->type.t = t;
1519+ vtop->r = REG_FRET;
1520+ return;
1521+ }
1522+ else {
1523+ int d, n = intr(gv(RC_INT));
1524+ int s = !(vtop->type.t & VT_UNSIGNED);
1525+ int l = ((vtop->type.t & VT_BTYPE) == VT_LLONG);
1526+ --vtop;
1527+ d = get_reg(RC_FLOAT);
1528+ ++vtop;
1529+ vtop[0].r = d;
1530+ o(0x1e220000 | !s << 16 | (t != VT_FLOAT) << 22 | fltr(d) |
1531+ l << 31 | n << 5); // [us]cvtf [sd](d),[wx](n)
1532+ }
1533+}
1534+
1535+ST_FUNC void gen_cvt_ftoi(int t)
1536+{
1537+ if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) {
1538+ int func = (t & VT_BTYPE) == VT_LLONG ?
1539+ (t & VT_UNSIGNED ? TOK___fixunstfdi : TOK___fixtfdi) :
1540+ (t & VT_UNSIGNED ? TOK___fixunstfsi : TOK___fixtfsi);
1541+ vpush_global_sym(&func_old_type, func);
1542+ vrott(2);
1543+ gfunc_call(1);
1544+ vpushi(0);
1545+ vtop->type.t = t;
1546+ vtop->r = REG_IRET;
1547+ return;
1548+ }
1549+ else {
1550+ int d, n = fltr(gv(RC_FLOAT));
1551+ int l = ((vtop->type.t & VT_BTYPE) != VT_FLOAT);
1552+ --vtop;
1553+ d = get_reg(RC_INT);
1554+ ++vtop;
1555+ vtop[0].r = d;
1556+ o(0x1e380000 |
1557+ !!(t & VT_UNSIGNED) << 16 |
1558+ ((t & VT_BTYPE) == VT_LLONG) << 31 | intr(d) |
1559+ l << 22 | n << 5); // fcvtz[su] [wx](d),[sd](n)
1560+ }
1561+}
1562+
1563+ST_FUNC void gen_cvt_ftof(int t)
1564+{
1565+ int f = vtop[0].type.t;
1566+ assert(t == VT_FLOAT || t == VT_DOUBLE || t == VT_LDOUBLE);
1567+ assert(f == VT_FLOAT || f == VT_DOUBLE || f == VT_LDOUBLE);
1568+ if (t == f)
1569+ return;
1570+
1571+ if (t == VT_LDOUBLE || f == VT_LDOUBLE) {
1572+ int func = (t == VT_LDOUBLE) ?
1573+ (f == VT_FLOAT ? TOK___extendsftf2 : TOK___extenddftf2) :
1574+ (t == VT_FLOAT ? TOK___trunctfsf2 : TOK___trunctfdf2);
1575+ vpush_global_sym(&func_old_type, func);
1576+ vrott(2);
1577+ gfunc_call(1);
1578+ vpushi(0);
1579+ vtop->type.t = t;
1580+ vtop->r = REG_FRET;
1581+ }
1582+ else {
1583+ int x, a;
1584+ gv(RC_FLOAT);
1585+ assert(vtop[0].r < VT_CONST);
1586+ a = fltr(vtop[0].r);
1587+ --vtop;
1588+ x = get_reg(RC_FLOAT);
1589+ ++vtop;
1590+ vtop[0].r = x;
1591+ x = fltr(x);
1592+
1593+ if (f == VT_FLOAT)
1594+ o(0x1e22c000 | x | a << 5); // fcvt d(x),s(a)
1595+ else
1596+ o(0x1e624000 | x | a << 5); // fcvt s(x),d(a)
1597+ }
1598+}
1599+
1600+ST_FUNC void ggoto(void)
1601+{
1602+ arm64_gen_bl_or_b(1);
1603+ --vtop;
1604+}
1605+
1606+ST_FUNC void gen_vla_sp_save(int addr) {
1607+ tcc_error("variable length arrays unsupported for this target");
1608+}
1609+
1610+ST_FUNC void gen_vla_sp_restore(int addr) {
1611+ tcc_error("variable length arrays unsupported for this target");
1612+}
1613+
1614+ST_FUNC void gen_vla_alloc(CType *type, int align) {
1615+ tcc_error("variable length arrays unsupported for this target");
1616+}
1617+
1618+/* end of A64 code generator */
1619+/*************************************************************/
1620+#endif
1621+/*************************************************************/
configure+6−0
@@ -99,6 +99,9 @@ classify_cpu () · 98 unmodified lines
9999 esac
100100 cpu="armv4l"
101101 ;;
102+ aarch64)
103+ cpu="aarch64"
104+ ;;
102105 alpha)
103106 cpu="alpha"
104107 ;;
@@ -435,6 +438,9 @@ elif test "$cpu" = "armv4l" ; then · 330 unmodified lines
435438 echo "ARCH=arm" >> config.mak
436439 echo "#define HOST_ARM 1" >> $TMPH
437440 echo "#define TCC_ARM_VERSION $cpuver" >> $TMPH
441+elif test "$cpu" = "aarch64" ; then
442+ echo "ARCH=arm64" >> config.mak
443+ echo "#define HOST_ARM64 1" >> $TMPH
438444 elif test "$cpu" = "powerpc" ; then
439445 echo "ARCH=ppc" >> config.mak
440446 echo "#define HOST_PPC 1" >> $TMPH
conftest.c+2−0
@@ -7,6 +7,8 @@ · 6 unmodified lines
77 # define TRIPLET_ARCH "x86_64"
88 #elif defined(__arm__)
99 # define TRIPLET_ARCH "arm"
10+#elif defined(__aarch64__)
11+# define TRIPLET_ARCH "aarch64"
1012 #else
1113 # define TRIPLET_ARCH "unknown"
1214 #endif
elf.h+112−0
@@ -2336,6 +2336,117 @@ typedef Elf32_Addr Elf32_Conflict; · 2335 unmodified lines
23362336 #define R_AARCH64_NONE 0 /* No relocation. */
23372337 #define R_AARCH64_ABS64 257 /* Direct 64 bit. */
23382338 #define R_AARCH64_ABS32 258 /* Direct 32 bit. */
2339+#define R_AARCH64_ABS16 259 /* Direct 16-bit. */
2340+#define R_AARCH64_PREL64 260 /* PC-relative 64-bit. */
2341+#define R_AARCH64_PREL32 261 /* PC-relative 32-bit. */
2342+#define R_AARCH64_PREL16 262 /* PC-relative 16-bit. */
2343+#define R_AARCH64_MOVW_UABS_G0 263 /* Dir. MOVZ imm. from bits 15:0. */
2344+#define R_AARCH64_MOVW_UABS_G0_NC 264 /* Likewise for MOVK; no check. */
2345+#define R_AARCH64_MOVW_UABS_G1 265 /* Dir. MOVZ imm. from bits 31:16. */
2346+#define R_AARCH64_MOVW_UABS_G1_NC 266 /* Likewise for MOVK; no check. */
2347+#define R_AARCH64_MOVW_UABS_G2 267 /* Dir. MOVZ imm. from bits 47:32. */
2348+#define R_AARCH64_MOVW_UABS_G2_NC 268 /* Likewise for MOVK; no check. */
2349+#define R_AARCH64_MOVW_UABS_G3 269 /* Dir. MOV{K,Z} imm. from 63:48. */
2350+#define R_AARCH64_MOVW_SABS_G0 270 /* Dir. MOV{N,Z} imm. from 15:0. */
2351+#define R_AARCH64_MOVW_SABS_G1 271 /* Dir. MOV{N,Z} imm. from 31:16. */
2352+#define R_AARCH64_MOVW_SABS_G2 272 /* Dir. MOV{N,Z} imm. from 47:32. */
2353+#define R_AARCH64_LD_PREL_LO19 273 /* PC-rel. LD imm. from bits 20:2. */
2354+#define R_AARCH64_ADR_PREL_LO21 274 /* PC-rel. ADR imm. from bits 20:0. */
2355+#define R_AARCH64_ADR_PREL_PG_HI21 275 /* Page-rel. ADRP imm. from 32:12. */
2356+#define R_AARCH64_ADR_PREL_PG_HI21_NC 276 /* Likewise; no overflow check. */
2357+#define R_AARCH64_ADD_ABS_LO12_NC 277 /* Dir. ADD imm. from bits 11:0. */
2358+#define R_AARCH64_LDST8_ABS_LO12_NC 278 /* Likewise for LD/ST; no check. */
2359+#define R_AARCH64_TSTBR14 279 /* PC-rel. TBZ/TBNZ imm. from 15:2. */
2360+#define R_AARCH64_CONDBR19 280 /* PC-rel. cond. br. imm. from 20:2. */
2361+#define R_AARCH64_JUMP26 282 /* PC-rel. B imm. from bits 27:2. */
2362+#define R_AARCH64_CALL26 283 /* Likewise for CALL. */
2363+#define R_AARCH64_LDST16_ABS_LO12_NC 284 /* Dir. ADD imm. from bits 11:1. */
2364+#define R_AARCH64_LDST32_ABS_LO12_NC 285 /* Likewise for bits 11:2. */
2365+#define R_AARCH64_LDST64_ABS_LO12_NC 286 /* Likewise for bits 11:3. */
2366+#define R_AARCH64_MOVW_PREL_G0 287 /* PC-rel. MOV{N,Z} imm. from 15:0. */
2367+#define R_AARCH64_MOVW_PREL_G0_NC 288 /* Likewise for MOVK; no check. */
2368+#define R_AARCH64_MOVW_PREL_G1 289 /* PC-rel. MOV{N,Z} imm. from 31:16. */
2369+#define R_AARCH64_MOVW_PREL_G1_NC 290 /* Likewise for MOVK; no check. */
2370+#define R_AARCH64_MOVW_PREL_G2 291 /* PC-rel. MOV{N,Z} imm. from 47:32. */
2371+#define R_AARCH64_MOVW_PREL_G2_NC 292 /* Likewise for MOVK; no check. */
2372+#define R_AARCH64_MOVW_PREL_G3 293 /* PC-rel. MOV{N,Z} imm. from 63:48. */
2373+#define R_AARCH64_LDST128_ABS_LO12_NC 299 /* Dir. ADD imm. from bits 11:4. */
2374+#define R_AARCH64_MOVW_GOTOFF_G0 300 /* GOT-rel. off. MOV{N,Z} imm. 15:0. */
2375+#define R_AARCH64_MOVW_GOTOFF_G0_NC 301 /* Likewise for MOVK; no check. */
2376+#define R_AARCH64_MOVW_GOTOFF_G1 302 /* GOT-rel. o. MOV{N,Z} imm. 31:16. */
2377+#define R_AARCH64_MOVW_GOTOFF_G1_NC 303 /* Likewise for MOVK; no check. */
2378+#define R_AARCH64_MOVW_GOTOFF_G2 304 /* GOT-rel. o. MOV{N,Z} imm. 47:32. */
2379+#define R_AARCH64_MOVW_GOTOFF_G2_NC 305 /* Likewise for MOVK; no check. */
2380+#define R_AARCH64_MOVW_GOTOFF_G3 306 /* GOT-rel. o. MOV{N,Z} imm. 63:48. */
2381+#define R_AARCH64_GOTREL64 307 /* GOT-relative 64-bit. */
2382+#define R_AARCH64_GOTREL32 308 /* GOT-relative 32-bit. */
2383+#define R_AARCH64_GOT_LD_PREL19 309 /* PC-rel. GOT off. load imm. 20:2. */
2384+#define R_AARCH64_LD64_GOTOFF_LO15 310 /* GOT-rel. off. LD/ST imm. 14:3. */
2385+#define R_AARCH64_ADR_GOT_PAGE 311 /* P-page-rel. GOT off. ADRP 32:12. */
2386+#define R_AARCH64_LD64_GOT_LO12_NC 312 /* Dir. GOT off. LD/ST imm. 11:3. */
2387+#define R_AARCH64_LD64_GOTPAGE_LO15 313 /* GOT-page-rel. GOT off. LD/ST 14:3 */
2388+#define R_AARCH64_TLSGD_ADR_PREL21 512 /* PC-relative ADR imm. 20:0. */
2389+#define R_AARCH64_TLSGD_ADR_PAGE21 513 /* page-rel. ADRP imm. 32:12. */
2390+#define R_AARCH64_TLSGD_ADD_LO12_NC 514 /* direct ADD imm. from 11:0. */
2391+#define R_AARCH64_TLSGD_MOVW_G1 515 /* GOT-rel. MOV{N,Z} 31:16. */
2392+#define R_AARCH64_TLSGD_MOVW_G0_NC 516 /* GOT-rel. MOVK imm. 15:0. */
2393+#define R_AARCH64_TLSLD_ADR_PREL21 517 /* Like 512; local dynamic model. */
2394+#define R_AARCH64_TLSLD_ADR_PAGE21 518 /* Like 513; local dynamic model. */
2395+#define R_AARCH64_TLSLD_ADD_LO12_NC 519 /* Like 514; local dynamic model. */
2396+#define R_AARCH64_TLSLD_MOVW_G1 520 /* Like 515; local dynamic model. */
2397+#define R_AARCH64_TLSLD_MOVW_G0_NC 521 /* Like 516; local dynamic model. */
2398+#define R_AARCH64_TLSLD_LD_PREL19 522 /* TLS PC-rel. load imm. 20:2. */
2399+#define R_AARCH64_TLSLD_MOVW_DTPREL_G2 523 /* TLS DTP-rel. MOV{N,Z} 47:32. */
2400+#define R_AARCH64_TLSLD_MOVW_DTPREL_G1 524 /* TLS DTP-rel. MOV{N,Z} 31:16. */
2401+#define R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC 525 /* Likewise; MOVK; no check. */
2402+#define R_AARCH64_TLSLD_MOVW_DTPREL_G0 526 /* TLS DTP-rel. MOV{N,Z} 15:0. */
2403+#define R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC 527 /* Likewise; MOVK; no check. */
2404+#define R_AARCH64_TLSLD_ADD_DTPREL_HI12 528 /* DTP-rel. ADD imm. from 23:12. */
2405+#define R_AARCH64_TLSLD_ADD_DTPREL_LO12 529 /* DTP-rel. ADD imm. from 11:0. */
2406+#define R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC 530 /* Likewise; no ovfl. check. */
2407+#define R_AARCH64_TLSLD_LDST8_DTPREL_LO12 531 /* DTP-rel. LD/ST imm. 11:0. */
2408+#define R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC 532 /* Likewise; no check. */
2409+#define R_AARCH64_TLSLD_LDST16_DTPREL_LO12 533 /* DTP-rel. LD/ST imm. 11:1. */
2410+#define R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC 534 /* Likewise; no check. */
2411+#define R_AARCH64_TLSLD_LDST32_DTPREL_LO12 535 /* DTP-rel. LD/ST imm. 11:2. */
2412+#define R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC 536 /* Likewise; no check. */
2413+#define R_AARCH64_TLSLD_LDST64_DTPREL_LO12 537 /* DTP-rel. LD/ST imm. 11:3. */
2414+#define R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC 538 /* Likewise; no check. */
2415+#define R_AARCH64_TLSIE_MOVW_GOTTPREL_G1 539 /* GOT-rel. MOV{N,Z} 31:16. */
2416+#define R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC 540 /* GOT-rel. MOVK 15:0. */
2417+#define R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 541 /* Page-rel. ADRP 32:12. */
2418+#define R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC 542 /* Direct LD off. 11:3. */
2419+#define R_AARCH64_TLSIE_LD_GOTTPREL_PREL19 543 /* PC-rel. load imm. 20:2. */
2420+#define R_AARCH64_TLSLE_MOVW_TPREL_G2 544 /* TLS TP-rel. MOV{N,Z} 47:32. */
2421+#define R_AARCH64_TLSLE_MOVW_TPREL_G1 545 /* TLS TP-rel. MOV{N,Z} 31:16. */
2422+#define R_AARCH64_TLSLE_MOVW_TPREL_G1_NC 546 /* Likewise; MOVK; no check. */
2423+#define R_AARCH64_TLSLE_MOVW_TPREL_G0 547 /* TLS TP-rel. MOV{N,Z} 15:0. */
2424+#define R_AARCH64_TLSLE_MOVW_TPREL_G0_NC 548 /* Likewise; MOVK; no check. */
2425+#define R_AARCH64_TLSLE_ADD_TPREL_HI12 549 /* TP-rel. ADD imm. 23:12. */
2426+#define R_AARCH64_TLSLE_ADD_TPREL_LO12 550 /* TP-rel. ADD imm. 11:0. */
2427+#define R_AARCH64_TLSLE_ADD_TPREL_LO12_NC 551 /* Likewise; no ovfl. check. */
2428+#define R_AARCH64_TLSLE_LDST8_TPREL_LO12 552 /* TP-rel. LD/ST off. 11:0. */
2429+#define R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC 553 /* Likewise; no ovfl. check. */
2430+#define R_AARCH64_TLSLE_LDST16_TPREL_LO12 554 /* TP-rel. LD/ST off. 11:1. */
2431+#define R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC 555 /* Likewise; no check. */
2432+#define R_AARCH64_TLSLE_LDST32_TPREL_LO12 556 /* TP-rel. LD/ST off. 11:2. */
2433+#define R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC 557 /* Likewise; no check. */
2434+#define R_AARCH64_TLSLE_LDST64_TPREL_LO12 558 /* TP-rel. LD/ST off. 11:3. */
2435+#define R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC 559 /* Likewise; no check. */
2436+#define R_AARCH64_TLSDESC_LD_PREL19 560 /* PC-rel. load immediate 20:2. */
2437+#define R_AARCH64_TLSDESC_ADR_PREL21 561 /* PC-rel. ADR immediate 20:0. */
2438+#define R_AARCH64_TLSDESC_ADR_PAGE21 562 /* Page-rel. ADRP imm. 32:12. */
2439+#define R_AARCH64_TLSDESC_LD64_LO12 563 /* Direct LD off. from 11:3. */
2440+#define R_AARCH64_TLSDESC_ADD_LO12 564 /* Direct ADD imm. from 11:0. */
2441+#define R_AARCH64_TLSDESC_OFF_G1 565 /* GOT-rel. MOV{N,Z} imm. 31:16. */
2442+#define R_AARCH64_TLSDESC_OFF_G0_NC 566 /* GOT-rel. MOVK imm. 15:0; no ck. */
2443+#define R_AARCH64_TLSDESC_LDR 567 /* Relax LDR. */
2444+#define R_AARCH64_TLSDESC_ADD 568 /* Relax ADD. */
2445+#define R_AARCH64_TLSDESC_CALL 569 /* Relax BLR. */
2446+#define R_AARCH64_TLSLE_LDST128_TPREL_LO12 570 /* TP-rel. LD/ST off. 11:4. */
2447+#define R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC 571 /* Likewise; no check. */
2448+#define R_AARCH64_TLSLD_LDST128_DTPREL_LO12 572 /* DTP-rel. LD/ST imm. 11:4. */
2449+#define R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC 573 /* Likewise; no check. */
23392450 #define R_AARCH64_COPY 1024 /* Copy symbol at runtime. */
23402451 #define R_AARCH64_GLOB_DAT 1025 /* Create GOT entry. */
23412452 #define R_AARCH64_JUMP_SLOT 1026 /* Create PLT entry. */
@@ -2344,6 +2455,7 @@ typedef Elf32_Addr Elf32_Conflict; · 2 unmodified lines
23442455 #define R_AARCH64_TLS_DTPREL64 1029 /* Module-relative offset, 64 bit. */
23452456 #define R_AARCH64_TLS_TPREL64 1030 /* TP-relative offset, 64 bit. */
23462457 #define R_AARCH64_TLSDESC 1031 /* TLS Descriptor. */
2458+#define R_AARCH64_IRELATIVE 1032 /* STT_GNU_IFUNC relocation. */
23472459
23482460 /* ARM relocs. */
23492461
include/stdarg.h+13−0
@@ -46,6 +46,19 @@ typedef char *va_list; · 45 unmodified lines
4646 #define va_copy(dest, src) (dest) = (src)
4747 #define va_end(ap)
4848
49+#elif defined(__aarch64__)
50+typedef struct {
51+ void *__stack;
52+ void *__gr_top;
53+ void *__vr_top;
54+ int __gr_offs;
55+ int __vr_offs;
56+} va_list;
57+#define va_start(ap, last) __va_start(ap, last)
58+#define va_arg(ap, type) __va_arg(ap, type)
59+#define va_end(ap)
60+#define va_copy(dest, src) ((dest) = (src))
61+
4962 #else /* __i386__ */
5063 typedef char *va_list;
5164 /* only correct for i386 */
lib/Makefile+12−0
@@ -28,6 +28,11 @@ ifndef TARGET # native library · 27 unmodified lines
2828 ifeq ($(ARCH),arm)
2929 TARGET = arm
3030 XCC = $(CC)
31+ else
32+ ifeq ($(ARCH),arm64)
33+ TARGET = arm64
34+ else
35+ endif
3136 endif
3237 endif
3338 endif
@@ -49,6 +54,7 @@ X86_64_O = libtcc1.o alloca86_64.o · 15 unmodified lines
4954 ARM_O = libtcc1.o armeabi.o alloca-arm.o
5055 WIN32_O = $(I386_O) crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o
5156 WIN64_O = $(X86_64_O) crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o
57+ARM64_O = lib-arm64.o
5258
5359 # build TCC runtime library to contain PIC code, so it can be linked
5460 # into shared libraries
@@ -86,6 +92,11 @@ ifeq "$(TARGET)" "arm" · 31 unmodified lines
8692 OBJ = $(addprefix $(DIR)/,$(ARM_O))
8793 TGT = -DTCC_TARGET_ARM
8894 XCC ?= $(TCC) -B$(TOP)
95+else
96+ifeq "$(TARGET)" "arm64"
97+ OBJ = $(addprefix $(DIR)/,$(ARM64_O))
98+ TGT = -DTCC_TARGET_ARM64
99+ XCC ?= $(TCC) -B$(TOP)
89100 else
90101 $(error libtcc1.a not supported on target '$(TARGET)')
91102 endif
@@ -93,6 +104,7 @@ endif · 1 unmodified line
93104 endif
94105 endif
95106 endif
107+endif
96108
97109 XFLAGS = $(CPPFLAGS) $(CFLAGS) $(PICFLAGS) $(TGT)
98110
lib/lib-arm64.c+652−0
@@ -0,0 +1,652 @@
1+/*
2+ * TCC runtime library for arm64.
3+ *
4+ * Copyright (c) 2015 Edmund Grimley Evans
5+ *
6+ * Copying and distribution of this file, with or without modification,
7+ * are permitted in any medium without royalty provided the copyright
8+ * notice and this notice are preserved. This file is offered as-is,
9+ * without any warranty.
10+ */
11+
12+#include <stdint.h>
13+#include <string.h>
14+
15+void __clear_cache(char *beg, char *end)
16+{
17+#warning __clear_cache not yet implemented
18+}
19+
20+typedef struct {
21+ uint64_t x0, x1;
22+} u128_t;
23+
24+static long double f3_zero(int sgn)
25+{
26+ long double f;
27+ u128_t x = { 0, (uint64_t)sgn << 63 };
28+ memcpy(&f, &x, 16);
29+ return f;
30+}
31+
32+static long double f3_infinity(int sgn)
33+{
34+ long double f;
35+ u128_t x = { 0, (uint64_t)sgn << 63 | 0x7fff000000000000 };
36+ memcpy(&f, &x, 16);
37+ return f;
38+}
39+
40+static long double f3_NaN(void)
41+{
42+ long double f;
43+#if 0
44+ // ARM's default NaN usually has just the top fraction bit set:
45+ u128_t x = { 0, 0x7fff800000000000 };
46+#else
47+ // GCC's library sets all fraction bits:
48+ u128_t x = { -1, 0x7fffffffffffffff };
49+#endif
50+ memcpy(&f, &x, 16);
51+ return f;
52+}
53+
54+static int fp3_convert_NaN(long double *f, int sgn, u128_t mnt)
55+{
56+ u128_t x = { mnt.x0,
57+ mnt.x1 | 0x7fff800000000000 | (uint64_t)sgn << 63 };
58+ memcpy(f, &x, 16);
59+ return 1;
60+}
61+
62+static int fp3_detect_NaNs(long double *f,
63+ int a_sgn, int a_exp, u128_t a,
64+ int b_sgn, int b_exp, u128_t b)
65+{
66+ // Detect signalling NaNs:
67+ if (a_exp == 32767 && (a.x0 | a.x1 << 16) && !(a.x1 >> 47 & 1))
68+ return fp3_convert_NaN(f, a_sgn, a);
69+ if (b_exp == 32767 && (b.x0 | b.x1 << 16) && !(b.x1 >> 47 & 1))
70+ return fp3_convert_NaN(f, b_sgn, b);
71+
72+ // Detect quiet NaNs:
73+ if (a_exp == 32767 && (a.x0 | a.x1 << 16))
74+ return fp3_convert_NaN(f, a_sgn, a);
75+ if (b_exp == 32767 && (b.x0 | b.x1 << 16))
76+ return fp3_convert_NaN(f, b_sgn, b);
77+
78+ return 0;
79+}
80+
81+static void f3_unpack(int *sgn, int32_t *exp, u128_t *mnt, long double f)
82+{
83+ u128_t x;
84+ memcpy(&x, &f, 16);
85+ *sgn = x.x1 >> 63;
86+ *exp = x.x1 >> 48 & 32767;
87+ x.x1 = x.x1 << 16 >> 16;
88+ if (*exp)
89+ x.x1 |= (uint64_t)1 << 48;
90+ else
91+ *exp = 1;
92+ *mnt = x;
93+}
94+
95+static u128_t f3_normalise(int32_t *exp, u128_t mnt)
96+{
97+ int sh;
98+ if (!(mnt.x0 | mnt.x1))
99+ return mnt;
100+ if (!mnt.x1) {
101+ mnt.x1 = mnt.x0;
102+ mnt.x0 = 0;
103+ *exp -= 64;
104+ }
105+ for (sh = 32; sh; sh >>= 1) {
106+ if (!(mnt.x1 >> (64 - sh))) {
107+ mnt.x1 = mnt.x1 << sh | mnt.x0 >> (64 - sh);
108+ mnt.x0 = mnt.x0 << sh;
109+ *exp -= sh;
110+ }
111+ }
112+ return mnt;
113+}
114+
115+static u128_t f3_sticky_shift(int32_t sh, u128_t x)
116+{
117+ if (sh >= 128) {
118+ x.x0 = !!(x.x0 | x.x1);
119+ x.x1 = 0;
120+ return x;
121+ }
122+ if (sh >= 64) {
123+ x.x0 = x.x1 | !!x.x0;
124+ x.x1 = 0;
125+ sh -= 64;
126+ }
127+ if (sh > 0) {
128+ x.x0 = x.x0 >> sh | x.x1 << (64 - sh) | !!(x.x0 << (64 - sh));
129+ x.x1 = x.x1 >> sh;
130+ }
131+ return x;
132+}
133+
134+static long double f3_round(int sgn, int32_t exp, u128_t x)
135+{
136+ long double f;
137+ int error;
138+
139+ if (exp > 0) {
140+ x = f3_sticky_shift(13, x);
141+ }
142+ else {
143+ x = f3_sticky_shift(14 - exp, x);
144+ exp = 0;
145+ }
146+
147+ error = x.x0 & 3;
148+ x.x0 = x.x0 >> 2 | x.x1 << 62;
149+ x.x1 = x.x1 >> 2;
150+
151+ if (error == 3 || ((error == 2) & (x.x0 & 1))) {
152+ if (!++x.x0) {
153+ ++x.x1;
154+ if (x.x1 == (uint64_t)1 << 48)
155+ exp = 1;
156+ else if (x.x1 == (uint64_t)1 << 49) {
157+ ++exp;
158+ x.x0 = x.x0 >> 1 | x.x1 << 63;
159+ x.x1 = x.x1 >> 1;
160+ }
161+ }
162+ }
163+
164+ if (exp >= 32767)
165+ return f3_infinity(sgn);
166+
167+ x.x1 = x.x1 << 16 >> 16 | (uint64_t)exp << 48 | (uint64_t)sgn << 63;
168+ memcpy(&f, &x, 16);
169+ return f;
170+}
171+
172+static long double f3_add(long double fa, long double fb, int neg)
173+{
174+ u128_t a, b, x;
175+ int32_t a_exp, b_exp, x_exp;
176+ int a_sgn, b_sgn, x_sgn;
177+ long double fx;
178+
179+ f3_unpack(&a_sgn, &a_exp, &a, fa);
180+ f3_unpack(&b_sgn, &b_exp, &b, fb);
181+
182+ if (fp3_detect_NaNs(&fx, a_sgn, a_exp, a, b_sgn, b_exp, b))
183+ return fx;
184+
185+ b_sgn ^= neg;
186+
187+ // Handle infinities and zeroes:
188+ if (a_exp == 32767 && b_exp == 32767 && a_sgn != b_sgn)
189+ return f3_NaN();
190+ if (a_exp == 32767)
191+ return f3_infinity(a_sgn);
192+ if (b_exp == 32767)
193+ return f3_infinity(b_sgn);
194+ if (!(a.x0 | a.x1 | b.x0 | b.x1))
195+ return f3_zero(a_sgn & b_sgn);
196+
197+ a.x1 = a.x1 << 3 | a.x0 >> 61;
198+ a.x0 = a.x0 << 3;
199+ b.x1 = b.x1 << 3 | b.x0 >> 61;
200+ b.x0 = b.x0 << 3;
201+
202+ if (a_exp <= b_exp) {
203+ a = f3_sticky_shift(b_exp - a_exp, a);
204+ a_exp = b_exp;
205+ }
206+ else {
207+ b = f3_sticky_shift(a_exp - b_exp, b);
208+ b_exp = a_exp;
209+ }
210+
211+ x_sgn = a_sgn;
212+ x_exp = a_exp;
213+ if (a_sgn == b_sgn) {
214+ x.x0 = a.x0 + b.x0;
215+ x.x1 = a.x1 + b.x1 + (x.x0 < a.x0);
216+ }
217+ else {
218+ x.x0 = a.x0 - b.x0;
219+ x.x1 = a.x1 - b.x1 - (x.x0 > a.x0);
220+ if (x.x1 >> 63) {
221+ x_sgn ^= 1;
222+ x.x0 = -x.x0;
223+ x.x1 = -x.x1 - !!x.x0;
224+ }
225+ }
226+
227+ if (!(x.x0 | x.x1))
228+ return f3_zero(0);
229+
230+ x = f3_normalise(&x_exp, x);
231+
232+ return f3_round(x_sgn, x_exp + 12, x);
233+}
234+
235+long double __addtf3(long double a, long double b)
236+{
237+ return f3_add(a, b, 0);
238+}
239+
240+long double __subtf3(long double a, long double b)
241+{
242+ return f3_add(a, b, 1);
243+}
244+
245+long double __multf3(long double fa, long double fb)
246+{
247+ u128_t a, b, x;
248+ int32_t a_exp, b_exp, x_exp;
249+ int a_sgn, b_sgn, x_sgn;
250+ long double fx;
251+
252+ f3_unpack(&a_sgn, &a_exp, &a, fa);
253+ f3_unpack(&b_sgn, &b_exp, &b, fb);
254+
255+ if (fp3_detect_NaNs(&fx, a_sgn, a_exp, a, b_sgn, b_exp, b))
256+ return fx;
257+
258+ // Handle infinities and zeroes:
259+ if ((a_exp == 32767 && !(b.x0 | b.x1)) ||
260+ (b_exp == 32767 && !(a.x0 | a.x1)))
261+ return f3_NaN();
262+ if (a_exp == 32767 || b_exp == 32767)
263+ return f3_infinity(a_sgn ^ b_sgn);
264+ if (!(a.x0 | a.x1) || !(b.x0 | b.x1))
265+ return f3_zero(a_sgn ^ b_sgn);
266+
267+ a = f3_normalise(&a_exp, a);
268+ b = f3_normalise(&b_exp, b);
269+
270+ x_sgn = a_sgn ^ b_sgn;
271+ x_exp = a_exp + b_exp - 16352;
272+
273+ {
274+ // Convert to base (1 << 30), discarding bottom 6 bits, which are zero,
275+ // so there are (32, 30, 30, 30) bits in (a3, a2, a1, a0):
276+ uint64_t a0 = a.x0 << 28 >> 34;
277+ uint64_t b0 = b.x0 << 28 >> 34;
278+ uint64_t a1 = a.x0 >> 36 | a.x1 << 62 >> 34;
279+ uint64_t b1 = b.x0 >> 36 | b.x1 << 62 >> 34;
280+ uint64_t a2 = a.x1 << 32 >> 34;
281+ uint64_t b2 = b.x1 << 32 >> 34;
282+ uint64_t a3 = a.x1 >> 32;
283+ uint64_t b3 = b.x1 >> 32;
284+ // Use 16 small multiplications and additions that do not overflow:
285+ uint64_t x0 = a0 * b0;
286+ uint64_t x1 = (x0 >> 30) + a0 * b1 + a1 * b0;
287+ uint64_t x2 = (x1 >> 30) + a0 * b2 + a1 * b1 + a2 * b0;
288+ uint64_t x3 = (x2 >> 30) + a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0;
289+ uint64_t x4 = (x3 >> 30) + a1 * b3 + a2 * b2 + a3 * b1;
290+ uint64_t x5 = (x4 >> 30) + a2 * b3 + a3 * b2;
291+ uint64_t x6 = (x5 >> 30) + a3 * b3;
292+ // We now have (64, 30, 30, ...) bits in (x6, x5, x4, ...).
293+ // Take the top 128 bits, setting bottom bit if any lower bits were set:
294+ uint64_t y0 = (x5 << 34 | x4 << 34 >> 30 | x3 << 34 >> 60 |
295+ !!(x3 << 38 | (x2 | x1 | x0) << 34));
296+ uint64_t y1 = x6;
297+ // Top bit may be zero. Renormalise:
298+ if (!(y1 >> 63)) {
299+ y1 = y1 << 1 | y0 >> 63;
300+ y0 = y0 << 1;
301+ --x_exp;
302+ }
303+ x.x0 = y0;
304+ x.x1 = y1;
305+ }
306+
307+ return f3_round(x_sgn, x_exp, x);
308+}
309+
310+long double __divtf3(long double fa, long double fb)
311+{
312+ u128_t a, b, x;
313+ int32_t a_exp, b_exp, x_exp;
314+ int a_sgn, b_sgn, x_sgn, i;
315+ long double fx;
316+
317+ f3_unpack(&a_sgn, &a_exp, &a, fa);
318+ f3_unpack(&b_sgn, &b_exp, &b, fb);
319+
320+ if (fp3_detect_NaNs(&fx, a_sgn, a_exp, a, b_sgn, b_exp, b))
321+ return fx;
322+
323+ // Handle infinities and zeroes:
324+ if ((a_exp == 32767 && b_exp == 32767) ||
325+ (!(a.x0 | a.x1) && !(b.x0 | b.x1)))
326+ return f3_NaN();
327+ if (a_exp == 32767 || !(b.x0 | b.x1))
328+ return f3_infinity(a_sgn ^ b_sgn);
329+ if (!(a.x0 | a.x1) || b_exp == 32767)
330+ return f3_zero(a_sgn ^ b_sgn);
331+
332+ a = f3_normalise(&a_exp, a);
333+ b = f3_normalise(&b_exp, b);
334+
335+ x_sgn = a_sgn ^ b_sgn;
336+ x_exp = a_exp - b_exp + 16395;
337+
338+ a.x0 = a.x0 >> 1 | a.x1 << 63;
339+ a.x1 = a.x1 >> 1;
340+ b.x0 = b.x0 >> 1 | b.x1 << 63;
341+ b.x1 = b.x1 >> 1;
342+ x.x0 = 0;
343+ x.x1 = 0;
344+ for (i = 0; i < 116; i++) {
345+ x.x1 = x.x1 << 1 | x.x0 >> 63;
346+ x.x0 = x.x0 << 1;
347+ if (a.x1 > b.x1 || (a.x1 == b.x1 && a.x0 >= b.x0)) {
348+ a.x1 = a.x1 - b.x1 - (a.x0 < b.x0);
349+ a.x0 = a.x0 - b.x0;
350+ x.x0 |= 1;
351+ }
352+ a.x1 = a.x1 << 1 | a.x0 >> 63;
353+ a.x0 = a.x0 << 1;
354+ }
355+ x.x0 |= !!(a.x0 | a.x1);
356+
357+ x = f3_normalise(&x_exp, x);
358+
359+ return f3_round(x_sgn, x_exp, x);
360+}
361+
362+long double __extendsftf2(float f)
363+{
364+ long double fx;
365+ u128_t x;
366+ uint32_t a;
367+ uint64_t aa;
368+ memcpy(&a, &f, 4);
369+ aa = a;
370+ x.x0 = 0;
371+ if (!(a << 1))
372+ x.x1 = aa << 32;
373+ else if (a << 1 >> 24 == 255)
374+ x.x1 = (0x7fff000000000000 | aa >> 31 << 63 | aa << 41 >> 16 |
375+ (uint64_t)!!(a << 9) << 47);
376+ else
377+ x.x1 = (aa >> 31 << 63 | ((aa >> 23 & 255) + 16256) << 48 |
378+ aa << 41 >> 16);
379+ memcpy(&fx, &x, 16);
380+ return fx;
381+}
382+
383+long double __extenddftf2(double f)
384+{
385+ long double fx;
386+ u128_t x;
387+ uint64_t a;
388+ memcpy(&a, &f, 8);
389+ x.x0 = a << 60;
390+ if (!(a << 1))
391+ x.x1 = a;
392+ else if (a << 1 >> 53 == 2047)
393+ x.x1 = (0x7fff000000000000 | a >> 63 << 63 | a << 12 >> 16 |
394+ (uint64_t)!!(a << 12) << 47);
395+ else
396+ x.x1 = a >> 63 << 63 | ((a >> 52 & 2047) + 15360) << 48 | a << 12 >> 16;
397+ memcpy(&fx, &x, 16);
398+ return fx;
399+}
400+
401+float __trunctfsf2(long double f)
402+{
403+ u128_t mnt;
404+ int32_t exp;
405+ int sgn;
406+ uint32_t x;
407+ float fx;
408+
409+ f3_unpack(&sgn, &exp, &mnt, f);
410+
411+ if (exp == 32767 && (mnt.x0 | mnt.x1 << 16))
412+ x = 0x7fc00000 | (uint32_t)sgn << 31 | (mnt.x1 >> 25 & 0x007fffff);
413+ else if (exp > 16510)
414+ x = 0x7f800000 | (uint32_t)sgn << 31;
415+ else if (exp < 16233)
416+ x = (uint32_t)sgn << 31;
417+ else {
418+ exp -= 16257;
419+ x = mnt.x1 >> 23 | !!(mnt.x0 | mnt.x1 << 41);
420+ if (exp < 0) {
421+ x = x >> -exp | !!(x << (32 + exp));
422+ exp = 0;
423+ }
424+ if ((x & 3) == 3 || (x & 7) == 6)
425+ x += 4;
426+ x = ((x >> 2) + (exp << 23)) | (uint32_t)sgn << 31;
427+ }
428+ memcpy(&fx, &x, 4);
429+ return fx;
430+}
431+
432+double __trunctfdf2(long double f)
433+{
434+ u128_t mnt;
435+ int32_t exp;
436+ int sgn;
437+ uint64_t x;
438+ double fx;
439+
440+ f3_unpack(&sgn, &exp, &mnt, f);
441+
442+ if (exp == 32767 && (mnt.x0 | mnt.x1 << 16))
443+ x = (0x7ff8000000000000 | (uint64_t)sgn << 63 |
444+ mnt.x1 << 16 >> 12 | mnt.x0 >> 60);
445+ else if (exp > 17406)
446+ x = 0x7ff0000000000000 | (uint64_t)sgn << 63;
447+ else if (exp < 15308)
448+ x = (uint64_t)sgn << 63;
449+ else {
450+ exp -= 15361;
451+ x = mnt.x1 << 6 | mnt.x0 >> 58 | !!(mnt.x0 << 6);
452+ if (exp < 0) {
453+ x = x >> -exp | !!(x << (64 + exp));
454+ exp = 0;
455+ }
456+ if ((x & 3) == 3 || (x & 7) == 6)
457+ x += 4;
458+ x = ((x >> 2) + ((uint64_t)exp << 52)) | (uint64_t)sgn << 63;
459+ }
460+ memcpy(&fx, &x, 8);
461+ return fx;
462+}
463+
464+int32_t __fixtfsi(long double fa)
465+{
466+ u128_t a;
467+ int32_t a_exp;
468+ int a_sgn;
469+ int32_t x;
470+ f3_unpack(&a_sgn, &a_exp, &a, fa);
471+ if (a_exp < 16369)
472+ return 0;
473+ if (a_exp > 16413)
474+ return a_sgn ? -0x80000000 : 0x7fffffff;
475+ x = a.x1 >> (16431 - a_exp);
476+ return a_sgn ? -x : x;
477+}
478+
479+int64_t __fixtfdi(long double fa)
480+{
481+ u128_t a;
482+ int32_t a_exp;
483+ int a_sgn;
484+ int64_t x;
485+ f3_unpack(&a_sgn, &a_exp, &a, fa);
486+ if (a_exp < 16383)
487+ return 0;
488+ if (a_exp > 16445)
489+ return a_sgn ? -0x8000000000000000 : 0x7fffffffffffffff;
490+ x = (a.x1 << 15 | a.x0 >> 49) >> (16446 - a_exp);
491+ return a_sgn ? -x : x;
492+}
493+
494+uint32_t __fixunstfsi(long double fa)
495+{
496+ u128_t a;
497+ int32_t a_exp;
498+ int a_sgn;
499+ f3_unpack(&a_sgn, &a_exp, &a, fa);
500+ if (a_sgn || a_exp < 16369)
501+ return 0;
502+ if (a_exp > 16414)
503+ return -1;
504+ return a.x1 >> (16431 - a_exp);
505+}
506+
507+uint64_t __fixunstfdi(long double fa)
508+{
509+ u128_t a;
510+ int32_t a_exp;
511+ int a_sgn;
512+ f3_unpack(&a_sgn, &a_exp, &a, fa);
513+ if (a_sgn || a_exp < 16383)
514+ return 0;
515+ if (a_exp > 16446)
516+ return -1;
517+ return (a.x1 << 15 | a.x0 >> 49) >> (16446 - a_exp);
518+}
519+
520+long double __floatsitf(int32_t a)
521+{
522+ int sgn = 0;
523+ int exp = 16414;
524+ uint32_t mnt = a;
525+ u128_t x = { 0, 0 };
526+ long double f;
527+ int i;
528+ if (a) {
529+ if (a < 0) {
530+ sgn = 1;
531+ mnt = -mnt;
532+ }
533+ for (i = 16; i; i >>= 1)
534+ if (!(mnt >> (32 - i))) {
535+ mnt <<= i;
536+ exp -= i;
537+ }
538+ x.x1 = ((uint64_t)sgn << 63 | (uint64_t)exp << 48 |
539+ (uint64_t)(mnt << 1) << 16);
540+ }
541+ memcpy(&f, &x, 16);
542+ return f;
543+}
544+
545+long double __floatditf(int64_t a)
546+{
547+ int sgn = 0;
548+ int exp = 16446;
549+ uint64_t mnt = a;
550+ u128_t x = { 0, 0 };
551+ long double f;
552+ int i;
553+ if (a) {
554+ if (a < 0) {
555+ sgn = 1;
556+ mnt = -mnt;
557+ }
558+ for (i = 32; i; i >>= 1)
559+ if (!(mnt >> (64 - i))) {
560+ mnt <<= i;
561+ exp -= i;
562+ }
563+ x.x0 = mnt << 49;
564+ x.x1 = (uint64_t)sgn << 63 | (uint64_t)exp << 48 | mnt << 1 >> 16;
565+ }
566+ memcpy(&f, &x, 16);
567+ return f;
568+}
569+
570+long double __floatunsitf(uint32_t a)
571+{
572+ int exp = 16414;
573+ uint32_t mnt = a;
574+ u128_t x = { 0, 0 };
575+ long double f;
576+ int i;
577+ if (a) {
578+ for (i = 16; i; i >>= 1)
579+ if (!(mnt >> (32 - i))) {
580+ mnt <<= i;
581+ exp -= i;
582+ }
583+ x.x1 = (uint64_t)exp << 48 | (uint64_t)(mnt << 1) << 16;
584+ }
585+ memcpy(&f, &x, 16);
586+ return f;
587+}
588+
589+long double __floatunditf(uint64_t a)
590+{
591+ int exp = 16446;
592+ uint64_t mnt = a;
593+ u128_t x = { 0, 0 };
594+ long double f;
595+ int i;
596+ if (a) {
597+ for (i = 32; i; i >>= 1)
598+ if (!(mnt >> (64 - i))) {
599+ mnt <<= i;
600+ exp -= i;
601+ }
602+ x.x0 = mnt << 49;
603+ x.x1 = (uint64_t)exp << 48 | mnt << 1 >> 16;
604+ }
605+ memcpy(&f, &x, 16);
606+ return f;
607+}
608+
609+static int f3_cmp(long double fa, long double fb)
610+{
611+ u128_t a, b;
612+ memcpy(&a, &fa, 16);
613+ memcpy(&b, &fb, 16);
614+ return (!(a.x0 | a.x1 << 1 | b.x0 | b.x1 << 1) ? 0 :
615+ ((a.x1 << 1 >> 49 == 0x7fff && (a.x0 | a.x1 << 16)) ||
616+ (b.x1 << 1 >> 49 == 0x7fff && (b.x0 | b.x1 << 16))) ? 2 :
617+ a.x1 >> 63 != b.x1 >> 63 ? (int)(b.x1 >> 63) - (int)(a.x1 >> 63) :
618+ a.x1 < b.x1 ? (int)(a.x1 >> 63 << 1) - 1 :
619+ a.x1 > b.x1 ? 1 - (int)(a.x1 >> 63 << 1) :
620+ a.x0 < b.x0 ? (int)(a.x1 >> 63 << 1) - 1 :
621+ b.x0 < a.x0 ? 1 - (int)(a.x1 >> 63 << 1) : 0);
622+}
623+
624+int __eqtf2(long double a, long double b)
625+{
626+ return !!f3_cmp(a, b);
627+}
628+
629+int __netf2(long double a, long double b)
630+{
631+ return !!f3_cmp(a, b);
632+}
633+
634+int __lttf2(long double a, long double b)
635+{
636+ return f3_cmp(a, b);
637+}
638+
639+int __letf2(long double a, long double b)
640+{
641+ return f3_cmp(a, b);
642+}
643+
644+int __gttf2(long double a, long double b)
645+{
646+ return -f3_cmp(b, a);
647+}
648+
649+int __getf2(long double a, long double b)
650+{
651+ return -f3_cmp(b, a);
652+}
lib/testfp.c+510−0
@@ -0,0 +1,510 @@
1+/*
2+ * Test 128-bit floating-point arithmetic on arm64:
3+ * build with two different compilers and compare the output.
4+ *
5+ * Copyright (c) 2015 Edmund Grimley Evans
6+ *
7+ * Copying and distribution of this file, with or without modification,
8+ * are permitted in any medium without royalty provided the copyright
9+ * notice and this notice are preserved. This file is offered as-is,
10+ * without any warranty.
11+ */
12+
13+#include <stdint.h>
14+#include <stdio.h>
15+#include <stdlib.h>
16+#include <string.h>
17+
18+#define check(x) ((x) ? (void)0 : check_fail(#x, __FILE__, __LINE__))
19+
20+void check_fail(const char *assertion, const char *file, unsigned int line)
21+{
22+ printf("%s:%d: Check (%s) failed.", file, line, assertion);
23+ exit(1);
24+}
25+
26+typedef struct {
27+ unsigned long long x0, x1;
28+} u128_t;
29+
30+float copy_fi(uint32_t x)
31+{
32+ float f;
33+ memcpy(&f, &x, 4);
34+ return f;
35+}
36+
37+double copy_di(uint64_t x)
38+{
39+ double f;
40+ memcpy(&f, &x, 8);
41+ return f;
42+}
43+
44+long double copy_ldi(u128_t x)
45+{
46+ long double f;
47+ memcpy(&f, &x, 16);
48+ return f;
49+}
50+
51+uint32_t copy_if(float f)
52+{
53+ uint32_t x;
54+ memcpy(&x, &f, 4);
55+ return x;
56+}
57+
58+uint64_t copy_id(double f)
59+{
60+ uint64_t x;
61+ memcpy(&x, &f, 8);
62+ return x;
63+}
64+
65+u128_t copy_ild(long double f)
66+{
67+ u128_t x;
68+ memcpy(&x, &f, 16);
69+ return x;
70+}
71+
72+long double make(int sgn, int exp, uint64_t high, uint64_t low)
73+{
74+ u128_t x = { low,
75+ (0x0000ffffffffffff & high) |
76+ (0x7fff000000000000 & (uint64_t)exp << 48) |
77+ (0x8000000000000000 & (uint64_t)sgn << 63) };
78+ return copy_ldi(x);
79+}
80+
81+void cmp(long double a, long double b)
82+{
83+ u128_t ax = copy_ild(a);
84+ u128_t bx = copy_ild(b);
85+ int eq = (a == b);
86+ int ne = (a != b);
87+ int lt = (a < b);
88+ int le = (a <= b);
89+ int gt = (a > b);
90+ int ge = (a >= b);
91+
92+ check(eq == 0 || eq == 1);
93+ check(lt == 0 || lt == 1);
94+ check(gt == 0 || gt == 1);
95+ check(ne == !eq && le == (lt | eq) && ge == (gt | eq));
96+ check(eq + lt + gt < 2);
97+
98+ printf("cmp %016llx%016llx %016llx%016llx %d %d %d\n",
99+ ax.x1, ax.x0, bx.x1, bx.x0, lt, eq, gt);
100+}
101+
102+void cmps(void)
103+{
104+ int i, j;
105+
106+ for (i = 0; i < 2; i++)
107+ for (j = 0; j < 2; j++)
108+ cmp(make(i, 0, 0, 0), make(j, 0, 0, 0));
109+
110+ for (i = 0; i < 2; i++) {
111+ for (j = 0; j < 64; j++) {
112+ long double f1 = make(i, 32767, (uint64_t)1 << j, 0);
113+ long double f2 = make(i, 32767, 0, (uint64_t)1 << j);
114+ cmp(f1, 0);
115+ cmp(f2, 0);
116+ cmp(0, f1);
117+ cmp(0, f2);
118+ }
119+ }
120+
121+ for (i = 0; i < 6; i++)
122+ for (j = 0; j < 6; j++)
123+ cmp(make(i & 1, i >> 1, 0, 0),
124+ make(j & 1, j >> 1, 0, 0));
125+
126+ for (i = 0; i < 2; i++) {
127+ for (j = 0; j < 2; j++) {
128+ int a, b;
129+ for (a = 0; a < 2; a++) {
130+ for (b = 0; b < 2; b++) {
131+ cmp(make(i, j, a, b), make(i, j, 0, 0));
132+ cmp(make(i, j, 0, 0), make(i, j, a, b));
133+ }
134+ }
135+ }
136+ }
137+}
138+
139+void xop(const char *name, long double a, long double b, long double c)
140+{
141+ u128_t ax = copy_ild(a);
142+ u128_t bx = copy_ild(b);
143+ u128_t cx = copy_ild(c);
144+ printf("%s %016llx%016llx %016llx%016llx %016llx%016llx\n",
145+ name, ax.x1, ax.x0, bx.x1, bx.x0, cx.x1, cx.x0);
146+}
147+
148+void fadd(long double a, long double b)
149+{
150+ xop("add", a, b, a + b);
151+}
152+
153+void fsub(long double a, long double b)
154+{
155+ xop("sub", a, b, a - b);
156+}
157+
158+void fmul(long double a, long double b)
159+{
160+ xop("mul", a, b, a * b);
161+}
162+
163+void fdiv(long double a, long double b)
164+{
165+ xop("div", a, b, a / b);
166+}
167+
168+void nanz(void)
169+{
170+ // Check NaNs:
171+ {
172+ long double x[7];
173+ int i, j, n = 0;
174+ x[n++] = make(0, 32000, 0x95132b76effc, 0xd79035214b4f8d53);
175+ x[n++] = make(1, 32001, 0xbe71d7a51587, 0x30601c6815d6c3ac);
176+ x[n++] = make(0, 32767, 0, 1);
177+ x[n++] = make(0, 32767, (uint64_t)1 << 46, 0);
178+ x[n++] = make(1, 32767, (uint64_t)1 << 47, 0);
179+ x[n++] = make(1, 32767, 0x7596c7099ad5, 0xe25fed2c58f73fc9);
180+ x[n++] = make(0, 32767, 0x835d143360f9, 0x5e315efb35630666);
181+ check(n == sizeof(x) / sizeof(*x));
182+ for (i = 0; i < n; i++) {
183+ for (j = 0; j < n; j++) {
184+ fadd(x[i], x[j]);
185+ fsub(x[i], x[j]);
186+ fmul(x[i], x[j]);
187+ fdiv(x[i], x[j]);
188+ }
189+ }
190+ }
191+
192+ // Check infinities and zeroes:
193+ {
194+ long double x[6];
195+ int i, j, n = 0;
196+ x[n++] = make(1, 32000, 0x62acda85f700, 0x47b6c9f35edc4044);
197+ x[n++] = make(0, 32001, 0x94b7abf55af7, 0x9f425fe354428e19);
198+ x[n++] = make(0, 32767, 0, 0);
199+ x[n++] = make(1, 32767, 0, 0);
200+ x[n++] = make(0, 0, 0, 0);
201+ x[n++] = make(1, 0, 0, 0);
202+ check(n == sizeof(x) / sizeof(*x));
203+ for (i = 0; i < n; i++) {
204+ for (j = 0; j < n; j++) {
205+ fadd(x[i], x[j]);
206+ fsub(x[i], x[j]);
207+ fmul(x[i], x[j]);
208+ fdiv(x[i], x[j]);
209+ }
210+ }
211+ }
212+}
213+
214+void adds(void)
215+{
216+ // Check shifting and add/sub:
217+ {
218+ int i;
219+ for (i = -130; i <= 130; i++) {
220+ int s1 = (uint32_t)i % 3 < 1;
221+ int s2 = (uint32_t)i % 5 < 2;
222+ fadd(make(s1, 16384 , 0x502c065e4f71a65d, 0xd2f9bdb031f4f031),
223+ make(s2, 16384 + i, 0xae267395a9bc1033, 0xb56b5800da1ba448));
224+ }
225+ }
226+
227+ // Check normalisation:
228+ {
229+ uint64_t a0 = 0xc6bab0a6afbef5ed;
230+ uint64_t a1 = 0x4f84136c4a2e9b52;
231+ int ee[] = { 0, 1, 10000 };
232+ int e, i;
233+ for (e = 0; e < sizeof(ee) / sizeof(*ee); e++) {
234+ int exp = ee[e];
235+ fsub(make(0, exp, a1, a0), make(0, 0, 0, 0));
236+ for (i = 63; i >= 0; i--)
237+ fsub(make(0, exp, a1 | (uint64_t)1 << i >> 1, a0),
238+ make(0, exp, a1 >> i << i, 0));
239+ for (i = 63; i >=0; i--)
240+ fsub(make(0, exp, a1, a0 | (uint64_t)1 << i >> 1),
241+ make(0, exp, a1, a0 >> i << i));
242+ }
243+ }
244+
245+ // Carry/overflow from rounding:
246+ {
247+ fadd(make(0, 114, -1, -1), make(0, 1, 0, 0));
248+ fadd(make(0, 32766, -1, -1), make(0, 32653, 0, 0));
249+ fsub(make(1, 32766, -1, -1), make(0, 32653, 0, 0));
250+ }
251+}
252+
253+void muls(void)
254+{
255+ int i, j;
256+
257+ {
258+ long double max = make(0, 32766, -1, -1);
259+ long double min = make(0, 0, 0, 1);
260+ fmul(max, max);
261+ fmul(max, min);
262+ fmul(min, min);
263+ }
264+
265+ for (i = 117; i > 0; i--)
266+ fmul(make(0, 16268, 0x643dcea76edc, 0xe0877a598403627a),
267+ make(i & 1, i, 0, 0));
268+
269+ fmul(make(0, 16383, -1, -3), make(0, 16383, 0, 1));
270+ // Round to next exponent:
271+ fmul(make(0, 16383, -1, -2), make(0, 16383, 0, 1));
272+ // Round from subnormal to normal:
273+ fmul(make(0, 1, -1, -1), make(0, 16382, 0, 0));
274+
275+ for (i = 0; i < 2; i++)
276+ for (j = 0; j < 112; j++)
277+ fmul(make(0, 16383, (uint64_t)1 << i, 0),
278+ make(0, 16383,
279+ j < 64 ? 0 : (uint64_t)1 << (j - 64),
280+ j < 64 ? (uint64_t)1 << j : 0));
281+}
282+
283+void divs(void)
284+{
285+ int i;
286+
287+ {
288+ long double max = make(0, 32766, -1, -1);
289+ long double min = make(0, 0, 0, 1);
290+ fdiv(max, max);
291+ fdiv(max, min);
292+ fdiv(min, max);
293+ fdiv(min, min);
294+ }
295+
296+ for (i = 0; i < 64; i++)
297+ fdiv(make(0, 16383, -1, -1), make(0, 16383, -1, -(uint64_t)1 << i));
298+ for (i = 0; i < 48; i++)
299+ fdiv(make(0, 16383, -1, -1), make(0, 16383, -(uint64_t)1 << i, 0));
300+}
301+
302+void cvtlsw(int32_t a)
303+{
304+ long double f = a;
305+ u128_t x = copy_ild(f);
306+ printf("cvtlsw %08lx %016llx%016llx\n", (long)(uint32_t)a, x.x1, x.x0);
307+}
308+
309+void cvtlsx(int64_t a)
310+{
311+ long double f = a;
312+ u128_t x = copy_ild(f);
313+ printf("cvtlsx %016llx %016llx%016llx\n",
314+ (long long)(uint64_t)a, x.x1, x.x0);
315+}
316+
317+void cvtluw(uint32_t a)
318+{
319+ long double f = a;
320+ u128_t x = copy_ild(f);
321+ printf("cvtluw %08lx %016llx%016llx\n", (long)a, x.x1, x.x0);
322+}
323+
324+void cvtlux(uint64_t a)
325+{
326+ long double f = a;
327+ u128_t x = copy_ild(f);
328+ printf("cvtlux %016llx %016llx%016llx\n", (long long)a, x.x1, x.x0);
329+}
330+
331+void cvtil(long double a)
332+{
333+ u128_t x = copy_ild(a);
334+ int32_t b1 = a;
335+ int64_t b2 = a;
336+ uint32_t b3 = a;
337+ uint64_t b4 = a;
338+ printf("cvtswl %016llx%016llx %08lx\n",
339+ x.x1, x.x0, (long)(uint32_t)b1);
340+ printf("cvtsxl %016llx%016llx %016llx\n",
341+ x.x1, x.x0, (long long)(uint64_t)b2);
342+ printf("cvtuwl %016llx%016llx %08lx\n",
343+ x.x1, x.x0, (long)b3);
344+ printf("cvtuxl %016llx%016llx %016llx\n",
345+ x.x1, x.x0, (long long)b4);
346+}
347+
348+void cvtlf(float a)
349+{
350+ uint32_t ax = copy_if(a);
351+ long double b = a;
352+ u128_t bx = copy_ild(b);
353+ printf("cvtlf %08lx %016llx%016llx\n", (long)ax, bx.x1, bx.x0);
354+}
355+
356+void cvtld(double a)
357+{
358+ uint64_t ax = copy_id(a);
359+ long double b = a;
360+ u128_t bx = copy_ild(b);
361+ printf("cvtld %016llx %016llx%016llx\n", (long long)ax, bx.x1, bx.x0);
362+}
363+
364+void cvtfl(long double a)
365+{
366+ u128_t ax = copy_ild(a);
367+ float b = a;
368+ uint32_t bx = copy_if(b);
369+ printf("cvtfl %016llx%016llx %08lx\n", ax.x1, ax.x0, (long)bx);
370+}
371+
372+void cvtdl(long double a)
373+{
374+ u128_t ax = copy_ild(a);
375+ double b = a;
376+ uint64_t bx = copy_id(b);
377+ printf("cvtdl %016llx%016llx %016llx\n", ax.x1, ax.x0, (long long)bx);
378+}
379+
380+void cvts(void)
381+{
382+ int i, j;
383+
384+ {
385+ uint32_t x = 0xad040c5b;
386+ cvtlsw(0);
387+ for (i = 0; i < 31; i++)
388+ cvtlsw(x >> (31 - i));
389+ for (i = 0; i < 31; i++)
390+ cvtlsw(-(x >> (31 - i)));
391+ cvtlsw(0x80000000);
392+ }
393+ {
394+ uint64_t x = 0xb630a248cad9afd2;
395+ cvtlsx(0);
396+ for (i = 0; i < 63; i++)
397+ cvtlsx(x >> (63 - i));
398+ for (i = 0; i < 63; i++)
399+ cvtlsx(-(x >> (63 - i)));
400+ cvtlsx(0x8000000000000000);
401+ }
402+ {
403+ uint32_t x = 0xad040c5b;
404+ cvtluw(0);
405+ for (i = 0; i < 32; i++)
406+ cvtluw(x >> (31 - i));
407+ }
408+ {
409+ uint64_t x = 0xb630a248cad9afd2;
410+ cvtlux(0);
411+ for (i = 0; i < 64; i++)
412+ cvtlux(x >> (63 - i));
413+ }
414+
415+ for (i = 0; i < 2; i++) {
416+ cvtil(make(i, 32767, 0, 1));
417+ cvtil(make(i, 32767, (uint64_t)1 << 47, 0));
418+ cvtil(make(i, 32767, 123, 456));
419+ cvtil(make(i, 32767, 0, 0));
420+ cvtil(make(i, 16382, -1, -1));
421+ cvtil(make(i, 16383, -1, -1));
422+ cvtil(make(i, 16384, 0x7fffffffffff, -1));
423+ cvtil(make(i, 16384, 0x800000000000, 0));
424+ for (j = 0; j < 68; j++)
425+ cvtil(make(i, 16381 + j, 0xd4822c0a10ec, 0x1fe2f8b2669f5c9d));
426+ }
427+
428+ cvtlf(copy_fi(0x00000000));
429+ cvtlf(copy_fi(0x456789ab));
430+ cvtlf(copy_fi(0x7f800000));
431+ cvtlf(copy_fi(0x7f923456));
432+ cvtlf(copy_fi(0x7fdbcdef));
433+ cvtlf(copy_fi(0x80000000));
434+ cvtlf(copy_fi(0xabcdef12));
435+ cvtlf(copy_fi(0xff800000));
436+ cvtlf(copy_fi(0xff923456));
437+ cvtlf(copy_fi(0xffdbcdef));
438+
439+ cvtld(copy_di(0x0000000000000000));
440+ cvtld(copy_di(0x456789abcdef0123));
441+ cvtld(copy_di(0x7ff0000000000000));
442+ cvtld(copy_di(0x7ff123456789abcd));
443+ cvtld(copy_di(0x7ffabcdef1234567));
444+ cvtld(copy_di(0x8000000000000000));
445+ cvtld(copy_di(0xcdef123456789abc));
446+ cvtld(copy_di(0xfff0000000000000));
447+ cvtld(copy_di(0xfff123456789abcd));
448+ cvtld(copy_di(0xfffabcdef1234567));
449+
450+ for (i = 0; i < 2; i++) { \
451+ cvtfl(make(i, 0, 0, 0));
452+ cvtfl(make(i, 16232, -1, -1));
453+ cvtfl(make(i, 16233, 0, 0));
454+ cvtfl(make(i, 16233, 0, 1));
455+ cvtfl(make(i, 16383, 0xab0ffd000000, 0));
456+ cvtfl(make(i, 16383, 0xab0ffd000001, 0));
457+ cvtfl(make(i, 16383, 0xab0ffeffffff, 0));
458+ cvtfl(make(i, 16383, 0xab0fff000000, 0));
459+ cvtfl(make(i, 16383, 0xab0fff000001, 0));
460+ cvtfl(make(i, 16510, 0xfffffeffffff, -1));
461+ cvtfl(make(i, 16510, 0xffffff000000, 0));
462+ cvtfl(make(i, 16511, 0, 0));
463+ cvtfl(make(i, 32767, 0, 0));
464+ cvtfl(make(i, 32767, 0, 1));
465+ cvtfl(make(i, 32767, 0x4cbe01ac5f40, 0x75cee3c6afbb00b5));
466+ cvtfl(make(i, 32767, 0x800000000000, 1));
467+ cvtfl(make(i, 32767, 0xa11caaaf6a52, 0x696033e871eab099));
468+ }
469+
470+ for (i = 0; i < 2; i++) {
471+ cvtdl(make(i, 0, 0, 0));
472+ cvtdl(make(i, 15307, -1, -1));
473+ cvtdl(make(i, 15308, 0, 0));
474+ cvtdl(make(i, 15308, 0, 1));
475+ cvtdl(make(i, 16383, 0xabc123abc0ff, 0xe800000000000000));
476+ cvtdl(make(i, 16383, 0xabc123abc0ff, 0xe800000000000001));
477+ cvtdl(make(i, 16383, 0xabc123abc0ff, 0xf7ffffffffffffff));
478+ cvtdl(make(i, 16383, 0xabc123abc0ff, 0xf800000000000000));
479+ cvtdl(make(i, 16383, 0xabc123abc0ff, 0xf800000000000001));
480+ cvtdl(make(i, 17406, 0xffffffffffff, 0xf7ffffffffffffff));
481+ cvtdl(make(i, 17406, 0xffffffffffff, 0xf800000000000000));
482+ cvtdl(make(i, 17407, 0, 0));
483+ cvtdl(make(i, 32767, 0, 0));
484+ cvtdl(make(i, 32767, 0, 1));
485+ cvtdl(make(i, 32767, 0x4cbe01ac5f40, 0x75cee3c6afbb00b5));
486+ cvtdl(make(i, 32767, 0x800000000000, 1));
487+ cvtdl(make(i, 32767, 0xa11caaaf6a52, 0x696033e871eab099));
488+ }
489+}
490+
491+void tests(void)
492+{
493+ cmps();
494+ nanz();
495+ adds();
496+ muls();
497+ divs();
498+ cvts();
499+}
500+
501+int main()
502+{
503+#ifdef __aarch64__
504+ tests();
505+#else
506+ printf("This test program is intended for a little-endian architecture\n"
507+ "with an IEEE-standard 128-bit long double.\n");
508+#endif
509+ return 0;
510+}
libtcc.c+6−1
@@ -45,6 +45,9 @@ ST_DATA struct TCCState *tcc_state; · 44 unmodified lines
4545 #ifdef TCC_TARGET_ARM
4646 #include "arm-gen.c"
4747 #endif
48+#ifdef TCC_TARGET_ARM64
49+#include "arm64-gen.c"
50+#endif
4851 #ifdef TCC_TARGET_C67
4952 #include "c67-gen.c"
5053 #endif
@@ -959,6 +962,8 @@ LIBTCCAPI TCCState *tcc_new(void) · 908 unmodified lines
959962 #else
960963 s->float_abi = ARM_SOFTFP_FLOAT;
961964 #endif
965+#elif defined(TCC_TARGET_ARM64)
966+ tcc_define_symbol(s, "__aarch64__", NULL);
962967 #endif
963968
964969 #ifdef TCC_TARGET_PE
@@ -1560,7 +1565,7 @@ static int tcc_set_linker(TCCState *s, const char *option) · 595 unmodified lines
15601565 } else if (link_option(option, "oformat=", &p)) {
15611566 #if defined(TCC_TARGET_PE)
15621567 if (strstart("pe-", &p)) {
1563−#elif defined(TCC_TARGET_X86_64)
1568+#elif defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
15641569 if (strstart("elf64-", &p)) {
15651570 #else
15661571 if (strstart("elf32-", &p)) {
tcc.c+2−0
@@ -203,6 +203,8 @@ static void display_info(TCCState *s, int what) · 202 unmodified lines
203203 # endif
204204 #elif defined TCC_TARGET_ARM
205205 "ARM"
206+#elif defined TCC_TARGET_ARM64
207+ "AArch64"
206208 # ifdef TCC_ARM_HARDFLOAT
207209 " Hard Float"
208210 # endif
tcc.h+25−5
@@ -113,7 +113,7 @@ · 112 unmodified lines
113113 #endif
114114
115115 #include "elf.h"
116−#ifdef TCC_TARGET_X86_64
116+#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
117117 # define ELFCLASSW ELFCLASS64
118118 # define ElfW(type) Elf##64##_##type
119119 # define ELFW(type) ELF##64##_##type
@@ -151,23 +151,26 @@ · 31 unmodified lines
151151 /* target selection */
152152 /* #define TCC_TARGET_I386 *//* i386 code generator */
153153 /* #define TCC_TARGET_ARM *//* ARMv4 code generator */
154+/* #define TCC_TARGET_ARM64 *//* ARMv8 code generator */
154155 /* #define TCC_TARGET_C67 *//* TMS320C67xx code generator */
155156 /* #define TCC_TARGET_X86_64 *//* x86-64 code generator */
156157
157158 /* default target is I386 */
158159 #if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_ARM) && \
159− !defined(TCC_TARGET_C67) && !defined(TCC_TARGET_X86_64)
160+ !defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_C67) && \
161+ !defined(TCC_TARGET_X86_64)
160162 #define TCC_TARGET_I386
161163 #endif
162164
163165 #if !defined(TCC_UCLIBC) && !defined(TCC_TARGET_ARM) && \
164− !defined(TCC_TARGET_C67) && !defined(TCC_TARGET_X86_64) && \
165− !defined(CONFIG_USE_LIBGCC)
166+ !defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_C67) && \
167+ !defined(TCC_TARGET_X86_64) && !defined(CONFIG_USE_LIBGCC)
166168 #define CONFIG_TCC_BCHECK /* enable bound checking code */
167169 #endif
168170
169171 /* define it to include assembler support */
170−#if !defined(TCC_TARGET_ARM) && !defined(TCC_TARGET_C67)
172+#if !defined(TCC_TARGET_ARM) && !defined(TCC_TARGET_ARM64) && \
173+ !defined(TCC_TARGET_C67)
171174 #define CONFIG_TCC_ASM
172175 #endif
173176
@@ -184,6 +187,8 @@ · 10 unmodified lines
184187 # define TCC_IS_NATIVE
185188 # elif defined __arm__ && defined TCC_TARGET_ARM
186189 # define TCC_IS_NATIVE
190+# elif defined __aarch64__ && defined TCC_TARGET_ARM64
191+# define TCC_IS_NATIVE
187192 # endif
188193 #endif
189194
@@ -256,6 +261,8 @@ · 66 unmodified lines
256261 # define CONFIG_TCC_ELFINTERP "/usr/libexec/ld-elf.so.2"
257262 # elif defined __GNU__
258263 # define CONFIG_TCC_ELFINTERP "/lib/ld.so"
264+# elif defined TCC_TARGET_ARM64
265+# define CONFIG_TCC_ELFINTERP "/lib/ld-linux-aarch64.so.1"
259266 # elif defined(TCC_TARGET_X86_64)
260267 # define CONFIG_TCC_ELFINTERP "/lib64/ld-linux-x86-64.so.2"
261268 # elif defined(TCC_UCLIBC)
@@ -290,6 +297,9 @@ · 28 unmodified lines
290297 #ifdef TCC_TARGET_ARM
291298 # include "arm-gen.c"
292299 #endif
300+#ifdef TCC_TARGET_ARM64
301+# include "arm64-gen.c"
302+#endif
293303 #ifdef TCC_TARGET_C67
294304 # include "coff.h"
295305 # include "c67-gen.c"
@@ -1214,6 +1224,7 @@ ST_FUNC void vpushv(SValue *v); · 918 unmodified lines
12141224 ST_FUNC void save_reg(int r);
12151225 ST_FUNC int get_reg(int rc);
12161226 ST_FUNC void save_regs(int n);
1227+ST_FUNC void gaddrof(void);
12171228 ST_FUNC int gv(int rc);
12181229 ST_FUNC void gv2(int rc1, int rc2);
12191230 ST_FUNC void vpop(void);
@@ -1357,6 +1368,15 @@ ST_FUNC uint32_t encbranch(int pos, int addr, int fail); · 137 unmodified lines
13571368 ST_FUNC void gen_cvt_itof1(int t);
13581369 #endif
13591370
1371+/* ------------ arm64-gen.c ------------ */
1372+#ifdef TCC_TARGET_ARM64
1373+ST_FUNC void gen_cvt_sxtw(void);
1374+ST_FUNC void gen_opl(int op);
1375+ST_FUNC void greturn(void);
1376+ST_FUNC void gen_va_start(void);
1377+ST_FUNC void gen_va_arg(CType *t);
1378+#endif
1379+
13601380 /* ------------ c67-gen.c ------------ */
13611381 #ifdef TCC_TARGET_C67
13621382 #endif
tccelf.c+133−4
@@ -291,7 +291,7 @@ ST_FUNC void put_elf_reloca(Section *symtab, Section *s, unsigned long offset, · 290 unmodified lines
291291 rel = section_ptr_add(sr, sizeof(ElfW_Rel));
292292 rel->r_offset = offset;
293293 rel->r_info = ELFW(R_INFO)(symbol, type);
294−#ifdef TCC_TARGET_X86_64
294+#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
295295 rel->r_addend = addend;
296296 #else
297297 if (addend)
@@ -506,7 +506,7 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s) · 208 unmodified lines
506506 sym_index = ELFW(R_SYM)(rel->r_info);
507507 sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
508508 val = sym->st_value;
509−#ifdef TCC_TARGET_X86_64
509+#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
510510 val += rel->r_addend;
511511 #endif
512512 type = ELFW(R_TYPE)(rel->r_info);
@@ -760,6 +760,69 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s) · 247 unmodified lines
760760 fprintf(stderr,"FIXME: handle reloc type %x at %x [%p] to %x\n",
761761 type, (unsigned)addr, ptr, (unsigned)val);
762762 break;
763+#elif defined(TCC_TARGET_ARM64)
764+ case R_AARCH64_ABS64:
765+ *(uint64_t *)ptr = val;
766+ break;
767+ case R_AARCH64_ABS32:
768+ *(uint32_t *)ptr = val;
769+ break;
770+ case R_AARCH64_MOVW_UABS_G0_NC:
771+ *(uint32_t *)ptr = (*(uint32_t *)ptr & 0xffe0001f) |
772+ (val & 0xffff) << 5;
773+ break;
774+ case R_AARCH64_MOVW_UABS_G1_NC:
775+ *(uint32_t *)ptr = (*(uint32_t *)ptr & 0xffe0001f) |
776+ (val >> 16 & 0xffff) << 5;
777+ break;
778+ case R_AARCH64_MOVW_UABS_G2_NC:
779+ *(uint32_t *)ptr = (*(uint32_t *)ptr & 0xffe0001f) |
780+ (val >> 32 & 0xffff) << 5;
781+ break;
782+ case R_AARCH64_MOVW_UABS_G3:
783+ *(uint32_t *)ptr = (*(uint32_t *)ptr & 0xffe0001f) |
784+ (val >> 48 & 0xffff) << 5;
785+ break;
786+ case R_AARCH64_ADR_PREL_PG_HI21: {
787+ uint64_t off = (val >> 12) - (addr >> 12);
788+ if ((off + ((uint64_t)1 << 20)) >> 21)
789+ tcc_error("R_AARCH64_ADR_PREL_PG_HI21 relocation failed");
790+ *(uint32_t *)ptr = (*(uint32_t *)ptr & 0x9f00001f) |
791+ (off & 0x1ffffc) << 3 | (off & 3) << 29;
792+ break;
793+ }
794+ case R_AARCH64_ADD_ABS_LO12_NC:
795+ *(uint32_t *)ptr = (*(uint32_t *)ptr & 0xffc003ff) |
796+ (val & 0xfff) << 10;
797+ break;
798+ case R_AARCH64_JUMP26:
799+ case R_AARCH64_CALL26:
800+ if (((val - addr) + ((uint64_t)1 << 27)) & ~(uint64_t)0xffffffc)
801+ tcc_error("R_AARCH64_(JUMP|CALL)26 relocation failed");
802+ *(uint32_t *)ptr = 0x14000000 | (type == R_AARCH64_CALL26) << 31 |
803+ ((val - addr) >> 2 & 0x3ffffff);
804+ break;
805+ case R_AARCH64_ADR_GOT_PAGE: {
806+ uint64_t off =
807+ (((s1->got->sh_addr +
808+ s1->sym_attrs[sym_index].got_offset) >> 12) - (addr >> 12));
809+ if ((off + ((uint64_t)1 << 20)) >> 21)
810+ tcc_error("R_AARCH64_ADR_GOT_PAGE relocation failed");
811+ *(uint32_t *)ptr = (*(uint32_t *)ptr & 0x9f00001f) |
812+ (off & 0x1ffffc) << 3 | (off & 3) << 29;
813+ break;
814+ }
815+ case R_AARCH64_LD64_GOT_LO12_NC:
816+ *(uint32_t *)ptr = (*(uint32_t *)ptr & 0xfff803ff) |
817+ ((s1->got->sh_addr + s1->sym_attrs[sym_index].got_offset)
818+ & 0xff8) << 7;
819+ break;
820+ case R_AARCH64_COPY:
821+ break;
822+ default:
823+ fprintf(stderr, "FIXME: handle reloc type %x at %x [%p] to %x\n",
824+ type, (unsigned)addr, ptr, (unsigned)val);
825+ break;
763826 #elif defined(TCC_TARGET_C67)
764827 case R_C60_32:
765828 *(int *)ptr += val;
@@ -955,7 +1018,7 @@ static void put32(unsigned char *p, uint32_t val) · 189 unmodified lines
9551018 }
9561019
9571020 #if defined(TCC_TARGET_I386) || defined(TCC_TARGET_ARM) || \
958− defined(TCC_TARGET_X86_64)
1021+ defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
9591022 static uint32_t get32(unsigned char *p)
9601023 {
9611024 return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
@@ -1014,6 +1077,8 @@ static unsigned long put_got_entry(TCCState *s1, · 52 unmodified lines
10141077 (reloc_type == R_386_JMP_SLOT);
10151078 #elif defined(TCC_TARGET_ARM)
10161079 (reloc_type == R_ARM_JUMP_SLOT);
1080+#elif defined(TCC_TARGET_ARM64)
1081+ (reloc_type == R_AARCH64_JUMP_SLOT);
10171082 #else
10181083 0;
10191084 #endif
@@ -1135,6 +1200,24 @@ static unsigned long put_got_entry(TCCState *s1, · 115 unmodified lines
11351200 if (sym->st_shndx == SHN_UNDEF)
11361201 offset = plt->data_offset - 16;
11371202 }
1203+#elif defined(TCC_TARGET_ARM64)
1204+ if (need_plt_entry) {
1205+ Section *plt;
1206+ uint8_t *p;
1207+
1208+ if (s1->output_type == TCC_OUTPUT_DLL)
1209+ tcc_error("DLLs unimplemented!");
1210+
1211+ plt = s1->plt;
1212+ if (plt->data_offset == 0)
1213+ section_ptr_add(plt, 32);
1214+ p = section_ptr_add(plt, 16);
1215+ put32(p, s1->got->data_offset);
1216+ put32(p + 4, (uint64_t)s1->got->data_offset >> 32);
1217+
1218+ if (sym->st_shndx == SHN_UNDEF)
1219+ offset = plt->data_offset - 16;
1220+ }
11381221 #elif defined(TCC_TARGET_C67)
11391222 if (s1->dynsym) {
11401223 tcc_error("C67 got not implemented");
@@ -1277,6 +1360,18 @@ ST_FUNC void build_got_entries(TCCState *s1) · 136 unmodified lines
12771360 put32(p+2, 0x46c0); /* nop */
12781361 put32(p+4, 0xeafffffe); /* b $sym */
12791362 }
1363+#elif defined(TCC_TARGET_ARM64)
1364+ //xx Other cases may be required here:
1365+ case R_AARCH64_ADR_GOT_PAGE:
1366+ case R_AARCH64_LD64_GOT_LO12_NC:
1367+ if (!s1->got)
1368+ build_got(s1);
1369+ sym_index = ELFW(R_SYM)(rel->r_info);
1370+ sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
1371+ reloc_type = R_AARCH64_GLOB_DAT;
1372+ put_got_entry(s1, reloc_type, sym->st_size, sym->st_info,
1373+ sym_index);
1374+ break;
12801375 #elif defined(TCC_TARGET_C67)
12811376 case R_C60_GOT32:
12821377 case R_C60_GOTOFF:
@@ -1796,6 +1891,40 @@ ST_FUNC void relocate_plt(TCCState *s1) · 513 unmodified lines
17961891 put32(p + 12, x + get32(p + 12) + s1->plt->data - p);
17971892 p += 16;
17981893 }
1894+#elif defined(TCC_TARGET_ARM64)
1895+ uint64_t plt = s1->plt->sh_addr;
1896+ uint64_t got = s1->got->sh_addr;
1897+ uint64_t off = (got >> 12) - (plt >> 12);
1898+ if ((off + ((uint64_t)1 << 20)) >> 21)
1899+ tcc_error("Failed relocating PLT");
1900+ put32(p, 0xa9bf7bf0); // stp x16,x30,[sp,#-16]!
1901+ put32(p + 4, (0x90000010 | // adrp x16,...
1902+ (off & 0x1ffffc) << 3 | (off & 3) << 29));
1903+ put32(p + 8, (0xf9400211 | // ldr x17,[x16,#...]
1904+ (got & 0xff8) << 7));
1905+ put32(p + 12, (0x91000210 | // add x16,x16,#...
1906+ (got & 0xfff) << 10));
1907+ put32(p + 16, 0xd61f0220); // br x17
1908+ put32(p + 20, 0xd503201f); // nop
1909+ put32(p + 24, 0xd503201f); // nop
1910+ put32(p + 28, 0xd503201f); // nop
1911+ p += 32;
1912+ while (p < p_end) {
1913+ uint64_t pc = plt + (p - s1->plt->data);
1914+ uint64_t addr = got +
1915+ (get32(p) | (uint64_t)get32(p + 4) << 32);
1916+ uint32_t off = (addr >> 12) - (pc >> 12);
1917+ if ((off + ((uint64_t)1 << 20)) >> 21)
1918+ tcc_error("Failed relocating PLT");
1919+ put32(p, (0x90000010 | // adrp x16,...
1920+ (off & 0x1ffffc) << 3 | (off & 3) << 29));
1921+ put32(p + 4, (0xf9400211 | // ldr x17,[x16,#...]
1922+ (addr & 0xff8) << 7));
1923+ put32(p + 8, (0x91000210 | // add x16,x16,#...
1924+ (addr & 0xfff) << 10));
1925+ put32(p + 12, 0xd61f0220); // br x17
1926+ p += 16;
1927+ }
17991928 #elif defined(TCC_TARGET_C67)
18001929 /* XXX: TODO */
18011930 #else
@@ -2093,7 +2222,7 @@ static void fill_dynamic(TCCState *s1, struct dyn_inf *dyninf) · 291 unmodified lines
20932222 put_dt(dynamic, DT_SYMTAB, s1->dynsym->sh_addr);
20942223 put_dt(dynamic, DT_STRSZ, dyninf->dynstr->data_offset);
20952224 put_dt(dynamic, DT_SYMENT, sizeof(ElfW(Sym)));
2096−#ifdef TCC_TARGET_X86_64
2225+#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
20972226 put_dt(dynamic, DT_RELA, dyninf->rel_addr);
20982227 put_dt(dynamic, DT_RELASZ, dyninf->rel_size);
20992228 put_dt(dynamic, DT_RELAENT, sizeof(ElfW_Rel));
tccgen.c+102−25
@@ -545,7 +545,7 @@ ST_FUNC void save_reg(int r) · 544 unmodified lines
545545 type = &p->type;
546546 if ((p->r & VT_LVAL) ||
547547 (!is_float(type->t) && (type->t & VT_BTYPE) != VT_LLONG))
548−#ifdef TCC_TARGET_X86_64
548+#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
549549 type = &char_pointer_type;
550550 #else
551551 type = &int_type;
@@ -562,7 +562,7 @@ ST_FUNC void save_reg(int r) · 10 unmodified lines
562562 o(0xd8dd); /* fstp %st(0) */
563563 }
564564 #endif
565−#ifndef TCC_TARGET_X86_64
565+#if !defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_X86_64)
566566 /* special long long case */
567567 if ((type->t & VT_BTYPE) == VT_LLONG) {
568568 sv.c.ul += 4;
@@ -681,7 +681,7 @@ static void move_reg(int r, int s, int t) · 112 unmodified lines
681681 }
682682
683683 /* get address of vtop (vtop MUST BE an lvalue) */
684−static void gaddrof(void)
684+ST_FUNC void gaddrof(void)
685685 {
686686 if (vtop->r & VT_REF)
687687 gv(RC_INT);
@@ -803,11 +803,13 @@ ST_FUNC int gv(int rc) · 115 unmodified lines
803803
804804 r = vtop->r & VT_VALMASK;
805805 rc2 = (rc & RC_FLOAT) ? RC_FLOAT : RC_INT;
806+#ifndef TCC_TARGET_ARM64
806807 if (rc == RC_IRET)
807808 rc2 = RC_LRET;
808809 #ifdef TCC_TARGET_X86_64
809810 else if (rc == RC_FRET)
810811 rc2 = RC_QRET;
812+#endif
811813 #endif
812814
813815 /* need to reload if:
@@ -817,7 +819,7 @@ ST_FUNC int gv(int rc) · 3 unmodified lines
817819 if (r >= VT_CONST
818820 || (vtop->r & VT_LVAL)
819821 || !(reg_classes[r] & rc)
820−#ifdef TCC_TARGET_X86_64
822+#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
821823 || ((vtop->type.t & VT_BTYPE) == VT_QLONG && !(reg_classes[vtop->r2] & rc2))
822824 || ((vtop->type.t & VT_BTYPE) == VT_QFLOAT && !(reg_classes[vtop->r2] & rc2))
823825 #else
@@ -826,7 +828,7 @@ ST_FUNC int gv(int rc) · 2 unmodified lines
826828 )
827829 {
828830 r = get_reg(rc);
829−#ifdef TCC_TARGET_X86_64
831+#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
830832 if (((vtop->type.t & VT_BTYPE) == VT_QLONG) || ((vtop->type.t & VT_BTYPE) == VT_QFLOAT)) {
831833 int addr_type = VT_LLONG, load_size = 8, load_type = ((vtop->type.t & VT_BTYPE) == VT_QLONG) ? VT_LLONG : VT_DOUBLE;
832834 #else
@@ -838,7 +840,7 @@ ST_FUNC int gv(int rc) · 5 unmodified lines
838840 original_type = vtop->type.t;
839841 /* two register type load : expand to two words
840842 temporarily */
841−#ifndef TCC_TARGET_X86_64
843+#if !defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_X86_64)
842844 if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
843845 /* load constant */
844846 ll = vtop->c.ull;
@@ -890,7 +892,7 @@ ST_FUNC int gv(int rc) · 45 unmodified lines
890892 t1 = t;
891893 /* compute memory access type */
892894 if (vtop->r & VT_REF)
893−#ifdef TCC_TARGET_X86_64
895+#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
894896 t = VT_PTR;
895897 #else
896898 t = VT_INT;
@@ -952,6 +954,7 @@ ST_FUNC void gv2(int rc1, int rc2) · 55 unmodified lines
952954 }
953955 }
954956
957+#ifndef TCC_TARGET_ARM64
955958 /* wrapper around RC_FRET to return a register by type */
956959 static int rc_fret(int t)
957960 {
@@ -962,6 +965,7 @@ static int rc_fret(int t) · 4 unmodified lines
962965 #endif
963966 return RC_FRET;
964967 }
968+#endif
965969
966970 /* wrapper around REG_FRET to return a register by type */
967971 static int reg_fret(int t)
@@ -1147,7 +1151,7 @@ ST_FUNC int gvtst(int inv, int t) · 179 unmodified lines
11471151 return gtst(inv, t);
11481152 }
11491153
1150−#ifndef TCC_TARGET_X86_64
1154+#if !defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_X86_64)
11511155 /* generate CPU independent (unsigned) long long operations */
11521156 static void gen_opl(int op)
11531157 {
@@ -1358,7 +1362,7 @@ static void gen_opl(int op) · 204 unmodified lines
13581362 #elif defined(TCC_TARGET_ARM)
13591363 b = ind;
13601364 o(0x1A000000 | encbranch(ind, 0, 1));
1361−#elif defined(TCC_TARGET_C67)
1365+#elif defined(TCC_TARGET_C67) || defined(TCC_TARGET_ARM64)
13621366 tcc_error("not implemented");
13631367 #else
13641368 #error not supported
@@ -1512,7 +1516,8 @@ static void gen_opic(int op) · 147 unmodified lines
15121516 general_case:
15131517 if (!nocode_wanted) {
15141518 /* call low level op generator */
1515− if (t1 == VT_LLONG || t2 == VT_LLONG)
1519+ if (t1 == VT_LLONG || t2 == VT_LLONG ||
1520+ (PTR_SIZE == 8 && (t1 == VT_PTR || t2 == VT_PTR)))
15161521 gen_opl(op);
15171522 else
15181523 gen_opi(op);
@@ -1679,7 +1684,7 @@ ST_FUNC void gen_op(int op) · 160 unmodified lines
16791684 if (op >= TOK_ULT && op <= TOK_LOR) {
16801685 check_comparison_pointer_types(vtop - 1, vtop, op);
16811686 /* pointers are handled are unsigned */
1682−#ifdef TCC_TARGET_X86_64
1687+#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
16831688 t = VT_LLONG | VT_UNSIGNED;
16841689 #else
16851690 t = VT_INT | VT_UNSIGNED;
@@ -1700,7 +1705,7 @@ ST_FUNC void gen_op(int op) · 14 unmodified lines
17001705 vrott(3);
17011706 gen_opic(op);
17021707 /* set to integer type */
1703−#ifdef TCC_TARGET_X86_64
1708+#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
17041709 vtop->type.t = VT_LLONG;
17051710 #else
17061711 vtop->type.t = VT_INT;
@@ -1724,7 +1729,7 @@ ST_FUNC void gen_op(int op) · 17 unmodified lines
17241729 u = pointed_size(&vtop[-1].type);
17251730 if (u < 0)
17261731 tcc_error("unknown array element size");
1727−#ifdef TCC_TARGET_X86_64
1732+#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
17281733 vpushll(u);
17291734 #else
17301735 /* XXX: cast to int ? (long long case) */
@@ -1833,6 +1838,9 @@ ST_FUNC void gen_op(int op) · 102 unmodified lines
18331838 /* generic itof for unsigned long long case */
18341839 static void gen_cvt_itof1(int t)
18351840 {
1841+#ifdef TCC_TARGET_ARM64
1842+ gen_cvt_itof(t);
1843+#else
18361844 if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) ==
18371845 (VT_LLONG | VT_UNSIGNED)) {
18381846
@@ -1851,12 +1859,16 @@ static void gen_cvt_itof1(int t) · 12 unmodified lines
18511859 } else {
18521860 gen_cvt_itof(t);
18531861 }
1862+#endif
18541863 }
18551864 #endif
18561865
18571866 /* generic ftoi for unsigned long long case */
18581867 static void gen_cvt_ftoi1(int t)
18591868 {
1869+#ifdef TCC_TARGET_ARM64
1870+ gen_cvt_ftoi(t);
1871+#else
18601872 int st;
18611873
18621874 if (t == (VT_LLONG | VT_UNSIGNED)) {
@@ -1878,6 +1890,7 @@ static void gen_cvt_ftoi1(int t) · 15 unmodified lines
18781890 } else {
18791891 gen_cvt_ftoi(t);
18801892 }
1893+#endif
18811894 }
18821895
18831896 /* force char or short cast */
@@ -1968,7 +1981,7 @@ static void gen_cast(CType *type) · 84 unmodified lines
19681981 vtop->c.ll = vtop->c.ull;
19691982 else if (sbt & VT_UNSIGNED)
19701983 vtop->c.ll = vtop->c.ui;
1971−#ifdef TCC_TARGET_X86_64
1984+#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
19721985 else if (sbt == VT_PTR)
19731986 ;
19741987 #endif
@@ -1979,7 +1992,7 @@ static void gen_cast(CType *type) · 4 unmodified lines
19791992 vtop->c.ull = vtop->c.ll;
19801993 else if (dbt == VT_BOOL)
19811994 vtop->c.i = (vtop->c.ll != 0);
1982−#ifdef TCC_TARGET_X86_64
1995+#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
19831996 else if (dbt == VT_PTR)
19841997 ;
19851998 #endif
@@ -2024,7 +2037,7 @@ static void gen_cast(CType *type) · 38 unmodified lines
20242037 gen_cast(type);
20252038 }
20262039 }
2027−#ifndef TCC_TARGET_X86_64
2040+#if !defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_X86_64)
20282041 } else if ((dbt & VT_BTYPE) == VT_LLONG) {
20292042 if ((sbt & VT_BTYPE) != VT_LLONG) {
20302043 /* scalar to long long */
@@ -2056,11 +2069,18 @@ static void gen_cast(CType *type) · 25 unmodified lines
20562069 (sbt & VT_BTYPE) != VT_PTR &&
20572070 (sbt & VT_BTYPE) != VT_FUNC) {
20582071 /* need to convert from 32bit to 64bit */
2059− int r = gv(RC_INT);
2072+ gv(RC_INT);
20602073 if (sbt != (VT_INT | VT_UNSIGNED)) {
2074+#if defined(TCC_TARGET_ARM64)
2075+ gen_cvt_sxtw();
2076+#elif defined(TCC_TARGET_X86_64)
2077+ int r = gv(RC_INT);
20612078 /* x86_64 specific: movslq */
20622079 o(0x6348);
20632080 o(0xc0 + (REG_VALUE(r) << 3) + REG_VALUE(r));
2081+#else
2082+#error
2083+#endif
20642084 }
20652085 }
20662086 #endif
@@ -2589,7 +2609,7 @@ ST_FUNC void vstore(void) · 522 unmodified lines
25892609 if ((vtop[-1].r & VT_VALMASK) == VT_LLOCAL) {
25902610 SValue sv;
25912611 t = get_reg(RC_INT);
2592−#ifdef TCC_TARGET_X86_64
2612+#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
25932613 sv.type.t = VT_PTR;
25942614 #else
25952615 sv.type.t = VT_INT;
@@ -2600,7 +2620,7 @@ ST_FUNC void vstore(void) · 4 unmodified lines
26002620 vtop[-1].r = t | VT_LVAL;
26012621 }
26022622 /* two word case handling : store second register at word + 4 (or +8 for x86-64) */
2603−#ifdef TCC_TARGET_X86_64
2623+#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
26042624 if (((ft & VT_BTYPE) == VT_QLONG) || ((ft & VT_BTYPE) == VT_QFLOAT)) {
26052625 int addr_type = VT_LLONG, load_size = 8, load_type = ((vtop->type.t & VT_BTYPE) == VT_QLONG) ? VT_LLONG : VT_DOUBLE;
26062626 #else
@@ -3098,6 +3118,13 @@ static int parse_btype(CType *type, AttributeDef *ad) · 491 unmodified lines
30983118 goto basic_type1;
30993119 }
31003120 break;
3121+#ifdef TCC_TARGET_ARM64
3122+ case TOK_UINT128:
3123+ /* GCC's __uint128_t appears in some Linux header files. Make it a
3124+ synonym for long double to get the size and alignment right. */
3125+ u = VT_LDOUBLE;
3126+ goto basic_type;
3127+#endif
31013128 case TOK_BOOL:
31023129 u = VT_BOOL;
31033130 goto basic_type;
@@ -3233,7 +3260,8 @@ the_end: · 129 unmodified lines
32333260
32343261 /* long is never used as type */
32353262 if ((t & VT_BTYPE) == VT_LONG)
3236−#if !defined TCC_TARGET_X86_64 || defined TCC_TARGET_PE
3263+#if (!defined TCC_TARGET_X86_64 && !defined TCC_TARGET_ARM64) || \
3264+ defined TCC_TARGET_PE
32373265 t = (t & ~VT_BTYPE) | VT_INT;
32383266 #else
32393267 t = (t & ~VT_BTYPE) | VT_LLONG;
@@ -3881,6 +3909,36 @@ ST_FUNC void unary(void) · 641 unmodified lines
38813909 break;
38823910 #endif
38833911 #endif
3912+
3913+#ifdef TCC_TARGET_ARM64
3914+ case TOK___va_start: {
3915+ next();
3916+ skip('(');
3917+ expr_eq();
3918+ skip(',');
3919+ expr_eq();
3920+ skip(')');
3921+ //xx check types
3922+ gen_va_start();
3923+ vpushi(0);
3924+ vtop->type.t = VT_VOID;
3925+ break;
3926+ }
3927+ case TOK___va_arg: {
3928+ CType type;
3929+ next();
3930+ skip('(');
3931+ expr_eq();
3932+ skip(',');
3933+ parse_type(&type);
3934+ skip(')');
3935+ //xx check types
3936+ gen_va_arg(&type);
3937+ vtop->type = type;
3938+ break;
3939+ }
3940+#endif
3941+
38843942 case TOK_INC:
38853943 case TOK_DEC:
38863944 t = tok;
@@ -4071,6 +4129,15 @@ ST_FUNC void unary(void) · 184 unmodified lines
40714129 if (!ret_nregs) {
40724130 /* get some space for the returned structure */
40734131 size = type_size(&s->type, &align);
4132+#ifdef TCC_TARGET_ARM64
4133+ /* On arm64, a small struct is return in registers.
4134+ It is much easier to write it to memory if we know
4135+ that we are allowed to write some extra bytes, so
4136+ round the allocated space up to a power of 2: */
4137+ if (size < 16)
4138+ while (size & (size - 1))
4139+ size = (size | (size - 1)) + 1;
4140+#endif
40744141 loc = (loc - size) & -align;
40754142 ret.type = s->type;
40764143 ret.r = VT_LOCAL | VT_LVAL;
@@ -4094,12 +4161,14 @@ ST_FUNC void unary(void) · 17 unmodified lines
40944161 ret.r2 = REG_QRET;
40954162 #endif
40964163 } else {
4164+#ifndef TCC_TARGET_ARM64
40974165 #ifdef TCC_TARGET_X86_64
40984166 if ((ret.type.t & VT_BTYPE) == VT_QLONG)
40994167 #else
41004168 if ((ret.type.t & VT_BTYPE) == VT_LLONG)
41014169 #endif
41024170 ret.r2 = REG_LRET;
4171+#endif
41034172 ret.r = REG_IRET;
41044173 }
41054174 ret.c.i = 0;
@@ -4717,6 +4786,10 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 611 unmodified lines
47174786 if (tok != ';') {
47184787 gexpr();
47194788 gen_assign_cast(&func_vt);
4789+#ifdef TCC_TARGET_ARM64
4790+ // Perhaps it would be better to use this for all backends:
4791+ greturn();
4792+#else
47204793 if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
47214794 CType type, ret_type;
47224795 int ret_align, ret_nregs;
@@ -4770,6 +4843,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 47 unmodified lines
47704843 } else {
47714844 gv(RC_IRET);
47724845 }
4846+#endif
47734847 vtop--; /* NOT vpop() because on x86 it would flush the fp stack */
47744848 }
47754849 skip(';');
@@ -5160,9 +5234,9 @@ static void init_putv(CType *type, Section *sec, unsigned long c, · 384 unmodified lines
51605234 /* XXX: generate error if incorrect relocation */
51615235 gen_assign_cast(&dtype);
51625236 bt = type->t & VT_BTYPE;
5163− /* we'll write at most 12 bytes */
5164− if (c + 12 > sec->data_allocated) {
5165− section_realloc(sec, c + 12);
5237+ /* we'll write at most 16 bytes */
5238+ if (c + 16 > sec->data_allocated) {
5239+ section_realloc(sec, c + 16);
51665240 }
51675241 ptr = sec->data + c;
51685242 /* XXX: make code faster ? */
@@ -5184,6 +5258,9 @@ static void init_putv(CType *type, Section *sec, unsigned long c, · 15 unmodified lines
51845258 (bt == VT_INT && bit_size != 32)))
51855259 tcc_error("initializer element is not computable at load time");
51865260 switch(bt) {
5261+ /* XXX: when cross-compiling we assume that each type has the
5262+ same representation on host and target, which is likely to
5263+ be wrong in the case of long double */
51875264 case VT_BOOL:
51885265 vtop->c.i = (vtop->c.i != 0);
51895266 case VT_BYTE:
@@ -5203,7 +5280,7 @@ static void init_putv(CType *type, Section *sec, unsigned long c, · 13 unmodified lines
52035280 break;
52045281 case VT_PTR: {
52055282 addr_t val = (vtop->c.ptr_offset & bit_mask) << bit_pos;
5206−#ifdef TCC_TARGET_X86_64
5283+#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
52075284 if (vtop->r & VT_SYM)
52085285 greloca(sec, vtop->sym, c, R_DATA_PTR, val);
52095286 else
@@ -5217,7 +5294,7 @@ static void init_putv(CType *type, Section *sec, unsigned long c, · 7 unmodified lines
52175294 }
52185295 default: {
52195296 int val = (vtop->c.i & bit_mask) << bit_pos;
5220−#ifdef TCC_TARGET_X86_64
5297+#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
52215298 if (vtop->r & VT_SYM)
52225299 greloca(sec, vtop->sym, c, R_DATA_PTR, val);
52235300 else
tccrun.c+21−0
@@ -604,6 +604,27 @@ static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level) · 603 unmodified lines
604604 }
605605 }
606606
607+/* ------------------------------------------------------------- */
608+#elif defined(__aarch64__)
609+
610+static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
611+{
612+ if (level < 0)
613+ return -1;
614+ else if (level == 0) {
615+ *paddr = uc->uc_mcontext.pc;
616+ return 0;
617+ }
618+ else {
619+ addr_t *fp = (addr_t *)uc->uc_mcontext.regs[29];
620+ int i;
621+ for (i = 1; i < level; i++)
622+ fp = (addr_t *)fp[0];
623+ *paddr = fp[1];
624+ return 0;
625+ }
626+}
627+
607628 /* ------------------------------------------------------------- */
608629 #else
609630
tcctok.h+33−0
@@ -59,6 +59,10 @@ · 58 unmodified lines
5959 DEF(TOK_ASM2, "__asm")
6060 DEF(TOK_ASM3, "__asm__")
6161
62+#ifdef TCC_TARGET_ARM64
63+ DEF(TOK_UINT128, "__uint128_t")
64+#endif
65+
6266 /*********************************************************************/
6367 /* the following are not keywords. They are included to ease parsing */
6468 /* preprocessor only */
@@ -136,6 +140,11 @@ · 71 unmodified lines
136140 DEF(TOK_REGPARM1, "regparm")
137141 DEF(TOK_REGPARM2, "__regparm__")
138142
143+#ifdef TCC_TARGET_ARM64
144+ DEF(TOK___va_start, "__va_start")
145+ DEF(TOK___va_arg, "__va_arg")
146+#endif
147+
139148 /* pragma */
140149 DEF(TOK_pack, "pack")
141150 #if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_X86_64)
@@ -229,6 +238,30 @@ · 87 unmodified lines
229238 #if defined TCC_TARGET_PE
230239 DEF(TOK___chkstk, "__chkstk")
231240 #endif
241+#ifdef TCC_TARGET_ARM64
242+ DEF(TOK___addtf3, "__addtf3")
243+ DEF(TOK___subtf3, "__subtf3")
244+ DEF(TOK___multf3, "__multf3")
245+ DEF(TOK___divtf3, "__divtf3")
246+ DEF(TOK___extendsftf2, "__extendsftf2")
247+ DEF(TOK___extenddftf2, "__extenddftf2")
248+ DEF(TOK___trunctfsf2, "__trunctfsf2")
249+ DEF(TOK___trunctfdf2, "__trunctfdf2")
250+ DEF(TOK___fixtfsi, "__fixtfsi")
251+ DEF(TOK___fixtfdi, "__fixtfdi")
252+ DEF(TOK___fixunstfsi, "__fixunstfsi")
253+ DEF(TOK___fixunstfdi, "__fixunstfdi")
254+ DEF(TOK___floatsitf, "__floatsitf")
255+ DEF(TOK___floatditf, "__floatditf")
256+ DEF(TOK___floatunsitf, "__floatunsitf")
257+ DEF(TOK___floatunditf, "__floatunditf")
258+ DEF(TOK___eqtf2, "__eqtf2")
259+ DEF(TOK___netf2, "__netf2")
260+ DEF(TOK___lttf2, "__lttf2")
261+ DEF(TOK___letf2, "__letf2")
262+ DEF(TOK___gttf2, "__gttf2")
263+ DEF(TOK___getf2, "__getf2")
264+#endif
232265
233266 /* bound checking symbols */
234267 #ifdef CONFIG_TCC_BCHECK

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t