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
70NATIVE_DEFINES_$(CONFIG_arm_eabihf) += -DTCC_ARM_EABI -DTCC_ARM_HARDFLOAT70NATIVE_DEFINES_$(CONFIG_arm_eabihf) += -DTCC_ARM_EABI -DTCC_ARM_HARDFLOAT
71NATIVE_DEFINES_$(CONFIG_arm_eabi) += -DTCC_ARM_EABI71NATIVE_DEFINES_$(CONFIG_arm_eabi) += -DTCC_ARM_EABI
72NATIVE_DEFINES_$(CONFIG_arm_vfp) += -DTCC_ARM_VFP72NATIVE_DEFINES_$(CONFIG_arm_vfp) += -DTCC_ARM_VFP
73NATIVE_DEFINES_$(CONFIG_arm64) += -DTCC_TARGET_ARM64
73NATIVE_DEFINES += $(NATIVE_DEFINES_yes)74NATIVE_DEFINES += $(NATIVE_DEFINES_yes)
74 75
75ifeq ($(TOP),.)76ifeq ($(TOP),.)
@@ -86,6 +87,7 @@ ARM_VFP_CROSS = arm-linux-gnu-tcc$(EXESUF) · 10 unmodified lines
86ARM_EABI_CROSS = arm-linux-gnueabi-tcc$(EXESUF)87ARM_EABI_CROSS = arm-linux-gnueabi-tcc$(EXESUF)
87ARM_EABIHF_CROSS = arm-linux-gnueabihf-tcc$(EXESUF)88ARM_EABIHF_CROSS = arm-linux-gnueabihf-tcc$(EXESUF)
88ARM_CROSS = $(ARM_FPA_CROSS) $(ARM_FPA_LD_CROSS) $(ARM_VFP_CROSS) $(ARM_EABI_CROSS)89ARM_CROSS = $(ARM_FPA_CROSS) $(ARM_FPA_LD_CROSS) $(ARM_VFP_CROSS) $(ARM_EABI_CROSS)
90ARM64_CROSS = arm64-tcc$(EXESUF)
89C67_CROSS = c67-tcc$(EXESUF)91C67_CROSS = c67-tcc$(EXESUF)
90 92
91# Legacy symlinks for cross compilers93# 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
107WINCE_FILES = $(CORE_FILES) arm-gen.c tccpe.c109WINCE_FILES = $(CORE_FILES) arm-gen.c tccpe.c
108X86_64_FILES = $(CORE_FILES) x86_64-gen.c i386-asm.c x86_64-asm.h110X86_64_FILES = $(CORE_FILES) x86_64-gen.c i386-asm.c x86_64-asm.h
109ARM_FILES = $(CORE_FILES) arm-gen.c111ARM_FILES = $(CORE_FILES) arm-gen.c
112ARM64_FILES = $(CORE_FILES) arm64-gen.c
110C67_FILES = $(CORE_FILES) c67-gen.c tcccoff.c113C67_FILES = $(CORE_FILES) c67-gen.c tcccoff.c
111 114
112ifdef CONFIG_WIN64115ifdef CONFIG_WIN64
113PROGS+=tiny_impdef$(EXESUF) tiny_libmaker$(EXESUF)116PROGS+=tiny_impdef$(EXESUF) tiny_libmaker$(EXESUF)
114NATIVE_FILES=$(WIN64_FILES)117NATIVE_FILES=$(WIN64_FILES)
115PROGS_CROSS=$(WIN32_CROSS) $(I386_CROSS) $(X64_CROSS) $(ARM_CROSS) $(C67_CROSS) $(WINCE_CROSS)118PROGS_CROSS=$(WIN32_CROSS) $(I386_CROSS) $(X64_CROSS) $(ARM_CROSS) $(ARM64_CROSS) $(C67_CROSS) $(WINCE_CROSS)
116LIBTCC1_CROSS=lib/i386-win32/libtcc1.a119LIBTCC1_CROSS=lib/i386-win32/libtcc1.a
117LIBTCC1=libtcc1.a120LIBTCC1=libtcc1.a
118else ifdef CONFIG_WIN32121else ifdef CONFIG_WIN32
119PROGS+=tiny_impdef$(EXESUF) tiny_libmaker$(EXESUF)122PROGS+=tiny_impdef$(EXESUF) tiny_libmaker$(EXESUF)
120NATIVE_FILES=$(WIN32_FILES)123NATIVE_FILES=$(WIN32_FILES)
121PROGS_CROSS=$(WIN64_CROSS) $(I386_CROSS) $(X64_CROSS) $(ARM_CROSS) $(C67_CROSS) $(WINCE_CROSS)124PROGS_CROSS=$(WIN64_CROSS) $(I386_CROSS) $(X64_CROSS) $(ARM_CROSS) $(ARM64_CROSS) $(C67_CROSS) $(WINCE_CROSS)
122LIBTCC1_CROSS=lib/x86_64-win32/libtcc1.a125LIBTCC1_CROSS=lib/x86_64-win32/libtcc1.a
123LIBTCC1=libtcc1.a126LIBTCC1=libtcc1.a
124else ifeq ($(ARCH),i386)127else ifeq ($(ARCH),i386)
125NATIVE_FILES=$(I386_FILES)128NATIVE_FILES=$(I386_FILES)
126PROGS_CROSS=$(X64_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(ARM_CROSS) $(C67_CROSS) $(WINCE_CROSS)129PROGS_CROSS=$(X64_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(ARM_CROSS) $(ARM64_CROSS) $(C67_CROSS) $(WINCE_CROSS)
127LIBTCC1_CROSS=lib/i386-win32/libtcc1.a lib/x86_64-win32/libtcc1.a130LIBTCC1_CROSS=lib/i386-win32/libtcc1.a lib/x86_64-win32/libtcc1.a
128LIBTCC1=libtcc1.a131LIBTCC1=libtcc1.a
129else ifeq ($(ARCH),x86-64)132else ifeq ($(ARCH),x86-64)
130NATIVE_FILES=$(X86_64_FILES)133NATIVE_FILES=$(X86_64_FILES)
131PROGS_CROSS=$(I386_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(ARM_CROSS) $(C67_CROSS) $(WINCE_CROSS)134PROGS_CROSS=$(I386_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(ARM_CROSS) $(ARM64_CROSS) $(C67_CROSS) $(WINCE_CROSS)
132LIBTCC1_CROSS=lib/i386-win32/libtcc1.a lib/x86_64-win32/libtcc1.a lib/i386/libtcc1.a135LIBTCC1_CROSS=lib/i386-win32/libtcc1.a lib/x86_64-win32/libtcc1.a lib/i386/libtcc1.a
133LIBTCC1=libtcc1.a136LIBTCC1=libtcc1.a
134else ifeq ($(ARCH),arm)137else ifeq ($(ARCH),arm)
135NATIVE_FILES=$(ARM_FILES)138NATIVE_FILES=$(ARM_FILES)
136PROGS_CROSS=$(I386_CROSS) $(X64_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(C67_CROSS) $(WINCE_CROSS)139PROGS_CROSS=$(I386_CROSS) $(X64_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(ARM64_CROSS) $(C67_CROSS) $(WINCE_CROSS)
140LIBTCC1=libtcc1.a
141LIBTCC1_CROSS=lib/i386-win32/libtcc1.a lib/x86_64-win32/libtcc1.a lib/i386/libtcc1.a
142else ifeq ($(ARCH),arm64)
143NATIVE_FILES=$(ARM64_FILES)
144PROGS_CROSS=$(I386_CROSS) $(X64_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(ARM_CROSS) $(C67_CROSS) $(WINCE_CROSS)
137LIBTCC1=libtcc1.a145LIBTCC1=libtcc1.a
138LIBTCC1_CROSS=lib/i386-win32/libtcc1.a lib/x86_64-win32/libtcc1.a lib/i386/libtcc1.a146LIBTCC1_CROSS=lib/i386-win32/libtcc1.a lib/x86_64-win32/libtcc1.a lib/i386/libtcc1.a
139endif147endif
@@ -181,6 +189,7 @@ $(ARM_FPA_CROSS): DEFINES = -DTCC_TARGET_ARM · 41 unmodified lines
181$(ARM_FPA_LD_CROSS)$(EXESUF): DEFINES = -DTCC_TARGET_ARM -DLDOUBLE_SIZE=12189$(ARM_FPA_LD_CROSS)$(EXESUF): DEFINES = -DTCC_TARGET_ARM -DLDOUBLE_SIZE=12
182$(ARM_VFP_CROSS): DEFINES = -DTCC_TARGET_ARM -DTCC_ARM_VFP -DCONFIG_MULTIARCHDIR="\"arm-linux-gnu\""190$(ARM_VFP_CROSS): DEFINES = -DTCC_TARGET_ARM -DTCC_ARM_VFP -DCONFIG_MULTIARCHDIR="\"arm-linux-gnu\""
183$(ARM_EABI_CROSS): DEFINES = -DTCC_TARGET_ARM -DTCC_ARM_EABI -DTCC_ARM_VFP -DCONFIG_MULTIARCHDIR="\"arm-linux-gnueabi\""191$(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
184 193
185$(I386_CROSS): $(I386_FILES)194$(I386_CROSS): $(I386_FILES)
186$(X64_CROSS): $(X86_64_FILES)195$(X64_CROSS): $(X86_64_FILES)
@@ -189,6 +198,7 @@ $(WIN64_CROSS): $(WIN64_FILES) · 2 unmodified lines
189$(WINCE_CROSS): $(WINCE_FILES)198$(WINCE_CROSS): $(WINCE_FILES)
190$(C67_CROSS): $(C67_FILES)199$(C67_CROSS): $(C67_FILES)
191$(ARM_FPA_CROSS) $(ARM_FPA_LD_CROSS) $(ARM_VFP_CROSS) $(ARM_EABI_CROSS): $(ARM_FILES)200$(ARM_FPA_CROSS) $(ARM_FPA_LD_CROSS) $(ARM_VFP_CROSS) $(ARM_EABI_CROSS): $(ARM_FILES)
201$(ARM64_CROSS): $(ARM64_FILES)
192 202
193# libtcc generation and test203# libtcc generation and test
194ifndef ONE_SOURCE204ifndef 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
62ST_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
95static uint32_t intr(int r)
96{
97 assert(TREG_R(0) <= r && r <= TREG_R30);
98 return r < TREG_R30 ? r : 30;
99}
100
101static 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:
108ST_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
117static 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
166static 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
203static 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:
221ST_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:
237ST_FUNC void gsym(int t)
238{
239 gsym_addr(t, ind);
240}
241
242static 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
261static 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
267static 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
284static 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
298static 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
375static 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
387static 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
401static 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
426ST_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
521ST_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
557static 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
571static 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
629static 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
643static 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
764static 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
803ST_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
973static unsigned long arm64_func_va_list_stack;
974static int arm64_func_va_list_gr_offs;
975static int arm64_func_va_list_vr_offs;
976static int arm64_func_sub_sp_offset;
977
978ST_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
1056ST_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
1092ST_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
1153ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align)
1154{
1155 return 0;
1156}
1157
1158ST_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
1204ST_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:
1243ST_FUNC int gjmp(int t)
1244{
1245 int r = ind;
1246 o(t);
1247 return r;
1248}
1249
1250// Generate branch to known address:
1251ST_FUNC void gjmp_addr(int a)
1252{
1253 assert(a - ind + 0x8000000 < 0x10000000);
1254 o(0x14000000 | ((a - ind) >> 2 & 0x3ffffff));
1255}
1256
1257ST_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
1288static 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
1391ST_FUNC void gen_opi(int op)
1392{
1393 arm64_gen_opil(op, 0);
1394}
1395
1396ST_FUNC void gen_opl(int op)
1397{
1398 arm64_gen_opil(op, 1);
1399}
1400
1401ST_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:
1501ST_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
1507ST_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
1535ST_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
1563ST_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
1600ST_FUNC void ggoto(void)
1601{
1602 arm64_gen_bl_or_b(1);
1603 --vtop;
1604}
1605
1606ST_FUNC void gen_vla_sp_save(int addr) {
1607 tcc_error("variable length arrays unsupported for this target");
1608}
1609
1610ST_FUNC void gen_vla_sp_restore(int addr) {
1611 tcc_error("variable length arrays unsupported for this target");
1612}
1613
1614ST_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
99 esac99 esac
100 cpu="armv4l"100 cpu="armv4l"
101 ;;101 ;;
102 aarch64)
103 cpu="aarch64"
104 ;;
102 alpha)105 alpha)
103 cpu="alpha"106 cpu="alpha"
104 ;;107 ;;
@@ -435,6 +438,9 @@ elif test "$cpu" = "armv4l" ; then · 330 unmodified lines
435 echo "ARCH=arm" >> config.mak438 echo "ARCH=arm" >> config.mak
436 echo "#define HOST_ARM 1" >> $TMPH439 echo "#define HOST_ARM 1" >> $TMPH
437 echo "#define TCC_ARM_VERSION $cpuver" >> $TMPH440 echo "#define TCC_ARM_VERSION $cpuver" >> $TMPH
441elif test "$cpu" = "aarch64" ; then
442 echo "ARCH=arm64" >> config.mak
443 echo "#define HOST_ARM64 1" >> $TMPH
438elif test "$cpu" = "powerpc" ; then444elif test "$cpu" = "powerpc" ; then
439 echo "ARCH=ppc" >> config.mak445 echo "ARCH=ppc" >> config.mak
440 echo "#define HOST_PPC 1" >> $TMPH446 echo "#define HOST_PPC 1" >> $TMPH
conftest.c+2−0
@@ -7,6 +7,8 @@ · 6 unmodified lines
7# define TRIPLET_ARCH "x86_64"7# define TRIPLET_ARCH "x86_64"
8#elif defined(__arm__)8#elif defined(__arm__)
9# define TRIPLET_ARCH "arm"9# define TRIPLET_ARCH "arm"
10#elif defined(__aarch64__)
11# define TRIPLET_ARCH "aarch64"
10#else12#else
11# define TRIPLET_ARCH "unknown"13# define TRIPLET_ARCH "unknown"
12#endif14#endif
elf.h+112−0
@@ -2336,6 +2336,117 @@ typedef Elf32_Addr Elf32_Conflict; · 2335 unmodified lines
2336#define R_AARCH64_NONE 0 /* No relocation. */2336#define R_AARCH64_NONE 0 /* No relocation. */
2337#define R_AARCH64_ABS64 257 /* Direct 64 bit. */2337#define R_AARCH64_ABS64 257 /* Direct 64 bit. */
2338#define R_AARCH64_ABS32 258 /* Direct 32 bit. */2338#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. */
2339#define R_AARCH64_COPY 1024 /* Copy symbol at runtime. */2450#define R_AARCH64_COPY 1024 /* Copy symbol at runtime. */
2340#define R_AARCH64_GLOB_DAT 1025 /* Create GOT entry. */2451#define R_AARCH64_GLOB_DAT 1025 /* Create GOT entry. */
2341#define R_AARCH64_JUMP_SLOT 1026 /* Create PLT entry. */2452#define R_AARCH64_JUMP_SLOT 1026 /* Create PLT entry. */
@@ -2344,6 +2455,7 @@ typedef Elf32_Addr Elf32_Conflict; · 2 unmodified lines
2344#define R_AARCH64_TLS_DTPREL64 1029 /* Module-relative offset, 64 bit. */2455#define R_AARCH64_TLS_DTPREL64 1029 /* Module-relative offset, 64 bit. */
2345#define R_AARCH64_TLS_TPREL64 1030 /* TP-relative offset, 64 bit. */2456#define R_AARCH64_TLS_TPREL64 1030 /* TP-relative offset, 64 bit. */
2346#define R_AARCH64_TLSDESC 1031 /* TLS Descriptor. */2457#define R_AARCH64_TLSDESC 1031 /* TLS Descriptor. */
2458#define R_AARCH64_IRELATIVE 1032 /* STT_GNU_IFUNC relocation. */
2347 2459
2348/* ARM relocs. */2460/* ARM relocs. */
2349 2461
include/stdarg.h+13−0
@@ -46,6 +46,19 @@ typedef char *va_list; · 45 unmodified lines
46#define va_copy(dest, src) (dest) = (src)46#define va_copy(dest, src) (dest) = (src)
47#define va_end(ap)47#define va_end(ap)
48 48
49#elif defined(__aarch64__)
50typedef 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
49#else /* __i386__ */62#else /* __i386__ */
50typedef char *va_list;63typedef char *va_list;
51/* only correct for i386 */64/* only correct for i386 */
lib/Makefile+12−0
@@ -28,6 +28,11 @@ ifndef TARGET # native library · 27 unmodified lines
28 ifeq ($(ARCH),arm)28 ifeq ($(ARCH),arm)
29 TARGET = arm29 TARGET = arm
30 XCC = $(CC)30 XCC = $(CC)
31 else
32 ifeq ($(ARCH),arm64)
33 TARGET = arm64
34 else
35 endif
31 endif36 endif
32 endif37 endif
33 endif38 endif
@@ -49,6 +54,7 @@ X86_64_O = libtcc1.o alloca86_64.o · 15 unmodified lines
49ARM_O = libtcc1.o armeabi.o alloca-arm.o54ARM_O = libtcc1.o armeabi.o alloca-arm.o
50WIN32_O = $(I386_O) crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o55WIN32_O = $(I386_O) crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o
51WIN64_O = $(X86_64_O) crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o56WIN64_O = $(X86_64_O) crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o
57ARM64_O = lib-arm64.o
52 58
53# build TCC runtime library to contain PIC code, so it can be linked59# build TCC runtime library to contain PIC code, so it can be linked
54# into shared libraries60# into shared libraries
@@ -86,6 +92,11 @@ ifeq "$(TARGET)" "arm" · 31 unmodified lines
86 OBJ = $(addprefix $(DIR)/,$(ARM_O))92 OBJ = $(addprefix $(DIR)/,$(ARM_O))
87 TGT = -DTCC_TARGET_ARM93 TGT = -DTCC_TARGET_ARM
88 XCC ?= $(TCC) -B$(TOP)94 XCC ?= $(TCC) -B$(TOP)
95else
96ifeq "$(TARGET)" "arm64"
97 OBJ = $(addprefix $(DIR)/,$(ARM64_O))
98 TGT = -DTCC_TARGET_ARM64
99 XCC ?= $(TCC) -B$(TOP)
89else100else
90 $(error libtcc1.a not supported on target '$(TARGET)')101 $(error libtcc1.a not supported on target '$(TARGET)')
91endif102endif
@@ -93,6 +104,7 @@ endif · 1 unmodified line
93endif104endif
94endif105endif
95endif106endif
107endif
96 108
97XFLAGS = $(CPPFLAGS) $(CFLAGS) $(PICFLAGS) $(TGT)109XFLAGS = $(CPPFLAGS) $(CFLAGS) $(PICFLAGS) $(TGT)
98 110
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
15void __clear_cache(char *beg, char *end)
16{
17#warning __clear_cache not yet implemented
18}
19
20typedef struct {
21 uint64_t x0, x1;
22} u128_t;
23
24static 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
32static 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
40static 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
54static 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
62static 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
81static 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
95static 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
115static 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
134static 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
172static 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
235long double __addtf3(long double a, long double b)
236{
237 return f3_add(a, b, 0);
238}
239
240long double __subtf3(long double a, long double b)
241{
242 return f3_add(a, b, 1);
243}
244
245long 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
310long 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
362long 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
383long 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
401float __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
432double __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
464int32_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
479int64_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
494uint32_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
507uint64_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
520long 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
545long 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
570long 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
589long 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
609static 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
624int __eqtf2(long double a, long double b)
625{
626 return !!f3_cmp(a, b);
627}
628
629int __netf2(long double a, long double b)
630{
631 return !!f3_cmp(a, b);
632}
633
634int __lttf2(long double a, long double b)
635{
636 return f3_cmp(a, b);
637}
638
639int __letf2(long double a, long double b)
640{
641 return f3_cmp(a, b);
642}
643
644int __gttf2(long double a, long double b)
645{
646 return -f3_cmp(b, a);
647}
648
649int __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
20void 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
26typedef struct {
27 unsigned long long x0, x1;
28} u128_t;
29
30float copy_fi(uint32_t x)
31{
32 float f;
33 memcpy(&f, &x, 4);
34 return f;
35}
36
37double copy_di(uint64_t x)
38{
39 double f;
40 memcpy(&f, &x, 8);
41 return f;
42}
43
44long double copy_ldi(u128_t x)
45{
46 long double f;
47 memcpy(&f, &x, 16);
48 return f;
49}
50
51uint32_t copy_if(float f)
52{
53 uint32_t x;
54 memcpy(&x, &f, 4);
55 return x;
56}
57
58uint64_t copy_id(double f)
59{
60 uint64_t x;
61 memcpy(&x, &f, 8);
62 return x;
63}
64
65u128_t copy_ild(long double f)
66{
67 u128_t x;
68 memcpy(&x, &f, 16);
69 return x;
70}
71
72long 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
81void 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
102void 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
139void 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
148void fadd(long double a, long double b)
149{
150 xop("add", a, b, a + b);
151}
152
153void fsub(long double a, long double b)
154{
155 xop("sub", a, b, a - b);
156}
157
158void fmul(long double a, long double b)
159{
160 xop("mul", a, b, a * b);
161}
162
163void fdiv(long double a, long double b)
164{
165 xop("div", a, b, a / b);
166}
167
168void 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
214void 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
253void 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
283void 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
302void 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
309void 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
317void 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
324void 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
331void 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
348void 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
356void 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
364void 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
372void 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
380void 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
491void tests(void)
492{
493 cmps();
494 nanz();
495 adds();
496 muls();
497 divs();
498 cvts();
499}
500
501int 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
45#ifdef TCC_TARGET_ARM45#ifdef TCC_TARGET_ARM
46#include "arm-gen.c"46#include "arm-gen.c"
47#endif47#endif
48#ifdef TCC_TARGET_ARM64
49#include "arm64-gen.c"
50#endif
48#ifdef TCC_TARGET_C6751#ifdef TCC_TARGET_C67
49#include "c67-gen.c"52#include "c67-gen.c"
50#endif53#endif
@@ -959,6 +962,8 @@ LIBTCCAPI TCCState *tcc_new(void) · 908 unmodified lines
959#else962#else
960 s->float_abi = ARM_SOFTFP_FLOAT;963 s->float_abi = ARM_SOFTFP_FLOAT;
961#endif964#endif
965#elif defined(TCC_TARGET_ARM64)
966 tcc_define_symbol(s, "__aarch64__", NULL);
962#endif967#endif
963 968
964#ifdef TCC_TARGET_PE969#ifdef TCC_TARGET_PE
@@ -1560,7 +1565,7 @@ static int tcc_set_linker(TCCState *s, const char *option) · 595 unmodified lines
1560 } else if (link_option(option, "oformat=", &p)) {1565 } else if (link_option(option, "oformat=", &p)) {
1561#if defined(TCC_TARGET_PE)1566#if defined(TCC_TARGET_PE)
1562 if (strstart("pe-", &p)) {1567 if (strstart("pe-", &p)) {
1563#elif defined(TCC_TARGET_X86_64)1568#elif defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
1564 if (strstart("elf64-", &p)) {1569 if (strstart("elf64-", &p)) {
1565#else1570#else
1566 if (strstart("elf32-", &p)) {1571 if (strstart("elf32-", &p)) {
tcc.c+2−0
@@ -203,6 +203,8 @@ static void display_info(TCCState *s, int what) · 202 unmodified lines
203# endif203# endif
204#elif defined TCC_TARGET_ARM204#elif defined TCC_TARGET_ARM
205 "ARM"205 "ARM"
206#elif defined TCC_TARGET_ARM64
207 "AArch64"
206# ifdef TCC_ARM_HARDFLOAT208# ifdef TCC_ARM_HARDFLOAT
207 " Hard Float"209 " Hard Float"
208# endif210# endif
tcc.h+25−5
@@ -113,7 +113,7 @@ · 112 unmodified lines
113#endif113#endif
114 114
115#include "elf.h"115#include "elf.h"
116#ifdef TCC_TARGET_X86_64116#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
117# define ELFCLASSW ELFCLASS64117# define ELFCLASSW ELFCLASS64
118# define ElfW(type) Elf##64##_##type118# define ElfW(type) Elf##64##_##type
119# define ELFW(type) ELF##64##_##type119# define ELFW(type) ELF##64##_##type
@@ -151,23 +151,26 @@ · 31 unmodified lines
151/* target selection */151/* target selection */
152/* #define TCC_TARGET_I386 *//* i386 code generator */152/* #define TCC_TARGET_I386 *//* i386 code generator */
153/* #define TCC_TARGET_ARM *//* ARMv4 code generator */153/* #define TCC_TARGET_ARM *//* ARMv4 code generator */
154/* #define TCC_TARGET_ARM64 *//* ARMv8 code generator */
154/* #define TCC_TARGET_C67 *//* TMS320C67xx code generator */155/* #define TCC_TARGET_C67 *//* TMS320C67xx code generator */
155/* #define TCC_TARGET_X86_64 *//* x86-64 code generator */156/* #define TCC_TARGET_X86_64 *//* x86-64 code generator */
156 157
157/* default target is I386 */158/* default target is I386 */
158#if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_ARM) && \159#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)
160#define TCC_TARGET_I386162#define TCC_TARGET_I386
161#endif163#endif
162 164
163#if !defined(TCC_UCLIBC) && !defined(TCC_TARGET_ARM) && \165#if !defined(TCC_UCLIBC) && !defined(TCC_TARGET_ARM) && \
164 !defined(TCC_TARGET_C67) && !defined(TCC_TARGET_X86_64) && \166 !defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_C67) && \
165 !defined(CONFIG_USE_LIBGCC)167 !defined(TCC_TARGET_X86_64) && !defined(CONFIG_USE_LIBGCC)
166#define CONFIG_TCC_BCHECK /* enable bound checking code */168#define CONFIG_TCC_BCHECK /* enable bound checking code */
167#endif169#endif
168 170
169/* define it to include assembler support */171/* 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)
171#define CONFIG_TCC_ASM174#define CONFIG_TCC_ASM
172#endif175#endif
173 176
@@ -184,6 +187,8 @@ · 10 unmodified lines
184# define TCC_IS_NATIVE187# define TCC_IS_NATIVE
185# elif defined __arm__ && defined TCC_TARGET_ARM188# elif defined __arm__ && defined TCC_TARGET_ARM
186# define TCC_IS_NATIVE189# define TCC_IS_NATIVE
190# elif defined __aarch64__ && defined TCC_TARGET_ARM64
191# define TCC_IS_NATIVE
187# endif192# endif
188#endif193#endif
189 194
@@ -256,6 +261,8 @@ · 66 unmodified lines
256# define CONFIG_TCC_ELFINTERP "/usr/libexec/ld-elf.so.2"261# define CONFIG_TCC_ELFINTERP "/usr/libexec/ld-elf.so.2"
257# elif defined __GNU__262# elif defined __GNU__
258# define CONFIG_TCC_ELFINTERP "/lib/ld.so"263# define CONFIG_TCC_ELFINTERP "/lib/ld.so"
264# elif defined TCC_TARGET_ARM64
265# define CONFIG_TCC_ELFINTERP "/lib/ld-linux-aarch64.so.1"
259# elif defined(TCC_TARGET_X86_64)266# elif defined(TCC_TARGET_X86_64)
260# define CONFIG_TCC_ELFINTERP "/lib64/ld-linux-x86-64.so.2"267# define CONFIG_TCC_ELFINTERP "/lib64/ld-linux-x86-64.so.2"
261# elif defined(TCC_UCLIBC)268# elif defined(TCC_UCLIBC)
@@ -290,6 +297,9 @@ · 28 unmodified lines
290#ifdef TCC_TARGET_ARM297#ifdef TCC_TARGET_ARM
291# include "arm-gen.c"298# include "arm-gen.c"
292#endif299#endif
300#ifdef TCC_TARGET_ARM64
301# include "arm64-gen.c"
302#endif
293#ifdef TCC_TARGET_C67303#ifdef TCC_TARGET_C67
294# include "coff.h"304# include "coff.h"
295# include "c67-gen.c"305# include "c67-gen.c"
@@ -1214,6 +1224,7 @@ ST_FUNC void vpushv(SValue *v); · 918 unmodified lines
1214ST_FUNC void save_reg(int r);1224ST_FUNC void save_reg(int r);
1215ST_FUNC int get_reg(int rc);1225ST_FUNC int get_reg(int rc);
1216ST_FUNC void save_regs(int n);1226ST_FUNC void save_regs(int n);
1227ST_FUNC void gaddrof(void);
1217ST_FUNC int gv(int rc);1228ST_FUNC int gv(int rc);
1218ST_FUNC void gv2(int rc1, int rc2);1229ST_FUNC void gv2(int rc1, int rc2);
1219ST_FUNC void vpop(void);1230ST_FUNC void vpop(void);
@@ -1357,6 +1368,15 @@ ST_FUNC uint32_t encbranch(int pos, int addr, int fail); · 137 unmodified lines
1357ST_FUNC void gen_cvt_itof1(int t);1368ST_FUNC void gen_cvt_itof1(int t);
1358#endif1369#endif
1359 1370
1371/* ------------ arm64-gen.c ------------ */
1372#ifdef TCC_TARGET_ARM64
1373ST_FUNC void gen_cvt_sxtw(void);
1374ST_FUNC void gen_opl(int op);
1375ST_FUNC void greturn(void);
1376ST_FUNC void gen_va_start(void);
1377ST_FUNC void gen_va_arg(CType *t);
1378#endif
1379
1360/* ------------ c67-gen.c ------------ */1380/* ------------ c67-gen.c ------------ */
1361#ifdef TCC_TARGET_C671381#ifdef TCC_TARGET_C67
1362#endif1382#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
291 rel = section_ptr_add(sr, sizeof(ElfW_Rel));291 rel = section_ptr_add(sr, sizeof(ElfW_Rel));
292 rel->r_offset = offset;292 rel->r_offset = offset;
293 rel->r_info = ELFW(R_INFO)(symbol, type);293 rel->r_info = ELFW(R_INFO)(symbol, type);
294#ifdef TCC_TARGET_X86_64294#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
295 rel->r_addend = addend;295 rel->r_addend = addend;
296#else296#else
297 if (addend)297 if (addend)
@@ -506,7 +506,7 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s) · 208 unmodified lines
506 sym_index = ELFW(R_SYM)(rel->r_info);506 sym_index = ELFW(R_SYM)(rel->r_info);
507 sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];507 sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
508 val = sym->st_value;508 val = sym->st_value;
509#ifdef TCC_TARGET_X86_64509#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
510 val += rel->r_addend;510 val += rel->r_addend;
511#endif511#endif
512 type = ELFW(R_TYPE)(rel->r_info);512 type = ELFW(R_TYPE)(rel->r_info);
@@ -760,6 +760,69 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s) · 247 unmodified lines
760 fprintf(stderr,"FIXME: handle reloc type %x at %x [%p] to %x\n",760 fprintf(stderr,"FIXME: handle reloc type %x at %x [%p] to %x\n",
761 type, (unsigned)addr, ptr, (unsigned)val);761 type, (unsigned)addr, ptr, (unsigned)val);
762 break;762 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;
763#elif defined(TCC_TARGET_C67)826#elif defined(TCC_TARGET_C67)
764 case R_C60_32:827 case R_C60_32:
765 *(int *)ptr += val;828 *(int *)ptr += val;
@@ -955,7 +1018,7 @@ static void put32(unsigned char *p, uint32_t val) · 189 unmodified lines
955}1018}
956 1019
957#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_ARM) || \1020#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)
959static uint32_t get32(unsigned char *p)1022static uint32_t get32(unsigned char *p)
960{1023{
961 return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);1024 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
1014 (reloc_type == R_386_JMP_SLOT);1077 (reloc_type == R_386_JMP_SLOT);
1015#elif defined(TCC_TARGET_ARM)1078#elif defined(TCC_TARGET_ARM)
1016 (reloc_type == R_ARM_JUMP_SLOT);1079 (reloc_type == R_ARM_JUMP_SLOT);
1080#elif defined(TCC_TARGET_ARM64)
1081 (reloc_type == R_AARCH64_JUMP_SLOT);
1017#else1082#else
1018 0;1083 0;
1019#endif1084#endif
@@ -1135,6 +1200,24 @@ static unsigned long put_got_entry(TCCState *s1, · 115 unmodified lines
1135 if (sym->st_shndx == SHN_UNDEF)1200 if (sym->st_shndx == SHN_UNDEF)
1136 offset = plt->data_offset - 16;1201 offset = plt->data_offset - 16;
1137 }1202 }
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 }
1138#elif defined(TCC_TARGET_C67)1221#elif defined(TCC_TARGET_C67)
1139 if (s1->dynsym) {1222 if (s1->dynsym) {
1140 tcc_error("C67 got not implemented");1223 tcc_error("C67 got not implemented");
@@ -1277,6 +1360,18 @@ ST_FUNC void build_got_entries(TCCState *s1) · 136 unmodified lines
1277 put32(p+2, 0x46c0); /* nop */1360 put32(p+2, 0x46c0); /* nop */
1278 put32(p+4, 0xeafffffe); /* b $sym */1361 put32(p+4, 0xeafffffe); /* b $sym */
1279 }1362 }
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;
1280#elif defined(TCC_TARGET_C67)1375#elif defined(TCC_TARGET_C67)
1281 case R_C60_GOT32:1376 case R_C60_GOT32:
1282 case R_C60_GOTOFF:1377 case R_C60_GOTOFF:
@@ -1796,6 +1891,40 @@ ST_FUNC void relocate_plt(TCCState *s1) · 513 unmodified lines
1796 put32(p + 12, x + get32(p + 12) + s1->plt->data - p);1891 put32(p + 12, x + get32(p + 12) + s1->plt->data - p);
1797 p += 16;1892 p += 16;
1798 }1893 }
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 }
1799#elif defined(TCC_TARGET_C67)1928#elif defined(TCC_TARGET_C67)
1800 /* XXX: TODO */1929 /* XXX: TODO */
1801#else1930#else
@@ -2093,7 +2222,7 @@ static void fill_dynamic(TCCState *s1, struct dyn_inf *dyninf) · 291 unmodified lines
2093 put_dt(dynamic, DT_SYMTAB, s1->dynsym->sh_addr);2222 put_dt(dynamic, DT_SYMTAB, s1->dynsym->sh_addr);
2094 put_dt(dynamic, DT_STRSZ, dyninf->dynstr->data_offset);2223 put_dt(dynamic, DT_STRSZ, dyninf->dynstr->data_offset);
2095 put_dt(dynamic, DT_SYMENT, sizeof(ElfW(Sym)));2224 put_dt(dynamic, DT_SYMENT, sizeof(ElfW(Sym)));
2096#ifdef TCC_TARGET_X86_642225#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
2097 put_dt(dynamic, DT_RELA, dyninf->rel_addr);2226 put_dt(dynamic, DT_RELA, dyninf->rel_addr);
2098 put_dt(dynamic, DT_RELASZ, dyninf->rel_size);2227 put_dt(dynamic, DT_RELASZ, dyninf->rel_size);
2099 put_dt(dynamic, DT_RELAENT, sizeof(ElfW_Rel));2228 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
545 type = &p->type;545 type = &p->type;
546 if ((p->r & VT_LVAL) ||546 if ((p->r & VT_LVAL) ||
547 (!is_float(type->t) && (type->t & VT_BTYPE) != VT_LLONG))547 (!is_float(type->t) && (type->t & VT_BTYPE) != VT_LLONG))
548#ifdef TCC_TARGET_X86_64548#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
549 type = &char_pointer_type;549 type = &char_pointer_type;
550#else550#else
551 type = &int_type;551 type = &int_type;
@@ -562,7 +562,7 @@ ST_FUNC void save_reg(int r) · 10 unmodified lines
562 o(0xd8dd); /* fstp %st(0) */562 o(0xd8dd); /* fstp %st(0) */
563 }563 }
564#endif564#endif
565#ifndef TCC_TARGET_X86_64565#if !defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_X86_64)
566 /* special long long case */566 /* special long long case */
567 if ((type->t & VT_BTYPE) == VT_LLONG) {567 if ((type->t & VT_BTYPE) == VT_LLONG) {
568 sv.c.ul += 4;568 sv.c.ul += 4;
@@ -681,7 +681,7 @@ static void move_reg(int r, int s, int t) · 112 unmodified lines
681}681}
682 682
683/* get address of vtop (vtop MUST BE an lvalue) */683/* get address of vtop (vtop MUST BE an lvalue) */
684static void gaddrof(void)684ST_FUNC void gaddrof(void)
685{685{
686 if (vtop->r & VT_REF)686 if (vtop->r & VT_REF)
687 gv(RC_INT);687 gv(RC_INT);
@@ -803,11 +803,13 @@ ST_FUNC int gv(int rc) · 115 unmodified lines
803 803
804 r = vtop->r & VT_VALMASK;804 r = vtop->r & VT_VALMASK;
805 rc2 = (rc & RC_FLOAT) ? RC_FLOAT : RC_INT;805 rc2 = (rc & RC_FLOAT) ? RC_FLOAT : RC_INT;
806#ifndef TCC_TARGET_ARM64
806 if (rc == RC_IRET)807 if (rc == RC_IRET)
807 rc2 = RC_LRET;808 rc2 = RC_LRET;
808#ifdef TCC_TARGET_X86_64809#ifdef TCC_TARGET_X86_64
809 else if (rc == RC_FRET)810 else if (rc == RC_FRET)
810 rc2 = RC_QRET;811 rc2 = RC_QRET;
812#endif
811#endif813#endif
812 814
813 /* need to reload if:815 /* need to reload if:
@@ -817,7 +819,7 @@ ST_FUNC int gv(int rc) · 3 unmodified lines
817 if (r >= VT_CONST819 if (r >= VT_CONST
818 || (vtop->r & VT_LVAL)820 || (vtop->r & VT_LVAL)
819 || !(reg_classes[r] & rc)821 || !(reg_classes[r] & rc)
820#ifdef TCC_TARGET_X86_64822#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
821 || ((vtop->type.t & VT_BTYPE) == VT_QLONG && !(reg_classes[vtop->r2] & rc2))823 || ((vtop->type.t & VT_BTYPE) == VT_QLONG && !(reg_classes[vtop->r2] & rc2))
822 || ((vtop->type.t & VT_BTYPE) == VT_QFLOAT && !(reg_classes[vtop->r2] & rc2))824 || ((vtop->type.t & VT_BTYPE) == VT_QFLOAT && !(reg_classes[vtop->r2] & rc2))
823#else825#else
@@ -826,7 +828,7 @@ ST_FUNC int gv(int rc) · 2 unmodified lines
826 )828 )
827 {829 {
828 r = get_reg(rc);830 r = get_reg(rc);
829#ifdef TCC_TARGET_X86_64831#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
830 if (((vtop->type.t & VT_BTYPE) == VT_QLONG) || ((vtop->type.t & VT_BTYPE) == VT_QFLOAT)) {832 if (((vtop->type.t & VT_BTYPE) == VT_QLONG) || ((vtop->type.t & VT_BTYPE) == VT_QFLOAT)) {
831 int addr_type = VT_LLONG, load_size = 8, load_type = ((vtop->type.t & VT_BTYPE) == VT_QLONG) ? VT_LLONG : VT_DOUBLE;833 int addr_type = VT_LLONG, load_size = 8, load_type = ((vtop->type.t & VT_BTYPE) == VT_QLONG) ? VT_LLONG : VT_DOUBLE;
832#else834#else
@@ -838,7 +840,7 @@ ST_FUNC int gv(int rc) · 5 unmodified lines
838 original_type = vtop->type.t;840 original_type = vtop->type.t;
839 /* two register type load : expand to two words841 /* two register type load : expand to two words
840 temporarily */842 temporarily */
841#ifndef TCC_TARGET_X86_64843#if !defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_X86_64)
842 if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {844 if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
843 /* load constant */845 /* load constant */
844 ll = vtop->c.ull;846 ll = vtop->c.ull;
@@ -890,7 +892,7 @@ ST_FUNC int gv(int rc) · 45 unmodified lines
890 t1 = t;892 t1 = t;
891 /* compute memory access type */893 /* compute memory access type */
892 if (vtop->r & VT_REF)894 if (vtop->r & VT_REF)
893#ifdef TCC_TARGET_X86_64895#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
894 t = VT_PTR;896 t = VT_PTR;
895#else897#else
896 t = VT_INT;898 t = VT_INT;
@@ -952,6 +954,7 @@ ST_FUNC void gv2(int rc1, int rc2) · 55 unmodified lines
952 }954 }
953}955}
954 956
957#ifndef TCC_TARGET_ARM64
955/* wrapper around RC_FRET to return a register by type */958/* wrapper around RC_FRET to return a register by type */
956static int rc_fret(int t)959static int rc_fret(int t)
957{960{
@@ -962,6 +965,7 @@ static int rc_fret(int t) · 4 unmodified lines
962#endif965#endif
963 return RC_FRET;966 return RC_FRET;
964}967}
968#endif
965 969
966/* wrapper around REG_FRET to return a register by type */970/* wrapper around REG_FRET to return a register by type */
967static int reg_fret(int t)971static int reg_fret(int t)
@@ -1147,7 +1151,7 @@ ST_FUNC int gvtst(int inv, int t) · 179 unmodified lines
1147 return gtst(inv, t);1151 return gtst(inv, t);
1148}1152}
1149 1153
1150#ifndef TCC_TARGET_X86_641154#if !defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_X86_64)
1151/* generate CPU independent (unsigned) long long operations */1155/* generate CPU independent (unsigned) long long operations */
1152static void gen_opl(int op)1156static void gen_opl(int op)
1153{1157{
@@ -1358,7 +1362,7 @@ static void gen_opl(int op) · 204 unmodified lines
1358#elif defined(TCC_TARGET_ARM)1362#elif defined(TCC_TARGET_ARM)
1359 b = ind;1363 b = ind;
1360 o(0x1A000000 | encbranch(ind, 0, 1));1364 o(0x1A000000 | encbranch(ind, 0, 1));
1361#elif defined(TCC_TARGET_C67)1365#elif defined(TCC_TARGET_C67) || defined(TCC_TARGET_ARM64)
1362 tcc_error("not implemented");1366 tcc_error("not implemented");
1363#else1367#else
1364#error not supported1368#error not supported
@@ -1512,7 +1516,8 @@ static void gen_opic(int op) · 147 unmodified lines
1512 general_case:1516 general_case:
1513 if (!nocode_wanted) {1517 if (!nocode_wanted) {
1514 /* call low level op generator */1518 /* 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)))
1516 gen_opl(op);1521 gen_opl(op);
1517 else1522 else
1518 gen_opi(op);1523 gen_opi(op);
@@ -1679,7 +1684,7 @@ ST_FUNC void gen_op(int op) · 160 unmodified lines
1679 if (op >= TOK_ULT && op <= TOK_LOR) {1684 if (op >= TOK_ULT && op <= TOK_LOR) {
1680 check_comparison_pointer_types(vtop - 1, vtop, op);1685 check_comparison_pointer_types(vtop - 1, vtop, op);
1681 /* pointers are handled are unsigned */1686 /* pointers are handled are unsigned */
1682#ifdef TCC_TARGET_X86_641687#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
1683 t = VT_LLONG | VT_UNSIGNED;1688 t = VT_LLONG | VT_UNSIGNED;
1684#else1689#else
1685 t = VT_INT | VT_UNSIGNED;1690 t = VT_INT | VT_UNSIGNED;
@@ -1700,7 +1705,7 @@ ST_FUNC void gen_op(int op) · 14 unmodified lines
1700 vrott(3);1705 vrott(3);
1701 gen_opic(op);1706 gen_opic(op);
1702 /* set to integer type */1707 /* set to integer type */
1703#ifdef TCC_TARGET_X86_641708#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
1704 vtop->type.t = VT_LLONG;1709 vtop->type.t = VT_LLONG;
1705#else1710#else
1706 vtop->type.t = VT_INT; 1711 vtop->type.t = VT_INT;
@@ -1724,7 +1729,7 @@ ST_FUNC void gen_op(int op) · 17 unmodified lines
1724 u = pointed_size(&vtop[-1].type);1729 u = pointed_size(&vtop[-1].type);
1725 if (u < 0)1730 if (u < 0)
1726 tcc_error("unknown array element size");1731 tcc_error("unknown array element size");
1727#ifdef TCC_TARGET_X86_641732#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
1728 vpushll(u);1733 vpushll(u);
1729#else1734#else
1730 /* XXX: cast to int ? (long long case) */1735 /* XXX: cast to int ? (long long case) */
@@ -1833,6 +1838,9 @@ ST_FUNC void gen_op(int op) · 102 unmodified lines
1833/* generic itof for unsigned long long case */1838/* generic itof for unsigned long long case */
1834static void gen_cvt_itof1(int t)1839static void gen_cvt_itof1(int t)
1835{1840{
1841#ifdef TCC_TARGET_ARM64
1842 gen_cvt_itof(t);
1843#else
1836 if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) == 1844 if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) ==
1837 (VT_LLONG | VT_UNSIGNED)) {1845 (VT_LLONG | VT_UNSIGNED)) {
1838 1846
@@ -1851,12 +1859,16 @@ static void gen_cvt_itof1(int t) · 12 unmodified lines
1851 } else {1859 } else {
1852 gen_cvt_itof(t);1860 gen_cvt_itof(t);
1853 }1861 }
1862#endif
1854}1863}
1855#endif1864#endif
1856 1865
1857/* generic ftoi for unsigned long long case */1866/* generic ftoi for unsigned long long case */
1858static void gen_cvt_ftoi1(int t)1867static void gen_cvt_ftoi1(int t)
1859{1868{
1869#ifdef TCC_TARGET_ARM64
1870 gen_cvt_ftoi(t);
1871#else
1860 int st;1872 int st;
1861 1873
1862 if (t == (VT_LLONG | VT_UNSIGNED)) {1874 if (t == (VT_LLONG | VT_UNSIGNED)) {
@@ -1878,6 +1890,7 @@ static void gen_cvt_ftoi1(int t) · 15 unmodified lines
1878 } else {1890 } else {
1879 gen_cvt_ftoi(t);1891 gen_cvt_ftoi(t);
1880 }1892 }
1893#endif
1881}1894}
1882 1895
1883/* force char or short cast */1896/* force char or short cast */
@@ -1968,7 +1981,7 @@ static void gen_cast(CType *type) · 84 unmodified lines
1968 vtop->c.ll = vtop->c.ull;1981 vtop->c.ll = vtop->c.ull;
1969 else if (sbt & VT_UNSIGNED)1982 else if (sbt & VT_UNSIGNED)
1970 vtop->c.ll = vtop->c.ui;1983 vtop->c.ll = vtop->c.ui;
1971#ifdef TCC_TARGET_X86_641984#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
1972 else if (sbt == VT_PTR)1985 else if (sbt == VT_PTR)
1973 ;1986 ;
1974#endif1987#endif
@@ -1979,7 +1992,7 @@ static void gen_cast(CType *type) · 4 unmodified lines
1979 vtop->c.ull = vtop->c.ll;1992 vtop->c.ull = vtop->c.ll;
1980 else if (dbt == VT_BOOL)1993 else if (dbt == VT_BOOL)
1981 vtop->c.i = (vtop->c.ll != 0);1994 vtop->c.i = (vtop->c.ll != 0);
1982#ifdef TCC_TARGET_X86_641995#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
1983 else if (dbt == VT_PTR)1996 else if (dbt == VT_PTR)
1984 ;1997 ;
1985#endif1998#endif
@@ -2024,7 +2037,7 @@ static void gen_cast(CType *type) · 38 unmodified lines
2024 gen_cast(type);2037 gen_cast(type);
2025 }2038 }
2026 }2039 }
2027#ifndef TCC_TARGET_X86_642040#if !defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_X86_64)
2028 } else if ((dbt & VT_BTYPE) == VT_LLONG) {2041 } else if ((dbt & VT_BTYPE) == VT_LLONG) {
2029 if ((sbt & VT_BTYPE) != VT_LLONG) {2042 if ((sbt & VT_BTYPE) != VT_LLONG) {
2030 /* scalar to long long */2043 /* scalar to long long */
@@ -2056,11 +2069,18 @@ static void gen_cast(CType *type) · 25 unmodified lines
2056 (sbt & VT_BTYPE) != VT_PTR &&2069 (sbt & VT_BTYPE) != VT_PTR &&
2057 (sbt & VT_BTYPE) != VT_FUNC) {2070 (sbt & VT_BTYPE) != VT_FUNC) {
2058 /* need to convert from 32bit to 64bit */2071 /* need to convert from 32bit to 64bit */
2059 int r = gv(RC_INT);2072 gv(RC_INT);
2060 if (sbt != (VT_INT | VT_UNSIGNED)) {2073 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);
2061 /* x86_64 specific: movslq */2078 /* x86_64 specific: movslq */
2062 o(0x6348);2079 o(0x6348);
2063 o(0xc0 + (REG_VALUE(r) << 3) + REG_VALUE(r));2080 o(0xc0 + (REG_VALUE(r) << 3) + REG_VALUE(r));
2081#else
2082#error
2083#endif
2064 }2084 }
2065 }2085 }
2066#endif2086#endif
@@ -2589,7 +2609,7 @@ ST_FUNC void vstore(void) · 522 unmodified lines
2589 if ((vtop[-1].r & VT_VALMASK) == VT_LLOCAL) {2609 if ((vtop[-1].r & VT_VALMASK) == VT_LLOCAL) {
2590 SValue sv;2610 SValue sv;
2591 t = get_reg(RC_INT);2611 t = get_reg(RC_INT);
2592#ifdef TCC_TARGET_X86_642612#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
2593 sv.type.t = VT_PTR;2613 sv.type.t = VT_PTR;
2594#else2614#else
2595 sv.type.t = VT_INT;2615 sv.type.t = VT_INT;
@@ -2600,7 +2620,7 @@ ST_FUNC void vstore(void) · 4 unmodified lines
2600 vtop[-1].r = t | VT_LVAL;2620 vtop[-1].r = t | VT_LVAL;
2601 }2621 }
2602 /* two word case handling : store second register at word + 4 (or +8 for x86-64) */2622 /* two word case handling : store second register at word + 4 (or +8 for x86-64) */
2603#ifdef TCC_TARGET_X86_642623#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
2604 if (((ft & VT_BTYPE) == VT_QLONG) || ((ft & VT_BTYPE) == VT_QFLOAT)) {2624 if (((ft & VT_BTYPE) == VT_QLONG) || ((ft & VT_BTYPE) == VT_QFLOAT)) {
2605 int addr_type = VT_LLONG, load_size = 8, load_type = ((vtop->type.t & VT_BTYPE) == VT_QLONG) ? VT_LLONG : VT_DOUBLE;2625 int addr_type = VT_LLONG, load_size = 8, load_type = ((vtop->type.t & VT_BTYPE) == VT_QLONG) ? VT_LLONG : VT_DOUBLE;
2606#else2626#else
@@ -3098,6 +3118,13 @@ static int parse_btype(CType *type, AttributeDef *ad) · 491 unmodified lines
3098 goto basic_type1;3118 goto basic_type1;
3099 }3119 }
3100 break;3120 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
3101 case TOK_BOOL:3128 case TOK_BOOL:
3102 u = VT_BOOL;3129 u = VT_BOOL;
3103 goto basic_type;3130 goto basic_type;
@@ -3233,7 +3260,8 @@ the_end: · 129 unmodified lines
3233 3260
3234 /* long is never used as type */3261 /* long is never used as type */
3235 if ((t & VT_BTYPE) == VT_LONG)3262 if ((t & VT_BTYPE) == VT_LONG)
3236#if !defined TCC_TARGET_X86_64 || defined TCC_TARGET_PE3263#if (!defined TCC_TARGET_X86_64 && !defined TCC_TARGET_ARM64) || \
3264 defined TCC_TARGET_PE
3237 t = (t & ~VT_BTYPE) | VT_INT;3265 t = (t & ~VT_BTYPE) | VT_INT;
3238#else3266#else
3239 t = (t & ~VT_BTYPE) | VT_LLONG;3267 t = (t & ~VT_BTYPE) | VT_LLONG;
@@ -3881,6 +3909,36 @@ ST_FUNC void unary(void) · 641 unmodified lines
3881 break;3909 break;
3882#endif3910#endif
3883#endif3911#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
3884 case TOK_INC:3942 case TOK_INC:
3885 case TOK_DEC:3943 case TOK_DEC:
3886 t = tok;3944 t = tok;
@@ -4071,6 +4129,15 @@ ST_FUNC void unary(void) · 184 unmodified lines
4071 if (!ret_nregs) {4129 if (!ret_nregs) {
4072 /* get some space for the returned structure */4130 /* get some space for the returned structure */
4073 size = type_size(&s->type, &align);4131 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
4074 loc = (loc - size) & -align;4141 loc = (loc - size) & -align;
4075 ret.type = s->type;4142 ret.type = s->type;
4076 ret.r = VT_LOCAL | VT_LVAL;4143 ret.r = VT_LOCAL | VT_LVAL;
@@ -4094,12 +4161,14 @@ ST_FUNC void unary(void) · 17 unmodified lines
4094 ret.r2 = REG_QRET;4161 ret.r2 = REG_QRET;
4095#endif4162#endif
4096 } else {4163 } else {
4164#ifndef TCC_TARGET_ARM64
4097#ifdef TCC_TARGET_X86_644165#ifdef TCC_TARGET_X86_64
4098 if ((ret.type.t & VT_BTYPE) == VT_QLONG)4166 if ((ret.type.t & VT_BTYPE) == VT_QLONG)
4099#else4167#else
4100 if ((ret.type.t & VT_BTYPE) == VT_LLONG)4168 if ((ret.type.t & VT_BTYPE) == VT_LLONG)
4101#endif4169#endif
4102 ret.r2 = REG_LRET;4170 ret.r2 = REG_LRET;
4171#endif
4103 ret.r = REG_IRET;4172 ret.r = REG_IRET;
4104 }4173 }
4105 ret.c.i = 0;4174 ret.c.i = 0;
@@ -4717,6 +4786,10 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 611 unmodified lines
4717 if (tok != ';') {4786 if (tok != ';') {
4718 gexpr();4787 gexpr();
4719 gen_assign_cast(&func_vt);4788 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
4720 if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {4793 if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
4721 CType type, ret_type;4794 CType type, ret_type;
4722 int ret_align, ret_nregs;4795 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
4770 } else {4843 } else {
4771 gv(RC_IRET);4844 gv(RC_IRET);
4772 }4845 }
4846#endif
4773 vtop--; /* NOT vpop() because on x86 it would flush the fp stack */4847 vtop--; /* NOT vpop() because on x86 it would flush the fp stack */
4774 }4848 }
4775 skip(';');4849 skip(';');
@@ -5160,9 +5234,9 @@ static void init_putv(CType *type, Section *sec, unsigned long c, · 384 unmodified lines
5160 /* XXX: generate error if incorrect relocation */5234 /* XXX: generate error if incorrect relocation */
5161 gen_assign_cast(&dtype);5235 gen_assign_cast(&dtype);
5162 bt = type->t & VT_BTYPE;5236 bt = type->t & VT_BTYPE;
5163 /* we'll write at most 12 bytes */5237 /* we'll write at most 16 bytes */
5164 if (c + 12 > sec->data_allocated) {5238 if (c + 16 > sec->data_allocated) {
5165 section_realloc(sec, c + 12);5239 section_realloc(sec, c + 16);
5166 }5240 }
5167 ptr = sec->data + c;5241 ptr = sec->data + c;
5168 /* XXX: make code faster ? */5242 /* XXX: make code faster ? */
@@ -5184,6 +5258,9 @@ static void init_putv(CType *type, Section *sec, unsigned long c, · 15 unmodified lines
5184 (bt == VT_INT && bit_size != 32)))5258 (bt == VT_INT && bit_size != 32)))
5185 tcc_error("initializer element is not computable at load time");5259 tcc_error("initializer element is not computable at load time");
5186 switch(bt) {5260 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 */
5187 case VT_BOOL:5264 case VT_BOOL:
5188 vtop->c.i = (vtop->c.i != 0);5265 vtop->c.i = (vtop->c.i != 0);
5189 case VT_BYTE:5266 case VT_BYTE:
@@ -5203,7 +5280,7 @@ static void init_putv(CType *type, Section *sec, unsigned long c, · 13 unmodified lines
5203 break;5280 break;
5204 case VT_PTR: {5281 case VT_PTR: {
5205 addr_t val = (vtop->c.ptr_offset & bit_mask) << bit_pos;5282 addr_t val = (vtop->c.ptr_offset & bit_mask) << bit_pos;
5206#ifdef TCC_TARGET_X86_645283#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
5207 if (vtop->r & VT_SYM)5284 if (vtop->r & VT_SYM)
5208 greloca(sec, vtop->sym, c, R_DATA_PTR, val);5285 greloca(sec, vtop->sym, c, R_DATA_PTR, val);
5209 else5286 else
@@ -5217,7 +5294,7 @@ static void init_putv(CType *type, Section *sec, unsigned long c, · 7 unmodified lines
5217 }5294 }
5218 default: {5295 default: {
5219 int val = (vtop->c.i & bit_mask) << bit_pos;5296 int val = (vtop->c.i & bit_mask) << bit_pos;
5220#ifdef TCC_TARGET_X86_645297#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
5221 if (vtop->r & VT_SYM)5298 if (vtop->r & VT_SYM)
5222 greloca(sec, vtop->sym, c, R_DATA_PTR, val);5299 greloca(sec, vtop->sym, c, R_DATA_PTR, val);
5223 else5300 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
604 }604 }
605}605}
606 606
607/* ------------------------------------------------------------- */
608#elif defined(__aarch64__)
609
610static 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
607/* ------------------------------------------------------------- */628/* ------------------------------------------------------------- */
608#else629#else
609 630
tcctok.h+33−0
@@ -59,6 +59,10 @@ · 58 unmodified lines
59 DEF(TOK_ASM2, "__asm")59 DEF(TOK_ASM2, "__asm")
60 DEF(TOK_ASM3, "__asm__")60 DEF(TOK_ASM3, "__asm__")
61 61
62#ifdef TCC_TARGET_ARM64
63 DEF(TOK_UINT128, "__uint128_t")
64#endif
65
62/*********************************************************************/66/*********************************************************************/
63/* the following are not keywords. They are included to ease parsing */67/* the following are not keywords. They are included to ease parsing */
64/* preprocessor only */68/* preprocessor only */
@@ -136,6 +140,11 @@ · 71 unmodified lines
136 DEF(TOK_REGPARM1, "regparm")140 DEF(TOK_REGPARM1, "regparm")
137 DEF(TOK_REGPARM2, "__regparm__")141 DEF(TOK_REGPARM2, "__regparm__")
138 142
143#ifdef TCC_TARGET_ARM64
144 DEF(TOK___va_start, "__va_start")
145 DEF(TOK___va_arg, "__va_arg")
146#endif
147
139/* pragma */148/* pragma */
140 DEF(TOK_pack, "pack")149 DEF(TOK_pack, "pack")
141#if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_X86_64)150#if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_X86_64)
@@ -229,6 +238,30 @@ · 87 unmodified lines
229#if defined TCC_TARGET_PE238#if defined TCC_TARGET_PE
230 DEF(TOK___chkstk, "__chkstk")239 DEF(TOK___chkstk, "__chkstk")
231#endif240#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
232 265
233/* bound checking symbols */266/* bound checking symbols */
234#ifdef CONFIG_TCC_BCHECK267#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